kdecore Library API Documentation

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,v 1.58 2002/03/01 14:52:04 elter Exp $
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., 59 Temple Place - Suite 330,
00019     Boston, MA 02111-1307, 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 <qapplication.h>
00030 #include <qbitmap.h>
00031 #include <qimage.h>
00032 #include <qwhatsthis.h>
00033 #include <qcstring.h>
00034 
00035 #ifndef Q_WS_QWS
00036 #include "kwin.h"
00037 #include "kapplication.h"
00038 
00039 #include <kglobal.h>
00040 #include <kiconloader.h>
00041 
00042 #include <kdatastream.h>
00043 #include <klocale.h>
00044 #include <dcopclient.h>
00045 #include <kstartupinfo.h>
00046 
00047 #include <X11/Xlib.h>
00048 #include <X11/Xatom.h>
00049 #include <X11/Xutil.h>
00050 
00051 #include "netwm.h"
00052 
00053 static bool atoms_created = FALSE;
00054 extern Atom qt_wm_protocols;
00055 extern Atom qt_wm_state;
00056 extern Time qt_x_time;
00057 
00058 // Fix for --enable-final. This gets undefined at the end of this file.
00059 #ifndef None
00060 #define None    0L
00061 #endif
00062 
00063 Atom net_wm_context_help;
00064 static Atom kde_wm_change_state;
00065 void kwin_net_create_atoms() {
00066     if (!atoms_created){
00067     const int max = 20;
00068     Atom* atoms[max];
00069     const char* names[max];
00070     Atom atoms_return[max];
00071     int n = 0;
00072 
00073     atoms[n] = &net_wm_context_help;
00074     names[n++] = "_NET_WM_CONTEXT_HELP";
00075 
00076     atoms[n] = &kde_wm_change_state;
00077     names[n++] = "_KDE_WM_CHANGE_STATE";
00078 
00079     // we need a const_cast for the shitty X API
00080     XInternAtoms( qt_xdisplay(), const_cast<char**>(names), n, FALSE, atoms_return );
00081     for (int i = 0; i < n; i++ )
00082         *atoms[i] = atoms_return[i];
00083 
00084     atoms_created = True;
00085     }
00086 }
00087 
00088 /*
00089   Sends a client message to the ROOT window.
00090  */
00091 static void sendClientMessageToRoot(Window w, Atom a, long x, long y = 0, long z = 0 ){
00092   XEvent ev;
00093   long mask;
00094 
00095   memset(&ev, 0, sizeof(ev));
00096   ev.xclient.type = ClientMessage;
00097   ev.xclient.window = w;
00098   ev.xclient.message_type = a;
00099   ev.xclient.format = 32;
00100   ev.xclient.data.l[0] = x;
00101   ev.xclient.data.l[1] = y;
00102   ev.xclient.data.l[2] = z;
00103   mask = SubstructureRedirectMask;
00104   XSendEvent(qt_xdisplay(), qt_xrootwin(), False, mask, &ev);
00105 }
00106 
00107 /*
00108   Send a client message to window w
00109  */
00110 static void sendClientMessage(Window w, Atom a, long x){
00111   XEvent ev;
00112   long mask;
00113 
00114   memset(&ev, 0, sizeof(ev));
00115   ev.xclient.type = ClientMessage;
00116   ev.xclient.window = w;
00117   ev.xclient.message_type = a;
00118   ev.xclient.format = 32;
00119   ev.xclient.data.l[0] = x;
00120   ev.xclient.data.l[1] = CurrentTime;
00121   mask = 0L;
00122   if (w == qt_xrootwin())
00123     mask = SubstructureRedirectMask;        /* magic! */
00124   XSendEvent(qt_xdisplay(), w, False, mask, &ev);
00125 }
00126 
00127 class ContextWidget : public QWidget
00128 {
00129 public:
00130     ContextWidget()
00131     : QWidget(0,0)
00132     {
00133     kwin_net_create_atoms();
00134     kapp->installX11EventFilter( this );
00135     QWhatsThis::enterWhatsThisMode();
00136     QCursor c = *QApplication::overrideCursor();
00137     QWhatsThis::leaveWhatsThisMode();
00138     XGrabPointer( qt_xdisplay(), qt_xrootwin(), TRUE,
00139               (uint)( ButtonPressMask | ButtonReleaseMask |
00140                   PointerMotionMask | EnterWindowMask |
00141                   LeaveWindowMask ),
00142               GrabModeAsync, GrabModeAsync,
00143               None, c.handle(), CurrentTime );
00144     qApp->enter_loop();
00145     }
00146 
00147 
00148     bool x11Event( XEvent * ev)
00149     {
00150     if ( ev->type == ButtonPress && ev->xbutton.button == Button1 ) {
00151         XUngrabPointer( qt_xdisplay(), ev->xbutton.time );
00152         Window root;
00153         Window child = qt_xrootwin();
00154         int root_x, root_y, lx, ly;
00155         uint state;
00156         Window w;
00157         do {
00158         w = child;
00159         XQueryPointer( qt_xdisplay(), w, &root, &child,
00160                    &root_x, &root_y, &lx, &ly, &state );
00161         } while  ( child != None && child != w );
00162 
00163         ::sendClientMessage(w, qt_wm_protocols, net_wm_context_help);
00164         XEvent e = *ev;
00165         e.xbutton.window = w;
00166         e.xbutton.subwindow = w;
00167         e.xbutton.x = lx;
00168         e.xbutton.y = ly;
00169         XSendEvent( qt_xdisplay(), w, TRUE, ButtonPressMask, &e );
00170         qApp->exit_loop();
00171         return TRUE;
00172     }
00173     return FALSE;
00174     }
00175 };
00176 
00177 void KWin::invokeContextHelp()
00178 {
00179     ContextWidget w;
00180 }
00181 
00182 void KWin::setSystemTrayWindowFor( WId trayWin, WId forWin )
00183 {
00184   bool is_kde = true;
00185     Display *xdisplay = qt_xdisplay();
00186 
00187     NETRootInfo rootinfo( xdisplay, NET::SupportingWMCheck );
00188     const char *wmname = rootinfo.wmName();
00189     if ((!wmname) || strncmp("KWin", wmname, 4)) {
00190       is_kde = false;
00191     }
00192 
00193     if ( !forWin ) {
00194     forWin = qt_xrootwin();
00195     }
00196 
00197     NETWinInfo info( xdisplay, trayWin, qt_xrootwin(), 0 );
00198     info.setKDESystemTrayWinFor( forWin );
00199 
00200     if (! is_kde) {
00201       static Atom net_system_tray_selection;
00202       static Atom net_system_tray_opcode;
00203       static bool atoms_created = false;
00204 
00205       if (!atoms_created){
00206     const int max = 20;
00207     Atom* atoms[max];
00208     const char* names[max];
00209     Atom atoms_return[max];
00210     int n = 0;
00211 
00212     QCString screenstr;
00213     screenstr.setNum(qt_xscreen());
00214     QCString trayatom = "_NET_SYSTEM_TRAY_S" + screenstr;
00215 
00216     atoms[n] = &net_system_tray_selection;
00217     names[n++] = trayatom;
00218 
00219     atoms[n] = &net_system_tray_opcode;
00220     names[n++] = "_NET_SYSTEM_TRAY_OPCODE";
00221 
00222     // we need a const_cast for the shitty X API
00223     XInternAtoms( xdisplay, const_cast<char**>(names), n, 
00224               FALSE, atoms_return );
00225 
00226     for (int i = 0; i < n; i++ )
00227         *atoms[i] = atoms_return[i];
00228 
00229     atoms_created = True;
00230       }
00231 
00232       XGrabServer (xdisplay);
00233       Window manager_window = XGetSelectionOwner (xdisplay,
00234                           net_system_tray_selection);
00235       
00236       if ( manager_window != None ) {
00237     XSelectInput (xdisplay,
00238               manager_window, StructureNotifyMask);
00239       }
00240       
00241 
00242       XUngrabServer (xdisplay);
00243       XFlush (xdisplay);    
00244 
00245       if ( manager_window != None ) {
00246 
00247 #define SYSTEM_TRAY_REQUEST_DOCK    0
00248 #define SYSTEM_TRAY_BEGIN_MESSAGE   1
00249 #define SYSTEM_TRAY_CANCEL_MESSAGE  2
00250          
00251     XClientMessageEvent ev;
00252     memset(&ev, 0, sizeof(ev));
00253     ev.type = ClientMessage;
00254     ev.window = trayWin;
00255     ev.message_type = net_system_tray_opcode;
00256     ev.format = 32;
00257     ev.data.l[0] = qt_x_time;
00258     ev.data.l[1] = SYSTEM_TRAY_REQUEST_DOCK;
00259     ev.data.l[2] = trayWin;
00260     
00261     XSendEvent (xdisplay,
00262             manager_window, false, NoEventMask, (XEvent *)&ev);
00263 
00264     XSync (xdisplay, False);
00265       }
00266     }
00267 }
00268 
00269 void KWin::setActiveWindow( WId win)
00270 {
00271     NETRootInfo info( qt_xdisplay(), 0 );
00272     info.setActiveWindow( win );
00273 }
00274 
00275 KWin::Info KWin::info( WId win )
00276 {
00277     Info w;
00278     NETWinInfo inf( qt_xdisplay(), win, qt_xrootwin(),
00279             NET::WMState |
00280             NET::WMStrut |
00281             NET::WMWindowType |
00282             NET::WMName |
00283             NET::WMVisibleName |
00284             NET::WMDesktop |
00285             NET::WMPid |
00286             NET::WMKDEFrameStrut |
00287             NET::XAWMState
00288             );
00289 
00290     w.win = win;
00291     w.state = inf.state();
00292     w.mappingState = inf.mappingState();
00293     w.strut = inf.strut();
00294     w.windowType = inf.windowType();
00295     if ( inf.name() ) {
00296     w.name = QString::fromUtf8( inf.name() );
00297     } else {
00298     char* c = 0;
00299     if ( XFetchName( qt_xdisplay(), win, &c ) != 0 ) {
00300         w.name = QString::fromLocal8Bit( c );
00301         XFree( c );
00302     }
00303     }
00304     if ( inf.visibleName() )
00305     w.visibleName = QString::fromUtf8( inf.visibleName() );
00306     else
00307     w.visibleName = w.name;
00308 
00309     w.desktop = inf.desktop();
00310     w.onAllDesktops = inf.desktop() == NETWinInfo::OnAllDesktops;
00311     w.pid = inf.pid();
00312     NETRect frame, geom;
00313     inf.kdeGeometry( frame, geom );
00314     w.geometry.setRect( geom.pos.x, geom.pos.y, geom.size.width, geom.size.height );
00315     w.frameGeometry.setRect( frame.pos.x, frame.pos.y, frame.size.width, frame.size.height );
00316     return w;
00317 }
00318 
00319 QPixmap KWin::icon( WId win, int width, int height, bool scale )
00320 {
00321     QPixmap result;
00322     NETWinInfo info( qt_xdisplay(), win, qt_xrootwin(), NET::WMIcon );
00323     NETIcon ni = info.icon( width, height );
00324     if ( ni.data && ni.size.width > 0 && ni.size.height > 0 ) {
00325     QImage img( (uchar*) ni.data, (int) ni.size.width, (int) ni.size.height, 32, 0, 0, QImage::IgnoreEndian );
00326     img.setAlphaBuffer( TRUE );
00327     if ( scale && width > 0 && height > 0 &&img.size() != QSize( width, height ) && !img.isNull() )
00328         img = img.smoothScale( width, height );
00329     if ( !img.isNull() )
00330         result.convertFromImage( img );
00331     return result;
00332     }
00333 
00334     Pixmap p = None;
00335     Pixmap p_mask = None;
00336 
00337     XWMHints *hints = XGetWMHints(qt_xdisplay(), win );
00338     if (hints && (hints->flags & IconPixmapHint)){
00339     p = hints->icon_pixmap;
00340     }
00341     if (hints && (hints->flags & IconMaskHint)){
00342     p_mask = hints->icon_mask;
00343     }
00344     if (hints)
00345     XFree((char*)hints);
00346 
00347     if (p != None){
00348     Window root;
00349     int x, y;
00350     unsigned int w = 0;
00351     unsigned int h = 0;
00352     unsigned int border_w, depth;
00353     XGetGeometry(qt_xdisplay(), p, &root,
00354              &x, &y, &w, &h, &border_w, &depth);
00355     if (w > 0 && h > 0){
00356         QPixmap pm(w, h, depth);
00357         XCopyArea(qt_xdisplay(), p, pm.handle(),
00358               qt_xget_temp_gc(qt_xscreen(), depth==1),
00359               0, 0, w, h, 0, 0);
00360         if (p_mask != None){
00361         QBitmap bm(w, h);
00362         XCopyArea(qt_xdisplay(), p_mask, bm.handle(),
00363               qt_xget_temp_gc(qt_xscreen(), true),
00364               0, 0, w, h, 0, 0);
00365         pm.setMask(bm);
00366         }
00367         if ( scale && width > 0 && height > 0 && !pm.isNull() &&
00368          ( (int) w != width || (int) h != height) ){
00369         result.convertFromImage( pm.convertToImage().smoothScale( width, height ) );
00370         } else {
00371         result = pm;
00372         }
00373     }
00374     }
00375 
00376     // Try to load the icon from the classhint if the app didn't specify
00377     // its own:
00378     if( result.isNull() ) {
00379     int iconWidth;
00380 
00381         // Since width can be any arbitrary size, but the icons cannot,
00382         // take the nearest value for best results (ignoring 22 pixel
00383         // icons as they don't exist for apps):
00384     if( width < 24 )
00385         iconWidth = 16;
00386     else if( width < 40 )
00387         iconWidth = 32;
00388     else
00389         iconWidth = 48;
00390 
00391     XClassHint  hint;
00392     if( XGetClassHint( qt_xdisplay(), win, &hint ) ) {
00393         QString className = hint.res_class;
00394 
00395         QPixmap pm = KGlobal::instance()->iconLoader()->loadIcon( className.lower(), KIcon::Small, iconWidth,
00396                                       KIcon::DefaultState, 0, true );
00397         if( scale && !pm.isNull() )
00398         result.convertFromImage( pm.convertToImage().smoothScale( width, height ) );
00399         else
00400         result = pm;
00401 
00402         XFree( hint.res_name );
00403         XFree( hint.res_class );
00404     }
00405 
00406     // If the icon is still a null pixmap, load the 'xapp' icon
00407     // as a last resort:
00408     if ( result.isNull() ) {
00409         QPixmap pm = KGlobal::instance()->iconLoader()->loadIcon(  "xapp", KIcon::Small, iconWidth,
00410                                        KIcon::DefaultState, 0, true );
00411         if( scale && !pm.isNull() )
00412         result.convertFromImage( pm.convertToImage().smoothScale( width, height ) );
00413         else
00414         result = pm;
00415     }
00416     }
00417     return result;
00418 }
00419 
00420 void KWin::setIcons( WId win, const QPixmap& icon, const QPixmap& miniIcon )
00421 {
00422     if ( icon.isNull() )
00423     return;
00424     NETWinInfo info( qt_xdisplay(), win, qt_xrootwin(), 0 );
00425     QImage img = icon.convertToImage().convertDepth( 32 );
00426     NETIcon ni;
00427     ni.size.width = img.size().width();
00428     ni.size.height = img.size().height();
00429     ni.data = (unsigned char *) img.bits();
00430     info.setIcon( ni, true );
00431     if ( miniIcon.isNull() )
00432     return;
00433     img = miniIcon.convertToImage().convertDepth( 32 );
00434     ni.size.width = img.size().width();
00435     ni.size.height = img.size().height();
00436     ni.data = (unsigned char *) img.bits();
00437     info.setIcon( ni, false );
00438 }
00439 
00440 void KWin::setType( WId win, NET::WindowType windowType )
00441 {
00442     NETWinInfo info( qt_xdisplay(), win, qt_xrootwin(), 0 );
00443     info.setWindowType( windowType );
00444 }
00445 
00446 void KWin::setState( WId win, unsigned long state )
00447 {
00448     NETWinInfo info( qt_xdisplay(), win, qt_xrootwin(), NET::WMState );
00449     info.setState( state, state );
00450 }
00451 
00452 void KWin::clearState( WId win, unsigned long state )
00453 {
00454     NETWinInfo info( qt_xdisplay(), win, qt_xrootwin(), NET::WMState );
00455     info.setState( 0, state );
00456 }
00457 
00458 void KWin::setOnAllDesktops( WId win, bool b )
00459 {
00460     NETWinInfo info( qt_xdisplay(), win, qt_xrootwin(), NET::WMDesktop );
00461     if ( b )
00462     info.setDesktop( NETWinInfo::OnAllDesktops );
00463     else if ( info.desktop()  == NETWinInfo::OnAllDesktops ) {
00464     NETRootInfo rinfo( qt_xdisplay(), NET::CurrentDesktop );
00465     info.setDesktop( rinfo.currentDesktop() );
00466     }
00467 }
00468 
00469 void KWin::setOnDesktop( WId win, int desktop )
00470 {
00471     NETWinInfo info( qt_xdisplay(), win, qt_xrootwin(), NET::WMDesktop );
00472     info.setDesktop( desktop );
00473 }
00474 
00475 
00476 QString KWin::Info::visibleNameWithState() const
00477 {
00478     QString s = visibleName;
00479     if ( isIconified() ) {
00480     s.prepend('(');
00481     s.append(')');
00482     }
00483     return s;
00484 }
00485 
00486 
00487 void KWin::setStrut( WId win, int left, int right, int top, int bottom )
00488 {
00489     NETWinInfo info( qt_xdisplay(), win, qt_xrootwin(), 0 );
00490     NETStrut strut;
00491     strut.left = left;
00492     strut.right = right;
00493     strut.top = top;
00494     strut.bottom = bottom;
00495     info.setStrut( strut );
00496 }
00497 
00498 int KWin::currentDesktop()
00499 {
00500     if (!qt_xdisplay())
00501       return 0;
00502     NETRootInfo info( qt_xdisplay(), NET::CurrentDesktop );
00503     return info.currentDesktop();
00504 }
00505 
00506 int KWin::numberOfDesktops()
00507 {
00508     if (!qt_xdisplay())
00509       return 0;
00510     NETRootInfo info( qt_xdisplay(), NET::NumberOfDesktops );
00511     return info.numberOfDesktops();
00512 }
00513 
00514 void KWin::setCurrentDesktop( int desktop )
00515 {
00516     NETRootInfo info( qt_xdisplay(), NET::CurrentDesktop );
00517     info.setCurrentDesktop( desktop );
00518 }
00519 
00520 
00521 void KWin::iconifyWindow( WId win, bool animation)
00522 {
00523     if ( !animation )
00524     sendClientMessageToRoot( win, kde_wm_change_state, IconicState, 1 );
00525     XIconifyWindow( qt_xdisplay(), win, qt_xscreen() );
00526 }
00527 
00528 
00529 void KWin::deIconifyWindow( WId win, bool animation )
00530 {
00531     if ( !animation )
00532     sendClientMessageToRoot( win, kde_wm_change_state, NormalState, 1 );
00533     XMapWindow( qt_xdisplay(), win );
00534 }
00535 
00536 void KWin::appStarted()
00537 {
00538     KStartupInfo::appStarted();
00539 }
00540 
00541 // Fix for --enable-final. This gets defined at the top of this file.
00542 #undef  None
00543 #endif
KDE Logo
This file is part of the documentation for kdelibs Version 3.1.0.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Oct 8 12:20:42 2003 by doxygen 1.2.18 written by Dimitri van Heesch, © 1997-2001