vinagre r341 - in trunk: . src src/view



Author: jwendell
Date: Thu May 29 17:08:54 2008
New Revision: 341
URL: http://svn.gnome.org/viewvc/vinagre?rev=341&view=rev

Log:
2008-05-29  Jonh Wendell <jwendell gnome org>

	Fixed bug #522100 - Provide option to leave fullscreen mode


Added:
   trunk/src/view/   (props changed)
   trunk/src/view/Makefile.am
   trunk/src/view/autoDrawer.c
   trunk/src/view/autoDrawer.h
   trunk/src/view/drawer.c
   trunk/src/view/drawer.h
   trunk/src/view/ovBox.c
   trunk/src/view/ovBox.h
Modified:
   trunk/ChangeLog
   trunk/configure.ac
   trunk/src/Makefile.am
   trunk/src/vinagre-commands.c
   trunk/src/vinagre-tab.c
   trunk/src/vinagre-window.c
   trunk/src/vinagre-window.h

Modified: trunk/configure.ac
==============================================================================
--- trunk/configure.ac	(original)
+++ trunk/configure.ac	Thu May 29 17:08:54 2008
@@ -86,6 +86,7 @@
 help/Makefile
 po/Makefile.in
 src/Makefile
+src/view/Makefile
 ])
 
 #*******************************************************************************

Modified: trunk/src/Makefile.am
==============================================================================
--- trunk/src/Makefile.am	(original)
+++ trunk/src/Makefile.am	Thu May 29 17:08:54 2008
@@ -1,4 +1,6 @@
-NULL =
+SUBDIRS = view
+
+NULL = 
 
 INCLUDES = 						\
 	-DBINDIR=\"$(bindir)\"			 	\
@@ -37,6 +39,7 @@
 vinagre_LDADD = \
 	$(VINAGRE_LIBS)		\
 	$(GTKVNC_LIBS)		\
+	view/libview.la		\
 	$(NULL)
 
 vinagre_enum_headers = \

Added: trunk/src/view/Makefile.am
==============================================================================
--- (empty file)
+++ trunk/src/view/Makefile.am	Thu May 29 17:08:54 2008
@@ -0,0 +1,17 @@
+NULL = 
+
+INCLUDES =                                  \
+        -I$(top_srcdir)                     \
+        -I$(top_builddir)                   \
+        -I$(top_srcdir)/src                 \
+        -I$(top_builddir)/src               \
+        $(VINAGRE_CFLAGS)                   \
+        $(NULL)
+
+noinst_LTLIBRARIES = libview.la
+
+libview_la_SOURCES = \
+	autoDrawer.h autoDrawer.c \
+	drawer.h drawer.c \
+	ovBox.h ovBox.c \
+	$(NULL)

Added: trunk/src/view/autoDrawer.c
==============================================================================
--- (empty file)
+++ trunk/src/view/autoDrawer.c	Thu May 29 17:08:54 2008
@@ -0,0 +1,889 @@
+/* *************************************************************************
+ * 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 <libview/autoDrawer.h>
+
+
+struct _ViewAutoDrawerPrivate
+{
+   gboolean active;
+   gboolean pinned;
+   gboolean inputUngrabbed;
+
+   gboolean opened;
+
+   gboolean fill;
+   gint offset;
+
+   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;
+   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);
+   fraction = priv->opened
+      ? 1 : ((double)priv->overlapPixels / priv->over->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;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * 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;
+
+   if (!toplevel || !GTK_WIDGET_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);
+      g_assert(gtk_container_get_border_width(   GTK_CONTAINER(priv->evBox))
+                                              == 0);
+      if (   (guint)x < (guint)priv->evBox->allocation.width
+          && (guint)y < (guint)priv->evBox->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 (window->group && window->group->grabs) {
+         grabbed = GTK_WIDGET(window->group->grabs->data);
+      }
+      if (!grabbed) {
+         grabbed = gtk_grab_get_current();
+      }
+      g_assert(grabbed);
+
+      if (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 (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 (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,        // IN: Unused
+                               GdkEventCrossing *event, // 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,     // 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,    // IN
+                         GtkWidget *widget,    // 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_TOPLEVEL(oldToplevel)) {
+      g_signal_handlers_disconnect_by_func(oldToplevel,
+                                           G_CALLBACK(ViewAutoDrawerOnSetFocus),
+                                           that);
+   }
+
+   if (newToplevel && GTK_WIDGET_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.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+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)          // 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->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,
+      };
+
+      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);
+}

Added: trunk/src/view/autoDrawer.h
==============================================================================
--- (empty file)
+++ trunk/src/view/autoDrawer.h	Thu May 29 17:08:54 2008
@@ -0,0 +1,89 @@
+/* *************************************************************************
+ * 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 <libview/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);
+
+G_END_DECLS
+
+
+#endif /* LIBVIEW_AUTODRAWER_H */

Added: trunk/src/view/drawer.c
==============================================================================
--- (empty file)
+++ trunk/src/view/drawer.c	Thu May 29 17:08:54 2008
@@ -0,0 +1,332 @@
+/* *************************************************************************
+ * 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 <libview/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;
+   }
+}

Added: trunk/src/view/drawer.h
==============================================================================
--- (empty file)
+++ trunk/src/view/drawer.h	Thu May 29 17:08:54 2008
@@ -0,0 +1,82 @@
+/* *************************************************************************
+ * 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 <libview/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);
+
+
+G_END_DECLS
+
+
+#endif /* LIBVIEW_DRAWER_H */

Added: trunk/src/view/ovBox.c
==============================================================================
--- (empty file)
+++ trunk/src/view/ovBox.c	Thu May 29 17:08:54 2008
@@ -0,0 +1,902 @@
+/* *************************************************************************
+ * 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 <libview/ovBox.h>
+
+
+struct _ViewOvBoxPrivate
+{
+   GdkWindow *underWin;
+   GtkWidget *under;
+   GdkWindow *overWin;
+   GtkWidget *over;
+   GtkRequisition overR;
+   unsigned int min;
+   double fraction;
+};
+
+#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)          // Unused
+{
+   ViewOvBox *that;
+   ViewOvBoxPrivate *priv;
+
+   that = VIEW_OV_BOX(instance);
+   that->priv = VIEW_OV_BOX_GET_PRIVATE(that);
+   priv = that->priv;
+
+   GTK_WIDGET_UNSET_FLAGS(that, GTK_NO_WINDOW);
+
+   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;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * ViewOvBoxMap --
+ *
+ *      "map" method of a ViewOvBox.
+ *
+ * Results:
+ *      None
+ *
+ * Side effects:
+ *      None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static void
+ViewOvBoxMap(GtkWidget *widget) // IN
+{
+   gdk_window_show(widget->window);
+   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(widget->window);
+   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);
+   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;
+
+   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;
+   }
+
+   boxWidth = GTK_WIDGET(that)->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);
+   *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;
+
+   widget = GTK_WIDGET(that);
+   gtk_style_set_background(widget->style, widget->window, GTK_STATE_NORMAL);
+   gtk_style_set_background(widget->style, that->priv->underWin, GTK_STATE_NORMAL);
+   gtk_style_set_background(widget->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;
+
+   GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED);
+
+   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.colormap = gtk_widget_get_colormap(widget);
+   attributes.event_mask = gtk_widget_get_events(widget) | GDK_EXPOSURE_MASK;
+   mask = GDK_WA_VISUAL | GDK_WA_COLORMAP | GDK_WA_X | GDK_WA_Y;
+
+   allocation = &widget->allocation;
+   attributes.x = allocation->x;
+   attributes.y = allocation->y;
+   attributes.width = allocation->width;
+   attributes.height = allocation->height;
+   widget->window = gdk_window_new(gtk_widget_get_parent_window(widget),
+				   &attributes, mask);
+   gdk_window_set_user_data(widget->window, that);
+   widget->style = gtk_style_attach(widget->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(widget->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(widget->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);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * 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;
+
+   widget->allocation = *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_REALIZED(widget)) {
+      gdk_window_move_resize(widget->window, 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_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;
+   widgetClass->size_request = ViewOvBoxSizeRequest;
+   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,
+      };
+
+      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_REALIZED(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;
+}

Added: trunk/src/view/ovBox.h
==============================================================================
--- (empty file)
+++ trunk/src/view/ovBox.h	Thu May 29 17:08:54 2008
@@ -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 */

Modified: trunk/src/vinagre-commands.c
==============================================================================
--- trunk/src/vinagre-commands.c	(original)
+++ trunk/src/vinagre-commands.c	Thu May 29 17:08:54 2008
@@ -250,21 +250,8 @@
 
   active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
 
-  if (active &&
-      gdk_screen_is_composited (gtk_widget_get_screen (GTK_WIDGET (window))))
-    {
-      gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), FALSE);
-      vinagre_utils_show_error (_("Scaling does not work properly on composited windows. Disable the visual effects and try again."),
-				GTK_WINDOW (window));
-      return;
-    }
-
   if (!vinagre_tab_set_scaling (vinagre_window_get_active_tab (window), active))
-    {
-      gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), FALSE);
-      vinagre_utils_show_error (_("Scaling is not supported on this installation.\n\nRead the README file (shipped with Vinagre) in order to know how to enable this feature."),
-				GTK_WINDOW (window));
-    }
+    gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), FALSE);
 }
 
 void

Modified: trunk/src/vinagre-tab.c
==============================================================================
--- trunk/src/vinagre-tab.c	(original)
+++ trunk/src/vinagre-tab.c	Thu May 29 17:08:54 2008
@@ -32,6 +32,7 @@
 #include "vinagre-tab.h"
 #include "vinagre-utils.h"
 #include "vinagre-prefs.h"
+#include "view/autoDrawer.h"
 
 #define VINAGRE_TAB_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), VINAGRE_TYPE_TAB, VinagreTabPrivate))
 
@@ -48,6 +49,10 @@
   guint32            keyring_item_id;
   VinagreTabState    state;
   gchar             *clipboard_str;
+  GtkWidget         *layout;
+  GtkWidget         *toolbar;
+  GtkWidget         *ro_button;
+  GtkWidget         *scaling_button;
 };
 
 G_DEFINE_TYPE(VinagreTab, vinagre_tab, GTK_TYPE_VBOX)
@@ -102,13 +107,17 @@
 
   if (event->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)
     {
-      vnc_display_force_grab  (VNC_DISPLAY(tab->priv->vnc), TRUE);
+      //vnc_display_force_grab  (VNC_DISPLAY(tab->priv->vnc), TRUE);
+      gtk_widget_show (tab->priv->toolbar);
+      ViewAutoDrawer_SetActive (VIEW_AUTODRAWER (tab->priv->layout), TRUE);
       gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (tab->priv->scroll),
 				      h, v);
     }
   else
     {
-      vnc_display_force_grab  (VNC_DISPLAY(tab->priv->vnc), FALSE);
+      //vnc_display_force_grab  (VNC_DISPLAY(tab->priv->vnc), FALSE);
+      gtk_widget_hide (tab->priv->toolbar);
+      ViewAutoDrawer_SetActive (VIEW_AUTODRAWER (tab->priv->layout), FALSE);
       gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (tab->priv->scroll),
 				      GTK_POLICY_AUTOMATIC,
 				      GTK_POLICY_AUTOMATIC);
@@ -630,10 +639,141 @@
 }
 
 static void
+close_button_clicked (GtkToolButton *button,
+		      VinagreTab    *tab)
+{
+  vinagre_notebook_remove_tab (tab->priv->nb, tab);
+}
+
+static void
+fullscreen_button_clicked (GtkToolButton *button,
+			   VinagreTab    *tab)
+{
+  vinagre_window_toggle_fullscreen (tab->priv->window);
+}
+
+static void
+screenshot_button_clicked (GtkToolButton *button,
+			   VinagreTab    *tab)
+{
+  vinagre_tab_take_screenshot (tab);
+}
+
+static void
+cad_button_clicked (GtkToolButton *button,
+			   VinagreTab    *tab)
+{
+  vinagre_tab_send_ctrlaltdel (tab);
+}
+
+static void
+ro_button_clicked (GtkToggleToolButton *button,
+		   VinagreTab          *tab)
+{
+  GtkAction *action;
+
+  vinagre_tab_set_readonly (tab, gtk_toggle_tool_button_get_active (button));
+
+  action = gtk_action_group_get_action (vinagre_window_get_connected_action (tab->priv->window), "ViewReadOnly");
+  gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
+				vinagre_tab_get_readonly (tab));
+}
+
+static void
+scaling_button_clicked (GtkToggleToolButton *button,
+			VinagreTab          *tab)
+{
+  GtkAction *action;
+
+  if (!vinagre_tab_set_scaling (tab, gtk_toggle_tool_button_get_active (button)))
+    gtk_toggle_tool_button_set_active (button, FALSE);
+
+  action = gtk_action_group_get_action (vinagre_window_get_connected_action (tab->priv->window), "ViewScaling");
+  gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
+				vinagre_tab_get_scaling (tab));
+}
+
+static void
+setup_layout (VinagreTab *tab)
+{
+  GtkWidget  *button;
+
+  tab->priv->toolbar = gtk_toolbar_new ();
+  GTK_WIDGET_SET_FLAGS (tab->priv->toolbar, GTK_NO_SHOW_ALL);
+
+  gtk_toolbar_set_tooltips (GTK_TOOLBAR (tab->priv->toolbar), TRUE);
+  gtk_toolbar_set_style (GTK_TOOLBAR (tab->priv->toolbar), GTK_TOOLBAR_BOTH_HORIZ);
+
+  /* Leave fullscreen */
+  button = GTK_WIDGET (gtk_tool_button_new_from_stock (GTK_STOCK_LEAVE_FULLSCREEN));
+  gtk_widget_show (GTK_WIDGET (button));
+  gtk_tool_item_set_is_important (GTK_TOOL_ITEM (button), TRUE);
+  gtk_toolbar_insert (GTK_TOOLBAR (tab->priv->toolbar), GTK_TOOL_ITEM (button), 0);
+  g_signal_connect (button, "clicked", G_CALLBACK (fullscreen_button_clicked), tab);
+
+  /* Close connection */
+  button = GTK_WIDGET (gtk_tool_button_new_from_stock (GTK_STOCK_CLOSE));
+  gtk_tool_item_set_tooltip_text (GTK_TOOL_ITEM (button), _("Close connection"));
+  gtk_widget_show (GTK_WIDGET (button));
+  gtk_toolbar_insert (GTK_TOOLBAR (tab->priv->toolbar), GTK_TOOL_ITEM (button), 0);
+  g_signal_connect (button, "clicked", G_CALLBACK (close_button_clicked), tab);
+
+  /* Space */
+  button = GTK_WIDGET (gtk_separator_tool_item_new ());
+  gtk_separator_tool_item_set_draw (GTK_SEPARATOR_TOOL_ITEM (button), FALSE);
+  gtk_tool_item_set_expand (GTK_TOOL_ITEM (button), TRUE);
+  gtk_widget_show (GTK_WIDGET (button));
+  gtk_toolbar_insert (GTK_TOOLBAR (tab->priv->toolbar), GTK_TOOL_ITEM (button), 0);
+
+  /* Scaling */
+  button = GTK_WIDGET (gtk_toggle_tool_button_new ());
+  gtk_tool_button_set_label (GTK_TOOL_BUTTON (button), _("Scaling"));
+  gtk_tool_item_set_tooltip_text (GTK_TOOL_ITEM (button), _("Scaling"));
+  gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (button), "zoom-fit-best");
+  gtk_widget_show (GTK_WIDGET (button));
+  gtk_toolbar_insert (GTK_TOOLBAR (tab->priv->toolbar), GTK_TOOL_ITEM (button), 0);
+  g_signal_connect (button, "toggled", G_CALLBACK (scaling_button_clicked), tab);
+  tab->priv->scaling_button = button;
+
+  /* Read only */
+  button = GTK_WIDGET (gtk_toggle_tool_button_new ());
+  gtk_tool_button_set_label (GTK_TOOL_BUTTON (button), _("Read only"));
+  gtk_tool_item_set_tooltip_text (GTK_TOOL_ITEM (button), _("Read only"));
+  gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (button), "emblem-readonly");
+  gtk_widget_show (GTK_WIDGET (button));
+  gtk_toolbar_insert (GTK_TOOLBAR (tab->priv->toolbar), GTK_TOOL_ITEM (button), 0);
+  g_signal_connect (button, "toggled", G_CALLBACK (ro_button_clicked), tab);
+  tab->priv->ro_button = button;
+
+  /* Screenshot */
+  button = GTK_WIDGET (gtk_tool_button_new (NULL, NULL));
+  gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (button), "applets-screenshooter");
+  gtk_tool_button_set_label (GTK_TOOL_BUTTON (button), _("Take screenshot"));
+  gtk_tool_item_set_tooltip_text (GTK_TOOL_ITEM (button), _("Take screenshot"));
+  g_signal_connect (button, "clicked", G_CALLBACK (screenshot_button_clicked), tab);
+  gtk_widget_show (GTK_WIDGET (button));
+  gtk_toolbar_insert (GTK_TOOLBAR (tab->priv->toolbar), GTK_TOOL_ITEM (button), 0);
+
+  /* Send Ctrl-alt-del */
+  button = GTK_WIDGET (gtk_tool_button_new (NULL, NULL));
+  gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (button), "preferences-desktop-keyboard-shortcuts");
+  gtk_tool_button_set_label (GTK_TOOL_BUTTON (button), _("Send Ctrl-Alt-Del"));
+  gtk_tool_item_set_tooltip_text (GTK_TOOL_ITEM (button), _("Send Ctrl-Alt-Del"));
+  g_signal_connect (button, "clicked", G_CALLBACK (cad_button_clicked), tab);
+  gtk_widget_show (GTK_WIDGET (button));
+  gtk_toolbar_insert (GTK_TOOLBAR (tab->priv->toolbar), GTK_TOOL_ITEM (button), 0);
+
+  tab->priv->layout = ViewAutoDrawer_New ();
+  ViewAutoDrawer_SetActive (VIEW_AUTODRAWER (tab->priv->layout), FALSE);
+  ViewOvBox_SetOver (VIEW_OV_BOX (tab->priv->layout), tab->priv->toolbar);
+  ViewOvBox_SetUnder (VIEW_OV_BOX (tab->priv->layout), tab->priv->scroll);
+}
+
+static void
 vinagre_tab_init (VinagreTab *tab)
 {
-  GtkWidget *viewport;
-  gboolean shared;
+  GtkWidget     *viewport;
+  gboolean       shared;
 
   tab->priv = VINAGRE_TAB_GET_PRIVATE (tab);
   tab->priv->save_password = FALSE;
@@ -649,8 +789,6 @@
   gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (tab->priv->scroll),
 				       GTK_SHADOW_NONE);
 
-  gtk_box_pack_end (GTK_BOX(tab), tab->priv->scroll, TRUE, TRUE, 0);
-
   /* Create the vnc widget */
   tab->priv->vnc = vnc_display_new ();
 
@@ -725,6 +863,9 @@
 		    G_CALLBACK (vnc_key_event),
 		    NULL);
 
+  setup_layout (tab);
+
+  gtk_box_pack_end (GTK_BOX(tab), tab->priv->layout, TRUE, TRUE, 0);
   gtk_widget_show_all (GTK_WIDGET (tab));
 }
 
@@ -886,7 +1027,23 @@
   if (vnc_display_get_scaling (VNC_DISPLAY (tab->priv->vnc)) == active)
     return TRUE;
 
-  return vnc_display_set_scaling (VNC_DISPLAY (tab->priv->vnc), active);
+  if (active &&
+      gdk_screen_is_composited (gtk_widget_get_screen (GTK_WIDGET (tab->priv->window))))
+    {
+      vinagre_utils_show_error (_("Scaling does not work properly on composited windows. Disable the visual effects and try again."),
+				GTK_WINDOW (tab->priv->window));
+      return FALSE;
+    }
+
+  if (!vnc_display_set_scaling (VNC_DISPLAY (tab->priv->vnc), active))
+    {
+      vinagre_utils_show_error (_("Scaling is not supported on this installation.\n\nRead the README file (shipped with Vinagre) in order to know how to enable this feature."),
+				GTK_WINDOW (tab->priv->window));
+      return FALSE;
+    }
+
+  gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (tab->priv->scaling_button), active);
+  return TRUE;
 }
 
 gboolean
@@ -901,6 +1058,7 @@
   g_return_if_fail (VINAGRE_IS_TAB (tab));
 
   vnc_display_set_read_only (VNC_DISPLAY (tab->priv->vnc), active);
+  gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (tab->priv->ro_button), active);
 }
 
 gboolean

Modified: trunk/src/vinagre-window.c
==============================================================================
--- trunk/src/vinagre-window.c	(original)
+++ trunk/src/vinagre-window.c	Thu May 29 17:08:54 2008
@@ -1131,6 +1131,14 @@
   return window->priv->always_sensitive_action_group;
 }
 
+GtkActionGroup *
+vinagre_window_get_connected_action (VinagreWindow *window)
+{
+  g_return_val_if_fail (VINAGRE_IS_WINDOW (window), NULL);
+
+  return window->priv->machine_connected_action_group;
+}
+
 GtkWidget *
 vinagre_window_get_fav_panel (VinagreWindow *window)
 {

Modified: trunk/src/vinagre-window.h
==============================================================================
--- trunk/src/vinagre-window.h	(original)
+++ trunk/src/vinagre-window.h	Thu May 29 17:08:54 2008
@@ -79,6 +79,7 @@
 GtkWidget	*vinagre_window_get_notebook		(VinagreWindow	       *window);
 GtkActionGroup	*vinagre_window_get_main_action		(VinagreWindow         *window);
 GtkActionGroup	*vinagre_window_get_sensitive_action	(VinagreWindow         *window);
+GtkActionGroup	*vinagre_window_get_connected_action	(VinagreWindow         *window);
 
 void		vinagre_window_update_bookmarks_list_menu (VinagreWindow       *window);
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]