1 /*
2  * Copyright (C) 2000-2019 the xine project
3  *
4  * This file is part of xine, a unix video player.
5  *
6  * xine is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * xine is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
19  *
20  */
21 #define _XITK_C_
22 
23 /* required to enable POSIX variant of getpwuid_r on solaris */
24 #define _POSIX_PTHREAD_SEMANTICS 1
25 
26 
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30 
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <pthread.h>
35 #include <pwd.h>
36 #include <errno.h>
37 #include <inttypes.h>
38 #include <unistd.h>
39 #include <signal.h>
40 #include <time.h>
41 #include <sys/types.h>
42 #include <sys/wait.h>
43 #include <sys/time.h>
44 
45 #ifdef ENABLE_NLS
46 #include <locale.h>
47 #endif
48 
49 #ifdef HAVE_EXECINFO_H
50 #include <execinfo.h>
51 #endif
52 
53 #include <X11/Xlib.h>
54 #include <X11/Xatom.h>
55 #include <X11/keysym.h>
56 
57 #include "utils.h"
58 #include "_xitk.h"
59 
60 extern char **environ;
61 #undef TRACE_LOCKS
62 
63 #ifdef TRACE_LOCKS
64 static int ml = 0;
65 #define MUTLOCK()                          \
66   do {                                     \
67     int i;                                 \
68     ml++;                                  \
69     for (i = 0; i < ml; i++) printf ("."); \
70     printf ("LOCK\n");                     \
71     pthread_mutex_lock (&xitk->mutex);     \
72   } while (0)
73 
74 #define MUTUNLOCK()                        \
75   do {                                     \
76     int i;                                 \
77     for (i = 0; i < ml; i++) printf ("."); \
78     printf ("UNLOCK\n");                   \
79     ml--;                                  \
80     pthread_mutex_unlock (&xitk->mutex);   \
81   } while (0)
82 
83 #else
84 #define MUTLOCK()   pthread_mutex_lock (&xitk->mutex)
85 #define MUTUNLOCK() pthread_mutex_unlock (&xitk->mutex)
86 #endif
87 
88 #define FXLOCK(_fx)       __gfx_lock(_fx)
89 #define FXUNLOCK(_fx)     __gfx_unlock(_fx)
90 
91 typedef struct {
92   xitk_dnode_t                node;
93 
94   Window                      window;
95   Atom                        XA_XITK;
96 
97   xitk_move_t                 move;
98 
99   struct {
100     int                       x;
101     int                       y;
102   } old_pos;
103 
104   struct {
105     int                       x;
106     int                       y;
107   } new_pos;
108 
109   int                         width;
110   int                         height;
111 
112   XEvent                     *old_event;
113 
114   xitk_widget_list_t         *widget_list;
115   char                       *name;
116   widget_event_callback_t     xevent_callback;
117   widget_newpos_callback_t    newpos_callback;
118   xitk_register_key_t         key;
119   xitk_dnd_t                 *xdnd;
120   void                       *user_data;
121 
122   pthread_mutex_t             mutex;
123   int                         destroy;
124   pthread_t                   owning_thread;
125 } __gfx_t;
126 
127 
__gfx_lock(__gfx_t * fx)128 static int __gfx_lock(__gfx_t *fx)
129 {
130   int retval = pthread_mutex_lock(&fx->mutex);
131   if (0 == retval)
132     fx->owning_thread = pthread_self();
133 
134   return retval;
135 }
136 
__gfx_unlock(__gfx_t * fx)137 static int __gfx_unlock(__gfx_t *fx)
138 {
139   fx->owning_thread = (pthread_t)0;
140   return pthread_mutex_unlock(&fx->mutex);
141 }
142 
__gfx_safe_lock(__gfx_t * fx)143 static int __gfx_safe_lock (__gfx_t *fx) {
144   pthread_t self = pthread_self ();
145   if (!pthread_mutex_trylock (&fx->mutex)) {
146     fx->owning_thread = self;
147     return 0;
148   }
149   if (pthread_equal (self, fx->owning_thread))
150     return 1;
151   if (!pthread_mutex_lock (&fx->mutex)) {
152     fx->owning_thread = self;
153     return 0;
154   }
155   return 2;
156 }
157 
158 typedef struct {
159   xitk_t                      x;
160 
161   XColor                      black;
162   int                         display_width;
163   int                         display_height;
164   int                         verbosity;
165   xitk_dlist_t                wlists;
166   xitk_dlist_t                gfxs;
167   int                         use_xshm;
168 
169   uint32_t                    wm_type;
170 
171   int                        (*x_error_handler)(Display *, XErrorEvent *);
172 
173   pthread_mutex_t             mutex;
174   int                         running;
175   xitk_register_key_t         key;
176   xitk_config_t              *config;
177   xitk_signal_callback_t      sig_callback;
178   void                       *sig_data;
179 
180   Window                      modalw;
181   xitk_widget_t              *menu;
182 
183   struct timeval              keypress;
184 
185   KeyCode                     ignore_keys[2];
186 
187   pthread_t                  *tips_thread;
188   unsigned long               tips_timeout;
189 
190   struct {
191     Window                    window;
192     int                       focus;
193   } parent;
194 
195   pid_t                       xitk_pid;
196 
197   struct {
198     Atom                      XA_WIN_LAYER;
199     Atom                      XA_STAYS_ON_TOP;
200 
201     Atom                      XA_NET_WM_STATE;
202     Atom                      XA_NET_WM_STATE_ABOVE;
203     Atom                      XA_NET_WM_STATE_FULLSCREEN;
204 
205     Atom                      XA_WM_WINDOW_TYPE;
206     Atom                      XA_WM_WINDOW_TYPE_DESKTOP;
207     Atom                      XA_WM_WINDOW_TYPE_DOCK;
208     Atom                      XA_WM_WINDOW_TYPE_TOOLBAR;
209     Atom                      XA_WM_WINDOW_TYPE_MENU;
210     Atom                      XA_WM_WINDOW_TYPE_UTILITY;
211     Atom                      XA_WM_WINDOW_TYPE_SPLASH;
212     Atom                      XA_WM_WINDOW_TYPE_DIALOG;
213     Atom                      XA_WM_WINDOW_TYPE_DROPDOWN_MENU;
214     Atom                      XA_WM_WINDOW_TYPE_POPUP_MENU;
215     Atom                      XA_WM_WINDOW_TYPE_TOOLTIP;
216     Atom                      XA_WM_WINDOW_TYPE_NOTIFICATION;
217     Atom                      XA_WM_WINDOW_TYPE_COMBO;
218     Atom                      XA_WM_WINDOW_TYPE_DND;
219     Atom                      XA_WM_WINDOW_TYPE_NORMAL;
220   } atoms;
221 
222 } __xitk_t;
223 
224 xitk_t *gXitk;
225 
226 void widget_stop(void);
227 
xitk_modal_window(Window w)228 void xitk_modal_window(Window w) {
229   __xitk_t *xitk = (__xitk_t *)gXitk;
230   xitk->modalw = w;
231 }
xitk_unmodal_window(Window w)232 void xitk_unmodal_window(Window w) {
233   __xitk_t *xitk = (__xitk_t *)gXitk;
234   if (w == xitk->modalw)
235     xitk->modalw = None;
236 }
237 
238 /*
239  * Execute a shell command.
240  */
xitk_system(int dont_run_as_root,const char * command)241 int xitk_system(int dont_run_as_root, const char *command) {
242   int pid, status;
243 
244   /*
245    * Don't permit run as root
246    */
247   if(dont_run_as_root) {
248     if(getuid() == 0)
249       return -1;
250   }
251 
252   if(command == NULL)
253     return 1;
254 
255   pid = fork();
256 
257   if(pid == -1)
258     return -1;
259 
260   if(pid == 0) {
261     char *argv[4];
262     argv[0] = "sh";
263     argv[1] = "-c";
264     argv[2] = command;
265     argv[3] = 0;
266     execve("/bin/sh", argv, environ);
267     exit(127);
268   }
269 
270   do {
271     if(waitpid(pid, &status, 0) == -1) {
272       if (errno != EINTR)
273 	return -1;
274     }
275     else {
276       return WEXITSTATUS(status);
277     }
278   } while(1);
279 
280   return -1;
281 }
282 
283 /*
284  * A thread-safe usecond sleep
285  */
xitk_usec_sleep(unsigned long usec)286 void xitk_usec_sleep(unsigned long usec) {
287 #ifdef HAVE_NANOSLEEP
288   /* nanosleep is prefered on solaris, because it's mt-safe */
289   struct timespec ts, remaining;
290 
291   ts.tv_sec =   usec / 1000000;
292   ts.tv_nsec = (usec % 1000000) * 1000;
293   while (nanosleep (&ts, &remaining) == -1 && errno == EINTR)
294     ts = remaining;
295 #else
296   usleep(usec);
297 #endif
298 }
299 
_x_ignoring_error_handler(Display * display,XErrorEvent * xevent)300 static int _x_ignoring_error_handler(Display *display, XErrorEvent *xevent) {
301   (void)display;
302   (void)xevent;
303   return 0;
304 }
305 
_x_error_handler(Display * display,XErrorEvent * xevent)306 static int _x_error_handler(Display *display, XErrorEvent *xevent) {
307   char buffer[2048];
308 
309   XGetErrorText(display, xevent->error_code, &buffer[0], 1023);
310 
311   XITK_WARNING("X error received: '%s'\n", buffer);
312 
313   xitk_x_error = 1;
314   return 0;
315 
316 }
317 
xitk_set_current_menu(xitk_widget_t * menu)318 void xitk_set_current_menu(xitk_widget_t *menu) {
319   __xitk_t *xitk = (__xitk_t *)gXitk;
320 
321   if (xitk->menu)
322     xitk_menu_destroy (xitk->menu);
323   xitk->menu = menu;
324 }
325 
xitk_unset_current_menu(void)326 void xitk_unset_current_menu(void) {
327   __xitk_t *xitk = (__xitk_t *)gXitk;
328 
329   xitk->menu = NULL;
330 }
331 
xitk_install_x_error_handler(void)332 int xitk_install_x_error_handler(void) {
333   __xitk_t *xitk = (__xitk_t *)gXitk;
334 
335   if (xitk->x_error_handler == NULL) {
336     xitk->x_error_handler = XSetErrorHandler (_x_error_handler);
337     XSync (xitk->x.display, False);
338     return 1;
339   }
340   return 0;
341 }
342 
xitk_uninstall_x_error_handler(void)343 int xitk_uninstall_x_error_handler(void) {
344   __xitk_t *xitk = (__xitk_t *)gXitk;
345 
346   if (xitk->x_error_handler != NULL) {
347     XSetErrorHandler (xitk->x_error_handler);
348     xitk->x_error_handler = NULL;
349     XSync (xitk->x.display, False);
350     return 1;
351   }
352   return 0;
353 }
354 
355 /*
356  *
357  */
xitk_signal_handler(int sig)358 static void xitk_signal_handler(int sig) {
359   __xitk_t *xitk = (__xitk_t *)gXitk;
360   pid_t cur_pid = getppid();
361 
362   if (xitk) {
363     /* First, call registered handler */
364     if (cur_pid == xitk->xitk_pid) {
365       if (xitk->sig_callback)
366         xitk->sig_callback (sig, xitk->sig_data);
367     }
368     xitk->running = 0;
369   }
370 
371   switch (sig) {
372 
373   case SIGINT:
374   case SIGTERM:
375   case SIGQUIT:
376     if (xitk && (cur_pid == xitk->xitk_pid)) {
377       xitk_dlist_clear (&xitk->wlists);
378       xitk_dlist_clear (&xitk->gfxs);
379       xitk_config_deinit (xitk->config);
380       XITK_FREE (xitk);
381       exit(1);
382     }
383     break;
384 
385   case SIGSEGV:
386     {
387       fprintf(stderr, "xiTK received SIGSEGV signal, RIP.\n");
388 #ifndef DEBUG
389       abort();
390 #elif defined(HAVE_EXECINFO_H)
391       void    *backtrace_array[255];
392       char   **backtrace_strings;
393       int      entries, i;
394 
395       if((entries = backtrace(backtrace_array, 255))) {
396 	if((backtrace_strings = backtrace_symbols(backtrace_array, entries))) {
397 	  printf("Backtrace:\n");
398 
399 	  for(i = 0; i < entries; i++) {
400 	    printf("  [%d] %s\n", i, backtrace_strings[i]);
401 	  }
402 
403 	  free(backtrace_strings);
404 	  printf("--\n");
405 	}
406       }
407 #endif
408     }
409     break;
410 
411 
412   }
413 }
414 
415 /*
416  * Desc: query the server for support for the MIT_SHM extension
417  * Return:  0 = not available
418  *          1 = shared XImage support available
419  *          2 = shared Pixmap support available also
420  * Shamelessly stolen from gdk, and slightly tuned for xitk.
421  */
xitk_check_xshm(Display * display)422 static int xitk_check_xshm(Display *display) {
423 #ifdef HAVE_SHM
424   if(XShmQueryExtension(display)) {
425     int major, minor, ignore;
426     Bool pixmaps;
427 
428     if(XQueryExtension(display, "MIT-SHM", &ignore, &ignore, &ignore)) {
429       if(XShmQueryVersion(display, &major, &minor, &pixmaps ) == True) {
430 	if((pixmaps == True) && ((XShmPixmapFormat(display)) == ZPixmap))
431 	  return 2;
432 	else if(pixmaps == True)
433 	  return 1;
434       }
435     }
436   }
437 #endif
438   return 0;
439 }
xitk_is_use_xshm(void)440 int xitk_is_use_xshm(void) {
441   __xitk_t *xitk = (__xitk_t *)gXitk;
442 
443   return xitk->use_xshm;
444 }
445 
get_wm_name(Display * display,Window win,const char * atom_name)446 static char *get_wm_name(Display *display, Window win, const char *atom_name) {
447   char *wm_name = NULL;
448   Atom  atom;
449 
450   /* Extract WM Name */
451   if((atom = XInternAtom(display, atom_name, True)) != None) {
452     unsigned char   *prop_return = NULL;
453     unsigned long    nitems_return;
454     unsigned long    bytes_after_return;
455     Atom             type_return, type_utf8;
456     int              format_return;
457 
458     if((XGetWindowProperty(display, win, atom, 0, 4, False, XA_STRING,
459 			   &type_return, &format_return, &nitems_return,
460 			   &bytes_after_return, &prop_return)) == Success) {
461 
462       if(type_return != None) {
463 	if(type_return != XA_STRING) {
464 	  type_utf8 = XInternAtom(display, "UTF8_STRING", True);
465 	  if(type_utf8 != None) {
466 
467 	    if(type_return == type_utf8) {
468 
469 	      if(prop_return)
470 		XFree(prop_return);
471 	      prop_return = NULL;
472 
473 	      if((XGetWindowProperty(display, win, atom, 0, 4, False, type_utf8,
474 				     &type_return, &format_return, &nitems_return,
475 				     &bytes_after_return, &prop_return)) == Success) {
476 
477 		if(format_return == 8)
478 		  wm_name = strdup((char *)prop_return);
479 
480 	      }
481 	    }
482 	    else if(format_return == 8)
483 	      wm_name = strdup((char *)prop_return);
484 
485 	  }
486 	}
487 	else
488 	  wm_name = strdup((char *)prop_return);
489 
490       }
491 
492       if(prop_return)
493 	XFree(prop_return);
494     }
495   }
496 
497   return wm_name;
498 }
xitk_check_wm(Display * display)499 static uint32_t xitk_check_wm(Display *display) {
500   __xitk_t *xitk = (__xitk_t *)gXitk;
501   Atom      atom;
502   uint32_t  type = WM_TYPE_UNKNOWN;
503   char     *wm_name = NULL;
504 
505   xitk->x.x_lock_display (display);
506 
507   if((atom = XInternAtom(display, "XFWM_FLAGS", True)) != None) {
508     type |= WM_TYPE_XFCE;
509   }
510   else if((atom = XInternAtom(display, "_WINDOWMAKER_WM_PROTOCOLS", True)) != None) {
511     type |= WM_TYPE_WINDOWMAKER;
512   }
513   else if((atom = XInternAtom(display, "_SAWMILL_TIMESTAMP", True)) != None) {
514     type |= WM_TYPE_SAWFISH;
515   }
516   else if((atom = XInternAtom(display, "ENLIGHTENMENT_COMMS", True)) != None) {
517     type |= WM_TYPE_E;
518   }
519   else if((atom = XInternAtom(display, "_METACITY_RESTART_MESSAGE", True)) != None) {
520     type |= WM_TYPE_METACITY;
521   }
522   else if((atom = XInternAtom(display, "_AS_STYLE", True)) != None) {
523     type |= WM_TYPE_AFTERSTEP;
524   }
525   else if((atom = XInternAtom(display, "_ICEWM_WINOPTHINT", True)) != None) {
526     type |= WM_TYPE_ICE;
527   }
528   else if((atom = XInternAtom(display, "_BLACKBOX_HINTS", True)) != None) {
529     type |= WM_TYPE_BLACKBOX;
530   }
531   else if((atom = XInternAtom(display, "LARSWM_EXIT", True)) != None) {
532     type |= WM_TYPE_LARSWM;
533   }
534   else if(((atom = XInternAtom(display, "KWIN_RUNNING", True)) != None) &&
535 	  ((atom = XInternAtom(display, "_DT_SM_WINDOW_INFO", True)) != None)) {
536     type |= WM_TYPE_KWIN;
537   }
538   else if((atom = XInternAtom(display, "DTWM_IS_RUNNING", True)) != None) {
539     type |= WM_TYPE_DTWM;
540   }
541 
542   xitk_install_x_error_handler();
543 
544   if((atom = XInternAtom(display, "_WIN_SUPPORTING_WM_CHECK", True)) != None) {
545     unsigned char   *prop_return = NULL;
546     unsigned long    nitems_return;
547     unsigned long    bytes_after_return;
548     Atom             type_return;
549     int              format_return;
550     Status           status;
551 
552     /* Check for Gnome Compliant WM */
553     if((XGetWindowProperty(display, (XDefaultRootWindow(display)), atom, 0,
554 			   1, False, XA_CARDINAL,
555 			   &type_return, &format_return, &nitems_return,
556 			   &bytes_after_return, &prop_return)) == Success) {
557 
558       if((type_return != None) && (type_return == XA_CARDINAL) &&
559 	 ((format_return == 32) && (nitems_return == 1) && (bytes_after_return == 0))) {
560 	unsigned char   *prop_return2 = NULL;
561 	Window           win_id;
562 
563 	win_id = *(unsigned long *)prop_return;
564 
565 	status = XGetWindowProperty(display, win_id, atom, 0,
566 				    1, False, XA_CARDINAL,
567 				    &type_return, &format_return, &nitems_return,
568 				    &bytes_after_return, &prop_return2);
569 
570 	if((status == Success) && (type_return != None) && (type_return == XA_CARDINAL)) {
571 
572 	  if((format_return == 32) && (nitems_return == 1)
573 	     && (bytes_after_return == 0) && (win_id == *(unsigned long *)prop_return2)) {
574 	    type |= WM_TYPE_GNOME_COMP;
575 	  }
576 	}
577 
578 	if(prop_return2)
579 	  XFree(prop_return2);
580 
581 	if((wm_name = get_wm_name(display, win_id, "_NET_WM_NAME")) == NULL) {
582 	  /*
583 	   * Enlightenment is Gnome compliant, but don't set
584 	   * the _NET_WM_NAME atom property
585 	   */
586 	  wm_name = get_wm_name(display, (XDefaultRootWindow(display)), "_WIN_WM_NAME");
587 	}
588       }
589 
590       if(prop_return)
591 	XFree(prop_return);
592     }
593   }
594 
595   /* Check for Extended Window Manager Hints (EWMH) Compliant */
596   if(((atom = XInternAtom(display, "_NET_SUPPORTING_WM_CHECK", True)) != None) &&
597      (XInternAtom(display, "_NET_WORKAREA", True) != None)) {
598     unsigned char   *prop_return = NULL;
599     unsigned long    nitems_return;
600     unsigned long    bytes_after_return;
601     Atom             type_return;
602     int              format_return;
603     Status           status;
604 
605     if((XGetWindowProperty(display, (XDefaultRootWindow(display)), atom, 0, 1, False, XA_WINDOW,
606 			   &type_return, &format_return, &nitems_return,
607 			   &bytes_after_return, &prop_return)) == Success) {
608 
609       if((type_return != None) && (type_return == XA_WINDOW) &&
610 	 (format_return == 32) && (nitems_return == 1) && (bytes_after_return == 0)) {
611 	unsigned char   *prop_return2 = NULL;
612 	Window           win_id;
613 
614 	win_id = *(unsigned long *)prop_return;
615 
616 	status = XGetWindowProperty(display, win_id, atom, 0,
617 				    1, False, XA_WINDOW,
618 				    &type_return, &format_return, &nitems_return,
619 				    &bytes_after_return, &prop_return2);
620 
621 	if((status == Success) && (type_return != None) && (type_return == XA_WINDOW) &&
622 	   (format_return == 32) && (nitems_return == 1) && (bytes_after_return == 0)) {
623 
624 	  if(win_id == *(unsigned long *)prop_return) {
625 	    free(wm_name);
626 	    wm_name = get_wm_name(display, win_id, "_NET_WM_NAME");
627 	    type |= WM_TYPE_EWMH_COMP;
628 	  }
629 	}
630 	if(prop_return2)
631 	  XFree(prop_return2);
632       }
633       if(prop_return)
634 	XFree(prop_return);
635     }
636   }
637 
638   xitk_uninstall_x_error_handler();
639 
640   if (type & WM_TYPE_EWMH_COMP) {
641     xitk->atoms.XA_WIN_LAYER               = XInternAtom(display, "_NET_WM_STATE", False);
642     xitk->atoms.XA_STAYS_ON_TOP            = XInternAtom(display, "_NET_WM_STATE_STAYS_ON_TOP", False);
643     xitk->atoms.XA_NET_WM_STATE            = XInternAtom(display, "_NET_WM_STATE", False);
644     xitk->atoms.XA_NET_WM_STATE_ABOVE      = XInternAtom(display, "_NET_WM_STATE_ABOVE", False);
645     xitk->atoms.XA_NET_WM_STATE_FULLSCREEN = XInternAtom(display, "_NET_WM_STATE_FULLSCREEN", False);
646 
647     xitk->atoms.XA_WM_WINDOW_TYPE               = XInternAtom(display, "_NET_WM_WINDOW_TYPE", False);
648     xitk->atoms.XA_WM_WINDOW_TYPE_DESKTOP       = XInternAtom(display, "_NET_WM_WINDOW_TYPE_DESKTOP", False);
649     xitk->atoms.XA_WM_WINDOW_TYPE_DOCK          = XInternAtom(display, "_NET_WM_WINDOW_TYPE_DOCK", False);
650     xitk->atoms.XA_WM_WINDOW_TYPE_TOOLBAR       = XInternAtom(display, "_NET_WM_WINDOW_TYPE_TOOLBAR", False);
651     xitk->atoms.XA_WM_WINDOW_TYPE_MENU          = XInternAtom(display, "_NET_WM_WINDOW_TYPE_MENU", False);
652     xitk->atoms.XA_WM_WINDOW_TYPE_UTILITY       = XInternAtom(display, "_NET_WM_WINDOW_TYPE_UTILITY", False);
653     xitk->atoms.XA_WM_WINDOW_TYPE_SPLASH        = XInternAtom(display, "_NET_WM_WINDOW_TYPE_SPLASH", False);
654     xitk->atoms.XA_WM_WINDOW_TYPE_DIALOG        = XInternAtom(display, "_NET_WM_WINDOW_TYPE_DIALOG", False);
655     xitk->atoms.XA_WM_WINDOW_TYPE_DROPDOWN_MENU = XInternAtom(display, "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU", False);
656     xitk->atoms.XA_WM_WINDOW_TYPE_POPUP_MENU    = XInternAtom(display, "_NET_WM_WINDOW_TYPE_POPUP_MENU", False);
657     xitk->atoms.XA_WM_WINDOW_TYPE_TOOLTIP       = XInternAtom(display, "_NET_WM_WINDOW_TYPE_TOOLTIP", False);
658     xitk->atoms.XA_WM_WINDOW_TYPE_NOTIFICATION  = XInternAtom(display, "_NET_WM_WINDOW_TYPE_NOTIFICATION", False);
659     xitk->atoms.XA_WM_WINDOW_TYPE_COMBO         = XInternAtom(display, "_NET_WM_WINDOW_TYPE_COMBO", False);
660     xitk->atoms.XA_WM_WINDOW_TYPE_DND           = XInternAtom(display, "_NET_WM_WINDOW_TYPE_DND", False);
661     xitk->atoms.XA_WM_WINDOW_TYPE_NORMAL        = XInternAtom(display, "_NET_WM_WINDOW_TYPE_NORMAL", False);
662   }
663 
664   switch(type & WM_TYPE_COMP_MASK) {
665   case WM_TYPE_KWIN:
666     if (xitk->atoms.XA_NET_WM_STATE == None)
667       xitk->atoms.XA_NET_WM_STATE    = XInternAtom(display, "_NET_WM_STATE", False);
668     if (xitk->atoms.XA_STAYS_ON_TOP == None)
669       xitk->atoms.XA_STAYS_ON_TOP = XInternAtom(display, "_NET_WM_STATE_STAYS_ON_TOP", False);
670     break;
671 
672   case WM_TYPE_MOTIF:
673   case WM_TYPE_LARSWM:
674     break;
675 
676   case WM_TYPE_UNKNOWN:
677   case WM_TYPE_E:
678   case WM_TYPE_ICE:
679   case WM_TYPE_WINDOWMAKER:
680   case WM_TYPE_XFCE:
681   case WM_TYPE_SAWFISH:
682   case WM_TYPE_METACITY: /* Untested */
683   case WM_TYPE_AFTERSTEP:
684   case WM_TYPE_BLACKBOX:
685   case WM_TYPE_DTWM:
686     xitk->atoms.XA_WIN_LAYER = XInternAtom(display, "_WIN_LAYER", False);
687     break;
688   }
689 
690   xitk->x.x_unlock_display (display);
691 
692   if(xitk->verbosity) {
693     printf("[ WM type: ");
694 
695     if(type & WM_TYPE_GNOME_COMP)
696       printf("(GnomeCompliant) ");
697     if(type & WM_TYPE_EWMH_COMP)
698       printf("(EWMH) ");
699 
700     switch(type & WM_TYPE_COMP_MASK) {
701     case WM_TYPE_UNKNOWN:
702       printf("Unknown");
703       break;
704     case WM_TYPE_KWIN:
705       printf("KWIN");
706       break;
707     case WM_TYPE_E:
708       printf("Enlightenment");
709       break;
710     case WM_TYPE_ICE:
711       printf("Ice");
712       break;
713     case WM_TYPE_WINDOWMAKER:
714       printf("WindowMaker");
715       break;
716     case WM_TYPE_MOTIF:
717       printf("Motif(like?)");
718       break;
719     case WM_TYPE_XFCE:
720       printf("XFce");
721       break;
722     case WM_TYPE_SAWFISH:
723       printf("Sawfish");
724       break;
725     case WM_TYPE_METACITY:
726       printf("Metacity");
727       break;
728     case WM_TYPE_AFTERSTEP:
729       printf("Afterstep");
730       break;
731     case WM_TYPE_BLACKBOX:
732       printf("Blackbox");
733       break;
734     case WM_TYPE_LARSWM:
735       printf("LarsWM");
736       break;
737     case WM_TYPE_DTWM:
738       printf("dtwm");
739       break;
740     }
741 
742     if(wm_name)
743       printf(" {%s}", wm_name);
744 
745     printf(" ]-\n");
746   }
747 
748   if(wm_name)
749     free(wm_name);
750 
751   return type;
752 }
xitk_get_wm_type(void)753 uint32_t xitk_get_wm_type(void) {
754   __xitk_t *xitk = (__xitk_t *)gXitk;
755 
756   return xitk->wm_type;
757 }
758 
xitk_get_layer_level(void)759 int xitk_get_layer_level(void) {
760   __xitk_t *xitk = (__xitk_t *)gXitk;
761   int level = 10;
762 
763   if ((xitk->wm_type & WM_TYPE_GNOME_COMP) || (xitk->wm_type & WM_TYPE_EWMH_COMP))
764     level = 10;
765 
766   switch (xitk->wm_type & WM_TYPE_COMP_MASK) {
767   case WM_TYPE_UNKNOWN:
768   case WM_TYPE_KWIN:
769   case WM_TYPE_SAWFISH:
770   case WM_TYPE_METACITY: /* Untested */
771   case WM_TYPE_ICE:
772   case WM_TYPE_AFTERSTEP:
773   case WM_TYPE_BLACKBOX:
774   case WM_TYPE_WINDOWMAKER:
775     level = 10; /* Wrong, but we need to provide a default value */
776     break;
777   case WM_TYPE_XFCE:
778     level = 8;
779     break;
780   case WM_TYPE_E:
781     level = 6;
782     break;
783   case WM_TYPE_MOTIF:
784   case WM_TYPE_LARSWM:
785     level = 0;
786     break;
787   }
788   return level;
789 }
790 
xitk_set_layer_above(Window window)791 void xitk_set_layer_above(Window window) {
792   __xitk_t *xitk = (__xitk_t *)gXitk;
793 
794   if ((xitk->wm_type & WM_TYPE_GNOME_COMP) && !(xitk->wm_type & WM_TYPE_EWMH_COMP)) {
795     long propvalue[1];
796 
797     propvalue[0] = xitk_get_layer_level();
798 
799     xitk->x.x_lock_display (xitk->x.display);
800     XChangeProperty (xitk->x.display, window, xitk->atoms.XA_WIN_LAYER,
801 		    XA_CARDINAL, 32, PropModeReplace, (unsigned char *)propvalue,
802 		    1);
803     xitk->x.x_unlock_display (xitk->x.display);
804     return;
805   }
806 
807 
808   if (xitk->wm_type & WM_TYPE_EWMH_COMP) {
809     XEvent xev;
810 
811     memset(&xev, 0, sizeof xev);
812     xitk->x.x_lock_display (xitk->x.display);
813     if(xitk->wm_type & WM_TYPE_KWIN) {
814       xev.xclient.type         = ClientMessage;
815       xev.xclient.display      = xitk->x.display;
816       xev.xclient.window       = window;
817       xev.xclient.message_type = xitk->atoms.XA_NET_WM_STATE;
818       xev.xclient.format       = 32;
819       xev.xclient.data.l[0]    = 1;
820       xev.xclient.data.l[1]    = xitk->atoms.XA_STAYS_ON_TOP;
821       xev.xclient.data.l[2]    = 0l;
822       xev.xclient.data.l[3]    = 0l;
823       xev.xclient.data.l[4]    = 0l;
824 
825       XSendEvent (xitk->x.display, DefaultRootWindow (xitk->x.display), True, SubstructureRedirectMask, &xev);
826     }
827     else {
828       xev.xclient.type         = ClientMessage;
829       xev.xclient.serial       = 0;
830       xev.xclient.send_event   = True;
831       xev.xclient.display      = xitk->x.display;
832       xev.xclient.window       = window;
833       xev.xclient.message_type = xitk->atoms.XA_NET_WM_STATE;
834       xev.xclient.format       = 32;
835       xev.xclient.data.l[0]    = (long) 1;
836       xev.xclient.data.l[1]    = (long) xitk->atoms.XA_NET_WM_STATE_ABOVE;
837       xev.xclient.data.l[2]    = (long) None;
838 
839       XSendEvent (xitk->x.display, DefaultRootWindow (xitk->x.display),
840 		 False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent*) &xev);
841 
842     }
843     xitk->x.x_unlock_display (xitk->x.display);
844 
845     return;
846   }
847 
848   switch (xitk->wm_type & WM_TYPE_COMP_MASK) {
849   case WM_TYPE_MOTIF:
850   case WM_TYPE_LARSWM:
851     break;
852 
853   case WM_TYPE_KWIN:
854     xitk->x.x_lock_display (xitk->x.display);
855     XChangeProperty (xitk->x.display, window, xitk->atoms.XA_WIN_LAYER,
856 		    XA_ATOM, 32, PropModeReplace, (unsigned char *)&xitk->atoms.XA_STAYS_ON_TOP, 1);
857     xitk->x.x_unlock_display (xitk->x.display);
858     break;
859 
860   case WM_TYPE_UNKNOWN:
861   case WM_TYPE_WINDOWMAKER:
862   case WM_TYPE_ICE:
863   case WM_TYPE_E:
864   case WM_TYPE_XFCE:
865   case WM_TYPE_SAWFISH:
866   case WM_TYPE_METACITY: /* Untested */
867   case WM_TYPE_AFTERSTEP:
868   case WM_TYPE_BLACKBOX:
869   case WM_TYPE_DTWM:
870     {
871       long propvalue[1];
872 
873       propvalue[0] = xitk_get_layer_level();
874 
875       xitk->x.x_lock_display (xitk->x.display);
876       XChangeProperty (xitk->x.display, window, xitk->atoms.XA_WIN_LAYER,
877 		      XA_CARDINAL, 32, PropModeReplace, (unsigned char *)propvalue,
878 		      1);
879       xitk->x.x_unlock_display (xitk->x.display);
880     }
881     break;
882   }
883 }
884 
xitk_set_window_layer(Window window,int layer)885 void xitk_set_window_layer(Window window, int layer) {
886   __xitk_t *xitk = (__xitk_t *)gXitk;
887   XEvent xev;
888 
889   if (((xitk->wm_type & WM_TYPE_COMP_MASK) == WM_TYPE_KWIN) ||
890       ((xitk->wm_type & WM_TYPE_EWMH_COMP) && !(xitk->wm_type & WM_TYPE_GNOME_COMP))) {
891     return;
892   }
893 
894   memset(&xev, 0, sizeof xev);
895   xev.type                 = ClientMessage;
896   xev.xclient.type         = ClientMessage;
897   xev.xclient.window       = window;
898   xev.xclient.message_type = xitk->atoms.XA_WIN_LAYER;
899   xev.xclient.format       = 32;
900   xev.xclient.data.l[0]    = (long) layer;
901   xev.xclient.data.l[1]    = (long) 0;
902   xev.xclient.data.l[2]    = (long) 0;
903   xev.xclient.data.l[3]    = (long) 0;
904 
905   xitk->x.x_lock_display (xitk->x.display);
906   XSendEvent (xitk->x.display, RootWindow (xitk->x.display, (XDefaultScreen (xitk->x.display))),
907 	     False, SubstructureNotifyMask, (XEvent*) &xev);
908   xitk->x.x_unlock_display (xitk->x.display);
909 }
910 
_set_ewmh_state(Window window,Atom atom,int enable)911 static void _set_ewmh_state(Window window, Atom atom, int enable) {
912   __xitk_t *xitk = (__xitk_t *)gXitk;
913   XEvent xev;
914 
915   if((window == None) || (atom == None))
916     return;
917 
918   memset(&xev, 0, sizeof(xev));
919   xev.xclient.type         = ClientMessage;
920   xev.xclient.message_type = xitk->atoms.XA_NET_WM_STATE;
921   xev.xclient.display      = xitk->x.display;
922   xev.xclient.window       = window;
923   xev.xclient.format       = 32;
924   xev.xclient.data.l[0]    = (enable == 1) ? 1 : 0;
925   xev.xclient.data.l[1]    = atom;
926   xev.xclient.data.l[2]    = 0l;
927   xev.xclient.data.l[3]    = 0l;
928   xev.xclient.data.l[4]    = 0l;
929 
930   xitk->x.x_lock_display (xitk->x.display);
931   XSendEvent (xitk->x.display, DefaultRootWindow (xitk->x.display), True, SubstructureRedirectMask, &xev);
932   xitk->x.x_unlock_display (xitk->x.display);
933 }
934 
xitk_set_ewmh_fullscreen(Window window)935 void xitk_set_ewmh_fullscreen(Window window) {
936   __xitk_t *xitk = (__xitk_t *)gXitk;
937 
938   if (!(xitk->wm_type & WM_TYPE_EWMH_COMP) || (window == None))
939     return;
940 
941   _set_ewmh_state (window, xitk->atoms.XA_NET_WM_STATE_FULLSCREEN, 1);
942   _set_ewmh_state (window, xitk->atoms.XA_STAYS_ON_TOP, 1);
943 }
944 
xitk_unset_ewmh_fullscreen(Window window)945 void xitk_unset_ewmh_fullscreen(Window window) {
946   __xitk_t *xitk = (__xitk_t *)gXitk;
947 
948   if (!(xitk->wm_type & WM_TYPE_EWMH_COMP) || (window == None))
949     return;
950 
951   _set_ewmh_state (window, xitk->atoms.XA_NET_WM_STATE_FULLSCREEN, 0);
952   _set_ewmh_state (window, xitk->atoms.XA_STAYS_ON_TOP, 0);
953 }
954 
_set_wm_window_type(Window window,xitk_wm_window_type_t type,int value)955 static void _set_wm_window_type(Window window, xitk_wm_window_type_t type, int value) {
956   __xitk_t *xitk = (__xitk_t *)gXitk;
957 
958   if (window && (xitk->wm_type & WM_TYPE_EWMH_COMP)) {
959     Atom *atom = NULL;
960 
961     switch(type) {
962     case WINDOW_TYPE_DESKTOP:
963       atom = &xitk->atoms.XA_WM_WINDOW_TYPE_DESKTOP;
964       break;
965     case WINDOW_TYPE_DOCK:
966       atom = &xitk->atoms.XA_WM_WINDOW_TYPE_DOCK;
967       break;
968     case WINDOW_TYPE_TOOLBAR:
969       atom = &xitk->atoms.XA_WM_WINDOW_TYPE_TOOLBAR;
970       break;
971     case WINDOW_TYPE_MENU:
972       atom = &xitk->atoms.XA_WM_WINDOW_TYPE_MENU;
973       break;
974     case WINDOW_TYPE_UTILITY:
975       atom = &xitk->atoms.XA_WM_WINDOW_TYPE_UTILITY;
976       break;
977     case WINDOW_TYPE_SPLASH:
978       atom = &xitk->atoms.XA_WM_WINDOW_TYPE_SPLASH;
979       break;
980     case WINDOW_TYPE_DIALOG:
981       atom = &xitk->atoms.XA_WM_WINDOW_TYPE_DIALOG;
982       break;
983     case WINDOW_TYPE_DROPDOWN_MENU:
984       atom = &xitk->atoms.XA_WM_WINDOW_TYPE_DROPDOWN_MENU;
985       break;
986     case WINDOW_TYPE_POPUP_MENU:
987       atom = &xitk->atoms.XA_WM_WINDOW_TYPE_POPUP_MENU;
988       break;
989     case WINDOW_TYPE_TOOLTIP:
990       atom = &xitk->atoms.XA_WM_WINDOW_TYPE_TOOLTIP;
991       break;
992     case WINDOW_TYPE_NOTIFICATION:
993       atom = &xitk->atoms.XA_WM_WINDOW_TYPE_NOTIFICATION;
994       break;
995     case WINDOW_TYPE_COMBO:
996       atom = &xitk->atoms.XA_WM_WINDOW_TYPE_COMBO;
997       break;
998     case WINDOW_TYPE_DND:
999       atom = &xitk->atoms.XA_WM_WINDOW_TYPE_DND;
1000       break;
1001     case WINDOW_TYPE_NORMAL:
1002       atom = &xitk->atoms.XA_WM_WINDOW_TYPE_NORMAL;
1003       break;
1004     }
1005 
1006     if(atom) {
1007       XLOCK (xitk->x.x_lock_display, xitk->x.display);
1008       XChangeProperty (xitk->x.display, window, xitk->atoms.XA_WM_WINDOW_TYPE, XA_ATOM, 32, PropModeReplace, (unsigned char *)atom, 1);
1009       XRaiseWindow (xitk->x.display, window);
1010       XUNLOCK (xitk->x.x_unlock_display, xitk->x.display);
1011     }
1012   }
1013 }
1014 
xitk_unset_wm_window_type(Window window,xitk_wm_window_type_t type)1015 void xitk_unset_wm_window_type(Window window, xitk_wm_window_type_t type) {
1016   _set_wm_window_type(window, type, 0);
1017 }
1018 
xitk_set_wm_window_type(Window window,xitk_wm_window_type_t type)1019 void xitk_set_wm_window_type(Window window, xitk_wm_window_type_t type) {
1020   _set_wm_window_type(window, type, 1);
1021 }
1022 
1023 /*
1024  * Create a new widget_list, store the pointer in private
1025  * list of xitk_widget_list_t, then return the widget_list pointer.
1026  */
xitk_widget_list_new(void)1027 xitk_widget_list_t *xitk_widget_list_new (void) {
1028   __xitk_t *xitk = (__xitk_t *)gXitk;
1029   xitk_widget_list_t *l;
1030 
1031   l = (xitk_widget_list_t *) xitk_xmalloc(sizeof(xitk_widget_list_t));
1032 
1033   l->widget_focused     = NULL;
1034   l->widget_under_mouse = NULL;
1035   l->widget_pressed     = NULL;
1036 
1037   xitk_dlist_init (&l->list);
1038 
1039   l->xitk = &xitk->x;
1040 
1041   MUTLOCK();
1042 
1043   xitk_dlist_add_tail (&xitk->wlists, &l->node);
1044 
1045   MUTUNLOCK();
1046 
1047 #ifdef XITK_DEBUG
1048   printf  ("xitk: new wl @ %p.\n", (void *)l);
1049 #endif
1050   return l;
1051 }
1052 
1053 /*
1054  * Change the window for the xevent_handler previously initialized
1055  * at widget_register_event_handler() time. It also remade it
1056  * DND aware, only if DND stuff was initialized at register time too.
1057  */
xitk_change_window_for_event_handler(xitk_register_key_t key,Window window)1058 void xitk_change_window_for_event_handler (xitk_register_key_t key, Window window) {
1059   __xitk_t *xitk = (__xitk_t *)gXitk;
1060   __gfx_t  *fx;
1061 
1062   MUTLOCK();
1063 
1064   fx = (__gfx_t *)xitk->gfxs.head.next;
1065 
1066   while (fx->node.next) {
1067 
1068     FXLOCK(fx);
1069     if(fx->key == key) {
1070 
1071       fx->window = window;
1072 
1073       if(fx->xdnd && (window != None)) {
1074 	if(!xitk_make_window_dnd_aware(fx->xdnd, window))
1075 	  xitk_unset_dnd_callback(fx->xdnd);
1076       }
1077 
1078       FXUNLOCK(fx);
1079       MUTUNLOCK();
1080       return;
1081     }
1082 
1083     FXUNLOCK(fx);
1084     fx = (__gfx_t *)fx->node.next;
1085   }
1086 
1087   MUTUNLOCK();
1088 }
1089 
1090 /*
1091  * Register a callback function called when a signal happen.
1092  */
xitk_register_signal_handler(xitk_signal_callback_t sigcb,void * user_data)1093 void xitk_register_signal_handler(xitk_signal_callback_t sigcb, void *user_data) {
1094   __xitk_t *xitk = (__xitk_t *)gXitk;
1095 
1096   if (sigcb) {
1097     xitk->sig_callback = sigcb;
1098     xitk->sig_data     = user_data;
1099   }
1100 }
1101 
1102 /*
1103  * Register a window, with his own event handler, callback
1104  * for DND events, and widget list.
1105  */
xitk_register_event_handler(const char * name,Window window,widget_event_callback_t cb,widget_newpos_callback_t pos_cb,xitk_dnd_callback_t dnd_cb,xitk_widget_list_t * wl,void * user_data)1106 xitk_register_key_t xitk_register_event_handler(const char *name, Window window,
1107 						widget_event_callback_t cb,
1108 						widget_newpos_callback_t pos_cb,
1109 						xitk_dnd_callback_t dnd_cb,
1110 						xitk_widget_list_t *wl, void *user_data) {
1111   __xitk_t *xitk = (__xitk_t *)gXitk;
1112   __gfx_t   *fx;
1113 
1114   //  printf("%s()\n", __FUNCTION__);
1115 
1116   fx = (__gfx_t *) xitk_xmalloc(sizeof(__gfx_t));
1117   if (!fx)
1118     return -1;
1119 
1120   fx->name = name ? strdup(name) : strdup("NO_SET");
1121 
1122   fx->window    = window;
1123   fx->new_pos.x = 0;
1124   fx->new_pos.y = 0;
1125   fx->width     = 0;
1126   fx->height    = 0;
1127   fx->user_data = user_data;
1128   pthread_mutex_init(&fx->mutex, NULL);
1129   fx->owning_thread = (pthread_t)0;
1130 
1131   if(window != None) {
1132     XWindowAttributes wattr;
1133     Status            err;
1134 
1135     XLOCK (xitk->x.x_lock_display, xitk->x.display);
1136     err = XGetWindowAttributes (xitk->x.display, fx->window, &wattr);
1137     XUNLOCK (xitk->x.x_unlock_display, xitk->x.display);
1138 
1139     if(err != BadDrawable && err != BadWindow) {
1140       Window c;
1141 
1142       XLOCK (xitk->x.x_lock_display, xitk->x.display);
1143       XTranslateCoordinates (xitk->x.display, fx->window, wattr.root,
1144 			    0, 0, &(fx->new_pos.x), &(fx->new_pos.y), &c);
1145       XUNLOCK (xitk->x.x_unlock_display, xitk->x.display);
1146 
1147       /*
1148 	fx->new_pos.x = wattr.x;
1149 	fx->new_pos.y = wattr.y;
1150       */
1151       fx->width     = wattr.width;
1152       fx->height    = wattr.height;
1153     }
1154   }
1155 
1156   if(cb)
1157     fx->xevent_callback = cb;
1158 #if 0
1159   else {
1160     XITK_DIE("%s()@%d: Callback should be non NULL\n", __FUNCTION__, __LINE__);
1161   }
1162 #endif
1163 
1164   if(pos_cb && (window != None))
1165     fx->newpos_callback = pos_cb;
1166   else
1167     fx->newpos_callback = NULL;
1168 
1169   if(wl)
1170     fx->widget_list = wl;
1171   else
1172     fx->widget_list = NULL;
1173 
1174   if(dnd_cb && (window != None)) {
1175     fx->xdnd = (xitk_dnd_t *) xitk_xmalloc(sizeof(xitk_dnd_t));
1176 
1177     xitk_init_dnd (&xitk->x, fx->xdnd);
1178     if(xitk_make_window_dnd_aware(fx->xdnd, fx->window))
1179       xitk_set_dnd_callback(fx->xdnd, dnd_cb);
1180   }
1181   else
1182     fx->xdnd = NULL;
1183 
1184   if(fx->window) {
1185 
1186     XLOCK (xitk->x.x_lock_display, xitk->x.display);
1187     fx->XA_XITK = XInternAtom (xitk->x.display, "_XITK_EVENT", False);
1188     XChangeProperty (xitk->x.display, fx->window, fx->XA_XITK, XA_ATOM,
1189 		     32, PropModeAppend, (unsigned char *)&XITK_VERSION, 1);
1190     XUNLOCK (xitk->x.x_unlock_display, xitk->x.display);
1191 
1192   }
1193   else
1194     fx->XA_XITK = None;
1195 
1196   MUTLOCK();
1197   fx->key = ++xitk->key;
1198   xitk_dlist_add_tail (&xitk->gfxs, &fx->node);
1199   MUTUNLOCK();
1200 
1201 #ifdef XITK_DEBUG
1202   printf  ("xitk: new fx #%d \"%s\" @ %p.\n", fx->key, fx->name, (void *)fx);
1203 #endif
1204   return fx->key;
1205 }
1206 
__fx_from_key(__xitk_t * xitk,xitk_register_key_t key)1207 static __gfx_t *__fx_from_key (__xitk_t *xitk, xitk_register_key_t key) {
1208   /* fx->key is set uniquely in xitk_register_event_handler, then never changed.
1209    * MUTLOCK () is enough. */
1210   __gfx_t *fx;
1211   for (fx = (__gfx_t *)xitk->gfxs.head.next; fx->node.next; fx = (__gfx_t *)fx->node.next) {
1212     if (fx->key == key)
1213       return fx;
1214   }
1215   return NULL;
1216 }
1217 
__fx_destroy(__gfx_t * fx,int locked)1218 static void __fx_destroy(__gfx_t *fx, int locked) {
1219   __xitk_t *xitk = (__xitk_t *)gXitk;
1220   if(!fx)
1221     return;
1222 
1223   if(!locked)
1224     MUTLOCK();
1225 
1226   if(fx->xdnd) {
1227     xitk_unset_dnd_callback(fx->xdnd);
1228     free(fx->xdnd);
1229   }
1230 
1231   if (fx->widget_list && fx->widget_list->destroy) {
1232     xitk_dnode_remove (&fx->widget_list->node);
1233     xitk_dlist_clear (&fx->widget_list->list);
1234     free(fx->widget_list);
1235 #ifdef XITK_DEBUG
1236     printf  ("xitk: deferredly killed wl @ %p.\n", (void *)fx->widget_list);
1237 #endif
1238   }
1239 
1240   fx->xevent_callback = NULL;
1241   fx->newpos_callback = NULL;
1242   fx->user_data       = NULL;
1243 
1244   free(fx->name);
1245 
1246   xitk_dnode_remove (&fx->node);
1247 
1248   FXUNLOCK(fx);
1249   pthread_mutex_destroy(&fx->mutex);
1250 
1251   free(fx);
1252 
1253   if(!locked)
1254     MUTUNLOCK();
1255 
1256 #ifdef XITK_DEBUG
1257   printf  ("xitk: killed fx @ %p.\n", (void *)fx);
1258 #endif
1259 }
1260 
1261 /*
1262  * Remove from the list the window/event_handler
1263  * specified by the key.
1264  */
xitk_unregister_event_handler(xitk_register_key_t * key)1265 void xitk_unregister_event_handler(xitk_register_key_t *key) {
1266   __xitk_t *xitk = (__xitk_t *)gXitk;
1267   __gfx_t  *fx;
1268 
1269   //  printf("%s()\n", __FUNCTION__);
1270 
1271   MUTLOCK ();
1272   fx = __fx_from_key (xitk, *key);
1273   if (fx) {
1274     *key = 0;
1275     if (__gfx_safe_lock (fx)) {
1276       /* We already hold this, we are inside a callback. */
1277       /* NOTE: After return from this, application may free () fx->user_data. */
1278       fx->xevent_callback = NULL;
1279       fx->newpos_callback = NULL;
1280       fx->user_data       = NULL;
1281       fx->destroy = 1;
1282     } else {
1283       __fx_destroy (fx, 1);
1284     }
1285   }
1286   MUTUNLOCK ();
1287 }
1288 
xitk_widget_list_defferred_destroy(xitk_widget_list_t * wl)1289 void xitk_widget_list_defferred_destroy(xitk_widget_list_t *wl) {
1290   __xitk_t *xitk = (__xitk_t *)gXitk;
1291   __gfx_t  *fx;
1292 
1293   MUTLOCK();
1294   fx = (__gfx_t *)xitk->gfxs.head.next;
1295   while (fx->node.next) {
1296     if (fx->widget_list && fx->widget_list == wl) {
1297       if (fx->destroy) {
1298       /* there was pending destroy, widget list needed */
1299         fx->widget_list->destroy = 1;
1300         MUTUNLOCK();
1301         return;
1302       } else {
1303 	fx->widget_list = NULL;
1304 	break;
1305       }
1306     }
1307 
1308     fx = (__gfx_t *)fx->node.next;
1309   }
1310 
1311   xitk_dnode_remove (&wl->node);
1312   xitk_dlist_clear (&wl->list);
1313   MUTUNLOCK();
1314 
1315   free(wl);
1316 #ifdef XITK_DEBUG
1317   printf  ("xitk: killed wl @ %p.\n", (void *)wl);
1318 #endif
1319 }
1320 
1321 /*
1322  * Copy window information matching with key in passed window_info_t struct.
1323  */
xitk_get_window_info(xitk_register_key_t key,window_info_t * winf)1324 int xitk_get_window_info(xitk_register_key_t key, window_info_t *winf) {
1325   __xitk_t *xitk = (__xitk_t *)gXitk;
1326   __gfx_t  *fx;
1327 
1328   MUTLOCK();
1329 
1330   fx = __fx_from_key (xitk, key);
1331   if (fx) {
1332     int already_locked = __gfx_safe_lock (fx);
1333 
1334     if (fx->window != None) {
1335       Window c;
1336 
1337       winf->window = fx->window;
1338 
1339       if(fx->name)
1340 	winf->name = strdup(fx->name);
1341 
1342       XLOCK (xitk->x.x_lock_display, xitk->x.display);
1343       XTranslateCoordinates (xitk->x.display, fx->window, DefaultRootWindow (xitk->x.display),
1344 			    0, 0, &(fx->new_pos.x), &(fx->new_pos.y), &c);
1345       XUNLOCK (xitk->x.x_unlock_display, xitk->x.display);
1346 
1347 
1348       winf->x      = fx->new_pos.x;
1349       winf->y      = fx->new_pos.y;
1350       winf->height = fx->height;
1351       winf->width  = fx->width;
1352 
1353       if (!already_locked)
1354         __gfx_unlock (fx);
1355 
1356       MUTUNLOCK();
1357       return 1;
1358 
1359     }
1360     if (!already_locked)
1361       __gfx_unlock (fx);
1362   }
1363 
1364   MUTUNLOCK();
1365   return 0;
1366 }
1367 
1368 static void xitk_xevent_notify_impl(XEvent *event);
1369 
xitk_xevent_notify(XEvent * event)1370 void xitk_xevent_notify(XEvent *event) {
1371   __xitk_t *xitk = (__xitk_t *)gXitk;
1372   /* protect walking through gfx list */
1373   MUTLOCK();
1374   xitk_xevent_notify_impl(event);
1375   MUTUNLOCK();
1376 }
1377 
1378 /*
1379  * Here events are handled. All widget are locally
1380  * handled, then if a event handler callback was passed
1381  * at register time, it will be called.
1382  */
xitk_xevent_notify_impl(XEvent * event)1383 void xitk_xevent_notify_impl(XEvent *event) {
1384   __xitk_t *xitk = (__xitk_t *)gXitk;
1385   __gfx_t  *fx, *fxd;
1386 
1387   fx = (__gfx_t *)xitk->gfxs.head.next;
1388   if (!fx->node.next)
1389     return;
1390 
1391   if(event->type == KeyPress || event->type == KeyRelease) {
1392 
1393     /* Filter keys that dont't need to be handled by xine  */
1394     /* and could be used by our screen saver reset "ping". */
1395     /* So they will not kill tips and menus.               */
1396 
1397     size_t i;
1398 
1399     for (i = 0; i < sizeof (xitk->ignore_keys) / sizeof (xitk->ignore_keys[0]); ++i)
1400       if(event->xkey.keycode == xitk->ignore_keys[i])
1401 	return;
1402   }
1403 
1404   FXLOCK(fx);
1405 
1406   if (xitk->modalw != None) {
1407     while (fx->node.next && (fx->window != xitk->modalw)) {
1408 
1409       if(fx->xevent_callback && (fx->window != None && event->type != KeyRelease))
1410 	fx->xevent_callback(event, fx->user_data);
1411 
1412       fx = (__gfx_t *)fx->node.next;
1413     }
1414   }
1415 
1416   while (fx->node.next) {
1417 
1418     if(event->type == KeyRelease)
1419       gettimeofday (&xitk->keypress, 0);
1420 
1421     if(fx->window != None) {
1422 
1423       //printf("event %d\n", event->type);
1424 
1425       if(fx->window == event->xany.window) {
1426 
1427 	switch(event->type) {
1428 
1429 	case MappingNotify:
1430           XLOCK (xitk->x.x_lock_display, xitk->x.display);
1431 	  XRefreshKeyboardMapping((XMappingEvent *) event);
1432           XUNLOCK (xitk->x.x_unlock_display, xitk->x.display);
1433 	  break;
1434 
1435 	case KeyPress: {
1436 	  XKeyEvent      mykeyevent;
1437 	  KeySym         mykey;
1438 	  char           kbuf[256];
1439 	  int            modifier;
1440 	  int            handled = 0;
1441 	  xitk_widget_t *w = NULL;
1442 
1443 	  mykeyevent = event->xkey;
1444 
1445 	  xitk_get_key_modifier(event, &modifier);
1446 
1447           XLOCK (xitk->x.x_lock_display, xitk->x.display);
1448 	  XLookupString(&mykeyevent, kbuf, sizeof(kbuf), &mykey, NULL);
1449           XUNLOCK (xitk->x.x_unlock_display, xitk->x.display);
1450 
1451 	  xitk_tips_hide_tips();
1452 
1453 	  if(fx->widget_list && fx->widget_list->widget_focused) {
1454 	    w = fx->widget_list->widget_focused;
1455 	  }
1456 
1457 	  if(w && (((w->type & WIDGET_TYPE_MASK) == WIDGET_TYPE_INPUTTEXT) &&
1458 		   (mykey != XK_Tab) && (mykey != XK_KP_Tab) && (mykey != XK_ISO_Left_Tab))) {
1459 
1460 	    xitk_send_key_event(w, event);
1461 
1462 	    if((mykey == XK_Return) || (mykey == XK_KP_Enter) || (mykey == XK_ISO_Enter)) {
1463 	      widget_event_t  event;
1464 
1465 	      event.type = WIDGET_EVENT_PAINT;
1466 	      (void) w->event(w, &event, NULL);
1467 
1468 	      xitk_set_focus_to_next_widget(fx->widget_list, 0);
1469 	    }
1470 
1471 	    FXUNLOCK(fx);
1472 	    return;
1473 	  }
1474 
1475 	  /* close menu */
1476 	  if(mykey == XK_Escape) {
1477 	    if(w && ((w->type & WIDGET_GROUP_MASK) & WIDGET_GROUP_MENU)) {
1478 	      xitk_widget_t *m = xitk_menu_get_menu(w);
1479 
1480 	      xitk_menu_destroy(m);
1481 	      FXUNLOCK(fx);
1482 	      return;
1483 	    }
1484 	  }
1485 	  /* set focus to next widget */
1486 	  else if((mykey == XK_Tab) || (mykey == XK_KP_Tab) || (mykey == XK_ISO_Left_Tab)) {
1487 	    if(fx->widget_list) {
1488 	      handled = 1;
1489 	      xitk_set_focus_to_next_widget(fx->widget_list, (modifier & MODIFIER_SHIFT));
1490 	    }
1491 	  }
1492 	  /* simulate click event on space/return/enter key event */
1493 	  else if((mykey == XK_space) || (mykey == XK_Return) ||
1494 		  (mykey == XK_KP_Enter) || (mykey == XK_ISO_Enter)) {
1495 	    if(w && (((w->type & WIDGET_CLICKABLE) && (w->type & WIDGET_KEYABLE))
1496 		     && w->visible && w->enable)) {
1497 
1498 	    __menu_sim_click:
1499 
1500 	      if(w && (((w->type & WIDGET_TYPE_MASK) == WIDGET_TYPE_BUTTON) ||
1501 		       ((w->type & WIDGET_TYPE_MASK) == WIDGET_TYPE_LABELBUTTON) ||
1502 		       ((w->type & WIDGET_TYPE_MASK) == WIDGET_TYPE_CHECKBOX))) {
1503 		widget_event_t         event;
1504 		widget_event_result_t  result;
1505 
1506 		handled = 1;
1507 
1508 		event.type           = WIDGET_EVENT_CLICK;
1509 		event.x              = w->x;
1510 		event.y              = w->y;
1511 		event.button_pressed = LBUTTON_DOWN;
1512 		event.button         = Button1;
1513 
1514 		(void) w->event(w, &event, &result);
1515 
1516 		event.button_pressed = LBUTTON_UP;
1517 
1518 		(void) w->event(w, &event, &result);
1519 
1520 		//		if(fx->xevent_callback)
1521 		//		  fx->xevent_callback(event, fx->user_data);
1522 	      }
1523 	    }
1524 	  }
1525 	  /* move sliders, handle menu items */
1526 	  else if(((mykey == XK_Left) || (mykey == XK_Right)
1527 		   || (mykey == XK_Up) || (mykey == XK_Down)
1528 		   || (mykey == XK_Prior) || (mykey == XK_Next))
1529 		  && ((modifier & 0xFFFFFFEF) == MODIFIER_NOMOD)) {
1530 
1531 	    if(w && ((w->type & WIDGET_GROUP_MASK) & WIDGET_GROUP_BROWSER)) {
1532 	      xitk_widget_t *b = xitk_browser_get_browser(w);
1533 
1534 	      if(b) {
1535 		handled = 1;
1536 		if(mykey == XK_Up)
1537 		  xitk_browser_step_down(b, NULL);
1538 		else if(mykey == XK_Down)
1539 		  xitk_browser_step_up(b, NULL);
1540 		else if(mykey == XK_Left)
1541 		  xitk_browser_step_left(b, NULL);
1542 		else if(mykey == XK_Right)
1543 		  xitk_browser_step_right(b, NULL);
1544 		else if(mykey == XK_Prior)
1545 		  xitk_browser_page_down(b, NULL);
1546 		else if(mykey == XK_Next)
1547 		  xitk_browser_page_up(b, NULL);
1548 	      }
1549 	    }
1550 	    else if(w && (((w->type & WIDGET_TYPE_MASK) == WIDGET_TYPE_SLIDER)
1551 			  && (w->type & WIDGET_KEYABLE))) {
1552 	      handled = 1;
1553 	      if((mykey == XK_Left) || (mykey == XK_Down) || (mykey == XK_Next)) {
1554 		xitk_slider_make_backstep(w);
1555 	      }
1556 	      else {
1557 		xitk_slider_make_step(w);
1558 	      }
1559 	      xitk_slider_callback_exec(w);
1560 	    }
1561 	    else if(w && ((w->type & WIDGET_GROUP_MASK) & WIDGET_GROUP_MENU)) {
1562 	      handled = 1;
1563 	      if(mykey == XK_Left) {
1564 		/* close menu branch */
1565 		xitk_menu_destroy_branch(w);
1566 	      }
1567 	      else if(mykey == XK_Right) {
1568 		/* simulate click event: trigger action of menu item (e.g. open submenu) */
1569 		goto __menu_sim_click; // (goto is bad but simple ...)
1570 	      }
1571 	      else {
1572 		/* next/previous menu item */
1573 		if(fx->widget_list)
1574 		  xitk_set_focus_to_next_widget(fx->widget_list,
1575 						((mykey == XK_Up) || (mykey == XK_Prior)));
1576 	      }
1577 	    }
1578 	  }
1579 	  else if((mykey == XK_0) || (mykey == XK_1) || (mykey == XK_2) || (mykey == XK_3) ||
1580 		  (mykey == XK_4) || (mykey == XK_5) || (mykey == XK_6) || (mykey == XK_7) ||
1581 		  (mykey == XK_8) || (mykey == XK_9) ||
1582 		  (mykey == XK_underscore) ||
1583 		  (mykey == XK_a) || (mykey == XK_A) || (mykey == XK_b) || (mykey == XK_B) ||
1584 		  (mykey == XK_c) || (mykey == XK_C) || (mykey == XK_d) || (mykey == XK_D) ||
1585 		  (mykey == XK_e) || (mykey == XK_E) || (mykey == XK_f) || (mykey == XK_F) ||
1586 		  (mykey == XK_g) || (mykey == XK_G) || (mykey == XK_h) || (mykey == XK_H) ||
1587 		  (mykey == XK_i) || (mykey == XK_I) || (mykey == XK_j) || (mykey == XK_J) ||
1588 		  (mykey == XK_k) || (mykey == XK_K) || (mykey == XK_l) || (mykey == XK_L) ||
1589 		  (mykey == XK_m) || (mykey == XK_M) || (mykey == XK_n) || (mykey == XK_N) ||
1590 		  (mykey == XK_o) || (mykey == XK_O) || (mykey == XK_p) || (mykey == XK_P) ||
1591 		  (mykey == XK_q) || (mykey == XK_Q) || (mykey == XK_r) || (mykey == XK_R) ||
1592 		  (mykey == XK_s) || (mykey == XK_S) || (mykey == XK_t) || (mykey == XK_T) ||
1593 		  (mykey == XK_u) || (mykey == XK_U) || (mykey == XK_v) || (mykey == XK_V) ||
1594 		  (mykey == XK_w) || (mykey == XK_W) || (mykey == XK_x) || (mykey == XK_X) ||
1595 		  (mykey == XK_y) || (mykey == XK_Y) || (mykey == XK_z) || (mykey == XK_Z)) {
1596 
1597 
1598 	    if(w && ((w->type & WIDGET_GROUP_MASK) & WIDGET_GROUP_BROWSER)) {
1599 	      xitk_widget_t *b = xitk_browser_get_browser(w);
1600 
1601 	      if(b) {
1602 		handled = 1;
1603 		xitk_browser_warp_jump(b, kbuf, modifier);
1604 	      }
1605 
1606 	    }
1607 	  }
1608 
1609 	  if(!handled) {
1610 
1611             if (xitk->menu &&
1612 	       ((fx->widget_list &&
1613 		 ((!fx->widget_list->widget_focused) ||
1614 		  (!(fx->widget_list->widget_focused->type & WIDGET_GROUP_MENU)))) ||
1615 		(!fx->widget_list)))  {
1616 
1617 	      xitk_set_current_menu(NULL);
1618 	    }
1619 
1620 	    if((w == NULL) || (w && (((w->type & WIDGET_TYPE_MASK) == WIDGET_TYPE_INPUTTEXT) == 0))) {
1621 	      if(fx->xevent_callback) {
1622 		fx->xevent_callback(event, fx->user_data);
1623 	      }
1624 	    }
1625 
1626 	    if(w && ((w->type & WIDGET_TYPE_MASK) == WIDGET_TYPE_INPUTTEXT) &&
1627 	       ((mykey == XK_Return) || (mykey == XK_KP_Enter) || (mykey == XK_ISO_Enter))) {
1628 	      widget_event_t  event;
1629 
1630 	      event.type = WIDGET_EVENT_PAINT;
1631 	      (void) w->event(w, &event, NULL);
1632 
1633 	      xitk_set_focus_to_next_widget(fx->widget_list, 0);
1634 
1635 	    }
1636 	  }
1637 
1638 	  if(fx->destroy)
1639 	    __fx_destroy(fx, 0);
1640 	  else
1641 	    FXUNLOCK(fx);
1642 
1643 	  return;
1644 	}
1645 	break;
1646 
1647 	case Expose:
1648 	  if (fx->widget_list) {
1649 
1650             XLOCK (xitk->x.x_lock_display, xitk->x.display);
1651             while (XCheckTypedWindowEvent (xitk->x.display, fx->window,
1652 					 Expose, event) == True);
1653             XUNLOCK (xitk->x.x_unlock_display, xitk->x.display);
1654 
1655 	    if(event->xexpose.count == 0)
1656 	      xitk_paint_widget_list(fx->widget_list);
1657 	  }
1658 	  break;
1659 
1660 	case MotionNotify: {
1661 	  XWindowAttributes wattr;
1662 
1663           XLOCK (xitk->x.x_lock_display, xitk->x.display);
1664           while (XCheckMaskEvent (xitk->x.display, ButtonMotionMask, event) == True);
1665           XUNLOCK (xitk->x.x_unlock_display, xitk->x.display);
1666 
1667 	  fx->old_event = event;
1668 	  if(fx->move.enabled) {
1669 
1670 	    if(fx->widget_list->widget_focused &&
1671 	       (fx->widget_list->widget_focused->type & WIDGET_GROUP_MENU)) {
1672 	      xitk_widget_t *menu = xitk_menu_get_menu(fx->widget_list->widget_focused);
1673 
1674 	      if(xitk_menu_show_sub_branchs(menu))
1675 		xitk_menu_destroy_sub_branchs(menu);
1676 
1677 	    }
1678 
1679 	    fx->old_pos.x = fx->new_pos.x;
1680 	    fx->old_pos.y = fx->new_pos.y;
1681 
1682 	    fx->new_pos.x = (event->xmotion.x_root)
1683 	      + (event->xmotion.x_root - fx->old_event->xmotion.x_root)
1684 	      - fx->move.offset_x;
1685 	    fx->new_pos.y = (event->xmotion.y_root)
1686 	      + (event->xmotion.y_root - fx->old_event->xmotion.y_root)
1687 	      - fx->move.offset_y;
1688 
1689             XLOCK (xitk->x.x_lock_display, xitk->x.display);
1690 
1691             XMoveWindow (xitk->x.display, fx->window,
1692 			fx->new_pos.x, fx->new_pos.y);
1693             XGetWindowAttributes (xitk->x.display, fx->window, &wattr);
1694 
1695             XUNLOCK (xitk->x.x_unlock_display, xitk->x.display);
1696 
1697 	  }
1698 	  else {
1699 	    if(fx->widget_list) {
1700 	      xitk_motion_notify_widget_list (fx->widget_list,
1701 					      event->xmotion.x,
1702 					      event->xmotion.y, event->xmotion.state);
1703 	    }
1704 	  }
1705 	}
1706 	  break;
1707 
1708 	case LeaveNotify:
1709 	  if(!(fx->widget_list && fx->widget_list->widget_pressed &&
1710 	       (fx->widget_list->widget_pressed->type & WIDGET_TYPE_MASK) == WIDGET_TYPE_SLIDER))
1711 	    event->xcrossing.x = event->xcrossing.y = -1; /* Simulate moving out of any widget */
1712 	    /* but leave the actual coords for an active slider, otherwise the slider may jump */
1713 	  /* fall through */
1714 	case EnterNotify:
1715 	  if(fx->widget_list)
1716 	    if(event->xcrossing.mode == NotifyNormal) /* Ptr. moved rel. to win., not (un)grab */
1717 	      xitk_motion_notify_widget_list (fx->widget_list,
1718 					      event->xcrossing.x,
1719 					      event->xcrossing.y, event->xcrossing.state);
1720 	  break;
1721 
1722 	case ButtonPress: {
1723 	  XWindowAttributes   wattr;
1724 	  Status              status;
1725 
1726 	  xitk_tips_hide_tips();
1727 
1728           XLOCK (xitk->x.x_lock_display, xitk->x.display);
1729           status = XGetWindowAttributes (xitk->x.display, fx->window, &wattr);
1730 	  /*
1731 	   * Give focus (and raise) to window after click
1732 	   * if it's viewable (e.g. not iconified).
1733 	   */
1734 	  if((status != BadDrawable) && (status != BadWindow)
1735 	     && (wattr.map_state == IsViewable)) {
1736             XRaiseWindow (xitk->x.display, fx->window);
1737             XSetInputFocus (xitk->x.display, fx->window, RevertToParent, CurrentTime);
1738 	  }
1739           XUNLOCK (xitk->x.x_unlock_display, xitk->x.display);
1740 
1741           if (xitk->menu &&
1742 	     ((fx->widget_list &&
1743 	       ((!fx->widget_list->widget_focused) ||
1744 		(!(fx->widget_list->widget_focused->type & WIDGET_GROUP_MENU)))) ||
1745 	      (!fx->widget_list)))  {
1746 
1747 	    xitk_set_current_menu(NULL);
1748 
1749 	    FXUNLOCK(fx);
1750 	    return;
1751 	  }
1752 
1753 	  if(fx->widget_list) {
1754 
1755 	    fx->move.enabled = !xitk_click_notify_widget_list (fx->widget_list,
1756 							       event->xbutton.x,
1757 							       event->xbutton.y,
1758 							       event->xbutton.button, 0);
1759 	    if(event->xbutton.button != Button1) {
1760 	      xitk_widget_t *w = fx->widget_list->widget_focused;
1761 
1762 	      fx->move.enabled = 0;
1763 
1764 	      if(w && ((w->type & WIDGET_GROUP_MASK) & WIDGET_GROUP_BROWSER)) {
1765 		xitk_widget_t *b = xitk_browser_get_browser(w);
1766 
1767 		if(b) {
1768 
1769 		  if(event->xbutton.button == Button4) {
1770 		    xitk_browser_step_down(b, NULL);
1771 		  }
1772 		  else if(event->xbutton.button == Button5) {
1773 		    xitk_browser_step_up(b, NULL);
1774 		  }
1775 
1776 		}
1777 	      }
1778 	    }
1779 
1780 	    if(fx->move.enabled) {
1781 	      XWindowAttributes wattr;
1782 	      Status            err;
1783 
1784               XLOCK (xitk->x.x_lock_display, xitk->x.display);
1785               err = XGetWindowAttributes (xitk->x.display, fx->window, &wattr);
1786               XUNLOCK (xitk->x.x_unlock_display, xitk->x.display);
1787 
1788 	      if(err != BadDrawable && err != BadWindow) {
1789 
1790 		fx->old_pos.x = event->xmotion.x_root - event->xbutton.x;
1791 		fx->old_pos.y = event->xmotion.y_root - event->xbutton.y;
1792 
1793 	      }
1794 
1795 	      fx->move.offset_x = event->xbutton.x;
1796 	      fx->move.offset_y = event->xbutton.y;
1797 
1798 	    }
1799 	  }
1800 	}
1801 	break;
1802 
1803 	case ButtonRelease:
1804 
1805 	  xitk_tips_hide_tips();
1806 
1807 	  if(fx->move.enabled) {
1808 
1809 	    fx->move.enabled = 0;
1810 	    /* Inform application about window movement. */
1811 
1812 	    if(fx->newpos_callback)
1813               fx->newpos_callback (fx->user_data,
1814                 fx->new_pos.x, fx->new_pos.y, fx->width, fx->height);
1815 	  }
1816 	  else {
1817 	    if(fx->widget_list) {
1818 	      xitk_click_notify_widget_list (fx->widget_list,
1819 					     event->xbutton.x, event->xbutton.y,
1820 					     event->xbutton.button, 1);
1821 	    }
1822 	  }
1823 	  break;
1824 
1825 	case ConfigureNotify: {
1826 	  XWindowAttributes wattr;
1827 	  Status            err;
1828 
1829           if (fx->widget_list) {
1830             xitk_widget_t *w = (xitk_widget_t *)fx->widget_list->list.head.next;
1831             while (w->node.next) {
1832 	      if(((w->type & WIDGET_GROUP_MASK) & WIDGET_GROUP_COMBO) &&
1833 		 (w->type & WIDGET_GROUP_WIDGET)) {
1834 		xitk_combo_update_pos(w);
1835 	      }
1836 	      w = (xitk_widget_t *)w->node.next;
1837 	    }
1838 	  }
1839 
1840 	  /* Inform application about window movement. */
1841 	  if(fx->newpos_callback) {
1842 
1843             XLOCK (xitk->x.x_lock_display, xitk->x.display);
1844             err = XGetWindowAttributes (xitk->x.display, fx->window, &wattr);
1845             XUNLOCK (xitk->x.x_unlock_display, xitk->x.display);
1846 
1847 	    if(err != BadDrawable && err != BadWindow) {
1848 	      fx->width = wattr.width;
1849 	      fx->height = wattr.height;
1850 	    }
1851             fx->newpos_callback (fx->user_data,
1852               event->xconfigure.x, event->xconfigure.y, fx->width, fx->height);
1853 	  }
1854 	}
1855 	break;
1856 
1857 	case SelectionNotify:
1858 	case ClientMessage:
1859 	  if(fx->xdnd)
1860 	    xitk_process_client_dnd_message(fx->xdnd, event);
1861 	  break;
1862 	}
1863 
1864 	if(fx->xevent_callback) {
1865 	  fx->xevent_callback(event, fx->user_data);
1866 	}
1867       }
1868     }
1869 
1870     fxd = fx;
1871     fx = (__gfx_t *)fx->node.next;
1872 
1873     if(fxd->destroy)
1874       __fx_destroy(fxd, 0);
1875     else
1876       FXUNLOCK(fxd);
1877 
1878 #warning FIXME
1879     if (xitk->modalw != None) {
1880 
1881       /* Flush remain fxs */
1882       while (fx->node.next && (fx->window != xitk->modalw)) {
1883 	FXLOCK(fx);
1884 
1885 	if(fx->xevent_callback && (fx->window != None && event->type != KeyRelease))
1886 	  fx->xevent_callback(event, fx->user_data);
1887 
1888 	fxd = fx;
1889 	fx = (__gfx_t *)fx->node.next;
1890 
1891 	if(fxd->destroy)
1892 	  __fx_destroy(fxd, 0);
1893 	else
1894 	  FXUNLOCK(fxd);
1895       }
1896       return;
1897     }
1898 
1899     if (fx->node.next)
1900       FXLOCK(fx);
1901   }
1902 }
1903 
1904 /*
1905  * Initiatization of widget internals.
1906  */
1907 
1908 void (*xitk_x_lock_display) (Display *display);
1909 void (*xitk_x_unlock_display) (Display *display);
1910 
xitk_init(Display * display,XColor black,void (* x_lock_display)(Display * display),void (* x_unlock_display)(Display * display),int verbosity)1911 void xitk_init (Display *display, XColor black, void (*x_lock_display) (Display *display),
1912   void (*x_unlock_display) (Display *display), int verbosity) {
1913   __xitk_t *xitk;
1914   char buffer[256];
1915   pthread_mutexattr_t attr;
1916 
1917   /* Nasty (temporary) kludge. */
1918   xitk_x_lock_display = x_lock_display;
1919   xitk_x_unlock_display = x_unlock_display;
1920 
1921 #ifdef ENABLE_NLS
1922   bindtextdomain("xitk", XITK_LOCALE);
1923 #endif
1924 
1925   xitk = xitk_xmalloc (sizeof (*xitk));
1926   gXitk = &xitk->x;
1927 
1928   xitk->xitk_pid = getppid ();
1929 
1930   xitk->x.x_lock_display   = x_lock_display;
1931   xitk->x.x_unlock_display = x_unlock_display;
1932 
1933   xitk->black           = black;
1934   xitk->display_width   = DisplayWidth(display, DefaultScreen(display));
1935   xitk->display_height  = DisplayHeight(display, DefaultScreen(display));
1936   xitk->verbosity       = verbosity;
1937   xitk_dlist_init (&xitk->wlists);
1938   xitk_dlist_init (&xitk->gfxs);
1939   xitk->x.display       = display;
1940   xitk->key             = 0;
1941   xitk->sig_callback    = NULL;
1942   xitk->sig_data        = NULL;
1943   xitk->config          = xitk_config_init();
1944   xitk->use_xshm        = (xitk_config_get_shm_feature(xitk->config)) ? (xitk_check_xshm(display)) : 0;
1945   xitk_x_error           = 0;
1946   xitk->x_error_handler = NULL;
1947   xitk->modalw          = None;
1948   xitk->ignore_keys[0]  = XKeysymToKeycode(display, XK_Shift_L);
1949   xitk->ignore_keys[1]  = XKeysymToKeycode(display, XK_Control_L);
1950   xitk->tips_timeout    = TIPS_TIMEOUT;
1951   XGetInputFocus(display, &(xitk->parent.window), &(xitk->parent.focus));
1952 
1953   xitk->atoms.XA_WIN_LAYER = None;
1954   xitk->atoms.XA_STAYS_ON_TOP = None;
1955 
1956   xitk->atoms.XA_NET_WM_STATE = None;
1957   xitk->atoms.XA_NET_WM_STATE_ABOVE = None;
1958   xitk->atoms.XA_NET_WM_STATE_FULLSCREEN = None;
1959 
1960   xitk->atoms.XA_WM_WINDOW_TYPE = None;
1961   xitk->atoms.XA_WM_WINDOW_TYPE_DESKTOP = None;
1962   xitk->atoms.XA_WM_WINDOW_TYPE_DOCK = None;
1963   xitk->atoms.XA_WM_WINDOW_TYPE_TOOLBAR = None;
1964   xitk->atoms.XA_WM_WINDOW_TYPE_MENU = None;
1965   xitk->atoms.XA_WM_WINDOW_TYPE_UTILITY = None;
1966   xitk->atoms.XA_WM_WINDOW_TYPE_SPLASH = None;
1967   xitk->atoms.XA_WM_WINDOW_TYPE_DIALOG = None;
1968   xitk->atoms.XA_WM_WINDOW_TYPE_DROPDOWN_MENU = None;
1969   xitk->atoms.XA_WM_WINDOW_TYPE_POPUP_MENU = None;
1970   xitk->atoms.XA_WM_WINDOW_TYPE_TOOLTIP = None;
1971   xitk->atoms.XA_WM_WINDOW_TYPE_NOTIFICATION = None;
1972   xitk->atoms.XA_WM_WINDOW_TYPE_COMBO = None;
1973   xitk->atoms.XA_WM_WINDOW_TYPE_DND = None;
1974   xitk->atoms.XA_WM_WINDOW_TYPE_NORMAL = None;
1975 
1976   memset(&xitk->keypress, 0, sizeof(xitk->keypress));
1977 
1978   pthread_mutexattr_init(&attr);
1979   pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
1980   pthread_mutex_init (&xitk->mutex, &attr);
1981 
1982   snprintf(buffer, sizeof(buffer), "-[ xiTK version %d.%d.%d ", XITK_MAJOR_VERSION, XITK_MINOR_VERSION, XITK_SUB_VERSION);
1983 
1984   /* Check if SHM is working */
1985 #ifdef HAVE_SHM
1986   if(xitk->use_xshm) {
1987     XImage             *xim;
1988     XShmSegmentInfo     shminfo;
1989 
1990     xim = XShmCreateImage(display,
1991 			  (DefaultVisual(display, (DefaultScreen(display)))),
1992 			  (DefaultDepth(display, (DefaultScreen(display)))),
1993 			  ZPixmap, NULL, &shminfo, 10, 10);
1994     if(!xim)
1995       xitk->use_xshm = 0;
1996     else {
1997       shminfo.shmid = shmget(IPC_PRIVATE, xim->bytes_per_line * xim->height, IPC_CREAT | 0777);
1998       if(shminfo.shmid < 0) {
1999 	XDestroyImage(xim);
2000 	xitk->use_xshm = 0;
2001       }
2002       else {
2003 	shminfo.shmaddr = xim->data =  shmat(shminfo.shmid, 0, 0);
2004 	if(shminfo.shmaddr == (char *) -1) {
2005 	  XDestroyImage(xim);
2006 	  xitk->use_xshm = 0;
2007 	}
2008 	else {
2009 	  shminfo.readOnly = False;
2010 
2011 	  xitk_x_error = 0;
2012 	  xitk_install_x_error_handler();
2013 
2014 	  XShmAttach(display, &shminfo);
2015 	  XSync(display, False);
2016 	  if(xitk_x_error)
2017 	    xitk->use_xshm = 0;
2018 	  else {
2019 	    XShmDetach(display, &shminfo);
2020 	    strlcat(buffer, "[XShm]", sizeof(buffer));
2021 	  }
2022 
2023 	  XDestroyImage(xim);
2024 	  shmdt(shminfo.shmaddr);
2025 
2026 	  xitk_uninstall_x_error_handler();
2027 	  xitk_x_error = 0;
2028 	}
2029 	shmctl(shminfo.shmid, IPC_RMID, 0);
2030       }
2031     }
2032   }
2033 #endif
2034 
2035 #ifdef WITH_XFT
2036   strlcat(buffer, "[XFT]", sizeof(buffer));
2037 #elif defined(WITH_XMB)
2038   strlcat(buffer, "[XMB]", sizeof(buffer));
2039 #endif
2040 
2041   strlcat(buffer, " ]-", sizeof(buffer));
2042 
2043   if(verbosity)
2044     printf("%s", buffer);
2045 
2046   xitk->wm_type = xitk_check_wm(display);
2047 
2048   /* init font caching */
2049   xitk_font_cache_init();
2050 
2051   xitk_cursors_init(display);
2052   xitk_tips_init(display);
2053 }
2054 
2055 /*
2056  * Start widget event handling.
2057  * It will block till widget_stop() call
2058  */
xitk_run(xitk_startup_callback_t cb,void * data)2059 void xitk_run (xitk_startup_callback_t cb, void *data) {
2060   __xitk_t *xitk = (__xitk_t *)gXitk;
2061   XEvent            myevent;
2062   struct sigaction  action;
2063   fd_set            r;
2064   Bool              got_event;
2065   __gfx_t          *fx;
2066   struct timeval    tv;
2067   int               xconnection;
2068 
2069   action.sa_handler = xitk_signal_handler;
2070   sigemptyset(&(action.sa_mask));
2071   action.sa_flags = 0;
2072   if(sigaction(SIGHUP, &action, NULL) != 0) {
2073     XITK_WARNING("sigaction(SIGHUP) failed: %s\n", strerror(errno));
2074   }
2075   action.sa_handler = xitk_signal_handler;
2076   sigemptyset(&(action.sa_mask));
2077   action.sa_flags = 0;
2078   if(sigaction(SIGUSR1, &action, NULL) != 0) {
2079     XITK_WARNING("sigaction(SIGUSR1) failed: %s\n", strerror(errno));
2080   }
2081   action.sa_handler = xitk_signal_handler;
2082   sigemptyset(&(action.sa_mask));
2083   action.sa_flags = 0;
2084   if(sigaction(SIGUSR2, &action, NULL) != 0) {
2085     XITK_WARNING("sigaction(SIGUSR2) failed: %s\n", strerror(errno));
2086   }
2087   action.sa_handler = xitk_signal_handler;
2088   sigemptyset(&(action.sa_mask));
2089   action.sa_flags = 0;
2090   if(sigaction(SIGINT, &action, NULL) != 0) {
2091     XITK_WARNING("sigaction(SIGINT) failed: %s\n", strerror(errno));
2092   }
2093   action.sa_handler = xitk_signal_handler;
2094   sigemptyset(&(action.sa_mask));
2095   action.sa_flags = 0;
2096   if(sigaction(SIGTERM, &action, NULL) != 0) {
2097     XITK_WARNING("sigaction(SIGTERM) failed: %s\n", strerror(errno));
2098   }
2099   action.sa_handler = xitk_signal_handler;
2100   sigemptyset(&(action.sa_mask));
2101   action.sa_flags = 0;
2102   if(sigaction(SIGQUIT, &action, NULL) != 0) {
2103     XITK_WARNING("sigaction(SIGQUIT) failed: %s\n", strerror(errno));
2104   }
2105 #ifndef DEBUG
2106   action.sa_handler = xitk_signal_handler;
2107   sigemptyset(&(action.sa_mask));
2108   action.sa_flags = 0;
2109   if(sigaction(SIGSEGV, &action, NULL) != 0) {
2110     XITK_WARNING("sigaction(SIGSEGV) failed: %s\n", strerror(errno));
2111   }
2112 #endif
2113   xitk->running = 1;
2114 
2115   XLOCK (xitk->x.x_lock_display, xitk->x.display);
2116   XSync (xitk->x.display, True); /* Flushing the toilets */
2117   XUNLOCK (xitk->x.x_unlock_display, xitk->x.display);
2118 
2119   /*
2120    * Force to repain the widget list if it exist
2121    */
2122   MUTLOCK();
2123 
2124   fx = (__gfx_t *)xitk->gfxs.head.next;
2125 
2126   while (fx->node.next) {
2127     FXLOCK(fx);
2128 
2129     if(fx->window != None && fx->widget_list) {
2130       XEvent xexp;
2131 
2132       memset(&xexp, 0, sizeof xexp);
2133       xexp.xany.type          = Expose;
2134       xexp.xexpose.type       = Expose;
2135       xexp.xexpose.send_event = True;
2136       xexp.xexpose.display    = xitk->x.display;
2137       xexp.xexpose.window     = fx->window;
2138       xexp.xexpose.count      = 0;
2139 
2140       XLOCK (xitk->x.x_lock_display, xitk->x.display);
2141       if (!XSendEvent (xitk->x.display, fx->window, False, ExposureMask, &xexp)) {
2142 	XITK_WARNING("XSendEvent(display, 0x%x ...) failed.\n", (unsigned int) fx->window);
2143       }
2144       XUNLOCK (xitk->x.x_unlock_display, xitk->x.display);
2145     }
2146 
2147     FXUNLOCK(fx);
2148     fx = (__gfx_t *)fx->node.next;
2149   }
2150 
2151   MUTUNLOCK();
2152 
2153   /* We're ready to handle anything */
2154   if(cb)
2155     cb(data);
2156 
2157   XLOCK (xitk->x.x_lock_display, xitk->x.display);
2158   xconnection = ConnectionNumber (xitk->x.display);
2159   XUNLOCK (xitk->x.x_unlock_display, xitk->x.display);
2160 
2161   /*
2162    * Now, wait for a new xevent
2163    */
2164   while (xitk->running) {
2165 
2166     FD_ZERO(&r);
2167     FD_SET(xconnection, &r);
2168 
2169     tv.tv_sec  = 0;
2170     tv.tv_usec = 33000;
2171 
2172     select(xconnection + 1, &r, 0, 0, &tv);
2173 
2174     if (!xitk->running)
2175       break;
2176 
2177     XLOCK (xitk->x.x_lock_display, xitk->x.display);
2178     got_event = (XPending (xitk->x.display) != 0);
2179     if( got_event )
2180       XNextEvent (xitk->x.display, &myevent);
2181     XUNLOCK (xitk->x.x_unlock_display, xitk->x.display);
2182 
2183     while(got_event == True) {
2184 
2185       xitk_xevent_notify(&myevent);
2186 
2187       if (!xitk->running)
2188         break;
2189 
2190       XLOCK (xitk->x.x_lock_display, xitk->x.display);
2191       got_event = (XPending (xitk->x.display) != 0);
2192       if( got_event )
2193         XNextEvent (xitk->x.display, &myevent);
2194       XUNLOCK (xitk->x.x_unlock_display, xitk->x.display);
2195     }
2196 
2197   }
2198 
2199   /* pending destroys of the event handlers */
2200   while (1) {
2201     fx = (__gfx_t *)xitk->gfxs.head.next;
2202     if (!fx->node.next)
2203       break;
2204     FXLOCK (fx);
2205     __fx_destroy(fx, 1);
2206   }
2207   MUTLOCK ();
2208   xitk_dlist_clear (&xitk->gfxs);
2209   xitk_dlist_clear (&xitk->wlists);
2210   MUTUNLOCK ();
2211 
2212   /* destroy font caching */
2213   xitk_font_cache_done();
2214 
2215   xitk_config_deinit (xitk->config);
2216   pthread_mutex_destroy (&xitk->mutex);
2217 
2218   XITK_FREE (gXitk);
2219 
2220 }
2221 
2222 /*
2223  * Stop the wait xevent loop
2224  */
xitk_stop(void)2225 void xitk_stop(void) {
2226   __xitk_t *xitk = (__xitk_t *)gXitk;
2227   xitk_tips_deinit();
2228   xitk_cursors_deinit (xitk->x.display);
2229   xitk->running = 0;
2230 
2231   if (xitk->parent.window != None) {
2232     int (*previous_error_handler)(Display *, XErrorEvent *);
2233     XSync (xitk->x.display, False);
2234     /* don't care about BadWindow when the focussed window is gone already */
2235     previous_error_handler = XSetErrorHandler(_x_ignoring_error_handler);
2236     XSetInputFocus (xitk->x.display, xitk->parent.window, xitk->parent.focus, CurrentTime);
2237     XSync (xitk->x.display, False);
2238     XSetErrorHandler(previous_error_handler);
2239   }
2240 }
2241 
xitk_get_system_font(void)2242 const char *xitk_get_system_font(void) {
2243   __xitk_t *xitk = (__xitk_t *)gXitk;
2244 
2245   return xitk_config_get_system_font (xitk->config);
2246 }
2247 
xitk_get_default_font(void)2248 const char *xitk_get_default_font(void) {
2249   __xitk_t *xitk = (__xitk_t *)gXitk;
2250 
2251   return xitk_config_get_default_font (xitk->config);
2252 }
2253 
xitk_get_xmb_enability(void)2254 int xitk_get_xmb_enability(void) {
2255   __xitk_t *xitk = (__xitk_t *)gXitk;
2256 
2257   return xitk_config_get_xmb_enability (xitk->config);
2258 }
2259 
xitk_set_xmb_enability(int value)2260 void xitk_set_xmb_enability(int value) {
2261   __xitk_t *xitk = (__xitk_t *)gXitk;
2262 
2263   xitk_config_set_xmb_enability (xitk->config, value);
2264 }
2265 
xitk_get_black_color(void)2266 int xitk_get_black_color(void) {
2267   __xitk_t *xitk = (__xitk_t *)gXitk;
2268 
2269   return xitk_config_get_black_color (xitk->config);
2270 }
2271 
xitk_get_white_color(void)2272 int xitk_get_white_color(void) {
2273   __xitk_t *xitk = (__xitk_t *)gXitk;
2274 
2275   return xitk_config_get_white_color (xitk->config);
2276 }
2277 
xitk_get_background_color(void)2278 int xitk_get_background_color(void) {
2279   __xitk_t *xitk = (__xitk_t *)gXitk;
2280 
2281   return xitk_config_get_background_color (xitk->config);
2282 }
2283 
xitk_get_focus_color(void)2284 int xitk_get_focus_color(void) {
2285   __xitk_t *xitk = (__xitk_t *)gXitk;
2286 
2287   return xitk_config_get_focus_color (xitk->config);
2288 }
2289 
xitk_get_select_color(void)2290 int xitk_get_select_color(void) {
2291   __xitk_t *xitk = (__xitk_t *)gXitk;
2292 
2293   return xitk_config_get_select_color (xitk->config);
2294 }
2295 
xitk_get_timer_label_animation(void)2296 unsigned long xitk_get_timer_label_animation(void) {
2297   __xitk_t *xitk = (__xitk_t *)gXitk;
2298 
2299   return xitk_config_get_timer_label_animation (xitk->config);
2300 }
2301 
xitk_get_warning_foreground(void)2302 unsigned long xitk_get_warning_foreground(void) {
2303   __xitk_t *xitk = (__xitk_t *)gXitk;
2304 
2305   return xitk_config_get_warning_foreground (xitk->config);
2306 }
2307 
xitk_get_warning_background(void)2308 unsigned long xitk_get_warning_background(void) {
2309   __xitk_t *xitk = (__xitk_t *)gXitk;
2310 
2311   return xitk_config_get_warning_background (xitk->config);
2312 }
2313 
xitk_get_timer_dbl_click(void)2314 long int xitk_get_timer_dbl_click(void) {
2315   __xitk_t *xitk = (__xitk_t *)gXitk;
2316 
2317   return xitk_config_get_timer_dbl_click (xitk->config);
2318 }
2319 
xitk_get_barstyle_feature(void)2320 int xitk_get_barstyle_feature(void) {
2321   __xitk_t *xitk = (__xitk_t *)gXitk;
2322 
2323   return xitk_config_get_barstyle_feature (xitk->config);
2324 }
2325 
xitk_get_checkstyle_feature(void)2326 int xitk_get_checkstyle_feature(void) {
2327   __xitk_t *xitk = (__xitk_t *)gXitk;
2328 
2329   return xitk_config_get_checkstyle_feature (xitk->config);
2330 }
2331 
xitk_get_cursors_feature(void)2332 int xitk_get_cursors_feature(void) {
2333   __xitk_t *xitk = (__xitk_t *)gXitk;
2334 
2335   return xitk_config_get_cursors_feature (xitk->config);
2336 }
2337 
xitk_get_menu_shortcuts_enability(void)2338 int xitk_get_menu_shortcuts_enability(void) {
2339   __xitk_t *xitk = (__xitk_t *)gXitk;
2340 
2341   return xitk_config_get_menu_shortcuts_enability (xitk->config);
2342 }
2343 
xitk_get_display_width(void)2344 int xitk_get_display_width(void) {
2345   __xitk_t *xitk = (__xitk_t *)gXitk;
2346 
2347   return xitk->display_width;
2348 }
2349 
xitk_get_display_height(void)2350 int xitk_get_display_height(void) {
2351   __xitk_t *xitk = (__xitk_t *)gXitk;
2352 
2353   return xitk->display_height;
2354 }
2355 
xitk_get_black_pixel_color(void)2356 XColor xitk_get_black_pixel_color(void) {
2357   __xitk_t *xitk = (__xitk_t *)gXitk;
2358 
2359   return xitk->black;
2360 }
2361 
xitk_get_tips_timeout(void)2362 unsigned long xitk_get_tips_timeout(void) {
2363   __xitk_t *xitk = (__xitk_t *)gXitk;
2364 
2365   return xitk->tips_timeout;
2366 }
2367 
xitk_set_tips_timeout(unsigned long timeout)2368 void xitk_set_tips_timeout(unsigned long timeout) {
2369   __xitk_t *xitk = (__xitk_t *)gXitk;
2370 
2371   xitk->tips_timeout = timeout;
2372 }
2373 
xitk_filter_filename(const char * name)2374 char *xitk_filter_filename(const char *name) {
2375   if (!name)
2376     return NULL;
2377   if (!strncasecmp (name, "file:", 5)) {
2378     static const uint8_t tab_unhex[256] = {
2379       255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
2380       255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
2381       255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
2382         0,  1,  2,  3,  4,  5,  6,  7,  8,  9,255,255,255,255,255,255,
2383       255, 10, 11, 12, 13, 14, 15,255,255,255,255,255,255,255,255,255,
2384       255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
2385       255, 10, 11, 12, 13, 14, 15,255,255,255,255,255,255,255,255,255,
2386       255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
2387       255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
2388       255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
2389       255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
2390       255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
2391       255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
2392       255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
2393       255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
2394       255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255
2395     };
2396     const uint8_t *p = (const uint8_t *)name + 5;
2397     uint8_t *ret, *q;
2398     size_t l = strlen ((const char *)p);
2399     ret = malloc (l + 2);
2400     if (!ret)
2401       return NULL;
2402     while (*p == '/') p++;
2403     q = ret;
2404     *q++ = '/';
2405     while (*p) {
2406       uint8_t z = *p++;
2407       if (z == '%') {
2408         do {
2409           uint8_t y;
2410           y = tab_unhex[*p];
2411           if (y & 128) break;
2412           p++;
2413           z = y;
2414           y = tab_unhex[*p];
2415           if (y & 128) break;
2416           p++;
2417           z = (z << 4) | y;
2418         } while (0);
2419       }
2420       *q++ = z;
2421     }
2422     *q = 0;
2423     return (char *)ret;
2424   }
2425   return strdup (name);
2426 }
2427 
2428 /*
2429  *
2430  */
xitk_set_locale(void)2431 const char *xitk_set_locale(void) {
2432   const char *cur_locale = NULL;
2433 
2434 #ifdef ENABLE_NLS
2435   if(setlocale (LC_ALL,"") == NULL) {
2436     XITK_WARNING("locale not supported by C library\n");
2437     return NULL;
2438   }
2439 
2440   cur_locale = setlocale(LC_ALL, NULL);
2441 #endif
2442 
2443   return cur_locale;
2444 }
2445 
2446 
2447 /*
2448  *
2449  */
xitk_get_last_keypressed_time(void)2450 long int xitk_get_last_keypressed_time(void) {
2451   __xitk_t *xitk = (__xitk_t *)gXitk;
2452   struct timeval tm, tm_diff;
2453 
2454   gettimeofday(&tm, NULL);
2455   timersub (&tm, &xitk->keypress, &tm_diff);
2456   return tm_diff.tv_sec;
2457 }
2458 
2459 /*
2460  * Return 0/1 from char value (valids are 1/0, true/false,
2461  * yes/no, on/off. Case isn't checked.
2462  */
xitk_get_bool_value(const char * val)2463 int xitk_get_bool_value(const char *val) {
2464   static const struct {
2465     char str[7];
2466     uint8_t value;
2467   } bools[] = {
2468     { "1",     1 }, { "true",  1 }, { "yes",   1 }, { "on",    1 },
2469     { "0",     0 }, { "false", 0 }, { "no",    0 }, { "off",   0 }
2470   };
2471   int i;
2472 
2473   ABORT_IF_NULL(val);
2474 
2475   for(i = 0; i < sizeof(bools)/sizeof(bools[0]); i++) {
2476     if(!(strcasecmp(bools[i].str, val)))
2477       return bools[i].value;
2478   }
2479 
2480   return 0;
2481 }
2482