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