gtkselection.c 86.7 KB
Newer Older
Cody Russell's avatar
Cody Russell committed
1
/* GTK - The GIMP Toolkit
Elliot Lee's avatar
Elliot Lee committed
2
3
4
 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
 *
 * This library is free software; you can redistribute it and/or
5
 * modify it under the terms of the GNU Lesser General Public
Elliot Lee's avatar
Elliot Lee committed
6
7
8
9
10
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
12
 * Lesser General Public License for more details.
Elliot Lee's avatar
Elliot Lee committed
13
 *
14
 * You should have received a copy of the GNU Lesser General Public
Javier Jardón's avatar
Javier Jardón committed
15
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
Elliot Lee's avatar
Elliot Lee committed
16
17
 */

18
/* This file implements most of the work of the ICCCM selection protocol.
Elliot Lee's avatar
Elliot Lee committed
19
 * The code was written after an intensive study of the equivalent part
20
 * of John Ousterhout’s Tk toolkit, and does many things in much the 
Elliot Lee's avatar
Elliot Lee committed
21
22
 * same way.
 *
23
 * The one thing in the ICCCM that isn’t fully supported here (or in Tk)
Elliot Lee's avatar
Elliot Lee committed
24
25
26
27
28
 * is side effects targets. For these to be handled properly, MULTIPLE
 * targets need to be done in the order specified. This cannot be
 * guaranteed with the way we do things, since if we are doing INCR
 * transfers, the order will depend on the timing of the requestor.
 *
29
 * By Owen Taylor <owt1@cornell.edu>	      8/16/97
Elliot Lee's avatar
Elliot Lee committed
30
31
32
33
 */

/* Terminology note: when not otherwise specified, the term "incr" below
 * refers to the _sending_ part of the INCR protocol. The receiving
William Jon McCann's avatar
William Jon McCann committed
34
35
 * portion is referred to just as “retrieval”. (Terminology borrowed
 * from Tk, because there is no good opposite to “retrieval” in English.
36
 * “send” can’t be made into a noun gracefully and we’re already using
William Jon McCann's avatar
William Jon McCann committed
37
 * “emission” for something else ....)
Elliot Lee's avatar
Elliot Lee committed
38
39
40
41
42
43
44
 */

/* The MOTIF entry widget seems to ask for the TARGETS target, then
   (regardless of the reply) ask for the TEXT target. It's slightly
   possible though that it somehow thinks we are responding negatively
   to the TARGETS request, though I don't really think so ... */

45
/*
46
 * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
47
48
49
50
51
 * file for a list of people on the GTK+ Team.  See the ChangeLog
 * files for a list of changes.  These files are distributed with
 * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
 */

52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
/**
 * SECTION:gtkselection
 * @Title: Selections
 * @Short_description: Functions for handling inter-process communication
 *     via selections
 * @See_also: #GtkWidget - Much of the operation of selections happens via
 *     signals for #GtkWidget. In particular, if you are using the functions
 *     in this section, you may need to pay attention to
 *     #GtkWidget::selection-get, #GtkWidget::selection-received and
 *     #GtkWidget::selection-clear-event signals
 *
 * The selection mechanism provides the basis for different types
 * of communication between processes. In particular, drag and drop and
 * #GtkClipboard work via selections. You will very seldom or
 * never need to use most of the functions in this section directly;
 * #GtkClipboard provides a nicer interface to the same functionality.
 *
69
70
71
72
73
74
75
 * If an application is expected to exchange image data and work
 * on Windows, it is highly advised to support at least "image/bmp" target
 * for the widest possible compatibility with third-party applications.
 * #GtkClipboard already does that by using gtk_target_list_add_image_targets()
 * and gtk_selection_data_set_pixbuf() or gtk_selection_data_get_pixbuf(),
 * which is one of the reasons why it is advised to use #GtkClipboard.
 *
76
 * Some of the datatypes defined this section are used in
77
 * the #GtkClipboard and drag-and-drop API’s as well. The
78
 * #GtkTargetEntry and #GtkTargetList objects represent
79
80
81
82
83
84
 * lists of data types that are supported when sending or
 * receiving data. The #GtkSelectionData object is used to
 * store a chunk of data along with the data type and other
 * associated information.
 */

85
86
87
/* We are using deprecated API, here, and we know that */
#define GDK_DISABLE_DEPRECATION_WARNINGS

88
#include "config.h"
89
90
91
92

#include "gtkselection.h"
#include "gtkselectionprivate.h"

Elliot Lee's avatar
Elliot Lee committed
93
#include <stdarg.h>
94
#include <string.h>
95
96
#include "gdk.h"

Elliot Lee's avatar
Elliot Lee committed
97
#include "gtkmain.h"
Matthias Clasen's avatar
Matthias Clasen committed
98
#include "gtkdebug.h"
99
#include "gtktextbufferrichtext.h"
Matthias Clasen's avatar
Matthias Clasen committed
100
#include "gtkintl.h"
101
#include "gdk-pixbuf/gdk-pixbuf.h"
Elliot Lee's avatar
Elliot Lee committed
102

103
104
105
106
#ifdef GDK_WINDOWING_X11
#include "x11/gdkx.h"
#endif

107
108
109
110
#ifdef GDK_WINDOWING_WIN32
#include "win32/gdkwin32.h"
#endif

111
112
113
114
#ifdef GDK_WINDOWING_WAYLAND
#include <gdk/wayland/gdkwayland.h>
#endif

115
116
117
118
#ifdef GDK_WINDOWING_BROADWAY
#include "broadway/gdkbroadway.h"
#endif

Matthias Clasen's avatar
Matthias Clasen committed
119
#undef DEBUG_SELECTION
Elliot Lee's avatar
Elliot Lee committed
120
121
122

/* Maximum size of a sent chunk, in bytes. Also the default size of
   our buffers */
123
#ifdef GDK_WINDOWING_X11
124
#define GTK_SELECTION_MAX_SIZE(display)                                 \
125
  GDK_IS_X11_DISPLAY (display) ?                                        \
126
127
128
  MIN(262144,                                                           \
      XExtendedMaxRequestSize (GDK_DISPLAY_XDISPLAY (display)) == 0     \
       ? XMaxRequestSize (GDK_DISPLAY_XDISPLAY (display)) - 100         \
129
130
       : XExtendedMaxRequestSize (GDK_DISPLAY_XDISPLAY (display)) - 100)\
  : G_MAXINT
131
132
133
#else
/* No chunks on Win32 */
#define GTK_SELECTION_MAX_SIZE(display) G_MAXINT
134
#endif
Owen Taylor's avatar
Owen Taylor committed
135

136
#define IDLE_ABORT_TIME 30
Owen Taylor's avatar
Owen Taylor committed
137

Elliot Lee's avatar
Elliot Lee committed
138
139
140
141
142
enum {
  INCR,
  MULTIPLE,
  TARGETS,
  TIMESTAMP,
143
  SAVE_TARGETS,
Elliot Lee's avatar
Elliot Lee committed
144
145
146
147
148
149
150
151
152
153
  LAST_ATOM
};

typedef struct _GtkSelectionInfo GtkSelectionInfo;
typedef struct _GtkIncrConversion GtkIncrConversion;
typedef struct _GtkIncrInfo GtkIncrInfo;
typedef struct _GtkRetrievalInfo GtkRetrievalInfo;

struct _GtkSelectionInfo
{
154
155
156
157
  GdkAtom	 selection;
  GtkWidget	*widget;	/* widget that owns selection */
  guint32	 time;		/* time used to acquire selection */
  GdkDisplay	*display;	/* needed in gtk_selection_remove_all */    
Elliot Lee's avatar
Elliot Lee committed
158
159
160
161
};

struct _GtkIncrConversion 
{
162
163
  GdkAtom	    target;	/* Requested target */
  GdkAtom	    property;	/* Property to store in */
Elliot Lee's avatar
Elliot Lee committed
164
  GtkSelectionData  data;	/* The data being supplied */
165
  gint		    offset;	/* Current offset in sent selection.
Elliot Lee's avatar
Elliot Lee committed
166
167
				 *  -1 => All done
				 *  -2 => Only the final (empty) portion
168
				 *	  left to send */
Elliot Lee's avatar
Elliot Lee committed
169
170
171
172
173
174
175
};

struct _GtkIncrInfo
{
  GdkWindow *requestor;		/* Requestor window - we create a GdkWindow
				   so we can receive events */
  GdkAtom    selection;		/* Selection we're sending */
176
  
Elliot Lee's avatar
Elliot Lee committed
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
  GtkIncrConversion *conversions; /* Information about requested conversions -
				   * With MULTIPLE requests (benighted 1980's
				   * hardware idea), there can be more than
				   * one */
  gint num_conversions;
  gint num_incrs;		/* number of remaining INCR style transactions */
  guint32 idle_time;
};


struct _GtkRetrievalInfo
{
  GtkWidget *widget;
  GdkAtom selection;		/* Selection being retrieved. */
  GdkAtom target;		/* Form of selection that we requested */
  guint32 idle_time;		/* Number of seconds since we last heard
				   from selection owner */
  guchar   *buffer;		/* Buffer in which to accumulate results */
195
  gint	   offset;		/* Current offset in buffer, -1 indicates
Elliot Lee's avatar
Elliot Lee committed
196
				   not yet started */
197
  guint32 notify_time;		/* Timestamp from SelectionNotify */
Elliot Lee's avatar
Elliot Lee committed
198
199
200
};

/* Local Functions */
201
static void gtk_selection_init              (void);
202
203
static gboolean gtk_selection_incr_timeout      (GtkIncrInfo      *info);
static gboolean gtk_selection_retrieval_timeout (GtkRetrievalInfo *info);
204
205
206
207
208
209
210
211
212
213
214
215
static void gtk_selection_retrieval_report  (GtkRetrievalInfo *info,
					     GdkAtom           type,
					     gint              format,
					     guchar           *buffer,
					     gint              length,
					     guint32           time);
static void gtk_selection_invoke_handler    (GtkWidget        *widget,
					     GtkSelectionData *data,
					     guint             time);
static void gtk_selection_default_handler   (GtkWidget        *widget,
					     GtkSelectionData *data);
static int  gtk_selection_bytes_per_item    (gint              format);
Elliot Lee's avatar
Elliot Lee committed
216
217
218
219
220
221
222
223

/* Local Data */
static gint initialize = TRUE;
static GList *current_retrievals = NULL;
static GList *current_incrs = NULL;
static GList *current_selections = NULL;

static GdkAtom gtk_selection_atoms[LAST_ATOM];
224
static const char gtk_selection_handler_key[] = "gtk-selection-handlers";
Elliot Lee's avatar
Elliot Lee committed
225

226
227
228
229
230
231
232
233
/****************
 * Target Lists *
 ****************/

/*
 * Target lists
 */

234
235
236

/**
 * gtk_target_list_new:
237
238
 * @targets: (array length=ntargets) (allow-none): Pointer to an array
 *   of #GtkTargetEntry
239
 * @ntargets: number of entries in @targets.
240
241
242
 * 
 * Creates a new #GtkTargetList from an array of #GtkTargetEntry.
 * 
243
 * Returns: (transfer full): the new #GtkTargetList.
244
 **/
245
GtkTargetList *
246
247
gtk_target_list_new (const GtkTargetEntry *targets,
		     guint                 ntargets)
248
{
249
  GtkTargetList *result = g_slice_new (GtkTargetList);
250
251
252
253
254
255
256
257
258
  result->list = NULL;
  result->ref_count = 1;

  if (targets)
    gtk_target_list_add_table (result, targets, ntargets);
  
  return result;
}

259
260
261
262
263
264
/**
 * gtk_target_list_ref:
 * @list:  a #GtkTargetList
 * 
 * Increases the reference count of a #GtkTargetList by one.
 *
265
 * Returns: the passed in #GtkTargetList.
266
 **/
267
GtkTargetList *
268
269
gtk_target_list_ref (GtkTargetList *list)
{
270
  g_return_val_if_fail (list != NULL, NULL);
271

272
  list->ref_count++;
273
274

  return list;
275
276
}

277
278
279
280
281
282
283
/**
 * gtk_target_list_unref:
 * @list: a #GtkTargetList
 * 
 * Decreases the reference count of a #GtkTargetList by one.
 * If the resulting reference count is zero, frees the list.
 **/
284
285
286
void               
gtk_target_list_unref (GtkTargetList *list)
{
287
288
289
  g_return_if_fail (list != NULL);
  g_return_if_fail (list->ref_count > 0);

290
291
292
293
294
295
  list->ref_count--;
  if (list->ref_count == 0)
    {
      GList *tmp_list = list->list;
      while (tmp_list)
	{
Owen Taylor's avatar
Owen Taylor committed
296
	  GtkTargetPair *pair = tmp_list->data;
297
	  g_slice_free (GtkTargetPair, pair);
298
299
300

	  tmp_list = tmp_list->next;
	}
Owen Taylor's avatar
Owen Taylor committed
301
302
      
      g_list_free (list->list);
303
      g_slice_free (GtkTargetList, list);
304
305
306
    }
}

307
308
309
310
311
312
313
314
315
/**
 * gtk_target_list_add:
 * @list:  a #GtkTargetList
 * @target: the interned atom representing the target
 * @flags: the flags for this target
 * @info: an ID that will be passed back to the application
 * 
 * Appends another target to a #GtkTargetList.
 **/
316
317
void 
gtk_target_list_add (GtkTargetList *list,
318
319
320
		     GdkAtom        target,
		     guint          flags,
		     guint          info)
321
322
323
324
325
{
  GtkTargetPair *pair;

  g_return_if_fail (list != NULL);
  
326
  pair = g_slice_new (GtkTargetPair);
327
328
329
330
331
332
333
  pair->target = target;
  pair->flags = flags;
  pair->info = info;

  list->list = g_list_append (list->list, pair);
}

334
335
336
337
338
339
static GdkAtom utf8_atom;
static GdkAtom text_atom;
static GdkAtom ctext_atom;
static GdkAtom text_plain_atom;
static GdkAtom text_plain_utf8_atom;
static GdkAtom text_plain_locale_atom;
Matthias Clasen's avatar
Matthias Clasen committed
340
static GdkAtom text_uri_list_atom;
341
342
343
344
345
346
347
348
349

static void 
init_atoms (void)
{
  gchar *tmp;
  const gchar *charset;

  if (!utf8_atom)
    {
350
351
352
353
354
      utf8_atom = gdk_atom_intern_static_string ("UTF8_STRING");
      text_atom = gdk_atom_intern_static_string ("TEXT");
      ctext_atom = gdk_atom_intern_static_string ("COMPOUND_TEXT");
      text_plain_atom = gdk_atom_intern_static_string ("text/plain");
      text_plain_utf8_atom = gdk_atom_intern_static_string ("text/plain;charset=utf-8");
355
356
357
358
      g_get_charset (&charset);
      tmp = g_strdup_printf ("text/plain;charset=%s", charset);
      text_plain_locale_atom = gdk_atom_intern (tmp, FALSE);
      g_free (tmp);
Matthias Clasen's avatar
Matthias Clasen committed
359

360
      text_uri_list_atom = gdk_atom_intern_static_string ("text/uri-list");
361
362
363
364
365
366
    }
}

/**
 * gtk_target_list_add_text_targets:
 * @list: a #GtkTargetList
367
 * @info: an ID that will be passed back to the application
368
 * 
369
 * Appends the text targets supported by #GtkSelectionData to
370
 * the target list. All targets are added with the same @info.
371
372
373
374
 * 
 * Since: 2.6
 **/
void 
375
376
gtk_target_list_add_text_targets (GtkTargetList *list,
				  guint          info)
377
378
379
380
381
382
383
{
  g_return_if_fail (list != NULL);
  
  init_atoms ();

  /* Keep in sync with gtk_selection_data_targets_include_text()
   */
384
385
386
387
388
  gtk_target_list_add (list, utf8_atom, 0, info);  
  gtk_target_list_add (list, ctext_atom, 0, info);  
  gtk_target_list_add (list, text_atom, 0, info);  
  gtk_target_list_add (list, GDK_TARGET_STRING, 0, info);  
  gtk_target_list_add (list, text_plain_utf8_atom, 0, info);  
389
390
  if (!g_get_charset (NULL))
    gtk_target_list_add (list, text_plain_locale_atom, 0, info);  
391
  gtk_target_list_add (list, text_plain_atom, 0, info);  
392
393
}

394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
/**
 * gtk_target_list_add_rich_text_targets:
 * @list: a #GtkTargetList
 * @info: an ID that will be passed back to the application
 * @deserializable: if %TRUE, then deserializable rich text formats
 *                  will be added, serializable formats otherwise.
 * @buffer: a #GtkTextBuffer.
 *
 * Appends the rich text targets registered with
 * gtk_text_buffer_register_serialize_format() or
 * gtk_text_buffer_register_deserialize_format() to the target list. All
 * targets are added with the same @info.
 *
 * Since: 2.10
 **/
void
gtk_target_list_add_rich_text_targets (GtkTargetList  *list,
                                       guint           info,
                                       gboolean        deserializable,
                                       GtkTextBuffer  *buffer)
{
  GdkAtom *atoms;
  gint     n_atoms;
  gint     i;

  g_return_if_fail (list != NULL);
  g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));

  if (deserializable)
    atoms = gtk_text_buffer_get_deserialize_formats (buffer, &n_atoms);
  else
    atoms = gtk_text_buffer_get_serialize_formats (buffer, &n_atoms);

  for (i = 0; i < n_atoms; i++)
    gtk_target_list_add (list, atoms[i], 0, info);

  g_free (atoms);
}

433
434
435
/**
 * gtk_target_list_add_image_targets:
 * @list: a #GtkTargetList
436
 * @info: an ID that will be passed back to the application
437
438
439
 * @writable: whether to add only targets for which GTK+ knows
 *   how to convert a pixbuf into the format
 * 
440
 * Appends the image targets supported by #GtkSelectionData to
441
 * the target list. All targets are added with the same @info.
442
443
444
445
446
 * 
 * Since: 2.6
 **/
void 
gtk_target_list_add_image_targets (GtkTargetList *list,
447
				   guint          info,
448
449
450
451
452
453
454
455
456
457
				   gboolean       writable)
{
  GSList *formats, *f;
  gchar **mimes, **m;
  GdkAtom atom;

  g_return_if_fail (list != NULL);

  formats = gdk_pixbuf_get_formats ();

458
459
460
461
  /* Make sure png comes first */
  for (f = formats; f; f = f->next)
    {
      GdkPixbufFormat *fmt = f->data;
462
463
464
465
      gchar *name; 
 
      name = gdk_pixbuf_format_get_name (fmt);
      if (strcmp (name, "png") == 0)
466
467
468
469
	{
	  formats = g_slist_delete_link (formats, f);
	  formats = g_slist_prepend (formats, fmt);

470
471
	  g_free (name);

472
473
474
	  break;
	}

475
      g_free (name);
476
477
    }  

478
479
480
481
482
483
484
485
486
487
488
  for (f = formats; f; f = f->next)
    {
      GdkPixbufFormat *fmt = f->data;

      if (writable && !gdk_pixbuf_format_is_writable (fmt))
	continue;
      
      mimes = gdk_pixbuf_format_get_mime_types (fmt);
      for (m = mimes; *m; m++)
	{
	  atom = gdk_atom_intern (*m, FALSE);
489
	  gtk_target_list_add (list, atom, 0, info);  
490
491
492
493
494
495
496
	}
      g_strfreev (mimes);
    }

  g_slist_free (formats);
}

Matthias Clasen's avatar
Matthias Clasen committed
497
498
499
500
501
/**
 * gtk_target_list_add_uri_targets:
 * @list: a #GtkTargetList
 * @info: an ID that will be passed back to the application
 * 
502
 * Appends the URI targets supported by #GtkSelectionData to
Matthias Clasen's avatar
Matthias Clasen committed
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
 * the target list. All targets are added with the same @info.
 * 
 * Since: 2.6
 **/
void 
gtk_target_list_add_uri_targets (GtkTargetList *list,
				 guint          info)
{
  g_return_if_fail (list != NULL);
  
  init_atoms ();

  gtk_target_list_add (list, text_uri_list_atom, 0, info);  
}

518
519
520
/**
 * gtk_target_list_add_table:
 * @list: a #GtkTargetList
521
 * @targets: (array length=ntargets): the table of #GtkTargetEntry
522
523
524
525
 * @ntargets: number of targets in the table
 * 
 * Prepends a table of #GtkTargetEntry to a target list.
 **/
526
void               
527
528
529
gtk_target_list_add_table (GtkTargetList        *list,
			   const GtkTargetEntry *targets,
			   guint                 ntargets)
530
531
532
533
534
{
  gint i;

  for (i=ntargets-1; i >= 0; i--)
    {
535
      GtkTargetPair *pair = g_slice_new (GtkTargetPair);
536
537
538
539
540
541
542
543
      pair->target = gdk_atom_intern (targets[i].target, FALSE);
      pair->flags = targets[i].flags;
      pair->info = targets[i].info;
      
      list->list = g_list_prepend (list->list, pair);
    }
}

544
545
546
547
548
549
550
/**
 * gtk_target_list_remove:
 * @list: a #GtkTargetList
 * @target: the interned atom representing the target
 * 
 * Removes a target from a target list.
 **/
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
void 
gtk_target_list_remove (GtkTargetList *list,
			GdkAtom            target)
{
  GList *tmp_list;

  g_return_if_fail (list != NULL);

  tmp_list = list->list;
  while (tmp_list)
    {
      GtkTargetPair *pair = tmp_list->data;
      
      if (pair->target == target)
	{
566
	  g_slice_free (GtkTargetPair, pair);
567

568
	  list->list = g_list_remove_link (list->list, tmp_list);
569
570
571
572
573
574
575
576
577
	  g_list_free_1 (tmp_list);

	  return;
	}
      
      tmp_list = tmp_list->next;
    }
}

578
579
580
581
/**
 * gtk_target_list_find:
 * @list: a #GtkTargetList
 * @target: an interned atom representing the target to search for
582
583
 * @info: (out) (allow-none): a pointer to the location to store
 *        application info for target, or %NULL
584
 *
585
 * Looks up a given target in a #GtkTargetList.
586
 *
587
 * Returns: %TRUE if the target was found, otherwise %FALSE
588
 **/
589
590
591
592
593
gboolean
gtk_target_list_find (GtkTargetList *list,
		      GdkAtom        target,
		      guint         *info)
{
594
595
  GList *tmp_list;

Hans Breuer's avatar
Hans Breuer committed
596
  g_return_val_if_fail (list != NULL, FALSE);
597
598

  tmp_list = list->list;
599
600
601
602
603
604
  while (tmp_list)
    {
      GtkTargetPair *pair = tmp_list->data;

      if (pair->target == target)
	{
605
606
607
          if (info)
            *info = pair->info;

608
609
	  return TRUE;
	}
610

611
612
613
614
615
616
      tmp_list = tmp_list->next;
    }

  return FALSE;
}

617
618
619
/**
 * gtk_target_table_new_from_list:
 * @list: a #GtkTargetList
620
 * @n_targets: (out): return location for the number ot targets in the table
621
622
623
624
625
626
 *
 * This function creates an #GtkTargetEntry array that contains the
 * same targets as the passed %list. The returned table is newly
 * allocated and should be freed using gtk_target_table_free() when no
 * longer needed.
 *
627
 * Returns: (array length=n_targets) (transfer full): the new table.
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
 *
 * Since: 2.10
 **/
GtkTargetEntry *
gtk_target_table_new_from_list (GtkTargetList *list,
                                gint          *n_targets)
{
  GtkTargetEntry *targets;
  GList          *tmp_list;
  gint            i;

  g_return_val_if_fail (list != NULL, NULL);
  g_return_val_if_fail (n_targets != NULL, NULL);

  *n_targets = g_list_length (list->list);
  targets = g_new0 (GtkTargetEntry, *n_targets);

645
  for (tmp_list = list->list, i = 0; tmp_list; tmp_list = tmp_list->next, i++)
646
647
648
649
650
651
652
653
654
655
656
657
658
    {
      GtkTargetPair *pair = tmp_list->data;

      targets[i].target = gdk_atom_name (pair->target);
      targets[i].flags  = pair->flags;
      targets[i].info   = pair->info;
    }

  return targets;
}

/**
 * gtk_target_table_free:
659
 * @targets: (array length=n_targets): a #GtkTargetEntry array
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
 * @n_targets: the number of entries in the array
 *
 * This function frees a target table as returned by
 * gtk_target_table_new_from_list()
 *
 * Since: 2.10
 **/
void
gtk_target_table_free (GtkTargetEntry *targets,
                       gint            n_targets)
{
  gint i;

  g_return_if_fail (targets == NULL || n_targets > 0);

  for (i = 0; i < n_targets; i++)
    g_free (targets[i].target);

  g_free (targets);
}

681
682
/**
 * gtk_selection_owner_set_for_display:
683
684
 * @display: the #GdkDisplay where the selection is set
 * @widget: (allow-none): new selection owner (a #GtkWidget), or %NULL.
685
 * @selection: an interned atom representing the selection to claim.
686
 * @time_: timestamp with which to claim the selection
Elliot Lee's avatar
Elliot Lee committed
687
 *
688
689
690
 * Claim ownership of a given selection for a particular widget, or,
 * if @widget is %NULL, release ownership of the selection.
 *
691
 * Returns: TRUE if the operation succeeded 
Matthias Clasen's avatar
Matthias Clasen committed
692
693
 * 
 * Since: 2.2
694
 */
695
gboolean
696
697
698
699
gtk_selection_owner_set_for_display (GdkDisplay   *display,
				     GtkWidget    *widget,
				     GdkAtom       selection,
				     guint32       time)
Elliot Lee's avatar
Elliot Lee committed
700
701
702
{
  GList *tmp_list;
  GtkWidget *old_owner;
703
  GtkSelectionInfo *selection_info = NULL;
Elliot Lee's avatar
Elliot Lee committed
704
  GdkWindow *window;
705

706
  g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
707
  g_return_val_if_fail (selection != GDK_NONE, FALSE);
708
  g_return_val_if_fail (widget == NULL || gtk_widget_get_realized (widget), FALSE);
709
  g_return_val_if_fail (widget == NULL || gtk_widget_get_display (widget) == display, FALSE);
710
  
Elliot Lee's avatar
Elliot Lee committed
711
712
713
  if (widget == NULL)
    window = NULL;
  else
714
    window = gtk_widget_get_window (widget);
715

Elliot Lee's avatar
Elliot Lee committed
716
717
718
  tmp_list = current_selections;
  while (tmp_list)
    {
719
720
721
722
723
      if (((GtkSelectionInfo *)tmp_list->data)->selection == selection)
	{
	  selection_info = tmp_list->data;
	  break;
	}
Elliot Lee's avatar
Elliot Lee committed
724
725
726
      
      tmp_list = tmp_list->next;
    }
727
  
728
  if (gdk_selection_owner_set_for_display (display, window, selection, time, TRUE))
Elliot Lee's avatar
Elliot Lee committed
729
730
731
732
733
734
735
736
737
738
739
    {
      old_owner = NULL;
      
      if (widget == NULL)
	{
	  if (selection_info)
	    {
	      old_owner = selection_info->widget;
	      current_selections = g_list_remove_link (current_selections,
						       tmp_list);
	      g_list_free (tmp_list);
740
	      g_slice_free (GtkSelectionInfo, selection_info);
Elliot Lee's avatar
Elliot Lee committed
741
742
743
744
745
746
	    }
	}
      else
	{
	  if (selection_info == NULL)
	    {
747
	      selection_info = g_slice_new (GtkSelectionInfo);
Elliot Lee's avatar
Elliot Lee committed
748
749
750
	      selection_info->selection = selection;
	      selection_info->widget = widget;
	      selection_info->time = time;
751
752
	      selection_info->display = display;
	      current_selections = g_list_prepend (current_selections,
753
						   selection_info);
Elliot Lee's avatar
Elliot Lee committed
754
755
756
757
758
759
	    }
	  else
	    {
	      old_owner = selection_info->widget;
	      selection_info->widget = widget;
	      selection_info->time = time;
760
	      selection_info->display = display;
Elliot Lee's avatar
Elliot Lee committed
761
762
763
	    }
	}
      /* If another widget in the application lost the selection,
764
765
766
       *  send it a GDK_SELECTION_CLEAR event.
       */
      if (old_owner && old_owner != widget)
Elliot Lee's avatar
Elliot Lee committed
767
	{
768
	  GdkEvent *event = gdk_event_new (GDK_SELECTION_CLEAR);
769
770

          event->selection.window = g_object_ref (gtk_widget_get_window (old_owner));
771
772
	  event->selection.selection = selection;
	  event->selection.time = time;
773
	  
774
775
776
	  gtk_widget_event (old_owner, event);

	  gdk_event_free (event);
Elliot Lee's avatar
Elliot Lee committed
777
778
779
780
781
782
783
	}
      return TRUE;
    }
  else
    return FALSE;
}

784
785
/**
 * gtk_selection_owner_set:
Johan Dahlin's avatar
Johan Dahlin committed
786
 * @widget: (allow-none):  a #GtkWidget, or %NULL.
787
 * @selection:  an interned atom representing the selection to claim
788
 * @time_: timestamp with which to claim the selection
789
790
791
792
 * 
 * Claims ownership of a given selection for a particular widget,
 * or, if @widget is %NULL, release ownership of the selection.
 * 
793
 * Returns: %TRUE if the operation succeeded
794
795
796
797
798
799
 **/
gboolean
gtk_selection_owner_set (GtkWidget *widget,
			 GdkAtom    selection,
			 guint32    time)
{
800
801
  GdkDisplay *display;
  
802
  g_return_val_if_fail (widget == NULL || gtk_widget_get_realized (widget), FALSE);
803
  g_return_val_if_fail (selection != GDK_NONE, FALSE);
804
805
806
807
808
809
810
811

  if (widget)
    display = gtk_widget_get_display (widget);
  else
    {
      GTK_NOTE (MULTIHEAD,
		g_warning ("gtk_selection_owner_set (NULL,...) is not multihead safe"));
		 
Owen Taylor's avatar
Owen Taylor committed
812
      display = gdk_display_get_default ();
813
    }
814
  
815
816
  return gtk_selection_owner_set_for_display (display, widget,
					      selection, time);
817
818
}

819
typedef struct _GtkSelectionTargetList GtkSelectionTargetList;
820

821
822
823
824
825
826
827
828
struct _GtkSelectionTargetList {
  GdkAtom selection;
  GtkTargetList *list;
};

static GtkTargetList *
gtk_selection_target_list_get (GtkWidget    *widget,
			       GdkAtom       selection)
Elliot Lee's avatar
Elliot Lee committed
829
{
830
  GtkSelectionTargetList *sellist;
Elliot Lee's avatar
Elliot Lee committed
831
  GList *tmp_list;
832
833
  GList *lists;

Manish Singh's avatar
Manish Singh committed
834
  lists = g_object_get_data (G_OBJECT (widget), gtk_selection_handler_key);
835
  
836
  tmp_list = lists;
Elliot Lee's avatar
Elliot Lee committed
837
838
  while (tmp_list)
    {
839
840
841
      sellist = tmp_list->data;
      if (sellist->selection == selection)
	return sellist->list;
Elliot Lee's avatar
Elliot Lee committed
842
843
      tmp_list = tmp_list->next;
    }
844

845
  sellist = g_slice_new (GtkSelectionTargetList);
846
847
848
849
  sellist->selection = selection;
  sellist->list = gtk_target_list_new (NULL, 0);

  lists = g_list_prepend (lists, sellist);
Matthias Clasen's avatar
Matthias Clasen committed
850
  g_object_set_data (G_OBJECT (widget), I_(gtk_selection_handler_key), lists);
851
852
853
854
855
856
857
858
859
860
861

  return sellist->list;
}

static void
gtk_selection_target_list_remove (GtkWidget    *widget)
{
  GtkSelectionTargetList *sellist;
  GList *tmp_list;
  GList *lists;

Manish Singh's avatar
Manish Singh committed
862
  lists = g_object_get_data (G_OBJECT (widget), gtk_selection_handler_key);
863
  
864
865
  tmp_list = lists;
  while (tmp_list)
Elliot Lee's avatar
Elliot Lee committed
866
    {
867
868
869
870
      sellist = tmp_list->data;

      gtk_target_list_unref (sellist->list);

871
      g_slice_free (GtkSelectionTargetList, sellist);
872
      tmp_list = tmp_list->next;
Elliot Lee's avatar
Elliot Lee committed
873
    }
874
875

  g_list_free (lists);
Matthias Clasen's avatar
Matthias Clasen committed
876
  g_object_set_data (G_OBJECT (widget), I_(gtk_selection_handler_key), NULL);
877
878
}

879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
/**
 * gtk_selection_clear_targets:
 * @widget:    a #GtkWidget
 * @selection: an atom representing a selection
 *
 * Remove all targets registered for the given selection for the
 * widget.
 **/
void 
gtk_selection_clear_targets (GtkWidget *widget,
			     GdkAtom    selection)
{
  GtkSelectionTargetList *sellist;
  GList *tmp_list;
  GList *lists;

895
896
897
  g_return_if_fail (GTK_IS_WIDGET (widget));
  g_return_if_fail (selection != GDK_NONE);

898
899
#ifdef GDK_WINDOWING_WAYLAND
  if (GDK_IS_WAYLAND_DISPLAY (gtk_widget_get_display (widget)))
900
    gdk_wayland_selection_clear_targets (gtk_widget_get_display (widget), selection);
LRN's avatar
LRN committed
901
902
903
904
#endif
#ifdef GDK_WINDOWING_WIN32
  if (GDK_IS_WIN32_DISPLAY (gtk_widget_get_display (widget)))
    gdk_win32_selection_clear_targets (gtk_widget_get_display (widget), selection);
905
906
#endif

Manish Singh's avatar
Manish Singh committed
907
  lists = g_object_get_data (G_OBJECT (widget), gtk_selection_handler_key);
908
909
910
911
912
913
914
915
916
  
  tmp_list = lists;
  while (tmp_list)
    {
      sellist = tmp_list->data;
      if (sellist->selection == selection)
	{
	  lists = g_list_delete_link (lists, tmp_list);
	  gtk_target_list_unref (sellist->list);
917
	  g_slice_free (GtkSelectionTargetList, sellist);
918
919
920
921
922
923
924

	  break;
	}
      
      tmp_list = tmp_list->next;
    }
  
Matthias Clasen's avatar
Matthias Clasen committed
925
  g_object_set_data (G_OBJECT (widget), I_(gtk_selection_handler_key), lists);
926
927
}

928
929
/**
 * gtk_selection_add_target:
930
 * @widget:  a #GtkWidget
931
932
933
934
935
936
937
 * @selection: the selection
 * @target: target to add.
 * @info: A unsigned integer which will be passed back to the application.
 * 
 * Appends a specified target to the list of supported targets for a 
 * given widget and selection.
 **/
938
939
940
941
942
943
944
945
void 
gtk_selection_add_target (GtkWidget	    *widget, 
			  GdkAtom	     selection,
			  GdkAtom	     target,
			  guint              info)
{
  GtkTargetList *list;

946
947
  g_return_if_fail (GTK_IS_WIDGET (widget));
  g_return_if_fail (selection != GDK_NONE);
948
949
950

  list = gtk_selection_target_list_get (widget, selection);
  gtk_target_list_add (list, target, 0, info);
951
952
953
954
#ifdef GDK_WINDOWING_WAYLAND
  if (GDK_IS_WAYLAND_DISPLAY (gtk_widget_get_display (widget)))
    gdk_wayland_selection_add_targets (gtk_widget_get_window (widget), selection, 1, &target);
#endif
955
#ifdef GDK_WINDOWING_WIN32
956
957
  if (GDK_IS_WIN32_DISPLAY (gtk_widget_get_display (widget)))
    gdk_win32_selection_add_targets (gtk_widget_get_window (widget), selection, 1, &target);
958
#endif
959
960
}

961
962
963
964
/**
 * gtk_selection_add_targets:
 * @widget: a #GtkWidget
 * @selection: the selection
965
 * @targets: (array length=ntargets): a table of targets to add
966
967
968
969
970
 * @ntargets:  number of entries in @targets
 * 
 * Prepends a table of targets to the list of supported targets
 * for a given widget and selection.
 **/
971
void 
972
973
974
975
gtk_selection_add_targets (GtkWidget            *widget, 
			   GdkAtom               selection,
			   const GtkTargetEntry *targets,
			   guint                 ntargets)
976
977
{
  GtkTargetList *list;
978
979
980

  g_return_if_fail (GTK_IS_WIDGET (widget));
  g_return_if_fail (selection != GDK_NONE);
981
  g_return_if_fail (targets != NULL);
Elliot Lee's avatar
Elliot Lee committed
982
  
983
984
  list = gtk_selection_target_list_get (widget, selection);
  gtk_target_list_add_table (list, targets, ntargets);
985

986
987
988
989
990
991
992
993
994
995
996
997
998
999
#ifdef GDK_WINDOWING_WAYLAND
  if (GDK_IS_WAYLAND_DISPLAY (gtk_widget_get_display (widget)))
    {
      GdkAtom *atoms = g_new (GdkAtom, ntargets);
      guint i;

      for (i = 0; i < ntargets; i++)
        atoms[i] = gdk_atom_intern (targets[i].target, FALSE);

      gdk_wayland_selection_add_targets (gtk_widget_get_window (widget), selection, ntargets, atoms);
      g_free (atoms);
    }
#endif

1000
#ifdef GDK_WINDOWING_WIN32
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
  if (GDK_IS_WIN32_DISPLAY (gtk_widget_get_display (widget)))
    {
      int i;
      GdkAtom *atoms = g_new (GdkAtom, ntargets);

      for (i = 0; i < ntargets; ++i)
        atoms[i] = gdk_atom_intern (targets[i].target, FALSE);
      gdk_win32_selection_add_targets (gtk_widget_get_window (widget), selection, ntargets, atoms);
      g_free (atoms);
    }
1011
#endif
Elliot Lee's avatar
Elliot Lee committed
1012
1013
}

1014

1015
/**
Elliot Lee's avatar
Elliot Lee committed
1016
 * gtk_selection_remove_all:
1017
1018
1019
1020
1021
1022
1023
 * @widget: a #GtkWidget 
 * 
 * Removes all handlers and unsets ownership of all 
 * selections for a widget. Called when widget is being
 * destroyed. This function will not generally be
 * called by applications.
 **/
Elliot Lee's avatar
Elliot Lee committed
1024
1025
1026
1027
1028
1029
void
gtk_selection_remove_all (GtkWidget *widget)
{
  GList *tmp_list;
  GList *next;
  GtkSelectionInfo *selection_info;
1030
1031
1032

  g_return_if_fail (GTK_IS_WIDGET (widget));

Elliot Lee's avatar
Elliot Lee committed
1033
  /* Remove pending requests/incrs for this widget */
1034
  
Elliot Lee's avatar
Elliot Lee committed
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
  tmp_list = current_retrievals;
  while (tmp_list)
    {
      next = tmp_list->next;
      if (((GtkRetrievalInfo *)tmp_list->data)->widget == widget)
	{
	  current_retrievals = g_list_remove_link (current_retrievals, 
						   tmp_list);
	  /* structure will be freed in timeout */
	  g_list_free (tmp_list);
	}
      tmp_list = next;
    }
  
  /* Disclaim ownership of any selections */
1050
  
Elliot Lee's avatar
Elliot Lee committed
1051
1052
1053
1054
1055
1056
1057
1058
  tmp_list = current_selections;
  while (tmp_list)
    {
      next = tmp_list->next;
      selection_info = (GtkSelectionInfo *)tmp_list->data;
      
      if (selection_info->widget == widget)
	{	
1059
1060
1061
1062
1063
	  gdk_selection_owner_set_for_display (selection_info->display,
					       NULL, 
					       selection_info->selection,
				               GDK_CURRENT_TIME, FALSE);
	  current_selections = g_list_remove_link (current_selections,
Elliot Lee's avatar
Elliot Lee committed
1064
1065
						   tmp_list);
	  g_list_free (tmp_list);
1066
	  g_slice_free (GtkSelectionInfo, selection_info);
Elliot Lee's avatar
Elliot Lee committed
1067
1068
1069
1070
	}
      
      tmp_list = next;
    }
1071
1072
1073

  /* Remove all selection lists */
  gtk_selection_target_list_remove (widget);
Elliot Lee's avatar
Elliot Lee committed
1074
1075
1076
}


1077
1078
1079
1080
1081
1082
1083
1084
1085
/**
 * gtk_selection_convert:
 * @widget: The widget which acts as requestor
 * @selection: Which selection to get
 * @target: Form of information desired (e.g., STRING)
 * @time_: Time of request (usually of triggering event)
       In emergency, you could use #GDK_CURRENT_TIME
 * 
 * Requests the contents of a selection. When received, 
William Jon McCann's avatar
William Jon McCann committed
1086
 * a “selection-received” signal will be generated.
1087
 * 
1088
 * Returns: %TRUE if requested succeeded. %FALSE if we could not process
1089
1090
1091
 *          request. (e.g., there was already a request in process for
 *          this widget).
 **/
1092
gboolean
Elliot Lee's avatar
Elliot Lee committed
1093
gtk_selection_convert (GtkWidget *widget, 
1094
1095
		       GdkAtom	  selection, 
		       GdkAtom	  target,
1096
		       guint32	  time_)
Elliot Lee's avatar
Elliot Lee committed
1097
1098
1099
1100
{
  GtkRetrievalInfo *info;
  GList *tmp_list;
  GdkWindow *owner_window;
1101
  GdkDisplay *display;
Bastien Nocera's avatar
Bastien Nocera committed
1102
  guint id;
1103
  
1104
1105
  g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
  g_return_val_if_fail (selection != GDK_NONE, FALSE);
1106
  
Elliot Lee's avatar
Elliot Lee committed
1107
1108
1109
  if (initialize)
    gtk_selection_init ();
  
1110
  if (!gtk_widget_get_realized (widget))
Elliot Lee's avatar
Elliot Lee committed
1111
    gtk_widget_realize (widget);
1112
  
Elliot Lee's avatar
Elliot Lee committed
1113
1114
1115
1116
1117
  /* Check to see if there are already any retrievals in progress for
     this widget. If we changed GDK to use the selection for the 
     window property in which to store the retrieved information, then
     we could support multiple retrievals for different selections.
     This might be useful for DND. */
1118
  
Elliot Lee's avatar
Elliot Lee committed
1119
1120
1121
1122
1123
1124
1125
1126
  tmp_list = current_retrievals;
  while (tmp_list)
    {
      info = (GtkRetrievalInfo *)tmp_list->data;
      if (info->widget == widget)
	return FALSE;
      tmp_list = tmp_list->next;
    }
1127
  
1128
  info = g_slice_new (GtkRetrievalInfo);
1129
  
Elliot Lee's avatar
Elliot Lee committed
1130
1131
1132
  info->widget = widget;
  info->selection = selection;
  info->target = target;
Owen Taylor's avatar
Owen Taylor committed
1133
  info->idle_time = 0;
Elliot Lee's avatar
Elliot Lee committed
1134
1135
  info->buffer = NULL;
  info->offset = -1;
1136
  
Elliot Lee's avatar
Elliot Lee committed
1137
1138
  /* Check if this process has current owner. If so, call handler
     procedure directly to avoid deadlocks with INCR. */
1139
1140
1141

  display = gtk_widget_get_display (widget);
  owner_window = gdk_selection_owner_get_for_display (display, selection);
Elliot Lee's avatar
Elliot Lee committed
1142
  
1143
1144
1145
1146
1147
1148
1149
1150
1151
#ifdef GDK_WINDOWING_WIN32
  /* Special handling for DELETE requests,
   * make sure this goes down into GDK layer.
   */
  if (GDK_IS_WIN32_DISPLAY (display) &&
      target == gdk_atom_intern_static_string ("DELETE"))
    owner_window = NULL;
#endif

Elliot Lee's avatar
Elliot Lee committed
1152
1153
1154
  if (owner_window != NULL)
    {
      GtkWidget *owner_widget;
1155
      gpointer owner_widget_ptr;
1156
      GtkSelectionData selection_data = {0};
1157
      
Elliot Lee's avatar
Elliot Lee committed
1158
1159
1160
      selection_data.selection = selection;
      selection_data.target = target;
      selection_data.length = -1;
1161
      selection_data.display = display;
1162
      
1163
1164
      gdk_window_get_user_data (owner_window, &owner_widget_ptr);
      owner_widget = owner_widget_ptr;
1165
      
Elliot Lee's avatar
Elliot Lee committed
1166
1167
      if (owner_widget != NULL)
	{
1168
	  gtk_selection_invoke_handler (owner_widget, 
1169
					&selection_data,
1170
					time_);
1171
	  
Elliot Lee's avatar
Elliot Lee committed
1172
1173
1174
1175
	  gtk_selection_retrieval_report (info,
					  selection_data.type, 
					  selection_data.format,
					  selection_data.data,
1176
					  selection_data.length,
1177
					  time_);
1178
	  
Elliot Lee's avatar
Elliot Lee committed
1179
	  g_free (selection_data.data);
1180
1181
          selection_data.data = NULL;
          selection_data.length = -1;
Elliot Lee's avatar
Elliot Lee committed
1182
	  
1183
	  g_slice_free (GtkRetrievalInfo, info);
Elliot Lee's avatar
Elliot Lee committed
1184
1185
1186
	  return TRUE;
	}
    }
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205

#if defined GDK_WINDOWING_BROADWAY
  /* This patch is a workaround to circumvent unimplemented
     clipboard functionality in broadwayd. It eliminates
     35s delay on popup menu before first clipboard copy,
     by preventing conversion to be started.
   
     https://gitlab.gnome.org/GNOME/gtk/issues/1630
  */ 
  if (GDK_IS_BROADWAY_DISPLAY (display))
  {
      g_debug("gtk_selection_convert: disabled for broadway backend");

      gtk_selection_retrieval_report (
          info, GDK_NONE, 0, NULL, -1, GDK_CURRENT_TIME);

      return FALSE;
  }
#endif
Elliot Lee's avatar
Elliot Lee committed
1206
1207
  
  /* Otherwise, we need to go through X */
1208
  
Elliot Lee's avatar
Elliot Lee committed
1209
  current_retrievals = g_list_append (current_retrievals, info);
1210
  gdk_selection_convert (gtk_widget_get_window (widget), selection, target, time_);
Bastien Nocera's avatar
Bastien Nocera committed
1211
  id = gdk_threads_add_timeout (1000,
1212
      (GSourceFunc) gtk_selection_retrieval_timeout, info);
Bastien Nocera's avatar
Bastien Nocera committed
1213
  g_source_set_name_by_id (id, "[gtk+] gtk_selection_retrieval_timeout");
1214
  
Elliot Lee's avatar
Elliot Lee committed
1215
1216
1217
  return TRUE;
}

1218
1219
/**
 * gtk_selection_data_get_selection:
1220
 * @selection_data: a pointer to a #GtkSelectionData-struct.
1221
1222
1223
 *
 * Retrieves the selection #GdkAtom of the selection data.
 *
1224
 * Returns: (transfer none): the selection #GdkAtom of the selection data.
1225
1226
1227
1228
 *
 * Since: 2.16
 **/
GdkAtom
1229
gtk_selection_data_get_selection (const GtkSelectionData *selection_data)
1230
1231
1232
1233
1234
1235
{
  g_return_val_if_fail (selection_data != NULL, 0);

  return selection_data->selection;
}

Tim Janik's avatar
Tim Janik committed
1236
1237
/**
 * gtk_selection_data_get_target:
1238
 * @selection_data: a pointer to a #GtkSelectionData-struct.
Tim Janik's avatar
Tim Janik committed
1239
1240
1241
 *
 * Retrieves the target of the selection.
 *
1242
 * Returns: (transfer none): the target of the selection.
Matthias Clasen's avatar
2.13.5    
Matthias Clasen committed
1243
 *
1244
 * Since: 2.14
Tim Janik's avatar
Tim Janik committed
1245
 **/
1246
GdkAtom
1247
gtk_selection_data_get_target (const GtkSelectionData *selection_data)
Tim Janik's avatar
Tim Janik committed
1248
1249
1250
1251
1252
1253
1254
1255
{
  g_return_val_if_fail (selection_data != NULL, 0);

  return selection_data->target;
}

/**
 * gtk_selection_data_get_data_type:
1256
 * @selection_data: a pointer to a #GtkSelectionData-struct.
Tim Janik's avatar
Tim Janik committed
1257
1258
1259
 *
 * Retrieves the data type of the selection.
 *
1260
 * Returns: (transfer none): the data type of the selection.
Matthias Clasen's avatar
2.13.5    
Matthias Clasen committed
1261
 *
1262
 * Since: 2.14
Tim Janik's avatar
Tim Janik committed
1263
 **/
1264
GdkAtom
1265
gtk_selection_data_get_data_type (const GtkSelectionData *selection_data)
Tim Janik's avatar
Tim Janik committed
1266
1267
1268
1269
1270
1271
1272
1273
{
  g_return_val_if_fail (selection_data != NULL, 0);

  return selection_data->type;
}

/**
 * gtk_selection_data_get_format: