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