]> Pileus Git - ~andy/gtk/blob - gdk/gdk.c
dce2ac063e4297f85686f5db94e5e26c2bc046eb
[~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 Lesser 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  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser 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-2000.  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
41 struct _GdkPredicate
42 {
43   GdkEventFunc func;
44   gpointer data;
45 };
46
47 /* Private variable declarations
48  */
49 static int gdk_initialized = 0;                     /* 1 if the library is initialized,
50                                                      * 0 otherwise.
51                                                      */
52
53 static gchar  *gdk_progclass = NULL;
54
55 #ifdef G_ENABLE_DEBUG
56 static const GDebugKey gdk_debug_keys[] = {
57   {"events",        GDK_DEBUG_EVENTS},
58   {"misc",          GDK_DEBUG_MISC},
59   {"dnd",           GDK_DEBUG_DND},
60   {"xim",           GDK_DEBUG_XIM},
61   {"nograbs",       GDK_DEBUG_NOGRABS},
62 };
63
64 static const int gdk_ndebug_keys = sizeof(gdk_debug_keys)/sizeof(GDebugKey);
65
66 #endif /* G_ENABLE_DEBUG */
67
68 static GdkArgContext *
69 gdk_arg_context_new (gpointer cb_data)
70 {
71   GdkArgContext *result = g_new (GdkArgContext, 1);
72   result->tables = g_ptr_array_new ();
73   result->cb_data = cb_data;
74
75   return result;
76 }
77
78 static void
79 gdk_arg_context_destroy (GdkArgContext *context)
80 {
81   g_ptr_array_free (context->tables, TRUE);
82   g_free (context);
83 }
84
85 static void
86 gdk_arg_context_add_table (GdkArgContext *context, GdkArgDesc *table)
87 {
88   g_ptr_array_add (context->tables, table);
89 }
90
91 static void
92 gdk_arg_context_parse (GdkArgContext *context, gint *argc, gchar ***argv)
93 {
94   int i, j, k;
95
96   /* Save a copy of the original argc and argv */
97   if (argc && argv)
98     {
99       for (i = 1; i < *argc; i++)
100         {
101           char *arg;
102           
103           if (!(*argv)[i][0] == '-' && (*argv)[i][1] == '-')
104             continue;
105           
106           arg = (*argv)[i] + 2;
107
108           /* '--' terminates list of arguments */
109           if (arg == 0)
110             {
111               (*argv)[i] = NULL;
112               break;
113             }
114               
115           for (j = 0; j < context->tables->len; j++)
116             {
117               GdkArgDesc *table = context->tables->pdata[j];
118               for (k = 0; table[k].name; k++)
119                 {
120                   switch (table[k].type)
121                     {
122                     case GDK_ARG_STRING:
123                     case GDK_ARG_CALLBACK:
124                     case GDK_ARG_INT:
125                       {
126                         int len = strlen (table[k].name);
127                         
128                         if (strncmp (arg, table[k].name, len) == 0 &&
129                             (arg[len] == '=' || arg[len] == 0))
130                           {
131                             char *value = NULL;
132
133                             (*argv)[i] = NULL;
134
135                             if (arg[len] == '=')
136                               value = arg + len + 1;
137                             else if (i < *argc - 1)
138                               {
139                                 value = (*argv)[i + 1];
140                                 (*argv)[i+1] = NULL;
141                                 i++;
142                               }
143                             else
144                               value = "";
145
146                             switch (table[k].type)
147                               {
148                               case GDK_ARG_STRING:
149                                 *(gchar **)table[k].location = g_strdup (value);
150                                 break;
151                               case GDK_ARG_INT:
152                                 *(gint *)table[k].location = atoi (value);
153                                 break;
154                               case GDK_ARG_CALLBACK:
155                                 (*table[k].callback)(table[k].name, value, context->cb_data);
156                                 break;
157                               default:
158                                 ;
159                               }
160
161                             goto next_arg;
162                           }
163                         break;
164                       }
165                     case GDK_ARG_BOOL:
166                     case GDK_ARG_NOBOOL:
167                       if (strcmp (arg, table[k].name) == 0)
168                         {
169                           (*argv)[i] = NULL;
170                           
171                           *(gboolean *)table[k].location = (table[k].type == GDK_ARG_BOOL) ? TRUE : FALSE;
172                           goto next_arg;
173                         }
174                     }
175                 }
176             }
177         next_arg:
178           ;
179         }
180           
181       for (i = 1; i < *argc; i++)
182         {
183           for (k = i; k < *argc; k++)
184             if ((*argv)[k] != NULL)
185               break;
186           
187           if (k > i)
188             {
189               k -= i;
190               for (j = i + k; j < *argc; j++)
191                 (*argv)[j-k] = (*argv)[j];
192               *argc -= k;
193             }
194         }
195     }
196 }
197
198 #ifdef G_ENABLE_DEBUG
199 static void
200 gdk_arg_debug_cb (const char *key, const char *value, gpointer user_data)
201 {
202   _gdk_debug_flags |= g_parse_debug_string (value,
203                                             (GDebugKey *) gdk_debug_keys,
204                                             gdk_ndebug_keys);
205 }
206
207 static void
208 gdk_arg_no_debug_cb (const char *key, const char *value, gpointer user_data)
209 {
210   _gdk_debug_flags &= ~g_parse_debug_string (value,
211                                              (GDebugKey *) gdk_debug_keys,
212                                              gdk_ndebug_keys);
213 }
214 #endif /* G_ENABLE_DEBUG */
215
216 static void
217 gdk_arg_class_cb (const char *key, const char *value, gpointer user_data)
218 {
219   gdk_set_program_class (value);
220 }
221
222 static void
223 gdk_arg_name_cb (const char *key, const char *value, gpointer user_data)
224 {
225   g_set_prgname (value);
226 }
227
228 static GdkArgDesc gdk_args[] = {
229   { "class" ,       GDK_ARG_CALLBACK, NULL, gdk_arg_class_cb    },
230   { "name",         GDK_ARG_CALLBACK, NULL, gdk_arg_name_cb     },
231 #ifdef G_ENABLE_DEBUG
232   { "gdk-debug",    GDK_ARG_CALLBACK, NULL, gdk_arg_debug_cb    },
233   { "gdk-no-debug", GDK_ARG_CALLBACK, NULL, gdk_arg_no_debug_cb },
234 #endif /* G_ENABLE_DEBUG */
235   { NULL }
236 };
237
238 /*
239  *--------------------------------------------------------------
240  * gdk_init_check
241  *
242  *   Initialize the library for use.
243  *
244  * Arguments:
245  *   "argc" is the number of arguments.
246  *   "argv" is an array of strings.
247  *
248  * Results:
249  *   "argc" and "argv" are modified to reflect any arguments
250  *   which were not handled. (Such arguments should either
251  *   be handled by the application or dismissed). If initialization
252  *   fails, returns FALSE, otherwise TRUE.
253  *
254  * Side effects:
255  *   The library is initialized.
256  *
257  *--------------------------------------------------------------
258  */
259
260 gboolean
261 gdk_init_check (int    *argc,
262                 char ***argv)
263 {
264   gchar **argv_orig = NULL;
265   gint argc_orig = 0;
266   GdkArgContext *arg_context;
267   gboolean result;
268   int i;
269   
270   if (gdk_initialized)
271     return TRUE;
272
273   if (argc && argv)
274     {
275       argc_orig = *argc;
276       
277       argv_orig = g_malloc ((argc_orig + 1) * sizeof (char*));
278       for (i = 0; i < argc_orig; i++)
279         argv_orig[i] = g_strdup ((*argv)[i]);
280       argv_orig[argc_orig] = NULL;
281
282       if (*argc > 0)
283         {
284           gchar *d;
285           
286           d = strrchr((*argv)[0], G_DIR_SEPARATOR);
287           if (d != NULL)
288             g_set_prgname (d + 1);
289           else
290             g_set_prgname ((*argv)[0]);
291         }
292     }
293   else
294     {
295       g_set_prgname ("<unknown>");
296     }
297   
298 #ifdef G_ENABLE_DEBUG
299   {
300     gchar *debug_string = getenv("GDK_DEBUG");
301     if (debug_string != NULL)
302       _gdk_debug_flags = g_parse_debug_string (debug_string,
303                                               (GDebugKey *) gdk_debug_keys,
304                                               gdk_ndebug_keys);
305   }
306 #endif  /* G_ENABLE_DEBUG */
307   
308   arg_context = gdk_arg_context_new (NULL);
309   gdk_arg_context_add_table (arg_context, gdk_args);
310   gdk_arg_context_add_table (arg_context, _gdk_windowing_args);
311   gdk_arg_context_parse (arg_context, argc, argv);
312   gdk_arg_context_destroy (arg_context);
313   
314   GDK_NOTE (MISC, g_message ("progname: \"%s\"", g_get_prgname ()));
315
316   g_type_init ();
317   
318   result = _gdk_windowing_init_check (argc_orig, argv_orig);
319
320   for (i = 0; i < argc_orig; i++)
321     g_free(argv_orig[i]);
322   g_free(argv_orig);
323
324   if (!result)
325     return FALSE;
326   
327   _gdk_visual_init ();
328   _gdk_windowing_window_init ();
329   _gdk_windowing_image_init ();
330   _gdk_events_init ();
331   _gdk_input_init ();
332   _gdk_dnd_init ();
333
334   gdk_initialized = 1;
335
336   return TRUE;
337 }
338
339 void
340 gdk_init (int *argc, char ***argv)
341 {
342   if (!gdk_init_check (argc, argv))
343     {
344       g_warning ("cannot open display: %s", gdk_get_display ());
345       exit(1);
346     }
347 }
348
349 /*
350  *--------------------------------------------------------------
351  * gdk_exit
352  *
353  *   Restores the library to an un-itialized state and exits
354  *   the program using the "exit" system call.
355  *
356  * Arguments:
357  *   "errorcode" is the error value to pass to "exit".
358  *
359  * Results:
360  *   Allocated structures are freed and the program exits
361  *   cleanly.
362  *
363  * Side effects:
364  *
365  *--------------------------------------------------------------
366  */
367
368 void
369 gdk_exit (gint errorcode)
370 {
371   /* de-initialisation is done by the gdk_exit_funct(),
372      no need to do this here (Alex J.) */
373   exit (errorcode);
374 }
375
376 #if 0
377
378 /* This is disabled, but the code isn't removed, because we might
379  * want to have some sort of explicit way to shut down GDK cleanly
380  * at some point in the future.
381  */
382
383 /*
384  *--------------------------------------------------------------
385  * gdk_exit_func
386  *
387  *   This is the "atexit" function that makes sure the
388  *   library gets a chance to cleanup.
389  *
390  * Arguments:
391  *
392  * Results:
393  *
394  * Side effects:
395  *   The library is un-initialized and the program exits.
396  *
397  *--------------------------------------------------------------
398  */
399
400 static void
401 gdk_exit_func (void)
402 {
403   static gboolean in_gdk_exit_func = FALSE;
404   
405   /* This is to avoid an infinite loop if a program segfaults in
406      an atexit() handler (and yes, it does happen, especially if a program
407      has trounced over memory too badly for even g_message to work) */
408   if (in_gdk_exit_func == TRUE)
409     return;
410   in_gdk_exit_func = TRUE;
411   
412   if (gdk_initialized)
413     {
414       _gdk_image_exit ();
415       _gdk_input_exit ();
416
417       _gdk_windowing_exit ();
418       
419       gdk_initialized = 0;
420     }
421 }
422
423 #endif
424
425 void
426 gdk_threads_enter ()
427 {
428   GDK_THREADS_ENTER ();
429 }
430
431 void
432 gdk_threads_leave ()
433 {
434   GDK_THREADS_LEAVE ();
435 }
436
437 /**
438  * gdk_threads_init:
439  * 
440  * Initializes GDK so that it can be used from multiple threads
441  * in conjunction with gdk_threads_enter() and gdk_threads_leave().
442  * g_thread_init() must be called previous to this function.
443  *
444  * This call must be made before any use of the main loop from
445  * GTK+; to be safe, call it before gtk_init().
446  **/
447 void
448 gdk_threads_init ()
449 {
450   if (!g_thread_supported ())
451     g_error ("g_thread_init() must be called before gdk_threads_init()");
452
453   gdk_threads_mutex = g_mutex_new ();
454 }
455
456 G_CONST_RETURN char *
457 gdk_get_program_class (void)
458 {
459   if (gdk_progclass == NULL)
460     {
461       gdk_progclass = g_strdup (g_get_prgname ());
462       gdk_progclass[0] = g_ascii_toupper (gdk_progclass[0]);
463     }
464   
465   return gdk_progclass;
466 }
467
468 void
469 gdk_set_program_class (const char *program_class)
470 {
471   if (gdk_progclass)
472     g_free (gdk_progclass);
473
474   gdk_progclass = g_strdup (program_class);
475 }