예제 #1
0
void QXcbWindowSurface::flush(QWidget *widget, const QRegion &region, const QPoint &offset)
{
    QRect bounds = region.boundingRect();

    if (size().isEmpty() || !geometry().contains(bounds))
        return;

    Q_XCB_NOOP(connection());

    QXcbWindow *window = static_cast<QXcbWindow *>(widget->window()->platformWindow());

    extern QWidgetData* qt_widget_data(QWidget *);
    QPoint widgetOffset = qt_qwidget_data(widget)->wrect.topLeft();

    QVector<QRect> rects = region.rects();
    for (int i = 0; i < rects.size(); ++i)
        m_image->put(window->window(), rects.at(i).topLeft() - widgetOffset, rects.at(i).translated(offset));

    Q_XCB_NOOP(connection());

    if (m_syncingResize) {
        xcb_flush(xcb_connection());
        connection()->sync();
        m_syncingResize = false;
        window->updateSyncRequestCounter();
    }
}
예제 #2
0
void QXcbBackingStore::flush(QWindow *window, const QRegion &region, const QPoint &offset)
{
    if (!m_image || m_image->size().isEmpty())
        return;

    QSize imageSize = m_image->size();

    QRegion clipped = region;
    clipped &= QRect(0, 0, window->width(), window->height());
    clipped &= QRect(0, 0, imageSize.width(), imageSize.height()).translated(-offset);

    QRect bounds = clipped.boundingRect();

    if (bounds.isNull())
        return;

    Q_XCB_NOOP(connection());

    QXcbWindow *platformWindow = static_cast<QXcbWindow *>(window->handle());

    QVector<QRect> rects = clipped.rects();
    for (int i = 0; i < rects.size(); ++i)
        m_image->put(platformWindow->xcb_window(), rects.at(i).topLeft(), rects.at(i).translated(offset));

    Q_XCB_NOOP(connection());

    if (m_syncingResize) {
        xcb_flush(xcb_connection());
        connection()->sync();
        m_syncingResize = false;
        platformWindow->updateSyncRequestCounter();
    }
}
예제 #3
0
void QXcbCursor::changeCursor(QCursor *cursor, QWindow *widget)
{
    QXcbWindow *w = 0;
    if (widget && widget->handle())
        w = static_cast<QXcbWindow *>(widget->handle());
    else
        // No X11 cursor control when there is no widget under the cursor
        return;

    xcb_cursor_t c = XCB_CURSOR_NONE;
    bool isBitmapCursor = false;

    if (cursor) {
        const Qt::CursorShape shape = cursor->shape();
        isBitmapCursor = shape == Qt::BitmapCursor;

        if (!isBitmapCursor) {
            const QXcbCursorCacheKey key(*cursor);
            CursorHash::iterator it = m_cursorHash.find(key);
            if (it == m_cursorHash.end()) {
                it = m_cursorHash.insert(key, createFontCursor(shape));
            }
            c = it.value();
        } else {
            // Do not cache bitmap cursors, as otherwise they have unclear
            // lifetime (we effectively leak xcb_cursor_t).
            c = createBitmapCursor(cursor);
        }
    }

    w->setCursor(c, isBitmapCursor);
}
예제 #4
0
void QXcbDrag::drop(const QMouseEvent *event)
{
    QBasicDrag::drop(event);

    if (!current_target)
        return;

    xcb_client_message_event_t drop;
    drop.response_type = XCB_CLIENT_MESSAGE;
    drop.window = current_target;
    drop.format = 32;
    drop.type = atom(QXcbAtom::XdndDrop);
    drop.data.data32[0] = connection()->clipboard()->owner();
    drop.data.data32[1] = 0; // flags
    drop.data.data32[2] = connection()->time();

    drop.data.data32[3] = 0;
    drop.data.data32[4] = currentDrag()->supportedActions();

    QXcbWindow *w = connection()->platformWindowFromId(current_proxy_target);

    if (w && (w->window()->type() == Qt::Desktop) /*&& !w->acceptDrops()*/)
        w = 0;

    Transaction t = {
        connection()->time(),
        current_target,
        current_proxy_target,
        (w ? w->window() : 0),
//        current_embeddig_widget,
        currentDrag(),
        QTime::currentTime()
    };
    transactions.append(t);

    // timer is needed only for drops that came from other processes.
    if (!t.targetWindow && cleanup_timer == -1) {
        cleanup_timer = startTimer(XdndDropTransactionTimeout);
    }

    if (w) {
        handleDrop(w->window(), &drop);
    } else {
        xcb_send_event(xcb_connection(), false, current_proxy_target, XCB_EVENT_MASK_NO_EVENT, (const char *)&drop);
    }

    current_target = 0;
    current_proxy_target = 0;
    source_time = 0;
//    current_embedding_widget = 0;
}
예제 #5
0
void QXcbWindowSurface::resize(const QSize &size)
{
    if (size == QWindowSurface::size())
        return;

    Q_XCB_NOOP(connection());
    QWindowSurface::resize(size);

    QXcbScreen *screen = static_cast<QXcbScreen *>(QPlatformScreen::platformScreenForWidget(window()));
    QXcbWindow* win = static_cast<QXcbWindow *>(window()->platformWindow());

    delete m_image;
    m_image = new QXcbShmImage(screen, size, win->depth(), win->format());
    Q_XCB_NOOP(connection());

    m_syncingResize = true;
}
예제 #6
0
QPlatformWindow *QXcbIntegration::createPlatformWindow(QWindow *window) const
{
    QXcbScreen *screen = static_cast<QXcbScreen *>(window->screen()->handle());
    QXcbGlIntegration *glIntegration = screen->connection()->glIntegration();
    if (window->type() != Qt::Desktop) {
        if (glIntegration) {
            QXcbWindow *xcbWindow = glIntegration->createWindow(window);
            xcbWindow->create();
            return xcbWindow;
        }
    }

    Q_ASSERT(window->type() == Qt::Desktop || !window->supportsOpenGL()
             || (!glIntegration && window->surfaceType() == QSurface::RasterGLSurface)); // for VNC
    QXcbWindow *xcbWindow = new QXcbWindow(window);
    xcbWindow->create();
    return xcbWindow;
}
예제 #7
0
void QXcbConnection::xi2ReportTabletEvent(const TabletData &tabletData, void *event)
{
    xXIDeviceEvent *ev = reinterpret_cast<xXIDeviceEvent *>(event);
    QXcbWindow *xcbWindow = platformWindowFromId(ev->event);
    if (!xcbWindow)
        return;
    QWindow *window = xcbWindow->window();
    const double scale = 65536.0;
    QPointF local(ev->event_x / scale, ev->event_y / scale);
    QPointF global(ev->root_x / scale, ev->root_y / scale);
    double pressure = 0, rotation = 0;
    int xTilt = 0, yTilt = 0;

    for (QHash<int, TabletData::ValuatorClassInfo>::const_iterator it = tabletData.valuatorInfo.constBegin(),
            ite = tabletData.valuatorInfo.constEnd(); it != ite; ++it) {
        int valuator = it.key();
        const TabletData::ValuatorClassInfo &classInfo(it.value());
        double value;
        if (xi2GetValuatorValueIfSet(event, classInfo.number, &value)) {
            double normalizedValue = (value - classInfo.minVal) / double(classInfo.maxVal - classInfo.minVal);
            switch (valuator) {
            case QXcbAtom::AbsPressure:
                pressure = normalizedValue;
                break;
            case QXcbAtom::AbsTiltX:
                xTilt = value;
                break;
            case QXcbAtom::AbsTiltY:
                yTilt = value;
                break;
            case QXcbAtom::AbsWheel:
                rotation = value / 64.0;
                break;
            default:
                break;
            }
        }
    }

    QWindowSystemInterface::handleTabletEvent(window, tabletData.down, local, global,
                                              QTabletEvent::Stylus, tabletData.pointerType,
                                              pressure, xTilt, yTilt, 0,
                                              rotation, 0, tabletData.serialId);
}
예제 #8
0
void QXcbBackingStore::resize(const QSize &size, const QRegion &)
{
    if (m_image && size == m_image->size())
        return;

    Q_XCB_NOOP(connection());

    QXcbScreen *screen = static_cast<QXcbScreen *>(window()->screen()->handle());
    QPlatformWindow *pw = window()->handle();
    if (!pw) {
        window()->create();
        pw = window()->handle();
    }
    QXcbWindow* win = static_cast<QXcbWindow *>(pw);

    delete m_image;
    m_image = new QXcbShmImage(screen, size, win->depth(), win->imageFormat());
    Q_XCB_NOOP(connection());

    m_syncingResize = true;
}
예제 #9
0
void QXcbCursor::changeCursor(QCursor *cursor, QWindow *widget)
{
    QXcbWindow *w = 0;
    if (widget && widget->handle())
        w = static_cast<QXcbWindow *>(widget->handle());
    else
        // No X11 cursor control when there is no widget under the cursor
        return;

    xcb_cursor_t c = XCB_CURSOR_NONE;
    if (cursor) {
        const QXcbCursorCacheKey key(*cursor);
        CursorHash::iterator it = m_cursorHash.find(key);
        if (it == m_cursorHash.end()) {
            const Qt::CursorShape shape = cursor->shape();
            it = m_cursorHash.insert(key, shape == Qt::BitmapCursor ? createBitmapCursor(cursor) : createFontCursor(shape));
        }
        c = it.value();
    }

    w->setCursor(c);
}
예제 #10
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);
    }
}
예제 #11
0
void QXcbNativeBackingStore::flush(QWindow *window, const QRegion &region, const QPoint &offset)
{
    if (m_pixmap.isNull())
        return;

    QSize pixmapSize = m_pixmap.size();

    QRegion clipped = region;
    clipped &= QRect(QPoint(), QHighDpi::toNativePixels(window->size(), window));
    clipped &= QRect(0, 0, pixmapSize.width(), pixmapSize.height()).translated(-offset);

    QRect br = clipped.boundingRect();
    if (br.isNull())
        return;

    QXcbWindow *platformWindow = static_cast<QXcbWindow *>(window->handle());
    if (!platformWindow) {
        qWarning("QXcbBackingStore::flush: QWindow has no platform window (QTBUG-32681)");
        return;
    }

    Window wid = platformWindow->xcb_window();
    Pixmap pid = qt_x11PixmapHandle(m_pixmap);

    QVector<XRectangle> clipRects = qt_region_to_xrectangles(clipped);

#if QT_CONFIG(xrender)
    if (m_translucentBackground)
    {
        XWindowAttributes attrib;
        XGetWindowAttributes(display(), wid, &attrib);
        XRenderPictFormat *format = XRenderFindVisualFormat(display(), attrib.visual);

        Picture srcPic = qt_x11PictureHandle(m_pixmap);
        Picture dstPic = XRenderCreatePicture(display(), wid, format, 0, 0);

        XRenderSetPictureClipRectangles(display(), dstPic, 0, 0, clipRects.constData(), clipRects.size());

        XRenderComposite(display(), PictOpSrc, srcPic, None, dstPic,
                         br.x() + offset.x(), br.y() + offset.y(),
                         0, 0,
                         br.x(), br.y(),
                         br.width(), br.height());

        XRenderFreePicture(display(), dstPic);
    }
    else
#endif
    {
        GC gc = XCreateGC(display(), wid, 0, Q_NULLPTR);

        if (clipRects.size() != 1)
            XSetClipRectangles(display(), gc, 0, 0, clipRects.data(), clipRects.size(), YXBanded);

        XCopyArea(display(), pid, wid, gc, br.x() + offset.x(), br.y() + offset.y(), br.width(), br.height(), br.x(), br.y());
        XFreeGC(display(), gc);
    }


    if (platformWindow->needsSync()) {
        platformWindow->updateSyncRequestCounter();
    } else {
        XFlush(display());
    }
}