Back to index

lightning-sunbird  0.9+nobinonly
nsAppRootAccessible.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* vim:expandtab:shiftwidth=4:tabstop=4:
00003  */
00004 /* ***** BEGIN LICENSE BLOCK *****
00005  * Version: NPL 1.1/GPL 2.0/LGPL 2.1
00006  *
00007  *
00008  * The contents of this file are subject to the Mozilla Public
00009  * License Version 1.1 (the "License"); you may not use this file
00010  * except in compliance with the License. You may obtain a copy of
00011  * the License at http://www.mozilla.org/MPL/
00012  *
00013  * Software distributed under the License is distributed on an "AS
00014  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
00015  * implied. See the License for the specific language governing
00016  * rights and limitations under the License.
00017  *
00018  * The Original Code is mozilla.org code.
00019  *
00020  * The Initial Developer of the Original Code is Sun Microsystems, Inc.
00021  * Portions created by Sun Microsystems are Copyright (C) 2002 Sun
00022  * Microsystems, Inc. All Rights Reserved.
00023  *
00024  * Original Author: Bolian Yin (bolian.yin@sun.com)
00025  *
00026  * Contributor(s): 
00027  *
00028  * Alternatively, the contents of this file may be used under the terms of
00029  * either the GNU General Public License Version 2 or later (the "GPL"), or
00030  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00031  * in which case the provisions of the GPL or the LGPL are applicable instead
00032  * of those above. If you wish to allow use of your version of this file only
00033  * under the terms of either the GPL or the LGPL, and not to allow others to
00034  * use your version of this file under the terms of the NPL, indicate your
00035  * decision by deleting the provisions above and replace them with the notice
00036  * and other provisions required by the GPL or the LGPL. If you do not delete
00037  * the provisions above, a recipient may use your version of this file under
00038  * the terms of any one of the NPL, the GPL or the LGPL.
00039  *
00040  * ***** END LICENSE BLOCK ***** */
00041 
00042 #include "nsCOMPtr.h"
00043 #include "nsMai.h"
00044 #include "nsAppRootAccessible.h"
00045 #include "prlink.h"
00046 #include "nsIServiceManager.h"
00047 
00048 #include <gtk/gtk.h>
00049 #include <atk/atk.h>
00050 
00051 /* app root accessible */
00052 static nsAppRootAccessible *sAppRoot = nsnull;
00053 
00054 /* maiutil */
00055 
00056 static guint mai_util_add_global_event_listener(GSignalEmissionHook listener,
00057                                                 const gchar *event_type);
00058 static void mai_util_remove_global_event_listener(guint remove_listener);
00059 static guint mai_util_add_key_event_listener(AtkKeySnoopFunc listener,
00060                                              gpointer data);
00061 static void mai_util_remove_key_event_listener(guint remove_listener);
00062 static AtkObject *mai_util_get_root(void);
00063 static G_CONST_RETURN gchar *mai_util_get_toolkit_name(void);
00064 static G_CONST_RETURN gchar *mai_util_get_toolkit_version(void);
00065 
00066 
00067 /* Misc */
00068 
00069 static void _listener_info_destroy(gpointer data);
00070 static guint add_listener (GSignalEmissionHook listener,
00071                            const gchar *object_type,
00072                            const gchar *signal,
00073                            const gchar *hook_data);
00074 static AtkKeyEventStruct *atk_key_event_from_gdk_event_key(GdkEventKey *key);
00075 static gboolean notify_hf(gpointer key, gpointer value, gpointer data);
00076 static void insert_hf(gpointer key, gpointer value, gpointer data);
00077 static gboolean remove_hf(gpointer key, gpointer value, gpointer data);
00078 static gint mai_key_snooper(GtkWidget *the_widget, GdkEventKey *event,
00079                             gpointer func_data);
00080 static void value_destroy_func(gpointer data);
00081 
00082 static GHashTable *listener_list = NULL;
00083 static gint listener_idx = 1;
00084 
00085 typedef struct _MaiUtilListenerInfo MaiUtilListenerInfo;
00086 
00087 
00088 #define MAI_TYPE_UTIL              (mai_util_get_type ())
00089 #define MAI_UTIL(obj)              (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
00090                                     MAI_TYPE_UTIL, MaiUtil))
00091 #define MAI_UTIL_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), \
00092                                     MAI_TYPE_UTIL, MaiUtilClass))
00093 #define MAI_IS_UTIL(obj)           (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
00094                                     MAI_TYPE_UTIL))
00095 #define MAI_IS_UTIL_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), \
00096                                     MAI_TYPE_UTIL))
00097 #define MAI_UTIL_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), \
00098                                     MAI_TYPE_UTIL, MaiUtilClass))
00099 
00100 typedef struct _MaiUtil                  MaiUtil;
00101 typedef struct _MaiUtilClass             MaiUtilClass;
00102 
00103 static GHashTable *key_listener_list = NULL;
00104 static guint key_snooper_id = 0;
00105 
00106 G_BEGIN_DECLS
00107 typedef void (*GnomeAccessibilityInit) (void);
00108 typedef void (*GnomeAccessibilityShutdown) (void);
00109 G_END_DECLS
00110 
00111 struct _MaiUtil
00112 {
00113     AtkUtil parent;
00114     GList *listener_list;
00115 };
00116 
00117 struct MaiKeyListenerInfo
00118 {
00119     AtkKeySnoopFunc listener;
00120     gpointer data;
00121 };
00122 
00123 struct GnomeAccessibilityModule
00124 {
00125     const char *libName;
00126     PRLibrary *lib;
00127     const char *initName;
00128     GnomeAccessibilityInit init;
00129     const char *shutdownName;
00130     GnomeAccessibilityShutdown shutdown;
00131 };
00132 
00133 GType mai_util_get_type (void);
00134 static void mai_util_class_init(MaiUtilClass *klass);
00135 
00136 struct _MaiUtilClass
00137 {
00138     AtkUtilClass parent_class;
00139 };
00140 
00141 /* supporting */
00142 PRLogModuleInfo *gMaiLog = NULL;
00143 
00144 #define MAI_VERSION MOZILLA_VERSION
00145 #define MAI_NAME "Gecko"
00146 
00147 struct _MaiUtilListenerInfo
00148 {
00149     gint key;
00150     guint signal_id;
00151     gulong hook_id;
00152 };
00153 
00154 static GnomeAccessibilityModule sAtkBridge = {
00155 #ifdef AIX
00156     "libatk-bridge.a(libatk-bridge.so.0)", NULL,
00157 #else
00158     "libatk-bridge.so", NULL,
00159 #endif
00160     "gnome_accessibility_module_init", NULL,
00161 
00162     "gnome_accessibility_module_shutdown", NULL,
00163 };
00164 
00165 GType
00166 mai_util_get_type(void)
00167 {
00168     static GType type = 0;
00169 
00170     if (!type) {
00171         static const GTypeInfo tinfo = {
00172             sizeof(MaiUtilClass),
00173             (GBaseInitFunc) NULL, /* base init */
00174             (GBaseFinalizeFunc) NULL, /* base finalize */
00175             (GClassInitFunc) mai_util_class_init, /* class init */
00176             (GClassFinalizeFunc) NULL, /* class finalize */
00177             NULL, /* class data */
00178             sizeof(MaiUtil), /* instance size */
00179             0, /* nb preallocs */
00180             (GInstanceInitFunc) NULL, /* instance init */
00181             NULL /* value table */
00182         };
00183 
00184         type = g_type_register_static(ATK_TYPE_UTIL,
00185                                       "MaiUtil", &tinfo, GTypeFlags(0));
00186     }
00187     return type;
00188 }
00189 
00190 /* intialize the the atk interface (function pointers) with MAI implementation.
00191  * When atk bridge get loaded, these interface can be used.
00192  */
00193 static void
00194 mai_util_class_init(MaiUtilClass *klass)
00195 {
00196     AtkUtilClass *atk_class;
00197     gpointer data;
00198 
00199     data = g_type_class_peek(ATK_TYPE_UTIL);
00200     atk_class = ATK_UTIL_CLASS(data);
00201 
00202     atk_class->add_global_event_listener =
00203         mai_util_add_global_event_listener;
00204     atk_class->remove_global_event_listener =
00205         mai_util_remove_global_event_listener;
00206     atk_class->add_key_event_listener = mai_util_add_key_event_listener;
00207     atk_class->remove_key_event_listener = mai_util_remove_key_event_listener;
00208     atk_class->get_root = mai_util_get_root;
00209     atk_class->get_toolkit_name = mai_util_get_toolkit_name;
00210     atk_class->get_toolkit_version = mai_util_get_toolkit_version;
00211 
00212     listener_list = g_hash_table_new_full(g_int_hash, g_int_equal, NULL,
00213                                           _listener_info_destroy);
00214 }
00215 
00216 static guint
00217 mai_util_add_global_event_listener(GSignalEmissionHook listener,
00218                                    const gchar *event_type)
00219 {
00220     guint rc = 0;
00221     gchar **split_string;
00222 
00223     split_string = g_strsplit (event_type, ":", 3);
00224 
00225     if (split_string) {
00226         if (!strcmp ("window", split_string[0])) {
00227             /*  ???
00228                 static gboolean initialized = FALSE;
00229 
00230                 if (!initialized) {
00231                 do_window_event_initialization ();
00232                 initialized = TRUE;
00233                 }
00234                 rc = add_listener (listener, "MaiWindow",
00235                 split_string[1], event_type);
00236             */
00237             rc = add_listener (listener, "MaiAtkObject", split_string[1], event_type);
00238         }
00239         else {
00240             rc = add_listener (listener, split_string[1], split_string[2],
00241                                event_type);
00242         }
00243     }
00244     return rc;
00245 }
00246 
00247 static void
00248 mai_util_remove_global_event_listener(guint remove_listener)
00249 {
00250     if (remove_listener > 0) {
00251         MaiUtilListenerInfo *listener_info;
00252         gint tmp_idx = remove_listener;
00253 
00254         listener_info = (MaiUtilListenerInfo *)
00255             g_hash_table_lookup(listener_list, &tmp_idx);
00256 
00257         if (listener_info != NULL) {
00258             /* Hook id of 0 and signal id of 0 are invalid */
00259             if (listener_info->hook_id != 0 && listener_info->signal_id != 0) {
00260                 /* Remove the emission hook */
00261                 g_signal_remove_emission_hook(listener_info->signal_id,
00262                                               listener_info->hook_id);
00263 
00264                 /* Remove the element from the hash */
00265                 g_hash_table_remove(listener_list, &tmp_idx);
00266             }
00267             else {
00268                 /* do not use g_warning with such complex format args, */
00269                 /* Forte CC can not preprocess it correctly */
00270                 g_log((gchar *)0, G_LOG_LEVEL_WARNING,
00271                       "Invalid listener hook_id %ld or signal_id %d\n",
00272                       listener_info->hook_id, listener_info->signal_id);
00273 
00274             }
00275         }
00276         else {
00277             /* do not use g_warning with such complex format args, */
00278             /* Forte CC can not preprocess it correctly */
00279             g_log((gchar *)0, G_LOG_LEVEL_WARNING,
00280                   "No listener with the specified listener id %d",
00281                   remove_listener);
00282         }
00283     }
00284     else {
00285         g_warning("Invalid listener_id %d", remove_listener);
00286     }
00287 }
00288 
00289 static AtkKeyEventStruct *
00290 atk_key_event_from_gdk_event_key (GdkEventKey *key)
00291 {
00292     AtkKeyEventStruct *event = g_new0(AtkKeyEventStruct, 1);
00293     switch (key->type) {
00294     case GDK_KEY_PRESS:
00295         event->type = ATK_KEY_EVENT_PRESS;
00296         break;
00297     case GDK_KEY_RELEASE:
00298         event->type = ATK_KEY_EVENT_RELEASE;
00299         break;
00300     default:
00301         g_assert_not_reached ();
00302         return NULL;
00303     }
00304     event->state = key->state;
00305     event->keyval = key->keyval;
00306     event->length = key->length;
00307     if (key->string && key->string [0] && 
00308         (key->state & GDK_CONTROL_MASK ||
00309          g_unichar_isgraph (g_utf8_get_char (key->string)))) {
00310         event->string = key->string;
00311     }
00312     else if (key->type == GDK_KEY_PRESS ||
00313              key->type == GDK_KEY_RELEASE) {
00314         event->string = gdk_keyval_name (key->keyval);      
00315     }
00316     event->keycode = key->hardware_keycode;
00317     event->timestamp = key->time;
00318 
00319     MAI_LOG_DEBUG(("MaiKey:\tsym %u\n\tmods %x\n\tcode %u\n\ttime %lx\n",
00320                    (unsigned int) event->keyval,
00321                    (unsigned int) event->state,
00322                    (unsigned int) event->keycode,
00323                    (unsigned long int) event->timestamp));
00324     return event;
00325 }
00326 
00327 static gboolean
00328 notify_hf(gpointer key, gpointer value, gpointer data)
00329 {
00330     AtkKeyEventStruct *event = (AtkKeyEventStruct *) data;
00331     MaiKeyListenerInfo *info = (MaiKeyListenerInfo *)value;
00332 
00333     return (*(info->listener))(event, info->data) ? TRUE : FALSE;
00334 }
00335 
00336 static void
00337 value_destroy_func(gpointer data)
00338 {
00339     g_free(data);
00340 }
00341 
00342 static void
00343 insert_hf(gpointer key, gpointer value, gpointer data)
00344 {
00345     GHashTable *new_table = (GHashTable *) data;
00346     g_hash_table_insert (new_table, key, value);
00347 }
00348 
00349 static gboolean
00350 remove_hf(gpointer key, gpointer value, gpointer data)
00351 {
00352     AtkKeySnoopFunc listener = (AtkKeySnoopFunc)data;
00353     MaiKeyListenerInfo *info = (MaiKeyListenerInfo *)value;
00354     if (info->listener == listener)
00355         return TRUE;
00356     return FALSE;
00357 }
00358 
00359 static gint
00360 mai_key_snooper(GtkWidget *the_widget, GdkEventKey *event, gpointer func_data)
00361 {
00362     /* notify each AtkKeySnoopFunc in turn... */
00363 
00364     gint consumed = 0;
00365     if (key_listener_list) {
00366         AtkKeyEventStruct *keyEvent = atk_key_event_from_gdk_event_key(event);
00367         GHashTable *new_hash = g_hash_table_new(NULL, NULL);
00368         g_hash_table_foreach (key_listener_list, insert_hf, new_hash);
00369         consumed = g_hash_table_foreach_steal (new_hash, notify_hf, keyEvent);
00370         g_hash_table_destroy (new_hash);
00371         g_free (keyEvent);
00372     }
00373     return (consumed ? 1 : 0);
00374 }
00375 
00376 static guint
00377 mai_util_add_key_event_listener (AtkKeySnoopFunc listener,
00378                                  gpointer data)
00379 {
00380     NS_ENSURE_TRUE(listener, 0);
00381 
00382     static guint key=0;
00383     MaiKeyListenerInfo *info = g_new0(MaiKeyListenerInfo, 1);
00384     NS_ENSURE_TRUE(info, 0);
00385 
00386     info->listener = listener;
00387     info->data = data;
00388 
00389     if (!key_listener_list) {
00390         key_listener_list = g_hash_table_new_full(NULL, NULL, NULL,
00391                                                   value_destroy_func);
00392         key_snooper_id = gtk_key_snooper_install(mai_key_snooper, NULL);
00393     }
00394     g_hash_table_insert(key_listener_list, GUINT_TO_POINTER (key++),
00395                         (gpointer)info);
00396     return key;
00397 }
00398 
00399 static void
00400 mai_util_remove_key_event_listener (guint remove_listener)
00401 {
00402     g_hash_table_foreach_remove(key_listener_list, remove_hf,
00403                                 (gpointer)remove_listener);
00404     if (g_hash_table_size(key_listener_list) == 0) {
00405         gtk_key_snooper_remove(key_snooper_id);
00406     }
00407 }
00408 
00409 AtkObject *
00410 mai_util_get_root(void)
00411 {
00412     nsAppRootAccessible *root = nsAppRootAccessible::Create();
00413 
00414     if (!root)
00415         return nsnull;
00416     return root->GetAtkObject();
00417 }
00418 
00419 G_CONST_RETURN gchar *
00420 mai_util_get_toolkit_name(void)
00421 {
00422     return MAI_NAME;
00423 }
00424 
00425 G_CONST_RETURN gchar *
00426 mai_util_get_toolkit_version(void)
00427 {
00428     return MAI_VERSION;
00429 }
00430 
00431 void
00432 _listener_info_destroy(gpointer data)
00433 {
00434     g_free(data);
00435 }
00436 
00437 guint
00438 add_listener (GSignalEmissionHook listener,
00439               const gchar *object_type,
00440               const gchar *signal,
00441               const gchar *hook_data)
00442 {
00443     GType type;
00444     guint signal_id;
00445     gint rc = 0;
00446 
00447     type = g_type_from_name(object_type);
00448     if (type) {
00449         signal_id = g_signal_lookup(signal, type);
00450         if (signal_id > 0) {
00451             MaiUtilListenerInfo *listener_info;
00452 
00453             rc = listener_idx;
00454 
00455             listener_info =  (MaiUtilListenerInfo *)
00456                 g_malloc(sizeof(MaiUtilListenerInfo));
00457             listener_info->key = listener_idx;
00458             listener_info->hook_id =
00459                 g_signal_add_emission_hook(signal_id, 0, listener,
00460                                            g_strdup(hook_data),
00461                                            (GDestroyNotify)g_free);
00462             listener_info->signal_id = signal_id;
00463 
00464             g_hash_table_insert(listener_list, &(listener_info->key),
00465                                 listener_info);
00466             listener_idx++;
00467         }
00468         else {
00469             g_warning("Invalid signal type %s\n", signal);
00470         }
00471     }
00472     else {
00473         g_warning("Invalid object type %s\n", object_type);
00474     }
00475     return rc;
00476 }
00477 
00478 
00479 
00480 
00481 // currently support one child
00482 nsRootAccessibleWrap *sOnlyChild = nsnull;
00483 
00484 static nsresult LoadGtkModule(GnomeAccessibilityModule& aModule);
00485 
00486 nsAppRootAccessible::nsAppRootAccessible():
00487     nsAccessibleWrap(nsnull, nsnull),
00488     mChildren(nsnull),
00489     mInitialized(PR_FALSE)
00490 {
00491     MAI_LOG_DEBUG(("======Create AppRootAcc=%p\n", (void*)this));
00492 }
00493 
00494 nsAppRootAccessible::~nsAppRootAccessible()
00495 {
00496     MAI_LOG_DEBUG(("======Destory AppRootAcc=%p\n", (void*)this));
00497 }
00498 
00499 /* virtual functions */
00500 
00501 #if 0
00502 #ifdef MAI_LOGGING
00503 void
00504 nsAppRootAccessible::DumpMaiObjectInfo(int aDepth)
00505 {
00506     --aDepth;
00507     if (aDepth < 0)
00508         return;
00509     g_print("nsAppRootAccessible: this=0x%x, aDepth=%d, type=%s\n",
00510             (unsigned int)this, aDepth, "nsAppRootAccessible");
00511     gint nChild = GetChildCount();
00512     g_print("#child=%d<br>\n", nChild);
00513     g_print("Iface num: 1=component, 2=action, 3=value, 4=editabletext,"
00514             "5=hyperlink, 6=hypertext, 7=selection, 8=table, 9=text\n");
00515     g_print("<ul>\n");
00516 
00517     MaiObject *maiChild;
00518     for (int childIndex = 0; childIndex < nChild; childIndex++) {
00519         maiChild = RefChild(childIndex);
00520         if (maiChild) {
00521             g_print("  <li>");
00522             maiChild->DumpMaiObjectInfo(aDepth);
00523         }
00524     }
00525     g_print("</ul>\n");
00526     g_print("End of nsAppRootAccessible: this=0x%x, type=%s\n<br>",
00527             (unsigned int)this, "nsAppRootAccessible");
00528 }
00529 #endif
00530 #endif
00531 
00532 NS_IMETHODIMP nsAppRootAccessible::Init()
00533 {
00534     NS_ASSERTION((mInitialized == FALSE), "Init AppRoot Again!!");
00535     if (mInitialized == PR_TRUE)
00536         return NS_OK;
00537 
00538     MAI_LOG_DEBUG(("Mozilla Atk Implementation initializing\n"));
00539     g_type_init();
00540     // Initialize the MAI Utility class
00541     g_type_class_unref(g_type_class_ref(MAI_TYPE_UTIL));
00542 
00543     // load and initialize atk-bridge library
00544     nsresult rv = LoadGtkModule(sAtkBridge);
00545     if (NS_SUCCEEDED(rv)) {
00546         // init atk-bridge
00547         (*sAtkBridge.init)();
00548     }
00549     else
00550         MAI_LOG_DEBUG(("Fail to load lib: %s\n", sAtkBridge.libName));
00551 
00552     rv = NS_NewArray(getter_AddRefs(mChildren));
00553     return rv;
00554 }
00555 
00556 /* static */ void nsAppRootAccessible::Unload()
00557 {
00558     NS_IF_RELEASE(sAppRoot);
00559     if (sAtkBridge.lib) {
00560         if (sAtkBridge.shutdown)
00561             (*sAtkBridge.shutdown)();
00562         //Not unload atk-bridge library
00563         //an exit function registered will take care of it
00564         sAtkBridge.lib = NULL;
00565         sAtkBridge.init = NULL;
00566         sAtkBridge.shutdown = NULL;
00567     }
00568 }
00569 
00570 NS_IMETHODIMP nsAppRootAccessible::GetName(nsAString& _retval)
00571 {
00572     nsCOMPtr<nsIStringBundleService> bundleService = 
00573       do_GetService(NS_STRINGBUNDLE_CONTRACTID);
00574 
00575     NS_ASSERTION(bundleService, "String bundle service must be present!");
00576 
00577     nsCOMPtr<nsIStringBundle> bundle;
00578     bundleService->CreateBundle("chrome://branding/locale/brand.properties",
00579                                 getter_AddRefs(bundle));
00580     nsXPIDLString appName;
00581 
00582     if (bundle) {
00583       bundle->GetStringFromName(NS_LITERAL_STRING("brandShortName").get(),
00584                                 getter_Copies(appName));
00585     } else {
00586       NS_WARNING("brand.properties not present, using default app name");
00587       appName.AssignLiteral("Mozilla");
00588     }
00589 
00590     _retval.Assign(appName);
00591     return NS_OK;
00592 }
00593 
00594 NS_IMETHODIMP nsAppRootAccessible::GetDescription(nsAString& aDescription)
00595 {
00596     GetName(aDescription);
00597     aDescription.AppendLiteral(" Root Accessible");
00598     return NS_OK;
00599 }
00600 
00601 NS_IMETHODIMP nsAppRootAccessible::GetRole(PRUint32 *aRole)
00602 {
00603     *aRole = ROLE_APPLICATION;
00604     return NS_OK;
00605 }
00606 
00607 NS_IMETHODIMP nsAppRootAccessible::GetFinalRole(PRUint32 *aFinalRole)
00608 {
00609     return GetRole(aFinalRole);
00610 }
00611 
00612 NS_IMETHODIMP nsAppRootAccessible::GetParent(nsIAccessible **  aParent)
00613 {
00614     *aParent = nsnull;
00615     return NS_OK;
00616 }
00617 
00618 NS_IMETHODIMP nsAppRootAccessible::GetChildAt(PRInt32 aChildNum,
00619                                               nsIAccessible **aChild)
00620 {
00621     PRUint32 count = 0;
00622     nsresult rv = NS_OK;
00623     *aChild = nsnull;
00624     if (mChildren)
00625         rv = mChildren->GetLength(&count);
00626     NS_ENSURE_SUCCESS(rv, rv);
00627 
00628     if (aChildNum >= NS_STATIC_CAST(PRInt32, count) || count == 0)
00629         return NS_ERROR_INVALID_ARG;
00630 
00631     if (aChildNum < 0)
00632         aChildNum = count - 1;
00633 
00634     nsCOMPtr<nsIWeakReference> childWeakRef;
00635     rv = mChildren->QueryElementAt(aChildNum, NS_GET_IID(nsIWeakReference),
00636                                    getter_AddRefs(childWeakRef));
00637     if (childWeakRef) {
00638         MAI_LOG_DEBUG(("GetChildAt(%d), has weak ref\n", aChildNum));
00639         nsCOMPtr<nsIAccessible> childAcc = do_QueryReferent(childWeakRef);
00640         if (childAcc) {
00641             MAI_LOG_DEBUG(("GetChildAt(%d), has Acc Child ref\n", aChildNum));
00642             NS_IF_ADDREF(*aChild = childAcc);
00643         }
00644         else
00645             MAI_LOG_DEBUG(("GetChildAt(%d), NOT has Acc Child ref\n",
00646                            aChildNum));
00647 
00648     }
00649     else
00650         MAI_LOG_DEBUG(("GetChildAt(%d), NOT has weak ref\n", aChildNum));
00651     return rv;
00652 }
00653 
00654 NS_IMETHODIMP nsAppRootAccessible::GetChildCount(PRInt32 *aAccChildCount) 
00655 {
00656     PRUint32 count = 0;
00657     nsresult rv = NS_OK;
00658     if (mChildren)
00659         rv = mChildren->GetLength(&count);
00660     if (NS_SUCCEEDED(rv)) {
00661         MAI_LOG_DEBUG(("\nGet Acc Child OK, count=%d\n", count));
00662     }
00663     else
00664         MAI_LOG_DEBUG(("\nGet Acc Child Failed, count=%d\n", count));
00665 
00666     *aAccChildCount = NS_STATIC_CAST(PRInt32, count);
00667     return rv;
00668 }
00669 
00670 NS_IMETHODIMP nsAppRootAccessible::GetFirstChild(nsIAccessible * *aFirstChild) 
00671 {
00672     nsCOMPtr<nsIAccessible> firstChild;
00673     *aFirstChild = nsnull;
00674     nsresult rv = NS_OK;
00675     rv = mChildren->QueryElementAt(0, NS_GET_IID(nsIAccessible),
00676                                    getter_AddRefs(firstChild));
00677     if (firstChild)
00678         NS_IF_ADDREF(*aFirstChild = firstChild);
00679     return rv;
00680 }
00681 
00682 NS_IMETHODIMP nsAppRootAccessible::GetNextSibling(nsIAccessible * *aNextSibling) 
00683 { 
00684     *aNextSibling = nsnull; 
00685     return NS_OK;  
00686 }
00687 
00688 NS_IMETHODIMP nsAppRootAccessible::GetPreviousSibling(nsIAccessible * *aPreviousSibling) 
00689 {
00690     *aPreviousSibling = nsnull;
00691     return NS_OK;  
00692 }
00693 
00694 NS_IMETHODIMP nsAppRootAccessible::GetNativeInterface(void **aOutAccessible)
00695 {
00696     *aOutAccessible = nsnull;
00697 
00698     if (!mMaiAtkObject) {
00699         mMaiAtkObject =
00700             NS_REINTERPRET_CAST(AtkObject *,
00701                                 g_object_new(MAI_TYPE_ATK_OBJECT, NULL));
00702         NS_ENSURE_TRUE(mMaiAtkObject, NS_ERROR_OUT_OF_MEMORY);
00703 
00704         atk_object_initialize(mMaiAtkObject, this);
00705         mMaiAtkObject->role = ATK_ROLE_INVALID;
00706         mMaiAtkObject->layer = ATK_LAYER_INVALID;
00707     }
00708 
00709     *aOutAccessible = mMaiAtkObject;
00710     return NS_OK;
00711 }
00712 
00713 nsresult
00714 nsAppRootAccessible::AddRootAccessible(nsRootAccessibleWrap *aRootAccWrap)
00715 {
00716     NS_ENSURE_ARG_POINTER(aRootAccWrap);
00717 
00718     nsresult rv = NS_ERROR_FAILURE;
00719 
00720     // add by weak reference
00721     rv = mChildren->AppendElement(NS_STATIC_CAST(nsIAccessibleDocument*, aRootAccWrap),
00722                                   PR_TRUE);
00723 
00724 #ifdef MAI_LOGGING
00725     PRUint32 count = 0;
00726     mChildren->GetLength(&count);
00727     if (NS_SUCCEEDED(rv)) {
00728         MAI_LOG_DEBUG(("\nAdd RootAcc=%p OK, count=%d\n",
00729                        (void*)aRootAccWrap, count));
00730     }
00731     else
00732         MAI_LOG_DEBUG(("\nAdd RootAcc=%p Failed, count=%d\n",
00733                        (void*)aRootAccWrap, count));
00734 #endif
00735 
00736     return rv;
00737 }
00738 
00739 nsresult
00740 nsAppRootAccessible::RemoveRootAccessible(nsRootAccessibleWrap *aRootAccWrap)
00741 {
00742     NS_ENSURE_ARG_POINTER(aRootAccWrap);
00743 
00744     PRUint32 index = 0;
00745     nsresult rv = NS_ERROR_FAILURE;
00746 
00747     // we must use weak ref to get the index
00748     nsCOMPtr<nsIWeakReference> weakPtr =
00749         do_GetWeakReference(NS_STATIC_CAST(nsIAccessibleDocument*, aRootAccWrap));
00750     rv = mChildren->IndexOf(0, weakPtr, &index);
00751 
00752 #ifdef MAI_LOGGING
00753     PRUint32 count = 0;
00754     mChildren->GetLength(&count);
00755 
00756     if (NS_SUCCEEDED(rv)) {
00757         rv = mChildren->RemoveElementAt(index);
00758         MAI_LOG_DEBUG(("\nRemove RootAcc=%p, count=%d\n",
00759                        (void*)aRootAccWrap, (count-1)));
00760     }
00761     else
00762         MAI_LOG_DEBUG(("\nFail to Remove RootAcc=%p, count=%d\n",
00763                        (void*)aRootAccWrap, count));
00764 #else
00765     NS_ENSURE_SUCCESS(rv, rv);
00766     rv = mChildren->RemoveElementAt(index);
00767 
00768 #endif
00769     return rv;
00770 }
00771 
00772 nsAppRootAccessible *
00773 nsAppRootAccessible::Create()
00774 {
00775     if (!sAppRoot) {
00776         sAppRoot = new nsAppRootAccessible();
00777         NS_ASSERTION(sAppRoot, "OUT OF MEMORY");
00778         if (sAppRoot) {
00779             if (NS_FAILED(sAppRoot->Init())) {
00780                 delete sAppRoot;
00781                 sAppRoot = nsnull;
00782             }
00783             else
00784                 NS_IF_ADDREF(sAppRoot);
00785         }
00786     }
00787     return sAppRoot;
00788 }
00789 
00790 static nsresult
00791 LoadGtkModule(GnomeAccessibilityModule& aModule)
00792 {
00793     NS_ENSURE_ARG(aModule.libName);
00794 
00795     if (!(aModule.lib = PR_LoadLibrary(aModule.libName))) {
00796 
00797         MAI_LOG_DEBUG(("Fail to load lib: %s in default path\n", aModule.libName));
00798 
00799         //try to load the module with "gtk-2.0/modules" appended
00800         char *curLibPath = PR_GetLibraryPath();
00801         nsCAutoString libPath(curLibPath);
00802         libPath.Append(":/usr/lib");
00803         MAI_LOG_DEBUG(("Current Lib path=%s\n", libPath.get()));
00804         PR_FreeLibraryName(curLibPath);
00805 
00806         PRInt16 loc1 = 0, loc2 = 0;
00807         PRInt16 subLen = 0;
00808         while (loc2 >= 0) {
00809             loc2 = libPath.FindChar(':', loc1);
00810             if (loc2 < 0)
00811                 subLen = libPath.Length() - loc1;
00812             else
00813                 subLen = loc2 - loc1;
00814             nsCAutoString sub(Substring(libPath, loc1, subLen));
00815             sub.Append("/gtk-2.0/modules/");
00816             sub.Append(aModule.libName);
00817             aModule.lib = PR_LoadLibrary(sub.get());
00818             if (aModule.lib) {
00819                 MAI_LOG_DEBUG(("Ok, load %s from %s\n", aModule.libName, sub.get()));
00820                 break;
00821             }
00822             loc1 = loc2+1;
00823         }
00824         if (!aModule.lib) {
00825             MAI_LOG_DEBUG(("Fail to load %s\n", aModule.libName));
00826             return NS_ERROR_FAILURE;
00827         }
00828     }
00829 
00830     //we have loaded the library, try to get the function ptrs
00831     if (!(aModule.init = PR_FindFunctionSymbol(aModule.lib,
00832                                                aModule.initName)) ||
00833         !(aModule.shutdown = PR_FindFunctionSymbol(aModule.lib,
00834                                                    aModule.shutdownName))) {
00835 
00836         //fail, :(
00837         MAI_LOG_DEBUG(("Fail to find symbol %s in %s",
00838                        aModule.init ? aModule.shutdownName : aModule.initName,
00839                        aModule.libName));
00840         PR_UnloadLibrary(aModule.lib);
00841         aModule.lib = NULL;
00842         return NS_ERROR_FAILURE;
00843     }
00844     return NS_OK;
00845 }