summaryrefslogtreecommitdiffstats
path: root/src/view
diff options
context:
space:
mode:
authorDaniel P. Berrange <berrange@redhat.com>2011-07-01 12:49:38 +0100
committerDaniel P. Berrange <berrange@redhat.com>2011-07-01 12:56:02 +0100
commite37190e75497794d188d3547515cccc9376e5111 (patch)
tree76de59d0dc386d6338cb9b2c48e751c7452bbde2 /src/view
parent72d54bf0fc6c875e87394b2e75dcf8b72202f0be (diff)
downloadvirt-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.c982
-rw-r--r--src/view/autoDrawer.h91
-rw-r--r--src/view/drawer.c364
-rw-r--r--src/view/drawer.h83
-rw-r--r--src/view/ovBox.c943
-rw-r--r--src/view/ovBox.h103
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 */