 f7bcb45607
			
		
	
	f7bcb45607
	
	
	
		
			
			Sun Oct 18 18:16:39 1998 Owen Taylor <otaylor@gtk.org> * gdk/gdk.c gdkprivate.h: Added a modular client-message-filter mechanism, that is used for the DND messages. Removed all the old DND code. * gdk/gdkcolormap.c gdk/gdkcolormap.h: Add a function to get the visual of a given colormap. * gtk/gtkcolorsel.c: Conversion to new DND, drag a color-swatch. * gdk/gdk.h gdk/gdkdnd.c: The low-level X oriented portions of drag and drop protocols. Sending and receiving client messages, and navigating window trees. * gdk/gdkimage.c: added a gdk_flush() when destroying SHM images to hopefully make it more likely that X will gracefully handle the segment being destroyed. * gdk/gdkprivate.h gtk/gtkdebug.h: Add new DND debugging flags. * gtk/gtkeditable.[ch]: Updates for the selection handling changes. * gtk/gtkselection.[ch]: Added GtkTargetList, a refcounted data structure for keeping track of lists of GdkAtom + information. Removed selection_handler_add in favor of a "drag_data_get" signal. * gtk/gtkdnd.[ch] gtk/gtk.h: New files - highlevel (event loop dependent) parts of the DND protocols, display of drag icons, drag-under highlighting, and the "default handlers". * gtk/gtkinvisible.[ch]: New widget - InputOnly offscreen windows that are used for reliable pointer grabs and selection handling in the DND code. * gtk/testdnd.c: New test program for new DND. (Old DND tests in testgtk still need to be converted.) * gtk/testselection.c: Use the new selection API. * docs/dnd_internals: Start at describing how all the new code works inside. * docs/Changes-1.2.txt: New file describing source-incompatible changes in GTK+-1.2. Sat Oct 17 22:50:34 1998 Owen Taylor <otaylor@gtk.org> * gdk/gdkwindow.c (gdk_window_remove_filter): Free the right list node. * gdk/gdkwindow.c (gdk_window_init): Add gdk_root_parent to the XID table so we can receive events on it. Wed Oct 14 12:57:40 1998 Owen Taylor <otaylor@redhat.com> * gdk/gdk.c gdk/gdk.h (gdk_event_get_time): New function to get the timestamp from a generic event. Fri Oct 9 13:16:04 1998 Owen Taylor <otaylor@redhat.com> * gtk/gtkwidget.c (gtk_widget_add_events): Added function that safely adds additional events to a widget's event mask, even if the widget has previously been realized. (We can do this, but not remove events from the event mask). Fri Oct 2 17:35:35 1998 Owen Taylor <otaylor@redhat.com> * gdk/gdkproperty.c (gdk_property_get): Allow type == 0, for AnyPropertyType. Fri Oct 2 10:32:21 1998 Owen Taylor <otaylor@redhat.com> * gdk/gdkproperty.c (gdk_atom_intern): Add client-local hashing. Thu Sep 24 20:33:54 1998 Owen Taylor <otaylor@redhat.com> * gdk/gdk.c (gdk_event_send_clientmessage_toall): serial isn't a timestamp. Thu Sep 17 14:23:03 1998 Owen Taylor <otaylor@redhat.com> * gdk/gdk.c (gdk_event_translate): Removed printing of unknown window lookup warnings. (Made it a GDK_NOTE) - they happen in many circumstances.
		
			
				
	
	
		
			211 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			211 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| This document describes some of the internals of the DND handling
 | |
| code.
 | |
| 
 | |
| Organization
 | |
| ============
 | |
| 
 | |
| The DND code is split between a lowlevel part - gdkdnd.c and a
 | |
| highlevel part - gtkdnd.c.  To put it simply, gdkdnd.c contain the
 | |
| portions of DND code that are easiest to do in raw X, while gtkdnd.c
 | |
| contains the portions of DND that are easiest to do with an event loop
 | |
| and high level selection handling.
 | |
| 
 | |
| Except for a few details of selection handling, most of the
 | |
| dependencies on the DND protocol are confined to gdkdnd.c.
 | |
| There are two or three supported protocols - Motif DND,
 | |
| Xdnd and a pseudo-protocol ROOTWIN, which is used for drops
 | |
| on root windows that aren't really accepting drops.
 | |
| gdkdnd.c divides into 4 pieces:
 | |
| 
 | |
|  1) Utility functions (finding client windows)
 | |
|  2) Motif specific code (the biggest chunk)
 | |
|  3) Xdnd specific code
 | |
|  4) The public interfaces
 | |
| 
 | |
| The code in gtkdnd.c roughly consists of three parts  
 | |
|   
 | |
|  1) General utility functions
 | |
|  2) Destination side code
 | |
|  3) Source side code.
 | |
| 
 | |
| Both on the source and dest side, there is some division
 | |
| between the low level layers and the default handlers,
 | |
| though they are rather mixed in many cases.
 | |
| 
 | |
| Structures and Memory Management
 | |
| ================================
 | |
| 
 | |
| Information about source sites and drop sites is stored
 | |
| in the structures GtkSourceSite and GtkDestSite.
 | |
| 
 | |
| Information about in-progress drags and drops is stored
 | |
| in the structures GtkSourceInfo and GtkDestInfo.
 | |
| 
 | |
| The GtkSourceInfo structure is created when the drag
 | |
| begins, and persists until the drag either completes
 | |
| or times out. A pointer to it is stored in 
 | |
| dataset-data for the GdkDragContext, however there
 | |
| is no ownership. If the SourceInfo is destroyed
 | |
| before the context, the field is simply cleared.
 | |
| 
 | |
| A GtkDestInfo is attached to each GdkDragContext
 | |
| that is received for an incoming drag. In contrast
 | |
| to the SourceInfo the DestInfo is "owned" by the
 | |
| context, and when the context is destroyed, destroyed.
 | |
| 
 | |
| The GDK API
 | |
| ===========
 | |
| 
 | |
| It is expect that the GDK DND API will never be
 | |
| used by anything other than the DND code in GTK+.
 | |
| 
 | |
| /* Drag and Drop */
 | |
| 
 | |
| GdkDragContext * gdk_drag_context_new        (void);
 | |
| void             gdk_drag_context_ref        (GdkDragContext *context);
 | |
| void             gdk_drag_context_unref      (GdkDragContext *context);
 | |
| 
 | |
| These create and refcount GdkDragContexts in a
 | |
| straightforward manner.
 | |
| 
 | |
| /* Destination side */
 | |
| 
 | |
| void             gdk_drag_status        (GdkDragContext   *context,
 | |
| 				         GdkDragAction     action,
 | |
| 					 guint32           time);
 | |
| void             gdk_drop_reply         (GdkDragContext   *context,
 | |
| 					 gboolean          ok,
 | |
| 					 guint32           time);
 | |
| void             gdk_drop_finish        (GdkDragContext   *context,
 | |
| 					 gboolean          success,
 | |
| 					 guint32           time);
 | |
| GdkAtom          gdk_drag_get_selection (GdkDragContext   *context);
 | |
| 
 | |
| /* Source side */
 | |
| 
 | |
| GdkDragContext * gdk_drag_begin      (GdkWindow      *window,
 | |
| 				      GList          *targets,
 | |
| 				      GdkDragAction   actions);
 | |
| gboolean         gdk_drag_get_protocol (guint32          xid,
 | |
| 					GdkDragProtocol *protocol);
 | |
| void             gdk_drag_find_window (GdkDragContext   *context,
 | |
| 				       GdkWindow       *drag_window,
 | |
| 			 	       gint             x_root,
 | |
| 				       gint             y_root,
 | |
| 				       GdkWindow      **dest_window,
 | |
| 				       GdkDragProtocol *protocol);
 | |
| gboolean        gdk_drag_motion      (GdkDragContext *context,
 | |
| 				      GdkWindow      *dest_window,
 | |
| 				      GdkDragProtocol protocol,
 | |
| 				      gint            x_root, 
 | |
| 				      gint            y_root,
 | |
| 				      GdkDragAction   action,
 | |
| 				      guint32         time);
 | |
| void            gdk_drag_drop        (GdkDragContext *context,
 | |
| 				      guint32         time);
 | |
| void            gdk_drag_abort       (GdkDragContext *context,
 | |
| 				      guint32         time);
 | |
| 
 | |
| GdkAtom       gdk_drag_get_selection (GdkDragContext *context);
 | |
| 
 | |
| Retrieves the selection that will be used to communicate
 | |
| the data for the drag context (valid on both source
 | |
| and dest sides)
 | |
| 
 | |
| Cursors and window heirarchies
 | |
| ==============================
 | |
| 
 | |
| The DND code, when possible (and it isn't possible over
 | |
| Motif window) uses a shaped window as a drag icon.
 | |
| Because the cursor may fall inside this window during the
 | |
| drag, we actually have to figure out which window
 | |
| the cursor is in _ourselves_ so we can ignore the
 | |
| drag icon properly. (Oh for OutputOnly windows!)
 | |
| 
 | |
| To avoid obscene amounts of server traffic (which are only
 | |
| slighly observerable locally, but would really kill a
 | |
| session over a slow link), the code in GDK does
 | |
| XGetWindowAttributes for every child of the root window at
 | |
| the beginning of the drag, then selects with
 | |
| SubstructureNotifyMask on the root window, so that
 | |
| it can update this list.
 | |
| 
 | |
| It probably would be easier to just reread the entire
 | |
| list when one of these events occurs, instead of 
 | |
| incrementally updating, but updating the list in
 | |
| sync was sort of fun code, so I did it that way ;-)
 | |
| 
 | |
| There is also a problem of trying to follow the
 | |
| mouse cursor as well as possible. Currently, the
 | |
| code uses PointerMotionHint, and an XQueryPointer
 | |
| on MotionNotify events. This results in pretty
 | |
| good syncing, but may result in somewhat poor
 | |
| accuracy for drops. (Because the coordinates of
 | |
| the drop are the coordinates when the server receives
 | |
| the button press, which might actually be before
 | |
| the XQueryPointer for the previous MotionNotify
 | |
| event is done.)
 | |
| 
 | |
| Probably better is doing MotionNotify compression 
 | |
| and discarding MotionNotify events when there
 | |
| are more on the queue before the next ButtonPress/Release.
 | |
| 
 | |
| Proxying
 | |
| ========
 | |
| 
 | |
| A perhaps rather unusual feature of GTK's DND is proxying. A
 | |
| dest site can be specified as a proxy drop site for another
 | |
| window. This is most needed for the plug-socket code - the
 | |
| socket needs to pass on drags to the plug since the original
 | |
| source only sees toplevel windows. However, it can also be
 | |
| used as a user visible proxy - i.e., dragging to buttons on
 | |
| the taskbar.
 | |
| 
 | |
| Internally, when the outer drag enters a proxy dest site, a
 | |
| new source drag is created, with SourceInfo and
 | |
| GdkDragContext. From the GDK side, it looks much like a
 | |
| normal source drag; on the GTK+ side, most of the code is
 | |
| disjoint. The need to pass in a specific target window
 | |
| is the reason why the GDK DND API splits
 | |
| gdk_drag_find_window() and gdk_drag_motion().
 | |
| 
 | |
| For proxy drags, the GtkDestInfo and GtkSourceInfo for the
 | |
| drag point at each other.
 | |
| 
 | |
| Because the abstraction of the drag protocol is at the GDK
 | |
| level, a proxy drag from Motif to Xdnd or vice versa happens
 | |
| pretty much automatically during the drag, though the
 | |
| drop can get complicated. For Xdnd <-> Motif,
 | |
| Motif <-> Xdnd, or Motif <-> Motif drags, it is necessary to 
 | |
| for the Proxy to retrieve the data and pass it on to
 | |
| the true destination, since either the selection names
 | |
| differ or (Motif<->Motif), the proxy needs to know
 | |
| about the XmDRAG_SUCCESS/FAILURE selection targets.
 | |
| 
 | |
| Further Reading:
 | |
| ================
 | |
| 
 | |
| Xdnd:
 | |
| 
 | |
| The spec is at:
 | |
| 
 | |
|  http://www.cco.caltech.edu/~jafl/xdnd/
 | |
| 
 | |
| Motif:
 | |
| 
 | |
| The Motif DND protocol is best described in the 
 | |
| Hungry Programmers _Inside Lesstif_ book, available
 | |
| from:
 | |
| 
 | |
|   http://www.igpm.rwth-aachen.de/~albrecht/hungry.html
 | |
| 
 | |
| Harald Albrecht and Mitch Miers have done a far
 | |
| better job at documenting the DND protocol then
 | |
| anything the OpenGroup has produced.
 | |
| 
 | |
| 
 | |
| 
 | |
| Owen Taylor
 | |
| otaylor@redhat.com
 | |
| Oct 18, 1998
 |