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