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