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()
00418 && ( e->xfocus.detail == NotifyDetailNone || e->xfocus.detail == NotifyPointerRoot ))
00419 {
00420 updateXTime();
00421 Window focus;
00422 int revert;
00423 XGetInputFocus( qt_xdisplay(), &focus, &revert );
00424 if( focus == None || focus == PointerRoot )
00425 {
00426
00427 if( mostRecentlyActivatedClient() != NULL )
00428 requestFocus( mostRecentlyActivatedClient(), true );
00429 else
00430 focusToNull();
00431 }
00432 }
00433
00434 case FocusOut:
00435 return true;
00436 default:
00437 break;
00438 }
00439 return FALSE;
00440 }
00441
00442
00443
00444
00445 Window Workspace::findSpecialEventWindow( XEvent* e )
00446 {
00447 switch( e->type )
00448 {
00449 case CreateNotify:
00450 return e->xcreatewindow.window;
00451 case DestroyNotify:
00452 return e->xdestroywindow.window;
00453 case UnmapNotify:
00454 return e->xunmap.window;
00455 case MapNotify:
00456 return e->xmap.window;
00457 case MapRequest:
00458 return e->xmaprequest.window;
00459 case ReparentNotify:
00460 return e->xreparent.window;
00461 case ConfigureNotify:
00462 return e->xconfigure.window;
00463 case GravityNotify:
00464 return e->xgravity.window;
00465 case ConfigureRequest:
00466 return e->xconfigurerequest.window;
00467 case CirculateNotify:
00468 return e->xcirculate.window;
00469 case CirculateRequest:
00470 return e->xcirculaterequest.window;
00471 default:
00472 return None;
00473 };
00474 }
00475
00479 bool Workspace::netCheck( XEvent* e )
00480 {
00481 unsigned int dirty = rootInfo->event( e );
00482
00483 if ( dirty & NET::DesktopNames )
00484 saveDesktopSettings();
00485
00486 return dirty != 0;
00487 }
00488
00489
00490
00491
00492
00493
00497 bool Client::windowEvent( XEvent* e )
00498 {
00499 if( e->xany.window == window())
00500 {
00501 unsigned long dirty[ 2 ];
00502 info->event( e, dirty, 2 );
00503
00504 if ( ( dirty[ WinInfo::PROTOCOLS ] & NET::WMName ) != 0 )
00505 fetchName();
00506 if ( ( dirty[ WinInfo::PROTOCOLS ] & NET::WMIconName ) != 0 )
00507 fetchIconicName();
00508 if ( ( dirty[ WinInfo::PROTOCOLS ] & NET::WMStrut ) != 0 )
00509 {
00510 if( isTopMenu())
00511 checkWorkspacePosition();
00512 workspace()->updateClientArea();
00513 }
00514 if ( ( dirty[ WinInfo::PROTOCOLS ] & NET::WMIcon) != 0 )
00515 getIcons();
00516
00517
00518
00519 if(( dirty[ WinInfo::PROTOCOLS2 ] & NET::WM2UserTime ) != 0 )
00520 {
00521 workspace()->setWasUserInteraction();
00522 updateUserTime( info->userTime());
00523 }
00524 if(( dirty[ WinInfo::PROTOCOLS2 ] & NET::WM2StartupId ) != 0 )
00525 startupIdChanged();
00526 }
00527
00528
00529 switch (e->type)
00530 {
00531 case UnmapNotify:
00532 unmapNotifyEvent( &e->xunmap );
00533 break;
00534 case DestroyNotify:
00535 destroyNotifyEvent( &e->xdestroywindow );
00536 break;
00537 case MapRequest:
00538
00539 return mapRequestEvent( &e->xmaprequest );
00540 case ConfigureRequest:
00541 configureRequestEvent( &e->xconfigurerequest );
00542 break;
00543 case PropertyNotify:
00544 propertyNotifyEvent( &e->xproperty );
00545 break;
00546 case KeyPress:
00547 updateUserTime();
00548 workspace()->setWasUserInteraction();
00549 break;
00550 case ButtonPress:
00551 updateUserTime();
00552 workspace()->setWasUserInteraction();
00553 buttonPressEvent( e->xbutton.window, e->xbutton.button, e->xbutton.state,
00554 e->xbutton.x, e->xbutton.y, e->xbutton.x_root, e->xbutton.y_root );
00555 break;;
00556 case KeyRelease:
00557
00558
00559
00560 break;
00561 case ButtonRelease:
00562
00563
00564
00565 buttonReleaseEvent( e->xbutton.window, e->xbutton.button, e->xbutton.state,
00566 e->xbutton.x, e->xbutton.y, e->xbutton.x_root, e->xbutton.y_root );
00567 break;
00568 case MotionNotify:
00569 motionNotifyEvent( e->xmotion.window, e->xmotion.state,
00570 e->xmotion.x, e->xmotion.y, e->xmotion.x_root, e->xmotion.y_root );
00571 break;
00572 case EnterNotify:
00573 enterNotifyEvent( &e->xcrossing );
00574
00575
00576
00577
00578
00579 motionNotifyEvent( e->xcrossing.window, e->xcrossing.state,
00580 e->xcrossing.x, e->xcrossing.y, e->xcrossing.x_root, e->xcrossing.y_root );
00581 break;
00582 case LeaveNotify:
00583 motionNotifyEvent( e->xcrossing.window, e->xcrossing.state,
00584 e->xcrossing.x, e->xcrossing.y, e->xcrossing.x_root, e->xcrossing.y_root );
00585 leaveNotifyEvent( &e->xcrossing );
00586 break;
00587 case FocusIn:
00588 focusInEvent( &e->xfocus );
00589 break;
00590 case FocusOut:
00591 focusOutEvent( &e->xfocus );
00592 break;
00593 case ReparentNotify:
00594 break;
00595 case ClientMessage:
00596 clientMessageEvent( &e->xclient );
00597 break;
00598 case ColormapChangeMask:
00599 if( e->xany.window == window())
00600 {
00601 cmap = e->xcolormap.colormap;
00602 if ( isActive() )
00603 workspace()->updateColormap();
00604 }
00605 break;
00606 case VisibilityNotify:
00607 visibilityNotifyEvent( &e->xvisibility );
00608 break;
00609 default:
00610 if( e->xany.window == window())
00611 {
00612 if( e->type == Shape::shapeEvent() )
00613 {
00614 is_shape = Shape::hasShape( window());
00615 updateShape();
00616 }
00617 }
00618 break;
00619 }
00620 return true;
00621 }
00622
00626 bool Client::mapRequestEvent( XMapRequestEvent* e )
00627 {
00628 if( e->window != window())
00629 {
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642 if( e->parent == wrapperId())
00643 return false;
00644 return true;
00645 }
00646 if( isTopMenu() && workspace()->managingTopMenus())
00647 return true;
00648 switch ( mappingState() )
00649 {
00650 case WithdrawnState:
00651 assert( false );
00652
00653 break;
00654 case IconicState:
00655
00656 if( isMinimized())
00657 unminimize();
00658 if( isShade())
00659 setShade( ShadeNone );
00660 if( !isOnCurrentDesktop())
00661 {
00662 if( workspace()->allowClientActivation( this ))
00663 workspace()->activateClient( this );
00664 else
00665 demandAttention();
00666 }
00667 break;
00668 case NormalState:
00669
00670 break;
00671 }
00672 return true;
00673 }
00674
00678 void Client::unmapNotifyEvent( XUnmapEvent* e )
00679 {
00680 if( e->window != window())
00681 return;
00682 if( e->event != wrapperId())
00683 {
00684 bool ignore = true;
00685 if( e->event == workspace()->rootWin() && e->send_event )
00686 ignore = false;
00687 if( ignore )
00688 return;
00689 }
00690 switch( mappingState())
00691 {
00692 case IconicState:
00693 releaseWindow();
00694 return;
00695 case NormalState:
00696
00697 XEvent ev;
00698 if( XCheckTypedWindowEvent (qt_xdisplay(), window(),
00699 DestroyNotify, &ev) )
00700 {
00701 destroyClient();
00702 return;
00703 }
00704 releaseWindow();
00705 break;
00706 default:
00707 assert( false );
00708 }
00709 }
00710
00711 void Client::destroyNotifyEvent( XDestroyWindowEvent* e )
00712 {
00713 if( e->window != window())
00714 return;
00715 destroyClient();
00716 }
00717
00718
00719 bool blockAnimation = FALSE;
00720
00724 void Client::clientMessageEvent( XClientMessageEvent* e )
00725 {
00726 if( e->window != window())
00727 return;
00728
00729 if ( e->message_type == atoms->kde_wm_change_state )
00730 {
00731 if( isTopMenu() && workspace()->managingTopMenus())
00732 return;
00733 if( e->data.l[ 1 ] )
00734 blockAnimation = true;
00735 if( e->data.l[ 0 ] == IconicState )
00736 minimize();
00737 else if( e->data.l[ 0 ] == NormalState )
00738 {
00739 if( isMinimized())
00740 unminimize();
00741 if( isShade())
00742 setShade( ShadeNone );
00743 if( !isOnCurrentDesktop())
00744 {
00745 if( workspace()->allowClientActivation( this ))
00746 workspace()->activateClient( this );
00747 else
00748 demandAttention();
00749 }
00750 }
00751 blockAnimation = false;
00752 }
00753 else if ( e->message_type == atoms->wm_change_state)
00754 {
00755 if( isTopMenu() && workspace()->managingTopMenus())
00756 return;
00757 if ( e->data.l[0] == IconicState )
00758 minimize();
00759 return;
00760 }
00761 }
00762
00763
00767 void Client::configureRequestEvent( XConfigureRequestEvent* e )
00768 {
00769 if( e->window != window())
00770 return;
00771 if ( isResize() || isMove())
00772 return;
00773
00774 if( isFullScreen()
00775 || isSplash()
00776 || isTopMenu())
00777 {
00778 sendSyntheticConfigureNotify();
00779 return;
00780 }
00781
00782 if ( e->value_mask & CWBorderWidth )
00783 {
00784
00785 XWindowChanges wc;
00786 unsigned int value_mask = 0;
00787
00788 wc.border_width = 0;
00789 value_mask = CWBorderWidth;
00790 XConfigureWindow( qt_xdisplay(), window(), value_mask, & wc );
00791 }
00792
00793 if( e->value_mask & ( CWX | CWY | CWHeight | CWWidth ))
00794 configureRequest( e->value_mask, e->x, e->y, e->width, e->height );
00795
00796 if ( e->value_mask & CWStackMode )
00797 restackWindow( e->above, e->detail, NET::FromApplication );
00798
00799
00800
00801
00802
00803 sendSyntheticConfigureNotify();
00804
00805
00806
00807 }
00808
00809
00813 void Client::propertyNotifyEvent( XPropertyEvent* e )
00814 {
00815 if( e->window != window())
00816 return;
00817 switch ( e->atom )
00818 {
00819 case XA_WM_NORMAL_HINTS:
00820 getWmNormalHints();
00821 break;
00822 case XA_WM_NAME:
00823 fetchName();
00824 break;
00825 case XA_WM_ICON_NAME:
00826 fetchIconicName();
00827 break;
00828 case XA_WM_TRANSIENT_FOR:
00829 readTransient();
00830 break;
00831 case XA_WM_HINTS:
00832 getWMHints();
00833 getIcons();
00834 break;
00835 default:
00836 if ( e->atom == atoms->wm_protocols )
00837 getWindowProtocols();
00838 else if (e->atom == atoms->wm_client_leader )
00839 getWmClientLeader();
00840 else if( e->atom == qt_window_role )
00841 window_role = getStringProperty( window(), qt_window_role );
00842 break;
00843 }
00844 }
00845
00846
00847 void Client::enterNotifyEvent( XCrossingEvent* e )
00848 {
00849 if( e->window != frameId())
00850 return;
00851 if( e->mode == NotifyNormal ||
00852 ( !options->focusPolicyIsReasonable() &&
00853 e->mode == NotifyUngrab ) )
00854 {
00855
00856 if (options->shadeHover && isShade())
00857 {
00858 delete shadeHoverTimer;
00859 shadeHoverTimer = new QTimer( this );
00860 connect( shadeHoverTimer, SIGNAL( timeout() ), this, SLOT( shadeHover() ));
00861 shadeHoverTimer->start( options->shadeHoverInterval, TRUE );
00862 }
00863
00864 if ( options->focusPolicy == Options::ClickToFocus )
00865 return;
00866
00867 if ( options->autoRaise && !isDesktop() &&
00868 !isDock() && !isTopMenu() && workspace()->focusChangeEnabled() &&
00869 workspace()->topClientOnDesktop( workspace()->currentDesktop()) != this )
00870 {
00871 delete autoRaiseTimer;
00872 autoRaiseTimer = new QTimer( this );
00873 connect( autoRaiseTimer, SIGNAL( timeout() ), this, SLOT( autoRaise() ) );
00874 autoRaiseTimer->start( options->autoRaiseInterval, TRUE );
00875 }
00876
00877 if ( options->focusPolicy != Options::FocusStrictlyUnderMouse && ( isDesktop() || isDock() || isTopMenu() ) )
00878 return;
00879
00880 workspace()->requestFocus( this );
00881 return;
00882 }
00883 }
00884
00885 void Client::leaveNotifyEvent( XCrossingEvent* e )
00886 {
00887 if( e->window != frameId())
00888 return;
00889 if ( e->mode == NotifyNormal )
00890 {
00891 if ( !buttonDown )
00892 {
00893 mode = PositionCenter;
00894 setCursor( arrowCursor );
00895 }
00896 bool lostMouse = !rect().contains( QPoint( e->x, e->y ) );
00897
00898
00899
00900
00901
00902
00903
00904 if ( !lostMouse && e->detail != NotifyInferior )
00905 {
00906 int d1, d2, d3, d4;
00907 unsigned int d5;
00908 Window w, child;
00909 if( XQueryPointer( qt_xdisplay(), frameId(), &w, &child, &d1, &d2, &d3, &d4, &d5 ) == False
00910 || child == None )
00911 lostMouse = true;
00912 }
00913 if ( lostMouse )
00914 {
00915 cancelAutoRaise();
00916 delete shadeHoverTimer;
00917 shadeHoverTimer = 0;
00918 if ( shade_mode == ShadeHover && !moveResizeMode && !buttonDown )
00919 setShade( ShadeNormal );
00920 }
00921 if ( options->focusPolicy == Options::FocusStrictlyUnderMouse )
00922 if ( isActive() && lostMouse )
00923 workspace()->requestFocus( 0 ) ;
00924 return;
00925 }
00926 }
00927
00928 #define XCapL KKeyNative::modXLock()
00929 #define XNumL KKeyNative::modXNumLock()
00930 #define XScrL KKeyNative::modXScrollLock()
00931 void Client::grabButton( int modifier )
00932 {
00933 unsigned int mods[ 8 ] =
00934 {
00935 0, XCapL, XNumL, XNumL | XCapL,
00936 XScrL, XScrL | XCapL,
00937 XScrL | XNumL, XScrL | XNumL | XCapL
00938 };
00939 for( int i = 0;
00940 i < 8;
00941 ++i )
00942 XGrabButton( qt_xdisplay(), AnyButton,
00943 modifier | mods[ i ],
00944 wrapperId(), FALSE, ButtonPressMask,
00945 GrabModeSync, GrabModeAsync, None, None );
00946 }
00947
00948 void Client::ungrabButton( int modifier )
00949 {
00950 unsigned int mods[ 8 ] =
00951 {
00952 0, XCapL, XNumL, XNumL | XCapL,
00953 XScrL, XScrL | XCapL,
00954 XScrL | XNumL, XScrL | XNumL | XCapL
00955 };
00956 for( int i = 0;
00957 i < 8;
00958 ++i )
00959 XUngrabButton( qt_xdisplay(), AnyButton,
00960 modifier | mods[ i ], wrapperId());
00961 }
00962 #undef XCapL
00963 #undef XNumL
00964 #undef XScrL
00965
00966
00967
00968
00969
00970
00971
00972 void Client::updateMouseGrab()
00973 {
00974 if( isActive() )
00975 {
00976
00977
00978 if( !options->clickRaise || not_obscured )
00979 ungrabButton( None );
00980 else
00981 grabButton( None );
00982 ungrabButton( ShiftMask );
00983 ungrabButton( ControlMask );
00984 ungrabButton( ControlMask | ShiftMask );
00985 }
00986 else
00987 {
00988 XUngrabButton( qt_xdisplay(), AnyButton, AnyModifier, wrapperId());
00989
00990 XGrabButton(qt_xdisplay(), AnyButton, AnyModifier, wrapperId(), FALSE,
00991 ButtonPressMask,
00992 GrabModeSync, GrabModeAsync,
00993 None, None );
00994 }
00995 }
00996
00997 int qtToX11Button( Qt::ButtonState button )
00998 {
00999 if( button == Qt::LeftButton )
01000 return Button1;
01001 else if( button == Qt::MidButton )
01002 return Button2;
01003 else if( button == Qt::RightButton )
01004 return Button3;
01005 return AnyButton;
01006 }
01007
01008 int qtToX11State( Qt::ButtonState state )
01009 {
01010 int ret = 0;
01011 if( state & Qt::LeftButton )
01012 ret |= Button1Mask;
01013 if( state & Qt::MidButton )
01014 ret |= Button2Mask;
01015 if( state & Qt::RightButton )
01016 ret |= Button3Mask;
01017 if( state & Qt::ShiftButton )
01018 ret |= ShiftMask;
01019 if( state & Qt::ControlButton )
01020 ret |= ControlMask;
01021 if( state & Qt::AltButton )
01022 ret |= KKeyNative::modX(KKey::ALT);
01023 if( state & Qt::MetaButton )
01024 ret |= KKeyNative::modX(KKey::WIN);
01025 return ret;
01026 }
01027
01028
01029
01030 bool Client::eventFilter( QObject* o, QEvent* e )
01031 {
01032 if( decoration == NULL
01033 || o != decoration->widget())
01034 return false;
01035 if( e->type() == QEvent::MouseButtonPress )
01036 {
01037 QMouseEvent* ev = static_cast< QMouseEvent* >( e );
01038 return buttonPressEvent( decorationId(), qtToX11Button( ev->button()), qtToX11State( ev->state()),
01039 ev->x(), ev->y(), ev->globalX(), ev->globalY() );
01040 }
01041 if( e->type() == QEvent::MouseButtonRelease )
01042 {
01043 QMouseEvent* ev = static_cast< QMouseEvent* >( e );
01044 return buttonReleaseEvent( decorationId(), qtToX11Button( ev->button()), qtToX11State( ev->state()),
01045 ev->x(), ev->y(), ev->globalX(), ev->globalY() );
01046 }
01047 if( e->type() == QEvent::MouseMove )
01048 {
01049 QMouseEvent* ev = static_cast< QMouseEvent* >( e );
01050 return motionNotifyEvent( decorationId(), qtToX11State( ev->state()),
01051 ev->x(), ev->y(), ev->globalX(), ev->globalY() );
01052 }
01053 if( e->type() == QEvent::Resize )
01054 {
01055 QResizeEvent* ev = static_cast< QResizeEvent* >( e );
01056
01057
01058
01059
01060 if( ev->size() != size())
01061 return true;
01062 }
01063 return false;
01064 }
01065
01066
01067 bool Client::buttonPressEvent( Window w, int button, int state, int x, int y, int x_root, int y_root )
01068 {
01069 if (buttonDown)
01070 {
01071 if( w == wrapperId())
01072 XAllowEvents(qt_xdisplay(), SyncPointer, CurrentTime );
01073 return true;
01074 }
01075
01076 if( w == wrapperId() || w == frameId() || w == decorationId())
01077 {
01078 updateUserTime();
01079 workspace()->setWasUserInteraction();
01080 uint keyModX = (options->keyCmdAllModKey() == Qt::Key_Meta) ?
01081 KKeyNative::modX(KKey::WIN) :
01082 KKeyNative::modX(KKey::ALT);
01083 bool bModKeyHeld = keyModX != 0 && ( state & KKeyNative::accelModMaskX()) == keyModX;
01084
01085 if( isSplash()
01086 && button == Button1 && !bModKeyHeld )
01087 {
01088 hideClient( true );
01089 if( w == wrapperId())
01090 XAllowEvents(qt_xdisplay(), SyncPointer, CurrentTime );
01091 return true;
01092 }
01093
01094 if ( isActive() && w == wrapperId()
01095 && ( options->clickRaise && !bModKeyHeld ) )
01096 {
01097 if ( button < 4 )
01098 autoRaise();
01099 }
01100
01101 Options::MouseCommand com = Options::MouseNothing;
01102 bool was_action = false;
01103 if ( bModKeyHeld )
01104 {
01105 was_action = true;
01106 switch (button)
01107 {
01108 case Button1:
01109 com = options->commandAll1();
01110 break;
01111 case Button2:
01112 com = options->commandAll2();
01113 break;
01114 case Button3:
01115 com = options->commandAll3();
01116 break;
01117 }
01118 }
01119 else
01120 {
01121 if( !isActive() && w == wrapperId())
01122 {
01123 was_action = true;
01124 switch (button)
01125 {
01126 case Button1:
01127 com = options->commandWindow1();
01128 break;
01129 case Button2:
01130 com = options->commandWindow2();
01131 break;
01132 case Button3:
01133 com = options->commandWindow3();
01134 break;
01135 default:
01136 com = Options::MouseActivateAndPassClick;
01137 }
01138 }
01139 }
01140 if( was_action )
01141 {
01142 bool replay = performMouseCommand( com, QPoint( x_root, y_root) );
01143
01144 if ( isSpecialWindow() && !isOverride())
01145 replay = TRUE;
01146
01147 if( w == wrapperId())
01148 XAllowEvents(qt_xdisplay(), replay? ReplayPointer : SyncPointer, CurrentTime );
01149 return true;
01150 }
01151 }
01152
01153 if( w == wrapperId())
01154 {
01155 XAllowEvents(qt_xdisplay(), ReplayPointer, CurrentTime );
01156 return true;
01157 }
01158 if( w == decorationId())
01159 return false;
01160 if( w == frameId())
01161 processDecorationButtonPress( button, state, x, y, x_root, y_root );
01162 return true;
01163 }
01164
01165
01166
01167
01168 void Client::processDecorationButtonPress( int button, int , int x, int y, int x_root, int y_root )
01169 {
01170 Options::MouseCommand com = Options::MouseNothing;
01171 bool active = isActive();
01172 if ( !wantsInput() )
01173 active = TRUE;
01174
01175 if ( button == Button1 )
01176 com = active ? options->commandActiveTitlebar1() : options->commandInactiveTitlebar1();
01177 else if ( button == Button2 )
01178 com = active ? options->commandActiveTitlebar2() : options->commandInactiveTitlebar2();
01179 else if ( button == Button3 )
01180 com = active ? options->commandActiveTitlebar3() : options->commandInactiveTitlebar3();
01181 if( com != Options::MouseOperationsMenu
01182 && com != Options::MouseMinimize )
01183 {
01184
01185 buttonDown = TRUE;
01186 moveOffset = QPoint( x, y );
01187 invertedMoveOffset = rect().bottomRight() - moveOffset;
01188 unrestrictedMoveResize = false;
01189 setCursor( mode );
01190 }
01191 performMouseCommand( com, QPoint( x_root, y_root ));
01192 }
01193
01194
01195 void Client::processMousePressEvent( QMouseEvent* e )
01196 {
01197 if( e->type() != QEvent::MouseButtonPress )
01198 {
01199 kdWarning() << "processMousePressEvent()" << endl;
01200 return;
01201 }
01202 int button;
01203 switch( e->button())
01204 {
01205 case LeftButton:
01206 button = Button1;
01207 break;
01208 case MidButton:
01209 button = Button2;
01210 break;
01211 case RightButton:
01212 button = Button3;
01213 break;
01214 default:
01215 return;
01216 }
01217 processDecorationButtonPress( button, e->state(), e->x(), e->y(), e->globalX(), e->globalY());
01218 }
01219
01220
01221 bool Client::buttonReleaseEvent( Window w, int , int state, int x, int y, int x_root, int y_root )
01222 {
01223 if( w == decorationId() && !buttonDown)
01224 return false;
01225 if( w == wrapperId())
01226 {
01227 XAllowEvents(qt_xdisplay(), SyncPointer, CurrentTime );
01228 return true;
01229 }
01230 if( w != frameId() && w != decorationId() && w != moveResizeGrabWindow())
01231 return true;
01232 x = this->x();
01233 y = this->y();
01234 if ( (state & ( Button1Mask & Button2Mask & Button3Mask )) == 0 )
01235 {
01236 buttonDown = FALSE;
01237 if ( moveResizeMode )
01238 {
01239 finishMoveResize( false );
01240
01241 QPoint mousepos( x_root - x, y_root - y );
01242 mode = mousePosition( mousepos );
01243 }
01244 setCursor( mode );
01245 }
01246 return true;
01247 }
01248
01249 static bool was_motion = false;
01250 static Time next_motion_time = CurrentTime;
01251
01252
01253
01254
01255
01256
01257
01258 static Bool motion_predicate( Display*, XEvent* ev, XPointer )
01259 {
01260 if( ev->type == MotionNotify )
01261 {
01262 was_motion = true;
01263 next_motion_time = ev->xmotion.time;
01264 }
01265 return False;
01266 }
01267
01268 static bool waitingMotionEvent()
01269 {
01270
01271
01272
01273 if( next_motion_time != CurrentTime
01274 && timestampCompare( qt_x_time, next_motion_time ) < 0 )
01275 return true;
01276 was_motion = false;
01277 XSync( qt_xdisplay(), False );
01278 XEvent dummy;
01279 XCheckIfEvent( qt_xdisplay(), &dummy, motion_predicate, NULL );
01280 return was_motion;
01281 }
01282
01283
01284 bool Client::motionNotifyEvent( Window w, int , int x, int y, int x_root, int y_root )
01285 {
01286 if( w != frameId() && w != decorationId() && w != moveResizeGrabWindow())
01287 return true;
01288 if ( !buttonDown )
01289 {
01290 Position newmode = mousePosition( QPoint( x, y ));
01291 if( newmode != mode )
01292 setCursor( newmode );
01293 mode = newmode;
01294 return false;
01295 }
01296 if( w == moveResizeGrabWindow())
01297 {
01298 x = this->x();
01299 y = this->y();
01300 }
01301 if( !waitingMotionEvent())
01302 handleMoveResize( x, y, x_root, y_root );
01303 return true;
01304 }
01305
01306 void Client::focusInEvent( XFocusInEvent* e )
01307 {
01308 if( e->window != window())
01309 return;
01310 if ( e->mode == NotifyUngrab )
01311 return;
01312 if ( e->detail == NotifyPointer )
01313 return;
01314 if( !isShown( false ) || !isOnCurrentDesktop())
01315 return;
01316
01317 bool activate = workspace()->allowClientActivation( this, -1U, true );
01318 workspace()->gotFocusIn( this );
01319 if( activate )
01320 setActive( TRUE );
01321 else
01322 {
01323 workspace()->restoreFocus();
01324 demandAttention();
01325 }
01326 }
01327
01328
01329
01330
01331
01332
01333
01334
01335
01336
01337
01338
01339
01340
01341
01342 static bool follows_focusin = false;
01343 static bool follows_focusin_failed = false;
01344 static Bool predicate_follows_focusin( Display*, XEvent* e, XPointer arg )
01345 {
01346 if( follows_focusin || follows_focusin_failed )
01347 return False;
01348 Client* c = ( Client* ) arg;
01349 if( e->type == FocusIn && c->workspace()->findClient( WindowMatchPredicate( e->xfocus.window )))
01350 {
01351 follows_focusin = true;
01352 return False;
01353 }
01354
01355
01356 if( e->type == FocusIn || e->type == FocusOut || e->type == KeymapNotify )
01357 return False;
01358 follows_focusin_failed = true;
01359 return False;
01360 }
01361
01362 static bool check_follows_focusin( Client* c )
01363 {
01364 follows_focusin = follows_focusin_failed = false;
01365 XEvent dummy;
01366
01367
01368
01369 XCheckIfEvent( qt_xdisplay(), &dummy, predicate_follows_focusin, (XPointer)c );
01370 return follows_focusin;
01371 }
01372
01373
01374 void Client::focusOutEvent( XFocusOutEvent* e )
01375 {
01376 if( e->window != window())
01377 return;
01378 if ( e->mode == NotifyGrab )
01379 return;
01380 if ( isShade() )
01381 return;
01382 if ( e->detail != NotifyNonlinear
01383 && e->detail != NotifyNonlinearVirtual )
01384
01385 return;
01386 if ( QApplication::activePopupWidget() )
01387 return;
01388 if( !check_follows_focusin( this ))
01389 setActive( FALSE );
01390 }
01391
01392 void Client::visibilityNotifyEvent( XVisibilityEvent * e)
01393 {
01394 if( e->window != frameId())
01395 return;
01396 bool new_not_obscured = e->state == VisibilityUnobscured;
01397 if( not_obscured == new_not_obscured )
01398 return;
01399 not_obscured = new_not_obscured;
01400 updateMouseGrab();
01401 }
01402
01403
01404 void Client::NETMoveResize( int x_root, int y_root, NET::Direction direction )
01405 {
01406 if( direction == NET::Move )
01407 performMouseCommand( Options::MouseMove, QPoint( x_root, y_root ));
01408 else if( direction >= NET::TopLeft && direction <= NET::Left )
01409 {
01410 static const Position convert[] =
01411 {
01412 PositionTopLeft,
01413 PositionTop,
01414 PositionTopRight,
01415 PositionRight,
01416 PositionBottomRight,
01417 PositionBottom,
01418 PositionBottomLeft,
01419 PositionLeft
01420 };
01421 if(!isResizable() || isShade())
01422 return;
01423 if( moveResizeMode )
01424 finishMoveResize( false );
01425 buttonDown = TRUE;
01426 moveOffset = QPoint( x_root - x(), y_root - y());
01427 invertedMoveOffset = rect().bottomRight() - moveOffset;
01428 unrestrictedMoveResize = false;
01429 mode = convert[ direction ];
01430 setCursor( mode );
01431 if( !startMoveResize())
01432 {
01433 buttonDown = false;
01434 setCursor( mode );
01435 }
01436 }
01437 else if( direction == NET::KeyboardMove )
01438 {
01439 QCursor::setPos( geometry().center() );
01440 performMouseCommand( Options::MouseUnrestrictedMove, geometry().center());
01441 }
01442 else if( direction == NET::KeyboardSize )
01443 {
01444 QCursor::setPos( geometry().bottomRight());
01445 performMouseCommand( Options::MouseUnrestrictedResize, geometry().bottomRight());
01446 }
01447 }
01448
01449 void Client::keyPressEvent( uint key_code )
01450 {
01451 updateUserTime();
01452 if ( !isMove() && !isResize() )
01453 return;
01454 bool is_control = key_code & Qt::CTRL;
01455 bool is_alt = key_code & Qt::ALT;
01456 key_code = key_code & 0xffff;
01457 int delta = is_control?1:is_alt?32:8;
01458 QPoint pos = QCursor::pos();
01459 switch ( key_code )
01460 {
01461 case Key_Left:
01462 pos.rx() -= delta;
01463 break;
01464 case Key_Right:
01465 pos.rx() += delta;
01466 break;
01467 case Key_Up:
01468 pos.ry() -= delta;
01469 break;
01470 case Key_Down:
01471 pos.ry() += delta;
01472 break;
01473 case Key_Space:
01474 case Key_Return:
01475 case Key_Enter:
01476 finishMoveResize( false );
01477 buttonDown = FALSE;
01478 setCursor( mode );
01479 break;
01480 case Key_Escape:
01481 finishMoveResize( true );
01482 buttonDown = FALSE;
01483 setCursor( mode );
01484 break;
01485 default:
01486 return;
01487 }
01488 QCursor::setPos( pos );
01489 }
01490
01491
01492
01493
01494
01495 bool Group::groupEvent( XEvent* e )
01496 {
01497 unsigned long dirty[ 2 ];
01498 leader_info->event( e, dirty, 2 );
01499 if ( ( dirty[ WinInfo::PROTOCOLS ] & NET::WMIcon) != 0 )
01500 getIcons();
01501 if(( dirty[ WinInfo::PROTOCOLS2 ] & NET::WM2StartupId ) != 0 )
01502 startupIdChanged();
01503 return false;
01504 }
01505
01506
01507 }