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