diff --git a/ChangeLog b/ChangeLog index a47e7ece91a7351bb47896856c46808ece79f358..df7121f59d59f465b716a11725be408fc4d5ee43 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,23 @@ +2001-01-08 Alexander Larsson + + * gtk/gtkwindow-decorate.[hc]: + * gtk/Makefile.am: + New files. Contains an implementation of a minimal WM for + linux-fb. + + * gtk/gtkwindow.h: + Add the possibility for GtkWindows to specify a frame. This + is used for the window decoration code, but could concievably + be used for X programs too (xmms style windows). + GtkWindow->frame is the toplevel window if the window is framed. + The signal frame_event gets all events that are targeted to + GtkWindow->frame. + (_gtk_window_constrain_size): Exported for usage by gtkwindow-decorate.c. + + * gtk/gtkwindow.c: + Implement gtk_window_set_has_frame and gtk_window_set_frame_dimensions. + Call out to gtkwindow-decorate.c for WM support in linx-fb. + 2001-01-08 Alexander Larsson * docs/README.linux-fb: diff --git a/ChangeLog.pre-2-0 b/ChangeLog.pre-2-0 index a47e7ece91a7351bb47896856c46808ece79f358..df7121f59d59f465b716a11725be408fc4d5ee43 100644 --- a/ChangeLog.pre-2-0 +++ b/ChangeLog.pre-2-0 @@ -1,3 +1,23 @@ +2001-01-08 Alexander Larsson + + * gtk/gtkwindow-decorate.[hc]: + * gtk/Makefile.am: + New files. Contains an implementation of a minimal WM for + linux-fb. + + * gtk/gtkwindow.h: + Add the possibility for GtkWindows to specify a frame. This + is used for the window decoration code, but could concievably + be used for X programs too (xmms style windows). + GtkWindow->frame is the toplevel window if the window is framed. + The signal frame_event gets all events that are targeted to + GtkWindow->frame. + (_gtk_window_constrain_size): Exported for usage by gtkwindow-decorate.c. + + * gtk/gtkwindow.c: + Implement gtk_window_set_has_frame and gtk_window_set_frame_dimensions. + Call out to gtkwindow-decorate.c for WM support in linx-fb. + 2001-01-08 Alexander Larsson * docs/README.linux-fb: diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index a47e7ece91a7351bb47896856c46808ece79f358..df7121f59d59f465b716a11725be408fc4d5ee43 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,23 @@ +2001-01-08 Alexander Larsson + + * gtk/gtkwindow-decorate.[hc]: + * gtk/Makefile.am: + New files. Contains an implementation of a minimal WM for + linux-fb. + + * gtk/gtkwindow.h: + Add the possibility for GtkWindows to specify a frame. This + is used for the window decoration code, but could concievably + be used for X programs too (xmms style windows). + GtkWindow->frame is the toplevel window if the window is framed. + The signal frame_event gets all events that are targeted to + GtkWindow->frame. + (_gtk_window_constrain_size): Exported for usage by gtkwindow-decorate.c. + + * gtk/gtkwindow.c: + Implement gtk_window_set_has_frame and gtk_window_set_frame_dimensions. + Call out to gtkwindow-decorate.c for WM support in linx-fb. + 2001-01-08 Alexander Larsson * docs/README.linux-fb: diff --git a/ChangeLog.pre-2-2 b/ChangeLog.pre-2-2 index a47e7ece91a7351bb47896856c46808ece79f358..df7121f59d59f465b716a11725be408fc4d5ee43 100644 --- a/ChangeLog.pre-2-2 +++ b/ChangeLog.pre-2-2 @@ -1,3 +1,23 @@ +2001-01-08 Alexander Larsson + + * gtk/gtkwindow-decorate.[hc]: + * gtk/Makefile.am: + New files. Contains an implementation of a minimal WM for + linux-fb. + + * gtk/gtkwindow.h: + Add the possibility for GtkWindows to specify a frame. This + is used for the window decoration code, but could concievably + be used for X programs too (xmms style windows). + GtkWindow->frame is the toplevel window if the window is framed. + The signal frame_event gets all events that are targeted to + GtkWindow->frame. + (_gtk_window_constrain_size): Exported for usage by gtkwindow-decorate.c. + + * gtk/gtkwindow.c: + Implement gtk_window_set_has_frame and gtk_window_set_frame_dimensions. + Call out to gtkwindow-decorate.c for WM support in linx-fb. + 2001-01-08 Alexander Larsson * docs/README.linux-fb: diff --git a/ChangeLog.pre-2-4 b/ChangeLog.pre-2-4 index a47e7ece91a7351bb47896856c46808ece79f358..df7121f59d59f465b716a11725be408fc4d5ee43 100644 --- a/ChangeLog.pre-2-4 +++ b/ChangeLog.pre-2-4 @@ -1,3 +1,23 @@ +2001-01-08 Alexander Larsson + + * gtk/gtkwindow-decorate.[hc]: + * gtk/Makefile.am: + New files. Contains an implementation of a minimal WM for + linux-fb. + + * gtk/gtkwindow.h: + Add the possibility for GtkWindows to specify a frame. This + is used for the window decoration code, but could concievably + be used for X programs too (xmms style windows). + GtkWindow->frame is the toplevel window if the window is framed. + The signal frame_event gets all events that are targeted to + GtkWindow->frame. + (_gtk_window_constrain_size): Exported for usage by gtkwindow-decorate.c. + + * gtk/gtkwindow.c: + Implement gtk_window_set_has_frame and gtk_window_set_frame_dimensions. + Call out to gtkwindow-decorate.c for WM support in linx-fb. + 2001-01-08 Alexander Larsson * docs/README.linux-fb: diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6 index a47e7ece91a7351bb47896856c46808ece79f358..df7121f59d59f465b716a11725be408fc4d5ee43 100644 --- a/ChangeLog.pre-2-6 +++ b/ChangeLog.pre-2-6 @@ -1,3 +1,23 @@ +2001-01-08 Alexander Larsson + + * gtk/gtkwindow-decorate.[hc]: + * gtk/Makefile.am: + New files. Contains an implementation of a minimal WM for + linux-fb. + + * gtk/gtkwindow.h: + Add the possibility for GtkWindows to specify a frame. This + is used for the window decoration code, but could concievably + be used for X programs too (xmms style windows). + GtkWindow->frame is the toplevel window if the window is framed. + The signal frame_event gets all events that are targeted to + GtkWindow->frame. + (_gtk_window_constrain_size): Exported for usage by gtkwindow-decorate.c. + + * gtk/gtkwindow.c: + Implement gtk_window_set_has_frame and gtk_window_set_frame_dimensions. + Call out to gtkwindow-decorate.c for WM support in linx-fb. + 2001-01-08 Alexander Larsson * docs/README.linux-fb: diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 index a47e7ece91a7351bb47896856c46808ece79f358..df7121f59d59f465b716a11725be408fc4d5ee43 100644 --- a/ChangeLog.pre-2-8 +++ b/ChangeLog.pre-2-8 @@ -1,3 +1,23 @@ +2001-01-08 Alexander Larsson + + * gtk/gtkwindow-decorate.[hc]: + * gtk/Makefile.am: + New files. Contains an implementation of a minimal WM for + linux-fb. + + * gtk/gtkwindow.h: + Add the possibility for GtkWindows to specify a frame. This + is used for the window decoration code, but could concievably + be used for X programs too (xmms style windows). + GtkWindow->frame is the toplevel window if the window is framed. + The signal frame_event gets all events that are targeted to + GtkWindow->frame. + (_gtk_window_constrain_size): Exported for usage by gtkwindow-decorate.c. + + * gtk/gtkwindow.c: + Implement gtk_window_set_has_frame and gtk_window_set_frame_dimensions. + Call out to gtkwindow-decorate.c for WM support in linx-fb. + 2001-01-08 Alexander Larsson * docs/README.linux-fb: diff --git a/gtk/Makefile.am b/gtk/Makefile.am index 591121392ffb7706be5c8a9937cf428c8760b91c..b8d296f9976d4059b125d126cdf82c2b418f47af 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -204,6 +204,7 @@ gtk_private_h_sources = @STRIP_BEGIN@ \ gtkthemes.h \ gtktreedatalist.h \ gtktreeprivate.h \ + gtkwindow-decorate.h \ @STRIP_END@ # GTK+ C sources to build the library from gtk_c_sources = @STRIP_BEGIN@ \ @@ -353,6 +354,7 @@ gtk_c_sources = @STRIP_BEGIN@ \ gtkvseparator.c \ gtkwidget.c \ gtkwindow.c \ + gtkwindow-decorate.c \ fnmatch.c \ fnmatch.h \ gdk-pixbuf-loader.c \ diff --git a/gtk/gtkwindow-decorate.c b/gtk/gtkwindow-decorate.c new file mode 100644 index 0000000000000000000000000000000000000000..d864e1509222a6d483af96520a6773f386b9dee2 --- /dev/null +++ b/gtk/gtkwindow-decorate.c @@ -0,0 +1,706 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 2001 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Authors: Alexander Larsson + */ + +#include "gtkprivate.h" +#include "gtksignal.h" +#include "gtkwindow.h" +#include "gtkmain.h" + + +#ifdef GDK_WINDOWING_FB +#define DECORATE_WINDOWS +#endif + +#ifdef DECORATE_WINDOWS +#include "linux-fb/gdkfb.h" + +typedef enum +{ + GTK_WINDOW_REGION_TITLE, + GTK_WINDOW_REGION_CLOSE, + GTK_WINDOW_REGION_BR_RESIZE +} GtkWindowRegionType; + +typedef struct _GtkWindowRegion GtkWindowRegion; +typedef struct _GtkWindowDecoration GtkWindowDecoration; + +struct _GtkWindowRegion +{ + GdkRectangle rect; + GtkWindowRegionType type; +}; + +typedef enum +{ + RESIZE_TOP_LEFT, + RESIZE_TOP, + RESIZE_TOP_RIGHT, + RESIZE_RIGHT, + RESIZE_BOTTOM_RIGHT, + RESIZE_BOTTOM, + RESIZE_BOTTOM_LEFT, + RESIZE_LEFT, + RESIZE_NONE, +} GtkWindowResizeType; + +struct _GtkWindowDecoration +{ + gint n_regions; + GtkWindowRegion *regions; + + gint last_x, last_y; + + PangoLayout *title_layout; + + GtkWindowResizeType resize; + + gboolean moving : 1; + gboolean closing : 1; + gboolean decorated : 1; + gboolean real_inner_move : 1; + gboolean focused : 1; +}; + +#define DECORATION_BORDER_TOP 15 +#define DECORATION_BORDER_LEFT 3 +#define DECORATION_BORDER_RIGHT 3 +#define DECORATION_BORDER_BOTTOM 3 +#define DECORATION_BORDER_TOT_X (DECORATION_BORDER_LEFT + DECORATION_BORDER_RIGHT) +#define DECORATION_BORDER_TOT_Y (DECORATION_BORDER_TOP + DECORATION_BORDER_BOTTOM) +#define DECORATION_BUTTON_SIZE 9 +#define DECORATION_BUTTON_Y_OFFSET 2 +#define DECORATION_TITLE_FONT "Sans 9" + +static void gtk_decorated_window_recalculate_regions (GtkWindow *window); +static GtkWindowRegionType gtk_decorated_window_region_type (GtkWindow *window, + gint x, + gint y); +static gint gtk_decorated_window_frame_event (GtkWidget *widget, + GdkEvent *event); +static gint gtk_decorated_window_button_press (GtkWidget *widget, + GdkEventButton *event); +static gint gtk_decorated_window_button_release (GtkWidget *widget, + GdkEventButton *event); +static gint gtk_decorated_window_motion_notify (GtkWidget *widget, + GdkEventMotion *event); +static void gtk_decorated_window_paint (GtkWidget *widget, + GdkRectangle *area); +static gint gtk_decorated_window_focus_change (GtkWidget *widget, + GdkEventFocus *event); +static void gtk_decorated_window_realize (GtkWindow *window); +static void gtk_decorated_window_unrealize (GtkWindow *window); + +static void +gtk_decoration_free (GtkWindowDecoration *deco) +{ + g_free (deco->regions); + deco->regions = NULL; + deco->n_regions = 0; + + g_free (deco); +} + +void +gtk_decorated_window_init (GtkWindow *window) +{ + GtkWindowDecoration *deco; + + deco = g_new (GtkWindowDecoration, 1); + + deco->n_regions = 0; + deco->regions = NULL; + deco->title_layout = NULL; + deco->resize = RESIZE_NONE; + deco->moving = FALSE; + deco->decorated = TRUE; + deco->closing = FALSE; + deco->real_inner_move = FALSE; + + g_object_set_data_full (G_OBJECT (window), "gtk-window-decoration", deco, + (GDestroyNotify) gtk_decoration_free); + + gtk_window_set_has_frame (window); + + gtk_signal_connect (GTK_OBJECT (window), + "frame_event", + GTK_SIGNAL_FUNC (gtk_decorated_window_frame_event), + window); + gtk_signal_connect (GTK_OBJECT (window), + "focus_in_event", + GTK_SIGNAL_FUNC (gtk_decorated_window_focus_change), + window); + gtk_signal_connect (GTK_OBJECT (window), + "focus_out_event", + GTK_SIGNAL_FUNC (gtk_decorated_window_focus_change), + window); + gtk_signal_connect (GTK_OBJECT (window), + "realize", + GTK_SIGNAL_FUNC (gtk_decorated_window_realize), + window); + gtk_signal_connect (GTK_OBJECT (window), + "unrealize", + GTK_SIGNAL_FUNC (gtk_decorated_window_unrealize), + window); +} + +static inline GtkWindowDecoration * +get_decoration (GtkWindow *window) +{ + return (GtkWindowDecoration *)g_object_get_data (G_OBJECT (window), "gtk-window-decoration"); +} + +void +gtk_decorated_window_set_title (GtkWindow *window, + const gchar *title) +{ + GtkWindowDecoration *deco = get_decoration (window); + + if (deco->title_layout) + pango_layout_set_text (deco->title_layout, title, -1); +} + +void +gtk_decorated_window_calculate_frame_size (GtkWindow *window) +{ + GdkWMDecoration decorations; + GtkWindowDecoration *deco = get_decoration (window); + + if (gdk_window_get_decorations (GTK_WIDGET (window)->window, + &decorations)) + { + if ((decorations & GDK_DECOR_BORDER) && + (decorations & GDK_DECOR_TITLE)) + deco->decorated = TRUE; + else + deco->decorated = FALSE; + } + else + deco->decorated = (window->type != GTK_WINDOW_POPUP); + + if (deco->decorated) + gtk_window_set_frame_dimensions (window, + DECORATION_BORDER_LEFT, + DECORATION_BORDER_TOP, + DECORATION_BORDER_RIGHT, + DECORATION_BORDER_BOTTOM); + else + gtk_window_set_frame_dimensions (window, 0, 0, 0, 0); + + gtk_decorated_window_recalculate_regions (window); +} + +static gboolean +gtk_decorated_window_inner_change (GdkWindow *win, + gint x, gint y, + gint width, gint height, + gpointer user_data) +{ + GtkWindow *window = (GtkWindow *)user_data; + GtkWidget *widget = GTK_WIDGET (window); + GtkWindowDecoration *deco = get_decoration (window); + + if (deco->real_inner_move) + { + deco->real_inner_move = FALSE; + return FALSE; + } + + deco->real_inner_move = TRUE; + gdk_window_move_resize (widget->window, + window->frame_left, window->frame_top, + width, height); + + gdk_window_move_resize (window->frame, + x - window->frame_left, y - window->frame_top, + width + window->frame_left + window->frame_right, + height + window->frame_top + window->frame_bottom); + return TRUE; +} + +static void +gtk_decorated_window_inner_get_pos (GdkWindow *win, + gint *x, gint *y, + gpointer user_data) +{ + GtkWindow *window = (GtkWindow *)user_data; + + gdk_window_get_position (window->frame, x, y); + + *x += window->frame_left; + *y += window->frame_top; +} + +static void +gtk_decorated_window_realize (GtkWindow *window) +{ + GtkWindowDecoration *deco = get_decoration (window); + GtkWidget *widget = GTK_WIDGET (window); + + deco->title_layout = gtk_widget_create_pango_layout (widget, + (window->title)?window->title:""); + + pango_layout_set_font_description (deco->title_layout, + pango_font_description_from_string(DECORATION_TITLE_FONT)); + + gdk_fb_window_set_child_handler (window->frame, + gtk_decorated_window_inner_change, + gtk_decorated_window_inner_get_pos, + window); +} + +static void +gtk_decorated_window_unrealize (GtkWindow *window) +{ + GtkWindowDecoration *deco = get_decoration (window); + + if (deco->title_layout) + { + g_object_unref (G_OBJECT (deco->title_layout)); + deco->title_layout = NULL; + } +} + +static gint +gtk_decorated_window_frame_event (GtkWidget *widget, GdkEvent *event) +{ + GtkWindowDecoration *deco = get_decoration (GTK_WINDOW (widget)); + GdkEventExpose *expose_event; + + switch (event->type) + { + case GDK_EXPOSE: + expose_event = (GdkEventExpose *)event; + if (deco->decorated) + gtk_decorated_window_paint (widget, &expose_event->area); + return TRUE; + break; + case GDK_CONFIGURE: + gtk_decorated_window_recalculate_regions (GTK_WINDOW (widget)); + break; + case GDK_MOTION_NOTIFY: + return gtk_decorated_window_motion_notify (widget, (GdkEventMotion *)event); + break; + case GDK_BUTTON_PRESS: + return gtk_decorated_window_button_press (widget, (GdkEventButton *)event); + break; + case GDK_BUTTON_RELEASE: + return gtk_decorated_window_button_release (widget, (GdkEventButton *)event); + default: + break; + } + return FALSE; +} + +static gint +gtk_decorated_window_focus_change (GtkWidget *widget, + GdkEventFocus *event) +{ + GtkWindow *window = GTK_WINDOW(widget); + GtkWindowDecoration *deco = get_decoration (window); + deco->focused = event->in; + gdk_window_invalidate_rect (window->frame, NULL, FALSE); + return TRUE; +} + +static gint +gtk_decorated_window_motion_notify (GtkWidget *widget, + GdkEventMotion *event) +{ + GtkWindow *window; + GtkWindowDecoration *deco; + GdkModifierType mask; + GdkWindow *win; + gint x, y; + gint win_x, win_y, win_w, win_h; + + window = GTK_WINDOW (widget); + deco = get_decoration (window); + + if (!deco->decorated) + return TRUE; + + win = widget->window; + gdk_window_get_pointer (window->frame, &x, &y, &mask); + + gdk_window_get_position (window->frame, &win_x, &win_y); + win_x += DECORATION_BORDER_LEFT; + win_y += DECORATION_BORDER_TOP; + + gdk_window_get_geometry (win, NULL, NULL, &win_w, &win_h, NULL); + + if (deco->moving) + { + int dx, dy; + dx = x - deco->last_x; + dy = y - deco->last_y; + + gtk_window_reposition (window, win_x + dx, win_y + dy); + } + + if (deco->resize != RESIZE_NONE) + { + int w, h; + + w = win_w; + h = win_h; + + switch(deco->resize) { + case RESIZE_BOTTOM_RIGHT: + w = x - DECORATION_BORDER_TOT_X; + h = y - DECORATION_BORDER_TOT_Y; + break; + case RESIZE_RIGHT: + w = x - DECORATION_BORDER_TOT_X; + break; + case RESIZE_BOTTOM: + h = y - DECORATION_BORDER_TOT_Y; + break; + case RESIZE_TOP_LEFT: + case RESIZE_TOP: + case RESIZE_TOP_RIGHT: + case RESIZE_BOTTOM_LEFT: + case RESIZE_LEFT: + default: + g_warning ("Resize mode %d not handled yet.\n", deco->resize); + break; + } + + if ((w > 0) && (h > 0)) + { + _gtk_window_constrain_size (window, w,h, &w, &h); + + if ((w != win_w) || (h != win_h)) + gdk_window_resize (widget->window, w, h); + } + } + + return TRUE; +} + +static GtkWindowRegionType +gtk_decorated_window_region_type (GtkWindow *window, gint x, gint y) +{ + GtkWindowDecoration *deco = get_decoration (window); + int i; + + for (i=0;in_regions;i++) + { + if ((x > deco->regions[i].rect.x) && + (x - deco->regions[i].rect.x < deco->regions[i].rect.width) && + (y > deco->regions[i].rect.y) && + (y - deco->regions[i].rect.y < deco->regions[i].rect.height)) + return deco->regions[i].type; + } + return -1; +} + +static gint +gtk_decorated_window_button_press (GtkWidget *widget, + GdkEventButton *event) +{ + GtkWindow *window; + GtkWindowRegionType type; + GtkWindowDecoration *deco; + gint x, y; + + window = GTK_WINDOW (widget); + deco = get_decoration (window); + + if (!deco->decorated) + return TRUE; + + x = event->x; + y = event->y; + + type = gtk_decorated_window_region_type (window, x, y); + + deco->last_x = x; + deco->last_y = y; + + switch (type) + { + case GTK_WINDOW_REGION_TITLE: + if (event->state & GDK_BUTTON1_MASK) + deco->moving = TRUE; + break; + case GTK_WINDOW_REGION_CLOSE: + if (event->state & GDK_BUTTON1_MASK) + deco->closing = TRUE; + break; + case GTK_WINDOW_REGION_BR_RESIZE: + if (event->state & GDK_BUTTON1_MASK) + deco->resize = RESIZE_BOTTOM_RIGHT; + break; + default: + break; + } + + return TRUE; +} + +static gint +gtk_decorated_window_button_release (GtkWidget *widget, + GdkEventButton *event) +{ + GtkWindow *window; + GtkWindowRegionType type; + GtkWindowDecoration *deco; + + window = GTK_WINDOW (widget); + deco = get_decoration (window); + + if (deco->closing) + { + type = gtk_decorated_window_region_type (window, event->x, event->y); + if (type == GTK_WINDOW_REGION_CLOSE) + { + GdkEventAny event; + + event.type = GDK_DELETE; + event.window = widget->window; + event.send_event = TRUE; + + /* Synthesize delete_event */ + g_object_ref (G_OBJECT (event.window)); + + gtk_main_do_event ((GdkEvent*)&event); + + g_object_unref (G_OBJECT (event.window)); + } + } + + deco->closing = FALSE; + deco->moving = FALSE; + deco->resize = RESIZE_NONE; + return TRUE; +} + +static void +gtk_decorated_window_paint (GtkWidget *widget, + GdkRectangle *area) +{ + GtkWindow *window = GTK_WINDOW (widget); + GtkWindowDecoration *deco = get_decoration (window); + gint x1, y1, x2, y2; + GtkStateType border_state; + + if (deco->decorated) + { + GdkWindow *frame; + gint width, height; + + frame = window->frame; + gdk_window_get_size (frame, &width, &height); + + /* Top */ + gtk_paint_flat_box (widget->style, frame, GTK_STATE_NORMAL, + GTK_SHADOW_NONE, area, widget, "base", + 0, 0, + width, DECORATION_BORDER_TOP); + /* Bottom */ + gtk_paint_flat_box (widget->style, frame, GTK_STATE_NORMAL, + GTK_SHADOW_NONE, area, widget, "base", + 0, height - DECORATION_BORDER_BOTTOM, + width, DECORATION_BORDER_BOTTOM); + /* Left */ + gtk_paint_flat_box (widget->style, frame, GTK_STATE_NORMAL, + GTK_SHADOW_NONE, area, widget, "base", + 0, DECORATION_BORDER_TOP, + DECORATION_BORDER_LEFT, height - DECORATION_BORDER_TOT_Y); + /* Right */ + gtk_paint_flat_box (widget->style, frame, GTK_STATE_NORMAL, + GTK_SHADOW_NONE, area, widget, "base", + width - DECORATION_BORDER_RIGHT, DECORATION_BORDER_TOP, + DECORATION_BORDER_RIGHT, height - DECORATION_BORDER_TOT_Y); + + /* Border: */ + if (deco->focused) + border_state = GTK_STATE_SELECTED; + else + border_state = GTK_STATE_PRELIGHT; + + gtk_paint_box (widget->style, frame, border_state, + GTK_SHADOW_OUT, area, widget, "base", + 0, 0, width, height); + + gtk_paint_box (widget->style, frame, border_state, + GTK_SHADOW_IN, area, widget, "base", + DECORATION_BORDER_LEFT - 2, DECORATION_BORDER_TOP - 2, + width - (DECORATION_BORDER_LEFT + DECORATION_BORDER_RIGHT) + 3, + height - (DECORATION_BORDER_TOP + DECORATION_BORDER_BOTTOM) + 3); + + /* Close button: */ + + x1 = width - DECORATION_BORDER_LEFT - DECORATION_BUTTON_SIZE; + y1 = DECORATION_BUTTON_Y_OFFSET; + x2 = width - DECORATION_BORDER_LEFT; + y2 = DECORATION_BUTTON_Y_OFFSET + DECORATION_BUTTON_SIZE; + + if (area) + gdk_gc_set_clip_rectangle (widget->style->bg_gc[widget->state], area); + + gdk_draw_rectangle (frame, widget->style->bg_gc[widget->state], TRUE, + x1, y1, x2 - x1, y2 - y1); + + if (area) + gdk_gc_set_clip_rectangle (widget->style->bg_gc[widget->state], NULL); + + if (area) + gdk_gc_set_clip_rectangle (widget->style->black_gc, area); + + gdk_draw_line (frame, widget->style->black_gc, x1, y1, x2-1, y2-1); + + gdk_draw_line (frame, widget->style->black_gc, x1, y2-1, x2-1, y1); + + if (area) + gdk_gc_set_clip_rectangle (widget->style->black_gc, NULL); + + + + /* Title */ + if (deco->title_layout) + { + if (area) + gdk_gc_set_clip_rectangle (widget->style->fg_gc [widget->state], area); + + gdk_draw_layout (frame, + widget->style->fg_gc [widget->state], + DECORATION_BORDER_LEFT, 1, + deco->title_layout); + if (area) + gdk_gc_set_clip_rectangle (widget->style->fg_gc [widget->state], NULL); + } + + } +} + + +static void +gtk_decorated_window_recalculate_regions (GtkWindow *window) +{ + gint n_regions; + gint width, height; + GtkWindowRegion *region; + GtkWindowDecoration *deco = get_decoration (window); + + n_regions = 0; + + if (!deco->decorated) + return; + + n_regions += 2; /* close, Title */ + if (window->allow_shrink || window->allow_grow) + n_regions += 2; + + if (deco->n_regions != n_regions) + { + g_free (deco->regions); + deco->regions = g_new (GtkWindowRegion, n_regions); + deco->n_regions = n_regions; + } + + width = GTK_WIDGET (window)->allocation.width + DECORATION_BORDER_TOT_X; + height = GTK_WIDGET (window)->allocation.height + DECORATION_BORDER_TOT_Y; + + region = deco->regions; + + /* Close button */ + region->rect.x = width - DECORATION_BORDER_LEFT - DECORATION_BUTTON_SIZE; + region->rect.y = 2; + region->rect.width = DECORATION_BUTTON_SIZE; + region->rect.height = DECORATION_BUTTON_SIZE; + region->type = GTK_WINDOW_REGION_CLOSE; + region++; + + /* title bar */ + region->rect.x = 0; + region->rect.y = 0; + region->rect.width = width; + region->rect.height = DECORATION_BORDER_TOP; + region->type = GTK_WINDOW_REGION_TITLE; + region++; + + if (window->allow_shrink || window->allow_grow) + { + region->rect.x = width - (DECORATION_BORDER_RIGHT + 10); + region->rect.y = height - DECORATION_BORDER_BOTTOM; + region->rect.width = DECORATION_BORDER_RIGHT + 10; + region->rect.height = DECORATION_BORDER_BOTTOM; + region->type = GTK_WINDOW_REGION_BR_RESIZE; + region++; + + region->rect.x = width - DECORATION_BORDER_RIGHT; + region->rect.y = height - (DECORATION_BORDER_BOTTOM + 10); + region->rect.width = DECORATION_BORDER_RIGHT; + region->rect.height = DECORATION_BORDER_BOTTOM + 10; + region->type = GTK_WINDOW_REGION_BR_RESIZE; + region++; + } +} + +void +gtk_decorated_window_move_resize_window (GtkWindow *window, + gint x, + gint y, + gint width, + gint height) +{ + GtkWidget *widget = GTK_WIDGET (window); + GtkWindowDecoration *deco = get_decoration (window); + + deco->real_inner_move = TRUE; + gdk_window_move_resize (GTK_WIDGET (window)->window, + x, y, width, height); +} +#else + +void +gtk_decorated_window_init (GtkWindow *window) +{ +} + +void +gtk_decorated_window_calculate_frame_size (GtkWindow *window) +{ +} + +void +gtk_decorated_window_set_title (GtkWindow *window, + const gchar *title) +{ +} + +void +gtk_decorated_window_move_resize_window (GtkWindow *window, + gint x, + gint y, + gint width, + gint height) +{ + gdk_window_move_resize (GTK_WIDGET (window)->window, + x, y, width, height); +} +#endif + + + diff --git a/gtk/gtkwindow-decorate.h b/gtk/gtkwindow-decorate.h new file mode 100644 index 0000000000000000000000000000000000000000..df07467a5cf753cdeafae1ad95cdfbc34dba21ce --- /dev/null +++ b/gtk/gtkwindow-decorate.h @@ -0,0 +1,32 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 2001 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Authors: Alexander Larsson + */ + +void gtk_decorated_window_init (GtkWindow *window); +void gtk_decorated_window_calculate_frame_size (GtkWindow *window); +void gtk_decorated_window_set_title (GtkWindow *window, + const gchar *title); +void gtk_decorated_window_move_resize_window (GtkWindow *window, + gint x, + gint y, + gint width, + gint height); diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c index 898748daece646b148551541296889ba8792e576..cfa5a3d2e1c853dd15e5c375adaa55cb05a62be3 100644 --- a/gtk/gtkwindow.c +++ b/gtk/gtkwindow.c @@ -43,6 +43,7 @@ #include "gtkrc.h" #include "gtksignal.h" #include "gtkwindow.h" +#include "gtkwindow-decorate.h" #include "gtkbindings.h" #include "gtkmain.h" #include "gtkiconfactory.h" @@ -54,8 +55,10 @@ enum { SET_FOCUS, + FRAME_EVENT, LAST_SIGNAL }; + enum { ARG_0, ARG_TYPE, @@ -105,10 +108,15 @@ static void gtk_window_hide (GtkWidget *widget); static void gtk_window_map (GtkWidget *widget); static void gtk_window_unmap (GtkWidget *widget); static void gtk_window_realize (GtkWidget *widget); +static void gtk_window_unrealize (GtkWidget *widget); static void gtk_window_size_request (GtkWidget *widget, GtkRequisition *requisition); static void gtk_window_size_allocate (GtkWidget *widget, GtkAllocation *allocation); +static gint gtk_window_event (GtkWidget *widget, + GdkEvent *event); +static gboolean gtk_window_frame_event (GtkWidget *widget, + GdkEvent *event); static gint gtk_window_configure_event (GtkWidget *widget, GdkEventConfigure *event); static gint gtk_window_key_press_event (GtkWidget *widget, @@ -171,6 +179,7 @@ static GtkWindowGeometryInfo* gtk_window_get_geometry_info (GtkWindow *window, gboolean create); static void gtk_window_geometry_destroy (GtkWindowGeometryInfo *info); + static GSList *toplevel_list = NULL; static GtkBinClass *parent_class = NULL; static guint window_signals[LAST_SIGNAL] = { 0 }; @@ -227,6 +236,7 @@ gtk_window_class_init (GtkWindowClass *klass) widget_class->map = gtk_window_map; widget_class->unmap = gtk_window_unmap; widget_class->realize = gtk_window_realize; + widget_class->unrealize = gtk_window_unrealize; widget_class->size_request = gtk_window_size_request; widget_class->size_allocate = gtk_window_size_allocate; widget_class->configure_event = gtk_window_configure_event; @@ -244,6 +254,7 @@ gtk_window_class_init (GtkWindowClass *klass) container_class->focus = gtk_window_focus; klass->set_focus = gtk_window_real_set_focus; + klass->frame_event = gtk_window_frame_event; gtk_object_add_arg_type ("GtkWindow::type", GTK_TYPE_WINDOW_TYPE, GTK_ARG_READWRITE, ARG_TYPE); gtk_object_add_arg_type ("GtkWindow::title", GTK_TYPE_STRING, GTK_ARG_READWRITE, ARG_TITLE); @@ -264,6 +275,15 @@ gtk_window_class_init (GtkWindowClass *klass) gtk_marshal_VOID__POINTER, GTK_TYPE_NONE, 1, GTK_TYPE_WIDGET); + + window_signals[FRAME_EVENT] = + gtk_signal_new ("frame_event", + GTK_RUN_LAST, + GTK_CLASS_TYPE (object_class), + GTK_SIGNAL_OFFSET (GtkWindowClass, frame_event), + gtk_marshal_BOOLEAN__POINTER, + GTK_TYPE_BOOL, 1, + GTK_TYPE_GDK_EVENT); } static void @@ -288,11 +308,24 @@ gtk_window_init (GtkWindow *window) window->position = GTK_WIN_POS_NONE; window->use_uposition = TRUE; window->modal = FALSE; - + window->frame = NULL; + window->has_frame = FALSE; + window->frame_left = 0; + window->frame_right = 0; + window->frame_top = 0; + window->frame_bottom = 0; + gtk_widget_ref (GTK_WIDGET (window)); gtk_object_sink (GTK_OBJECT (window)); window->has_user_ref_count = TRUE; toplevel_list = g_slist_prepend (toplevel_list, window); + + gtk_decorated_window_init (window); + + gtk_signal_connect (GTK_OBJECT (window), + "event", + GTK_SIGNAL_FUNC (gtk_window_event), + NULL); } static void @@ -426,7 +459,11 @@ gtk_window_set_title (GtkWindow *window, window->title = g_strdup (title); if (GTK_WIDGET_REALIZED (window)) - gdk_window_set_title (GTK_WIDGET (window)->window, window->title); + { + gdk_window_set_title (GTK_WIDGET (window)->window, window->title); + + gtk_decorated_window_set_title (window, title); + } } void @@ -697,8 +734,11 @@ gtk_window_reposition (GtkWindow *window, &info->last.geometry, info->last.flags); } - - gdk_window_move (GTK_WIDGET (window)->window, x, y); + + if (window->frame) + gdk_window_move (window->frame, x - window->frame_left, y - window->frame_top); + else + gdk_window_move (GTK_WIDGET (window)->window, x, y); } } @@ -993,23 +1033,24 @@ gtk_window_show (GtkWidget *widget) GtkWindow *window = GTK_WINDOW (widget); GtkContainer *container = GTK_CONTAINER (window); gboolean need_resize; - + gboolean was_realized; + GTK_WIDGET_SET_FLAGS (widget, GTK_VISIBLE); - + need_resize = container->need_resize || !GTK_WIDGET_REALIZED (widget); container->need_resize = FALSE; - + if (need_resize) { GtkWindowGeometryInfo *info = gtk_window_get_geometry_info (window, TRUE); GtkAllocation allocation = { 0, 0 }; GdkGeometry new_geometry; guint width, height, new_flags; - + /* determine default size to initially show the window with */ gtk_widget_size_request (widget, NULL); gtk_window_compute_default_size (window, &width, &height); - + /* save away the last default size for later comparisions */ info->last.width = width; info->last.height = height; @@ -1020,16 +1061,25 @@ gtk_window_show (GtkWidget *widget) &new_geometry, new_flags, width, height, &width, &height); - + /* and allocate the window */ allocation.width = width; allocation.height = height; gtk_widget_size_allocate (widget, &allocation); - if (GTK_WIDGET_REALIZED (widget)) + was_realized = FALSE; + if (!GTK_WIDGET_REALIZED (widget)) + { + gtk_widget_realize (widget); + was_realized = TRUE;; + } + + /* Must be done after the windows are realized, + so that the decorations can be read */ + gtk_decorated_window_calculate_frame_size (window); + + if (!was_realized) gdk_window_resize (widget->window, width, height); - else - gtk_widget_realize (widget); } gtk_container_check_resize (container); @@ -1075,6 +1125,8 @@ gtk_window_map (GtkWidget *widget) gtk_widget_map (window->bin.child); gdk_window_show (widget->window); + if (window->frame) + gdk_window_show (window->frame); } static void @@ -1085,19 +1137,25 @@ gtk_window_unmap (GtkWidget *widget) g_return_if_fail (widget != NULL); g_return_if_fail (GTK_IS_WINDOW (widget)); + window = GTK_WINDOW (widget); + GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED); - gdk_window_withdraw (widget->window); + if (window->frame) + gdk_window_withdraw (window->frame); + else + gdk_window_withdraw (widget->window); - window = GTK_WINDOW (widget); window->use_uposition = TRUE; window->resize_count = 0; window->handling_resize = FALSE; + } static void gtk_window_realize (GtkWidget *widget) { GtkWindow *window; + GdkWindow *parent_window; GdkWindowAttr attributes; gint attributes_mask; @@ -1146,11 +1204,46 @@ gtk_window_realize (GtkWidget *widget) attributes.title = window->title; attributes.wmclass_name = window->wmclass_name; attributes.wmclass_class = window->wmclass_class; - attributes.width = widget->allocation.width; - attributes.height = widget->allocation.height; attributes.wclass = GDK_INPUT_OUTPUT; attributes.visual = gtk_widget_get_visual (widget); attributes.colormap = gtk_widget_get_colormap (widget); + + if (window->has_frame) + { + attributes.width = widget->allocation.width + window->frame_left + window->frame_right; + attributes.height = widget->allocation.height + window->frame_top + window->frame_bottom; + attributes.event_mask = (GDK_EXPOSURE_MASK | + GDK_KEY_PRESS_MASK | + GDK_ENTER_NOTIFY_MASK | + GDK_LEAVE_NOTIFY_MASK | + GDK_FOCUS_CHANGE_MASK | + GDK_STRUCTURE_MASK | + GDK_BUTTON_MOTION_MASK | + GDK_POINTER_MOTION_HINT_MASK | + GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK); + + attributes_mask = GDK_WA_VISUAL | GDK_WA_COLORMAP; + + window->frame = gdk_window_new (NULL, &attributes, attributes_mask); + gdk_window_set_user_data (window->frame, widget); + + attributes.window_type = GDK_WINDOW_CHILD; + attributes.x = window->frame_left; + attributes.y = window->frame_right; + + attributes_mask = GDK_WA_X | GDK_WA_Y; + + parent_window = window->frame; + } + else + { + attributes_mask = 0; + parent_window = NULL; + } + + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; attributes.event_mask = gtk_widget_get_events (widget); attributes.event_mask |= (GDK_EXPOSURE_MASK | GDK_KEY_PRESS_MASK | @@ -1158,24 +1251,47 @@ gtk_window_realize (GtkWidget *widget) GDK_LEAVE_NOTIFY_MASK | GDK_FOCUS_CHANGE_MASK | GDK_STRUCTURE_MASK); - - attributes_mask = GDK_WA_VISUAL | GDK_WA_COLORMAP; + + attributes_mask |= GDK_WA_VISUAL | GDK_WA_COLORMAP; attributes_mask |= (window->title ? GDK_WA_TITLE : 0); attributes_mask |= (window->wmclass_name ? GDK_WA_WMCLASS : 0); - - widget->window = gdk_window_new (NULL, &attributes, attributes_mask); + widget->window = gdk_window_new (parent_window, &attributes, attributes_mask); gdk_window_set_user_data (widget->window, window); - + widget->style = gtk_style_attach (widget->style, widget->window); gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL); + if (window->frame) + gtk_style_set_background (widget->style, window->frame, GTK_STATE_NORMAL); + gtk_window_paint (widget, NULL); - + if (window->transient_parent && GTK_WIDGET_REALIZED (window->transient_parent)) gdk_window_set_transient_for (widget->window, GTK_WIDGET (window->transient_parent)->window); } + +static void +gtk_window_unrealize (GtkWidget *widget) +{ + GtkWindow *window; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_WINDOW (widget)); + + window = GTK_WINDOW (widget); + + if (window->frame) + { + gdk_window_set_user_data (window->frame, NULL); + gdk_window_destroy (window->frame); + window->frame = NULL; + } + + (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget); +} + static void gtk_window_size_request (GtkWidget *widget, GtkRequisition *requisition) @@ -1229,6 +1345,78 @@ gtk_window_size_allocate (GtkWidget *widget, gtk_widget_size_allocate (window->bin.child, &child_allocation); } + + if (GTK_WIDGET_REALIZED (widget) && window->frame) + { + gdk_window_resize (window->frame, + allocation->width + window->frame_left + window->frame_right, + allocation->height + window->frame_top + window->frame_bottom); + } +} + +static gint +gtk_window_event (GtkWidget *widget, GdkEvent *event) +{ + GtkWindow *window; + gboolean return_val; + + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + window = GTK_WINDOW (widget); + + if (window->frame && (event->any.window == window->frame)) + { + if ((event->type != GDK_KEY_PRESS) && + (event->type != GDK_KEY_RELEASE) && + (event->type != GDK_FOCUS_CHANGE)) + { + gtk_signal_emit_stop_by_name (GTK_OBJECT (widget), "event"); + return_val = FALSE; + gtk_signal_emit (GTK_OBJECT (widget), window_signals[FRAME_EVENT], event, &return_val); + return TRUE; + } + else + { + g_object_unref (event->any.window); + event->any.window = g_object_ref (widget->window); + } + } + + return FALSE; +} + +static gboolean +gtk_window_frame_event (GtkWidget *widget, GdkEvent *event) +{ + GdkEventConfigure *configure_event; + GtkWindow *window = GTK_WINDOW (widget); + GdkRectangle rect; + + switch (event->type) + { + case GDK_CONFIGURE: + configure_event = (GdkEventConfigure *)event; + + /* Invalidate the decorations */ + rect.x = 0; + rect.y = 0; + rect.width = configure_event->width; + rect.height = configure_event->height; + + gdk_window_invalidate_rect (window->frame, &rect, FALSE); + + /* Pass on the (modified) configure event */ + configure_event->width -= window->frame_left + window->frame_right; + configure_event->height -= window->frame_top + window->frame_bottom; + return gtk_window_configure_event (widget, configure_event); + break; + default: + break; + } + return FALSE; } static gint @@ -1842,7 +2030,12 @@ gtk_window_move_resize (GtkWindow *window) */ if (x != -1 && y != -1) - gdk_window_move (widget->window, x, y); + { + if (window->frame) + gdk_window_move (window->frame, x - window->frame_left, y - window->frame_top); + else + gdk_window_move (GTK_WIDGET (window)->window, x, y); + } /* we have to preserve the values and flags that are used * for computation of default_size_changed and hints_changed @@ -1886,9 +2079,26 @@ gtk_window_move_resize (GtkWindow *window) /* request a new window size */ if (x != -1 && y != -1) - gdk_window_move_resize (GTK_WIDGET (window)->window, x, y, new_width, new_height); + { + if (window->frame) + { + gdk_window_move_resize (window->frame, + x - window->frame_left, y - window->frame_top, + new_width + window->frame_left + window->frame_right, + new_height + window->frame_top + window->frame_bottom); + gdk_window_resize (GTK_WIDGET (window)->window, new_width, new_height); + } + else + gdk_window_move_resize (GTK_WIDGET (window)->window, x, y, new_width, new_height); + } else - gdk_window_resize (GTK_WIDGET (window)->window, new_width, new_height); + { + if (window->frame) + gdk_window_resize (window->frame, + new_width + window->frame_left + window->frame_right, + new_height + window->frame_top + window->frame_bottom); + gdk_window_resize (GTK_WIDGET (window)->window, new_width, new_height); + } window->resize_count += 1; /* we are now awaiting the new configure event in response to our @@ -1912,7 +2122,12 @@ gtk_window_move_resize (GtkWindow *window) else { if (x != -1 && y != -1) - gdk_window_move (widget->window, x, y); + { + if (window->frame) + gdk_window_move (window->frame, x - window->frame_left, y - window->frame_top); + else + gdk_window_move (widget->window, x, y); + } if (container->resize_widgets) gtk_container_resize_children (GTK_CONTAINER (window)); @@ -1992,6 +2207,31 @@ gtk_window_compute_default_size (GtkWindow *window, } } +void +_gtk_window_constrain_size (GtkWindow *window, + gint width, + gint height, + gint *new_width, + gint *new_height) +{ + GtkWindowGeometryInfo *info = (GtkWindowGeometryInfo *)gtk_object_get_data (GTK_OBJECT (window), "gtk-window-geometry"); + + if (info) + { + GdkWindowHints flags = info->last.flags; + GdkGeometry *geometry = &info->last.geometry; + + gtk_window_constrain_size (window, + geometry, + flags, + width, + height, + new_width, + new_height); + } +} + + /* Constrain a window size to obey the hints passed in geometry * and flags. The result will be stored in *new_width and *new_height * @@ -2262,8 +2502,8 @@ gtk_window_compute_reposition (GtkWindow *window, if (window->use_uposition) { gint ox, oy; - gdk_window_get_origin (parent_widget->window, - &ox, &oy); + gdk_window_get_origin (parent_widget->window, + &ox, &oy); *x = ox + (parent_widget->allocation.width - new_width) / 2; *y = oy + (parent_widget->allocation.height - new_height) / 2; @@ -2348,3 +2588,50 @@ gtk_window_expose (GtkWidget *widget, return TRUE; } + +void +gtk_window_set_has_frame (GtkWindow *window) +{ + g_return_if_fail (window != NULL); + g_return_if_fail (GTK_IS_WINDOW (window)); + g_return_if_fail (!GTK_WIDGET_REALIZED (window)); + + window->has_frame = TRUE; +} + +void +gtk_window_set_frame_dimensions (GtkWindow *window, + gint left, + gint top, + gint right, + gint bottom) +{ + GtkWidget *widget = GTK_WIDGET (window); + + g_return_if_fail (window != NULL); + g_return_if_fail (GTK_IS_WINDOW (window)); + + if (window->frame_left == left && + window->frame_top == top && + window->frame_right == right && + window->frame_bottom == bottom) + return; + + window->frame_left = left; + window->frame_top = top; + window->frame_right = right; + window->frame_bottom = bottom; + + if (GTK_WIDGET_REALIZED (widget) && window->frame) + { + gint width = widget->allocation.width + left + right; + gint height = widget->allocation.height + top + bottom; + gdk_window_resize (window->frame, width, height); + gtk_decorated_window_move_resize_window (window, + left, top, + widget->allocation.width, + widget->allocation.height); + } +} + + diff --git a/gtk/gtkwindow.h b/gtk/gtkwindow.h index 058da9fc513490bc570e6887a8e8f3a80c691b16..7d4cb6b0e84f7b354f18bccab94750df307a9343 100644 --- a/gtk/gtkwindow.h +++ b/gtk/gtkwindow.h @@ -47,8 +47,8 @@ extern "C" { #define GTK_WINDOW_GET_CLASS(obj) (GTK_CHECK_GET_CLASS ((obj), GTK_TYPE_WINDOW, GtkWindowClass)) -typedef struct _GtkWindow GtkWindow; -typedef struct _GtkWindowClass GtkWindowClass; +typedef struct _GtkWindow GtkWindow; +typedef struct _GtkWindowClass GtkWindowClass; struct _GtkWindow { @@ -59,6 +59,8 @@ struct _GtkWindow gchar *wmclass_class; GtkWindowType type; + GdkWindow *frame; + GtkWidget *focus_widget; GtkWidget *default_widget; GtkWindow *transient_parent; @@ -80,14 +82,23 @@ struct _GtkWindow guint use_uposition : 1; guint modal : 1; guint destroy_with_parent : 1; + + guint has_frame : 1; + + guint frame_left; + guint frame_top; + guint frame_right; + guint frame_bottom; }; struct _GtkWindowClass { GtkBinClass parent_class; - void (* set_focus) (GtkWindow *window, - GtkWidget *focus); + void (* set_focus) (GtkWindow *window, + GtkWidget *focus); + gboolean (* frame_event) (GtkWidget *widget, + GdkEvent *event); }; @@ -126,6 +137,13 @@ void gtk_window_set_geometry_hints (GtkWindow *window, void gtk_window_set_default_size (GtkWindow *window, gint width, gint height); +/* gtk_window_set_has_frame () must be called before realizing the window_*/ +void gtk_window_set_has_frame (GtkWindow *window); +void gtk_window_set_frame_dimensions (GtkWindow *window, + gint left, + gint top, + gint right, + gint bottom); /* If window is set modal, input will be grabbed when show and released when hide */ void gtk_window_set_modal (GtkWindow *window, @@ -135,6 +153,7 @@ GList* gtk_window_list_toplevels (void); /* Get the "built-in" accel group (convenience thing) */ GtkAccelGroup* gtk_window_get_default_accel_group (GtkWindow *window); + /* --- internal functions --- */ void gtk_window_set_focus (GtkWindow *window, GtkWidget *focus); @@ -147,6 +166,11 @@ void gtk_window_add_embedded_xid (GtkWindow *window, void gtk_window_reposition (GtkWindow *window, gint x, gint y); +void _gtk_window_constrain_size (GtkWindow *window, + gint width, + gint height, + gint *new_width, + gint *new_height); #ifdef __cplusplus }