]> Pileus Git - ~andy/gtk/blob - docs/dnd_internals.txt
46156dfdd90feb200a7efc467b061b81d2232b49
[~andy/gtk] / docs / dnd_internals.txt
1 This document describes some of the internals of the DND handling
2 code.
3
4 Organization
5 ============
6
7 The DND code is split between a lowlevel part - gdkdnd.c and a
8 highlevel part - gtkdnd.c.  To put it simply, gdkdnd.c contain the
9 portions of DND code that are easiest to do in raw X, while gtkdnd.c
10 contains the portions of DND that are easiest to do with an event loop
11 and high level selection handling.
12
13 Except for a few details of selection handling, most of the
14 dependencies on the DND protocol are confined to gdkdnd.c.
15 There are two or three supported protocols - Motif DND,
16 Xdnd and a pseudo-protocol ROOTWIN, which is used for drops
17 on root windows that aren't really accepting drops.
18 gdkdnd.c divides into 4 pieces:
19
20  1) Utility functions (finding client windows)
21  2) Motif specific code (the biggest chunk)
22  3) Xdnd specific code
23  4) The public interfaces
24
25 The code in gtkdnd.c roughly consists of three parts  
26   
27  1) General utility functions
28  2) Destination side code
29  3) Source side code.
30
31 Both on the source and dest side, there is some division
32 between the low level layers and the default handlers,
33 though they are rather mixed in many cases.
34
35 Structures and Memory Management
36 ================================
37
38 Information about source sites and drop sites is stored
39 in the structures GtkSourceSite and GtkDestSite.
40
41 Information about in-progress drags and drops is stored
42 in the structures GtkSourceInfo and GtkDestInfo.
43
44 The GtkSourceInfo structure is created when the drag
45 begins, and persists until the drag either completes
46 or times out. A pointer to it is stored in 
47 dataset-data for the GdkDragContext, however there
48 is no ownership. If the SourceInfo is destroyed
49 before the context, the field is simply cleared.
50
51 A GtkDestInfo is attached to each GdkDragContext
52 that is received for an incoming drag. In contrast
53 to the SourceInfo the DestInfo is "owned" by the
54 context, and when the context is destroyed, destroyed.
55
56 The GDK API
57 ===========
58
59 It is expect that the GDK DND API will never be
60 used by anything other than the DND code in GTK+.
61
62 /* Drag and Drop */
63
64 GdkDragContext * gdk_drag_context_new        (void);
65 void             gdk_drag_context_ref        (GdkDragContext *context);
66 void             gdk_drag_context_unref      (GdkDragContext *context);
67
68 These create and refcount GdkDragContexts in a
69 straightforward manner.
70
71 /* Destination side */
72
73 void             gdk_drag_status        (GdkDragContext   *context,
74                                          GdkDragAction     action,
75                                          guint32           time);
76 void             gdk_drop_reply         (GdkDragContext   *context,
77                                          gboolean          ok,
78                                          guint32           time);
79 void             gdk_drop_finish        (GdkDragContext   *context,
80                                          gboolean          success,
81                                          guint32           time);
82 GdkAtom          gdk_drag_get_selection (GdkDragContext   *context);
83
84 /* Source side */
85
86 GdkDragContext * gdk_drag_begin      (GdkWindow      *window,
87                                       GList          *targets,
88                                       GdkDragAction   actions);
89 gboolean         gdk_drag_get_protocol (guint32          xid,
90                                         GdkDragProtocol *protocol);
91 void             gdk_drag_find_window (GdkDragContext   *context,
92                                        GdkWindow       *drag_window,
93                                        gint             x_root,
94                                        gint             y_root,
95                                        GdkWindow      **dest_window,
96                                        GdkDragProtocol *protocol);
97 gboolean        gdk_drag_motion      (GdkDragContext *context,
98                                       GdkWindow      *dest_window,
99                                       GdkDragProtocol protocol,
100                                       gint            x_root, 
101                                       gint            y_root,
102                                       GdkDragAction   action,
103                                       guint32         time);
104 void            gdk_drag_drop        (GdkDragContext *context,
105                                       guint32         time);
106 void            gdk_drag_abort       (GdkDragContext *context,
107                                       guint32         time);
108
109 GdkAtom       gdk_drag_get_selection (GdkDragContext *context);
110
111 Retrieves the selection that will be used to communicate
112 the data for the drag context (valid on both source
113 and dest sides)
114
115 Cursors and window heirarchies
116 ==============================
117
118 The DND code, when possible (and it isn't possible over
119 Motif window) uses a shaped window as a drag icon.
120 Because the cursor may fall inside this window during the
121 drag, we actually have to figure out which window
122 the cursor is in _ourselves_ so we can ignore the
123 drag icon properly. (Oh for OutputOnly windows!)
124
125 To avoid obscene amounts of server traffic (which are only
126 slighly observerable locally, but would really kill a
127 session over a slow link), the code in GDK does
128 XGetWindowAttributes for every child of the root window at
129 the beginning of the drag, then selects with
130 SubstructureNotifyMask on the root window, so that
131 it can update this list.
132
133 It probably would be easier to just reread the entire
134 list when one of these events occurs, instead of 
135 incrementally updating, but updating the list in
136 sync was sort of fun code, so I did it that way ;-)
137
138 There is also a problem of trying to follow the
139 mouse cursor as well as possible. Currently, the
140 code uses PointerMotionHint, and an XQueryPointer
141 on MotionNotify events. This results in pretty
142 good syncing, but may result in somewhat poor
143 accuracy for drops. (Because the coordinates of
144 the drop are the coordinates when the server receives
145 the button press, which might actually be before
146 the XQueryPointer for the previous MotionNotify
147 event is done.)
148
149 Probably better is doing MotionNotify compression 
150 and discarding MotionNotify events when there
151 are more on the queue before the next ButtonPress/Release.
152
153 Proxying
154 ========
155
156 A perhaps rather unusual feature of GTK's DND is proxying. A
157 dest site can be specified as a proxy drop site for another
158 window. This is most needed for the plug-socket code - the
159 socket needs to pass on drags to the plug since the original
160 source only sees toplevel windows. However, it can also be
161 used as a user visible proxy - i.e., dragging to buttons on
162 the taskbar.
163
164 Internally, when the outer drag enters a proxy dest site, a
165 new source drag is created, with SourceInfo and
166 GdkDragContext. From the GDK side, it looks much like a
167 normal source drag; on the GTK+ side, most of the code is
168 disjoint. The need to pass in a specific target window
169 is the reason why the GDK DND API splits
170 gdk_drag_find_window() and gdk_drag_motion().
171
172 For proxy drags, the GtkDestInfo and GtkSourceInfo for the
173 drag point at each other.
174
175 Because the abstraction of the drag protocol is at the GDK
176 level, a proxy drag from Motif to Xdnd or vice versa happens
177 pretty much automatically during the drag, though the
178 drop can get complicated. For Xdnd <-> Motif,
179 Motif <-> Xdnd, or Motif <-> Motif drags, it is necessary to 
180 for the Proxy to retrieve the data and pass it on to
181 the true destination, since either the selection names
182 differ or (Motif<->Motif), the proxy needs to know
183 about the XmDRAG_SUCCESS/FAILURE selection targets.
184
185 Further Reading:
186 ================
187
188 Xdnd:
189
190 The spec is at:
191
192  http://www.cco.caltech.edu/~jafl/xdnd/
193
194 Motif:
195
196 The Motif DND protocol is best described in the 
197 Hungry Programmers _Inside Lesstif_ book, available
198 from:
199
200   http://www.igpm.rwth-aachen.de/~albrecht/hungry.html
201
202 Harald Albrecht and Mitch Miers have done a far
203 better job at documenting the DND protocol then
204 anything the OpenGroup has produced.
205
206
207
208 Owen Taylor
209 otaylor@redhat.com
210 Oct 18, 1998