1 /*
2 * Copyright (C) 2000-2019 the xine project
3 *
4 * This file is part of xine, a unix video player.
5 *
6 * xine is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * xine is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
19 *
20 *
21 */
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include <stdio.h>
27 #include <errno.h>
28 #include <sys/time.h>
29 #include <X11/Xlib.h>
30 #include <X11/Xutil.h>
31 #include <X11/keysym.h>
32 #include <pthread.h>
33
34 #include <xine.h>
35 #include <xine/xineutils.h>
36
37 #include "common.h"
38
39 #define WINDOW_WIDTH 250
40 #define WINDOW_HEIGHT 221
41
42
43 typedef struct {
44 xitk_window_t *xwin;
45
46 int x;
47 int y;
48
49 xitk_widget_list_t *widget_list;
50
51 struct {
52 xitk_widget_t *left;
53 xitk_widget_t *right;
54 xitk_widget_t *up;
55 xitk_widget_t *down;
56 xitk_widget_t *select;
57 } navigator;
58
59 struct {
60 xitk_widget_t *menu[7];
61 } menus;
62
63 struct {
64 xitk_widget_t *prev;
65 xitk_widget_t *next;
66 } angles;
67
68 struct {
69 xitk_widget_t *number[11];
70 } numbers;
71
72
73 int running;
74 int visible;
75 xitk_register_key_t widget_key;
76
77 } _eventer_t;
78
79 static _eventer_t *eventer = NULL;
80
event_sender_sticky_cb(void * data,xine_cfg_entry_t * cfg)81 void event_sender_sticky_cb(void *data, xine_cfg_entry_t *cfg) {
82 gGui_t *gui = data;
83 int old_sticky_value = gui->eventer_sticky;
84
85 gui->eventer_sticky = cfg->num_value;
86 if(eventer) {
87 if((!old_sticky_value) && gui->eventer_sticky) {
88 int px, py, pw;
89 xitk_get_window_position (gui->display, gui->panel_window, &px, &py, &pw, NULL);
90 eventer->x = px + pw;
91 eventer->y = py;
92 xitk_window_move_window (gui->imlib_data, eventer->xwin, eventer->x, eventer->y);
93 }
94 }
95 }
96
event_sender_store_new_position(void * data,int x,int y,int w,int h)97 static void event_sender_store_new_position (void *data, int x, int y, int w, int h) {
98
99 if(eventer && !gGui->eventer_sticky) {
100 eventer->x = x;
101 eventer->y = y;
102 config_update_num ("gui.eventer_x", x);
103 config_update_num ("gui.eventer_y", y);
104 }
105 }
106
event_sender_show_tips(int enabled,unsigned long timeout)107 void event_sender_show_tips(int enabled, unsigned long timeout) {
108
109 if(eventer) {
110 if(enabled)
111 xitk_set_widgets_tips_timeout(eventer->widget_list, timeout);
112 else
113 xitk_disable_widgets_tips(eventer->widget_list);
114 }
115 }
116
event_sender_update_tips_timeout(unsigned long timeout)117 void event_sender_update_tips_timeout(unsigned long timeout) {
118 if(eventer)
119 xitk_set_widgets_tips_timeout(eventer->widget_list, timeout);
120 }
121
122 /* Send given event to xine engine */
event_sender_send(int event)123 void event_sender_send (int event) {
124 xine_event_t xine_event;
125
126 if (!event)
127 return;
128
129 xine_event.type = event;
130 xine_event.data_length = 0;
131 xine_event.data = NULL;
132 xine_event.stream = gGui->stream;
133 gettimeofday(&xine_event.tv, NULL);
134 xine_event_send (gGui->stream, &xine_event);
135 }
136
event_sender_send2(xitk_widget_t * w,void * data)137 static void event_sender_send2 (xitk_widget_t *w, void *data) {
138 int event = (long int)data;
139 xine_event_t xine_event;
140
141 xine_event.type = event;
142 xine_event.data_length = 0;
143 xine_event.data = NULL;
144 xine_event.stream = gGui->stream;
145 gettimeofday(&xine_event.tv, NULL);
146 xine_event_send (gGui->stream, &xine_event);
147 }
148
149 static void event_sender_exit(xitk_widget_t *, void *);
150
event_sender_handle_event(XEvent * event,void * data)151 static void event_sender_handle_event(XEvent *event, void *data) {
152 xine_event_t xine_event;
153
154 switch(event->type) {
155
156 case ButtonRelease:
157 /*
158 * If we tried to move sticky window, move it back to stored position.
159 */
160 if(eventer && gGui->eventer_sticky) {
161 if (panel_is_visible (gGui->panel)) {
162 int x, y;
163 xitk_window_get_window_position(gGui->imlib_data, eventer->xwin, &x, &y, NULL, NULL);
164 if((x != eventer->x) || (y != eventer->y))
165 xitk_window_move_window(gGui->imlib_data, eventer->xwin, eventer->x, eventer->y);
166 }
167 }
168 return;
169
170 case KeyPress:
171 {
172 XKeyEvent mykeyevent;
173 KeySym key;
174 char kbuf[256];
175
176 mykeyevent = event->xkey;
177
178 gGui->x_lock_display (gGui->display);
179 XLookupString(&mykeyevent, kbuf, sizeof(kbuf), &key, NULL);
180 gGui->x_unlock_display (gGui->display);
181
182 switch(key) {
183 case XK_Up:
184 xine_event.type = XINE_EVENT_INPUT_UP;
185 break;
186 case XK_Down:
187 xine_event.type = XINE_EVENT_INPUT_DOWN;
188 break;
189 case XK_Left:
190 xine_event.type = XINE_EVENT_INPUT_LEFT;
191 break;
192 case XK_Right:
193 xine_event.type = XINE_EVENT_INPUT_RIGHT;
194 break;
195
196 case XK_Return:
197 case XK_KP_Enter:
198 case XK_ISO_Enter:
199 xine_event.type = XINE_EVENT_INPUT_SELECT;
200 break;
201
202 case XK_0:
203 xine_event.type = XINE_EVENT_INPUT_NUMBER_0;
204 break;
205 case XK_1:
206 xine_event.type = XINE_EVENT_INPUT_NUMBER_1;
207 break;
208 case XK_2:
209 xine_event.type = XINE_EVENT_INPUT_NUMBER_2;
210 break;
211 case XK_3:
212 xine_event.type = XINE_EVENT_INPUT_NUMBER_3;
213 break;
214 case XK_4:
215 xine_event.type = XINE_EVENT_INPUT_NUMBER_4;
216 break;
217 case XK_5:
218 xine_event.type = XINE_EVENT_INPUT_NUMBER_5;
219 break;
220 case XK_6:
221 xine_event.type = XINE_EVENT_INPUT_NUMBER_6;
222 break;
223 case XK_7:
224 xine_event.type = XINE_EVENT_INPUT_NUMBER_7;
225 break;
226 case XK_8:
227 xine_event.type = XINE_EVENT_INPUT_NUMBER_8;
228 break;
229 case XK_9:
230 xine_event.type = XINE_EVENT_INPUT_NUMBER_9;
231 break;
232
233 case XK_plus:
234 case XK_KP_Add:
235 xine_event.type = XINE_EVENT_INPUT_NUMBER_10_ADD;
236 break;
237
238 case XK_Escape:
239 event_sender_exit(NULL, NULL);
240 return;
241
242 default:
243 gui_handle_event (event, gGui);
244 return;
245 }
246 }
247 break;
248
249 default:
250 return;
251 }
252
253 xine_event.data_length = 0;
254 xine_event.data = NULL;
255 xine_event.stream = gGui->stream;
256 gettimeofday(&xine_event.tv, NULL);
257 xine_event_send (gGui->stream, &xine_event);
258 }
259
event_sender_update_menu_buttons(void)260 void event_sender_update_menu_buttons(void) {
261
262 if(eventer) {
263 if((!strncmp(gGui->mmk.mrl, "dvd:/", 5)) || (!strncmp(gGui->mmk.mrl, "dvdnav:/", 8))) {
264 xitk_labelbutton_change_label(eventer->menus.menu[0], _("Menu toggle"));
265 xitk_labelbutton_change_label(eventer->menus.menu[1], _("Title"));
266 xitk_labelbutton_change_label(eventer->menus.menu[2], _("Root"));
267 xitk_labelbutton_change_label(eventer->menus.menu[3], _("Subpicture"));
268 xitk_labelbutton_change_label(eventer->menus.menu[4], _("Audio"));
269 xitk_labelbutton_change_label(eventer->menus.menu[5], _("Angle"));
270 xitk_labelbutton_change_label(eventer->menus.menu[6], _("Part"));
271 }
272 else if(!strncmp(gGui->mmk.mrl, "bd:/", 4)) {
273 xitk_labelbutton_change_label(eventer->menus.menu[0], _("Top Menu"));
274 xitk_labelbutton_change_label(eventer->menus.menu[1], _("Popup Menu"));
275 xitk_labelbutton_change_label(eventer->menus.menu[2], _("Menu 3"));
276 xitk_labelbutton_change_label(eventer->menus.menu[3], _("Menu 4"));
277 xitk_labelbutton_change_label(eventer->menus.menu[4], _("Menu 5"));
278 xitk_labelbutton_change_label(eventer->menus.menu[5], _("Menu 6"));
279 xitk_labelbutton_change_label(eventer->menus.menu[6], _("Menu 7"));
280 } else {
281 xitk_labelbutton_change_label(eventer->menus.menu[0], _("Menu 1"));
282 xitk_labelbutton_change_label(eventer->menus.menu[1], _("Menu 2"));
283 xitk_labelbutton_change_label(eventer->menus.menu[2], _("Menu 3"));
284 xitk_labelbutton_change_label(eventer->menus.menu[3], _("Menu 4"));
285 xitk_labelbutton_change_label(eventer->menus.menu[4], _("Menu 5"));
286 xitk_labelbutton_change_label(eventer->menus.menu[5], _("Menu 6"));
287 xitk_labelbutton_change_label(eventer->menus.menu[6], _("Menu 7"));
288 }
289 }
290 }
291
event_sender_exit(xitk_widget_t * w,void * data)292 static void event_sender_exit(xitk_widget_t *w, void *data) {
293
294 if(eventer) {
295 window_info_t wi;
296
297 eventer->running = 0;
298 eventer->visible = 0;
299
300 if((xitk_get_window_info(eventer->widget_key, &wi))) {
301 config_update_num ("gui.eventer_x", wi.x);
302 config_update_num ("gui.eventer_y", wi.y);
303 WINDOW_INFO_ZERO(&wi);
304 }
305
306 xitk_unregister_event_handler(&eventer->widget_key);
307
308 xitk_destroy_widgets(eventer->widget_list);
309 xitk_window_destroy_window(gGui->imlib_data, eventer->xwin);
310
311 eventer->xwin = NULL;
312 /* xitk_dlist_init (&eventer->widget_list->list); */
313
314 gGui->x_lock_display (gGui->display);
315 XFreeGC(gGui->display, (XITK_WIDGET_LIST_GC(eventer->widget_list)));
316 gGui->x_unlock_display (gGui->display);
317
318 XITK_WIDGET_LIST_FREE(eventer->widget_list);
319
320 free(eventer);
321 eventer = NULL;
322
323 try_to_set_input_focus(gGui->video_window);
324 }
325 }
326
event_sender_is_visible(void)327 int event_sender_is_visible(void) {
328
329 if(eventer != NULL) {
330 if(gGui->use_root_window)
331 return xitk_is_window_visible(gGui->display, xitk_window_get_window(eventer->xwin));
332 else
333 return eventer->visible && xitk_is_window_visible(gGui->display, xitk_window_get_window(eventer->xwin));
334 }
335
336 return 0;
337 }
338
event_sender_is_running(void)339 int event_sender_is_running(void) {
340
341 if(eventer != NULL)
342 return eventer->running;
343
344 return 0;
345 }
346
event_sender_raise_window(void)347 void event_sender_raise_window(void) {
348 if(eventer != NULL)
349 raise_window(xitk_window_get_window(eventer->xwin), eventer->visible, eventer->running);
350 }
351
event_sender_toggle_visibility(xitk_widget_t * w,void * data)352 void event_sender_toggle_visibility(xitk_widget_t *w, void *data) {
353 if(eventer != NULL)
354 toggle_window(xitk_window_get_window(eventer->xwin), eventer->widget_list,
355 &eventer->visible, eventer->running);
356 }
357
event_sender_move(int x,int y)358 void event_sender_move(int x, int y) {
359
360 if(eventer != NULL) {
361 if(gGui->eventer_sticky) {
362 eventer->x = x;
363 eventer->y = y;
364 config_update_num ("gui.eventer_x", x);
365 config_update_num ("gui.eventer_y", y);
366 xitk_window_move_window(gGui->imlib_data, eventer->xwin, x, y);
367 }
368 }
369 }
370
event_sender_end(void)371 void event_sender_end(void) {
372 event_sender_exit(NULL, NULL);
373 }
374
event_sender_reparent(void)375 void event_sender_reparent(void) {
376 if(eventer)
377 reparent_window((xitk_window_get_window(eventer->xwin)));
378 }
379
event_sender_panel(void)380 void event_sender_panel(void) {
381 GC gc;
382 xitk_labelbutton_widget_t lb;
383 int x, y, i;
384 xitk_widget_t *w;
385
386 eventer = (_eventer_t *) calloc(1, sizeof(_eventer_t));
387
388 eventer->x = xine_config_register_num (__xineui_global_xine_instance, "gui.eventer_x",
389 80,
390 CONFIG_NO_DESC,
391 CONFIG_NO_HELP,
392 CONFIG_LEVEL_DEB,
393 CONFIG_NO_CB,
394 CONFIG_NO_DATA);
395 eventer->y = xine_config_register_num (__xineui_global_xine_instance, "gui.eventer_y",
396 80,
397 CONFIG_NO_DESC,
398 CONFIG_NO_HELP,
399 CONFIG_LEVEL_DEB,
400 CONFIG_NO_CB,
401 CONFIG_NO_DATA);
402
403 if (gGui->eventer_sticky && panel_is_visible (gGui->panel)) {
404 int px, py, pw;
405 xitk_get_window_position(gGui->display, gGui->panel_window, &px, &py, &pw, NULL);
406 eventer->x = px + pw;
407 eventer->y = py;
408 }
409
410 /* Create window */
411 eventer->xwin = xitk_window_create_simple_window(gGui->imlib_data, eventer->x, eventer->y, WINDOW_WIDTH, WINDOW_HEIGHT);
412
413 set_window_states_start((xitk_window_get_window(eventer->xwin)));
414
415 gGui->x_lock_display (gGui->display);
416 XStoreName(gGui->display, (xitk_window_get_window(eventer->xwin)), _("xine Event Sender"));
417 gc = XCreateGC(gGui->display,
418 (xitk_window_get_window(eventer->xwin)), None, None);
419 gGui->x_unlock_display (gGui->display);
420
421 eventer->widget_list = xitk_widget_list_new();
422 xitk_widget_list_set(eventer->widget_list,
423 WIDGET_LIST_WINDOW, (void *) (xitk_window_get_window(eventer->xwin)));
424 xitk_widget_list_set(eventer->widget_list, WIDGET_LIST_GC, gc);
425
426 XITK_WIDGET_INIT(&lb, gGui->imlib_data);
427
428 lb.button_type = CLICK_BUTTON;
429 lb.align = ALIGN_CENTER;
430 lb.callback = event_sender_send2;
431 lb.state_callback = NULL;
432 lb.skin_element_name = NULL;
433
434 #define I2PTR(n) (void *)((long int)(n))
435
436 x = 80 + 5 + 5;
437 y = 5 + 23 * 3 + 5 - 40;
438
439 lb.label = _("Up");
440 lb.userdata = I2PTR (XINE_EVENT_INPUT_UP);
441 eventer->navigator.up = xitk_noskin_labelbutton_create (eventer->widget_list,
442 &lb, x, y, 70, 40, "Black", "Black", "White", hboldfontname);
443 xitk_add_widget (eventer->widget_list, eventer->navigator.up);
444
445 xitk_enable_and_show_widget(eventer->navigator.up);
446
447 x -= 70;
448 y += 40;
449
450 lb.label = _("Left");
451 lb.userdata = I2PTR (XINE_EVENT_INPUT_LEFT);
452 eventer->navigator.left = xitk_noskin_labelbutton_create (eventer->widget_list,
453 &lb, x, y, 70, 40, "Black", "Black", "White", hboldfontname);
454 xitk_add_widget (eventer->widget_list, eventer->navigator.left);
455
456 xitk_enable_and_show_widget(eventer->navigator.left);
457
458 x += 75;
459 y += 5;
460
461 lb.label = _("Select");
462 lb.userdata = I2PTR (XINE_EVENT_INPUT_SELECT);
463 eventer->navigator.select = xitk_noskin_labelbutton_create (eventer->widget_list,
464 &lb, x, y, 60, 30, "Black", "Black", "White", hboldfontname);
465 xitk_add_widget (eventer->widget_list, eventer->navigator.select);
466
467 xitk_enable_and_show_widget(eventer->navigator.select);
468
469 x += 65;
470 y -= 5;
471
472 lb.label = _("Right");
473 lb.userdata = I2PTR (XINE_EVENT_INPUT_RIGHT);
474 eventer->navigator.right = xitk_noskin_labelbutton_create (eventer->widget_list,
475 &lb, x, y, 70, 40, "Black", "Black", "White", hboldfontname);
476 xitk_add_widget (eventer->widget_list, eventer->navigator.right);
477
478 xitk_enable_and_show_widget(eventer->navigator.right);
479
480 x -= 70;
481 y += 40;
482
483 lb.label = _("Down");
484 lb.userdata = I2PTR (XINE_EVENT_INPUT_DOWN);
485 eventer->navigator.down = xitk_noskin_labelbutton_create (eventer->widget_list,
486 &lb, x, y, 70, 40, "Black", "Black", "White", hboldfontname);
487 xitk_add_widget (eventer->widget_list, eventer->navigator.down);
488
489 xitk_enable_and_show_widget(eventer->navigator.down);
490
491 x = 23 * 2 + 5 + (80 - 23 * 3) / 2 + 1; /* (+1 to round up) */
492 y = 5 + 23 * 3 + 5 + 40 + 5;
493
494 for(i = 9; i >= 0; i--) {
495 char number[3];
496
497 snprintf(number, sizeof(number), "%d", i);
498
499 lb.label = number;
500 lb.userdata = I2PTR (XINE_EVENT_INPUT_NUMBER_0 + i);
501
502 if(!i)
503 x -= 46;
504
505 eventer->numbers.number[i] = xitk_noskin_labelbutton_create (eventer->widget_list,
506 &lb, x, y, 23, 23, "Black", "Black", "White", hboldfontname);
507 xitk_add_widget (eventer->widget_list, eventer->numbers.number[i]);
508
509 xitk_enable_and_show_widget(eventer->numbers.number[i]);
510
511 if(!((i - 1) % 3)) {
512 y += 23;
513 x += 46;
514 }
515 else
516 x -= 23;
517
518 }
519
520 x += 46;
521
522 {
523 char number[5];
524
525 i = 10;
526
527 snprintf(number, sizeof(number), "+ %d", i);
528
529 lb.label = number;
530 lb.userdata = I2PTR (XINE_EVENT_INPUT_NUMBER_10_ADD);
531
532 eventer->numbers.number[i] = xitk_noskin_labelbutton_create (eventer->widget_list,
533 &lb, x, y, 46, 23, "Black", "Black", "White", hboldfontname);
534 xitk_add_widget (eventer->widget_list, eventer->numbers.number[i]);
535
536 xitk_enable_and_show_widget(eventer->numbers.number[i]);
537 }
538
539 x = WINDOW_WIDTH - 80 - 5;
540 y = 5 + 23 * 3 + 5 + 40 + 5;
541
542 lb.label = _("Angle +");
543 lb.userdata = I2PTR (XINE_EVENT_INPUT_ANGLE_NEXT);
544 eventer->angles.next = xitk_noskin_labelbutton_create (eventer->widget_list,
545 &lb, x, y, 80, 23, "Black", "Black", "White", hboldfontname);
546 xitk_add_widget (eventer->widget_list, eventer->angles.next);
547
548 xitk_enable_and_show_widget(eventer->angles.next);
549
550 y += 23;
551
552 lb.label = _("Angle -");
553 lb.userdata = I2PTR (XINE_EVENT_INPUT_ANGLE_PREVIOUS);
554 eventer->angles.prev = xitk_noskin_labelbutton_create (eventer->widget_list,
555 &lb, x, y, 80, 23, "Black", "Black", "White", hboldfontname);
556 xitk_add_widget (eventer->widget_list, eventer->angles.prev);
557
558 xitk_enable_and_show_widget(eventer->angles.prev);
559
560
561 x = 5;
562 y = 5;
563
564 for(i = 0; i < 7; i++) {
565 lb.label = "";
566 lb.userdata = I2PTR (XINE_EVENT_INPUT_MENU1 + i);
567 eventer->menus.menu[i] = xitk_noskin_labelbutton_create (eventer->widget_list,
568 &lb, x, y, 80, 23, "Black", "Black", "White", hboldfontname);
569 xitk_add_widget (eventer->widget_list, eventer->menus.menu[i]);
570
571 xitk_enable_and_show_widget(eventer->menus.menu[i]);
572
573 if(i == 2) {
574 x += 80;
575 y -= (23 * 3);
576 }
577 if(i == 3) {
578 x += 80;
579 y -= 23;
580 }
581
582 y += 23;
583 }
584 event_sender_update_menu_buttons();
585
586 x = WINDOW_WIDTH - 70 - 5;
587 y = WINDOW_HEIGHT - 23 - 5;
588
589 lb.label = _("Close");
590 lb.callback = event_sender_exit;
591 lb.userdata = NULL;
592 w = xitk_noskin_labelbutton_create (eventer->widget_list,
593 &lb, x, y, 70, 23, "Black", "Black", "White", hboldfontname);
594 xitk_add_widget (eventer->widget_list, w);
595
596 xitk_enable_and_show_widget(w);
597 event_sender_show_tips (panel_get_tips_enable (gGui->panel), panel_get_tips_timeout (gGui->panel));
598
599 eventer->widget_key = xitk_register_event_handler("eventer",
600 (xitk_window_get_window(eventer->xwin)),
601 event_sender_handle_event,
602 event_sender_store_new_position,
603 NULL,
604 eventer->widget_list,
605 NULL);
606
607
608 eventer->visible = 1;
609 eventer->running = 1;
610 event_sender_raise_window();
611
612 try_to_set_input_focus(xitk_window_get_window(eventer->xwin));
613 }
614