[gtk+/client-side-decorations: 1/50] work in progress



commit c6a3cc92bb78918e5fa2782b83673649e648a802
Author: Cody Russell <crussell canonical com>
Date:   Fri May 15 14:59:01 2009 -0400

    work in progress

 gtk/gtkwindow-decorate.c |  499 ++++++++++++++++++++++++++++++----------------
 gtk/gtkwindow-decorate.h |    1 +
 gtk/gtkwindow.c          |  218 ++++++++++++++++++--
 gtk/gtkwindow.h          |    3 +
 4 files changed, 535 insertions(+), 186 deletions(-)
---
diff --git a/gtk/gtkwindow-decorate.c b/gtk/gtkwindow-decorate.c
index 5ff0612..31ad8f9 100644
--- a/gtk/gtkwindow-decorate.c
+++ b/gtk/gtkwindow-decorate.c
@@ -24,18 +24,20 @@
 #include "config.h"
 #include "gtkprivate.h"
 #include "gtkwindow.h"
+#include "gtkhbox.h"
+#include "gtkbutton.h"
 #include "gtkmain.h"
 #include "gtkwindow-decorate.h"
 #include "gtkintl.h"
 #include "gtkalias.h"
 
-
-#ifdef DECORATE_WINDOWS
+#include <math.h>
 
 typedef enum
 {
   GTK_WINDOW_REGION_TITLE,
   GTK_WINDOW_REGION_MAXIMIZE,
+  GTK_WINDOW_REGION_MINIMIZE,
   GTK_WINDOW_REGION_CLOSE,
   GTK_WINDOW_REGION_BR_RESIZE
 } GtkWindowRegionType;
@@ -69,29 +71,31 @@ struct _GtkWindowDecoration
 
   gint last_x, last_y;
   gint last_w, last_h;
-  
+
+  gint radius;
+  gboolean round_corners;
+
   PangoLayout *title_layout;
 
   GtkWindowResizeType resize;
-  
+
+  GtkWidget *hbox;
+  GtkWidget *close_button;
+  GtkWidget *max_button;
+  GtkWidget *min_button;
+
+  guint minimizing : 1;
   guint moving : 1;
   guint closing : 1;
   guint maximizing : 1;
   guint maximized : 1;
   guint maximizable : 1;
+  guint minimizable : 1;
   guint decorated : 1;
   guint real_inner_move : 1;
   guint focused : 1;
 };
 
-#define DECORATION_BORDER_TOP 15
-#define DECORATION_BORDER_LEFT 3
-#define DECORATION_BORDER_RIGHT 3
-#define DECORATION_BORDER_BOTTOM 3
-#define DECORATION_BORDER_TOT_X (DECORATION_BORDER_LEFT + DECORATION_BORDER_RIGHT)
-#define DECORATION_BORDER_TOT_Y (DECORATION_BORDER_TOP + DECORATION_BORDER_BOTTOM)
-#define DECORATION_BUTTON_SIZE 9
-#define DECORATION_BUTTON_Y_OFFSET 2
 #define DECORATION_TITLE_FONT "Sans 9"
 
 static void gtk_decorated_window_recalculate_regions      (GtkWindow      *window);
@@ -122,6 +126,8 @@ gtk_decoration_free (GtkWindowDecoration *deco)
   deco->regions = NULL;
   deco->n_regions = 0;
 
+  g_object_unref (deco->hbox);
+
   g_free (deco);
 }
 
@@ -141,12 +147,22 @@ gtk_decorated_window_init (GtkWindow   *window)
   deco->closing = FALSE;
   deco->maximizing = FALSE;
   deco->maximized = FALSE;
+  deco->minimizing = FALSE;
   deco->maximizable = FALSE;
   deco->real_inner_move = FALSE;
- 
+  deco->round_corners = TRUE;
+  deco->radius = 5;
+
+  deco->close_button = gtk_button_new_from_stock ("stock-smiley-26");
+  deco->hbox = gtk_hbox_new (FALSE, 0);
+  gtk_box_pack_start (GTK_BOX (deco->hbox), deco->close_button, FALSE, FALSE, 0);
+  gtk_widget_show_all (deco->hbox);
+  gtk_widget_set_parent_window (deco->hbox, window->frame);
+  gtk_widget_set_parent (deco->hbox, GTK_WIDGET (window));
+
   g_object_set_data_full (G_OBJECT (window), I_("gtk-window-decoration"), deco,
 			  (GDestroyNotify) gtk_decoration_free);
-  
+
   gtk_window_set_has_frame (window, TRUE);
 
   g_signal_connect (window,
@@ -177,35 +193,69 @@ get_decoration (GtkWindow *window)
   return (GtkWindowDecoration *)g_object_get_data (G_OBJECT (window), "gtk-window-decoration");
 }
 
+GtkWidget *
+gtk_decorated_window_get_box (GtkWindow *window)
+{
+  GtkWindowDecoration *deco;
+
+  g_return_val_if_fail (GTK_IS_WINDOW (window), NULL);
+
+  deco = get_decoration (window);
+
+  return deco->hbox;
+}
+
 void
 gtk_decorated_window_set_title (GtkWindow   *window,
 				const gchar *title)
 {
-  GtkWindowDecoration *deco = get_decoration (window);
-  
+  GtkWindowDecoration *deco;
+
+  g_return_val_if_fail (GTK_IS_WINDOW (window), NULL);
+
+  deco = get_decoration (window);
+
   if (deco->title_layout)
     pango_layout_set_text (deco->title_layout, title, -1);
 }
 
-void 
+void
 gtk_decorated_window_calculate_frame_size (GtkWindow *window)
 {
   GdkWMDecoration decorations;
   GtkWindowDecoration *deco = get_decoration (window);
-  
-  if (gdk_window_get_decorations (GTK_WIDGET (window)->window,
-				  &decorations))
+  gint border_left, border_top, border_right, border_bottom;
+
+  decorations = gtk_window_get_client_side_decorations (window);
+  if (!decorations)
+    {
+      gdk_window_get_decorations (GTK_WIDGET (window)->window,
+                                  &decorations);
+    }
+
+  if (decorations)
     {
       if ((decorations & GDK_DECOR_BORDER) &&
 	  (decorations & GDK_DECOR_TITLE))
 	{
 	  deco->decorated = TRUE;
+
 	  if ((decorations & GDK_DECOR_MAXIMIZE) &&
 	      (gtk_window_get_type_hint (window) == GDK_WINDOW_TYPE_HINT_NORMAL))
-	    deco->maximizable = TRUE;
+            {
+              deco->maximizable = TRUE;
+            }
+
+          if ((decorations & GDK_DECOR_MINIMIZE) &&
+              (gtk_window_get_type_hint (window) == GDK_WINDOW_TYPE_HINT_NORMAL))
+            {
+              deco->minimizable = TRUE;
+            }
 	}
       else
-	deco->decorated = FALSE;
+        {
+          deco->decorated = FALSE;
+        }
     }
   else
     {
@@ -214,13 +264,24 @@ gtk_decorated_window_calculate_frame_size (GtkWindow *window)
     }
 
   if (deco->decorated)
-    gtk_window_set_frame_dimensions (window,
-				     DECORATION_BORDER_LEFT,
-				     DECORATION_BORDER_TOP,
-				     DECORATION_BORDER_RIGHT,
-				     DECORATION_BORDER_BOTTOM);
+    {
+      gtk_widget_style_get (GTK_WIDGET (window),
+                            "decoration-border-left",   &border_left,
+                            "decoration-border-top",    &border_top,
+                            "decoration-border-right",  &border_right,
+                            "decoration-border-bottom", &border_bottom,
+                            NULL);
+
+      gtk_window_set_frame_dimensions (window,
+                                       border_left,
+                                       border_top,
+                                       border_right,
+                                       border_bottom);
+    }
   else
-    gtk_window_set_frame_dimensions (window, 0, 0, 0, 0);
+    {
+      gtk_window_set_frame_dimensions (window, 0, 0, 0, 0);
+    }
 
   gtk_decorated_window_recalculate_regions (window);
 }
@@ -261,7 +322,7 @@ gtk_decorated_window_inner_get_pos (GdkWindow *win,
   GtkWindow *window = (GtkWindow *)user_data;
 
   gdk_window_get_position (window->frame, x, y);
-  
+
   *x += window->frame_left;
   *y += window->frame_top;
 }
@@ -279,20 +340,6 @@ gtk_decorated_window_realize (GtkWindow   *window)
   font_desc = pango_font_description_from_string(DECORATION_TITLE_FONT);
   pango_layout_set_font_description (deco->title_layout, font_desc);
   pango_font_description_free (font_desc);
-
-#if 0
-  /* What is this code exactly doing? I remember we were using the
-     decorated windows with the DirectFB port and it did just work,
-     and there was definitely no code in linux-fb involved. */
-  gdk_fb_window_set_child_handler (window->frame,
-				   gtk_decorated_window_inner_change,
-				   gtk_decorated_window_inner_get_pos,
-				   window);
-
-  /* This is a huge hack to make frames have the same shape as
-     the window they wrap */
-  gdk_window_shape_combine_mask (window->frame, GDK_FB_USE_CHILD_SHAPE, 0, 0);
-#endif
 }
 
 
@@ -363,20 +410,28 @@ gtk_decorated_window_motion_notify (GtkWidget       *widget,
   GdkWindow *win;
   gint x, y;
   gint win_x, win_y, win_w, win_h;
-  
+  gint border_top, border_left, border_right, border_bottom;
+
   window = GTK_WINDOW (widget);
   deco = get_decoration (window);
-  
+
   if (!deco->decorated)
     return TRUE;
-  
+
   win = widget->window;
   gdk_window_get_pointer (window->frame, &x, &y, &mask);
-  
+
+  gtk_widget_style_get (GTK_WIDGET (window),
+                        "decoration-border-left",   &border_left,
+                        "decoration-border-top",    &border_top,
+                        "decoration-border-right",  &border_right,
+                        "decoration-border-bottom", &border_bottom,
+                        NULL);
+
   gdk_window_get_position (window->frame, &win_x, &win_y);
-  win_x += DECORATION_BORDER_LEFT;
-  win_y += DECORATION_BORDER_TOP;
-  
+  win_x += border_left;
+  win_y += border_top;
+
   gdk_window_get_geometry (win, NULL, NULL, &win_w, &win_h, NULL);
 
   if (deco->moving)
@@ -397,14 +452,14 @@ gtk_decorated_window_motion_notify (GtkWidget       *widget,
       
       switch(deco->resize) {
       case RESIZE_BOTTOM_RIGHT:
-	w = x - DECORATION_BORDER_TOT_X;
-	h = y - DECORATION_BORDER_TOT_Y;
+	w = x - border_left + border_right;
+	h = y - border_top + border_bottom;
 	break;
       case RESIZE_RIGHT:
-	w = x - DECORATION_BORDER_TOT_X;
+	w = x - border_left + border_right;
 	break;
       case RESIZE_BOTTOM:
-	h = y - DECORATION_BORDER_TOT_Y;
+	h = y - border_top + border_bottom;
 	break;
       case RESIZE_TOP_LEFT:
       case RESIZE_TOP:
@@ -440,8 +495,11 @@ gtk_decorated_window_region_type (GtkWindow *window, gint x, gint y)
 	  (x - deco->regions[i].rect.x < deco->regions[i].rect.width) &&
 	  (y > deco->regions[i].rect.y) &&
 	  (y - deco->regions[i].rect.y < deco->regions[i].rect.height))
-	return deco->regions[i].type;
+        {
+          return deco->regions[i].type;
+        }
     }
+
   return -1;
 }
 
@@ -452,7 +510,7 @@ gtk_decorated_window_button_press (GtkWidget       *widget,
   GtkWindow *window;
   GtkWindowRegionType type;
   GtkWindowDecoration *deco;
-  gint x, y; 
+  gint x, y;
 
   window = GTK_WINDOW (widget);
   deco = get_decoration (window);
@@ -462,40 +520,50 @@ gtk_decorated_window_button_press (GtkWidget       *widget,
 
   x = event->x;
   y = event->y;
-  
+
   type = gtk_decorated_window_region_type (window, x, y);
 
   switch (type)
     {
     case GTK_WINDOW_REGION_TITLE:
-      if (!deco->maximized && event->state & GDK_BUTTON1_MASK)
+      if (!deco->maximized && event->button == 1)
 	{
-	  deco->last_x = x;
-	  deco->last_y = y;
-	  deco->moving = TRUE;
+          gtk_window_begin_move_drag (window,
+                                      event->button,
+                                      event->x_root,
+                                      event->y_root,
+                                      event->time);
 	}
       break;
+#if 0
     case GTK_WINDOW_REGION_MAXIMIZE:
-      if (event->state & GDK_BUTTON1_MASK)
+      if (event->button == 1)
 	deco->maximizing = TRUE;
       break;
+    case GTK_WINDOW_REGION_MINIMIZE:
+      if (event->button == 1)
+        deco->minimizing = TRUE;
+      break;
     case GTK_WINDOW_REGION_CLOSE:
-      if (event->state & GDK_BUTTON1_MASK)
+      if (event->button == 1)
 	deco->closing = TRUE;
       break;
+#endif
     case GTK_WINDOW_REGION_BR_RESIZE:
       if (!deco->maximized)
 	{
-	  if (event->state & GDK_BUTTON1_MASK)
-	    deco->resize = RESIZE_BOTTOM_RIGHT;
-	  deco->last_x = x;
-	  deco->last_y = y;
+          gtk_window_begin_resize_drag (window,
+                                        GDK_WINDOW_EDGE_SOUTH_EAST,
+                                        event->button,
+                                        event->x_root,
+                                        event->y_root,
+                                        event->time);
 	}
       break;
     default:
       break;
     }
-  
+
   return TRUE;
 }
 
@@ -506,13 +574,13 @@ gtk_decorated_window_button_release (GtkWidget	    *widget,
   GtkWindow *window;
   GtkWindowRegionType type;
   GtkWindowDecoration *deco;
-      
+
   window = GTK_WINDOW (widget);
+  type = gtk_decorated_window_region_type (window, event->x, event->y);
   deco = get_decoration (window);
 
   if (deco->closing)
     {
-      type = gtk_decorated_window_region_type (window, event->x, event->y);
       if (type == GTK_WINDOW_REGION_CLOSE)
 	{
 	  GdkEvent *event = gdk_event_new (GDK_DELETE);
@@ -527,7 +595,6 @@ gtk_decorated_window_button_release (GtkWidget	    *widget,
     }
   else if (deco->maximizing)
     {
-      type = gtk_decorated_window_region_type (window, event->x, event->y);
       if (type == GTK_WINDOW_REGION_MAXIMIZE)
         {
 	  if (deco->maximized)
@@ -536,9 +603,17 @@ gtk_decorated_window_button_release (GtkWidget	    *widget,
 	    gtk_window_maximize (window);
 	}
     }
-  
+  else if (deco->minimizing)
+    {
+      if (type == GTK_WINDOW_REGION_MINIMIZE)
+        {
+          gtk_window_iconify (window);
+        }
+    }
+
   deco->closing = FALSE;
   deco->maximizing = FALSE;
+  deco->minimizing = FALSE;
   deco->moving = FALSE;
   deco->resize = RESIZE_NONE;
   return TRUE;
@@ -551,11 +626,19 @@ gtk_decorated_window_window_state (GtkWidget	       *widget,
   GtkWindow *window;
   GtkWindowDecoration *deco;
   GdkWindowObject *priv;
-      
+  gint border_left, border_right, border_top, border_bottom;
+
   window = GTK_WINDOW (widget);
   deco = get_decoration (window);
   priv = GDK_WINDOW_OBJECT (window->frame);
 
+  gtk_widget_style_get (widget,
+                        "decoration-border-left",   &border_left,
+                        "decoration-border-top",    &border_top,
+                        "decoration-border-right",  &border_right,
+                        "decoration-border-bottom", &border_bottom,
+                        NULL);
+
   if (event->changed_mask & GDK_WINDOW_STATE_MAXIMIZED)
     {
       if (event->new_window_state & GDK_WINDOW_STATE_MAXIMIZED)
@@ -564,12 +647,12 @@ gtk_decorated_window_window_state (GtkWidget	       *widget,
 	  gdk_window_get_geometry (widget->window, NULL, NULL,
 				   &deco->last_w, &deco->last_h, NULL);
 	  gdk_window_get_origin (widget->window, &deco->last_x, &deco->last_y);
-	  w = gdk_screen_get_width(gdk_screen_get_default()) - DECORATION_BORDER_TOT_X;
-	  h = gdk_screen_get_height(gdk_screen_get_default()) - DECORATION_BORDER_TOT_Y;
+	  w = gdk_screen_get_width(gdk_screen_get_default()) - border_left + border_right;
+	  h = gdk_screen_get_height(gdk_screen_get_default()) - border_top + border_bottom;
 	  _gtk_window_constrain_size (window, w, h, &w, &h);
 	  if (w != deco->last_w || h != deco->last_h)
 	    {
-	      _gtk_window_reposition (window, DECORATION_BORDER_LEFT, DECORATION_BORDER_TOP);
+	      _gtk_window_reposition (window, border_left, border_top);
 	      gdk_window_resize (widget->window, w, h);
 	      deco->maximized = TRUE;
 	    }
@@ -594,60 +677,128 @@ gtk_decorated_window_paint (GtkWidget    *widget,
   GtkWindowDecoration *deco = get_decoration (window);
   gint x1, y1, x2, y2;
   GtkStateType border_state;
+  GdkRectangle rect;
 
   if (deco->decorated)
     {
       GdkWindow *frame;
       gint width, height;
+      gint border_top, border_bottom, border_left, border_right;
+      gint button_size;
+      gint y_offset;
 
       frame = window->frame;
       gdk_drawable_get_size (frame, &width, &height);
 
+      gtk_widget_style_get (GTK_WIDGET (window),
+                            "decoration-border-left",     &border_left,
+                            "decoration-border-top",      &border_top,
+                            "decoration-border-right",    &border_right,
+                            "decoration-border-bottom",   &border_bottom,
+                            "decoration-button-size",     &button_size,
+                            "decoration-button-y-offset", &y_offset,
+                            NULL);
+
+      height += border_top + border_bottom;
+      width += border_left + border_right;
+
+      rect.x = area->x - border_left;
+      rect.y = area->y - border_top;
+      rect.width = area->width + border_left + border_right;
+      rect.height = area->height + border_top + border_bottom;
+
+#if 1
+      /* XXX - what is this for? */
+
       /* Top */
       gtk_paint_flat_box (widget->style, frame, GTK_STATE_NORMAL,
 			  GTK_SHADOW_NONE, area, widget, "base",
 			  0, 0,
-			  width, DECORATION_BORDER_TOP);
+			  width, border_top);
       /* Bottom */
       gtk_paint_flat_box (widget->style, frame, GTK_STATE_NORMAL,
 			  GTK_SHADOW_NONE, area, widget, "base",
-			  0, height - DECORATION_BORDER_BOTTOM,
-			  width, DECORATION_BORDER_BOTTOM);
+			  0, height - border_bottom,
+			  width, border_bottom);
       /* Left */
       gtk_paint_flat_box (widget->style, frame, GTK_STATE_NORMAL,
 			  GTK_SHADOW_NONE, area, widget, "base",
-			  0, DECORATION_BORDER_TOP,
-			  DECORATION_BORDER_LEFT, height - DECORATION_BORDER_TOT_Y);
+			  0, border_top,
+			  border_left, height - border_top + border_bottom);
       /* Right */
       gtk_paint_flat_box (widget->style, frame, GTK_STATE_NORMAL,
 			  GTK_SHADOW_NONE, area, widget, "base",
-			  width - DECORATION_BORDER_RIGHT, DECORATION_BORDER_TOP,
-			  DECORATION_BORDER_RIGHT, height - DECORATION_BORDER_TOT_Y);
-      
+			  width - border_right, border_top,
+			  border_right, height - border_top + border_bottom);
+#endif
+
       /* Border: */
       if (deco->focused)
 	border_state = GTK_STATE_SELECTED;
-      else 
+      else
 	border_state = GTK_STATE_PRELIGHT;
 
-      gtk_paint_box (widget->style, frame, border_state, 
-		     GTK_SHADOW_OUT, area, widget, "base",
-		     0, 0, width, height);
-      
-      gtk_paint_box (widget->style, frame, border_state, 
-		     GTK_SHADOW_IN, area, widget, "base",
-		     DECORATION_BORDER_LEFT - 2, DECORATION_BORDER_TOP - 2,
-		     width - (DECORATION_BORDER_LEFT + DECORATION_BORDER_RIGHT) + 3,
-		     height - (DECORATION_BORDER_TOP + DECORATION_BORDER_BOTTOM) + 3);
+      if (deco->round_corners)
+        {
+          cairo_pattern_t *gradient;
+          cairo_t *cr;
+          const int hmargin = 2, vmargin = 2, radius = 5;
+          const int width = widget->allocation.width + border_left + border_right;
+          const int height = widget->allocation.height + border_top + border_bottom;
+
+          cr = gdk_cairo_create (frame);
+          cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
+          cairo_paint (cr);
+
+          cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
+          cairo_arc (cr, hmargin + radius, vmargin + radius,
+                     radius, M_PI, 3 * M_PI / 2);
+          cairo_line_to (cr, width - hmargin - radius, vmargin);
+          cairo_arc (cr, width - hmargin - radius, vmargin + radius,
+                     radius, 3 * M_PI / 2, 2 * M_PI);
+          cairo_line_to (cr, width - hmargin, height - vmargin - radius);
+          cairo_arc (cr, width - hmargin - radius, height - vmargin - radius,
+                     radius, 0, M_PI / 2);
+          cairo_line_to (cr, hmargin + radius, height - vmargin);
+          cairo_arc (cr, hmargin + radius, height - vmargin - radius,
+                     radius, M_PI / 2, M_PI);
+          cairo_close_path (cr);
+
+          gradient = cairo_pattern_create_linear (width / 2 - 1, vmargin,
+                                                  width / 2 + 1, height);
+          cairo_pattern_add_color_stop_rgba (gradient, 0, 1, 1, 1, 0.2);
+          cairo_pattern_add_color_stop_rgba (gradient, 1, 1, 1, 1, 0.9);
+          cairo_set_source (cr, gradient);
+          cairo_fill_preserve (cr);
+
+          cairo_set_source_rgba (cr, 1, 1, 1, 2);
+          cairo_set_line_width (cr, 1);
+          cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
+          cairo_stroke (cr);
+
+          cairo_destroy (cr);
+        }
+      else
+        {
+          gtk_paint_box (widget->style, frame, border_state,
+                         GTK_SHADOW_OUT, area, widget, "base",
+                         0, 0, width, height);
+
+          gtk_paint_box (widget->style, frame, border_state,
+                         GTK_SHADOW_IN, area, widget, "base",
+                         border_left - 2, border_top - 2,
+                         width - (border_left + border_right) + 3,
+                         height - (border_top + border_bottom) + 3);
+        }
 
+#if 0
       if (deco->maximizable)
 	{
 	  /* Maximize button: */
-
-	  x1 = width - (DECORATION_BORDER_LEFT * 2) - (DECORATION_BUTTON_SIZE * 2);
-	  y1 = DECORATION_BUTTON_Y_OFFSET;
-	  x2 = x1 + DECORATION_BUTTON_SIZE;
-	  y2 = y1 + DECORATION_BUTTON_SIZE;
+	  x1 = width - (border_left * 2) - (button_size * 2);
+	  y1 = y_offset;
+	  x2 = x1 + button_size;
+	  y2 = y1 + button_size;
 
 	  if (area)
 	    gdk_gc_set_clip_rectangle (widget->style->bg_gc[widget->state], area);
@@ -659,18 +810,37 @@ gtk_decorated_window_paint (GtkWidget    *widget,
 
 	  gdk_draw_rectangle (frame, widget->style->black_gc, FALSE,
 			      x1 + 1, y1 + 2,
-			      DECORATION_BUTTON_SIZE - 3, DECORATION_BUTTON_SIZE - 4);
+			      button_size - 3, button_size - 4);
 
 	  if (area)
 	    gdk_gc_set_clip_rectangle (widget->style->black_gc, NULL);
 	}
-      
+
+      if (deco->minimizable)
+        {
+          /* Minimize button */
+          x1 = width - (border_left * 2) - (button_size * 3);
+          y1 = y_offset;
+          x2 = x1 + button_size;
+          y2 = y1 + button_size;
+
+          if (area)
+            gdk_gc_set_clip_rectangle (widget->style->bg_gc[widget->state], area);
+
+          gdk_draw_rectangle (frame, widget->style->bg_gc[widget->state], TRUE,
+                              x1, y1, x2 - x1, y2 - y1);
+
+          gdk_draw_line (frame, widget->style->black_gc, x1 + 1, y2 - 2, x2 - 2, y2 - 2);
+
+          if (area)
+            gdk_gc_set_clip_rectangle (widget->style->black_gc, NULL);
+        }
+
       /* Close button: */
-      
-      x1 = width - DECORATION_BORDER_LEFT - DECORATION_BUTTON_SIZE;
-      y1 = DECORATION_BUTTON_Y_OFFSET;
-      x2 = width - DECORATION_BORDER_LEFT;
-      y2 = DECORATION_BUTTON_Y_OFFSET + DECORATION_BUTTON_SIZE;
+      x1 = width - border_left - button_size;
+      y1 = y_offset;
+      x2 = width - border_left;
+      y2 = y_offset + button_size;
 
       if (area)
 	gdk_gc_set_clip_rectangle (widget->style->bg_gc[widget->state], area);
@@ -679,10 +849,10 @@ gtk_decorated_window_paint (GtkWidget    *widget,
 			  x1, y1, x2 - x1, y2 - y1);
 
       if (area)
-	gdk_gc_set_clip_rectangle (widget->style->bg_gc[widget->state], NULL);
-      
-      if (area)
-	gdk_gc_set_clip_rectangle (widget->style->black_gc, area);
+        {
+          gdk_gc_set_clip_rectangle (widget->style->bg_gc[widget->state], NULL);
+          gdk_gc_set_clip_rectangle (widget->style->black_gc, area);
+        }
 
       gdk_draw_line (frame, widget->style->black_gc, x1, y1, x2-1, y2-1);
 
@@ -690,9 +860,9 @@ gtk_decorated_window_paint (GtkWidget    *widget,
 
       if (area)
 	gdk_gc_set_clip_rectangle (widget->style->black_gc, NULL);
-      
-      
+#endif
 
+#if 0
       /* Title */
       if (deco->title_layout)
 	{
@@ -701,12 +871,12 @@ gtk_decorated_window_paint (GtkWidget    *widget,
 
 	  gdk_draw_layout (frame,
 			   widget->style->fg_gc [border_state],
-			   DECORATION_BORDER_LEFT, 1,
+			   border_left, 1,
 			   deco->title_layout);
 	  if (area)
 	    gdk_gc_set_clip_rectangle (widget->style->fg_gc [border_state], NULL);
 	}
-      
+#endif
     }
 }
 
@@ -718,15 +888,20 @@ gtk_decorated_window_recalculate_regions (GtkWindow *window)
   gint width, height;
   GtkWindowRegion *region;
   GtkWindowDecoration *deco = get_decoration (window);
-      
+  gint border_left, border_right, border_top, border_bottom;
+  gint button_size;
+  gint y_offset;
+
   n_regions = 0;
 
   if (!deco->decorated)
     return;
-  
+
   n_regions += 2; /* close, Title */
   if (deco->maximizable)
     n_regions += 1;
+  if (deco->minimizable)
+    n_regions += 1;
   if (window->allow_shrink || window->allow_grow)
     n_regions += 2;
 
@@ -737,51 +912,70 @@ gtk_decorated_window_recalculate_regions (GtkWindow *window)
       deco->n_regions = n_regions;
     }
 
-  width = GTK_WIDGET (window)->allocation.width + DECORATION_BORDER_TOT_X;
-  height = GTK_WIDGET (window)->allocation.height + DECORATION_BORDER_TOT_Y;
+  gtk_widget_style_get (GTK_WIDGET (window),
+                        "decoration-border-left",     &border_left,
+                        "decoration-border-top",      &border_top,
+                        "decoration-border-right",    &border_right,
+                        "decoration-border-bottom",   &border_bottom,
+                        "decoration-button-size",     &button_size,
+                        "decoration-button-y-offset", &y_offset,
+                        NULL);
+
+  width = GTK_WIDGET (window)->allocation.width + border_left + border_right;
+  height = GTK_WIDGET (window)->allocation.height + border_top + border_bottom;
 
   region = deco->regions;
 
+  if (deco->minimizable)
+    {
+      region->rect.x = width - (border_left * 2) - (button_size * 3);
+      region->rect.y = y_offset;
+      region->rect.width = button_size;
+      region->rect.height = button_size;
+      region->type = GTK_WINDOW_REGION_MINIMIZE;
+      region++;
+    }
+
   /* Maximize button */
   if (deco->maximizable)
     {
-      region->rect.x = width - (DECORATION_BORDER_LEFT * 2) - (DECORATION_BUTTON_SIZE * 2);
-      region->rect.y = DECORATION_BUTTON_Y_OFFSET;
-      region->rect.width = DECORATION_BUTTON_SIZE;
-      region->rect.height = DECORATION_BUTTON_SIZE;
+      region->rect.x = width - (border_left * 2) - (button_size * 2);
+      region->rect.y = y_offset;
+      region->rect.width = button_size;
+      region->rect.height = button_size;
       region->type = GTK_WINDOW_REGION_MAXIMIZE;
       region++;
     }
 
   /* Close button */
-  region->rect.x = width - DECORATION_BORDER_LEFT - DECORATION_BUTTON_SIZE;
-  region->rect.y = DECORATION_BUTTON_Y_OFFSET;
-  region->rect.width = DECORATION_BUTTON_SIZE;
-  region->rect.height = DECORATION_BUTTON_SIZE;
+  region->rect.x = width - border_left - button_size;
+  region->rect.y = y_offset;
+  region->rect.width = button_size;
+  region->rect.height = button_size;
   region->type = GTK_WINDOW_REGION_CLOSE;
   region++;
-    
+
   /* title bar */
   region->rect.x = 0;
   region->rect.y = 0;
   region->rect.width = width;
-  region->rect.height = DECORATION_BORDER_TOP;
+  region->rect.height = border_top;
   region->type = GTK_WINDOW_REGION_TITLE;
   region++;
-  
+
   if (window->allow_shrink || window->allow_grow)
     {
-      region->rect.x = width - (DECORATION_BORDER_RIGHT + 10);
-      region->rect.y = height - DECORATION_BORDER_BOTTOM;
-      region->rect.width = DECORATION_BORDER_RIGHT + 10;
-      region->rect.height = DECORATION_BORDER_BOTTOM;
+      region->rect.x = width - (border_right + 10);
+      region->rect.y = height - border_bottom;
+      region->rect.width = border_right + 10;
+      region->rect.height = border_bottom;
       region->type = GTK_WINDOW_REGION_BR_RESIZE;
       region++;
 
-      region->rect.x = width - DECORATION_BORDER_RIGHT;
-      region->rect.y = height - (DECORATION_BORDER_BOTTOM + 10);
-      region->rect.width = DECORATION_BORDER_RIGHT;
-      region->rect.height = DECORATION_BORDER_BOTTOM + 10;
+      region->rect.x = width - border_right;
+      region->rect.y = height - (border_bottom + 10);
+      region->rect.width = border_right;
+      region->rect.height = border_bottom + 10;
       region->type = GTK_WINDOW_REGION_BR_RESIZE;
       region++;
     }
@@ -796,40 +990,11 @@ gtk_decorated_window_move_resize_window (GtkWindow   *window,
 {
   GtkWidget *widget = GTK_WIDGET (window);
   GtkWindowDecoration *deco = get_decoration (window);
-  
+
   deco->real_inner_move = TRUE;
   gdk_window_move_resize (widget->window,
 			  x, y, width, height);
 }
-#else
-
-void
-gtk_decorated_window_init (GtkWindow  *window)
-{
-}
-
-void 
-gtk_decorated_window_calculate_frame_size (GtkWindow *window)
-{
-}
-
-void
-gtk_decorated_window_set_title (GtkWindow   *window,
-				const gchar *title)
-{
-}
-
-void
-gtk_decorated_window_move_resize_window (GtkWindow   *window,
-					 gint         x,
-					 gint         y,
-					 gint         width,
-					 gint         height)
-{
-  gdk_window_move_resize (GTK_WIDGET (window)->window,
-			  x, y, width, height);
-}
-#endif
 
 
 #define __GTK_WINDOW_DECORATE_C__
diff --git a/gtk/gtkwindow-decorate.h b/gtk/gtkwindow-decorate.h
index 9f182f4..bd1f2a7 100644
--- a/gtk/gtkwindow-decorate.h
+++ b/gtk/gtkwindow-decorate.h
@@ -35,6 +35,7 @@ void gtk_decorated_window_move_resize_window   (GtkWindow   *window,
 						gint         y,
 						gint         width,
 						gint         height);
+GtkWidget *gtk_decorated_window_get_box        (GtkWindow *window);
 
 G_END_DECLS
 
diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c
index 1238c22..b48ac6d 100644
--- a/gtk/gtkwindow.c
+++ b/gtk/gtkwindow.c
@@ -185,6 +185,10 @@ struct _GtkWindowPrivate
   guint opacity_set : 1;
   guint builder_visible : 1;
 
+  gboolean client_side_decorated;
+  GdkWMDecoration client_side_decorations;
+  GdkWMDecoration old_decorations;
+
   GdkWindowTypeHint type_hint;
 
   gdouble opacity;
@@ -217,6 +221,8 @@ static gint gtk_window_key_press_event    (GtkWidget         *widget,
 					   GdkEventKey       *event);
 static gint gtk_window_key_release_event  (GtkWidget         *widget,
 					   GdkEventKey       *event);
+static gboolean gtk_window_button_press_event (GtkWidget      *widget,
+                                               GdkEventButton *event);
 static gint gtk_window_enter_notify_event (GtkWidget         *widget,
 					   GdkEventCrossing  *event);
 static gint gtk_window_leave_notify_event (GtkWidget         *widget,
@@ -456,7 +462,8 @@ gtk_window_class_init (GtkWindowClass *klass)
   widget_class->focus_out_event = gtk_window_focus_out_event;
   widget_class->client_event = gtk_window_client_event;
   widget_class->focus = gtk_window_focus;
-  
+  widget_class->button_press_event = gtk_window_button_press_event;
+
   widget_class->expose_event = gtk_window_expose;
    
   container_class->check_resize = gtk_window_check_resize;
@@ -778,6 +785,50 @@ gtk_window_class_init (GtkWindowClass *klass)
 							1.0,
 							GTK_PARAM_READWRITE));
 
+  /* Style properties */
+  gtk_widget_class_install_style_property (widget_class,
+                                           g_param_spec_boolean ("client-side-decorations",
+                                                                 P_("Client-side window decorations"),
+                                                                 P_("Whether to decorate windows without the WM"),
+                                                                 FALSE,
+                                                                 GTK_PARAM_READWRITE));
+
+  gtk_widget_class_install_style_property (widget_class,
+                                           g_param_spec_int ("decoration-border-top",
+                                                             P_("Top border decoration size"),
+                                                             P_("Top border decoration size"),
+                                                             0, G_MAXINT, 24, GTK_PARAM_READWRITE));
+
+  gtk_widget_class_install_style_property (widget_class,
+                                           g_param_spec_int ("decoration-border-left",
+                                                             P_("Left border decoration size"),
+                                                             P_("Left border decoration size"),
+                                                             0, G_MAXINT, 6, GTK_PARAM_READWRITE));
+
+  gtk_widget_class_install_style_property (widget_class,
+                                           g_param_spec_int ("decoration-border-right",
+                                                             P_("Right border decoration size"),
+                                                             P_("Right border decoration size"),
+                                                             0, G_MAXINT, 6, GTK_PARAM_READWRITE));
+
+  gtk_widget_class_install_style_property (widget_class,
+                                           g_param_spec_int ("decoration-border-bottom",
+                                                             P_("Bottom border decoration size"),
+                                                             P_("Bottom border decoration size"),
+                                                             0, G_MAXINT, 6, GTK_PARAM_READWRITE));
+
+  gtk_widget_class_install_style_property (widget_class,
+                                           g_param_spec_int ("decoration-button-size",
+                                                             P_("Decoration button size"),
+                                                             P_("Client-side decoration button size"),
+                                                             0, G_MAXINT, 12, GTK_PARAM_READWRITE));
+
+  gtk_widget_class_install_style_property (widget_class,
+                                           g_param_spec_int ("decoration-button-y-offset",
+                                                             P_("Decoration button Y offset"),
+                                                             P_("Client-side decoration button Y offset"),
+                                                             0, G_MAXINT, 4, GTK_PARAM_READWRITE));
+
   window_signals[SET_FOCUS] =
     g_signal_new (I_("set-focus"),
                   G_TYPE_FROM_CLASS (gobject_class),
@@ -929,11 +980,18 @@ gtk_window_init (GtkWindow *window)
   priv->type_hint = GDK_WINDOW_TYPE_HINT_NORMAL;
   priv->opacity = 1.0;
   priv->startup_id = NULL;
+  priv->client_side_decorated = TRUE;
+  priv->client_side_decorations = (GDK_DECOR_BORDER |
+                                   GDK_DECOR_TITLE  |
+                                   GDK_DECOR_MAXIMIZE);
+  priv->old_decorations = 0;
 
   colormap = _gtk_widget_peek_colormap ();
-  if (colormap)
-    gtk_widget_set_colormap (GTK_WIDGET (window), colormap);
-  
+  //if (colormap)
+  //  gtk_widget_set_colormap (GTK_WIDGET (window), colormap);
+  gtk_widget_set_colormap (GTK_WIDGET (window),
+                           gdk_screen_get_rgba_colormap (gtk_widget_get_screen (GTK_WIDGET (window))));
+
   g_object_ref_sink (window);
   window->has_user_ref_count = TRUE;
   toplevel_list = g_slist_prepend (toplevel_list, window);
@@ -2871,29 +2929,38 @@ gtk_window_set_geometry_hints (GtkWindow       *window,
  *
  * On Windows, this function always works, since there's no window manager
  * policy involved.
- * 
+ *
  **/
 void
 gtk_window_set_decorated (GtkWindow *window,
                           gboolean   setting)
 {
+  GtkWindowPrivate *priv;
+
   g_return_if_fail (GTK_IS_WINDOW (window));
 
+  priv = GTK_WINDOW_GET_PRIVATE (window);
   setting = setting != FALSE;
 
   if (setting == window->decorated)
     return;
 
   window->decorated = setting;
-  
+
   if (GTK_WIDGET (window)->window)
     {
-      if (window->decorated)
-        gdk_window_set_decorations (GTK_WIDGET (window)->window,
-                                    GDK_DECOR_ALL);
+      if (window->decorated && !priv->client_side_decorations)
+        {
+          g_print ("gdk_window_set_decorations (GDK_DECOR_ALL)\n");
+          gdk_window_set_decorations (GTK_WIDGET (window)->window,
+                                      GDK_DECOR_ALL);
+        }
       else
-        gdk_window_set_decorations (GTK_WIDGET (window)->window,
-                                    0);
+        {
+          g_print ("gdk_window_set_decorations (0)\n");
+          gdk_window_set_decorations (GTK_WIDGET (window)->window,
+                                      0);
+        }
     }
 
   g_object_notify (G_OBJECT (window), "decorated");
@@ -2916,6 +2983,55 @@ gtk_window_get_decorated (GtkWindow *window)
   return window->decorated;
 }
 
+void
+gtk_window_set_client_side_decorations (GtkWindow       *window,
+                                        GdkWMDecoration  setting)
+{
+  GtkWindowPrivate *priv;
+
+  g_return_if_fail (GTK_IS_WINDOW (window));
+
+  priv = GTK_WINDOW_GET_PRIVATE (window);
+
+  if (setting == priv->client_side_decorations)
+    return;
+
+  priv->client_side_decorations = setting;
+
+  if (GTK_WIDGET (window)->window)
+    {
+      if (priv->client_side_decorations)
+        {
+          gdk_window_get_decorations (GTK_WIDGET (window)->window,
+                                      &priv->old_decorations);
+          gdk_window_set_decorations (GTK_WIDGET (window)->window, 0);
+          g_print ("gdk_window_set_decorations (0)\n");
+        }
+      else
+        {
+          if (priv->old_decorations)
+            {
+              gdk_window_set_decorations (GTK_WIDGET (window)->window,
+                                          priv->old_decorations);
+              g_print ("gdk_window_set_decorations (non-zero)\n");
+              priv->old_decorations = 0;
+            }
+        }
+    }
+}
+
+GdkWMDecoration
+gtk_window_get_client_side_decorations (GtkWindow *window)
+{
+  GtkWindowPrivate *priv;
+
+  g_return_val_if_fail (GTK_IS_WINDOW (window), 0);
+
+  priv = GTK_WINDOW_GET_PRIVATE (window);
+
+  return priv->client_side_decorations;
+}
+
 /**
  * gtk_window_set_deletable:
  * @window: a #GtkWindow
@@ -4744,7 +4860,11 @@ gtk_window_realize (GtkWidget *widget)
       
       window->frame = gdk_window_new (gtk_widget_get_root_window (widget),
 				      &attributes, attributes_mask);
-						 
+      if (priv->client_side_decorations)
+        {
+          gdk_window_set_decorations (window->frame, 0);
+        }
+
       if (priv->opacity_set)
 	gdk_window_set_opacity (window->frame, priv->opacity);
 
@@ -4779,6 +4899,8 @@ gtk_window_realize (GtkWidget *widget)
 			    GDK_LEAVE_NOTIFY_MASK |
 			    GDK_FOCUS_CHANGE_MASK |
 			    GDK_STRUCTURE_MASK);
+  if (priv->client_side_decorated)
+    attributes.event_mask |= GDK_BUTTON_PRESS_MASK;
   attributes.type_hint = priv->type_hint;
 
   attributes_mask |= GDK_WA_VISUAL | GDK_WA_COLORMAP | GDK_WA_TYPE_HINT;
@@ -4809,9 +4931,12 @@ gtk_window_realize (GtkWidget *widget)
 
   if (window->wm_role)
     gdk_window_set_role (widget->window, window->wm_role);
-  
-  if (!window->decorated)
-    gdk_window_set_decorations (widget->window, 0);
+
+  if (!window->decorated || priv->client_side_decorated)
+    {
+      g_print ("gdk_window_set_decorations (0)\n");
+      gdk_window_set_decorations (widget->window, 0);
+    }
 
   if (!priv->deletable)
     gdk_window_set_functions (widget->window, GDK_FUNC_ALL | GDK_FUNC_CLOSE);
@@ -4899,17 +5024,18 @@ gtk_window_size_request (GtkWidget      *widget,
 {
   GtkWindow *window;
   GtkBin *bin;
+  GtkWidget *decorated_hbox;
+  GtkRequisition child_requisition;
 
   window = GTK_WINDOW (widget);
   bin = GTK_BIN (window);
-  
+  decorated_hbox = gtk_decorated_window_get_box (window);
+
   requisition->width = GTK_CONTAINER (window)->border_width * 2;
   requisition->height = GTK_CONTAINER (window)->border_width * 2;
 
   if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
     {
-      GtkRequisition child_requisition;
-      
       gtk_widget_size_request (bin->child, &child_requisition);
 
       requisition->width += child_requisition.width;
@@ -4923,9 +5049,14 @@ gtk_window_size_allocate (GtkWidget     *widget,
 {
   GtkWindow *window;
   GtkAllocation child_allocation;
+  GtkAllocation new_allocation;
+  GtkWidget *decorated_hbox = NULL;
+  GtkWindowPrivate *priv;
 
   window = GTK_WINDOW (widget);
   widget->allocation = *allocation;
+  priv = GTK_WINDOW_GET_PRIVATE (window);
+  decorated_hbox = gtk_decorated_window_get_box (window);
 
   if (window->bin.child && GTK_WIDGET_VISIBLE (window->bin.child))
     {
@@ -4939,6 +5070,25 @@ gtk_window_size_allocate (GtkWidget     *widget,
       gtk_widget_size_allocate (window->bin.child, &child_allocation);
     }
 
+  if (decorated_hbox && priv->client_side_decorations)
+    {
+      GtkRequisition deco_requisition;
+      GtkAllocation deco_allocation;
+
+      gtk_widget_size_request (decorated_hbox, &deco_requisition);
+
+      deco_allocation.x = 0;
+      deco_allocation.y = 0;
+      deco_allocation.width = deco_requisition.width;
+      deco_allocation.height = deco_requisition.height;
+
+      g_print ("deco x: %d, y: %d, width: %d, height: %d\n",
+               deco_allocation.x, deco_allocation.y,
+               deco_allocation.width, deco_allocation.width);
+
+      gtk_widget_size_allocate (decorated_hbox, &deco_allocation);
+    }
+
   if (GTK_WIDGET_REALIZED (widget) && window->frame)
     {
       gdk_window_resize (window->frame,
@@ -5196,6 +5346,26 @@ gtk_window_key_release_event (GtkWidget   *widget,
   return handled;
 }
 
+static gboolean
+gtk_window_button_press_event (GtkWidget      *widget,
+                               GdkEventButton *event)
+{
+  GtkWindowPrivate *priv = GTK_WINDOW_GET_PRIVATE (widget);
+
+  if (priv->client_side_decorated)
+    {
+      gtk_window_begin_move_drag (GTK_WINDOW (widget),
+                                  event->button,
+                                  event->x_root,
+                                  event->y_root,
+                                  event->time);
+
+      return TRUE;
+    }
+
+  return GTK_WIDGET_CLASS (gtk_window_parent_class)->button_press_event (widget, event);
+}
+
 static void
 gtk_window_real_activate_default (GtkWindow *window)
 {
@@ -6570,9 +6740,19 @@ static gint
 gtk_window_expose (GtkWidget      *widget,
 		   GdkEventExpose *event)
 {
+  GtkWindowPrivate *priv = GTK_WINDOW_GET_PRIVATE (widget);
+  GtkWidget *hbox = gtk_decorated_window_get_box (GTK_WINDOW (widget));
+
   if (!GTK_WIDGET_APP_PAINTABLE (widget))
     gtk_window_paint (widget, &event->area);
-  
+
+  if (hbox && priv->client_side_decorations)
+    {
+      gtk_container_propagate_expose (GTK_CONTAINER (widget),
+                                      hbox,
+                                      event);
+    }
+
   if (GTK_WIDGET_CLASS (gtk_window_parent_class)->expose_event)
     return GTK_WIDGET_CLASS (gtk_window_parent_class)->expose_event (widget, event);
 
diff --git a/gtk/gtkwindow.h b/gtk/gtkwindow.h
index 6918971..f8af4c1 100644
--- a/gtk/gtkwindow.h
+++ b/gtk/gtkwindow.h
@@ -271,6 +271,9 @@ void       gtk_window_get_frame_dimensions     (GtkWindow *window,
 void       gtk_window_set_decorated            (GtkWindow *window,
                                                 gboolean   setting);
 gboolean   gtk_window_get_decorated            (GtkWindow *window);
+void       gtk_window_set_client_side_decorations (GtkWindow       *window,
+                                                   GdkWMDecoration  decoration);
+GdkWMDecoration gtk_window_get_client_side_deocrations (GtkWindow *window);
 void       gtk_window_set_deletable            (GtkWindow *window,
                                                 gboolean   setting);
 gboolean   gtk_window_get_deletable            (GtkWindow *window);



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