1 #if ! defined(PROG_DISABLE_GUI)
2 
3 #if defined(PROG_HAS_X11)
4 #include <X11/Xlib.h>
5 #include <X11/Xutil.h>
6 #include <X11/Xatom.h>
7 #include <X11/Xproto.h>
8 #include <X11/cursorfont.h>
9 #include <X11/extensions/XShm.h>
10 
11 #if defined(PROG_HAS_XRANDR)
12 #include <X11/extensions/Xrandr.h>
13 #endif
14 
15 #include <GL/gl.h>
16 #include <GL/glx.h>
17 #endif
18 
19 #include "declarations.h"
20 #include "conf_str.h"
21 #include "worker_draw.h"
22 
23 #if ! defined(PROG_DISABLE_INPUT)
24 #include "input/input_driver.h"
25 #endif
26 
27 #include <pwd.h>
28 
29 #if defined(PROG_HAS_DRAWPIXELS)
30 #if defined(PROG_HAS_POSIX_SHM) && defined(HAVE_SYS_MMAN_H)
31 #include <fcntl.h>
32 #include <sys/mman.h>
33 #else
34 #include <sys/ipc.h>
35 #include <sys/sem.h>
36 #include <sys/shm.h>
37 #endif
38 #endif
39 
40 
41 
worker_draw(void * ta)42 void worker_draw(void *ta) {
43 #if defined(PROG_HAS_X11)
44 	unsigned int *b, e;
45 
46 	struct timeval tv;
47 #endif
48 	struct t_ctx *ti;
49 
50 	ti = (struct t_ctx *) ta;
51 
52 	/* This thread does not like to receive pthread_cancel() */
53 	ti->ar = THREAD_TERM_SELF;
54 
55 	pthread_cleanup_push(worker_draw_cancel, ti);
56 #if defined(PROG_HAS_X11)
57 	if(worker_draw_init(ti) == 0) {
58 		if((b = (unsigned int *) conf_fetch("refresh_score")) == NULL) {
59 			e = 0;
60 		}
61 		else {
62 			e = *b;
63 		}
64 
65 		i_fps = e;
66 
67 		while(ti->pr == THREAD_STATE_RUN) {
68 			(void) window_loop_begin((struct t_str *) ti->tp, &tv);
69 			(void) window_loop_end((struct t_str *) ti->tp, &tv, e);
70 		}
71 	}
72 #endif
73 	/* Free allocated resources and terminate thread */
74 	pthread_cleanup_pop(1);
75 
76 	(void) worker_draw_finalize(ti);
77 }
78 
worker_draw_cancel(void * ta)79 static void worker_draw_cancel(void *ta) {
80 	struct t_ctx *ti;
81 
82 	ti = (struct t_ctx *) ta;
83 
84 	if(ti->tp != NULL) {
85 		(void) worker_draw_cancel_local(ti, (struct t_str *) ti->tp);
86 
87 		(void) free(ti->tp);
88 
89 		ti->tp = NULL;
90 	}
91 
92 	ti->tr = THREAD_STATE_STOP;
93 }
94 
worker_draw_cancel_local(__UNUSED__ struct t_ctx * ti,struct t_str * tp)95 static void worker_draw_cancel_local(__UNUSED__ struct t_ctx *ti, struct t_str *tp) {
96 #if defined(PROG_HAS_X11)
97 	if(tp->d != NULL) {
98 		(void) window_close_all();
99 
100 		(void) XLockDisplay(tp->d);
101 
102 		if(c_fpt != NULL) (void) XFreeFontPath(c_fpt);
103 
104 		(void) XUnlockDisplay(tp->d);
105 		(void) XCloseDisplay(tp->d);
106 
107 		tp->d = NULL;
108 	}
109 
110 	if(tp->n != NULL) (void) free(tp->n);
111 
112 	(void) worker_draw_cancel_local_free();
113 #else
114 	(void) tp;
115 #endif
116 }
117 #if defined(PROG_HAS_X11)
worker_draw_cancel_local_free(void)118 static void worker_draw_cancel_local_free(void) {
119 	unsigned int i;
120 
121 	for(i = 0; i < 2; i++) {
122 		if(w_evt[i] != NULL) {
123 			(void) free(w_evt[i]);
124 
125 			w_evt[i] = NULL;
126 		}
127 	}
128 
129 	c_lck = IS_NO;
130 	c_pnd = IS_NO;
131 	c_cnt = 0;
132 	c_evt = 0;
133 }
134 #endif
worker_draw_finalize(struct t_ctx * ti)135 static void worker_draw_finalize(struct t_ctx *ti) {
136 	(void) thread_exit(ti, NULL);
137 }
138 #if defined(PROG_HAS_X11)
worker_draw_init(struct t_ctx * ti)139 static int worker_draw_init(struct t_ctx *ti) {
140 	int r;
141 
142 	int *a;
143 
144 	struct t_str *c;
145 
146 	APP_MALLOC_RET_VALUE(c, sizeof(struct t_str), -1);
147 
148 	ti->tp = c;
149 
150 	(void) thread_title(ti, APPLICATION_EXEC "_draw");
151 
152 	if((a = (int *) conf_fetch("cpu_window_draw")) != NULL) {
153 		if(*a != 0) (void) thread_affinity(*a);
154 	}
155 
156 	r = worker_draw_init_local(ti, (struct t_str *) ti->tp);
157 
158 	ti->tr = THREAD_STATE_IDLE;
159 
160 	return(r);
161 }
162 
worker_draw_init_local(__UNUSED__ struct t_ctx * ti,struct t_str * tp)163 static int worker_draw_init_local(__UNUSED__ struct t_ctx *ti, struct t_str *tp) {
164 	char *f, *s;
165 
166 	size_t t;
167 #if defined(PROG_HAS_XRANDR)
168 	XRRScreenConfiguration *c;
169 #endif
170 	if((s = (char *) conf_fetch("display")) == NULL) {
171 		if((f = env_get("DISPLAY")) == NULL) f = env_get("HOSTDISPLAY");
172 
173 		s = f;
174 	}
175 	else f = NULL;
176 #if defined(HAVE_SETENV)
177 	/* Set this as Redtools may want to use same display */
178 	if(s != NULL) (void) setenv("DISPLAY", (const char *) s, 1);
179 #endif
180 	(void) XInitThreads();
181 
182 	(void) XSetErrorHandler(window_error_handler);
183 	(void) XSetIOErrorHandler(window_error_io_handler);
184 
185 	tp->n = NULL;
186 
187 	if((tp->d = XOpenDisplay(s)) == NULL) {
188 		(void) flush_error();
189 
190 		if(s == NULL) {
191 			LOGWARN(
192 				ERROR_SLIGHT, SUBSYSTEM,
193 				_("Failed to open X11 display")
194 			);
195 		}
196 		else {
197 			LOGWARN(
198 				ERROR_SLIGHT, SUBSYSTEM,
199 				_("Failed to open X11 display %s"),
200 				s
201 			);
202 		}
203 
204 		(void) env_free(f);
205 
206 		return(-1);
207 	}
208 
209 	/* Store display name for later use */
210 	if(s == NULL) s = "<local>";
211 
212 	t = str_len(s, STRING_ASCII);
213 
214 	if((tp->n = malloc(t + sizeof(char))) == NULL) {
215 		LOGWARN(
216 			ERROR_SLIGHT, SUBSYSTEM,
217 			_("Failed to allocate %lu bytes of memory"),
218 			(unsigned long) (t + sizeof(char))
219 		);
220 
221 		(void) env_free(f);
222 
223 		return(-1);
224 	}
225 
226 	(void) memcpy((void *) tp->n, (const void *) s, t);
227 
228 	tp->n[t] = 0;
229 
230 	(void) env_free(f);
231 
232 	(void) XLockDisplay(tp->d);
233 
234 	tp->c = XDefaultScreen(tp->d);
235 	tp->r = XDefaultRootWindow(tp->d);
236 
237 	/* Get root window attributes */
238 	(void) memset((void *) &tp->b, 0, sizeof(tp->b));
239 
240 	if(XGetWindowAttributes(tp->d, tp->r, &tp->b) == 0) {
241 		(void) flush_error();
242 
243 		LOGWARN(
244 			ERROR_SLIGHT, SUBSYSTEM,
245 			_("Failed to get root window %lu attributes on screen %s.%d"),
246 			(unsigned long) tp->r, tp->n, (int) tp->c
247 		);
248 
249 		(void) XUnlockDisplay(tp->d);
250 
251 		return(-1);
252 	}
253 
254 	/* Get default screen refresh rate from randr extension if supported */
255 #if defined(PROG_HAS_XRANDR)
256 	if((c = XRRGetScreenInfo(tp->d, tp->r)) != NULL) {
257 		tp->m = (unsigned int) XRRConfigCurrentRate(c);
258 
259 		(void) XRRFreeScreenConfigInfo(c);
260 
261 		if(tp->m < WINDOW_UPDATE_MIN) {
262 			(void) flush_error();
263 
264 			LOGWARN(
265 				ERROR_NOERROR, SUBSYSTEM,
266 				_("Display %s refresh rate %uHz is below acceptable limit of %uHz, setting window refresh rate to %uHz"),
267 				tp->n, tp->m, (unsigned int) WINDOW_UPDATE_MIN, worker_draw_get_refresh_rate()
268 			);
269 
270 			tp->m = worker_draw_get_refresh_rate();
271 		}
272 	}
273 	else tp->m = worker_draw_get_refresh_rate();
274 #else
275 	tp->m = worker_draw_get_refresh_rate();
276 #endif
277 	/* Store server font paths for later use */
278 	c_fpt = XGetFontPath(tp->d, &n_fpt);
279 
280 	/* Calculate screen dpi */
281 	x_dpi = (double) XDisplayWidth(tp->d, tp->c) * 25.4 / (double) XDisplayWidthMM(tp->d, tp->c);
282 	y_dpi = (double) XDisplayHeight(tp->d, tp->c) * 25.4 / (double) XDisplayHeightMM(tp->d, tp->c);
283 
284 	(void) XUnlockDisplay(tp->d);
285 
286 	/* Whining limit is 72 dpi */
287 	if(x_dpi < 72.0 || y_dpi < 72.0) {
288 		(void) flush_error();
289 
290 		LOGWARN(
291 			ERROR_NOERROR, SUBSYSTEM,
292 			_("Display resolution %gx%g DPI is smaller than expected on screen %s.%d"),
293 			x_dpi, y_dpi, tp->n, (int) tp->c
294 		);
295 	}
296 
297 	/* Initialize global widget stuff */
298 #if ! defined(PROG_DISABLE_WIDGET)
299 	(void) widget_init_global();
300 #endif
301 	return(0);
302 }
303 
window_error_handler(Display * d,XErrorEvent * e)304 static int window_error_handler(Display *d, XErrorEvent *e) {
305 	unsigned int i;
306 
307 	char *s, *p;
308 
309 	if(d == NULL || e == NULL) return(0);
310 
311 	(void) handler_stack_print();
312 
313 	APP_MALLOC_RET_VALUE(s, CONFIG_LINE_LENGTH + sizeof(char), 0);
314 
315 	s[0] = 0;
316 
317 	for(i = 0; ; i++) {
318 		if(w_err_t[i].s == NULL) {
319 			p = _("Unknown");
320 
321 			break;
322 		}
323 		else if(w_err_t[i].c == (int) e->request_code) {
324 			p = w_err_t[i].s;
325 
326 			break;
327 		}
328 	}
329 
330 	(void) XLockDisplay(d);
331 	(void) XGetErrorText(d, e->error_code, s, CONFIG_LINE_LENGTH);
332 	(void) XUnlockDisplay(d);
333 
334 	(void) flush_error();
335 
336 	LOGWARN(
337 		ERROR_SLIGHT, SUBSYSTEM,
338 		_("Xlib error occurred. %s: %s (failed request serial %lu, error code %d, major op-code %d, minor op-code %d).%c"
339 		" Use xdpyinfo -queryExtensions to check failed extension by major op-code"),
340 		p, s, (unsigned long) e->serial, (int) e->error_code, (int) e->request_code, (int) e->minor_code, CONFIG_LINE_FEED
341 	);
342 
343 	(void) free(s);
344 
345 	return(0);
346 }
347 
window_error_null_handler(__UNUSED__ Display * d,__UNUSED__ XErrorEvent * e)348 static int window_error_null_handler(__UNUSED__ Display *d, __UNUSED__ XErrorEvent *e) {
349 	return(0);
350 }
351 
window_error_io_handler(__UNUSED__ Display * d)352 static int window_error_io_handler(__UNUSED__ Display *d) {
353 	(void) handler_stack_print();
354 
355 	(void) flush_error();
356 
357 	LOGWARN(
358 		ERROR_NOERROR, SUBSYSTEM,
359 		_("Xlib I/O error occurred. %s will now stop. Thank you for your cooperation"),
360 		APPLICATION_NAME
361 	);
362 
363 	(void) window_error_io_handler_emergency();
364 	(void) main_stop();
365 
366 	/* To keep compiler happy */
367 	return(0);
368 }
369 
window_error_io_handler_emergency(void)370 static void window_error_io_handler_emergency(void) {
371 	unsigned int i;
372 
373 	/* In case of emergency shutdown, free what can be freed */
374 	if(a_win != NULL) {
375 		for(i = 0; i < c_win; i++) {
376 			if(a_win[i] == NULL) continue;
377 
378 			(void) window_close_dealloc(a_win[i], NULL);
379 #if defined(PROG_HAS_DRAWPIXELS) && ! defined(PROG_HAS_POSIX_SHM)
380 			(void) window_close_dealloc_sem(a_win[i]);
381 #endif
382 			(void) free(a_win[i]);
383 		}
384 
385 		(void) free(a_win);
386 
387 		a_win = NULL;
388 	}
389 
390 	c_win = 0;
391 
392 	(void) worker_draw_cancel_local_free();
393 }
394 
window_loop_begin(struct t_str * tp,struct timeval * t)395 static void window_loop_begin(struct t_str *tp, struct timeval *t) {
396 	(void) timer_get_time(t);
397 
398 	(void) window_cmd_roll(tp);
399 
400 	if(a_win != NULL) {
401 		(void) window_loop();
402 		(void) window_event(tp);
403 	}
404 }
405 
window_loop_end(struct t_str * tp,struct timeval * t,unsigned int e)406 static void window_loop_end(struct t_str *tp, struct timeval *t, unsigned int e) {
407 	long n;
408 
409 	struct timeval v;
410 
411 	(void) timer_get_time(&v);
412 
413 	n = (long) (v.tv_usec - t->tv_usec);
414 
415 	if(n < 0) n = 1000000 + n;
416 
417 	n = ((1000000 / tp->m) - n) * 1000;
418 
419 	if(n > 0) (void) timer_wait(0, n);
420 
421 	if(e != 0) (void) window_loop_fps(tp, n, e);
422 }
423 
window_loop_fps(struct t_str * tp,long n,unsigned int e)424 static void window_loop_fps(struct t_str *tp, long n, unsigned int e) {
425 	double r, t;
426 
427 	t = (double) ((double) n / 10000000.0) * (double) tp->m;
428 
429 	s_fps -= u_fps[c_fps];
430 	s_fps += t;
431 
432 	u_fps[c_fps] = t;
433 
434 	if(++c_fps == WINDOW_UPDATE_FPS) {
435 		c_fps = 0;
436 
437 		++k_fps;
438 	}
439 
440 	if(k_fps > 0 && --i_fps == 0) {
441 		r = s_fps / (double) WINDOW_UPDATE_FPS;
442 
443 		(void) fprintf(stdout, "%g%% @ %ufps%c", r, tp->m, CONFIG_LINE_FEED);
444 
445 		i_fps = e;
446 	}
447 }
448 
window_loop(void)449 static void window_loop(void) {
450 	unsigned int i;
451 
452 	struct a_window *a;
453 
454 	void (*cb)(struct d_par *);
455 
456 	for(i = 0; i < c_win; i++) {
457 		if((a = window_get_struct_by_handle(i + 1)) == NULL) continue;
458 
459 		if(a->m != 0) {
460 			/* Active window needs constant exposing */
461 			(void) window_event_send_expose(a);
462 		}
463 		else {
464 			/* Inactive window is exposed only if refresh is requested */
465 			(void) window_cmd_roll_operation(a);
466 		}
467 
468 		/* Wake up window thread to run its callback functions */
469 		(void) thread_wake(a->x);
470 
471 		/* Call window main loop callback */
472 		if((cb = a->cb_main_loop) != NULL) (void) (*cb)(&a->par_main_loop);
473 	}
474 }
475 
window_open(struct t_str * tp,struct w_ctx * w)476 static unsigned int window_open(struct t_str *tp, struct w_ctx *w) {
477 	unsigned int i, d;
478 
479 	struct a_window *a;
480 	struct a_window **t;
481 
482 	void (*cb)(unsigned int, struct d_par *);
483 
484 	/* Check if some slot can be reused */
485 	d = 0;
486 
487 	for(i = 0; i < c_win; i++) {
488 		if(a_win[i] == NULL) {
489 			d = i + 1;
490 
491 			break;
492 		}
493 	}
494 
495 	if(d == 0) {
496 		/* No free slot found, allocate one */
497 		APP_REALLOC_RET_VALUE(t, a_win, sizeof(struct a_win *) * (c_win + 1), 0);
498 		APP_MALLOC_RET_VALUE(a_win[c_win], sizeof(struct a_window), 0);
499 
500 		(void) memset((void *) a_win[c_win], 0, sizeof(struct a_window));
501 
502 		d = ++c_win;
503 	}
504 	else {
505 		/* Reuse existing slot */
506 		APP_MALLOC_RET_VALUE(a_win[d - 1], sizeof(struct a_window), 0);
507 
508 		(void) memset((void *) a_win[d - 1], 0, sizeof(struct a_window));
509 	}
510 
511 	a = a_win[d - 1];
512 
513 	/* Set reasonable defaults for this window */
514 	a->a = d;
515 
516 	(void) window_open_op_def(a, tp, w);
517 
518 	/* Create thread to run callbacks for this window */
519 	if(window_open_op_thread(a) != 0) {
520 		(void) window_close_dealloc(a, a->d);
521 		(void) window_close_free(d);
522 
523 		return(0);
524 	}
525 
526 	/* Create window to be displayed later */
527 	if(window_open_op(a, w) != 0) {
528 		(void) window_close_thread(a);
529 		(void) window_close_dealloc(a, a->d);
530 		(void) window_close_free(d);
531 
532 		return(0);
533 	}
534 
535 	/* Create possible widgets and menues for this window */
536 	a->w_gui.id = a->p;
537 	a->w_gui.hnd = a->a;
538 
539 	a->w_gui.set = w->e;
540 
541 	a->w_gui.w = (unsigned int) a->b.width;
542 	a->w_gui.h = (unsigned int) a->b.height;
543 #if ! defined(PROG_DISABLE_WIDGET)
544 	if(widget_init_stack(&a->w_gui) != 0) {
545 		(void) window_close_thread(a);
546 		(void) window_close_dealloc(a, a->d);
547 		(void) window_close_free(d);
548 
549 		return(0);
550 	}
551 #endif
552 #if ! defined(PROG_DISABLE_MENU)
553 	if(menu_init_stack_by_id(a->x, (unsigned int) a->w_gui.id, d,
554 		(unsigned int) a->b.width, a->w) != 0) {
555 #if ! defined(PROG_DISABLE_WIDGET)
556 		(void) widget_free_stack(&a->w_gui);
557 #endif
558 		(void) window_close_thread(a);
559 		(void) window_close_dealloc(a, a->d);
560 		(void) window_close_free(d);
561 
562 		return(0);
563 	}
564 #endif
565 	a->par_main_loop.s = window_open_op_par(w->par_main_loop.s);
566 	a->par_main_loop.n = w->par_main_loop.n;
567 
568 	a->par_expose.s = window_open_op_par(w->par_expose.s);
569 	a->par_expose.n = w->par_expose.n;
570 
571 	a->par_key_press.s = window_open_op_par(w->par_key_press.s);
572 	a->par_key_press.n = w->par_key_press.n;
573 	a->par_key_release.s = window_open_op_par(w->par_key_release.s);
574 	a->par_key_release.n = w->par_key_release.n;
575 	a->par_button_press.s = window_open_op_par(w->par_button_press.s);
576 	a->par_button_press.n = w->par_button_press.n;
577 	a->par_button_release.s = window_open_op_par(w->par_button_release.s);
578 	a->par_button_release.n = w->par_button_release.n;
579 
580 	a->par_client_message.s = window_open_op_par(w->par_client_message.s);
581 	a->par_client_message.n = w->par_client_message.n;
582 
583 	a->par_configure_notify.s = window_open_op_par(w->par_configure_notify.s);
584 	a->par_configure_notify.n = w->par_configure_notify.n;
585 	a->par_destroy_notify.s = window_open_op_par(w->par_destroy_notify.s);
586 	a->par_destroy_notify.n = w->par_destroy_notify.n;
587 	a->par_motion_notify.s = window_open_op_par(w->par_motion_notify.s);
588 	a->par_motion_notify.n = w->par_motion_notify.n;
589 	a->par_map_notify.s = window_open_op_par(w->par_map_notify.s);
590 	a->par_map_notify.n = w->par_map_notify.n;
591 	a->par_unmap_notify.s = window_open_op_par(w->par_unmap_notify.s);
592 	a->par_unmap_notify.n = w->par_unmap_notify.n;
593 
594 	a->par_open_notify.s = window_open_op_par(w->par_open_notify.s);
595 	a->par_open_notify.n = w->par_open_notify.n;
596 
597 	/* Wait for window thread to start */
598 	(void) window_open_op_thread_wait(a);
599 
600 	/* Call open notify callback */
601 	if((cb = w->cb_open_notify) != NULL) (void) (*cb)(a->a, &a->par_open_notify);
602 
603 	(void) window_open_op_map(a, w);
604 
605 	return(d);
606 }
607 
window_open_op(struct a_window * a,struct w_ctx * w)608 static int window_open_op(struct a_window *a, struct w_ctx *w) {
609 	XVisualInfo *v;
610 
611 	(void) XLockDisplay(a->d);
612 
613 	(void) window_open_op_cursor(a);
614 
615 	if((v = window_open_op_visual(a)) == NULL) {
616 		(void) XUnlockDisplay(a->d);
617 
618 		return(-1);
619 	}
620 
621 	if(window_open_op_create(a, w, v) != 0) {
622 		(void) window_open_op_visual_free(v);
623 
624 		(void) XUnlockDisplay(a->d);
625 
626 		return(-1);
627 	}
628 
629 	(void) window_open_op_visual_free(v);
630 
631 	if(window_open_op_alloc(a, w) != 0) {
632 		(void) XDestroyWindow(a->d, a->w);
633 		(void) XUnlockDisplay(a->d);
634 
635 		return(-1);
636 	}
637 
638 	(void) window_open_op_flags(a);
639 	(void) window_open_op_hints(a, w);
640 	(void) window_open_op_title(a, w);
641 
642 	(void) XUnlockDisplay(a->d);
643 
644 	return(0);
645 }
646 
window_open_op_def(struct a_window * a,struct t_str * tp,struct w_ctx * w)647 static void window_open_op_def(struct a_window *a, struct t_str *tp, struct w_ctx *w) {
648 #if defined(PROG_HAS_XRANDR)
649 	XRRScreenConfiguration *c;
650 #endif
651 	a->z = WINDOW_OPERATION_NONE;
652 	a->q = IS_NO;
653 	a->y = 0;
654 
655 	a->s = WINDOW_STATE_UNMAPPED;
656 
657 	a->n = tp->n;
658 	a->d = tp->d;
659 	a->c = tp->c;
660 	a->r = tp->r;
661 
662 	a->h = w->r;
663 	a->m = w->m;
664 #if ! defined(PROG_DISABLE_WIDGET)
665 	a->p = w->p;
666 #endif
667 	a->shm_i = NULL;
668 
669 	a->shm_s.shmid = -1;
670 	a->shm_s.shmaddr = (void *) -1;
671 
672 	a->a_i.c = IS_NO;
673 
674 	a->a_i.b_d = NULL;
675 	a->a_i.b_m = NULL;
676 
677 	a->gl_c = NULL;
678 
679 	a->w_x = w;
680 
681 	a->t = tp;
682 
683 	a->cb_main_loop = w->cb_main_loop;
684 
685 	a->cb_expose = w->cb_expose;
686 
687 	a->cb_key_press = w->cb_key_press;
688 	a->cb_key_release = w->cb_key_release;
689 	a->cb_button_press = w->cb_button_press;
690 	a->cb_button_release = w->cb_button_release;
691 
692 	a->cb_client_message = w->cb_client_message;
693 
694 	a->cb_configure_notify = w->cb_configure_notify;
695 	a->cb_destroy_notify = w->cb_destroy_notify;
696 	a->cb_motion_notify = w->cb_motion_notify;
697 	a->cb_map_notify = w->cb_map_notify;
698 	a->cb_unmap_notify = w->cb_unmap_notify;
699 
700 	/* Update global window refresh divider */
701 	if(a->m != 0) {
702 		/* Get default screen refresh rate from randr extension if supported */
703 #if defined(PROG_HAS_XRANDR)
704 		if((c = XRRGetScreenInfo(tp->d, tp->r)) != NULL) {
705 			tp->m = (unsigned int) XRRConfigCurrentRate(c);
706 
707 			(void) XRRFreeScreenConfigInfo(c);
708 
709 			if(tp->m < WINDOW_UPDATE_MIN) tp->m = worker_draw_get_refresh_rate();
710 		}
711 		else tp->m = worker_draw_get_refresh_rate();
712 #else
713 		tp->m = worker_draw_get_refresh_rate();
714 #endif
715 		if(a->m > tp->m) a->m = tp->m;
716 
717 		tp->m = (unsigned int) round((double) tp->m / (double) a->m);
718 	}
719 #if ! defined(PROG_DISABLE_WIDGET)
720 	(void) widget_init_stack_def(&a->w_gui);
721 #endif
722 }
723 
window_open_op_map(struct a_window * a,struct w_ctx * w)724 static void window_open_op_map(struct a_window *a, struct w_ctx *w) {
725 	(void) XLockDisplay(a->d);
726 	(void) XMoveWindow(a->d, a->w, w->x, w->y);
727 	(void) XDefineCursor(a->d, a->w, a->o[WINDOW_CURSOR_DEFAULT]);
728 	(void) XUnlockDisplay(a->d);
729 }
730 
window_open_op_cursor(struct a_window * a)731 static void window_open_op_cursor(struct a_window *a) {
732 	unsigned int i;
733 
734 	for(i = 0; i < WINDOW_CURSORS; i++) a->o[i] = XCreateFontCursor(a->d, w_cursor[i]);
735 }
736 
window_open_op_flags(struct a_window * a)737 static void window_open_op_flags(struct a_window *a) {
738 	int i, o;
739 	long k;
740 
741 	Atom p, v;
742 
743 	/* Set atoms for session manager */
744 	i = 0;
745 	o = 0;
746 
747 	if((a->v[0] = XInternAtom(a->d, "WM_DELETE_WINDOW", False)) != 0) i++;
748 
749 	if(s_sel == IS_NO) {
750 		/* Set this atom only if not set already on some window */
751 		if((a->v[1] = XInternAtom(a->d, "WM_SAVE_YOURSELF", False)) != 0) {
752 			if(i == 0) o = 1;
753 
754 			i++;
755 
756 			/* This window is the keeper of save yourself atom */
757 			a->y |= 0x1;
758 
759 			s_sel = IS_YES;
760 		}
761 	}
762 	else a->v[1] = 0;
763 
764 	if(i > 0) (void) XSetWMProtocols(a->d, a->w, &a->v[o], i);
765 
766 	/* Set atoms for window manager */
767 	if((p = XInternAtom(a->d, "_NET_WM_WINDOW_TYPE", False)) != 0) {
768 		if((v = XInternAtom(a->d, "_NET_WM_WINDOW_TYPE_NORMAL", False)) != 0) {
769 			(void) XChangeProperty(
770 				a->d, a->w, p, XA_ATOM, 32, PropModeReplace,
771 				(unsigned char *) &v, 1);
772 		}
773 	}
774 
775 	if((p = XInternAtom(a->d, "_NET_WM_PID", False)) != 0) {
776 		k = (long) getpid();
777 
778 		(void) XChangeProperty(
779 			a->d, a->w, p, XA_CARDINAL, 32, PropModeReplace,
780 			(unsigned char *) &k, 1);
781 	}
782 }
783 
window_open_op_hints(struct a_window * a,struct w_ctx * w)784 static void window_open_op_hints(struct a_window *a, struct w_ctx *w) {
785 	char *s;
786 
787 	XClassHint *c;
788 	XSizeHints d;
789 	XTextProperty t;
790 	XWMHints m;
791 
792 	if((s = node_get_node()) != NULL) {
793 		if(XStringListToTextProperty(&s, 1, &t) != 0) {
794 			(void) XSetWMClientMachine(a->d, a->w, &t);
795 			(void) XFree((void *) t.value);
796 		}
797 	}
798 
799 	(void) memset((void *) &d, 0, sizeof(d));
800 
801 	d.flags = PPosition | PSize | PMinSize | PMaxSize | PResizeInc | PWinGravity;
802 
803 	d.x = (int) w->x;
804 	d.y = (int) w->y;
805 
806 	d.width = (unsigned int) w->w;
807 	d.height = (unsigned int) w->h;
808 	d.min_width = (unsigned int) w->w;
809 	d.min_height = (unsigned int) w->h;
810 	d.max_width = (unsigned int) w->w;
811 	d.max_height = (unsigned int) w->h;
812 	d.base_width = (unsigned int) w->w;
813 	d.base_height = (unsigned int) w->h;
814 
815 	d.width_inc = 1;
816 	d.height_inc = 1;
817 
818 	d.win_gravity = StaticGravity;
819 
820 	(void) XSetWMNormalHints(a->d, a->w, &d);
821 
822 	(void) memset((void *) &m, 0, sizeof(m));
823 
824 	m.flags = InputHint | StateHint;
825 	m.initial_state = NormalState;
826 	m.input = True;
827 
828 	(void) XSetWMHints(a->d, a->w, &m);
829 
830 	if((c = XAllocClassHint()) != NULL) {
831 		c->res_name = APPLICATION_NAME;
832 		c->res_class = APPLICATION_EXEC;
833 
834 		(void) XSetClassHint(a->d, a->w, c);
835 		(void) XFree((void *) c);
836 	}
837 }
838 
window_open_op_title(struct a_window * a,struct w_ctx * w)839 static void window_open_op_title(struct a_window *a, struct w_ctx *w) {
840 #ifdef X_HAVE_UTF8_STRING
841 	char *r;
842 
843 	size_t t;
844 
845 	if(w->s == NULL || w->c == NULL) return;
846 
847 	t = str_len(w->s, STRING_ASCII);
848 
849 	(void) XStoreName(a->d, a->w, w->s);
850 	(void) XSetIconName(a->d, a->w, w->s);
851 
852 	if((r = unicode_convert(w->c, w->s, t, "UTF-8")) != NULL) {
853 		(void) XChangeProperty(a->d, a->w,
854 			XInternAtom(a->d, "_NET_WM_NAME", False),
855 			XInternAtom(a->d, "UTF8_STRING", False),
856 			8, PropModeReplace, (unsigned char *) r, (int) t);
857 
858 		(void) unicode_free(r);
859 	}
860 #else
861 	if(w->s == NULL) return;
862 
863 	(void) XStoreName(a->d, a->w, w->s);
864 	(void) XSetIconName(a->d, a->w, w->s);
865 #endif
866 	(void) XFlush(a->d);
867 }
868 
window_open_op_create(struct a_window * a,struct w_ctx * w,XVisualInfo * v)869 static int window_open_op_create(struct a_window *a, struct w_ctx *w, XVisualInfo *v) {
870 	int x, y;
871 	unsigned int e, f;
872 
873 	Window p, c;
874 	XSetWindowAttributes u;
875 
876 	struct a_window *b;
877 
878 	/* Get parent for this window or use root window as parent by default */
879 	if(w->r != 0) {
880 		if((b = window_get_struct_by_handle(w->r)) == NULL) {
881 			(void) flush_error();
882 
883 			LOGWARN(
884 				ERROR_SLIGHT, SUBSYSTEM,
885 				_("Failed to query parent window %u on display %s"),
886 				w->r, a->n
887 			);
888 
889 			return(-1);
890 		}
891 
892 		e = b->b.width;
893 		f = b->b.height;
894 
895 		p = b->w;
896 	}
897 	else {
898 		e = a->t->b.width;
899 		f = a->t->b.height;
900 
901 		p = RootWindow(a->d, v->screen);
902 	}
903 
904 	/* Center window to its parent if position is negative */
905 	if(w->x < 0) {
906 		if((x = (e - w->w) / 2) < 0) x = 0;
907 
908 		w->x = x;
909 	}
910 	else x = w->x;
911 
912 	if(w->y < 0) {
913 		if((y = (f - w->h) / 2) < 0) y = 0;
914 
915 		w->y = y;
916 	}
917 	else y = w->y;
918 
919 	/* Set reasonable default attributes */
920 	(void) memset((void *) &u, 0, sizeof(u));
921 
922 	u.backing_store = WhenMapped;
923 	u.background_pixel = 0;
924 	u.border_pixel = 0;
925 	u.override_redirect = False;
926 
927 	if(w->r != 0) {
928 		u.save_under = True;
929 	}
930 	else u.save_under = False;
931 
932 	u.colormap = XCreateColormap(a->d, RootWindow(a->d, v->screen), v->visual, AllocNone);
933 
934 	u.event_mask = ExposureMask | StructureNotifyMask | ResizeRedirectMask |
935 		EnterWindowMask | LeaveWindowMask | FocusChangeMask |
936 		KeyPressMask | KeyReleaseMask |
937 		ButtonPressMask | ButtonReleaseMask | ButtonMotionMask | PointerMotionMask;
938 
939 	/* Create window and get its attributes */
940 	a->w = XCreateWindow(a->d, p, x, y, w->w, w->h, 0, v->depth, InputOutput, v->visual,
941 		CWBackPixel | CWBorderPixel | CWColormap | CWEventMask, &u);
942 
943 	(void) memset((void *) &a->b, 0, sizeof(a->b));
944 	(void) memset((void *) &a->w_act, 0, sizeof(a->w_act));
945 
946 	if(XGetWindowAttributes(a->d, a->w, &a->b) == 0) {
947 		(void) flush_error();
948 
949 		LOGWARN(
950 			ERROR_SLIGHT, SUBSYSTEM,
951 			_("Failed to query window %lu attributes on display %s"),
952 			(unsigned long) a->w, a->n
953 		);
954 
955 		(void) XDestroyWindow(a->d, a->w);
956 
957 		return(-1);
958 	}
959 
960 	(void) XTranslateCoordinates(a->d, a->w, p, 0, 0, &a->b.x, &a->b.y, &c);
961 
962 	/* Active window size is initially same as physical window size */
963 	a->w_act.left = 0;
964 	a->w_act.right = (unsigned int) a->b.width;
965 	a->w_act.top = 0;
966 	a->w_act.bottom = (unsigned int) a->b.height;
967 
968 	/* Absolute window size is needed for drawing operations */
969 	a->w_act.s.width = (unsigned int) a->b.width;
970 	a->w_act.s.height = (unsigned int) a->b.height;
971 
972 	return(0);
973 }
974 
window_open_op_alloc(struct a_window * a,struct w_ctx * w)975 static int window_open_op_alloc(struct a_window *a, struct w_ctx *w) {
976 	int e;
977 #if defined(PROG_HAS_DRAWPIXELS) && ! defined(PROG_HAS_POSIX_SHM)
978 	int b, c;
979 
980 	Bool d;
981 
982 	if(XShmQueryExtension(a->d) == False) {
983 		(void) flush_error();
984 
985 		LOGWARN(
986 			ERROR_SLIGHT, SUBSYSTEM,
987 			_("Failed to query SHM extension on display %s"),
988 			a->n
989 		);
990 
991 		return(-1);
992 	}
993 
994 	if(XShmQueryVersion(a->d, &b, &c, &d) == False) {
995 		(void) flush_error();
996 
997 		LOGWARN(
998 			ERROR_SLIGHT, SUBSYSTEM,
999 			_("Failed to query SHM version on display %s"),
1000 			a->n
1001 		);
1002 
1003 		return(-1);
1004 	}
1005 
1006 	/* Create semaphore for shared memory segment */
1007 	if((e = window_open_op_alloc_sem(a)) == -1) return(-1);
1008 #else
1009 	e = 0;
1010 #endif
1011 	/* Create image and initialize memory for framebuffer */
1012 	if(window_open_op_alloc_shm(a, w, e) != 0) return(-1);
1013 #if ! defined(PROG_HAS_DRAWPIXELS)
1014 	(void) window_event_op_expose_op(a);
1015 #endif
1016 	return(0);
1017 }
1018 #if defined(PROG_HAS_DRAWPIXELS) && ! defined(PROG_HAS_POSIX_SHM)
window_open_op_alloc_sem(struct a_window * a)1019 static int window_open_op_alloc_sem(struct a_window *a) {
1020 	int b, e, f;
1021 
1022 	key_t k;
1023 
1024 	union w_semun m;
1025 
1026 	(void) memset((void *) &m, 0, sizeof(m));
1027 
1028 	b = 0;
1029 
1030 	if(f_ipc == -1) {
1031 		window_open_op_alloc_sem_again:
1032 
1033 		if(window_get_ipc_key((long *) &k, NULL, 0) != 0) return(-1);
1034 #if defined(SEM_A) && defined(SEM_R)
1035 		f = SEM_R | SEM_A | SEM_R >> 3 | SEM_A >> 3 | SEM_R >> 6 | SEM_A >> 6;
1036 #else
1037 		f = 0666;
1038 #endif
1039 		if((f_ipc = semget(k, 1, f)) == -1) {
1040 			if((f_ipc = semget(k, 1, IPC_CREAT | f)) == -1) {
1041 				LOGWARN(
1042 					ERROR_SLIGHT, SUBSYSTEM,
1043 					_("Failed to create semaphore on display %s"),
1044 					a->n
1045 				);
1046 
1047 				return(-1);
1048 			}
1049 
1050 			m.val = 1;
1051 
1052 			if(semctl(f_ipc, 0, SETVAL, m) == -1) {
1053 				LOGWARN(
1054 					ERROR_SLIGHT, SUBSYSTEM,
1055 					_("Failed to set semaphore 0x%.8x initial value on display %s"),
1056 					f_ipc, a->n
1057 				);
1058 
1059 				return(-1);
1060 			}
1061 		}
1062 
1063 		++b;
1064 	}
1065 
1066 	if((e = semctl(f_ipc, 0, GETVAL)) == -1) {
1067 		if(b == 0) goto window_open_op_alloc_sem_again;
1068 
1069 		LOGWARN(
1070 			ERROR_SLIGHT, SUBSYSTEM,
1071 			_("Failed to get semaphore 0x%.8x value on display %s"),
1072 			f_ipc, a->n
1073 		);
1074 
1075 		return(-1);
1076 	}
1077 
1078 	m.val = ++e;
1079 
1080 	if(semctl(f_ipc, 0, SETVAL, m) == -1) {
1081 		LOGWARN(
1082 			ERROR_SLIGHT, SUBSYSTEM,
1083 			_("Failed to set semaphore 0x%.8x value on display %s"),
1084 			f_ipc, a->n
1085 		);
1086 
1087 		return(-1);
1088 	}
1089 
1090 	return(e);
1091 }
1092 #endif
window_open_op_alloc_shm(struct a_window * a,struct w_ctx * w,int h)1093 static int window_open_op_alloc_shm(struct a_window *a, struct w_ctx *w, int h) {
1094 	Visual *v;
1095 	XVisualInfo o;
1096 #if defined(PROG_HAS_DRAWPIXELS) && ! defined(PROG_HAS_POSIX_SHM)
1097 	char *p;
1098 
1099 	key_t k;
1100 #else
1101 	(void) h;
1102 #endif
1103 	/* Try to get suitable visual */
1104 	if(XMatchVisualInfo(a->d, a->c, 32, TrueColor, &o) == 0) {
1105 		if((v = XDefaultVisual(a->d, a->c)) == NULL) {
1106 			(void) flush_error();
1107 
1108 			LOGWARN(
1109 				ERROR_SLIGHT, SUBSYSTEM,
1110 				_("Failed to get default visual on screen %s.%d"),
1111 				a->n, a->c
1112 			);
1113 
1114 			return(-1);
1115 		}
1116 	}
1117 	else v = o.visual;
1118 
1119 	(void) memset((void *) &a->shm_s, 0, sizeof(a->shm_s));
1120 
1121 	/* Create empty image */
1122 	if((a->shm_i = XShmCreateImage(a->d, v, 32, ZPixmap, NULL, &a->shm_s, w->w, w->h)) == NULL) {
1123 		(void) flush_error();
1124 
1125 		LOGWARN(
1126 			ERROR_SLIGHT, SUBSYSTEM,
1127 			_("Failed to create empty shared memory image on display %s"),
1128 			a->n
1129 		);
1130 
1131 		return(-1);
1132 	}
1133 #if defined(PROG_HAS_DRAWPIXELS)
1134 	/* Allocate shared memory segment for framebuffer image */
1135 #if defined(PROG_HAS_POSIX_SHM)
1136 	/* Filename must be unique in case of two window application, now it is not */
1137 	if((a->shm_s.shmid = shm_open(APPLICATION_EXEC, O_CREAT | O_RDWR,
1138 		S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) == -1) {
1139 		LOGWARN(
1140 			ERROR_SLIGHT, SUBSYSTEM,
1141 			_("Failed to get shared memory segment on display %s"),
1142 			a->n
1143 		);
1144 
1145 		(void) XDestroyImage(a->shm_i);
1146 
1147 		a->shm_i = NULL;
1148 
1149 		return(-1);
1150 	}
1151 
1152 	if(ftruncate(a->shm_s.shmid, (off_t) (w->w * w->h) * sizeof(struct pixel_rgba_8)) != 0) {
1153 		LOGWARN(
1154 			ERROR_SLIGHT, SUBSYSTEM,
1155 			_("Failed to resize shared memory segment on display %s"),
1156 			a->n
1157 		);
1158 
1159 		(void) window_close_dealloc(a, NULL);
1160 
1161 		return(-1);
1162 	}
1163 
1164 	if((a->shm_s.shmaddr = (char *) mmap(NULL, (w->w * w->h) * sizeof(struct pixel_rgba_8),
1165 		PROT_READ | PROT_WRITE, MAP_SHARED, a->shm_s.shmid, 0)) == MAP_FAILED) {
1166 		LOGWARN(
1167 			ERROR_SLIGHT, SUBSYSTEM,
1168 			_("Failed to get shared memory segment address on display %s"),
1169 			a->n
1170 		);
1171 
1172 		a->shm_s.shmaddr = (void *) -1;
1173 
1174 		(void) window_close_dealloc(a, NULL);
1175 
1176 		return(-1);
1177 	}
1178 
1179 	(void) shm_unlink(APPLICATION_EXEC);
1180 
1181 	a->shm_i->data = a->shm_s.shmaddr;
1182 #else
1183 	if((p = window_open_op_alloc_ftok()) == NULL) {
1184 		(void) XDestroyImage(a->shm_i);
1185 
1186 		a->shm_i = NULL;
1187 
1188 		return(-1);
1189 	}
1190 
1191 	if((k = ftok(p, h)) == -1) {
1192 		LOGWARN(
1193 			ERROR_SLIGHT, SUBSYSTEM,
1194 			_("Failed to create IPC identifier for shared memory segment on display %s"),
1195 			a->n
1196 		);
1197 
1198 		(void) free(p);
1199 		(void) XDestroyImage(a->shm_i);
1200 
1201 		a->shm_i = NULL;
1202 
1203 		return(-1);
1204 	}
1205 
1206 	(void) free(p);
1207 
1208 	if((a->shm_s.shmid = shmget(k, (w->w * w->h) * sizeof(struct pixel_rgba_8),
1209 		IPC_CREAT | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) == -1) {
1210 		LOGWARN(
1211 			ERROR_SLIGHT, SUBSYSTEM,
1212 			_("Failed to get shared memory segment on display %s"),
1213 			a->n
1214 		);
1215 
1216 		(void) XDestroyImage(a->shm_i);
1217 
1218 		a->shm_i = NULL;
1219 
1220 		return(-1);
1221 	}
1222 
1223 	a->shm_s.shmaddr = a->shm_i->data = (char *) shmat(a->shm_s.shmid, NULL, 0);
1224 
1225 	if(a->shm_s.shmaddr == (void *) -1) {
1226 		LOGWARN(
1227 			ERROR_SLIGHT, SUBSYSTEM,
1228 			_("Failed to get shared memory segment address on display %s"),
1229 			a->n
1230 		);
1231 
1232 		(void) window_close_dealloc(a, NULL);
1233 
1234 		return(-1);
1235 	}
1236 
1237 	a->shm_s.readOnly = False;
1238 #endif
1239 	(void) memset((void *) a->shm_i->data, 0, (w->w * w->h) * sizeof(struct pixel_rgba_8));
1240 
1241 	if(XShmAttach(a->d, &a->shm_s) == False) {
1242 		(void) flush_error();
1243 
1244 		LOGWARN(
1245 			ERROR_SLIGHT, SUBSYSTEM,
1246 			_("Failed to attach shared memory segment on display %s"),
1247 			a->n
1248 		);
1249 
1250 		(void) window_close_dealloc(a, NULL);
1251 
1252 		return(-1);
1253 	}
1254 #else
1255 	/* Allocate memory segment for framebuffer texture */
1256 	if((a->shm_i->data = malloc((w->w * w->h) * sizeof(struct pixel_rgba_8))) == NULL) {
1257 		LOGWARN(
1258 			ERROR_SLIGHT, SUBSYSTEM,
1259 			_("Failed to allocate %lu bytes of memory"),
1260 			(unsigned long) ((w->w * w->h) * sizeof(struct pixel_rgba_8))
1261 		);
1262 
1263 		(void) window_close_dealloc(a, NULL);
1264 
1265 		return(-1);
1266 	}
1267 
1268 	(void) memset((void *) a->shm_i->data, 0, (w->w * w->h) * sizeof(struct pixel_rgba_8));
1269 #endif
1270 	return(0);
1271 }
1272 #if defined(PROG_HAS_DRAWPIXELS) && ! defined(PROG_HAS_POSIX_SHM)
window_open_op_alloc_ftok(void)1273 static char *window_open_op_alloc_ftok(void) {
1274 	char *o, *p, *q;
1275 
1276 	size_t u;
1277 
1278 	struct stat a;
1279 
1280 	/* First check if static installation path works */
1281 	if(stat(DIR_PLACE_BIN, &a) == 0) return(str_dup((const char *) DIR_PLACE_BIN, STRING_ASCII));
1282 #if defined(__sun__) && defined(HAVE_GETEXECNAME)
1283 	if((q = (char *) getexecname()) == NULL) {
1284 		if((q = main_exec()) == NULL) {
1285 			(void) flush_error();
1286 
1287 			LOGWARN(
1288 				ERROR_SLIGHT, SUBSYSTEM,
1289 				_("Failed to figure out application runtime path")
1290 			);
1291 
1292 			return(NULL);
1293 		}
1294 	}
1295 #else
1296 	if((q = main_exec()) == NULL) {
1297 		(void) flush_error();
1298 
1299 		LOGWARN(
1300 			ERROR_SLIGHT, SUBSYSTEM,
1301 			_("Failed to figure out application runtime path")
1302 		);
1303 
1304 		return(NULL);
1305 	}
1306 #endif
1307 	u = str_len(q, STRING_ASCII) + (sizeof(char) * 8);
1308 
1309 	APP_MALLOC_RET_VALUE(p, u, NULL);
1310 
1311 	if(q[0] == CONFIG_PATH_DELIM) {
1312 		/* Path is absolute, no tricks needed */
1313 		(void) snprintf(p, u, "%s", q);
1314 	}
1315 	else {
1316 		/* Path is relative, try to find base directory */
1317 		if((o = window_open_op_alloc_ftok_rel(p, q, u)) == NULL) {
1318 			(void) free(p);
1319 
1320 			return(NULL);
1321 		}
1322 
1323 		p = o;
1324 	}
1325 
1326 	/* Check that file actually exists */
1327 	if(stat((const char *) p, &a) != 0) {
1328 		LOGWARN(
1329 			ERROR_SLIGHT, SUBSYSTEM,
1330 			_("Failed to stat application runtime path '%s'"),
1331 			p
1332 		);
1333 
1334 		(void) free(p);
1335 
1336 		return(NULL);
1337 	}
1338 
1339 	return(p);
1340 }
1341 
window_open_op_alloc_ftok_rel(char * p,char * q,size_t u)1342 static char *window_open_op_alloc_ftok_rel(char *p, char *q, size_t u) {
1343 	int e;
1344 
1345 	char *o, *r;
1346 
1347 	size_t t;
1348 
1349 	r = p;
1350 	t = CONFIG_PATH_LENGTH;
1351 
1352 	while(1) {
1353 		if(t >= CONFIG_PATH_LENGTH * CONFIG_PATH_LENGTH) return(NULL);
1354 
1355 		APP_REALLOC_RET_VALUE(o, r, t + u, NULL);
1356 
1357 		if(getcwd(r, t) == NULL) {
1358 			(void) get_error(&e);
1359 
1360 			/* In case of range error, allocate some more memory and try again */
1361 			if(e == ERANGE) t += CONFIG_PATH_LENGTH;
1362 			else {
1363 				LOGWARN(
1364 					ERROR_SLIGHT, SUBSYSTEM,
1365 					_("Failed to get current working directory")
1366 				);
1367 
1368 				return(NULL);
1369 			}
1370 		}
1371 		else break;
1372 	}
1373 
1374 	/* For some dumb reason linux prefixes path with (unreachable) if path cannot be accessed */
1375 	if(r[0] != CONFIG_PATH_DELIM) {
1376 		(void) flush_error();
1377 
1378 		LOGWARN(
1379 			ERROR_SLIGHT, SUBSYSTEM,
1380 			_("Failed to get current working directory")
1381 		);
1382 
1383 		return(NULL);
1384 	}
1385 
1386 	u = str_len(r, STRING_ASCII);
1387 
1388 	(void) snprintf(r + u, t - u, "%c%s", CONFIG_PATH_DELIM, q);
1389 
1390 	return(r);
1391 }
1392 #endif
window_open_op_thread(struct a_window * a)1393 static int window_open_op_thread(struct a_window *a) {
1394 	APP_MALLOC_RET_VALUE(a->x, sizeof(struct t_ctx), -1);
1395 
1396 	a->x->pr = THREAD_STATE_RUN;
1397 	a->x->tr = THREAD_STATE_BORN;
1398 
1399 	if(thread_init(a->x, worker_cb, a->x) != 0) {
1400 		(void) free(a->x);
1401 
1402 		return(-1);
1403 	}
1404 
1405 	return(0);
1406 }
1407 
window_open_op_thread_wait(struct a_window * a)1408 static void window_open_op_thread_wait(struct a_window *a) {
1409 	unsigned int i;
1410 
1411 	i = 0;
1412 
1413 	while(a->x->tr != THREAD_STATE_RUN && a->x->tr != THREAD_STATE_IDLE && a->x->tr != THREAD_STATE_STOP) {
1414 		if(i > 10000) {
1415 			(void) flush_error();
1416 
1417 			LOGWARN(
1418 				ERROR_FATAL, SUBSYSTEM,
1419 				_("Failed to start callback thread for window %lu on display %s"),
1420 				(unsigned long) a->w, a->n
1421 			);
1422 
1423 			return;
1424 		}
1425 
1426 		if(++i % 1000 == 0) {
1427 			(void) flush_error();
1428 
1429 			LOGWARN(
1430 				ERROR_NOERROR, SUBSYSTEM,
1431 				_("Waiting for window %lu callback thread to start taking too long on display %s, still waiting (%u/%u)"),
1432 				(unsigned long) a->w, a->n, (i + 1) / 1000, 10000 / 1000
1433 			);
1434 		}
1435 
1436 		(void) timer_wait(0, TIMER_RESOLUTION_THREADAGAIN);
1437 	}
1438 }
1439 
window_open_op_par(char * s)1440 static char *window_open_op_par(char *s) {
1441 	char *r;
1442 
1443 	size_t t;
1444 
1445 	if(s == NULL) return(NULL);
1446 
1447 	t = str_len(s, STRING_ASCII);
1448 
1449 	APP_MALLOC_RET_VALUE(r, t + sizeof(char), NULL);
1450 
1451 	(void) memcpy((void *) r, (const void *) s, t);
1452 
1453 	r[t] = 0;
1454 
1455 	return(r);
1456 }
1457 
window_open_op_visual(struct a_window * a)1458 static XVisualInfo *window_open_op_visual(struct a_window *a) {
1459 	unsigned int *b, e;
1460 
1461 	XVisualInfo *r;
1462 
1463 	if(glXQueryExtension(a->d, &a->gl_e, &a->gl_v) == False) {
1464 		(void) flush_error();
1465 
1466 		LOGWARN(
1467 			ERROR_SLIGHT, SUBSYSTEM,
1468 			_("Failed to query GLX extension on display %s"),
1469 			a->n
1470 		);
1471 
1472 		return(NULL);
1473 	}
1474 
1475 	if(glXQueryVersion(a->d, &a->gl_m, &a->gl_i) == False) {
1476 		(void) flush_error();
1477 
1478 		LOGWARN(
1479 			ERROR_SLIGHT, SUBSYSTEM,
1480 			_("Failed to query GLX version on display %s"),
1481 			a->n
1482 		);
1483 
1484 		return(NULL);
1485 	}
1486 
1487 	if((r = window_open_op_visual_at(a)) == NULL) {
1488 		if((b = (unsigned int *) conf_fetch("bpc")) == NULL) {
1489 			e = 8;
1490 		}
1491 		else {
1492 			e = *b;
1493 		}
1494 
1495 		switch(e) {
1496 			case 8:
1497 				if((r = window_open_op_visual_gl(a, w_gl_buffers_8)) == NULL) return(NULL);
1498 
1499 				break;
1500 			case 10:
1501 				if((r = window_open_op_visual_gl(a, w_gl_buffers_10)) == NULL) return(NULL);
1502 
1503 				break;
1504 			default:
1505 				(void) flush_error();
1506 
1507 				LOGWARN(
1508 					ERROR_SLIGHT, SUBSYSTEM,
1509 					_("Failed to choose %d bits per component on screen %s.%d, only 8 or 10 is supported"),
1510 					e, a->n, a->c
1511 				);
1512 
1513 				return(NULL);
1514 		}
1515 	}
1516 
1517 	if((a->gl_c = glXCreateContext(a->d, r, NULL, GL_TRUE)) == NULL) {
1518 		/* If direct rendering context fails, try not to use direct rendering */
1519 		if((a->gl_c = glXCreateContext(a->d, r, NULL, GL_FALSE)) == NULL) {
1520 			(void) flush_error();
1521 
1522 			LOGWARN(
1523 				ERROR_SLIGHT, SUBSYSTEM,
1524 				_("Failed to create GLX context on display %s"),
1525 				a->n
1526 			);
1527 
1528 			(void) window_open_op_visual_free(r);
1529 
1530 			return(NULL);
1531 		}
1532 	}
1533 
1534 	return(r);
1535 }
1536 
window_open_op_visual_at(struct a_window * a)1537 static XVisualInfo *window_open_op_visual_at(struct a_window *a) {
1538 	int i, *b;
1539 
1540 	XVisualInfo v;
1541 	XVisualInfo *r;
1542 
1543 	if((b = (int *) conf_fetch("visual")) == NULL) return(NULL);
1544 
1545 	(void) memset((void *) &v, 0, sizeof(v));
1546 
1547 	v.screen = a->c;
1548 	v.visualid = (VisualID) *b;
1549 
1550 	if((r = XGetVisualInfo(a->d, VisualIDMask | VisualScreenMask, &v, &i)) == NULL) {
1551 		(void) flush_error();
1552 
1553 		LOGWARN(
1554 			ERROR_NOERROR, SUBSYSTEM,
1555 			_("Failed to choose visual %d (0x%x) on display %s, trying server default instead"),
1556 			*b, *b, a->n
1557 		);
1558 
1559 		return(NULL);
1560 	}
1561 
1562 	return(r);
1563 }
1564 
window_open_op_visual_gl(struct a_window * a,const int ** w)1565 static XVisualInfo *window_open_op_visual_gl(struct a_window *a, const int **w) {
1566 	int i;
1567 
1568 	XVisualInfo v;
1569 	XVisualInfo *r;
1570 
1571 	for(i = 0; ; i++) {
1572 		if(w[i] == NULL) break;
1573 
1574 		if((r = glXChooseVisual(a->d, a->c, (int *) w[i])) != NULL) return(r);
1575 	}
1576 
1577 	/* If visuals failed, try handmade visual */
1578 	(void) flush_error();
1579 
1580 	LOGWARN(
1581 		ERROR_NOERROR, SUBSYSTEM,
1582 		_("Failed to choose any of the GLX visuals on display %s, trying handmade visual"),
1583 		a->n
1584 	);
1585 
1586 	(void) memset((void *) &v, 0, sizeof(v));
1587 
1588 	/* Try to get visual that has 8 bits per color component */
1589 	v.bits_per_rgb = 8;
1590 	v.screen = a->c;
1591 
1592 	if((r = XGetVisualInfo(a->d, VisualBitsPerRGBMask | VisualScreenMask, &v, &i)) != NULL) {
1593 		if(i <= 0) {
1594 			(void) window_open_op_visual_free(r);
1595 
1596 			r = NULL;
1597 		}
1598 	}
1599 
1600 	/* If this also fails, fallback to screen default visual */
1601 	if(r == NULL) {
1602 		(void) flush_error();
1603 
1604 		LOGWARN(
1605 			ERROR_NOERROR, SUBSYSTEM,
1606 			_("Failed to choose handmade visual on display %s, trying default visual"),
1607 			a->n
1608 		);
1609 
1610 		(void) memset((void *) &v, 0, sizeof(v));
1611 
1612 		v.depth = a->t->b.depth;
1613 		v.screen = a->c;
1614 
1615 		if((r = XGetVisualInfo(a->d, VisualDepthMask | VisualScreenMask, &v, &i)) != NULL) {
1616 			if(i <= 0) {
1617 				(void) flush_error();
1618 
1619 				LOGWARN(
1620 					ERROR_SLIGHT, SUBSYSTEM,
1621 					_("Failed to choose proper visual on display %s"),
1622 					a->n
1623 				);
1624 
1625 				(void) window_open_op_visual_free(r);
1626 
1627 				return(NULL);
1628 			}
1629 		}
1630 		else {
1631 			(void) flush_error();
1632 
1633 			LOGWARN(
1634 				ERROR_SLIGHT, SUBSYSTEM,
1635 				_("Failed to choose suitable visual on display %s"),
1636 				a->n
1637 			);
1638 
1639 			return(NULL);
1640 		}
1641 	}
1642 
1643 	return(r);
1644 }
1645 
window_open_op_visual_free(XVisualInfo * v)1646 static void window_open_op_visual_free(XVisualInfo *v) {
1647 	(void) XFree((void *) v);
1648 }
1649 
window_close(unsigned int w)1650 static void window_close(unsigned int w) {
1651 	struct a_window *a;
1652 
1653 	if((a = window_get_struct_by_handle(w)) == NULL) return;
1654 
1655 	a->s = WINDOW_STATE_UNMAPPED;
1656 
1657 	(void) XLockDisplay(a->d);
1658 
1659 	/* Unmap and destroy window only if this window is not subwindow as parent destroys it */
1660 	if(a->h == 0) (void) XUnmapWindow(a->d, a->w);
1661 
1662 	(void) window_close_dealloc(a, a->d);
1663 #if defined(PROG_HAS_DRAWPIXELS) && ! defined(PROG_HAS_POSIX_SHM)
1664 	(void) window_close_dealloc_sem(a);
1665 #endif
1666 	if(a->h == 0) (void) XDestroyWindow(a->d, a->w);
1667 
1668 	(void) XUnlockDisplay(a->d);
1669 
1670 	/* Check if this window was the keeper of save yourself atom */
1671 	if((a->y & 0x1) == 0x1) s_sel = IS_NO;
1672 
1673 	/* Free all allocated stuff */
1674 	(void) window_close_icon(w);
1675 	(void) window_close_thread(a);
1676 	(void) window_close_op(a);
1677 	(void) window_close_free(w);
1678 }
1679 
window_close_op(struct a_window * a)1680 static void window_close_op(struct a_window *a) {
1681 	if(a->par_main_loop.s != NULL) (void) free(a->par_main_loop.s);
1682 
1683 	if(a->par_expose.s != NULL) (void) free(a->par_expose.s);
1684 
1685 	if(a->par_key_press.s != NULL) (void) free(a->par_key_press.s);
1686 	if(a->par_key_release.s != NULL) (void) free(a->par_key_release.s);
1687 	if(a->par_button_press.s != NULL) (void) free(a->par_button_press.s);
1688 	if(a->par_button_release.s != NULL) (void) free(a->par_button_release.s);
1689 
1690 	if(a->par_client_message.s != NULL) (void) free(a->par_client_message.s);
1691 
1692 	if(a->par_configure_notify.s != NULL) (void) free(a->par_configure_notify.s);
1693 	if(a->par_destroy_notify.s != NULL) (void) free(a->par_destroy_notify.s);
1694 	if(a->par_motion_notify.s != NULL) (void) free(a->par_motion_notify.s);
1695 	if(a->par_map_notify.s != NULL) (void) free(a->par_map_notify.s);
1696 	if(a->par_unmap_notify.s != NULL) (void) free(a->par_unmap_notify.s);
1697 
1698 	if(a->par_open_notify.s != NULL) (void) free(a->par_open_notify.s);
1699 }
1700 
window_close_dealloc(struct a_window * a,Display * d)1701 static void window_close_dealloc(struct a_window *a, Display *d) {
1702 	unsigned int i;
1703 
1704 	if(d != NULL) {
1705 		/* Restore default cursor only if this window is not subwindow */
1706 		if(a->h == 0) (void) XUndefineCursor(d, a->w);
1707 
1708 		for(i = 0; i < WINDOW_CURSORS; i++) (void) XFreeCursor(d, a->o[i]);
1709 
1710 		if(a->gl_c != NULL) {
1711 #if ! defined(PROG_HAS_DRAWPIXELS)
1712 			if(glXMakeCurrent(a->d, a->w, a->gl_c) != False) {
1713 				(void) glDeleteTextures(1, &a->gl_t);
1714 			}
1715 #endif
1716 			(void) glXMakeCurrent(d, None, NULL);
1717 			(void) glXDestroyContext(d, a->gl_c);
1718 		}
1719 #if defined(PROG_HAS_DRAWPIXELS)
1720 		if(a->shm_s.shmid != -1) (void) XShmDetach(d, &a->shm_s);
1721 #endif
1722 	}
1723 
1724 	if(a->shm_i != NULL) {
1725 #if ! defined(PROG_HAS_DRAWPIXELS)
1726 		if(a->shm_i->data != NULL) (void) free(a->shm_i->data);
1727 #endif
1728 		(void) XDestroyImage(a->shm_i);
1729 
1730 		a->shm_i = NULL;
1731 	}
1732 #if defined(PROG_HAS_DRAWPIXELS)
1733 	/* Free shared memory segment */
1734 	if(a->shm_s.shmid != -1) {
1735 #if defined(PROG_HAS_POSIX_SHM)
1736 		(void) shm_unlink(APPLICATION_EXEC);
1737 #else
1738 		(void) shmctl(a->shm_s.shmid, IPC_RMID, NULL);
1739 #endif
1740 		a->shm_s.shmid = -1;
1741 	}
1742 
1743 	if(a->shm_s.shmaddr != (void *) -1) {
1744 #if defined(PROG_HAS_POSIX_SHM)
1745 		(void) munmap((void *) a->shm_s.shmaddr, (a->w_x->w * a->w_x->h) * sizeof(struct pixel_rgba_8));
1746 #else
1747 		(void) shmdt((const void *) a->shm_s.shmaddr);
1748 #endif
1749 		a->shm_s.shmaddr = (void *) -1;
1750 	}
1751 #endif
1752 	/* Free possible menu and widget stacks */
1753 #if ! defined(PROG_DISABLE_MENU)
1754 	(void) menu_free_stack_by_id(a->w_gui.id);
1755 #endif
1756 #if ! defined(PROG_DISABLE_WIDGET)
1757 	(void) widget_free_stack(&a->w_gui);
1758 #endif
1759 }
1760 #if defined(PROG_HAS_DRAWPIXELS) && ! defined(PROG_HAS_POSIX_SHM)
window_close_dealloc_sem(struct a_window * a)1761 static void window_close_dealloc_sem(struct a_window *a) {
1762 	int e;
1763 
1764 	union w_semun m;
1765 
1766 	if(f_ipc == -1) return;
1767 
1768 	if((e = semctl(f_ipc, 0, GETVAL)) == -1) {
1769 		LOGWARN(
1770 			ERROR_SLIGHT, SUBSYSTEM,
1771 			_("Failed to get semaphore 0x%.8x value on display %s"),
1772 			f_ipc, a->n
1773 		);
1774 
1775 		return;
1776 	}
1777 
1778 	/* Decrement semaphore and delete it if its value goes to zero */
1779 	(void) memset((void *) &m, 0, sizeof(m));
1780 
1781 	if((m.val = --e) <= 1) {
1782 		if((semctl(f_ipc, 0, IPC_RMID)) == -1) {
1783 			LOGWARN(
1784 				ERROR_SLIGHT, SUBSYSTEM,
1785 				_("Failed to remove semaphore 0x%.8x on display %s"),
1786 				f_ipc, a->n
1787 			);
1788 
1789 			return;
1790 		}
1791 
1792 		f_ipc = -1;
1793 	}
1794 	else {
1795 		if(semctl(f_ipc, 0, SETVAL, m) == -1) {
1796 			LOGWARN(
1797 				ERROR_SLIGHT, SUBSYSTEM,
1798 				_("Failed to set semaphore 0x%.8x value on display %s"),
1799 				f_ipc, a->n
1800 			);
1801 
1802 			return;
1803 		}
1804 	}
1805 }
1806 #endif
window_close_icon(unsigned int h)1807 static void window_close_icon(unsigned int h) {
1808 	struct a_window *a;
1809 
1810 	if((a = window_get_struct_by_handle(h)) == NULL) return;
1811 
1812 	if(a->a_i.c != IS_YES) return;
1813 
1814 	(void) XLockDisplay(a->d);
1815 	(void) XFreePixmap(a->d, a->a_i.p_d);
1816 	(void) XFreePixmap(a->d, a->a_i.p_m);
1817 	(void) XDestroyImage(a->a_i.m_d);
1818 	(void) XDestroyImage(a->a_i.m_m);
1819 	(void) XFreeGC(a->d, a->a_i.g);
1820 	(void) XUnlockDisplay(a->d);
1821 
1822 	a->a_i.c = IS_NO;
1823 }
1824 
window_close_thread(struct a_window * a)1825 static void window_close_thread(struct a_window *a) {
1826 	if(thread_kill(a->x) == 0) (void) window_close_thread_wait(a);
1827 
1828 	(void) free(a->x);
1829 }
1830 
window_close_thread_wait(struct a_window * a)1831 static void window_close_thread_wait(struct a_window *a) {
1832 	unsigned long j;
1833 
1834 	j = 0;
1835 
1836 	while(1) {
1837 		if(a->x->tr == THREAD_STATE_STOP) break;
1838 
1839 		if(++j >= 10000) break;
1840 
1841 		(void) timer_wait(0, TIMER_RESOLUTION_THREADAGAIN);
1842 	}
1843 }
1844 
window_close_free(unsigned int w)1845 static void window_close_free(unsigned int w) {
1846 	unsigned int i, p;
1847 
1848 	/* Get rid of permanent commands for this window */
1849 	for(i = 0, p = 0; i < c_evt; i++) {
1850 		if(w_evt[0][i].c == WINDOW_COMMAND_NONE) continue;
1851 
1852 		if(w_evt[0][i].e == IS_YES) {
1853 			if(w_evt[0][i].h == a_win[w - 1]->a) {
1854 				if(w_evt[0][i].p != NULL) (void) free(w_evt[0][i].p);
1855 
1856 				(void) window_cmd_push_clear(0, i);
1857 			}
1858 			else ++p;
1859 		}
1860 	}
1861 
1862 	/* Stop continuous command processing if needed */
1863 	if(p == 0) c_pnd = IS_YES;
1864 
1865 	(void) free(a_win[w - 1]);
1866 
1867 	a_win[w - 1] = NULL;
1868 }
1869 
window_close_all(void)1870 static void window_close_all(void) {
1871 	unsigned int i;
1872 
1873 	if(a_win != NULL) {
1874 		for(i = 0; i < c_win; i++) (void) window_close(i + 1);
1875 
1876 		(void) free(a_win);
1877 
1878 		a_win = NULL;
1879 	}
1880 
1881 	c_win = 0;
1882 }
1883 
window_icon(unsigned int h,char * s)1884 static void window_icon(unsigned int h, char *s) {
1885 	unsigned int i, j, k;
1886 	unsigned int s_r, s_g, s_b;
1887 	unsigned long p;
1888 
1889 	size_t t;
1890 
1891 	struct a_window *a;
1892 	struct t_img *r;
1893 
1894 	Visual *v;
1895 	XGCValues g;
1896 	XWMHints n;
1897 
1898 	if((a = window_get_struct_by_handle(h)) == NULL) return;
1899 	if((r = image_read(s, 0)) == NULL) return;
1900 
1901 	(void) window_close_icon(h);
1902 
1903 	if(a->a_i.b_d != NULL) (void) free(a->a_i.b_d);
1904 	if(a->a_i.b_m != NULL) (void) free(a->a_i.b_m);
1905 
1906 	a->a_i.w = (unsigned int) r->w;
1907 	a->a_i.h = (unsigned int) r->h;
1908 
1909 	(void) XLockDisplay(a->d);
1910 
1911 	if((v = XDefaultVisual(a->d, a->c)) == NULL) {
1912 		(void) flush_error();
1913 
1914 		LOGWARN(
1915 			ERROR_SLIGHT, SUBSYSTEM,
1916 			_("Failed to get default visual for screen %s.%d"),
1917 			a->n, a->c
1918 		);
1919 
1920 		(void) XUnlockDisplay(a->d);
1921 
1922 		return;
1923 	}
1924 
1925 	/* Allocate image data and mask buffers */
1926 	s_r = window_icon_op((unsigned long) v->red_mask);
1927 	s_g = window_icon_op((unsigned long) v->green_mask);
1928 	s_b = window_icon_op((unsigned long) v->blue_mask);
1929 
1930 	t = (a->a_i.w * a->a_i.h) * sizeof(struct pixel_rgba_8);
1931 
1932 	if((a->a_i.b_d = malloc(t)) == NULL) {
1933 		LOGWARN(
1934 			ERROR_SLIGHT, SUBSYSTEM,
1935 			_("Failed to allocate %lu bytes of memory"),
1936 			(unsigned long) t
1937 		);
1938 
1939 		(void) XUnlockDisplay(a->d);
1940 
1941 		return;
1942 	}
1943 
1944 	if((a->a_i.b_m = malloc(t)) == NULL) {
1945 		LOGWARN(
1946 			ERROR_SLIGHT, SUBSYSTEM,
1947 			_("Failed to allocate %lu bytes of memory"),
1948 			(unsigned long) t
1949 		);
1950 
1951 		(void) XUnlockDisplay(a->d);
1952 
1953 		(void) free(a->a_i.b_d);
1954 
1955 		a->a_i.b_d = NULL;
1956 
1957 		return;
1958 	}
1959 
1960 	/* Copy image data to image and mask buffers */
1961 	for(i = 0; i < a->a_i.h; i++) {
1962 		k = i * a->a_i.w;
1963 
1964 		for(j = 0; j < a->a_i.w; j++) {
1965 			p = 0;
1966 			p |= (uint32_t) (r->p[k + j].pixel.r << s_r);
1967 			p |= (uint32_t) (r->p[k + j].pixel.g << s_g);
1968 			p |= (uint32_t) (r->p[k + j].pixel.b << s_b);
1969 
1970 			a->a_i.b_d[k + j].pixel.p = (uint32_t) p;
1971 
1972 			p = 0;
1973 			p |= (uint32_t) (r->p[k + j].pixel.a << s_r);
1974 			p |= (uint32_t) (r->p[k + j].pixel.a << s_g);
1975 			p |= (uint32_t) (r->p[k + j].pixel.a << s_b);
1976 
1977 			a->a_i.b_m[k + j].pixel.p = (uint32_t) p;
1978 		}
1979 	}
1980 
1981 	(void) image_free(r);
1982 
1983 	/* Put images to pixmaps */
1984 	(void) memset((void *) &g, 0, sizeof(g));
1985 
1986 	a->a_i.g = XCreateGC(a->d, a->r, 0, &g);
1987 
1988 	a->a_i.m_d = XCreateImage(a->d, v, a->b.depth, ZPixmap, 0, (char *) a->a_i.b_d, a->a_i.w, a->a_i.h, 32, 0);
1989 	a->a_i.m_m = XCreateImage(a->d, v, a->b.depth, ZPixmap, 0, (char *) a->a_i.b_m, a->a_i.w, a->a_i.h, 32, 0);
1990 	a->a_i.p_d = XCreatePixmap(a->d, a->r, a->a_i.w, a->a_i.h, a->b.depth);
1991 	a->a_i.p_m = XCreatePixmap(a->d, a->r, a->a_i.w, a->a_i.h, a->b.depth);
1992 
1993 	(void) XPutImage(a->d, a->a_i.p_d, a->a_i.g, a->a_i.m_d, 0, 0, 0, 0, a->a_i.w, a->a_i.h);
1994 	(void) XPutImage(a->d, a->a_i.p_m, a->a_i.g, a->a_i.m_m, 0, 0, 0, 0, a->a_i.w, a->a_i.h);
1995 
1996 	/* Notify window manager that we now have an icon */
1997 	(void) memset((void *) &n, 0, sizeof(n));
1998 
1999 	n.flags = IconPixmapHint | IconMaskHint;
2000 	n.icon_pixmap = a->a_i.p_d;
2001 	n.icon_mask = a->a_i.p_m;
2002 
2003 	(void) XSetWMHints(a->d, a->w, &n);
2004 	(void) XUnlockDisplay(a->d);
2005 
2006 	a->a_i.c = IS_YES;
2007 }
2008 
window_icon_op(unsigned long c)2009 static unsigned int window_icon_op(unsigned long c) {
2010 	unsigned int i;
2011 
2012 	for(i = 0; i < 4; i++) {
2013 		if((c & 0xff) != 0) return(i * 8);
2014 
2015 		c >>= 8;
2016 	}
2017 
2018 	return(0);
2019 }
2020 
window_event(struct t_str * tp)2021 static void window_event(struct t_str *tp) {
2022 	int i, j;
2023 	unsigned int k, n;
2024 
2025 	fd_set f;
2026 
2027 	XEvent e;
2028 
2029 	struct timeval tv;
2030 	struct a_window *a;
2031 
2032 	struct a_window *b[10];
2033 
2034 	(void) XLockDisplay(tp->d);
2035 	(void) XFlush(tp->d);
2036 
2037 	if((i = XEventsQueued(tp->d, QueuedAlready)) == 0) {
2038 		tv.tv_sec = 0;
2039 		tv.tv_usec = 0;
2040 
2041 		j = ConnectionNumber(tp->d);
2042 
2043 		FD_ZERO(&f);
2044 		FD_SET(j, &f);
2045 
2046 		if(select(j + 1, &f, NULL, NULL, &tv) == 1) {
2047 			if((i = XPending(tp->d)) == 0) {
2048 				(void) XUnlockDisplay(tp->d);
2049 
2050 				return;
2051 			}
2052 		}
2053 	}
2054 
2055 	(void) memset((void *) &e, 0, sizeof(e));
2056 
2057 	k = 0;
2058 
2059 	while(i-- > 0) {
2060 		(void) XNextEvent(tp->d, &e);
2061 
2062 		if((a = window_get_struct_by_window(e.xany.window)) == NULL) continue;
2063 
2064 		(void) window_event_op(a, &e);
2065 
2066 		/* Wake up window thread to run its callback functions now if needed */
2067 		if(k == 10) {
2068 			(void) XUnlockDisplay(tp->d);
2069 
2070 			for(n = 0; n < k; n++) (void) thread_wake(b[n]->x);
2071 
2072 			k = 0;
2073 
2074 			(void) XLockDisplay(tp->d);
2075 		}
2076 
2077 		b[k++] = a;
2078 	}
2079 
2080 	(void) XUnlockDisplay(tp->d);
2081 
2082 	/* Wake up window thread to run its callback functions */
2083 	for(n = 0; n < k; n++) (void) thread_wake(b[n]->x);
2084 }
2085 
window_event_op(struct a_window * a,XEvent * e)2086 static void window_event_op(struct a_window *a, XEvent *e) {
2087 	switch(e->type) {
2088 		case Expose:
2089 			(void) window_event_op_expose(a, e);
2090 
2091 			break;
2092 		case KeyPress:
2093 			(void) window_event_op_keypress(a, e);
2094 
2095 			break;
2096 		case KeyRelease:
2097 			(void) window_event_op_keyrelease(a, e);
2098 
2099 			break;
2100 		case ButtonPress:
2101 			(void) window_event_op_buttonpress(a, e);
2102 
2103 			break;
2104 		case ButtonRelease:
2105 			(void) window_event_op_buttonrelease(a, e);
2106 
2107 			break;
2108 		case MotionNotify:
2109 			(void) window_event_op_motionnotify(a, e);
2110 
2111 			break;
2112 		case ConfigureNotify:
2113 			(void) window_event_op_configurenotify(a, e);
2114 
2115 			break;
2116 		case DestroyNotify:
2117 			(void) window_event_op_destroynotify(a);
2118 
2119 			break;
2120 		case MapNotify:
2121 			(void) window_event_op_mapnotify(a);
2122 
2123 			break;
2124 		case UnmapNotify:
2125 			(void) window_event_op_unmapnotify(a);
2126 
2127 			break;
2128 		case EnterNotify:
2129 			break;
2130 		case LeaveNotify:
2131 			break;
2132 		case FocusIn:
2133 			break;
2134 		case FocusOut:
2135 			break;
2136 		case ResizeRequest:
2137 			break;
2138 		case ClientMessage:
2139 			(void) window_event_op_clientmessage(a, e);
2140 
2141 			break;
2142 		default:
2143 			break;
2144 	}
2145 }
2146 
window_event_op_expose(struct a_window * a,XEvent * e)2147 static void window_event_op_expose(struct a_window *a, XEvent *e) {
2148 	char *p;
2149 #if defined(PROG_HAS_DRAWPIXELS)
2150 	double x, y;
2151 #endif
2152 	GLenum g;
2153 
2154 	a->q = IS_NO;
2155 
2156 	/* Active windows are refreshed by its own expose event */
2157 	if(e->xany.send_event == False && a->m != 0) return;
2158 
2159 	if(glXMakeCurrent(a->d, a->w, a->gl_c) != False) {
2160 		p = a->shm_i->data + ((e->xexpose.y * a->b.width) + e->xexpose.x) * sizeof(struct pixel_rgba_8);
2161 #if defined(PROG_HAS_DRAWPIXELS)
2162 		x = maths_map(e->xexpose.x, 0.0, a->b.width, -1.0, 1.0);
2163 		y = maths_map(e->xexpose.y, 0.0, a->b.height, 1.0, -1.0);
2164 
2165 		(void) glPixelStorei(GL_UNPACK_ALIGNMENT, sizeof(struct pixel_rgba_8));
2166 		(void) glPixelStorei(GL_UNPACK_ROW_LENGTH, a->b.width);
2167 		(void) glPixelZoom(1.0, -1.0);
2168 		(void) glRasterPos2d((GLdouble) x, (GLdouble) y);
2169 		(void) glDrawPixels((GLsizei) e->xexpose.width, (GLsizei) e->xexpose.height,
2170 			GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, (const GLvoid *) p);
2171 #else
2172 		(void) glBindTexture(GL_TEXTURE_2D, a->gl_t);
2173 
2174 		(void) glPixelStorei(GL_UNPACK_ALIGNMENT, sizeof(struct pixel_rgba_8));
2175 		(void) glPixelStorei(GL_UNPACK_ROW_LENGTH, a->b.width);
2176 		(void) glTexSubImage2D(GL_TEXTURE_2D, 0, (GLint) e->xexpose.x, (GLint) e->xexpose.y,
2177 			(GLsizei) e->xexpose.width, (GLsizei) e->xexpose.height,
2178 			GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, (const GLvoid *) p);
2179 
2180 		(void) glEnable(GL_TEXTURE_2D);
2181 		(void) glBegin(GL_QUADS);
2182 
2183 		(void) glTexCoord2i(0, 1);
2184 		(void) glVertex3d(-1.0, -1.0, 0.0);
2185 		(void) glTexCoord2i(1, 1);
2186 		(void) glVertex3d(1.0, -1.0, 0.0);
2187 		(void) glTexCoord2i(1, 0);
2188 		(void) glVertex3d(1.0, 1.0, 0.0);
2189 		(void) glTexCoord2i(0, 0);
2190 		(void) glVertex3d(-1.0, 1.0, 0.0);
2191 
2192 		(void) glEnd();
2193 		(void) glDisable(GL_TEXTURE_2D);
2194 #endif
2195 		(void) glXSwapBuffers(a->d, a->w);
2196 
2197 		(void) callback_event_add(a->x, a->cb_expose, &a->cb_p, &a->par_expose);
2198 
2199 		while((g = glGetError()) != GL_NO_ERROR) {
2200 			(void) window_event_op_expose_er(a, g);
2201 		}
2202 	}
2203 }
2204 #if ! defined(PROG_HAS_DRAWPIXELS)
window_event_op_expose_op(struct a_window * a)2205 static void window_event_op_expose_op(struct a_window *a) {
2206 	if(glXMakeCurrent(a->d, a->w, a->gl_c) != False) {
2207 		(void) glGenTextures(1, &a->gl_t);
2208 		(void) glBindTexture(GL_TEXTURE_2D, a->gl_t);
2209 
2210 		(void) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
2211 		(void) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
2212 		(void) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2213 		(void) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2214 
2215 		(void) glPixelStorei(GL_UNPACK_ALIGNMENT, sizeof(struct pixel_rgba_8));
2216 		(void) glPixelStorei(GL_UNPACK_ROW_LENGTH, a->b.width);
2217 		(void) glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, (GLsizei) a->b.width, (GLsizei) a->b.height,
2218 			0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, (const GLvoid *) a->shm_i->data);
2219 	}
2220 
2221 	while(glGetError() != GL_NO_ERROR) {}
2222 }
2223 #endif
window_event_op_expose_er(struct a_window * a,GLenum g)2224 static void window_event_op_expose_er(struct a_window *a, GLenum g) {
2225 	LOGWARN(
2226 		ERROR_SLIGHT, SUBSYSTEM,
2227 		_("OpenGL error code 0x%.8x (%d) occurred on screen %s.%d"),
2228 		(int) g, (int) g, a->n, (int) a->c
2229 	);
2230 }
window_event_op_keypress(struct a_window * a,XEvent * e)2231 static void window_event_op_keypress(struct a_window *a, XEvent *e) {
2232 #if ! defined(PROG_DISABLE_WIDGET)
2233 	struct w_info *w;
2234 #endif
2235 	/* Maybe menu system like to handle this event */
2236 #if ! defined(PROG_DISABLE_MENU)
2237 	if(menu_event_redirect_keypress(a->a,
2238 		e->xkey.x, e->xkey.y, e->xkey.x_root, e->xkey.y_root,
2239 		e->xkey.keycode, e->xkey.state) != 0) return;
2240 #endif
2241 	a->cb_p.x = e->xkey.x;
2242 	a->cb_p.y = e->xkey.y;
2243 	a->cb_p.x_root = e->xkey.x_root;
2244 	a->cb_p.y_root = e->xkey.y_root;
2245 
2246 	a->cb_p.state = e->xkey.state;
2247 
2248 	a->cb_p.key_t = (size_t) XLookupString(&e->xkey, a->cb_p.key,
2249 		sizeof(a->cb_p.key) - sizeof(char), NULL, NULL);
2250 
2251 	a->cb_p.key[a->cb_p.key_t] = 0;
2252 
2253 	/* Translate some of the keycodes to internal format */
2254 	if((a->cb_p.keycode = window_event_key(a)) == 0) a->cb_p.keycode = e->xkey.keycode;
2255 
2256 	/* If window movement key was pressed, stop here or hint buttonpress about it */
2257 	if(a->cb_p.moved == IS_YES) return;
2258 
2259 	if((a->cb_p.keycode == 2 || a->cb_p.keycode == 3) && a->cb_p.moved == IS_NO && a->h == 0) {
2260 		a->cb_p.moved = IS_MAYBE;
2261 	}
2262 #if ! defined(PROG_DISABLE_WIDGET)
2263 	if(a->w_gui.o.c != 0) {
2264 		if((w = widget_get_info_by_id(&a->w_gui, (unsigned int) a->w_gui.o.c)) == NULL) {
2265 			return;
2266 		}
2267 
2268 		a->cb_p.x_root = a->cb_p.x;
2269 		a->cb_p.y_root = a->cb_p.y;
2270 
2271 		a->cb_p.x -= w->x;
2272 		a->cb_p.y -= w->y;
2273 
2274 		(void) widget_push_cb_key_press(a->x, w, &a->cb_p);
2275 	}
2276 	else (void) callback_event_add(a->x, a->cb_key_press, &a->cb_p, &a->par_key_press);
2277 #else
2278 	(void) callback_event_add(a->x, a->cb_key_press, &a->cb_p, &a->par_key_press);
2279 #endif
2280 }
2281 
window_event_op_keyrelease(struct a_window * a,XEvent * e)2282 static void window_event_op_keyrelease(struct a_window *a, XEvent *e) {
2283 #if ! defined(PROG_DISABLE_WIDGET)
2284 	struct w_info *w;
2285 #endif
2286 	/* Maybe menu system like to handle this event */
2287 #if ! defined(PROG_DISABLE_MENU)
2288 	if(menu_event_redirect_keyrelease(a->a,
2289 		e->xkey.x, e->xkey.y, e->xkey.x_root, e->xkey.y_root,
2290 		e->xkey.keycode, e->xkey.state) != 0) return;
2291 #endif
2292 	a->cb_p.x = e->xkey.x;
2293 	a->cb_p.y = e->xkey.y;
2294 	a->cb_p.x_root = e->xkey.x_root;
2295 	a->cb_p.y_root = e->xkey.y_root;
2296 
2297 	a->cb_p.state = e->xkey.state;
2298 
2299 	a->cb_p.key_t = (size_t) XLookupString(&e->xkey, a->cb_p.key,
2300 		sizeof(a->cb_p.key) - sizeof(char), NULL, NULL);
2301 
2302 	a->cb_p.key[a->cb_p.key_t] = 0;
2303 
2304 	/* Translate some of the keycodes to internal format */
2305 	if((a->cb_p.keycode = window_event_key(a)) == 0) a->cb_p.keycode = e->xkey.keycode;
2306 
2307 	/* If window movement key was released, remove hint if it is set */
2308 	if((a->cb_p.keycode == 2 || a->cb_p.keycode == 3) && a->cb_p.moved == IS_MAYBE) {
2309 		a->cb_p.moved = IS_NO;
2310 	}
2311 #if ! defined(PROG_DISABLE_WIDGET)
2312 	if(a->w_gui.o.c != 0) {
2313 		if((w = widget_get_info_by_id(&a->w_gui, (unsigned int) a->w_gui.o.c)) == NULL) {
2314 			return;
2315 		}
2316 
2317 		a->cb_p.x_root = a->cb_p.x;
2318 		a->cb_p.y_root = a->cb_p.y;
2319 
2320 		a->cb_p.x -= w->x;
2321 		a->cb_p.y -= w->y;
2322 
2323 		(void) widget_push_cb_key_release(a->x, w, &a->cb_p);
2324 	}
2325 	else (void) callback_event_add(a->x, a->cb_key_release, &a->cb_p, &a->par_key_release);
2326 #else
2327 	(void) callback_event_add(a->x, a->cb_key_release, &a->cb_p, &a->par_key_release);
2328 #endif
2329 }
2330 
window_event_op_buttonpress(struct a_window * a,XEvent * e)2331 static void window_event_op_buttonpress(struct a_window *a, XEvent *e) {
2332 #if ! defined(PROG_DISABLE_WIDGET)
2333 	struct w_info *w;
2334 #endif
2335 	/* Maybe menu system like to handle this event */
2336 #if ! defined(PROG_DISABLE_MENU)
2337 	if(menu_event_redirect_buttonpress(a->a,
2338 		e->xbutton.x, e->xbutton.y, e->xbutton.x_root, e->xbutton.y_root,
2339 		e->xbutton.button, e->xbutton.state) != 0) return;
2340 #endif
2341 	a->cb_p.x = e->xbutton.x;
2342 	a->cb_p.y = e->xbutton.y;
2343 	a->cb_p.x_old = e->xbutton.x;
2344 	a->cb_p.y_old = e->xbutton.y;
2345 	a->cb_p.x_root = e->xbutton.x_root;
2346 	a->cb_p.y_root = e->xbutton.y_root;
2347 
2348 	a->cb_p.state = e->xbutton.state;
2349 	a->cb_p.button = e->xbutton.button;
2350 
2351 	/* If button was pressed while moving, stop here, or start moving if hint is on */
2352 	if(a->cb_p.moved == IS_YES) {
2353 		return;
2354 	}
2355 	else if(a->cb_p.moved == IS_MAYBE) {
2356 		(void) XDefineCursor(a->d, a->w, a->o[WINDOW_CURSOR_MOVING]);
2357 
2358 		a->cb_p.x_move = a->cb_p.x;
2359 		a->cb_p.y_move = a->cb_p.y;
2360 
2361 		a->cb_p.moved = IS_YES;
2362 
2363 		return;
2364 	}
2365 
2366 	a->cb_p.drspeed = 0.0;
2367 #if ! defined(PROG_DISABLE_WIDGET)
2368 	if(a->cb_p.gsw == IS_YES) {
2369 		/* Button was pressed on widget scale */
2370 		if((w = widget_get_info_by_name(&a->w_gui, a->cb_p.gis)) == NULL) {
2371 			return;
2372 		}
2373 
2374 		a->cb_p.x_root = a->cb_p.x;
2375 		a->cb_p.y_root = a->cb_p.y;
2376 
2377 		a->cb_p.x -= w->x;
2378 		a->cb_p.y -= w->y;
2379 
2380 		(void) widget_step_set(&a->w_gui, a->cb_p.gis, a->cb_p.gps);
2381 		(void) widget_refresh(&a->w_gui);
2382 		(void) widget_push_cb_button_press(a->x, &a->w_gui, w, &a->cb_p);
2383 	}
2384 	else if(a->w_gui.o.c != 0) {
2385 		/* Button was pressed on widget */
2386 		if((w = widget_get_info_by_id(&a->w_gui, (unsigned int) a->w_gui.o.c)) == NULL) {
2387 			return;
2388 		}
2389 
2390 		/* Dragging may be possible when button is pressed and this widget is draggable */
2391 		if(widget_get_drag_by_widget(w) == IS_YES) {
2392 			a->cb_p.dragged = IS_MAYBE;
2393 		}
2394 
2395 		a->cb_p.x_root = a->cb_p.x;
2396 		a->cb_p.y_root = a->cb_p.y;
2397 
2398 		a->cb_p.x -= w->x;
2399 		a->cb_p.y -= w->y;
2400 
2401 		(void) widget_push_cb_button_press(a->x, &a->w_gui, w, &a->cb_p);
2402 	}
2403 	else (void) callback_event_add(a->x, a->cb_button_press, &a->cb_p, &a->par_button_press);
2404 #else
2405 	(void) callback_event_add(a->x, a->cb_button_press, &a->cb_p, &a->par_button_press);
2406 #endif
2407 }
2408 
window_event_op_buttonrelease(struct a_window * a,XEvent * e)2409 static void window_event_op_buttonrelease(struct a_window *a, XEvent *e) {
2410 #if ! defined(PROG_DISABLE_WIDGET)
2411 	struct w_info *w;
2412 #endif
2413 	/* Maybe menu system like to handle this event */
2414 #if ! defined(PROG_DISABLE_MENU)
2415 	if(menu_event_redirect_buttonrelease(a->a,
2416 		e->xbutton.x, e->xbutton.y, e->xbutton.x_root, e->xbutton.y_root,
2417 		e->xbutton.button, e->xbutton.state) != 0) return;
2418 #endif
2419 	a->cb_p.x = e->xbutton.x;
2420 	a->cb_p.y = e->xbutton.y;
2421 	a->cb_p.x_old = e->xbutton.x;
2422 	a->cb_p.y_old = e->xbutton.y;
2423 	a->cb_p.x_root = e->xbutton.x_root;
2424 	a->cb_p.y_root = e->xbutton.y_root;
2425 
2426 	a->cb_p.state = e->xbutton.state;
2427 	a->cb_p.button = e->xbutton.button;
2428 
2429 	/* If window is moving or moving is hinted, stop it */
2430 	if(a->cb_p.moved != IS_NO) {
2431 		(void) XDefineCursor(a->d, a->w, a->o[WINDOW_CURSOR_DEFAULT]);
2432 
2433 		a->cb_p.moved = IS_NO;
2434 
2435 		return;
2436 	}
2437 
2438 	/* Releasing button always stops dragging */
2439 	if(a->cb_p.dragged != IS_NO) {
2440 #if ! defined(PROG_DISABLE_WIDGET)
2441 		if(a->cb_p.gsw != IS_YES) {
2442 			(void) XDefineCursor(a->d, a->w, a->o[WINDOW_CURSOR_DEFAULT]);
2443 		}
2444 #endif
2445 		a->cb_p.x_drop = a->cb_p.x;
2446 		a->cb_p.y_drop = a->cb_p.y;
2447 
2448 		a->cb_p.dragged = IS_NO;
2449 		a->cb_p.drspeed = 0.0;
2450 	}
2451 #if ! defined(PROG_DISABLE_WIDGET)
2452 	if(a->w_gui.o.c != 0) {
2453 		if((w = widget_get_info_by_id(&a->w_gui, (unsigned int) a->w_gui.o.c)) == NULL) {
2454 			return;
2455 		}
2456 
2457 		a->cb_p.x_root = a->cb_p.x;
2458 		a->cb_p.y_root = a->cb_p.y;
2459 
2460 		a->cb_p.x -= w->x;
2461 		a->cb_p.y -= w->y;
2462 
2463 		(void) widget_push_cb_button_release(a->x, &a->w_gui, w, &a->cb_p);
2464 	}
2465 	else (void) callback_event_add(a->x, a->cb_button_release, &a->cb_p, &a->par_button_release);
2466 #else
2467 	(void) callback_event_add(a->x, a->cb_button_release, &a->cb_p, &a->par_button_release);
2468 #endif
2469 }
2470 
window_event_op_motionnotify(struct a_window * a,XEvent * e)2471 static void window_event_op_motionnotify(struct a_window *a, XEvent *e) {
2472 #if ! defined(PROG_DISABLE_WIDGET)
2473 	struct w_info *w;
2474 
2475 	struct position u, v;
2476 #endif
2477 	/* Handle event only if menu is not opened */
2478 #if ! defined(PROG_DISABLE_MENU)
2479 	if(menu_state_check(a->a) != 0) return;
2480 #endif
2481 	a->cb_p.x = e->xmotion.x;
2482 	a->cb_p.y = e->xmotion.y;
2483 	a->cb_p.x_root = e->xmotion.x_root;
2484 	a->cb_p.y_root = e->xmotion.y_root;
2485 
2486 	a->cb_p.pressed = e->xmotion.state;
2487 	a->cb_p.detail = e->xmotion.is_hint;
2488 
2489 	/* Move window if moving is set */
2490 	if(a->cb_p.moved == IS_YES) {
2491 		(void) XMoveWindow(a->d, a->w, a->cb_p.x_root - a->cb_p.x_move, a->cb_p.y_root - a->cb_p.y_move);
2492 
2493 		return;
2494 	}
2495 
2496 	/* If dragging is on and widget is selected, call button press callback for the widget continuously */
2497 #if ! defined(PROG_DISABLE_WIDGET)
2498 	if((a->cb_p.dragged == IS_MAYBE || a->cb_p.dragged == IS_YES) && a->w_gui.o.c != 0) {
2499 		(void) XDefineCursor(a->d, a->w, a->o[WINDOW_CURSOR_UPDOWN]);
2500 
2501 		a->cb_p.dragged = IS_YES;
2502 
2503 		if(e->xmotion.x != a->cb_p.x_old || e->xmotion.y != a->cb_p.y_old) {
2504 			if((w = widget_get_info_by_id(&a->w_gui, (unsigned int) a->w_gui.o.c)) == NULL) {
2505 				return;
2506 			}
2507 
2508 			/* Calculate dragging speed */
2509 			u.x = 0.0;
2510 			u.y = (double) e->xmotion.y;
2511 			u.z = 0.0;
2512 
2513 			v.x = 0.0;
2514 			v.y = (double) a->cb_p.y_old;
2515 			v.z = 0.0;
2516 
2517 			a->cb_p.drspeed = coords_difference_2d(&u, &v);
2518 
2519 			/* Change button number based on dragging direction */
2520 			if(e->xmotion.y != a->cb_p.y_old) {
2521 				if(e->xmotion.y > a->cb_p.y_old) {
2522 					a->cb_p.button = 1;
2523 				}
2524 				else a->cb_p.button = 3;
2525 			}
2526 
2527 			a->cb_p.x_old = e->xmotion.x;
2528 			a->cb_p.y_old = e->xmotion.y;
2529 
2530 			(void) widget_push_cb_button_press(a->x, &a->w_gui, w, &a->cb_p);
2531 		}
2532 		else a->cb_p.drspeed = 0.0;
2533 	}
2534 	else {
2535 		if(a->w_gui.mb != NULL) {
2536 			/* Extra sanity check, as I've seen this crash if mouse goes over window border */
2537 			if(a->cb_p.x < 0 || a->cb_p.x >= a->b.width || a->cb_p.y < 0 || a->cb_p.y >= a->b.height) {
2538 				return;
2539 			}
2540 
2541 			a->w_gui.o.c = a->w_gui.mb[(a->b.width * a->cb_p.y) + a->cb_p.x].c;
2542 
2543 			if(a->w_gui.o.c != 0) {
2544 				/* Check if pointer was already on this widget */
2545 				if((unsigned int) a->w_gui.o.c == a->cb_p.moveover) {
2546 					return;
2547 				}
2548 
2549 				/* Change pointer back to default if it is finger */
2550 				if(a->cb_p.gsw == IS_YES) {
2551 					(void) XDefineCursor(a->d, a->w, a->o[WINDOW_CURSOR_DEFAULT]);
2552 
2553 					a->cb_p.gsw = IS_NO;
2554 				}
2555 
2556 				if(a->cb_p.moveover != 0) {
2557 					/* Pointer leaved previously selected widget */
2558 					if((w = widget_get_info_by_id(&a->w_gui, a->cb_p.moveover)) != NULL) {
2559 						(void) widget_cb_move_out(a->x, &a->w_gui, w, &a->cb_p);
2560 					}
2561 				}
2562 
2563 				/* Pointer entered on this widget */
2564 				if((w = widget_get_info_by_id(&a->w_gui, (unsigned int) a->w_gui.o.c)) == NULL) {
2565 					return;
2566 				}
2567 
2568 				a->cb_p.moveover = (unsigned int) a->w_gui.o.c;
2569 
2570 				(void) widget_cb_move_over(a->x, &a->w_gui, w, &a->cb_p);
2571 			}
2572 			else {
2573 				if(a->cb_p.moveover == 0) {
2574 					if(a->cb_p.gsw == IS_YES) {
2575 						if((a->cb_p.gis = widget_cb_move_gauge(&a->w_gui, &a->cb_p, &a->cb_p.gps)) == NULL) {
2576 							/* Change pointer back to default */
2577 							(void) XDefineCursor(a->d, a->w, a->o[WINDOW_CURSOR_DEFAULT]);
2578 
2579 							a->cb_p.gsw = IS_NO;
2580 						}
2581 
2582 						return;
2583 					}
2584 
2585 					(void) callback_event_add(a->x, a->cb_motion_notify, &a->cb_p, &a->par_motion_notify);
2586 
2587 					return;
2588 				}
2589 
2590 				/* Change pointer to finger if this widget has scale */
2591 				if(widget_get_scale_by_id(&a->w_gui, a->cb_p.moveover) == IS_YES) {
2592 					(void) XDefineCursor(a->d, a->w, a->o[WINDOW_CURSOR_HAND]);
2593 
2594 					a->cb_p.gsw = IS_YES;
2595 				}
2596 
2597 				/* Pointer leaved selected widget */
2598 				if((w = widget_get_info_by_id(&a->w_gui, a->cb_p.moveover)) == NULL) {
2599 					return;
2600 				}
2601 
2602 				(void) widget_cb_move_out(a->x, &a->w_gui, w, &a->cb_p);
2603 
2604 				a->cb_p.moveover = 0;
2605 			}
2606 		}
2607 		else (void) callback_event_add(a->x, a->cb_motion_notify, &a->cb_p, &a->par_motion_notify);
2608 	}
2609 #else
2610 	(void) callback_event_add(a->x, a->cb_motion_notify, &a->cb_p, &a->par_motion_notify);
2611 #endif
2612 }
2613 
window_event_op_configurenotify(struct a_window * a,XEvent * e)2614 static void window_event_op_configurenotify(struct a_window *a, XEvent *e) {
2615 	Window c;
2616 #if ! defined(PROG_DISABLE_MENU)
2617 	(void) menu_close_stack();
2618 #endif
2619 	(void) XGetWindowAttributes(e->xconfigure.display, e->xconfigure.window, &a->b);
2620 	(void) XTranslateCoordinates(e->xconfigure.display, e->xconfigure.window, a->r, 0, 0, &a->b.x, &a->b.y, &c);
2621 
2622 	(void) callback_event_add(a->x, a->cb_configure_notify, &a->cb_p, &a->par_configure_notify);
2623 }
2624 
window_event_op_destroynotify(struct a_window * a)2625 static void window_event_op_destroynotify(struct a_window *a) {
2626 	(void) callback_event_add(a->x, a->cb_destroy_notify, &a->cb_p, &a->par_destroy_notify);
2627 }
2628 
window_event_op_mapnotify(struct a_window * a)2629 static void window_event_op_mapnotify(struct a_window *a) {
2630 	(void) callback_event_add(a->x, a->cb_map_notify, &a->cb_p, &a->par_map_notify);
2631 }
2632 
window_event_op_unmapnotify(struct a_window * a)2633 static void window_event_op_unmapnotify(struct a_window *a) {
2634 #if ! defined(PROG_DISABLE_MENU)
2635 	(void) menu_close_stack();
2636 #endif
2637 	(void) callback_event_add(a->x, a->cb_unmap_notify, &a->cb_p, &a->par_unmap_notify);
2638 }
2639 
window_event_op_clientmessage(struct a_window * a,XEvent * e)2640 static void window_event_op_clientmessage(struct a_window *a, XEvent *e) {
2641 	Atom p;
2642 
2643 	if((p = XInternAtom(a->d, "WM_PROTOCOLS", True)) != 0) {
2644 		if(p == (Atom) e->xclient.message_type) {
2645 			if(a->v[0] == (Atom) e->xclient.data.l[0]) {
2646 				/* This is delete window message */
2647 				(void) callback_event_add(a->x, a->cb_destroy_notify, &a->cb_p, &a->par_destroy_notify);
2648 			}
2649 			else if(a->v[1] == (Atom) e->xclient.data.l[0]) {
2650 				/* This is save yourself message */
2651 				(void) XSetCommand(a->d, a->w, main_argv(), main_argc());
2652 			}
2653 
2654 			return;
2655 		}
2656 	}
2657 
2658 	(void) memcpy((void *) &a->cb_p.data.l, (const void *) &e->xclient.data.l, sizeof(a->cb_p.data.l));
2659 
2660 	(void) callback_event_add(a->x, a->cb_client_message, &a->cb_p, &a->par_client_message);
2661 }
2662 
window_event_send_expose(struct a_window * a)2663 static void window_event_send_expose(struct a_window *a) {
2664 	struct a_window *b;
2665 
2666 	XExposeEvent e;
2667 
2668 	if(a->s != WINDOW_STATE_MAPPED || a->q != IS_NO) return;
2669 
2670 	if(a->h != 0) {
2671 		/* Leave if parent window is gone */
2672 		if((b = window_get_struct_by_handle(a->h)) == NULL) {
2673 			return;
2674 		}
2675 
2676 		if(b->s != WINDOW_STATE_MAPPED) return;
2677 	}
2678 
2679 	a->q = IS_YES;
2680 
2681 	(void) memset((void *) &e, 0, sizeof(e));
2682 
2683 	e.type = Expose;
2684 
2685 	e.display = a->d;
2686 	e.window = a->w;
2687 
2688 	if(a->z == WINDOW_OPERATION_EXPOSE) {
2689 		/* Expose requested area if exposing was requested... */
2690 		e.x = a->w_exp.x;
2691 		e.y = a->w_exp.y;
2692 		e.width = a->w_exp.s.width;
2693 		e.height = a->w_exp.s.height;
2694 	}
2695 	else {
2696 		/* ...otherwise expose the whole window */
2697 		e.x = 0;
2698 		e.y = 0;
2699 		e.width = a->b.width;
2700 		e.height = a->b.height;
2701 	}
2702 
2703 	(void) XLockDisplay(a->d);
2704 	(void) XSendEvent(a->d, a->w, True, ExposureMask, (XEvent *) &e);
2705 	(void) XUnlockDisplay(a->d);
2706 }
2707 
window_event_key(struct a_window * a)2708 static unsigned int window_event_key(struct a_window *a) {
2709 	unsigned int i;
2710 
2711 	/* Convert keycode to internal format if needed */
2712 	for(i = 0; ; i++) {
2713 		if(w_key_t[i].s == NULL) break;
2714 		if(w_key_t[i].t != a->cb_p.key_t) continue;
2715 
2716 		if(memcmp((const void *) w_key_t[i].s, (const void *) a->cb_p.key, a->cb_p.key_t) == 0) {
2717 			return(w_key_t[i].c);
2718 		}
2719 	}
2720 
2721 	return(0);
2722 }
2723 #endif
2724 #if ! defined(PROG_DISABLE_INPUT) && defined(PROG_HAS_X11)
window_event_send_buttonpress(char * v,unsigned int b,unsigned int s)2725 void window_event_send_buttonpress(char *v, unsigned int b, unsigned int s) {
2726 	unsigned int m;
2727 
2728 	struct a_window *n;
2729 
2730 	Window r, c;
2731 	XButtonEvent e;
2732 
2733 	if((n = window_event_pass_op(v)) == NULL) return;
2734 
2735 	(void) memset((void *) &e, 0, sizeof(e));
2736 
2737 	e.type = ButtonPress;
2738 
2739 	e.display = n->d;
2740 	e.root = n->r;
2741 	e.window = n->w;
2742 	e.subwindow = None;
2743 
2744 	e.button = b;
2745 	e.state = s;
2746 	e.same_screen = True;
2747 
2748 	(void) XLockDisplay(n->d);
2749 	(void) XQueryPointer(n->d, n->w, &r, &c, &e.x_root, &e.y_root, &e.x, &e.y, &m);
2750 	(void) XSendEvent(n->d, n->w, True, ButtonPressMask, (XEvent *) &e);
2751 	(void) XUnlockDisplay(n->d);
2752 }
2753 
window_event_send_buttonrelease(char * v,unsigned int b,unsigned int s)2754 void window_event_send_buttonrelease(char *v, unsigned int b, unsigned int s) {
2755 	unsigned int m;
2756 
2757 	struct a_window *n;
2758 
2759 	Window r, c;
2760 	XButtonEvent e;
2761 
2762 	if((n = window_event_pass_op(v)) == NULL) return;
2763 
2764 	(void) memset((void *) &e, 0, sizeof(e));
2765 
2766 	e.type = ButtonRelease;
2767 
2768 	e.display = n->d;
2769 	e.root = n->r;
2770 	e.window = n->w;
2771 	e.subwindow = None;
2772 
2773 	e.button = b;
2774 	e.state = s;
2775 	e.same_screen = True;
2776 
2777 	(void) XLockDisplay(n->d);
2778 	(void) XQueryPointer(n->d, n->w, &r, &c, &e.x_root, &e.y_root, &e.x, &e.y, &m);
2779 	(void) XSendEvent(n->d, n->w, True, ButtonReleaseMask, (XEvent *) &e);
2780 	(void) XUnlockDisplay(n->d);
2781 }
2782 
window_event_send_keypress(char * v,unsigned int b,unsigned int s)2783 void window_event_send_keypress(char *v, unsigned int b, unsigned int s) {
2784 	unsigned int m;
2785 
2786 	struct a_window *n;
2787 
2788 	Window r, c;
2789 	XKeyEvent e;
2790 
2791 	if((n = window_event_pass_op(v)) == NULL) return;
2792 
2793 	(void) memset((void *) &e, 0, sizeof(e));
2794 
2795 	e.type = KeyPress;
2796 
2797 	e.display = n->d;
2798 	e.root = n->r;
2799 	e.window = n->w;
2800 	e.subwindow = None;
2801 
2802 	e.keycode = b;
2803 	e.state = s;
2804 	e.same_screen = True;
2805 
2806 	(void) XLockDisplay(n->d);
2807 	(void) XQueryPointer(n->d, n->w, &r, &c, &e.x_root, &e.y_root, &e.x, &e.y, &m);
2808 	(void) XSendEvent(n->d, n->w, True, KeyPressMask, (XEvent *) &e);
2809 	(void) XUnlockDisplay(n->d);
2810 }
2811 
window_event_send_keyrelease(char * v,unsigned int b,unsigned int s)2812 void window_event_send_keyrelease(char *v, unsigned int b, unsigned int s) {
2813 	unsigned int m;
2814 
2815 	struct a_window *n;
2816 
2817 	Window r, c;
2818 	XKeyEvent e;
2819 
2820 	if((n = window_event_pass_op(v)) == NULL) return;
2821 
2822 	(void) memset((void *) &e, 0, sizeof(e));
2823 
2824 	e.type = KeyRelease;
2825 
2826 	e.display = n->d;
2827 	e.root = n->r;
2828 	e.window = n->w;
2829 	e.subwindow = None;
2830 
2831 	e.keycode = b;
2832 	e.state = s;
2833 	e.same_screen = True;
2834 
2835 	(void) XLockDisplay(n->d);
2836 	(void) XQueryPointer(n->d, n->w, &r, &c, &e.x_root, &e.y_root, &e.x, &e.y, &m);
2837 	(void) XSendEvent(n->d, n->w, True, KeyReleaseMask, (XEvent *) &e);
2838 	(void) XUnlockDisplay(n->d);
2839 }
2840 
window_event_send_motion_xy(char * v,float x,float y)2841 void window_event_send_motion_xy(char *v, float x, float y) {
2842 	struct a_window *n;
2843 
2844 	if((n = window_event_pass_op(v)) == NULL) return;
2845 
2846 	(void) XLockDisplay(n->d);
2847 
2848 	(void) XWarpPointer(n->d, None, None,
2849 		0, 0, 0, 0,
2850 		(int) round((double) x), (int) round((double) y));
2851 
2852 	(void) XUnlockDisplay(n->d);
2853 }
2854 
window_event_pass_op(char * s)2855 static struct a_window *window_event_pass_op(char *s) {
2856 	unsigned int i;
2857 
2858 	size_t t;
2859 
2860 	if(a_win == NULL) return(NULL);
2861 
2862 	t = str_len(s, STRING_ASCII);
2863 
2864 	for(i = 0; i < c_win; i++) {
2865 		if(a_win[i] == NULL) continue;
2866 
2867 		if(window_event_pass_at(s, t, a_win[i]) == 0) {
2868 			return(a_win[i]);
2869 		}
2870 	}
2871 
2872 	return(NULL);
2873 }
2874 
window_event_pass_at(char * s,size_t t,struct a_window * a)2875 static int window_event_pass_at(char *s, size_t t, struct a_window *a) {
2876 	int p;
2877 
2878 	char *r;
2879 
2880 	p = -1;
2881 	r = NULL;
2882 
2883 	(void) XLockDisplay(a->d);
2884 
2885 	if(XFetchName(a->d, a->w, &r) == 0) {
2886 		(void) XUnlockDisplay(a->d);
2887 
2888 		return(p);
2889 	}
2890 
2891 	if(r != NULL) {
2892 		if(str_len(r, STRING_ASCII) == t) {
2893 			if(memcmp((const void *) s, (const void *) r, t) == 0) p = 0;
2894 		}
2895 
2896 		(void) XFree(r);
2897 	}
2898 
2899 	(void) XUnlockDisplay(a->d);
2900 
2901 	return(p);
2902 }
2903 #endif
window_cmd_clip(struct clip_2 * c,unsigned int * e,unsigned int * f,unsigned int * u,unsigned int * v)2904 int window_cmd_clip(struct clip_2 *c, unsigned int *e, unsigned int *f, unsigned int *u, unsigned int *v) {
2905 #if defined(PROG_HAS_X11)
2906 	if(c->x + *u > 0 && c->x < (int) c->s.width && c->y + *v > 0 && c->y < (int) c->s.height) {
2907 		*e = 0;
2908 		*f = 0;
2909 
2910 		/* Test if start x is over the left edge and end x is visible */
2911 		if(c->x < 0 && c->x + *u > 0) {
2912 			*e = -(c->x);
2913 
2914 			c->x = 0;
2915 		}
2916 
2917 		/* Test if start x is visible and end x is over the right edge */
2918 		if(c->x <= (int) c->s.width && c->x + *u >= c->s.width) {
2919 			*u = c->s.width - c->x;
2920 		}
2921 
2922 		/* Test if start y is over the top edge and end y is visible */
2923 		if(c->y < 0 && c->y + *v > 0) {
2924 			*f = -(c->y);
2925 
2926 			c->y = 0;
2927 		}
2928 
2929 		/* Test if start y is visible and end y is over the bottom edge */
2930 		if(c->y <= (int) c->s.height && c->y + *v >= c->s.height) {
2931 			*v = *v - ((c->y + *v) - c->s.height);
2932 		}
2933 
2934 		return(0);
2935 	}
2936 
2937 	return(-1);
2938 #else
2939 	(void) c;
2940 	(void) e;
2941 	(void) f;
2942 	(void) u;
2943 	(void) v;
2944 
2945 	return(-1);
2946 #endif
2947 }
2948 
window_cmd_push(struct w_cmd * w)2949 int window_cmd_push(struct w_cmd *w) {
2950 #if defined(PROG_HAS_X11)
2951 	unsigned int i, k, r;
2952 
2953 	/* Hold on a while if command pipeline is locked */
2954 	while(c_lck == IS_MAYBE) {
2955 		(void) timer_wait(0, TIMER_RESOLUTION_VERYFAST);
2956 	}
2957 
2958 	c_lck = IS_YES;
2959 
2960 	for(k = 0; k < 3; k++) {
2961 		for(i = 0; i < c_evt; i++) {
2962 			if(w_evt[0][i].c != WINDOW_COMMAND_NONE) continue;
2963 
2964 			/* Copy command parameters so caller does not need to keep them after push */
2965 			if(w->p != NULL && w->t != 0) {
2966 				/* window_cmd_roll() frees this if needed */
2967 				if((w_evt[0][i].p = malloc(w->t)) == NULL) {
2968 					LOGWARN(
2969 						ERROR_SLIGHT, SUBSYSTEM,
2970 						_("Failed to allocate %lu bytes of memory"),
2971 						(unsigned long) w->t
2972 					);
2973 
2974 					w_evt[0][i].c = WINDOW_COMMAND_NONE;
2975 
2976 					c_lck = IS_NO;
2977 
2978 					return(-1);
2979 				}
2980 
2981 				(void) memcpy((void *) w_evt[0][i].p, (const void *) w->p, w->t);
2982 			}
2983 			else w_evt[0][i].p = NULL;
2984 
2985 			w_evt[0][i].n = ++c_cnt;
2986 
2987 			w_evt[0][i].h = w->h;
2988 			w_evt[0][i].e = w->e;
2989 			w_evt[0][i].c = w->c;
2990 
2991 			if(w->e == IS_YES) {
2992 				c_pnd = IS_MAYBE;
2993 			}
2994 			else if(c_pnd != IS_MAYBE) {
2995 				c_pnd = IS_YES;
2996 			}
2997 
2998 			c_lck = IS_NO;
2999 
3000 			return(0);
3001 		}
3002 
3003 		/* If no free slot was found, allocate more slots */
3004 		if((r = window_cmd_push_op()) != 0) {
3005 			c_lck = IS_NO;
3006 
3007 			return(r);
3008 		}
3009 	}
3010 
3011 	c_lck = IS_NO;
3012 
3013 	return(-1);
3014 #else
3015 	(void) w;
3016 
3017 	return(-1);
3018 #endif
3019 }
3020 #if defined(PROG_HAS_X11)
window_cmd_push_op(void)3021 static int window_cmd_push_op(void) {
3022 	unsigned int i;
3023 
3024 	size_t u;
3025 
3026 	struct w_cmd *t;
3027 
3028 	if(c_evt >= WINDOW_COMMAND_POOL_MAX) {
3029 		(void) flush_error();
3030 
3031 		LOGWARN(
3032 			ERROR_NOERROR, SUBSYSTEM,
3033 			_("Failed to append command to window command pool, it has reached its maximum limit of %u entries"),
3034 			(unsigned int) WINDOW_COMMAND_POOL_MAX
3035 		);
3036 
3037 		return(-2);
3038 	}
3039 
3040 	u = sizeof(struct w_cmd) * (c_evt + WINDOW_COMMAND_POOL_SIZE);
3041 
3042 	APP_REALLOC_RET_VALUE(t, w_evt[0], u, -1);
3043 	APP_REALLOC_RET_VALUE(t, w_evt[1], u, -1);
3044 
3045 	for(i = c_evt; i < c_evt + WINDOW_COMMAND_POOL_SIZE; i++) {
3046 		(void) window_cmd_push_clear(0, i);
3047 		(void) window_cmd_push_clear(1, i);
3048 	}
3049 
3050 	c_evt += WINDOW_COMMAND_POOL_SIZE;
3051 
3052 	return(0);
3053 }
3054 
window_cmd_push_clear(unsigned int p,unsigned int i)3055 static void window_cmd_push_clear(unsigned int p, unsigned int i) {
3056 	w_evt[p][i].c = WINDOW_COMMAND_NONE;
3057 	w_evt[p][i].e = IS_NO;
3058 	w_evt[p][i].h = 0;
3059 	w_evt[p][i].n = 0;
3060 
3061 	w_evt[p][i].p = NULL;
3062 
3063 	w_evt[p][i].t = 0;
3064 }
3065 #endif
window_cmd_cancel_permanent(unsigned int c)3066 void window_cmd_cancel_permanent(unsigned int c) {
3067 #if defined(PROG_HAS_X11)
3068 	unsigned int i, p;
3069 
3070 	/* Hold on a while if command pipeline is locked */
3071 	while(c_lck == IS_MAYBE) {
3072 		(void) timer_wait(0, TIMER_RESOLUTION_VERYFAST);
3073 	}
3074 
3075 	c_lck = IS_YES;
3076 
3077 	/* Remove all permanent commands of requested type */
3078 	for(i = 0, p = 0; i < c_evt; i++) {
3079 		if(w_evt[0][i].e == IS_YES) {
3080 			if(w_evt[0][i].c == c) {
3081 				if(w_evt[0][i].p != NULL) (void) free(w_evt[0][i].p);
3082 
3083 				(void) window_cmd_push_clear(0, i);
3084 			}
3085 			else ++p;
3086 		}
3087 	}
3088 
3089 	/* Stop continuous command processing if needed */
3090 	if(p == 0) c_pnd = IS_YES;
3091 
3092 	c_lck = IS_NO;
3093 #else
3094 	(void) c;
3095 #endif
3096 }
3097 #if defined(PROG_HAS_X11)
window_cmd_roll(struct t_str * tp)3098 static void window_cmd_roll(struct t_str *tp) {
3099 	unsigned int i, p;
3100 
3101 	/* If there are no pending commands, leave */
3102 	if(c_pnd != IS_YES && c_pnd != IS_MAYBE) return;
3103 	if(c_pnd == IS_YES) c_pnd = IS_NO;
3104 
3105 	/* Hold on a while if command pipeline is locked */
3106 	while(c_lck == IS_YES) {
3107 		(void) timer_wait(0, TIMER_RESOLUTION_VERYFAST);
3108 	}
3109 
3110 	/* Make sorted copy of pipeline, skipping unused slots */
3111 	c_lck = IS_MAYBE;
3112 
3113 	p = window_cmd_roll_op();
3114 
3115 	c_lck = IS_NO;
3116 
3117 	for(i = 0; i < p; i++) {
3118 		switch(w_evt[1][i].c) {
3119 			case WINDOW_COMMAND_DRAW_PIXEL:
3120 				(void) window_cmd_roll_draw_pixel(&w_evt[1][i]);
3121 
3122 				break;
3123 			case WINDOW_COMMAND_DRAW_PIXEL_ALPHA:
3124 				(void) window_cmd_roll_draw_pixel_alpha(&w_evt[1][i]);
3125 
3126 				break;
3127 			case WINDOW_COMMAND_DRAW_PIXELS:
3128 				(void) window_cmd_roll_draw_pixels(&w_evt[1][i]);
3129 
3130 				break;
3131 			case WINDOW_COMMAND_DRAW_PIXELS_ALPHA:
3132 				(void) window_cmd_roll_draw_pixels_alpha(&w_evt[1][i]);
3133 
3134 				break;
3135 			case WINDOW_COMMAND_DRAW_SUBPIXEL:
3136 				(void) window_cmd_roll_draw_subpixel(&w_evt[1][i]);
3137 
3138 				break;
3139 			case WINDOW_COMMAND_DRAW_SUBPIXEL_ALPHA:
3140 				(void) window_cmd_roll_draw_subpixel_alpha(&w_evt[1][i]);
3141 
3142 				break;
3143 			case WINDOW_COMMAND_DRAW_SUBPIXELS:
3144 				(void) window_cmd_roll_draw_subpixels(&w_evt[1][i]);
3145 
3146 				break;
3147 			case WINDOW_COMMAND_DRAW_SUBPIXELS_ALPHA:
3148 				(void) window_cmd_roll_draw_subpixels_alpha(&w_evt[1][i]);
3149 
3150 				break;
3151 			case WINDOW_COMMAND_DRAW_LINE:
3152 				(void) window_cmd_roll_draw_line(&w_evt[1][i]);
3153 
3154 				break;
3155 			case WINDOW_COMMAND_DRAW_LINE_AA:
3156 				(void) window_cmd_roll_draw_line_aa(&w_evt[1][i]);
3157 
3158 				break;
3159 			case WINDOW_COMMAND_DRAW_LINE_ALPHA:
3160 				(void) window_cmd_roll_draw_line_alpha(&w_evt[1][i]);
3161 
3162 				break;
3163 			case WINDOW_COMMAND_DRAW_LINES:
3164 				(void) window_cmd_roll_draw_lines(&w_evt[1][i]);
3165 
3166 				break;
3167 			case WINDOW_COMMAND_DRAW_LINES_AA:
3168 				(void) window_cmd_roll_draw_lines_aa(&w_evt[1][i]);
3169 
3170 				break;
3171 			case WINDOW_COMMAND_DRAW_LINES_ALPHA:
3172 				(void) window_cmd_roll_draw_lines_alpha(&w_evt[1][i]);
3173 
3174 				break;
3175 			case WINDOW_COMMAND_DRAW_CIRCLE:
3176 				(void) window_cmd_roll_draw_circle(&w_evt[1][i]);
3177 
3178 				break;
3179 			case WINDOW_COMMAND_DRAW_CIRCLE_AA:
3180 				(void) window_cmd_roll_draw_circle_aa(&w_evt[1][i]);
3181 
3182 				break;
3183 			case WINDOW_COMMAND_DRAW_CIRCLE_ALPHA:
3184 				(void) window_cmd_roll_draw_circle_alpha(&w_evt[1][i]);
3185 
3186 				break;
3187 			case WINDOW_COMMAND_DRAW_CIRCLES:
3188 				(void) window_cmd_roll_draw_circles(&w_evt[1][i]);
3189 
3190 				break;
3191 			case WINDOW_COMMAND_DRAW_CIRCLES_AA:
3192 				(void) window_cmd_roll_draw_circles_aa(&w_evt[1][i]);
3193 
3194 				break;
3195 			case WINDOW_COMMAND_DRAW_CIRCLES_ALPHA:
3196 				(void) window_cmd_roll_draw_circles_alpha(&w_evt[1][i]);
3197 
3198 				break;
3199 			case WINDOW_COMMAND_DRAW_TEXT:
3200 				(void) window_cmd_roll_draw_text(&w_evt[1][i]);
3201 
3202 				break;
3203 			case WINDOW_COMMAND_DRAW_TEXTS:
3204 				(void) window_cmd_roll_draw_texts(&w_evt[1][i]);
3205 
3206 				break;
3207 			case WINDOW_COMMAND_DRAW_SET:
3208 				(void) window_cmd_roll_draw_set(&w_evt[1][i]);
3209 
3210 				break;
3211 			case WINDOW_COMMAND_DRAW_SET_ALPHA:
3212 				(void) window_cmd_roll_draw_set_alpha(&w_evt[1][i]);
3213 
3214 				break;
3215 			case WINDOW_COMMAND_DRAW_BORDER:
3216 				(void) window_cmd_roll_draw_border(&w_evt[1][i]);
3217 
3218 				break;
3219 			case WINDOW_COMMAND_DRAW_BORDER_ALPHA:
3220 				(void) window_cmd_roll_draw_border_alpha(&w_evt[1][i]);
3221 
3222 				break;
3223 			case WINDOW_COMMAND_DRAW_COPY:
3224 				(void) window_cmd_roll_draw_copy(&w_evt[1][i]);
3225 
3226 				break;
3227 			case WINDOW_COMMAND_DRAW_COPY_ALPHA:
3228 				(void) window_cmd_roll_draw_copy_alpha(&w_evt[1][i]);
3229 
3230 				break;
3231 			case WINDOW_COMMAND_DRAW_WIPE:
3232 				(void) window_cmd_roll_draw_wipe(&w_evt[1][i]);
3233 
3234 				break;
3235 			case WINDOW_COMMAND_WINDOW_OPEN:
3236 				(void) window_cmd_roll_window_open(tp, &w_evt[1][i]);
3237 
3238 				break;
3239 			case WINDOW_COMMAND_WINDOW_ICON:
3240 				(void) window_cmd_roll_window_icon(&w_evt[1][i]);
3241 
3242 				break;
3243 			case WINDOW_COMMAND_WINDOW_CLOSE:
3244 				(void) window_cmd_roll_window_close(&w_evt[1][i]);
3245 
3246 				break;
3247 			case WINDOW_COMMAND_WINDOW_MAP:
3248 				(void) window_cmd_roll_window_map(&w_evt[1][i]);
3249 
3250 				break;
3251 			case WINDOW_COMMAND_WINDOW_UNMAP:
3252 				(void) window_cmd_roll_window_unmap(&w_evt[1][i]);
3253 
3254 				break;
3255 			case WINDOW_COMMAND_WINDOW_SET_ATTRS:
3256 				(void) window_cmd_roll_window_set_attrs(&w_evt[1][i]);
3257 
3258 				break;
3259 			case WINDOW_COMMAND_WINDOW_REFRESH:
3260 				(void) window_cmd_roll_window_refresh(&w_evt[1][i]);
3261 
3262 				break;
3263 #if ! defined(PROG_DISABLE_BOB)
3264 			case WINDOW_COMMAND_BOBS:
3265 				(void) window_cmd_roll_window_bobs();
3266 
3267 				break;
3268 #endif
3269 			default:
3270 				break;
3271 		}
3272 
3273 		/* Free command parameters allocated by window_cmd_push() if this command is not permanent */
3274 		if(w_evt[1][i].p != NULL && w_evt[1][i].e != IS_YES) (void) free(w_evt[1][i].p);
3275 	}
3276 }
3277 
window_cmd_roll_op(void)3278 static unsigned int window_cmd_roll_op(void) {
3279 	unsigned int i, p;
3280 
3281 	p = 0;
3282 
3283 	for(i = 0; i < c_evt; i++) {
3284 		if(w_evt[0][i].c == WINDOW_COMMAND_NONE) continue;
3285 
3286 		(void) memcpy((void *) &w_evt[1][p++], (const void *) &w_evt[0][i], sizeof(struct w_cmd));
3287 
3288 		/* Dont clear this slot now if it is permanent */
3289 		if(w_evt[0][i].e != IS_YES) (void) window_cmd_push_clear(0, i);
3290 	}
3291 
3292 	/* Sort pipeline objects by their order number */
3293 	if(p > 1) (void) qsort((void *) w_evt[1], (size_t) p, sizeof(struct w_cmd), window_cmd_roll_cmp);
3294 
3295 	c_cnt = 0;
3296 
3297 	return(p);
3298 }
3299 
window_cmd_roll_cmp(const void * a,const void * b)3300 static int window_cmd_roll_cmp(const void *a, const void *b) {
3301 	const struct w_cmd *c, *d;
3302 
3303 	c = (const struct w_cmd *) a;
3304 	d = (const struct w_cmd *) b;
3305 
3306 	return(c->n - d->n);
3307 }
3308 
window_cmd_roll_draw_pixel(struct w_cmd * w)3309 static void window_cmd_roll_draw_pixel(struct w_cmd *w) {
3310 	struct a_window *a;
3311 
3312 	struct point_2 *c;
3313 
3314 	if((a = window_get_struct_by_handle(w->h)) == NULL) return;
3315 
3316 	c = (struct point_2 *) w->p;
3317 
3318 	if(c->x < a->w_act.left || c->x >= a->w_act.right || c->y < a->w_act.top || c->y >= a->w_act.bottom) return;
3319 
3320 	(void) draw_pixel_noclip((struct pixel_rgba_8 *) a->shm_i->data, &c->p, c->x, c->y, &a->w_act);
3321 }
3322 
window_cmd_roll_draw_pixel_alpha(struct w_cmd * w)3323 static void window_cmd_roll_draw_pixel_alpha(struct w_cmd *w) {
3324 	struct a_window *a;
3325 
3326 	struct point_2 *c;
3327 
3328 	if((a = window_get_struct_by_handle(w->h)) == NULL) return;
3329 
3330 	c = (struct point_2 *) w->p;
3331 
3332 	if(c->x < a->w_act.left || c->x >= a->w_act.right || c->y < a->w_act.top || c->y >= a->w_act.bottom) return;
3333 
3334 	(void) draw_pixel_alpha_noclip((struct pixel_rgba_8 *) a->shm_i->data, &c->p, c->x, c->y, &a->w_act);
3335 }
3336 
window_cmd_roll_draw_pixels(struct w_cmd * w)3337 static void window_cmd_roll_draw_pixels(struct w_cmd *w) {
3338 	unsigned int i;
3339 
3340 	struct a_window *a;
3341 
3342 	struct points_2 *c;
3343 
3344 	if((a = window_get_struct_by_handle(w->h)) == NULL) return;
3345 
3346 	c = (struct points_2 *) w->p;
3347 
3348 	for(i = 0; i < c->c; i++) {
3349 		(void) draw_pixel((struct pixel_rgba_8 *) a->shm_i->data, &c->p[i].p,
3350 			c->p[i].x, c->p[i].y, &a->w_act);
3351 	}
3352 }
3353 
window_cmd_roll_draw_pixels_alpha(struct w_cmd * w)3354 static void window_cmd_roll_draw_pixels_alpha(struct w_cmd *w) {
3355 	unsigned int i;
3356 
3357 	struct a_window *a;
3358 
3359 	struct points_2 *c;
3360 
3361 	if((a = window_get_struct_by_handle(w->h)) == NULL) return;
3362 
3363 	c = (struct points_2 *) w->p;
3364 
3365 	for(i = 0; i < c->c; i++) {
3366 		(void) draw_pixel_alpha((struct pixel_rgba_8 *) a->shm_i->data, &c->p[i].p,
3367 			c->p[i].x, c->p[i].y, &a->w_act);
3368 	}
3369 }
3370 
window_cmd_roll_draw_subpixel(struct w_cmd * w)3371 static void window_cmd_roll_draw_subpixel(struct w_cmd *w) {
3372 	struct a_window *a;
3373 
3374 	struct subpoint_2 *c;
3375 
3376 	if((a = window_get_struct_by_handle(w->h)) == NULL) return;
3377 
3378 	c = (struct subpoint_2 *) w->p;
3379 
3380 	(void) draw_subpixel((struct pixel_rgba_8 *) a->shm_i->data, &c->p, c->x, c->y, &a->w_act);
3381 }
3382 
window_cmd_roll_draw_subpixel_alpha(struct w_cmd * w)3383 static void window_cmd_roll_draw_subpixel_alpha(struct w_cmd *w) {
3384 	struct a_window *a;
3385 
3386 	struct subpoint_2 *c;
3387 
3388 	if((a = window_get_struct_by_handle(w->h)) == NULL) return;
3389 
3390 	c = (struct subpoint_2 *) w->p;
3391 
3392 	(void) draw_subpixel_alpha((struct pixel_rgba_8 *) a->shm_i->data, &c->p, c->x, c->y, &a->w_act);
3393 }
3394 
window_cmd_roll_draw_subpixels(struct w_cmd * w)3395 static void window_cmd_roll_draw_subpixels(struct w_cmd *w) {
3396 	unsigned int i;
3397 
3398 	struct a_window *a;
3399 
3400 	struct subpoints_2 *c;
3401 
3402 	if((a = window_get_struct_by_handle(w->h)) == NULL) return;
3403 
3404 	c = (struct subpoints_2 *) w->p;
3405 
3406 	for(i = 0; i < c->c; i++) {
3407 		(void) draw_subpixel((struct pixel_rgba_8 *) a->shm_i->data, &c->p[i].p,
3408 			c->p[i].x, c->p[i].y, &a->w_act);
3409 	}
3410 }
3411 
window_cmd_roll_draw_subpixels_alpha(struct w_cmd * w)3412 static void window_cmd_roll_draw_subpixels_alpha(struct w_cmd *w) {
3413 	unsigned int i;
3414 
3415 	struct a_window *a;
3416 
3417 	struct subpoints_2 *c;
3418 
3419 	if((a = window_get_struct_by_handle(w->h)) == NULL) return;
3420 
3421 	c = (struct subpoints_2 *) w->p;
3422 
3423 	for(i = 0; i < c->c; i++) {
3424 		(void) draw_subpixel_alpha((struct pixel_rgba_8 *) a->shm_i->data, &c->p[i].p,
3425 			c->p[i].x, c->p[i].y, &a->w_act);
3426 	}
3427 }
3428 
window_cmd_roll_draw_line(struct w_cmd * w)3429 static void window_cmd_roll_draw_line(struct w_cmd *w) {
3430 	struct a_window *a;
3431 
3432 	struct point_4 *c;
3433 
3434 	if((a = window_get_struct_by_handle(w->h)) == NULL) return;
3435 
3436 	c = (struct point_4 *) w->p;
3437 
3438 	(void) draw_line((struct pixel_rgba_8 *) a->shm_i->data, &c->p,
3439 		c->x1, c->y1, c->x2, c->y2, &a->w_act);
3440 }
3441 
window_cmd_roll_draw_line_aa(struct w_cmd * w)3442 static void window_cmd_roll_draw_line_aa(struct w_cmd *w) {
3443 	struct a_window *a;
3444 
3445 	struct point_4 *c;
3446 
3447 	if((a = window_get_struct_by_handle(w->h)) == NULL) return;
3448 
3449 	c = (struct point_4 *) w->p;
3450 
3451 	(void) draw_line_aa((struct pixel_rgba_8 *) a->shm_i->data, &c->p,
3452 		c->x1, c->y1, c->x2, c->y2, &a->w_act);
3453 }
3454 
window_cmd_roll_draw_line_alpha(struct w_cmd * w)3455 static void window_cmd_roll_draw_line_alpha(struct w_cmd *w) {
3456 	struct a_window *a;
3457 
3458 	struct point_4 *c;
3459 
3460 	if((a = window_get_struct_by_handle(w->h)) == NULL) return;
3461 
3462 	c = (struct point_4 *) w->p;
3463 
3464 	(void) draw_line_alpha((struct pixel_rgba_8 *) a->shm_i->data, &c->p,
3465 		c->x1, c->y1, c->x2, c->y2, &a->w_act);
3466 }
3467 
window_cmd_roll_draw_lines(struct w_cmd * w)3468 static void window_cmd_roll_draw_lines(struct w_cmd *w) {
3469 	unsigned int i;
3470 
3471 	struct a_window *a;
3472 
3473 	struct points_4 *c;
3474 
3475 	if((a = window_get_struct_by_handle(w->h)) == NULL) return;
3476 
3477 	c = (struct points_4 *) w->p;
3478 
3479 	for(i = 0; i < c->c; i++) {
3480 		(void) draw_line((struct pixel_rgba_8 *) a->shm_i->data, &c->p[i].p,
3481 			c->p[i].x1, c->p[i].y1, c->p[i].x2, c->p[i].y2, &a->w_act);
3482 	}
3483 }
3484 
window_cmd_roll_draw_lines_aa(struct w_cmd * w)3485 static void window_cmd_roll_draw_lines_aa(struct w_cmd *w) {
3486 	unsigned int i;
3487 
3488 	struct a_window *a;
3489 
3490 	struct points_4 *c;
3491 
3492 	if((a = window_get_struct_by_handle(w->h)) == NULL) return;
3493 
3494 	c = (struct points_4 *) w->p;
3495 
3496 	for(i = 0; i < c->c; i++) {
3497 		(void) draw_line_aa((struct pixel_rgba_8 *) a->shm_i->data, &c->p[i].p,
3498 			c->p[i].x1, c->p[i].y1, c->p[i].x2, c->p[i].y2, &a->w_act);
3499 	}
3500 }
3501 
window_cmd_roll_draw_lines_alpha(struct w_cmd * w)3502 static void window_cmd_roll_draw_lines_alpha(struct w_cmd *w) {
3503 	unsigned int i;
3504 
3505 	struct a_window *a;
3506 
3507 	struct points_4 *c;
3508 
3509 	if((a = window_get_struct_by_handle(w->h)) == NULL) return;
3510 
3511 	c = (struct points_4 *) w->p;
3512 
3513 	for(i = 0; i < c->c; i++) {
3514 		(void) draw_line_alpha((struct pixel_rgba_8 *) a->shm_i->data, &c->p[i].p,
3515 			c->p[i].x1, c->p[i].y1, c->p[i].x2, c->p[i].y2, &a->w_act);
3516 	}
3517 }
3518 
window_cmd_roll_draw_circle(struct w_cmd * w)3519 static void window_cmd_roll_draw_circle(struct w_cmd *w) {
3520 	struct a_window *a;
3521 
3522 	struct circle_2 *c;
3523 
3524 	if((a = window_get_struct_by_handle(w->h)) == NULL) return;
3525 
3526 	c = (struct circle_2 *) w->p;
3527 
3528 	(void) draw_circle((struct pixel_rgba_8 *) a->shm_i->data, &c->p,
3529 		c->x, c->y, c->n, c->r, c->f, c->d, &a->w_act);
3530 }
3531 
window_cmd_roll_draw_circle_aa(struct w_cmd * w)3532 static void window_cmd_roll_draw_circle_aa(struct w_cmd *w) {
3533 	struct a_window *a;
3534 
3535 	struct circle_2 *c;
3536 
3537 	if((a = window_get_struct_by_handle(w->h)) == NULL) return;
3538 
3539 	c = (struct circle_2 *) w->p;
3540 
3541 	(void) draw_circle_aa((struct pixel_rgba_8 *) a->shm_i->data, &c->p,
3542 		c->x, c->y, c->n, c->r, c->f, c->d, &a->w_act);
3543 }
3544 
window_cmd_roll_draw_circle_alpha(struct w_cmd * w)3545 static void window_cmd_roll_draw_circle_alpha(struct w_cmd *w) {
3546 	struct a_window *a;
3547 
3548 	struct circle_2 *c;
3549 
3550 	if((a = window_get_struct_by_handle(w->h)) == NULL) return;
3551 
3552 	c = (struct circle_2 *) w->p;
3553 
3554 	(void) draw_circle_alpha((struct pixel_rgba_8 *) a->shm_i->data, &c->p,
3555 		c->x, c->y, c->n, c->r, c->f, c->d, &a->w_act);
3556 }
3557 
window_cmd_roll_draw_circles(struct w_cmd * w)3558 static void window_cmd_roll_draw_circles(struct w_cmd *w) {
3559 	unsigned int i;
3560 
3561 	struct a_window *a;
3562 
3563 	struct circles_2 *c;
3564 
3565 	if((a = window_get_struct_by_handle(w->h)) == NULL) return;
3566 
3567 	c = (struct circles_2 *) w->p;
3568 
3569 	for(i = 0; i < c->c; i++) {
3570 		(void) draw_circle((struct pixel_rgba_8 *) a->shm_i->data, &c->p[i].p,
3571 			c->p[i].x, c->p[i].y, c->p[i].n, c->p[i].r, c->p[i].f, c->p[i].d, &a->w_act);
3572 	}
3573 }
3574 
window_cmd_roll_draw_circles_aa(struct w_cmd * w)3575 static void window_cmd_roll_draw_circles_aa(struct w_cmd *w) {
3576 	unsigned int i;
3577 
3578 	struct a_window *a;
3579 
3580 	struct circles_2 *c;
3581 
3582 	if((a = window_get_struct_by_handle(w->h)) == NULL) return;
3583 
3584 	c = (struct circles_2 *) w->p;
3585 
3586 	for(i = 0; i < c->c; i++) {
3587 		(void) draw_circle_aa((struct pixel_rgba_8 *) a->shm_i->data, &c->p[i].p,
3588 			c->p[i].x, c->p[i].y, c->p[i].n, c->p[i].r, c->p[i].f, c->p[i].d, &a->w_act);
3589 	}
3590 }
3591 
window_cmd_roll_draw_circles_alpha(struct w_cmd * w)3592 static void window_cmd_roll_draw_circles_alpha(struct w_cmd *w) {
3593 	unsigned int i;
3594 
3595 	struct a_window *a;
3596 
3597 	struct circles_2 *c;
3598 
3599 	if((a = window_get_struct_by_handle(w->h)) == NULL) return;
3600 
3601 	c = (struct circles_2 *) w->p;
3602 
3603 	for(i = 0; i < c->c; i++) {
3604 		(void) draw_circle_alpha((struct pixel_rgba_8 *) a->shm_i->data, &c->p[i].p,
3605 			c->p[i].x, c->p[i].y, c->p[i].n, c->p[i].r, c->p[i].f, c->p[i].d, &a->w_act);
3606 	}
3607 }
3608 
window_cmd_roll_draw_text(struct w_cmd * w)3609 static void window_cmd_roll_draw_text(struct w_cmd *w) {
3610 	struct a_window *a;
3611 
3612 	struct text_2 *c;
3613 
3614 	if((a = window_get_struct_by_handle(w->h)) == NULL) return;
3615 
3616 	c = (struct text_2 *) w->p;
3617 
3618 	(void) window_cmd_roll_draw_text_op(a, c);
3619 }
3620 
window_cmd_roll_draw_texts(struct w_cmd * w)3621 static void window_cmd_roll_draw_texts(struct w_cmd *w) {
3622 	unsigned int i;
3623 
3624 	struct a_window *a;
3625 
3626 	struct texts_2 *c;
3627 
3628 	if((a = window_get_struct_by_handle(w->h)) == NULL) return;
3629 
3630 	c = (struct texts_2 *) w->p;
3631 
3632 	for(i = 0; i < c->c; i++) (void) window_cmd_roll_draw_text_op(a, &c->p[i]);
3633 }
3634 
window_cmd_roll_draw_text_op(struct a_window * a,struct text_2 * c)3635 static void window_cmd_roll_draw_text_op(struct a_window *a, struct text_2 *c) {
3636 	unsigned int x, y, z;
3637 	unsigned int e, f, u, v;
3638 
3639 	uint32_t r;
3640 
3641 	struct clip_2 k;
3642 	struct pixel_rgba_8 *m, *n, *o, *p;
3643 
3644 	u = fonts_get_width(c->f);
3645 	v = fonts_get_height(c->f);
3646 
3647 	/* Handle clipping if needed */
3648 	k.x = c->x;
3649 	k.y = c->y;
3650 
3651 	k.s.width = a->w_act.s.width;
3652 	k.s.height = a->w_act.s.height;
3653 
3654 	if(window_cmd_clip(&k, &e, &f, &u, &v) != 0) return;
3655 
3656 	/* Render text */
3657 	z = fonts_get_pitch(c->f);
3658 	p = fonts_get_content(c->f);
3659 
3660 	m = (struct pixel_rgba_8 *) a->shm_i->data;
3661 	m += (k.y * k.s.width) + k.x;
3662 
3663 	for(y = f; y < v; y++) {
3664 		n = m + ((y - f) * k.s.width);
3665 		o = p + (y * z);
3666 
3667 		for(x = e; x < u; x++) {
3668 			r = draw_pixel_alpha_rgba_8(n[x - e].pixel.p, o[x].pixel.p, (uint32_t) o[x].pixel.a);
3669 
3670 			n[x - e].pixel.p = r;
3671 		}
3672 	}
3673 }
3674 
window_cmd_roll_draw_set(struct w_cmd * w)3675 static void window_cmd_roll_draw_set(struct w_cmd *w) {
3676 	unsigned int x, y;
3677 	unsigned int e, f, u, v;
3678 
3679 	struct a_window *a;
3680 
3681 	struct clip_2 k;
3682 	struct point_4 *c;
3683 	struct pixel_rgba_8 *m, *n;
3684 
3685 	if((a = window_get_struct_by_handle(w->h)) == NULL) return;
3686 
3687 	c = (struct point_4 *) w->p;
3688 
3689 	/* Handle clipping if needed */
3690 	k.x = c->x1;
3691 	k.y = c->y1;
3692 
3693 	u = c->x2 - c->x1;
3694 	v = c->y2 - c->y1;
3695 
3696 	k.s.width = a->w_act.s.width;
3697 	k.s.height = a->w_act.s.height;
3698 
3699 	if(window_cmd_clip(&k, &e, &f, &u, &v) != 0) return;
3700 
3701 	u += k.x;
3702 	v += k.y;
3703 
3704 	/* Render block */
3705 	m = (struct pixel_rgba_8 *) a->shm_i->data;
3706 
3707 	for(y = k.y; y < v - f; y++) {
3708 		n = m + (y * a->w_act.s.width);
3709 
3710 		for(x = k.x; x < u - e; x++) n[x].pixel.p = c->p.pixel.p;
3711 	}
3712 }
3713 
window_cmd_roll_draw_set_alpha(struct w_cmd * w)3714 static void window_cmd_roll_draw_set_alpha(struct w_cmd *w) {
3715 	unsigned int x, y;
3716 	unsigned int e, f, u, v;
3717 
3718 	uint32_t r;
3719 
3720 	struct a_window *a;
3721 
3722 	struct clip_2 k;
3723 	struct point_4 *c;
3724 	struct pixel_rgba_8 *m, *n;
3725 
3726 	if((a = window_get_struct_by_handle(w->h)) == NULL) return;
3727 
3728 	c = (struct point_4 *) w->p;
3729 
3730 	/* Handle clipping if needed */
3731 	k.x = c->x1;
3732 	k.y = c->y1;
3733 
3734 	u = c->x2 - c->x1;
3735 	v = c->y2 - c->y1;
3736 
3737 	k.s.width = a->w_act.s.width;
3738 	k.s.height = a->w_act.s.height;
3739 
3740 	if(window_cmd_clip(&k, &e, &f, &u, &v) != 0) return;
3741 
3742 	u += k.x;
3743 	v += k.y;
3744 
3745 	/* Render block */
3746 	m = (struct pixel_rgba_8 *) a->shm_i->data;
3747 
3748 	for(y = k.y; y < v - f; y++) {
3749 		n = m + (y * a->w_act.s.width);
3750 
3751 		for(x = k.x; x < u - e; x++) {
3752 			r = draw_pixel_alpha_rgba_8(n[x].pixel.p, c->p.pixel.p, (uint32_t) c->p.pixel.a);
3753 
3754 			n[x].pixel.p = r;
3755 		}
3756 	}
3757 }
3758 
window_cmd_roll_draw_border(struct w_cmd * w)3759 static void window_cmd_roll_draw_border(struct w_cmd *w) {
3760 	unsigned int i, j, k, h;
3761 
3762 	struct a_window *a;
3763 
3764 	struct border_4 *c;
3765 	struct pixel_rgba_8 *m;
3766 
3767 	if((a = window_get_struct_by_handle(w->h)) == NULL) return;
3768 
3769 	c = (struct border_4 *) w->p;
3770 
3771 	if(c->t == 0) return;
3772 
3773 	h = c->t;
3774 	k = VALUE_MIN2(c->w, c->h) / 2;
3775 
3776 	if(h > k) h = k;
3777 
3778 	m = (struct pixel_rgba_8 *) a->shm_i->data;
3779 
3780 	/* Horizontal borders */
3781 	for(i = 0; i < h; i++) {
3782 		for(j = 0; j < c->w; j++) {
3783 			(void) draw_pixel(m, &c->p, c->x + j, c->y + i, &a->w_act);
3784 			(void) draw_pixel(m, &c->p, c->x + j, c->y + c->h - i - 1, &a->w_act);
3785 		}
3786 	}
3787 
3788 	/* Vertical borders, dont overwrite corners */
3789 	for(i = h; i < c->h - h; i++) {
3790 		for(j = 0; j < h; j++) {
3791 			(void) draw_pixel(m, &c->p, c->x + j, c->y + i, &a->w_act);
3792 			(void) draw_pixel(m, &c->p, c->x + c->w - j - 1, c->y + i, &a->w_act);
3793 		}
3794 	}
3795 }
3796 
window_cmd_roll_draw_border_alpha(struct w_cmd * w)3797 static void window_cmd_roll_draw_border_alpha(struct w_cmd *w) {
3798 	unsigned int i, j, k, h;
3799 
3800 	struct a_window *a;
3801 
3802 	struct border_4 *c;
3803 	struct pixel_rgba_8 *m;
3804 
3805 	if((a = window_get_struct_by_handle(w->h)) == NULL) return;
3806 
3807 	c = (struct border_4 *) w->p;
3808 
3809 	if(c->t == 0 || c->p.pixel.a == 0) return;
3810 
3811 	h = c->t;
3812 	k = VALUE_MIN2(c->w, c->h) / 2;
3813 
3814 	if(h > k) h = k;
3815 
3816 	m = (struct pixel_rgba_8 *) a->shm_i->data;
3817 
3818 	/* Horizontal borders */
3819 	for(i = 0; i < h; i++) {
3820 		for(j = 0; j < c->w; j++) {
3821 			(void) draw_pixel_alpha(m, &c->p, c->x + j, c->y + i, &a->w_act);
3822 			(void) draw_pixel_alpha(m, &c->p, c->x + j, c->y + c->h - i - 1, &a->w_act);
3823 		}
3824 	}
3825 
3826 	/* Vertical borders, dont overwrite corners */
3827 	for(i = h; i < c->h - h; i++) {
3828 		for(j = 0; j < h; j++) {
3829 			(void) draw_pixel_alpha(m, &c->p, c->x + j, c->y + i, &a->w_act);
3830 			(void) draw_pixel_alpha(m, &c->p, c->x + c->w - j - 1, c->y + i, &a->w_act);
3831 		}
3832 	}
3833 }
3834 
window_cmd_roll_draw_copy(struct w_cmd * w)3835 static void window_cmd_roll_draw_copy(struct w_cmd *w) {
3836 	unsigned int y;
3837 	unsigned int e, f, g, h, u, v;
3838 
3839 	char *c_d, *c_s;
3840 
3841 	struct a_window *a;
3842 
3843 	struct clip_2 d, s;
3844 	struct region_copy_8 *c;
3845 	struct pixel_rgba_8 *m, *n;
3846 
3847 	if((a = window_get_struct_by_handle(w->h)) == NULL) return;
3848 
3849 	c = (struct region_copy_8 *) w->p;
3850 
3851 	if(c->p == NULL) {
3852 		c->p = (struct pixel_rgba_8 *) a->shm_i->data;
3853 
3854 		c->s.width = a->w_act.s.width;
3855 		c->s.height = a->w_act.s.height;
3856 	}
3857 
3858 	/* Handle destination clipping if needed */
3859 	s.x = c->sx;
3860 	s.y = c->sy;
3861 
3862 	s.s.width = c->s.width;
3863 	s.s.height = c->s.height;
3864 
3865 	u = s.s.width;
3866 	v = s.s.height;
3867 
3868 	if(window_cmd_clip(&s, &e, &f, &u, &v) != 0) return;
3869 
3870 	d.x = c->dx;
3871 	d.y = c->dy;
3872 
3873 	u = c->c.width;
3874 	v = c->c.height;
3875 
3876 	d.s.width = a->w_act.s.width;
3877 	d.s.height = a->w_act.s.height;
3878 
3879 	if(window_cmd_clip(&d, &g, &h, &u, &v) != 0) return;
3880 
3881 	/* Copy block */
3882 	m = (struct pixel_rgba_8 *) a->shm_i->data;
3883 	n = (struct pixel_rgba_8 *) c->p;
3884 
3885 	m += (d.y * d.s.width) + d.x;
3886 	n += (s.y * s.s.width) + s.x;
3887 
3888 	for(y = 0; y < v - h; y++) {
3889 		c_d = (char *) m + ((y * d.s.width) * sizeof(struct pixel_rgba_8));
3890 		c_s = (char *) n + ((y * s.s.width) * sizeof(struct pixel_rgba_8));
3891 
3892 		(void) memmove((void *) c_d, (const void *) c_s, (u - g) * sizeof(struct pixel_rgba_8));
3893 	}
3894 }
3895 
window_cmd_roll_draw_copy_alpha(struct w_cmd * w)3896 static void window_cmd_roll_draw_copy_alpha(struct w_cmd *w) {
3897 	unsigned int x, y;
3898 	unsigned int e, f, u, v;
3899 
3900 	uint32_t r;
3901 
3902 	struct a_window *a;
3903 
3904 	struct clip_2 d, s;
3905 	struct region_copy_8 *c;
3906 	struct pixel_rgba_8 *m, *n, *o;
3907 
3908 	if((a = window_get_struct_by_handle(w->h)) == NULL) return;
3909 
3910 	c = (struct region_copy_8 *) w->p;
3911 
3912 	if(c->p == NULL) {
3913 		c->p = (struct pixel_rgba_8 *) a->shm_i->data;
3914 
3915 		c->s.width = a->w_act.s.width;
3916 		c->s.height = a->w_act.s.height;
3917 	}
3918 
3919 	/* Handle destination clipping if needed */
3920 	s.x = c->sx;
3921 	s.y = c->sy;
3922 
3923 	s.s.width = c->s.width;
3924 	s.s.height = c->s.height;
3925 
3926 	u = s.s.width;
3927 	v = s.s.height;
3928 
3929 	if(window_cmd_clip(&s, &e, &f, &u, &v) != 0) return;
3930 
3931 	d.x = c->dx;
3932 	d.y = c->dy;
3933 
3934 	u = c->c.width;
3935 	v = c->c.height;
3936 
3937 	d.s.width = a->w_act.s.width;
3938 	d.s.height = a->w_act.s.height;
3939 
3940 	if(window_cmd_clip(&d, &e, &f, &u, &v) != 0) return;
3941 
3942 	/* Copy block */
3943 	m = (struct pixel_rgba_8 *) a->shm_i->data;
3944 	m += (d.y * d.s.width) + d.x;
3945 
3946 	for(y = f; y < v; y++) {
3947 		n = m + ((y - f) * d.s.width);
3948 		o = c->p + (y * c->s.width);
3949 
3950 		for(x = e; x < u; x++) {
3951 			r = draw_pixel_alpha_rgba_8(n[x - e].pixel.p, o[x].pixel.p, (uint32_t) o[x].pixel.a);
3952 
3953 			n[x - e].pixel.p = r;
3954 		}
3955 	}
3956 }
3957 
window_cmd_roll_draw_wipe(struct w_cmd * w)3958 static void window_cmd_roll_draw_wipe(struct w_cmd *w) {
3959 	struct a_window *a;
3960 
3961 	if((a = window_get_struct_by_handle(w->h)) == NULL) return;
3962 
3963 	(void) memset((void *) a->shm_i->data, 0,
3964 		(a->w_act.s.height * a->w_act.s.width) * sizeof(struct pixel_rgba_8));
3965 }
3966 
window_cmd_roll_window_open(struct t_str * tp,struct w_cmd * w)3967 static void window_cmd_roll_window_open(struct t_str *tp, struct w_cmd *w) {
3968 	struct w_ctx *c;
3969 
3970 	c = (struct w_ctx *) w->p;
3971 
3972 	(void) window_open(tp, c);
3973 
3974 	/* Free the bits allocated by gui_window_open() */
3975 	if(c->s != NULL) (void) free(c->s);
3976 	if(c->c != NULL) (void) free(c->c);
3977 
3978 	if(c->par_main_loop.s != NULL) (void) free(c->par_main_loop.s);
3979 
3980 	if(c->par_expose.s != NULL) (void) free(c->par_expose.s);
3981 
3982 	if(c->par_key_press.s != NULL) (void) free(c->par_key_press.s);
3983 	if(c->par_key_release.s != NULL) (void) free(c->par_key_release.s);
3984 	if(c->par_button_press.s != NULL) (void) free(c->par_button_press.s);
3985 	if(c->par_button_release.s != NULL) (void) free(c->par_button_release.s);
3986 
3987 	if(c->par_client_message.s != NULL) (void) free(c->par_client_message.s);
3988 
3989 	if(c->par_configure_notify.s != NULL) (void) free(c->par_configure_notify.s);
3990 	if(c->par_destroy_notify.s != NULL) (void) free(c->par_destroy_notify.s);
3991 	if(c->par_motion_notify.s != NULL) (void) free(c->par_motion_notify.s);
3992 	if(c->par_map_notify.s != NULL) (void) free(c->par_map_notify.s);
3993 	if(c->par_unmap_notify.s != NULL) (void) free(c->par_unmap_notify.s);
3994 
3995 	if(c->par_open_notify.s != NULL) (void) free(c->par_open_notify.s);
3996 }
3997 
window_cmd_roll_window_icon(struct w_cmd * w)3998 static void window_cmd_roll_window_icon(struct w_cmd *w) {
3999 	char *c;
4000 
4001 	if((c = (char *) w->p) == NULL) return;
4002 
4003 	if(window_get_struct_by_handle(w->h) == NULL) {
4004 		(void) free(w->p);
4005 
4006 		return;
4007 	}
4008 
4009 	(void) window_icon(w->h, c);
4010 }
4011 
window_cmd_roll_window_close(struct w_cmd * w)4012 static void window_cmd_roll_window_close(struct w_cmd *w) {
4013 	(void) window_close(w->h);
4014 }
4015 
window_cmd_roll_window_map(struct w_cmd * w)4016 static void window_cmd_roll_window_map(struct w_cmd *w) {
4017 	struct a_window *a;
4018 
4019 	if((a = window_get_struct_by_handle(w->h)) == NULL) return;
4020 
4021 	/* Set window pre-attributes if needed */
4022 	if(a->h == 0) (void) window_cmd_roll_window_map_op(a, w->h, IS_YES);
4023 
4024 	a->s = WINDOW_STATE_MAPPED;
4025 
4026 	(void) XLockDisplay(a->d);
4027 	(void) XMapWindow(a->d, a->w);
4028 	(void) XUnlockDisplay(a->d);
4029 
4030 	/* Set window post-attributes if needed */
4031 	if(a->h == 0) (void) window_cmd_roll_window_map_op(a, w->h, IS_NO);
4032 }
4033 
window_cmd_roll_window_map_op(struct a_window * a,unsigned int h,unsigned int u)4034 static void window_cmd_roll_window_map_op(struct a_window *a, unsigned int h, unsigned int u) {
4035 	char *e, *f, *p, *r, *s;
4036 
4037 	size_t t;
4038 
4039 	struct c_f c_f_t[] = {
4040 		{ "above", NULL, 0.0, CONFIG_TYPE_BOOLEAN_NO, 0, CONFIG_TYPE_BOOLEAN },
4041 		{ "below", NULL, 0.0, CONFIG_TYPE_BOOLEAN_NO, 0, CONFIG_TYPE_BOOLEAN },
4042 		{ "desktop", NULL, 0.0, 0, 0, CONFIG_TYPE_INTEGER },
4043 		{ "noborder", NULL, 0.0, CONFIG_TYPE_BOOLEAN_NO, 0, CONFIG_TYPE_BOOLEAN },
4044 		{ "nopager", NULL, 0.0, CONFIG_TYPE_BOOLEAN_NO, 0, CONFIG_TYPE_BOOLEAN },
4045 		{ "notaskbar", NULL, 0.0, CONFIG_TYPE_BOOLEAN_NO, 0, CONFIG_TYPE_BOOLEAN },
4046 		{ "opaque", NULL, 0.0, 0, 0, CONFIG_TYPE_FLOAT },
4047 		{ "sticky", NULL, 0.0, CONFIG_TYPE_BOOLEAN_NO, 0, CONFIG_TYPE_BOOLEAN },
4048 		{ "x", NULL, 0.0, 0, 0, CONFIG_TYPE_INTEGER },
4049 		{ "y", NULL, 0.0, 0, 0, CONFIG_TYPE_INTEGER },
4050 
4051 		{ NULL, NULL, 0.0, 0, 0, 0 }
4052 	};
4053 
4054 	if((s = (char *) conf_fetch("window_attributes")) == NULL) return;
4055 
4056 	/* First make a copy of original settings string... */
4057 	t = str_len(s, STRING_ASCII);
4058 
4059 	APP_MALLOC_RET_VOID(p, t + (sizeof(char) * 2));
4060 
4061 	(void) memcpy((void *) p, (const void *) s, t);
4062 
4063 	p[t++] = CONFIG_LINE_FEED;
4064 	p[t] = 0;
4065 
4066 	if((e = str_chr((const char *) p, ':')) == NULL) {
4067 		(void) free(p);
4068 
4069 		return;
4070 	}
4071 
4072 	*e = 0;
4073 
4074 	if((++e)[0] == 0) {
4075 		(void) free(p);
4076 
4077 		return;
4078 	}
4079 
4080 	/* ...then try to fetch window name which is hopefully set... */
4081 	r = NULL;
4082 
4083 	(void) XLockDisplay(a->d);
4084 
4085 	if(XFetchName(a->d, a->w, &r) == 0) {
4086 		(void) XUnlockDisplay(a->d);
4087 
4088 		(void) free(p);
4089 
4090 		return;
4091 	}
4092 
4093 	if(r == NULL) {
4094 		(void) XUnlockDisplay(a->d);
4095 
4096 		(void) free(p);
4097 
4098 		return;
4099 	}
4100 
4101 	/* ...and check if window name is there */
4102 	t = str_len(p, STRING_ASCII);
4103 
4104 	if(str_len(r, STRING_ASCII) == t) {
4105 		if(strncmp((const char *) p, (const char *) r, t) == 0) {
4106 			/* Convert pipes to line-ends for config parser */
4107 			while(1) {
4108 				if((f = str_chr((const char *) e, '|')) == NULL) {
4109 					if(*e != 0) (void) conf_read_line((void *) c_f_t, e, 1);
4110 
4111 					break;
4112 				}
4113 
4114 				if((f = str_chr((const char *) ++f, '|')) == NULL) break;
4115 
4116 				(f - 1)[0] = CONFIG_LINE_FEED;
4117 				(f++)[0] = 0;
4118 
4119 				if(*e != 0) (void) conf_read_line((void *) c_f_t, e, 1);
4120 
4121 				e = f;
4122 			}
4123 
4124 			(void) window_cmd_roll_window_map_at(c_f_t, h, u);
4125 			(void) conf_free_op((void *) c_f_t);
4126 		}
4127 	}
4128 
4129 	(void) free(p);
4130 
4131 	(void) XFree(r);
4132 	(void) XUnlockDisplay(a->d);
4133 }
4134 
window_cmd_roll_window_map_at(struct c_f * c_f_t,unsigned int h,unsigned int u)4135 static void window_cmd_roll_window_map_at(struct c_f *c_f_t, unsigned int h, unsigned int u) {
4136 	unsigned int i;
4137 
4138 	int *c;
4139 	double *d;
4140 
4141 	struct w_cmd r;
4142 	struct w_att p;
4143 
4144 	struct c_a c_a_t[] = {
4145 		{ "above", IS_YES, CONFIG_TYPE_BOOLEAN, WINDOW_ATTR_ABOVE },
4146 		{ "below", IS_YES, CONFIG_TYPE_BOOLEAN, WINDOW_ATTR_BELOW },
4147 		{ "desktop", IS_YES, CONFIG_TYPE_INTEGER, WINDOW_ATTR_DESKTOP },
4148 		{ "noborder", IS_YES, CONFIG_TYPE_BOOLEAN, WINDOW_ATTR_BORDER },
4149 		{ "nopager", IS_YES, CONFIG_TYPE_BOOLEAN, WINDOW_ATTR_SKIP_PAGER },
4150 		{ "notaskbar", IS_YES, CONFIG_TYPE_BOOLEAN, WINDOW_ATTR_SKIP_TASKBAR },
4151 		{ "opaque", IS_YES, CONFIG_TYPE_FLOAT, WINDOW_ATTR_TRANSPARENCY },
4152 		{ "sticky", IS_YES, CONFIG_TYPE_BOOLEAN, WINDOW_ATTR_STICKY },
4153 		{ "x", IS_YES, CONFIG_TYPE_INTEGER, WINDOW_ATTR_POS_X },
4154 		{ "y", IS_YES, CONFIG_TYPE_INTEGER, WINDOW_ATTR_POS_Y },
4155 
4156 		{ NULL, 0, 0, 0 }
4157 	};
4158 
4159 	r.c = WINDOW_COMMAND_NONE;
4160 	r.e = IS_NO;
4161 	r.h = h;
4162 	r.p = (void *) &p;
4163 	r.t = sizeof(struct w_att);
4164 
4165 	for(i = 0; ; i++) {
4166 		if(c_a_t[i].s == NULL) break;
4167 		if(c_a_t[i].p != u) continue;
4168 
4169 		switch(c_a_t[i].t) {
4170 			case CONFIG_TYPE_BOOLEAN:
4171 				if((c = (int *) conf_fetch_op((void *) c_f_t, c_a_t[i].s)) != NULL) {
4172 					if(*c == IS_YES) {
4173 						p.c = c_a_t[i].c;
4174 						p.v = 0.0;
4175 
4176 						(void) window_cmd_roll_window_set_attrs(&r);
4177 					}
4178 				}
4179 
4180 				break;
4181 			case CONFIG_TYPE_INTEGER:
4182 				if((c = (int *) conf_fetch_op((void *) c_f_t, c_a_t[i].s)) != NULL) {
4183 					p.c = c_a_t[i].c;
4184 					p.v = (double) *c;
4185 
4186 					(void) window_cmd_roll_window_set_attrs(&r);
4187 				}
4188 
4189 				break;
4190 			case CONFIG_TYPE_FLOAT:
4191 				if((d = (double *) conf_fetch_op((void *) c_f_t, c_a_t[i].s)) != NULL) {
4192 					p.c = c_a_t[i].c;
4193 					p.v = (double) *d;
4194 
4195 					(void) window_cmd_roll_window_set_attrs(&r);
4196 				}
4197 
4198 				break;
4199 			default:
4200 				break;
4201 		}
4202 	}
4203 }
4204 
window_cmd_roll_window_unmap(struct w_cmd * w)4205 static void window_cmd_roll_window_unmap(struct w_cmd *w) {
4206 	struct a_window *a;
4207 
4208 	if((a = window_get_struct_by_handle(w->h)) == NULL) return;
4209 
4210 	a->s = WINDOW_STATE_UNMAPPED;
4211 
4212 	(void) XLockDisplay(a->d);
4213 	(void) XUnmapWindow(a->d, a->w);
4214 	(void) XUnlockDisplay(a->d);
4215 }
4216 
window_cmd_roll_window_set_attrs(struct w_cmd * w)4217 static void window_cmd_roll_window_set_attrs(struct w_cmd *w) {
4218 	long k;
4219 	double d;
4220 
4221 	Atom p, v;
4222 	XSetWindowAttributes u;
4223 	XWindowChanges y;
4224 
4225 	struct a_window *a;
4226 	struct w_att *c;
4227 
4228 	if((a = window_get_struct_by_handle(w->h)) == NULL) return;
4229 
4230 	c = (struct w_att *) w->p;
4231 
4232 	(void) XLockDisplay(a->d);
4233 
4234 	switch(c->c) {
4235 		case WINDOW_ATTR_ABOVE:
4236 			if(a->s == WINDOW_STATE_MAPPED) {
4237 				if((p = XInternAtom(a->d, "_NET_WM_STATE", False)) == 0) break;
4238 				if((v = XInternAtom(a->d, "_NET_WM_STATE_ABOVE", False)) == 0) break;
4239 
4240 				(void) window_cmd_roll_window_set_attrs_op(a, WINDOW_ATTR_STATE_ADD, p, v);
4241 			}
4242 			else {
4243 				if((p = XInternAtom(a->d, "_NET_WM_STATE", False)) != 0) {
4244 					if((v = XInternAtom(a->d, "_NET_WM_STATE_ABOVE", False)) == 0) break;
4245 
4246 					(void) XChangeProperty(
4247 						a->d, a->w, p, XA_ATOM, 32, PropModeAppend,
4248 						(unsigned char *) &v, 1);
4249 				}
4250 
4251 				if((p = XInternAtom(a->d, "_WIN_LAYER", False)) != 0) {
4252 					k = 6;
4253 
4254 					(void) XChangeProperty(
4255 						a->d, a->w, p, XA_CARDINAL, 32, PropModeAppend,
4256 						(unsigned char *) &k, 1);
4257 				}
4258 			}
4259 
4260 			break;
4261 		case WINDOW_ATTR_BELOW:
4262 			if(a->s == WINDOW_STATE_MAPPED) {
4263 				if((p = XInternAtom(a->d, "_NET_WM_STATE", False)) == 0) break;
4264 				if((v = XInternAtom(a->d, "_NET_WM_STATE_BELOW", False)) == 0) break;
4265 
4266 				(void) window_cmd_roll_window_set_attrs_op(a, WINDOW_ATTR_STATE_ADD, p, v);
4267 			}
4268 			else {
4269 				if((p = XInternAtom(a->d, "_NET_WM_STATE", False)) != 0) {
4270 					if((v = XInternAtom(a->d, "_NET_WM_STATE_BELOW", False)) == 0) break;
4271 
4272 					(void) XChangeProperty(
4273 						a->d, a->w, p, XA_ATOM, 32, PropModeAppend,
4274 						(unsigned char *) &v, 1);
4275 				}
4276 
4277 				if((p = XInternAtom(a->d, "_WIN_LAYER", False)) != 0) {
4278 					k = 2;
4279 
4280 					(void) XChangeProperty(
4281 						a->d, a->w, p, XA_CARDINAL, 32, PropModeAppend,
4282 						(unsigned char *) &k, 1);
4283 				}
4284 			}
4285 
4286 			break;
4287 		case WINDOW_ATTR_BORDER:
4288 			(void) memset((void *) &u, 0, sizeof(u));
4289 
4290 			if(c->v > 0.0) {
4291 				u.override_redirect = False;
4292 			}
4293 			else {
4294 				u.override_redirect = True;
4295 			}
4296 
4297 			(void) XChangeWindowAttributes(a->d, a->w, CWOverrideRedirect, &u);
4298 
4299 			break;
4300 		case WINDOW_ATTR_DESKTOP:
4301 			if((p = XInternAtom(a->d, "_NET_WM_DESKTOP", False)) == 0) break;
4302 
4303 			k = (long) round(c->v);
4304 
4305 			if(a->s == WINDOW_STATE_MAPPED) {
4306 				(void) window_cmd_roll_window_set_attrs_op(a, k, p, 0);
4307 			}
4308 			else {
4309 				++k;
4310 
4311 				(void) XChangeProperty(
4312 					a->d, a->w, p, XA_CARDINAL, 32, PropModeAppend,
4313 					(unsigned char *) &k, 1);
4314 			}
4315 
4316 			break;
4317 		case WINDOW_ATTR_POS_X:
4318 			(void) memset((void *) &y, 0, sizeof(y));
4319 
4320 			y.x = (int) round(c->v);
4321 
4322 			(void) XConfigureWindow(a->d, a->w, CWX, &y);
4323 			(void) XFlush(a->d);
4324 
4325 			break;
4326 		case WINDOW_ATTR_POS_Y:
4327 			(void) memset((void *) &y, 0, sizeof(y));
4328 
4329 			y.y = (int) round(c->v);
4330 
4331 			(void) XConfigureWindow(a->d, a->w, CWY, &y);
4332 			(void) XFlush(a->d);
4333 
4334 			break;
4335 		case WINDOW_ATTR_SKIP_PAGER:
4336 			if((p = XInternAtom(a->d, "_NET_WM_STATE", False)) == 0) break;
4337 			if((v = XInternAtom(a->d, "_NET_WM_STATE_SKIP_PAGER", False)) == 0) break;
4338 
4339 			if(a->s == WINDOW_STATE_MAPPED) {
4340 				(void) window_cmd_roll_window_set_attrs_op(a, WINDOW_ATTR_STATE_ADD, p, v);
4341 			}
4342 			else {
4343 				(void) XChangeProperty(
4344 					a->d, a->w, p, XA_ATOM, 32, PropModeAppend,
4345 					(unsigned char *) &v, 1);
4346 			}
4347 
4348 			break;
4349 		case WINDOW_ATTR_SKIP_TASKBAR:
4350 			if((p = XInternAtom(a->d, "_NET_WM_STATE", False)) == 0) break;
4351 			if((v = XInternAtom(a->d, "_NET_WM_STATE_SKIP_TASKBAR", False)) == 0) break;
4352 
4353 			if(a->s == WINDOW_STATE_MAPPED) {
4354 				(void) window_cmd_roll_window_set_attrs_op(a, WINDOW_ATTR_STATE_ADD, p, v);
4355 			}
4356 			else {
4357 				(void) XChangeProperty(
4358 					a->d, a->w, p, XA_ATOM, 32, PropModeAppend,
4359 					(unsigned char *) &v, 1);
4360 			}
4361 
4362 			break;
4363 		case WINDOW_ATTR_STICKY:
4364 			if((p = XInternAtom(a->d, "_NET_WM_DESKTOP", False)) == 0) break;
4365 
4366 			k = 0xffffffff;
4367 
4368 			if(a->s == WINDOW_STATE_MAPPED) {
4369 				(void) window_cmd_roll_window_set_attrs_op(a, k, p, 0);
4370 
4371 				if((p = XInternAtom(a->d, "_NET_WM_STATE", False)) == 0) break;
4372 				if((v = XInternAtom(a->d, "_NET_WM_STATE_STICKY", False)) == 0) break;
4373 
4374 				(void) window_cmd_roll_window_set_attrs_op(a, WINDOW_ATTR_STATE_ADD, p, v);
4375 			}
4376 			else {
4377 				(void) XChangeProperty(
4378 					a->d, a->w, p, XA_CARDINAL, 32, PropModeAppend,
4379 					(unsigned char *) &k, 1);
4380 
4381 				if((p = XInternAtom(a->d, "_NET_WM_STATE", False)) == 0) break;
4382 				if((v = XInternAtom(a->d, "_NET_WM_STATE_STICKY", False)) == 0) break;
4383 
4384 				(void) XChangeProperty(
4385 					a->d, a->w, p, XA_ATOM, 32, PropModeAppend,
4386 					(unsigned char *) &v, 1);
4387 			}
4388 
4389 			break;
4390 		case WINDOW_ATTR_TRANSPARENCY:
4391 			if((p = XInternAtom(a->d, "_NET_WM_WINDOW_OPACITY", False)) == 0) break;
4392 
4393 			d = c->v;
4394 
4395 			if(d < 0.0) d = 0.0;
4396 			if(d > 1.0) d = 1.0;
4397 
4398 			k = (long) round(0xffffffff * d);
4399 
4400 			if(k == 0) ++k;
4401 
4402 			if(a->s == WINDOW_STATE_MAPPED) {
4403 				(void) window_cmd_roll_window_set_attrs_op(a, k, p, 0);
4404 			}
4405 			else {
4406 				(void) XChangeProperty(
4407 					a->d, a->w, p, XA_CARDINAL, 32, PropModeReplace,
4408 					(unsigned char *) &k, 1);
4409 			}
4410 
4411 			break;
4412 		default:
4413 			break;
4414 	}
4415 
4416 	(void) XUnlockDisplay(a->d);
4417 }
4418 
window_cmd_roll_window_set_attrs_op(struct a_window * a,long c,Atom p,Atom v)4419 static void window_cmd_roll_window_set_attrs_op(struct a_window *a, long c, Atom p, Atom v) {
4420 	XEvent e;
4421 
4422 	(void) memset((void *) &e, 0, sizeof(e));
4423 
4424 	e.xclient.type = ClientMessage;
4425 
4426 	e.xclient.display = a->d;
4427 	e.xclient.window = a->w;
4428 
4429 	e.xclient.message_type = p;
4430 	e.xclient.format = 32;
4431 
4432 	e.xclient.data.l[0] = c;
4433 	e.xclient.data.l[1] = v;
4434 	e.xclient.data.l[2] = 0;
4435 	e.xclient.data.l[3] = 0;
4436 	e.xclient.data.l[4] = 0;
4437 
4438 	(void) XSendEvent(
4439 		a->d, XDefaultRootWindow(a->d), False,
4440 		SubstructureRedirectMask | SubstructureNotifyMask, (XEvent *) &e);
4441 	(void) XFlush(a->d);
4442 }
4443 
window_cmd_roll_window_refresh(struct w_cmd * w)4444 static void window_cmd_roll_window_refresh(struct w_cmd *w) {
4445 	struct a_window *a;
4446 
4447 	struct clip_2 *c;
4448 
4449 	if((a = window_get_struct_by_handle(w->h)) == NULL) return;
4450 
4451 	/* Dont overwrite expose in progress */
4452 	if(a->z == WINDOW_OPERATION_EXPOSE) return;
4453 
4454 	c = (struct clip_2 *) w->p;
4455 
4456 	a->w_exp.x = c->x;
4457 	a->w_exp.y = c->y;
4458 	a->w_exp.s.width = c->s.width;
4459 	a->w_exp.s.height = c->s.height;
4460 
4461 	if(a->w_exp.s.width == 0) a->w_exp.s.width = a->w_act.s.width;
4462 	if(a->w_exp.s.height == 0) a->w_exp.s.height = a->w_act.s.height;
4463 
4464 	a->z = WINDOW_OPERATION_EXPOSE;
4465 }
4466 #if ! defined(PROG_DISABLE_BOB)
window_cmd_roll_window_bobs(void)4467 static void window_cmd_roll_window_bobs(void) {
4468 	unsigned int i, j;
4469 
4470 	struct w_bob b[2];
4471 	struct w_cmd c[2];
4472 
4473 	struct region_copy_8 p[2];
4474 
4475 	c[0].p = (void *) &p[0];
4476 	c[1].p = (void *) &p[1];
4477 
4478 	p[0].sx = 0;
4479 	p[0].sy = 0;
4480 	p[1].sx = 0;
4481 	p[1].sy = 0;
4482 
4483 	/* Hold on a while if bob container is locked */
4484 	(void) bob_locked();
4485 
4486 	/* First, loop through bob containers... */
4487 	for(i = 0; i < bob_begin(); i++) {
4488 		/* ...and then the bobs in that container */
4489 		for(j = 0; j < bob_count(i); j++) {
4490 			if(bob_get_frame(i, j, &b[0], &b[1]) != 0) continue;
4491 
4492 			c[0].h = b[0].hnd;
4493 
4494 			p[0].dx = b[0].x;
4495 			p[0].dy = b[0].y;
4496 
4497 			p[0].c.width = b[0].width;
4498 			p[0].c.height = b[0].height;
4499 			p[0].s.width = b[0].width;
4500 			p[0].s.height = b[0].height;
4501 
4502 			p[0].p = b[0].frame;
4503 
4504 			if(b[0].opaque != 0) {
4505 				/* Copy bob frame to window without alpha channel taking effect */
4506 				(void) window_cmd_roll_draw_copy(&c[0]);
4507 			}
4508 			else {
4509 				/* Copy bob frame and shadow to window, shadow first */
4510 				if(b[1].frame != NULL) {
4511 					/* Valid window handle is only in bob's structure, not shadow's */
4512 					c[1].h = b[0].hnd;
4513 
4514 					p[1].dx = b[1].x;
4515 					p[1].dy = b[1].y;
4516 
4517 					p[1].c.width = b[1].width;
4518 					p[1].c.height = b[1].height;
4519 					p[1].s.width = b[1].width;
4520 					p[1].s.height = b[1].height;
4521 
4522 					p[1].p = b[1].frame;
4523 
4524 					(void) window_cmd_roll_draw_copy_alpha(&c[1]);
4525 				}
4526 
4527 				(void) window_cmd_roll_draw_copy_alpha(&c[0]);
4528 			}
4529 		}
4530 	}
4531 
4532 	(void) bob_end();
4533 }
4534 #endif
window_cmd_roll_operation(struct a_window * a)4535 static void window_cmd_roll_operation(struct a_window *a) {
4536 	switch(a->z) {
4537 		case WINDOW_OPERATION_EXPOSE:
4538 			(void) window_event_send_expose(a);
4539 
4540 			a->z = WINDOW_OPERATION_NONE;
4541 
4542 			break;
4543 		default:
4544 			break;
4545 	}
4546 }
4547 
window_get_struct_by_handle(unsigned int w)4548 static struct a_window *window_get_struct_by_handle(unsigned int w) {
4549 	if(a_win == NULL || w == 0 || w > c_win) return(NULL);
4550 
4551 	return(a_win[w - 1]);
4552 }
4553 
window_get_struct_by_window(Window w)4554 static struct a_window *window_get_struct_by_window(Window w) {
4555 	unsigned int i;
4556 
4557 	if(a_win != NULL) {
4558 		for(i = 0; i < c_win; i++) {
4559 			if(a_win[i] == NULL) continue;
4560 
4561 			if(a_win[i]->w == w) return(a_win[i]);
4562 		}
4563 	}
4564 
4565 	return(NULL);
4566 }
4567 
worker_draw_get_refresh_rate(void)4568 static unsigned int worker_draw_get_refresh_rate(void) {
4569 	unsigned int *b;
4570 
4571 	if((b = (unsigned int *) conf_fetch("refresh_rate")) == NULL) return(WINDOW_UPDATE_FPS);
4572 
4573 	return(*b);
4574 }
4575 #endif
4576 #if ! defined(PROG_DISABLE_WIDGET)
window_get_widget_by_handle(unsigned int w)4577 struct w_stack *window_get_widget_by_handle(unsigned int w) {
4578 #if defined(PROG_HAS_X11)
4579 	struct a_window *a;
4580 
4581 	if((a = window_get_struct_by_handle(w)) == NULL) return(NULL);
4582 
4583 	return(&a->w_gui);
4584 #else
4585 	(void) w;
4586 
4587 	return(NULL);
4588 #endif
4589 }
4590 #endif
window_get_obscure(unsigned int h,unsigned int x,unsigned int y,struct pixel_rgba_8 * p)4591 struct t_img *window_get_obscure(unsigned int h, unsigned int x, unsigned int y, struct pixel_rgba_8 *p) {
4592 #if defined(PROG_HAS_X11)
4593 	int e, f;
4594 	unsigned int i, j, t, u, v;
4595 	unsigned int cx, cy, cw, ch;
4596 
4597 	Window c;
4598 	XImage *m;
4599 
4600 	struct clip_2 n;
4601 
4602 	struct a_window *a;
4603 	struct t_img *r;
4604 
4605 	if((a = window_get_struct_by_handle(h)) == NULL) return(NULL);
4606 
4607 	APP_MALLOC_RET_VALUE(r, sizeof(struct t_img), NULL);
4608 
4609 	e = 0;
4610 	f = 0;
4611 
4612 	(void) XLockDisplay(a->d);
4613 	(void) XTranslateCoordinates(a->d, a->w, a->r, 0, 0, &e, &f, &c);
4614 
4615 	/* Get root window bitmap and apply clipping if needed */
4616 	cw = x;
4617 	ch = y;
4618 
4619 	n.x = e;
4620 	n.y = f;
4621 
4622 	n.s.width = a->t->b.width;
4623 	n.s.height = a->t->b.height;
4624 
4625 	if(window_cmd_clip(&n, &cx, &cy, &cw, &ch) != 0) {
4626 		(void) XUnlockDisplay(a->d);
4627 
4628 		(void) free(r);
4629 
4630 		return(NULL);
4631 	}
4632 
4633 	if((m = XGetImage(a->d, a->r, n.x, n.y, cw, ch, AllPlanes, ZPixmap)) == NULL) {
4634 		(void) flush_error();
4635 
4636 		LOGWARN(
4637 			ERROR_SLIGHT, SUBSYSTEM,
4638 			_("Failed to get root window %lu image on screen %s.%d"),
4639 			(unsigned long) a->w, a->n, (int) a->c
4640 		);
4641 
4642 		(void) XUnlockDisplay(a->d);
4643 
4644 		(void) free(r);
4645 
4646 		return(NULL);
4647 	}
4648 
4649 	/* Allocate image and copy root window bitmap to it */
4650 	if((r->p = (struct pixel_rgba_8 *) malloc((m->width * m->height) * sizeof(struct pixel_rgba_8))) == NULL) {
4651 		LOGWARN(
4652 			ERROR_SLIGHT, SUBSYSTEM,
4653 			_("Failed to allocate %lu bytes of memory"),
4654 			(unsigned long) ((m->width * m->height) * sizeof(struct pixel_rgba_8))
4655 		);
4656 
4657 		(void) XDestroyImage(m);
4658 		(void) XUnlockDisplay(a->d);
4659 
4660 		(void) free(r);
4661 
4662 		return(NULL);
4663 	}
4664 
4665 	r->w = (int32_t) m->width;
4666 	r->h = (int32_t) m->height;
4667 	r->b = (int32_t) sizeof(struct pixel_rgba_8) * 8;
4668 
4669 	r->c = NULL;
4670 	r->t = 0;
4671 
4672 	t = window_get_obscure_at((unsigned long) m->red_mask);
4673 	u = window_get_obscure_at((unsigned long) m->green_mask);
4674 	v = window_get_obscure_at((unsigned long) m->blue_mask);
4675 
4676 	for(i = cy; i < ch - cy; i++) {
4677 		for(j = cx; j < cw - cx; j++) {
4678 			(void) window_get_obscure_op(m, r->p, p, (int) j, (int) i, (unsigned int) r->w, t, u, v);
4679 		}
4680 	}
4681 
4682 	(void) XDestroyImage(m);
4683 	(void) XUnlockDisplay(a->d);
4684 
4685 	return(r);
4686 #else
4687 	(void) h;
4688 	(void) x;
4689 	(void) y;
4690 	(void) p;
4691 
4692 	return(NULL);
4693 #endif
4694 }
4695 #if defined(PROG_HAS_X11)
window_get_obscure_op(XImage * m,struct pixel_rgba_8 * p,struct pixel_rgba_8 * g,int x,int y,unsigned int w,unsigned int t,unsigned int u,unsigned int v)4696 static void window_get_obscure_op(XImage *m, struct pixel_rgba_8 *p, struct pixel_rgba_8 *g, int x, int y, unsigned int w, unsigned int t, unsigned int u, unsigned int v) {
4697 	unsigned long q;
4698 
4699 	struct pixel_rgba_8 r;
4700 
4701 	q = XGetPixel(m, (int) x, (int) y);
4702 
4703 	r.pixel.r = (uint32_t) (q >> t);
4704 	r.pixel.g = (uint32_t) (q >> u);
4705 	r.pixel.b = (uint32_t) (q >> v);
4706 	r.pixel.a = 0;
4707 
4708 	p[(y * w) + x].pixel.p = draw_pixel_alpha_rgba_8(r.pixel.p, g->pixel.p, (uint32_t) g->pixel.a);
4709 }
4710 
window_get_obscure_at(unsigned long c)4711 static unsigned int window_get_obscure_at(unsigned long c) {
4712 	unsigned int i;
4713 
4714 	for(i = 0; i < 4; i++) {
4715 		if((c & 0xff) != 0) return(i * 8);
4716 
4717 		c >>= 8;
4718 	}
4719 
4720 	return(0);
4721 }
4722 #endif
window_get_pointer_root(unsigned int h,int * x,int * y)4723 void window_get_pointer_root(unsigned int h, int *x, int *y) {
4724 #if defined(PROG_HAS_X11)
4725 	int rx, ry, wx, wy;
4726 	unsigned int m;
4727 
4728 	Window r, c;
4729 
4730 	struct a_window *a;
4731 
4732 	if((a = window_get_struct_by_handle(h)) == NULL) return;
4733 
4734 	(void) XLockDisplay(a->d);
4735 	(void) XQueryPointer(a->d, a->w, &r, &c, &rx, &ry, &wx, &wy, &m);
4736 	(void) XUnlockDisplay(a->d);
4737 
4738 	*x = rx;
4739 	*y = ry;
4740 #else
4741 	(void) h;
4742 	(void) x;
4743 	(void) y;
4744 #endif
4745 }
4746 
window_get_active_width(unsigned int h)4747 unsigned int window_get_active_width(unsigned int h) {
4748 #if defined(PROG_HAS_X11)
4749 	struct a_window *a;
4750 
4751 	if((a = window_get_struct_by_handle(h)) == NULL) return(0);
4752 
4753 	return(a->w_act.s.width);
4754 #else
4755 	(void) h;
4756 
4757 	return(0);
4758 #endif
4759 }
4760 
window_get_active_height(unsigned int h)4761 unsigned int window_get_active_height(unsigned int h) {
4762 #if defined(PROG_HAS_X11)
4763 	struct a_window *a;
4764 
4765 	if((a = window_get_struct_by_handle(h)) == NULL) return(0);
4766 
4767 	return(a->w_act.s.height);
4768 #else
4769 	(void) h;
4770 
4771 	return(0);
4772 #endif
4773 }
4774 
window_get_dpi_width(void)4775 double window_get_dpi_width(void) {
4776 #if defined(PROG_HAS_X11)
4777 	return(x_dpi);
4778 #else
4779 	return(0.0);
4780 #endif
4781 }
4782 
window_get_dpi_height(void)4783 double window_get_dpi_height(void) {
4784 #if defined(PROG_HAS_X11)
4785 	return(y_dpi);
4786 #else
4787 	return(0.0);
4788 #endif
4789 }
4790 
window_get_mod_shift(void)4791 unsigned int window_get_mod_shift(void) {
4792 #if defined(PROG_HAS_X11)
4793 	return(WINDOW_KEY_MODIFIER_SHIFT);
4794 #else
4795 	return(0);
4796 #endif
4797 }
4798 
window_get_mod_lock(void)4799 unsigned int window_get_mod_lock(void) {
4800 #if defined(PROG_HAS_X11)
4801 	return(WINDOW_KEY_MODIFIER_LOCK);
4802 #else
4803 	return(0);
4804 #endif
4805 }
4806 
window_get_mod_ctrl(void)4807 unsigned int window_get_mod_ctrl(void) {
4808 #if defined(PROG_HAS_X11)
4809 	return(WINDOW_KEY_MODIFIER_CTRL);
4810 #else
4811 	return(0);
4812 #endif
4813 }
4814 
window_get_mod_cmd(void)4815 unsigned int window_get_mod_cmd(void) {
4816 #if defined(PROG_HAS_X11)
4817 	return(WINDOW_KEY_MODIFIER_CMD);
4818 #else
4819 	return(0);
4820 #endif
4821 }
4822 
window_get_mod_alt(void)4823 unsigned int window_get_mod_alt(void) {
4824 #if defined(PROG_HAS_X11)
4825 	return(WINDOW_KEY_MODIFIER_ALT);
4826 #else
4827 	return(0);
4828 #endif
4829 }
4830 
window_get_geometry(unsigned int h,struct rect_4 * r)4831 int window_get_geometry(unsigned int h, struct rect_4 *r) {
4832 #if defined(PROG_HAS_X11)
4833 	unsigned int b, d;
4834 
4835 	Window w, c;
4836 
4837 	struct a_window *a;
4838 
4839 	if((a = window_get_struct_by_handle(h)) == NULL) return(-1);
4840 
4841 	(void) XLockDisplay(a->d);
4842 
4843 	if(XGetGeometry(a->d, a->w, &w, &r->left, &r->top, &r->s.width, &r->s.height, &b, &d) == 0) {
4844 		(void) flush_error();
4845 
4846 		LOGWARN(
4847 			ERROR_SLIGHT, SUBSYSTEM,
4848 			_("Failed to get window %lu attributes on screen %s.%d"),
4849 			(unsigned long) a->w, a->n, (int) a->c
4850 		);
4851 
4852 		(void) XUnlockDisplay(a->d);
4853 
4854 		return(-1);
4855 	}
4856 
4857 	(void) XTranslateCoordinates(a->d, a->w, w, 0, 0, &r->left, &r->top, &c);
4858 	(void) XUnlockDisplay(a->d);
4859 #else
4860 	(void) h;
4861 
4862 	r->left = 0;
4863 	r->top = 0;
4864 
4865 	r->s.width = 0;
4866 	r->s.height = 0;
4867 #endif
4868 	r->right = r->left + r->s.width;
4869 	r->bottom = r->top + r->s.height;
4870 
4871 	return(0);
4872 }
4873 #if defined(PROG_HAS_X11) && defined(PROG_HAS_DRAWPIXELS) && ! defined(PROG_HAS_POSIX_SHM)
window_get_ipc_key(long * k,long * v,int d)4874 int window_get_ipc_key(long *k, long *v, int d) {
4875 	int f, n;
4876 
4877 	char *p;
4878 
4879 	if((p = window_open_op_alloc_ftok()) == NULL) return(-1);
4880 
4881 	if((*k = (long) ftok(p, d)) == -1) {
4882 		LOGWARN(
4883 			ERROR_SLIGHT, SUBSYSTEM,
4884 			_("Failed to create IPC key")
4885 		);
4886 
4887 		(void) free(p);
4888 
4889 		return(-1);
4890 	}
4891 
4892 	(void) free(p);
4893 
4894 	if(v != NULL) {
4895 		*v = 0;
4896 #if defined(SEM_A) && defined(SEM_R)
4897 		f = SEM_R | SEM_A | SEM_R >> 3 | SEM_A >> 3 | SEM_R >> 6 | SEM_A >> 6;
4898 #else
4899 		f = 0666;
4900 #endif
4901 		if((n = semget((key_t) *k, 1, f)) == -1) return(0);
4902 		if((*v = (long) semctl(n, 0, GETVAL)) == -1) return(0);
4903 	}
4904 
4905 	return(0);
4906 }
4907 #endif
window_get_default_font(char * f)4908 char *window_get_default_font(char *f) {
4909 #if defined(PROG_HAS_X11)
4910 	int k;
4911 	unsigned int i;
4912 
4913 	char *p;
4914 
4915 	size_t t;
4916 
4917 	t = CONFIG_PATH_LENGTH;
4918 
4919 	APP_MALLOC_RET_VALUE(p, t + sizeof(char), NULL);
4920 
4921 	if(f == NULL) f = WINDOW_DEFAULT_FONT;
4922 
4923 	/* If font has path delim at start, assume static path */
4924 	if(f[0] == CONFIG_PATH_DELIM) {
4925 		(void) snprintf(p, t, "%s", f);
4926 
4927 		if(window_get_default_font_op(p) == 0) return(p);
4928 	}
4929 
4930 	for(i = 0; ; i++) {
4931 		if(c_d_t[i] == NULL) break;
4932 
4933 		if(conf_read_try(c_d_t[i], f, p, t) != 0) continue;
4934 
4935 		if(window_get_default_font_op(p) == 0) return(p);
4936 	}
4937 
4938 	/* If font was not found in default directories, look through X server directories as well */
4939 	for(k = 0; k < n_fpt; k++) {
4940 		(void) snprintf(
4941 			p, t,
4942 			"%s%c%s",
4943 			c_fpt[k], CONFIG_PATH_DELIM, f
4944 		);
4945 
4946 		if(window_get_default_font_op(p) == 0) return(p);
4947 	}
4948 
4949 	(void) free(p);
4950 
4951 	(void) flush_error();
4952 
4953 	LOGWARN(
4954 		ERROR_FATAL, SUBSYSTEM,
4955 		_("Failed to find font file '%s' from default directories or any of the X server font directories"),
4956 		f
4957 	);
4958 #else
4959 	(void) f;
4960 #endif
4961 	return(NULL);
4962 }
4963 #if defined(PROG_HAS_X11)
window_get_default_font_op(char * p)4964 static int window_get_default_font_op(char *p) {
4965 	struct stat a;
4966 
4967 	if(stat((const char *) p, &a) != 0) return(-1);
4968 
4969 	switch(a.st_mode & S_IFMT) {
4970 		case S_IFREG:
4971 		case S_IFLNK:
4972 			break;
4973 		default:
4974 			return(-1);
4975 	}
4976 
4977 	return(0);
4978 }
4979 #endif
window_get_default_font_free(char * p)4980 void window_get_default_font_free(char *p) {
4981 #if defined(PROG_HAS_X11)
4982 	if(p != NULL) (void) free(p);
4983 #else
4984 	(void) p;
4985 #endif
4986 }
4987 
window_get_default_font_path(unsigned int i)4988 const char *window_get_default_font_path(unsigned int i) {
4989 	return(c_d_t[i]);
4990 }
4991 #if defined(PROG_HAS_X11)
window_get_default_refresh_rate(void)4992 unsigned int window_get_default_refresh_rate(void) {
4993 	return(WINDOW_UPDATE_FPS);
4994 }
4995 #endif
4996 #if defined(PROG_HAS_X11)
window_get_release_version(void)4997 char *window_get_release_version(void) {
4998 #if defined(GL_VERSION)
4999 	return(window_get_version_op(GL_VERSION));
5000 #else
5001 	return(NULL);
5002 #endif
5003 }
5004 
window_get_renderer_version(void)5005 char *window_get_renderer_version(void) {
5006 #if defined(GL_RENDERER)
5007 	return(window_get_version_op(GL_RENDERER));
5008 #else
5009 	return(NULL);
5010 #endif
5011 }
5012 
window_get_shader_version(void)5013 char *window_get_shader_version(void) {
5014 #if defined(GL_SHADING_LANGUAGE_VERSION)
5015 	return(window_get_version_op(GL_SHADING_LANGUAGE_VERSION));
5016 #else
5017 	return(NULL);
5018 #endif
5019 }
5020 
window_get_vendor_version(void)5021 char *window_get_vendor_version(void) {
5022 #if defined(GL_VENDOR)
5023 	return(window_get_version_op(GL_VENDOR));
5024 #else
5025 	return(NULL);
5026 #endif
5027 }
5028 
window_get_version_free(char * s)5029 void window_get_version_free(char *s) {
5030 	if(s != NULL) (void) free(s);
5031 }
5032 
window_get_version_op(int n)5033 static char *window_get_version_op(int n) {
5034 	char *f, *r, *s;
5035 
5036 	size_t t;
5037 
5038 	Display *d;
5039 	GLXContext g;
5040 	Window w;
5041 	XSetWindowAttributes a;
5042 	XVisualInfo *v;
5043 
5044 	if((s = (char *) conf_fetch("display")) == NULL) {
5045 		if((f = env_get("DISPLAY")) == NULL) f = env_get("HOSTDISPLAY");
5046 
5047 		s = f;
5048 	}
5049 	else f = NULL;
5050 
5051 	(void) XInitThreads();
5052 	(void) XSetErrorHandler(window_error_null_handler);
5053 
5054 	if((d = XOpenDisplay(s)) == NULL) {
5055 		(void) env_free(f);
5056 
5057 		return((char *) -1);
5058 	}
5059 
5060 	(void) env_free(f);
5061 
5062 	(void) XLockDisplay(d);
5063 
5064 	r = NULL;
5065 
5066 	/* Create window for fetching requested OpenGL string out of its context */
5067 	(void) memset((void *) &a, 0, sizeof(a));
5068 
5069 	w = XCreateWindow(d, XDefaultRootWindow(d), 0, 0, 1, 1, 0,
5070 		CopyFromParent, InputOutput, CopyFromParent, 0, &a);
5071 
5072 	if((v = glXChooseVisual(d, XDefaultScreen(d), (int *) w_gl_single_8)) != NULL) {
5073 		if((g = glXCreateContext(d, v, NULL, GL_TRUE)) != NULL) {
5074 			(void) glXMakeCurrent(d, w, g);
5075 
5076 			if((s = (char *) glGetString((GLenum) n)) != NULL) {
5077 				t = str_len(s, STRING_ASCII);
5078 
5079 				if((r = malloc(t + sizeof(char))) != NULL) {
5080 					(void) memcpy((void *) r, (const void *) s, t);
5081 
5082 					r[t] = 0;
5083 				}
5084 			}
5085 
5086 			(void) glXMakeCurrent(d, None, NULL);
5087 			(void) glXDestroyContext(d, g);
5088 		}
5089 
5090 		(void) XFree(v);
5091 	}
5092 
5093 	(void) XDestroyWindow(d, w);
5094 
5095 	(void) XUnlockDisplay(d);
5096 	(void) XCloseDisplay(d);
5097 
5098 	return(r);
5099 }
5100 #endif
5101 #endif
5102