st: Reimplement StClipboard on top of MetaSelection
And stop using X11/gdk for this. https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/331
This commit is contained in:
parent
8572bb97c7
commit
1ebbd7c768
@ -863,6 +863,7 @@ _shell_global_set_plugin (ShellGlobal *global,
|
|||||||
}
|
}
|
||||||
|
|
||||||
st_entry_set_cursor_func (entry_cursor_func, global);
|
st_entry_set_cursor_func (entry_cursor_func, global);
|
||||||
|
st_clipboard_set_selection (meta_display_get_selection (display));
|
||||||
|
|
||||||
g_signal_connect (global->stage, "notify::width",
|
g_signal_connect (global->stage, "notify::width",
|
||||||
G_CALLBACK (global_stage_notify_width), global);
|
G_CALLBACK (global_stage_notify_width), global);
|
||||||
|
@ -125,7 +125,7 @@ st_cflags = [
|
|||||||
libst = shared_library('st-1.0',
|
libst = shared_library('st-1.0',
|
||||||
sources: st_gir_sources + st_non_gir_sources,
|
sources: st_gir_sources + st_non_gir_sources,
|
||||||
c_args: st_cflags,
|
c_args: st_cflags,
|
||||||
dependencies: [clutter_dep, gtk_dep, croco_dep, x11_dep, m_dep],
|
dependencies: [clutter_dep, gtk_dep, croco_dep, mutter_dep, m_dep],
|
||||||
build_rpath: mutter_typelibdir,
|
build_rpath: mutter_typelibdir,
|
||||||
install_rpath: mutter_typelibdir,
|
install_rpath: mutter_typelibdir,
|
||||||
install_dir: pkglibdir,
|
install_dir: pkglibdir,
|
||||||
@ -152,7 +152,7 @@ libst_gir = gnome.generate_gir(libst,
|
|||||||
sources: st_gir_sources,
|
sources: st_gir_sources,
|
||||||
nsversion: '1.0',
|
nsversion: '1.0',
|
||||||
namespace: 'St',
|
namespace: 'St',
|
||||||
includes: ['Clutter-' + mutter_api_version, 'Cally-' + mutter_api_version, 'Gtk-3.0'],
|
includes: ['Clutter-' + mutter_api_version, 'Cally-' + mutter_api_version, 'Meta-' + mutter_api_version, 'Gtk-3.0'],
|
||||||
dependencies: [mutter_dep],
|
dependencies: [mutter_dep],
|
||||||
include_directories: include_directories('..'),
|
include_directories: include_directories('..'),
|
||||||
extra_args: ['-DST_COMPILATION', '--quiet'],
|
extra_args: ['-DST_COMPILATION', '--quiet'],
|
||||||
|
@ -19,251 +19,49 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* SECTION:st-clipboard
|
* SECTION:st-clipboard
|
||||||
* @short_description: a simple representation of the X clipboard
|
* @short_description: a simple representation of the clipboard
|
||||||
*
|
*
|
||||||
* #StCliboard is a very simple object representation of the clipboard
|
* #StCliboard is a very simple object representation of the clipboard
|
||||||
* available to applications. Text is always assumed to be UTF-8 and non-text
|
* available to applications. Text is always assumed to be UTF-8 and non-text
|
||||||
* items are not handled.
|
* items are not handled.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
#include "st-clipboard.h"
|
#include "st-clipboard.h"
|
||||||
#include <X11/Xlib.h>
|
|
||||||
#include <X11/Xatom.h>
|
|
||||||
#include <gdk/gdk.h>
|
|
||||||
#include <gdk/gdkx.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
struct _StClipboardPrivate
|
#include <meta/display.h>
|
||||||
{
|
#include <meta/meta-selection-source-memory.h>
|
||||||
Window clipboard_window;
|
#include <meta/meta-selection.h>
|
||||||
gchar *clipboard_text;
|
|
||||||
|
|
||||||
Atom *supported_targets;
|
G_DEFINE_TYPE (StClipboard, st_clipboard, G_TYPE_OBJECT)
|
||||||
gint n_targets;
|
|
||||||
};
|
|
||||||
|
|
||||||
G_DEFINE_TYPE_WITH_PRIVATE (StClipboard, st_clipboard, G_TYPE_OBJECT)
|
typedef struct _TransferData TransferData;
|
||||||
|
struct _TransferData
|
||||||
typedef struct _EventFilterData EventFilterData;
|
|
||||||
struct _EventFilterData
|
|
||||||
{
|
{
|
||||||
StClipboard *clipboard;
|
StClipboard *clipboard;
|
||||||
StClipboardCallbackFunc callback;
|
StClipboardCallbackFunc callback;
|
||||||
gpointer user_data;
|
gpointer user_data;
|
||||||
|
GOutputStream *stream;
|
||||||
};
|
};
|
||||||
|
|
||||||
static Atom __atom_primary = None;
|
const char *supported_mimetypes[] = {
|
||||||
static Atom __atom_clip = None;
|
"text/plain;charset=utf-8",
|
||||||
static Atom __utf8_string = None;
|
"UTF8_STRING",
|
||||||
static Atom __atom_targets = None;
|
"text/plain",
|
||||||
|
"STRING",
|
||||||
static void
|
};
|
||||||
st_clipboard_dispose (GObject *object)
|
|
||||||
{
|
|
||||||
G_OBJECT_CLASS (st_clipboard_parent_class)->dispose (object);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
st_clipboard_finalize (GObject *object)
|
|
||||||
{
|
|
||||||
StClipboardPrivate *priv = ((StClipboard *) object)->priv;
|
|
||||||
|
|
||||||
g_free (priv->clipboard_text);
|
|
||||||
priv->clipboard_text = NULL;
|
|
||||||
|
|
||||||
g_free (priv->supported_targets);
|
|
||||||
priv->supported_targets = NULL;
|
|
||||||
priv->n_targets = 0;
|
|
||||||
|
|
||||||
G_OBJECT_CLASS (st_clipboard_parent_class)->finalize (object);
|
|
||||||
}
|
|
||||||
|
|
||||||
static GdkFilterReturn
|
|
||||||
st_clipboard_provider (GdkXEvent *xevent_p,
|
|
||||||
GdkEvent *gev,
|
|
||||||
void *user_data)
|
|
||||||
{
|
|
||||||
StClipboard *clipboard = user_data;
|
|
||||||
XEvent *xev = (XEvent *) xevent_p;
|
|
||||||
XSelectionEvent notify_event;
|
|
||||||
XSelectionRequestEvent *req_event;
|
|
||||||
GdkDisplay *display = gdk_display_get_default ();
|
|
||||||
|
|
||||||
if (xev->type != SelectionRequest ||
|
|
||||||
xev->xany.window != clipboard->priv->clipboard_window ||
|
|
||||||
!clipboard->priv->clipboard_text)
|
|
||||||
return GDK_FILTER_CONTINUE;
|
|
||||||
|
|
||||||
req_event = &xev->xselectionrequest;
|
|
||||||
|
|
||||||
gdk_x11_display_error_trap_push (display);
|
|
||||||
|
|
||||||
if (req_event->target == __atom_targets)
|
|
||||||
{
|
|
||||||
XChangeProperty (req_event->display,
|
|
||||||
req_event->requestor,
|
|
||||||
req_event->property,
|
|
||||||
XA_ATOM,
|
|
||||||
32,
|
|
||||||
PropModeReplace,
|
|
||||||
(guchar*) clipboard->priv->supported_targets,
|
|
||||||
clipboard->priv->n_targets);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
XChangeProperty (req_event->display,
|
|
||||||
req_event->requestor,
|
|
||||||
req_event->property,
|
|
||||||
req_event->target,
|
|
||||||
8,
|
|
||||||
PropModeReplace,
|
|
||||||
(guchar*) clipboard->priv->clipboard_text,
|
|
||||||
strlen (clipboard->priv->clipboard_text));
|
|
||||||
}
|
|
||||||
|
|
||||||
notify_event.type = SelectionNotify;
|
|
||||||
notify_event.display = req_event->display;
|
|
||||||
notify_event.requestor = req_event->requestor;
|
|
||||||
notify_event.selection = req_event->selection;
|
|
||||||
notify_event.target = req_event->target;
|
|
||||||
notify_event.time = req_event->time;
|
|
||||||
|
|
||||||
if (req_event->property == None)
|
|
||||||
notify_event.property = req_event->target;
|
|
||||||
else
|
|
||||||
notify_event.property = req_event->property;
|
|
||||||
|
|
||||||
/* notify the requestor that they have a copy of the selection */
|
|
||||||
XSendEvent (req_event->display, req_event->requestor, False, 0,
|
|
||||||
(XEvent *) ¬ify_event);
|
|
||||||
/* Make it happen non async */
|
|
||||||
XSync (GDK_DISPLAY_XDISPLAY (display), FALSE);
|
|
||||||
|
|
||||||
if (gdk_x11_display_error_trap_pop (display))
|
|
||||||
{
|
|
||||||
/* FIXME: Warn here on fail ? */
|
|
||||||
}
|
|
||||||
|
|
||||||
return GDK_FILTER_REMOVE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
static MetaSelection *meta_selection = NULL;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
st_clipboard_class_init (StClipboardClass *klass)
|
st_clipboard_class_init (StClipboardClass *klass)
|
||||||
{
|
{
|
||||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
||||||
|
|
||||||
object_class->dispose = st_clipboard_dispose;
|
|
||||||
object_class->finalize = st_clipboard_finalize;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
st_clipboard_init (StClipboard *self)
|
st_clipboard_init (StClipboard *self)
|
||||||
{
|
{
|
||||||
GdkDisplay *gdk_display;
|
|
||||||
Display *dpy;
|
|
||||||
StClipboardPrivate *priv;
|
|
||||||
|
|
||||||
priv = self->priv = st_clipboard_get_instance_private (self);
|
|
||||||
|
|
||||||
gdk_display = gdk_display_get_default ();
|
|
||||||
dpy = GDK_DISPLAY_XDISPLAY (gdk_display);
|
|
||||||
|
|
||||||
priv->clipboard_window =
|
|
||||||
XCreateSimpleWindow (dpy,
|
|
||||||
gdk_x11_get_default_root_xwindow (),
|
|
||||||
-1, -1, 1, 1, 0, 0, 0);
|
|
||||||
|
|
||||||
/* Only create once */
|
|
||||||
if (__atom_primary == None)
|
|
||||||
__atom_primary = XInternAtom (dpy, "PRIMARY", 0);
|
|
||||||
|
|
||||||
if (__atom_clip == None)
|
|
||||||
__atom_clip = XInternAtom (dpy, "CLIPBOARD", 0);
|
|
||||||
|
|
||||||
if (__utf8_string == None)
|
|
||||||
__utf8_string = XInternAtom (dpy, "UTF8_STRING", 0);
|
|
||||||
|
|
||||||
if (__atom_targets == None)
|
|
||||||
__atom_targets = XInternAtom (dpy, "TARGETS", 0);
|
|
||||||
|
|
||||||
priv->n_targets = 2;
|
|
||||||
priv->supported_targets = g_new (Atom, priv->n_targets);
|
|
||||||
|
|
||||||
priv->supported_targets[0] = __utf8_string;
|
|
||||||
priv->supported_targets[1] = __atom_targets;
|
|
||||||
|
|
||||||
gdk_window_add_filter (NULL, /* all windows */
|
|
||||||
st_clipboard_provider,
|
|
||||||
self);
|
|
||||||
}
|
|
||||||
|
|
||||||
static GdkFilterReturn
|
|
||||||
st_clipboard_x11_event_filter (GdkXEvent *xevent_p,
|
|
||||||
GdkEvent *gev,
|
|
||||||
void *user_data)
|
|
||||||
{
|
|
||||||
XEvent *xev = (XEvent *) xevent_p;
|
|
||||||
EventFilterData *filter_data = user_data;
|
|
||||||
StClipboardPrivate *priv = filter_data->clipboard->priv;
|
|
||||||
Atom actual_type;
|
|
||||||
int actual_format, result;
|
|
||||||
unsigned long nitems, bytes_after;
|
|
||||||
unsigned char *data = NULL;
|
|
||||||
GdkDisplay *display = gdk_display_get_default ();
|
|
||||||
|
|
||||||
if(xev->type != SelectionNotify ||
|
|
||||||
xev->xany.window != priv->clipboard_window)
|
|
||||||
return GDK_FILTER_CONTINUE;
|
|
||||||
|
|
||||||
if (xev->xselection.property == None)
|
|
||||||
{
|
|
||||||
/* clipboard empty */
|
|
||||||
filter_data->callback (filter_data->clipboard,
|
|
||||||
NULL,
|
|
||||||
filter_data->user_data);
|
|
||||||
|
|
||||||
gdk_window_remove_filter (NULL,
|
|
||||||
st_clipboard_x11_event_filter,
|
|
||||||
filter_data);
|
|
||||||
g_free (filter_data);
|
|
||||||
return GDK_FILTER_REMOVE;
|
|
||||||
}
|
|
||||||
|
|
||||||
gdk_x11_display_error_trap_push (display);
|
|
||||||
|
|
||||||
result = XGetWindowProperty (xev->xselection.display,
|
|
||||||
xev->xselection.requestor,
|
|
||||||
xev->xselection.property,
|
|
||||||
0L, G_MAXINT,
|
|
||||||
True,
|
|
||||||
AnyPropertyType,
|
|
||||||
&actual_type,
|
|
||||||
&actual_format,
|
|
||||||
&nitems,
|
|
||||||
&bytes_after,
|
|
||||||
&data);
|
|
||||||
|
|
||||||
if (gdk_x11_display_error_trap_pop (display) || result != Success)
|
|
||||||
{
|
|
||||||
/* FIXME: handle failure better */
|
|
||||||
g_warning ("Clipboard: prop retrival failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
filter_data->callback (filter_data->clipboard, (char*) data,
|
|
||||||
filter_data->user_data);
|
|
||||||
|
|
||||||
gdk_window_remove_filter (NULL,
|
|
||||||
st_clipboard_x11_event_filter,
|
|
||||||
filter_data);
|
|
||||||
|
|
||||||
g_free (filter_data);
|
|
||||||
|
|
||||||
if (data)
|
|
||||||
XFree (data);
|
|
||||||
|
|
||||||
return GDK_FILTER_REMOVE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -287,10 +85,57 @@ st_clipboard_get_default (void)
|
|||||||
return default_clipboard;
|
return default_clipboard;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Atom
|
static gboolean
|
||||||
atom_for_clipboard_type (StClipboardType type)
|
convert_type (StClipboardType type,
|
||||||
|
MetaSelectionType *type_out)
|
||||||
{
|
{
|
||||||
return type == ST_CLIPBOARD_TYPE_CLIPBOARD ? __atom_clip : __atom_primary;
|
if (type == ST_CLIPBOARD_TYPE_PRIMARY)
|
||||||
|
*type_out = META_SELECTION_PRIMARY;
|
||||||
|
else if (type == ST_CLIPBOARD_TYPE_CLIPBOARD)
|
||||||
|
*type_out = META_SELECTION_CLIPBOARD;
|
||||||
|
else
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
pick_mimetype (MetaSelection *meta_selection,
|
||||||
|
MetaSelectionType selection_type)
|
||||||
|
{
|
||||||
|
const char *selected_mimetype = NULL;
|
||||||
|
GList *mimetypes;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
mimetypes = meta_selection_get_mimetypes (meta_selection, selection_type);
|
||||||
|
|
||||||
|
for (i = 0; i < G_N_ELEMENTS (supported_mimetypes); i++)
|
||||||
|
{
|
||||||
|
if (g_list_find_custom (mimetypes, supported_mimetypes[i],
|
||||||
|
(GCompareFunc) g_strcmp0))
|
||||||
|
{
|
||||||
|
selected_mimetype = supported_mimetypes[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_list_free_full (mimetypes, g_free);
|
||||||
|
return selected_mimetype;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
transfer_cb (MetaSelection *selection,
|
||||||
|
GAsyncResult *res,
|
||||||
|
TransferData *data)
|
||||||
|
{
|
||||||
|
const gchar *text = NULL;
|
||||||
|
|
||||||
|
if (meta_selection_transfer_finish (selection, res, NULL))
|
||||||
|
text = g_memory_output_stream_get_data (G_MEMORY_OUTPUT_STREAM (data->stream));
|
||||||
|
|
||||||
|
data->callback (data->clipboard, text, data->user_data);
|
||||||
|
g_object_unref (data->stream);
|
||||||
|
g_free (data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -310,37 +155,35 @@ st_clipboard_get_text (StClipboard *clipboard,
|
|||||||
StClipboardCallbackFunc callback,
|
StClipboardCallbackFunc callback,
|
||||||
gpointer user_data)
|
gpointer user_data)
|
||||||
{
|
{
|
||||||
EventFilterData *data;
|
MetaSelectionType selection_type;
|
||||||
GdkDisplay *gdk_display;
|
TransferData *data;
|
||||||
Display *dpy;
|
const char *mimetype = NULL;
|
||||||
|
|
||||||
g_return_if_fail (ST_IS_CLIPBOARD (clipboard));
|
g_return_if_fail (ST_IS_CLIPBOARD (clipboard));
|
||||||
|
g_return_if_fail (meta_selection != NULL);
|
||||||
g_return_if_fail (callback != NULL);
|
g_return_if_fail (callback != NULL);
|
||||||
|
|
||||||
data = g_new0 (EventFilterData, 1);
|
if (convert_type (type, &selection_type))
|
||||||
|
mimetype = pick_mimetype (meta_selection, selection_type);
|
||||||
|
|
||||||
|
if (!mimetype)
|
||||||
|
{
|
||||||
|
callback (clipboard, NULL, user_data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
data = g_new0 (TransferData, 1);
|
||||||
data->clipboard = clipboard;
|
data->clipboard = clipboard;
|
||||||
data->callback = callback;
|
data->callback = callback;
|
||||||
data->user_data = user_data;
|
data->user_data = user_data;
|
||||||
|
data->stream = g_memory_output_stream_new_resizable ();
|
||||||
|
|
||||||
gdk_window_add_filter (NULL, /* all windows */
|
meta_selection_transfer_async (meta_selection,
|
||||||
st_clipboard_x11_event_filter,
|
selection_type,
|
||||||
|
mimetype, -1,
|
||||||
|
data->stream, NULL,
|
||||||
|
(GAsyncReadyCallback) transfer_cb,
|
||||||
data);
|
data);
|
||||||
|
|
||||||
gdk_display = gdk_display_get_default ();
|
|
||||||
dpy = GDK_DISPLAY_XDISPLAY (gdk_display);
|
|
||||||
|
|
||||||
gdk_x11_display_error_trap_push (gdk_display);
|
|
||||||
|
|
||||||
XConvertSelection (dpy,
|
|
||||||
atom_for_clipboard_type (type),
|
|
||||||
__utf8_string, __utf8_string,
|
|
||||||
clipboard->priv->clipboard_window,
|
|
||||||
CurrentTime);
|
|
||||||
|
|
||||||
if (gdk_x11_display_error_trap_pop (gdk_display))
|
|
||||||
{
|
|
||||||
/* FIXME */
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -356,31 +199,26 @@ st_clipboard_set_text (StClipboard *clipboard,
|
|||||||
StClipboardType type,
|
StClipboardType type,
|
||||||
const gchar *text)
|
const gchar *text)
|
||||||
{
|
{
|
||||||
StClipboardPrivate *priv;
|
MetaSelectionType selection_type;
|
||||||
GdkDisplay *gdk_display;
|
MetaSelectionSource *source;
|
||||||
Display *dpy;
|
GBytes *bytes;
|
||||||
|
|
||||||
g_return_if_fail (ST_IS_CLIPBOARD (clipboard));
|
g_return_if_fail (ST_IS_CLIPBOARD (clipboard));
|
||||||
|
g_return_if_fail (meta_selection != NULL);
|
||||||
g_return_if_fail (text != NULL);
|
g_return_if_fail (text != NULL);
|
||||||
|
|
||||||
priv = clipboard->priv;
|
if (!convert_type (type, &selection_type))
|
||||||
|
return;
|
||||||
|
|
||||||
/* make a copy of the text */
|
bytes = g_bytes_new_take (g_strdup (text), strlen (text));
|
||||||
g_free (priv->clipboard_text);
|
source = meta_selection_source_memory_new ("text/plain;charset=utf-8", bytes);
|
||||||
priv->clipboard_text = g_strdup (text);
|
g_bytes_unref (bytes);
|
||||||
|
|
||||||
/* tell X we own the clipboard selection */
|
meta_selection_set_owner (meta_selection, selection_type, source);
|
||||||
gdk_display = gdk_display_get_default ();
|
}
|
||||||
dpy = GDK_DISPLAY_XDISPLAY (gdk_display);
|
|
||||||
|
|
||||||
gdk_x11_display_error_trap_push (gdk_display);
|
void
|
||||||
|
st_clipboard_set_selection (MetaSelection *selection)
|
||||||
XSetSelectionOwner (dpy, atom_for_clipboard_type (type), priv->clipboard_window, CurrentTime);
|
|
||||||
|
|
||||||
XSync (dpy, FALSE);
|
|
||||||
|
|
||||||
if (gdk_x11_display_error_trap_pop (gdk_display))
|
|
||||||
{
|
{
|
||||||
/* FIXME */
|
meta_selection = selection;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
#define _ST_CLIPBOARD_H
|
#define _ST_CLIPBOARD_H
|
||||||
|
|
||||||
#include <glib-object.h>
|
#include <glib-object.h>
|
||||||
|
#include <meta/meta-selection.h>
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
@ -32,7 +33,6 @@ G_BEGIN_DECLS
|
|||||||
G_DECLARE_FINAL_TYPE (StClipboard, st_clipboard, ST, CLIPBOARD, GObject)
|
G_DECLARE_FINAL_TYPE (StClipboard, st_clipboard, ST, CLIPBOARD, GObject)
|
||||||
|
|
||||||
typedef struct _StClipboard StClipboard;
|
typedef struct _StClipboard StClipboard;
|
||||||
typedef struct _StClipboardPrivate StClipboardPrivate;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* StClipboard:
|
* StClipboard:
|
||||||
@ -44,7 +44,6 @@ struct _StClipboard
|
|||||||
{
|
{
|
||||||
/*< private >*/
|
/*< private >*/
|
||||||
GObject parent;
|
GObject parent;
|
||||||
StClipboardPrivate *priv;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@ -74,6 +73,8 @@ void st_clipboard_set_text (StClipboard *clipboard,
|
|||||||
StClipboardType type,
|
StClipboardType type,
|
||||||
const gchar *text);
|
const gchar *text);
|
||||||
|
|
||||||
|
void st_clipboard_set_selection (MetaSelection *selection);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
#endif /* _ST_CLIPBOARD_H */
|
#endif /* _ST_CLIPBOARD_H */
|
||||||
|
Loading…
Reference in New Issue
Block a user