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