• 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_tqt_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_tqt_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_tqt_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() || inhibitConfigureRequests)
789 {
790 // Send a synthetic configure notification to make sure the
791 // window contents get updated by the application
792 sendSyntheticConfigureNotify();
793 return; // we have better things to do right now
794 }
795
796 if( fullscreen_mode == FullScreenNormal ) // refuse resizing of fullscreen windows
797 { // but allow resizing fullscreen hacks in order to let them cancel fullscreen mode
798 sendSyntheticConfigureNotify();
799 return;
800 }
801 if( isSplash() // no manipulations with splashscreens either
802 || isTopMenu()) // topmenus neither
803 {
804 sendSyntheticConfigureNotify();
805 return;
806 }
807
808 if ( e->value_mask & CWBorderWidth )
809 {
810 // first, get rid of a window border
811 XWindowChanges wc;
812 unsigned int value_mask = 0;
813
814 wc.border_width = 0;
815 value_mask = CWBorderWidth;
816 XConfigureWindow( tqt_xdisplay(), window(), value_mask, & wc );
817 }
818
819 if( e->value_mask & ( CWX | CWY | CWHeight | CWWidth ))
820 configureRequest( e->value_mask, e->x, e->y, e->width, e->height, 0, false );
821
822 if ( e->value_mask & CWStackMode )
823 restackWindow( e->above, e->detail, NET::FromApplication, userTime(), false );
824
825 // TODO sending a synthetic configure notify always is fine, even in cases where
826 // the ICCCM doesn't require this - it can be thought of as 'the WM decided to move
827 // the window later'. The client should not cause that many configure request,
828 // so this should not have any significant impact. With user moving/resizing
829 // the it should be optimized though (see also Client::setGeometry()/plainResize()/move()).
830 sendSyntheticConfigureNotify();
831
832 // SELI TODO accept configure requests for isDesktop windows (because kdesktop
833 // may get XRANDR resize event before twin), but check it's still at the bottom?
834 }
835
836
840void Client::propertyNotifyEvent( XPropertyEvent* e )
841 {
842 if( e->window != window())
843 return; // ignore frame/wrapper
844 switch ( e->atom )
845 {
846 case XA_WM_NORMAL_HINTS:
847 getWmNormalHints();
848 break;
849 case XA_WM_NAME:
850 fetchName();
851 break;
852 case XA_WM_ICON_NAME:
853 fetchIconicName();
854 break;
855 case XA_WM_TRANSIENT_FOR:
856 readTransient();
857 break;
858 case XA_WM_HINTS:
859 getWMHints();
860 getIcons(); // because KWin::icon() uses WMHints as fallback
861 break;
862 default:
863 if ( e->atom == atoms->wm_protocols )
864 getWindowProtocols();
865 else if (e->atom == atoms->wm_client_leader )
866 getWmClientLeader();
867 else if( e->atom == tqt_window_role )
868 window_role = staticWindowRole( window());
869 else if( e->atom == atoms->motif_wm_hints )
870 getMotifHints();
871 break;
872 }
873 }
874
875
876void Client::enterNotifyEvent( XCrossingEvent* e )
877 {
878 if( e->window != frameId())
879 return; // care only about entering the whole frame
880 if( e->mode == NotifyNormal ||
881 ( !options->focusPolicyIsReasonable() &&
882 e->mode == NotifyUngrab ) )
883 {
884
885 if (options->shadeHover && isShade())
886 {
887 delete shadeHoverTimer;
888 shadeHoverTimer = new TQTimer( this );
889 connect( shadeHoverTimer, TQ_SIGNAL( timeout() ), this, TQ_SLOT( shadeHover() ));
890 shadeHoverTimer->start( options->shadeHoverInterval, TRUE );
891 }
892
893 if ( options->focusPolicy == Options::ClickToFocus )
894 return;
895
896 if ( options->autoRaise && !isDesktop() &&
897 !isDock() && !isTopMenu() && workspace()->focusChangeEnabled() &&
898 workspace()->topClientOnDesktop( workspace()->currentDesktop()) != this )
899 {
900 delete autoRaiseTimer;
901 autoRaiseTimer = new TQTimer( this );
902 connect( autoRaiseTimer, TQ_SIGNAL( timeout() ), this, TQ_SLOT( autoRaise() ) );
903 autoRaiseTimer->start( options->autoRaiseInterval, TRUE );
904 }
905
906 TQPoint currentPos( e->x_root, e->y_root );
907 if ( options->focusPolicy != Options::FocusStrictlyUnderMouse && ( isDesktop() || isDock() || isTopMenu() ) )
908 return;
909 // for FocusFollowsMouse, change focus only if the mouse has actually been moved, not if the focus
910 // change came because of window changes (e.g. closing a window) - #92290
911 if( options->focusPolicy != Options::FocusFollowsMouse
912 || currentPos != workspace()->focusMousePosition())
913 {
914 if ( options->delayFocus )
915 workspace()->requestDelayFocus( this );
916 else
917 workspace()->requestFocus( this );
918 }
919 return;
920 }
921 }
922
923void Client::leaveNotifyEvent( XCrossingEvent* e )
924 {
925 if( e->window != frameId())
926 return; // care only about leaving the whole frame
927 if ( e->mode == NotifyNormal )
928 {
929 if ( !buttonDown )
930 {
931 mode = PositionCenter;
932 setCursor( TQt::arrowCursor );
933 }
934 bool lostMouse = !rect().contains( TQPoint( e->x, e->y ) );
935 // 'lostMouse' wouldn't work with e.g. B2 or Keramik, which have non-rectangular decorations
936 // (i.e. the LeaveNotify event comes before leaving the rect and no LeaveNotify event
937 // comes after leaving the rect) - so lets check if the pointer is really outside the window
938
939 // TODO this still sucks if a window appears above this one - it should lose the mouse
940 // if this window is another client, but not if it's a popup ... maybe after KDE3.1 :(
941 // (repeat after me 'AARGHL!')
942 if ( !lostMouse && e->detail != NotifyInferior )
943 {
944 int d1, d2, d3, d4;
945 unsigned int d5;
946 Window w, child;
947 if( XQueryPointer( tqt_xdisplay(), frameId(), &w, &child, &d1, &d2, &d3, &d4, &d5 ) == False
948 || child == None )
949 lostMouse = true; // really lost the mouse
950 }
951 if ( lostMouse )
952 {
953 cancelAutoRaise();
954 workspace()->cancelDelayFocus();
955 cancelShadeHover();
956 if ( shade_mode == ShadeHover && !moveResizeMode && !buttonDown )
957 setShade( ShadeNormal );
958 }
959 if ( options->focusPolicy == Options::FocusStrictlyUnderMouse )
960 if ( isActive() && lostMouse )
961 workspace()->requestFocus( 0 ) ;
962 return;
963 }
964 }
965
966#define XCapL KKeyNative::modXLock()
967#define XNumL KKeyNative::modXNumLock()
968#define XScrL KKeyNative::modXScrollLock()
969void Client::grabButton( int modifier )
970 {
971 unsigned int mods[ 8 ] =
972 {
973 0, XCapL, XNumL, XNumL | XCapL,
974 XScrL, XScrL | XCapL,
975 XScrL | XNumL, XScrL | XNumL | XCapL
976 };
977 for( int i = 0;
978 i < 8;
979 ++i )
980 XGrabButton( tqt_xdisplay(), AnyButton,
981 modifier | mods[ i ],
982 wrapperId(), FALSE, ButtonPressMask,
983 GrabModeSync, GrabModeAsync, None, None );
984 }
985
986void Client::ungrabButton( int modifier )
987 {
988 unsigned int mods[ 8 ] =
989 {
990 0, XCapL, XNumL, XNumL | XCapL,
991 XScrL, XScrL | XCapL,
992 XScrL | XNumL, XScrL | XNumL | XCapL
993 };
994 for( int i = 0;
995 i < 8;
996 ++i )
997 XUngrabButton( tqt_xdisplay(), AnyButton,
998 modifier | mods[ i ], wrapperId());
999 }
1000#undef XCapL
1001#undef XNumL
1002#undef XScrL
1003
1004/*
1005 Releases the passive grab for some modifier combinations when a
1006 window becomes active. This helps broken X programs that
1007 missinterpret LeaveNotify events in grab mode to work properly
1008 (Motif, AWT, Tk, ...)
1009 */
1010void Client::updateMouseGrab()
1011 {
1012 if( workspace()->globalShortcutsDisabled())
1013 {
1014 XUngrabButton( tqt_xdisplay(), AnyButton, AnyModifier, wrapperId());
1015 // keep grab for the simple click without modifiers if needed (see below)
1016 bool not_obscured = workspace()->topClientOnDesktop( workspace()->currentDesktop(), true, false ) == this;
1017 if( !( !options->clickRaise || not_obscured ))
1018 grabButton( None );
1019 return;
1020 }
1021 if( isActive() && !workspace()->forcedGlobalMouseGrab()) // see Workspace::establishTabBoxGrab()
1022 {
1023 // first grab all modifier combinations
1024 XGrabButton(tqt_xdisplay(), AnyButton, AnyModifier, wrapperId(), FALSE,
1025 ButtonPressMask,
1026 GrabModeSync, GrabModeAsync,
1027 None, None );
1028 // remove the grab for no modifiers only if the window
1029 // is unobscured or if the user doesn't want click raise
1030 // (it is unobscured if it the topmost in the unconstrained stacking order, i.e. it is
1031 // the most recently raised window)
1032 bool not_obscured = workspace()->topClientOnDesktop( workspace()->currentDesktop(), true, false ) == this;
1033 if( !options->clickRaise || not_obscured )
1034 ungrabButton( None );
1035 else
1036 grabButton( None );
1037 ungrabButton( ShiftMask );
1038 ungrabButton( ControlMask );
1039 ungrabButton( ControlMask | ShiftMask );
1040 }
1041 else
1042 {
1043 XUngrabButton( tqt_xdisplay(), AnyButton, AnyModifier, wrapperId());
1044 // simply grab all modifier combinations
1045 XGrabButton(tqt_xdisplay(), AnyButton, AnyModifier, wrapperId(), FALSE,
1046 ButtonPressMask,
1047 GrabModeSync, GrabModeAsync,
1048 None, None );
1049 }
1050 }
1051
1052int qtToX11Button( TQt::ButtonState button )
1053 {
1054 if( button == TQt::LeftButton )
1055 return Button1;
1056 else if( button == TQt::MidButton )
1057 return Button2;
1058 else if( button == TQt::RightButton )
1059 return Button3;
1060 return AnyButton;
1061 }
1062
1063int qtToX11State( TQt::ButtonState state )
1064 {
1065 int ret = 0;
1066 if( state & TQt::LeftButton )
1067 ret |= Button1Mask;
1068 if( state & TQt::MidButton )
1069 ret |= Button2Mask;
1070 if( state & TQt::RightButton )
1071 ret |= Button3Mask;
1072 if( state & TQt::ShiftButton )
1073 ret |= ShiftMask;
1074 if( state & TQt::ControlButton )
1075 ret |= ControlMask;
1076 if( state & TQt::AltButton )
1077 ret |= KKeyNative::modX(KKey::ALT);
1078 if( state & TQt::MetaButton )
1079 ret |= KKeyNative::modX(KKey::WIN);
1080 return ret;
1081 }
1082
1083// Qt propagates mouse events up the widget hierachy, which means events
1084// for the decoration window cannot be (easily) intercepted as X11 events
1085bool Client::eventFilter( TQObject* o, TQEvent* e )
1086 {
1087 if (o == shadowWidget)
1088 {
1089 if (e->type() == TQEvent::MouseButtonRelease)
1090 {
1091 int buttonMask, buttonPressed, x, y, x_root, y_root;
1092 unsigned int mask;
1093 TQMouseEvent *qe = (TQMouseEvent *)e;
1094 Window inner_window, parent_window, pointer_window, root_window;
1095 XButtonEvent xe;
1096
1097 removeShadow();
1098 switch (qe->button())
1099 {
1100 case TQt::MidButton:
1101 buttonMask = Button2Mask;
1102 buttonPressed = Button2;
1103 break;
1104 case TQt::RightButton:
1105 buttonMask = Button3Mask;
1106 buttonPressed = Button3;
1107 break;
1108 default:
1109 buttonMask = Button1Mask;
1110 buttonPressed = Button1;
1111 break;
1112 }
1113
1114 // find the window under the cursor that should receive the
1115 // simulated events
1116 root_window = tqt_xrootwin();
1117 XQueryPointer(tqt_xdisplay(), root_window, &root_window,
1118 &pointer_window, &x_root, &y_root, &x, &y, &mask);
1119
1120 if (pointer_window != None)
1121 {
1122 // Save the child window immediately under the window
1123 // decoration, if any. This is so that we can send an event to
1124 // the immediate descendant of a window's window decoration,
1125 // which causes KWin to refocus windows properly
1126 parent_window = pointer_window;
1127 XQueryPointer(tqt_xdisplay(), parent_window, &root_window,
1128 &pointer_window, &x_root, &y_root, &x, &y, &mask);
1129 inner_window = pointer_window;
1130
1131 while (pointer_window != None)
1132 {
1133 // Recursively query for the child window under the pointer,
1134 // using the returned child window as the parent window for
1135 // the subsequent query. When no child window is left, we've
1136 // found the child that will receive the simulated event
1137 parent_window = pointer_window;
1138 XQueryPointer(tqt_xdisplay(), parent_window, &root_window,
1139 &pointer_window, &x_root, &y_root, &x, &y, &mask);
1140 }
1141 pointer_window = parent_window;
1142 }
1143 else
1144 inner_window = None;
1145
1146 // simulate a mouse button press
1147 xe.type = ButtonPress;
1148 xe.display = tqt_xdisplay();
1149 xe.root = tqt_xrootwin();
1150 xe.subwindow = None;
1151 xe.time = CurrentTime;
1152 xe.x = x;
1153 xe.y = y;
1154 xe.x_root = x_root;
1155 xe.y_root = y_root;
1156 xe.state = 0;
1157 xe.button = buttonPressed;
1158 xe.same_screen = True;
1159 if (inner_window != None && inner_window != pointer_window)
1160 {
1161 xe.window = inner_window;
1162 XSendEvent(tqt_xdisplay(), inner_window, True, ButtonPressMask,
1163 (XEvent *)&xe);
1164 }
1165 xe.window = pointer_window;
1166 XSendEvent(tqt_xdisplay(), pointer_window, True, ButtonPressMask,
1167 (XEvent *)&xe);
1168
1169 // simulate a mouse button release
1170 xe.type = ButtonRelease;
1171 xe.display = tqt_xdisplay();
1172 xe.root = tqt_xrootwin();
1173 xe.subwindow = None;
1174 xe.time = CurrentTime;
1175 xe.x = x;
1176 xe.y = y;
1177 xe.x_root = x_root;
1178 xe.y_root = y_root;
1179 xe.state = buttonMask;
1180 xe.button = buttonPressed;
1181 xe.same_screen = True;
1182 if (inner_window != None && inner_window != pointer_window)
1183 {
1184 xe.window = inner_window;
1185 XSendEvent(tqt_xdisplay(), inner_window, True, ButtonReleaseMask,
1186 (XEvent *)&xe);
1187 }
1188 xe.window = pointer_window;
1189 XSendEvent(tqt_xdisplay(), pointer_window, True, ButtonReleaseMask,
1190 (XEvent *)&xe);
1191
1192 drawDelayedShadow();
1193
1194 return true;
1195 }
1196 else if (e->type() == TQEvent::Wheel)
1197 {
1198 int x, y, x_root, y_root;
1199 unsigned int buttonMask, buttonPressed, mask;
1200 TQWheelEvent *wheelEvent = (TQWheelEvent *)e;
1201 Window inner_window, parent_window, pointer_window,
1202 root_window;
1203 XButtonEvent xe;
1204
1205 removeShadow();
1206
1207 // state and button parameters passed to XSendEvent depend on the
1208 // direction in which the mouse wheel was rolled
1209 buttonMask = wheelEvent->delta() > 0 ? Button4Mask : Button5Mask;
1210 buttonPressed = wheelEvent->delta() > 0 ? Button4 : Button5;
1211
1212 // find the window under the cursor that should receive the
1213 // simulated events
1214 root_window = tqt_xrootwin();
1215 XQueryPointer(tqt_xdisplay(), root_window, &root_window,
1216 &pointer_window, &x_root, &y_root, &x, &y, &mask);
1217
1218 if (pointer_window != None)
1219 {
1220 // Save the child window immediately under the window
1221 // decoration, if any. This is so that we can send an event to
1222 // the immediate descendant of a window's window decoration,
1223 // which causes KWin to refocus windows properly
1224 parent_window = pointer_window;
1225 XQueryPointer(tqt_xdisplay(), parent_window, &root_window,
1226 &pointer_window, &x_root, &y_root, &x, &y, &mask);
1227 inner_window = pointer_window;
1228
1229 while (pointer_window != None)
1230 {
1231 // Recursively query for the child window under the pointer,
1232 // using the returned child window as the parent window for
1233 // the subsequent query. When no child window is left, we've
1234 // found the child that will receive the simulated event
1235 parent_window = pointer_window;
1236 XQueryPointer(tqt_xdisplay(), parent_window, &root_window,
1237 &pointer_window, &x_root, &y_root, &x, &y, &mask);
1238 }
1239 pointer_window = parent_window;
1240 }
1241 else
1242 inner_window = None;
1243
1244 // simulate a mouse button press
1245 xe.type = ButtonPress;
1246 xe.display = tqt_xdisplay();
1247 xe.root = tqt_xrootwin();
1248 xe.subwindow = None;
1249 xe.time = CurrentTime;
1250 xe.x = x;
1251 xe.y = y;
1252 xe.x_root = x_root;
1253 xe.y_root = y_root;
1254 xe.state = 0;
1255 xe.same_screen = True;
1256 if (inner_window != None && inner_window != pointer_window)
1257 {
1258 xe.button = buttonPressed;
1259 xe.window = inner_window;
1260 XSendEvent(tqt_xdisplay(), inner_window, True, ButtonPressMask,
1261 (XEvent *)&xe);
1262 }
1263 xe.button = buttonPressed;
1264 xe.window = pointer_window;
1265 XSendEvent(tqt_xdisplay(), pointer_window, True, ButtonPressMask,
1266 (XEvent *)&xe);
1267
1268 // simulate a mouse button release
1269 xe.type = ButtonRelease;
1270 xe.display = tqt_xdisplay();
1271 xe.root = tqt_xrootwin();
1272 xe.subwindow = None;
1273 xe.time = CurrentTime;
1274 xe.x = x;
1275 xe.y = y;
1276 xe.x_root = x_root;
1277 xe.y_root = y_root;
1278 xe.same_screen = True;
1279 if (inner_window != None && inner_window != pointer_window)
1280 {
1281 xe.window = inner_window;
1282 xe.state = buttonMask;
1283 xe.button = buttonPressed;
1284 XSendEvent(tqt_xdisplay(), inner_window, True, ButtonReleaseMask,
1285 (XEvent *)&xe);
1286 }
1287 xe.state = buttonMask;
1288 xe.button = buttonPressed;
1289 xe.window = pointer_window;
1290 XSendEvent(tqt_xdisplay(), pointer_window, True, ButtonReleaseMask,
1291 (XEvent *)&xe);
1292
1293 drawDelayedShadow();
1294
1295 return true;
1296 }
1297 }
1298 if( decoration == NULL
1299 || o != decoration->widget())
1300 return false;
1301 if( e->type() == TQEvent::MouseButtonPress )
1302 {
1303 TQMouseEvent* ev = static_cast<TQMouseEvent*>( e );
1304 return buttonPressEvent( decorationId(), qtToX11Button( ev->button()), qtToX11State( ev->state()),
1305 ev->x(), ev->y(), ev->globalX(), ev->globalY() );
1306 }
1307 if( e->type() == TQEvent::MouseButtonRelease )
1308 {
1309 TQMouseEvent* ev = static_cast<TQMouseEvent*>( e );
1310 return buttonReleaseEvent( decorationId(), qtToX11Button( ev->button()), qtToX11State( ev->state()),
1311 ev->x(), ev->y(), ev->globalX(), ev->globalY() );
1312 }
1313 if( e->type() == TQEvent::MouseMove ) // FRAME i fake z enter/leave?
1314 {
1315 TQMouseEvent* ev = static_cast<TQMouseEvent*>( e );
1316 return motionNotifyEvent( decorationId(), qtToX11State( ev->state()),
1317 ev->x(), ev->y(), ev->globalX(), ev->globalY() );
1318 }
1319 if( e->type() == TQEvent::Wheel )
1320 {
1321 TQWheelEvent* ev = static_cast<TQWheelEvent*>( e );
1322 bool r = buttonPressEvent( decorationId(), ev->delta() > 0 ? Button4 : Button5, qtToX11State( ev->state()),
1323 ev->x(), ev->y(), ev->globalX(), ev->globalY() );
1324 r = r || buttonReleaseEvent( decorationId(), ev->delta() > 0 ? Button4 : Button5, qtToX11State( ev->state()),
1325 ev->x(), ev->y(), ev->globalX(), ev->globalY() );
1326 return r;
1327 }
1328 if( e->type() == TQEvent::Resize )
1329 {
1330 TQResizeEvent* ev = static_cast<TQResizeEvent*>( e );
1331 // Filter out resize events that inform about size different than frame size.
1332 // This will ensure that decoration->width() etc. and decoration->widget()->width() will be in sync.
1333 // These events only seem to be delayed events from initial resizing before show() was called
1334 // on the decoration widget.
1335 if( ev->size() != size())
1336 return true;
1337 }
1338 return false;
1339 }
1340
1341// return value matters only when filtering events before decoration gets them
1342bool Client::buttonPressEvent( Window w, int button, int state, int x, int y, int x_root, int y_root )
1343 {
1344 if (buttonDown)
1345 {
1346 if( w == wrapperId())
1347 XAllowEvents(tqt_xdisplay(), SyncPointer, CurrentTime ); //tqt_x_time);
1348 return true;
1349 }
1350
1351 if( w == wrapperId() || w == frameId() || w == decorationId())
1352 { // FRAME neco s tohohle by se melo zpracovat, nez to dostane dekorace
1353 // FRAME something out of this would be processed before it gets decorations
1354 updateUserTime();
1355 workspace()->setWasUserInteraction();
1356 uint keyModX = (options->keyCmdAllModKey() == TQt::Key_Meta) ?
1357 KKeyNative::modX(KKey::WIN) :
1358 KKeyNative::modX(KKey::ALT);
1359 bool bModKeyHeld = keyModX != 0 && ( state & KKeyNative::accelModMaskX()) == keyModX;
1360
1361 if( isSplash()
1362 && button == Button1 && !bModKeyHeld )
1363 { // hide splashwindow if the user clicks on it
1364 hideClient( true );
1365 if( w == wrapperId())
1366 XAllowEvents(tqt_xdisplay(), SyncPointer, CurrentTime ); //tqt_x_time);
1367 return true;
1368 }
1369
1370 Options::MouseCommand com = Options::MouseNothing;
1371 bool was_action = false;
1372 bool perform_handled = false;
1373 if ( bModKeyHeld )
1374 {
1375 was_action = true;
1376 switch (button)
1377 {
1378 case Button1:
1379 com = options->commandAll1();
1380 break;
1381 case Button2:
1382 com = options->commandAll2();
1383 break;
1384 case Button3:
1385 com = options->commandAll3();
1386 break;
1387 case Button4:
1388 case Button5:
1389 com = options->operationWindowMouseWheel( button == Button4 ? 120 : -120 );
1390 break;
1391 }
1392 }
1393 else
1394 { // inactive inner window
1395 if( !isActive() && w == wrapperId())
1396 {
1397 was_action = true;
1398 perform_handled = true;
1399 switch (button)
1400 {
1401 case Button1:
1402 com = options->commandWindow1();
1403 break;
1404 case Button2:
1405 com = options->commandWindow2();
1406 break;
1407 case Button3:
1408 com = options->commandWindow3();
1409 break;
1410 default:
1411 com = Options::MouseActivateAndPassClick;
1412 }
1413 }
1414 // active inner window
1415 if( isActive() && w == wrapperId()
1416 && options->clickRaise && button < 4 ) // exclude wheel
1417 {
1418 com = Options::MouseActivateRaiseAndPassClick;
1419 was_action = true;
1420 perform_handled = true;
1421 }
1422 }
1423 if( was_action )
1424 {
1425 bool replay = performMouseCommand( com, TQPoint( x_root, y_root), perform_handled );
1426
1427 if ( isSpecialWindow())
1428 replay = TRUE;
1429
1430 if( w == wrapperId()) // these can come only from a grab
1431 XAllowEvents(tqt_xdisplay(), replay? ReplayPointer : SyncPointer, CurrentTime ); //tqt_x_time);
1432 return true;
1433 }
1434 }
1435
1436 if( w == wrapperId()) // these can come only from a grab
1437 {
1438 XAllowEvents(tqt_xdisplay(), ReplayPointer, CurrentTime ); //tqt_x_time);
1439 return true;
1440 }
1441 if( w == decorationId())
1442 return false; // don't eat decoration events
1443 if( w == frameId())
1444 processDecorationButtonPress( button, state, x, y, x_root, y_root );
1445 return true;
1446 }
1447
1448
1449// this function processes button press events only after decoration decides not to handle them,
1450// unlike buttonPressEvent(), which (when the window is decoration) filters events before decoration gets them
1451void Client::processDecorationButtonPress( int button, int /*state*/, int x, int y, int x_root, int y_root )
1452 {
1453 Options::MouseCommand com = Options::MouseNothing;
1454 bool active = isActive();
1455 if ( !wantsInput() ) // we cannot be active, use it anyway
1456 active = TRUE;
1457
1458 if ( button == Button1 )
1459 com = active ? options->commandActiveTitlebar1() : options->commandInactiveTitlebar1();
1460 else if ( button == Button2 )
1461 com = active ? options->commandActiveTitlebar2() : options->commandInactiveTitlebar2();
1462 else if ( button == Button3 )
1463 com = active ? options->commandActiveTitlebar3() : options->commandInactiveTitlebar3();
1464 if( button == Button1
1465 && com != Options::MouseOperationsMenu // actions where it's not possible to get the matching
1466 && com != Options::MouseMinimize ) // mouse release event
1467 {
1468 mode = mousePosition( TQPoint( x, y ));
1469 buttonDown = TRUE;
1470 moveOffset = TQPoint( x, y );
1471 invertedMoveOffset = rect().bottomRight() - moveOffset;
1472 unrestrictedMoveResize = false;
1473 setCursor( mode ); // update to sizeAllCursor if about to move
1474 }
1475 performMouseCommand( com, TQPoint( x_root, y_root ));
1476 }
1477
1478// called from decoration
1479void Client::processMousePressEvent( TQMouseEvent* e )
1480 {
1481 if( e->type() != TQEvent::MouseButtonPress )
1482 {
1483 kdWarning() << "processMousePressEvent()" << endl;
1484 return;
1485 }
1486 int button;
1487 switch( e->button())
1488 {
1489 case TQt::LeftButton:
1490 button = Button1;
1491 break;
1492 case TQt::MidButton:
1493 button = Button2;
1494 break;
1495 case TQt::RightButton:
1496 button = Button3;
1497 break;
1498 default:
1499 return;
1500 }
1501 processDecorationButtonPress( button, e->state(), e->x(), e->y(), e->globalX(), e->globalY());
1502 }
1503
1504// return value matters only when filtering events before decoration gets them
1505bool Client::buttonReleaseEvent( Window w, int /*button*/, int state, int x, int y, int x_root, int y_root )
1506 {
1507 if( w == decorationId() && !buttonDown)
1508 return false;
1509 if( w == wrapperId())
1510 {
1511 XAllowEvents(tqt_xdisplay(), SyncPointer, CurrentTime ); //tqt_x_time);
1512 return true;
1513 }
1514 if( w != frameId() && w != decorationId() && w != moveResizeGrabWindow())
1515 return true;
1516 x = this->x(); // translate from grab window to local coords
1517 y = this->y();
1518 if ( (state & ( Button1Mask & Button2Mask & Button3Mask )) == 0 )
1519 {
1520 buttonDown = FALSE;
1521 if ( moveResizeMode )
1522 {
1523 finishMoveResize( false );
1524 // mouse position is still relative to old Client position, adjust it
1525 TQPoint mousepos( x_root - x, y_root - y );
1526 mode = mousePosition( mousepos );
1527 }
1528 setCursor( mode );
1529 }
1530 return true;
1531 }
1532
1533static bool was_motion = false;
1534static Time next_motion_time = CurrentTime;
1535// Check whole incoming X queue for MotionNotify events
1536// checking whole queue is done by always returning False in the predicate.
1537// If there are more MotionNotify events in the queue, all until the last
1538// one may be safely discarded (if a ButtonRelease event comes, a MotionNotify
1539// will be faked from it, so there's no need to check other events).
1540// This helps avoiding being overloaded by being flooded from many events
1541// from the XServer.
1542static Bool motion_predicate( Display*, XEvent* ev, XPointer )
1543{
1544 if( ev->type == MotionNotify )
1545 {
1546 was_motion = true;
1547 next_motion_time = ev->xmotion.time; // for setting time
1548 }
1549 return False;
1550}
1551
1552static bool waitingMotionEvent()
1553 {
1554// The queue doesn't need to be checked until the X timestamp
1555// of processes events reaches the timestamp of the last suitable
1556// MotionNotify event in the queue.
1557 if( next_motion_time != CurrentTime
1558 && timestampCompare( get_tqt_x_time(), next_motion_time ) < 0 )
1559 return true;
1560 was_motion = false;
1561 XSync( tqt_xdisplay(), False ); // this helps to discard more MotionNotify events
1562 XEvent dummy;
1563 XCheckIfEvent( tqt_xdisplay(), &dummy, motion_predicate, NULL );
1564 return was_motion;
1565 }
1566
1567// return value matters only when filtering events before decoration gets them
1568bool Client::motionNotifyEvent( Window w, int /*state*/, int x, int y, int x_root, int y_root )
1569 {
1570 if( w != frameId() && w != decorationId() && w != moveResizeGrabWindow())
1571 return true; // care only about the whole frame
1572 if ( !buttonDown )
1573 {
1574 Position newmode = mousePosition( TQPoint( x, y ));
1575 if( newmode != mode )
1576 setCursor( newmode );
1577 mode = newmode;
1578 // reset the timestamp for the optimization, otherwise with long passivity
1579 // the option in waitingMotionEvent() may be always true
1580 next_motion_time = CurrentTime;
1581 return false;
1582 }
1583 if( w == moveResizeGrabWindow())
1584 {
1585 x = this->x(); // translate from grab window to local coords
1586 y = this->y();
1587 }
1588 if( !waitingMotionEvent())
1589 handleMoveResize( x, y, x_root, y_root );
1590 return true;
1591 }
1592
1593void Client::focusInEvent( XFocusInEvent* e )
1594 {
1595 if( e->window != window())
1596 return; // only window gets focus
1597 if ( e->mode == NotifyUngrab )
1598 return; // we don't care
1599 if ( e->detail == NotifyPointer )
1600 return; // we don't care
1601 if( !isShown( false ) || !isOnCurrentDesktop()) // we unmapped it, but it got focus meanwhile ->
1602 return; // activateNextClient() already transferred focus elsewhere
1603 // check if this client is in should_get_focus list or if activation is allowed
1604 bool activate = workspace()->allowClientActivation( this, -1U, true );
1605 workspace()->gotFocusIn( this ); // remove from should_get_focus list
1606 if( activate )
1607 setActive( TRUE );
1608 else
1609 {
1610 workspace()->restoreFocus();
1611 demandAttention();
1612 }
1613 }
1614
1615// When a client loses focus, FocusOut events are usually immediatelly
1616// followed by FocusIn events for another client that gains the focus
1617// (unless the focus goes to another screen, or to the nofocus widget).
1618// Without this check, the former focused client would have to be
1619// deactivated, and after that, the new one would be activated, with
1620// a short time when there would be no active client. This can cause
1621// flicker sometimes, e.g. when a fullscreen is shown, and focus is transferred
1622// from it to its transient, the fullscreen would be kept in the Active layer
1623// at the beginning and at the end, but not in the middle, when the active
1624// client would be temporarily none (see Client::belongToLayer() ).
1625// Therefore, the events queue is checked, whether it contains the matching
1626// FocusIn event, and if yes, deactivation of the previous client will
1627// be skipped, as activation of the new one will automatically deactivate
1628// previously active client.
1629static bool follows_focusin = false;
1630static bool follows_focusin_failed = false;
1631static Bool predicate_follows_focusin( Display*, XEvent* e, XPointer arg )
1632 {
1633 if( follows_focusin || follows_focusin_failed )
1634 return False;
1635 Client* c = ( Client* ) arg;
1636 if( e->type == FocusIn && c->workspace()->findClient( WindowMatchPredicate( e->xfocus.window )))
1637 { // found FocusIn
1638 follows_focusin = true;
1639 return False;
1640 }
1641 // events that may be in the queue before the FocusIn event that's being
1642 // searched for
1643 if( e->type == FocusIn || e->type == FocusOut || e->type == KeymapNotify )
1644 return False;
1645 follows_focusin_failed = true; // a different event - stop search
1646 return False;
1647 }
1648
1649static bool check_follows_focusin( Client* c )
1650 {
1651 follows_focusin = follows_focusin_failed = false;
1652 XEvent dummy;
1653 // XCheckIfEvent() is used to make the search non-blocking, the predicate
1654 // always returns False, so nothing is removed from the events queue.
1655 // XPeekIfEvent() would block.
1656 XCheckIfEvent( tqt_xdisplay(), &dummy, predicate_follows_focusin, (XPointer)c );
1657 return follows_focusin;
1658 }
1659
1660
1661void Client::focusOutEvent( XFocusOutEvent* e )
1662 {
1663 if( e->window != window())
1664 return; // only window gets focus
1665 if ( e->mode == NotifyGrab )
1666 return; // we don't care
1667 if ( isShade() )
1668 return; // here neither
1669 if ( e->detail != NotifyNonlinear
1670 && e->detail != NotifyNonlinearVirtual )
1671 // SELI check all this
1672 return; // hack for motif apps like netscape
1673 if ( TQApplication::activePopupWidget() )
1674 return;
1675 if( !check_follows_focusin( this ))
1676 setActive( FALSE );
1677 }
1678
1679// performs _NET_WM_MOVERESIZE
1680void Client::NETMoveResize( int x_root, int y_root, NET::Direction direction )
1681 {
1682 if( direction == NET::Move )
1683 performMouseCommand( Options::MouseMove, TQPoint( x_root, y_root ));
1684 else if( moveResizeMode && direction == NET::MoveResizeCancel )
1685 {
1686 finishMoveResize( true );
1687 buttonDown = FALSE;
1688 setCursor( mode );
1689 }
1690 else if( direction >= NET::TopLeft && direction <= NET::Left )
1691 {
1692 static const Position convert[] =
1693 {
1694 PositionTopLeft,
1695 PositionTop,
1696 PositionTopRight,
1697 PositionRight,
1698 PositionBottomRight,
1699 PositionBottom,
1700 PositionBottomLeft,
1701 PositionLeft
1702 };
1703 if(!isResizable() || isShade())
1704 return;
1705 if( moveResizeMode )
1706 finishMoveResize( false );
1707 buttonDown = TRUE;
1708 moveOffset = TQPoint( x_root - x(), y_root - y()); // map from global
1709 invertedMoveOffset = rect().bottomRight() - moveOffset;
1710 unrestrictedMoveResize = false;
1711 mode = convert[ direction ];
1712 setCursor( mode );
1713 if( !startMoveResize())
1714 {
1715 buttonDown = false;
1716 setCursor( mode );
1717 }
1718 }
1719 else if( direction == NET::KeyboardMove )
1720 { // ignore mouse coordinates given in the message, mouse position is used by the moving algorithm
1721 TQCursor::setPos( geometry().center() );
1722 performMouseCommand( Options::MouseUnrestrictedMove, geometry().center());
1723 }
1724 else if( direction == NET::KeyboardSize )
1725 { // ignore mouse coordinates given in the message, mouse position is used by the resizing algorithm
1726 TQCursor::setPos( geometry().bottomRight());
1727 performMouseCommand( Options::MouseUnrestrictedResize, geometry().bottomRight());
1728 }
1729 }
1730
1731void Client::keyPressEvent( uint key_code )
1732 {
1733 updateUserTime();
1734 if ( !isMove() && !isResize() )
1735 return;
1736 bool is_control = key_code & TQt::CTRL;
1737 bool is_alt = key_code & TQt::ALT;
1738 key_code = key_code & 0xffff;
1739 int delta = is_control?1:is_alt?32:8;
1740 TQPoint pos = TQCursor::pos();
1741 switch ( key_code )
1742 {
1743 case Key_Left:
1744 pos.rx() -= delta;
1745 break;
1746 case Key_Right:
1747 pos.rx() += delta;
1748 break;
1749 case Key_Up:
1750 pos.ry() -= delta;
1751 break;
1752 case Key_Down:
1753 pos.ry() += delta;
1754 break;
1755 case Key_Space:
1756 case Key_Return:
1757 case Key_Enter:
1758 finishMoveResize( false );
1759 buttonDown = FALSE;
1760 setCursor( mode );
1761 break;
1762 case Key_Escape:
1763 finishMoveResize( true );
1764 buttonDown = FALSE;
1765 setCursor( mode );
1766 break;
1767 default:
1768 return;
1769 }
1770 TQCursor::setPos( pos );
1771 }
1772
1773// ****************************************
1774// Group
1775// ****************************************
1776
1777bool Group::groupEvent( XEvent* e )
1778 {
1779 unsigned long dirty[ 2 ];
1780 leader_info->event( e, dirty, 2 ); // pass through the NET stuff
1781 if ( ( dirty[ WinInfo::PROTOCOLS ] & NET::WMIcon) != 0 )
1782 getIcons();
1783 if(( dirty[ WinInfo::PROTOCOLS2 ] & NET::WM2StartupId ) != 0 )
1784 startupIdChanged();
1785 return false;
1786 }
1787
1788
1789} // 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.