1 | /* GTK - The GIMP Toolkit |
---|
2 | * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald |
---|
3 | * |
---|
4 | * This library is free software; you can redistribute it and/or |
---|
5 | * modify it under the terms of the GNU 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. |
---|
8 | * |
---|
9 | * This library is distributed in the hope that it will be useful, |
---|
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
---|
12 | * Library General Public License for more details. |
---|
13 | * |
---|
14 | * You should have received a copy of the GNU Library General Public |
---|
15 | * License along with this library; if not, write to the |
---|
16 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
---|
17 | * Boston, MA 02111-1307, USA. |
---|
18 | */ |
---|
19 | |
---|
20 | /* |
---|
21 | * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS |
---|
22 | * file for a list of people on the GTK+ Team. See the ChangeLog |
---|
23 | * files for a list of changes. These files are distributed with |
---|
24 | * GTK+ at ftp://ftp.gtk.org/pub/gtk/. |
---|
25 | */ |
---|
26 | |
---|
27 | #include <X11/Xlocale.h> /* so we get the right setlocale */ |
---|
28 | #include <errno.h> |
---|
29 | #include <stdio.h> |
---|
30 | #include <stdlib.h> |
---|
31 | #include <string.h> |
---|
32 | #include <sys/types.h> |
---|
33 | #include <unistd.h> /* For getuid() and friends */ |
---|
34 | #include <gmodule.h> |
---|
35 | #include "gtkbutton.h" |
---|
36 | #include "gtkdnd.h" |
---|
37 | #include "gtkfeatures.h" |
---|
38 | #include "gtkhscrollbar.h" |
---|
39 | #include "gtkhseparator.h" |
---|
40 | #include "gtkmain.h" |
---|
41 | #include "gtkpreview.h" |
---|
42 | #include "gtkrc.h" |
---|
43 | #include "gtkscrolledwindow.h" |
---|
44 | #include "gtkselection.h" |
---|
45 | #include "gtksignal.h" |
---|
46 | #include "gtktable.h" |
---|
47 | #include "gtktext.h" |
---|
48 | #include "gtkvbox.h" |
---|
49 | #include "gtkvscrollbar.h" |
---|
50 | #include "gtkwidget.h" |
---|
51 | #include "gtkwindow.h" |
---|
52 | #include "gtkprivate.h" |
---|
53 | #include "gdk/gdki18n.h" |
---|
54 | #include "config.h" |
---|
55 | #include "gtkdebug.h" |
---|
56 | #include "gtkintl.h" |
---|
57 | |
---|
58 | /* Private type definitions |
---|
59 | */ |
---|
60 | typedef struct _GtkInitFunction GtkInitFunction; |
---|
61 | typedef struct _GtkQuitFunction GtkQuitFunction; |
---|
62 | typedef struct _GtkClosure GtkClosure; |
---|
63 | typedef struct _GtkKeySnooperData GtkKeySnooperData; |
---|
64 | |
---|
65 | struct _GtkInitFunction |
---|
66 | { |
---|
67 | GtkFunction function; |
---|
68 | gpointer data; |
---|
69 | }; |
---|
70 | |
---|
71 | struct _GtkQuitFunction |
---|
72 | { |
---|
73 | guint id; |
---|
74 | guint main_level; |
---|
75 | GtkCallbackMarshal marshal; |
---|
76 | GtkFunction function; |
---|
77 | gpointer data; |
---|
78 | GtkDestroyNotify destroy; |
---|
79 | }; |
---|
80 | |
---|
81 | struct _GtkClosure |
---|
82 | { |
---|
83 | GtkCallbackMarshal marshal; |
---|
84 | gpointer data; |
---|
85 | GtkDestroyNotify destroy; |
---|
86 | }; |
---|
87 | |
---|
88 | struct _GtkKeySnooperData |
---|
89 | { |
---|
90 | GtkKeySnoopFunc func; |
---|
91 | gpointer func_data; |
---|
92 | guint id; |
---|
93 | }; |
---|
94 | |
---|
95 | static void gtk_exit_func (void); |
---|
96 | static gint gtk_quit_invoke_function (GtkQuitFunction *quitf); |
---|
97 | static void gtk_quit_destroy (GtkQuitFunction *quitf); |
---|
98 | static gint gtk_invoke_key_snoopers (GtkWidget *grab_widget, |
---|
99 | GdkEvent *event); |
---|
100 | |
---|
101 | static void gtk_destroy_closure (gpointer data); |
---|
102 | static gboolean gtk_invoke_idle_timeout (gpointer data); |
---|
103 | static void gtk_invoke_input (gpointer data, |
---|
104 | gint source, |
---|
105 | GdkInputCondition condition); |
---|
106 | |
---|
107 | #if 0 |
---|
108 | static void gtk_error (gchar *str); |
---|
109 | static void gtk_warning (gchar *str); |
---|
110 | static void gtk_message (gchar *str); |
---|
111 | static void gtk_print (gchar *str); |
---|
112 | #endif |
---|
113 | |
---|
114 | const guint gtk_major_version = GTK_MAJOR_VERSION; |
---|
115 | const guint gtk_minor_version = GTK_MINOR_VERSION; |
---|
116 | const guint gtk_micro_version = GTK_MICRO_VERSION; |
---|
117 | const guint gtk_binary_age = GTK_BINARY_AGE; |
---|
118 | const guint gtk_interface_age = GTK_INTERFACE_AGE; |
---|
119 | |
---|
120 | static guint gtk_main_loop_level = 0; |
---|
121 | static gint gtk_initialized = FALSE; |
---|
122 | static GList *current_events = NULL; |
---|
123 | |
---|
124 | static GSList *main_loops = NULL; /* stack of currently executing main loops */ |
---|
125 | |
---|
126 | static GSList *grabs = NULL; /* A stack of unique grabs. The grabbing |
---|
127 | * widget is the first one on the list. |
---|
128 | */ |
---|
129 | static GList *init_functions = NULL; /* A list of init functions. |
---|
130 | */ |
---|
131 | static GList *quit_functions = NULL; /* A list of quit functions. |
---|
132 | */ |
---|
133 | static GMemChunk *quit_mem_chunk = NULL; |
---|
134 | |
---|
135 | static GSList *key_snoopers = NULL; |
---|
136 | |
---|
137 | static GdkVisual *gtk_visual; /* The visual to be used in creating new |
---|
138 | * widgets. |
---|
139 | */ |
---|
140 | static GdkColormap *gtk_colormap; /* The colormap to be used in creating new |
---|
141 | * widgets. |
---|
142 | */ |
---|
143 | |
---|
144 | guint gtk_debug_flags = 0; /* Global GTK debug flag */ |
---|
145 | |
---|
146 | #ifdef G_ENABLE_DEBUG |
---|
147 | static const GDebugKey gtk_debug_keys[] = { |
---|
148 | {"objects", GTK_DEBUG_OBJECTS}, |
---|
149 | {"misc", GTK_DEBUG_MISC}, |
---|
150 | {"signals", GTK_DEBUG_SIGNALS}, |
---|
151 | {"dnd", GTK_DEBUG_DND}, |
---|
152 | {"plugsocket", GTK_DEBUG_PLUGSOCKET} |
---|
153 | }; |
---|
154 | |
---|
155 | static const guint gtk_ndebug_keys = sizeof (gtk_debug_keys) / sizeof (GDebugKey); |
---|
156 | |
---|
157 | #endif /* G_ENABLE_DEBUG */ |
---|
158 | |
---|
159 | gchar* |
---|
160 | gtk_check_version (guint required_major, |
---|
161 | guint required_minor, |
---|
162 | guint required_micro) |
---|
163 | { |
---|
164 | if (required_major > GTK_MAJOR_VERSION) |
---|
165 | return "Gtk+ version too old (major mismatch)"; |
---|
166 | if (required_major < GTK_MAJOR_VERSION) |
---|
167 | return "Gtk+ version too new (major mismatch)"; |
---|
168 | if (required_minor > GTK_MINOR_VERSION) |
---|
169 | return "Gtk+ version too old (minor mismatch)"; |
---|
170 | if (required_minor < GTK_MINOR_VERSION) |
---|
171 | return "Gtk+ version too new (minor mismatch)"; |
---|
172 | if (required_micro < GTK_MICRO_VERSION - GTK_BINARY_AGE) |
---|
173 | return "Gtk+ version too new (micro mismatch)"; |
---|
174 | if (required_micro > GTK_MICRO_VERSION) |
---|
175 | return "Gtk+ version too old (micro mismatch)"; |
---|
176 | return NULL; |
---|
177 | } |
---|
178 | |
---|
179 | /* This checks to see if the process is running suid or sgid |
---|
180 | * at the current time. If so, we don't allow GTK+ to be initialized. |
---|
181 | * This is meant to be a mild check - we only error out if we |
---|
182 | * can prove the programmer is doing something wrong, not if |
---|
183 | * they could be doing something wrong. For this reason, we |
---|
184 | * don't use issetugid() on BSD or prctl (PR_GET_DUMPABLE). |
---|
185 | */ |
---|
186 | static gboolean |
---|
187 | check_setugid (void) |
---|
188 | { |
---|
189 | uid_t ruid, euid, suid; /* Real, effective and saved user ID's */ |
---|
190 | gid_t rgid, egid, sgid; /* Real, effective and saved group ID's */ |
---|
191 | |
---|
192 | #ifdef HAVE_GETRESUID |
---|
193 | /* These aren't in the header files, so we prototype them here. |
---|
194 | */ |
---|
195 | int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid); |
---|
196 | int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid); |
---|
197 | |
---|
198 | if (getresuid (&ruid, &euid, &suid) != 0 || |
---|
199 | getresgid (&rgid, &egid, &sgid) != 0) |
---|
200 | #endif /* HAVE_GETRESUID */ |
---|
201 | { |
---|
202 | suid = ruid = getuid (); |
---|
203 | sgid = rgid = getgid (); |
---|
204 | euid = geteuid (); |
---|
205 | egid = getegid (); |
---|
206 | } |
---|
207 | |
---|
208 | if (ruid != euid || ruid != suid || |
---|
209 | rgid != egid || rgid != sgid) |
---|
210 | { |
---|
211 | g_warning ("This process is currently running setuid or setgid.\n" |
---|
212 | "This is not a supported use of GTK+. You must create a helper\n" |
---|
213 | "program instead. For further details, see:\n\n" |
---|
214 | " http://www.gtk.org/setuid.html\n\n" |
---|
215 | "Refusing to initialize GTK+."); |
---|
216 | exit (1); |
---|
217 | } |
---|
218 | |
---|
219 | return TRUE; |
---|
220 | } |
---|
221 | |
---|
222 | gboolean |
---|
223 | gtk_init_check (int *argc, |
---|
224 | char ***argv) |
---|
225 | { |
---|
226 | extern void gtk_object_post_arg_parsing_init (void); |
---|
227 | GSList *gtk_modules = NULL; |
---|
228 | GSList *slist; |
---|
229 | gchar *env_string = NULL; |
---|
230 | |
---|
231 | if (gtk_initialized) |
---|
232 | return TRUE; |
---|
233 | |
---|
234 | if (!check_setugid ()) |
---|
235 | return FALSE; |
---|
236 | |
---|
237 | #if 0 |
---|
238 | g_set_error_handler (gtk_error); |
---|
239 | g_set_warning_handler (gtk_warning); |
---|
240 | g_set_message_handler (gtk_message); |
---|
241 | g_set_print_handler (gtk_print); |
---|
242 | #endif |
---|
243 | |
---|
244 | /* Initialize "gdk". We pass along the 'argc' and 'argv' |
---|
245 | * parameters as they contain information that GDK uses |
---|
246 | */ |
---|
247 | if (!gdk_init_check (argc, argv)) |
---|
248 | return FALSE; |
---|
249 | |
---|
250 | gdk_event_handler_set ((GdkEventFunc)gtk_main_do_event, NULL, NULL); |
---|
251 | |
---|
252 | #ifdef G_ENABLE_DEBUG |
---|
253 | env_string = getenv ("GTK_DEBUG"); |
---|
254 | if (env_string != NULL) |
---|
255 | { |
---|
256 | gtk_debug_flags = g_parse_debug_string (env_string, |
---|
257 | gtk_debug_keys, |
---|
258 | gtk_ndebug_keys); |
---|
259 | env_string = NULL; |
---|
260 | } |
---|
261 | #endif /* G_ENABLE_DEBUG */ |
---|
262 | |
---|
263 | env_string = getenv ("GTK_MODULES"); |
---|
264 | if (env_string) |
---|
265 | { |
---|
266 | gchar **modules, **as; |
---|
267 | |
---|
268 | modules = g_strsplit (env_string, ":", -1); |
---|
269 | for (as = modules; *as; as++) |
---|
270 | { |
---|
271 | if (**as) |
---|
272 | gtk_modules = g_slist_prepend (gtk_modules, *as); |
---|
273 | else |
---|
274 | g_free (*as); |
---|
275 | } |
---|
276 | g_free (modules); |
---|
277 | env_string = NULL; |
---|
278 | } |
---|
279 | |
---|
280 | if (argc && argv) |
---|
281 | { |
---|
282 | gint i, j, k; |
---|
283 | |
---|
284 | for (i = 1; i < *argc;) |
---|
285 | { |
---|
286 | if (strcmp ("--gtk-module", (*argv)[i]) == 0 || |
---|
287 | strncmp ("--gtk-module=", (*argv)[i], 13) == 0) |
---|
288 | { |
---|
289 | gchar *module_name = (*argv)[i] + 12; |
---|
290 | |
---|
291 | if (*module_name == '=') |
---|
292 | module_name++; |
---|
293 | else if (i + 1 < *argc) |
---|
294 | { |
---|
295 | (*argv)[i] = NULL; |
---|
296 | i += 1; |
---|
297 | module_name = (*argv)[i]; |
---|
298 | } |
---|
299 | (*argv)[i] = NULL; |
---|
300 | |
---|
301 | if (module_name && *module_name) |
---|
302 | gtk_modules = g_slist_prepend (gtk_modules, g_strdup (module_name)); |
---|
303 | } |
---|
304 | else if (strcmp ("--g-fatal-warnings", (*argv)[i]) == 0) |
---|
305 | { |
---|
306 | GLogLevelFlags fatal_mask; |
---|
307 | |
---|
308 | fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK); |
---|
309 | fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL; |
---|
310 | g_log_set_always_fatal (fatal_mask); |
---|
311 | (*argv)[i] = NULL; |
---|
312 | } |
---|
313 | #ifdef G_ENABLE_DEBUG |
---|
314 | else if ((strcmp ("--gtk-debug", (*argv)[i]) == 0) || |
---|
315 | (strncmp ("--gtk-debug=", (*argv)[i], 12) == 0)) |
---|
316 | { |
---|
317 | gchar *equal_pos = strchr ((*argv)[i], '='); |
---|
318 | |
---|
319 | if (equal_pos != NULL) |
---|
320 | { |
---|
321 | gtk_debug_flags |= g_parse_debug_string (equal_pos+1, |
---|
322 | gtk_debug_keys, |
---|
323 | gtk_ndebug_keys); |
---|
324 | } |
---|
325 | else if ((i + 1) < *argc && (*argv)[i + 1]) |
---|
326 | { |
---|
327 | gtk_debug_flags |= g_parse_debug_string ((*argv)[i+1], |
---|
328 | gtk_debug_keys, |
---|
329 | gtk_ndebug_keys); |
---|
330 | (*argv)[i] = NULL; |
---|
331 | i += 1; |
---|
332 | } |
---|
333 | (*argv)[i] = NULL; |
---|
334 | } |
---|
335 | else if ((strcmp ("--gtk-no-debug", (*argv)[i]) == 0) || |
---|
336 | (strncmp ("--gtk-no-debug=", (*argv)[i], 15) == 0)) |
---|
337 | { |
---|
338 | gchar *equal_pos = strchr ((*argv)[i], '='); |
---|
339 | |
---|
340 | if (equal_pos != NULL) |
---|
341 | { |
---|
342 | gtk_debug_flags &= ~g_parse_debug_string (equal_pos+1, |
---|
343 | gtk_debug_keys, |
---|
344 | gtk_ndebug_keys); |
---|
345 | } |
---|
346 | else if ((i + 1) < *argc && (*argv)[i + 1]) |
---|
347 | { |
---|
348 | gtk_debug_flags &= ~g_parse_debug_string ((*argv)[i+1], |
---|
349 | gtk_debug_keys, |
---|
350 | gtk_ndebug_keys); |
---|
351 | (*argv)[i] = NULL; |
---|
352 | i += 1; |
---|
353 | } |
---|
354 | (*argv)[i] = NULL; |
---|
355 | } |
---|
356 | #endif /* G_ENABLE_DEBUG */ |
---|
357 | i += 1; |
---|
358 | } |
---|
359 | |
---|
360 | for (i = 1; i < *argc; i++) |
---|
361 | { |
---|
362 | for (k = i; k < *argc; k++) |
---|
363 | if ((*argv)[k] != NULL) |
---|
364 | break; |
---|
365 | |
---|
366 | if (k > i) |
---|
367 | { |
---|
368 | k -= i; |
---|
369 | for (j = i + k; j < *argc; j++) |
---|
370 | (*argv)[j-k] = (*argv)[j]; |
---|
371 | *argc -= k; |
---|
372 | } |
---|
373 | } |
---|
374 | } |
---|
375 | |
---|
376 | /* load gtk modules */ |
---|
377 | gtk_modules = g_slist_reverse (gtk_modules); |
---|
378 | for (slist = gtk_modules; slist; slist = slist->next) |
---|
379 | { |
---|
380 | gchar *module_name; |
---|
381 | GModule *module = NULL; |
---|
382 | GtkModuleInitFunc modinit_func = NULL; |
---|
383 | |
---|
384 | module_name = slist->data; |
---|
385 | slist->data = NULL; |
---|
386 | if (!(module_name[0] == '/' || |
---|
387 | (module_name[0] == 'l' && |
---|
388 | module_name[1] == 'i' && |
---|
389 | module_name[2] == 'b'))) |
---|
390 | { |
---|
391 | gchar *old = module_name; |
---|
392 | |
---|
393 | module_name = g_strconcat ("lib", module_name, ".so", NULL); |
---|
394 | g_free (old); |
---|
395 | } |
---|
396 | if (g_module_supported ()) |
---|
397 | { |
---|
398 | module = g_module_open (module_name, G_MODULE_BIND_LAZY); |
---|
399 | if (module && |
---|
400 | g_module_symbol (module, "gtk_module_init", (gpointer*) &modinit_func) && |
---|
401 | modinit_func) |
---|
402 | { |
---|
403 | if (!g_slist_find (gtk_modules, (void *)modinit_func)) |
---|
404 | { |
---|
405 | g_module_make_resident (module); |
---|
406 | slist->data = (void *)modinit_func; |
---|
407 | } |
---|
408 | else |
---|
409 | { |
---|
410 | g_module_close (module); |
---|
411 | module = NULL; |
---|
412 | } |
---|
413 | } |
---|
414 | } |
---|
415 | if (!modinit_func) |
---|
416 | { |
---|
417 | g_warning ("Failed to load module \"%s\": %s", |
---|
418 | module ? g_module_name (module) : module_name, |
---|
419 | g_module_error ()); |
---|
420 | if (module) |
---|
421 | g_module_close (module); |
---|
422 | } |
---|
423 | g_free (module_name); |
---|
424 | } |
---|
425 | |
---|
426 | #ifdef ENABLE_NLS |
---|
427 | bindtextdomain("gtk+", GTK_LOCALEDIR); |
---|
428 | #endif |
---|
429 | |
---|
430 | /* Initialize the default visual and colormap to be |
---|
431 | * used in creating widgets. (We want to use the system |
---|
432 | * defaults so as to be nice to the colormap). |
---|
433 | */ |
---|
434 | gtk_visual = gdk_visual_get_system (); |
---|
435 | gtk_colormap = gdk_colormap_get_system (); |
---|
436 | |
---|
437 | gtk_type_init (); |
---|
438 | gtk_object_post_arg_parsing_init (); |
---|
439 | gtk_signal_init (); |
---|
440 | gtk_rc_init (); |
---|
441 | |
---|
442 | |
---|
443 | /* Register an exit function to make sure we are able to cleanup. |
---|
444 | */ |
---|
445 | g_atexit (gtk_exit_func); |
---|
446 | |
---|
447 | /* Set the 'initialized' flag. |
---|
448 | */ |
---|
449 | gtk_initialized = TRUE; |
---|
450 | |
---|
451 | /* initialize gtk modules |
---|
452 | */ |
---|
453 | for (slist = gtk_modules; slist; slist = slist->next) |
---|
454 | { |
---|
455 | if (slist->data) |
---|
456 | { |
---|
457 | GtkModuleInitFunc modinit; |
---|
458 | |
---|
459 | modinit = (GtkModuleInitFunc)slist->data; |
---|
460 | modinit (argc, argv); |
---|
461 | } |
---|
462 | } |
---|
463 | g_slist_free (gtk_modules); |
---|
464 | |
---|
465 | return TRUE; |
---|
466 | } |
---|
467 | |
---|
468 | void |
---|
469 | gtk_init (int *argc, char ***argv) |
---|
470 | { |
---|
471 | if (!gtk_init_check (argc, argv)) |
---|
472 | { |
---|
473 | g_warning ("cannot open display: %s", gdk_get_display ()); |
---|
474 | exit(1); |
---|
475 | } |
---|
476 | } |
---|
477 | |
---|
478 | void |
---|
479 | gtk_exit (int errorcode) |
---|
480 | { |
---|
481 | /* Only if "gtk" has been initialized should we de-initialize. |
---|
482 | */ |
---|
483 | /* de-initialisation is done by the gtk_exit_funct(), |
---|
484 | * no need to do this here (Alex J.) |
---|
485 | */ |
---|
486 | gdk_exit(errorcode); |
---|
487 | } |
---|
488 | |
---|
489 | gchar* |
---|
490 | gtk_set_locale (void) |
---|
491 | { |
---|
492 | return gdk_set_locale (); |
---|
493 | } |
---|
494 | |
---|
495 | void |
---|
496 | gtk_main (void) |
---|
497 | { |
---|
498 | GList *tmp_list; |
---|
499 | GList *functions; |
---|
500 | GtkInitFunction *init; |
---|
501 | GMainLoop *loop; |
---|
502 | |
---|
503 | gtk_main_loop_level++; |
---|
504 | |
---|
505 | loop = g_main_new (TRUE); |
---|
506 | main_loops = g_slist_prepend (main_loops, loop); |
---|
507 | |
---|
508 | tmp_list = functions = init_functions; |
---|
509 | init_functions = NULL; |
---|
510 | |
---|
511 | while (tmp_list) |
---|
512 | { |
---|
513 | init = tmp_list->data; |
---|
514 | tmp_list = tmp_list->next; |
---|
515 | |
---|
516 | (* init->function) (init->data); |
---|
517 | g_free (init); |
---|
518 | } |
---|
519 | g_list_free (functions); |
---|
520 | |
---|
521 | if (g_main_is_running (main_loops->data)) |
---|
522 | { |
---|
523 | GDK_THREADS_LEAVE (); |
---|
524 | g_main_run (loop); |
---|
525 | GDK_THREADS_ENTER (); |
---|
526 | gdk_flush (); |
---|
527 | } |
---|
528 | |
---|
529 | if (quit_functions) |
---|
530 | { |
---|
531 | GList *reinvoke_list = NULL; |
---|
532 | GtkQuitFunction *quitf; |
---|
533 | |
---|
534 | while (quit_functions) |
---|
535 | { |
---|
536 | quitf = quit_functions->data; |
---|
537 | |
---|
538 | tmp_list = quit_functions; |
---|
539 | quit_functions = g_list_remove_link (quit_functions, quit_functions); |
---|
540 | g_list_free_1 (tmp_list); |
---|
541 | |
---|
542 | if ((quitf->main_level && quitf->main_level != gtk_main_loop_level) || |
---|
543 | gtk_quit_invoke_function (quitf)) |
---|
544 | { |
---|
545 | reinvoke_list = g_list_prepend (reinvoke_list, quitf); |
---|
546 | } |
---|
547 | else |
---|
548 | { |
---|
549 | gtk_quit_destroy (quitf); |
---|
550 | } |
---|
551 | } |
---|
552 | if (reinvoke_list) |
---|
553 | { |
---|
554 | GList *work; |
---|
555 | |
---|
556 | work = g_list_last (reinvoke_list); |
---|
557 | if (quit_functions) |
---|
558 | quit_functions->prev = work; |
---|
559 | work->next = quit_functions; |
---|
560 | quit_functions = work; |
---|
561 | } |
---|
562 | |
---|
563 | gdk_flush (); |
---|
564 | } |
---|
565 | |
---|
566 | main_loops = g_slist_remove (main_loops, loop); |
---|
567 | |
---|
568 | g_main_destroy (loop); |
---|
569 | |
---|
570 | gtk_main_loop_level--; |
---|
571 | } |
---|
572 | |
---|
573 | guint |
---|
574 | gtk_main_level (void) |
---|
575 | { |
---|
576 | return gtk_main_loop_level; |
---|
577 | } |
---|
578 | |
---|
579 | void |
---|
580 | gtk_main_quit (void) |
---|
581 | { |
---|
582 | g_return_if_fail (main_loops != NULL); |
---|
583 | |
---|
584 | g_main_quit (main_loops->data); |
---|
585 | } |
---|
586 | |
---|
587 | gint |
---|
588 | gtk_events_pending (void) |
---|
589 | { |
---|
590 | gboolean result; |
---|
591 | |
---|
592 | GDK_THREADS_LEAVE (); |
---|
593 | result = g_main_pending(); |
---|
594 | GDK_THREADS_ENTER (); |
---|
595 | |
---|
596 | return result; |
---|
597 | } |
---|
598 | |
---|
599 | gint |
---|
600 | gtk_main_iteration (void) |
---|
601 | { |
---|
602 | GDK_THREADS_LEAVE (); |
---|
603 | g_main_iteration (TRUE); |
---|
604 | GDK_THREADS_ENTER (); |
---|
605 | |
---|
606 | if (main_loops) |
---|
607 | return !g_main_is_running (main_loops->data); |
---|
608 | else |
---|
609 | return TRUE; |
---|
610 | } |
---|
611 | |
---|
612 | gint |
---|
613 | gtk_main_iteration_do (gboolean blocking) |
---|
614 | { |
---|
615 | GDK_THREADS_LEAVE (); |
---|
616 | g_main_iteration (blocking); |
---|
617 | GDK_THREADS_ENTER (); |
---|
618 | |
---|
619 | if (main_loops) |
---|
620 | return !g_main_is_running (main_loops->data); |
---|
621 | else |
---|
622 | return TRUE; |
---|
623 | } |
---|
624 | |
---|
625 | void |
---|
626 | gtk_main_do_event (GdkEvent *event) |
---|
627 | { |
---|
628 | GtkWidget *event_widget; |
---|
629 | GtkWidget *grab_widget; |
---|
630 | GdkEvent *next_event; |
---|
631 | GList *tmp_list; |
---|
632 | |
---|
633 | /* If there are any events pending then get the next one. |
---|
634 | */ |
---|
635 | next_event = gdk_event_peek (); |
---|
636 | |
---|
637 | /* Try to compress enter/leave notify events. These event |
---|
638 | * pairs occur when the mouse is dragged quickly across |
---|
639 | * a window with many buttons (or through a menu). Instead |
---|
640 | * of highlighting and de-highlighting each widget that |
---|
641 | * is crossed it is better to simply de-highlight the widget |
---|
642 | * which contained the mouse initially and highlight the |
---|
643 | * widget which ends up containing the mouse. |
---|
644 | */ |
---|
645 | if (next_event) |
---|
646 | if (((event->type == GDK_ENTER_NOTIFY) || |
---|
647 | (event->type == GDK_LEAVE_NOTIFY)) && |
---|
648 | ((next_event->type == GDK_ENTER_NOTIFY) || |
---|
649 | (next_event->type == GDK_LEAVE_NOTIFY)) && |
---|
650 | (next_event->type != event->type) && |
---|
651 | (next_event->any.window == event->any.window)) |
---|
652 | { |
---|
653 | /* Throw both the peeked copy and the queued copy away |
---|
654 | */ |
---|
655 | gdk_event_free (next_event); |
---|
656 | next_event = gdk_event_get (); |
---|
657 | gdk_event_free (next_event); |
---|
658 | |
---|
659 | return; |
---|
660 | } |
---|
661 | |
---|
662 | if (next_event) |
---|
663 | gdk_event_free (next_event); |
---|
664 | |
---|
665 | /* Find the widget which got the event. We store the widget |
---|
666 | * in the user_data field of GdkWindow's. |
---|
667 | * Ignore the event if we don't have a widget for it, except |
---|
668 | * for GDK_PROPERTY_NOTIFY events which are handled specialy. |
---|
669 | * Though this happens rarely, bogus events can occour |
---|
670 | * for e.g. destroyed GdkWindows. |
---|
671 | */ |
---|
672 | event_widget = gtk_get_event_widget (event); |
---|
673 | if (!event_widget) |
---|
674 | { |
---|
675 | /* To handle selection INCR transactions, we select |
---|
676 | * PropertyNotify events on the requestor window and create |
---|
677 | * a corresponding (fake) GdkWindow so that events get |
---|
678 | * here. There won't be a widget though, so we have to handle |
---|
679 | * them specially |
---|
680 | */ |
---|
681 | if (event->type == GDK_PROPERTY_NOTIFY) |
---|
682 | gtk_selection_incr_event (event->any.window, |
---|
683 | &event->property); |
---|
684 | |
---|
685 | return; |
---|
686 | } |
---|
687 | |
---|
688 | /* Push the event onto a stack of current events for |
---|
689 | * gtk_current_event_get(). |
---|
690 | */ |
---|
691 | current_events = g_list_prepend (current_events, event); |
---|
692 | |
---|
693 | /* If there is a grab in effect... |
---|
694 | */ |
---|
695 | if (grabs) |
---|
696 | { |
---|
697 | grab_widget = grabs->data; |
---|
698 | |
---|
699 | /* If the grab widget is an ancestor of the event widget |
---|
700 | * then we send the event to the original event widget. |
---|
701 | * This is the key to implementing modality. |
---|
702 | */ |
---|
703 | if (GTK_WIDGET_IS_SENSITIVE (event_widget) && |
---|
704 | gtk_widget_is_ancestor (event_widget, grab_widget)) |
---|
705 | grab_widget = event_widget; |
---|
706 | } |
---|
707 | else |
---|
708 | { |
---|
709 | grab_widget = event_widget; |
---|
710 | } |
---|
711 | |
---|
712 | /* Not all events get sent to the grabbing widget. |
---|
713 | * The delete, destroy, expose, focus change and resize |
---|
714 | * events still get sent to the event widget because |
---|
715 | * 1) these events have no meaning for the grabbing widget |
---|
716 | * and 2) redirecting these events to the grabbing widget |
---|
717 | * could cause the display to be messed up. |
---|
718 | * |
---|
719 | * Drag events are also not redirected, since it isn't |
---|
720 | * clear what the semantics of that would be. |
---|
721 | */ |
---|
722 | switch (event->type) |
---|
723 | { |
---|
724 | case GDK_NOTHING: |
---|
725 | break; |
---|
726 | |
---|
727 | case GDK_DELETE: |
---|
728 | gtk_widget_ref (event_widget); |
---|
729 | if ((!grabs || gtk_widget_get_toplevel (grabs->data) == event_widget) && |
---|
730 | !gtk_widget_event (event_widget, event)) |
---|
731 | gtk_widget_destroy (event_widget); |
---|
732 | gtk_widget_unref (event_widget); |
---|
733 | break; |
---|
734 | |
---|
735 | case GDK_DESTROY: |
---|
736 | /* Unexpected GDK_DESTROY from the outside, ignore for |
---|
737 | * child windows, handle like a GDK_DELETE for toplevels |
---|
738 | */ |
---|
739 | if (!event_widget->parent) |
---|
740 | { |
---|
741 | gtk_widget_ref (event_widget); |
---|
742 | if (!gtk_widget_event (event_widget, event) && |
---|
743 | !GTK_OBJECT_DESTROYED (event_widget)) |
---|
744 | gtk_widget_destroy (event_widget); |
---|
745 | gtk_widget_unref (event_widget); |
---|
746 | } |
---|
747 | break; |
---|
748 | |
---|
749 | case GDK_PROPERTY_NOTIFY: |
---|
750 | case GDK_EXPOSE: |
---|
751 | case GDK_NO_EXPOSE: |
---|
752 | case GDK_FOCUS_CHANGE: |
---|
753 | case GDK_CONFIGURE: |
---|
754 | case GDK_MAP: |
---|
755 | case GDK_UNMAP: |
---|
756 | case GDK_SELECTION_CLEAR: |
---|
757 | case GDK_SELECTION_REQUEST: |
---|
758 | case GDK_SELECTION_NOTIFY: |
---|
759 | case GDK_CLIENT_EVENT: |
---|
760 | case GDK_VISIBILITY_NOTIFY: |
---|
761 | gtk_widget_event (event_widget, event); |
---|
762 | break; |
---|
763 | |
---|
764 | case GDK_BUTTON_PRESS: |
---|
765 | case GDK_2BUTTON_PRESS: |
---|
766 | case GDK_3BUTTON_PRESS: |
---|
767 | /* We treat button 4-5 specially, assume we have |
---|
768 | * a MS-style scrollwheel mouse, and try to find |
---|
769 | * a plausible widget to scroll. We also trap |
---|
770 | * button 4-5 double and triple clicks here, since |
---|
771 | * they will be generated if the user scrolls quickly. |
---|
772 | */ |
---|
773 | if ((grab_widget == event_widget) && |
---|
774 | (event->button.button == 4 || event->button.button == 5)) |
---|
775 | { |
---|
776 | GtkWidget *range = NULL; |
---|
777 | GtkWidget *scrollwin; |
---|
778 | |
---|
779 | if (GTK_IS_RANGE (event_widget)) |
---|
780 | range = event_widget; |
---|
781 | else |
---|
782 | { |
---|
783 | scrollwin = gtk_widget_get_ancestor (event_widget, |
---|
784 | GTK_TYPE_SCROLLED_WINDOW); |
---|
785 | if (scrollwin) |
---|
786 | range = GTK_SCROLLED_WINDOW (scrollwin)->vscrollbar; |
---|
787 | } |
---|
788 | |
---|
789 | if (range && GTK_WIDGET_VISIBLE (range)) |
---|
790 | { |
---|
791 | if (event->type == GDK_BUTTON_PRESS) |
---|
792 | { |
---|
793 | GtkAdjustment *adj = GTK_RANGE (range)->adjustment; |
---|
794 | gfloat new_value = adj->value + ((event->button.button == 4) ? |
---|
795 | -adj->page_increment / 2: |
---|
796 | adj->page_increment / 2); |
---|
797 | new_value = CLAMP (new_value, adj->lower, adj->upper - adj->page_size); |
---|
798 | gtk_adjustment_set_value (adj, new_value); |
---|
799 | } |
---|
800 | break; |
---|
801 | } |
---|
802 | } |
---|
803 | gtk_propagate_event (grab_widget, event); |
---|
804 | break; |
---|
805 | |
---|
806 | case GDK_KEY_PRESS: |
---|
807 | case GDK_KEY_RELEASE: |
---|
808 | if (key_snoopers) |
---|
809 | { |
---|
810 | if (gtk_invoke_key_snoopers (grab_widget, event)) |
---|
811 | break; |
---|
812 | } |
---|
813 | /* else fall through */ |
---|
814 | case GDK_MOTION_NOTIFY: |
---|
815 | case GDK_BUTTON_RELEASE: |
---|
816 | case GDK_PROXIMITY_IN: |
---|
817 | case GDK_PROXIMITY_OUT: |
---|
818 | gtk_propagate_event (grab_widget, event); |
---|
819 | break; |
---|
820 | |
---|
821 | case GDK_ENTER_NOTIFY: |
---|
822 | if (GTK_WIDGET_IS_SENSITIVE (grab_widget)) |
---|
823 | { |
---|
824 | gtk_widget_event (grab_widget, event); |
---|
825 | if (event_widget == grab_widget) |
---|
826 | GTK_PRIVATE_SET_FLAG (event_widget, GTK_LEAVE_PENDING); |
---|
827 | } |
---|
828 | break; |
---|
829 | |
---|
830 | case GDK_LEAVE_NOTIFY: |
---|
831 | if (GTK_WIDGET_LEAVE_PENDING (event_widget)) |
---|
832 | { |
---|
833 | GTK_PRIVATE_UNSET_FLAG (event_widget, GTK_LEAVE_PENDING); |
---|
834 | gtk_widget_event (event_widget, event); |
---|
835 | } |
---|
836 | else if (GTK_WIDGET_IS_SENSITIVE (grab_widget)) |
---|
837 | gtk_widget_event (grab_widget, event); |
---|
838 | break; |
---|
839 | |
---|
840 | case GDK_DRAG_STATUS: |
---|
841 | case GDK_DROP_FINISHED: |
---|
842 | gtk_drag_source_handle_event (event_widget, event); |
---|
843 | break; |
---|
844 | case GDK_DRAG_ENTER: |
---|
845 | case GDK_DRAG_LEAVE: |
---|
846 | case GDK_DRAG_MOTION: |
---|
847 | case GDK_DROP_START: |
---|
848 | gtk_drag_dest_handle_event (event_widget, event); |
---|
849 | break; |
---|
850 | } |
---|
851 | |
---|
852 | tmp_list = current_events; |
---|
853 | current_events = g_list_remove_link (current_events, tmp_list); |
---|
854 | g_list_free_1 (tmp_list); |
---|
855 | } |
---|
856 | |
---|
857 | gint |
---|
858 | gtk_true (void) |
---|
859 | { |
---|
860 | return TRUE; |
---|
861 | } |
---|
862 | |
---|
863 | gint |
---|
864 | gtk_false (void) |
---|
865 | { |
---|
866 | return FALSE; |
---|
867 | } |
---|
868 | |
---|
869 | void |
---|
870 | gtk_grab_add (GtkWidget *widget) |
---|
871 | { |
---|
872 | g_return_if_fail (widget != NULL); |
---|
873 | |
---|
874 | if (!GTK_WIDGET_HAS_GRAB (widget) && GTK_WIDGET_IS_SENSITIVE (widget)) |
---|
875 | { |
---|
876 | GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_GRAB); |
---|
877 | |
---|
878 | grabs = g_slist_prepend (grabs, widget); |
---|
879 | gtk_widget_ref (widget); |
---|
880 | } |
---|
881 | } |
---|
882 | |
---|
883 | GtkWidget* |
---|
884 | gtk_grab_get_current (void) |
---|
885 | { |
---|
886 | if (grabs) |
---|
887 | return GTK_WIDGET (grabs->data); |
---|
888 | return NULL; |
---|
889 | } |
---|
890 | |
---|
891 | void |
---|
892 | gtk_grab_remove (GtkWidget *widget) |
---|
893 | { |
---|
894 | g_return_if_fail (widget != NULL); |
---|
895 | |
---|
896 | if (GTK_WIDGET_HAS_GRAB (widget)) |
---|
897 | { |
---|
898 | GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_GRAB); |
---|
899 | |
---|
900 | grabs = g_slist_remove (grabs, widget); |
---|
901 | gtk_widget_unref (widget); |
---|
902 | } |
---|
903 | } |
---|
904 | |
---|
905 | void |
---|
906 | gtk_init_add (GtkFunction function, |
---|
907 | gpointer data) |
---|
908 | { |
---|
909 | GtkInitFunction *init; |
---|
910 | |
---|
911 | init = g_new (GtkInitFunction, 1); |
---|
912 | init->function = function; |
---|
913 | init->data = data; |
---|
914 | |
---|
915 | init_functions = g_list_prepend (init_functions, init); |
---|
916 | } |
---|
917 | |
---|
918 | guint |
---|
919 | gtk_key_snooper_install (GtkKeySnoopFunc snooper, |
---|
920 | gpointer func_data) |
---|
921 | { |
---|
922 | GtkKeySnooperData *data; |
---|
923 | static guint snooper_id = 1; |
---|
924 | |
---|
925 | g_return_val_if_fail (snooper != NULL, 0); |
---|
926 | |
---|
927 | data = g_new (GtkKeySnooperData, 1); |
---|
928 | data->func = snooper; |
---|
929 | data->func_data = func_data; |
---|
930 | data->id = snooper_id++; |
---|
931 | key_snoopers = g_slist_prepend (key_snoopers, data); |
---|
932 | |
---|
933 | return data->id; |
---|
934 | } |
---|
935 | |
---|
936 | void |
---|
937 | gtk_key_snooper_remove (guint snooper_id) |
---|
938 | { |
---|
939 | GtkKeySnooperData *data = NULL; |
---|
940 | GSList *slist; |
---|
941 | |
---|
942 | slist = key_snoopers; |
---|
943 | while (slist) |
---|
944 | { |
---|
945 | data = slist->data; |
---|
946 | if (data->id == snooper_id) |
---|
947 | break; |
---|
948 | |
---|
949 | slist = slist->next; |
---|
950 | data = NULL; |
---|
951 | } |
---|
952 | if (data) |
---|
953 | key_snoopers = g_slist_remove (key_snoopers, data); |
---|
954 | } |
---|
955 | |
---|
956 | static gint |
---|
957 | gtk_invoke_key_snoopers (GtkWidget *grab_widget, |
---|
958 | GdkEvent *event) |
---|
959 | { |
---|
960 | GSList *slist; |
---|
961 | gint return_val = FALSE; |
---|
962 | |
---|
963 | slist = key_snoopers; |
---|
964 | while (slist && !return_val) |
---|
965 | { |
---|
966 | GtkKeySnooperData *data; |
---|
967 | |
---|
968 | data = slist->data; |
---|
969 | slist = slist->next; |
---|
970 | return_val = (*data->func) (grab_widget, (GdkEventKey*) event, data->func_data); |
---|
971 | } |
---|
972 | |
---|
973 | return return_val; |
---|
974 | } |
---|
975 | |
---|
976 | guint |
---|
977 | gtk_quit_add_full (guint main_level, |
---|
978 | GtkFunction function, |
---|
979 | GtkCallbackMarshal marshal, |
---|
980 | gpointer data, |
---|
981 | GtkDestroyNotify destroy) |
---|
982 | { |
---|
983 | static guint quit_id = 1; |
---|
984 | GtkQuitFunction *quitf; |
---|
985 | |
---|
986 | g_return_val_if_fail ((function != NULL) || (marshal != NULL), 0); |
---|
987 | |
---|
988 | if (!quit_mem_chunk) |
---|
989 | quit_mem_chunk = g_mem_chunk_new ("quit mem chunk", sizeof (GtkQuitFunction), |
---|
990 | 512, G_ALLOC_AND_FREE); |
---|
991 | |
---|
992 | quitf = g_chunk_new (GtkQuitFunction, quit_mem_chunk); |
---|
993 | |
---|
994 | quitf->id = quit_id++; |
---|
995 | quitf->main_level = main_level; |
---|
996 | quitf->function = function; |
---|
997 | quitf->marshal = marshal; |
---|
998 | quitf->data = data; |
---|
999 | quitf->destroy = destroy; |
---|
1000 | |
---|
1001 | quit_functions = g_list_prepend (quit_functions, quitf); |
---|
1002 | |
---|
1003 | return quitf->id; |
---|
1004 | } |
---|
1005 | |
---|
1006 | static void |
---|
1007 | gtk_quit_destroy (GtkQuitFunction *quitf) |
---|
1008 | { |
---|
1009 | if (quitf->destroy) |
---|
1010 | quitf->destroy (quitf->data); |
---|
1011 | g_mem_chunk_free (quit_mem_chunk, quitf); |
---|
1012 | } |
---|
1013 | |
---|
1014 | static gint |
---|
1015 | gtk_quit_destructor (GtkObject **object_p) |
---|
1016 | { |
---|
1017 | if (*object_p) |
---|
1018 | gtk_object_destroy (*object_p); |
---|
1019 | g_free (object_p); |
---|
1020 | |
---|
1021 | return FALSE; |
---|
1022 | } |
---|
1023 | |
---|
1024 | void |
---|
1025 | gtk_quit_add_destroy (guint main_level, |
---|
1026 | GtkObject *object) |
---|
1027 | { |
---|
1028 | GtkObject **object_p; |
---|
1029 | |
---|
1030 | g_return_if_fail (main_level > 0); |
---|
1031 | g_return_if_fail (object != NULL); |
---|
1032 | g_return_if_fail (GTK_IS_OBJECT (object)); |
---|
1033 | |
---|
1034 | object_p = g_new (GtkObject*, 1); |
---|
1035 | *object_p = object; |
---|
1036 | gtk_signal_connect (object, |
---|
1037 | "destroy", |
---|
1038 | GTK_SIGNAL_FUNC (gtk_widget_destroyed), |
---|
1039 | object_p); |
---|
1040 | gtk_quit_add (main_level, (GtkFunction) gtk_quit_destructor, object_p); |
---|
1041 | } |
---|
1042 | |
---|
1043 | guint |
---|
1044 | gtk_quit_add (guint main_level, |
---|
1045 | GtkFunction function, |
---|
1046 | gpointer data) |
---|
1047 | { |
---|
1048 | return gtk_quit_add_full (main_level, function, NULL, data, NULL); |
---|
1049 | } |
---|
1050 | |
---|
1051 | void |
---|
1052 | gtk_quit_remove (guint id) |
---|
1053 | { |
---|
1054 | GtkQuitFunction *quitf; |
---|
1055 | GList *tmp_list; |
---|
1056 | |
---|
1057 | tmp_list = quit_functions; |
---|
1058 | while (tmp_list) |
---|
1059 | { |
---|
1060 | quitf = tmp_list->data; |
---|
1061 | |
---|
1062 | if (quitf->id == id) |
---|
1063 | { |
---|
1064 | quit_functions = g_list_remove_link (quit_functions, tmp_list); |
---|
1065 | g_list_free (tmp_list); |
---|
1066 | gtk_quit_destroy (quitf); |
---|
1067 | |
---|
1068 | return; |
---|
1069 | } |
---|
1070 | |
---|
1071 | tmp_list = tmp_list->next; |
---|
1072 | } |
---|
1073 | } |
---|
1074 | |
---|
1075 | void |
---|
1076 | gtk_quit_remove_by_data (gpointer data) |
---|
1077 | { |
---|
1078 | GtkQuitFunction *quitf; |
---|
1079 | GList *tmp_list; |
---|
1080 | |
---|
1081 | tmp_list = quit_functions; |
---|
1082 | while (tmp_list) |
---|
1083 | { |
---|
1084 | quitf = tmp_list->data; |
---|
1085 | |
---|
1086 | if (quitf->data == data) |
---|
1087 | { |
---|
1088 | quit_functions = g_list_remove_link (quit_functions, tmp_list); |
---|
1089 | g_list_free (tmp_list); |
---|
1090 | gtk_quit_destroy (quitf); |
---|
1091 | |
---|
1092 | return; |
---|
1093 | } |
---|
1094 | |
---|
1095 | tmp_list = tmp_list->next; |
---|
1096 | } |
---|
1097 | } |
---|
1098 | |
---|
1099 | guint |
---|
1100 | gtk_timeout_add_full (guint32 interval, |
---|
1101 | GtkFunction function, |
---|
1102 | GtkCallbackMarshal marshal, |
---|
1103 | gpointer data, |
---|
1104 | GtkDestroyNotify destroy) |
---|
1105 | { |
---|
1106 | if (marshal) |
---|
1107 | { |
---|
1108 | GtkClosure *closure; |
---|
1109 | |
---|
1110 | closure = g_new (GtkClosure, 1); |
---|
1111 | closure->marshal = marshal; |
---|
1112 | closure->data = data; |
---|
1113 | closure->destroy = destroy; |
---|
1114 | |
---|
1115 | return g_timeout_add_full (0, interval, |
---|
1116 | gtk_invoke_idle_timeout, |
---|
1117 | closure, |
---|
1118 | gtk_destroy_closure); |
---|
1119 | } |
---|
1120 | else |
---|
1121 | return g_timeout_add_full (0, interval, function, data, destroy); |
---|
1122 | } |
---|
1123 | |
---|
1124 | guint |
---|
1125 | gtk_timeout_add (guint32 interval, |
---|
1126 | GtkFunction function, |
---|
1127 | gpointer data) |
---|
1128 | { |
---|
1129 | return g_timeout_add_full (0, interval, function, data, NULL); |
---|
1130 | } |
---|
1131 | |
---|
1132 | void |
---|
1133 | gtk_timeout_remove (guint tag) |
---|
1134 | { |
---|
1135 | g_source_remove (tag); |
---|
1136 | } |
---|
1137 | |
---|
1138 | guint |
---|
1139 | gtk_idle_add_full (gint priority, |
---|
1140 | GtkFunction function, |
---|
1141 | GtkCallbackMarshal marshal, |
---|
1142 | gpointer data, |
---|
1143 | GtkDestroyNotify destroy) |
---|
1144 | { |
---|
1145 | if (marshal) |
---|
1146 | { |
---|
1147 | GtkClosure *closure; |
---|
1148 | |
---|
1149 | closure = g_new (GtkClosure, 1); |
---|
1150 | closure->marshal = marshal; |
---|
1151 | closure->data = data; |
---|
1152 | closure->destroy = destroy; |
---|
1153 | |
---|
1154 | return g_idle_add_full (priority, |
---|
1155 | gtk_invoke_idle_timeout, |
---|
1156 | closure, |
---|
1157 | gtk_destroy_closure); |
---|
1158 | } |
---|
1159 | else |
---|
1160 | return g_idle_add_full (priority, function, data, destroy); |
---|
1161 | } |
---|
1162 | |
---|
1163 | guint |
---|
1164 | gtk_idle_add (GtkFunction function, |
---|
1165 | gpointer data) |
---|
1166 | { |
---|
1167 | return g_idle_add_full (GTK_PRIORITY_DEFAULT, function, data, NULL); |
---|
1168 | } |
---|
1169 | |
---|
1170 | guint |
---|
1171 | gtk_idle_add_priority (gint priority, |
---|
1172 | GtkFunction function, |
---|
1173 | gpointer data) |
---|
1174 | { |
---|
1175 | return g_idle_add_full (priority, function, data, NULL); |
---|
1176 | } |
---|
1177 | |
---|
1178 | void |
---|
1179 | gtk_idle_remove (guint tag) |
---|
1180 | { |
---|
1181 | g_source_remove (tag); |
---|
1182 | } |
---|
1183 | |
---|
1184 | void |
---|
1185 | gtk_idle_remove_by_data (gpointer data) |
---|
1186 | { |
---|
1187 | if (!g_idle_remove_by_data (data)) |
---|
1188 | g_warning ("gtk_idle_remove_by_data(%p): no such idle", data); |
---|
1189 | } |
---|
1190 | |
---|
1191 | guint |
---|
1192 | gtk_input_add_full (gint source, |
---|
1193 | GdkInputCondition condition, |
---|
1194 | GdkInputFunction function, |
---|
1195 | GtkCallbackMarshal marshal, |
---|
1196 | gpointer data, |
---|
1197 | GtkDestroyNotify destroy) |
---|
1198 | { |
---|
1199 | if (marshal) |
---|
1200 | { |
---|
1201 | GtkClosure *closure; |
---|
1202 | |
---|
1203 | closure = g_new (GtkClosure, 1); |
---|
1204 | closure->marshal = marshal; |
---|
1205 | closure->data = data; |
---|
1206 | closure->destroy = destroy; |
---|
1207 | |
---|
1208 | return gdk_input_add_full (source, |
---|
1209 | condition, |
---|
1210 | (GdkInputFunction) gtk_invoke_input, |
---|
1211 | closure, |
---|
1212 | (GdkDestroyNotify) gtk_destroy_closure); |
---|
1213 | } |
---|
1214 | else |
---|
1215 | return gdk_input_add_full (source, condition, function, data, destroy); |
---|
1216 | } |
---|
1217 | |
---|
1218 | void |
---|
1219 | gtk_input_remove (guint tag) |
---|
1220 | { |
---|
1221 | g_source_remove (tag); |
---|
1222 | } |
---|
1223 | |
---|
1224 | static void |
---|
1225 | gtk_destroy_closure (gpointer data) |
---|
1226 | { |
---|
1227 | GtkClosure *closure = data; |
---|
1228 | |
---|
1229 | if (closure->destroy) |
---|
1230 | (closure->destroy) (closure->data); |
---|
1231 | g_free (closure); |
---|
1232 | } |
---|
1233 | |
---|
1234 | static gboolean |
---|
1235 | gtk_invoke_idle_timeout (gpointer data) |
---|
1236 | { |
---|
1237 | GtkClosure *closure = data; |
---|
1238 | |
---|
1239 | GtkArg args[1]; |
---|
1240 | gint ret_val = FALSE; |
---|
1241 | args[0].name = NULL; |
---|
1242 | args[0].type = GTK_TYPE_BOOL; |
---|
1243 | args[0].d.pointer_data = &ret_val; |
---|
1244 | closure->marshal (NULL, closure->data, 0, args); |
---|
1245 | return ret_val; |
---|
1246 | } |
---|
1247 | |
---|
1248 | static void |
---|
1249 | gtk_invoke_input (gpointer data, |
---|
1250 | gint source, |
---|
1251 | GdkInputCondition condition) |
---|
1252 | { |
---|
1253 | GtkClosure *closure = data; |
---|
1254 | |
---|
1255 | GtkArg args[3]; |
---|
1256 | args[0].type = GTK_TYPE_INT; |
---|
1257 | args[0].name = NULL; |
---|
1258 | GTK_VALUE_INT(args[0]) = source; |
---|
1259 | args[1].type = GTK_TYPE_GDK_INPUT_CONDITION; |
---|
1260 | args[1].name = NULL; |
---|
1261 | GTK_VALUE_FLAGS(args[1]) = condition; |
---|
1262 | args[2].type = GTK_TYPE_NONE; |
---|
1263 | args[2].name = NULL; |
---|
1264 | |
---|
1265 | closure->marshal (NULL, closure->data, 2, args); |
---|
1266 | } |
---|
1267 | |
---|
1268 | GdkEvent* |
---|
1269 | gtk_get_current_event (void) |
---|
1270 | { |
---|
1271 | if (current_events) |
---|
1272 | return gdk_event_copy ((GdkEvent *) current_events->data); |
---|
1273 | else |
---|
1274 | return NULL; |
---|
1275 | } |
---|
1276 | |
---|
1277 | GtkWidget* |
---|
1278 | gtk_get_event_widget (GdkEvent *event) |
---|
1279 | { |
---|
1280 | GtkWidget *widget; |
---|
1281 | |
---|
1282 | widget = NULL; |
---|
1283 | if (event && event->any.window) |
---|
1284 | gdk_window_get_user_data (event->any.window, (void**) &widget); |
---|
1285 | |
---|
1286 | return widget; |
---|
1287 | } |
---|
1288 | |
---|
1289 | static void |
---|
1290 | gtk_exit_func (void) |
---|
1291 | { |
---|
1292 | if (gtk_initialized) |
---|
1293 | { |
---|
1294 | gtk_initialized = FALSE; |
---|
1295 | gtk_preview_uninit (); |
---|
1296 | } |
---|
1297 | } |
---|
1298 | |
---|
1299 | |
---|
1300 | static gint |
---|
1301 | gtk_quit_invoke_function (GtkQuitFunction *quitf) |
---|
1302 | { |
---|
1303 | if (!quitf->marshal) |
---|
1304 | return quitf->function (quitf->data); |
---|
1305 | else |
---|
1306 | { |
---|
1307 | GtkArg args[1]; |
---|
1308 | gint ret_val = FALSE; |
---|
1309 | |
---|
1310 | args[0].name = NULL; |
---|
1311 | args[0].type = GTK_TYPE_BOOL; |
---|
1312 | args[0].d.pointer_data = &ret_val; |
---|
1313 | ((GtkCallbackMarshal) quitf->marshal) (NULL, |
---|
1314 | quitf->data, |
---|
1315 | 0, args); |
---|
1316 | return ret_val; |
---|
1317 | } |
---|
1318 | } |
---|
1319 | |
---|
1320 | void |
---|
1321 | gtk_propagate_event (GtkWidget *widget, |
---|
1322 | GdkEvent *event) |
---|
1323 | { |
---|
1324 | gint handled_event; |
---|
1325 | |
---|
1326 | g_return_if_fail (widget != NULL); |
---|
1327 | g_return_if_fail (GTK_IS_WIDGET (widget)); |
---|
1328 | g_return_if_fail (event != NULL); |
---|
1329 | |
---|
1330 | handled_event = FALSE; |
---|
1331 | |
---|
1332 | gtk_widget_ref (widget); |
---|
1333 | |
---|
1334 | if ((event->type == GDK_KEY_PRESS) || |
---|
1335 | (event->type == GDK_KEY_RELEASE)) |
---|
1336 | { |
---|
1337 | /* Only send key events within Window widgets to the Window |
---|
1338 | * The Window widget will in turn pass the |
---|
1339 | * key event on to the currently focused widget |
---|
1340 | * for that window. |
---|
1341 | */ |
---|
1342 | GtkWidget *window; |
---|
1343 | |
---|
1344 | window = gtk_widget_get_ancestor (widget, GTK_TYPE_WINDOW); |
---|
1345 | |
---|
1346 | if (window) |
---|
1347 | { |
---|
1348 | /* If there is a grab within the window, give the grab widget |
---|
1349 | * a first crack at the key event |
---|
1350 | */ |
---|
1351 | if (widget != window && GTK_WIDGET_HAS_GRAB (widget)) |
---|
1352 | handled_event = gtk_widget_event (widget, event); |
---|
1353 | |
---|
1354 | if (!handled_event) |
---|
1355 | { |
---|
1356 | window = gtk_widget_get_ancestor (widget, GTK_TYPE_WINDOW); |
---|
1357 | if (window) |
---|
1358 | { |
---|
1359 | if (GTK_WIDGET_IS_SENSITIVE (window)) |
---|
1360 | gtk_widget_event (window, event); |
---|
1361 | } |
---|
1362 | } |
---|
1363 | |
---|
1364 | handled_event = TRUE; /* don't send to widget */ |
---|
1365 | } |
---|
1366 | } |
---|
1367 | |
---|
1368 | /* Other events get propagated up the widget tree |
---|
1369 | * so that parents can see the button and motion |
---|
1370 | * events of the children. |
---|
1371 | */ |
---|
1372 | if (!handled_event) |
---|
1373 | { |
---|
1374 | while (TRUE) |
---|
1375 | { |
---|
1376 | GtkWidget *tmp; |
---|
1377 | |
---|
1378 | handled_event = !GTK_WIDGET_IS_SENSITIVE (widget) || gtk_widget_event (widget, event); |
---|
1379 | tmp = widget->parent; |
---|
1380 | gtk_widget_unref (widget); |
---|
1381 | |
---|
1382 | widget = tmp; |
---|
1383 | |
---|
1384 | if (!handled_event && widget) |
---|
1385 | gtk_widget_ref (widget); |
---|
1386 | else |
---|
1387 | break; |
---|
1388 | } |
---|
1389 | } |
---|
1390 | else |
---|
1391 | gtk_widget_unref (widget); |
---|
1392 | } |
---|
1393 | |
---|
1394 | #if 0 |
---|
1395 | static void |
---|
1396 | gtk_error (gchar *str) |
---|
1397 | { |
---|
1398 | gtk_print (str); |
---|
1399 | } |
---|
1400 | |
---|
1401 | static void |
---|
1402 | gtk_warning (gchar *str) |
---|
1403 | { |
---|
1404 | gtk_print (str); |
---|
1405 | } |
---|
1406 | |
---|
1407 | static void |
---|
1408 | gtk_message (gchar *str) |
---|
1409 | { |
---|
1410 | gtk_print (str); |
---|
1411 | } |
---|
1412 | |
---|
1413 | static void |
---|
1414 | gtk_print (gchar *str) |
---|
1415 | { |
---|
1416 | static GtkWidget *window = NULL; |
---|
1417 | static GtkWidget *text; |
---|
1418 | static int level = 0; |
---|
1419 | GtkWidget *box1; |
---|
1420 | GtkWidget *box2; |
---|
1421 | GtkWidget *table; |
---|
1422 | GtkWidget *hscrollbar; |
---|
1423 | GtkWidget *vscrollbar; |
---|
1424 | GtkWidget *separator; |
---|
1425 | GtkWidget *button; |
---|
1426 | |
---|
1427 | if (level > 0) |
---|
1428 | { |
---|
1429 | fputs (str, stdout); |
---|
1430 | fflush (stdout); |
---|
1431 | return; |
---|
1432 | } |
---|
1433 | |
---|
1434 | if (!window) |
---|
1435 | { |
---|
1436 | window = gtk_window_new (GTK_WINDOW_TOPLEVEL); |
---|
1437 | |
---|
1438 | gtk_signal_connect (GTK_OBJECT (window), "destroy", |
---|
1439 | (GtkSignalFunc) gtk_widget_destroyed, |
---|
1440 | &window); |
---|
1441 | |
---|
1442 | gtk_window_set_title (GTK_WINDOW (window), "Messages"); |
---|
1443 | |
---|
1444 | box1 = gtk_vbox_new (FALSE, 0); |
---|
1445 | gtk_container_add (GTK_CONTAINER (window), box1); |
---|
1446 | gtk_widget_show (box1); |
---|
1447 | |
---|
1448 | |
---|
1449 | box2 = gtk_vbox_new (FALSE, 10); |
---|
1450 | gtk_container_set_border_width (GTK_CONTAINER (box2), 10); |
---|
1451 | gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); |
---|
1452 | gtk_widget_show (box2); |
---|
1453 | |
---|
1454 | |
---|
1455 | table = gtk_table_new (2, 2, FALSE); |
---|
1456 | gtk_table_set_row_spacing (GTK_TABLE (table), 0, 2); |
---|
1457 | gtk_table_set_col_spacing (GTK_TABLE (table), 0, 2); |
---|
1458 | gtk_box_pack_start (GTK_BOX (box2), table, TRUE, TRUE, 0); |
---|
1459 | gtk_widget_show (table); |
---|
1460 | |
---|
1461 | text = gtk_text_new (NULL, NULL); |
---|
1462 | gtk_text_set_editable (GTK_TEXT (text), FALSE); |
---|
1463 | gtk_table_attach_defaults (GTK_TABLE (table), text, 0, 1, 0, 1); |
---|
1464 | gtk_widget_show (text); |
---|
1465 | gtk_widget_realize (text); |
---|
1466 | |
---|
1467 | hscrollbar = gtk_hscrollbar_new (GTK_TEXT (text)->hadj); |
---|
1468 | gtk_table_attach (GTK_TABLE (table), hscrollbar, 0, 1, 1, 2, |
---|
1469 | GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0); |
---|
1470 | gtk_widget_show (hscrollbar); |
---|
1471 | |
---|
1472 | vscrollbar = gtk_vscrollbar_new (GTK_TEXT (text)->vadj); |
---|
1473 | gtk_table_attach (GTK_TABLE (table), vscrollbar, 1, 2, 0, 1, |
---|
1474 | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); |
---|
1475 | gtk_widget_show (vscrollbar); |
---|
1476 | |
---|
1477 | separator = gtk_hseparator_new (); |
---|
1478 | gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0); |
---|
1479 | gtk_widget_show (separator); |
---|
1480 | |
---|
1481 | |
---|
1482 | box2 = gtk_vbox_new (FALSE, 10); |
---|
1483 | gtk_container_set_border_width (GTK_CONTAINER (box2), 10); |
---|
1484 | gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0); |
---|
1485 | gtk_widget_show (box2); |
---|
1486 | |
---|
1487 | |
---|
1488 | button = gtk_button_new_with_label ("close"); |
---|
1489 | gtk_signal_connect_object (GTK_OBJECT (button), "clicked", |
---|
1490 | (GtkSignalFunc) gtk_widget_hide, |
---|
1491 | GTK_OBJECT (window)); |
---|
1492 | gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); |
---|
1493 | GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); |
---|
1494 | gtk_widget_grab_default (button); |
---|
1495 | gtk_widget_show (button); |
---|
1496 | } |
---|
1497 | |
---|
1498 | level += 1; |
---|
1499 | gtk_text_insert (GTK_TEXT (text), NULL, NULL, NULL, str, -1); |
---|
1500 | level -= 1; |
---|
1501 | |
---|
1502 | if (!GTK_WIDGET_VISIBLE (window)) |
---|
1503 | gtk_widget_show (window); |
---|
1504 | } |
---|
1505 | #endif |
---|