1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 2001 Red Hat, Inc.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19 
20 /*
21  * Authors: Alexander Larsson <alexl@redhat.com>
22  */
23 
24 #include "config.h"
25 #include "gtkprivate.h"
26 #include "gtkwindow.h"
27 #include "gtkmain.h"
28 #include "gtkwindow-decorate.h"
29 #include "gtkintl.h"
30 #include "gtkalias.h"
31 
32 
33 #ifdef DECORATE_WINDOWS
34 
35 typedef enum
36 {
37   GTK_WINDOW_REGION_TITLE,
38   GTK_WINDOW_REGION_MAXIMIZE,
39   GTK_WINDOW_REGION_CLOSE,
40   GTK_WINDOW_REGION_BR_RESIZE
41 } GtkWindowRegionType;
42 
43 typedef struct _GtkWindowRegion GtkWindowRegion;
44 typedef struct _GtkWindowDecoration GtkWindowDecoration;
45 
46 struct _GtkWindowRegion
47 {
48   GdkRectangle rect;
49   GtkWindowRegionType type;
50 };
51 
52 typedef enum
53 {
54   RESIZE_TOP_LEFT,
55   RESIZE_TOP,
56   RESIZE_TOP_RIGHT,
57   RESIZE_RIGHT,
58   RESIZE_BOTTOM_RIGHT,
59   RESIZE_BOTTOM,
60   RESIZE_BOTTOM_LEFT,
61   RESIZE_LEFT,
62   RESIZE_NONE,
63 } GtkWindowResizeType;
64 
65 struct _GtkWindowDecoration
66 {
67   gint n_regions;
68   GtkWindowRegion *regions;
69 
70   gint last_x, last_y;
71   gint last_w, last_h;
72 
73   PangoLayout *title_layout;
74 
75   GtkWindowResizeType resize;
76 
77   guint moving : 1;
78   guint closing : 1;
79   guint maximizing : 1;
80   guint maximized : 1;
81   guint maximizable : 1;
82   guint decorated : 1;
83   guint real_inner_move : 1;
84   guint focused : 1;
85 };
86 
87 #define DECORATION_BORDER_TOP 15
88 #define DECORATION_BORDER_LEFT 3
89 #define DECORATION_BORDER_RIGHT 3
90 #define DECORATION_BORDER_BOTTOM 3
91 #define DECORATION_BORDER_TOT_X (DECORATION_BORDER_LEFT + DECORATION_BORDER_RIGHT)
92 #define DECORATION_BORDER_TOT_Y (DECORATION_BORDER_TOP + DECORATION_BORDER_BOTTOM)
93 #define DECORATION_BUTTON_SIZE 9
94 #define DECORATION_BUTTON_Y_OFFSET 2
95 #define DECORATION_TITLE_FONT "Sans 9"
96 
97 static void gtk_decorated_window_recalculate_regions      (GtkWindow      *window);
98 static GtkWindowRegionType gtk_decorated_window_region_type    (GtkWindow      *window,
99 						 gint            x,
100 						 gint            y);
101 static gint gtk_decorated_window_frame_event    (GtkWindow *window,
102 						 GdkEvent *event);
103 static gint gtk_decorated_window_button_press   (GtkWidget      *widget,
104 						 GdkEventButton *event);
105 static gint gtk_decorated_window_button_release (GtkWidget      *widget,
106 						 GdkEventButton *event);
107 static gint gtk_decorated_window_motion_notify  (GtkWidget      *widget,
108 						 GdkEventMotion *event);
109 static gint gtk_decorated_window_window_state   (GtkWidget           *widget,
110 						 GdkEventWindowState *event);
111 static void gtk_decorated_window_paint          (GtkWidget      *widget,
112 						 GdkRectangle   *area);
113 static gint gtk_decorated_window_focus_change   (GtkWidget         *widget,
114 						 GdkEventFocus     *event);
115 static void gtk_decorated_window_realize        (GtkWindow   *window);
116 static void gtk_decorated_window_unrealize      (GtkWindow   *window);
117 
118 static void
gtk_decoration_free(GtkWindowDecoration * deco)119 gtk_decoration_free (GtkWindowDecoration *deco)
120 {
121   g_free (deco->regions);
122   deco->regions = NULL;
123   deco->n_regions = 0;
124 
125   g_free (deco);
126 }
127 
128 void
gtk_decorated_window_init(GtkWindow * window)129 gtk_decorated_window_init (GtkWindow   *window)
130 {
131   GtkWindowDecoration *deco;
132 
133   deco = g_new (GtkWindowDecoration, 1);
134 
135   deco->n_regions = 0;
136   deco->regions = NULL;
137   deco->title_layout = NULL;
138   deco->resize = RESIZE_NONE;
139   deco->moving = FALSE;
140   deco->decorated = TRUE;
141   deco->closing = FALSE;
142   deco->maximizing = FALSE;
143   deco->maximized = FALSE;
144   deco->maximizable = FALSE;
145   deco->real_inner_move = FALSE;
146 
147   g_object_set_data_full (G_OBJECT (window), I_("gtk-window-decoration"), deco,
148 			  (GDestroyNotify) gtk_decoration_free);
149 
150   gtk_window_set_has_frame (window, TRUE);
151 
152   g_signal_connect (window,
153 		    "frame-event",
154 		    G_CALLBACK (gtk_decorated_window_frame_event),
155 		    window);
156   g_signal_connect (window,
157 		    "focus-in-event",
158 		    G_CALLBACK (gtk_decorated_window_focus_change),
159 		    window);
160   g_signal_connect (window,
161 		    "focus-out-event",
162 		    G_CALLBACK (gtk_decorated_window_focus_change),
163 		    window);
164   g_signal_connect (window,
165 		    "realize",
166 		    G_CALLBACK (gtk_decorated_window_realize),
167 		    window);
168   g_signal_connect (window,
169 		    "unrealize",
170 		    G_CALLBACK (gtk_decorated_window_unrealize),
171 		    window);
172 }
173 
174 static inline GtkWindowDecoration *
get_decoration(GtkWindow * window)175 get_decoration (GtkWindow *window)
176 {
177   return (GtkWindowDecoration *)g_object_get_data (G_OBJECT (window), "gtk-window-decoration");
178 }
179 
180 void
gtk_decorated_window_set_title(GtkWindow * window,const gchar * title)181 gtk_decorated_window_set_title (GtkWindow   *window,
182 				const gchar *title)
183 {
184   GtkWindowDecoration *deco = get_decoration (window);
185 
186   if (deco->title_layout)
187     pango_layout_set_text (deco->title_layout, title, -1);
188 }
189 
190 void
gtk_decorated_window_calculate_frame_size(GtkWindow * window)191 gtk_decorated_window_calculate_frame_size (GtkWindow *window)
192 {
193   GdkWMDecoration decorations;
194   GtkWindowDecoration *deco = get_decoration (window);
195 
196   if (gdk_window_get_decorations (GTK_WIDGET (window)->window,
197 				  &decorations))
198     {
199       if ((decorations & GDK_DECOR_BORDER) &&
200 	  (decorations & GDK_DECOR_TITLE))
201 	{
202 	  deco->decorated = TRUE;
203 	  if ((decorations & GDK_DECOR_MAXIMIZE) &&
204 	      (gtk_window_get_type_hint (window) == GDK_WINDOW_TYPE_HINT_NORMAL))
205 	    deco->maximizable = TRUE;
206 	}
207       else
208 	deco->decorated = FALSE;
209     }
210   else
211     {
212       deco->decorated = (window->type != GTK_WINDOW_POPUP);
213       deco->maximizable = (gtk_window_get_type_hint (window) == GDK_WINDOW_TYPE_HINT_NORMAL);
214     }
215 
216   if (deco->decorated)
217     gtk_window_set_frame_dimensions (window,
218 				     DECORATION_BORDER_LEFT,
219 				     DECORATION_BORDER_TOP,
220 				     DECORATION_BORDER_RIGHT,
221 				     DECORATION_BORDER_BOTTOM);
222   else
223     gtk_window_set_frame_dimensions (window, 0, 0, 0, 0);
224 
225   gtk_decorated_window_recalculate_regions (window);
226 }
227 
228 static gboolean
gtk_decorated_window_inner_change(GdkWindow * win,gint x,gint y,gint width,gint height,gpointer user_data)229 gtk_decorated_window_inner_change (GdkWindow *win,
230 				   gint x, gint y,
231 				   gint width, gint height,
232 				   gpointer user_data)
233 {
234   GtkWindow *window = (GtkWindow *)user_data;
235   GtkWidget *widget = GTK_WIDGET (window);
236   GtkWindowDecoration *deco = get_decoration (window);
237 
238   if (deco->real_inner_move)
239     {
240       deco->real_inner_move = FALSE;
241       return FALSE;
242     }
243 
244   deco->real_inner_move = TRUE;
245   gdk_window_move_resize (widget->window,
246 			  window->frame_left, window->frame_top,
247 			  width, height);
248 
249   gdk_window_move_resize (window->frame,
250 			  x - window->frame_left, y - window->frame_top,
251 			  width + window->frame_left + window->frame_right,
252 			  height + window->frame_top + window->frame_bottom);
253   return TRUE;
254 }
255 
256 static void
gtk_decorated_window_inner_get_pos(GdkWindow * win,gint * x,gint * y,gpointer user_data)257 gtk_decorated_window_inner_get_pos (GdkWindow *win,
258 				    gint *x, gint *y,
259 				    gpointer user_data)
260 {
261   GtkWindow *window = (GtkWindow *)user_data;
262 
263   gdk_window_get_position (window->frame, x, y);
264 
265   *x += window->frame_left;
266   *y += window->frame_top;
267 }
268 
269 static void
gtk_decorated_window_realize(GtkWindow * window)270 gtk_decorated_window_realize (GtkWindow   *window)
271 {
272   GtkWindowDecoration *deco = get_decoration (window);
273   GtkWidget *widget = GTK_WIDGET (window);
274   PangoFontDescription *font_desc;
275 
276   deco->title_layout = gtk_widget_create_pango_layout (widget,
277 						       (window->title)?window->title:"");
278 
279   font_desc = pango_font_description_from_string(DECORATION_TITLE_FONT);
280   pango_layout_set_font_description (deco->title_layout, font_desc);
281   pango_font_description_free (font_desc);
282 
283 #if 0
284   /* What is this code exactly doing? I remember we were using the
285      decorated windows with the DirectFB port and it did just work,
286      and there was definitely no code in linux-fb involved. */
287   gdk_fb_window_set_child_handler (window->frame,
288 				   gtk_decorated_window_inner_change,
289 				   gtk_decorated_window_inner_get_pos,
290 				   window);
291 
292   /* This is a huge hack to make frames have the same shape as
293      the window they wrap */
294   gdk_window_shape_combine_mask (window->frame, GDK_FB_USE_CHILD_SHAPE, 0, 0);
295 #endif
296 }
297 
298 
299 static void
gtk_decorated_window_unrealize(GtkWindow * window)300 gtk_decorated_window_unrealize (GtkWindow   *window)
301 {
302   GtkWindowDecoration *deco = get_decoration (window);
303 
304   if (deco->title_layout)
305     {
306       g_object_unref (deco->title_layout);
307       deco->title_layout = NULL;
308     }
309 }
310 
311 static gint
gtk_decorated_window_frame_event(GtkWindow * window,GdkEvent * event)312 gtk_decorated_window_frame_event (GtkWindow *window, GdkEvent *event)
313 {
314   GtkWindowDecoration *deco = get_decoration (window);
315   GtkWidget *widget = GTK_WIDGET (window);
316   GdkEventExpose *expose_event;
317 
318   switch (event->type)
319     {
320     case GDK_EXPOSE:
321       expose_event = (GdkEventExpose *)event;
322       if (deco->decorated)
323 	gtk_decorated_window_paint (widget, &expose_event->area);
324       return TRUE;
325       break;
326     case GDK_CONFIGURE:
327       gtk_decorated_window_recalculate_regions (window);
328       break;
329     case GDK_MOTION_NOTIFY:
330       return gtk_decorated_window_motion_notify (widget, (GdkEventMotion *)event);
331       break;
332     case GDK_BUTTON_PRESS:
333       return gtk_decorated_window_button_press (widget, (GdkEventButton *)event);
334       break;
335     case GDK_BUTTON_RELEASE:
336       return gtk_decorated_window_button_release (widget, (GdkEventButton *)event);
337     case GDK_WINDOW_STATE:
338       return gtk_decorated_window_window_state (widget, (GdkEventWindowState *)event);
339     default:
340       break;
341     }
342   return FALSE;
343 }
344 
345 static gint
gtk_decorated_window_focus_change(GtkWidget * widget,GdkEventFocus * event)346 gtk_decorated_window_focus_change (GtkWidget         *widget,
347 				   GdkEventFocus     *event)
348 {
349   GtkWindow *window = GTK_WINDOW(widget);
350   GtkWindowDecoration *deco = get_decoration (window);
351   deco->focused = event->in;
352   gdk_window_invalidate_rect (window->frame, NULL, FALSE);
353   return FALSE;
354 }
355 
356 static gint
gtk_decorated_window_motion_notify(GtkWidget * widget,GdkEventMotion * event)357 gtk_decorated_window_motion_notify (GtkWidget       *widget,
358 				    GdkEventMotion  *event)
359 {
360   GtkWindow *window;
361   GtkWindowDecoration *deco;
362   GdkModifierType mask;
363   GdkWindow *win;
364   gint x, y;
365   gint win_x, win_y, win_w, win_h;
366 
367   window = GTK_WINDOW (widget);
368   deco = get_decoration (window);
369 
370   if (!deco->decorated)
371     return TRUE;
372 
373   win = widget->window;
374   gdk_window_get_pointer (window->frame, &x, &y, &mask);
375 
376   gdk_window_get_position (window->frame, &win_x, &win_y);
377   win_x += DECORATION_BORDER_LEFT;
378   win_y += DECORATION_BORDER_TOP;
379 
380   gdk_window_get_geometry (win, NULL, NULL, &win_w, &win_h, NULL);
381 
382   if (deco->moving)
383     {
384       int dx, dy;
385       dx = x - deco->last_x;
386       dy = y - deco->last_y;
387 
388       _gtk_window_reposition (window, win_x + dx, win_y + dy);
389     }
390 
391   if (deco->resize != RESIZE_NONE)
392     {
393       int w, h;
394 
395       w = win_w;
396       h = win_h;
397 
398       switch(deco->resize) {
399       case RESIZE_BOTTOM_RIGHT:
400 	w = x - DECORATION_BORDER_TOT_X;
401 	h = y - DECORATION_BORDER_TOT_Y;
402 	break;
403       case RESIZE_RIGHT:
404 	w = x - DECORATION_BORDER_TOT_X;
405 	break;
406       case RESIZE_BOTTOM:
407 	h = y - DECORATION_BORDER_TOT_Y;
408 	break;
409       case RESIZE_TOP_LEFT:
410       case RESIZE_TOP:
411       case RESIZE_TOP_RIGHT:
412       case RESIZE_BOTTOM_LEFT:
413       case RESIZE_LEFT:
414       default:
415 	g_warning ("Resize mode %d not handled yet.\n", deco->resize);
416 	break;
417       }
418 
419       if ((w > 0) && (h > 0))
420 	{
421 	  _gtk_window_constrain_size (window, w,h, &w, &h);
422 
423 	  if ((w != win_w) || (h != win_h))
424 	    gdk_window_resize (widget->window, w, h);
425 	}
426     }
427 
428   return TRUE;
429 }
430 
431 static GtkWindowRegionType
gtk_decorated_window_region_type(GtkWindow * window,gint x,gint y)432 gtk_decorated_window_region_type (GtkWindow *window, gint x, gint y)
433 {
434   GtkWindowDecoration *deco = get_decoration (window);
435   int i;
436 
437   for (i=0;i<deco->n_regions;i++)
438     {
439       if ((x > deco->regions[i].rect.x) &&
440 	  (x - deco->regions[i].rect.x < deco->regions[i].rect.width) &&
441 	  (y > deco->regions[i].rect.y) &&
442 	  (y - deco->regions[i].rect.y < deco->regions[i].rect.height))
443 	return deco->regions[i].type;
444     }
445   return -1;
446 }
447 
448 static gint
gtk_decorated_window_button_press(GtkWidget * widget,GdkEventButton * event)449 gtk_decorated_window_button_press (GtkWidget       *widget,
450 				   GdkEventButton  *event)
451 {
452   GtkWindow *window;
453   GtkWindowRegionType type;
454   GtkWindowDecoration *deco;
455   gint x, y;
456 
457   window = GTK_WINDOW (widget);
458   deco = get_decoration (window);
459 
460   if (!deco->decorated)
461     return TRUE;
462 
463   x = event->x;
464   y = event->y;
465 
466   type = gtk_decorated_window_region_type (window, x, y);
467 
468   switch (type)
469     {
470     case GTK_WINDOW_REGION_TITLE:
471       if (!deco->maximized && event->state & GDK_BUTTON1_MASK)
472 	{
473 	  deco->last_x = x;
474 	  deco->last_y = y;
475 	  deco->moving = TRUE;
476 	}
477       break;
478     case GTK_WINDOW_REGION_MAXIMIZE:
479       if (event->state & GDK_BUTTON1_MASK)
480 	deco->maximizing = TRUE;
481       break;
482     case GTK_WINDOW_REGION_CLOSE:
483       if (event->state & GDK_BUTTON1_MASK)
484 	deco->closing = TRUE;
485       break;
486     case GTK_WINDOW_REGION_BR_RESIZE:
487       if (!deco->maximized)
488 	{
489 	  if (event->state & GDK_BUTTON1_MASK)
490 	    deco->resize = RESIZE_BOTTOM_RIGHT;
491 	  deco->last_x = x;
492 	  deco->last_y = y;
493 	}
494       break;
495     default:
496       break;
497     }
498 
499   return TRUE;
500 }
501 
502 static gint
gtk_decorated_window_button_release(GtkWidget * widget,GdkEventButton * event)503 gtk_decorated_window_button_release (GtkWidget	    *widget,
504 				     GdkEventButton *event)
505 {
506   GtkWindow *window;
507   GtkWindowRegionType type;
508   GtkWindowDecoration *deco;
509 
510   window = GTK_WINDOW (widget);
511   deco = get_decoration (window);
512 
513   if (deco->closing)
514     {
515       type = gtk_decorated_window_region_type (window, event->x, event->y);
516       if (type == GTK_WINDOW_REGION_CLOSE)
517 	{
518 	  GdkEvent *event = gdk_event_new (GDK_DELETE);
519 
520 	  event->any.type = GDK_DELETE;
521 	  event->any.window = g_object_ref (widget->window);
522 	  event->any.send_event = TRUE;
523 
524 	  gtk_main_do_event (event);
525 	  gdk_event_free (event);
526 	}
527     }
528   else if (deco->maximizing)
529     {
530       type = gtk_decorated_window_region_type (window, event->x, event->y);
531       if (type == GTK_WINDOW_REGION_MAXIMIZE)
532         {
533 	  if (deco->maximized)
534 	    gtk_window_unmaximize (window);
535 	  else
536 	    gtk_window_maximize (window);
537 	}
538     }
539 
540   deco->closing = FALSE;
541   deco->maximizing = FALSE;
542   deco->moving = FALSE;
543   deco->resize = RESIZE_NONE;
544   return TRUE;
545 }
546 
547 static gint
gtk_decorated_window_window_state(GtkWidget * widget,GdkEventWindowState * event)548 gtk_decorated_window_window_state (GtkWidget	       *widget,
549 				   GdkEventWindowState *event)
550 {
551   GtkWindow *window;
552   GtkWindowDecoration *deco;
553   GdkWindowObject *priv;
554 
555   window = GTK_WINDOW (widget);
556   deco = get_decoration (window);
557   priv = GDK_WINDOW_OBJECT (window->frame);
558 
559   if (event->changed_mask & GDK_WINDOW_STATE_MAXIMIZED)
560     {
561       if (event->new_window_state & GDK_WINDOW_STATE_MAXIMIZED)
562 	{
563 	  int w, h;
564 	  gdk_window_get_geometry (widget->window, NULL, NULL,
565 				   &deco->last_w, &deco->last_h, NULL);
566 	  gdk_window_get_origin (widget->window, &deco->last_x, &deco->last_y);
567 	  w = gdk_screen_get_width(gdk_screen_get_default()) - DECORATION_BORDER_TOT_X;
568 	  h = gdk_screen_get_height(gdk_screen_get_default()) - DECORATION_BORDER_TOT_Y;
569 	  _gtk_window_constrain_size (window, w, h, &w, &h);
570 	  if (w != deco->last_w || h != deco->last_h)
571 	    {
572 	      _gtk_window_reposition (window, DECORATION_BORDER_LEFT, DECORATION_BORDER_TOP);
573 	      gdk_window_resize (widget->window, w, h);
574 	      deco->maximized = TRUE;
575 	    }
576 	}
577       else
578 	{
579 	  _gtk_window_reposition (window, deco->last_x, deco->last_y);
580 	  _gtk_window_constrain_size (window, deco->last_w, deco->last_h,
581 				      &deco->last_w, &deco->last_h);
582 	  gdk_window_resize (widget->window, deco->last_w, deco->last_h);
583 	  deco->maximized = FALSE;
584 	}
585     }
586   return TRUE;
587 }
588 
589 static void
gtk_decorated_window_paint(GtkWidget * widget,GdkRectangle * area)590 gtk_decorated_window_paint (GtkWidget    *widget,
591 			    GdkRectangle *area)
592 {
593   GtkWindow *window = GTK_WINDOW (widget);
594   GtkWindowDecoration *deco = get_decoration (window);
595   gint x1, y1, x2, y2;
596   GtkStateType border_state;
597 
598   if (deco->decorated)
599     {
600       GdkWindow *frame;
601       gint width, height;
602 
603       frame = window->frame;
604       gdk_drawable_get_size (frame, &width, &height);
605 
606       /* Top */
607       gtk_paint_flat_box (widget->style, frame, GTK_STATE_NORMAL,
608 			  GTK_SHADOW_NONE, area, widget, "base",
609 			  0, 0,
610 			  width, DECORATION_BORDER_TOP);
611       /* Bottom */
612       gtk_paint_flat_box (widget->style, frame, GTK_STATE_NORMAL,
613 			  GTK_SHADOW_NONE, area, widget, "base",
614 			  0, height - DECORATION_BORDER_BOTTOM,
615 			  width, DECORATION_BORDER_BOTTOM);
616       /* Left */
617       gtk_paint_flat_box (widget->style, frame, GTK_STATE_NORMAL,
618 			  GTK_SHADOW_NONE, area, widget, "base",
619 			  0, DECORATION_BORDER_TOP,
620 			  DECORATION_BORDER_LEFT, height - DECORATION_BORDER_TOT_Y);
621       /* Right */
622       gtk_paint_flat_box (widget->style, frame, GTK_STATE_NORMAL,
623 			  GTK_SHADOW_NONE, area, widget, "base",
624 			  width - DECORATION_BORDER_RIGHT, DECORATION_BORDER_TOP,
625 			  DECORATION_BORDER_RIGHT, height - DECORATION_BORDER_TOT_Y);
626 
627       /* Border: */
628       if (deco->focused)
629 	border_state = GTK_STATE_SELECTED;
630       else
631 	border_state = GTK_STATE_PRELIGHT;
632 
633       gtk_paint_box (widget->style, frame, border_state,
634 		     GTK_SHADOW_OUT, area, widget, "base",
635 		     0, 0, width, height);
636 
637       gtk_paint_box (widget->style, frame, border_state,
638 		     GTK_SHADOW_IN, area, widget, "base",
639 		     DECORATION_BORDER_LEFT - 2, DECORATION_BORDER_TOP - 2,
640 		     width - (DECORATION_BORDER_LEFT + DECORATION_BORDER_RIGHT) + 3,
641 		     height - (DECORATION_BORDER_TOP + DECORATION_BORDER_BOTTOM) + 3);
642 
643       if (deco->maximizable)
644 	{
645 	  /* Maximize button: */
646 
647 	  x1 = width - (DECORATION_BORDER_LEFT * 2) - (DECORATION_BUTTON_SIZE * 2);
648 	  y1 = DECORATION_BUTTON_Y_OFFSET;
649 	  x2 = x1 + DECORATION_BUTTON_SIZE;
650 	  y2 = y1 + DECORATION_BUTTON_SIZE;
651 
652 	  if (area)
653 	    gdk_gc_set_clip_rectangle (widget->style->bg_gc[widget->state], area);
654 
655 	  gdk_draw_rectangle (frame, widget->style->bg_gc[widget->state], TRUE,
656 			      x1, y1, x2 - x1, y2 - y1);
657 
658 	  gdk_draw_line (frame, widget->style->black_gc, x1 + 1, y1 + 1, x2 - 2, y1 + 1);
659 
660 	  gdk_draw_rectangle (frame, widget->style->black_gc, FALSE,
661 			      x1 + 1, y1 + 2,
662 			      DECORATION_BUTTON_SIZE - 3, DECORATION_BUTTON_SIZE - 4);
663 
664 	  if (area)
665 	    gdk_gc_set_clip_rectangle (widget->style->black_gc, NULL);
666 	}
667 
668       /* Close button: */
669 
670       x1 = width - DECORATION_BORDER_LEFT - DECORATION_BUTTON_SIZE;
671       y1 = DECORATION_BUTTON_Y_OFFSET;
672       x2 = width - DECORATION_BORDER_LEFT;
673       y2 = DECORATION_BUTTON_Y_OFFSET + DECORATION_BUTTON_SIZE;
674 
675       if (area)
676 	gdk_gc_set_clip_rectangle (widget->style->bg_gc[widget->state], area);
677 
678       gdk_draw_rectangle (frame, widget->style->bg_gc[widget->state], TRUE,
679 			  x1, y1, x2 - x1, y2 - y1);
680 
681       if (area)
682 	gdk_gc_set_clip_rectangle (widget->style->bg_gc[widget->state], NULL);
683 
684       if (area)
685 	gdk_gc_set_clip_rectangle (widget->style->black_gc, area);
686 
687       gdk_draw_line (frame, widget->style->black_gc, x1, y1, x2-1, y2-1);
688 
689       gdk_draw_line (frame, widget->style->black_gc, x1, y2-1, x2-1, y1);
690 
691       if (area)
692 	gdk_gc_set_clip_rectangle (widget->style->black_gc, NULL);
693 
694 
695 
696       /* Title */
697       if (deco->title_layout)
698 	{
699 	  if (area)
700 	    gdk_gc_set_clip_rectangle (widget->style->fg_gc [border_state], area);
701 
702 	  gdk_draw_layout (frame,
703 			   widget->style->fg_gc [border_state],
704 			   DECORATION_BORDER_LEFT, 1,
705 			   deco->title_layout);
706 	  if (area)
707 	    gdk_gc_set_clip_rectangle (widget->style->fg_gc [border_state], NULL);
708 	}
709 
710     }
711 }
712 
713 
714 static void
gtk_decorated_window_recalculate_regions(GtkWindow * window)715 gtk_decorated_window_recalculate_regions (GtkWindow *window)
716 {
717   gint n_regions;
718   gint width, height;
719   GtkWindowRegion *region;
720   GtkWindowDecoration *deco = get_decoration (window);
721 
722   n_regions = 0;
723 
724   if (!deco->decorated)
725     return;
726 
727   n_regions += 2; /* close, Title */
728   if (deco->maximizable)
729     n_regions += 1;
730   if (window->allow_shrink || window->allow_grow)
731     n_regions += 2;
732 
733   if (deco->n_regions != n_regions)
734     {
735       g_free (deco->regions);
736       deco->regions = g_new (GtkWindowRegion, n_regions);
737       deco->n_regions = n_regions;
738     }
739 
740   width = GTK_WIDGET (window)->allocation.width + DECORATION_BORDER_TOT_X;
741   height = GTK_WIDGET (window)->allocation.height + DECORATION_BORDER_TOT_Y;
742 
743   region = deco->regions;
744 
745   /* Maximize button */
746   if (deco->maximizable)
747     {
748       region->rect.x = width - (DECORATION_BORDER_LEFT * 2) - (DECORATION_BUTTON_SIZE * 2);
749       region->rect.y = DECORATION_BUTTON_Y_OFFSET;
750       region->rect.width = DECORATION_BUTTON_SIZE;
751       region->rect.height = DECORATION_BUTTON_SIZE;
752       region->type = GTK_WINDOW_REGION_MAXIMIZE;
753       region++;
754     }
755 
756   /* Close button */
757   region->rect.x = width - DECORATION_BORDER_LEFT - DECORATION_BUTTON_SIZE;
758   region->rect.y = DECORATION_BUTTON_Y_OFFSET;
759   region->rect.width = DECORATION_BUTTON_SIZE;
760   region->rect.height = DECORATION_BUTTON_SIZE;
761   region->type = GTK_WINDOW_REGION_CLOSE;
762   region++;
763 
764   /* title bar */
765   region->rect.x = 0;
766   region->rect.y = 0;
767   region->rect.width = width;
768   region->rect.height = DECORATION_BORDER_TOP;
769   region->type = GTK_WINDOW_REGION_TITLE;
770   region++;
771 
772   if (window->allow_shrink || window->allow_grow)
773     {
774       region->rect.x = width - (DECORATION_BORDER_RIGHT + 10);
775       region->rect.y = height - DECORATION_BORDER_BOTTOM;
776       region->rect.width = DECORATION_BORDER_RIGHT + 10;
777       region->rect.height = DECORATION_BORDER_BOTTOM;
778       region->type = GTK_WINDOW_REGION_BR_RESIZE;
779       region++;
780 
781       region->rect.x = width - DECORATION_BORDER_RIGHT;
782       region->rect.y = height - (DECORATION_BORDER_BOTTOM + 10);
783       region->rect.width = DECORATION_BORDER_RIGHT;
784       region->rect.height = DECORATION_BORDER_BOTTOM + 10;
785       region->type = GTK_WINDOW_REGION_BR_RESIZE;
786       region++;
787     }
788 }
789 
790 void
gtk_decorated_window_move_resize_window(GtkWindow * window,gint x,gint y,gint width,gint height)791 gtk_decorated_window_move_resize_window (GtkWindow   *window,
792 					 gint         x,
793 					 gint         y,
794 					 gint         width,
795 					 gint         height)
796 {
797   GtkWidget *widget = GTK_WIDGET (window);
798   GtkWindowDecoration *deco = get_decoration (window);
799 
800   deco->real_inner_move = TRUE;
801   gdk_window_move_resize (widget->window,
802 			  x, y, width, height);
803 }
804 #else
805 
806 void
gtk_decorated_window_init(GtkWindow * window)807 gtk_decorated_window_init (GtkWindow  *window)
808 {
809 }
810 
811 void
gtk_decorated_window_calculate_frame_size(GtkWindow * window)812 gtk_decorated_window_calculate_frame_size (GtkWindow *window)
813 {
814 }
815 
816 void
gtk_decorated_window_set_title(GtkWindow * window,const gchar * title)817 gtk_decorated_window_set_title (GtkWindow   *window,
818 				const gchar *title)
819 {
820 }
821 
822 void
gtk_decorated_window_move_resize_window(GtkWindow * window,gint x,gint y,gint width,gint height)823 gtk_decorated_window_move_resize_window (GtkWindow   *window,
824 					 gint         x,
825 					 gint         y,
826 					 gint         width,
827 					 gint         height)
828 {
829   gdk_window_move_resize (GTK_WIDGET (window)->window,
830 			  x, y, width, height);
831 }
832 #endif
833 
834 
835 #define __GTK_WINDOW_DECORATE_C__
836 #include "gtkaliasdef.c"
837