00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "client.h"
00019 #include "workspace.h"
00020 #include "atoms.h"
00021 #include "tabbox.h"
00022 #include "group.h"
00023 #include "rules.h"
00024
00025 #include <qwhatsthis.h>
00026 #include <kkeynative.h>
00027 #include <qapplication.h>
00028
00029 #include <X11/extensions/shape.h>
00030 #include <X11/Xatom.h>
00031
00032 extern Time qt_x_time;
00033 extern Atom qt_window_role;
00034
00035 namespace KWinInternal
00036 {
00037
00038
00039
00040
00041
00042 WinInfo::WinInfo( Client * c, Display * display, Window window,
00043 Window rwin, const unsigned long pr[], int pr_size )
00044 : NETWinInfo( display, window, rwin, pr, pr_size, NET::WindowManager ), m_client( c )
00045 {
00046 }
00047
00048 void WinInfo::changeDesktop(int desktop)
00049 {
00050 m_client->workspace()->sendClientToDesktop( m_client, desktop, true );
00051 }
00052
00053 void WinInfo::changeState( unsigned long state, unsigned long mask )
00054 {
00055 mask &= ~NET::Sticky;
00056 mask &= ~NET::Hidden;
00057 state &= mask;
00058
00059 if(( mask & NET::FullScreen ) != 0 && ( state & NET::FullScreen ) == 0 )
00060 m_client->setFullScreen( false, false );
00061 if ( (mask & NET::Max) == NET::Max )
00062 m_client->setMaximize( state & NET::MaxVert, state & NET::MaxHoriz );
00063 else if ( mask & NET::MaxVert )
00064 m_client->setMaximize( state & NET::MaxVert, m_client->maximizeMode() & Client::MaximizeHorizontal );
00065 else if ( mask & NET::MaxHoriz )
00066 m_client->setMaximize( m_client->maximizeMode() & Client::MaximizeVertical, state & NET::MaxHoriz );
00067
00068 if ( mask & NET::Shaded )
00069 m_client->setShade( state & NET::Shaded ? ShadeNormal : ShadeNone );
00070 if ( mask & NET::KeepAbove)
00071 m_client->setKeepAbove( (state & NET::KeepAbove) != 0 );
00072 if ( mask & NET::KeepBelow)
00073 m_client->setKeepBelow( (state & NET::KeepBelow) != 0 );
00074 if( mask & NET::SkipTaskbar )
00075 m_client->setSkipTaskbar( ( state & NET::SkipTaskbar ) != 0, true );
00076 if( mask & NET::SkipPager )
00077 m_client->setSkipPager( ( state & NET::SkipPager ) != 0 );
00078 if( mask & NET::DemandsAttention )
00079 m_client->demandAttention(( state & NET::DemandsAttention ) != 0 );
00080 if( mask & NET::Modal )
00081 m_client->setModal( ( state & NET::Modal ) != 0 );
00082
00083 if(( mask & NET::FullScreen ) != 0 && ( state & NET::FullScreen ) != 0 )
00084 m_client->setFullScreen( true, false );
00085 }
00086
00087
00088
00089
00090
00091
00092 RootInfo::RootInfo( Workspace* ws, Display *dpy, Window w, const char *name, unsigned long pr[], int pr_num, int scr )
00093 : NETRootInfo4( dpy, w, name, pr, pr_num, scr )
00094 {
00095 workspace = ws;
00096 }
00097
00098 void RootInfo::changeNumberOfDesktops(int n)
00099 {
00100 workspace->setNumberOfDesktops( n );
00101 }
00102
00103 void RootInfo::changeCurrentDesktop(int d)
00104 {
00105 workspace->setCurrentDesktop( d );
00106 }
00107
00108 void RootInfo::changeActiveWindow( Window w, NET::RequestSource src, Time timestamp, Window active_window )
00109 {
00110 if( Client* c = workspace->findClient( WindowMatchPredicate( w )))
00111 {
00112 if( timestamp == CurrentTime )
00113 timestamp = c->userTime();
00114 if( src != NET::FromApplication && src != FromTool )
00115 src = NET::FromTool;
00116 if( src == NET::FromTool )
00117 workspace->activateClient( c, true );
00118 else
00119 {
00120 Client* c2;
00121 if( workspace->allowClientActivation( c, timestamp ))
00122 workspace->activateClient( c );
00123
00124 else if( active_window != None
00125 && ( c2 = workspace->findClient( WindowMatchPredicate( active_window ))) != NULL
00126 && workspace->allowClientActivation( c2,
00127 timestampCompare( timestamp, c2->userTime() > 0 ? timestamp : c2->userTime())))
00128 workspace->activateClient( c );
00129 else
00130 c->demandAttention();
00131 }
00132 }
00133 }
00134
00135 void RootInfo::restackWindow( Window w, RequestSource src, Window above, int detail, Time timestamp )
00136 {
00137 if( Client* c = workspace->findClient( WindowMatchPredicate( w )))
00138 {
00139 if( timestamp == CurrentTime )
00140 timestamp = c->userTime();
00141 if( src != NET::FromApplication && src != FromTool )
00142 src = NET::FromTool;
00143 c->restackWindow( above, detail, src, timestamp, true );
00144 }
00145 }
00146
00147 void RootInfo::gotTakeActivity( Window w, Time timestamp, long flags )
00148 {
00149 if( Client* c = workspace->findClient( WindowMatchPredicate( w )))
00150 workspace->handleTakeActivity( c, timestamp, flags );
00151 }
00152
00153 void RootInfo::closeWindow(Window w)
00154 {
00155 Client* c = workspace->findClient( WindowMatchPredicate( w ));
00156 if ( c )
00157 c->closeWindow();
00158 }
00159
00160 void RootInfo::moveResize(Window w, int x_root, int y_root, unsigned long direction)
00161 {
00162 Client* c = workspace->findClient( WindowMatchPredicate( w ));
00163 if ( c )
00164 {
00165 updateXTime();
00166 c->NETMoveResize( x_root, y_root, (Direction)direction);
00167 }
00168 }
00169
00170 void RootInfo::moveResizeWindow(Window w, int flags, int x, int y, int width, int height )
00171 {
00172 Client* c = workspace->findClient( WindowMatchPredicate( w ));
00173 if ( c )
00174 c->NETMoveResizeWindow( flags, x, y, width, height );
00175 }
00176
00177 void RootInfo::gotPing( Window w, Time timestamp )
00178 {
00179 if( Client* c = workspace->findClient( WindowMatchPredicate( w )))
00180 c->gotPing( timestamp );
00181 }
00182
00183 void RootInfo::changeShowingDesktop( bool showing )
00184 {
00185 workspace->setShowingDesktop( showing );
00186 }
00187
00188
00189
00190
00191
00195 bool Workspace::workspaceEvent( XEvent * e )
00196 {
00197 if ( mouse_emulation && (e->type == ButtonPress || e->type == ButtonRelease ) )
00198 {
00199 mouse_emulation = FALSE;
00200 XUngrabKeyboard( qt_xdisplay(), qt_x_time );
00201 }
00202
00203 if ( e->type == PropertyNotify || e->type == ClientMessage )
00204 {
00205 if ( netCheck( e ) )
00206 return TRUE;
00207 }
00208
00209
00210 switch (e->type)
00211 {
00212 case ButtonPress:
00213 case ButtonRelease:
00214 was_user_interaction = true;
00215
00216 case MotionNotify:
00217 if ( tab_grab || control_grab )
00218 {
00219 tab_box->handleMouseEvent( e );
00220 return TRUE;
00221 }
00222 break;
00223 case KeyPress:
00224 {
00225 was_user_interaction = true;
00226 KKeyNative keyX( (XEvent*)e );
00227 uint keyQt = keyX.keyCodeQt();
00228 kdDebug(125) << "Workspace::keyPress( " << keyX.key().toString() << " )" << endl;
00229 if (movingClient)
00230 {
00231 movingClient->keyPressEvent(keyQt);
00232 return true;
00233 }
00234 if( tab_grab || control_grab )
00235 {
00236 tabBoxKeyPress( keyX );
00237 return true;
00238 }
00239 break;
00240 }
00241 case KeyRelease:
00242 was_user_interaction = true;
00243 if( tab_grab || control_grab )
00244 {
00245 tabBoxKeyRelease( e->xkey );
00246 return true;
00247 }
00248 break;
00249 };
00250
00251 if( Client* c = findClient( WindowMatchPredicate( e->xany.window )))
00252 {
00253 if( c->windowEvent( e ))
00254 return true;
00255 }
00256 else if( Client* c = findClient( WrapperIdMatchPredicate( e->xany.window )))
00257 {
00258 if( c->windowEvent( e ))
00259 return true;
00260 }
00261 else if( Client* c = findClient( FrameIdMatchPredicate( e->xany.window )))
00262 {
00263 if( c->windowEvent( e ))
00264 return true;
00265 }
00266 else
00267 {
00268 Window special = findSpecialEventWindow( e );
00269 if( special != None )
00270 if( Client* c = findClient( WindowMatchPredicate( special )))
00271 {
00272 if( c->windowEvent( e ))
00273 return true;
00274 }
00275 }
00276 if( movingClient != NULL && movingClient->moveResizeGrabWindow() == e->xany.window
00277 && ( e->type == MotionNotify || e->type == ButtonPress || e->type == ButtonRelease ))
00278 {
00279 if( movingClient->windowEvent( e ))
00280 return true;
00281 }
00282
00283 switch (e->type)
00284 {
00285 case CreateNotify:
00286 if ( e->xcreatewindow.parent == root &&
00287 !QWidget::find( e->xcreatewindow.window) &&
00288 !e->xcreatewindow.override_redirect )
00289 {
00290
00291 XChangeProperty(qt_xdisplay(), e->xcreatewindow.window,
00292 atoms->kde_net_wm_user_creation_time, XA_CARDINAL,
00293 32, PropModeReplace, (unsigned char *)&qt_x_time, 1);
00294 }
00295 break;
00296
00297 case UnmapNotify:
00298 {
00299
00300 if ( removeSystemTrayWin( e->xunmap.window, true ) )
00301 {
00302
00303
00304
00305
00306
00307
00308
00309 XEvent ev;
00310 WId w = e->xunmap.window;
00311 if ( XCheckTypedWindowEvent (qt_xdisplay(), w,
00312 ReparentNotify, &ev) )
00313 {
00314 if ( ev.xreparent.parent != root )
00315 {
00316 XReparentWindow( qt_xdisplay(), w, root, 0, 0 );
00317 addSystemTrayWin( w );
00318 }
00319 }
00320 return TRUE;
00321 }
00322
00323 return ( e->xunmap.event != e->xunmap.window );
00324 }
00325 case MapNotify:
00326
00327 return ( e->xmap.event != e->xmap.window );
00328
00329 case ReparentNotify:
00330 {
00331
00332
00333 return TRUE;
00334 }
00335 case DestroyNotify:
00336 {
00337 if ( removeSystemTrayWin( e->xdestroywindow.window, false ) )
00338 return TRUE;
00339 return false;
00340 }
00341 case MapRequest:
00342 {
00343 updateXTime();
00344
00345
00346
00347 Client* c = findClient( WindowMatchPredicate( e->xmaprequest.window ));
00348 if ( !c )
00349 {
00350
00351
00352
00353
00354
00355
00356
00357
00358 if ( addSystemTrayWin( e->xmaprequest.window ) )
00359 return TRUE;
00360 c = createClient( e->xmaprequest.window, false );
00361 if ( c != NULL && root != qt_xrootwin() )
00362 {
00363
00364 XReparentWindow( qt_xdisplay(), c->frameId(), root, 0, 0 );
00365 }
00366 if( c == NULL )
00367 XMapRaised( qt_xdisplay(), e->xmaprequest.window );
00368 return true;
00369 }
00370 if( c )
00371 {
00372 c->windowEvent( e );
00373 updateFocusChains( c, FocusChainUpdate );
00374 return true;
00375 }
00376 break;
00377 }
00378 case EnterNotify:
00379 {
00380 if ( QWhatsThis::inWhatsThisMode() )
00381 {
00382 QWidget* w = QWidget::find( e->xcrossing.window );
00383 if ( w )
00384 QWhatsThis::leaveWhatsThisMode();
00385 }
00386 if( electricBorder(e))
00387 return true;
00388 break;
00389 }
00390 case LeaveNotify:
00391 {
00392 if ( !QWhatsThis::inWhatsThisMode() )
00393 break;
00394
00395 Client* c = findClient( FrameIdMatchPredicate( e->xcrossing.window ));
00396 if ( c && e->xcrossing.detail != NotifyInferior )
00397 QWhatsThis::leaveWhatsThisMode();
00398 break;
00399 }
00400 case ConfigureRequest:
00401 {
00402 if ( e->xconfigurerequest.parent == root )
00403 {
00404 XWindowChanges wc;
00405 wc.border_width = e->xconfigurerequest.border_width;
00406 wc.x = e->xconfigurerequest.x;
00407 wc.y = e->xconfigurerequest.y;
00408 wc.width = e->xconfigurerequest.width;
00409 wc.height = e->xconfigurerequest.height;
00410 wc.sibling = None;
00411 wc.stack_mode = Above;
00412 unsigned int value_mask = e->xconfigurerequest.value_mask
00413 & ( CWX | CWY | CWWidth | CWHeight | CWBorderWidth );
00414 XConfigureWindow( qt_xdisplay(), e->xconfigurerequest.window, value_mask, &wc );
00415 return true;
00416 }
00417 break;
00418 }
00419 case KeyPress:
00420 if ( mouse_emulation )
00421 return keyPressMouseEmulation( e->xkey );
00422 break;
00423 case KeyRelease:
00424 if ( mouse_emulation )
00425 return FALSE;
00426 break;
00427 case FocusIn:
00428 if( e->xfocus.window == rootWin()
00429 && ( e->xfocus.detail == NotifyDetailNone || e->xfocus.detail == NotifyPointerRoot ))
00430 {
00431 updateXTime();
00432 Window focus;
00433 int revert;
00434 XGetInputFocus( qt_xdisplay(), &focus, &revert );
00435 if( focus == None || focus == PointerRoot )
00436 {
00437
00438 Client *c = mostRecentlyActivatedClient();
00439 if( c != NULL )
00440 requestFocus( c, true );
00441 else if( activateNextClient( NULL ))
00442 ;
00443 else
00444 focusToNull();
00445 }
00446 }
00447
00448 case FocusOut:
00449 return true;
00450 case ClientMessage:
00451 if( electricBorder( e ))
00452 return true;
00453 break;
00454 default:
00455 break;
00456 }
00457 return FALSE;
00458 }
00459
00460
00461
00462
00463 Window Workspace::findSpecialEventWindow( XEvent* e )
00464 {
00465 switch( e->type )
00466 {
00467 case CreateNotify:
00468 return e->xcreatewindow.window;
00469 case DestroyNotify:
00470 return e->xdestroywindow.window;
00471 case UnmapNotify:
00472 return e->xunmap.window;
00473 case MapNotify:
00474 return e->xmap.window;
00475 case MapRequest:
00476 return e->xmaprequest.window;
00477 case ReparentNotify:
00478 return e->xreparent.window;
00479 case ConfigureNotify:
00480 return e->xconfigure.window;
00481 case GravityNotify:
00482 return e->xgravity.window;
00483 case ConfigureRequest:
00484 return e->xconfigurerequest.window;
00485 case CirculateNotify:
00486 return e->xcirculate.window;
00487 case CirculateRequest:
00488 return e->xcirculaterequest.window;
00489 default:
00490 return None;
00491 };
00492 }
00493
00497 bool Workspace::netCheck( XEvent* e )
00498 {
00499 unsigned int dirty = rootInfo->event( e );
00500
00501 if ( dirty & NET::DesktopNames )
00502 saveDesktopSettings();
00503
00504 return dirty != 0;
00505 }
00506
00507
00508
00509
00510
00511
00515 bool Client::windowEvent( XEvent* e )
00516 {
00517 if( e->xany.window == window())
00518 {
00519 unsigned long dirty[ 2 ];
00520 info->event( e, dirty, 2 );
00521
00522 if ( ( dirty[ WinInfo::PROTOCOLS ] & NET::WMName ) != 0 )
00523 fetchName();
00524 if ( ( dirty[ WinInfo::PROTOCOLS ] & NET::WMIconName ) != 0 )
00525 fetchIconicName();
00526 if ( ( dirty[ WinInfo::PROTOCOLS ] & NET::WMStrut ) != 0
00527 || ( dirty[ WinInfo::PROTOCOLS2 ] & NET::WM2ExtendedStrut ) != 0 )
00528 {
00529 if( isTopMenu())
00530 checkWorkspacePosition();
00531 workspace()->updateClientArea();
00532 }
00533 if ( ( dirty[ WinInfo::PROTOCOLS ] & NET::WMIcon) != 0 )
00534 getIcons();
00535
00536
00537
00538 if(( dirty[ WinInfo::PROTOCOLS2 ] & NET::WM2UserTime ) != 0 )
00539 {
00540 workspace()->setWasUserInteraction();
00541 updateUserTime( info->userTime());
00542 }
00543 if(( dirty[ WinInfo::PROTOCOLS2 ] & NET::WM2StartupId ) != 0 )
00544 startupIdChanged();
00545 if( dirty[ WinInfo::PROTOCOLS ] & NET::WMIconGeometry )
00546 {
00547 if( demandAttentionKNotifyTimer != NULL )
00548 demandAttentionKNotify();
00549 }
00550 }
00551
00552
00553 switch (e->type)
00554 {
00555 case UnmapNotify:
00556 unmapNotifyEvent( &e->xunmap );
00557 break;
00558 case DestroyNotify:
00559 destroyNotifyEvent( &e->xdestroywindow );
00560 break;
00561 case MapRequest:
00562
00563 return mapRequestEvent( &e->xmaprequest );
00564 case ConfigureRequest:
00565 configureRequestEvent( &e->xconfigurerequest );
00566 break;
00567 case PropertyNotify:
00568 propertyNotifyEvent( &e->xproperty );
00569 break;
00570 case KeyPress:
00571 updateUserTime();
00572 workspace()->setWasUserInteraction();
00573 break;
00574 case ButtonPress:
00575 updateUserTime();
00576 workspace()->setWasUserInteraction();
00577 buttonPressEvent( e->xbutton.window, e->xbutton.button, e->xbutton.state,
00578 e->xbutton.x, e->xbutton.y, e->xbutton.x_root, e->xbutton.y_root );
00579 break;
00580 case KeyRelease:
00581
00582
00583
00584 break;
00585 case ButtonRelease:
00586
00587
00588
00589 buttonReleaseEvent( e->xbutton.window, e->xbutton.button, e->xbutton.state,
00590 e->xbutton.x, e->xbutton.y, e->xbutton.x_root, e->xbutton.y_root );
00591 break;
00592 case MotionNotify:
00593 motionNotifyEvent( e->xmotion.window, e->xmotion.state,
00594 e->xmotion.x, e->xmotion.y, e->xmotion.x_root, e->xmotion.y_root );
00595 workspace()->updateFocusMousePosition( QPoint( e->xmotion.x_root, e->xmotion.y_root ));
00596 break;
00597 case EnterNotify:
00598 enterNotifyEvent( &e->xcrossing );
00599
00600
00601
00602
00603
00604 motionNotifyEvent( e->xcrossing.window, e->xcrossing.state,
00605 e->xcrossing.x, e->xcrossing.y, e->xcrossing.x_root, e->xcrossing.y_root );
00606 workspace()->updateFocusMousePosition( QPoint( e->xcrossing.x_root, e->xcrossing.y_root ));
00607 break;
00608 case LeaveNotify:
00609 motionNotifyEvent( e->xcrossing.window, e->xcrossing.state,
00610 e->xcrossing.x, e->xcrossing.y, e->xcrossing.x_root, e->xcrossing.y_root );
00611 leaveNotifyEvent( &e->xcrossing );
00612
00613
00614 break;
00615 case FocusIn:
00616 focusInEvent( &e->xfocus );
00617 break;
00618 case FocusOut:
00619 focusOutEvent( &e->xfocus );
00620 break;
00621 case ReparentNotify:
00622 break;
00623 case ClientMessage:
00624 clientMessageEvent( &e->xclient );
00625 break;
00626 case ColormapChangeMask:
00627 if( e->xany.window == window())
00628 {
00629 cmap = e->xcolormap.colormap;
00630 if ( isActive() )
00631 workspace()->updateColormap();
00632 }
00633 break;
00634 default:
00635 if( e->xany.window == window())
00636 {
00637 if( e->type == Shape::shapeEvent() )
00638 {
00639 is_shape = Shape::hasShape( window());
00640 updateShape();
00641 }
00642 }
00643 break;
00644 }
00645 return true;
00646 }
00647
00651 bool Client::mapRequestEvent( XMapRequestEvent* e )
00652 {
00653 if( e->window != window())
00654 {
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667 if( e->parent == wrapperId())
00668 return false;
00669 return true;
00670 }
00671 if( isTopMenu() && workspace()->managingTopMenus())
00672 return true;
00673 switch ( mappingState() )
00674 {
00675 case WithdrawnState:
00676 assert( false );
00677
00678 break;
00679 case IconicState:
00680
00681 if( isMinimized())
00682 unminimize();
00683 if( isShade())
00684 setShade( ShadeNone );
00685 if( !isOnCurrentDesktop())
00686 {
00687 if( workspace()->allowClientActivation( this ))
00688 workspace()->activateClient( this );
00689 else
00690 demandAttention();
00691 }
00692 break;
00693 case NormalState:
00694
00695 break;
00696 }
00697 return true;
00698 }
00699
00703 void Client::unmapNotifyEvent( XUnmapEvent* e )
00704 {
00705 if( e->window != window())
00706 return;
00707 if( e->event != wrapperId())
00708 {
00709 bool ignore = true;
00710 if( e->event == workspace()->rootWin() && e->send_event )
00711 ignore = false;
00712 if( ignore )
00713 return;
00714 }
00715 switch( mappingState())
00716 {
00717 case IconicState:
00718 releaseWindow();
00719 return;
00720 case NormalState:
00721
00722 XEvent ev;
00723 if( XCheckTypedWindowEvent (qt_xdisplay(), window(),
00724 DestroyNotify, &ev) )
00725 {
00726 destroyClient();
00727 return;
00728 }
00729 releaseWindow();
00730 break;
00731 default:
00732 assert( false );
00733 }
00734 }
00735
00736 void Client::destroyNotifyEvent( XDestroyWindowEvent* e )
00737 {
00738 if( e->window != window())
00739 return;
00740 destroyClient();
00741 }
00742
00743
00744 bool blockAnimation = FALSE;
00745
00749 void Client::clientMessageEvent( XClientMessageEvent* e )
00750 {
00751 if( e->window != window())
00752 return;
00753
00754 if ( e->message_type == atoms->kde_wm_change_state )
00755 {
00756 if( isTopMenu() && workspace()->managingTopMenus())
00757 return;
00758 if( e->data.l[ 1 ] )
00759 blockAnimation = true;
00760 if( e->data.l[ 0 ] == IconicState )
00761 minimize();
00762 else if( e->data.l[ 0 ] == NormalState )
00763 {
00764 if( isMinimized())
00765 unminimize();
00766 if( isShade())
00767 setShade( ShadeNone );
00768 if( !isOnCurrentDesktop())
00769 {
00770 if( workspace()->allowClientActivation( this ))
00771 workspace()->activateClient( this );
00772 else
00773 demandAttention();
00774 }
00775 }
00776 blockAnimation = false;
00777 }
00778 else if ( e->message_type == atoms->wm_change_state)
00779 {
00780 if( isTopMenu() && workspace()->managingTopMenus())
00781 return;
00782 if ( e->data.l[0] == IconicState )
00783 minimize();
00784 return;
00785 }
00786 }
00787
00788
00792 void Client::configureRequestEvent( XConfigureRequestEvent* e )
00793 {
00794 if( e->window != window())
00795 return;
00796 if ( isResize() || isMove())
00797 return;
00798
00799 if( fullscreen_mode == FullScreenNormal )
00800 {
00801 sendSyntheticConfigureNotify();
00802 return;
00803 }
00804 if( isSplash()
00805 || isTopMenu())
00806 {
00807 sendSyntheticConfigureNotify();
00808 return;
00809 }
00810
00811 if ( e->value_mask & CWBorderWidth )
00812 {
00813
00814 XWindowChanges wc;
00815 unsigned int value_mask = 0;
00816
00817 wc.border_width = 0;
00818 value_mask = CWBorderWidth;
00819 XConfigureWindow( qt_xdisplay(), window(), value_mask, & wc );
00820 }
00821
00822 if( e->value_mask & ( CWX | CWY | CWHeight | CWWidth ))
00823 configureRequest( e->value_mask, e->x, e->y, e->width, e->height, 0, false );
00824
00825 if ( e->value_mask & CWStackMode )
00826 restackWindow( e->above, e->detail, NET::FromApplication, userTime(), false );
00827
00828
00829
00830
00831
00832
00833 sendSyntheticConfigureNotify();
00834
00835
00836
00837 }
00838
00839
00843 void Client::propertyNotifyEvent( XPropertyEvent* e )
00844 {
00845 if( e->window != window())
00846 return;
00847 switch ( e->atom )
00848 {
00849 case XA_WM_NORMAL_HINTS:
00850 getWmNormalHints();
00851 break;
00852 case XA_WM_NAME:
00853 fetchName();
00854 break;
00855 case XA_WM_ICON_NAME:
00856 fetchIconicName();
00857 break;
00858 case XA_WM_TRANSIENT_FOR:
00859 readTransient();
00860 break;
00861 case XA_WM_HINTS:
00862 getWMHints();
00863 getIcons();
00864 break;
00865 default:
00866 if ( e->atom == atoms->wm_protocols )
00867 getWindowProtocols();
00868 else if (e->atom == atoms->wm_client_leader )
00869 getWmClientLeader();
00870 else if( e->atom == qt_window_role )
00871 window_role = staticWindowRole( window());
00872 else if( e->atom == atoms->motif_wm_hints )
00873 getMotifHints();
00874 break;
00875 }
00876 }
00877
00878
00879 void Client::enterNotifyEvent( XCrossingEvent* e )
00880 {
00881 if( e->window != frameId())
00882 return;
00883 if( e->mode == NotifyNormal ||
00884 ( !options->focusPolicyIsReasonable() &&
00885 e->mode == NotifyUngrab ) )
00886 {
00887
00888 if (options->shadeHover && isShade())
00889 {
00890 delete shadeHoverTimer;
00891 shadeHoverTimer = new QTimer( this );
00892 connect( shadeHoverTimer, SIGNAL( timeout() ), this, SLOT( shadeHover() ));
00893 shadeHoverTimer->start( options->shadeHoverInterval, TRUE );
00894 }
00895
00896 if ( options->focusPolicy == Options::ClickToFocus )
00897 return;
00898
00899 if ( options->autoRaise && !isDesktop() &&
00900 !isDock() && !isTopMenu() && workspace()->focusChangeEnabled() &&
00901 workspace()->topClientOnDesktop( workspace()->currentDesktop()) != this )
00902 {
00903 delete autoRaiseTimer;
00904 autoRaiseTimer = new QTimer( this );
00905 connect( autoRaiseTimer, SIGNAL( timeout() ), this, SLOT( autoRaise() ) );
00906 autoRaiseTimer->start( options->autoRaiseInterval, TRUE );
00907 }
00908
00909 QPoint currentPos( e->x_root, e->y_root );
00910 if ( options->focusPolicy != Options::FocusStrictlyUnderMouse && ( isDesktop() || isDock() || isTopMenu() ) )
00911 return;
00912
00913
00914 if( options->focusPolicy != Options::FocusFollowsMouse
00915 || currentPos != workspace()->focusMousePosition())
00916 {
00917 if ( options->delayFocus )
00918 workspace()->requestDelayFocus( this );
00919 else
00920 workspace()->requestFocus( this );
00921 }
00922 return;
00923 }
00924 }
00925
00926 void Client::leaveNotifyEvent( XCrossingEvent* e )
00927 {
00928 if( e->window != frameId())
00929 return;
00930 if ( e->mode == NotifyNormal )
00931 {
00932 if ( !buttonDown )
00933 {
00934 mode = PositionCenter;
00935 setCursor( arrowCursor );
00936 }
00937 bool lostMouse = !rect().contains( QPoint( e->x, e->y ) );
00938
00939
00940
00941
00942
00943
00944
00945 if ( !lostMouse && e->detail != NotifyInferior )
00946 {
00947 int d1, d2, d3, d4;
00948 unsigned int d5;
00949 Window w, child;
00950 if( XQueryPointer( qt_xdisplay(), frameId(), &w, &child, &d1, &d2, &d3, &d4, &d5 ) == False
00951 || child == None )
00952 lostMouse = true;
00953 }
00954 if ( lostMouse )
00955 {
00956 cancelAutoRaise();
00957 workspace()->cancelDelayFocus();
00958 cancelShadeHover();
00959 if ( shade_mode == ShadeHover && !moveResizeMode && !buttonDown )
00960 setShade( ShadeNormal );
00961 }
00962 if ( options->focusPolicy == Options::FocusStrictlyUnderMouse )
00963 if ( isActive() && lostMouse )
00964 workspace()->requestFocus( 0 ) ;
00965 return;
00966 }
00967 }
00968
00969 #define XCapL KKeyNative::modXLock()
00970 #define XNumL KKeyNative::modXNumLock()
00971 #define XScrL KKeyNative::modXScrollLock()
00972 void Client::grabButton( int modifier )
00973 {
00974 unsigned int mods[ 8 ] =
00975 {
00976 0, XCapL, XNumL, XNumL | XCapL,
00977 XScrL, XScrL | XCapL,
00978 XScrL | XNumL, XScrL | XNumL | XCapL
00979 };
00980 for( int i = 0;
00981 i < 8;
00982 ++i )
00983 XGrabButton( qt_xdisplay(), AnyButton,
00984 modifier | mods[ i ],
00985 wrapperId(), FALSE, ButtonPressMask,
00986 GrabModeSync, GrabModeAsync, None, None );
00987 }
00988
00989 void Client::ungrabButton( int modifier )
00990 {
00991 unsigned int mods[ 8 ] =
00992 {
00993 0, XCapL, XNumL, XNumL | XCapL,
00994 XScrL, XScrL | XCapL,
00995 XScrL | XNumL, XScrL | XNumL | XCapL
00996 };
00997 for( int i = 0;
00998 i < 8;
00999 ++i )
01000 XUngrabButton( qt_xdisplay(), AnyButton,
01001 modifier | mods[ i ], wrapperId());
01002 }
01003 #undef XCapL
01004 #undef XNumL
01005 #undef XScrL
01006
01007
01008
01009
01010
01011
01012
01013 void Client::updateMouseGrab()
01014 {
01015 if( workspace()->globalShortcutsDisabled())
01016 {
01017 XUngrabButton( qt_xdisplay(), AnyButton, AnyModifier, wrapperId());
01018
01019 bool not_obscured = workspace()->topClientOnDesktop( workspace()->currentDesktop(), true, false ) == this;
01020 if( !( !options->clickRaise || not_obscured ))
01021 grabButton( None );
01022 return;
01023 }
01024 if( isActive() && !workspace()->forcedGlobalMouseGrab())
01025 {
01026
01027 XGrabButton(qt_xdisplay(), AnyButton, AnyModifier, wrapperId(), FALSE,
01028 ButtonPressMask,
01029 GrabModeSync, GrabModeAsync,
01030 None, None );
01031
01032
01033
01034
01035 bool not_obscured = workspace()->topClientOnDesktop( workspace()->currentDesktop(), true, false ) == this;
01036 if( !options->clickRaise || not_obscured )
01037 ungrabButton( None );
01038 else
01039 grabButton( None );
01040 ungrabButton( ShiftMask );
01041 ungrabButton( ControlMask );
01042 ungrabButton( ControlMask | ShiftMask );
01043 }
01044 else
01045 {
01046 XUngrabButton( qt_xdisplay(), AnyButton, AnyModifier, wrapperId());
01047
01048 XGrabButton(qt_xdisplay(), AnyButton, AnyModifier, wrapperId(), FALSE,
01049 ButtonPressMask,
01050 GrabModeSync, GrabModeAsync,
01051 None, None );
01052 }
01053 }
01054
01055 int qtToX11Button( Qt::ButtonState button )
01056 {
01057 if( button == Qt::LeftButton )
01058 return Button1;
01059 else if( button == Qt::MidButton )
01060 return Button2;
01061 else if( button == Qt::RightButton )
01062 return Button3;
01063 return AnyButton;
01064 }
01065
01066 int qtToX11State( Qt::ButtonState state )
01067 {
01068 int ret = 0;
01069 if( state & Qt::LeftButton )
01070 ret |= Button1Mask;
01071 if( state & Qt::MidButton )
01072 ret |= Button2Mask;
01073 if( state & Qt::RightButton )
01074 ret |= Button3Mask;
01075 if( state & Qt::ShiftButton )
01076 ret |= ShiftMask;
01077 if( state & Qt::ControlButton )
01078 ret |= ControlMask;
01079 if( state & Qt::AltButton )
01080 ret |= KKeyNative::modX(KKey::ALT);
01081 if( state & Qt::MetaButton )
01082 ret |= KKeyNative::modX(KKey::WIN);
01083 return ret;
01084 }
01085
01086
01087
01088 bool Client::eventFilter( QObject* o, QEvent* e )
01089 {
01090 if( decoration == NULL
01091 || o != decoration->widget())
01092 return false;
01093 if( e->type() == QEvent::MouseButtonPress )
01094 {
01095 QMouseEvent* ev = static_cast< QMouseEvent* >( e );
01096 return buttonPressEvent( decorationId(), qtToX11Button( ev->button()), qtToX11State( ev->state()),
01097 ev->x(), ev->y(), ev->globalX(), ev->globalY() );
01098 }
01099 if( e->type() == QEvent::MouseButtonRelease )
01100 {
01101 QMouseEvent* ev = static_cast< QMouseEvent* >( e );
01102 return buttonReleaseEvent( decorationId(), qtToX11Button( ev->button()), qtToX11State( ev->state()),
01103 ev->x(), ev->y(), ev->globalX(), ev->globalY() );
01104 }
01105 if( e->type() == QEvent::MouseMove )
01106 {
01107 QMouseEvent* ev = static_cast< QMouseEvent* >( e );
01108 return motionNotifyEvent( decorationId(), qtToX11State( ev->state()),
01109 ev->x(), ev->y(), ev->globalX(), ev->globalY() );
01110 }
01111 if( e->type() == QEvent::Wheel )
01112 {
01113 QWheelEvent* ev = static_cast< QWheelEvent* >( e );
01114 bool r = buttonPressEvent( decorationId(), ev->delta() > 0 ? Button4 : Button5, qtToX11State( ev->state()),
01115 ev->x(), ev->y(), ev->globalX(), ev->globalY() );
01116 r = r || buttonReleaseEvent( decorationId(), ev->delta() > 0 ? Button4 : Button5, qtToX11State( ev->state()),
01117 ev->x(), ev->y(), ev->globalX(), ev->globalY() );
01118 return r;
01119 }
01120 if( e->type() == QEvent::Resize )
01121 {
01122 QResizeEvent* ev = static_cast< QResizeEvent* >( e );
01123
01124
01125
01126
01127 if( ev->size() != size())
01128 return true;
01129 }
01130 return false;
01131 }
01132
01133
01134 bool Client::buttonPressEvent( Window w, int button, int state, int x, int y, int x_root, int y_root )
01135 {
01136 if (buttonDown)
01137 {
01138 if( w == wrapperId())
01139 XAllowEvents(qt_xdisplay(), SyncPointer, CurrentTime );
01140 return true;
01141 }
01142
01143 if( w == wrapperId() || w == frameId() || w == decorationId())
01144 {
01145 updateUserTime();
01146 workspace()->setWasUserInteraction();
01147 uint keyModX = (options->keyCmdAllModKey() == Qt::Key_Meta) ?
01148 KKeyNative::modX(KKey::WIN) :
01149 KKeyNative::modX(KKey::ALT);
01150 bool bModKeyHeld = keyModX != 0 && ( state & KKeyNative::accelModMaskX()) == keyModX;
01151
01152 if( isSplash()
01153 && button == Button1 && !bModKeyHeld )
01154 {
01155 hideClient( true );
01156 if( w == wrapperId())
01157 XAllowEvents(qt_xdisplay(), SyncPointer, CurrentTime );
01158 return true;
01159 }
01160
01161 Options::MouseCommand com = Options::MouseNothing;
01162 bool was_action = false;
01163 bool perform_handled = false;
01164 if ( bModKeyHeld )
01165 {
01166 was_action = true;
01167 switch (button)
01168 {
01169 case Button1:
01170 com = options->commandAll1();
01171 break;
01172 case Button2:
01173 com = options->commandAll2();
01174 break;
01175 case Button3:
01176 com = options->commandAll3();
01177 break;
01178 case Button4:
01179 case Button5:
01180 com = options->operationWindowMouseWheel( button == Button4 ? 120 : -120 );
01181 break;
01182 }
01183 }
01184 else
01185 {
01186 if( !isActive() && w == wrapperId())
01187 {
01188 was_action = true;
01189 perform_handled = true;
01190 switch (button)
01191 {
01192 case Button1:
01193 com = options->commandWindow1();
01194 break;
01195 case Button2:
01196 com = options->commandWindow2();
01197 break;
01198 case Button3:
01199 com = options->commandWindow3();
01200 break;
01201 default:
01202 com = Options::MouseActivateAndPassClick;
01203 }
01204 }
01205
01206 if( isActive() && w == wrapperId()
01207 && options->clickRaise && button < 4 )
01208 {
01209 com = Options::MouseActivateRaiseAndPassClick;
01210 was_action = true;
01211 perform_handled = true;
01212 }
01213 }
01214 if( was_action )
01215 {
01216 bool replay = performMouseCommand( com, QPoint( x_root, y_root), perform_handled );
01217
01218 if ( isSpecialWindow())
01219 replay = TRUE;
01220
01221 if( w == wrapperId())
01222 XAllowEvents(qt_xdisplay(), replay? ReplayPointer : SyncPointer, CurrentTime );
01223 return true;
01224 }
01225 }
01226
01227 if( w == wrapperId())
01228 {
01229 XAllowEvents(qt_xdisplay(), ReplayPointer, CurrentTime );
01230 return true;
01231 }
01232 if( w == decorationId())
01233 return false;
01234 if( w == frameId())
01235 processDecorationButtonPress( button, state, x, y, x_root, y_root );
01236 return true;
01237 }
01238
01239
01240
01241
01242 void Client::processDecorationButtonPress( int button, int , int x, int y, int x_root, int y_root )
01243 {
01244 Options::MouseCommand com = Options::MouseNothing;
01245 bool active = isActive();
01246 if ( !wantsInput() )
01247 active = TRUE;
01248
01249 if ( button == Button1 )
01250 com = active ? options->commandActiveTitlebar1() : options->commandInactiveTitlebar1();
01251 else if ( button == Button2 )
01252 com = active ? options->commandActiveTitlebar2() : options->commandInactiveTitlebar2();
01253 else if ( button == Button3 )
01254 com = active ? options->commandActiveTitlebar3() : options->commandInactiveTitlebar3();
01255 if( button == Button1
01256 && com != Options::MouseOperationsMenu
01257 && com != Options::MouseMinimize )
01258 {
01259 mode = mousePosition( QPoint( x, y ));
01260 buttonDown = TRUE;
01261 moveOffset = QPoint( x, y );
01262 invertedMoveOffset = rect().bottomRight() - moveOffset;
01263 unrestrictedMoveResize = false;
01264 setCursor( mode );
01265 }
01266 performMouseCommand( com, QPoint( x_root, y_root ));
01267 }
01268
01269
01270 void Client::processMousePressEvent( QMouseEvent* e )
01271 {
01272 if( e->type() != QEvent::MouseButtonPress )
01273 {
01274 kdWarning() << "processMousePressEvent()" << endl;
01275 return;
01276 }
01277 int button;
01278 switch( e->button())
01279 {
01280 case LeftButton:
01281 button = Button1;
01282 break;
01283 case MidButton:
01284 button = Button2;
01285 break;
01286 case RightButton:
01287 button = Button3;
01288 break;
01289 default:
01290 return;
01291 }
01292 processDecorationButtonPress( button, e->state(), e->x(), e->y(), e->globalX(), e->globalY());
01293 }
01294
01295
01296 bool Client::buttonReleaseEvent( Window w, int , int state, int x, int y, int x_root, int y_root )
01297 {
01298 if( w == decorationId() && !buttonDown)
01299 return false;
01300 if( w == wrapperId())
01301 {
01302 XAllowEvents(qt_xdisplay(), SyncPointer, CurrentTime );
01303 return true;
01304 }
01305 if( w != frameId() && w != decorationId() && w != moveResizeGrabWindow())
01306 return true;
01307 x = this->x();
01308 y = this->y();
01309 if ( (state & ( Button1Mask & Button2Mask & Button3Mask )) == 0 )
01310 {
01311 buttonDown = FALSE;
01312 if ( moveResizeMode )
01313 {
01314 finishMoveResize( false );
01315
01316 QPoint mousepos( x_root - x, y_root - y );
01317 mode = mousePosition( mousepos );
01318 }
01319 setCursor( mode );
01320 }
01321 return true;
01322 }
01323
01324 static bool was_motion = false;
01325 static Time next_motion_time = CurrentTime;
01326
01327
01328
01329
01330
01331
01332
01333 static Bool motion_predicate( Display*, XEvent* ev, XPointer )
01334 {
01335 if( ev->type == MotionNotify )
01336 {
01337 was_motion = true;
01338 next_motion_time = ev->xmotion.time;
01339 }
01340 return False;
01341 }
01342
01343 static bool waitingMotionEvent()
01344 {
01345
01346
01347
01348 if( next_motion_time != CurrentTime
01349 && timestampCompare( qt_x_time, next_motion_time ) < 0 )
01350 return true;
01351 was_motion = false;
01352 XSync( qt_xdisplay(), False );
01353 XEvent dummy;
01354 XCheckIfEvent( qt_xdisplay(), &dummy, motion_predicate, NULL );
01355 return was_motion;
01356 }
01357
01358
01359 bool Client::motionNotifyEvent( Window w, int , int x, int y, int x_root, int y_root )
01360 {
01361 if( w != frameId() && w != decorationId() && w != moveResizeGrabWindow())
01362 return true;
01363 if ( !buttonDown )
01364 {
01365 Position newmode = mousePosition( QPoint( x, y ));
01366 if( newmode != mode )
01367 setCursor( newmode );
01368 mode = newmode;
01369
01370
01371 next_motion_time = CurrentTime;
01372 return false;
01373 }
01374 if( w == moveResizeGrabWindow())
01375 {
01376 x = this->x();
01377 y = this->y();
01378 }
01379 if( !waitingMotionEvent())
01380 handleMoveResize( x, y, x_root, y_root );
01381 return true;
01382 }
01383
01384 void Client::focusInEvent( XFocusInEvent* e )
01385 {
01386 if( e->window != window())
01387 return;
01388 if ( e->mode == NotifyUngrab )
01389 return;
01390 if ( e->detail == NotifyPointer )
01391 return;
01392 if( !isShown( false ) || !isOnCurrentDesktop())
01393 return;
01394
01395 bool activate = workspace()->allowClientActivation( this, -1U, true );
01396 workspace()->gotFocusIn( this );
01397 if( activate )
01398 setActive( TRUE );
01399 else
01400 {
01401 workspace()->restoreFocus();
01402 demandAttention();
01403 }
01404 }
01405
01406
01407
01408
01409
01410
01411
01412
01413
01414
01415
01416
01417
01418
01419
01420 static bool follows_focusin = false;
01421 static bool follows_focusin_failed = false;
01422 static Bool predicate_follows_focusin( Display*, XEvent* e, XPointer arg )
01423 {
01424 if( follows_focusin || follows_focusin_failed )
01425 return False;
01426 Client* c = ( Client* ) arg;
01427 if( e->type == FocusIn && c->workspace()->findClient( WindowMatchPredicate( e->xfocus.window )))
01428 {
01429 follows_focusin = true;
01430 return False;
01431 }
01432
01433
01434 if( e->type == FocusIn || e->type == FocusOut || e->type == KeymapNotify )
01435 return False;
01436 follows_focusin_failed = true;
01437 return False;
01438 }
01439
01440 static bool check_follows_focusin( Client* c )
01441 {
01442 follows_focusin = follows_focusin_failed = false;
01443 XEvent dummy;
01444
01445
01446
01447 XCheckIfEvent( qt_xdisplay(), &dummy, predicate_follows_focusin, (XPointer)c );
01448 return follows_focusin;
01449 }
01450
01451
01452 void Client::focusOutEvent( XFocusOutEvent* e )
01453 {
01454 if( e->window != window())
01455 return;
01456 if ( e->mode == NotifyGrab )
01457 return;
01458 if ( isShade() )
01459 return;
01460 if ( e->detail != NotifyNonlinear
01461 && e->detail != NotifyNonlinearVirtual )
01462
01463 return;
01464 if ( QApplication::activePopupWidget() )
01465 return;
01466 if( !check_follows_focusin( this ))
01467 setActive( FALSE );
01468 }
01469
01470
01471 void Client::NETMoveResize( int x_root, int y_root, NET::Direction direction )
01472 {
01473 if( direction == NET::Move )
01474 performMouseCommand( Options::MouseMove, QPoint( x_root, y_root ));
01475 else if( moveResizeMode && direction == NET::MoveResizeCancel )
01476 {
01477 finishMoveResize( true );
01478 buttonDown = FALSE;
01479 setCursor( mode );
01480 }
01481 else if( direction >= NET::TopLeft && direction <= NET::Left )
01482 {
01483 static const Position convert[] =
01484 {
01485 PositionTopLeft,
01486 PositionTop,
01487 PositionTopRight,
01488 PositionRight,
01489 PositionBottomRight,
01490 PositionBottom,
01491 PositionBottomLeft,
01492 PositionLeft
01493 };
01494 if(!isResizable() || isShade())
01495 return;
01496 if( moveResizeMode )
01497 finishMoveResize( false );
01498 buttonDown = TRUE;
01499 moveOffset = QPoint( x_root - x(), y_root - y());
01500 invertedMoveOffset = rect().bottomRight() - moveOffset;
01501 unrestrictedMoveResize = false;
01502 mode = convert[ direction ];
01503 setCursor( mode );
01504 if( !startMoveResize())
01505 {
01506 buttonDown = false;
01507 setCursor( mode );
01508 }
01509 }
01510 else if( direction == NET::KeyboardMove )
01511 {
01512 QCursor::setPos( geometry().center() );
01513 performMouseCommand( Options::MouseUnrestrictedMove, geometry().center());
01514 }
01515 else if( direction == NET::KeyboardSize )
01516 {
01517 QCursor::setPos( geometry().bottomRight());
01518 performMouseCommand( Options::MouseUnrestrictedResize, geometry().bottomRight());
01519 }
01520 }
01521
01522 void Client::keyPressEvent( uint key_code )
01523 {
01524 updateUserTime();
01525 if ( !isMove() && !isResize() )
01526 return;
01527 bool is_control = key_code & Qt::CTRL;
01528 bool is_alt = key_code & Qt::ALT;
01529 key_code = key_code & 0xffff;
01530 int delta = is_control?1:is_alt?32:8;
01531 QPoint pos = QCursor::pos();
01532 switch ( key_code )
01533 {
01534 case Key_Left:
01535 pos.rx() -= delta;
01536 break;
01537 case Key_Right:
01538 pos.rx() += delta;
01539 break;
01540 case Key_Up:
01541 pos.ry() -= delta;
01542 break;
01543 case Key_Down:
01544 pos.ry() += delta;
01545 break;
01546 case Key_Space:
01547 case Key_Return:
01548 case Key_Enter:
01549 finishMoveResize( false );
01550 buttonDown = FALSE;
01551 setCursor( mode );
01552 break;
01553 case Key_Escape:
01554 finishMoveResize( true );
01555 buttonDown = FALSE;
01556 setCursor( mode );
01557 break;
01558 default:
01559 return;
01560 }
01561 QCursor::setPos( pos );
01562 }
01563
01564
01565
01566
01567
01568 bool Group::groupEvent( XEvent* e )
01569 {
01570 unsigned long dirty[ 2 ];
01571 leader_info->event( e, dirty, 2 );
01572 if ( ( dirty[ WinInfo::PROTOCOLS ] & NET::WMIcon) != 0 )
01573 getIcons();
01574 if(( dirty[ WinInfo::PROTOCOLS2 ] & NET::WM2StartupId ) != 0 )
01575 startupIdChanged();
01576 return false;
01577 }
01578
01579
01580 }