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