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