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 | } |