michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set ts=2 et sw=2 tw=80: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "ApplicationAccessibleWrap.h" michael@0: michael@0: #include "nsCOMPtr.h" michael@0: #include "nsMai.h" michael@0: #include "nsAutoPtr.h" michael@0: #include "nsAccessibilityService.h" michael@0: michael@0: #include michael@0: #include michael@0: michael@0: using namespace mozilla; michael@0: using namespace mozilla::a11y; michael@0: michael@0: michael@0: // ApplicationAccessibleWrap michael@0: michael@0: ApplicationAccessibleWrap::ApplicationAccessibleWrap(): michael@0: ApplicationAccessible() michael@0: { michael@0: } michael@0: michael@0: ApplicationAccessibleWrap::~ApplicationAccessibleWrap() michael@0: { michael@0: AccessibleWrap::ShutdownAtkObject(); michael@0: } michael@0: michael@0: gboolean michael@0: toplevel_event_watcher(GSignalInvocationHint* ihint, michael@0: guint n_param_values, michael@0: const GValue* param_values, michael@0: gpointer data) michael@0: { michael@0: static GQuark sQuark_gecko_acc_obj = 0; michael@0: michael@0: if (!sQuark_gecko_acc_obj) michael@0: sQuark_gecko_acc_obj = g_quark_from_static_string("GeckoAccObj"); michael@0: michael@0: if (nsAccessibilityService::IsShutdown()) michael@0: return TRUE; michael@0: michael@0: GObject* object = reinterpret_cast(g_value_get_object(param_values)); michael@0: if (!GTK_IS_WINDOW(object)) michael@0: return TRUE; michael@0: michael@0: AtkObject* child = gtk_widget_get_accessible(GTK_WIDGET(object)); michael@0: michael@0: // GTK native dialog michael@0: if (!IS_MAI_OBJECT(child) && michael@0: (atk_object_get_role(child) == ATK_ROLE_DIALOG)) { michael@0: michael@0: if (data == reinterpret_cast(nsIAccessibleEvent::EVENT_SHOW)) { michael@0: michael@0: // Attach the dialog accessible to app accessible tree michael@0: Accessible* windowAcc = GetAccService()->AddNativeRootAccessible(child); michael@0: g_object_set_qdata(G_OBJECT(child), sQuark_gecko_acc_obj, michael@0: reinterpret_cast(windowAcc)); michael@0: michael@0: } else { michael@0: michael@0: // Deattach the dialog accessible michael@0: Accessible* windowAcc = michael@0: reinterpret_cast michael@0: (g_object_get_qdata(G_OBJECT(child), sQuark_gecko_acc_obj)); michael@0: if (windowAcc) { michael@0: GetAccService()->RemoveNativeRootAccessible(windowAcc); michael@0: g_object_set_qdata(G_OBJECT(child), sQuark_gecko_acc_obj, nullptr); michael@0: } michael@0: michael@0: } michael@0: } michael@0: michael@0: return TRUE; michael@0: } michael@0: michael@0: ENameValueFlag michael@0: ApplicationAccessibleWrap::Name(nsString& aName) michael@0: { michael@0: // ATK doesn't provide a way to obtain an application name (for example, michael@0: // Firefox or Thunderbird) like IA2 does. Thus let's return an application michael@0: // name as accessible name that was used to get a branding name (for example, michael@0: // Minefield aka nightly Firefox or Daily aka nightly Thunderbird). michael@0: GetAppName(aName); michael@0: return eNameOK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: ApplicationAccessibleWrap::GetNativeInterface(void** aOutAccessible) michael@0: { michael@0: *aOutAccessible = nullptr; michael@0: michael@0: if (!mAtkObject) { michael@0: mAtkObject = michael@0: reinterpret_cast michael@0: (g_object_new(MAI_TYPE_ATK_OBJECT, nullptr)); michael@0: NS_ENSURE_TRUE(mAtkObject, NS_ERROR_OUT_OF_MEMORY); michael@0: michael@0: atk_object_initialize(mAtkObject, this); michael@0: mAtkObject->role = ATK_ROLE_INVALID; michael@0: mAtkObject->layer = ATK_LAYER_INVALID; michael@0: } michael@0: michael@0: *aOutAccessible = mAtkObject; michael@0: return NS_OK; michael@0: } michael@0: michael@0: struct AtkRootAccessibleAddedEvent { michael@0: AtkObject *app_accessible; michael@0: AtkObject *root_accessible; michael@0: uint32_t index; michael@0: }; michael@0: michael@0: gboolean fireRootAccessibleAddedCB(gpointer data) michael@0: { michael@0: AtkRootAccessibleAddedEvent* eventData = (AtkRootAccessibleAddedEvent*)data; michael@0: g_signal_emit_by_name(eventData->app_accessible, "children_changed::add", michael@0: eventData->index, eventData->root_accessible, nullptr); michael@0: g_object_unref(eventData->app_accessible); michael@0: g_object_unref(eventData->root_accessible); michael@0: free(data); michael@0: michael@0: return FALSE; michael@0: } michael@0: michael@0: bool michael@0: ApplicationAccessibleWrap::InsertChildAt(uint32_t aIdx, Accessible* aChild) michael@0: { michael@0: if (!ApplicationAccessible::InsertChildAt(aIdx, aChild)) michael@0: return false; michael@0: michael@0: AtkObject* atkAccessible = AccessibleWrap::GetAtkObject(aChild); michael@0: atk_object_set_parent(atkAccessible, mAtkObject); michael@0: michael@0: uint32_t count = mChildren.Length(); michael@0: michael@0: // Emit children_changed::add in a timeout michael@0: // to make sure aRootAccWrap is fully initialized. michael@0: AtkRootAccessibleAddedEvent* eventData = (AtkRootAccessibleAddedEvent*) michael@0: malloc(sizeof(AtkRootAccessibleAddedEvent)); michael@0: if (eventData) { michael@0: eventData->app_accessible = mAtkObject; michael@0: eventData->root_accessible = atkAccessible; michael@0: eventData->index = count -1; michael@0: g_object_ref(mAtkObject); michael@0: g_object_ref(atkAccessible); michael@0: g_timeout_add(0, fireRootAccessibleAddedCB, eventData); michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: ApplicationAccessibleWrap::RemoveChild(Accessible* aChild) michael@0: { michael@0: int32_t index = aChild->IndexInParent(); michael@0: michael@0: AtkObject* atkAccessible = AccessibleWrap::GetAtkObject(aChild); michael@0: atk_object_set_parent(atkAccessible, nullptr); michael@0: g_signal_emit_by_name(mAtkObject, "children_changed::remove", index, michael@0: atkAccessible, nullptr); michael@0: michael@0: return ApplicationAccessible::RemoveChild(aChild); michael@0: } michael@0: