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