maemo-ui-old/src/mmyth_epg_grid_widget.c
author renatofilho
Tue Jan 29 18:40:32 2008 +0000 (2008-01-29)
branchtrunk
changeset 896 9f80dd75cd8a
parent 754 cb885ee44618
permissions -rw-r--r--
[svn r902] fixed var names
     1 #include <gtk/gtksignal.h>
     2 #include <gdk/gdkevents.h>
     3 #include <gdk/gdkkeysyms.h>
     4 
     5 #include "mmyth_uicommon.h"
     6 #include "mmyth_epg_grid_widget.h"
     7 
     8 #include <gmyth/gmyth_util.h>
     9 #include <gmyth/gmyth_epg.h>
    10 
    11 #define PIXELS_HOUR 105
    12 #define PROGRAM_SEPARATION 2
    13 
    14 enum {
    15     SELECTION_UPDATED_SIGNAL,
    16     LAST_SIGNAL
    17 };
    18 
    19 struct _MMythEpgGridWidgetPrivate {
    20     /*
    21      * private widget components 
    22      */
    23     GtkWidget      *epg_channels_vbox;
    24     GtkWidget      *epg_programs_vbox;
    25 
    26     GHashTable     *service_model_hash;
    27 
    28     /*
    29      * guidegrid attributes 
    30      */
    31     gboolean        show_favorites;
    32     gint            current_start_channel_id;
    33 
    34     GTimeVal       *current_start_time;
    35     GTimeVal       *current_end_time;
    36 
    37     guint           selected_channel_index;
    38 
    39     /*
    40      * GList of ProgramInfo for each Channel 
    41      */
    42     GList          *program_list[MAX_DISPLAY_CHANS];
    43     GList          *channel_list;
    44 
    45     GMythEPG       *mmyth_epg;
    46 
    47     GMythBackendInfo *backend_info;
    48 
    49     gint            DISPLAY_CHANS;
    50 };
    51 
    52 static void     mmyth_epg_grid_widget_class_init(MMythEpgGridWidgetClass *
    53                                                  klass);
    54 static void     mmyth_epg_grid_widget_init(MMythEpgGridWidget * object);
    55 static void    
    56 mmyth_epg_grid_widget_private_init(MMythEpgGridWidgetPrivate * private);
    57 static void     mmyth_epg_grid_widget_mount_services(MMythEpgGridWidget *
    58                                                      object,
    59                                                      GTimeVal * start_time,
    60                                                      GTimeVal * end_time);
    61 static void     mmyth_epg_grid_widget_mount_header(MMythEpgGridWidget *
    62                                                    object);
    63 static void     mmyth_epg_grid_widget_clicked(GtkWidget * widget,
    64                                               GdkEventExpose * event,
    65                                               gpointer data);
    66 static GtkWidget *create_event_box_lbl(gchar * str, int width,
    67                                        const GdkColor * bg_color,
    68                                        const GdkColor * fg_color);
    69 
    70 static void    
    71 mmyth_epg_grid_widget_fill_programinfos(MMythEpgGridWidgetPrivate *
    72                                         private);
    73 static void    
    74 mmyth_epg_grid_widget_fill_program_row_infos(MMythEpgGridWidgetPrivate *
    75                                              private, unsigned int chanNum,
    76                                              unsigned int row);
    77 
    78 static gint     mmyth_epg_grid_widget_signals[LAST_SIGNAL] = { 0 };
    79 
    80 G_DEFINE_TYPE(MMythEpgGridWidget, mmyth_epg_grid_widget,
    81               GTK_TYPE_EVENT_BOX)
    82 
    83     static void
    84      
    85         
    86         
    87         
    88         
    89         
    90         
    91         
    92         
    93         
    94         
    95         
    96         
    97           mmyth_epg_grid_widget_class_init(MMythEpgGridWidgetClass * klass)
    98 {
    99     g_type_class_add_private(klass, sizeof(MMythEpgGridWidgetPrivate));
   100 
   101     mmyth_epg_grid_widget_signals[SELECTION_UPDATED_SIGNAL] =
   102         g_signal_new("selection_updated", G_TYPE_FROM_CLASS(klass),
   103                      G_SIGNAL_RUN_FIRST, 0, NULL, NULL,
   104                      g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1,
   105                      G_TYPE_POINTER);
   106 }
   107 
   108 static void
   109 mmyth_epg_grid_widget_private_init(MMythEpgGridWidgetPrivate * private)
   110 {
   111     time_t          cur_time;
   112 
   113     g_return_if_fail(private != NULL);
   114 
   115     private->epg_channels_vbox = NULL;
   116     private->epg_programs_vbox = NULL;
   117     private->service_model_hash = NULL;
   118 
   119     private->show_favorites = FALSE;
   120     private->current_start_channel_id = -1;
   121 
   122     /*
   123      * Selected the first diplayable channel initially 
   124      */
   125     private->selected_channel_index = 0;
   126 
   127     /*
   128      * TODO fix the current start/end time 
   129      */
   130     private->current_start_time = g_new0(GTimeVal, 1);
   131     private->current_start_time->tv_sec = time(&cur_time);
   132 
   133     private->current_end_time = g_new0(GTimeVal, 1);
   134     private->current_end_time->tv_sec = time(&cur_time) + 10800;
   135 
   136     private->DISPLAY_CHANS = MAX_DISPLAY_CHANS;
   137 
   138     private->backend_info =
   139         gmyth_backend_info_new_full("localhost", "mythtv", "mythtv",
   140                                     "mythconverg", 6543);
   141 
   142     // TODO: Close the epg and unref it in dispose call
   143     private->mmyth_epg = gmyth_epg_new();
   144     if (!gmyth_epg_connect(private->mmyth_epg, private->backend_info)) {
   145         g_warning("[%s] Could not connect mysql handler to db",
   146                   __FUNCTION__);
   147         g_object_unref(private->mmyth_epg);
   148         private->mmyth_epg = NULL;
   149     }
   150 }
   151 
   152 static void
   153 mmyth_epg_grid_widget_init(MMythEpgGridWidget * mmyth_epg_grid_widget)
   154 {
   155     MMythEpgGridWidgetPrivate *private =
   156         MMYTH_EPG_GRID_WIDGET_GET_PRIVATE(mmyth_epg_grid_widget);
   157 
   158     /*
   159      * init private fields 
   160      */
   161     mmyth_epg_grid_widget_private_init(private);
   162 
   163     mmyth_epg_grid_widget->epg_view_model = NULL;
   164     mmyth_epg_grid_widget->selected_grid_item = NULL;
   165 
   166     GtkWidget      *epg_event_box = GTK_WIDGET(mmyth_epg_grid_widget);
   167     gtk_widget_modify_bg(epg_event_box, GTK_STATE_NORMAL, &main_bg_color);
   168     gtk_widget_set_size_request(epg_event_box, 0, 125);
   169 
   170     GtkWidget      *epg_main_hbox = gtk_hbox_new(FALSE, 10);
   171     gtk_container_set_border_width(GTK_CONTAINER(epg_main_hbox), 10);
   172 
   173     gtk_container_add(GTK_CONTAINER(epg_event_box), epg_main_hbox);
   174 
   175     /*
   176      * channels vbox 
   177      */
   178     GtkWidget      *epg_channels_vbox = gtk_vbox_new(FALSE, 3);
   179     private->epg_channels_vbox = epg_channels_vbox;
   180 
   181     /*
   182      * programs vbox 
   183      */
   184     GtkWidget      *epg_programs_vbox = gtk_vbox_new(FALSE, 3);
   185     private->epg_programs_vbox = epg_programs_vbox;
   186 
   187     /*
   188      * packing start 
   189      */
   190     gtk_box_pack_start(GTK_BOX(epg_main_hbox),
   191                        epg_channels_vbox, FALSE, FALSE, 0);
   192     gtk_box_pack_start(GTK_BOX(epg_main_hbox),
   193                        epg_programs_vbox, FALSE, FALSE, 0);
   194 
   195     /*
   196      * table header (first line) 
   197      */
   198     mmyth_epg_grid_widget_mount_header(mmyth_epg_grid_widget);
   199 
   200     /*
   201      * service programs 
   202      */
   203     /*
   204      * mount service programs with current time 
   205      */
   206     mmyth_epg_grid_widget_mount_services(mmyth_epg_grid_widget,
   207                                          private->current_start_time,
   208                                          private->current_end_time);
   209 }
   210 
   211 GtkWidget      *
   212 mmyth_epg_grid_widget_new()
   213 {
   214     return GTK_WIDGET(gtk_type_new(mmyth_epg_grid_widget_get_type()));
   215 }
   216 
   217 static void
   218 mmyth_epg_grid_widget_mount_services(MMythEpgGridWidget *
   219                                      mmyth_epg_grid_widget,
   220                                      GTimeVal * start_time,
   221                                      GTimeVal * end_time)
   222 {
   223     GList          *proglist;
   224     GList          *channel_list = NULL;
   225     GMythChannelInfo *channel_info;
   226 
   227     int             chanid;
   228     MMythEpgGridWidgetPrivate *private =
   229         MMYTH_EPG_GRID_WIDGET_GET_PRIVATE(mmyth_epg_grid_widget);
   230 
   231     // update view_model
   232     /*
   233      * FIXME shallow free or recursive? 
   234      */
   235     if (mmyth_epg_grid_widget->epg_view_model != NULL) {
   236         g_list_free(mmyth_epg_grid_widget->epg_view_model);
   237         mmyth_epg_grid_widget->epg_view_model = NULL;
   238     }
   239 
   240     if (private->service_model_hash != NULL) {
   241         g_hash_table_destroy(private->service_model_hash);
   242     }
   243 
   244     private->service_model_hash = g_hash_table_new(NULL, NULL);
   245 
   246     /*
   247      * fill program infos from db 
   248      */
   249     mmyth_epg_grid_widget_fill_programinfos(private);
   250 
   251     channel_list = private->channel_list;
   252 
   253     /*
   254      * for each channel get_programs() 
   255      */
   256     for (chanid = 0; channel_list &&
   257          chanid < private->DISPLAY_CHANS; chanid++) {
   258         proglist = (GList *) private->program_list[chanid];
   259 
   260         channel_info = (GMythChannelInfo *) channel_list->data;
   261         channel_list = g_list_next(channel_list);
   262 
   263         /*
   264          * Service Title
   265          */
   266         GString        *name = NULL;
   267         if (channel_info->channel_name)
   268             name = g_string_new(channel_info->channel_name->str);
   269 
   270         GdkColor        title_bg_color;
   271         title_bg_color.red = 5000;
   272         title_bg_color.green = 9000;
   273         title_bg_color.blue = 40000;
   274 
   275         GdkColor        title_fg_color;
   276         title_fg_color.red = 60000;
   277         title_fg_color.green = 60000;
   278         title_fg_color.blue = 60000;
   279 
   280         GtkWidget      *event_box_channel =
   281             create_event_box_lbl(name->str, 90,
   282                                  &title_bg_color,
   283                                  &title_fg_color);
   284 
   285         gtk_box_pack_start(GTK_BOX(private->epg_channels_vbox),
   286                            event_box_channel, FALSE, FALSE, 0);
   287 
   288         GtkWidget      *epg_line_hbox = gtk_hbox_new(FALSE, 0);
   289 
   290         GdkColor        bg_color;
   291         bg_color.red = 5000;
   292         bg_color.green = 30000;
   293         bg_color.blue = 60000;
   294 
   295         GdkColor        fg_color;
   296         fg_color.red = 60000;
   297         fg_color.green = 60000;
   298         fg_color.blue = 60000;
   299 
   300         /*
   301          * Content parsing 
   302          */
   303         GList          *epg_grid_list = NULL;
   304 
   305         GMythProgramInfo *proginfo;
   306         int             pixel_count = 0;
   307         for (; proglist; proglist = proglist->next) {
   308             proginfo = (GMythProgramInfo *) proglist->data;
   309 
   310             GString        *content_name = proginfo->title;
   311 
   312             GTimeVal       *initial_time = g_new0(GTimeVal, 1);
   313             GTimeVal       *last_time = g_new0(GTimeVal, 1);
   314             GTimeVal       *duration = g_new0(GTimeVal, 1);
   315 
   316             GTimeVal       *schedule_start_time = proginfo->startts;
   317             GTimeVal       *schedule_end_time = proginfo->endts;
   318 
   319             initial_time->tv_sec =
   320                 (schedule_start_time->tv_sec <
   321                  start_time->tv_sec) ? start_time->
   322                 tv_sec : schedule_start_time->tv_sec;
   323             last_time->tv_sec =
   324                 (schedule_end_time->tv_sec >
   325                  end_time->tv_sec) ? end_time->tv_sec : schedule_end_time->
   326                 tv_sec;
   327             duration->tv_sec = last_time->tv_sec - initial_time->tv_sec;
   328 
   329             // Verify program time 
   330 #if 0
   331             g_debug("ServiceID: %d, ScheduleID: %d\n", service->id,
   332                     schedule->id);
   333             fprintf(stderr, "program time\nfrom = %d, to = %d\n",
   334                     schedule->validFrom, schedule->validTo);
   335 
   336             struct tm       loctime;
   337 
   338             /*
   339              * Convert it to local time representation. 
   340              */
   341             if (localtime_r((time_t *) & schedule->validFrom, &loctime) ==
   342                 NULL) {
   343                 g_warning("localtime_r error in mmyth_epg_grid_widget!\n");
   344                 return NULL;
   345             }
   346             fprintf(stderr, asctime(&loctime));
   347 
   348             if (localtime_r((time_t *) & schedule->validTo, &loctime) ==
   349                 NULL) {
   350                 g_warning("localtime_r error in mmyth_epg_grid_widget!\n");
   351                 return NULL;
   352             }
   353             fprintf(stderr, asctime(&loctime));
   354 #endif
   355 
   356             /*
   357              * fprintf(stderr, "duration = %d\n", duration); 
   358              */
   359             double          duration_hour =
   360                 duration->tv_sec / (double) 3600.0;
   361             /*
   362              * fprintf(stderr, "duration_hour = %lf\n", duration_hour); 
   363              */
   364 
   365             int             size = PIXELS_HOUR * duration_hour;
   366 
   367             /*
   368              * complete hour 
   369              */
   370             /*
   371              * FIXME: UGLY WRONG HACK TO ALIGN PROGRAM TIME!!!
   372              */
   373             if (last_time->tv_sec % 3600 != 0) {
   374                 size -= PROGRAM_SEPARATION;
   375             }
   376             if (initial_time->tv_sec % 3600 != 0) {
   377                 size -= PROGRAM_SEPARATION;
   378             }
   379 
   380             pixel_count += size + PROGRAM_SEPARATION;
   381             GtkWidget      *event_box =
   382                 create_event_box_lbl(content_name->str,
   383                                      size, &bg_color,
   384                                      &fg_color);
   385             gtk_widget_add_events(event_box,
   386                                   GDK_BUTTON_PRESS_MASK |
   387                                   GDK_BUTTON_RELEASE_MASK);
   388 
   389             /*
   390              * create EpgGridItem 
   391              */
   392             EpgGridItem    *epg_grid_item = g_new0(EpgGridItem, 1);
   393             epg_grid_item->proginfo = proginfo;
   394             epg_grid_item->event_box = event_box;
   395             epg_grid_item->object = mmyth_epg_grid_widget;
   396 
   397             epg_grid_list =
   398                 g_list_prepend(epg_grid_list, (gpointer) epg_grid_item);
   399 
   400             gtk_box_pack_start(GTK_BOX(epg_line_hbox),
   401                                event_box, FALSE, FALSE,
   402                                PROGRAM_SEPARATION);
   403 
   404             g_signal_connect(G_OBJECT(event_box), "button-press-event",
   405                              G_CALLBACK(mmyth_epg_grid_widget_clicked),
   406                              (gpointer *) epg_grid_list);
   407         }
   408 #if 0
   409         printf("chaind = %d!!!!" chanid);
   410         fflush(stdout);
   411 #endif
   412 
   413         if (!epg_grid_list) {
   414             /*
   415              * No programs for current channel 
   416              */
   417             /*
   418              * FIXME: size HARDCODED 
   419              */
   420             GtkWidget      *event_box =
   421                 create_event_box_lbl("No program list available",
   422                                      PIXELS_HOUR * 3, &bg_color,
   423                                      &fg_color);
   424             gtk_widget_add_events(event_box,
   425                                   GDK_BUTTON_PRESS_MASK |
   426                                   GDK_BUTTON_RELEASE_MASK);
   427 
   428             /*
   429              * create EpgGridItem 
   430              */
   431             EpgGridItem    *epg_grid_item = g_new0(EpgGridItem, 1);
   432             epg_grid_item->proginfo = NULL;
   433             epg_grid_item->event_box = event_box;
   434             epg_grid_item->object = mmyth_epg_grid_widget;
   435 
   436             epg_grid_list =
   437                 g_list_prepend(epg_grid_list, (gpointer) epg_grid_item);
   438 
   439             gtk_box_pack_start(GTK_BOX(epg_line_hbox),
   440                                event_box, FALSE, FALSE,
   441                                PROGRAM_SEPARATION);
   442 
   443             g_signal_connect(G_OBJECT(event_box), "button-press-event",
   444                              G_CALLBACK(mmyth_epg_grid_widget_clicked),
   445                              (gpointer *) epg_grid_list);
   446         }
   447 
   448         epg_grid_list = g_list_reverse(epg_grid_list);
   449         mmyth_epg_grid_widget->epg_view_model =
   450             g_list_append(mmyth_epg_grid_widget->epg_view_model,
   451                           epg_grid_list);
   452 
   453         gtk_box_pack_start(GTK_BOX(private->epg_programs_vbox),
   454                            epg_line_hbox, FALSE, FALSE, 0);
   455     }
   456 }
   457 
   458 static void
   459 mmyth_epg_grid_widget_mount_header(MMythEpgGridWidget *
   460                                    mmyth_epg_grid_widget)
   461 {
   462     MMythEpgGridWidgetPrivate *private =
   463         MMYTH_EPG_GRID_WIDGET_GET_PRIVATE(mmyth_epg_grid_widget);
   464 
   465     struct tm       hour_tm;
   466     const gchar     name_title[] = "Today";
   467     GtkWidget      *lbl_title = gtk_label_new(name_title);
   468 
   469     gtk_misc_set_alignment(GTK_MISC(lbl_title), 0.0, 0.5);
   470 
   471     gtk_box_pack_start(GTK_BOX(private->epg_channels_vbox),
   472                        lbl_title, FALSE, FALSE, 0);
   473 
   474     /*
   475      * hours title line 
   476      */
   477     GtkWidget      *epg_programs_hours_hbox = gtk_hbox_new(TRUE, 0);
   478 
   479     if (localtime_r
   480         ((time_t *) & private->current_start_time->tv_sec,
   481          &hour_tm) == NULL) {
   482         g_warning("localtime_r error in mmyth_epg_grid_widget!\n");
   483         return;
   484     }
   485 
   486     if (hour_tm.tm_min > 30) {
   487         hour_tm.tm_min = 30;
   488     } else if (hour_tm.tm_min > 0) {
   489         hour_tm.tm_min = 0;
   490     }
   491 
   492     gchar           hour1_str[10];
   493     strftime(hour1_str, 8, "%H:%M", &hour_tm);
   494     GtkWidget      *lbl_hour1 = gtk_label_new(hour1_str);
   495     gtk_misc_set_alignment(GTK_MISC(lbl_hour1), 0.0, 0.5);
   496 
   497     hour_tm.tm_hour++;
   498     gchar           hour2_str[10];
   499     strftime(hour2_str, 8, "%H:%M", &hour_tm);
   500     GtkWidget      *lbl_hour2 = gtk_label_new(hour2_str);
   501     gtk_misc_set_alignment(GTK_MISC(lbl_hour2), 0.0, 0.5);
   502 
   503     hour_tm.tm_hour++;
   504     gchar           hour3_str[10];
   505     strftime(hour3_str, 8, "%H:%M", &hour_tm);
   506     GtkWidget      *lbl_hour3 = gtk_label_new(hour3_str);
   507     gtk_misc_set_alignment(GTK_MISC(lbl_hour3), 0.0, 0.5);
   508 
   509     gtk_box_pack_start(GTK_BOX(epg_programs_hours_hbox),
   510                        lbl_hour1, TRUE, TRUE, 0);
   511     gtk_box_pack_start(GTK_BOX(epg_programs_hours_hbox),
   512                        lbl_hour2, TRUE, TRUE, 0);
   513     gtk_box_pack_start(GTK_BOX(epg_programs_hours_hbox),
   514                        lbl_hour3, TRUE, TRUE, 0);
   515 
   516     gtk_box_pack_start(GTK_BOX(private->epg_programs_vbox),
   517                        epg_programs_hours_hbox, FALSE, FALSE, 0);
   518 }
   519 
   520 /******************************************************************************
   521  *              INTERNAL CALLBACKS FOR STATE CHANGE                           *
   522  *****************************************************************************/
   523 static void
   524 mmyth_epg_grid_widget_deselect_service(MMythEpgGridWidget *
   525                                        mmyth_epg_grid_widget)
   526 {
   527     EpgGridItem    *epg_grid_item;
   528 
   529     /*
   530      * deselect
   531      */
   532     if (mmyth_epg_grid_widget->selected_grid_item != NULL) {
   533         epg_grid_item =
   534             (EpgGridItem *) mmyth_epg_grid_widget->selected_grid_item->
   535             data;
   536         gtk_widget_set_state(GTK_WIDGET(epg_grid_item->event_box),
   537                              GTK_STATE_NORMAL);
   538     }
   539 }
   540 
   541 static void
   542 mmyth_epg_grid_widget_clicked(GtkWidget * widget,
   543                               GdkEventExpose * event, gpointer data)
   544 {
   545     g_return_if_fail(data != NULL);
   546 
   547     GList          *epg_grid_item_list = (GList *) data;
   548     EpgGridItem    *epg_grid_item =
   549         (EpgGridItem *) epg_grid_item_list->data;
   550 
   551     /*
   552      * update the selected service 
   553      */
   554     mmyth_epg_grid_widget_update_service(epg_grid_item->object,
   555                                          (GList *) data);
   556 }
   557 
   558 void
   559 mmyth_epg_grid_widget_update_service(MMythEpgGridWidget * object,
   560                                      GList * selected_grid_list)
   561 {
   562     g_return_if_fail(object != NULL);
   563     g_return_if_fail(selected_grid_list != NULL);
   564 
   565     EpgGridItem    *epg_grid_item =
   566         (EpgGridItem *) selected_grid_list->data;
   567 
   568     mmyth_epg_grid_widget_deselect_service(epg_grid_item->object);
   569 
   570     /*
   571      * updating current selected schedule_item and schedule_list
   572      */
   573     object->selected_grid_item = selected_grid_list;
   574 
   575     /*
   576      * set state of the event box 
   577      */
   578     gtk_widget_set_state(GTK_WIDGET(epg_grid_item->event_box),
   579                          GTK_STATE_SELECTED);
   580     /*
   581      * emit update signal for listeners 
   582      */
   583     g_signal_emit(object,
   584                   mmyth_epg_grid_widget_signals[SELECTION_UPDATED_SIGNAL],
   585                   0, (gpointer) epg_grid_item);
   586 }
   587 
   588 static GtkWidget *
   589 create_event_box_lbl(gchar * str, int width, const GdkColor * bg_color,
   590                      const GdkColor * fg_color)
   591 {
   592     GtkWidget      *event_box = gtk_event_box_new();
   593     GtkWidget      *lbl = gtk_label_new(str);
   594     gtk_label_set_ellipsize(GTK_LABEL(lbl), PANGO_ELLIPSIZE_END);
   595 
   596     gtk_widget_modify_bg(event_box, GTK_STATE_NORMAL, bg_color);
   597     gtk_widget_modify_fg(lbl, GTK_STATE_NORMAL, fg_color);
   598 
   599     /*
   600      * selected colors are const
   601      */
   602     GdkColor        selected_bg_color;
   603     selected_bg_color.red = 100;
   604     selected_bg_color.green = 40000;
   605     selected_bg_color.blue = 100;
   606 
   607     GdkColor        selected_fg_color;
   608     selected_fg_color.red = 100;
   609     selected_fg_color.green = 100;
   610     selected_fg_color.blue = 100;
   611 
   612     gtk_widget_modify_bg(event_box, GTK_STATE_SELECTED,
   613                          &selected_bg_color);
   614     gtk_widget_modify_fg(lbl, GTK_STATE_SELECTED, &selected_fg_color);
   615 
   616     gtk_misc_set_alignment(GTK_MISC(lbl), 0.0, 0.5);
   617     gtk_container_add(GTK_CONTAINER(event_box), lbl);
   618     gtk_widget_set_size_request(event_box, width, -1);
   619 
   620     return event_box;
   621 }
   622 
   623 /******************************************************************************
   624  *                            METHODS                                         *
   625  *****************************************************************************/
   626 
   627 /*
   628  * Callback for hardware keys 
   629  */
   630 gboolean
   631 mmyth_epg_grid_widget_key_press(MMythEpgGridWidget * object,
   632                                 GtkWidget * widget, GdkEventKey * event)
   633 {
   634     MMythEpgGridWidgetPrivate *private =
   635         MMYTH_EPG_GRID_WIDGET_GET_PRIVATE(object);
   636 
   637     EpgGridItem    *epg_grid_item;
   638     GList          *tmp;
   639 
   640     /*
   641      * List of selected_grid_item 
   642      */
   643     GList          *selected_view_model;
   644 
   645     gint            channel_index;
   646 
   647     if (object->selected_grid_item == NULL) {
   648         g_warning("No program selected");
   649         return FALSE;
   650     }
   651 
   652     epg_grid_item = (EpgGridItem *) object->selected_grid_item->data;
   653 
   654     channel_index = private->selected_channel_index;
   655 
   656     switch (event->keyval) {
   657     case GDK_Up:
   658         selected_view_model =
   659             g_list_nth(object->epg_view_model, channel_index - 1);
   660         if (selected_view_model != NULL) {
   661             private->selected_channel_index = channel_index - 1;
   662             tmp = (GList *) selected_view_model->data;
   663             /*
   664              * TODO: select a better centralized item currently is
   665              * picking the 1st or last item 
   666              */
   667             if (g_list_next(object->selected_grid_item) == NULL &&
   668                 g_list_previous(object->selected_grid_item) != NULL) {
   669                 /*
   670                  * in this case the new selected will be the last 
   671                  */
   672                 tmp = g_list_last(tmp);
   673             }
   674 
   675             /*
   676              * update the selected service 
   677              */
   678             mmyth_epg_grid_widget_update_service(object, tmp);
   679         }
   680         return TRUE;
   681     case GDK_Down:
   682         selected_view_model =
   683             g_list_nth(object->epg_view_model, channel_index + 1);
   684         if (selected_view_model != NULL) {
   685             private->selected_channel_index = channel_index + 1;
   686             tmp = (GList *) selected_view_model->data;
   687             /*
   688              * TODO: select a better centralized item currently is
   689              * picking the 1st or last item 
   690              */
   691             if (g_list_next(object->selected_grid_item) == NULL &&
   692                 g_list_previous(object->selected_grid_item) != NULL) {
   693                 /*
   694                  * in this case the new selected will be the last 
   695                  */
   696                 tmp = g_list_last(tmp);
   697             }
   698 
   699             /*
   700              * update the selected service 
   701              */
   702             mmyth_epg_grid_widget_update_service(object, tmp);
   703         }
   704         return TRUE;
   705     case GDK_Left:
   706         tmp = g_list_previous(object->selected_grid_item);
   707         if (tmp != NULL) {
   708             /*
   709              * update the selected service 
   710              */
   711             mmyth_epg_grid_widget_update_service(object, tmp);
   712         }
   713         return TRUE;
   714     case GDK_Right:
   715         tmp = g_list_next(object->selected_grid_item);
   716         if (tmp != NULL) {
   717             /*
   718              * update the selected service 
   719              */
   720             mmyth_epg_grid_widget_update_service(object, tmp);
   721         }
   722         return TRUE;
   723     default:
   724         return TRUE;
   725     }
   726 
   727     return FALSE;
   728 }
   729 
   730 static void
   731 mmyth_epg_grid_widget_fill_programinfos(MMythEpgGridWidgetPrivate *
   732                                         private)
   733 {
   734     GList          *channels_list = NULL;
   735     int             y;
   736 
   737     if ((private->mmyth_epg != NULL) &&
   738         (gmyth_epg_get_channel_list(private->mmyth_epg, &channels_list) <
   739          0)) {
   740         private->channel_list = NULL;
   741         return;
   742     }
   743 
   744     private->channel_list = channels_list;
   745 
   746     for (y = 0; y < private->DISPLAY_CHANS && channels_list; y++) {
   747         GMythChannelInfo *channel_info =
   748             (GMythChannelInfo *) channels_list->data;
   749 
   750         mmyth_epg_grid_widget_fill_program_row_infos(private,
   751                                                      channel_info->
   752                                                      channel_ID, y);
   753 
   754         channels_list = g_list_next(channels_list);
   755     }
   756 }
   757 
   758 static void
   759 mmyth_epg_grid_widget_fill_program_row_infos(MMythEpgGridWidgetPrivate *
   760                                              private, guint chanNum,
   761                                              guint row)
   762 {
   763     gint            res = gmyth_epg_get_program_list(private->mmyth_epg,
   764                                                      &(private->
   765                                                        program_list[row]),
   766                                                      chanNum,
   767                                                      private->
   768                                                      current_start_time,
   769                                                      private->
   770                                                      current_end_time);
   771 
   772     if (res < 0) {
   773         g_warning("[%s] Error while retrieving epg programs",
   774                   __FUNCTION__);
   775     }
   776 }