• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • twin
 

twin

  • twin
events.cpp
1/*****************************************************************
2 KWin - the KDE window manager
3 This file is part of the KDE project.
4
5Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org>
6Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org>
7
8You can Freely distribute this program under the GNU General Public
9License. See the file "COPYING" for the exact licensing terms.
10******************************************************************/
11
12/*
13
14 This file contains things relevant to handling incoming events.
15
16*/
17
18#include "client.h"
19#include "workspace.h"
20#include "atoms.h"
21#include "tabbox.h"
22#include "group.h"
23#include "rules.h"
24
25#include <tqwhatsthis.h>
26#include <kkeynative.h>
27#include <tqapplication.h>
28
29#include <X11/extensions/shape.h>
30#include <X11/Xatom.h>
31#include <stdlib.h>
32
33extern Atom tqt_window_role;
34
35namespace KWinInternal
36{
37
38// ****************************************
39// WinInfo
40// ****************************************
41
42WinInfo::WinInfo( Client * c, Display * display, Window window,
43 Window rwin, const unsigned long pr[], int pr_size )
44 : NETWinInfo( display, window, rwin, pr, pr_size, NET::WindowManager ), m_client( c )
45 {
46 }
47
48void WinInfo::changeDesktop(int desktop)
49 {
50 m_client->workspace()->sendClientToDesktop( m_client, desktop, true );
51 }
52
53void WinInfo::changeState( unsigned long state, unsigned long mask )
54 {
55 mask &= ~NET::Sticky; // KWin doesn't support large desktops, ignore
56 mask &= ~NET::Hidden; // clients are not allowed to change this directly
57 state &= mask; // for safety, clear all other bits
58
59 if(( mask & NET::FullScreen ) != 0 && ( state & NET::FullScreen ) == 0 )
60 m_client->setFullScreen( false, false );
61 if ( (mask & NET::Max) == NET::Max )
62 m_client->setMaximize( state & NET::MaxVert, state & NET::MaxHoriz );
63 else if ( mask & NET::MaxVert )
64 m_client->setMaximize( state & NET::MaxVert, m_client->maximizeMode() & Client::MaximizeHorizontal );
65 else if ( mask & NET::MaxHoriz )
66 m_client->setMaximize( m_client->maximizeMode() & Client::MaximizeVertical, state & NET::MaxHoriz );
67
68 if ( mask & NET::Shaded )
69 m_client->setShade( state & NET::Shaded ? ShadeNormal : ShadeNone );
70 if ( mask & NET::KeepAbove)
71 m_client->setKeepAbove( (state & NET::KeepAbove) != 0 );
72 if ( mask & NET::KeepBelow)
73 m_client->setKeepBelow( (state & NET::KeepBelow) != 0 );
74 if( mask & NET::SkipTaskbar )
75 m_client->setSkipTaskbar( ( state & NET::SkipTaskbar ) != 0, true );
76 if( mask & NET::SkipPager )
77 m_client->setSkipPager( ( state & NET::SkipPager ) != 0 );
78 if( mask & NET::DemandsAttention )
79 m_client->demandAttention(( state & NET::DemandsAttention ) != 0 );
80 if( mask & NET::Modal )
81 m_client->setModal( ( state & NET::Modal ) != 0 );
82 // unsetting fullscreen first, setting it last (because e.g. maximize works only for !isFullScreen() )
83 if(( mask & NET::FullScreen ) != 0 && ( state & NET::FullScreen ) != 0 )
84 m_client->setFullScreen( true, false );
85 }
86
87
88// ****************************************
89// RootInfo
90// ****************************************
91
92RootInfo::RootInfo( Workspace* ws, Display *dpy, Window w, const char *name, unsigned long pr[], int pr_num, int scr )
93 : NETRootInfo4( dpy, w, name, pr, pr_num, scr )
94 {
95 workspace = ws;
96 }
97
98void RootInfo::changeNumberOfDesktops(int n)
99 {
100 workspace->setNumberOfDesktops( n );
101 }
102
103void RootInfo::changeCurrentDesktop(int d)
104 {
105 workspace->setCurrentDesktop( d );
106 }
107
108void RootInfo::changeActiveWindow( Window w, NET::RequestSource src, Time timestamp, Window active_window )
109 {
110 if( Client* c = workspace->findClient( WindowMatchPredicate( w )))
111 {
112 if( timestamp == CurrentTime )
113 timestamp = c->userTime();
114 if( src != NET::FromApplication && src != FromTool )
115 src = NET::FromTool;
116 if( src == NET::FromTool )
117 workspace->activateClient( c, true ); // force
118 else // NET::FromApplication
119 {
120 Client* c2;
121 if( workspace->allowClientActivation( c, timestamp ))
122 workspace->activateClient( c );
123 // if activation of the requestor's window would be allowed, allow activation too
124 else if( active_window != None
125 && ( c2 = workspace->findClient( WindowMatchPredicate( active_window ))) != NULL
126 && workspace->allowClientActivation( c2,
127 timestampCompare( timestamp, c2->userTime() > 0 ? timestamp : c2->userTime())))
128 workspace->activateClient( c );
129 else
130 c->demandAttention();
131 }
132 }
133 }
134
135void RootInfo::restackWindow( Window w, RequestSource src, Window above, int detail, Time timestamp )
136 {
137 if( Client* c = workspace->findClient( WindowMatchPredicate( w )))
138 {
139 if( timestamp == CurrentTime )
140 timestamp = c->userTime();
141 if( src != NET::FromApplication && src != FromTool )
142 src = NET::FromTool;
143 c->restackWindow( above, detail, src, timestamp, true );
144 }
145 }
146
147void RootInfo::gotTakeActivity( Window w, Time timestamp, long flags )
148 {
149 if( Client* c = workspace->findClient( WindowMatchPredicate( w )))
150 workspace->handleTakeActivity( c, timestamp, flags );
151 }
152
153void RootInfo::closeWindow(Window w)
154 {
155 Client* c = workspace->findClient( WindowMatchPredicate( w ));
156 if ( c )
157 c->closeWindow();
158 }
159
160void RootInfo::moveResize(Window w, int x_root, int y_root, unsigned long direction)
161 {
162 Client* c = workspace->findClient( WindowMatchPredicate( w ));
163 if ( c )
164 {
165 updateXTime(); // otherwise grabbing may have old timestamp - this message should include timestamp
166 c->NETMoveResize( x_root, y_root, (Direction)direction);
167 }
168 }
169
170void RootInfo::moveResizeWindow(Window w, int flags, int x, int y, int width, int height )
171 {
172 Client* c = workspace->findClient( WindowMatchPredicate( w ));
173 if ( c )
174 c->NETMoveResizeWindow( flags, x, y, width, height );
175 }
176
177void RootInfo::gotPing( Window w, Time timestamp )
178 {
179 if( Client* c = workspace->findClient( WindowMatchPredicate( w )))
180 c->gotPing( timestamp );
181 }
182
183void RootInfo::changeShowingDesktop( bool showing )
184 {
185 workspace->setShowingDesktop( showing );
186 }
187
188// ****************************************
189// Workspace
190// ****************************************
191
195bool Workspace::workspaceEvent( XEvent * e )
196 {
197 if ( mouse_emulation && (e->type == ButtonPress || e->type == ButtonRelease ) )
198 {
199 mouse_emulation = FALSE;
200 XUngrabKeyboard( tqt_xdisplay(), GET_QT_X_TIME() );
201 }
202
203 if( e->type == PropertyNotify || e->type == ClientMessage )
204 {
205 unsigned long dirty[ NETRootInfo::PROPERTIES_SIZE ];
206 rootInfo->event( e, dirty, NETRootInfo::PROPERTIES_SIZE );
207 if( dirty[ NETRootInfo::PROTOCOLS ] & NET::DesktopNames )
208 saveDesktopSettings();
209 if( dirty[ NETRootInfo::PROTOCOLS2 ] & NET::WM2DesktopLayout )
210 updateDesktopLayout();
211 }
212
213 // events that should be handled before Clients can get them
214 switch (e->type)
215 {
216 case ButtonPress:
217 case ButtonRelease:
218 was_user_interaction = true;
219 // fallthrough
220 case MotionNotify:
221 if ( tab_grab || control_grab )
222 {
223 tab_box->handleMouseEvent( e );
224 return TRUE;
225 }
226 break;
227 case KeyPress:
228 {
229 was_user_interaction = true;
230 KKeyNative keyX( (XEvent*)e );
231 uint keyQt = keyX.keyCodeQt();
232 kdDebug(125) << "Workspace::keyPress( " << keyX.key().toString() << " )" << endl;
233 if (movingClient)
234 {
235 movingClient->keyPressEvent(keyQt);
236 return true;
237 }
238 if( tab_grab || control_grab )
239 {
240 tabBoxKeyPress( keyX );
241 return true;
242 }
243 break;
244 }
245 case KeyRelease:
246 was_user_interaction = true;
247 if( tab_grab || control_grab )
248 {
249 tabBoxKeyRelease( e->xkey );
250 return true;
251 }
252 break;
253 };
254
255 if( Client* c = findClient( WindowMatchPredicate( e->xany.window )))
256 {
257 if( c->windowEvent( e ))
258 return true;
259 }
260 else if( Client* c = findClient( WrapperIdMatchPredicate( e->xany.window )))
261 {
262 if( c->windowEvent( e ))
263 return true;
264 }
265 else if( Client* c = findClient( FrameIdMatchPredicate( e->xany.window )))
266 {
267 if( c->windowEvent( e ))
268 return true;
269 }
270 else
271 {
272 Window special = findSpecialEventWindow( e );
273 if( special != None )
274 if( Client* c = findClient( WindowMatchPredicate( special )))
275 {
276 if( c->windowEvent( e ))
277 return true;
278 }
279 }
280 if( movingClient != NULL && movingClient->moveResizeGrabWindow() == e->xany.window
281 && ( e->type == MotionNotify || e->type == ButtonPress || e->type == ButtonRelease ))
282 {
283 if( movingClient->windowEvent( e ))
284 return true;
285 }
286
287 switch (e->type)
288 {
289 case CreateNotify:
290 if ( e->xcreatewindow.parent == root &&
291 !TQWidget::find( e->xcreatewindow.window) &&
292 !e->xcreatewindow.override_redirect )
293 {
294 // see comments for allowClientActivation()
295 Time my_qtx_time = GET_QT_X_TIME();
296 XChangeProperty(tqt_xdisplay(), e->xcreatewindow.window,
297 atoms->kde_net_wm_user_creation_time, XA_CARDINAL,
298 32, PropModeReplace, (unsigned char *)&my_qtx_time, 1);
299 SET_QT_X_TIME(my_qtx_time);
300 }
301 break;
302
303 case UnmapNotify:
304 {
305 // check for system tray windows
306 if ( removeSystemTrayWin( e->xunmap.window, true ) )
307 {
308 // If the system tray gets destroyed, the system tray
309 // icons automatically get unmapped, reparented and mapped
310 // again to the closest non-client ancestor due to
311 // QXEmbed's SaveSet feature. Unfortunatly with kicker
312 // this closest ancestor is not the root window, but our
313 // decoration, so we reparent explicitely back to the root
314 // window.
315 XEvent ev;
316 WId w = e->xunmap.window;
317 if ( XCheckTypedWindowEvent (tqt_xdisplay(), w,
318 ReparentNotify, &ev) )
319 {
320 if ( ev.xreparent.parent != root )
321 {
322 XReparentWindow( tqt_xdisplay(), w, root, 0, 0 );
323 addSystemTrayWin( w );
324 }
325 }
326 return TRUE;
327 }
328
329 return ( e->xunmap.event != e->xunmap.window ); // hide wm typical event from Qt
330 }
331 case MapNotify:
332
333 return ( e->xmap.event != e->xmap.window ); // hide wm typical event from Qt
334
335 case ReparentNotify:
336 {
337 //do not confuse Qt with these events. After all, _we_ are the
338 //window manager who does the reparenting.
339 return TRUE;
340 }
341 case DestroyNotify:
342 {
343 if ( removeSystemTrayWin( e->xdestroywindow.window, false ) )
344 return TRUE;
345 return false;
346 }
347 case MapRequest:
348 {
349 updateXTime();
350
351 // e->xmaprequest.window is different from e->xany.window
352 // TODO this shouldn't be necessary now
353 Client* c = findClient( WindowMatchPredicate( e->xmaprequest.window ));
354 if ( !c )
355 {
356// don't check for the parent being the root window, this breaks when some app unmaps
357// a window, changes something and immediately maps it back, without giving KWin
358// a chance to reparent it back to root
359// since KWin can get MapRequest only for root window children and
360// children of WindowWrapper (=clients), the check is AFAIK useless anyway
361// Note: Now the save-set support in Client::mapRequestEvent() actually requires that
362// this code doesn't check the parent to be root.
363// if ( e->xmaprequest.parent == root ) { //###TODO store previously destroyed client ids
364 if ( addSystemTrayWin( e->xmaprequest.window ) )
365 return TRUE;
366 c = createClient( e->xmaprequest.window, false );
367 if ( c != NULL && root != tqt_xrootwin() )
368 { // TODO what is this?
369 // TODO may use TQWidget::create
370 XReparentWindow( tqt_xdisplay(), c->frameId(), root, 0, 0 );
371 }
372 if( c == NULL ) // refused to manage, simply map it (most probably override redirect)
373 XMapRaised( tqt_xdisplay(), e->xmaprequest.window );
374 return true;
375 }
376 if( c )
377 {
378 c->windowEvent( e );
379 updateFocusChains( c, FocusChainUpdate );
380 return true;
381 }
382 break;
383 }
384 case EnterNotify:
385 {
386 if ( TQWhatsThis::inWhatsThisMode() )
387 {
388 TQWidget* w = TQWidget::find( e->xcrossing.window );
389 if ( w )
390 TQWhatsThis::leaveWhatsThisMode();
391 }
392 if (activeBorderEvent(e))
393 return true;
394 break;
395 }
396 case LeaveNotify:
397 {
398 if ( !TQWhatsThis::inWhatsThisMode() )
399 break;
400 // TODO is this cliente ever found, given that client events are searched above?
401 Client* c = findClient( FrameIdMatchPredicate( e->xcrossing.window ));
402 if ( c && e->xcrossing.detail != NotifyInferior )
403 TQWhatsThis::leaveWhatsThisMode();
404 break;
405 }
406 case ConfigureRequest:
407 {
408 if ( e->xconfigurerequest.parent == root )
409 {
410 XWindowChanges wc;
411 wc.border_width = e->xconfigurerequest.border_width;
412 wc.x = e->xconfigurerequest.x;
413 wc.y = e->xconfigurerequest.y;
414 wc.width = e->xconfigurerequest.width;
415 wc.height = e->xconfigurerequest.height;
416 wc.sibling = None;
417 wc.stack_mode = Above;
418 unsigned int value_mask = e->xconfigurerequest.value_mask
419 & ( CWX | CWY | CWWidth | CWHeight | CWBorderWidth );
420 XConfigureWindow( tqt_xdisplay(), e->xconfigurerequest.window, value_mask, &wc );
421 return true;
422 }
423 break;
424 }
425 case KeyPress:
426 if ( mouse_emulation )
427 return keyPressMouseEmulation( e->xkey );
428 break;
429 case KeyRelease:
430 if ( mouse_emulation )
431 return FALSE;
432 break;
433 case FocusIn:
434 if( e->xfocus.window == rootWin() && TQCString( getenv("TDE_MULTIHEAD")).lower() != "true"
435 && ( e->xfocus.detail == NotifyDetailNone || e->xfocus.detail == NotifyPointerRoot ))
436 {
437 updateXTime(); // focusToNull() uses tqt_x_time, which is old now (FocusIn has no timestamp)
438 Window focus;
439 int revert;
440 XGetInputFocus( tqt_xdisplay(), &focus, &revert );
441 if( focus == None || focus == PointerRoot )
442 {
443 //kdWarning( 1212 ) << "X focus set to None/PointerRoot, reseting focus" << endl;
444 Client *c = mostRecentlyActivatedClient();
445 if( c != NULL )
446 requestFocus( c, true );
447 else if( activateNextClient( NULL ))
448 ; // ok, activated
449 else
450 focusToNull();
451 }
452 }
453 // fall through
454 case FocusOut:
455 return true; // always eat these, they would tell Qt that KWin is the active app
456 case ClientMessage:
457 if (activeBorderEvent(e))
458 return true;
459 break;
460 default:
461 break;
462 }
463 return FALSE;
464 }
465
466// Some events don't have the actual window which caused the event
467// as e->xany.window (e.g. ConfigureRequest), but as some other
468// field in the XEvent structure.
469Window Workspace::findSpecialEventWindow( XEvent* e )
470 {
471 switch( e->type )
472 {
473 case CreateNotify:
474 return e->xcreatewindow.window;
475 case DestroyNotify:
476 return e->xdestroywindow.window;
477 case UnmapNotify:
478 return e->xunmap.window;
479 case MapNotify:
480 return e->xmap.window;
481 case MapRequest:
482 return e->xmaprequest.window;
483 case ReparentNotify:
484 return e->xreparent.window;
485 case ConfigureNotify:
486 return e->xconfigure.window;
487 case GravityNotify:
488 return e->xgravity.window;
489 case ConfigureRequest:
490 return e->xconfigurerequest.window;
491 case CirculateNotify:
492 return e->xcirculate.window;
493 case CirculateRequest:
494 return e->xcirculaterequest.window;
495 default:
496 return None;
497 };
498 }
499
500// ****************************************
501// Client
502// ****************************************
503
507bool Client::windowEvent( XEvent* e )
508 {
509 if( e->xany.window == window()) // avoid doing stuff on frame or wrapper
510 {
511 unsigned long dirty[ 2 ];
512 info->event( e, dirty, 2 ); // pass through the NET stuff
513
514 if ( ( dirty[ WinInfo::PROTOCOLS ] & NET::WMName ) != 0 )
515 fetchName();
516 if ( ( dirty[ WinInfo::PROTOCOLS ] & NET::WMIconName ) != 0 )
517 fetchIconicName();
518 if ( ( dirty[ WinInfo::PROTOCOLS ] & NET::WMStrut ) != 0
519 || ( dirty[ WinInfo::PROTOCOLS2 ] & NET::WM2ExtendedStrut ) != 0 )
520 {
521 if( isTopMenu()) // the fallback mode of KMenuBar may alter the strut
522 checkWorkspacePosition(); // restore it
523 workspace()->updateClientArea();
524 }
525 if ( ( dirty[ WinInfo::PROTOCOLS ] & NET::WMIcon) != 0 )
526 getIcons();
527 // Note there's a difference between userTime() and info->userTime()
528 // info->userTime() is the value of the property, userTime() also includes
529 // updates of the time done by KWin (ButtonPress on windowrapper etc.).
530 if(( dirty[ WinInfo::PROTOCOLS2 ] & NET::WM2UserTime ) != 0 )
531 {
532 workspace()->setWasUserInteraction();
533 updateUserTime( info->userTime());
534 }
535 if(( dirty[ WinInfo::PROTOCOLS2 ] & NET::WM2StartupId ) != 0 )
536 startupIdChanged();
537 if( dirty[ WinInfo::PROTOCOLS ] & NET::WMIconGeometry )
538 {
539 if( demandAttentionKNotifyTimer != NULL )
540 demandAttentionKNotify();
541 }
542 }
543
544// TODO move all focus handling stuff to separate file?
545 switch (e->type)
546 {
547 case UnmapNotify:
548 unmapNotifyEvent( &e->xunmap );
549 break;
550 case DestroyNotify:
551 destroyNotifyEvent( &e->xdestroywindow );
552 break;
553 case MapRequest:
554 // this one may pass the event to workspace
555 return mapRequestEvent( &e->xmaprequest );
556 case ConfigureRequest:
557 configureRequestEvent( &e->xconfigurerequest );
558 break;
559 case PropertyNotify:
560 propertyNotifyEvent( &e->xproperty );
561 break;
562 case KeyPress:
563 updateUserTime();
564 workspace()->setWasUserInteraction();
565 break;
566 case ButtonPress:
567 updateUserTime();
568 workspace()->setWasUserInteraction();
569 buttonPressEvent( e->xbutton.window, e->xbutton.button, e->xbutton.state,
570 e->xbutton.x, e->xbutton.y, e->xbutton.x_root, e->xbutton.y_root );
571 break;
572 case KeyRelease:
573 // don't update user time on releases
574 // e.g. if the user presses Alt+F2, the Alt release
575 // would appear as user input to the currently active window
576 break;
577 case ButtonRelease:
578 // don't update user time on releases
579 // e.g. if the user presses Alt+F2, the Alt release
580 // would appear as user input to the currently active window
581 buttonReleaseEvent( e->xbutton.window, e->xbutton.button, e->xbutton.state,
582 e->xbutton.x, e->xbutton.y, e->xbutton.x_root, e->xbutton.y_root );
583 break;
584 case MotionNotify:
585 motionNotifyEvent( e->xmotion.window, e->xmotion.state,
586 e->xmotion.x, e->xmotion.y, e->xmotion.x_root, e->xmotion.y_root );
587 workspace()->updateFocusMousePosition( TQPoint( e->xmotion.x_root, e->xmotion.y_root ));
588 break;
589 case EnterNotify:
590 enterNotifyEvent( &e->xcrossing );
591 // MotionNotify is guaranteed to be generated only if the mouse
592 // move start and ends in the window; for cases when it only
593 // starts or only ends there, Enter/LeaveNotify are generated.
594 // Fake a MotionEvent in such cases to make handle of mouse
595 // events simpler (Qt does that too).
596 motionNotifyEvent( e->xcrossing.window, e->xcrossing.state,
597 e->xcrossing.x, e->xcrossing.y, e->xcrossing.x_root, e->xcrossing.y_root );
598 workspace()->updateFocusMousePosition( TQPoint( e->xcrossing.x_root, e->xcrossing.y_root ));
599 break;
600 case LeaveNotify:
601 motionNotifyEvent( e->xcrossing.window, e->xcrossing.state,
602 e->xcrossing.x, e->xcrossing.y, e->xcrossing.x_root, e->xcrossing.y_root );
603 leaveNotifyEvent( &e->xcrossing );
604 // not here, it'd break following enter notify handling
605 // workspace()->updateFocusMousePosition( TQPoint( e->xcrossing.x_root, e->xcrossing.y_root ));
606 break;
607 case FocusIn:
608 focusInEvent( &e->xfocus );
609 break;
610 case FocusOut:
611 focusOutEvent( &e->xfocus );
612 break;
613 case ReparentNotify:
614 break;
615 case ClientMessage:
616 clientMessageEvent( &e->xclient );
617 break;
618 case ColormapChangeMask:
619 if( e->xany.window == window())
620 {
621 cmap = e->xcolormap.colormap;
622 if ( isActive() )
623 workspace()->updateColormap();
624 }
625 break;
626 default:
627 if( e->xany.window == window())
628 {
629 if( e->type == Shape::shapeEvent() )
630 {
631 is_shape = Shape::hasShape( window()); // workaround for #19644
632 updateShape();
633 }
634 }
635 break;
636 }
637 return true; // eat all events
638 }
639
643bool Client::mapRequestEvent( XMapRequestEvent* e )
644 {
645 if( e->window != window())
646 {
647 // Special support for the save-set feature, which is a bit broken.
648 // If there's a window from one client embedded in another one,
649 // e.g. using XEMBED, and the embedder suddenly looses its X connection,
650 // save-set will reparent the embedded window to its closest ancestor
651 // that will remains. Unfortunately, with reparenting window managers,
652 // this is not the root window, but the frame (or in KWin's case,
653 // it's the wrapper for the client window). In this case,
654 // the wrapper will get ReparentNotify for a window it won't know,
655 // which will be ignored, and then it gets MapRequest, as save-set
656 // always maps. Returning true here means that Workspace::workspaceEvent()
657 // will handle this MapRequest and manage this window (i.e. act as if
658 // it was reparented to root window).
659 if( e->parent == wrapperId())
660 return false;
661 return true; // no messing with frame etc.
662 }
663 if( isTopMenu() && workspace()->managingTopMenus())
664 return true; // twin controls these
665 switch ( mappingState() )
666 {
667 case WithdrawnState:
668 assert( false ); // WMs are not supposed to manage clients in Withdrawn state,
669// manage(); // after initial mapping manage() is called from createClient()
670 break;
671 case IconicState:
672 // also copied in clientMessage()
673 if( isMinimized())
674 unminimize();
675 if( isShade())
676 setShade( ShadeNone );
677 if( !isOnCurrentDesktop())
678 {
679 if( workspace()->allowClientActivation( this ))
680 workspace()->activateClient( this );
681 else
682 demandAttention();
683 }
684 break;
685 case NormalState:
686 // TODO fake MapNotify?
687 break;
688 }
689 return true;
690 }
691
695void Client::unmapNotifyEvent( XUnmapEvent* e )
696 {
697 if( e->window != window())
698 return;
699 if( e->event != wrapperId())
700 { // most probably event from root window when initially reparenting
701 bool ignore = true;
702 if( e->event == workspace()->rootWin() && e->send_event )
703 ignore = false; // XWithdrawWindow()
704 if( ignore )
705 return;
706 }
707 switch( mappingState())
708 {
709 case IconicState:
710 releaseWindow();
711 return;
712 case NormalState:
713 // maybe we will be destroyed soon. Check this first.
714 XEvent ev;
715 if( XCheckTypedWindowEvent (tqt_xdisplay(), window(),
716 DestroyNotify, &ev) ) // TODO I don't like this much
717 {
718 destroyClient(); // deletes this
719 return;
720 }
721 releaseWindow();
722 break;
723 default:
724 assert( false );
725 }
726 }
727
728void Client::destroyNotifyEvent( XDestroyWindowEvent* e )
729 {
730 if( e->window != window())
731 return;
732 destroyClient();
733 }
734
735
736bool blockAnimation = FALSE;
737
741void Client::clientMessageEvent( XClientMessageEvent* e )
742 {
743 if( e->window != window())
744 return; // ignore frame/wrapper
745 // WM_STATE
746 if ( e->message_type == atoms->kde_wm_change_state )
747 {
748 if( isTopMenu() && workspace()->managingTopMenus())
749 return; // twin controls these
750 if( e->data.l[ 1 ] )
751 blockAnimation = true;
752 if( e->data.l[ 0 ] == IconicState )
753 minimize();
754 else if( e->data.l[ 0 ] == NormalState )
755 { // copied from mapRequest()
756 if( isMinimized())
757 unminimize();
758 if( isShade())
759 setShade( ShadeNone );
760 if( !isOnCurrentDesktop())
761 {
762 if( workspace()->allowClientActivation( this ))
763 workspace()->activateClient( this );
764 else
765 demandAttention();
766 }
767 }
768 blockAnimation = false;
769 }
770 else if ( e->message_type == atoms->wm_change_state)
771 {
772 if( isTopMenu() && workspace()->managingTopMenus())
773 return; // twin controls these
774 if ( e->data.l[0] == IconicState )
775 minimize();
776 return;
777 }
778 }
779
780
784void Client::configureRequestEvent( XConfigureRequestEvent* e )
785 {
786 if( e->window != window())
787 return; // ignore frame/wrapper
788 if ( isResize() || isMove())
789 return; // we have better things to do right now
790
791 if( fullscreen_mode == FullScreenNormal ) // refuse resizing of fullscreen windows
792 { // but allow resizing fullscreen hacks in order to let them cancel fullscreen mode
793 sendSyntheticConfigureNotify();
794 return;
795 }
796 if( isSplash() // no manipulations with splashscreens either
797 || isTopMenu()) // topmenus neither
798 {
799 sendSyntheticConfigureNotify();
800 return;
801 }
802
803 if ( e->value_mask & CWBorderWidth )
804 {
805 // first, get rid of a window border
806 XWindowChanges wc;
807 unsigned int value_mask = 0;
808
809 wc.border_width = 0;
810 value_mask = CWBorderWidth;
811 XConfigureWindow( tqt_xdisplay(), window(), value_mask, & wc );
812 }
813
814 if( e->value_mask & ( CWX | CWY | CWHeight | CWWidth ))
815 configureRequest( e->value_mask, e->x, e->y, e->width, e->height, 0, false );
816
817 if ( e->value_mask & CWStackMode )
818 restackWindow( e->above, e->detail, NET::FromApplication, userTime(), false );
819
820 // TODO sending a synthetic configure notify always is fine, even in cases where
821 // the ICCCM doesn't require this - it can be though of as 'the WM decided to move
822 // the window later'. The client should not cause that many configure request,
823 // so this should not have any significant impact. With user moving/resizing
824 // the it should be optimized though (see also Client::setGeometry()/plainResize()/move()).
825 sendSyntheticConfigureNotify();
826
827 // SELI TODO accept configure requests for isDesktop windows (because kdesktop
828 // may get XRANDR resize event before twin), but check it's still at the bottom?
829 }
830
831
835void Client::propertyNotifyEvent( XPropertyEvent* e )
836 {
837 if( e->window != window())
838 return; // ignore frame/wrapper
839 switch ( e->atom )
840 {
841 case XA_WM_NORMAL_HINTS:
842 getWmNormalHints();
843 break;
844 case XA_WM_NAME:
845 fetchName();
846 break;
847 case XA_WM_ICON_NAME:
848 fetchIconicName();
849 break;
850 case XA_WM_TRANSIENT_FOR:
851 readTransient();
852 break;
853 case XA_WM_HINTS:
854 getWMHints();
855 getIcons(); // because KWin::icon() uses WMHints as fallback
856 break;
857 default:
858 if ( e->atom == atoms->wm_protocols )
859 getWindowProtocols();
860 else if (e->atom == atoms->wm_client_leader )
861 getWmClientLeader();
862 else if( e->atom == tqt_window_role )
863 window_role = staticWindowRole( window());
864 else if( e->atom == atoms->motif_wm_hints )
865 getMotifHints();
866 break;
867 }
868 }
869
870
871void Client::enterNotifyEvent( XCrossingEvent* e )
872 {
873 if( e->window != frameId())
874 return; // care only about entering the whole frame
875 if( e->mode == NotifyNormal ||
876 ( !options->focusPolicyIsReasonable() &&
877 e->mode == NotifyUngrab ) )
878 {
879
880 if (options->shadeHover && isShade())
881 {
882 delete shadeHoverTimer;
883 shadeHoverTimer = new TQTimer( this );
884 connect( shadeHoverTimer, TQT_SIGNAL( timeout() ), this, TQT_SLOT( shadeHover() ));
885 shadeHoverTimer->start( options->shadeHoverInterval, TRUE );
886 }
887
888 if ( options->focusPolicy == Options::ClickToFocus )
889 return;
890
891 if ( options->autoRaise && !isDesktop() &&
892 !isDock() && !isTopMenu() && workspace()->focusChangeEnabled() &&
893 workspace()->topClientOnDesktop( workspace()->currentDesktop()) != this )
894 {
895 delete autoRaiseTimer;
896 autoRaiseTimer = new TQTimer( this );
897 connect( autoRaiseTimer, TQT_SIGNAL( timeout() ), this, TQT_SLOT( autoRaise() ) );
898 autoRaiseTimer->start( options->autoRaiseInterval, TRUE );
899 }
900
901 TQPoint currentPos( e->x_root, e->y_root );
902 if ( options->focusPolicy != Options::FocusStrictlyUnderMouse && ( isDesktop() || isDock() || isTopMenu() ) )
903 return;
904 // for FocusFollowsMouse, change focus only if the mouse has actually been moved, not if the focus
905 // change came because of window changes (e.g. closing a window) - #92290
906 if( options->focusPolicy != Options::FocusFollowsMouse
907 || currentPos != workspace()->focusMousePosition())
908 {
909 if ( options->delayFocus )
910 workspace()->requestDelayFocus( this );
911 else
912 workspace()->requestFocus( this );
913 }
914 return;
915 }
916 }
917
918void Client::leaveNotifyEvent( XCrossingEvent* e )
919 {
920 if( e->window != frameId())
921 return; // care only about leaving the whole frame
922 if ( e->mode == NotifyNormal )
923 {
924 if ( !buttonDown )
925 {
926 mode = PositionCenter;
927 setCursor( tqarrowCursor );
928 }
929 bool lostMouse = !rect().contains( TQPoint( e->x, e->y ) );
930 // 'lostMouse' wouldn't work with e.g. B2 or Keramik, which have non-rectangular decorations
931 // (i.e. the LeaveNotify event comes before leaving the rect and no LeaveNotify event
932 // comes after leaving the rect) - so lets check if the pointer is really outside the window
933
934 // TODO this still sucks if a window appears above this one - it should lose the mouse
935 // if this window is another client, but not if it's a popup ... maybe after KDE3.1 :(
936 // (repeat after me 'AARGHL!')
937 if ( !lostMouse && e->detail != NotifyInferior )
938 {
939 int d1, d2, d3, d4;
940 unsigned int d5;
941 Window w, child;
942 if( XQueryPointer( tqt_xdisplay(), frameId(), &w, &child, &d1, &d2, &d3, &d4, &d5 ) == False
943 || child == None )
944 lostMouse = true; // really lost the mouse
945 }
946 if ( lostMouse )
947 {
948 cancelAutoRaise();
949 workspace()->cancelDelayFocus();
950 cancelShadeHover();
951 if ( shade_mode == ShadeHover && !moveResizeMode && !buttonDown )
952 setShade( ShadeNormal );
953 }
954 if ( options->focusPolicy == Options::FocusStrictlyUnderMouse )
955 if ( isActive() && lostMouse )
956 workspace()->requestFocus( 0 ) ;
957 return;
958 }
959 }
960
961#define XCapL KKeyNative::modXLock()
962#define XNumL KKeyNative::modXNumLock()
963#define XScrL KKeyNative::modXScrollLock()
964void Client::grabButton( int modifier )
965 {
966 unsigned int mods[ 8 ] =
967 {
968 0, XCapL, XNumL, XNumL | XCapL,
969 XScrL, XScrL | XCapL,
970 XScrL | XNumL, XScrL | XNumL | XCapL
971 };
972 for( int i = 0;
973 i < 8;
974 ++i )
975 XGrabButton( tqt_xdisplay(), AnyButton,
976 modifier | mods[ i ],
977 wrapperId(), FALSE, ButtonPressMask,
978 GrabModeSync, GrabModeAsync, None, None );
979 }
980
981void Client::ungrabButton( int modifier )
982 {
983 unsigned int mods[ 8 ] =
984 {
985 0, XCapL, XNumL, XNumL | XCapL,
986 XScrL, XScrL | XCapL,
987 XScrL | XNumL, XScrL | XNumL | XCapL
988 };
989 for( int i = 0;
990 i < 8;
991 ++i )
992 XUngrabButton( tqt_xdisplay(), AnyButton,
993 modifier | mods[ i ], wrapperId());
994 }
995#undef XCapL
996#undef XNumL
997#undef XScrL
998
999/*
1000 Releases the passive grab for some modifier combinations when a
1001 window becomes active. This helps broken X programs that
1002 missinterpret LeaveNotify events in grab mode to work properly
1003 (Motif, AWT, Tk, ...)
1004 */
1005void Client::updateMouseGrab()
1006 {
1007 if( workspace()->globalShortcutsDisabled())
1008 {
1009 XUngrabButton( tqt_xdisplay(), AnyButton, AnyModifier, wrapperId());
1010 // keep grab for the simple click without modifiers if needed (see below)
1011 bool not_obscured = workspace()->topClientOnDesktop( workspace()->currentDesktop(), true, false ) == this;
1012 if( !( !options->clickRaise || not_obscured ))
1013 grabButton( None );
1014 return;
1015 }
1016 if( isActive() && !workspace()->forcedGlobalMouseGrab()) // see Workspace::establishTabBoxGrab()
1017 {
1018 // first grab all modifier combinations
1019 XGrabButton(tqt_xdisplay(), AnyButton, AnyModifier, wrapperId(), FALSE,
1020 ButtonPressMask,
1021 GrabModeSync, GrabModeAsync,
1022 None, None );
1023 // remove the grab for no modifiers only if the window
1024 // is unobscured or if the user doesn't want click raise
1025 // (it is unobscured if it the topmost in the unconstrained stacking order, i.e. it is
1026 // the most recently raised window)
1027 bool not_obscured = workspace()->topClientOnDesktop( workspace()->currentDesktop(), true, false ) == this;
1028 if( !options->clickRaise || not_obscured )
1029 ungrabButton( None );
1030 else
1031 grabButton( None );
1032 ungrabButton( ShiftMask );
1033 ungrabButton( ControlMask );
1034 ungrabButton( ControlMask | ShiftMask );
1035 }
1036 else
1037 {
1038 XUngrabButton( tqt_xdisplay(), AnyButton, AnyModifier, wrapperId());
1039 // simply grab all modifier combinations
1040 XGrabButton(tqt_xdisplay(), AnyButton, AnyModifier, wrapperId(), FALSE,
1041 ButtonPressMask,
1042 GrabModeSync, GrabModeAsync,
1043 None, None );
1044 }
1045 }
1046
1047int qtToX11Button( TQt::ButtonState button )
1048 {
1049 if( button == TQt::LeftButton )
1050 return Button1;
1051 else if( button == TQt::MidButton )
1052 return Button2;
1053 else if( button == TQt::RightButton )
1054 return Button3;
1055 return AnyButton;
1056 }
1057
1058int qtToX11State( TQt::ButtonState state )
1059 {
1060 int ret = 0;
1061 if( state & TQt::LeftButton )
1062 ret |= Button1Mask;
1063 if( state & TQt::MidButton )
1064 ret |= Button2Mask;
1065 if( state & TQt::RightButton )
1066 ret |= Button3Mask;
1067 if( state & TQt::ShiftButton )
1068 ret |= ShiftMask;
1069 if( state & TQt::ControlButton )
1070 ret |= ControlMask;
1071 if( state & TQt::AltButton )
1072 ret |= KKeyNative::modX(KKey::ALT);
1073 if( state & TQt::MetaButton )
1074 ret |= KKeyNative::modX(KKey::WIN);
1075 return ret;
1076 }
1077
1078// Qt propagates mouse events up the widget hierachy, which means events
1079// for the decoration window cannot be (easily) intercepted as X11 events
1080bool Client::eventFilter( TQObject* o, TQEvent* e )
1081 {
1082 if (o == shadowWidget)
1083 {
1084 if (e->type() == TQEvent::MouseButtonRelease)
1085 {
1086 int buttonMask, buttonPressed, x, y, x_root, y_root;
1087 unsigned int mask;
1088 TQMouseEvent *qe = (TQMouseEvent *)e;
1089 Window inner_window, parent_window, pointer_window, root_window;
1090 XButtonEvent xe;
1091
1092 removeShadow();
1093 switch (qe->button())
1094 {
1095 case TQt::MidButton:
1096 buttonMask = Button2Mask;
1097 buttonPressed = Button2;
1098 break;
1099 case TQt::RightButton:
1100 buttonMask = Button3Mask;
1101 buttonPressed = Button3;
1102 break;
1103 default:
1104 buttonMask = Button1Mask;
1105 buttonPressed = Button1;
1106 break;
1107 }
1108
1109 // find the window under the cursor that should receive the
1110 // simulated events
1111 root_window = tqt_xrootwin();
1112 XQueryPointer(tqt_xdisplay(), root_window, &root_window,
1113 &pointer_window, &x_root, &y_root, &x, &y, &mask);
1114
1115 if (pointer_window != None)
1116 {
1117 // Save the child window immediately under the window
1118 // decoration, if any. This is so that we can send an event to
1119 // the immediate descendant of a window's window decoration,
1120 // which causes KWin to refocus windows properly
1121 parent_window = pointer_window;
1122 XQueryPointer(tqt_xdisplay(), parent_window, &root_window,
1123 &pointer_window, &x_root, &y_root, &x, &y, &mask);
1124 inner_window = pointer_window;
1125
1126 while (pointer_window != None)
1127 {
1128 // Recursively query for the child window under the pointer,
1129 // using the returned child window as the parent window for
1130 // the subsequent query. When no child window is left, we've
1131 // found the child that will receive the simulated event
1132 parent_window = pointer_window;
1133 XQueryPointer(tqt_xdisplay(), parent_window, &root_window,
1134 &pointer_window, &x_root, &y_root, &x, &y, &mask);
1135 }
1136 pointer_window = parent_window;
1137 }
1138 else
1139 inner_window = None;
1140
1141 // simulate a mouse button press
1142 xe.type = ButtonPress;
1143 xe.display = tqt_xdisplay();
1144 xe.root = tqt_xrootwin();
1145 xe.subwindow = None;
1146 xe.time = CurrentTime;
1147 xe.x = x;
1148 xe.y = y;
1149 xe.x_root = x_root;
1150 xe.y_root = y_root;
1151 xe.state = 0;
1152 xe.button = buttonPressed;
1153 xe.same_screen = True;
1154 if (inner_window != None && inner_window != pointer_window)
1155 {
1156 xe.window = inner_window;
1157 XSendEvent(tqt_xdisplay(), inner_window, True, ButtonPressMask,
1158 (XEvent *)&xe);
1159 }
1160 xe.window = pointer_window;
1161 XSendEvent(tqt_xdisplay(), pointer_window, True, ButtonPressMask,
1162 (XEvent *)&xe);
1163
1164 // simulate a mouse button release
1165 xe.type = ButtonRelease;
1166 xe.display = tqt_xdisplay();
1167 xe.root = tqt_xrootwin();
1168 xe.subwindow = None;
1169 xe.time = CurrentTime;
1170 xe.x = x;
1171 xe.y = y;
1172 xe.x_root = x_root;
1173 xe.y_root = y_root;
1174 xe.state = buttonMask;
1175 xe.button = buttonPressed;
1176 xe.same_screen = True;
1177 if (inner_window != None && inner_window != pointer_window)
1178 {
1179 xe.window = inner_window;
1180 XSendEvent(tqt_xdisplay(), inner_window, True, ButtonReleaseMask,
1181 (XEvent *)&xe);
1182 }
1183 xe.window = pointer_window;
1184 XSendEvent(tqt_xdisplay(), pointer_window, True, ButtonReleaseMask,
1185 (XEvent *)&xe);
1186
1187 drawDelayedShadow();
1188
1189 return true;
1190 }
1191 else if (e->type() == TQEvent::Wheel)
1192 {
1193 int x, y, x_root, y_root;
1194 unsigned int buttonMask, buttonPressed, mask;
1195 TQWheelEvent *wheelEvent = (TQWheelEvent *)e;
1196 Window inner_window, parent_window, pointer_window,
1197 root_window;
1198 XButtonEvent xe;
1199
1200 removeShadow();
1201
1202 // state and button parameters passed to XSendEvent depend on the
1203 // direction in which the mouse wheel was rolled
1204 buttonMask = wheelEvent->delta() > 0 ? Button4Mask : Button5Mask;
1205 buttonPressed = wheelEvent->delta() > 0 ? Button4 : Button5;
1206
1207 // find the window under the cursor that should receive the
1208 // simulated events
1209 root_window = tqt_xrootwin();
1210 XQueryPointer(tqt_xdisplay(), root_window, &root_window,
1211 &pointer_window, &x_root, &y_root, &x, &y, &mask);
1212
1213 if (pointer_window != None)
1214 {
1215 // Save the child window immediately under the window
1216 // decoration, if any. This is so that we can send an event to
1217 // the immediate descendant of a window's window decoration,
1218 // which causes KWin to refocus windows properly
1219 parent_window = pointer_window;
1220 XQueryPointer(tqt_xdisplay(), parent_window, &root_window,
1221 &pointer_window, &x_root, &y_root, &x, &y, &mask);
1222 inner_window = pointer_window;
1223
1224 while (pointer_window != None)
1225 {
1226 // Recursively query for the child window under the pointer,
1227 // using the returned child window as the parent window for
1228 // the subsequent query. When no child window is left, we've
1229 // found the child that will receive the simulated event
1230 parent_window = pointer_window;
1231 XQueryPointer(tqt_xdisplay(), parent_window, &root_window,
1232 &pointer_window, &x_root, &y_root, &x, &y, &mask);
1233 }
1234 pointer_window = parent_window;
1235 }
1236 else
1237 inner_window = None;
1238
1239 // simulate a mouse button press
1240 xe.type = ButtonPress;
1241 xe.display = tqt_xdisplay();
1242 xe.root = tqt_xrootwin();
1243 xe.subwindow = None;
1244 xe.time = CurrentTime;
1245 xe.x = x;
1246 xe.y = y;
1247 xe.x_root = x_root;
1248 xe.y_root = y_root;
1249 xe.state = 0;
1250 xe.same_screen = True;
1251 if (inner_window != None && inner_window != pointer_window)
1252 {
1253 xe.button = buttonPressed;
1254 xe.window = inner_window;
1255 XSendEvent(tqt_xdisplay(), inner_window, True, ButtonPressMask,
1256 (XEvent *)&xe);
1257 }
1258 xe.button = buttonPressed;
1259 xe.window = pointer_window;
1260 XSendEvent(tqt_xdisplay(), pointer_window, True, ButtonPressMask,
1261 (XEvent *)&xe);
1262
1263 // simulate a mouse button release
1264 xe.type = ButtonRelease;
1265 xe.display = tqt_xdisplay();
1266 xe.root = tqt_xrootwin();
1267 xe.subwindow = None;
1268 xe.time = CurrentTime;
1269 xe.x = x;
1270 xe.y = y;
1271 xe.x_root = x_root;
1272 xe.y_root = y_root;
1273 xe.same_screen = True;
1274 if (inner_window != None && inner_window != pointer_window)
1275 {
1276 xe.window = inner_window;
1277 xe.state = buttonMask;
1278 xe.button = buttonPressed;
1279 XSendEvent(tqt_xdisplay(), inner_window, True, ButtonReleaseMask,
1280 (XEvent *)&xe);
1281 }
1282 xe.state = buttonMask;
1283 xe.button = buttonPressed;
1284 xe.window = pointer_window;
1285 XSendEvent(tqt_xdisplay(), pointer_window, True, ButtonReleaseMask,
1286 (XEvent *)&xe);
1287
1288 drawDelayedShadow();
1289
1290 return true;
1291 }
1292 }
1293 if( decoration == NULL
1294 || o != decoration->widget())
1295 return false;
1296 if( e->type() == TQEvent::MouseButtonPress )
1297 {
1298 TQMouseEvent* ev = TQT_TQMOUSEEVENT( e );
1299 return buttonPressEvent( decorationId(), qtToX11Button( ev->button()), qtToX11State( ev->state()),
1300 ev->x(), ev->y(), ev->globalX(), ev->globalY() );
1301 }
1302 if( e->type() == TQEvent::MouseButtonRelease )
1303 {
1304 TQMouseEvent* ev = TQT_TQMOUSEEVENT( e );
1305 return buttonReleaseEvent( decorationId(), qtToX11Button( ev->button()), qtToX11State( ev->state()),
1306 ev->x(), ev->y(), ev->globalX(), ev->globalY() );
1307 }
1308 if( e->type() == TQEvent::MouseMove ) // FRAME i fake z enter/leave?
1309 {
1310 TQMouseEvent* ev = TQT_TQMOUSEEVENT( e );
1311 return motionNotifyEvent( decorationId(), qtToX11State( ev->state()),
1312 ev->x(), ev->y(), ev->globalX(), ev->globalY() );
1313 }
1314 if( e->type() == TQEvent::Wheel )
1315 {
1316 TQWheelEvent* ev = TQT_TQWHEELEVENT( e );
1317 bool r = buttonPressEvent( decorationId(), ev->delta() > 0 ? Button4 : Button5, qtToX11State( ev->state()),
1318 ev->x(), ev->y(), ev->globalX(), ev->globalY() );
1319 r = r || buttonReleaseEvent( decorationId(), ev->delta() > 0 ? Button4 : Button5, qtToX11State( ev->state()),
1320 ev->x(), ev->y(), ev->globalX(), ev->globalY() );
1321 return r;
1322 }
1323 if( e->type() == TQEvent::Resize )
1324 {
1325 TQResizeEvent* ev = TQT_TQRESIZEEVENT( e );
1326 // Filter out resize events that inform about size different than frame size.
1327 // This will ensure that decoration->width() etc. and decoration->widget()->width() will be in sync.
1328 // These events only seem to be delayed events from initial resizing before show() was called
1329 // on the decoration widget.
1330 if( ev->size() != size())
1331 return true;
1332 }
1333 return false;
1334 }
1335
1336// return value matters only when filtering events before decoration gets them
1337bool Client::buttonPressEvent( Window w, int button, int state, int x, int y, int x_root, int y_root )
1338 {
1339 if (buttonDown)
1340 {
1341 if( w == wrapperId())
1342 XAllowEvents(tqt_xdisplay(), SyncPointer, CurrentTime ); //tqt_x_time);
1343 return true;
1344 }
1345
1346 if( w == wrapperId() || w == frameId() || w == decorationId())
1347 { // FRAME neco s tohohle by se melo zpracovat, nez to dostane dekorace
1348 // FRAME something out of this would be processed before it gets decorations
1349 updateUserTime();
1350 workspace()->setWasUserInteraction();
1351 uint keyModX = (options->keyCmdAllModKey() == TQt::Key_Meta) ?
1352 KKeyNative::modX(KKey::WIN) :
1353 KKeyNative::modX(KKey::ALT);
1354 bool bModKeyHeld = keyModX != 0 && ( state & KKeyNative::accelModMaskX()) == keyModX;
1355
1356 if( isSplash()
1357 && button == Button1 && !bModKeyHeld )
1358 { // hide splashwindow if the user clicks on it
1359 hideClient( true );
1360 if( w == wrapperId())
1361 XAllowEvents(tqt_xdisplay(), SyncPointer, CurrentTime ); //tqt_x_time);
1362 return true;
1363 }
1364
1365 Options::MouseCommand com = Options::MouseNothing;
1366 bool was_action = false;
1367 bool perform_handled = false;
1368 if ( bModKeyHeld )
1369 {
1370 was_action = true;
1371 switch (button)
1372 {
1373 case Button1:
1374 com = options->commandAll1();
1375 break;
1376 case Button2:
1377 com = options->commandAll2();
1378 break;
1379 case Button3:
1380 com = options->commandAll3();
1381 break;
1382 case Button4:
1383 case Button5:
1384 com = options->operationWindowMouseWheel( button == Button4 ? 120 : -120 );
1385 break;
1386 }
1387 }
1388 else
1389 { // inactive inner window
1390 if( !isActive() && w == wrapperId())
1391 {
1392 was_action = true;
1393 perform_handled = true;
1394 switch (button)
1395 {
1396 case Button1:
1397 com = options->commandWindow1();
1398 break;
1399 case Button2:
1400 com = options->commandWindow2();
1401 break;
1402 case Button3:
1403 com = options->commandWindow3();
1404 break;
1405 default:
1406 com = Options::MouseActivateAndPassClick;
1407 }
1408 }
1409 // active inner window
1410 if( isActive() && w == wrapperId()
1411 && options->clickRaise && button < 4 ) // exclude wheel
1412 {
1413 com = Options::MouseActivateRaiseAndPassClick;
1414 was_action = true;
1415 perform_handled = true;
1416 }
1417 }
1418 if( was_action )
1419 {
1420 bool replay = performMouseCommand( com, TQPoint( x_root, y_root), perform_handled );
1421
1422 if ( isSpecialWindow())
1423 replay = TRUE;
1424
1425 if( w == wrapperId()) // these can come only from a grab
1426 XAllowEvents(tqt_xdisplay(), replay? ReplayPointer : SyncPointer, CurrentTime ); //tqt_x_time);
1427 return true;
1428 }
1429 }
1430
1431 if( w == wrapperId()) // these can come only from a grab
1432 {
1433 XAllowEvents(tqt_xdisplay(), ReplayPointer, CurrentTime ); //tqt_x_time);
1434 return true;
1435 }
1436 if( w == decorationId())
1437 return false; // don't eat decoration events
1438 if( w == frameId())
1439 processDecorationButtonPress( button, state, x, y, x_root, y_root );
1440 return true;
1441 }
1442
1443
1444// this function processes button press events only after decoration decides not to handle them,
1445// unlike buttonPressEvent(), which (when the window is decoration) filters events before decoration gets them
1446void Client::processDecorationButtonPress( int button, int /*state*/, int x, int y, int x_root, int y_root )
1447 {
1448 Options::MouseCommand com = Options::MouseNothing;
1449 bool active = isActive();
1450 if ( !wantsInput() ) // we cannot be active, use it anyway
1451 active = TRUE;
1452
1453 if ( button == Button1 )
1454 com = active ? options->commandActiveTitlebar1() : options->commandInactiveTitlebar1();
1455 else if ( button == Button2 )
1456 com = active ? options->commandActiveTitlebar2() : options->commandInactiveTitlebar2();
1457 else if ( button == Button3 )
1458 com = active ? options->commandActiveTitlebar3() : options->commandInactiveTitlebar3();
1459 if( button == Button1
1460 && com != Options::MouseOperationsMenu // actions where it's not possible to get the matching
1461 && com != Options::MouseMinimize ) // mouse release event
1462 {
1463 mode = mousePosition( TQPoint( x, y ));
1464 buttonDown = TRUE;
1465 moveOffset = TQPoint( x, y );
1466 invertedMoveOffset = rect().bottomRight() - moveOffset;
1467 unrestrictedMoveResize = false;
1468 setCursor( mode ); // update to sizeAllCursor if about to move
1469 }
1470 performMouseCommand( com, TQPoint( x_root, y_root ));
1471 }
1472
1473// called from decoration
1474void Client::processMousePressEvent( TQMouseEvent* e )
1475 {
1476 if( e->type() != TQEvent::MouseButtonPress )
1477 {
1478 kdWarning() << "processMousePressEvent()" << endl;
1479 return;
1480 }
1481 int button;
1482 switch( e->button())
1483 {
1484 case TQt::LeftButton:
1485 button = Button1;
1486 break;
1487 case TQt::MidButton:
1488 button = Button2;
1489 break;
1490 case TQt::RightButton:
1491 button = Button3;
1492 break;
1493 default:
1494 return;
1495 }
1496 processDecorationButtonPress( button, e->state(), e->x(), e->y(), e->globalX(), e->globalY());
1497 }
1498
1499// return value matters only when filtering events before decoration gets them
1500bool Client::buttonReleaseEvent( Window w, int /*button*/, int state, int x, int y, int x_root, int y_root )
1501 {
1502 if( w == decorationId() && !buttonDown)
1503 return false;
1504 if( w == wrapperId())
1505 {
1506 XAllowEvents(tqt_xdisplay(), SyncPointer, CurrentTime ); //tqt_x_time);
1507 return true;
1508 }
1509 if( w != frameId() && w != decorationId() && w != moveResizeGrabWindow())
1510 return true;
1511 x = this->x(); // translate from grab window to local coords
1512 y = this->y();
1513 if ( (state & ( Button1Mask & Button2Mask & Button3Mask )) == 0 )
1514 {
1515 buttonDown = FALSE;
1516 if ( moveResizeMode )
1517 {
1518 finishMoveResize( false );
1519 // mouse position is still relative to old Client position, adjust it
1520 TQPoint mousepos( x_root - x, y_root - y );
1521 mode = mousePosition( mousepos );
1522 }
1523 setCursor( mode );
1524 }
1525 return true;
1526 }
1527
1528static bool was_motion = false;
1529static Time next_motion_time = CurrentTime;
1530// Check whole incoming X queue for MotionNotify events
1531// checking whole queue is done by always returning False in the predicate.
1532// If there are more MotionNotify events in the queue, all until the last
1533// one may be safely discarded (if a ButtonRelease event comes, a MotionNotify
1534// will be faked from it, so there's no need to check other events).
1535// This helps avoiding being overloaded by being flooded from many events
1536// from the XServer.
1537static Bool motion_predicate( Display*, XEvent* ev, XPointer )
1538{
1539 if( ev->type == MotionNotify )
1540 {
1541 was_motion = true;
1542 next_motion_time = ev->xmotion.time; // for setting time
1543 }
1544 return False;
1545}
1546
1547static bool waitingMotionEvent()
1548 {
1549// The queue doesn't need to be checked until the X timestamp
1550// of processes events reaches the timestamp of the last suitable
1551// MotionNotify event in the queue.
1552 if( next_motion_time != CurrentTime
1553 && timestampCompare( GET_QT_X_TIME(), next_motion_time ) < 0 )
1554 return true;
1555 was_motion = false;
1556 XSync( tqt_xdisplay(), False ); // this helps to discard more MotionNotify events
1557 XEvent dummy;
1558 XCheckIfEvent( tqt_xdisplay(), &dummy, motion_predicate, NULL );
1559 return was_motion;
1560 }
1561
1562// return value matters only when filtering events before decoration gets them
1563bool Client::motionNotifyEvent( Window w, int /*state*/, int x, int y, int x_root, int y_root )
1564 {
1565 if( w != frameId() && w != decorationId() && w != moveResizeGrabWindow())
1566 return true; // care only about the whole frame
1567 if ( !buttonDown )
1568 {
1569 Position newmode = mousePosition( TQPoint( x, y ));
1570 if( newmode != mode )
1571 setCursor( newmode );
1572 mode = newmode;
1573 // reset the timestamp for the optimization, otherwise with long passivity
1574 // the option in waitingMotionEvent() may be always true
1575 next_motion_time = CurrentTime;
1576 return false;
1577 }
1578 if( w == moveResizeGrabWindow())
1579 {
1580 x = this->x(); // translate from grab window to local coords
1581 y = this->y();
1582 }
1583 if( !waitingMotionEvent())
1584 handleMoveResize( x, y, x_root, y_root );
1585 return true;
1586 }
1587
1588void Client::focusInEvent( XFocusInEvent* e )
1589 {
1590 if( e->window != window())
1591 return; // only window gets focus
1592 if ( e->mode == NotifyUngrab )
1593 return; // we don't care
1594 if ( e->detail == NotifyPointer )
1595 return; // we don't care
1596 if( !isShown( false ) || !isOnCurrentDesktop()) // we unmapped it, but it got focus meanwhile ->
1597 return; // activateNextClient() already transferred focus elsewhere
1598 // check if this client is in should_get_focus list or if activation is allowed
1599 bool activate = workspace()->allowClientActivation( this, -1U, true );
1600 workspace()->gotFocusIn( this ); // remove from should_get_focus list
1601 if( activate )
1602 setActive( TRUE );
1603 else
1604 {
1605 workspace()->restoreFocus();
1606 demandAttention();
1607 }
1608 }
1609
1610// When a client loses focus, FocusOut events are usually immediatelly
1611// followed by FocusIn events for another client that gains the focus
1612// (unless the focus goes to another screen, or to the nofocus widget).
1613// Without this check, the former focused client would have to be
1614// deactivated, and after that, the new one would be activated, with
1615// a short time when there would be no active client. This can cause
1616// flicker sometimes, e.g. when a fullscreen is shown, and focus is transferred
1617// from it to its transient, the fullscreen would be kept in the Active layer
1618// at the beginning and at the end, but not in the middle, when the active
1619// client would be temporarily none (see Client::belongToLayer() ).
1620// Therefore, the events queue is checked, whether it contains the matching
1621// FocusIn event, and if yes, deactivation of the previous client will
1622// be skipped, as activation of the new one will automatically deactivate
1623// previously active client.
1624static bool follows_focusin = false;
1625static bool follows_focusin_failed = false;
1626static Bool predicate_follows_focusin( Display*, XEvent* e, XPointer arg )
1627 {
1628 if( follows_focusin || follows_focusin_failed )
1629 return False;
1630 Client* c = ( Client* ) arg;
1631 if( e->type == FocusIn && c->workspace()->findClient( WindowMatchPredicate( e->xfocus.window )))
1632 { // found FocusIn
1633 follows_focusin = true;
1634 return False;
1635 }
1636 // events that may be in the queue before the FocusIn event that's being
1637 // searched for
1638 if( e->type == FocusIn || e->type == FocusOut || e->type == KeymapNotify )
1639 return False;
1640 follows_focusin_failed = true; // a different event - stop search
1641 return False;
1642 }
1643
1644static bool check_follows_focusin( Client* c )
1645 {
1646 follows_focusin = follows_focusin_failed = false;
1647 XEvent dummy;
1648 // XCheckIfEvent() is used to make the search non-blocking, the predicate
1649 // always returns False, so nothing is removed from the events queue.
1650 // XPeekIfEvent() would block.
1651 XCheckIfEvent( tqt_xdisplay(), &dummy, predicate_follows_focusin, (XPointer)c );
1652 return follows_focusin;
1653 }
1654
1655
1656void Client::focusOutEvent( XFocusOutEvent* e )
1657 {
1658 if( e->window != window())
1659 return; // only window gets focus
1660 if ( e->mode == NotifyGrab )
1661 return; // we don't care
1662 if ( isShade() )
1663 return; // here neither
1664 if ( e->detail != NotifyNonlinear
1665 && e->detail != NotifyNonlinearVirtual )
1666 // SELI check all this
1667 return; // hack for motif apps like netscape
1668 if ( TQApplication::activePopupWidget() )
1669 return;
1670 if( !check_follows_focusin( this ))
1671 setActive( FALSE );
1672 }
1673
1674// performs _NET_WM_MOVERESIZE
1675void Client::NETMoveResize( int x_root, int y_root, NET::Direction direction )
1676 {
1677 if( direction == NET::Move )
1678 performMouseCommand( Options::MouseMove, TQPoint( x_root, y_root ));
1679 else if( moveResizeMode && direction == NET::MoveResizeCancel )
1680 {
1681 finishMoveResize( true );
1682 buttonDown = FALSE;
1683 setCursor( mode );
1684 }
1685 else if( direction >= NET::TopLeft && direction <= NET::Left )
1686 {
1687 static const Position convert[] =
1688 {
1689 PositionTopLeft,
1690 PositionTop,
1691 PositionTopRight,
1692 PositionRight,
1693 PositionBottomRight,
1694 PositionBottom,
1695 PositionBottomLeft,
1696 PositionLeft
1697 };
1698 if(!isResizable() || isShade())
1699 return;
1700 if( moveResizeMode )
1701 finishMoveResize( false );
1702 buttonDown = TRUE;
1703 moveOffset = TQPoint( x_root - x(), y_root - y()); // map from global
1704 invertedMoveOffset = rect().bottomRight() - moveOffset;
1705 unrestrictedMoveResize = false;
1706 mode = convert[ direction ];
1707 setCursor( mode );
1708 if( !startMoveResize())
1709 {
1710 buttonDown = false;
1711 setCursor( mode );
1712 }
1713 }
1714 else if( direction == NET::KeyboardMove )
1715 { // ignore mouse coordinates given in the message, mouse position is used by the moving algorithm
1716 TQCursor::setPos( geometry().center() );
1717 performMouseCommand( Options::MouseUnrestrictedMove, geometry().center());
1718 }
1719 else if( direction == NET::KeyboardSize )
1720 { // ignore mouse coordinates given in the message, mouse position is used by the resizing algorithm
1721 TQCursor::setPos( geometry().bottomRight());
1722 performMouseCommand( Options::MouseUnrestrictedResize, geometry().bottomRight());
1723 }
1724 }
1725
1726void Client::keyPressEvent( uint key_code )
1727 {
1728 updateUserTime();
1729 if ( !isMove() && !isResize() )
1730 return;
1731 bool is_control = key_code & TQt::CTRL;
1732 bool is_alt = key_code & TQt::ALT;
1733 key_code = key_code & 0xffff;
1734 int delta = is_control?1:is_alt?32:8;
1735 TQPoint pos = TQCursor::pos();
1736 switch ( key_code )
1737 {
1738 case Key_Left:
1739 pos.rx() -= delta;
1740 break;
1741 case Key_Right:
1742 pos.rx() += delta;
1743 break;
1744 case Key_Up:
1745 pos.ry() -= delta;
1746 break;
1747 case Key_Down:
1748 pos.ry() += delta;
1749 break;
1750 case Key_Space:
1751 case Key_Return:
1752 case Key_Enter:
1753 finishMoveResize( false );
1754 buttonDown = FALSE;
1755 setCursor( mode );
1756 break;
1757 case Key_Escape:
1758 finishMoveResize( true );
1759 buttonDown = FALSE;
1760 setCursor( mode );
1761 break;
1762 default:
1763 return;
1764 }
1765 TQCursor::setPos( pos );
1766 }
1767
1768// ****************************************
1769// Group
1770// ****************************************
1771
1772bool Group::groupEvent( XEvent* e )
1773 {
1774 unsigned long dirty[ 2 ];
1775 leader_info->event( e, dirty, 2 ); // pass through the NET stuff
1776 if ( ( dirty[ WinInfo::PROTOCOLS ] & NET::WMIcon) != 0 )
1777 getIcons();
1778 if(( dirty[ WinInfo::PROTOCOLS2 ] & NET::WM2StartupId ) != 0 )
1779 startupIdChanged();
1780 return false;
1781 }
1782
1783
1784} // namespace

twin

Skip menu "twin"
  • Main Page
  • Alphabetical List
  • Class List
  • File List
  • Class Members

twin

Skip menu "twin"
  • kate
  • libkonq
  • twin
  •   lib
Generated for twin by doxygen 1.9.4
This website is maintained by Timothy Pearson.