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