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