~mterry/ubuntu/natty/gnome-shell/wip

« back to all changes in this revision

Viewing changes to src/st/st-clipboard.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastien Bacher
  • Date: 2009-10-12 22:44:00 UTC
  • mfrom: (1.1.5 upstream)
  • Revision ID: james.westby@ubuntu.com-20091012224400-k91p42yvou07i525
Tags: 2.28.0-0ubuntu1
* New upstream version
* debian/control:
  - updated build requirement
* debian/patches/80_git_change_fix_alt_tab_ressource_usage.patch:
  - git change to fix ressources not being freed on alt-tab

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
 
2
/*
 
3
 * st-clipboard.c: clipboard object
 
4
 *
 
5
 * Copyright 2009 Intel Corporation.
 
6
 *
 
7
 * This program is free software; you can redistribute it and/or modify it
 
8
 * under the terms and conditions of the GNU Lesser General Public License,
 
9
 * version 2.1, as published by the Free Software Foundation.
 
10
 *
 
11
 * This program is distributed in the hope it will be useful, but WITHOUT ANY
 
12
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 
13
 * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
 
14
 * more details.
 
15
 *
 
16
 * You should have received a copy of the GNU Lesser General Public License
 
17
 * along with this program; if not, write to the Free Software Foundation,
 
18
 * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
 
19
 *
 
20
 * Written by: Thomas Wood <thomas.wood@intel.com>
 
21
 *
 
22
 */
 
23
 
 
24
/**
 
25
 * SECTION:st-clipboard
 
26
 * @short_description: a simple representation of the X clipboard
 
27
 *
 
28
 * #StCliboard is a very simple object representation of the clipboard
 
29
 * available to applications. Text is always assumed to be UTF-8 and non-text
 
30
 * items are not handled.
 
31
 */
 
32
 
 
33
 
 
34
#include "st-clipboard.h"
 
35
#include <X11/Xlib.h>
 
36
#include <X11/Xatom.h>
 
37
#include <clutter/x11/clutter-x11.h>
 
38
#include <string.h>
 
39
 
 
40
G_DEFINE_TYPE (StClipboard, st_clipboard, G_TYPE_OBJECT)
 
41
 
 
42
#define CLIPBOARD_PRIVATE(o) \
 
43
  (G_TYPE_INSTANCE_GET_PRIVATE ((o), ST_TYPE_CLIPBOARD, StClipboardPrivate))
 
44
 
 
45
struct _StClipboardPrivate
 
46
{
 
47
  Window clipboard_window;
 
48
  gchar *clipboard_text;
 
49
 
 
50
  Atom  *supported_targets;
 
51
  gint   n_targets;
 
52
};
 
53
 
 
54
typedef struct _EventFilterData EventFilterData;
 
55
struct _EventFilterData
 
56
{
 
57
  StClipboard            *clipboard;
 
58
  StClipboardCallbackFunc callback;
 
59
  gpointer                user_data;
 
60
};
 
61
 
 
62
static Atom __atom_clip = None;
 
63
static Atom __utf8_string = None;
 
64
static Atom __atom_targets = None;
 
65
 
 
66
static void
 
67
st_clipboard_get_property (GObject    *object,
 
68
                           guint       property_id,
 
69
                           GValue     *value,
 
70
                           GParamSpec *pspec)
 
71
{
 
72
  switch (property_id)
 
73
    {
 
74
    default:
 
75
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 
76
    }
 
77
}
 
78
 
 
79
static void
 
80
st_clipboard_set_property (GObject      *object,
 
81
                           guint         property_id,
 
82
                           const GValue *value,
 
83
                           GParamSpec   *pspec)
 
84
{
 
85
  switch (property_id)
 
86
    {
 
87
    default:
 
88
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 
89
    }
 
90
}
 
91
 
 
92
static void
 
93
st_clipboard_dispose (GObject *object)
 
94
{
 
95
  G_OBJECT_CLASS (st_clipboard_parent_class)->dispose (object);
 
96
}
 
97
 
 
98
static void
 
99
st_clipboard_finalize (GObject *object)
 
100
{
 
101
  StClipboardPrivate *priv = ((StClipboard *) object)->priv;
 
102
 
 
103
  g_free (priv->clipboard_text);
 
104
  priv->clipboard_text = NULL;
 
105
 
 
106
  g_free (priv->supported_targets);
 
107
  priv->supported_targets = NULL;
 
108
  priv->n_targets = 0;
 
109
 
 
110
  G_OBJECT_CLASS (st_clipboard_parent_class)->finalize (object);
 
111
}
 
112
 
 
113
static ClutterX11FilterReturn
 
114
st_clipboard_provider (XEvent       *xev,
 
115
                       ClutterEvent *cev,
 
116
                       StClipboard  *clipboard)
 
117
{
 
118
  XSelectionEvent notify_event;
 
119
  XSelectionRequestEvent *req_event;
 
120
 
 
121
  if (xev->type != SelectionRequest)
 
122
    return CLUTTER_X11_FILTER_CONTINUE;
 
123
 
 
124
  req_event = &xev->xselectionrequest;
 
125
 
 
126
  clutter_x11_trap_x_errors ();
 
127
 
 
128
  if (req_event->target == __atom_targets)
 
129
    {
 
130
      XChangeProperty (req_event->display,
 
131
                       req_event->requestor,
 
132
                       req_event->property,
 
133
                       XA_ATOM,
 
134
                       32,
 
135
                       PropModeReplace,
 
136
                       (guchar*) clipboard->priv->supported_targets,
 
137
                       clipboard->priv->n_targets);
 
138
    }
 
139
  else
 
140
    {
 
141
      XChangeProperty (req_event->display,
 
142
                       req_event->requestor,
 
143
                       req_event->property,
 
144
                       req_event->target,
 
145
                       8,
 
146
                       PropModeReplace,
 
147
                       (guchar*) clipboard->priv->clipboard_text,
 
148
                       strlen (clipboard->priv->clipboard_text));
 
149
    }
 
150
 
 
151
  notify_event.type = SelectionNotify;
 
152
  notify_event.display = req_event->display;
 
153
  notify_event.requestor = req_event->requestor;
 
154
  notify_event.selection = req_event->selection;
 
155
  notify_event.target = req_event->target;
 
156
  notify_event.time = req_event->time;
 
157
 
 
158
  if (req_event->property == None)
 
159
    notify_event.property = req_event->target;
 
160
  else
 
161
    notify_event.property = req_event->property;
 
162
 
 
163
  /* notify the requestor that they have a copy of the selection */
 
164
  XSendEvent (req_event->display, req_event->requestor, False, 0,
 
165
              (XEvent *) &notify_event);
 
166
  /* Make it happen non async */
 
167
  XSync (clutter_x11_get_default_display(), FALSE);
 
168
 
 
169
  clutter_x11_untrap_x_errors (); /* FIXME: Warn here on fail ? */
 
170
 
 
171
  return CLUTTER_X11_FILTER_REMOVE;
 
172
}
 
173
 
 
174
 
 
175
static void
 
176
st_clipboard_class_init (StClipboardClass *klass)
 
177
{
 
178
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
179
 
 
180
  g_type_class_add_private (klass, sizeof (StClipboardPrivate));
 
181
 
 
182
  object_class->get_property = st_clipboard_get_property;
 
183
  object_class->set_property = st_clipboard_set_property;
 
184
  object_class->dispose = st_clipboard_dispose;
 
185
  object_class->finalize = st_clipboard_finalize;
 
186
}
 
187
 
 
188
static void
 
189
st_clipboard_init (StClipboard *self)
 
190
{
 
191
  Display *dpy;
 
192
  StClipboardPrivate *priv;
 
193
 
 
194
  priv = self->priv = CLIPBOARD_PRIVATE (self);
 
195
 
 
196
  priv->clipboard_window =
 
197
    XCreateSimpleWindow (clutter_x11_get_default_display (),
 
198
                         clutter_x11_get_root_window (),
 
199
                         -1, -1, 1, 1, 0, 0, 0);
 
200
 
 
201
  dpy = clutter_x11_get_default_display ();
 
202
 
 
203
  /* Only create once */
 
204
  if (__atom_clip == None)
 
205
    __atom_clip = XInternAtom (dpy, "CLIPBOARD", 0);
 
206
 
 
207
  if (__utf8_string == None)
 
208
    __utf8_string = XInternAtom (dpy, "UTF8_STRING", 0);
 
209
 
 
210
  if (__atom_targets == None)
 
211
    __atom_targets = XInternAtom (dpy, "TARGETS", 0);
 
212
 
 
213
  priv->n_targets = 2;
 
214
  priv->supported_targets = g_new (Atom, priv->n_targets);
 
215
 
 
216
  priv->supported_targets[0] = __utf8_string;
 
217
  priv->supported_targets[1] = __atom_targets;
 
218
 
 
219
  clutter_x11_add_filter ((ClutterX11FilterFunc) st_clipboard_provider,
 
220
                          self);
 
221
}
 
222
 
 
223
static ClutterX11FilterReturn
 
224
st_clipboard_x11_event_filter (XEvent          *xev,
 
225
                               ClutterEvent    *cev,
 
226
                               EventFilterData *filter_data)
 
227
{
 
228
  Atom actual_type;
 
229
  int actual_format, result;
 
230
  unsigned long nitems, bytes_after;
 
231
  unsigned char *data = NULL;
 
232
 
 
233
  if(xev->type != SelectionNotify)
 
234
    return CLUTTER_X11_FILTER_CONTINUE;
 
235
 
 
236
  if (xev->xselection.property == None)
 
237
    {
 
238
      /* clipboard empty */
 
239
      filter_data->callback (filter_data->clipboard,
 
240
                             NULL,
 
241
                             filter_data->user_data);
 
242
 
 
243
      clutter_x11_remove_filter ((ClutterX11FilterFunc) st_clipboard_x11_event_filter,
 
244
                                 filter_data);
 
245
      g_free (filter_data);
 
246
      return CLUTTER_X11_FILTER_REMOVE;
 
247
    }
 
248
 
 
249
  clutter_x11_trap_x_errors ();
 
250
 
 
251
  result = XGetWindowProperty (xev->xselection.display,
 
252
                               xev->xselection.requestor,
 
253
                               xev->xselection.property,
 
254
                               0L, G_MAXINT,
 
255
                               True,
 
256
                               AnyPropertyType,
 
257
                               &actual_type,
 
258
                               &actual_format,
 
259
                               &nitems,
 
260
                               &bytes_after,
 
261
                               &data);
 
262
 
 
263
  if (clutter_x11_untrap_x_errors () || result != Success)
 
264
    {
 
265
      /* FIXME: handle failure better */
 
266
      g_warning ("Clipboard: prop retrival failed");
 
267
    }
 
268
 
 
269
  filter_data->callback (filter_data->clipboard, (char*) data,
 
270
                         filter_data->user_data);
 
271
 
 
272
  clutter_x11_remove_filter
 
273
                          ((ClutterX11FilterFunc) st_clipboard_x11_event_filter,
 
274
                          filter_data);
 
275
 
 
276
  g_free (filter_data);
 
277
 
 
278
  if (data)
 
279
    XFree (data);
 
280
 
 
281
  return CLUTTER_X11_FILTER_REMOVE;
 
282
}
 
283
 
 
284
/**
 
285
 * st_clipboard_get_default:
 
286
 *
 
287
 * Get the global #StClipboard object that represents the clipboard.
 
288
 *
 
289
 * Returns: (transfer none): a #StClipboard owned by St and must not be
 
290
 * unrefferenced or freed.
 
291
 */
 
292
StClipboard*
 
293
st_clipboard_get_default (void)
 
294
{
 
295
  static StClipboard *default_clipboard = NULL;
 
296
 
 
297
  if (!default_clipboard)
 
298
    {
 
299
      default_clipboard = g_object_new (ST_TYPE_CLIPBOARD, NULL);
 
300
    }
 
301
 
 
302
  return default_clipboard;
 
303
}
 
304
 
 
305
/**
 
306
 * st_clipboard_get_text:
 
307
 * @clipboard: A #StCliboard
 
308
 * @callback: function to be called when the text is retreived
 
309
 * @user_data: data to be passed to the callback
 
310
 *
 
311
 * Request the data from the clipboard in text form. @callback is executed
 
312
 * when the data is retreived.
 
313
 *
 
314
 */
 
315
void
 
316
st_clipboard_get_text (StClipboard            *clipboard,
 
317
                       StClipboardCallbackFunc callback,
 
318
                       gpointer                user_data)
 
319
{
 
320
  EventFilterData *data;
 
321
 
 
322
  Display *dpy;
 
323
 
 
324
  g_return_if_fail (ST_IS_CLIPBOARD (clipboard));
 
325
  g_return_if_fail (callback != NULL);
 
326
 
 
327
  data = g_new0 (EventFilterData, 1);
 
328
  data->clipboard = clipboard;
 
329
  data->callback = callback;
 
330
  data->user_data = user_data;
 
331
 
 
332
  clutter_x11_add_filter ((ClutterX11FilterFunc) st_clipboard_x11_event_filter,
 
333
                          data);
 
334
 
 
335
  dpy = clutter_x11_get_default_display ();
 
336
 
 
337
  clutter_x11_trap_x_errors (); /* safety on */
 
338
 
 
339
  XConvertSelection (dpy,
 
340
                     __atom_clip,
 
341
                     __utf8_string, __utf8_string,
 
342
                     clipboard->priv->clipboard_window,
 
343
                     CurrentTime);
 
344
 
 
345
  clutter_x11_untrap_x_errors ();
 
346
}
 
347
 
 
348
/**
 
349
 * st_clipboard_set_text:
 
350
 * @clipboard: A #StClipboard
 
351
 * @text: text to copy to the clipboard
 
352
 *
 
353
 * Sets text as the current contents of the clipboard.
 
354
 *
 
355
 */
 
356
void
 
357
st_clipboard_set_text (StClipboard *clipboard,
 
358
                       const gchar *text)
 
359
{
 
360
  StClipboardPrivate *priv;
 
361
  Display *dpy;
 
362
 
 
363
  g_return_if_fail (ST_IS_CLIPBOARD (clipboard));
 
364
  g_return_if_fail (text != NULL);
 
365
 
 
366
  priv = clipboard->priv;
 
367
 
 
368
  /* make a copy of the text */
 
369
  g_free (priv->clipboard_text);
 
370
  priv->clipboard_text = g_strdup (text);
 
371
 
 
372
  /* tell X we own the clipboard selection */
 
373
  dpy = clutter_x11_get_default_display ();
 
374
 
 
375
  clutter_x11_trap_x_errors ();
 
376
 
 
377
  XSetSelectionOwner (dpy, __atom_clip, priv->clipboard_window, CurrentTime);
 
378
  XSync (dpy, FALSE);
 
379
 
 
380
  clutter_x11_untrap_x_errors ();
 
381
}