-
Notifications
You must be signed in to change notification settings - Fork 178
Closed
Labels
enhancementNew feature or requestNew feature or request
Description
您好作者,目前该库只提供了 Windows 上的系统菜单弹出支持,对于 Linux 常见的桌面协议 X11 和 wayland 并没有提供支持。我尝试去实现功能支持,目前已经实现了,在 KDE 桌面环境测试,使用 Qt 6.10,弹出系统菜单的逻辑都在实现AbstractWindowContext::virtual_hook,下面是实现代码:
X11
编译通过需要链接 X11
在对应实现的实现文件需要引入头文件:
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#undef CursorShape // 避免和 Qt::CursorShape 冲突然后在virtual_hook中实现:
if (id == ShowSystemMenuHook) {
auto *x11app = qApp->nativeInterface<QNativeInterface::QX11Application>();
if (!x11app)
return;
auto display = x11app->display();
if (!display)
return;
// use window id (XID)
Window xwin = static_cast<Window>(m_windowId);
Atom atom = XInternAtom(display, "_GTK_SHOW_WINDOW_MENU", False);
if (atom == None)
return; // WM might not support this atom
auto pos = static_cast<QPoint *>(data);
XEvent ev;
memset(&ev, 0, sizeof(ev));
ev.xclient.type = ClientMessage;
ev.xclient.window = xwin;
ev.xclient.message_type = atom;
ev.xclient.format = 32;
ev.xclient.data.l[0] = 3; // button
ev.xclient.data.l[1] = pos->x(); // root x
ev.xclient.data.l[2] = pos->y(); // root y
ev.xclient.data.l[3] = 0;
// send to the root so WM receives it
Window root = DefaultRootWindow(display);
XSendEvent(display, root, False, SubstructureRedirectMask | SubstructureNotifyMask,
&ev);
XFlush(display);
} Wayland
编译通过需要链接 wayland-client
在对应实现的实现文件需要引入头文件:
#include <QtGui/qpa/qplatformnativeinterface.h>
#include <wayland-client.h>需要增加 xdg_toplevel_show_window_menu 实现函数(参考 QT 代码):
static inline void xdg_toplevel_show_window_menu(struct xdg_toplevel *xdg_toplevel,
struct wl_seat *seat, uint32_t serial,
int32_t x, int32_t y) {
constexpr auto XDG_TOPLEVEL_SHOW_WINDOW_MENU = 4;
wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, XDG_TOPLEVEL_SHOW_WINDOW_MENU,
NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0,
seat, serial, x, y);
}然后在virtual_hook中实现:
if (id == ShowSystemMenuHook) {
auto *native = QGuiApplication::platformNativeInterface();
auto *waylandApp = qApp->nativeInterface<QNativeInterface::QWaylandApplication>();
if (!waylandApp) {
return;
}
uint serial = waylandApp->lastInputSerial();
wl_seat *seat = waylandApp->lastInputSeat();
if (serial == 0 || !seat) {
return;
}
void *rawToplevel = native->nativeResourceForWindow("xdg_toplevel", m_windowHandle);
if (!rawToplevel) {
return;
}
xdg_toplevel *toplevel = static_cast<xdg_toplevel *>(rawToplevel);
auto pos = static_cast<QPoint *>(data);
int lx = pos->x();
int ly = pos->y();
xdg_toplevel_show_window_menu(toplevel, seat, serial, lx, ly);
wl_display *d = waylandApp->display();
if (d){
wl_display_flush(d);
}
}补充说明
- 对应的桌面协议需要链接对应的库,这样对于一个库来说不够解耦而过于笨重,不能为了支持这两种协议都要链接,这个是不可取的,是否要考虑类似 QtPlugin 的设计,这个我希望您拿主意,合并这个功能和考虑这个设计,会造成库架构的调整。
- 在 KDE 测试由于我桌面只有 wayland ,所以测试 x11 使用的是 xwayland 。功能测试的时候发现系统菜单弹出始终会偏移一段距离,我分析不出来为什么,麻烦您如果有业余时间能够深入研究一下。
Metadata
Metadata
Assignees
Labels
enhancementNew feature or requestNew feature or request