diff --git a/CMakeLists.txt b/CMakeLists.txt --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -485,6 +485,7 @@ scripting/workspace_wrapper.cpp shadow.cpp sm.cpp + sync_filter.cpp thumbnailitem.cpp toplevel.cpp touch_hide_cursor_spy.cpp diff --git a/main.h b/main.h --- a/main.h +++ b/main.h @@ -190,6 +190,14 @@ return m_terminating; } + bool updatingXTimer() { + return m_updatingXTimer; + } + + void setUpdatingXTimer(bool updating) { + m_updatingXTimer = updating; + } + static void setupMalloc(); static void setupLocalizedString(); @@ -258,6 +266,7 @@ #endif Platform *m_platform = nullptr; bool m_terminating = false; + bool m_updatingXTimer = false; }; inline static Application *kwinApp() diff --git a/main.cpp b/main.cpp --- a/main.cpp +++ b/main.cpp @@ -365,7 +365,22 @@ // no timestamp return; case XCB_PROPERTY_NOTIFY: - time = reinterpret_cast(event)->time; + { + xcb_property_notify_event_t *propertyNotify = reinterpret_cast(event); + time = propertyNotify->time; + + // updateXTime handling see also Platform::updateXTime + if (kwinApp()->m_updatingXTimer && propertyNotify->window == m_rootWindow + && propertyNotify->atom == atoms->clipboard + ) { + // this event was sent by Platform::updateXTime + // to forcefully update the timestamp at the expected point in time + // inspired by https://code.woboq.org/qt5/qtbase/src/plugins/platforms/xcb/qxcbconnection.h.html#QXcbConnection QXcbConnection::getTimestamp() + kwinApp()->setX11Time(time, Application::TimestampUpdate::Always); + xcb_delete_property(connection(), m_rootWindow, atoms->clipboard); + m_updatingXTimer = false; + } + } break; case XCB_SELECTION_CLEAR: time = reinterpret_cast(event)->time; diff --git a/platform.h b/platform.h --- a/platform.h +++ b/platform.h @@ -41,6 +41,7 @@ namespace KWin { + namespace ColorCorrect { class Manager; } @@ -364,13 +365,9 @@ virtual OverlayWindow *createOverlayWindow(); /** - * Allows a platform to update the X11 timestamp. - * Mostly for the X11 standalone platform to interact with QX11Info. - * - * Default implementation does nothing. This means code relying on the X timestamp being up to date, - * might not be working. E.g. synced X11 window resizing + * Allows a platform to update the X11 timestamp, asynchrounously. */ - virtual void updateXTime(); + void updateXTime(); /** * Creates the OutlineVisual for the given @p outline. diff --git a/platform.cpp b/platform.cpp --- a/platform.cpp +++ b/platform.cpp @@ -20,6 +20,7 @@ #include "platform.h" #include "abstract_output.h" +#include "atoms.h" #include #include "composite.h" #include "cursor.h" @@ -34,6 +35,8 @@ #include "wayland_server.h" #include "colorcorrection/manager.h" +#include "xcb/xproto.h" + #include #include @@ -501,8 +504,30 @@ return nullptr; } + +/** + * Updates xTime(). This used to simply fetch current timestamp from the server, + * but that can cause xTime() to be newer than timestamp of events that are + * still in our events queue, thus e.g. making XSetInputFocus() caused by such + * event to be ignored. Therefore events queue is searched for first + * event with timestamp, and extra PropertyNotify is generated in order to make + * sure such event is found. + */ void Platform::updateXTime() { + // change a dummy property so that we get an event caught in Application::updateX11Time + xcb_window_t window = rootWindow(); + + xcb_change_property(connection(), XCB_PROP_MODE_APPEND, window, atoms->clipboard, + XCB_ATOM_INTEGER, 32, 0, nullptr); + xcb_flush(connection()); + + // from xcb_aux_sync + xcb_get_input_focus_cookie_t cookie = xcb_get_input_focus(connection()); + free(xcb_get_input_focus_reply(connection(), cookie, 0)); + + // will update + kwinApp()->setUpdatingXTimer(true); } OutlineVisual *Platform::createOutline(Outline *outline) diff --git a/plugins/platforms/x11/standalone/CMakeLists.txt b/plugins/platforms/x11/standalone/CMakeLists.txt --- a/plugins/platforms/x11/standalone/CMakeLists.txt +++ b/plugins/platforms/x11/standalone/CMakeLists.txt @@ -7,7 +7,6 @@ overlaywindow_x11.cpp screenedges_filter.cpp screens_xrandr.cpp - sync_filter.cpp windowselector.cpp x11_decoration_renderer.cpp x11_output.cpp diff --git a/plugins/platforms/x11/standalone/x11_platform.h b/plugins/platforms/x11/standalone/x11_platform.h --- a/plugins/platforms/x11/standalone/x11_platform.h +++ b/plugins/platforms/x11/standalone/x11_platform.h @@ -29,7 +29,6 @@ namespace KWin { -class SyncFilter; class XInputIntegration; class WindowSelector; class X11EventFilter; @@ -63,7 +62,6 @@ OverlayWindow *createOverlayWindow() override; - void updateXTime() override; OutlineVisual *createOutline(Outline *outline) override; Decoration::Renderer *createDecorationRenderer(Decoration::DecoratedClientImpl *client) override; @@ -103,7 +101,6 @@ Display *m_x11Display; QScopedPointer m_windowSelector; QScopedPointer m_screenEdgesFilter; - std::unique_ptr m_syncFilter; QVector m_outputs; }; diff --git a/plugins/platforms/x11/standalone/x11_platform.cpp b/plugins/platforms/x11/standalone/x11_platform.cpp --- a/plugins/platforms/x11/standalone/x11_platform.cpp +++ b/plugins/platforms/x11/standalone/x11_platform.cpp @@ -20,7 +20,6 @@ #include "x11_platform.h" #include "x11cursor.h" #include "edge.h" -#include "sync_filter.h" #include "windowselector.h" #include #include @@ -74,13 +73,6 @@ } } #endif - connect(kwinApp(), &Application::workspaceCreated, this, - [this] { - if (Xcb::Extensions::self()->isSyncAvailable()) { - m_syncFilter = std::make_unique(); - } - } - ); setSupportsGammaControl(true); } @@ -348,22 +340,6 @@ return new OverlayWindowX11(); } -/* - Updates xTime(). This used to simply fetch current timestamp from the server, - but that can cause xTime() to be newer than timestamp of events that are - still in our events queue, thus e.g. making XSetInputFocus() caused by such - event to be ignored. Therefore events queue is searched for first - event with timestamp, and extra PropertyNotify is generated in order to make - sure such event is found. -*/ -void X11StandalonePlatform::updateXTime() -{ - // NOTE: QX11Info::getTimestamp does not yet search the event queue as the old - // solution did. This means there might be regressions currently. See the - // documentation above on how it should be done properly. - kwinApp()->setX11Time(QX11Info::getTimestamp(), Application::TimestampUpdate::Always); -} - OutlineVisual *X11StandalonePlatform::createOutline(Outline *outline) { // first try composited Outline diff --git a/plugins/platforms/x11/standalone/sync_filter.h b/sync_filter.h rename from plugins/platforms/x11/standalone/sync_filter.h rename to sync_filter.h --- a/plugins/platforms/x11/standalone/sync_filter.h +++ b/sync_filter.h @@ -25,10 +25,10 @@ { class X11Cursor; -class SyncFilter : public X11EventFilter +class SyncAlarmNotifyX11Filter : public X11EventFilter { public: - explicit SyncFilter(); + explicit SyncAlarmNotifyX11Filter(); bool event(xcb_generic_event_t *event) override; }; diff --git a/plugins/platforms/x11/standalone/sync_filter.cpp b/sync_filter.cpp rename from plugins/platforms/x11/standalone/sync_filter.cpp rename to sync_filter.cpp --- a/plugins/platforms/x11/standalone/sync_filter.cpp +++ b/sync_filter.cpp @@ -25,12 +25,12 @@ namespace KWin { -SyncFilter::SyncFilter() +SyncAlarmNotifyX11Filter::SyncAlarmNotifyX11Filter() : X11EventFilter(QVector{Xcb::Extensions::self()->syncAlarmNotifyEvent()}) { } -bool SyncFilter::event(xcb_generic_event_t *event) +bool SyncAlarmNotifyX11Filter::event(xcb_generic_event_t *event) { auto e = reinterpret_cast< xcb_sync_alarm_notify_event_t* >(event); auto client = workspace()->findClient( diff --git a/workspace.h b/workspace.h --- a/workspace.h +++ b/workspace.h @@ -44,6 +44,7 @@ namespace KWin { +class SyncAlarmNotifyX11Filter; namespace Xcb { @@ -670,6 +671,7 @@ QScopedPointer m_movingClientFilter; SessionManager *m_sessionManager; + QScopedPointer m_syncFilter; private: friend bool performTransiencyCheck(); friend Workspace *workspace(); diff --git a/workspace.cpp b/workspace.cpp --- a/workspace.cpp +++ b/workspace.cpp @@ -50,6 +50,7 @@ #include "screens.h" #include "platform.h" #include "scripting/scripting.h" +#include "sync_filter.h" #ifdef KWIN_BUILD_TABBOX #include "tabbox.h" #endif @@ -446,6 +447,14 @@ } if (new_active_client != nullptr) activateClient(new_active_client); + + if (Xcb::Extensions::self()->isSyncAvailable()) { + connect(kwinApp(), &Application::workspaceCreated, this, + [this] { + QScopedPointer m_syncFilter(new SyncAlarmNotifyX11Filter()); + } + ); + } } Workspace::~Workspace() diff --git a/x11client.cpp b/x11client.cpp --- a/x11client.cpp +++ b/x11client.cpp @@ -2344,9 +2344,7 @@ void X11Client::getSyncCounter() { - // TODO: make sync working on XWayland - static const bool isX11 = kwinApp()->operationMode() == Application::OperationModeX11; - if (!Xcb::Extensions::self()->isSyncAvailable() || !isX11) + if (!Xcb::Extensions::self()->isSyncAvailable()) return; Xcb::Property syncProp(false, window(), atoms->net_wm_sync_request_counter, XCB_ATOM_CARDINAL, 0, 1);