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