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_return_if_fail(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 /* FIXME: Where does this constant 10 come from */
413 self->vbox = gtk_vbox_new(TRUE, 10);
414 gtk_widget_set_parent(self->vbox, GTK_WIDGET(self));
416 priv->visible_toolbars = 0;
418 priv->title = g_strdup("");
420 priv->fullscreen = FALSE;
421 priv->fullscreenshortcutallowed = FALSE;
422 priv->increase_button_pressed_down = FALSE;
423 priv->decrease_button_pressed_down = FALSE;
425 priv->connected_adjustment = NULL;
429 * Performs the standard gtk finalize function, freeing allocated
430 * memory and propagating the finalization to the parent.
432 static void hildon_appview_finalize(GObject * obj_self)
435 g_return_if_fail(HILDON_APPVIEW(obj_self));
436 self = HILDON_APPVIEW(obj_self);
438 if (self->priv->menu_ui)
439 g_free (self->priv->menu_ui);
441 if (self->priv->connected_adjustment != NULL)
442 g_object_remove_weak_pointer (G_OBJECT (self->priv->connected_adjustment),
443 (gpointer) &self->priv->connected_adjustment);
445 if (G_OBJECT_CLASS(parent_class)->finalize)
446 G_OBJECT_CLASS(parent_class)->finalize(obj_self);
448 g_free(self->priv->title);
452 * An accessor to set private properties of HildonAppView.
454 static void hildon_appview_set_property(GObject * object, guint property_id,
455 const GValue * value, GParamSpec * pspec)
457 HildonAppView *appview = HILDON_APPVIEW (object);
459 switch (property_id) {
460 case PROP_CONNECTED_ADJUSTMENT:
461 hildon_appview_set_connected_adjustment (appview, g_value_get_object (value));
464 case PROP_FULLSCREEN_KEY_ALLOWED:
465 hildon_appview_set_fullscreen_key_allowed (appview, g_value_get_boolean (value));
468 case PROP_FULLSCREEN:
469 hildon_appview_set_fullscreen (appview, g_value_get_boolean (value));
473 hildon_appview_set_title (appview, g_value_get_string (value));
477 hildon_appview_set_menu_ui (appview, g_value_get_string (value));
481 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
487 * An accessor to get private properties of HildonAppView.
489 static void hildon_appview_get_property(GObject * object, guint property_id,
490 GValue * value, GParamSpec * pspec)
492 HildonAppViewPrivate *priv = HILDON_APPVIEW_GET_PRIVATE(object);
494 switch (property_id) {
495 case PROP_CONNECTED_ADJUSTMENT:
496 g_value_set_object (value, priv->connected_adjustment);
499 case PROP_FULLSCREEN_KEY_ALLOWED:
500 g_value_set_boolean (value, priv->fullscreenshortcutallowed);
503 case PROP_FULLSCREEN:
504 g_value_set_boolean (value, priv->fullscreen);
508 g_value_set_string (value, priv->title);
512 g_value_set_string (value, priv->menu_ui);
516 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
522 * Used when the HildonAppView is exposed, this function gets a GtkBoxChild
523 * as first argument, and a pointer to a gint as second argument. If such
524 * GtkBoxChild is visible, the function increments the gint. It is used
525 * in a loop, to compute the number of visible toolbars.
527 static void visible_toolbar(gpointer data, gpointer user_data)
529 if(GTK_WIDGET_VISIBLE(((GtkBoxChild *)data)->widget))
530 (*((gint *)user_data))++;
534 * Used in the paint_toolbar function to discover how many toolbars are
535 * above the find toolbar. It's called in a loop that iterates through
536 * all the children of the GtkVBox of the HildonAppView.
538 static void find_findtoolbar_index(gpointer data, gpointer user_data)
540 gint *pass_bundle = (gint *)user_data;
542 if(((GtkBoxChild *)data)->widget->allocation.y < pass_bundle[0]
543 && GTK_WIDGET_VISIBLE(((GtkBoxChild *)data)->widget))
548 * Used in the paint_toolbar function, it's get a GtkBoxChild as first argument
549 * and a pointer to a GtkWidget as the second one, which will be addressed to
550 * the find toolbar widget, if it is contained in the given GtkBoxChild.
552 static void find_findtoolbar(gpointer data, gpointer user_data)
554 if(HILDON_IS_FIND_TOOLBAR(((GtkBoxChild *)data)->widget)
555 && GTK_WIDGET_VISIBLE(((GtkBoxChild *)data)->widget))
556 (*((GtkWidget **)user_data)) = ((GtkBoxChild *)data)->widget;
560 * Paints all the toolbar children of the GtkVBox of the HildonAppView.
562 static void paint_toolbar(GtkWidget *widget, GtkBox *box,
563 GdkEventExpose * event,
566 gint toolbar_num = 0;
569 GtkWidget *findtoolbar = NULL;
570 gchar toolbar_mode[40];
572 /* Iterate through all the children of the vbox of the HildonAppView.
573 * The visible_toolbar function increments toolbar_num if the toolbar
574 * is visible. After this loop, toobar_num will contain the number
575 * of the visible toolbars. */
576 g_list_foreach(box->children, visible_toolbar,
577 (gpointer) &toolbar_num);
581 /* Loop through all the children of the GtkVBox of the HildonAppView.
582 * The find_findtoolbar function will assign a pointer to the find toolbar
583 * to "findtoolbar" argument. If the findtoolbar is not found, i.e. it
584 * isn't in the GtkVBox, then the "findtoolbar" argument will stay NULL */
585 g_list_foreach(box->children, find_findtoolbar,
586 (gpointer) &findtoolbar);
587 if(findtoolbar != NULL){
588 gint pass_bundle[2];/* an array for convient data passing
589 the first member contains the y allocation
590 of the find toolbar, and the second allocation
591 contains the index(how many toolbars are above
593 pass_bundle[0] = findtoolbar->allocation.y;
594 pass_bundle[1] = ftb_index;
596 /* computes how many toolbars are above the find toolbar, and the value is
597 * stored in pass_bundle[1] */
598 g_list_foreach(box->children, find_findtoolbar_index,
599 (gpointer) pass_bundle);
600 ftb_index = pass_bundle[1];
603 sprintf(toolbar_mode, "toolbar%sframe-top",
604 fullscreen ? "-fullscreen-" : "-");
605 gtk_paint_box(widget->style, widget->window,
606 GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
607 &event->area, widget, toolbar_mode,
608 widget->allocation.x,
609 GTK_WIDGET(box)->allocation.y -TOOLBAR_UP,
610 widget->allocation.width, TOOLBAR_UP);
612 /*top most toolbar painting*/
613 if(findtoolbar != NULL && ftb_index == 0 )
615 sprintf(toolbar_mode, "findtoolbar%s",
616 fullscreen ? "-fullscreen" : "");
618 gtk_paint_box(widget->style, widget->window,
619 GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
620 &event->area, widget, toolbar_mode,
621 widget->allocation.x,
622 GTK_WIDGET(box)->allocation.y,
623 widget->allocation.width,
626 sprintf(toolbar_mode, "toolbar%s",
627 fullscreen ? "-fullscreen" : "");
628 gtk_paint_box(widget->style, widget->window,
629 GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
630 &event->area, widget, toolbar_mode,
631 widget->allocation.x,
632 GTK_WIDGET(box)->allocation.y,
633 widget->allocation.width,
636 /*multi toolbar painting*/
637 for(count = 0; count < toolbar_num - 1; count++)
639 sprintf(toolbar_mode, "toolbar%sframe-middle",
640 fullscreen ? "-fullscreen-" : "-");
642 gtk_paint_box(widget->style, widget->window,
643 GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
644 &event->area, widget, toolbar_mode,
645 widget->allocation.x,
646 GTK_WIDGET(box)->allocation.y +
647 (1 + count) * TOOLBAR_HEIGHT +
648 count * TOOLBAR_MIDDLE,
649 widget->allocation.width,
652 if(findtoolbar != NULL && count + 1 == ftb_index){
653 sprintf(toolbar_mode, "findtoolbar%s",
654 fullscreen ? "-fullscreen" : "");
656 gtk_paint_box(widget->style, widget->window,
657 GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
658 &event->area, widget, toolbar_mode,
659 widget->allocation.x,
660 GTK_WIDGET(box)->allocation.y +
661 (1 + count) * (TOOLBAR_HEIGHT + TOOLBAR_MIDDLE),
662 widget->allocation.width,
665 sprintf(toolbar_mode, "toolbar%s",
666 fullscreen ? "-fullscreen" : "");
668 gtk_paint_box(widget->style, widget->window,
669 GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
670 &event->area, widget, toolbar_mode,
671 widget->allocation.x,
672 GTK_WIDGET(box)->allocation.y +
673 (1 + count) * (TOOLBAR_HEIGHT + TOOLBAR_MIDDLE),
674 widget->allocation.width,
678 sprintf(toolbar_mode, "toolbar%sframe-bottom",
679 fullscreen ? "-fullscreen-" : "-");
681 gtk_paint_box(widget->style, widget->window,
682 GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
683 &event->area, widget, toolbar_mode,
684 widget->allocation.x,
685 GTK_WIDGET(box)->allocation.y +
686 GTK_WIDGET(box)->allocation.height,
687 widget->allocation.width, TOOLBAR_DOWN);
691 * Callback function to an expose event.
693 static gboolean hildon_appview_expose(GtkWidget * widget,
694 GdkEventExpose * event)
696 gint toolbar_num = 0;
697 GtkBox *box = GTK_BOX(HILDON_APPVIEW(widget)->vbox);
699 if(GTK_WIDGET_VISIBLE(box) && box->children != NULL)
701 HildonAppViewPrivate *priv = HILDON_APPVIEW_GET_PRIVATE(widget);
703 /* Iterate through all the children of the vbox of the HildonAppView.
704 * The visible_toolbar function increments toolbar_num if the toolbar
705 * is visible. After this loop, toobar_num will contain the number
706 * of the visible toolbars. */
707 g_list_foreach(box->children, visible_toolbar,
708 (gpointer) &toolbar_num);
710 if( priv->visible_toolbars != toolbar_num)
712 /* If the code reaches this block, it means that a toolbar as been added
713 * or removed since last time the view was drawn. Let's then compute the
714 * new height of the toolbars areas */
716 /* the height difference */
717 gint change = (priv->visible_toolbars - toolbar_num) *
718 (TOOLBAR_HEIGHT+TOOLBAR_MIDDLE+TOOLBAR_UP);
720 change = TOOLBAR_MIDDLE + TOOLBAR_UP;
721 /* the new y-coordinate for the toolbars area */
722 y_pos = HILDON_APPVIEW(widget)->vbox->allocation.y - change;
724 gtk_widget_queue_draw_area(widget, 0, y_pos, widget->allocation.width,
725 change + HILDON_APPVIEW(widget)->vbox->allocation.height +
727 priv->visible_toolbars = toolbar_num;
732 if (HILDON_APPVIEW(widget)->priv->fullscreen)
735 paint_toolbar(widget, box, event, TRUE);
739 gint appview_height_decrement = 0;
742 appview_height_decrement = toolbar_num * TOOLBAR_HEIGHT +
743 (toolbar_num - 1) * TOOLBAR_MIDDLE
744 + TOOLBAR_UP + TOOLBAR_DOWN;
746 paint_toolbar(widget, box, event, FALSE);
750 appview_height_decrement = MARGIN_APPVIEW_BOTTOM;
752 gtk_paint_box(widget->style, widget->window,
753 GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
754 &event->area, widget, "bottom-border",
755 widget->allocation.x,
756 widget->allocation.y +
757 (widget->allocation.height - MARGIN_APPVIEW_BOTTOM),
758 widget->allocation.width, MARGIN_APPVIEW_BOTTOM);
760 gtk_paint_box( widget->style, widget->window,
761 GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
763 widget, "left-border", widget->allocation.x,
764 widget->allocation.y, MARGIN_APPVIEW_LEFT,
765 widget->allocation.height - appview_height_decrement );
766 gtk_paint_box( widget->style, widget->window,
767 GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
769 widget, "right-border",
770 (widget->allocation.x +
771 widget->allocation.width) -
772 MARGIN_APPVIEW_RIGHT, widget->allocation.y,
773 MARGIN_APPVIEW_RIGHT,
774 widget->allocation.height - appview_height_decrement );
777 GTK_WIDGET_CLASS(parent_class)->expose_event(widget, event);
784 * Responds to the usual size_request signal.
786 static void hildon_appview_size_request(GtkWidget * widget,
787 GtkRequisition * requisition)
789 HildonAppViewPrivate *priv = HILDON_APPVIEW(widget)->priv;
790 GtkWidget *child = GTK_BIN(widget)->child;
792 /* forward the size_request to the eventual child of the main container */
794 gtk_widget_size_request(child, requisition);
796 /* forward the size_request to the eventual vbox (which may contain
798 if (HILDON_APPVIEW(widget)->vbox != NULL)
799 gtk_widget_size_request(HILDON_APPVIEW(widget)->vbox, requisition);
801 /* express the size_request for the view */
802 if (priv->fullscreen) {
803 requisition->height = WINDOW_HEIGHT;
804 requisition->width = WINDOW_WIDTH;
806 requisition->height = APPVIEW_HEIGHT;
807 requisition->width = APPVIEW_WIDTH;
812 * Computes size and position for the children of the view.
814 static void hildon_appview_size_allocate(GtkWidget * widget,
815 GtkAllocation * allocation)
817 GtkAllocation box_allocation;
818 GtkAllocation alloc = *allocation;
819 gint border_width = GTK_CONTAINER(widget)->border_width;
820 GtkBin *bin = GTK_BIN(widget);
821 GtkBox *box = GTK_BOX(HILDON_APPVIEW(widget)->vbox);
822 gboolean at_least_one_visible_toolbar = FALSE;
824 if(!GTK_IS_WIDGET(bin->child)) return;
826 widget->allocation = *allocation;
828 if (bin->child != NULL && GTK_IS_WIDGET(bin->child)) {
829 if (HILDON_APPVIEW(widget)->priv->fullscreen) {
830 alloc.x += border_width;
831 alloc.y += border_width;
832 alloc.width -= (border_width * 2);
833 alloc.height -= (border_width * 2);
835 alloc.x += border_width + MARGIN_APPVIEW_LEFT;
836 alloc.y += border_width + MARGIN_APPVIEW_TOP;
837 alloc.width -= (border_width * 2) + (MARGIN_APPVIEW_LEFT +
838 MARGIN_APPVIEW_RIGHT);
839 alloc.height -= (border_width * 2) + MARGIN_APPVIEW_TOP;
843 if (box->children != NULL) {
846 /* Iterate through all the children of the vbox of the HildonAppView.
847 * The visible_toolbar function increments toolbar_num if the toolbar
848 * is visible. After this loop, toobar_num will contain the number
849 * of the visible toolbars. */
850 g_list_foreach(box->children, visible_toolbar,
853 box_height = length * TOOLBAR_HEIGHT +
854 (length - 1) * TOOLBAR_MIDDLE;
856 if(bin->child != NULL) {
857 alloc.height = alloc.height - box_height - TOOLBAR_UP
859 at_least_one_visible_toolbar = TRUE;
862 box_allocation.y = allocation->height - box_height - TOOLBAR_DOWN;
863 box_allocation.height = box_height;
864 box_allocation.x = allocation->x + TOOLBAR_LEFT;
865 box_allocation.width = allocation->width - TOOLBAR_LEFT -
867 gtk_widget_size_allocate(GTK_WIDGET(box), &box_allocation);
871 /* The bottom skin graphics is visible only when there are no toolbars */
872 if ((HILDON_APPVIEW(widget)->priv->fullscreen == FALSE) &&
873 (at_least_one_visible_toolbar == FALSE))
874 alloc.height -= MARGIN_APPVIEW_BOTTOM;
876 gtk_widget_size_allocate(GTK_WIDGET(bin->child), &alloc);
880 * Overrides gtk_container_forall, calling the callback function for each of
881 * the children of HildonAppPrivate.
883 static void hildon_appview_forall(GtkContainer * container,
884 gboolean include_internals,
885 GtkCallback callback,
886 gpointer callback_data)
888 HildonAppView *self = HILDON_APPVIEW(container);
890 g_return_if_fail(callback != NULL);
892 GTK_CONTAINER_CLASS(parent_class)->forall(container, include_internals,
893 callback, callback_data);
894 if(include_internals && self->vbox != NULL)
895 (* callback)(GTK_WIDGET(self->vbox), callback_data);
899 * Shows all the widgets in the container.
901 static void hildon_appview_show_all(GtkWidget *widget)
903 HildonAppView *self = HILDON_APPVIEW(widget);
906 gtk_widget_show_all(self->vbox);
908 /* Parent handless stuff inside appview */
909 GTK_WIDGET_CLASS(parent_class)->show_all(widget);
913 * Frees all the resources and propagates the destroy call to the parent.
915 static void hildon_appview_destroy(GtkObject *obj)
917 HildonAppView *self = HILDON_APPVIEW(obj);
919 if(self->vbox != NULL){
920 gtk_widget_unparent(self->vbox);
924 GTK_OBJECT_CLASS(parent_class)->destroy(obj);
927 /*******************/
929 /*******************/
932 static void hildon_appview_toolbar_toggle_request( HildonAppView *self )
938 /*Signal - When is changed to this appview, this is called*/
939 static void hildon_appview_switched_to(HildonAppView * self)
943 g_return_if_fail(self && HILDON_IS_APPVIEW(self));
945 parent = gtk_widget_get_parent(GTK_WIDGET(self));
946 hildon_appview_set_fullscreen( self, self->priv->fullscreen );
949 /*Signal - When the fullscreen state is changed, this is called*/
950 static void hildon_appview_real_fullscreen_state_change(HildonAppView *
955 HildonAppViewPrivate *priv;
956 g_return_if_fail(self && HILDON_IS_APPVIEW(self));
959 /* Ensure that state is really changed */
960 if( priv->fullscreen == fullscreen )
964 gtk_window_fullscreen( GTK_WINDOW(
965 gtk_widget_get_parent(GTK_WIDGET(self))) );
967 gtk_window_unfullscreen( GTK_WINDOW(
968 gtk_widget_get_parent(GTK_WIDGET(self))) );
970 priv->fullscreen = fullscreen;
973 /*******************/
975 /*******************/
979 * queries a window for the root window coordinates and size of its
980 * client area (i.e. minus the title borders etc.)
982 static void get_client_area(GtkWidget * widget, GtkAllocation * allocation)
984 GdkWindow *window = widget->window;
987 gdk_window_get_origin(window, &allocation->x, &allocation->y);
989 memset( allocation, 0, sizeof(GtkAllocation) );
992 /*The menu popuping needs a menu popup-function*/
993 static void hildon_appview_menupopupfunc( GtkMenu *menu, gint *x, gint *y,
994 gboolean *push_in, GtkWidget *widget )
996 GtkAllocation client_area = { 0, 0, 0, 0 };
998 get_client_area( GTK_WIDGET(widget), &client_area );
1000 gtk_widget_style_get (GTK_WIDGET (menu), "horizontal-offset", x,
1001 "vertical-offset", y, NULL);
1003 *x += client_area.x;
1004 *y += client_area.y;
1008 /* Similar to above, but used in fullscreen mode */
1009 static void hildon_appview_menupopupfuncfull( GtkMenu *menu, gint *x, gint *y,
1013 gtk_widget_style_get (GTK_WIDGET (menu), "horizontal-offset", x,
1014 "vertical-offset", y, NULL);
1020 /*******************/
1021 /*public functions*/
1022 /*******************/
1026 * hildon_appview_new:
1027 * @title: The application view title of the new @HildonAppView.
1029 * Use this function to create a new application view.
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 scrollbar
1047 * to it. Similar as adding first a @GtkScrolledWindow and then the
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 /* FIXME: child doesn't need to be a viewport in order it can
1065 be packed into scrolled window. It just needs to support
1066 setting adjustments. */
1067 if (GTK_IS_VIEWPORT(child))
1068 gtk_container_add(GTK_CONTAINER(scrolledw), child);
1071 if( GTK_IS_CONTAINER(child) )
1072 gtk_container_set_focus_vadjustment( GTK_CONTAINER(child),
1073 gtk_scrolled_window_get_vadjustment(scrolledw) );
1074 gtk_scrolled_window_add_with_viewport(scrolledw, child);
1077 gtk_container_add(GTK_CONTAINER(self), GTK_WIDGET(scrolledw));
1081 * hildon_appview_get_title:
1082 * @self : A @HildonAppView
1084 * Gets the title of given #HildonAppView.
1086 * Return value: The title of the application view.
1088 const gchar *hildon_appview_get_title(HildonAppView * self)
1090 g_return_val_if_fail(self && HILDON_IS_APPVIEW(self), "");
1091 return self->priv->title;
1095 * hildon_appview_set_title:
1096 * @self : A @HildonAppView
1097 * @newname : The new title of the application view.
1099 * Sets an title of an application view. The title is visible only if
1100 * twoparttitle is enabled on the @HildonApp
1103 void hildon_appview_set_title(HildonAppView * self, const gchar * newname)
1107 g_return_if_fail(self && HILDON_IS_APPVIEW(self));
1108 oldtitle = self->priv->title;
1110 if (newname != NULL)
1111 self->priv->title = g_strdup(newname);
1113 self->priv->title = g_strdup("");
1116 g_signal_emit_by_name(G_OBJECT(self), "title_change");
1120 * hildon_appview_set_toolbar:
1121 * @self: A #HildonAppView
1122 * @toolbar: A #GtkToolbar
1124 * Sets the #GtkToolbar to given #HildonAppView. This is, however, not a recommned way to
1125 * set your toolbars. When you have multi toolbars, calling this function more than once will just
1126 * replace the bottom most toolbar. There is a #GtkVBox in #HildonAppView's public structure, the programmer
1127 * is responsible to pack his toolbars in the #GtkVBox, and #HildonAppView will take care of put them at the
1131 #ifndef HILDON_DISABLE_DEPRECATED
1132 void hildon_appview_set_toolbar(HildonAppView * self, GtkToolbar * toolbar)
1134 GtkBox *box = GTK_BOX(HILDON_APPVIEW(self)->vbox);
1135 g_return_if_fail(self && HILDON_IS_APPVIEW(self));
1136 if(toolbar != NULL)/*for failure checking*/
1137 g_return_if_fail(GTK_IS_TOOLBAR(toolbar));
1139 /*if it is NULL, it unsets the last one,
1140 * if it is not null, it unsets the last one anyway*/
1141 if(box->children != NULL){
1142 GtkWidget *last_widget;
1144 last_widget = ((GtkBoxChild *)g_list_last
1145 (box->children)->data)->widget;
1146 gtk_container_remove(GTK_CONTAINER(box),
1150 gtk_box_pack_end(box, GTK_WIDGET(toolbar), TRUE, TRUE, 0);
1151 gtk_widget_queue_resize(GTK_WIDGET(self));
1152 /*deprecated signal*/
1153 g_signal_emit_by_name(G_OBJECT(self), "toolbar-changed");
1157 * hildon_appview_get_toolbar:
1158 * @self: A #HildonAppView
1160 * This function will only
1161 * return the last widget that has been packed into the #GtkVBox in the public structure. Note
1162 * this does not, however, mean that it is the bottom most toolbar.
1164 * Return value: The #GtkToolbar assigned to this application view.
1166 #ifndef HILDON_DISABLE_DEPRECATED
1167 GtkToolbar *hildon_appview_get_toolbar(HildonAppView * self)
1169 GtkBox *box = GTK_BOX(HILDON_APPVIEW(self)->vbox);
1170 g_return_val_if_fail(self != NULL && HILDON_IS_APPVIEW(self), FALSE);
1171 if(box != NULL && box->children != NULL)
1172 return GTK_TOOLBAR(((GtkBoxChild*)
1173 g_list_last(box->children)->data)->widget);
1179 * hildon_appview_set_fullscreen:
1180 * @self: A @HildonAppView
1181 * @fullscreen: The new state of fullscreen mode. TRUE means fullscreen
1182 * will be set. FALSE the opposite.
1184 * Set the fullscreen state of given #HildonAppView class.
1186 void hildon_appview_set_fullscreen(HildonAppView * self,
1187 gboolean fullscreen)
1189 g_return_if_fail(self && HILDON_IS_APPVIEW(self));
1190 g_signal_emit_by_name(G_OBJECT(self), "fullscreen_state_change",
1195 * hildon_appview_get_fullscreen:
1196 * @self: A @HildonAppView
1198 * Gets the current state of fullscreen mode.
1200 * Return value: The current state of fullscreen mode.
1202 gboolean hildon_appview_get_fullscreen(HildonAppView * self)
1204 g_return_val_if_fail(self && HILDON_IS_APPVIEW(self), FALSE);
1205 return self->priv->fullscreen;
1209 * hildon_appview_get_fullscreen_key_allowed:
1210 * @self: A @HildonAppView
1212 * Check if fullscreening with a shortcut is allowed for given
1215 * Return value: Wheter it's possible to swith fullscreen on/off with
1218 gboolean hildon_appview_get_fullscreen_key_allowed(HildonAppView * self)
1220 g_return_val_if_fail(self && HILDON_IS_APPVIEW(self), FALSE);
1221 return self->priv->fullscreenshortcutallowed;
1225 * hildon_appview_set_fullscreen_key_allowed:
1226 * @self: A @HildonAppView
1227 * @allow: Wheter it's possible to swith fullscreen on/off with
1230 * Sets given #HildonAppView whether to allow toggling fullscreen mode
1231 * with a shortcut key.
1233 void hildon_appview_set_fullscreen_key_allowed(HildonAppView * self,
1236 g_return_if_fail(self && HILDON_IS_APPVIEW(self));
1237 self->priv->fullscreenshortcutallowed = allow;
1241 * hildon_appview_get_menu:
1242 * @self : #HildonAppView
1244 * Gets the #GtMenu assigned to the #HildonAppview.
1246 * Return value: The #GtkMenu assigned to this application view.
1248 GtkMenu *hildon_appview_get_menu(HildonAppView * self)
1250 g_return_val_if_fail(self && HILDON_IS_APPVIEW(self), NULL);
1252 if (self->priv->menu == NULL) {
1253 /* Create hildonlike menu */
1256 GtkWidget *parent = gtk_widget_get_parent (GTK_WIDGET (self));
1258 /* Try to get appview menu from ui manager */
1259 if (parent && HILDON_IS_APP (parent))
1261 uim = hildon_app_get_ui_manager (HILDON_APP (parent));
1265 gtk_ui_manager_get_widget (uim, "/HildonApp");
1270 if (self->priv->menu == NULL)
1272 /* Fall back to oldskool menus */
1273 self->priv->menu = GTK_WIDGET (g_object_new (GTK_TYPE_MENU, NULL));
1276 gtk_widget_set_name(GTK_WIDGET(self->priv->menu),
1277 "menu_force_with_corners");
1278 gtk_widget_show_all (self->priv->menu);
1281 return GTK_MENU(self->priv->menu);
1285 * _hildon_appview_toggle_menu:
1286 * @self : A @HildonAppView
1287 * @button_event_time :
1289 * This function should be only called from @HildonApp.
1290 * Should be renamed to popup menu. Just the first parameter is used.
1292 void _hildon_appview_toggle_menu(HildonAppView * self,
1293 Time button_event_time)
1297 g_return_if_fail(self && HILDON_IS_APPVIEW(self));
1299 if (!self->priv->menu)
1302 if (GTK_WIDGET_VISIBLE(self->priv->menu)) {
1303 gtk_menu_popdown(GTK_MENU(self->priv->menu));
1304 gtk_menu_shell_deactivate(GTK_MENU_SHELL(self->priv->menu));
1308 /* Avoid opening an empty menu */
1309 children = gtk_container_get_children(
1310 GTK_CONTAINER(hildon_appview_get_menu(self)));
1311 if (children != NULL) {
1314 g_list_free(children);
1315 menu = GTK_WIDGET(hildon_appview_get_menu(self));
1316 if (self->priv->fullscreen) {
1317 gtk_menu_popup(GTK_MENU(menu), NULL, NULL,
1318 (GtkMenuPositionFunc)
1319 hildon_appview_menupopupfuncfull,
1320 self, 0, button_event_time);
1322 gtk_menu_popup(GTK_MENU(menu), NULL, NULL,
1323 (GtkMenuPositionFunc)
1324 hildon_appview_menupopupfunc,
1325 self, 0, button_event_time);
1327 gtk_menu_shell_select_first(GTK_MENU_SHELL(menu), TRUE);
1333 * _hildon_appview_menu_visible
1334 * @self : A @HildonAppView
1336 * Checks whether the titlebar menu is currently visible
1337 * Return value : TRUE if the menu is visible, FALSE if not.
1340 gboolean _hildon_appview_menu_visible(HildonAppView * self)
1342 g_return_val_if_fail (HILDON_IS_APPVIEW (self), FALSE);
1344 return GTK_WIDGET_VISIBLE(GTK_WIDGET(hildon_appview_get_menu(self)));
1348 * hildon_appview_set_connected_adjustment
1349 * @self : A @HildonAppView
1350 * @adjustment : A new #GtkAdjustment set to reach to increase
1351 * / decrease hardware keys or NULL to unset.
1353 * Sets a #GtkAdjustment which will change when increase/decrease buttons
1356 void hildon_appview_set_connected_adjustment (HildonAppView * self,
1357 GtkAdjustment * adjustment)
1359 g_return_if_fail (HILDON_IS_APPVIEW (self));
1361 /* Disconnect old adjustment */
1362 if (self->priv->connected_adjustment != NULL)
1363 g_object_remove_weak_pointer (G_OBJECT (self->priv->connected_adjustment),
1364 (gpointer) &self->priv->connected_adjustment);
1366 /* Start using the new one */
1367 self->priv->connected_adjustment = adjustment;
1368 if (self->priv->connected_adjustment != NULL)
1369 g_object_add_weak_pointer (G_OBJECT (self->priv->connected_adjustment),
1370 (gpointer) &self->priv->connected_adjustment);
1374 * hildon_appview_get_connected_adjustment
1375 * @self : A @HildonAppView
1377 * Retrieves the @GtkAdjustment which is connected to this application view
1378 * and is changed with increase / decrease hardware buttons.
1380 * Return value: Currently connectd #GtkAdjustment assigned to this
1381 * application view or NULL if it's not set.
1383 GtkAdjustment * hildon_appview_get_connected_adjustment (HildonAppView * self)
1385 g_return_val_if_fail (HILDON_IS_APPVIEW (self), NULL);
1387 return self->priv->connected_adjustment;
1392 * hildon_appview_set_menu_ui
1393 * @self : A @HildonAppView
1394 * @ui_string : A @GtkUIManager ui description string
1396 * Sets the ui description (xml) from which the UIManager creates menus
1397 * (see @GtkUIManager for details on how to use it)
1399 void hildon_appview_set_menu_ui(HildonAppView *self, const gchar *ui_string)
1401 g_return_if_fail (HILDON_IS_APPVIEW (self));
1405 if (self->priv->menu_ui)
1406 g_free (self->priv->menu_ui);
1408 self->priv->menu_ui = g_strdup (ui_string);
1410 /* FIXME: We should update the menu here, preferrably by a
1411 * hildon_app_ensure_menu_update() which re-installs the menu ui
1412 * and calls gtk_ui_manager_ensure_update()
1418 if (self->priv->menu_ui)
1420 g_free (self->priv->menu_ui);
1421 self->priv->menu_ui = NULL;
1425 g_object_notify (G_OBJECT(self), "menu-ui");
1429 * hildon_appview_get_menu_ui
1430 * @self : A @HildonAppView
1432 * Sets the ui description (xml) from which the UIManager creates menus
1433 * (see @GtkUIManager for details on how to use it)
1435 * Return value: Currently set ui description
1438 const gchar *hildon_appview_get_menu_ui(HildonAppView *self)
1440 g_return_val_if_fail (HILDON_IS_APPVIEW (self), NULL);
1442 return (self->priv->menu_ui);
1446 /* Called when '+' hardkey is pressed/released */
1447 void _hildon_appview_increase_button_state_changed (HildonAppView * self,
1450 self->priv->increase_button_pressed_down = newkeytype;
1452 /* Transform '+' press into adjustment update (usually scrollbar move) */
1453 if ((self->priv->connected_adjustment != NULL) && (newkeytype == GDK_KEY_PRESS))
1455 gfloat clampedvalue = CLAMP (gtk_adjustment_get_value (self->priv->connected_adjustment) + self->priv->connected_adjustment->step_increment,
1456 self->priv->connected_adjustment->lower,
1457 self->priv->connected_adjustment->upper - self->priv->connected_adjustment->page_size);
1458 gtk_adjustment_set_value (self->priv->connected_adjustment, clampedvalue);
1461 g_signal_emit (G_OBJECT (self), appview_signals[INCREASE_BUTTON_EVENT], 0, newkeytype);
1464 /* Called when '-' hardkey is pressed/released */
1465 void _hildon_appview_decrease_button_state_changed (HildonAppView * self,
1468 self->priv->decrease_button_pressed_down = newkeytype;
1470 /* Transform '-' press into adjustment update (usually scrollbar move) */
1471 if ((self->priv->connected_adjustment != NULL) && (newkeytype == GDK_KEY_PRESS))
1473 gfloat clampedvalue = CLAMP (gtk_adjustment_get_value (self->priv->connected_adjustment) - self->priv->connected_adjustment->step_increment,
1474 self->priv->connected_adjustment->lower,
1475 self->priv->connected_adjustment->upper - self->priv->connected_adjustment->page_size);
1476 gtk_adjustment_set_value (self->priv->connected_adjustment, clampedvalue);
1479 g_signal_emit (G_OBJECT (self), appview_signals[DECREASE_BUTTON_EVENT], 0, newkeytype);