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

KDEUI

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

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.6.1
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