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