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"
30 #ifdef GDK_WINDOWING_FB
31 #define DECORATE_WINDOWS
34 #ifdef DECORATE_WINDOWS
35 #include "linux-fb/gdkfb.h"
39 GTK_WINDOW_REGION_TITLE,
40 GTK_WINDOW_REGION_MAXIMIZE,
41 GTK_WINDOW_REGION_CLOSE,
42 GTK_WINDOW_REGION_BR_RESIZE
43 } GtkWindowRegionType;
45 typedef struct _GtkWindowRegion GtkWindowRegion;
46 typedef struct _GtkWindowDecoration GtkWindowDecoration;
48 struct _GtkWindowRegion
51 GtkWindowRegionType type;
65 } GtkWindowResizeType;
67 struct _GtkWindowDecoration
70 GtkWindowRegion *regions;
75 PangoLayout *title_layout;
77 GtkWindowResizeType resize;
83 guint maximizable : 1;
85 guint real_inner_move : 1;
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"
99 static void gtk_decorated_window_recalculate_regions (GtkWindow *window);
100 static GtkWindowRegionType gtk_decorated_window_region_type (GtkWindow *window,
103 static gint gtk_decorated_window_frame_event (GtkWindow *window,
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,
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);
121 gtk_decoration_free (GtkWindowDecoration *deco)
123 g_free (deco->regions);
124 deco->regions = NULL;
131 gtk_decorated_window_init (GtkWindow *window)
133 GtkWindowDecoration *deco;
135 deco = g_new (GtkWindowDecoration, 1);
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;
149 g_object_set_data_full (G_OBJECT (window), "gtk-window-decoration", deco,
150 (GDestroyNotify) gtk_decoration_free);
152 gtk_window_set_has_frame (window, TRUE);
154 g_signal_connect (window,
156 G_CALLBACK (gtk_decorated_window_frame_event),
158 g_signal_connect (window,
160 G_CALLBACK (gtk_decorated_window_focus_change),
162 g_signal_connect (window,
164 G_CALLBACK (gtk_decorated_window_focus_change),
166 g_signal_connect (window,
168 G_CALLBACK (gtk_decorated_window_realize),
170 g_signal_connect (window,
172 G_CALLBACK (gtk_decorated_window_unrealize),
176 static inline GtkWindowDecoration *
177 get_decoration (GtkWindow *window)
179 return (GtkWindowDecoration *)g_object_get_data (G_OBJECT (window), "gtk-window-decoration");
183 gtk_decorated_window_set_title (GtkWindow *window,
186 GtkWindowDecoration *deco = get_decoration (window);
188 if (deco->title_layout)
189 pango_layout_set_text (deco->title_layout, title, -1);
193 gtk_decorated_window_calculate_frame_size (GtkWindow *window)
195 GdkWMDecoration decorations;
196 GtkWindowDecoration *deco = get_decoration (window);
198 if (gdk_window_get_decorations (GTK_WIDGET (window)->window,
201 if ((decorations & GDK_DECOR_BORDER) &&
202 (decorations & GDK_DECOR_TITLE))
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;
210 deco->decorated = FALSE;
214 deco->decorated = (window->type != GTK_WINDOW_POPUP);
215 deco->maximizable = (gtk_window_get_type_hint (window) == GDK_WINDOW_TYPE_HINT_NORMAL);
219 gtk_window_set_frame_dimensions (window,
220 DECORATION_BORDER_LEFT,
221 DECORATION_BORDER_TOP,
222 DECORATION_BORDER_RIGHT,
223 DECORATION_BORDER_BOTTOM);
225 gtk_window_set_frame_dimensions (window, 0, 0, 0, 0);
227 gtk_decorated_window_recalculate_regions (window);
231 gtk_decorated_window_inner_change (GdkWindow *win,
233 gint width, gint height,
236 GtkWindow *window = (GtkWindow *)user_data;
237 GtkWidget *widget = GTK_WIDGET (window);
238 GtkWindowDecoration *deco = get_decoration (window);
240 if (deco->real_inner_move)
242 deco->real_inner_move = FALSE;
246 deco->real_inner_move = TRUE;
247 gdk_window_move_resize (widget->window,
248 window->frame_left, window->frame_top,
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);
259 gtk_decorated_window_inner_get_pos (GdkWindow *win,
263 GtkWindow *window = (GtkWindow *)user_data;
265 gdk_window_get_position (window->frame, x, y);
267 *x += window->frame_left;
268 *y += window->frame_top;
272 gtk_decorated_window_realize (GtkWindow *window)
274 GtkWindowDecoration *deco = get_decoration (window);
275 GtkWidget *widget = GTK_WIDGET (window);
276 PangoFontDescription *font_desc;
278 deco->title_layout = gtk_widget_create_pango_layout (widget,
279 (window->title)?window->title:"");
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);
285 gdk_fb_window_set_child_handler (window->frame,
286 gtk_decorated_window_inner_change,
287 gtk_decorated_window_inner_get_pos,
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);
297 gtk_decorated_window_unrealize (GtkWindow *window)
299 GtkWindowDecoration *deco = get_decoration (window);
301 if (deco->title_layout)
303 g_object_unref (deco->title_layout);
304 deco->title_layout = NULL;
309 gtk_decorated_window_frame_event (GtkWindow *window, GdkEvent *event)
311 GtkWindowDecoration *deco = get_decoration (window);
312 GtkWidget *widget = GTK_WIDGET (window);
313 GdkEventExpose *expose_event;
318 expose_event = (GdkEventExpose *)event;
320 gtk_decorated_window_paint (widget, &expose_event->area);
324 gtk_decorated_window_recalculate_regions (window);
326 case GDK_MOTION_NOTIFY:
327 return gtk_decorated_window_motion_notify (widget, (GdkEventMotion *)event);
329 case GDK_BUTTON_PRESS:
330 return gtk_decorated_window_button_press (widget, (GdkEventButton *)event);
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);
343 gtk_decorated_window_focus_change (GtkWidget *widget,
344 GdkEventFocus *event)
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);
354 gtk_decorated_window_motion_notify (GtkWidget *widget,
355 GdkEventMotion *event)
358 GtkWindowDecoration *deco;
359 GdkModifierType mask;
362 gint win_x, win_y, win_w, win_h;
364 window = GTK_WINDOW (widget);
365 deco = get_decoration (window);
367 if (!deco->decorated)
370 win = widget->window;
371 gdk_window_get_pointer (window->frame, &x, &y, &mask);
373 gdk_window_get_position (window->frame, &win_x, &win_y);
374 win_x += DECORATION_BORDER_LEFT;
375 win_y += DECORATION_BORDER_TOP;
377 gdk_window_get_geometry (win, NULL, NULL, &win_w, &win_h, NULL);
382 dx = x - deco->last_x;
383 dy = y - deco->last_y;
385 _gtk_window_reposition (window, win_x + dx, win_y + dy);
388 if (deco->resize != RESIZE_NONE)
395 switch(deco->resize) {
396 case RESIZE_BOTTOM_RIGHT:
397 w = x - DECORATION_BORDER_TOT_X;
398 h = y - DECORATION_BORDER_TOT_Y;
401 w = x - DECORATION_BORDER_TOT_X;
404 h = y - DECORATION_BORDER_TOT_Y;
406 case RESIZE_TOP_LEFT:
408 case RESIZE_TOP_RIGHT:
409 case RESIZE_BOTTOM_LEFT:
412 g_warning ("Resize mode %d not handled yet.\n", deco->resize);
416 if ((w > 0) && (h > 0))
418 _gtk_window_constrain_size (window, w,h, &w, &h);
420 if ((w != win_w) || (h != win_h))
421 gdk_window_resize (widget->window, w, h);
428 static GtkWindowRegionType
429 gtk_decorated_window_region_type (GtkWindow *window, gint x, gint y)
431 GtkWindowDecoration *deco = get_decoration (window);
434 for (i=0;i<deco->n_regions;i++)
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;
446 gtk_decorated_window_button_press (GtkWidget *widget,
447 GdkEventButton *event)
450 GtkWindowRegionType type;
451 GtkWindowDecoration *deco;
454 window = GTK_WINDOW (widget);
455 deco = get_decoration (window);
457 if (!deco->decorated)
463 type = gtk_decorated_window_region_type (window, x, y);
467 case GTK_WINDOW_REGION_TITLE:
468 if (!deco->maximized && event->state & GDK_BUTTON1_MASK)
475 case GTK_WINDOW_REGION_MAXIMIZE:
476 if (event->state & GDK_BUTTON1_MASK)
477 deco->maximizing = TRUE;
479 case GTK_WINDOW_REGION_CLOSE:
480 if (event->state & GDK_BUTTON1_MASK)
481 deco->closing = TRUE;
483 case GTK_WINDOW_REGION_BR_RESIZE:
484 if (!deco->maximized)
486 if (event->state & GDK_BUTTON1_MASK)
487 deco->resize = RESIZE_BOTTOM_RIGHT;
500 gtk_decorated_window_button_release (GtkWidget *widget,
501 GdkEventButton *event)
504 GtkWindowRegionType type;
505 GtkWindowDecoration *deco;
507 window = GTK_WINDOW (widget);
508 deco = get_decoration (window);
512 type = gtk_decorated_window_region_type (window, event->x, event->y);
513 if (type == GTK_WINDOW_REGION_CLOSE)
515 GdkEvent *event = gdk_event_new (GDK_DELETE);
517 event->any.type = GDK_DELETE;
518 event->any.window = g_object_ref (widget->window);
519 event->any.send_event = TRUE;
521 gtk_main_do_event (event);
522 gdk_event_free (event);
525 else if (deco->maximizing)
527 type = gtk_decorated_window_region_type (window, event->x, event->y);
528 if (type == GTK_WINDOW_REGION_MAXIMIZE)
531 gtk_window_unmaximize (window);
533 gtk_window_maximize (window);
537 deco->closing = FALSE;
538 deco->maximizing = FALSE;
539 deco->moving = FALSE;
540 deco->resize = RESIZE_NONE;
545 gtk_decorated_window_window_state (GtkWidget *widget,
546 GdkEventWindowState *event)
549 GtkWindowDecoration *deco;
550 GdkWindowObject *priv;
552 window = GTK_WINDOW (widget);
553 deco = get_decoration (window);
554 priv = GDK_WINDOW_OBJECT (window->frame);
556 if (event->changed_mask & GDK_WINDOW_STATE_MAXIMIZED)
558 if (event->new_window_state & GDK_WINDOW_STATE_MAXIMIZED)
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)
569 _gtk_window_reposition (window, DECORATION_BORDER_LEFT, DECORATION_BORDER_TOP);
570 gdk_window_resize (widget->window, w, h);
571 deco->maximized = TRUE;
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;
587 gtk_decorated_window_paint (GtkWidget *widget,
590 GtkWindow *window = GTK_WINDOW (widget);
591 GtkWindowDecoration *deco = get_decoration (window);
593 GtkStateType border_state;
600 frame = window->frame;
601 gdk_drawable_get_size (frame, &width, &height);
604 gtk_paint_flat_box (widget->style, frame, GTK_STATE_NORMAL,
605 GTK_SHADOW_NONE, area, widget, "base",
607 width, DECORATION_BORDER_TOP);
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);
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);
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);
626 border_state = GTK_STATE_SELECTED;
628 border_state = GTK_STATE_PRELIGHT;
630 gtk_paint_box (widget->style, frame, border_state,
631 GTK_SHADOW_OUT, area, widget, "base",
632 0, 0, width, height);
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);
640 if (deco->maximizable)
642 /* Maximize button: */
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;
650 gdk_gc_set_clip_rectangle (widget->style->bg_gc[widget->state], area);
652 gdk_draw_rectangle (frame, widget->style->bg_gc[widget->state], TRUE,
653 x1, y1, x2 - x1, y2 - y1);
655 gdk_draw_line (frame, widget->style->black_gc, x1 + 1, y1 + 1, x2 - 2, y1 + 1);
657 gdk_draw_rectangle (frame, widget->style->black_gc, FALSE,
659 DECORATION_BUTTON_SIZE - 3, DECORATION_BUTTON_SIZE - 4);
662 gdk_gc_set_clip_rectangle (widget->style->black_gc, NULL);
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;
673 gdk_gc_set_clip_rectangle (widget->style->bg_gc[widget->state], area);
675 gdk_draw_rectangle (frame, widget->style->bg_gc[widget->state], TRUE,
676 x1, y1, x2 - x1, y2 - y1);
679 gdk_gc_set_clip_rectangle (widget->style->bg_gc[widget->state], NULL);
682 gdk_gc_set_clip_rectangle (widget->style->black_gc, area);
684 gdk_draw_line (frame, widget->style->black_gc, x1, y1, x2-1, y2-1);
686 gdk_draw_line (frame, widget->style->black_gc, x1, y2-1, x2-1, y1);
689 gdk_gc_set_clip_rectangle (widget->style->black_gc, NULL);
694 if (deco->title_layout)
697 gdk_gc_set_clip_rectangle (widget->style->fg_gc [border_state], area);
699 gdk_draw_layout (frame,
700 widget->style->fg_gc [border_state],
701 DECORATION_BORDER_LEFT, 1,
704 gdk_gc_set_clip_rectangle (widget->style->fg_gc [border_state], NULL);
712 gtk_decorated_window_recalculate_regions (GtkWindow *window)
716 GtkWindowRegion *region;
717 GtkWindowDecoration *deco = get_decoration (window);
721 if (!deco->decorated)
724 n_regions += 2; /* close, Title */
725 if (deco->maximizable)
727 if (window->allow_shrink || window->allow_grow)
730 if (deco->n_regions != n_regions)
732 g_free (deco->regions);
733 deco->regions = g_new (GtkWindowRegion, n_regions);
734 deco->n_regions = n_regions;
737 width = GTK_WIDGET (window)->allocation.width + DECORATION_BORDER_TOT_X;
738 height = GTK_WIDGET (window)->allocation.height + DECORATION_BORDER_TOT_Y;
740 region = deco->regions;
742 /* Maximize button */
743 if (deco->maximizable)
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;
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;
764 region->rect.width = width;
765 region->rect.height = DECORATION_BORDER_TOP;
766 region->type = GTK_WINDOW_REGION_TITLE;
769 if (window->allow_shrink || window->allow_grow)
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;
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;
788 gtk_decorated_window_move_resize_window (GtkWindow *window,
794 GtkWidget *widget = GTK_WIDGET (window);
795 GtkWindowDecoration *deco = get_decoration (window);
797 deco->real_inner_move = TRUE;
798 gdk_window_move_resize (widget->window,
799 x, y, width, height);
804 gtk_decorated_window_init (GtkWindow *window)
809 gtk_decorated_window_calculate_frame_size (GtkWindow *window)
814 gtk_decorated_window_set_title (GtkWindow *window,
820 gtk_decorated_window_move_resize_window (GtkWindow *window,
826 gdk_window_move_resize (GTK_WIDGET (window)->window,
827 x, y, width, height);