void QXcbWindowSurface::flush(QWidget *widget, const QRegion ®ion, 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(); } }
void QXcbBackingStore::flush(QWindow *window, const QRegion ®ion, 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(); } }
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); }
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; }
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; }
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; }
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); }
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; }
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); }
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); } }
void QXcbNativeBackingStore::flush(QWindow *window, const QRegion ®ion, 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()); } }