/* mb-desktop-xine - a desktop media playing module. Copyright 2004 Matthew Allum This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. */ #include "xinebrowser.h" /* Xine callbacks */ static void dest_size_cb(void *user_data, int video_width, int video_height, double video_pixel_aspect, int *dest_width, int *dest_height, double *dest_pixel_aspect) { BrowserData *data = (BrowserData *)user_data; *dest_width = data->width; *dest_height = data->height; *dest_pixel_aspect = data->pixel_aspect; } static void frame_output_cb(void *user_data, int video_width, int video_height, double video_pixel_aspect, int *dest_x, int *dest_y, int *dest_width, int *dest_height, double *dest_pixel_aspect, int *win_x, int *win_y) { BrowserData *data = (BrowserData *)user_data; int pos_stream, pos_time, length_time; if (data->showing_info && data->running) { xine_get_pos_length (data->stream, &pos_stream, &pos_time, &length_time); if ((pos_time - data->last_osd_show_time) >= 1000 ) { xinebrowser_show_info (data->mb, data, MBX_INFO_DPY_TIME); data->last_osd_show_time = pos_time; } } *dest_x = 0; *dest_y = 0; *win_x = 0; *win_y = 0; *dest_width = data->width; *dest_height = data->height; *dest_pixel_aspect = data->pixel_aspect; } static void event_listener(void *user_data, const xine_event_t *event) { BrowserData *data = (BrowserData *)user_data; switch(event->type) { case XINE_EVENT_UI_PLAYBACK_FINISHED: data->running = 2; break; case XINE_EVENT_PROGRESS: { char text[1024] = { 0 }; int text_w, text_h, cur_x, cur_y, max_w; xine_progress_data_t *pevent = (xine_progress_data_t *) event->data; printf("%s [%d%%]\n", pevent->description, pevent->percent); #if 0 /* Dont work ? */ xine_osd_clear (data->osd); snprintf(text, 1024, "%s [%d%%]\n", pevent->description, pevent->percent); xine_osd_get_text_size (data->osd, text, &text_w, &text_h); cur_y = text_h; cur_x = text_h; max_w = data->display_width - (2 * text_h); // xinebrowser_clip_osd (mb, data, &text, max_w); xine_osd_draw_text (data->osd, cur_x, cur_y, text, XINE_OSD_TEXT1); xine_osd_show(data->osd, 0); /* xine_gui_send_vo_data(data->stream, XINE_GUI_SEND_EXPOSE_EVENT, (void *) data->win); */ #endif } break; } } static MBDesktopItem * xinebrowser_get_prev_item(MBDesktop *mb, BrowserData *data, MBDesktopItem *item_sibling) { MBDesktopItem *item = NULL; item = mbdesktop_item_get_prev_sibling(item_sibling); while (item != NULL && mbdesktop_item_is_folder(mb,item)) { item = mbdesktop_item_get_prev_sibling(item); } if (item == NULL) { return xinebrowser_get_prev_item(mb, data, mbdesktop_item_get_last_sibling(item_sibling)); } return item; } static MBDesktopItem * xinebrowser_get_next_item(MBDesktop *mb, BrowserData *data, MBDesktopItem *item_sibling) { MBDesktopItem *item = NULL; item = mbdesktop_item_get_next_sibling(item_sibling); while (item != NULL && mbdesktop_item_is_folder(mb,item)) item = mbdesktop_item_get_next_sibling(item); if (item == NULL) { return xinebrowser_get_next_item(mb, data, mbdesktop_item_get_first_sibling(item_sibling)); } return item; } static MBDesktopItem * xinebrowser_get_random_item(MBDesktop *mb, BrowserData *data, MBDesktopItem *item) { /* MBDesktopItem *item = NULL; int n = 0, r = 0; item = mbdesktop_item_get_first_sibling(item); while (item = mbdesktop_item_get_next_sibling(item)) n++; r= 1+ (int) (n*rand()/(RAND_MAX+1.0)); */ } static void xinebrowser_dvd_send_event (MBDesktop *mb, BrowserData *data, int event_id) { xine_event_t event; event.type = event_id; event.stream = data->stream; event.data = NULL; event.data_length = 0; xine_event_send (data->stream, (xine_event_t *) (&event)); } void xinebrowser_win_open (MBDesktop *mb, BrowserData *data, Bool force_shm) { char *vo_driver = data->BrowserVideoDriver ; char *ao_driver = data->BrowserAudioDriver ; Display *display = data->display; int screen = mbdesktop_xscreen(mb); int res_h, res_v; x11_visual_t vis; if (force_shm) vo_driver = "xshm"; XLockDisplay(display); data->win = XCreateSimpleWindow(display, XDefaultRootWindow(display), 0, 0, 100, 100, 0, 0, 0); XSelectInput(display, data->win, (ExposureMask|ButtonPressMask|KeyPressMask| ButtonMotionMask|StructureNotifyMask| PropertyChangeMask|PointerMotionMask)); XChangeProperty(display, data->win, data->atoms[WINDOW_STATE], XA_ATOM, 32, PropModeReplace, (unsigned char *) &data->atoms[WINDOW_STATE_FULLSCREEN], 1); if(XShmQueryExtension(display) == True) data->completion_event = XShmGetEventBase(display) + ShmCompletion; else data->completion_event = -1; XMapRaised(display, data->win); res_h = (DisplayWidth(display, screen) * 1000 / DisplayWidthMM(display, screen)); res_v = (DisplayHeight(display, screen) * 1000 / DisplayHeightMM(display, screen)); XSync(display, False); XUnlockDisplay(display); vis.display = display; vis.screen = screen; vis.d = data->win; vis.dest_size_cb = dest_size_cb; vis.frame_output_cb = frame_output_cb; vis.user_data = (void *)data; data->pixel_aspect = (double)res_v / res_h; /* Assume we get fullscreen */ data->width = DisplayWidth(display, screen); data->height = DisplayHeight(display, screen); if(fabs(data->pixel_aspect - 1.0) < 0.01) data->pixel_aspect = 1.0; /* * Below could be bad, but seems to prevent crashes on ipaq * and no negative effects as yet ... ? */ if (data->pixel_aspect == 0.0) data->pixel_aspect = 1.0; data->vo_port = xine_open_video_driver(data->xine, vo_driver, XINE_VISUAL_TYPE_X11, (void *) &vis); data->ao_port = xine_open_audio_driver(data->xine , ao_driver, NULL); if (data->vo_port == NULL) fprintf(stderr, "mbdesktop-xine: *WARNING* vo_port is NULL\n"); if (data->ao_port == NULL) fprintf(stderr, "mbdesktop-xine: *WARNING* ao_port is NULL\n"); data->stream = xine_stream_new(data->xine, data->ao_port, data->vo_port); if (data->current_mode & MBX_MODE_MUSIC) { xine_post_out_t *audio_source; data->vis = xine_post_init (data->xine, data->BrowserVizPlugin, 0, &data->ao_port, &data->vo_port); if (data->vis) { audio_source = xine_get_audio_source (data->stream); if (!xine_post_wire_audio_port (audio_source, data->vis->audio_input[0])) fprintf(stderr, "mbdesktop-xine: Failed to rewire audio to visuals\n"); } else { fprintf(stderr, "mbdesktop-xine: Visual plugin '%s' not installed\n", data->BrowserVizPlugin ); } } else { data->vis = NULL; } data->event_queue = xine_event_new_queue(data->stream); data->osd = xine_osd_new (data->stream, 0, 0, DisplayWidth(display, screen), DisplayHeight(display, screen)); xine_osd_set_font (data->osd, "sans", 16); xine_osd_set_text_palette (data->osd, XINE_TEXTPALETTE_WHITE_BLACK_TRANSPARENT, XINE_OSD_TEXT1 ); /* Set Volume to Max - User can control volume via TV ? */ xine_set_param (data->stream, XINE_PARAM_AUDIO_VOLUME, data->volume); xine_event_create_listener_thread(data->event_queue, event_listener, (void *)data); xine_gui_send_vo_data(data->stream, XINE_GUI_SEND_DRAWABLE_CHANGED, (void *) data->win); xine_gui_send_vo_data(data->stream, XINE_GUI_SEND_VIDEOWIN_VISIBLE, (void *) 1); } void xinebrowser_win_close (MBDesktop *mb, BrowserData *data) { xine_osd_hide(data->osd, 0); xine_osd_clear(data->osd); xine_osd_free(data->osd); xine_stop(data->stream); xine_close(data->stream); xine_dispose(data->stream); data->stream = NULL; data->osd = NULL; if (data->vis) { xine_post_dispose (data->xine, data->vis); } xine_event_dispose_queue(data->event_queue); xine_close_audio_driver(data->xine, data->ao_port); xine_close_video_driver(data->xine, data->vo_port); XLockDisplay(data->display); XUnmapWindow(data->display, data->win); XDestroyWindow(data->display, data->win); XSync(data->display, False); XUnlockDisplay(data->display); } void xinebrowser_volume_change (MBDesktop *mb, BrowserData *data, int action) { char osd_text[1024] = { 0 }; if (!data->stream) return; if (action == MBX_VOLUME_TOGGLE_MUTE || data->is_muted) { if (data->is_muted) { data->is_muted = 0; snprintf(osd_text, 1024, "Volume [%d%%]", data->volume); } else { data->is_muted = 1; snprintf(osd_text, 1024, "Volume [Muted]"); } xine_set_param (data->stream, XINE_PARAM_AUDIO_MUTE, data->is_muted); } else if (action == MBX_VOLUME_INC) { if (data->volume < 100) data->volume++; snprintf(osd_text, 1024, "Volume [%d%%]", data->volume); xine_set_param (data->stream, XINE_PARAM_AUDIO_VOLUME, data->volume); } else /* MBX_VOLUME_DEC */ { if (data->volume) data->volume--; snprintf(osd_text, 1024, "Volume [%d%%]", data->volume); xine_set_param (data->stream, XINE_PARAM_AUDIO_VOLUME, data->volume); } if (data->osd) { int cur_x, cur_y, text_w, text_h; xine_osd_hide(data->osd, 0); xine_osd_clear (data->osd); xine_osd_get_text_size (data->osd, osd_text, &text_w, &text_h); cur_y = text_h; cur_x = text_h; xine_osd_draw_text (data->osd, cur_x, cur_y, osd_text, XINE_OSD_TEXT1); xine_osd_show(data->osd, 0); xine_osd_hide(data->osd, xine_get_current_vpts(data->stream)+(8*90000)); } } void xinebrowser_win_event_loop (MBDesktop *mb, BrowserData *data) { Display *display = data->display; int screen = mbdesktop_xscreen(mb); Bool old_show; Bool playing_fast = False; data->running = 1; data->showing_info = False; data->play_state = PLAY_STATE_NORMAL; data->last_osd_show_time = 0; while(data->running) { XEvent xevent; XNextEvent(display, &xevent); switch(xevent.type) { case KeyPress: { XKeyEvent kevent; KeySym ksym; char kbuf[256]; int len; int pos_stream; /* 0..65535 */ int pos_time; /* milliseconds */ int length_time;/* milliseconds */ kevent = xevent.xkey; XLockDisplay(display); len = XLookupString(&kevent, kbuf, sizeof(kbuf), &ksym, NULL); XUnlockDisplay(display); switch (ksym) { case XK_Home: if (data->current_mode == MBX_MODE_MOVIE_DVD) { xinebrowser_dvd_send_event (mb, data, XINE_EVENT_INPUT_MENU1); } break; /* also case BVW_DVD_TITLE_MENU: event.type = XINE_EVENT_INPUT_MENU2; break; case BVW_DVD_SUBPICTURE_MENU: event.type = XINE_EVENT_INPUT_MENU4; break; case BVW_DVD_AUDIO_MENU: event.type = XINE_EVENT_INPUT_MENU5; break; case BVW_DVD_ANGLE_MENU: event.type = XINE_EVENT_INPUT_MENU6; break; case BVW_DVD_CHAPTER_MENU: event.type = XINE_EVENT_INPUT_MENU7; break; */ case XK_i: if (data->showing_info) { data->showing_info = False; xine_osd_hide(data->osd, 0); } else data->showing_info = True; break; case XK_q: case XK_Q: data->running = 0; break; case XK_m: case XK_M: xinebrowser_volume_change (mb, data, MBX_VOLUME_TOGGLE_MUTE); break; case XK_plus: xinebrowser_volume_change (mb, data, MBX_VOLUME_INC); break; case XK_minus: xinebrowser_volume_change (mb, data, MBX_VOLUME_DEC); break; case XK_Up: if (data->current_mode == MBX_MODE_MOVIE_DVD) { xinebrowser_dvd_send_event (mb, data, XINE_EVENT_INPUT_UP); } else xinebrowser_volume_change (mb, data, MBX_VOLUME_INC); break; case XK_Down: if (data->current_mode == MBX_MODE_MOVIE_DVD) { xinebrowser_dvd_send_event (mb, data, XINE_EVENT_INPUT_DOWN); } else xinebrowser_volume_change (mb, data, MBX_VOLUME_DEC); break; case XK_Right: old_show = data->showing_info; data->showing_info = False; data->last_osd_show_time = 0; xine_osd_hide(data->osd, 0); if (data->current_mode == MBX_MODE_MUSIC_FILE) { data->current_item = xinebrowser_get_next_item(mb, data, data->current_item); xinebrowser_play(mb, data, mbdesktop_item_get_extended_name(mb, data->current_item)); xinebrowser_show_info (mb, data, MBX_INFO_TIMEOUT); } else if (data->current_mode == MBX_MODE_MUSIC_CD) { if (++data->cd_idx == data->cd_num_mrls) data->cd_idx = 0; /* Play next track */ if((!xine_open(data->stream, data->cd_mrls[data->cd_idx])) || (!xine_play(data->stream, 0, 0))) return; /* Failed to play */ xinebrowser_show_info (mb, data, MBX_INFO_TIMEOUT); } else if (data->current_mode == MBX_MODE_MOVIE_DVD) { xinebrowser_dvd_send_event (mb, data, XINE_EVENT_INPUT_RIGHT); /* XINE_EVENT_INPUT_NEXT ? */ } else { if (xine_get_pos_length (data->stream, &pos_stream, &pos_time, &length_time)) { if (!xine_play (data->stream, pos_stream+1000, 0 )) { fprintf(stderr, "mbdesktop-xine: seek failed\n"); } } } data->showing_info = old_show; break; case XK_Left: old_show = data->showing_info; data->showing_info = False; xine_osd_hide(data->osd, 0); if (data->current_mode == MBX_MODE_MUSIC_FILE) { data->current_item = xinebrowser_get_prev_item(mb, data, data->current_item); xinebrowser_play(mb, data, mbdesktop_item_get_extended_name(mb, data->current_item)); xinebrowser_show_info (mb, data, MBX_INFO_TIMEOUT); } else if (data->current_mode == MBX_MODE_MUSIC_CD) { if (--data->cd_idx < 0) data->cd_idx = 0; /* Play next track */ if((!xine_open(data->stream, data->cd_mrls[data->cd_idx])) || (!xine_play(data->stream, 0, 0))) return; /* Failed to play */ xinebrowser_show_info (mb, data, MBX_INFO_TIMEOUT); } else if (data->current_mode == MBX_MODE_MOVIE_DVD) { xinebrowser_dvd_send_event (mb, data, XINE_EVENT_INPUT_LEFT); /* XINE_EVENT_INPUT_PREV ? */ } else { if (xine_get_pos_length (data->stream, &pos_stream, &pos_time, &length_time)) { if (!xine_play (data->stream, (pos_stream-1000 > 0) ? pos_stream-1000 : 0, 0 )) { fprintf(stderr, "mbdesktop-xine: seek failed\n"); } } } data->showing_info = old_show; break; case XK_space: if(xine_get_param(data->stream, XINE_PARAM_SPEED) != XINE_SPEED_PAUSE) xine_set_param(data->stream, XINE_PARAM_SPEED, XINE_SPEED_PAUSE); else xine_set_param(data->stream, XINE_PARAM_SPEED, XINE_SPEED_NORMAL); break; case XK_f: if (playing_fast) { playing_fast = False; xine_set_param(data->stream, XINE_PARAM_SPEED, XINE_SPEED_NORMAL ); } else { playing_fast = True; xine_set_param(data->stream, XINE_PARAM_SPEED, XINE_SPEED_FAST_4 ); } break; case XK_Return: case XK_KP_Enter: if (data->current_mode == MBX_MODE_MOVIE_DVD) { xinebrowser_dvd_send_event (mb, data, XINE_EVENT_INPUT_SELECT); } else data->running = 0; /* Quit - func mainly for handhelds */ break; } } break; case Expose: if(xevent.xexpose.count != 0) break; xine_gui_send_vo_data(data->stream, XINE_GUI_SEND_EXPOSE_EVENT, &xevent); break; case ConfigureNotify: { XConfigureEvent *cev = (XConfigureEvent *) &xevent; Window tmp_win; /* printf("config notify: %ix%i +%i+%i vs %ix%i\n ", cev->width, cev->height, cev->x, cev->y, data->width, data->height); */ data->width = cev->width; data->height = cev->height; } break; } /* if(xevent.type == data->completion_event) xine_gui_send_vo_data(data->stream, XINE_GUI_SEND_COMPLETION_EVENT, &xevent); */ if (data->running == 2) /* Signals track has finished,*/ { old_show = data->showing_info; data->showing_info = False; xine_osd_hide(data->osd, 0); switch (data->current_mode) { case MBX_MODE_MUSIC_FILE: data->current_item = xinebrowser_get_next_item(mb, data, data->current_item); if (data->current_item == xinebrowser_get_next_item(mb, data, mbdesktop_item_get_first_sibling(data->current_item))) return; /* Dont loop */ xinebrowser_play(mb, data, mbdesktop_item_get_extended_name(mb, data->current_item)); xinebrowser_show_info (mb, data, MBX_INFO_TIMEOUT); break; case MBX_MODE_MUSIC_CD: if (++data->cd_idx == data->cd_num_mrls) return; /* CD finished, no loop */ /* Play next track */ if((!xine_open(data->stream, data->cd_mrls[data->cd_idx])) || (!xine_play(data->stream, 0, 0))) return; /* Failed to play */ xinebrowser_show_info (mb, data, MBX_INFO_TIMEOUT); break; default: return; /* Quit for mpegs. * Playlists will continue on */ } data->showing_info = old_show; data->running = 1; } } } static void clip_osd (MBDesktop *mb, BrowserData *data, char **text_to_clip, int max_width) { int width = 0, height = 0, i = 0; char *text = *text_to_clip; return; /* XXX xine_osd_get_text_size() broke for widths or me using it wrong ? */ i = strlen(text); do { text[i] = '\0'; xine_osd_get_text_size (data->osd, text, &width, &height); printf("%s -> %i vs %i\n", text, width, max_width); } while (width > max_width && --i > 0); } void xinebrowser_show_info (MBDesktop *mb, BrowserData *data, int info_flags) { int cur_y = 0, cur_x = 0, text_w = 0, text_h = 0, max_w; char *text = alloca(sizeof(char)*1024); int pos_stream; /* 0..65535 */ int pos_time; /* milliseconds */ int length_time; /* milliseconds */ xine_osd_clear (data->osd); snprintf(text, 1024, "Title : %s", (xine_get_meta_info(data->stream, XINE_META_INFO_TITLE) != NULL) ? xine_get_meta_info(data->stream, XINE_META_INFO_TITLE) : "Unknown" ); xine_osd_get_text_size (data->osd, text, &text_w, &text_h); cur_y = text_h; cur_x = text_h; max_w = data->display_width - (2 * text_h); clip_osd (mb, data, &text, max_w); xine_osd_draw_text (data->osd, cur_x, cur_y, text, XINE_OSD_TEXT1); cur_y += text_h; if (data->current_mode != MBX_MODE_MUSIC_RADIO) { if (xine_get_meta_info(data->stream, XINE_META_INFO_ARTIST)) { snprintf(text, 1024, "Artist : %s", xine_get_meta_info(data->stream, XINE_META_INFO_ARTIST)); clip_osd (mb, data, &text, max_w); xine_osd_draw_text (data->osd, cur_x, cur_y, text, XINE_OSD_TEXT1); cur_y += text_h; } if (xine_get_meta_info(data->stream, XINE_META_INFO_ALBUM)) { snprintf(text, 1024, "Album : %s", xine_get_meta_info(data->stream, XINE_META_INFO_ALBUM)); clip_osd (mb, data, &text, max_w); xine_osd_draw_text (data->osd, cur_x, cur_y, text, XINE_OSD_TEXT1); cur_y += text_h; } if (info_flags & MBX_INFO_DPY_TIME) { if (xine_get_pos_length (data->stream, &pos_stream, &pos_time, &length_time)) { int sec, min, hour, ttime; int rsec, rmin, rhour; ttime = pos_time/1000; sec = ttime % 60; ttime = ttime - sec; min = (ttime % (60*60)) / 60; ttime = ttime - (min * 60); hour = ttime / (60*60); ttime = (length_time-pos_time)/1000; rsec = ttime % 60; ttime = ttime - rsec; rmin = (ttime % (60*60)) / 60; ttime = ttime - (rmin * 60); rhour = ttime / (60*60); snprintf(text, 1024, "Time : %02d:%02d:%02d, %02d:%02d:%02d Remains", hour, min, sec, rhour, rmin, rsec); clip_osd (mb, data, &text, max_w); xine_osd_draw_text (data->osd, cur_x, cur_y, text, XINE_OSD_TEXT1); cur_y += text_h; } } } xine_osd_show(data->osd, 0); if (info_flags & MBX_INFO_TIMEOUT) xine_osd_hide(data->osd, xine_get_current_vpts(data->stream)+(4*90000)); } Bool xinebrowser_play(MBDesktop *mb, BrowserData *data, char *mrl) { if (mrl == NULL) return False; #if 0 if (data->current_mode == MBX_MODE_MUSIC_RADIO) { /* XXX Little bit of a hack, radio sets extended name as mrl ... */ mrl = alloca(strlen(current_path)); sprintf(mrl, "%s", current_path); } else { mrl = alloca(strlen(current_path)+strlen(item->name)+3); sprintf(mrl, "%s/%s", current_path, item->name); } #endif if (data->stream != NULL) xine_stop(data->stream); if((!xine_open(data->stream, mrl)) || (!xine_play(data->stream, 0, 0))) return False; return True; } MBPixbufImage * xinebrowser_make_thumbnail (MBDesktop *mb, BrowserData *data, char *mrl) { #define MIN_LEN_FOR_SEEK 25000 int length = 0; int pos_stream, pos_time; unsigned char *yuv, *y, *u, *v, *rgb; int width, height, ratio, format; MBPixbufImage *img = NULL, *img_scaled = NULL, *img_backing = NULL; if (xine_open (data->stream, mrl) == 0) { /* XXX need to close down here */ fprintf(stderr, "xine open error with %s\n", mrl); return NULL; } if (xine_play (data->stream, 0, 0) == 0) { fprintf(stderr, "failed to play %s\n", mrl); return NULL; } if (xine_get_pos_length (data->stream, &pos_stream, &pos_time, &length) == 0) { fprintf(stderr, "failed to get length of %s\n", mrl); return NULL; } if (length > MIN_LEN_FOR_SEEK) { if (xine_play (data->stream, (int) (65535 / 3), 0) == 0) { printf("hmm looks like initial xine play failed\n"); xine_play (data->stream, (int) (65535 / 3), 0); } } if (xine_get_current_frame (data->stream, &width, &height, &ratio, &format, NULL) == 0) { printf("xine_get_current_frame failed\n"); return NULL; } if (width == 0 || height == 0) { printf("width / height failed\n"); return NULL; } yuv = malloc ((width + 8) * (height + 1) * 2); if (xine_get_current_frame (data->stream, &width, &height, &ratio, &format, yuv) == 0) { printf("xine_get_current_frame 2 failed\n"); free (yuv); return NULL; } /* Convert to yv12 */ switch (format) { case XINE_IMGFMT_YUY2: { uint8_t *yuy2 = yuv; yuv = malloc (width * height * 2); y = yuv; u = yuv + width * height; v = yuv + width * height * 5 / 4; yuy2toyv12 (y, u, v, yuy2, width, height); free (yuy2); } break; case XINE_IMGFMT_YV12: y = yuv; u = yuv + width * height; v = yuv + width * height * 5 / 4; printf ("Format YV12\n"); break; default: printf ("Format '%.4s' unsupported", (char *) &format); free (yuv); return NULL; } /* Convert to rgb */ rgb = yv12torgb (y, u, v, width, height); img = mb_pixbuf_img_new_from_data(mb->pixbuf, rgb, width, height, False); /* Scaled image if needed */ if (width > mbdesktop_icon_size(mb) || height > mbdesktop_icon_size(mb)) { int scaled_w, scaled_h; if ( width > height ) { scaled_w = mbdesktop_icon_size(mb); scaled_h = ( mbdesktop_icon_size(mb) * height )/ width; } else { scaled_h = mbdesktop_icon_size(mb); scaled_w = ( mbdesktop_icon_size(mb) * width )/ height; } img_scaled = mb_pixbuf_img_scale(mb->pixbuf, img, scaled_w, scaled_h); img_backing = mb_pixbuf_img_rgba_new(mb->pixbuf, mbdesktop_icon_size(mb), mbdesktop_icon_size(mb)); mb_pixbuf_img_copy_composite (mb->pixbuf, img_backing, img_scaled, 0, 0, scaled_w, scaled_h, ( mbdesktop_icon_size(mb) - scaled_w)/2, ( mbdesktop_icon_size(mb) - scaled_h)/2); mb_pixbuf_img_free(mb->pixbuf, img); mb_pixbuf_img_free(mb->pixbuf, img_scaled); img = img_backing; } xine_stop(data->stream); return img; } int xinebrowser_init (MBDesktop *mb, MBDesktopFolderModule *folder_module, char *arg_str) { DIR *dp; struct dirent *dir_entry; struct stat stat_info; MBDesktopItem *folder; BrowserData *data = NULL; char xine_configfile[2048]; data = malloc(sizeof(BrowserData)); memset(data, 0, sizeof(BrowserData)); /* Defaults */ data->BrowserPath = "/movies"; data->BrowserFolderName = "Movies"; data->BrowserMusicPath = "/music"; data->BrowserMusicFolderName = "Music"; data->BrowserDrivePath = "/dev/dvd"; data->BrowserVizPlugin = "goom"; data->BrowserVideoDriver = "auto"; data->BrowserAudioDriver = "auto"; data->BrowserRadioPath = "/radio"; data->BrowserRadioFolderName = "Radio"; data->BrowserPlaylistsPath = "/playlists"; data->use_xshm_for_vis_hack = False; data->use_video_thumbnails = True; if (arg_str != NULL) { MBDotDesktop *dd; dd = mb_dotdesktop_new_from_file(arg_str); if (dd) { if (mb_dotdesktop_get(dd, "MoviePath")) { data->BrowserPath = strdup(mb_dotdesktop_get(dd, "MoviePath")); if (data->BrowserPath[strlen(data->BrowserPath)-1] == '/') data->BrowserPath[strlen(data->BrowserPath)-1] = '\0'; } if (mb_dotdesktop_get(dd, "MovieFolderName")) data->BrowserFolderName = strdup(mb_dotdesktop_get(dd, "MovieFolderName")); if (mb_dotdesktop_get(dd, "MusicPath")) { data->BrowserMusicPath = strdup(mb_dotdesktop_get(dd,"MusicPath")); if (data->BrowserMusicPath[strlen(data->BrowserMusicPath)-1] == '/') data->BrowserMusicPath[strlen(data->BrowserMusicPath)-1] = '\0'; } if (mb_dotdesktop_get(dd, "MusicFolderName")) data->BrowserMusicFolderName = strdup(mb_dotdesktop_get(dd,"MusicFolderName")); if (mb_dotdesktop_get(dd, "RadioFolderName")) data->BrowserRadioFolderName = strdup(mb_dotdesktop_get(dd,"RadioFolderName")); if (mb_dotdesktop_get(dd, "DrivePath")) data->BrowserDrivePath = strdup(mb_dotdesktop_get(dd,"DrivePath")); if (mb_dotdesktop_get(dd, "VizPlugin")) data->BrowserVizPlugin = strdup(mb_dotdesktop_get(dd,"VizPlugin")); if (mb_dotdesktop_get(dd, "VideoDriver")) data->BrowserVideoDriver = strdup(mb_dotdesktop_get(dd,"VideoDriver")); if (mb_dotdesktop_get(dd, "AudioDriver")) data->BrowserAudioDriver = strdup(mb_dotdesktop_get(dd,"AudioDriver")); if (mb_dotdesktop_get(dd, "RadioPath")) data->BrowserRadioPath = strdup(mb_dotdesktop_get(dd,"RadioPath")); if (mb_dotdesktop_get(dd, "PlaylistsPath")) data->BrowserPlaylistsPath = strdup(mb_dotdesktop_get(dd,"PlaylistsPath")); if (mb_dotdesktop_get(dd, "ForceXShmForVisuals") && !strcasecmp("true", mb_dotdesktop_get(dd, "ForceXShmForVisuals"))) data->use_xshm_for_vis_hack = True; if (mb_dotdesktop_get(dd, "ThumbnailVideo") && !strcasecmp("false", mb_dotdesktop_get(dd, "ThumbnailVideo"))) data->use_video_thumbnails = False; mb_dotdesktop_free(dd); } else { fprintf(stderr, "mbxine: Failed to open config '%s'. Using defualts\n", arg_str); } } data->current_mode = MBX_MODE_UNKNOWN; data->current_item = NULL; /* Create top level folders */ /* Movie folder */ if (lstat(data->BrowserPath, &stat_info) == 0 && (S_ISDIR(stat_info.st_mode))) { folder = mbdesktop_module_folder_create (mb, data->BrowserFolderName, "mbmoviefolder.png"); mbdesktop_item_set_user_data (mb, folder, (void *)data); mbdesktop_item_set_extended_name(mb, folder, data->BrowserFolderName); mbdesktop_item_folder_set_view (mb, folder, VIEW_LIST); mbdesktop_items_append_to_top_level (mb, folder); mbdesktop_item_set_activate_callback (mb, folder, xinebrowser_movie_open_cb); } else { fprintf(stderr, "mbxine: Not adding '%s' Folder. Path '%s' is invalid\n" , data->BrowserFolderName, data->BrowserPath ); } /* Music folder */ if ( (lstat(data->BrowserMusicPath, &stat_info) == 0 && (S_ISDIR(stat_info.st_mode))) || (lstat(data->BrowserPlaylistsPath, &stat_info) == 0 && (S_ISDIR(stat_info.st_mode))) || (lstat(data->BrowserRadioPath, &stat_info) == 0 && (S_ISDIR(stat_info.st_mode))) ) { MBDesktopItem *subitem = NULL; folder = mbdesktop_module_folder_create (mb, data->BrowserMusicFolderName, "mbmusicfolder.png"); mbdesktop_item_folder_set_view (mb, folder, VIEW_LIST); mbdesktop_item_set_user_data (mb, folder, (void *)data); mbdesktop_item_set_extended_name(mb, folder, data->BrowserMusicFolderName); mbdesktop_items_append_to_top_level (mb, folder); if ( (lstat(data->BrowserMusicPath, &stat_info) == 0 && (S_ISDIR(stat_info.st_mode)))) { subitem = mbdesktop_module_folder_create (mb, "Browse", "mbmusicfolder.png"); mbdesktop_item_set_extended_name(mb, subitem, data->BrowserMusicFolderName); mbdesktop_item_folder_set_view (mb, subitem, VIEW_LIST); mbdesktop_item_set_user_data (mb, subitem, (void *)data); mbdesktop_items_append_to_folder(mb, folder, subitem ); mbdesktop_item_set_activate_callback (mb, subitem, xinebrowser_music_open_cb); } else { fprintf(stderr, "mbxine: Not adding Music Browse. '%s' does not exist\n", data->BrowserMusicPath ); } /* Playlists */ if ( (lstat(data->BrowserPlaylistsPath, &stat_info) == 0 && (S_ISDIR(stat_info.st_mode)))) { subitem = mbdesktop_module_folder_create (mb, "Playlists", "mbmusicfolder.png"); mbdesktop_item_set_user_data(mb, subitem, (void *)data); mbdesktop_items_append_to_folder(mb, folder, subitem ); mbdesktop_item_set_activate_callback (mb, subitem, xinebrowser_playlists_open_cb); } else { fprintf(stderr, "mbxine: Not adding Playlists. '%s' does not exist\n", data->BrowserPlaylistsPath ); } /* subitem = mbdesktop_item_new_with_params( mb, "Play Random Tracks", NULL, NULL, ITEM_TYPE_MODULE_ITEM ); mbdesktop_item_set_user_data(mb, subitem, (void *)data); mbdesktop_items_append_to_folder(mb, folder, subitem ); subitem = mbdesktop_item_new_with_params( mb, "Play Random Albums", NULL, NULL, ITEM_TYPE_MODULE_ITEM ); mbdesktop_item_set_user_data(mb, subitem, (void *)data); mbdesktop_items_append_to_folder(mb, folder, subitem ); */ if (lstat(data->BrowserRadioPath, &stat_info) == 0 && (S_ISDIR(stat_info.st_mode))) { subitem = mbdesktop_module_folder_create (mb, data->BrowserRadioFolderName, "mbmusicfolder.png"); mbdesktop_item_folder_set_view (mb, subitem, VIEW_LIST); mbdesktop_item_set_user_data (mb, subitem, (void *)data); mbdesktop_item_set_extended_name(mb, subitem, "Radio"); mbdesktop_items_append_to_folder(mb, folder, subitem ); /* mbdesktop_items_append_to_top_level (mb, folder); */ mbdesktop_item_set_activate_callback (mb, subitem, xinebrowser_radio_open_cb); } else { fprintf(stderr, "mbxine: Not adding Radio. '%s' does not exist\n", data->BrowserRadioPath ); } } else { fprintf(stderr, "mbxine: Not adding '%s' Folder. No valid Radio, Music or Playlist paths\n" , data->BrowserMusicFolderName); } /* Radio folder */ /* Setup Disc */ if (stat(data->BrowserDrivePath, &stat_info) != -1) { MBDesktopItem *item_new = NULL; item_new = mbdesktop_item_new_with_params( mb, "Play Disc", "mbplaydisc.png", NULL, ITEM_TYPE_MODULE_ITEM ); mbdesktop_item_set_activate_callback (mb, item_new, xinebrowser_disc_activate_cb); mbdesktop_item_set_user_data (mb, item_new, (void *)data); mbdesktop_items_append_to_top_level (mb, item_new); } else { fprintf(stderr, "mbxine: Not disc items. '%s' does not exist\n", data->BrowserDrivePath ); } if(!XInitThreads()) { printf("XInitThreads() failed\n"); return 1; } /* As Xine threaded we use out own display connection */ data->display = XOpenDisplay(NULL); data->display_width = DisplayWidth(data->display, mbdesktop_xscreen(mb)); data->mb = mb; /* XXX not all these are needded anymore ... */ data->atoms[WINDOW_STATE] = XInternAtom(data->display, "_NET_WM_STATE",False); data->atoms[WINDOW_STATE_FULLSCREEN] = XInternAtom(data->display, "_NET_WM_STATE_FULLSCREEN",False); data->atoms[WINDOW_STATE_MODAL] = XInternAtom(data->display, "_NET_WM_STATE_MODAL",False); data->atoms[WINDOW_TYPE_DIALOG] = XInternAtom(data->display, "_NET_WM_WINDOW_TYPE_DIALOG",False); data->atoms[WINDOW_TYPE] = XInternAtom(data->display, "_NET_WM_WINDOW_TYPE",False); data->atoms[_NET_WM_NAME] = XInternAtom(data->display, "_NET_WM_NAME",False); data->atoms[UTF8_STRING] = XInternAtom(data->display, "UTF8_STRING",False); /* Xine init stuff */ data->xine = xine_new(); sprintf(xine_configfile, "%s%s", xine_get_homedir(), "/.xine/config"); xine_config_load(data->xine, xine_configfile); xine_init(data->xine); data->volume = 80; data->is_muted = 0; return 1; } #define MODULE_NAME "mbdesktop-xine" #define MODULE_DESC "Xine based Media Browser/Player" #define MODULE_AUTHOR "Matthew Allum" #define MODULE_MAJOR_VER 0 #define MODULE_MINOR_VER 0 #define MODULE_MICRO_VER 2 #define MODULE_API_VERSION 0 MBDesktopModuleInfo xinebrowser_info = { MODULE_NAME , MODULE_DESC , MODULE_AUTHOR , MODULE_MAJOR_VER , MODULE_MINOR_VER , MODULE_MICRO_VER , MODULE_API_VERSION }; MBDesktopFolderModule folder_module = { &xinebrowser_info, xinebrowser_init, NULL, NULL };