static QPixmap grabWindow( HWND hWnd, QString *title=0, QString *windowClass=0 ) { RECT windowRect; GetWindowRect(hWnd, &windowRect); int w = windowRect.right - windowRect.left; int h = windowRect.bottom - windowRect.top; HDC targetDC = GetWindowDC(hWnd); HDC hDC = CreateCompatibleDC(targetDC); HBITMAP tempPict = CreateCompatibleBitmap(targetDC, w, h); HGDIOBJ oldPict = SelectObject(hDC, tempPict); BitBlt(hDC, 0, 0, w, h, targetDC, 0, 0, SRCCOPY); tempPict = (HBITMAP) SelectObject(hDC, oldPict); QPixmap pm = QPixmap::fromWinHBITMAP(tempPict); DeleteDC(hDC); ReleaseDC(hWnd, targetDC); KWindowInfo winInfo( findRealWindow(hWnd), NET::WMVisibleName, NET::WM2WindowClass ); if ( title ) { (*title) = winInfo.visibleName(); } if ( windowClass ) { (*windowClass) = winInfo.windowClassName(); } return pm; }
static Window windowUnderCursor( bool includeDecorations = true ) { Window root; Window child; uint mask; int rootX, rootY, winX, winY; XGrabServer( QX11Info::display() ); XQueryPointer( QX11Info::display(), QX11Info::appRootWindow(), &root, &child, &rootX, &rootY, &winX, &winY, &mask ); if( child == None ) { child = QX11Info::appRootWindow(); } if( !includeDecorations ) { Window real_child = findRealWindow( child ); if( real_child != None ) { // test just in case child = real_child; } } return child; }
static Window findRealWindow( Window w, int depth = 0 ) { if( depth > 5 ) return None; static Atom wm_state = XInternAtom( qt_xdisplay(), "WM_STATE", False ); Atom type; int format; unsigned long nitems, after; unsigned char* prop; if( XGetWindowProperty( qt_xdisplay(), w, wm_state, 0, 0, False, AnyPropertyType, &type, &format, &nitems, &after, &prop ) == Success ) { if( prop != NULL ) XFree( prop ); if( type != None ) return w; } Window root, parent; Window* children; unsigned int nchildren; Window ret = None; if( XQueryTree( qt_xdisplay(), w, &root, &parent, &children, &nchildren ) != 0 ) { for( unsigned int i = 0; i < nchildren && ret == None; ++i ) ret = findRealWindow( children[ i ], depth + 1 ); if( children != NULL ) XFree( children ); } return ret; }
static Window findRealWindow( const QPoint & pos, Window w, int md ) { if ( qt_xdnd_deco && w == qt_xdnd_deco->winId() ) return 0; if ( md ) { XWindowAttributes attr; XGetWindowAttributes( qt_xdisplay(), w, &attr ); if ( attr.map_state != IsUnmapped && QRect(attr.x,attr.y,attr.width,attr.height) .contains(pos) ) { { Atom type = None; int f; unsigned long n, a; unsigned char *data; XGetWindowProperty( qt_xdisplay(), w, qt_wm_state, 0, 0, False, AnyPropertyType, &type, &f,&n,&a,&data ); if ( data ) XFree(data); if ( type ) return w; } Window r, p; Window* c; uint nc; if ( XQueryTree( qt_xdisplay(), w, &r, &p, &c, &nc ) ) { r=0; for (uint i=nc; !r && i--; ) { r = findRealWindow( pos-QPoint(attr.x,attr.y), c[i], md-1 ); } XFree((void*)c); if ( r ) return r; // We didn't find a client window! Just use the // innermost window. } // No children! return w; } } return 0; }
bool WindowSelector::x11Event( XEvent* e ) { if( e->type != ButtonPress ) return false; kapp->desktop()->releaseMouse(); if( e->xbutton.button == Button1 ) { WId window = findRealWindow( e->xbutton.subwindow ); if( window ) selected_signal( window ); } delete this; return true; }
static QPixmap grabWindow( Window child, int x, int y, uint w, uint h, uint border, QString *title=0, QString *windowClass=0 ) { QPixmap pm( QPixmap::grabWindow( QX11Info::appRootWindow(), x, y, w, h ) ); KWindowInfo winInfo( findRealWindow(child), NET::WMVisibleName, NET::WM2WindowClass ); if ( title ) { (*title) = winInfo.visibleName(); } if ( windowClass ) { (*windowClass) = winInfo.windowClassName(); } #ifdef HAVE_X11_EXTENSIONS_SHAPE_H int tmp1, tmp2; //Check whether the extension is available if ( XShapeQueryExtension( QX11Info::display(), &tmp1, &tmp2 ) ) { QBitmap mask( w, h ); //As the first step, get the mask from XShape. int count, order; XRectangle* rects = XShapeGetRectangles( QX11Info::display(), child, ShapeBounding, &count, &order ); //The ShapeBounding region is the outermost shape of the window; //ShapeBounding - ShapeClipping is defined to be the border. //Since the border area is part of the window, we use bounding // to limit our work region if (rects) { //Create a QRegion from the rectangles describing the bounding mask. QRegion contents; for ( int pos = 0; pos < count; pos++ ) contents += QRegion( rects[pos].x, rects[pos].y, rects[pos].width, rects[pos].height ); XFree( rects ); //Create the bounding box. QRegion bbox( 0, 0, w, h ); if( border > 0 ) { contents.translate( border, border ); contents += QRegion( 0, 0, border, h ); contents += QRegion( 0, 0, w, border ); contents += QRegion( 0, h - border, w, border ); contents += QRegion( w - border, 0, border, h ); } //Get the masked away area. QRegion maskedAway = bbox - contents; QVector<QRect> maskedAwayRects = maskedAway.rects(); //Construct a bitmap mask from the rectangles QPainter p(&mask); p.fillRect(0, 0, w, h, Qt::color1); for (int pos = 0; pos < maskedAwayRects.count(); pos++) p.fillRect(maskedAwayRects[pos], Qt::color0); p.end(); pm.setMask(mask); } } #endif // HAVE_X11_EXTENSIONS_SHAPE_H return pm; }
void KSnapshot::performGrab() { grabber->releaseMouse(); grabber->hide(); grabTimer.stop(); XGrabServer( qt_xdisplay()); if ( mainWidget->mode() == WindowUnderCursor ) { Window root; Window child; uint mask; int rootX, rootY, winX, winY; XQueryPointer( qt_xdisplay(), qt_xrootwin(), &root, &child, &rootX, &rootY, &winX, &winY, &mask); if( child == None ) child = qt_xrootwin(); if( !mainWidget->includeDecorations()) { Window real_child = findRealWindow( child ); if( real_child != None ) // test just in case child = real_child; } int x, y; unsigned int w, h; unsigned int border; unsigned int depth; XGetGeometry( qt_xdisplay(), child, &root, &x, &y, &w, &h, &border, &depth ); w += 2 * border; h += 2 * border; Window parent; Window* children; unsigned int nchildren; if( XQueryTree( qt_xdisplay(), child, &root, &parent, &children, &nchildren ) != 0 ) { if( children != NULL ) XFree( children ); int newx, newy; Window dummy; if( XTranslateCoordinates( qt_xdisplay(), parent, qt_xrootwin(), x, y, &newx, &newy, &dummy )) { x = newx; y = newy; } } snapshot = QPixmap::grabWindow( qt_xrootwin(), x, y, w, h ); #ifdef HAVE_X11_EXTENSIONS_SHAPE_H //No XShape - no work. if (haveXShape) { QBitmap mask(w, h); //As the first step, get the mask from XShape. int count, order; XRectangle* rects = XShapeGetRectangles( qt_xdisplay(), child, ShapeBounding, &count, &order); //The ShapeBounding region is the outermost shape of the window; //ShapeBounding - ShapeClipping is defined to be the border. //Since the border area is part of the window, we use bounding // to limit our work region if (rects) { //Create a QRegion from the rectangles describing the bounding mask. QRegion contents; for (int pos = 0; pos < count; pos++) contents += QRegion(rects[pos].x, rects[pos].y, rects[pos].width, rects[pos].height); XFree(rects); //Create the bounding box. QRegion bbox(0, 0, snapshot.width(), snapshot.height()); if( border > 0 ) { contents.translate( border, border ); contents += QRegion( 0, 0, border, h ); contents += QRegion( 0, 0, w, border ); contents += QRegion( 0, h - border, w, border ); contents += QRegion( w - border, 0, border, h ); } //Get the masked away area. QRegion maskedAway = bbox - contents; QMemArray<QRect> maskedAwayRects = maskedAway.rects(); //Construct a bitmap mask from the rectangles QPainter p(&mask); p.fillRect(0, 0, w, h, Qt::color1); for (uint pos = 0; pos < maskedAwayRects.count(); pos++) p.fillRect(maskedAwayRects[pos], Qt::color0); p.end(); snapshot.setMask(mask); } } #endif } else { snapshot = QPixmap::grabWindow( qt_xrootwin() ); } XUngrabServer( qt_xdisplay()); updatePreview(); QApplication::restoreOverrideCursor(); modified = true; // show(); slotOk(); }
void QXcbDrag::move(const QMouseEvent *me) { // The mouse event is in the coordinate system of the window that started the drag. // We do not know which window that was at this point, so we just use the device pixel ratio // of the QGuiApplication. This will break once we support screens with different DPR. Fixing // this properly requires some redesign of the drag and drop architecture. static const int dpr = int(qApp->devicePixelRatio()); QBasicDrag::move(me); QPoint globalPos = me->globalPos(); if (source_sameanswer.contains(globalPos) && source_sameanswer.isValid()) return; const QList<QXcbScreen *> &screens = connection()->screens(); QXcbScreen *screen = connection()->primaryScreen(); for (int i = 0; i < screens.size(); ++i) { if (screens.at(i)->geometry().contains(globalPos)) { screen = screens.at(i); break; } } if (screen != current_screen) { // ### need to recreate the shaped pixmap window? // int screen = QCursor::x11Screen(); // if ((qt_xdnd_current_screen == -1 && screen != X11->defaultScreen) || (screen != qt_xdnd_current_screen)) { // // recreate the pixmap on the new screen... // delete xdnd_data.deco; // QWidget* parent = object->source()->window()->x11Info().screen() == screen // ? object->source()->window() : QApplication::desktop()->screen(screen); // xdnd_data.deco = new QShapedPixmapWidget(parent); // if (!QWidget::mouseGrabber()) { // updatePixmap(); // xdnd_data.deco->grabMouse(); // } // } // xdnd_data.deco->move(QCursor::pos() - xdnd_data.deco->pm_hot); current_screen = screen; } // qt_xdnd_current_screen = screen; xcb_window_t rootwin = current_screen->root(); xcb_translate_coordinates_reply_t *translate = ::translateCoordinates(connection(), rootwin, rootwin, globalPos.x() * dpr, globalPos.y() * dpr); if (!translate) return; xcb_window_t target = translate->child; int lx = translate->dst_x; int ly = translate->dst_y; free (translate); if (target && target != rootwin) { xcb_window_t src = rootwin; while (target != 0) { DNDDEBUG << "checking target for XdndAware" << target << lx << ly; // translate coordinates translate = ::translateCoordinates(connection(), src, target, lx, ly); if (!translate) { target = 0; break; } lx = translate->dst_x; ly = translate->dst_y; src = target; xcb_window_t child = translate->child; free(translate); // check if it has XdndAware xcb_get_property_cookie_t cookie = Q_XCB_CALL(xcb_get_property(xcb_connection(), false, target, atom(QXcbAtom::XdndAware), XCB_GET_PROPERTY_TYPE_ANY, 0, 0)); xcb_get_property_reply_t *reply = xcb_get_property_reply(xcb_connection(), cookie, 0); bool aware = reply && reply->type != XCB_NONE; free(reply); if (aware) { DNDDEBUG << "Found XdndAware on " << target; break; } target = child; } if (!target || target == shapedPixmapWindow()->handle()->winId()) { DNDDEBUG << "need to find real window"; target = findRealWindow(globalPos, rootwin, 6, true); if (target == 0) target = findRealWindow(globalPos, rootwin, 6, false); DNDDEBUG << "real window found" << target; } } QXcbWindow *w = 0; if (target) { w = connection()->platformWindowFromId(target); if (w && (w->window()->type() == Qt::Desktop) /*&& !w->acceptDrops()*/) w = 0; } else { w = 0; target = rootwin; } xcb_window_t proxy_target = xdndProxy(connection(), target); if (!proxy_target) proxy_target = target; int target_version = 1; if (proxy_target) { xcb_get_property_cookie_t cookie = xcb_get_property(xcb_connection(), false, proxy_target, atom(QXcbAtom::XdndAware), XCB_GET_PROPERTY_TYPE_ANY, 0, 1); xcb_get_property_reply_t *reply = xcb_get_property_reply(xcb_connection(), cookie, 0); if (!reply || reply->type == XCB_NONE) target = 0; target_version = *(uint32_t *)xcb_get_property_value(reply); target_version = qMin(xdnd_version, target_version ? target_version : 1); free(reply); } if (target != current_target) { if (current_target) send_leave(); current_target = target; current_proxy_target = proxy_target; if (target) { int flags = target_version << 24; if (drag_types.size() > 3) flags |= 0x0001; xcb_client_message_event_t enter; enter.response_type = XCB_CLIENT_MESSAGE; enter.window = target; enter.format = 32; enter.type = atom(QXcbAtom::XdndEnter); enter.data.data32[0] = connection()->clipboard()->owner(); enter.data.data32[1] = flags; enter.data.data32[2] = drag_types.size()>0 ? drag_types.at(0) : 0; enter.data.data32[3] = drag_types.size()>1 ? drag_types.at(1) : 0; enter.data.data32[4] = drag_types.size()>2 ? drag_types.at(2) : 0; // provisionally set the rectangle to 5x5 pixels... source_sameanswer = QRect(globalPos.x() - 2, globalPos.y() -2 , 5, 5); DEBUG() << "sending Xdnd enter source=" << enter.data.data32[0]; if (w) handleEnter(w->window(), &enter); else if (target) xcb_send_event(xcb_connection(), false, proxy_target, XCB_EVENT_MASK_NO_EVENT, (const char *)&enter); waiting_for_status = false; } } if (waiting_for_status) return; if (target) { waiting_for_status = true; xcb_client_message_event_t move; move.response_type = XCB_CLIENT_MESSAGE; move.window = target; move.format = 32; move.type = atom(QXcbAtom::XdndPosition); move.data.data32[0] = connection()->clipboard()->owner(); move.data.data32[1] = 0; // flags move.data.data32[2] = (globalPos.x() * dpr << 16) + globalPos.y() * dpr; move.data.data32[3] = connection()->time(); move.data.data32[4] = toXdndAction(defaultAction(currentDrag()->supportedActions(), QGuiApplication::keyboardModifiers())); DEBUG() << "sending Xdnd position source=" << move.data.data32[0] << "target=" << move.window; source_time = connection()->time(); if (w) handle_xdnd_position(w->window(), &move); else xcb_send_event(xcb_connection(), false, proxy_target, XCB_EVENT_MASK_NO_EVENT, (const char *)&move); } }
xcb_window_t QXcbDrag::findRealWindow(const QPoint & pos, xcb_window_t w, int md, bool ignoreNonXdndAwareWindows) { if (w == shapedPixmapWindow()->handle()->winId()) return 0; if (md) { xcb_get_window_attributes_cookie_t cookie = xcb_get_window_attributes(xcb_connection(), w); xcb_get_window_attributes_reply_t *reply = xcb_get_window_attributes_reply(xcb_connection(), cookie, 0); if (!reply) return 0; if (reply->map_state != XCB_MAP_STATE_VIEWABLE) return 0; free(reply); xcb_get_geometry_cookie_t gcookie = xcb_get_geometry(xcb_connection(), w); xcb_get_geometry_reply_t *greply = xcb_get_geometry_reply(xcb_connection(), gcookie, 0); if (!greply) return 0; QRect windowRect(greply->x, greply->y, greply->width, greply->height); free(greply); if (windowRect.contains(pos)) { bool windowContainsMouse = !ignoreNonXdndAwareWindows; { xcb_get_property_cookie_t cookie = Q_XCB_CALL(xcb_get_property(xcb_connection(), false, w, connection()->atom(QXcbAtom::XdndAware), XCB_GET_PROPERTY_TYPE_ANY, 0, 0)); xcb_get_property_reply_t *reply = xcb_get_property_reply(xcb_connection(), cookie, 0); bool isAware = reply && reply->type != XCB_NONE; free(reply); if (isAware) { const QPoint relPos = pos - windowRect.topLeft(); // When ShapeInput and ShapeBounding are not set they return a single rectangle with the geometry of the window, this is why we // need to check both here so that in the case one is set and the other is not we still get the correct result. if (connection()->hasInputShape()) windowContainsMouse = windowInteractsWithPosition(xcb_connection(), relPos, w, XCB_SHAPE_SK_INPUT); if (windowContainsMouse && connection()->hasXShape()) windowContainsMouse = windowInteractsWithPosition(xcb_connection(), relPos, w, XCB_SHAPE_SK_BOUNDING); if (!connection()->hasInputShape() && !connection()->hasXShape()) windowContainsMouse = true; if (windowContainsMouse) return w; } } xcb_query_tree_cookie_t cookie = xcb_query_tree (xcb_connection(), w); xcb_query_tree_reply_t *reply = xcb_query_tree_reply(xcb_connection(), cookie, 0); if (!reply) return 0; int nc = xcb_query_tree_children_length(reply); xcb_window_t *c = xcb_query_tree_children(reply); xcb_window_t r = 0; for (uint i = nc; !r && i--;) r = findRealWindow(pos - windowRect.topLeft(), c[i], md-1, ignoreNonXdndAwareWindows); free(reply); if (r) return r; // We didn't find a client window! Just use the // innermost window. // No children! if (!windowContainsMouse) return 0; else return w; } } return 0; }
void QDragManager::move( const QPoint & globalPos ) { if ( qt_xdnd_source_sameanswer.contains( globalPos ) && qt_xdnd_source_sameanswer.isValid() && !qt_xdnd_source_sameanswer.isEmpty() ) { // ### probably unnecessary return; } if ( qt_xdnd_deco ) { qt_xdnd_deco->move(globalPos-qt_xdnd_source_object->pixmapHotSpot()); qt_xdnd_deco->raise(); } Window target = 0; int lx = 0, ly = 0; if ( !XTranslateCoordinates( qt_xdisplay(), qt_xrootwin(), qt_xrootwin(), globalPos.x(), globalPos.y(), &lx, &ly, &target) ) { // somehow got to a different screen? ignore for now return; } if ( target == qt_xrootwin() ) { // Ok. } else if ( target ) { target = qt_x11_findClientWindow( target, qt_wm_state, TRUE ); if ( qt_xdnd_deco && !target || target == qt_xdnd_deco->winId() ) { target = findRealWindow(globalPos,qt_xrootwin(),6); } } if ( target == 0 ) target = qt_xrootwin(); QWidget * w = QWidget::find( (WId)target ); int emask = NoEventMask; if ( w && w->isDesktop() && !w->acceptDrops() ) { emask = EnterWindowMask; w = 0; } if ( target != qt_xdnd_current_target ) { if ( qt_xdnd_current_target ) qt_xdnd_send_leave(); Atom * type[3]={0,0,0}; const char* fmt; int nfmt=0; for (nfmt=0; nfmt<3 && (fmt=object->format(nfmt)); nfmt++) type[nfmt] = qt_xdnd_str_to_atom( fmt ); XClientMessageEvent enter; enter.type = ClientMessage; enter.window = target; enter.format = 32; enter.message_type = qt_xdnd_enter; enter.data.l[0] = object->source()->winId(); enter.data.l[1] = 1 << 24; // flags enter.data.l[2] = type[0] ? *type[0] : 0; // ### enter.data.l[3] = type[1] ? *type[1] : 0; enter.data.l[4] = type[2] ? *type[2] : 0; qt_xdnd_current_target = target; // provisionally set the rectangle to 5x5 pixels... qt_xdnd_source_sameanswer = QRect( globalPos.x() - 2, globalPos.y() -2 , 5, 5 ); if ( w ) { qt_handle_xdnd_enter( w, (const XEvent *)&enter ); } else { XSendEvent( qt_xdisplay(), target, FALSE, emask, (XEvent*)&enter ); } } XClientMessageEvent move; move.type = ClientMessage; move.window = target; move.format = 32; move.message_type = qt_xdnd_position; move.window = target; move.data.l[0] = object->source()->winId(); move.data.l[1] = 0; // flags move.data.l[2] = (globalPos.x() << 16) + globalPos.y(); move.data.l[3] = qt_x_clipboardtime; move.data.l[4] = qt_xdnd_action_copy; if ( w ) qt_handle_xdnd_position( w, (const XEvent *)&move ); else XSendEvent( qt_xdisplay(), target, FALSE, emask, (XEvent*)&move ); }