xcb: Fix DnD for separate X screens
Recreate QShapedPixmapWindow when the cursor goes to another X screen. Change-Id: Ifd4c4281971b23abc45a9f6c0509832a45c31521 Reviewed-by: Lars Knoll <lars.knoll@theqtcompany.com>
This commit is contained in:
parent
de70798859
commit
c55a36cb90
@ -38,8 +38,8 @@
|
|||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
QShapedPixmapWindow::QShapedPixmapWindow()
|
QShapedPixmapWindow::QShapedPixmapWindow(QScreen *screen)
|
||||||
: QWindow(),
|
: QWindow(screen),
|
||||||
m_backingStore(0)
|
m_backingStore(0)
|
||||||
{
|
{
|
||||||
QSurfaceFormat format;
|
QSurfaceFormat format;
|
||||||
|
@ -55,7 +55,7 @@ class QShapedPixmapWindow : public QWindow
|
|||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
QShapedPixmapWindow();
|
explicit QShapedPixmapWindow(QScreen *screen = 0);
|
||||||
~QShapedPixmapWindow();
|
~QShapedPixmapWindow();
|
||||||
|
|
||||||
void render();
|
void render();
|
||||||
|
@ -203,25 +203,15 @@ void QBasicDrag::restoreCursor()
|
|||||||
|
|
||||||
void QBasicDrag::startDrag()
|
void QBasicDrag::startDrag()
|
||||||
{
|
{
|
||||||
// ### TODO Check if its really necessary to have m_drag_icon_window
|
QPoint pos;
|
||||||
// when QDrag is used without a pixmap - QDrag::setPixmap()
|
|
||||||
if (!m_drag_icon_window)
|
|
||||||
m_drag_icon_window = new QShapedPixmapWindow();
|
|
||||||
|
|
||||||
m_drag_icon_window->setPixmap(m_drag->pixmap());
|
|
||||||
m_drag_icon_window->setHotspot(m_drag->hotSpot());
|
|
||||||
|
|
||||||
#ifndef QT_NO_CURSOR
|
#ifndef QT_NO_CURSOR
|
||||||
QPoint pos = QCursor::pos();
|
pos = QCursor::pos();
|
||||||
if (pos.x() == int(qInf())) {
|
if (pos.x() == int(qInf())) {
|
||||||
// ### fixme: no mouse pos registered. Get pos from touch...
|
// ### fixme: no mouse pos registered. Get pos from touch...
|
||||||
pos = QPoint();
|
pos = QPoint();
|
||||||
}
|
}
|
||||||
m_drag_icon_window->updateGeometry(pos);
|
|
||||||
#endif
|
#endif
|
||||||
|
recreateShapedPixmapWindow(Q_NULLPTR, pos);
|
||||||
m_drag_icon_window->setVisible(true);
|
|
||||||
|
|
||||||
enableEventFilter();
|
enableEventFilter();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -229,6 +219,19 @@ void QBasicDrag::endDrag()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QBasicDrag::recreateShapedPixmapWindow(QScreen *screen, const QPoint &pos)
|
||||||
|
{
|
||||||
|
delete m_drag_icon_window;
|
||||||
|
// ### TODO Check if its really necessary to have m_drag_icon_window
|
||||||
|
// when QDrag is used without a pixmap - QDrag::setPixmap()
|
||||||
|
m_drag_icon_window = new QShapedPixmapWindow(screen);
|
||||||
|
|
||||||
|
m_drag_icon_window->setPixmap(m_drag->pixmap());
|
||||||
|
m_drag_icon_window->setHotspot(m_drag->hotSpot());
|
||||||
|
m_drag_icon_window->updateGeometry(pos);
|
||||||
|
m_drag_icon_window->setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
void QBasicDrag::cancel()
|
void QBasicDrag::cancel()
|
||||||
{
|
{
|
||||||
disableEventFilter();
|
disableEventFilter();
|
||||||
|
@ -58,6 +58,7 @@ class QWindow;
|
|||||||
class QEventLoop;
|
class QEventLoop;
|
||||||
class QDropData;
|
class QDropData;
|
||||||
class QShapedPixmapWindow;
|
class QShapedPixmapWindow;
|
||||||
|
class QScreen;
|
||||||
|
|
||||||
class Q_GUI_EXPORT QBasicDrag : public QPlatformDrag, public QObject
|
class Q_GUI_EXPORT QBasicDrag : public QPlatformDrag, public QObject
|
||||||
{
|
{
|
||||||
@ -80,6 +81,7 @@ protected:
|
|||||||
|
|
||||||
void moveShapedPixmapWindow(const QPoint &deviceIndependentPosition);
|
void moveShapedPixmapWindow(const QPoint &deviceIndependentPosition);
|
||||||
QShapedPixmapWindow *shapedPixmapWindow() const { return m_drag_icon_window; }
|
QShapedPixmapWindow *shapedPixmapWindow() const { return m_drag_icon_window; }
|
||||||
|
void recreateShapedPixmapWindow(QScreen *screen, const QPoint &pos);
|
||||||
void updateCursor(Qt::DropAction action);
|
void updateCursor(Qt::DropAction action);
|
||||||
|
|
||||||
bool canDrop() const { return m_can_drop; }
|
bool canDrop() const { return m_can_drop; }
|
||||||
|
@ -376,8 +376,10 @@ public:
|
|||||||
|
|
||||||
QXcbConnection *connection() const { return const_cast<QXcbConnection *>(this); }
|
QXcbConnection *connection() const { return const_cast<QXcbConnection *>(this); }
|
||||||
|
|
||||||
|
const QList<QXcbVirtualDesktop *> &virtualDesktops() const { return m_virtualDesktops; }
|
||||||
const QList<QXcbScreen *> &screens() const { return m_screens; }
|
const QList<QXcbScreen *> &screens() const { return m_screens; }
|
||||||
int primaryScreenNumber() const { return m_primaryScreenNumber; }
|
int primaryScreenNumber() const { return m_primaryScreenNumber; }
|
||||||
|
QXcbVirtualDesktop *primaryVirtualDesktop() const { return m_virtualDesktops.value(m_primaryScreenNumber); }
|
||||||
QXcbScreen *primaryScreen() const;
|
QXcbScreen *primaryScreen() const;
|
||||||
|
|
||||||
inline xcb_atom_t atom(QXcbAtom::Atom atom) const { return m_allAtoms[atom]; }
|
inline xcb_atom_t atom(QXcbAtom::Atom atom) const { return m_allAtoms[atom]; }
|
||||||
|
@ -607,30 +607,33 @@ xcb_cursor_t QXcbCursor::createBitmapCursor(QCursor *cursor)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void QXcbCursor::queryPointer(QXcbConnection *c, xcb_window_t *rootWin, QPoint *pos, int *keybMask)
|
void QXcbCursor::queryPointer(QXcbConnection *c, QXcbVirtualDesktop **virtualDesktop, QPoint *pos, int *keybMask)
|
||||||
{
|
{
|
||||||
if (pos)
|
if (pos)
|
||||||
*pos = QPoint();
|
*pos = QPoint();
|
||||||
xcb_screen_iterator_t it = xcb_setup_roots_iterator(c->setup());
|
|
||||||
while (it.rem) {
|
xcb_window_t root = c->primaryVirtualDesktop()->root();
|
||||||
xcb_window_t root = it.data->root;
|
xcb_query_pointer_cookie_t cookie = xcb_query_pointer(c->xcb_connection(), root);
|
||||||
xcb_query_pointer_cookie_t cookie = xcb_query_pointer(c->xcb_connection(), root);
|
xcb_generic_error_t *err = 0;
|
||||||
xcb_generic_error_t *err = 0;
|
xcb_query_pointer_reply_t *reply = xcb_query_pointer_reply(c->xcb_connection(), cookie, &err);
|
||||||
xcb_query_pointer_reply_t *reply = xcb_query_pointer_reply(c->xcb_connection(), cookie, &err);
|
if (!err && reply) {
|
||||||
if (!err && reply) {
|
if (virtualDesktop) {
|
||||||
if (pos)
|
foreach (QXcbVirtualDesktop *vd, c->virtualDesktops()) {
|
||||||
*pos = QPoint(reply->root_x, reply->root_y);
|
if (vd->root() == reply->root) {
|
||||||
if (rootWin)
|
*virtualDesktop = vd;
|
||||||
*rootWin = root;
|
break;
|
||||||
if (keybMask)
|
}
|
||||||
*keybMask = reply->mask;
|
}
|
||||||
free(reply);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
free(err);
|
if (pos)
|
||||||
|
*pos = QPoint(reply->root_x, reply->root_y);
|
||||||
|
if (keybMask)
|
||||||
|
*keybMask = reply->mask;
|
||||||
free(reply);
|
free(reply);
|
||||||
xcb_screen_next(&it);
|
return;
|
||||||
}
|
}
|
||||||
|
free(err);
|
||||||
|
free(reply);
|
||||||
}
|
}
|
||||||
|
|
||||||
QPoint QXcbCursor::pos() const
|
QPoint QXcbCursor::pos() const
|
||||||
@ -642,9 +645,9 @@ QPoint QXcbCursor::pos() const
|
|||||||
|
|
||||||
void QXcbCursor::setPos(const QPoint &pos)
|
void QXcbCursor::setPos(const QPoint &pos)
|
||||||
{
|
{
|
||||||
xcb_window_t root = 0;
|
QXcbVirtualDesktop *virtualDesktop = Q_NULLPTR;
|
||||||
queryPointer(connection(), &root, 0);
|
queryPointer(connection(), &virtualDesktop, 0);
|
||||||
xcb_warp_pointer(xcb_connection(), XCB_NONE, root, 0, 0, 0, 0, pos.x(), pos.y());
|
xcb_warp_pointer(xcb_connection(), XCB_NONE, virtualDesktop->root(), 0, 0, 0, 0, pos.x(), pos.y());
|
||||||
xcb_flush(xcb_connection());
|
xcb_flush(xcb_connection());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@ public:
|
|||||||
QPoint pos() const Q_DECL_OVERRIDE;
|
QPoint pos() const Q_DECL_OVERRIDE;
|
||||||
void setPos(const QPoint &pos) Q_DECL_OVERRIDE;
|
void setPos(const QPoint &pos) Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
static void queryPointer(QXcbConnection *c, xcb_window_t *rootWin, QPoint *pos, int *keybMask = 0);
|
static void queryPointer(QXcbConnection *c, QXcbVirtualDesktop **virtualDesktop, QPoint *pos, int *keybMask = 0);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
#ifndef QT_NO_CURSOR
|
#ifndef QT_NO_CURSOR
|
||||||
|
@ -39,6 +39,7 @@
|
|||||||
#include "qxcbwindow.h"
|
#include "qxcbwindow.h"
|
||||||
#include "qxcbscreen.h"
|
#include "qxcbscreen.h"
|
||||||
#include "qwindow.h"
|
#include "qwindow.h"
|
||||||
|
#include "qxcbcursor.h"
|
||||||
#include <private/qdnd_p.h>
|
#include <private/qdnd_p.h>
|
||||||
#include <qdebug.h>
|
#include <qdebug.h>
|
||||||
#include <qevent.h>
|
#include <qevent.h>
|
||||||
@ -160,7 +161,7 @@ void QXcbDrag::init()
|
|||||||
source_time = XCB_CURRENT_TIME;
|
source_time = XCB_CURRENT_TIME;
|
||||||
target_time = XCB_CURRENT_TIME;
|
target_time = XCB_CURRENT_TIME;
|
||||||
|
|
||||||
current_screen = 0;
|
QXcbCursor::queryPointer(connection(), ¤t_virtual_desktop, 0);
|
||||||
drag_types.clear();
|
drag_types.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -308,38 +309,20 @@ void QXcbDrag::move(const QPoint &globalPos)
|
|||||||
if (source_sameanswer.contains(globalPos) && source_sameanswer.isValid())
|
if (source_sameanswer.contains(globalPos) && source_sameanswer.isValid())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const QList<QXcbScreen *> &screens = connection()->screens();
|
QXcbVirtualDesktop *virtualDesktop = Q_NULLPTR;
|
||||||
QXcbScreen *screen = connection()->primaryScreen();
|
QPoint cursorPos;
|
||||||
for (int i = 0; i < screens.size(); ++i) {
|
QXcbCursor::queryPointer(connection(), &virtualDesktop, &cursorPos);
|
||||||
if (screens.at(i)->geometry().contains(globalPos)) {
|
QXcbScreen *screen = virtualDesktop->screenAt(cursorPos);
|
||||||
screen = screens.at(i);
|
QPoint deviceIndependentPos = QHighDpiScaling::mapPositionFromNative(globalPos, screen);
|
||||||
break;
|
|
||||||
}
|
if (virtualDesktop != current_virtual_desktop) {
|
||||||
|
recreateShapedPixmapWindow(static_cast<QPlatformScreen*>(screen)->screen(), deviceIndependentPos);
|
||||||
|
current_virtual_desktop = virtualDesktop;
|
||||||
|
} else {
|
||||||
|
QBasicDrag::moveShapedPixmapWindow(deviceIndependentPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
QBasicDrag::moveShapedPixmapWindow(QHighDpiScaling::mapPositionFromNative(globalPos, screen));
|
xcb_window_t rootwin = current_virtual_desktop->root();
|
||||||
|
|
||||||
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 =
|
xcb_translate_coordinates_reply_t *translate =
|
||||||
::translateCoordinates(connection(), rootwin, rootwin, globalPos.x(), globalPos.y());
|
::translateCoordinates(connection(), rootwin, rootwin, globalPos.x(), globalPos.y());
|
||||||
if (!translate)
|
if (!translate)
|
||||||
|
@ -133,7 +133,7 @@ private:
|
|||||||
// window to send events to (always valid if current_target)
|
// window to send events to (always valid if current_target)
|
||||||
xcb_window_t current_proxy_target;
|
xcb_window_t current_proxy_target;
|
||||||
|
|
||||||
QXcbScreen *current_screen;
|
QXcbVirtualDesktop *current_virtual_desktop;
|
||||||
|
|
||||||
// 10 minute timer used to discard old XdndDrop transactions
|
// 10 minute timer used to discard old XdndDrop transactions
|
||||||
enum { XdndDropTransactionTimeout = 600000 };
|
enum { XdndDropTransactionTimeout = 600000 };
|
||||||
|
@ -61,6 +61,15 @@ QXcbVirtualDesktop::~QXcbVirtualDesktop()
|
|||||||
delete m_xSettings;
|
delete m_xSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QXcbScreen *QXcbVirtualDesktop::screenAt(const QPoint &pos) const
|
||||||
|
{
|
||||||
|
foreach (QXcbScreen *screen, connection()->screens()) {
|
||||||
|
if (screen->virtualDesktop() == this && screen->nativeGeometry().contains(pos))
|
||||||
|
return screen;
|
||||||
|
}
|
||||||
|
return Q_NULLPTR;
|
||||||
|
}
|
||||||
|
|
||||||
QXcbXSettings *QXcbVirtualDesktop::xSettings() const
|
QXcbXSettings *QXcbVirtualDesktop::xSettings() const
|
||||||
{
|
{
|
||||||
if (!m_xSettings) {
|
if (!m_xSettings) {
|
||||||
|
@ -64,6 +64,8 @@ public:
|
|||||||
int number() const { return m_number; }
|
int number() const { return m_number; }
|
||||||
QSize size() const { return QSize(m_screen->width_in_pixels, m_screen->height_in_pixels); }
|
QSize size() const { return QSize(m_screen->width_in_pixels, m_screen->height_in_pixels); }
|
||||||
QSize physicalSize() const { return QSize(m_screen->width_in_millimeters, m_screen->height_in_millimeters); }
|
QSize physicalSize() const { return QSize(m_screen->width_in_millimeters, m_screen->height_in_millimeters); }
|
||||||
|
xcb_window_t root() const { return m_screen->root; }
|
||||||
|
QXcbScreen *screenAt(const QPoint &pos) const;
|
||||||
|
|
||||||
QXcbXSettings *xSettings() const;
|
QXcbXSettings *xSettings() const;
|
||||||
|
|
||||||
@ -104,6 +106,7 @@ public:
|
|||||||
void setVirtualSiblings(QList<QPlatformScreen *> sl) { m_siblings = sl; }
|
void setVirtualSiblings(QList<QPlatformScreen *> sl) { m_siblings = sl; }
|
||||||
void removeVirtualSibling(QPlatformScreen *s) { m_siblings.removeOne(s); }
|
void removeVirtualSibling(QPlatformScreen *s) { m_siblings.removeOne(s); }
|
||||||
void addVirtualSibling(QPlatformScreen *s) { ((QXcbScreen *) s)->isPrimary() ? m_siblings.prepend(s) : m_siblings.append(s); }
|
void addVirtualSibling(QPlatformScreen *s) { ((QXcbScreen *) s)->isPrimary() ? m_siblings.prepend(s) : m_siblings.append(s); }
|
||||||
|
QXcbVirtualDesktop *virtualDesktop() const { return m_virtualDesktop; }
|
||||||
|
|
||||||
void setPrimary(bool primary) { m_primary = primary; }
|
void setPrimary(bool primary) { m_primary = primary; }
|
||||||
bool isPrimary() const { return m_primary; }
|
bool isPrimary() const { return m_primary; }
|
||||||
|
Loading…
x
Reference in New Issue
Block a user