1 /*
2  * Copyright (C) 2002-2008 Stefan Holst
3  * Copyright (C) 2005-2019 the xine project
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA.
18  *
19  * oxine main program
20  */
21 
22 #define LOG
23 
24 #include "config.h"
25 
26 #include <stdio.h>
27 #include <ctype.h>
28 #include <dirent.h>
29 #include <string.h>
30 #include <sys/stat.h>
31 #include <fcntl.h>
32 #include <getopt.h>
33 
34 #include <xine.h>
35 #include "common.h"
36 #include "oxine.h"
37 #include "odk.h"
38 #include "otk.h"
39 #include "oxine_event.h"
40 #include "xine/xmlparser.h"
41 #include "utils.h"
42 #include "globals.h"
43 
44 #include "mediamarks.h"
45 #include "playlist.h"
46 
47 static oxine_t *oxine_instance_get(void);
48 static void oxine_instance_unget(oxine_t *oxine);
49 
50 
51 typedef struct menuitem_s menuitem_t;
52 
53 struct menuitem_s {
54   char *title;
55   void *data;
56   int  x, y, w, h;
57   void (*func)(void *data);
58 };
59 
60 
61 static void main_menu_cb(void *data);
62 #if 0
63 static void media_stop_cb(void *data);
64 static void media_info_cb(void *data);
65 static void media_pause_cb(void *data, int i);
66 
67 //static void event_delay(void *data);
68 
69 const char *playpause_strings[] = { "<", ">" };
70 
71 static void media_pause_cb(void *data, int i) {
72   oxine_t *oxine = (oxine_t*) data;
73 
74   switch(i) {
75     case 1:
76       odk_set_speed(oxine->odk, ODK_SPEED_NORMAL);
77       break;
78     case 2:
79       odk_set_speed(oxine->odk, ODK_SPEED_PAUSE);
80       break;
81   }
82 }
83 
84 static void format_time(char *buf, int sec) {
85     sprintf(buf, "%d:%02d:%02d", sec/3600, (sec%3600)/60, ((sec%3600)%60));
86 }
87 
88 static void media_stop_cb(void *data) {
89   oxine_t *oxine = (oxine_t*) data;
90 
91   odk_stop(oxine->odk);
92   oxine->main_menu_cb(oxine);
93 }
94 
95 static void media_tracks_list_cb(void *data, void *entry) {
96   oxine_t *oxine = (oxine_t *) data;
97   char *mrl = (char *) entry;
98 
99   odk_stop(oxine->odk);
100   odk_open_and_play(oxine->odk, mrl);
101 }
102 
103 static void media_tracks_quit(void *data) {
104   oxine_t *oxine = (oxine_t*) data;
105 
106   oxine->need_draw = 0;
107   printf("%d\n", oxine->mode);
108   oxine->mode = OXINE_MODE_NORMAL;
109   printf("%d\n", oxine->mode);
110   oxine->pauseplay = NULL;
111   otk_clear(oxine->otk);
112 }
113 
114 static void media_tracks_cb(void *data) {
115   oxine_t *oxine = (oxine_t *) data;
116   int num, i = 0;
117   char **str;
118   otk_widget_t *list;
119 
120   oxine->pauseplay = NULL;
121   oxine->main_window = NULL;
122   oxine->info_window = NULL;
123   otk_clear(oxine->otk);
124   oxine->main_window = otk_window_new (oxine->otk, NULL, 50, 50, 550, 500);
125   list = otk_list_new(oxine->main_window, 10, 10, 500, 490, media_tracks_list_cb, oxine);
126 
127   str = xine_get_autoplay_mrls (oxine->xine, "CD", &num);
128   while(i < num) {
129     /* printf("%d %s\n", i, str[i]); */
130     otk_add_listentry(list, str[i], str[i], -1);
131     i++;
132   }
133   otk_list_set_pos(list, 0);
134   otk_set_focus(list);
135   otk_draw_all(oxine->otk);
136 }
137 
138 static void info_button_time(void *data) {
139   oxine_t *oxine = (oxine_t *)data;
140   int ret, pos_time, length;
141 
142   ret = odk_get_pos_length_high(oxine->odk, NULL, &pos_time, &length);
143   /* oxine->time = malloc(sizeof(char)*255); */
144   if(ret) {
145     pos_time /= 1000;
146     length /= 1000;
147     sprintf(oxine->time, "(%d:%02d:%02d / %d:%02d:%02d)", pos_time/3600, (pos_time%3600)/60, ((pos_time%3600)%60),
148 	    length/3600, (length%3600)/60, ((length%3600)%60));
149   }
150   else sprintf(oxine->time, "N/A");
151 }
152 #endif
153 
media_info_close_cb(void * data)154 static void media_info_close_cb(void *data) {
155   oxine_t *oxine = (oxine_t*) data;
156 
157   if (!oxine->info_window) return;
158 
159   otk_destroy_widget(oxine->info_window);
160   oxine->info_window = NULL;
161   otk_draw_all(oxine->otk);
162 
163   if (oxine->lines[0]) ho_free(oxine->lines[0]);
164   if (oxine->lines[1]) ho_free(oxine->lines[1]);
165   if (oxine->lines[2]) ho_free(oxine->lines[2]);
166 }
167 
168 #if 0
169 static void media_info_cb(void *data) {
170   oxine_t *oxine = (oxine_t*) data;
171   int pos_time, length, ret;
172   int cline = 0;
173   const char *buf1;
174   char *buf2;
175   /* otk_widget_t *b, *layout; */
176 
177   oxine->media_info_close_cb = media_info_close_cb;
178   oxine->pauseplay = NULL;
179   if (oxine->info_window) {
180     otk_destroy_widget(oxine->info_window);
181     oxine->info_window = NULL;
182     otk_draw_all(oxine->otk);
183     return;
184   }
185   /* otk_clear(oxine->otk); */
186 
187   buf2 = NULL;
188   buf1 = odk_get_mrl(oxine->odk);
189   if (buf1) {
190     buf2 = strrchr(buf1,'/');
191     if (buf2) buf2++; else buf2 = buf1;
192   }
193 
194   if (oxine->lines[0]) ho_free(oxine->lines[0]);
195   if (oxine->lines[1]) ho_free(oxine->lines[1]);
196   if (oxine->lines[2]) ho_free(oxine->lines[2]);
197 
198   oxine->lines[0] = odk_get_meta_info(oxine->odk, XINE_META_INFO_TITLE);
199   if(!oxine->lines[0] && buf2) oxine->lines[0] = ho_strdup(buf2);
200   if(oxine->lines[0]) cline++;
201   buf1 = odk_get_meta_info(oxine->odk, XINE_META_INFO_ARTIST);
202   buf2 = odk_get_meta_info(oxine->odk, XINE_META_INFO_ALBUM);
203   if (buf1 && buf2) {
204     oxine->lines[cline] = ho_newstring(strlen(buf1)+strlen(buf2)+10);
205     sprintf(oxine->lines[cline], "%s: %s", buf1, buf2);
206     cline++;
207   } else if (buf1 && (strlen(buf1)>0)) {
208     oxine->lines[cline++] = ho_strdup(buf1);
209   } else if (buf2 && (strlen(buf2)>0)) {
210     oxine->lines[cline++] = ho_strdup(buf2);
211   }
212   /*
213   oxine->genre = odk_get_meta_info(oxine->odk, XINE_META_INFO_GENRE);
214   if(!oxine->genre) oxine->genre = ho_strdup("Genre N/A");
215   oxine->year = odk_get_meta_info(oxine->odk, XINE_META_INFO_YEAR);
216   if(!oxine->year) oxine->year = ho_strdup("Year N/A");
217 */
218   ret = odk_get_pos_length_high(oxine->odk, NULL, &pos_time, &length);
219 
220   if(ret && (length > 0)) {
221     oxine->lines[cline] = ho_newstring(255);
222     pos_time /= 1000;
223     length /= 1000;
224     format_time(oxine->lines[cline], length);
225   }
226 
227   oxine->info_window = otk_window_new (oxine->otk, NULL, 5, 5, 790, 240);
228 
229   if (oxine->lines[0])
230   otk_label_new(oxine->info_window, 5, 40, OTK_ALIGN_LEFT|OTK_ALIGN_VCENTER, oxine->lines[0]);
231 
232   if (oxine->lines[1])
233   otk_label_new(oxine->info_window, 5, 110, OTK_ALIGN_LEFT|OTK_ALIGN_VCENTER, oxine->lines[1]);
234 
235   if (oxine->lines[2])
236   otk_label_new(oxine->info_window, 5, 180, OTK_ALIGN_LEFT|OTK_ALIGN_VCENTER, oxine->lines[2]);
237 
238   /*
239   layout = otk_layout_new(oxine->info_window, 10, 10, 680, 480, 6, 1);
240 
241   b = otk_button_grid_new(oxine->title, media_freeandreturnto_cb, oxine);
242   otk_layout_add_widget(layout, b, 0, 0, 1, 1);
243   otk_set_focus(b);
244 
245   b = otk_button_grid_new(oxine->artist, media_freeandreturnto_cb, oxine);
246   otk_layout_add_widget(layout, b, 0, 1, 1, 1);
247 
248   b = otk_button_grid_new(oxine->genre, media_freeandreturnto_cb, oxine);
249   otk_layout_add_widget(layout, b, 0, 2, 1, 1);
250 
251   b = otk_button_grid_new(oxine->album, media_freeandreturnto_cb, oxine);
252   otk_layout_add_widget(layout, b, 0, 3, 1, 1);
253 
254   b = otk_button_grid_new(oxine->year, media_freeandreturnto_cb, oxine);
255   otk_layout_add_widget(layout, b, 0, 4, 1, 1);
256 
257   b = otk_button_grid_new(oxine->time, media_freeandreturnto_cb, oxine);
258   otk_layout_add_widget(layout, b, 0, 5, 1, 1);
259   otk_button_uc_set(b, info_button_time, oxine);
260  */
261 
262   otk_draw_all(oxine->otk);
263 
264   schedule_job(5000, media_info_close_cb, oxine);
265 }
266 #endif
267 
shutdown_cb(void * data)268 static void shutdown_cb (void *data) {
269   gui_execute_action_id (gGui, ACTID_QUIT);
270 }
271 
mrl_cb(void * data)272 static void mrl_cb (void *data) {
273   char *parameter = (char *) data;
274   oxine_t *oxine = oxine_instance_get();
275   if (!oxine)
276     return;
277 
278   oxine->pauseplay = NULL;
279   oxine->main_window = NULL;
280   otk_clear(oxine->otk);
281   oxine->mode = OXINE_MODE_NORMAL;
282   odk_open_and_play(oxine->odk, parameter);
283 
284   oxine_instance_unget(oxine);
285 }
286 
autoplay_cb(void * data)287 static void autoplay_cb (void *data) {
288   char *parameter = (char *) data;
289   oxine_t *oxine = oxine_instance_get();
290   int    num_mrls, j;
291 #if XINE_MAJOR_VERSION < 1 || (XINE_MAJOR_VERSION == 1 && XINE_MINOR_VERSION < 2)
292   char **autoplay_mrls;
293 #else
294   const char * const *autoplay_mrls;
295 #endif
296 
297   if (!oxine)
298     return;
299 
300   autoplay_mrls = xine_get_autoplay_mrls (__xineui_global_xine_instance,
301                   parameter,
302                   &num_mrls);
303 
304   if(autoplay_mrls) {
305     playlist_delete_all(NULL, NULL);
306 
307     for (j = 0; j < num_mrls; j++)
308       mediamark_append_entry((const char *)autoplay_mrls[j],
309                              (const char *)autoplay_mrls[j], NULL, 0, -1, 0, 0);
310 
311     oxine->pauseplay = NULL;
312     oxine->main_window = NULL;
313     otk_clear(oxine->otk);
314     oxine->mode = OXINE_MODE_NORMAL;
315 
316     gGui->playlist.cur = 0;
317     gui_set_current_mmk(mediamark_get_current_mmk());
318 
319     gui_xine_open_and_play(gGui->mmk.mrl, gGui->mmk.sub, 0,
320                            gGui->mmk.start, gGui->mmk.av_offset, gGui->mmk.spu_offset, 0);
321   }
322 
323   oxine_instance_unget(oxine);
324 }
325 
326 
327 #if 0
328 static void playing_menu_update(void *data) {
329   oxine_t *oxine = (oxine_t *) data;
330   int pos_time, length;
331 
332   if (oxine->pos_str)
333     if (odk_get_pos_length_high(oxine->odk, NULL, &pos_time, &length)) {
334       pos_time /= 1000;
335       format_time(oxine->pos_str, pos_time);
336     }
337 }
338 
339 static void playing_menu_cb(void *data) {
340    oxine_t *oxine = (oxine_t *) data;
341    otk_widget_t *b, *l;
342    otk_widget_t *layout;
343    int pos_time, length;
344 
345    oxine->pauseplay = NULL;
346    if (oxine->main_window) {
347      otk_destroy_widget(oxine->main_window);
348      oxine->main_window = NULL;
349      otk_draw_all(oxine->otk);
350    }
351 
352    /* otk_clear(oxine->otk); */
353 
354    if(oxine->mode == OXINE_MODE_PLAY_MENU) {
355      oxine->mode = OXINE_MODE_NORMAL;
356      return ;
357    }
358    oxine->mode = OXINE_MODE_PLAY_MENU;
359 
360    oxine->main_window = otk_window_new (oxine->otk, NULL, 50, 400, 700, 150);
361    layout = otk_layout_new(oxine->main_window, 10, 10, 680, 130, 2, 6);
362    oxine->pauseplay = otk_selector_grid_new (playpause_strings, 2, media_pause_cb, oxine);
363    otk_layout_add_widget(layout, oxine->pauseplay, 0, 0, 1, 1);
364    otk_set_focus(oxine->pauseplay);
365    if (odk_get_speed(oxine->odk) == ODK_SPEED_PAUSE) otk_selector_set(oxine->pauseplay, 2);
366 
367    b = otk_button_grid_new ("}", media_stop_cb, oxine);
368    otk_layout_add_widget(layout, b, 1, 0, 1, 1);
369 
370 /*   b = otk_button_grid_new ("Volume", NULL, NULL);
371    otk_layout_add_widget(layout, b, 0, 1, 1, 1);
372 
373    b = otk_slider_grid_new (odk_get_volume);
374    otk_layout_add_widget(layout, b, 1, 1, 1, 1);
375 
376    if(!oxine->cd_in_use) {
377      b = otk_button_grid_new("Seek", NULL, NULL);
378      otk_layout_add_widget(layout, b, 0, 2, 1, 1);
379    }else {
380      b = otk_button_grid_new ("T", media_tracks_cb, oxine);
381      otk_layout_add_widget(layout, b, 0, 2, 1, 1);
382    }*/
383 
384    if(oxine->cd_in_use) {
385      b = otk_button_grid_new ("T", media_tracks_cb, oxine);
386      otk_layout_add_widget(layout, b, 3, 0, 1, 1);
387    }
388 
389    b = otk_slider_grid_new (odk_get_seek);
390    otk_layout_add_widget(layout, b, 2, 1, 4, 1);
391    otk_set_update(b,1);
392 
393    b = otk_button_grid_new ("i", media_info_cb, oxine);
394    otk_layout_add_widget(layout, b, 2, 0, 1, 1);
395 
396    if (!oxine->pos_str) oxine->pos_str = ho_newstring(64);
397    if (odk_get_pos_length_high(oxine->odk, NULL, &pos_time, &length)) {
398      pos_time /= 1000;
399      format_time(oxine->pos_str, pos_time);
400    }
401 
402    l = otk_label_new (oxine->main_window,  110, 100, OTK_ALIGN_CENTER|OTK_ALIGN_VCENTER, oxine->pos_str);
403    otk_set_update(l,1);
404    otk_button_uc_set(b, playing_menu_update, oxine);
405 
406    /* oxine->need_draw = 1; */
407 
408    otk_draw_all(oxine->otk);
409 }
410 #endif
411 
read_entire_file(const char * mrl,int * file_size)412 static char *read_entire_file (const char *mrl, int *file_size) {
413 
414   char        *buf;
415   struct stat  statb;
416   int          fd;
417 
418   if (stat (mrl, &statb) < 0) {
419     lprintf ("cannot stat '%s'\n", mrl);
420     return NULL;
421   }
422 
423   *file_size = statb.st_size;
424 
425   fd = xine_open_cloexec(mrl, O_RDONLY);
426   if (fd<0)
427     return NULL;
428 
429   buf = ho_newstring((*file_size)+1);
430 
431   if (!buf)
432     return NULL;
433 
434   buf[*file_size]=0;
435 
436   *file_size = read (fd, buf, *file_size);
437 
438   close (fd);
439 
440   return buf;
441 }
442 
menuitem_load(xml_node_t * node)443 static menuitem_t *menuitem_load(xml_node_t *node) {
444 
445   menuitem_t *item = ho_new(menuitem_t);
446 
447   item->x = atoi(xml_parser_get_property(node, "x"));
448   item->y = atoi(xml_parser_get_property(node, "y"));
449   item->w = atoi(xml_parser_get_property(node, "width"));
450   item->h = atoi(xml_parser_get_property(node, "height"));
451   item->func = NULL;
452   item->title = NULL;
453   item->data = NULL;
454 
455   if ( (node = node->child) == NULL )
456     return item;
457 
458   do {
459     if (!strcasecmp (node->name, "title")) {
460       item->title = ho_strdup (node->data);
461     } else if (!strcasecmp (node->name, "action")) {
462       const char *type = xml_parser_get_property(node, "type");
463 
464       if(type) {
465         if(!strcasecmp(type, "autoplay")) {
466           item->data = ho_strdup(xml_parser_get_property (node, "parameter"));
467           item->func = autoplay_cb;
468         } else if(!strcasecmp(type, "mrl")) {
469           item->data = ho_strdup(xml_parser_get_property (node, "parameter"));
470           item->func = mrl_cb;
471         } else if(!strcasecmp(type, "mediamarks")) {
472           item->func = mediamarks_cb;
473         } else if(!strcasecmp(type, "playlist")) {
474           item->func = playlist_cb;
475         } else if(!strcasecmp(type, "shutdown")) {
476           item->func = shutdown_cb;
477         } else if(!strcasecmp(type, "shell")) {
478         }
479       }
480     }
481   } while ( (node = node->next) != NULL );
482 
483   return item;
484 }
485 
read_main_menu(oxine_t * oxine,list_t * list,const char * mrl)486 static int read_main_menu(oxine_t *oxine, list_t *list, const char *mrl) {
487 
488   int size;
489   char *file = read_entire_file(mrl, &size);
490   xml_node_t *node;
491 
492   if (!file) return 0;
493 
494   xml_parser_init_R (xml_parser_t *xml, file, strlen (file), XML_PARSER_CASE_INSENSITIVE);
495 
496   if (xml_parser_build_tree_R (xml, &node)<0) {
497     lprintf("xml parsing of %s failed\n", mrl);
498     xml_parser_finalize_R (xml);
499     return 0;
500   }
501 
502   if (strcasecmp (node->name, "oxinemm")) {
503     lprintf ("error, root node must be OXINEMM\n");
504     xml_parser_finalize_R (xml);
505     return 0;
506   }
507 
508   node = node->child;
509 
510   if (!node || strcasecmp (node->name, "window")) {
511     lprintf ("error, node WINDOW expected (%s found)\n", (!node) ? "(null)" : node->name );
512     xml_parser_finalize_R (xml);
513     return 0;
514   }
515 
516   oxine->win_x = atoi(xml_parser_get_property(node, "x"));
517   oxine->win_y = atoi(xml_parser_get_property(node, "y"));
518   oxine->win_w = atoi(xml_parser_get_property(node, "width"));
519   oxine->win_h = atoi(xml_parser_get_property(node, "height"));
520 
521   node = node->child;
522 
523   while (node) {
524 
525     if (!strcasecmp (node->name, "entry")) {
526       menuitem_t *item = menuitem_load(node);
527       if( item )
528         list_append_content(list, item);
529     }
530 
531     node=node->next;
532   }
533 
534   xml_parser_free_tree(node);
535   xml_parser_finalize_R (xml);
536   ho_free(file);
537 
538   return 1;
539 }
540 
main_menu_init(oxine_t * oxine)541 static void main_menu_init(oxine_t *oxine)
542 {
543   char         mmpath[XITK_NAME_MAX];
544 
545   oxine->main_menu_items = list_new();
546 
547   memset(mmpath,0,sizeof(mmpath));
548   snprintf(mmpath,sizeof(mmpath),"%s/.xine/oxine/mainmenu", xine_get_homedir());
549   if (!read_main_menu(oxine, oxine->main_menu_items, mmpath)) {
550     lprintf("trying to load system wide mainmenu\n");
551     snprintf(mmpath, sizeof(mmpath),"%s/mainmenu", XINE_OXINEDIR);
552     if (read_main_menu(oxine, oxine->main_menu_items, mmpath)) {
553       /**/
554     } else {
555       list_free(oxine->main_menu_items);
556       oxine->main_menu_items = NULL;
557     }
558   } else {
559     /**/
560   }
561 }
562 
main_menu_free(list_t * list)563 static void main_menu_free(list_t *list) {
564 
565   menuitem_t *item;
566 
567   if (!list) return;
568 
569   item = list_first_content(list);
570   while (item) {
571     if (item->title) ho_free(item->title);
572     if (item->data) ho_free(item->data);
573     list_delete_current(list);
574     ho_free(item);
575     item = list_first_content(list);
576   }
577 
578   list_free(list);
579 }
580 
main_menu_cb(void * data)581 static void main_menu_cb(void *data) {
582 
583   oxine_t *oxine = (oxine_t*) data;
584   menuitem_t *item;
585   otk_widget_t *b;
586 
587   lock_job_mutex();
588   if (oxine->info_window) {
589     media_info_close_cb(oxine);
590   }
591   unlock_job_mutex();
592 
593   oxine->pauseplay = NULL;
594   oxine->main_window = NULL;
595 
596   otk_clear(oxine->otk);
597 
598 #if 0
599   oxine->main_window = otk_window_new (oxine->otk, NULL, 50, 130, 700, 420);
600 
601   /*
602   b = otk_button_new (oxine->main_window, 50, 45, 290, 60, "Play Disc", disc_cb, oxine);
603   otk_set_focus(b);
604   */
605 
606   b = otk_button_new (oxine->main_window, 360, 45, 290, 60, "Mediamarks", mediamarks_cb, oxine);
607   otk_set_focus(b);
608 
609   /*
610   b = otk_button_new (oxine->main_window, 50, 150, 290, 60, "Analogue TV", tv_cb, oxine);
611   otk_set_focus(b);
612   */
613 
614   otk_button_new (oxine->main_window, 360, 150, 290, 60, "Playlist", playlist_cb, oxine);
615 
616   /*
617   otk_button_new (oxine->main_window, 50, 255, 290, 60, "Digital TV", dvb_cb, oxine);
618 
619   otk_button_new (oxine->main_window, 360, 255, 290, 60, "Control", control_cb, oxine);
620   */
621 
622   otk_button_new (oxine->main_window, 205, 320, 290, 60, "Shutdown", shutdown_cb, oxine);
623 
624 /*  otk_button_new (oxine->main_window, 50, 180, 290, 60, "File", file_cb, oxine);
625   otk_button_new (oxine->main_window, 50, 260, 290, 60, "Streaming", streaming_cb, oxine);*/
626 #endif
627 
628   oxine->main_window = otk_window_new (oxine->otk, NULL, oxine->win_x, oxine->win_y,
629                                                          oxine->win_w, oxine->win_h);
630 
631   item = list_first_content(oxine->main_menu_items);
632 
633   while (item) {
634 
635     b = otk_button_new (oxine->main_window, item->x, item->y, item->w, item->h,
636                         item->title, item->func, (item->data) ? item->data : oxine);
637     otk_set_focus(b);
638 
639     item = list_next_content(oxine->main_menu_items);
640   }
641 
642 
643   otk_draw_all(oxine->otk);
644 }
645 
return_cb(void * this)646 static void return_cb(void *this) {
647   oxine_t *oxine = (oxine_t*) this;
648 
649   if (oxine->reentry)
650     oxine->reentry(oxine->reentry_data);
651   else
652     oxine->main_menu_cb(oxine);
653   return;
654 }
655 
oxine_error_msg(const char * text)656 static void oxine_error_msg(const char *text)
657 {
658   oxine_t *oxine = oxine_instance_get();
659   otk_widget_t *b;
660   int l;
661   char *text2, *s;
662 
663   if (!oxine)
664     return;
665 
666   s = text2 = strdup(text);
667 
668   otk_clear(oxine->otk);
669   oxine->main_window = otk_window_new (oxine->otk, NULL, 100, 150, 600, 300);
670 
671   for( l = 0; l < 4 && s && strlen(s); l++ ) {
672     char *line = s;
673     otk_widget_t *label;
674 
675     if( (s = strchr(s,'\n')) ) {
676       *s++ = '\0';
677     }
678 
679     label = otk_label_new(oxine->main_window, 300, 30 + l*25,
680                           OTK_ALIGN_CENTER|OTK_ALIGN_VCENTER, line);
681     otk_label_set_font_size(label, 20);
682   }
683 
684   b = otk_button_new(oxine->main_window, 260, 240, 80, 50, "OK", return_cb, oxine);
685   otk_set_focus(b);
686   oxine->mode = OXINE_MODE_MAINMENU;
687   otk_draw_all(oxine->otk);
688 
689   free(text2);
690 
691   oxine_instance_unget(oxine);
692 }
693 
694 /*
695  * initialisation
696  */
697 
create_oxine(void)698 static oxine_t *create_oxine(void) {
699 
700   oxine_t *oxine;
701   xine_cfg_entry_t centry;
702 
703   oxine = ho_new(oxine_t);
704 
705   oxine->main_menu_cb = main_menu_cb;
706 
707   oxine->xine = __xineui_global_xine_instance;
708 
709   oxine->cd_mountpoint =
710   xine_config_register_string (oxine->xine,
711 				"gui.osdmenu.dvd_mountpoint",
712 				"/dvd",
713 				"directory a media in dvd device will be mounted",
714 				"directory a media in dvd device will be mounted",
715 				10,
716 				NULL,
717 				NULL);
718 
719   if (xine_config_lookup_entry (oxine->xine, "input.dvd_device", &centry)) {
720     oxine->cd_device = centry.str_value;
721   }
722 
723   start_scheduler();
724 
725   oxine->odk = odk_init();
726 
727   oxine->otk = otk_init(oxine->odk);
728 
729   oxine->mode = OXINE_MODE_NORMAL;
730 
731   return oxine;
732 }
733 
destroy_oxine(oxine_t * oxine)734 static void destroy_oxine(oxine_t *oxine) {
735 
736   if (oxine->otk) otk_free(oxine->otk);
737   if (oxine->odk) odk_free(oxine->odk);
738 
739   main_menu_free(oxine->main_menu_items);
740 
741   ho_free(oxine);
742 
743   stop_scheduler();
744 
745 #ifdef DEBUG
746   heapstat();
747 #endif
748 }
749 
oxine_menu(void)750 void oxine_menu(void)
751 {
752   oxine_t *oxine = oxine_instance_get();
753 
754   if( !oxine )
755     return;
756 
757   if( !oxine->main_menu_items )
758     main_menu_init(oxine);
759 
760   if( !oxine->main_menu_items ) {
761     printf("oxine: main menu items missing, check ~/.xine/oxine/mainmenu\n");
762     oxine_instance_unget(oxine);
763     return;
764   }
765 
766   oxine_adapt();
767 
768   if( oxine->mode != OXINE_MODE_MAINMENU ) {
769     video_window_reset_ssaver (gGui->vwin);
770     gGui->nongui_error_msg = oxine_error_msg;
771 
772     if( oxine->reentry )
773       oxine->reentry(oxine->reentry_data);
774     else
775       main_menu_cb(oxine);
776     oxine->mode = OXINE_MODE_MAINMENU;
777   } else {
778     oxine->mode = OXINE_MODE_NORMAL;
779     otk_clear(oxine->otk);
780   }
781 
782   oxine_instance_unget(oxine);
783 }
784 
oxine_action_event(int xine_event_type)785 int oxine_action_event(int xine_event_type)
786 {
787   oxine_t *oxine = oxine_instance_get();
788   oxine_event_t ev;
789 
790   if( !oxine )
791     return 0;
792 
793   if( oxine->mode == OXINE_MODE_NORMAL ) {
794     oxine_instance_unget(oxine);
795     return 0;
796   }
797 
798   ev.type = OXINE_EVENT_KEY;
799 
800   switch( xine_event_type ) {
801   default:
802     oxine_instance_unget(oxine);
803     return 0;
804   case XINE_EVENT_INPUT_UP:
805     ev.key = OXINE_KEY_UP;
806     break;
807   case XINE_EVENT_INPUT_DOWN:
808     ev.key = OXINE_KEY_DOWN;
809     break;
810   case XINE_EVENT_INPUT_LEFT:
811     ev.key = OXINE_KEY_LEFT;
812     break;
813   case XINE_EVENT_INPUT_RIGHT:
814     ev.key = OXINE_KEY_RIGHT;
815     break;
816   case XINE_EVENT_INPUT_SELECT:
817     gGui->nongui_error_msg = oxine_error_msg;
818     ev.key = OXINE_KEY_SELECT;
819     break;
820   }
821 
822   video_window_reset_ssaver (gGui->vwin);
823   otk_send_event(oxine->otk, &ev);
824   oxine_instance_unget(oxine);
825   return 1;
826 }
827 
oxine_mouse_event(int xine_event_type,int x,int y)828 int oxine_mouse_event(int xine_event_type, int x, int y) {
829   oxine_t *oxine = oxine_instance_get();
830   oxine_event_t ev;
831   int retval;
832 
833   if( !oxine )
834     return 0;
835 
836   if( oxine->mode == OXINE_MODE_NORMAL ) {
837     oxine_instance_unget(oxine);
838     return 0;
839   }
840 
841   ev.x = x;
842   ev.y = y;
843 
844   switch( xine_event_type ) {
845   default:
846     oxine_instance_unget(oxine);
847     return 0;
848   case XINE_EVENT_INPUT_MOUSE_MOVE:
849     ev.type = OXINE_EVENT_MOTION;
850     break;
851   case XINE_EVENT_INPUT_MOUSE_BUTTON:
852     gGui->nongui_error_msg = oxine_error_msg;
853     ev.type = OXINE_EVENT_BUTTON;
854     ev.key = OXINE_BUTTON1;
855     break;
856   }
857 
858   video_window_reset_ssaver (gGui->vwin);
859   retval = otk_send_event(oxine->otk, &ev);
860   oxine_instance_unget(oxine);
861   return retval;
862 }
863 
oxine_adapt(void)864 void oxine_adapt(void)
865 {
866   oxine_t *oxine = oxine_instance_get();
867   oxine_event_t ev;
868 
869   if( !oxine )
870     return;
871 
872   ev.type = OXINE_EVENT_FORMAT_CHANGED;
873   otk_send_event(oxine->otk, &ev);
874   oxine_instance_unget(oxine);
875 }
876 
877 static pthread_mutex_t oxine_instance_mutex = PTHREAD_MUTEX_INITIALIZER;
878 static pthread_cond_t oxine_instance_unlocked = PTHREAD_COND_INITIALIZER;
879 static oxine_t *oxine_instance = NULL;
880 static int oxine_instance_locks = 0;
881 
oxine_instance_get(void)882 oxine_t *oxine_instance_get(void)
883 {
884   oxine_t *oxine;
885 
886   pthread_mutex_lock(&oxine_instance_mutex);
887 
888   oxine = oxine_instance;
889   if (oxine)
890     oxine_instance_locks++;
891 
892   pthread_mutex_unlock(&oxine_instance_mutex);
893 
894   return oxine;
895 }
896 
oxine_instance_unget(oxine_t * oxine)897 void oxine_instance_unget(oxine_t *oxine)
898 {
899   pthread_mutex_lock(&oxine_instance_mutex);
900 
901   if (0 == --oxine_instance_locks)
902     pthread_cond_broadcast(&oxine_instance_unlocked);
903 
904   pthread_mutex_unlock(&oxine_instance_mutex);
905 }
906 
oxine_init(void)907 void oxine_init(void)
908 {
909   pthread_mutex_lock(&oxine_instance_mutex);
910 
911   oxine_instance = create_oxine();
912   oxine_instance_locks = 1;
913 
914   pthread_mutex_unlock(&oxine_instance_mutex);
915 }
916 
oxine_exit(void)917 void oxine_exit(void)
918 {
919   oxine_t *oxine = oxine_instance;
920 
921   pthread_mutex_lock(&oxine_instance_mutex);
922 
923   oxine_instance = NULL;
924   oxine_instance_locks--;
925 
926   while (oxine_instance_locks > 0)
927     pthread_cond_wait(&oxine_instance_unlocked, &oxine_instance_mutex);
928 
929   destroy_oxine(oxine);
930 
931   pthread_mutex_unlock(&oxine_instance_mutex);
932 }
933