gtk2/gtk/gtkwindow.c
Owen Taylor a1a252ce46 Get rid of a bunch of g_strdup_printf("%s%s") in favor of g_strconcat().
Fri Feb  2 12:26:50 2001  Owen Taylor  <otaylor@redhat.com>

	* gtk/gtkrc.c (gtk_rc_add_initial_default_files): Get rid of
	a bunch of g_strdup_printf("%s%s") in favor of g_strconcat().

	* gtk/gtkrc.c Makefile.am: Use $(libdir), not $(exe_prefix),
	since some people set $(libdir) separately. (#1290, David Kaelbling)

Thu Feb  1 18:25:46 2001  Owen Taylor  <otaylor@redhat.com>

	* gtk/gtkfilesel.c: If PATH_MAX and MAXPATHLEN are not
	defined, define MAXPATHLEN to 2048. (The Hurd doesn't have
	MAXPATHLEN, but the code here depends on a fixed value.)
	(#4524)

Wed Jan 31 22:01:04 2001  Owen Taylor  <otaylor@redhat.com>

	* gtk/gtkhandlebox.c (gtk_handle_box_button_changed): Handle the case
	where child == NULL and handle_position == RIGHT or BOTTOM. (#8041g)

Wed Jan 31 21:20:39 2001  Owen Taylor  <otaylor@redhat.com>

	* gtk/gtkctree.c (real_tree_move): If the node being moved isn't
	viewable there is no way that moving the node will cause the
	focus row to become not viewable, so omit check on the visibility
	of new_sibling, which is irrelevant. (Fixes #8002, David Helder)

Wed Jan 31 20:38:17 2001  Owen Taylor  <otaylor@redhat.com>

	* gtk/gtkentry.c (gtk_entry_commit_cb): Delete the current
	selection before inserting new text.

Wed Jan 31 18:49:33 2001  Owen Taylor  <otaylor@redhat.com>

	* gtk/gtkoptionmenu.c (gtk_option_menu_item_state_changed_cb):
	Make the sensitivity of the reparented child track that of
	the original parent menu item. (#34218, David Hodson)

	* gtk/gtkoptionmenu.c (gtk_option_menu_item_destroy_cb): Handle
	the case where the current item is destroyed properly.

	* gtk/gtkoptionmenu.c: Some additional code cleanups and fix
	some edge cases with child-less menuitems.

Wed Jan 31 17:16:13 2001  Owen Taylor  <otaylor@redhat.com>

	* gtk/gtkcombo.c (gtk_combo_window_key_press): Make Return
	key pop down window. (#12074, Jon K Hellan)

Wed Jan 31 16:21:42 2001  Owen Taylor  <otaylor@redhat.com>

	* gtk/gtklist.c (gtk_list_signal_item_toggle): Don't allow
	toggling of rows off in BROWSE or EXTENDED mode. (#12072, Jon K Hellan)
	The solution here isn't perfect - you get an extraneous
	emission of "toggle", which could conceivably confuse an app,
	but better than the current situation. LXR search seems to
	indicate that no apps in GNOME CVS connect to "toggle".

Wed Jan 31 15:46:13 2001  Owen Taylor  <otaylor@redhat.com>

        * gtk/Makefile.am (libgtkinclude_HEADERS): Move gtkcompat.h from
        gtk_public_h_sources to directly here to avoid warning when
        building srcdir != builddir. (#9656)

Tue Jan 30 19:49:02 2001  Owen Taylor  <otaylor@redhat.com>

	* gtk/gtkrange.c: Patch from Kipp Hickman to make the event
	handlers in gtkrange.c return the proper values (TRUE == handled)
	(#10316).

	This is just the tip of the iceberg, but gtkrange.c is the
	most common place where the propagation is problematical,
	and also a place where it is almost certainly safe to change
	this in the stable branch.

	(You don't want right click popups on a range control or anything...)

Tue Jan 30 18:57:59 2001  Owen Taylor  <otaylor@redhat.com>

	* gtk/gtktext.c (clear_focus_area): We need to clear the focus
	area on focus out, even if a background pixmap isn't set.
	(#13941)

Tue Jan 30 18:24:10 2001  Owen Taylor  <otaylor@redhat.com>

	* gtk/gtknotebook.c (gtk_notebook_set_shape): Fix from Sean Cunningham
	to deal with setting the shape properly when scrolling arrows are
	turned on, but not visible because there is sufficient space.
	(#13432)

Tue Jan 30 16:39:25 2001  Owen Taylor  <otaylor@redhat.com>

	* gtk/gtkitemfactory.c (gtk_item_factory_delete_item): For menu
	items with submenus, destroy the item along with the submenu.
	(#7841, Brian Masney(?)) Also, handle paths of the form '<foo>/abcd...'
	properly.

	* gtk/testgtk.c (menu_items): Add a dummy branch that we delete
	later.

Tue Jan 30 15:51:25 2001  Owen Taylor  <otaylor@redhat.com>

	* gtk/gtkwindow.c (gtk_window_real_set_focus): Fix a problem where
	the focus widget sometimes wasn't drawn with the default if there
	was no default widget.

	* gtk/gtkstyle.c (gtk_style_real_unrealize): free colors,
	unreference pixmaps.

	* gtk/gtkstyle.c (gtk_style_realize): Reference colormap
	for some extra safety.

Mon Jan 29 19:00:01 2001  Owen Taylor  <otaylor@redhat.com>

	* gtk/gtk{ctree.c,clist.c} (set_cell_contents): Handle setting
	the text of a cell to the old pointer value better, by
	copying the new text before freeing the old text. Some code
	cleanup. (#8079, Karl Nelson)

Mon Jan 29 16:50:19 2001  Owen Taylor  <otaylor@redhat.com>

	* gtk/gtklabel.[ch] gtk/gtkframe.[ch]: Make gtk_label_get_text()
	gtk_frame_get_label() non strdup'ing, and G_CONST_RETURN.

Mon Jan 29 15:22:51 2001  Owen Taylor  <otaylor@redhat.com>

	* gtk/gtkmenu.c (gtk_menu_remove): When removing an
	item from a menu, check to see if it matches
	menu->old_active_menu_item, and if so, unref and clear
	old_active_menu_item (Patch from Pavel Cisler)

	* gtk/gtkmenushell.c (gtk_menu_shell_remove): Unset
	menu_shell->active_menu_item, if it is the child being
	removed. (Patch based on that of Gene Ragan, #50337)
2001-02-02 17:53:29 +00:00

2653 lines
74 KiB
C

/* GTK - The GIMP Toolkit
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
*
* 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.
*/
/*
* Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
* file for a list of people on the GTK+ Team. See the ChangeLog
* files for a list of changes. These files are distributed with
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
*/
#include <string.h>
#include <limits.h>
#include "gdk/gdk.h"
#include "gdk/gdkkeysyms.h"
#if defined (GDK_WINDOWING_X11)
#include "x11/gdkx.h"
#elif defined (GDK_WINDOWING_WIN32)
#include "win32/gdkwin32.h"
#elif defined (GDK_WINDOWING_NANOX)
#include "nanox/gdkprivate-nanox.h"
#elif defined (GDK_WINDOWING_FB)
#include "linux-fb/gdkfb.h"
#endif
#include "gtkprivate.h"
#include "gtkrc.h"
#include "gtksignal.h"
#include "gtkwindow.h"
#include "gtkwindow-decorate.h"
#include "gtkbindings.h"
#include "gtkmain.h"
#include "gtkiconfactory.h"
/* TODO: remove this define and assorted code in 1.3 and fix up the
* real culprits.
*/
#define FIXME_ZVT_ME_HARDER
enum {
SET_FOCUS,
FRAME_EVENT,
LAST_SIGNAL
};
enum {
ARG_0,
ARG_TYPE,
ARG_TITLE,
ARG_AUTO_SHRINK,
ARG_ALLOW_SHRINK,
ARG_ALLOW_GROW,
ARG_MODAL,
ARG_WIN_POS,
ARG_DEFAULT_WIDTH,
ARG_DEFAULT_HEIGHT,
ARG_DESTROY_WITH_PARENT
};
typedef struct {
GdkGeometry geometry; /* Last set of geometry hints we set */
GdkWindowHints flags;
gint width;
gint height;
} GtkWindowLastGeometryInfo;
typedef struct {
/* Properties that the app has set on the window
*/
GdkGeometry geometry; /* Geometry hints */
GdkWindowHints mask;
GtkWidget *widget; /* subwidget to which hints apply */
gint width; /* Default size */
gint height;
GtkWindowLastGeometryInfo last;
} GtkWindowGeometryInfo;
static void gtk_window_class_init (GtkWindowClass *klass);
static void gtk_window_init (GtkWindow *window);
static void gtk_window_set_arg (GtkObject *object,
GtkArg *arg,
guint arg_id);
static void gtk_window_get_arg (GtkObject *object,
GtkArg *arg,
guint arg_id);
static void gtk_window_shutdown (GObject *object);
static void gtk_window_destroy (GtkObject *object);
static void gtk_window_finalize (GObject *object);
static void gtk_window_show (GtkWidget *widget);
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,
GdkEventKey *event);
static gint gtk_window_key_release_event (GtkWidget *widget,
GdkEventKey *event);
static gint gtk_window_enter_notify_event (GtkWidget *widget,
GdkEventCrossing *event);
static gint gtk_window_leave_notify_event (GtkWidget *widget,
GdkEventCrossing *event);
static gint gtk_window_focus_in_event (GtkWidget *widget,
GdkEventFocus *event);
static gint gtk_window_focus_out_event (GtkWidget *widget,
GdkEventFocus *event);
static gint gtk_window_client_event (GtkWidget *widget,
GdkEventClient *event);
static void gtk_window_check_resize (GtkContainer *container);
static gint gtk_window_focus (GtkContainer *container,
GtkDirectionType direction);
static void gtk_window_real_set_focus (GtkWindow *window,
GtkWidget *focus);
static void gtk_window_move_resize (GtkWindow *window);
static gboolean gtk_window_compare_hints (GdkGeometry *geometry_a,
guint flags_a,
GdkGeometry *geometry_b,
guint flags_b);
static void gtk_window_compute_default_size (GtkWindow *window,
guint *width,
guint *height);
static void gtk_window_constrain_size (GtkWindow *window,
GdkGeometry *geometry,
guint flags,
gint width,
gint height,
gint *new_width,
gint *new_height);
static void gtk_window_compute_hints (GtkWindow *window,
GdkGeometry *new_geometry,
guint *new_flags);
static void gtk_window_compute_reposition (GtkWindow *window,
gint new_width,
gint new_height,
gint *x,
gint *y);
static void gtk_window_read_rcfiles (GtkWidget *widget,
GdkEventClient *event);
static void gtk_window_paint (GtkWidget *widget,
GdkRectangle *area);
static gint gtk_window_expose (GtkWidget *widget,
GdkEventExpose *event);
static void gtk_window_unset_transient_for (GtkWindow *window);
static void gtk_window_transient_parent_realized (GtkWidget *parent,
GtkWidget *window);
static void gtk_window_transient_parent_unrealized (GtkWidget *parent,
GtkWidget *window);
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 };
GtkType
gtk_window_get_type (void)
{
static GtkType window_type = 0;
if (!window_type)
{
static const GtkTypeInfo window_info =
{
"GtkWindow",
sizeof (GtkWindow),
sizeof (GtkWindowClass),
(GtkClassInitFunc) gtk_window_class_init,
(GtkObjectInitFunc) gtk_window_init,
/* reserved_1 */ NULL,
/* reserved_2 */ NULL,
(GtkClassInitFunc) NULL,
};
window_type = gtk_type_unique (gtk_bin_get_type (), &window_info);
}
return window_type;
}
static void
gtk_window_class_init (GtkWindowClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GtkObjectClass *object_class;
GtkWidgetClass *widget_class;
GtkContainerClass *container_class;
object_class = (GtkObjectClass*) klass;
widget_class = (GtkWidgetClass*) klass;
container_class = (GtkContainerClass*) klass;
parent_class = gtk_type_class (gtk_bin_get_type ());
gobject_class->shutdown = gtk_window_shutdown;
gobject_class->finalize = gtk_window_finalize;
object_class->set_arg = gtk_window_set_arg;
object_class->get_arg = gtk_window_get_arg;
object_class->destroy = gtk_window_destroy;
widget_class->show = gtk_window_show;
widget_class->hide = gtk_window_hide;
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;
widget_class->key_press_event = gtk_window_key_press_event;
widget_class->key_release_event = gtk_window_key_release_event;
widget_class->enter_notify_event = gtk_window_enter_notify_event;
widget_class->leave_notify_event = gtk_window_leave_notify_event;
widget_class->focus_in_event = gtk_window_focus_in_event;
widget_class->focus_out_event = gtk_window_focus_out_event;
widget_class->client_event = gtk_window_client_event;
widget_class->expose_event = gtk_window_expose;
container_class->check_resize = gtk_window_check_resize;
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);
gtk_object_add_arg_type ("GtkWindow::auto_shrink", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_AUTO_SHRINK);
gtk_object_add_arg_type ("GtkWindow::allow_shrink", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_ALLOW_SHRINK);
gtk_object_add_arg_type ("GtkWindow::allow_grow", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_ALLOW_GROW);
gtk_object_add_arg_type ("GtkWindow::modal", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_MODAL);
gtk_object_add_arg_type ("GtkWindow::window_position", GTK_TYPE_WINDOW_POSITION, GTK_ARG_READWRITE, ARG_WIN_POS);
gtk_object_add_arg_type ("GtkWindow::default_width", GTK_TYPE_INT, GTK_ARG_READWRITE, ARG_DEFAULT_WIDTH);
gtk_object_add_arg_type ("GtkWindow::default_height", GTK_TYPE_INT, GTK_ARG_READWRITE, ARG_DEFAULT_HEIGHT);
gtk_object_add_arg_type ("GtkWindow::destroy_with_parent", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_DESTROY_WITH_PARENT);
window_signals[SET_FOCUS] =
gtk_signal_new ("set_focus",
GTK_RUN_LAST,
GTK_CLASS_TYPE (object_class),
GTK_SIGNAL_OFFSET (GtkWindowClass, set_focus),
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
gtk_window_init (GtkWindow *window)
{
GTK_WIDGET_UNSET_FLAGS (window, GTK_NO_WINDOW);
GTK_WIDGET_SET_FLAGS (window, GTK_TOPLEVEL);
gtk_container_set_resize_mode (GTK_CONTAINER (window), GTK_RESIZE_QUEUE);
window->title = NULL;
window->wmclass_name = g_strdup (g_get_prgname ());
window->wmclass_class = g_strdup (gdk_progclass);
window->type = GTK_WINDOW_TOPLEVEL;
window->focus_widget = NULL;
window->default_widget = NULL;
window->resize_count = 0;
window->allow_shrink = FALSE;
window->allow_grow = TRUE;
window->auto_shrink = FALSE;
window->handling_resize = FALSE;
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
gtk_window_set_arg (GtkObject *object,
GtkArg *arg,
guint arg_id)
{
GtkWindow *window;
window = GTK_WINDOW (object);
switch (arg_id)
{
case ARG_TYPE:
window->type = GTK_VALUE_ENUM (*arg);
break;
case ARG_TITLE:
gtk_window_set_title (window, GTK_VALUE_STRING (*arg));
break;
case ARG_AUTO_SHRINK:
window->auto_shrink = (GTK_VALUE_BOOL (*arg) != FALSE);
gtk_widget_queue_resize (GTK_WIDGET (window));
break;
case ARG_ALLOW_SHRINK:
window->allow_shrink = (GTK_VALUE_BOOL (*arg) != FALSE);
gtk_widget_queue_resize (GTK_WIDGET (window));
break;
case ARG_ALLOW_GROW:
window->allow_grow = (GTK_VALUE_BOOL (*arg) != FALSE);
gtk_widget_queue_resize (GTK_WIDGET (window));
break;
case ARG_MODAL:
gtk_window_set_modal (window, GTK_VALUE_BOOL (*arg));
break;
case ARG_WIN_POS:
gtk_window_set_position (window, GTK_VALUE_ENUM (*arg));
break;
case ARG_DEFAULT_WIDTH:
gtk_window_set_default_size (window, GTK_VALUE_INT (*arg), -2);
break;
case ARG_DEFAULT_HEIGHT:
gtk_window_set_default_size (window, -2, GTK_VALUE_INT (*arg));
break;
case ARG_DESTROY_WITH_PARENT:
gtk_window_set_destroy_with_parent (window, GTK_VALUE_BOOL (*arg));
break;
default:
break;
}
}
static void
gtk_window_get_arg (GtkObject *object,
GtkArg *arg,
guint arg_id)
{
GtkWindow *window;
window = GTK_WINDOW (object);
switch (arg_id)
{
GtkWindowGeometryInfo *info;
case ARG_TYPE:
GTK_VALUE_ENUM (*arg) = window->type;
break;
case ARG_TITLE:
GTK_VALUE_STRING (*arg) = g_strdup (window->title);
break;
case ARG_AUTO_SHRINK:
GTK_VALUE_BOOL (*arg) = window->auto_shrink;
break;
case ARG_ALLOW_SHRINK:
GTK_VALUE_BOOL (*arg) = window->allow_shrink;
break;
case ARG_ALLOW_GROW:
GTK_VALUE_BOOL (*arg) = window->allow_grow;
break;
case ARG_MODAL:
GTK_VALUE_BOOL (*arg) = window->modal;
break;
case ARG_WIN_POS:
GTK_VALUE_ENUM (*arg) = window->position;
break;
case ARG_DEFAULT_WIDTH:
info = gtk_window_get_geometry_info (window, FALSE);
if (!info)
GTK_VALUE_INT (*arg) = -1;
else
GTK_VALUE_INT (*arg) = info->width;
break;
case ARG_DEFAULT_HEIGHT:
info = gtk_window_get_geometry_info (window, FALSE);
if (!info)
GTK_VALUE_INT (*arg) = -1;
else
GTK_VALUE_INT (*arg) = info->height;
break;
case ARG_DESTROY_WITH_PARENT:
GTK_VALUE_BOOL (*arg) = window->destroy_with_parent;
break;
default:
arg->type = GTK_TYPE_INVALID;
break;
}
}
GtkWidget*
gtk_window_new (GtkWindowType type)
{
GtkWindow *window;
g_return_val_if_fail (type >= GTK_WINDOW_TOPLEVEL && type <= GTK_WINDOW_POPUP, NULL);
window = gtk_type_new (GTK_TYPE_WINDOW);
window->type = type;
return GTK_WIDGET (window);
}
void
gtk_window_set_title (GtkWindow *window,
const gchar *title)
{
g_return_if_fail (window != NULL);
g_return_if_fail (GTK_IS_WINDOW (window));
if (window->title)
g_free (window->title);
window->title = g_strdup (title);
if (GTK_WIDGET_REALIZED (window))
{
gdk_window_set_title (GTK_WIDGET (window)->window, window->title);
gtk_decorated_window_set_title (window, title);
}
}
void
gtk_window_set_wmclass (GtkWindow *window,
const gchar *wmclass_name,
const gchar *wmclass_class)
{
g_return_if_fail (window != NULL);
g_return_if_fail (GTK_IS_WINDOW (window));
g_free (window->wmclass_name);
window->wmclass_name = g_strdup (wmclass_name);
g_free (window->wmclass_class);
window->wmclass_class = g_strdup (wmclass_class);
if (GTK_WIDGET_REALIZED (window))
g_warning ("shouldn't set wmclass after window is realized!\n");
}
void
gtk_window_set_focus (GtkWindow *window,
GtkWidget *focus)
{
g_return_if_fail (window != NULL);
g_return_if_fail (GTK_IS_WINDOW (window));
if (focus)
{
g_return_if_fail (GTK_IS_WIDGET (focus));
g_return_if_fail (GTK_WIDGET_CAN_FOCUS (focus));
}
if ((window->focus_widget != focus) ||
(focus && !GTK_WIDGET_HAS_FOCUS (focus)))
gtk_signal_emit (GTK_OBJECT (window), window_signals[SET_FOCUS], focus);
}
void
gtk_window_set_default (GtkWindow *window,
GtkWidget *default_widget)
{
g_return_if_fail (window != NULL);
g_return_if_fail (GTK_IS_WINDOW (window));
if (default_widget)
g_return_if_fail (GTK_WIDGET_CAN_DEFAULT (default_widget));
if (window->default_widget != default_widget)
{
if (window->default_widget)
{
if (window->focus_widget != window->default_widget ||
!GTK_WIDGET_RECEIVES_DEFAULT (window->default_widget))
GTK_WIDGET_UNSET_FLAGS (window->default_widget, GTK_HAS_DEFAULT);
gtk_widget_draw_default (window->default_widget);
}
window->default_widget = default_widget;
if (window->default_widget)
{
if (window->focus_widget == NULL ||
!GTK_WIDGET_RECEIVES_DEFAULT (window->focus_widget))
GTK_WIDGET_SET_FLAGS (window->default_widget, GTK_HAS_DEFAULT);
gtk_widget_draw_default (window->default_widget);
}
}
}
void
gtk_window_set_policy (GtkWindow *window,
gint allow_shrink,
gint allow_grow,
gint auto_shrink)
{
g_return_if_fail (window != NULL);
g_return_if_fail (GTK_IS_WINDOW (window));
window->allow_shrink = (allow_shrink != FALSE);
window->allow_grow = (allow_grow != FALSE);
window->auto_shrink = (auto_shrink != FALSE);
gtk_widget_queue_resize (GTK_WIDGET (window));
}
void
gtk_window_add_accel_group (GtkWindow *window,
GtkAccelGroup *accel_group)
{
g_return_if_fail (window != NULL);
g_return_if_fail (GTK_IS_WINDOW (window));
g_return_if_fail (accel_group != NULL);
gtk_accel_group_attach (accel_group, GTK_OBJECT (window));
}
void
gtk_window_remove_accel_group (GtkWindow *window,
GtkAccelGroup *accel_group)
{
g_return_if_fail (window != NULL);
g_return_if_fail (GTK_IS_WINDOW (window));
g_return_if_fail (accel_group != NULL);
gtk_accel_group_detach (accel_group, GTK_OBJECT (window));
}
GtkAccelGroup*
gtk_window_get_default_accel_group (GtkWindow *window)
{
GtkAccelGroup *group;
g_return_val_if_fail (GTK_IS_WINDOW (window), NULL);
group = gtk_object_get_data (GTK_OBJECT (window),
"gtk-accel-group");
if (group == NULL)
{
group = gtk_accel_group_new ();
gtk_window_add_accel_group (window, group);
gtk_object_set_data (GTK_OBJECT (window),
"gtk-accel-group",
group);
gtk_accel_group_unref (group);
}
return group;
}
void
gtk_window_set_position (GtkWindow *window,
GtkWindowPosition position)
{
g_return_if_fail (window != NULL);
g_return_if_fail (GTK_IS_WINDOW (window));
window->position = position;
}
gint
gtk_window_activate_focus (GtkWindow *window)
{
g_return_val_if_fail (window != NULL, FALSE);
g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
if (window->focus_widget)
{
if (GTK_WIDGET_IS_SENSITIVE (window->focus_widget))
gtk_widget_activate (window->focus_widget);
return TRUE;
}
return FALSE;
}
gint
gtk_window_activate_default (GtkWindow *window)
{
g_return_val_if_fail (window != NULL, FALSE);
g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
if (window->default_widget && GTK_WIDGET_IS_SENSITIVE (window->default_widget))
{
gtk_widget_activate (window->default_widget);
return TRUE;
}
return FALSE;
}
void
gtk_window_set_modal (GtkWindow *window,
gboolean modal)
{
g_return_if_fail (window != NULL);
g_return_if_fail (GTK_IS_WINDOW (window));
window->modal = modal != FALSE;
/* adjust desired modality state */
if (GTK_WIDGET_VISIBLE (window) && window->modal)
gtk_grab_add (GTK_WIDGET (window));
else
gtk_grab_remove (GTK_WIDGET (window));
}
GList*
gtk_window_list_toplevels (void)
{
GList *list = NULL;
GSList *slist;
for (slist = toplevel_list; slist; slist = slist->next)
list = g_list_prepend (list, gtk_widget_ref (slist->data));
return list;
}
void
gtk_window_add_embedded_xid (GtkWindow *window, guint xid)
{
GList *embedded_windows;
g_return_if_fail (window != NULL);
g_return_if_fail (GTK_IS_WINDOW (window));
embedded_windows = gtk_object_get_data (GTK_OBJECT (window), "gtk-embedded");
if (embedded_windows)
gtk_object_remove_no_notify_by_id (GTK_OBJECT (window),
g_quark_from_static_string ("gtk-embedded"));
embedded_windows = g_list_prepend (embedded_windows,
GUINT_TO_POINTER (xid));
gtk_object_set_data_full (GTK_OBJECT (window), "gtk-embedded",
embedded_windows,
embedded_windows ?
(GtkDestroyNotify) g_list_free : NULL);
}
void
gtk_window_remove_embedded_xid (GtkWindow *window, guint xid)
{
GList *embedded_windows;
GList *node;
g_return_if_fail (window != NULL);
g_return_if_fail (GTK_IS_WINDOW (window));
embedded_windows = gtk_object_get_data (GTK_OBJECT (window), "gtk-embedded");
if (embedded_windows)
gtk_object_remove_no_notify_by_id (GTK_OBJECT (window),
g_quark_from_static_string ("gtk-embedded"));
node = g_list_find (embedded_windows, GUINT_TO_POINTER (xid));
if (node)
{
embedded_windows = g_list_remove_link (embedded_windows, node);
g_list_free_1 (node);
}
gtk_object_set_data_full (GTK_OBJECT (window),
"gtk-embedded", embedded_windows,
embedded_windows ?
(GtkDestroyNotify) g_list_free : NULL);
}
void
gtk_window_reposition (GtkWindow *window,
gint x,
gint y)
{
GtkWindowGeometryInfo *info;
g_return_if_fail (window != NULL);
g_return_if_fail (GTK_IS_WINDOW (window));
/* keep this in sync with gtk_window_compute_reposition()
*/
if (GTK_WIDGET_REALIZED (window))
{
info = gtk_window_get_geometry_info (window, TRUE);
if (!(info->last.flags & GDK_HINT_POS))
{
info->last.flags |= GDK_HINT_POS;
gdk_window_set_geometry_hints (GTK_WIDGET (window)->window,
&info->last.geometry,
info->last.flags);
}
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);
}
}
static void
gtk_window_shutdown (GObject *object)
{
GtkWindow *window;
g_return_if_fail (GTK_IS_WINDOW (object));
window = GTK_WINDOW (object);
gtk_window_set_focus (window, NULL);
gtk_window_set_default (window, NULL);
G_OBJECT_CLASS (parent_class)->shutdown (object);
}
static void
parent_destroyed_callback (GtkWindow *parent, GtkWindow *child)
{
gtk_widget_destroy (GTK_WIDGET (child));
}
static void
connect_parent_destroyed (GtkWindow *window)
{
if (window->transient_parent)
{
gtk_signal_connect (GTK_OBJECT (window->transient_parent),
"destroy",
GTK_SIGNAL_FUNC (parent_destroyed_callback),
window);
}
}
static void
disconnect_parent_destroyed (GtkWindow *window)
{
if (window->transient_parent)
{
gtk_signal_disconnect_by_func (GTK_OBJECT (window->transient_parent),
GTK_SIGNAL_FUNC (parent_destroyed_callback),
window);
}
}
static void
gtk_window_transient_parent_realized (GtkWidget *parent,
GtkWidget *window)
{
if (GTK_WIDGET_REALIZED (window))
gdk_window_set_transient_for (window->window, parent->window);
}
static void
gtk_window_transient_parent_unrealized (GtkWidget *parent,
GtkWidget *window)
{
if (GTK_WIDGET_REALIZED (window))
gdk_property_delete (window->window,
gdk_atom_intern ("WM_TRANSIENT_FOR", FALSE));
}
static void
gtk_window_unset_transient_for (GtkWindow *window)
{
if (window->transient_parent)
{
gtk_signal_disconnect_by_func (GTK_OBJECT (window->transient_parent),
GTK_SIGNAL_FUNC (gtk_window_transient_parent_realized),
window);
gtk_signal_disconnect_by_func (GTK_OBJECT (window->transient_parent),
GTK_SIGNAL_FUNC (gtk_window_transient_parent_unrealized),
window);
gtk_signal_disconnect_by_func (GTK_OBJECT (window->transient_parent),
GTK_SIGNAL_FUNC (gtk_widget_destroyed),
&window->transient_parent);
if (window->destroy_with_parent)
disconnect_parent_destroyed (window);
window->transient_parent = NULL;
}
}
void
gtk_window_set_transient_for (GtkWindow *window,
GtkWindow *parent)
{
g_return_if_fail (GTK_IS_WINDOW (window));
g_return_if_fail (parent == NULL || GTK_IS_WINDOW (parent));
g_return_if_fail (window != parent);
if (window->transient_parent)
{
if (GTK_WIDGET_REALIZED (window) &&
GTK_WIDGET_REALIZED (window->transient_parent) &&
(!parent || !GTK_WIDGET_REALIZED (parent)))
gtk_window_transient_parent_unrealized (GTK_WIDGET (window->transient_parent),
GTK_WIDGET (window));
gtk_window_unset_transient_for (window);
}
window->transient_parent = parent;
if (parent)
{
gtk_signal_connect (GTK_OBJECT (parent), "destroy",
GTK_SIGNAL_FUNC (gtk_widget_destroyed),
&window->transient_parent);
gtk_signal_connect (GTK_OBJECT (parent), "realize",
GTK_SIGNAL_FUNC (gtk_window_transient_parent_realized),
window);
gtk_signal_connect (GTK_OBJECT (parent), "unrealize",
GTK_SIGNAL_FUNC (gtk_window_transient_parent_unrealized),
window);
if (window->destroy_with_parent)
connect_parent_destroyed (window);
if (GTK_WIDGET_REALIZED (window) &&
GTK_WIDGET_REALIZED (parent))
gtk_window_transient_parent_realized (GTK_WIDGET (parent),
GTK_WIDGET (window));
}
}
/**
* gtk_window_set_destroy_with_parent:
* @window: a #GtkWindow
* @setting: whether to destroy @window with its transient parent
*
* If @setting is TRUE, then destroying the transient parent of @window
* will also destroy @window itself. This is useful for dialogs that
* shouldn't persist beyond the lifetime of the main window they're
* associated with, for example.
**/
void
gtk_window_set_destroy_with_parent (GtkWindow *window,
gboolean setting)
{
g_return_if_fail (GTK_IS_WINDOW (window));
if (window->destroy_with_parent == (setting != FALSE))
return;
if (window->destroy_with_parent)
{
disconnect_parent_destroyed (window);
}
else
{
connect_parent_destroyed (window);
}
window->destroy_with_parent = setting;
}
static void
gtk_window_geometry_destroy (GtkWindowGeometryInfo *info)
{
if (info->widget)
gtk_signal_disconnect_by_func (GTK_OBJECT (info->widget),
GTK_SIGNAL_FUNC (gtk_widget_destroyed),
&info->widget);
g_free (info);
}
static GtkWindowGeometryInfo*
gtk_window_get_geometry_info (GtkWindow *window,
gboolean create)
{
GtkWindowGeometryInfo *info;
info = gtk_object_get_data (GTK_OBJECT (window), "gtk-window-geometry");
if (!info && create)
{
info = g_new0 (GtkWindowGeometryInfo, 1);
info->width = 0;
info->height = 0;
info->last.width = -1;
info->last.height = -1;
info->widget = NULL;
info->mask = 0;
gtk_object_set_data_full (GTK_OBJECT (window),
"gtk-window-geometry",
info,
(GtkDestroyNotify) gtk_window_geometry_destroy);
}
return info;
}
void
gtk_window_set_geometry_hints (GtkWindow *window,
GtkWidget *geometry_widget,
GdkGeometry *geometry,
GdkWindowHints geom_mask)
{
GtkWindowGeometryInfo *info;
g_return_if_fail (window != NULL);
info = gtk_window_get_geometry_info (window, TRUE);
if (info->widget)
gtk_signal_disconnect_by_func (GTK_OBJECT (info->widget),
GTK_SIGNAL_FUNC (gtk_widget_destroyed),
&info->widget);
info->widget = geometry_widget;
if (info->widget)
gtk_signal_connect (GTK_OBJECT (geometry_widget), "destroy",
GTK_SIGNAL_FUNC (gtk_widget_destroyed),
&info->widget);
if (geometry)
info->geometry = *geometry;
info->mask = geom_mask;
gtk_widget_queue_resize (GTK_WIDGET (window));
}
void
gtk_window_set_default_size (GtkWindow *window,
gint width,
gint height)
{
GtkWindowGeometryInfo *info;
g_return_if_fail (GTK_IS_WINDOW (window));
info = gtk_window_get_geometry_info (window, TRUE);
if (width >= 0)
info->width = width;
if (height >= 0)
info->height = height;
gtk_widget_queue_resize (GTK_WIDGET (window));
}
static void
gtk_window_destroy (GtkObject *object)
{
GtkWindow *window;
g_return_if_fail (GTK_IS_WINDOW (object));
window = GTK_WINDOW (object);
if (window->transient_parent)
gtk_window_set_transient_for (window, NULL);
if (window->has_user_ref_count)
{
window->has_user_ref_count = FALSE;
gtk_widget_unref (GTK_WIDGET (window));
}
GTK_OBJECT_CLASS (parent_class)->destroy (object);
}
static void
gtk_window_finalize (GObject *object)
{
GtkWindow *window;
g_return_if_fail (GTK_IS_WINDOW (object));
window = GTK_WINDOW (object);
toplevel_list = g_slist_remove (toplevel_list, window);
g_free (window->title);
g_free (window->wmclass_name);
g_free (window->wmclass_class);
G_OBJECT_CLASS(parent_class)->finalize (object);
}
static void
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;
/* constrain size to geometry */
gtk_window_compute_hints (window, &new_geometry, &new_flags);
gtk_window_constrain_size (window,
&new_geometry, new_flags,
width, height,
&width, &height);
/* and allocate the window */
allocation.width = width;
allocation.height = height;
gtk_widget_size_allocate (widget, &allocation);
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);
}
gtk_container_check_resize (container);
gtk_widget_map (widget);
if (window->modal)
gtk_grab_add (widget);
}
static void
gtk_window_hide (GtkWidget *widget)
{
GtkWindow *window;
g_return_if_fail (widget != NULL);
g_return_if_fail (GTK_IS_WINDOW (widget));
window = GTK_WINDOW (widget);
GTK_WIDGET_UNSET_FLAGS (widget, GTK_VISIBLE);
gtk_widget_unmap (widget);
if (window->modal)
gtk_grab_remove (widget);
}
static void
gtk_window_map (GtkWidget *widget)
{
GtkWindow *window;
g_return_if_fail (widget != NULL);
g_return_if_fail (GTK_IS_WINDOW (widget));
GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
window = GTK_WINDOW (widget);
if (window->bin.child &&
GTK_WIDGET_VISIBLE (window->bin.child) &&
!GTK_WIDGET_MAPPED (window->bin.child))
gtk_widget_map (window->bin.child);
gdk_window_show (widget->window);
if (window->frame)
gdk_window_show (window->frame);
}
static void
gtk_window_unmap (GtkWidget *widget)
{
GtkWindow *window;
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);
if (window->frame)
gdk_window_withdraw (window->frame);
else
gdk_window_withdraw (widget->window);
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;
g_return_if_fail (GTK_IS_WINDOW (widget));
window = GTK_WINDOW (widget);
/* ensure widget tree is properly size allocated */
if (widget->allocation.x == -1 &&
widget->allocation.y == -1 &&
widget->allocation.width == 1 &&
widget->allocation.height == 1)
{
GtkRequisition requisition;
GtkAllocation allocation = { 0, 0, 200, 200 };
gtk_widget_size_request (widget, &requisition);
if (requisition.width || requisition.height)
{
/* non-empty window */
allocation.width = requisition.width;
allocation.height = requisition.height;
}
gtk_widget_size_allocate (widget, &allocation);
gtk_container_queue_resize (GTK_CONTAINER (widget));
g_return_if_fail (!GTK_WIDGET_REALIZED (widget));
}
GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
switch (window->type)
{
case GTK_WINDOW_TOPLEVEL:
attributes.window_type = GDK_WINDOW_TOPLEVEL;
break;
case GTK_WINDOW_DIALOG:
attributes.window_type = GDK_WINDOW_DIALOG;
break;
case GTK_WINDOW_POPUP:
attributes.window_type = GDK_WINDOW_TEMP;
break;
}
attributes.title = window->title;
attributes.wmclass_name = window->wmclass_name;
attributes.wmclass_class = window->wmclass_class;
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 |
GDK_ENTER_NOTIFY_MASK |
GDK_LEAVE_NOTIFY_MASK |
GDK_FOCUS_CHANGE_MASK |
GDK_STRUCTURE_MASK);
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 (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)
{
GtkWindow *window;
GtkBin *bin;
g_return_if_fail (widget != NULL);
g_return_if_fail (GTK_IS_WINDOW (widget));
g_return_if_fail (requisition != NULL);
window = GTK_WINDOW (widget);
bin = GTK_BIN (window);
requisition->width = GTK_CONTAINER (window)->border_width * 2;
requisition->height = GTK_CONTAINER (window)->border_width * 2;
if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
{
GtkRequisition child_requisition;
gtk_widget_size_request (bin->child, &child_requisition);
requisition->width += child_requisition.width;
requisition->height += child_requisition.height;
}
}
static void
gtk_window_size_allocate (GtkWidget *widget,
GtkAllocation *allocation)
{
GtkWindow *window;
GtkAllocation child_allocation;
g_return_if_fail (widget != NULL);
g_return_if_fail (GTK_IS_WINDOW (widget));
g_return_if_fail (allocation != NULL);
window = GTK_WINDOW (widget);
widget->allocation = *allocation;
if (window->bin.child && GTK_WIDGET_VISIBLE (window->bin.child))
{
child_allocation.x = GTK_CONTAINER (window)->border_width;
child_allocation.y = GTK_CONTAINER (window)->border_width;
child_allocation.width =
MAX (1, (gint)allocation->width - child_allocation.x * 2);
child_allocation.height =
MAX (1, (gint)allocation->height - child_allocation.y * 2);
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
gtk_window_configure_event (GtkWidget *widget,
GdkEventConfigure *event)
{
GtkWindow *window;
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);
/* we got a configure event specifying the new window size and position,
* in principle we have to distinguish 4 cases here:
* 1) the size didn't change and resize_count == 0
* -> the window was merely moved (sometimes not even that)
* 2) the size didn't change and resize_count > 0
* -> we requested a new size, but didn't get it
* 3) the size changed and resize_count > 0
* -> we asked for a new size and we got one
* 4) the size changed and resize_count == 0
* -> we got resized from outside the toolkit, and have to
* accept that size since we don't want to fight neither the
* window manager nor the user
* in the three latter cases we have to reallocate the widget tree,
* which happens in gtk_window_move_resize(), so we set a flag for
* that function and assign the new size. if resize_count > 1,
* we simply do nothing and wait for more configure events.
*/
if (window->resize_count > 0 ||
widget->allocation.width != event->width ||
widget->allocation.height != event->height)
{
if (window->resize_count > 0)
window->resize_count -= 1;
if (window->resize_count == 0)
{
window->handling_resize = TRUE;
widget->allocation.width = event->width;
widget->allocation.height = event->height;
gtk_widget_queue_resize (widget);
}
}
return TRUE;
}
static gint
gtk_window_key_press_event (GtkWidget *widget,
GdkEventKey *event)
{
GtkWindow *window;
GtkDirectionType direction = 0;
gboolean handled;
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);
handled = FALSE;
if (window->focus_widget &&
window->focus_widget != widget &&
GTK_WIDGET_IS_SENSITIVE (window->focus_widget))
{
handled = gtk_widget_event (window->focus_widget, (GdkEvent*) event);
}
if (!handled)
handled = gtk_accel_groups_activate (GTK_OBJECT (window), event->keyval, event->state);
if (!handled)
{
switch (event->keyval)
{
case GDK_space:
if (window->focus_widget)
{
if (GTK_WIDGET_IS_SENSITIVE (window->focus_widget))
gtk_widget_activate (window->focus_widget);
handled = TRUE;
}
break;
case GDK_Return:
case GDK_KP_Enter:
if (window->default_widget && GTK_WIDGET_IS_SENSITIVE (window->default_widget) &&
(!window->focus_widget || !GTK_WIDGET_RECEIVES_DEFAULT (window->focus_widget)))
{
gtk_widget_activate (window->default_widget);
handled = TRUE;
}
else if (window->focus_widget)
{
if (GTK_WIDGET_IS_SENSITIVE (window->focus_widget))
gtk_widget_activate (window->focus_widget);
handled = TRUE;
}
break;
case GDK_Up:
case GDK_Down:
case GDK_Left:
case GDK_Right:
case GDK_KP_Up:
case GDK_KP_Down:
case GDK_KP_Left:
case GDK_KP_Right:
case GDK_Tab:
case GDK_ISO_Left_Tab:
switch (event->keyval)
{
case GDK_Up:
case GDK_KP_Up:
direction = GTK_DIR_UP;
break;
case GDK_Down:
case GDK_KP_Down:
direction = GTK_DIR_DOWN;
break;
case GDK_Left:
case GDK_KP_Left:
direction = GTK_DIR_LEFT;
break;
case GDK_Right:
case GDK_KP_Right:
direction = GTK_DIR_RIGHT;
break;
case GDK_Tab:
case GDK_ISO_Left_Tab:
if (event->state & GDK_SHIFT_MASK)
direction = GTK_DIR_TAB_BACKWARD;
else
direction = GTK_DIR_TAB_FORWARD;
break;
default :
direction = GTK_DIR_UP; /* never reached, but makes compiler happy */
}
gtk_container_focus (GTK_CONTAINER (widget), direction);
if (!GTK_CONTAINER (window)->focus_child)
gtk_window_set_focus (GTK_WINDOW (widget), NULL);
else
handled = TRUE;
break;
}
}
if (!handled && GTK_WIDGET_CLASS (parent_class)->key_press_event)
handled = GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event);
return handled;
}
static gint
gtk_window_key_release_event (GtkWidget *widget,
GdkEventKey *event)
{
GtkWindow *window;
gint handled;
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);
handled = FALSE;
if (window->focus_widget &&
window->focus_widget != widget &&
GTK_WIDGET_SENSITIVE (window->focus_widget))
{
handled = gtk_widget_event (window->focus_widget, (GdkEvent*) event);
}
if (!handled && GTK_WIDGET_CLASS (parent_class)->key_release_event)
handled = GTK_WIDGET_CLASS (parent_class)->key_release_event (widget, event);
return handled;
}
static gint
gtk_window_enter_notify_event (GtkWidget *widget,
GdkEventCrossing *event)
{
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);
return FALSE;
}
static gint
gtk_window_leave_notify_event (GtkWidget *widget,
GdkEventCrossing *event)
{
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);
return FALSE;
}
static gint
gtk_window_focus_in_event (GtkWidget *widget,
GdkEventFocus *event)
{
GtkWindow *window;
GdkEventFocus fevent;
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);
/* It appears spurious focus in events can occur when
* the window is hidden. So we'll just check to see if
* the window is visible before actually handling the
* event
*/
if (GTK_WIDGET_VISIBLE (widget))
{
window = GTK_WINDOW (widget);
if (window->focus_widget &&
window->focus_widget != widget &&
!GTK_WIDGET_HAS_FOCUS (window->focus_widget))
{
fevent.type = GDK_FOCUS_CHANGE;
fevent.window = window->focus_widget->window;
fevent.in = TRUE;
gtk_widget_event (window->focus_widget, (GdkEvent*) &fevent);
}
}
return FALSE;
}
static gint
gtk_window_focus_out_event (GtkWidget *widget,
GdkEventFocus *event)
{
GtkWindow *window;
GdkEventFocus fevent;
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->focus_widget &&
window->focus_widget != widget &&
GTK_WIDGET_HAS_FOCUS (window->focus_widget))
{
fevent.type = GDK_FOCUS_CHANGE;
fevent.window = window->focus_widget->window;
fevent.in = FALSE;
gtk_widget_event (window->focus_widget, (GdkEvent*) &fevent);
}
return FALSE;
}
static GdkAtom atom_rcfiles = GDK_NONE;
static void
gtk_window_read_rcfiles (GtkWidget *widget,
GdkEventClient *event)
{
GList *embedded_windows;
embedded_windows = gtk_object_get_data (GTK_OBJECT (widget), "gtk-embedded");
if (embedded_windows)
{
GdkEventClient sev;
int i;
for(i = 0; i < 5; i++)
sev.data.l[i] = 0;
sev.data_format = 32;
sev.message_type = atom_rcfiles;
while (embedded_windows)
{
guint xid = GPOINTER_TO_UINT (embedded_windows->data);
gdk_event_send_client_message ((GdkEvent *) &sev, xid);
embedded_windows = embedded_windows->next;
}
}
if (gtk_rc_reparse_all ())
{
/* If the above returned true, some of our RC files are out
* of date, so we need to reset all our widgets. Our other
* toplevel windows will also get the message, but by
* then, the RC file will up to date, so we have to tell
* them now. Also, we have to invalidate cached icons in
* icon sets so they get re-rendered.
*/
GList *list, *toplevels;
_gtk_icon_set_invalidate_caches ();
toplevels = gtk_window_list_toplevels ();
for (list = toplevels; list; list = list->next)
{
gtk_widget_reset_rc_styles (list->data);
gtk_widget_unref (list->data);
}
g_list_free (toplevels);
}
}
static gint
gtk_window_client_event (GtkWidget *widget,
GdkEventClient *event)
{
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);
if (!atom_rcfiles)
atom_rcfiles = gdk_atom_intern("_GTK_READ_RCFILES", FALSE);
if(event->message_type == atom_rcfiles)
gtk_window_read_rcfiles (widget, event);
return FALSE;
}
static void
gtk_window_check_resize (GtkContainer *container)
{
GtkWindow *window;
g_return_if_fail (container != NULL);
g_return_if_fail (GTK_IS_WINDOW (container));
window = GTK_WINDOW (container);
if (GTK_WIDGET_VISIBLE (container))
gtk_window_move_resize (window);
}
static gboolean
gtk_window_focus (GtkContainer *container,
GtkDirectionType direction)
{
GtkBin *bin = GTK_BIN (container);
GtkWindow *window = GTK_WINDOW (container);
GtkWidget *old_focus_child = container->focus_child;
GtkWidget *parent;
/* We need a special implementation here to deal properly with wrapping
* around in the tab chain without the danger of going into an
* infinite loop.
*/
if (old_focus_child)
{
if (GTK_IS_CONTAINER (old_focus_child) &&
GTK_WIDGET_DRAWABLE (old_focus_child) &&
GTK_WIDGET_IS_SENSITIVE (old_focus_child) &&
gtk_container_focus (GTK_CONTAINER (old_focus_child), direction))
return TRUE;
}
if (window->focus_widget)
{
/* Wrapped off the end, clear the focus setting for the toplpevel */
parent = window->focus_widget->parent;
while (parent)
{
gtk_container_set_focus_child (GTK_CONTAINER (parent), NULL);
parent = GTK_WIDGET (parent)->parent;
}
gtk_window_set_focus (GTK_WINDOW (container), NULL);
}
/* Now try to focus the first widget in the window */
if (GTK_WIDGET_DRAWABLE (bin->child) &&
GTK_WIDGET_IS_SENSITIVE (bin->child))
{
if (GTK_IS_CONTAINER (bin->child))
{
if (gtk_container_focus (GTK_CONTAINER (bin->child), direction))
return TRUE;
}
else if (GTK_WIDGET_CAN_FOCUS (bin->child))
{
gtk_widget_grab_focus (bin->child);
return TRUE;
}
}
return FALSE;
}
static void
gtk_window_real_set_focus (GtkWindow *window,
GtkWidget *focus)
{
GdkEventFocus event;
gboolean def_flags = 0;
g_return_if_fail (window != NULL);
g_return_if_fail (GTK_IS_WINDOW (window));
if (window->default_widget)
def_flags = GTK_WIDGET_HAS_DEFAULT (window->default_widget);
if (window->focus_widget)
{
event.type = GDK_FOCUS_CHANGE;
event.window = window->focus_widget->window;
event.in = FALSE;
if (GTK_WIDGET_RECEIVES_DEFAULT (window->focus_widget) &&
(window->focus_widget != window->default_widget))
{
GTK_WIDGET_UNSET_FLAGS (window->focus_widget, GTK_HAS_DEFAULT);
/* if any widget had the default set there should be
a default_widget, but might not so this is a sanity
check */
if (window->default_widget)
GTK_WIDGET_SET_FLAGS (window->default_widget, GTK_HAS_DEFAULT);
}
gtk_widget_event (window->focus_widget, (GdkEvent*) &event);
}
window->focus_widget = focus;
if (window->focus_widget)
{
event.type = GDK_FOCUS_CHANGE;
event.window = window->focus_widget->window;
event.in = TRUE;
if (GTK_WIDGET_RECEIVES_DEFAULT (window->focus_widget) &&
(window->focus_widget != window->default_widget))
{
if (GTK_WIDGET_CAN_DEFAULT (window->focus_widget))
GTK_WIDGET_SET_FLAGS (window->focus_widget, GTK_HAS_DEFAULT);
if (window->default_widget)
GTK_WIDGET_UNSET_FLAGS (window->default_widget, GTK_HAS_DEFAULT);
}
gtk_widget_event (window->focus_widget, (GdkEvent*) &event);
}
if (window->default_widget &&
(def_flags != GTK_WIDGET_FLAGS (window->default_widget)))
gtk_widget_queue_draw (window->default_widget);
}
/*********************************
* Functions related to resizing *
*********************************/
static void
gtk_window_move_resize (GtkWindow *window)
{
GtkWidget *widget;
GtkContainer *container;
GtkWindowGeometryInfo *info;
GtkWindowLastGeometryInfo saved_last_info;
GdkGeometry new_geometry;
guint new_flags;
gint x, y;
gint width, height;
gint new_width, new_height;
gboolean default_size_changed = FALSE;
gboolean hints_changed = FALSE;
g_return_if_fail (GTK_IS_WINDOW (window));
g_return_if_fail (GTK_WIDGET_REALIZED (window));
widget = GTK_WIDGET (window);
container = GTK_CONTAINER (widget);
info = gtk_window_get_geometry_info (window, TRUE);
saved_last_info = info->last;
gtk_widget_size_request (widget, NULL);
gtk_window_compute_default_size (window, &new_width, &new_height);
if (info->last.width < 0 ||
info->last.width != new_width ||
info->last.height != new_height)
{
default_size_changed = TRUE;
info->last.width = new_width;
info->last.height = new_height;
/* We need to force a reposition in this case
*/
if (window->position == GTK_WIN_POS_CENTER_ALWAYS)
window->use_uposition = TRUE;
}
/* Compute new set of hints for the window
*/
gtk_window_compute_hints (window, &new_geometry, &new_flags);
if (!gtk_window_compare_hints (&info->last.geometry, info->last.flags,
&new_geometry, new_flags))
{
hints_changed = TRUE;
info->last.geometry = new_geometry;
info->last.flags = new_flags;
}
/* From the default size and the allocation, figure out the size
* the window should be.
*/
if (!default_size_changed ||
(!window->auto_shrink &&
new_width <= widget->allocation.width &&
new_height <= widget->allocation.height))
{
new_width = widget->allocation.width;
new_height = widget->allocation.height;
}
/* constrain the window size to the specified geometry */
gtk_window_constrain_size (window,
&new_geometry, new_flags,
new_width, new_height,
&new_width, &new_height);
/* compute new window position if a move is required
*/
gtk_window_compute_reposition (window, new_width, new_height, &x, &y);
if (x != 1 && y != -1 && !(new_flags & GDK_HINT_POS))
{
new_flags |= GDK_HINT_POS;
hints_changed = TRUE;
}
/* handle actual resizing:
* - handle reallocations due to configure events
* - figure whether we need to request a new window size
* - handle simple resizes within our widget tree
* - reposition window if neccessary
*/
width = widget->allocation.width;
height = widget->allocation.height;
if (window->handling_resize)
{
GtkAllocation allocation;
/* if we are just responding to a configure event, which
* might be due to a resize by the window manager, the
* user, or a response to a resizing request we made
* earlier, we go ahead, allocate the new size and we're done
* (see gtk_window_configure_event() for more details).
*/
window->handling_resize = FALSE;
allocation = widget->allocation;
gtk_widget_size_allocate (widget, &allocation);
gtk_widget_queue_draw (widget);
#ifdef FIXME_ZVT_ME_HARDER
if ((default_size_changed || hints_changed) && (width != new_width || height != new_height))
{
/* We could be here for two reasons
* 1) We coincidentally got a resize while handling
* another resize.
* 2) Our computation of default_size_changed was completely
* screwed up, probably because one of our children
* is broken (i.e. changes requisition during
* size allocation). It's probably a zvt widget.
*
* For 1), we could just go ahead and ask for the
* new size right now, but doing that for 2)
* might well be fighting the user (and can even
* trigger a loop). Since we really don't want to
* do that, we requeue a resize in hopes that
* by the time it gets handled, the child has seen
* the light and is willing to go along with the
* new size. (this happens for the zvt widget, since
* the size_allocate() above will have stored the
* requisition corresponding to the new size in the
* zvt widget)
*
* This doesn't buy us anything for 1), but it shouldn't
* hurt us too badly, since it is what would have
* happened if we had gotten the configure event before
* the new size had been set.
*/
if (x != -1 && y != -1)
{
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
*/
info->last = saved_last_info;
gtk_widget_queue_resize (widget);
return;
}
#endif /* FIXME_ZVT_ME_HARDER */
}
/* Now set hints if necessary
*/
if (hints_changed)
gdk_window_set_geometry_hints (widget->window,
&new_geometry,
new_flags);
if ((default_size_changed || hints_changed) &&
(width != new_width || height != new_height))
{
/* given that (width != new_width || height != new_height), we are in one
* of the following situations:
*
* default_size_changed
* our requisition has changed and we need a different window size,
* so we request it from the window manager.
*
* !default_size_changed
* the window manager wouldn't assign us the size we requested, in this
* case we don't try to request a new size with every resize.
*
* !default_size_changed && hints_changed
* the window manager rejects our size, but we have just changed the
* window manager hints, so there's a certain chance our request will
* be honoured this time, so we try again.
*/
/* request a new window size */
if (x != -1 && y != -1)
{
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
{
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
* resizing request. the configure event will cause a new resize
* with ->handling_resize=TRUE.
* until then, we want to
* - discard expose events
* - coalesce resizes for our children
* - defer any window resizes until the configure event arrived
* to achive this, we queue a resize for the window, but remove its
* resizing handler, so resizing will not be handled from the next
* idle handler but when the configure event arrives.
*
* FIXME: we should also dequeue the pending redraws here, since
* we handle those ourselves in ->handling_resize==TRUE.
*/
gtk_widget_queue_resize (GTK_WIDGET (container));
if (container->resize_mode == GTK_RESIZE_QUEUE)
gtk_container_dequeue_resize_handler (container);
}
else
{
if (x != -1 && y != -1)
{
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));
}
}
/* Compare two sets of Geometry hints for equality.
*/
static gboolean
gtk_window_compare_hints (GdkGeometry *geometry_a,
guint flags_a,
GdkGeometry *geometry_b,
guint flags_b)
{
if (flags_a != flags_b)
return FALSE;
if ((flags_a & GDK_HINT_MIN_SIZE) &&
(geometry_a->min_width != geometry_b->min_width ||
geometry_a->min_height != geometry_b->min_height))
return FALSE;
if ((flags_a & GDK_HINT_MAX_SIZE) &&
(geometry_a->max_width != geometry_b->max_width ||
geometry_a->max_height != geometry_b->max_height))
return FALSE;
if ((flags_a & GDK_HINT_BASE_SIZE) &&
(geometry_a->base_width != geometry_b->base_width ||
geometry_a->base_height != geometry_b->base_height))
return FALSE;
if ((flags_a & GDK_HINT_ASPECT) &&
(geometry_a->min_aspect != geometry_b->min_aspect ||
geometry_a->max_aspect != geometry_b->max_aspect))
return FALSE;
if ((flags_a & GDK_HINT_RESIZE_INC) &&
(geometry_a->width_inc != geometry_b->width_inc ||
geometry_a->height_inc != geometry_b->height_inc))
return FALSE;
return TRUE;
}
/* Compute the default_size for a window. The result will
* be stored in *width and *height. The default size is
* the size the window should have when initially mapped.
* This routine does not attempt to constrain the size
* to obey the geometry hints - that must be done elsewhere.
*/
static void
gtk_window_compute_default_size (GtkWindow *window,
guint *width,
guint *height)
{
GtkRequisition requisition;
GtkWindowGeometryInfo *info;
gtk_widget_get_child_requisition (GTK_WIDGET (window), &requisition);
*width = requisition.width;
*height = requisition.height;
info = gtk_window_get_geometry_info (window, FALSE);
if (*width == 0 && *height == 0)
{
/* empty window */
*width = 200;
*height = 200;
}
if (info)
{
*width = info->width > 0 ? info->width : *width;
*height = info->height > 0 ? info->height : *height;
}
}
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
*
* This routine is partially borrowed from fvwm.
*
* Copyright 1993, Robert Nation
* You may use this code for any purpose, as long as the original
* copyright remains in the source code and all documentation
*
* which in turn borrows parts of the algorithm from uwm
*/
static void
gtk_window_constrain_size (GtkWindow *window,
GdkGeometry *geometry,
guint flags,
gint width,
gint height,
gint *new_width,
gint *new_height)
{
gint min_width = 0;
gint min_height = 0;
gint base_width = 0;
gint base_height = 0;
gint xinc = 1;
gint yinc = 1;
gint max_width = G_MAXINT;
gint max_height = G_MAXINT;
#define FLOOR(value, base) ( ((gint) ((value) / (base))) * (base) )
if ((flags & GDK_HINT_BASE_SIZE) && (flags & GDK_HINT_MIN_SIZE))
{
base_width = geometry->base_width;
base_height = geometry->base_height;
min_width = geometry->min_width;
min_height = geometry->min_height;
}
else if (flags & GDK_HINT_BASE_SIZE)
{
base_width = geometry->base_width;
base_height = geometry->base_height;
min_width = geometry->base_width;
min_height = geometry->base_height;
}
else if (flags & GDK_HINT_MIN_SIZE)
{
base_width = geometry->min_width;
base_height = geometry->min_height;
min_width = geometry->min_width;
min_height = geometry->min_height;
}
if (flags & GDK_HINT_MAX_SIZE)
{
max_width = geometry->max_width ;
max_height = geometry->max_height;
}
if (flags & GDK_HINT_RESIZE_INC)
{
xinc = MAX (xinc, geometry->width_inc);
yinc = MAX (yinc, geometry->height_inc);
}
/* clamp width and height to min and max values
*/
width = CLAMP (width, min_width, max_width);
height = CLAMP (height, min_height, max_height);
/* shrink to base + N * inc
*/
width = base_width + FLOOR (width - base_width, xinc);
height = base_height + FLOOR (height - base_height, yinc);
/* constrain aspect ratio, according to:
*
* width
* min_aspect <= -------- <= max_aspect
* height
*/
if (flags & GDK_HINT_ASPECT &&
geometry->min_aspect > 0 &&
geometry->max_aspect > 0)
{
gint delta;
if (geometry->min_aspect * height > width)
{
delta = FLOOR (height - width * geometry->min_aspect, yinc);
if (height - delta >= min_height)
height -= delta;
else
{
delta = FLOOR (height * geometry->min_aspect - width, xinc);
if (width + delta <= max_width)
width += delta;
}
}
if (geometry->max_aspect * height < width)
{
delta = FLOOR (width - height * geometry->max_aspect, xinc);
if (width - delta >= min_width)
width -= delta;
else
{
delta = FLOOR (width / geometry->max_aspect - height, yinc);
if (height + delta <= max_height)
height += delta;
}
}
}
#undef FLOOR
*new_width = width;
*new_height = height;
}
/* Compute the set of geometry hints and flags for a window
* based on the application set geometry, and requisiition
* of the window. gtk_widget_size_request() must have been
* called first.
*/
static void
gtk_window_compute_hints (GtkWindow *window,
GdkGeometry *new_geometry,
guint *new_flags)
{
GtkWidget *widget;
GtkWidgetAuxInfo *aux_info;
gint ux, uy;
gint extra_width = 0;
gint extra_height = 0;
GtkWindowGeometryInfo *geometry_info;
GtkRequisition requisition;
g_return_if_fail (GTK_IS_WINDOW (window));
widget = GTK_WIDGET (window);
gtk_widget_get_child_requisition (widget, &requisition);
geometry_info = gtk_window_get_geometry_info (GTK_WINDOW (widget), FALSE);
g_return_if_fail (geometry_info != NULL);
*new_flags = geometry_info->mask;
*new_geometry = geometry_info->geometry;
if (geometry_info->widget)
{
extra_width = widget->requisition.width - geometry_info->widget->requisition.width;
extra_height = widget->requisition.height - geometry_info->widget->requisition.height;
}
ux = 0;
uy = 0;
aux_info = gtk_object_get_data (GTK_OBJECT (widget), "gtk-aux-info");
if (aux_info && (aux_info->x != -1) && (aux_info->y != -1))
{
ux = aux_info->x;
uy = aux_info->y;
*new_flags |= GDK_HINT_POS;
}
if (*new_flags & GDK_HINT_BASE_SIZE)
{
new_geometry->base_width += extra_width;
new_geometry->base_height += extra_height;
}
else if (!(*new_flags & GDK_HINT_MIN_SIZE) &&
(*new_flags & GDK_HINT_RESIZE_INC) &&
((extra_width != 0) || (extra_height != 0)))
{
*new_flags |= GDK_HINT_BASE_SIZE;
new_geometry->base_width = extra_width;
new_geometry->base_height = extra_height;
}
if (*new_flags & GDK_HINT_MIN_SIZE)
{
if (new_geometry->min_width < 0)
new_geometry->min_width = requisition.width;
else
new_geometry->min_width += extra_width;
if (new_geometry->min_height < 0)
new_geometry->min_width = requisition.height;
else
new_geometry->min_height += extra_height;
}
else if (!window->allow_shrink)
{
*new_flags |= GDK_HINT_MIN_SIZE;
new_geometry->min_width = requisition.width;
new_geometry->min_height = requisition.height;
}
if (*new_flags & GDK_HINT_MAX_SIZE)
{
if (new_geometry->max_width < 0)
new_geometry->max_width = requisition.width;
else
new_geometry->max_width += extra_width;
if (new_geometry->max_height < 0)
new_geometry->max_width = requisition.height;
else
new_geometry->max_height += extra_height;
}
else if (!window->allow_grow)
{
*new_flags |= GDK_HINT_MAX_SIZE;
new_geometry->max_width = requisition.width;
new_geometry->max_height = requisition.height;
}
}
/* Compute a new position for the window based on a new
* size. *x and *y will be set to the new coordinates, or to -1 if the
* window does not need to be moved
*/
static void
gtk_window_compute_reposition (GtkWindow *window,
gint new_width,
gint new_height,
gint *x,
gint *y)
{
GtkWidget *widget;
GtkWindowPosition pos;
GtkWidget *parent_widget;
widget = GTK_WIDGET (window);
*x = -1;
*y = -1;
parent_widget = (GtkWidget*) window->transient_parent;
pos = window->position;
if (pos == GTK_WIN_POS_CENTER_ON_PARENT &&
(parent_widget == NULL ||
!GTK_WIDGET_MAPPED (parent_widget)))
pos = GTK_WIN_POS_NONE;
switch (pos)
{
case GTK_WIN_POS_CENTER:
case GTK_WIN_POS_CENTER_ALWAYS:
if (window->use_uposition)
{
gint screen_width = gdk_screen_width ();
gint screen_height = gdk_screen_height ();
*x = (screen_width - new_width) / 2;
*y = (screen_height - new_height) / 2;
}
break;
case GTK_WIN_POS_CENTER_ON_PARENT:
if (window->use_uposition)
{
gint 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;
}
break;
case GTK_WIN_POS_MOUSE:
if (window->use_uposition)
{
gint screen_width = gdk_screen_width ();
gint screen_height = gdk_screen_height ();
gdk_window_get_pointer (NULL, x, y, NULL);
*x -= new_width / 2;
*y -= new_height / 2;
*x = CLAMP (*x, 0, screen_width - new_width);
*y = CLAMP (*y, 0, screen_height - new_height);
}
break;
default:
if (window->use_uposition)
{
GtkWidgetAuxInfo *aux_info;
aux_info = gtk_object_get_data (GTK_OBJECT (window), "gtk-aux-info");
if (aux_info &&
aux_info->x != -1 && aux_info->y != -1 &&
aux_info->x != -2 && aux_info->y != -2)
{
*x = aux_info->x;
*y = aux_info->y;
}
}
break;
}
if (*x != -1 && *y != -1)
{
GtkWidgetAuxInfo *aux_info;
/* we handle necessary window positioning by hand here,
* so we can coalesce the window movement with possible
* resizes to get only one configure event.
* keep this in sync with gtk_widget_set_uposition()
* and gtk_window_reposition().
*/
gtk_widget_set_uposition (widget, -1, -1); /* ensure we have aux_info */
aux_info = gtk_object_get_data (GTK_OBJECT (widget), "gtk-aux-info");
aux_info->x = *x;
aux_info->y = *y;
window->use_uposition = FALSE;
}
}
/***********************
* Redrawing functions *
***********************/
static void
gtk_window_paint (GtkWidget *widget,
GdkRectangle *area)
{
gtk_paint_flat_box (widget->style, widget->window, GTK_STATE_NORMAL,
GTK_SHADOW_NONE, area, widget, "base", 0, 0, -1, -1);
}
static gint
gtk_window_expose (GtkWidget *widget,
GdkEventExpose *event)
{
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);
if (!GTK_WIDGET_APP_PAINTABLE (widget))
gtk_window_paint (widget, &event->area);
if (GTK_WIDGET_CLASS (parent_class)->expose_event)
return GTK_WIDGET_CLASS (parent_class)->expose_event (widget, event);
return TRUE;
}
/**
* gtk_window_set_has_frame:
* @window: a #GtkWindow
*
* If this function is called on a window before it is realized
* or showed it will have a "frame" window around widget-window,
* accessible in window->frame. Using the signal frame_event
* you can recieve all events targeted at the frame.
*
* This function is used by the linux-fb port to implement managed
* windows, but it could concievably be used by X-programs that
* want to do their own window decorations.
**/
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;
}
/**
* gtk_window_set_frame_dimensions:
* @window: a #GtkWindow that has a frame
* @left: The width of the left border
* @top: The height of the top border
* @right: The width of the right border
* @bottom: The height of the bottom border
*
* For windows with frames (see #gtk_window_set_has_frame) this function
* can be used to change the size of the frame border.
**/
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);
}
}