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