1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 2001 Red Hat, Inc.
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.
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.
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.
21 * Authors: Alexander Larsson <alexl@redhat.com>
25 #include "gtkprivate.h"
26 #include "gtkwindow.h"
28 #include "gtkwindow-decorate.h"
33 #ifdef DECORATE_WINDOWS
37 GTK_WINDOW_REGION_TITLE,
38 GTK_WINDOW_REGION_MAXIMIZE,
39 GTK_WINDOW_REGION_CLOSE,
40 GTK_WINDOW_REGION_BR_RESIZE
41 } GtkWindowRegionType;
43 typedef struct _GtkWindowRegion GtkWindowRegion;
44 typedef struct _GtkWindowDecoration GtkWindowDecoration;
46 struct _GtkWindowRegion
49 GtkWindowRegionType type;
63 } GtkWindowResizeType;
65 struct _GtkWindowDecoration
68 GtkWindowRegion *regions;
73 PangoLayout *title_layout;
75 GtkWindowResizeType resize;
81 guint maximizable : 1;
83 guint real_inner_move : 1;
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"
97 static void gtk_decorated_window_recalculate_regions (GtkWindow *window);
98 static GtkWindowRegionType gtk_decorated_window_region_type (GtkWindow *window,
101 static gint gtk_decorated_window_frame_event (GtkWindow *window,
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,
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);
119 gtk_decoration_free (GtkWindowDecoration *deco)
121 g_free (deco->regions);
122 deco->regions = NULL;
129 gtk_decorated_window_init (GtkWindow *window)
131 GtkWindowDecoration *deco;
133 deco = g_new (GtkWindowDecoration, 1);
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;
147 g_object_set_data_full (G_OBJECT (window), I_("gtk-window-decoration"), deco,
148 (GDestroyNotify) gtk_decoration_free);
150 gtk_window_set_has_frame (window, TRUE);
152 g_signal_connect (window,
154 G_CALLBACK (gtk_decorated_window_frame_event),
156 g_signal_connect (window,
158 G_CALLBACK (gtk_decorated_window_focus_change),
160 g_signal_connect (window,
162 G_CALLBACK (gtk_decorated_window_focus_change),
164 g_signal_connect (window,
166 G_CALLBACK (gtk_decorated_window_realize),
168 g_signal_connect (window,
170 G_CALLBACK (gtk_decorated_window_unrealize),
174 static inline GtkWindowDecoration *
175 get_decoration (GtkWindow *window)
177 return (GtkWindowDecoration *)g_object_get_data (G_OBJECT (window), "gtk-window-decoration");
181 gtk_decorated_window_set_title (GtkWindow *window,
184 GtkWindowDecoration *deco = get_decoration (window);
186 if (deco->title_layout)
187 pango_layout_set_text (deco->title_layout, title, -1);
191 gtk_decorated_window_calculate_frame_size (GtkWindow *window)
193 GdkWMDecoration decorations;
194 GtkWindowDecoration *deco = get_decoration (window);
196 if (gdk_window_get_decorations (GTK_WIDGET (window)->window,
199 if ((decorations & GDK_DECOR_BORDER) &&
200 (decorations & GDK_DECOR_TITLE))
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;
208 deco->decorated = FALSE;
212 deco->decorated = (window->type != GTK_WINDOW_POPUP);
213 deco->maximizable = (gtk_window_get_type_hint (window) == GDK_WINDOW_TYPE_HINT_NORMAL);
217 gtk_window_set_frame_dimensions (window,
218 DECORATION_BORDER_LEFT,
219 DECORATION_BORDER_TOP,
220 DECORATION_BORDER_RIGHT,
221 DECORATION_BORDER_BOTTOM);
223 gtk_window_set_frame_dimensions (window, 0, 0, 0, 0);
225 gtk_decorated_window_recalculate_regions (window);
229 gtk_decorated_window_inner_change (GdkWindow *win,
231 gint width, gint height,
234 GtkWindow *window = (GtkWindow *)user_data;
235 GtkWidget *widget = GTK_WIDGET (window);
236 GtkWindowDecoration *deco = get_decoration (window);
238 if (deco->real_inner_move)
240 deco->real_inner_move = FALSE;
244 deco->real_inner_move = TRUE;
245 gdk_window_move_resize (widget->window,
246 window->frame_left, window->frame_top,
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);
257 gtk_decorated_window_inner_get_pos (GdkWindow *win,
261 GtkWindow *window = (GtkWindow *)user_data;
263 gdk_window_get_position (window->frame, x, y);
265 *x += window->frame_left;
266 *y += window->frame_top;
270 gtk_decorated_window_realize (GtkWindow *window)
272 GtkWindowDecoration *deco = get_decoration (window);
273 GtkWidget *widget = GTK_WIDGET (window);
274 PangoFontDescription *font_desc;
276 deco->title_layout = gtk_widget_create_pango_layout (widget,
277 (window->title)?window->title:"");
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);
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,
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);
300 gtk_decorated_window_unrealize (GtkWindow *window)
302 GtkWindowDecoration *deco = get_decoration (window);
304 if (deco->title_layout)
306 g_object_unref (deco->title_layout);
307 deco->title_layout = NULL;
312 gtk_decorated_window_frame_event (GtkWindow *window, GdkEvent *event)
314 GtkWindowDecoration *deco = get_decoration (window);
315 GtkWidget *widget = GTK_WIDGET (window);
316 GdkEventExpose *expose_event;
321 expose_event = (GdkEventExpose *)event;
323 gtk_decorated_window_paint (widget, &expose_event->area);
327 gtk_decorated_window_recalculate_regions (window);
329 case GDK_MOTION_NOTIFY:
330 return gtk_decorated_window_motion_notify (widget, (GdkEventMotion *)event);
332 case GDK_BUTTON_PRESS:
333 return gtk_decorated_window_button_press (widget, (GdkEventButton *)event);
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);
346 gtk_decorated_window_focus_change (GtkWidget *widget,
347 GdkEventFocus *event)
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);
357 gtk_decorated_window_motion_notify (GtkWidget *widget,
358 GdkEventMotion *event)
361 GtkWindowDecoration *deco;
362 GdkModifierType mask;
365 gint win_x, win_y, win_w, win_h;
367 window = GTK_WINDOW (widget);
368 deco = get_decoration (window);
370 if (!deco->decorated)
373 win = widget->window;
374 gdk_window_get_pointer (window->frame, &x, &y, &mask);
376 gdk_window_get_position (window->frame, &win_x, &win_y);
377 win_x += DECORATION_BORDER_LEFT;
378 win_y += DECORATION_BORDER_TOP;
380 gdk_window_get_geometry (win, NULL, NULL, &win_w, &win_h, NULL);
385 dx = x - deco->last_x;
386 dy = y - deco->last_y;
388 _gtk_window_reposition (window, win_x + dx, win_y + dy);
391 if (deco->resize != RESIZE_NONE)
398 switch(deco->resize) {
399 case RESIZE_BOTTOM_RIGHT:
400 w = x - DECORATION_BORDER_TOT_X;
401 h = y - DECORATION_BORDER_TOT_Y;
404 w = x - DECORATION_BORDER_TOT_X;
407 h = y - DECORATION_BORDER_TOT_Y;
409 case RESIZE_TOP_LEFT:
411 case RESIZE_TOP_RIGHT:
412 case RESIZE_BOTTOM_LEFT:
415 g_warning ("Resize mode %d not handled yet.\n", deco->resize);
419 if ((w > 0) && (h > 0))
421 _gtk_window_constrain_size (window, w,h, &w, &h);
423 if ((w != win_w) || (h != win_h))
424 gdk_window_resize (widget->window, w, h);
431 static GtkWindowRegionType
432 gtk_decorated_window_region_type (GtkWindow *window, gint x, gint y)
434 GtkWindowDecoration *deco = get_decoration (window);
437 for (i=0;i<deco->n_regions;i++)
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;
449 gtk_decorated_window_button_press (GtkWidget *widget,
450 GdkEventButton *event)
453 GtkWindowRegionType type;
454 GtkWindowDecoration *deco;
457 window = GTK_WINDOW (widget);
458 deco = get_decoration (window);
460 if (!deco->decorated)
466 type = gtk_decorated_window_region_type (window, x, y);
470 case GTK_WINDOW_REGION_TITLE:
471 if (!deco->maximized && event->state & GDK_BUTTON1_MASK)
478 case GTK_WINDOW_REGION_MAXIMIZE:
479 if (event->state & GDK_BUTTON1_MASK)
480 deco->maximizing = TRUE;
482 case GTK_WINDOW_REGION_CLOSE:
483 if (event->state & GDK_BUTTON1_MASK)
484 deco->closing = TRUE;
486 case GTK_WINDOW_REGION_BR_RESIZE:
487 if (!deco->maximized)
489 if (event->state & GDK_BUTTON1_MASK)
490 deco->resize = RESIZE_BOTTOM_RIGHT;
503 gtk_decorated_window_button_release (GtkWidget *widget,
504 GdkEventButton *event)
507 GtkWindowRegionType type;
508 GtkWindowDecoration *deco;
510 window = GTK_WINDOW (widget);
511 deco = get_decoration (window);
515 type = gtk_decorated_window_region_type (window, event->x, event->y);
516 if (type == GTK_WINDOW_REGION_CLOSE)
518 GdkEvent *event = gdk_event_new (GDK_DELETE);
520 event->any.type = GDK_DELETE;
521 event->any.window = g_object_ref (widget->window);
522 event->any.send_event = TRUE;
524 gtk_main_do_event (event);
525 gdk_event_free (event);
528 else if (deco->maximizing)
530 type = gtk_decorated_window_region_type (window, event->x, event->y);
531 if (type == GTK_WINDOW_REGION_MAXIMIZE)
534 gtk_window_unmaximize (window);
536 gtk_window_maximize (window);
540 deco->closing = FALSE;
541 deco->maximizing = FALSE;
542 deco->moving = FALSE;
543 deco->resize = RESIZE_NONE;
548 gtk_decorated_window_window_state (GtkWidget *widget,
549 GdkEventWindowState *event)
552 GtkWindowDecoration *deco;
553 GdkWindowObject *priv;
555 window = GTK_WINDOW (widget);
556 deco = get_decoration (window);
557 priv = GDK_WINDOW_OBJECT (window->frame);
559 if (event->changed_mask & GDK_WINDOW_STATE_MAXIMIZED)
561 if (event->new_window_state & GDK_WINDOW_STATE_MAXIMIZED)
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)
572 _gtk_window_reposition (window, DECORATION_BORDER_LEFT, DECORATION_BORDER_TOP);
573 gdk_window_resize (widget->window, w, h);
574 deco->maximized = TRUE;
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;
590 gtk_decorated_window_paint (GtkWidget *widget,
593 GtkWindow *window = GTK_WINDOW (widget);
594 GtkWindowDecoration *deco = get_decoration (window);
596 GtkStateType border_state;
603 frame = window->frame;
604 gdk_drawable_get_size (frame, &width, &height);
607 gtk_paint_flat_box (widget->style, frame, GTK_STATE_NORMAL,
608 GTK_SHADOW_NONE, area, widget, "base",
610 width, DECORATION_BORDER_TOP);
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);
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);
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);
629 border_state = GTK_STATE_SELECTED;
631 border_state = GTK_STATE_PRELIGHT;
633 gtk_paint_box (widget->style, frame, border_state,
634 GTK_SHADOW_OUT, area, widget, "base",
635 0, 0, width, height);
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);
643 if (deco->maximizable)
645 /* Maximize button: */
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;
653 gdk_gc_set_clip_rectangle (widget->style->bg_gc[widget->state], area);
655 gdk_draw_rectangle (frame, widget->style->bg_gc[widget->state], TRUE,
656 x1, y1, x2 - x1, y2 - y1);
658 gdk_draw_line (frame, widget->style->black_gc, x1 + 1, y1 + 1, x2 - 2, y1 + 1);
660 gdk_draw_rectangle (frame, widget->style->black_gc, FALSE,
662 DECORATION_BUTTON_SIZE - 3, DECORATION_BUTTON_SIZE - 4);
665 gdk_gc_set_clip_rectangle (widget->style->black_gc, NULL);
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;
676 gdk_gc_set_clip_rectangle (widget->style->bg_gc[widget->state], area);
678 gdk_draw_rectangle (frame, widget->style->bg_gc[widget->state], TRUE,
679 x1, y1, x2 - x1, y2 - y1);
682 gdk_gc_set_clip_rectangle (widget->style->bg_gc[widget->state], NULL);
685 gdk_gc_set_clip_rectangle (widget->style->black_gc, area);
687 gdk_draw_line (frame, widget->style->black_gc, x1, y1, x2-1, y2-1);
689 gdk_draw_line (frame, widget->style->black_gc, x1, y2-1, x2-1, y1);
692 gdk_gc_set_clip_rectangle (widget->style->black_gc, NULL);
697 if (deco->title_layout)
700 gdk_gc_set_clip_rectangle (widget->style->fg_gc [border_state], area);
702 gdk_draw_layout (frame,
703 widget->style->fg_gc [border_state],
704 DECORATION_BORDER_LEFT, 1,
707 gdk_gc_set_clip_rectangle (widget->style->fg_gc [border_state], NULL);
715 gtk_decorated_window_recalculate_regions (GtkWindow *window)
719 GtkWindowRegion *region;
720 GtkWindowDecoration *deco = get_decoration (window);
724 if (!deco->decorated)
727 n_regions += 2; /* close, Title */
728 if (deco->maximizable)
730 if (window->allow_shrink || window->allow_grow)
733 if (deco->n_regions != n_regions)
735 g_free (deco->regions);
736 deco->regions = g_new (GtkWindowRegion, n_regions);
737 deco->n_regions = n_regions;
740 width = GTK_WIDGET (window)->allocation.width + DECORATION_BORDER_TOT_X;
741 height = GTK_WIDGET (window)->allocation.height + DECORATION_BORDER_TOT_Y;
743 region = deco->regions;
745 /* Maximize button */
746 if (deco->maximizable)
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;
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;
767 region->rect.width = width;
768 region->rect.height = DECORATION_BORDER_TOP;
769 region->type = GTK_WINDOW_REGION_TITLE;
772 if (window->allow_shrink || window->allow_grow)
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;
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;
791 gtk_decorated_window_move_resize_window (GtkWindow *window,
797 GtkWidget *widget = GTK_WIDGET (window);
798 GtkWindowDecoration *deco = get_decoration (window);
800 deco->real_inner_move = TRUE;
801 gdk_window_move_resize (widget->window,
802 x, y, width, height);
807 gtk_decorated_window_init (GtkWindow *window)
812 gtk_decorated_window_calculate_frame_size (GtkWindow *window)
817 gtk_decorated_window_set_title (GtkWindow *window,
823 gtk_decorated_window_move_resize_window (GtkWindow *window,
829 gdk_window_move_resize (GTK_WIDGET (window)->window,
830 x, y, width, height);
835 #define __GTK_WINDOW_DECORATE_C__
836 #include "gtkaliasdef.c"