예제 #1
0
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;
}
예제 #2
0
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;
}
예제 #3
0
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;
}
예제 #4
0
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;
}
예제 #5
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;
    }
예제 #6
0
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;
}
예제 #7
0
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();
}
예제 #8
0
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);
    }
}
예제 #9
0
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;
}
예제 #10
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 );
}