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