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>
24 #include "gtkprivate.h"
25 #include "gtksignal.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_CLOSE,
41 GTK_WINDOW_REGION_BR_RESIZE
42 } GtkWindowRegionType;
44 typedef struct _GtkWindowRegion GtkWindowRegion;
45 typedef struct _GtkWindowDecoration GtkWindowDecoration;
47 struct _GtkWindowRegion
50 GtkWindowRegionType type;
64 } GtkWindowResizeType;
66 struct _GtkWindowDecoration
69 GtkWindowRegion *regions;
73 PangoLayout *title_layout;
75 GtkWindowResizeType resize;
79 gboolean decorated : 1;
80 gboolean real_inner_move : 1;
84 #define DECORATION_BORDER_TOP 15
85 #define DECORATION_BORDER_LEFT 3
86 #define DECORATION_BORDER_RIGHT 3
87 #define DECORATION_BORDER_BOTTOM 3
88 #define DECORATION_BORDER_TOT_X (DECORATION_BORDER_LEFT + DECORATION_BORDER_RIGHT)
89 #define DECORATION_BORDER_TOT_Y (DECORATION_BORDER_TOP + DECORATION_BORDER_BOTTOM)
90 #define DECORATION_BUTTON_SIZE 9
91 #define DECORATION_BUTTON_Y_OFFSET 2
92 #define DECORATION_TITLE_FONT "Sans 9"
94 static void gtk_decorated_window_recalculate_regions (GtkWindow *window);
95 static GtkWindowRegionType gtk_decorated_window_region_type (GtkWindow *window,
98 static gint gtk_decorated_window_frame_event (GtkWidget *widget,
100 static gint gtk_decorated_window_button_press (GtkWidget *widget,
101 GdkEventButton *event);
102 static gint gtk_decorated_window_button_release (GtkWidget *widget,
103 GdkEventButton *event);
104 static gint gtk_decorated_window_motion_notify (GtkWidget *widget,
105 GdkEventMotion *event);
106 static void gtk_decorated_window_paint (GtkWidget *widget,
108 static gint gtk_decorated_window_focus_change (GtkWidget *widget,
109 GdkEventFocus *event);
110 static void gtk_decorated_window_realize (GtkWindow *window);
111 static void gtk_decorated_window_unrealize (GtkWindow *window);
114 gtk_decoration_free (GtkWindowDecoration *deco)
116 g_free (deco->regions);
117 deco->regions = NULL;
124 gtk_decorated_window_init (GtkWindow *window)
126 GtkWindowDecoration *deco;
128 deco = g_new (GtkWindowDecoration, 1);
131 deco->regions = NULL;
132 deco->title_layout = NULL;
133 deco->resize = RESIZE_NONE;
134 deco->moving = FALSE;
135 deco->decorated = TRUE;
136 deco->closing = FALSE;
137 deco->real_inner_move = FALSE;
139 g_object_set_data_full (G_OBJECT (window), "gtk-window-decoration", deco,
140 (GDestroyNotify) gtk_decoration_free);
142 gtk_window_set_has_frame (window, TRUE);
144 gtk_signal_connect (GTK_OBJECT (window),
146 GTK_SIGNAL_FUNC (gtk_decorated_window_frame_event),
148 gtk_signal_connect (GTK_OBJECT (window),
150 GTK_SIGNAL_FUNC (gtk_decorated_window_focus_change),
152 gtk_signal_connect (GTK_OBJECT (window),
154 GTK_SIGNAL_FUNC (gtk_decorated_window_focus_change),
156 gtk_signal_connect (GTK_OBJECT (window),
158 GTK_SIGNAL_FUNC (gtk_decorated_window_realize),
160 gtk_signal_connect (GTK_OBJECT (window),
162 GTK_SIGNAL_FUNC (gtk_decorated_window_unrealize),
166 static inline GtkWindowDecoration *
167 get_decoration (GtkWindow *window)
169 return (GtkWindowDecoration *)g_object_get_data (G_OBJECT (window), "gtk-window-decoration");
173 gtk_decorated_window_set_title (GtkWindow *window,
176 GtkWindowDecoration *deco = get_decoration (window);
178 if (deco->title_layout)
179 pango_layout_set_text (deco->title_layout, title, -1);
183 gtk_decorated_window_calculate_frame_size (GtkWindow *window)
185 GdkWMDecoration decorations;
186 GtkWindowDecoration *deco = get_decoration (window);
188 if (gdk_window_get_decorations (GTK_WIDGET (window)->window,
191 if ((decorations & GDK_DECOR_BORDER) &&
192 (decorations & GDK_DECOR_TITLE))
193 deco->decorated = TRUE;
195 deco->decorated = FALSE;
198 deco->decorated = (window->type != GTK_WINDOW_POPUP);
201 gtk_window_set_frame_dimensions (window,
202 DECORATION_BORDER_LEFT,
203 DECORATION_BORDER_TOP,
204 DECORATION_BORDER_RIGHT,
205 DECORATION_BORDER_BOTTOM);
207 gtk_window_set_frame_dimensions (window, 0, 0, 0, 0);
209 gtk_decorated_window_recalculate_regions (window);
213 gtk_decorated_window_inner_change (GdkWindow *win,
215 gint width, gint height,
218 GtkWindow *window = (GtkWindow *)user_data;
219 GtkWidget *widget = GTK_WIDGET (window);
220 GtkWindowDecoration *deco = get_decoration (window);
222 if (deco->real_inner_move)
224 deco->real_inner_move = FALSE;
228 deco->real_inner_move = TRUE;
229 gdk_window_move_resize (widget->window,
230 window->frame_left, window->frame_top,
233 gdk_window_move_resize (window->frame,
234 x - window->frame_left, y - window->frame_top,
235 width + window->frame_left + window->frame_right,
236 height + window->frame_top + window->frame_bottom);
241 gtk_decorated_window_inner_get_pos (GdkWindow *win,
245 GtkWindow *window = (GtkWindow *)user_data;
247 gdk_window_get_position (window->frame, x, y);
249 *x += window->frame_left;
250 *y += window->frame_top;
254 gtk_decorated_window_realize (GtkWindow *window)
256 GtkWindowDecoration *deco = get_decoration (window);
257 GtkWidget *widget = GTK_WIDGET (window);
258 PangoFontDescription *font_desc;
260 deco->title_layout = gtk_widget_create_pango_layout (widget,
261 (window->title)?window->title:"");
263 font_desc = pango_font_description_from_string(DECORATION_TITLE_FONT);
264 pango_layout_set_font_description (deco->title_layout, font_desc);
265 pango_font_description_free (font_desc);
267 gdk_fb_window_set_child_handler (window->frame,
268 gtk_decorated_window_inner_change,
269 gtk_decorated_window_inner_get_pos,
272 /* This is a huge hack to make frames have the same shape as
273 the window they wrap */
274 gdk_window_shape_combine_mask (window->frame, GDK_FB_USE_CHILD_SHAPE, 0, 0);
279 gtk_decorated_window_unrealize (GtkWindow *window)
281 GtkWindowDecoration *deco = get_decoration (window);
283 if (deco->title_layout)
285 g_object_unref (G_OBJECT (deco->title_layout));
286 deco->title_layout = NULL;
291 gtk_decorated_window_frame_event (GtkWidget *widget, GdkEvent *event)
293 GtkWindowDecoration *deco = get_decoration (GTK_WINDOW (widget));
294 GdkEventExpose *expose_event;
299 expose_event = (GdkEventExpose *)event;
301 gtk_decorated_window_paint (widget, &expose_event->area);
305 gtk_decorated_window_recalculate_regions (GTK_WINDOW (widget));
307 case GDK_MOTION_NOTIFY:
308 return gtk_decorated_window_motion_notify (widget, (GdkEventMotion *)event);
310 case GDK_BUTTON_PRESS:
311 return gtk_decorated_window_button_press (widget, (GdkEventButton *)event);
313 case GDK_BUTTON_RELEASE:
314 return gtk_decorated_window_button_release (widget, (GdkEventButton *)event);
322 gtk_decorated_window_focus_change (GtkWidget *widget,
323 GdkEventFocus *event)
325 GtkWindow *window = GTK_WINDOW(widget);
326 GtkWindowDecoration *deco = get_decoration (window);
327 deco->focused = event->in;
328 gdk_window_invalidate_rect (window->frame, NULL, FALSE);
333 gtk_decorated_window_motion_notify (GtkWidget *widget,
334 GdkEventMotion *event)
337 GtkWindowDecoration *deco;
338 GdkModifierType mask;
341 gint win_x, win_y, win_w, win_h;
343 window = GTK_WINDOW (widget);
344 deco = get_decoration (window);
346 if (!deco->decorated)
349 win = widget->window;
350 gdk_window_get_pointer (window->frame, &x, &y, &mask);
352 gdk_window_get_position (window->frame, &win_x, &win_y);
353 win_x += DECORATION_BORDER_LEFT;
354 win_y += DECORATION_BORDER_TOP;
356 gdk_window_get_geometry (win, NULL, NULL, &win_w, &win_h, NULL);
361 dx = x - deco->last_x;
362 dy = y - deco->last_y;
364 _gtk_window_reposition (window, win_x + dx, win_y + dy);
367 if (deco->resize != RESIZE_NONE)
374 switch(deco->resize) {
375 case RESIZE_BOTTOM_RIGHT:
376 w = x - DECORATION_BORDER_TOT_X;
377 h = y - DECORATION_BORDER_TOT_Y;
380 w = x - DECORATION_BORDER_TOT_X;
383 h = y - DECORATION_BORDER_TOT_Y;
385 case RESIZE_TOP_LEFT:
387 case RESIZE_TOP_RIGHT:
388 case RESIZE_BOTTOM_LEFT:
391 g_warning ("Resize mode %d not handled yet.\n", deco->resize);
395 if ((w > 0) && (h > 0))
397 _gtk_window_constrain_size (window, w,h, &w, &h);
399 if ((w != win_w) || (h != win_h))
400 gdk_window_resize (widget->window, w, h);
407 static GtkWindowRegionType
408 gtk_decorated_window_region_type (GtkWindow *window, gint x, gint y)
410 GtkWindowDecoration *deco = get_decoration (window);
413 for (i=0;i<deco->n_regions;i++)
415 if ((x > deco->regions[i].rect.x) &&
416 (x - deco->regions[i].rect.x < deco->regions[i].rect.width) &&
417 (y > deco->regions[i].rect.y) &&
418 (y - deco->regions[i].rect.y < deco->regions[i].rect.height))
419 return deco->regions[i].type;
425 gtk_decorated_window_button_press (GtkWidget *widget,
426 GdkEventButton *event)
429 GtkWindowRegionType type;
430 GtkWindowDecoration *deco;
433 window = GTK_WINDOW (widget);
434 deco = get_decoration (window);
436 if (!deco->decorated)
442 type = gtk_decorated_window_region_type (window, x, y);
449 case GTK_WINDOW_REGION_TITLE:
450 if (event->state & GDK_BUTTON1_MASK)
453 case GTK_WINDOW_REGION_CLOSE:
454 if (event->state & GDK_BUTTON1_MASK)
455 deco->closing = TRUE;
457 case GTK_WINDOW_REGION_BR_RESIZE:
458 if (event->state & GDK_BUTTON1_MASK)
459 deco->resize = RESIZE_BOTTOM_RIGHT;
469 gtk_decorated_window_button_release (GtkWidget *widget,
470 GdkEventButton *event)
473 GtkWindowRegionType type;
474 GtkWindowDecoration *deco;
476 window = GTK_WINDOW (widget);
477 deco = get_decoration (window);
481 type = gtk_decorated_window_region_type (window, event->x, event->y);
482 if (type == GTK_WINDOW_REGION_CLOSE)
486 event.type = GDK_DELETE;
487 event.window = widget->window;
488 event.send_event = TRUE;
490 /* Synthesize delete_event */
491 g_object_ref (G_OBJECT (event.window));
493 gtk_main_do_event ((GdkEvent*)&event);
495 g_object_unref (G_OBJECT (event.window));
499 deco->closing = FALSE;
500 deco->moving = FALSE;
501 deco->resize = RESIZE_NONE;
506 gtk_decorated_window_paint (GtkWidget *widget,
509 GtkWindow *window = GTK_WINDOW (widget);
510 GtkWindowDecoration *deco = get_decoration (window);
512 GtkStateType border_state;
519 frame = window->frame;
520 gdk_window_get_size (frame, &width, &height);
523 gtk_paint_flat_box (widget->style, frame, GTK_STATE_NORMAL,
524 GTK_SHADOW_NONE, area, widget, "base",
526 width, DECORATION_BORDER_TOP);
528 gtk_paint_flat_box (widget->style, frame, GTK_STATE_NORMAL,
529 GTK_SHADOW_NONE, area, widget, "base",
530 0, height - DECORATION_BORDER_BOTTOM,
531 width, DECORATION_BORDER_BOTTOM);
533 gtk_paint_flat_box (widget->style, frame, GTK_STATE_NORMAL,
534 GTK_SHADOW_NONE, area, widget, "base",
535 0, DECORATION_BORDER_TOP,
536 DECORATION_BORDER_LEFT, height - DECORATION_BORDER_TOT_Y);
538 gtk_paint_flat_box (widget->style, frame, GTK_STATE_NORMAL,
539 GTK_SHADOW_NONE, area, widget, "base",
540 width - DECORATION_BORDER_RIGHT, DECORATION_BORDER_TOP,
541 DECORATION_BORDER_RIGHT, height - DECORATION_BORDER_TOT_Y);
545 border_state = GTK_STATE_SELECTED;
547 border_state = GTK_STATE_PRELIGHT;
549 gtk_paint_box (widget->style, frame, border_state,
550 GTK_SHADOW_OUT, area, widget, "base",
551 0, 0, width, height);
553 gtk_paint_box (widget->style, frame, border_state,
554 GTK_SHADOW_IN, area, widget, "base",
555 DECORATION_BORDER_LEFT - 2, DECORATION_BORDER_TOP - 2,
556 width - (DECORATION_BORDER_LEFT + DECORATION_BORDER_RIGHT) + 3,
557 height - (DECORATION_BORDER_TOP + DECORATION_BORDER_BOTTOM) + 3);
561 x1 = width - DECORATION_BORDER_LEFT - DECORATION_BUTTON_SIZE;
562 y1 = DECORATION_BUTTON_Y_OFFSET;
563 x2 = width - DECORATION_BORDER_LEFT;
564 y2 = DECORATION_BUTTON_Y_OFFSET + DECORATION_BUTTON_SIZE;
567 gdk_gc_set_clip_rectangle (widget->style->bg_gc[widget->state], area);
569 gdk_draw_rectangle (frame, widget->style->bg_gc[widget->state], TRUE,
570 x1, y1, x2 - x1, y2 - y1);
573 gdk_gc_set_clip_rectangle (widget->style->bg_gc[widget->state], NULL);
576 gdk_gc_set_clip_rectangle (widget->style->black_gc, area);
578 gdk_draw_line (frame, widget->style->black_gc, x1, y1, x2-1, y2-1);
580 gdk_draw_line (frame, widget->style->black_gc, x1, y2-1, x2-1, y1);
583 gdk_gc_set_clip_rectangle (widget->style->black_gc, NULL);
588 if (deco->title_layout)
591 gdk_gc_set_clip_rectangle (widget->style->fg_gc [widget->state], area);
593 gdk_draw_layout (frame,
594 widget->style->fg_gc [widget->state],
595 DECORATION_BORDER_LEFT, 1,
598 gdk_gc_set_clip_rectangle (widget->style->fg_gc [widget->state], NULL);
606 gtk_decorated_window_recalculate_regions (GtkWindow *window)
610 GtkWindowRegion *region;
611 GtkWindowDecoration *deco = get_decoration (window);
615 if (!deco->decorated)
618 n_regions += 2; /* close, Title */
619 if (window->allow_shrink || window->allow_grow)
622 if (deco->n_regions != n_regions)
624 g_free (deco->regions);
625 deco->regions = g_new (GtkWindowRegion, n_regions);
626 deco->n_regions = n_regions;
629 width = GTK_WIDGET (window)->allocation.width + DECORATION_BORDER_TOT_X;
630 height = GTK_WIDGET (window)->allocation.height + DECORATION_BORDER_TOT_Y;
632 region = deco->regions;
635 region->rect.x = width - DECORATION_BORDER_LEFT - DECORATION_BUTTON_SIZE;
637 region->rect.width = DECORATION_BUTTON_SIZE;
638 region->rect.height = DECORATION_BUTTON_SIZE;
639 region->type = GTK_WINDOW_REGION_CLOSE;
645 region->rect.width = width;
646 region->rect.height = DECORATION_BORDER_TOP;
647 region->type = GTK_WINDOW_REGION_TITLE;
650 if (window->allow_shrink || window->allow_grow)
652 region->rect.x = width - (DECORATION_BORDER_RIGHT + 10);
653 region->rect.y = height - DECORATION_BORDER_BOTTOM;
654 region->rect.width = DECORATION_BORDER_RIGHT + 10;
655 region->rect.height = DECORATION_BORDER_BOTTOM;
656 region->type = GTK_WINDOW_REGION_BR_RESIZE;
659 region->rect.x = width - DECORATION_BORDER_RIGHT;
660 region->rect.y = height - (DECORATION_BORDER_BOTTOM + 10);
661 region->rect.width = DECORATION_BORDER_RIGHT;
662 region->rect.height = DECORATION_BORDER_BOTTOM + 10;
663 region->type = GTK_WINDOW_REGION_BR_RESIZE;
669 gtk_decorated_window_move_resize_window (GtkWindow *window,
675 GtkWidget *widget = GTK_WIDGET (window);
676 GtkWindowDecoration *deco = get_decoration (window);
678 deco->real_inner_move = TRUE;
679 gdk_window_move_resize (widget->window,
680 x, y, width, height);
685 gtk_decorated_window_init (GtkWindow *window)
690 gtk_decorated_window_calculate_frame_size (GtkWindow *window)
695 gtk_decorated_window_set_title (GtkWindow *window,
701 gtk_decorated_window_move_resize_window (GtkWindow *window,
707 gdk_window_move_resize (GTK_WIDGET (window)->window,
708 x, y, width, height);