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