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"
20 /* If you don't want to use gdk's signal handlers define this */
21 /* #define I_NEED_TO_ACTUALLY_DEBUG_MY_PROGRAMS 1 */
23 #include <X11/Xlocale.h>
34 #ifdef HAVE_SYS_SELECT_H
35 #include <sys/select.h>
36 #endif /* HAVE_SYS_SELECT_H_ */
38 #define XLIB_ILLEGAL_ACCESS
39 #include <X11/Xatom.h>
42 #include <X11/Xutil.h>
43 #include <X11/Xmu/WinUtil.h>
45 #include <X11/Xresource.h>
47 #include <X11/cursorfont.h>
49 #include "gdkprivate.h"
53 #include "gdkkeysyms.h"
57 #ifndef X_GETTIMEOFDAY
58 #define X_GETTIMEOFDAY(tv) gettimeofday (tv, NULL)
59 #endif /* X_GETTIMEOFDAY */
62 #define DOUBLE_CLICK_TIME 250
63 #define TRIPLE_CLICK_TIME 500
64 #define DOUBLE_CLICK_DIST 5
65 #define TRIPLE_CLICK_DIST 5
69 # define SELECT_MASK fd_set
75 # define SELECT_MASK void
77 # define SELECT_MASK int
82 typedef struct _GdkInput GdkInput;
83 typedef struct _GdkPredicate GdkPredicate;
89 GdkInputCondition condition;
90 GdkInputFunction function;
92 GdkDestroyNotify destroy;
102 * Private function declarations
105 static GdkEvent *gdk_event_new (void);
106 static gint gdk_event_wait (void);
107 static gint gdk_event_apply_filters (XEvent *xevent,
110 static gint gdk_event_translate (GdkEvent *event,
113 static Bool gdk_event_get_type (Display *display,
117 static void gdk_synthesize_click (GdkEvent *event,
120 static void gdk_dnd_drag_begin (GdkWindow *initial_window);
121 static void gdk_dnd_drag_enter (Window dest);
122 static void gdk_dnd_drag_leave (Window dest);
123 static void gdk_dnd_drag_end (Window dest,
125 static GdkAtom gdk_dnd_check_types (GdkWindow *window,
128 static void gdk_print_atom (GdkAtom anatom);
132 * old junk from offix, we might use it though so leave it
134 Window gdk_get_client_window (Display *dpy,
136 #ifdef WE_HAVE_MOTIF_DROPS_DONE
137 static GdkWindow * gdk_drop_get_real_window (GdkWindow *w,
141 static void gdk_exit_func (void);
142 static int gdk_x_error (Display *display,
144 static int gdk_x_io_error (Display *display);
145 static RETSIGTYPE gdk_signal (int signum);
149 static GdkIM gdk_im_get (void);
150 static gint gdk_im_open (XrmDatabase db,
153 static void gdk_im_close (void);
154 static void gdk_ic_cleanup (void);
157 /* Private variable declarations
159 static int initialized = 0; /* 1 if the library is initialized,
162 static int connection_number = 0; /* The file descriptor number of our
163 * connection to the X server. This
164 * is used so that we may determine
165 * when events are pending by using
166 * the "select" system call.
170 static struct timeval start; /* The time at which the library was
173 static struct timeval timer; /* Timeout interval to use in the call
174 * to "select". This is used in
175 * conjunction with "timerp" to create
176 * a maximum time to wait for an event
179 static struct timeval *timerp; /* The actual timer passed to "select"
180 * This may be NULL, in which case
181 * "select" will block until an event
184 static guint32 timer_val; /* The timeout length as specified by
185 * the user in milliseconds.
187 static GList *inputs; /* A list of the input file descriptors
188 * that we care about. Each list node
189 * contains a GdkInput struct that describes
190 * when we are interested in the specified
191 * file descriptor. That is, when it is
192 * available for read, write or has an
195 static guint32 button_click_time[2]; /* The last 2 button click times. Used
196 * to determine if the latest button click
197 * is part of a double or triple click.
199 static GdkWindow *button_window[2]; /* The last 2 windows to receive button presses.
200 * Also used to determine if the latest button
201 * click is part of a double or triple click.
203 static guint button_number[2]; /* The last 2 buttons to be pressed.
205 static GdkWindowPrivate *xgrab_window = NULL; /* Window that currently holds the
210 static gint xim_using; /* using XIM Protocol if TRUE */
211 static GdkIM xim_im; /* global IM */
212 static XIMStyles* xim_styles; /* im supports these styles */
213 static XIMStyle xim_best_allowed_style;
214 static GdkICPrivate *xim_ic; /* currently using IC */
215 static GdkWindow* xim_window; /* currently using Widow */
216 static GList* xim_ic_list;
220 #define OTHER_XEVENT_BUFSIZE 4
221 static XEvent other_xevent[OTHER_XEVENT_BUFSIZE]; /* XEvents passed along to user */
222 static int other_xevent_i = 0;
223 static GList *putback_events = NULL;
225 static gulong base_id;
226 static gint autorepeat;
228 #ifdef G_ENABLE_DEBUG
229 static GDebugKey gdk_debug_keys[] = {
230 {"events", GDK_DEBUG_EVENTS},
231 {"misc", GDK_DEBUG_MISC},
232 {"dnd", GDK_DEBUG_DND},
233 {"color-context", GDK_DEBUG_COLOR_CONTEXT},
234 {"xim", GDK_DEBUG_XIM}
237 static const int gdk_ndebug_keys = sizeof(gdk_debug_keys)/sizeof(GDebugKey);
239 #endif /* G_ENABLE_DEBUG */
242 *--------------------------------------------------------------
245 * Initialize the library for use.
248 * "argc" is the number of arguments.
249 * "argv" is an array of strings.
252 * "argc" and "argv" are modified to reflect any arguments
253 * which were not handled. (Such arguments should either
254 * be handled by the application or dismissed).
257 * The library is initialized.
259 *--------------------------------------------------------------
266 XKeyboardState keyboard_state;
269 XClassHint *class_hint;
270 int argc_orig = *argc;
273 argv_orig = malloc ((argc_orig + 1) * sizeof (char*));
274 for (i = 0; i < argc_orig; i++)
275 argv_orig[i] = g_strdup ((*argv)[i]);
276 argv_orig[argc_orig] = NULL;
278 X_GETTIMEOFDAY (&start);
280 #ifndef I_NEED_TO_ACTUALLY_DEBUG_MY_PROGRAMS
281 signal (SIGHUP, gdk_signal);
282 signal (SIGINT, gdk_signal);
283 signal (SIGQUIT, gdk_signal);
284 signal (SIGBUS, gdk_signal);
285 signal (SIGSEGV, gdk_signal);
286 signal (SIGPIPE, gdk_signal);
287 signal (SIGTERM, gdk_signal);
290 gdk_display_name = NULL;
292 XSetErrorHandler (gdk_x_error);
293 XSetIOErrorHandler (gdk_x_io_error);
297 #ifdef G_ENABLE_DEBUG
299 gchar *debug_string = getenv("GDK_DEBUG");
300 if (debug_string != NULL)
301 gdk_debug_flags = g_parse_debug_string (debug_string,
305 #endif /* G_ENABLE_DEBUG */
310 gdk_progname = (*argv)[0];
312 for (i = 1; i < *argc;)
314 if ((*argv)[i] == NULL)
320 #ifdef G_ENABLE_DEBUG
321 if (strcmp ("--gdk-debug", (*argv)[i]) == 0)
325 if ((i + 1) < *argc && (*argv)[i + 1])
327 gdk_debug_flags |= g_parse_debug_string ((*argv)[i+1],
330 (*argv)[i + 1] = NULL;
334 else if (strcmp ("--gdk-no-debug", (*argv)[i]) == 0)
338 if ((i + 1) < *argc && (*argv)[i + 1])
340 gdk_debug_flags &= ~g_parse_debug_string ((*argv)[i+1],
343 (*argv)[i + 1] = NULL;
347 #endif /* G_ENABLE_DEBUG */
348 else if (strcmp ("--display", (*argv)[i]) == 0)
352 if ((i + 1) < *argc && (*argv)[i + 1])
354 gdk_display_name = g_strdup ((*argv)[i + 1]);
355 (*argv)[i + 1] = NULL;
359 else if (strcmp ("--sync", (*argv)[i]) == 0)
364 else if (strcmp ("--no-xshm", (*argv)[i]) == 0)
367 gdk_use_xshm = FALSE;
369 else if (strcmp ("--name", (*argv)[i]) == 0)
371 if ((i + 1) < *argc && (*argv)[i + 1])
374 gdk_progname = (*argv)[i];
378 else if (strcmp ("--class", (*argv)[i]) == 0)
380 if ((i + 1) < *argc && (*argv)[i + 1])
383 gdk_progclass = (*argv)[i];
388 else if (strcmp ("--gxid_host", (*argv)[i]) == 0)
390 if ((i + 1) < *argc && (*argv)[i + 1])
393 gdk_input_gxid_host = ((*argv)[i]);
397 else if (strcmp ("--gxid_port", (*argv)[i]) == 0)
399 if ((i + 1) < *argc && (*argv)[i + 1])
402 gdk_input_gxid_port = atoi ((*argv)[i]);
408 else if (strcmp ("--xim-preedit", (*argv)[i]) == 0)
410 if ((i + 1) < *argc && (*argv)[i + 1])
413 if (strcmp ("none", (*argv)[i]) == 0)
414 gdk_im_set_best_style (GdkIMPreeditNone);
415 else if (strcmp ("nothing", (*argv)[i]) == 0)
416 gdk_im_set_best_style (GdkIMPreeditNothing);
417 else if (strcmp ("area", (*argv)[i]) == 0)
418 gdk_im_set_best_style (GdkIMPreeditArea);
419 else if (strcmp ("position", (*argv)[i]) == 0)
420 gdk_im_set_best_style (GdkIMPreeditPosition);
421 else if (strcmp ("callbacks", (*argv)[i]) == 0)
422 gdk_im_set_best_style (GdkIMPreeditCallbacks);
425 else if (strcmp ("--xim-status", (*argv)[i]) == 0)
427 if ((i + 1) < *argc && (*argv)[i + 1])
430 if (strcmp ("none", (*argv)[i]) == 0)
431 gdk_im_set_best_style (GdkIMStatusNone);
432 else if (strcmp ("nothing", (*argv)[i]) == 0)
433 gdk_im_set_best_style (GdkIMStatusNothing);
434 else if (strcmp ("area", (*argv)[i]) == 0)
435 gdk_im_set_best_style (GdkIMStatusArea);
436 else if (strcmp ("callbacks", (*argv)[i]) == 0)
437 gdk_im_set_best_style (GdkIMStatusCallbacks);
445 for (i = 1; i < *argc; i++)
447 for (k = i; k < *argc; k++)
448 if ((*argv)[k] != NULL)
454 for (j = i + k; j < *argc; j++)
455 (*argv)[j-k] = (*argv)[j];
462 gdk_progname = "<unknown>";
465 gdk_display = XOpenDisplay (gdk_display_name);
468 g_warning ("cannot open display: %s", XDisplayName (gdk_display_name));
472 /* This is really crappy. We have to look into the display structure
473 * to find the base resource id. This is only needed for recording
474 * and playback of events.
476 /* base_id = RESOURCE_BASE; */
478 GDK_NOTE (EVENTS, g_print ("base id: %lu\n", base_id));
480 connection_number = ConnectionNumber (gdk_display);
482 g_print ("connection number: %d\n", connection_number));
485 XSynchronize (gdk_display, True);
487 gdk_screen = DefaultScreen (gdk_display);
488 gdk_root_window = RootWindow (gdk_display, gdk_screen);
490 gdk_leader_window = XCreateSimpleWindow(gdk_display, gdk_root_window,
491 10, 10, 10, 10, 0, 0 , 0);
492 class_hint = XAllocClassHint();
493 class_hint->res_name = gdk_progname;
494 if (gdk_progclass == NULL)
496 gdk_progclass = g_strdup (gdk_progname);
497 gdk_progclass[0] = toupper (gdk_progclass[0]);
499 class_hint->res_class = gdk_progclass;
500 XSetClassHint(gdk_display, gdk_leader_window, class_hint);
501 XSetCommand(gdk_display, gdk_leader_window, argv_orig, argc_orig);
504 gdk_wm_delete_window = XInternAtom (gdk_display, "WM_DELETE_WINDOW", True);
505 gdk_wm_take_focus = XInternAtom (gdk_display, "WM_TAKE_FOCUS", True);
506 gdk_wm_protocols = XInternAtom (gdk_display, "WM_PROTOCOLS", True);
507 gdk_wm_window_protocols[0] = gdk_wm_delete_window;
508 gdk_wm_window_protocols[1] = gdk_wm_take_focus;
509 gdk_selection_property = XInternAtom (gdk_display, "GDK_SELECTION", False);
511 gdk_dnd.gdk_XdeEnter = gdk_atom_intern("_XDE_ENTER", FALSE);
512 gdk_dnd.gdk_XdeLeave = gdk_atom_intern("_XDE_LEAVE", FALSE);
513 gdk_dnd.gdk_XdeRequest = gdk_atom_intern("_XDE_REQUEST", FALSE);
514 gdk_dnd.gdk_XdeDataAvailable = gdk_atom_intern("_XDE_DATA_AVAILABLE", FALSE);
515 gdk_dnd.gdk_XdeTypelist = gdk_atom_intern("_XDE_TYPELIST", FALSE);
516 gdk_dnd.c->gdk_cursor_dragdefault = XCreateFontCursor(gdk_display, XC_bogosity);
517 gdk_dnd.c->gdk_cursor_dragok = XCreateFontCursor(gdk_display, XC_heart);
519 XGetKeyboardControl (gdk_display, &keyboard_state);
520 autorepeat = keyboard_state.global_auto_repeat;
526 button_click_time[0] = 0;
527 button_click_time[1] = 0;
528 button_window[0] = NULL;
529 button_window[1] = NULL;
530 button_number[0] = -1;
531 button_number[1] = -1;
533 if (ATEXIT (gdk_exit_func))
534 g_warning ("unable to register exit function");
542 /* initialize XIM Protocol variables */
546 if (!(xim_best_allowed_style & GdkIMPreeditMask))
547 gdk_im_set_best_style (GdkIMPreeditCallbacks);
548 if (!(xim_best_allowed_style & GdkIMStatusMask))
549 gdk_im_set_best_style (GdkIMStatusCallbacks);
551 xim_window = (GdkWindow*)NULL;
553 gdk_im_open (NULL, NULL, NULL);
560 *--------------------------------------------------------------
563 * Restores the library to an un-itialized state and exits
564 * the program using the "exit" system call.
567 * "errorcode" is the error value to pass to "exit".
570 * Allocated structures are freed and the program exits
575 *--------------------------------------------------------------
579 gdk_exit (int errorcode)
581 /* de-initialisation is done by the gdk_exit_funct(),
582 no need to do this here (Alex J.) */
587 *--------------------------------------------------------------
596 *--------------------------------------------------------------
602 if (!setlocale (LC_ALL,""))
603 g_print ("locale not supported by C library\n");
605 if (!XSupportsLocale ())
607 g_print ("locale not supported by Xlib, locale set to C\n");
608 setlocale (LC_ALL, "C");
611 if (!XSetLocaleModifiers (""))
613 g_print ("can not set locale modifiers\n");
616 return setlocale (LC_ALL,NULL);
620 *--------------------------------------------------------------
623 * Returns the number of events pending on the queue.
624 * These events have already been read from the server
630 * Returns the number of events on XLib's event queue.
634 *--------------------------------------------------------------
638 gdk_events_pending ()
643 result = XPending (gdk_display);
645 tmp_list = putback_events;
649 tmp_list = tmp_list->next;
656 *--------------------------------------------------------------
657 * gdk_event_get_graphics_expose
659 * Waits for a GraphicsExpose or NoExpose event
664 * For GraphicsExpose events, returns a pointer to the event
665 * converted into a GdkEvent Otherwise, returns NULL.
669 *-------------------------------------------------------------- */
672 graphics_expose_predicate (Display *display,
676 GdkWindowPrivate *private = (GdkWindowPrivate *)arg;
678 g_return_val_if_fail (private != NULL, False);
680 if ((xevent->xany.window == private->xwindow) &&
681 ((xevent->xany.type == GraphicsExpose) ||
682 (xevent->xany.type == NoExpose)))
689 gdk_event_get_graphics_expose (GdkWindow *window)
694 g_return_val_if_fail (window != NULL, NULL);
696 XIfEvent (gdk_display, &xevent, graphics_expose_predicate, (XPointer)window);
698 if (xevent.xany.type == GraphicsExpose)
700 event = gdk_event_new ();
702 if (gdk_event_translate (event, &xevent))
705 gdk_event_free (event);
712 *--------------------------------------------------------------
715 * Gets the next event.
720 * If an event was received that we care about, returns
721 * a pointer to that event, to be freed with gdk_event_free.
722 * Otherwise, returns NULL. This function will also return
723 * before an event is received if the timeout interval
728 *--------------------------------------------------------------
741 temp_list = putback_events;
744 temp_event = temp_list->data;
746 if ((* pred) (temp_event, data))
749 *event = *temp_event;
750 putback_events = g_list_remove_link (putback_events, temp_list);
751 g_list_free (temp_list);
755 temp_list = temp_list->next;
758 event_pred.func = pred;
759 event_pred.data = data;
761 if (XCheckIfEvent (gdk_display, &xevent, gdk_event_get_type, (XPointer) & event_pred))
763 return gdk_event_translate (event, &xevent);
769 event = putback_events->data;
771 temp_list = putback_events;
772 putback_events = g_list_remove_link (putback_events, temp_list);
773 g_list_free_1 (temp_list);
778 /* Wait for an event to occur or the timeout to elapse.
779 * If an event occurs "gdk_event_wait" will return TRUE.
780 * If the timeout elapses "gdk_event_wait" will return
783 if (gdk_event_wait ())
785 /* If we get here we can rest assurred that an event
786 * has occurred. Read it.
790 if (xim_using && xim_window)
792 { /* don't dispatch events used by IM */
793 XNextEvent (gdk_display, &xevent);
794 filter_status = XFilterEvent (&xevent,
795 GDK_WINDOW_XWINDOW (xim_window));
796 } while (filter_status == True);
798 XNextEvent (gdk_display, &xevent);
800 XNextEvent (gdk_display, &xevent);
802 event = gdk_event_new ();
804 event->any.type = GDK_NOTHING;
805 event->any.window = NULL;
806 event->any.send_event = FALSE;
807 event->any.send_event = xevent.xany.send_event;
809 if (gdk_event_translate (event, &xevent))
812 gdk_event_free (event);
819 gdk_event_put (GdkEvent *event)
823 g_return_if_fail (event != NULL);
825 new_event = gdk_event_copy (event);
827 putback_events = g_list_prepend (putback_events, new_event);
831 *--------------------------------------------------------------
834 * Copy a event structure into new storage.
837 * "event" is the event struct to copy.
840 * A new event structure. Free it with gdk_event_free.
843 * The reference count of the window in the event is increased.
845 *--------------------------------------------------------------
848 static GMemChunk *event_chunk;
855 if (event_chunk == NULL)
856 event_chunk = g_mem_chunk_new ("events",
861 new_event = g_chunk_new (GdkEvent, event_chunk);
867 gdk_event_copy (GdkEvent *event)
871 g_return_val_if_fail (event != NULL, NULL);
873 new_event = gdk_event_new ();
876 gdk_window_ref (new_event->any.window);
878 switch (event->any.type)
881 case GDK_KEY_RELEASE:
882 new_event->key.string = g_strdup (event->key.string);
885 case GDK_ENTER_NOTIFY:
886 case GDK_LEAVE_NOTIFY:
887 if (event->crossing.subwindow != NULL)
888 gdk_window_ref (event->crossing.subwindow);
891 case GDK_DROP_DATA_AVAIL:
892 new_event->dropdataavailable.data_type = g_strdup (event->dropdataavailable.data_type);
893 new_event->dropdataavailable.data = g_malloc (event->dropdataavailable.data_numbytes);
894 memcpy (new_event->dropdataavailable.data,
895 event->dropdataavailable.data,
896 event->dropdataavailable.data_numbytes);
907 *--------------------------------------------------------------
910 * Free a event structure obtained from gdk_event_copy. Do not use
911 * with other event structures.
914 * "event" is the event struct to free.
919 * The reference count of the window in the event is decreased and
920 * might be freed, too.
922 *-------------------------------------------------------------- */
925 gdk_event_free (GdkEvent *event)
927 g_assert (event_chunk != NULL);
928 g_return_if_fail (event != NULL);
930 if (event->any.window)
931 gdk_window_unref (event->any.window);
933 switch (event->any.type)
936 case GDK_KEY_RELEASE:
937 g_free (event->key.string);
940 case GDK_ENTER_NOTIFY:
941 case GDK_LEAVE_NOTIFY:
942 if (event->crossing.subwindow != NULL)
943 gdk_window_unref (event->crossing.subwindow);
946 case GDK_DROP_DATA_AVAIL:
947 g_free (event->dropdataavailable.data_type);
948 g_free (event->dropdataavailable.data);
951 case GDK_DRAG_REQUEST:
952 g_free (event->dragrequest.data_type);
959 g_mem_chunk_free (event_chunk, event);
963 *--------------------------------------------------------------
964 * gdk_set_show_events
966 * Turns on/off the showing of events.
969 * "show_events" is a boolean describing whether or
970 * not to show the events gdk receives.
975 * When "show_events" is TRUE, calls to "gdk_event_get"
976 * will output debugging informatin regarding the event
977 * received to stdout.
979 *--------------------------------------------------------------
983 gdk_set_show_events (int show_events)
986 gdk_debug_flags |= GDK_DEBUG_EVENTS;
988 gdk_debug_flags &= ~GDK_DEBUG_EVENTS;
992 gdk_set_use_xshm (gint use_xshm)
994 gdk_use_xshm = use_xshm;
998 gdk_get_show_events ()
1000 return gdk_debug_flags & GDK_DEBUG_EVENTS;
1006 return gdk_use_xshm;
1010 *--------------------------------------------------------------
1013 * Get the number of milliseconds since the library was
1019 * The time since the library was initialized is returned.
1020 * This time value is accurate to milliseconds even though
1021 * a more accurate time down to the microsecond could be
1026 *--------------------------------------------------------------
1033 struct timeval elapsed;
1034 guint32 milliseconds;
1036 X_GETTIMEOFDAY (&end);
1038 if (start.tv_usec > end.tv_usec)
1040 end.tv_usec += 1000000;
1043 elapsed.tv_sec = end.tv_sec - start.tv_sec;
1044 elapsed.tv_usec = end.tv_usec - start.tv_usec;
1046 milliseconds = (elapsed.tv_sec * 1000) + (elapsed.tv_usec / 1000);
1048 return milliseconds;
1052 *--------------------------------------------------------------
1055 * Returns the current timer.
1060 * Returns the current timer interval. This interval is
1061 * in units of milliseconds.
1065 *--------------------------------------------------------------
1075 *--------------------------------------------------------------
1078 * Sets the timer interval.
1081 * "milliseconds" is the new value for the timer.
1086 * Calls to "gdk_event_get" will last for a maximum
1087 * of time of "milliseconds". However, a value of 0
1088 * milliseconds will cause "gdk_event_get" to block
1089 * indefinately until an event is received.
1091 *--------------------------------------------------------------
1095 gdk_timer_set (guint32 milliseconds)
1097 timer_val = milliseconds;
1098 timer.tv_sec = milliseconds / 1000;
1099 timer.tv_usec = (milliseconds % 1000) * 1000;
1110 gdk_timer_disable ()
1116 gdk_input_add_full (gint source,
1117 GdkInputCondition condition,
1118 GdkInputFunction function,
1120 GdkDestroyNotify destroy)
1122 static gint next_tag = 1;
1135 if ((input->source == source) && (input->condition == condition))
1138 (input->destroy) (input->data);
1139 input->function = function;
1141 input->destroy = destroy;
1148 input = g_new (GdkInput, 1);
1149 input->tag = next_tag++;
1150 input->source = source;
1151 input->condition = condition;
1152 input->function = function;
1154 input->destroy = destroy;
1157 inputs = g_list_prepend (inputs, input);
1164 gdk_input_add (gint source,
1165 GdkInputCondition condition,
1166 GdkInputFunction function,
1169 return gdk_input_add_interp (source, condition, function, data, NULL);
1173 gdk_input_remove (gint tag)
1184 if (input->tag == tag)
1187 (input->destroy) (input->data);
1192 list->next->prev = list->prev;
1194 list->prev->next = list->next;
1196 inputs = list->next;
1198 temp_list->next = NULL;
1199 temp_list->prev = NULL;
1201 g_free (temp_list->data);
1202 g_list_free (temp_list);
1211 *--------------------------------------------------------------
1214 * Grabs the pointer to a specific window
1217 * "window" is the window which will receive the grab
1218 * "owner_events" specifies whether events will be reported as is,
1219 * or relative to "window"
1220 * "event_mask" masks only interesting events
1221 * "confine_to" limits the cursor movement to the specified window
1222 * "cursor" changes the cursor for the duration of the grab
1223 * "time" specifies the time
1228 * requires a corresponding call to gdk_pointer_ungrab
1230 *--------------------------------------------------------------
1234 gdk_pointer_grab (GdkWindow * window,
1236 GdkEventMask event_mask,
1237 GdkWindow * confine_to,
1241 /* From gdkwindow.c */
1242 extern int nevent_masks;
1243 extern int event_mask_table[];
1246 GdkWindowPrivate *window_private;
1247 GdkWindowPrivate *confine_to_private;
1248 GdkCursorPrivate *cursor_private;
1255 g_return_val_if_fail (window != NULL, 0);
1257 window_private = (GdkWindowPrivate*) window;
1258 confine_to_private = (GdkWindowPrivate*) confine_to;
1259 cursor_private = (GdkCursorPrivate*) cursor;
1261 xwindow = window_private->xwindow;
1263 if (!confine_to || confine_to_private->destroyed)
1266 xconfine_to = confine_to_private->xwindow;
1271 xcursor = cursor_private->xcursor;
1275 for (i = 0; i < nevent_masks; i++)
1277 if (event_mask & (1 << (i + 1)))
1278 xevent_mask |= event_mask_table[i];
1281 if (((GdkWindowPrivate *)window)->extension_events &&
1282 gdk_input_vtable.grab_pointer)
1283 return_val = gdk_input_vtable.grab_pointer (window,
1289 return_val = Success;
1291 if (return_val == Success)
1293 if (!window_private->destroyed)
1294 return_val = XGrabPointer (window_private->xdisplay,
1298 GrabModeAsync, GrabModeAsync,
1303 return_val = AlreadyGrabbed;
1306 if (return_val == GrabSuccess)
1307 xgrab_window = window_private;
1313 *--------------------------------------------------------------
1314 * gdk_pointer_ungrab
1316 * Releases any pointer grab
1324 *--------------------------------------------------------------
1328 gdk_pointer_ungrab (guint32 time)
1330 if (gdk_input_vtable.ungrab_pointer)
1331 gdk_input_vtable.ungrab_pointer (time);
1333 XUngrabPointer (gdk_display, time);
1334 xgrab_window = NULL;
1338 *--------------------------------------------------------------
1339 * gdk_pointer_is_grabbed
1341 * Tell wether there is an active x pointer grab in effect
1349 *--------------------------------------------------------------
1353 gdk_pointer_is_grabbed (void)
1355 return xgrab_window != NULL;
1359 *--------------------------------------------------------------
1362 * Grabs the keyboard to a specific window
1365 * "window" is the window which will receive the grab
1366 * "owner_events" specifies whether events will be reported as is,
1367 * or relative to "window"
1368 * "time" specifies the time
1373 * requires a corresponding call to gdk_keyboard_ungrab
1375 *--------------------------------------------------------------
1379 gdk_keyboard_grab (GdkWindow * window,
1383 GdkWindowPrivate *window_private;
1386 g_return_val_if_fail (window != NULL, 0);
1388 window_private = (GdkWindowPrivate*) window;
1389 xwindow = window_private->xwindow;
1391 if (!window_private->destroyed)
1392 return XGrabKeyboard (window_private->xdisplay,
1395 GrabModeAsync, GrabModeAsync,
1398 return AlreadyGrabbed;
1402 *--------------------------------------------------------------
1403 * gdk_keyboard_ungrab
1405 * Releases any keyboard grab
1413 *--------------------------------------------------------------
1417 gdk_keyboard_ungrab (guint32 time)
1419 XUngrabKeyboard (gdk_display, time);
1423 *--------------------------------------------------------------
1426 * Return the width of the screen.
1434 *--------------------------------------------------------------
1442 return_val = DisplayWidth (gdk_display, gdk_screen);
1448 *--------------------------------------------------------------
1451 * Return the height of the screen.
1459 *--------------------------------------------------------------
1463 gdk_screen_height ()
1467 return_val = DisplayHeight (gdk_display, gdk_screen);
1473 gdk_key_repeat_disable ()
1475 XAutoRepeatOff (gdk_display);
1479 gdk_key_repeat_restore ()
1482 XAutoRepeatOn (gdk_display);
1484 XAutoRepeatOff (gdk_display);
1489 *--------------------------------------------------------------
1492 * Flushes the Xlib output buffer and then waits
1493 * until all requests have been received and processed
1494 * by the X server. The only real use for this function
1495 * is in dealing with XShm.
1503 *--------------------------------------------------------------
1508 XSync (gdk_display, False);
1515 XBell(gdk_display, 100);
1520 *--------------------------------------------------------------
1523 * Waits until an event occurs or the timer runs out.
1528 * Returns TRUE if an event is ready to be read and FALSE
1529 * if the timer ran out.
1533 *--------------------------------------------------------------
1541 GdkInputCondition condition;
1542 SELECT_MASK readfds;
1543 SELECT_MASK writefds;
1544 SELECT_MASK exceptfds;
1548 /* If there are no events pending we will wait for an event.
1549 * The time we wait is dependant on the "timer". If no timer
1550 * has been specified then we'll block until an event arrives.
1551 * If a timer has been specified we'll block until an event
1552 * arrives or the timer expires. (This is all done using the
1553 * "select" system call).
1556 if (XPending (gdk_display) == 0)
1559 FD_ZERO (&writefds);
1560 FD_ZERO (&exceptfds);
1562 FD_SET (connection_number, &readfds);
1563 max_input = connection_number;
1571 if (input->condition & GDK_INPUT_READ)
1572 FD_SET (input->source, &readfds);
1573 if (input->condition & GDK_INPUT_WRITE)
1574 FD_SET (input->source, &writefds);
1575 if (input->condition & GDK_INPUT_EXCEPTION)
1576 FD_SET (input->source, &exceptfds);
1578 max_input = MAX (max_input, input->source);
1581 nfd = select (max_input+1, &readfds, &writefds, &exceptfds, timerp);
1588 if (FD_ISSET (connection_number, &readfds))
1590 if (XPending (gdk_display) == 0)
1594 XNoOp (gdk_display);
1595 XFlush (gdk_display);
1610 if (FD_ISSET (input->source, &readfds))
1611 condition |= GDK_INPUT_READ;
1612 if (FD_ISSET (input->source, &writefds))
1613 condition |= GDK_INPUT_WRITE;
1614 if (FD_ISSET (input->source, &exceptfds))
1615 condition |= GDK_INPUT_EXCEPTION;
1617 if (condition && input->function)
1618 (* input->function) (input->data, input->source, condition);
1629 gdk_event_apply_filters (XEvent *xevent,
1633 GdkEventFilter *filter;
1635 GdkFilterReturn result;
1641 filter = (GdkEventFilter *)tmp_list->data;
1643 result = (*filter->function)(xevent, event, filter->data);
1644 if (result != GDK_FILTER_CONTINUE)
1647 tmp_list = tmp_list->next;
1650 return GDK_FILTER_CONTINUE;
1654 gdk_event_translate (GdkEvent *event,
1659 GdkWindowPrivate *window_private;
1660 XComposeStatus compose;
1663 static gchar* buf = NULL;
1664 static gint buf_len= 0;
1670 /* Are static variables used for this purpose thread-safe? */
1671 static GdkPoint dnd_drag_start = {0,0},
1672 dnd_drag_oldpos = {0,0};
1673 static GdkRectangle dnd_drag_dropzone = {0,0,0,0};
1674 static GdkWindowPrivate *real_sw = NULL;
1675 static Window dnd_drag_curwin = None;
1679 /* Find the GdkWindow that this event occurred in.
1680 * All events occur in some GdkWindow (otherwise, why
1681 * would we be receiving them). It really is an error
1682 * to receive an event for which we cannot find the
1683 * corresponding GdkWindow. We handle events with window=None
1684 * specially - they are generated by XFree86's XInput under
1685 * some circumstances.
1688 if ((xevent->xany.window == None) &&
1689 gdk_input_vtable.window_none_event)
1691 return_val = gdk_input_vtable.window_none_event (event,xevent);
1693 if (return_val >= 0) /* was handled */
1699 window = gdk_window_lookup (xevent->xany.window);
1700 window_private = (GdkWindowPrivate *) window;
1703 gdk_window_ref (window);
1704 else if(gdk_null_window_warnings) /* Special purpose programs that
1705 get events for other windows may
1706 want to disable this */
1707 g_warning ("%#lx -> NULL\n", xevent->xany.window);
1709 /* Check for filters for this window */
1712 GdkFilterReturn result;
1713 result = gdk_event_apply_filters (xevent, event,
1715 ?window_private->filters
1718 if (result != GDK_FILTER_CONTINUE)
1720 return (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE;
1724 /* We do a "manual" conversion of the XEvent to a
1725 * GdkEvent. The structures are mostly the same so
1726 * the conversion is fairly straightforward. We also
1727 * optionally print debugging info regarding events
1731 * During drag & drop you get events where the pointer is
1732 * in other windows. Need to just do finer-grained checking
1734 switch (xevent->type)
1737 /* Lookup the string corresponding to the given keysym.
1743 buf = g_new (gchar, buf_len);
1745 if (xim_using == TRUE && xim_ic)
1749 /* Clear keyval. Depending on status, may not be set */
1750 event->key.keyval = GDK_VoidSymbol;
1751 charcount = XmbLookupString(xim_ic->xic,
1752 &xevent->xkey, buf, buf_len-1,
1753 (KeySym*) &event->key.keyval,
1755 if (status == XBufferOverflow)
1757 /* alloc adequate size of buffer */
1759 g_print("XIM: overflow (required %i)\n", charcount));
1761 while (buf_len <= charcount)
1763 buf = (gchar *) g_realloc (buf, buf_len);
1765 charcount = XmbLookupString (xim_ic->xic,
1766 &xevent->xkey, buf, buf_len-1,
1767 (KeySym*) &event->key.keyval,
1770 if (status == XLookupNone)
1777 charcount = XLookupString (&xevent->xkey, buf, buf_len,
1778 (KeySym*) &event->key.keyval,
1781 charcount = XLookupString (&xevent->xkey, buf, 16,
1782 (KeySym*) &event->key.keyval,
1785 if (charcount > 0 && buf[charcount-1] == '\0')
1788 buf[charcount] = '\0';
1790 /* Print debugging info.
1792 #ifdef G_ENABLE_DEBUG
1793 if (gdk_debug_flags & GDK_DEBUG_EVENTS)
1795 g_print ("key press:\twindow: %ld key: %12s %d\n",
1796 xevent->xkey.window - base_id,
1797 event->key.keyval ? XKeysymToString (event->key.keyval) : "(none)",
1800 g_print ("\t\tlength: %4d string: \"%s\"\n",
1803 #endif /* G_ENABLE_DEBUG */
1805 event->key.type = GDK_KEY_PRESS;
1806 event->key.window = window;
1807 event->key.time = xevent->xkey.time;
1808 event->key.state = (GdkModifierType) xevent->xkey.state;
1809 event->key.string = g_strdup (buf);
1810 event->key.length = charcount;
1812 return_val = window_private && !window_private->destroyed;
1815 g_free (event->key.string);
1820 /* Lookup the string corresponding to the given keysym.
1822 charcount = XLookupString (&xevent->xkey, buf, 16,
1823 (KeySym*) &event->key.keyval,
1826 /* Print debugging info.
1829 g_print ("key release:\t\twindow: %ld key: %12s %d\n",
1830 xevent->xkey.window - base_id,
1831 XKeysymToString (event->key.keyval),
1832 event->key.keyval));
1834 event->key.type = GDK_KEY_RELEASE;
1835 event->key.window = window;
1836 event->key.time = xevent->xkey.time;
1837 event->key.state = (GdkModifierType) xevent->xkey.state;
1838 event->key.length = 0;
1839 event->key.string = NULL;
1841 return_val = window_private && !window_private->destroyed;
1845 /* Print debugging info.
1848 g_print ("button press[%d]:\t\twindow: %ld x,y: %d %d button: %d\n",
1849 window_private?window_private->dnd_drag_enabled:0,
1850 xevent->xbutton.window - base_id,
1851 xevent->xbutton.x, xevent->xbutton.y,
1852 xevent->xbutton.button));
1854 if (window_private &&
1855 (window_private->extension_events != 0) &&
1856 gdk_input_ignore_core)
1859 event->button.type = GDK_BUTTON_PRESS;
1860 event->button.window = window;
1861 event->button.time = xevent->xbutton.time;
1862 event->button.x = xevent->xbutton.x;
1863 event->button.y = xevent->xbutton.y;
1864 event->button.x_root = (gfloat)xevent->xbutton.x_root;
1865 event->button.y_root = (gfloat)xevent->xbutton.y_root;
1866 event->button.pressure = 0.5;
1867 event->button.xtilt = 0;
1868 event->button.ytilt = 0;
1869 event->button.state = (GdkModifierType) xevent->xbutton.state;
1870 event->button.button = xevent->xbutton.button;
1871 event->button.source = GDK_SOURCE_MOUSE;
1872 event->button.deviceid = GDK_CORE_POINTER;
1874 if ((event->button.time < (button_click_time[1] + TRIPLE_CLICK_TIME)) &&
1875 (event->button.window == button_window[1]) &&
1876 (event->button.button == button_number[1]))
1878 gdk_synthesize_click (event, 3);
1880 button_click_time[1] = 0;
1881 button_click_time[0] = 0;
1882 button_window[1] = NULL;
1883 button_window[0] = 0;
1884 button_number[1] = -1;
1885 button_number[0] = -1;
1887 else if ((event->button.time < (button_click_time[0] + DOUBLE_CLICK_TIME)) &&
1888 (event->button.window == button_window[0]) &&
1889 (event->button.button == button_number[0]))
1891 gdk_synthesize_click (event, 2);
1893 button_click_time[1] = button_click_time[0];
1894 button_click_time[0] = event->button.time;
1895 button_window[1] = button_window[0];
1896 button_window[0] = event->button.window;
1897 button_number[1] = button_number[0];
1898 button_number[0] = event->button.button;
1902 button_click_time[1] = 0;
1903 button_click_time[0] = event->button.time;
1904 button_window[1] = NULL;
1905 button_window[0] = event->button.window;
1906 button_number[1] = -1;
1907 button_number[0] = event->button.button;
1910 && window_private->dnd_drag_enabled
1911 && !gdk_dnd.drag_perhaps
1912 && event->button.button == 1
1913 && !gdk_dnd.drag_really)
1915 gdk_dnd.drag_perhaps = 1;
1916 dnd_drag_start.x = xevent->xbutton.x_root;
1917 dnd_drag_start.y = xevent->xbutton.y_root;
1918 real_sw = window_private;
1920 if(gdk_dnd.drag_startwindows)
1922 g_free(gdk_dnd.drag_startwindows);
1923 gdk_dnd.drag_startwindows = NULL;
1925 gdk_dnd.drag_numwindows = gdk_dnd.drag_really = 0;
1926 gdk_dnd.dnd_grabbed = FALSE;
1929 /* Set motion mask for first DnD'd window, since it
1930 will be the one that is actually dragged */
1931 XWindowAttributes dnd_winattr;
1932 XSetWindowAttributes dnd_setwinattr;
1934 /* We need to get motion events while the button is down, so
1935 we can know whether to really start dragging or not... */
1936 XGetWindowAttributes(gdk_display, (Window)window_private->xwindow,
1939 window_private->dnd_drag_savedeventmask = dnd_winattr.your_event_mask;
1940 dnd_setwinattr.event_mask =
1941 window_private->dnd_drag_eventmask = ButtonMotionMask | EnterWindowMask | LeaveWindowMask;
1942 XChangeWindowAttributes(gdk_display, window_private->xwindow,
1943 CWEventMask, &dnd_setwinattr);
1946 return_val = window_private && !window_private->destroyed;
1950 /* Print debugging info.
1953 g_print ("button release[%d]:\twindow: %ld x,y: %d %d button: %d\n",
1954 window_private?window_private->dnd_drag_enabled:0,
1955 xevent->xbutton.window - base_id,
1956 xevent->xbutton.x, xevent->xbutton.y,
1957 xevent->xbutton.button));
1959 if (window_private &&
1960 (window_private->extension_events != 0) &&
1961 gdk_input_ignore_core)
1964 event->button.type = GDK_BUTTON_RELEASE;
1965 event->button.window = window;
1966 event->button.time = xevent->xbutton.time;
1967 event->button.x = xevent->xbutton.x;
1968 event->button.y = xevent->xbutton.y;
1969 event->button.x_root = (gfloat)xevent->xbutton.x_root;
1970 event->button.y_root = (gfloat)xevent->xbutton.y_root;
1971 event->button.pressure = 0.5;
1972 event->button.xtilt = 0;
1973 event->button.ytilt = 0;
1974 event->button.state = (GdkModifierType) xevent->xbutton.state;
1975 event->button.button = xevent->xbutton.button;
1976 event->button.source = GDK_SOURCE_MOUSE;
1977 event->button.deviceid = GDK_CORE_POINTER;
1979 if(gdk_dnd.drag_perhaps)
1982 XSetWindowAttributes attrs;
1983 /* Reset event mask to pre-drag value, assuming event_mask
1984 doesn't change during drag */
1985 attrs.event_mask = real_sw->dnd_drag_savedeventmask;
1986 XChangeWindowAttributes(gdk_display, real_sw->xwindow,
1987 CWEventMask, &attrs);
1990 if (gdk_dnd.dnd_grabbed)
1992 gdk_dnd_display_drag_cursor(-2,
1995 XUngrabPointer(gdk_display, CurrentTime);
1996 gdk_dnd.dnd_grabbed = FALSE;
1999 if(gdk_dnd.drag_really)
2002 foo.x = xevent->xbutton.x_root;
2003 foo.y = xevent->xbutton.y_root;
2005 if(gdk_dnd.dnd_drag_target != None)
2006 gdk_dnd_drag_end(gdk_dnd.dnd_drag_target, foo);
2007 gdk_dnd.drag_really = 0;
2009 gdk_dnd.drag_numwindows = 0;
2010 if(gdk_dnd.drag_startwindows)
2012 g_free(gdk_dnd.drag_startwindows);
2013 gdk_dnd.drag_startwindows = NULL;
2019 gdk_dnd.drag_perhaps = 0;
2020 dnd_drag_start.x = dnd_drag_start.y = 0;
2021 dnd_drag_dropzone.x = dnd_drag_dropzone.y = 0;
2022 dnd_drag_dropzone.width = dnd_drag_dropzone.height = 0;
2023 dnd_drag_curwin = None;
2024 return_val = window_private?TRUE:FALSE;
2026 return_val = window_private && !window_private->destroyed;
2030 /* Print debugging info.
2033 g_print ("motion notify:\t\twindow: %ld x,y: %d %d hint: %s d:%d r%d\n",
2034 xevent->xmotion.window - base_id,
2035 xevent->xmotion.x, xevent->xmotion.y,
2036 (xevent->xmotion.is_hint) ? "true" : "false",
2037 gdk_dnd.drag_perhaps, gdk_dnd.drag_really));
2039 if (window_private &&
2040 (window_private->extension_events != 0) &&
2041 gdk_input_ignore_core)
2044 event->motion.type = GDK_MOTION_NOTIFY;
2045 event->motion.window = window;
2046 event->motion.time = xevent->xmotion.time;
2047 event->motion.x = xevent->xmotion.x;
2048 event->motion.y = xevent->xmotion.y;
2049 event->motion.x_root = (gfloat)xevent->xmotion.x_root;
2050 event->motion.y_root = (gfloat)xevent->xmotion.y_root;
2051 event->motion.pressure = 0.5;
2052 event->motion.xtilt = 0;
2053 event->motion.ytilt = 0;
2054 event->motion.state = (GdkModifierType) xevent->xmotion.state;
2055 event->motion.is_hint = xevent->xmotion.is_hint;
2056 event->motion.source = GDK_SOURCE_MOUSE;
2057 event->motion.deviceid = GDK_CORE_POINTER;
2059 #define IS_IN_ZONE(cx, cy) (cx >= dnd_drag_dropzone.x \
2060 && cy >= dnd_drag_dropzone.y \
2061 && cx < (dnd_drag_dropzone.x + dnd_drag_dropzone.width) \
2062 && cy < (dnd_drag_dropzone.y + dnd_drag_dropzone.height))
2064 if(gdk_dnd.drag_perhaps && gdk_dnd.drag_really)
2066 /* First, we have to find what window the motion was in... */
2067 /* XXX there has to be a better way to do this, perhaps with
2068 XTranslateCoordinates or XQueryTree - I don't know how,
2069 and this sort of works */
2070 static Window lastwin = None, curwin = None, twin;
2071 Window childwin = gdk_root_window;
2074 /* Interlude - display cursor for the drag ASAP */
2075 gdk_dnd_display_drag_cursor(xevent->xmotion.x_root,
2076 xevent->xmotion.y_root,
2077 gdk_dnd.dnd_drag_target?TRUE:FALSE,
2081 curwin = gdk_root_window;
2082 ox = x = xevent->xmotion.x_root;
2083 oy = y = xevent->xmotion.y_root;
2084 while(childwin != None)
2088 XTranslateCoordinates(gdk_display, curwin, curwin,
2089 x, y, &x, &y, &childwin);
2090 if(childwin != None)
2092 XTranslateCoordinates(gdk_display, curwin, childwin,
2093 x, y, &x, &y, &twin);
2097 g_print("Drag is now in window %#lx, lastwin was %#lx, ddc = %#lx\n",
2098 curwin, lastwin, dnd_drag_curwin));
2099 if(curwin != dnd_drag_curwin && curwin != lastwin)
2101 /* We have left one window and entered another
2102 (do leave & enter bits) */
2103 if(dnd_drag_curwin != None)
2104 gdk_dnd_drag_leave(dnd_drag_curwin);
2105 dnd_drag_curwin = curwin;
2106 gdk_dnd_drag_enter(dnd_drag_curwin);
2107 dnd_drag_dropzone.x = dnd_drag_dropzone.y = 0;
2108 dnd_drag_dropzone.width = dnd_drag_dropzone.height = 0;
2109 gdk_dnd.dnd_drag_target = None;
2111 g_print("curwin = %#lx, lastwin = %#lx, dnd_drag_curwin = %#lx\n",
2112 curwin, lastwin, dnd_drag_curwin));
2114 gdk_dnd_display_drag_cursor(xevent->xmotion.x_root,
2115 xevent->xmotion.y_root,
2118 else if(dnd_drag_dropzone.width > 0
2119 && dnd_drag_dropzone.height > 0
2120 && curwin == dnd_drag_curwin)
2122 /* Handle all that dropzone stuff - thanks John ;-) */
2123 if (gdk_dnd.dnd_drag_target != None)
2125 gboolean in_zone = IS_IN_ZONE(xevent->xmotion.x_root,
2126 xevent->xmotion.y_root);
2127 gboolean old_in_zone = IS_IN_ZONE(dnd_drag_oldpos.x,
2130 if (!in_zone && old_in_zone)
2132 /* We were in the drop zone and moved out */
2133 gdk_dnd.dnd_drag_target = None;
2134 gdk_dnd_drag_leave(curwin);
2135 gdk_dnd_display_drag_cursor(xevent->xmotion.x_root,
2136 xevent->xmotion.y_root,
2139 else if (!in_zone && !old_in_zone)
2141 /* We were outside drop zone but in the window
2142 - have to send enter events */
2143 gdk_dnd_drag_enter(curwin);
2144 dnd_drag_curwin = curwin;
2145 dnd_drag_dropzone.x = dnd_drag_dropzone.y = 0;
2146 gdk_dnd.dnd_drag_target = None;
2150 dnd_drag_curwin = None; */
2154 return_val = window_private && !window_private->destroyed;
2158 /* Print debugging info.
2161 g_print ("enter notify:\t\twindow: %ld detail: %d subwin: %ld\n",
2162 xevent->xcrossing.window - base_id,
2163 xevent->xcrossing.detail,
2164 xevent->xcrossing.subwindow - base_id));
2166 /* Tell XInput stuff about it if appropriate */
2167 if (window_private &&
2168 (window_private->extension_events != 0) &&
2169 gdk_input_vtable.enter_event)
2170 gdk_input_vtable.enter_event (&xevent->xcrossing, window);
2172 event->crossing.type = GDK_ENTER_NOTIFY;
2173 event->crossing.window = window;
2175 /* If the subwindow field of the XEvent is non-NULL, then
2176 * lookup the corresponding GdkWindow.
2178 if (xevent->xcrossing.subwindow != None)
2179 event->crossing.subwindow = gdk_window_lookup (xevent->xcrossing.subwindow);
2181 event->crossing.subwindow = NULL;
2183 /* Translate the crossing detail into Gdk terms.
2185 switch (xevent->xcrossing.detail)
2187 case NotifyInferior:
2188 event->crossing.detail = GDK_NOTIFY_INFERIOR;
2190 case NotifyAncestor:
2191 event->crossing.detail = GDK_NOTIFY_ANCESTOR;
2194 event->crossing.detail = GDK_NOTIFY_VIRTUAL;
2196 case NotifyNonlinear:
2197 event->crossing.detail = GDK_NOTIFY_NONLINEAR;
2199 case NotifyNonlinearVirtual:
2200 event->crossing.detail = GDK_NOTIFY_NONLINEAR_VIRTUAL;
2203 event->crossing.detail = GDK_NOTIFY_UNKNOWN;
2207 #ifdef G_ENABLE_DEBUG
2208 if ((gdk_debug_flags & GDK_DEBUG_DND) & gdk_dnd.drag_perhaps)
2210 g_print("We may[%d] have a drag into %#lx = %#lx\n",
2211 gdk_dnd.drag_really,
2212 xevent->xcrossing.window, real_sw->xwindow);
2214 #endif /* G_ENABLE_DEBUG */
2216 if (gdk_dnd.drag_perhaps && gdk_dnd.drag_really &&
2217 (xevent->xcrossing.window == real_sw->xwindow))
2219 gdk_dnd.drag_really = 0;
2221 GDK_NOTE (DND, g_print("Ungrabbed\n"));
2223 gdk_dnd.drag_numwindows = 0;
2224 g_free(gdk_dnd.drag_startwindows);
2225 gdk_dnd.drag_startwindows = NULL;
2226 /* We don't want to ungrab the pointer here, or we'll
2227 * start getting spurious enter/leave events */
2229 XChangeActivePointerGrab (gdk_display, 0, None, CurrentTime);
2233 return_val = window_private && !window_private->destroyed;
2237 /* Print debugging info.
2240 g_print ("leave notify:\t\twindow: %ld detail: %d subwin: %ld\n",
2241 xevent->xcrossing.window - base_id,
2242 xevent->xcrossing.detail, xevent->xcrossing.subwindow - base_id));
2244 event->crossing.type = GDK_LEAVE_NOTIFY;
2245 event->crossing.window = window;
2247 /* If the subwindow field of the XEvent is non-NULL, then
2248 * lookup the corresponding GdkWindow.
2250 if (xevent->xcrossing.subwindow != None)
2251 event->crossing.subwindow = gdk_window_lookup (xevent->xcrossing.subwindow);
2253 event->crossing.subwindow = NULL;
2255 /* Translate the crossing detail into Gdk terms.
2257 switch (xevent->xcrossing.detail)
2259 case NotifyInferior:
2260 event->crossing.detail = GDK_NOTIFY_INFERIOR;
2262 case NotifyAncestor:
2263 event->crossing.detail = GDK_NOTIFY_ANCESTOR;
2266 event->crossing.detail = GDK_NOTIFY_VIRTUAL;
2268 case NotifyNonlinear:
2269 event->crossing.detail = GDK_NOTIFY_NONLINEAR;
2271 case NotifyNonlinearVirtual:
2272 event->crossing.detail = GDK_NOTIFY_NONLINEAR_VIRTUAL;
2275 event->crossing.detail = GDK_NOTIFY_UNKNOWN;
2278 #ifdef G_ENABLE_DEBUG
2279 if ((gdk_debug_flags & GDK_DEBUG_DND) & gdk_dnd.drag_perhaps)
2281 g_print("We may[%d] have a drag out of %#lx = %#lx\n",
2282 gdk_dnd.drag_really,
2283 xevent->xcrossing.window, real_sw->xwindow);
2285 #endif /* G_ENABLE_DEBUG */
2286 if (gdk_dnd.drag_perhaps && !gdk_dnd.drag_really &&
2287 (xevent->xcrossing.window == real_sw->xwindow))
2289 gdk_dnd_drag_addwindow((GdkWindow *) real_sw);
2290 gdk_dnd_drag_begin((GdkWindow *) real_sw);
2291 XGrabPointer(gdk_display, real_sw->xwindow, False,
2293 ButtonPressMask | ButtonReleaseMask,
2294 GrabModeAsync, GrabModeAsync, gdk_root_window,
2296 gdk_dnd.dnd_grabbed = TRUE;
2297 gdk_dnd.drag_really = 1;
2298 gdk_dnd_display_drag_cursor(xevent->xmotion.x_root,
2299 xevent->xmotion.y_root,
2303 return_val = window_private && !window_private->destroyed;
2308 /* We only care about focus events that indicate that _this_
2309 * window (not a ancestor or child) got or lost the focus
2311 switch (xevent->xfocus.detail)
2313 case NotifyAncestor:
2314 case NotifyInferior:
2315 case NotifyNonlinear:
2316 /* Print debugging info.
2319 g_print ("focus %s:\t\twindow: %ld\n",
2320 (xevent->xany.type == FocusIn) ? "in" : "out",
2321 xevent->xfocus.window - base_id));
2323 event->focus_change.type = GDK_FOCUS_CHANGE;
2324 event->focus_change.window = window;
2325 event->focus_change.in = (xevent->xany.type == FocusIn);
2327 return_val = window_private && !window_private->destroyed;
2335 /* Print debugging info.
2338 g_print ("keymap notify\n"));
2340 /* Not currently handled */
2344 /* Print debugging info.
2347 g_print ("expose:\t\twindow: %ld %d x,y: %d %d w,h: %d %d\n",
2348 xevent->xexpose.window - base_id, xevent->xexpose.count,
2349 xevent->xexpose.x, xevent->xexpose.y,
2350 xevent->xexpose.width, xevent->xexpose.height));
2352 event->expose.type = GDK_EXPOSE;
2353 event->expose.window = window;
2354 event->expose.area.x = xevent->xexpose.x;
2355 event->expose.area.y = xevent->xexpose.y;
2356 event->expose.area.width = xevent->xexpose.width;
2357 event->expose.area.height = xevent->xexpose.height;
2358 event->expose.count = xevent->xexpose.count;
2360 return_val = window_private && !window_private->destroyed;
2363 case GraphicsExpose:
2364 /* Print debugging info.
2367 g_print ("graphics expose:\tdrawable: %ld\n",
2368 xevent->xgraphicsexpose.drawable - base_id));
2370 event->expose.type = GDK_EXPOSE;
2371 event->expose.window = window;
2372 event->expose.area.x = xevent->xgraphicsexpose.x;
2373 event->expose.area.y = xevent->xgraphicsexpose.y;
2374 event->expose.area.width = xevent->xgraphicsexpose.width;
2375 event->expose.area.height = xevent->xgraphicsexpose.height;
2376 event->expose.count = xevent->xexpose.count;
2378 return_val = window_private && !window_private->destroyed;
2382 /* Print debugging info.
2385 g_print ("no expose:\t\tdrawable: %ld\n",
2386 xevent->xnoexpose.drawable - base_id));
2388 event->no_expose.type = GDK_NO_EXPOSE;
2389 event->no_expose.window = window;
2391 return_val = window_private && !window_private->destroyed;
2394 case VisibilityNotify:
2395 /* Print debugging info.
2397 #ifdef G_ENABLE_DEBUG
2398 if (gdk_debug_flags & GDK_DEBUG_EVENTS)
2399 switch (xevent->xvisibility.state)
2401 case VisibilityFullyObscured:
2402 g_print ("visibility notify:\twindow: %ld none\n",
2403 xevent->xvisibility.window - base_id);
2405 case VisibilityPartiallyObscured:
2406 g_print ("visibility notify:\twindow: %ld partial\n",
2407 xevent->xvisibility.window - base_id);
2409 case VisibilityUnobscured:
2410 g_print ("visibility notify:\twindow: %ld full\n",
2411 xevent->xvisibility.window - base_id);
2414 #endif /* G_ENABLE_DEBUG */
2416 event->visibility.type = GDK_VISIBILITY_NOTIFY;
2417 event->visibility.window = window;
2419 switch (xevent->xvisibility.state)
2421 case VisibilityFullyObscured:
2422 event->visibility.state = GDK_VISIBILITY_FULLY_OBSCURED;
2425 case VisibilityPartiallyObscured:
2426 event->visibility.state = GDK_VISIBILITY_PARTIAL;
2429 case VisibilityUnobscured:
2430 event->visibility.state = GDK_VISIBILITY_UNOBSCURED;
2434 return_val = window_private && !window_private->destroyed;
2438 /* Not currently handled */
2442 /* Print debugging info.
2445 g_print ("destroy notify:\twindow: %ld\n",
2446 xevent->xdestroywindow.window - base_id));
2448 event->any.type = GDK_DESTROY;
2449 event->any.window = window;
2451 return_val = window_private && !window_private->destroyed;
2453 gdk_window_destroy_notify (window);
2457 /* Print debugging info.
2460 g_print ("unmap notify:\t\twindow: %ld\n",
2461 xevent->xmap.window - base_id));
2463 event->any.type = GDK_UNMAP;
2464 event->any.window = window;
2466 if (xgrab_window == window_private)
2467 xgrab_window = NULL;
2469 return_val = window_private && !window_private->destroyed;
2473 /* Print debugging info.
2476 g_print ("map notify:\t\twindow: %ld\n",
2477 xevent->xmap.window - base_id));
2479 event->any.type = GDK_MAP;
2480 event->any.window = window;
2482 return_val = window_private && !window_private->destroyed;
2485 case ReparentNotify:
2486 /* Print debugging info.
2489 g_print ("reparent notify:\twindow: %ld\n",
2490 xevent->xreparent.window - base_id));
2492 /* Not currently handled */
2495 case ConfigureNotify:
2496 /* Print debugging info.
2498 while ((XPending (gdk_display) > 0) &&
2499 XCheckTypedWindowEvent(gdk_display, xevent->xany.window,
2500 ConfigureNotify, xevent))
2501 /*XSync (gdk_display, 0)*/;
2504 g_print ("configure notify:\twindow: %ld x,y: %d %d w,h: %d %d b-w: %d above: %ld ovr: %d\n",
2505 xevent->xconfigure.window - base_id,
2506 xevent->xconfigure.x,
2507 xevent->xconfigure.y,
2508 xevent->xconfigure.width,
2509 xevent->xconfigure.height,
2510 xevent->xconfigure.border_width,
2511 xevent->xconfigure.above - base_id,
2512 xevent->xconfigure.override_redirect));
2516 if ((window_private->extension_events != 0) &&
2517 gdk_input_vtable.configure_event)
2518 gdk_input_vtable.configure_event (&xevent->xconfigure, window);
2520 if (window_private->window_type != GDK_WINDOW_CHILD)
2522 event->configure.type = GDK_CONFIGURE;
2523 event->configure.window = window;
2524 event->configure.width = xevent->xconfigure.width;
2525 event->configure.height = xevent->xconfigure.height;
2527 if (!xevent->xconfigure.x &&
2528 !xevent->xconfigure.y)
2532 Window child_window = 0;
2534 if (!XTranslateCoordinates (window_private->xdisplay,
2535 window_private->xwindow,
2540 g_warning ("GdkWindow %ld doesn't share root windows display?",
2541 window_private->xwindow - base_id);
2542 event->configure.x = tx;
2543 event->configure.y = ty;
2547 event->configure.x = xevent->xconfigure.x;
2548 event->configure.y = xevent->xconfigure.y;
2550 window_private->x = event->configure.x;
2551 window_private->y = event->configure.y;
2552 window_private->width = xevent->xconfigure.width;
2553 window_private->height = xevent->xconfigure.height;
2554 if (window_private->resize_count > 1)
2555 window_private->resize_count -= 1;
2557 return_val = !window_private->destroyed;
2562 case PropertyNotify:
2563 /* Print debugging info.
2566 g_print ("property notify:\twindow: %ld\n",
2567 xevent->xproperty.window - base_id));
2569 event->property.type = GDK_PROPERTY_NOTIFY;
2570 event->property.window = window;
2571 event->property.atom = xevent->xproperty.atom;
2572 event->property.time = xevent->xproperty.time;
2573 event->property.state = xevent->xproperty.state;
2575 return_val = window_private && !window_private->destroyed;
2578 case SelectionClear:
2580 g_print ("selection clear:\twindow: %ld\n",
2581 xevent->xproperty.window - base_id));
2583 event->selection.type = GDK_SELECTION_CLEAR;
2584 event->selection.window = window;
2585 event->selection.selection = xevent->xselectionclear.selection;
2586 event->selection.time = xevent->xselectionclear.time;
2588 return_val = window_private && !window_private->destroyed;
2591 case SelectionRequest:
2593 g_print ("selection request:\twindow: %ld\n",
2594 xevent->xproperty.window - base_id));
2596 event->selection.type = GDK_SELECTION_REQUEST;
2597 event->selection.window = window;
2598 event->selection.selection = xevent->xselectionrequest.selection;
2599 event->selection.target = xevent->xselectionrequest.target;
2600 event->selection.property = xevent->xselectionrequest.property;
2601 event->selection.requestor = xevent->xselectionrequest.requestor;
2602 event->selection.time = xevent->xselectionrequest.time;
2604 return_val = window_private && !window_private->destroyed;
2607 case SelectionNotify:
2609 g_print ("selection notify:\twindow: %ld\n",
2610 xevent->xproperty.window - base_id));
2613 event->selection.type = GDK_SELECTION_NOTIFY;
2614 event->selection.window = window;
2615 event->selection.selection = xevent->xselection.selection;
2616 event->selection.target = xevent->xselection.target;
2617 event->selection.property = xevent->xselection.property;
2618 event->selection.time = xevent->xselection.time;
2620 return_val = window_private && !window_private->destroyed;
2623 case ColormapNotify:
2624 /* Print debugging info.
2627 g_print ("colormap notify:\twindow: %ld\n",
2628 xevent->xcolormap.window - base_id));
2630 /* Not currently handled */
2634 /* Print debugging info.
2637 g_print ("client message:\twindow: %ld\n",
2638 xevent->xclient.window - base_id));
2640 /* Client messages are the means of the window manager
2641 * communicating with a program. We'll first check to
2642 * see if this is really the window manager talking
2645 if (xevent->xclient.message_type == gdk_wm_protocols)
2647 if ((Atom) xevent->xclient.data.l[0] == gdk_wm_delete_window)
2649 /* The delete window request specifies a window
2650 * to delete. We don't actually destroy the
2651 * window because "it is only a request". (The
2652 * window might contain vital data that the
2653 * program does not want destroyed). Instead
2654 * the event is passed along to the program,
2655 * which should then destroy the window.
2658 /* Print debugging info.
2661 g_print ("delete window:\t\twindow: %ld\n",
2662 xevent->xclient.window - base_id));
2664 event->any.type = GDK_DELETE;
2665 event->any.window = window;
2667 return_val = window_private && !window_private->destroyed;
2669 else if ((Atom) xevent->xclient.data.l[0] == gdk_wm_take_focus)
2673 else if (xevent->xclient.message_type == gdk_dnd.gdk_XdeEnter)
2677 event->dropenter.u.allflags = xevent->xclient.data.l[1];
2679 GDK_NOTE (DND, g_print ("GDK_DROP_ENTER [%d][%d]\n",
2680 window_private->dnd_drop_enabled, event->dropenter.u.flags.sendreply));
2683 /* Now figure out if we really want this drop...
2684 * If someone is trying funky clipboard stuff, ignore
2687 && window_private->dnd_drop_enabled
2688 && event->dropenter.u.flags.sendreply
2689 && (reptype = gdk_dnd_check_types (window, xevent)))
2693 replyev.xclient.type = ClientMessage;
2694 replyev.xclient.window = xevent->xclient.data.l[0];
2695 replyev.xclient.format = 32;
2696 replyev.xclient.message_type = gdk_dnd.gdk_XdeRequest;
2697 replyev.xclient.data.l[0] = window_private->xwindow;
2699 event->dragrequest.u.allflags = 0;
2700 event->dragrequest.u.flags.protocol_version =
2701 DND_PROTOCOL_VERSION;
2702 event->dragrequest.u.flags.willaccept = 1;
2703 event->dragrequest.u.flags.delete_data =
2704 (window_private->dnd_drop_destructive_op) ? 1 : 0;
2706 replyev.xclient.data.l[1] = event->dragrequest.u.allflags;
2707 replyev.xclient.data.l[2] = replyev.xclient.data.l[3] = 0;
2708 replyev.xclient.data.l[4] = reptype;
2710 XSendEvent (gdk_display, replyev.xclient.window,
2711 False, NoEventMask, &replyev);
2713 event->any.type = GDK_DROP_ENTER;
2714 event->any.window = window;
2715 event->dropenter.requestor = replyev.xclient.window;
2716 event->dropenter.u.allflags = xevent->xclient.data.l[1];
2718 GDK_NOTE (DND, g_print("We sent a GDK_DROP_ENTER on to Gtk\n"));
2722 else if (xevent->xclient.message_type == gdk_dnd.gdk_XdeLeave)
2724 #ifdef G_ENABLE_DEBUG
2725 if (gdk_debug_flags & (GDK_DEBUG_EVENTS | GDK_DEBUG_DND))
2726 g_print ("GDK_DROP_LEAVE\n");
2729 if (window_private && window_private->dnd_drop_enabled)
2731 event->dropleave.type = GDK_DROP_LEAVE;
2732 event->dropleave.window = window;
2733 event->dropleave.requestor = xevent->xclient.data.l[0];
2734 event->dropleave.u.allflags = xevent->xclient.data.l[1];
2740 else if (xevent->xclient.message_type == gdk_dnd.gdk_XdeRequest)
2743 * make sure to only handle requests from the window the cursor is
2746 #ifdef G_ENABLE_DEBUG
2747 if (gdk_debug_flags & (GDK_DEBUG_EVENTS | GDK_DEBUG_DND))
2748 g_print ("GDK_DRAG_REQUEST\n");
2750 event->dragrequest.u.allflags = xevent->xclient.data.l[1];
2753 if (window && gdk_dnd.drag_really &&
2754 xevent->xclient.data.l[0] == dnd_drag_curwin &&
2755 event->dragrequest.u.flags.sendreply == 0)
2757 /* Got request - do we need to ask user? */
2758 if (!event->dragrequest.u.flags.willaccept
2759 && event->dragrequest.u.flags.senddata)
2762 event->dragrequest.type = GDK_DRAG_REQUEST;
2763 event->dragrequest.window = window;
2764 event->dragrequest.requestor = xevent->xclient.data.l[0];
2765 event->dragrequest.isdrop = 0;
2766 event->dragrequest.drop_coords.x =
2767 event->dragrequest.drop_coords.y = 0;
2770 else if (event->dragrequest.u.flags.willaccept)
2772 window_private->dnd_drag_destructive_op =
2773 event->dragrequest.u.flags.delete_data;
2774 window_private->dnd_drag_accepted = 1;
2775 window_private->dnd_drag_data_type =
2776 xevent->xclient.data.l[4];
2778 gdk_dnd.dnd_drag_target = dnd_drag_curwin;
2779 gdk_dnd_display_drag_cursor(-1, -1, TRUE, TRUE);
2781 dnd_drag_dropzone.x = xevent->xclient.data.l[2] & 65535;
2782 dnd_drag_dropzone.y =
2783 (xevent->xclient.data.l[2] >> 16) & 65535;
2784 dnd_drag_dropzone.width = xevent->xclient.data.l[3] & 65535;
2785 dnd_drag_dropzone.height =
2786 (xevent->xclient.data.l[3] >> 16) & 65535;
2789 else if(xevent->xclient.message_type == gdk_dnd.gdk_XdeDataAvailable)
2791 gint tmp_int; Atom tmp_atom;
2793 guchar *tmp_charptr;
2795 #ifdef G_ENABLE_DEBUG
2796 if (gdk_debug_flags & (GDK_DEBUG_EVENTS | GDK_DEBUG_DND))
2797 g_print("GDK_DROP_DATA_AVAIL\n");
2799 event->dropdataavailable.u.allflags = xevent->xclient.data.l[1];
2801 /* No preview of data ATM */
2802 && event->dropdataavailable.u.flags.isdrop)
2804 event->dropdataavailable.type = GDK_DROP_DATA_AVAIL;
2805 event->dropdataavailable.window = window;
2806 event->dropdataavailable.requestor = xevent->xclient.data.l[0];
2807 event->dropdataavailable.data_type =
2808 gdk_atom_name(xevent->xclient.data.l[2]);
2809 if(XGetWindowProperty (gdk_display,
2810 event->dropdataavailable.requestor,
2811 xevent->xclient.data.l[2],
2813 False, XA_PRIMARY, &tmp_atom,
2815 &event->dropdataavailable.data_numbytes,
2820 g_warning("XGetWindowProperty on %#x may have failed\n",
2821 event->dropdataavailable.requestor);
2822 event->dropdataavailable.data = NULL;
2826 GDK_NOTE (DND, g_print("XGetWindowProperty got us %ld bytes\n",
2827 event->dropdataavailable.data_numbytes));
2828 event->dropdataavailable.data =
2829 g_malloc (event->dropdataavailable.data_numbytes);
2830 memcpy (event->dropdataavailable.data,
2831 tmp_charptr, event->dropdataavailable.data_numbytes);
2840 /* Send unknown ClientMessage's on to Gtk for it to use */
2841 event->client.type = GDK_CLIENT_EVENT;
2842 event->client.window = window;
2843 event->client.message_type = xevent->xclient.message_type;
2844 event->client.data_format = xevent->xclient.format;
2845 memcpy(&event->client.data, &xevent->xclient.data,
2846 sizeof(event->client.data));
2853 return_val = return_val && !window_private->destroyed;
2857 /* Print debugging info.
2860 g_print ("mapping notify\n"));
2862 /* Let XLib know that there is a new keyboard mapping.
2864 XRefreshKeyboardMapping (&xevent->xmapping);
2868 /* something else - (e.g., a Xinput event) */
2870 if (window_private &&
2871 (window_private->extension_events != 0) &&
2872 gdk_input_vtable.other_event)
2873 return_val = gdk_input_vtable.other_event(event, xevent, window);
2877 if (return_val < 0) /* not an XInput event, convert */
2879 event->other.type = GDK_OTHER_EVENT;
2880 event->other.window = window;
2881 event->other.xevent = (GdkXEvent *)&other_xevent[other_xevent_i];
2882 memcpy (&other_xevent[other_xevent_i], xevent, sizeof (XEvent));
2883 other_xevent_i = (other_xevent_i+1) % OTHER_XEVENT_BUFSIZE;
2887 return_val = return_val && !window_private->destroyed;
2894 if (event->any.window)
2895 gdk_window_ref (event->any.window);
2896 if (((event->any.type == GDK_ENTER_NOTIFY) ||
2897 (event->any.type == GDK_LEAVE_NOTIFY)) &&
2898 (event->crossing.subwindow != NULL))
2899 gdk_window_ref (event->crossing.subwindow);
2903 /* Mark this event as having no resources to be freed */
2904 event->any.window = NULL;
2905 event->any.type = GDK_NOTHING;
2909 gdk_window_unref (window);
2916 gdk_event_get_type (Display *display,
2923 if (gdk_event_translate (&event, xevent))
2925 pred = (GdkPredicate*) arg;
2926 return (* pred->func) (&event, pred->data);
2934 gdk_synthesize_click (GdkEvent *event,
2937 GdkEvent temp_event;
2939 g_return_if_fail (event != NULL);
2941 temp_event = *event;
2942 temp_event.type = (nclicks == 2) ? GDK_2BUTTON_PRESS : GDK_3BUTTON_PRESS;
2944 gdk_event_put (&temp_event);
2948 *--------------------------------------------------------------
2951 * This is the "atexit" function that makes sure the
2952 * library gets a chance to cleanup.
2959 * The library is un-initialized and the program exits.
2961 *--------------------------------------------------------------
2967 static gboolean in_gdk_exit_func = FALSE;
2969 /* This is to avoid an infinite loop if a program segfaults in
2970 an atexit() handler (and yes, it does happen, especially if a program
2971 has trounced over memory too badly for even g_print to work) */
2972 if(in_gdk_exit_func == TRUE) return;
2973 in_gdk_exit_func = TRUE;
2985 gdk_key_repeat_restore ();
2987 XCloseDisplay (gdk_display);
2993 *--------------------------------------------------------------
2996 * The X error handling routine.
2999 * "display" is the X display the error orignated from.
3000 * "error" is the XErrorEvent that we are handling.
3003 * Either we were expecting some sort of error to occur,
3004 * in which case we set the "gdk_error_code" flag, or this
3005 * error was unexpected, in which case we will print an
3006 * error message and exit. (Since trying to continue will
3007 * most likely simply lead to more errors).
3011 *--------------------------------------------------------------
3015 gdk_x_error (Display *display,
3020 if (gdk_error_warnings)
3022 XGetErrorText (display, error->error_code, buf, 63);
3023 g_error ("%s", buf);
3026 gdk_error_code = -1;
3031 *--------------------------------------------------------------
3034 * The X I/O error handling routine.
3037 * "display" is the X display the error orignated from.
3040 * An X I/O error basically means we lost our connection
3041 * to the X server. There is not much we can do to
3042 * continue, so simply print an error message and exit.
3046 *--------------------------------------------------------------
3050 gdk_x_io_error (Display *display)
3052 g_error ("an x io error occurred");
3057 *--------------------------------------------------------------
3060 * The signal handler.
3063 * "sig_num" is the number of the signal we received.
3066 * The signals we catch are all fatal. So we simply build
3067 * up a nice little error message and print it and exit.
3068 * If in the process of doing so another signal is received
3069 * we notice that we are already exiting and simply kill
3074 *--------------------------------------------------------------
3078 gdk_signal (int sig_num)
3080 static int caught_fatal_sig = 0;
3083 if (caught_fatal_sig)
3084 kill (getpid (), sig_num);
3085 caught_fatal_sig = 1;
3111 sig = "unknown signal";
3115 g_print ("\n** ERROR **: %s caught\n", sig);
3120 gdk_dnd_drag_begin (GdkWindow *initial_window)
3122 GdkEventDragBegin tev;
3123 tev.type = GDK_DRAG_BEGIN;
3124 tev.window = initial_window;
3126 tev.u.flags.protocol_version = DND_PROTOCOL_VERSION;
3128 gdk_event_put ((GdkEvent *) &tev);
3132 gdk_dnd_drag_enter (Window dest)
3135 GdkEventDropEnter tev;
3137 GdkWindowPrivate *wp;
3139 sev.xclient.type = ClientMessage;
3140 sev.xclient.format = 32;
3141 sev.xclient.message_type = gdk_dnd.gdk_XdeEnter;
3142 sev.xclient.window = dest;
3145 tev.u.flags.protocol_version = DND_PROTOCOL_VERSION;
3146 tev.u.flags.sendreply = 1;
3147 for (i = 0; i < gdk_dnd.drag_numwindows; i++)
3149 wp = (GdkWindowPrivate *) gdk_dnd.drag_startwindows[i];
3150 if (wp->dnd_drag_data_numtypesavail)
3152 sev.xclient.data.l[0] = wp->xwindow;
3153 tev.u.flags.extended_typelist = (wp->dnd_drag_data_numtypesavail > 3)?1:0;
3154 sev.xclient.data.l[1] = tev.u.allflags;
3155 sev.xclient.data.l[2] = wp->dnd_drag_data_typesavail[0];
3156 if (wp->dnd_drag_data_numtypesavail > 1)
3158 sev.xclient.data.l[3] = wp->dnd_drag_data_typesavail[1];
3159 if (wp->dnd_drag_data_numtypesavail > 2)
3161 sev.xclient.data.l[4] = wp->dnd_drag_data_typesavail[2];
3164 sev.xclient.data.l[4] = None;
3167 sev.xclient.data.l[3] = sev.xclient.data.l[4] = None;
3168 XSendEvent (gdk_display, dest, False, NoEventMask, &sev);
3178 *--------------------------------------------------------------
3181 * Begin using input method with XIM Protocol(X11R6 standard)
3184 * "ic" is the "Input Context" which is created by gtk_ic_new.
3185 * The input area is specified with "window".
3188 * The gdk's event handling routine is switched to XIM based routine.
3189 * XIM based routine uses XFilterEvent to get rid of events used by IM,
3190 * and uses XmbLookupString instead of XLookupString.
3194 *--------------------------------------------------------------
3198 gdk_im_begin (GdkIC ic, GdkWindow* window)
3200 GdkICPrivate *private;
3203 g_return_if_fail (ic != NULL);
3204 g_return_if_fail (window);
3206 private = (GdkICPrivate *) ic;
3210 xim_window = window;
3213 XGetICValues (private->xic, XNFocusWindow, &xwin, NULL);
3214 if (xwin != GDK_WINDOW_XWINDOW(window))
3215 XSetICValues (private->xic, XNFocusWindow,
3216 GDK_WINDOW_XWINDOW(window), NULL);
3217 if (private != xim_ic)
3218 XSetICFocus (private->xic);
3223 *--------------------------------------------------------------
3226 * End using input method with XIM Protocol(X11R6 standard)
3231 * The gdk's event handling routine is switched to normal routine.
3232 * User should call this function before ic and window will be destroyed.
3236 *--------------------------------------------------------------
3254 gdk_im_choose_better_style (GdkIMStyle style1, GdkIMStyle style2)
3256 GdkIMStyle s1, s2, u;
3258 if (style1 == 0) return style2;
3259 if (style2 == 0) return style1;
3260 if ((style1 & (GdkIMPreeditMask | GdkIMStatusMask))
3261 == (style2 & (GdkIMPreeditMask | GdkIMStatusMask)))
3264 s1 = style1 & GdkIMPreeditMask;
3265 s2 = style2 & GdkIMPreeditMask;
3268 if (u & GdkIMPreeditCallbacks)
3269 return (s1 == GdkIMPreeditCallbacks)? style1:style2;
3270 else if (u & GdkIMPreeditPosition)
3271 return (s1 == GdkIMPreeditPosition)? style1:style2;
3272 else if (u & GdkIMPreeditArea)
3273 return (s1 == GdkIMPreeditArea)? style1:style2;
3274 else if (u & GdkIMPreeditNothing)
3275 return (s1 == GdkIMPreeditNothing)? style1:style2;
3277 s1 = style1 & GdkIMStatusMask;
3278 s2 = style2 & GdkIMStatusMask;
3280 if ( u & GdkIMStatusCallbacks)
3281 return (s1 == GdkIMStatusCallbacks)? style1:style2;
3282 else if ( u & GdkIMStatusArea)
3283 return (s1 == GdkIMStatusArea)? style1:style2;
3284 else if ( u & GdkIMStatusNothing)
3285 return (s1 == GdkIMStatusNothing)? style1:style2;
3286 else if ( u & GdkIMStatusNone)
3287 return (s1 == GdkIMStatusNone)? style1:style2;
3289 return 0; /* Get rid of stupid warning */
3293 gdk_im_decide_style (GdkIMStyle supported_style)
3296 GdkIMStyle style, tmp;
3298 g_return_val_if_fail (xim_styles != NULL, 0);
3301 for (i=0; i<xim_styles->count_styles; i++)
3303 tmp = xim_styles->supported_styles[i];
3304 if (tmp == (tmp & supported_style & xim_best_allowed_style))
3305 style = gdk_im_choose_better_style (style, tmp);
3311 gdk_im_set_best_style (GdkIMStyle style)
3313 if (style & GdkIMPreeditMask)
3315 xim_best_allowed_style &= ~GdkIMPreeditMask;
3317 xim_best_allowed_style |= GdkIMPreeditNone;
3318 if (!(style & GdkIMPreeditNone))
3320 xim_best_allowed_style |= GdkIMPreeditNothing;
3321 if (!(style & GdkIMPreeditNothing))
3323 xim_best_allowed_style |= GdkIMPreeditArea;
3324 if (!(style & GdkIMPreeditArea))
3326 xim_best_allowed_style |= GdkIMPreeditPosition;
3327 if (!(style & GdkIMPreeditPosition))
3328 xim_best_allowed_style |= GdkIMPreeditCallbacks;
3333 if (style & GdkIMStatusMask)
3335 xim_best_allowed_style &= ~GdkIMStatusMask;
3337 xim_best_allowed_style |= GdkIMStatusNone;
3338 if (!(style & GdkIMStatusNone))
3340 xim_best_allowed_style |= GdkIMStatusNothing;
3341 if (!(style & GdkIMStatusNothing))
3343 xim_best_allowed_style |= GdkIMStatusArea;
3344 if (!(style & GdkIMStatusArea))
3345 xim_best_allowed_style |= GdkIMStatusCallbacks;
3350 return xim_best_allowed_style;
3354 gdk_im_open (XrmDatabase db, gchar* res_name, gchar* res_class)
3356 xim_im = XOpenIM (GDK_DISPLAY(), db, res_name, res_class);
3359 GDK_NOTE (XIM, g_warning ("Unable to open open IM."));
3362 XGetIMValues (xim_im, XNQueryInputStyle, &xim_styles, NULL, NULL);
3385 return (xim_im != NULL);
3389 gdk_ic_new (GdkWindow* client_window,
3390 GdkWindow* focus_window,
3391 GdkIMStyle style, ...)
3394 GdkICPrivate *private;
3395 XVaNestedList preedit_attr;
3397 g_return_val_if_fail (client_window != NULL, NULL);
3398 g_return_val_if_fail (focus_window != NULL, NULL);
3399 g_return_val_if_fail (gdk_im_ready(), NULL);
3401 private = g_new (GdkICPrivate, 1);
3403 va_start (list, style);
3404 preedit_attr = (XVaNestedList) & (va_arg (list, void *));
3407 private->style = gdk_im_decide_style (style);
3408 if (private->style != style)
3410 g_warning ("can not create input context with specified input style.");
3415 private->xic = XCreateIC(gdk_im_get (),
3416 XNInputStyle, style,
3417 XNClientWindow, GDK_WINDOW_XWINDOW (client_window),
3418 XNFocusWindow, GDK_WINDOW_XWINDOW (focus_window),
3419 preedit_attr? XNPreeditAttributes : NULL, preedit_attr,
3427 xim_ic_list = g_list_append (xim_ic_list, private);
3432 gdk_ic_destroy (GdkIC ic)
3434 GdkICPrivate *private;
3436 g_return_if_fail (ic != NULL);
3438 private = (GdkICPrivate *) ic;
3440 if (xim_ic == private)
3443 XDestroyIC (private->xic);
3444 xim_ic_list = g_list_remove (xim_ic_list, private);
3448 gdk_ic_get_style (GdkIC ic)
3450 GdkICPrivate *private;
3452 g_return_val_if_fail (ic != NULL, 0);
3454 private = (GdkICPrivate *) ic;
3456 return private->style;
3460 gdk_ic_set_values (GdkIC ic, ...)
3464 GdkICPrivate *private;
3466 g_return_if_fail (ic != NULL);
3468 private = (GdkICPrivate *) ic;
3470 va_start (list, ic);
3471 args = (XVaNestedList) & (va_arg (list, void *));
3474 XSetICValues (private->xic, XNVaNestedList, args, NULL);
3478 gdk_ic_get_values (GdkIC ic, ...)
3482 GdkICPrivate *private;
3484 g_return_if_fail (ic != NULL);
3486 private = (GdkICPrivate *) ic;
3488 va_start (list, ic);
3489 args = (XVaNestedList) & (va_arg (list, void *));
3492 XGetICValues (private->xic, XNVaNestedList, args, NULL);
3496 gdk_ic_set_attr (GdkIC ic, const char *target, ...)
3500 GdkICPrivate *private;
3502 g_return_if_fail (ic != NULL);
3503 g_return_if_fail (target != NULL);
3505 private = (GdkICPrivate *) ic;
3507 va_start (list, target);
3508 attr = (XVaNestedList) & (va_arg (list, void *));
3511 XSetICValues (private->xic, target, attr, NULL);
3515 gdk_ic_get_attr (GdkIC ic, const char *target, ...)
3519 GdkICPrivate *private;
3521 g_return_if_fail (ic != NULL);
3522 g_return_if_fail (target != NULL);
3524 private = (GdkICPrivate *) ic;
3526 va_start (list, target);
3527 attr = (XVaNestedList) & (va_arg (list, void *));
3530 XGetICValues (private->xic, target, attr, NULL);
3534 gdk_ic_get_events (GdkIC ic)
3539 GdkICPrivate *private;
3542 /* From gdkwindow.c */
3543 extern int nevent_masks;
3544 extern int event_mask_table[];
3546 g_return_val_if_fail (ic != NULL, 0);
3548 private = (GdkICPrivate *) ic;
3550 if (XGetICValues (private->xic, XNFilterEvents, &xmask, NULL) != NULL)
3552 GDK_NOTE (XIM, g_warning ("Call to XGetICValues: %s failed", XNFilterEvents));
3557 for (i=0, bit=2; i < nevent_masks; i++, bit <<= 1)
3558 if (xmask & event_mask_table [i])
3561 xmask &= ~ event_mask_table [i];
3565 g_warning ("ic requires events not supported by the application (%#04lx)", xmask);
3571 gdk_ic_cleanup (void)
3575 GdkICPrivate *private;
3578 for (node = xim_ic_list; node != NULL; node = node->next)
3582 private = (GdkICPrivate *) (node->data);
3583 XDestroyIC (private->xic);
3588 #ifdef G_ENABLE_DEBUG
3589 if ((gdk_debug_flags & GDK_DEBUG_XIM) && destroyed > 0)
3591 g_warning ("Cleaned up %i IC(s)\n", destroyed);
3593 #endif /* G_ENABLE_DEBUG */
3594 g_list_free(xim_ic_list);
3598 #else /* !USE_XIM */
3601 gdk_im_begin (GdkIC ic, GdkWindow* window)
3611 gdk_im_decide_style (GdkIMStyle supported_style)
3613 return GdkIMPreeditNone | GdkIMStatusNone;
3617 gdk_im_set_best_style (GdkIMStyle style)
3619 return GdkIMPreeditNone | GdkIMStatusNone;
3629 gdk_ic_new (GdkWindow* client_window,
3630 GdkWindow* focus_window,
3631 GdkIMStyle style, ...)
3637 gdk_ic_destroy (GdkIC ic)
3642 gdk_ic_get_style (GdkIC ic)
3644 return GdkIMPreeditNone | GdkIMStatusNone;
3648 gdk_ic_set_values (GdkIC ic, ...)
3653 gdk_ic_get_values (GdkIC ic, ...)
3658 gdk_ic_set_attr (GdkIC ic, const char *target, ...)
3663 gdk_ic_get_attr (GdkIC ic, const char *target, ...)
3668 gdk_ic_get_events (GdkIC ic)
3673 #endif /* USE_XIM */
3678 _g_mbtowc (wchar_t *wstr, const char *str, size_t len)
3680 static wchar_t wcs[MB_CUR_MAX + 1];
3681 static gchar mbs[MB_CUR_MAX + 1];
3683 wcs[0] = (wchar_t) NULL;
3686 len = _Xmbstowcs (wcs, str, (len<MB_CUR_MAX)? len:MB_CUR_MAX);
3689 else if (wcs[0] == (wchar_t) NULL)
3692 len = _Xwctomb (mbs, wcs[0]);
3701 #endif /* X_LOCALE */
3704 gdk_dnd_drag_leave (Window dest)
3707 GdkEventDropLeave tev;
3709 GdkWindowPrivate *wp;
3713 tev.u.flags.protocol_version = DND_PROTOCOL_VERSION;
3714 sev.xclient.type = ClientMessage;
3715 sev.xclient.window = dest;
3716 sev.xclient.format = 32;
3717 sev.xclient.message_type = gdk_dnd.gdk_XdeLeave;
3718 sev.xclient.data.l[1] = tev.u.allflags;
3719 for (i = 0; i < gdk_dnd.drag_numwindows; i++)
3721 wp = (GdkWindowPrivate *) gdk_dnd.drag_startwindows[i];
3722 sev.xclient.data.l[0] = wp->xwindow;
3723 XSendEvent(gdk_display, dest, False, NoEventMask, &sev);
3724 wp->dnd_drag_accepted = 0;
3729 * when a drop occurs, we go through the list of windows being dragged and
3730 * tell them that it has occurred, so that they can set things up and reply
3734 gdk_dnd_drag_end (Window dest,
3737 GdkWindowPrivate *wp;
3738 GdkEventDragRequest tev;
3741 tev.type = GDK_DRAG_REQUEST;
3742 tev.drop_coords = coords;
3743 tev.requestor = dest;
3745 tev.u.flags.protocol_version = DND_PROTOCOL_VERSION;
3748 for (i = 0; i < gdk_dnd.drag_numwindows; i++)
3750 wp = (GdkWindowPrivate *) gdk_dnd.drag_startwindows[i];
3751 if (wp->dnd_drag_accepted)
3753 tev.window = (GdkWindow *) wp;
3754 tev.u.flags.delete_data = wp->dnd_drag_destructive_op;
3756 gdk_atom_name(wp->dnd_drag_data_type);
3758 gdk_event_put((GdkEvent *) &tev);
3764 gdk_dnd_check_types (GdkWindow *window,
3767 GdkWindowPrivate *wp = (GdkWindowPrivate *) window;
3769 GdkEventDropEnter event;
3771 g_return_val_if_fail(window != NULL, 0);
3772 g_return_val_if_fail(xevent != NULL, 0);
3773 g_return_val_if_fail(xevent->type == ClientMessage, 0);
3774 g_return_val_if_fail(xevent->xclient.message_type == gdk_dnd.gdk_XdeEnter, 0);
3776 if(wp->dnd_drop_data_numtypesavail <= 0 ||
3777 !wp->dnd_drop_data_typesavail)
3780 for (i = 2; i <= 4; i++)
3782 for (j = 0; j < wp->dnd_drop_data_numtypesavail; j++)
3784 if (xevent->xclient.data.l[i] == wp->dnd_drop_data_typesavail[j])
3785 return xevent->xclient.data.l[i];
3789 /* Now we get the extended type list if it's available */
3790 event.u.allflags = xevent->xclient.data.l[1];
3791 if (event.u.flags.extended_typelist)
3793 Atom *exttypes, realtype;
3794 gulong nitems, nbar;
3797 if (XGetWindowProperty(gdk_display, xevent->xclient.data.l[0],
3798 gdk_dnd.gdk_XdeTypelist, 0L, LONG_MAX - 1,
3799 False, AnyPropertyType, &realtype, &realfmt,
3800 &nitems, &nbar, (unsigned char **) &exttypes)
3804 if (realfmt != (sizeof(Atom) * 8))
3806 g_warning("XdeTypelist property had format of %d instead of the expected %d, on window %#lx\n",
3807 realfmt, sizeof(Atom) * 8, xevent->xclient.data.l[0]);
3811 for (i = 0; i <= nitems; i++)
3813 for (j = 0; j < wp->dnd_drop_data_numtypesavail; j++)
3815 if (exttypes[i] == wp->dnd_drop_data_typesavail[j])
3828 * used for debugging only
3832 gdk_print_atom (GdkAtom anatom)
3834 gchar *tmpstr = NULL;
3835 tmpstr = (anatom!=None)?gdk_atom_name(anatom):"(none)";
3836 g_print("Atom %lu has name %s\n", anatom, tmpstr);
3843 * used only by below routine and itself
3846 getchildren (Display *dpy,
3850 Window root, parent, *children, inf = 0;
3852 unsigned int nchildren, i;
3854 unsigned long nitems, after;
3855 unsigned char *data;
3857 if (XQueryTree(dpy, win, &root, &parent, &children, &nchildren) == 0)
3860 for (i = 0; !inf && (i < nchildren); i++)
3862 XGetWindowProperty (dpy, children[i], WM_STATE, 0, 0, False,
3863 AnyPropertyType, &type, &format, &nitems,
3870 for (i = 0; !inf && (i < nchildren); i++)
3871 inf = getchildren (dpy, children[i], WM_STATE);
3873 if (children != None)
3874 XFree ((char *) children);
3880 * find a window with WM_STATE, else return win itself, as per ICCCM
3882 * modification of the XmuClientWindow() routine from X11R6.3
3885 gdk_get_client_window (Display *dpy,
3891 unsigned long nitems, after;
3892 unsigned char *data;
3896 return DefaultRootWindow(dpy);
3898 if ((WM_STATE = XInternAtom (dpy, "WM_STATE", True)) == 0)
3901 XGetWindowProperty (dpy, win, WM_STATE, 0, 0, False, AnyPropertyType,
3902 &type, &format, &nitems, &after, &data);
3906 inf = getchildren (dpy, win, WM_STATE);
3914 #ifdef WE_HAVE_MOTIF_DROPS_DONE
3916 gdk_drop_get_real_window (GdkWindow *w,
3920 GdkWindow *retval = w;
3921 GdkWindowPrivate *awin;
3923 gint16 myx = *x, myy = *y;
3925 g_return_val_if_fail(w != NULL && x != NULL && y != NULL, NULL);
3931 for (children = gdk_window_get_children(retval);
3932 children && children->next;
3933 children = children->next)
3935 awin = (GdkWindowPrivate *) children->data;
3936 if ((myx >= awin->x) && (myy >= awin->y)
3937 && (myx < (awin->x + awin->width))
3938 && (myy < (awin->y + awin->height)))
3940 retval = (GdkWindow *) awin;
3954 /* Sends a ClientMessage to all toplevel client windows */
3956 gdk_event_send_clientmessage_toall(GdkEvent *event)
3959 Window *ret_children, ret_root, ret_parent, curwin;
3960 unsigned int ret_nchildren;
3963 g_return_if_fail(event != NULL);
3965 /* Set up our event to send, with the exception of its target window */
3966 sev.xclient.type = ClientMessage;
3967 sev.xclient.display = gdk_display;
3968 sev.xclient.format = event->client.data_format;
3969 sev.xclient.serial = CurrentTime;
3970 memcpy(&sev.xclient.data, &event->client.data, sizeof(sev.xclient.data));
3971 sev.xclient.message_type = event->client.message_type;
3973 /* OK, we're all set, now let's find some windows to send this to */
3974 if(XQueryTree(gdk_display, gdk_root_window, &ret_root, &ret_parent,
3975 &ret_children, &ret_nchildren) != True)
3978 /* foreach true child window of the root window, send an event to it */
3979 for(i = 0; i < ret_nchildren; i++) {
3980 curwin = gdk_get_client_window(gdk_display, ret_children[i]);
3981 sev.xclient.window = curwin;
3982 XSendEvent(gdk_display, curwin, False, NoEventMask, &sev);
3985 XFree(ret_children);
3989 gdk_get_display(void)
3991 return (gchar *)XDisplayName (gdk_display_name);