#include typedef struct ItemEntry ItemEntry; typedef struct VideoCtrls VideoCtrls; typedef struct DemoApp { CltrAnimator *anim; CltrWidget *list; CltrWidget *video; CltrWidget *win; GList *items; /* video stuff */ gboolean paused; VideoCtrls *video_ctrls; gboolean ignore_next_xevent_hack; } DemoApp; struct ItemEntry { gchar *nice_name; gchar *path; gchar *uri; gint64 stoptime; CltrListCell *cell; }; enum { VIDEO_PLAY_BTN = 0, VIDEO_STOP_BTN, VIDEO_REWND_BTN, VIDEO_FFWD_BTN, VIDEO_VOLUP_BTN, VIDEO_VOLDOWN_BTN, VIDEO_BEGIN_BTN, N_VIDEO_BTNS }; struct VideoCtrls { ClutterFont *font; CltrWidget *container; CltrWidget *buttons[N_VIDEO_BTNS]; }; static void zoom_out_complete (CltrAnimator *anim, void *userdata); static void zoom_video_out(DemoApp *app); void handle_xevent(CltrWidget *win, XEvent *xev, void *cookie); int usage(char *progname) { fprintf(stderr, "Usage ... check source for now\n"); exit(-1); } /* video control buttons */ void video_ctrl_hide(DemoApp *app) { cltr_widget_hide(app->video_ctrls->container); cltr_window_focus_widget(CLTR_WINDOW(app->win), app->video); app->ignore_next_xevent_hack = TRUE; /* urg */ cltr_window_on_xevent(CLTR_WINDOW(app->win), handle_xevent, app); } void video_ctrl_stop_cb(CltrButton *button, void *cookie) { DemoApp *app = (DemoApp*)cookie; cltr_widget_hide(app->video_ctrls->container); cltr_window_focus_widget(CLTR_WINDOW(app->win), app->list); zoom_video_out(app); } void video_ctrl_play_cb(CltrButton *button, void *cookie) { DemoApp *app = (DemoApp*)cookie; VideoCtrls *v = app->video_ctrls; PixbufPixel col = { 0xff, 0xff, 0xff, 0xff }; if (app->paused) { cltr_video_play (CLTR_VIDEO(app->video), NULL); cltr_button_set_label(CLTR_BUTTON(v->buttons[VIDEO_PLAY_BTN]), "PAUSE", v->font, &col); app->paused = FALSE; video_ctrl_hide(app); } else { cltr_button_set_label(CLTR_BUTTON(v->buttons[VIDEO_PLAY_BTN]), "PLAY", v->font, &col); cltr_video_pause (CLTR_VIDEO(app->video)); app->paused = TRUE; cltr_widget_queue_paint(v->buttons[VIDEO_PLAY_BTN]); } } void video_ctrl_seek_begin_cb(CltrButton *button, void *cookie) { DemoApp *app = (DemoApp*)cookie; video_ctrl_hide(app); cltr_video_seek (CLTR_VIDEO(app->video), 0.0, NULL); } void init_video_ctrl(DemoApp *app) { VideoCtrls *v; int width, height, x =0, y = 0; PixbufPixel col = { 0xff, 0xff, 0xff, 0xff }; v = app->video_ctrls = g_malloc0(sizeof(VideoCtrls)); v->font = font_new ("Sans Bold 20"); font_get_pixel_size (v->font, "1234567890", &width, &height); height += 6; v->container = cltr_overlay_new(width, height * 3 /*N_VIDEO_BTNS*/); v->buttons[VIDEO_PLAY_BTN] = cltr_button_new(width, height-1); cltr_button_set_label(CLTR_BUTTON(v->buttons[VIDEO_PLAY_BTN]), "PAUSE", v->font, &col); cltr_button_on_activate(CLTR_BUTTON(v->buttons[VIDEO_PLAY_BTN]), video_ctrl_play_cb, (void *)app); cltr_widget_add_child(v->container, v->buttons[VIDEO_PLAY_BTN], x, y); y += height; v->buttons[VIDEO_STOP_BTN] = cltr_button_new(width, height-1); cltr_button_set_label(CLTR_BUTTON(v->buttons[VIDEO_STOP_BTN]), "STOP", v->font, &col); cltr_button_on_activate(CLTR_BUTTON(v->buttons[VIDEO_STOP_BTN]), video_ctrl_stop_cb, (void *)app); cltr_widget_add_child(v->container, v->buttons[VIDEO_STOP_BTN], x, y); y += height; v->buttons[VIDEO_REWND_BTN] = cltr_button_new(width, height-1); cltr_button_set_label(CLTR_BUTTON(v->buttons[VIDEO_REWND_BTN]), "BEGIN", v->font, &col); cltr_button_on_activate(CLTR_BUTTON(v->buttons[VIDEO_REWND_BTN]), video_ctrl_seek_begin_cb, (void *)app); cltr_widget_add_child(v->container, v->buttons[VIDEO_REWND_BTN], x, y); y += height; /* v->buttons[VIDEO_FFWD_BTN] = cltr_button_new(width, height-1); cltr_button_set_label(CLTR_BUTTON(v->buttons[VIDEO_FFWD_BTN]), "FFWD", v->font, &col); cltr_widget_add_child(v->container, v->buttons[VIDEO_FFWD_BTN], x, y); y += height; */ cltr_widget_add_child(app->video, v->container, 100, 100); /* focus - URG !*/ cltr_widget_set_focus_next(v->buttons[VIDEO_PLAY_BTN], v->buttons[VIDEO_STOP_BTN], CLTR_SOUTH); cltr_widget_set_focus_next(v->buttons[VIDEO_STOP_BTN], v->buttons[VIDEO_PLAY_BTN], CLTR_NORTH); cltr_widget_set_focus_next(v->buttons[VIDEO_STOP_BTN], v->buttons[VIDEO_REWND_BTN], CLTR_SOUTH); cltr_widget_set_focus_next(v->buttons[VIDEO_REWND_BTN], v->buttons[VIDEO_STOP_BTN], CLTR_NORTH); cltr_widget_set_focus_next(v->buttons[VIDEO_REWND_BTN], v->buttons[VIDEO_PLAY_BTN], CLTR_SOUTH); } void show_video_ctrl(DemoApp *app) { cltr_widget_show_all(app->video_ctrls->container); } /* ********************* */ gboolean populate(DemoApp *app, char *path) { GDir *dir; GError *error; const gchar *entry = NULL; int n_pixb = 0, i =0; CltrList *list = CLTR_LIST(app->list); Pixbuf *default_thumb_pixb = NULL; default_thumb_pixb = pixbuf_new_from_file("clutter-logo-800x600.png"); if (!default_thumb_pixb) g_error( "failed to open clutter-logo-800x600.png\n"); if ((dir = g_dir_open (path, 0, &error)) == NULL) { /* handle this much better */ g_error( "failed to open '%s'\n", path); return FALSE; } g_printf("One sec."); while ((entry = g_dir_read_name (dir)) != NULL) { Pixbuf *pixb = NULL; gint i = 0; ItemEntry *new_item; char *img_path; char *seek_path, *seek_data = NULL; gint64 seek_time = 0; /* Eeek! */ if (!(g_str_has_suffix (entry, ".mpg") || g_str_has_suffix (entry, ".MPG") || g_str_has_suffix (entry, ".mpg4") || g_str_has_suffix (entry, ".MPG4") || g_str_has_suffix (entry, ".avi") || g_str_has_suffix (entry, ".mov") || g_str_has_suffix (entry, ".MOV") || g_str_has_suffix (entry, ".ogg") || g_str_has_suffix (entry, ".OGG") || g_str_has_suffix (entry, ".AVI"))) { continue; } new_item = g_malloc0(sizeof(ItemEntry)); new_item->nice_name = g_strdup(entry); i = strlen(new_item->nice_name) - 1; while (i-- && new_item->nice_name[i] != '.') ; if (i > 0) new_item->nice_name[i] = '\0'; seek_path = g_strconcat(path, "/", new_item->nice_name, ".seek", NULL); if (g_file_get_contents (seek_path, &seek_data, NULL, NULL)) { seek_time = atol(seek_data); } img_path = g_strconcat(path, "/", new_item->nice_name, ".png", NULL); pixb = pixbuf_new_from_file(img_path); if (!pixb) pixb = default_thumb_pixb; new_item->cell = cltr_list_cell_new(list, pixb, new_item->nice_name); cltr_list_append_cell(list, new_item->cell); new_item->uri = g_strconcat("file://", path, "/", entry, NULL); new_item->path = g_strdup(path); new_item->stoptime = seek_time; app->items = g_list_append(app->items, new_item); g_free(img_path); g_printf("."); } g_dir_close (dir); g_printf("\n"); return TRUE; } ItemEntry* cell_to_item(DemoApp *app, CltrListCell *cell) { GList *item = NULL; item = g_list_first(app->items); while (item) { ItemEntry *entry = item->data; if (entry->cell == cell) return entry; item = g_list_next(item); } return NULL; } void zoom_video_out(DemoApp *app) { ItemEntry *item; char filename[1024]; Pixbuf *spixb, *dpixb; int dstx, dsty, dstw, dsth; PixbufPixel col = { 0, 0, 0, 0xff }; int x1, y1, x2, y2; FILE *fp; cltr_video_pause (CLTR_VIDEO(app->video)); item = cell_to_item(app, cltr_list_get_active_cell(CLTR_LIST(app->list))); item->stoptime = cltr_video_get_time (CLTR_VIDEO(app->video)); snprintf(filename, 1024, "%s/%s.png", item->path, item->nice_name); spixb = cltr_video_get_pixbuf (CLTR_VIDEO(app->video)); /* fixup pixbuf so scaled like video * */ /* XXX wrongly assume width > height */ dstw = spixb->width; dsth = (spixb->width * cltr_widget_height(app->win)) / cltr_widget_width(app->win) ; printf("dsth %i, spixb h %i\n", dsth, spixb->height); dsty = (dsth - spixb->height)/2; dstx = 0; dpixb = pixbuf_new(dstw, dsth); pixbuf_fill_rect(dpixb, 0, 0, -1, -1, &col); pixbuf_copy(spixb, dpixb, 0, 0, spixb->width, spixb->height, dstx, dsty); cltr_list_cell_set_pixbuf(cltr_list_get_active_cell(app->list), dpixb); pixbuf_write_png(dpixb, filename); /* reset the viewing pixbuf */ pixbuf_unref(dpixb); /* write out the seektime too */ snprintf(filename, 1024, "%s/%s.seek", item->path, item->nice_name); fp = fopen(filename, "w"); if (fp) { fprintf(fp, "%li", item->stoptime); fclose(fp); } cltr_list_get_active_cell_video_box_co_ords(CLTR_LIST(app->list), &x1, &y1, &x2, &y2); cltr_video_stop (CLTR_VIDEO(app->video)); /* zoom out, XXX old anim needs freeing */ app->anim = cltr_animator_zoom_new(app->list, x1, y1, x2, y2, 0,0,800,600); printf("got return, seek time %li, %i, %i \n", cltr_video_get_time (CLTR_VIDEO(app->video)), x1, y1); cltr_widget_show(app->list); cltr_animator_run(app->anim, zoom_out_complete, app); return; } void init_show_controls(DemoApp *app) { /* app->anim = cltr_animator_move_new(app->video_ctrls->container, -100, 200, 100, 200); cltr_widget_show_all(app->video_ctrls->container); cltr_animator_run(app->anim, NULL, app); */ cltr_widget_show_all(app->video_ctrls->container); cltr_window_focus_widget(CLTR_WINDOW(app->win), app->video_ctrls->buttons[VIDEO_PLAY_BTN]); cltr_window_on_xevent(CLTR_WINDOW(app->win), NULL, NULL); } void handle_xevent(CltrWidget *win, XEvent *xev, void *cookie) { KeySym kc; DemoApp *app = (DemoApp*)cookie; /* * XXX really need to think about not queuing xevents in * the current queue or something :/ */ if (app->ignore_next_xevent_hack) { app->ignore_next_xevent_hack = FALSE; return; } if (xev->type == KeyPress) { XKeyEvent *xkeyev = &xev->xkey; kc = XKeycodeToKeysym(xkeyev->display, xkeyev->keycode, 0); switch (kc) { case XK_Return: { init_show_controls(app); /* zoom_video_out(app); */ } break; } } } static void zoom_out_complete (CltrAnimator *anim, void *userdata) { DemoApp *app = (DemoApp*)userdata; cltr_window_on_xevent(CLTR_WINDOW(app->win), NULL, NULL); cltr_widget_hide(app->video); cltr_widget_queue_paint(app->win); } void zoom_in_complete (CltrAnimator *anim, void *userdata) { DemoApp *app = (DemoApp*)userdata; ItemEntry *item; /* cltr_animator_reset(anim); */ item = cell_to_item(app, cltr_list_get_active_cell(app->list)); app->paused = FALSE; cltr_video_set_source(CLTR_VIDEO(app->video), item->uri); if (item->stoptime) { printf("*** seeking to %li\n", item->stoptime); cltr_video_seek_time (CLTR_VIDEO(app->video), item->stoptime, NULL); } cltr_video_play(CLTR_VIDEO(app->video), NULL); if (item->stoptime) { printf("*** seeking to %li\n", item->stoptime); cltr_video_seek_time (CLTR_VIDEO(app->video), item->stoptime, NULL); } cltr_widget_show(app->video); cltr_widget_hide(CLTR_WIDGET(app->list)); cltr_window_on_xevent(CLTR_WINDOW(app->win), handle_xevent, app); } void cell_activated (CltrList *list, CltrListCell *cell, void *userdata) { DemoApp *app = (DemoApp*)userdata; int x1, y1, x2, y2; static have_added_child = 0; /* HACK */ cltr_list_get_active_cell_video_box_co_ords(CLTR_LIST(list), &x1, &y1, &x2, &y2); if (app->video == NULL) { /* app->video = cltr_video_new(x2-x1, y2-y1); cltr_widget_add_child(app->win, app->video, x1, y1); */ app->video = cltr_video_new(800, 600); cltr_widget_add_child(app->win, app->video, 0, 0); init_video_ctrl(app); } app->anim = cltr_animator_zoom_new(CLTR_WIDGET(list), 0,0,800,600, x1, y1, x2, y2); have_added_child = 1; cltr_animator_run(app->anim, zoom_in_complete, app); } int main(int argc, char **argv) { int i; CltrWidget *win = NULL, *list = NULL; CltrFont *font = NULL; PixbufPixel col = { 0xff, 0, 0, 0xff }; gchar *movie_path = NULL; gboolean want_fullscreen = FALSE; gint cols = 3; DemoApp *app; cltr_init(&argc, &argv); for (i = 1; i < argc; i++) { if (!strcmp ("--movie-path", argv[i]) || !strcmp ("-i", argv[i])) { if (++i>=argc) usage (argv[0]); movie_path = argv[i]; continue; } if (!strcmp ("--cols", argv[i]) || !strcmp ("-c", argv[i])) { if (++i>=argc) usage (argv[0]); cols = atoi(argv[i]); continue; } if (!strcmp ("-fs", argv[i]) || !strcmp ("--fullscreen", argv[i])) { want_fullscreen = TRUE; continue; } if (!strcmp("--help", argv[i]) || !strcmp("-h", argv[i])) { usage(argv[0]); } usage(argv[0]); } if (!movie_path) { g_error("usage: %s -i ", argv[0]); exit(-1); } app = g_malloc0(sizeof(DemoApp)); app->win = cltr_window_new(800, 600); if (want_fullscreen) cltr_window_set_fullscreen(CLTR_WINDOW(app->win)); app->list = cltr_list_new(800, 600, 800, 600/5); if (!populate(app, movie_path)) exit(-1); cltr_widget_add_child(app->win, app->list, 0, 0); cltr_window_focus_widget(CLTR_WINDOW(app->win), app->list); cltr_widget_show_all(app->win); cltr_list_on_activate_cell(CLTR_LIST(app->list), cell_activated, (gpointer)app); cltr_main_loop(); }