utils.cpp
00001 /***************************************************************** 00002 KWin - the KDE window manager 00003 This file is part of the KDE project. 00004 00005 Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org> 00006 Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org> 00007 00008 You can Freely distribute this program under the GNU General Public 00009 License. See the file "COPYING" for the exact licensing terms. 00010 ******************************************************************/ 00011 00012 /* 00013 00014 This file is for (very) small utility functions/classes. 00015 00016 */ 00017 00018 #include "utils.h" 00019 00020 #include <unistd.h> 00021 #include <string.h> 00022 #include <netdb.h> 00023 00024 #ifndef KCMRULES 00025 00026 #include <tqapplication.h> 00027 #include <kxerrorhandler.h> 00028 #include <assert.h> 00029 #include <kdebug.h> 00030 00031 #include <X11/Xlib.h> 00032 #include <X11/extensions/shape.h> 00033 #include <X11/Xatom.h> 00034 00035 #include "atoms.h" 00036 #include "notifications.h" 00037 00038 #ifdef USE_QT4 00039 #include <Qt/qx11info_x11.h> 00040 #endif // USE_QT4 00041 00042 #endif 00043 00044 namespace KWinInternal 00045 { 00046 00047 #ifndef KCMRULES 00048 00049 // used to store the return values of 00050 // XShapeQueryExtension. 00051 // Necessary since shaped window are an extension to X 00052 int Shape::kwin_shape_version = 0; 00053 int Shape::kwin_shape_event = 0; 00054 00055 // does the window w need a shape combine mask around it? 00056 bool Shape::hasShape( WId w) 00057 { 00058 int xws, yws, xbs, ybs; 00059 unsigned int wws, hws, wbs, hbs; 00060 int boundingShaped = 0, clipShaped = 0; 00061 if (!available()) 00062 return FALSE; 00063 XShapeQueryExtents(qt_xdisplay(), w, 00064 &boundingShaped, &xws, &yws, &wws, &hws, 00065 &clipShaped, &xbs, &ybs, &wbs, &hbs); 00066 return boundingShaped != 0; 00067 } 00068 00069 int Shape::shapeEvent() 00070 { 00071 return kwin_shape_event; 00072 } 00073 00074 void Shape::init() 00075 { 00076 kwin_shape_version = 0; 00077 int dummy; 00078 if( !XShapeQueryExtension(qt_xdisplay(), &kwin_shape_event, &dummy)) 00079 return; 00080 int major, minor; 00081 if( !XShapeQueryVersion( qt_xdisplay(), &major, &minor )) 00082 return; 00083 kwin_shape_version = major * 0x10 + minor; 00084 } 00085 00086 void Motif::readFlags( WId w, bool& noborder, bool& resize, bool& move, 00087 bool& minimize, bool& maximize, bool& close ) 00088 { 00089 Atom type; 00090 int format; 00091 unsigned long length, after; 00092 unsigned char* data; 00093 MwmHints* hints = 0; 00094 if ( XGetWindowProperty( qt_xdisplay(), w, atoms->motif_wm_hints, 0, 5, 00095 FALSE, atoms->motif_wm_hints, &type, &format, 00096 &length, &after, &data ) == Success ) 00097 { 00098 if ( data ) 00099 hints = (MwmHints*) data; 00100 } 00101 noborder = false; 00102 resize = true; 00103 move = true; 00104 minimize = true; 00105 maximize = true; 00106 close = true; 00107 if ( hints ) 00108 { 00109 // To quote from Metacity 'We support those MWM hints deemed non-stupid' 00110 if ( hints->flags & MWM_HINTS_FUNCTIONS ) 00111 { 00112 // if MWM_FUNC_ALL is set, other flags say what to turn _off_ 00113 bool set_value = (( hints->functions & MWM_FUNC_ALL ) == 0 ); 00114 resize = move = minimize = maximize = close = !set_value; 00115 if( hints->functions & MWM_FUNC_RESIZE ) 00116 resize = set_value; 00117 if( hints->functions & MWM_FUNC_MOVE ) 00118 move = set_value; 00119 if( hints->functions & MWM_FUNC_MINIMIZE ) 00120 minimize = set_value; 00121 if( hints->functions & MWM_FUNC_MAXIMIZE ) 00122 maximize = set_value; 00123 if( hints->functions & MWM_FUNC_CLOSE ) 00124 close = set_value; 00125 } 00126 if ( hints->flags & MWM_HINTS_DECORATIONS ) 00127 { 00128 if ( hints->decorations == 0 ) 00129 noborder = true; 00130 } 00131 XFree( data ); 00132 } 00133 } 00134 00135 //************************************ 00136 // KWinSelectionOwner 00137 //************************************ 00138 00139 KWinSelectionOwner::KWinSelectionOwner( int screen_P ) 00140 : KSelectionOwner( make_selection_atom( screen_P ), screen_P ) 00141 { 00142 } 00143 00144 Atom KWinSelectionOwner::make_selection_atom( int screen_P ) 00145 { 00146 if( screen_P < 0 ) 00147 screen_P = DefaultScreen( qt_xdisplay()); 00148 char tmp[ 30 ]; 00149 sprintf( tmp, "WM_S%d", screen_P ); 00150 return XInternAtom( qt_xdisplay(), tmp, False ); 00151 } 00152 00153 void KWinSelectionOwner::getAtoms() 00154 { 00155 KSelectionOwner::getAtoms(); 00156 if( xa_version == None ) 00157 { 00158 Atom atoms[ 1 ]; 00159 const char* const names[] = 00160 { "VERSION" }; 00161 XInternAtoms( qt_xdisplay(), const_cast< char** >( names ), 1, False, atoms ); 00162 xa_version = atoms[ 0 ]; 00163 } 00164 } 00165 00166 void KWinSelectionOwner::replyTargets( Atom property_P, Window requestor_P ) 00167 { 00168 KSelectionOwner::replyTargets( property_P, requestor_P ); 00169 Atom atoms[ 1 ] = { xa_version }; 00170 // PropModeAppend ! 00171 XChangeProperty( qt_xdisplay(), requestor_P, property_P, XA_ATOM, 32, PropModeAppend, 00172 reinterpret_cast< unsigned char* >( atoms ), 1 ); 00173 } 00174 00175 bool KWinSelectionOwner::genericReply( Atom target_P, Atom property_P, Window requestor_P ) 00176 { 00177 if( target_P == xa_version ) 00178 { 00179 long version[] = { 2, 0 }; 00180 XChangeProperty( qt_xdisplay(), requestor_P, property_P, XA_INTEGER, 32, 00181 PropModeReplace, reinterpret_cast< unsigned char* >( &version ), 2 ); 00182 } 00183 else 00184 return KSelectionOwner::genericReply( target_P, property_P, requestor_P ); 00185 return true; 00186 } 00187 00188 Atom KWinSelectionOwner::xa_version = None; 00189 00190 00191 TQCString getStringProperty(WId w, Atom prop, char separator) 00192 { 00193 Atom type; 00194 int format, status; 00195 unsigned long nitems = 0; 00196 unsigned long extra = 0; 00197 unsigned char *data = 0; 00198 TQCString result = ""; 00199 KXErrorHandler handler; // ignore errors 00200 status = XGetWindowProperty( qt_xdisplay(), w, prop, 0, 10000, 00201 FALSE, XA_STRING, &type, &format, 00202 &nitems, &extra, &data ); 00203 if ( status == Success) 00204 { 00205 if (data && separator) 00206 { 00207 for (int i=0; i<(int)nitems; i++) 00208 if (!data[i] && i+1<(int)nitems) 00209 data[i] = separator; 00210 } 00211 if (data) 00212 result = (const char*) data; 00213 XFree(data); 00214 } 00215 return result; 00216 } 00217 00218 static Time next_x_time; 00219 static Bool update_x_time_predicate( Display*, XEvent* event, XPointer ) 00220 { 00221 if( next_x_time != CurrentTime ) 00222 return False; 00223 // from qapplication_x11.cpp 00224 switch ( event->type ) { 00225 case ButtonPress: 00226 // fallthrough intended 00227 case ButtonRelease: 00228 next_x_time = event->xbutton.time; 00229 break; 00230 case MotionNotify: 00231 next_x_time = event->xmotion.time; 00232 break; 00233 case KeyPress: 00234 // fallthrough intended 00235 case KeyRelease: 00236 next_x_time = event->xkey.time; 00237 break; 00238 case PropertyNotify: 00239 next_x_time = event->xproperty.time; 00240 break; 00241 case EnterNotify: 00242 case LeaveNotify: 00243 next_x_time = event->xcrossing.time; 00244 break; 00245 case SelectionClear: 00246 next_x_time = event->xselectionclear.time; 00247 break; 00248 default: 00249 break; 00250 } 00251 return False; 00252 } 00253 00254 /* 00255 Updates qt_x_time. This used to simply fetch current timestamp from the server, 00256 but that can cause qt_x_time to be newer than timestamp of events that are 00257 still in our events queue, thus e.g. making XSetInputFocus() caused by such 00258 event to be ignored. Therefore events queue is searched for first 00259 event with timestamp, and extra PropertyNotify is generated in order to make 00260 sure such event is found. 00261 */ 00262 void updateXTime() 00263 { 00264 static TQWidget* w = 0; 00265 if ( !w ) 00266 w = new TQWidget; 00267 long data = 1; 00268 XChangeProperty(qt_xdisplay(), w->winId(), atoms->kwin_running, atoms->kwin_running, 32, 00269 PropModeAppend, (unsigned char*) &data, 1); 00270 next_x_time = CurrentTime; 00271 XEvent dummy; 00272 XCheckIfEvent( qt_xdisplay(), &dummy, update_x_time_predicate, NULL ); 00273 if( next_x_time == CurrentTime ) 00274 { 00275 XSync( qt_xdisplay(), False ); 00276 XCheckIfEvent( qt_xdisplay(), &dummy, update_x_time_predicate, NULL ); 00277 } 00278 assert( next_x_time != CurrentTime ); 00279 SET_QT_X_TIME(next_x_time); 00280 XEvent ev; // remove the PropertyNotify event from the events queue 00281 XWindowEvent( qt_xdisplay(), w->winId(), PropertyChangeMask, &ev ); 00282 } 00283 00284 static int server_grab_count = 0; 00285 00286 void grabXServer() 00287 { 00288 if( ++server_grab_count == 1 ) 00289 XGrabServer( qt_xdisplay()); 00290 } 00291 00292 void ungrabXServer() 00293 { 00294 assert( server_grab_count > 0 ); 00295 if( --server_grab_count == 0 ) 00296 { 00297 XUngrabServer( qt_xdisplay()); 00298 XFlush( qt_xdisplay()); 00299 Notify::sendPendingEvents(); 00300 } 00301 } 00302 00303 bool grabbedXServer() 00304 { 00305 return server_grab_count > 0; 00306 } 00307 00308 #endif 00309 00310 bool isLocalMachine( const TQCString& host ) 00311 { 00312 #ifdef HOST_NAME_MAX 00313 char hostnamebuf[HOST_NAME_MAX]; 00314 #else 00315 char hostnamebuf[256]; 00316 #endif 00317 if (gethostname (hostnamebuf, sizeof hostnamebuf) >= 0) 00318 { 00319 hostnamebuf[sizeof(hostnamebuf)-1] = 0; 00320 if (host == hostnamebuf) 00321 return true; 00322 if( char *dot = strchr(hostnamebuf, '.')) 00323 { 00324 *dot = '\0'; 00325 if( host == hostnamebuf ) 00326 return true; 00327 } 00328 else 00329 { // e.g. LibreOffice likes to give FQDN, even if gethostname() doesn't include domain 00330 struct addrinfo hints, *res, *addr; 00331 bool is_local = false; 00332 00333 memset (&hints, 0, sizeof (hints)); 00334 hints.ai_family = PF_UNSPEC; 00335 hints.ai_socktype = SOCK_STREAM; 00336 hints.ai_flags |= AI_CANONNAME; 00337 00338 if( getaddrinfo( host, NULL, &hints, &res ) != 0) 00339 return false; 00340 for(addr = res; !is_local && addr; addr = addr->ai_next) 00341 { 00342 if( addr->ai_canonname && 00343 host == TQCString( addr->ai_canonname )) 00344 is_local = true; 00345 } 00346 freeaddrinfo(res); 00347 return is_local; 00348 } 00349 } 00350 return false; 00351 } 00352 00353 #ifndef KCMRULES 00354 ShortcutDialog::ShortcutDialog( const KShortcut& cut ) 00355 : KShortcutDialog( cut, false /*TODO???*/ ) 00356 { 00357 // make it a popup, so that it has the grab 00358 XSetWindowAttributes attrs; 00359 attrs.override_redirect = True; 00360 XChangeWindowAttributes( qt_xdisplay(), winId(), CWOverrideRedirect, &attrs ); 00361 setWFlags( WType_Popup ); 00362 } 00363 00364 void ShortcutDialog::accept() 00365 { 00366 for( int i = 0; 00367 ; 00368 ++i ) 00369 { 00370 KKeySequence seq = shortcut().seq( i ); 00371 if( seq.isNull()) 00372 break; 00373 if( seq.key( 0 ) == Key_Escape ) 00374 { 00375 reject(); 00376 return; 00377 } 00378 if( seq.key( 0 ) == Key_Space ) 00379 { // clear 00380 setShortcut( KShortcut()); 00381 KShortcutDialog::accept(); 00382 return; 00383 } 00384 if( seq.key( 0 ).modFlags() == 0 ) 00385 { // no shortcuts without modifiers 00386 KShortcut cut = shortcut(); 00387 cut.setSeq( i, KKeySequence()); 00388 setShortcut( cut ); 00389 return; 00390 } 00391 } 00392 KShortcutDialog::accept(); 00393 } 00394 00395 // Workaround for Qt bug causing #119142 - wheel event causes only calling 00396 // of hide() but not close(), so dialog closing is not performed. 00397 // Possible recursive calling close->hide->close should be fine, as close() 00398 // has checks against that. 00399 void ShortcutDialog::hide() 00400 { 00401 close(); 00402 return KShortcutDialog::hide(); 00403 } 00404 00405 #endif 00406 00407 00408 } // namespace 00409 00410 #ifndef KCMRULES 00411 #include "utils.moc" 00412 #endif