kwin.cpp

00001 /* This file is part of the KDE libraries
00002     Copyright (C) 1999 Matthias Ettrich (ettrich@kde.org)
00003 
00004     $Id: kwin.cpp 586837 2006-09-20 18:19:59Z mueller $
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 <stdlib.h>
00023 #include <unistd.h>
00024 
00025 #ifdef HAVE_SYSENT_H
00026 #include <sysent.h>
00027 #endif
00028 
00029 #include <kuniqueapplication.h>
00030 #include <qbitmap.h>
00031 #include <qimage.h>
00032 #include <qwhatsthis.h>
00033 #include <qcstring.h>
00034 #include <qdialog.h>
00035 
00036 #include "config.h"
00037 #include "kwin.h"
00038 #include "kapplication.h"
00039 
00040 #include <kglobal.h>
00041 #include <kiconloader.h>
00042 #include <kdebug.h>
00043 
00044 #include <kdatastream.h>
00045 #include <klocale.h>
00046 #include <dcopclient.h>
00047 #include <dcopref.h>
00048 #ifdef Q_WS_X11
00049 #include <kstartupinfo.h>
00050 #include <kxerrorhandler.h>
00051 
00052 #include <X11/Xlib.h>
00053 #include <X11/Xatom.h>
00054 #include <X11/Xutil.h>
00055 
00056 #include "netwm.h"
00057 
00058 static bool atoms_created = false;
00059 extern Atom qt_wm_protocols;
00060 extern Time qt_x_time;
00061 extern Time qt_x_user_time;
00062 
00063 static Atom net_wm_context_help;
00064 static Atom kde_wm_change_state;
00065 static Atom kde_wm_window_opacity;
00066 static Atom kde_wm_window_shadow;
00067 static Atom kwin_UTF8_STRING;
00068 
00069 static void kwin_net_create_atoms() {
00070     if (!atoms_created){
00071     const int max = 20;
00072     Atom* atoms[max];
00073     const char* names[max];
00074     Atom atoms_return[max];
00075     int n = 0;
00076 
00077     atoms[n] = &net_wm_context_help;
00078     names[n++] = "_NET_WM_CONTEXT_HELP";
00079 
00080     atoms[n] = &kde_wm_change_state;
00081     names[n++] = "_KDE_WM_CHANGE_STATE";
00082         
00083         atoms[n] = &kde_wm_window_opacity;
00084         names[n++] = (char*) "_KDE_WM_WINDOW_OPACITY";
00085 
00086         atoms[n] = &kde_wm_window_shadow;
00087         names[n++] = (char*) "_KDE_WM_WINDOW_SHADOW";
00088 
00089     // we need a const_cast for the shitty X API
00090     XInternAtoms( qt_xdisplay(), const_cast<char**>(names), n, false, atoms_return );
00091     for (int i = 0; i < n; i++ )
00092         *atoms[i] = atoms_return[i];
00093 
00094     atoms_created = True;
00095     }
00096 }
00097 #endif
00098 
00099 /*
00100   Sends a client message to the ROOT window.
00101  */
00102 #ifdef Q_WS_X11
00103 static void sendClientMessageToRoot(Window w, Atom a, long x, long y = 0, long z = 0 ){
00104   XEvent ev;
00105   long mask;
00106 
00107   memset(&ev, 0, sizeof(ev));
00108   ev.xclient.type = ClientMessage;
00109   ev.xclient.window = w;
00110   ev.xclient.message_type = a;
00111   ev.xclient.format = 32;
00112   ev.xclient.data.l[0] = x;
00113   ev.xclient.data.l[1] = y;
00114   ev.xclient.data.l[2] = z;
00115   mask = SubstructureRedirectMask;
00116   XSendEvent(qt_xdisplay(), qt_xrootwin(), False, mask, &ev);
00117 }
00118 #endif
00119 
00120 /*
00121   Send a client message to window w
00122  */
00123 #ifdef Q_WS_X11
00124 static void sendClientMessage(Window w, Atom a, long x){
00125   XEvent ev;
00126   long mask;
00127 
00128   memset(&ev, 0, sizeof(ev));
00129   ev.xclient.type = ClientMessage;
00130   ev.xclient.window = w;
00131   ev.xclient.message_type = a;
00132   ev.xclient.format = 32;
00133   ev.xclient.data.l[0] = x;
00134   ev.xclient.data.l[1] = CurrentTime;
00135   mask = 0L;
00136   if (w == qt_xrootwin())
00137     mask = SubstructureRedirectMask;        /* magic! */
00138   XSendEvent(qt_xdisplay(), w, False, mask, &ev);
00139 }
00140 #endif
00141 
00142 #ifdef Q_WS_X11
00143 namespace
00144 {
00145 class ContextWidget : public QWidget
00146 {
00147 public:
00148     ContextWidget();
00149     virtual bool x11Event( XEvent * ev);
00150 };
00151 
00152 ContextWidget::ContextWidget()
00153     : QWidget(0,0)
00154     {
00155     kwin_net_create_atoms();
00156     kapp->installX11EventFilter( this );
00157     QWhatsThis::enterWhatsThisMode();
00158     QCursor c = *QApplication::overrideCursor();
00159     QWhatsThis::leaveWhatsThisMode();
00160     XGrabPointer( qt_xdisplay(), qt_xrootwin(), true,
00161               (uint)( ButtonPressMask | ButtonReleaseMask |
00162                   PointerMotionMask | EnterWindowMask |
00163                   LeaveWindowMask ),
00164               GrabModeAsync, GrabModeAsync,
00165               None, c.handle(), CurrentTime );
00166     qApp->enter_loop();
00167     }
00168 
00169 
00170 bool ContextWidget::x11Event( XEvent * ev)
00171     {
00172     if ( ev->type == ButtonPress && ev->xbutton.button == Button1 ) {
00173         XUngrabPointer( qt_xdisplay(), ev->xbutton.time );
00174         Window root;
00175         Window child = qt_xrootwin();
00176         int root_x, root_y, lx, ly;
00177         uint state;
00178         Window w;
00179         do {
00180         w = child;
00181         XQueryPointer( qt_xdisplay(), w, &root, &child,
00182                    &root_x, &root_y, &lx, &ly, &state );
00183         } while  ( child != None && child != w );
00184 
00185         ::sendClientMessage(w, qt_wm_protocols, net_wm_context_help);
00186         XEvent e = *ev;
00187         e.xbutton.window = w;
00188         e.xbutton.subwindow = w;
00189         e.xbutton.x = lx;
00190         e.xbutton.y = ly;
00191         XSendEvent( qt_xdisplay(), w, true, ButtonPressMask, &e );
00192         qApp->exit_loop();
00193         return true;
00194     }
00195     return false;
00196     }
00197 } // namespace
00198 #endif
00199 
00200 void KWin::invokeContextHelp()
00201 {
00202 #ifdef Q_WS_X11
00203     ContextWidget w;
00204 #endif
00205 }
00206 
00207 void KWin::setSystemTrayWindowFor( WId trayWin, WId forWin )
00208 {
00209 #ifdef Q_WS_X11
00210     NETWinInfo info( qt_xdisplay(), trayWin, qt_xrootwin(), 0 );
00211     if ( !forWin )
00212     forWin = qt_xrootwin();
00213     info.setKDESystemTrayWinFor( forWin );
00214     NETRootInfo rootinfo( qt_xdisplay(), NET::Supported );
00215     if( !rootinfo.isSupported( NET::WMKDESystemTrayWinFor )) {
00216         DCOPRef ref( "kded", "kded" );
00217         if( !ref.send( "loadModule", QCString( "kdetrayproxy" )))
00218             kdWarning( 176 ) << "Loading of kdetrayproxy failed." << endl;
00219     }
00220 #endif
00221 }
00222 
00223 void KWin::activateWindow( WId win, long time )
00224 {
00225 #ifdef Q_WS_X11
00226     NETRootInfo info( qt_xdisplay(), 0 );
00227     if( time == 0 )
00228         time = qt_x_user_time;
00229     info.setActiveWindow( win, NET::FromApplication, time,
00230         kapp->activeWindow() ? kapp->activeWindow()->winId() : 0 );
00231 #endif // Q_WS_X11 ...
00232     KUniqueApplication::setHandleAutoStarted();
00233 }
00234 
00235 void KWin::forceActiveWindow( WId win, long time )
00236 {
00237 #ifdef Q_WS_X11
00238     NETRootInfo info( qt_xdisplay(), 0 );
00239     if( time == 0 )
00240         time = qt_x_time;
00241     info.setActiveWindow( win, NET::FromTool, time, 0 );
00242 #endif // Q_WS_X11
00243     KUniqueApplication::setHandleAutoStarted();
00244 }
00245 
00246 void KWin::setActiveWindow( WId win )
00247 {
00248 #ifdef Q_WS_X11
00249     NETRootInfo info( qt_xdisplay(), 0 );
00250     info.setActiveWindow( win, NET::FromUnknown, 0, 0 );
00251 #endif
00252     KUniqueApplication::setHandleAutoStarted();
00253 }
00254 
00255 void KWin::demandAttention( WId win, bool set )
00256 {
00257 #ifdef Q_WS_X11
00258     NETWinInfo info( qt_xdisplay(), win, qt_xrootwin(), 0 );
00259     info.setState( set ? NET::DemandsAttention : 0, NET::DemandsAttention );
00260 #endif
00261 }
00262 
00263 void KWin::setUserTime( WId win, long time )
00264 {
00265 #ifdef Q_WS_X11
00266     NETWinInfo info( qt_xdisplay(), win, qt_xrootwin(), 0 );
00267     info.setUserTime( time );
00268 #endif
00269 }
00270 
00271 KWin::WindowInfo KWin::windowInfo( WId win, unsigned long properties, unsigned long properties2 )
00272 {
00273     return WindowInfo( win, properties, properties2 );
00274 }
00275 
00276 
00277 WId KWin::transientFor( WId win )
00278 {
00279 #ifdef Q_WS_X11
00280     KXErrorHandler handler; // ignore badwindow
00281     Window transient_for = None;
00282     if( XGetTransientForHint( qt_xdisplay(), win, &transient_for ))
00283         return transient_for;
00284     // XGetTransientForHint() did sync
00285     return None;
00286 #else
00287     return 0L;
00288 #endif
00289 }
00290 
00291 void KWin::setMainWindow( QWidget* subwindow, WId mainwindow )
00292 {
00293 #ifdef Q_WS_X11
00294     if( mainwindow != 0 )
00295     {
00296         /*
00297          Grmbl. See QDialog::show(). That should get fixed in Qt somehow.
00298         */
00299         if( qt_cast< QDialog* >( subwindow ) != NULL
00300             && subwindow->parentWidget() == NULL
00301             && kapp->mainWidget() != NULL )
00302         {
00303             kdWarning() << "KWin::setMainWindow(): There either mustn't be kapp->mainWidget(),"
00304                 " or the dialog must have a non-NULL parent, otherwise Qt will reset the change. Bummer." << endl;
00305         }
00306         XSetTransientForHint( qt_xdisplay(), subwindow->winId(), mainwindow );
00307     }
00308     else
00309         XDeleteProperty( qt_xdisplay(), subwindow->winId(), XA_WM_TRANSIENT_FOR );
00310 #endif
00311 }
00312 
00313 WId KWin::groupLeader( WId win )
00314 {
00315 #ifdef Q_WS_X11
00316     KXErrorHandler handler; // ignore badwindow
00317     XWMHints *hints = XGetWMHints( qt_xdisplay(), win );
00318     Window window_group = None;
00319     if ( hints )
00320     {
00321         if( hints->flags & WindowGroupHint )
00322             window_group = hints->window_group;
00323         XFree( reinterpret_cast< char* >( hints ));
00324     }
00325     // XGetWMHints() did sync
00326     return window_group;
00327 #else
00328     return 0L;
00329 #endif
00330 }
00331 
00332 // this one is deprecated, KWin::WindowInfo should be used instead
00333 KWin::Info KWin::info( WId win )
00334 {
00335     Info w;
00336 #ifdef Q_WS_X11
00337     NETWinInfo inf( qt_xdisplay(), win, qt_xrootwin(),
00338             NET::WMState |
00339             NET::WMStrut |
00340             NET::WMWindowType |
00341             NET::WMName |
00342             NET::WMVisibleName |
00343             NET::WMDesktop |
00344             NET::WMPid |
00345             NET::WMKDEFrameStrut |
00346             NET::XAWMState
00347             );
00348 
00349     w.win = win;
00350     w.state = inf.state();
00351     w.mappingState = inf.mappingState();
00352     w.strut = inf.strut();
00353     w.windowType = inf.windowType( -1U );
00354     if ( inf.name() ) {
00355     w.name = QString::fromUtf8( inf.name() );
00356     } else {
00357     char* c = 0;
00358     if ( XFetchName( qt_xdisplay(), win, &c ) != 0 ) {
00359         w.name = QString::fromLocal8Bit( c );
00360         XFree( c );
00361     }
00362     }
00363     if ( inf.visibleName() )
00364     w.visibleName = QString::fromUtf8( inf.visibleName() );
00365     else
00366     w.visibleName = w.name;
00367 
00368     w.desktop = inf.desktop();
00369     w.onAllDesktops = inf.desktop() == NETWinInfo::OnAllDesktops;
00370     w.pid = inf.pid();
00371     NETRect frame, geom;
00372     inf.kdeGeometry( frame, geom );
00373     w.geometry.setRect( geom.pos.x, geom.pos.y, geom.size.width, geom.size.height );
00374     w.frameGeometry.setRect( frame.pos.x, frame.pos.y, frame.size.width, frame.size.height );
00375 #endif
00376     return w;
00377 }
00378 
00379 QPixmap KWin::icon( WId win, int width, int height, bool scale )
00380 {
00381     return icon( win, width, height, scale, NETWM | WMHints | ClassHint | XApp );
00382 }
00383 
00384 
00385 QPixmap KWin::icon( WId win, int width, int height, bool scale, int flags )
00386 {
00387 #ifdef Q_WS_X11
00388     KXErrorHandler handler; // ignore badwindow
00389 #endif
00390     QPixmap result;
00391 #ifdef Q_WS_X11
00392     if( flags & NETWM ) {
00393         NETWinInfo info( qt_xdisplay(), win, qt_xrootwin(), NET::WMIcon );
00394         NETIcon ni = info.icon( width, height );
00395         if ( ni.data && ni.size.width > 0 && ni.size.height > 0 ) {
00396             QImage img( (uchar*) ni.data, (int) ni.size.width, (int) ni.size.height, 32, 0, 0, QImage::IgnoreEndian );
00397         img.setAlphaBuffer( true );
00398         if ( scale && width > 0 && height > 0 &&img.size() != QSize( width, height ) && !img.isNull() )
00399             img = img.smoothScale( width, height );
00400         if ( !img.isNull() )
00401             result.convertFromImage( img );
00402         return result;
00403         }
00404     }
00405 
00406     if( flags & WMHints ) {
00407         Pixmap p = None;
00408         Pixmap p_mask = None;
00409 
00410         XWMHints *hints = XGetWMHints(qt_xdisplay(), win );
00411         if (hints && (hints->flags & IconPixmapHint)){
00412             p = hints->icon_pixmap;
00413         }
00414         if (hints && (hints->flags & IconMaskHint)){
00415         p_mask = hints->icon_mask;
00416         }
00417         if (hints)
00418         XFree((char*)hints);
00419 
00420         if (p != None){
00421         Window root;
00422         int x, y;
00423         unsigned int w = 0;
00424         unsigned int h = 0;
00425             unsigned int border_w, depth;
00426         XGetGeometry(qt_xdisplay(), p, &root,
00427                  &x, &y, &w, &h, &border_w, &depth);
00428         if (w > 0 && h > 0){
00429             QPixmap pm(w, h, depth);
00430             // Always detach before doing something behind QPixmap's back.
00431             pm.detach();
00432             XCopyArea(qt_xdisplay(), p, pm.handle(),
00433                   qt_xget_temp_gc(qt_xscreen(), depth==1),
00434                   0, 0, w, h, 0, 0);
00435             if (p_mask != None){
00436                 QBitmap bm(w, h);
00437             XCopyArea(qt_xdisplay(), p_mask, bm.handle(),
00438                   qt_xget_temp_gc(qt_xscreen(), true),
00439                   0, 0, w, h, 0, 0);
00440             pm.setMask(bm);
00441             }
00442             if ( scale && width > 0 && height > 0 && !pm.isNull() &&
00443              ( (int) w != width || (int) h != height) ){
00444             result.convertFromImage( pm.convertToImage().smoothScale( width, height ) );
00445             } else {
00446             result = pm;
00447             }
00448         }
00449         }
00450     }
00451 
00452     // Since width can be any arbitrary size, but the icons cannot,
00453     // take the nearest value for best results (ignoring 22 pixel
00454     // icons as they don't exist for apps):
00455     int iconWidth;
00456     if( width < 24 )
00457         iconWidth = 16;
00458     else if( width < 40 )
00459         iconWidth = 32;
00460     else
00461         iconWidth = 48;
00462 
00463     if( flags & ClassHint ) {
00464         // Try to load the icon from the classhint if the app didn't specify
00465         // its own:
00466         if( result.isNull() ) {
00467 
00468         XClassHint  hint;
00469         if( XGetClassHint( qt_xdisplay(), win, &hint ) ) {
00470             QString className = hint.res_class;
00471 
00472             QPixmap pm = KGlobal::instance()->iconLoader()->loadIcon( className.lower(), KIcon::Small, iconWidth,
00473                                           KIcon::DefaultState, 0, true );
00474             if( scale && !pm.isNull() )
00475             result.convertFromImage( pm.convertToImage().smoothScale( width, height ) );
00476             else
00477             result = pm;
00478 
00479             XFree( hint.res_name );
00480             XFree( hint.res_class );
00481         }
00482         }
00483     }
00484 
00485     if( flags & XApp ) {
00486     // If the icon is still a null pixmap, load the 'xapp' icon
00487     // as a last resort:
00488     if ( result.isNull() ) {
00489         QPixmap pm = KGlobal::instance()->iconLoader()->loadIcon(  "xapp", KIcon::Small, iconWidth,
00490                                        KIcon::DefaultState, 0, true );
00491         if( scale && !pm.isNull() )
00492         result.convertFromImage( pm.convertToImage().smoothScale( width, height ) );
00493         else
00494         result = pm;
00495     }
00496     }
00497 #endif
00498     return result;
00499 }
00500 
00501 void KWin::setIcons( WId win, const QPixmap& icon, const QPixmap& miniIcon )
00502 {
00503 #ifdef Q_WS_X11
00504     if ( icon.isNull() )
00505     return;
00506     NETWinInfo info( qt_xdisplay(), win, qt_xrootwin(), 0 );
00507     QImage img = icon.convertToImage().convertDepth( 32 );
00508     NETIcon ni;
00509     ni.size.width = img.size().width();
00510     ni.size.height = img.size().height();
00511     ni.data = (unsigned char *) img.bits();
00512     info.setIcon( ni, true );
00513     if ( miniIcon.isNull() )
00514     return;
00515     img = miniIcon.convertToImage().convertDepth( 32 );
00516     ni.size.width = img.size().width();
00517     ni.size.height = img.size().height();
00518     ni.data = (unsigned char *) img.bits();
00519     info.setIcon( ni, false );
00520 #endif
00521 }
00522 
00523 void KWin::setType( WId win, NET::WindowType windowType )
00524 {
00525 #ifdef Q_WS_X11
00526     NETWinInfo info( qt_xdisplay(), win, qt_xrootwin(), 0 );
00527     info.setWindowType( windowType );
00528 #endif
00529 }
00530 
00531 void KWin::setState( WId win, unsigned long state )
00532 {
00533 #ifdef Q_WS_X11
00534     NETWinInfo info( qt_xdisplay(), win, qt_xrootwin(), NET::WMState );
00535     info.setState( state, state );
00536 #endif
00537 }
00538 
00539 void KWin::clearState( WId win, unsigned long state )
00540 {
00541 #ifdef Q_WS_X11
00542     NETWinInfo info( qt_xdisplay(), win, qt_xrootwin(), NET::WMState );
00543     info.setState( 0, state );
00544 #endif
00545 }
00546 
00547 void KWin::setOpacity( WId win, uint percent )
00548 {
00549 #ifdef Q_WS_X11
00550     kwin_net_create_atoms();
00551     if (percent > 99)
00552         XDeleteProperty (qt_xdisplay(), win, kde_wm_window_opacity);
00553     else
00554     {
00555         long opacity = long(0xFFFFFFFF/100.0*percent);
00556         XChangeProperty(qt_xdisplay(), win, kde_wm_window_opacity, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &opacity, 1L);
00557     }
00558 #endif
00559 }
00560 
00561 void KWin::setShadowSize( WId win, uint percent )
00562 {
00563 #ifdef Q_WS_X11
00564     kwin_net_create_atoms();
00565     long shadowSize = long(0xFFFFFFFF/100.0*percent);
00566     XChangeProperty(qt_xdisplay(), win, kde_wm_window_shadow, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &shadowSize, 1L);
00567 #endif
00568 }
00569 
00570 void KWin::setOnAllDesktops( WId win, bool b )
00571 {
00572 #ifdef Q_WS_X11
00573     NETWinInfo info( qt_xdisplay(), win, qt_xrootwin(), NET::WMDesktop );
00574     if ( b )
00575     info.setDesktop( NETWinInfo::OnAllDesktops );
00576     else if ( info.desktop()  == NETWinInfo::OnAllDesktops ) {
00577     NETRootInfo rinfo( qt_xdisplay(), NET::CurrentDesktop );
00578     info.setDesktop( rinfo.currentDesktop() );
00579     }
00580 #endif
00581 }
00582 
00583 void KWin::setOnDesktop( WId win, int desktop )
00584 {
00585 #ifdef Q_WS_X11
00586     NETWinInfo info( qt_xdisplay(), win, qt_xrootwin(), NET::WMDesktop );
00587     info.setDesktop( desktop );
00588 #endif
00589 }
00590 
00591 void KWin::setExtendedStrut( WId win, int left_width, int left_start, int left_end,
00592     int right_width, int right_start, int right_end, int top_width, int top_start, int top_end,
00593     int bottom_width, int bottom_start, int bottom_end )
00594 {
00595 #ifdef Q_WS_X11
00596     NETWinInfo info( qt_xdisplay(), win, qt_xrootwin(), 0 );
00597     NETExtendedStrut strut;
00598     strut.left_width = left_width;
00599     strut.right_width = right_width;
00600     strut.top_width = top_width;
00601     strut.bottom_width = bottom_width;
00602     strut.left_start = left_start;
00603     strut.left_end = left_end;
00604     strut.right_start = right_start;
00605     strut.right_end = right_end;
00606     strut.top_start = top_start;
00607     strut.top_end = top_end;
00608     strut.bottom_start = bottom_start;
00609     strut.bottom_end = bottom_end;
00610     info.setExtendedStrut( strut );
00611 #endif
00612 }
00613 
00614 void KWin::setStrut( WId win, int left, int right, int top, int bottom )
00615 {
00616 #ifdef Q_WS_X11
00617     NETWinInfo info( qt_xdisplay(), win, qt_xrootwin(), 0 );
00618     NETStrut strut;
00619     strut.left = left;
00620     strut.right = right;
00621     strut.top = top;
00622     strut.bottom = bottom;
00623     info.setStrut( strut );
00624 #endif
00625 }
00626 
00627 int KWin::currentDesktop()
00628 {
00629 #ifdef Q_WS_X11
00630     if (!qt_xdisplay())
00631 #endif
00632       return 1;
00633 #ifdef Q_WS_X11
00634     NETRootInfo info( qt_xdisplay(), NET::CurrentDesktop );
00635     return info.currentDesktop();
00636 #endif
00637 }
00638 
00639 int KWin::numberOfDesktops()
00640 {
00641 #ifdef Q_WS_X11
00642     if (!qt_xdisplay())
00643 #endif
00644       return 0;
00645 #ifdef Q_WS_X11
00646     NETRootInfo info( qt_xdisplay(), NET::NumberOfDesktops );
00647     return info.numberOfDesktops();
00648 #endif
00649 }
00650 
00651 void KWin::setCurrentDesktop( int desktop )
00652 {
00653 #ifdef Q_WS_X11
00654     NETRootInfo info( qt_xdisplay(), NET::CurrentDesktop );
00655     info.setCurrentDesktop( desktop );
00656 #endif
00657 }
00658 
00659 void KWin::setCurrentDesktopViewport( int desktop, QPoint viewport )
00660 {
00661 #ifdef Q_WS_X11
00662     NETRootInfo info( qt_xdisplay(), NET::CurrentDesktop );
00663     NETPoint netview;
00664     netview.x = viewport.x();
00665     netview.y = viewport.y();
00666     info.setDesktopViewport( desktop, netview );
00667 #endif
00668 }
00669 
00670 void KWin::iconifyWindow( WId win, bool animation)
00671 {
00672 #ifdef Q_WS_X11
00673     if ( !animation )
00674     {
00675         kwin_net_create_atoms();
00676     sendClientMessageToRoot( win, kde_wm_change_state, IconicState, 1 );
00677     }
00678     XIconifyWindow( qt_xdisplay(), win, qt_xscreen() );
00679 #endif
00680 }
00681 
00682 
00683 void KWin::deIconifyWindow( WId win, bool animation )
00684 {
00685 #ifdef Q_WS_X11
00686     if ( !animation )
00687     {
00688         kwin_net_create_atoms();
00689     sendClientMessageToRoot( win, kde_wm_change_state, NormalState, 1 );
00690     }
00691     XMapWindow( qt_xdisplay(), win );
00692 #endif
00693 }
00694 
00695 void KWin::raiseWindow( WId win )
00696 {
00697 #ifdef Q_WS_X11
00698     NETRootInfo info( qt_xdisplay(), NET::Supported );
00699     if( info.isSupported( NET::WM2RestackWindow ))
00700         info.restackRequest( win, None, Above );
00701     else
00702         XRaiseWindow( qt_xdisplay(), win );
00703 #endif
00704 }
00705 
00706 void KWin::lowerWindow( WId win )
00707 {
00708 #ifdef Q_WS_X11
00709     NETRootInfo info( qt_xdisplay(), NET::Supported );
00710     if( info.isSupported( NET::WM2RestackWindow ))
00711         info.restackRequest( win, None, Below );
00712     else
00713         XLowerWindow( qt_xdisplay(), win );
00714 #endif
00715 }
00716 
00717 void KWin::appStarted()
00718 {
00719 #ifdef Q_WS_X11
00720     KStartupInfo::appStarted();
00721 #endif
00722 }
00723 
00724 class KWin::WindowInfoPrivate
00725 {
00726     public:
00727     WindowInfoPrivate()
00728 #ifdef Q_WS_X11
00729     : info( NULL )
00730 #endif
00731     {}
00732 #ifdef Q_WS_X11
00733     ~WindowInfoPrivate() { delete info; }
00734     NETWinInfo* info;
00735 #endif
00736     WId win_;
00737     QString name_;
00738         QString iconic_name_;
00739     QRect geometry_;
00740         QRect frame_geometry_;
00741     int ref;
00742         bool valid;
00743     private:
00744     WindowInfoPrivate( const WindowInfoPrivate& );
00745     void operator=( const WindowInfoPrivate& );
00746 };
00747 
00748 // KWin::info() should be updated too if something has to be changed here
00749 KWin::WindowInfo::WindowInfo( WId win, unsigned long properties, unsigned long properties2 )
00750 {
00751 #ifdef Q_WS_X11
00752     KXErrorHandler handler;
00753     d = new WindowInfoPrivate;
00754     d->ref = 1;
00755     if( properties == 0 )
00756     properties = NET::WMState |
00757              NET::WMStrut |
00758              NET::WMWindowType |
00759              NET::WMName |
00760              NET::WMVisibleName |
00761                      NET::WMIconName |
00762                      NET::WMVisibleIconName |
00763              NET::WMDesktop |
00764              NET::WMPid |
00765              NET::WMKDEFrameStrut |
00766              NET::XAWMState |
00767                      NET::WMGeometry;
00768     if( properties & NET::WMVisibleIconName )
00769     properties |= NET::WMIconName | NET::WMVisibleName; // force, in case it will be used as a fallback
00770     if( properties & NET::WMVisibleName )
00771     properties |= NET::WMName; // force, in case it will be used as a fallback
00772     if( properties2 & NET::WM2ExtendedStrut )
00773         properties |= NET::WMStrut; // will be used as fallback
00774     properties |= NET::XAWMState; // force to get error detection for valid()
00775     unsigned long props[ 2 ] = { properties, properties2 };
00776     d->info = new NETWinInfo( qt_xdisplay(), win, qt_xrootwin(), props, 2 );
00777     d->win_ = win;
00778     if( properties & NET::WMName ) {
00779         if( d->info->name() && d->info->name()[ 0 ] != '\0' )
00780         d->name_ = QString::fromUtf8( d->info->name() );
00781         else
00782             d->name_ = readNameProperty( win, XA_WM_NAME );
00783     }
00784     if( properties & NET::WMIconName ) {
00785         if( d->info->iconName() && d->info->iconName()[ 0 ] != '\0' )
00786             d->iconic_name_ = QString::fromUtf8( d->info->iconName());
00787         else
00788             d->iconic_name_ = readNameProperty( win, XA_WM_ICON_NAME );
00789     }
00790     if( properties & ( NET::WMGeometry | NET::WMKDEFrameStrut )) {
00791         NETRect frame, geom;
00792         d->info->kdeGeometry( frame, geom );
00793         d->geometry_.setRect( geom.pos.x, geom.pos.y, geom.size.width, geom.size.height );
00794         d->frame_geometry_.setRect( frame.pos.x, frame.pos.y, frame.size.width, frame.size.height );
00795     }
00796     d->valid = !handler.error( false ); // no sync - NETWinInfo did roundtrips
00797 #endif
00798 }
00799 
00800 // this one is only to make QValueList<> or similar happy
00801 KWin::WindowInfo::WindowInfo()
00802     : d( NULL )
00803 {
00804 }
00805 
00806 KWin::WindowInfo::~WindowInfo()
00807 {
00808     if( d != NULL ) {
00809     if( --d->ref == 0 ) {
00810         delete d;
00811     }
00812     }
00813 }
00814 
00815 KWin::WindowInfo::WindowInfo( const WindowInfo& wininfo )
00816     : d( wininfo.d )
00817 {
00818     if( d != NULL )
00819     ++d->ref;
00820 }
00821 
00822 KWin::WindowInfo& KWin::WindowInfo::operator=( const WindowInfo& wininfo )
00823 {
00824     if( d != wininfo.d ) {
00825     if( d != NULL )
00826         if( --d->ref == 0 )
00827         delete d;
00828     d = wininfo.d;
00829     if( d != NULL )
00830         ++d->ref;
00831     }
00832     return *this;
00833 }
00834 
00835 bool KWin::WindowInfo::valid( bool withdrawn_is_valid ) const
00836 {
00837     if( !d->valid )
00838         return false;
00839     if( !withdrawn_is_valid && mappingState() == NET::Withdrawn )
00840         return false;
00841     return true;
00842 }
00843 
00844 WId KWin::WindowInfo::win() const
00845 {
00846     return d->win_;
00847 }
00848 
00849 unsigned long KWin::WindowInfo::state() const
00850 {
00851 #ifdef Q_WS_X11
00852     kdWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS ] & NET::WMState ) == 0, 176 )
00853         << "Pass NET::WMState to KWin::windowInfo()" << endl;
00854     return d->info->state();
00855 #else
00856     return 0;
00857 #endif
00858 }
00859 
00860 NET::MappingState KWin::WindowInfo::mappingState() const
00861 {
00862 #ifdef Q_WS_X11
00863     kdWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS ] & NET::XAWMState ) == 0, 176 )
00864         << "Pass NET::XAWMState to KWin::windowInfo()" << endl;
00865     return d->info->mappingState();
00866 #else
00867     return NET::Visible;
00868 #endif
00869 }
00870 
00871 NETExtendedStrut KWin::WindowInfo::extendedStrut() const
00872 {
00873 #ifdef Q_WS_X11
00874     kdWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS2 ] & NET::WM2ExtendedStrut ) == 0, 176 )
00875         << "Pass NET::WM2ExtendedStrut to second argument of KWin::windowInfo()" << endl;
00876     NETExtendedStrut ext = d->info->extendedStrut();
00877     NETStrut str = d->info->strut();
00878     if( ext.left_width == 0 && ext.right_width == 0 && ext.top_width == 0 && ext.bottom_width == 0
00879         && ( str.left != 0 || str.right != 0 || str.top != 0 || str.bottom != 0 )) {
00880         // build extended from simple
00881         if( str.left != 0 ) {
00882             ext.left_width = str.left;
00883             ext.left_start = 0;
00884             ext.left_end = XDisplayHeight( qt_xdisplay(), DefaultScreen( qt_xdisplay()));
00885         }
00886         if( str.right != 0 ) {
00887             ext.right_width = str.right;
00888             ext.right_start = 0;
00889             ext.right_end = XDisplayHeight( qt_xdisplay(), DefaultScreen( qt_xdisplay()));
00890         }
00891         if( str.top != 0 ) {
00892             ext.top_width = str.top;
00893             ext.top_start = 0;
00894             ext.top_end = XDisplayWidth( qt_xdisplay(), DefaultScreen( qt_xdisplay()));
00895         }
00896         if( str.bottom != 0 ) {
00897             ext.bottom_width = str.bottom;
00898             ext.bottom_start = 0;
00899             ext.bottom_end = XDisplayWidth( qt_xdisplay(), DefaultScreen( qt_xdisplay()));
00900         }
00901     }
00902     return ext;
00903 #else
00904     NETExtendedStrut n;
00905     return n;
00906 #endif
00907 }
00908 
00909 NETStrut KWin::WindowInfo::strut() const
00910 {
00911 #ifdef Q_WS_X11
00912     kdWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS ] & NET::WMStrut ) == 0, 176 )
00913         << "Pass NET::WMStrut to KWin::windowInfo()" << endl;
00914     return d->info->strut();
00915 #else
00916     NETStrut n;
00917     return n;
00918 #endif
00919 }
00920 
00921 NET::WindowType KWin::WindowInfo::windowType( int supported_types ) const
00922 {
00923 #ifdef Q_WS_X11
00924     kdWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS ] & NET::WMWindowType ) == 0, 176 )
00925         << "Pass NET::WMWindowType to KWin::windowInfo()" << endl;
00926     return d->info->windowType( supported_types );
00927 #else
00928     return 0;
00929 #endif
00930 }
00931 
00932 QString KWin::WindowInfo::visibleNameWithState() const
00933 {
00934     QString s = visibleName();
00935     if ( isMinimized() ) {
00936     s.prepend('(');
00937     s.append(')');
00938     }
00939     return s;
00940 }
00941 
00942 QString KWin::Info::visibleNameWithState() const
00943 {
00944     QString s = visibleName;
00945     if ( isMinimized() ) {
00946     s.prepend('(');
00947     s.append(')');
00948     }
00949     return s;
00950 }
00951 
00952 QString KWin::WindowInfo::visibleName() const
00953 {
00954 #ifdef Q_WS_X11
00955     kdWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS ] & NET::WMVisibleName ) == 0, 176 )
00956         << "Pass NET::WMVisibleName to KWin::windowInfo()" << endl;
00957     return d->info->visibleName() && d->info->visibleName()[ 0 ] != '\0'
00958         ? QString::fromUtf8(d->info->visibleName()) : name();
00959 #else
00960     return QString("name");
00961 #endif
00962 }
00963 
00964 QString KWin::WindowInfo::name() const
00965 {
00966 #ifdef Q_WS_X11
00967     kdWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS ] & NET::WMName ) == 0, 176 )
00968         << "Pass NET::WMName to KWin::windowInfo()" << endl;
00969     return d->name_;
00970 #else
00971     return QString();
00972 #endif
00973 }
00974 
00975 QString KWin::WindowInfo::visibleIconNameWithState() const
00976 {
00977     QString s = visibleIconName();
00978     if ( isMinimized() ) {
00979     s.prepend('(');
00980     s.append(')');
00981     }
00982     return s;
00983 }
00984 
00985 QString KWin::WindowInfo::visibleIconName() const
00986 {
00987 #ifdef Q_WS_X11
00988     kdWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS ] & NET::WMVisibleIconName ) == 0, 176 )
00989         << "Pass NET::WMVisibleIconName to KWin::windowInfo()" << endl;
00990     if( d->info->visibleIconName() && d->info->visibleIconName()[ 0 ] != '\0' )
00991         return QString::fromUtf8( d->info->visibleIconName());
00992     if( d->info->iconName() && d->info->iconName()[ 0 ] != '\0' )
00993         return QString::fromUtf8( d->info->iconName());
00994     if( !d->iconic_name_.isEmpty())
00995         return d->iconic_name_;
00996 #endif
00997     return visibleName();
00998 }
00999 
01000 QString KWin::WindowInfo::iconName() const
01001 {
01002 #ifdef Q_WS_X11
01003     kdWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS ] & NET::WMIconName ) == 0, 176 )
01004         << "Pass NET::WMIconName to KWin::windowInfo()" << endl;
01005     if( d->info->iconName() && d->info->iconName()[ 0 ] != '\0' )
01006         return QString::fromUtf8( d->info->iconName());
01007     if( !d->iconic_name_.isEmpty())
01008         return d->iconic_name_;
01009 #endif
01010     return name();
01011 }
01012 
01013 bool KWin::WindowInfo::isOnCurrentDesktop() const
01014 {
01015 #ifdef Q_WS_X11
01016     return isOnDesktop( KWin::currentDesktop());
01017 #else
01018     return false;
01019 #endif
01020 }
01021 
01022 bool KWin::WindowInfo::isOnDesktop( int desktop ) const
01023 {
01024 #ifdef Q_WS_X11
01025     kdWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS ] & NET::WMDesktop ) == 0, 176 )
01026         << "Pass NET::WMDesktop to KWin::windowInfo()" << endl;
01027     return d->info->desktop() == desktop || d->info->desktop() == NET::OnAllDesktops;
01028 #else
01029     return false;
01030 #endif
01031 }
01032 
01033 bool KWin::WindowInfo::onAllDesktops() const
01034 {
01035 #ifdef Q_WS_X11
01036     kdWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS ] & NET::WMDesktop ) == 0, 176 )
01037         << "Pass NET::WMDesktop to KWin::windowInfo()" << endl;
01038     return d->info->desktop() == NET::OnAllDesktops;
01039 #else
01040     return false;
01041 #endif
01042 }
01043 
01044 int KWin::WindowInfo::desktop() const
01045 {
01046 #ifdef Q_WS_X11
01047     kdWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS ] & NET::WMDesktop ) == 0, 176 )
01048         << "Pass NET::WMDesktop to KWin::windowInfo()" << endl;
01049     return d->info->desktop();
01050 #else
01051     return 1;
01052 #endif
01053 }
01054 
01055 QRect KWin::WindowInfo::geometry() const
01056 {
01057 #ifdef Q_WS_X11
01058     kdWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS ] & NET::WMGeometry ) == 0, 176 )
01059         << "Pass NET::WMGeometry to KWin::windowInfo()" << endl;
01060     return d->geometry_;
01061 #else
01062     return QRect( 100, 100, 200, 200 );
01063 #endif
01064 }
01065 
01066 QRect KWin::WindowInfo::frameGeometry() const
01067 {
01068 #ifdef Q_WS_X11
01069     kdWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS ] & NET::WMKDEFrameStrut ) == 0, 176 )
01070         << "Pass NET::WMKDEFrameStrut to KWin::windowInfo()" << endl;
01071     return d->frame_geometry_;
01072 #else
01073     return QRect();
01074 #endif
01075 }
01076 
01077 WId KWin::WindowInfo::transientFor() const
01078 {
01079 #ifdef Q_WS_X11
01080     kdWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS2 ] & NET::WM2TransientFor ) == 0, 176 )
01081         << "Pass NET::WM2TransientFor to KWin::windowInfo()" << endl;
01082     return d->info->transientFor();
01083 #else
01084     return 0;
01085 #endif
01086 }
01087 
01088 WId KWin::WindowInfo::groupLeader() const
01089 {
01090 #ifdef Q_WS_X11
01091     kdWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS2 ] & NET::WM2GroupLeader ) == 0, 176 )
01092         << "Pass NET::WM2GroupLeader to KWin::windowInfo()" << endl;
01093     return d->info->groupLeader();
01094 #else
01095     return 0;
01096 #endif
01097 }
01098 
01099 QCString KWin::WindowInfo::windowClassClass() const
01100 {
01101 #ifdef Q_WS_X11
01102     kdWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS2 ] & NET::WM2WindowClass ) == 0, 176 )
01103         << "Pass NET::WM2WindowClass to KWin::windowInfo()" << endl;
01104     return d->info->windowClassClass();
01105 #else
01106     return 0;
01107 #endif
01108 }
01109 
01110 QCString KWin::WindowInfo::windowClassName() const
01111 {
01112 #ifdef Q_WS_X11
01113     kdWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS2 ] & NET::WM2WindowClass ) == 0, 176 )
01114         << "Pass NET::WM2WindowClass to KWin::windowInfo()" << endl;
01115     return d->info->windowClassName();
01116 #else
01117     return 0;
01118 #endif
01119 }
01120 
01121 QCString KWin::WindowInfo::windowRole() const
01122 {
01123 #ifdef Q_WS_X11
01124     kdWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS2 ] & NET::WM2WindowRole ) == 0, 176 )
01125         << "Pass NET::WM2WindowRole to KWin::windowInfo()" << endl;
01126     return d->info->windowRole();
01127 #else
01128     return 0;
01129 #endif
01130 }
01131 
01132 QCString KWin::WindowInfo::clientMachine() const
01133 {
01134 #ifdef Q_WS_X11
01135     kdWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS2 ] & NET::WM2ClientMachine ) == 0, 176 )
01136         << "Pass NET::WM2ClientMachine to KWin::windowInfo()" << endl;
01137     return d->info->clientMachine();
01138 #else
01139     return 0;
01140 #endif
01141 }
01142 
01143 bool KWin::WindowInfo::actionSupported( NET::Action action ) const
01144 {
01145 #ifdef Q_WS_X11
01146     kdWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS2 ] & NET::WM2AllowedActions ) == 0, 176 )
01147         << "Pass NET::WM2AllowedActions to KWin::windowInfo()" << endl;
01148     if( allowedActionsSupported())
01149         return d->info->allowedActions() & action;
01150     else
01151 #endif
01152         return true; // no idea if it's supported or not -> pretend it is
01153 }
01154 
01155 // see NETWM spec section 7.6
01156 bool KWin::WindowInfo::isMinimized() const
01157 {
01158 #ifdef Q_WS_X11
01159     if( mappingState() != NET::Iconic )
01160         return false;
01161     // NETWM 1.2 compliant WM - uses NET::Hidden for minimized windows
01162     if(( state() & NET::Hidden ) != 0
01163     && ( state() & NET::Shaded ) == 0 ) // shaded may have NET::Hidden too
01164         return true;
01165     // older WMs use WithdrawnState for other virtual desktops
01166     // and IconicState only for minimized
01167     return icccmCompliantMappingState() ? false : true;
01168 #else
01169     return false;
01170 #endif
01171 }
01172 
01173 bool KWin::Info::isMinimized() const
01174 {
01175 #ifdef Q_WS_X11
01176     if( mappingState != NET::Iconic )
01177         return false;
01178     // NETWM 1.2 compliant WM - uses NET::Hidden for minimized windows
01179     if(( state & NET::Hidden ) != 0
01180     && ( state & NET::Shaded ) == 0 ) // shaded may have NET::Hidden too
01181         return true;
01182     // older WMs use WithdrawnState for other virtual desktops
01183     // and IconicState only for minimized
01184     return icccmCompliantMappingState() ? false : true;
01185 #else
01186     return false;
01187 #endif
01188 }
01189 
01190 bool KWin::Info::isIconified() const
01191 {
01192     return isMinimized();
01193 }
01194 
01195 bool KWin::icccmCompliantMappingState()
01196 {
01197 #ifdef Q_WS_X11
01198     static enum { noidea, yes, no } wm_is_1_2_compliant = noidea;
01199     if( wm_is_1_2_compliant == noidea ) {
01200         NETRootInfo info( qt_xdisplay(), NET::Supported );
01201         wm_is_1_2_compliant = info.isSupported( NET::Hidden ) ? yes : no;
01202     }
01203     return wm_is_1_2_compliant == yes;
01204 #else
01205     return false;
01206 #endif
01207 }
01208 
01209 bool KWin::allowedActionsSupported()
01210 {
01211 #ifdef Q_WS_X11
01212     static enum { noidea, yes, no } wm_supports_allowed_actions = noidea;
01213     if( wm_supports_allowed_actions == noidea ) {
01214         NETRootInfo info( qt_xdisplay(), NET::Supported );
01215         wm_supports_allowed_actions = info.isSupported( NET::WM2AllowedActions ) ? yes : no;
01216     }
01217     return wm_supports_allowed_actions == yes;
01218 #else
01219     return false;
01220 #endif
01221 }
01222 
01223 QString KWin::readNameProperty( WId win, unsigned long atom )
01224 {
01225 #ifdef Q_WS_X11
01226     XTextProperty tp;
01227     char **text = NULL;
01228     int count;
01229 #endif
01230     QString result;
01231 #ifdef Q_WS_X11
01232     if ( XGetTextProperty( qt_xdisplay(), win, &tp, atom ) != 0 && tp.value != NULL ) 
01233     {
01234         if (!kwin_UTF8_STRING)
01235           kwin_UTF8_STRING = XInternAtom( qt_xdisplay(), "UTF8_STRING", False);
01236 
01237         if ( XmbTextPropertyToTextList( qt_xdisplay(), &tp, &text, &count) == Success &&
01238                   text != NULL && count > 0 ) {
01239             result = QString::fromLocal8Bit( text[0] );
01240         } else if ( tp.encoding == kwin_UTF8_STRING ) {
01241             result = QString::fromUtf8 ( (const char*) tp.value );
01242         } else if ( tp.encoding == XA_STRING )
01243             result = QString::fromLocal8Bit( (const char*) tp.value );
01244         if( text != NULL )
01245             XFreeStringList( text );
01246         XFree( tp.value );
01247     }
01248 #endif
01249     return result;
01250 }
01251 
01252 //#endif
KDE Home | KDE Accessibility Home | Description of Access Keys