forked from AuroraMiddleware/gtk
x11: Introduce GdkX11PendingSelectionNotify
This object tracks the SelectionNotifyEvent that has to be sent in response to a SelectionRequest. Currently it just looks like code reshuffling, but it's a prerequisite for handling MULTIPLE, which requires to only send the notify after every stream has writtten at least once. But anyway, code is cleaner now, so it's a win!
This commit is contained in:
parent
bcc0d4b5f0
commit
ea18793965
@ -92,8 +92,6 @@ gdk_x11_clipboard_default_output_done (GObject *clipboard,
|
||||
static void
|
||||
gdk_x11_clipboard_default_output_handler (GdkX11Clipboard *cb,
|
||||
const char *target,
|
||||
const char *encoding,
|
||||
int format,
|
||||
GOutputStream *stream)
|
||||
{
|
||||
gdk_clipboard_write_async (GDK_CLIPBOARD (cb),
|
||||
@ -232,7 +230,7 @@ handle_text_list (GdkX11Clipboard *cb,
|
||||
g_object_unref (converter);
|
||||
g_object_unref (stream);
|
||||
|
||||
gdk_x11_clipboard_default_output_handler (cb, "text/plain;charset=utf-8", encoding, format, converter_stream);
|
||||
gdk_x11_clipboard_default_output_handler (cb, "text/plain;charset=utf-8", converter_stream);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -242,7 +240,7 @@ handle_utf8 (GdkX11Clipboard *cb,
|
||||
int format,
|
||||
GOutputStream *stream)
|
||||
{
|
||||
gdk_x11_clipboard_default_output_handler (cb, "text/plain;charset=utf-8", encoding, format, stream);
|
||||
gdk_x11_clipboard_default_output_handler (cb, "text/plain;charset=utf-8", stream);
|
||||
}
|
||||
|
||||
static GInputStream *
|
||||
@ -480,16 +478,15 @@ gdk_x11_clipboard_claim_remote (GdkX11Clipboard *cb,
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_x11_clipboard_request_selection (GdkX11Clipboard *cb,
|
||||
Window requestor,
|
||||
const char *target,
|
||||
const char *property,
|
||||
gulong timestamp)
|
||||
gdk_x11_clipboard_request_selection (GdkX11Clipboard *cb,
|
||||
GdkX11PendingSelectionNotify *notify,
|
||||
Window requestor,
|
||||
const char *target,
|
||||
const char *property,
|
||||
gulong timestamp)
|
||||
{
|
||||
const char *type, *mime_type;
|
||||
MimeTypeHandleFunc handler_func = NULL;
|
||||
const char *mime_type;
|
||||
GdkDisplay *display;
|
||||
gint format;
|
||||
gsize i;
|
||||
|
||||
display = gdk_clipboard_get_display (GDK_CLIPBOARD (cb));
|
||||
@ -497,9 +494,21 @@ gdk_x11_clipboard_request_selection (GdkX11Clipboard *cb,
|
||||
|
||||
if (mime_type)
|
||||
{
|
||||
handler_func = gdk_x11_clipboard_default_output_handler;
|
||||
type = target;
|
||||
format = 8;
|
||||
if (gdk_content_formats_contain_mime_type (gdk_clipboard_get_formats (GDK_CLIPBOARD (cb)), mime_type))
|
||||
{
|
||||
GOutputStream *stream;
|
||||
|
||||
stream = gdk_x11_selection_output_stream_new (display,
|
||||
notify,
|
||||
requestor,
|
||||
cb->selection,
|
||||
target,
|
||||
property,
|
||||
target,
|
||||
8,
|
||||
timestamp);
|
||||
gdk_x11_clipboard_default_output_handler (cb, target, stream);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -508,65 +517,30 @@ gdk_x11_clipboard_request_selection (GdkX11Clipboard *cb,
|
||||
if (g_str_equal (target, special_targets[i].x_target) &&
|
||||
special_targets[i].handler)
|
||||
{
|
||||
GOutputStream *stream;
|
||||
|
||||
if (special_targets[i].mime_type)
|
||||
mime_type = gdk_intern_mime_type (special_targets[i].mime_type);
|
||||
handler_func = special_targets[i].handler;
|
||||
type = special_targets[i].type;
|
||||
format = special_targets[i].format;
|
||||
break;
|
||||
stream = gdk_x11_selection_output_stream_new (display,
|
||||
notify,
|
||||
requestor,
|
||||
cb->selection,
|
||||
target,
|
||||
property,
|
||||
special_targets[i].type,
|
||||
special_targets[i].format,
|
||||
timestamp);
|
||||
special_targets[i].handler (cb,
|
||||
target,
|
||||
special_targets[i].type,
|
||||
special_targets[i].format,
|
||||
stream);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (handler_func == NULL ||
|
||||
(mime_type && !gdk_content_formats_contain_mime_type (gdk_clipboard_get_formats (GDK_CLIPBOARD (cb)), mime_type)))
|
||||
{
|
||||
Display *xdisplay = gdk_x11_display_get_xdisplay (display);
|
||||
XSelectionEvent xreply;
|
||||
int error;
|
||||
|
||||
xreply.type = SelectionNotify;
|
||||
xreply.serial = 0;
|
||||
xreply.send_event = True;
|
||||
xreply.requestor = requestor;
|
||||
xreply.selection = cb->xselection;
|
||||
xreply.target = gdk_x11_get_xatom_by_name_for_display (display, target);
|
||||
xreply.property = None;
|
||||
xreply.time = timestamp;
|
||||
|
||||
GDK_NOTE(CLIPBOARD, g_printerr ("%s%s: Sending SelectionNotify rejecting request\n",
|
||||
cb->selection, target));
|
||||
|
||||
gdk_x11_display_error_trap_push (display);
|
||||
if (XSendEvent (xdisplay, xreply.requestor, False, NoEventMask, (XEvent*) & xreply) == 0)
|
||||
{
|
||||
GDK_NOTE(CLIPBOARD, g_printerr ("%s:%s: failed to XSendEvent()\n",
|
||||
cb->selection, target));
|
||||
g_warning ("failed to XSendEvent()");
|
||||
}
|
||||
XSync (xdisplay, False);
|
||||
|
||||
error = gdk_x11_display_error_trap_pop (display);
|
||||
if (error != Success)
|
||||
{
|
||||
GDK_NOTE(CLIPBOARD, g_printerr ("%s:%s: X error during write: %d\n",
|
||||
cb->selection, target, error));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GOutputStream *stream;
|
||||
|
||||
stream = gdk_x11_selection_output_stream_new (display,
|
||||
requestor,
|
||||
cb->selection,
|
||||
target,
|
||||
property,
|
||||
type,
|
||||
format,
|
||||
timestamp);
|
||||
handler_func (cb, target, type, format, stream);
|
||||
}
|
||||
gdk_x11_pending_selection_notify_send (notify, display, FALSE);
|
||||
}
|
||||
|
||||
static GdkFilterReturn
|
||||
@ -604,6 +578,7 @@ gdk_x11_clipboard_filter_event (GdkXEvent *xev,
|
||||
|
||||
case SelectionRequest:
|
||||
{
|
||||
GdkX11PendingSelectionNotify *notify;
|
||||
const char *target, *property;
|
||||
|
||||
if (xevent->xselectionrequest.selection != cb->xselection)
|
||||
@ -630,7 +605,16 @@ gdk_x11_clipboard_filter_event (GdkXEvent *xev,
|
||||
|
||||
GDK_NOTE(CLIPBOARD, g_printerr ("%s: got SelectionRequest for %s @ %s\n",
|
||||
cb->selection, target, property));
|
||||
|
||||
notify = gdk_x11_pending_selection_notify_new (xevent->xselectionrequest.requestor,
|
||||
xevent->xselectionrequest.selection,
|
||||
xevent->xselectionrequest.target,
|
||||
xevent->xselectionrequest.property ? xevent->xselectionrequest.property
|
||||
: xevent->xselectionrequest.target,
|
||||
xevent->xselectionrequest.time);
|
||||
|
||||
gdk_x11_clipboard_request_selection (cb,
|
||||
notify,
|
||||
xevent->xselectionrequest.requestor,
|
||||
target,
|
||||
property,
|
||||
|
@ -29,10 +29,11 @@
|
||||
#include "gdkx11property.h"
|
||||
#include "gdkx11window.h"
|
||||
|
||||
typedef struct GdkX11SelectionOutputStreamPrivate GdkX11SelectionOutputStreamPrivate;
|
||||
typedef struct _GdkX11SelectionOutputStreamPrivate GdkX11SelectionOutputStreamPrivate;
|
||||
|
||||
struct GdkX11SelectionOutputStreamPrivate {
|
||||
struct _GdkX11SelectionOutputStreamPrivate {
|
||||
GdkDisplay *display;
|
||||
GdkX11PendingSelectionNotify *notify;
|
||||
Window xwindow;
|
||||
char *selection;
|
||||
Atom xselection;
|
||||
@ -52,11 +53,17 @@ struct GdkX11SelectionOutputStreamPrivate {
|
||||
|
||||
GTask *pending_task;
|
||||
|
||||
guint started : 1;
|
||||
guint incr : 1;
|
||||
guint delete_pending : 1;
|
||||
};
|
||||
|
||||
struct _GdkX11PendingSelectionNotify
|
||||
{
|
||||
gsize n_pending;
|
||||
|
||||
XSelectionEvent xevent;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (GdkX11SelectionOutputStream, gdk_x11_selection_output_stream, G_TYPE_OUTPUT_STREAM);
|
||||
|
||||
static GdkFilterReturn
|
||||
@ -80,7 +87,7 @@ gdk_x11_selection_output_stream_needs_flush_unlocked (GdkX11SelectionOutputStrea
|
||||
{
|
||||
GdkX11SelectionOutputStreamPrivate *priv = gdk_x11_selection_output_stream_get_instance_private (stream);
|
||||
|
||||
if (priv->data->len == 0)
|
||||
if (priv->data->len == 0 && priv->notify == NULL)
|
||||
return FALSE;
|
||||
|
||||
if (g_output_stream_is_closing (G_OUTPUT_STREAM (stream)))
|
||||
@ -148,7 +155,7 @@ gdk_x11_selection_output_stream_perform_flush (GdkX11SelectionOutputStream *stre
|
||||
element_size = get_element_size (priv->format);
|
||||
n_elements = priv->data->len / element_size;
|
||||
|
||||
if (!priv->started && !g_output_stream_is_closing (G_OUTPUT_STREAM (stream)))
|
||||
if (priv->notify && !g_output_stream_is_closing (G_OUTPUT_STREAM (stream)))
|
||||
{
|
||||
XWindowAttributes attrs;
|
||||
|
||||
@ -190,30 +197,10 @@ gdk_x11_selection_output_stream_perform_flush (GdkX11SelectionOutputStream *stre
|
||||
priv->flush_requested = FALSE;
|
||||
}
|
||||
|
||||
if (!priv->started)
|
||||
if (priv->notify)
|
||||
{
|
||||
XSelectionEvent xevent;
|
||||
|
||||
xevent.type = SelectionNotify;
|
||||
xevent.serial = 0;
|
||||
xevent.send_event = True;
|
||||
xevent.requestor = priv->xwindow;
|
||||
xevent.selection = priv->xselection;
|
||||
xevent.target = priv->xtarget;
|
||||
xevent.property = priv->xproperty;
|
||||
xevent.time = priv->timestamp;
|
||||
|
||||
if (XSendEvent (xdisplay, priv->xwindow, False, NoEventMask, (XEvent*) & xevent) == 0)
|
||||
{
|
||||
GDK_NOTE(SELECTION, g_printerr ("%s:%s: failed to XSendEvent()\n",
|
||||
priv->selection, priv->target));
|
||||
g_warning ("failed to XSendEvent()");
|
||||
}
|
||||
XSync (xdisplay, False);
|
||||
|
||||
GDK_NOTE(SELECTION, g_printerr ("%s:%s: sent SelectionNotify for %s on %s\n",
|
||||
priv->selection, priv->target, priv->target, priv->property));
|
||||
priv->started = TRUE;
|
||||
gdk_x11_pending_selection_notify_send (priv->notify, priv->display, TRUE);
|
||||
priv->notify = NULL;
|
||||
}
|
||||
|
||||
priv->delete_pending = TRUE;
|
||||
@ -475,6 +462,9 @@ gdk_x11_selection_output_stream_finalize (GObject *object)
|
||||
GdkX11SelectionOutputStream *stream = GDK_X11_SELECTION_OUTPUT_STREAM (object);
|
||||
GdkX11SelectionOutputStreamPrivate *priv = gdk_x11_selection_output_stream_get_instance_private (stream);
|
||||
|
||||
/* not sending a notify is terrible */
|
||||
g_assert (priv->notify == NULL);
|
||||
|
||||
g_byte_array_unref (priv->data);
|
||||
g_cond_clear (&priv->cond);
|
||||
g_mutex_clear (&priv->mutex);
|
||||
@ -550,14 +540,15 @@ gdk_x11_selection_output_stream_filter_event (GdkXEvent *xev,
|
||||
}
|
||||
|
||||
GOutputStream *
|
||||
gdk_x11_selection_output_stream_new (GdkDisplay *display,
|
||||
Window window,
|
||||
const char *selection,
|
||||
const char *target,
|
||||
const char *property,
|
||||
const char *type,
|
||||
int format,
|
||||
gulong timestamp)
|
||||
gdk_x11_selection_output_stream_new (GdkDisplay *display,
|
||||
GdkX11PendingSelectionNotify *notify,
|
||||
Window window,
|
||||
const char *selection,
|
||||
const char *target,
|
||||
const char *property,
|
||||
const char *type,
|
||||
int format,
|
||||
gulong timestamp)
|
||||
{
|
||||
GdkX11SelectionOutputStream *stream;
|
||||
GdkX11SelectionOutputStreamPrivate *priv;
|
||||
@ -567,6 +558,7 @@ gdk_x11_selection_output_stream_new (GdkDisplay *display,
|
||||
|
||||
priv->display = display;
|
||||
GDK_X11_DISPLAY (display)->streams = g_slist_prepend (GDK_X11_DISPLAY (display)->streams, stream);
|
||||
priv->notify = notify;
|
||||
priv->xwindow = window;
|
||||
priv->selection = g_strdup (selection);
|
||||
priv->xselection = gdk_x11_get_xatom_by_name_for_display (display, priv->selection);
|
||||
@ -580,6 +572,86 @@ gdk_x11_selection_output_stream_new (GdkDisplay *display,
|
||||
priv->timestamp = timestamp;
|
||||
|
||||
gdk_window_add_filter (NULL, gdk_x11_selection_output_stream_filter_event, stream);
|
||||
|
||||
|
||||
return G_OUTPUT_STREAM (stream);
|
||||
}
|
||||
|
||||
GdkX11PendingSelectionNotify *
|
||||
gdk_x11_pending_selection_notify_new (Window window,
|
||||
Atom selection,
|
||||
Atom target,
|
||||
Atom property,
|
||||
Time timestamp)
|
||||
{
|
||||
GdkX11PendingSelectionNotify *pending;
|
||||
|
||||
pending = g_slice_new0 (GdkX11PendingSelectionNotify);
|
||||
pending->n_pending = 1;
|
||||
|
||||
pending->xevent.type = SelectionNotify;
|
||||
pending->xevent.serial = 0;
|
||||
pending->xevent.send_event = True;
|
||||
pending->xevent.requestor = window;
|
||||
pending->xevent.selection = selection;
|
||||
pending->xevent.target = target;
|
||||
pending->xevent.property = property;
|
||||
pending->xevent.time = timestamp;
|
||||
|
||||
return pending;
|
||||
}
|
||||
|
||||
void
|
||||
gdk_x11_pending_selection_notify_require (GdkX11PendingSelectionNotify *notify,
|
||||
guint n_sends)
|
||||
{
|
||||
notify->n_pending += n_sends;
|
||||
}
|
||||
|
||||
void
|
||||
gdk_x11_pending_selection_notify_send (GdkX11PendingSelectionNotify *notify,
|
||||
GdkDisplay *display,
|
||||
gboolean success)
|
||||
{
|
||||
Display *xdisplay;
|
||||
int error;
|
||||
|
||||
notify->n_pending--;
|
||||
if (notify->n_pending)
|
||||
{
|
||||
GDK_NOTE(SELECTION, g_printerr ("%s:%s: not sending SelectionNotify yet, %zu streams still pending\n",
|
||||
gdk_x11_get_xatom_name_for_display (display, notify->xevent.selection),
|
||||
gdk_x11_get_xatom_name_for_display (display, notify->xevent.target),
|
||||
notify->n_pending));
|
||||
return;
|
||||
}
|
||||
|
||||
GDK_NOTE(SELECTION, g_printerr ("%s:%s: sending SelectionNotify reporting %s\n",
|
||||
gdk_x11_get_xatom_name_for_display (display, notify->xevent.selection),
|
||||
gdk_x11_get_xatom_name_for_display (display, notify->xevent.target),
|
||||
success ? "success" : "failure"));
|
||||
if (!success)
|
||||
notify->xevent.property = None;
|
||||
|
||||
xdisplay = gdk_x11_display_get_xdisplay (display);
|
||||
|
||||
gdk_x11_display_error_trap_push (display);
|
||||
|
||||
if (XSendEvent (xdisplay, notify->xevent.requestor, False, NoEventMask, (XEvent*) ¬ify->xevent) == 0)
|
||||
{
|
||||
GDK_NOTE(SELECTION, g_printerr ("%s:%s: failed to XSendEvent()\n",
|
||||
gdk_x11_get_xatom_name_for_display (display, notify->xevent.selection),
|
||||
gdk_x11_get_xatom_name_for_display (display, notify->xevent.target)));
|
||||
}
|
||||
XSync (xdisplay, False);
|
||||
|
||||
error = gdk_x11_display_error_trap_pop (display);
|
||||
if (error != Success)
|
||||
{
|
||||
GDK_NOTE(SELECTION, g_printerr ("%s:%s: X error during write: %d\n",
|
||||
gdk_x11_get_xatom_name_for_display (display, notify->xevent.selection),
|
||||
gdk_x11_get_xatom_name_for_display (display, notify->xevent.target),
|
||||
error));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -36,6 +36,8 @@ G_BEGIN_DECLS
|
||||
#define GDK_IS_X11_SELECTION_OUTPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GDK_TYPE_X11_SELECTION_OUTPUT_STREAM))
|
||||
#define GDK_X11_SELECTION_OUTPUT_STREAM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDK_TYPE_X11_SELECTION_OUTPUT_STREAM, GdkX11SelectionOutputStreamClass))
|
||||
|
||||
typedef struct _GdkX11PendingSelectionNotify GdkX11PendingSelectionNotify;
|
||||
|
||||
typedef struct GdkX11SelectionOutputStream GdkX11SelectionOutputStream;
|
||||
typedef struct GdkX11SelectionOutputStreamClass GdkX11SelectionOutputStreamClass;
|
||||
|
||||
@ -53,6 +55,7 @@ struct GdkX11SelectionOutputStreamClass
|
||||
GType gdk_x11_selection_output_stream_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GOutputStream * gdk_x11_selection_output_stream_new (GdkDisplay *display,
|
||||
GdkX11PendingSelectionNotify *notify,
|
||||
Window window,
|
||||
const char *selection,
|
||||
const char *target,
|
||||
@ -61,6 +64,17 @@ GOutputStream * gdk_x11_selection_output_stream_new (GdkDisplay
|
||||
int format,
|
||||
gulong timestamp);
|
||||
|
||||
GdkX11PendingSelectionNotify *
|
||||
gdk_x11_pending_selection_notify_new (Window window,
|
||||
Atom selection,
|
||||
Atom target,
|
||||
Atom property,
|
||||
Time timestamp);
|
||||
void gdk_x11_pending_selection_notify_require (GdkX11PendingSelectionNotify *notify,
|
||||
guint n_sends);
|
||||
void gdk_x11_pending_selection_notify_send (GdkX11PendingSelectionNotify *notify,
|
||||
GdkDisplay *display,
|
||||
gboolean success);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user