KWin
Loading...
Searching...
No Matches
events.cpp
Go to the documentation of this file.
1/*
2 KWin - the KDE window manager
3 This file is part of the KDE project.
4
5 SPDX-FileCopyrightText: 1999, 2000 Matthias Ettrich <ettrich@kde.org>
6 SPDX-FileCopyrightText: 2003 Lubos Lunak <l.lunak@kde.org>
7
8 SPDX-License-Identifier: GPL-2.0-or-later
9*/
10
11/*
12
13 This file contains things relevant to handling incoming events.
14
15*/
16
17#include "atoms.h"
18#include "cursor.h"
20#include "focuschain.h"
21#include "group.h"
22#include "netinfo.h"
23#include "rules.h"
24#include "screenedge.h"
25#include "useractions.h"
26#include "utils/xcbutils.h"
27#include "wayland/surface.h"
29#include "wayland_server.h"
30#include "workspace.h"
31#include "x11window.h"
32
33#if KWIN_BUILD_TABBOX
34#include "tabbox/tabbox.h"
35#endif
36
37#include <KDecoration2/Decoration>
38
39#include <QApplication>
40#include <QDebug>
41#include <QHoverEvent>
42#include <QKeyEvent>
43#include <QMouseEvent>
44#include <QStyleHints>
45#include <QWheelEvent>
46
47#include <kkeyserver.h>
48
49#include <xcb/damage.h>
50#include <xcb/sync.h>
51#include <xcb/xcb_icccm.h>
52
53#include "compositor.h"
54#include "x11eventfilter.h"
55
56#ifndef XCB_GE_GENERIC
57#define XCB_GE_GENERIC 35
59{
60 uint8_t response_type;
61 uint8_t extension;
62 uint16_t sequence;
63 uint32_t length;
64 uint16_t event_type;
65 uint8_t pad0[22];
66 uint32_t full_sequence;
68#endif
69
70namespace KWin
71{
72
73// ****************************************
74// Workspace
75// ****************************************
76
77static xcb_window_t findEventWindow(xcb_generic_event_t *event)
78{
79 const uint8_t eventType = event->response_type & ~0x80;
80 switch (eventType) {
81 case XCB_KEY_PRESS:
82 case XCB_KEY_RELEASE:
83 return reinterpret_cast<xcb_key_press_event_t *>(event)->event;
84 case XCB_BUTTON_PRESS:
85 case XCB_BUTTON_RELEASE:
86 return reinterpret_cast<xcb_button_press_event_t *>(event)->event;
87 case XCB_MOTION_NOTIFY:
88 return reinterpret_cast<xcb_motion_notify_event_t *>(event)->event;
89 case XCB_ENTER_NOTIFY:
90 case XCB_LEAVE_NOTIFY:
91 return reinterpret_cast<xcb_enter_notify_event_t *>(event)->event;
92 case XCB_FOCUS_IN:
93 case XCB_FOCUS_OUT:
94 return reinterpret_cast<xcb_focus_in_event_t *>(event)->event;
95 case XCB_EXPOSE:
96 return reinterpret_cast<xcb_expose_event_t *>(event)->window;
97 case XCB_GRAPHICS_EXPOSURE:
98 return reinterpret_cast<xcb_graphics_exposure_event_t *>(event)->drawable;
99 case XCB_NO_EXPOSURE:
100 return reinterpret_cast<xcb_no_exposure_event_t *>(event)->drawable;
101 case XCB_VISIBILITY_NOTIFY:
102 return reinterpret_cast<xcb_visibility_notify_event_t *>(event)->window;
103 case XCB_CREATE_NOTIFY:
104 return reinterpret_cast<xcb_create_notify_event_t *>(event)->window;
105 case XCB_DESTROY_NOTIFY:
106 return reinterpret_cast<xcb_destroy_notify_event_t *>(event)->window;
107 case XCB_UNMAP_NOTIFY:
108 return reinterpret_cast<xcb_unmap_notify_event_t *>(event)->window;
109 case XCB_MAP_NOTIFY:
110 return reinterpret_cast<xcb_map_notify_event_t *>(event)->window;
111 case XCB_MAP_REQUEST:
112 return reinterpret_cast<xcb_map_request_event_t *>(event)->window;
113 case XCB_REPARENT_NOTIFY:
114 return reinterpret_cast<xcb_reparent_notify_event_t *>(event)->window;
115 case XCB_CONFIGURE_NOTIFY:
116 return reinterpret_cast<xcb_configure_notify_event_t *>(event)->window;
117 case XCB_CONFIGURE_REQUEST:
118 return reinterpret_cast<xcb_configure_request_event_t *>(event)->window;
119 case XCB_GRAVITY_NOTIFY:
120 return reinterpret_cast<xcb_gravity_notify_event_t *>(event)->window;
121 case XCB_RESIZE_REQUEST:
122 return reinterpret_cast<xcb_resize_request_event_t *>(event)->window;
123 case XCB_CIRCULATE_NOTIFY:
124 case XCB_CIRCULATE_REQUEST:
125 return reinterpret_cast<xcb_circulate_notify_event_t *>(event)->window;
126 case XCB_PROPERTY_NOTIFY:
127 return reinterpret_cast<xcb_property_notify_event_t *>(event)->window;
128 case XCB_COLORMAP_NOTIFY:
129 return reinterpret_cast<xcb_colormap_notify_event_t *>(event)->window;
130 case XCB_CLIENT_MESSAGE:
131 return reinterpret_cast<xcb_client_message_event_t *>(event)->window;
132 default:
133 // extension handling
134 if (eventType == Xcb::Extensions::self()->shapeNotifyEvent()) {
135 return reinterpret_cast<xcb_shape_notify_event_t *>(event)->affected_window;
136 }
137 if (eventType == Xcb::Extensions::self()->damageNotifyEvent()) {
138 return reinterpret_cast<xcb_damage_notify_event_t *>(event)->drawable;
139 }
140 return XCB_WINDOW_NONE;
141 }
142}
143
147bool Workspace::workspaceEvent(xcb_generic_event_t *e)
148{
149 const uint8_t eventType = e->response_type & ~0x80;
150
151 const xcb_window_t eventWindow = findEventWindow(e);
152 if (eventWindow != XCB_WINDOW_NONE) {
153 if (X11Window *window = findClient(Predicate::WindowMatch, eventWindow)) {
154 if (window->windowEvent(e)) {
155 return true;
156 }
157 } else if (X11Window *window = findClient(Predicate::WrapperIdMatch, eventWindow)) {
158 if (window->windowEvent(e)) {
159 return true;
160 }
161 } else if (X11Window *window = findClient(Predicate::FrameIdMatch, eventWindow)) {
162 if (window->windowEvent(e)) {
163 return true;
164 }
165 } else if (X11Window *window = findClient(Predicate::InputIdMatch, eventWindow)) {
166 if (window->windowEvent(e)) {
167 return true;
168 }
169 } else if (X11Window *window = findUnmanaged(eventWindow)) {
170 if (window->windowEvent(e)) {
171 return true;
172 }
173 }
174 }
175
176 switch (eventType) {
177 case XCB_CREATE_NOTIFY: {
178 const auto *event = reinterpret_cast<xcb_create_notify_event_t *>(e);
179 if (event->parent == kwinApp()->x11RootWindow() && !QWidget::find(event->window) && !event->override_redirect) {
180 // see comments for allowWindowActivation()
181 kwinApp()->updateXTime();
182 const xcb_timestamp_t t = xTime();
183 xcb_change_property(kwinApp()->x11Connection(), XCB_PROP_MODE_REPLACE, event->window, atoms->kde_net_wm_user_creation_time, XCB_ATOM_CARDINAL, 32, 1, &t);
184 }
185 break;
186 }
187 case XCB_UNMAP_NOTIFY: {
188 const auto *event = reinterpret_cast<xcb_unmap_notify_event_t *>(e);
189 return (event->event != event->window); // hide wm typical event from Qt
190 }
191 case XCB_REPARENT_NOTIFY: {
192 // do not confuse Qt with these events. After all, _we_ are the
193 // window manager who does the reparenting.
194 return true;
195 }
196 case XCB_MAP_REQUEST: {
197 kwinApp()->updateXTime();
198
199 const auto *event = reinterpret_cast<xcb_map_request_event_t *>(e);
200 if (X11Window *window = findClient(Predicate::WindowMatch, event->window)) {
201 // e->xmaprequest.window is different from e->xany.window
202 // TODO this shouldn't be necessary now
203 window->windowEvent(e);
204 m_focusChain->update(window, FocusChain::Update);
205 } else if (true /*|| e->xmaprequest.parent != root */) {
206 // NOTICE don't check for the parent being the root window, this breaks when some app unmaps
207 // a window, changes something and immediately maps it back, without giving KWin
208 // a chance to reparent it back to root
209 // since KWin can get MapRequest only for root window children and
210 // children of WindowWrapper (=clients), the check is AFAIK useless anyway
211 // NOTICE: The save-set support in X11Window::mapRequestEvent() actually requires that
212 // this code doesn't check the parent to be root.
213 if (!createX11Window(event->window, false)) {
214 xcb_map_window(kwinApp()->x11Connection(), event->window);
215 const uint32_t values[] = {XCB_STACK_MODE_ABOVE};
216 xcb_configure_window(kwinApp()->x11Connection(), event->window, XCB_CONFIG_WINDOW_STACK_MODE, values);
217 }
218 }
219 return true;
220 }
221 case XCB_MAP_NOTIFY: {
222 const auto *event = reinterpret_cast<xcb_map_notify_event_t *>(e);
223 if (event->override_redirect) {
224 X11Window *window = findUnmanaged(event->window);
225 if (window == nullptr) {
226 window = createUnmanaged(event->window);
227 }
228 if (window) {
229 // if hasScheduledRelease is true, it means a unamp and map sequence has occurred.
230 // since release is scheduled after map notify, this old Unmanaged will get released
231 // before KWIN has chance to remanage it again. so release it right now.
232 if (window->hasScheduledRelease()) {
233 window->releaseWindow();
234 window = createUnmanaged(event->window);
235 }
236 if (window) {
237 return window->windowEvent(e);
238 }
239 }
240 }
241 return (event->event != event->window); // hide wm typical event from Qt
242 }
243
244 case XCB_CONFIGURE_REQUEST: {
245 const auto *event = reinterpret_cast<xcb_configure_request_event_t *>(e);
246 if (event->parent == kwinApp()->x11RootWindow()) {
247 uint32_t values[5] = {0, 0, 0, 0, 0};
248 const uint32_t value_mask = event->value_mask
249 & (XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT | XCB_CONFIG_WINDOW_BORDER_WIDTH);
250 int i = 0;
251 if (value_mask & XCB_CONFIG_WINDOW_X) {
252 values[i++] = event->x;
253 }
254 if (value_mask & XCB_CONFIG_WINDOW_Y) {
255 values[i++] = event->y;
256 }
257 if (value_mask & XCB_CONFIG_WINDOW_WIDTH) {
258 values[i++] = event->width;
259 }
260 if (value_mask & XCB_CONFIG_WINDOW_HEIGHT) {
261 values[i++] = event->height;
262 }
263 if (value_mask & XCB_CONFIG_WINDOW_BORDER_WIDTH) {
264 values[i++] = event->border_width;
265 }
266 xcb_configure_window(kwinApp()->x11Connection(), event->window, value_mask, values);
267 return true;
268 }
269 break;
270 }
271 case XCB_CONFIGURE_NOTIFY: {
272 const auto configureNotifyEvent = reinterpret_cast<xcb_configure_notify_event_t *>(e);
273 if (configureNotifyEvent->override_redirect && configureNotifyEvent->event == kwinApp()->x11RootWindow()) {
274 updateXStackingOrder();
275 }
276 break;
277 }
278 case XCB_FOCUS_IN: {
279 const auto *event = reinterpret_cast<xcb_focus_in_event_t *>(e);
280 if (event->event == kwinApp()->x11RootWindow()
281 && (event->detail == XCB_NOTIFY_DETAIL_NONE || event->detail == XCB_NOTIFY_DETAIL_POINTER_ROOT || event->detail == XCB_NOTIFY_DETAIL_INFERIOR)) {
282 Xcb::CurrentInput currentInput;
283 kwinApp()->updateXTime(); // focusToNull() uses xTime(), which is old now (FocusIn has no timestamp)
284 // it seems we can "loose" focus reversions when the closing window hold a grab
285 // => catch the typical pattern (though we don't want the focus on the root anyway) #348935
286 const bool lostFocusPointerToRoot = currentInput->focus == kwinApp()->x11RootWindow() && event->detail == XCB_NOTIFY_DETAIL_INFERIOR;
287 if (!currentInput.isNull() && (currentInput->focus == XCB_WINDOW_NONE || currentInput->focus == XCB_INPUT_FOCUS_POINTER_ROOT || lostFocusPointerToRoot)) {
288 // kWarning( 1212 ) << "X focus set to None/PointerRoot, reseting focus" ;
290 if (window != nullptr) {
291 requestFocus(window, true);
292 } else if (activateNextWindow(nullptr)) {
293 ; // ok, activated
294 } else {
295 focusToNull();
296 }
297 }
298 }
299 }
300 // fall through
301 case XCB_FOCUS_OUT:
302 return true; // always eat these, they would tell Qt that KWin is the active app
303 default:
304 break;
305 }
306 return false;
307}
308
309// ****************************************
310// Client
311// ****************************************
312
316bool X11Window::windowEvent(xcb_generic_event_t *e)
317{
318 if (isUnmanaged()) {
319 NET::Properties dirtyProperties;
320 NET::Properties2 dirtyProperties2;
321 info->event(e, &dirtyProperties, &dirtyProperties2); // pass through the NET stuff
322 if (dirtyProperties2 & NET::WM2Opacity) {
324 setOpacity(info->opacityF());
325 }
326 }
327 if (dirtyProperties2 & NET::WM2OpaqueRegion) {
328 getWmOpaqueRegion();
329 }
330 if (dirtyProperties2.testFlag(NET::WM2WindowRole)) {
331 Q_EMIT windowRoleChanged();
332 }
333 if (dirtyProperties2.testFlag(NET::WM2WindowClass)) {
334 getResourceClass();
335 }
336 const uint8_t eventType = e->response_type & ~0x80;
337 switch (eventType) {
338 case XCB_DESTROY_NOTIFY:
340 break;
341 case XCB_UNMAP_NOTIFY: {
342 workspace()->updateFocusMousePosition(Cursors::self()->mouse()->pos()); // may cause leave event
343
344 // unmap notify might have been emitted due to a destroy notify
345 // but unmap notify gets emitted before the destroy notify, nevertheless at this
346 // point the window is already destroyed. This means any XCB request with the window
347 // will cause an error.
348 // To not run into these errors we try to wait for the destroy notify. For this we
349 // generate a round trip to the X server and wait a very short time span before
350 // handling the release.
351 kwinApp()->updateXTime();
352 // using 1 msec to not just move it at the end of the event loop but add an very short
353 // timespan to cover cases like unmap() followed by destroy(). The only other way to
354 // ensure that the window is not destroyed when we do the release handling is to grab
355 // the XServer which we do not want to do for an Unmanaged. The timespan of 1 msec is
356 // short enough to not cause problems in the close window animations.
357 // It's of course still possible that we miss the destroy in which case non-fatal
358 // X errors are reported to the event loop and logged by Qt.
359 m_releaseTimer.start(1);
360 break;
361 }
362 case XCB_CONFIGURE_NOTIFY:
363 configureNotifyEvent(reinterpret_cast<xcb_configure_notify_event_t *>(e));
364 break;
365 case XCB_PROPERTY_NOTIFY:
366 propertyNotifyEvent(reinterpret_cast<xcb_property_notify_event_t *>(e));
367 break;
368 case XCB_CLIENT_MESSAGE:
369 clientMessageEvent(reinterpret_cast<xcb_client_message_event_t *>(e));
370 break;
371 default: {
372 if (eventType == Xcb::Extensions::self()->shapeNotifyEvent()) {
373 detectShape();
374 Q_EMIT shapeChanged();
375 }
376 if (eventType == Xcb::Extensions::self()->damageNotifyEvent()) {
377 damageNotifyEvent();
378 }
379 break;
380 }
381 }
382 return false; // don't eat events, even our own unmanaged widgets are tracked
383 }
384
385 if (findEventWindow(e) == window()) { // avoid doing stuff on frame or wrapper
386 NET::Properties dirtyProperties;
387 NET::Properties2 dirtyProperties2;
388 info->event(e, &dirtyProperties, &dirtyProperties2); // pass through the NET stuff
389
390 if ((dirtyProperties & NET::WMName) != 0) {
391 fetchName();
392 }
393 if ((dirtyProperties & NET::WMIconName) != 0) {
394 fetchIconicName();
395 }
396 if ((dirtyProperties & NET::WMStrut) != 0
397 || (dirtyProperties2 & NET::WM2ExtendedStrut) != 0) {
399 }
400 if ((dirtyProperties & NET::WMIcon) != 0) {
401 getIcons();
402 }
403 // Note there's a difference between userTime() and info->userTime()
404 // info->userTime() is the value of the property, userTime() also includes
405 // updates of the time done by KWin (ButtonPress on windowrapper etc.).
406 if ((dirtyProperties2 & NET::WM2UserTime) != 0) {
408 updateUserTime(info->userTime());
409 }
410 if ((dirtyProperties2 & NET::WM2StartupId) != 0) {
411 startupIdChanged();
412 }
413 if (dirtyProperties2 & NET::WM2Opacity) {
415 setOpacity(info->opacityF());
416 } else {
417 // forward to the frame if there's possibly another compositing manager running
418 NETWinInfo i(kwinApp()->x11Connection(), frameId(), kwinApp()->x11RootWindow(), NET::Properties(), NET::Properties2());
419 i.setOpacity(info->opacity());
420 }
421 }
422 if (dirtyProperties2.testFlag(NET::WM2WindowRole)) {
423 Q_EMIT windowRoleChanged();
424 }
425 if (dirtyProperties2.testFlag(NET::WM2WindowClass)) {
426 getResourceClass();
427 }
428 if (dirtyProperties2.testFlag(NET::WM2BlockCompositing)) {
429 setBlockingCompositing(info->isBlockingCompositing());
430 }
431 if (dirtyProperties2.testFlag(NET::WM2GroupLeader)) {
432 checkGroup();
433 updateAllowedActions(); // Group affects isMinimizable()
434 }
435 if (dirtyProperties2.testFlag(NET::WM2Urgency)) {
436 updateUrgency();
437 }
438 if (dirtyProperties2 & NET::WM2OpaqueRegion) {
439 getWmOpaqueRegion();
440 }
441 if (dirtyProperties2 & NET::WM2DesktopFileName) {
442 setDesktopFileName(QString::fromUtf8(info->desktopFileName()));
443 }
444 if (dirtyProperties2 & NET::WM2GTKFrameExtents) {
445 setClientFrameExtents(info->gtkFrameExtents());
446 }
447 }
448
449 const uint8_t eventType = e->response_type & ~0x80;
450 switch (eventType) {
451 case XCB_UNMAP_NOTIFY:
452 unmapNotifyEvent(reinterpret_cast<xcb_unmap_notify_event_t *>(e));
453 break;
454 case XCB_DESTROY_NOTIFY:
455 destroyNotifyEvent(reinterpret_cast<xcb_destroy_notify_event_t *>(e));
456 break;
457 case XCB_MAP_REQUEST:
458 // this one may pass the event to workspace
459 return mapRequestEvent(reinterpret_cast<xcb_map_request_event_t *>(e));
460 case XCB_CONFIGURE_REQUEST:
461 configureRequestEvent(reinterpret_cast<xcb_configure_request_event_t *>(e));
462 break;
463 case XCB_PROPERTY_NOTIFY:
464 propertyNotifyEvent(reinterpret_cast<xcb_property_notify_event_t *>(e));
465 break;
466 case XCB_KEY_PRESS:
467 updateUserTime(reinterpret_cast<xcb_key_press_event_t *>(e)->time);
468 break;
469 case XCB_BUTTON_PRESS: {
470 const auto *event = reinterpret_cast<xcb_button_press_event_t *>(e);
471 updateUserTime(event->time);
472 buttonPressEvent(event->event, event->detail, event->state,
473 event->event_x, event->event_y, event->root_x, event->root_y, event->time);
474 break;
475 }
476 case XCB_KEY_RELEASE:
477 // don't update user time on releases
478 // e.g. if the user presses Alt+F2, the Alt release
479 // would appear as user input to the currently active window
480 break;
481 case XCB_BUTTON_RELEASE: {
482 const auto *event = reinterpret_cast<xcb_button_release_event_t *>(e);
483 // don't update user time on releases
484 // e.g. if the user presses Alt+F2, the Alt release
485 // would appear as user input to the currently active window
486 buttonReleaseEvent(event->event, event->detail, event->state,
487 event->event_x, event->event_y, event->root_x, event->root_y);
488 break;
489 }
490 case XCB_MOTION_NOTIFY: {
491 const auto *event = reinterpret_cast<xcb_motion_notify_event_t *>(e);
492
493 int x = Xcb::fromXNative(event->event_x);
494 int y = Xcb::fromXNative(event->event_y);
495 int root_x = Xcb::fromXNative(event->root_x);
496 int root_y = Xcb::fromXNative(event->root_y);
497
498 motionNotifyEvent(event->event, event->state,
499 x, y, root_x, root_y);
500 workspace()->updateFocusMousePosition(QPointF(root_x, root_y));
501 break;
502 }
503 case XCB_ENTER_NOTIFY: {
504 auto *event = reinterpret_cast<xcb_enter_notify_event_t *>(e);
505 enterNotifyEvent(event);
506 // MotionNotify is guaranteed to be generated only if the mouse
507 // move start and ends in the window; for cases when it only
508 // starts or only ends there, Enter/LeaveNotify are generated.
509 // Fake a MotionEvent in such cases to make handle of mouse
510 // events simpler (Qt does that too).
511 int x = Xcb::fromXNative(event->event_x);
512 int y = Xcb::fromXNative(event->event_y);
513 int root_x = Xcb::fromXNative(event->root_x);
514 int root_y = Xcb::fromXNative(event->root_y);
515
516 motionNotifyEvent(event->event, event->state,
517 x, y, root_x, root_y);
518 workspace()->updateFocusMousePosition(QPointF(root_x, root_y));
519 break;
520 }
521 case XCB_LEAVE_NOTIFY: {
522 auto *event = reinterpret_cast<xcb_leave_notify_event_t *>(e);
523
524 int x = Xcb::fromXNative(event->event_x);
525 int y = Xcb::fromXNative(event->event_y);
526 int root_x = Xcb::fromXNative(event->root_x);
527 int root_y = Xcb::fromXNative(event->root_y);
528 motionNotifyEvent(event->event, event->state,
529 x, y, root_x, root_y);
530 leaveNotifyEvent(event);
531 // not here, it'd break following enter notify handling
532 // workspace()->updateFocusMousePosition( QPoint( e->xcrossing.x_root, e->xcrossing.y_root ));
533 break;
534 }
535 case XCB_FOCUS_IN:
536 focusInEvent(reinterpret_cast<xcb_focus_in_event_t *>(e));
537 break;
538 case XCB_FOCUS_OUT:
539 focusOutEvent(reinterpret_cast<xcb_focus_out_event_t *>(e));
540 break;
541 case XCB_REPARENT_NOTIFY:
542 break;
543 case XCB_CLIENT_MESSAGE:
544 clientMessageEvent(reinterpret_cast<xcb_client_message_event_t *>(e));
545 break;
546 case XCB_EXPOSE: {
547 xcb_expose_event_t *event = reinterpret_cast<xcb_expose_event_t *>(e);
548 if (event->window == frameId() && !Compositor::self()->isActive()) {
549 // TODO: only repaint required areas
551 }
552 break;
553 }
554 default:
555 if (eventType == Xcb::Extensions::self()->shapeNotifyEvent() && reinterpret_cast<xcb_shape_notify_event_t *>(e)->affected_window == window()) {
556 detectShape(); // workaround for #19644
557 updateShape();
558 }
559 if (eventType == Xcb::Extensions::self()->damageNotifyEvent() && reinterpret_cast<xcb_damage_notify_event_t *>(e)->drawable == frameId()) {
560 damageNotifyEvent();
561 }
562 break;
563 }
564 return true; // eat all events
565}
566
570bool X11Window::mapRequestEvent(xcb_map_request_event_t *e)
571{
572 if (e->window != window()) {
573 // Special support for the save-set feature, which is a bit broken.
574 // If there's a window from one client embedded in another one,
575 // e.g. using XEMBED, and the embedder suddenly loses its X connection,
576 // save-set will reparent the embedded window to its closest ancestor
577 // that will remains. Unfortunately, with reparenting window managers,
578 // this is not the root window, but the frame (or in KWin's case,
579 // it's the wrapper for the client window). In this case,
580 // the wrapper will get ReparentNotify for a window it won't know,
581 // which will be ignored, and then it gets MapRequest, as save-set
582 // always maps. Returning true here means that Workspace::workspaceEvent()
583 // will handle this MapRequest and manage this window (i.e. act as if
584 // it was reparented to root window).
585 if (e->parent == wrapperId()) {
586 return false;
587 }
588 return true; // no messing with frame etc.
589 }
590 // also copied in clientMessage()
591 if (isMinimized()) {
592 setMinimized(false);
593 }
594 if (isShade()) {
596 }
597 if (!isOnCurrentDesktop()) {
598 if (allowWindowActivation()) {
599 workspace()->activateWindow(this);
600 } else {
602 }
603 }
604 return true;
605}
606
610void X11Window::unmapNotifyEvent(xcb_unmap_notify_event_t *e)
611{
612 if (e->window != window()) {
613 return;
614 }
615 if (e->event != wrapperId()) {
616 // most probably event from root window when initially reparenting
617 bool ignore = true;
618 if (e->event == kwinApp()->x11RootWindow() && (e->response_type & 0x80)) {
619 ignore = false; // XWithdrawWindow()
620 }
621 if (ignore) {
622 return;
623 }
624 }
625
626 // check whether this is result of an XReparentWindow - window then won't be parented by wrapper
627 // in this case do not release the window (causes reparent to root, removal from saveSet and what not)
628 // but just destroy the window
629 Xcb::Tree tree(m_client);
630 xcb_window_t daddy = tree.parent();
631 if (daddy == m_wrapper) {
632 releaseWindow(); // unmapped from a regular window state
633 } else {
634 destroyWindow(); // the window was moved to some other parent
635 }
636}
637
638void X11Window::destroyNotifyEvent(xcb_destroy_notify_event_t *e)
639{
640 if (e->window != window()) {
641 return;
642 }
644}
645
649void X11Window::clientMessageEvent(xcb_client_message_event_t *e)
650{
651 if (e->type == atoms->wl_surface_serial) {
652 m_surfaceSerial = (uint64_t(e->data.data32[1]) << 32) | e->data.data32[0];
653 if (auto w = waylandServer()) {
654 if (XwaylandSurfaceV1Interface *xwaylandSurface = w->xwaylandShell()->findSurface(m_surfaceSerial)) {
655 setSurface(xwaylandSurface->surface());
656 }
657 }
658 } else if (e->type == atoms->wl_surface_id) {
659 m_pendingSurfaceId = e->data.data32[0];
660 if (auto w = waylandServer()) {
661 if (auto s = SurfaceInterface::get(m_pendingSurfaceId, w->xWaylandConnection())) {
662 setSurface(s);
663 }
664 }
665 }
666
667 if (e->window != window()) {
668 return; // ignore frame/wrapper
669 }
670 // WM_STATE
671 if (e->type == atoms->wm_change_state) {
672 if (e->data.data32[0] == XCB_ICCCM_WM_STATE_ICONIC) {
673 setMinimized(true);
674 }
675 return;
676 }
677}
678
679void X11Window::configureNotifyEvent(xcb_configure_notify_event_t *e)
680{
681 if (effects) {
682 effects->checkInputWindowStacking(); // keep them on top
683 }
684 QRectF newgeom(Xcb::fromXNative(e->x), Xcb::fromXNative(e->y), Xcb::fromXNative(e->width), Xcb::fromXNative(e->height));
685 if (newgeom != m_frameGeometry) {
687
688 QRectF old = m_frameGeometry;
689 m_clientGeometry = newgeom;
690 m_frameGeometry = newgeom;
691 m_bufferGeometry = newgeom;
692 checkOutput();
693 Q_EMIT bufferGeometryChanged(old);
694 Q_EMIT clientGeometryChanged(old);
695 Q_EMIT frameGeometryChanged(old);
696 Q_EMIT shapeChanged();
697 }
698}
699
703void X11Window::configureRequestEvent(xcb_configure_request_event_t *e)
704{
705 if (e->window != window()) {
706 return; // ignore frame/wrapper
707 }
709 return; // we have better things to do right now
710 }
711
712 if (m_fullscreenMode == FullScreenNormal) { // refuse resizing of fullscreen windows
713 // but allow resizing fullscreen hacks in order to let them cancel fullscreen mode
714 sendSyntheticConfigureNotify();
715 return;
716 }
717 if (isSplash()) { // no manipulations with splashscreens either
718 sendSyntheticConfigureNotify();
719 return;
720 }
721
722 if (e->value_mask & XCB_CONFIG_WINDOW_BORDER_WIDTH) {
723 // first, get rid of a window border
724 m_client.setBorderWidth(0);
725 }
726
727 if (e->value_mask & (XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_HEIGHT | XCB_CONFIG_WINDOW_WIDTH)) {
728 configureRequest(e->value_mask, Xcb::fromXNative(e->x),
729 Xcb::fromXNative(e->y), Xcb::fromXNative(e->width), Xcb::fromXNative(e->height), 0, false);
730 }
731 if (e->value_mask & XCB_CONFIG_WINDOW_STACK_MODE) {
732 restackWindow(e->sibling, e->stack_mode, NET::FromApplication, userTime(), false);
733 }
734
735 // Sending a synthetic configure notify always is fine, even in cases where
736 // the ICCCM doesn't require this - it can be though of as 'the WM decided to move
737 // the window later'. The window should not cause that many configure request,
738 // so this should not have any significant impact. With user moving/resizing
739 // the it should be optimized though (see also X11Window::setGeometry()/resize()/move()).
740 sendSyntheticConfigureNotify();
741
742 // SELI TODO accept configure requests for isDesktop windows (because kdesktop
743 // may get XRANDR resize event before kwin), but check it's still at the bottom?
744}
745
749void X11Window::propertyNotifyEvent(xcb_property_notify_event_t *e)
750{
751 if (e->window != window()) {
752 return; // ignore frame/wrapper
753 }
754 switch (e->atom) {
755 case XCB_ATOM_WM_NORMAL_HINTS:
756 getWmNormalHints();
757 break;
758 case XCB_ATOM_WM_NAME:
759 fetchName();
760 break;
761 case XCB_ATOM_WM_ICON_NAME:
762 fetchIconicName();
763 break;
764 case XCB_ATOM_WM_TRANSIENT_FOR:
765 readTransient();
766 break;
767 case XCB_ATOM_WM_HINTS:
768 getIcons(); // because KWin::icon() uses WMHints as fallback
769 break;
770 default:
771 if (e->atom == atoms->motif_wm_hints) {
772 getMotifHints();
773 } else if (e->atom == atoms->net_wm_sync_request_counter) {
774 getSyncCounter();
775 } else if (e->atom == atoms->activities) {
777 } else if (e->atom == atoms->kde_color_sheme) {
779 } else if (e->atom == atoms->kde_screen_edge_show) {
780 updateShowOnScreenEdge();
781 } else if (e->atom == atoms->kde_net_wm_appmenu_service_name) {
783 } else if (e->atom == atoms->kde_net_wm_appmenu_object_path) {
785 } else if (e->atom == atoms->wm_client_leader) {
786 getWmClientLeader();
787 } else if (e->atom == atoms->kde_net_wm_shadow) {
788 updateShadow();
789 } else if (e->atom == atoms->kde_skip_close_animation) {
790 getSkipCloseAnimation();
791 }
792 break;
793 }
794}
795
796void X11Window::enterNotifyEvent(xcb_enter_notify_event_t *e)
797{
798 if (waylandServer()) {
799 return;
800 }
801 if (e->event != frameId()) {
802 return; // care only about entering the whole frame
803 }
804
806 if (e->mode == XCB_NOTIFY_MODE_NORMAL || (e->mode == XCB_NOTIFY_MODE_UNGRAB && mouseDrivenFocus)) {
807 pointerEnterEvent(QPoint(e->root_x, e->root_y));
808 return;
809 }
810}
811
812void X11Window::leaveNotifyEvent(xcb_leave_notify_event_t *e)
813{
814 if (waylandServer()) {
815 return;
816 }
817 if (e->event != frameId()) {
818 return; // care only about leaving the whole frame
819 }
820 if (e->mode == XCB_NOTIFY_MODE_NORMAL) {
823 updateCursor();
824 }
825 bool lostMouse = !exclusiveContains(rect(), QPointF(e->event_x, e->event_y));
826 // 'lostMouse' wouldn't work with e.g. B2 or Keramik, which have non-rectangular decorations
827 // (i.e. the LeaveNotify event comes before leaving the rect and no LeaveNotify event
828 // comes after leaving the rect) - so lets check if the pointer is really outside the window
829
830 // TODO this still sucks if a window appears above this one - it should lose the mouse
831 // if this window is another window, but not if it's a popup ... maybe after KDE3.1 :(
832 // (repeat after me 'AARGHL!')
833 if (!lostMouse && e->detail != XCB_NOTIFY_DETAIL_INFERIOR) {
834 Xcb::Pointer pointer(frameId());
835 if (!pointer || !pointer->same_screen || pointer->child == XCB_WINDOW_NONE) {
836 // really lost the mouse
837 lostMouse = true;
838 }
839 }
840 if (lostMouse) {
842 if (isDecorated()) {
843 // sending a move instead of a leave. With leave we need to send proper coords, with move it's handled internally
844 QHoverEvent leaveEvent(QEvent::HoverMove, QPointF(-1, -1), QPointF(-1, -1), Qt::NoModifier);
845 QCoreApplication::sendEvent(decoration(), &leaveEvent);
846 }
847 }
848 if (options->focusPolicy() == Options::FocusStrictlyUnderMouse && isActive() && lostMouse) {
849 workspace()->requestDelayFocus(nullptr);
850 }
851 return;
852 }
853}
854
855static uint16_t x11CommandAllModifier()
856{
857 switch (options->commandAllModifier()) {
858 case Qt::MetaModifier:
859 return KKeyServer::modXMeta();
860 case Qt::AltModifier:
861 return KKeyServer::modXAlt();
862 default:
863 return 0;
864 }
865}
866
867#define XCapL KKeyServer::modXLock()
868#define XNumL KKeyServer::modXNumLock()
869#define XScrL KKeyServer::modXScrollLock()
870void X11Window::establishCommandWindowGrab(uint8_t button)
871{
872 // Unfortunately there are a lot of possible modifier combinations that we need to take into
873 // account. We tackle that problem in a kind of smart way. First, we grab the button with all
874 // possible modifiers, then we ungrab the ones that are relevant only to commandAllx().
875
876 m_wrapper.grabButton(XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC, XCB_MOD_MASK_ANY, button);
877
878 uint16_t x11Modifier = x11CommandAllModifier();
879
880 unsigned int mods[8] = {
881 0, XCapL, XNumL, XNumL | XCapL,
882 XScrL, XScrL | XCapL,
883 XScrL | XNumL, XScrL | XNumL | XCapL};
884 for (int i = 0; i < 8; ++i) {
885 m_wrapper.ungrabButton(x11Modifier | mods[i], button);
886 }
887}
888
889void X11Window::establishCommandAllGrab(uint8_t button)
890{
891 uint16_t x11Modifier = x11CommandAllModifier();
892
893 unsigned int mods[8] = {
894 0, XCapL, XNumL, XNumL | XCapL,
895 XScrL, XScrL | XCapL,
896 XScrL | XNumL, XScrL | XNumL | XCapL};
897 for (int i = 0; i < 8; ++i) {
898 m_wrapper.grabButton(XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC, x11Modifier | mods[i], button);
899 }
900}
901#undef XCapL
902#undef XNumL
903#undef XScrL
904
906{
907 if (waylandServer()) {
908 return;
909 }
910
911 xcb_ungrab_button(kwinApp()->x11Connection(), XCB_BUTTON_INDEX_ANY, m_wrapper, XCB_MOD_MASK_ANY);
912
913#if KWIN_BUILD_TABBOX
914 if (workspace()->tabbox()->forcedGlobalMouseGrab()) { // see TabBox::establishTabBoxGrab()
915 m_wrapper.grabButton(XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC);
916 return;
917 }
918#endif
919
920 // When a passive grab is activated or deactivated, the X server will generate crossing
921 // events as if the pointer were suddenly to warp from its current position to some position
922 // in the grab window. Some /broken/ X11 clients do get confused by such EnterNotify and
923 // LeaveNotify events so we release the passive grab for the active window.
924 //
925 // The passive grab below is established so the window can be raised or activated when it
926 // is clicked.
929 establishCommandWindowGrab(XCB_BUTTON_INDEX_1);
930 }
932 establishCommandWindowGrab(XCB_BUTTON_INDEX_2);
933 }
935 establishCommandWindowGrab(XCB_BUTTON_INDEX_3);
936 }
938 establishCommandWindowGrab(XCB_BUTTON_INDEX_4);
939 establishCommandWindowGrab(XCB_BUTTON_INDEX_5);
940 }
941 }
942
943 // We want to grab <command modifier> + buttons no matter what state the window is in. The
944 // window will receive funky EnterNotify and LeaveNotify events, but there is nothing that
945 // we can do about it, unfortunately.
946
947 if (!workspace()->globalShortcutsDisabled()) {
949 establishCommandAllGrab(XCB_BUTTON_INDEX_1);
950 }
952 establishCommandAllGrab(XCB_BUTTON_INDEX_2);
953 }
955 establishCommandAllGrab(XCB_BUTTON_INDEX_3);
956 }
958 establishCommandAllGrab(XCB_BUTTON_INDEX_4);
959 establishCommandAllGrab(XCB_BUTTON_INDEX_5);
960 }
961 }
962}
963
964static bool modKeyDown(int state)
965{
966 const uint keyModX = (options->keyCmdAllModKey() == Qt::Key_Meta) ? KKeyServer::modXMeta() : KKeyServer::modXAlt();
967 return keyModX && (state & KKeyServer::accelModMaskX()) == keyModX;
968}
969
970// return value matters only when filtering events before decoration gets them
971bool X11Window::buttonPressEvent(xcb_window_t w, int button, int state, int x, int y, int x_root, int y_root, xcb_timestamp_t time)
972{
973 if (waylandServer()) {
974 return true;
975 }
977 if (w == wrapperId()) {
978 xcb_allow_events(kwinApp()->x11Connection(), XCB_ALLOW_SYNC_POINTER, XCB_TIME_CURRENT_TIME); // xTime());
979 }
980 return true;
981 }
982
983 if (w == wrapperId() || w == frameId() || w == inputId()) {
984 // FRAME neco s tohohle by se melo zpracovat, nez to dostane dekorace
985 updateUserTime(time);
986 const bool bModKeyHeld = modKeyDown(state);
987
988 if (isSplash()
989 && button == XCB_BUTTON_INDEX_1 && !bModKeyHeld) {
990 // hide splashwindow if the user clicks on it
991 setHidden(true);
992 if (w == wrapperId()) {
993 xcb_allow_events(kwinApp()->x11Connection(), XCB_ALLOW_SYNC_POINTER, XCB_TIME_CURRENT_TIME); // xTime());
994 }
995 return true;
996 }
997
999 bool was_action = false;
1000 if (bModKeyHeld) {
1001 was_action = true;
1002 switch (button) {
1003 case XCB_BUTTON_INDEX_1:
1004 com = options->commandAll1();
1005 break;
1006 case XCB_BUTTON_INDEX_2:
1007 com = options->commandAll2();
1008 break;
1009 case XCB_BUTTON_INDEX_3:
1010 com = options->commandAll3();
1011 break;
1012 case XCB_BUTTON_INDEX_4:
1013 case XCB_BUTTON_INDEX_5:
1014 com = options->operationWindowMouseWheel(button == XCB_BUTTON_INDEX_4 ? 120 : -120);
1015 break;
1016 }
1017 } else {
1018 if (w == wrapperId()) {
1019 if (button < 4) {
1020 com = getMouseCommand(x11ToQtMouseButton(button), &was_action);
1021 } else if (button < 6) {
1022 com = getWheelCommand(Qt::Vertical, &was_action);
1023 }
1024 }
1025 }
1026 if (was_action) {
1027 bool replay = performMouseCommand(com, QPoint(x_root, y_root));
1028
1029 if (isSpecialWindow()) {
1030 replay = true;
1031 }
1032
1033 if (w == wrapperId()) { // these can come only from a grab
1034 xcb_allow_events(kwinApp()->x11Connection(), replay ? XCB_ALLOW_REPLAY_POINTER : XCB_ALLOW_SYNC_POINTER, XCB_TIME_CURRENT_TIME); // xTime());
1035 }
1036 return true;
1037 }
1038 }
1039
1040 if (w == wrapperId()) { // these can come only from a grab
1041 xcb_allow_events(kwinApp()->x11Connection(), XCB_ALLOW_REPLAY_POINTER, XCB_TIME_CURRENT_TIME); // xTime());
1042 return true;
1043 }
1044 if (w == inputId()) {
1045 x = x_root - frameGeometry().x();
1046 y = y_root - frameGeometry().y();
1047 // New API processes core events FIRST and only passes unused ones to the decoration
1048 QMouseEvent ev(QMouseEvent::MouseButtonPress,
1049 QPoint(x, y),
1050 QPoint(x_root, y_root),
1051 x11ToQtMouseButton(button),
1052 x11ToQtMouseButtons(state) | x11ToQtMouseButton(button),
1053 Qt::KeyboardModifiers());
1054 return processDecorationButtonPress(&ev, true);
1055 }
1056 if (w == frameId() && isDecorated()) {
1057 if (button >= 4 && button <= 7) {
1058 const Qt::KeyboardModifiers modifiers = x11ToQtKeyboardModifiers(state);
1059 // Logic borrowed from qapplication_x11.cpp
1060 const int delta = 120 * ((button == 4 || button == 6) ? 1 : -1);
1061 const bool hor = (((button == 4 || button == 5) && (modifiers & Qt::AltModifier))
1062 || (button == 6 || button == 7));
1063
1064 const QPoint angle = hor ? QPoint(delta, 0) : QPoint(0, delta);
1065 QWheelEvent event(QPointF(x, y),
1066 QPointF(x_root, y_root),
1067 QPoint(),
1068 angle,
1069 x11ToQtMouseButtons(state),
1070 modifiers,
1071 Qt::NoScrollPhase,
1072 false);
1073 event.setAccepted(false);
1074 QCoreApplication::sendEvent(decoration(), &event);
1075 if (!event.isAccepted() && !hor) {
1077 performMouseCommand(options->operationTitlebarMouseWheel(delta), QPoint(x_root, y_root));
1078 }
1079 }
1080 } else {
1081 QMouseEvent event(QEvent::MouseButtonPress,
1082 QPointF(x, y),
1083 QPointF(x_root, y_root),
1084 x11ToQtMouseButton(button),
1085 x11ToQtMouseButtons(state) | x11ToQtMouseButton(button),
1087 event.setTimestamp(time);
1088 event.setAccepted(false);
1089 QCoreApplication::sendEvent(decoration(), &event);
1090 if (!event.isAccepted()) {
1092 }
1093 }
1094 return true;
1095 }
1096 return true;
1097}
1098
1099// return value matters only when filtering events before decoration gets them
1100bool X11Window::buttonReleaseEvent(xcb_window_t w, int button, int state, int x, int y, int x_root, int y_root)
1101{
1102 if (waylandServer()) {
1103 return true;
1104 }
1105 if (w == frameId() && isDecorated()) {
1106 // wheel handled on buttonPress
1107 if (button < 4 || button > 7) {
1108 QMouseEvent event(QEvent::MouseButtonRelease,
1109 QPointF(x, y),
1110 QPointF(x_root, y_root),
1111 x11ToQtMouseButton(button),
1112 x11ToQtMouseButtons(state) & ~x11ToQtMouseButton(button),
1114 event.setAccepted(false);
1115 QCoreApplication::sendEvent(decoration(), &event);
1116 if (event.isAccepted() || !titlebarPositionUnderMouse()) {
1117 invalidateDecorationDoubleClickTimer(); // click was for the deco and shall not init a doubleclick
1118 }
1119 }
1120 }
1121 if (w == wrapperId()) {
1122 xcb_allow_events(kwinApp()->x11Connection(), XCB_ALLOW_SYNC_POINTER, XCB_TIME_CURRENT_TIME); // xTime());
1123 return true;
1124 }
1125 if (w != frameId() && w != inputId() && w != moveResizeGrabWindow()) {
1126 return true;
1127 }
1128 if (w == frameId() && workspace()->userActionsMenu() && workspace()->userActionsMenu()->isShown()) {
1130 }
1131 x = this->x(); // translate from grab window to local coords
1132 y = this->y();
1133
1134 // Check whether other buttons are still left pressed
1135 int buttonMask = XCB_BUTTON_MASK_1 | XCB_BUTTON_MASK_2 | XCB_BUTTON_MASK_3;
1136 if (button == XCB_BUTTON_INDEX_1) {
1137 buttonMask &= ~XCB_BUTTON_MASK_1;
1138 } else if (button == XCB_BUTTON_INDEX_2) {
1139 buttonMask &= ~XCB_BUTTON_MASK_2;
1140 } else if (button == XCB_BUTTON_INDEX_3) {
1141 buttonMask &= ~XCB_BUTTON_MASK_3;
1142 }
1143
1144 if ((state & buttonMask) == 0) {
1146 }
1147 return true;
1148}
1149
1150// return value matters only when filtering events before decoration gets them
1151bool X11Window::motionNotifyEvent(xcb_window_t w, int state, int x, int y, int x_root, int y_root)
1152{
1153 if (waylandServer()) {
1154 return true;
1155 }
1156 if (w == frameId() && isDecorated() && !isMinimized()) {
1157 // TODO Mouse move event dependent on state
1158 QHoverEvent event(QEvent::HoverMove, QPointF(x, y), QPointF(x, y));
1159 QCoreApplication::instance()->sendEvent(decoration(), &event);
1160 }
1161 if (w != frameId() && w != inputId() && w != moveResizeGrabWindow()) {
1162 return true; // care only about the whole frame
1163 }
1165 if (w == inputId()) {
1166 int x = x_root - frameGeometry().x(); // + padding_left;
1167 int y = y_root - frameGeometry().y(); // + padding_top;
1168
1169 if (isDecorated()) {
1170 QHoverEvent event(QEvent::HoverMove, QPointF(x, y), QPointF(x, y));
1171 QCoreApplication::instance()->sendEvent(decoration(), &event);
1172 }
1173 }
1174 Gravity newGravity = modKeyDown(state) ? Gravity::None : mouseGravity();
1175 if (newGravity != interactiveMoveResizeGravity()) {
1177 updateCursor();
1178 }
1179 return false;
1180 }
1181 if (w == moveResizeGrabWindow()) {
1182 x = this->x(); // translate from grab window to local coords
1183 y = this->y();
1184 }
1185
1186 handleInteractiveMoveResize(QPoint(x, y), QPoint(x_root, y_root));
1187 if (isInteractiveMove()) {
1188 workspace()->screenEdges()->check(QPoint(x_root, y_root), QDateTime::fromMSecsSinceEpoch(xTime(), Qt::UTC));
1189 }
1190
1191 return true;
1192}
1193
1194void X11Window::focusInEvent(xcb_focus_in_event_t *e)
1195{
1196 if (e->event != window()) {
1197 return; // only window gets focus
1198 }
1199 if (e->mode == XCB_NOTIFY_MODE_UNGRAB) {
1200 return; // we don't care
1201 }
1202 if (e->detail == XCB_NOTIFY_DETAIL_POINTER) {
1203 return; // we don't care
1204 }
1205 if (isShade() || !isShown() || !isOnCurrentDesktop()) { // we unmapped it, but it got focus meanwhile ->
1206 return; // activateNextWindow() already transferred focus elsewhere
1207 }
1209 window->cancelFocusOutTimer();
1210 });
1211 // check if this window is in should_get_focus list or if activation is allowed
1212 bool activate = allowWindowActivation(-1U, true);
1213 workspace()->gotFocusIn(this); // remove from should_get_focus list
1214 if (activate) {
1215 setActive(true);
1216 } else {
1217 if (workspace()->restoreFocus()) {
1219 } else {
1220 qCWarning(KWIN_CORE, "Failed to restore focus. Activating 0x%x", window());
1221 setActive(true);
1222 }
1223 }
1224}
1225
1226void X11Window::focusOutEvent(xcb_focus_out_event_t *e)
1227{
1228 if (e->event != window()) {
1229 return; // only window gets focus
1230 }
1231 if (e->mode == XCB_NOTIFY_MODE_GRAB) {
1232 return; // we don't care
1233 }
1234 if (isShade()) {
1235 return; // here neither
1236 }
1237 if (e->detail != XCB_NOTIFY_DETAIL_NONLINEAR
1238 && e->detail != XCB_NOTIFY_DETAIL_NONLINEAR_VIRTUAL) {
1239 // SELI check all this
1240 return; // hack for motif apps like netscape
1241 }
1242 if (QApplication::activePopupWidget()) {
1243 return;
1244 }
1245
1246 // When a window loses focus, FocusOut events are usually immediatelly
1247 // followed by FocusIn events for another window that gains the focus
1248 // (unless the focus goes to another screen, or to the nofocus widget).
1249 // Without this check, the former focused window would have to be
1250 // deactivated, and after that, the new one would be activated, with
1251 // a short time when there would be no active window. This can cause
1252 // flicker sometimes, e.g. when a fullscreen is shown, and focus is transferred
1253 // from it to its transient, the fullscreen would be kept in the Active layer
1254 // at the beginning and at the end, but not in the middle, when the active
1255 // window would be temporarily none (see X11Window::belongToLayer() ).
1256 // Therefore the setActive(false) call is moved to the end of the current
1257 // event queue. If there is a matching FocusIn event in the current queue
1258 // this will be processed before the setActive(false) call and the activation
1259 // of the window which gained FocusIn will automatically deactivate the
1260 // previously active window.
1261 if (!m_focusOutTimer) {
1262 m_focusOutTimer = new QTimer(this);
1263 m_focusOutTimer->setSingleShot(true);
1264 m_focusOutTimer->setInterval(0);
1265 connect(m_focusOutTimer, &QTimer::timeout, this, [this]() {
1266 setActive(false);
1267 });
1268 }
1269 m_focusOutTimer->start();
1270}
1271
1272// performs _NET_WM_MOVERESIZE
1273void X11Window::NETMoveResize(qreal x_root, qreal y_root, NET::Direction direction, xcb_button_t button)
1274{
1275 if (direction == NET::Move) {
1276 // move cursor to the provided position to prevent the window jumping there on first movement
1277 // the expectation is that the cursor is already at the provided position,
1278 // thus it's more a safety measurement
1279 Cursors::self()->mouse()->setPos(QPointF(x_root, y_root));
1280 performMouseCommand(Options::MouseMove, QPointF(x_root, y_root));
1281 } else if (isInteractiveMoveResize() && direction == NET::MoveResizeCancel) {
1284 updateCursor();
1285 } else if (direction >= NET::TopLeft && direction <= NET::Left) {
1286 static const Gravity convert[] = {
1295 if (!isResizable() || isShade()) {
1296 return;
1297 }
1300 }
1302 setInteractiveMoveOffset(QPointF(x_root - x(), y_root - y())); // map from global
1305 setInteractiveMoveResizeGravity(convert[direction]);
1308 }
1309 updateCursor();
1310 } else if (direction == NET::KeyboardMove) {
1311 // ignore mouse coordinates given in the message, mouse position is used by the moving algorithm
1312 Cursors::self()->mouse()->setPos(frameGeometry().center());
1314 } else if (direction == NET::KeyboardSize) {
1315 // ignore mouse coordinates given in the message, mouse position is used by the resizing algorithm
1316 Cursors::self()->mouse()->setPos(frameGeometry().bottomRight());
1318 }
1319}
1320
1321void X11Window::keyPressEvent(uint key_code, xcb_timestamp_t time)
1322{
1323 updateUserTime(time);
1324 Window::keyPressEvent(key_code);
1325}
1326
1327} // namespace
Xcb::Atom kde_skip_close_animation
Definition atoms.h:60
Xcb::Atom wm_change_state
Definition atoms.h:29
Xcb::Atom motif_wm_hints
Definition atoms.h:35
Xcb::Atom kde_net_wm_appmenu_object_path
Definition atoms.h:70
Xcb::Atom wl_surface_id
Definition atoms.h:67
Xcb::Atom wm_client_leader
Definition atoms.h:30
Xcb::Atom kde_color_sheme
Definition atoms.h:59
Xcb::Atom wl_surface_serial
Definition atoms.h:68
Xcb::Atom kde_net_wm_shadow
Definition atoms.h:58
Xcb::Atom activities
Definition atoms.h:24
Xcb::Atom kde_net_wm_appmenu_service_name
Definition atoms.h:69
Xcb::Atom net_wm_sync_request_counter
Definition atoms.h:56
Xcb::Atom kde_net_wm_user_creation_time
Definition atoms.h:39
Xcb::Atom kde_screen_edge_show
Definition atoms.h:61
static bool compositing()
Static check to test whether the Compositor is available and active.
Definition compositor.h:78
static Compositor * self()
void setPos(const QPointF &pos)
Definition cursor.cpp:210
static Cursors * self()
Definition cursor.cpp:35
Cursor * mouse() const
Definition cursor.h:266
MouseWheelCommand commandAllWheel() const
Definition options.h:550
MouseCommand commandWindowWheel
Definition options.h:151
@ MouseUnrestrictedResize
Definition options.h:460
@ MouseUnrestrictedMove
Definition options.h:456
Qt::KeyboardModifier commandAllModifier() const
Definition options.h:558
MouseCommand commandAll2
Definition options.h:153
bool isClickRaise() const
Definition options.h:270
MouseCommand commandAll3
Definition options.h:154
MouseCommand commandWindow2
Definition options.h:149
@ MouseWheelNothing
Definition options.h:485
MouseCommand commandAll1
Definition options.h:152
MouseCommand operationWindowMouseWheel(int delta) const
Definition options.h:493
FocusPolicy focusPolicy
Definition options.h:77
uint keyCmdAllModKey
Definition options.h:155
MouseCommand operationTitlebarMouseWheel(int delta) const
Definition options.h:489
MouseCommand commandWindow3
Definition options.h:150
bool focusPolicyIsReasonable
Definition options.h:113
bool isNextFocusPrefersMouse() const
Definition options.h:248
@ FocusFollowsMouse
Definition options.h:224
@ FocusStrictlyUnderMouse
Definition options.h:240
MouseCommand commandWindow1
Definition options.h:148
void check(const QPoint &pos, const QDateTime &now, bool forceNoPushBack=false)
static SurfaceInterface * get(wl_resource *native)
Definition surface.cpp:819
void setOpacity(qreal opacity)
Definition window.cpp:196
QPointF interactiveMoveOffset() const
Definition window.h:1595
QPointF pos
Definition window.h:79
void triggerDecorationRepaint()
Definition window.cpp:2683
Gravity mouseGravity() const
Definition window.cpp:2587
void setMinimized(bool set)
Definition window.cpp:984
QRectF frameGeometry
Definition window.h:431
void setDesktopFileName(const QString &name)
Definition window.cpp:2949
void frameGeometryAboutToChange()
void invalidateDecorationDoubleClickTimer()
Definition window.cpp:2797
void setSurface(SurfaceInterface *surface)
Definition window.cpp:347
QRectF m_bufferGeometry
Definition window.h:1727
bool isInteractiveMoveResizePointerButtonDown() const
Definition window.h:1624
bool isInteractiveMove() const
Definition window.h:1107
void setShade(bool set)
Definition window.cpp:863
void setInteractiveMoveResizePointerButtonDown(bool down)
Definition window.h:1628
void keyPressEvent(uint key_code)
Definition window.cpp:2531
bool startInteractiveMoveResize()
Definition window.cpp:1185
void endInteractiveMoveResize()
Definition window.cpp:2614
bool isShade() const
Definition window.h:1034
bool isMostRecentlyRaised() const
Definition window.cpp:691
bool isShown() const
Definition window.cpp:4232
bool isInteractiveMoveResize() const
Definition window.h:1570
virtual void pointerEnterEvent(const QPointF &globalPos)
Definition window.cpp:2821
void demandAttention(bool set=true)
Definition window.cpp:708
std::shared_ptr< KDecoration2::Decoration > decoration
Definition window.h:1820
QRectF m_frameGeometry
Definition window.h:1725
void setInteractiveMoveResizeGravity(Gravity gravity)
Definition window.h:1620
void setActive(bool)
Definition window.cpp:499
void handleInteractiveMoveResize(qreal x, qreal y, qreal x_root, qreal y_root)
Definition window.cpp:1423
void clientGeometryChanged(const QRectF &oldGeometry)
Options::MouseCommand getMouseCommand(Qt::MouseButton button, bool *handled) const
Definition window.cpp:1981
bool isInteractiveResize() const
Definition window.h:1114
Options::MouseCommand getWheelCommand(Qt::Orientation orientation, bool *handled) const
Definition window.cpp:2009
void finishInteractiveMoveResize(bool cancel)
Definition window.cpp:1262
virtual void pointerLeaveEvent()
Definition window.cpp:2847
bool isOnCurrentDesktop() const
Definition window.cpp:848
void windowRoleChanged()
void setUnrestrictedInteractiveMoveResize(bool set)
Definition window.h:1591
void setInteractiveMoveOffset(const QPointF &offset)
Definition window.h:1599
bool isMinimized() const
Definition window.h:988
void setHidden(bool hidden)
Definition window.cpp:4242
qreal y
Definition window.h:94
bool isActive() const
Definition window.h:882
bool isDecorated() const
Definition window.h:1162
bool performMouseCommand(Options::MouseCommand, const QPointF &globalPos)
Definition window.cpp:2022
qreal x
Definition window.h:89
void updateColorScheme()
Definition window.cpp:1053
QRectF rect
Definition window.h:113
void bufferGeometryChanged(const QRectF &oldGeometry)
bool isSplash() const
Definition window.h:1942
void updateCursor()
Definition window.cpp:2376
void frameGeometryChanged(const QRectF &oldGeometry)
void updateShadow()
Definition window.cpp:264
void setInvertedInteractiveMoveOffset(const QPointF &offset)
Definition window.h:1607
bool isSpecialWindow() const
Definition window.cpp:702
bool processDecorationButtonPress(QMouseEvent *event, bool ignoreMenu=false)
Definition window.cpp:2720
QRectF m_clientGeometry
Definition window.h:1726
bool titlebarPositionUnderMouse() const
Definition window.cpp:959
Gravity interactiveMoveResizeGravity() const
Definition window.h:1616
X11Window * findUnmanaged(std::function< bool(const X11Window *)> func) const
Window * mostRecentlyActivatedWindow() const
Definition workspace.h:772
void updateClientArea()
ScreenEdges * screenEdges() const
X11Window * findClient(std::function< bool(const X11Window *)> func) const
Finds the first Client matching the condition expressed by passed in func.
void activateWindow(Window *window, bool force=false)
void gotFocusIn(const Window *window)
UserActionsMenu * userActionsMenu() const
Definition workspace.h:310
void updateFocusMousePosition(const QPointF &pos)
Definition workspace.h:820
bool activateNextWindow(Window *window)
bool requestFocus(Window *window, bool force=false)
bool workspaceEvent(xcb_generic_event_t *)
Definition events.cpp:147
void forEachClient(std::function< void(X11Window *)> func)
void setWasUserInteraction()
void requestDelayFocus(Window *)
void checkGroup(Group *gr=nullptr, bool force=false)
void checkActivities() override
xcb_window_t inputId() const
Definition x11window.h:82
xcb_window_t moveResizeGrabWindow() const
Definition x11window.h:615
void checkApplicationMenuObjectPath()
xcb_window_t frameId() const
void NETMoveResize(qreal x_root, qreal y_root, NET::Direction direction, xcb_button_t button)
Definition events.cpp:1273
bool hasScheduledRelease() const
void restackWindow(xcb_window_t above, int detail, NET::RequestSource source, xcb_timestamp_t timestamp, bool send_event=false)
Definition layers.cpp:680
void updateMouseGrab() override
Definition events.cpp:905
void destroyWindow() override
void keyPressEvent(uint key_code, xcb_timestamp_t time)
Definition events.cpp:1321
void checkApplicationMenuServiceName()
bool isUnmanaged() const override
bool windowEvent(xcb_generic_event_t *e)
Definition events.cpp:316
void updateUserTime(xcb_timestamp_t time=XCB_TIME_CURRENT_TIME)
xcb_window_t window() const
bool allowWindowActivation(xcb_timestamp_t time=-1U, bool focus_in=false)
bool isResizable() const override
xcb_timestamp_t userTime() const override
void releaseWindow(bool on_shutdown=false)
xcb_window_t wrapperId() const
void setBlockingCompositing(bool block)
int damageNotifyEvent() const
Definition xcbutils.cpp:486
int shapeNotifyEvent() const
Definition xcbutils.cpp:534
static Extensions * self()
Definition xcbutils.cpp:346
void setBorderWidth(uint32_t width)
Definition xcbutils.h:1845
void grabButton(uint8_t pointerMode, uint8_t keyboardmode, uint16_t modifiers=XCB_MOD_MASK_ANY, uint8_t button=XCB_BUTTON_INDEX_ANY, uint16_t eventMask=XCB_EVENT_MASK_BUTTON_PRESS, xcb_window_t confineTo=XCB_WINDOW_NONE, xcb_cursor_t cursor=XCB_CURSOR_NONE, bool ownerEvents=false)
Definition xcbutils.h:1854
void ungrabButton(uint16_t modifiers=XCB_MOD_MASK_ANY, uint8_t button=XCB_BUTTON_INDEX_ANY)
Definition xcbutils.h:1865
#define XScrL
Definition events.cpp:869
#define XCapL
Definition events.cpp:867
struct xcb_ge_generic_event_t xcb_ge_generic_event_t
#define XNumL
Definition events.cpp:868
qreal fromXNative(int value)
Definition xcbutils.cpp:632
Gravity
Definition globals.h:150
@ ShadeNone
Definition common.h:63
Qt::MouseButtons x11ToQtMouseButtons(int state)
Definition common.cpp:155
Qt::MouseButton x11ToQtMouseButton(int button)
Definition common.cpp:135
KWIN_EXPORT xcb_timestamp_t xTime()
Definition xcb.h:29
WaylandServer * waylandServer()
Workspace * workspace()
Definition workspace.h:830
Options * options
Definition main.cpp:73
EffectsHandler * effects
Qt::KeyboardModifiers x11ToQtKeyboardModifiers(int state)
Definition common.cpp:176
KWIN_EXPORT Atoms * atoms
Definition main.cpp:74