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"
KDE 4.7 API Reference