File indexing completed on 2024-12-22 04:31:07

0001 /*
0002  * Copyright (C) 2021 CutefishOS Team.
0003  *
0004  * Author:     cutefish <cutefishos@foxmail.com>
0005  *
0006  * This program is free software: you can redistribute it and/or modify
0007  * it under the terms of the GNU General Public License as published by
0008  * the Free Software Foundation, either version 3 of the License, or
0009  * any later version.
0010  *
0011  * This program is distributed in the hope that it will be useful,
0012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0014  * GNU General Public License for more details.
0015  *
0016  * You should have received a copy of the GNU General Public License
0017  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
0018  */
0019 
0020 #include "windowhelper.h"
0021 
0022 #include <QApplication>
0023 #include <QX11Info>
0024 #include <QCursor>
0025 
0026 #include <KWindowSystem>
0027 
0028 static uint qtEdgesToXcbMoveResizeDirection(Qt::Edges edges)
0029 {
0030     if (edges == (Qt::TopEdge | Qt::LeftEdge))
0031         return 0;
0032     if (edges == Qt::TopEdge)
0033         return 1;
0034     if (edges == (Qt::TopEdge | Qt::RightEdge))
0035         return 2;
0036     if (edges == Qt::RightEdge)
0037         return 3;
0038     if (edges == (Qt::RightEdge | Qt::BottomEdge))
0039         return 4;
0040     if (edges == Qt::BottomEdge)
0041         return 5;
0042     if (edges == (Qt::BottomEdge | Qt::LeftEdge))
0043         return 6;
0044     if (edges == Qt::LeftEdge)
0045         return 7;
0046 
0047     return 0;
0048 }
0049 
0050 WindowHelper::WindowHelper(QObject *parent)
0051     : QObject(parent)
0052     , m_moveResizeAtom(0)
0053     , m_compositing(false)
0054 {
0055     // create move-resize atom
0056     // ref: https://github.com/qt/qtbase/blob/9db7cc79a26ced4997277b5c206ca15949133240/src/plugins/platforms/xcb/qxcbwindow.cpp
0057     xcb_connection_t* connection(QX11Info::connection());
0058     const QString atomName(QStringLiteral("_NET_WM_MOVERESIZE"));
0059     xcb_intern_atom_cookie_t cookie(xcb_intern_atom(connection, false, atomName.size(), qPrintable(atomName)));
0060     QScopedPointer<xcb_intern_atom_reply_t> reply(xcb_intern_atom_reply(connection, cookie, nullptr));
0061     m_moveResizeAtom = reply ? reply->atom : 0;
0062 
0063     onCompositingChanged(KWindowSystem::compositingActive());
0064     connect(KWindowSystem::self(), &KWindowSystem::compositingChanged, this, &WindowHelper::onCompositingChanged);
0065 }
0066 
0067 bool WindowHelper::compositing() const
0068 {
0069     return m_compositing;
0070 }
0071 
0072 void WindowHelper::startSystemMove(QWindow *w)
0073 {
0074     doStartSystemMoveResize(w, 16);
0075 }
0076 
0077 void WindowHelper::startSystemResize(QWindow *w, Qt::Edges edges)
0078 {
0079     doStartSystemMoveResize(w, edges);
0080 }
0081 
0082 void WindowHelper::minimizeWindow(QWindow *w)
0083 {
0084     KWindowSystem::minimizeWindow(w->winId());
0085 }
0086 
0087 void WindowHelper::doStartSystemMoveResize(QWindow *w, int edges)
0088 {
0089     const qreal dpiRatio = qApp->devicePixelRatio();
0090 
0091     xcb_connection_t *connection(QX11Info::connection());
0092     xcb_client_message_event_t xev;
0093     xev.response_type = XCB_CLIENT_MESSAGE;
0094     xev.type = m_moveResizeAtom;
0095     xev.sequence = 0;
0096     xev.window = w->winId();
0097     xev.format = 32;
0098     xev.data.data32[0] = QCursor::pos().x() * dpiRatio;
0099     xev.data.data32[1] = QCursor::pos().y() * dpiRatio;
0100 
0101     if (edges == 16)
0102         xev.data.data32[2] = 8; // move
0103     else
0104         xev.data.data32[2] = qtEdgesToXcbMoveResizeDirection(Qt::Edges(edges));
0105 
0106     xev.data.data32[3] = XCB_BUTTON_INDEX_1;
0107     xev.data.data32[4] = 0;
0108     xcb_ungrab_pointer(connection, XCB_CURRENT_TIME);
0109     xcb_send_event(connection, false, QX11Info::appRootWindow(),
0110                    XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY,
0111                    (const char *)&xev);
0112 }
0113 
0114 void WindowHelper::onCompositingChanged(bool enabled)
0115 {
0116     if (enabled != m_compositing) {
0117         m_compositing = enabled;
0118         emit compositingChanged();
0119     }
0120 }