~ubuntu-branches/ubuntu/raring/gtk+2.0/raring-proposed

« back to all changes in this revision

Viewing changes to .pc/git_dnd_on_vnc.patch/gdk/x11/gdkdnd-x11.c

  • Committer: Package Import Robot
  • Author(s): Sebastien Bacher
  • Date: 2012-02-06 22:03:26 UTC
  • mfrom: (1.14.12)
  • Revision ID: package-import@ubuntu.com-20120206220326-10d7cnkpdpbi9iox
Tags: 2.24.10-0ubuntu1
* New upstream version, dropped patches included in the new version
* debian/patches/090_logging_file_saves.patch:
  - improve the logging of saved filed, thanks Siegfried Gevatter 
    (lp: #920961)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* GDK - The GIMP Drawing Kit
2
 
 * Copyright (C) 1995-1999 Peter Mattis, Spencer Kimball and Josh MacDonald
3
 
 *
4
 
 * This library is free software; you can redistribute it and/or
5
 
 * modify it under the terms of the GNU Lesser General Public
6
 
 * License as published by the Free Software Foundation; either
7
 
 * version 2 of the License, or (at your option) any later version.
8
 
 *
9
 
 * This library is distributed in the hope that it will be useful,
10
 
 * 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.
13
 
 *
14
 
 * You should have received a copy of the GNU Lesser General Public
15
 
 * License along with this library; if not, write to the
16
 
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17
 
 * Boston, MA 02111-1307, USA.
18
 
 */
19
 
 
20
 
/*
21
 
 * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22
 
 * file for a list of people on the GTK+ Team.  See the ChangeLog
23
 
 * files for a list of changes.  These files are distributed with
24
 
 * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
25
 
 */
26
 
 
27
 
#include "config.h"
28
 
 
29
 
#include <X11/Xlib.h>
30
 
#include <X11/Xutil.h>
31
 
#include <X11/Xatom.h>
32
 
#include <X11/extensions/shape.h>
33
 
#ifdef HAVE_XCOMPOSITE
34
 
#include <X11/extensions/Xcomposite.h>
35
 
#endif
36
 
 
37
 
#include <string.h>
38
 
 
39
 
#include "gdk.h"          /* For gdk_flush() */
40
 
#include "gdkx.h"
41
 
#include "gdkasync.h"
42
 
#include "gdkdnd.h"
43
 
#include "gdkproperty.h"
44
 
#include "gdkprivate-x11.h"
45
 
#include "gdkinternals.h"
46
 
#include "gdkscreen-x11.h"
47
 
#include "gdkdisplay-x11.h"
48
 
#include "gdkalias.h"
49
 
 
50
 
typedef struct _GdkDragContextPrivateX11 GdkDragContextPrivateX11;
51
 
 
52
 
typedef enum {
53
 
  GDK_DRAG_STATUS_DRAG,
54
 
  GDK_DRAG_STATUS_MOTION_WAIT,
55
 
  GDK_DRAG_STATUS_ACTION_WAIT,
56
 
  GDK_DRAG_STATUS_DROP
57
 
} GtkDragStatus;
58
 
 
59
 
typedef struct {
60
 
  guint32 xid;
61
 
  gint x, y, width, height;
62
 
  gboolean mapped;
63
 
  gboolean shape_selected;
64
 
  gboolean shape_valid;
65
 
  GdkRegion *shape;
66
 
} GdkCacheChild;
67
 
 
68
 
typedef struct {
69
 
  GList *children;
70
 
  GHashTable *child_hash;
71
 
  guint old_event_mask;
72
 
  GdkScreen *screen;
73
 
  gint ref_count;
74
 
} GdkWindowCache;
75
 
 
76
 
/* Structure that holds information about a drag in progress.
77
 
 * this is used on both source and destination sides.
78
 
 */
79
 
struct _GdkDragContextPrivateX11 {
80
 
  GdkDragContext context;
81
 
 
82
 
  Atom motif_selection;
83
 
  guint   ref_count;
84
 
 
85
 
  guint16 last_x;               /* Coordinates from last event */
86
 
  guint16 last_y;
87
 
  GdkDragAction old_action;       /* The last action we sent to the source */
88
 
  GdkDragAction old_actions;      /* The last actions we sent to the source */
89
 
  GdkDragAction xdnd_actions;     /* What is currently set in XdndActionList */
90
 
 
91
 
  Window dest_xid;              /* The last window we looked up */
92
 
  Window drop_xid;            /* The (non-proxied) window that is receiving drops */
93
 
  guint xdnd_targets_set : 1;   /* Whether we've already set XdndTypeList */
94
 
  guint xdnd_actions_set : 1;   /* Whether we've already set XdndActionList */
95
 
  guint xdnd_have_actions : 1;  /* Whether an XdndActionList was provided */
96
 
  guint motif_targets_set : 1;  /* Whether we've already set motif initiator info */
97
 
  guint drag_status : 4;        /* current status of drag */
98
 
  
99
 
  guint drop_failed : 1;        /* Whether the drop was unsuccessful */
100
 
  guint version;                /* Xdnd protocol version */
101
 
 
102
 
  GSList *window_caches;
103
 
};
104
 
 
105
 
#define PRIVATE_DATA(context) ((GdkDragContextPrivateX11 *) GDK_DRAG_CONTEXT (context)->windowing_data)
106
 
 
107
 
/* Forward declarations */
108
 
 
109
 
static GdkWindowCache *gdk_window_cache_get   (GdkScreen      *screen);
110
 
static GdkWindowCache *gdk_window_cache_ref   (GdkWindowCache *cache);
111
 
static void            gdk_window_cache_unref (GdkWindowCache *cache);
112
 
 
113
 
static void motif_read_target_table (GdkDisplay *display);
114
 
 
115
 
static GdkFilterReturn motif_dnd_filter (GdkXEvent *xev,
116
 
                                         GdkEvent  *event,
117
 
                                         gpointer   data);
118
 
 
119
 
static GdkFilterReturn xdnd_enter_filter    (GdkXEvent *xev,
120
 
                                             GdkEvent  *event,
121
 
                                             gpointer   data);
122
 
static GdkFilterReturn xdnd_leave_filter    (GdkXEvent *xev,
123
 
                                             GdkEvent  *event,
124
 
                                             gpointer   data);
125
 
static GdkFilterReturn xdnd_position_filter (GdkXEvent *xev,
126
 
                                             GdkEvent  *event,
127
 
                                             gpointer   data);
128
 
static GdkFilterReturn xdnd_status_filter   (GdkXEvent *xev,
129
 
                                             GdkEvent  *event,
130
 
                                             gpointer   data);
131
 
static GdkFilterReturn xdnd_finished_filter (GdkXEvent *xev,
132
 
                                             GdkEvent  *event,
133
 
                                             gpointer   data);
134
 
static GdkFilterReturn xdnd_drop_filter     (GdkXEvent *xev,
135
 
                                             GdkEvent  *event,
136
 
                                             gpointer   data);
137
 
 
138
 
static void   xdnd_manage_source_filter (GdkDragContext *context,
139
 
                                         GdkWindow      *window,
140
 
                                         gboolean        add_filter);
141
 
 
142
 
static void gdk_drag_context_finalize   (GObject              *object);
143
 
 
144
 
static GList *contexts;
145
 
static GSList *window_caches;
146
 
 
147
 
static const struct {
148
 
  const char *atom_name;
149
 
  GdkFilterFunc func;
150
 
} xdnd_filters[] = {
151
 
  { "XdndEnter",    xdnd_enter_filter },
152
 
  { "XdndLeave",    xdnd_leave_filter },
153
 
  { "XdndPosition", xdnd_position_filter },
154
 
  { "XdndStatus",   xdnd_status_filter },
155
 
  { "XdndFinished", xdnd_finished_filter },
156
 
  { "XdndDrop",     xdnd_drop_filter },
157
 
};
158
 
              
159
 
G_DEFINE_TYPE (GdkDragContext, gdk_drag_context, G_TYPE_OBJECT)
160
 
 
161
 
static void
162
 
gdk_drag_context_init (GdkDragContext *dragcontext)
163
 
{
164
 
  GdkDragContextPrivateX11 *private;
165
 
 
166
 
  private = G_TYPE_INSTANCE_GET_PRIVATE (dragcontext, 
167
 
                                         GDK_TYPE_DRAG_CONTEXT, 
168
 
                                         GdkDragContextPrivateX11);
169
 
  
170
 
  dragcontext->windowing_data = private;
171
 
 
172
 
  contexts = g_list_prepend (contexts, dragcontext);
173
 
}
174
 
 
175
 
static void
176
 
gdk_drag_context_class_init (GdkDragContextClass *klass)
177
 
{
178
 
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
179
 
 
180
 
  object_class->finalize = gdk_drag_context_finalize;
181
 
 
182
 
  g_type_class_add_private (object_class, sizeof (GdkDragContextPrivateX11));
183
 
}
184
 
 
185
 
static void
186
 
gdk_drag_context_finalize (GObject *object)
187
 
{
188
 
  GdkDragContext *context = GDK_DRAG_CONTEXT (object);
189
 
  GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
190
 
  
191
 
  g_list_free (context->targets);
192
 
 
193
 
  if (context->source_window)
194
 
    {
195
 
      if ((context->protocol == GDK_DRAG_PROTO_XDND) &&
196
 
          !context->is_source)
197
 
        xdnd_manage_source_filter (context, context->source_window, FALSE);
198
 
      
199
 
      g_object_unref (context->source_window);
200
 
    }
201
 
  
202
 
  if (context->dest_window)
203
 
    g_object_unref (context->dest_window);
204
 
 
205
 
  g_slist_free_full (private->window_caches, (GDestroyNotify)gdk_window_cache_unref);
206
 
  private->window_caches = NULL;
207
 
  
208
 
  contexts = g_list_remove (contexts, context);
209
 
 
210
 
  G_OBJECT_CLASS (gdk_drag_context_parent_class)->finalize (object);
211
 
}
212
 
 
213
 
/* Drag Contexts */
214
 
 
215
 
/**
216
 
 * gdk_drag_context_new:
217
 
 * 
218
 
 * Creates a new #GdkDragContext.
219
 
 * 
220
 
 * Return value: the newly created #GdkDragContext.
221
 
 *
222
 
 * Deprecated: 2.24: This function is not useful, you always
223
 
 *   obtain drag contexts by gdk_drag_begin() or similar.
224
 
 **/
225
 
GdkDragContext *
226
 
gdk_drag_context_new (void)
227
 
{
228
 
  return g_object_new (GDK_TYPE_DRAG_CONTEXT, NULL);
229
 
}
230
 
 
231
 
/**
232
 
 * gdk_drag_context_ref:
233
 
 * @context: a #GdkDragContext.
234
 
 *
235
 
 * Deprecated function; use g_object_ref() instead.
236
 
 *
237
 
 * Deprecated: 2.2: Use g_object_ref() instead.
238
 
 **/
239
 
void            
240
 
gdk_drag_context_ref (GdkDragContext *context)
241
 
{
242
 
  g_return_if_fail (GDK_IS_DRAG_CONTEXT (context));
243
 
 
244
 
  g_object_ref (context);
245
 
}
246
 
 
247
 
/**
248
 
 * gdk_drag_context_unref:
249
 
 * @context: a #GdkDragContext.
250
 
 *
251
 
 * Deprecated function; use g_object_unref() instead.
252
 
 *
253
 
 * Deprecated: 2.2: Use g_object_unref() instead.
254
 
 **/
255
 
void            
256
 
gdk_drag_context_unref (GdkDragContext *context)
257
 
{
258
 
  g_return_if_fail (GDK_IS_DRAG_CONTEXT (context));
259
 
 
260
 
  g_object_unref (context);
261
 
}
262
 
 
263
 
static GdkDragContext *
264
 
gdk_drag_context_find (GdkDisplay *display,
265
 
                       gboolean    is_source,
266
 
                       Window      source_xid,
267
 
                       Window      dest_xid)
268
 
{
269
 
  GList *tmp_list = contexts;
270
 
  GdkDragContext *context;
271
 
  GdkDragContextPrivateX11 *private;
272
 
  Window context_dest_xid;
273
 
 
274
 
  while (tmp_list)
275
 
    {
276
 
      context = (GdkDragContext *)tmp_list->data;
277
 
      private = PRIVATE_DATA (context);
278
 
 
279
 
      if ((context->source_window && gdk_drawable_get_display (context->source_window) != display) ||
280
 
          (context->dest_window && gdk_drawable_get_display (context->dest_window) != display))
281
 
        continue;
282
 
 
283
 
      context_dest_xid = context->dest_window ? 
284
 
                            (private->drop_xid ?
285
 
                              private->drop_xid :
286
 
                              GDK_DRAWABLE_XID (context->dest_window)) :
287
 
                             None;
288
 
 
289
 
      if ((!context->is_source == !is_source) &&
290
 
          ((source_xid == None) || (context->source_window &&
291
 
            (GDK_DRAWABLE_XID (context->source_window) == source_xid))) &&
292
 
          ((dest_xid == None) || (context_dest_xid == dest_xid)))
293
 
        return context;
294
 
      
295
 
      tmp_list = tmp_list->next;
296
 
    }
297
 
  
298
 
  return NULL;
299
 
}
300
 
 
301
 
static void
302
 
precache_target_list (GdkDragContext *context)
303
 
{
304
 
  if (context->targets)
305
 
    {
306
 
      GPtrArray *targets = g_ptr_array_new ();
307
 
      GList *tmp_list;
308
 
      int i;
309
 
 
310
 
      for (tmp_list = context->targets; tmp_list; tmp_list = tmp_list->next)
311
 
        g_ptr_array_add (targets, gdk_atom_name (GDK_POINTER_TO_ATOM (tmp_list->data)));
312
 
 
313
 
      _gdk_x11_precache_atoms (GDK_WINDOW_DISPLAY (context->source_window),
314
 
                               (const gchar **)targets->pdata,
315
 
                               targets->len);
316
 
 
317
 
      for (i =0; i < targets->len; i++)
318
 
        g_free (targets->pdata[i]);
319
 
 
320
 
      g_ptr_array_free (targets, TRUE);
321
 
    }
322
 
}
323
 
 
324
 
/* Utility functions */
325
 
 
326
 
static void
327
 
free_cache_child (GdkCacheChild *child,
328
 
                  GdkDisplay    *display)
329
 
{
330
 
  if (child->shape)
331
 
    gdk_region_destroy (child->shape);
332
 
 
333
 
  if (child->shape_selected && display)
334
 
    {
335
 
      GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
336
 
 
337
 
      XShapeSelectInput (display_x11->xdisplay, child->xid, 0);
338
 
    }
339
 
 
340
 
  g_free (child);
341
 
}
342
 
 
343
 
static void
344
 
gdk_window_cache_add (GdkWindowCache *cache,
345
 
                      guint32 xid,
346
 
                      gint x, gint y, gint width, gint height, 
347
 
                      gboolean mapped)
348
 
{
349
 
  GdkCacheChild *child = g_new (GdkCacheChild, 1);
350
 
 
351
 
  child->xid = xid;
352
 
  child->x = x;
353
 
  child->y = y;
354
 
  child->width = width;
355
 
  child->height = height;
356
 
  child->mapped = mapped;
357
 
  child->shape_selected = FALSE;
358
 
  child->shape_valid = FALSE;
359
 
  child->shape = NULL;
360
 
 
361
 
  cache->children = g_list_prepend (cache->children, child);
362
 
  g_hash_table_insert (cache->child_hash, GUINT_TO_POINTER (xid), 
363
 
                       cache->children);
364
 
}
365
 
 
366
 
static GdkFilterReturn
367
 
gdk_window_cache_shape_filter (GdkXEvent *xev,
368
 
                               GdkEvent  *event,
369
 
                               gpointer   data)
370
 
{
371
 
  XEvent *xevent = (XEvent *)xev;
372
 
  GdkWindowCache *cache = data;
373
 
 
374
 
  GdkDisplayX11 *display = GDK_DISPLAY_X11 (gdk_screen_get_display (cache->screen));
375
 
 
376
 
  if (display->have_shapes &&
377
 
      xevent->type == display->shape_event_base + ShapeNotify)
378
 
    {
379
 
      XShapeEvent *xse = (XShapeEvent*)xevent;
380
 
      GList *node;
381
 
 
382
 
      node = g_hash_table_lookup (cache->child_hash,
383
 
                                  GUINT_TO_POINTER (xse->window));
384
 
      if (node)
385
 
        {
386
 
          GdkCacheChild *child = node->data;
387
 
          child->shape_valid = FALSE;
388
 
          if (child->shape)
389
 
            {
390
 
              gdk_region_destroy (child->shape);
391
 
              child->shape = NULL;
392
 
            }
393
 
        }
394
 
 
395
 
      return GDK_FILTER_REMOVE;
396
 
    }
397
 
 
398
 
  return GDK_FILTER_CONTINUE;
399
 
}
400
 
 
401
 
static GdkFilterReturn
402
 
gdk_window_cache_filter (GdkXEvent *xev,
403
 
                         GdkEvent  *event,
404
 
                         gpointer   data)
405
 
{
406
 
  XEvent *xevent = (XEvent *)xev;
407
 
  GdkWindowCache *cache = data;
408
 
 
409
 
  switch (xevent->type)
410
 
    {
411
 
    case CirculateNotify:
412
 
      break;
413
 
    case ConfigureNotify:
414
 
      {
415
 
        XConfigureEvent *xce = &xevent->xconfigure;
416
 
        GList *node;
417
 
 
418
 
        node = g_hash_table_lookup (cache->child_hash, 
419
 
                                    GUINT_TO_POINTER (xce->window));
420
 
        if (node) 
421
 
          {
422
 
            GdkCacheChild *child = node->data;
423
 
            child->x = xce->x; 
424
 
            child->y = xce->y;
425
 
            child->width = xce->width; 
426
 
            child->height = xce->height;
427
 
            if (xce->above == None && (node->next))
428
 
              {
429
 
                GList *last = g_list_last (cache->children);
430
 
                cache->children = g_list_remove_link (cache->children, node);
431
 
                last->next = node;
432
 
                node->next = NULL;
433
 
                node->prev = last;
434
 
              }
435
 
            else
436
 
              {
437
 
                GList *above_node = g_hash_table_lookup (cache->child_hash, 
438
 
                                                         GUINT_TO_POINTER (xce->above));
439
 
                if (above_node && node->next != above_node)
440
 
                  {
441
 
                    /* Put the window above (before in the list) above_node
442
 
                     */
443
 
                    cache->children = g_list_remove_link (cache->children, node);
444
 
                    node->prev = above_node->prev;
445
 
                    if (node->prev)
446
 
                      node->prev->next = node;
447
 
                    else
448
 
                      cache->children = node;
449
 
                    node->next = above_node;
450
 
                    above_node->prev = node;
451
 
                  }
452
 
              }
453
 
          }
454
 
        break;
455
 
      }
456
 
    case CreateNotify:
457
 
      {
458
 
        XCreateWindowEvent *xcwe = &xevent->xcreatewindow;
459
 
 
460
 
        if (!g_hash_table_lookup (cache->child_hash, 
461
 
                                  GUINT_TO_POINTER (xcwe->window))) 
462
 
          gdk_window_cache_add (cache, xcwe->window, 
463
 
                                xcwe->x, xcwe->y, xcwe->width, xcwe->height,
464
 
                                FALSE);
465
 
        break;
466
 
      }
467
 
    case DestroyNotify:
468
 
      {
469
 
        XDestroyWindowEvent *xdwe = &xevent->xdestroywindow;
470
 
        GList *node;
471
 
 
472
 
        node = g_hash_table_lookup (cache->child_hash, 
473
 
                                    GUINT_TO_POINTER (xdwe->window));
474
 
        if (node) 
475
 
          {
476
 
            GdkCacheChild *child = node->data;
477
 
 
478
 
            g_hash_table_remove (cache->child_hash,
479
 
                                 GUINT_TO_POINTER (xdwe->window));
480
 
            cache->children = g_list_remove_link (cache->children, node);
481
 
            /* window is destroyed, no need to disable ShapeNotify */
482
 
            free_cache_child (child, NULL);
483
 
            g_list_free_1 (node);
484
 
          }
485
 
        break;
486
 
      }
487
 
    case MapNotify:
488
 
      {
489
 
        XMapEvent *xme = &xevent->xmap;
490
 
        GList *node;
491
 
 
492
 
        node = g_hash_table_lookup (cache->child_hash, 
493
 
                                    GUINT_TO_POINTER (xme->window));
494
 
        if (node) 
495
 
          {
496
 
            GdkCacheChild *child = node->data;
497
 
            child->mapped = TRUE;
498
 
          }
499
 
        break;
500
 
      }
501
 
    case ReparentNotify:
502
 
      break;
503
 
    case UnmapNotify:
504
 
      {
505
 
        XMapEvent *xume = &xevent->xmap;
506
 
        GList *node;
507
 
 
508
 
        node = g_hash_table_lookup (cache->child_hash, 
509
 
                                    GUINT_TO_POINTER (xume->window));
510
 
        if (node)
511
 
          {
512
 
            GdkCacheChild *child = node->data;
513
 
            child->mapped = FALSE;
514
 
          }
515
 
        break;
516
 
      }
517
 
    default:
518
 
      return GDK_FILTER_CONTINUE;
519
 
    }
520
 
  return GDK_FILTER_REMOVE;
521
 
}
522
 
 
523
 
static GdkWindowCache *
524
 
gdk_window_cache_new (GdkScreen *screen)
525
 
{
526
 
  XWindowAttributes xwa;
527
 
  Display *xdisplay = GDK_SCREEN_XDISPLAY (screen);
528
 
  GdkWindow *root_window = gdk_screen_get_root_window (screen);
529
 
  GdkChildInfoX11 *children;
530
 
  guint nchildren, i;
531
 
  Window cow;
532
 
  
533
 
  GdkWindowCache *result = g_new (GdkWindowCache, 1);
534
 
 
535
 
  result->children = NULL;
536
 
  result->child_hash = g_hash_table_new (g_direct_hash, NULL);
537
 
  result->screen = screen;
538
 
  result->ref_count = 1;
539
 
 
540
 
  XGetWindowAttributes (xdisplay, GDK_WINDOW_XWINDOW (root_window), &xwa);
541
 
  result->old_event_mask = xwa.your_event_mask;
542
 
 
543
 
  if (G_UNLIKELY (!GDK_DISPLAY_X11 (GDK_SCREEN_X11 (screen)->display)->trusted_client)) 
544
 
    {
545
 
      GList *toplevel_windows, *list;
546
 
      GdkWindow *window;
547
 
      gint x, y, width, height;
548
 
      
549
 
      toplevel_windows = gdk_screen_get_toplevel_windows (screen);
550
 
      for (list = toplevel_windows; list; list = list->next) {
551
 
        window = GDK_WINDOW (list->data);
552
 
        gdk_window_get_geometry (window, &x, &y, &width, &height, NULL);
553
 
        gdk_window_cache_add (result, GDK_WINDOW_XID (window), 
554
 
                              x, y, width, height, 
555
 
                              gdk_window_is_visible (window));
556
 
      }
557
 
      g_list_free (toplevel_windows);
558
 
      return result;
559
 
    }
560
 
 
561
 
  XSelectInput (xdisplay, GDK_WINDOW_XWINDOW (root_window),
562
 
                result->old_event_mask | SubstructureNotifyMask);
563
 
  gdk_window_add_filter (root_window, gdk_window_cache_filter, result);
564
 
  gdk_window_add_filter (NULL, gdk_window_cache_shape_filter, result);
565
 
 
566
 
  if (!_gdk_x11_get_window_child_info (gdk_screen_get_display (screen),
567
 
                                       GDK_WINDOW_XWINDOW (root_window),
568
 
                                       FALSE, NULL,
569
 
                                       &children, &nchildren))
570
 
    return result;
571
 
 
572
 
  for (i = 0; i < nchildren ; i++)
573
 
    {
574
 
      gdk_window_cache_add (result, children[i].window,
575
 
                            children[i].x, children[i].y, children[i].width, children[i].height,
576
 
                            children[i].is_mapped);
577
 
    }
578
 
 
579
 
  g_free (children);
580
 
 
581
 
#ifdef HAVE_XCOMPOSITE
582
 
  /*
583
 
   * Add the composite overlay window to the cache, as this can be a reasonable
584
 
   * Xdnd proxy as well.
585
 
   * This is only done when the screen is composited in order to avoid mapping
586
 
   * the COW. We assume that the CM is using the COW (which is true for pretty
587
 
   * much any CM currently in use).
588
 
   */
589
 
  if (gdk_screen_is_composited (screen))
590
 
    {
591
 
      cow = XCompositeGetOverlayWindow (xdisplay, GDK_WINDOW_XWINDOW (root_window));
592
 
      gdk_window_cache_add (result, cow, 0, 0, gdk_screen_get_width (screen), gdk_screen_get_height (screen), TRUE);
593
 
      XCompositeReleaseOverlayWindow (xdisplay, GDK_WINDOW_XWINDOW (root_window));
594
 
    }
595
 
#endif
596
 
 
597
 
  return result;
598
 
}
599
 
 
600
 
static void
601
 
gdk_window_cache_destroy (GdkWindowCache *cache)
602
 
{
603
 
  GdkWindow *root_window = gdk_screen_get_root_window (cache->screen);
604
 
 
605
 
  XSelectInput (GDK_WINDOW_XDISPLAY (root_window),
606
 
                GDK_WINDOW_XWINDOW (root_window),
607
 
                cache->old_event_mask);
608
 
  gdk_window_remove_filter (root_window, gdk_window_cache_filter, cache);
609
 
  gdk_window_remove_filter (NULL, gdk_window_cache_shape_filter, cache);
610
 
 
611
 
  gdk_error_trap_push ();
612
 
 
613
 
  g_list_foreach (cache->children, (GFunc)free_cache_child,
614
 
      gdk_screen_get_display (cache->screen));
615
 
 
616
 
  gdk_flush ();
617
 
  gdk_error_trap_pop ();
618
 
 
619
 
  g_list_free (cache->children);
620
 
  g_hash_table_destroy (cache->child_hash);
621
 
 
622
 
  g_free (cache);
623
 
}
624
 
 
625
 
static GdkWindowCache *
626
 
gdk_window_cache_ref (GdkWindowCache *cache)
627
 
{
628
 
  cache->ref_count += 1;
629
 
 
630
 
  return cache;
631
 
}
632
 
 
633
 
static void
634
 
gdk_window_cache_unref (GdkWindowCache *cache)
635
 
{
636
 
  g_assert (cache->ref_count > 0);
637
 
 
638
 
  cache->ref_count -= 1;
639
 
 
640
 
  if (cache->ref_count == 0)
641
 
    {
642
 
      window_caches = g_slist_remove (window_caches, cache);
643
 
      gdk_window_cache_destroy (cache);
644
 
    }
645
 
}
646
 
 
647
 
GdkWindowCache *
648
 
gdk_window_cache_get (GdkScreen *screen)
649
 
{
650
 
  GSList *list;
651
 
  GdkWindowCache *cache;
652
 
 
653
 
  for (list = window_caches; list; list = list->next)
654
 
    {
655
 
      cache = list->data;
656
 
      if (cache->screen == screen)
657
 
        return gdk_window_cache_ref (cache);
658
 
    }
659
 
 
660
 
  cache = gdk_window_cache_new (screen);
661
 
 
662
 
  window_caches = g_slist_prepend (window_caches, cache);
663
 
 
664
 
  return cache;
665
 
}
666
 
 
667
 
 
668
 
static gboolean
669
 
is_pointer_within_shape (GdkDisplay    *display,
670
 
                         GdkCacheChild *child,
671
 
                         gint           x_pos,
672
 
                         gint           y_pos)
673
 
{
674
 
  if (!child->shape_selected)
675
 
    {
676
 
      GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
677
 
 
678
 
      XShapeSelectInput (display_x11->xdisplay, child->xid, ShapeNotifyMask);
679
 
      child->shape_selected = TRUE;
680
 
    }
681
 
  if (!child->shape_valid)
682
 
    {
683
 
      GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
684
 
      GdkRegion *input_shape;
685
 
 
686
 
      child->shape = _xwindow_get_shape (display_x11->xdisplay,
687
 
                                         child->xid, ShapeBounding);
688
 
#ifdef ShapeInput
689
 
      input_shape = _xwindow_get_shape (display_x11->xdisplay,
690
 
                                        child->xid, ShapeInput);
691
 
      if (child->shape && input_shape)
692
 
        {
693
 
          gdk_region_intersect (child->shape, input_shape);
694
 
          gdk_region_destroy (input_shape);
695
 
        }
696
 
      else if (input_shape)
697
 
        {
698
 
          child->shape = input_shape;
699
 
        }
700
 
#endif
701
 
 
702
 
      child->shape_valid = TRUE;
703
 
    }
704
 
 
705
 
  return child->shape == NULL ||
706
 
         gdk_region_point_in (child->shape, x_pos, y_pos);
707
 
}
708
 
 
709
 
static Window
710
 
get_client_window_at_coords_recurse (GdkDisplay *display,
711
 
                                     Window      win,
712
 
                                     gboolean    is_toplevel,
713
 
                                     gint        x,
714
 
                                     gint        y)
715
 
{
716
 
  GdkChildInfoX11 *children;
717
 
  unsigned int nchildren;
718
 
  int i;
719
 
  gboolean found_child = FALSE;
720
 
  GdkChildInfoX11 child = { 0, };
721
 
  gboolean has_wm_state = FALSE;
722
 
 
723
 
  if (!_gdk_x11_get_window_child_info (display, win, TRUE,
724
 
                                       is_toplevel? &has_wm_state : NULL,
725
 
                                       &children, &nchildren))
726
 
    return None;
727
 
 
728
 
  if (has_wm_state)
729
 
    {
730
 
      g_free (children);
731
 
 
732
 
      return win;
733
 
    }
734
 
 
735
 
  for (i = nchildren - 1; (i >= 0) && !found_child; i--)
736
 
    {
737
 
      GdkChildInfoX11 *cur_child = &children[i];
738
 
       
739
 
      if ((cur_child->is_mapped) && (cur_child->window_class == InputOutput) &&
740
 
          (x >= cur_child->x) && (x < cur_child->x + cur_child->width) &&
741
 
          (y >= cur_child->y) && (y < cur_child->y + cur_child->height))
742
 
        {
743
 
          x -= cur_child->x;
744
 
          y -= cur_child->y;
745
 
          child = *cur_child;
746
 
          found_child = TRUE;
747
 
        }
748
 
    }
749
 
   
750
 
  g_free (children);
751
 
 
752
 
  if (found_child)
753
 
    {
754
 
      if (child.has_wm_state)
755
 
        return child.window;
756
 
      else
757
 
        return get_client_window_at_coords_recurse (display, child.window, FALSE, x, y);
758
 
    }
759
 
  else
760
 
    return None;
761
 
}
762
 
 
763
 
static Window 
764
 
get_client_window_at_coords (GdkWindowCache *cache,
765
 
                             Window          ignore,
766
 
                             gint            x_root,
767
 
                             gint            y_root)
768
 
{
769
 
  GList *tmp_list;
770
 
  Window retval = None;
771
 
 
772
 
  gdk_error_trap_push ();
773
 
  
774
 
  tmp_list = cache->children;
775
 
 
776
 
  while (tmp_list && !retval)
777
 
    {
778
 
      GdkCacheChild *child = tmp_list->data;
779
 
 
780
 
      if ((child->xid != ignore) && (child->mapped))
781
 
        {
782
 
          if ((x_root >= child->x) && (x_root < child->x + child->width) &&
783
 
              (y_root >= child->y) && (y_root < child->y + child->height))
784
 
            {
785
 
              GdkDisplay *display = gdk_screen_get_display (cache->screen);
786
 
 
787
 
              if (!is_pointer_within_shape (display, child,
788
 
                                            x_root - child->x,
789
 
                                            y_root - child->y))
790
 
                {
791
 
                  tmp_list = tmp_list->next;
792
 
                  continue;
793
 
                }
794
 
 
795
 
              retval = get_client_window_at_coords_recurse (display,
796
 
                  child->xid, TRUE,
797
 
                  x_root - child->x,
798
 
                  y_root - child->y);
799
 
              if (!retval)
800
 
                retval = child->xid;
801
 
            }
802
 
        }
803
 
      tmp_list = tmp_list->next;
804
 
    }
805
 
 
806
 
  gdk_error_trap_pop ();
807
 
  
808
 
  if (retval)
809
 
    return retval;
810
 
  else
811
 
    return GDK_WINDOW_XWINDOW (gdk_screen_get_root_window (cache->screen));
812
 
}
813
 
 
814
 
/*************************************************************
815
 
 ***************************** MOTIF *************************
816
 
 *************************************************************/
817
 
 
818
 
/* values used in the message type for Motif DND */
819
 
enum {
820
 
    XmTOP_LEVEL_ENTER,
821
 
    XmTOP_LEVEL_LEAVE,
822
 
    XmDRAG_MOTION,
823
 
    XmDROP_SITE_ENTER,
824
 
    XmDROP_SITE_LEAVE,
825
 
    XmDROP_START,
826
 
    XmDROP_FINISH,
827
 
    XmDRAG_DROP_FINISH,
828
 
    XmOPERATION_CHANGED
829
 
};
830
 
 
831
 
/* Values used to specify type of protocol to use */
832
 
enum {
833
 
    XmDRAG_NONE,
834
 
    XmDRAG_DROP_ONLY,
835
 
    XmDRAG_PREFER_PREREGISTER,
836
 
    XmDRAG_PREREGISTER,
837
 
    XmDRAG_PREFER_DYNAMIC,
838
 
    XmDRAG_DYNAMIC,
839
 
    XmDRAG_PREFER_RECEIVER
840
 
};
841
 
 
842
 
/* Operation codes */
843
 
enum {
844
 
  XmDROP_NOOP,
845
 
  XmDROP_MOVE = 0x01,
846
 
  XmDROP_COPY = 0x02,
847
 
  XmDROP_LINK = 0x04
848
 
};
849
 
 
850
 
/* Drop site status */
851
 
enum {
852
 
  XmNO_DROP_SITE = 0x01,
853
 
  XmDROP_SITE_INVALID = 0x02,
854
 
  XmDROP_SITE_VALID = 0x03
855
 
};
856
 
 
857
 
/* completion status */
858
 
enum {
859
 
  XmDROP,
860
 
  XmDROP_HELP,
861
 
  XmDROP_CANCEL,
862
 
  XmDROP_INTERRUPT
863
 
};
864
 
 
865
 
/* Byte swapping routines. The motif specification leaves it
866
 
 * up to us to save a few bytes in the client messages
867
 
 */
868
 
static gchar local_byte_order = '\0';
869
 
 
870
 
#ifdef G_ENABLE_DEBUG
871
 
static void
872
 
print_target_list (GList *targets)
873
 
{
874
 
  while (targets)
875
 
    {
876
 
      gchar *name = gdk_atom_name (GDK_POINTER_TO_ATOM (targets->data));
877
 
      g_message ("\t%s", name);
878
 
      g_free (name);
879
 
      targets = targets->next;
880
 
    }
881
 
}
882
 
#endif /* G_ENABLE_DEBUG */
883
 
 
884
 
static void
885
 
init_byte_order (void)
886
 
{
887
 
  guint32 myint = 0x01020304;
888
 
  local_byte_order = (*(gchar *)&myint == 1) ? 'B' : 'l';
889
 
}
890
 
 
891
 
static guint16
892
 
card16_to_host (guint16 x, gchar byte_order) {
893
 
  if (byte_order == local_byte_order)
894
 
    return x;
895
 
  else
896
 
    return (x << 8) | (x >> 8);
897
 
}
898
 
 
899
 
static guint32
900
 
card32_to_host (guint32 x, gchar byte_order) {
901
 
  if (byte_order == local_byte_order)
902
 
    return x;
903
 
  else
904
 
    return (x << 24) | ((x & 0xff00) << 8) | ((x & 0xff0000) >> 8) | (x >> 24);
905
 
}
906
 
 
907
 
/* Motif packs together fields of varying length into the
908
 
 * client message. We can't rely on accessing these
909
 
 * through data.s[], data.l[], etc, because on some architectures
910
 
 * (i.e., Alpha) these won't be valid for format == 8. 
911
 
 */
912
 
 
913
 
#define MOTIF_XCLIENT_BYTE(xevent,i) \
914
 
  (xevent)->xclient.data.b[i]
915
 
#define MOTIF_XCLIENT_SHORT(xevent,i) \
916
 
  ((gint16 *)&((xevent)->xclient.data.b[0]))[i]
917
 
#define MOTIF_XCLIENT_LONG(xevent,i) \
918
 
  ((gint32 *)&((xevent)->xclient.data.b[0]))[i]
919
 
 
920
 
#define MOTIF_UNPACK_BYTE(xevent,i) MOTIF_XCLIENT_BYTE(xevent,i)
921
 
#define MOTIF_UNPACK_SHORT(xevent,i) \
922
 
  card16_to_host (MOTIF_XCLIENT_SHORT(xevent,i), MOTIF_XCLIENT_BYTE(xevent, 1))
923
 
#define MOTIF_UNPACK_LONG(xevent,i) \
924
 
  card32_to_host (MOTIF_XCLIENT_LONG(xevent,i), MOTIF_XCLIENT_BYTE(xevent, 1))
925
 
 
926
 
/***** Dest side ***********/
927
 
 
928
 
/* Property placed on source windows */
929
 
typedef struct _MotifDragInitiatorInfo {
930
 
  guint8 byte_order;
931
 
  guint8 protocol_version;
932
 
  guint16 targets_index;
933
 
  guint32 selection_atom;
934
 
} MotifDragInitiatorInfo;
935
 
 
936
 
/* Header for target table on the drag window */
937
 
typedef struct _MotifTargetTableHeader {
938
 
  guchar byte_order;
939
 
  guchar protocol_version;
940
 
  guint16 n_lists;
941
 
  guint32 total_size;
942
 
} MotifTargetTableHeader;
943
 
 
944
 
/* Property placed on target windows */
945
 
typedef struct _MotifDragReceiverInfo {
946
 
  guint8 byte_order;
947
 
  guint8 protocol_version;
948
 
  guint8 protocol_style;
949
 
  guint8 pad;
950
 
  guint32 proxy_window;
951
 
  guint16 num_drop_sites;
952
 
  guint16 padding;
953
 
  guint32 total_size;
954
 
} MotifDragReceiverInfo;
955
 
 
956
 
/* Target table handling */
957
 
 
958
 
static GdkFilterReturn
959
 
motif_drag_window_filter (GdkXEvent *xevent,
960
 
                          GdkEvent  *event,
961
 
                          gpointer data)
962
 
{
963
 
  XEvent *xev = (XEvent *)xevent;
964
 
  GdkDisplay *display = GDK_WINDOW_DISPLAY (event->any.window); 
965
 
  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
966
 
 
967
 
  switch (xev->xany.type)
968
 
    {
969
 
    case DestroyNotify:
970
 
      display_x11->motif_drag_window = None;
971
 
      display_x11->motif_drag_gdk_window = NULL;
972
 
      break;
973
 
    case PropertyNotify:
974
 
      if (display_x11->motif_target_lists &&
975
 
          (xev->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_TARGETS")))
976
 
        motif_read_target_table (display);
977
 
      break;
978
 
    }
979
 
  return GDK_FILTER_REMOVE;
980
 
}
981
 
 
982
 
static Window
983
 
motif_lookup_drag_window (GdkDisplay *display,
984
 
                          Display    *lookup_xdisplay)
985
 
{
986
 
  Window retval = None;
987
 
  gulong bytes_after, nitems;
988
 
  Atom type;
989
 
  gint format;
990
 
  guchar *data;
991
 
 
992
 
  XGetWindowProperty (lookup_xdisplay, RootWindow (lookup_xdisplay, 0),
993
 
                      gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_WINDOW"),
994
 
                      0, 1, FALSE,
995
 
                      XA_WINDOW, &type, &format, &nitems, &bytes_after,
996
 
                      &data);
997
 
  
998
 
  if ((format == 32) && (nitems == 1) && (bytes_after == 0))
999
 
    {
1000
 
      retval = *(Window *)data;
1001
 
      GDK_NOTE (DND, 
1002
 
                g_message ("Found drag window %#lx\n", GDK_DISPLAY_X11 (display)->motif_drag_window));
1003
 
    }
1004
 
 
1005
 
  if (type != None)
1006
 
    XFree (data);
1007
 
 
1008
 
  return retval;
1009
 
}
1010
 
 
1011
 
/* Finds the window where global Motif drag information is stored.
1012
 
 * If it doesn't exist and 'create' is TRUE, create one.
1013
 
 */
1014
 
static Window 
1015
 
motif_find_drag_window (GdkDisplay *display,
1016
 
                        gboolean    create)
1017
 
{
1018
 
  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
1019
 
  
1020
 
  if (!display_x11->motif_drag_window)
1021
 
    {
1022
 
      Atom motif_drag_window_atom = gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_WINDOW");
1023
 
      display_x11->motif_drag_window = motif_lookup_drag_window (display, display_x11->xdisplay);
1024
 
      
1025
 
      if (!display_x11->motif_drag_window && create)
1026
 
        {
1027
 
          /* Create a persistant window. (Copied from LessTif) */
1028
 
          
1029
 
          Display *persistant_xdisplay;
1030
 
          XSetWindowAttributes attr;
1031
 
          persistant_xdisplay = XOpenDisplay (gdk_display_get_name (display));
1032
 
          XSetCloseDownMode (persistant_xdisplay, RetainPermanent);
1033
 
 
1034
 
          XGrabServer (persistant_xdisplay);
1035
 
          
1036
 
          display_x11->motif_drag_window = motif_lookup_drag_window (display, persistant_xdisplay);
1037
 
 
1038
 
          if (!display_x11->motif_drag_window)
1039
 
            {
1040
 
              attr.override_redirect = True;
1041
 
              attr.event_mask = PropertyChangeMask;
1042
 
              
1043
 
               display_x11->motif_drag_window = 
1044
 
                XCreateWindow (persistant_xdisplay, 
1045
 
                               RootWindow (persistant_xdisplay, 0),
1046
 
                              -100, -100, 10, 10, 0, 0,
1047
 
                              InputOnly, (Visual *)CopyFromParent,
1048
 
                              (CWOverrideRedirect | CWEventMask), &attr);
1049
 
              
1050
 
              GDK_NOTE (DND,
1051
 
                        g_message ("Created drag window %#lx\n", display_x11->motif_drag_window));
1052
 
              
1053
 
              XChangeProperty (persistant_xdisplay, 
1054
 
                               RootWindow (persistant_xdisplay, 0),
1055
 
                               motif_drag_window_atom, XA_WINDOW,
1056
 
                               32, PropModeReplace,
1057
 
                               (guchar *)&motif_drag_window_atom, 1);
1058
 
 
1059
 
            }
1060
 
          XUngrabServer (persistant_xdisplay);
1061
 
          XCloseDisplay (persistant_xdisplay);
1062
 
        }
1063
 
 
1064
 
      /* There is a miniscule race condition here if the drag window
1065
 
       * gets destroyed exactly now.
1066
 
       */
1067
 
      if (display_x11->motif_drag_window)
1068
 
        {
1069
 
          display_x11->motif_drag_gdk_window = 
1070
 
            gdk_window_foreign_new_for_display (display, display_x11->motif_drag_window);
1071
 
          gdk_window_add_filter (display_x11->motif_drag_gdk_window,
1072
 
                                 motif_drag_window_filter,
1073
 
                                 NULL);
1074
 
        }
1075
 
    }
1076
 
 
1077
 
  return display_x11->motif_drag_window;
1078
 
}
1079
 
 
1080
 
static void 
1081
 
motif_read_target_table (GdkDisplay *display)
1082
 
{
1083
 
  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
1084
 
  gulong bytes_after, nitems;
1085
 
  Atom type;
1086
 
  gint format;
1087
 
  gint i, j;
1088
 
  
1089
 
  Atom motif_drag_targets_atom = gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_TARGETS");
1090
 
 
1091
 
  if (display_x11->motif_target_lists)
1092
 
    {
1093
 
      for (i=0; i<display_x11->motif_n_target_lists; i++)
1094
 
        g_list_free (display_x11->motif_target_lists[i]);
1095
 
      
1096
 
      g_free (display_x11->motif_target_lists);
1097
 
      display_x11->motif_target_lists = NULL;
1098
 
      display_x11->motif_n_target_lists = 0;
1099
 
    }
1100
 
 
1101
 
  if (motif_find_drag_window (display, FALSE))
1102
 
    {
1103
 
      guchar *data;
1104
 
      MotifTargetTableHeader *header = NULL;
1105
 
      guchar *target_bytes = NULL;
1106
 
      guchar *p;
1107
 
      gboolean success = FALSE;
1108
 
 
1109
 
      gdk_error_trap_push ();
1110
 
      XGetWindowProperty (display_x11->xdisplay, 
1111
 
                          display_x11->motif_drag_window, 
1112
 
                          motif_drag_targets_atom,
1113
 
                          0, (sizeof(MotifTargetTableHeader)+3)/4, FALSE,
1114
 
                          motif_drag_targets_atom, 
1115
 
                          &type, &format, &nitems, &bytes_after,
1116
 
                          &data);
1117
 
 
1118
 
      if (gdk_error_trap_pop () || (format != 8) || (nitems < sizeof (MotifTargetTableHeader)))
1119
 
        goto error;
1120
 
 
1121
 
      header = (MotifTargetTableHeader *)data;
1122
 
 
1123
 
      header->n_lists = card16_to_host (header->n_lists, header->byte_order);
1124
 
      header->total_size = card32_to_host (header->total_size, header->byte_order);
1125
 
 
1126
 
      gdk_error_trap_push ();
1127
 
      XGetWindowProperty (display_x11->xdisplay, 
1128
 
                          display_x11->motif_drag_window, 
1129
 
                          motif_drag_targets_atom,
1130
 
                          (sizeof(MotifTargetTableHeader)+3)/4, 
1131
 
                          (header->total_size + 3)/4 - (sizeof(MotifTargetTableHeader) + 3)/4,
1132
 
                          FALSE,
1133
 
                          motif_drag_targets_atom, &type, &format, &nitems, 
1134
 
                          &bytes_after, &target_bytes);
1135
 
      
1136
 
      if (gdk_error_trap_pop () || (format != 8) || (bytes_after != 0) || 
1137
 
          (nitems != header->total_size - sizeof(MotifTargetTableHeader)))
1138
 
          goto error;
1139
 
 
1140
 
      display_x11->motif_n_target_lists = header->n_lists;
1141
 
      display_x11->motif_target_lists = g_new0 (GList *, display_x11->motif_n_target_lists);
1142
 
 
1143
 
      p = target_bytes;
1144
 
      for (i=0; i<header->n_lists; i++)
1145
 
        {
1146
 
          gint n_targets;
1147
 
          guint32 *targets;
1148
 
          
1149
 
          if (p + sizeof(guint16) - target_bytes > nitems)
1150
 
            goto error;
1151
 
 
1152
 
          n_targets = card16_to_host (*(gushort *)p, header->byte_order);
1153
 
 
1154
 
          /* We need to make a copy of the targets, since it may
1155
 
           * be unaligned
1156
 
           */
1157
 
          targets = g_new (guint32, n_targets);
1158
 
          memcpy (targets, p + sizeof(guint16), sizeof(guint32) * n_targets);
1159
 
 
1160
 
          p +=  sizeof(guint16) + n_targets * sizeof(guint32);
1161
 
          if (p - target_bytes > nitems)
1162
 
            goto error;
1163
 
 
1164
 
          for (j=0; j<n_targets; j++)
1165
 
            display_x11->motif_target_lists[i] = 
1166
 
              g_list_prepend (display_x11->motif_target_lists[i],
1167
 
                              GUINT_TO_POINTER (card32_to_host (targets[j],
1168
 
                                                                header->byte_order)));
1169
 
          g_free (targets);
1170
 
          display_x11->motif_target_lists[i] = g_list_reverse (display_x11->motif_target_lists[i]);
1171
 
        }
1172
 
 
1173
 
      success = TRUE;
1174
 
      
1175
 
    error:
1176
 
      if (header)
1177
 
        XFree (header);
1178
 
      
1179
 
      if (target_bytes)
1180
 
        XFree (target_bytes);
1181
 
 
1182
 
      if (!success)
1183
 
        {
1184
 
          if (display_x11->motif_target_lists)
1185
 
            {
1186
 
              g_free (display_x11->motif_target_lists);
1187
 
              display_x11->motif_target_lists = NULL;
1188
 
              display_x11->motif_n_target_lists = 0;
1189
 
            }
1190
 
          g_warning ("Error reading Motif target table\n");
1191
 
        }
1192
 
    }
1193
 
}
1194
 
 
1195
 
static gint
1196
 
targets_sort_func (gconstpointer a, gconstpointer b)
1197
 
{
1198
 
  return (GPOINTER_TO_UINT (a) < GPOINTER_TO_UINT (b)) ?
1199
 
    -1 : ((GPOINTER_TO_UINT (a) > GPOINTER_TO_UINT (b)) ? 1 : 0);
1200
 
}
1201
 
 
1202
 
/* Check if given (sorted) list is in the targets table */
1203
 
static gint
1204
 
motif_target_table_check (GdkDisplay *display,
1205
 
                          GList      *sorted)
1206
 
{
1207
 
  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
1208
 
  GList *tmp_list1, *tmp_list2;
1209
 
  gint i;
1210
 
 
1211
 
  for (i=0; i<display_x11->motif_n_target_lists; i++)
1212
 
    {
1213
 
      tmp_list1 = display_x11->motif_target_lists[i];
1214
 
      tmp_list2 = sorted;
1215
 
      
1216
 
      while (tmp_list1 && tmp_list2)
1217
 
        {
1218
 
          if (tmp_list1->data != tmp_list2->data)
1219
 
            break;
1220
 
 
1221
 
          tmp_list1 = tmp_list1->next;
1222
 
          tmp_list2 = tmp_list2->next;
1223
 
        }
1224
 
      if (!tmp_list1 && !tmp_list2)     /* Found it */
1225
 
        return i;
1226
 
    }
1227
 
 
1228
 
  return -1;
1229
 
}
1230
 
 
1231
 
static gint
1232
 
motif_add_to_target_table (GdkDisplay *display,
1233
 
                           GList      *targets) /* targets is list of GdkAtom */
1234
 
{
1235
 
  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
1236
 
  GList *sorted = NULL;
1237
 
  gint index = -1;
1238
 
  gint i;
1239
 
  GList *tmp_list;
1240
 
  
1241
 
  /* make a sorted copy of the list */
1242
 
  
1243
 
  while (targets)
1244
 
    {
1245
 
      Atom xatom = gdk_x11_atom_to_xatom_for_display (display, GDK_POINTER_TO_ATOM (targets->data));
1246
 
      sorted = g_list_insert_sorted (sorted, GUINT_TO_POINTER (xatom), targets_sort_func);
1247
 
      targets = targets->next;
1248
 
    }
1249
 
 
1250
 
  /* First check if it is there already */
1251
 
 
1252
 
  if (display_x11->motif_target_lists)
1253
 
    index = motif_target_table_check (display, sorted);
1254
 
 
1255
 
  /* We need to grab the server while doing this, to ensure
1256
 
   * atomiticity. Ugh
1257
 
   */
1258
 
 
1259
 
  if (index < 0)
1260
 
    {
1261
 
      /* We need to make sure that it exists _before_ we grab the
1262
 
       * server, since we can't open a new connection after we
1263
 
       * grab the server. 
1264
 
       */
1265
 
      motif_find_drag_window (display, TRUE);
1266
 
 
1267
 
      gdk_x11_display_grab (display);
1268
 
      motif_read_target_table (display);
1269
 
    
1270
 
      /* Check again, in case it was added in the meantime */
1271
 
      
1272
 
      if (display_x11->motif_target_lists)
1273
 
        index = motif_target_table_check (display, sorted);
1274
 
 
1275
 
      if (index < 0)
1276
 
        {
1277
 
          guint32 total_size = 0;
1278
 
          guchar *data;
1279
 
          guchar *p;
1280
 
          guint16 *p16;
1281
 
          MotifTargetTableHeader *header;
1282
 
          
1283
 
          if (!display_x11->motif_target_lists)
1284
 
            {
1285
 
              display_x11->motif_target_lists = g_new (GList *, 1);
1286
 
              display_x11->motif_n_target_lists = 1;
1287
 
            }
1288
 
          else
1289
 
            {
1290
 
              display_x11->motif_n_target_lists++;
1291
 
              display_x11->motif_target_lists = g_realloc (display_x11->motif_target_lists,
1292
 
                                                           sizeof(GList *) * display_x11->motif_n_target_lists);
1293
 
            }
1294
 
          display_x11->motif_target_lists[display_x11->motif_n_target_lists - 1] = sorted;
1295
 
          sorted = NULL;
1296
 
          index = display_x11->motif_n_target_lists - 1;
1297
 
 
1298
 
          total_size = sizeof (MotifTargetTableHeader);
1299
 
          for (i = 0; i < display_x11->motif_n_target_lists ; i++)
1300
 
            total_size += sizeof(guint16) + sizeof(guint32) * g_list_length (display_x11->motif_target_lists[i]);
1301
 
 
1302
 
          data = g_malloc (total_size);
1303
 
 
1304
 
          header = (MotifTargetTableHeader *)data;
1305
 
          p = data + sizeof(MotifTargetTableHeader);
1306
 
 
1307
 
          header->byte_order = local_byte_order;
1308
 
          header->protocol_version = 0;
1309
 
          header->n_lists = display_x11->motif_n_target_lists;
1310
 
          header->total_size = total_size;
1311
 
 
1312
 
          for (i = 0; i < display_x11->motif_n_target_lists ; i++)
1313
 
            {
1314
 
              guint16 n_targets = g_list_length (display_x11->motif_target_lists[i]);
1315
 
              guint32 *targets = g_new (guint32, n_targets);
1316
 
              guint32 *p32 = targets;
1317
 
              
1318
 
              tmp_list = display_x11->motif_target_lists[i];
1319
 
              while (tmp_list)
1320
 
                {
1321
 
                  *p32 = GPOINTER_TO_UINT (tmp_list->data);
1322
 
                  
1323
 
                  tmp_list = tmp_list->next;
1324
 
                  p32++;
1325
 
                }
1326
 
 
1327
 
              p16 = (guint16 *)p;
1328
 
              p += sizeof(guint16);
1329
 
 
1330
 
              memcpy (p, targets, n_targets * sizeof(guint32));
1331
 
 
1332
 
              *p16 = n_targets;
1333
 
              p += sizeof(guint32) * n_targets;
1334
 
              g_free (targets);
1335
 
            }
1336
 
 
1337
 
          XChangeProperty (display_x11->xdisplay,
1338
 
                           display_x11->motif_drag_window,
1339
 
                           gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_TARGETS"),
1340
 
                           gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_TARGETS"),
1341
 
                           8, PropModeReplace,
1342
 
                           data, total_size);
1343
 
        }
1344
 
      gdk_x11_display_ungrab (display);
1345
 
    }
1346
 
 
1347
 
  g_list_free (sorted);
1348
 
  return index;
1349
 
}
1350
 
 
1351
 
/* Translate flags */
1352
 
 
1353
 
static void
1354
 
motif_dnd_translate_flags (GdkDragContext *context, guint16 flags)
1355
 
{
1356
 
  guint recommended_op = flags & 0x000f;
1357
 
  guint possible_ops = (flags & 0x0f0) >> 4;
1358
 
  
1359
 
  switch (recommended_op)
1360
 
    {
1361
 
    case XmDROP_MOVE:
1362
 
      context->suggested_action = GDK_ACTION_MOVE;
1363
 
      break;
1364
 
    case XmDROP_COPY:
1365
 
      context->suggested_action = GDK_ACTION_COPY;
1366
 
      break;
1367
 
    case XmDROP_LINK:
1368
 
      context->suggested_action = GDK_ACTION_LINK;
1369
 
      break;
1370
 
    default:
1371
 
      context->suggested_action = GDK_ACTION_COPY;
1372
 
      break;
1373
 
    }
1374
 
 
1375
 
  context->actions = 0;
1376
 
  if (possible_ops & XmDROP_MOVE)
1377
 
    context->actions |= GDK_ACTION_MOVE;
1378
 
  if (possible_ops & XmDROP_COPY)
1379
 
    context->actions |= GDK_ACTION_COPY;
1380
 
  if (possible_ops & XmDROP_LINK)
1381
 
    context->actions |= GDK_ACTION_LINK;
1382
 
}
1383
 
 
1384
 
static guint16
1385
 
motif_dnd_get_flags (GdkDragContext *context)
1386
 
{
1387
 
  guint16 flags = 0;
1388
 
  
1389
 
  switch (context->suggested_action)
1390
 
    {
1391
 
    case GDK_ACTION_MOVE:
1392
 
      flags = XmDROP_MOVE;
1393
 
      break;
1394
 
    case GDK_ACTION_COPY:
1395
 
      flags = XmDROP_COPY;
1396
 
      break;
1397
 
    case GDK_ACTION_LINK:
1398
 
      flags = XmDROP_LINK;
1399
 
      break;
1400
 
    default:
1401
 
      flags = XmDROP_NOOP;
1402
 
      break;
1403
 
    }
1404
 
  
1405
 
  if (context->actions & GDK_ACTION_MOVE)
1406
 
    flags |= XmDROP_MOVE << 8;
1407
 
  if (context->actions & GDK_ACTION_COPY)
1408
 
    flags |= XmDROP_COPY << 8;
1409
 
  if (context->actions & GDK_ACTION_LINK)
1410
 
    flags |= XmDROP_LINK << 8;
1411
 
 
1412
 
  return flags;
1413
 
}
1414
 
 
1415
 
/* Source Side */
1416
 
 
1417
 
static void
1418
 
motif_set_targets (GdkDragContext *context)
1419
 
{
1420
 
  GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
1421
 
  MotifDragInitiatorInfo info;
1422
 
  gint i;
1423
 
  GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window);
1424
 
  
1425
 
  info.byte_order = local_byte_order;
1426
 
  info.protocol_version = 0;
1427
 
  
1428
 
  info.targets_index = motif_add_to_target_table (display, context->targets);
1429
 
 
1430
 
  for (i=0; ; i++)
1431
 
    {
1432
 
      gchar buf[20];
1433
 
      g_snprintf(buf, 20, "_GDK_SELECTION_%d", i);
1434
 
      
1435
 
      private->motif_selection = gdk_x11_get_xatom_by_name_for_display (display, buf);
1436
 
      if (!XGetSelectionOwner (GDK_DISPLAY_XDISPLAY (display), private->motif_selection))
1437
 
        break;
1438
 
    }
1439
 
 
1440
 
  info.selection_atom = private->motif_selection;
1441
 
 
1442
 
  XChangeProperty (GDK_DRAWABLE_XDISPLAY (context->source_window),
1443
 
                   GDK_DRAWABLE_XID (context->source_window),
1444
 
                   private->motif_selection,
1445
 
                   gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_INITIATOR_INFO"),
1446
 
                   8, PropModeReplace,
1447
 
                   (guchar *)&info, sizeof (info));
1448
 
 
1449
 
  private->motif_targets_set = 1;
1450
 
}
1451
 
 
1452
 
static guint32
1453
 
motif_check_dest (GdkDisplay *display,
1454
 
                  Window      win)
1455
 
{
1456
 
  gboolean retval = FALSE;
1457
 
  guchar *data;
1458
 
  MotifDragReceiverInfo *info;
1459
 
  Atom type = None;
1460
 
  int format;
1461
 
  unsigned long nitems, after;
1462
 
  Atom motif_drag_receiver_info_atom = gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_RECEIVER_INFO");
1463
 
 
1464
 
  gdk_error_trap_push ();
1465
 
  XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), win, 
1466
 
                      motif_drag_receiver_info_atom, 
1467
 
                      0, (sizeof(*info)+3)/4, False, AnyPropertyType,
1468
 
                      &type, &format, &nitems, &after, 
1469
 
                      &data);
1470
 
 
1471
 
  if (gdk_error_trap_pop() == 0)
1472
 
    {
1473
 
      if (type != None)
1474
 
        {
1475
 
          info = (MotifDragReceiverInfo *)data;
1476
 
          
1477
 
          if ((format == 8) && (nitems == sizeof(*info)))
1478
 
            {
1479
 
              if ((info->protocol_version == 0) &&
1480
 
                  ((info->protocol_style == XmDRAG_PREFER_PREREGISTER) ||
1481
 
                   (info->protocol_style == XmDRAG_PREFER_DYNAMIC) ||
1482
 
                   (info->protocol_style == XmDRAG_DYNAMIC)))
1483
 
                retval = TRUE;
1484
 
            }
1485
 
          else
1486
 
            {
1487
 
              GDK_NOTE (DND, 
1488
 
                        g_warning ("Invalid Motif drag receiver property on window %ld\n", win));
1489
 
            }
1490
 
          
1491
 
          XFree (info);
1492
 
        }
1493
 
    }
1494
 
 
1495
 
  return retval ? win : None;
1496
 
}
1497
 
 
1498
 
static void
1499
 
motif_send_enter (GdkDragContext  *context,
1500
 
                  guint32          time)
1501
 
{
1502
 
  GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
1503
 
  GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window);
1504
 
  XEvent xev;
1505
 
 
1506
 
  if (!G_LIKELY (GDK_DISPLAY_X11 (display)->trusted_client))
1507
 
    return; /* Motif Dnd requires getting properties on the root window */
1508
 
 
1509
 
  xev.xclient.type = ClientMessage;
1510
 
  xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_AND_DROP_MESSAGE");
1511
 
  xev.xclient.format = 8;
1512
 
  xev.xclient.window = GDK_DRAWABLE_XID (context->dest_window);
1513
 
 
1514
 
  MOTIF_XCLIENT_BYTE (&xev, 0) = XmTOP_LEVEL_ENTER;
1515
 
  MOTIF_XCLIENT_BYTE (&xev, 1) = local_byte_order;
1516
 
  MOTIF_XCLIENT_SHORT (&xev, 1) = 0;
1517
 
  MOTIF_XCLIENT_LONG (&xev, 1) = time;
1518
 
  MOTIF_XCLIENT_LONG (&xev, 2) = GDK_DRAWABLE_XID (context->source_window);
1519
 
 
1520
 
  if (!private->motif_targets_set)
1521
 
    motif_set_targets (context);
1522
 
 
1523
 
  MOTIF_XCLIENT_LONG (&xev, 3) = private->motif_selection;
1524
 
  MOTIF_XCLIENT_LONG (&xev, 4) = 0;
1525
 
 
1526
 
  if (!_gdk_send_xevent (display,
1527
 
                         GDK_DRAWABLE_XID (context->dest_window),
1528
 
                         FALSE, 0, &xev))
1529
 
    GDK_NOTE (DND, 
1530
 
              g_message ("Send event to %lx failed",
1531
 
                         GDK_DRAWABLE_XID (context->dest_window)));
1532
 
}
1533
 
 
1534
 
static void
1535
 
motif_send_leave (GdkDragContext  *context,
1536
 
                  guint32          time)
1537
 
{
1538
 
  GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window);
1539
 
  XEvent xev;
1540
 
 
1541
 
  xev.xclient.type = ClientMessage;
1542
 
  xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_AND_DROP_MESSAGE");
1543
 
  xev.xclient.format = 8;
1544
 
  xev.xclient.window = GDK_DRAWABLE_XID (context->dest_window);
1545
 
 
1546
 
  MOTIF_XCLIENT_BYTE (&xev, 0) = XmTOP_LEVEL_LEAVE;
1547
 
  MOTIF_XCLIENT_BYTE (&xev, 1) = local_byte_order;
1548
 
  MOTIF_XCLIENT_SHORT (&xev, 1) = 0;
1549
 
  MOTIF_XCLIENT_LONG (&xev, 1) = time;
1550
 
  MOTIF_XCLIENT_LONG (&xev, 2) = 0;
1551
 
  MOTIF_XCLIENT_LONG (&xev, 3) = 0;
1552
 
  MOTIF_XCLIENT_LONG (&xev, 4) = 0;
1553
 
 
1554
 
  if (!_gdk_send_xevent (display,
1555
 
                         GDK_DRAWABLE_XID (context->dest_window),
1556
 
                         FALSE, 0, &xev))
1557
 
    GDK_NOTE (DND, 
1558
 
              g_message ("Send event to %lx failed",
1559
 
                         GDK_DRAWABLE_XID (context->dest_window)));
1560
 
}
1561
 
 
1562
 
static gboolean
1563
 
motif_send_motion (GdkDragContext  *context,
1564
 
                    gint            x_root, 
1565
 
                    gint            y_root,
1566
 
                    GdkDragAction   action,
1567
 
                    guint32         time)
1568
 
{
1569
 
  GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
1570
 
  GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window);
1571
 
  gboolean retval;
1572
 
  XEvent xev;
1573
 
 
1574
 
  xev.xclient.type = ClientMessage;
1575
 
  xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_AND_DROP_MESSAGE");
1576
 
  xev.xclient.format = 8;
1577
 
  xev.xclient.window = GDK_DRAWABLE_XID (context->dest_window);
1578
 
 
1579
 
  MOTIF_XCLIENT_BYTE (&xev, 1) = local_byte_order;
1580
 
  MOTIF_XCLIENT_SHORT (&xev, 1) = motif_dnd_get_flags (context);
1581
 
  MOTIF_XCLIENT_LONG (&xev, 1) = time;
1582
 
  MOTIF_XCLIENT_LONG (&xev, 3) = 0;
1583
 
  MOTIF_XCLIENT_LONG (&xev, 4) = 0;
1584
 
 
1585
 
  if ((context->suggested_action != private->old_action) ||
1586
 
      (context->actions != private->old_actions))
1587
 
    {
1588
 
      MOTIF_XCLIENT_BYTE (&xev, 0) = XmOPERATION_CHANGED;
1589
 
 
1590
 
      /* private->drag_status = GDK_DRAG_STATUS_ACTION_WAIT; */
1591
 
      retval = TRUE;
1592
 
    }
1593
 
  else
1594
 
    {
1595
 
      MOTIF_XCLIENT_BYTE (&xev, 0) = XmDRAG_MOTION;
1596
 
 
1597
 
      MOTIF_XCLIENT_SHORT (&xev, 4) = x_root;
1598
 
      MOTIF_XCLIENT_SHORT (&xev, 5) = y_root;
1599
 
      
1600
 
      private->drag_status = GDK_DRAG_STATUS_MOTION_WAIT;
1601
 
      retval = FALSE;
1602
 
    }
1603
 
 
1604
 
  if (!_gdk_send_xevent (display,
1605
 
                         GDK_DRAWABLE_XID (context->dest_window),
1606
 
                         FALSE, 0, &xev))
1607
 
    GDK_NOTE (DND, 
1608
 
              g_message ("Send event to %lx failed",
1609
 
                         GDK_DRAWABLE_XID (context->dest_window)));
1610
 
 
1611
 
  return retval;
1612
 
}
1613
 
 
1614
 
static void
1615
 
motif_send_drop (GdkDragContext *context, guint32 time)
1616
 
{
1617
 
  GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
1618
 
  GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window);
1619
 
  XEvent xev;
1620
 
 
1621
 
  xev.xclient.type = ClientMessage;
1622
 
  xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_AND_DROP_MESSAGE");
1623
 
  xev.xclient.format = 8;
1624
 
  xev.xclient.window = GDK_DRAWABLE_XID (context->dest_window);
1625
 
 
1626
 
  MOTIF_XCLIENT_BYTE (&xev, 0) = XmDROP_START;
1627
 
  MOTIF_XCLIENT_BYTE (&xev, 1) = local_byte_order;
1628
 
  MOTIF_XCLIENT_SHORT (&xev, 1) = motif_dnd_get_flags (context);
1629
 
  MOTIF_XCLIENT_LONG (&xev, 1)  = time;
1630
 
 
1631
 
  MOTIF_XCLIENT_SHORT (&xev, 4) = private->last_x;
1632
 
  MOTIF_XCLIENT_SHORT (&xev, 5) = private->last_y;
1633
 
 
1634
 
  MOTIF_XCLIENT_LONG (&xev, 3)  = private->motif_selection;
1635
 
  MOTIF_XCLIENT_LONG (&xev, 4)  = GDK_DRAWABLE_XID (context->source_window);
1636
 
 
1637
 
  if (!_gdk_send_xevent (display,
1638
 
                         GDK_DRAWABLE_XID (context->dest_window),
1639
 
                         FALSE, 0, &xev))
1640
 
    GDK_NOTE (DND, 
1641
 
              g_message ("Send event to %lx failed",
1642
 
                         GDK_DRAWABLE_XID (context->dest_window)));
1643
 
}
1644
 
 
1645
 
/* Target Side */
1646
 
 
1647
 
static gboolean
1648
 
motif_read_initiator_info (GdkDisplay *display,
1649
 
                           Window      source_window, 
1650
 
                           Atom        atom,
1651
 
                           GList     **targets,
1652
 
                           Atom       *selection)
1653
 
{
1654
 
  GList *tmp_list;
1655
 
  Atom type;
1656
 
  gint format;
1657
 
  gulong nitems;
1658
 
  gulong bytes_after;
1659
 
  guchar *data;
1660
 
  MotifDragInitiatorInfo *initiator_info;
1661
 
  
1662
 
  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
1663
 
  
1664
 
  gdk_error_trap_push ();
1665
 
  XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), source_window, atom,
1666
 
                      0, sizeof(*initiator_info), FALSE,
1667
 
                      gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_INITIATOR_INFO"),
1668
 
                      &type, &format, &nitems, &bytes_after,
1669
 
                      &data);
1670
 
 
1671
 
  if (gdk_error_trap_pop () || (format != 8) || (nitems != sizeof (MotifDragInitiatorInfo)) || (bytes_after != 0))
1672
 
    {
1673
 
      g_warning ("Error reading initiator info\n");
1674
 
      return FALSE;
1675
 
    }
1676
 
 
1677
 
  initiator_info = (MotifDragInitiatorInfo *)data;
1678
 
 
1679
 
  motif_read_target_table (display);
1680
 
 
1681
 
  initiator_info->targets_index = 
1682
 
    card16_to_host (initiator_info->targets_index, initiator_info->byte_order);
1683
 
  initiator_info->selection_atom = 
1684
 
    card32_to_host (initiator_info->selection_atom, initiator_info->byte_order);
1685
 
  
1686
 
  if (initiator_info->targets_index >= display_x11->motif_n_target_lists)
1687
 
    {
1688
 
      g_warning ("Invalid target index in TOP_LEVEL_ENTER MESSAGE");
1689
 
      XFree (initiator_info);
1690
 
      return FALSE;
1691
 
    }
1692
 
 
1693
 
  tmp_list = g_list_last (display_x11->motif_target_lists[initiator_info->targets_index]);
1694
 
 
1695
 
  *targets = NULL;
1696
 
  while (tmp_list)
1697
 
    {
1698
 
      GdkAtom atom = gdk_x11_xatom_to_atom_for_display (display, GPOINTER_TO_UINT (tmp_list->data));
1699
 
      *targets = g_list_prepend (*targets, GDK_ATOM_TO_POINTER (atom));
1700
 
      tmp_list = tmp_list->prev;
1701
 
    }
1702
 
 
1703
 
#ifdef G_ENABLE_DEBUG
1704
 
  if (_gdk_debug_flags & GDK_DEBUG_DND)
1705
 
    print_target_list (*targets);
1706
 
#endif /* G_ENABLE_DEBUG */
1707
 
 
1708
 
  *selection = initiator_info->selection_atom;
1709
 
 
1710
 
  XFree (initiator_info);
1711
 
 
1712
 
  return TRUE;
1713
 
}
1714
 
 
1715
 
static GdkDragContext *
1716
 
motif_drag_context_new (GdkWindow *dest_window,
1717
 
                        guint32    timestamp,
1718
 
                        guint32    source_window,
1719
 
                        guint32    atom)
1720
 
{
1721
 
  GdkDragContext *new_context;
1722
 
  GdkDragContextPrivateX11 *private;
1723
 
  GdkDisplay *display = GDK_DRAWABLE_DISPLAY (dest_window);
1724
 
  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
1725
 
 
1726
 
  /* FIXME, current_dest_drag really shouldn't be NULL'd
1727
 
   * if we error below.
1728
 
   */
1729
 
  if (display_x11->current_dest_drag != NULL)
1730
 
    {
1731
 
      if (timestamp >= display_x11->current_dest_drag->start_time)
1732
 
        {
1733
 
          g_object_unref (display_x11->current_dest_drag);
1734
 
          display_x11->current_dest_drag = NULL;
1735
 
        }
1736
 
      else
1737
 
        return NULL;
1738
 
    }
1739
 
 
1740
 
  new_context = gdk_drag_context_new ();
1741
 
  private = PRIVATE_DATA (new_context);
1742
 
 
1743
 
  new_context->protocol = GDK_DRAG_PROTO_MOTIF;
1744
 
  new_context->is_source = FALSE;
1745
 
 
1746
 
  new_context->source_window = gdk_window_lookup_for_display (display, source_window);
1747
 
  if (new_context->source_window)
1748
 
    g_object_ref (new_context->source_window);
1749
 
  else
1750
 
    {
1751
 
      new_context->source_window = gdk_window_foreign_new_for_display (display, source_window);
1752
 
      if (!new_context->source_window)
1753
 
        {
1754
 
          g_object_unref (new_context);
1755
 
          return NULL;
1756
 
        }
1757
 
    }
1758
 
 
1759
 
  new_context->dest_window = dest_window;
1760
 
  g_object_ref (dest_window);
1761
 
  new_context->start_time = timestamp;
1762
 
 
1763
 
  if (!motif_read_initiator_info (GDK_WINDOW_DISPLAY (dest_window),
1764
 
                                  source_window,
1765
 
                                  atom,
1766
 
                                  &new_context->targets,
1767
 
                                  &private->motif_selection))
1768
 
    {
1769
 
      g_object_unref (new_context);
1770
 
      return NULL;
1771
 
    }
1772
 
 
1773
 
  return new_context;
1774
 
}
1775
 
 
1776
 
/*
1777
 
 * The MOTIF drag protocol has no real provisions for distinguishing
1778
 
 * multiple simultaneous drops. If the sources grab the pointer
1779
 
 * when doing drags, that shouldn't happen, in any case. If it
1780
 
 * does, we can't do much except hope for the best.
1781
 
 */
1782
 
 
1783
 
static GdkFilterReturn
1784
 
motif_top_level_enter (GdkEvent *event,
1785
 
                       guint16   flags, 
1786
 
                       guint32   timestamp, 
1787
 
                       guint32   source_window, 
1788
 
                       guint32   atom)
1789
 
{
1790
 
  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_DRAWABLE_DISPLAY (event->any.window));
1791
 
  GdkDragContext *new_context;
1792
 
 
1793
 
  GDK_NOTE(DND, g_message ("Motif DND top level enter: flags: %#4x time: %d source_widow: %#4x atom: %d",
1794
 
                           flags, timestamp, source_window, atom));
1795
 
 
1796
 
  new_context = motif_drag_context_new (event->any.window, timestamp, source_window, atom);
1797
 
  if (!new_context)
1798
 
    return GDK_FILTER_REMOVE;
1799
 
 
1800
 
  event->dnd.type = GDK_DRAG_ENTER;
1801
 
  event->dnd.context = new_context;
1802
 
  g_object_ref (new_context);
1803
 
 
1804
 
  display_x11->current_dest_drag = new_context;
1805
 
 
1806
 
  return GDK_FILTER_TRANSLATE;
1807
 
}
1808
 
 
1809
 
static GdkFilterReturn
1810
 
motif_top_level_leave (GdkEvent *event,
1811
 
                       guint16   flags, 
1812
 
                       guint32   timestamp)
1813
 
{
1814
 
  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_DRAWABLE_DISPLAY (event->any.window));
1815
 
 
1816
 
  GDK_NOTE(DND, g_message ("Motif DND top level leave: flags: %#4x time: %d",
1817
 
                           flags, timestamp));
1818
 
 
1819
 
  if ((display_x11->current_dest_drag != NULL) &&
1820
 
      (display_x11->current_dest_drag->protocol == GDK_DRAG_PROTO_MOTIF) &&
1821
 
      (timestamp >= display_x11->current_dest_drag->start_time))
1822
 
    {
1823
 
      event->dnd.type = GDK_DRAG_LEAVE;
1824
 
      /* Pass ownership of context to the event */
1825
 
      event->dnd.context = display_x11->current_dest_drag;
1826
 
 
1827
 
      display_x11->current_dest_drag = NULL;
1828
 
 
1829
 
      return GDK_FILTER_TRANSLATE;
1830
 
    }
1831
 
  else
1832
 
    return GDK_FILTER_REMOVE;
1833
 
}
1834
 
 
1835
 
static GdkFilterReturn
1836
 
motif_motion (GdkEvent *event,
1837
 
              guint16   flags, 
1838
 
              guint32   timestamp,
1839
 
              gint16    x_root,
1840
 
              gint16    y_root)
1841
 
{
1842
 
  GdkDragContextPrivateX11 *private;
1843
 
  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_DRAWABLE_DISPLAY (event->any.window));
1844
 
  
1845
 
  GDK_NOTE(DND, g_message ("Motif DND motion: flags: %#4x time: %d (%d, %d)",
1846
 
                           flags, timestamp, x_root, y_root));
1847
 
 
1848
 
  if ((display_x11->current_dest_drag != NULL) &&
1849
 
      (display_x11->current_dest_drag->protocol == GDK_DRAG_PROTO_MOTIF) &&
1850
 
      (timestamp >= display_x11->current_dest_drag->start_time))
1851
 
    {
1852
 
      private = PRIVATE_DATA (display_x11->current_dest_drag);
1853
 
 
1854
 
      event->dnd.type = GDK_DRAG_MOTION;
1855
 
      event->dnd.context = display_x11->current_dest_drag;
1856
 
      g_object_ref (display_x11->current_dest_drag);
1857
 
 
1858
 
      event->dnd.time = timestamp;
1859
 
 
1860
 
      motif_dnd_translate_flags (display_x11->current_dest_drag, flags);
1861
 
 
1862
 
      event->dnd.x_root = x_root;
1863
 
      event->dnd.y_root = y_root;
1864
 
 
1865
 
      private->last_x = x_root;
1866
 
      private->last_y = y_root;
1867
 
 
1868
 
      private->drag_status = GDK_DRAG_STATUS_MOTION_WAIT;
1869
 
 
1870
 
      return GDK_FILTER_TRANSLATE;
1871
 
    }
1872
 
 
1873
 
  return GDK_FILTER_REMOVE;
1874
 
}
1875
 
 
1876
 
static GdkFilterReturn
1877
 
motif_operation_changed (GdkEvent *event,
1878
 
                         guint16   flags, 
1879
 
                         guint32   timestamp)
1880
 
{
1881
 
  GdkDragContextPrivateX11 *private;
1882
 
  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_DRAWABLE_DISPLAY (event->any.window));
1883
 
  GDK_NOTE(DND, g_message ("Motif DND operation changed: flags: %#4x time: %d",
1884
 
                           flags, timestamp));
1885
 
 
1886
 
  if ((display_x11->current_dest_drag != NULL) &&
1887
 
      (display_x11->current_dest_drag->protocol == GDK_DRAG_PROTO_MOTIF) &&
1888
 
      (timestamp >= display_x11->current_dest_drag->start_time))
1889
 
    {
1890
 
      event->dnd.type = GDK_DRAG_MOTION;
1891
 
      event->dnd.send_event = FALSE;
1892
 
      event->dnd.context = display_x11->current_dest_drag;
1893
 
      g_object_ref (display_x11->current_dest_drag);
1894
 
 
1895
 
      event->dnd.time = timestamp;
1896
 
      private = PRIVATE_DATA (display_x11->current_dest_drag);
1897
 
 
1898
 
      motif_dnd_translate_flags (display_x11->current_dest_drag, flags);
1899
 
 
1900
 
      event->dnd.x_root = private->last_x;
1901
 
      event->dnd.y_root = private->last_y;
1902
 
 
1903
 
      private->drag_status = GDK_DRAG_STATUS_ACTION_WAIT;
1904
 
 
1905
 
      return GDK_FILTER_TRANSLATE;
1906
 
    }
1907
 
 
1908
 
  return GDK_FILTER_REMOVE;
1909
 
}
1910
 
 
1911
 
static GdkFilterReturn
1912
 
motif_drop_start (GdkEvent *event,
1913
 
                  guint16   flags,
1914
 
                  guint32   timestamp,
1915
 
                  guint32   source_window,
1916
 
                  guint32   atom,
1917
 
                  gint16    x_root,
1918
 
                  gint16    y_root)
1919
 
{
1920
 
  GdkDragContext *new_context;
1921
 
  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_DRAWABLE_DISPLAY (event->any.window));
1922
 
 
1923
 
  GDK_NOTE(DND, g_message ("Motif DND drop start: flags: %#4x time: %d (%d, %d) source_widow: %#4x atom: %d",
1924
 
                           flags, timestamp, x_root, y_root, source_window, atom));
1925
 
 
1926
 
  new_context = motif_drag_context_new (event->any.window, timestamp, source_window, atom);
1927
 
  if (!new_context)
1928
 
    return GDK_FILTER_REMOVE;
1929
 
 
1930
 
  motif_dnd_translate_flags (new_context, flags);
1931
 
 
1932
 
  event->dnd.type = GDK_DROP_START;
1933
 
  event->dnd.context = new_context;
1934
 
  event->dnd.time = timestamp;
1935
 
  event->dnd.x_root = x_root;
1936
 
  event->dnd.y_root = y_root;
1937
 
 
1938
 
  gdk_x11_window_set_user_time (event->any.window, timestamp);
1939
 
 
1940
 
  g_object_ref (new_context);
1941
 
  display_x11->current_dest_drag = new_context;
1942
 
 
1943
 
  return GDK_FILTER_TRANSLATE;
1944
 
}  
1945
 
 
1946
 
static GdkFilterReturn
1947
 
motif_drag_status (GdkEvent *event,
1948
 
                   guint16   flags,
1949
 
                   guint32   timestamp)
1950
 
{
1951
 
  GdkDragContext *context;
1952
 
  GdkDisplay *display;
1953
 
  
1954
 
  GDK_NOTE (DND, 
1955
 
            g_message ("Motif status message: flags %x", flags));
1956
 
 
1957
 
  display = gdk_drawable_get_display (event->any.window);
1958
 
  if (!display)
1959
 
    return GDK_FILTER_REMOVE;
1960
 
  
1961
 
  context = gdk_drag_context_find (display, TRUE, GDK_DRAWABLE_XID (event->any.window), None);
1962
 
 
1963
 
  if (context)
1964
 
    {
1965
 
      GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
1966
 
      if ((private->drag_status == GDK_DRAG_STATUS_MOTION_WAIT) ||
1967
 
          (private->drag_status == GDK_DRAG_STATUS_ACTION_WAIT))
1968
 
        private->drag_status = GDK_DRAG_STATUS_DRAG;
1969
 
      
1970
 
      event->dnd.type = GDK_DRAG_STATUS;
1971
 
      event->dnd.send_event = FALSE;
1972
 
      event->dnd.context = context;
1973
 
      g_object_ref (context);
1974
 
 
1975
 
      event->dnd.time = timestamp;
1976
 
 
1977
 
      if ((flags & 0x00f0) >> 4 == XmDROP_SITE_VALID)
1978
 
        {
1979
 
          switch (flags & 0x000f)
1980
 
            {
1981
 
            case XmDROP_NOOP:
1982
 
              context->action = 0;
1983
 
              break;
1984
 
            case XmDROP_MOVE:
1985
 
                context->action = GDK_ACTION_MOVE;
1986
 
                break;
1987
 
            case XmDROP_COPY:
1988
 
              context->action = GDK_ACTION_COPY;
1989
 
              break;
1990
 
            case XmDROP_LINK:
1991
 
              context->action = GDK_ACTION_LINK;
1992
 
              break;
1993
 
            }
1994
 
        }
1995
 
      else
1996
 
        context->action = 0;
1997
 
 
1998
 
      return GDK_FILTER_TRANSLATE;
1999
 
    }
2000
 
  return GDK_FILTER_REMOVE;
2001
 
}
2002
 
 
2003
 
static GdkFilterReturn
2004
 
motif_dnd_filter (GdkXEvent *xev,
2005
 
                  GdkEvent  *event,
2006
 
                  gpointer data)
2007
 
{
2008
 
  XEvent *xevent = (XEvent *)xev;
2009
 
 
2010
 
  guint8 reason;
2011
 
  guint16 flags;
2012
 
  guint32 timestamp;
2013
 
  guint32 source_window;
2014
 
  Atom atom;
2015
 
  gint16 x_root, y_root;
2016
 
  gboolean is_reply;
2017
 
 
2018
 
  if (!event->any.window ||
2019
 
      gdk_window_get_window_type (event->any.window) == GDK_WINDOW_FOREIGN)
2020
 
    return GDK_FILTER_CONTINUE;                 /* Not for us */
2021
 
  
2022
 
  /* First read some fields common to all Motif DND messages */
2023
 
 
2024
 
  reason = MOTIF_UNPACK_BYTE (xevent, 0);
2025
 
  flags = MOTIF_UNPACK_SHORT (xevent, 1);
2026
 
  timestamp = MOTIF_UNPACK_LONG (xevent, 1);
2027
 
 
2028
 
  is_reply = ((reason & 0x80) != 0);
2029
 
 
2030
 
  switch (reason & 0x7f)
2031
 
    {
2032
 
    case XmTOP_LEVEL_ENTER:
2033
 
      source_window = MOTIF_UNPACK_LONG (xevent, 2);
2034
 
      atom = MOTIF_UNPACK_LONG (xevent, 3);
2035
 
      return motif_top_level_enter (event, flags, timestamp, source_window, atom);
2036
 
    case XmTOP_LEVEL_LEAVE:
2037
 
      return motif_top_level_leave (event, flags, timestamp);
2038
 
 
2039
 
    case XmDRAG_MOTION:
2040
 
      x_root = MOTIF_UNPACK_SHORT (xevent, 4);
2041
 
      y_root = MOTIF_UNPACK_SHORT (xevent, 5);
2042
 
      
2043
 
      if (!is_reply)
2044
 
        return motif_motion (event, flags, timestamp, x_root, y_root);
2045
 
      else
2046
 
        return motif_drag_status (event, flags, timestamp);
2047
 
 
2048
 
    case XmDROP_SITE_ENTER:
2049
 
      return motif_drag_status (event, flags, timestamp);
2050
 
 
2051
 
    case XmDROP_SITE_LEAVE:
2052
 
      return motif_drag_status (event,
2053
 
                                XmNO_DROP_SITE << 8 | XmDROP_NOOP, 
2054
 
                                timestamp);
2055
 
    case XmDROP_START:
2056
 
      x_root = MOTIF_UNPACK_SHORT (xevent, 4);
2057
 
      y_root = MOTIF_UNPACK_SHORT (xevent, 5);
2058
 
      atom = MOTIF_UNPACK_LONG (xevent, 3);
2059
 
      source_window = MOTIF_UNPACK_LONG (xevent, 4);
2060
 
 
2061
 
      if (!is_reply)
2062
 
        return motif_drop_start (event, flags, timestamp, source_window, atom, x_root, y_root);
2063
 
      
2064
 
     break;
2065
 
    case XmOPERATION_CHANGED:
2066
 
      if (!is_reply)
2067
 
        return motif_operation_changed (event, flags, timestamp);
2068
 
      else
2069
 
        return motif_drag_status (event, flags, timestamp);
2070
 
 
2071
 
      break;
2072
 
      /* To the best of my knowledge, these next two messages are 
2073
 
       * not part of the protocol, though they are defined in
2074
 
       * the header files.
2075
 
       */
2076
 
    case XmDROP_FINISH:
2077
 
    case XmDRAG_DROP_FINISH:
2078
 
      break;
2079
 
    }
2080
 
 
2081
 
  return GDK_FILTER_REMOVE;
2082
 
}
2083
 
 
2084
 
/*************************************************************
2085
 
 ***************************** XDND **************************
2086
 
 *************************************************************/
2087
 
 
2088
 
/* Utility functions */
2089
 
 
2090
 
static struct {
2091
 
  const gchar *name;
2092
 
  GdkAtom atom;
2093
 
  GdkDragAction action;
2094
 
} xdnd_actions_table[] = {
2095
 
    { "XdndActionCopy",    None, GDK_ACTION_COPY },
2096
 
    { "XdndActionMove",    None, GDK_ACTION_MOVE },
2097
 
    { "XdndActionLink",    None, GDK_ACTION_LINK },
2098
 
    { "XdndActionAsk",     None, GDK_ACTION_ASK  },
2099
 
    { "XdndActionPrivate", None, GDK_ACTION_COPY },
2100
 
  };
2101
 
 
2102
 
static const gint xdnd_n_actions = sizeof(xdnd_actions_table) / sizeof(xdnd_actions_table[0]);
2103
 
static gboolean xdnd_actions_initialized = FALSE;
2104
 
 
2105
 
static void
2106
 
xdnd_initialize_actions (void)
2107
 
{
2108
 
  gint i;
2109
 
  
2110
 
  xdnd_actions_initialized = TRUE;
2111
 
  for (i=0; i < xdnd_n_actions; i++)
2112
 
    xdnd_actions_table[i].atom = gdk_atom_intern_static_string (xdnd_actions_table[i].name);
2113
 
}
2114
 
 
2115
 
static GdkDragAction
2116
 
xdnd_action_from_atom (GdkDisplay *display,
2117
 
                       Atom        xatom)
2118
 
{
2119
 
  GdkAtom atom;
2120
 
  gint i;
2121
 
 
2122
 
  if (xatom == None)
2123
 
    return 0;
2124
 
 
2125
 
  atom = gdk_x11_xatom_to_atom_for_display (display, xatom);
2126
 
 
2127
 
  if (!xdnd_actions_initialized)
2128
 
    xdnd_initialize_actions();
2129
 
 
2130
 
  for (i=0; i<xdnd_n_actions; i++)
2131
 
    if (atom == xdnd_actions_table[i].atom)
2132
 
      return xdnd_actions_table[i].action;
2133
 
 
2134
 
  return 0;
2135
 
}
2136
 
 
2137
 
static Atom
2138
 
xdnd_action_to_atom (GdkDisplay    *display,
2139
 
                     GdkDragAction  action)
2140
 
{
2141
 
  gint i;
2142
 
 
2143
 
  if (!xdnd_actions_initialized)
2144
 
    xdnd_initialize_actions();
2145
 
 
2146
 
  for (i=0; i<xdnd_n_actions; i++)
2147
 
    if (action == xdnd_actions_table[i].action)
2148
 
      return gdk_x11_atom_to_xatom_for_display (display, xdnd_actions_table[i].atom);
2149
 
 
2150
 
  return None;
2151
 
}
2152
 
 
2153
 
/* Source side */
2154
 
 
2155
 
static GdkFilterReturn 
2156
 
xdnd_status_filter (GdkXEvent *xev,
2157
 
                    GdkEvent  *event,
2158
 
                    gpointer   data)
2159
 
{
2160
 
  GdkDisplay *display;
2161
 
  XEvent *xevent = (XEvent *)xev;
2162
 
  guint32 dest_window = xevent->xclient.data.l[0];
2163
 
  guint32 flags = xevent->xclient.data.l[1];
2164
 
  Atom action = xevent->xclient.data.l[4];
2165
 
  GdkDragContext *context;
2166
 
 
2167
 
  if (!event->any.window ||
2168
 
      gdk_window_get_window_type (event->any.window) == GDK_WINDOW_FOREIGN)
2169
 
    return GDK_FILTER_CONTINUE;                 /* Not for us */
2170
 
  
2171
 
  GDK_NOTE (DND, 
2172
 
            g_message ("XdndStatus: dest_window: %#x  action: %ld",
2173
 
                       dest_window, action));
2174
 
 
2175
 
  display = gdk_drawable_get_display (event->any.window);
2176
 
  context = gdk_drag_context_find (display, TRUE, xevent->xclient.window, dest_window);
2177
 
  
2178
 
  if (context)
2179
 
    {
2180
 
      GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
2181
 
      if (private->drag_status == GDK_DRAG_STATUS_MOTION_WAIT)
2182
 
        private->drag_status = GDK_DRAG_STATUS_DRAG;
2183
 
      
2184
 
      event->dnd.send_event = FALSE;
2185
 
      event->dnd.type = GDK_DRAG_STATUS;
2186
 
      event->dnd.context = context;
2187
 
      g_object_ref (context);
2188
 
 
2189
 
      event->dnd.time = GDK_CURRENT_TIME; /* FIXME? */
2190
 
      if (!(action != 0) != !(flags & 1))
2191
 
        {
2192
 
          GDK_NOTE (DND,
2193
 
                    g_warning ("Received status event with flags not corresponding to action!\n"));
2194
 
          action = 0;
2195
 
        }
2196
 
 
2197
 
      context->action = xdnd_action_from_atom (display, action);
2198
 
 
2199
 
      return GDK_FILTER_TRANSLATE;
2200
 
    }
2201
 
 
2202
 
  return GDK_FILTER_REMOVE;
2203
 
}
2204
 
 
2205
 
static GdkFilterReturn 
2206
 
xdnd_finished_filter (GdkXEvent *xev,
2207
 
                      GdkEvent  *event,
2208
 
                      gpointer   data)
2209
 
{
2210
 
  GdkDisplay *display;
2211
 
  XEvent *xevent = (XEvent *)xev;
2212
 
  guint32 dest_window = xevent->xclient.data.l[0];
2213
 
  GdkDragContext *context;
2214
 
  GdkDragContextPrivateX11 *private;
2215
 
 
2216
 
  if (!event->any.window ||
2217
 
      gdk_window_get_window_type (event->any.window) == GDK_WINDOW_FOREIGN)
2218
 
    return GDK_FILTER_CONTINUE;                 /* Not for us */
2219
 
  
2220
 
  GDK_NOTE (DND, 
2221
 
            g_message ("XdndFinished: dest_window: %#x", dest_window));
2222
 
 
2223
 
  display = gdk_drawable_get_display (event->any.window);
2224
 
  context = gdk_drag_context_find (display, TRUE, xevent->xclient.window, dest_window);
2225
 
  
2226
 
  if (context)
2227
 
    {
2228
 
      private = PRIVATE_DATA (context);
2229
 
      if (private->version == 5)
2230
 
        private->drop_failed = xevent->xclient.data.l[1] == 0;
2231
 
      
2232
 
      event->dnd.type = GDK_DROP_FINISHED;
2233
 
      event->dnd.context = context;
2234
 
      g_object_ref (context);
2235
 
 
2236
 
      event->dnd.time = GDK_CURRENT_TIME; /* FIXME? */
2237
 
 
2238
 
      return GDK_FILTER_TRANSLATE;
2239
 
    }
2240
 
 
2241
 
  return GDK_FILTER_REMOVE;
2242
 
}
2243
 
 
2244
 
static void
2245
 
xdnd_set_targets (GdkDragContext *context)
2246
 
{
2247
 
  GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
2248
 
  Atom *atomlist;
2249
 
  GList *tmp_list = context->targets;
2250
 
  gint i;
2251
 
  gint n_atoms = g_list_length (context->targets);
2252
 
  GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window);
2253
 
 
2254
 
  atomlist = g_new (Atom, n_atoms);
2255
 
  i = 0;
2256
 
  while (tmp_list)
2257
 
    {
2258
 
      atomlist[i] = gdk_x11_atom_to_xatom_for_display (display, GDK_POINTER_TO_ATOM (tmp_list->data));
2259
 
      tmp_list = tmp_list->next;
2260
 
      i++;
2261
 
    }
2262
 
 
2263
 
  XChangeProperty (GDK_DRAWABLE_XDISPLAY (context->source_window),
2264
 
                   GDK_DRAWABLE_XID (context->source_window),
2265
 
                   gdk_x11_get_xatom_by_name_for_display (display, "XdndTypeList"),
2266
 
                   XA_ATOM, 32, PropModeReplace,
2267
 
                   (guchar *)atomlist, n_atoms);
2268
 
 
2269
 
  g_free (atomlist);
2270
 
 
2271
 
  private->xdnd_targets_set = 1;
2272
 
}
2273
 
 
2274
 
static void
2275
 
xdnd_set_actions (GdkDragContext *context)
2276
 
{
2277
 
  GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
2278
 
  Atom *atomlist;
2279
 
  gint i;
2280
 
  gint n_atoms;
2281
 
  guint actions;
2282
 
  GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window);
2283
 
 
2284
 
  if (!xdnd_actions_initialized)
2285
 
    xdnd_initialize_actions();
2286
 
  
2287
 
  actions = context->actions;
2288
 
  n_atoms = 0;
2289
 
  for (i=0; i<xdnd_n_actions; i++)
2290
 
    {
2291
 
      if (actions & xdnd_actions_table[i].action)
2292
 
        {
2293
 
          actions &= ~xdnd_actions_table[i].action;
2294
 
          n_atoms++;
2295
 
        }
2296
 
    }
2297
 
 
2298
 
  atomlist = g_new (Atom, n_atoms);
2299
 
 
2300
 
  actions = context->actions;
2301
 
  n_atoms = 0;
2302
 
  for (i=0; i<xdnd_n_actions; i++)
2303
 
    {
2304
 
      if (actions & xdnd_actions_table[i].action)
2305
 
        {
2306
 
          actions &= ~xdnd_actions_table[i].action;
2307
 
          atomlist[n_atoms] = gdk_x11_atom_to_xatom_for_display (display, xdnd_actions_table[i].atom);
2308
 
          n_atoms++;
2309
 
        }
2310
 
    }
2311
 
 
2312
 
  XChangeProperty (GDK_DRAWABLE_XDISPLAY (context->source_window),
2313
 
                   GDK_DRAWABLE_XID (context->source_window),
2314
 
                   gdk_x11_get_xatom_by_name_for_display (display, "XdndActionList"),
2315
 
                   XA_ATOM, 32, PropModeReplace,
2316
 
                   (guchar *)atomlist, n_atoms);
2317
 
 
2318
 
  g_free (atomlist);
2319
 
 
2320
 
  private->xdnd_actions_set = TRUE;
2321
 
  private->xdnd_actions = context->actions;
2322
 
}
2323
 
 
2324
 
static void
2325
 
send_client_message_async_cb (Window   window,
2326
 
                              gboolean success,
2327
 
                              gpointer data)
2328
 
{
2329
 
  GdkDragContext *context = data;
2330
 
  GDK_NOTE (DND,
2331
 
            g_message ("Got async callback for #%lx, success = %d",
2332
 
                       window, success));
2333
 
 
2334
 
  /* On failure, we immediately continue with the protocol
2335
 
   * so we don't end up blocking for a timeout
2336
 
   */
2337
 
  if (!success &&
2338
 
      context->dest_window &&
2339
 
      window == GDK_WINDOW_XID (context->dest_window))
2340
 
    {
2341
 
      GdkEvent temp_event;
2342
 
      GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
2343
 
 
2344
 
      g_object_unref (context->dest_window);
2345
 
      context->dest_window = NULL;
2346
 
      context->action = 0;
2347
 
 
2348
 
      private->drag_status = GDK_DRAG_STATUS_DRAG;
2349
 
 
2350
 
      temp_event.dnd.type = GDK_DRAG_STATUS;
2351
 
      temp_event.dnd.window = context->source_window;
2352
 
      temp_event.dnd.send_event = TRUE;
2353
 
      temp_event.dnd.context = context;
2354
 
      temp_event.dnd.time = GDK_CURRENT_TIME;
2355
 
 
2356
 
      gdk_event_put (&temp_event);
2357
 
    }
2358
 
 
2359
 
  g_object_unref (context);
2360
 
}
2361
 
 
2362
 
 
2363
 
static GdkDisplay *
2364
 
gdk_drag_context_get_display (GdkDragContext *context)
2365
 
{
2366
 
  if (context->source_window)
2367
 
    return GDK_DRAWABLE_DISPLAY (context->source_window);
2368
 
  else if (context->dest_window)
2369
 
    return GDK_DRAWABLE_DISPLAY (context->dest_window);
2370
 
 
2371
 
  g_assert_not_reached ();
2372
 
  return NULL;
2373
 
}
2374
 
 
2375
 
static void
2376
 
send_client_message_async (GdkDragContext      *context,
2377
 
                           Window               window, 
2378
 
                           gboolean             propagate,
2379
 
                           glong                event_mask,
2380
 
                           XClientMessageEvent *event_send)
2381
 
{
2382
 
  GdkDisplay *display = gdk_drag_context_get_display (context);
2383
 
  
2384
 
  g_object_ref (context);
2385
 
 
2386
 
  _gdk_x11_send_client_message_async (display, window,
2387
 
                                      propagate, event_mask, event_send,
2388
 
                                      send_client_message_async_cb, context);
2389
 
}
2390
 
 
2391
 
static gboolean
2392
 
xdnd_send_xevent (GdkDragContext *context,
2393
 
                  GdkWindow      *window, 
2394
 
                  gboolean        propagate,
2395
 
                  XEvent         *event_send)
2396
 
{
2397
 
  GdkDisplay *display = gdk_drag_context_get_display (context);
2398
 
  Window xwindow;
2399
 
  glong event_mask;
2400
 
 
2401
 
  g_assert (event_send->xany.type == ClientMessage);
2402
 
 
2403
 
  /* We short-circuit messages to ourselves */
2404
 
  if (gdk_window_get_window_type (window) != GDK_WINDOW_FOREIGN)
2405
 
    {
2406
 
      gint i;
2407
 
      
2408
 
      for (i = 0; i < G_N_ELEMENTS (xdnd_filters); i++)
2409
 
        {
2410
 
          if (gdk_x11_get_xatom_by_name_for_display (display, xdnd_filters[i].atom_name) ==
2411
 
              event_send->xclient.message_type)
2412
 
            {
2413
 
              GdkEvent temp_event;
2414
 
              temp_event.any.window = window;
2415
 
 
2416
 
              if  ((*xdnd_filters[i].func) (event_send, &temp_event, NULL) == GDK_FILTER_TRANSLATE)
2417
 
                {
2418
 
                  gdk_event_put (&temp_event);
2419
 
                  g_object_unref (temp_event.dnd.context);
2420
 
                }
2421
 
              
2422
 
              return TRUE;
2423
 
            }
2424
 
        }
2425
 
    }
2426
 
 
2427
 
  xwindow = GDK_WINDOW_XWINDOW (window);
2428
 
  
2429
 
  if (_gdk_x11_display_is_root_window (display, xwindow))
2430
 
    event_mask = ButtonPressMask;
2431
 
  else
2432
 
    event_mask = 0;
2433
 
  
2434
 
  send_client_message_async (context, xwindow, propagate, event_mask,
2435
 
                             &event_send->xclient);
2436
 
 
2437
 
  return TRUE;
2438
 
}
2439
 
 
2440
 
static void
2441
 
xdnd_send_enter (GdkDragContext *context)
2442
 
{
2443
 
  XEvent xev;
2444
 
  GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
2445
 
  GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->dest_window);
2446
 
 
2447
 
  xev.xclient.type = ClientMessage;
2448
 
  xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "XdndEnter");
2449
 
  xev.xclient.format = 32;
2450
 
  xev.xclient.window = private->drop_xid ? 
2451
 
                           private->drop_xid : 
2452
 
                           GDK_DRAWABLE_XID (context->dest_window);
2453
 
  xev.xclient.data.l[0] = GDK_DRAWABLE_XID (context->source_window);
2454
 
  xev.xclient.data.l[1] = (private->version << 24); /* version */
2455
 
  xev.xclient.data.l[2] = 0;
2456
 
  xev.xclient.data.l[3] = 0;
2457
 
  xev.xclient.data.l[4] = 0;
2458
 
 
2459
 
  GDK_NOTE(DND,
2460
 
           g_message ("Sending enter source window %#lx XDND protocol version %d\n",
2461
 
                      GDK_DRAWABLE_XID (context->source_window), private->version));
2462
 
  if (g_list_length (context->targets) > 3)
2463
 
    {
2464
 
      if (!private->xdnd_targets_set)
2465
 
        xdnd_set_targets (context);
2466
 
      xev.xclient.data.l[1] |= 1;
2467
 
    }
2468
 
  else
2469
 
    {
2470
 
      GList *tmp_list = context->targets;
2471
 
      gint i = 2;
2472
 
 
2473
 
      while (tmp_list)
2474
 
        {
2475
 
          xev.xclient.data.l[i] = gdk_x11_atom_to_xatom_for_display (display,
2476
 
                                                                     GDK_POINTER_TO_ATOM (tmp_list->data));
2477
 
          tmp_list = tmp_list->next;
2478
 
          i++;
2479
 
        }
2480
 
    }
2481
 
 
2482
 
  if (!xdnd_send_xevent (context, context->dest_window,
2483
 
                         FALSE, &xev))
2484
 
    {
2485
 
      GDK_NOTE (DND, 
2486
 
                g_message ("Send event to %lx failed",
2487
 
                           GDK_DRAWABLE_XID (context->dest_window)));
2488
 
      g_object_unref (context->dest_window);
2489
 
      context->dest_window = NULL;
2490
 
    }
2491
 
}
2492
 
 
2493
 
static void
2494
 
xdnd_send_leave (GdkDragContext *context)
2495
 
{
2496
 
  GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window);
2497
 
  XEvent xev;
2498
 
 
2499
 
  GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
2500
 
 
2501
 
  xev.xclient.type = ClientMessage;
2502
 
  xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "XdndLeave");
2503
 
  xev.xclient.format = 32;
2504
 
  xev.xclient.window = private->drop_xid ? 
2505
 
                           private->drop_xid : 
2506
 
                           GDK_DRAWABLE_XID (context->dest_window);
2507
 
  xev.xclient.data.l[0] = GDK_DRAWABLE_XID (context->source_window);
2508
 
  xev.xclient.data.l[1] = 0;
2509
 
  xev.xclient.data.l[2] = 0;
2510
 
  xev.xclient.data.l[3] = 0;
2511
 
  xev.xclient.data.l[4] = 0;
2512
 
 
2513
 
  if (!xdnd_send_xevent (context, context->dest_window,
2514
 
                         FALSE, &xev))
2515
 
    {
2516
 
      GDK_NOTE (DND, 
2517
 
                g_message ("Send event to %lx failed",
2518
 
                           GDK_DRAWABLE_XID (context->dest_window)));
2519
 
      g_object_unref (context->dest_window);
2520
 
      context->dest_window = NULL;
2521
 
    }
2522
 
}
2523
 
 
2524
 
static void
2525
 
xdnd_send_drop (GdkDragContext *context, guint32 time)
2526
 
{
2527
 
  GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
2528
 
  GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window);
2529
 
  XEvent xev;
2530
 
 
2531
 
  xev.xclient.type = ClientMessage;
2532
 
  xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "XdndDrop");
2533
 
  xev.xclient.format = 32;
2534
 
  xev.xclient.window = private->drop_xid ? 
2535
 
                           private->drop_xid : 
2536
 
                           GDK_DRAWABLE_XID (context->dest_window);
2537
 
  xev.xclient.data.l[0] = GDK_DRAWABLE_XID (context->source_window);
2538
 
  xev.xclient.data.l[1] = 0;
2539
 
  xev.xclient.data.l[2] = time;
2540
 
  xev.xclient.data.l[3] = 0;
2541
 
  xev.xclient.data.l[4] = 0;
2542
 
 
2543
 
  if (!xdnd_send_xevent (context, context->dest_window,
2544
 
                         FALSE, &xev))
2545
 
    {
2546
 
      GDK_NOTE (DND, 
2547
 
                g_message ("Send event to %lx failed",
2548
 
                           GDK_DRAWABLE_XID (context->dest_window)));
2549
 
      g_object_unref (context->dest_window);
2550
 
      context->dest_window = NULL;
2551
 
    }
2552
 
}
2553
 
 
2554
 
static void
2555
 
xdnd_send_motion (GdkDragContext *context,
2556
 
                  gint            x_root, 
2557
 
                  gint            y_root,
2558
 
                  GdkDragAction   action,
2559
 
                  guint32         time)
2560
 
{
2561
 
  GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
2562
 
  GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window);
2563
 
  XEvent xev;
2564
 
 
2565
 
  xev.xclient.type = ClientMessage;
2566
 
  xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "XdndPosition");
2567
 
  xev.xclient.format = 32;
2568
 
  xev.xclient.window = private->drop_xid ? 
2569
 
                           private->drop_xid : 
2570
 
                           GDK_DRAWABLE_XID (context->dest_window);
2571
 
  xev.xclient.data.l[0] = GDK_DRAWABLE_XID (context->source_window);
2572
 
  xev.xclient.data.l[1] = 0;
2573
 
  xev.xclient.data.l[2] = (x_root << 16) | y_root;
2574
 
  xev.xclient.data.l[3] = time;
2575
 
  xev.xclient.data.l[4] = xdnd_action_to_atom (display, action);
2576
 
 
2577
 
  if (!xdnd_send_xevent (context, context->dest_window,
2578
 
                         FALSE, &xev))
2579
 
    {
2580
 
      GDK_NOTE (DND, 
2581
 
                g_message ("Send event to %lx failed",
2582
 
                           GDK_DRAWABLE_XID (context->dest_window)));
2583
 
      g_object_unref (context->dest_window);
2584
 
      context->dest_window = NULL;
2585
 
    }
2586
 
  private->drag_status = GDK_DRAG_STATUS_MOTION_WAIT;
2587
 
}
2588
 
 
2589
 
static guint32
2590
 
xdnd_check_dest (GdkDisplay *display,
2591
 
                 Window      win,
2592
 
                 guint      *xdnd_version)
2593
 
{
2594
 
  gboolean retval = FALSE;
2595
 
  Atom type = None;
2596
 
  int format;
2597
 
  unsigned long nitems, after;
2598
 
  guchar *data;
2599
 
  Atom *version;
2600
 
  Window *proxy_data;
2601
 
  Window proxy;
2602
 
  Atom xdnd_proxy_atom = gdk_x11_get_xatom_by_name_for_display (display, "XdndProxy");
2603
 
  Atom xdnd_aware_atom = gdk_x11_get_xatom_by_name_for_display (display, "XdndAware");
2604
 
 
2605
 
  proxy = None;
2606
 
 
2607
 
  gdk_error_trap_push ();
2608
 
  
2609
 
  if (XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), win, 
2610
 
                          xdnd_proxy_atom, 0, 
2611
 
                          1, False, AnyPropertyType,
2612
 
                          &type, &format, &nitems, &after, 
2613
 
                          &data) == Success)
2614
 
    {
2615
 
      if (type != None)
2616
 
        {
2617
 
          proxy_data = (Window *)data;
2618
 
          
2619
 
          if ((format == 32) && (nitems == 1))
2620
 
            {
2621
 
              proxy = *proxy_data;
2622
 
            }
2623
 
          else
2624
 
            GDK_NOTE (DND, 
2625
 
                      g_warning ("Invalid XdndProxy "
2626
 
                                 "property on window %ld\n", win));
2627
 
          
2628
 
          XFree (proxy_data);
2629
 
        }
2630
 
      
2631
 
      if ((XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), proxy ? proxy : win,
2632
 
                               xdnd_aware_atom, 0, 
2633
 
                               1, False, AnyPropertyType,
2634
 
                               &type, &format, &nitems, &after, 
2635
 
                               &data) == Success) &&
2636
 
          type != None)
2637
 
        {
2638
 
          version = (Atom *)data;
2639
 
          
2640
 
          if ((format == 32) && (nitems == 1))
2641
 
            {
2642
 
              if (*version >= 3)
2643
 
                retval = TRUE;
2644
 
              if (xdnd_version)
2645
 
                *xdnd_version = *version;
2646
 
            }
2647
 
          else
2648
 
            GDK_NOTE (DND, 
2649
 
                      g_warning ("Invalid XdndAware "
2650
 
                                 "property on window %ld\n", win));
2651
 
          
2652
 
          XFree (version);
2653
 
        }
2654
 
    }
2655
 
 
2656
 
  gdk_error_trap_pop ();
2657
 
  
2658
 
  return retval ? (proxy ? proxy : win) : None;
2659
 
}
2660
 
 
2661
 
/* Target side */
2662
 
 
2663
 
static void
2664
 
xdnd_read_actions (GdkDragContext *context)
2665
 
{
2666
 
  GdkDisplay *display = GDK_WINDOW_DISPLAY (context->source_window);
2667
 
  Atom type;
2668
 
  int format;
2669
 
  gulong nitems, after;
2670
 
  guchar *data;
2671
 
  Atom *atoms;
2672
 
 
2673
 
  gint i;
2674
 
  
2675
 
  PRIVATE_DATA (context)->xdnd_have_actions = FALSE;
2676
 
 
2677
 
  if (gdk_window_get_window_type (context->source_window) == GDK_WINDOW_FOREIGN)
2678
 
    {
2679
 
      /* Get the XdndActionList, if set */
2680
 
      
2681
 
      gdk_error_trap_push ();
2682
 
      
2683
 
      if (XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display),
2684
 
                              GDK_DRAWABLE_XID (context->source_window),
2685
 
                              gdk_x11_get_xatom_by_name_for_display (display, "XdndActionList"),
2686
 
                              0, 65536,
2687
 
                              False, XA_ATOM, &type, &format, &nitems,
2688
 
                              &after, &data) == Success &&
2689
 
          type == XA_ATOM)
2690
 
        {
2691
 
          atoms = (Atom *)data;
2692
 
          
2693
 
          context->actions = 0;
2694
 
          
2695
 
          for (i=0; i<nitems; i++)
2696
 
            context->actions |= xdnd_action_from_atom (display, atoms[i]);
2697
 
          
2698
 
          PRIVATE_DATA (context)->xdnd_have_actions = TRUE;
2699
 
          
2700
 
#ifdef G_ENABLE_DEBUG
2701
 
          if (_gdk_debug_flags & GDK_DEBUG_DND)
2702
 
            {
2703
 
              GString *action_str = g_string_new (NULL);
2704
 
              if (context->actions & GDK_ACTION_MOVE)
2705
 
                g_string_append(action_str, "MOVE ");
2706
 
              if (context->actions & GDK_ACTION_COPY)
2707
 
                g_string_append(action_str, "COPY ");
2708
 
              if (context->actions & GDK_ACTION_LINK)
2709
 
                g_string_append(action_str, "LINK ");
2710
 
              if (context->actions & GDK_ACTION_ASK)
2711
 
                g_string_append(action_str, "ASK ");
2712
 
              
2713
 
              g_message("Xdnd actions = %s", action_str->str);
2714
 
              g_string_free (action_str, TRUE);
2715
 
            }
2716
 
#endif /* G_ENABLE_DEBUG */
2717
 
          
2718
 
        }
2719
 
 
2720
 
      if (data)
2721
 
        XFree (data);
2722
 
      
2723
 
      gdk_error_trap_pop ();
2724
 
    }
2725
 
  else
2726
 
    {
2727
 
      /* Local drag
2728
 
       */
2729
 
      GdkDragContext *source_context;
2730
 
 
2731
 
      source_context = gdk_drag_context_find (display, TRUE,
2732
 
                                              GDK_DRAWABLE_XID (context->source_window),
2733
 
                                              GDK_DRAWABLE_XID (context->dest_window));
2734
 
 
2735
 
      if (source_context)
2736
 
        {
2737
 
          context->actions = source_context->actions;
2738
 
          PRIVATE_DATA (context)->xdnd_have_actions = TRUE;
2739
 
        }
2740
 
    }
2741
 
}
2742
 
 
2743
 
/* We have to make sure that the XdndActionList we keep internally
2744
 
 * is up to date with the XdndActionList on the source window
2745
 
 * because we get no notification, because Xdnd wasn't meant
2746
 
 * to continually send actions. So we select on PropertyChangeMask
2747
 
 * and add this filter.
2748
 
 */
2749
 
static GdkFilterReturn 
2750
 
xdnd_source_window_filter (GdkXEvent *xev,
2751
 
                           GdkEvent  *event,
2752
 
                           gpointer   cb_data)
2753
 
{
2754
 
  XEvent *xevent = (XEvent *)xev;
2755
 
  GdkDragContext *context = cb_data;
2756
 
  GdkDisplay *display = GDK_WINDOW_DISPLAY(event->any.window);
2757
 
 
2758
 
  if ((xevent->xany.type == PropertyNotify) &&
2759
 
      (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "XdndActionList")))
2760
 
    {
2761
 
      xdnd_read_actions (context);
2762
 
 
2763
 
      return GDK_FILTER_REMOVE;
2764
 
    }
2765
 
 
2766
 
  return GDK_FILTER_CONTINUE;
2767
 
}
2768
 
 
2769
 
static void
2770
 
xdnd_manage_source_filter (GdkDragContext *context,
2771
 
                           GdkWindow      *window,
2772
 
                           gboolean        add_filter)
2773
 
{
2774
 
  if (!GDK_WINDOW_DESTROYED (window) &&
2775
 
      gdk_window_get_window_type (window) == GDK_WINDOW_FOREIGN)
2776
 
    {
2777
 
      gdk_error_trap_push ();
2778
 
 
2779
 
      if (add_filter)
2780
 
        {
2781
 
          gdk_window_set_events (window,
2782
 
                                 gdk_window_get_events (window) |
2783
 
                                 GDK_PROPERTY_CHANGE_MASK);
2784
 
          gdk_window_add_filter (window, xdnd_source_window_filter, context);
2785
 
        }
2786
 
      else
2787
 
        {
2788
 
          gdk_window_remove_filter (window,
2789
 
                                    xdnd_source_window_filter,
2790
 
                                    context);
2791
 
          /* Should we remove the GDK_PROPERTY_NOTIFY mask?
2792
 
           * but we might want it for other reasons. (Like
2793
 
           * INCR selection transactions).
2794
 
           */
2795
 
        }
2796
 
      
2797
 
      gdk_display_sync (gdk_drawable_get_display (window));
2798
 
      gdk_error_trap_pop ();  
2799
 
    }
2800
 
}
2801
 
 
2802
 
static void
2803
 
base_precache_atoms (GdkDisplay *display)
2804
 
{
2805
 
  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
2806
 
 
2807
 
  if (!display_x11->base_dnd_atoms_precached)
2808
 
    {
2809
 
      static const char *const precache_atoms[] = {
2810
 
        "ENLIGHTENMENT_DESKTOP",
2811
 
        "WM_STATE",
2812
 
        "XdndAware",
2813
 
        "XdndProxy",
2814
 
        "_MOTIF_DRAG_RECEIVER_INFO"
2815
 
      };
2816
 
 
2817
 
      _gdk_x11_precache_atoms (display,
2818
 
                               precache_atoms, G_N_ELEMENTS (precache_atoms));
2819
 
 
2820
 
      display_x11->base_dnd_atoms_precached = TRUE;
2821
 
    }
2822
 
}
2823
 
 
2824
 
static void
2825
 
xdnd_precache_atoms (GdkDisplay *display)
2826
 
{
2827
 
  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
2828
 
 
2829
 
  if (!display_x11->xdnd_atoms_precached)
2830
 
    {
2831
 
      static const char *const precache_atoms[] = {
2832
 
        "XdndActionAsk",
2833
 
        "XdndActionCopy",
2834
 
        "XdndActionLink",
2835
 
        "XdndActionList",
2836
 
        "XdndActionMove",
2837
 
        "XdndActionPrivate",
2838
 
        "XdndDrop",
2839
 
        "XdndEnter",
2840
 
        "XdndFinished",
2841
 
        "XdndLeave",
2842
 
        "XdndPosition",
2843
 
        "XdndSelection",
2844
 
        "XdndStatus",
2845
 
        "XdndTypeList"
2846
 
      };
2847
 
 
2848
 
      _gdk_x11_precache_atoms (display,
2849
 
                               precache_atoms, G_N_ELEMENTS (precache_atoms));
2850
 
 
2851
 
      display_x11->xdnd_atoms_precached = TRUE;
2852
 
    }
2853
 
}
2854
 
 
2855
 
static GdkFilterReturn 
2856
 
xdnd_enter_filter (GdkXEvent *xev,
2857
 
                   GdkEvent  *event,
2858
 
                   gpointer   cb_data)
2859
 
{
2860
 
  GdkDisplay *display;
2861
 
  GdkDisplayX11 *display_x11;
2862
 
  XEvent *xevent = (XEvent *)xev;
2863
 
  GdkDragContext *new_context;
2864
 
  gint i;
2865
 
  
2866
 
  Atom type;
2867
 
  int format;
2868
 
  gulong nitems, after;
2869
 
  guchar *data;
2870
 
  Atom *atoms;
2871
 
 
2872
 
  guint32 source_window;
2873
 
  gboolean get_types;
2874
 
  gint version;
2875
 
 
2876
 
  if (!event->any.window ||
2877
 
      gdk_window_get_window_type (event->any.window) == GDK_WINDOW_FOREIGN)
2878
 
    return GDK_FILTER_CONTINUE;                 /* Not for us */
2879
 
 
2880
 
  source_window = xevent->xclient.data.l[0];
2881
 
  get_types = ((xevent->xclient.data.l[1] & 1) != 0);
2882
 
  version = (xevent->xclient.data.l[1] & 0xff000000) >> 24;
2883
 
  
2884
 
  display = GDK_DRAWABLE_DISPLAY (event->any.window);
2885
 
  display_x11 = GDK_DISPLAY_X11 (display);
2886
 
 
2887
 
  xdnd_precache_atoms (display);
2888
 
 
2889
 
  GDK_NOTE (DND, 
2890
 
            g_message ("XdndEnter: source_window: %#x, version: %#x",
2891
 
                       source_window, version));
2892
 
 
2893
 
  if (version < 3)
2894
 
    {
2895
 
      /* Old source ignore */
2896
 
      GDK_NOTE (DND, g_message ("Ignored old XdndEnter message"));
2897
 
      return GDK_FILTER_REMOVE;
2898
 
    }
2899
 
  
2900
 
  if (display_x11->current_dest_drag != NULL)
2901
 
    {
2902
 
      g_object_unref (display_x11->current_dest_drag);
2903
 
      display_x11->current_dest_drag = NULL;
2904
 
    }
2905
 
 
2906
 
  new_context = gdk_drag_context_new ();
2907
 
  new_context->protocol = GDK_DRAG_PROTO_XDND;
2908
 
  PRIVATE_DATA(new_context)->version = version;
2909
 
 
2910
 
  new_context->source_window = gdk_window_lookup_for_display (display, source_window);
2911
 
  if (new_context->source_window)
2912
 
    g_object_ref (new_context->source_window);
2913
 
  else
2914
 
    {
2915
 
      new_context->source_window = gdk_window_foreign_new_for_display (display, source_window);
2916
 
      if (!new_context->source_window)
2917
 
        {
2918
 
          g_object_unref (new_context);
2919
 
          return GDK_FILTER_REMOVE;
2920
 
        }
2921
 
    }
2922
 
  new_context->dest_window = event->any.window;
2923
 
  g_object_ref (new_context->dest_window);
2924
 
 
2925
 
  new_context->targets = NULL;
2926
 
  if (get_types)
2927
 
    {
2928
 
      gdk_error_trap_push ();
2929
 
      XGetWindowProperty (GDK_DRAWABLE_XDISPLAY (event->any.window), 
2930
 
                          source_window, 
2931
 
                          gdk_x11_get_xatom_by_name_for_display (display, "XdndTypeList"),
2932
 
                          0, 65536,
2933
 
                          False, XA_ATOM, &type, &format, &nitems,
2934
 
                          &after, &data);
2935
 
 
2936
 
      if (gdk_error_trap_pop () || (format != 32) || (type != XA_ATOM))
2937
 
        {
2938
 
          g_object_unref (new_context);
2939
 
 
2940
 
          if (data)
2941
 
            XFree (data);
2942
 
 
2943
 
          return GDK_FILTER_REMOVE;
2944
 
        }
2945
 
 
2946
 
      atoms = (Atom *)data;
2947
 
 
2948
 
      for (i=0; i<nitems; i++)
2949
 
        new_context->targets = 
2950
 
          g_list_append (new_context->targets,
2951
 
                         GDK_ATOM_TO_POINTER (gdk_x11_xatom_to_atom_for_display (display,
2952
 
                                                                                 atoms[i])));
2953
 
 
2954
 
      XFree(atoms);
2955
 
    }
2956
 
  else
2957
 
    {
2958
 
      for (i=0; i<3; i++)
2959
 
        if (xevent->xclient.data.l[2+i])
2960
 
          new_context->targets =
2961
 
            g_list_append (new_context->targets,
2962
 
                           GDK_ATOM_TO_POINTER (gdk_x11_xatom_to_atom_for_display (display, 
2963
 
                                                                                   xevent->xclient.data.l[2+i])));
2964
 
    }
2965
 
 
2966
 
#ifdef G_ENABLE_DEBUG
2967
 
  if (_gdk_debug_flags & GDK_DEBUG_DND)
2968
 
    print_target_list (new_context->targets);
2969
 
#endif /* G_ENABLE_DEBUG */
2970
 
 
2971
 
  xdnd_manage_source_filter (new_context, new_context->source_window, TRUE);
2972
 
  xdnd_read_actions (new_context);
2973
 
 
2974
 
  event->dnd.type = GDK_DRAG_ENTER;
2975
 
  event->dnd.context = new_context;
2976
 
  g_object_ref (new_context);
2977
 
 
2978
 
  display_x11->current_dest_drag = new_context;
2979
 
 
2980
 
  return GDK_FILTER_TRANSLATE;
2981
 
}
2982
 
 
2983
 
static GdkFilterReturn 
2984
 
xdnd_leave_filter (GdkXEvent *xev,
2985
 
                   GdkEvent  *event,
2986
 
                   gpointer   data)
2987
 
{
2988
 
  XEvent *xevent = (XEvent *)xev;
2989
 
  guint32 source_window = xevent->xclient.data.l[0];
2990
 
  GdkDisplay *display;
2991
 
  GdkDisplayX11 *display_x11;
2992
 
 
2993
 
  if (!event->any.window ||
2994
 
      gdk_window_get_window_type (event->any.window) == GDK_WINDOW_FOREIGN)
2995
 
    return GDK_FILTER_CONTINUE;                 /* Not for us */
2996
 
 
2997
 
  GDK_NOTE (DND, 
2998
 
            g_message ("XdndLeave: source_window: %#x",
2999
 
                       source_window));
3000
 
 
3001
 
  display = GDK_DRAWABLE_DISPLAY (event->any.window);
3002
 
  display_x11 = GDK_DISPLAY_X11 (display);
3003
 
 
3004
 
  xdnd_precache_atoms (display);
3005
 
 
3006
 
  if ((display_x11->current_dest_drag != NULL) &&
3007
 
      (display_x11->current_dest_drag->protocol == GDK_DRAG_PROTO_XDND) &&
3008
 
      (GDK_DRAWABLE_XID (display_x11->current_dest_drag->source_window) == source_window))
3009
 
    {
3010
 
      event->dnd.type = GDK_DRAG_LEAVE;
3011
 
      /* Pass ownership of context to the event */
3012
 
      event->dnd.context = display_x11->current_dest_drag;
3013
 
 
3014
 
      display_x11->current_dest_drag = NULL;
3015
 
 
3016
 
      return GDK_FILTER_TRANSLATE;
3017
 
    }
3018
 
  else
3019
 
    return GDK_FILTER_REMOVE;
3020
 
}
3021
 
 
3022
 
static GdkFilterReturn 
3023
 
xdnd_position_filter (GdkXEvent *xev,
3024
 
                      GdkEvent  *event,
3025
 
                      gpointer   data)
3026
 
{
3027
 
  XEvent *xevent = (XEvent *)xev;
3028
 
  guint32 source_window = xevent->xclient.data.l[0];
3029
 
  gint16 x_root = xevent->xclient.data.l[2] >> 16;
3030
 
  gint16 y_root = xevent->xclient.data.l[2] & 0xffff;
3031
 
  guint32 time = xevent->xclient.data.l[3];
3032
 
  Atom action = xevent->xclient.data.l[4];
3033
 
 
3034
 
  GdkDisplay *display;
3035
 
  GdkDisplayX11 *display_x11;
3036
 
 
3037
 
   if (!event->any.window ||
3038
 
       gdk_window_get_window_type (event->any.window) == GDK_WINDOW_FOREIGN)
3039
 
     return GDK_FILTER_CONTINUE;                        /* Not for us */
3040
 
   
3041
 
  GDK_NOTE (DND, 
3042
 
            g_message ("XdndPosition: source_window: %#x position: (%d, %d)  time: %d  action: %ld",
3043
 
                       source_window, x_root, y_root, time, action));
3044
 
 
3045
 
  display = GDK_DRAWABLE_DISPLAY (event->any.window);
3046
 
  display_x11 = GDK_DISPLAY_X11 (display);
3047
 
  
3048
 
  xdnd_precache_atoms (display);
3049
 
 
3050
 
  if ((display_x11->current_dest_drag != NULL) &&
3051
 
      (display_x11->current_dest_drag->protocol == GDK_DRAG_PROTO_XDND) &&
3052
 
      (GDK_DRAWABLE_XID (display_x11->current_dest_drag->source_window) == source_window))
3053
 
    {
3054
 
      event->dnd.type = GDK_DRAG_MOTION;
3055
 
      event->dnd.context = display_x11->current_dest_drag;
3056
 
      g_object_ref (display_x11->current_dest_drag);
3057
 
 
3058
 
      event->dnd.time = time;
3059
 
 
3060
 
      display_x11->current_dest_drag->suggested_action = xdnd_action_from_atom (display, action);
3061
 
      
3062
 
      if (!(PRIVATE_DATA (display_x11->current_dest_drag))->xdnd_have_actions)
3063
 
        display_x11->current_dest_drag->actions = display_x11->current_dest_drag->suggested_action;
3064
 
 
3065
 
      event->dnd.x_root = x_root;
3066
 
      event->dnd.y_root = y_root;
3067
 
 
3068
 
      (PRIVATE_DATA (display_x11->current_dest_drag))->last_x = x_root;
3069
 
      (PRIVATE_DATA (display_x11->current_dest_drag))->last_y = y_root;
3070
 
      
3071
 
      return GDK_FILTER_TRANSLATE;
3072
 
    }
3073
 
 
3074
 
  return GDK_FILTER_REMOVE;
3075
 
}
3076
 
 
3077
 
static GdkFilterReturn 
3078
 
xdnd_drop_filter (GdkXEvent *xev,
3079
 
                  GdkEvent  *event,
3080
 
                  gpointer   data)
3081
 
{
3082
 
  XEvent *xevent = (XEvent *)xev;
3083
 
  guint32 source_window = xevent->xclient.data.l[0];
3084
 
  guint32 time = xevent->xclient.data.l[2];
3085
 
  GdkDisplay *display;
3086
 
  GdkDisplayX11 *display_x11;
3087
 
  
3088
 
  if (!event->any.window ||
3089
 
      gdk_window_get_window_type (event->any.window) == GDK_WINDOW_FOREIGN)
3090
 
    return GDK_FILTER_CONTINUE;                 /* Not for us */
3091
 
  
3092
 
  GDK_NOTE (DND, 
3093
 
            g_message ("XdndDrop: source_window: %#x  time: %d",
3094
 
                       source_window, time));
3095
 
 
3096
 
  display = GDK_DRAWABLE_DISPLAY (event->any.window);
3097
 
  display_x11 = GDK_DISPLAY_X11 (display);
3098
 
 
3099
 
  xdnd_precache_atoms (display);
3100
 
 
3101
 
  if ((display_x11->current_dest_drag != NULL) &&
3102
 
      (display_x11->current_dest_drag->protocol == GDK_DRAG_PROTO_XDND) &&
3103
 
      (GDK_DRAWABLE_XID (display_x11->current_dest_drag->source_window) == source_window))
3104
 
    {
3105
 
      GdkDragContextPrivateX11 *private;
3106
 
      private = PRIVATE_DATA (display_x11->current_dest_drag);
3107
 
 
3108
 
      event->dnd.type = GDK_DROP_START;
3109
 
 
3110
 
      event->dnd.context = display_x11->current_dest_drag;
3111
 
      g_object_ref (display_x11->current_dest_drag);
3112
 
 
3113
 
      event->dnd.time = time;
3114
 
      event->dnd.x_root = private->last_x;
3115
 
      event->dnd.y_root = private->last_y;
3116
 
 
3117
 
      gdk_x11_window_set_user_time (event->any.window, time);
3118
 
      
3119
 
      return GDK_FILTER_TRANSLATE;
3120
 
    }
3121
 
 
3122
 
  return GDK_FILTER_REMOVE;
3123
 
}
3124
 
 
3125
 
/*************************************************************
3126
 
 ************************** Public API ***********************
3127
 
 *************************************************************/
3128
 
void
3129
 
_gdk_dnd_init (GdkDisplay *display)
3130
 
{
3131
 
  int i;
3132
 
  init_byte_order ();
3133
 
 
3134
 
  gdk_display_add_client_message_filter (
3135
 
        display,
3136
 
        gdk_atom_intern_static_string ("_MOTIF_DRAG_AND_DROP_MESSAGE"),
3137
 
        motif_dnd_filter, NULL);
3138
 
  
3139
 
  for (i = 0; i < G_N_ELEMENTS (xdnd_filters); i++)
3140
 
    {
3141
 
      gdk_display_add_client_message_filter (
3142
 
        display,
3143
 
        gdk_atom_intern_static_string (xdnd_filters[i].atom_name),
3144
 
        xdnd_filters[i].func, NULL);
3145
 
    }
3146
 
}                     
3147
 
 
3148
 
/* Source side */
3149
 
 
3150
 
static void
3151
 
gdk_drag_do_leave (GdkDragContext *context, guint32 time)
3152
 
{
3153
 
  if (context->dest_window)
3154
 
    {
3155
 
      switch (context->protocol)
3156
 
        {
3157
 
        case GDK_DRAG_PROTO_MOTIF:
3158
 
          motif_send_leave (context, time);
3159
 
          break;
3160
 
        case GDK_DRAG_PROTO_XDND:
3161
 
          xdnd_send_leave (context);
3162
 
          break;
3163
 
        case GDK_DRAG_PROTO_ROOTWIN:
3164
 
        case GDK_DRAG_PROTO_NONE:
3165
 
        default:
3166
 
          break;
3167
 
        }
3168
 
 
3169
 
      g_object_unref (context->dest_window);
3170
 
      context->dest_window = NULL;
3171
 
    }
3172
 
}
3173
 
 
3174
 
/**
3175
 
 * gdk_drag_begin:
3176
 
 * @window: the source window for this drag.
3177
 
 * @targets: (transfer none) (element-type GdkAtom): the offered targets,
3178
 
 *     as list of #GdkAtom<!-- -->s
3179
 
 * 
3180
 
 * Starts a drag and creates a new drag context for it.
3181
 
 *
3182
 
 * This function is called by the drag source.
3183
 
 * 
3184
 
 * Return value: a newly created #GdkDragContext.
3185
 
 **/
3186
 
GdkDragContext * 
3187
 
gdk_drag_begin (GdkWindow     *window,
3188
 
                GList         *targets)
3189
 
{
3190
 
  GdkDragContext *new_context;
3191
 
  
3192
 
  g_return_val_if_fail (window != NULL, NULL);
3193
 
  g_return_val_if_fail (GDK_WINDOW_IS_X11 (window), NULL);
3194
 
 
3195
 
  new_context = gdk_drag_context_new ();
3196
 
  new_context->is_source = TRUE;
3197
 
  new_context->source_window = window;
3198
 
  g_object_ref (window);
3199
 
 
3200
 
  new_context->targets = g_list_copy (targets);
3201
 
  precache_target_list (new_context);
3202
 
  
3203
 
  new_context->actions = 0;
3204
 
 
3205
 
  return new_context;
3206
 
}
3207
 
 
3208
 
static GdkNativeWindow
3209
 
_gdk_drag_get_protocol_for_display (GdkDisplay      *display,
3210
 
                                    GdkNativeWindow  xid,
3211
 
                                    GdkDragProtocol *protocol,
3212
 
                                    guint           *version)
3213
 
 
3214
 
{
3215
 
  GdkWindow *window;
3216
 
  GdkNativeWindow retval;
3217
 
  g_return_val_if_fail (GDK_IS_DISPLAY (display), None);
3218
 
 
3219
 
  base_precache_atoms (display);
3220
 
 
3221
 
  /* Check for a local drag
3222
 
   */
3223
 
  window = gdk_window_lookup_for_display (display, xid);
3224
 
  if (window &&
3225
 
      gdk_window_get_window_type (window) != GDK_WINDOW_FOREIGN)
3226
 
    {
3227
 
      if (g_object_get_data (G_OBJECT (window), "gdk-dnd-registered") != NULL)
3228
 
        {
3229
 
          *protocol = GDK_DRAG_PROTO_XDND;
3230
 
          *version = 5;
3231
 
          xdnd_precache_atoms (display);
3232
 
          GDK_NOTE (DND, g_message ("Entering local Xdnd window %#x\n", xid));
3233
 
          return xid;
3234
 
        }
3235
 
      else if (_gdk_x11_display_is_root_window (display, (Window) xid))
3236
 
        {
3237
 
          *protocol = GDK_DRAG_PROTO_ROOTWIN;
3238
 
          GDK_NOTE (DND, g_message ("Entering root window\n"));
3239
 
          return xid;
3240
 
        }
3241
 
    }
3242
 
  else if ((retval = xdnd_check_dest (display, xid, version)))
3243
 
    {
3244
 
      *protocol = GDK_DRAG_PROTO_XDND;
3245
 
      xdnd_precache_atoms (display);
3246
 
      GDK_NOTE (DND, g_message ("Entering Xdnd window %#x\n", xid));
3247
 
      return retval;
3248
 
    }
3249
 
  else if ((retval = motif_check_dest (display, xid)))
3250
 
    {
3251
 
      *protocol = GDK_DRAG_PROTO_MOTIF;
3252
 
      GDK_NOTE (DND, g_message ("Entering motif window %#x\n", xid));
3253
 
      return retval;
3254
 
    }
3255
 
  else
3256
 
    {
3257
 
      /* Check if this is a root window */
3258
 
 
3259
 
      gboolean rootwin = FALSE;
3260
 
      Atom type = None;
3261
 
      int format;
3262
 
      unsigned long nitems, after;
3263
 
      unsigned char *data;
3264
 
 
3265
 
      if (_gdk_x11_display_is_root_window (display, (Window) xid))
3266
 
        rootwin = TRUE;
3267
 
 
3268
 
      gdk_error_trap_push ();
3269
 
      
3270
 
      if (!rootwin)
3271
 
        {
3272
 
          if (XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), xid,
3273
 
                                  gdk_x11_get_xatom_by_name_for_display (display, "ENLIGHTENMENT_DESKTOP"),
3274
 
                                  0, 0, False, AnyPropertyType,
3275
 
                                  &type, &format, &nitems, &after, &data) == Success &&
3276
 
              type != None)
3277
 
            {
3278
 
              XFree (data);
3279
 
              rootwin = TRUE;
3280
 
            }
3281
 
        }
3282
 
 
3283
 
      /* Until I find out what window manager the next one is for,
3284
 
       * I'm leaving it commented out. It's supported in the
3285
 
       * xscreensaver sources, though.
3286
 
       */
3287
 
#if 0
3288
 
      if (!rootwin)
3289
 
        {
3290
 
          if (XGetWindowProperty (gdk_display, win,
3291
 
                                  gdk_x11_get_xatom_by_name ("__SWM_VROOT"),
3292
 
                                  0, 0, False, AnyPropertyType,
3293
 
                                  &type, &format, &nitems, &data) &&
3294
 
              type != None)
3295
 
            {
3296
 
              XFree (data);
3297
 
              rootwin = TRUE;
3298
 
            }
3299
 
        }
3300
 
#endif      
3301
 
 
3302
 
      gdk_error_trap_pop ();
3303
 
 
3304
 
      if (rootwin)
3305
 
        {
3306
 
          GDK_NOTE (DND, g_message ("Entering root window\n"));
3307
 
          *protocol = GDK_DRAG_PROTO_ROOTWIN;
3308
 
          return xid;
3309
 
        }
3310
 
    }
3311
 
 
3312
 
  *protocol = GDK_DRAG_PROTO_NONE;
3313
 
 
3314
 
  return 0; /* a.k.a. None */
3315
 
}
3316
 
 
3317
 
/**
3318
 
 * gdk_drag_get_protocol_for_display:
3319
 
 * @display: the #GdkDisplay where the destination window resides
3320
 
 * @xid: the windowing system id of the destination window.
3321
 
 * @protocol: location where the supported DND protocol is returned.
3322
 
 * @returns: the windowing system id of the window where the drop should happen. This 
3323
 
 *     may be @xid or the id of a proxy window, or zero if @xid doesn't
3324
 
 *     support Drag and Drop.
3325
 
 *
3326
 
 * Finds out the DND protocol supported by a window.
3327
 
 *
3328
 
 * Since: 2.2
3329
 
 */ 
3330
 
GdkNativeWindow
3331
 
gdk_drag_get_protocol_for_display (GdkDisplay      *display,
3332
 
                                   GdkNativeWindow  xid,
3333
 
                                   GdkDragProtocol *protocol)
3334
 
{
3335
 
  return _gdk_drag_get_protocol_for_display (display, xid, protocol, NULL);
3336
 
}
3337
 
 
3338
 
static GdkWindowCache *
3339
 
drag_context_find_window_cache (GdkDragContext  *context,
3340
 
                                GdkScreen       *screen)
3341
 
{
3342
 
  GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
3343
 
  GSList *tmp_list;
3344
 
  GdkWindowCache *cache;
3345
 
 
3346
 
  for (tmp_list = private->window_caches; tmp_list; tmp_list = tmp_list->next)
3347
 
    {
3348
 
      cache = tmp_list->data;
3349
 
      if (cache->screen == screen)
3350
 
        return cache;
3351
 
    }
3352
 
 
3353
 
  cache = gdk_window_cache_get (screen);
3354
 
  private->window_caches = g_slist_prepend (private->window_caches, cache);
3355
 
  
3356
 
  return cache;
3357
 
}
3358
 
 
3359
 
/**
3360
 
 * gdk_drag_find_window_for_screen:
3361
 
 * @context: a #GdkDragContext
3362
 
 * @drag_window: a window which may be at the pointer position, but
3363
 
 * should be ignored, since it is put up by the drag source as an icon.
3364
 
 * @screen: the screen where the destination window is sought. 
3365
 
 * @x_root: the x position of the pointer in root coordinates.
3366
 
 * @y_root: the y position of the pointer in root coordinates.
3367
 
 * @dest_window: (out): location to store the destination window in.
3368
 
 * @protocol: (out): location to store the DND protocol in.
3369
 
 *
3370
 
 * Finds the destination window and DND protocol to use at the
3371
 
 * given pointer position.
3372
 
 *
3373
 
 * This function is called by the drag source to obtain the 
3374
 
 * @dest_window and @protocol parameters for gdk_drag_motion().
3375
 
 *
3376
 
 * Since: 2.2
3377
 
 **/
3378
 
void
3379
 
gdk_drag_find_window_for_screen (GdkDragContext  *context,
3380
 
                                 GdkWindow       *drag_window,
3381
 
                                 GdkScreen       *screen,
3382
 
                                 gint             x_root,
3383
 
                                 gint             y_root,
3384
 
                                 GdkWindow      **dest_window,
3385
 
                                 GdkDragProtocol *protocol)
3386
 
{
3387
 
  GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
3388
 
  GdkWindowCache *window_cache;
3389
 
  GdkDisplay *display;
3390
 
  Window dest;
3391
 
 
3392
 
  g_return_if_fail (context != NULL);
3393
 
 
3394
 
  display = GDK_WINDOW_DISPLAY (context->source_window);
3395
 
 
3396
 
  window_cache = drag_context_find_window_cache (context, screen);
3397
 
 
3398
 
  dest = get_client_window_at_coords (window_cache,
3399
 
                                      drag_window && GDK_WINDOW_IS_X11 (drag_window) ? 
3400
 
                                      GDK_DRAWABLE_XID (drag_window) : None,
3401
 
                                      x_root, y_root);
3402
 
 
3403
 
  if (private->dest_xid != dest)
3404
 
    {
3405
 
      Window recipient;
3406
 
      private->dest_xid = dest;
3407
 
 
3408
 
      /* Check if new destination accepts drags, and which protocol */
3409
 
 
3410
 
      /* There is some ugliness here. We actually need to pass
3411
 
       * _three_ pieces of information to drag_motion - dest_window,
3412
 
       * protocol, and the XID of the unproxied window. The first
3413
 
       * two are passed explicitely, the third implicitly through
3414
 
       * protocol->dest_xid.
3415
 
       */
3416
 
      if ((recipient = _gdk_drag_get_protocol_for_display (display, dest, 
3417
 
                                                           protocol, &private->version)))
3418
 
        {
3419
 
          *dest_window = gdk_window_lookup_for_display (display, recipient);
3420
 
          if (*dest_window)
3421
 
            g_object_ref (*dest_window);
3422
 
          else
3423
 
            *dest_window = gdk_window_foreign_new_for_display (display, recipient);
3424
 
        }
3425
 
      else
3426
 
        *dest_window = NULL;
3427
 
    }
3428
 
  else
3429
 
    {
3430
 
      *dest_window = context->dest_window;
3431
 
      if (*dest_window)
3432
 
        g_object_ref (*dest_window);
3433
 
      *protocol = context->protocol;
3434
 
    }
3435
 
}
3436
 
 
3437
 
/**
3438
 
 * gdk_drag_motion:
3439
 
 * @context: a #GdkDragContext.
3440
 
 * @dest_window: the new destination window, obtained by 
3441
 
 *     gdk_drag_find_window().
3442
 
 * @protocol: the DND protocol in use, obtained by gdk_drag_find_window().
3443
 
 * @x_root: the x position of the pointer in root coordinates.
3444
 
 * @y_root: the y position of the pointer in root coordinates.
3445
 
 * @suggested_action: the suggested action.
3446
 
 * @possible_actions: the possible actions.
3447
 
 * @time_: the timestamp for this operation.
3448
 
 * 
3449
 
 * Updates the drag context when the pointer moves or the 
3450
 
 * set of actions changes.
3451
 
 *
3452
 
 * This function is called by the drag source.
3453
 
 * 
3454
 
 * Return value: FIXME
3455
 
 **/
3456
 
gboolean        
3457
 
gdk_drag_motion (GdkDragContext *context,
3458
 
                 GdkWindow      *dest_window,
3459
 
                 GdkDragProtocol protocol,
3460
 
                 gint            x_root, 
3461
 
                 gint            y_root,
3462
 
                 GdkDragAction   suggested_action,
3463
 
                 GdkDragAction   possible_actions,
3464
 
                 guint32         time)
3465
 
{
3466
 
  GdkDragContextPrivateX11 *private = PRIVATE_DATA (context);
3467
 
 
3468
 
  g_return_val_if_fail (context != NULL, FALSE);
3469
 
  g_return_val_if_fail (dest_window == NULL || GDK_WINDOW_IS_X11 (dest_window), FALSE);
3470
 
 
3471
 
  private->old_actions = context->actions;
3472
 
  context->actions = possible_actions;
3473
 
  
3474
 
  if (private->old_actions != possible_actions)
3475
 
    private->xdnd_actions_set = FALSE;
3476
 
  
3477
 
  if (protocol == GDK_DRAG_PROTO_XDND && private->version == 0)
3478
 
    {
3479
 
      /* This ugly hack is necessary since GTK+ doesn't know about
3480
 
       * the XDND protocol version, and in particular doesn't know 
3481
 
       * that gdk_drag_find_window_for_screen() has the side-effect 
3482
 
       * of setting private->version, and therefore sometimes call
3483
 
       * gdk_drag_motion() without a prior call to 
3484
 
       * gdk_drag_find_window_for_screen(). This happens, e.g.
3485
 
       * when GTK+ is proxying DND events to embedded windows.
3486
 
       */ 
3487
 
      if (dest_window)
3488
 
        {
3489
 
          GdkDisplay *display = GDK_WINDOW_DISPLAY (dest_window);
3490
 
          
3491
 
          xdnd_check_dest (display, 
3492
 
                           GDK_DRAWABLE_XID (dest_window), 
3493
 
                           &private->version);
3494
 
        }
3495
 
    }
3496
 
 
3497
 
  /* When we have a Xdnd target, make sure our XdndActionList
3498
 
   * matches the current actions;
3499
 
   */
3500
 
  if (protocol == GDK_DRAG_PROTO_XDND && !private->xdnd_actions_set)
3501
 
    {
3502
 
      if (dest_window)
3503
 
        {
3504
 
          if (gdk_window_get_window_type (dest_window) == GDK_WINDOW_FOREIGN)
3505
 
            xdnd_set_actions (context);
3506
 
          else if (context->dest_window == dest_window)
3507
 
            {
3508
 
              GdkDisplay *display = GDK_WINDOW_DISPLAY (dest_window);
3509
 
              GdkDragContext *dest_context;
3510
 
                    
3511
 
              dest_context = gdk_drag_context_find (display, FALSE,
3512
 
                                                    GDK_DRAWABLE_XID (context->source_window),
3513
 
                                                    GDK_DRAWABLE_XID (dest_window));
3514
 
 
3515
 
              if (dest_context)
3516
 
                {
3517
 
                  dest_context->actions = context->actions;
3518
 
                  PRIVATE_DATA (dest_context)->xdnd_have_actions = TRUE;
3519
 
                }
3520
 
            }
3521
 
        }
3522
 
    }
3523
 
 
3524
 
  if (context->dest_window != dest_window)
3525
 
    {
3526
 
      GdkEvent temp_event;
3527
 
 
3528
 
      /* Send a leave to the last destination */
3529
 
      gdk_drag_do_leave (context, time);
3530
 
      private->drag_status = GDK_DRAG_STATUS_DRAG;
3531
 
 
3532
 
      /* Check if new destination accepts drags, and which protocol */
3533
 
 
3534
 
      if (dest_window)
3535
 
        {
3536
 
          context->dest_window = dest_window;
3537
 
          private->drop_xid = private->dest_xid;
3538
 
          g_object_ref (context->dest_window);
3539
 
          context->protocol = protocol;
3540
 
 
3541
 
          switch (protocol)
3542
 
            {
3543
 
            case GDK_DRAG_PROTO_MOTIF:
3544
 
              motif_send_enter (context, time);
3545
 
              break;
3546
 
 
3547
 
            case GDK_DRAG_PROTO_XDND:
3548
 
              xdnd_send_enter (context);
3549
 
              break;
3550
 
 
3551
 
            case GDK_DRAG_PROTO_ROOTWIN:
3552
 
            case GDK_DRAG_PROTO_NONE:
3553
 
            default:
3554
 
              break;
3555
 
            }
3556
 
          private->old_action = suggested_action;
3557
 
          context->suggested_action = suggested_action;
3558
 
          private->old_actions = possible_actions;
3559
 
        }
3560
 
      else
3561
 
        {
3562
 
          context->dest_window = NULL;
3563
 
          private->drop_xid = None;
3564
 
          context->action = 0;
3565
 
        }
3566
 
 
3567
 
      /* Push a status event, to let the client know that
3568
 
       * the drag changed 
3569
 
       */
3570
 
 
3571
 
      temp_event.dnd.type = GDK_DRAG_STATUS;
3572
 
      temp_event.dnd.window = context->source_window;
3573
 
      /* We use this to signal a synthetic status. Perhaps
3574
 
       * we should use an extra field...
3575
 
       */
3576
 
      temp_event.dnd.send_event = TRUE;
3577
 
 
3578
 
      temp_event.dnd.context = context;
3579
 
      temp_event.dnd.time = time;
3580
 
 
3581
 
      gdk_event_put (&temp_event);
3582
 
    }
3583
 
  else
3584
 
    {
3585
 
      private->old_action = context->suggested_action;
3586
 
      context->suggested_action = suggested_action;
3587
 
    }
3588
 
 
3589
 
  /* Send a drag-motion event */
3590
 
 
3591
 
  private->last_x = x_root;
3592
 
  private->last_y = y_root;
3593
 
      
3594
 
  if (context->dest_window)
3595
 
    {
3596
 
      if (private->drag_status == GDK_DRAG_STATUS_DRAG)
3597
 
        {
3598
 
          switch (context->protocol)
3599
 
            {
3600
 
            case GDK_DRAG_PROTO_MOTIF:
3601
 
              motif_send_motion (context, x_root, y_root, suggested_action, time);
3602
 
              break;
3603
 
              
3604
 
            case GDK_DRAG_PROTO_XDND:
3605
 
              xdnd_send_motion (context, x_root, y_root, suggested_action, time);
3606
 
              break;
3607
 
 
3608
 
            case GDK_DRAG_PROTO_ROOTWIN:
3609
 
              {
3610
 
                GdkEvent temp_event;
3611
 
                /* GTK+ traditionally has used application/x-rootwin-drop,
3612
 
                 * but the XDND spec specifies x-rootwindow-drop.
3613
 
                 */
3614
 
                GdkAtom target1 = gdk_atom_intern_static_string ("application/x-rootwindow-drop");
3615
 
                GdkAtom target2 = gdk_atom_intern_static_string ("application/x-rootwin-drop");
3616
 
 
3617
 
                if (g_list_find (context->targets,
3618
 
                                 GDK_ATOM_TO_POINTER (target1)) ||
3619
 
                    g_list_find (context->targets,
3620
 
                                 GDK_ATOM_TO_POINTER (target2)))
3621
 
                  context->action = context->suggested_action;
3622
 
                else
3623
 
                  context->action = 0;
3624
 
 
3625
 
                temp_event.dnd.type = GDK_DRAG_STATUS;
3626
 
                temp_event.dnd.window = context->source_window;
3627
 
                temp_event.dnd.send_event = FALSE;
3628
 
                temp_event.dnd.context = context;
3629
 
                temp_event.dnd.time = time;
3630
 
 
3631
 
                gdk_event_put (&temp_event);
3632
 
              }
3633
 
              break;
3634
 
            case GDK_DRAG_PROTO_NONE:
3635
 
              g_warning ("GDK_DRAG_PROTO_NONE is not valid in gdk_drag_motion()");
3636
 
              break;
3637
 
            default:
3638
 
              break;
3639
 
            }
3640
 
        }
3641
 
      else
3642
 
        return TRUE;
3643
 
    }
3644
 
 
3645
 
  return FALSE;
3646
 
}
3647
 
 
3648
 
/**
3649
 
 * gdk_drag_drop:
3650
 
 * @context: a #GdkDragContext.
3651
 
 * @time_: the timestamp for this operation.
3652
 
 * 
3653
 
 * Drops on the current destination.
3654
 
 * 
3655
 
 * This function is called by the drag source.
3656
 
 **/
3657
 
void
3658
 
gdk_drag_drop (GdkDragContext *context,
3659
 
               guint32         time)
3660
 
{
3661
 
  g_return_if_fail (context != NULL);
3662
 
 
3663
 
  if (context->dest_window)
3664
 
    {
3665
 
      switch (context->protocol)
3666
 
        {
3667
 
        case GDK_DRAG_PROTO_MOTIF:
3668
 
          motif_send_leave (context, time);
3669
 
          motif_send_drop (context, time);
3670
 
          break;
3671
 
          
3672
 
        case GDK_DRAG_PROTO_XDND:
3673
 
          xdnd_send_drop (context, time);
3674
 
          break;
3675
 
 
3676
 
        case GDK_DRAG_PROTO_ROOTWIN:
3677
 
          g_warning ("Drops for GDK_DRAG_PROTO_ROOTWIN must be handled internally");
3678
 
          break;
3679
 
        case GDK_DRAG_PROTO_NONE:
3680
 
          g_warning ("GDK_DRAG_PROTO_NONE is not valid in gdk_drag_drop()");
3681
 
          break;
3682
 
        default:
3683
 
          break;
3684
 
        }
3685
 
    }
3686
 
}
3687
 
 
3688
 
/**
3689
 
 * gdk_drag_abort:
3690
 
 * @context: a #GdkDragContext.
3691
 
 * @time_: the timestamp for this operation.
3692
 
 * 
3693
 
 * Aborts a drag without dropping. 
3694
 
 *
3695
 
 * This function is called by the drag source.
3696
 
 **/
3697
 
void
3698
 
gdk_drag_abort (GdkDragContext *context,
3699
 
                guint32         time)
3700
 
{
3701
 
  g_return_if_fail (context != NULL);
3702
 
 
3703
 
  gdk_drag_do_leave (context, time);
3704
 
}
3705
 
 
3706
 
/* Destination side */
3707
 
 
3708
 
/**
3709
 
 * gdk_drag_status:
3710
 
 * @context: a #GdkDragContext.
3711
 
 * @action: the selected action which will be taken when a drop happens, 
3712
 
 *    or 0 to indicate that a drop will not be accepted.
3713
 
 * @time_: the timestamp for this operation.
3714
 
 * 
3715
 
 * Selects one of the actions offered by the drag source.
3716
 
 *
3717
 
 * This function is called by the drag destination in response to
3718
 
 * gdk_drag_motion() called by the drag source.
3719
 
 **/
3720
 
void             
3721
 
gdk_drag_status (GdkDragContext   *context,
3722
 
                 GdkDragAction     action,
3723
 
                 guint32           time)
3724
 
{
3725
 
  GdkDragContextPrivateX11 *private;
3726
 
  XEvent xev;
3727
 
  GdkDisplay *display;
3728
 
 
3729
 
  g_return_if_fail (context != NULL);
3730
 
 
3731
 
  private = PRIVATE_DATA (context);
3732
 
  display = GDK_DRAWABLE_DISPLAY (context->source_window);
3733
 
  
3734
 
  context->action = action;
3735
 
 
3736
 
  if (context->protocol == GDK_DRAG_PROTO_MOTIF)
3737
 
    {
3738
 
      gboolean need_coords = FALSE;
3739
 
      
3740
 
      xev.xclient.type = ClientMessage;
3741
 
      xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display,
3742
 
                                                                        "_MOTIF_DRAG_AND_DROP_MESSAGE");
3743
 
      xev.xclient.format = 8;
3744
 
      xev.xclient.window = GDK_DRAWABLE_XID (context->source_window);
3745
 
 
3746
 
      if (private->drag_status == GDK_DRAG_STATUS_ACTION_WAIT)
3747
 
        {
3748
 
          MOTIF_XCLIENT_BYTE (&xev, 0) = XmOPERATION_CHANGED | 0x80;
3749
 
        }
3750
 
      else
3751
 
        {
3752
 
          if ((action != 0) != (private->old_action != 0))
3753
 
            {
3754
 
              if (action != 0)
3755
 
                {
3756
 
                  MOTIF_XCLIENT_BYTE (&xev, 0) = XmDROP_SITE_ENTER | 0x80;
3757
 
                  need_coords = TRUE;
3758
 
                }
3759
 
              else
3760
 
                MOTIF_XCLIENT_BYTE (&xev, 0) = XmDROP_SITE_LEAVE | 0x80;
3761
 
            }
3762
 
          else
3763
 
            {
3764
 
              MOTIF_XCLIENT_BYTE (&xev, 0) = XmDRAG_MOTION | 0x80;
3765
 
              need_coords = TRUE;
3766
 
            }
3767
 
        }
3768
 
 
3769
 
      MOTIF_XCLIENT_BYTE (&xev, 1) = local_byte_order;
3770
 
 
3771
 
      switch (action)
3772
 
        {
3773
 
        case GDK_ACTION_MOVE:
3774
 
          MOTIF_XCLIENT_SHORT (&xev, 1) = XmDROP_MOVE;
3775
 
          break;
3776
 
        case GDK_ACTION_COPY:
3777
 
          MOTIF_XCLIENT_SHORT (&xev, 1) = XmDROP_COPY;
3778
 
          break;
3779
 
        case GDK_ACTION_LINK:
3780
 
          MOTIF_XCLIENT_SHORT (&xev, 1) = XmDROP_LINK;
3781
 
          break;
3782
 
        default:
3783
 
          MOTIF_XCLIENT_SHORT (&xev, 1) = XmDROP_NOOP;
3784
 
          break;
3785
 
        }
3786
 
 
3787
 
      if (action)
3788
 
        MOTIF_XCLIENT_SHORT (&xev, 1) |= (XmDROP_SITE_VALID << 4);
3789
 
      else
3790
 
        MOTIF_XCLIENT_SHORT (&xev, 1) |= (XmNO_DROP_SITE << 4);
3791
 
 
3792
 
      MOTIF_XCLIENT_LONG (&xev, 1) = time;
3793
 
      
3794
 
      if (need_coords)
3795
 
        {
3796
 
          MOTIF_XCLIENT_SHORT (&xev, 4) = private->last_x;
3797
 
          MOTIF_XCLIENT_SHORT (&xev, 5) = private->last_y;
3798
 
        }
3799
 
      else
3800
 
        MOTIF_XCLIENT_LONG (&xev, 2) = 0;
3801
 
      
3802
 
      MOTIF_XCLIENT_LONG (&xev, 3) = 0;
3803
 
      MOTIF_XCLIENT_LONG (&xev, 4) = 0;
3804
 
 
3805
 
      if (!_gdk_send_xevent (display,
3806
 
                             GDK_DRAWABLE_XID (context->source_window),
3807
 
                             FALSE, 0, &xev))
3808
 
        GDK_NOTE (DND, 
3809
 
                  g_message ("Send event to %lx failed",
3810
 
                             GDK_DRAWABLE_XID (context->source_window)));
3811
 
    }
3812
 
  else if (context->protocol == GDK_DRAG_PROTO_XDND)
3813
 
    {
3814
 
      xev.xclient.type = ClientMessage;
3815
 
      xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "XdndStatus");
3816
 
      xev.xclient.format = 32;
3817
 
      xev.xclient.window = GDK_DRAWABLE_XID (context->source_window);
3818
 
 
3819
 
      xev.xclient.data.l[0] = GDK_DRAWABLE_XID (context->dest_window);
3820
 
      xev.xclient.data.l[1] = (action != 0) ? (2 | 1) : 0;
3821
 
      xev.xclient.data.l[2] = 0;
3822
 
      xev.xclient.data.l[3] = 0;
3823
 
      xev.xclient.data.l[4] = xdnd_action_to_atom (display, action);
3824
 
      
3825
 
      if (!xdnd_send_xevent (context, context->source_window,
3826
 
                             FALSE, &xev))
3827
 
        GDK_NOTE (DND, 
3828
 
                  g_message ("Send event to %lx failed",
3829
 
                             GDK_DRAWABLE_XID (context->source_window)));
3830
 
    }
3831
 
 
3832
 
  private->old_action = action;
3833
 
}
3834
 
 
3835
 
/**
3836
 
 * gdk_drop_reply:
3837
 
 * @context: a #GdkDragContext.
3838
 
 * @ok: %TRUE if the drop is accepted.
3839
 
 * @time_: the timestamp for this operation.
3840
 
 * 
3841
 
 * Accepts or rejects a drop. 
3842
 
 *
3843
 
 * This function is called by the drag destination in response
3844
 
 * to a drop initiated by the drag source.
3845
 
 **/
3846
 
void 
3847
 
gdk_drop_reply (GdkDragContext   *context,
3848
 
                gboolean          ok,
3849
 
                guint32           time)
3850
 
{
3851
 
  GdkDragContextPrivateX11 *private;
3852
 
 
3853
 
  g_return_if_fail (context != NULL);
3854
 
 
3855
 
  private = PRIVATE_DATA (context);
3856
 
  
3857
 
  if (context->protocol == GDK_DRAG_PROTO_MOTIF)
3858
 
    {
3859
 
      GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window);
3860
 
      XEvent xev;
3861
 
 
3862
 
      xev.xclient.type = ClientMessage;
3863
 
      xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display,
3864
 
                                                                        "_MOTIF_DRAG_AND_DROP_MESSAGE");
3865
 
      xev.xclient.format = 8;
3866
 
 
3867
 
      MOTIF_XCLIENT_BYTE (&xev, 0) = XmDROP_START | 0x80;
3868
 
      MOTIF_XCLIENT_BYTE (&xev, 1) = local_byte_order;
3869
 
      if (ok)
3870
 
        MOTIF_XCLIENT_SHORT (&xev, 1) = XmDROP_COPY | 
3871
 
                                       (XmDROP_SITE_VALID << 4) |
3872
 
                                       (XmDROP_NOOP << 8) |
3873
 
                                       (XmDROP << 12);
3874
 
      else
3875
 
        MOTIF_XCLIENT_SHORT (&xev, 1) = XmDROP_NOOP | 
3876
 
                                       (XmNO_DROP_SITE << 4) |
3877
 
                                       (XmDROP_NOOP << 8) |
3878
 
                                       (XmDROP_CANCEL << 12);
3879
 
      MOTIF_XCLIENT_SHORT (&xev, 2) = private->last_x;
3880
 
      MOTIF_XCLIENT_SHORT (&xev, 3) = private->last_y;
3881
 
      MOTIF_XCLIENT_LONG (&xev, 2) = 0;
3882
 
      MOTIF_XCLIENT_LONG (&xev, 3) = 0;
3883
 
      MOTIF_XCLIENT_LONG (&xev, 4) = 0;
3884
 
      
3885
 
      _gdk_send_xevent (display,
3886
 
                        GDK_DRAWABLE_XID (context->source_window),
3887
 
                        FALSE, 0, &xev);
3888
 
    }
3889
 
}
3890
 
 
3891
 
/**
3892
 
 * gdk_drop_finish:
3893
 
 * @context: a #GtkDragContext.
3894
 
 * @success: %TRUE if the data was successfully received.
3895
 
 * @time_: the timestamp for this operation.
3896
 
 * 
3897
 
 * Ends the drag operation after a drop.
3898
 
 *
3899
 
 * This function is called by the drag destination.
3900
 
 **/
3901
 
void             
3902
 
gdk_drop_finish (GdkDragContext   *context,
3903
 
                 gboolean          success,
3904
 
                 guint32           time)
3905
 
{
3906
 
  g_return_if_fail (context != NULL);
3907
 
 
3908
 
  if (context->protocol == GDK_DRAG_PROTO_XDND)
3909
 
    {
3910
 
      GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window);
3911
 
      XEvent xev;
3912
 
 
3913
 
      xev.xclient.type = ClientMessage;
3914
 
      xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "XdndFinished");
3915
 
      xev.xclient.format = 32;
3916
 
      xev.xclient.window = GDK_DRAWABLE_XID (context->source_window);
3917
 
      
3918
 
      xev.xclient.data.l[0] = GDK_DRAWABLE_XID (context->dest_window);
3919
 
      if (success)
3920
 
        {
3921
 
          xev.xclient.data.l[1] = 1;
3922
 
          xev.xclient.data.l[2] = xdnd_action_to_atom (display, 
3923
 
                                                       context->action);
3924
 
        }
3925
 
      else
3926
 
        {
3927
 
          xev.xclient.data.l[1] = 0;
3928
 
          xev.xclient.data.l[2] = None;
3929
 
        }
3930
 
      xev.xclient.data.l[3] = 0;
3931
 
      xev.xclient.data.l[4] = 0;
3932
 
 
3933
 
      if (!xdnd_send_xevent (context, context->source_window,
3934
 
                             FALSE, &xev))
3935
 
        GDK_NOTE (DND, 
3936
 
                  g_message ("Send event to %lx failed",
3937
 
                             GDK_DRAWABLE_XID (context->source_window)));
3938
 
    }
3939
 
}
3940
 
 
3941
 
 
3942
 
void            
3943
 
gdk_window_register_dnd (GdkWindow      *window)
3944
 
{
3945
 
  static const gulong xdnd_version = 5;
3946
 
  MotifDragReceiverInfo info;
3947
 
  Atom motif_drag_receiver_info_atom;
3948
 
  GdkDisplay *display = gdk_drawable_get_display (window);
3949
 
 
3950
 
  g_return_if_fail (window != NULL);
3951
 
 
3952
 
  if (gdk_window_get_window_type (window) == GDK_WINDOW_OFFSCREEN)
3953
 
    return;
3954
 
 
3955
 
  base_precache_atoms (display);
3956
 
 
3957
 
  if (g_object_get_data (G_OBJECT (window), "gdk-dnd-registered") != NULL)
3958
 
    return;
3959
 
  else
3960
 
    g_object_set_data (G_OBJECT (window), "gdk-dnd-registered", GINT_TO_POINTER (TRUE));
3961
 
  
3962
 
  /* Set Motif drag receiver information property */
3963
 
 
3964
 
  motif_drag_receiver_info_atom = gdk_x11_get_xatom_by_name_for_display (display,
3965
 
                                                                         "_MOTIF_DRAG_RECEIVER_INFO");
3966
 
  /* initialize to zero to avoid writing uninitialized data to socket */
3967
 
  memset(&info, 0, sizeof(info));
3968
 
  info.byte_order = local_byte_order;
3969
 
  info.protocol_version = 0;
3970
 
  info.protocol_style = XmDRAG_DYNAMIC;
3971
 
  info.proxy_window = None;
3972
 
  info.num_drop_sites = 0;
3973
 
  info.total_size = sizeof(info);
3974
 
 
3975
 
  XChangeProperty (GDK_DISPLAY_XDISPLAY (display), GDK_DRAWABLE_XID (window),
3976
 
                   motif_drag_receiver_info_atom,
3977
 
                   motif_drag_receiver_info_atom,
3978
 
                   8, PropModeReplace,
3979
 
                   (guchar *)&info,
3980
 
                   sizeof (info));
3981
 
 
3982
 
  /* Set XdndAware */
3983
 
 
3984
 
  /* The property needs to be of type XA_ATOM, not XA_INTEGER. Blech */
3985
 
  XChangeProperty (GDK_DISPLAY_XDISPLAY (display),
3986
 
                   GDK_DRAWABLE_XID (window),
3987
 
                   gdk_x11_get_xatom_by_name_for_display (display, "XdndAware"),
3988
 
                   XA_ATOM, 32, PropModeReplace,
3989
 
                   (guchar *)&xdnd_version, 1);
3990
 
}
3991
 
 
3992
 
/**
3993
 
 * gdk_drag_get_selection:
3994
 
 * @context: a #GdkDragContext.
3995
 
 * 
3996
 
 * Returns the selection atom for the current source window.
3997
 
 * 
3998
 
 * Return value: the selection atom.
3999
 
 **/
4000
 
GdkAtom
4001
 
gdk_drag_get_selection (GdkDragContext *context)
4002
 
{
4003
 
  g_return_val_if_fail (context != NULL, GDK_NONE);
4004
 
 
4005
 
  if (context->protocol == GDK_DRAG_PROTO_MOTIF)
4006
 
    return gdk_x11_xatom_to_atom_for_display (GDK_DRAWABLE_DISPLAY (context->source_window),
4007
 
                                              (PRIVATE_DATA (context))->motif_selection);
4008
 
  else if (context->protocol == GDK_DRAG_PROTO_XDND)
4009
 
    return gdk_atom_intern_static_string ("XdndSelection");
4010
 
  else
4011
 
    return GDK_NONE;
4012
 
}
4013
 
 
4014
 
/**
4015
 
 * gdk_drag_drop_succeeded:
4016
 
 * @context: a #GdkDragContext
4017
 
 * 
4018
 
 * Returns whether the dropped data has been successfully 
4019
 
 * transferred. This function is intended to be used while 
4020
 
 * handling a %GDK_DROP_FINISHED event, its return value is
4021
 
 * meaningless at other times.
4022
 
 * 
4023
 
 * Return value: %TRUE if the drop was successful.
4024
 
 *
4025
 
 * Since: 2.6
4026
 
 **/
4027
 
gboolean 
4028
 
gdk_drag_drop_succeeded (GdkDragContext *context)
4029
 
{
4030
 
  GdkDragContextPrivateX11 *private;
4031
 
 
4032
 
  g_return_val_if_fail (context != NULL, FALSE);
4033
 
 
4034
 
  private = PRIVATE_DATA (context);
4035
 
 
4036
 
  return !private->drop_failed;
4037
 
}
4038
 
 
4039
 
#define __GDK_DND_X11_C__
4040
 
#include "gdkaliasdef.c"