diff --git a/ChangeLog b/ChangeLog index 14421344d1..e9826dbb74 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2007-12-28 Christian Persch + + * modules/other/gail/Makefile.am: + * modules/other/gail/tests/*: + * configure.in: Merge tests from standalone gail. Bug #504568. + 2007-12-28 Matthias Clasen * gtk/gtkclipboard.c: Make the finalizer work when display is diff --git a/configure.in b/configure.in index 6651b2be87..c4d56e16a3 100644 --- a/configure.in +++ b/configure.in @@ -1839,6 +1839,7 @@ modules/Makefile modules/other/Makefile modules/other/gail/Makefile modules/other/gail/libgail-util/Makefile +modules/other/gail/tests/Makefile modules/engines/Makefile modules/engines/pixbuf/Makefile modules/engines/ms-windows/Makefile diff --git a/modules/other/gail/Makefile.am b/modules/other/gail/Makefile.am index b864901e96..9abc107248 100644 --- a/modules/other/gail/Makefile.am +++ b/modules/other/gail/Makefile.am @@ -1,6 +1,6 @@ include $(top_srcdir)/Makefile.decl -SUBDIRS = libgail-util +SUBDIRS = libgail-util tests if OS_WIN32 no_undefined = -no-undefined diff --git a/modules/other/gail/tests/Makefile.am b/modules/other/gail/tests/Makefile.am new file mode 100644 index 0000000000..d7af911fd2 --- /dev/null +++ b/modules/other/gail/tests/Makefile.am @@ -0,0 +1,226 @@ +if OS_WIN32 +no_undefined = -no-undefined +endif + +if !OS_WIN32 +moduledir = $(libdir)/gtk-2.0/modules +module_LTLIBRARIES = \ + libferret.la +endif + +noinst_LTLIBRARIES = \ + libtestaction.la \ + libtestbutton.la \ + libtestcombo.la \ + libtestcomponent.la \ + libtestimage.la \ + libtestnotebook.la \ + libtestobject.la \ + libtestmenuitem.la \ + libtestoptionmenu.la \ + libtestpaned.la \ + libtestprops.la \ + libtestselection.la \ + libteststatusbar.la \ + libtesttable.la \ + libtesttext.la \ + libtesttoplevel.la \ + libtesttreetable.la \ + libtestvalues.la + +AM_CPPFLAGS = \ + -I$(top_srcdir)/gdk \ + -I$(top_builddir)/gdk \ + -I$(top_srcdir)/gtk \ + -I$(top_builddir)/gtk + +AM_CFLAGS = \ + $(GTK_DEP_CFLAGS) \ + $(GTK_DEBUG_FLAGS) + +if !OS_WIN32 +libferret_la_SOURCES = \ + testlib.c \ + testlib.h \ + ferret.c + +libferret_la_LDFLAGS = \ + -rpath $(moduledir) -module -avoid-version \ + $(GTK_DEP_LIBS) \ + $(LDFLAGS) + +libferret_la_LIBADD = \ + $(GAIL_INET_LIBS) +endif + +libtestaction_la_SOURCES = \ + testaction.c + +libtestaction_la_LDFLAGS = \ + -rpath $(moduledir) -module -avoid-version $(no_undefined) \ + $(GTK_DEP_LIBS) \ + $(LDFLAGS) + +libtestbutton_la_SOURCES = \ + testlib.c \ + testlib.h \ + testbutton.c + +libtestbutton_la_LDFLAGS = \ + -rpath $(moduledir) -module -avoid-version $(no_undefined) \ + $(GTK_DEP_LIBS) \ + $(LDFLAGS) + +libtestcombo_la_SOURCES = \ + testlib.c \ + testlib.h \ + testcombo.c + +libtestcombo_la_LDFLAGS = \ + -rpath $(moduledir) -module -avoid-version $(no_undefined) \ + $(GTK_DEP_LIBS) \ + $(LDFLAGS) + +libtestcomponent_la_SOURCES = \ + testcomponent.c + +libtestcomponent_la_LDFLAGS = \ + -rpath $(moduledir) -module -avoid-version $(no_undefined) \ + $(GTK_DEP_LIBS) \ + $(LDFLAGS) + +libtestimage_la_SOURCES = \ + testimage.c + +libtestimage_la_LDFLAGS = \ + -rpath $(moduledir) -module -avoid-version $(no_undefined) \ + $(GTK_DEP_LIBS) \ + $(LDFLAGS) + +libtestmenuitem_la_SOURCES = \ + testlib.c \ + testlib.h \ + testmenuitem.c + +libtestmenuitem_la_LDFLAGS = \ + -rpath $(moduledir) -module -avoid-version $(no_undefined) \ + $(GTK_DEP_LIBS) \ + $(LDFLAGS) + +libtestnotebook_la_SOURCES = \ + testlib.c \ + testlib.h \ + testnotebook.c + +libtestnotebook_la_LDFLAGS = \ + -rpath $(moduledir) -module -avoid-version $(no_undefined) \ + $(GTK_DEP_LIBS) \ + $(LDFLAGS) + +libtestobject_la_SOURCES = \ + testlib.c \ + testlib.h \ + testobject.c + +libtestobject_la_LDFLAGS = \ + -rpath $(moduledir) -module -avoid-version $(no_undefined) \ + $(GTK_DEP_LIBS) \ + $(LDFLAGS) + +libtestoptionmenu_la_SOURCES = \ + testlib.c \ + testlib.h \ + testoptionmenu.c + +libtestoptionmenu_la_LDFLAGS = \ + -rpath $(moduledir) -module -avoid-version $(no_undefined) \ + $(GTK_DEP_LIBS) \ + $(LDFLAGS) + +libtestpaned_la_SOURCES = \ + testlib.c \ + testlib.h \ + testpaned.c + +libtestpaned_la_LDFLAGS = \ + -rpath $(moduledir) -module -avoid-version $(no_undefined) \ + $(GTK_DEP_LIBS) \ + $(LDFLAGS) + +libtestprops_la_SOURCES = \ + testlib.c \ + testlib.h \ + testprops.c + +libtestprops_la_LDFLAGS = \ + -rpath $(moduledir) -module -avoid-version $(no_undefined) \ + $(GTK_DEP_LIBS) \ + $(LDFLAGS) + +libtestselection_la_SOURCES = \ + testselection.c + +libtestselection_la_LDFLAGS = \ + -rpath $(moduledir) -module -avoid-version $(no_undefined) \ + $(GTK_DEP_LIBS) \ + $(LDFLAGS) + +libteststatusbar_la_SOURCES = \ + teststatusbar.c + +libteststatusbar_la_LDFLAGS = \ + -rpath $(moduledir) -module -avoid-version $(no_undefined) \ + $(GTK_DEP_LIBS) \ + $(LDFLAGS) + +libtesttable_la_SOURCES = \ + testlib.c \ + testlib.h \ + testtextlib.c \ + testtextlib.h \ + testtable.c + +libtesttable_la_LDFLAGS = \ + -rpath $(moduledir) -module -avoid-version $(no_undefined) \ + $(GTK_DEP_LIBS) \ + $(LDFLAGS) + +libtesttext_la_SOURCES = \ + testlib.c \ + testlib.h \ + testtextlib.c \ + testtextlib.h \ + testtext.c + +libtesttext_la_LDFLAGS = \ + -rpath $(moduledir) -module -avoid-version $(no_undefined) \ + $(GTK_DEP_LIBS) \ + $(LDFLAGS) + +libtesttoplevel_la_SOURCES = \ + testlib.c \ + testlib.h \ + testtoplevel.c + +libtesttoplevel_la_LDFLAGS = \ + -rpath $(moduledir) -module -avoid-version $(no_undefined) \ + $(GTK_DEP_LIBS) \ + $(LDFLAGS) + +libtesttreetable_la_SOURCES = \ + testlib.c \ + testlib.h \ + testtreetable.c + +libtesttreetable_la_LDFLAGS = \ + -rpath $(moduledir) -module -avoid-version $(no_undefined) \ + $(GTK_DEP_LIBS) \ + $(LDFLAGS) + +libtestvalues_la_SOURCES = \ + testvalues.c + +libtestvalues_la_LDFLAGS = \ + -rpath $(moduledir) -module -avoid-version $(no_undefined) \ + $(GTK_DEP_LIBS) \ + $(LDFLAGS) diff --git a/modules/other/gail/tests/README b/modules/other/gail/tests/README new file mode 100644 index 0000000000..7a6fdcba4e --- /dev/null +++ b/modules/other/gail/tests/README @@ -0,0 +1,314 @@ + +============================ +GAIL README +Last Updated: August 2, 2001 +============================ + + +General Info +============ + +This README describes how to use the various test programs +in the gail/tests directory. + +To run the various test programs described in this README, +the test libraries must be built and installed. Running +"make", then "make install" in the gail top-level directory +will take care of this. Then do the following: + +1. Set the environment variable GTK_MODULES to + "libgail:lib" + + For example, for ferret, it would be "libgail:libferret" + +2. Run the GTK+ test program specified. These test programs + are found in the GTK+ build directory in the subdirectory + called "tests". + +Most test programs will display output directly to the +terminal window where the GTK+ test program was launched. +Some test programs (testtable and testtext) will launch a +test GUI program which allows more interactive testing. + +The test GUI has two windows. The first window is the +"Test Control" window and the second window is the +"Test Output" window. In the "Test Control" window, +press the button(s) that corresponds to the tests to run +and press the "Run Tests" button at the bottom of the +screen. Some tests have associated text entry fields +which become active when the button is toggled on. These +text entry fields correspond to arguments that affect how +the test is executed. They are pre-filled with default +values but the user can change them if desired. The +output from the tests is displayed in the "Test Output" +window. + + +testlib +======= + +Contains general purpose functionality that is used by the +various tests. These include functions that find a specific +widget/AtkObject in the test program, and functions used by +tests that use the Gail Test GUI. + + +ferret +====== + +Ferret is a passive in-process test tool for ATK and GAIL. + +Run a GTK+-2.0 application such as "testgtk", and ferret will +display a window on screen. In this window accessibility +information about the GTK+ widgets will appear as they +receive focus. + +The ferret window has several tabs, one for each of the +following ATK interfaces. + + Object + Action + Component + Image + Table + Text + Value + +Tabs that do not apply to the current widget in focus will be +displayed as inactive. Clicking on an active tab will display +information about the AtkObject accessed via the ATK API. In the +Action tab the various actions are displayed as buttons. When +a button is clicked, the action specified on the button's +label is performed. + +If you have installed the "festival" speech synthesis system, +running festival in server mode (festival --server) and turning +on Ferret's Festival support will cause the following to happen: + +1. AtkObject accessible names, roles, and keybindings will be + spoken as they receive focus. +2. When the caret (cursor) is moved in a text field, the + current line will be spoken, unless the caret is moved + just a single character. In the later case, only the + single character after the caret will be spoken. + +Festival support can be turned on by checking "Festival" in the +menu, or by setting the environment variable FERRET_FESTIVAL +prior to starting the test. By checking "Festival Terse" or +by setting the environment variable FERRET_TERSE, only the +name of the AtkObject will be spoken (and not the roles and +keybindings). + +A magnifier can be turned on to enlarge the widget in focus +by checking "Magnifier" in the menu, or by setting the +environment variable FERRET_MAGNIFIER. This requires that +the magnifier standalone code is running. + +Checking "Track Mouse in the menu or by setting the environment +variable FERRET_MOUSETRACK causes ferret to display information +about the widget that is under the mouse rather than the widget +that has focus. The mouse is tracked via GtkWidget +"enter_notify_event" signals, so flyweight objects are not tracked. + +Checking "Terminal Output" in the menu or by setting the +environment variable FERRET_ASCII will display the information +that is normally displayed to the ferret GUI window to the +terminal screen. + +Checking "No ATK Signals" in the menu or by setting the +environment variable FERRET_NOSIGNALS will cause ferret to +ignore any ATK signals, and it will not update its display +when such signals occur. + + +testaction +========== + +This is a GTK+ module used to test the implementation of the ATK +interface AtkAction, except for atk_action_do_action() in the GAIL +library. It is normally used with the GTK+ test program testgtk. + + +testbutton +========== + +This is a GTK+ module used to test the accessible implementation +for buttons. It is normally used with the GTK+ test program testgtk. + +Set the TEST_ACCESSIBLE_NAME environment variable to have the test +driver attach to a widget by widget name (compared via the +gtk_widget_get_name function call). + +Set the environment variable TEST_ACCESSIBLE_AUTO and the program +will execute the action defined for a GailButton once. + + +testcombo +========= + +This is a GTK+ module used to test the implementation of the ATK action +interfaces on GailCombo. It is normally used with the GTK+ test program +testgtk by putting the focus in the GtkCombo in entry window. + + +testcomponent +============= + +This is a GTK+ module used to test the implementation of the ATK +interface AtkComponent in the GAIL library. It is normally used with the +GTK+ test program testgtk. + + +testimage +========= + +This is a GTK+ module used to test the implementation of the ATK +interface AtkImage in the GAIL library. It is normally used with the GTK+ +test program testgtk, but can also be used with testdnd when you want +to test GtkPixmap. This modules pops up an extra dialog on startup , containing +GtkArrows and a GtkImage. This dialog has to be closed before control is returned to main window. + + +testmenuitem +============ + +This is a GTK+ module used to test the accessible implementation +for menu items. It is normally used with the GTK+ test program testgtk. + +Set the TEST_ACCESSIBLE_NAME environment variable to have the test +driver attach to a widget by widget name (compared via the +gtk_widget_get_name function call). + +Set the environment variable TEST_ACCESSIBLE_AUTO and the program +will execute the action defined for a GailButton once. + + +testnotebook +============= + +This is a GTK+ module used to test the implementation of the ATK +interface AtkSelection for GailNotebook. It is normally used with the +GTK+ test program testgtk. + + +testobject +========== + +This is a GTK+ module used to test the implementation of the ATK +interface in atkobject.h in the GAIL library. It is normally used with the +GTK+ test program testgtk. + + +testoptionmenu +============== + +This is a GTK+ module used to test the implementation of the ATK interfaces +for GtkOptionmenu. It should be used with the GTK+ test program testgtk and +its file selection dialog. + + +testpaned +========= + +This is a GTK+ module used to test the implementation of the ATK +interface AtkValue for GailPaned. It is normally used with the +GTK+ test program testgtk. It checks the setting of the position +programmatically and that notification is received if the position +is changed interactively. + + +testprops +========== + +This is a GTK+ module used to test the implementation of ATK properties +and property change handlers in the GAIL library. It is normally used with +the GTK+ test program testgtk. To see the changing of the state +ATK_STATE_SHOWING use menus in "progress bar". To see the changing of the +state ATK_STATE_SENSITIVE uses "labels". To see changing of child and parent +use resize check box in "panes". + +Set the TEST_ACCESSIBLE_NAME environment variable to have the test +driver attach to a widget by widget name (compared via the +gtk_widget_get_name function call). + + +testselection +============= + +This is a GTK+ module used to test the implementation of the AtkSelection +interface works for the GAIL library. It is normally used with the GTK+ +test program testgtk and clicking on the menus option. It can also be used +with the GtkCombo which can be accessed by clicking on the entry option. + + +teststatusbar +============= + +This is a GTK+ module used to test that the text on the statusbar +can be retrieved using GailStatusbar. It is normally used with the GTK+ +test program testgtk and clicking on statusbar button. + + +testtable +========= + +This is GTK+ module used to test the implementation of AtkTable +interfaces. It can be used with GailTreeView, for example. It +can be used with any of the following GTK+ test programs: +testtreecolumns, testtreefocus, testtreesort, testtreeview, +or treestoretest. + +Set the TEST_ACCESSIBLE_NO_PROPERTIES environment variable +to not receive information about property values changing +(like cell state changes). + +Set the TEST_ACCESSIBLE_NO_GUI environment variable to run the +test without the GUI program. + + +testtext +======== + +This is a GTK+ module used to test the implementation of AtkText and +AtkEditableText interfaces on GailTextView. It is normally used with +the GTK+ test program testtext started with a text file loaded. +It can also be used with the GTK+ test program testgtk, and then +click on the "entry" or "label" button. + +Set the TEST_ACCESSIBLE_NAME environment variable to have the test +driver attach to a widget by widget name (compared via the +gtk_widget_get_name function call). + +Set the TEST_ACCESSIBLE_DELAY environment variable to an integer +and the test driver will attach to only a widget on the nth screen +that is displayed. + + +testtoplevel +============ + +This test exercises the AtkUtil functions. It accesses the +atk_get_root() toplevel object, sets/removes global listeners, +and displays the ATK implementation name/version. + +Set the TEST_ACCESSIBLE_DEPTH environment variable to control +how deep the children of the toplevel object are displayed. +The default is a depth of 2. Specifying a depth of -1 will +show the complete hierarchy. + + +testvalues +========== + +This is a GTK+ module used to test the implementation of AtkValue interface +works for the GAIL library. GailProgressbar, GailSpinbutton and GailRange +can all be tested using this module. + + +GAIL README Authors +=================== + +-Brian Cameron (brian.cameron@sun.com) +-Bill Haneman (bill.haneman@sun.com) +-Padraig O'Briain (padraig.obriain@sun.com) + diff --git a/modules/other/gail/tests/ferret.c b/modules/other/gail/tests/ferret.c new file mode 100644 index 0000000000..73ce9da2ed --- /dev/null +++ b/modules/other/gail/tests/ferret.c @@ -0,0 +1,2690 @@ +#define MAX_BUFFER 256 +#define GTK_ENABLE_BROKEN +#define MAX_GROUPS 20 +#define MAX_NAME_VALUE 20 + +#include +#include +#include +#include +#include +#include +#include +#include +#include "testlib.h" +#include "config.h" + +typedef enum +{ + OBJECT, + ACTION, + COMPONENT, + IMAGE, + SELECTION, + TABLE, + TEXT, + VALUE, + END_TABS +} TabNumber; + +typedef enum +{ + OBJECT_INTERFACE, + RELATION_INTERFACE, + STATE_INTERFACE, + ACTION_INTERFACE, + COMPONENT_INTERFACE, + IMAGE_INTERFACE, + SELECTION_INTERFACE, + TABLE_INTERFACE, + TEXT_INTERFACE, + TEXT_ATTRIBUTES, + VALUE_INTERFACE +} GroupId; + +typedef enum +{ + VALUE_STRING, + VALUE_BOOLEAN, + VALUE_TEXT, + VALUE_BUTTON +} ValueType; + +/* GUI Information for the group */ + +typedef struct +{ + GroupId group_id; + GtkFrame *scroll_outer_frame; + GtkWidget *frame; + GtkVBox *group_vbox; + GtkAdjustment *adj; + GList *name_value; + gchar *name; + gboolean is_scrolled; + gint default_height; +} GroupInfo; + +typedef struct +{ + GList *groups; + GtkWidget *page; + GtkWidget *main_box; + gchar *name; +} TabInfo; + +typedef struct +{ + ValueType type; + gboolean active; + + GtkHBox *column1, *column2, *hbox; + GtkLabel *label; + + GtkButton *button; + GValue button_gval; + gulong signal_id; + AtkObject *atkobj; + gint action_num; + + GtkWidget *string; + GtkWidget *boolean; + GtkWidget *text; +} NameValue; + +typedef enum { + FERRET_SIGNAL_OBJECT, + FERRET_SIGNAL_TEXT, + FERRET_SIGNAL_TABLE +} FerretSignalType; + +/* Function prototypes */ + +/* GUI functions */ + +static void _init_data(void); +static void _create_window(void); +static void _add_menu(GtkWidget ** menu, GtkWidget ** menuitem, + gchar * name, gboolean init_value, GCallback func); +static void _clear_tab(TabNumber tab_n); +static void _greyout_tab (GtkWidget *widget, gboolean is_sensitive); +static void _finished_group(TabNumber tab_n, gint group_num); +static gboolean _object_is_ours (AtkObject *aobject); +static void _create_event_watcher (void); + +/* Mouse Watcher/Magnifier/Festival functions */ + +static gboolean _mouse_watcher (GSignalInvocationHint *ihint, + guint n_param_values, + const GValue *param_values, + gpointer data); +static gboolean _button_watcher (GSignalInvocationHint *ihint, + guint n_param_values, + const GValue *param_values, + gpointer data); +static void _send_to_magnifier (gint x, gint y, gint w, gint h); +static void _send_to_festival (const gchar * name, + const gchar * role_name, const gchar * accel); +static void _speak_caret_event (AtkObject * aobject); +static void _festival_say (const gchar * text); +static void _festival_write (const gchar * text, int fd); +static gint _festival_init (void); + +/* Update functions */ + +static void _update_current_page(GtkNotebook *notebook, gpointer p, + guint current_page); +static void _update(TabNumber top_tab, AtkObject *aobject); + +/* Print functions */ + +static void _print_accessible (AtkObject *aobject); + +static gint _print_object (AtkObject *aobject); +static gint _print_relation (AtkObject *aobject); +static gint _print_state (AtkObject *aobject); + +static gint _print_action (AtkAction *aobject); +static gint _print_component (AtkComponent *aobject); +static gint _print_image (AtkImage *aobject); +static gint _print_selection (AtkSelection *aobject); +static gint _print_table (AtkTable *aobject); +static gint _print_text (AtkText *aobject); +static gint _print_text_attributes (AtkText *aobject); +static gint _print_value (AtkValue *aobject); +static void _print_value_type(gint group_num, gchar *type, GValue *value); +static gint _print_groupname(TabNumber tab_n, GroupId group_id, + const char *groupname); +static NameValue* _print_key_value(TabNumber tab_n, gint group_number, + const char *label, gpointer value, ValueType type); +static void _print_signal(AtkObject *aobject, FerretSignalType type, + const char *name, const char *info); + +/* Data Access functions */ + +static GroupInfo* _get_group(TabInfo *tab, GroupId group_id, + const gchar *groupname); +void _get_group_scrolled(GroupInfo *group); +static NameValue* _get_name_value(GroupInfo *group, const gchar *label, + gpointer value, ValueType type); + +/* Signal handlers */ + +static void _update_handlers(AtkObject *obj); +static void _notify_text_insert_handler (GObject *obj, + int position, int offset); +static void _notify_text_delete_handler (GObject *obj, + int position, int offset); +static void _notify_caret_handler (GObject *obj, int position); +static void _notify_table_row_inserted (GObject *obj, + gint start_offset, gint length); +static void _notify_table_column_inserted (GObject *obj, + gint start_offset, gint length); +static void _notify_table_row_deleted (GObject *obj, + gint start_offset, gint length); +static void _notify_table_column_deleted (GObject *obj, + gint start_offset, gint length); +static void _notify_table_row_reordered (GObject *obj); +static void _notify_table_column_reordered (GObject *obj); +static void _notify_object_child_added (GObject *obj, + gint index, AtkObject *child); +static void _notify_object_child_removed (GObject *obj, + gint index, AtkObject *child); +static void _notify_object_state_change (GObject *obj, + gchar *name, gboolean set); + +/* Property handlers */ + +static void _property_change_handler (AtkObject *obj, + AtkPropertyValues *values); + +/* Ferret GUI callbacks */ + +void _action_cb(GtkWidget *widget, gpointer *userdata); +void _toggle_terminal(GtkCheckMenuItem *checkmenuitem, + gpointer user_data); +void _toggle_no_signals(GtkCheckMenuItem *checkmenuitem, + gpointer user_data); +void _toggle_magnifier(GtkCheckMenuItem *checkmenuitem, + gpointer user_data); +void _toggle_festival(GtkCheckMenuItem *checkmenuitem, + gpointer user_data); +void _toggle_festival_terse(GtkCheckMenuItem *checkmenuitem, + gpointer user_data); +void _toggle_trackmouse(GtkCheckMenuItem *checkmenuitem, + gpointer user_data); +void _toggle_trackfocus(GtkCheckMenuItem *checkmenuitem, + gpointer user_data); + +/* Global variables */ +static GtkNotebook *notebook; +static TabInfo *nbook_tabs[END_TABS]; +static gint mouse_watcher_focus_id = -1; +static gint mouse_watcher_button_id = -1; +static gint focus_tracker_id = -1; +static gboolean use_magnifier = FALSE; +static gboolean use_festival = FALSE; +static gboolean track_mouse = FALSE; +static gboolean track_focus = TRUE; +static gboolean say_role = TRUE; +static gboolean say_accel = TRUE; +static gboolean display_ascii = FALSE; +static gboolean no_signals = FALSE; +static gint last_caret_offset = 0; + +static AtkObject *last_object = NULL; +static GtkWidget *mainWindow = NULL; +static GtkWidget *vbox1 = NULL; +static GtkWidget *menu = NULL; +static GtkWidget *menutop = NULL; +static GtkWidget *menubar = NULL; +static GtkWidget *menuitem_terminal = NULL; +static GtkWidget *menuitem_no_signals = NULL; +static GtkWidget *menuitem_magnifier = NULL; +static GtkWidget *menuitem_festival = NULL; +static GtkWidget *menuitem_festival_terse = NULL; +static GtkWidget *menuitem_trackmouse = NULL; +static GtkWidget *menuitem_trackfocus = NULL; + +#ifdef HAVE_SOCKADDR_UN_SUN_LEN +static struct sockaddr_un mag_server = { 0, AF_UNIX , "/tmp/magnifier_socket" }; +static struct sockaddr_un client = { 0 , AF_UNIX, "/tmp/mag_client"}; +#else +static struct sockaddr_un mag_server = { AF_UNIX , "/tmp/magnifier_socket" }; +static struct sockaddr_un client = { AF_UNIX, "/tmp/mag_client"}; +#endif + +/* GUI Information for the output window */ +typedef struct +{ + GtkWindow *outputWindow; + GtkWidget *hbox; + GtkWidget *vbox; + GtkWidget *label; + GtkWidget *textInsert; + gchar *testTitle; +} MainDialog; + +static void +_send_to_magnifier(gint x, gint y, gint w, gint h) +{ + int desc, length_msg; + gchar buff[100]; + + sprintf (buff, "~5:%d,%d", x+w/2, y+h/2); + +#ifdef MAG_DEBUG + g_print ("sending magnifier: %s\n", buff); +#endif + +#ifdef HAVE_SOCKADDR_UN_SUN_LEN + mag_server.sun_len = SUN_LEN(&mag_server); + client.sun_len = SUN_LEN(&client); +#endif + + if((desc=socket(AF_UNIX,SOCK_STREAM,0)) == -1){ + perror("socket"); + return; + } + unlink("/tmp/mag_client"); + + if (bind(desc, (struct sockaddr*)&client, sizeof(client)) == -1) + { + perror("bind"); + return; + } + + if (connect(desc,(struct sockaddr*)&mag_server,sizeof(mag_server)) == -1) + { + perror("connect"); + return; + } + + length_msg = write(desc,buff,strlen(buff)); + unlink("/tmp/mag_client"); + return; +} + +static int _festival_init (void) +{ + int fd; + struct sockaddr_in name; + int tries = 2; + + name.sin_family = AF_INET; + name.sin_port = htons (1314); + name.sin_addr.s_addr = htonl(INADDR_ANY); + fd = socket (PF_INET, SOCK_STREAM, 0); + + while (connect(fd, (struct sockaddr *) &name, sizeof (name)) < 0) { + if (!tries--) { + perror ("connect"); + return -1; + } + } + + _festival_write ("(audio_mode'async)", fd); + return fd; +} + +static void _festival_say (const gchar *text) +{ + static int fd = 0; + gchar *quoted; + gchar *p; + gchar prefix [100]; + const gchar *stretch; + + fprintf (stderr, "saying %s\n", text); + + if (!fd) + { + fd = _festival_init (); + } + + quoted = g_malloc(100+strlen(text)*2); + + stretch = g_strdup (g_getenv ("FESTIVAL_STRETCH")); + if (!stretch) stretch = "0.75"; + sprintf (prefix, "(audio_mode'shutup)\n (Parameter.set 'Duration_Stretch %s)\n (SayText \"", stretch); + + strcpy(quoted, prefix); + p = quoted + strlen (prefix); + while (*text) { + if ( *text == '\\' || *text == '"' ) + *p = '\\'; + *p++ = *text++; + } + *p++ = '"'; + *p++ = ')'; + *p = 0; + + _festival_write (quoted, fd); + + g_free(quoted); +} + + +static void _send_to_festival (const gchar *role_name, + const gchar *name, const gchar *accel) +{ + gchar *string; + int len = (strlen (role_name)+1 + strlen (name)+2 + 4 + strlen (accel)+2); + int i, j; + gchar ch; + gchar *accel_name; + + string = (gchar *) g_malloc (len * sizeof (gchar)); + + i = 0; + if (say_role) + { + j = 0; + while (role_name[j]) + { + ch = role_name[j++]; + if (ch == '_') ch = ' '; + string[i++] = ch; + }; + string[i++] = ' '; + } + j = 0; + while (name[j]) + { + ch = name[j++]; + if (ch == '_') ch = ' '; + string[i++] = ch; + }; + if ((say_accel) && (strlen (accel) > 0)) + { + accel_name = (gchar *)accel; + if (strncmp (accel, " 1) + { + text = atk_text_get_text_at_offset (ATK_TEXT (aobject), + caret_offset, + ATK_TEXT_BOUNDARY_LINE_START, + &dummy1, + &dummy2); + } + else + { + text = atk_text_get_text_before_offset (ATK_TEXT (aobject), + caret_offset, + ATK_TEXT_BOUNDARY_CHAR, + &dummy1, + &dummy2); + } + _festival_say (text); + g_free (text); + last_caret_offset = caret_offset; +} + +static void +_greyout_tab (GtkWidget *page_child, gboolean is_sensitive) +{ + GtkWidget *tab; + + tab = gtk_notebook_get_tab_label (notebook, page_child); + if (tab) + gtk_widget_set_sensitive (GTK_WIDGET (tab), is_sensitive); +} + +static void +_refresh_notebook (AtkObject *aobject) +{ + if (ATK_IS_OBJECT (aobject)) + { + _greyout_tab (nbook_tabs[ACTION]->page, ATK_IS_ACTION(aobject)); + _greyout_tab (nbook_tabs[COMPONENT]->page, ATK_IS_COMPONENT(aobject)); + _greyout_tab (nbook_tabs[IMAGE]->page, ATK_IS_IMAGE(aobject)); + _greyout_tab (nbook_tabs[SELECTION]->page, ATK_IS_SELECTION(aobject)); + _greyout_tab (nbook_tabs[TABLE]->page, ATK_IS_TABLE(aobject)); + _greyout_tab (nbook_tabs[TEXT]->page, ATK_IS_TEXT(aobject)); + _greyout_tab (nbook_tabs[VALUE]->page, ATK_IS_VALUE(aobject)); + } +} + +static void _print_accessible (AtkObject *aobject) +{ + TabNumber top_tab; + + if (_object_is_ours(aobject)) + { + if (display_ascii) + g_print("\nFocus entered the ferret output window!\n"); + return; + } + + _refresh_notebook(aobject); + + if (display_ascii) + g_print("\nFocus change\n"); + + /* Do not attach signal handlers if the user has asked not to */ + if (!no_signals) + _update_handlers(aobject); + else + last_object = aobject; /* _update_handler normally does this */ + + top_tab = gtk_notebook_get_current_page (notebook) + OBJECT; + _update(top_tab, aobject); + + if (use_magnifier) + { + gint x, y; + gint w=0, h=0; + + if (ATK_IS_TEXT (aobject)) + { + gint x0, y0, w0, h0; + gint xN, yN, wN, hN; + gint len; + len = atk_text_get_character_count (ATK_TEXT (aobject)); + atk_text_get_character_extents (ATK_TEXT (aobject), 0, + &x0, &y0, &w0, &h0, + ATK_XY_SCREEN); + if (len > 0) + { + atk_text_get_character_extents (ATK_TEXT (aobject), len-1, + &xN, &yN, &wN, &hN, + ATK_XY_SCREEN); + x = MIN (x0, xN); + y = MIN (y0, yN); + w = MAX (x0+w0, xN+wN) - x; + h = MAX (y0+h0, yN+hN) - y; + } + else + { + x = x0; + y = y0; + } + } + else if (ATK_IS_COMPONENT (aobject)) + { + atk_component_get_extents (ATK_COMPONENT(aobject), + &x, &y, &w, &h, + ATK_XY_SCREEN); + } + if (w > -1) _send_to_magnifier (x, y, w, h); + } +} + +static gboolean +_object_is_ours (AtkObject *aobject) +{ + /* determine whether this object is parented by our own accessible... */ + + AtkObject *toplevel = aobject; + + while (atk_object_get_role(aobject) != ATK_ROLE_FRAME) + { + aobject = atk_object_get_parent (aobject); + if (aobject == NULL) break; + toplevel = aobject; + }; + + /* + * Some widgets do not have an ATK_ROLE_FRAME at the top, + * so ignore those. + */ + if (aobject != NULL) + { + if (GTK_ACCESSIBLE(toplevel)->widget == mainWindow) + { + return TRUE; + } + } + + return FALSE; +} + +static gchar * +ferret_get_name_from_container (AtkObject *aobject) +{ + gchar *s = NULL; + gint n = atk_object_get_n_accessible_children (aobject); + gint i = 0; + + while (!s && (i < n)) + { + AtkObject *child; + child = atk_object_ref_accessible_child (aobject, i); + if (ATK_IS_TEXT (child)) + { + gint count = atk_text_get_character_count (ATK_TEXT (child)); + s = atk_text_get_text (ATK_TEXT (child), + 0, + count); + } + g_object_unref (child); + ++i; + } + + if (!s) + { + s = g_strdup (""); + } + return s; +} + +static gint +_print_object (AtkObject *aobject) +{ + G_CONST_RETURN gchar * parent_name = NULL; + G_CONST_RETURN gchar * name = NULL; + G_CONST_RETURN gchar * description = NULL; + G_CONST_RETURN gchar * typename = NULL; + G_CONST_RETURN gchar * parent_typename = NULL; + G_CONST_RETURN gchar * role_name = NULL; + G_CONST_RETURN gchar * accel_name = NULL; + G_CONST_RETURN gchar * text = NULL; + AtkRole role; + AtkObject *parent = NULL; + static AtkObject *prev_aobject = NULL; + gint n_children = 0; + gint index_in_parent = -1; + gchar *output_str; + gint group_num; + TabNumber tab_n = OBJECT; + + group_num = _print_groupname(tab_n, OBJECT_INTERFACE, "Object Interface"); + + name = atk_object_get_name (aobject); + typename = g_type_name (G_OBJECT_TYPE (aobject)); + description = atk_object_get_description (aobject); + parent = atk_object_get_parent(aobject); + if (parent) + index_in_parent = atk_object_get_index_in_parent(aobject); + n_children = atk_object_get_n_accessible_children(aobject); + role = atk_object_get_role(aobject); + role_name = atk_role_get_name(role); + + if (ATK_IS_ACTION (aobject)) + { + accel_name = atk_action_get_keybinding (ATK_ACTION(aobject), 0); + if (!accel_name) accel_name = ""; + } + else + { + accel_name = ""; + } + + if (GTK_IS_ACCESSIBLE (aobject) && + GTK_IS_WIDGET (GTK_ACCESSIBLE (aobject)->widget)) + { + _print_key_value(tab_n, group_num, "Widget name", + (gpointer)gtk_widget_get_name(GTK_ACCESSIBLE (aobject)->widget), + VALUE_STRING); + } + else + { + _print_key_value(tab_n, group_num, "Widget name", "No Widget", + VALUE_STRING); + } + + if (typename) + { + _print_key_value(tab_n, group_num, "Accessible Type", + (gpointer)typename, VALUE_STRING); + } + else + { + _print_key_value(tab_n, group_num, "Accessible Type", "NULL", + VALUE_STRING); + } + + if (name) + { + _print_key_value(tab_n, group_num, "Accessible Name", + (gpointer)name, VALUE_STRING); + } + else + { + _print_key_value(tab_n, group_num, "Accessible Name", "(unknown)", + VALUE_STRING); + } + if (use_festival) + { + if (aobject != prev_aobject) + { + if (ATK_IS_TEXT (aobject) && !name) + { + text = + atk_text_get_text_at_offset (ATK_TEXT (aobject), + (gint) 0, + ATK_TEXT_BOUNDARY_SENTENCE_END, + (gint *) NULL, + (gint *) NULL); + fprintf (stderr, "first sentence: %s\n", text); + _send_to_festival (role_name, + text, ""); + if (!name) name = "no name"; + } + else + { + text = ""; + if (!name) + { + if (atk_object_get_role (aobject) == ATK_ROLE_TABLE_CELL) + { + gchar *cname = ferret_get_name_from_container (aobject); + if (cname) name = g_strdup (cname); + } + else if (atk_object_get_role (aobject) == ATK_ROLE_CHECK_BOX) + { + name = g_strdup ("check box"); + } + else + { + name = "no name"; + } + } + _send_to_festival (role_name, name, accel_name); + } + } + } + + if (parent) + { + parent_name = atk_object_get_name(parent); + + parent_typename = g_type_name (G_OBJECT_TYPE (parent)); + + if (parent_typename) + { + _print_key_value(tab_n, group_num, "Parent Accessible Type", + (gpointer)parent_typename, VALUE_STRING); + } + else + { + _print_key_value(tab_n, group_num, + "Parent Accessible Type", "NULL", VALUE_STRING); + } + + if (parent_name) + { + _print_key_value(tab_n, group_num, "Parent Accessible Name", + (gpointer)parent_name, VALUE_STRING); + } + else + { + _print_key_value(tab_n, group_num, + "Parent Accessible Name", "NULL", VALUE_STRING); + } + + output_str = g_strdup_printf("%d", index_in_parent); + _print_key_value(tab_n, group_num, "Index in Parent", + (gpointer)output_str, VALUE_STRING); + g_free(output_str); + } + else + { + _print_key_value(tab_n, group_num, "Parent", "NULL", VALUE_STRING); + } + + if (description) + { + _print_key_value(tab_n, group_num, "Accessible Description", + (gpointer)description, VALUE_STRING); + } + else + { + _print_key_value(tab_n, group_num, + "Accessible Description", "NULL", VALUE_STRING); + } + + if (role_name) + { + _print_key_value(tab_n, group_num, "Accessible Role", (gpointer)role_name, + VALUE_STRING); + } + else + { + _print_key_value(tab_n, group_num, "Accessible Role", "NULL", + VALUE_STRING); + } + + output_str = g_strdup_printf("%d", n_children); + _print_key_value(tab_n, group_num, "Number Children", (gpointer)output_str, + VALUE_STRING); + g_free(output_str); + prev_aobject = aobject; + + return(group_num); +} + +static gint +_print_relation (AtkObject *aobject) +{ + AtkRelationSet* relation_set = atk_object_ref_relation_set (aobject); + gint n_relations = atk_relation_set_get_n_relations (relation_set); + gint group_num; + TabNumber tab_n = OBJECT; + + group_num = _print_groupname(tab_n, RELATION_INTERFACE, + "Relation Interface"); + + if (relation_set) + { + AtkRelation * relation; + G_CONST_RETURN gchar * relation_name = NULL; + G_CONST_RETURN gchar * relation_obj_name = NULL; + AtkRelationType relation_type; + AtkObject *relation_obj; + GPtrArray * relation_arry; + gchar *label_str; + gchar *output_str; + gint i, j; + + output_str = g_strdup_printf("%d", n_relations); + _print_key_value(tab_n, group_num, + "Number of Relations", (gpointer)output_str, VALUE_STRING); + g_free(output_str); + + for (i = 0; i < n_relations; i++) + { + relation = atk_relation_set_get_relation (relation_set, i); + + relation_type = atk_relation_get_relation_type (relation); + relation_name = atk_relation_type_get_name (relation_type); + + relation_arry = atk_relation_get_target(relation); + + if (relation_name) + { + label_str = g_strdup_printf("Relation %d Name", i + 1); + _print_key_value(tab_n, group_num, label_str, + (gpointer)relation_name, VALUE_STRING); + g_free(label_str); + } + else + { + label_str = g_strdup_printf("Relation %d Type", i + 1); + output_str = g_strdup_printf("%d", relation_type); + _print_key_value(tab_n, group_num, label_str, + (gpointer)output_str, VALUE_STRING); + g_free(label_str); + g_free(output_str); + } + + label_str = g_strdup_printf("Relation %d with", i + 1); + output_str = g_strdup_printf("%d AtkObjects", relation_arry->len); + _print_key_value(tab_n, group_num, label_str, (gpointer)output_str, + VALUE_STRING); + g_free(label_str); + g_free(output_str); + + for (j=0; j < relation_arry->len; j++) + { + label_str = g_strdup_printf( + "Relation %d,%d with AtkObject Name", i + 1, j + 1); + relation_obj = (AtkObject *) + g_ptr_array_index(relation_arry, j); + relation_obj_name = atk_object_get_name(relation_obj); + + _print_key_value(tab_n, group_num, label_str, + (gpointer)relation_obj_name, VALUE_STRING); + g_free(label_str); + } + } + + g_object_unref (relation_set); + } + return(group_num); +} + +static gint +_print_state (AtkObject *aobject) +{ + AtkStateSet *state_set = atk_object_ref_state_set(aobject); + gint group_num; + TabNumber tab_n = OBJECT; + static AtkStateType states_to_track[] = + { + ATK_STATE_ACTIVE, + ATK_STATE_CHECKED, + ATK_STATE_EXPANDED, + ATK_STATE_EXPANDABLE, + ATK_STATE_SELECTED, + ATK_STATE_SHOWING, + ATK_STATE_VISIBLE + }; + + group_num = _print_groupname(tab_n, STATE_INTERFACE, + "State Interface"); + + if (state_set) + { + gboolean boolean_value; + AtkStateType one_state; + G_CONST_RETURN gchar *name; + gint i; + + for (i=0; i < sizeof(states_to_track)/sizeof(AtkStateType); i++) + { + one_state = (AtkStateType) states_to_track[i]; + name = atk_state_type_get_name (one_state); + + if (name) + { + boolean_value = + atk_state_set_contains_state (state_set, one_state); + _print_key_value(tab_n, group_num, name, + (gpointer)(&boolean_value), VALUE_BOOLEAN); + } + } + } + + g_object_unref (state_set); + return(group_num); +} + +static gint +_print_action (AtkAction *aobject) +{ + G_CONST_RETURN gchar *action_name; + G_CONST_RETURN gchar *action_description; + G_CONST_RETURN gchar *action_keybinding; + gchar *label_str, *output_str; + gint group_num; + gint num_actions, j; + TabNumber tab_n = ACTION; + NameValue *nv; + + group_num = _print_groupname(tab_n, ACTION_INTERFACE, + "Action Interface"); + + num_actions = atk_action_get_n_actions (aobject); + output_str = g_strdup_printf("%d", num_actions); + _print_key_value(tab_n, group_num, "Number of Actions", + (gpointer) output_str, VALUE_STRING); + g_free(output_str); + + for (j = 0; j < num_actions; j++) + { + label_str = g_strdup_printf("Action %d Name", j + 1); + action_name = atk_action_get_name (aobject, j); + if (action_name) + { + nv = _print_key_value(tab_n, group_num, label_str, + (gpointer) action_name, VALUE_BUTTON); + } + else + { + nv = _print_key_value(tab_n, group_num, label_str, "NULL", + VALUE_BUTTON); + } + + nv->atkobj = ATK_OBJECT(aobject); + nv->action_num = j; + nv->signal_id = g_signal_connect (GTK_OBJECT (nv->button), + "clicked", GTK_SIGNAL_FUNC (_action_cb), nv); + + g_free(label_str); + + label_str = g_strdup_printf("Action %d Description", j + 1); + action_description = atk_action_get_description (aobject, j); + if (action_description) + { + _print_key_value(tab_n, group_num, label_str, + (gpointer)action_description, VALUE_STRING); + } + else + { + _print_key_value(tab_n, group_num, label_str, "NULL", + VALUE_STRING); + } + g_free(label_str); + + label_str = g_strdup_printf("Action %d Keybinding", j + 1); + action_keybinding = atk_action_get_keybinding (aobject, j); + if (action_keybinding) + { + _print_key_value(tab_n, group_num, label_str, + (gpointer)action_keybinding, VALUE_STRING); + } + else + { + _print_key_value(tab_n, group_num, label_str, "NULL", + VALUE_STRING); + } + g_free(label_str); + } + return(group_num); +} + +static gint +_print_component (AtkComponent *aobject) +{ + gchar *output_str; + gint x = 0; + gint y = 0; + gint width = 0; + gint height = 0; + gint group_num; + TabNumber tab_n = COMPONENT; + + group_num = _print_groupname(tab_n, COMPONENT_INTERFACE, + "Component Interface"); + + atk_component_get_extents (aobject, + &x, &y, &width, &height, ATK_XY_SCREEN); + + output_str = g_strdup_printf("x: %d y: %d width: %d height %d", + x, y, width, height); + _print_key_value(tab_n, group_num, "Geometry", (gpointer)output_str, + VALUE_STRING); + g_free(output_str); + return(group_num); +} + +static gint +_print_image (AtkImage *aobject) +{ + G_CONST_RETURN gchar *image_desc; + gchar *output_str; + gint x = 0; + gint y = 0; + gint height = 0; + gint width = 0; + gint group_num; + TabNumber tab_n = IMAGE; + + group_num = _print_groupname(tab_n, IMAGE_INTERFACE, + "Image Interface"); + + image_desc = atk_image_get_image_description(aobject); + if (image_desc) + { + _print_key_value(tab_n, group_num, "Description", (gpointer)image_desc, + VALUE_STRING); + } + else + { + _print_key_value(tab_n, group_num, "Description", "NULL", + VALUE_STRING); + } + + atk_image_get_image_position(aobject, &x, &y, ATK_XY_SCREEN); + atk_image_get_image_size(aobject, &height, &width); + + output_str = g_strdup_printf("x: %d y: %d width: %d height %d", + x, y, width, height); + _print_key_value(tab_n, group_num, "Geometry", (gpointer)output_str, + VALUE_STRING); + g_free(output_str); + return(group_num); +} + +static gint +_print_selection (AtkSelection *aobject) +{ + AtkObject *object; + AtkRole role; + gchar *label_str, *output_str; + gint group_num; + gint n_selected, j, n_selectable; + TabNumber tab_n = SELECTION; + + group_num = _print_groupname(tab_n, SELECTION_INTERFACE, + "Selection Interface"); + + n_selected = atk_selection_get_selection_count (aobject); + output_str = g_strdup_printf ("%d", n_selected); + _print_key_value (tab_n, group_num, "Number of Selected Children", + (gpointer) output_str, VALUE_STRING); + g_free (output_str); + /* + * The number of selected items is the number of children except for + * a ComboBox where it is the number of items in the list. + */ + object = ATK_OBJECT (aobject); + role = atk_object_get_role (object); + if (role == ATK_ROLE_COMBO_BOX) + { + object = atk_object_ref_accessible_child (object, 0); + g_return_val_if_fail (atk_object_get_role (object) == ATK_ROLE_LIST, + group_num); + n_selectable = atk_object_get_n_accessible_children (object); + g_object_unref (G_OBJECT (object)); + } + else + { + n_selectable = atk_object_get_n_accessible_children (object); + } + output_str = g_strdup_printf ("%d", n_selectable); + _print_key_value (tab_n, group_num, "Number of Selectable Children", + (gpointer) output_str, VALUE_STRING); + g_free (output_str); + + for (j = 0; j < n_selected; j++) + { + G_CONST_RETURN gchar *selected_name; + AtkObject *selected_object; + + selected_object = atk_selection_ref_selection (aobject, j); + selected_name = atk_object_get_name (selected_object); + if (selected_name == NULL) + { + selected_name = "No name"; + } + label_str = g_strdup_printf ("Selected item: %d Name", j+1); + _print_key_value (tab_n, group_num, label_str, + (gpointer) selected_name, VALUE_STRING); + g_free (label_str); + g_object_unref (G_OBJECT (selected_object)); + } + return group_num; +} + +static gint +_print_table (AtkTable *aobject) +{ + gchar *label_str, *output_str; + G_CONST_RETURN gchar *col_desc; + AtkObject *caption; + gint n_cols, n_rows; + gint i; + gint group_num; + TabNumber tab_n = TABLE; + + group_num = _print_groupname(tab_n, TABLE_INTERFACE, + "Table Interface"); + + n_cols = atk_table_get_n_columns(aobject); + output_str = g_strdup_printf("%d", n_cols); + _print_key_value(tab_n, group_num, "Number Columns", (gpointer)output_str, + VALUE_STRING); + g_free(output_str); + + n_rows = atk_table_get_n_rows(aobject); + output_str = g_strdup_printf("%d", n_rows); + _print_key_value(tab_n, group_num, "Number Rows", (gpointer)output_str, + VALUE_STRING); + g_free(output_str); + + caption = atk_table_get_caption(aobject); + if (caption) + { + G_CONST_RETURN gchar* caption_name; + + caption_name = atk_object_get_name (caption); + if (caption_name) + { + _print_key_value(tab_n, group_num, "Caption Name", + (gpointer)caption_name, VALUE_STRING); + } + } + + for (i=0; i < n_cols; i++) + { + label_str = g_strdup_printf("Column %d Description", i + 1); + + col_desc = atk_table_get_column_description(aobject, i); + if (col_desc) + { + _print_key_value(tab_n, group_num, label_str, (gpointer)col_desc, + VALUE_STRING); + } + else + { + _print_key_value(tab_n, group_num, label_str, "NULL", + VALUE_STRING); + } + + g_free(label_str); + } + + return(group_num); +} + +static gint +_print_text (AtkText *aobject) +{ + gchar *output_str, *text_val, *text_val_escaped; + gint n_chars, caret_offset; + gint start_offset, end_offset; + gint group_num; + gint x, y, w, h; + TabNumber tab_n = TEXT; + + group_num = _print_groupname(tab_n, TEXT_INTERFACE, + "Text Content"); + + n_chars = atk_text_get_character_count(aobject); + + output_str = g_strdup_printf("%d", n_chars); + _print_key_value(tab_n, group_num, "Total Character Count", + (gpointer)output_str, VALUE_STRING); + g_free(output_str); + + /* + * Pass through g_strescape so that non-ASCII chars are made + * print-able. + */ + text_val = atk_text_get_text (aobject, 0, n_chars); + if (text_val) + { + text_val_escaped = g_strescape(text_val, NULL); + _print_key_value (tab_n, group_num, "Text", (gpointer)text_val_escaped, + VALUE_TEXT); + g_free (text_val); + g_free (text_val_escaped); + } + else + { + _print_key_value (tab_n, group_num, "Text", "NULL", VALUE_TEXT); + } + + caret_offset = atk_text_get_caret_offset(aobject); + output_str = g_strdup_printf("%d", caret_offset); + _print_key_value(tab_n, group_num, "Caret Offset", (gpointer)output_str, + VALUE_STRING); + g_free(output_str); + + if (caret_offset < 0) + return(group_num); + + text_val = atk_text_get_text_at_offset (aobject, caret_offset, + ATK_TEXT_BOUNDARY_CHAR, + &start_offset, &end_offset); + if (text_val) + { + text_val_escaped = g_strescape(text_val, NULL); + _print_key_value(tab_n, group_num, "Current Character", + (gpointer)text_val_escaped, VALUE_STRING); + g_free (text_val); + g_free (text_val_escaped); + } + else + { + _print_key_value(tab_n, group_num, "Current Character", "none", + VALUE_STRING); + } + + atk_text_get_character_extents (aobject, caret_offset, + &x, &y, &w, &h, ATK_XY_SCREEN); + output_str = g_strdup_printf ("(%d, %d) (%d, %d)", x, y, w, h); + if (output_str) + { + _print_key_value(tab_n, group_num, "Character Bounds (screen)", + (gpointer)output_str, VALUE_STRING); + g_free(output_str); + } + + atk_text_get_character_extents (aobject, caret_offset, + &x, &y, &w, &h, ATK_XY_WINDOW); + output_str = g_strdup_printf ("(%d, %d) (%d, %d)", x, y, w, h); + if (output_str) + { + _print_key_value(tab_n, group_num, "Character Bounds (window)", + (gpointer)output_str, VALUE_STRING); + g_free(output_str); + } + + text_val = atk_text_get_text_at_offset (aobject, caret_offset, + ATK_TEXT_BOUNDARY_WORD_START, + &start_offset, &end_offset); + if (text_val) + { + text_val_escaped = g_strescape(text_val, NULL); + _print_key_value(tab_n, group_num, "Current Word", + (gpointer)text_val_escaped, VALUE_STRING); + g_free (text_val); + g_free (text_val_escaped); + } + else + { + _print_key_value(tab_n, group_num, "Current Word", "none", + VALUE_STRING); + } + + text_val = atk_text_get_text_at_offset (aobject, caret_offset, + ATK_TEXT_BOUNDARY_LINE_START, + &start_offset, &end_offset); + if (text_val) + { + text_val_escaped = g_strescape(text_val, NULL); + _print_key_value(tab_n, group_num, "Current Line", + (gpointer)text_val_escaped, VALUE_STRING); + g_free (text_val); + g_free (text_val_escaped); + } + else + { + _print_key_value(tab_n, group_num, "Current Line", "none", + VALUE_STRING); + } + + text_val = atk_text_get_text_at_offset (aobject, caret_offset, + ATK_TEXT_BOUNDARY_SENTENCE_START, + &start_offset, &end_offset); + if (text_val) + { + text_val_escaped = g_strescape(text_val, NULL); + _print_key_value(tab_n, group_num, "Current Sentence", + (gpointer)text_val_escaped, VALUE_STRING); + g_free (text_val); + g_free (text_val_escaped); + } + else + { + _print_key_value(tab_n, group_num, "Current Line", "none", + VALUE_STRING); + } + return(group_num); +} + +static gint +_print_text_attributes (AtkText *aobject) +{ + AtkAttributeSet *attribute_set; + AtkAttribute *attribute; + gchar *output_str, *label_str; + gint start_offset, end_offset, caret_offset; + gint attribute_set_len, attribute_offset, i; + gint n_chars; + gint group_num; + TabNumber tab_n = TEXT; + + n_chars = atk_text_get_character_count(aobject); + + group_num = _print_groupname (tab_n, TEXT_ATTRIBUTES, + "Text Attributes at Caret"); + + caret_offset = atk_text_get_caret_offset(aobject); + attribute_offset = caret_offset; + + start_offset = 0; + end_offset = 0; + + attribute_set = atk_text_get_run_attributes(aobject, attribute_offset, + &start_offset, &end_offset); + + label_str = g_strdup_printf("Attribute run start"); + + output_str = g_strdup_printf("%d", start_offset); + _print_key_value(tab_n, group_num, label_str, (gpointer)output_str, + VALUE_STRING); + g_free(label_str); + g_free(output_str); + + label_str = g_strdup_printf("Attribute run end"); + output_str = g_strdup_printf("%d", end_offset); + _print_key_value(tab_n, group_num, label_str, (gpointer)output_str, + VALUE_STRING); + g_free(label_str); + g_free(output_str); + + if (attribute_set == NULL) + attribute_set_len = 0; + else + attribute_set_len = g_slist_length(attribute_set); + + label_str = g_strdup_printf("Number of Attributes"); + output_str = g_strdup_printf("%d", attribute_set_len); + _print_key_value(tab_n, group_num, label_str, (gpointer)output_str, + VALUE_STRING); + g_free(label_str); + g_free(output_str); + + for (i=0; i < attribute_set_len; i++) + { + attribute = ((AtkAttribute *) g_slist_nth(attribute_set, i)->data); + + _print_key_value(tab_n, group_num, attribute->name, + (gpointer)attribute->value, VALUE_STRING); + } + if (attribute_set != NULL) + atk_attribute_set_free(attribute_set); + + + return(group_num); +} + +static gint +_print_value (AtkValue *aobject) +{ + GValue *value_back, val; + gint group_num; + TabNumber tab_n = VALUE; + + value_back = &val; + + group_num = _print_groupname(tab_n, VALUE_INTERFACE, + "Value Interface"); + + atk_value_get_current_value(aobject, value_back); + _print_value_type(group_num, "Value", value_back); + atk_value_get_minimum_value(aobject, value_back); + _print_value_type(group_num, "Minimum Value", value_back); + atk_value_get_maximum_value(aobject, value_back); + _print_value_type(group_num, "Maximum Value", value_back); + return(group_num); +} + +static void +_print_value_type(gint group_num, gchar *type, GValue *value) +{ + gchar *label_str = NULL; + gchar *output_str = NULL; + TabNumber tab_n = VALUE; + + if (G_VALUE_HOLDS_DOUBLE (value)) + { + label_str = g_strdup_printf("%s - Double", type); + output_str = g_strdup_printf("%f", + g_value_get_double (value)); + _print_key_value(tab_n, group_num, label_str, (gpointer)output_str, + VALUE_STRING); + } + else if (G_VALUE_HOLDS_INT (value)) + { + label_str = g_strdup_printf("%s - Integer", type); + output_str = g_strdup_printf("%d", + g_value_get_int (value)); + _print_key_value(tab_n, group_num, label_str, (gpointer)output_str, + VALUE_STRING); + } + else + { + _print_key_value(tab_n, group_num, "Value", "Unknown Type", + VALUE_STRING); + } + + if (label_str) + g_free(label_str); + if (output_str) + g_free(output_str); +} + +static void +_create_event_watcher (void) +{ + focus_tracker_id = atk_add_focus_tracker (_print_accessible); + + if (track_mouse) + { + mouse_watcher_focus_id = + atk_add_global_event_listener(_mouse_watcher, + "Gtk:GtkWidget:enter_notify_event"); + mouse_watcher_button_id = + atk_add_global_event_listener(_button_watcher, + "Gtk:GtkWidget:button_press_event"); + } +} + +static gboolean +_mouse_watcher (GSignalInvocationHint *ihint, + guint n_param_values, + const GValue *param_values, + gpointer data) +{ + GObject *object; + GtkWidget *widget; + + object = g_value_get_object (param_values + 0); + + if (GTK_IS_MENU(object)) return TRUE; + + g_assert (GTK_IS_WIDGET(object)); + + widget = GTK_WIDGET (object); + if (GTK_IS_WINDOW (widget)) + { + GtkWidget *focus_widget = GTK_WINDOW (widget)->focus_widget; + if (focus_widget != NULL) + widget = focus_widget; + } + + _print_accessible (gtk_widget_get_accessible (widget)); + return TRUE; +} + +static gboolean +_button_watcher (GSignalInvocationHint *ihint, + guint n_param_values, + const GValue *param_values, + gpointer data) +{ + GObject *object; + GtkWidget *widget; + + object = g_value_get_object (param_values + 0); + + widget = GTK_WIDGET (object); + if (GTK_IS_CONTAINER (widget)) + { + if (G_VALUE_HOLDS_BOXED (param_values + 1)) + { + GdkEventButton *event; + gpointer gp; + AtkObject *aobject; + AtkObject *child; + gint aobject_x, aobject_y; + gint x, y; + + gp = g_value_get_boxed (param_values + 1); + event = (GdkEventButton *) gp; + aobject = gtk_widget_get_accessible (widget); + aobject_x = aobject_y = 0; + atk_component_get_position (ATK_COMPONENT (aobject), + &aobject_x, &aobject_y, + ATK_XY_WINDOW); + x = aobject_x + (gint) event->x; + y = aobject_y + (gint) event->y; + child = atk_component_ref_accessible_at_point (ATK_COMPONENT (aobject), + x, + y, + ATK_XY_WINDOW); + if (child) + { + _print_accessible (child); + g_object_unref (child); + } + else + { + if (!GTK_IS_MENU_ITEM (widget)) + { + g_print ("No child at position %d %d for %s\n", + x, + y, + g_type_name (G_OBJECT_TYPE (widget))); + } + } + } + } + + return TRUE; +} + +static void _add_notebook_page (GtkNotebook *nbook, + GtkWidget *content_widget, + GtkWidget **new_page, + const gchar *label_text) +{ + GtkWidget *label; + + if (content_widget != NULL) + { + *new_page = content_widget; + } + else + { + *new_page = gtk_vpaned_new (); + } + + label = gtk_label_new (""); + gtk_label_set_markup_with_mnemonic (GTK_LABEL (label), label_text); + gtk_notebook_append_page (notebook, *new_page, label); + gtk_widget_show(*new_page); +} + +static void +_create_notebook (void) +{ + TabInfo *tab; + notebook = GTK_NOTEBOOK (gtk_notebook_new()); + + tab = nbook_tabs[OBJECT]; + _add_notebook_page (notebook, tab->main_box, &tab->page, "_Object"); + + tab = nbook_tabs[ACTION]; + _add_notebook_page (notebook, tab->main_box, &tab->page, "_Action"); + + tab = nbook_tabs[COMPONENT]; + _add_notebook_page (notebook, tab->main_box, &tab->page, "_Component"); + + tab = nbook_tabs[IMAGE]; + _add_notebook_page (notebook, tab->main_box, &tab->page, "_Image"); + + tab = nbook_tabs[SELECTION]; + _add_notebook_page (notebook, tab->main_box, &tab->page, "_Selection"); + + tab = nbook_tabs[TABLE]; + _add_notebook_page (notebook, tab->main_box, &tab->page, "_Table"); + + tab = nbook_tabs[TEXT]; + _add_notebook_page (notebook, tab->main_box, &tab->page, "Te_xt"); + + tab = nbook_tabs[VALUE]; + _add_notebook_page (notebook, tab->main_box, &tab->page, "_Value"); + + g_signal_connect (GTK_OBJECT (notebook), + "switch-page", + GTK_SIGNAL_FUNC (_update_current_page), + NULL); +} + +static void +_init_data(void) +{ + TabInfo *the_tab; + + the_tab = g_new0(TabInfo, 1); + the_tab->page = NULL; + the_tab->main_box = gtk_vbox_new(FALSE, 20); + the_tab->name = "Object"; + nbook_tabs[OBJECT] = the_tab; + + the_tab = g_new0(TabInfo, 1); + the_tab->page = NULL; + the_tab->main_box = gtk_vbox_new(FALSE, 20); + the_tab->name = "Action"; + nbook_tabs[ACTION] = the_tab; + + the_tab = g_new0(TabInfo, 1); + the_tab->page = NULL; + the_tab->main_box = gtk_vbox_new(FALSE, 20); + the_tab->name = "Component"; + nbook_tabs[COMPONENT] = the_tab; + + the_tab = g_new0(TabInfo, 1); + the_tab->page = NULL; + the_tab->main_box = gtk_vbox_new(FALSE, 20); + the_tab->name = "Image"; + nbook_tabs[IMAGE] = the_tab; + + the_tab = g_new0(TabInfo, 1); + the_tab->page = NULL; + the_tab->main_box = gtk_vbox_new(FALSE, 20); + the_tab->name = "Selection"; + nbook_tabs[SELECTION] = the_tab; + + the_tab = g_new0(TabInfo, 1); + the_tab->page = NULL; + the_tab->main_box = gtk_vbox_new(FALSE, 20); + the_tab->name = "Table"; + nbook_tabs[TABLE] = the_tab; + + the_tab = g_new0(TabInfo, 1); + the_tab->page = NULL; + the_tab->main_box = gtk_vbox_new(FALSE, 20); + the_tab->name = "Text"; + nbook_tabs[TEXT] = the_tab; + + the_tab = g_new0(TabInfo, 1); + the_tab->page = NULL; + the_tab->main_box = gtk_vbox_new(FALSE, 20); + the_tab->name = "Value"; + nbook_tabs[VALUE] = the_tab; +} + +static void +_create_window (void) +{ + static GtkWidget *window = NULL; + + if (!window) + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_widget_set_name (window, "Ferret Window"); + gtk_window_set_policy (GTK_WINDOW(window), TRUE, TRUE, FALSE); + + g_signal_connect (GTK_OBJECT (window), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroyed), + &window); + + gtk_window_set_title (GTK_WINDOW (window), "GTK+ Ferret Output"); + gtk_window_set_default_size (GTK_WINDOW (window), 333, 550); + gtk_container_set_border_width (GTK_CONTAINER (window), 0); + + vbox1 = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), vbox1); + gtk_widget_show (vbox1); + + menubar = gtk_menu_bar_new (); + gtk_box_pack_start (GTK_BOX (vbox1), menubar, FALSE, TRUE, 0); + gtk_widget_show (menubar); + menutop = gtk_menu_item_new_with_label("Menu"); + gtk_menu_bar_append(GTK_MENU_BAR(menubar), menutop); + gtk_widget_show (menutop); + menu = gtk_menu_new(); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (menutop), menu); + gtk_widget_show (menu); + + _add_menu(&menu, &menuitem_trackmouse, "Track Mouse", track_mouse, + GTK_SIGNAL_FUNC(_toggle_trackmouse)); + _add_menu(&menu, &menuitem_trackfocus, "Track Focus", track_focus, + GTK_SIGNAL_FUNC(_toggle_trackfocus)); + _add_menu(&menu, &menuitem_magnifier, "Magnifier", use_magnifier, + GTK_SIGNAL_FUNC(_toggle_magnifier)); + _add_menu(&menu, &menuitem_festival, "Festival", use_festival, + GTK_SIGNAL_FUNC(_toggle_festival)); + _add_menu(&menu, &menuitem_festival_terse, "Festival Terse", + (!say_role && !say_accel), + GTK_SIGNAL_FUNC(_toggle_festival_terse)); + _add_menu(&menu, &menuitem_terminal, "Terminal Output", display_ascii, + GTK_SIGNAL_FUNC(_toggle_terminal)); + _add_menu(&menu, &menuitem_no_signals, "No ATK Signals", no_signals, + GTK_SIGNAL_FUNC(_toggle_no_signals)); + + _create_notebook (); + gtk_container_add (GTK_CONTAINER (vbox1), GTK_WIDGET (notebook)); + gtk_widget_show (GTK_WIDGET (notebook)); + } + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + + mainWindow = GTK_WIDGET (window); +} + +static void +_add_menu(GtkWidget ** menu, GtkWidget ** menuitem, gchar * name, + gboolean init_value, GCallback func) +{ + *menuitem = gtk_check_menu_item_new_with_label(name); + gtk_check_menu_item_set_active( + GTK_CHECK_MENU_ITEM(*menuitem), init_value); + gtk_menu_shell_append (GTK_MENU_SHELL (*menu), *menuitem); + gtk_widget_show(*menuitem); + g_signal_connect(GTK_OBJECT(*menuitem), "toggled", func, NULL); +} + +int +gtk_module_init(gint argc, char* argv[]) +{ + if (g_getenv ("FERRET_ASCII")) + display_ascii = TRUE; + + if (g_getenv ("FERRET_NOSIGNALS")) + no_signals = TRUE; + + if (display_ascii) + g_print("GTK ferret Module loaded\n"); + + if (g_getenv("FERRET_MAGNIFIER")) + use_magnifier = TRUE; + + if (g_getenv ("FERRET_FESTIVAL")) + use_festival = TRUE; + + if (g_getenv ("FERRET_MOUSETRACK")) + track_mouse = TRUE; + + if (g_getenv ("FERRET_TERSE")) + { + say_role = FALSE; + say_accel = FALSE; + } + + _init_data(); + + _create_window(); + + _create_event_watcher(); + + return 0; +} + +static void +_clear_tab(TabNumber tab_n) +{ + GList *group_list, *nv_list; + TabInfo *tab; + GroupInfo *group; + NameValue *nv; + + tab = nbook_tabs[tab_n]; + + for (group_list = tab->groups; group_list; group_list = group_list->next) + { + group = (GroupInfo *) group_list->data; + + if (group->is_scrolled) + gtk_widget_hide(GTK_WIDGET(group->scroll_outer_frame)); + + gtk_widget_hide(GTK_WIDGET(group->frame)); + gtk_widget_hide(GTK_WIDGET(group->group_vbox)); + + for (nv_list = group->name_value; nv_list; nv_list = nv_list->next) + { + nv = (NameValue *) nv_list->data; + nv->active = FALSE; + gtk_widget_hide(GTK_WIDGET(nv->column1)); + gtk_widget_hide(GTK_WIDGET(nv->column2)); + gtk_widget_hide(GTK_WIDGET(nv->label)); + + switch (nv->type) + { + case VALUE_STRING: + gtk_widget_hide(GTK_WIDGET(nv->string)); + break; + case VALUE_BOOLEAN: + gtk_widget_hide(GTK_WIDGET(nv->boolean)); + break; + case VALUE_TEXT: + gtk_widget_hide(GTK_WIDGET(nv->text)); + break; + case VALUE_BUTTON: + gtk_widget_hide(GTK_WIDGET(nv->button)); + break; + } + gtk_widget_hide(GTK_WIDGET(nv->hbox)); + + /* Disconnect signal handler if any */ + if (nv->signal_id != -1) + g_signal_handler_disconnect(nv->button, nv->signal_id); + + nv->signal_id = -1; + } + } +} + +static gint +_print_groupname(TabNumber tab_n, GroupId group_id, + const char *groupname) +{ + TabInfo *tab; + GroupInfo *the_group; + gint rc = -1; + + if (display_ascii) + g_print("\n<%s>\n", groupname); + + tab = nbook_tabs[tab_n]; + the_group = _get_group(tab, group_id, groupname); + rc = g_list_index(tab->groups, the_group); + return rc; +} + +static GroupInfo* +_get_group(TabInfo *tab, GroupId group_id, const gchar *groupname) +{ + GroupInfo *group = NULL; + gboolean found = FALSE; + GList *group_list; + + for (group_list = tab->groups; group_list; group_list = group_list->next) + { + group = (GroupInfo *) group_list->data; + if (group_id == group->group_id) + { + found = TRUE; + break; + } + } + + if (!found) + { + /* build a new one */ + group = (GroupInfo *)g_new0(GroupInfo, 1); + group->group_id = group_id; + _get_group_scrolled(group); + + if (group->is_scrolled) + { + group->frame = gtk_scrolled_window_new (NULL, NULL); + gtk_widget_set_usize(GTK_WIDGET(group->frame), -2, + group->default_height); + group->scroll_outer_frame = GTK_FRAME(gtk_frame_new(groupname)); + gtk_container_add(GTK_CONTAINER(group->scroll_outer_frame), + group->frame); + } + else + { + group->frame = gtk_frame_new(groupname); + } + + gtk_container_set_border_width(GTK_CONTAINER(group->frame), 10); + + group->name = g_strdup(groupname); + group->group_vbox = GTK_VBOX(gtk_vbox_new(FALSE, 10)); + + if (group->is_scrolled) + { + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (group->frame), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_add_with_viewport( + GTK_SCROLLED_WINDOW(group->frame), + GTK_WIDGET(group->group_vbox)); + } + else + { + gtk_container_add(GTK_CONTAINER(group->frame), + GTK_WIDGET(group->group_vbox)); + } + + tab->groups = g_list_append (tab->groups, group); + + if (group->is_scrolled) + { + gtk_box_pack_start_defaults(GTK_BOX(tab->main_box), + GTK_WIDGET(group->scroll_outer_frame)); + } + else + { + gtk_box_pack_start_defaults(GTK_BOX(tab->main_box), + GTK_WIDGET(group->frame)); + } + } + + return group; +} + +void +_get_group_scrolled(GroupInfo *group) +{ + if (group->group_id == OBJECT_INTERFACE) + { + group->is_scrolled = FALSE; + } + else if (group->group_id == RELATION_INTERFACE) + { + group->is_scrolled = TRUE; + group->default_height = 50; + } + else if (group->group_id == STATE_INTERFACE) + { + group->is_scrolled = TRUE; + group->default_height = 100; + } + else if (group->group_id == ACTION_INTERFACE) + { + group->is_scrolled = TRUE; + group->default_height = 200; + } + else if (group->group_id == TEXT_ATTRIBUTES) + { + group->is_scrolled = TRUE; + group->default_height = 70; + } + else + { + group->is_scrolled = FALSE; + } +} + +NameValue * +_get_name_value(GroupInfo *group, const gchar *label, + gpointer value_ptr, ValueType type) +{ + NameValue *name_value = NULL; + GList *nv_list; + GValue *value; + gboolean found = FALSE; + static char *empty_string = ""; + + if (!label) + { + label = empty_string; + } + + for (nv_list = group->name_value; nv_list; nv_list = nv_list->next) + { + name_value = (NameValue *) nv_list->data; + if (!name_value->active) + { + found = TRUE; + break; + } + } + + if (!found) + { + name_value = (NameValue *)g_new0(NameValue, 1); + name_value->column1 = GTK_HBOX(gtk_hbox_new(FALSE, 10)); + name_value->column2 = GTK_HBOX(gtk_hbox_new(FALSE, 10)); + name_value->hbox = GTK_HBOX(gtk_hbox_new(FALSE, 5)); + name_value->label = GTK_LABEL(gtk_label_new(label)); + name_value->string = gtk_label_new (NULL); + name_value->boolean = gtk_check_button_new (); + name_value->text = gtk_entry_new_with_max_length (1000); + name_value->button = GTK_BUTTON(gtk_button_new ()); + + gtk_box_pack_end(GTK_BOX(name_value->column1), + GTK_WIDGET(name_value->label), FALSE, FALSE, 10); + + switch (type) + { + case VALUE_STRING: + gtk_label_set_text(GTK_LABEL(name_value->string), + (gchar *) value_ptr); + gtk_box_pack_start(GTK_BOX(name_value->column2), + GTK_WIDGET(name_value->string), FALSE, FALSE, 10); + break; + case VALUE_BOOLEAN: + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(name_value->boolean), + *((gboolean *)value_ptr)); + gtk_widget_set_sensitive(name_value->boolean, FALSE); + gtk_box_pack_start(GTK_BOX(name_value->column2), + GTK_WIDGET(name_value->boolean), FALSE, FALSE, 10); + break; + case VALUE_TEXT: + gtk_entry_set_text (GTK_ENTRY (name_value->text), + (gchar *)value_ptr); + gtk_box_pack_start(GTK_BOX(name_value->column2), + GTK_WIDGET(name_value->text), FALSE, FALSE, 10); + case VALUE_BUTTON: + value = &(name_value->button_gval); + memset (value, 0, sizeof (GValue)); + g_value_init (value, G_TYPE_STRING); + g_value_set_string (value, (gchar *)value_ptr); + g_object_set_property(G_OBJECT(name_value->button), + "label", value); + gtk_box_pack_start(GTK_BOX(name_value->column2), + GTK_WIDGET(name_value->button), FALSE, FALSE, 10); + break; + } + + gtk_box_pack_start_defaults(GTK_BOX(name_value->hbox), + GTK_WIDGET(name_value->column1)); + gtk_box_pack_start_defaults(GTK_BOX(name_value->hbox), + GTK_WIDGET(name_value->column2)); + gtk_container_add(GTK_CONTAINER(group->group_vbox), + GTK_WIDGET(name_value->hbox)); + group->name_value = g_list_append (group->name_value, name_value); + } + else + { + gtk_label_set_text(GTK_LABEL(name_value->label), label); + switch (type) + { + case VALUE_STRING: + gtk_label_set_text(GTK_LABEL(name_value->string), + (gchar *) value_ptr); + break; + case VALUE_BOOLEAN: + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(name_value->boolean), + *((gboolean *)value_ptr)); + gtk_widget_set_sensitive(name_value->boolean, FALSE); + break; + case VALUE_TEXT: + gtk_entry_set_text (GTK_ENTRY (name_value->text), + (gchar *) value_ptr); + break; + case VALUE_BUTTON: + value = &(name_value->button_gval); + memset (value, 0, sizeof (GValue)); + g_value_init (value, G_TYPE_STRING); + g_value_set_string (value, (gchar *)value_ptr); + g_object_set_property(G_OBJECT(name_value->button), + "label", value); + break; + } + } + + name_value->active = TRUE; + name_value->type = type; + name_value->signal_id = -1; + + gtk_widget_show(GTK_WIDGET(name_value->label)); + + switch (type) + { + case VALUE_STRING: + gtk_widget_show(GTK_WIDGET(name_value->string)); + break; + case VALUE_BOOLEAN: + gtk_widget_show(GTK_WIDGET(name_value->boolean)); + break; + case VALUE_TEXT: + gtk_widget_show(GTK_WIDGET(name_value->text)); + break; + case VALUE_BUTTON: + gtk_widget_show(GTK_WIDGET(name_value->button)); + break; + } + + gtk_widget_show(GTK_WIDGET(name_value->column1)); + gtk_widget_show(GTK_WIDGET(name_value->column2)); + gtk_widget_show(GTK_WIDGET(name_value->hbox)); + gtk_widget_show(GTK_WIDGET(group->group_vbox)); + + return name_value; +} + +static NameValue * +_print_key_value(TabNumber tab_n, gint group_number, + const char *label, gpointer value, ValueType type) +{ + TabInfo *tab; + GroupInfo *the_group; + + if (display_ascii) + { + if (type == VALUE_BOOLEAN) + { + if (*((gboolean *)value)) + g_print("\t%-30s\tTRUE\n", label); + else + g_print("\t%-30s\tFALSE\n", label); + } + else + { + g_print("\t%-30s\t%s\n", label, + value ? (gchar *)value : "NULL"); + } + } + + tab = nbook_tabs[tab_n]; + the_group = (GroupInfo *)g_list_nth_data(tab->groups, group_number); + return _get_name_value(the_group, label, (gpointer)value, type); +} + +static void +_finished_group(TabNumber tab_no, gint group_number) +{ + TabInfo *tab; + GroupInfo *the_group; + + tab = nbook_tabs[tab_no]; + + the_group = (GroupInfo *)g_list_nth_data(tab->groups, group_number); + + if (the_group->is_scrolled) + gtk_widget_show(GTK_WIDGET(the_group->scroll_outer_frame)); + + gtk_widget_show(GTK_WIDGET(the_group->frame)); + gtk_widget_show(GTK_WIDGET(the_group->group_vbox)); + gtk_widget_show(GTK_WIDGET(tab->main_box)); +} + +/* Signal handlers */ + +static gulong child_added_id = 0; +static gulong child_removed_id = 0; +static gulong state_change_id = 0; + +static gulong text_caret_handler_id = 0; +static gulong text_inserted_id = 0; +static gulong text_deleted_id = 0; + +static gulong table_row_inserted_id = 0; +static gulong table_column_inserted_id = 0; +static gulong table_row_deleted_id = 0; +static gulong table_column_deleted_id = 0; +static gulong table_row_reordered_id = 0; +static gulong table_column_reordered_id = 0; + +static gulong property_id = 0; + +static void +_update_handlers(AtkObject *obj) +{ + /* Remove signal handlers from object that had focus before */ + + if (last_object != NULL && G_TYPE_CHECK_INSTANCE(last_object)) + { + if (child_added_id != 0) + g_signal_handler_disconnect(last_object, child_added_id); + if (child_removed_id != 0) + g_signal_handler_disconnect(last_object, child_removed_id); + if (state_change_id != 0) + g_signal_handler_disconnect(last_object, state_change_id); + + if (text_caret_handler_id != 0) + g_signal_handler_disconnect(last_object, text_caret_handler_id); + if (text_inserted_id != 0) + g_signal_handler_disconnect(last_object, text_inserted_id); + if (text_deleted_id != 0) + g_signal_handler_disconnect(last_object, text_deleted_id); + + if (table_row_inserted_id != 0) + g_signal_handler_disconnect(last_object, table_row_inserted_id); + if (table_column_inserted_id != 0) + g_signal_handler_disconnect(last_object, table_column_inserted_id); + if (table_row_deleted_id != 0) + g_signal_handler_disconnect(last_object, table_row_deleted_id); + if (table_column_deleted_id != 0) + g_signal_handler_disconnect(last_object, table_column_deleted_id); + if (table_row_reordered_id != 0) + g_signal_handler_disconnect(last_object, table_row_reordered_id); + if (table_column_reordered_id != 0) + g_signal_handler_disconnect(last_object, table_column_reordered_id); + if (property_id != 0) + g_signal_handler_disconnect(last_object, property_id); + + g_object_unref(last_object); + } + + last_object = NULL; + + child_added_id = 0; + child_removed_id = 0; + text_caret_handler_id = 0; + text_inserted_id = 0; + text_deleted_id = 0; + table_row_inserted_id = 0; + table_column_inserted_id = 0; + table_row_deleted_id = 0; + table_column_deleted_id = 0; + table_row_reordered_id = 0; + table_column_reordered_id = 0; + property_id = 0; + + if (!G_TYPE_CHECK_INSTANCE(obj)) + return; + + g_object_ref(obj); + last_object = obj; + + /* Add signal handlers to object that now has focus. */ + + if (ATK_IS_OBJECT(obj)) + { + child_added_id = g_signal_connect_closure (obj, + "children_changed::add", + g_cclosure_new (G_CALLBACK (_notify_object_child_added), + NULL, NULL), FALSE); + + child_removed_id = g_signal_connect_closure (obj, + "children_changed::remove", + g_cclosure_new (G_CALLBACK (_notify_object_child_removed), + NULL, NULL), FALSE); + + state_change_id = g_signal_connect_closure (obj, + "state_change", + g_cclosure_new (G_CALLBACK (_notify_object_state_change), + NULL, NULL), FALSE); + } + + if (ATK_IS_TEXT(obj)) + { + text_caret_handler_id = g_signal_connect_closure_by_id (obj, + g_signal_lookup ("text_caret_moved", G_OBJECT_TYPE (obj)), + 0, g_cclosure_new (G_CALLBACK (_notify_caret_handler), + NULL, NULL), FALSE); + text_inserted_id = g_signal_connect_closure (obj, + "text_changed::insert", + g_cclosure_new (G_CALLBACK (_notify_text_insert_handler), + NULL, NULL), FALSE); + text_deleted_id = g_signal_connect_closure (obj, + "text_changed::delete", + g_cclosure_new (G_CALLBACK (_notify_text_delete_handler), + NULL, NULL), FALSE); + } + + if (ATK_IS_TABLE(obj)) + { + table_row_inserted_id = g_signal_connect_closure_by_id (obj, + g_signal_lookup ("row_inserted", G_OBJECT_TYPE (obj)), + 0, g_cclosure_new (G_CALLBACK (_notify_table_row_inserted), + NULL, NULL), FALSE); + table_column_inserted_id = g_signal_connect_closure_by_id (obj, + g_signal_lookup ("column_inserted", G_OBJECT_TYPE (obj)), + 0, g_cclosure_new (G_CALLBACK (_notify_table_column_inserted), + NULL, NULL), FALSE); + table_row_deleted_id = g_signal_connect_closure_by_id (obj, + g_signal_lookup ("row_deleted", G_OBJECT_TYPE (obj)), + 0, g_cclosure_new (G_CALLBACK (_notify_table_row_deleted), + NULL, NULL), FALSE); + table_column_deleted_id = g_signal_connect_closure_by_id (obj, + g_signal_lookup ("column_deleted", G_OBJECT_TYPE (obj)), + 0, g_cclosure_new (G_CALLBACK (_notify_table_column_deleted), + NULL, NULL), FALSE); + table_row_reordered_id = g_signal_connect_closure_by_id (obj, + g_signal_lookup ("row_reordered", G_OBJECT_TYPE (obj)), + 0, g_cclosure_new (G_CALLBACK (_notify_table_row_reordered), + NULL, NULL), FALSE); + table_column_reordered_id = g_signal_connect_closure_by_id (obj, + g_signal_lookup ("column_reordered", G_OBJECT_TYPE (obj)), + 0, g_cclosure_new (G_CALLBACK (_notify_table_column_reordered), + NULL, NULL), FALSE); + } + + property_id = g_signal_connect_closure_by_id (obj, + g_signal_lookup ("property_change", G_OBJECT_TYPE (obj)), + 0, g_cclosure_new (G_CALLBACK (_property_change_handler), + NULL, NULL), + FALSE); +} + +/* Text signals */ + +static void +_notify_text_insert_handler (GObject *obj, int position, int offset) +{ + gchar *text = atk_text_get_text (ATK_TEXT (obj), position, position + offset); + gchar *output_str = g_strdup_printf("position %d, length %d text: %s", + position, offset, text ? text: ""); + _print_signal(ATK_OBJECT(obj), FERRET_SIGNAL_TEXT, + "Text Insert", output_str); + g_free(output_str); +} + +static void +_notify_text_delete_handler (GObject *obj, int position, int offset) +{ + gchar *text = atk_text_get_text (ATK_TEXT (obj), position, position + offset); + gchar *output_str = g_strdup_printf("position %d, length %d text: %s", + position, offset, text ? text: ""); + _print_signal(ATK_OBJECT(obj), FERRET_SIGNAL_TEXT, + "Text Delete", output_str); + g_free(output_str); +} + +static void +_notify_caret_handler (GObject *obj, int position) +{ + gchar *output_str = g_strdup_printf("position %d", position); + _print_signal(ATK_OBJECT(obj), FERRET_SIGNAL_TEXT, + "Text Caret Moved", output_str); + g_free(output_str); +} + +/* Table signals */ + +static void +_notify_table_row_inserted (GObject *obj, gint start_offset, + gint length) +{ + gchar *output_str = + g_strdup_printf("position %d, num of rows inserted %d!\n", + start_offset, length); + _print_signal(ATK_OBJECT(obj), FERRET_SIGNAL_TABLE, + "Table Row Inserted", output_str); + g_free(output_str); +} + +static void +_notify_table_column_inserted (GObject *obj, gint start_offset, + gint length) +{ + gchar *output_str = + g_strdup_printf("position %d, num of rows inserted %d!\n", + start_offset, length); + _print_signal(ATK_OBJECT(obj), FERRET_SIGNAL_TABLE, + "Table Column Inserted", output_str); + g_free(output_str); +} + +static void +_notify_table_row_deleted (GObject *obj, gint start_offset, + gint length) +{ + gchar *output_str = g_strdup_printf("position %d, num of rows inserted %d!\n", + start_offset, length); + _print_signal(ATK_OBJECT(obj), FERRET_SIGNAL_TABLE, + "Table Row Deleted", output_str); + g_free(output_str); +} + +static void +_notify_table_column_deleted (GObject *obj, gint start_offset, + gint length) +{ + gchar *output_str = g_strdup_printf("position %d, num of rows inserted %d!\n", + start_offset, length); + _print_signal(ATK_OBJECT(obj), FERRET_SIGNAL_TABLE, + "Table Column Deleted", output_str); + g_free(output_str); +} + +static void +_notify_table_row_reordered (GObject *obj) +{ + _print_signal(ATK_OBJECT(obj), FERRET_SIGNAL_TABLE, + "Table Row Reordered", NULL); +} + +static void +_notify_table_column_reordered (GObject *obj) +{ + _print_signal(ATK_OBJECT(obj), FERRET_SIGNAL_TABLE, + "Table Column Reordered", NULL); +} + +/* Object signals */ + +static void +_notify_object_child_added (GObject *obj, gint index, + AtkObject *child) +{ + gchar *output_str = g_strdup_printf("index %d", index); + _print_signal(ATK_OBJECT(obj), FERRET_SIGNAL_OBJECT, + "Child Added", output_str); + g_free(output_str); +} + +static void +_notify_object_child_removed (GObject *obj, gint index, + AtkObject *child) +{ + gchar *output_str = g_strdup_printf("index %d", index); + _print_signal(ATK_OBJECT(obj), FERRET_SIGNAL_OBJECT, + "Child Removed", output_str); + g_free(output_str); +} + +static void +_notify_object_state_change (GObject *obj, gchar *name, gboolean set) +{ + gchar *output_str = g_strdup_printf("name %s %s set", + name, set ? "is" : "was"); + _print_signal(ATK_OBJECT(obj), FERRET_SIGNAL_OBJECT, + "State Change", output_str); + g_free(output_str); +} + + +/* Function to print signals */ + +static void +_print_signal(AtkObject *aobject, FerretSignalType type, + const char *name, const char *info) +{ + TabNumber top_tab = gtk_notebook_get_current_page (notebook) + OBJECT; + + if (no_signals) + return; + + if (display_ascii) + { + if (info != NULL) + g_print("SIGNAL:\t%-34s\t%s\n", name, info); + else + g_print("SIGNAL:\t%-34s\n", name); + } + + if (use_festival) + { + if ((type == FERRET_SIGNAL_TEXT) && (!strncmp(name, "Text Caret", 10))) + { + _speak_caret_event (aobject); + } + else if (type == FERRET_SIGNAL_TEXT) + { + last_caret_offset = atk_text_get_caret_offset (ATK_TEXT (aobject)); + } + } + + if (use_magnifier && ATK_IS_TEXT (aobject) && + (type == FERRET_SIGNAL_TEXT) && (!strncmp(name, "Text Caret", 10))) + { + gint x, y, w, h; + gint caret_offset = atk_text_get_caret_offset (ATK_TEXT (aobject)); + atk_text_get_character_extents ( ATK_TEXT (aobject), caret_offset, &x, &y, &w, &h, ATK_XY_SCREEN); + _send_to_magnifier (x, y, w, h); + } + + if ((type == FERRET_SIGNAL_TEXT && top_tab == TEXT) || + (type == FERRET_SIGNAL_TABLE && top_tab == TABLE) || + (type == FERRET_SIGNAL_OBJECT && top_tab == OBJECT)) + { + if (display_ascii) + g_print("Updating tab\n"); + + _update(top_tab, aobject); + } +} + +/* Update functions */ + +static void +_update (TabNumber top_tab, AtkObject *aobject) +{ + gint group_num; + + if (top_tab >= OBJECT && top_tab < END_TABS) + { + _clear_tab(top_tab); + } + + if (top_tab == OBJECT && ATK_IS_OBJECT(aobject)) + { + group_num = _print_object(aobject); + _finished_group(OBJECT, group_num); + group_num = _print_relation(aobject); + _finished_group(OBJECT, group_num); + group_num = _print_state(aobject); + _finished_group(OBJECT, group_num); + } + if (top_tab == TEXT && ATK_IS_TEXT(aobject)) + { + group_num = _print_text(ATK_TEXT (aobject)); + _finished_group(TEXT, group_num); + group_num = _print_text_attributes(ATK_TEXT (aobject)); + _finished_group(TEXT, group_num); + } + if (top_tab == SELECTION && ATK_IS_SELECTION(aobject)) + { + group_num = _print_selection(ATK_SELECTION (aobject)); + _finished_group(SELECTION, group_num); + } + if (top_tab == TABLE && ATK_IS_TABLE(aobject)) + { + group_num = _print_table(ATK_TABLE (aobject)); + _finished_group(TABLE, group_num); + } + if (top_tab == ACTION && ATK_IS_ACTION(aobject)) + { + group_num = _print_action(ATK_ACTION (aobject)); + _finished_group(ACTION, group_num); + } + if (top_tab == COMPONENT && ATK_IS_COMPONENT(aobject)) + { + group_num = _print_component(ATK_COMPONENT(aobject)); + _finished_group(COMPONENT, group_num); + } + if (top_tab == IMAGE && ATK_IS_IMAGE(aobject)) + { + group_num = _print_image(ATK_IMAGE (aobject)); + _finished_group(IMAGE, group_num); + } + if (top_tab == VALUE && ATK_IS_VALUE(aobject)) + { + group_num = _print_value(ATK_VALUE(aobject)); + _finished_group(VALUE, group_num); + } +} + +static void +_update_current_page(GtkNotebook *notebook, gpointer p, guint current_page) +{ + _update(current_page+OBJECT, last_object); +} + +/* Property listeners */ + +static void _property_change_handler (AtkObject *obj, + AtkPropertyValues *values) +{ + TabNumber top_tab = gtk_notebook_get_current_page (notebook) + OBJECT; + + if (no_signals) + return; + + /* + * Only process if the property change corrisponds to the current + * object + */ + if (obj != last_object) + { + if (display_ascii) + { + g_print("\nProperty change event <%s> for object not in focus\n", + values->property_name); + } + + return; + } + + if (display_ascii) + { + g_print("\nProperty change event <%s> occurred.\n", + values->property_name); + } + + /* + * Update the top tab if a property changes. + * + * We may be able to ignore some property changes if they do not + * change anything in ferret. + */ + + if (top_tab == OBJECT && + ((strcmp (values->property_name, "accessible-name") == 0) || + (strcmp (values->property_name, "accessible-description") == 0) || + (strcmp (values->property_name, "accessible-parent") == 0) || + (strcmp (values->property_name, "accessible-value") == 0) || + (strcmp (values->property_name, "accessible-role") == 0) || + (strcmp (values->property_name, "accessible-component-layout") == 0) || + (strcmp (values->property_name, "accessible-component-mdi-zorder") == 0) || + (strcmp (values->property_name, "accessible-table-caption") == 0) || + (strcmp (values->property_name, + "accessible-table-column-description") == 0) || + (strcmp (values->property_name, + "accessible-table-column-header") == 0) || + (strcmp (values->property_name, + "accessible-table-row-description") == 0) || + (strcmp (values->property_name, + "accessible-table-row-header") == 0) || + (strcmp (values->property_name, "accessible-table-summary") == 0))) + { + if (display_ascii) + g_print("Updating tab\n"); + + _update(top_tab, last_object); + } + else if (top_tab == VALUE && + (strcmp (values->property_name, "accessible-value") == 0)) + { + if (display_ascii) + g_print("Updating tab\n"); + + _update(top_tab, last_object); + } +} + +/* Action button callback function */ + +void _action_cb(GtkWidget *widget, gpointer *userdata) +{ + NameValue *nv = (NameValue *)userdata; + atk_action_do_action(ATK_ACTION(nv->atkobj), nv->action_num); +} + +/* Menu-bar callback functions */ + +void _toggle_terminal(GtkCheckMenuItem *checkmenuitem, + gpointer user_data) +{ + if (checkmenuitem->active) + display_ascii = TRUE; + else + display_ascii = FALSE; +} + +void _toggle_no_signals(GtkCheckMenuItem *checkmenuitem, + gpointer user_data) +{ + if (checkmenuitem->active) + no_signals = TRUE; + else + no_signals = FALSE; +} + +void _toggle_magnifier(GtkCheckMenuItem *checkmenuitem, + gpointer user_data) +{ + if (checkmenuitem->active) + use_magnifier = TRUE; + else + use_magnifier = FALSE; +} + +void _toggle_festival(GtkCheckMenuItem *checkmenuitem, + gpointer user_data) +{ + if (checkmenuitem->active) + use_festival = TRUE; + else + use_festival = FALSE; +} + +void _toggle_festival_terse(GtkCheckMenuItem *checkmenuitem, + gpointer user_data) +{ + if (checkmenuitem->active) + { + say_role = FALSE; + say_accel = FALSE; + } + else + { + say_role = TRUE; + say_accel = TRUE; + } +} + +void _toggle_trackmouse(GtkCheckMenuItem *checkmenuitem, + gpointer user_data) +{ + if (checkmenuitem->active) + { + mouse_watcher_focus_id = + atk_add_global_event_listener(_mouse_watcher, + "Gtk:GtkWidget:enter_notify_event"); + mouse_watcher_button_id = + atk_add_global_event_listener(_button_watcher, + "Gtk:GtkWidget:button_press_event"); + track_mouse = TRUE; + } + else + { + if (mouse_watcher_focus_id != -1) + { + atk_remove_global_event_listener(mouse_watcher_focus_id); + atk_remove_global_event_listener(mouse_watcher_button_id); + track_mouse = FALSE; + } + } +} + +void _toggle_trackfocus(GtkCheckMenuItem *checkmenuitem, + gpointer user_data) +{ + if (checkmenuitem->active) + { + track_focus = TRUE; + focus_tracker_id = atk_add_focus_tracker (_print_accessible); + } + else + { + g_print ("No longer tracking focus.\n"); + track_focus = FALSE; + atk_remove_focus_tracker (focus_tracker_id); + } +} diff --git a/modules/other/gail/tests/testaction.c b/modules/other/gail/tests/testaction.c new file mode 100644 index 0000000000..9bed7301dc --- /dev/null +++ b/modules/other/gail/tests/testaction.c @@ -0,0 +1,87 @@ +#include +#include +#include +#include "testlib.h" + +/* + * This module is used to test the implementation of AtkAction, + * i.e. the getting of the name and the getting and setting of description + */ + +static void _create_event_watcher (void); +static void _check_object (AtkObject *obj); + +static void +_check_object (AtkObject *obj) +{ + G_CONST_RETURN char *accessible_name; + G_CONST_RETURN gchar * typename = NULL; + + if (GTK_IS_ACCESSIBLE (obj)) + { + GtkWidget* widget = NULL; + + widget = GTK_ACCESSIBLE (obj)->widget; + typename = g_type_name (GTK_OBJECT_TYPE (widget)); + g_print ("Widget type name: %s\n", typename ? typename : "NULL"); + } + typename = g_type_name (G_OBJECT_TYPE (obj)); + g_print ("Accessible type name: %s\n", typename ? typename : "NULL"); + accessible_name = atk_object_get_name (obj); + if (accessible_name) + g_print ("Name: %s\n", accessible_name); + + if (ATK_IS_ACTION (obj)) + { + AtkAction *action = ATK_ACTION (obj); + gint n_actions, i; + G_CONST_RETURN gchar *action_name; + G_CONST_RETURN gchar *action_desc; + G_CONST_RETURN gchar *action_binding; + const gchar *desc = "Test description"; + + n_actions = atk_action_get_n_actions (action); + g_print ("AtkAction supported number of actions: %d\n", n_actions); + for (i = 0; i < n_actions; i++) + { + action_name = atk_action_get_name (action, i); + g_print ("Name of Action %d: %s\n", i, action_name); + action_binding = atk_action_get_keybinding (action, i); + if (action_binding) + g_print ("Name of Action Keybinding %d: %s\n", i, action_binding); + + if (!atk_action_set_description (action, i, desc)) + { + g_print ("atk_action_set_description failed\n"); + } + else + { + action_desc = atk_action_get_description (action, i); + if (strcmp (desc, action_desc) != 0) + { + g_print ("Problem with setting and getting action description\n"); + } + } + } + if (atk_action_set_description (action, n_actions, desc)) + { + g_print ("atk_action_set_description succeeded but should not have\n"); + } + } +} + +static void +_create_event_watcher (void) +{ + atk_add_focus_tracker (_check_object); +} + +int +gtk_module_init(gint argc, char* argv[]) +{ + g_print("testaction Module loaded\n"); + + _create_event_watcher(); + + return 0; +} diff --git a/modules/other/gail/tests/testbutton.c b/modules/other/gail/tests/testbutton.c new file mode 100644 index 0000000000..8f8ae4742e --- /dev/null +++ b/modules/other/gail/tests/testbutton.c @@ -0,0 +1,206 @@ +#include +#include "testlib.h" + +/* + * This module is used to test the accessible implementation for buttons + * + * 1) It verifies that ATK_STATE_ARMED is set when a button is pressed + * To check this click on the button whose name is specified in the + * environment variable TEST_ACCESSIBLE_NAME or "button box" if the + * environment variable is not set. + * + * 2) If the environment variable TEST_ACCESSIBLE_AUTO is set the program + * will execute the action defined for a GailButton once. + * + * 3) Change an inconsistent toggle button to be consistent and vice versa. + * + * Note that currently this code needs to be changed manually to test + * different actions. + */ + +static void _create_event_watcher (void); +static void _check_object (AtkObject *obj); +static void button_pressed_handler (GtkButton *button); +static void _print_states (AtkObject *obj); +static void _print_button_image_info(AtkObject *obj); +static gint _do_button_action (gpointer data); +static gint _toggle_inconsistent (gpointer data); +static gint _finish_button_action (gpointer data); + +#define NUM_VALID_ROLES 4 + +static void +_check_object (AtkObject *obj) +{ + AtkRole role; + static gboolean first_time = TRUE; + + role = atk_object_get_role (obj); + if (role == ATK_ROLE_FRAME) + /* + * Find the specified button in the window + */ + { + AtkRole valid_roles[NUM_VALID_ROLES]; + G_CONST_RETURN char *name; + AtkObject *atk_button; + GtkWidget *widget; + + valid_roles[0] = ATK_ROLE_PUSH_BUTTON; + valid_roles[1] = ATK_ROLE_TOGGLE_BUTTON; + valid_roles[2] = ATK_ROLE_CHECK_BOX; + valid_roles[3] = ATK_ROLE_RADIO_BUTTON; + + name = g_getenv ("TEST_ACCESSIBLE_NAME"); + if (name == NULL) + name = "button box"; + atk_button = find_object_by_accessible_name_and_role (obj, name, + valid_roles, NUM_VALID_ROLES); + + if (atk_button == NULL) + { + g_print ("Object not found for %s\n", name); + return; + } + g_assert (GTK_IS_ACCESSIBLE (atk_button)); + widget = GTK_ACCESSIBLE (atk_button)->widget; + g_assert (GTK_IS_BUTTON (widget)); + g_signal_connect (GTK_OBJECT (widget), + "pressed", + GTK_SIGNAL_FUNC (button_pressed_handler), + NULL); + if (GTK_IS_TOGGLE_BUTTON (widget)) + { + _toggle_inconsistent (GTK_TOGGLE_BUTTON (widget)); + } + if (first_time) + first_time = FALSE; + else + return; + + if (g_getenv ("TEST_ACCESSIBLE_AUTO")) + { + gtk_idle_add (_do_button_action, atk_button); + } + } +} + +static gint _toggle_inconsistent (gpointer data) +{ + GtkToggleButton *toggle_button = GTK_TOGGLE_BUTTON (data); + + if (gtk_toggle_button_get_inconsistent (toggle_button)) + { + gtk_toggle_button_set_inconsistent (toggle_button, FALSE); + } + else + { + gtk_toggle_button_set_inconsistent (toggle_button, TRUE); + } + return FALSE; +} + +static gint _do_button_action (gpointer data) +{ + AtkObject *obj = ATK_OBJECT (data); + + atk_action_do_action (ATK_ACTION (obj), 2); + + gtk_timeout_add (5000, _finish_button_action, obj); + return FALSE; +} + +static gint _finish_button_action (gpointer data) +{ +#if 0 + AtkObject *obj = ATK_OBJECT (data); + + atk_action_do_action (ATK_ACTION (obj), 0); +#endif + + return FALSE; +} + +static void +button_pressed_handler (GtkButton *button) +{ + AtkObject *obj; + + obj = gtk_widget_get_accessible (GTK_WIDGET (button)); + _print_states (obj); + _print_button_image_info (obj); + + if (GTK_IS_TOGGLE_BUTTON (button)) + { + gtk_idle_add (_toggle_inconsistent, GTK_TOGGLE_BUTTON (button)); + } +} + +static void +_print_states (AtkObject *obj) +{ + AtkStateSet *state_set; + gint i; + + state_set = atk_object_ref_state_set (obj); + + g_print ("*** Start states ***\n"); + for (i = 0; i < 64; i++) + { + AtkStateType one_state; + G_CONST_RETURN gchar *name; + + if (atk_state_set_contains_state (state_set, i)) + { + one_state = i; + + name = atk_state_type_get_name (one_state); + + if (name) + g_print("%s\n", name); + } + } + g_object_unref (state_set); + g_print ("*** End states ***\n"); +} + +static void +_print_button_image_info(AtkObject *obj) { + + gint height, width; + G_CONST_RETURN gchar *desc; + + height = width = 0; + + if(!ATK_IS_IMAGE(obj)) + return; + + g_print("*** Start Button Image Info ***\n"); + desc = atk_image_get_image_description(ATK_IMAGE(obj)); + g_print ("atk_image_get_image_desc returns : %s\n", desc ? desc : ""); + atk_image_get_image_size(ATK_IMAGE(obj), &height ,&width); + g_print("atk_image_get_image_size returns: height %d width %d\n",height,width); + if(atk_image_set_image_description(ATK_IMAGE(obj), "New image Description")){ + desc = atk_image_get_image_description(ATK_IMAGE(obj)); + g_print ("atk_image_get_image_desc now returns : %s\n",desc ?desc:""); + } + g_print("*** End Button Image Info ***\n"); + + +} + +static void +_create_event_watcher (void) +{ + atk_add_focus_tracker (_check_object); +} + +int +gtk_module_init(gint argc, char* argv[]) +{ + g_print("testbutton Module loaded\n"); + + _create_event_watcher(); + + return 0; +} diff --git a/modules/other/gail/tests/testcombo.c b/modules/other/gail/tests/testcombo.c new file mode 100644 index 0000000000..60f84a9241 --- /dev/null +++ b/modules/other/gail/tests/testcombo.c @@ -0,0 +1,189 @@ +#include +#include + +static void _test_selection (AtkObject *obj); +static void _check_combo_box (AtkObject *obj); +static void _check_children (AtkObject *obj); +static gint _open_combo_list (gpointer data); +static gint _close_combo_list (gpointer data); + +#define NUM_VALID_ROLES 1 + +static void _check_children (AtkObject *obj) +{ + gint n_children, i, j; + AtkObject *child; + AtkObject *grand_child; + AtkObject *parent; + + n_children = atk_object_get_n_accessible_children (obj); + + if (n_children > 1) + { + g_print ("*** Unexpected number of children for combo box: %d\n", + n_children); + return; + } + if (n_children == 2) + { + child = atk_object_ref_accessible_child (obj, 1); + g_return_if_fail (atk_object_get_role (child) == ATK_ROLE_TEXT); + parent = atk_object_get_parent (child); + j = atk_object_get_index_in_parent (child); + if (j != 1) + g_print ("*** inconsistency between parent and children %d %d ***\n", + 1, j); + g_object_unref (G_OBJECT (child)); + } + + child = atk_object_ref_accessible_child (obj, 0); + g_return_if_fail (atk_object_get_role (child) == ATK_ROLE_LIST); + parent = atk_object_get_parent (child); + j = atk_object_get_index_in_parent (child); + if (j != 0) + g_print ("*** inconsistency between parent and children %d %d ***\n", + 0, j); + + n_children = atk_object_get_n_accessible_children (child); + for (i = 0; i < n_children; i++) + { + G_CONST_RETURN gchar *name; + + grand_child = atk_object_ref_accessible_child (child, i); + name = atk_object_get_name (grand_child); + g_print ("Index: %d Name: %s\n", i, name ? name : ""); + g_object_unref (G_OBJECT (grand_child)); + } + g_object_unref (G_OBJECT (child)); +} + +static void _test_selection (AtkObject *obj) +{ + gint count; + gint n_children; + AtkObject *list; + + count = atk_selection_get_selection_count (ATK_SELECTION (obj)); + g_return_if_fail (count == 0); + + list = atk_object_ref_accessible_child (obj, 0); + n_children = atk_object_get_n_accessible_children (list); + g_object_unref (G_OBJECT (list)); + + atk_selection_add_selection (ATK_SELECTION (obj), n_children - 1); + count = atk_selection_get_selection_count (ATK_SELECTION (obj)); + g_return_if_fail (count == 1); + g_return_if_fail (atk_selection_is_child_selected (ATK_SELECTION (obj), + n_children - 1)); + atk_selection_add_selection (ATK_SELECTION (obj), 0); + count = atk_selection_get_selection_count (ATK_SELECTION (obj)); + g_return_if_fail (count == 1); + g_return_if_fail (atk_selection_is_child_selected (ATK_SELECTION (obj), 0)); + atk_selection_clear_selection (ATK_SELECTION (obj)); + count = atk_selection_get_selection_count (ATK_SELECTION (obj)); + g_return_if_fail (count == 0); +} + +static void _check_combo_box (AtkObject *obj) +{ + static gboolean done = FALSE; + static gboolean done_selection = FALSE; + AtkRole role; + + role = atk_object_get_role (obj); + + if (role == ATK_ROLE_FRAME) + { + AtkRole roles[NUM_VALID_ROLES]; + AtkObject *combo_obj; + + if (done_selection) + return; + + roles[0] = ATK_ROLE_COMBO_BOX; + + combo_obj = find_object_by_role (obj, roles, NUM_VALID_ROLES); + + if (combo_obj) + { + if (!done_selection) + { + done_selection = TRUE; + } + if (g_getenv ("TEST_ACCESSIBLE_COMBO_NOEDIT") != NULL) + { + GtkEntry *entry; + + entry = GTK_ENTRY (GTK_COMBO (GTK_ACCESSIBLE (combo_obj)->widget)->entry); + gtk_entry_set_editable (entry, FALSE); + } + _check_children (combo_obj); + _test_selection (combo_obj); + } + + return; + } + if (role != ATK_ROLE_COMBO_BOX) + return; + + g_print ("*** Start ComboBox ***\n"); + _check_children (obj); + + if (!done) + { + gtk_idle_add (_open_combo_list, obj); + done = TRUE; + } + else + return; + g_print ("*** End ComboBox ***\n"); +} + +static gint _open_combo_list (gpointer data) +{ + AtkObject *obj = ATK_OBJECT (data); + + g_print ("_open_combo_list\n"); + atk_action_do_action (ATK_ACTION (obj), 0); + + gtk_timeout_add (5000, _close_combo_list, obj); + return FALSE; +} + +static gint _close_combo_list (gpointer data) +{ + AtkObject *obj = ATK_OBJECT (data); + + gint count; + gint n_children; + AtkObject *list; + + count = atk_selection_get_selection_count (ATK_SELECTION (obj)); + g_return_val_if_fail (count == 0, FALSE); + + list = atk_object_ref_accessible_child (obj, 0); + n_children = atk_object_get_n_accessible_children (list); + g_object_unref (G_OBJECT (list)); + + atk_selection_add_selection (ATK_SELECTION (obj), n_children - 1); + + atk_action_do_action (ATK_ACTION (obj), 0); + + return FALSE; +} + +static void +_create_event_watcher (void) +{ + atk_add_focus_tracker (_check_combo_box); +} + +int +gtk_module_init(gint argc, char* argv[]) +{ + g_print("testcombo Module loaded\n"); + + _create_event_watcher(); + + return 0; +} diff --git a/modules/other/gail/tests/testcomponent.c b/modules/other/gail/tests/testcomponent.c new file mode 100644 index 0000000000..7600c102bc --- /dev/null +++ b/modules/other/gail/tests/testcomponent.c @@ -0,0 +1,121 @@ +#include + +static void _check_position (AtkObject *obj); + +static void _check_position (AtkObject *obj) +{ + AtkObject *parent, *ret_object; + + gint x, y, width, height; + gint x1, y1, width1, height1; + + x = y = width = height = 0; + x1 = y1 = width1 = height1 = 0; + + if (!ATK_IS_COMPONENT (obj)) + return; + + atk_component_get_extents (ATK_COMPONENT(obj), &x, &y, &width, &height, ATK_XY_SCREEN); + atk_component_get_position (ATK_COMPONENT(obj), &x1, &y1, ATK_XY_SCREEN ); + atk_component_get_size (ATK_COMPONENT(obj), &width1, &height1); + if ((x1 != x) || (y1 != y)) + { + g_print ("atk_component_get_extents and atk_get_position give different" + " values: %d,%d %d,%d\n", x, y, x1, y1); + } + if ((width1 != width) || (height1 != height)) + { + g_print ("atk_component_get_extents and atk_get_size give different" + " values: %d,%d %d,%d\n", width, height, width1, height1); + } + + atk_component_get_position (ATK_COMPONENT(obj), &x1, &y1, ATK_XY_SCREEN); + g_print ("Object Type: %s\n", g_type_name (G_OBJECT_TYPE (obj))); + g_print ("Object at %d, %d on screen\n", x1, y1); + g_print ("Object at %d, %d, size: %d, %d\n", x, y, width, height); + + parent = atk_object_get_parent (obj); + + if (ATK_IS_COMPONENT (parent)) + { + gint px, py, pwidth, pheight; + + atk_component_get_extents (ATK_COMPONENT(parent), + &px, &py, &pwidth, &pheight, ATK_XY_SCREEN); + g_print ("Parent Type: %s\n", g_type_name (G_OBJECT_TYPE (parent))); + g_print ("Parent at %d, %d, size: %d, %d\n", px, py, pwidth, pheight); + ret_object = atk_component_ref_accessible_at_point (ATK_COMPONENT (parent), + x, y, ATK_XY_SCREEN); + + if (!ret_object) + { + g_print ("1:atk_component_ref_accessible_at_point returns NULL\n"); + } + else if (ret_object != obj) + { + g_print ("1:atk_component_ref_accessible_at_point returns wrong value for %d %d\n", + x, y); + atk_component_get_extents (ATK_COMPONENT(ret_object), + &px, &py, &pwidth, &pheight, ATK_XY_SCREEN); + g_print ("ret_object at %d, %d, size: %d, %d\n", px, py, pwidth, pheight); + } + if (ret_object) + g_object_unref (G_OBJECT (ret_object)); + ret_object = atk_component_ref_accessible_at_point (ATK_COMPONENT (parent), + x+width-1, y+height-1, ATK_XY_SCREEN); + if (!ret_object) + { + g_print ("2:atk_component_ref_accessible_at_point returns NULL\n"); + } + else if (ret_object != obj) + { + g_print ("2:atk_component_ref_accessible_at_point returns wrong value for %d %d\n", + x+width-1, y+height-1); + } + if (ret_object) + g_object_unref (G_OBJECT (ret_object)); + ret_object = atk_component_ref_accessible_at_point (ATK_COMPONENT (parent), + x-1, y-1, ATK_XY_SCREEN); + if ((ret_object) && (ret_object == obj)) + { + g_print ("3:atk_component_ref_accessible_at_point returns wrong value for %d %d\n", + x-1, y-1); + } + if (ret_object) + g_object_unref (G_OBJECT (ret_object)); + ret_object = atk_component_ref_accessible_at_point (ATK_COMPONENT (parent), + x+width, y+height, ATK_XY_SCREEN); + if ((ret_object) && (ret_object == obj)) + { + g_print ("4:atk_component_ref_accessible_at_point returns wrong value for %d %d\n", + x+width, y+height); + } + if (ret_object) + g_object_unref (G_OBJECT (ret_object)); + } + if (!atk_component_contains (ATK_COMPONENT(obj), x, y, ATK_XY_SCREEN)) + g_print ("Component does not contain position, %d %d\n", x, y); + if (atk_component_contains (ATK_COMPONENT(obj), x-1, y-1, ATK_XY_SCREEN)) + g_print ("Component does contain position, %d %d\n", x-1, y-1); + if (!atk_component_contains (ATK_COMPONENT(obj), x+width-1, y+height-1, ATK_XY_SCREEN)) + g_print ("Component does not contain position, %d %d\n", + x+width-1, y+height-1); + if (atk_component_contains (ATK_COMPONENT(obj), x+width, y+height, ATK_XY_SCREEN)) + g_print ("Component does contain position, %d %d\n", x+width, y+height); +} + +static void +_create_event_watcher (void) +{ + atk_add_focus_tracker (_check_position); +} + +int +gtk_module_init(gint argc, char* argv[]) +{ + g_print("testcomponent Module loaded\n"); + + _create_event_watcher(); + + return 0; +} diff --git a/modules/other/gail/tests/testimage.c b/modules/other/gail/tests/testimage.c new file mode 100644 index 0000000000..f8da1a8c16 --- /dev/null +++ b/modules/other/gail/tests/testimage.c @@ -0,0 +1,159 @@ +#include +#include "testlib.h" +#include + +/* + * This test modules tests the AtkImage interface. When the module is loaded + * with testgtk , it also creates a dialog that contains GtkArrows and a + * GtkImage. + * + */ + +typedef struct +{ + GtkWidget *dialog; + GtkWidget *arrow1; + GtkWidget *arrow2; + GtkWidget *arrow3; + GtkWidget *arrow4; + GtkWidget *close_button; + GtkImage *image; +}MainDialog; + +static void destroy (GtkWidget *widget, gpointer data) +{ + gtk_widget_destroy(GTK_WIDGET(data)); +} + +static void _check_arrows (AtkObject *obj) +{ + AtkRole role; + MainDialog *md; + static gint visibleDialog = 0; + + + role = atk_object_get_role(obj); + if(role == ATK_ROLE_FRAME) { + + md = (MainDialog *) malloc (sizeof(MainDialog)); + if (visibleDialog == 0) + { + md->arrow1 = gtk_arrow_new(GTK_ARROW_UP,GTK_SHADOW_IN); + md->arrow2 = gtk_arrow_new(GTK_ARROW_DOWN,GTK_SHADOW_IN); + md->arrow3 = gtk_arrow_new(GTK_ARROW_LEFT,GTK_SHADOW_OUT); + md->arrow4 = gtk_arrow_new(GTK_ARROW_RIGHT,GTK_SHADOW_OUT); + md->dialog = gtk_dialog_new(); + gtk_window_set_modal(GTK_WINDOW(md->dialog), TRUE); + gtk_box_pack_start(GTK_BOX (GTK_DIALOG (md->dialog)->vbox), + md->arrow1, TRUE,TRUE, 0); + gtk_box_pack_start(GTK_BOX (GTK_DIALOG (md->dialog)->vbox), + md->arrow2, TRUE,TRUE, 0); + gtk_box_pack_start(GTK_BOX (GTK_DIALOG (md->dialog)->vbox), + md->arrow3, TRUE,TRUE, 0); + gtk_box_pack_start(GTK_BOX (GTK_DIALOG (md->dialog)->vbox), + md->arrow4, TRUE,TRUE, 0); + g_signal_connect(GTK_OBJECT(md->dialog), "destroy", + GTK_SIGNAL_FUNC(destroy), md->dialog); + + md->image = GTK_IMAGE(gtk_image_new_from_file("circles.xbm")); + gtk_box_pack_start(GTK_BOX (GTK_DIALOG (md->dialog)->vbox), + GTK_WIDGET(md->image), TRUE,TRUE, 0); + md->close_button = gtk_button_new_from_stock(GTK_STOCK_CLOSE); + g_signal_connect(GTK_OBJECT(md->close_button), "clicked", + GTK_SIGNAL_FUNC(destroy), md->dialog); + + gtk_box_pack_start(GTK_BOX (GTK_DIALOG (md->dialog)->action_area), + md->close_button, TRUE,TRUE, 0); + + + gtk_widget_show_all(md->dialog); + visibleDialog = 1; + + + } + } +} + + +static void +_print_image_info(AtkObject *obj) { + + gint height, width; + G_CONST_RETURN gchar *desc; + G_CONST_RETURN gchar *name = atk_object_get_name (obj); + G_CONST_RETURN gchar *type_name = g_type_name(G_TYPE_FROM_INSTANCE (obj)); + + height = width = 0; + + + if(!ATK_IS_IMAGE(obj)) + return; + + g_print("atk_object_get_name : %s\n", name ? name : ""); + g_print("atk_object_get_type_name : %s\n",type_name ?type_name :""); + g_print("*** Start Image Info ***\n"); + desc = atk_image_get_image_description(ATK_IMAGE(obj)); + g_print ("atk_image_get_image_desc returns : %s\n",desc ? desc:""); + atk_image_get_image_size(ATK_IMAGE(obj), &height ,&width); + g_print("atk_image_get_image_size returns: height %d width %d\n", + height,width); + if(atk_image_set_image_description(ATK_IMAGE(obj),"New image Description")){ + desc = atk_image_get_image_description(ATK_IMAGE(obj)); + g_print ("atk_image_get_image_desc now returns : %s\n",desc?desc:""); + } + g_print("*** End Image Info ***\n"); + + +} +static void _traverse_children (AtkObject *obj) +{ + gint n_children, i; + + n_children = atk_object_get_n_accessible_children (obj); + for (i = 0; i < n_children; i++) + { + AtkObject *child; + + child = atk_object_ref_accessible_child (obj, i); + _print_image_info(child); + _traverse_children (child); + g_object_unref (G_OBJECT (child)); + } +} + + +static void _check_objects (AtkObject *obj) +{ + AtkRole role; + + g_print ("Start of _check_values\n"); + + _check_arrows(obj); + role = atk_object_get_role (obj); + + if (role == ATK_ROLE_FRAME || role == ATK_ROLE_DIALOG) + { + /* + * Add handlers to all children. + */ + _traverse_children (obj); + } + g_print ("End of _check_values\n"); +} + + +static void +_create_event_watcher (void) +{ + atk_add_focus_tracker (_check_objects); +} + +int +gtk_module_init(gint argc, char* argv[]) +{ + g_print("testimages Module loaded\n"); + + _create_event_watcher(); + + return 0; +} diff --git a/modules/other/gail/tests/testlib.c b/modules/other/gail/tests/testlib.c new file mode 100644 index 0000000000..9b325d9221 --- /dev/null +++ b/modules/other/gail/tests/testlib.c @@ -0,0 +1,954 @@ +#include +#include +#include +#include "testlib.h" + +static gint _get_position_in_array (gint window, + gchar *the_test_name); +static gint _get_position_in_parameters (gint window, + gchar *label, + gint position); +static void _create_output_window (OutputWindow **outwin); +static gboolean _create_select_tests_window (AtkObject *obj, + TLruntest runtest, + OutputWindow **outwin); +static void _toggle_selectedcb (GtkWidget *widget, + gpointer test); +static void _testselectioncb (GtkWidget *widget, + gpointer data); +static void _destroy (GtkWidget *widget, + gpointer data); + +/* General functions */ + +/** + * find_object_by_role: + * @obj: An #AtkObject + * @roles: An array of roles to search for + * @num_roles: The number of entries in @roles + * + * Find the #AtkObject which is a decendant of the specified @obj + * which is of an #AtkRole type specified in the @roles array. + * + * Returns: the #AtkObject that meets the specified criteria or NULL + * if no object is found. + **/ +AtkObject* +find_object_by_role (AtkObject *obj, + AtkRole *roles, + gint num_roles) +{ + /* + * Find the first object which is a descendant of the specified object + * which matches the specified role. + * + * This function returns a reference to the AtkObject which should be + * removed when finished with the object. + */ + gint i, j; + gint n_children; + AtkObject *child; + + if (obj == NULL) + return NULL; + + for (j=0; j < num_roles; j++) + { + if (atk_object_get_role (obj) == roles[j]) + return obj; + } + + n_children = atk_object_get_n_accessible_children (obj); + for (i = 0; i < n_children; i++) + { + AtkObject* found_obj; + + child = atk_object_ref_accessible_child (obj, i); + + if (child == NULL) + continue; + + for (j=0; j < num_roles; j++) + { + if (atk_object_get_role (child) == roles[j]) + return child; + } + + found_obj = find_object_by_role (child, roles, num_roles); + g_object_unref (child); + if (found_obj) + return found_obj; + } + return NULL; +} + +/** + * find_object_by_name_and_role: + * @obj: An #AtkObject + * @name: The GTK widget name + * @roles: An array of roles to search for + * @num_roles: The number of entries in @roles + * + * Find the #AtkObject which is a decendant of the specified @obj + * which is of an #AtkRole type specified in the @roles array which + * also has the GTK widget name specified in @name. + * + * Returns: the #AtkObject that meets the specified criteria or NULL + * if no object is found. + **/ +AtkObject* +find_object_by_name_and_role(AtkObject *obj, + const gchar *name, + AtkRole *roles, + gint num_roles) +{ + AtkObject *child; + GtkWidget* widget; + gint i, j; + gint n_children; + + if (obj == NULL) + return NULL; + + widget = GTK_ACCESSIBLE (obj)->widget; + if (GTK_IS_WIDGET (widget)) + { + if (strcmp (name, gtk_widget_get_name(GTK_WIDGET (widget))) == 0) + { + for (j=0; j < num_roles; j++) + { + if (atk_object_get_role (obj) == roles[j]) + return obj; + } + } + } + + n_children = atk_object_get_n_accessible_children (obj); + for (i = 0; i < n_children; i++) + { + AtkObject* found_obj; + + child = atk_object_ref_accessible_child (obj, i); + + if (child == NULL) + continue; + + widget = GTK_ACCESSIBLE (child)->widget; + if (GTK_IS_WIDGET (widget)) + { + if (strcmp(name, gtk_widget_get_name(GTK_WIDGET (widget))) == 0) + { + for (j=0; j < num_roles; j++) + { + if (atk_object_get_role (child) == roles[j]) + return child; + } + } + } + found_obj = find_object_by_name_and_role (child, name, roles, num_roles); + g_object_unref (child); + if (found_obj) + return found_obj; + } + return NULL; +} + +/** + * find_object_by_accessible_name_and_role: + * @obj: An #AtkObject + * @name: The accessible name + * @roles: An array of roles to search for + * @num_roles: The number of entries in @roles + * + * Find the #AtkObject which is a decendant of the specified @obj + * which has the specified @name and matches one of the + * specified @roles. + * + * Returns: the #AtkObject that meets the specified criteria or NULL + * if no object is found. + */ +AtkObject* +find_object_by_accessible_name_and_role (AtkObject *obj, + const gchar *name, + AtkRole *roles, + gint num_roles) +{ + AtkObject *child; + gint i, j; + gint n_children; + G_CONST_RETURN gchar *accessible_name; + + if (obj == NULL) + return NULL; + + accessible_name = atk_object_get_name (obj); + if (accessible_name && (strcmp(name, accessible_name) == 0)) + { + for (j=0; j < num_roles; j++) + { + if (atk_object_get_role (obj) == roles[j]) + return obj; + } + } + + n_children = atk_object_get_n_accessible_children (obj); + for (i = 0; i < n_children; i++) + { + AtkObject* found_obj; + + child = atk_object_ref_accessible_child (obj, i); + + if (child == NULL) + continue; + + accessible_name = atk_object_get_name (child); + if (accessible_name && (strcmp(name, accessible_name) == 0)) + { + for (j=0; j < num_roles; j++) + { + if (atk_object_get_role (child) == roles[j]) + return child; + } + } + found_obj = find_object_by_accessible_name_and_role (child, name, + roles, num_roles); + g_object_unref (child); + if (found_obj) + return found_obj; + } + return NULL; +} + +/** + * find_object_by_name_and_role: + * @obj: An #AtkObject + * @type: The type + * + * Find the #AtkObject which is a decendant of the specified @obj + * which has the specified @type. + * + * Returns: the #AtkObject that meets the specified criteria or NULL + * if no object is found. + */ +AtkObject* +find_object_by_type (AtkObject *obj, + gchar *type) +{ + /* + * Find the first object which is a descendant of the specified object + * which matches the specified type. + * + * This function returns a reference to the AtkObject which should be + * removed when finished with the object. + */ + gint i; + gint n_children; + AtkObject *child; + G_CONST_RETURN gchar * typename = NULL; + + if (obj == NULL) + return NULL; + + typename = g_type_name (G_OBJECT_TYPE (obj)); + if (strcmp (typename, type) == 0) + return obj; + + n_children = atk_object_get_n_accessible_children (obj); + for (i = 0; i < n_children; i++) + { + AtkObject* found_obj; + + child = atk_object_ref_accessible_child (obj, i); + + if (child == NULL) + continue; + + typename = g_type_name (G_OBJECT_TYPE (child)); + + if (strcmp (typename, type) == 0) + return child; + + found_obj = find_object_by_type (child, type); + g_object_unref (child); + if (found_obj) + return found_obj; + } + return NULL; +} + +/** + * already_accessed_atk_object + * @obj: An #AtkObject + * + * Keeps a static GPtrArray of objects that have been passed into this + * function. + * + * Returns: TRUE if @obj has been passed into this function before + * and FALSE otherwise. + */ +gboolean +already_accessed_atk_object (AtkObject *obj) +{ + static GPtrArray *obj_array = NULL; + gboolean found = FALSE; + gint i; + + /* + * We create a property handler for each object if one was not associated + * with it already. + * + * We add it to our array of objects which have property handlers; if an + * object is destroyed it remains in the array. + */ + if (obj_array == NULL) + obj_array = g_ptr_array_new (); + + for (i = 0; i < obj_array->len; i++) + { + if (obj == g_ptr_array_index (obj_array, i)) + { + found = TRUE; + break; + } + } + if (!found) + g_ptr_array_add (obj_array, obj); + + return found; +} + +/** + * display_children + * @obj: An #AtkObject + * @depth: Number of spaces to indent output. + * @child_number: The child number of this object. + * + * Displays the hierarchy of widgets starting from @obj. + **/ +void +display_children (AtkObject *obj, + gint depth, + gint child_number) +{ + display_children_to_depth(obj, -1, depth, child_number); +} + +/** + * display_children_to_depth + * @obj: An #AtkObject + * @to_depth: Display to this depth. + * @depth: Number of spaces to indent output. + * @child_number: The child number of this object. + * + * Displays the hierarchy of widgets starting from @obj only + * to the specified depth. + **/ +void +display_children_to_depth (AtkObject *obj, + gint to_depth, + gint depth, + gint child_number) +{ + AtkRole role; + const gchar *rolename; + const gchar *typename; + gint n_children, parent_index, i; + + if (to_depth >= 0 && depth > to_depth) + return; + + if (obj == NULL) + return; + + for (i=0; i < depth; i++) + g_print(" "); + + role = atk_object_get_role (obj); + rolename = atk_role_get_name (role); + + /* + * Note that child_number and parent_index should be the same + * unless there is an error. + */ + parent_index = atk_object_get_index_in_parent(obj); + g_print("child <%d == %d> ", child_number, parent_index); + + n_children = atk_object_get_n_accessible_children (obj); + g_print ("children <%d> ", n_children); + + if (rolename) + g_print("role <%s>, ", rolename); + else + g_print("role "); + + if (GTK_IS_ACCESSIBLE(obj)) + { + GtkWidget *widget; + + widget = GTK_ACCESSIBLE (obj)->widget; + g_print("name <%s>, ", gtk_widget_get_name(GTK_WIDGET (widget))); + } + else + g_print("name , "); + + typename = g_type_name (G_OBJECT_TYPE (obj)); + g_print ("typename <%s>\n", typename); + + for (i = 0; i < n_children; i++) + { + AtkObject *child; + + child = atk_object_ref_accessible_child (obj, i); + if (child != NULL) + { + display_children_to_depth (child, to_depth, depth + 1, i); + g_object_unref (G_OBJECT (child)); + } + } +} + +/* Test GUI logic */ + +/* GUI Information for the Select Tests Window */ +typedef struct +{ + GtkWidget *selecttestsWindow; + GtkWidget *hbox; + GtkWidget *vbox; + GtkWidget *label; + GtkWidget *textInsert; + GtkWidget *button; + gchar *selecttestsTitle; +}MainDialog; + +/* Functionality information about each added test */ +typedef struct +{ + GtkWidget *toggleButton; + GtkWidget *hbox; + GtkWidget *parameterLabel[MAX_PARAMS]; + GtkWidget *parameterInput[MAX_PARAMS]; + gchar *testName; + gint numParameters; +}TestList; + +typedef struct +{ + TLruntest runtest; + AtkObject* obj; + gint win_num; +}TestCB; + +static MainDialog *md[MAX_WINDOWS]; +static OutputWindow *ow; + +/* An array containing function information on all of the tests */ +static TestList listoftests[MAX_WINDOWS][MAX_TESTS]; + +/* A counter for the actual number of added tests */ +gint counter; + +/* A global for keeping track of the window numbers */ +static gint window_no = 0; +/* An array containing the names of the tests that are "on" */ +static gchar *onTests[MAX_WINDOWS][MAX_TESTS]; +static gint g_visibleDialog = 0; +static gint testcount[MAX_WINDOWS]; +static TestCB testcb[MAX_WINDOWS]; + +/** + * create_windows: + * @obj: An #AtkObject + * @runtest: The callback function to run when the "Run Tests" button + * is clicked. + * @outwin: The output window to use. If NULL is passed in, then + * create a new one. + * + * Creates the test window and the output window (if @outwin is NULL) + * Runs _create_output_window() and _create_select_tests_window() + * and sets g_visibleDialog to 1 + * + * Returns: The window number of the created window if successful, -1 otherwise. + **/ +gint +create_windows (AtkObject *obj, + TLruntest runtest, + OutputWindow **outwin) +{ + gboolean valid; + gint tmp; + + g_visibleDialog = 1; + _create_output_window(outwin); + valid = _create_select_tests_window(obj, runtest, outwin); + if (valid) + { + tmp = window_no; + window_no++; + return tmp; + } + else + return -1; +} + +/** + * _create_output_window + * @outwin: If outwin is passed in as NULL, a new output window is created + * otherwise, the outwin passed in is shared. + * + * Creates the Test Result Output Window . + **/ +static void +_create_output_window (OutputWindow **outwin) +{ + GtkWidget *view; + GtkWidget *scrolled_window; + OutputWindow *localow; + + if (*outwin == NULL) + { + localow = (OutputWindow *) malloc (sizeof(OutputWindow)); + + localow->outputBuffer = gtk_text_buffer_new(NULL); + view = gtk_text_view_new_with_buffer(GTK_TEXT_BUFFER(localow->outputBuffer)); + gtk_widget_set_usize(view, 700, 500); + gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(view), GTK_WRAP_WORD); + gtk_text_view_set_editable(GTK_TEXT_VIEW(view), FALSE); + + localow->outputWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_title(GTK_WINDOW(localow->outputWindow), "Test Output"); + scrolled_window = gtk_scrolled_window_new(NULL, NULL); + + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), + GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + gtk_container_add(GTK_CONTAINER(localow->outputWindow), scrolled_window); + gtk_container_add(GTK_CONTAINER(scrolled_window), view); + gtk_text_buffer_get_iter_at_offset(localow->outputBuffer, &localow->outputIter, 0); + gtk_widget_show(view); + gtk_widget_show(scrolled_window); + gtk_widget_show(localow->outputWindow); + + gtk_text_buffer_set_text(GTK_TEXT_BUFFER(localow->outputBuffer), + "\n\nWelcome to the test GUI:\nTest results are printed here\n\n", 58); + gtk_text_buffer_get_iter_at_offset(GTK_TEXT_BUFFER(localow->outputBuffer), + &localow->outputIter, 0); + *outwin = localow; + ow = *outwin; + } +} + +/** + * _create_select_tests_window: + * @obj: An #AtkObject + * @runtest: The callback function that is run when the "Run Tests" + * button is clicked. + * @outwin: The output window to use. + * + * Creates the Test Select Window + * + * Returns: TRUE if successful, FALSE otherwise + **/ +static gboolean +_create_select_tests_window (AtkObject *obj, + TLruntest runtest, + OutputWindow **outwin) +{ + AtkText *textwidget; + GtkWidget *hbuttonbox; + GtkWidget *scrolledWindow; + + if (window_no >= 0 && window_no < MAX_WINDOWS) + { + md[window_no] = (MainDialog *) malloc (sizeof(MainDialog)); + + textwidget = ATK_TEXT (obj); + + /* Setup Window */ + md[window_no]->selecttestsTitle = "Test Setting"; + md[window_no]->selecttestsWindow = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW( ow->outputWindow), + md[window_no]->selecttestsTitle); + gtk_window_set_resizable (GTK_WINDOW(md[window_no]->selecttestsWindow), + FALSE); + gtk_window_set_position (GTK_WINDOW(md[window_no]->selecttestsWindow), + GTK_WIN_POS_CENTER); + g_signal_connect (GTK_OBJECT(md[window_no]->selecttestsWindow), + "destroy", + GTK_SIGNAL_FUNC(_destroy), + &md[window_no]->selecttestsWindow); + + /* Setup Scrolling */ + scrolledWindow = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledWindow), + GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + gtk_widget_set_usize (scrolledWindow, 500, 600); + gtk_container_add (GTK_CONTAINER (md[window_no]->selecttestsWindow), + scrolledWindow); + + /* Setup Layout */ + md[window_no]->vbox = gtk_vbox_new (TRUE, 0); + md[window_no]->button = gtk_button_new_with_mnemonic ("_Run Tests"); + hbuttonbox = gtk_hbutton_box_new (); + gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox), + GTK_BUTTONBOX_SPREAD); + gtk_box_pack_end_defaults (GTK_BOX (hbuttonbox), + GTK_WIDGET (md[window_no]->button)); + gtk_box_pack_end_defaults (GTK_BOX (md[window_no]->vbox), hbuttonbox); + gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolledWindow), + md[window_no]->vbox); + + testcb[window_no].runtest = runtest; + testcb[window_no].obj = obj; + testcb[window_no].win_num = window_no; + g_signal_connect (GTK_OBJECT (md[window_no]->button), + "clicked", + GTK_SIGNAL_FUNC (_testselectioncb), + (gpointer)&testcb[window_no]); + + /* Show all */ + gtk_widget_grab_focus (md[window_no]->button); + gtk_widget_show (md[window_no]->button); + gtk_widget_show (hbuttonbox); + gtk_widget_show (scrolledWindow); + gtk_widget_show_all (GTK_WIDGET (md[window_no]->selecttestsWindow)); + return TRUE; + } + else + return FALSE; +} + +/** + * add_test + * @window: The window number + * @name: The test name + * @num_params: The number of arguments the test uses. + * @parameter_names: The names of each argument. + * @default_names: The default values of each argument. + * + * Adds a Test with the passed-in details to the Tests Select Window. + * + * Returns: FALSE if the num_params passed in is greater than + * MAX_PARAMS, otherwise returns TRUE + * + **/ +gboolean +add_test (gint window, + gchar *name, + gint num_params, + gchar* parameter_names[], + gchar* default_names[]) +{ + gint i; + + if (num_params > MAX_PARAMS) + return FALSE; + else + { + md[window]->hbox = gtk_hbox_new (FALSE, 0); + gtk_box_set_spacing (GTK_BOX (md[window]->hbox), 10); + gtk_container_set_border_width (GTK_CONTAINER (md[window]->hbox), 10); + gtk_container_add (GTK_CONTAINER (md[window]->vbox), md[window]->hbox); + listoftests[window][testcount[window]].toggleButton = + gtk_toggle_button_new_with_label (name); + gtk_box_pack_start (GTK_BOX (md[window]->hbox), + listoftests[window][testcount[window]].toggleButton, FALSE, FALSE, 0); + listoftests[window][testcount[window]].testName = name; + listoftests[window][testcount[window]].numParameters = num_params; + for (i=0; ihbox), + listoftests[window][testcount[window]].parameterLabel[i], FALSE, FALSE, 0); + listoftests[window][testcount[window]].parameterInput[i] = gtk_entry_new(); + gtk_entry_set_text (GTK_ENTRY (listoftests[window][testcount[window]].parameterInput[i]), + default_names[i]); + gtk_widget_set_usize (listoftests[window][testcount[window]].parameterInput[i], 50, 22); + gtk_box_pack_start (GTK_BOX (md[window]->hbox), + listoftests[window][testcount[window]].parameterInput[i], FALSE, FALSE, 0); + gtk_widget_set_sensitive ( + GTK_WIDGET (listoftests[window][testcount[window]].parameterLabel[i]), FALSE); + gtk_widget_set_sensitive ( + GTK_WIDGET (listoftests[window][testcount[window]].parameterInput[i]), FALSE); + gtk_widget_show (listoftests[window][testcount[window]].parameterLabel[i]); + gtk_widget_show (listoftests[window][testcount[window]].parameterInput[i]); + } + g_signal_connect (GTK_OBJECT (listoftests[window][testcount[window]].toggleButton), + "toggled", + GTK_SIGNAL_FUNC(_toggle_selectedcb), + (gpointer)&(listoftests[window][testcount[window]])); + gtk_widget_show (listoftests[window][testcount[window]].toggleButton); + gtk_widget_show (md[window]->hbox); + gtk_widget_show (md[window]->vbox); + + testcount[window]++; + counter++; + return TRUE; + } +} + +/** + * tests_set: + * @window: The window number + * @count: Passes back the number of tests on. + * + * Gets an array of strings corresponding to the tests that are "on". + * A test is assumed on if the toggle button is on and if all its + * parameters have values. + * + * Returns: an array of strings corresponding to the tests that + * are "on". + **/ +gchar **tests_set(gint window, int *count) +{ + gint i =0, j = 0, num; + gboolean nullparam; + gchar* input; + + *count = 0; + for (i = 0; i < MAX_TESTS; i++) + onTests[window][i] = NULL; + + for (i = 0; i < testcount[window]; i++) + { + nullparam = FALSE; + if (GTK_TOGGLE_BUTTON(listoftests[window][i].toggleButton)->active) + { + num = listoftests[window][i].numParameters; + for (j = 0; j < num; j++) + { + input = gtk_editable_get_chars ( + GTK_EDITABLE (listoftests[window][i].parameterInput[j]), 0, -1); + + if (input != NULL && (! strcmp(input, ""))) + nullparam = TRUE; + } + if (!nullparam) + { + onTests[window][*count] = listoftests[window][i].testName; + *count = *count + 1; + } + } + } + return onTests[window]; +} + +/** + * _get_position_in_array: + * @window: The window number + * @the_test_name: The name of the test + * + * Gets the index of the passed-in @the_test_name. + * + * Returns: the position in listoftests[] of @the_test_name + **/ +static gint +_get_position_in_array(gint window, + gchar *the_test_name) +{ + gint i; + + for (i = 0; i < testcount[window]; i++) + { + if (strcmp(listoftests[window][i].testName, the_test_name) == 0) + return i; + } + return -1; +} + +/** + * _get_position_in_parameters: + * @window: The window number + * @label: The label name + * @position: The parameter position + * + * Gets the index of the passed-in parameter @label. + * + * Returns: the position in parameterLabel[] (a member of + * listoftests[]) of @label + **/ +static gint +_get_position_in_parameters(gint window, + gchar *label, + gint position) +{ + gint i; + G_CONST_RETURN gchar *label_string; + + for (i = 0; i < MAX_PARAMS; i++) + { + label_string = gtk_label_get_text( + GTK_LABEL (listoftests[window][position].parameterLabel[i])); + + if (strcmp(label_string, label) == 0) + return i; + } + return -1; +} + +/** + * set_output_buffer: + * @output: The string to add to the output buffer + * + * Tidies up the output Window + **/ +void +set_output_buffer(gchar *output) +{ + gtk_text_buffer_insert (GTK_TEXT_BUFFER (ow->outputBuffer), + &ow->outputIter, output, strlen(output)); + gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (ow->outputBuffer), + &ow->outputIter, 0); +} + +/** + * isVisibleDialog: + * + * Informs user if a visible test window running. + * + * Returns: TRUE if g_visibleDialog is set to 1, otherwise FALSE + **/ +gboolean +isVisibleDialog(void) +{ + if (g_visibleDialog >= 1) + return TRUE; + else + return FALSE; +} + +/** + * get_arg_of_func: + * @window: The window number + * @function_name: The name of the function + * @arg_label: The label of the argument. + * + * Gets the user input associated with the @function_name and @arg_label. + * + * Returns: the user input associated with the @function_name and @arg_label. + **/ +gchar* +get_arg_of_func (gint window, + gchar *function_name, + gchar *arg_label) +{ + G_CONST_RETURN gchar *argString; + gchar *retString; + gint position, paramPosition; + + position = _get_position_in_array(window, function_name); + + if (position == -1) + { + g_print("No such function\n"); + return NULL; + } + + paramPosition = _get_position_in_parameters(window, arg_label, position); + + if (paramPosition == -1) + { + g_print("No such parameter Label\n"); + return NULL; + } + + if (position != -1 && paramPosition != -1) + { + argString = gtk_editable_get_chars ( + GTK_EDITABLE (listoftests[window][position].parameterInput[paramPosition]), + 0, -1); + retString = g_strdup(argString); + } + else + retString = NULL; + + return retString; +} + +/** + * string_to_int: + * @the_string: The string to convert + * + * Converts the passed-in string to an integer + * + * Returns: An integer corresponding to @the_string. + **/ +int +string_to_int (const char *the_string) +{ + char *end_ptr; + double ret_val; + int int_ret_val; + + while (1) + { + ret_val = strtod( the_string, &end_ptr); + if (*end_ptr == '\0') + break; + else + printf("\nError: input must be a number\n"); + } + + int_ret_val = (int) ret_val; + return (int_ret_val); +} + +/** + * _toggle_selectedcb: + * @widget: The ToggleButton widget + * @test: user data containing the TestList structure. + * + * Toggle Button Callback, activating the text entry fields + **/ +static void +_toggle_selectedcb (GtkWidget *widget, + gpointer test) +{ + int i; + TestList *testlist = (TestList *) test; + gboolean toggled; + gboolean sensitive; + toggled = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)); + if (toggled) + sensitive = TRUE; + else + sensitive = FALSE; + + for (i=0; i < testlist->numParameters; i++) + { + gtk_widget_set_sensitive (GTK_WIDGET (testlist->parameterLabel[i]), + sensitive); + gtk_widget_set_sensitive (GTK_WIDGET (testlist->parameterInput[i]), + sensitive); + } +} + +/* + * _testselectioncb: + * widget: The Button widget + * data: The user data containing a TestCB structure + * + * Callback for when the "Run Tests" button is pressed + **/ +static void +_testselectioncb (GtkWidget *widget, + gpointer data) +{ + TestCB* local_testcb = (TestCB *)data; + local_testcb->runtest(local_testcb->obj, local_testcb->win_num); +} + +/** + * _destroy: + * @widget: The GUI widget + * @data: User data, not used. + * + * Destroy Callback. + **/ +static void +_destroy (GtkWidget *widget, + gpointer data) +{ + gtk_main_quit(); +} + diff --git a/modules/other/gail/tests/testlib.h b/modules/other/gail/tests/testlib.h new file mode 100644 index 0000000000..7118bbf593 --- /dev/null +++ b/modules/other/gail/tests/testlib.h @@ -0,0 +1,70 @@ +#include +#include + +/* Maximum characters in the output buffer */ +#define MAX_LINE_SIZE 1000 + +/* Maximum number of tests */ +#define MAX_TESTS 30 + +/* Maximum number of test windows */ +#define MAX_WINDOWS 5 + +/* Maximum number of parameters any test can have */ +#define MAX_PARAMS 3 + +/* Information on the Output Window */ + +typedef struct +{ + GtkWidget *outputWindow; + GtkTextBuffer *outputBuffer; + GtkTextIter outputIter; +}OutputWindow; + +typedef void (*TLruntest) (AtkObject * obj, gint win_num); + +/* General purpose functions */ + +gboolean already_accessed_atk_object (AtkObject *obj); +AtkObject* find_object_by_role (AtkObject *obj, + AtkRole *role, + gint num_roles); +AtkObject* find_object_by_type (AtkObject *obj, + gchar *type); +AtkObject* find_object_by_name_and_role (AtkObject *obj, + const gchar *name, + AtkRole *roles, + gint num_roles); +AtkObject* find_object_by_accessible_name_and_role (AtkObject *obj, + const gchar *name, + AtkRole *roles, + gint num_roles); +void display_children (AtkObject *obj, + gint depth, + gint child_number); +void display_children_to_depth (AtkObject *obj, + gint to_depth, + gint depth, + gint child_number); + + +/* Test GUI functions */ + +gint create_windows (AtkObject *obj, + TLruntest runtest, + OutputWindow **outwin); +gboolean add_test (gint window, + gchar *name, + gint num_params, + gchar *parameter_names[], + gchar *default_names[]); +void set_output_buffer (gchar *output); +gchar **tests_set (gint window, + int *count); +gchar *get_arg_of_func (gint window, + gchar *function_name, + gchar *arg_label); +int string_to_int (const char *the_string); +gboolean isVisibleDialog (void); + diff --git a/modules/other/gail/tests/testmenuitem.c b/modules/other/gail/tests/testmenuitem.c new file mode 100644 index 0000000000..129bde578c --- /dev/null +++ b/modules/other/gail/tests/testmenuitem.c @@ -0,0 +1,138 @@ +#include +#include +#include "testlib.h" + +/* + * This module is used to test the accessible implementation for menu items + * + * 1) When a menu item is clicked in testgtk, the action for the + * item is performed. + * 2) The name of the keybinding for the 'activate" action for a menu item + * is output, if it exists. + * 3) Execute the action for a menu item programatically + */ +#define NUM_VALID_ROLES 1 + +static void _create_event_watcher (void); +static void _check_object (AtkObject *obj); +static gint _do_menu_item_action (gpointer data); + +static void +_check_object (AtkObject *obj) +{ + AtkRole role; + static G_CONST_RETURN char *name = NULL; + static gboolean first_time = TRUE; + + role = atk_object_get_role (obj); + if (role == ATK_ROLE_FRAME) + /* + * Find the specified menu item + */ + { + AtkRole valid_roles[NUM_VALID_ROLES]; + AtkObject *atk_menu_item; + GtkWidget *widget; + + if (name == NULL) + { + valid_roles[0] = ATK_ROLE_MENU_ITEM; + + name = g_getenv ("TEST_ACCESSIBLE_NAME"); + if (name == NULL) + name = "foo"; + } + atk_menu_item = find_object_by_accessible_name_and_role (obj, name, + valid_roles, NUM_VALID_ROLES); + + if (atk_menu_item == NULL) + { + g_print ("Object not found for %s\n", name); + return; + } + + g_assert (GTK_IS_ACCESSIBLE (atk_menu_item)); + widget = GTK_ACCESSIBLE (atk_menu_item)->widget; + g_assert (GTK_IS_MENU_ITEM (widget)); + + if (first_time) + first_time = FALSE; + else + return; + + /* + * This action opens the menu whose name is "foo" or whatever + * was specified in the environment variable TEST_ACCESSIBLE_NAME + */ + atk_action_do_action (ATK_ACTION (atk_menu_item), 0); + } + else if ((role == ATK_ROLE_MENU_ITEM) || + (role == ATK_ROLE_CHECK_MENU_ITEM) || + (role == ATK_ROLE_RADIO_MENU_ITEM) || + (role == ATK_ROLE_TEAR_OFF_MENU_ITEM)) + { + G_CONST_RETURN char *keybinding; + G_CONST_RETURN char *accessible_name; + + accessible_name = atk_object_get_name (obj); + if (accessible_name) + g_print ("Name: %s\n", accessible_name); + g_print ("Action: %s\n", atk_action_get_name (ATK_ACTION (obj), 0)); + keybinding = atk_action_get_keybinding (ATK_ACTION (obj), 0); + if (keybinding) + g_print ("KeyBinding: %s\n", keybinding); + /* + * Do the action associated with the menu item once, otherwise + * we get into a loop + */ + if (strcmp (name, accessible_name) == 0) + { + if (first_time) + first_time = FALSE; + else + return; + if (g_getenv ("TEST_ACCESSIBLE_AUTO")) + { + gtk_idle_add (_do_menu_item_action, obj); + } + } + } + else + { + G_CONST_RETURN char *accessible_name; + + accessible_name = atk_object_get_name (obj); + if (accessible_name) + g_print ("Name: %s\n", accessible_name); + else if (GTK_IS_ACCESSIBLE (obj)) + { + GtkWidget *widget = GTK_ACCESSIBLE (obj)->widget; + g_print ("Type: %s\n", g_type_name (G_OBJECT_TYPE (widget))); + } + } +} + +static gint _do_menu_item_action (gpointer data) +{ + AtkObject *obj = ATK_OBJECT (data); + + atk_action_do_action (ATK_ACTION (obj), 0); + + return FALSE; +} + +static void +_create_event_watcher (void) +{ + atk_add_focus_tracker (_check_object); +} + +int +gtk_module_init(gint argc, char* argv[]) +{ + g_print("testmenuitem Module loaded\n"); + + _create_event_watcher(); + + return 0; +} diff --git a/modules/other/gail/tests/testnotebook.c b/modules/other/gail/tests/testnotebook.c new file mode 100644 index 0000000000..77d015b221 --- /dev/null +++ b/modules/other/gail/tests/testnotebook.c @@ -0,0 +1,226 @@ +#include + +#include +#include +#include +#include +#include "testlib.h" + +#define NUM_VALID_ROLES 1 + +static void _print_type (AtkObject *obj); +static void _do_selection (AtkObject *obj); +static gint _finish_selection (gpointer data); +static gint _remove_page (gpointer data); + +static void _print_type (AtkObject *obj) +{ + G_CONST_RETURN gchar *typename = NULL; + G_CONST_RETURN gchar *name = NULL; + G_CONST_RETURN gchar *description = NULL; + AtkRole role; + + if (GTK_IS_ACCESSIBLE (obj)) + { + GtkWidget* widget = NULL; + + widget = GTK_ACCESSIBLE (obj)->widget; + typename = g_type_name (GTK_OBJECT_TYPE (widget)); + g_print ("\tWidget type name: %s\n", typename ? typename : "NULL"); + } + + typename = g_type_name (G_OBJECT_TYPE (obj)); + g_print ("\tAccessible type name: %s\n", typename ? typename : "NULL"); + + name = atk_object_get_name (obj); + g_print("\tAccessible Name: %s\n", (name) ? name : "NULL"); + + role = atk_object_get_role(obj); + g_print ("\tAccessible Role: %d\n", role); + + description = atk_object_get_description (obj); + g_print ("\tAccessible Description: %s\n", (description) ? description : "NULL"); + if (role == ATK_ROLE_PAGE_TAB) + { + AtkObject *parent, *child; + gint x, y, width, height; + + x = y = width = height = 0; + atk_component_get_extents (ATK_COMPONENT (obj), &x, &y, &width, &height, + ATK_XY_SCREEN); + g_print ("obj: x: %d y: %d width: %d height: %d\n", x, y, width, height); + x = y = width = height = 0; + atk_component_get_extents (ATK_COMPONENT (obj), &x, &y, &width, &height, + ATK_XY_WINDOW); + g_print ("obj: x: %d y: %d width: %d height: %d\n", x, y, width, height); + parent = atk_object_get_parent (obj); + x = y = width = height = 0; + atk_component_get_extents (ATK_COMPONENT (parent), &x, &y, &width, &height, + ATK_XY_SCREEN); + g_print ("parent: x: %d y: %d width: %d height: %d\n", x, y, width, height); + x = y = width = height = 0; + atk_component_get_extents (ATK_COMPONENT (parent), &x, &y, &width, &height, + ATK_XY_WINDOW); + g_print ("parent: x: %d y: %d width: %d height: %d\n", x, y, width, height); + + child = atk_object_ref_accessible_child (obj, 0); + x = y = width = height = 0; + atk_component_get_extents (ATK_COMPONENT (child), &x, &y, &width, &height, + ATK_XY_SCREEN); + g_print ("child: x: %d y: %d width: %d height: %d\n", x, y, width, height); + x = y = width = height = 0; + atk_component_get_extents (ATK_COMPONENT (child), &x, &y, &width, &height, + ATK_XY_WINDOW); + g_print ("child: x: %d y: %d width: %d height: %d\n", x, y, width, height); + + g_object_unref (child); + } +} + + +static void +_do_selection (AtkObject *obj) +{ + gint i; + gint n_children; + AtkRole role; + AtkObject *selection_obj; + static gboolean done_selection = FALSE; + + if (done_selection) + return; + + role = atk_object_get_role (obj); + + if (role == ATK_ROLE_FRAME) + { + AtkRole roles[NUM_VALID_ROLES]; + + roles[0] = ATK_ROLE_PAGE_TAB_LIST; + + selection_obj = find_object_by_role (obj, roles, NUM_VALID_ROLES); + + if (selection_obj) + { + done_selection = TRUE; + } + else + return; + } + else + { + return; + } + + g_print ("*** Start do_selection ***\n"); + + n_children = atk_object_get_n_accessible_children (selection_obj); + g_print ("*** Number of notebook pages: %d\n", n_children); + + for (i = 0; i < n_children; i++) + { + if (atk_selection_is_child_selected (ATK_SELECTION (selection_obj), i)) + { + g_print ("%d page selected\n", i); + } + else + { + g_print ("%d page not selected\n", i); + } + } + /* + * Should not be able to select all items in a notebook. + */ + atk_selection_select_all_selection (ATK_SELECTION (selection_obj)); + i = atk_selection_get_selection_count (ATK_SELECTION (selection_obj)); + if ( i != 1) + { + g_print ("Unexpected selection count: %d, expected 1\n", i); + g_print ("\t value of i is: %d\n", i); + return; + } + + for (i = 0; i < n_children; i++) + { + atk_selection_add_selection (ATK_SELECTION (selection_obj), i); + + if (atk_selection_is_child_selected (ATK_SELECTION (selection_obj), i)) + { + g_print ("Page %d: successfully selected\n", i); + _finish_selection (selection_obj); + } + else + { + g_print ("ERROR: child %d: selection failed\n", i); + } + } + g_print ("*** End _do_selection ***\n"); + gtk_timeout_add (5000, _remove_page, selection_obj); +} + +static gint _remove_page (gpointer data) +{ + AtkObject *obj = ATK_OBJECT (data); + GtkWidget *widget = NULL; + + if (GTK_IS_ACCESSIBLE (obj)) + widget = GTK_ACCESSIBLE (obj)->widget; + + g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE); + gtk_notebook_remove_page (GTK_NOTEBOOK (widget), 4); + return FALSE; +} + +static gint _finish_selection (gpointer data) +{ + AtkObject *obj = ATK_OBJECT (data); + AtkObject *selected; + AtkObject *parent_object; + GtkWidget *parent_widget; + gint i, index; + + g_print ("\t*** Start Finish selection ***\n"); + + i = atk_selection_get_selection_count (ATK_SELECTION (obj)); + if (i != 1) + { + g_print ("\tUnexpected selection count: %d, expected 1\n", i); + return FALSE; + } + selected = atk_selection_ref_selection (ATK_SELECTION (obj), 0); + g_return_val_if_fail (selected != NULL, FALSE); + + g_print ("\t*** Selected Item ***\n"); + index = atk_object_get_index_in_parent (selected); + g_print ("\tIndex in parent is: %d\n", index); + + parent_object = atk_object_get_parent (selected); + g_return_val_if_fail (ATK_IS_OBJECT (parent_object), FALSE); + g_return_val_if_fail (parent_object == obj, FALSE); + parent_widget = GTK_ACCESSIBLE (parent_object)->widget; + g_return_val_if_fail (GTK_IS_NOTEBOOK (parent_widget), FALSE); + + _print_type (selected); + i = atk_selection_get_selection_count (ATK_SELECTION (obj)); + g_return_val_if_fail (i == 1, FALSE); + g_object_unref (selected); + g_print ("\t*** End Finish selection ***\n"); + return FALSE; +} + + +static void +_create_event_watcher (void) +{ + atk_add_focus_tracker (_do_selection); +} + +int +gtk_module_init(gint argc, char* argv[]) +{ + g_print("testnotebook Module loaded\n"); + + _create_event_watcher(); + + return 0; +} diff --git a/modules/other/gail/tests/testobject.c b/modules/other/gail/tests/testobject.c new file mode 100644 index 0000000000..c96516daec --- /dev/null +++ b/modules/other/gail/tests/testobject.c @@ -0,0 +1,339 @@ +#include +#include "testlib.h" + +static void _print_accessible (AtkObject *obj); +static void _print_type (AtkObject *obj); +static void _print_states (AtkObject *obj); +static void _check_children (AtkObject *obj); +static void _check_relation (AtkObject *obj); +static void _create_event_watcher (void); +static void _focus_handler (AtkObject *obj, gboolean focus_in); +static gboolean _children_changed (GSignalInvocationHint *ihint, + guint n_param_values, + const GValue *param_values, + gpointer data); + +static guint id; + +static void _print_states (AtkObject *obj) +{ + AtkStateSet *state_set; + gint i; + + state_set = atk_object_ref_state_set (obj); + + g_print ("*** Start states ***\n"); + for (i = 0; i < 64; i++) + { + AtkStateType one_state; + G_CONST_RETURN gchar *name; + + if (atk_state_set_contains_state (state_set, i)) + { + one_state = i; + + name = atk_state_type_get_name (one_state); + + if (name) + g_print("%s\n", name); + } + } + g_object_unref (state_set); + g_print ("*** End states ***\n"); +} + +static void _print_type (AtkObject *obj) +{ + G_CONST_RETURN gchar * typename = NULL; + G_CONST_RETURN gchar * name = NULL; + AtkRole role; + static gboolean in_print_type = FALSE; + + if (GTK_IS_ACCESSIBLE (obj)) + { + GtkWidget* widget = NULL; + + widget = GTK_ACCESSIBLE (obj)->widget; + typename = g_type_name (GTK_OBJECT_TYPE (widget)); + g_print ("Widget type name: %s\n", typename ? typename : "NULL"); + } + typename = g_type_name (G_OBJECT_TYPE (obj)); + g_print ("Accessible type name: %s\n", typename ? typename : "NULL"); + name = atk_object_get_name (obj); + g_print("Accessible Name: %s\n", (name) ? name : "NULL"); + role = atk_object_get_role (obj); + g_print ("Accessible Role: %s\n", atk_role_get_name (role)); + + if (ATK_IS_COMPONENT (obj)) + { + gint x, y, width, height; + AtkStateSet *states; + + _print_states (obj); + states = atk_object_ref_state_set (obj); + if (atk_state_set_contains_state (states, ATK_STATE_VISIBLE)) + { + AtkObject *parent; + + atk_component_get_extents (ATK_COMPONENT (obj), + &x, &y, &width, &height, + ATK_XY_SCREEN); + g_print ("ATK_XY_SCREEN: x: %d y: %d width: %d height: %d\n", + x, y, width, height); + + atk_component_get_extents (ATK_COMPONENT (obj), + &x, &y, &width, &height, + ATK_XY_WINDOW); + g_print ("ATK_XY_WINDOW: x: %d y: %d width: %d height: %d\n", + x, y, width, height); + if (atk_state_set_contains_state (states, ATK_STATE_SHOWING) && + ATK_IS_TEXT (obj)) + { + gint offset; + + atk_text_get_character_extents (ATK_TEXT (obj), 1, + &x, &y, &width, &height, + ATK_XY_WINDOW); + g_print ("Character extents : %d %d %d %d\n", + x, y, width, height); + if (width != 0 && height != 0) + { + offset = atk_text_get_offset_at_point (ATK_TEXT (obj), + x, y, + ATK_XY_WINDOW); + if (offset != 1) + { + g_print ("Wrong offset returned (%d) %d\n", 1, offset); + } + } + } + if (in_print_type) + return; + + parent = atk_object_get_parent (obj); + if (!ATK_IS_COMPONENT (parent)) + { + /* Assume toplevel */ + g_object_unref (G_OBJECT (states)); + return; + } +#if 0 + obj1 = atk_component_ref_accessible_at_point (ATK_COMPONENT (parent), + x, y, ATK_XY_WINDOW); + if (obj != obj1) + { + g_print ("Inconsistency between object and ref_accessible_at_point\n"); + in_print_type = TRUE; + _print_type (obj1); + in_print_type = FALSE; + } +#endif + } + g_object_unref (G_OBJECT (states)); + } +} + +static void _print_accessible (AtkObject *obj) +{ + GtkWidget* widget = NULL; + AtkObject* parent_atk; + AtkObject* ref_obj; + AtkRole role; + static gboolean first_time = TRUE; + + if (first_time) + { + first_time = FALSE; + atk_add_global_event_listener (_children_changed, + "Atk:AtkObject:children_changed"); + } + + /* + * Check that the object returned by the atk_implementor_ref_accessible() + * for a widget is the same as the accessible object + */ + if (GTK_IS_ACCESSIBLE (obj)) + { + widget = GTK_ACCESSIBLE (obj)->widget; + ref_obj = atk_implementor_ref_accessible (ATK_IMPLEMENTOR (widget)); + g_assert (ref_obj == obj); + g_object_unref (G_OBJECT (ref_obj)); + } + /* + * Add a focus handler so we see focus out events as well + */ + if (ATK_IS_COMPONENT (obj)) + atk_component_add_focus_handler (ATK_COMPONENT (obj), _focus_handler); + g_print ("Object:\n"); + _print_type (obj); + _print_states (obj); + + /* + * Get the parent object + */ + parent_atk = atk_object_get_parent (obj); + if (parent_atk) + { + g_print ("Parent Object:\n"); + _print_type (parent_atk); + parent_atk = atk_object_get_parent (parent_atk); + if (parent_atk) + { + g_print ("Grandparent Object:\n"); + _print_type (parent_atk); + } + } + else + { + g_print ("No parent\n"); + } + + role = atk_object_get_role (obj); + + if ((role == ATK_ROLE_FRAME) || (role == ATK_ROLE_DIALOG)) + { + _check_children (obj); + } +} + +static void _check_relation (AtkObject *obj) +{ + AtkRelationSet* relation_set = atk_object_ref_relation_set (obj); + gint n_relations, i; + + g_return_if_fail (relation_set); + + n_relations = atk_relation_set_get_n_relations (relation_set); + for (i = 0; i < n_relations; i++) + { + AtkRelation* relation = atk_relation_set_get_relation (relation_set, i); + + g_print ("Index: %d Relation type: %d Number: %d\n", i, + atk_relation_get_relation_type (relation), + atk_relation_get_target (relation)->len); + } + g_object_unref (relation_set); +} + +static void _check_children (AtkObject *obj) +{ + gint n_children, i; + AtkLayer layer; + AtkRole role; + + g_print ("Start Check Children\n"); + n_children = atk_object_get_n_accessible_children (obj); + g_print ("Number of children: %d\n", n_children); + + role = atk_object_get_role (obj); + + if (ATK_IS_COMPONENT (obj)) + { + atk_component_add_focus_handler (ATK_COMPONENT (obj), _focus_handler); + layer = atk_component_get_layer (ATK_COMPONENT (obj)); + if (role == ATK_ROLE_MENU) + g_assert (layer == ATK_LAYER_POPUP); + else + g_print ("Layer: %d\n", layer); + } + + for (i = 0; i < n_children; i++) + { + AtkObject *child; + AtkObject *parent; + int j; + + child = atk_object_ref_accessible_child (obj, i); + parent = atk_object_get_parent (child); + j = atk_object_get_index_in_parent (child); + _print_type (child); + _check_relation (child); + _check_children (child); + if (obj != parent) + { + g_print ("*** Inconsistency between atk_object_get_parent() and " + "atk_object_ref_accessible_child() ***\n"); + _print_type (child); + _print_type (obj); + if (parent) + _print_type (parent); + } + g_object_unref (G_OBJECT (child)); + + if (j != i) + g_print ("*** Inconsistency between parent and children %d %d ***\n", + i, j); + } + g_print ("End Check Children\n"); +} + +static gboolean +_children_changed (GSignalInvocationHint *ihint, + guint n_param_values, + const GValue *param_values, + gpointer data) +{ + GObject *object; + guint index; + gpointer target; + G_CONST_RETURN gchar *target_name = "NotAtkObject"; + + object = g_value_get_object (param_values + 0); + index = g_value_get_uint (param_values + 1); + target = g_value_get_pointer (param_values + 2); + if (G_IS_OBJECT (target)) + { + if (ATK_IS_OBJECT (target)) + { + target_name = atk_object_get_name (target); + } + if (!target_name) + target_name = g_type_name (G_OBJECT_TYPE (G_OBJECT (target))); + } + else + { + if (!target) + { + AtkObject *child; + + child = atk_object_ref_accessible_child (ATK_OBJECT (object), index); + if (child) + { + target_name = g_type_name (G_OBJECT_TYPE (G_OBJECT (child))); + g_object_unref (child); + } + } + } + g_print ("_children_watched: %s %s %s index: %d\n", + g_type_name (G_OBJECT_TYPE (object)), + g_quark_to_string (ihint->detail), + target_name, index); + return TRUE; +} + +static void +_create_event_watcher (void) +{ + /* + * _print_accessible() will be called for an accessible object when its + * widget receives focus. + */ + id = atk_add_focus_tracker (_print_accessible); +} + +static void +_focus_handler (AtkObject *obj, gboolean focus_in) +{ + g_print ("In _focus_handler focus_in: %s\n", focus_in ? "true" : "false"); + _print_type (obj); +} + +int +gtk_module_init(gint argc, char* argv[]) +{ + g_print("testobject Module loaded\n"); + + _create_event_watcher(); + + return 0; +} diff --git a/modules/other/gail/tests/testoptionmenu.c b/modules/other/gail/tests/testoptionmenu.c new file mode 100644 index 0000000000..3e9e74c63c --- /dev/null +++ b/modules/other/gail/tests/testoptionmenu.c @@ -0,0 +1,154 @@ +#include +#include "testlib.h" + +/* + * This module is used to test the accessible implementation for GtkOptionMenu + * + * When the GtkOption menu in the FileSelectionDialog is tabbed to, the menu + * is opened and the second item in the menu is selected which causes the + * menu to be closed and the item in the GtkOptionMenu to be updated. + */ +#define NUM_VALID_ROLES 1 + +static void _create_event_watcher (void); +static void _check_object (AtkObject *obj); +static gint _do_menu_item_action (gpointer data); +static gboolean doing_action = FALSE; + +static void +_check_object (AtkObject *obj) +{ + AtkRole role; + static G_CONST_RETURN char *name = NULL; + static gboolean first_time = TRUE; + + role = atk_object_get_role (obj); + if (role == ATK_ROLE_PUSH_BUTTON) + /* + * Find the specified optionmenu item + */ + { + AtkRole valid_roles[NUM_VALID_ROLES]; + AtkObject *atk_option_menu; + GtkWidget *widget; + + if (name == NULL) + { + name = g_getenv ("TEST_ACCESSIBLE_NAME"); + if (name == NULL) + name = "foo"; + } + valid_roles[0] = ATK_ROLE_PUSH_BUTTON; + atk_option_menu = find_object_by_accessible_name_and_role (obj, name, + valid_roles, NUM_VALID_ROLES); + + if (atk_option_menu == NULL) + { + g_print ("Object not found for %s\n", name); + return; + } + else + { + g_print ("Object found for %s\n", name); + } + + + g_assert (GTK_IS_ACCESSIBLE (atk_option_menu)); + widget = GTK_ACCESSIBLE (atk_option_menu)->widget; + g_assert (GTK_IS_OPTION_MENU (widget)); + + if (first_time) + first_time = FALSE; + else + return; + + /* + * This action opens the GtkOptionMenu whose name is "foo" or whatever + * was specified in the environment variable TEST_ACCESSIBLE_NAME + */ + atk_action_do_action (ATK_ACTION (atk_option_menu), 0); + } + else if ((role == ATK_ROLE_MENU_ITEM) || + (role == ATK_ROLE_CHECK_MENU_ITEM) || + (role == ATK_ROLE_RADIO_MENU_ITEM) || + (role == ATK_ROLE_TEAR_OFF_MENU_ITEM)) + { + AtkObject *parent, *child; + AtkRole parent_role; + + /* + * If we receive focus while waiting for the menu to be closed + * we return immediately + */ + if (doing_action) + return; + + parent = atk_object_get_parent (obj); + parent_role = atk_object_get_role (parent); + g_assert (parent_role == ATK_ROLE_MENU); + + child = atk_object_ref_accessible_child (parent, 1); + doing_action = TRUE; + gtk_timeout_add (5000, _do_menu_item_action, child); + } + else + { + G_CONST_RETURN char *accessible_name; + + accessible_name = atk_object_get_name (obj); + if (accessible_name) + { + g_print ("Name: %s\n", accessible_name); + } + else if (GTK_IS_ACCESSIBLE (obj)) + { + GtkWidget *widget = GTK_ACCESSIBLE (obj)->widget; + g_print ("Type: %s\n", g_type_name (G_OBJECT_TYPE (widget))); + } + if (role == ATK_ROLE_TABLE) + { + gint n_cols, i; + + n_cols = atk_table_get_n_columns (ATK_TABLE (obj)); + g_print ("Number of Columns: %d\n", n_cols); + + for (i = 0; i < n_cols; i++) + { + AtkObject *header; + + header = atk_table_get_column_header (ATK_TABLE (obj), i); + g_print ("header: %s %s\n", + g_type_name (G_OBJECT_TYPE (header)), + atk_object_get_name (header)); + } + } + } +} + +static gint _do_menu_item_action (gpointer data) +{ + AtkObject *obj = ATK_OBJECT (data); + + atk_action_do_action (ATK_ACTION (obj), 0); + doing_action = FALSE; + + g_object_unref (obj); + + return FALSE; +} + +static void +_create_event_watcher (void) +{ + atk_add_focus_tracker (_check_object); +} + +int +gtk_module_init(gint argc, char* argv[]) +{ + g_print("testoptionmenu Module loaded\n"); + + _create_event_watcher(); + + return 0; +} diff --git a/modules/other/gail/tests/testpaned.c b/modules/other/gail/tests/testpaned.c new file mode 100644 index 0000000000..ae39364c10 --- /dev/null +++ b/modules/other/gail/tests/testpaned.c @@ -0,0 +1,133 @@ +#include +#include +#include +#include + +static gint _test_paned (gpointer data); +static void _check_paned (AtkObject *obj); + +static void _property_change_handler (AtkObject *obj, + AtkPropertyValues *values); + +#define NUM_VALID_ROLES 1 +static gint last_position; + +static void _property_change_handler (AtkObject *obj, + AtkPropertyValues *values) +{ + G_CONST_RETURN gchar *type_name = g_type_name (G_TYPE_FROM_INSTANCE (obj)); + G_CONST_RETURN gchar *name = atk_object_get_name (obj); + + g_print ("_property_change_handler: Accessible Type: %s\n", + type_name ? type_name : "NULL"); + g_print ("_property_change_handler: Accessible name: %s\n", + name ? name : "NULL"); + g_print ("_property_change_handler: PropertyName: %s\n", + values->property_name ? values->property_name: "NULL"); + if (strcmp (values->property_name, "accessible-value") == 0) + { + GValue *value, val; + int position; + value = &val; + + memset (value, 0, sizeof (GValue)); + atk_value_get_current_value (ATK_VALUE (obj), value); + g_return_if_fail (G_VALUE_HOLDS_INT (value)); + position = g_value_get_int (value); + g_print ("Position is %d previous position was %d\n", + position, last_position); + last_position = position; + atk_value_get_minimum_value (ATK_VALUE (obj), value); + g_return_if_fail (G_VALUE_HOLDS_INT (value)); + position = g_value_get_int (value); + g_print ("Minimum Value is %d\n", position); + atk_value_get_maximum_value (ATK_VALUE (obj), value); + g_return_if_fail (G_VALUE_HOLDS_INT (value)); + position = g_value_get_int (value); + g_print ("Maximum Value is %d\n", position); + } +} + +static gint _test_paned (gpointer data) +{ + AtkObject *obj = ATK_OBJECT (data); + AtkRole role = atk_object_get_role (obj); + GtkWidget *widget; + static gint times = 0; + + widget = GTK_ACCESSIBLE (obj)->widget; + + if (role == ATK_ROLE_SPLIT_PANE) + { + GValue *value, val; + int position; + value = &val; + + memset (value, 0, sizeof (GValue)); + atk_value_get_current_value (ATK_VALUE (obj), value); + g_return_val_if_fail (G_VALUE_HOLDS_INT (value), FALSE); + position = g_value_get_int (value); + g_print ("Position is : %d\n", position); + last_position = position; + position *= 2; + g_value_set_int (value, position); + atk_value_set_current_value (ATK_VALUE (obj), value); + times++; + } + if (times < 4) + return TRUE; + else + return FALSE; +} + +static void _check_paned (AtkObject *obj) +{ + static gboolean done_paned = FALSE; + AtkRole role; + + role = atk_object_get_role (obj); + + if (role == ATK_ROLE_FRAME) + { + AtkRole roles[NUM_VALID_ROLES]; + AtkObject *paned_obj; + + if (done_paned) + return; + + roles[0] = ATK_ROLE_SPLIT_PANE; + + paned_obj = find_object_by_role (obj, roles, NUM_VALID_ROLES); + + if (paned_obj) + { + if (!done_paned) + { + done_paned = TRUE; + } + atk_object_connect_property_change_handler (paned_obj, + (AtkPropertyChangeHandler*) _property_change_handler); + gtk_timeout_add (2000, _test_paned, paned_obj); + } + + return; + } + if (role != ATK_ROLE_COMBO_BOX) + return; +} + +static void +_create_event_watcher (void) +{ + atk_add_focus_tracker (_check_paned); +} + +int +gtk_module_init(gint argc, char* argv[]) +{ + g_print("testpaned Module loaded\n"); + + _create_event_watcher(); + + return 0; +} diff --git a/modules/other/gail/tests/testprops.c b/modules/other/gail/tests/testprops.c new file mode 100644 index 0000000000..8db555e177 --- /dev/null +++ b/modules/other/gail/tests/testprops.c @@ -0,0 +1,220 @@ +#include +#include +#include +#include +#include + +static void _traverse_children (AtkObject *obj); +static void _add_handler (AtkObject *obj); +static void _check_properties (AtkObject *obj); +static void _property_change_handler (AtkObject *obj, + AtkPropertyValues *values); +static void _state_changed (AtkObject *obj, + const gchar *name, + gboolean set); +static void _selection_changed (AtkObject *obj); +static void _visible_data_changed (AtkObject *obj); +static void _model_changed (AtkObject *obj); +static void _create_event_watcher (void); + +static guint id; + +static void +_state_changed (AtkObject *obj, + const gchar *name, + gboolean set) +{ + g_print ("_state_changed: %s: state %s %s\n", + g_type_name (G_OBJECT_TYPE (obj)), + set ? "is" : "was", name); +} + +static void +_selection_changed (AtkObject *obj) +{ + gchar *type; + + if (ATK_IS_TEXT (obj)) + type = "text"; + else if (ATK_IS_SELECTION (obj)) + type = "child selection"; + else + { + g_assert_not_reached(); + return; + } + + g_print ("In selection_changed signal handler for %s, object type: %s\n", + type, g_type_name (G_OBJECT_TYPE (obj))); +} + +static void +_visible_data_changed (AtkObject *obj) +{ + g_print ("In visible_data_changed signal handler, object type: %s\n", + g_type_name (G_OBJECT_TYPE (obj))); +} + +static void +_model_changed (AtkObject *obj) +{ + g_print ("In model_changed signal handler, object type: %s\n", + g_type_name (G_OBJECT_TYPE (obj))); +} + +static void +_property_change_handler (AtkObject *obj, + AtkPropertyValues *values) +{ + G_CONST_RETURN gchar *type_name = g_type_name (G_TYPE_FROM_INSTANCE (obj)); + G_CONST_RETURN gchar *name = atk_object_get_name (obj); + + g_print ("_property_change_handler: Accessible Type: %s\n", + type_name ? type_name : "NULL"); + g_print ("_property_change_handler: Accessible name: %s\n", + name ? name : "NULL"); + g_print ("_property_change_handler: PropertyName: %s\n", + values->property_name ? values->property_name: "NULL"); + if (G_VALUE_HOLDS_STRING (&values->new_value)) + g_print ("_property_change_handler: PropertyValue: %s\n", + g_value_get_string (&values->new_value)); + else if (strcmp (values->property_name, "accessible-child") == 0) + { + if (G_IS_VALUE (&values->old_value)) + { + g_print ("Child is removed: %s\n", + g_type_name (G_TYPE_FROM_INSTANCE (g_value_get_pointer (&values->old_value)))); + } + if (G_IS_VALUE (&values->new_value)) + { + g_print ("Child is added: %s\n", + g_type_name (G_TYPE_FROM_INSTANCE (g_value_get_pointer (&values->new_value)))); + } + } + else if (strcmp (values->property_name, "accessible-parent") == 0) + { + if (G_IS_VALUE (&values->old_value)) + { + g_print ("Parent is removed: %s\n", + g_type_name (G_TYPE_FROM_INSTANCE (g_value_get_pointer (&values->old_value)))); + } + if (G_IS_VALUE (&values->new_value)) + { + g_print ("Parent is added: %s\n", + g_type_name (G_TYPE_FROM_INSTANCE (g_value_get_pointer (&values->new_value)))); + } + } + else if (strcmp (values->property_name, "accessible-value") == 0) + { + if (G_VALUE_HOLDS_DOUBLE (&values->new_value)) + { + g_print ("Value now is (double) %f\n", + g_value_get_double (&values->new_value)); + } + } +} + +static void +_traverse_children (AtkObject *obj) +{ + gint n_children, i; + AtkRole role; + + role = atk_object_get_role (obj); + + if ((role == ATK_ROLE_TABLE) || + (role == ATK_ROLE_TREE_TABLE)) + return; + + n_children = atk_object_get_n_accessible_children (obj); + for (i = 0; i < n_children; i++) + { + AtkObject *child; + + child = atk_object_ref_accessible_child (obj, i); + _add_handler (child); + _traverse_children (child); + g_object_unref (G_OBJECT (child)); + } +} + +static void +_add_handler (AtkObject *obj) +{ + static GPtrArray *obj_array = NULL; + gboolean found = FALSE; + gint i; + + /* + * We create a property handler for each object if one was not associated + * with it already. + * + * We add it to our array of objects which have property handlers; if an + * object is destroyed it remains in the array. + */ + if (obj_array == NULL) + obj_array = g_ptr_array_new (); + + for (i = 0; i < obj_array->len; i++) + { + if (obj == g_ptr_array_index (obj_array, i)) + { + found = TRUE; + break; + } + } + if (!found) + { + atk_object_connect_property_change_handler (obj, + (AtkPropertyChangeHandler*) _property_change_handler); + g_signal_connect (obj, "state-change", + (GCallback) _state_changed, NULL); + if (ATK_IS_SELECTION (obj)) + g_signal_connect (obj, "selection_changed", + (GCallback) _selection_changed, NULL); + g_signal_connect (obj, "visible_data_changed", + (GCallback) _visible_data_changed, NULL); + if (ATK_IS_TABLE (obj)) + g_signal_connect (obj, "model_changed", + (GCallback) _model_changed, NULL); + g_ptr_array_add (obj_array, obj); + } +} + +static void +_check_properties (AtkObject *obj) +{ + AtkRole role; + + g_print ("Start of _check_properties: %s\n", + g_type_name (G_OBJECT_TYPE (obj))); + + _add_handler (obj); + + role = atk_object_get_role (obj); + if (role == ATK_ROLE_FRAME || + role == ATK_ROLE_DIALOG) + { + /* + * Add handlers to all children. + */ + _traverse_children (obj); + } + g_print ("End of _check_properties\n"); +} + +static void +_create_event_watcher (void) +{ + id = atk_add_focus_tracker (_check_properties); +} + +int +gtk_module_init(gint argc, char* argv[]) +{ + g_print("testprops Module loaded\n"); + + _create_event_watcher(); + + return 0; +} diff --git a/modules/other/gail/tests/testselection.c b/modules/other/gail/tests/testselection.c new file mode 100644 index 0000000000..0311663d97 --- /dev/null +++ b/modules/other/gail/tests/testselection.c @@ -0,0 +1,198 @@ +#include +#include +#include + +/* + * This module tests the selection interface on menu items. + * To use this module run the test program testgtk and use the menus + * option. + */ +static void _do_selection (AtkObject *obj); +static gint _finish_selection (gpointer data); +static AtkObject* _find_object (AtkObject* obj, AtkRole role); +static void _print_type (AtkObject *obj); + +static AtkObject* +_find_object (AtkObject *obj, + AtkRole role) +{ + /* + * Find the first object which is a descendant of the specified object + * which matches the specified role. + * + * This function returns a reference to the AtkObject which should be + * removed when finished with the object. + */ + gint i; + gint n_children; + AtkObject *child; + + n_children = atk_object_get_n_accessible_children (obj); + for (i = 0; i < n_children; i++) + { + AtkObject* found_obj; + + child = atk_object_ref_accessible_child (obj, i); + if (atk_object_get_role (child) == role) + { + return child; + } + found_obj = _find_object (child, role); + g_object_unref (child); + if (found_obj) + { + return found_obj; + } + } + return NULL; +} + +static void _print_type (AtkObject *obj) +{ + G_CONST_RETURN gchar * typename = NULL; + G_CONST_RETURN gchar * name = NULL; + AtkRole role; + + if (GTK_IS_ACCESSIBLE (obj)) + { + GtkWidget* widget = NULL; + + widget = GTK_ACCESSIBLE (obj)->widget; + typename = g_type_name (GTK_OBJECT_TYPE (widget)); + g_print ("Widget type name: %s\n", typename ? typename : "NULL"); + } + typename = g_type_name (G_OBJECT_TYPE (obj)); + g_print ("Accessible type name: %s\n", typename ? typename : "NULL"); + name = atk_object_get_name (obj); + g_print("Accessible Name: %s\n", (name) ? name : "NULL"); + role = atk_object_get_role(obj); + g_print ("Accessible Role: %d\n", role); +} + +static void +_do_selection (AtkObject *obj) +{ + gint i; + AtkObject *selected; + AtkRole role; + AtkObject *selection_obj; + + role = atk_object_get_role (obj); + + if ((role == ATK_ROLE_FRAME) && + (strcmp (atk_object_get_name (obj), "menus") == 0)) + { + selection_obj = _find_object (obj, ATK_ROLE_MENU_BAR); + if (selection_obj) + { + g_object_unref (selection_obj); + } + } + else if (role == ATK_ROLE_COMBO_BOX) + { + selection_obj = obj; + } + else + return; + + g_print ("*** Start do_selection ***\n"); + + + if (!selection_obj) + { + g_print ("no selection_obj\n"); + return; + } + + i = atk_selection_get_selection_count (ATK_SELECTION (selection_obj)); + if (i != 0) + { + for (i = 0; i < atk_object_get_n_accessible_children (selection_obj); i++) + { + if (atk_selection_is_child_selected (ATK_SELECTION (selection_obj), i)) + { + g_print ("%d child selected\n", i); + } + else + { + g_print ("%d child not selected\n", i); + } + } + } + /* + * Should not be able to select all items on a menu bar + */ + atk_selection_select_all_selection (ATK_SELECTION (selection_obj)); + i = atk_selection_get_selection_count (ATK_SELECTION (selection_obj)); + if ( i != 0) + { + g_print ("Unexpected selection count: %d, expected 0\n", i); + return; + } + /* + * There should not be any items selected + */ + selected = atk_selection_ref_selection (ATK_SELECTION (selection_obj), 0); + if ( selected != NULL) + { + g_print ("Unexpected selection: %d, expected 0\n", i); + } + atk_selection_add_selection (ATK_SELECTION (selection_obj), 1); + gtk_timeout_add (2000, _finish_selection, selection_obj); + g_print ("*** End _do_selection ***\n"); +} + +static gint _finish_selection (gpointer data) +{ + AtkObject *obj = ATK_OBJECT (data); + AtkObject *selected; + gint i; + gboolean is_selected; + + g_print ("*** Start Finish selection ***\n"); + + /* + * If being run for for menus, at this point menu item foo should be + * selected which means that its submenu should be visible. + */ + i = atk_selection_get_selection_count (ATK_SELECTION (obj)); + if (i != 1) + { + g_print ("Unexpected selection count: %d, expected 1\n", i); + return FALSE; + } + selected = atk_selection_ref_selection (ATK_SELECTION (obj), 0); + g_return_val_if_fail (selected != NULL, FALSE); + g_print ("*** Selected Item ***\n"); + _print_type (selected); + g_object_unref (selected); + is_selected = atk_selection_is_child_selected (ATK_SELECTION (obj), 1); + g_return_val_if_fail (is_selected, FALSE); + is_selected = atk_selection_is_child_selected (ATK_SELECTION (obj), 0); + g_return_val_if_fail (!is_selected, FALSE); + selected = atk_selection_ref_selection (ATK_SELECTION (obj), 1); + g_return_val_if_fail (selected == NULL, FALSE); + atk_selection_remove_selection (ATK_SELECTION (obj), 0); + i = atk_selection_get_selection_count (ATK_SELECTION (obj)); + g_return_val_if_fail (i == 0, FALSE); + selected = atk_selection_ref_selection (ATK_SELECTION (obj), 0); + g_return_val_if_fail (selected == NULL, FALSE); + g_print ("*** End Finish selection ***\n"); + return FALSE; +} + +static void +_create_event_watcher (void) +{ + atk_add_focus_tracker (_do_selection); +} + +int +gtk_module_init(gint argc, char* argv[]) +{ + g_print("testselection Module loaded\n"); + + _create_event_watcher(); + + return 0; +} diff --git a/modules/other/gail/tests/teststatusbar.c b/modules/other/gail/tests/teststatusbar.c new file mode 100644 index 0000000000..97d6abb59d --- /dev/null +++ b/modules/other/gail/tests/teststatusbar.c @@ -0,0 +1,127 @@ +#include +#include +#include + +/* + * To use this test module, run the test program testgtk and click on + * statusbar + */ + +static void _check_statusbar (AtkObject *obj); +static AtkObject* _find_object (AtkObject* obj, AtkRole role); +static void _notify_handler (GObject *obj, GParamSpec *pspec); +static void _property_change_handler (AtkObject *obj, + AtkPropertyValues *values); + +static AtkObject* +_find_object (AtkObject *obj, + AtkRole role) +{ + /* + * Find the first object which is a descendant of the specified object + * which matches the specified role. + * + * This function returns a reference to the AtkObject which should be + * removed when finished with the object. + */ + gint i; + gint n_children; + AtkObject *child; + + n_children = atk_object_get_n_accessible_children (obj); + for (i = 0; i < n_children; i++) + { + AtkObject* found_obj; + + child = atk_object_ref_accessible_child (obj, i); + if (atk_object_get_role (child) == role) + { + return child; + } + found_obj = _find_object (child, role); + g_object_unref (child); + if (found_obj) + { + return found_obj; + } + } + return NULL; +} + +static void _property_change_handler (AtkObject *obj, + AtkPropertyValues *values) +{ + G_CONST_RETURN gchar *type_name = g_type_name (G_TYPE_FROM_INSTANCE (obj)); + G_CONST_RETURN gchar *name = atk_object_get_name (obj); + + g_print ("_property_change_handler: Accessible Type: %s\n", + type_name ? type_name : "NULL"); + g_print ("_property_change_handler: Accessible name: %s\n", + name ? name : "NULL"); + g_print ("_property_change_handler: PropertyName: %s\n", + values->property_name ? values->property_name: "NULL"); + if (G_VALUE_HOLDS_STRING (&values->new_value)) + g_print ("_property_change_handler: PropertyValue: %s\n", + g_value_get_string (&values->new_value)); +} + +static void _check_statusbar (AtkObject *obj) +{ + AtkRole role; + AtkObject *statusbar, *label; + + role = atk_object_get_role (obj); + if (role != ATK_ROLE_FRAME) + return; + + statusbar = _find_object (obj, ATK_ROLE_STATUSBAR); + if (!statusbar) + return; + g_print ("_check_statusbar\n"); + label = atk_object_ref_accessible_child (statusbar, 0); + g_return_if_fail (label == NULL); + + /* + * We get notified of changes to the label + */ + g_signal_connect_closure_by_id (statusbar, + g_signal_lookup ("notify", + G_OBJECT_TYPE (statusbar)), + 0, + g_cclosure_new (G_CALLBACK (_notify_handler), + NULL, NULL), + FALSE); + atk_object_connect_property_change_handler (statusbar, + (AtkPropertyChangeHandler*) _property_change_handler); + +} + +static void +_notify_handler (GObject *obj, GParamSpec *pspec) +{ + AtkObject *atk_obj = ATK_OBJECT (obj); + G_CONST_RETURN gchar *name; + + g_print ("_notify_handler: property: %s\n", pspec->name); + if (strcmp (pspec->name, "accessible-name") == 0) + { + name = atk_object_get_name (atk_obj); + g_print ("_notify_handler: value: |%s|\n", name ? name : ""); + } +} + +static void +_create_event_watcher (void) +{ + atk_add_focus_tracker (_check_statusbar); +} + +int +gtk_module_init(gint argc, char* argv[]) +{ + g_print("teststatusbar Module loaded\n"); + + _create_event_watcher(); + + return 0; +} diff --git a/modules/other/gail/tests/testtable.c b/modules/other/gail/tests/testtable.c new file mode 100644 index 0000000000..3e3cf83da0 --- /dev/null +++ b/modules/other/gail/tests/testtable.c @@ -0,0 +1,939 @@ +#include +#include "testtextlib.h" + +#define NUM_ROWS_TO_LOOP 30 + +typedef struct +{ + GtkWidget *tb_others; + GtkWidget *tb_ref_selection; + GtkWidget *tb_ref_at; + GtkWidget *tb_ref_accessible_child; + GtkWidget *child_entry; + GtkWidget *row_entry; + GtkWidget *col_entry; + GtkWidget *index_entry; +}TestChoice; + +static void _check_table (AtkObject *in_obj); +void table_runtest(AtkObject *); +static void other_runtest(AtkObject *obj); +static void ref_at_runtest(AtkObject *obj, gint row, gint col); +static void ref_accessible_child_runtest(AtkObject *obj, gint childno); +static void ref_selection_runtest (AtkObject *obj, gint index); +static void _selection_tests(AtkObject *obj); +static void _display_header_info(gchar *type, + AtkObject *header_obj, gint header_num); +static void _process_child(AtkObject *child_obj); + +static void _notify_table_row_inserted (GObject *obj, + gint start_offset, gint length); +static void _notify_table_column_inserted (GObject *obj, + gint start_offset, gint length); +static void _notify_table_row_deleted (GObject *obj, + gint start_offset, gint length); +static void _notify_table_column_deleted (GObject *obj, + gint start_offset, gint length); +static void _notify_table_row_reordered (GObject *obj); +static void _notify_table_column_reordered (GObject *obj); +static void _notify_table_child_added (GObject *obj, + gint index, AtkObject *child); +static void _notify_table_child_removed (GObject *obj, + gint index, AtkObject *child); +static void _property_signal_connect (AtkObject *obj); +static void _property_change_handler (AtkObject *obj, + AtkPropertyValues *values); + +static gboolean tested_set_headers = FALSE; +static void test_choice_gui (AtkObject **obj); +static void nogui_runtest (AtkObject *obj); +static void nogui_ref_at_runtest (AtkObject *obj); +static void nogui_process_child (AtkObject *obj); + +static TestChoice *tc; +static gint g_visibleGUI = 0; +static AtkTable *g_table = NULL; +static AtkObject *current_obj = NULL; +gboolean g_done = FALSE; +gboolean g_properties = TRUE; + +/* + * destroy + * + * Destroy Callback + * + */ +static void destroy (GtkWidget *widget, gpointer data) +{ + gtk_main_quit(); +} + +static void choicecb (GtkWidget *widget, gpointer data) +{ + AtkObject **ptr_to_obj = (AtkObject **)data; + AtkObject *obj = *ptr_to_obj; + + if (GTK_TOGGLE_BUTTON(tc->tb_others)->active) + { + other_runtest(obj); + } + else if (GTK_TOGGLE_BUTTON(tc->tb_ref_selection)->active) + { + const gchar *indexstr; + gint index; + + indexstr = gtk_entry_get_text(GTK_ENTRY(tc->index_entry)); + index = string_to_int((gchar *)indexstr); + + ref_selection_runtest(obj, index); + } + else if (GTK_TOGGLE_BUTTON(tc->tb_ref_at)->active) + { + const gchar *rowstr, *colstr; + gint row, col; + + rowstr = gtk_entry_get_text(GTK_ENTRY(tc->row_entry)); + colstr = gtk_entry_get_text(GTK_ENTRY(tc->col_entry)); + row = string_to_int((gchar *)rowstr); + col = string_to_int((gchar *)colstr); + + ref_at_runtest(obj, row, col); + } + else if (GTK_TOGGLE_BUTTON(tc->tb_ref_accessible_child)->active) + { + const gchar *childstr; + gint childno; + childstr = gtk_entry_get_text(GTK_ENTRY(tc->child_entry)); + childno = string_to_int((gchar *)childstr); + + ref_accessible_child_runtest(obj, childno); + } +} + +static void _check_table (AtkObject *in_obj) +{ + AtkObject *obj = NULL; + G_CONST_RETURN char *no_properties; + G_CONST_RETURN char *no_gui; + + no_properties = g_getenv ("TEST_ACCESSIBLE_NO_PROPERTIES"); + no_gui = g_getenv ("TEST_ACCESSIBLE_NO_GUI"); + + if (no_properties != NULL) + g_properties = FALSE; + if (no_gui != NULL) + g_visibleGUI = 1; + + obj = find_object_by_type(in_obj, "GailTreeView"); + if (obj != NULL) + g_print("Found GailTreeView table in child!\n"); + else + { + obj = find_object_by_type(in_obj, "GailCList"); + if (obj != NULL) + g_print("Found GailCList in child!\n"); + else + { + g_print("No object found %s\n", g_type_name (G_OBJECT_TYPE (in_obj))); + return; + } + } + + g_print ("In _check_table\n"); + + if (!already_accessed_atk_object(obj)) + { + /* Set up signal handlers */ + + g_print ("Adding signal handler\n"); + g_signal_connect_closure_by_id (obj, + g_signal_lookup ("column_inserted", G_OBJECT_TYPE (obj)), + 0, + g_cclosure_new (G_CALLBACK (_notify_table_column_inserted), + NULL, NULL), + FALSE); + g_signal_connect_closure_by_id (obj, + g_signal_lookup ("row_inserted", G_OBJECT_TYPE (obj)), + 0, + g_cclosure_new (G_CALLBACK (_notify_table_row_inserted), + NULL, NULL), + FALSE); + g_signal_connect_closure_by_id (obj, + g_signal_lookup ("column_deleted", G_OBJECT_TYPE (obj)), + 0, + g_cclosure_new (G_CALLBACK (_notify_table_column_deleted), + NULL, NULL), + FALSE); + g_signal_connect_closure_by_id (obj, + g_signal_lookup ("row_deleted", G_OBJECT_TYPE (obj)), + 0, + g_cclosure_new (G_CALLBACK (_notify_table_row_deleted), + NULL, NULL), + FALSE); + g_signal_connect_closure_by_id (obj, + g_signal_lookup ("column_reordered", G_OBJECT_TYPE (obj)), + 0, + g_cclosure_new (G_CALLBACK (_notify_table_column_reordered), + NULL, NULL), + FALSE); + g_signal_connect_closure_by_id (obj, + g_signal_lookup ("row_reordered", G_OBJECT_TYPE (obj)), + 0, + g_cclosure_new (G_CALLBACK (_notify_table_row_reordered), + NULL, NULL), + FALSE); + g_signal_connect_closure (obj, "children_changed::add", + g_cclosure_new (G_CALLBACK (_notify_table_child_added), + NULL, NULL), + FALSE); + + g_signal_connect_closure (obj, "children_changed::remove", + g_cclosure_new (G_CALLBACK (_notify_table_child_removed), + NULL, NULL), + FALSE); + + } + g_table = ATK_TABLE(obj); + + atk_object_connect_property_change_handler (obj, + (AtkPropertyChangeHandler*) _property_change_handler); + + current_obj = obj; + /* + * The use of ¤t_obj allows us to change the object being processed + * in the GUI. + */ + if (g_visibleGUI != 1) + test_choice_gui(¤t_obj); + else if (no_gui != NULL) + nogui_runtest(obj); +} + +static +void other_runtest(AtkObject *obj) +{ + AtkObject *header_obj; + AtkObject *out_obj; + G_CONST_RETURN gchar *out_string; + GString *out_desc; + gint n_cols, n_rows; + gint rows_to_loop = NUM_ROWS_TO_LOOP; + gint i, j; + out_desc = g_string_sized_new(256); + + n_cols = atk_table_get_n_columns(ATK_TABLE(obj)); + n_rows = atk_table_get_n_rows(ATK_TABLE(obj)); + + g_print ("Number of columns is %d\n", n_cols); + g_print ("Number of rows is %d\n", n_rows); + + /* Loop NUM_ROWS_TO_LOOP rows if possible */ + if (n_rows < NUM_ROWS_TO_LOOP) + rows_to_loop = n_rows; + + g_print ("\n"); + + /* Caption */ + + out_obj = atk_table_get_caption(ATK_TABLE(obj)); + if (out_obj != NULL) + { + out_string = atk_object_get_name (out_obj); + if (out_string) + g_print("Caption Name is <%s>\n", out_string); + else + g_print("Caption has no name\n"); + } + else + g_print("No caption\n"); + + /* Column descriptions and headers */ + + g_print ("\n"); + for (i=0; i < n_cols; i++) + { + /* check default */ + out_string = atk_table_get_column_description(ATK_TABLE(obj), i); + if (out_string != NULL) + g_print("%d: Column description is <%s>\n", i, out_string); + else + g_print("%d: Column description is \n", i); + + /* check setting a new value */ + + g_string_printf(out_desc, "new column description %d", i); + + if (out_string == NULL || strcmp (out_string, out_desc->str) != 0) + { + g_print("%d, Setting the column description to <%s>\n", + i, out_desc->str); + atk_table_set_column_description(ATK_TABLE(obj), i, out_desc->str); + out_string = atk_table_get_column_description(ATK_TABLE(obj), i); + if (out_string != NULL) + g_print("%d: Column description is <%s>\n", i, out_string); + else + g_print("%d: Column description is \n", i); + } + + /* Column header */ + header_obj = atk_table_get_column_header(ATK_TABLE(obj), i); + _display_header_info("Column", header_obj, i); + } + + /* Row description */ + + g_print ("\n"); + + for (i=0; i < rows_to_loop; i++) + { + out_string = atk_table_get_row_description(ATK_TABLE(obj), i); + if (out_string != NULL) + g_print("%d: Row description is <%s>\n", i, out_string); + else + g_print("%d: Row description is \n", i); + + g_string_printf(out_desc, "new row description %d", i); + + if (out_string == NULL || strcmp (out_string, out_desc->str) != 0) + { + g_print("%d: Setting the row description to <%s>\n", + i, out_desc->str); + atk_table_set_row_description(ATK_TABLE(obj), i, out_desc->str); + + out_string = atk_table_get_row_description(ATK_TABLE(obj), i); + if (out_string != NULL) + g_print("%d: Row description is <%s>\n", i, out_string); + else + g_print("%d: Row description is \n", i); + } + + header_obj = atk_table_get_row_header(ATK_TABLE(obj), i); + _display_header_info("Row", header_obj, i); + + for (j=0; j \n", header_num, + type, header_text); + } + else + { + g_print("%d: %s header is a text value \n", header_num, + type); + } + } + else + { + g_print ("%d: %s header is of type %s!\n", header_num, + type, atk_role_get_name (role)); + } + } + else + { + g_print ("%d: %s header object is NULL!\n", header_num, type); + } +} + +static void _property_signal_connect (AtkObject *obj) +{ + if (g_properties && obj != NULL) + { + g_signal_connect_closure_by_id (obj, + g_signal_lookup ("property_change", G_OBJECT_TYPE (obj)), + 0, + g_cclosure_new (G_CALLBACK (_property_change_handler), + NULL, NULL), + FALSE); + } +} + +static void +_property_change_handler (AtkObject *obj, + AtkPropertyValues *values) +{ + gchar *obj_text; + const gchar *name; + + if (g_table != NULL) + { + gint index = atk_object_get_index_in_parent(obj); + + if (index >= 0) + g_print("Index is %d, row is %d, col is %d\n", index, + atk_table_get_row_at_index(g_table, index), + atk_table_get_column_at_index(g_table, index)); + else + g_print ("index: %d for %s\n", index, g_type_name (G_OBJECT_TYPE (obj))); + } + + if (ATK_IS_TEXT(obj)) + { + obj_text = atk_text_get_text (ATK_TEXT (obj), 0, 15); + if (obj_text == NULL) + g_print(" Cell text is \n"); + else + g_print(" Cell text is <%s>\n", obj_text); + } + + g_print(" PropertyName <%s>\n", + values->property_name ? values->property_name: "NULL"); + g_print(" - "); + + if (&values->old_value != NULL && G_IS_VALUE (&values->old_value)) + { + GType old_type = G_VALUE_TYPE (&values->old_value); + + switch (old_type) + { + case G_TYPE_INT: + g_print("value was <%d>\n", g_value_get_int (&values->old_value)); + break; + case G_TYPE_STRING: + name = g_value_get_string (&values->old_value); + if (name != NULL) + g_print ("value was <%s>\n", name); + else + g_print ("value was \n"); + break; + default: + g_print("value was \n"); + break; + } + } + else + { + g_print("value was \n"); + } + g_print(" - "); + if (&values->new_value != NULL && G_IS_VALUE (&values->new_value)) + { + GType new_type = G_VALUE_TYPE (&values->new_value); + + switch (new_type) + { + case G_TYPE_INT: + g_print("value is <%d>\n", g_value_get_int (&values->new_value)); + break; + case G_TYPE_STRING: + name = g_value_get_string (&values->new_value); + if (name != NULL) + g_print ("value is <%s>\n", name); + else + g_print ("value is \n"); + break; + default: + g_print("value is \n"); + break; + } + } + else + { + g_print("value is \n"); + } +} + +static +void test_choice_gui(AtkObject **obj) +{ + GtkWidget *window; + GtkWidget *vbox; + GtkWidget *hbox; + GtkWidget *child_label; + GtkWidget *row_label; + GtkWidget *col_label; + GtkWidget *index_label; + GtkWidget *hseparator; + GtkWidget *hbuttonbox; + GtkWidget *button; + + + tc = (TestChoice *) g_malloc (sizeof(TestChoice)); + + window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_title(GTK_WINDOW(window), "Test to run"); + + g_signal_connect(GTK_OBJECT(window), "destroy", + GTK_SIGNAL_FUNC(destroy), &window); + + vbox = gtk_vbox_new(TRUE, 0); + gtk_box_set_spacing(GTK_BOX(vbox), 10); + + + hbox = gtk_hbox_new(FALSE, 0); + gtk_box_set_spacing(GTK_BOX(hbox), 10); + tc->tb_ref_selection = gtk_toggle_button_new_with_label("ref_selection"); + gtk_box_pack_start_defaults(GTK_BOX(hbox), tc->tb_ref_selection); + index_label = gtk_label_new("index: "); + gtk_box_pack_start_defaults(GTK_BOX(hbox), index_label); + tc->index_entry = gtk_entry_new(); + gtk_entry_set_text(GTK_ENTRY(tc->index_entry), "1"); + gtk_box_pack_start_defaults(GTK_BOX(hbox), tc->index_entry); + gtk_box_pack_start_defaults(GTK_BOX(vbox), hbox); + + hbox = gtk_hbox_new(FALSE, 0); + gtk_box_set_spacing(GTK_BOX(hbox), 10); + tc->tb_ref_at = gtk_toggle_button_new_with_label("ref_at"); + gtk_box_pack_start_defaults(GTK_BOX(hbox), tc->tb_ref_at); + row_label = gtk_label_new("row:"); + gtk_box_pack_start_defaults(GTK_BOX(hbox), row_label); + tc->row_entry = gtk_entry_new(); + gtk_entry_set_text(GTK_ENTRY(tc->row_entry), "1"); + gtk_box_pack_start_defaults(GTK_BOX(hbox), tc->row_entry); + col_label = gtk_label_new("column:"); + gtk_box_pack_start_defaults(GTK_BOX(hbox), col_label); + tc->col_entry = gtk_entry_new(); + gtk_entry_set_text(GTK_ENTRY(tc->col_entry), "1"); + gtk_box_pack_start_defaults(GTK_BOX(hbox), tc->col_entry); + gtk_box_pack_start_defaults(GTK_BOX(vbox), hbox); + + hbox = gtk_hbox_new(FALSE, 0); + gtk_box_set_spacing(GTK_BOX(hbox), 10); + tc->tb_ref_accessible_child = gtk_toggle_button_new_with_label("ref_accessible_child"); + gtk_box_pack_start_defaults(GTK_BOX(hbox), tc->tb_ref_accessible_child); + child_label = gtk_label_new("Child no:"); + gtk_box_pack_start_defaults(GTK_BOX(hbox), child_label); + tc->child_entry = gtk_entry_new(); + gtk_entry_set_text(GTK_ENTRY(tc->child_entry), "1"); + gtk_box_pack_start_defaults(GTK_BOX(hbox), tc->child_entry); + gtk_box_pack_start_defaults(GTK_BOX(vbox), hbox); + + tc->tb_others = gtk_toggle_button_new_with_label("others"); + gtk_box_pack_start_defaults(GTK_BOX(vbox), tc->tb_others); + + hseparator = gtk_hseparator_new(); + gtk_box_pack_start_defaults(GTK_BOX(vbox), hseparator); + + button = gtk_button_new_with_mnemonic("_Run Test"); + + hbuttonbox = gtk_hbutton_box_new(); + gtk_button_box_set_layout(GTK_BUTTON_BOX(hbuttonbox), + GTK_BUTTONBOX_SPREAD); + gtk_box_pack_end_defaults(GTK_BOX(hbuttonbox), GTK_WIDGET(button)); + gtk_box_pack_end_defaults(GTK_BOX(vbox), hbuttonbox); + g_signal_connect(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(choicecb), obj); + + gtk_container_add(GTK_CONTAINER(window), vbox); + gtk_widget_show(vbox); + gtk_widget_show(window); + gtk_widget_show_all(GTK_WIDGET(window)); + + g_visibleGUI = 1; +} + +void static +nogui_runtest (AtkObject *obj) +{ + g_print ("Running non-GUI tests...\n"); + other_runtest (obj); + nogui_ref_at_runtest (obj); +} + +static void +nogui_ref_at_runtest (AtkObject *obj) +{ + AtkObject *child_obj; + gint i, j; + gint n_cols; + gint rows_to_loop = 5; + + n_cols = atk_table_get_n_columns (ATK_TABLE(obj)); + + if (atk_table_get_n_rows(ATK_TABLE(obj)) < rows_to_loop) + rows_to_loop = atk_table_get_n_rows (ATK_TABLE(obj)); + + for (i=0; i < rows_to_loop; i++) + { + /* Just the first rows_to_loop rows */ + for (j=0; j < n_cols; j++) + { + gint index = atk_table_get_index_at(ATK_TABLE(obj), i, j); + if(atk_selection_is_child_selected(ATK_SELECTION(obj), index)) + g_print("atk_selection_is_child_selected,index = %d returns TRUE\n", index); + + g_print("Testing ref_at row %d column %d\n", i, j); + + if (i == 3 && j == 0) + { + g_print("child_obj gotten from atk_selection_ref_selection\n"); + + /* use atk_selection_ref_selection just once to check it works */ + child_obj = atk_selection_ref_selection(ATK_SELECTION(obj), index ); + } + else + { + child_obj = atk_table_ref_at(ATK_TABLE(obj), i, j); + } + + _property_signal_connect(child_obj); + + g_print("Index is %d, row is %d, col is %d\n", index, + atk_table_get_row_at_index(ATK_TABLE(obj), index), + atk_table_get_column_at_index(ATK_TABLE(obj), index)); + + nogui_process_child (child_obj); + + /* Generic cell tests */ + /* Just test setting column headers once. */ + + if (!tested_set_headers) + { + tested_set_headers = TRUE; + + g_print("Testing set_column_header for column %d, to cell value %d,%d\n", + j, i, j); + atk_table_set_column_header(ATK_TABLE(obj), j, child_obj); + + g_print("Testing set_row_header for row %d, to cell value %d,%d\n", + i, i, j); + atk_table_set_row_header(ATK_TABLE(obj), i, child_obj); + } + if (child_obj) + g_object_unref (child_obj); + } + } +} + +static void +nogui_process_child (AtkObject *obj) +{ + gchar default_val[5] = "NULL"; + + if (ATK_IS_TEXT(obj)) + { + gchar *current_text; + current_text = atk_text_get_text (ATK_TEXT(obj), 0, -1); + g_print ("Child supports text interface.\nCurrent text is %s\n", current_text); + } + + if (ATK_IS_ACTION(obj)) + { + AtkAction *action = ATK_ACTION(obj); + gint n_actions, i; + G_CONST_RETURN gchar *name, *description; + + n_actions = atk_action_get_n_actions (action); + g_print ("Child supports %d actions.\n", n_actions); + for (i = 0; i < n_actions; i++) + { + name = atk_action_get_name (action, i); + description = atk_action_get_description (action, i); + + if (name == NULL) + name = default_val; + if (description == NULL) + description = default_val; + + g_print (" %d: name = <%s>\n", i, name); + g_print (" description = <%s>\n", description); + } + } +} + diff --git a/modules/other/gail/tests/testtext.c b/modules/other/gail/tests/testtext.c new file mode 100644 index 0000000000..6af191c9a5 --- /dev/null +++ b/modules/other/gail/tests/testtext.c @@ -0,0 +1,134 @@ +#include +#include "testtextlib.h" + +#define NUM_VALID_ROLES 6 + +static void _create_event_watcher (void); +static void _check_text (AtkObject *obj); +void runtest(AtkObject *, gint); + +static guint id1 = 0; +static guint win_count = 0; + +static void _check_text (AtkObject *in_obj) +{ + AtkObject *obj = NULL; + AtkRole role; + gchar* title; + AtkRole valid_roles[NUM_VALID_ROLES]; + + if (g_getenv("TEST_ACCESSIBLE_DELAY") != NULL) + { + int max_cnt = string_to_int(g_getenv("TEST_ACCESSIBLE_DELAY")); + win_count++; + if (win_count <= max_cnt) + return; + } + + /* Set Up */ + + valid_roles[0] = ATK_ROLE_TEXT; + valid_roles[1] = ATK_ROLE_LABEL; + valid_roles[2] = ATK_ROLE_ACCEL_LABEL; + valid_roles[3] = ATK_ROLE_PASSWORD_TEXT; + valid_roles[4] = ATK_ROLE_TABLE_CELL; + valid_roles[5] = ATK_ROLE_PANEL; + + /* The following if/else grabs the windows name, or sets title to NULL if none. */ + if (in_obj->name) + { + title = in_obj->name; + } + else + { + GtkWidget *toplevel; + GtkWidget* widget = GTK_ACCESSIBLE (in_obj)->widget; + + if (widget == NULL) + { + title = NULL; + } + + toplevel = gtk_widget_get_toplevel (widget); + if (GTK_IS_WINDOW (toplevel) && GTK_WINDOW (toplevel)->title) + { + title = GTK_WINDOW (toplevel)->title; + } + else + title = NULL; + } + /* If no window name, do nothing */ + if (title == NULL) + return; + /* + * If testtext test program, find obj just by role since only one child + * with no name + */ + else if (g_ascii_strncasecmp(title, "testtext", 7) == 0) + { + obj = find_object_by_role(in_obj, valid_roles, NUM_VALID_ROLES); + } + /* + * Otherwise, get obj by name and role so you can specify exactly which + * obj to run tests on + */ + else + { + G_CONST_RETURN gchar *test_accessible_name = g_getenv ("TEST_ACCESSIBLE_NAME"); + + if (test_accessible_name != NULL) + { + obj = find_object_by_accessible_name_and_role(in_obj, + test_accessible_name, valid_roles, NUM_VALID_ROLES); + } + if (obj != NULL) + { + if (atk_object_get_role (obj) == ATK_ROLE_PANEL) + { + /* Get the child and check whether it is a label */ + + obj = atk_object_ref_accessible_child (obj, 0); + g_assert (atk_object_get_role (obj) == ATK_ROLE_LABEL); + g_object_unref (obj); + } + g_print("Found valid name and role in child!\n"); + } + else + { + obj = find_object_by_role(in_obj, valid_roles, NUM_VALID_ROLES - 1); + if (obj != NULL) + g_print("Found valid role in child\n"); + } + } + if (obj == NULL) + { + g_print("Object not found\n"); + return; + } + role = atk_object_get_role(obj); + + g_print("_check_text - Found role type %s!\n\n", atk_role_get_name (role)); + + add_handlers(obj); + + if (!(isVisibleDialog())) + setup_gui(obj, runtest); + atk_remove_focus_tracker (id1); +} + +static void +_create_event_watcher (void) +{ + id1 = atk_add_focus_tracker (_check_text); +} + +int +gtk_module_init(gint argc, char* argv[]) +{ + g_print("testtext Module loaded.\n"); + _create_event_watcher(); + + return 0; +} + + diff --git a/modules/other/gail/tests/testtextlib.c b/modules/other/gail/tests/testtextlib.c new file mode 100644 index 0000000000..38b8d0f8d0 --- /dev/null +++ b/modules/other/gail/tests/testtextlib.c @@ -0,0 +1,740 @@ +#include +#include +#include "testtextlib.h" + +static AtkAttributeSet *attrib = NULL; +static char result_string[2][6] = {"FALSE", "TRUE"}; + +/** + * setup_gui: + * @obj: An @AtkObject + * @test: The callback to be run when the "Run Tests" button + * in the GUI is clicked. + * + * Sets up the GUI windows. + * + * Returns: the window number, or -1 if failure. + **/ +gint setup_gui(AtkObject *obj, TLruntest test) +{ + gchar *paramnames[MAX_PARAMS]; + gchar *defaults[MAX_PARAMS]; + static OutputWindow *tow = NULL; + gint window; + + if (tow) + window = create_windows(obj, test, &tow); + else + window = create_windows(obj, test, &tow); + + if (window == -1) + return -1; + + /* Get Text [at|after|before] Offset Tests */ + paramnames[0] = "offset"; + defaults[0] = "1"; + add_test(window, "atk_text_get_text_after_offset", 1, paramnames, defaults); + add_test(window, "atk_text_get_text_before_offset", 1, paramnames, defaults); + add_test(window, "atk_text_get_text_at_offset",1 , paramnames, defaults); + + /* Get Character Count Test */ + add_test(window, "atk_text_get_character_count", 0, NULL, NULL); + + /* Get Character At Offset Test */ + paramnames[0] = "offset"; + defaults[0] = "1"; + add_test(window, "atk_text_get_character_at_offset", 1, paramnames, defaults); + + /* Get Text Test */ + paramnames[0] = "position 1"; + paramnames[1] = "position 2"; + defaults[0] = "0"; + defaults[1] = "5"; + add_test(window, "atk_text_get_text", 2, paramnames, defaults); + + /* Caret Tests */ + add_test(window, "atk_text_get_caret_offset", 0, NULL, NULL); + + paramnames[0] = "offset"; + defaults[0] = "1"; + add_test(window, "atk_text_set_caret_offset", 1, paramnames, defaults); + + /* Selection Tests */ + add_test(window, "atk_text_get_n_selections", 0, NULL, NULL); + + paramnames[0] = "selection no"; + defaults[0] = "0"; + add_test(window, "atk_text_get_selection", 1, paramnames, defaults); + + paramnames[0] = "start"; + paramnames[1] = "end"; + defaults[0] = "3"; + defaults[1] = "8"; + add_test(window, "atk_text_add_selection", 2, paramnames, defaults); + + paramnames[0] = "selection no"; + paramnames[1] = "start"; + paramnames[2] = "end"; + defaults[0] = "0"; + defaults[1] = "5"; + defaults[2] = "7"; + add_test(window, "atk_text_set_selection", 3, paramnames, defaults); + + paramnames[0] = "selection no"; + defaults[0] = "0"; + add_test(window, "atk_text_remove_selection", 1, paramnames, defaults); + + paramnames[0] = "offset"; + defaults[0] = "36"; + add_test(window, "atk_text_get_run_attributes", 1, paramnames, defaults); + + add_test(window, "atk_text_get_default_attributes", 0, paramnames, defaults); + + paramnames[0] = "offset"; + paramnames[1] = "coord mode"; + defaults[0] = "0"; + defaults[1] = "ATK_XY_SCREEN"; + add_test(window, "atk_text_get_character_extents", 2, paramnames, defaults); + + paramnames[0] = "x"; + paramnames[1] = "y"; + paramnames[2] = "coord mode"; + defaults[0] = "106"; + defaults[1] = "208"; + defaults[2] = "ATK_XY_SCREEN"; + add_test(window, "atk_text_get_offset_at_point", 3, paramnames, defaults); + + /* Editable Text Tests */ + if (ATK_IS_EDITABLE_TEXT(obj)) + { + + paramnames[0] = "start"; + paramnames[1] = "end"; + defaults[0] = "20"; + defaults[1] = "27"; + add_test(window, "atk_editable_text_set_run_attributes", 2, paramnames, defaults); + + paramnames[0] = "start"; + paramnames[1] = "end"; + defaults[0] = "3"; + defaults[1] = "5"; + add_test(window, "atk_editable_text_cut_text", 2, paramnames, defaults); + + paramnames[0] = "position"; + defaults[0] = "8"; + add_test(window, "atk_editable_text_paste_text", 1, paramnames, defaults); + + paramnames[0] = "start"; + paramnames[1] = "end"; + defaults[0] = "15"; + defaults[1] = "20"; + add_test(window, "atk_editable_text_delete_text", 2, paramnames, defaults); + paramnames[0] = "start"; + paramnames[1] = "end"; + defaults[0] = "5"; + defaults[1] = "20"; + add_test(window, "atk_editable_text_copy_text", 2, paramnames, defaults); + + paramnames[0] = "insert text"; + paramnames[1] = "position"; + defaults[0] = "this is my insert"; + defaults[1] = "15"; + add_test(window, "atk_editable_text_insert_text", 2, paramnames, defaults); + } + return window; +} + +/** + * add_handlers: + * @obj: An #AtkObject + * + * Sets up text signal handlers. + * + **/ +void add_handlers(AtkObject *obj) +{ + if (!already_accessed_atk_object(obj)) + { + /* Set up signal handlers */ + + g_print ("Adding signal handler\n"); + g_signal_connect_closure_by_id (obj, + g_signal_lookup ("text_caret_moved", G_OBJECT_TYPE (obj)), + 0, + g_cclosure_new (G_CALLBACK (_notify_caret_handler), + NULL, NULL), + FALSE); + + g_signal_connect_closure (obj, "text_changed::insert", + g_cclosure_new (G_CALLBACK (_notify_text_insert_handler), + NULL, NULL), + FALSE); + + g_signal_connect_closure (obj, "text_changed::delete", + g_cclosure_new (G_CALLBACK (_notify_text_delete_handler), + NULL, NULL), + FALSE); + } +} + +/** + * notify_text_insert_handler: + * @obj: A #Gobject + * @start_offset: Start offset of insert + * @end_offset: End offset of insert. + * + * Text inserted singal handler + **/ +void +_notify_text_insert_handler (GObject *obj, int start_offset, int end_offset) +{ + g_print ("SIGNAL - Text inserted at position %d, length %d!\n", + start_offset, end_offset); +} + +/** + * notify_text_delete_handler: + * @obj: A #Gobject + * @start_offset: Start offset of delete + * @end_offset: End offset of delete. + * + * Text deleted singal handler + **/ +void +_notify_text_delete_handler (GObject *obj, int start_offset, int end_offset) +{ + g_print ("SIGNAL - Text deleted at position %d, length %d!\n", + start_offset, end_offset); +} + +/** + * notify_caret_handler: + * @obj: A #Gobject + * @position: Caret position + * + * Caret (cursor) moved signal handler. + **/ +void +_notify_caret_handler (GObject *obj, int position) +{ + g_print ("SIGNAL - The caret moved to position %d!\n", position); +} + +/** + * runtest: + * @obj: An #AtkObject + * @win_val: The window number + * + * The callback to run when the "Run Tests" button on the + * Test GUI is clicked. + **/ +void +runtest(AtkObject *obj, gint win_val) +{ + gint i, size; + gunichar uni_char; + gchar output[MAX_LINE_SIZE]; + gchar **testsOn; + + testsOn = tests_set(win_val, &size); + + for(i = 0; i < size; i++) + { + gint param_int1, param_int2, start, end, j, x, y, height, width; + gchar *param_string1, *param_string2, *param_string3, *text; + gboolean result; + gint index; + + if (strcmp(testsOn[i], "atk_text_get_text_at_offset") == 0) + { + param_string1 = get_arg_of_func(win_val, "atk_text_get_text_at_offset", "offset"); + param_int1 = string_to_int(param_string1); + + _run_offset_test(obj, "at", param_int1, ATK_TEXT_BOUNDARY_WORD_END); + _run_offset_test(obj, "at", param_int1, ATK_TEXT_BOUNDARY_WORD_START); + _run_offset_test(obj, "at", param_int1, ATK_TEXT_BOUNDARY_LINE_END); + _run_offset_test(obj, "at", param_int1, ATK_TEXT_BOUNDARY_LINE_START); + _run_offset_test(obj, "at", param_int1, ATK_TEXT_BOUNDARY_SENTENCE_END); + _run_offset_test(obj, "at", param_int1, ATK_TEXT_BOUNDARY_SENTENCE_START); + _run_offset_test(obj, "at", param_int1, ATK_TEXT_BOUNDARY_CHAR); + } + + if (strcmp(testsOn[i], "atk_text_get_text_after_offset") == 0) + { + param_string1 = get_arg_of_func(win_val, "atk_text_get_text_after_offset", "offset"); + param_int1 = string_to_int(param_string1); + + _run_offset_test(obj, "after", param_int1, ATK_TEXT_BOUNDARY_WORD_END); + _run_offset_test(obj, "after", param_int1, ATK_TEXT_BOUNDARY_WORD_START); + _run_offset_test(obj, "after", param_int1, ATK_TEXT_BOUNDARY_LINE_END); + _run_offset_test(obj, "after", param_int1, ATK_TEXT_BOUNDARY_LINE_START); + _run_offset_test(obj, "after", param_int1, ATK_TEXT_BOUNDARY_SENTENCE_END); + _run_offset_test(obj, "after", param_int1, ATK_TEXT_BOUNDARY_SENTENCE_START); + _run_offset_test(obj, "after", param_int1, ATK_TEXT_BOUNDARY_CHAR); + } + + if (strcmp(testsOn[i], "atk_text_get_text_before_offset") == 0) + { + param_string1 = get_arg_of_func(win_val, "atk_text_get_text_before_offset", "offset"); + param_int1 = string_to_int(param_string1); + + _run_offset_test(obj, "before", param_int1, ATK_TEXT_BOUNDARY_WORD_END); + _run_offset_test(obj, "before", param_int1, ATK_TEXT_BOUNDARY_WORD_START); + _run_offset_test(obj, "before", param_int1, ATK_TEXT_BOUNDARY_LINE_END); + _run_offset_test(obj, "before", param_int1, ATK_TEXT_BOUNDARY_LINE_START); + _run_offset_test(obj, "before", param_int1, ATK_TEXT_BOUNDARY_SENTENCE_END); + _run_offset_test(obj, "before", param_int1, ATK_TEXT_BOUNDARY_SENTENCE_START); + _run_offset_test(obj, "before", param_int1, ATK_TEXT_BOUNDARY_CHAR); + } + + if (strcmp(testsOn[i], "atk_text_get_character_count") == 0) + { + param_int1 = atk_text_get_character_count (ATK_TEXT (obj)); + sprintf(output, "\nText character count: %d\n", param_int1); + set_output_buffer(output); + } + + if (strcmp(testsOn[i], "atk_text_get_character_at_offset") == 0) + { + param_string1 = get_arg_of_func(win_val, "atk_text_get_character_at_offset", + "offset"); + uni_char = atk_text_get_character_at_offset (ATK_TEXT(obj), + string_to_int(param_string1)); + sprintf(output, "\nCharacter at offset %d: |%x|\n", + string_to_int(param_string1), uni_char); + set_output_buffer(output); + } + + if (strcmp(testsOn[i], "atk_text_get_text") == 0) + { + param_string1 = get_arg_of_func(win_val, "atk_text_get_text", "position 1"); + param_string2 = get_arg_of_func(win_val, "atk_text_get_text", "position 2"); + text = atk_text_get_text (ATK_TEXT (obj), string_to_int(param_string1), + string_to_int(param_string2)); + sprintf(output, "\nText %d, %d: %s\n", string_to_int(param_string1), + string_to_int(param_string2), text); + g_free (text); + set_output_buffer(output); + } + + if (strcmp(testsOn[i], "atk_text_get_caret_offset") == 0) + { + param_int1 = atk_text_get_caret_offset (ATK_TEXT (obj)); + if (param_int1 == -1) + sprintf(output, "\nCaret offset: |Not Supported|\n"); + else + sprintf(output, "\nCaret offset: %d\n", param_int1); + set_output_buffer(output); + } + + if (strcmp(testsOn[i], "atk_text_set_caret_offset") == 0) + { + param_string1 = get_arg_of_func(win_val, "atk_text_set_caret_offset", "offset"); + atk_text_set_caret_offset(ATK_TEXT(obj), string_to_int(param_string1)); + sprintf(output, "\nPutting caret at offset: |%d|\n", + string_to_int(param_string1)); + param_int1 = atk_text_get_caret_offset (ATK_TEXT (obj)); + + if (param_int1 == -1) + sprintf(output, "\nCaret offset: |Not Supported|\n"); + else + sprintf(output, "\nCaret offset was set at: |%d|\n", param_int1); + + set_output_buffer(output); + } + + if (strcmp(testsOn[i], "atk_text_get_n_selections") == 0) + { + param_int1 = atk_text_get_n_selections(ATK_TEXT(obj)); + if (param_int1 == -1) + { + sprintf(output, "\nNo selected regions\n"); + set_output_buffer(output); + } + + for (j = 0; j < param_int1; j++) + { + sprintf(output, "\nNumber of selected text regions is: |%d|\n", j); + set_output_buffer(output); + + text = atk_text_get_selection(ATK_TEXT(obj), j, &start, &end); + if (text != NULL) + { + sprintf(output, "\nSelected text for region %d is: |%s|\n", j, text); + set_output_buffer(output); + sprintf(output, + "\nStart selection bounds: %d\tEnd selection bounds: %d\n", + start, end); + } + else + { + sprintf(output, "\nNo selected region %d\n", j); + } + + set_output_buffer(output); + } + } + + if (strcmp(testsOn[i], "atk_text_add_selection") == 0) + { + param_string1 = get_arg_of_func(win_val, "atk_text_add_selection", "start"); + param_string2 = get_arg_of_func(win_val, "atk_text_add_selection", "end"); + result = atk_text_add_selection(ATK_TEXT(obj), + string_to_int(param_string1), string_to_int(param_string2)); + sprintf(output, "\nSet selection bounds between %d, and %d: %s", + string_to_int(param_string1), string_to_int(param_string2), + result_string[result]); + set_output_buffer(output); + + param_int1 = atk_text_get_n_selections(ATK_TEXT(obj)); + for (j = 0; j < param_int1; j++) + { + sprintf(output, "\nNumber of selected text region is: %d\n", j); + set_output_buffer(output); + text = atk_text_get_selection(ATK_TEXT(obj), j, &start, &end); + + if (text != NULL) + { + sprintf(output, "\nSelected text for region %d is: |%s|\n", j, text); + set_output_buffer(output); + sprintf(output, + "\nStart selection bounds: %d\tEnd selection bounds: %d\n", + start, end); + } + else + { + sprintf(output, "\nNo selected region %d\n", j); + } + + set_output_buffer(output); + } + } + + if (strcmp(testsOn[i], "atk_text_get_selection") == 0) + { + param_string1 = get_arg_of_func(win_val, "atk_text_get_selection", "selection no"); + text = atk_text_get_selection(ATK_TEXT(obj), + string_to_int(param_string1), &start, &end); + + if (text != NULL) + { + sprintf(output, "\nSelected text for region %d is: |%s|\n", + string_to_int(param_string1), text); + set_output_buffer(output); + sprintf(output, + "\nStart selection bounds: %d\t End selection bounds: %d\n", + start, end); + } + else + { + sprintf(output, "\nNo selected region %d\n", string_to_int(param_string1)); + } + + set_output_buffer(output); + } + + if (strcmp(testsOn[i], "atk_text_set_selection") == 0) + { + param_string1 = get_arg_of_func(win_val, "atk_text_set_selection", "selection no"); + param_string2 = get_arg_of_func(win_val, "atk_text_set_selection", "start"); + param_string3 = get_arg_of_func(win_val, "atk_text_set_selection", "end"); + result = atk_text_set_selection(ATK_TEXT(obj), string_to_int(param_string1), + string_to_int(param_string2), string_to_int(param_string3)); + sprintf(output, "Set selection %d's bounds between %d and %d: %s\n", + string_to_int(param_string1), string_to_int(param_string2), + string_to_int(param_string3), result_string[result]); + set_output_buffer(output); + text = atk_text_get_selection(ATK_TEXT(obj), string_to_int(param_string1), + &start, &end); + + if (text != NULL) + { + sprintf(output, "Selected text for the reset region %d is: |%s|\n", + string_to_int(param_string1), text); + set_output_buffer(output); + sprintf(output, + "\nNew start selection bounds: %d\tNew end selection bounds: %d\n", + start, end); + } + else + { + sprintf(output, "\nNo selected region %d\n", string_to_int(param_string1)); + } + + set_output_buffer(output); + } + + if (strcmp(testsOn[i], "atk_text_remove_selection") == 0) + { + param_string1 = get_arg_of_func(win_val, "atk_text_remove_selection", "selection no"); + result = atk_text_remove_selection(ATK_TEXT(obj), string_to_int(param_string1)); + sprintf(output, "Remove selection for region %d: %s\n", + string_to_int(param_string1), result_string[result]); + set_output_buffer(output); + text = atk_text_get_selection(ATK_TEXT(obj), + string_to_int(param_string1), &start, &end); + + if (text != NULL) + sprintf(output, "\nRemoved regions text should be empty instead of: %s", text); + else + sprintf(output, "\nRemoved regions text should be empty, this is: ||"); + + set_output_buffer(output); + } + + if (strcmp(testsOn[i], "atk_text_get_run_attributes") == 0) + { + gint test_int; + param_string1 = get_arg_of_func(win_val, "atk_text_get_run_attributes", "offset"); + test_int = string_to_int(param_string1); + attrib = atk_text_get_run_attributes(ATK_TEXT(obj), test_int, &start, &end); + sprintf(output, "get_run_attributes at offset %i:\nStart: %i, End: %i\n", test_int, + start, end); + set_output_buffer(output); + if (attrib != NULL) { + GSList *node; + index = 0; + node = attrib; + while (node != NULL) + { + AtkAttribute* att = node->data; + + sprintf(output, "List index: %i, Name: %s, Value: %s\n", index, + att->name, att->value); + set_output_buffer(output); + node = node->next; + index++; + } + atk_attribute_set_free (attrib); + } + } + + if (strcmp(testsOn[i], "atk_text_get_default_attributes") == 0) + { + attrib = atk_text_get_default_attributes(ATK_TEXT(obj)); + sprintf(output, "get_default_attributes\n"); + set_output_buffer(output); + if (attrib != NULL) { + GSList *node; + index = 0; + node = attrib; + while (node != NULL) + { + AtkAttribute* att = node->data; + + sprintf(output, "List index: %i, Name: %s, Value: %s\n", index, + att->name, att->value); + set_output_buffer(output); + node = node->next; + index++; + } + atk_attribute_set_free (attrib); + } + } + + if (strcmp(testsOn[i], "atk_text_get_character_extents") == 0) + { + gint test_int; + param_string1 = get_arg_of_func(win_val, "atk_text_get_character_extents", + "offset"); + param_string2 = get_arg_of_func(win_val, "atk_text_get_character_extents", + "coord mode"); + test_int = string_to_int(param_string1); + if (strcmp(param_string2, "ATK_XY_SCREEN") == 0) + { + atk_text_get_character_extents(ATK_TEXT(obj), test_int, &x, &y, &width, + &height, ATK_XY_SCREEN); + sprintf(output, + "get_character_extents at offset %i, mode: SCREEN\nX: %i, Y: %i, width: %i, height: %i\n", + test_int, x, y, width, height); + } + else if (strcmp(param_string2, "ATK_XY_WINDOW") == 0) + { + atk_text_get_character_extents(ATK_TEXT(obj), test_int, &x, &y, &width, + &height, ATK_XY_WINDOW); + sprintf(output, + "get_character_extents at offset %i, mode: WIDGET_WINDOW\nX: %i, Y: %i, width: %i, height: %i\n", + test_int, x, y, width, height); + } + else + sprintf(output, "get_character_extents_at_offset: Invalid coord mode argument!"); + + set_output_buffer(output); + } + + if (strcmp(testsOn[i], "atk_text_get_offset_at_point") == 0) + { + gint test_int; + param_string1 = get_arg_of_func(win_val, "atk_text_get_offset_at_point", "x"); + param_string2 = get_arg_of_func(win_val, "atk_text_get_offset_at_point", "y"); + param_string3 = get_arg_of_func(win_val, "atk_text_get_offset_at_point", "coord mode"); + param_int1 = string_to_int(param_string1); + param_int2 = string_to_int(param_string2); + if (strcmp(param_string3, "ATK_XY_SCREEN") == 0) + { + test_int = atk_text_get_offset_at_point(ATK_TEXT(obj), param_int1, param_int2, + ATK_XY_SCREEN); + if (test_int != -1) + sprintf(output, "get_offset_at_point %i,%i mode: SCREEN is %i\n", param_int1, param_int2, test_int); + else + sprintf(output, "Cannot get_offset_at_point\n"); + } + else if (strcmp(param_string3, "ATK_XY_WINDOW") == 0) + { + test_int = atk_text_get_offset_at_point(ATK_TEXT(obj), param_int1, param_int2, + ATK_XY_WINDOW); + if (test_int != -1) + sprintf(output, "get_offset_at_point %i,%i mode: WIDGET_WINDOW is %i\n", param_int1, param_int2, test_int); + else + sprintf(output, "Cannot get_offset_at_point\n"); + } + else + sprintf(output, "get_offset_at_point: Invalid coord mode argument!"); + + set_output_buffer(output); + } + if (ATK_IS_EDITABLE_TEXT(obj)) + { + if (strcmp(testsOn[i], "atk_editable_text_set_run_attributes") == 0) + { + param_string1 = get_arg_of_func(win_val, + "atk_editable_text_set_run_attributes", "start"); + param_string2 = get_arg_of_func(win_val, + "atk_editable_text_set_run_attributes", "end"); + result = atk_editable_text_set_run_attributes(ATK_EDITABLE_TEXT(obj), + attrib, string_to_int(param_string1), string_to_int(param_string2)); + if (result) + sprintf(output, "\nSetting attributes in range %d to %d...OK\n", + string_to_int(param_string1), string_to_int(param_string2)); + else + sprintf(output, "\nSetting attributes in range %d to %d...Failed\n", + string_to_int(param_string1), string_to_int(param_string2)); + set_output_buffer(output); + } + + if (strcmp(testsOn[i], "atk_editable_text_cut_text") == 0) + { + param_string1 = get_arg_of_func(win_val, "atk_editable_text_cut_text", "start"); + param_string2 = get_arg_of_func(win_val, "atk_editable_text_cut_text", "end"); + atk_editable_text_cut_text(ATK_EDITABLE_TEXT(obj), + string_to_int(param_string1), string_to_int(param_string2)); + sprintf(output, "\nCutting text %d to %d...\n", + string_to_int(param_string1), string_to_int(param_string2)); + set_output_buffer(output); + } + + if (strcmp(testsOn[i], "atk_editable_text_paste_text") == 0) + { + param_string1 = get_arg_of_func(win_val, "atk_editable_text_paste_text", + "position"); + atk_editable_text_paste_text(ATK_EDITABLE_TEXT(obj), + string_to_int(param_string1)); + sprintf(output, "\nPasting text to %d\n", string_to_int(param_string1)); + set_output_buffer(output); + } + + if (strcmp(testsOn[i], "atk_editable_text_delete_text") == 0) + { + param_string1 = get_arg_of_func(win_val, "atk_editable_text_delete_text", "start"); + param_string2 = get_arg_of_func(win_val, "atk_editable_text_delete_text", "end"); + atk_editable_text_delete_text(ATK_EDITABLE_TEXT(obj), + string_to_int(param_string1), string_to_int(param_string2)); + sprintf(output, "\nDeleting text %d to %d...\n", + string_to_int(param_string1), string_to_int(param_string2)); + set_output_buffer(output); + } + + if (strcmp(testsOn[i], "atk_editable_text_copy_text") == 0) + { + param_string1 = get_arg_of_func(win_val, "atk_editable_text_copy_text", "start"); + param_string2 = get_arg_of_func(win_val, "atk_editable_text_copy_text", "end"); + atk_editable_text_copy_text(ATK_EDITABLE_TEXT(obj), + string_to_int(param_string1), string_to_int(param_string2)); + sprintf(output, "\nCopying text %d to %d...\n", + string_to_int(param_string1), string_to_int(param_string2)); + set_output_buffer(output); + } + + if (strcmp(testsOn[i], "atk_editable_text_insert_text") == 0) + { + param_string1 = get_arg_of_func(win_val, "atk_editable_text_insert_text", + "insert text"); + param_string2 = get_arg_of_func(win_val, "atk_editable_text_insert_text", + "position"); + param_int2 = string_to_int(param_string2); + atk_editable_text_insert_text(ATK_EDITABLE_TEXT(obj), + param_string1, strlen(param_string1), ¶m_int2); + sprintf(output, "\nInserting text at %d...\n", param_int2); + set_output_buffer(output); + } + } + } +} + +/** + * _run_offset_test: + * @obj: An #AtkObject + * @type: The type of test to run. Can be "at", "before", or "after". + * @offset: The offset into the text buffer. + * @boundary: The boundary type. + * + * Tests the following ATK_TEXT API functions: + * atk_text_get_text_at_offset + * atk_text_get_text_before_offseet + * atk_text_get_text_after_offset + **/ +void _run_offset_test(AtkObject * obj, char * type, gint offset, + AtkTextBoundary boundary) +{ + gchar output[MAX_LINE_SIZE]; + gchar default_val[5] = "NULL"; + gchar *text; + gint startOffset, endOffset; + + if (strcmp(type, "at") == 0) + text = atk_text_get_text_at_offset (ATK_TEXT (obj), + offset, boundary, &startOffset, &endOffset); + else if (strcmp(type, "before") == 0) + text = atk_text_get_text_before_offset (ATK_TEXT (obj), + offset, boundary, &startOffset, &endOffset); + else if (strcmp(type, "after") == 0) + text = atk_text_get_text_after_offset (ATK_TEXT (obj), + offset, boundary, &startOffset, &endOffset); + else + text = NULL; + + if (text == NULL) + text = g_strdup (default_val); + + if (boundary == ATK_TEXT_BOUNDARY_CHAR) + sprintf(output, "\n|%s| Text |%s| Boundary |BOUNDARY_CHAR|\n", + type, text); + else if (boundary == ATK_TEXT_BOUNDARY_WORD_START) + sprintf(output, "\n|%s| Text |%s| Boundary |BOUNDARY_WORD_START|\n", + type, text); + else if (boundary == ATK_TEXT_BOUNDARY_WORD_END) + sprintf(output, "\n|%s| Text |%s| Boundary |BOUNDARY_WORD_END|\n", + type, text); + else if (boundary == ATK_TEXT_BOUNDARY_SENTENCE_START) + sprintf(output, "\n|%s| Text |%s| Boundary |BOUNDARY_SENTENCE_START|\n", + type, text); + else if (boundary == ATK_TEXT_BOUNDARY_SENTENCE_END) + sprintf(output, "\n|%s| Text |%s| Boundary |BOUNDARY_SENTENCE_END|\n", + type, text); + else if (boundary == ATK_TEXT_BOUNDARY_LINE_START) + sprintf(output, "\n|%s| Text |%s| Boundary |BOUNDARY_LINE_START|\n", + type, text); + else if (boundary == ATK_TEXT_BOUNDARY_LINE_END) + sprintf(output, "\n|%s| Text |%s| Boundary |BOUNDARY_LINE_END|\n", + type, text); + else + sprintf(output, "\n|%s| Text |%s| Boundary |UNKNOWN|\n", + type, text); + + g_free (text); + set_output_buffer(output); + + sprintf(output, "Offset %d, startOffset %d, endOffset %d\n", + offset, startOffset, endOffset); + set_output_buffer(output); +} diff --git a/modules/other/gail/tests/testtextlib.h b/modules/other/gail/tests/testtextlib.h new file mode 100644 index 0000000000..d135c2205d --- /dev/null +++ b/modules/other/gail/tests/testtextlib.h @@ -0,0 +1,15 @@ +#include +#include +#include +#include "testlib.h" + +void add_handlers (AtkObject *obj); +gint setup_gui (AtkObject *obj, TLruntest test); +void runtest(AtkObject *obj, gint win_num); +void _run_offset_test(AtkObject *obj, char * type, gint param_int1, AtkTextBoundary boundary); +void _notify_caret_handler (GObject *obj, int position); +void _notify_text_insert_handler (GObject *obj, + int start_offset, int end_offset); +void _notify_text_delete_handler (GObject *obj, + int start_offset, int end_offset); + diff --git a/modules/other/gail/tests/testtoplevel.c b/modules/other/gail/tests/testtoplevel.c new file mode 100644 index 0000000000..fa27833dd7 --- /dev/null +++ b/modules/other/gail/tests/testtoplevel.c @@ -0,0 +1,128 @@ +#include +#include +#include +#include "testlib.h" + +static void _notify_toplevel_child_added (GObject *obj, + guint index, AtkObject *child, gpointer user_data); +static void _notify_toplevel_child_removed (GObject *obj, + guint index, AtkObject *child, gpointer user_data); +static gboolean _button_press_event_watcher (GSignalInvocationHint *ihint, + guint n_param_values, const GValue *param_values, gpointer data); + +static guint id; +static gboolean g_register_listener = FALSE; +static guint g_signal_listener = 0; +static gint g_press_count = 0; + +static void +_check_toplevel (AtkObject *obj) +{ + AtkObject *root_obj; + const gchar *name_string, *version_string; + gint max_depth; + + g_print ("Start of _check_toplevel\n"); + root_obj = atk_get_root(); + + if (!already_accessed_atk_object(root_obj)) + { + g_signal_connect_closure (root_obj, "children_changed::add", + g_cclosure_new (G_CALLBACK (_notify_toplevel_child_added), + NULL, NULL), + FALSE); + + g_signal_connect_closure (root_obj, "children_changed::remove", + g_cclosure_new (G_CALLBACK (_notify_toplevel_child_removed), + NULL, NULL), + FALSE); + } + + name_string = atk_get_toolkit_name(); + version_string = atk_get_toolkit_version(); + g_print ("Toolkit name <%s> version <%s>\n", name_string, + version_string); + + if (g_getenv("TEST_ACCESSIBLE_DEPTH") != NULL) + max_depth = string_to_int(g_getenv("TEST_ACCESSIBLE_DEPTH")); + else + max_depth = 2; + + display_children_to_depth(root_obj, max_depth, 0, 0); + g_print ("End of _check_toplevel\n"); + + if (!g_register_listener) + { + g_print("Adding global event listener on buttons\n"); + g_register_listener = TRUE; + g_signal_listener = atk_add_global_event_listener(_button_press_event_watcher, + "Gtk:GtkButton:pressed"); + } +} + +static void +_create_event_watcher (void) +{ + id = atk_add_focus_tracker (_check_toplevel); +} + +int +gtk_module_init(gint argc, char* argv[]) +{ + g_print("testtoplevel Module loaded\n"); + + _create_event_watcher(); + + return 0; +} + +static void _notify_toplevel_child_added (GObject *obj, + guint child_index, AtkObject *child, gpointer user_data) +{ + g_print ("SIGNAL - Child added - index %d\n", child_index); +} + +static void _notify_toplevel_child_removed (GObject *obj, + guint child_index, AtkObject *child, gpointer user_data) +{ + g_print ("SIGNAL - Child removed - index %d\n", child_index); +} + +static gboolean +_button_press_event_watcher (GSignalInvocationHint *ihint, + guint n_param_values, + const GValue *param_values, + gpointer data) +{ + GObject *object; + gchar * button_name = (gchar *) data; + + object = g_value_get_object (param_values + 0); + + if (ATK_IS_IMPLEMENTOR(object)) + { + AtkObject * atk_obj = + atk_implementor_ref_accessible(ATK_IMPLEMENTOR(object)); + + g_print("Button <%s> pressed %d times!\n", button_name, + (g_press_count + 1)); + g_print("Displaying children of Button pressed!\n"); + display_children(atk_obj, 0, 0); + + if (g_press_count >= 5) + { + g_print("Removing global event listener on buttons\n"); + atk_remove_global_event_listener(g_signal_listener); + g_signal_listener = 0; + g_press_count = 0; + g_register_listener = FALSE; + } + else + { + g_press_count++; + } + } + + return TRUE; +} + diff --git a/modules/other/gail/tests/testtreetable.c b/modules/other/gail/tests/testtreetable.c new file mode 100644 index 0000000000..6ff492532b --- /dev/null +++ b/modules/other/gail/tests/testtreetable.c @@ -0,0 +1,499 @@ +#include +#include + +/* + * This module is for use with the test program testtreeview + */ +static gboolean state_change_watch (GSignalInvocationHint *ihint, + guint n_param_values, + const GValue *param_values, + gpointer data); + +static void _check_table (AtkObject *in_obj); +static void _check_cell_actions (AtkObject *in_obj); + +static gint _find_expander_column (AtkTable *table); +static void _check_expanders (AtkTable *table, + gint expander_column); +static void _runtest (AtkObject *obj); +static void _create_event_watcher (void); +static void row_inserted (AtkObject *obj, + gint row, + gint count); +static void row_deleted (AtkObject *obj, + gint row, + gint count); +static AtkObject *table_obj = NULL; +static gint expander_column = -1; +static gboolean editing_cell = FALSE; + +static gboolean +state_change_watch (GSignalInvocationHint *ihint, + guint n_param_values, + const GValue *param_values, + gpointer data) +{ + GObject *object; + gboolean state_set; + G_CONST_RETURN gchar *state_name; + AtkStateType state_type; + + object = g_value_get_object (param_values + 0); + g_return_val_if_fail (ATK_IS_OBJECT (object), FALSE); + + state_name = g_value_get_string (param_values + 1); + state_set = g_value_get_boolean (param_values + 2); + + g_print ("Object type: %s state: %s set: %d\n", + g_type_name (G_OBJECT_TYPE (object)), state_name, state_set); + state_type = atk_state_type_for_name (state_name); + if (state_type == ATK_STATE_EXPANDED) + { + AtkObject *parent = atk_object_get_parent (ATK_OBJECT (object)); + + if (ATK_IS_TABLE (parent)) + _check_expanders (ATK_TABLE (parent), expander_column); + } + return TRUE; +} + +static void +_check_table (AtkObject *in_obj) +{ + AtkObject *obj; + AtkRole role[2]; + AtkRole obj_role; + static gboolean emission_hook_added = FALSE; + + if (!emission_hook_added) + { + emission_hook_added = TRUE; + g_signal_add_emission_hook ( + g_signal_lookup ("state-change", ATK_TYPE_OBJECT), + /* + * To specify an emission hook for a particular state, e.g. + * ATK_STATE_EXPANDED, instead of 0 use + * g_quark_from_string (atk_state_type_get_name (ATK_STATE_EXPANDED)) + */ + 0, + state_change_watch, NULL, (GDestroyNotify) NULL); + } + + role[0] = ATK_ROLE_TABLE; + role[1] = ATK_ROLE_TREE_TABLE; + + g_print ("focus event for: %s\n", g_type_name (G_OBJECT_TYPE (in_obj))); + + _check_cell_actions (in_obj); + + obj_role = atk_object_get_role (in_obj); + if (obj_role == ATK_ROLE_TABLE_CELL) + obj = atk_object_get_parent (in_obj); + else + obj = find_object_by_role (in_obj, role, 2); + if (obj == NULL) + return; + + editing_cell = FALSE; + + if (obj != table_obj) + { + table_obj = obj; + g_print("Found %s table\n", g_type_name (G_OBJECT_TYPE (obj))); + g_signal_connect (G_OBJECT (obj), + "row_inserted", + G_CALLBACK (row_inserted), + NULL); + g_signal_connect (G_OBJECT (obj), + "row_deleted", + G_CALLBACK (row_deleted), + NULL); + /* + * Find expander column + */ + if (ATK_IS_TABLE (obj)) + { + if (atk_object_get_role (obj) == ATK_ROLE_TREE_TABLE) + { + expander_column = _find_expander_column (ATK_TABLE (obj)); + if (expander_column == -1) + { + g_warning ("Expander column not found\n"); + return; + } + } + _runtest(obj); + } + else + g_warning ("Table does not support AtkTable interface\n"); + } + else + { + /* + * We do not call these functions at the same time as we set the + * signals as the GtkTreeView may not be displayed yet. + */ + gint x, y, width, height, first_x, last_x, last_y; + gint first_row, last_row, first_column, last_column; + gint index; + AtkObject *first_child, *last_child, *header; + AtkComponent *component = ATK_COMPONENT (obj); + AtkTable *table = ATK_TABLE (obj); + + atk_component_get_extents (component, + &x, &y, &width, &height, ATK_XY_WINDOW); + g_print ("WINDOW: x: %d y: %d width: %d height: %d\n", + x, y, width, height); + atk_component_get_extents (component, + &x, &y, &width, &height, ATK_XY_SCREEN); + g_print ("SCREEN: x: %d y: %d width: %d height: %d\n", + x, y, width, height); + last_x = x + width - 1; + last_y = y + height - 1; + first_x = x; + header = atk_table_get_column_header (table, 0); + if (header) + { + atk_component_get_extents (ATK_COMPONENT (header), + &x, &y, &width, &height, ATK_XY_SCREEN); + g_print ("Got column header: x: %d y: %d width: %d height: %d\n", + x, y, width, height); + y += height; + } + first_child = atk_component_ref_accessible_at_point (component, + first_x, y, ATK_XY_SCREEN); + atk_component_get_extents (ATK_COMPONENT (first_child), + &x, &y, &width, &height, ATK_XY_SCREEN); + g_print ("first_child: x: %d y: %d width: %d height: %d\n", + x, y, width, height); + index = atk_object_get_index_in_parent (ATK_OBJECT (first_child)); + first_row = atk_table_get_row_at_index (table, index); + first_column = atk_table_get_column_at_index (table, index); + g_print ("first_row: %d first_column: %d index: %d\n", + first_row, first_column, index); + g_assert (index == atk_table_get_index_at (table, first_row, first_column)); + last_child = atk_component_ref_accessible_at_point (component, + last_x, last_y, ATK_XY_SCREEN); + if (last_child == NULL) + { + /* The TreeView may be bigger than the data */ + gint n_children; + + n_children = atk_object_get_n_accessible_children (obj); + last_child = atk_object_ref_accessible_child (obj, n_children - 1); + } + atk_component_get_extents (ATK_COMPONENT (last_child), + &x, &y, &width, &height, ATK_XY_SCREEN); + g_print ("last_child: x: %d y: %d width: %d height: %d\n", + x, y, width, height); + index = atk_object_get_index_in_parent (ATK_OBJECT (last_child)); + last_row = atk_table_get_row_at_index (table, index); + last_column = atk_table_get_column_at_index (table, index); + g_print ("last_row: %d last_column: %d index: %d\n", + last_row, last_column, index); + g_assert (index == atk_table_get_index_at (table, last_row, last_column)); + g_object_unref (first_child); + g_object_unref (last_child); + + if (expander_column >= 0) + { + gint n_rows, i; + gint x, y, width, height; + + n_rows = atk_table_get_n_rows (table); + for (i = 0; i < n_rows; i++) + { + AtkObject *child_obj; + AtkStateSet *state_set; + gboolean showing; + + child_obj = atk_table_ref_at (table, i, expander_column); + state_set = atk_object_ref_state_set (child_obj); + showing = atk_state_set_contains_state (state_set, + ATK_STATE_SHOWING); + g_object_unref (state_set); + atk_component_get_extents (ATK_COMPONENT (child_obj), + &x, &y, &width, &height, + ATK_XY_SCREEN); + g_object_unref (child_obj); + if (showing) + g_print ("Row: %d Column: %d x: %d y: %d width: %d height: %d\n", + i, expander_column, x, y, width, height); + } + } + } +} + +static void +_check_cell_actions (AtkObject *in_obj) +{ + AtkRole role; + AtkAction *action; + gint n_actions, i; + + role = atk_object_get_role (in_obj); + if (role != ATK_ROLE_TABLE_CELL) + return; + + if (!ATK_IS_ACTION (in_obj)) + return; + + if (editing_cell) + return; + + action = ATK_ACTION (in_obj); + + n_actions = atk_action_get_n_actions (action); + + for (i = 0; i < n_actions; i++) + { + G_CONST_RETURN gchar* name; + + name = atk_action_get_name (action, i); + g_print ("Action %d is %s\n", i, name); +#if 0 + if (strcmp (name, "edit") == 0) + { + editing_cell = TRUE; + atk_action_do_action (action, i); + } +#endif + } + return; +} + +static gint +_find_expander_column (AtkTable *table) +{ + gint n_columns, i; + gint retval = -1; + + n_columns = atk_table_get_n_columns (table); + for (i = 0; i < n_columns; i++) + { + AtkObject *cell; + AtkRelationSet *relation_set; + + cell = atk_table_ref_at (table, 0, i); + relation_set = atk_object_ref_relation_set (cell); + if (atk_relation_set_contains (relation_set, + ATK_RELATION_NODE_CHILD_OF)) + retval = i; + g_object_unref (relation_set); + g_object_unref (cell); + if (retval >= 0) + break; + } + return retval; +} + +static void +_check_expanders (AtkTable *table, + gint expander_column) +{ + gint n_rows, i; + + n_rows = atk_table_get_n_rows (table); + + for (i = 0; i < n_rows; i++) + { + AtkObject *cell; + AtkRelationSet *relation_set; + AtkRelation *relation; + GPtrArray *target; + gint j; + + cell = atk_table_ref_at (table, i, expander_column); + + relation_set = atk_object_ref_relation_set (cell); + relation = atk_relation_set_get_relation_by_type (relation_set, + ATK_RELATION_NODE_CHILD_OF); + g_assert (relation); + target = atk_relation_get_target (relation); + g_assert (target->len == 1); + for (j = 0; j < target->len; j++) + { + AtkObject *target_obj; + AtkRole role; + gint target_index, target_row; + + target_obj = g_ptr_array_index (target, j); + role = atk_object_get_role (target_obj); + + switch (role) + { + case ATK_ROLE_TREE_TABLE: + g_print ("Row %d is top level\n", i); + break; + case ATK_ROLE_TABLE_CELL: + target_index = atk_object_get_index_in_parent (target_obj); + target_row = atk_table_get_row_at_index (table, target_index); + g_print ("Row %d has parent at %d\n", i, target_row); + break; + default: + g_assert_not_reached (); + } + } + g_object_unref (relation_set); + g_object_unref (cell); + } +} + +static void +_create_event_watcher (void) +{ + atk_add_focus_tracker (_check_table); +} + +int +gtk_module_init (gint argc, + char *argv[]) +{ + g_print ("testtreetable Module loaded\n"); + + _create_event_watcher (); + + return 0; +} + +static void +_runtest (AtkObject *obj) +{ + AtkObject *child_obj; + AtkTable *table; + AtkObject *caption; + gint i; + gint n_cols, n_rows, n_children; + + table = ATK_TABLE (obj); + n_children = atk_object_get_n_accessible_children (ATK_OBJECT (obj)); + n_cols = atk_table_get_n_columns (table); + n_rows = atk_table_get_n_rows (table); + g_print ("n_children: %d n_rows: %d n_cols: %d\n", + n_children, n_rows, n_cols); + + for (i = 0; i < n_rows; i++) + { + gint index = atk_table_get_index_at (table, i, expander_column); + gint index_in_parent; + + child_obj = atk_table_ref_at (table, i, expander_column); + index_in_parent = atk_object_get_index_in_parent (child_obj); + g_print ("index: %d %d row %d column %d\n", index, index_in_parent, i, expander_column); + + g_object_unref (child_obj); + } + caption = atk_table_get_caption (table); + if (caption) + { + const gchar *caption_name = atk_object_get_name (caption); + + g_print ("Caption: %s\n", caption_name ? caption_name : ""); + } + for (i = 0; i < n_cols; i++) + { + AtkObject *header; + + header = atk_table_get_column_header (table, i); + g_print ("Header for column %d is %p\n", i, header); + if (header) + { + const gchar *name; + AtkRole role; + AtkObject *parent; + AtkObject *child; + gint index; + + name = atk_object_get_name (header); + role = atk_object_get_role (header); + parent = atk_object_get_parent (header); + + if (parent) + { + index = atk_object_get_index_in_parent (header); + g_print ("Parent: %s index: %d\n", G_OBJECT_TYPE_NAME (parent), index); + child = atk_object_ref_accessible_child (parent, 0); + g_print ("Child: %s %p\n", G_OBJECT_TYPE_NAME (child), child); + if (index >= 0) + { + child = atk_object_ref_accessible_child (parent, index); + g_print ("Index: %d child: %s\n", index, G_OBJECT_TYPE_NAME (child)); + g_object_unref (child); + } + } + else + g_print ("Parent of header is NULL\n"); + g_print ("%s %s %s\n", G_OBJECT_TYPE_NAME (header), name ? name: "", atk_role_get_name (role)); + } + } +} + +static void +row_inserted (AtkObject *obj, + gint row, + gint count) +{ +#if 0 + GtkWidget *widget; + GtkTreeView *tree_view; + GtkTreeModel *tree_model; +#endif + gint index; + + g_print ("row_inserted: row: %d count: %d\n", row, count); + index = atk_table_get_index_at (ATK_TABLE (obj), row+1, 0); + g_print ("index for first column of next row is %d\n", index); + +#if 0 + widget = GTK_ACCESSIBLE (obj)->widget; + tree_view = GTK_TREE_VIEW (widget); + tree_model = gtk_tree_view_get_model (tree_view); + if (GTK_IS_TREE_STORE (tree_model)) + { + GtkTreeStore *tree_store; + GtkTreePath *tree_path; + GtkTreeIter tree_iter; + + tree_store = GTK_TREE_STORE (tree_model); + tree_path = gtk_tree_path_new_from_string ("3:0"); + gtk_tree_model_get_iter (tree_model, &tree_iter, tree_path); + gtk_tree_path_free (tree_path); + gtk_tree_store_remove (tree_store, &tree_iter); + } +#endif +} + +static void +row_deleted (AtkObject *obj, + gint row, + gint count) +{ +#if 0 + GtkWidget *widget; + GtkTreeView *tree_view; + GtkTreeModel *tree_model; +#endif + gint index; + + g_print ("row_deleted: row: %d count: %d\n", row, count); + index = atk_table_get_index_at (ATK_TABLE (obj), row+1, 0); + g_print ("index for first column of next row is %d\n", index); + +#if 0 + widget = GTK_ACCESSIBLE (obj)->widget; + tree_view = GTK_TREE_VIEW (widget); + tree_model = gtk_tree_view_get_model (tree_view); + if (GTK_IS_TREE_STORE (tree_model)) + { + GtkTreeStore *tree_store; + GtkTreePath *tree_path; + GtkTreeIter tree_iter, new_iter; + + tree_store = GTK_TREE_STORE (tree_model); + tree_path = gtk_tree_path_new_from_string ("2"); + gtk_tree_model_get_iter (tree_model, &tree_iter, tree_path); + gtk_tree_path_free (tree_path); + gtk_tree_store_insert_before (tree_store, &new_iter, NULL, &tree_iter); + } +#endif +} diff --git a/modules/other/gail/tests/testvalues.c b/modules/other/gail/tests/testvalues.c new file mode 100644 index 0000000000..fcb811970d --- /dev/null +++ b/modules/other/gail/tests/testvalues.c @@ -0,0 +1,194 @@ +#include +#include +#include +#include + +static void _traverse_children (AtkObject *obj); +static void _add_handler (AtkObject *obj); +static void _check_values (AtkObject *obj); +static void _value_change_handler (AtkObject *obj, + AtkPropertyValues *values); + +static guint id; + +static void _value_change_handler (AtkObject *obj, + AtkPropertyValues *values) +{ + G_CONST_RETURN gchar *type_name = g_type_name (G_TYPE_FROM_INSTANCE (obj)); + GValue *value_back, val; + + value_back = &val; + + if (!ATK_IS_VALUE (obj)) { + return; + } + + if (strcmp (values->property_name, "accessible-value") == 0) { + g_print ("_value_change_handler: Accessible Type: %s\n", + type_name ? type_name : "NULL"); + if(G_VALUE_HOLDS_DOUBLE (&values->new_value)) + { + g_print( "adjustment value changed : new value: %f\n", + g_value_get_double (&values->new_value)); + } + + g_print("Now calling the AtkValue interface functions\n"); + + atk_value_get_current_value (ATK_VALUE(obj), value_back); + g_return_if_fail (G_VALUE_HOLDS_DOUBLE (value_back)); + g_print ("atk_value_get_current_value returns %f\n", + g_value_get_double (value_back) ); + + atk_value_get_maximum_value (ATK_VALUE (obj), value_back); + g_return_if_fail (G_VALUE_HOLDS_DOUBLE (value_back)); + g_print ("atk_value_get_maximum returns %f\n", + g_value_get_double (value_back)); + + atk_value_get_minimum_value (ATK_VALUE (obj), value_back); + g_return_if_fail (G_VALUE_HOLDS_DOUBLE (value_back)); + g_print ("atk_value_get_minimum returns %f\n", + g_value_get_double (value_back)); + + + } + +} + +static void _traverse_children (AtkObject *obj) +{ + gint n_children, i; + + n_children = atk_object_get_n_accessible_children (obj); + for (i = 0; i < n_children; i++) + { + AtkObject *child; + + child = atk_object_ref_accessible_child (obj, i); + _add_handler (child); + _traverse_children (child); + g_object_unref (G_OBJECT (child)); + } +} + +static void _add_handler (AtkObject *obj) +{ + static GPtrArray *obj_array = NULL; + gboolean found = FALSE; + gint i; + + /* + * We create a property handler for each object if one was not associated + * with it already. + * + * We add it to our array of objects which have property handlers; if an + * object is destroyed it remains in the array. + */ + if (obj_array == NULL) + obj_array = g_ptr_array_new (); + + for (i = 0; i < obj_array->len; i++) + { + if (obj == g_ptr_array_index (obj_array, i)) + { + found = TRUE; + break; + } + } + if (!found) + { + atk_object_connect_property_change_handler (obj, + (AtkPropertyChangeHandler*) _value_change_handler); + g_ptr_array_add (obj_array, obj); + } +} + +static void _set_values (AtkObject *obj) { + + GValue *value_back, val; + static gint count = 0; + gdouble double_value; + + value_back = &val; + + if(ATK_IS_VALUE(obj)) { + /* Spin button also inherits the text interfaces from GailEntry. + * Check when spin button recieves focus. + */ + + if(ATK_IS_TEXT(obj) && ATK_IS_EDITABLE_TEXT(obj)) { + if(count == 0) { + gint x; + gchar* text; + count++; + x = atk_text_get_character_count (ATK_TEXT (obj)); + text = atk_text_get_text (ATK_TEXT (obj), 0, x); + g_print("Text : %s\n", text); + text = "5.7"; + atk_editable_text_set_text_contents(ATK_EDITABLE_TEXT(obj),text); + g_print("Set text to %s\n",text); + atk_value_get_current_value(ATK_VALUE(obj), value_back); + g_return_if_fail (G_VALUE_HOLDS_DOUBLE (value_back)); + g_print("atk_value_get_current_value returns %f\n", + g_value_get_double( value_back)); + } + } else { + memset (value_back, 0, sizeof (GValue)); + g_value_init (value_back, G_TYPE_DOUBLE); + g_value_set_double (value_back, 10.0); + if (atk_value_set_current_value (ATK_VALUE (obj), value_back)) + { + double_value = g_value_get_double (value_back); + g_print("atk_value_set_current_value returns %f\n", + double_value); + } + } + } +} + +static void _check_values (AtkObject *obj) +{ + static gint calls = 0; + AtkRole role; + + g_print ("Start of _check_values\n"); + + _set_values(obj); + + _add_handler (obj); + + if (++calls < 2) + { + /* + * Just do this on this on the first 2 objects visited + */ + atk_object_set_name (obj, "test123"); + atk_object_set_description (obj, "test123"); + } + + role = atk_object_get_role (obj); + + if (role == ATK_ROLE_FRAME || role == ATK_ROLE_DIALOG) + { + /* + * Add handlers to all children. + */ + _traverse_children (obj); + } + g_print ("End of _check_values\n"); +} + +static void +_create_event_watcher (void) +{ + id = atk_add_focus_tracker (_check_values); +} + +int +gtk_module_init(gint argc, char* argv[]) +{ + g_print("testvalues Module loaded\n"); + + _create_event_watcher(); + + return 0; +}