[prev in list] [next in list] [prev in thread] [next in thread]
List: kde-commits
Subject: =?utf-8?q?=5Bkdelibs/frameworks=5D_kdeui/util=3A_Full_port_to_XC?= =?utf-8?q?B_by_Fredrik_H=C3=B6glu
From: David Faure <faure+bluesystems () kde ! org>
Date: 2012-11-30 22:12:39
Message-ID: 20121130221239.747CCA6091 () git ! kde ! org
[Download RAW message or body]
Git commit a3189d1af16e389032b237c10952675166b171f8 by David Faure.
Committed on 30/11/2012 at 19:20.
Pushed by dfaure into branch 'frameworks'.
Full port to XCB by Fredrik Höglund <fredrik@kde.org>
M +437 -266 kdeui/util/kmanagerselection.cpp
M +55 -26 kdeui/util/kmanagerselection.h
http://commits.kde.org/kdelibs/a3189d1af16e389032b237c10952675166b171f8
diff --git a/kdeui/util/kmanagerselection.cpp b/kdeui/util/kmanagerselection.cpp
index 9c356db..4e67549 100644
--- a/kdeui/util/kmanagerselection.cpp
+++ b/kdeui/util/kmanagerselection.cpp
@@ -39,13 +39,38 @@ DEALINGS IN THE SOFTWARE.
#endif
#include <QtCore/QObject>
+#include <QtCore/QBasicTimer>
+#include <QTimerEvent>
#include <qx11info_x11.h>
#include <qwidget.h>
#include <kdebug.h>
-#include <kxerrorhandler.h>
-#include <X11/Xatom.h>
-#include <xcb/xcb.h>
+
+static xcb_window_t get_selection_owner(xcb_connection_t *c, xcb_atom_t selection)
+{
+ xcb_window_t owner = XCB_NONE;
+ xcb_get_selection_owner_reply_t *reply = xcb_get_selection_owner_reply(c, \
xcb_get_selection_owner(c, selection), 0); +
+ if (reply) {
+ owner = reply->owner;
+ free(reply);
+ }
+
+ return owner;
+}
+
+static xcb_atom_t intern_atom(xcb_connection_t *c, const char *name)
+{
+ xcb_atom_t atom = XCB_NONE;
+ xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(c, xcb_intern_atom(c, \
false, strlen(name), name), 0); +
+ if (reply) {
+ atom = reply->atom;
+ free(reply);
+ }
+
+ return atom;
+}
class KSelectionOwner::Private
#if QT_VERSION > QT_VERSION_CHECK(5, 0, 0)
@@ -53,29 +78,42 @@ class KSelectionOwner::Private
#endif
{
public:
- Private( KSelectionOwner* owner_P, Atom selection_P, int screen_P )
- : selection( selection_P ),
- screen( screen_P >= 0 ? screen_P : DefaultScreen( QX11Info::display() ) ),
- window( None ),
- timestamp( CurrentTime ),
- extra1( 0 ),
- extra2( 0 ),
- owner( owner_P )
+ enum State { Idle, WaitingForTimestamp, WaitingForPreviousOwner };
+
+ Private(KSelectionOwner* owner_P, xcb_atom_t selection_P, int screen_P)
+ : state(Idle),
+ selection(selection_P),
+ root(QX11Info::appRootWindow(screen_P)),
+ window(XCB_NONE),
+ prev_owner(XCB_NONE),
+ timestamp(XCB_CURRENT_TIME),
+ extra1(0),
+ extra2(0),
+ force_kill(false),
+ owner(owner_P)
{
#if QT_VERSION > QT_VERSION_CHECK(5, 0, 0)
QCoreApplication::instance()->installNativeEventFilter(this);
#endif
}
- const Atom selection;
- const int screen;
- Window window;
- Time timestamp;
- long extra1, extra2;
- static Atom manager_atom;
- static Atom xa_multiple;
- static Atom xa_targets;
- static Atom xa_timestamp;
+ void claimSucceeded();
+ void gotTimestamp();
+ void timeout();
+
+ State state;
+ const xcb_atom_t selection;
+ xcb_window_t root;
+ xcb_window_t window;
+ xcb_window_t prev_owner;
+ xcb_timestamp_t timestamp;
+ uint32_t extra1, extra2;
+ QBasicTimer timer;
+ bool force_kill;
+ static xcb_atom_t manager_atom;
+ static xcb_atom_t xa_multiple;
+ static xcb_atom_t xa_targets;
+ static xcb_atom_t xa_timestamp;
protected:
bool nativeEventFilter(const QByteArray& eventType, void *message, long *result) \
Q_DECL_OVERRIDE @@ -92,15 +130,15 @@ private:
};
-KSelectionOwner::KSelectionOwner( Atom selection_P, int screen_P, QObject* parent_P \
)
- : QObject( parent_P ),
- d( new Private( this, selection_P, screen_P ) )
+KSelectionOwner::KSelectionOwner(xcb_atom_t selection_P, int screen_P, QObject \
*parent_P) + : QObject(parent_P),
+ d(new Private(this, selection_P, screen_P))
{
}
-KSelectionOwner::KSelectionOwner( const char* selection_P, int screen_P, QObject* \
parent_P )
- : QObject( parent_P ),
- d( new Private( this, XInternAtom( QX11Info::display(), selection_P, False \
), screen_P ) ) +KSelectionOwner::KSelectionOwner(const char *selection_P, int \
screen_P, QObject *parent_P) + : QObject(parent_P),
+ d(new Private(this, intern_atom(QX11Info::connection(), selection_P), \
screen_P)) {
}
@@ -110,110 +148,157 @@ KSelectionOwner::~KSelectionOwner()
delete d;
}
-bool KSelectionOwner::claim( bool force_P, bool force_kill_P )
+void KSelectionOwner::Private::claimSucceeded()
+{
+ state = Idle;
+
+ xcb_client_message_event_t ev;
+ ev.response_type = XCB_CLIENT_MESSAGE;
+ ev.format = 32;
+ ev.window = root;
+ ev.type = Private::manager_atom;
+ ev.data.data32[0] = timestamp;
+ ev.data.data32[1] = selection;
+ ev.data.data32[2] = window;
+ ev.data.data32[3] = extra1;
+ ev.data.data32[4] = extra2;
+
+ xcb_send_event(QX11Info::connection(), false, root, \
XCB_EVENT_MASK_STRUCTURE_NOTIFY, (const char *) &ev); +
+ // kDebug() << "Claimed selection";
+
+ emit owner->claimedOwnership();
+}
+
+void KSelectionOwner::Private::gotTimestamp()
+{
+ Q_ASSERT(state == WaitingForTimestamp);
+
+ state = Idle;
+
+ xcb_connection_t *c = QX11Info::connection();
+
+ // Set the selection owner and immediately verify that the claim was successful
+ xcb_set_selection_owner(c, window, selection, timestamp);
+ xcb_window_t new_owner = get_selection_owner(c, selection);
+
+ if (new_owner != window)
{
- if( Private::manager_atom == None )
+ // kDebug() << "Failed to claim selection : " << new_owner;
+ xcb_destroy_window(c, window);
+ timestamp = XCB_CURRENT_TIME;
+ window = XCB_NONE;
+
+ emit owner->failedToClaimOwnership();
+ return;
+ }
+
+ if (prev_owner != XCB_NONE) {
+ // kDebug() << "Waiting for previous owner to disown";
+ timer.start(1000, owner);
+ state = WaitingForPreviousOwner;
+
+ // Note: We've already selected for structure notify events
+ // on the previous owner window
+ return;
+ }
+
+ // If there was no previous owner, we're done
+ claimSucceeded();
+}
+
+void KSelectionOwner::Private::timeout()
+{
+ Q_ASSERT(state == WaitingForPreviousOwner);
+
+ state = Idle;
+
+ if (force_kill) {
+ // kDebug() << "Killing previous owner";
+ xcb_connection_t *c = QX11Info::connection();
+
+ // Ignore any errors from the kill request
+ xcb_generic_error_t *err = xcb_request_check(c, xcb_kill_client_checked(c, \
prev_owner)); + free(err);
+
+ claimSucceeded();
+ return;
+ }
+
+ emit owner->failedToClaimOwnership();
+}
+
+void KSelectionOwner::claim(bool force_P, bool force_kill_P)
+{
+ Q_ASSERT(d->state == Private::Idle);
+
+ if (Private::manager_atom == XCB_NONE)
getAtoms();
- if( d->timestamp != CurrentTime )
+
+ if (d->timestamp != XCB_CURRENT_TIME)
release();
- Display* const dpy = QX11Info::display();
- XFlush(dpy);
- Window prev_owner = XGetSelectionOwner( dpy, d->selection );
- if( prev_owner != None )
- {
- if( !force_P )
- {
-// kDebug() << "Selection already owned, failing";
- return false;
- }
- XSelectInput( dpy, prev_owner, StructureNotifyMask );
- }
- XSetWindowAttributes attrs;
- attrs.override_redirect = True;
- d->window = XCreateWindow( dpy, RootWindow( dpy, d->screen ), 0, 0, 1, 1,
- 0, CopyFromParent, InputOnly, CopyFromParent, CWOverrideRedirect, &attrs );
-// kDebug() << "Using owner window " << window;
- Atom tmp = XA_ATOM;
- XSelectInput( dpy, d->window, PropertyChangeMask );
- XChangeProperty( dpy, d->window, XA_ATOM, XA_ATOM, 32, PropModeReplace,
- reinterpret_cast< unsigned char* >( &tmp ), 1 );
- XEvent ev;
- XSync( dpy, False );
- XCheckTypedWindowEvent( dpy, d->window, PropertyNotify, &ev ); // get a \
timestamp
- d->timestamp = ev.xproperty.time;
- XSelectInput( dpy, d->window, StructureNotifyMask ); // for DestroyNotify
- XSetSelectionOwner( dpy, d->selection, d->window, d->timestamp );
- Window new_owner = XGetSelectionOwner( dpy, d->selection );
- if( new_owner != d->window )
- {
-// kDebug() << "Failed to claim selection : " << new_owner;
- XDestroyWindow( dpy, d->window );
- XFlush(dpy);
- d->timestamp = CurrentTime;
- return false;
- }
- if( prev_owner != None )
+
+ xcb_connection_t *c = QX11Info::connection();
+ d->prev_owner = get_selection_owner(c, d->selection);
+
+ if (d->prev_owner != XCB_NONE)
+ {
+ if (!force_P)
{
-// kDebug() << "Waiting for previous owner to disown";
- for( int cnt = 0;
- ;
- ++cnt )
- {
- if( XCheckTypedWindowEvent( dpy, prev_owner, DestroyNotify, &ev ) == \
True )
- break;
- struct timeval tm = { 0, 50000 }; // 50 ms
- select( 0, NULL, NULL, NULL, &tm );
- if( cnt == 19 )
- {
- if( force_kill_P )
- {
- KXErrorHandler err;
-// kDebug() << "Killing previous owner";
- XKillClient( dpy, prev_owner );
- err.error( true ); // ignore errors when killing
- }
- break;
- }
- }
+ // kDebug() << "Selection already owned, failing";
+ emit failedToClaimOwnership();
+ return;
}
- ev.type = ClientMessage;
- ev.xclient.window = RootWindow( dpy, d->screen );
- ev.xclient.display = dpy;
- ev.xclient.message_type = Private::manager_atom;
- ev.xclient.format = 32;
- ev.xclient.data.l[ 0 ] = d->timestamp;
- ev.xclient.data.l[ 1 ] = d->selection;
- ev.xclient.data.l[ 2 ] = d->window;
- ev.xclient.data.l[ 3 ] = d->extra1;
- ev.xclient.data.l[ 4 ] = d->extra2;
- XSendEvent( dpy, RootWindow( dpy, d->screen ), False, StructureNotifyMask, &ev \
);
- XFlush(dpy);
-// kDebug() << "Claimed selection";
- return true;
+
+ // Select structure notify events so get an event when the previous owner
+ // destroys the window
+ uint32_t mask = XCB_EVENT_MASK_STRUCTURE_NOTIFY;
+ xcb_change_window_attributes(c, d->prev_owner, XCB_CW_EVENT_MASK, &mask);
}
+ uint32_t values[] = { true, XCB_EVENT_MASK_PROPERTY_CHANGE | \
XCB_EVENT_MASK_STRUCTURE_NOTIFY }; +
+ d->window = xcb_generate_id(c);
+ xcb_create_window(c, XCB_COPY_FROM_PARENT, d->window, d->root, 0, 0, 1, 1, 0,
+ XCB_WINDOW_CLASS_INPUT_ONLY, XCB_COPY_FROM_PARENT,
+ XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK, values);
+
+ // Trigger a property change event so we get a timestamp
+ xcb_atom_t tmp = XCB_ATOM_ATOM;
+ xcb_change_property(c, XCB_PROP_MODE_REPLACE, d->window, XCB_ATOM_ATOM, \
XCB_ATOM_ATOM, 32, 1, (const void *) &tmp); +
+ // Now we have to return to the event loop and wait for the property change \
event + d->force_kill = force_kill_P;
+ d->state = Private::WaitingForTimestamp;
+}
+
// destroy resource first
void KSelectionOwner::release()
- {
- if( d->timestamp == CurrentTime )
+{
+ if (d->timestamp == XCB_CURRENT_TIME)
return;
- XDestroyWindow( QX11Info::display(), d->window ); // also makes the selection \
not owned
-// kDebug() << "Releasing selection";
- d->timestamp = CurrentTime;
- }
-Window KSelectionOwner::ownerWindow() const
- {
- if( d->timestamp == CurrentTime )
- return None;
+ xcb_destroy_window(QX11Info::connection(), d->window); // also makes the \
selection not owned + d->window = XCB_NONE;
+
+ // kDebug() << "Releasing selection";
+
+ d->timestamp = XCB_CURRENT_TIME;
+}
+
+xcb_window_t KSelectionOwner::ownerWindow() const
+{
+ if (d->timestamp == XCB_CURRENT_TIME)
+ return XCB_NONE;
+
return d->window;
- }
+}
-void KSelectionOwner::setData( long extra1_P, long extra2_P )
- {
+void KSelectionOwner::setData(uint32_t extra1_P, uint32_t extra2_P)
+{
d->extra1 = extra1_P;
d->extra2 = extra2_P;
- }
+}
bool KSelectionOwner::filterEvent( void* ev_P )
{
@@ -229,27 +314,44 @@ bool KSelectionOwner::filterEvent( void* ev_P )
return true;
}
#endif
- switch( response_type )
+ switch (response_type)
{
case XCB_SELECTION_CLEAR:
{
xcb_selection_clear_event_t* ev = \
reinterpret_cast<xcb_selection_clear_event_t *>(event);
- if( d->timestamp == CurrentTime || ev->selection != d->selection )
+ if( d->timestamp == XCB_CURRENT_TIME || ev->selection != d->selection )
return false;
- d->timestamp = CurrentTime;
+
+ d->timestamp = XCB_CURRENT_TIME;
// kDebug() << "Lost selection";
- Window window = d->window;
+
+ xcb_window_t window = d->window;
emit lostOwnership();
- XSelectInput( QX11Info::display(), window, 0 );
- XDestroyWindow( QX11Info::display(), window );
+
+ // Unset the event mask before we destroy the window so we don't get a \
destroy event + uint32_t event_mask = XCB_NONE;
+ xcb_change_window_attributes(QX11Info::connection(), window, \
XCB_CW_EVENT_MASK, &event_mask); + xcb_destroy_window(QX11Info::connection(), \
window); return true;
}
case XCB_DESTROY_NOTIFY:
{
xcb_destroy_notify_event_t* ev = reinterpret_cast<xcb_destroy_notify_event_t \
*>(event);
- if( d->timestamp == CurrentTime || ev->window != d->window )
+ if (ev->window == d->prev_owner) {
+ if (d->state == Private::WaitingForPreviousOwner) {
+ d->timer.stop();
+ d->claimSucceeded();
+ return true;
+ }
+ // It is possible for the previous owner to be destroyed
+ // while we're waiting for the timestamp
+ d->prev_owner = XCB_NONE;
+ }
+
+ if (d->timestamp == XCB_CURRENT_TIME || ev->window != d->window)
return false;
- d->timestamp = CurrentTime;
+
+ d->timestamp = XCB_CURRENT_TIME;
// kDebug() << "Lost selection (destroyed)";
emit lostOwnership();
return true;
@@ -257,16 +359,39 @@ bool KSelectionOwner::filterEvent( void* ev_P )
case XCB_SELECTION_NOTIFY:
{
xcb_selection_notify_event_t* ev = \
reinterpret_cast<xcb_selection_notify_event_t *>(event);
- if( d->timestamp == CurrentTime || ev->selection != d->selection )
+ if( d->timestamp == XCB_CURRENT_TIME || ev->selection != d->selection )
return false;
+
// ignore?
return false;
}
case XCB_SELECTION_REQUEST:
filter_selection_request(event);
return false;
+ case XCB_PROPERTY_NOTIFY:
+ {
+ xcb_property_notify_event_t *ev = \
reinterpret_cast<xcb_property_notify_event_t *>(event); + if (ev->window == \
d->window && d->state == Private::WaitingForTimestamp) { + d->timestamp = \
ev->time; + d->gotTimestamp();
+ return true;
+ }
+ return false;
}
- return false;
+ default:
+ return false;
+ }
+}
+
+void KSelectionOwner::timerEvent(QTimerEvent *event)
+{
+ if (event->timerId() == d->timer.timerId()) {
+ d->timer.stop();
+ d->timeout();
+ return;
+ }
+
+ QObject::timerEvent(event);
}
#if 0
@@ -280,116 +405,137 @@ void KSelectionOwner::filter_selection_request( void* event )
{
xcb_selection_request_event_t* ev = \
reinterpret_cast<xcb_selection_request_event_t *>(event);
- if( d->timestamp == CurrentTime || ev->selection != d->selection )
+ if (d->timestamp == XCB_CURRENT_TIME || ev->selection != d->selection)
return;
- if( ev->time != CurrentTime
- && ev->time - d->timestamp > 1U << 31 )
+
+ if (ev->time != XCB_CURRENT_TIME && ev->time - d->timestamp > 1U << 31)
return; // too old or too new request
-// kDebug() << "Got selection request";
+
+ // kDebug() << "Got selection request";
+
+ xcb_connection_t *c = QX11Info::connection();
bool handled = false;
- if( ev->target == Private::xa_multiple )
+
+ if (ev->target == Private::xa_multiple)
+ {
+ if (ev->property != XCB_NONE)
{
- if( ev->property != None )
- {
- const int MAX_ATOMS = 100; // no need to handle more?
- int format;
- Atom type;
- unsigned long items;
- unsigned long after;
- unsigned char* data;
- if( XGetWindowProperty( QX11Info::display(), ev->requestor, \
ev->property, 0,
- MAX_ATOMS, False, AnyPropertyType, &type, &format, &items, &after,
- &data ) == Success && format == 32 && items % 2 == 0 )
- {
- bool handled_array[ MAX_ATOMS ];
- Atom* atoms = reinterpret_cast< Atom* >( data );
- for( unsigned int i = 0;
- i < items / 2;
- ++i )
- handled_array[ i ] = handle_selection(
- atoms[ i * 2 ], atoms[ i * 2 + 1 ], ev->requestor );
+ const int MAX_ATOMS = 100;
+
+ xcb_get_property_cookie_t cookie = xcb_get_property(c, false, \
ev->requestor, ev->property, + \
XCB_GET_PROPERTY_TYPE_ANY, 0, MAX_ATOMS); + xcb_get_property_reply_t \
*reply = xcb_get_property_reply(c, cookie, 0); +
+ if (reply && reply->format == 32 && reply->value_len % 2 == 0) {
+ xcb_atom_t *atoms = reinterpret_cast<xcb_atom_t \
*>(xcb_get_property_value(reply)); + bool handled_array[MAX_ATOMS];
+
+ for (int i = 0; i < reply->value_len / 2; i++)
+ handled_array[i] = handle_selection(atoms[i * 2], atoms[i * 2 + \
1], ev->requestor); +
bool all_handled = true;
- for( unsigned int i = 0;
- i < items / 2;
- ++i )
- if( !handled_array[ i ] )
- {
+ for (int i = 0; i < reply->value_len / 2; i++) {
+ if (!handled_array[i]) {
all_handled = false;
- atoms[ i * 2 + 1 ] = None;
- }
- if( !all_handled )
- XChangeProperty( QX11Info::display(), ev->requestor, \
ev->property, XA_ATOM,
- 32, PropModeReplace, reinterpret_cast< unsigned char* >( \
atoms ), items );
- handled = true;
- XFree( data );
+ atoms[i * 2 + 1] = XCB_NONE;
+ }
+ }
+
+ if (!all_handled) {
+ xcb_change_property(c, ev->requestor, ev->property, \
XCB_ATOM_ATOM, 32, XCB_PROP_MODE_REPLACE, + \
reply->value_len, reinterpret_cast<const void *>(atoms)); }
+
+ handled = true;
}
+
+ if (reply)
+ free(reply);
}
- else
- {
- if( ev->property == None ) // obsolete client
+ } else {
+ if (ev->property == XCB_NONE) // obsolete client
ev->property = ev->target;
- handled = handle_selection( ev->target, ev->property, ev->requestor );
- }
- XEvent xev;
- xev.xselection.selection = ev->selection;
- xev.xselection.type = SelectionNotify;
- xev.xselection.display = QX11Info::display();
- xev.xselection.requestor = ev->requestor;
- xev.xselection.target = ev->target;
- xev.xselection.property = handled ? ev->property : None;
- XSendEvent( QX11Info::display(), ev->requestor, False, 0, &xev );
+
+ handled = handle_selection(ev->target, ev->property, ev->requestor);
}
-bool KSelectionOwner::handle_selection( Atom target_P, Atom property_P, Window \
requestor_P )
- {
- if( target_P == Private::xa_timestamp )
- {
-// kDebug() << "Handling timestamp request";
- XChangeProperty( QX11Info::display(), requestor_P, property_P, XA_INTEGER, \
32,
- PropModeReplace, reinterpret_cast< unsigned char* >( &d->timestamp ), 1 \
);
- }
- else if( target_P == Private::xa_targets )
- replyTargets( property_P, requestor_P );
- else if( genericReply( target_P, property_P, requestor_P ))
- ; // handled
- else
+ xcb_selection_notify_event_t xev;
+ xev.response_type = XCB_SELECTION_NOTIFY;
+ xev.selection = ev->selection;
+ xev.requestor = ev->requestor;
+ xev.target = ev->target;
+ xev.property = handled ? ev->property : XCB_NONE;
+
+ xcb_send_event(c, false, ev->requestor, 0, (const char *) &xev);
+}
+
+bool KSelectionOwner::handle_selection(xcb_atom_t target_P, xcb_atom_t property_P, \
xcb_window_t requestor_P) +{
+ if( target_P == Private::xa_timestamp ) {
+ // kDebug() << "Handling timestamp request";
+ xcb_change_property(QX11Info::connection(), requestor_P, property_P, \
XCB_ATOM_INTEGER, 32, + XCB_PROP_MODE_REPLACE, 1, \
reinterpret_cast<const void *>(&d->timestamp)); + } else if (target_P == \
Private::xa_targets) { + replyTargets(property_P, requestor_P);
+ } else if (genericReply(target_P, property_P, requestor_P)) {
+ // handled
+ } else {
return false; // unknown
- return true;
}
-void KSelectionOwner::replyTargets( Atom property_P, Window requestor_P )
- {
- Atom atoms[ 3 ] = { Private::xa_multiple, Private::xa_timestamp, \
Private::xa_targets };
-// kDebug() << "Handling targets request";
- XChangeProperty( QX11Info::display(), requestor_P, property_P, XA_ATOM, 32, \
PropModeReplace,
- reinterpret_cast< unsigned char* >( atoms ), 3 );
- }
+ return true;
+}
-bool KSelectionOwner::genericReply( Atom, Atom, Window )
- {
+void KSelectionOwner::replyTargets(xcb_atom_t property_P, xcb_window_t requestor_P)
+{
+ xcb_atom_t atoms[3] = { Private::xa_multiple, Private::xa_timestamp, \
Private::xa_targets }; +
+ xcb_change_property(QX11Info::connection(), requestor_P, property_P, \
XCB_ATOM_ATOM, 32, XCB_PROP_MODE_REPLACE, + sizeof(atoms) / \
sizeof(atoms[0]), reinterpret_cast<const void *>(atoms)); +
+ // kDebug() << "Handling targets request";
+}
+
+bool KSelectionOwner::genericReply(xcb_atom_t, xcb_atom_t, xcb_window_t)
+{
return false;
- }
+}
void KSelectionOwner::getAtoms()
- {
- if( Private::manager_atom == None )
- {
- Atom atoms[ 4 ];
- const char* const names[] =
- { "MANAGER", "MULTIPLE", "TARGETS", "TIMESTAMP" };
- XInternAtoms( QX11Info::display(), const_cast< char** >( names ), 4, False, \
atoms );
- Private::manager_atom = atoms[ 0 ];
- Private::xa_multiple = atoms[ 1];
- Private::xa_targets = atoms[ 2 ];
- Private::xa_timestamp = atoms[ 3 ];
+{
+ if (Private::manager_atom != XCB_NONE)
+ return;
+
+ xcb_connection_t *c = QX11Info::connection();
+
+ struct {
+ const char *name;
+ xcb_atom_t *atom;
+ } atoms[] = {
+ { "MANAGER", &Private::manager_atom },
+ { "MULTIPLE", &Private::xa_multiple },
+ { "TARGETS", &Private::xa_targets },
+ { "TIMESTAMP", &Private::xa_timestamp }
+ };
+
+ const int count = sizeof(atoms) / sizeof(atoms[0]);
+ xcb_intern_atom_cookie_t cookies[count];
+
+ for (int i = 0; i < count; i++)
+ cookies[i] = xcb_intern_atom(c, false, strlen(atoms[i].name), \
atoms[i].name); +
+ for (int i = 0; i < count; i++) {
+ if (xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(c, cookies[i], \
0)) { + *atoms[i].atom = reply->atom;
+ free(reply);
}
}
+}
-Atom KSelectionOwner::Private::manager_atom = None;
-Atom KSelectionOwner::Private::xa_multiple = None;
-Atom KSelectionOwner::Private::xa_targets = None;
-Atom KSelectionOwner::Private::xa_timestamp = None;
+xcb_atom_t KSelectionOwner::Private::manager_atom = XCB_NONE;
+xcb_atom_t KSelectionOwner::Private::xa_multiple = XCB_NONE;
+xcb_atom_t KSelectionOwner::Private::xa_targets = XCB_NONE;
+xcb_atom_t KSelectionOwner::Private::xa_timestamp = XCB_NONE;
//*******************************************
// KSelectionWatcher
@@ -402,21 +548,21 @@ class KSelectionWatcher::Private
#endif
{
public:
- Private( KSelectionWatcher* watcher_P, Atom selection_P, int screen_P )
- : selection( selection_P ),
- screen( screen_P >= 0 ? screen_P : DefaultScreen( QX11Info::display())),
- selection_owner( None ),
- watcher( watcher_P )
+ Private(KSelectionWatcher* watcher_P, xcb_atom_t selection_P, int screen_P)
+ : root(QX11Info::appRootWindow(screen_P)),
+ selection(selection_P),
+ selection_owner(XCB_NONE),
+ watcher(watcher_P)
{
#if QT_VERSION > QT_VERSION_CHECK(5, 0, 0)
QCoreApplication::instance()->installNativeEventFilter(this);
#endif
}
- const Atom selection;
- const int screen;
- Window selection_owner;
- static Atom manager_atom;
+ xcb_window_t root;
+ const xcb_atom_t selection;
+ xcb_window_t selection_owner;
+ static xcb_atom_t manager_atom;
protected:
bool nativeEventFilter(const QByteArray& eventType, void *message, long *result) \
Q_DECL_OVERRIDE @@ -432,62 +578,85 @@ private:
KSelectionWatcher* watcher;
};
-KSelectionWatcher::KSelectionWatcher( Atom selection_P, int screen_P, QObject* \
parent_P )
- : QObject( parent_P ),
- d( new Private( this, selection_P, screen_P ))
- {
+KSelectionWatcher::KSelectionWatcher(xcb_atom_t selection_P, int screen_P, QObject \
*parent_P) + : QObject(parent_P),
+ d(new Private(this, selection_P, screen_P))
+{
init();
- }
+}
-KSelectionWatcher::KSelectionWatcher( const char* selection_P, int screen_P, \
QObject* parent_P )
- : QObject( parent_P ),
- d( new Private( this, XInternAtom( QX11Info::display(), selection_P, False \
), screen_P ))
- {
+KSelectionWatcher::KSelectionWatcher(const char *selection_P, int screen_P, QObject \
*parent_P) + : QObject(parent_P),
+ d(new Private(this, intern_atom(QX11Info::connection(), selection_P), \
screen_P)) +{
init();
- }
+}
KSelectionWatcher::~KSelectionWatcher()
- {
+{
delete d;
- }
+}
void KSelectionWatcher::init()
+{
+ if (Private::manager_atom == XCB_NONE)
{
- if( Private::manager_atom == None )
- {
- Display* const dpy = QX11Info::display();
- Private::manager_atom = XInternAtom( dpy, "MANAGER", False );
- XWindowAttributes attrs;
- XGetWindowAttributes( dpy, RootWindow( dpy, d->screen ), &attrs );
- long event_mask = attrs.your_event_mask;
- // StructureNotifyMask on the root window is needed
- XSelectInput( dpy, RootWindow( dpy, d->screen ), event_mask | \
StructureNotifyMask );
- XFlush(dpy);
+ xcb_connection_t *c = QX11Info::connection();
+
+ xcb_intern_atom_cookie_t atom_cookie = xcb_intern_atom(c, false, \
strlen("MANAGER"), "MANAGER"); + xcb_get_window_attributes_cookie_t \
attr_cookie = xcb_get_window_attributes(c, d->root); +
+ xcb_intern_atom_reply_t *atom_reply = xcb_intern_atom_reply(c, atom_cookie, \
0); + Private::manager_atom = atom_reply->atom;
+ free(atom_reply);
+
+ xcb_get_window_attributes_reply_t *attr = xcb_get_window_attributes_reply(c, \
attr_cookie, 0); + uint32_t event_mask = attr->your_event_mask;
+ free(attr);
+
+ if (!(event_mask & XCB_EVENT_MASK_STRUCTURE_NOTIFY)) {
+ // We need XCB_EVENT_MASK_STRUCTURE_NORITY on the root window
+ event_mask |= XCB_EVENT_MASK_STRUCTURE_NOTIFY;
+ xcb_change_window_attributes(c, d->root, XCB_CW_EVENT_MASK, \
&event_mask); }
- owner(); // trigger reading of current selection status
}
-Window KSelectionWatcher::owner()
- {
- Display* const dpy = QX11Info::display();
- KXErrorHandler handler;
- Window current_owner = XGetSelectionOwner( dpy, d->selection );
- if( current_owner == None )
- return None;
- if( current_owner == d->selection_owner )
+ owner(); // trigger reading of current selection status
+}
+
+xcb_window_t KSelectionWatcher::owner()
+{
+ xcb_connection_t *c = QX11Info::connection();
+
+ xcb_window_t current_owner = get_selection_owner(c, d->selection);
+ if (current_owner == XCB_NONE)
+ return XCB_NONE;
+
+ if (current_owner == d->selection_owner)
return d->selection_owner;
- XSelectInput( dpy, current_owner, StructureNotifyMask );
- if( !handler.error( true ) && current_owner == XGetSelectionOwner( dpy, \
d->selection ))
- {
-// kDebug() << "isOwner: " << current_owner;
+
+ // We have a new selection owner - select for structure notify events
+ uint32_t mask = XCB_EVENT_MASK_STRUCTURE_NOTIFY;
+ xcb_void_cookie_t cookie = xcb_change_window_attributes_checked(c, \
current_owner, XCB_CW_EVENT_MASK, &mask); +
+ // Verify that the owner didn't change again while selecting for events
+ xcb_window_t new_owner = get_selection_owner(c, d->selection);
+ xcb_generic_error_t *err = xcb_request_check(c, cookie);
+
+ if (!err && current_owner == new_owner) {
d->selection_owner = current_owner;
- emit newOwner( d->selection_owner );
- }
- else
- d->selection_owner = None;
- return d->selection_owner;
+ emit newOwner(d->selection_owner);
+ } else {
+ // ### This doesn't look right - the selection could have an owner
+ d->selection_owner = XCB_NONE;
}
+ if (err)
+ free(err);
+
+ return d->selection_owner;
+}
+
void KSelectionWatcher::filterEvent(void* ev_P)
{
xcb_generic_event_t* event = reinterpret_cast<xcb_generic_event_t *>(ev_P);
@@ -506,13 +675,15 @@ void KSelectionWatcher::filterEvent(void* ev_P)
// }
if (response_type == XCB_DESTROY_NOTIFY) {
xcb_destroy_notify_event_t* ev = reinterpret_cast<xcb_destroy_notify_event_t \
*>(event);
- if( d->selection_owner == None || ev->window != d->selection_owner )
+ if( d->selection_owner == XCB_NONE || ev->window != d->selection_owner )
return;
- d->selection_owner = None; // in case the exactly same ID gets reused as the \
owner
- if( owner() == None )
+
+ d->selection_owner = XCB_NONE; // in case the exactly same ID gets reused as \
the owner +
+ if (owner() == XCB_NONE)
emit lostOwner(); // it must be safe to delete 'this' in a slot
return;
}
}
-Atom KSelectionWatcher::Private::manager_atom = None;
+xcb_atom_t KSelectionWatcher::Private::manager_atom = XCB_NONE;
diff --git a/kdeui/util/kmanagerselection.h b/kdeui/util/kmanagerselection.h
index 21ace13..e931e26 100644
--- a/kdeui/util/kmanagerselection.h
+++ b/kdeui/util/kmanagerselection.h
@@ -28,9 +28,8 @@ DEALINGS IN THE SOFTWARE.
#include <kdeui_export.h>
#include <QtCore/QObject>
-#include <X11/Xlib.h>
-#include <fixx11h.h>
-
+#include <xcb/xcb.h>
+#include <xcb/xproto.h>
/**
This class implements claiming and owning manager selections, as described
@@ -53,7 +52,8 @@ class KDEUI_EXPORT KSelectionOwner
* @param screen X screen, or -1 for default
* @param parent parent object, or NULL if there is none
*/
- explicit KSelectionOwner( Atom selection, int screen = -1, QObject* parent = \
NULL ); + explicit KSelectionOwner(xcb_atom_t selection, int screen = -1, \
QObject* parent = NULL); +
/**
* @overload
* This constructor accepts the selection name and creates the appropriate \
atom @@ -63,35 +63,50 @@ class KDEUI_EXPORT KSelectionOwner
* @param screen X screen, or -1 for default
* @param parent parent object, or NULL if there is none
*/
- explicit KSelectionOwner( const char* selection, int screen = -1, QObject* \
parent = NULL ); + explicit KSelectionOwner(const char *selection, int screen \
= -1, QObject* parent = NULL); +
/**
* Destructor. Calls release().
*/
virtual ~KSelectionOwner();
+
/**
- * This function attemps to claim ownership of the manager selection, using
- * the current X timestamp. If @p force is false, and the selection is \
already
- * owned, the selection is not claimed, and false is returned. If claiming
- * is forced and the selection is owned by another client, it is waited for \
up to 1 second
- * for the previous owner to disown the selection, if @p force_kill is true,
- * and the previous owner fails to disown the selection in time,
- * it will be forcibly killed. True is returned after successfully claiming
- * ownership of the selection.
+ * Try to claim ownership of the manager selection using the current X \
timestamp. + *
+ * This function returns immediately, but it may take up to one second for \
the claim + * to succeed or fail, at which point either the \
claimedOwnership() or + * failedToClaimOwnership() signal is emitted. The \
claim will not be completed until + * the caller has returned to the event \
loop. + *
+ * If @p force is false, and the selection is already owned, the selection \
is not claimed, + * and failedToClaimOwnership() is emitted. If @p force is \
true and the selection is + * owned by another client, the client will be \
given one second to relinquish ownership + * of the selection. If @p \
force_kill is true, and the previous owner fails to disown + * the selection \
in time, it will be forcibly killed.
*/
- bool claim( bool force, bool force_kill = true );
+ void claim(bool force, bool force_kill = true);
+
/**
* If the selection is owned, the ownership is given up.
*/
void release();
+
/**
* If the selection is owned, returns the window used internally
* for owning the selection.
*/
- Window ownerWindow() const; // None if not owning the selection
+ xcb_window_t ownerWindow() const; // None if not owning the selection
+
+ /**
+ * @internal
+ */
+ bool filterEvent(void *ev_P); // internal
+
/**
* @internal
*/
- bool filterEvent( void* ev_P ); // internal
+ void timerEvent(QTimerEvent *event);
+
Q_SIGNALS:
/**
* This signal is emitted if the selection was owned and the ownership
@@ -100,6 +115,19 @@ class KDEUI_EXPORT KSelectionOwner
* to this signal.
*/
void lostOwnership();
+
+ /**
+ * This signal is emitted when claim() was succesful in claiming
+ * ownership of the selection.
+ */
+ void claimedOwnership();
+
+ /**
+ * This signal is emitted when claim() failed to claim ownership
+ * of the selection.
+ */
+ void failedToClaimOwnership();
+
protected:
/**
* Called for every X event received on the window used for owning
@@ -115,13 +143,13 @@ class KDEUI_EXPORT KSelectionOwner
* @param property property to use for the reply data
* @param requestor requestor window
*/
- virtual bool genericReply( Atom target, Atom property, Window requestor );
+ virtual bool genericReply(xcb_atom_t target, xcb_atom_t property, \
xcb_window_t requestor); /**
* Called to announce the supported targets, as described in the ICCCM
* section 2.6. The default implementation announces the required targets
* MULTIPLE, TIMESTAMP and TARGETS.
*/
- virtual void replyTargets( Atom property, Window requestor );
+ virtual void replyTargets(xcb_atom_t property, xcb_window_t requestor);
/**
* Called to create atoms needed for claiming the selection and
* communication using the selection handling mechanism. The default
@@ -134,10 +162,11 @@ class KDEUI_EXPORT KSelectionOwner
* after successfully claiming a selection. These extra data
* are in data.l[3] and data.l[4] fields of the XClientMessage.
*/
- void setData( long extra1, long extra2 );
+ void setData(uint32_t extra1, uint32_t extra2);
+
private:
- void filter_selection_request( void* ev_P );
- bool handle_selection( Atom target_P, Atom property_P, Window requestor_P );
+ void filter_selection_request(void *ev_P);
+ bool handle_selection(xcb_atom_t target_P, xcb_atom_t property_P, \
xcb_window_t requestor_P);
class Private;
Private* const d;
@@ -163,7 +192,7 @@ class KDEUI_EXPORT KSelectionWatcher
* @param screen X screen, or -1 for default
* @param parent parent object, or NULL if there is none
*/
- explicit KSelectionWatcher( Atom selection, int screen = -1, QObject* parent \
= NULL ); + explicit KSelectionWatcher(xcb_atom_t selection, int screen = -1, \
QObject *parent = NULL); /**
* @overload
* This constructor accepts the selection name and creates the appropriate \
atom @@ -173,25 +202,25 @@ class KDEUI_EXPORT KSelectionWatcher
* @param screen X screen, or -1 for default
* @param parent parent object, or NULL if there is none
*/
- explicit KSelectionWatcher( const char* selection, int screen = -1, QObject* \
parent = NULL ); + explicit KSelectionWatcher(const char *selection, int \
screen = -1, QObject *parent = NULL); virtual ~KSelectionWatcher();
/**
* Return the current owner of the manager selection, if any. Note that if \
the event
* informing about the owner change is still in the input queue, newOwner() \
might
* have been emitted yet.
*/
- Window owner();
+ xcb_window_t owner();
/**
* @internal
*/
- void filterEvent( void* ev_P ); // internal
+ void filterEvent(void *ev_P); // internal
Q_SIGNALS:
/**
* This signal is emitted when the selection is successfully claimed by a \
new
* owner.
* @param owner the new owner of the selection
*/
- void newOwner( Window owner );
+ void newOwner(xcb_window_t owner);
/**
* This signal is emitted when the selection is given up, i.e. there's no
* owner. Note that the selection may be immediatelly claimed again,
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic