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 * MRL Browser
21 *
22 */
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include <stdio.h>
28 #include <errno.h>
29 #include <X11/Xlib.h>
30 #include <X11/Xutil.h>
31
32 #include "common.h"
33
34 struct xui_mrlb_st {
35 gGui_t *gui;
36 xitk_widget_t *w;
37 };
38
39 /*
40 *
41 */
mrl_browser_show_tips(xui_mrlb_t * mrlb,int enabled,unsigned long timeout)42 void mrl_browser_show_tips (xui_mrlb_t *mrlb, int enabled, unsigned long timeout) {
43 if (mrlb && mrlb->w)
44 xitk_mrlbrowser_set_tips_timeout (mrlb->w, enabled, timeout);
45 }
46
mrl_browser_update_tips_timeout(xui_mrlb_t * mrlb,unsigned long timeout)47 void mrl_browser_update_tips_timeout (xui_mrlb_t *mrlb, unsigned long timeout) {
48 if (mrlb && mrlb->w) {
49 if (xitk_get_widget_tips_timeout (mrlb->w) > 0)
50 xitk_mrlbrowser_set_tips_timeout (mrlb->w, 1, timeout);
51 }
52 }
53
54 /*
55 *
56 */
set_mrl_browser_transient(xui_mrlb_t * mrlb)57 void set_mrl_browser_transient (xui_mrlb_t *mrlb) {
58 if (mrlb && mrlb->w) {
59 if (!mrlb->gui->use_root_window && mrlb->gui->video_display == mrlb->gui->display)
60 xitk_mrlbrowser_set_transient (mrlb->w, mrlb->gui->video_window);
61 }
62 }
63
64 /*
65 *
66 */
mrl_browser_change_skins(xui_mrlb_t * mrlb,int synthetic)67 void mrl_browser_change_skins (xui_mrlb_t *mrlb, int synthetic) {
68 (void)synthetic;
69 if (mrlb && mrlb->w) {
70 xitk_mrlbrowser_change_skins (mrlb->w, mrlb->gui->skin_config);
71 set_mrl_browser_transient (mrlb);
72 if (mrl_browser_is_visible (mrlb))
73 raise_window ((xitk_mrlbrowser_get_window_id (mrlb->w)), 1, 1);
74 }
75 }
76
77 /*
78 *
79 */
mrl_browser_is_visible(xui_mrlb_t * mrlb)80 int mrl_browser_is_visible (xui_mrlb_t *mrlb) {
81 if (mrlb && mrlb->w)
82 return (xitk_mrlbrowser_is_visible (mrlb->w));
83 return 0;
84 }
85
86 /*
87 *
88 */
mrl_browser_is_running(xui_mrlb_t * mrlb)89 int mrl_browser_is_running (xui_mrlb_t *mrlb) {
90 if (mrlb && mrlb->w)
91 return (xitk_mrlbrowser_is_running (mrlb->w));
92 return 0;
93 }
94
95 /*
96 *
97 */
show_mrl_browser(xui_mrlb_t * mrlb)98 void show_mrl_browser (xui_mrlb_t *mrlb) {
99 if (mrlb && mrlb->w) {
100 mrlb->gui->nongui_error_msg = NULL;
101 xitk_mrlbrowser_show (mrlb->w);
102 set_mrl_browser_transient (mrlb);
103 layer_above_video ((xitk_mrlbrowser_get_window_id (mrlb->w)));
104 }
105 }
106
107 /*
108 *
109 */
hide_mrl_browser(xui_mrlb_t * mrlb)110 void hide_mrl_browser (xui_mrlb_t *mrlb) {
111 if (mrlb && mrlb->w)
112 xitk_mrlbrowser_hide (mrlb->w);
113 }
114
115 /*
116 *
117 */
mrl_browser_toggle_visibility(xitk_widget_t * w,void * data)118 void mrl_browser_toggle_visibility (xitk_widget_t *w, void *data) {
119 xui_mrlb_t *mrlb = data;
120
121 (void)w;
122 if (mrlb) {
123 if (mrl_browser_is_visible (mrlb))
124 hide_mrl_browser (mrlb);
125 else
126 show_mrl_browser (mrlb);
127 }
128 }
129
130 /*
131 *
132 */
destroy_mrl_browser(xui_mrlb_t * mrlb)133 void destroy_mrl_browser (xui_mrlb_t *mrlb) {
134 if (mrlb) {
135 if (mrlb->w) {
136 window_info_t wi;
137
138 if ((xitk_mrlbrowser_get_window_info (mrlb->w, &wi))) {
139 config_update_num ("gui.mrl_browser_x", wi.x);
140 config_update_num ("gui.mrl_browser_y", wi.y);
141 }
142 xitk_mrlbrowser_destroy (mrlb->w);
143 mrlb->w = NULL;
144 }
145 mrlb->gui->mrlb = NULL;
146 try_to_set_input_focus (mrlb->gui->video_window);
147 free (mrlb);
148 }
149 }
150
151 /*
152 *
153 */
mrl_browser_kill(xitk_widget_t * w,void * data)154 static void mrl_browser_kill(xitk_widget_t *w, void *data) {
155 xui_mrlb_t *mrlb = data;
156
157 (void)w;
158 /* xitk_mrlbrowser_exit () calls this, then xitk_mrlbrowser_destroy ().
159 so we just shut down our own stuff here. */
160 if (mrlb) {
161 if (mrlb->w) {
162 window_info_t wi;
163
164 if ((xitk_mrlbrowser_get_window_info (mrlb->w, &wi))) {
165 config_update_num ("gui.mrl_browser_x", wi.x);
166 config_update_num ("gui.mrl_browser_y", wi.y);
167 }
168 mrlb->w = NULL;
169 }
170 mrlb->gui->mrlb = NULL;
171 try_to_set_input_focus (mrlb->gui->video_window);
172 free (mrlb);
173 }
174 }
175
mrl_browser_get_valid_mrl_ending(xui_mrlb_t * mrlb)176 static xitk_mrlbrowser_filter_t **mrl_browser_get_valid_mrl_ending (xui_mrlb_t *mrlb) {
177 xitk_mrlbrowser_filter_t **filters = NULL;
178 int num_endings = 0;
179 char *mrl_exts, *pmrl_exts, *p, *pp;
180
181 filters = (xitk_mrlbrowser_filter_t **)
182 calloc((num_endings + 2), sizeof(xitk_mrlbrowser_filter_t *));
183 filters[num_endings] = (xitk_mrlbrowser_filter_t *)
184 xitk_xmalloc(sizeof(xitk_mrlbrowser_filter_t));
185 filters[num_endings]->name = strdup("All");
186 filters[num_endings]->ending = strdup("*");
187
188 mrl_exts = xine_get_file_extensions (mrlb->gui->xine);
189 if(mrl_exts) {
190 char patterns[2048];
191 char *e;
192
193 p = strdup(mrl_exts);
194
195 num_endings++;
196
197 pp = p;
198 while(*p != '\0') {
199 if(*p == ' ')
200 *p = ',';
201 p++;
202 }
203
204 filters[num_endings] = (xitk_mrlbrowser_filter_t *) xitk_xmalloc(sizeof(xitk_mrlbrowser_filter_t));
205 filters[num_endings]->name = strdup(_("All extensions"));
206 filters[num_endings]->ending = pp;
207
208 pmrl_exts = mrl_exts;
209 while((e = xine_strsep(&pmrl_exts, " ")) != NULL) {
210
211 snprintf(patterns, sizeof(patterns), "*.%s", e);
212
213 num_endings++;
214
215 filters = (xitk_mrlbrowser_filter_t **)
216 realloc(filters, sizeof(xitk_mrlbrowser_filter_t *) * (num_endings + 2));
217
218 filters[num_endings] = (xitk_mrlbrowser_filter_t *)
219 xitk_xmalloc(sizeof(xitk_mrlbrowser_filter_t));
220
221 filters[num_endings]->name = strdup(patterns);
222 filters[num_endings]->ending = strdup(e);
223 }
224
225 free(mrl_exts);
226 }
227
228 filters[num_endings + 1] = (xitk_mrlbrowser_filter_t *)
229 xitk_xmalloc(sizeof(xitk_mrlbrowser_filter_t));
230 filters[num_endings + 1]->name = NULL;
231 filters[num_endings + 1]->ending = NULL;
232
233 return filters;
234 }
235
236
237 /*
238 *
239 */
mrl_browser(gGui_t * gui,xitk_mrl_callback_t add_cb,xitk_mrl_callback_t play_cb,select_cb_t sel_cb,xitk_dnd_callback_t dnd_cb)240 static xui_mrlb_t *mrl_browser (gGui_t *gui,
241 xitk_mrl_callback_t add_cb, xitk_mrl_callback_t play_cb, select_cb_t sel_cb, xitk_dnd_callback_t dnd_cb) {
242 xui_mrlb_t *mrlb;
243 xitk_mrlbrowser_widget_t mb;
244 const char *const *ip_availables;
245 xitk_mrlbrowser_filter_t **mrl_filters;
246
247 if (!gui)
248 return NULL;
249
250 if (gui->mrlb) {
251 show_mrl_browser (gui->mrlb);
252 set_mrl_browser_transient (gui->mrlb);
253 return gui->mrlb;
254 }
255
256 mrlb = calloc (1, sizeof (*mrlb));
257 if (!mrlb)
258 return NULL;
259 mrlb->gui = gui;
260
261 ip_availables = xine_get_browsable_input_plugin_ids (mrlb->gui->xine);
262 mrl_filters = mrl_browser_get_valid_mrl_ending (mrlb);
263
264 XITK_WIDGET_INIT (&mb, mrlb->gui->imlib_data);
265
266 mb.window_trans = (mrlb->gui->use_root_window || mrlb->gui->video_display != mrlb->gui->display) ? None
267 : mrlb->gui->video_window;
268 mb.layer_above = (is_layer_above ());
269 mb.icon = &mrlb->gui->icon;
270 mb.set_wm_window_normal = !video_window_is_visible (mrlb->gui->vwin);
271 mb.x = xine_config_register_num (mrlb->gui->xine, "gui.mrl_browser_x",
272 200, "gui mrl browser x coordinate",
273 CONFIG_NO_HELP, CONFIG_LEVEL_DEB, CONFIG_NO_CB, CONFIG_NO_DATA);
274 mb.y = xine_config_register_num (mrlb->gui->xine, "gui.mrl_browser_y",
275 100, "gui mrl browser y coordinate",
276 CONFIG_NO_HELP, CONFIG_LEVEL_DEB, CONFIG_NO_CB, CONFIG_NO_DATA);
277 mb.window_title = _("xine MRL Browser");
278
279 mb.skin_element_name = "MrlBG";
280 mb.resource_name = mb.window_title;
281 mb.resource_class = "xine";
282
283 mb.origin.skin_element_name = "MrlCurOrigin";
284 mb.origin.cur_origin = NULL;
285
286 mb.dndcallback = dnd_cb;
287 mb.dnddata = gui;
288
289 mb.select.skin_element_name = "MrlSelect";
290 mb.select.caption = _("Add");
291 mb.select.callback = add_cb;
292 mb.select.data = mrlb;
293
294 mb.play.skin_element_name = "MrlPlay";
295 mb.play.callback = play_cb;
296 mb.play.data = mrlb;
297
298 mb.dismiss.skin_element_name = "MrlDismiss";
299 mb.dismiss.caption = _("Dismiss");
300
301 mb.kill.callback = mrl_browser_kill;
302 mb.kill.data = mrlb;
303
304 mb.ip_availables = ip_availables;
305
306 mb.ip_name.button.skin_element_name = "MrlPlugNameBG";
307
308 mb.ip_name.label.skin_element_name = "MrlPlugLabel";
309 /* TRANSLATORS: only ASCII characters (skin) */
310 mb.ip_name.label.label_str = pgettext ("skin", "Source:");
311
312 mb.xine = mrlb->gui->xine;
313
314 /* The browser */
315
316 mb.browser.arrow_up.skin_element_name = "MrlUp";
317 mb.browser.slider.skin_element_name = "SliderMrl";
318 mb.browser.arrow_dn.skin_element_name = "MrlDn";
319
320 mb.browser.arrow_left.skin_element_name = "MrlLeft";
321 mb.browser.slider_h.skin_element_name = "SliderHMrl";
322 mb.browser.arrow_right.skin_element_name = "MrlRight";
323
324 mb.browser.browser.skin_element_name = "MrlItemBtn";
325 mb.browser.browser.num_entries = 0;
326 mb.browser.browser.entries = NULL;
327 mb.browser.callback = sel_cb;
328 mb.browser.userdata = mrlb;
329
330 mb.combo.skin_element_name = "MrlFilt";
331
332 mb.mrl_filters = mrl_filters;
333
334 mrlb->w = xitk_mrlbrowser_create (NULL, mrlb->gui->skin_config, &mb);
335
336 if(mrl_filters) {
337 int i;
338
339 for(i = 0; mrl_filters[i] && (mrl_filters[i]->name && mrl_filters[i]->ending); i++) {
340 free(mrl_filters[i]->name);
341 free(mrl_filters[i]->ending);
342 free(mrl_filters[i]);
343 }
344 free(mrl_filters[i]);
345 free(mrl_filters);
346 }
347
348 mrlb->gui->mrlb = mrlb;
349 return mrlb;
350 }
351
352 /*
353 *
354 */
mrl_handle_selection(xitk_widget_t * w,void * data,int selected)355 static void mrl_handle_selection (xitk_widget_t *w, void *data, int selected) {
356 (void)w;
357 (void)data;
358 (void)selected;
359 }
360
361 /*
362 * Callback called by mrlbrowser on add event.
363 */
mrl_add_noautoplay(xitk_widget_t * w,void * data,xine_mrl_t * mrl)364 static void mrl_add_noautoplay(xitk_widget_t *w, void *data, xine_mrl_t *mrl) {
365 xui_mrlb_t *mrlb = data;
366
367 (void)w;
368 if (mrlb && mrl) {
369 int num = mrlb->gui->playlist.num;
370
371 if(!playlist_is_running()) {
372 playlist_editor();
373 }
374 else {
375 if(!playlist_is_visible())
376 playlist_toggle_visibility(NULL, NULL);
377 }
378
379 mediamark_append_entry((char *)mrl->mrl, (char *)mrl->mrl, NULL, 0, -1, 0, 0);
380
381 if ((!num) && ((xine_get_status (mrlb->gui->stream) == XINE_STATUS_STOP) || mrlb->gui->logo_mode)) {
382 mrlb->gui->playlist.cur = mrlb->gui->playlist.num - 1;
383 gui_set_current_mmk(mediamark_get_current_mmk());
384 }
385
386 playlist_update_playlist();
387
388 if ((!is_playback_widgets_enabled (mrlb->gui->panel)) && mrlb->gui->playlist.num)
389 enable_playback_controls (mrlb->gui->panel, 1);
390 }
391 }
392
mrl_add(xitk_widget_t * w,void * data,xine_mrl_t * mrl)393 static void mrl_add(xitk_widget_t *w, void *data, xine_mrl_t *mrl) {
394 xui_mrlb_t *mrlb = data;
395
396 (void)w;
397 if (mrlb && mrl) {
398
399 if(!playlist_is_running()) {
400 playlist_editor();
401 }
402 else {
403 if(!playlist_is_visible())
404 playlist_toggle_visibility(NULL, NULL);
405 }
406
407 gui_dndcallback((char *)mrl->mrl);
408 }
409 }
410
411 /*
412 * Callback called by mrlbrowser on play event.
413 */
mrl_play(xitk_widget_t * w,void * data,xine_mrl_t * mrl)414 static void mrl_play(xitk_widget_t *w, void *data, xine_mrl_t *mrl) {
415 xui_mrlb_t *mrlb = data;
416
417 (void)w;
418 if (mrlb && mrl) {
419 mediamark_t mmk;
420 char *_mrl = mrl->mrl;
421
422 if ((xine_get_status (mrlb->gui->stream) != XINE_STATUS_STOP)) {
423 mrlb->gui->ignore_next = 1;
424 xine_stop (mrlb->gui->stream);
425 mrlb->gui->ignore_next = 0;
426 }
427
428 if (!is_playback_widgets_enabled (mrlb->gui->panel))
429 enable_playback_controls (mrlb->gui->panel, 1);
430
431 if(mrl_look_like_playlist(_mrl)) {
432 if(mediamark_concat_mediamarks(_mrl)) {
433 gui_set_current_mmk(mediamark_get_current_mmk());
434 _mrl = (char *) mediamark_get_current_mrl();
435 playlist_update_playlist();
436 }
437 }
438
439 osd_hide();
440
441 if (!xine_open (mrlb->gui->stream, (const char *) _mrl)) {
442 gui_handle_xine_error (mrlb->gui->stream, _mrl);
443 enable_playback_controls (mrlb->gui->panel, 0);
444 gui_display_logo();
445 return;
446 }
447
448 if (!gui_xine_play (mrlb->gui, mrlb->gui->stream, 0, 0, 0)) {
449 enable_playback_controls (mrlb->gui->panel, 0);
450 gui_display_logo();
451 return;
452 }
453
454 mmk.mrl = _mrl;
455 mmk.ident = NULL;
456 mmk.sub = NULL;
457 mmk.start = 0;
458 mmk.end = -1;
459 mmk.av_offset = 0;
460 mmk.spu_offset = 0;
461 mmk.got_alternate = 0;
462 mmk.alternates = NULL;
463 mmk.cur_alt = NULL;
464 gui_set_current_mmk(&mmk);
465 }
466 }
467
mrl_browser_reparent(xui_mrlb_t * mrlb)468 void mrl_browser_reparent (xui_mrlb_t *mrlb) {
469 if (mrlb && mrlb->w)
470 reparent_window ((xitk_mrlbrowser_get_window_id (mrlb->w)));
471 }
472
473 /*
474 * Create a new mrl browser.
475 */
open_mrlbrowser(xitk_widget_t * w,void * data)476 void open_mrlbrowser(xitk_widget_t *w, void *data) {
477 gGui_t *gui = data;
478
479 if (gui) {
480 mrl_browser (gui, mrl_add, mrl_play, mrl_handle_selection, gui_dndcallback);
481 set_mrl_browser_transient (gui->mrlb);
482 mrl_browser_show_tips (gui->mrlb, panel_get_tips_enable (gui->panel), panel_get_tips_timeout (gui->panel));
483 }
484 }
485
open_mrlbrowser_from_playlist(xitk_widget_t * w,void * data)486 void open_mrlbrowser_from_playlist(xitk_widget_t *w, void *data) {
487 gGui_t *gui = data;
488
489 if (gui) {
490 mrl_browser (gui, mrl_add_noautoplay, mrl_play, mrl_handle_selection, gui_dndcallback);
491 set_mrl_browser_transient (gui->mrlb);
492 mrl_browser_show_tips (gui->mrlb, panel_get_tips_enable (gui->panel), panel_get_tips_timeout (gui->panel));
493 }
494 }
495