]> Pileus Git - ~andy/gtk/blob - gdk/gdk.c
Add call to g_type_init() - we'll need this later, and this makes sure
[~andy/gtk] / gdk / gdk.c
1 /* GDK - The GIMP Drawing Kit
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 "config.h"
28
29 #include <string.h>
30 #include <stdlib.h>
31
32 #include "gdk.h"
33 #include "gdkinternals.h"
34
35 #ifndef HAVE_XCONVERTCASE
36 #include "gdkkeysyms.h"
37 #endif
38
39 typedef struct _GdkPredicate  GdkPredicate;
40 typedef struct _GdkErrorTrap  GdkErrorTrap;
41
42 struct _GdkPredicate
43 {
44   GdkEventFunc func;
45   gpointer data;
46 };
47
48 struct _GdkErrorTrap
49 {
50   gint error_warnings;
51   gint error_code;
52 };
53
54 /* 
55  * Private function declarations
56  */
57 static void         gdk_exit_func                (void);
58
59 GdkFilterReturn gdk_wm_protocols_filter (GdkXEvent *xev,
60                                          GdkEvent  *event,
61                                          gpointer   data);
62
63 /* Private variable declarations
64  */
65 static int gdk_initialized = 0;                     /* 1 if the library is initialized,
66                                                      * 0 otherwise.
67                                                      */
68
69 static GSList *gdk_error_traps = NULL;               /* List of error traps */
70 static GSList *gdk_error_trap_free_list = NULL;      /* Free list */
71
72 #ifdef G_ENABLE_DEBUG
73 static const GDebugKey gdk_debug_keys[] = {
74   {"events",        GDK_DEBUG_EVENTS},
75   {"misc",          GDK_DEBUG_MISC},
76   {"dnd",           GDK_DEBUG_DND},
77   {"color-context", GDK_DEBUG_COLOR_CONTEXT},
78   {"xim",           GDK_DEBUG_XIM}
79 };
80
81 static const int gdk_ndebug_keys = sizeof(gdk_debug_keys)/sizeof(GDebugKey);
82
83 #endif /* G_ENABLE_DEBUG */
84
85 GdkArgContext *
86 gdk_arg_context_new (gpointer cb_data)
87 {
88   GdkArgContext *result = g_new (GdkArgContext, 1);
89   result->tables = g_ptr_array_new ();
90   result->cb_data = cb_data;
91
92   return result;
93 }
94
95 void
96 gdk_arg_context_destroy (GdkArgContext *context)
97 {
98   g_ptr_array_free (context->tables, TRUE);
99   g_free (context);
100 }
101
102 void
103 gdk_arg_context_add_table (GdkArgContext *context, GdkArgDesc *table)
104 {
105   g_ptr_array_add (context->tables, table);
106 }
107
108 void
109 gdk_arg_context_parse (GdkArgContext *context, gint *argc, gchar ***argv)
110 {
111   int i, j, k;
112
113   /* Save a copy of the original argc and argv */
114   if (argc && argv)
115     {
116       for (i = 1; i < *argc; i++)
117         {
118           char *arg;
119           
120           if (!(*argv)[i][0] == '-' && (*argv)[i][1] == '-')
121             continue;
122           
123           arg = (*argv)[i] + 2;
124
125           /* '--' terminates list of arguments */
126           if (arg == 0)
127             {
128               (*argv)[i] = NULL;
129               break;
130             }
131               
132           for (j = 0; j < context->tables->len; j++)
133             {
134               GdkArgDesc *table = context->tables->pdata[j];
135               for (k = 0; table[k].name; k++)
136                 {
137                   switch (table[k].type)
138                     {
139                     case GDK_ARG_STRING:
140                     case GDK_ARG_CALLBACK:
141                     case GDK_ARG_INT:
142                       {
143                         int len = strlen (table[k].name);
144                         
145                         if (strncmp (arg, table[k].name, len) == 0 &&
146                             (arg[len] == '=' || argc[len] == 0))
147                           {
148                             char *value = NULL;
149
150                             (*argv)[i] = NULL;
151
152                             if (arg[len] == '=')
153                               value = arg + len + 1;
154                             else if (i < *argc - 1)
155                               {
156                                 value = (*argv)[i + 1];
157                                 (*argv)[i+1] = NULL;
158                                 i++;
159                               }
160                             else
161                               value = "";
162
163                             switch (table[k].type)
164                               {
165                               case GDK_ARG_STRING:
166                                 *(gchar **)table[k].location = g_strdup (value);
167                                 break;
168                               case GDK_ARG_INT:
169                                 *(gint *)table[k].location = atoi (value);
170                                 break;
171                               case GDK_ARG_CALLBACK:
172                                 (*table[k].callback)(table[k].name, value, context->cb_data);
173                                 break;
174                               default:
175                                 ;
176                               }
177
178                             goto next_arg;
179                           }
180                         break;
181                       }
182                     case GDK_ARG_BOOL:
183                     case GDK_ARG_NOBOOL:
184                       if (strcmp (arg, table[k].name) == 0)
185                         {
186                           (*argv)[i] = NULL;
187                           
188                           *(gboolean *)table[k].location = (table[k].type == GDK_ARG_BOOL) ? TRUE : FALSE;
189                           goto next_arg;
190                         }
191                     }
192                 }
193             }
194         next_arg:
195           ;
196         }
197           
198       for (i = 1; i < *argc; i++)
199         {
200           for (k = i; k < *argc; k++)
201             if ((*argv)[k] != NULL)
202               break;
203           
204           if (k > i)
205             {
206               k -= i;
207               for (j = i + k; j < *argc; j++)
208                 (*argv)[j-k] = (*argv)[j];
209               *argc -= k;
210             }
211         }
212     }
213 }
214
215 static void
216 gdk_arg_debug_cb (const char *key, const char *value, gpointer user_data)
217 {
218   gdk_debug_flags |= g_parse_debug_string (value,
219                                            (GDebugKey *) gdk_debug_keys,
220                                            gdk_ndebug_keys);
221 }
222
223 static void
224 gdk_arg_no_debug_cb (const char *key, const char *value, gpointer user_data)
225 {
226   gdk_debug_flags &= ~g_parse_debug_string (value,
227                                             (GDebugKey *) gdk_debug_keys,
228                                             gdk_ndebug_keys);
229 }
230
231 static void
232 gdk_arg_name_cb (const char *key, const char *value, gpointer user_data)
233 {
234   g_set_prgname (value);
235 }
236
237 static GdkArgDesc gdk_args[] = {
238   { "name",         GDK_ARG_STRING,   NULL, gdk_arg_name_cb     },
239 #ifdef G_ENABLE_DEBUG
240   { "gdk-debug",    GDK_ARG_CALLBACK, NULL, gdk_arg_debug_cb    },
241   { "gdk-no-debug", GDK_ARG_CALLBACK, NULL, gdk_arg_no_debug_cb },
242 #endif /* G_ENABLE_DEBUG */
243   { NULL }
244 };
245
246 /*
247  *--------------------------------------------------------------
248  * gdk_init_check
249  *
250  *   Initialize the library for use.
251  *
252  * Arguments:
253  *   "argc" is the number of arguments.
254  *   "argv" is an array of strings.
255  *
256  * Results:
257  *   "argc" and "argv" are modified to reflect any arguments
258  *   which were not handled. (Such arguments should either
259  *   be handled by the application or dismissed). If initialization
260  *   fails, returns FALSE, otherwise TRUE.
261  *
262  * Side effects:
263  *   The library is initialized.
264  *
265  *--------------------------------------------------------------
266  */
267
268 gboolean
269 gdk_init_check (int    *argc,
270                 char ***argv)
271 {
272   gchar **argv_orig = NULL;
273   gint argc_orig = 0;
274   GdkArgContext *arg_context;
275   gboolean result;
276   int i;
277   
278   if (gdk_initialized)
279     return TRUE;
280
281   if (g_thread_supported ())
282     gdk_threads_mutex = g_mutex_new ();
283   
284   if (argc && argv)
285     {
286       argc_orig = *argc;
287       
288       argv_orig = g_malloc ((argc_orig + 1) * sizeof (char*));
289       for (i = 0; i < argc_orig; i++)
290         argv_orig[i] = g_strdup ((*argv)[i]);
291       argv_orig[argc_orig] = NULL;
292
293       if (*argc > 0)
294         {
295           gchar *d;
296           
297           d = strrchr((*argv)[0], G_DIR_SEPARATOR);
298           if (d != NULL)
299             g_set_prgname (d + 1);
300           else
301             g_set_prgname ((*argv)[0]);
302         }
303     }
304
305   
306 #ifdef G_ENABLE_DEBUG
307   {
308     gchar *debug_string = getenv("GDK_DEBUG");
309     if (debug_string != NULL)
310       gdk_debug_flags = g_parse_debug_string (debug_string,
311                                               (GDebugKey *) gdk_debug_keys,
312                                               gdk_ndebug_keys);
313   }
314 #endif  /* G_ENABLE_DEBUG */
315
316   arg_context = gdk_arg_context_new (NULL);
317   gdk_arg_context_add_table (arg_context, gdk_args);
318   gdk_arg_context_add_table (arg_context, _gdk_windowing_args);
319   gdk_arg_context_parse (arg_context, argc, argv);
320   gdk_arg_context_destroy (arg_context);
321   
322   GDK_NOTE (MISC, g_message ("progname: \"%s\"", g_get_prgname ()));
323
324   g_type_init ();
325   
326   result = _gdk_windowing_init_check (argc_orig, argv_orig);
327
328   for (i = 0; i < argc_orig; i++)
329     g_free(argv_orig[i]);
330   g_free(argv_orig);
331
332   if (!result)
333     return FALSE;
334   
335   g_atexit (gdk_exit_func);
336   
337   gdk_events_init ();
338   gdk_visual_init ();
339   gdk_window_init ();
340   gdk_image_init ();
341   gdk_input_init ();
342   gdk_dnd_init ();
343
344 #ifdef USE_XIM
345   gdk_im_open ();
346 #endif
347   
348   gdk_initialized = 1;
349
350   return TRUE;
351 }
352
353 void
354 gdk_init (int *argc, char ***argv)
355 {
356   if (!gdk_init_check (argc, argv))
357     {
358       g_warning ("cannot open display: %s", gdk_get_display ());
359       exit(1);
360     }
361 }
362
363 /*
364  *--------------------------------------------------------------
365  * gdk_exit
366  *
367  *   Restores the library to an un-itialized state and exits
368  *   the program using the "exit" system call.
369  *
370  * Arguments:
371  *   "errorcode" is the error value to pass to "exit".
372  *
373  * Results:
374  *   Allocated structures are freed and the program exits
375  *   cleanly.
376  *
377  * Side effects:
378  *
379  *--------------------------------------------------------------
380  */
381
382 void
383 gdk_exit (gint errorcode)
384 {
385   /* de-initialisation is done by the gdk_exit_funct(),
386      no need to do this here (Alex J.) */
387   exit (errorcode);
388 }
389
390 /*
391  *--------------------------------------------------------------
392  * gdk_exit_func
393  *
394  *   This is the "atexit" function that makes sure the
395  *   library gets a chance to cleanup.
396  *
397  * Arguments:
398  *
399  * Results:
400  *
401  * Side effects:
402  *   The library is un-initialized and the program exits.
403  *
404  *--------------------------------------------------------------
405  */
406
407 static void
408 gdk_exit_func (void)
409 {
410   static gboolean in_gdk_exit_func = FALSE;
411   
412   /* This is to avoid an infinite loop if a program segfaults in
413      an atexit() handler (and yes, it does happen, especially if a program
414      has trounced over memory too badly for even g_message to work) */
415   if (in_gdk_exit_func == TRUE)
416     return;
417   in_gdk_exit_func = TRUE;
418   
419   if (gdk_initialized)
420     {
421 #ifdef USE_XIM
422       /* cleanup IC */
423       gdk_ic_cleanup ();
424       /* close IM */
425       gdk_im_close ();
426 #endif
427       gdk_image_exit ();
428       gdk_input_exit ();
429       gdk_key_repeat_restore ();
430
431       gdk_windowing_exit ();
432       
433       gdk_initialized = 0;
434     }
435 }
436
437 /*************************************************************
438  * gdk_error_trap_push:
439  *     Push an error trap. X errors will be trapped until
440  *     the corresponding gdk_error_pop(), which will return
441  *     the error code, if any.
442  *   arguments:
443  *     
444  *   results:
445  *************************************************************/
446
447 void
448 gdk_error_trap_push (void)
449 {
450   GSList *node;
451   GdkErrorTrap *trap;
452
453   if (gdk_error_trap_free_list)
454     {
455       node = gdk_error_trap_free_list;
456       gdk_error_trap_free_list = gdk_error_trap_free_list->next;
457     }
458   else
459     {
460       node = g_slist_alloc ();
461       node->data = g_new (GdkErrorTrap, 1);
462     }
463
464   node->next = gdk_error_traps;
465   gdk_error_traps = node;
466   
467   trap = node->data;
468   trap->error_code = gdk_error_code;
469   trap->error_warnings = gdk_error_warnings;
470
471   gdk_error_code = 0;
472   gdk_error_warnings = 0;
473 }
474
475 /*************************************************************
476  * gdk_error_trap_pop:
477  *     Pop an error trap added with gdk_error_push()
478  *   arguments:
479  *     
480  *   results:
481  *     0, if no error occured, otherwise the error code.
482  *************************************************************/
483
484 gint
485 gdk_error_trap_pop (void)
486 {
487   GSList *node;
488   GdkErrorTrap *trap;
489   gint result;
490
491   g_return_val_if_fail (gdk_error_traps != NULL, 0);
492
493   node = gdk_error_traps;
494   gdk_error_traps = gdk_error_traps->next;
495
496   node->next = gdk_error_trap_free_list;
497   gdk_error_trap_free_list = node;
498   
499   result = gdk_error_code;
500   
501   trap = node->data;
502   gdk_error_code = trap->error_code;
503   gdk_error_warnings = trap->error_warnings;
504   
505   return result;
506 }
507
508 #ifndef HAVE_XCONVERTCASE
509 /* compatibility function from X11R6.3, since XConvertCase is not
510  * supplied by X11R5.
511  */
512 void
513 gdk_keyval_convert_case (guint symbol,
514                          guint *lower,
515                          guint *upper)
516 {
517   guint xlower = symbol;
518   guint xupper = symbol;
519
520   switch (symbol >> 8)
521     {
522 #if     defined (GDK_A) && defined (GDK_Ooblique)
523     case 0: /* Latin 1 */
524       if ((symbol >= GDK_A) && (symbol <= GDK_Z))
525         xlower += (GDK_a - GDK_A);
526       else if ((symbol >= GDK_a) && (symbol <= GDK_z))
527         xupper -= (GDK_a - GDK_A);
528       else if ((symbol >= GDK_Agrave) && (symbol <= GDK_Odiaeresis))
529         xlower += (GDK_agrave - GDK_Agrave);
530       else if ((symbol >= GDK_agrave) && (symbol <= GDK_odiaeresis))
531         xupper -= (GDK_agrave - GDK_Agrave);
532       else if ((symbol >= GDK_Ooblique) && (symbol <= GDK_Thorn))
533         xlower += (GDK_oslash - GDK_Ooblique);
534       else if ((symbol >= GDK_oslash) && (symbol <= GDK_thorn))
535         xupper -= (GDK_oslash - GDK_Ooblique);
536       break;
537 #endif  /* LATIN1 */
538       
539 #if     defined (GDK_Aogonek) && defined (GDK_tcedilla)
540     case 1: /* Latin 2 */
541       /* Assume the KeySym is a legal value (ignore discontinuities) */
542       if (symbol == GDK_Aogonek)
543         xlower = GDK_aogonek;
544       else if (symbol >= GDK_Lstroke && symbol <= GDK_Sacute)
545         xlower += (GDK_lstroke - GDK_Lstroke);
546       else if (symbol >= GDK_Scaron && symbol <= GDK_Zacute)
547         xlower += (GDK_scaron - GDK_Scaron);
548       else if (symbol >= GDK_Zcaron && symbol <= GDK_Zabovedot)
549         xlower += (GDK_zcaron - GDK_Zcaron);
550       else if (symbol == GDK_aogonek)
551         xupper = GDK_Aogonek;
552       else if (symbol >= GDK_lstroke && symbol <= GDK_sacute)
553         xupper -= (GDK_lstroke - GDK_Lstroke);
554       else if (symbol >= GDK_scaron && symbol <= GDK_zacute)
555         xupper -= (GDK_scaron - GDK_Scaron);
556       else if (symbol >= GDK_zcaron && symbol <= GDK_zabovedot)
557         xupper -= (GDK_zcaron - GDK_Zcaron);
558       else if (symbol >= GDK_Racute && symbol <= GDK_Tcedilla)
559         xlower += (GDK_racute - GDK_Racute);
560       else if (symbol >= GDK_racute && symbol <= GDK_tcedilla)
561         xupper -= (GDK_racute - GDK_Racute);
562       break;
563 #endif  /* LATIN2 */
564       
565 #if     defined (GDK_Hstroke) && defined (GDK_Cabovedot)
566     case 2: /* Latin 3 */
567       /* Assume the KeySym is a legal value (ignore discontinuities) */
568       if (symbol >= GDK_Hstroke && symbol <= GDK_Hcircumflex)
569         xlower += (GDK_hstroke - GDK_Hstroke);
570       else if (symbol >= GDK_Gbreve && symbol <= GDK_Jcircumflex)
571         xlower += (GDK_gbreve - GDK_Gbreve);
572       else if (symbol >= GDK_hstroke && symbol <= GDK_hcircumflex)
573         xupper -= (GDK_hstroke - GDK_Hstroke);
574       else if (symbol >= GDK_gbreve && symbol <= GDK_jcircumflex)
575         xupper -= (GDK_gbreve - GDK_Gbreve);
576       else if (symbol >= GDK_Cabovedot && symbol <= GDK_Scircumflex)
577         xlower += (GDK_cabovedot - GDK_Cabovedot);
578       else if (symbol >= GDK_cabovedot && symbol <= GDK_scircumflex)
579         xupper -= (GDK_cabovedot - GDK_Cabovedot);
580       break;
581 #endif  /* LATIN3 */
582       
583 #if     defined (GDK_Rcedilla) && defined (GDK_Amacron)
584     case 3: /* Latin 4 */
585       /* Assume the KeySym is a legal value (ignore discontinuities) */
586       if (symbol >= GDK_Rcedilla && symbol <= GDK_Tslash)
587         xlower += (GDK_rcedilla - GDK_Rcedilla);
588       else if (symbol >= GDK_rcedilla && symbol <= GDK_tslash)
589         xupper -= (GDK_rcedilla - GDK_Rcedilla);
590       else if (symbol == GDK_ENG)
591         xlower = GDK_eng;
592       else if (symbol == GDK_eng)
593         xupper = GDK_ENG;
594       else if (symbol >= GDK_Amacron && symbol <= GDK_Umacron)
595         xlower += (GDK_amacron - GDK_Amacron);
596       else if (symbol >= GDK_amacron && symbol <= GDK_umacron)
597         xupper -= (GDK_amacron - GDK_Amacron);
598       break;
599 #endif  /* LATIN4 */
600       
601 #if     defined (GDK_Serbian_DJE) && defined (GDK_Cyrillic_yu)
602     case 6: /* Cyrillic */
603       /* Assume the KeySym is a legal value (ignore discontinuities) */
604       if (symbol >= GDK_Serbian_DJE && symbol <= GDK_Serbian_DZE)
605         xlower -= (GDK_Serbian_DJE - GDK_Serbian_dje);
606       else if (symbol >= GDK_Serbian_dje && symbol <= GDK_Serbian_dze)
607         xupper += (GDK_Serbian_DJE - GDK_Serbian_dje);
608       else if (symbol >= GDK_Cyrillic_YU && symbol <= GDK_Cyrillic_HARDSIGN)
609         xlower -= (GDK_Cyrillic_YU - GDK_Cyrillic_yu);
610       else if (symbol >= GDK_Cyrillic_yu && symbol <= GDK_Cyrillic_hardsign)
611         xupper += (GDK_Cyrillic_YU - GDK_Cyrillic_yu);
612       break;
613 #endif  /* CYRILLIC */
614       
615 #if     defined (GDK_Greek_ALPHAaccent) && defined (GDK_Greek_finalsmallsigma)
616     case 7: /* Greek */
617       /* Assume the KeySym is a legal value (ignore discontinuities) */
618       if (symbol >= GDK_Greek_ALPHAaccent && symbol <= GDK_Greek_OMEGAaccent)
619         xlower += (GDK_Greek_alphaaccent - GDK_Greek_ALPHAaccent);
620       else if (symbol >= GDK_Greek_alphaaccent && symbol <= GDK_Greek_omegaaccent &&
621                symbol != GDK_Greek_iotaaccentdieresis &&
622                symbol != GDK_Greek_upsilonaccentdieresis)
623         xupper -= (GDK_Greek_alphaaccent - GDK_Greek_ALPHAaccent);
624       else if (symbol >= GDK_Greek_ALPHA && symbol <= GDK_Greek_OMEGA)
625         xlower += (GDK_Greek_alpha - GDK_Greek_ALPHA);
626       else if (symbol >= GDK_Greek_alpha && symbol <= GDK_Greek_omega &&
627                symbol != GDK_Greek_finalsmallsigma)
628         xupper -= (GDK_Greek_alpha - GDK_Greek_ALPHA);
629       break;
630 #endif  /* GREEK */
631     }
632
633   if (lower)
634     *lower = xlower;
635   if (upper)
636     *upper = xupper;
637 }
638 #endif
639
640 guint
641 gdk_keyval_to_upper (guint keyval)
642 {
643   guint result;
644   
645   gdk_keyval_convert_case (keyval, NULL, &result);
646
647   return result;
648 }
649
650 guint
651 gdk_keyval_to_lower (guint keyval)
652 {
653   guint result;
654   
655   gdk_keyval_convert_case (keyval, &result, NULL);
656
657   return result;
658 }
659
660 gboolean
661 gdk_keyval_is_upper (guint keyval)
662 {
663   if (keyval)
664     {
665       guint upper_val = 0;
666       
667       gdk_keyval_convert_case (keyval, NULL, &upper_val);
668       return upper_val == keyval;
669     }
670   return FALSE;
671 }
672
673 gboolean
674 gdk_keyval_is_lower (guint keyval)
675 {
676   if (keyval)
677     {
678       guint lower_val = 0;
679       
680       gdk_keyval_convert_case (keyval, &lower_val, NULL);
681       return lower_val == keyval;
682     }
683   return FALSE;
684 }
685
686 void
687 gdk_threads_enter ()
688 {
689   GDK_THREADS_ENTER ();
690 }
691
692 void
693 gdk_threads_leave ()
694 {
695   GDK_THREADS_LEAVE ();
696 }
697