* configure.ac: 0.12.0
[hildon] / hildon-widgets / hildon-appview.c
1 /*
2  * This file is part of hildon-libs
3  *
4  * Copyright (C) 2005 Nokia Corporation.
5  *
6  * Contact: Luc Pionchon <luc.pionchon@nokia.com>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public License
10  * as published by the Free Software Foundation; either version 2.1 of
11  * the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21  * 02110-1301 USA
22  *
23  */
24
25
26 #include <memory.h>
27 #include <string.h>
28 #include <strings.h>
29 #include <stdio.h>
30 #include "hildon-app.h"
31 #include <hildon-appview.h>
32 #include <hildon-find-toolbar.h>
33
34 #include <gtk/gtkadjustment.h>
35 #include <gtk/gtkmenu.h>
36 #include <gtk/gtkimcontext.h>
37 #include <gtk/gtkmenuitem.h>
38 #include <gtk/gtkcheckmenuitem.h>
39 #include <gtk/gtkmenushell.h>
40 #include <gtk/gtkwindow.h>
41 #include <gtk/gtkwidget.h>
42 #include <gtk/gtkhbox.h>
43 #include <gtk/gtkvbox.h>
44 #include <gtk/gtklabel.h>
45 #include <gtk/gtkprogressbar.h>
46 #include <gtk/gtkimage.h>
47 #include <gtk/gtkiconfactory.h>
48 #include <gtk/gtk.h>
49 #include <gdk/gdkkeysyms.h>
50 #include <gdk/gdk.h>
51
52 #include <X11/X.h>
53 #include <X11/Xlib.h>
54 #include <X11/Xatom.h>
55
56
57 #include <libintl.h>
58 #define _(String) gettext(String)
59
60 enum {
61   PROP_0,
62   PROP_CONNECTED_ADJUSTMENT,
63   PROP_FULLSCREEN_KEY_ALLOWED,
64   PROP_FULLSCREEN,
65   PROP_TITLE,
66   PROP_MENU_UI
67 };
68
69 /*The size of screen*/
70 #define WINDOW_HEIGHT           480
71 #define WINDOW_WIDTH            800
72
73 #define NAVIGATOR_HEIGHT        WINDOW_HEIGHT
74
75 #define APPVIEW_HEIGHT          396
76 #define APPVIEW_WIDTH           672
77
78 #define TOOLBAR_HEIGHT          40
79 #define TOOLBAR_UP              9
80 #define TOOLBAR_DOWN            9
81 #define TOOLBAR_MIDDLE          10
82 #define TOOLBAR_RIGHT           24
83 #define TOOLBAR_LEFT            24
84 #define TOOLBAR_WIDTH           APPVIEW_WIDTH
85
86 #define WORKAREA_ATOM "_NET_WORKAREA"
87
88 /* Non atom defines */
89 #define _NET_WM_STATE_REMOVE    0       /* remove/unset property */
90 #define _NET_WM_STATE_ADD       1       /* add/set property */
91
92 /*Margins
93  * These margins are set to be 5pixels smaller than in the specs
94  * Inner things are allocation that extra space
95  * */
96 /*
97 #define MARGIN_TOOLBAR_TOP 2
98 #define MARGIN_TOOLBAR_BOTTOM 6
99 #define MARGIN_TOOLBAR_LEFT 22
100 #define MARGIN_TOOLBAR_RIGHT 23
101 */
102 #define MARGIN_APPVIEW_TOP 0
103 #define MARGIN_APPVIEW_BOTTOM 24
104 #define MARGIN_APPVIEW_LEFT 24
105 #define MARGIN_APPVIEW_RIGHT 24
106
107
108 #define HILDON_APPVIEW_GET_PRIVATE(obj) \
109     (G_TYPE_INSTANCE_GET_PRIVATE ((obj),\
110      HILDON_TYPE_APPVIEW, HildonAppViewPrivate))
111
112 /*Progressbar*/
113 #define DEFAULT_WIDTH 20
114 #define DEFAULT_HEIGHT 28
115 #define BANNER_WIDTH DEFAULT_WIDTH
116 #define BANNER_HEIGHT DEFAULT_HEIGHT
117
118 static GtkBinClass *parent_class;
119
120 static void hildon_appview_init(HildonAppView * self);
121 static void hildon_appview_class_init(HildonAppViewClass * appview_class);
122
123 static void hildon_appview_menupopupfunc(GtkMenu *menu, gint *x, gint *y,
124                                          gboolean *push_in,
125                                          GtkWidget *widget);
126 static void hildon_appview_menupopupfuncfull(GtkMenu *menu, gint *x, gint *y,
127                                              gboolean *push_in,
128                                              GtkWidget *widget);
129 static gboolean hildon_appview_expose(GtkWidget * widget,
130                                       GdkEventExpose * event);
131 static void hildon_appview_forall(GtkContainer * container,
132                                   gboolean include_internals,
133                                   GtkCallback callback,
134                                   gpointer callback_data);
135 static void hildon_appview_show_all(GtkWidget *widget);
136
137 static void hildon_appview_size_allocate(GtkWidget * widget,
138                                          GtkAllocation * allocation);
139 static void hildon_appview_size_request(GtkWidget * widget,
140                                         GtkRequisition * requisition);
141 static void hildon_appview_finalize(GObject * obj_self);
142 static void hildon_appview_set_property(GObject * object, guint property_id,
143                                     const GValue * value, GParamSpec * pspec);
144 static void hildon_appview_get_property(GObject * object, guint property_id,
145                                     GValue * value, GParamSpec * pspec);
146 static void hildon_appview_destroy(GtkObject *obj);
147 static void hildon_appview_real_fullscreen_state_change(HildonAppView *
148                                                         self,
149                                                         gboolean
150                                                         fullscreen);
151 static void hildon_appview_switched_to(HildonAppView * self);
152 static void get_client_area(GtkWidget * widget,
153                             GtkAllocation * allocation);
154
155 typedef void (*HildonAppViewSignal) (HildonAppView *, gint, gpointer);
156
157 /* signals */
158 enum {
159     TOOLBAR_CHANGED,
160     TOOLBAR_TOGGLE_REQUEST,
161     FULLSCREEN_STATE_CHANGE,
162     TITLE_CHANGE,
163     SWITCHED_TO,
164     SWITCHED_FROM,
165     INCREASE_BUTTON_EVENT,
166     DECREASE_BUTTON_EVENT,
167     HILDON_APPVIEW_LAST_SIGNAL
168 };
169
170 static guint appview_signals[HILDON_APPVIEW_LAST_SIGNAL] = { 0 };
171
172 enum {
173     WIN_TYPE = 0,
174     WIN_TYPE_MESSAGE,
175     MAX_WIN_MESSAGES
176 };
177
178 struct _HildonAppViewPrivate {
179     GtkWidget *menu;
180     gchar *title;
181
182     GtkAllocation allocation;
183
184     guint fullscreen : 1;
185     guint fullscreenshortcutallowed : 1;
186     /* For future expansion. We might use the below variables for disabling keyrepeat
187      * if we need it someday. */
188     guint increase_button_pressed_down : 1;
189     guint decrease_button_pressed_down : 1;
190     gint visible_toolbars;
191     GtkAdjustment * connected_adjustment;
192
193     gchar *menu_ui;
194 };
195
196 /* FIXME: Extremely old Legacy code. I wonder why we need 
197           a custom marshaller in the first place. */
198 static void hildon_appview_signal_marshal(GClosure * closure,
199                                           GValue * return_value,
200                                           guint n_param_values,
201                                           const GValue * param_values,
202                                           gpointer invocation_hint,
203                                           gpointer marshal_data)
204 {
205     register HildonAppViewSignal callback;
206     register GCClosure *cc = (GCClosure *) closure;
207     register gpointer data1, data2;
208
209     g_return_if_fail(n_param_values == 2);
210
211     if (G_CCLOSURE_SWAP_DATA(closure)) {
212         data1 = closure->data;
213         data2 = g_value_peek_pointer(param_values + 0);
214     } else {
215         data1 = g_value_peek_pointer(param_values + 0);
216         data2 = closure->data;
217     }
218
219     callback =
220   /* This is a compilation workaround for gcc > 3.3 since glib is buggy */ 
221   /* see http://bugzilla.gnome.org/show_bug.cgi?id=310175 */
222            
223 #ifdef __GNUC__
224   __extension__
225 #endif
226         (HildonAppViewSignal) (marshal_data !=
227                                NULL ? marshal_data : cc->callback);
228
229     callback((HildonAppView *) data1,
230              (gint) g_value_get_int(param_values + 1), data2);
231 }
232
233 GType hildon_appview_get_type(void)
234 {
235     static GType appview_type = 0;
236
237     if (!appview_type) {
238         static const GTypeInfo appview_info = {
239             sizeof(HildonAppViewClass),
240             NULL,       /* base_init */
241             NULL,       /* base_finalize */
242             (GClassInitFunc) hildon_appview_class_init,
243             NULL,       /* class_finalize */
244             NULL,       /* class_data */
245             sizeof(HildonAppView),
246             0,  /* n_preallocs */
247             (GInstanceInitFunc) hildon_appview_init,
248         };
249         appview_type = g_type_register_static(GTK_TYPE_BIN,
250                                               "HildonAppView",
251                                               &appview_info, 0);
252     }
253     return appview_type;
254 }
255
256 /*
257  * Class initialisation.
258  */
259 static void hildon_appview_class_init(HildonAppViewClass * appview_class)
260 {
261     /* Get convenience variables */
262     GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(appview_class);
263     GObjectClass *object_class = G_OBJECT_CLASS(appview_class);
264     GtkContainerClass *container_class =
265         GTK_CONTAINER_CLASS(appview_class);
266
267     /* Set the global parent_class here */
268     parent_class = g_type_class_peek_parent(appview_class);
269
270     object_class->set_property = hildon_appview_set_property;
271     object_class->get_property = hildon_appview_get_property;
272
273     /* Set the widgets virtual functions */
274     widget_class->size_allocate = hildon_appview_size_allocate;
275     widget_class->size_request = hildon_appview_size_request;
276     widget_class->expose_event = hildon_appview_expose;
277     widget_class->show_all = hildon_appview_show_all;
278     /* widget_class->realize = hildon_appview_realize; */
279     
280     /* now the object stuff */
281     object_class->finalize = hildon_appview_finalize;
282
283     /* To the container */
284     container_class->forall = hildon_appview_forall;
285     
286     /* gtkobject stuff*/
287     GTK_OBJECT_CLASS(appview_class)->destroy = hildon_appview_destroy; 
288     
289     /* And own virtual functions */
290     appview_class->fullscreen_state_change =
291         hildon_appview_real_fullscreen_state_change;
292     appview_class->switched_to = hildon_appview_switched_to;
293
294     g_type_class_add_private(appview_class,
295                              sizeof(struct _HildonAppViewPrivate));
296
297     /* New signals */
298     appview_signals[TOOLBAR_CHANGED] =
299         g_signal_new("toolbar-changed",
300                      G_OBJECT_CLASS_TYPE(object_class),
301                      G_SIGNAL_RUN_FIRST,
302                      G_STRUCT_OFFSET(HildonAppViewClass, toolbar_changed),
303                      NULL, NULL,
304                      g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
305
306     appview_signals[TOOLBAR_TOGGLE_REQUEST] =
307         g_signal_new("toolbar-toggle-request",
308                      G_OBJECT_CLASS_TYPE(object_class),
309                      G_SIGNAL_RUN_FIRST,
310                      G_STRUCT_OFFSET(HildonAppViewClass,
311                                      toolbar_toggle_request), NULL, NULL,
312                      g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
313
314     appview_signals[FULLSCREEN_STATE_CHANGE] =
315         g_signal_new("fullscreen_state_change",
316                      G_OBJECT_CLASS_TYPE(object_class),
317                      G_SIGNAL_RUN_FIRST,
318                      G_STRUCT_OFFSET(HildonAppViewClass,
319                                      fullscreen_state_change), NULL, NULL,
320                      hildon_appview_signal_marshal, G_TYPE_NONE, 1,
321                      G_TYPE_INT);
322
323     appview_signals[TITLE_CHANGE] =
324         g_signal_new("title_change",
325                      G_OBJECT_CLASS_TYPE(object_class),
326                      G_SIGNAL_RUN_FIRST,
327                      G_STRUCT_OFFSET(HildonAppViewClass, title_change),
328                      NULL, NULL,
329                      g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
330
331     appview_signals[SWITCHED_TO] =
332         g_signal_new("switched_to",
333                      G_OBJECT_CLASS_TYPE(object_class),
334                      G_SIGNAL_RUN_FIRST,
335                      G_STRUCT_OFFSET(HildonAppViewClass, switched_to),
336                      NULL, NULL,
337                      g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
338
339     appview_signals[SWITCHED_FROM] =
340         g_signal_new("switched_from",
341                      G_OBJECT_CLASS_TYPE(object_class),
342                      G_SIGNAL_RUN_FIRST,
343                      G_STRUCT_OFFSET(HildonAppViewClass, switched_from),
344                      NULL, NULL,
345                      g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
346
347     appview_signals[INCREASE_BUTTON_EVENT] =
348         g_signal_new("increase_button_event",
349                      G_OBJECT_CLASS_TYPE(object_class),
350                      G_SIGNAL_RUN_FIRST,
351                      G_STRUCT_OFFSET(HildonAppViewClass, increase_button_event),
352                      NULL, NULL,
353                      g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1,
354                      G_TYPE_UINT);
355
356     appview_signals[DECREASE_BUTTON_EVENT] =
357         g_signal_new("decrease_button_event",
358                      G_OBJECT_CLASS_TYPE(object_class),
359                      G_SIGNAL_RUN_FIRST,
360                      G_STRUCT_OFFSET(HildonAppViewClass, decrease_button_event),
361                      NULL, NULL,
362                      g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1,
363                      G_TYPE_UINT);
364
365     /* New properties */                     
366     g_object_class_install_property(object_class, PROP_CONNECTED_ADJUSTMENT,
367         g_param_spec_object("connected-adjustment",
368                             "Connected GtkAdjustment",
369                             "The GtkAdjustment. The increase and decrease hardware buttons are mapped to this.",
370                             GTK_TYPE_ADJUSTMENT,
371                             G_PARAM_READWRITE));
372
373     g_object_class_install_property(object_class, PROP_FULLSCREEN_KEY_ALLOWED,
374                                     g_param_spec_boolean("fullscreen-key-allowed",
375                                                          "Fullscreen key allowed",
376                                                          "Whether the fullscreen key is allowed or not",
377                                                          FALSE,
378                                                          G_PARAM_READWRITE));
379
380     g_object_class_install_property(object_class, PROP_FULLSCREEN,
381                                     g_param_spec_boolean("fullscreen",
382                                                          "Fullscreen",
383                                                          "Whether the appview should be fullscreen or not",
384                                                          FALSE,
385                                                          G_PARAM_READWRITE));
386     g_object_class_install_property(object_class, PROP_TITLE,
387                                     g_param_spec_string("title",
388                                                         "Title",
389                                                         "Appview title",
390                                                         NULL,
391                                                         G_PARAM_READWRITE));
392     g_object_class_install_property(object_class, PROP_MENU_UI,
393                                     g_param_spec_string("menu-ui",
394                                                         "Menu UI string",
395                                                         "UI string for application view menu",
396                                                         NULL,
397                                                         G_PARAM_READWRITE));
398    widget_class = (GtkWidgetClass*) appview_class;
399 }
400
401 /*
402  * Performs the initialisation of the widget.
403  */
404 static void hildon_appview_init(HildonAppView * self)
405 {
406     HildonAppViewPrivate *priv = self->priv =
407         HILDON_APPVIEW_GET_PRIVATE(self);
408
409     /* the vbox is used to handle both the view's main body and how many
410      * toolbars as the user wants */
411
412     /* FIXME: Where does this constant 10 come from */
413     self->vbox = gtk_vbox_new(TRUE, 10);
414     gtk_widget_set_parent(self->vbox, GTK_WIDGET(self));
415     priv->menu = NULL;
416     priv->visible_toolbars = 0;
417
418     priv->title = g_strdup("");
419
420     priv->fullscreen = FALSE;
421     priv->fullscreenshortcutallowed = FALSE;
422     priv->increase_button_pressed_down = FALSE;
423     priv->decrease_button_pressed_down = FALSE;
424    
425     priv->connected_adjustment = NULL;
426 }
427
428 /*
429  * Performs the standard gtk finalize function, freeing allocated
430  * memory and propagating the finalization to the parent.
431  */
432 static void hildon_appview_finalize(GObject * obj_self)
433 {
434     HildonAppView *self;
435     g_return_if_fail(HILDON_APPVIEW(obj_self));
436     self = HILDON_APPVIEW(obj_self);
437
438     if (self->priv->menu_ui)
439       g_free (self->priv->menu_ui);
440
441     if (self->priv->connected_adjustment != NULL)
442       g_object_remove_weak_pointer (G_OBJECT (self->priv->connected_adjustment),
443                                     (gpointer) &self->priv->connected_adjustment);
444
445     if (G_OBJECT_CLASS(parent_class)->finalize)
446         G_OBJECT_CLASS(parent_class)->finalize(obj_self);
447
448     g_free(self->priv->title);
449 }
450
451 /*
452  * An accessor to set private properties of HildonAppView.
453  */
454 static void hildon_appview_set_property(GObject * object, guint property_id,
455                                     const GValue * value, GParamSpec * pspec)
456 {
457     HildonAppView *appview = HILDON_APPVIEW (object);
458
459     switch (property_id) {
460     case PROP_CONNECTED_ADJUSTMENT:
461         hildon_appview_set_connected_adjustment (appview, g_value_get_object (value));
462         break;
463
464     case PROP_FULLSCREEN_KEY_ALLOWED:
465         hildon_appview_set_fullscreen_key_allowed (appview, g_value_get_boolean (value));
466         break;
467
468     case PROP_FULLSCREEN:
469         hildon_appview_set_fullscreen (appview, g_value_get_boolean (value));
470         break;
471
472     case PROP_TITLE:
473         hildon_appview_set_title (appview, g_value_get_string (value));
474         break;
475
476     case PROP_MENU_UI:
477         hildon_appview_set_menu_ui (appview, g_value_get_string (value));
478         break;
479     
480     default:
481         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
482         break;
483     }
484 }
485
486 /*
487  * An accessor to get private properties of HildonAppView.
488  */
489 static void hildon_appview_get_property(GObject * object, guint property_id,
490                                     GValue * value, GParamSpec * pspec)
491 {
492     HildonAppViewPrivate *priv = HILDON_APPVIEW_GET_PRIVATE(object);
493
494     switch (property_id) {
495     case PROP_CONNECTED_ADJUSTMENT:
496         g_value_set_object (value, priv->connected_adjustment);
497         break;
498
499     case PROP_FULLSCREEN_KEY_ALLOWED:
500         g_value_set_boolean (value, priv->fullscreenshortcutallowed);
501         break;
502
503     case PROP_FULLSCREEN:
504         g_value_set_boolean (value, priv->fullscreen);
505         break;
506
507     case PROP_TITLE:
508         g_value_set_string (value, priv->title);
509         break;
510
511     case PROP_MENU_UI:
512         g_value_set_string (value, priv->menu_ui);
513         break;
514         
515     default:
516         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
517         break;
518     }
519 }
520
521 /*
522  * Used when the HildonAppView is exposed, this function gets a GtkBoxChild
523  * as first argument, and a pointer to a gint as second argument. If such
524  * GtkBoxChild is visible, the function increments the gint. It is used
525  * in a loop, to compute the number of visible toolbars.
526  */
527 static void visible_toolbar(gpointer data, gpointer user_data) 
528 {
529     if(GTK_WIDGET_VISIBLE(((GtkBoxChild *)data)->widget))
530       (*((gint *)user_data))++;
531 }
532
533 /*
534  * Used in the paint_toolbar function to discover how many toolbars are
535  * above the find toolbar. It's called in a loop that iterates through
536  * all the children of the GtkVBox of the HildonAppView.
537  */
538 static void find_findtoolbar_index(gpointer data, gpointer user_data)
539 {
540     gint *pass_bundle = (gint *)user_data;
541     
542     if(((GtkBoxChild *)data)->widget->allocation.y < pass_bundle[0]
543        && GTK_WIDGET_VISIBLE(((GtkBoxChild *)data)->widget))
544         pass_bundle[1]++;
545 }
546
547 /*
548  * Used in the paint_toolbar function, it's get a GtkBoxChild as first argument
549  * and a pointer to a GtkWidget as the second one, which will be addressed to
550  * the find toolbar widget, if it is contained in the given GtkBoxChild.
551  */
552 static void find_findtoolbar(gpointer data, gpointer user_data)
553 {
554     if(HILDON_IS_FIND_TOOLBAR(((GtkBoxChild *)data)->widget)
555        && GTK_WIDGET_VISIBLE(((GtkBoxChild *)data)->widget))
556         (*((GtkWidget **)user_data)) = ((GtkBoxChild *)data)->widget;
557 }
558
559 /*
560  * Paints all the toolbar children of the GtkVBox of the HildonAppView.
561  */
562 static void paint_toolbar(GtkWidget *widget, GtkBox *box, 
563                           GdkEventExpose * event, 
564                           gboolean fullscreen)
565 {
566     gint toolbar_num = 0; 
567     gint ftb_index = 0;
568     gint count;
569     GtkWidget *findtoolbar = NULL;
570     gchar toolbar_mode[40];
571
572     /* Iterate through all the children of the vbox of the HildonAppView.
573      * The visible_toolbar function increments toolbar_num if the toolbar
574      * is visible. After this loop, toobar_num will contain the number
575      * of the visible toolbars. */
576     g_list_foreach(box->children, visible_toolbar, 
577                    (gpointer) &toolbar_num);
578     if(toolbar_num <= 0)
579       return;
580
581     /* Loop through all the children of the GtkVBox of the HildonAppView.
582      * The find_findtoolbar function will assign a pointer to the find toolbar
583      * to "findtoolbar" argument. If the findtoolbar is not found, i.e. it
584      * isn't in the GtkVBox, then the "findtoolbar" argument will stay NULL */
585     g_list_foreach(box->children, find_findtoolbar, 
586                    (gpointer) &findtoolbar);
587     if(findtoolbar != NULL){
588         gint pass_bundle[2];/* an array for convient data passing
589                               the first member contains the y allocation
590                                           of the find toolbar, and the second allocation
591                                                 contains the index(how many toolbars are above
592                                                 find toolbar) */
593         pass_bundle[0] = findtoolbar->allocation.y;
594         pass_bundle[1] = ftb_index;
595
596         /* computes how many toolbars are above the find toolbar, and the value is
597          * stored in pass_bundle[1] */
598         g_list_foreach(box->children, find_findtoolbar_index,
599                        (gpointer) pass_bundle);
600         ftb_index = pass_bundle[1];
601     }
602     /*upper border*/
603     sprintf(toolbar_mode, "toolbar%sframe-top", 
604             fullscreen ? "-fullscreen-" : "-");
605     gtk_paint_box(widget->style, widget->window,
606                   GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
607                   &event->area, widget, toolbar_mode,
608                   widget->allocation.x,
609                   GTK_WIDGET(box)->allocation.y -TOOLBAR_UP,
610                   widget->allocation.width, TOOLBAR_UP);
611     
612     /*top most toolbar painting*/
613     if(findtoolbar != NULL && ftb_index == 0 )
614     {
615         sprintf(toolbar_mode, "findtoolbar%s", 
616                 fullscreen ? "-fullscreen" : "");
617         
618         gtk_paint_box(widget->style, widget->window,
619                       GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
620                       &event->area, widget, toolbar_mode,
621                       widget->allocation.x,
622                       GTK_WIDGET(box)->allocation.y,
623                       widget->allocation.width,
624                       TOOLBAR_HEIGHT);
625     }else{
626         sprintf(toolbar_mode, "toolbar%s", 
627                 fullscreen ? "-fullscreen" : "");
628         gtk_paint_box(widget->style, widget->window,
629                       GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
630                       &event->area, widget, toolbar_mode,
631                       widget->allocation.x,
632                       GTK_WIDGET(box)->allocation.y,
633                       widget->allocation.width,
634                       TOOLBAR_HEIGHT);
635     }
636     /*multi toolbar painting*/
637     for(count = 0; count < toolbar_num - 1; count++)
638     {
639         sprintf(toolbar_mode, "toolbar%sframe-middle", 
640                 fullscreen ? "-fullscreen-" : "-");
641         
642         gtk_paint_box(widget->style, widget->window,
643                   GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
644                   &event->area, widget, toolbar_mode,
645                   widget->allocation.x,
646                   GTK_WIDGET(box)->allocation.y + 
647                   (1 + count) * TOOLBAR_HEIGHT + 
648                   count * TOOLBAR_MIDDLE,
649                   widget->allocation.width,
650                   TOOLBAR_MIDDLE);
651         
652         if(findtoolbar != NULL && count + 1 == ftb_index){
653             sprintf(toolbar_mode, "findtoolbar%s", 
654                     fullscreen ? "-fullscreen" : "");
655             
656             gtk_paint_box(widget->style, widget->window,
657                       GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
658                       &event->area, widget, toolbar_mode,
659                       widget->allocation.x,
660                       GTK_WIDGET(box)->allocation.y + 
661                       (1 + count) * (TOOLBAR_HEIGHT + TOOLBAR_MIDDLE),
662                       widget->allocation.width,
663                       TOOLBAR_HEIGHT);
664         }else{
665             sprintf(toolbar_mode, "toolbar%s", 
666                     fullscreen ? "-fullscreen" : "");
667             
668             gtk_paint_box(widget->style, widget->window,
669                       GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
670                       &event->area, widget, toolbar_mode,
671                       widget->allocation.x,
672                       GTK_WIDGET(box)->allocation.y + 
673                       (1 + count) * (TOOLBAR_HEIGHT + TOOLBAR_MIDDLE),
674                       widget->allocation.width,
675                       TOOLBAR_HEIGHT);
676         }
677     }
678     sprintf(toolbar_mode, "toolbar%sframe-bottom", 
679             fullscreen ? "-fullscreen-" : "-");
680     
681     gtk_paint_box(widget->style, widget->window,
682                   GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
683                   &event->area, widget, toolbar_mode,
684                   widget->allocation.x,
685                   GTK_WIDGET(box)->allocation.y + 
686                   GTK_WIDGET(box)->allocation.height,
687                   widget->allocation.width, TOOLBAR_DOWN);
688 }
689
690 /*
691  * Callback function to an expose event.
692  */
693 static gboolean hildon_appview_expose(GtkWidget * widget,
694                                       GdkEventExpose * event)
695 {
696    gint toolbar_num = 0;
697    GtkBox *box = GTK_BOX(HILDON_APPVIEW(widget)->vbox);
698
699   if(GTK_WIDGET_VISIBLE(box) && box->children != NULL)
700   {
701     HildonAppViewPrivate *priv = HILDON_APPVIEW_GET_PRIVATE(widget);
702
703     /* Iterate through all the children of the vbox of the HildonAppView.
704      * The visible_toolbar function increments toolbar_num if the toolbar
705      * is visible. After this loop, toobar_num will contain the number
706      * of the visible toolbars. */
707     g_list_foreach(box->children, visible_toolbar, 
708                    (gpointer) &toolbar_num);
709     
710     if( priv->visible_toolbars != toolbar_num)
711     {
712      /* If the code reaches this block, it means that a toolbar as been added
713       * or removed since last time the view was drawn. Let's then compute the
714       * new height of the toolbars areas */
715      gint y_pos = 0;
716      /* the height difference */
717      gint change = (priv->visible_toolbars - toolbar_num) *
718                    (TOOLBAR_HEIGHT+TOOLBAR_MIDDLE+TOOLBAR_UP);
719      if( change < 0 )
720        change = TOOLBAR_MIDDLE + TOOLBAR_UP;
721      /* the new y-coordinate for the toolbars area */
722      y_pos = HILDON_APPVIEW(widget)->vbox->allocation.y - change;
723        
724      gtk_widget_queue_draw_area(widget, 0, y_pos, widget->allocation.width,
725                  change + HILDON_APPVIEW(widget)->vbox->allocation.height +
726                  TOOLBAR_DOWN);
727      priv->visible_toolbars = toolbar_num;
728     }
729   }
730
731
732    if (HILDON_APPVIEW(widget)->priv->fullscreen)
733    {
734            if (toolbar_num > 0)
735              paint_toolbar(widget, box, event, TRUE);
736    }
737    else
738    {
739            gint appview_height_decrement = 0;
740            if (toolbar_num > 0)
741      {
742              appview_height_decrement = toolbar_num * TOOLBAR_HEIGHT +
743                                          (toolbar_num - 1) * TOOLBAR_MIDDLE 
744                                    + TOOLBAR_UP + TOOLBAR_DOWN;
745             
746        paint_toolbar(widget, box, event, FALSE);
747            }
748      else
749      {
750              appview_height_decrement = MARGIN_APPVIEW_BOTTOM;
751
752              gtk_paint_box(widget->style, widget->window,
753                                  GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
754                                  &event->area, widget, "bottom-border",
755                                  widget->allocation.x,
756                      widget->allocation.y +
757                      (widget->allocation.height - MARGIN_APPVIEW_BOTTOM),
758                      widget->allocation.width, MARGIN_APPVIEW_BOTTOM);
759             }
760   gtk_paint_box( widget->style, widget->window,
761                  GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT, 
762                  &event->area,
763                  widget, "left-border", widget->allocation.x,
764                  widget->allocation.y, MARGIN_APPVIEW_LEFT,
765                  widget->allocation.height - appview_height_decrement );
766   gtk_paint_box( widget->style, widget->window,
767                  GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT, 
768                  &event->area,
769                  widget, "right-border",
770                  (widget->allocation.x +
771                  widget->allocation.width) -
772                  MARGIN_APPVIEW_RIGHT, widget->allocation.y,
773                  MARGIN_APPVIEW_RIGHT,
774                  widget->allocation.height - appview_height_decrement );
775   }
776
777   GTK_WIDGET_CLASS(parent_class)->expose_event(widget, event);
778
779   return FALSE;
780
781 }
782
783 /*
784  * Responds to the usual size_request signal.
785  */
786 static void hildon_appview_size_request(GtkWidget * widget,
787                                         GtkRequisition * requisition)
788 {
789     HildonAppViewPrivate *priv = HILDON_APPVIEW(widget)->priv;
790     GtkWidget *child = GTK_BIN(widget)->child;
791
792     /* forward the size_request to the eventual child of the main container */
793     if (child)
794         gtk_widget_size_request(child, requisition);
795
796     /* forward the size_request to the eventual vbox (which may contain
797      * toolbars) */
798     if (HILDON_APPVIEW(widget)->vbox != NULL)
799         gtk_widget_size_request(HILDON_APPVIEW(widget)->vbox, requisition);
800
801     /* express the size_request for the view */
802     if (priv->fullscreen) {
803         requisition->height = WINDOW_HEIGHT;
804         requisition->width = WINDOW_WIDTH;
805     } else {
806         requisition->height = APPVIEW_HEIGHT;
807         requisition->width = APPVIEW_WIDTH;
808     }
809 }
810
811 /*
812  * Computes size and position for the children of the view.
813  */
814 static void hildon_appview_size_allocate(GtkWidget * widget,
815                                          GtkAllocation * allocation)
816 {
817     GtkAllocation box_allocation;
818     GtkAllocation alloc = *allocation;
819     gint border_width = GTK_CONTAINER(widget)->border_width;
820     GtkBin *bin = GTK_BIN(widget);
821     GtkBox *box = GTK_BOX(HILDON_APPVIEW(widget)->vbox);
822     gboolean at_least_one_visible_toolbar = FALSE;
823
824     if(!GTK_IS_WIDGET(bin->child)) return;
825
826     widget->allocation = *allocation;
827     
828     if (bin->child != NULL && GTK_IS_WIDGET(bin->child)) {
829         if (HILDON_APPVIEW(widget)->priv->fullscreen) {
830             alloc.x += border_width;
831             alloc.y += border_width;
832             alloc.width -= (border_width * 2);
833             alloc.height -= (border_width * 2);
834         } else {
835             alloc.x += border_width + MARGIN_APPVIEW_LEFT;
836             alloc.y += border_width + MARGIN_APPVIEW_TOP;
837             alloc.width -= (border_width * 2) + (MARGIN_APPVIEW_LEFT +
838                                       MARGIN_APPVIEW_RIGHT);
839             alloc.height -= (border_width * 2) + MARGIN_APPVIEW_TOP;
840         }
841     }
842
843     if (box->children != NULL) {
844         gint length = 0;
845         gint box_height = 0;
846         /* Iterate through all the children of the vbox of the HildonAppView.
847          * The visible_toolbar function increments toolbar_num if the toolbar
848          * is visible. After this loop, toobar_num will contain the number
849          * of the visible toolbars. */
850         g_list_foreach(box->children, visible_toolbar, 
851                      (gpointer) &length);
852         if(length > 0){
853             box_height = length * TOOLBAR_HEIGHT + 
854               (length - 1) * TOOLBAR_MIDDLE;
855        
856             if(bin->child != NULL) {
857                 alloc.height = alloc.height - box_height - TOOLBAR_UP
858                   - TOOLBAR_DOWN;
859                 at_least_one_visible_toolbar = TRUE;
860             }
861         
862             box_allocation.y = allocation->height - box_height - TOOLBAR_DOWN;
863             box_allocation.height = box_height;
864             box_allocation.x = allocation->x + TOOLBAR_LEFT;
865             box_allocation.width = allocation->width - TOOLBAR_LEFT - 
866               TOOLBAR_RIGHT;
867             gtk_widget_size_allocate(GTK_WIDGET(box), &box_allocation);
868         }
869     }
870     
871     /* The bottom skin graphics is visible only when there are no toolbars */
872     if ((HILDON_APPVIEW(widget)->priv->fullscreen == FALSE) &&
873         (at_least_one_visible_toolbar == FALSE))
874         alloc.height -= MARGIN_APPVIEW_BOTTOM;
875     
876     gtk_widget_size_allocate(GTK_WIDGET(bin->child), &alloc);
877 }
878
879 /*
880  * Overrides gtk_container_forall, calling the callback function for each of
881  * the children of HildonAppPrivate.
882  */
883 static void hildon_appview_forall(GtkContainer * container,
884                                   gboolean include_internals,
885                                   GtkCallback callback,
886                                   gpointer callback_data)
887 {
888     HildonAppView *self = HILDON_APPVIEW(container);
889
890     g_return_if_fail(callback != NULL);
891
892     GTK_CONTAINER_CLASS(parent_class)->forall(container, include_internals,
893                                               callback, callback_data);
894     if(include_internals && self->vbox != NULL)
895         (* callback)(GTK_WIDGET(self->vbox), callback_data);
896 }
897
898 /**
899  * Shows all the widgets in the container.
900  */
901 static void hildon_appview_show_all(GtkWidget *widget)
902 {
903     HildonAppView *self = HILDON_APPVIEW(widget);
904     
905     /* Toolbar items */
906     gtk_widget_show_all(self->vbox);
907
908     /* Parent handless stuff inside appview */
909     GTK_WIDGET_CLASS(parent_class)->show_all(widget);
910 }
911
912 /*
913  * Frees all the resources and propagates the destroy call to the parent.
914  */
915 static void hildon_appview_destroy(GtkObject *obj)
916 {
917     HildonAppView *self = HILDON_APPVIEW(obj);
918     
919     if(self->vbox != NULL){
920         gtk_widget_unparent(self->vbox);
921         self->vbox = NULL;      
922     }
923
924     GTK_OBJECT_CLASS(parent_class)->destroy(obj);
925 }
926
927 /*******************/
928 /*   Signals       */
929 /*******************/
930
931 /*
932 static void hildon_appview_toolbar_toggle_request( HildonAppView *self )
933 {
934
935 }
936 */
937
938 /*Signal - When is changed to this appview, this is called*/
939 static void hildon_appview_switched_to(HildonAppView * self)
940 {
941     GtkWidget *parent;
942
943     g_return_if_fail(self && HILDON_IS_APPVIEW(self));
944
945     parent = gtk_widget_get_parent(GTK_WIDGET(self));
946     hildon_appview_set_fullscreen( self, self->priv->fullscreen );
947 }
948
949 /*Signal - When the fullscreen state is changed, this is called*/
950 static void hildon_appview_real_fullscreen_state_change(HildonAppView *
951                                                         self,
952                                                         gboolean
953                                                         fullscreen)
954 {
955     HildonAppViewPrivate *priv;
956     g_return_if_fail(self && HILDON_IS_APPVIEW(self));
957     priv = self->priv;
958
959     /* Ensure that state is really changed */
960     if( priv->fullscreen == fullscreen )
961       return;
962
963     if( fullscreen )
964       gtk_window_fullscreen( GTK_WINDOW(
965                              gtk_widget_get_parent(GTK_WIDGET(self))) );
966     else
967       gtk_window_unfullscreen( GTK_WINDOW(
968                              gtk_widget_get_parent(GTK_WIDGET(self))) );
969
970     priv->fullscreen = fullscreen;
971 }
972
973 /*******************/
974 /*     General     */
975 /*******************/
976
977
978 /*
979  * queries a window for the root window coordinates and size of its
980  * client area (i.e. minus the title borders etc.)
981  */
982 static void get_client_area(GtkWidget * widget, GtkAllocation * allocation)
983 {
984     GdkWindow *window = widget->window;
985     
986     if (window)
987       gdk_window_get_origin(window, &allocation->x, &allocation->y);
988     else
989       memset( allocation, 0, sizeof(GtkAllocation) );
990 }
991
992 /*The menu popuping needs a menu popup-function*/
993 static void hildon_appview_menupopupfunc( GtkMenu *menu, gint *x, gint *y,
994                                           gboolean *push_in, GtkWidget *widget )
995 {
996   GtkAllocation client_area = { 0, 0, 0, 0 };
997
998   get_client_area( GTK_WIDGET(widget), &client_area );
999
1000   gtk_widget_style_get (GTK_WIDGET (menu), "horizontal-offset", x,
1001                         "vertical-offset", y, NULL);
1002    
1003   *x += client_area.x;
1004   *y += client_area.y;
1005   
1006 }
1007
1008 /* Similar to above, but used in fullscreen mode */
1009 static void hildon_appview_menupopupfuncfull( GtkMenu *menu, gint *x, gint *y,
1010                                               gboolean *push_in, 
1011                                               GtkWidget *widget )
1012 {
1013   gtk_widget_style_get (GTK_WIDGET (menu), "horizontal-offset", x,
1014                         "vertical-offset", y, NULL);
1015
1016   *x = MAX (0, *x);
1017   *y = MAX (0, *y);
1018 }
1019
1020 /*******************/
1021 /*public functions*/
1022 /*******************/
1023
1024
1025 /**
1026  * hildon_appview_new: 
1027  * @title: The application view title of the new @HildonAppView.
1028  * 
1029  * Use this function to create a new application view.
1030  * 
1031  * Return value: A @HildonAppView.
1032  **/
1033 GtkWidget *hildon_appview_new(const gchar * title)
1034 {
1035     HildonAppView *newappview = g_object_new(HILDON_TYPE_APPVIEW, NULL);
1036
1037     hildon_appview_set_title(newappview, title);
1038     return GTK_WIDGET(newappview);
1039 }
1040
1041 /**
1042  * hildon_appview_add_with_scrollbar
1043  * @self : A @HildonAppView
1044  * @child : A @GtkWidget
1045  *
1046  * Adds the @child to the @self(HildonAppView) and creates a scrollbar
1047  * to it. Similar as adding first a @GtkScrolledWindow and then the
1048  * @child to it.
1049  */
1050 void hildon_appview_add_with_scrollbar(HildonAppView * self,
1051                                        GtkWidget * child)
1052 {
1053     GtkScrolledWindow *scrolledw;
1054
1055     g_return_if_fail(HILDON_IS_APPVIEW(self));
1056     g_return_if_fail(GTK_IS_WIDGET(child));
1057     g_return_if_fail(child->parent == NULL);
1058
1059     scrolledw = GTK_SCROLLED_WINDOW(gtk_scrolled_window_new(NULL, NULL));
1060     gtk_scrolled_window_set_policy(scrolledw, GTK_POLICY_NEVER,
1061                                    GTK_POLICY_AUTOMATIC);
1062     gtk_scrolled_window_set_shadow_type(scrolledw, GTK_SHADOW_NONE);
1063
1064     /* FIXME: child doesn't need to be a viewport in order it can
1065               be packed into scrolled window. It just needs to support
1066               setting adjustments. */
1067     if (GTK_IS_VIEWPORT(child))
1068         gtk_container_add(GTK_CONTAINER(scrolledw), child);
1069     else
1070     {
1071       if( GTK_IS_CONTAINER(child) )
1072         gtk_container_set_focus_vadjustment( GTK_CONTAINER(child),
1073                               gtk_scrolled_window_get_vadjustment(scrolledw) );
1074         gtk_scrolled_window_add_with_viewport(scrolledw, child);
1075     }
1076
1077     gtk_container_add(GTK_CONTAINER(self), GTK_WIDGET(scrolledw));
1078 }
1079
1080 /**
1081  * hildon_appview_get_title:
1082  * @self : A @HildonAppView
1083  *
1084  * Gets the title of given #HildonAppView.
1085  *
1086  * Return value: The title of the application view.
1087  **/
1088 const gchar *hildon_appview_get_title(HildonAppView * self)
1089 {
1090     g_return_val_if_fail(self && HILDON_IS_APPVIEW(self), "");
1091     return self->priv->title;
1092 }
1093
1094 /**
1095  * hildon_appview_set_title:
1096  * @self : A @HildonAppView
1097  * @newname : The new title of the application view.
1098  * 
1099  * Sets an title of an application view. The title is visible only if
1100  * twoparttitle is enabled on the @HildonApp
1101  * 
1102  **/
1103 void hildon_appview_set_title(HildonAppView * self, const gchar * newname)
1104 {
1105     gchar *oldtitle;
1106
1107     g_return_if_fail(self && HILDON_IS_APPVIEW(self));
1108     oldtitle = self->priv->title;
1109
1110     if (newname != NULL)
1111         self->priv->title = g_strdup(newname);
1112     else
1113         self->priv->title = g_strdup("");
1114
1115     g_free(oldtitle);
1116     g_signal_emit_by_name(G_OBJECT(self), "title_change");
1117 }
1118
1119 /**
1120  * hildon_appview_set_toolbar:
1121  * @self: A #HildonAppView
1122  * @toolbar: A #GtkToolbar
1123  *
1124  * Sets the #GtkToolbar to given #HildonAppView. This is, however, not a recommned way to
1125  * set your toolbars. When you have multi toolbars, calling this function more than once will just
1126  * replace the bottom most toolbar. There is a #GtkVBox in #HildonAppView's public structure, the programmer
1127  * is responsible to pack his toolbars in the #GtkVBox, and #HildonAppView will take care of put them at the
1128  * right place.
1129  * 
1130  **/
1131 #ifndef HILDON_DISABLE_DEPRECATED
1132 void hildon_appview_set_toolbar(HildonAppView * self, GtkToolbar * toolbar)
1133 {
1134     GtkBox *box = GTK_BOX(HILDON_APPVIEW(self)->vbox);
1135     g_return_if_fail(self && HILDON_IS_APPVIEW(self));
1136     if(toolbar != NULL)/*for failure checking*/
1137         g_return_if_fail(GTK_IS_TOOLBAR(toolbar));
1138     
1139     /*if it is NULL, it unsets the last one, 
1140      * if it is not null, it unsets the last one anyway*/
1141     if(box->children != NULL){
1142         GtkWidget *last_widget;
1143         
1144         last_widget = ((GtkBoxChild *)g_list_last
1145                        (box->children)->data)->widget;
1146         gtk_container_remove(GTK_CONTAINER(box), 
1147                              last_widget);
1148     }
1149     
1150     gtk_box_pack_end(box, GTK_WIDGET(toolbar), TRUE, TRUE, 0);
1151     gtk_widget_queue_resize(GTK_WIDGET(self));
1152     /*deprecated signal*/
1153     g_signal_emit_by_name(G_OBJECT(self), "toolbar-changed");
1154 }
1155 #endif
1156 /**
1157  * hildon_appview_get_toolbar:
1158  * @self: A #HildonAppView
1159  *
1160  * This function will only 
1161  * return the last widget that has been packed into the #GtkVBox in the public structure. Note
1162  * this does not, however, mean that it is the bottom most toolbar.
1163  * 
1164  * Return value: The #GtkToolbar assigned to this application view. 
1165  **/
1166 #ifndef HILDON_DISABLE_DEPRECATED
1167 GtkToolbar *hildon_appview_get_toolbar(HildonAppView * self)
1168 {
1169     GtkBox *box = GTK_BOX(HILDON_APPVIEW(self)->vbox);
1170     g_return_val_if_fail(self != NULL && HILDON_IS_APPVIEW(self), FALSE);
1171     if(box != NULL && box->children != NULL)
1172       return GTK_TOOLBAR(((GtkBoxChild*)
1173                           g_list_last(box->children)->data)->widget);
1174     else
1175       return NULL;
1176 }
1177 #endif
1178 /**
1179  * hildon_appview_set_fullscreen:
1180  * @self: A @HildonAppView
1181  * @fullscreen: The new state of fullscreen mode. TRUE means fullscreen
1182  * will be set. FALSE the opposite.
1183  * 
1184  * Set the fullscreen state of given #HildonAppView class.
1185  **/
1186 void hildon_appview_set_fullscreen(HildonAppView * self,
1187                                    gboolean fullscreen)
1188 {
1189     g_return_if_fail(self && HILDON_IS_APPVIEW(self));
1190     g_signal_emit_by_name(G_OBJECT(self), "fullscreen_state_change",
1191                           fullscreen);
1192 }
1193
1194 /**
1195  * hildon_appview_get_fullscreen:
1196  * @self: A @HildonAppView
1197  *
1198  * Gets the current state of fullscreen mode.
1199  * 
1200  * Return value: The current state of fullscreen mode.
1201  **/
1202 gboolean hildon_appview_get_fullscreen(HildonAppView * self)
1203 {
1204     g_return_val_if_fail(self && HILDON_IS_APPVIEW(self), FALSE);
1205     return self->priv->fullscreen;
1206 }
1207
1208 /**
1209  * hildon_appview_get_fullscreen_key_allowed:
1210  * @self: A @HildonAppView
1211  *
1212  * Check if fullscreening with a shortcut is allowed for given
1213  * #HildonAppView.
1214  * 
1215  * Return value: Wheter it's possible to swith fullscreen on/off with
1216  *               a shortcut key.
1217  **/
1218 gboolean hildon_appview_get_fullscreen_key_allowed(HildonAppView * self)
1219 {
1220     g_return_val_if_fail(self && HILDON_IS_APPVIEW(self), FALSE);
1221     return self->priv->fullscreenshortcutallowed;
1222 }
1223
1224 /**
1225  * hildon_appview_set_fullscreen_key_allowed:
1226  * @self: A @HildonAppView
1227  * @allow: Wheter it's possible to swith fullscreen on/off with
1228  *               a shortcut key.
1229  *
1230  * Sets given #HildonAppView whether to allow toggling fullscreen mode
1231  * with a shortcut key.
1232  **/
1233 void hildon_appview_set_fullscreen_key_allowed(HildonAppView * self,
1234                                                gboolean allow)
1235 {
1236     g_return_if_fail(self && HILDON_IS_APPVIEW(self));
1237     self->priv->fullscreenshortcutallowed = allow;
1238 }
1239
1240 /**
1241  * hildon_appview_get_menu:
1242  * @self : #HildonAppView
1243  * 
1244  * Gets the #GtMenu assigned to the #HildonAppview.
1245  *
1246  * Return value: The #GtkMenu assigned to this application view.
1247  **/
1248 GtkMenu *hildon_appview_get_menu(HildonAppView * self)
1249 {
1250     g_return_val_if_fail(self && HILDON_IS_APPVIEW(self), NULL);
1251
1252     if (self->priv->menu == NULL) {
1253         /* Create hildonlike menu */
1254         
1255         GtkUIManager *uim;
1256         GtkWidget *parent = gtk_widget_get_parent (GTK_WIDGET (self));
1257
1258         /* Try to get appview menu from ui manager */        
1259         if (parent && HILDON_IS_APP (parent))
1260           {
1261             uim = hildon_app_get_ui_manager (HILDON_APP (parent));
1262             if (uim)
1263               {
1264                 self->priv->menu =
1265                   gtk_ui_manager_get_widget (uim, "/HildonApp");
1266               }
1267           }
1268         
1269         
1270         if (self->priv->menu == NULL)
1271           {
1272             /* Fall back to oldskool menus */
1273             self->priv->menu = GTK_WIDGET (g_object_new (GTK_TYPE_MENU, NULL));
1274           }  
1275           
1276         gtk_widget_set_name(GTK_WIDGET(self->priv->menu),
1277                             "menu_force_with_corners");
1278         gtk_widget_show_all (self->priv->menu);
1279     }
1280
1281     return GTK_MENU(self->priv->menu);
1282 }
1283
1284 /**
1285  * _hildon_appview_toggle_menu:
1286  * @self : A @HildonAppView
1287  * @button_event_time :
1288  *
1289  * This function should be only called from @HildonApp.
1290  * Should be renamed to popup menu. Just the first parameter is used.
1291  */
1292 void _hildon_appview_toggle_menu(HildonAppView * self,
1293                                  Time button_event_time)
1294 {
1295     GList *children;
1296
1297     g_return_if_fail(self && HILDON_IS_APPVIEW(self));
1298
1299     if (!self->priv->menu)
1300         return;
1301
1302     if (GTK_WIDGET_VISIBLE(self->priv->menu)) {
1303         gtk_menu_popdown(GTK_MENU(self->priv->menu));
1304         gtk_menu_shell_deactivate(GTK_MENU_SHELL(self->priv->menu));
1305         return;
1306     }
1307
1308     /* Avoid opening an empty menu */
1309     children = gtk_container_get_children(
1310                         GTK_CONTAINER(hildon_appview_get_menu(self)));
1311     if (children != NULL) {
1312         GtkWidget *menu;
1313
1314         g_list_free(children);
1315         menu = GTK_WIDGET(hildon_appview_get_menu(self));
1316         if (self->priv->fullscreen) {
1317             gtk_menu_popup(GTK_MENU(menu), NULL, NULL,
1318                            (GtkMenuPositionFunc)
1319                            hildon_appview_menupopupfuncfull,
1320                            self, 0, button_event_time);
1321         } else {
1322             gtk_menu_popup(GTK_MENU(menu), NULL, NULL,
1323                            (GtkMenuPositionFunc)
1324                            hildon_appview_menupopupfunc,
1325                            self, 0, button_event_time);
1326         }
1327         gtk_menu_shell_select_first(GTK_MENU_SHELL(menu), TRUE);
1328     }
1329
1330 }
1331
1332 /**
1333  * _hildon_appview_menu_visible
1334  * @self :  A @HildonAppView
1335  * 
1336  * Checks whether the titlebar menu is currently visible
1337  * Return value : TRUE if the menu is visible, FALSE if not.
1338  */
1339
1340 gboolean _hildon_appview_menu_visible(HildonAppView * self)
1341 {
1342     g_return_val_if_fail (HILDON_IS_APPVIEW (self), FALSE);
1343     
1344     return GTK_WIDGET_VISIBLE(GTK_WIDGET(hildon_appview_get_menu(self)));
1345 }
1346
1347 /**
1348  * hildon_appview_set_connected_adjustment
1349  * @self : A @HildonAppView
1350  * @adjustment : A new #GtkAdjustment set to reach to increase
1351  *   / decrease hardware keys or NULL to unset.
1352  * 
1353  * Sets a #GtkAdjustment which will change when increase/decrease buttons
1354  * are pressed.
1355  **/
1356 void hildon_appview_set_connected_adjustment (HildonAppView * self,
1357                                               GtkAdjustment * adjustment)
1358 {
1359     g_return_if_fail (HILDON_IS_APPVIEW (self));
1360
1361     /* Disconnect old adjustment */
1362     if (self->priv->connected_adjustment != NULL)
1363       g_object_remove_weak_pointer (G_OBJECT (self->priv->connected_adjustment),
1364                                     (gpointer) &self->priv->connected_adjustment);
1365
1366     /* Start using the new one */
1367     self->priv->connected_adjustment = adjustment;
1368     if (self->priv->connected_adjustment != NULL)
1369         g_object_add_weak_pointer (G_OBJECT (self->priv->connected_adjustment),
1370                                    (gpointer) &self->priv->connected_adjustment);
1371 }
1372
1373 /**
1374  * hildon_appview_get_connected_adjustment
1375  * @self : A @HildonAppView
1376  * 
1377  * Retrieves the @GtkAdjustment which is connected to this application view
1378  * and is changed with increase / decrease hardware buttons.
1379  *
1380  * Return value: Currently connectd #GtkAdjustment assigned to this
1381  *               application view or NULL if it's not set.
1382  **/
1383 GtkAdjustment * hildon_appview_get_connected_adjustment (HildonAppView * self)
1384 {
1385     g_return_val_if_fail (HILDON_IS_APPVIEW (self), NULL);
1386    
1387     return self->priv->connected_adjustment;
1388 }
1389
1390
1391 /**
1392  * hildon_appview_set_menu_ui
1393  * @self : A @HildonAppView
1394  * @ui_string : A @GtkUIManager ui description string
1395  *
1396  * Sets the ui description (xml) from which the UIManager creates menus
1397  * (see @GtkUIManager for details on how to use it)
1398  **/
1399 void hildon_appview_set_menu_ui(HildonAppView *self, const gchar *ui_string)
1400 {
1401   g_return_if_fail (HILDON_IS_APPVIEW (self));
1402   
1403   if (ui_string)
1404     {
1405       if (self->priv->menu_ui)
1406         g_free (self->priv->menu_ui);
1407       
1408       self->priv->menu_ui = g_strdup (ui_string);
1409       
1410       /* FIXME: We should update the menu here, preferrably by a
1411        * hildon_app_ensure_menu_update() which re-installs the menu ui
1412        * and calls gtk_ui_manager_ensure_update() 
1413        */
1414     }
1415   else
1416     {
1417       /* Reset the UI */
1418       if (self->priv->menu_ui)
1419         {
1420           g_free (self->priv->menu_ui);
1421           self->priv->menu_ui = NULL;
1422         }
1423     }
1424
1425     g_object_notify (G_OBJECT(self), "menu-ui");
1426 }
1427
1428 /**
1429  * hildon_appview_get_menu_ui
1430  * @self : A @HildonAppView
1431  *
1432  * Sets the ui description (xml) from which the UIManager creates menus
1433  * (see @GtkUIManager for details on how to use it)
1434  *
1435  * Return value: Currently set ui description
1436  * 
1437  **/
1438 const gchar *hildon_appview_get_menu_ui(HildonAppView *self)
1439 {
1440   g_return_val_if_fail (HILDON_IS_APPVIEW (self), NULL);
1441
1442   return (self->priv->menu_ui);
1443
1444 }
1445
1446 /* Called when '+' hardkey is pressed/released */
1447 void _hildon_appview_increase_button_state_changed (HildonAppView * self,
1448                                                     guint newkeytype)
1449 {
1450   self->priv->increase_button_pressed_down = newkeytype;
1451
1452   /* Transform '+' press into adjustment update (usually scrollbar move) */
1453   if ((self->priv->connected_adjustment != NULL) && (newkeytype == GDK_KEY_PRESS))
1454     {
1455       gfloat clampedvalue = CLAMP (gtk_adjustment_get_value (self->priv->connected_adjustment) + self->priv->connected_adjustment->step_increment,
1456                                    self->priv->connected_adjustment->lower,
1457                                    self->priv->connected_adjustment->upper - self->priv->connected_adjustment->page_size);
1458       gtk_adjustment_set_value (self->priv->connected_adjustment, clampedvalue);                                
1459     }   
1460
1461   g_signal_emit (G_OBJECT (self), appview_signals[INCREASE_BUTTON_EVENT], 0, newkeytype);
1462 }
1463
1464 /* Called when '-' hardkey is pressed/released */
1465 void _hildon_appview_decrease_button_state_changed (HildonAppView * self,
1466                                                     guint newkeytype)
1467 {
1468   self->priv->decrease_button_pressed_down = newkeytype;
1469
1470   /* Transform '-' press into adjustment update (usually scrollbar move) */
1471   if ((self->priv->connected_adjustment != NULL) && (newkeytype == GDK_KEY_PRESS))
1472     {
1473       gfloat clampedvalue = CLAMP (gtk_adjustment_get_value (self->priv->connected_adjustment) - self->priv->connected_adjustment->step_increment,
1474                                    self->priv->connected_adjustment->lower,
1475                                    self->priv->connected_adjustment->upper - self->priv->connected_adjustment->page_size);
1476       gtk_adjustment_set_value (self->priv->connected_adjustment, clampedvalue);                                
1477     }
1478
1479   g_signal_emit (G_OBJECT (self), appview_signals[DECREASE_BUTTON_EVENT], 0, newkeytype);
1480 }