*
* Copyright (C) 2006 Nokia Corporation.
*
- * Contact: Luc Pionchon <luc.pionchon@nokia.com>
+ * Contact: Michael Dominic Kostrzewa <michael.kostrzewa@nokia.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
+ * as published by the Free Software Foundation; version 2.1 of
+ * the License.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
GdkEventKey *event);
static gboolean
hildon_window_window_state_event (GtkWidget *widget,
- GdkEventWindowState *event,
- gpointer null);
+ GdkEventWindowState *event);
+
-static void
-hildon_window_title_notify (GObject *gobject,
- GParamSpec *arg1,
- gpointer user_data);
static void
-hildon_window_is_topmost_notify (GObject *self,
- GParamSpec *property_spec,
- gpointer null);
+hildon_window_notify (GObject *gobject, GParamSpec *param);
-static gboolean
-hildon_window_vbox_expose_event (GtkWidget *vbox,
- GdkEventExpose *event,
- gpointer window);
+static void
+hildon_window_is_topmost_notify (HildonWindow *window);
static gboolean
hildon_window_toggle_menu (HildonWindow * self);
object_class->set_property = hildon_window_set_property;
object_class->get_property = hildon_window_get_property;
+ object_class->notify = hildon_window_notify;
/* Set the widgets virtual functions */
widget_class->size_allocate = hildon_window_size_allocate;
widget_class->unrealize = hildon_window_unrealize;
widget_class->key_press_event = hildon_window_key_press_event;
widget_class->key_release_event = hildon_window_key_release_event;
+ widget_class->window_state_event = hildon_window_window_state_event;
/* now the object stuff */
object_class->finalize = hildon_window_finalize;
"Size of graphical toolbar borders",
GTK_TYPE_BORDER,
G_PARAM_READABLE));
-
+
+ /* opera hack, install clip operation signal */
+ g_signal_new ("clipboard_operation",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (HildonWindowClass, clipboard_operation),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1,
+ GTK_TYPE_INT);
}
static void
{
HildonWindowPrivate *priv = self->priv = HILDON_WINDOW_GET_PRIVATE(self);
- self->priv->vbox = gtk_vbox_new (TRUE, 10);
+ self->priv->vbox = gtk_vbox_new (TRUE, TOOLBAR_MIDDLE);
gtk_widget_set_parent (self->priv->vbox, GTK_WIDGET(self));
priv->menu = NULL;
priv->visible_toolbars = 0;
priv->fullscreen = FALSE;
priv->program = NULL;
- gtk_widget_set_events (GTK_WIDGET(self), GDK_BUTTON_PRESS_MASK |
- GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK);
-
- /* Handle the drawing of the vbox (add the pixmap borders) */
- g_signal_connect (G_OBJECT (self->priv->vbox), "expose-event",
- G_CALLBACK (hildon_window_vbox_expose_event),
- self);
-
- /* Used to keep track of fullscreen / unfullscreen */
- g_signal_connect (G_OBJECT (self), "window_state_event",
- G_CALLBACK (hildon_window_window_state_event), self);
-
- g_signal_connect (G_OBJECT (self), "notify::title",
- G_CALLBACK (hildon_window_title_notify), self);
-
- g_signal_connect (G_OBJECT (self), "notify::is-topmost",
- G_CALLBACK (hildon_window_is_topmost_notify), self);
/* We need to track the root window _MB_CURRENT_APP_WINDOW property */
gdk_window_set_events (gdk_get_default_root_window (),
if (!priv->borders)
{
hildon_window_get_borders (HILDON_WINDOW (widget));
+ b = HILDON_WINDOW(widget)->priv->borders;
+ tb = HILDON_WINDOW(widget)->priv->toolbar_borders;
}
tb_height = bx->allocation.height + tb->top + tb->bottom;
g_list_foreach (box->children, visible_toolbars,
¤tly_visible_toolbars);
- if (priv->previous_vbox_y != priv->vbox->allocation.y)
- {
- gint draw_from_y = priv->previous_vbox_y < priv->vbox->allocation.y?
- priv->previous_vbox_y - tb->top:
- priv->vbox->allocation.y - tb->top;
-
- gtk_widget_queue_draw_area (widget, 0, draw_from_y,
- widget->allocation.width,
- widget->allocation.height - draw_from_y);
-
- priv->previous_vbox_y = priv->vbox->allocation.y;
- }
+ paint_toolbar (widget, box,
+ event, priv->fullscreen);
if (!HILDON_WINDOW (widget)->priv->fullscreen)
{
}
/* If no toolbar, draw the bottom window border */
- if (!currently_visible_toolbars &&b->bottom > 0)
+ if (!currently_visible_toolbars && b->bottom > 0)
{
gtk_paint_box (widget->style, widget->window,
GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
* rectangle. Instead start with the drawing of the GtkBin */
GTK_WIDGET_CLASS (g_type_class_peek_parent (parent_class))->
expose_event (widget, event);
+ /*GTK_WIDGET_CLASS (parent_class))->
+ expose_event (widget, event);*/
return FALSE;
if (!priv->borders)
{
hildon_window_get_borders (HILDON_WINDOW (widget));
+ b = HILDON_WINDOW (widget)->priv->borders;
+ tb = HILDON_WINDOW (widget)->priv->toolbar_borders;
}
widget->allocation = *allocation;
- gtk_widget_size_request (box, &req);
+ gtk_widget_get_child_requisition (box, &req);
box_alloc.width = allocation->width - tb->left - tb->right;
box_alloc.height = ( (req.height < allocation->height) ?
box_alloc.x = allocation->x + tb->left;
box_alloc.y = allocation->y + allocation->height - box_alloc.height - tb->bottom;
-
- if (bin->child != NULL && GTK_IS_WIDGET (bin->child))
+ if (bin->child != NULL && GTK_IS_WIDGET (bin->child)
+ && GTK_WIDGET_VISIBLE (bin->child))
{
alloc.x += border_width;
alloc.y += border_width;
alloc.y += b->top;
alloc.height -= b->top;
- }
- if (box_alloc.height <= 0 &&
- !(HILDON_WINDOW (widget)->priv->fullscreen))
- alloc.height -= b->bottom;
+ if (box_alloc.height <= 0)
+ alloc.height -= b->bottom;
+ else
+ alloc.height -= (tb->top + tb->bottom);
+ }
else
- alloc.height -= (tb->top + tb->bottom);
+ {
+ if (!(box_alloc.height <= 0))
+ alloc.height -= (tb->top + tb->bottom);
+ }
gtk_widget_size_allocate (bin->child, &alloc);
}
gtk_widget_size_allocate (box, &box_alloc);
+
+ if (priv->previous_vbox_y != box_alloc.y)
+ {
+ /* The size of the VBox has changed, we need to redraw part
+ * of the window borders */
+ gint draw_from_y = priv->previous_vbox_y < box_alloc.y?
+ priv->previous_vbox_y - tb->top:
+ box_alloc.y - tb->top;
+
+ gtk_widget_queue_draw_area (widget, 0, draw_from_y,
+ widget->allocation.width,
+ widget->allocation.height - draw_from_y);
+
+ priv->previous_vbox_y = box_alloc.y;
+ }
+
}
static void
GTK_OBJECT_CLASS (parent_class)->destroy (obj);
}
+
static void
-hildon_window_is_topmost_notify (GObject *self,
- GParamSpec *property_spec,
- gpointer null)
+hildon_window_notify (GObject *gobject, GParamSpec *param)
{
- HildonWindow *window = HILDON_WINDOW (self);
-
- if (window->priv->is_topmost)
+ HildonWindow *window = HILDON_WINDOW (gobject);
+
+ if (strcmp (param->name, "title") == 0)
{
- hildon_window_take_common_toolbar (window);
- }
- else
+ hildon_window_update_title (window);
+ }
+ else if (strcmp (param->name, "is-topmost"))
{
- /* If the window lost focus while the user started to press
- * the ESC key, we won't get the release event. We need to
- * stop the timeout*/
- if (window->priv->escape_timeout)
- {
- g_source_remove (window->priv->escape_timeout);
- window->priv->escape_timeout = 0;
- }
+ hildon_window_is_topmost_notify (window);
}
-}
-
-
-static gboolean
-hildon_window_vbox_expose_event (GtkWidget *vbox,
- GdkEventExpose *event,
- gpointer window)
-{
- HildonWindowPrivate *priv = HILDON_WINDOW (window)->priv;
-
- hildon_window_get_borders (HILDON_WINDOW(window));
-
- event->area.x -= priv->toolbar_borders->left;
- event->area.y -= priv->toolbar_borders->top;
- event->area.width += (priv->toolbar_borders->left +
- priv->toolbar_borders->right);
- event->area.height += (priv->toolbar_borders->top +
- priv->toolbar_borders->bottom);
- paint_toolbar (GTK_WIDGET (window), GTK_BOX (vbox), event, priv->fullscreen);
-
- GTK_WIDGET_CLASS (G_TYPE_INSTANCE_GET_CLASS (vbox, GTK_TYPE_VBOX, GtkVBox))
- ->expose_event (vbox, event);
-
- event->area = GTK_WIDGET(window)->allocation;
-
-
- return TRUE;
+ if (G_OBJECT_CLASS(parent_class)->notify)
+ G_OBJECT_CLASS(parent_class)->notify (gobject, param);
}
/* Utilities */
return ret;
}
+static int
+xclient_message_type_check (XClientMessageEvent *cm, const gchar *name)
+{
+ return cm->message_type == XInternAtom(GDK_DISPLAY(), name, FALSE);
+}
/*****************/
/* Event filters */
/*****************/
/*
- * Handle the window border custom button, which toggles the menu
+ * Handle the window border custom button, which toggles the menu,
+ * and the Hildon input method copy paste messages
*/
static GdkFilterReturn
hildon_window_event_filter (GdkXEvent *xevent, GdkEvent *event, gpointer data)
if (eventti->type == ClientMessage)
{
XClientMessageEvent *cm = xevent;
- Atom mb_grab_transfer_atom =
- XInternAtom (GDK_DISPLAY(), "_MB_GRAB_TRANSFER", FALSE);
- if (cm->message_type == mb_grab_transfer_atom)
+ if (xclient_message_type_check (cm, "_MB_GRAB_TRANSFER"))
{
hildon_window_toggle_menu (HILDON_WINDOW ( data ));
return GDK_FILTER_REMOVE;
}
+ /* opera hack clipboard client message */
+ else if (xclient_message_type_check (cm, "_HILDON_IM_CLIPBOARD_COPY"))
+ {
+ g_signal_emit_by_name(G_OBJECT(data), "clipboard_operation",
+ HILDON_WINDOW_CO_COPY);
+ return GDK_FILTER_REMOVE;
+ }
+ else if (xclient_message_type_check(cm, "_HILDON_IM_CLIPBOARD_CUT"))
+ {
+ g_signal_emit_by_name(G_OBJECT(data), "clipboard_operation",
+ HILDON_WINDOW_CO_CUT);
+ return GDK_FILTER_REMOVE;
+ }
+ else if (xclient_message_type_check(cm, "_HILDON_IM_CLIPBOARD_PASTE"))
+ {
+ g_signal_emit_by_name(G_OBJECT(data), "clipboard_operation",
+ HILDON_WINDOW_CO_PASTE);
+ return GDK_FILTER_REMOVE;
+ }
}
return GDK_FILTER_CONTINUE;
*/
static gboolean
hildon_window_window_state_event (GtkWidget *widget,
- GdkEventWindowState *event,
- gpointer null)
+ GdkEventWindowState *event)
{
if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN)
{
event->new_window_state & GDK_WINDOW_STATE_FULLSCREEN;
}
- return FALSE;
+ if (GTK_WIDGET_CLASS (parent_class)->window_state_event)
+ {
+ return GTK_WIDGET_CLASS (parent_class)->window_state_event (
+ widget,
+ event);
+ }
+ else
+ {
+ return FALSE;
+ }
}
static void
/* Private methods */
/********************/
+
+/*
+ * Takes the common toolbar when we acquire the top-most status
+ */
+static void
+hildon_window_is_topmost_notify (HildonWindow *window)
+{
+ if (window->priv->is_topmost)
+ {
+ hildon_window_take_common_toolbar (window);
+ }
+
+ else
+ {
+ /* If the window lost focus while the user started to press
+ * the ESC key, we won't get the release event. We need to
+ * stop the timeout*/
+ if (window->priv->escape_timeout)
+ {
+ g_source_remove (window->priv->escape_timeout);
+ window->priv->escape_timeout = 0;
+ }
+ }
+}
+
/*
* Sets the program to which the window belongs. This should only be called
* by hildon_program_add_window
hildon_window_toggle_menu (HildonWindow * self)
{
GtkMenu *menu_to_use = NULL;
+ GList *menu_children = NULL;
- g_return_if_fail (self && HILDON_IS_WINDOW (self));
+ g_return_val_if_fail (self && HILDON_IS_WINDOW (self), FALSE);
/* Select which menu to use, Window specific has highest priority,
* then program specific */
}
- if (GTK_WIDGET_VISIBLE (GTK_WIDGET (menu_to_use)))
+ if (GTK_WIDGET_MAPPED (GTK_WIDGET (menu_to_use)))
{
gtk_menu_popdown (menu_to_use);
gtk_menu_shell_deactivate (GTK_MENU_SHELL (menu_to_use));
return TRUE;
}
- if (gtk_container_get_children (GTK_CONTAINER (menu_to_use)) != NULL)
+ /* Check if the menu has items */
+ menu_children = gtk_container_get_children (GTK_CONTAINER (menu_to_use));
+
+ if (menu_children)
{
+ g_list_free (menu_children);
+
/* Apply right theming */
gtk_widget_set_name (GTK_WIDGET (menu_to_use),
"menu_force_with_corners");
gtk_get_current_event_time ());
}
gtk_menu_shell_select_first (GTK_MENU_SHELL (menu_to_use), TRUE);
+ return TRUE;
}
- return TRUE;
+ return FALSE;
+
}
/*
/* Send fake event, simulation a situation that user
pressed 'x' from the corner */
event = gdk_event_new(GDK_DELETE);
- ((GdkEventAny *)event)->window = GTK_WIDGET(data)->window;
+ ((GdkEventAny *)event)->window = GDK_WINDOW (g_object_ref (GTK_WIDGET(data)->window));
gtk_main_do_event(event);
+
+ /* That unrefs the window, so we're reffing it above */
gdk_event_free(event);
priv->escape_timeout = 0;
g_return_if_fail (self && HILDON_IS_WINDOW (self));
gtk_container_remove (vbox, GTK_WIDGET(toolbar));
- /* FIXME: As the toolbar border graphics go beyond the VBox, we
- * need to trigger a manual redraw */
- gtk_widget_queue_draw_area (GTK_WIDGET (self) , 0, 0,
- GTK_WIDGET(self)->allocation.width,
- GTK_WIDGET(self)->allocation.height);
}
/**
*
* Sets the menu to be used for this window. This menu overrides
* a program-wide menu that may have been set with
- * hildon_program_set_common_menu.
+ * hildon_program_set_common_menu. Pass NULL to remove the current
+ * menu.
**/
void
hildon_window_set_menu (HildonWindow *self, GtkMenu *menu)
{
- g_return_if_fail (self && HILDON_IS_WINDOW (self) &&
- menu && GTK_IS_MENU (menu));
+ g_return_if_fail (HILDON_IS_WINDOW (self));
- if (self->priv->menu)
- {
+ if (self->priv->menu != NULL) {
+ gtk_menu_detach (GTK_MENU (self->priv->menu));
g_object_unref (self->priv->menu);
}
- self->priv->menu = GTK_WIDGET (menu);
- gtk_widget_set_name (GTK_WIDGET (self->priv->menu),
- "menu_force_with_corners");
- gtk_widget_show_all (self->priv->menu);
+ self->priv->menu = (menu != NULL) ? GTK_WIDGET (menu) : NULL;
+ if (self->priv->menu != NULL) {
+ gtk_widget_set_name (self->priv->menu, "menu_force_with_corners");
+ gtk_menu_attach_to_widget (GTK_MENU (self->priv->menu), GTK_WIDGET (self), &detach_menu_func);
+ g_object_ref (GTK_MENU (self->priv->menu));
+ }
- gtk_menu_attach_to_widget (menu, GTK_WIDGET (self), &detach_menu_func);
+ gtk_widget_show_all (GTK_WIDGET (self));
}
/**