diff -r d2d226b5a4bd -r 987fafbda04d maemo-ui-old/src/mmyth_epg_grid_widget.c --- a/maemo-ui-old/src/mmyth_epg_grid_widget.c Fri Feb 01 14:30:21 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,776 +0,0 @@ -#include -#include -#include - -#include "mmyth_uicommon.h" -#include "mmyth_epg_grid_widget.h" - -#include -#include - -#define PIXELS_HOUR 105 -#define PROGRAM_SEPARATION 2 - -enum { - SELECTION_UPDATED_SIGNAL, - LAST_SIGNAL -}; - -struct _MMythEpgGridWidgetPrivate { - /* - * private widget components - */ - GtkWidget *epg_channels_vbox; - GtkWidget *epg_programs_vbox; - - GHashTable *service_model_hash; - - /* - * guidegrid attributes - */ - gboolean show_favorites; - gint current_start_channel_id; - - GTimeVal *current_start_time; - GTimeVal *current_end_time; - - guint selected_channel_index; - - /* - * GList of ProgramInfo for each Channel - */ - GList *program_list[MAX_DISPLAY_CHANS]; - GList *channel_list; - - GMythEPG *mmyth_epg; - - GMythBackendInfo *backend_info; - - gint DISPLAY_CHANS; -}; - -static void mmyth_epg_grid_widget_class_init(MMythEpgGridWidgetClass * - klass); -static void mmyth_epg_grid_widget_init(MMythEpgGridWidget * object); -static void -mmyth_epg_grid_widget_private_init(MMythEpgGridWidgetPrivate * private); -static void mmyth_epg_grid_widget_mount_services(MMythEpgGridWidget * - object, - GTimeVal * start_time, - GTimeVal * end_time); -static void mmyth_epg_grid_widget_mount_header(MMythEpgGridWidget * - object); -static void mmyth_epg_grid_widget_clicked(GtkWidget * widget, - GdkEventExpose * event, - gpointer data); -static GtkWidget *create_event_box_lbl(gchar * str, int width, - const GdkColor * bg_color, - const GdkColor * fg_color); - -static void -mmyth_epg_grid_widget_fill_programinfos(MMythEpgGridWidgetPrivate * - private); -static void -mmyth_epg_grid_widget_fill_program_row_infos(MMythEpgGridWidgetPrivate * - private, unsigned int chanNum, - unsigned int row); - -static gint mmyth_epg_grid_widget_signals[LAST_SIGNAL] = { 0 }; - -G_DEFINE_TYPE(MMythEpgGridWidget, mmyth_epg_grid_widget, - GTK_TYPE_EVENT_BOX) - - static void - - - - - - - - - - - - - - mmyth_epg_grid_widget_class_init(MMythEpgGridWidgetClass * klass) -{ - g_type_class_add_private(klass, sizeof(MMythEpgGridWidgetPrivate)); - - mmyth_epg_grid_widget_signals[SELECTION_UPDATED_SIGNAL] = - g_signal_new("selection_updated", G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_FIRST, 0, NULL, NULL, - g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, - G_TYPE_POINTER); -} - -static void -mmyth_epg_grid_widget_private_init(MMythEpgGridWidgetPrivate * private) -{ - time_t cur_time; - - g_return_if_fail(private != NULL); - - private->epg_channels_vbox = NULL; - private->epg_programs_vbox = NULL; - private->service_model_hash = NULL; - - private->show_favorites = FALSE; - private->current_start_channel_id = -1; - - /* - * Selected the first diplayable channel initially - */ - private->selected_channel_index = 0; - - /* - * TODO fix the current start/end time - */ - private->current_start_time = g_new0(GTimeVal, 1); - private->current_start_time->tv_sec = time(&cur_time); - - private->current_end_time = g_new0(GTimeVal, 1); - private->current_end_time->tv_sec = time(&cur_time) + 10800; - - private->DISPLAY_CHANS = MAX_DISPLAY_CHANS; - - private->backend_info = - gmyth_backend_info_new_full("localhost", "mythtv", "mythtv", - "mythconverg", 6543); - - // TODO: Close the epg and unref it in dispose call - private->mmyth_epg = gmyth_epg_new(); - if (!gmyth_epg_connect(private->mmyth_epg, private->backend_info)) { - g_warning("[%s] Could not connect mysql handler to db", - __FUNCTION__); - g_object_unref(private->mmyth_epg); - private->mmyth_epg = NULL; - } -} - -static void -mmyth_epg_grid_widget_init(MMythEpgGridWidget * mmyth_epg_grid_widget) -{ - MMythEpgGridWidgetPrivate *private = - MMYTH_EPG_GRID_WIDGET_GET_PRIVATE(mmyth_epg_grid_widget); - - /* - * init private fields - */ - mmyth_epg_grid_widget_private_init(private); - - mmyth_epg_grid_widget->epg_view_model = NULL; - mmyth_epg_grid_widget->selected_grid_item = NULL; - - GtkWidget *epg_event_box = GTK_WIDGET(mmyth_epg_grid_widget); - gtk_widget_modify_bg(epg_event_box, GTK_STATE_NORMAL, &main_bg_color); - gtk_widget_set_size_request(epg_event_box, 0, 125); - - GtkWidget *epg_main_hbox = gtk_hbox_new(FALSE, 10); - gtk_container_set_border_width(GTK_CONTAINER(epg_main_hbox), 10); - - gtk_container_add(GTK_CONTAINER(epg_event_box), epg_main_hbox); - - /* - * channels vbox - */ - GtkWidget *epg_channels_vbox = gtk_vbox_new(FALSE, 3); - private->epg_channels_vbox = epg_channels_vbox; - - /* - * programs vbox - */ - GtkWidget *epg_programs_vbox = gtk_vbox_new(FALSE, 3); - private->epg_programs_vbox = epg_programs_vbox; - - /* - * packing start - */ - gtk_box_pack_start(GTK_BOX(epg_main_hbox), - epg_channels_vbox, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(epg_main_hbox), - epg_programs_vbox, FALSE, FALSE, 0); - - /* - * table header (first line) - */ - mmyth_epg_grid_widget_mount_header(mmyth_epg_grid_widget); - - /* - * service programs - */ - /* - * mount service programs with current time - */ - mmyth_epg_grid_widget_mount_services(mmyth_epg_grid_widget, - private->current_start_time, - private->current_end_time); -} - -GtkWidget * -mmyth_epg_grid_widget_new() -{ - return GTK_WIDGET(gtk_type_new(mmyth_epg_grid_widget_get_type())); -} - -static void -mmyth_epg_grid_widget_mount_services(MMythEpgGridWidget * - mmyth_epg_grid_widget, - GTimeVal * start_time, - GTimeVal * end_time) -{ - GList *proglist; - GList *channel_list = NULL; - GMythChannelInfo *channel_info; - - int chanid; - MMythEpgGridWidgetPrivate *private = - MMYTH_EPG_GRID_WIDGET_GET_PRIVATE(mmyth_epg_grid_widget); - - // update view_model - /* - * FIXME shallow free or recursive? - */ - if (mmyth_epg_grid_widget->epg_view_model != NULL) { - g_list_free(mmyth_epg_grid_widget->epg_view_model); - mmyth_epg_grid_widget->epg_view_model = NULL; - } - - if (private->service_model_hash != NULL) { - g_hash_table_destroy(private->service_model_hash); - } - - private->service_model_hash = g_hash_table_new(NULL, NULL); - - /* - * fill program infos from db - */ - mmyth_epg_grid_widget_fill_programinfos(private); - - channel_list = private->channel_list; - - /* - * for each channel get_programs() - */ - for (chanid = 0; channel_list && - chanid < private->DISPLAY_CHANS; chanid++) { - proglist = (GList *) private->program_list[chanid]; - - channel_info = (GMythChannelInfo *) channel_list->data; - channel_list = g_list_next(channel_list); - - /* - * Service Title - */ - GString *name = NULL; - if (channel_info->channel_name) - name = g_string_new(channel_info->channel_name->str); - - GdkColor title_bg_color; - title_bg_color.red = 5000; - title_bg_color.green = 9000; - title_bg_color.blue = 40000; - - GdkColor title_fg_color; - title_fg_color.red = 60000; - title_fg_color.green = 60000; - title_fg_color.blue = 60000; - - GtkWidget *event_box_channel = - create_event_box_lbl(name->str, 90, - &title_bg_color, - &title_fg_color); - - gtk_box_pack_start(GTK_BOX(private->epg_channels_vbox), - event_box_channel, FALSE, FALSE, 0); - - GtkWidget *epg_line_hbox = gtk_hbox_new(FALSE, 0); - - GdkColor bg_color; - bg_color.red = 5000; - bg_color.green = 30000; - bg_color.blue = 60000; - - GdkColor fg_color; - fg_color.red = 60000; - fg_color.green = 60000; - fg_color.blue = 60000; - - /* - * Content parsing - */ - GList *epg_grid_list = NULL; - - GMythProgramInfo *proginfo; - int pixel_count = 0; - for (; proglist; proglist = proglist->next) { - proginfo = (GMythProgramInfo *) proglist->data; - - GString *content_name = proginfo->title; - - GTimeVal *initial_time = g_new0(GTimeVal, 1); - GTimeVal *last_time = g_new0(GTimeVal, 1); - GTimeVal *duration = g_new0(GTimeVal, 1); - - GTimeVal *schedule_start_time = proginfo->startts; - GTimeVal *schedule_end_time = proginfo->endts; - - initial_time->tv_sec = - (schedule_start_time->tv_sec < - start_time->tv_sec) ? start_time-> - tv_sec : schedule_start_time->tv_sec; - last_time->tv_sec = - (schedule_end_time->tv_sec > - end_time->tv_sec) ? end_time->tv_sec : schedule_end_time-> - tv_sec; - duration->tv_sec = last_time->tv_sec - initial_time->tv_sec; - - // Verify program time -#if 0 - g_debug("ServiceID: %d, ScheduleID: %d\n", service->id, - schedule->id); - fprintf(stderr, "program time\nfrom = %d, to = %d\n", - schedule->validFrom, schedule->validTo); - - struct tm loctime; - - /* - * Convert it to local time representation. - */ - if (localtime_r((time_t *) & schedule->validFrom, &loctime) == - NULL) { - g_warning("localtime_r error in mmyth_epg_grid_widget!\n"); - return NULL; - } - fprintf(stderr, asctime(&loctime)); - - if (localtime_r((time_t *) & schedule->validTo, &loctime) == - NULL) { - g_warning("localtime_r error in mmyth_epg_grid_widget!\n"); - return NULL; - } - fprintf(stderr, asctime(&loctime)); -#endif - - /* - * fprintf(stderr, "duration = %d\n", duration); - */ - double duration_hour = - duration->tv_sec / (double) 3600.0; - /* - * fprintf(stderr, "duration_hour = %lf\n", duration_hour); - */ - - int size = PIXELS_HOUR * duration_hour; - - /* - * complete hour - */ - /* - * FIXME: UGLY WRONG HACK TO ALIGN PROGRAM TIME!!! - */ - if (last_time->tv_sec % 3600 != 0) { - size -= PROGRAM_SEPARATION; - } - if (initial_time->tv_sec % 3600 != 0) { - size -= PROGRAM_SEPARATION; - } - - pixel_count += size + PROGRAM_SEPARATION; - GtkWidget *event_box = - create_event_box_lbl(content_name->str, - size, &bg_color, - &fg_color); - gtk_widget_add_events(event_box, - GDK_BUTTON_PRESS_MASK | - GDK_BUTTON_RELEASE_MASK); - - /* - * create EpgGridItem - */ - EpgGridItem *epg_grid_item = g_new0(EpgGridItem, 1); - epg_grid_item->proginfo = proginfo; - epg_grid_item->event_box = event_box; - epg_grid_item->object = mmyth_epg_grid_widget; - - epg_grid_list = - g_list_prepend(epg_grid_list, (gpointer) epg_grid_item); - - gtk_box_pack_start(GTK_BOX(epg_line_hbox), - event_box, FALSE, FALSE, - PROGRAM_SEPARATION); - - g_signal_connect(G_OBJECT(event_box), "button-press-event", - G_CALLBACK(mmyth_epg_grid_widget_clicked), - (gpointer *) epg_grid_list); - } -#if 0 - printf("chaind = %d!!!!" chanid); - fflush(stdout); -#endif - - if (!epg_grid_list) { - /* - * No programs for current channel - */ - /* - * FIXME: size HARDCODED - */ - GtkWidget *event_box = - create_event_box_lbl("No program list available", - PIXELS_HOUR * 3, &bg_color, - &fg_color); - gtk_widget_add_events(event_box, - GDK_BUTTON_PRESS_MASK | - GDK_BUTTON_RELEASE_MASK); - - /* - * create EpgGridItem - */ - EpgGridItem *epg_grid_item = g_new0(EpgGridItem, 1); - epg_grid_item->proginfo = NULL; - epg_grid_item->event_box = event_box; - epg_grid_item->object = mmyth_epg_grid_widget; - - epg_grid_list = - g_list_prepend(epg_grid_list, (gpointer) epg_grid_item); - - gtk_box_pack_start(GTK_BOX(epg_line_hbox), - event_box, FALSE, FALSE, - PROGRAM_SEPARATION); - - g_signal_connect(G_OBJECT(event_box), "button-press-event", - G_CALLBACK(mmyth_epg_grid_widget_clicked), - (gpointer *) epg_grid_list); - } - - epg_grid_list = g_list_reverse(epg_grid_list); - mmyth_epg_grid_widget->epg_view_model = - g_list_append(mmyth_epg_grid_widget->epg_view_model, - epg_grid_list); - - gtk_box_pack_start(GTK_BOX(private->epg_programs_vbox), - epg_line_hbox, FALSE, FALSE, 0); - } -} - -static void -mmyth_epg_grid_widget_mount_header(MMythEpgGridWidget * - mmyth_epg_grid_widget) -{ - MMythEpgGridWidgetPrivate *private = - MMYTH_EPG_GRID_WIDGET_GET_PRIVATE(mmyth_epg_grid_widget); - - struct tm hour_tm; - const gchar name_title[] = "Today"; - GtkWidget *lbl_title = gtk_label_new(name_title); - - gtk_misc_set_alignment(GTK_MISC(lbl_title), 0.0, 0.5); - - gtk_box_pack_start(GTK_BOX(private->epg_channels_vbox), - lbl_title, FALSE, FALSE, 0); - - /* - * hours title line - */ - GtkWidget *epg_programs_hours_hbox = gtk_hbox_new(TRUE, 0); - - if (localtime_r - ((time_t *) & private->current_start_time->tv_sec, - &hour_tm) == NULL) { - g_warning("localtime_r error in mmyth_epg_grid_widget!\n"); - return; - } - - if (hour_tm.tm_min > 30) { - hour_tm.tm_min = 30; - } else if (hour_tm.tm_min > 0) { - hour_tm.tm_min = 0; - } - - gchar hour1_str[10]; - strftime(hour1_str, 8, "%H:%M", &hour_tm); - GtkWidget *lbl_hour1 = gtk_label_new(hour1_str); - gtk_misc_set_alignment(GTK_MISC(lbl_hour1), 0.0, 0.5); - - hour_tm.tm_hour++; - gchar hour2_str[10]; - strftime(hour2_str, 8, "%H:%M", &hour_tm); - GtkWidget *lbl_hour2 = gtk_label_new(hour2_str); - gtk_misc_set_alignment(GTK_MISC(lbl_hour2), 0.0, 0.5); - - hour_tm.tm_hour++; - gchar hour3_str[10]; - strftime(hour3_str, 8, "%H:%M", &hour_tm); - GtkWidget *lbl_hour3 = gtk_label_new(hour3_str); - gtk_misc_set_alignment(GTK_MISC(lbl_hour3), 0.0, 0.5); - - gtk_box_pack_start(GTK_BOX(epg_programs_hours_hbox), - lbl_hour1, TRUE, TRUE, 0); - gtk_box_pack_start(GTK_BOX(epg_programs_hours_hbox), - lbl_hour2, TRUE, TRUE, 0); - gtk_box_pack_start(GTK_BOX(epg_programs_hours_hbox), - lbl_hour3, TRUE, TRUE, 0); - - gtk_box_pack_start(GTK_BOX(private->epg_programs_vbox), - epg_programs_hours_hbox, FALSE, FALSE, 0); -} - -/****************************************************************************** - * INTERNAL CALLBACKS FOR STATE CHANGE * - *****************************************************************************/ -static void -mmyth_epg_grid_widget_deselect_service(MMythEpgGridWidget * - mmyth_epg_grid_widget) -{ - EpgGridItem *epg_grid_item; - - /* - * deselect - */ - if (mmyth_epg_grid_widget->selected_grid_item != NULL) { - epg_grid_item = - (EpgGridItem *) mmyth_epg_grid_widget->selected_grid_item-> - data; - gtk_widget_set_state(GTK_WIDGET(epg_grid_item->event_box), - GTK_STATE_NORMAL); - } -} - -static void -mmyth_epg_grid_widget_clicked(GtkWidget * widget, - GdkEventExpose * event, gpointer data) -{ - g_return_if_fail(data != NULL); - - GList *epg_grid_item_list = (GList *) data; - EpgGridItem *epg_grid_item = - (EpgGridItem *) epg_grid_item_list->data; - - /* - * update the selected service - */ - mmyth_epg_grid_widget_update_service(epg_grid_item->object, - (GList *) data); -} - -void -mmyth_epg_grid_widget_update_service(MMythEpgGridWidget * object, - GList * selected_grid_list) -{ - g_return_if_fail(object != NULL); - g_return_if_fail(selected_grid_list != NULL); - - EpgGridItem *epg_grid_item = - (EpgGridItem *) selected_grid_list->data; - - mmyth_epg_grid_widget_deselect_service(epg_grid_item->object); - - /* - * updating current selected schedule_item and schedule_list - */ - object->selected_grid_item = selected_grid_list; - - /* - * set state of the event box - */ - gtk_widget_set_state(GTK_WIDGET(epg_grid_item->event_box), - GTK_STATE_SELECTED); - /* - * emit update signal for listeners - */ - g_signal_emit(object, - mmyth_epg_grid_widget_signals[SELECTION_UPDATED_SIGNAL], - 0, (gpointer) epg_grid_item); -} - -static GtkWidget * -create_event_box_lbl(gchar * str, int width, const GdkColor * bg_color, - const GdkColor * fg_color) -{ - GtkWidget *event_box = gtk_event_box_new(); - GtkWidget *lbl = gtk_label_new(str); - gtk_label_set_ellipsize(GTK_LABEL(lbl), PANGO_ELLIPSIZE_END); - - gtk_widget_modify_bg(event_box, GTK_STATE_NORMAL, bg_color); - gtk_widget_modify_fg(lbl, GTK_STATE_NORMAL, fg_color); - - /* - * selected colors are const - */ - GdkColor selected_bg_color; - selected_bg_color.red = 100; - selected_bg_color.green = 40000; - selected_bg_color.blue = 100; - - GdkColor selected_fg_color; - selected_fg_color.red = 100; - selected_fg_color.green = 100; - selected_fg_color.blue = 100; - - gtk_widget_modify_bg(event_box, GTK_STATE_SELECTED, - &selected_bg_color); - gtk_widget_modify_fg(lbl, GTK_STATE_SELECTED, &selected_fg_color); - - gtk_misc_set_alignment(GTK_MISC(lbl), 0.0, 0.5); - gtk_container_add(GTK_CONTAINER(event_box), lbl); - gtk_widget_set_size_request(event_box, width, -1); - - return event_box; -} - -/****************************************************************************** - * METHODS * - *****************************************************************************/ - -/* - * Callback for hardware keys - */ -gboolean -mmyth_epg_grid_widget_key_press(MMythEpgGridWidget * object, - GtkWidget * widget, GdkEventKey * event) -{ - MMythEpgGridWidgetPrivate *private = - MMYTH_EPG_GRID_WIDGET_GET_PRIVATE(object); - - EpgGridItem *epg_grid_item; - GList *tmp; - - /* - * List of selected_grid_item - */ - GList *selected_view_model; - - gint channel_index; - - if (object->selected_grid_item == NULL) { - g_warning("No program selected"); - return FALSE; - } - - epg_grid_item = (EpgGridItem *) object->selected_grid_item->data; - - channel_index = private->selected_channel_index; - - switch (event->keyval) { - case GDK_Up: - selected_view_model = - g_list_nth(object->epg_view_model, channel_index - 1); - if (selected_view_model != NULL) { - private->selected_channel_index = channel_index - 1; - tmp = (GList *) selected_view_model->data; - /* - * TODO: select a better centralized item currently is - * picking the 1st or last item - */ - if (g_list_next(object->selected_grid_item) == NULL && - g_list_previous(object->selected_grid_item) != NULL) { - /* - * in this case the new selected will be the last - */ - tmp = g_list_last(tmp); - } - - /* - * update the selected service - */ - mmyth_epg_grid_widget_update_service(object, tmp); - } - return TRUE; - case GDK_Down: - selected_view_model = - g_list_nth(object->epg_view_model, channel_index + 1); - if (selected_view_model != NULL) { - private->selected_channel_index = channel_index + 1; - tmp = (GList *) selected_view_model->data; - /* - * TODO: select a better centralized item currently is - * picking the 1st or last item - */ - if (g_list_next(object->selected_grid_item) == NULL && - g_list_previous(object->selected_grid_item) != NULL) { - /* - * in this case the new selected will be the last - */ - tmp = g_list_last(tmp); - } - - /* - * update the selected service - */ - mmyth_epg_grid_widget_update_service(object, tmp); - } - return TRUE; - case GDK_Left: - tmp = g_list_previous(object->selected_grid_item); - if (tmp != NULL) { - /* - * update the selected service - */ - mmyth_epg_grid_widget_update_service(object, tmp); - } - return TRUE; - case GDK_Right: - tmp = g_list_next(object->selected_grid_item); - if (tmp != NULL) { - /* - * update the selected service - */ - mmyth_epg_grid_widget_update_service(object, tmp); - } - return TRUE; - default: - return TRUE; - } - - return FALSE; -} - -static void -mmyth_epg_grid_widget_fill_programinfos(MMythEpgGridWidgetPrivate * - private) -{ - GList *channels_list = NULL; - int y; - - if ((private->mmyth_epg != NULL) && - (gmyth_epg_get_channel_list(private->mmyth_epg, &channels_list) < - 0)) { - private->channel_list = NULL; - return; - } - - private->channel_list = channels_list; - - for (y = 0; y < private->DISPLAY_CHANS && channels_list; y++) { - GMythChannelInfo *channel_info = - (GMythChannelInfo *) channels_list->data; - - mmyth_epg_grid_widget_fill_program_row_infos(private, - channel_info-> - channel_ID, y); - - channels_list = g_list_next(channels_list); - } -} - -static void -mmyth_epg_grid_widget_fill_program_row_infos(MMythEpgGridWidgetPrivate * - private, guint chanNum, - guint row) -{ - gint res = gmyth_epg_get_program_list(private->mmyth_epg, - &(private-> - program_list[row]), - chanNum, - private-> - current_start_time, - private-> - current_end_time); - - if (res < 0) { - g_warning("[%s] Error while retrieving epg programs", - __FUNCTION__); - } -}