minor doc update
[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_assert(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     self->vbox = gtk_vbox_new(TRUE, TOOLBAR_MIDDLE);
413     /* TOOLBAR_MIDDLE is here properly used, as originally meant. In order to
414      * be free to use whatever distance between toolbars, it's crucial to mind
415      * that the relevant gtkrc file must contain the following border property
416      * for the "toolbar-frame-middle" property:  border = {24, 24, 5, 4}
417      */
418
419     gtk_widget_set_parent(self->vbox, GTK_WIDGET(self));
420     priv->menu = NULL;
421     priv->visible_toolbars = 0;
422
423     priv->title = g_strdup("");
424
425     priv->fullscreen = FALSE;
426     priv->fullscreenshortcutallowed = FALSE;
427     priv->increase_button_pressed_down = FALSE;
428     priv->decrease_button_pressed_down = FALSE;
429    
430     priv->connected_adjustment = NULL;
431 }
432
433 /*
434  * Performs the standard gtk finalize function, freeing allocated
435  * memory and propagating the finalization to the parent.
436  */
437 static void hildon_appview_finalize(GObject * obj_self)
438 {
439     HildonAppView *self;
440     g_assert(HILDON_APPVIEW(obj_self));
441     self = HILDON_APPVIEW(obj_self);
442
443     if (self->priv->menu_ui)
444       g_free (self->priv->menu_ui);
445
446     if (self->priv->connected_adjustment != NULL)
447       g_object_remove_weak_pointer (G_OBJECT (self->priv->connected_adjustment),
448                                     (gpointer) &self->priv->connected_adjustment);
449
450     if (G_OBJECT_CLASS(parent_class)->finalize)
451         G_OBJECT_CLASS(parent_class)->finalize(obj_self);
452
453     g_free(self->priv->title);
454 }
455
456 /*
457  * An accessor to set private properties of HildonAppView.
458  */
459 static void hildon_appview_set_property(GObject * object, guint property_id,
460                                     const GValue * value, GParamSpec * pspec)
461 {
462     HildonAppView *appview = HILDON_APPVIEW (object);
463
464     switch (property_id) {
465     case PROP_CONNECTED_ADJUSTMENT:
466         hildon_appview_set_connected_adjustment (appview, g_value_get_object (value));
467         break;
468
469     case PROP_FULLSCREEN_KEY_ALLOWED:
470         hildon_appview_set_fullscreen_key_allowed (appview, g_value_get_boolean (value));
471         break;
472
473     case PROP_FULLSCREEN:
474         hildon_appview_set_fullscreen (appview, g_value_get_boolean (value));
475         break;
476
477     case PROP_TITLE:
478         hildon_appview_set_title (appview, g_value_get_string (value));
479         break;
480
481     case PROP_MENU_UI:
482         hildon_appview_set_menu_ui (appview, g_value_get_string (value));
483         break;
484     
485     default:
486         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
487         break;
488     }
489 }
490
491 /*
492  * An accessor to get private properties of HildonAppView.
493  */
494 static void hildon_appview_get_property(GObject * object, guint property_id,
495                                     GValue * value, GParamSpec * pspec)
496 {
497     HildonAppViewPrivate *priv = HILDON_APPVIEW_GET_PRIVATE(object);
498
499     switch (property_id) {
500     case PROP_CONNECTED_ADJUSTMENT:
501         g_value_set_object (value, priv->connected_adjustment);
502         break;
503
504     case PROP_FULLSCREEN_KEY_ALLOWED:
505         g_value_set_boolean (value, priv->fullscreenshortcutallowed);
506         break;
507
508     case PROP_FULLSCREEN:
509         g_value_set_boolean (value, priv->fullscreen);
510         break;
511
512     case PROP_TITLE:
513         g_value_set_string (value, priv->title);
514         break;
515
516     case PROP_MENU_UI:
517         g_value_set_string (value, priv->menu_ui);
518         break;
519         
520     default:
521         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
522         break;
523     }
524 }
525
526 /*
527  * Used when the HildonAppView is exposed, this function gets a GtkBoxChild
528  * as first argument, and a pointer to a gint as second argument. If such
529  * GtkBoxChild is visible, the function increments the gint. It is used
530  * in a loop, to compute the number of visible toolbars.
531  */
532 static void visible_toolbar(gpointer child, gpointer number_of_visible_toolbars) 
533 {
534     if(GTK_WIDGET_VISIBLE(((GtkBoxChild *)child)->widget))
535       (*((gint *)number_of_visible_toolbars))++;
536 }
537
538 /*
539  * Used in the paint_toolbar function to discover how many toolbars are
540  * above the find toolbar. It's called in a loop that iterates through
541  * all the children of the GtkVBox of the HildonAppView.
542  */
543 static void find_findtoolbar_index(gpointer child, gpointer number_of_visible_toolbars)
544 {
545     gint *pass_bundle = (gint *)number_of_visible_toolbars;
546     
547     if(((GtkBoxChild *)child)->widget->allocation.y < pass_bundle[0]
548        && GTK_WIDGET_VISIBLE(((GtkBoxChild *)child)->widget))
549         pass_bundle[1]++;
550 }
551
552 /*
553  * Used in the paint_toolbar function, it's get a GtkBoxChild as first argument
554  * and a pointer to a GtkWidget as the second one, which will be addressed to
555  * the find toolbar widget, if it is contained in the given GtkBoxChild.
556  */
557 static void find_findtoolbar(gpointer child, gpointer widget)
558 {
559     if(HILDON_IS_FIND_TOOLBAR(((GtkBoxChild *)child)->widget)
560        && GTK_WIDGET_VISIBLE(((GtkBoxChild *)child)->widget))
561         (*((GtkWidget **)widget)) = ((GtkBoxChild *)child)->widget;
562 }
563
564 /*
565  * Paints all the toolbar children of the GtkVBox of the HildonAppView.
566  */
567 static void paint_toolbar(GtkWidget *widget, GtkBox *box, 
568                           GdkEventExpose * event, 
569                           gboolean fullscreen)
570 {
571     gint toolbar_num = 0; 
572     gint ftb_index = 0;
573     gint count;
574     GtkWidget *findtoolbar = NULL;
575     gchar toolbar_mode[40];
576
577     /* Iterate through all the children of the vbox of the HildonAppView.
578      * The visible_toolbar function increments toolbar_num if the toolbar
579      * is visible. After this loop, toobar_num will contain the number
580      * of the visible toolbars. */
581     g_list_foreach(box->children, visible_toolbar, 
582                    (gpointer) &toolbar_num);
583     if(toolbar_num <= 0)
584       return;
585
586     /* Loop through all the children of the GtkVBox of the HildonAppView.
587      * The find_findtoolbar function will assign a pointer to the find toolbar
588      * to "findtoolbar" argument. If the findtoolbar is not found, i.e. it
589      * isn't in the GtkVBox, then the "findtoolbar" argument will stay NULL */
590     g_list_foreach(box->children, find_findtoolbar, 
591                    (gpointer) &findtoolbar);
592     if(findtoolbar != NULL){
593         gint pass_bundle[2];
594         
595         /* an array for convient data passing
596          * the first member contains the y allocation
597          * of the find toolbar, and the second allocation
598          * contains the index(how many toolbars are above
599          * find toolbar) */
600         pass_bundle[0] = findtoolbar->allocation.y;
601         pass_bundle[1] = ftb_index;
602
603         /* computes how many toolbars are above the find toolbar, and the
604          * value is stored in pass_bundle[1] */
605         g_list_foreach(box->children, find_findtoolbar_index,
606                        (gpointer) pass_bundle);
607         ftb_index = pass_bundle[1];
608     }
609     /*upper border*/
610     sprintf(toolbar_mode, "toolbar%sframe-top", 
611             fullscreen ? "-fullscreen-" : "-");
612     gtk_paint_box(widget->style, widget->window,
613                   GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
614                   &event->area, widget, toolbar_mode,
615                   widget->allocation.x,
616                   GTK_WIDGET(box)->allocation.y -TOOLBAR_UP,
617                   widget->allocation.width, TOOLBAR_UP);
618     
619     /*top most toolbar painting*/
620     if(findtoolbar != NULL && ftb_index == 0 )
621     {
622         sprintf(toolbar_mode, "findtoolbar%s", 
623                 fullscreen ? "-fullscreen" : "");
624         
625         gtk_paint_box(widget->style, widget->window,
626                       GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
627                       &event->area, widget, toolbar_mode,
628                       widget->allocation.x,
629                       GTK_WIDGET(box)->allocation.y,
630                       widget->allocation.width,
631                       TOOLBAR_HEIGHT);
632     }else{
633         sprintf(toolbar_mode, "toolbar%s", 
634                 fullscreen ? "-fullscreen" : "");
635         gtk_paint_box(widget->style, widget->window,
636                       GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
637                       &event->area, widget, toolbar_mode,
638                       widget->allocation.x,
639                       GTK_WIDGET(box)->allocation.y,
640                       widget->allocation.width,
641                       TOOLBAR_HEIGHT);
642     }
643     /*multi toolbar painting*/
644     for(count = 0; count < toolbar_num - 1; count++)
645     {
646         sprintf(toolbar_mode, "toolbar%sframe-middle", 
647                 fullscreen ? "-fullscreen-" : "-");
648         
649         gtk_paint_box(widget->style, widget->window,
650                   GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
651                   &event->area, widget, toolbar_mode,
652                   widget->allocation.x,
653                   GTK_WIDGET(box)->allocation.y + 
654                   (1 + count) * TOOLBAR_HEIGHT + 
655                   count * TOOLBAR_MIDDLE,
656                   widget->allocation.width,
657                   TOOLBAR_MIDDLE);
658
659         if(findtoolbar != NULL && count + 1 == ftb_index){
660             sprintf(toolbar_mode, "findtoolbar%s", 
661                     fullscreen ? "-fullscreen" : "");
662             
663             gtk_paint_box(widget->style, widget->window,
664                       GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
665                       &event->area, widget, toolbar_mode,
666                       widget->allocation.x,
667                       GTK_WIDGET(box)->allocation.y + 
668                       (1 + count) * (TOOLBAR_HEIGHT + TOOLBAR_MIDDLE),
669                       widget->allocation.width,
670                       TOOLBAR_HEIGHT);
671         }else{
672             sprintf(toolbar_mode, "toolbar%s", 
673                     fullscreen ? "-fullscreen" : "");
674             
675             gtk_paint_box(widget->style, widget->window,
676                       GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
677                       &event->area, widget, toolbar_mode,
678                       widget->allocation.x,
679                       GTK_WIDGET(box)->allocation.y + 
680                       (1 + count) * (TOOLBAR_HEIGHT + TOOLBAR_MIDDLE),
681                       widget->allocation.width,
682                       TOOLBAR_HEIGHT);
683         }
684     }
685     sprintf(toolbar_mode, "toolbar%sframe-bottom", 
686             fullscreen ? "-fullscreen-" : "-");
687     
688     gtk_paint_box(widget->style, widget->window,
689                   GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
690                   &event->area, widget, toolbar_mode,
691                   widget->allocation.x,
692                   GTK_WIDGET(box)->allocation.y + 
693                   GTK_WIDGET(box)->allocation.height,
694                   widget->allocation.width, TOOLBAR_DOWN);
695 }
696
697 /*
698  * Callback function to an expose event.
699  */
700 static gboolean hildon_appview_expose(GtkWidget * widget,
701                                       GdkEventExpose * event)
702 {
703     gint toolbar_num = 0;
704     GtkBox *box = GTK_BOX(HILDON_APPVIEW(widget)->vbox);
705
706     if(GTK_WIDGET_VISIBLE(box) && box->children != NULL)
707     {
708         HildonAppViewPrivate *priv = HILDON_APPVIEW_GET_PRIVATE(widget);
709
710         /* Iterate through all the children of the vbox of the HildonAppView.
711          * The visible_toolbar function increments toolbar_num if the toolbar
712          * is visible. After this loop, toobar_num will contain the number
713          * of the visible toolbars. */
714         g_list_foreach(box->children, visible_toolbar, 
715                 (gpointer) &toolbar_num);
716
717         if( priv->visible_toolbars != toolbar_num)
718         {
719             /* If the code reaches this block, it means that a toolbar as 
720              * been added or removed since last time the view was drawn.
721              * Let's then compute the new height of the toolbars areas */
722             gint y_pos = 0;
723             /* the height difference */
724             gint change = (priv->visible_toolbars - toolbar_num) *
725                 (TOOLBAR_HEIGHT+TOOLBAR_MIDDLE+TOOLBAR_UP);
726             if( change < 0 )
727                 change = TOOLBAR_MIDDLE + TOOLBAR_UP;
728             /* the new y-coordinate for the toolbars area */
729             y_pos = HILDON_APPVIEW(widget)->vbox->allocation.y - change;
730
731             gtk_widget_queue_draw_area(widget, 0, y_pos, widget->allocation.width,
732                     change + HILDON_APPVIEW(widget)->vbox->allocation.height +
733                     TOOLBAR_DOWN);
734             priv->visible_toolbars = toolbar_num;
735         }
736     }
737
738
739     if (HILDON_APPVIEW(widget)->priv->fullscreen)
740     {
741         if (toolbar_num > 0)
742             paint_toolbar(widget, box, event, TRUE);
743     }
744     else
745     {
746         gint appview_height_decrement = 0;
747         if (toolbar_num > 0)
748         {
749             appview_height_decrement = toolbar_num * TOOLBAR_HEIGHT +
750                 (toolbar_num - 1) * TOOLBAR_MIDDLE 
751                 + TOOLBAR_UP + TOOLBAR_DOWN;
752
753             paint_toolbar(widget, box, event, FALSE);
754         }
755         else
756         {
757             appview_height_decrement = MARGIN_APPVIEW_BOTTOM;
758
759             gtk_paint_box(widget->style, widget->window,
760                     GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
761                     &event->area, widget, "bottom-border",
762                     widget->allocation.x,
763                     widget->allocation.y +
764                     (widget->allocation.height - MARGIN_APPVIEW_BOTTOM),
765                     widget->allocation.width, MARGIN_APPVIEW_BOTTOM);
766         }
767         gtk_paint_box( widget->style, widget->window,
768                 GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT, 
769                 &event->area,
770                 widget, "left-border", widget->allocation.x,
771                 widget->allocation.y, MARGIN_APPVIEW_LEFT,
772                 widget->allocation.height - appview_height_decrement );
773         gtk_paint_box( widget->style, widget->window,
774                 GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT, 
775                 &event->area,
776                 widget, "right-border",
777                 (widget->allocation.x +
778                  widget->allocation.width) -
779                 MARGIN_APPVIEW_RIGHT, widget->allocation.y,
780                 MARGIN_APPVIEW_RIGHT,
781                 widget->allocation.height - appview_height_decrement );
782     }
783
784     GTK_WIDGET_CLASS(parent_class)->expose_event(widget, event);
785
786     return FALSE;
787 }
788
789 /*
790  * Responds to the usual size_request signal.
791  */
792 static void hildon_appview_size_request(GtkWidget * widget,
793                                         GtkRequisition * requisition)
794 {
795     HildonAppViewPrivate *priv = HILDON_APPVIEW(widget)->priv;
796     GtkWidget *child = GTK_BIN(widget)->child;
797
798     /* forward the size_request to the eventual child of the main container */
799     if (child)
800         gtk_widget_size_request(child, requisition);
801
802     /* forward the size_request to the eventual vbox (which may contain
803      * toolbars) */
804     if (HILDON_APPVIEW(widget)->vbox != NULL)
805         gtk_widget_size_request(HILDON_APPVIEW(widget)->vbox, requisition);
806
807     /* express the size_request for the view */
808     if (priv->fullscreen) {
809         requisition->height = WINDOW_HEIGHT;
810         requisition->width = WINDOW_WIDTH;
811     } else {
812         requisition->height = APPVIEW_HEIGHT;
813         requisition->width = APPVIEW_WIDTH;
814     }
815 }
816
817 /*
818  * Computes size and position for the children of the view.
819  */
820 static void hildon_appview_size_allocate(GtkWidget * widget,
821                                          GtkAllocation * allocation)
822 {
823     GtkAllocation box_allocation;
824     GtkAllocation alloc = *allocation;
825     gint border_width = GTK_CONTAINER(widget)->border_width;
826     GtkBin *bin = GTK_BIN(widget);
827     GtkBox *box = GTK_BOX(HILDON_APPVIEW(widget)->vbox);
828     gboolean at_least_one_visible_toolbar = FALSE;
829
830     if(!GTK_IS_WIDGET(bin->child)) return;
831
832     widget->allocation = *allocation;
833     
834     if (bin->child != NULL && GTK_IS_WIDGET(bin->child)) {
835         if (HILDON_APPVIEW(widget)->priv->fullscreen) {
836             alloc.x += border_width;
837             alloc.y += border_width;
838             alloc.width -= (border_width * 2);
839             alloc.height -= (border_width * 2);
840         } else {
841             alloc.x += border_width + MARGIN_APPVIEW_LEFT;
842             alloc.y += border_width + MARGIN_APPVIEW_TOP;
843             alloc.width -= (border_width * 2) + (MARGIN_APPVIEW_LEFT +
844                                       MARGIN_APPVIEW_RIGHT);
845             alloc.height -= (border_width * 2) + MARGIN_APPVIEW_TOP;
846         }
847     }
848
849     if (box->children != NULL) {
850         gint length = 0;
851         gint box_height = 0;
852         /* Iterate through all the children of the vbox of the HildonAppView.
853          * The visible_toolbar function increments toolbar_num if the toolbar
854          * is visible. After this loop, toobar_num will contain the number
855          * of the visible toolbars. */
856         g_list_foreach(box->children, visible_toolbar, 
857                      (gpointer) &length);
858         if(length > 0){
859             box_height = length * TOOLBAR_HEIGHT + 
860               (length - 1) * TOOLBAR_MIDDLE;
861        
862             if(bin->child != NULL) {
863                 alloc.height = alloc.height - box_height - TOOLBAR_UP
864                   - TOOLBAR_DOWN;
865                 at_least_one_visible_toolbar = TRUE;
866             }
867         
868             box_allocation.y = allocation->height - box_height - TOOLBAR_DOWN;
869             box_allocation.height = box_height;
870             box_allocation.x = allocation->x + TOOLBAR_LEFT;
871             box_allocation.width = allocation->width - TOOLBAR_LEFT - 
872               TOOLBAR_RIGHT;
873             gtk_widget_size_allocate(GTK_WIDGET(box), &box_allocation);
874         }
875     }
876     
877     /* The bottom skin graphics is visible only when there are no toolbars */
878     if ((HILDON_APPVIEW(widget)->priv->fullscreen == FALSE) &&
879         (at_least_one_visible_toolbar == FALSE))
880         alloc.height -= MARGIN_APPVIEW_BOTTOM;
881     
882     gtk_widget_size_allocate(GTK_WIDGET(bin->child), &alloc);
883 }
884
885 /*
886  * Overrides gtk_container_forall, calling the callback function for each of
887  * the children of HildonAppPrivate.
888  */
889 static void hildon_appview_forall(GtkContainer * container,
890                                   gboolean include_internals,
891                                   GtkCallback callback,
892                                   gpointer callback_data)
893 {
894     HildonAppView *self = HILDON_APPVIEW(container);
895
896     g_assert(callback != NULL);
897
898     GTK_CONTAINER_CLASS(parent_class)->forall(container, include_internals,
899                                               callback, callback_data);
900     if(include_internals && self->vbox != NULL)
901         (* callback)(GTK_WIDGET(self->vbox), callback_data);
902 }
903
904 /**
905  * Shows all the widgets in the container.
906  */
907 static void hildon_appview_show_all(GtkWidget *widget)
908 {
909     HildonAppView *self = HILDON_APPVIEW(widget);
910     
911     /* Toolbar items */
912     gtk_widget_show_all(self->vbox);
913
914     /* Parent handless stuff inside appview */
915     GTK_WIDGET_CLASS(parent_class)->show_all(widget);
916 }
917
918 /*
919  * Frees all the resources and propagates the destroy call to the parent.
920  */
921 static void hildon_appview_destroy(GtkObject *obj)
922 {
923     HildonAppView *self = HILDON_APPVIEW(obj);
924     
925     if(self->vbox != NULL){
926         gtk_widget_unparent(self->vbox);
927         self->vbox = NULL;      
928     }
929
930     GTK_OBJECT_CLASS(parent_class)->destroy(obj);
931 }
932
933 /*******************/
934 /*   Signals       */
935 /*******************/
936
937 /*Signal - When is changed to this appview, this is called*/
938 static void hildon_appview_switched_to(HildonAppView * self)
939 {
940     GtkWidget *parent;
941
942     g_assert(self && HILDON_IS_APPVIEW(self));
943
944     parent = gtk_widget_get_parent(GTK_WIDGET(self));
945     hildon_appview_set_fullscreen( self, self->priv->fullscreen );
946 }
947
948 /*Signal - When the fullscreen state is changed, this is called*/
949 static void hildon_appview_real_fullscreen_state_change(HildonAppView *
950                                                         self,
951                                                         gboolean
952                                                         fullscreen)
953 {
954     HildonAppViewPrivate *priv;
955     g_assert(self && HILDON_IS_APPVIEW(self));
956     priv = self->priv;
957
958     /* Ensure that state is really changed */
959     if( priv->fullscreen == fullscreen )
960       return;
961
962     if( fullscreen )
963       gtk_window_fullscreen( GTK_WINDOW(
964                              gtk_widget_get_parent(GTK_WIDGET(self))) );
965     else
966       gtk_window_unfullscreen( GTK_WINDOW(
967                              gtk_widget_get_parent(GTK_WIDGET(self))) );
968
969     priv->fullscreen = fullscreen;
970 }
971
972 /*******************/
973 /*     General     */
974 /*******************/
975
976
977 /*
978  * queries a window for the root window coordinates and size of its
979  * client area (i.e. minus the title borders etc.)
980  */
981 static void get_client_area(GtkWidget * widget, GtkAllocation * allocation)
982 {
983     GdkWindow *window = widget->window;
984     
985     if (window)
986       gdk_window_get_origin(window, &allocation->x, &allocation->y);
987     else
988       memset( allocation, 0, sizeof(GtkAllocation) );
989 }
990
991 /*The menu popuping needs a menu popup-function*/
992 static void hildon_appview_menupopupfunc( GtkMenu *menu, gint *x, gint *y,
993                                           gboolean *push_in, GtkWidget *widget )
994 {
995   GtkAllocation client_area = { 0, 0, 0, 0 };
996
997   get_client_area( GTK_WIDGET(widget), &client_area );
998
999   gtk_widget_style_get (GTK_WIDGET (menu), "horizontal-offset", x,
1000                         "vertical-offset", y, NULL);
1001    
1002   *x += client_area.x;
1003   *y += client_area.y;
1004   
1005 }
1006
1007 /* Similar to above, but used in fullscreen mode */
1008 static void hildon_appview_menupopupfuncfull( GtkMenu *menu, gint *x, gint *y,
1009                                               gboolean *push_in, 
1010                                               GtkWidget *widget )
1011 {
1012   gtk_widget_style_get (GTK_WIDGET (menu), "horizontal-offset", x,
1013                         "vertical-offset", y, NULL);
1014
1015   *x = MAX (0, *x);
1016   *y = MAX (0, *y);
1017 }
1018
1019 /*******************/
1020 /*public functions*/
1021 /*******************/
1022
1023
1024 /**
1025  * hildon_appview_new: 
1026  * @title: The application view title of the new @HildonAppView.
1027  * 
1028  * Use this function to create a new application view. The title will 
1029  * be set only if two-part-title is enabled on the @HildonApp.
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 vertical 
1047  * scrollbar to it. Similar as adding first a @GtkScrolledWindow 
1048  * and then the @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     /* Check whether child widget supports adjustments */
1065     if (GTK_WIDGET_GET_CLASS (child)->set_scroll_adjustments_signal)
1066         gtk_container_add(GTK_CONTAINER(scrolledw), child);
1067     else
1068     {
1069       if( GTK_IS_CONTAINER(child) )
1070         gtk_container_set_focus_vadjustment( GTK_CONTAINER(child),
1071                               gtk_scrolled_window_get_vadjustment(scrolledw) );
1072         gtk_scrolled_window_add_with_viewport(scrolledw, child);
1073     }
1074
1075     gtk_container_add(GTK_CONTAINER(self), GTK_WIDGET(scrolledw));
1076 }
1077
1078 /**
1079  * hildon_appview_get_title:
1080  * @self : A @HildonAppView
1081  *
1082  * Gets the title of given #HildonAppView.
1083  *
1084  * Return value: The title of the application view.
1085  **/
1086 const gchar *hildon_appview_get_title(HildonAppView * self)
1087 {
1088     g_return_val_if_fail(self && HILDON_IS_APPVIEW(self), "");
1089     return self->priv->title;
1090 }
1091
1092 /**
1093  * hildon_appview_set_title:
1094  * @self : A @HildonAppView
1095  * @newname : The new title of the application view.
1096  * 
1097  * Sets an title of an application view. The title is visible only if
1098  * two-part-title is enabled on the @HildonApp.
1099  * 
1100  **/
1101 void hildon_appview_set_title(HildonAppView * self, const gchar * newname)
1102 {
1103     gchar *oldtitle;
1104
1105     g_return_if_fail(self && HILDON_IS_APPVIEW(self));
1106     oldtitle = self->priv->title;
1107
1108     if (newname != NULL)
1109         self->priv->title = g_strdup(newname);
1110     else
1111         self->priv->title = g_strdup("");
1112
1113     g_free(oldtitle);
1114     g_signal_emit_by_name(G_OBJECT(self), "title_change");
1115 }
1116
1117 /**
1118  * hildon_appview_set_toolbar:
1119  * @self: A #HildonAppView
1120  * @toolbar: A #GtkToolbar
1121  *
1122  * Sets the #GtkToolbar to given #HildonAppView. This is, however, not a recommned way to
1123  * set your toolbars. When you have multi toolbars, calling this function more than once will just
1124  * replace the bottom most toolbar. There is a #GtkVBox in #HildonAppView's public structure, the programmer
1125  * is responsible to pack his toolbars in the #GtkVBox, and #HildonAppView will take care of put them at the
1126  * right place.
1127  * 
1128  **/
1129 #ifndef HILDON_DISABLE_DEPRECATED
1130 void hildon_appview_set_toolbar(HildonAppView * self, GtkToolbar * toolbar)
1131 {
1132     GtkBox *box = GTK_BOX(HILDON_APPVIEW(self)->vbox);
1133     g_return_if_fail(self && HILDON_IS_APPVIEW(self));
1134     if(toolbar != NULL)/*for failure checking*/
1135         g_return_if_fail(GTK_IS_TOOLBAR(toolbar));
1136     
1137     /*if it is NULL, it unsets the last one, 
1138      * if it is not null, it unsets the last one anyway*/
1139     if(box->children != NULL){
1140         GtkWidget *last_widget;
1141         
1142         last_widget = ((GtkBoxChild *)g_list_last
1143                        (box->children)->data)->widget;
1144         gtk_container_remove(GTK_CONTAINER(box), 
1145                              last_widget);
1146     }
1147     
1148     gtk_box_pack_end(box, GTK_WIDGET(toolbar), TRUE, TRUE, 0);
1149     gtk_widget_queue_resize(GTK_WIDGET(self));
1150     /*deprecated signal*/
1151     g_signal_emit_by_name(G_OBJECT(self), "toolbar-changed");
1152 }
1153 #endif
1154 /**
1155  * hildon_appview_get_toolbar:
1156  * @self: A #HildonAppView
1157  *
1158  * This function will only 
1159  * return the last widget that has been packed into the #GtkVBox in the public structure. Note
1160  * this does not, however, mean that it is the bottom most toolbar.
1161  * 
1162  * Return value: The #GtkToolbar assigned to this application view. 
1163  **/
1164 #ifndef HILDON_DISABLE_DEPRECATED
1165 GtkToolbar *hildon_appview_get_toolbar(HildonAppView * self)
1166 {
1167     GtkBox *box = GTK_BOX(HILDON_APPVIEW(self)->vbox);
1168     g_return_val_if_fail(self != NULL && HILDON_IS_APPVIEW(self), FALSE);
1169     if(box != NULL && box->children != NULL)
1170       return GTK_TOOLBAR(((GtkBoxChild*)
1171                           g_list_last(box->children)->data)->widget);
1172     else
1173       return NULL;
1174 }
1175 #endif
1176 /**
1177  * hildon_appview_set_fullscreen:
1178  * @self: A @HildonAppView
1179  * @fullscreen: The new state of fullscreen mode. TRUE means fullscreen
1180  * will be set. FALSE the opposite.
1181  * 
1182  * Set the fullscreen state of given #HildonAppView class.
1183  **/
1184 void hildon_appview_set_fullscreen(HildonAppView * self,
1185                                    gboolean fullscreen)
1186 {
1187     g_return_if_fail(self && HILDON_IS_APPVIEW(self));
1188     g_signal_emit_by_name(G_OBJECT(self), "fullscreen_state_change",
1189                           fullscreen);
1190 }
1191
1192 /**
1193  * hildon_appview_get_fullscreen:
1194  * @self: A @HildonAppView
1195  *
1196  * Gets the current state of fullscreen mode.
1197  * 
1198  * Return value: The current state of fullscreen mode.
1199  **/
1200 gboolean hildon_appview_get_fullscreen(HildonAppView * self)
1201 {
1202     g_return_val_if_fail(self && HILDON_IS_APPVIEW(self), FALSE);
1203     return self->priv->fullscreen;
1204 }
1205
1206 /**
1207  * hildon_appview_get_fullscreen_key_allowed:
1208  * @self: A @HildonAppView
1209  *
1210  * Check if fullscreening with a shortcut is allowed for given
1211  * #HildonAppView.
1212  * 
1213  * Return value: Wheter it's possible to swith fullscreen on/off with
1214  *               a shortcut key.
1215  **/
1216 gboolean hildon_appview_get_fullscreen_key_allowed(HildonAppView * self)
1217 {
1218     g_return_val_if_fail(self && HILDON_IS_APPVIEW(self), FALSE);
1219     return self->priv->fullscreenshortcutallowed;
1220 }
1221
1222 /**
1223  * hildon_appview_set_fullscreen_key_allowed:
1224  * @self: A @HildonAppView
1225  * @allow: Wheter it's possible to swith fullscreen on/off with
1226  *               a shortcut key.
1227  *
1228  * Sets given #HildonAppView whether to allow toggling fullscreen mode
1229  * with a shortcut key.
1230  **/
1231 void hildon_appview_set_fullscreen_key_allowed(HildonAppView * self,
1232                                                gboolean allow)
1233 {
1234     g_return_if_fail(self && HILDON_IS_APPVIEW(self));
1235     self->priv->fullscreenshortcutallowed = allow;
1236 }
1237
1238 /**
1239  * hildon_appview_get_menu:
1240  * @self : #HildonAppView
1241  * 
1242  * Gets the #GtMenu assigned to the #HildonAppview.
1243  *
1244  * Return value: The #GtkMenu assigned to this application view.
1245  **/
1246 GtkMenu *hildon_appview_get_menu(HildonAppView * self)
1247 {
1248     g_return_val_if_fail(self && HILDON_IS_APPVIEW(self), NULL);
1249
1250     if (self->priv->menu == NULL) {
1251         /* Create hildonlike menu */
1252         
1253         GtkUIManager *uim;
1254         GtkWidget *parent = gtk_widget_get_parent (GTK_WIDGET (self));
1255
1256         /* Try to get appview menu from ui manager */        
1257         if (parent && HILDON_IS_APP (parent))
1258           {
1259             uim = hildon_app_get_ui_manager (HILDON_APP (parent));
1260             if (uim)
1261               {
1262                 self->priv->menu =
1263                   gtk_ui_manager_get_widget (uim, "/HildonApp");
1264               }
1265           }
1266         
1267         
1268         if (self->priv->menu == NULL)
1269           {
1270             /* Fall back to oldskool menus */
1271             self->priv->menu = GTK_WIDGET (g_object_new (GTK_TYPE_MENU, NULL));
1272           }  
1273           
1274         gtk_widget_set_name(GTK_WIDGET(self->priv->menu),
1275                             "menu_force_with_corners");
1276         gtk_widget_show_all (self->priv->menu);
1277     }
1278
1279     return GTK_MENU(self->priv->menu);
1280 }
1281
1282 /**
1283  * _hildon_appview_toggle_menu:
1284  * @self : A @HildonAppView
1285  * @button_event_time :
1286  *
1287  * This function should be only called from @HildonApp.
1288  * Should be renamed to popup menu. Just the first parameter is used.
1289  */
1290 void _hildon_appview_toggle_menu(HildonAppView * self,
1291                                  Time button_event_time)
1292 {
1293     GList *children;
1294
1295     g_return_if_fail(self && HILDON_IS_APPVIEW(self));
1296
1297     if (!self->priv->menu)
1298         return;
1299
1300     if (GTK_WIDGET_VISIBLE(self->priv->menu)) {
1301         gtk_menu_popdown(GTK_MENU(self->priv->menu));
1302         gtk_menu_shell_deactivate(GTK_MENU_SHELL(self->priv->menu));
1303         return;
1304     }
1305
1306     /* Avoid opening an empty menu */
1307     children = gtk_container_get_children(
1308                         GTK_CONTAINER(hildon_appview_get_menu(self)));
1309     if (children != NULL) {
1310         GtkWidget *menu;
1311
1312         g_list_free(children);
1313         menu = GTK_WIDGET(hildon_appview_get_menu(self));
1314         if (self->priv->fullscreen) {
1315             gtk_menu_popup(GTK_MENU(menu), NULL, NULL,
1316                            (GtkMenuPositionFunc)
1317                            hildon_appview_menupopupfuncfull,
1318                            self, 0, button_event_time);
1319         } else {
1320             gtk_menu_popup(GTK_MENU(menu), NULL, NULL,
1321                            (GtkMenuPositionFunc)
1322                            hildon_appview_menupopupfunc,
1323                            self, 0, button_event_time);
1324         }
1325         gtk_menu_shell_select_first(GTK_MENU_SHELL(menu), TRUE);
1326     }
1327
1328 }
1329
1330 /**
1331  * _hildon_appview_menu_visible
1332  * @self :  A @HildonAppView
1333  * 
1334  * Checks whether the titlebar menu is currently visible
1335  * Return value : TRUE if the menu is visible, FALSE if not.
1336  */
1337
1338 gboolean _hildon_appview_menu_visible(HildonAppView * self)
1339 {
1340     g_return_val_if_fail (HILDON_IS_APPVIEW (self), FALSE);
1341     
1342     return GTK_WIDGET_VISIBLE(GTK_WIDGET(hildon_appview_get_menu(self)));
1343 }
1344
1345 /**
1346  * hildon_appview_set_connected_adjustment
1347  * @self : A @HildonAppView
1348  * @adjustment : A new #GtkAdjustment set to reach to increase
1349  *   / decrease hardware keys or NULL to unset.
1350  * 
1351  * Sets a #GtkAdjustment which will change when increase/decrease buttons
1352  * are pressed.
1353  **/
1354 void hildon_appview_set_connected_adjustment (HildonAppView * self,
1355                                               GtkAdjustment * adjustment)
1356 {
1357     g_return_if_fail (HILDON_IS_APPVIEW (self));
1358
1359     /* Disconnect old adjustment */
1360     if (self->priv->connected_adjustment != NULL)
1361       g_object_remove_weak_pointer (G_OBJECT (self->priv->connected_adjustment),
1362                                     (gpointer) &self->priv->connected_adjustment);
1363
1364     /* Start using the new one */
1365     self->priv->connected_adjustment = adjustment;
1366     if (self->priv->connected_adjustment != NULL)
1367         g_object_add_weak_pointer (G_OBJECT (self->priv->connected_adjustment),
1368                                    (gpointer) &self->priv->connected_adjustment);
1369 }
1370
1371 /**
1372  * hildon_appview_get_connected_adjustment
1373  * @self : A @HildonAppView
1374  * 
1375  * Retrieves the @GtkAdjustment which is connected to this application view
1376  * and is changed with increase / decrease hardware buttons.
1377  *
1378  * Return value: Currently connectd #GtkAdjustment assigned to this
1379  *               application view or NULL if it's not set.
1380  **/
1381 GtkAdjustment * hildon_appview_get_connected_adjustment (HildonAppView * self)
1382 {
1383     g_return_val_if_fail (HILDON_IS_APPVIEW (self), NULL);
1384    
1385     return self->priv->connected_adjustment;
1386 }
1387
1388
1389 /**
1390  * hildon_appview_set_menu_ui
1391  * @self : A @HildonAppView
1392  * @ui_string : A @GtkUIManager ui description string
1393  *
1394  * Sets the ui description (xml) from which the UIManager creates menus
1395  * (see @GtkUIManager for details on how to use it)
1396  **/
1397 void hildon_appview_set_menu_ui(HildonAppView *self, const gchar *ui_string)
1398 {
1399   g_return_if_fail (HILDON_IS_APPVIEW (self));
1400   
1401   if (ui_string)
1402     {
1403       if (self->priv->menu_ui)
1404         g_free (self->priv->menu_ui);
1405       
1406       self->priv->menu_ui = g_strdup (ui_string);
1407
1408       /* FIXME: We should update the menu here, preferrably by a
1409        * hildon_app_ensure_menu_update() which re-installs the menu ui
1410        * and calls gtk_ui_manager_ensure_update()
1411        */
1412     }
1413   else
1414     {
1415       /* Reset the UI */
1416       if (self->priv->menu_ui)
1417         {
1418           g_free (self->priv->menu_ui);
1419           self->priv->menu_ui = NULL;
1420         }
1421     }
1422
1423     g_object_notify (G_OBJECT(self), "menu-ui");
1424 }
1425
1426 /**
1427  * hildon_appview_get_menu_ui
1428  * @self : A @HildonAppView
1429  *
1430  * Sets the ui description (xml) from which the UIManager creates menus
1431  * (see @GtkUIManager for details on how to use it)
1432  *
1433  * Return value: Currently set ui description
1434  * 
1435  **/
1436 const gchar *hildon_appview_get_menu_ui(HildonAppView *self)
1437 {
1438   g_return_val_if_fail (HILDON_IS_APPVIEW (self), NULL);
1439
1440   return (self->priv->menu_ui);
1441
1442 }
1443
1444 /* Called when '+' hardkey is pressed/released */
1445 void _hildon_appview_increase_button_state_changed (HildonAppView * self,
1446                                                     guint newkeytype)
1447 {
1448   self->priv->increase_button_pressed_down = newkeytype;
1449
1450   /* Transform '+' press into adjustment update (usually scrollbar move) */
1451   if ((self->priv->connected_adjustment != NULL) && (newkeytype == GDK_KEY_PRESS))
1452     {
1453       gfloat clampedvalue = CLAMP (gtk_adjustment_get_value (self->priv->connected_adjustment) + self->priv->connected_adjustment->step_increment,
1454                                    self->priv->connected_adjustment->lower,
1455                                    self->priv->connected_adjustment->upper - self->priv->connected_adjustment->page_size);
1456       gtk_adjustment_set_value (self->priv->connected_adjustment, clampedvalue);                                
1457     }   
1458
1459   g_signal_emit (G_OBJECT (self), appview_signals[INCREASE_BUTTON_EVENT], 0, newkeytype);
1460 }
1461
1462 /* Called when '-' hardkey is pressed/released */
1463 void _hildon_appview_decrease_button_state_changed (HildonAppView * self,
1464                                                     guint newkeytype)
1465 {
1466   self->priv->decrease_button_pressed_down = newkeytype;
1467
1468   /* Transform '-' press into adjustment update (usually scrollbar move) */
1469   if ((self->priv->connected_adjustment != NULL) && (newkeytype == GDK_KEY_PRESS))
1470     {
1471       gfloat clampedvalue = CLAMP (gtk_adjustment_get_value (self->priv->connected_adjustment) - self->priv->connected_adjustment->step_increment,
1472                                    self->priv->connected_adjustment->lower,
1473                                    self->priv->connected_adjustment->upper - self->priv->connected_adjustment->page_size);
1474       gtk_adjustment_set_value (self->priv->connected_adjustment, clampedvalue);                                
1475     }
1476
1477   g_signal_emit (G_OBJECT (self), appview_signals[DECREASE_BUTTON_EVENT], 0, newkeytype);
1478 }