/* GAIL - The GNOME Accessibility Implementation Library * 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, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include "config.h" #include #include #include #include #include #include #include #include #include #include "gtktoplevelaccessible.h" G_DEFINE_TYPE (GtkToplevelAccessible, _gtk_toplevel_accessible, ATK_TYPE_OBJECT) static void gtk_toplevel_accessible_initialize (AtkObject *accessible, gpointer data) { ATK_OBJECT_CLASS (_gtk_toplevel_accessible_parent_class)->initialize (accessible, data); accessible->role = ATK_ROLE_APPLICATION; accessible->name = g_get_prgname (); accessible->accessible_parent = NULL; } static void gtk_toplevel_accessible_object_finalize (GObject *obj) { GtkToplevelAccessible *toplevel = GTK_TOPLEVEL_ACCESSIBLE (obj); if (toplevel->window_list) g_list_free (toplevel->window_list); G_OBJECT_CLASS (_gtk_toplevel_accessible_parent_class)->finalize (obj); } static gint gtk_toplevel_accessible_get_n_children (AtkObject *obj) { GtkToplevelAccessible *toplevel = GTK_TOPLEVEL_ACCESSIBLE (obj); return g_list_length (toplevel->window_list); } static AtkObject * gtk_toplevel_accessible_ref_child (AtkObject *obj, gint i) { GtkToplevelAccessible *toplevel; GtkWidget *widget; AtkObject *atk_obj; toplevel = GTK_TOPLEVEL_ACCESSIBLE (obj); widget = g_list_nth_data (toplevel->window_list, i); if (!widget) return NULL; atk_obj = gtk_widget_get_accessible (widget); g_object_ref (atk_obj); return atk_obj; } static gboolean is_combo_window (GtkWidget *widget) { GtkWidget *child; AtkObject *obj; child = gtk_bin_get_child (GTK_BIN (widget)); if (!GTK_IS_EVENT_BOX (child)) return FALSE; child = gtk_bin_get_child (GTK_BIN (child)); if (!GTK_IS_FRAME (child)) return FALSE; child = gtk_bin_get_child (GTK_BIN (child)); if (!GTK_IS_SCROLLED_WINDOW (child)) return FALSE; obj = gtk_widget_get_accessible (child); obj = atk_object_get_parent (obj); return FALSE; } static gboolean is_attached_menu_window (GtkWidget *widget) { GtkWidget *child; child = gtk_bin_get_child (GTK_BIN (widget)); if (GTK_IS_MENU (child)) { GtkWidget *attach; attach = gtk_menu_get_attach_widget (GTK_MENU (child)); /* Allow for menu belonging to the Panel Menu, which is a GtkButton */ if (GTK_IS_MENU_ITEM (attach) || GTK_IS_BUTTON (attach)) return TRUE; } return FALSE; } static void _gtk_toplevel_accessible_class_init (GtkToplevelAccessibleClass *klass) { AtkObjectClass *class = ATK_OBJECT_CLASS(klass); GObjectClass *g_object_class = G_OBJECT_CLASS(klass); class->initialize = gtk_toplevel_accessible_initialize; class->get_n_children = gtk_toplevel_accessible_get_n_children; class->ref_child = gtk_toplevel_accessible_ref_child; class->get_parent = NULL; g_object_class->finalize = gtk_toplevel_accessible_object_finalize; } static void remove_child (GtkToplevelAccessible *toplevel, GtkWindow *window) { AtkObject *atk_obj = ATK_OBJECT (toplevel); GList *l; guint window_count = 0; AtkObject *child; if (toplevel->window_list) { GtkWindow *tmp_window; for (l = toplevel->window_list; l; l = l->next) { tmp_window = GTK_WINDOW (l->data); if (window == tmp_window) { /* Remove the window from the window_list & emit the signal */ toplevel->window_list = g_list_delete_link (toplevel->window_list, l); child = gtk_widget_get_accessible (GTK_WIDGET (window)); g_signal_emit_by_name (atk_obj, "children-changed::remove", window_count, child, NULL); atk_object_set_parent (child, NULL); break; } window_count++; } } } static gboolean show_event_watcher (GSignalInvocationHint *ihint, guint n_param_values, const GValue *param_values, gpointer data) { GtkToplevelAccessible *toplevel = GTK_TOPLEVEL_ACCESSIBLE (data); AtkObject *atk_obj = ATK_OBJECT (toplevel); GObject *object; GtkWidget *widget; gint n_children; AtkObject *child; object = g_value_get_object (param_values + 0); if (!GTK_IS_WINDOW (object)) return TRUE; widget = GTK_WIDGET (object); if (gtk_widget_get_parent (widget) || is_attached_menu_window (widget) || #ifdef GDK_WINDOWING_X11 GTK_IS_PLUG (widget) || #endif is_combo_window (widget)) return TRUE; child = gtk_widget_get_accessible (widget); if (atk_object_get_role (child) == ATK_ROLE_REDUNDANT_OBJECT || atk_object_get_role (child) == ATK_ROLE_TOOL_TIP) return TRUE; /* Add the window to the list & emit the signal */ toplevel->window_list = g_list_append (toplevel->window_list, widget); n_children = g_list_length (toplevel->window_list); atk_object_set_parent (child, atk_obj); g_signal_emit_by_name (atk_obj, "children-changed::add", n_children - 1, child, NULL); g_signal_connect_swapped (G_OBJECT(object), "destroy", G_CALLBACK (remove_child), toplevel); return TRUE; } static gboolean hide_event_watcher (GSignalInvocationHint *ihint, guint n_param_values, const GValue *param_values, gpointer data) { GtkToplevelAccessible *toplevel = GTK_TOPLEVEL_ACCESSIBLE (data); GObject *object; object = g_value_get_object (param_values + 0); if (!GTK_IS_WINDOW (object)) return TRUE; remove_child (toplevel, GTK_WINDOW (object)); return TRUE; } static void _gtk_toplevel_accessible_init (GtkToplevelAccessible *toplevel) { GtkWindow *window; GtkWidget *widget; GList *l; guint signal_id; l = toplevel->window_list = gtk_window_list_toplevels (); while (l) { window = GTK_WINDOW (l->data); widget = GTK_WIDGET (window); if (!window || !gtk_widget_get_visible (widget) || is_attached_menu_window (widget) || #ifdef GDK_WINDOWING_X11 GTK_IS_PLUG (window) || #endif gtk_widget_get_parent (GTK_WIDGET (window))) { GList *temp_l = l->next; toplevel->window_list = g_list_delete_link (toplevel->window_list, l); l = temp_l; } else { g_signal_connect_swapped (G_OBJECT (window), "destroy", G_CALLBACK (remove_child), toplevel); l = l->next; } } g_type_class_ref (GTK_TYPE_WINDOW); signal_id = g_signal_lookup ("show", GTK_TYPE_WINDOW); g_signal_add_emission_hook (signal_id, 0, show_event_watcher, toplevel, (GDestroyNotify) NULL); signal_id = g_signal_lookup ("hide", GTK_TYPE_WINDOW); g_signal_add_emission_hook (signal_id, 0, hide_event_watcher, toplevel, (GDestroyNotify) NULL); }