2 * This file is part of hildon-libs
4 * Copyright (C) 2006 Nokia Corporation, all rights reserved.
6 * Contact: Michael Dominic Kostrzewa <michael.kostrzewa@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; version 2.1 of
11 * the License or 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-window.h>
32 #include "hildon-program.h"
33 #include "hildon-window-private.h"
34 #include <hildon-find-toolbar.h>
36 #include <gtk/gtkmenu.h>
37 #include <gtk/gtkimcontext.h>
38 #include <gtk/gtkmenuitem.h>
39 #include <gtk/gtkcheckmenuitem.h>
40 #include <gtk/gtkmenushell.h>
41 #include <gtk/gtkwindow.h>
42 #include <gtk/gtkwidget.h>
43 #include <gtk/gtkvbox.h>
44 #include <gtk/gtklabel.h>
45 #include <gtk/gtkentry.h>
46 #include <gtk/gtktextview.h>
47 #include <gtk/gtkscrolledwindow.h>
48 #include <gtk/gtkmain.h>
49 #include <gdk/gdkkeysyms.h>
52 #include<gtk/gtkprivate.h>
56 #include <X11/Xatom.h>
60 #define _(String) gettext(String)
62 /*The size of screen*/
63 #define WINDOW_HEIGHT 480
64 #define WINDOW_WIDTH 800
66 #define NAVIGATOR_HEIGHT WINDOW_HEIGHT
68 #define APPVIEW_HEIGHT 396
69 #define APPVIEW_WIDTH 672
71 #define TOOLBAR_HEIGHT 40
72 #define TOOLBAR_MIDDLE 10
73 #define TOOLBAR_WIDTH APPVIEW_WIDTH
76 #define CAN_HIBERNATE "CANKILL"
77 #define CAN_HIBERNATE_LENGTH 7
79 #define CAN_HIBERNATE_PROPERTY "_HILDON_ABLE_TO_HIBERNATE"
81 #define TITLE_SEPARATOR " - "
84 #define HILDON_WINDOW_GET_PRIVATE(obj) \
85 (G_TYPE_INSTANCE_GET_PRIVATE ((obj),\
86 HILDON_TYPE_WINDOW, HildonWindowPrivate))
88 static GtkWindowClass *parent_class;
91 hildon_window_init (HildonWindow * self);
94 hildon_window_class_init (HildonWindowClass * window_class);
97 hildon_window_menupopupfunc (GtkMenu *menu, gint *x, gint *y,
101 hildon_window_menupopupfuncfull (GtkMenu *menu, gint *x, gint *y,
105 hildon_window_expose (GtkWidget * widget, GdkEventExpose * event);
107 hildon_window_forall (GtkContainer * container,
108 gboolean include_internals,
109 GtkCallback callback,
110 gpointer callback_data);
112 hildon_window_show_all (GtkWidget *widget);
115 hildon_window_size_allocate (GtkWidget * widget,
116 GtkAllocation * allocation);
118 hildon_window_size_request (GtkWidget * widget,
119 GtkRequisition * requisition);
121 hildon_window_finalize (GObject * obj_self);
123 hildon_window_set_property (GObject * object, guint property_id,
124 const GValue * value, GParamSpec * pspec);
126 hildon_window_get_property (GObject * object, guint property_id,
127 GValue * value, GParamSpec * pspec);
129 hildon_window_destroy (GtkObject *obj);
131 hildon_window_realize (GtkWidget *widget);
133 hildon_window_unrealize (GtkWidget *widget);
135 hildon_window_key_press_event (GtkWidget *widget,
138 hildon_window_key_release_event (GtkWidget *widget,
141 hildon_window_window_state_event (GtkWidget *widget,
142 GdkEventWindowState *event);
146 hildon_window_notify (GObject *gobject, GParamSpec *param);
149 hildon_window_is_topmost_notify (HildonWindow *window);
152 hildon_window_toggle_menu (HildonWindow * self);
155 hildon_window_escape_timeout (gpointer data);
157 static GdkFilterReturn
158 hildon_window_event_filter (GdkXEvent *xevent, GdkEvent *event, gpointer data );
160 static GdkFilterReturn
161 hildon_window_root_window_event_filter (GdkXEvent *xevent,
166 hildon_window_get_borders (HildonWindow *window);
169 visible_toolbar (gpointer data, gpointer user_data);
171 paint_toolbar (GtkWidget *widget, GtkBox *box,
172 GdkEventExpose * event,
173 gboolean fullscreen);
175 typedef void (*HildonWindowSignal) (HildonWindow *, gint, gpointer);
192 struct _HildonWindowPrivate
198 GtkBorder *toolbar_borders;
200 GtkAllocation allocation;
204 guint escape_timeout;
205 gint visible_toolbars;
206 gint previous_vbox_y;
208 HildonProgram *program;
212 hildon_window_get_type (void)
214 static GType window_type = 0;
217 static const GTypeInfo window_info = {
218 sizeof(HildonWindowClass),
219 NULL, /* base_init */
220 NULL, /* base_finalize */
221 (GClassInitFunc) hildon_window_class_init,
222 NULL, /* class_finalize */
223 NULL, /* class_data */
224 sizeof(HildonWindow),
226 (GInstanceInitFunc) hildon_window_init,
228 window_type = g_type_register_static(GTK_TYPE_WINDOW,
235 /* Virtual methods */
238 hildon_window_class_init (HildonWindowClass * window_class)
240 /* Get convenience variables */
241 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (window_class);
242 GObjectClass *object_class = G_OBJECT_CLASS (window_class);
243 GtkContainerClass *container_class = GTK_CONTAINER_CLASS (window_class);
245 /* Set the global parent_class here */
246 parent_class = g_type_class_peek_parent (window_class);
248 object_class->set_property = hildon_window_set_property;
249 object_class->get_property = hildon_window_get_property;
250 object_class->notify = hildon_window_notify;
252 /* Set the widgets virtual functions */
253 widget_class->size_allocate = hildon_window_size_allocate;
254 widget_class->size_request = hildon_window_size_request;
255 widget_class->expose_event = hildon_window_expose;
256 widget_class->show_all = hildon_window_show_all;
257 widget_class->realize = hildon_window_realize;
258 widget_class->unrealize = hildon_window_unrealize;
259 widget_class->key_press_event = hildon_window_key_press_event;
260 widget_class->key_release_event = hildon_window_key_release_event;
261 widget_class->window_state_event = hildon_window_window_state_event;
263 /* now the object stuff */
264 object_class->finalize = hildon_window_finalize;
266 /* To the container */
267 container_class->forall = hildon_window_forall;
270 GTK_OBJECT_CLASS (window_class)->destroy = hildon_window_destroy;
272 g_type_class_add_private (window_class,
273 sizeof (struct _HildonWindowPrivate));
275 /* Install properties */
276 g_object_class_install_property (object_class, PROP_IS_TOPMOST,
277 g_param_spec_boolean ("is-topmost",
279 "Whether the window is currently activated by the window "
284 gtk_widget_class_install_style_property (widget_class,
285 g_param_spec_boxed ("borders",
287 "Size of graphical window borders",
291 gtk_widget_class_install_style_property (widget_class,
292 g_param_spec_boxed ("toolbar-borders",
293 "Graphical toolbar borders",
294 "Size of graphical toolbar borders",
298 /* opera hack, install clip operation signal */
299 g_signal_new ("clipboard_operation",
300 G_OBJECT_CLASS_TYPE (object_class),
302 G_STRUCT_OFFSET (HildonWindowClass, clipboard_operation),
304 g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1,
309 hildon_window_init (HildonWindow * self)
311 HildonWindowPrivate *priv = self->priv = HILDON_WINDOW_GET_PRIVATE(self);
313 self->priv->vbox = gtk_vbox_new (TRUE, TOOLBAR_MIDDLE);
314 gtk_widget_set_parent (self->priv->vbox, GTK_WIDGET(self));
316 priv->visible_toolbars = 0;
317 priv->is_topmost = FALSE;
318 priv->borders = NULL;
319 priv->toolbar_borders = NULL;
320 priv->escape_timeout = 0;
322 priv->fullscreen = FALSE;
324 priv->program = NULL;
326 /* We need to track the root window _MB_CURRENT_APP_WINDOW property */
327 gdk_window_set_events (gdk_get_default_root_window (),
328 gdk_window_get_events (gdk_get_default_root_window ()) | GDK_PROPERTY_CHANGE_MASK);
330 gdk_window_add_filter (gdk_get_default_root_window (),
331 hildon_window_root_window_event_filter, self);
335 hildon_window_finalize (GObject * obj_self)
338 g_return_if_fail (HILDON_WINDOW (obj_self));
339 self = HILDON_WINDOW (obj_self);
341 g_free (self->priv->borders);
342 g_free (self->priv->toolbar_borders);
344 if (G_OBJECT_CLASS (parent_class)->finalize)
345 G_OBJECT_CLASS (parent_class)->finalize (obj_self);
350 hildon_window_realize (GtkWidget *widget)
352 Atom *old_atoms, *new_atoms;
356 Window active_window;
358 GTK_WIDGET_CLASS (parent_class)->realize (widget);
360 gtk_widget_realize (GTK_WIDGET (HILDON_WINDOW (widget)->priv->vbox));
363 /* catch the custom button signal from mb to display the menu */
364 gdk_window_add_filter (widget->window, hildon_window_event_filter, widget );
366 window = GDK_WINDOW_XID ( widget->window );
367 disp = GDK_WINDOW_XDISPLAY ( widget->window );
369 /* Enable custom button that is used for menu */
370 XGetWMProtocols (disp, window, &old_atoms, &atom_count);
371 new_atoms = g_new (Atom, atom_count + 1);
373 memcpy (new_atoms, old_atoms, sizeof(Atom) * atom_count);
375 new_atoms[atom_count++] =
376 XInternAtom (disp, "_NET_WM_CONTEXT_CUSTOM", False);
378 XSetWMProtocols (disp, window, new_atoms, atom_count);
383 /* rely on GDK to set the window group to its default */
384 gdk_window_set_group (widget->window, NULL);
386 if (HILDON_WINDOW (widget)->priv->program)
388 gboolean can_hibernate = hildon_program_get_can_hibernate (
389 HILDON_WINDOW (widget)->priv->program);
391 hildon_window_set_can_hibernate_property (HILDON_WINDOW (widget),
395 /* Update the topmost status */
396 active_window = hildon_window_get_active_window();
397 hildon_window_update_topmost (HILDON_WINDOW (widget), active_window);
399 /* Update the window title */
400 hildon_window_update_title(HILDON_WINDOW (widget));
405 hildon_window_unrealize (GtkWidget *widget)
408 gdk_window_remove_filter (widget->window, hildon_window_event_filter,
411 gtk_widget_unrealize (GTK_WIDGET (HILDON_WINDOW (widget)->priv->vbox));
412 GTK_WIDGET_CLASS(parent_class)->unrealize(widget);
416 hildon_window_set_property (GObject * object, guint property_id,
417 const GValue * value, GParamSpec * pspec)
419 /*HildonWindow *window = HILDON_WINDOW (object);*/
421 switch (property_id) {
424 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
430 hildon_window_get_property (GObject * object, guint property_id,
431 GValue * value, GParamSpec * pspec)
433 HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (object);
435 switch (property_id) {
437 case PROP_IS_TOPMOST:
438 g_value_set_boolean (value, priv->is_topmost);
442 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
448 * Retrieve the graphical borders size used by the themes
451 hildon_window_get_borders (HildonWindow *window)
454 g_free (window->priv->borders);
455 g_free (window->priv->toolbar_borders);
457 gtk_widget_style_get (GTK_WIDGET (window), "borders",&window->priv->borders,
458 "toolbar-borders", &window->priv->toolbar_borders,
461 if (!window->priv->borders)
463 window->priv->borders = (GtkBorder *)g_malloc0 (sizeof (GtkBorder));
466 if (!window->priv->toolbar_borders)
468 window->priv->toolbar_borders =
469 (GtkBorder *)g_malloc0 (sizeof (GtkBorder));
474 visible_toolbars (gpointer data, gpointer user_data)
476 if (GTK_WIDGET_VISIBLE (GTK_WIDGET (((GtkBoxChild *)data)->widget)))
477 (*((gint *)user_data)) ++;
481 hildon_window_expose (GtkWidget * widget, GdkEventExpose * event)
483 HildonWindowPrivate *priv = HILDON_WINDOW (widget)->priv;
484 GtkWidget *bx = HILDON_WINDOW(widget)->priv->vbox;
485 GtkBox *box = GTK_BOX(bx);
486 GtkBorder *b = HILDON_WINDOW(widget)->priv->borders;
487 GtkBorder *tb = HILDON_WINDOW(widget)->priv->toolbar_borders;
489 gint currently_visible_toolbars = 0;
493 hildon_window_get_borders (HILDON_WINDOW (widget));
494 b = HILDON_WINDOW(widget)->priv->borders;
495 tb = HILDON_WINDOW(widget)->priv->toolbar_borders;
498 tb_height = bx->allocation.height + tb->top + tb->bottom;
500 g_list_foreach (box->children, visible_toolbars,
501 ¤tly_visible_toolbars);
503 paint_toolbar (widget, box,
504 event, priv->fullscreen);
506 if (!HILDON_WINDOW (widget)->priv->fullscreen)
509 /* Draw the left and right window border */
510 gint side_borders_height = widget->allocation.height - b->top;
512 if (currently_visible_toolbars)
513 side_borders_height -= tb_height;
515 side_borders_height -= b->bottom;
519 gtk_paint_box (widget->style, widget->window,
520 GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
521 &event->area, widget, "left-border",
522 widget->allocation.x, widget->allocation.y +
523 b->top, b->left, side_borders_height);
528 gtk_paint_box (widget->style, widget->window,
529 GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
530 &event->area, widget, "right-border",
531 widget->allocation.x + widget->allocation.width -
532 b->right, widget->allocation.y + b->top,
533 b->right, side_borders_height);
536 /* If no toolbar, draw the bottom window border */
537 if (!currently_visible_toolbars && b->bottom > 0)
539 gtk_paint_box (widget->style, widget->window,
540 GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
541 &event->area, widget, "bottom-border",
542 widget->allocation.x, widget->allocation.y +
543 (widget->allocation.height - b->bottom),
544 widget->allocation.width, b->bottom);
547 /* Draw the top border */
550 gtk_paint_box (widget->style, widget->window,
551 GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
552 &event->area, widget, "top-border",
553 widget->allocation.x, widget->allocation.y,
554 widget->allocation.width, b->top);
560 /* don't draw the window stuff as it overwrites our borders with a blank
561 * rectangle. Instead start with the drawing of the GtkBin */
562 GTK_WIDGET_CLASS (g_type_class_peek_parent (parent_class))->
563 expose_event (widget, event);
564 /*GTK_WIDGET_CLASS (parent_class))->
565 expose_event (widget, event);*/
572 hildon_window_size_request (GtkWidget * widget, GtkRequisition * requisition)
574 HildonWindowPrivate *priv = HILDON_WINDOW (widget)->priv;
575 GtkWidget *child = GTK_BIN (widget)->child;
577 gint border_width = GTK_CONTAINER(widget)->border_width;
581 hildon_window_get_borders (HILDON_WINDOW (widget));
585 gtk_widget_size_request (child, requisition);
587 if (HILDON_WINDOW (widget)->priv->vbox != NULL)
588 gtk_widget_size_request (HILDON_WINDOW (widget)->priv->vbox,
591 requisition->height += req2.height;
592 requisition->width = (requisition->width < req2.width) ?
593 req2.width : requisition->width;
596 requisition->width += 2 * border_width;
597 requisition->height += 2 * border_width;
599 if (!priv->fullscreen)
601 requisition->height += priv->borders->top;
602 if (req2.height == 0)
603 requisition->height += priv->borders->bottom;
604 requisition->width += priv->borders->left + priv->borders->right;
609 hildon_window_size_allocate (GtkWidget * widget, GtkAllocation * allocation)
611 HildonWindowPrivate *priv = HILDON_WINDOW (widget)->priv;
612 GtkAllocation box_alloc;
613 GtkAllocation alloc = *allocation;
615 gint border_width = GTK_CONTAINER(widget)->border_width;
617 GtkWidget *box = HILDON_WINDOW(widget)->priv->vbox;
618 GtkBin *bin = GTK_BIN(widget);
619 GtkBorder *b = HILDON_WINDOW (widget)->priv->borders;
620 GtkBorder *tb = HILDON_WINDOW (widget)->priv->toolbar_borders;
624 hildon_window_get_borders (HILDON_WINDOW (widget));
625 b = HILDON_WINDOW (widget)->priv->borders;
626 tb = HILDON_WINDOW (widget)->priv->toolbar_borders;
629 widget->allocation = *allocation;
631 gtk_widget_get_child_requisition (box, &req);
633 box_alloc.width = allocation->width - tb->left - tb->right;
634 box_alloc.height = ( (req.height < allocation->height) ?
635 req.height : allocation->height );
636 box_alloc.x = allocation->x + tb->left;
637 box_alloc.y = allocation->y + allocation->height - box_alloc.height - tb->bottom;
639 if (bin->child != NULL && GTK_IS_WIDGET (bin->child)
640 && GTK_WIDGET_VISIBLE (bin->child))
642 alloc.x += border_width;
643 alloc.y += border_width;
644 alloc.width -= (border_width * 2);
645 alloc.height -= (border_width * 2) + box_alloc.height;
647 if (!(HILDON_WINDOW (widget)->priv->fullscreen))
650 alloc.width -= (b->left + b->right);
653 alloc.height -= b->top;
655 if (box_alloc.height <= 0)
656 alloc.height -= b->bottom;
658 alloc.height -= (tb->top + tb->bottom);
662 if (!(box_alloc.height <= 0))
663 alloc.height -= (tb->top + tb->bottom);
666 gtk_widget_size_allocate (bin->child, &alloc);
670 gtk_widget_size_allocate (box, &box_alloc);
672 if (priv->previous_vbox_y != box_alloc.y)
674 /* The size of the VBox has changed, we need to redraw part
675 * of the window borders */
676 gint draw_from_y = priv->previous_vbox_y < box_alloc.y?
677 priv->previous_vbox_y - tb->top:
678 box_alloc.y - tb->top;
680 gtk_widget_queue_draw_area (widget, 0, draw_from_y,
681 widget->allocation.width,
682 widget->allocation.height - draw_from_y);
684 priv->previous_vbox_y = box_alloc.y;
690 hildon_window_forall (GtkContainer * container, gboolean include_internals,
691 GtkCallback callback, gpointer callback_data)
693 HildonWindow *self = HILDON_WINDOW (container);
695 g_return_if_fail (callback != NULL);
697 GTK_CONTAINER_CLASS (parent_class)->forall (container, include_internals,
698 callback, callback_data);
699 if (include_internals && self->priv->vbox != NULL)
700 (* callback)(GTK_WIDGET (self->priv->vbox), callback_data);
704 hildon_window_show_all (GtkWidget *widget)
706 HildonWindow *self = HILDON_WINDOW (widget);
708 GTK_WIDGET_CLASS (parent_class)->show_all (widget);
709 gtk_widget_show_all (self->priv->vbox);
714 hildon_window_destroy (GtkObject *obj)
716 HildonWindow *self = HILDON_WINDOW (obj);
719 if (self->priv->vbox != NULL)
721 if (self->priv->program)
723 GtkWidget * common_toolbar = GTK_WIDGET (
724 hildon_program_get_common_toolbar (self->priv->program));
725 if (common_toolbar && common_toolbar->parent == self->priv->vbox)
727 gtk_container_remove (GTK_CONTAINER (self->priv->vbox),
732 gtk_widget_unparent (self->priv->vbox);
733 self->priv->vbox = NULL;
737 menu_list = g_list_copy (gtk_menu_get_for_attach_widget (GTK_WIDGET (obj)));
741 if (GTK_IS_MENU(menu_list->data))
743 if (GTK_WIDGET_VISIBLE (GTK_WIDGET (menu_list->data)))
745 gtk_menu_popdown (GTK_MENU (menu_list->data));
746 gtk_menu_shell_deactivate (GTK_MENU_SHELL (menu_list->data));
748 gtk_menu_detach (GTK_MENU (menu_list->data));
750 menu_list = menu_list->next;
753 g_list_free (menu_list);
755 if (self->priv->program)
757 hildon_program_remove_window (self->priv->program, self);
760 gdk_window_remove_filter (gdk_get_default_root_window(),
761 hildon_window_root_window_event_filter,
764 gtk_widget_set_events (GTK_WIDGET(obj), 0);
766 GTK_OBJECT_CLASS (parent_class)->destroy (obj);
771 hildon_window_notify (GObject *gobject, GParamSpec *param)
773 HildonWindow *window = HILDON_WINDOW (gobject);
775 if (strcmp (param->name, "title") == 0)
778 hildon_window_update_title (window);
780 else if (strcmp (param->name, "is-topmost"))
782 hildon_window_is_topmost_notify (window);
785 if (G_OBJECT_CLASS(parent_class)->notify)
786 G_OBJECT_CLASS(parent_class)->notify (gobject, param);
792 visible_toolbar (gpointer data, gpointer user_data)
794 if (GTK_WIDGET_VISIBLE (((GtkBoxChild *)data)->widget))
795 (*((gint *)user_data))++;
799 find_findtoolbar_index (gpointer data, gpointer user_data)
801 gint *pass_bundle = (gint *)user_data;
803 if(((GtkBoxChild *)data)->widget->allocation.y < pass_bundle[0]
804 && GTK_WIDGET_VISIBLE (((GtkBoxChild *)data)->widget))
809 find_findtoolbar (gpointer data, gpointer user_data)
811 if(HILDON_IS_FIND_TOOLBAR (((GtkBoxChild *)data)->widget)
812 && GTK_WIDGET_VISIBLE (((GtkBoxChild *)data)->widget))
813 (*((GtkWidget **)user_data)) = ((GtkBoxChild *)data)->widget;
817 paint_toolbar (GtkWidget *widget, GtkBox *box,
818 GdkEventExpose * event,
821 gint toolbar_num = 0;
824 GtkWidget *findtoolbar = NULL;
825 gchar toolbar_mode[40];
826 GtkBorder *tb = HILDON_WINDOW (widget)->priv->toolbar_borders;
828 /* collect info to help on painting the boxes */
829 g_list_foreach (box->children, visible_toolbar,
830 (gpointer) &toolbar_num);
835 g_list_foreach (box->children, find_findtoolbar, (gpointer) &findtoolbar);
837 if (findtoolbar != NULL)
839 gint pass_bundle[2];/* an array for convient data passing
840 the first member contains the y allocation
841 of the find toolbar, and the second allocation
842 contains the index(how many toolbars are above
844 pass_bundle[0] = findtoolbar->allocation.y;
845 pass_bundle[1] = ftb_index;
846 g_list_foreach(box->children, find_findtoolbar_index,
847 (gpointer) pass_bundle);
848 ftb_index = pass_bundle[1];
852 sprintf (toolbar_mode, "toolbar%sframe-top",
853 fullscreen ? "-fullscreen-" : "-");
854 gtk_paint_box (widget->style, widget->window,
855 GTK_WIDGET_STATE (widget), GTK_SHADOW_OUT,
856 &event->area, widget, toolbar_mode,
857 widget->allocation.x,
858 GTK_WIDGET (box)->allocation.y - tb->top,
859 widget->allocation.width, tb->top);
861 /*top most toolbar painting*/
862 if (findtoolbar != NULL && ftb_index == 0 )
864 sprintf (toolbar_mode, "findtoolbar%s",
865 fullscreen ? "-fullscreen" : "");
867 gtk_paint_box (widget->style, widget->window,
868 GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
869 &event->area, widget, toolbar_mode,
870 widget->allocation.x,
871 GTK_WIDGET(box)->allocation.y,
872 widget->allocation.width,
877 sprintf (toolbar_mode, "toolbar%s",
878 fullscreen ? "-fullscreen" : "");
880 gtk_paint_box (widget->style, widget->window,
881 GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
882 &event->area, widget, toolbar_mode,
883 widget->allocation.x,
884 GTK_WIDGET(box)->allocation.y,
885 widget->allocation.width,
888 /*multi toolbar painting*/
889 for (count = 0; count < toolbar_num - 1; count++)
891 sprintf (toolbar_mode, "toolbar%sframe-middle",
892 fullscreen ? "-fullscreen-" : "-");
894 gtk_paint_box (widget->style, widget->window,
895 GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
896 &event->area, widget, toolbar_mode,
897 widget->allocation.x,
898 GTK_WIDGET(box)->allocation.y +
899 (1 + count) * TOOLBAR_HEIGHT +
900 count * TOOLBAR_MIDDLE,
901 widget->allocation.width,
904 if (findtoolbar != NULL && count + 1 == ftb_index)
907 sprintf (toolbar_mode, "findtoolbar%s",
908 fullscreen ? "-fullscreen" : "");
910 gtk_paint_box (widget->style, widget->window,
911 GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
912 &event->area, widget, toolbar_mode,
913 widget->allocation.x,
914 GTK_WIDGET(box)->allocation.y +
915 (1 + count) * (TOOLBAR_HEIGHT + TOOLBAR_MIDDLE),
916 widget->allocation.width,
921 sprintf (toolbar_mode, "toolbar%s",
922 fullscreen ? "-fullscreen" : "");
924 gtk_paint_box (widget->style, widget->window,
925 GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
926 &event->area, widget, toolbar_mode,
927 widget->allocation.x,
928 GTK_WIDGET(box)->allocation.y +
929 (1 + count) * (TOOLBAR_HEIGHT + TOOLBAR_MIDDLE),
930 widget->allocation.width,
934 sprintf (toolbar_mode, "toolbar%sframe-bottom",
935 fullscreen ? "-fullscreen-" : "-");
937 gtk_paint_box (widget->style, widget->window,
938 GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
939 &event->area, widget, toolbar_mode,
940 widget->allocation.x,
941 GTK_WIDGET(box)->allocation.y +
942 GTK_WIDGET(box)->allocation.height,
943 widget->allocation.width, tb->bottom);
948 * Checks the root window to know which is the topped window
951 hildon_window_get_active_window (void)
962 unsigned char *char_pointer;
964 Atom active_app_atom =
965 XInternAtom (GDK_DISPLAY (), "_MB_CURRENT_APP_WINDOW", False);
969 status = XGetWindowProperty (GDK_DISPLAY(), GDK_ROOT_WINDOW(),
970 active_app_atom, 0L, 16L,
971 0, XA_WINDOW, &realtype, &format,
972 &n, &extra, &win.char_pointer);
973 if (!(status == Success && realtype == XA_WINDOW && format == 32
974 && n == 1 && win.win != NULL))
977 XFree (win.char_pointer);
984 XFree(win.char_pointer);
990 xclient_message_type_check (XClientMessageEvent *cm, const gchar *name)
992 return cm->message_type == XInternAtom(GDK_DISPLAY(), name, FALSE);
1000 * Handle the window border custom button, which toggles the menu,
1001 * and the Hildon input method copy paste messages
1003 static GdkFilterReturn
1004 hildon_window_event_filter (GdkXEvent *xevent, GdkEvent *event, gpointer data)
1006 XAnyEvent *eventti = xevent;
1008 if (eventti->type == ClientMessage)
1010 XClientMessageEvent *cm = xevent;
1012 if (xclient_message_type_check (cm, "_MB_GRAB_TRANSFER"))
1014 hildon_window_toggle_menu (HILDON_WINDOW ( data ));
1015 return GDK_FILTER_REMOVE;
1017 /* opera hack clipboard client message */
1018 else if (xclient_message_type_check (cm, "_HILDON_IM_CLIPBOARD_COPY"))
1020 g_signal_emit_by_name(G_OBJECT(data), "clipboard_operation",
1021 HILDON_WINDOW_CO_COPY);
1022 return GDK_FILTER_REMOVE;
1024 else if (xclient_message_type_check(cm, "_HILDON_IM_CLIPBOARD_CUT"))
1026 g_signal_emit_by_name(G_OBJECT(data), "clipboard_operation",
1027 HILDON_WINDOW_CO_CUT);
1028 return GDK_FILTER_REMOVE;
1030 else if (xclient_message_type_check(cm, "_HILDON_IM_CLIPBOARD_PASTE"))
1032 g_signal_emit_by_name(G_OBJECT(data), "clipboard_operation",
1033 HILDON_WINDOW_CO_PASTE);
1034 return GDK_FILTER_REMOVE;
1038 return GDK_FILTER_CONTINUE;
1042 * Here we keep track of changes in the _MB_CURRENT_APP_WINDOW,
1043 * to know when we acquire/lose topmost status
1045 static GdkFilterReturn
1046 hildon_window_root_window_event_filter (GdkXEvent *xevent,
1050 XAnyEvent *eventti = xevent;
1051 HildonWindow *hwindow = HILDON_WINDOW (data);
1054 if (eventti->type == PropertyNotify)
1056 XPropertyEvent *pevent = xevent;
1057 Atom active_app_atom =
1058 XInternAtom (GDK_DISPLAY (), "_MB_CURRENT_APP_WINDOW", False);
1060 if (pevent->atom == active_app_atom)
1062 Window active_window = hildon_window_get_active_window();
1064 hildon_window_update_topmost (hwindow, active_window);
1068 return GDK_FILTER_CONTINUE;
1071 /***************************/
1072 /* Signal handlers */
1073 /***************************/
1076 * Handle the menu hardware key here
1079 hildon_window_key_press_event (GtkWidget *widget, GdkEventKey *event)
1081 HildonWindowPrivate *priv;
1083 g_return_val_if_fail (HILDON_IS_WINDOW (widget),FALSE);
1085 priv = HILDON_WINDOW (widget)->priv;
1087 switch (event->keyval)
1089 case HILDON_HARDKEY_MENU:
1090 if (hildon_window_toggle_menu (HILDON_WINDOW (widget)))
1093 case HILDON_HARDKEY_ESC:
1094 if (!priv->escape_timeout)
1096 priv->escape_timeout = g_timeout_add
1097 (HILDON_WINDOW_LONG_PRESS_TIME,
1098 hildon_window_escape_timeout, widget);
1103 return GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event);
1108 hildon_window_key_release_event (GtkWidget *widget, GdkEventKey *event)
1110 HildonWindowPrivate *priv;
1112 g_return_val_if_fail (HILDON_IS_WINDOW (widget),FALSE);
1114 priv = HILDON_WINDOW (widget)->priv;
1116 switch (event->keyval)
1118 case HILDON_HARDKEY_ESC:
1119 if (priv->escape_timeout)
1121 g_source_remove (priv->escape_timeout);
1122 priv->escape_timeout = 0;
1127 return GTK_WIDGET_CLASS (parent_class)->key_release_event (widget, event);
1132 * We keep track of the window state changes, because the drawing
1133 * (borders) differs whether we are in fullscreen mode or not
1136 hildon_window_window_state_event (GtkWidget *widget,
1137 GdkEventWindowState *event)
1139 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN)
1141 HILDON_WINDOW (widget)->priv->fullscreen =
1142 event->new_window_state & GDK_WINDOW_STATE_FULLSCREEN;
1145 if (GTK_WIDGET_CLASS (parent_class)->window_state_event)
1147 return GTK_WIDGET_CLASS (parent_class)->window_state_event (
1158 hildon_window_title_notify (GObject *gobject,
1162 HildonWindow *window = HILDON_WINDOW (gobject);
1164 hildon_window_update_title (window);
1168 /*******************/
1170 /*******************/
1172 /*The menu popuping needs a menu popup-function*/
1174 hildon_window_menupopupfunc (GtkMenu *menu, gint *x, gint *y,
1175 gboolean *push_in, GtkWidget *widget)
1179 GdkWindow *window = GTK_WIDGET(widget)->window;
1183 gdk_window_get_origin (window, &window_x, &window_y);
1186 gtk_widget_style_get (GTK_WIDGET (menu), "horizontal-offset", x,
1187 "vertical-offset", y, NULL);
1195 hildon_window_menupopupfuncfull ( GtkMenu *menu, gint *x, gint *y,
1199 gtk_widget_style_get (GTK_WIDGET (menu), "horizontal-offset", x,
1200 "vertical-offset", y, NULL);
1207 /********************/
1208 /* Private methods */
1209 /********************/
1213 * Takes the common toolbar when we acquire the top-most status
1216 hildon_window_is_topmost_notify (HildonWindow *window)
1218 if (window->priv->is_topmost)
1220 hildon_window_take_common_toolbar (window);
1225 /* If the window lost focus while the user started to press
1226 * the ESC key, we won't get the release event. We need to
1227 * stop the timeout*/
1228 if (window->priv->escape_timeout)
1230 g_source_remove (window->priv->escape_timeout);
1231 window->priv->escape_timeout = 0;
1237 * Sets the program to which the window belongs. This should only be called
1238 * by hildon_program_add_window
1241 hildon_window_set_program (HildonWindow *self, GObject *program)
1243 if (self->priv->program)
1245 g_object_unref (self->priv->program);
1248 /* Now that we are bound to a program, we can rely on it to track the
1250 gdk_window_remove_filter (gdk_get_default_root_window(),
1251 hildon_window_root_window_event_filter,
1254 self->priv->program = HILDON_PROGRAM (program);
1255 g_object_ref (program);
1259 * Unsets the program to which the window belongs. This should only be called
1260 * by hildon_program_add_window
1263 hildon_window_unset_program (HildonWindow *self)
1265 g_return_if_fail(self && HILDON_IS_WINDOW (self));
1267 if (self->priv->program)
1269 g_object_unref (self->priv->program);
1270 self->priv->program = NULL;
1272 /* We need to start tacking the root window again */
1273 gdk_window_set_events (gdk_get_default_root_window (),
1274 gdk_window_get_events (gdk_get_default_root_window ())
1275 | GDK_PROPERTY_CHANGE_MASK);
1277 gdk_window_add_filter (gdk_get_default_root_window (),
1278 hildon_window_root_window_event_filter, self );
1281 self->priv->program = NULL;
1285 * Sets whether or not the program to which this window belongs is
1286 * killable. This is used by the HildonProgram to signify to the
1287 * Task Navigator whether or not it can hibernate in memory-low situations
1290 hildon_window_set_can_hibernate_property (HildonWindow *self,
1291 gpointer _can_hibernate)
1293 GdkAtom killable_atom;
1294 gboolean can_hibernate;
1296 g_return_if_fail(self && HILDON_IS_WINDOW (self));
1298 if (!GTK_WIDGET_REALIZED ((GTK_WIDGET (self))))
1303 can_hibernate = * ((gboolean *)_can_hibernate);
1305 killable_atom = gdk_atom_intern (CAN_HIBERNATE_PROPERTY, FALSE);
1309 gdk_property_change (GTK_WIDGET (self)->window, killable_atom,
1310 (GdkAtom)31/* XA_STRING */, 8,
1311 GDK_PROP_MODE_REPLACE, (const guchar *)CAN_HIBERNATE,
1312 CAN_HIBERNATE_LENGTH);
1316 gdk_property_delete (GTK_WIDGET (self)->window, killable_atom);
1322 * If a common toolbar was set to the program, reparent it to
1326 hildon_window_take_common_toolbar (HildonWindow *self)
1328 g_return_if_fail(self && HILDON_IS_WINDOW (self));
1330 if (self->priv->program)
1332 GtkWidget *common_toolbar =
1333 GTK_WIDGET (hildon_program_get_common_toolbar (self->priv->program));
1335 if (common_toolbar && common_toolbar->parent != self->priv->vbox)
1337 g_object_ref (common_toolbar);
1338 if (common_toolbar->parent)
1340 gtk_container_remove (GTK_CONTAINER (common_toolbar->parent),
1344 gtk_box_pack_end (GTK_BOX(self->priv->vbox), common_toolbar,
1346 g_object_unref (common_toolbar);
1348 gtk_widget_set_size_request (common_toolbar, -1, TOOLBAR_HEIGHT);
1350 gtk_widget_show (self->priv->vbox);
1357 * Compare the window that was last topped, and act consequently
1360 hildon_window_update_topmost (HildonWindow *self, Window window_id)
1364 my_window = GDK_WINDOW_XID (GTK_WIDGET (self)->window);
1366 if (window_id == my_window)
1368 if (!self->priv->is_topmost)
1370 self->priv->is_topmost = TRUE;
1371 hildon_window_is_topmost_notify (self);
1372 g_object_notify (G_OBJECT (self), "is-topmost");
1375 else if (self->priv->is_topmost)
1377 /* Should this go in the signal handler? */
1378 GtkWidget *focus = gtk_window_get_focus (GTK_WINDOW (self));
1380 if (GTK_IS_ENTRY (focus))
1381 gtk_im_context_focus_out (GTK_ENTRY (focus)->im_context);
1382 if (GTK_IS_TEXT_VIEW (focus))
1383 gtk_im_context_focus_out (GTK_TEXT_VIEW (focus)->im_context);
1385 self->priv->is_topmost = FALSE;
1386 hildon_window_is_topmost_notify (self);
1387 g_object_notify (G_OBJECT (self), "is-topmost");
1393 * If the application
1394 * was given a name (with g_set_application_name(), set
1395 * "ProgramName - WindowTitle" as the displayed
1399 hildon_window_update_title (HildonWindow *window)
1401 const gchar * application_name;
1402 g_return_if_fail (window && HILDON_IS_WINDOW (window));
1404 if (!GTK_WIDGET_REALIZED (window))
1409 application_name = g_get_application_name ();
1411 if (application_name && application_name[0])
1413 const gchar *old_title = gtk_window_get_title (GTK_WINDOW (window));
1415 if (old_title && old_title[0])
1417 gchar *title = NULL;
1419 title = g_strjoin (TITLE_SEPARATOR, application_name,
1422 gdk_window_set_title (GTK_WIDGET (window)->window, title);
1431 detach_menu_func (GtkWidget *attach_widget, GtkMenu *menu)
1435 * Toggles the display of the HildonWindow menu.
1436 * Returns whether or not something was done (whether or not we had a menu
1440 hildon_window_toggle_menu (HildonWindow * self)
1442 GtkMenu *menu_to_use = NULL;
1443 GList *menu_children = NULL;
1445 g_return_val_if_fail (self && HILDON_IS_WINDOW (self), FALSE);
1447 /* Select which menu to use, Window specific has highest priority,
1448 * then program specific */
1449 if (self->priv->menu)
1451 menu_to_use = GTK_MENU (self->priv->menu);
1453 else if (self->priv->program)
1455 menu_to_use = hildon_program_get_common_menu (self->priv->program);
1456 if (menu_to_use && gtk_menu_get_attach_widget (menu_to_use) !=
1459 g_object_ref (menu_to_use);
1460 if (gtk_menu_get_attach_widget (menu_to_use))
1462 gtk_menu_detach (menu_to_use);
1465 gtk_menu_attach_to_widget (menu_to_use, GTK_WIDGET (self),
1467 g_object_unref (menu_to_use);
1477 if (GTK_WIDGET_MAPPED (GTK_WIDGET (menu_to_use)))
1479 gtk_menu_popdown (menu_to_use);
1480 gtk_menu_shell_deactivate (GTK_MENU_SHELL (menu_to_use));
1484 /* Check if the menu has items */
1485 menu_children = gtk_container_get_children (GTK_CONTAINER (menu_to_use));
1489 g_list_free (menu_children);
1491 /* Apply right theming */
1492 gtk_widget_set_name (GTK_WIDGET (menu_to_use),
1493 "menu_force_with_corners");
1495 if (self->priv->fullscreen)
1497 gtk_menu_popup (menu_to_use, NULL, NULL,
1498 (GtkMenuPositionFunc)
1499 hildon_window_menupopupfuncfull,
1501 gtk_get_current_event_time ());
1505 gtk_menu_popup (menu_to_use, NULL, NULL,
1506 (GtkMenuPositionFunc)
1507 hildon_window_menupopupfunc,
1509 gtk_get_current_event_time ());
1511 gtk_menu_shell_select_first (GTK_MENU_SHELL (menu_to_use), TRUE);
1520 * If the ESC key was not released when the timeout expires,
1524 hildon_window_escape_timeout (gpointer data)
1526 HildonWindowPrivate *priv;
1529 GDK_THREADS_ENTER ();
1531 priv = HILDON_WINDOW(data)->priv;
1533 /* Send fake event, simulation a situation that user
1534 pressed 'x' from the corner */
1535 event = gdk_event_new(GDK_DELETE);
1536 ((GdkEventAny *)event)->window = GDK_WINDOW (g_object_ref (GTK_WIDGET(data)->window));
1537 gtk_main_do_event(event);
1539 /* That unrefs the window, so we're reffing it above */
1540 gdk_event_free(event);
1542 priv->escape_timeout = 0;
1544 GDK_THREADS_LEAVE ();
1550 /******************/
1551 /* public methods */
1552 /******************/
1556 * hildon_window_new:
1558 * Use this function to create a new HildonWindow.
1560 * Return value: A @HildonWindow.
1563 hildon_window_new (void)
1565 HildonWindow *newwindow = g_object_new (HILDON_TYPE_WINDOW, NULL);
1567 return GTK_WIDGET (newwindow);
1571 * hildon_window_add_with_scrollbar
1572 * @self : A @HildonWindow
1573 * @child : A @GtkWidget
1575 * Adds the @child to the HildonWindow and creates a scrollbar
1576 * to it. Similar as adding first a @GtkScrolledWindow and then the
1580 hildon_window_add_with_scrollbar (HildonWindow * self,
1583 GtkScrolledWindow *scrolledw;
1585 g_return_if_fail (HILDON_IS_WINDOW (self));
1586 g_return_if_fail (GTK_IS_WIDGET (child));
1587 g_return_if_fail (child->parent == NULL);
1589 scrolledw = GTK_SCROLLED_WINDOW (gtk_scrolled_window_new (NULL, NULL));
1590 gtk_scrolled_window_set_policy (scrolledw, GTK_POLICY_NEVER,
1591 GTK_POLICY_AUTOMATIC);
1592 gtk_scrolled_window_set_shadow_type (scrolledw, GTK_SHADOW_NONE);
1594 if (GTK_IS_VIEWPORT (child))
1595 gtk_container_add (GTK_CONTAINER (scrolledw), child);
1598 if (GTK_IS_CONTAINER (child) )
1599 gtk_container_set_focus_vadjustment (GTK_CONTAINER(child),
1600 gtk_scrolled_window_get_vadjustment (scrolledw) );
1601 gtk_scrolled_window_add_with_viewport (scrolledw, child);
1604 gtk_container_add (GTK_CONTAINER (self), GTK_WIDGET (scrolledw));
1608 * hildon_window_add_toolbar:
1609 * @self: A @HildonWindow
1610 * @toolbar: A #GtkToolbar to add to the HildonWindow
1612 * Adds a toolbar to the window.
1615 hildon_window_add_toolbar (HildonWindow *self, GtkToolbar *toolbar)
1619 g_return_if_fail (self && HILDON_IS_WINDOW (self));
1620 g_return_if_fail (toolbar && GTK_IS_TOOLBAR (toolbar));
1622 vbox = GTK_BOX (self->priv->vbox);
1624 gtk_box_pack_start (vbox, GTK_WIDGET(toolbar), TRUE, TRUE, 0);
1625 gtk_box_reorder_child (vbox, GTK_WIDGET(toolbar), 0);
1626 gtk_widget_set_size_request (GTK_WIDGET (toolbar), -1, TOOLBAR_HEIGHT);
1628 gtk_widget_queue_resize (GTK_WIDGET(self));
1632 * hildon_window_remove_toolbar:
1633 * @self: A @HildonWindow
1634 * @toolbar: A #GtkToolbar to remove from the HildonWindow
1636 * Removes a toolbar from the window.
1639 hildon_window_remove_toolbar (HildonWindow *self, GtkToolbar *toolbar)
1641 GtkContainer *vbox = GTK_CONTAINER (self->priv->vbox);
1643 g_return_if_fail (self && HILDON_IS_WINDOW (self));
1645 gtk_container_remove (vbox, GTK_WIDGET(toolbar));
1649 * hildon_window_get_menu:
1650 * @self : #HildonWindow
1652 * Gets the #GtMenu assigned to the #HildonAppview.
1654 * Return value: The #GtkMenu assigned to this application view.
1657 hildon_window_get_menu (HildonWindow * self)
1659 g_return_val_if_fail (self && HILDON_IS_WINDOW (self), NULL);
1661 return GTK_MENU (self->priv->menu);
1666 * hildon_window_set_menu:
1667 * @self: A #HildonWindow
1668 * @menu: The #GtkMenu to be used for this #HildonWindow
1670 * Sets the menu to be used for this window. This menu overrides
1671 * a program-wide menu that may have been set with
1672 * hildon_program_set_common_menu. Pass NULL to remove the current
1676 hildon_window_set_menu (HildonWindow *self, GtkMenu *menu)
1678 g_return_if_fail (HILDON_IS_WINDOW (self));
1680 if (self->priv->menu != NULL) {
1681 gtk_menu_detach (GTK_MENU (self->priv->menu));
1682 g_object_unref (self->priv->menu);
1685 self->priv->menu = (menu != NULL) ? GTK_WIDGET (menu) : NULL;
1686 if (self->priv->menu != NULL) {
1687 gtk_widget_set_name (self->priv->menu, "menu_force_with_corners");
1688 gtk_menu_attach_to_widget (GTK_MENU (self->priv->menu), GTK_WIDGET (self), &detach_menu_func);
1689 g_object_ref (GTK_MENU (self->priv->menu));
1692 gtk_widget_show_all (GTK_WIDGET (self));
1696 * hildon_window_get_is_topmost:
1697 * @self: A #HildonWindow
1699 * Return value: Whether or not the #HildonWindow is currenltly activated
1700 * by the window manager.
1703 hildon_window_get_is_topmost(HildonWindow *self){
1704 g_return_val_if_fail (HILDON_IS_WINDOW (self), FALSE);
1706 return self->priv->is_topmost;