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 <X11/Xlib.h>
29 #include <X11/Xutil.h>
30 #include <X11/keysym.h>
31 #include <pthread.h>
32
33 #include "common.h"
34
35 #include "frequencies.h"
36
37 #define WINDOW_WIDTH 500
38 #define WINDOW_HEIGHT 346
39
40
41 static struct {
42 xitk_window_t *xwin;
43
44 xitk_widget_list_t *widget_list;
45
46 xitk_widget_t *input;
47 xitk_widget_t *system;
48 xitk_widget_t *chann;
49 xitk_widget_t *framerate;
50 xitk_widget_t *vidstd;
51
52 xitk_widget_t *close;
53 xitk_widget_t *update;
54
55 const char **system_entries;
56 const char **chann_entries;
57 const char **vidstd_entries;
58
59 int running;
60 int visible;
61 xitk_register_key_t widget_key;
62
63 } tvset;
64
65 typedef uint64_t v4l2_std_id;
66
67 /* one bit for each */
68 #define V4L2_STD_PAL_B ((v4l2_std_id)0x00000001)
69 #define V4L2_STD_PAL_B1 ((v4l2_std_id)0x00000002)
70 #define V4L2_STD_PAL_G ((v4l2_std_id)0x00000004)
71 #define V4L2_STD_PAL_H ((v4l2_std_id)0x00000008)
72 #define V4L2_STD_PAL_I ((v4l2_std_id)0x00000010)
73 #define V4L2_STD_PAL_D ((v4l2_std_id)0x00000020)
74 #define V4L2_STD_PAL_D1 ((v4l2_std_id)0x00000040)
75 #define V4L2_STD_PAL_K ((v4l2_std_id)0x00000080)
76
77 #define V4L2_STD_PAL_M ((v4l2_std_id)0x00000100)
78 #define V4L2_STD_PAL_N ((v4l2_std_id)0x00000200)
79 #define V4L2_STD_PAL_Nc ((v4l2_std_id)0x00000400)
80 #define V4L2_STD_PAL_60 ((v4l2_std_id)0x00000800)
81
82 #define V4L2_STD_NTSC_M ((v4l2_std_id)0x00001000)
83 #define V4L2_STD_NTSC_M_JP ((v4l2_std_id)0x00002000)
84
85 #define V4L2_STD_SECAM_B ((v4l2_std_id)0x00010000)
86 #define V4L2_STD_SECAM_D ((v4l2_std_id)0x00020000)
87 #define V4L2_STD_SECAM_G ((v4l2_std_id)0x00040000)
88 #define V4L2_STD_SECAM_H ((v4l2_std_id)0x00080000)
89 #define V4L2_STD_SECAM_K ((v4l2_std_id)0x00100000)
90 #define V4L2_STD_SECAM_K1 ((v4l2_std_id)0x00200000)
91 #define V4L2_STD_SECAM_L ((v4l2_std_id)0x00400000)
92
93 /* ATSC/HDTV */
94 #define V4L2_STD_ATSC_8_VSB ((v4l2_std_id)0x01000000)
95 #define V4L2_STD_ATSC_16_VSB ((v4l2_std_id)0x02000000)
96
97 static const struct {
98 char name[24];
99 uint64_t std;
100 } std_list[] = {
101 { "PAL-B", V4L2_STD_PAL_B },
102 { "PAL-B1", V4L2_STD_PAL_B1 },
103 { "PAL-G", V4L2_STD_PAL_G },
104 { "PAL-H", V4L2_STD_PAL_H },
105 { "PAL-I", V4L2_STD_PAL_I },
106 { "PAL-D", V4L2_STD_PAL_D },
107 { "PAL-D1", V4L2_STD_PAL_D1 },
108 { "PAL-K", V4L2_STD_PAL_K },
109 { "PAL-M", V4L2_STD_PAL_M },
110 { "PAL-N", V4L2_STD_PAL_N },
111 { "PAL-Nc", V4L2_STD_PAL_Nc },
112 { "PAL-60", V4L2_STD_PAL_60 },
113 { "NTSC-M", V4L2_STD_NTSC_M },
114 { "NTSC-M-JP", V4L2_STD_NTSC_M_JP },
115 { "SECAM-B", V4L2_STD_SECAM_B },
116 { "SECAM-D", V4L2_STD_SECAM_D },
117 { "SECAM-G", V4L2_STD_SECAM_G },
118 { "SECAM-H", V4L2_STD_SECAM_H },
119 { "SECAM-K", V4L2_STD_SECAM_K },
120 { "SECAM-K1", V4L2_STD_SECAM_K1 },
121 { "SECAM-L", V4L2_STD_SECAM_L },
122 { "ATSC-8-VSB", V4L2_STD_ATSC_8_VSB },
123 { "ATSC-16-VSB", V4L2_STD_ATSC_16_VSB }
124 };
125
126
tvset_update(xitk_widget_t * w,void * data)127 static void tvset_update(xitk_widget_t *w, void *data) {
128 xine_event_t xine_event;
129 xine_set_v4l2_data_t *ev_data;
130 int current_system, current_chan, current_std;
131
132 current_system = xitk_combo_get_current_selected(tvset.system);
133 current_chan = xitk_combo_get_current_selected(tvset.chann);
134 current_std = xitk_combo_get_current_selected(tvset.vidstd);
135
136 if (current_system < 0 || (size_t)current_system >= sizeof(chanlists) / sizeof(chanlists[0])) {
137 current_system = 0;
138 }
139 if (current_chan < 0 || current_chan >= chanlists[current_system].count) {
140 current_chan = 0;
141 }
142 if (current_std < 0 || (size_t)current_std >= sizeof(std_list) / sizeof(std_list[0])) {
143 current_std = 0;
144 }
145
146 ev_data = (xine_set_v4l2_data_t *)malloc(sizeof(xine_set_v4l2_data_t));
147
148 ev_data->input = xitk_intbox_get_value(tvset.input);
149 ev_data->frequency = (chanlists[current_system].list[current_chan].freq * 16) / 1000;
150
151 ev_data->standard_id = std_list[current_std].std;
152
153 xine_event.type = XINE_EVENT_SET_V4L2;
154 xine_event.data_length = sizeof(xine_set_v4l2_data_t);
155 xine_event.data = ev_data;
156 xine_event.stream = gGui->stream;
157 gettimeofday(&xine_event.tv, NULL);
158
159 xine_event_send(gGui->stream, &xine_event);
160 }
161
162
tvset_exit(xitk_widget_t * w,void * data)163 static void tvset_exit(xitk_widget_t *w, void *data) {
164 window_info_t wi;
165
166 if ( ! tvset.running ) return;
167
168 tvset.running = 0;
169 tvset.visible = 0;
170
171 if((xitk_get_window_info(tvset.widget_key, &wi))) {
172 config_update_num ("gui.tvset_x", wi.x);
173 config_update_num ("gui.tvset_y", wi.y);
174 WINDOW_INFO_ZERO(&wi);
175 }
176
177 xitk_unregister_event_handler(&tvset.widget_key);
178
179 xitk_destroy_widgets(tvset.widget_list);
180 xitk_window_destroy_window(gGui->imlib_data, tvset.xwin);
181
182 tvset.xwin = NULL;
183 /* xitk_dlist_init (&tvset.widget_list->list); */
184
185 gGui->x_lock_display (gGui->display);
186 XFreeGC(gGui->display, (XITK_WIDGET_LIST_GC(tvset.widget_list)));
187 gGui->x_unlock_display (gGui->display);
188
189 free(tvset.system_entries);
190 free(tvset.chann_entries);
191 free(tvset.vidstd_entries);
192 tvset.system_entries = NULL;
193 tvset.chann_entries = NULL;
194 tvset.vidstd_entries = NULL;
195
196 XITK_WIDGET_LIST_FREE(tvset.widget_list);
197
198 try_to_set_input_focus(gGui->video_window);
199 }
200
tvset_handle_event(XEvent * event,void * data)201 static void tvset_handle_event(XEvent *event, void *data) {
202
203 switch(event->type) {
204
205 case KeyPress:
206 if(xitk_get_key_pressed(event) == XK_Escape)
207 tvset_exit(NULL, NULL);
208 else
209 gui_handle_event (event, gGui);
210 break;
211 }
212 }
213
tvset_is_visible(void)214 int tvset_is_visible(void) {
215
216 if(gGui->use_root_window)
217 return xitk_is_window_visible(gGui->display, xitk_window_get_window(tvset.xwin));
218 else
219 return tvset.visible && xitk_is_window_visible(gGui->display, xitk_window_get_window(tvset.xwin));
220 }
221
tvset_is_running(void)222 int tvset_is_running(void) {
223 return tvset.running;
224 }
225
tvset_raise_window(void)226 void tvset_raise_window(void) {
227 raise_window(xitk_window_get_window(tvset.xwin), tvset.visible, tvset.running);
228 }
229
tvset_toggle_visibility(xitk_widget_t * w,void * data)230 void tvset_toggle_visibility(xitk_widget_t *w, void *data) {
231 toggle_window(xitk_window_get_window(tvset.xwin), tvset.widget_list,
232 &tvset.visible, tvset.running);
233 }
234
tvset_end(void)235 void tvset_end(void) {
236 tvset_exit(NULL, NULL);
237 }
238
239
update_chann_entries(int system_entry)240 static int update_chann_entries(int system_entry) {
241 int i;
242 const struct CHANLIST *list = chanlists[system_entry].list;
243 int len = chanlists[system_entry].count;
244
245 free(tvset.chann_entries);
246
247 tvset.chann_entries = (const char **) calloc((len+1), sizeof(const char *));
248
249 for(i = 0; i < len; i++)
250 tvset.chann_entries[i] = list[i].name;
251
252 tvset.chann_entries[i] = NULL;
253 return len;
254 }
255
system_combo_select(xitk_widget_t * w,void * data,int select)256 static void system_combo_select(xitk_widget_t *w, void *data, int select) {
257 int len;
258
259 len = update_chann_entries(select);
260
261 if( tvset.chann ) {
262 xitk_combo_update_list(tvset.chann, tvset.chann_entries, len);
263 xitk_combo_set_select(tvset.chann, 0);
264 }
265 }
266
267
tvset_reparent(void)268 void tvset_reparent(void) {
269 reparent_window((xitk_window_get_window(tvset.xwin)));
270 }
271
tvset_panel(void)272 void tvset_panel(void) {
273 GC gc;
274 xitk_labelbutton_widget_t lb;
275 xitk_label_widget_t lbl;
276 xitk_intbox_widget_t ib;
277 xitk_checkbox_widget_t cb;
278 xitk_combo_widget_t cmb;
279 xitk_inputtext_widget_t inp;
280 xitk_pixmap_t *bg;
281 size_t i;
282 int x, y, w, width, height;
283 xitk_widget_t *widget;
284
285 x = xine_config_register_num (__xineui_global_xine_instance, "gui.tvset_x",
286 80,
287 CONFIG_NO_DESC,
288 CONFIG_NO_HELP,
289 CONFIG_LEVEL_DEB,
290 CONFIG_NO_CB,
291 CONFIG_NO_DATA);
292 y = xine_config_register_num (__xineui_global_xine_instance, "gui.tvset_y",
293 80,
294 CONFIG_NO_DESC,
295 CONFIG_NO_HELP,
296 CONFIG_LEVEL_DEB,
297 CONFIG_NO_CB,
298 CONFIG_NO_DATA);
299
300 /* Create window */
301 tvset.xwin = xitk_window_create_dialog_window(gGui->imlib_data,
302 _("TV Analog Video Parameters"), x, y,
303 WINDOW_WIDTH, WINDOW_HEIGHT);
304
305 set_window_states_start((xitk_window_get_window(tvset.xwin)));
306
307 gGui->x_lock_display (gGui->display);
308 gc = XCreateGC(gGui->display,
309 (xitk_window_get_window(tvset.xwin)), None, None);
310 gGui->x_unlock_display (gGui->display);
311
312 tvset.widget_list = xitk_widget_list_new();
313 xitk_widget_list_set(tvset.widget_list,
314 WIDGET_LIST_WINDOW, (void *) (xitk_window_get_window(tvset.xwin)));
315 xitk_widget_list_set(tvset.widget_list, WIDGET_LIST_GC, gc);
316
317 XITK_WIDGET_INIT(&lb, gGui->imlib_data);
318 XITK_WIDGET_INIT(&lbl, gGui->imlib_data);
319 XITK_WIDGET_INIT(&cb, gGui->imlib_data);
320
321 xitk_window_get_window_size(tvset.xwin, &width, &height);
322 bg = xitk_image_create_xitk_pixmap(gGui->imlib_data, width, height);
323 gGui->x_lock_display (gGui->display);
324 XCopyArea(gGui->display, (xitk_window_get_background(tvset.xwin)), bg->pixmap,
325 bg->gc, 0, 0, width, height, 0, 0);
326 gGui->x_unlock_display (gGui->display);
327
328 x = 15;
329 y = 34 - 6;
330
331 draw_outter_frame(gGui->imlib_data, bg, _("General"), btnfontname,
332 x, y, WINDOW_WIDTH - 30, ((20 + 22) + 5 + 2) + 15);
333
334
335 /* First Line */
336 x = 20;
337 y += 15;
338 w = 139;
339 draw_inner_frame(gGui->imlib_data, bg, _("Input: "), lfontname,
340 x, y, w, (20 + 22));
341 XITK_WIDGET_INIT(&ib, gGui->imlib_data);
342 ib.skin_element_name = NULL;
343 ib.value = 4;
344 ib.step = 1;
345 ib.parent_wlist = tvset.widget_list;
346 ib.callback = NULL;
347 ib.userdata = NULL;
348 tvset.input = xitk_noskin_intbox_create (tvset.widget_list, &ib,
349 x + 10, y + 15, w - 20 + 1, 20, NULL, NULL, NULL);
350 xitk_add_widget (tvset.widget_list, tvset.input);
351 xitk_enable_and_show_widget(tvset.input);
352
353 {
354 static const size_t chanlists_count = sizeof(chanlists)/sizeof(chanlists[0]);
355 tvset.system_entries = (const char **) calloc((chanlists_count+1), sizeof(const char *));
356
357 for(i = 0; i < chanlists_count; i++)
358 tvset.system_entries[i] = chanlists[i].name;
359 tvset.system_entries[i] = NULL;
360 }
361
362 x += w + 5;
363 w = 155;
364 draw_inner_frame(gGui->imlib_data, bg, _("Broadcast System: "), lfontname,
365 x, y, w, (20 + 22));
366
367 XITK_WIDGET_INIT(&cmb, gGui->imlib_data);
368 cmb.skin_element_name = NULL;
369 cmb.layer_above = (is_layer_above());
370 cmb.parent_wlist = tvset.widget_list;
371 cmb.entries = tvset.system_entries;
372 cmb.parent_wkey = &tvset.widget_key;
373 cmb.callback = system_combo_select;
374 cmb.userdata = NULL;
375 tvset.system = xitk_noskin_combo_create (tvset.widget_list, &cmb,
376 x + 10, y + 15, w - 20 + 1, NULL, NULL);
377 xitk_add_widget (tvset.widget_list, tvset.system);
378 xitk_set_widget_pos(tvset.system, x + 10, y + 15 + (20 - xitk_get_widget_height(tvset.system)) / 2);
379 xitk_enable_and_show_widget(tvset.system);
380
381 xitk_combo_set_select(tvset.system, 0);
382 update_chann_entries(0);
383
384 x += w + 5;
385 w = 155;
386 draw_inner_frame(gGui->imlib_data, bg, _("Channel: "), lfontname,
387 x, y, w, (20 + 22));
388
389 XITK_WIDGET_INIT(&cmb, gGui->imlib_data);
390 cmb.skin_element_name = NULL;
391 cmb.layer_above = (is_layer_above());
392 cmb.parent_wlist = tvset.widget_list;
393 cmb.entries = tvset.chann_entries;
394 cmb.parent_wkey = &tvset.widget_key;
395 cmb.callback = NULL;
396 cmb.userdata = NULL;
397 tvset.chann = xitk_noskin_combo_create (tvset.widget_list, &cmb,
398 x + 10, y + 15, w - 20 + 1, NULL, NULL);
399 xitk_add_widget (tvset.widget_list, tvset.chann);
400 xitk_set_widget_pos(tvset.chann, x + 10, y + 15 + (20 - xitk_get_widget_height(tvset.chann)) / 2);
401 xitk_enable_and_show_widget(tvset.chann);
402
403 x = 15;
404 y += ((20 + 22) + 5 + 2) + 3;
405 draw_outter_frame(gGui->imlib_data, bg, _("Standard"), btnfontname,
406 x, y, WINDOW_WIDTH - 30, ((20 + 22) + 5 + 2) + 15);
407
408
409 x = 20;
410 y += 15;
411 w = 139;
412 draw_inner_frame(gGui->imlib_data, bg, _("Frame Rate: "), lfontname,
413 x, y, w, (20 + 22));
414
415 XITK_WIDGET_INIT(&inp, gGui->imlib_data);
416 inp.skin_element_name = NULL;
417 inp.text = NULL;
418 inp.max_length = 20;
419 inp.callback = NULL;
420 inp.userdata = NULL;
421 tvset.framerate = xitk_noskin_inputtext_create (tvset.widget_list, &inp,
422 x + 10, y + 15, w - 20 + 1, 20, "Black", "Black", fontname);
423 xitk_add_widget (tvset.widget_list, tvset.framerate);
424 xitk_enable_and_show_widget(tvset.framerate);
425
426 tvset.vidstd_entries = (const char **) malloc(sizeof(const char *) *
427 (sizeof(std_list)/sizeof(std_list[0])+1));
428
429 for(i = 0; i < (sizeof(std_list)/sizeof(std_list[0])); i++)
430 tvset.vidstd_entries[i] = std_list[i].name;
431 tvset.vidstd_entries[i] = NULL;
432
433 x += w + 5;
434 w = 155;
435 draw_inner_frame(gGui->imlib_data, bg, _("Analog Standard: "), lfontname,
436 x, y, w, (20 + 22));
437
438 XITK_WIDGET_INIT(&cmb, gGui->imlib_data);
439 cmb.skin_element_name = NULL;
440 cmb.layer_above = (is_layer_above());
441 cmb.parent_wlist = tvset.widget_list;
442 cmb.entries = tvset.vidstd_entries;
443 cmb.parent_wkey = &tvset.widget_key;
444 cmb.callback = NULL;
445 cmb.userdata = NULL;
446 tvset.vidstd = xitk_noskin_combo_create (tvset.widget_list, &cmb,
447 x + 10, y + 15, w - 20 + 1, NULL, NULL);
448 xitk_add_widget (tvset.widget_list, tvset.vidstd);
449 xitk_enable_and_show_widget(tvset.vidstd);
450
451 x = 15;
452 y += ((20 + 22) + 5 + 2) + 3;
453 draw_outter_frame(gGui->imlib_data, bg, _("Frame Size"), btnfontname,
454 x, y, WINDOW_WIDTH - 30, ((20 + 22) + 5 + 2) + 15);
455
456
457 x = 20;
458 y += 15;
459 w = 139;
460
461 x = 15;
462 y += ((20 + 22) + 5 + 2) + 3;
463 draw_outter_frame(gGui->imlib_data, bg, _("MPEG2"), btnfontname,
464 x, y, WINDOW_WIDTH - 30, ((20 + 22) + 5 + 2) + 15);
465
466
467 x = 20;
468 y += 15;
469 w = 139;
470
471 /* */
472 y = WINDOW_HEIGHT - (23 + 15);
473 x = 15;
474
475 lb.button_type = CLICK_BUTTON;
476 lb.label = _("Update");
477 lb.align = ALIGN_CENTER;
478 lb.callback = tvset_update;
479 lb.state_callback = NULL;
480 lb.userdata = NULL;
481 lb.skin_element_name = NULL;
482 tvset.update = xitk_noskin_labelbutton_create (tvset.widget_list,
483 &lb, x, y, 100, 23, "Black", "Black", "White", btnfontname);
484 xitk_add_widget (tvset.widget_list, tvset.update);
485 xitk_enable_and_show_widget(tvset.update);
486
487 x = WINDOW_WIDTH - (100 + 15);
488
489 lb.button_type = CLICK_BUTTON;
490 lb.label = _("Close");
491 lb.align = ALIGN_CENTER;
492 lb.callback = tvset_exit;
493 lb.state_callback = NULL;
494 lb.userdata = NULL;
495 lb.skin_element_name = NULL;
496 widget = xitk_noskin_labelbutton_create (tvset.widget_list,
497 &lb, x, y, 100, 23, "Black", "Black", "White", btnfontname);
498 xitk_add_widget (tvset.widget_list, widget);
499 xitk_enable_and_show_widget(widget);
500
501 xitk_window_change_background(gGui->imlib_data, tvset.xwin, bg->pixmap, width, height);
502 xitk_image_destroy_xitk_pixmap(bg);
503
504 tvset.widget_key = xitk_register_event_handler("tvset",
505 (xitk_window_get_window(tvset.xwin)),
506 tvset_handle_event,
507 NULL,
508 NULL,
509 tvset.widget_list,
510 NULL);
511
512 tvset.visible = 1;
513 tvset.running = 1;
514 tvset_raise_window();
515
516 try_to_set_input_focus(xitk_window_get_window(tvset.xwin));
517 }
518