Commit 4a18fe7e authored by Andrea Cimitan's avatar Andrea Cimitan Committed by Cosimo Cecchi

Introduce gtk_window_get/set_attached_to()

gtk_window_get/set_attached_to() is a new API that allows for windows to
be attached to a GtkWidget.
The attachment is a logical binding between the toplevel window and the
widget that generated it; this kind of information is currently used to
propagate style information from the widget to the window, but is also
useful e.g. for accessibility.

https://bugzilla.gnome.org/show_bug.cgi?id=666103
parent 133179fd
...@@ -5294,6 +5294,7 @@ gtk_window_set_gravity ...@@ -5294,6 +5294,7 @@ gtk_window_set_gravity
gtk_window_get_gravity gtk_window_get_gravity
gtk_window_set_position gtk_window_set_position
gtk_window_set_transient_for gtk_window_set_transient_for
gtk_window_set_attached_to
gtk_window_set_destroy_with_parent gtk_window_set_destroy_with_parent
gtk_window_set_hide_titlebar_when_maximized gtk_window_set_hide_titlebar_when_maximized
gtk_window_set_screen gtk_window_set_screen
...@@ -5352,6 +5353,7 @@ gtk_window_get_role ...@@ -5352,6 +5353,7 @@ gtk_window_get_role
gtk_window_get_size gtk_window_get_size
gtk_window_get_title gtk_window_get_title
gtk_window_get_transient_for gtk_window_get_transient_for
gtk_window_get_attached_to
gtk_window_get_type_hint gtk_window_get_type_hint
gtk_window_get_skip_taskbar_hint gtk_window_get_skip_taskbar_hint
gtk_window_get_skip_pager_hint gtk_window_get_skip_pager_hint
......
...@@ -3820,6 +3820,7 @@ gtk_window_get_skip_pager_hint ...@@ -3820,6 +3820,7 @@ gtk_window_get_skip_pager_hint
gtk_window_get_skip_taskbar_hint gtk_window_get_skip_taskbar_hint
gtk_window_get_title gtk_window_get_title
gtk_window_get_transient_for gtk_window_get_transient_for
gtk_window_get_attached_to
gtk_window_get_type gtk_window_get_type
gtk_window_get_type_hint gtk_window_get_type_hint
gtk_window_get_urgency_hint gtk_window_get_urgency_hint
...@@ -3891,6 +3892,7 @@ gtk_window_set_skip_taskbar_hint ...@@ -3891,6 +3892,7 @@ gtk_window_set_skip_taskbar_hint
gtk_window_set_startup_id gtk_window_set_startup_id
gtk_window_set_title gtk_window_set_title
gtk_window_set_transient_for gtk_window_set_transient_for
gtk_window_set_attached_to
gtk_window_set_type_hint gtk_window_set_type_hint
gtk_window_set_urgency_hint gtk_window_set_urgency_hint
gtk_window_set_wmclass gtk_window_set_wmclass
......
...@@ -1202,9 +1202,8 @@ gtk_menu_attach_to_widget (GtkMenu *menu, ...@@ -1202,9 +1202,8 @@ gtk_menu_attach_to_widget (GtkMenu *menu,
if (gtk_widget_get_state_flags (GTK_WIDGET (menu)) != 0) if (gtk_widget_get_state_flags (GTK_WIDGET (menu)) != 0)
gtk_widget_set_state_flags (GTK_WIDGET (menu), 0, TRUE); gtk_widget_set_state_flags (GTK_WIDGET (menu), 0, TRUE);
/* we don't need to set the style here, since /* Attach the widget to the toplevel window. */
* we are a toplevel widget. gtk_window_set_attached_to (GTK_WINDOW (menu->priv->toplevel), attach_widget);
*/
/* Fallback title for menu comes from attach widget */ /* Fallback title for menu comes from attach widget */
gtk_menu_update_title (menu); gtk_menu_update_title (menu);
...@@ -1258,6 +1257,9 @@ gtk_menu_detach (GtkMenu *menu) ...@@ -1258,6 +1257,9 @@ gtk_menu_detach (GtkMenu *menu)
} }
g_object_set_data (G_OBJECT (menu), I_(attach_data_key), NULL); g_object_set_data (G_OBJECT (menu), I_(attach_data_key), NULL);
/* Detach the toplevel window. */
gtk_window_set_attached_to (GTK_WINDOW (menu->priv->toplevel), NULL);
g_signal_handlers_disconnect_by_func (data->attach_widget, g_signal_handlers_disconnect_by_func (data->attach_widget,
(gpointer) attach_widget_screen_changed, (gpointer) attach_widget_screen_changed,
menu); menu);
......
...@@ -372,6 +372,11 @@ struct _GtkWidgetPrivate ...@@ -372,6 +372,11 @@ struct _GtkWidgetPrivate
*/ */
gchar *name; gchar *name;
/* The list of attached windows to this widget.
* We keep a list in order to call reset_style to all of them,
* recursively. */
GList *attached_windows;
/* The style for the widget. The style contains the /* The style for the widget. The style contains the
* colors the widget should be drawn in for each state * colors the widget should be drawn in for each state
* along with graphics contexts used to draw with and * along with graphics contexts used to draw with and
...@@ -8314,6 +8319,9 @@ gtk_widget_reset_style (GtkWidget *widget) ...@@ -8314,6 +8319,9 @@ gtk_widget_reset_style (GtkWidget *widget)
g_return_if_fail (GTK_IS_WIDGET (widget)); g_return_if_fail (GTK_IS_WIDGET (widget));
reset_style_recurse (widget, NULL); reset_style_recurse (widget, NULL);
g_list_foreach (widget->priv->attached_windows,
(GFunc) reset_style_recurse, NULL);
} }
#ifdef G_ENABLE_DEBUG #ifdef G_ENABLE_DEBUG
...@@ -13712,6 +13720,20 @@ _gtk_widget_get_sizegroups (GtkWidget *widget) ...@@ -13712,6 +13720,20 @@ _gtk_widget_get_sizegroups (GtkWidget *widget)
return NULL; return NULL;
} }
void
_gtk_widget_add_attached_window (GtkWidget *widget,
GtkWindow *window)
{
widget->priv->attached_windows = g_list_prepend (widget->priv->attached_windows, window);
}
void
_gtk_widget_remove_attached_window (GtkWidget *widget,
GtkWindow *window)
{
widget->priv->attached_windows = g_list_remove (widget->priv->attached_windows, window);
}
/** /**
* gtk_widget_path_append_for_widget: * gtk_widget_path_append_for_widget:
* @path: a widget path * @path: a widget path
...@@ -13800,7 +13822,15 @@ gtk_widget_get_path (GtkWidget *widget) ...@@ -13800,7 +13822,15 @@ gtk_widget_get_path (GtkWidget *widget)
* where style properties might be retrieved on that * where style properties might be retrieved on that
* situation. * situation.
*/ */
widget->priv->path = gtk_widget_path_new (); GtkWidget *attach_widget = NULL;
if (GTK_IS_WINDOW (widget))
attach_widget = gtk_window_get_attached_to (GTK_WINDOW (widget));
if (attach_widget != NULL)
widget->priv->path = gtk_widget_path_copy (gtk_widget_get_path (attach_widget));
else
widget->priv->path = gtk_widget_path_new ();
gtk_widget_path_append_for_widget (widget->priv->path, widget); gtk_widget_path_append_for_widget (widget->priv->path, widget);
} }
......
...@@ -100,6 +100,11 @@ void _gtk_widget_remove_sizegroup (GtkWidget *widget, ...@@ -100,6 +100,11 @@ void _gtk_widget_remove_sizegroup (GtkWidget *widget,
gpointer group); gpointer group);
GSList *_gtk_widget_get_sizegroups (GtkWidget *widget); GSList *_gtk_widget_get_sizegroups (GtkWidget *widget);
void _gtk_widget_add_attached_window (GtkWidget *widget,
GtkWindow *window);
void _gtk_widget_remove_attached_window (GtkWidget *widget,
GtkWindow *window);
void _gtk_widget_override_size_request (GtkWidget *widget, void _gtk_widget_override_size_request (GtkWidget *widget,
int width, int width,
int height, int height,
......
...@@ -105,6 +105,7 @@ struct _GtkWindowPrivate ...@@ -105,6 +105,7 @@ struct _GtkWindowPrivate
{ {
GtkMnemonicHash *mnemonic_hash; GtkMnemonicHash *mnemonic_hash;
GtkWidget *attach_widget;
GtkWidget *default_widget; GtkWidget *default_widget;
GtkWidget *focus_widget; GtkWidget *focus_widget;
GtkWindow *transient_parent; GtkWindow *transient_parent;
...@@ -223,6 +224,7 @@ enum { ...@@ -223,6 +224,7 @@ enum {
PROP_DELETABLE, PROP_DELETABLE,
PROP_GRAVITY, PROP_GRAVITY,
PROP_TRANSIENT_FOR, PROP_TRANSIENT_FOR,
PROP_ATTACHED_TO,
PROP_OPACITY, PROP_OPACITY,
PROP_HAS_RESIZE_GRIP, PROP_HAS_RESIZE_GRIP,
PROP_RESIZE_GRIP_VISIBLE, PROP_RESIZE_GRIP_VISIBLE,
...@@ -967,6 +969,21 @@ gtk_window_class_init (GtkWindowClass *klass) ...@@ -967,6 +969,21 @@ gtk_window_class_init (GtkWindowClass *klass)
GTK_TYPE_WINDOW, GTK_TYPE_WINDOW,
GTK_PARAM_READWRITE| G_PARAM_CONSTRUCT)); GTK_PARAM_READWRITE| G_PARAM_CONSTRUCT));
/**
* GtkWindow:attached-to:
*
* the widget attached to the window.
*
* Since: 3.4
*/
g_object_class_install_property (gobject_class,
PROP_ATTACHED_TO,
g_param_spec_object ("attached-to",
P_("Attached to Widget"),
P_("The widget where the window is attached"),
GTK_TYPE_WIDGET,
GTK_PARAM_READWRITE| G_PARAM_CONSTRUCT));
/** /**
* GtkWindow:opacity: * GtkWindow:opacity:
* *
...@@ -1277,6 +1294,9 @@ gtk_window_set_property (GObject *object, ...@@ -1277,6 +1294,9 @@ gtk_window_set_property (GObject *object,
case PROP_TRANSIENT_FOR: case PROP_TRANSIENT_FOR:
gtk_window_set_transient_for (window, g_value_get_object (value)); gtk_window_set_transient_for (window, g_value_get_object (value));
break; break;
case PROP_ATTACHED_TO:
gtk_window_set_attached_to (window, g_value_get_object (value));
break;
case PROP_OPACITY: case PROP_OPACITY:
gtk_window_set_opacity (window, g_value_get_double (value)); gtk_window_set_opacity (window, g_value_get_double (value));
break; break;
...@@ -1398,6 +1418,9 @@ gtk_window_get_property (GObject *object, ...@@ -1398,6 +1418,9 @@ gtk_window_get_property (GObject *object,
case PROP_TRANSIENT_FOR: case PROP_TRANSIENT_FOR:
g_value_set_object (value, gtk_window_get_transient_for (window)); g_value_set_object (value, gtk_window_get_transient_for (window));
break; break;
case PROP_ATTACHED_TO:
g_value_set_object (value, gtk_window_get_attached_to (window));
break;
case PROP_OPACITY: case PROP_OPACITY:
g_value_set_double (value, gtk_window_get_opacity (window)); g_value_set_double (value, gtk_window_get_opacity (window));
break; break;
...@@ -2375,6 +2398,20 @@ gtk_window_list_toplevels (void) ...@@ -2375,6 +2398,20 @@ gtk_window_list_toplevels (void)
return list; return list;
} }
static void
remove_attach_widget (GtkWindow *window)
{
GtkWindowPrivate *priv = window->priv;
if (priv->attach_widget)
{
_gtk_widget_remove_attached_window (priv->attach_widget, window);
g_object_unref (priv->attach_widget);
priv->attach_widget = NULL;
}
}
static void static void
gtk_window_dispose (GObject *object) gtk_window_dispose (GObject *object)
{ {
...@@ -2383,6 +2420,8 @@ gtk_window_dispose (GObject *object) ...@@ -2383,6 +2420,8 @@ gtk_window_dispose (GObject *object)
gtk_window_set_focus (window, NULL); gtk_window_set_focus (window, NULL);
gtk_window_set_default (window, NULL); gtk_window_set_default (window, NULL);
remove_attach_widget (GTK_WINDOW (object));
G_OBJECT_CLASS (gtk_window_parent_class)->dispose (object); G_OBJECT_CLASS (gtk_window_parent_class)->dispose (object);
} }
...@@ -2573,6 +2612,69 @@ gtk_window_get_transient_for (GtkWindow *window) ...@@ -2573,6 +2612,69 @@ gtk_window_get_transient_for (GtkWindow *window)
return window->priv->transient_parent; return window->priv->transient_parent;
} }
/**
* gtk_window_set_attached_to:
* @window: a #GtkWindow
* @attach_widget (allow-none): a #GtkWidget, or %NULL
*
* Attach the window to a widget. Indicates that @window belongs to @widget.
* For example the window of a GtkMenu could belong to a GtkMenuBar or
* a GtkEntry or a GtkComboBox, and so on...
*
* GTK will use this information for styling the @window,
* for presenting it as a child of @widget in the accessibility tree
* and other things.
*
* Passing %NULL for @attach_widget detaches the window.
*
* Since: 3.4
**/
void
gtk_window_set_attached_to (GtkWindow *window,
GtkWidget *attach_widget)
{
GtkWindowPrivate *priv;
g_return_if_fail (GTK_IS_WINDOW (window));
g_return_if_fail (GTK_WIDGET (window) != attach_widget);
priv = window->priv;
remove_attach_widget (window);
priv->attach_widget = attach_widget;
if (priv->attach_widget)
{
_gtk_widget_add_attached_window (priv->attach_widget, window);
g_object_ref_sink (priv->attach_widget);
}
/* Update the style, as the widget path might change. */
gtk_widget_reset_style (GTK_WIDGET (window));
}
/**
* gtk_window_get_attached_to:
* @window: a #GtkWindow
*
* Fetches the attach widget for this window. See
* gtk_window_set_attached_to().
*
* Return value: (transfer none): the widget where the window is attached,
* or %NULL if the window is not attached to any widget.
*
* Since: 3.4
**/
GtkWidget *
gtk_window_get_attached_to (GtkWindow *window)
{
g_return_val_if_fail (GTK_IS_WINDOW (window), NULL);
return window->priv->attach_widget;
}
/** /**
* gtk_window_set_opacity: * gtk_window_set_opacity:
* @window: a #GtkWindow * @window: a #GtkWindow
...@@ -4603,6 +4705,8 @@ gtk_window_destroy (GtkWidget *widget) ...@@ -4603,6 +4705,8 @@ gtk_window_destroy (GtkWidget *widget)
if (priv->transient_parent) if (priv->transient_parent)
gtk_window_set_transient_for (window, NULL); gtk_window_set_transient_for (window, NULL);
remove_attach_widget (GTK_WINDOW (widget));
/* frees the icons */ /* frees the icons */
gtk_window_set_icon_list (window, NULL); gtk_window_set_icon_list (window, NULL);
......
...@@ -135,6 +135,9 @@ gboolean gtk_window_activate_default (GtkWindow *window); ...@@ -135,6 +135,9 @@ gboolean gtk_window_activate_default (GtkWindow *window);
void gtk_window_set_transient_for (GtkWindow *window, void gtk_window_set_transient_for (GtkWindow *window,
GtkWindow *parent); GtkWindow *parent);
GtkWindow *gtk_window_get_transient_for (GtkWindow *window); GtkWindow *gtk_window_get_transient_for (GtkWindow *window);
void gtk_window_set_attached_to (GtkWindow *window,
GtkWidget *attach_widget);
GtkWidget *gtk_window_get_attached_to (GtkWindow *window);
void gtk_window_set_opacity (GtkWindow *window, void gtk_window_set_opacity (GtkWindow *window,
gdouble opacity); gdouble opacity);
gdouble gtk_window_get_opacity (GtkWindow *window); gdouble gtk_window_get_opacity (GtkWindow *window);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment