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