Re: non-attached style detached in gtkinvisible.



On 20 Dec 2000, Owen Taylor wrote:
> (I'm not so sure that your usage of GtkInvisible in the GtkWindow
> code is appropriate - I'll try to read that over in detail and get
> comments to you on that today.)

Here is a new version of that patch after i've made some changes tim
suggested. I would like to replace the dummy_widget hace with something
cleaner, but don't know what.

This is just the Gtk parts, there are some small changes to gdkfb too. One
function to read the decorations from a window and one to trap
gdk_window_move (GTK_WIDGET (window)->window, x, y) calls.

/ Alex

Index: Makefile.am
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/Makefile.am,v
retrieving revision 1.141
diff -u -p -r1.141 Makefile.am
--- Makefile.am	2000/11/16 21:17:53	1.141
+++ Makefile.am	2000/12/20 17:03:17
@@ -412,6 +412,7 @@ gtk_extra_sources = @STRIP_BEGIN@ \
 	maketypes.awk		\
 	makeenums.h		\
 	gtkargcollector.c	\
+	gtkwindow-decorate.c    \
 	gtk-boxed.defs		\
 	gtkmarshal.list		\
 @STRIP_END@
Index: gtkwindow.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkwindow.c,v
retrieving revision 1.93
diff -u -p -r1.93 gtkwindow.c
--- gtkwindow.c	2000/12/13 01:34:40	1.93
+++ gtkwindow.c	2000/12/20 17:03:18
@@ -105,6 +105,7 @@ static void gtk_window_hide
 static void gtk_window_map                (GtkWidget         *widget);
 static void gtk_window_unmap              (GtkWidget         *widget);
 static void gtk_window_realize            (GtkWidget         *widget);
+static void gtk_window_unrealize          (GtkWidget         *widget);
 static void gtk_window_size_request       (GtkWidget         *widget,
 					   GtkRequisition    *requisition);
 static void gtk_window_size_allocate      (GtkWidget         *widget,
@@ -171,6 +172,9 @@ static GtkWindowGeometryInfo* gtk_window
 							    gboolean   create);
 static void gtk_window_geometry_destroy  (GtkWindowGeometryInfo *info);

+
+#include "gtkwindow-decorate.c"
+
 static GSList      *toplevel_list = NULL;
 static GtkBinClass *parent_class = NULL;
 static guint        window_signals[LAST_SIGNAL] = { 0 };
@@ -227,6 +231,7 @@ gtk_window_class_init (GtkWindowClass *k
   widget_class->map = gtk_window_map;
   widget_class->unmap = gtk_window_unmap;
   widget_class->realize = gtk_window_realize;
+  widget_class->unrealize = gtk_window_unrealize;
   widget_class->size_request = gtk_window_size_request;
   widget_class->size_allocate = gtk_window_size_allocate;
   widget_class->configure_event = gtk_window_configure_event;
@@ -293,6 +298,10 @@ gtk_window_init (GtkWindow *window)
   gtk_object_sink (GTK_OBJECT (window));
   window->has_user_ref_count = TRUE;
   toplevel_list = g_slist_prepend (toplevel_list, window);
+
+#ifdef DECORATE_WINDOWS
+  window->priv = gtk_decorated_window_init_private ();
+#endif
 }

 static void
@@ -426,7 +435,13 @@ gtk_window_set_title (GtkWindow   *windo
   window->title = g_strdup (title);

   if (GTK_WIDGET_REALIZED (window))
-    gdk_window_set_title (GTK_WIDGET (window)->window, window->title);
+    {
+      gdk_window_set_title (GTK_WIDGET (window)->window, window->title);
+#ifdef DECORATE_WINDOWS
+      if (window->priv->title_layout)
+	pango_layout_set_text (window->priv->title_layout, title, -1);
+#endif
+    }
 }

 void
@@ -984,6 +999,14 @@ gtk_window_finalize (GObject *object)
   g_free (window->wmclass_name);
   g_free (window->wmclass_class);

+#ifdef DECORATE_WINDOWS
+  if (window->priv)
+    {
+      gtk_decorated_window_free_private (window->priv);
+      window->priv = NULL;
+    }
+#endif
+
   G_OBJECT_CLASS(parent_class)->finalize (object);
 }

@@ -1027,9 +1050,21 @@ gtk_window_show (GtkWidget *widget)
       gtk_widget_size_allocate (widget, &allocation);

       if (GTK_WIDGET_REALIZED (widget))
-	gdk_window_resize (widget->window, width, height);
+	{
+#ifdef DECORATE_WINDOWS
+	  gtk_decorated_window_calculate_decorations (window);
+#endif
+	  gdk_window_resize (widget->window, width, height);
+	}
       else
-	gtk_widget_realize (widget);
+	{
+
+	  gtk_widget_realize (widget);
+#ifdef DECORATE_WINDOWS
+	  gtk_decorated_window_calculate_decorations (window);
+	  gtk_decorated_window_resize (window, width, height);
+#endif
+	}
     }

   gtk_container_check_resize (container);
@@ -1075,6 +1110,10 @@ gtk_window_map (GtkWidget *widget)
     gtk_widget_map (window->bin.child);

   gdk_window_show (widget->window);
+#ifdef DECORATE_WINDOWS
+  if (window->priv->outer_window)
+    gdk_window_show (window->priv->outer_window);
+#endif
 }

 static void
@@ -1092,6 +1131,11 @@ gtk_window_unmap (GtkWidget *widget)
   window->use_uposition = TRUE;
   window->resize_count = 0;
   window->handling_resize = FALSE;
+
+#ifdef DECORATE_WINDOWS
+  if (window->priv->outer_window)
+    gdk_window_withdraw (window->priv->outer_window);
+#endif
 }

 static void
@@ -1146,11 +1190,90 @@ gtk_window_realize (GtkWidget *widget)
   attributes.title = window->title;
   attributes.wmclass_name = window->wmclass_name;
   attributes.wmclass_class = window->wmclass_class;
-  attributes.width = widget->allocation.width;
-  attributes.height = widget->allocation.height;
   attributes.wclass = GDK_INPUT_OUTPUT;
   attributes.visual = gtk_widget_get_visual (widget);
   attributes.colormap = gtk_widget_get_colormap (widget);
+
+#ifdef DECORATE_WINDOWS
+  {
+    GtkWindowPrivate *priv = window->priv;
+    priv->title_layout = gtk_widget_create_pango_layout (widget, (window->title)?window->title:"");
+
+    pango_layout_set_font_description (priv->title_layout,
+				       pango_font_description_from_string(DECORATION_TITLE_FONT));
+
+    attributes.width = widget->allocation.width + DECORATION_BORDER_TOT_X;
+    attributes.height = widget->allocation.height + DECORATION_BORDER_TOT_Y;
+    attributes.event_mask = (GDK_EXPOSURE_MASK |
+			     GDK_ENTER_NOTIFY_MASK |
+			     GDK_LEAVE_NOTIFY_MASK |
+			     GDK_STRUCTURE_MASK |
+			     GDK_BUTTON_MOTION_MASK |
+			     GDK_POINTER_MOTION_HINT_MASK |
+			     GDK_BUTTON_PRESS_MASK |
+			     GDK_BUTTON_RELEASE_MASK);
+
+    attributes_mask = GDK_WA_VISUAL | GDK_WA_COLORMAP;
+    attributes_mask |= (window->title ? GDK_WA_TITLE : 0);
+    attributes_mask |= (window->wmclass_name ? GDK_WA_WMCLASS : 0);
+
+    priv->outer_window = gdk_window_new (NULL, &attributes, attributes_mask);
+
+    priv->dummy_widget = gtk_invisible_new ();
+
+    gdk_window_set_user_data (priv->outer_window, priv->dummy_widget);
+
+    gtk_signal_connect (GTK_OBJECT (priv->dummy_widget),
+			"button_press_event",
+			GTK_SIGNAL_FUNC (gtk_decorated_window_button_press),
+			widget);
+    gtk_signal_connect (GTK_OBJECT (priv->dummy_widget),
+			"button_release_event",
+			GTK_SIGNAL_FUNC (gtk_decorated_window_button_release),
+			widget);
+    gtk_signal_connect (GTK_OBJECT (priv->dummy_widget),
+			"motion_notify_event",
+			GTK_SIGNAL_FUNC (gtk_decorated_window_motion_notify),
+			widget);
+    gtk_signal_connect (GTK_OBJECT (priv->dummy_widget),
+			"expose_event",
+			GTK_SIGNAL_FUNC (gtk_decorated_window_expose),
+			widget);
+    gtk_signal_connect (GTK_OBJECT (priv->dummy_widget),
+			"configure_event",
+			GTK_SIGNAL_FUNC (gtk_decorated_window_configure),
+			widget);
+
+    attributes.window_type = GDK_WINDOW_CHILD;
+    attributes.x = DECORATION_BORDER_LEFT;
+    attributes.y = DECORATION_BORDER_TOP;
+    attributes.width = widget->allocation.width;
+    attributes.height = widget->allocation.height;
+    attributes.event_mask = gtk_widget_get_events (widget);
+    attributes.event_mask |= (GDK_EXPOSURE_MASK |
+			      GDK_KEY_PRESS_MASK |
+			      GDK_ENTER_NOTIFY_MASK |
+			      GDK_LEAVE_NOTIFY_MASK |
+			      GDK_FOCUS_CHANGE_MASK |
+			      GDK_STRUCTURE_MASK);
+
+    attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
+
+    widget->window = gdk_window_new (priv->outer_window, &attributes, attributes_mask);
+    gdk_window_set_user_data (widget->window, window);
+
+    _gdk_window_set_child_handler (priv->outer_window,
+				   gtk_decorated_window_inner_change,
+				   gtk_decorated_window_inner_get_pos,
+				   window);
+
+    widget->style = gtk_style_attach (widget->style, widget->window);
+    gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
+    gtk_style_set_background (widget->style, priv->outer_window, GTK_STATE_NORMAL);
+  }
+#else
+  attributes.width = widget->allocation.width;
+  attributes.height = widget->allocation.height;
   attributes.event_mask = gtk_widget_get_events (widget);
   attributes.event_mask |= (GDK_EXPOSURE_MASK |
 			    GDK_KEY_PRESS_MASK |
@@ -1158,22 +1281,58 @@ gtk_window_realize (GtkWidget *widget)
 			    GDK_LEAVE_NOTIFY_MASK |
 			    GDK_FOCUS_CHANGE_MASK |
 			    GDK_STRUCTURE_MASK);
-
+
   attributes_mask = GDK_WA_VISUAL | GDK_WA_COLORMAP;
   attributes_mask |= (window->title ? GDK_WA_TITLE : 0);
   attributes_mask |= (window->wmclass_name ? GDK_WA_WMCLASS : 0);
-
+
   widget->window = gdk_window_new (NULL, &attributes, attributes_mask);
   gdk_window_set_user_data (widget->window, window);
-
+
   widget->style = gtk_style_attach (widget->style, widget->window);
   gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
-  gtk_window_paint (widget, NULL);
+#endif

+  gtk_window_paint (widget, NULL);
+#ifdef DECORATE_WINDOWS
+  gtk_decorated_window_paint (widget, NULL);
+#endif
+
   if (window->transient_parent &&
       GTK_WIDGET_REALIZED (window->transient_parent))
     gdk_window_set_transient_for (widget->window,
 				  GTK_WIDGET (window->transient_parent)->window);
+
+}
+
+
+static void
+gtk_window_unrealize (GtkWidget *widget)
+{
+#ifdef DECORATE_WINDOWS
+  GtkWindow *window;
+  GtkWindowPrivate *priv;
+
+  g_return_if_fail (GTK_IS_WINDOW (widget));
+
+  window = GTK_WINDOW (widget);
+  priv = window->priv;
+
+  gdk_window_set_user_data (priv->outer_window, NULL);
+  gdk_window_destroy (priv->outer_window);
+  priv->outer_window = NULL;
+
+  gtk_widget_destroy (priv->dummy_widget);
+  priv->dummy_widget = NULL;
+
+  if (priv->title_layout)
+    {
+      g_object_unref (G_OBJECT (priv->title_layout));
+      priv->title_layout = NULL;
+    }
+#endif
+
+  (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
 }

 static void
@@ -1229,6 +1388,14 @@ gtk_window_size_allocate (GtkWidget

       gtk_widget_size_allocate (window->bin.child, &child_allocation);
     }
+
+#ifdef DECORATE_WINDOWS
+  if (GTK_WIDGET_REALIZED (widget))
+    gtk_decorated_window_resize (window, allocation->width, allocation->height);
+
+  if (window->priv->decorated)
+    gtk_decorated_window_recalculate_regions (window);
+#endif
 }

 static gint
Index: gtkwindow.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkwindow.h,v
retrieving revision 1.24
diff -u -p -r1.24 gtkwindow.h
--- gtkwindow.h	2000/10/20 23:14:40	1.24
+++ gtkwindow.h	2000/12/20 17:03:18
@@ -47,8 +47,9 @@ extern "C" {
 #define GTK_WINDOW_GET_CLASS(obj)       (GTK_CHECK_GET_CLASS ((obj), GTK_TYPE_WINDOW, GtkWindowClass))


-typedef struct _GtkWindow       GtkWindow;
-typedef struct _GtkWindowClass  GtkWindowClass;
+typedef struct _GtkWindow        GtkWindow;
+typedef struct _GtkWindowPrivate GtkWindowPrivate;
+typedef struct _GtkWindowClass   GtkWindowClass;

 struct _GtkWindow
 {
@@ -80,6 +81,8 @@ struct _GtkWindow
   guint use_uposition : 1;
   guint modal : 1;
   guint destroy_with_parent : 1;
+
+  GtkWindowPrivate *priv;
 };

 struct _GtkWindowClass


-------------------------------------------------------
gtkwindow-decorate.c:
*********************

#ifdef GDK_WINDOWING_FB
#define DECORATE_WINDOWS
#endif

#ifdef DECORATE_WINDOWS
#include "gtkinvisible.h"
#endif

typedef enum
{
  GTK_WINDOW_REGION_TITLE,
  GTK_WINDOW_REGION_CLOSE,
  GTK_WINDOW_REGION_BR_RESIZE
} GtkWindowRegionType;

typedef struct _GtkWindowRegion GtkWindowRegion;

struct _GtkWindowRegion
{
  GdkRectangle rect;
  GtkWindowRegionType type;
};

typedef enum
{
  RESIZE_TOP_LEFT,
  RESIZE_TOP,
  RESIZE_TOP_RIGHT,
  RESIZE_RIGHT,
  RESIZE_BOTTOM_RIGHT,
  RESIZE_BOTTOM,
  RESIZE_BOTTOM_LEFT,
  RESIZE_LEFT,
  RESIZE_NONE,
} GtkWindowResizeType;

struct _GtkWindowPrivate
{
  GdkWindow *outer_window;

  GtkWidget *dummy_widget;

  gint n_regions;
  GtkWindowRegion *regions;

  gint last_x, last_y;
  PangoLayout *title_layout;

  GtkWindowResizeType resize;

  gboolean decorated : 1;

  gboolean moving : 1;
  gboolean closing : 1;
  gboolean real_inner_move : 1;
};

#define DECORATION_BORDER_TOP 13
#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 8
#define DECORATION_BUTTON_Y_OFFSET 2
#define DECORATION_TITLE_FONT "Sans 7"

#ifdef DECORATE_WINDOWS
static void gtk_decorated_window_calculate_decorations (GtkWindow      *window);
static void gtk_decorated_window_resize                (GtkWindow      *window,
						 gint            width,
						 gint            height);
static void gtk_decorated_window_move_resize           (GtkWindow      *window,
						 gint            x,
						 gint            y,
						 gint            width,
						 gint            height);
static void gtk_decorated_window_recalculate_regions      (GtkWindow      *window);
static GtkWindowRegionType gtk_decorated_window_region_type    (GtkWindow      *window,
						 gint            x,
						 gint            y);
static gint gtk_decorated_window_button_press             (GtkWidget      *dummy_widget,
						 GdkEventButton *event,
						 GtkWidget      *widget);
static gint gtk_decorated_window_button_release           (GtkWidget      *dummy_widget,
						 GdkEventButton *event,
						 GtkWidget      *widget);
static gint gtk_decorated_window_motion_notify            (GtkWidget      *dummy_widget,
						 GdkEventMotion *event,
						 GtkWidget      *widget);
static gint gtk_decorated_window_expose        (GtkWidget      *dummy_widget,
						 GdkEventExpose *event,
						 GtkWidget      *widget);
static gint gtk_decorated_window_configure     (GtkWidget      *dummy_widget,
						 GdkEventConfigure *event,
						 GtkWidget      *widget);
static void gtk_decorated_window_paint             (GtkWidget      *widget,
						 GdkRectangle   *area);

static GtkWindowPrivate *
gtk_decorated_window_init_private (void)
{
  GtkWindowPrivate *priv;
  priv = g_new (GtkWindowPrivate, 1);

  priv->outer_window = NULL;
  priv->dummy_widget = NULL;
  priv->n_regions = 0;
  priv->regions = NULL;
  priv->title_layout = NULL;
  priv->resize = RESIZE_NONE;
  priv->decorated = TRUE;
  priv->moving = FALSE;
  priv->closing = FALSE;
  priv->real_inner_move = FALSE;
  return priv;
}

static void
gtk_decorated_window_free_private (GtkWindowPrivate *priv)
{
  g_free (priv->regions);
  priv->regions = NULL;
  priv->n_regions = 0;

  g_free (priv);
}

static gboolean
gtk_decorated_window_inner_change (GdkWindow *win,
				 gint x, gint y,
				 gint width, gint height,
				 gpointer user_data)
{
  GtkWindow *window = (GtkWindow *)user_data;

  if (window->priv->real_inner_move)
    {
      window->priv->real_inner_move = FALSE;
      return FALSE;
    }

  gtk_decorated_window_move_resize (window, x, y, width, height);
  return TRUE;
}

static void
gtk_decorated_window_inner_get_pos (GdkWindow *win,
				    gint *x, gint *y,
				    gpointer user_data)
{
  GtkWindow *window = (GtkWindow *)user_data;

  gdk_window_get_position (window->priv->outer_window, x, y);
  if (window->priv->decorated)
    {
      *x += DECORATION_BORDER_LEFT;
      *y += DECORATION_BORDER_TOP;
    }
}


static gint
gtk_decorated_window_configure (GtkWidget         *dummy_widget,
				GdkEventConfigure *event,
				GtkWidget         *widget)
{
  GtkWindow *window;

  window = GTK_WINDOW (widget);

  if (window->priv->decorated)
    {
      GdkRectangle rect;

      /* Invalidate the decorations: */
      rect.x = 0;
      rect.y = 0;
      rect.width = event->width;
      rect.height = event->height;

      gdk_window_invalidate_rect (window->priv->outer_window, &rect, FALSE);

      event->width -= DECORATION_BORDER_TOT_X;
      event->height -= DECORATION_BORDER_TOT_Y;
    }

  gtk_window_configure_event (widget, event);

  return TRUE;
}


static gint
gtk_decorated_window_expose (GtkWidget      *dummy_widget,
			     GdkEventExpose *event,
			     GtkWidget      *widget)
{
  g_return_val_if_fail (widget != NULL, FALSE);
  g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE);
  g_return_val_if_fail (event != NULL, FALSE);

  if (GTK_WINDOW (widget)->priv->decorated)
    gtk_decorated_window_paint (widget, &event->area);

  return TRUE;
}


static void
gtk_decorated_window_calculate_decorations (GtkWindow *window)

{
  GdkWMDecoration decorations;

  if (_gdk_window_get_decorations (GTK_WIDGET (window)->window,
				      &decorations))
    {
      if ((decorations & GDK_DECOR_BORDER) &&
	  (decorations & GDK_DECOR_TITLE))
	window->priv->decorated = TRUE;
      else
	window->priv->decorated = FALSE;
    }
  else
    window->priv->decorated = (window->type != GTK_WINDOW_POPUP);
}


static void
gtk_decorated_window_resize (GtkWindow *window,
			     gint width, gint height)
{
  GtkWidget *widget = GTK_WIDGET (window);
  gint border_x = 0, border_y = 0;
  gint offset_x = 0, offset_y = 0;

  if (window->priv->decorated)
    {
      border_x = DECORATION_BORDER_TOT_X;
      border_y = DECORATION_BORDER_TOT_Y;
      offset_x = DECORATION_BORDER_LEFT;
      offset_y = DECORATION_BORDER_TOP;
    }

  window->priv->real_inner_move = TRUE;
  gdk_window_move_resize (widget->window,
			  offset_x, offset_y,
			  width, height);
  gdk_window_resize (window->priv->outer_window,
		     width + border_x, height + border_y);
}

static void
gtk_decorated_window_move_resize (GtkWindow *window,
				  gint x, gint y,
				  gint width, gint height)
{
  GtkWidget *widget = GTK_WIDGET (window);
  gint border_x = 0, border_y = 0;
  gint offset_x = 0, offset_y = 0;

  if (window->priv->decorated)
    {
      border_x = DECORATION_BORDER_TOT_X;
      border_y = DECORATION_BORDER_TOT_Y;
      offset_x = DECORATION_BORDER_LEFT;
      offset_y = DECORATION_BORDER_TOP;
    }

  window->priv->real_inner_move = TRUE;
  gdk_window_move_resize (widget->window,
			  offset_x, offset_y,
			  width, height);
  gdk_window_move_resize (window->priv->outer_window,
			  x - offset_x, y - offset_y,
			  width + border_x, height + border_y);
}

static gint
gtk_decorated_window_motion_notify (GtkWidget       *dummy_widget,
				    GdkEventMotion  *event,
				    GtkWidget       *widget)
{
  GtkWindow *window;
  GtkWindowPrivate *priv;
  GdkModifierType mask;
  GdkWindow *win;
  gint x, y;
  gint win_x, win_y, win_w, win_h;

  window = GTK_WINDOW (widget);
  priv = window->priv;

  if (!priv->decorated)
    return TRUE;

  win = widget->window;
  gdk_window_get_pointer (priv->outer_window, &x, &y, &mask);

  gdk_window_get_position (priv->outer_window, &win_x, &win_y);
  win_x += DECORATION_BORDER_LEFT;
  win_y += DECORATION_BORDER_TOP;

  gdk_window_get_geometry (win, NULL, NULL, &win_w, &win_h, NULL);

  if (priv->moving)
    {
      int dx, dy;
      dx = x - priv->last_x;
      dy = y - priv->last_y;

      gtk_window_reposition (window, win_x + dx, win_y + dy);
    }

  if (priv->resize != RESIZE_NONE)
    {
      int w, h;

      w = win_w;
      h = win_h;

      switch(priv->resize) {
      case RESIZE_BOTTOM_RIGHT:
	w = x - DECORATION_BORDER_TOT_X;
	h = y - DECORATION_BORDER_TOT_Y;
	break;
      case RESIZE_RIGHT:
	w = x - DECORATION_BORDER_TOT_X;
	break;
      case RESIZE_BOTTOM:
	h = y - DECORATION_BORDER_TOT_Y;
	break;
      case RESIZE_TOP_LEFT:
      case RESIZE_TOP:
      case RESIZE_TOP_RIGHT:
      case RESIZE_BOTTOM_LEFT:
      case RESIZE_LEFT:
      default:
	g_warning ("Resize mode %d not handled yet.\n", priv->resize);
	break;
      }

      if ((w > 0) && (h > 0))
	{
	  GtkWindowGeometryInfo *info = gtk_window_get_geometry_info (window, FALSE);

	  if (info)
	    {
	      GdkWindowHints mask = info->last.flags;
	      GdkGeometry *g = &info->last.geometry;

	      if (mask & GDK_HINT_MIN_SIZE)
		{
		  w = MAX (w, g->min_width);
		  h = MAX (h, g->min_height);
		}

	      if (mask & GDK_HINT_MAX_SIZE)
		{
		  w = MIN (w, g->max_width);
		  h = MIN (h, g->max_height);
		}
	    }

	  if ((w != win_w) || (h != win_h))
	    {
	      gdk_window_resize (priv->outer_window,
				 w + DECORATION_BORDER_TOT_X,
				 h + DECORATION_BORDER_TOT_Y);
	    }
	}
    }

  return TRUE;

}

static GtkWindowRegionType
gtk_decorated_window_region_type (GtkWindow *window, gint x, gint y)
{
  GtkWindowPrivate *priv;
  int i;

  priv = window->priv;
  for (i=0;i<priv->n_regions;i++)
    {
      if ((x > priv->regions[i].rect.x) &&
	  (x - priv->regions[i].rect.x < priv->regions[i].rect.width) &&
	  (y > priv->regions[i].rect.y) &&
	  (y - priv->regions[i].rect.y < priv->regions[i].rect.height))
	return priv->regions[i].type;
    }
  return -1;
}

static gint
gtk_decorated_window_button_press (GtkWidget       *dummy_widget,
				   GdkEventButton  *event,
				   GtkWidget       *widget)
{
  GtkWindow *window;
  GtkWindowRegionType type;
  GtkWindowPrivate *priv;
  gint x, y;

  window = GTK_WINDOW (widget);
  priv = window->priv;

  if (!priv->decorated)
    return TRUE;

  if (event->window != priv->outer_window)
    return TRUE;

  x = event->x;
  y = event->y;

  type = gtk_decorated_window_region_type (window, x, y);

  priv->last_x = x;
  priv->last_y = y;

  switch (type)
    {
    case GTK_WINDOW_REGION_TITLE:
      if (event->state & GDK_BUTTON1_MASK)
	priv->moving = TRUE;
      break;
    case GTK_WINDOW_REGION_CLOSE:
      if (event->state & GDK_BUTTON1_MASK)
	priv->closing = TRUE;
      break;
    case GTK_WINDOW_REGION_BR_RESIZE:
      if (event->state & GDK_BUTTON1_MASK)
	priv->resize = RESIZE_BOTTOM_RIGHT;
      break;
    default:
      break;
    }

  return TRUE;
}

static gint
gtk_decorated_window_button_release (GtkWidget	  *dummy_widget,
				     GdkEventButton *event,
				     GtkWidget      *widget)
{
  GtkWindow *window;
  GtkWindowRegionType type;
  GtkWindowPrivate *priv;

  window = GTK_WINDOW (widget);
  priv = window->priv;

  if (priv->closing)
    {
      type = gtk_decorated_window_region_type (window, event->x, event->y);
      if (type == GTK_WINDOW_REGION_CLOSE)
	{
	  GdkEventAny event;

	  event.type = GDK_DELETE;
	  event.window = widget->window;
	  event.send_event = TRUE;

	    /* Synthesize delete_event on key press. */
	  g_object_ref (G_OBJECT (event.window));

	  gtk_main_do_event ((GdkEvent*)&event);

	  g_object_unref (G_OBJECT (event.window));
	}
    }

  priv->closing = FALSE;
  priv->moving = FALSE;
  priv->resize = RESIZE_NONE;
  return TRUE;
}

static void
gtk_decorated_window_paint (GtkWidget    *widget,
			    GdkRectangle *area)
{
  GtkWindow *window = GTK_WINDOW (widget);
  GtkWindowPrivate *priv = window->priv;

  if (priv->decorated)
    {
      GdkWindow *outer_window;
      gint width, height;


      outer_window = priv->outer_window;
      gdk_window_get_size (outer_window, &width, &height);

      /* Top */
      gtk_paint_flat_box (widget->style, outer_window, GTK_STATE_NORMAL,
			  GTK_SHADOW_NONE, area, widget, "base",
			  0, 0,
			  width, DECORATION_BORDER_TOP);
      /* Bottom */
      gtk_paint_flat_box (widget->style, outer_window, GTK_STATE_NORMAL,
			  GTK_SHADOW_NONE, area, widget, "base",
			  0, height - DECORATION_BORDER_BOTTOM,
			  width, DECORATION_BORDER_BOTTOM);
      /* Left */
      gtk_paint_flat_box (widget->style, outer_window, GTK_STATE_NORMAL,
			  GTK_SHADOW_NONE, area, widget, "base",
			  0, DECORATION_BORDER_TOP,
			  DECORATION_BORDER_LEFT, height - DECORATION_BORDER_TOT_Y);
      /* Right */
      gtk_paint_flat_box (widget->style, outer_window, GTK_STATE_NORMAL,
			  GTK_SHADOW_NONE, area, widget, "base",
			  width - DECORATION_BORDER_RIGHT, DECORATION_BORDER_TOP,
			  DECORATION_BORDER_RIGHT, height - DECORATION_BORDER_TOT_Y);

      /* Border: */
      gtk_paint_box (widget->style, outer_window, GTK_STATE_NORMAL,
		     GTK_SHADOW_OUT, area, widget, "base",
		     0, 0, width, height);

      gtk_paint_box (widget->style, outer_window, GTK_STATE_NORMAL,
		     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);

      /* Close button: */

      gtk_paint_box (widget->style, outer_window, GTK_STATE_NORMAL,
		     GTK_SHADOW_OUT, area, widget, "base",
		     width - DECORATION_BORDER_LEFT - DECORATION_BUTTON_SIZE,
		     DECORATION_BUTTON_Y_OFFSET,
		     DECORATION_BUTTON_SIZE, DECORATION_BUTTON_SIZE);

      /* Title */
      if (priv->title_layout)
	{
	  if (area)
	    gdk_gc_set_clip_rectangle (widget->style->fg_gc [widget->state], area);
	  gdk_draw_layout (outer_window,
			   widget->style->fg_gc [widget->state],
			   DECORATION_BORDER_LEFT, 1,
			   priv->title_layout);
	  if (area)
	    gdk_gc_set_clip_rectangle (widget->style->fg_gc [widget->state], NULL);
	}
    }
}


static void
gtk_decorated_window_recalculate_regions (GtkWindow *window)
{
  gint n_regions;
  gint width, height;
  GtkWindowRegion *region;
  GtkWindowPrivate *priv;

  priv = window->priv;

  n_regions = 0;

  n_regions += 2; /* close, Title */
  if (window->allow_shrink || window->allow_grow)
    n_regions += 2;

  if (priv->n_regions != n_regions)
    {
      g_free (priv->regions);
      priv->regions = g_new (GtkWindowRegion, n_regions);
      priv->n_regions = n_regions;
    }

  width = GTK_WIDGET (window)->allocation.width + DECORATION_BORDER_TOT_X;
  height = GTK_WIDGET (window)->allocation.height + DECORATION_BORDER_TOT_Y;

  region = priv->regions;

  /* Close button */
  region->rect.x = width - DECORATION_BORDER_LEFT - DECORATION_BUTTON_SIZE;
  region->rect.y = 2;
  region->rect.width = DECORATION_BUTTON_SIZE;
  region->rect.height = DECORATION_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->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->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->type = GTK_WINDOW_REGION_BR_RESIZE;
      region++;
    }
}
#endif





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