From cfff488562e913673cf42ff915b242ee15a05176 Mon Sep 17 00:00:00 2001 From: zccrs Date: Fri, 17 May 2019 16:30:09 +0800 Subject: [PATCH] feat: support _GTK_SHOW_WINDOW_MENU https://github.com/linuxdeepin/internal-discussion/issues/1320 --- atoms.cpp | 1 + atoms.h | 1 + events.cpp | 8 ++++++ rootinfo_filter.cpp | 67 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 77 insertions(+) diff --git a/atoms.cpp b/atoms.cpp index ee9e8e2..ecd4cf6 100644 --- a/atoms.cpp +++ b/atoms.cpp @@ -56,6 +56,7 @@ Atoms::Atoms() , kde_skip_close_animation(QByteArrayLiteral("_KDE_NET_WM_SKIP_CLOSE_ANIMATION")) , kde_screen_edge_show(QByteArrayLiteral("_KDE_NET_WM_SCREEN_EDGE_SHOW")) , gtk_frame_extents(QByteArrayLiteral("_GTK_FRAME_EXTENTS")) + , gtk_show_window_menu(QByteArrayLiteral("_GTK_SHOW_WINDOW_MENU")) , kwin_dbus_service(QByteArrayLiteral("_ORG_KDE_KWIN_DBUS_SERVICE")) , utf8_string(QByteArrayLiteral("UTF8_STRING")) , wl_surface_id(QByteArrayLiteral("WL_SURFACE_ID")) diff --git a/atoms.h b/atoms.h index 2c7b2d9..fb2a544 100644 --- a/atoms.h +++ b/atoms.h @@ -65,6 +65,7 @@ public: Xcb::Atom kde_skip_close_animation; Xcb::Atom kde_screen_edge_show; Xcb::Atom gtk_frame_extents; + Xcb::Atom gtk_show_window_menu; Xcb::Atom kwin_dbus_service; Xcb::Atom utf8_string; Xcb::Atom wl_surface_id; diff --git a/events.cpp b/events.cpp index 17a2606..b4f558d 100644 --- a/events.cpp +++ b/events.cpp @@ -661,6 +661,14 @@ void Client::clientMessageEvent(xcb_client_message_event_t *e) if (e->data.data32[0] == XCB_ICCCM_WM_STATE_ICONIC) minimize(); return; + } else if (e->type == atoms->gtk_show_window_menu) { + // _GTK_SHOW_WINDOW_MENU + QPoint pos; + + pos.setX(e->data.data32[1]); + pos.setY(e->data.data32[2]); + + workspace()->showWindowMenu(QRect(pos, pos), this); } } diff --git a/rootinfo_filter.cpp b/rootinfo_filter.cpp index 1a0cb35..bef9202 100644 --- a/rootinfo_filter.cpp +++ b/rootinfo_filter.cpp @@ -20,6 +20,8 @@ along with this program. If not, see . #include "rootinfo_filter.h" #include "netinfo.h" #include "virtualdesktops.h" +#include "xcbutils.h" +#include "atoms.h" namespace KWin { @@ -30,15 +32,80 @@ RootInfoFilter::RootInfoFilter(RootInfo *parent) { } +static QVector getNetWMAtoms(xcb_atom_t property) +{ + QVector net_wm_atoms; + + xcb_window_t root = rootWindow(); + int offset = 0; + int remaining = 0; + xcb_connection_t *xcb_connection = connection(); + + do { + xcb_get_property_cookie_t cookie = xcb_get_property(xcb_connection, false, root, + + property, + + XCB_ATOM_ATOM, offset, 1024); + xcb_get_property_reply_t *reply = xcb_get_property_reply(xcb_connection, cookie, NULL); + if (!reply) + break; + + remaining = 0; + + if (reply->type == XCB_ATOM_ATOM && reply->format == 32) { + int len = xcb_get_property_value_length(reply)/sizeof(xcb_atom_t); + xcb_atom_t *atoms = (xcb_atom_t *)xcb_get_property_value(reply); + int s = net_wm_atoms.size(); + net_wm_atoms.resize(s + len); + memcpy(net_wm_atoms.data() + s, atoms, len*sizeof(xcb_atom_t)); + + remaining = reply->bytes_after; + offset += len; + } + + free(reply); + } while (remaining > 0); + + return net_wm_atoms; +} + bool RootInfoFilter::event(xcb_generic_event_t *event) { NET::Properties dirtyProtocols; NET::Properties2 dirtyProtocols2; + m_rootInfo->event(event, &dirtyProtocols, &dirtyProtocols2); if (dirtyProtocols & NET::DesktopNames) VirtualDesktopManager::self()->save(); if (dirtyProtocols2 & NET::WM2DesktopLayout) VirtualDesktopManager::self()->updateLayout(); + + // TODO(zccrs): 应该在 kwindowsystem 项目的 NETRootInfo 中添加 + if ((event->response_type & ~0x80) == XCB_PROPERTY_NOTIFY) { + xcb_property_notify_event_t *pe = reinterpret_cast(event); + Xcb::Atom net_support(QByteArrayLiteral("_NET_SUPPORTED")); + xcb_atom_t gtk_frame_extents = atoms->gtk_frame_extents; + + if (pe->atom == net_support) { + auto old_atoms = getNetWMAtoms(net_support); + QVector new_atoms; + + if (!old_atoms.contains(gtk_frame_extents)) { + // Append _GTK_FRAME_EXTENTS atom to _NET_SUPPORTED + new_atoms << gtk_frame_extents; + } + + if (!old_atoms.contains(atoms->gtk_show_window_menu)) { + // Support _GTK_SHOW_WINDOW_MENU + new_atoms << atoms->gtk_show_window_menu; + } + + if (!new_atoms.isEmpty()) { + xcb_change_property(connection(), XCB_PROP_MODE_APPEND, rootWindow(), + net_support, XCB_ATOM_ATOM, 32, new_atoms.length(), new_atoms.constData()); + } + } + } + return false; } -- 2.20.1