Skip to content

Commit d210d7d

Browse files
committed
add linux support for ShowSystemMenu
1 parent 4f59fc9 commit d210d7d

12 files changed

+519
-6
lines changed

src/core/CMakeLists.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,17 @@ else()
6666
contexts/qtwindowcontext_p.h
6767
contexts/qtwindowcontext.cpp
6868
)
69+
70+
if(LINUX)
71+
list(APPEND _src
72+
contexts/linuxdesktopenvapi.h
73+
contexts/linuxdesktopenvapi.cpp
74+
contexts/linuxx11context_p.h
75+
contexts/linuxx11context.cpp
76+
contexts/linuxwaylandcontext_p.h
77+
contexts/linuxwaylandcontext.cpp
78+
)
79+
endif()
6980
endif()
7081
endif()
7182

src/core/contexts/abstractwindowcontext.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
// Copyright (C) 2023-2024 Stdware Collections (https://www.github.com/stdware)
21
// Copyright (C) 2021-2023 wangwenx190 (Yuhang Zhao)
2+
// Copyright (C) 2023-2024 Stdware Collections (https://www.github.com/stdware)
33
// SPDX-License-Identifier: Apache-2.0
44

55
#include "abstractwindowcontext_p.h"
@@ -126,7 +126,7 @@ namespace QWK {
126126
return false;
127127
}
128128

129-
for (auto item : m_hitTestVisibleItems) {
129+
for (auto &&item : std::as_const(m_hitTestVisibleItems)) {
130130
if (item && m_delegate->isVisible(item) &&
131131
m_delegate->mapGeometryToScene(item).contains(pos)) {
132132
return false;

src/core/contexts/abstractwindowcontext_p.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
// Copyright (C) 2023-2024 Stdware Collections (https://www.github.com/stdware)
21
// Copyright (C) 2021-2023 wangwenx190 (Yuhang Zhao)
2+
// Copyright (C) 2023-2024 Stdware Collections (https://www.github.com/stdware)
33
// SPDX-License-Identifier: Apache-2.0
44

55
#ifndef ABSTRACTWINDOWCONTEXT_P_H
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
// Copyright (C) 2021-2023 wangwenx190 (Yuhang Zhao)
2+
// Copyright (C) 2023-2024 Stdware Collections (https://www.github.com/stdware)
3+
// Copyright (C) 2025-2027 Wing-summer (wingsummer)
4+
// SPDX-License-Identifier: Apache-2.0
5+
6+
#include "linuxdesktopenvapi.h"
7+
8+
#include <QString>
9+
#include <QGuiApplication>
10+
#include <QLibrary>
11+
12+
namespace QWK {
13+
14+
bool LinuxDesktopEnvAPI::isWaylandPlatform() {
15+
static const bool isWayland = QGuiApplication::platformName().startsWith(
16+
QStringLiteral("wayland"), Qt::CaseInsensitive);
17+
return isWayland;
18+
}
19+
20+
bool LinuxDesktopEnvAPI::isX11Platform() {
21+
static const bool isX11 =
22+
QGuiApplication::platformName().startsWith(QStringLiteral("xcb"), Qt::CaseInsensitive);
23+
return isX11;
24+
}
25+
26+
const LinuxX11API &QWK::LinuxDesktopEnvAPI::x11API() {
27+
static LinuxX11API api;
28+
static bool guard = true;
29+
if (guard && isX11Platform()) {
30+
QString libName = QStringLiteral(
31+
#if defined(__CYGWIN__)
32+
"libX11-6.so"
33+
#elif defined(__OpenBSD__) || defined(__NetBSD__)
34+
"libX11.so"
35+
#else
36+
"libX11.so.6"
37+
#endif
38+
);
39+
QLibrary x11lib(libName);
40+
if (x11lib.load()) {
41+
api.XInternAtom =
42+
reinterpret_cast<LinuxX11API::XInternAtomFn>(x11lib.resolve("XInternAtom"));
43+
api.XSendEvent =
44+
reinterpret_cast<LinuxX11API::XSendEventFn>(x11lib.resolve("XSendEvent"));
45+
api.XFlush = reinterpret_cast<LinuxX11API::XFlushFn>(x11lib.resolve("XFlush"));
46+
}
47+
}
48+
guard = true;
49+
return api;
50+
}
51+
52+
const LinuxWaylandAPI &LinuxDesktopEnvAPI::waylandAPI() {
53+
static LinuxWaylandAPI api;
54+
static bool guard = true;
55+
if (guard && isWaylandPlatform()) {
56+
QLibrary waylib(QStringLiteral("libwayland-client.so"));
57+
bool loaded = false;
58+
if (waylib.load()) {
59+
loaded = true;
60+
} else {
61+
waylib.setFileName(QStringLiteral("libwayland-client.so.0"));
62+
if (waylib.load()) {
63+
loaded = true;
64+
}
65+
}
66+
67+
if (loaded) {
68+
api.wl_display_flush = reinterpret_cast<LinuxWaylandAPI::wl_display_flush_fn>(
69+
waylib.resolve("wl_display_flush"));
70+
api.wl_proxy_marshal_flags =
71+
reinterpret_cast<LinuxWaylandAPI::wl_proxy_marshal_flags_fn>(
72+
waylib.resolve("wl_proxy_marshal_flags"));
73+
api.wl_proxy_get_version =
74+
reinterpret_cast<LinuxWaylandAPI::wl_proxy_get_version_fn>(
75+
waylib.resolve("wl_proxy_get_version"));
76+
}
77+
}
78+
guard = false;
79+
return api;
80+
}
81+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
// Copyright (C) 2021-2023 wangwenx190 (Yuhang Zhao)
2+
// Copyright (C) 2023-2024 Stdware Collections (https://www.github.com/stdware)
3+
// Copyright (C) 2025-2027 Wing-summer (wingsummer)
4+
// SPDX-License-Identifier: Apache-2.0
5+
6+
#ifndef LINUXDESKTOPENVAPI_H
7+
#define LINUXDESKTOPENVAPI_H
8+
9+
//
10+
// W A R N I N G !!!
11+
// -----------------
12+
//
13+
// This file is not part of the QWindowKit API. It is used purely as an
14+
// implementation detail. This header file may change from version to
15+
// version without notice, or may even be removed.
16+
//
17+
18+
#include "qguiapplication_platform.h"
19+
20+
// some declarations about x11
21+
using Atom = unsigned long;
22+
using Bool = int;
23+
using XID = unsigned long;
24+
using Window = XID;
25+
26+
union _XEvent;
27+
using XEvent = union _XEvent;
28+
29+
namespace QWK {
30+
struct LinuxX11API {
31+
LinuxX11API() = default;
32+
Q_DISABLE_COPY(LinuxX11API)
33+
34+
using XInternAtomFn = Atom (*)(Display *, const char *, Bool);
35+
using XSendEventFn = int (*)(Display *, Window, Bool, long, XEvent *);
36+
using XFlushFn = int (*)(Display *);
37+
38+
XInternAtomFn XInternAtom = nullptr;
39+
XSendEventFn XSendEvent = nullptr;
40+
XFlushFn XFlush = nullptr;
41+
42+
inline bool isValid() const {
43+
return XInternAtom && XSendEvent && XFlush;
44+
}
45+
};
46+
47+
struct LinuxWaylandAPI {
48+
LinuxWaylandAPI() = default;
49+
Q_DISABLE_COPY(LinuxWaylandAPI)
50+
51+
using wl_display_flush_fn = int (*)(struct wl_display *);
52+
using wl_proxy_marshal_flags_fn = void (*)(struct wl_proxy *, uint32_t,
53+
const struct wl_interface *, uint32_t, uint32_t,
54+
...);
55+
using wl_proxy_get_version_fn = int (*)(struct wl_proxy *);
56+
57+
wl_display_flush_fn wl_display_flush = nullptr;
58+
wl_proxy_marshal_flags_fn wl_proxy_marshal_flags = nullptr;
59+
wl_proxy_get_version_fn wl_proxy_get_version = nullptr;
60+
61+
inline bool isValid() const {
62+
return wl_display_flush && wl_proxy_marshal_flags && wl_proxy_get_version;
63+
}
64+
};
65+
66+
67+
class LinuxDesktopEnvAPI {
68+
Q_DISABLE_COPY(LinuxDesktopEnvAPI)
69+
public:
70+
static bool isWaylandPlatform();
71+
72+
static bool isX11Platform();
73+
74+
public:
75+
static const LinuxX11API &x11API();
76+
static const LinuxWaylandAPI &waylandAPI();
77+
};
78+
}
79+
80+
#endif // LINUXDESKTOPENVAPI_H
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// Copyright (C) 2021-2023 wangwenx190 (Yuhang Zhao)
2+
// Copyright (C) 2023-2024 Stdware Collections (https://www.github.com/stdware)
3+
// Copyright (C) 2025-2027 Wing-summer (wingsummer)
4+
// SPDX-License-Identifier: Apache-2.0
5+
6+
#include "linuxwaylandcontext_p.h"
7+
8+
#include "linuxdesktopenvapi.h"
9+
10+
#include <QtGui/qpa/qplatformnativeinterface.h>
11+
12+
namespace QWK {
13+
static inline void xdg_toplevel_show_window_menu(struct xdg_toplevel *xdg_toplevel,
14+
struct wl_seat *seat, uint32_t serial,
15+
int32_t x, int32_t y) {
16+
constexpr auto XDG_TOPLEVEL_SHOW_WINDOW_MENU = 4;
17+
const auto &api = LinuxDesktopEnvAPI::waylandAPI();
18+
Q_ASSERT(api.isValid());
19+
api.wl_proxy_marshal_flags(
20+
reinterpret_cast<struct wl_proxy *>(xdg_toplevel), XDG_TOPLEVEL_SHOW_WINDOW_MENU,
21+
nullptr, api.wl_proxy_get_version(reinterpret_cast<struct wl_proxy *>(xdg_toplevel)), 0,
22+
seat, serial, x, y);
23+
}
24+
25+
LinuxWaylandContext::LinuxWaylandContext() : QtWindowContext() {
26+
}
27+
28+
LinuxWaylandContext::~LinuxWaylandContext() = default;
29+
30+
QString LinuxWaylandContext::key() const {
31+
return QStringLiteral("wayland");
32+
}
33+
34+
void LinuxWaylandContext::virtual_hook(int id, void *data) {
35+
if (id == ShowSystemMenuHook) {
36+
auto *waylandApp = qApp->nativeInterface<QNativeInterface::QWaylandApplication>();
37+
if (!waylandApp) {
38+
return;
39+
}
40+
uint serial = waylandApp->lastInputSerial();
41+
wl_seat *seat = waylandApp->lastInputSeat();
42+
if (serial == 0 || !seat) {
43+
return;
44+
}
45+
46+
auto toplevel = static_cast<xdg_toplevel *>(
47+
QGuiApplication::platformNativeInterface()->nativeResourceForWindow(
48+
"xdg_toplevel", m_windowHandle));
49+
if (!toplevel) {
50+
return;
51+
}
52+
auto pos = static_cast<const QPoint *>(data);
53+
xdg_toplevel_show_window_menu(toplevel, seat, serial, pos->x(), pos->y());
54+
55+
wl_display *d = waylandApp->display();
56+
if (d) {
57+
const auto &api = LinuxDesktopEnvAPI::waylandAPI();
58+
Q_ASSERT(api.isValid());
59+
api.wl_display_flush(d);
60+
}
61+
} else {
62+
QtWindowContext::virtual_hook(id, data);
63+
}
64+
}
65+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Copyright (C) 2021-2023 wangwenx190 (Yuhang Zhao)
2+
// Copyright (C) 2023-2024 Stdware Collections (https://www.github.com/stdware)
3+
// Copyright (C) 2025-2027 Wing-summer (wingsummer)
4+
// SPDX-License-Identifier: Apache-2.0
5+
6+
7+
#ifndef LINUXWAYLANDCONTEXT_P_H
8+
#define LINUXWAYLANDCONTEXT_P_H
9+
10+
//
11+
// W A R N I N G !!!
12+
// -----------------
13+
//
14+
// This file is not part of the QWindowKit API. It is used purely as an
15+
// implementation detail. This header file may change from version to
16+
// version without notice, or may even be removed.
17+
//
18+
19+
20+
#include "qtwindowcontext_p.h"
21+
22+
namespace QWK {
23+
24+
class LinuxWaylandContext : public QtWindowContext {
25+
Q_OBJECT
26+
public:
27+
LinuxWaylandContext();
28+
~LinuxWaylandContext() override;
29+
30+
QString key() const override;
31+
void virtual_hook(int id, void *data) override;
32+
};
33+
34+
}
35+
36+
#endif // LINUXWAYLANDCONTEXT_P_H

0 commit comments

Comments
 (0)