Changeset View
Changeset View
Standalone View
Standalone View
src/Platforms/PlatformXcb.cpp
| Show First 20 Lines • Show All 56 Lines • ▼ Show 20 Line(s) | 55 | { | |||
|---|---|---|---|---|---|
| 57 | { | 57 | { | ||
| 58 | if (theXcbImage) { | 58 | if (theXcbImage) { | ||
| 59 | xcb_image_destroy(theXcbImage); | 59 | xcb_image_destroy(theXcbImage); | ||
| 60 | } | 60 | } | ||
| 61 | } | 61 | } | ||
| 62 | }; | 62 | }; | ||
| 63 | using XcbImagePtr = std::unique_ptr<xcb_image_t, XcbImagePtrDeleter>; | 63 | using XcbImagePtr = std::unique_ptr<xcb_image_t, XcbImagePtrDeleter>; | ||
| 64 | 64 | | |||
| 65 | struct CFreeDeleter | ||||
| 66 | { | ||||
| 67 | void operator()(void *ptr) const | ||||
| 68 | { | ||||
| 69 | free(ptr); | ||||
| 70 | } | ||||
| 71 | }; | ||||
| 72 | template<typename Reply> | ||||
| 73 | using XcbReplyPtr = std::unique_ptr<Reply, CFreeDeleter>; | ||||
| 74 | | ||||
| 65 | /* -- On Click Native Event Filter ------------------------------------------------------------- */ | 75 | /* -- On Click Native Event Filter ------------------------------------------------------------- */ | ||
| 66 | 76 | | |||
| 67 | class PlatformXcb::OnClickEventFilter: public QAbstractNativeEventFilter | 77 | class PlatformXcb::OnClickEventFilter: public QAbstractNativeEventFilter | ||
| 68 | { | 78 | { | ||
| 69 | public: | 79 | public: | ||
| 70 | 80 | | |||
| 71 | explicit OnClickEventFilter(PlatformXcb *thePlatformPtr) : | 81 | explicit OnClickEventFilter(PlatformXcb *thePlatformPtr) : | ||
| 72 | mPlatformPtr(thePlatformPtr) | 82 | mPlatformPtr(thePlatformPtr) | ||
| ▲ Show 20 Lines • Show All 113 Lines • ▼ Show 20 Line(s) | |||||
| 186 | QPoint PlatformXcb::getCursorPosition() | 196 | QPoint PlatformXcb::getCursorPosition() | ||
| 187 | { | 197 | { | ||
| 188 | // QCursor::pos() is not used because it requires additional calculations. | 198 | // QCursor::pos() is not used because it requires additional calculations. | ||
| 189 | // Its value is the offset to the origin of the current screen is in | 199 | // Its value is the offset to the origin of the current screen is in | ||
| 190 | // device-independent pixels while the origin itself uses native pixels. | 200 | // device-independent pixels while the origin itself uses native pixels. | ||
| 191 | 201 | | |||
| 192 | auto lXcbConn = QX11Info::connection(); | 202 | auto lXcbConn = QX11Info::connection(); | ||
| 193 | auto lPointerCookie = xcb_query_pointer_unchecked(lXcbConn, QX11Info::appRootWindow()); | 203 | auto lPointerCookie = xcb_query_pointer_unchecked(lXcbConn, QX11Info::appRootWindow()); | ||
| 194 | std::unique_ptr<xcb_query_pointer_reply_t> lPointerReply(xcb_query_pointer_reply(lXcbConn, lPointerCookie, nullptr)); | 204 | XcbReplyPtr<xcb_query_pointer_reply_t> lPointerReply(xcb_query_pointer_reply(lXcbConn, lPointerCookie, nullptr)); | ||
| 195 | 205 | | |||
| 196 | return QPoint(lPointerReply->root_x, lPointerReply->root_y); | 206 | return QPoint(lPointerReply->root_x, lPointerReply->root_y); | ||
| 197 | } | 207 | } | ||
| 198 | 208 | | |||
| 199 | QRect PlatformXcb::getDrawableGeometry(xcb_drawable_t theDrawable) | 209 | QRect PlatformXcb::getDrawableGeometry(xcb_drawable_t theDrawable) | ||
| 200 | { | 210 | { | ||
| 201 | auto lXcbConn = QX11Info::connection(); | 211 | auto lXcbConn = QX11Info::connection(); | ||
| 202 | auto lGeoCookie = xcb_get_geometry_unchecked(lXcbConn, theDrawable); | 212 | auto lGeoCookie = xcb_get_geometry_unchecked(lXcbConn, theDrawable); | ||
| 203 | std::unique_ptr<xcb_get_geometry_reply_t> lGeoReply(xcb_get_geometry_reply(lXcbConn, lGeoCookie, nullptr)); | 213 | XcbReplyPtr<xcb_get_geometry_reply_t> lGeoReply(xcb_get_geometry_reply(lXcbConn, lGeoCookie, nullptr)); | ||
| 204 | if (!lGeoReply) { | 214 | if (!lGeoReply) { | ||
| 205 | return QRect(); | 215 | return QRect(); | ||
| 206 | } | 216 | } | ||
| 207 | return QRect(lGeoReply->x, lGeoReply->y, lGeoReply->width, lGeoReply->height); | 217 | return QRect(lGeoReply->x, lGeoReply->y, lGeoReply->width, lGeoReply->height); | ||
| 208 | } | 218 | } | ||
| 209 | 219 | | |||
| 210 | xcb_window_t PlatformXcb::getWindowUnderCursor() | 220 | xcb_window_t PlatformXcb::getWindowUnderCursor() | ||
| 211 | { | 221 | { | ||
| 212 | auto lXcbConn = QX11Info::connection(); | 222 | auto lXcbConn = QX11Info::connection(); | ||
| 213 | auto lAppWin = QX11Info::appRootWindow(); | 223 | auto lAppWin = QX11Info::appRootWindow(); | ||
| 214 | 224 | | |||
| 215 | const QByteArray lAtomName("WM_STATE"); | 225 | const QByteArray lAtomName("WM_STATE"); | ||
| 216 | auto lAtomCookie = xcb_intern_atom_unchecked(lXcbConn, 0, lAtomName.length(), lAtomName.constData()); | 226 | auto lAtomCookie = xcb_intern_atom_unchecked(lXcbConn, 0, lAtomName.length(), lAtomName.constData()); | ||
| 217 | auto lPointerCookie = xcb_query_pointer_unchecked(lXcbConn, lAppWin); | 227 | auto lPointerCookie = xcb_query_pointer_unchecked(lXcbConn, lAppWin); | ||
| 218 | std::unique_ptr<xcb_intern_atom_reply_t> lAtomReply(xcb_intern_atom_reply(lXcbConn, lAtomCookie, nullptr)); | 228 | XcbReplyPtr<xcb_intern_atom_reply_t> lAtomReply(xcb_intern_atom_reply(lXcbConn, lAtomCookie, nullptr)); | ||
| 219 | std::unique_ptr<xcb_query_pointer_reply_t> lPointerReply(xcb_query_pointer_reply(lXcbConn, lPointerCookie, nullptr)); | 229 | XcbReplyPtr<xcb_query_pointer_reply_t> lPointerReply(xcb_query_pointer_reply(lXcbConn, lPointerCookie, nullptr)); | ||
| 220 | 230 | | |||
| 221 | if (lAtomReply->atom == XCB_ATOM_NONE) { | 231 | if (lAtomReply->atom == XCB_ATOM_NONE) { | ||
| 222 | return QX11Info::appRootWindow(); | 232 | return QX11Info::appRootWindow(); | ||
| 223 | } | 233 | } | ||
| 224 | 234 | | |||
| 225 | // now start testing | 235 | // now start testing | ||
| 226 | QStack<xcb_window_t> lWindowStack; | 236 | QStack<xcb_window_t> lWindowStack; | ||
| 227 | lWindowStack.push(lPointerReply->child); | 237 | lWindowStack.push(lPointerReply->child); | ||
| 228 | 238 | | |||
| 229 | while (!lWindowStack.isEmpty()) { | 239 | while (!lWindowStack.isEmpty()) { | ||
| 230 | lAppWin = lWindowStack.pop(); | 240 | lAppWin = lWindowStack.pop(); | ||
| 231 | 241 | | |||
| 232 | // next, check if our window has the WM_STATE property set on | 242 | // next, check if our window has the WM_STATE property set on | ||
| 233 | // the window. if yes, return the window - we have found it | 243 | // the window. if yes, return the window - we have found it | ||
| 234 | auto lPropCookie = xcb_get_property_unchecked(lXcbConn, 0, lAppWin, lAtomReply->atom, XCB_ATOM_ANY, 0, 0); | 244 | auto lPropCookie = xcb_get_property_unchecked(lXcbConn, 0, lAppWin, lAtomReply->atom, XCB_ATOM_ANY, 0, 0); | ||
| 235 | std::unique_ptr<xcb_get_property_reply_t> lPropReply(xcb_get_property_reply(lXcbConn, lPropCookie, nullptr)); | 245 | XcbReplyPtr<xcb_get_property_reply_t> lPropReply(xcb_get_property_reply(lXcbConn, lPropCookie, nullptr)); | ||
| 236 | 246 | | |||
| 237 | if (lPropReply->type != XCB_ATOM_NONE) { | 247 | if (lPropReply->type != XCB_ATOM_NONE) { | ||
| 238 | return lAppWin; | 248 | return lAppWin; | ||
| 239 | } | 249 | } | ||
| 240 | 250 | | |||
| 241 | // if we're here, this means the window is not the real window | 251 | // if we're here, this means the window is not the real window | ||
| 242 | // we should start looking at its children | 252 | // we should start looking at its children | ||
| 243 | auto lTreeCookie = xcb_query_tree_unchecked(lXcbConn, lAppWin); | 253 | auto lTreeCookie = xcb_query_tree_unchecked(lXcbConn, lAppWin); | ||
| 244 | std::unique_ptr<xcb_query_tree_reply_t> lTreeReply(xcb_query_tree_reply(lXcbConn, lTreeCookie, nullptr)); | 254 | XcbReplyPtr<xcb_query_tree_reply_t> lTreeReply(xcb_query_tree_reply(lXcbConn, lTreeCookie, nullptr)); | ||
| 245 | auto lWindowChildren = xcb_query_tree_children(lTreeReply.get()); | 255 | auto lWindowChildren = xcb_query_tree_children(lTreeReply.get()); | ||
| 246 | auto lWindowChildrenLength = xcb_query_tree_children_length(lTreeReply.get()); | 256 | auto lWindowChildrenLength = xcb_query_tree_children_length(lTreeReply.get()); | ||
| 247 | 257 | | |||
| 248 | for (int iIdx = lWindowChildrenLength - 1; iIdx >= 0; iIdx--) { | 258 | for (int iIdx = lWindowChildrenLength - 1; iIdx >= 0; iIdx--) { | ||
| 249 | lWindowStack.push(lWindowChildren[iIdx]); | 259 | lWindowStack.push(lWindowChildren[iIdx]); | ||
| 250 | } | 260 | } | ||
| 251 | } | 261 | } | ||
| 252 | 262 | | |||
| ▲ Show 20 Lines • Show All 73 Lines • ▼ Show 20 Line(s) | 332 | { | |||
| 326 | if (!theRect.contains(lCursorPos)) { | 336 | if (!theRect.contains(lCursorPos)) { | ||
| 327 | return thePixmap; | 337 | return thePixmap; | ||
| 328 | } | 338 | } | ||
| 329 | 339 | | |||
| 330 | // now we can get the image and start processing | 340 | // now we can get the image and start processing | ||
| 331 | auto lXcbConn = QX11Info::connection(); | 341 | auto lXcbConn = QX11Info::connection(); | ||
| 332 | 342 | | |||
| 333 | auto lCursorCookie = xcb_xfixes_get_cursor_image_unchecked(lXcbConn); | 343 | auto lCursorCookie = xcb_xfixes_get_cursor_image_unchecked(lXcbConn); | ||
| 334 | std::unique_ptr<xcb_xfixes_get_cursor_image_reply_t> lCursorReply(xcb_xfixes_get_cursor_image_reply(lXcbConn, lCursorCookie, nullptr)); | 344 | XcbReplyPtr<xcb_xfixes_get_cursor_image_reply_t> lCursorReply(xcb_xfixes_get_cursor_image_reply(lXcbConn, lCursorCookie, nullptr)); | ||
| 335 | if (!lCursorReply) { | 345 | if (!lCursorReply) { | ||
| 336 | return thePixmap; | 346 | return thePixmap; | ||
| 337 | } | 347 | } | ||
| 338 | 348 | | |||
| 339 | // get the image and process it into a qimage | 349 | // get the image and process it into a qimage | ||
| 340 | auto lPixelData = xcb_xfixes_get_cursor_image_cursor_image(lCursorReply.get()); | 350 | auto lPixelData = xcb_xfixes_get_cursor_image_cursor_image(lCursorReply.get()); | ||
| 341 | if (!lPixelData) { | 351 | if (!lPixelData) { | ||
| 342 | return thePixmap; | 352 | return thePixmap; | ||
| ▲ Show 20 Lines • Show All 78 Lines • ▼ Show 20 Line(s) | |||||
| 421 | } | 431 | } | ||
| 422 | 432 | | |||
| 423 | QPixmap PlatformXcb::getWindowPixmap(xcb_window_t theWindow, bool theBlendPointer) | 433 | QPixmap PlatformXcb::getWindowPixmap(xcb_window_t theWindow, bool theBlendPointer) | ||
| 424 | { | 434 | { | ||
| 425 | auto lXcbConn = QX11Info::connection(); | 435 | auto lXcbConn = QX11Info::connection(); | ||
| 426 | 436 | | |||
| 427 | // first get geometry information for our window | 437 | // first get geometry information for our window | ||
| 428 | auto lGeoCookie = xcb_get_geometry_unchecked(lXcbConn, theWindow); | 438 | auto lGeoCookie = xcb_get_geometry_unchecked(lXcbConn, theWindow); | ||
| 429 | std::unique_ptr<xcb_get_geometry_reply_t> lGeoReply(xcb_get_geometry_reply(lXcbConn, lGeoCookie, nullptr)); | 439 | XcbReplyPtr<xcb_get_geometry_reply_t> lGeoReply(xcb_get_geometry_reply(lXcbConn, lGeoCookie, nullptr)); | ||
| 430 | QRect lWindowRect(lGeoReply->x, lGeoReply->y, lGeoReply->width, lGeoReply->height); | 440 | QRect lWindowRect(lGeoReply->x, lGeoReply->y, lGeoReply->width, lGeoReply->height); | ||
| 431 | 441 | | |||
| 432 | // then proceed to get an image | 442 | // then proceed to get an image | ||
| 433 | auto lPixmap = getPixmapFromDrawable(theWindow, lWindowRect); | 443 | auto lPixmap = getPixmapFromDrawable(theWindow, lWindowRect); | ||
| 434 | 444 | | |||
| 435 | // translate window coordinates to global ones. | 445 | // translate window coordinates to global ones. | ||
| 436 | auto lRootGeoCookie = xcb_get_geometry_unchecked(lXcbConn, lGeoReply->root); | 446 | auto lRootGeoCookie = xcb_get_geometry_unchecked(lXcbConn, lGeoReply->root); | ||
| 437 | std::unique_ptr<xcb_get_geometry_reply_t> lRootGeoReply(xcb_get_geometry_reply(lXcbConn, lRootGeoCookie, nullptr)); | 447 | XcbReplyPtr<xcb_get_geometry_reply_t> lRootGeoReply(xcb_get_geometry_reply(lXcbConn, lRootGeoCookie, nullptr)); | ||
| 438 | auto lTranslateCookie = xcb_translate_coordinates_unchecked(lXcbConn, theWindow, lGeoReply->root, lRootGeoReply->x, lRootGeoReply->y); | 448 | auto lTranslateCookie = xcb_translate_coordinates_unchecked(lXcbConn, theWindow, lGeoReply->root, lRootGeoReply->x, lRootGeoReply->y); | ||
| 439 | std::unique_ptr<xcb_translate_coordinates_reply_t> lTranslateReply(xcb_translate_coordinates_reply(lXcbConn, lTranslateCookie, nullptr)); | 449 | XcbReplyPtr<xcb_translate_coordinates_reply_t> lTranslateReply(xcb_translate_coordinates_reply(lXcbConn, lTranslateCookie, nullptr)); | ||
| 440 | 450 | | |||
| 441 | // adjust local to global coordinates. | 451 | // adjust local to global coordinates. | ||
| 442 | lWindowRect.moveRight(lWindowRect.x() + lTranslateReply->dst_x); | 452 | lWindowRect.moveRight(lWindowRect.x() + lTranslateReply->dst_x); | ||
| 443 | lWindowRect.moveTop(lWindowRect.y() + lTranslateReply->dst_y); | 453 | lWindowRect.moveTop(lWindowRect.y() + lTranslateReply->dst_y); | ||
| 444 | 454 | | |||
| 445 | // if the window capture failed, try to obtain one from the full screen. | 455 | // if the window capture failed, try to obtain one from the full screen. | ||
| 446 | if (lPixmap.isNull()) { | 456 | if (lPixmap.isNull()) { | ||
| 447 | return getToplevelPixmap(lWindowRect, theBlendPointer); | 457 | return getToplevelPixmap(lWindowRect, theBlendPointer); | ||
| ▲ Show 20 Lines • Show All 273 Lines • ▼ Show 20 Line(s) | 728 | xcb_grab_pointer_cookie_t grabPointerCookie = xcb_grab_pointer_unchecked( | |||
| 721 | QX11Info::appRootWindow(), // window to grab pointer for (root) | 731 | QX11Info::appRootWindow(), // window to grab pointer for (root) | ||
| 722 | XCB_EVENT_MASK_BUTTON_RELEASE, // which events do I want | 732 | XCB_EVENT_MASK_BUTTON_RELEASE, // which events do I want | ||
| 723 | XCB_GRAB_MODE_SYNC, // pointer grab mode | 733 | XCB_GRAB_MODE_SYNC, // pointer grab mode | ||
| 724 | XCB_GRAB_MODE_ASYNC, // keyboard grab mode (why is this even here) | 734 | XCB_GRAB_MODE_ASYNC, // keyboard grab mode (why is this even here) | ||
| 725 | XCB_NONE, // confine pointer to which window (none) | 735 | XCB_NONE, // confine pointer to which window (none) | ||
| 726 | lXcbCursor, // cursor to change to for the duration of grab | 736 | lXcbCursor, // cursor to change to for the duration of grab | ||
| 727 | XCB_TIME_CURRENT_TIME // do this right now | 737 | XCB_TIME_CURRENT_TIME // do this right now | ||
| 728 | ); | 738 | ); | ||
| 729 | std::unique_ptr<xcb_grab_pointer_reply_t> lGrabPointerReply(xcb_grab_pointer_reply(QX11Info::connection(), grabPointerCookie, nullptr)); | 739 | XcbReplyPtr<xcb_grab_pointer_reply_t> lGrabPointerReply(xcb_grab_pointer_reply(QX11Info::connection(), grabPointerCookie, nullptr)); | ||
| 730 | 740 | | |||
| 731 | // if the grab failed, take the screenshot right away | 741 | // if the grab failed, take the screenshot right away | ||
| 732 | if (lGrabPointerReply->status != XCB_GRAB_STATUS_SUCCESS) { | 742 | if (lGrabPointerReply->status != XCB_GRAB_STATUS_SUCCESS) { | ||
| 733 | doGrabNow(theGrabMode, theIncludePointer, theIncludeDecorations); | 743 | doGrabNow(theGrabMode, theIncludePointer, theIncludeDecorations); | ||
| 734 | return; | 744 | return; | ||
| 735 | } | 745 | } | ||
| 736 | 746 | | |||
| 737 | // fix things if our pointer grab causes a lockup and install our event filter | 747 | // fix things if our pointer grab causes a lockup and install our event filter | ||
| 738 | mNativeEventFilter->setCaptureOptions(theGrabMode, theIncludePointer, theIncludeDecorations); | 748 | mNativeEventFilter->setCaptureOptions(theGrabMode, theIncludePointer, theIncludeDecorations); | ||
| 739 | xcb_allow_events(QX11Info::connection(), XCB_ALLOW_SYNC_POINTER, XCB_TIME_CURRENT_TIME); | 749 | xcb_allow_events(QX11Info::connection(), XCB_ALLOW_SYNC_POINTER, XCB_TIME_CURRENT_TIME); | ||
| 740 | qApp->installNativeEventFilter(mNativeEventFilter); | 750 | qApp->installNativeEventFilter(mNativeEventFilter); | ||
| 741 | 751 | | |||
| 742 | // done. clean stuff up | 752 | // done. clean stuff up | ||
| 743 | xcb_cursor_context_free(lXcbCursorCtx); | 753 | xcb_cursor_context_free(lXcbCursorCtx); | ||
| 744 | xcb_free_cursor(QX11Info::connection(), lXcbCursor); | 754 | xcb_free_cursor(QX11Info::connection(), lXcbCursor); | ||
| 745 | } | 755 | } | ||