gnome-panel rounded corners



I've got a patch to add rounded corners back to gnome-panel.  The only
applet I've found that this malfunctions with is the show desktop
applet, but the fix for that is 1 line long as shown in some of the
other applets that are in gnome-panel.  The reason I didn't include it
here is that it's in a different module.  Also included are the required
images.  They go in icons/

Let me know if anyone finds any bugs with these, including applets that
don't work if you put them in the corner.

Mark,
  I looked at moving this into a separate file, but some of it just
can't be done.  If you have any specific bits you want me to look at
separating out, let me know.

If you want me to commit this, I'll write a good ChangeLog entry and
then do so.  Let me know.

Thanks,
   Chris

Attachment: panel-corner-bottom-left.png
Description: PNG image

Attachment: panel-corner-bottom-right.png
Description: PNG image

Attachment: panel-corner-top-left.png
Description: PNG image

Attachment: panel-corner-top-right.png
Description: PNG image

Index: applets/clock/clock.c
===================================================================
RCS file: /cvs/gnome/gnome-panel/applets/clock/clock.c,v
retrieving revision 1.117
diff -u -p -r1.117 clock.c
--- applets/clock/clock.c	13 Nov 2003 00:21:45 -0000	1.117
+++ applets/clock/clock.c	13 Nov 2003 20:42:15 -0000
@@ -1218,7 +1218,9 @@ fill_clock_applet (PanelApplet *applet)
 					      "hidden", "1",
 					      NULL);
 	}
-	
+
+        panel_applet_set_stretch_widget (applet, cd->toggle);
+
 	return TRUE;
 }
 
Index: applets/wncklet/workspace-switcher.c
===================================================================
RCS file: /cvs/gnome/gnome-panel/applets/wncklet/workspace-switcher.c,v
retrieving revision 1.60
diff -u -p -r1.60 workspace-switcher.c
--- applets/wncklet/workspace-switcher.c	14 Oct 2003 20:28:37 -0000	1.60
+++ applets/wncklet/workspace-switcher.c	13 Nov 2003 20:42:15 -0000
@@ -447,6 +447,8 @@ workspace_switcher_applet_fill (PanelApp
 					      NULL);
 	}
 
+        panel_applet_set_stretch_widget (PANEL_APPLET (pager->applet), pager->pager);
+
 	return TRUE;
 }
 
Index: gnome-panel/panel-applet-frame.c
===================================================================
RCS file: /cvs/gnome/gnome-panel/gnome-panel/panel-applet-frame.c,v
retrieving revision 1.113
diff -u -p -r1.113 panel-applet-frame.c
--- gnome-panel/panel-applet-frame.c	13 Nov 2003 12:31:02 -0000	1.113
+++ gnome-panel/panel-applet-frame.c	13 Nov 2003 20:42:15 -0000
@@ -1,3 +1,4 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
 /*
  * panel-applet-frame.c: panel side container for applets
  *
@@ -53,6 +54,8 @@
 #define PROPERTY_FLAGS      "panel-applet-flags"
 #define PROPERTY_SIZE_HINTS "panel-applet-size-hints"
 #define PROPERTY_LOCKED_DOWN "panel-applet-locked-down"
+#define PROPERTY_TOPLEVEL_WINDOW "panel-applet-toplevel-window"
+#define PROPERTY_STRETCH_FLAGS "panel-applet-stretch-flags"
 
 
 struct _PanelAppletFramePrivate {
@@ -70,6 +73,8 @@ struct _PanelAppletFramePrivate {
 	GtkAllocation                   child_allocation;
 	GdkRectangle                    handle_rect;
 
+	PanelStretchFlags		stretch_flags;
+
 	guint                           has_handle : 1;
 };
 
@@ -697,19 +702,25 @@ panel_applet_frame_button_changed (GtkWi
 {
 	PanelAppletFrame *frame;
 	gboolean          handled = FALSE;
+	GdkWindow        *stretch_window;
 
 	frame = PANEL_APPLET_FRAME (widget);
 
 	if (!frame->priv->has_handle)
 		return handled;
 
-	if (event->window != widget->window)
+	stretch_window = g_object_get_data (G_OBJECT (widget), "StretchEventWindow");
+
+	if (event->window != widget->window &&
+	    event->window != stretch_window) {
 		return FALSE;
+	}
 
 	switch (event->button) {
 	case 1:
 	case 2:
-		if (button_event_in_rect (event, &frame->priv->handle_rect)) {
+		if (stretch_window == event->window ||
+		    button_event_in_rect (event, &frame->priv->handle_rect)) {
 			if (event->type == GDK_BUTTON_PRESS ||
 			    event->type == GDK_2BUTTON_PRESS) {
 				panel_widget_applet_drag_start (
@@ -1358,4 +1369,59 @@ panel_applet_frame_set_panel (PanelApple
 	g_return_if_fail (PANEL_IS_WIDGET (panel));
 
 	frame->priv->panel = panel;
+}
+
+void
+panel_applet_frame_set_stretch_flags (PanelAppletFrame *frame,
+				      PanelStretchFlags flags)
+{
+	GtkWidget *toplevel;
+	if (flags == frame->priv->stretch_flags)
+		return;
+	if (frame->priv->has_handle) {
+		/* If the applet either did touch the left, or will
+		   now, we have to call stretch events on the frame
+		   itself to handle the handle. */
+		if ((frame->priv->stretch_flags & PANEL_STRETCH_LEFT) ||
+		    (flags & PANEL_STRETCH_LEFT)) {
+			if (flags & PANEL_STRETCH_LEFT) {
+				/* If it will touch the left now, just
+				   call panel_stretch_events */
+				panel_stretch_events_to_toplevel (GTK_WIDGET (frame), flags);
+			} else {
+				/* But if it won't, then we just want
+				   to unstretch it since it used to
+				   touch the left. */
+				panel_stretch_events_to_toplevel (GTK_WIDGET (frame), PANEL_STRETCH_NONE);
+			}
+		}
+
+		if (!((frame->priv->stretch_flags & PANEL_STRETCH_RIGHT) ||
+		      (flags & PANEL_STRETCH_RIGHT))) {
+			/* If it both didn't touch the right and will
+			   still not now touch the right, we're done.
+			   Set the field and return. */
+			frame->priv->stretch_flags = flags;
+			return;
+		}
+		if (!(flags & PANEL_STRETCH_RIGHT)) {
+			/* If it won't touch the right now, then it
+			used to, so we just want to unstretch the
+			child applet. */
+			flags = PANEL_STRETCH_NONE;
+		}
+	}
+
+	/* Pass the settings on to the child applet. */
+	frame->priv->stretch_flags = flags;
+
+	toplevel = gtk_widget_get_toplevel (GTK_WIDGET (frame));
+	bonobo_pbclient_set_long (frame->priv->property_bag,
+				  PROPERTY_TOPLEVEL_WINDOW,
+				  gdk_x11_drawable_get_xid (toplevel->window),
+				  NULL);
+	bonobo_pbclient_set_short (frame->priv->property_bag,
+				   PROPERTY_STRETCH_FLAGS,
+				   flags,
+				   NULL);
 }
Index: gnome-panel/panel-applet-frame.h
===================================================================
RCS file: /cvs/gnome/gnome-panel/gnome-panel/panel-applet-frame.h,v
retrieving revision 1.33
diff -u -p -r1.33 panel-applet-frame.h
--- gnome-panel/panel-applet-frame.h	26 May 2003 13:41:07 -0000	1.33
+++ gnome-panel/panel-applet-frame.h	13 Nov 2003 20:42:15 -0000
@@ -28,6 +28,7 @@
 #include <gtk/gtkeventbox.h>
 
 #include "panel-widget.h"
+#include "panel-util.h"
 #include "applet.h"
 
 G_BEGIN_DECLS
@@ -91,6 +92,9 @@ int        panel_applet_frame_get_size_h
 void            panel_applet_frame_set_panel (PanelAppletFrame *frame,
 					      PanelWidget      *panel);
 PanelWidget    *panel_applet_frame_get_panel (PanelAppletFrame *frame);
+
+void		panel_applet_frame_set_stretch_flags (PanelAppletFrame *frame,
+						      PanelStretchFlags flags);
 
 
 G_END_DECLS
Index: gnome-panel/panel-toplevel.c
===================================================================
RCS file: /cvs/gnome/gnome-panel/gnome-panel/panel-toplevel.c,v
retrieving revision 1.45
diff -u -p -r1.45 panel-toplevel.c
--- gnome-panel/panel-toplevel.c	13 Nov 2003 13:09:06 -0000	1.45
+++ gnome-panel/panel-toplevel.c	13 Nov 2003 20:42:15 -0000
@@ -1,3 +1,4 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
 /*
  * panel-toplevel.c: The panel's toplevel window object.
  *
@@ -44,7 +45,10 @@
 #include "panel-widget.h"
 #include "panel-bindings.h"
 #include "panel-struts.h"
+#include "panel-util.h"
 #include "xstuff.h"
+#include "panel-menu-bar.h"
+#include "panel-applet-frame.h"
 
 #define PANEL_TOPLEVEL_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), PANEL_TYPE_TOPLEVEL, PanelToplevelPrivate))
 
@@ -131,6 +135,20 @@ struct _PanelToplevelPrivate {
 	GtkWidget              *hide_button_left;
 	GtkWidget              *hide_button_right;
 
+	GtkWidget              *corner_top_left_horizontal;
+	GtkWidget              *corner_top_right_horizontal;
+	GtkWidget              *corner_bottom_left_horizontal;
+	GtkWidget              *corner_bottom_right_horizontal;
+	GtkWidget              *corner_top_left_vertical;
+	GtkWidget              *corner_bottom_left_vertical;
+	GtkWidget              *corner_top_right_vertical;
+	GtkWidget              *corner_bottom_right_vertical;
+
+	GtkWidget              *extended_widget_at_start;
+	GtkWidget              *extended_widget_at_end;
+	PanelStretchFlags       extended_flags_at_start;
+	PanelStretchFlags       extended_flags_at_end;
+
 	PanelToplevel          *attach_toplevel;
 	gulong                  attach_toplevel_signals [N_ATTACH_TOPLEVEL_SIGNALS];
 	GtkWidget              *attach_widget;
@@ -1090,6 +1108,54 @@ panel_toplevel_hide_button_clicked (Pane
 }
 
 static GtkWidget *
+panel_toplevel_add_rounded_corner (PanelToplevel *toplevel,
+				   int            left_attach,
+				   int            right_attach,
+				   int            top_attach,
+				   int            bottom_attach)
+{
+	char *path;
+	char *filename;
+	GtkWidget *align = NULL;
+	GtkWidget *image;
+	gboolean left = FALSE;
+	gboolean top = FALSE;
+	gboolean horizontal = FALSE;
+
+	if (left_attach < 3)
+		left = TRUE;
+	if (top_attach < 3)
+		top = TRUE;
+	if (left_attach == 0 || left_attach == 4)
+		horizontal = TRUE;
+
+	filename = g_strdup_printf ("panel-corner-%s-%s.png", top ? "top" : "bottom", left ? "left" : "right");
+	path = panel_pixmap_discovery (filename, FALSE /* fallback */);
+	if (path != NULL) {
+		image = gtk_image_new_from_file (path);
+		g_free (path);
+		align = gtk_alignment_new (left ? 0.0 : 1.0, top ? 0.0 : 1.0, 0.0, 0.0);
+		gtk_container_add (GTK_CONTAINER (align), image);
+
+		gtk_table_attach (GTK_TABLE (toplevel->priv->table),
+				  align,
+				  left_attach,
+				  right_attach,
+				  top_attach,
+				  bottom_attach,
+				  GTK_FILL,
+				  GTK_FILL,
+				  0,
+				  0);
+		gtk_widget_show (image);
+		gtk_widget_show (align);
+	}
+	g_free (filename);
+
+	return align;
+}
+
+static GtkWidget *
 panel_toplevel_add_hide_button (PanelToplevel *toplevel,
 				GtkArrowType   arrow_type,
 				int            left_attach,
@@ -1099,21 +1165,26 @@ panel_toplevel_add_hide_button (PanelTop
 {
 	GtkWidget *button;
 	GtkWidget *arrow;
+	gboolean horizontal = FALSE;
 	
 	button = gtk_button_new ();
 	GTK_WIDGET_UNSET_FLAGS (button, GTK_CAN_DEFAULT);
 
 	switch (arrow_type) {
 	case GTK_ARROW_UP:
+		horizontal = FALSE;
 		gtk_widget_set_size_request (button, -1, HIDE_BUTTON_SIZE);
 		break;
 	case GTK_ARROW_DOWN:
+		horizontal = FALSE;
 		gtk_widget_set_size_request (button, -1, HIDE_BUTTON_SIZE);
 		break;
 	case GTK_ARROW_LEFT:
+		horizontal = TRUE;
 		gtk_widget_set_size_request (button, HIDE_BUTTON_SIZE, -1);
 		break;
 	case GTK_ARROW_RIGHT:
+		horizontal = TRUE;
 		gtk_widget_set_size_request (button, HIDE_BUTTON_SIZE, -1);
 		break;
 	default:
@@ -1146,8 +1217,8 @@ panel_toplevel_add_hide_button (PanelTop
 			  right_attach,
 			  top_attach,
 			  bottom_attach,
-			  GTK_FILL,
-			  GTK_FILL,
+			  GTK_FILL | (horizontal ? 0 : GTK_EXPAND),
+			  GTK_FILL | (horizontal ? GTK_EXPAND : 0),
 			  0,
 			  0);
 
@@ -1191,6 +1262,267 @@ panel_toplevel_update_buttons_showing (P
 }
 
 static void
+at_start_weak_ref (gpointer data, GObject *where_object_was)
+{
+	PanelToplevel *toplevel = data;
+	toplevel->priv->extended_widget_at_start = NULL;
+	toplevel->priv->extended_flags_at_start = PANEL_STRETCH_NONE;
+}
+
+static void
+at_end_weak_ref (gpointer data, GObject *where_object_was)
+{
+	PanelToplevel *toplevel = data;
+	toplevel->priv->extended_widget_at_end = NULL;
+	toplevel->priv->extended_flags_at_end = PANEL_STRETCH_NONE;
+}
+
+static void
+create_extension (PanelToplevel *toplevel, gboolean at_start)
+{
+	GtkWidget *widget;
+	PanelStretchFlags flags;
+	if (at_start) {
+		widget = toplevel->priv->extended_widget_at_start;
+		flags = toplevel->priv->extended_flags_at_start;
+	} else {
+		widget = toplevel->priv->extended_widget_at_end;
+		flags = toplevel->priv->extended_flags_at_end;
+	}
+	if (widget == NULL)
+		return;
+	if (PANEL_IS_MENU_BAR (widget)) {
+		GList *children;
+		children = gtk_container_get_children (GTK_CONTAINER(widget));
+		if (children) {
+			if (children->next == NULL) {
+				panel_stretch_events_to_toplevel (children->data, flags);
+			} else {
+				panel_stretch_events_to_toplevel (children->data, flags & ~PANEL_STRETCH_RIGHT);
+				children = children->next;
+				while (children) {
+					if (children->next)
+						panel_stretch_events_to_toplevel (children->data, flags & ~PANEL_STRETCH_LEFT & ~PANEL_STRETCH_RIGHT);
+					else
+						panel_stretch_events_to_toplevel (children->data, flags & ~PANEL_STRETCH_LEFT);
+					children = children->next;
+				}
+			}
+		}
+	} else if (BUTTON_IS_WIDGET (widget)) {
+		panel_stretch_events_to_toplevel (widget, flags);
+	} else if (PANEL_IS_APPLET_FRAME (widget)) {
+		panel_applet_frame_set_stretch_flags (PANEL_APPLET_FRAME (widget), flags);
+	}
+
+	if (at_start) {
+		g_object_weak_ref (G_OBJECT (widget), at_start_weak_ref, toplevel);
+	} else {
+		g_object_weak_ref (G_OBJECT (widget), at_end_weak_ref, toplevel);
+	}
+}
+
+static void
+cancel_extension (PanelToplevel *toplevel, gboolean at_start)
+{
+	GtkWidget *widget;
+	if (at_start) {
+		widget = toplevel->priv->extended_widget_at_start;
+	} else {
+		widget = toplevel->priv->extended_widget_at_end;
+	}
+	if (widget == NULL)
+		return;
+	if (at_start) {
+		g_object_weak_unref (G_OBJECT (widget), at_start_weak_ref, toplevel);
+	} else {
+		g_object_weak_unref (G_OBJECT (widget), at_end_weak_ref, toplevel);
+	}
+	if (PANEL_IS_MENU_BAR (widget)) {
+		GList *children;
+		children = gtk_container_get_children (GTK_CONTAINER(widget));
+		while (children) {
+			panel_stretch_events_to_toplevel (children->data, PANEL_STRETCH_NONE);
+			children = children->next;
+		}
+	} else if (BUTTON_IS_WIDGET (widget)) {
+		panel_stretch_events_to_toplevel (widget, PANEL_STRETCH_NONE);
+	} else if (PANEL_IS_APPLET_FRAME (widget)) {
+		panel_applet_frame_set_stretch_flags (PANEL_APPLET_FRAME (widget), PANEL_STRETCH_NONE);
+	}
+}
+
+static void
+panel_toplevel_update_extends (PanelToplevel *toplevel)
+{
+	int              monitor_width, monitor_height;
+	int              width, height;
+	AppletData *ad_start = NULL;
+	AppletData *ad_end = NULL;
+	GtkWidget *widget_start = NULL;
+	GtkWidget *widget_end = NULL;
+	PanelStretchFlags flags_start = 0, flags_end = 0;
+
+	if (!toplevel->priv->buttons_enabled &&
+	    !toplevel->priv->auto_hide &&
+	    toplevel->priv->expand) {
+		panel_toplevel_get_monitor_geometry (
+				toplevel, NULL, NULL, &monitor_width, &monitor_height);
+
+		width  = toplevel->priv->geometry.width;
+		height = toplevel->priv->geometry.height;
+
+		switch (toplevel->priv->orientation) {
+		case PANEL_ORIENTATION_LEFT:
+			flags_start = PANEL_STRETCH_TOP | PANEL_STRETCH_LEFT;
+			flags_end = PANEL_STRETCH_BOTTOM | PANEL_STRETCH_LEFT;
+			if (toplevel->priv->geometry.y == 0 && toplevel->priv->geometry.x == 0)
+				ad_start = panel_widget_get_applet_at_start (toplevel->priv->panel_widget);
+			if (toplevel->priv->geometry.y == (monitor_height - height) && toplevel->priv->geometry.x == 0)
+				ad_end = panel_widget_get_applet_at_end (toplevel->priv->panel_widget);
+			break;
+		case PANEL_ORIENTATION_RIGHT:
+			flags_start = PANEL_STRETCH_TOP | PANEL_STRETCH_RIGHT;
+			flags_end = PANEL_STRETCH_BOTTOM | PANEL_STRETCH_RIGHT;
+			if (toplevel->priv->geometry.y == 0 && toplevel->priv->geometry.x == (monitor_width - width))
+				ad_start = panel_widget_get_applet_at_start (toplevel->priv->panel_widget);
+			if (toplevel->priv->geometry.y == (monitor_height - height) && toplevel->priv->geometry.x == (monitor_width - width))
+				ad_end = panel_widget_get_applet_at_end (toplevel->priv->panel_widget);
+			break;
+		case PANEL_ORIENTATION_TOP:
+			flags_start = PANEL_STRETCH_TOP | PANEL_STRETCH_LEFT;
+			flags_end = PANEL_STRETCH_TOP | PANEL_STRETCH_RIGHT;
+			if (toplevel->priv->geometry.y == 0 && toplevel->priv->geometry.x == 0)
+				ad_start = panel_widget_get_applet_at_start (toplevel->priv->panel_widget);
+			if (toplevel->priv->geometry.y == 0 && toplevel->priv->geometry.x == (monitor_width - width))
+				ad_end = panel_widget_get_applet_at_end (toplevel->priv->panel_widget);
+			break;
+		case PANEL_ORIENTATION_BOTTOM:
+			flags_start = PANEL_STRETCH_BOTTOM | PANEL_STRETCH_LEFT;
+			flags_end = PANEL_STRETCH_BOTTOM | PANEL_STRETCH_RIGHT;
+			if (toplevel->priv->geometry.y == (monitor_height - height) && toplevel->priv->geometry.x == 0)
+				ad_start = panel_widget_get_applet_at_start (toplevel->priv->panel_widget);
+			if (toplevel->priv->geometry.y == (monitor_height - height) && toplevel->priv->geometry.x == (monitor_width - width))
+				ad_end = panel_widget_get_applet_at_end (toplevel->priv->panel_widget);
+			break;
+		}
+	}
+	if (ad_start)
+		widget_start = ad_start->applet;
+	if (ad_end)
+		widget_end = ad_end->applet;
+	if (widget_start != toplevel->priv->extended_widget_at_start ||
+	    flags_start != toplevel->priv->extended_flags_at_start) {
+		cancel_extension (toplevel, TRUE);
+		toplevel->priv->extended_widget_at_start = widget_start;
+		toplevel->priv->extended_flags_at_start = flags_start;
+		create_extension (toplevel, TRUE);
+	}
+	if (widget_end != toplevel->priv->extended_widget_at_end ||
+	    flags_end != toplevel->priv->extended_flags_at_end) {
+		cancel_extension (toplevel, FALSE);
+		toplevel->priv->extended_widget_at_end = widget_end;
+		toplevel->priv->extended_flags_at_end = flags_end;
+		create_extension (toplevel, FALSE);
+	}
+}
+
+static void
+panel_toplevel_update_corners (PanelToplevel *toplevel)
+{
+	int              monitor_width, monitor_height;
+	int              width, height;
+
+	panel_toplevel_get_monitor_geometry (
+			toplevel, NULL, NULL, &monitor_width, &monitor_height);
+
+	width  = toplevel->priv->geometry.width;
+	height = toplevel->priv->geometry.height;
+
+	if (toplevel->priv->buttons_enabled ||
+	    toplevel->priv->auto_hide ||
+	    ! toplevel->priv->expand) {
+		gtk_widget_hide (toplevel->priv->corner_top_left_vertical);
+		gtk_widget_hide (toplevel->priv->corner_top_right_vertical);
+		gtk_widget_hide (toplevel->priv->corner_bottom_right_vertical);
+		gtk_widget_hide (toplevel->priv->corner_bottom_left_vertical);
+		gtk_widget_hide (toplevel->priv->corner_top_left_horizontal);
+		gtk_widget_hide (toplevel->priv->corner_top_right_horizontal);
+		gtk_widget_hide (toplevel->priv->corner_bottom_right_horizontal);
+		gtk_widget_hide (toplevel->priv->corner_bottom_left_horizontal);
+	} else {
+		switch (toplevel->priv->orientation) {
+		case PANEL_ORIENTATION_LEFT:
+			if (toplevel->priv->geometry.y == 0 && toplevel->priv->geometry.x == 0)
+				gtk_widget_show (toplevel->priv->corner_top_left_vertical);
+			else
+				gtk_widget_hide (toplevel->priv->corner_top_left_vertical);
+			if (toplevel->priv->geometry.y == (monitor_height - height) && toplevel->priv->geometry.x == 0)
+				gtk_widget_show (toplevel->priv->corner_bottom_left_vertical);
+			else
+				gtk_widget_hide (toplevel->priv->corner_bottom_left_vertical);
+			gtk_widget_hide (toplevel->priv->corner_top_right_vertical);
+			gtk_widget_hide (toplevel->priv->corner_bottom_right_vertical);
+			gtk_widget_hide (toplevel->priv->corner_top_left_horizontal);
+			gtk_widget_hide (toplevel->priv->corner_top_right_horizontal);
+			gtk_widget_hide (toplevel->priv->corner_bottom_left_horizontal);
+			gtk_widget_hide (toplevel->priv->corner_bottom_right_horizontal);
+			break;
+		case PANEL_ORIENTATION_RIGHT:
+			gtk_widget_hide (toplevel->priv->corner_top_left_vertical);
+			gtk_widget_hide (toplevel->priv->corner_bottom_left_vertical);
+			if (toplevel->priv->geometry.y == 0 && toplevel->priv->geometry.x == (monitor_width - width))
+				gtk_widget_show (toplevel->priv->corner_top_right_vertical);
+			else
+				gtk_widget_hide (toplevel->priv->corner_top_right_vertical);
+			if (toplevel->priv->geometry.y == (monitor_height - height) && toplevel->priv->geometry.x == (monitor_width - width))
+				gtk_widget_show (toplevel->priv->corner_bottom_right_vertical);
+			else
+				gtk_widget_hide (toplevel->priv->corner_bottom_right_vertical);
+			gtk_widget_hide (toplevel->priv->corner_top_left_horizontal);
+			gtk_widget_hide (toplevel->priv->corner_top_right_horizontal);
+			gtk_widget_hide (toplevel->priv->corner_bottom_left_horizontal);
+			gtk_widget_hide (toplevel->priv->corner_bottom_right_horizontal);
+			break;
+		case PANEL_ORIENTATION_TOP:
+			gtk_widget_hide (toplevel->priv->corner_top_left_vertical);
+			gtk_widget_hide (toplevel->priv->corner_bottom_left_vertical);
+			gtk_widget_hide (toplevel->priv->corner_top_right_vertical);
+			gtk_widget_hide (toplevel->priv->corner_bottom_right_vertical);
+			if (toplevel->priv->geometry.y == 0 && toplevel->priv->geometry.x == 0)
+				gtk_widget_show (toplevel->priv->corner_top_left_horizontal);
+			else
+				gtk_widget_hide (toplevel->priv->corner_top_left_horizontal);
+			if (toplevel->priv->geometry.y == 0 && toplevel->priv->geometry.x == (monitor_width - width))
+				gtk_widget_show (toplevel->priv->corner_top_right_horizontal);
+			else
+				gtk_widget_hide (toplevel->priv->corner_top_right_horizontal);
+			gtk_widget_hide (toplevel->priv->corner_bottom_left_horizontal);
+			gtk_widget_hide (toplevel->priv->corner_bottom_right_horizontal);
+			break;
+		case PANEL_ORIENTATION_BOTTOM:
+			gtk_widget_hide (toplevel->priv->corner_top_left_vertical);
+			gtk_widget_hide (toplevel->priv->corner_bottom_left_vertical);
+			gtk_widget_hide (toplevel->priv->corner_top_right_vertical);
+			gtk_widget_hide (toplevel->priv->corner_bottom_right_vertical);
+			gtk_widget_hide (toplevel->priv->corner_top_left_horizontal);
+			gtk_widget_hide (toplevel->priv->corner_top_right_horizontal);
+			if (toplevel->priv->geometry.y == (monitor_height - height) && toplevel->priv->geometry.x == 0)
+				gtk_widget_show (toplevel->priv->corner_bottom_left_horizontal);
+			else
+				gtk_widget_hide (toplevel->priv->corner_bottom_left_horizontal);
+			if (toplevel->priv->geometry.y == (monitor_height - height) && toplevel->priv->geometry.x == (monitor_width - width))
+				gtk_widget_show (toplevel->priv->corner_bottom_right_horizontal);
+			else
+				gtk_widget_hide (toplevel->priv->corner_bottom_right_horizontal);
+			break;
+		}
+	}
+
+	panel_toplevel_update_extends(toplevel);
+}
+
+static void
 panel_toplevel_update_hide_buttons (PanelToplevel *toplevel)
 {
 	if (toplevel->priv->buttons_enabled)
@@ -2049,6 +2381,7 @@ panel_toplevel_update_position (PanelTop
 	}
 
 	panel_toplevel_update_edges (toplevel);
+	panel_toplevel_update_corners (toplevel);
 	panel_toplevel_update_description (toplevel);
 }
 
@@ -2375,6 +2708,7 @@ panel_toplevel_attach_to_widget (PanelTo
 	panel_toplevel_set_expand (toplevel, FALSE);
 	panel_toplevel_update_attach_orientation (toplevel);
 	panel_toplevel_update_hide_buttons (toplevel);
+	panel_toplevel_update_corners (toplevel);
 
 	gtk_widget_queue_resize (GTK_WIDGET (toplevel));
 }
@@ -3101,6 +3435,7 @@ panel_toplevel_hide (PanelToplevel    *t
 		}
 
 		panel_toplevel_update_hide_buttons (toplevel);
+		panel_toplevel_update_corners (toplevel);
 	}
 
 	if (toplevel->priv->animate && GTK_WIDGET_REALIZED (toplevel))
@@ -3143,6 +3478,7 @@ panel_toplevel_unhide (PanelToplevel *to
 	toplevel->priv->state = PANEL_STATE_NORMAL;
 
 	panel_toplevel_update_hide_buttons (toplevel);
+	panel_toplevel_update_corners (toplevel);
 
 	if (toplevel->priv->attach_toplevel)
 		panel_toplevel_push_autohide_disabler (toplevel->priv->attach_toplevel);
@@ -3886,19 +4222,43 @@ panel_toplevel_setup_widgets (PanelTople
 {
 	GtkWidget *container;
 
-	toplevel->priv->table = gtk_table_new (3, 3, FALSE);
+	toplevel->priv->table = gtk_table_new (5, 5, FALSE);
 
 	toplevel->priv->hide_button_top =
-		panel_toplevel_add_hide_button (toplevel, GTK_ARROW_UP,    1, 2, 0, 1);
+		panel_toplevel_add_hide_button (toplevel, GTK_ARROW_UP,    2, 3, 0, 1);
 
 	toplevel->priv->hide_button_bottom =
-		panel_toplevel_add_hide_button (toplevel, GTK_ARROW_DOWN,  1, 2, 2, 3);
+		panel_toplevel_add_hide_button (toplevel, GTK_ARROW_DOWN,  2, 3, 4, 5);
 
 	toplevel->priv->hide_button_left =
-		panel_toplevel_add_hide_button (toplevel, GTK_ARROW_LEFT,  0, 1, 1, 2);
+		panel_toplevel_add_hide_button (toplevel, GTK_ARROW_LEFT,  0, 1, 2, 3);
 
 	toplevel->priv->hide_button_right =
-		panel_toplevel_add_hide_button (toplevel, GTK_ARROW_RIGHT, 2, 3, 1, 2);
+		panel_toplevel_add_hide_button (toplevel, GTK_ARROW_RIGHT, 4, 5, 2, 3);
+
+	toplevel->priv->corner_top_left_horizontal =
+		panel_toplevel_add_rounded_corner (toplevel, 0, 1, 1, 2);
+
+	toplevel->priv->corner_top_right_horizontal =
+		panel_toplevel_add_rounded_corner (toplevel, 4, 5, 1, 2);
+
+	toplevel->priv->corner_bottom_left_horizontal =
+		panel_toplevel_add_rounded_corner (toplevel, 0, 1, 3, 4);
+
+	toplevel->priv->corner_bottom_right_horizontal =
+		panel_toplevel_add_rounded_corner (toplevel, 4, 5, 3, 4);
+
+	toplevel->priv->corner_top_left_vertical =
+		panel_toplevel_add_rounded_corner (toplevel, 1, 2, 0, 1);
+
+	toplevel->priv->corner_bottom_left_vertical =
+		panel_toplevel_add_rounded_corner (toplevel, 1, 2, 4, 5);
+
+	toplevel->priv->corner_top_right_vertical =
+		panel_toplevel_add_rounded_corner (toplevel, 3, 4, 0, 1);
+
+	toplevel->priv->corner_bottom_right_vertical =
+		panel_toplevel_add_rounded_corner (toplevel, 3, 4, 4, 5);
 
 	if (toplevel->priv->orientation & PANEL_HORIZONTAL_MASK) {
 		gtk_widget_show (toplevel->priv->hide_button_left);
@@ -3912,8 +4272,8 @@ panel_toplevel_setup_widgets (PanelTople
 
 	gtk_table_attach (GTK_TABLE (toplevel->priv->table),
 			  GTK_WIDGET (toplevel->priv->inner_frame),
-			  1, 2,
-			  1, 2,
+			  1, 4,
+			  1, 4,
 			  GTK_FILL | GTK_EXPAND | GTK_SHRINK,
 			  GTK_FILL | GTK_EXPAND | GTK_SHRINK,
 			  0, 0);
@@ -4139,6 +4499,8 @@ panel_toplevel_set_expand (PanelToplevel
 			panel_toplevel_set_y (toplevel, 0, TRUE);
 	}
 
+	panel_toplevel_update_corners (toplevel);
+
 	gtk_widget_queue_resize (GTK_WIDGET (toplevel));
 
 	panel_widget_set_packed (toplevel->priv->panel_widget, !toplevel->priv->expand);
@@ -4207,6 +4569,7 @@ panel_toplevel_set_orientation (PanelTop
 	toplevel->priv->orientation = orientation;
 
 	panel_toplevel_update_hide_buttons (toplevel);
+	panel_toplevel_update_corners (toplevel);
 
 	panel_widget_set_orientation (	
 		toplevel->priv->panel_widget,
@@ -4411,6 +4774,8 @@ panel_toplevel_set_auto_hide (PanelTople
 
 	toplevel->priv->auto_hide = auto_hide;
 
+	panel_toplevel_update_corners (toplevel);
+
 	if (toplevel->priv->auto_hide)
 		panel_toplevel_queue_auto_hide (toplevel);
 	else
@@ -4532,6 +4897,7 @@ panel_toplevel_set_enable_buttons (Panel
 	toplevel->priv->buttons_enabled = enable_buttons;
 
 	panel_toplevel_update_hide_buttons (toplevel);
+	panel_toplevel_update_corners (toplevel);
 
 	g_object_notify (G_OBJECT (toplevel), "buttons-enabled");
 }
Index: gnome-panel/panel-util.c
===================================================================
RCS file: /cvs/gnome/gnome-panel/gnome-panel/panel-util.c,v
retrieving revision 1.139
diff -u -p -r1.139 panel-util.c
--- gnome-panel/panel-util.c	6 Nov 2003 12:00:55 -0000	1.139
+++ gnome-panel/panel-util.c	13 Nov 2003 20:42:16 -0000
@@ -1,3 +1,4 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
 /*
  * GNOME panel utils
  * (C) 1997, 1998, 1999, 2000 The Free Software Foundation
@@ -588,6 +589,288 @@ panel_pixmap_discovery (const char *name
 						    FALSE /* only_if_exists */,
 						    NULL /* ret_locations */);
 	return pixmap;
+}
+
+typedef struct {
+	int realize_id;
+	int unrealize_id;
+	int size_allocate_id;
+	int map_id;
+	int unmap_id;
+	int hierarchy_changed_id;
+	PanelStretchFlags flags;
+	GtkWidget *toplevel;
+} PanelStretchInfo;
+
+static void
+stretch_widget_calc_geometry (GtkWidget *widget,
+			      int       *x,
+			      int       *y,
+			      int       *w,
+			      int       *h)
+{
+	PanelStretchInfo  *info;
+
+	g_assert (x && y && w && h);
+
+	info = g_object_get_data (G_OBJECT (widget) , "stretch-info");
+	info->toplevel = gtk_widget_get_toplevel (widget);
+
+	if (!(info->toplevel && GTK_WIDGET_REALIZED (info->toplevel)))
+		return;
+	
+	gtk_widget_translate_coordinates (widget, info->toplevel, 0, 0, x, y);
+
+	*w = widget->allocation.width;
+	*h = widget->allocation.height;
+
+	if (info->flags & PANEL_STRETCH_TOP) {
+		*h += *y;
+		*y  = 0;
+	}
+
+	if (info->flags & PANEL_STRETCH_LEFT) {
+		*w += *x;
+		*x  = 0;
+	}
+
+	if (info->flags & PANEL_STRETCH_BOTTOM)
+		*h = info->toplevel->allocation.height - *y;
+
+	if (info->flags & PANEL_STRETCH_RIGHT)
+		*w = info->toplevel->allocation.width - *x;
+}
+
+static void
+stretch_widget_realize (GtkWidget *widget)
+{
+	GdkWindowAttr  attributes = { 0 };
+	int            attributes_mask;
+	int            x, y, w, h;
+	GdkWindow     *eventwin;
+	PanelStretchInfo *info;
+
+	info = g_object_get_data (G_OBJECT (widget) , "stretch-info");
+
+	eventwin = g_object_get_data (G_OBJECT (widget), "StretchEventWindow");
+	if (eventwin != NULL) {
+		gdk_window_set_user_data (eventwin, NULL);
+		g_object_set_data (G_OBJECT (widget), "StretchEventWindow", NULL);
+		gdk_window_destroy (eventwin);
+	}
+
+	stretch_widget_calc_geometry (widget, &x, &y, &w, &h);
+	if (!(info->toplevel && GTK_WIDGET_REALIZED (info->toplevel)))
+		return;
+
+	attributes.window_type = GDK_WINDOW_CHILD;
+	attributes.x = x;
+	attributes.y = y;
+	attributes.width = w;
+	attributes.height = h;
+	attributes.wclass = GDK_INPUT_ONLY;
+	attributes.event_mask = (GDK_BUTTON_PRESS_MASK |
+				 GDK_BUTTON_RELEASE_MASK |
+				 GDK_POINTER_MOTION_MASK |
+				 GDK_POINTER_MOTION_HINT_MASK |
+				 GDK_KEY_PRESS_MASK |
+				 GDK_ENTER_NOTIFY_MASK |
+				 GDK_LEAVE_NOTIFY_MASK);
+	attributes_mask = GDK_WA_X | GDK_WA_Y;
+
+	eventwin = gdk_window_new (info->toplevel->window,
+				   &attributes,
+				   attributes_mask);
+	gdk_window_set_user_data (eventwin, widget);
+
+	g_object_set_data (G_OBJECT (widget),
+			   "StretchEventWindow",
+			   eventwin);
+}
+
+static void
+stretch_widget_unrealize (GtkWidget *widget)
+{
+	GdkWindow *eventwin = g_object_get_data (G_OBJECT (widget),
+						 "StretchEventWindow");
+	if (eventwin == NULL)
+		return;
+
+	gdk_window_set_user_data (eventwin, NULL);
+	gdk_window_destroy (eventwin);
+	g_object_set_data (G_OBJECT (widget),
+			   "StretchEventWindow",
+			   NULL);
+}
+
+/* Evil but otherwise it doesn't seem
+ * to work.  There needs to be a cleaner
+ * solution */
+static gboolean
+lower_in_idle (gpointer data)
+{
+	GdkWindow *eventwin = g_object_get_data (G_OBJECT (data),
+						 "StretchEventWindow");
+
+	g_object_unref (G_OBJECT (data));
+
+	if (eventwin == NULL)
+		return FALSE;
+
+	gdk_window_lower (eventwin);
+	return FALSE;
+}
+
+
+static void
+stretch_widget_map (GtkWidget *widget)
+{
+	GdkWindow *eventwin = g_object_get_data (G_OBJECT (widget),
+						 "StretchEventWindow");
+	if (eventwin == NULL)
+		return;
+
+	if (GTK_WIDGET_MAPPED (widget)) {
+		gdk_window_show (eventwin);
+		gdk_window_lower (eventwin);
+		g_idle_add (lower_in_idle,
+			    g_object_ref (G_OBJECT (widget)));
+	}
+}
+
+static void
+stretch_widget_unmap (GtkWidget *widget)
+{
+	GdkWindow *eventwin = g_object_get_data (G_OBJECT (widget),
+						 "StretchEventWindow");
+	if (eventwin == NULL)
+		return;
+
+	gdk_window_hide (eventwin);
+}
+
+
+static void
+stretch_widget_size_allocate (GtkWidget     *widget,
+			      GtkAllocation *allocation)
+{
+	GdkWindow *eventwin;
+	int        x, y, w, h;
+	int        old_x, old_y, old_w, old_h, old_d;
+	PanelStretchInfo *info;
+
+	info = g_object_get_data (G_OBJECT (widget) , "stretch-info");
+
+	eventwin = g_object_get_data (G_OBJECT (widget), "StretchEventWindow");
+	if (!eventwin)
+		return;
+
+	stretch_widget_calc_geometry (widget, &x, &y, &w, &h);
+	if (!(info->toplevel && GTK_WIDGET_REALIZED (info->toplevel)))
+		return;
+
+	gdk_window_get_geometry (eventwin, &old_x, &old_y, &old_w, &old_h, &old_d);
+
+	if ((x == old_x) && (y == old_y) && (w == old_w) && (h == old_h))
+		return;
+
+	/* somewhat evil */
+	stretch_widget_unrealize (widget);
+	stretch_widget_realize (widget);
+	stretch_widget_map (widget);
+}
+
+static void
+stretch_widget_hierarchy_changed (GtkWidget *widget,
+				 GtkWidget *previous_toplevel)
+{
+	stretch_widget_unrealize (widget);
+	stretch_widget_realize (widget);
+	stretch_widget_map (widget);
+}
+
+static void
+stretch_cancel (GtkWidget         *widget)
+{
+	PanelStretchInfo *info;
+
+	info = g_object_get_data (G_OBJECT (widget), "stretch-info");
+
+	if (info) {
+		stretch_widget_unrealize (widget);
+
+		g_signal_handler_disconnect (widget, info->realize_id);
+		g_signal_handler_disconnect (widget, info->unrealize_id);
+		g_signal_handler_disconnect (widget, info->size_allocate_id);
+		g_signal_handler_disconnect (widget, info->map_id);
+		g_signal_handler_disconnect (widget, info->unmap_id);
+		g_signal_handler_disconnect (widget, info->hierarchy_changed_id);
+
+		g_object_set_data (G_OBJECT (widget), "stretch-info", NULL);
+	}
+}
+
+void
+panel_stretch_events_to_toplevel (GtkWidget         *widget,
+				  PanelStretchFlags  flags)
+{
+	PanelStretchInfo *info;
+
+	if (flags == PANEL_STRETCH_NONE) {
+		stretch_cancel (widget);
+		return;
+	}
+
+	info = g_object_get_data (G_OBJECT (widget) , "stretch-info");
+
+	if (info) {
+		if (info->flags == flags &&
+		    GTK_WIDGET_REALIZED (widget) &&
+		    info->toplevel == gtk_widget_get_toplevel (widget))
+			return;
+		info->flags = flags;
+		stretch_widget_unrealize (widget);
+		stretch_widget_realize (widget);
+		stretch_widget_map (widget);
+		return;
+	}
+
+	info = g_new0 (PanelStretchInfo, 1);
+
+	info->realize_id =
+		g_signal_connect_after (GTK_WIDGET (widget), "realize",
+					G_CALLBACK (stretch_widget_realize),
+					NULL);
+	info->unrealize_id =
+		g_signal_connect (GTK_WIDGET (widget), "unrealize",
+				  G_CALLBACK (stretch_widget_unrealize),
+				  NULL);
+	info->size_allocate_id =
+		g_signal_connect_after (GTK_WIDGET (widget), "size_allocate",
+					G_CALLBACK (stretch_widget_size_allocate),
+					NULL);
+	info->map_id = 
+		g_signal_connect_after (GTK_WIDGET (widget), "map",
+					G_CALLBACK (stretch_widget_map),
+					NULL);
+	info->unmap_id = 
+		g_signal_connect_after (GTK_WIDGET (widget), "unmap",
+					G_CALLBACK (stretch_widget_unmap),
+					NULL);
+	info->hierarchy_changed_id = 
+		g_signal_connect_after (GTK_WIDGET (widget), "hierarchy_changed",
+					G_CALLBACK (stretch_widget_hierarchy_changed),
+					NULL);
+
+	info->flags = flags;
+
+	g_object_set_data_full (G_OBJECT (widget), "stretch-info", info, g_free);
+
+	if (GTK_WIDGET_REALIZED (widget))
+		stretch_widget_realize (widget);
+	if (GTK_WIDGET_MAPPED (widget))
+		stretch_widget_map (widget);
+
 }
 
 /* stolen from gtk */
Index: gnome-panel/panel-util.h
===================================================================
RCS file: /cvs/gnome/gnome-panel/gnome-panel/panel-util.h,v
retrieving revision 1.76
diff -u -p -r1.76 panel-util.h
--- gnome-panel/panel-util.h	6 Nov 2003 12:00:55 -0000	1.76
+++ gnome-panel/panel-util.h	13 Nov 2003 20:42:16 -0000
@@ -11,6 +11,14 @@
 
 G_BEGIN_DECLS
 
+typedef enum {
+	PANEL_STRETCH_NONE   = 0,
+	PANEL_STRETCH_TOP    = 1 << 0,
+	PANEL_STRETCH_RIGHT  = 1 << 1,
+	PANEL_STRETCH_BOTTOM = 1 << 2,
+	PANEL_STRETCH_LEFT   = 1 << 3,
+} PanelStretchFlags;
+
 typedef void (*UpdateFunction) (gpointer);
 
 /* TRUE if string is NULL or the first character is '\0' */
@@ -76,6 +84,9 @@ gboolean	panel_is_program_in_path (const
 
 char *		panel_pixmap_discovery	(const char *name,
 					 gboolean fallback);
+
+void		panel_stretch_events_to_toplevel (GtkWidget         *widget,
+						  PanelStretchFlags  flags);
 
 void		panel_signal_connect_object_while_alive (gpointer     object,
 							 const gchar *signal,
Index: gnome-panel/panel-widget.c
===================================================================
RCS file: /cvs/gnome/gnome-panel/gnome-panel/panel-widget.c,v
retrieving revision 1.367
diff -u -p -r1.367 panel-widget.c
--- gnome-panel/panel-widget.c	3 Nov 2003 16:22:45 -0000	1.367
+++ gnome-panel/panel-widget.c	13 Nov 2003 20:42:16 -0000
@@ -1,3 +1,4 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
 /* Gnome panel: panel widget
  * (C) 1997,1998,1999,2000 the Free Software Foundation
  * (C) 2000 Eazel, Inc.
@@ -2931,4 +2932,39 @@ panel_widget_register_open_dialog (Panel
 	panel_signal_connect_object_while_alive (dialog, "destroy",
 	 		 G_CALLBACK (panel_widget_open_dialog_destroyed),
 			 panel);
+}
+
+AppletData *
+panel_widget_get_applet_at_start (PanelWidget *panel)
+{
+	GList *l;
+	AppletData *ad;
+
+	g_return_val_if_fail (PANEL_IS_WIDGET (panel), NULL);
+
+	l = panel->applet_list;
+	if (l) {
+		ad = l->data;
+		if (ad->constrained <= 1)
+			return ad;
+	}
+	return NULL;
+}
+
+AppletData *
+panel_widget_get_applet_at_end (PanelWidget *panel)
+{
+	GList *l;
+	AppletData *ad;
+
+	g_return_val_if_fail (PANEL_IS_WIDGET (panel), NULL);
+
+	l = g_list_last (panel->applet_list);
+	if (l) {
+		ad = l->data;
+		if (ad->constrained + ad->cells >= panel->size - 1)
+			return ad;
+	}
+
+	return NULL;
 }
Index: gnome-panel/panel-widget.h
===================================================================
RCS file: /cvs/gnome/gnome-panel/gnome-panel/panel-widget.h,v
retrieving revision 1.158
diff -u -p -r1.158 panel-widget.h
--- gnome-panel/panel-widget.h	3 Nov 2003 16:22:45 -0000	1.158
+++ gnome-panel/panel-widget.h	13 Nov 2003 20:42:16 -0000
@@ -207,6 +207,8 @@ gboolean panel_widget_get_applet_locked 
 						   GtkWidget   *applet);
 gboolean panel_widget_toggle_applet_locked        (PanelWidget *panel,
 						   GtkWidget   *applet);
+AppletData *panel_widget_get_applet_at_start      (PanelWidget *panel);
+AppletData *panel_widget_get_applet_at_end        (PanelWidget *panel);
 
 void     panel_widget_register_open_dialog        (PanelWidget *panel,
 						   GtkWidget   *dialog);  
Index: icons/Makefile.am
===================================================================
RCS file: /cvs/gnome/gnome-panel/icons/Makefile.am,v
retrieving revision 1.5
diff -u -p -r1.5 Makefile.am
--- icons/Makefile.am	17 Jul 2003 11:18:39 -0000	1.5
+++ icons/Makefile.am	13 Nov 2003 20:42:16 -0000
@@ -18,6 +18,10 @@ icon_DATA =				\
 	gnome-run.png			\
 	gnome-screenshot.png		\
 	panel-drawer.png		\
+	panel-corner-bottom-left.png	\
+	panel-corner-bottom-right.png	\
+	panel-corner-top-left.png	\
+	panel-corner-top-right.png	\
 	gnome-main-menu.png		\
 	$(NULL)
 
Index: libpanel-applet/panel-applet.c
===================================================================
RCS file: /cvs/gnome/gnome-panel/libpanel-applet/panel-applet.c,v
retrieving revision 1.84
diff -u -p -r1.84 panel-applet.c
--- libpanel-applet/panel-applet.c	13 Nov 2003 12:35:26 -0000	1.84
+++ libpanel-applet/panel-applet.c	13 Nov 2003 20:42:16 -0000
@@ -1,3 +1,4 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
 /*
  * panel-applet.c: panel applet writing library.
  *
@@ -52,6 +53,14 @@
 #include "panel-applet-marshal.h"
 #include "panel-applet-enums.h"
 
+typedef enum {
+	PANEL_STRETCH_NONE   = 0,
+	PANEL_STRETCH_TOP    = 1 << 0,
+	PANEL_STRETCH_RIGHT  = 1 << 1,
+	PANEL_STRETCH_BOTTOM = 1 << 2,
+	PANEL_STRETCH_LEFT   = 1 << 3,
+} PanelStretchFlags;
+
 #define PANEL_APPLET_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), PANEL_TYPE_APPLET, PanelAppletPrivate))
 
 struct _PanelAppletPrivate {
@@ -78,6 +87,10 @@ struct _PanelAppletPrivate {
 	guint                       hierarchy_changed_id;
 
 	gboolean                    locked_down;
+
+	GtkWidget                  *stretch_widget;
+	GdkWindow		   *toplevel_window;
+	PanelStretchFlags           stretch_flags;
 };
 
 static GObjectClass *parent_class;
@@ -99,6 +112,8 @@ static guint panel_applet_signals [LAST_
 #define PROPERTY_FLAGS      "panel-applet-flags"
 #define PROPERTY_SIZE_HINTS "panel-applet-size-hints"
 #define PROPERTY_LOCKED_DOWN "panel-applet-locked-down"
+#define PROPERTY_TOPLEVEL_WINDOW "panel-applet-toplevel-window"
+#define PROPERTY_STRETCH_FLAGS "panel-applet-stretch-flags"
 
 enum {
 	PROPERTY_ORIENT_IDX,
@@ -107,6 +122,8 @@ enum {
 	PROPERTY_FLAGS_IDX,
 	PROPERTY_SIZE_HINTS_IDX,
 	PROPERTY_LOCKED_DOWN_IDX,
+	PROPERTY_TOPLEVEL_WINDOW_IDX,
+	PROPERTY_STRETCH_FLAGS_IDX,
 };
 
 static void
@@ -369,6 +386,339 @@ panel_applet_get_popup_component (PanelA
 	return bonobo_control_get_popup_ui_component (applet->priv->control);
 }
 
+typedef struct {
+	int realize_id;
+	int unrealize_id;
+	int size_allocate_id;
+	int map_id;
+	int unmap_id;
+	int hierarchy_changed_id;
+	PanelStretchFlags flags;
+	GdkWindow *toplevel_window;
+} PanelStretchInfo;
+
+static gboolean
+gdk_window_translate_coordinates (GdkWindow *src_window,
+				  GdkWindow *dest_window,
+				  int src_x,
+				  int src_y,
+				  int *dest_x,
+				  int *dest_y)
+{
+	int dx, dy;
+
+	if (gdk_drawable_get_screen (src_window) != gdk_drawable_get_screen (dest_window))
+		return FALSE;
+
+	gdk_window_get_origin (src_window, &dx, &dy);
+	src_x += dx;
+	src_y += dy;
+	gdk_window_get_origin (dest_window, &dx, &dy);
+	src_x -= dx;
+	src_y -= dy;
+
+	if (dest_x)
+		*dest_x = src_x;
+	if (dest_y)
+		*dest_y = src_y;
+	return TRUE;
+}
+
+static void
+stretch_widget_calc_geometry (GtkWidget *widget,
+			      int       *x,
+			      int       *y,
+			      int       *w,
+			      int       *h)
+{
+	PanelStretchInfo  *info;
+
+	g_assert (x && y && w && h);
+
+	info = g_object_get_data (G_OBJECT (widget) , "stretch-info");
+	
+	gdk_window_translate_coordinates (widget->window, info->toplevel_window, 0, 0, x, y);
+
+	*w = widget->allocation.width;
+	*h = widget->allocation.height;
+
+	if (info->flags & PANEL_STRETCH_TOP) {
+		*h += *y;
+		*y  = 0;
+	}
+
+	if (info->flags & PANEL_STRETCH_LEFT) {
+		*w += *x;
+		*x  = 0;
+	}
+
+	if (info->flags & (PANEL_STRETCH_BOTTOM | PANEL_STRETCH_RIGHT)) {
+		int toplevel_width, toplevel_height;
+
+		gdk_window_get_geometry (info->toplevel_window, NULL, NULL, &toplevel_width, &toplevel_height, NULL);
+
+		if (info->flags & PANEL_STRETCH_BOTTOM)
+			*h = toplevel_height - *y;
+
+		if (info->flags & PANEL_STRETCH_RIGHT)
+			*w = toplevel_width - *x;
+	}
+}
+
+static void
+stretch_widget_realize (GtkWidget *widget)
+{
+	GdkWindowAttr  attributes = { 0 };
+	int            attributes_mask;
+	int            x, y, w, h;
+	GdkWindow     *eventwin;
+	PanelStretchInfo  *info;
+
+	info = g_object_get_data (G_OBJECT (widget) , "stretch-info");
+	
+	eventwin = g_object_get_data (G_OBJECT (widget), "StretchEventWindow");
+	if (eventwin != NULL) {
+		gdk_window_set_user_data (eventwin, NULL);
+		g_object_set_data (G_OBJECT (widget), "StretchEventWindow", NULL);
+		gdk_window_destroy (eventwin);
+	}
+
+	stretch_widget_calc_geometry (widget, &x, &y, &w, &h);
+
+	attributes.window_type = GDK_WINDOW_CHILD;
+	attributes.x = x;
+	attributes.y = y;
+	attributes.width = w;
+	attributes.height = h;
+	attributes.wclass = GDK_INPUT_ONLY;
+	attributes.event_mask = (GDK_BUTTON_PRESS_MASK |
+				 GDK_BUTTON_RELEASE_MASK |
+				 GDK_POINTER_MOTION_MASK |
+				 GDK_POINTER_MOTION_HINT_MASK |
+				 GDK_KEY_PRESS_MASK |
+				 GDK_ENTER_NOTIFY_MASK |
+				 GDK_LEAVE_NOTIFY_MASK);
+	attributes_mask = GDK_WA_X | GDK_WA_Y;
+
+	eventwin = gdk_window_new (info->toplevel_window,
+				   &attributes,
+				   attributes_mask);
+	gdk_window_set_user_data (eventwin, widget);
+
+	g_object_set_data (G_OBJECT (widget),
+			   "StretchEventWindow",
+			   eventwin);
+}
+
+static void
+stretch_widget_unrealize (GtkWidget *widget)
+{
+	GdkWindow *eventwin = g_object_get_data (G_OBJECT (widget),
+						 "StretchEventWindow");
+	if (eventwin == NULL)
+		return;
+
+	gdk_window_set_user_data (eventwin, NULL);
+	gdk_window_destroy (eventwin);
+	g_object_set_data (G_OBJECT (widget),
+			   "StretchEventWindow",
+			   NULL);
+}
+
+/* Evil but otherwise it doesn't seem
+ * to work.  There needs to be a cleaner
+ * solution */
+static gboolean
+lower_in_idle (gpointer data)
+{
+	GdkWindow *eventwin = g_object_get_data (G_OBJECT (data),
+						 "StretchEventWindow");
+
+	g_object_unref (G_OBJECT (data));
+
+	if (eventwin == NULL)
+		return FALSE;
+
+	gdk_window_lower (eventwin);
+	return FALSE;
+}
+
+
+static void
+stretch_widget_map (GtkWidget *widget)
+{
+	GdkWindow *eventwin = g_object_get_data (G_OBJECT (widget),
+						 "StretchEventWindow");
+	if (eventwin == NULL)
+		return;
+
+	if (GTK_WIDGET_MAPPED (widget)) {
+		gdk_window_show (eventwin);
+		gdk_window_lower (eventwin);
+		g_idle_add (lower_in_idle,
+			    g_object_ref (G_OBJECT (widget)));
+	}
+}
+
+static void
+stretch_widget_unmap (GtkWidget *widget)
+{
+	GdkWindow *eventwin = g_object_get_data (G_OBJECT (widget),
+						 "StretchEventWindow");
+	if (eventwin == NULL)
+		return;
+
+	gdk_window_hide (eventwin);
+}
+
+
+static void
+stretch_widget_size_allocate (GtkWidget     *widget,
+			      GtkAllocation *allocation)
+{
+	GdkWindow *eventwin;
+	int        x, y, w, h;
+	int        old_x, old_y, old_w, old_h, old_d;
+
+	eventwin = g_object_get_data (G_OBJECT (widget), "StretchEventWindow");
+	if (!eventwin)
+		return;
+
+	stretch_widget_calc_geometry (widget, &x, &y, &w, &h);
+
+	gdk_window_get_geometry (eventwin, &old_x, &old_y, &old_w, &old_h, &old_d);
+
+	if ((x == old_x) && (y == old_y) && (w == old_w) && (h == old_h))
+		return;
+
+	/* somewhat evil */
+	stretch_widget_unrealize (widget);
+	stretch_widget_realize (widget);
+	stretch_widget_map (widget);
+}
+
+static void
+stretch_widget_hierarchy_changed (GtkWidget *widget,
+				 GtkWidget *previous_toplevel)
+{
+	stretch_widget_unrealize (widget);
+	stretch_widget_realize (widget);
+	stretch_widget_map (widget);
+}
+
+static void
+stretch_cancel (GtkWidget         *widget)
+{
+	PanelStretchInfo *info;
+
+	info = g_object_get_data (G_OBJECT (widget), "stretch-info");
+
+	if (info) {
+		stretch_widget_unrealize (widget);
+
+		g_signal_handler_disconnect (widget, info->realize_id);
+		g_signal_handler_disconnect (widget, info->unrealize_id);
+		g_signal_handler_disconnect (widget, info->size_allocate_id);
+		g_signal_handler_disconnect (widget, info->map_id);
+		g_signal_handler_disconnect (widget, info->unmap_id);
+		g_signal_handler_disconnect (widget, info->hierarchy_changed_id);
+
+		g_object_set_data (G_OBJECT (widget), "stretch-info", NULL);
+	}
+}
+
+static void
+panel_stretch_events_to_toplevel_window (GtkWidget         *widget,
+					 GdkWindow	   *toplevel_window,
+					 PanelStretchFlags  flags)
+{
+	PanelStretchInfo *info;
+
+	if (flags == PANEL_STRETCH_NONE) {
+		stretch_cancel (widget);
+		return;
+	}
+
+	info = g_object_get_data (G_OBJECT (widget) , "stretch-info");
+
+	if (info) {
+		if (info->flags == flags &&
+		    info->toplevel_window == toplevel_window)
+			return;
+		info->flags = flags;
+		info->toplevel_window = toplevel_window;
+		stretch_widget_unrealize (widget);
+		stretch_widget_realize (widget);
+		stretch_widget_map (widget);
+		return;
+	}
+
+	info = g_new0 (PanelStretchInfo, 1);
+
+	info->realize_id =
+		g_signal_connect_after (GTK_WIDGET (widget), "realize",
+					G_CALLBACK (stretch_widget_realize),
+					NULL);
+	info->unrealize_id =
+		g_signal_connect (GTK_WIDGET (widget), "unrealize",
+				  G_CALLBACK (stretch_widget_unrealize),
+				  NULL);
+	info->size_allocate_id =
+		g_signal_connect_after (GTK_WIDGET (widget), "size_allocate",
+					G_CALLBACK (stretch_widget_size_allocate),
+					NULL);
+	info->map_id = 
+		g_signal_connect_after (GTK_WIDGET (widget), "map",
+					G_CALLBACK (stretch_widget_map),
+					NULL);
+	info->unmap_id = 
+		g_signal_connect_after (GTK_WIDGET (widget), "unmap",
+					G_CALLBACK (stretch_widget_unmap),
+					NULL);
+	info->hierarchy_changed_id = 
+		g_signal_connect_after (GTK_WIDGET (widget), "hierarchy_changed",
+					G_CALLBACK (stretch_widget_hierarchy_changed),
+					NULL);
+
+	info->flags = flags;
+	info->toplevel_window = toplevel_window;
+
+	g_object_set_data_full (G_OBJECT (widget), "stretch-info", info, g_free);
+
+	if (GTK_WIDGET_REALIZED (widget))
+		stretch_widget_realize (widget);
+	if (GTK_WIDGET_MAPPED (widget))
+		stretch_widget_map (widget);
+
+}
+
+static void
+stretch_weak_ref (gpointer data, GObject *where_object_was)
+{
+	PanelApplet *applet = data;
+	applet->priv->stretch_widget = NULL;
+}
+
+void
+panel_applet_set_stretch_widget (PanelApplet *applet,
+				 GtkWidget   *widget)
+{
+	if (widget != applet->priv->stretch_widget) {
+		if (applet->priv->stretch_widget && applet->priv->toplevel_window) {
+			panel_stretch_events_to_toplevel_window (applet->priv->stretch_widget, applet->priv->toplevel_window, PANEL_STRETCH_NONE);
+		}
+		if (applet->priv->stretch_widget)
+			g_object_weak_unref (G_OBJECT (applet->priv->stretch_widget), stretch_weak_ref, applet);
+		applet->priv->stretch_widget = widget;
+		if (applet->priv->stretch_widget)
+			g_object_weak_ref (G_OBJECT (applet->priv->stretch_widget), stretch_weak_ref, applet);
+		if (applet->priv->stretch_widget && applet->priv->toplevel_window) {
+			panel_stretch_events_to_toplevel_window (applet->priv->stretch_widget, applet->priv->toplevel_window, applet->priv->stretch_flags);
+		}
+	}
+}
+
+
 static void
 panel_applet_finalize (GObject *object)
 {
@@ -378,6 +728,9 @@ panel_applet_finalize (GObject *object)
 		bonobo_object_unref (
 			BONOBO_OBJECT (applet->priv->prop_sack));
 
+	if (applet->priv->stretch_widget)
+		g_object_weak_unref (G_OBJECT (applet->priv->stretch_widget), stretch_weak_ref, applet);
+
 	g_free (applet->priv->size_hints);
 	g_free (applet->priv->prefs_key);
 	g_free (applet->priv->background);
@@ -936,6 +1289,12 @@ panel_applet_get_prop (BonoboPropertyBag
 	case PROPERTY_LOCKED_DOWN_IDX:
 		BONOBO_ARG_SET_BOOLEAN (arg, applet->priv->locked_down);
 		break;
+	case PROPERTY_TOPLEVEL_WINDOW_IDX:
+		BONOBO_ARG_SET_LONG (arg, gdk_x11_drawable_get_xid (applet->priv->toplevel_window));
+		break;
+	case PROPERTY_STRETCH_FLAGS_IDX:
+		BONOBO_ARG_SET_SHORT (arg, applet->priv->stretch_flags);
+		break;
 	default:
 		g_assert_not_reached ();
 		break;
@@ -1039,6 +1398,34 @@ panel_applet_set_prop (BonoboPropertyBag
 	case PROPERTY_LOCKED_DOWN_IDX:
 		applet->priv->locked_down = BONOBO_ARG_GET_BOOLEAN (arg);
 		break;
+	case PROPERTY_TOPLEVEL_WINDOW_IDX:
+		{
+			GdkWindow *new_window;
+			GdkDisplay *display;
+
+			display = gdk_screen_get_display (gdk_drawable_get_screen(GTK_WIDGET (applet)->window));
+
+			new_window = gdk_window_lookup_for_display (display, BONOBO_ARG_GET_LONG (arg));
+			if (new_window == NULL) {
+				new_window = gdk_window_foreign_new_for_display (display, BONOBO_ARG_GET_LONG (arg));
+			}
+
+			if (applet->priv->toplevel_window != new_window) {
+				applet->priv->toplevel_window = new_window;
+				if (applet->priv->stretch_widget && applet->priv->toplevel_window) {
+					panel_stretch_events_to_toplevel_window (applet->priv->stretch_widget, applet->priv->toplevel_window, applet->priv->stretch_flags);
+				}
+			}
+		}
+		break;
+	case PROPERTY_STRETCH_FLAGS_IDX:
+		if (applet->priv->stretch_flags != BONOBO_ARG_GET_SHORT (arg)) {
+			applet->priv->stretch_flags = BONOBO_ARG_GET_SHORT (arg);
+			if (applet->priv->stretch_widget && applet->priv->toplevel_window) {
+				panel_stretch_events_to_toplevel_window (applet->priv->stretch_widget, applet->priv->toplevel_window, applet->priv->stretch_flags);
+			}
+		}
+		break;
 	default:
 		g_assert_not_reached ();
 		break;
@@ -1102,6 +1489,22 @@ panel_applet_property_bag (PanelApplet *
 				 _("The Applet's containing Panel is locked down"),
 				 Bonobo_PROPERTY_READABLE | Bonobo_PROPERTY_WRITEABLE);
 
+	bonobo_property_bag_add (sack,
+				 PROPERTY_TOPLEVEL_WINDOW,
+				 PROPERTY_TOPLEVEL_WINDOW_IDX,
+				 BONOBO_ARG_LONG,
+				 NULL,
+				 _("The XID of the toplevel window of the containing panel"),
+				 Bonobo_PROPERTY_READABLE | Bonobo_PROPERTY_WRITEABLE);
+
+	bonobo_property_bag_add (sack,
+				 PROPERTY_STRETCH_FLAGS,
+				 PROPERTY_STRETCH_FLAGS_IDX,
+				 BONOBO_ARG_SHORT,
+				 NULL,
+				 _("The Applet's containing Panel is locked down"),
+				 Bonobo_PROPERTY_READABLE | Bonobo_PROPERTY_WRITEABLE);
+
 	return sack;
 }
 
@@ -1364,6 +1767,9 @@ panel_applet_instance_init (PanelApplet 
 	applet->priv->size   = GNOME_Vertigo_PANEL_MEDIUM;
 
 	applet->priv->moving_focus_out = FALSE;
+
+	applet->priv->stretch_widget = GTK_WIDGET (applet);
+	g_object_weak_ref (G_OBJECT (applet->priv->stretch_widget), stretch_weak_ref, applet);
 
 	gtk_widget_set_events (GTK_WIDGET (applet), 
 			       GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
Index: libpanel-applet/panel-applet.h
===================================================================
RCS file: /cvs/gnome/gnome-panel/libpanel-applet/panel-applet.h,v
retrieving revision 1.36
diff -u -p -r1.36 panel-applet.h
--- libpanel-applet/panel-applet.h	15 Sep 2003 22:10:46 -0000	1.36
+++ libpanel-applet/panel-applet.h	13 Nov 2003 20:42:16 -0000
@@ -143,6 +143,9 @@ void               panel_applet_setup_me
 						      const BonoboUIVerb *verb_list,
 						      gpointer            user_data);
 
+void               panel_applet_set_stretch_widget   (PanelApplet        *applet,
+						      GtkWidget          *widget);
+
 
 int                panel_applet_factory_main          (const gchar		  *iid,
 						       GType                       applet_type,


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