gtk2/gtk/a11y/gtkwindowaccessible.c
Matthias Clasen 9a65ed9ada window: Derive from GtkWidget
We want to remove GtkBin and GtkContainer as they don't
provide much useful functionality anymore. This requires
us to move get_request_mode and compute_expand down.

Update the accessible implementation to match, remove
remnants of container implementations in GtkWindow
subclasses, and fix livecycle issues around destroy
vs dispose in GtkAssistant.

After this commit, using gtk_container_add on window
subclasses is not allowed anymore, but adding childing
with <child> in ui files still works.

See #2681
2020-05-04 22:53:08 -04:00

345 lines
10 KiB
C

/* GTK+ - accessibility implementations
* Copyright 2011, F123 Consulting & Mais Diferenças
* Copyright 2001, 2002, 2003 Sun Microsystems Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "gtkwindowaccessibleprivate.h"
#include "gtkaccessibility.h"
#include "gtktoplevelaccessible.h"
#include "gtkwidgetaccessibleprivate.h"
#include "gtklabel.h"
#include "gtkwidgetprivate.h"
#include "gtkwindowprivate.h"
#include "gtknative.h"
/* atkcomponent.h */
static void gtk_window_accessible_get_extents (AtkComponent *component,
gint *x,
gint *y,
gint *width,
gint *height,
AtkCoordType coord_type);
static void gtk_window_accessible_get_size (AtkComponent *component,
gint *width,
gint *height);
static void atk_component_interface_init (AtkComponentIface *iface);
static void atk_window_interface_init (AtkWindowIface *iface);
G_DEFINE_TYPE_WITH_CODE (GtkWindowAccessible,
gtk_window_accessible,
GTK_TYPE_WIDGET_ACCESSIBLE,
G_IMPLEMENT_INTERFACE (ATK_TYPE_COMPONENT,
atk_component_interface_init)
G_IMPLEMENT_INTERFACE (ATK_TYPE_WINDOW,
atk_window_interface_init));
static void
gtk_window_accessible_focus_event (AtkObject *obj,
gboolean focus_in)
{
atk_object_notify_state_change (obj, ATK_STATE_ACTIVE, focus_in);
}
static void
gtk_window_accessible_notify_gtk (GObject *obj,
GParamSpec *pspec)
{
GtkWidget *widget = GTK_WIDGET (obj);
AtkObject* atk_obj = gtk_widget_get_accessible (widget);
if (g_strcmp0 (pspec->name, "title") == 0)
{
g_object_notify (G_OBJECT (atk_obj), "accessible-name");
g_signal_emit_by_name (atk_obj, "visible-data-changed");
}
else
GTK_WIDGET_ACCESSIBLE_CLASS (gtk_window_accessible_parent_class)->notify_gtk (obj, pspec);
}
static const gchar *
gtk_window_accessible_get_name (AtkObject *accessible)
{
const gchar* name;
GtkWidget* widget;
widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
if (widget == NULL)
return NULL;
name = ATK_OBJECT_CLASS (gtk_window_accessible_parent_class)->get_name (accessible);
if (name != NULL)
return name;
if (GTK_IS_WINDOW (widget))
{
GtkWindow *window = GTK_WINDOW (widget);
name = gtk_window_get_title (window);
}
return name;
}
static gint
gtk_window_accessible_get_index_in_parent (AtkObject *accessible)
{
GtkWidget* widget;
AtkObject* atk_obj;
gint index = -1;
widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
if (widget == NULL)
return -1;
index = ATK_OBJECT_CLASS (gtk_window_accessible_parent_class)->get_index_in_parent (accessible);
if (index != -1)
return index;
atk_obj = atk_get_root ();
if (GTK_IS_WINDOW (widget))
{
GtkWindow *window = GTK_WINDOW (widget);
if (GTK_IS_TOPLEVEL_ACCESSIBLE (atk_obj))
{
GtkToplevelAccessible *toplevel = GTK_TOPLEVEL_ACCESSIBLE (atk_obj);
index = g_list_index (gtk_toplevel_accessible_get_children (toplevel), window);
}
else
{
gint i, sibling_count;
sibling_count = atk_object_get_n_accessible_children (atk_obj);
for (i = 0; i < sibling_count && index == -1; ++i)
{
AtkObject *child = atk_object_ref_accessible_child (atk_obj, i);
if (accessible == child)
index = i;
g_object_unref (G_OBJECT (child));
}
}
}
return index;
}
static AtkRelationSet *
gtk_window_accessible_ref_relation_set (AtkObject *obj)
{
GtkWidget *widget;
AtkRelationSet *relation_set;
AtkObject *array[1];
AtkRelation* relation;
GtkWidget *current_widget;
widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (obj));
if (widget == NULL)
return NULL;
relation_set = ATK_OBJECT_CLASS (gtk_window_accessible_parent_class)->ref_relation_set (obj);
if (atk_object_get_role (obj) == ATK_ROLE_TOOL_TIP)
{
relation = atk_relation_set_get_relation_by_type (relation_set, ATK_RELATION_POPUP_FOR);
if (relation)
atk_relation_set_remove (relation_set, relation);
if (0) /* FIXME need a way to go from tooltip window to widget */
{
array[0] = gtk_widget_get_accessible (current_widget);
relation = atk_relation_new (array, 1, ATK_RELATION_POPUP_FOR);
atk_relation_set_add (relation_set, relation);
g_object_unref (relation);
}
}
return relation_set;
}
static AtkStateSet *
gtk_window_accessible_ref_state_set (AtkObject *accessible)
{
AtkStateSet *state_set;
GtkWidget *widget;
GtkWindow *window;
GdkSurface *gdk_surface;
GdkSurfaceState state;
widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
if (widget == NULL)
return NULL;
state_set = ATK_OBJECT_CLASS (gtk_window_accessible_parent_class)->ref_state_set (accessible);
window = GTK_WINDOW (widget);
if (gtk_window_is_active (window))
atk_state_set_add_state (state_set, ATK_STATE_ACTIVE);
gdk_surface = gtk_native_get_surface (GTK_NATIVE (window));
if (GDK_IS_TOPLEVEL (gdk_surface))
{
state = gdk_toplevel_get_state (GDK_TOPLEVEL (gdk_surface));
if (state & GDK_SURFACE_STATE_MINIMIZED)
atk_state_set_add_state (state_set, ATK_STATE_ICONIFIED);
}
if (gtk_window_get_modal (window))
atk_state_set_add_state (state_set, ATK_STATE_MODAL);
if (gtk_window_get_resizable (window))
atk_state_set_add_state (state_set, ATK_STATE_RESIZABLE);
return state_set;
}
static gint
gtk_window_accessible_get_n_children (AtkObject *object)
{
GtkWidget *window;
GtkWidget *child;
gint count = 0;
window = gtk_accessible_get_widget (GTK_ACCESSIBLE (object));
for (child = gtk_widget_get_first_child (GTK_WIDGET (window));
child != NULL;
child = gtk_widget_get_next_sibling (child))
count++;
return count;
}
static AtkObject *
gtk_window_accessible_ref_child (AtkObject *object,
gint i)
{
GtkWidget *window, *child;
int pos;
window = gtk_accessible_get_widget (GTK_ACCESSIBLE (object));
for (child = gtk_widget_get_first_child (GTK_WIDGET (window)), pos = 0;
child != NULL;
child = gtk_widget_get_next_sibling (child), pos++)
{
if (pos == i)
return g_object_ref (gtk_widget_get_accessible (child));
}
return NULL;
}
static void
gtk_window_accessible_class_init (GtkWindowAccessibleClass *klass)
{
GtkWidgetAccessibleClass *widget_class = (GtkWidgetAccessibleClass*)klass;
AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
widget_class->notify_gtk = gtk_window_accessible_notify_gtk;
class->get_name = gtk_window_accessible_get_name;
class->get_index_in_parent = gtk_window_accessible_get_index_in_parent;
class->ref_relation_set = gtk_window_accessible_ref_relation_set;
class->ref_state_set = gtk_window_accessible_ref_state_set;
class->focus_event = gtk_window_accessible_focus_event;
class->get_n_children = gtk_window_accessible_get_n_children;
class->ref_child = gtk_window_accessible_ref_child;
}
static void
gtk_window_accessible_init (GtkWindowAccessible *accessible)
{
}
static void
gtk_window_accessible_get_extents (AtkComponent *component,
gint *x,
gint *y,
gint *width,
gint *height,
AtkCoordType coord_type)
{
GtkWidget *widget;
GdkSurface *surface;
widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (component));
if (widget == NULL)
return;
surface = gtk_native_get_surface (GTK_NATIVE (widget));
if (surface == NULL)
return;
*x = 0;
*y = 0;
*width = gdk_surface_get_width (surface);
*height = gdk_surface_get_height (surface);
if (!gtk_widget_is_drawable (widget))
{
*x = G_MININT;
*y = G_MININT;
return;
}
}
static void
gtk_window_accessible_get_size (AtkComponent *component,
gint *width,
gint *height)
{
GtkWidget *widget;
GdkSurface *surface;
widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (component));
if (widget == NULL)
return;
surface = gtk_native_get_surface (GTK_NATIVE (widget));
if (surface == NULL)
return;
*width = gdk_surface_get_width (surface);
*height = gdk_surface_get_height (surface);
}
void
_gtk_window_accessible_set_is_active (GtkWindow *window,
gboolean is_active)
{
AtkObject *accessible = _gtk_widget_peek_accessible (GTK_WIDGET (window));
if (accessible == NULL)
return;
g_signal_emit_by_name (accessible, is_active ? "activate" : "deactivate");
}
static void
atk_component_interface_init (AtkComponentIface *iface)
{
iface->get_extents = gtk_window_accessible_get_extents;
iface->get_size = gtk_window_accessible_get_size;
}
static void
atk_window_interface_init (AtkWindowIface *iface)
{
/* At this moment AtkWindow is just about signals */
}