00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
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
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
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
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
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;
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
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
00358 pm.detach();
00359 XCopyArea(qt_xdisplay(), p, pm.handle(),
00360 qt_xget_temp_gc(qt_xscreen(), depth==1),
00361 0, 0, w, h, 0, 0);
00362 if (p_mask != None){
00363 QBitmap bm(w, h);
00364 XCopyArea(qt_xdisplay(), p_mask, bm.handle(),
00365 qt_xget_temp_gc(qt_xscreen(), true),
00366 0, 0, w, h, 0, 0);
00367 pm.setMask(bm);
00368 }
00369 if ( scale && width > 0 && height > 0 && !pm.isNull() &&
00370 ( (int) w != width || (int) h != height) ){
00371 result.convertFromImage( pm.convertToImage().smoothScale( width, height ) );
00372 } else {
00373 result = pm;
00374 }
00375 }
00376 }
00377
00378
00379
00380 if( result.isNull() ) {
00381 int iconWidth;
00382
00383
00384
00385
00386 if( width < 24 )
00387 iconWidth = 16;
00388 else if( width < 40 )
00389 iconWidth = 32;
00390 else
00391 iconWidth = 48;
00392
00393 XClassHint hint;
00394 if( XGetClassHint( qt_xdisplay(), win, &hint ) ) {
00395 QString className = hint.res_class;
00396
00397 QPixmap pm = KGlobal::instance()->iconLoader()->loadIcon( className.lower(), KIcon::Small, iconWidth,
00398 KIcon::DefaultState, 0, true );
00399 if( scale && !pm.isNull() )
00400 result.convertFromImage( pm.convertToImage().smoothScale( width, height ) );
00401 else
00402 result = pm;
00403
00404 XFree( hint.res_name );
00405 XFree( hint.res_class );
00406 }
00407
00408
00409
00410 if ( result.isNull() ) {
00411 QPixmap pm = KGlobal::instance()->iconLoader()->loadIcon( "xapp", KIcon::Small, iconWidth,
00412 KIcon::DefaultState, 0, true );
00413 if( scale && !pm.isNull() )
00414 result.convertFromImage( pm.convertToImage().smoothScale( width, height ) );
00415 else
00416 result = pm;
00417 }
00418 }
00419 return result;
00420 }
00421
00422 void KWin::setIcons( WId win, const QPixmap& icon, const QPixmap& miniIcon )
00423 {
00424 if ( icon.isNull() )
00425 return;
00426 NETWinInfo info( qt_xdisplay(), win, qt_xrootwin(), 0 );
00427 QImage img = icon.convertToImage().convertDepth( 32 );
00428 NETIcon ni;
00429 ni.size.width = img.size().width();
00430 ni.size.height = img.size().height();
00431 ni.data = (unsigned char *) img.bits();
00432 info.setIcon( ni, true );
00433 if ( miniIcon.isNull() )
00434 return;
00435 img = miniIcon.convertToImage().convertDepth( 32 );
00436 ni.size.width = img.size().width();
00437 ni.size.height = img.size().height();
00438 ni.data = (unsigned char *) img.bits();
00439 info.setIcon( ni, false );
00440 }
00441
00442 void KWin::setType( WId win, NET::WindowType windowType )
00443 {
00444 NETWinInfo info( qt_xdisplay(), win, qt_xrootwin(), 0 );
00445 info.setWindowType( windowType );
00446 }
00447
00448 void KWin::setState( WId win, unsigned long state )
00449 {
00450 NETWinInfo info( qt_xdisplay(), win, qt_xrootwin(), NET::WMState );
00451 info.setState( state, state );
00452 }
00453
00454 void KWin::clearState( WId win, unsigned long state )
00455 {
00456 NETWinInfo info( qt_xdisplay(), win, qt_xrootwin(), NET::WMState );
00457 info.setState( 0, state );
00458 }
00459
00460 void KWin::setOnAllDesktops( WId win, bool b )
00461 {
00462 NETWinInfo info( qt_xdisplay(), win, qt_xrootwin(), NET::WMDesktop );
00463 if ( b )
00464 info.setDesktop( NETWinInfo::OnAllDesktops );
00465 else if ( info.desktop() == NETWinInfo::OnAllDesktops ) {
00466 NETRootInfo rinfo( qt_xdisplay(), NET::CurrentDesktop );
00467 info.setDesktop( rinfo.currentDesktop() );
00468 }
00469 }
00470
00471 void KWin::setOnDesktop( WId win, int desktop )
00472 {
00473 NETWinInfo info( qt_xdisplay(), win, qt_xrootwin(), NET::WMDesktop );
00474 info.setDesktop( desktop );
00475 }
00476
00477
00478 QString KWin::Info::visibleNameWithState() const
00479 {
00480 QString s = visibleName;
00481 if ( isIconified() ) {
00482 s.prepend('(');
00483 s.append(')');
00484 }
00485 return s;
00486 }
00487
00488
00489 void KWin::setStrut( WId win, int left, int right, int top, int bottom )
00490 {
00491 NETWinInfo info( qt_xdisplay(), win, qt_xrootwin(), 0 );
00492 NETStrut strut;
00493 strut.left = left;
00494 strut.right = right;
00495 strut.top = top;
00496 strut.bottom = bottom;
00497 info.setStrut( strut );
00498 }
00499
00500 int KWin::currentDesktop()
00501 {
00502 if (!qt_xdisplay())
00503 return 0;
00504 NETRootInfo info( qt_xdisplay(), NET::CurrentDesktop );
00505 return info.currentDesktop();
00506 }
00507
00508 int KWin::numberOfDesktops()
00509 {
00510 if (!qt_xdisplay())
00511 return 0;
00512 NETRootInfo info( qt_xdisplay(), NET::NumberOfDesktops );
00513 return info.numberOfDesktops();
00514 }
00515
00516 void KWin::setCurrentDesktop( int desktop )
00517 {
00518 NETRootInfo info( qt_xdisplay(), NET::CurrentDesktop );
00519 info.setCurrentDesktop( desktop );
00520 }
00521
00522
00523 void KWin::iconifyWindow( WId win, bool animation)
00524 {
00525 if ( !animation )
00526 sendClientMessageToRoot( win, kde_wm_change_state, IconicState, 1 );
00527 XIconifyWindow( qt_xdisplay(), win, qt_xscreen() );
00528 }
00529
00530
00531 void KWin::deIconifyWindow( WId win, bool animation )
00532 {
00533 if ( !animation )
00534 sendClientMessageToRoot( win, kde_wm_change_state, NormalState, 1 );
00535 XMapWindow( qt_xdisplay(), win );
00536 }
00537
00538 void KWin::appStarted()
00539 {
00540 KStartupInfo::appStarted();
00541 }
00542
00543
00544 #undef None
00545 #endif