1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
|
// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: LGPL-3.0-or-later
#include <QGuiApplication>
#include <QWindow>
#include <QX11Info>
#include <QMouseEvent>
#include <qpa/qplatformwindow.h>
#include <xcb/xcb.h>
void setWindowProperty(quint32 WId, xcb_atom_t propAtom, xcb_atom_t typeAtom, const void *data, quint32 len, uint8_t format)
{
xcb_connection_t* conn = QX11Info::connection();
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, WId, propAtom, typeAtom, format, len, data);
xcb_flush(conn);
}
void clearWindowProperty(quint32 WId, xcb_atom_t propAtom)
{
xcb_delete_property_checked(QX11Info::connection(), WId, propAtom);
}
xcb_atom_t internAtom(xcb_connection_t *connection, const char *name, bool only_if_exists)
{
if (!name || *name == 0)
return XCB_NONE;
xcb_intern_atom_cookie_t cookie = xcb_intern_atom(connection, only_if_exists, strlen(name), name);
xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(connection, cookie, 0);
if (!reply)
return XCB_NONE;
xcb_atom_t atom = reply->atom;
free(reply);
return atom;
}
xcb_atom_t internAtom(const char *name, bool only_if_exists)
{
return internAtom(QX11Info::connection(), name, only_if_exists);
}
bool isSupported(xcb_atom_t targetAtom)
{
// get _NET_SUPPORTED from root window
QVector<xcb_atom_t> net_wm_atoms;
xcb_window_t root = QX11Info::appRootWindow();
int offset = 0;
int remaining = 0;
xcb_connection_t *xcb_connection = QX11Info::connection();
auto _net_supported = internAtom(QT_STRINGIFY(_NET_SUPPORTED), false);
do {
xcb_get_property_cookie_t cookie = xcb_get_property(xcb_connection, false, root, _net_supported,
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.contains(targetAtom);
}
bool setNoTitlebar(quint32 WId, bool on)
{
xcb_atom_t _deepin_no_titlebar = internAtom(QT_STRINGIFY(_DEEPIN_NO_TITLEBAR), false);
if (!isSupported(_deepin_no_titlebar))
return false;
quint8 value = on;
setWindowProperty(WId, _deepin_no_titlebar, XCB_ATOM_CARDINAL, &value, 1, 8);
// force enable window decorations, becouse we need the window shadow and border, its contains in decorations.
xcb_atom_t _deepin_force_decorate = internAtom(QT_STRINGIFY(_DEEPIN_FORCE_DECORATE), false);
if (on) {
quint8 value = on;
setWindowProperty(WId, _deepin_force_decorate, XCB_ATOM_CARDINAL, &value, 1, 8);
} else {
clearWindowProperty(WId, _deepin_force_decorate);
}
return true;
}
QObject *createNativeSettingsFor(QWindow *window)
{
// The platform function in dxcb plugin:
// https://github.com/linuxdeepin/qt5platform-plugins/blob/master/src/dnativesettings.h
static QFunctionPointer build_function = qApp->platformFunction("_d_buildNativeSettings");
if (!build_function) {
return nullptr;
}
QObject *obj = new QObject(window);
bool ok = reinterpret_cast<bool(*)(QObject*, quint32)>(build_function)(obj, window->winId());
if (!ok) {
delete obj;
return nullptr;
}
return obj;
}
class Window : public QWindow
{
public:
bool handleMoveing = false;
private:
void mouseMoveEvent(QMouseEvent *e) override {
if (handleMoveing && e->buttons() == Qt::LeftButton) {
handle()->startSystemMove();
} else {
QWindow::mouseMoveEvent(e);
}
}
};
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
Window window;
window.resize(200, 200);
if (setNoTitlebar(window.winId(), true)) {
// If enabled no titlebar mode, the window is no min/max/close buttons, you need to implement it by Qt widgets.
// Like as https://github.com/linuxdeepin/dtkwidget/blob/master/src/widgets/dtitlebar.cpp
window.handleMoveing = true;
auto nativeSettings = createNativeSettingsFor(&window);
if (nativeSettings) {
nativeSettings->setProperty("DTK/WindowRadius", "100,100");
nativeSettings->setProperty("borderWidth", 2);
nativeSettings->setProperty("borderColor", QColor(Qt::red));
nativeSettings->setProperty("shadowOffset", "30,30");
nativeSettings->setProperty("shadowRadius", 30);
nativeSettings->setProperty("shadowColor", QColor(Qt::blue));
// See more properties in DPlatformTheme
}
}
window.show();
return app.exec();
}
|