File indexing completed on 2024-05-19 16:34:57
0001 /* 0002 KWin - the KDE window manager 0003 This file is part of the KDE project. 0004 0005 SPDX-FileCopyrightText: 1999, 2000 Matthias Ettrich <ettrich@kde.org> 0006 SPDX-FileCopyrightText: 2003 Lubos Lunak <l.lunak@kde.org> 0007 0008 SPDX-License-Identifier: GPL-2.0-or-later 0009 */ 0010 0011 /* 0012 0013 This file is for (very) small utility functions/classes. 0014 0015 */ 0016 0017 #include "utils/common.h" 0018 #include "utils/c_ptr.h" 0019 0020 #include <QPainter> 0021 #include <QWidget> 0022 #include <kkeyserver.h> 0023 0024 #ifndef KCMRULES 0025 #include <QApplication> 0026 #include <QDebug> 0027 #endif 0028 0029 Q_LOGGING_CATEGORY(KWIN_CORE, "kwin_core", QtWarningMsg) 0030 Q_LOGGING_CATEGORY(KWIN_OPENGL, "kwin_scene_opengl", QtWarningMsg) 0031 Q_LOGGING_CATEGORY(KWIN_QPAINTER, "kwin_scene_qpainter", QtWarningMsg) 0032 Q_LOGGING_CATEGORY(KWIN_VIRTUALKEYBOARD, "kwin_virtualkeyboard", QtWarningMsg) 0033 namespace KWin 0034 { 0035 0036 #ifndef KCMRULES 0037 0038 //************************************ 0039 // StrutRect 0040 //************************************ 0041 0042 StrutRect::StrutRect(QRect rect, StrutArea area) 0043 : QRect(rect) 0044 , m_area(area) 0045 { 0046 } 0047 0048 StrutRect::StrutRect(int x, int y, int width, int height, StrutArea area) 0049 : QRect(x, y, width, height) 0050 , m_area(area) 0051 { 0052 } 0053 0054 StrutRect::StrutRect(const StrutRect &other) 0055 : QRect(other) 0056 , m_area(other.area()) 0057 { 0058 } 0059 0060 StrutRect &StrutRect::operator=(const StrutRect &other) 0061 { 0062 if (this != &other) { 0063 QRect::operator=(other); 0064 m_area = other.area(); 0065 } 0066 return *this; 0067 } 0068 0069 static int server_grab_count = 0; 0070 0071 void grabXServer() 0072 { 0073 if (++server_grab_count == 1) { 0074 xcb_grab_server(connection()); 0075 } 0076 } 0077 0078 void ungrabXServer() 0079 { 0080 Q_ASSERT(server_grab_count > 0); 0081 if (--server_grab_count == 0) { 0082 xcb_ungrab_server(connection()); 0083 xcb_flush(connection()); 0084 } 0085 } 0086 0087 static bool keyboard_grabbed = false; 0088 0089 bool grabXKeyboard(xcb_window_t w) 0090 { 0091 if (QWidget::keyboardGrabber() != nullptr) { 0092 return false; 0093 } 0094 if (keyboard_grabbed) { 0095 qCDebug(KWIN_CORE) << "Failed to grab X Keyboard: already grabbed by us"; 0096 return false; 0097 } 0098 if (qApp->activePopupWidget() != nullptr) { 0099 qCDebug(KWIN_CORE) << "Failed to grab X Keyboard: no popup widget"; 0100 return false; 0101 } 0102 if (w == XCB_WINDOW_NONE) { 0103 w = rootWindow(); 0104 } 0105 const xcb_grab_keyboard_cookie_t c = xcb_grab_keyboard_unchecked(connection(), false, w, xTime(), 0106 XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC); 0107 UniqueCPtr<xcb_grab_keyboard_reply_t> grab(xcb_grab_keyboard_reply(connection(), c, nullptr)); 0108 if (!grab) { 0109 qCDebug(KWIN_CORE) << "Failed to grab X Keyboard: grab null"; 0110 return false; 0111 } 0112 if (grab->status != XCB_GRAB_STATUS_SUCCESS) { 0113 qCDebug(KWIN_CORE) << "Failed to grab X Keyboard: grab failed with status" << grab->status; 0114 return false; 0115 } 0116 keyboard_grabbed = true; 0117 return true; 0118 } 0119 0120 void ungrabXKeyboard() 0121 { 0122 if (!keyboard_grabbed) { 0123 // grabXKeyboard() may fail sometimes, so don't fail, but at least warn anyway 0124 qCDebug(KWIN_CORE) << "ungrabXKeyboard() called but keyboard not grabbed!"; 0125 } 0126 keyboard_grabbed = false; 0127 xcb_ungrab_keyboard(connection(), XCB_TIME_CURRENT_TIME); 0128 } 0129 0130 #endif 0131 0132 // converting between X11 mouse/keyboard state mask and Qt button/keyboard states 0133 0134 Qt::MouseButton x11ToQtMouseButton(int button) 0135 { 0136 if (button == XCB_BUTTON_INDEX_1) { 0137 return Qt::LeftButton; 0138 } 0139 if (button == XCB_BUTTON_INDEX_2) { 0140 return Qt::MiddleButton; 0141 } 0142 if (button == XCB_BUTTON_INDEX_3) { 0143 return Qt::RightButton; 0144 } 0145 if (button == XCB_BUTTON_INDEX_4) { 0146 return Qt::XButton1; 0147 } 0148 if (button == XCB_BUTTON_INDEX_5) { 0149 return Qt::XButton2; 0150 } 0151 return Qt::NoButton; 0152 } 0153 0154 Qt::MouseButtons x11ToQtMouseButtons(int state) 0155 { 0156 Qt::MouseButtons ret = {}; 0157 if (state & XCB_KEY_BUT_MASK_BUTTON_1) { 0158 ret |= Qt::LeftButton; 0159 } 0160 if (state & XCB_KEY_BUT_MASK_BUTTON_2) { 0161 ret |= Qt::MiddleButton; 0162 } 0163 if (state & XCB_KEY_BUT_MASK_BUTTON_3) { 0164 ret |= Qt::RightButton; 0165 } 0166 if (state & XCB_KEY_BUT_MASK_BUTTON_4) { 0167 ret |= Qt::XButton1; 0168 } 0169 if (state & XCB_KEY_BUT_MASK_BUTTON_5) { 0170 ret |= Qt::XButton2; 0171 } 0172 return ret; 0173 } 0174 0175 Qt::KeyboardModifiers x11ToQtKeyboardModifiers(int state) 0176 { 0177 Qt::KeyboardModifiers ret = {}; 0178 if (state & XCB_KEY_BUT_MASK_SHIFT) { 0179 ret |= Qt::ShiftModifier; 0180 } 0181 if (state & XCB_KEY_BUT_MASK_CONTROL) { 0182 ret |= Qt::ControlModifier; 0183 } 0184 if (state & KKeyServer::modXAlt()) { 0185 ret |= Qt::AltModifier; 0186 } 0187 if (state & KKeyServer::modXMeta()) { 0188 ret |= Qt::MetaModifier; 0189 } 0190 return ret; 0191 } 0192 0193 QPointF popupOffset(const QRectF &anchorRect, const Qt::Edges anchorEdge, const Qt::Edges gravity, const QSizeF popupSize) 0194 { 0195 QPointF anchorPoint; 0196 switch (anchorEdge & (Qt::LeftEdge | Qt::RightEdge)) { 0197 case Qt::LeftEdge: 0198 anchorPoint.setX(anchorRect.x()); 0199 break; 0200 case Qt::RightEdge: 0201 anchorPoint.setX(anchorRect.x() + anchorRect.width()); 0202 break; 0203 default: 0204 anchorPoint.setX(qRound(anchorRect.x() + anchorRect.width() / 2.0)); 0205 } 0206 switch (anchorEdge & (Qt::TopEdge | Qt::BottomEdge)) { 0207 case Qt::TopEdge: 0208 anchorPoint.setY(anchorRect.y()); 0209 break; 0210 case Qt::BottomEdge: 0211 anchorPoint.setY(anchorRect.y() + anchorRect.height()); 0212 break; 0213 default: 0214 anchorPoint.setY(qRound(anchorRect.y() + anchorRect.height() / 2.0)); 0215 } 0216 0217 // calculate where the top left point of the popup will end up with the applied gravity 0218 // gravity indicates direction. i.e if gravitating towards the top the popup's bottom edge 0219 // will next to the anchor point 0220 QPointF popupPosAdjust; 0221 switch (gravity & (Qt::LeftEdge | Qt::RightEdge)) { 0222 case Qt::LeftEdge: 0223 popupPosAdjust.setX(-popupSize.width()); 0224 break; 0225 case Qt::RightEdge: 0226 popupPosAdjust.setX(0); 0227 break; 0228 default: 0229 popupPosAdjust.setX(qRound(-popupSize.width() / 2.0)); 0230 } 0231 switch (gravity & (Qt::TopEdge | Qt::BottomEdge)) { 0232 case Qt::TopEdge: 0233 popupPosAdjust.setY(-popupSize.height()); 0234 break; 0235 case Qt::BottomEdge: 0236 popupPosAdjust.setY(0); 0237 break; 0238 default: 0239 popupPosAdjust.setY(qRound(-popupSize.height() / 2.0)); 0240 } 0241 0242 return anchorPoint + popupPosAdjust; 0243 } 0244 0245 QRectF gravitateGeometry(const QRectF &rect, const QRectF &bounds, Gravity gravity) 0246 { 0247 QRectF geometry = rect; 0248 0249 switch (gravity) { 0250 case Gravity::TopLeft: 0251 geometry.moveRight(bounds.right()); 0252 geometry.moveBottom(bounds.bottom()); 0253 break; 0254 case Gravity::Top: 0255 case Gravity::TopRight: 0256 geometry.moveLeft(bounds.left()); 0257 geometry.moveBottom(bounds.bottom()); 0258 break; 0259 case Gravity::Right: 0260 case Gravity::BottomRight: 0261 case Gravity::Bottom: 0262 case Gravity::None: 0263 geometry.moveLeft(bounds.left()); 0264 geometry.moveTop(bounds.top()); 0265 break; 0266 case Gravity::BottomLeft: 0267 case Gravity::Left: 0268 geometry.moveRight(bounds.right()); 0269 geometry.moveTop(bounds.top()); 0270 break; 0271 } 0272 0273 return geometry; 0274 } 0275 0276 } // namespace 0277 0278 #ifndef KCMRULES 0279 #endif