• Skip to content
  • Skip to link menu
KDE 4.7 API Reference
  • KDE API Reference
  • kdelibs
  • KDE Home
  • Contact Us
 

KDEUI

kwindowsystem_x11.cpp
Go to the documentation of this file.
00001 /*
00002     This file is part of the KDE libraries
00003     Copyright (C) 1999 Matthias Ettrich (ettrich@kde.org)
00004     Copyright (C) 2007 Lubos Lunak (l.lunak@kde.org)
00005 
00006     This library is free software; you can redistribute it and/or
00007     modify it under the terms of the GNU Library General Public
00008     License as published by the Free Software Foundation; either
00009     version 2 of the License, or (at your option) any later version.
00010 
00011     This library is distributed in the hope that it will be useful,
00012     but WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014     Library General Public License for more details.
00015 
00016     You should have received a copy of the GNU Library General Public License
00017     along with this library; see the file COPYING.LIB.  If not, write to
00018     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00019     Boston, MA 02110-1301, USA.
00020 */
00021 
00022 #include "kwindowsystem.h"
00023 
00024 #include <kiconloader.h>
00025 #include <klocale.h>
00026 #include <kdebug.h>
00027 #include <ksystemeventfilter.h>
00028 #include <kxerrorhandler.h>
00029 #include <kxutils.h>
00030 #include <netwm.h>
00031 #include <QtGui/QApplication>
00032 #include <QtGui/QBitmap>
00033 #include <QDesktopWidget>
00034 #include <QtGui/QDialog>
00035 #include <QtDBus/QtDBus>
00036 #include <QtGui/QX11Info>
00037 #include <X11/Xatom.h>
00038 
00039 #include <config.h>
00040 
00041 #ifdef HAVE_XFIXES
00042 #include <X11/extensions/Xfixes.h>
00043 #endif
00044 
00045 class KWindowSystemStaticContainer {
00046 public:
00047     KWindowSystemStaticContainer() : d(0) {}
00048     KWindowSystem kwm;
00049     KWindowSystemPrivate* d;
00050 };
00051 
00052 
00053 K_GLOBAL_STATIC(KWindowSystemStaticContainer, g_kwmInstanceContainer)
00054 
00055 static Atom net_wm_cm;
00056 static void create_atoms( Display* dpy = QX11Info::display() );
00057 
00058 static unsigned long windows_properties[ 2 ] = { NET::ClientList | NET::ClientListStacking |
00059                                      NET::Supported |
00060                      NET::NumberOfDesktops |
00061                      NET::DesktopGeometry |
00062                                      NET::DesktopViewport |
00063                      NET::CurrentDesktop |
00064                      NET::DesktopNames |
00065                      NET::ActiveWindow |
00066                      NET::WorkArea, 
00067                                      NET::WM2ShowingDesktop };
00068 
00069 // ClientList and ClientListStacking is not per-window information, but a desktop information,
00070 // so track it even with only INFO_BASIC
00071 static unsigned long desktop_properties[ 2 ] = { NET::ClientList | NET::ClientListStacking |
00072                                      NET::Supported |
00073                      NET::NumberOfDesktops |
00074                      NET::DesktopGeometry |
00075                                      NET::DesktopViewport |
00076                      NET::CurrentDesktop |
00077                      NET::DesktopNames |
00078                      NET::ActiveWindow |
00079                      NET::WorkArea, 
00080                                      NET::WM2ShowingDesktop };
00081 
00082 class KWindowSystemPrivate
00083     : public QWidget, public NETRootInfo
00084 {
00085 public:
00086     KWindowSystemPrivate(int _what);
00087     void activate();
00088     QList<WId> windows;
00089     QList<WId> stackingOrder;
00090 
00091     struct StrutData
00092     {
00093         StrutData( WId window_, const NETStrut& strut_, int desktop_ )
00094             : window( window_ ), strut( strut_ ), desktop( desktop_ ) {}
00095         StrutData() {} // for QValueList to be happy
00096         WId window;
00097         NETStrut strut;
00098         int desktop;
00099     };
00100     QList<StrutData> strutWindows;
00101     QList<WId> possibleStrutWindows;
00102     bool strutSignalConnected;
00103     bool compositingEnabled;
00104     bool haveXfixes;
00105     int what;
00106     int xfixesEventBase;
00107     bool mapViewport();
00108 
00109     void addClient(Window);
00110     void removeClient(Window);
00111 
00112     bool x11Event( XEvent * ev );
00113 
00114     void updateStackingOrder();
00115     bool removeStrutWindow( WId );
00116 };
00117 
00118 KWindowSystemPrivate::KWindowSystemPrivate(int _what)
00119     : QWidget(0),
00120       NETRootInfo( QX11Info::display(),
00121                    _what >= KWindowSystem::INFO_WINDOWS ? windows_properties : desktop_properties,
00122                    2, -1, false ),
00123       strutSignalConnected( false ),
00124       haveXfixes( false ),
00125       what( _what )
00126 {
00127     KSystemEventFilter::installEventFilter(this);
00128     (void ) qApp->desktop(); //trigger desktop widget creation to select root window events
00129 
00130 #ifdef HAVE_XFIXES
00131     int errorBase;
00132     if ((haveXfixes = XFixesQueryExtension(QX11Info::display(), &xfixesEventBase, &errorBase))) {
00133         create_atoms();
00134         XFixesSelectSelectionInput(QX11Info::display(), winId(), net_wm_cm,
00135                                    XFixesSetSelectionOwnerNotifyMask |
00136                                    XFixesSelectionWindowDestroyNotifyMask |
00137                                    XFixesSelectionClientCloseNotifyMask);
00138         compositingEnabled = XGetSelectionOwner(QX11Info::display(), net_wm_cm) != None;
00139     }
00140 #endif
00141 }
00142 
00143 // not virtual, but it's called directly only from init()
00144 void KWindowSystemPrivate::activate()
00145 {
00146     NETRootInfo::activate();
00147     updateStackingOrder();
00148 }
00149 
00150 bool KWindowSystemPrivate::x11Event( XEvent * ev )
00151 {
00152     KWindowSystem* s_q = KWindowSystem::self();
00153 
00154 #ifdef HAVE_XFIXES
00155     if ( ev->type == xfixesEventBase + XFixesSelectionNotify && ev->xany.window == winId() ) {
00156         XFixesSelectionNotifyEvent *event = reinterpret_cast<XFixesSelectionNotifyEvent*>(ev);
00157         bool haveOwner = event->owner != None;
00158         if (compositingEnabled != haveOwner) {
00159             compositingEnabled = haveOwner;
00160             emit s_q->compositingChanged( compositingEnabled );
00161         }
00162         return true;
00163     }
00164 #endif
00165 
00166     if ( ev->xany.window == QX11Info::appRootWindow() ) {
00167         int old_current_desktop = currentDesktop();
00168         WId old_active_window = activeWindow();
00169         int old_number_of_desktops = numberOfDesktops();
00170         bool old_showing_desktop = showingDesktop();
00171         unsigned long m[ 5 ];
00172     NETRootInfo::event( ev, m, 5 );
00173 
00174     if (( m[ PROTOCOLS ] & CurrentDesktop ) && currentDesktop() != old_current_desktop )
00175         emit s_q->currentDesktopChanged( currentDesktop() );
00176     if (( m[ PROTOCOLS ] & DesktopViewport ) && mapViewport() && currentDesktop() != old_current_desktop )
00177         emit s_q->currentDesktopChanged( currentDesktop() );
00178     if (( m[ PROTOCOLS ] & ActiveWindow ) && activeWindow() != old_active_window )
00179         emit s_q->activeWindowChanged( activeWindow() );
00180     if ( m[ PROTOCOLS ] & DesktopNames )
00181         emit s_q->desktopNamesChanged();
00182     if (( m[ PROTOCOLS ] & NumberOfDesktops ) && numberOfDesktops() != old_number_of_desktops )
00183         emit s_q->numberOfDesktopsChanged( numberOfDesktops() );
00184     if (( m[ PROTOCOLS ] & DesktopGeometry ) && mapViewport() && numberOfDesktops() != old_number_of_desktops )
00185         emit s_q->numberOfDesktopsChanged( numberOfDesktops() );
00186     if ( m[ PROTOCOLS ] & WorkArea )
00187         emit s_q->workAreaChanged();
00188     if ( m[ PROTOCOLS ] & ClientListStacking ) {
00189         updateStackingOrder();
00190         emit s_q->stackingOrderChanged();
00191     }
00192         if(( m[ PROTOCOLS2 ] & WM2ShowingDesktop ) && showingDesktop() != old_showing_desktop ) {
00193         emit s_q->showingDesktopChanged( showingDesktop());
00194         }
00195     } else  if ( windows.contains( ev->xany.window ) ){
00196     NETWinInfo ni( QX11Info::display(), ev->xany.window, QX11Info::appRootWindow(), 0 );
00197         unsigned long dirty[ 2 ];
00198     ni.event( ev, dirty, 2 );
00199     if ( ev->type ==PropertyNotify ) {
00200             if( ev->xproperty.atom == XA_WM_HINTS )
00201             dirty[ NETWinInfo::PROTOCOLS ] |= NET::WMIcon; // support for old icons
00202             else if( ev->xproperty.atom == XA_WM_NAME )
00203                 dirty[ NETWinInfo::PROTOCOLS ] |= NET::WMName; // support for old name
00204             else if( ev->xproperty.atom == XA_WM_ICON_NAME )
00205                 dirty[ NETWinInfo::PROTOCOLS ] |= NET::WMIconName; // support for old iconic name
00206         }
00207         if( mapViewport() && ( dirty[ NETWinInfo::PROTOCOLS ] & (NET::WMState | NET::WMGeometry) )) {
00208         /* geometry change -> possible viewport change
00209          * state change -> possible NET::Sticky change
00210          */
00211             dirty[ NETWinInfo::PROTOCOLS ] |= NET::WMDesktop;
00212     }
00213     if ( (dirty[ NETWinInfo::PROTOCOLS ] & NET::WMStrut) != 0 ) {
00214             removeStrutWindow( ev->xany.window );
00215             if ( !possibleStrutWindows.contains( ev->xany.window ) )
00216             possibleStrutWindows.append( ev->xany.window );
00217     }
00218     if ( dirty[ NETWinInfo::PROTOCOLS ] || dirty[ NETWinInfo::PROTOCOLS2 ] ) {
00219         emit s_q->windowChanged( ev->xany.window );
00220         emit s_q->windowChanged( ev->xany.window, dirty );
00221         emit s_q->windowChanged( ev->xany.window, dirty[ NETWinInfo::PROTOCOLS ] );
00222         if ( (dirty[ NETWinInfo::PROTOCOLS ] & NET::WMStrut) != 0 )
00223         emit s_q->strutChanged();
00224     }
00225     }
00226 
00227     return false;
00228 }
00229 
00230 bool KWindowSystemPrivate::removeStrutWindow( WId w )
00231 {
00232     for( QList< StrutData >::Iterator it = strutWindows.begin();
00233          it != strutWindows.end();
00234          ++it )
00235         if( (*it).window == w ) {
00236             strutWindows.erase( it );
00237             return true;
00238         }
00239     return false;
00240 }
00241 
00242 void KWindowSystemPrivate::updateStackingOrder()
00243 {
00244     stackingOrder.clear();
00245     for ( int i = 0; i <  clientListStackingCount(); i++ )
00246     stackingOrder.append( clientListStacking()[i] );
00247 }
00248 
00249 void KWindowSystemPrivate::addClient(Window w)
00250 {
00251     KWindowSystem* s_q = KWindowSystem::self();
00252 
00253     if ( (what >= KWindowSystem::INFO_WINDOWS) && !QWidget::find( w ) )
00254         XSelectInput( QX11Info::display(), w, PropertyChangeMask | StructureNotifyMask );
00255 
00256     bool emit_strutChanged = false;
00257 
00258     if( strutSignalConnected ) {
00259         NETWinInfo info( QX11Info::display(), w, QX11Info::appRootWindow(), NET::WMStrut | NET::WMDesktop );
00260         NETStrut strut = info.strut();
00261         if ( strut.left || strut.top || strut.right || strut.bottom ) {
00262             strutWindows.append( StrutData( w, strut, info.desktop()));
00263             emit_strutChanged = true;
00264         }
00265     } else
00266         possibleStrutWindows.append( w );
00267 
00268     windows.append( w );
00269     emit s_q->windowAdded( w );
00270     if ( emit_strutChanged )
00271         emit s_q->strutChanged();
00272 }
00273 
00274 void KWindowSystemPrivate::removeClient(Window w)
00275 {
00276     KWindowSystem* s_q = KWindowSystem::self();
00277 
00278     bool emit_strutChanged = removeStrutWindow( w );
00279     if( strutSignalConnected && possibleStrutWindows.contains( w )) {
00280         NETWinInfo info( QX11Info::display(), w, QX11Info::appRootWindow(), NET::WMStrut );
00281         NETStrut strut = info.strut();
00282         if ( strut.left || strut.top || strut.right || strut.bottom ) {
00283             emit_strutChanged = true;
00284         }
00285     }
00286 
00287     possibleStrutWindows.removeAll( w );
00288     windows.removeAll( w );
00289     emit s_q->windowRemoved( w );
00290     if ( emit_strutChanged )
00291         emit s_q->strutChanged();
00292 }
00293 
00294 bool KWindowSystemPrivate::mapViewport()
00295 {
00296 // compiz claims support even though it doesn't use virtual desktops :(
00297 //    if( isSupported( NET::DesktopViewport ) && !isSupported( NET::NumberOfDesktops ))
00298 
00299 // this test is duplicated in KWindowSystem::mapViewport()
00300     if( isSupported( NET::DesktopViewport ) && numberOfDesktops( true ) <= 1
00301         && ( desktopGeometry( currentDesktop( true )).width > QApplication::desktop()->width()
00302             || desktopGeometry( currentDesktop( true )).height > QApplication::desktop()->height()))
00303         return true;
00304     return false;
00305 }
00306 
00307 static bool atoms_created = false;
00308 
00309 static Atom kde_wm_change_state;
00310 static Atom _wm_protocols;
00311 static Atom kwm_utf8_string;
00312 
00313 static void create_atoms( Display* dpy ) {
00314     if (!atoms_created){
00315     const int max = 20;
00316     Atom* atoms[max];
00317     const char* names[max];
00318     Atom atoms_return[max];
00319     int n = 0;
00320 
00321     atoms[n] = &kde_wm_change_state;
00322     names[n++] = "_KDE_WM_CHANGE_STATE";
00323 
00324         atoms[n] = &_wm_protocols;
00325         names[n++] = "WM_PROTOCOLS";
00326 
00327         atoms[n] = &kwm_utf8_string;
00328         names[n++] = "UTF8_STRING";
00329 
00330         char net_wm_cm_name[ 100 ];
00331         sprintf( net_wm_cm_name, "_NET_WM_CM_S%d", DefaultScreen( dpy ));
00332         atoms[n] = &net_wm_cm;
00333         names[n++] = net_wm_cm_name;
00334 
00335     // we need a const_cast for the shitty X API
00336     XInternAtoms( dpy, const_cast<char**>(names), n, false, atoms_return );
00337     for (int i = 0; i < n; i++ )
00338         *atoms[i] = atoms_return[i];
00339 
00340     atoms_created = True;
00341     }
00342 }
00343 
00344 static void sendClientMessageToRoot(Window w, Atom a, long x, long y = 0, long z = 0 ){
00345   XEvent ev;
00346   long mask;
00347 
00348   memset(&ev, 0, sizeof(ev));
00349   ev.xclient.type = ClientMessage;
00350   ev.xclient.window = w;
00351   ev.xclient.message_type = a;
00352   ev.xclient.format = 32;
00353   ev.xclient.data.l[0] = x;
00354   ev.xclient.data.l[1] = y;
00355   ev.xclient.data.l[2] = z;
00356   mask = SubstructureRedirectMask;
00357   XSendEvent(QX11Info::display(), QX11Info::appRootWindow(), False, mask, &ev);
00358 }
00359 
00360 KWindowSystem* KWindowSystem::self()
00361 {
00362     return &(g_kwmInstanceContainer->kwm);
00363 }
00364 
00365 
00366 KWindowSystemPrivate* KWindowSystem::s_d_func()
00367 {
00368     return g_kwmInstanceContainer->d;
00369 }
00370 
00371 
00372 // optimalization - create KWindowSystemPrivate only when needed and only for what is needed
00373 void KWindowSystem::connectNotify( const char* signal )
00374 {
00375     int what = INFO_BASIC;
00376     if( QLatin1String( signal ) == SIGNAL(workAreaChanged()))
00377         what = INFO_WINDOWS;
00378     else if( QLatin1String( signal ) == SIGNAL(strutChanged()))
00379         what = INFO_WINDOWS;
00380     else if( QLatin1String( signal ) == QMetaObject::normalizedSignature(SIGNAL(windowChanged(WId,const unsigned long*))).constData())
00381         what = INFO_WINDOWS;
00382     else if( QLatin1String( signal ) ==  QMetaObject::normalizedSignature(SIGNAL(windowChanged(WId,unsigned int))).constData())
00383         what = INFO_WINDOWS;
00384     else if( QLatin1String( signal ) ==  QMetaObject::normalizedSignature(SIGNAL(windowChanged(WId))).constData())
00385         what = INFO_WINDOWS;
00386 
00387     init( what );
00388     KWindowSystemPrivate* const s_d = s_d_func();
00389     if( !s_d->strutSignalConnected && qstrcmp( signal, SIGNAL(strutChanged())) == 0 )
00390         s_d->strutSignalConnected = true;
00391 
00392     QObject::connectNotify( signal );
00393 }
00394 
00395 // WARNING
00396 // you have to call s_d_func() again after calling this function if you want a valid pointer!
00397 void KWindowSystem::init(int what)
00398 {
00399     KWindowSystemPrivate* const s_d = s_d_func();
00400 
00401     if (what >= INFO_WINDOWS)
00402        what = INFO_WINDOWS;
00403     else
00404        what = INFO_BASIC;
00405 
00406     if ( !s_d )
00407     {
00408         g_kwmInstanceContainer->d = new KWindowSystemPrivate(what); // invalidates s_d
00409         g_kwmInstanceContainer->d->activate();
00410     }
00411     else if (s_d->what < what)
00412     {
00413         delete s_d;
00414         g_kwmInstanceContainer->d = new KWindowSystemPrivate(what); // invalidates s_d
00415         g_kwmInstanceContainer->d->activate();
00416     }
00417 }
00418 
00419 const QList<WId>& KWindowSystem::windows()
00420 {
00421     init( INFO_BASIC );
00422     return s_d_func()->windows;
00423 }
00424 
00425 KWindowInfo KWindowSystem::windowInfo( WId win, unsigned long properties, unsigned long properties2 )
00426 {
00427     return KWindowInfo( win, properties, properties2 );
00428 }
00429 
00430 bool KWindowSystem::hasWId(WId w)
00431 {
00432     init( INFO_BASIC );
00433     return s_d_func()->windows.contains( w );
00434 }
00435 
00436 QList<WId> KWindowSystem::stackingOrder()
00437 {
00438     init( INFO_BASIC );
00439     return s_d_func()->stackingOrder;
00440 }
00441 
00442 int KWindowSystem::currentDesktop()
00443 {
00444     if (!QX11Info::display())
00445       return 1;
00446 
00447     if( mapViewport()) {
00448         init( INFO_BASIC );
00449         KWindowSystemPrivate* const s_d = s_d_func();
00450         NETPoint p = s_d->desktopViewport( s_d->currentDesktop( true ));
00451         return viewportToDesktop( QPoint( p.x, p.y ));
00452     }
00453 
00454     KWindowSystemPrivate* const s_d = s_d_func();
00455     if( s_d )
00456         return s_d->currentDesktop( true );
00457     NETRootInfo info( QX11Info::display(), NET::CurrentDesktop );
00458     return info.currentDesktop( true );
00459 }
00460 
00461 int KWindowSystem::numberOfDesktops()
00462 {
00463     if (!QX11Info::display())
00464       return 1;
00465 
00466     if( mapViewport()) {
00467         init( INFO_BASIC );
00468         KWindowSystemPrivate* const s_d = s_d_func();
00469         NETSize s = s_d->desktopGeometry( s_d->currentDesktop( true ));
00470         return s.width / qApp->desktop()->width() * s.height / qApp->desktop()->height();
00471     }
00472 
00473     KWindowSystemPrivate* const s_d = s_d_func();
00474     if( s_d )
00475         return s_d->numberOfDesktops( true );
00476     NETRootInfo info( QX11Info::display(), NET::NumberOfDesktops );
00477     return info.numberOfDesktops( true );
00478 }
00479 
00480 void KWindowSystem::setCurrentDesktop( int desktop )
00481 {
00482     if( mapViewport()) {
00483         init( INFO_BASIC );
00484         KWindowSystemPrivate* const s_d = s_d_func();
00485         NETRootInfo info( QX11Info::display(), 0 );
00486         QPoint pos = desktopToViewport( desktop, true );
00487         NETPoint p;
00488         p.x = pos.x();
00489         p.y = pos.y();
00490         info.setDesktopViewport( s_d->currentDesktop( true ), p );
00491         return;
00492     }
00493     NETRootInfo info( QX11Info::display(), 0 );
00494     info.setCurrentDesktop( desktop, true );
00495 }
00496 
00497 void KWindowSystem::setOnAllDesktops( WId win, bool b )
00498 {
00499     if( mapViewport()) {
00500         if( b )
00501             setState( win, NET::Sticky );
00502         else
00503             clearState( win, NET::Sticky );
00504         return;
00505     }
00506     NETWinInfo info( QX11Info::display(), win, QX11Info::appRootWindow(), NET::WMDesktop );
00507     if ( b )
00508     info.setDesktop( NETWinInfo::OnAllDesktops, true );
00509     else if ( info.desktop( true )  == NETWinInfo::OnAllDesktops ) {
00510     NETRootInfo rinfo( QX11Info::display(), NET::CurrentDesktop );
00511     info.setDesktop( rinfo.currentDesktop( true ), true );
00512     }
00513 }
00514 
00515 void KWindowSystem::setOnDesktop( WId win, int desktop )
00516 {
00517     if( mapViewport()) {
00518         if( desktop == NET::OnAllDesktops )
00519             return setOnAllDesktops( win, true );
00520         else
00521             clearState( win, NET::Sticky );
00522         init( INFO_BASIC );
00523         QPoint p = desktopToViewport( desktop, false );
00524         Window dummy;
00525         int x, y;
00526         unsigned int w, h, b, dp;
00527         XGetGeometry( QX11Info::display(), win, &dummy, &x, &y, &w, &h, &b, &dp );
00528         // get global position
00529         XTranslateCoordinates( QX11Info::display(), win, QX11Info::appRootWindow(), 0, 0, &x, &y, &dummy );
00530         x += w / 2; // center
00531         y += h / 2;
00532         // transform to coordinates on the current "desktop"
00533         x = x % qApp->desktop()->width();
00534         y = y % qApp->desktop()->height();
00535         if( x < 0 )
00536             x = x + qApp->desktop()->width();
00537         if( y < 0 )
00538             y = y + qApp->desktop()->height();
00539         x += p.x(); // move to given "desktop"
00540         y += p.y();
00541         x -= w / 2; // from center back to topleft
00542         y -= h / 2;
00543         p = constrainViewportRelativePosition( QPoint( x, y ));
00544         int flags = ( NET::FromTool << 12 ) | ( 0x03 << 8 ) | 10; // from tool(?), x/y, static gravity
00545         KWindowSystemPrivate* const s_d = s_d_func();
00546         s_d->moveResizeWindowRequest( win, flags, p.x(), p.y(), w, h );
00547         return;
00548     }
00549     NETWinInfo info( QX11Info::display(), win, QX11Info::appRootWindow(), NET::WMDesktop );
00550     info.setDesktop( desktop, true );
00551 }
00552 
00553 WId KWindowSystem::activeWindow()
00554 {
00555     KWindowSystemPrivate* const s_d = s_d_func();
00556     if( s_d )
00557         return s_d->activeWindow();
00558     NETRootInfo info( QX11Info::display(), NET::ActiveWindow );
00559     return info.activeWindow();
00560 }
00561 
00562 void KWindowSystem::activateWindow( WId win, long time )
00563 {
00564     NETRootInfo info( QX11Info::display(), 0 );
00565     if( time == 0 )
00566         time = QX11Info::appUserTime();
00567     info.setActiveWindow( win, NET::FromApplication, time,
00568         qApp->activeWindow() ? qApp->activeWindow()->winId() : 0 );
00569 }
00570 
00571 void KWindowSystem::forceActiveWindow( WId win, long time )
00572 {
00573     NETRootInfo info( QX11Info::display(), 0 );
00574     if( time == 0 )
00575         time = QX11Info::appTime();
00576     info.setActiveWindow( win, NET::FromTool, time, 0 );
00577 }
00578 
00579 void KWindowSystem::demandAttention( WId win, bool set )
00580 {
00581     NETWinInfo info( QX11Info::display(), win, QX11Info::appRootWindow(), NET::WMState );
00582     info.setState( set ? NET::DemandsAttention : 0, NET::DemandsAttention );
00583 }
00584 
00585 WId KWindowSystem::transientFor( WId win )
00586 {
00587     KXErrorHandler handler; // ignore badwindow
00588     Window transient_for = None;
00589     if( XGetTransientForHint( QX11Info::display(), win, &transient_for ))
00590         return transient_for;
00591     // XGetTransientForHint() did sync
00592     return None;
00593 }
00594 
00595 void KWindowSystem::setMainWindow( QWidget* subwindow, WId mainwindow )
00596 {
00597     subwindow->setAttribute( Qt::WA_X11BypassTransientForHint );
00598     if( mainwindow != 0 )
00599         XSetTransientForHint( QX11Info::display(), subwindow->winId(), mainwindow );
00600     else
00601         XDeleteProperty( QX11Info::display(), subwindow->winId(), XA_WM_TRANSIENT_FOR );
00602 }
00603 
00604 WId KWindowSystem::groupLeader( WId win )
00605 {
00606     KXErrorHandler handler; // ignore badwindow
00607     XWMHints *hints = XGetWMHints( QX11Info::display(), win );
00608     Window window_group = None;
00609     if ( hints )
00610     {
00611         if( hints->flags & WindowGroupHint )
00612             window_group = hints->window_group;
00613         XFree( reinterpret_cast< char* >( hints ));
00614     }
00615     // XGetWMHints() did sync
00616     return window_group;
00617 }
00618 
00619 QPixmap KWindowSystem::icon( WId win, int width, int height, bool scale )
00620 {
00621     return icon( win, width, height, scale, NETWM | WMHints | ClassHint | XApp );
00622 }
00623 
00624 
00625 QPixmap KWindowSystem::icon( WId win, int width, int height, bool scale, int flags )
00626 {
00627     KXErrorHandler handler; // ignore badwindow
00628     QPixmap result;
00629     if( flags & NETWM ) {
00630         NETWinInfo info( QX11Info::display(), win, QX11Info::appRootWindow(), NET::WMIcon );
00631         NETIcon ni = info.icon( width, height );
00632         if ( ni.data && ni.size.width > 0 && ni.size.height > 0 ) {
00633             QImage img( (uchar*) ni.data, (int) ni.size.width, (int) ni.size.height, QImage::Format_ARGB32 );
00634         if ( scale && width > 0 && height > 0 &&img.size() != QSize( width, height ) && !img.isNull() )
00635             img = img.scaled( width, height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation );
00636         if ( !img.isNull() )
00637             result = QPixmap::fromImage( img );
00638         return result;
00639         }
00640     }
00641 
00642     if( flags & WMHints ) {
00643         Pixmap p = None;
00644         Pixmap p_mask = None;
00645 
00646         XWMHints *hints = XGetWMHints(QX11Info::display(), win );
00647         if (hints && (hints->flags & IconPixmapHint)){
00648             p = hints->icon_pixmap;
00649         }
00650         if (hints && (hints->flags & IconMaskHint)){
00651         p_mask = hints->icon_mask;
00652         }
00653         if (hints)
00654         XFree((char*)hints);
00655 
00656         if (p != None){
00657             QPixmap pm = KXUtils::createPixmapFromHandle( p, p_mask );
00658             if ( scale && width > 0 && height > 0 && !pm.isNull()
00659                  && ( pm.width() != width || pm.height() != height) ){
00660                 result = QPixmap::fromImage( pm.toImage().scaled( width, height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation ) );
00661         } else {
00662                 result = pm;
00663         }
00664         }
00665     }
00666 
00667     // Since width can be any arbitrary size, but the icons cannot,
00668     // take the nearest value for best results (ignoring 22 pixel
00669     // icons as they don't exist for apps):
00670     int iconWidth;
00671     if( width < 24 )
00672         iconWidth = 16;
00673     else if( width < 40 )
00674         iconWidth = 32;
00675     else
00676         iconWidth = 48;
00677 
00678     if( flags & ClassHint ) {
00679         // Try to load the icon from the classhint if the app didn't specify
00680         // its own:
00681         if( result.isNull() ) {
00682 
00683         XClassHint  hint;
00684         if( XGetClassHint( QX11Info::display(), win, &hint ) ) {
00685             QString className = hint.res_class;
00686 
00687                 QPixmap pm = KIconLoader::global()->loadIcon( className.toLower(), KIconLoader::Small, iconWidth,
00688                                                            KIconLoader::DefaultState, QStringList(), 0, true );
00689             if( scale && !pm.isNull() )
00690             result = QPixmap::fromImage( pm.toImage().scaled( width, height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation ) );
00691             else
00692             result = pm;
00693 
00694             XFree( hint.res_name );
00695             XFree( hint.res_class );
00696         }
00697         }
00698     }
00699 
00700     if( flags & XApp ) {
00701         // If the icon is still a null pixmap, load the icon for X applications
00702         // as a last resort:
00703         if ( result.isNull() ) {
00704             QPixmap pm = KIconLoader::global()->loadIcon( "xorg", KIconLoader::Small, iconWidth,
00705                                                           KIconLoader::DefaultState, QStringList(), 0, true );
00706         if( scale && !pm.isNull() )
00707         result = QPixmap::fromImage( pm.toImage().scaled( width, height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation ) );
00708         else
00709         result = pm;
00710         }
00711     }
00712     return result;
00713 }
00714 
00715 void KWindowSystem::setIcons( WId win, const QPixmap& icon, const QPixmap& miniIcon )
00716 {
00717     if ( icon.isNull() )
00718     return;
00719     NETWinInfo info( QX11Info::display(), win, QX11Info::appRootWindow(), 0 );
00720     QImage img = icon.toImage().convertToFormat( QImage::Format_ARGB32 );
00721     NETIcon ni;
00722     ni.size.width = img.size().width();
00723     ni.size.height = img.size().height();
00724     ni.data = (unsigned char *) img.bits();
00725     info.setIcon( ni, true );
00726     if ( miniIcon.isNull() )
00727     return;
00728     img = miniIcon.toImage().convertToFormat( QImage::Format_ARGB32 );
00729     if ( img.isNull() )
00730         return;
00731     ni.size.width = img.size().width();
00732     ni.size.height = img.size().height();
00733     ni.data = (unsigned char *) img.bits();
00734     info.setIcon( ni, false );
00735 }
00736 
00737 void KWindowSystem::setType( WId win, NET::WindowType windowType )
00738 {
00739     NETWinInfo info( QX11Info::display(), win, QX11Info::appRootWindow(), 0 );
00740     info.setWindowType( windowType );
00741 }
00742 
00743 void KWindowSystem::setState( WId win, unsigned long state )
00744 {
00745     NETWinInfo info( QX11Info::display(), win, QX11Info::appRootWindow(), NET::WMState );
00746     info.setState( state, state );
00747 }
00748 
00749 void KWindowSystem::clearState( WId win, unsigned long state )
00750 {
00751     NETWinInfo info( QX11Info::display(), win, QX11Info::appRootWindow(), NET::WMState );
00752     info.setState( 0, state );
00753 }
00754 
00755 void KWindowSystem::minimizeWindow( WId win, bool animation)
00756 {
00757     if ( !animation )
00758     {
00759         create_atoms();
00760     sendClientMessageToRoot( win, kde_wm_change_state, IconicState, 1 );
00761     }
00762     QX11Info inf;
00763     XIconifyWindow( QX11Info::display(), win, inf.screen() );
00764 }
00765 
00766 void KWindowSystem::unminimizeWindow( WId win, bool animation )
00767 {
00768     if ( !animation )
00769     {
00770         create_atoms();
00771     sendClientMessageToRoot( win, kde_wm_change_state, NormalState, 1 );
00772     }
00773     XMapWindow( QX11Info::display(), win );
00774 }
00775 
00776 void KWindowSystem::raiseWindow( WId win )
00777 {
00778     NETRootInfo info( QX11Info::display(), NET::Supported );
00779     if( info.isSupported( NET::WM2RestackWindow ))
00780         info.restackRequest( win, NET::FromTool, None, Above, QX11Info::appUserTime());
00781     else
00782         XRaiseWindow( QX11Info::display(), win );
00783 }
00784 
00785 void KWindowSystem::lowerWindow( WId win )
00786 {
00787     NETRootInfo info( QX11Info::display(), NET::Supported );
00788     if( info.isSupported( NET::WM2RestackWindow ))
00789         info.restackRequest( win, NET::FromTool, None, Below, QX11Info::appUserTime());
00790     else
00791         XLowerWindow( QX11Info::display(), win );
00792 }
00793 
00794 bool KWindowSystem::compositingActive()
00795 {
00796     if( QX11Info::display()) {
00797         init( INFO_BASIC );
00798         if (s_d_func()->haveXfixes) {
00799             return s_d_func()->compositingEnabled;
00800         } else {
00801             create_atoms();
00802             return XGetSelectionOwner( QX11Info::display(), net_wm_cm );
00803         }
00804     } else { // work even without QApplication instance
00805         Display* dpy = XOpenDisplay( NULL );
00806         create_atoms( dpy );
00807         bool ret = XGetSelectionOwner( dpy, net_wm_cm ) != None;
00808         XCloseDisplay( dpy );
00809         return ret;
00810     }
00811 }
00812 
00813 QRect KWindowSystem::workArea( int desktop )
00814 {
00815     init( INFO_BASIC );
00816     int desk  = (desktop > 0 && desktop <= (int) s_d_func()->numberOfDesktops() ) ? desktop : currentDesktop();
00817     if ( desk <= 0 )
00818         return QApplication::desktop()->geometry();
00819 
00820     NETRect r = s_d_func()->workArea( desk );
00821     if( r.size.width <= 0 || r.size.height <= 0 ) // not set
00822         return QApplication::desktop()->geometry();
00823 
00824     return QRect( r.pos.x, r.pos.y, r.size.width, r.size.height );
00825 }
00826 
00827 QRect KWindowSystem::workArea( const QList<WId>& exclude, int desktop )
00828 {
00829     init( INFO_WINDOWS ); // invalidates s_d_func's return value
00830     KWindowSystemPrivate* const s_d = s_d_func();
00831 
00832     QRect all = QApplication::desktop()->geometry();
00833     QRect a = all;
00834 
00835     if (desktop == -1)
00836         desktop = s_d->currentDesktop();
00837 
00838     QList<WId>::ConstIterator it1;
00839     for( it1 = s_d->windows.constBegin(); it1 != s_d->windows.constEnd(); ++it1 ) {
00840 
00841         if(exclude.contains(*it1))
00842             continue;
00843 
00844 // Kicker (very) extensively calls this function, causing hundreds of roundtrips just
00845 // to repeatedly find out struts of all windows. Therefore strut values for strut
00846 // windows are cached here.
00847         NETStrut strut;
00848         QList< KWindowSystemPrivate::StrutData >::Iterator it2 = s_d->strutWindows.begin();
00849         for( ; it2 != s_d->strutWindows.end(); ++it2 )
00850             if( (*it2).window == *it1 )
00851                 break;
00852 
00853             if( it2 != s_d->strutWindows.end()) {
00854                 if(!((*it2).desktop == desktop || (*it2).desktop == NETWinInfo::OnAllDesktops ))
00855                     continue;
00856 
00857                 strut = (*it2).strut;
00858             } else if( s_d->possibleStrutWindows.contains( *it1 ) ) {
00859 
00860                 NETWinInfo info( QX11Info::display(), (*it1), QX11Info::appRootWindow(), NET::WMStrut | NET::WMDesktop);
00861                 strut = info.strut();
00862                 s_d->possibleStrutWindows.removeAll( *it1 );
00863                 s_d->strutWindows.append( KWindowSystemPrivate::StrutData( *it1, info.strut(), info.desktop()));
00864 
00865                 if( !(info.desktop() == desktop || info.desktop() == NETWinInfo::OnAllDesktops) )
00866                     continue;
00867             } else
00868                 continue; // not a strut window
00869 
00870         QRect r = all;
00871         if ( strut.left > 0 )
00872             r.setLeft( r.left() + (int) strut.left );
00873         if ( strut.top > 0 )
00874             r.setTop( r.top() + (int) strut.top );
00875         if ( strut.right > 0  )
00876             r.setRight( r.right() - (int) strut.right );
00877         if ( strut.bottom > 0  )
00878             r.setBottom( r.bottom() - (int) strut.bottom );
00879 
00880         a = a.intersect(r);
00881     }
00882     return a;
00883 }
00884 
00885 QString KWindowSystem::desktopName( int desktop )
00886 {
00887     init( INFO_BASIC );
00888     KWindowSystemPrivate* const s_d = s_d_func();
00889 
00890     bool isDesktopSane = (desktop > 0 && desktop <= (int) s_d->numberOfDesktops());
00891     const char* name = s_d->desktopName( isDesktopSane ? desktop : currentDesktop() );
00892 
00893     if ( name && name[0] )
00894         return QString::fromUtf8( name );
00895 
00896     return i18n("Desktop %1",  desktop );
00897 }
00898 
00899 void KWindowSystem::setDesktopName( int desktop, const QString& name )
00900 {
00901     KWindowSystemPrivate* const s_d = s_d_func();
00902 
00903     if (desktop <= 0 || desktop > (int) numberOfDesktops() )
00904         desktop = currentDesktop();
00905 
00906     if( s_d ) {
00907         s_d->setDesktopName( desktop, name.toUtf8().constData() );
00908         return;
00909     }
00910 
00911     NETRootInfo info( QX11Info::display(), 0 );
00912     info.setDesktopName( desktop, name.toUtf8().constData() );
00913 }
00914 
00915 bool KWindowSystem::showingDesktop()
00916 {
00917     init( INFO_BASIC );
00918     return s_d_func()->showingDesktop();
00919 }
00920 
00921 void KWindowSystem::setUserTime( WId win, long time )
00922 {
00923     NETWinInfo info( QX11Info::display(), win, QX11Info::appRootWindow(), 0 );
00924     info.setUserTime( time );
00925 }
00926 
00927 void KWindowSystem::setExtendedStrut( WId win, int left_width, int left_start, int left_end,
00928     int right_width, int right_start, int right_end, int top_width, int top_start, int top_end,
00929     int bottom_width, int bottom_start, int bottom_end )
00930 {
00931     NETWinInfo info( QX11Info::display(), win, QX11Info::appRootWindow(), 0 );
00932     NETExtendedStrut strut;
00933     strut.left_width = left_width;
00934     strut.right_width = right_width;
00935     strut.top_width = top_width;
00936     strut.bottom_width = bottom_width;
00937     strut.left_start = left_start;
00938     strut.left_end = left_end;
00939     strut.right_start = right_start;
00940     strut.right_end = right_end;
00941     strut.top_start = top_start;
00942     strut.top_end = top_end;
00943     strut.bottom_start = bottom_start;
00944     strut.bottom_end = bottom_end;
00945     info.setExtendedStrut( strut );
00946     NETStrut oldstrut;
00947     oldstrut.left = left_width;
00948     oldstrut.right = right_width;
00949     oldstrut.top = top_width;
00950     oldstrut.bottom = bottom_width;
00951     info.setStrut( oldstrut );
00952 }
00953 
00954 void KWindowSystem::setStrut( WId win, int left, int right, int top, int bottom )
00955 {
00956     int w = XDisplayWidth( QX11Info::display(), DefaultScreen( QX11Info::display()));
00957     int h = XDisplayHeight( QX11Info::display(), DefaultScreen( QX11Info::display()));
00958     setExtendedStrut( win, left, 0, left != 0 ? w : 0, right, 0, right != 0 ? w : 0,
00959         top, 0, top != 0 ? h : 0, bottom, 0, bottom != 0 ? h : 0 );
00960 }
00961 
00962 bool KWindowSystem::icccmCompliantMappingState()
00963 {
00964     static enum { noidea, yes, no } wm_is_1_2_compliant = noidea;
00965     if( wm_is_1_2_compliant == noidea ) {
00966         NETRootInfo info( QX11Info::display(), NET::Supported );
00967         wm_is_1_2_compliant = info.isSupported( NET::Hidden ) ? yes : no;
00968     }
00969     return wm_is_1_2_compliant == yes;
00970 }
00971 
00972 bool KWindowSystem::allowedActionsSupported()
00973 {
00974     static enum { noidea, yes, no } wm_supports_allowed_actions = noidea;
00975     if( wm_supports_allowed_actions == noidea ) {
00976         NETRootInfo info( QX11Info::display(), NET::Supported );
00977         wm_supports_allowed_actions = info.isSupported( NET::WM2AllowedActions ) ? yes : no;
00978     }
00979     return wm_supports_allowed_actions == yes;
00980 }
00981 
00982 QString KWindowSystem::readNameProperty( WId win, unsigned long atom )
00983 {
00984     XTextProperty tp;
00985     char **text = NULL;
00986     int count;
00987     QString result;
00988     if ( XGetTextProperty( QX11Info::display(), win, &tp, atom ) != 0 && tp.value != NULL ) {
00989         create_atoms();
00990 
00991         if ( tp.encoding == kwm_utf8_string ) {
00992             result = QString::fromUtf8 ( (const char*) tp.value );
00993         } else if ( XmbTextPropertyToTextList( QX11Info::display(), &tp, &text, &count) == Success &&
00994                   text != NULL && count > 0 ) {
00995             result = QString::fromLocal8Bit( text[0] );
00996         } else if ( tp.encoding == XA_STRING )
00997             result = QString::fromLocal8Bit( (const char*) tp.value );
00998         if( text != NULL )
00999             XFreeStringList( text );
01000         XFree( tp.value );
01001     }
01002     return result;
01003 }
01004 
01005 void KWindowSystem::doNotManage( const QString& title )
01006 {
01007     QDBusInterface("org.kde.kwin", "/KWin", "org.kde.KWin", QDBusConnection::sessionBus())
01008         .call("doNotManage", title);
01009 }
01010 
01011 void KWindowSystem::allowExternalProcessWindowActivation( int pid )
01012 {
01013     // Normally supported by X11, but may depend on some window managers ?
01014     Q_UNUSED(pid)
01015 }
01016 
01017 void KWindowSystem::setBlockingCompositing( WId window, bool active )
01018 {
01019     NETWinInfo info( QX11Info::display(), window, QX11Info::appRootWindow(), 0 );
01020     info.setBlockingCompositing( active );
01021 }
01022 
01023 
01024 bool KWindowSystem::mapViewport()
01025 {
01026     KWindowSystemPrivate* const s_d = s_d_func();
01027     if( s_d )
01028         return s_d->mapViewport();
01029     // avoid creating KWindowSystemPrivate
01030     NETRootInfo infos( QX11Info::display(), NET::Supported );
01031     if( !infos.isSupported( NET::DesktopViewport ))
01032         return false;
01033     NETRootInfo info( QX11Info::display(), NET::NumberOfDesktops | NET::CurrentDesktop | NET::DesktopGeometry );
01034     if( info.numberOfDesktops( true ) <= 1
01035         && ( info.desktopGeometry( info.currentDesktop( true )).width > QApplication::desktop()->width()
01036             || info.desktopGeometry( info.currentDesktop( true )).height > QApplication::desktop()->height()))
01037         return true;
01038     return false;
01039 }
01040 
01041 int KWindowSystem::viewportToDesktop( const QPoint& p )
01042 {
01043     init( INFO_BASIC );
01044     KWindowSystemPrivate* const s_d = s_d_func();
01045     NETSize s = s_d->desktopGeometry( s_d->currentDesktop( true ));
01046     QSize vs = qApp->desktop()->size();
01047     int xs = s.width / vs.width();
01048     int x = p.x() < 0 ? 0 : p.x() >= s.width ? xs - 1 : p.x() / vs.width();
01049     int ys = s.height / vs.height();
01050     int y = p.y() < 0 ? 0 : p.y() >= s.height ? ys - 1 : p.y() / vs.height();
01051     return y * xs + x + 1;
01052 }
01053 
01054 int KWindowSystem::viewportWindowToDesktop( const QRect& r )
01055 {
01056     init( INFO_BASIC );
01057     KWindowSystemPrivate* const s_d = s_d_func();
01058     QPoint p = r.center();
01059     // make absolute
01060     p = QPoint( p.x() + s_d->desktopViewport( s_d->currentDesktop( true )).x,
01061         p.y() + s_d->desktopViewport( s_d->currentDesktop( true )).y );
01062     NETSize s = s_d->desktopGeometry( s_d->currentDesktop( true ));
01063     QSize vs = qApp->desktop()->size();
01064     int xs = s.width / vs.width();
01065     int x = p.x() < 0 ? 0 : p.x() >= s.width ? xs - 1 : p.x() / vs.width();
01066     int ys = s.height / vs.height();
01067     int y = p.y() < 0 ? 0 : p.y() >= s.height ? ys - 1 : p.y() / vs.height();
01068     return y * xs + x + 1;
01069 }
01070 
01071 QPoint KWindowSystem::desktopToViewport( int desktop, bool absolute )
01072 {
01073     init( INFO_BASIC );
01074     KWindowSystemPrivate* const s_d = s_d_func();
01075     NETSize s = s_d->desktopGeometry( s_d->currentDesktop( true ));
01076     QSize vs = qApp->desktop()->size();
01077     int xs = s.width / vs.width();
01078     int ys = s.height / vs.height();
01079     if( desktop <= 0 || desktop > xs * ys )
01080         return QPoint( 0, 0 );
01081     --desktop;
01082     QPoint ret( vs.width() * ( desktop % xs ), vs.height() * ( desktop / xs ));
01083     if( !absolute ) {
01084         ret = QPoint( ret.x() - s_d->desktopViewport( s_d->currentDesktop( true )).x,
01085             ret.y() - s_d->desktopViewport( s_d->currentDesktop( true )).y );
01086         if( ret.x() >= s.width )
01087             ret.setX( ret.x() - s.width );
01088         if( ret.x() < 0 )
01089             ret.setX( ret.x() + s.width );
01090         if( ret.y() >= s.height )
01091             ret.setY( ret.y() - s.height );
01092         if( ret.y() < 0 )
01093             ret.setY( ret.y() + s.height );
01094     }
01095     return ret;
01096 }
01097 
01098 QPoint KWindowSystem::constrainViewportRelativePosition( const QPoint& pos )
01099 {
01100     init( INFO_BASIC );
01101     KWindowSystemPrivate* const s_d = s_d_func();
01102     NETSize s = s_d->desktopGeometry( s_d->currentDesktop( true ));
01103     NETPoint c = s_d->desktopViewport( s_d->currentDesktop( true ));
01104     int x = ( pos.x() + c.x ) % s.width;
01105     int y = ( pos.y() + c.y ) % s.height;
01106     if( x < 0 )
01107         x += s.width;
01108     if( y < 0 )
01109         y += s.height;
01110     return QPoint( x - c.x, y - c.y );
01111 }
01112 
01113 #include "kwindowsystem.moc"

KDEUI

Skip menu "KDEUI"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Modules
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.7.5
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal