diff options
author | Daniel P. Berrange <berrange@redhat.com> | 2011-07-01 12:49:38 +0100 |
---|---|---|
committer | Daniel P. Berrange <berrange@redhat.com> | 2011-07-01 12:56:02 +0100 |
commit | e37190e75497794d188d3547515cccc9376e5111 (patch) | |
tree | 76de59d0dc386d6338cb9b2c48e751c7452bbde2 /src/view | |
parent | 72d54bf0fc6c875e87394b2e75dcf8b72202f0be (diff) | |
download | virt-viewer-e37190e75497794d188d3547515cccc9376e5111.tar.gz virt-viewer-e37190e75497794d188d3547515cccc9376e5111.tar.xz virt-viewer-e37190e75497794d188d3547515cccc9376e5111.zip |
Hide menu bar on fullscreen & add a hiding toolbar
* src/Makefile.am, src/view/autoDrawer.c, src/view/autoDrawer.c
src/view/drawer.c, src/view/drawer.h, src/view/ovBox.c,
src/view/ovBox.c: Import auto-drawer from vinagre
* src/viewer-priv.h, src/viewer.c, src/viewer.glade,
src/display-vnc.c: Insert an auto-drawer above the
notebook and display an auto-hiding toolbar when fullscreen
Diffstat (limited to 'src/view')
-rw-r--r-- | src/view/autoDrawer.c | 982 | ||||
-rw-r--r-- | src/view/autoDrawer.h | 91 | ||||
-rw-r--r-- | src/view/drawer.c | 364 | ||||
-rw-r--r-- | src/view/drawer.h | 83 | ||||
-rw-r--r-- | src/view/ovBox.c | 943 | ||||
-rw-r--r-- | src/view/ovBox.h | 103 |
6 files changed, 2566 insertions, 0 deletions
diff --git a/src/view/autoDrawer.c b/src/view/autoDrawer.c new file mode 100644 index 0000000..346dedd --- /dev/null +++ b/src/view/autoDrawer.c @@ -0,0 +1,982 @@ +/* ************************************************************************* + * Copyright (c) 2005 VMware Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * *************************************************************************/ + +/* + * autoDrawer.c - + * + * Subclass of ViewDrawer that encapsulates the behaviour typically required + * when using the drawer to implement a menu/toolbar that auto-opens when + * moused-over and auto-closes when the mouse leaves. + */ + + +#include "autoDrawer.h" + + +struct _ViewAutoDrawerPrivate +{ + gboolean active; + gboolean pinned; + gboolean inputUngrabbed; + + gboolean opened; + gboolean forceClosing; + + gboolean fill; + gint offset; + + guint closeConnection; + guint delayConnection; + guint delayValue; + guint overlapPixels; + guint noOverlapPixels; + + GtkWidget *over; + GtkWidget *evBox; +}; + +#define VIEW_AUTODRAWER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), VIEW_TYPE_AUTODRAWER, ViewAutoDrawerPrivate)) + +/* The unaltered parent class. */ +static ViewDrawerClass *parentClass; + + +/* + *----------------------------------------------------------------------------- + * + * ViewAutoDrawerEnforce -- + * + * Enforce an AutoDrawer's goal now. + * + * Results: + * None + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static void +ViewAutoDrawerEnforce(ViewAutoDrawer *that, // IN + gboolean animate) // IN +{ + double fraction; + GtkAllocation allocation; + ViewAutoDrawerPrivate *priv = that->priv; + + if (!priv->active) { + ViewOvBox_SetMin(VIEW_OV_BOX(that), -1); + ViewOvBox_SetFraction(VIEW_OV_BOX(that), 0); + return; + } + + g_assert(priv->over != NULL); + g_assert(GTK_IS_WIDGET(priv->over)); + + ViewOvBox_SetMin(VIEW_OV_BOX(that), priv->noOverlapPixels); + + // The forceClosing flag overrides the opened flag. + if (priv->opened && !priv->forceClosing) { + fraction = 1; + } else { + gtk_widget_get_allocation (priv->over, &allocation); + fraction = ((double)priv->overlapPixels / allocation.height); + } + + if (!animate) { + ViewOvBox_SetFraction(VIEW_OV_BOX(that), fraction); + } + ViewDrawer_SetGoal(VIEW_DRAWER(that), fraction); +} + + +/* + *----------------------------------------------------------------------------- + * + * ViewAutoDrawerOnEnforceDelay -- + * + * Callback fired when a delayed update happens to update the drawer state. + * + * Results: + * FALSE to indicate timer should not repeat. + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static gboolean +ViewAutoDrawerOnEnforceDelay(ViewAutoDrawer *that) // IN +{ + that->priv->delayConnection = 0; + ViewAutoDrawerEnforce(that, TRUE); + + return FALSE; +} + + +/* + *----------------------------------------------------------------------------- + * + * ViewAutoDrawerOnCloseDelay -- + * + * Callback fired when the drawer is closed manually. This prevents the + * drawer from reopening right away. + * + * Results: + * FALSE to indicate timer should not repeat. + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static gboolean +ViewAutoDrawerOnCloseDelay(ViewAutoDrawer *that) // IN +{ + that->priv->closeConnection = 0; + that->priv->forceClosing = FALSE; + + return FALSE; +} + + +/* + *----------------------------------------------------------------------------- + * + * ViewAutoDrawerUpdate -- + * + * Decide whether an AutoDrawer should be opened or closed, and enforce + * that decision now or later. + * + * Results: + * None + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static void +ViewAutoDrawerUpdate(ViewAutoDrawer *that, // IN + gboolean immediate) // IN +{ + ViewAutoDrawerPrivate *priv = that->priv; + GtkWidget *toplevel = gtk_widget_get_toplevel(GTK_WIDGET(that)); + GtkWindow *window; + GtkAllocation allocation; + + if (!toplevel || !gtk_widget_is_toplevel(toplevel)) { + // The autoDrawer cannot function properly without a toplevel. + return; + } + window = GTK_WINDOW(toplevel); + + /* + * We decide to open the drawer by OR'ing several conditions. Evaluating a + * condition can have the side-effect of setting 'immediate' to TRUE, so we + * cannot stop evaluating the conditions after we have found one to be TRUE. + */ + + priv->opened = FALSE; + + /* Is the AutoDrawer pinned? */ + + if (priv->pinned) { + immediate = TRUE; + + priv->opened = TRUE; + } + + /* Is the mouse cursor inside the event box? */ + + { + int x; + int y; + + gtk_widget_get_pointer(priv->evBox, &x, &y); + gtk_widget_get_allocation(priv->evBox, &allocation); + g_assert(gtk_container_get_border_width( GTK_CONTAINER(priv->evBox)) + == 0); + if ( (guint)x < (guint)allocation.width + && (guint)y < (guint)allocation.height) { + priv->opened = TRUE; + } + } + + /* If there is a focused widget, is it inside the event box? */ + + { + GtkWidget *focus; + + focus = gtk_window_get_focus(window); + if (focus && gtk_widget_is_ancestor(focus, priv->evBox)) { + /* + * Override the default 'immediate' to make sure the 'over' widget + * immediately appears along with the widget the focused widget. + */ + immediate = TRUE; + + priv->opened = TRUE; + } + } + + /* If input is grabbed, is it on behalf of a widget inside the event box? */ + + if (!priv->inputUngrabbed) { + GtkWidget *grabbed = NULL; + + if (gtk_window_has_group (window)) { + GtkWindowGroup *group = gtk_window_get_group (window); + grabbed = gtk_window_group_get_current_grab (group); + } + if (!grabbed) { + grabbed = gtk_grab_get_current(); + } + + if (grabbed && GTK_IS_MENU(grabbed)) { + /* + * With cascading menus, the deepest menu owns the grab. Traverse the + * menu hierarchy up until we reach the attach widget for the whole + * hierarchy. + */ + + for (;;) { + GtkWidget *menuAttach; + GtkWidget *menuItemParent; + + menuAttach = gtk_menu_get_attach_widget(GTK_MENU(grabbed)); + if (!menuAttach) { + /* + * It is unfortunately not mandatory for a menu to have a proper + * attach widget set. + */ + break; + } + + grabbed = menuAttach; + if (!GTK_IS_MENU_ITEM(grabbed)) { + break; + } + + menuItemParent = gtk_widget_get_parent(grabbed); + g_return_if_fail(menuItemParent); + if (!GTK_IS_MENU(menuItemParent)) { + break; + } + + grabbed = menuItemParent; + } + } + + if (grabbed && gtk_widget_is_ancestor(grabbed, priv->evBox)) { + /* + * Override the default 'immediate' to make sure the 'over' widget + * immediately appears along with the widget the grab happens on + * behalf of. + */ + immediate = TRUE; + + priv->opened = TRUE; + } + } + + if (priv->delayConnection) { + g_source_remove(priv->delayConnection); + } + + if (priv->forceClosing) { + ViewAutoDrawerEnforce(that, TRUE); + } else if (immediate) { + ViewAutoDrawerEnforce(that, FALSE); + } else { + priv->delayConnection = g_timeout_add(priv->delayValue, + (GSourceFunc)ViewAutoDrawerOnEnforceDelay, that); + } +} + + +/* + *----------------------------------------------------------------------------- + * + * ViewAutoDrawerOnOverEnterLeave -- + * + * Respond to enter/leave events by doing a delayed update of the drawer + * state. + * + * Results: + * FALSE to indicate event was not handled. + * + * Side effects: + * Will queue delayed update. + * + *----------------------------------------------------------------------------- + */ + +static gboolean +ViewAutoDrawerOnOverEnterLeave(GtkWidget *evBox G_GNUC_UNUSED, // IN: Unused + GdkEventCrossing *event G_GNUC_UNUSED, // IN + ViewAutoDrawer *that) // IN +{ + /* + * This change happens in response to user input. By default, give the user + * some time to correct his input before reacting to the change. + */ + ViewAutoDrawerUpdate(that, FALSE); + + return FALSE; +} + + +/* + *----------------------------------------------------------------------------- + * + * ViewAutoDrawerOnGrabNotify -- + * + * Respond to grab notifications by updating the drawer state. + * + * Results: + * None + * + * Side effects: + * Might queue delayed update. + * + *----------------------------------------------------------------------------- + */ + +static void +ViewAutoDrawerOnGrabNotify(GtkWidget *evBox G_GNUC_UNUSED, // IN: Unused + gboolean ungrabbed, // IN + ViewAutoDrawer *that) // IN +{ + ViewAutoDrawerPrivate *priv = that->priv; + + priv->inputUngrabbed = ungrabbed; + + /* + * This change happens in response to user input. By default, give the user + * some time to correct his input before reacting to the change. + */ + ViewAutoDrawerUpdate(that, FALSE); +} + + +/* + *----------------------------------------------------------------------------- + * + * ViewAutoDrawerOnSetFocus -- + * + * Respond to changes in the focus widget of the autoDrawer's toplevel + * by recalculating the state. + * + * Results: + * None + * + * Side effects: + * Drawer state is updated. + * + *----------------------------------------------------------------------------- + */ + +static void +ViewAutoDrawerOnSetFocus(GtkWindow *window G_GNUC_UNUSED, // IN + GtkWidget *widget G_GNUC_UNUSED, // IN + ViewAutoDrawer *that) // IN +{ + /* + * This change happens in response to user input. By default, give the user + * some time to correct his input before reacting to the change. + */ + ViewAutoDrawerUpdate(that, FALSE); +} + + +/* + *----------------------------------------------------------------------------- + * + * ViewAutoDrawerOnHierarchyChanged -- + * + * Respond to changes in the toplevel for the AutoDrawer. A toplevel is + * required for the AutoDrawer to calculate its state. + * + * Results: + * None + * + * Side effects: + * Drawer state is updated. + * + *----------------------------------------------------------------------------- + */ + +static void +ViewAutoDrawerOnHierarchyChanged(ViewAutoDrawer *that, // IN + GtkWidget *oldToplevel) // IN +{ + GtkWidget *newToplevel = gtk_widget_get_toplevel(GTK_WIDGET(that)); + + if (oldToplevel && gtk_widget_is_toplevel(oldToplevel)) { + g_signal_handlers_disconnect_by_func(oldToplevel, + G_CALLBACK(ViewAutoDrawerOnSetFocus), + that); + } + + if (newToplevel && gtk_widget_is_toplevel(newToplevel)) { + g_signal_connect_after(newToplevel, "set-focus", + G_CALLBACK(ViewAutoDrawerOnSetFocus), that); + } + + /* This change happens programmatically. Always react to it immediately. */ + ViewAutoDrawerUpdate(that, TRUE); +} + + +/* + *----------------------------------------------------------------------------- + * + * ViewAutoDrawerSetOver -- + * + * Virtual method override so that the user's over widget is placed + * inside the AutoDrawer's event box. + * + * Results: + * None + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static void +ViewAutoDrawerSetOver(ViewOvBox *ovBox, // IN + GtkWidget *widget) // IN +{ + ViewAutoDrawer *that = VIEW_AUTODRAWER(ovBox); + ViewAutoDrawerPrivate *priv = that->priv; + GtkWidget *oldChild = gtk_bin_get_child(GTK_BIN(priv->evBox)); + + if (oldChild) { + g_object_ref(oldChild); + gtk_container_remove(GTK_CONTAINER(priv->evBox), oldChild); + } + + if (widget) { + gtk_container_add(GTK_CONTAINER(priv->evBox), widget); + } + + if (oldChild) { + g_object_unref(oldChild); + } + + priv->over = widget; +} + + +/* + *----------------------------------------------------------------------------- + * + * ViewAutoDrawerRefreshPacking -- + * + * Sets the actual packing values for fill, expand, and packing + * given internal settings. + * + * Results: + * None + * + * Side effects: + * Drawer state is updated. + * + *----------------------------------------------------------------------------- + */ + +static void +ViewAutoDrawerRefreshPacking(ViewAutoDrawer *that) // IN +{ + gboolean expand; + gboolean fill; + guint padding; + + expand = (that->priv->fill || (that->priv->offset < 0)); + fill = that->priv->fill; + padding = (expand || fill) ? 0 : that->priv->offset; + + gtk_box_set_child_packing(GTK_BOX(that), that->priv->evBox, + expand, fill, padding, GTK_PACK_START); +} + + +/* + *----------------------------------------------------------------------------- + * + * ViewAutoDrawerInit -- + * + * Initialize a ViewAutoDrawer. + * + * Results: + * None + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static void +ViewAutoDrawerInit(GTypeInstance *instance, // IN + gpointer klass G_GNUC_UNUSED) // Unused +{ + ViewAutoDrawer *that; + ViewAutoDrawerPrivate *priv; + + that = VIEW_AUTODRAWER(instance); + that->priv = VIEW_AUTODRAWER_GET_PRIVATE(that); + priv = that->priv; + + priv->active = TRUE; + priv->pinned = FALSE; + priv->forceClosing = FALSE; + priv->inputUngrabbed = TRUE; + priv->delayConnection = 0; + priv->delayValue = 250; + priv->overlapPixels = 0; + priv->noOverlapPixels = 1; + + priv->fill = TRUE; + priv->offset = -1; + + priv->evBox = gtk_event_box_new(); + gtk_widget_show(priv->evBox); + VIEW_OV_BOX_CLASS(parentClass)->set_over(VIEW_OV_BOX(that), priv->evBox); + + g_signal_connect(priv->evBox, "enter-notify-event", + G_CALLBACK(ViewAutoDrawerOnOverEnterLeave), that); + g_signal_connect(priv->evBox, "leave-notify-event", + G_CALLBACK(ViewAutoDrawerOnOverEnterLeave), that); + g_signal_connect(priv->evBox, "grab-notify", + G_CALLBACK(ViewAutoDrawerOnGrabNotify), that); + + g_signal_connect(that, "hierarchy-changed", + G_CALLBACK(ViewAutoDrawerOnHierarchyChanged), NULL); + + /* This change happens programmatically. Always react to it immediately. */ + ViewAutoDrawerUpdate(that, TRUE); + + ViewAutoDrawerRefreshPacking(that); +} + + +/* + *----------------------------------------------------------------------------- + * + * ViewAutoDrawerFinalize -- + * + * "finalize" method of a ViewAutoDrawer. + * + * Results: + * None + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static void +ViewAutoDrawerFinalize(GObject *object) // IN +{ + ViewAutoDrawer *that; + + that = VIEW_AUTODRAWER(object); + if (that->priv->delayConnection) { + g_source_remove(that->priv->delayConnection); + } + + G_OBJECT_CLASS(parentClass)->finalize(object); +} + + +/* + *----------------------------------------------------------------------------- + * + * ViewAutoDrawerClassInit -- + * + * Initialize the ViewAutoDrawerClass. + * + * Results: + * None + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static void +ViewAutoDrawerClassInit(gpointer klass) // IN +{ + GObjectClass *objectClass = G_OBJECT_CLASS(klass); + ViewOvBoxClass *ovBoxClass = VIEW_OV_BOX_CLASS(klass); + + parentClass = g_type_class_peek_parent(klass); + + objectClass->finalize = ViewAutoDrawerFinalize; + + ovBoxClass->set_over = ViewAutoDrawerSetOver; + + g_type_class_add_private(objectClass, sizeof(ViewAutoDrawerPrivate)); +} + + +/* + *----------------------------------------------------------------------------- + * + * ViewAutoDrawer_GetType -- + * + * Get the (memoized) GType of the ViewAutoDrawer GTK+ object. + * + * Results: + * The GType + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +GType +ViewAutoDrawer_GetType(void) +{ + static GType type = 0; + + if (type == 0) { + static const GTypeInfo info = { + sizeof (ViewAutoDrawerClass), + NULL, /* BaseInit */ + NULL, /* BaseFinalize */ + (GClassInitFunc)ViewAutoDrawerClassInit, + NULL, + NULL, /* Class Data */ + sizeof (ViewAutoDrawer), + 0, /* n_preallocs */ + (GInstanceInitFunc)ViewAutoDrawerInit, + NULL, + }; + + type = g_type_register_static(VIEW_TYPE_DRAWER, "ViewAutoDrawer", &info, 0); + } + + return type; +} + + +/* + *----------------------------------------------------------------------------- + * + * ViewAutoDrawer_New -- + * + * Create a new ViewAutoDrawer GTK+ widget. + * + * Results: + * The widget + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +GtkWidget * +ViewAutoDrawer_New(void) +{ + return GTK_WIDGET(g_object_new(VIEW_TYPE_AUTODRAWER, NULL)); +} + + +/* + *----------------------------------------------------------------------------- + * + * ViewAutoDrawer_SetSlideDelay -- + * + * Set the response time of an AutoDrawer in ms., i.e. the time that + * elapses between: + * - when the AutoDrawer notices a change that can impact the outcome of + * the decision to open or close the drawer, + * and + * - when the AutoDrawer makes such decision. + * + * Users move the mouse inaccurately. If they temporarily move the mouse in + * or out of the AutoDrawer for less than the reponse time, their move will + * be ignored. + * + * Results: + * None + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +void +ViewAutoDrawer_SetSlideDelay(ViewAutoDrawer *that, // IN + guint delay) // IN +{ + g_return_if_fail(VIEW_IS_AUTODRAWER(that)); + + that->priv->delayValue = delay; +} + + +/* + *----------------------------------------------------------------------------- + * + * ViewAutoDrawer_SetOverlapPixels -- + * + * Set the number of pixels that the over widget overlaps the under widget + * when not open. + * + * Results: + * None + * + * Side effects: + * Drawer state is updated. + * + *----------------------------------------------------------------------------- + */ + +void +ViewAutoDrawer_SetOverlapPixels(ViewAutoDrawer *that, // IN + guint overlapPixels) // IN +{ + g_return_if_fail(VIEW_IS_AUTODRAWER(that)); + + that->priv->overlapPixels = overlapPixels; + + /* This change happens programmatically. Always react to it immediately. */ + ViewAutoDrawerUpdate(that, TRUE); +} + + +/* + *----------------------------------------------------------------------------- + * + * ViewAutoDrawer_SetNoOverlapPixels -- + * + * Set the number of pixels that the drawer reserves when not open. The + * over widget does not overlap the under widget over these pixels. + * + * Results: + * None + * + * Side effects: + * Drawer state is updated. + * + *----------------------------------------------------------------------------- + */ + +void +ViewAutoDrawer_SetNoOverlapPixels(ViewAutoDrawer *that, // IN + guint noOverlapPixels) // IN +{ + g_return_if_fail(VIEW_IS_AUTODRAWER(that)); + + that->priv->noOverlapPixels = noOverlapPixels; + + /* This change happens programmatically. Always react to it immediately. */ + ViewAutoDrawerUpdate(that, TRUE); +} + + +/* + *----------------------------------------------------------------------------- + * + * ViewAutoDrawer_SetActive -- + * + * Set whether the AutoDrawer is active or not. That is to say, whether + * it is acting as a drawer or not. When inactive, the over and under + * widget do not overlap and the net result is very much like a vbox. + * + * Results: + * None + * + * Side effects: + * Drawer state is updated. + * + *----------------------------------------------------------------------------- + */ + +void +ViewAutoDrawer_SetActive(ViewAutoDrawer *that, // IN + gboolean active) // IN +{ + g_return_if_fail(VIEW_IS_AUTODRAWER(that)); + + that->priv->active = active; + + /* This change happens programmatically. Always react to it immediately. */ + ViewAutoDrawerUpdate(that, TRUE); +} + + +/* + *----------------------------------------------------------------------------- + * + * ViewAutoDrawer_SetPinned -- + * + * Set whether the AutoDrawer is pinned or not. When pinned, the + * AutoDrawer will stay open regardless of the state of any other inputs. + * + * Results: + * None + * + * Side effects: + * Drawer state is updated. + * + *----------------------------------------------------------------------------- + */ + +void +ViewAutoDrawer_SetPinned(ViewAutoDrawer *that, // IN + gboolean pinned) // IN +{ + g_return_if_fail(VIEW_IS_AUTODRAWER(that)); + + that->priv->pinned = pinned; + + /* + * This change happens in response to user input. By default, give the user + * some time to correct his input before reacting to the change. + */ + ViewAutoDrawerUpdate(that, FALSE); +} + + +/* + *----------------------------------------------------------------------------- + * + * ViewAutoDrawer_SetFill -- + * + * Set whether the Over widget of the AutoDrawer should fill the full + * width of the AutoDrawer or just occupy the minimum space it needs. + * A value of TRUE overrides offset settings. + * + * Results: + * None + * + * Side effects: + * Drawer state is updated. + * + *----------------------------------------------------------------------------- + */ + +void +ViewAutoDrawer_SetFill(ViewAutoDrawer *that, // IN + gboolean fill) // IN +{ + g_return_if_fail(VIEW_IS_AUTODRAWER(that)); + + that->priv->fill = fill; + ViewAutoDrawerRefreshPacking(that); +} + + +/* + *----------------------------------------------------------------------------- + * + * ViewAutoDrawer_SetOffset -- + * + * Set the drawer's X offset, or distance in pixels from the left side. + * If offset is -1, the drawer will be centered. If fill has been set + * TRUE by SetFill, these settings will have no effect. + * + * Results: + * None + * + * Side effects: + * Drawer state is updated. + * + *----------------------------------------------------------------------------- + */ + +void +ViewAutoDrawer_SetOffset(ViewAutoDrawer *that, // IN + gint offset) // IN +{ + g_return_if_fail(VIEW_IS_AUTODRAWER(that)); + + that->priv->offset = offset; + ViewAutoDrawerRefreshPacking(that); +} + + +/* + *----------------------------------------------------------------------------- + * + * ViewAutoDrawer_Close -- + * + * Closes the drawer. This will not unset the pinned state. + * + * Results: + * None + * + * Side effects: + * Drawer state is updated. If there is a focused widget inside the + * drawer, unfocus it. + * + *----------------------------------------------------------------------------- + */ + +void +ViewAutoDrawer_Close(ViewAutoDrawer *that) // IN +{ + GtkWindow *window; + GtkWidget *focus; + GtkWidget *toplevel; + + g_return_if_fail(VIEW_IS_AUTODRAWER(that)); + toplevel = gtk_widget_get_toplevel(GTK_WIDGET(that)); + + if (!toplevel || !gtk_widget_is_toplevel(toplevel)) { + // The autoDrawer cannot function properly without a toplevel. + return; + } + window = GTK_WINDOW(toplevel); + + focus = gtk_window_get_focus(window); + if (focus && gtk_widget_is_ancestor(focus, that->priv->evBox)) { + gtk_window_set_focus(window, NULL); + } + + that->priv->forceClosing = TRUE; + that->priv->closeConnection = + g_timeout_add(ViewDrawer_GetCloseTime(&that->parent) + + that->priv->delayValue, + (GSourceFunc)ViewAutoDrawerOnCloseDelay, that); + + /* This change happens programmatically. Always react to it immediately. */ + ViewAutoDrawerUpdate(that, TRUE); +} diff --git a/src/view/autoDrawer.h b/src/view/autoDrawer.h new file mode 100644 index 0000000..a2fdd54 --- /dev/null +++ b/src/view/autoDrawer.h @@ -0,0 +1,91 @@ +/* ************************************************************************* + * Copyright (c) 2005 VMware Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * *************************************************************************/ + +/* + * autoDrawer.h -- + * + * Declarations for the ViewAutoDrawer GTK+ widget. + */ + + +#ifndef LIBVIEW_AUTODRAWER_H +#define LIBVIEW_AUTODRAWER_H + + +#include "drawer.h" + + +#define VIEW_TYPE_AUTODRAWER (ViewAutoDrawer_GetType()) +#define VIEW_AUTODRAWER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), VIEW_TYPE_AUTODRAWER, ViewAutoDrawer)) +#define VIEW_AUTODRAWER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), VIEW_TYPE_AUTODRAWER, ViewAutoDrawerClass)) +#define VIEW_IS_AUTODRAWER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), VIEW_TYPE_AUTODRAWER)) +#define VIEW_IS_AUTODRAWER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), VIEW_TYPE_AUTODRAWER)) +#define VIEW_AUTODRAWER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), VIEW_TYPE_AUTODRAWER, ViewAutoDrawerClass)) + +typedef struct _ViewAutoDrawerPrivate ViewAutoDrawerPrivate; + +typedef struct _ViewAutoDrawer { + /* Must come first. */ + ViewDrawer parent; + + /* Private. */ + ViewAutoDrawerPrivate *priv; +} ViewAutoDrawer; + +typedef struct _ViewAutoDrawerClass { + /* Must come first. */ + ViewDrawerClass parent; + + /* Padding for future expansion */ + void (*_view_reserved0)(void); + void (*_view_reserved1)(void); + void (*_view_reserved2)(void); + void (*_view_reserved3)(void); +} ViewAutoDrawerClass; + + +G_BEGIN_DECLS + + +GType ViewAutoDrawer_GetType(void); + +GtkWidget *ViewAutoDrawer_New(void); + +void ViewAutoDrawer_SetSlideDelay(ViewAutoDrawer *that, guint delay); +void ViewAutoDrawer_SetOverlapPixels(ViewAutoDrawer *that, guint overlapPixels); +void ViewAutoDrawer_SetNoOverlapPixels(ViewAutoDrawer *that, guint noOverlapPixels); + +void ViewAutoDrawer_SetActive(ViewAutoDrawer *that, gboolean active); + +void ViewAutoDrawer_SetPinned(ViewAutoDrawer *that, gboolean pinned); + +void ViewAutoDrawer_SetFill(ViewAutoDrawer *that, gboolean fill); + +void ViewAutoDrawer_SetOffset(ViewAutoDrawer *that, gint offset); + +void ViewAutoDrawer_Close(ViewAutoDrawer *that); + +G_END_DECLS + + +#endif /* LIBVIEW_AUTODRAWER_H */ diff --git a/src/view/drawer.c b/src/view/drawer.c new file mode 100644 index 0000000..aec0728 --- /dev/null +++ b/src/view/drawer.c @@ -0,0 +1,364 @@ +/* ************************************************************************* + * Copyright (c) 2005 VMware, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * *************************************************************************/ + +/* + * drawer.c - + * + * Implementation of a GTK+ drawer, i.e. a widget that opens and closes by + * sliding smoothly, at constant speed, over another one. + */ + + +#include "drawer.h" + + +struct _ViewDrawerPrivate +{ + unsigned int period; + double step; + double goal; + struct { + gboolean pending; + guint id; + } timer; +}; + +#define VIEW_DRAWER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), VIEW_TYPE_DRAWER, ViewDrawerPrivate)) + +/* The unaltered parent class. */ +static ViewOvBoxClass *parentClass; + + +/* + *----------------------------------------------------------------------------- + * + * ViewDrawerInit -- + * + * Initialize a ViewDrawer. + * + * Results: + * None + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static void +ViewDrawerInit(GTypeInstance *instance, // IN + gpointer klass) // Unused +{ + ViewDrawer *that; + + that = VIEW_DRAWER(instance); + that->priv = VIEW_DRAWER_GET_PRIVATE(that); + + that->priv->period = 10; + that->priv->step = 0.2; + that->priv->timer.pending = FALSE; +} + + +/* + *----------------------------------------------------------------------------- + * + * ViewDrawerFinalize -- + * + * "finalize" method of a ViewOvBox. + * + * Results: + * None + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static void +ViewDrawerFinalize(GObject *object) // IN +{ + ViewDrawer *that; + ViewDrawerPrivate *priv; + + that = VIEW_DRAWER(object); + priv = that->priv; + + if (priv->timer.pending) { + g_source_remove(priv->timer.id); + priv->timer.pending = FALSE; + } + + G_OBJECT_CLASS(parentClass)->finalize(object); +} + + +/* + *----------------------------------------------------------------------------- + * + * ViewDrawerClassInit -- + * + * Initialize the ViewDrawerClass. + * + * Results: + * None + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static void +ViewDrawerClassInit(gpointer klass) // IN +{ + GObjectClass *objectClass = G_OBJECT_CLASS(klass); + + parentClass = g_type_class_peek_parent(klass); + + objectClass->finalize = ViewDrawerFinalize; + + g_type_class_add_private(objectClass, sizeof(ViewDrawerPrivate)); +} + + +/* + *----------------------------------------------------------------------------- + * + * ViewDrawer_GetType -- + * + * Get the (memoized) GType of the ViewDrawer GTK+ object. + * + * Results: + * The GType + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +GType +ViewDrawer_GetType(void) +{ + static GType type = 0; + + if (type == 0) { + static const GTypeInfo info = { + sizeof (ViewDrawerClass), + NULL, /* BaseInit */ + NULL, /* BaseFinalize */ + (GClassInitFunc)ViewDrawerClassInit, + NULL, + NULL, /* Class Data */ + sizeof (ViewDrawer), + 0, /* n_preallocs */ + (GInstanceInitFunc)ViewDrawerInit, + }; + + type = g_type_register_static(VIEW_TYPE_OV_BOX, "ViewDrawer", &info, 0); + } + + return type; +} + + +/* + *----------------------------------------------------------------------------- + * + * ViewDrawer_New -- + * + * Create a new ViewDrawer GTK+ widget. + * + * Results: + * The widget + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +GtkWidget * +ViewDrawer_New(void) +{ + ViewDrawer *that; + + that = VIEW_DRAWER(g_object_new(VIEW_TYPE_DRAWER, NULL)); + + return GTK_WIDGET(that); +} + + +/* + *----------------------------------------------------------------------------- + * + * ViewDrawerOnTimer -- + * + * Timer callback of a ViewDrawer. If we have reached the goal, deschedule + * the timer. Otherwise make progress towards the goal, and keep the timer + * scheduled. + * + * Results: + * TRUE if the timer must be rescheduled. + * FALSE if the timer must not be rescheduled. + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static gint +ViewDrawerOnTimer(gpointer data) // IN +{ + ViewDrawer *that; + ViewDrawerPrivate *priv; + double fraction; + + that = VIEW_DRAWER(data); + priv = that->priv; + + fraction = ViewOvBox_GetFraction(VIEW_OV_BOX(that)); + /* + * Comparing double values with '==' is most of the time a bad idea, due to + * the inexact representation of values in binary (see + * http://www2.hursley.ibm.com/decimal/decifaq1.html and http://boost.org/libs/test/doc/components/test_tools/floating_point_comparison.html). + * But in this particular case it is legitimate. --hpreg + */ + if (priv->goal == fraction) { + return priv->timer.pending = FALSE; + } + + ViewOvBox_SetFraction(VIEW_OV_BOX(that), + priv->goal > fraction + ? MIN(fraction + priv->step, priv->goal) + : MAX(fraction - priv->step, priv->goal)); + return TRUE; +} + + +/* + *----------------------------------------------------------------------------- + * + * ViewDrawer_SetSpeed -- + * + * Set the 'period' (in ms.) and 'step' properties of a ViewDrawer, which + * determine the speed and smoothness of the drawer's motion. + * + * Results: + * None + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +void +ViewDrawer_SetSpeed(ViewDrawer *that, // IN + unsigned int period, // IN + double step) // IN +{ + ViewDrawerPrivate *priv; + + g_return_if_fail(that != NULL); + + priv = that->priv; + + priv->period = period; + if (priv->timer.pending) { + g_source_remove(priv->timer.id); + priv->timer.id = g_timeout_add(priv->period, ViewDrawerOnTimer, that); + } + priv->step = step; +} + + +/* + *----------------------------------------------------------------------------- + * + * ViewDrawer_SetGoal -- + * + * Set the 'goal' property of a ViewDrawer, i.e. how much the drawer should + * be opened when it is done sliding. + * + * Results: + * None + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +void +ViewDrawer_SetGoal(ViewDrawer *that, // IN + double goal) // IN +{ + ViewDrawerPrivate *priv; + + g_return_if_fail(that != NULL); + g_return_if_fail(goal >= 0 && goal <= 1); + + priv = that->priv; + + priv->goal = goal; + if (priv->timer.pending == FALSE) { + priv->timer.id = g_timeout_add(priv->period, ViewDrawerOnTimer, that); + priv->timer.pending = TRUE; + } +} + + +/* + *----------------------------------------------------------------------------- + * + * ViewDrawer_GetCloseTime -- + * + * Get the approximate amount of time it will take for this drawer to + * open and close, in ms. + * + * Results: + * The time it takes to open or close the drawer. + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +int +ViewDrawer_GetCloseTime(ViewDrawer *that) +{ + ViewDrawerPrivate *priv; + + if (that == NULL) { + return 0; + } + + priv = that->priv; + + return priv->period * ((int)(1/priv->step) + 1); +} diff --git a/src/view/drawer.h b/src/view/drawer.h new file mode 100644 index 0000000..12964a2 --- /dev/null +++ b/src/view/drawer.h @@ -0,0 +1,83 @@ +/* ************************************************************************* + * Copyright (c) 2005 VMware, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * *************************************************************************/ + +/* + * drawer.h -- + * + * Declarations for the ViewDrawer GTK+ widget. + */ + + +#ifndef LIBVIEW_DRAWER_H +#define LIBVIEW_DRAWER_H + + +#include "ovBox.h" + + +#define VIEW_TYPE_DRAWER (ViewDrawer_GetType()) +#define VIEW_DRAWER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), VIEW_TYPE_DRAWER, ViewDrawer)) +#define VIEW_DRAWER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), VIEW_TYPE_DRAWER, ViewDrawerClass)) +#define VIEW_IS_DRAWER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), VIEW_TYPE_DRAWER)) +#define VIEW_IS_DRAWER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), VIEW_TYPE_DRAWER)) +#define VIEW_DRAWER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), VIEW_TYPE_DRAWER, ViewDrawerClass)) + +typedef struct _ViewDrawerPrivate ViewDrawerPrivate; + +typedef struct _ViewDrawer { + /* Must come first. */ + ViewOvBox parent; + + /* Private. */ + ViewDrawerPrivate *priv; +} ViewDrawer; + + +typedef struct _ViewDrawerClass { + /* Must come first. */ + ViewOvBoxClass parent; + + /* Padding for future expansion */ + void (*_view_reserved0)(void); + void (*_view_reserved1)(void); + void (*_view_reserved2)(void); + void (*_view_reserved3)(void); +} ViewDrawerClass; + + +G_BEGIN_DECLS + + +GType ViewDrawer_GetType(void); + +GtkWidget *ViewDrawer_New(void); + +void ViewDrawer_SetSpeed(ViewDrawer *that, unsigned int period, double step); +void ViewDrawer_SetGoal(ViewDrawer *that, double fraction); +int ViewDrawer_GetCloseTime(ViewDrawer *that); + + +G_END_DECLS + + +#endif /* LIBVIEW_DRAWER_H */ diff --git a/src/view/ovBox.c b/src/view/ovBox.c new file mode 100644 index 0000000..955c20b --- /dev/null +++ b/src/view/ovBox.c @@ -0,0 +1,943 @@ +/* ************************************************************************* + * Copyright (c) 2005 VMware, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * *************************************************************************/ + +/* + * ovBox.c -- + * + * Implementation of a GTK+ overlapping box. Allows you to display and + * quickly move a child that overlaps another child. + * + * Implementation notes + * -------------------- + * + * Changing 'fraction' is fast (we just move the 'overWin' X window, which + * ultimately copies a rectangle on the X server side), and does not + * flicker (the 'under' and 'over' GTK children are not re-drawn, except + * for parts of them that become exposed). + * + * o Initially, we thought it could be done with only 2 X windows + * + * Layout Hierarchy + * ------ --------- + * + * /- overWin --\ underWin + * | | overWin + * /-+- underWin -+-\ + * | | | | + * | \------------/ | + * | | + * \----------------/ + * + * But the 'under' GTK child could create other X windows inside + * 'underWin', which makes it impossible to guarantee that 'overWin' + * will stay stacked on top. + * + * o So we are forced to use 3 X windows + * + * Layout Hierarchy + * ------ --------- + * + * /- overWin --\ window + * | | overWin + * /---+- window ---+---\ underWin + * | | | | + * | /-+- underWin -+-\ | + * | | | | | | + * | | \------------/ | | + * | | | | + * | \----------------/ | + * | | + * \--------------------/ + * + * --hpreg + */ + + +#include "ovBox.h" + + +struct _ViewOvBoxPrivate +{ + GdkWindow *underWin; + GtkWidget *under; + GdkWindow *overWin; + GtkWidget *over; + GtkRequisition overR; + unsigned int min; + double fraction; + gint verticalOffset; +}; + +#define VIEW_OV_BOX_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), VIEW_TYPE_OV_BOX, ViewOvBoxPrivate)) + +/* The unaltered parent class. */ +static GtkBoxClass *parentClass; + + +/* + *----------------------------------------------------------------------------- + * + * ViewOvBoxInit -- + * + * Initialize a ViewOvBox. + * + * Results: + * None + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static void +ViewOvBoxInit(GTypeInstance *instance, // IN + gpointer klass G_GNUC_UNUSED) // Unused +{ + ViewOvBox *that; + ViewOvBoxPrivate *priv; + + that = VIEW_OV_BOX(instance); + that->priv = VIEW_OV_BOX_GET_PRIVATE(that); + priv = that->priv; + + gtk_widget_set_has_window (GTK_WIDGET (that), TRUE); + + priv->underWin = NULL; + priv->under = NULL; + priv->overWin = NULL; + priv->over = NULL; + priv->overR.height = -1; + priv->overR.width = -1; + priv->min = 0; + priv->fraction = 0; + priv->verticalOffset = 0; +} + + +/* + *----------------------------------------------------------------------------- + * + * ViewOvBoxMap -- + * + * "map" method of a ViewOvBox. + * + * Results: + * None + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static void +ViewOvBoxMap(GtkWidget *widget) // IN +{ + gdk_window_show(gtk_widget_get_window (widget)); + GTK_WIDGET_CLASS(parentClass)->map(widget); +} + + +/* + *----------------------------------------------------------------------------- + * + * ViewOvBoxUnmap -- + * + * "unmap" method of a ViewOvBox. + * + * Results: + * None + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static void +ViewOvBoxUnmap(GtkWidget *widget) // IN +{ + gdk_window_hide(gtk_widget_get_window (widget)); + GTK_WIDGET_CLASS(parentClass)->unmap(widget); +} + + +/* + *----------------------------------------------------------------------------- + * + * ViewOvBoxGetActualMin -- + * + * Retrieve the actual 'min' value, i.e. a value that is guaranteed not to + * exceed the height of the 'over' child. + * + * Results: + * The actual 'min' value. + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static inline unsigned int +ViewOvBoxGetActualMin(ViewOvBox *that) // IN +{ + return MIN(that->priv->min, that->priv->overR.height); +} + + +/* + *----------------------------------------------------------------------------- + * + * ViewOvBoxGetUnderGeometry -- + * + * Retrieve the geometry to apply to 'that->underWin'. + * + * Results: + * The geometry + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static void +ViewOvBoxGetUnderGeometry(ViewOvBox *that, // IN + int *x, // OUT + int *y, // OUT + int *width, // OUT + int *height) // OUT +{ + unsigned int min; + GtkAllocation allocation; + + min = ViewOvBoxGetActualMin(that); + gtk_widget_get_allocation (GTK_WIDGET(that), &allocation); + + *x = 0; + *y = min; + *width = allocation.width; + *height = allocation.height - min; +} + + +/* + *----------------------------------------------------------------------------- + * + * ViewOvBoxGetOverGeometry -- + * + * Retrieve the geometry to apply to 'that->overWin'. + * + * Results: + * The geometry + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static void +ViewOvBoxGetOverGeometry(ViewOvBox *that, // IN + int *x, // OUT + int *y, // OUT + int *width, // OUT + int *height) // OUT +{ + ViewOvBoxPrivate *priv; + gboolean expand; + gboolean fill; + guint padding; + unsigned int boxWidth; + GtkAllocation allocation; + + priv = that->priv; + + if (priv->over) { + /* + * When a child's expand or fill property changes, GtkBox queues + * a resize for the child. + */ + gtk_container_child_get(GTK_CONTAINER(that), priv->over, + "expand", &expand, + "fill", &fill, + "padding", &padding, + NULL); + } else { + /* Default values used by GtkBox. */ + expand = TRUE; + fill = TRUE; + padding = 0; + } + + gtk_widget_get_allocation(GTK_WIDGET(that), &allocation); + boxWidth = allocation.width; + if (!expand) { + *width = MIN(priv->overR.width, boxWidth - padding); + *x = padding; + } else if (!fill) { + *width = MIN(priv->overR.width, boxWidth); + *x = (boxWidth - *width) / 2; + } else { + *width = boxWidth; + *x = 0; + } + + *y = (priv->overR.height - ViewOvBoxGetActualMin(that)) + * (priv->fraction - 1) + priv->verticalOffset; + *height = priv->overR.height; +} + + +/* + *----------------------------------------------------------------------------- + * + * ViewOvBoxSetBackground -- + * + * Set the background color of the 'underWin' and 'overWin' X windows. + * + * Results: + * None + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static void +ViewOvBoxSetBackground(ViewOvBox *that) // IN +{ + GtkWidget *widget; + GtkStyle *style; + + widget = GTK_WIDGET(that); + style = gtk_widget_get_style (widget); + gtk_style_set_background(style, gtk_widget_get_window(widget), GTK_STATE_NORMAL); + gtk_style_set_background(style, that->priv->underWin, GTK_STATE_NORMAL); + gtk_style_set_background(style, that->priv->overWin, GTK_STATE_NORMAL); +} + + +/* + *----------------------------------------------------------------------------- + * + * ViewOvBoxRealize -- + * + * "realize" method of a ViewOvBox. + * + * Results: + * None + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static void +ViewOvBoxRealize(GtkWidget *widget) // IN +{ + ViewOvBox *that; + ViewOvBoxPrivate *priv; + GdkWindowAttr attributes; + gint mask; + GtkAllocation allocation; + GdkWindow *window; + + gtk_widget_set_realized (widget, TRUE); + + that = VIEW_OV_BOX(widget); + priv = that->priv; + + attributes.window_type = GDK_WINDOW_CHILD; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gtk_widget_get_visual(widget); + attributes.event_mask = gtk_widget_get_events(widget) | GDK_EXPOSURE_MASK; + mask = GDK_WA_VISUAL | GDK_WA_X | GDK_WA_Y; + + gtk_widget_get_allocation(widget, &allocation); + attributes.x = allocation.x; + attributes.y = allocation.y; + attributes.width = allocation.width; + attributes.height = allocation.height; + window = gdk_window_new(gtk_widget_get_parent_window(widget), + &attributes, mask); + gtk_widget_set_window(widget, window); + gdk_window_set_user_data(window, that); + gtk_widget_set_style(widget, gtk_style_attach(gtk_widget_get_style(widget), window)); + + /* + * The order in which we create the children X window matters: the child + * created last is stacked on top. --hpreg + */ + + ViewOvBoxGetUnderGeometry(that, &attributes.x, &attributes.y, + &attributes.width, &attributes.height); + priv->underWin = gdk_window_new(window, &attributes, mask); + gdk_window_set_user_data(priv->underWin, that); + if (priv->under) { + gtk_widget_set_parent_window(priv->under, priv->underWin); + } + gdk_window_show(priv->underWin); + + ViewOvBoxGetOverGeometry(that, &attributes.x, &attributes.y, + &attributes.width, &attributes.height); + priv->overWin = gdk_window_new(window, &attributes, mask); + gdk_window_set_user_data(priv->overWin, that); + if (priv->over) { + gtk_widget_set_parent_window(priv->over, priv->overWin); + } + gdk_window_show(priv->overWin); + + ViewOvBoxSetBackground(that); +} + + +/* + *----------------------------------------------------------------------------- + * + * ViewOvBoxUnrealize -- + * + * "unrealize" method of a ViewOvBox. + * + * Results: + * None + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static void +ViewOvBoxUnrealize(GtkWidget *widget) // IN +{ + ViewOvBox *that; + ViewOvBoxPrivate *priv; + + that = VIEW_OV_BOX(widget); + priv = that->priv; + + /* + * Unrealize the parent before destroying the windows so that we end up + * unrealizing all the child widgets before destroying the child windows, + * giving them a chance to reparent their windows before we clobber them. + */ + GTK_WIDGET_CLASS(parentClass)->unrealize(widget); + + + gdk_window_set_user_data(priv->underWin, NULL); + gdk_window_destroy(priv->underWin); + priv->underWin = NULL; + + gdk_window_set_user_data(priv->overWin, NULL); + gdk_window_destroy(priv->overWin); + priv->overWin = NULL; + +} + + +/* + *----------------------------------------------------------------------------- + * + * ViewOvBoxSizeRequest -- + * + * "size_request" method of a ViewOvBox. + * + * Results: + * None + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static void +ViewOvBoxSizeRequest(GtkWidget *widget, // IN + GtkRequisition *requisition) // OUT +{ + ViewOvBox *that; + ViewOvBoxPrivate *priv; + GtkRequisition underR; + gboolean expand; + gboolean fill; + guint padding; + unsigned int min; + + that = VIEW_OV_BOX(widget); + priv = that->priv; + + gtk_widget_size_request(priv->under, &underR); + gtk_widget_size_request(priv->over, &priv->overR); + + gtk_container_child_get(GTK_CONTAINER(that), priv->over, + "expand", &expand, + "fill", &fill, + "padding", &padding, + NULL); + requisition->width = MAX(underR.width, + priv->overR.width + ((expand || fill) ? 0 : padding)); + min = ViewOvBoxGetActualMin(that); + requisition->height = MAX(underR.height + min, priv->overR.height); +} + +#ifdef WITH_GTK3 +static void +ViewOvBox_get_preferred_width (GtkWidget *widget, + gint *minimal_width, + gint *natural_width) +{ + GtkRequisition requisition; + + ViewOvBoxSizeRequest (widget, &requisition); + + *minimal_width = *natural_width = requisition.width; +} + +static void +ViewOvBox_get_preferred_height (GtkWidget *widget, + gint *minimal_height, + gint *natural_height) +{ + GtkRequisition requisition; + + ViewOvBoxSizeRequest (widget, &requisition); + + *minimal_height = *natural_height = requisition.height; +} +#else +#endif + + +/* + *----------------------------------------------------------------------------- + * + * ViewOvBoxSizeAllocate -- + * + * "size_allocate" method of a ViewOvBox. + * + * Results: + * None + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static void +ViewOvBoxSizeAllocate(GtkWidget *widget, // IN + GtkAllocation *allocation) // IN +{ + ViewOvBox *that; + ViewOvBoxPrivate *priv; + GtkAllocation under; + GtkAllocation over; + + gtk_widget_set_allocation (widget, allocation); + + that = VIEW_OV_BOX(widget); + priv = that->priv; + + ViewOvBoxGetUnderGeometry(that, &under.x, &under.y, &under.width, + &under.height); + ViewOvBoxGetOverGeometry(that, &over.x, &over.y, &over.width, &over.height); + + if (gtk_widget_get_realized(widget)) { + gdk_window_move_resize(gtk_widget_get_window(widget), + allocation->x, allocation->y, + allocation->width, allocation->height); + gdk_window_move_resize(priv->underWin, under.x, under.y, under.width, + under.height); + gdk_window_move_resize(priv->overWin, over.x, over.y, over.width, + over.height); + } + + under.x = 0; + under.y = 0; + gtk_widget_size_allocate(priv->under, &under); + over.x = 0; + over.y = 0; + gtk_widget_size_allocate(priv->over, &over); +} + + +/* + *----------------------------------------------------------------------------- + * + * ViewOvBoxStyleSet -- + * + * "style_set" method of a ViewOvBox. + * + * Results: + * None + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static void +ViewOvBoxStyleSet(GtkWidget *widget, // IN + GtkStyle *previousStyle) // IN: Unused +{ + ViewOvBox *that; + + that = VIEW_OV_BOX(widget); + + if (gtk_widget_get_realized(widget)) { + ViewOvBoxSetBackground(that); + } + + GTK_WIDGET_CLASS(parentClass)->style_set(widget, previousStyle); +} + + +/* + *----------------------------------------------------------------------------- + * + * ViewOvBoxSetChild -- + * + * Set a child of a ViewOvBox. + * + * Results: + * None + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static void +ViewOvBoxSetChild(ViewOvBox *that, // IN + GtkWidget **child, // IN + GdkWindow *childWin, // IN + GtkWidget *widget) // IN +{ + GtkWidget *oldChild = *child; + + if (oldChild) { + g_object_ref(oldChild); + gtk_container_remove(GTK_CONTAINER(that), oldChild); + } + + *child = widget; + if (*child) { + gtk_widget_set_parent_window(widget, childWin); + gtk_container_add(GTK_CONTAINER(that), *child); + } + + if (oldChild) { + g_object_unref(oldChild); + } +} + + +/* + *----------------------------------------------------------------------------- + * + * ViewOvBoxSetOver -- + * + * Base implementation of ViewOvBox_SetOver. + * + * Results: + * None + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static void +ViewOvBoxSetOver(ViewOvBox *that, // IN + GtkWidget *widget) // IN +{ + ViewOvBoxSetChild(that, &that->priv->over, that->priv->overWin, widget); +} + + +/* + *----------------------------------------------------------------------------- + * + * ViewOvBoxClassInit -- + * + * Initialize the ViewOvBoxClass. + * + * Results: + * None + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static void +ViewOvBoxClassInit(ViewOvBoxClass *klass) // IN +{ + GObjectClass *objectClass; + GtkWidgetClass *widgetClass; + + objectClass = G_OBJECT_CLASS(klass); + widgetClass = GTK_WIDGET_CLASS(klass); + + widgetClass->map = ViewOvBoxMap; + widgetClass->unmap = ViewOvBoxUnmap; + widgetClass->realize = ViewOvBoxRealize; + widgetClass->unrealize = ViewOvBoxUnrealize; +#if WITH_GTK3 + widgetClass->get_preferred_width = ViewOvBox_get_preferred_width; + widgetClass->get_preferred_height = ViewOvBox_get_preferred_height; +#else + widgetClass->size_request = ViewOvBoxSizeRequest; +#endif + widgetClass->size_allocate = ViewOvBoxSizeAllocate; + widgetClass->style_set = ViewOvBoxStyleSet; + + klass->set_over = ViewOvBoxSetOver; + + parentClass = g_type_class_peek_parent(klass); + + g_type_class_add_private(objectClass, sizeof(ViewOvBoxPrivate)); +} + + +/* + *----------------------------------------------------------------------------- + * + * ViewOvBox_GetType -- + * + * Get the (memoized) GType of the ViewOvBox GTK+ object. + * + * Results: + * The GType + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +GType +ViewOvBox_GetType(void) +{ + static GType type = 0; + + if (type == 0) { + static const GTypeInfo info = { + sizeof (ViewOvBoxClass), + NULL, /* BaseInit */ + NULL, /* BaseFinalize */ + (GClassInitFunc)ViewOvBoxClassInit, + NULL, + NULL, /* Class Data */ + sizeof (ViewOvBox), + 0, /* n_preallocs */ + (GInstanceInitFunc)ViewOvBoxInit, + NULL, + }; + + type = g_type_register_static(GTK_TYPE_BOX, "ViewOvBox", &info, 0); + } + + return type; +} + + +/* + *----------------------------------------------------------------------------- + * + * ViewOvBox_New -- + * + * Create a new ViewOvBox GTK+ widget. + * + * Results: + * The widget + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +GtkWidget * +ViewOvBox_New(void) +{ + ViewOvBox *that; + + that = VIEW_OV_BOX(g_object_new(VIEW_TYPE_OV_BOX, NULL)); + + return GTK_WIDGET(that); +} + + +/* + *----------------------------------------------------------------------------- + * + * ViewOvBox_SetUnder -- + * + * Set the under widget of a ViewOvBox. + * + * Results: + * None + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +void +ViewOvBox_SetUnder(ViewOvBox *that, // IN + GtkWidget *widget) // IN +{ + g_return_if_fail(that != NULL); + + ViewOvBoxSetChild(that, &that->priv->under, that->priv->underWin, widget); +} + + +/* + *----------------------------------------------------------------------------- + * + * ViewOvBox_SetOver -- + * + * Set the over widget of a ViewOvBox. + * + * Results: + * None + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +void +ViewOvBox_SetOver(ViewOvBox *that, // IN + GtkWidget *widget) // IN +{ + g_return_if_fail(that != NULL); + + VIEW_OV_BOX_GET_CLASS(that)->set_over(that, widget); +} + + +/* + *----------------------------------------------------------------------------- + * + * ViewOvBox_SetMin -- + * + * Set the 'min' property of a ViewOvBox, i.e. the number of pixel of the + * 'over' child that should always be displayed without overlapping on the + * 'under' child. + * + * Using a value of -1 displays the 'over' child entirely. + * + * Results: + * None + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +void +ViewOvBox_SetMin(ViewOvBox *that, // IN + unsigned int min) // IN +{ + g_return_if_fail(that != NULL); + + that->priv->min = min; + gtk_widget_queue_resize(GTK_WIDGET(that)); +} + + +/* + *----------------------------------------------------------------------------- + * + * ViewOvBox_SetFraction -- + * + * Set the 'fraction' property of a ViewOvBox, i.e. how much of the 'over' + * child should overlap on the 'under' child. + * + * Results: + * None + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +void +ViewOvBox_SetFraction(ViewOvBox *that, // IN + double fraction) // IN +{ + g_return_if_fail(that != NULL); + g_return_if_fail(fraction >=0 && fraction <= 1); + + that->priv->fraction = fraction; + if (gtk_widget_get_realized(GTK_WIDGET (that))) { + int x; + int y; + int width; + int height; + + ViewOvBoxGetOverGeometry(that, &x, &y, &width, &height); + gdk_window_move(that->priv->overWin, x, y); + } +} + + +/* + *----------------------------------------------------------------------------- + * + * ViewOvBox_GetFraction -- + * + * Retrieve the 'fraction' property of a ViewOvBox. + * + * Results: + * The value + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +double +ViewOvBox_GetFraction(ViewOvBox *that) +{ + g_return_val_if_fail(that != NULL, 0); + + return that->priv->fraction; +} diff --git a/src/view/ovBox.h b/src/view/ovBox.h new file mode 100644 index 0000000..4fa61fd --- /dev/null +++ b/src/view/ovBox.h @@ -0,0 +1,103 @@ +/* ************************************************************************* + * Copyright (c) 2005 VMware, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * *************************************************************************/ + +/* + * ovBox.h -- + * + * Declarations for the ViewOvBox GTK+ widget. + */ + + +#ifndef LIBVIEW_OVBOX_H +#define LIBVIEW_OVBOX_H + + +#include <gtk/gtk.h> + + +#define VIEW_TYPE_OV_BOX (ViewOvBox_GetType()) +#define VIEW_OV_BOX(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), VIEW_TYPE_OV_BOX, ViewOvBox)) +#define VIEW_OV_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), VIEW_TYPE_OV_BOX, ViewOvBoxClass)) +#define VIEW_IS_OV_BOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), VIEW_TYPE_OV_BOX)) +#define VIEW_IS_OV_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), VIEW_TYPE_OV_BOX)) +#define VIEW_OV_BOX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), VIEW_TYPE_OV_BOX, ViewOvBoxClass)) + +typedef struct _ViewOvBoxPrivate ViewOvBoxPrivate; + +typedef struct _ViewOvBox { + /* Must come first. */ + GtkBox parent; + + /* Private. */ + ViewOvBoxPrivate *priv; +} ViewOvBox; + + +typedef struct _ViewOvBoxClass { + /* Must come first. */ + GtkBoxClass parent; + + /* Virtual methods. */ + void (* set_over)(ViewOvBox *ovBox, GtkWidget *widget); + + /* Padding for future expansion */ + void (*_view_reserved0)(void); + void (*_view_reserved1)(void); + void (*_view_reserved2)(void); + void (*_view_reserved3)(void); +} ViewOvBoxClass; + + +G_BEGIN_DECLS + + +GType +ViewOvBox_GetType(void); + +GtkWidget * +ViewOvBox_New(void); + +void +ViewOvBox_SetUnder(ViewOvBox *that, + GtkWidget *widget); + +void +ViewOvBox_SetOver(ViewOvBox *that, + GtkWidget *widget); + +void +ViewOvBox_SetMin(ViewOvBox *that, + unsigned int min); + +void +ViewOvBox_SetFraction(ViewOvBox *that, + double fraction); + +double +ViewOvBox_GetFraction(ViewOvBox *that); + + +G_END_DECLS + + +#endif /* LIBVIEW_OVBOX_H */ |