1 /* GDK - The GIMP Drawing Kit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library 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.
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 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the Free
16 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 #include "../config.h"
28 #ifdef HAVE_SYS_SELECT_H
29 #include <sys/select.h>
30 #endif /* HAVE_SYS_SELECT_H_ */
32 #define XLIB_ILLEGAL_ACCESS
33 #include <X11/Xatom.h>
36 #include <X11/Xutil.h>
37 #include <X11/Xmu/WinUtil.h>
38 #include <X11/cursorfont.h>
40 #include "gdkprivate.h"
44 #ifndef X_GETTIMEOFDAY
45 #define X_GETTIMEOFDAY(tv) gettimeofday (tv, NULL)
46 #endif /* X_GETTIMEOFDAY */
49 #define DOUBLE_CLICK_TIME 250
50 #define TRIPLE_CLICK_TIME 500
51 #define DOUBLE_CLICK_DIST 5
52 #define TRIPLE_CLICK_DIST 5
56 # define SELECT_MASK fd_set
62 # define SELECT_MASK void
64 # define SELECT_MASK int
69 typedef struct _GdkInput GdkInput;
70 typedef struct _GdkPredicate GdkPredicate;
76 GdkInputCondition condition;
77 GdkInputFunction function;
88 * Private function declarations
90 static gint gdk_event_wait (void);
91 static gint gdk_event_translate (GdkEvent *event,
93 static Bool gdk_event_get_type (Display *display,
96 static void gdk_synthesize_click (GdkEvent *event,
99 static void gdk_dnd_drag_begin (GdkWindow *initial_window);
100 static void gdk_dnd_drag_enter (Window dest);
101 static void gdk_dnd_drag_leave (Window dest);
102 static void gdk_dnd_drag_end (Window dest,
104 static GdkAtom gdk_dnd_check_types (GdkWindow *window,
106 static void gdk_print_atom (GdkAtom anatom);
109 * old junk from offix, we might use it though so leave it
111 static Window gdk_drop_get_client_window (Display *dpy,
113 static GdkWindow * gdk_drop_get_real_window (GdkWindow *w,
116 static void gdk_exit_func (void);
117 static int gdk_x_error (Display *display,
119 static int gdk_x_io_error (Display *display);
120 static RETSIGTYPE gdk_signal (int signum);
123 /* Private variable declarations
125 static int initialized = 0; /* 1 if the library is initialized,
128 static int connection_number = 0; /* The file descriptor number of our
129 * connection to the X server. This
130 * is used so that we may determine
131 * when events are pending by using
132 * the "select" system call.
135 static gint received_destroy_notify = FALSE; /* Did we just receive a destroy notify
136 * event? If so, we need to actually
137 * destroy the window which received
140 static GdkWindow *window_to_destroy = NULL; /* If we previously received a destroy
141 * notify event then this is the window
142 * which received that event.
145 static struct timeval start; /* The time at which the library was
148 static struct timeval timer; /* Timeout interval to use in the call
149 * to "select". This is used in
150 * conjunction with "timerp" to create
151 * a maximum time to wait for an event
154 static struct timeval *timerp; /* The actual timer passed to "select"
155 * This may be NULL, in which case
156 * "select" will block until an event
159 static guint32 timer_val; /* The timeout length as specified by
160 * the user in milliseconds.
162 static GList *inputs; /* A list of the input file descriptors
163 * that we care about. Each list node
164 * contains a GdkInput struct that describes
165 * when we are interested in the specified
166 * file descriptor. That is, when it is
167 * available for read, write or has an
170 static guint32 button_click_time[2]; /* The last 2 button click times. Used
171 * to determine if the latest button click
172 * is part of a double or triple click.
174 static GdkWindow *button_window[2]; /* The last 2 windows to receive button presses.
175 * Also used to determine if the latest button
176 * click is part of a double or triple click.
178 static guint button_number[2]; /* The last 2 buttons to be pressed.
181 #define OTHER_XEVENT_BUFSIZE 4
182 static XEvent other_xevent[OTHER_XEVENT_BUFSIZE]; /* XEvents passed along to user */
183 static int other_xevent_i = 0;
184 static GList *putback_events = NULL;
186 static gulong base_id;
187 static gint autorepeat;
191 *--------------------------------------------------------------
194 * Initialize the library for use.
197 * "argc" is the number of arguments.
198 * "argv" is an array of strings.
201 * "argc" and "argv" are modified to reflect any arguments
202 * which were not handled. (Such arguments should either
203 * be handled by the application or dismissed).
206 * The library is initialized.
208 *--------------------------------------------------------------
215 XKeyboardState keyboard_state;
218 XClassHint *class_hint;
219 int argc_orig = *argc;
222 argv_orig = malloc ((argc_orig + 1) * sizeof (char*));
223 for (i = 0; i < argc_orig; i++)
224 argv_orig[i] = g_strdup ((*argv)[i]);
225 argv_orig[argc_orig] = NULL;
227 X_GETTIMEOFDAY (&start);
229 signal (SIGHUP, gdk_signal);
230 signal (SIGINT, gdk_signal);
231 signal (SIGQUIT, gdk_signal);
232 signal (SIGBUS, gdk_signal);
233 signal (SIGSEGV, gdk_signal);
234 signal (SIGPIPE, gdk_signal);
235 signal (SIGTERM, gdk_signal);
237 gdk_display_name = NULL;
239 XSetErrorHandler (gdk_x_error);
240 XSetIOErrorHandler (gdk_x_io_error);
247 gdk_progname = (*argv)[0];
249 for (i = 1; i < *argc;)
251 if (strcmp ("--display", (*argv)[i]) == 0)
257 gdk_display_name = g_strdup ((*argv)[i + 1]);
258 (*argv)[i + 1] = NULL;
262 else if (strcmp ("--sync", (*argv)[i]) == 0)
267 else if (strcmp ("--show-events", (*argv)[i]) == 0)
270 gdk_show_events = TRUE;
272 else if (strcmp ("--no-show-events", (*argv)[i]) == 0)
275 gdk_show_events = FALSE;
277 else if (strcmp ("--no-xshm", (*argv)[i]) == 0)
280 gdk_use_xshm = FALSE;
282 else if (strcmp ("--debug-level", (*argv)[i]) == 0)
287 gdk_debug_level = atoi ((*argv)[i]);
291 else if (strcmp ("-name", (*argv)[i]) == 0)
296 gdk_progname = (*argv)[i];
300 else if (strcmp ("-class", (*argv)[i]) == 0)
305 gdk_progclass = (*argv)[i];
310 else if (strcmp ("--gxid_host", (*argv)[i]) == 0)
315 gdk_input_gxid_host = ((*argv)[i]);
319 else if (strcmp ("--gxid_port", (*argv)[i]) == 0)
324 gdk_input_gxid_port = atoi ((*argv)[i]);
332 for (i = 1; i < *argc; i++)
334 for (k = i; k < *argc; k++)
335 if ((*argv)[k] != NULL)
341 for (j = i + k; j < *argc; j++)
342 (*argv)[j-k] = (*argv)[j];
349 gdk_progname = "<unknown>";
352 gdk_display = XOpenDisplay (gdk_display_name);
354 g_error ("cannot open display: %s", XDisplayName (gdk_display_name));
356 /* This is really crappy. We have to look into the display structure
357 * to find the base resource id. This is only needed for recording
358 * and playback of events.
360 /* base_id = RESOURCE_BASE; */
363 g_print ("base id: %lu\n", base_id);
365 connection_number = ConnectionNumber (gdk_display);
366 if (gdk_debug_level >= 1)
367 g_print ("connection number: %d\n", connection_number);
370 XSynchronize (gdk_display, True);
372 gdk_screen = DefaultScreen (gdk_display);
373 gdk_root_window = RootWindow (gdk_display, gdk_screen);
375 gdk_leader_window = XCreateSimpleWindow(gdk_display, gdk_root_window,
376 10, 10, 10, 10, 0, 0 , 0);
377 class_hint = XAllocClassHint();
378 class_hint->res_name = gdk_progname;
379 class_hint->res_class = gdk_progclass;
380 XSetClassHint(gdk_display, gdk_leader_window, class_hint);
381 XSetCommand(gdk_display, gdk_leader_window, argv_orig, argc_orig);
384 gdk_wm_delete_window = XInternAtom (gdk_display, "WM_DELETE_WINDOW", True);
385 gdk_wm_take_focus = XInternAtom (gdk_display, "WM_TAKE_FOCUS", True);
386 gdk_wm_protocols = XInternAtom (gdk_display, "WM_PROTOCOLS", True);
387 gdk_wm_window_protocols[0] = gdk_wm_delete_window;
388 gdk_wm_window_protocols[1] = gdk_wm_take_focus;
389 gdk_selection_property = XInternAtom (gdk_display, "GDK_SELECTION", False);
391 gdk_dnd.gdk_XdeEnter = gdk_atom_intern("_XDE_ENTER", FALSE);
392 gdk_dnd.gdk_XdeLeave = gdk_atom_intern("_XDE_LEAVE", FALSE);
393 gdk_dnd.gdk_XdeRequest = gdk_atom_intern("_XDE_REQUEST", FALSE);
394 gdk_dnd.gdk_XdeDataAvailable = gdk_atom_intern("_XDE_DATA_AVAILABLE", FALSE);
395 gdk_dnd.gdk_XdeTypelist = gdk_atom_intern("_XDE_TYPELIST", FALSE);
396 gdk_dnd.gdk_cursor_dragdefault = XCreateFontCursor(gdk_display, XC_bogosity);
397 gdk_dnd.gdk_cursor_dragok = XCreateFontCursor(gdk_display, XC_heart);
399 XGetKeyboardControl (gdk_display, &keyboard_state);
400 autorepeat = keyboard_state.global_auto_repeat;
406 button_click_time[0] = 0;
407 button_click_time[1] = 0;
408 button_window[0] = NULL;
409 button_window[1] = NULL;
410 button_number[0] = -1;
411 button_number[1] = -1;
413 if (ATEXIT (gdk_exit_func))
414 g_warning ("unable to register exit function");
425 *--------------------------------------------------------------
428 * Restores the library to an un-itialized state and exits
429 * the program using the "exit" system call.
432 * "errorcode" is the error value to pass to "exit".
435 * Allocated structures are freed and the program exits
440 *--------------------------------------------------------------
444 gdk_exit (int errorcode)
446 /* de-initialisation is done by the gdk_exit_funct(),
447 no need to do this here (Alex J.) */
452 *--------------------------------------------------------------
461 *--------------------------------------------------------------
467 if (!setlocale (LC_ALL,""))
468 g_print ("locale not supported by C library\n");
470 if (!XSupportsLocale ())
472 g_print ("locale not supported by Xlib, locale set to C\n");
473 setlocale (LC_ALL, "C");
476 if (!XSetLocaleModifiers (""))
478 g_print ("can not set locale modifiers\n");
481 return setlocale (LC_ALL,NULL);
485 *--------------------------------------------------------------
488 * Returns the number of events pending on the queue.
489 * These events have already been read from the server
495 * Returns the number of events on XLib's event queue.
499 *--------------------------------------------------------------
503 gdk_events_pending ()
505 return XPending (gdk_display);
509 *--------------------------------------------------------------
512 * Gets the next event.
515 * "event" is used to hold the received event.
516 * If "event" is NULL an event is received as normal
517 * however it is not placed in "event" (and thus no
521 * Returns TRUE if an event was received that we care about
522 * and FALSE otherwise. This function will also return
523 * before an event is received if the timeout interval
528 *--------------------------------------------------------------
532 gdk_event_get (GdkEvent *event,
536 GdkEvent *temp_event;
537 GdkPredicate event_pred;
541 /* If the last event we received was a destroy notify
542 * event then we will actually destroy the "gdk" data
543 * structures now. We don't want to destroy them at the
544 * time of receiving the event since the main program
545 * may try to access them and may need to destroy user
546 * data that has been attached to the window
548 if (received_destroy_notify)
551 g_print ("destroying window:\twindow: %ld\n",
552 ((GdkWindowPrivate*) window_to_destroy)->xwindow - base_id);
554 gdk_window_real_destroy (window_to_destroy);
555 received_destroy_notify = FALSE;
556 window_to_destroy = NULL;
559 /* Initially we haven't received an event and want to
560 * return FALSE. If "event" is non-NULL, then initialize
561 * it to the nothing event.
565 event->any.type = GDK_NOTHING;
566 event->any.window = NULL;
567 event->any.send_event = FALSE;
572 temp_list = putback_events;
575 temp_event = temp_list->data;
577 if ((* pred) (temp_event, data))
580 *event = *temp_event;
581 putback_events = g_list_remove_link (putback_events, temp_list);
582 g_list_free (temp_list);
586 temp_list = temp_list->next;
589 event_pred.func = pred;
590 event_pred.data = data;
592 if (XCheckIfEvent (gdk_display, &xevent, gdk_event_get_type, (XPointer) &event_pred))
594 return gdk_event_translate (event, &xevent);
600 temp_event = putback_events->data;
601 *event = *temp_event;
603 temp_list = putback_events;
604 putback_events = putback_events->next;
606 putback_events->prev = NULL;
608 temp_list->next = NULL;
609 temp_list->prev = NULL;
610 g_list_free (temp_list);
616 /* Wait for an event to occur or the timeout to elapse.
617 * If an event occurs "gdk_event_wait" will return TRUE.
618 * If the timeout elapses "gdk_event_wait" will return
621 if (gdk_event_wait ())
623 /* If we get here we can rest assurred that an event
624 * has occurred. Read it.
626 XNextEvent (gdk_display, &xevent);
628 event->any.send_event = xevent.xany.send_event;
630 /* If "event" non-NULL.
633 return gdk_event_translate (event, &xevent);
641 gdk_event_put (GdkEvent *event)
645 g_return_if_fail (event != NULL);
647 new_event = g_new (GdkEvent, 1);
650 putback_events = g_list_prepend (putback_events, new_event);
654 *--------------------------------------------------------------
657 * Copy a event structure into new storage.
660 * "event" is the event struct to copy.
663 * A new event structure. Free it with gdk_event_free.
666 * The reference count of the window in the event is increased.
668 *--------------------------------------------------------------
671 static GMemChunk *event_chunk;
674 gdk_event_copy (GdkEvent *event)
678 g_return_val_if_fail (event != NULL, NULL);
680 if (event_chunk == NULL)
681 event_chunk = g_mem_chunk_new ("events",
686 new_event = g_chunk_new (GdkEvent, event_chunk);
688 gdk_window_ref (new_event->any.window);
693 *--------------------------------------------------------------
696 * Free a event structure obtained from gdk_event_copy. Do not use
697 * with other event structures.
700 * "event" is the event struct to free.
705 * The reference count of the window in the event is decreased and
706 * might be freed, too.
708 *-------------------------------------------------------------- */
711 gdk_event_free (GdkEvent *event)
713 g_assert (event_chunk != NULL);
714 g_return_if_fail (event != NULL);
716 gdk_window_unref (event->any.window);
717 g_mem_chunk_free (event_chunk, event);
721 *--------------------------------------------------------------
722 * gdk_set_debug_level
724 * Sets the debugging level.
727 * "level" is the new debugging level.
732 * Other function calls to "gdk" use the debugging
733 * level to determine what kind of debugging information
736 *--------------------------------------------------------------
740 gdk_set_debug_level (int level)
742 gdk_debug_level = level;
746 *--------------------------------------------------------------
747 * gdk_set_show_events
749 * Turns on/off the showing of events.
752 * "show_events" is a boolean describing whether or
753 * not to show the events gdk receives.
758 * When "show_events" is TRUE, calls to "gdk_event_get"
759 * will output debugging informatin regarding the event
760 * received to stdout.
762 *--------------------------------------------------------------
766 gdk_set_show_events (int show_events)
768 gdk_show_events = show_events;
772 gdk_set_use_xshm (gint use_xshm)
774 gdk_use_xshm = use_xshm;
778 gdk_get_debug_level ()
780 return gdk_debug_level;
784 gdk_get_show_events ()
786 return gdk_show_events;
796 *--------------------------------------------------------------
799 * Get the number of milliseconds since the library was
805 * The time since the library was initialized is returned.
806 * This time value is accurate to milliseconds even though
807 * a more accurate time down to the microsecond could be
812 *--------------------------------------------------------------
819 struct timeval elapsed;
820 guint32 milliseconds;
822 X_GETTIMEOFDAY (&end);
824 if (start.tv_usec > end.tv_usec)
826 end.tv_usec += 1000000;
829 elapsed.tv_sec = end.tv_sec - start.tv_sec;
830 elapsed.tv_usec = end.tv_usec - start.tv_usec;
832 milliseconds = (elapsed.tv_sec * 1000) + (elapsed.tv_usec / 1000);
838 *--------------------------------------------------------------
841 * Returns the current timer.
846 * Returns the current timer interval. This interval is
847 * in units of milliseconds.
851 *--------------------------------------------------------------
861 *--------------------------------------------------------------
864 * Sets the timer interval.
867 * "milliseconds" is the new value for the timer.
872 * Calls to "gdk_event_get" will last for a maximum
873 * of time of "milliseconds". However, a value of 0
874 * milliseconds will cause "gdk_event_get" to block
875 * indefinately until an event is received.
877 *--------------------------------------------------------------
881 gdk_timer_set (guint32 milliseconds)
883 timer_val = milliseconds;
884 timer.tv_sec = milliseconds / 1000;
885 timer.tv_usec = (milliseconds % 1000) * 1000;
902 gdk_input_add (gint source,
903 GdkInputCondition condition,
904 GdkInputFunction function,
907 static gint next_tag = 1;
920 if ((input->source == source) && (input->condition == condition))
922 input->function = function;
930 input = g_new (GdkInput, 1);
931 input->tag = next_tag++;
932 input->source = source;
933 input->condition = condition;
934 input->function = function;
938 inputs = g_list_prepend (inputs, input);
945 gdk_input_remove (gint tag)
956 if (input->tag == tag)
961 list->next->prev = list->prev;
963 list->prev->next = list->next;
967 temp_list->next = NULL;
968 temp_list->prev = NULL;
970 g_free (temp_list->data);
971 g_list_free (temp_list);
980 *--------------------------------------------------------------
983 * Grabs the pointer to a specific window
986 * "window" is the window which will receive the grab
987 * "owner_events" specifies whether events will be reported as is,
988 * or relative to "window"
989 * "event_mask" masks only interesting events
990 * "confine_to" limits the cursor movement to the specified window
991 * "cursor" changes the cursor for the duration of the grab
992 * "time" specifies the time
997 * requires a corresponding call to gdk_pointer_ungrab
999 *--------------------------------------------------------------
1003 gdk_pointer_grab (GdkWindow * window,
1005 GdkEventMask event_mask,
1006 GdkWindow * confine_to,
1010 /* From gdkwindow.c */
1011 extern int nevent_masks;
1012 extern int event_mask_table[];
1015 GdkWindowPrivate *window_private;
1016 GdkWindowPrivate *confine_to_private;
1017 GdkCursorPrivate *cursor_private;
1024 g_return_val_if_fail (window != NULL, 0);
1026 window_private = (GdkWindowPrivate*) window;
1027 confine_to_private = (GdkWindowPrivate*) confine_to;
1028 cursor_private = (GdkCursorPrivate*) cursor;
1030 xwindow = window_private->xwindow;
1035 xconfine_to = confine_to_private->xwindow;
1040 xcursor = cursor_private->xcursor;
1044 for (i = 0; i < nevent_masks; i++)
1046 if (event_mask & (1 << (i + 1)))
1047 xevent_mask |= event_mask_table[i];
1050 if (((GdkWindowPrivate *)window)->extension_events &&
1051 gdk_input_vtable.grab_pointer)
1052 return_val = gdk_input_vtable.grab_pointer (window,
1058 return_val = Success;;
1060 if (return_val == Success)
1061 return_val = XGrabPointer (window_private->xdisplay,
1065 GrabModeAsync, GrabModeAsync,
1074 *--------------------------------------------------------------
1075 * gdk_pointer_ungrab
1077 * Releases any pointer grab
1085 *--------------------------------------------------------------
1089 gdk_pointer_ungrab (guint32 time)
1091 if (gdk_input_vtable.ungrab_pointer)
1092 gdk_input_vtable.ungrab_pointer (time);
1094 XUngrabPointer (gdk_display, time);
1098 *--------------------------------------------------------------
1101 * Grabs the keyboard to a specific window
1104 * "window" is the window which will receive the grab
1105 * "owner_events" specifies whether events will be reported as is,
1106 * or relative to "window"
1107 * "time" specifies the time
1112 * requires a corresponding call to gdk_keyboard_ungrab
1114 *--------------------------------------------------------------
1118 gdk_keyboard_grab (GdkWindow * window,
1122 GdkWindowPrivate *window_private;
1125 g_return_val_if_fail (window != NULL, 0);
1127 window_private = (GdkWindowPrivate*) window;
1128 xwindow = window_private->xwindow;
1130 return XGrabKeyboard (window_private->xdisplay,
1133 GrabModeAsync, GrabModeAsync,
1138 *--------------------------------------------------------------
1139 * gdk_keyboard_ungrab
1141 * Releases any keyboard grab
1149 *--------------------------------------------------------------
1153 gdk_keyboard_ungrab (guint32 time)
1155 XUngrabKeyboard (gdk_display, time);
1159 *--------------------------------------------------------------
1162 * Return the width of the screen.
1170 *--------------------------------------------------------------
1178 return_val = DisplayWidth (gdk_display, gdk_screen);
1184 *--------------------------------------------------------------
1187 * Return the height of the screen.
1195 *--------------------------------------------------------------
1199 gdk_screen_height ()
1203 return_val = DisplayHeight (gdk_display, gdk_screen);
1209 gdk_key_repeat_disable ()
1211 XAutoRepeatOff (gdk_display);
1215 gdk_key_repeat_restore ()
1218 XAutoRepeatOn (gdk_display);
1220 XAutoRepeatOff (gdk_display);
1225 *--------------------------------------------------------------
1228 * Flushes the Xlib output buffer and then waits
1229 * until all requests have been received and processed
1230 * by the X server. The only real use for this function
1231 * is in dealing with XShm.
1239 *--------------------------------------------------------------
1244 XSync (gdk_display, False);
1251 XBell(gdk_display, 100);
1256 *--------------------------------------------------------------
1259 * Waits until an event occurs or the timer runs out.
1264 * Returns TRUE if an event is ready to be read and FALSE
1265 * if the timer ran out.
1269 *--------------------------------------------------------------
1277 GdkInputCondition condition;
1278 SELECT_MASK readfds;
1279 SELECT_MASK writefds;
1280 SELECT_MASK exceptfds;
1284 /* If there are no events pending we will wait for an event.
1285 * The time we wait is dependant on the "timer". If no timer
1286 * has been specified then we'll block until an event arrives.
1287 * If a timer has been specified we'll block until an event
1288 * arrives or the timer expires. (This is all done using the
1289 * "select" system call).
1292 if (XPending (gdk_display) == 0)
1295 FD_ZERO (&writefds);
1296 FD_ZERO (&exceptfds);
1298 FD_SET (connection_number, &readfds);
1299 max_input = connection_number;
1307 if (input->condition & GDK_INPUT_READ)
1308 FD_SET (input->source, &readfds);
1309 if (input->condition & GDK_INPUT_WRITE)
1310 FD_SET (input->source, &writefds);
1311 if (input->condition & GDK_INPUT_EXCEPTION)
1312 FD_SET (input->source, &exceptfds);
1314 max_input = MAX (max_input, input->source);
1317 nfd = select (max_input+1, &readfds, &writefds, &exceptfds, timerp);
1324 if (FD_ISSET (connection_number, &readfds))
1326 if (XPending (gdk_display) == 0)
1330 XNoOp (gdk_display);
1331 XFlush (gdk_display);
1346 if (FD_ISSET (input->source, &readfds))
1347 condition |= GDK_INPUT_READ;
1348 if (FD_ISSET (input->source, &writefds))
1349 condition |= GDK_INPUT_WRITE;
1350 if (FD_ISSET (input->source, &exceptfds))
1351 condition |= GDK_INPUT_EXCEPTION;
1353 if (condition && input->function)
1354 (* input->function) (input->data, input->source, condition);
1365 gdk_event_translate (GdkEvent *event,
1370 GdkWindowPrivate *window_private;
1371 XComposeStatus compose;
1376 /* Are static variables used for this purpose thread-safe? */
1377 static GdkPoint dnd_drag_start = {0,0},
1378 dnd_drag_oldpos = {0,0};
1379 static GdkRectangle dnd_drag_dropzone = {0,0,0,0};
1380 static gint dnd_drag_perhaps = 0;
1381 static GdkWindowPrivate *real_sw = NULL;
1382 static Window dnd_drag_curwin = None, dnd_drag_target = None;
1386 /* Find the GdkWindow that this event occurred in.
1387 * All events occur in some GdkWindow (otherwise, why
1388 * would we be receiving them). It really is an error
1389 * to receive an event for which we cannot find the
1390 * corresponding GdkWindow. We handle events with window=None
1391 * specially - they are generated by XFree86's XInput under
1392 * some circumstances.
1395 if ((xevent->xany.window == None) &&
1396 gdk_input_vtable.window_none_event)
1398 return_val = gdk_input_vtable.window_none_event (event,xevent);
1400 if (return_val >= 0) /* was handled */
1406 window = gdk_window_lookup (xevent->xany.window);
1407 window_private = (GdkWindowPrivate *) window;
1409 /* We do a "manual" conversion of the XEvent to a
1410 * GdkEvent. The structures are mostly the same so
1411 * the conversion is fairly straightforward. We also
1412 * optionally print debugging info regarding events
1416 * During drag & drop you get events where the pointer is
1417 * in other windows. Need to just do finer-grained checking
1419 switch (xevent->type)
1422 /* Lookup the string corresponding to the given keysym.
1424 charcount = XLookupString (&xevent->xkey, buf, 16,
1425 (KeySym*) &event->key.keyval,
1428 /* Print debugging info.
1430 if (gdk_show_events)
1431 g_print ("key press:\t\twindow: %ld key: %12s %d\n",
1432 xevent->xkey.window - base_id,
1433 XKeysymToString (event->key.keyval),
1436 event->key.type = GDK_KEY_PRESS;
1437 event->key.window = window;
1438 event->key.time = xevent->xkey.time;
1439 event->key.state = (GdkModifierType) xevent->xkey.state;
1441 return_val = !window_private->destroyed;
1445 /* Lookup the string corresponding to the given keysym.
1447 charcount = XLookupString (&xevent->xkey, buf, 16,
1448 (KeySym*) &event->key.keyval,
1451 /* Print debugging info.
1453 if (gdk_show_events)
1454 g_print ("key release:\t\twindow: %ld key: %12s %d\n",
1455 xevent->xkey.window - base_id,
1456 XKeysymToString (event->key.keyval),
1459 event->key.type = GDK_KEY_RELEASE;
1460 event->key.window = window;
1461 event->key.time = xevent->xkey.time;
1462 event->key.state = (GdkModifierType) xevent->xkey.state;
1464 return_val = !window_private->destroyed;
1468 /* Print debugging info.
1470 if (gdk_show_events)
1471 g_print ("button press[%d]:\t\twindow: %ld x,y: %d %d button: %d\n",
1472 window_private?window_private->dnd_drag_enabled:0,
1473 xevent->xbutton.window - base_id,
1474 xevent->xbutton.x, xevent->xbutton.y,
1475 xevent->xbutton.button);
1477 if (window_private &&
1478 (window_private->extension_events != 0) &&
1479 gdk_input_ignore_core)
1482 event->button.type = GDK_BUTTON_PRESS;
1483 event->button.window = window;
1484 event->button.time = xevent->xbutton.time;
1485 event->button.x = xevent->xbutton.x;
1486 event->button.y = xevent->xbutton.y;
1487 event->button.pressure = 0.5;
1488 event->button.xtilt = 0;
1489 event->button.ytilt = 0;
1490 event->button.state = (GdkModifierType) xevent->xbutton.state;
1491 event->button.button = xevent->xbutton.button;
1492 event->button.source = GDK_SOURCE_MOUSE;
1493 event->button.deviceid = GDK_CORE_POINTER;
1495 if ((event->button.time < (button_click_time[1] + TRIPLE_CLICK_TIME)) &&
1496 (event->button.window == button_window[1]) &&
1497 (event->button.button == button_number[1]))
1499 gdk_synthesize_click (event, 3);
1501 button_click_time[1] = 0;
1502 button_click_time[0] = 0;
1503 button_window[1] = NULL;
1504 button_window[0] = 0;
1505 button_number[1] = -1;
1506 button_number[0] = -1;
1508 else if ((event->button.time < (button_click_time[0] + DOUBLE_CLICK_TIME)) &&
1509 (event->button.window == button_window[0]) &&
1510 (event->button.button == button_number[0]))
1512 gdk_synthesize_click (event, 2);
1514 button_click_time[1] = button_click_time[0];
1515 button_click_time[0] = event->button.time;
1516 button_window[1] = button_window[0];
1517 button_window[0] = event->button.window;
1518 button_number[1] = button_number[0];
1519 button_number[0] = event->button.button;
1523 button_click_time[1] = 0;
1524 button_click_time[0] = event->button.time;
1525 button_window[1] = NULL;
1526 button_window[0] = event->button.window;
1527 button_number[1] = -1;
1528 button_number[0] = event->button.button;
1531 && window_private->dnd_drag_enabled
1532 && !dnd_drag_perhaps
1533 && !gdk_dnd.drag_really)
1535 dnd_drag_perhaps = 1;
1536 dnd_drag_start.x = xevent->xbutton.x_root;
1537 dnd_drag_start.y = xevent->xbutton.y_root;
1538 real_sw = window_private;
1540 if(gdk_dnd.drag_startwindows)
1542 g_free(gdk_dnd.drag_startwindows);
1543 gdk_dnd.drag_startwindows = NULL;
1545 gdk_dnd.drag_numwindows = gdk_dnd.drag_really = 0;
1548 /* Set motion mask for first DnD'd window, since it
1549 will be the one that is actually dragged */
1550 XWindowAttributes dnd_winattr;
1551 XSetWindowAttributes dnd_setwinattr;
1554 /* We need to get motion events while the button is down, so
1555 we can know whether to really start dragging or not... */
1556 XGetWindowAttributes(gdk_display, (Window)window_private->xwindow,
1559 window_private->dnd_drag_savedeventmask = dnd_winattr.your_event_mask;
1560 dnd_setwinattr.event_mask =
1561 window_private->dnd_drag_eventmask = ButtonMotionMask;
1562 XChangeWindowAttributes(gdk_display, window_private->xwindow,
1563 CWEventMask, &dnd_setwinattr);
1566 return_val = window_private?(!window_private->destroyed):FALSE;
1570 /* Print debugging info.
1572 if (gdk_show_events)
1573 g_print ("button release[%d]:\twindow: %ld x,y: %d %d button: %d\n",
1574 window_private?window_private->dnd_drag_enabled:0,
1575 xevent->xbutton.window - base_id,
1576 xevent->xbutton.x, xevent->xbutton.y,
1577 xevent->xbutton.button);
1579 if (window_private &&
1580 (window_private->extension_events != 0) &&
1581 gdk_input_ignore_core)
1584 event->button.type = GDK_BUTTON_RELEASE;
1585 event->button.window = window;
1586 event->button.time = xevent->xbutton.time;
1587 event->button.x = xevent->xbutton.x;
1588 event->button.y = xevent->xbutton.y;
1589 event->button.pressure = 0.5;
1590 event->button.xtilt = 0;
1591 event->button.ytilt = 0;
1592 event->button.state = (GdkModifierType) xevent->xbutton.state;
1593 event->button.button = xevent->xbutton.button;
1594 event->button.source = GDK_SOURCE_MOUSE;
1595 event->button.deviceid = GDK_CORE_POINTER;
1597 if(dnd_drag_perhaps)
1599 if(gdk_dnd.drag_really)
1601 GdkPoint foo = {xevent->xbutton.x_root,
1602 xevent->xbutton.y_root};
1603 XUngrabPointer(gdk_display, CurrentTime);
1605 if(dnd_drag_target != None)
1606 gdk_dnd_drag_end(dnd_drag_target, foo);
1607 gdk_dnd.drag_really = 0;
1609 if(gdk_dnd.drag_numwindows)
1611 XSetWindowAttributes attrs;
1612 /* Reset event mask to pre-drag value, assuming event_mask
1613 doesn't change during drag */
1614 attrs.event_mask = real_sw->dnd_drag_savedeventmask;
1615 XChangeWindowAttributes(gdk_display, real_sw->xwindow,
1616 CWEventMask, &attrs);
1619 gdk_dnd.drag_numwindows = 0;
1620 if(gdk_dnd.drag_startwindows)
1622 g_free(gdk_dnd.drag_startwindows);
1623 gdk_dnd.drag_startwindows = NULL;
1629 dnd_drag_perhaps = 0;
1630 dnd_drag_start.x = dnd_drag_start.y = 0;
1631 dnd_drag_dropzone.x = dnd_drag_dropzone.y = 0;
1632 dnd_drag_dropzone.width = dnd_drag_dropzone.height = 0;
1633 dnd_drag_curwin = None;
1635 return_val = window ? (!window_private->destroyed) : FALSE;
1639 /* Print debugging info.
1641 if (gdk_show_events)
1642 g_print ("motion notify:\t\twindow: %ld x,y: %d %d hint: %s d:%d r%d\n",
1643 xevent->xmotion.window - base_id,
1644 xevent->xmotion.x, xevent->xmotion.y,
1645 (xevent->xmotion.is_hint) ? "true" : "false",
1646 dnd_drag_perhaps, gdk_dnd.drag_really);
1648 if (window_private &&
1649 (window_private->extension_events != 0) &&
1650 gdk_input_ignore_core)
1653 event->motion.type = GDK_MOTION_NOTIFY;
1654 event->motion.window = window;
1655 event->motion.time = xevent->xmotion.time;
1656 event->motion.x = xevent->xmotion.x;
1657 event->motion.y = xevent->xmotion.y;
1658 event->motion.pressure = 0.5;
1659 event->motion.xtilt = 0;
1660 event->motion.ytilt = 0;
1661 event->motion.state = (GdkModifierType) xevent->xmotion.state;
1662 event->motion.is_hint = xevent->xmotion.is_hint;
1663 event->motion.source = GDK_SOURCE_MOUSE;
1664 event->motion.deviceid = GDK_CORE_POINTER;
1666 #define IS_IN_ZONE(cx, cy) (cx >= dnd_drag_dropzone.x \
1667 && cy >= dnd_drag_dropzone.y \
1668 && cx < (dnd_drag_dropzone.x + dnd_drag_dropzone.width) \
1669 && cy < (dnd_drag_dropzone.y + dnd_drag_dropzone.height))
1671 if(dnd_drag_perhaps && gdk_dnd.drag_really)
1673 /* First, we have to find what window the motion was in... */
1674 /* XXX there has to be a better way to do this, perhaps with
1675 XTranslateCoordinates or XQueryTree - I don't know how,
1676 and this sort of works */
1677 Window curwin, childwin = gdk_root_window, rootwinret;
1680 while(childwin != None)
1683 XQueryPointer(gdk_display, curwin, &rootwinret, &childwin,
1684 &x, &y, &x, &y, &mask);
1686 if(curwin != dnd_drag_curwin)
1688 /* We have left one window and entered another
1689 (do leave & enter bits) */
1690 if(dnd_drag_curwin != real_sw->xwindow && dnd_drag_curwin != None)
1691 gdk_dnd_drag_leave(dnd_drag_curwin);
1692 dnd_drag_curwin = curwin;
1693 gdk_dnd_drag_enter(dnd_drag_curwin);
1694 dnd_drag_dropzone.x = dnd_drag_dropzone.y = 0;
1695 dnd_drag_dropzone.width = dnd_drag_dropzone.height = 0;
1696 dnd_drag_target = None;
1697 XChangeActivePointerGrab(gdk_display,
1699 ButtonPressMask | ButtonReleaseMask |
1700 EnterWindowMask | LeaveWindowMask,
1701 gdk_dnd.gdk_cursor_dragdefault,
1704 else if(dnd_drag_dropzone.width > 0
1705 && dnd_drag_dropzone.height > 0)
1707 /* Handle all that dropzone stuff - thanks John ;-) */
1708 if(dnd_drag_target != None
1709 && IS_IN_ZONE(dnd_drag_oldpos.x, dnd_drag_oldpos.y)
1710 && !IS_IN_ZONE(xevent->xmotion.x_root,
1711 xevent->xmotion.y_root))
1713 /* We were in the drop zone and moved out */
1714 dnd_drag_target = None;
1715 gdk_dnd_drag_leave(curwin);
1719 /* We were outside drop zone but in the window
1720 - have to send enter events */
1721 gdk_dnd_drag_enter(curwin);
1722 dnd_drag_curwin = curwin;
1723 dnd_drag_dropzone.x = dnd_drag_dropzone.y = 0;
1724 dnd_drag_target = None;
1727 dnd_drag_curwin = None;
1731 return_val = window?(!window_private->destroyed):FALSE;
1735 /* Print debugging info.
1737 if (gdk_show_events)
1738 g_print ("enter notify:\t\twindow: %ld detail: %d subwin: %ld\n",
1739 xevent->xcrossing.window - base_id,
1740 xevent->xcrossing.detail,
1741 xevent->xcrossing.subwindow - base_id);
1743 /* Tell XInput stuff about it if appropriate */
1744 if (window_private &&
1745 (window_private->extension_events != 0) &&
1746 gdk_input_vtable.enter_event)
1747 gdk_input_vtable.enter_event (&xevent->xcrossing, window);
1749 event->crossing.type = GDK_ENTER_NOTIFY;
1750 event->crossing.window = window;
1752 /* If the subwindow field of the XEvent is non-NULL, then
1753 * lookup the corresponding GdkWindow.
1755 if (xevent->xcrossing.subwindow != None)
1756 event->crossing.subwindow = gdk_window_lookup (xevent->xcrossing.subwindow);
1758 event->crossing.subwindow = NULL;
1760 /* Translate the crossing detail into Gdk terms.
1762 switch (xevent->xcrossing.detail)
1764 case NotifyInferior:
1765 event->crossing.detail = GDK_NOTIFY_INFERIOR;
1767 case NotifyAncestor:
1768 event->crossing.detail = GDK_NOTIFY_ANCESTOR;
1771 event->crossing.detail = GDK_NOTIFY_VIRTUAL;
1773 case NotifyNonlinear:
1774 event->crossing.detail = GDK_NOTIFY_NONLINEAR;
1776 case NotifyNonlinearVirtual:
1777 event->crossing.detail = GDK_NOTIFY_NONLINEAR_VIRTUAL;
1780 event->crossing.detail = GDK_NOTIFY_UNKNOWN;
1785 && gdk_dnd.drag_really
1786 && xevent->xcrossing.window == real_sw->xwindow)
1788 gdk_dnd.drag_really = 0;
1789 XUngrabPointer(gdk_display, CurrentTime);
1792 return_val = (window ? !window_private->destroyed : FALSE);
1796 /* Print debugging info.
1798 if (gdk_show_events)
1799 g_print ("leave notify:\t\twindow: %ld detail: %d subwin: %ld\n",
1800 xevent->xcrossing.window - base_id,
1801 xevent->xcrossing.detail, xevent->xcrossing.subwindow - base_id);
1803 event->crossing.type = GDK_LEAVE_NOTIFY;
1804 event->crossing.window = window;
1806 /* Translate the crossing detail into Gdk terms.
1808 switch (xevent->xcrossing.detail)
1810 case NotifyInferior:
1811 event->crossing.detail = GDK_NOTIFY_INFERIOR;
1813 case NotifyAncestor:
1814 event->crossing.detail = GDK_NOTIFY_ANCESTOR;
1817 event->crossing.detail = GDK_NOTIFY_VIRTUAL;
1819 case NotifyNonlinear:
1820 event->crossing.detail = GDK_NOTIFY_NONLINEAR;
1822 case NotifyNonlinearVirtual:
1823 event->crossing.detail = GDK_NOTIFY_NONLINEAR_VIRTUAL;
1826 event->crossing.detail = GDK_NOTIFY_UNKNOWN;
1830 && !gdk_dnd.drag_really)
1832 gdk_dnd_drag_addwindow((GdkWindow *) real_sw);
1833 gdk_dnd_drag_begin((GdkWindow *) real_sw);
1834 XGrabPointer(gdk_display, real_sw->xwindow, False,
1836 ButtonPressMask | ButtonReleaseMask |
1837 EnterWindowMask | LeaveWindowMask,
1838 GrabModeAsync, GrabModeAsync, gdk_root_window,
1839 gdk_dnd.gdk_cursor_dragdefault, CurrentTime);
1840 gdk_dnd.drag_really = 1;
1842 return_val = window ? (!window_private->destroyed) : FALSE;
1846 /* Print debugging info.
1848 if (gdk_show_events)
1849 g_print ("focus in:\t\twindow: %ld\n",
1850 xevent->xfocus.window - base_id);
1852 event->focus_change.type = GDK_FOCUS_CHANGE;
1853 event->focus_change.window = window;
1854 event->focus_change.in = TRUE;
1856 return_val = !window_private->destroyed;
1860 /* Print debugging info.
1862 if (gdk_show_events)
1863 g_print ("focus out:\t\twindow: %ld\n",
1864 xevent->xfocus.window - base_id);
1866 event->focus_change.type = GDK_FOCUS_CHANGE;
1867 event->focus_change.window = window;
1868 event->focus_change.in = FALSE;
1870 return_val = !window_private->destroyed;
1874 /* Print debugging info.
1876 if (gdk_show_events)
1877 g_print ("keymap notify\n");
1879 /* Not currently handled */
1883 /* Print debugging info.
1885 if (gdk_show_events)
1886 g_print ("expose:\t\twindow: %ld %d x,y: %d %d w,h: %d %d\n",
1887 xevent->xexpose.window - base_id, xevent->xexpose.count,
1888 xevent->xexpose.x, xevent->xexpose.y,
1889 xevent->xexpose.width, xevent->xexpose.height);
1891 event->expose.type = GDK_EXPOSE;
1892 event->expose.window = window;
1893 event->expose.area.x = xevent->xexpose.x;
1894 event->expose.area.y = xevent->xexpose.y;
1895 event->expose.area.width = xevent->xexpose.width;
1896 event->expose.area.height = xevent->xexpose.height;
1897 event->expose.count = xevent->xexpose.count;
1899 return_val = !window_private->destroyed;
1902 case GraphicsExpose:
1903 /* Print debugging info.
1905 if (gdk_show_events)
1906 g_print ("graphics expose:\tdrawable: %ld\n",
1907 xevent->xgraphicsexpose.drawable - base_id);
1909 event->expose.type = GDK_EXPOSE;
1910 event->expose.window = window;
1911 event->expose.area.x = xevent->xgraphicsexpose.x;
1912 event->expose.area.y = xevent->xgraphicsexpose.y;
1913 event->expose.area.width = xevent->xgraphicsexpose.width;
1914 event->expose.area.height = xevent->xgraphicsexpose.height;
1915 event->expose.count = xevent->xexpose.count;
1917 return_val = !window_private->destroyed;
1921 /* Print debugging info.
1923 if (gdk_show_events)
1924 g_print ("no expose:\t\tdrawable: %ld\n",
1925 xevent->xnoexpose.drawable - base_id);
1927 /* Not currently handled */
1930 case VisibilityNotify:
1931 /* Print debugging info.
1933 if (gdk_show_events)
1934 switch (xevent->xvisibility.state)
1936 case VisibilityFullyObscured:
1937 g_print ("visibility notify:\twindow: %ld none\n",
1938 xevent->xvisibility.window - base_id);
1940 case VisibilityPartiallyObscured:
1941 g_print ("visibility notify:\twindow: %ld partial\n",
1942 xevent->xvisibility.window - base_id);
1944 case VisibilityUnobscured:
1945 g_print ("visibility notify:\twindow: %ld full\n",
1946 xevent->xvisibility.window - base_id);
1950 /* Not currently handled */
1954 /* Not currently handled */
1958 /* Print debugging info.
1960 if (gdk_show_events)
1961 g_print ("destroy notify:\twindow: %ld\n",
1962 xevent->xdestroywindow.window - base_id);
1964 event->any.type = GDK_DESTROY;
1965 event->any.window = window;
1967 /* Remeber which window received the destroy notify
1968 * event so that we can destroy our associated
1969 * data structures the next time the user asks
1972 received_destroy_notify = TRUE;
1973 window_to_destroy = window;
1975 return_val = !window_private->destroyed;
1979 /* Print debugging info.
1981 if (gdk_show_events)
1982 g_print ("unmap notify:\t\twindow: %ld\n",
1983 xevent->xmap.window - base_id);
1985 event->any.type = GDK_UNMAP;
1986 event->any.window = window;
1988 return_val = !window_private->destroyed;
1992 /* Print debugging info.
1994 if (gdk_show_events)
1995 g_print ("map notify:\t\twindow: %ld\n",
1996 xevent->xmap.window - base_id);
1998 event->any.type = GDK_MAP;
1999 event->any.window = window;
2001 return_val = !window_private->destroyed;
2004 case ReparentNotify:
2005 /* Print debugging info.
2007 if (gdk_show_events)
2008 g_print ("reparent notify:\twindow: %ld\n",
2009 xevent->xreparent.window - base_id);
2011 /* Not currently handled */
2014 case ConfigureNotify:
2015 /* Print debugging info.
2017 while ((XPending(gdk_display) > 0) &&
2018 XCheckTypedWindowEvent(gdk_display, xevent->xany.window,
2019 ConfigureNotify, xevent))
2020 /*XSync(gdk_display, 0)*/;
2022 if (gdk_show_events)
2023 g_print ("configure notify:\twindow: %ld x,y: %d %d w,h: %d %d\n",
2024 xevent->xconfigure.window - base_id,
2025 xevent->xconfigure.x, xevent->xconfigure.y,
2026 xevent->xconfigure.width, xevent->xconfigure.height);
2028 if (window_private &&
2029 (window_private->extension_events != 0) &&
2030 gdk_input_vtable.configure_event)
2031 gdk_input_vtable.configure_event (&xevent->xconfigure, window);
2033 if ((window_private->window_type != GDK_WINDOW_CHILD) &&
2034 ((window_private->width != xevent->xconfigure.width) ||
2035 (window_private->height != xevent->xconfigure.height)))
2037 event->configure.type = GDK_CONFIGURE;
2038 event->configure.window = window;
2039 event->configure.x = xevent->xconfigure.x;
2040 event->configure.y = xevent->xconfigure.y;
2041 event->configure.width = xevent->xconfigure.width;
2042 event->configure.height = xevent->xconfigure.height;
2044 window_private->x = xevent->xconfigure.x;
2045 window_private->y = xevent->xconfigure.y;
2046 window_private->width = xevent->xconfigure.width;
2047 window_private->height = xevent->xconfigure.height;
2048 if (window_private->resize_count > 1)
2049 window_private->resize_count -= 1;
2051 return_val = !window_private->destroyed;
2055 case PropertyNotify:
2056 /* Print debugging info.
2058 if (gdk_show_events)
2059 g_print ("property notify:\twindow: %ld\n",
2060 xevent->xproperty.window - base_id);
2062 event->property.type = GDK_PROPERTY_NOTIFY;
2063 event->property.window = window;
2064 event->property.atom = xevent->xproperty.atom;
2065 event->property.time = xevent->xproperty.time;
2066 event->property.state = xevent->xproperty.state;
2068 return_val = !window_private->destroyed;
2071 case SelectionClear:
2072 if (gdk_show_events)
2073 g_print ("selection clear:\twindow: %ld\n",
2074 xevent->xproperty.window - base_id);
2076 event->selection.type = GDK_SELECTION_CLEAR;
2077 event->selection.window = window;
2078 event->selection.selection = xevent->xselectionclear.selection;
2079 event->selection.time = xevent->xselectionclear.time;
2081 return_val = !((GdkWindowPrivate*) window)->destroyed;
2084 case SelectionRequest:
2085 if (gdk_show_events)
2086 g_print ("selection request:\twindow: %ld\n",
2087 xevent->xproperty.window - base_id);
2089 event->selection.type = GDK_SELECTION_REQUEST;
2090 event->selection.window = window;
2091 event->selection.selection = xevent->xselectionrequest.selection;
2092 event->selection.target = xevent->xselectionrequest.target;
2093 event->selection.property = xevent->xselectionrequest.property;
2094 event->selection.requestor = xevent->xselectionrequest.requestor;
2095 event->selection.time = xevent->xselectionrequest.time;
2097 return_val = !((GdkWindowPrivate*) window)->destroyed;
2100 case SelectionNotify:
2101 if (gdk_show_events)
2102 g_print ("selection notify:\twindow: %ld\n",
2103 xevent->xproperty.window - base_id);
2106 event->selection.type = GDK_SELECTION_NOTIFY;
2107 event->selection.window = window;
2108 event->selection.selection = xevent->xselection.selection;
2109 event->selection.target = xevent->xselection.target;
2110 event->selection.property = xevent->xselection.property;
2111 event->selection.time = xevent->xselection.time;
2113 return_val = !((GdkWindowPrivate*) window)->destroyed;
2116 case ColormapNotify:
2117 /* Print debugging info.
2119 if (gdk_show_events)
2120 g_print ("colormap notify:\twindow: %ld\n",
2121 xevent->xcolormap.window - base_id);
2123 /* Not currently handled */
2127 /* Print debugging info.
2129 if (gdk_show_events)
2130 g_print ("client message:\twindow: %ld\n",
2131 xevent->xclient.window - base_id);
2133 /* Client messages are the means of the window manager
2134 * communicating with a program. We'll first check to
2135 * see if this is really the window manager talking
2138 if (xevent->xclient.message_type == gdk_wm_protocols)
2140 if ((Atom) xevent->xclient.data.l[0] == gdk_wm_delete_window)
2142 /* The delete window request specifies a window
2143 * to delete. We don't actually destroy the
2144 * window because "it is only a request". (The
2145 * window might contain vital data that the
2146 * program does not want destroyed). Instead
2147 * the event is passed along to the program,
2148 * which should then destroy the window.
2151 /* Print debugging info.
2153 if (gdk_show_events)
2154 g_print ("delete window:\t\twindow: %ld\n",
2155 xevent->xclient.window - base_id);
2157 event->any.type = GDK_DELETE;
2158 event->any.window = window;
2160 return_val = !window_private->destroyed;
2162 else if ((Atom) xevent->xclient.data.l[0] == gdk_wm_take_focus)
2166 else if (xevent->xclient.message_type == gdk_dnd.gdk_XdeEnter)
2170 event->dropenter.u.allflags = xevent->xclient.data.l[1];
2171 if (gdk_show_events)
2172 g_print ("GDK_DROP_ENTER\n");
2175 /* Now figure out if we really want this drop...
2176 * If someone is trying funky clipboard stuff, ignore
2179 && window_private->dnd_drop_enabled
2180 && event->dropenter.u.flags.sendreply
2181 && (reptype = gdk_dnd_check_types (window, xevent)))
2185 replyev.xclient.type = ClientMessage;
2186 replyev.xclient.window = xevent->xclient.data.l[0];
2187 replyev.xclient.format = 32;
2188 replyev.xclient.message_type = gdk_dnd.gdk_XdeRequest;
2189 replyev.xclient.data.l[0] = window_private->xwindow;
2191 event->dragrequest.u.allflags = 0;
2192 event->dragrequest.u.flags.protocol_version =
2193 DND_PROTOCOL_VERSION;
2194 event->dragrequest.u.flags.willaccept = 1;
2195 event->dragrequest.u.flags.delete_data =
2196 (window_private->dnd_drop_destructive_op) ? 1 : 0;
2198 replyev.xclient.data.l[1] = event->dragrequest.u.allflags;
2199 replyev.xclient.data.l[2] = replyev.xclient.data.l[3] = 0;
2200 replyev.xclient.data.l[4] = reptype;
2202 XSendEvent (gdk_display, replyev.xclient.window,
2203 False, NoEventMask, &replyev);
2205 event->any.type = GDK_DROP_ENTER;
2206 event->dropenter.requestor = replyev.xclient.window;
2207 event->dropenter.u.allflags = xevent->xclient.data.l[1];
2210 else if (xevent->xclient.message_type == gdk_dnd.gdk_XdeLeave)
2212 if (gdk_show_events)
2213 g_print ("GDK_DROP_LEAVE\n");
2214 if (window_private && window_private->dnd_drop_enabled)
2216 event->dropleave.type = GDK_DROP_LEAVE;
2217 event->dropleave.window = window;
2218 event->dropleave.requestor = xevent->xclient.data.l[0];
2219 event->dropleave.u.allflags = xevent->xclient.data.l[1];
2225 else if (xevent->xclient.message_type == gdk_dnd.gdk_XdeRequest)
2228 * make sure to only handle requests from the window the cursor is
2231 if (gdk_show_events)
2232 g_print ("GDK_DRAG_REQUEST\n");
2233 event->dragrequest.u.allflags = xevent->xclient.data.l[1];
2236 if (window && gdk_dnd.drag_really &&
2237 xevent->xclient.data.l[0] == dnd_drag_curwin &&
2238 event->dragrequest.u.flags.sendreply == 0)
2240 /* Got request - do we need to ask user? */
2241 if (!event->dragrequest.u.flags.willaccept
2242 && event->dragrequest.u.flags.senddata)
2245 event->dragrequest.type = GDK_DRAG_REQUEST;
2246 event->dragrequest.window = window;
2247 event->dragrequest.requestor = xevent->xclient.data.l[0];
2248 event->dragrequest.isdrop = 0;
2249 event->dragrequest.drop_coords.x =
2250 event->dragrequest.drop_coords.y = 0;
2253 else if (event->dragrequest.u.flags.willaccept)
2255 window_private->dnd_drag_destructive_op =
2256 event->dragrequest.u.flags.delete_data;
2257 window_private->dnd_drag_accepted = 1;
2258 window_private->dnd_drag_data_type =
2259 xevent->xclient.data.l[4];
2261 dnd_drag_target = dnd_drag_curwin;
2262 XChangeActivePointerGrab (gdk_display,
2266 EnterWindowMask | LeaveWindowMask,
2267 gdk_dnd.gdk_cursor_dragok,
2270 dnd_drag_dropzone.x = xevent->xclient.data.l[2] & 65535;
2271 dnd_drag_dropzone.y =
2272 (xevent->xclient.data.l[2] >> 16) & 65535;
2273 dnd_drag_dropzone.width = xevent->xclient.data.l[3] & 65535;
2274 dnd_drag_dropzone.height =
2275 (xevent->xclient.data.l[3] >> 16) & 65535;
2278 else if(xevent->xclient.message_type == gdk_dnd.gdk_XdeDataAvailable)
2280 gint tmp_int; Atom tmp_atom;
2282 guchar *tmp_charptr;
2286 g_print("GDK_DROP_DATA_AVAIL\n");
2287 event->dropdataavailable.u.allflags = xevent->xclient.data.l[1];
2289 /* No preview of data ATM */
2290 && event->dropdataavailable.u.flags.isdrop)
2292 event->dropdataavailable.type = GDK_DROP_DATA_AVAIL;
2293 event->dropdataavailable.window = window;
2294 event->dropdataavailable.requestor = xevent->xclient.data.l[0];
2295 event->dropdataavailable.data_type =
2296 gdk_atom_name(xevent->xclient.data.l[2]);
2297 if(XGetWindowProperty (gdk_display,
2298 event->dropdataavailable.requestor,
2299 xevent->xclient.data.l[2],
2301 False, XA_PRIMARY, &tmp_atom,
2303 &event->dropdataavailable.data_numbytes,
2308 g_warning("XGetWindowProperty on %#x may have failed\n",
2309 event->dropdataavailable.requestor);
2310 event->dropdataavailable.data = NULL;
2314 g_print("XGetWindowProperty got us %d bytes\n",
2315 event->dropdataavailable.data_numbytes);
2316 event->dropdataavailable.data =
2317 g_malloc(event->dropdataavailable.data_numbytes);
2318 memcpy(event->dropdataavailable.data,
2319 tmp_charptr, event->dropdataavailable.data_numbytes);
2326 /* Send unknown ClientMessage's on to Gtk for it to use */
2327 event->client.type = GDK_CLIENT_EVENT;
2328 event->client.window = window;
2329 event->client.message_type = xevent->xclient.message_type;
2330 event->client.data_format = xevent->xclient.format;
2331 memcpy(&event->client.data, &xevent->xclient.data,
2332 sizeof(event->client.data));
2335 return_val = return_val && !window_private->destroyed;
2339 /* Print debugging info.
2341 if (gdk_show_events)
2342 g_print ("mapping notify\n");
2344 /* Let XLib know that there is a new keyboard mapping.
2346 XRefreshKeyboardMapping (&xevent->xmapping);
2350 /* something else - (e.g., a Xinput event) */
2352 if (window_private &&
2353 (window_private->extension_events != 0) &&
2354 gdk_input_vtable.other_event)
2355 return_val = gdk_input_vtable.other_event(event, xevent, window);
2357 if (return_val < 0) /* not an XInput event, convert */
2359 event->other.type = GDK_OTHER_EVENT;
2360 event->other.window = window;
2361 event->other.xevent = &other_xevent[other_xevent_i];
2362 memcpy (&other_xevent[other_xevent_i], xevent, sizeof (XEvent));
2363 other_xevent_i = (other_xevent_i+1) % OTHER_XEVENT_BUFSIZE;
2367 return_val = return_val && !window_private->destroyed;
2375 gdk_event_get_type (Display *display,
2382 if (gdk_event_translate (&event, xevent))
2384 pred = (GdkPredicate*) arg;
2385 return (* pred->func) (&event, pred->data);
2392 gdk_synthesize_click (GdkEvent *event,
2395 GdkEvent temp_event;
2397 g_return_if_fail (event != NULL);
2399 temp_event = *event;
2400 temp_event.type = (nclicks == 2) ? GDK_2BUTTON_PRESS : GDK_3BUTTON_PRESS;
2402 gdk_event_put (&temp_event);
2406 *--------------------------------------------------------------
2409 * This is the "atexit" function that makes sure the
2410 * library gets a chance to cleanup.
2417 * The library is un-initialized and the program exits.
2419 *--------------------------------------------------------------
2429 gdk_key_repeat_restore ();
2431 XCloseDisplay (gdk_display);
2437 *--------------------------------------------------------------
2440 * The X error handling routine.
2443 * "display" is the X display the error orignated from.
2444 * "error" is the XErrorEvent that we are handling.
2447 * Either we were expecting some sort of error to occur,
2448 * in which case we set the "gdk_error_code" flag, or this
2449 * error was unexpected, in which case we will print an
2450 * error message and exit. (Since trying to continue will
2451 * most likely simply lead to more errors).
2455 *--------------------------------------------------------------
2459 gdk_x_error (Display *display,
2464 if (gdk_error_warnings)
2466 XGetErrorText (display, error->error_code, buf, 63);
2467 g_error ("%s", buf);
2470 gdk_error_code = -1;
2475 *--------------------------------------------------------------
2478 * The X I/O error handling routine.
2481 * "display" is the X display the error orignated from.
2484 * An X I/O error basically means we lost our connection
2485 * to the X server. There is not much we can do to
2486 * continue, so simply print an error message and exit.
2490 *--------------------------------------------------------------
2494 gdk_x_io_error (Display *display)
2496 g_error ("an x io error occurred");
2501 *--------------------------------------------------------------
2504 * The signal handler.
2507 * "sig_num" is the number of the signal we received.
2510 * The signals we catch are all fatal. So we simply build
2511 * up a nice little error message and print it and exit.
2512 * If in the process of doing so another signal is received
2513 * we notice that we are already exiting and simply kill
2518 *--------------------------------------------------------------
2522 gdk_signal (int sig_num)
2524 static int caught_fatal_sig = 0;
2527 if (caught_fatal_sig)
2528 kill (getpid (), sig_num);
2529 caught_fatal_sig = 1;
2555 sig = "unknown signal";
2559 g_print ("\n** ERROR **: %s caught\n", sig);
2564 gdk_dnd_drag_begin (GdkWindow *initial_window)
2566 GdkEventDragBegin tev;
2567 tev.type = GDK_DRAG_BEGIN;
2568 tev.window = initial_window;
2570 tev.u.flags.protocol_version = DND_PROTOCOL_VERSION;
2572 gdk_event_put ((GdkEvent *) &tev);
2576 gdk_dnd_drag_enter (Window dest)
2579 GdkEventDropEnter tev;
2581 GdkWindowPrivate *wp;
2583 sev.xclient.type = ClientMessage;
2584 sev.xclient.format = 32;
2585 sev.xclient.message_type = gdk_dnd.gdk_XdeEnter;
2586 sev.xclient.window = dest;
2589 tev.u.flags.protocol_version = DND_PROTOCOL_VERSION;
2590 tev.u.flags.sendreply = 1;
2591 for (i = 0; i < gdk_dnd.drag_numwindows; i++)
2593 wp = (GdkWindowPrivate *) gdk_dnd.drag_startwindows[i];
2594 if (wp->dnd_drag_data_numtypesavail)
2596 sev.xclient.data.l[0] = wp->xwindow;
2597 tev.u.flags.extended_typelist = (wp->dnd_drag_data_numtypesavail > 3)?1:0;
2598 sev.xclient.data.l[1] = tev.u.allflags;
2599 sev.xclient.data.l[2] = wp->dnd_drag_data_typesavail[0];
2600 if (wp->dnd_drag_data_numtypesavail > 1)
2602 sev.xclient.data.l[3] = wp->dnd_drag_data_typesavail[1];
2603 if (wp->dnd_drag_data_numtypesavail > 2)
2605 sev.xclient.data.l[4] = wp->dnd_drag_data_typesavail[2];
2608 sev.xclient.data.l[4] = None;
2611 sev.xclient.data.l[3] = sev.xclient.data.l[4] = None;
2612 XSendEvent (gdk_display, dest, False, NoEventMask, &sev);
2619 gdk_dnd_drag_leave (Window dest)
2622 GdkEventDropLeave tev;
2624 GdkWindowPrivate *wp;
2628 tev.u.flags.protocol_version = DND_PROTOCOL_VERSION;
2629 sev.xclient.type = ClientMessage;
2630 sev.xclient.window = dest;
2631 sev.xclient.format = 32;
2632 sev.xclient.message_type = gdk_dnd.gdk_XdeLeave;
2633 sev.xclient.data.l[1] = tev.u.allflags;
2634 for (i = 0; i < gdk_dnd.drag_numwindows; i++)
2636 wp = (GdkWindowPrivate *) gdk_dnd.drag_startwindows[i];
2637 sev.xclient.data.l[0] = wp->xwindow;
2638 XSendEvent(gdk_display, dest, False, NoEventMask, &sev);
2639 wp->dnd_drag_accepted = 0;
2644 * when a drop occurs, we go through the list of windows being dragged and
2645 * tell them that it has occurred, so that they can set things up and reply
2649 gdk_dnd_drag_end (Window dest,
2652 GdkWindowPrivate *wp;
2653 GdkEventDragRequest tev;
2657 tev.type = GDK_DRAG_REQUEST;
2658 tev.drop_coords = coords;
2659 tev.requestor = dest;
2661 tev.u.flags.protocol_version = DND_PROTOCOL_VERSION;
2664 for (i = 0; i < gdk_dnd.drag_numwindows; i++)
2666 wp = (GdkWindowPrivate *) gdk_dnd.drag_startwindows[i];
2667 if (wp->dnd_drag_accepted)
2669 tev.window = (GdkWindow *) wp;
2670 tev.u.flags.delete_data = wp->dnd_drag_destructive_op;
2672 gdk_atom_name(wp->dnd_drag_data_type);
2674 gdk_event_put((GdkEvent *) &tev);
2680 gdk_dnd_check_types (GdkWindow *window,
2683 GdkWindowPrivate *wp = (GdkWindowPrivate *) window;
2685 GdkEventDropEnter event;
2687 g_return_val_if_fail(window != NULL, 0);
2688 g_return_val_if_fail(xevent != NULL, 0);
2689 g_return_val_if_fail(xevent->type == ClientMessage, 0);
2690 g_return_val_if_fail(xevent->xclient.message_type == gdk_dnd.gdk_XdeEnter, 0);
2692 if(wp->dnd_drop_data_numtypesavail <= 0 ||
2693 !wp->dnd_drop_data_typesavail)
2696 for (i = 2; i <= 4; i++)
2698 for (j = 0; j < wp->dnd_drop_data_numtypesavail; j++)
2700 if (xevent->xclient.data.l[i] == wp->dnd_drop_data_typesavail[j])
2701 return xevent->xclient.data.l[i];
2705 /* Now we get the extended type list if it's available */
2706 event.u.allflags = xevent->xclient.data.l[1];
2707 if (event.u.flags.extended_typelist)
2709 Atom *exttypes, realtype;
2710 gulong nitems, nbar;
2713 if (XGetWindowProperty(gdk_display, xevent->xclient.data.l[0],
2714 gdk_dnd.gdk_XdeTypelist, 0L, LONG_MAX - 1,
2715 False, AnyPropertyType, &realtype, &realfmt,
2716 &nitems, &nbar, (unsigned char **) &exttypes)
2720 if (realfmt != (sizeof(Atom) * 8))
2722 g_warning("XdeTypelist property had format of %d instead of the expected %d, on window %#lx\n",
2723 realfmt, sizeof(Atom) * 8, xevent->xclient.data.l[0]);
2727 for (i = 0; i <= nitems; i++)
2729 for (j = 0; j < wp->dnd_drop_data_numtypesavail; j++)
2731 if (exttypes[i] == wp->dnd_drop_data_typesavail[j])
2744 * used for debugging only
2747 gdk_print_atom (GdkAtom anatom)
2749 gchar *tmpstr = NULL;
2750 tmpstr = (anatom!=None)?gdk_atom_name(anatom):"(none)";
2751 g_print("Atom %lu has name %s\n", anatom, tmpstr);
2757 * used only by below routine and itself
2760 getchildren (Display *dpy,
2764 Window root, parent, *children, inf = 0;
2766 unsigned int nchildren, i;
2768 unsigned long nitems, after;
2769 unsigned char *data;
2771 if (XQueryTree(dpy, win, &root, &parent, &children, &nchildren) == 0)
2774 for (i = 0; !inf && (i < nchildren); i++)
2776 XGetWindowProperty (dpy, children[i], WM_STATE, 0, 0, False,
2777 AnyPropertyType, &type, &format, &nitems,
2783 for (i = 0; !inf && (i < nchildren); i++)
2784 inf = getchildren (dpy, children[i], WM_STATE);
2787 XFree ((char *) children);
2793 * find a window with WM_STATE, else return win itself, as per ICCCM
2795 * modification of the XmuClientWindow() routine from X11R6.3
2798 gdk_get_client_window (Display *dpy,
2804 unsigned long nitems, after;
2805 unsigned char *data;
2809 return DefaultRootWindow(dpy);
2811 if ((WM_STATE = XInternAtom (dpy, "WM_STATE", True)) == 0)
2814 XGetWindowProperty (dpy, win, WM_STATE, 0, 0, False, AnyPropertyType,
2815 &type, &format, &nitems, &after, &data);
2819 inf = getchildren (dpy, win, WM_STATE);
2828 gdk_drop_get_real_window (GdkWindow *w,
2832 GdkWindow *retval = w;
2833 GdkWindowPrivate *awin;
2835 gint16 myx = *x, myy = *y;
2837 g_return_val_if_fail(w != NULL && x != NULL && y != NULL, NULL);
2843 for (children = gdk_window_get_children(retval);
2844 children && children->next;
2845 children = children->next)
2847 awin = (GdkWindowPrivate *) children->data;
2848 if ((myx >= awin->x) && (myy >= awin->y)
2849 && (myx < (awin->x + awin->width))
2850 && (myy < (awin->y + awin->height)))
2852 retval = (GdkWindow *) awin;
2865 /* Sends a ClientMessage to all toplevel client windows */
2867 gdk_event_send_clientmessage_toall(GdkEvent *event)
2870 Window *ret_children, ret_root, ret_parent, curwin;
2871 unsigned int ret_nchildren;
2874 g_return_if_fail(event != NULL);
2876 /* Set up our event to send, with the exception of its target window */
2877 sev.xclient.type = ClientMessage;
2878 sev.xclient.display = gdk_display;
2879 sev.xclient.format = event->client.data_format;
2880 sev.xclient.serial = CurrentTime;
2881 memcpy(&sev.xclient.data, &event->client.data, sizeof(sev.xclient.data));
2882 sev.xclient.message_type = event->client.message_type;
2884 /* OK, we're all set, now let's find some windows to send this to */
2885 if(XQueryTree(gdk_display, gdk_root_window, &ret_root, &ret_parent,
2886 &ret_children, &ret_nchildren) != True)
2889 /* foreach true child window of the root window, send an event to it */
2890 for(i = 0; i < ret_nchildren; i++) {
2891 curwin = gdk_get_client_window(gdk_display, ret_children[i]);
2892 sev.xclient.window = curwin;
2893 XSendEvent(gdk_display, curwin, False, NoEventMask, &sev);
2896 XFree(ret_children);