forked from AuroraMiddleware/gtk
9595c55184
Fri May 12 17:13:32 2000 Tim Janik <timj@gtk.org> * docs/Changes-1.4.txt: documented necessary changes for 1.4 transition. * gtk/gtktext.c: made the adjustments no-construct args, simply provide default adjustments. (gtk_text_destroy): release adjustments. * gtk/gtkprogressbar.c (gtk_progress_bar_class_init): made the adjustment argument non-construct. * gtk/gtkprogress.c (gtk_progress_destroy): release adjustment here, instead of in finalize. (gtk_progress_get_text_from_value): (gtk_progress_get_current_text): (gtk_progress_set_value): (gtk_progress_get_percentage_from_value): (gtk_progress_get_current_percentage): (gtk_progress_set_percentage): (gtk_progress_configure): ensure an adjustment is present. Thu May 11 01:24:08 2000 Tim Janik <timj@gtk.org> * gtk/gtkcolorsel.[hc]: * gtk/gtkcolorseldialog.[hc]: * gtk/gtkhsv.[hc]: major code cleanups, destroy handlers need to chain their parent implementation, use bit fields for boolean values, don't create unused widgets, usage of glib types, braces go on their own lines, function argument alignment, #include directives etc. etc. etc.. * gtk/Makefile.am (gtk_public_h_sources): install gtkhsv.h. Wed May 10 23:29:52 2000 Tim Janik <timj@gtk.org> * gtk/gtktoolbar.c (gtk_toolbar_destroy): don't unref a NULL tooltips. * gtk/gtkfilesel.c (gtk_file_selection_destroy): don't free a cmpl_state of NULL. * gtk/gtkcombo.c (gtk_combo_item_destroy): don#t keep references to freed data. (gtk_combo_destroy): don't keep a pointer to a destroyed window. * gtk/gtkmenu.c (gtk_menu_init): reset the menu's toplevel pointer to NULL when the toplevel is getting destroyed. (gtk_menu_set_tearoff_state): same here for the tearoff_window. (gtk_menu_destroy): (gtk_menu_init): store the information of whether we have to readd the initial child ref_count during destruction in a new GtkMenu field needs_destruction_ref_count. * gtk/gtkviewport.c: SHAME! ok this one is tricky, so i note it here, those reading: learn from my mistake! ;) in order for set_?adjustment to support a default adjustemnt if invoked with an adjustment pointer of NULL, the code read (pseudo): if (v->adjustment) unref (v->adjustment); if (!adjustment) adjustment = adjustment_new (); if (v->adjustment != adjustment) v->adjustment = ref (adjustment); now imagine the first unref to actually free the old adjustment and adjustment_new() creating a new adjustment from the very same memory portion. here, the latter comparision will unintendedly fail, and all hell breaks loose. (gtk_viewport_set_hadjustment): (gtk_viewport_set_vadjustment): reset viewport->?adjustment to NULL after unreferencing it. * gtk/gtkcontainer.[hc]: removed toplevel registration functions: gtk_container_register_toplevel(), gtk_container_unregister_toplevel() and gtk_container_get_toplevels() which had wrong semantics anyways: it didn't reference and copy the list. * gtk/gtkwindow.c: we take over the container toplevel registration bussiness now. windows are registered across multiple destructions, untill they are finalized. the initial implicit reference count users are holding on windows is removed with the first destruction though. (gtk_window_init): ref & sink and set has_user_ref_count, got rid of gtk_container_register_toplevel() call. add window to toplevel_list. (gtk_window_destroy): unref the window if has_user_ref_count is still set, got rid of call to gtk_container_unregister_toplevel(). (gtk_window_finalize): remove window from toplevel list. (gtk_window_list_toplevels): new function to return a newly created list with referenced toplevels. (gtk_window_read_rcfiles): use gtk_window_list_toplevels(). * gtk/gtkhscale.c (gtk_hscale_class_init): made the GtkRange adjustment a non-construct arg. * gtk/gtkvscale.c (gtk_vscale_class_init): likewise. * gtk/gtkhscrollbar.c (gtk_vscrollbar_class_init): likewise. * gtk/gtkvscrollbar.c (gtk_vscrollbar_class_init): likewise. * gtk/gtkrange.c: added some realized checks. (gtk_range_destroy): get rid of the h/v adjustments in the destroy handler instead of finalize. remove timer. (gtk_range_get_adjustment): demand create adjustment. * gtk/gtkviewport.c: made h/v adjustment non-construct args. we simply create them on demand now and get rid of them in the destroy handler. (gtk_viewport_destroy): get rid of the h/v adjustments in the destroy handler instead of finalize. (gtk_viewport_get_hadjustment): (gtk_viewport_get_vadjustment): (gtk_viewport_size_allocate): demand create h/v adjustment if required. * gtk/gtkwidget.c (gtk_widget_finalize): duplicate part of the gtk_widget_real_destroy () functionality. (gtk_widget_real_destroy): reinitialize with a new style, instead of setting widget->style to NULL. Fri May 5 13:02:09 2000 Tim Janik <timj@gtk.org> * gtk/gtkcalendar.c: * gtk/gtkbutton.c: ported _get_type() implementation over to GType, either to preserve memchunks allocation facilities, or because Gtk+ 1.0 GtkTypeInfo was still being used. * gtk/gtkobject.[hc]: derive from GObject. ported various functions over. prepare for ::destroy to be emitted multiple times. removed reference tracer magic. chain into GObjectClass.shutdown() to emit ::destroy signal. * gtk/gtksignal.c: removed assumptions about GTK_TYPE_OBJECT being fundamental. * gtk/gtkmain.c: removed gtk_object_post_arg_parsing_init() cludge. * gtk/gtksocket.c: * gtk/gtkplug.c: * gtk/gtklayout.c: * gtk/gtklabel.c: * gtk/gtkargcollector.c: * gtk/gtkarg.c: various fixups to work with GTK_TYPE_OBJECT not being a fundamental anymore, and to work with the new type system (nuked fundamental type varargs clutter). * gtk/*.c: install finalize handlers in the GObjectClass part of the class structure. changed direct GTK_OBJECT()->klass accesses to GTK_*_GET_CLASS(). changed direct object_class->type accesses to GTK_CLASS_TYPE(). * gtktypeutils.[hc]: use the reserved fundamental ids provided by GType. made most of the GTK_*() type macros and Gtk* typedefs simple wrappers around macros and types provided by GType. most notably, a significant portion of the old API vanished: GTK_TYPE_MAKE(), GTK_TYPE_SEQNO(), GTK_TYPE_FLAT_FIRST, GTK_TYPE_FLAT_LAST, GTK_TYPE_STRUCTURED_FIRST, GTK_TYPE_STRUCTURED_LAST, GTK_TYPE_ARGS, GTK_TYPE_CALLBACK, GTK_TYPE_C_CALLBACK, GTK_TYPE_FOREIGN, GtkTypeQuery, gtk_type_query(), gtk_type_set_varargs_type(), gtk_type_get_varargs_type(), gtk_type_check_object_cast(), gtk_type_check_class_cast(), gtk_type_describe_tree(), gtk_type_describe_heritage(), gtk_type_free(), gtk_type_children_types(), gtk_type_set_chunk_alloc(), gtk_type_register_enum(), gtk_type_register_flags(), gtk_type_parent_class(). replacements, where available are described in ../docs/Changes-1.4.txt. implemented compatibility functions for the remaining API. * configure.in: depend on glib 1.3.1, use gobject module.
2161 lines
60 KiB
C
2161 lines
60 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 Library 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
|
|
* Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Library 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-1999. 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"
|
|
#endif
|
|
|
|
#include "gtkprivate.h"
|
|
#include "gtkrc.h"
|
|
#include "gtksignal.h"
|
|
#include "gtkwindow.h"
|
|
#include "gtkbindings.h"
|
|
#include "gtkmain.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,
|
|
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
|
|
};
|
|
|
|
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_size_request (GtkWidget *widget,
|
|
GtkRequisition *requisition);
|
|
static void gtk_window_size_allocate (GtkWidget *widget,
|
|
GtkAllocation *allocation);
|
|
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 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_draw (GtkWidget *widget,
|
|
GdkRectangle *area);
|
|
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;
|
|
|
|
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);
|
|
|
|
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_NONE__POINTER,
|
|
GTK_TYPE_NONE, 1,
|
|
GTK_TYPE_WIDGET);
|
|
|
|
gtk_object_class_add_signals (object_class, window_signals, LAST_SIGNAL);
|
|
|
|
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->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->draw = gtk_window_draw;
|
|
widget_class->expose_event = gtk_window_expose;
|
|
|
|
container_class->check_resize = gtk_window_check_resize;
|
|
|
|
klass->set_focus = gtk_window_real_set_focus;
|
|
}
|
|
|
|
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;
|
|
|
|
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);
|
|
}
|
|
|
|
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;
|
|
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;
|
|
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);
|
|
}
|
|
|
|
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)
|
|
{
|
|
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)
|
|
{
|
|
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));
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
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
|
|
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);
|
|
|
|
window->transient_parent = NULL;
|
|
}
|
|
}
|
|
|
|
void
|
|
gtk_window_set_transient_for (GtkWindow *window,
|
|
GtkWindow *parent)
|
|
{
|
|
g_return_if_fail (window != 0);
|
|
|
|
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 (GTK_WIDGET_REALIZED (window) &&
|
|
GTK_WIDGET_REALIZED (parent))
|
|
gtk_window_transient_parent_realized (GTK_WIDGET (parent),
|
|
GTK_WIDGET (window));
|
|
}
|
|
}
|
|
|
|
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_unset_transient_for (window);
|
|
|
|
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;
|
|
|
|
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);
|
|
|
|
if (GTK_WIDGET_REALIZED (widget))
|
|
gdk_window_resize (widget->window, width, height);
|
|
else
|
|
gtk_widget_realize (widget);
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
static void
|
|
gtk_window_unmap (GtkWidget *widget)
|
|
{
|
|
GtkWindow *window;
|
|
|
|
g_return_if_fail (widget != NULL);
|
|
g_return_if_fail (GTK_IS_WINDOW (widget));
|
|
|
|
GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
|
|
gdk_window_hide (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;
|
|
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.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);
|
|
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 (NULL, &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);
|
|
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_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);
|
|
}
|
|
}
|
|
|
|
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.
|
|
*/
|
|
GList *list, *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 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 (window->default_widget)
|
|
{
|
|
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);
|
|
GTK_WIDGET_UNSET_FLAGS (window->default_widget, GTK_HAS_DEFAULT);
|
|
}
|
|
else
|
|
{
|
|
GTK_WIDGET_SET_FLAGS (window->default_widget, GTK_HAS_DEFAULT);
|
|
}
|
|
}
|
|
|
|
gtk_widget_event (window->focus_widget, (GdkEvent*) &event);
|
|
}
|
|
else if (window->default_widget)
|
|
{
|
|
GTK_WIDGET_SET_FLAGS (window->default_widget, GTK_HAS_DEFAULT);
|
|
}
|
|
|
|
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)
|
|
gdk_window_move (widget->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)
|
|
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);
|
|
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)
|
|
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;
|
|
}
|
|
}
|
|
|
|
/* 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)
|
|
{
|
|
new_geometry->min_width += extra_width;
|
|
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)
|
|
{
|
|
new_geometry->max_width += extra_width;
|
|
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;
|
|
|
|
widget = GTK_WIDGET (window);
|
|
|
|
*x = -1;
|
|
*y = -1;
|
|
|
|
switch (window->position)
|
|
{
|
|
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_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;
|
|
}
|
|
|
|
static void
|
|
gtk_window_draw (GtkWidget *widget,
|
|
GdkRectangle *area)
|
|
{
|
|
if (!GTK_WIDGET_APP_PAINTABLE (widget))
|
|
gtk_window_paint (widget, area);
|
|
|
|
if (GTK_WIDGET_CLASS (parent_class)->draw)
|
|
(* GTK_WIDGET_CLASS (parent_class)->draw) (widget, area);
|
|
}
|