2 * This file is part of hildon-libs
4 * Copyright (C) 2005 Nokia Corporation.
6 * Contact: Luc Pionchon <luc.pionchon@nokia.com>
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.
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.
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
30 #include "hildon-app.h"
31 #include <hildon-appview.h>
32 #include <hildon-find-toolbar.h>
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>
49 #include <gdk/gdkkeysyms.h>
54 #include <X11/Xatom.h>
58 #define _(String) gettext(String)
62 PROP_CONNECTED_ADJUSTMENT,
63 PROP_FULLSCREEN_KEY_ALLOWED,
69 /*The size of screen*/
70 #define WINDOW_HEIGHT 480
71 #define WINDOW_WIDTH 800
73 #define NAVIGATOR_HEIGHT WINDOW_HEIGHT
75 #define APPVIEW_HEIGHT 396
76 #define APPVIEW_WIDTH 672
78 #define TOOLBAR_HEIGHT 40
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
86 #define WORKAREA_ATOM "_NET_WORKAREA"
88 /* Non atom defines */
89 #define _NET_WM_STATE_REMOVE 0 /* remove/unset property */
90 #define _NET_WM_STATE_ADD 1 /* add/set property */
93 * These margins are set to be 5pixels smaller than in the specs
94 * Inner things are allocation that extra space
97 #define MARGIN_TOOLBAR_TOP 2
98 #define MARGIN_TOOLBAR_BOTTOM 6
99 #define MARGIN_TOOLBAR_LEFT 22
100 #define MARGIN_TOOLBAR_RIGHT 23
102 #define MARGIN_APPVIEW_TOP 0
103 #define MARGIN_APPVIEW_BOTTOM 24
104 #define MARGIN_APPVIEW_LEFT 24
105 #define MARGIN_APPVIEW_RIGHT 24
108 #define HILDON_APPVIEW_GET_PRIVATE(obj) \
109 (G_TYPE_INSTANCE_GET_PRIVATE ((obj),\
110 HILDON_TYPE_APPVIEW, HildonAppViewPrivate))
113 #define DEFAULT_WIDTH 20
114 #define DEFAULT_HEIGHT 28
115 #define BANNER_WIDTH DEFAULT_WIDTH
116 #define BANNER_HEIGHT DEFAULT_HEIGHT
118 static GtkBinClass *parent_class;
120 static void hildon_appview_init(HildonAppView * self);
121 static void hildon_appview_class_init(HildonAppViewClass * appview_class);
123 static void hildon_appview_menupopupfunc(GtkMenu *menu, gint *x, gint *y,
126 static void hildon_appview_menupopupfuncfull(GtkMenu *menu, gint *x, gint *y,
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);
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 *
151 static void hildon_appview_switched_to(HildonAppView * self);
152 static void get_client_area(GtkWidget * widget,
153 GtkAllocation * allocation);
155 typedef void (*HildonAppViewSignal) (HildonAppView *, gint, gpointer);
160 TOOLBAR_TOGGLE_REQUEST,
161 FULLSCREEN_STATE_CHANGE,
165 INCREASE_BUTTON_EVENT,
166 DECREASE_BUTTON_EVENT,
167 HILDON_APPVIEW_LAST_SIGNAL
170 static guint appview_signals[HILDON_APPVIEW_LAST_SIGNAL] = { 0 };
178 struct _HildonAppViewPrivate {
182 GtkAllocation allocation;
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;
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)
205 register HildonAppViewSignal callback;
206 register GCClosure *cc = (GCClosure *) closure;
207 register gpointer data1, data2;
209 g_assert(n_param_values == 2);
211 if (G_CCLOSURE_SWAP_DATA(closure)) {
212 data1 = closure->data;
213 data2 = g_value_peek_pointer(param_values + 0);
215 data1 = g_value_peek_pointer(param_values + 0);
216 data2 = closure->data;
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 */
226 (HildonAppViewSignal) (marshal_data !=
227 NULL ? marshal_data : cc->callback);
229 callback((HildonAppView *) data1,
230 (gint) g_value_get_int(param_values + 1), data2);
233 GType hildon_appview_get_type(void)
235 static GType appview_type = 0;
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),
247 (GInstanceInitFunc) hildon_appview_init,
249 appview_type = g_type_register_static(GTK_TYPE_BIN,
257 * Class initialisation.
259 static void hildon_appview_class_init(HildonAppViewClass * appview_class)
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);
267 /* Set the global parent_class here */
268 parent_class = g_type_class_peek_parent(appview_class);
270 object_class->set_property = hildon_appview_set_property;
271 object_class->get_property = hildon_appview_get_property;
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; */
280 /* now the object stuff */
281 object_class->finalize = hildon_appview_finalize;
283 /* To the container */
284 container_class->forall = hildon_appview_forall;
287 GTK_OBJECT_CLASS(appview_class)->destroy = hildon_appview_destroy;
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;
294 g_type_class_add_private(appview_class,
295 sizeof(struct _HildonAppViewPrivate));
298 appview_signals[TOOLBAR_CHANGED] =
299 g_signal_new("toolbar-changed",
300 G_OBJECT_CLASS_TYPE(object_class),
302 G_STRUCT_OFFSET(HildonAppViewClass, toolbar_changed),
304 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
306 appview_signals[TOOLBAR_TOGGLE_REQUEST] =
307 g_signal_new("toolbar-toggle-request",
308 G_OBJECT_CLASS_TYPE(object_class),
310 G_STRUCT_OFFSET(HildonAppViewClass,
311 toolbar_toggle_request), NULL, NULL,
312 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
314 appview_signals[FULLSCREEN_STATE_CHANGE] =
315 g_signal_new("fullscreen_state_change",
316 G_OBJECT_CLASS_TYPE(object_class),
318 G_STRUCT_OFFSET(HildonAppViewClass,
319 fullscreen_state_change), NULL, NULL,
320 hildon_appview_signal_marshal, G_TYPE_NONE, 1,
323 appview_signals[TITLE_CHANGE] =
324 g_signal_new("title_change",
325 G_OBJECT_CLASS_TYPE(object_class),
327 G_STRUCT_OFFSET(HildonAppViewClass, title_change),
329 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
331 appview_signals[SWITCHED_TO] =
332 g_signal_new("switched_to",
333 G_OBJECT_CLASS_TYPE(object_class),
335 G_STRUCT_OFFSET(HildonAppViewClass, switched_to),
337 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
339 appview_signals[SWITCHED_FROM] =
340 g_signal_new("switched_from",
341 G_OBJECT_CLASS_TYPE(object_class),
343 G_STRUCT_OFFSET(HildonAppViewClass, switched_from),
345 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
347 appview_signals[INCREASE_BUTTON_EVENT] =
348 g_signal_new("increase_button_event",
349 G_OBJECT_CLASS_TYPE(object_class),
351 G_STRUCT_OFFSET(HildonAppViewClass, increase_button_event),
353 g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1,
356 appview_signals[DECREASE_BUTTON_EVENT] =
357 g_signal_new("decrease_button_event",
358 G_OBJECT_CLASS_TYPE(object_class),
360 G_STRUCT_OFFSET(HildonAppViewClass, decrease_button_event),
362 g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1,
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.",
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",
380 g_object_class_install_property(object_class, PROP_FULLSCREEN,
381 g_param_spec_boolean("fullscreen",
383 "Whether the appview should be fullscreen or not",
386 g_object_class_install_property(object_class, PROP_TITLE,
387 g_param_spec_string("title",
392 g_object_class_install_property(object_class, PROP_MENU_UI,
393 g_param_spec_string("menu-ui",
395 "UI string for application view menu",
398 widget_class = (GtkWidgetClass*) appview_class;
402 * Performs the initialisation of the widget.
404 static void hildon_appview_init(HildonAppView * self)
406 HildonAppViewPrivate *priv = self->priv =
407 HILDON_APPVIEW_GET_PRIVATE(self);
409 /* the vbox is used to handle both the view's main body and how many
410 * toolbars as the user wants */
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}
419 gtk_widget_set_parent(self->vbox, GTK_WIDGET(self));
421 priv->visible_toolbars = 0;
423 priv->title = g_strdup("");
425 priv->fullscreen = FALSE;
426 priv->fullscreenshortcutallowed = FALSE;
427 priv->increase_button_pressed_down = FALSE;
428 priv->decrease_button_pressed_down = FALSE;
430 priv->connected_adjustment = NULL;
434 * Performs the standard gtk finalize function, freeing allocated
435 * memory and propagating the finalization to the parent.
437 static void hildon_appview_finalize(GObject * obj_self)
440 g_assert(HILDON_APPVIEW(obj_self));
441 self = HILDON_APPVIEW(obj_self);
443 if (self->priv->menu_ui)
444 g_free (self->priv->menu_ui);
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);
450 if (G_OBJECT_CLASS(parent_class)->finalize)
451 G_OBJECT_CLASS(parent_class)->finalize(obj_self);
453 g_free(self->priv->title);
457 * An accessor to set private properties of HildonAppView.
459 static void hildon_appview_set_property(GObject * object, guint property_id,
460 const GValue * value, GParamSpec * pspec)
462 HildonAppView *appview = HILDON_APPVIEW (object);
464 switch (property_id) {
465 case PROP_CONNECTED_ADJUSTMENT:
466 hildon_appview_set_connected_adjustment (appview, g_value_get_object (value));
469 case PROP_FULLSCREEN_KEY_ALLOWED:
470 hildon_appview_set_fullscreen_key_allowed (appview, g_value_get_boolean (value));
473 case PROP_FULLSCREEN:
474 hildon_appview_set_fullscreen (appview, g_value_get_boolean (value));
478 hildon_appview_set_title (appview, g_value_get_string (value));
482 hildon_appview_set_menu_ui (appview, g_value_get_string (value));
486 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
492 * An accessor to get private properties of HildonAppView.
494 static void hildon_appview_get_property(GObject * object, guint property_id,
495 GValue * value, GParamSpec * pspec)
497 HildonAppViewPrivate *priv = HILDON_APPVIEW_GET_PRIVATE(object);
499 switch (property_id) {
500 case PROP_CONNECTED_ADJUSTMENT:
501 g_value_set_object (value, priv->connected_adjustment);
504 case PROP_FULLSCREEN_KEY_ALLOWED:
505 g_value_set_boolean (value, priv->fullscreenshortcutallowed);
508 case PROP_FULLSCREEN:
509 g_value_set_boolean (value, priv->fullscreen);
513 g_value_set_string (value, priv->title);
517 g_value_set_string (value, priv->menu_ui);
521 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
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.
532 static void visible_toolbar(gpointer child, gpointer number_of_visible_toolbars)
534 if(GTK_WIDGET_VISIBLE(((GtkBoxChild *)child)->widget))
535 (*((gint *)number_of_visible_toolbars))++;
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.
543 static void find_findtoolbar_index(gpointer child, gpointer number_of_visible_toolbars)
545 gint *pass_bundle = (gint *)number_of_visible_toolbars;
547 if(((GtkBoxChild *)child)->widget->allocation.y < pass_bundle[0]
548 && GTK_WIDGET_VISIBLE(((GtkBoxChild *)child)->widget))
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.
557 static void find_findtoolbar(gpointer child, gpointer widget)
559 if(HILDON_IS_FIND_TOOLBAR(((GtkBoxChild *)child)->widget)
560 && GTK_WIDGET_VISIBLE(((GtkBoxChild *)child)->widget))
561 (*((GtkWidget **)widget)) = ((GtkBoxChild *)child)->widget;
565 * Paints all the toolbar children of the GtkVBox of the HildonAppView.
567 static void paint_toolbar(GtkWidget *widget, GtkBox *box,
568 GdkEventExpose * event,
571 gint toolbar_num = 0;
574 GtkWidget *findtoolbar = NULL;
575 gchar toolbar_mode[40];
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);
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){
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
600 pass_bundle[0] = findtoolbar->allocation.y;
601 pass_bundle[1] = ftb_index;
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];
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);
619 /*top most toolbar painting*/
620 if(findtoolbar != NULL && ftb_index == 0 )
622 sprintf(toolbar_mode, "findtoolbar%s",
623 fullscreen ? "-fullscreen" : "");
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,
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,
643 /*multi toolbar painting*/
644 for(count = 0; count < toolbar_num - 1; count++)
646 sprintf(toolbar_mode, "toolbar%sframe-middle",
647 fullscreen ? "-fullscreen-" : "-");
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,
659 if(findtoolbar != NULL && count + 1 == ftb_index){
660 sprintf(toolbar_mode, "findtoolbar%s",
661 fullscreen ? "-fullscreen" : "");
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,
672 sprintf(toolbar_mode, "toolbar%s",
673 fullscreen ? "-fullscreen" : "");
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,
685 sprintf(toolbar_mode, "toolbar%sframe-bottom",
686 fullscreen ? "-fullscreen-" : "-");
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);
698 * Callback function to an expose event.
700 static gboolean hildon_appview_expose(GtkWidget * widget,
701 GdkEventExpose * event)
703 gint toolbar_num = 0;
704 GtkBox *box = GTK_BOX(HILDON_APPVIEW(widget)->vbox);
706 if(GTK_WIDGET_VISIBLE(box) && box->children != NULL)
708 HildonAppViewPrivate *priv = HILDON_APPVIEW_GET_PRIVATE(widget);
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);
717 if( priv->visible_toolbars != toolbar_num)
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 */
723 /* the height difference */
724 gint change = (priv->visible_toolbars - toolbar_num) *
725 (TOOLBAR_HEIGHT+TOOLBAR_MIDDLE+TOOLBAR_UP);
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;
731 gtk_widget_queue_draw_area(widget, 0, y_pos, widget->allocation.width,
732 change + HILDON_APPVIEW(widget)->vbox->allocation.height +
734 priv->visible_toolbars = toolbar_num;
739 if (HILDON_APPVIEW(widget)->priv->fullscreen)
742 paint_toolbar(widget, box, event, TRUE);
746 gint appview_height_decrement = 0;
749 appview_height_decrement = toolbar_num * TOOLBAR_HEIGHT +
750 (toolbar_num - 1) * TOOLBAR_MIDDLE
751 + TOOLBAR_UP + TOOLBAR_DOWN;
753 paint_toolbar(widget, box, event, FALSE);
757 appview_height_decrement = MARGIN_APPVIEW_BOTTOM;
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);
767 gtk_paint_box( widget->style, widget->window,
768 GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
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,
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 );
784 GTK_WIDGET_CLASS(parent_class)->expose_event(widget, event);
790 * Responds to the usual size_request signal.
792 static void hildon_appview_size_request(GtkWidget * widget,
793 GtkRequisition * requisition)
795 HildonAppViewPrivate *priv = HILDON_APPVIEW(widget)->priv;
796 GtkWidget *child = GTK_BIN(widget)->child;
798 /* forward the size_request to the eventual child of the main container */
800 gtk_widget_size_request(child, requisition);
802 /* forward the size_request to the eventual vbox (which may contain
804 if (HILDON_APPVIEW(widget)->vbox != NULL)
805 gtk_widget_size_request(HILDON_APPVIEW(widget)->vbox, requisition);
807 /* express the size_request for the view */
808 if (priv->fullscreen) {
809 requisition->height = WINDOW_HEIGHT;
810 requisition->width = WINDOW_WIDTH;
812 requisition->height = APPVIEW_HEIGHT;
813 requisition->width = APPVIEW_WIDTH;
818 * Computes size and position for the children of the view.
820 static void hildon_appview_size_allocate(GtkWidget * widget,
821 GtkAllocation * allocation)
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;
830 if(!GTK_IS_WIDGET(bin->child)) return;
832 widget->allocation = *allocation;
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);
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;
849 if (box->children != NULL) {
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,
859 box_height = length * TOOLBAR_HEIGHT +
860 (length - 1) * TOOLBAR_MIDDLE;
862 if(bin->child != NULL) {
863 alloc.height = alloc.height - box_height - TOOLBAR_UP
865 at_least_one_visible_toolbar = TRUE;
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 -
873 gtk_widget_size_allocate(GTK_WIDGET(box), &box_allocation);
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;
882 gtk_widget_size_allocate(GTK_WIDGET(bin->child), &alloc);
886 * Overrides gtk_container_forall, calling the callback function for each of
887 * the children of HildonAppPrivate.
889 static void hildon_appview_forall(GtkContainer * container,
890 gboolean include_internals,
891 GtkCallback callback,
892 gpointer callback_data)
894 HildonAppView *self = HILDON_APPVIEW(container);
896 g_assert(callback != NULL);
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);
905 * Shows all the widgets in the container.
907 static void hildon_appview_show_all(GtkWidget *widget)
909 HildonAppView *self = HILDON_APPVIEW(widget);
912 gtk_widget_show_all(self->vbox);
914 /* Parent handless stuff inside appview */
915 GTK_WIDGET_CLASS(parent_class)->show_all(widget);
919 * Frees all the resources and propagates the destroy call to the parent.
921 static void hildon_appview_destroy(GtkObject *obj)
923 HildonAppView *self = HILDON_APPVIEW(obj);
925 if(self->vbox != NULL){
926 gtk_widget_unparent(self->vbox);
930 GTK_OBJECT_CLASS(parent_class)->destroy(obj);
933 /*******************/
935 /*******************/
937 /*Signal - When is changed to this appview, this is called*/
938 static void hildon_appview_switched_to(HildonAppView * self)
942 g_assert(self && HILDON_IS_APPVIEW(self));
944 parent = gtk_widget_get_parent(GTK_WIDGET(self));
945 hildon_appview_set_fullscreen( self, self->priv->fullscreen );
948 /*Signal - When the fullscreen state is changed, this is called*/
949 static void hildon_appview_real_fullscreen_state_change(HildonAppView *
954 HildonAppViewPrivate *priv;
955 g_assert(self && HILDON_IS_APPVIEW(self));
958 /* Ensure that state is really changed */
959 if( priv->fullscreen == fullscreen )
963 gtk_window_fullscreen( GTK_WINDOW(
964 gtk_widget_get_parent(GTK_WIDGET(self))) );
966 gtk_window_unfullscreen( GTK_WINDOW(
967 gtk_widget_get_parent(GTK_WIDGET(self))) );
969 priv->fullscreen = fullscreen;
972 /*******************/
974 /*******************/
978 * queries a window for the root window coordinates and size of its
979 * client area (i.e. minus the title borders etc.)
981 static void get_client_area(GtkWidget * widget, GtkAllocation * allocation)
983 GdkWindow *window = widget->window;
986 gdk_window_get_origin(window, &allocation->x, &allocation->y);
988 memset( allocation, 0, sizeof(GtkAllocation) );
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 )
995 GtkAllocation client_area = { 0, 0, 0, 0 };
997 get_client_area( GTK_WIDGET(widget), &client_area );
999 gtk_widget_style_get (GTK_WIDGET (menu), "horizontal-offset", x,
1000 "vertical-offset", y, NULL);
1002 *x += client_area.x;
1003 *y += client_area.y;
1007 /* Similar to above, but used in fullscreen mode */
1008 static void hildon_appview_menupopupfuncfull( GtkMenu *menu, gint *x, gint *y,
1012 gtk_widget_style_get (GTK_WIDGET (menu), "horizontal-offset", x,
1013 "vertical-offset", y, NULL);
1019 /*******************/
1020 /*public functions*/
1021 /*******************/
1025 * hildon_appview_new:
1026 * @title: The application view title of the new @HildonAppView.
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.
1031 * Return value: A @HildonAppView.
1033 GtkWidget *hildon_appview_new(const gchar * title)
1035 HildonAppView *newappview = g_object_new(HILDON_TYPE_APPVIEW, NULL);
1037 hildon_appview_set_title(newappview, title);
1038 return GTK_WIDGET(newappview);
1042 * hildon_appview_add_with_scrollbar
1043 * @self : A @HildonAppView
1044 * @child : A @GtkWidget
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.
1050 void hildon_appview_add_with_scrollbar(HildonAppView * self,
1053 GtkScrolledWindow *scrolledw;
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);
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);
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);
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);
1075 gtk_container_add(GTK_CONTAINER(self), GTK_WIDGET(scrolledw));
1079 * hildon_appview_get_title:
1080 * @self : A @HildonAppView
1082 * Gets the title of given #HildonAppView.
1084 * Return value: The title of the application view.
1086 const gchar *hildon_appview_get_title(HildonAppView * self)
1088 g_return_val_if_fail(self && HILDON_IS_APPVIEW(self), "");
1089 return self->priv->title;
1093 * hildon_appview_set_title:
1094 * @self : A @HildonAppView
1095 * @newname : The new title of the application view.
1097 * Sets an title of an application view. The title is visible only if
1098 * two-part-title is enabled on the @HildonApp.
1101 void hildon_appview_set_title(HildonAppView * self, const gchar * newname)
1105 g_return_if_fail(self && HILDON_IS_APPVIEW(self));
1106 oldtitle = self->priv->title;
1108 if (newname != NULL)
1109 self->priv->title = g_strdup(newname);
1111 self->priv->title = g_strdup("");
1114 g_signal_emit_by_name(G_OBJECT(self), "title_change");
1118 * hildon_appview_set_toolbar:
1119 * @self: A #HildonAppView
1120 * @toolbar: A #GtkToolbar
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
1129 #ifndef HILDON_DISABLE_DEPRECATED
1130 void hildon_appview_set_toolbar(HildonAppView * self, GtkToolbar * toolbar)
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));
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;
1142 last_widget = ((GtkBoxChild *)g_list_last
1143 (box->children)->data)->widget;
1144 gtk_container_remove(GTK_CONTAINER(box),
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");
1155 * hildon_appview_get_toolbar:
1156 * @self: A #HildonAppView
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.
1162 * Return value: The #GtkToolbar assigned to this application view.
1164 #ifndef HILDON_DISABLE_DEPRECATED
1165 GtkToolbar *hildon_appview_get_toolbar(HildonAppView * self)
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);
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.
1182 * Set the fullscreen state of given #HildonAppView class.
1184 void hildon_appview_set_fullscreen(HildonAppView * self,
1185 gboolean fullscreen)
1187 g_return_if_fail(self && HILDON_IS_APPVIEW(self));
1188 g_signal_emit_by_name(G_OBJECT(self), "fullscreen_state_change",
1193 * hildon_appview_get_fullscreen:
1194 * @self: A @HildonAppView
1196 * Gets the current state of fullscreen mode.
1198 * Return value: The current state of fullscreen mode.
1200 gboolean hildon_appview_get_fullscreen(HildonAppView * self)
1202 g_return_val_if_fail(self && HILDON_IS_APPVIEW(self), FALSE);
1203 return self->priv->fullscreen;
1207 * hildon_appview_get_fullscreen_key_allowed:
1208 * @self: A @HildonAppView
1210 * Check if fullscreening with a shortcut is allowed for given
1213 * Return value: Wheter it's possible to swith fullscreen on/off with
1216 gboolean hildon_appview_get_fullscreen_key_allowed(HildonAppView * self)
1218 g_return_val_if_fail(self && HILDON_IS_APPVIEW(self), FALSE);
1219 return self->priv->fullscreenshortcutallowed;
1223 * hildon_appview_set_fullscreen_key_allowed:
1224 * @self: A @HildonAppView
1225 * @allow: Wheter it's possible to swith fullscreen on/off with
1228 * Sets given #HildonAppView whether to allow toggling fullscreen mode
1229 * with a shortcut key.
1231 void hildon_appview_set_fullscreen_key_allowed(HildonAppView * self,
1234 g_return_if_fail(self && HILDON_IS_APPVIEW(self));
1235 self->priv->fullscreenshortcutallowed = allow;
1239 * hildon_appview_get_menu:
1240 * @self : #HildonAppView
1242 * Gets the #GtMenu assigned to the #HildonAppview.
1244 * Return value: The #GtkMenu assigned to this application view.
1246 GtkMenu *hildon_appview_get_menu(HildonAppView * self)
1248 g_return_val_if_fail(self && HILDON_IS_APPVIEW(self), NULL);
1250 if (self->priv->menu == NULL) {
1251 /* Create hildonlike menu */
1254 GtkWidget *parent = gtk_widget_get_parent (GTK_WIDGET (self));
1256 /* Try to get appview menu from ui manager */
1257 if (parent && HILDON_IS_APP (parent))
1259 uim = hildon_app_get_ui_manager (HILDON_APP (parent));
1263 gtk_ui_manager_get_widget (uim, "/HildonApp");
1268 if (self->priv->menu == NULL)
1270 /* Fall back to oldskool menus */
1271 self->priv->menu = GTK_WIDGET (g_object_new (GTK_TYPE_MENU, NULL));
1274 gtk_widget_set_name(GTK_WIDGET(self->priv->menu),
1275 "menu_force_with_corners");
1276 gtk_widget_show_all (self->priv->menu);
1279 return GTK_MENU(self->priv->menu);
1283 * _hildon_appview_toggle_menu:
1284 * @self : A @HildonAppView
1285 * @button_event_time :
1287 * This function should be only called from @HildonApp.
1288 * Should be renamed to popup menu. Just the first parameter is used.
1290 void _hildon_appview_toggle_menu(HildonAppView * self,
1291 Time button_event_time)
1295 g_return_if_fail(self && HILDON_IS_APPVIEW(self));
1297 if (!self->priv->menu)
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));
1306 /* Avoid opening an empty menu */
1307 children = gtk_container_get_children(
1308 GTK_CONTAINER(hildon_appview_get_menu(self)));
1309 if (children != NULL) {
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);
1320 gtk_menu_popup(GTK_MENU(menu), NULL, NULL,
1321 (GtkMenuPositionFunc)
1322 hildon_appview_menupopupfunc,
1323 self, 0, button_event_time);
1325 gtk_menu_shell_select_first(GTK_MENU_SHELL(menu), TRUE);
1331 * _hildon_appview_menu_visible
1332 * @self : A @HildonAppView
1334 * Checks whether the titlebar menu is currently visible
1335 * Return value : TRUE if the menu is visible, FALSE if not.
1338 gboolean _hildon_appview_menu_visible(HildonAppView * self)
1340 g_return_val_if_fail (HILDON_IS_APPVIEW (self), FALSE);
1342 return GTK_WIDGET_VISIBLE(GTK_WIDGET(hildon_appview_get_menu(self)));
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.
1351 * Sets a #GtkAdjustment which will change when increase/decrease buttons
1354 void hildon_appview_set_connected_adjustment (HildonAppView * self,
1355 GtkAdjustment * adjustment)
1357 g_return_if_fail (HILDON_IS_APPVIEW (self));
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);
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);
1372 * hildon_appview_get_connected_adjustment
1373 * @self : A @HildonAppView
1375 * Retrieves the @GtkAdjustment which is connected to this application view
1376 * and is changed with increase / decrease hardware buttons.
1378 * Return value: Currently connectd #GtkAdjustment assigned to this
1379 * application view or NULL if it's not set.
1381 GtkAdjustment * hildon_appview_get_connected_adjustment (HildonAppView * self)
1383 g_return_val_if_fail (HILDON_IS_APPVIEW (self), NULL);
1385 return self->priv->connected_adjustment;
1390 * hildon_appview_set_menu_ui
1391 * @self : A @HildonAppView
1392 * @ui_string : A @GtkUIManager ui description string
1394 * Sets the ui description (xml) from which the UIManager creates menus
1395 * (see @GtkUIManager for details on how to use it)
1397 void hildon_appview_set_menu_ui(HildonAppView *self, const gchar *ui_string)
1399 g_return_if_fail (HILDON_IS_APPVIEW (self));
1403 if (self->priv->menu_ui)
1404 g_free (self->priv->menu_ui);
1406 self->priv->menu_ui = g_strdup (ui_string);
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()
1416 if (self->priv->menu_ui)
1418 g_free (self->priv->menu_ui);
1419 self->priv->menu_ui = NULL;
1423 g_object_notify (G_OBJECT(self), "menu-ui");
1427 * hildon_appview_get_menu_ui
1428 * @self : A @HildonAppView
1430 * Sets the ui description (xml) from which the UIManager creates menus
1431 * (see @GtkUIManager for details on how to use it)
1433 * Return value: Currently set ui description
1436 const gchar *hildon_appview_get_menu_ui(HildonAppView *self)
1438 g_return_val_if_fail (HILDON_IS_APPVIEW (self), NULL);
1440 return (self->priv->menu_ui);
1444 /* Called when '+' hardkey is pressed/released */
1445 void _hildon_appview_increase_button_state_changed (HildonAppView * self,
1448 self->priv->increase_button_pressed_down = newkeytype;
1450 /* Transform '+' press into adjustment update (usually scrollbar move) */
1451 if ((self->priv->connected_adjustment != NULL) && (newkeytype == GDK_KEY_PRESS))
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);
1459 g_signal_emit (G_OBJECT (self), appview_signals[INCREASE_BUTTON_EVENT], 0, newkeytype);
1462 /* Called when '-' hardkey is pressed/released */
1463 void _hildon_appview_decrease_button_state_changed (HildonAppView * self,
1466 self->priv->decrease_button_pressed_down = newkeytype;
1468 /* Transform '-' press into adjustment update (usually scrollbar move) */
1469 if ((self->priv->connected_adjustment != NULL) && (newkeytype == GDK_KEY_PRESS))
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);
1477 g_signal_emit (G_OBJECT (self), appview_signals[DECREASE_BUTTON_EVENT], 0, newkeytype);