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