Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
michael@0 | 1 | /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
michael@0 | 2 | /* vim: set ts=2 et sw=2 tw=80: */ |
michael@0 | 3 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 4 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 5 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 6 | |
michael@0 | 7 | #include "AccessibleWrap.h" |
michael@0 | 8 | |
michael@0 | 9 | #include "Accessible-inl.h" |
michael@0 | 10 | #include "ApplicationAccessibleWrap.h" |
michael@0 | 11 | #include "InterfaceInitFuncs.h" |
michael@0 | 12 | #include "nsAccUtils.h" |
michael@0 | 13 | #include "nsIAccessibleRelation.h" |
michael@0 | 14 | #include "nsIAccessibleTable.h" |
michael@0 | 15 | #include "RootAccessible.h" |
michael@0 | 16 | #include "nsIAccessibleValue.h" |
michael@0 | 17 | #include "nsMai.h" |
michael@0 | 18 | #include "nsMaiHyperlink.h" |
michael@0 | 19 | #include "nsString.h" |
michael@0 | 20 | #include "nsAutoPtr.h" |
michael@0 | 21 | #include "prprf.h" |
michael@0 | 22 | #include "nsStateMap.h" |
michael@0 | 23 | #include "Relation.h" |
michael@0 | 24 | #include "RootAccessible.h" |
michael@0 | 25 | #include "States.h" |
michael@0 | 26 | #include "nsISimpleEnumerator.h" |
michael@0 | 27 | |
michael@0 | 28 | #include "mozilla/ArrayUtils.h" |
michael@0 | 29 | #include "nsXPCOMStrings.h" |
michael@0 | 30 | #include "nsComponentManagerUtils.h" |
michael@0 | 31 | #include "nsIPersistentProperties2.h" |
michael@0 | 32 | |
michael@0 | 33 | using namespace mozilla; |
michael@0 | 34 | using namespace mozilla::a11y; |
michael@0 | 35 | |
michael@0 | 36 | AccessibleWrap::EAvailableAtkSignals AccessibleWrap::gAvailableAtkSignals = |
michael@0 | 37 | eUnknown; |
michael@0 | 38 | |
michael@0 | 39 | //defined in ApplicationAccessibleWrap.cpp |
michael@0 | 40 | extern "C" GType g_atk_hyperlink_impl_type; |
michael@0 | 41 | |
michael@0 | 42 | /* MaiAtkObject */ |
michael@0 | 43 | |
michael@0 | 44 | enum { |
michael@0 | 45 | ACTIVATE, |
michael@0 | 46 | CREATE, |
michael@0 | 47 | DEACTIVATE, |
michael@0 | 48 | DESTROY, |
michael@0 | 49 | MAXIMIZE, |
michael@0 | 50 | MINIMIZE, |
michael@0 | 51 | RESIZE, |
michael@0 | 52 | RESTORE, |
michael@0 | 53 | LAST_SIGNAL |
michael@0 | 54 | }; |
michael@0 | 55 | |
michael@0 | 56 | enum MaiInterfaceType { |
michael@0 | 57 | MAI_INTERFACE_COMPONENT, /* 0 */ |
michael@0 | 58 | MAI_INTERFACE_ACTION, |
michael@0 | 59 | MAI_INTERFACE_VALUE, |
michael@0 | 60 | MAI_INTERFACE_EDITABLE_TEXT, |
michael@0 | 61 | MAI_INTERFACE_HYPERTEXT, |
michael@0 | 62 | MAI_INTERFACE_HYPERLINK_IMPL, |
michael@0 | 63 | MAI_INTERFACE_SELECTION, |
michael@0 | 64 | MAI_INTERFACE_TABLE, |
michael@0 | 65 | MAI_INTERFACE_TEXT, |
michael@0 | 66 | MAI_INTERFACE_DOCUMENT, |
michael@0 | 67 | MAI_INTERFACE_IMAGE /* 10 */ |
michael@0 | 68 | }; |
michael@0 | 69 | |
michael@0 | 70 | static GType GetAtkTypeForMai(MaiInterfaceType type) |
michael@0 | 71 | { |
michael@0 | 72 | switch (type) { |
michael@0 | 73 | case MAI_INTERFACE_COMPONENT: |
michael@0 | 74 | return ATK_TYPE_COMPONENT; |
michael@0 | 75 | case MAI_INTERFACE_ACTION: |
michael@0 | 76 | return ATK_TYPE_ACTION; |
michael@0 | 77 | case MAI_INTERFACE_VALUE: |
michael@0 | 78 | return ATK_TYPE_VALUE; |
michael@0 | 79 | case MAI_INTERFACE_EDITABLE_TEXT: |
michael@0 | 80 | return ATK_TYPE_EDITABLE_TEXT; |
michael@0 | 81 | case MAI_INTERFACE_HYPERTEXT: |
michael@0 | 82 | return ATK_TYPE_HYPERTEXT; |
michael@0 | 83 | case MAI_INTERFACE_HYPERLINK_IMPL: |
michael@0 | 84 | return g_atk_hyperlink_impl_type; |
michael@0 | 85 | case MAI_INTERFACE_SELECTION: |
michael@0 | 86 | return ATK_TYPE_SELECTION; |
michael@0 | 87 | case MAI_INTERFACE_TABLE: |
michael@0 | 88 | return ATK_TYPE_TABLE; |
michael@0 | 89 | case MAI_INTERFACE_TEXT: |
michael@0 | 90 | return ATK_TYPE_TEXT; |
michael@0 | 91 | case MAI_INTERFACE_DOCUMENT: |
michael@0 | 92 | return ATK_TYPE_DOCUMENT; |
michael@0 | 93 | case MAI_INTERFACE_IMAGE: |
michael@0 | 94 | return ATK_TYPE_IMAGE; |
michael@0 | 95 | } |
michael@0 | 96 | return G_TYPE_INVALID; |
michael@0 | 97 | } |
michael@0 | 98 | |
michael@0 | 99 | static const char* kNonUserInputEvent = ":system"; |
michael@0 | 100 | |
michael@0 | 101 | static const GInterfaceInfo atk_if_infos[] = { |
michael@0 | 102 | {(GInterfaceInitFunc)componentInterfaceInitCB, |
michael@0 | 103 | (GInterfaceFinalizeFunc) nullptr, nullptr}, |
michael@0 | 104 | {(GInterfaceInitFunc)actionInterfaceInitCB, |
michael@0 | 105 | (GInterfaceFinalizeFunc) nullptr, nullptr}, |
michael@0 | 106 | {(GInterfaceInitFunc)valueInterfaceInitCB, |
michael@0 | 107 | (GInterfaceFinalizeFunc) nullptr, nullptr}, |
michael@0 | 108 | {(GInterfaceInitFunc)editableTextInterfaceInitCB, |
michael@0 | 109 | (GInterfaceFinalizeFunc) nullptr, nullptr}, |
michael@0 | 110 | {(GInterfaceInitFunc)hypertextInterfaceInitCB, |
michael@0 | 111 | (GInterfaceFinalizeFunc) nullptr, nullptr}, |
michael@0 | 112 | {(GInterfaceInitFunc)hyperlinkImplInterfaceInitCB, |
michael@0 | 113 | (GInterfaceFinalizeFunc) nullptr, nullptr}, |
michael@0 | 114 | {(GInterfaceInitFunc)selectionInterfaceInitCB, |
michael@0 | 115 | (GInterfaceFinalizeFunc) nullptr, nullptr}, |
michael@0 | 116 | {(GInterfaceInitFunc)tableInterfaceInitCB, |
michael@0 | 117 | (GInterfaceFinalizeFunc) nullptr, nullptr}, |
michael@0 | 118 | {(GInterfaceInitFunc)textInterfaceInitCB, |
michael@0 | 119 | (GInterfaceFinalizeFunc) nullptr, nullptr}, |
michael@0 | 120 | {(GInterfaceInitFunc)documentInterfaceInitCB, |
michael@0 | 121 | (GInterfaceFinalizeFunc) nullptr, nullptr}, |
michael@0 | 122 | {(GInterfaceInitFunc)imageInterfaceInitCB, |
michael@0 | 123 | (GInterfaceFinalizeFunc) nullptr, nullptr} |
michael@0 | 124 | }; |
michael@0 | 125 | |
michael@0 | 126 | /** |
michael@0 | 127 | * This MaiAtkObject is a thin wrapper, in the MAI namespace, for AtkObject |
michael@0 | 128 | */ |
michael@0 | 129 | struct MaiAtkObject |
michael@0 | 130 | { |
michael@0 | 131 | AtkObject parent; |
michael@0 | 132 | /* |
michael@0 | 133 | * The AccessibleWrap whose properties and features are exported |
michael@0 | 134 | * via this object instance. |
michael@0 | 135 | */ |
michael@0 | 136 | AccessibleWrap* accWrap; |
michael@0 | 137 | }; |
michael@0 | 138 | |
michael@0 | 139 | struct MaiAtkObjectClass |
michael@0 | 140 | { |
michael@0 | 141 | AtkObjectClass parent_class; |
michael@0 | 142 | }; |
michael@0 | 143 | |
michael@0 | 144 | static guint mai_atk_object_signals [LAST_SIGNAL] = { 0, }; |
michael@0 | 145 | |
michael@0 | 146 | static void MaybeFireNameChange(AtkObject* aAtkObj, const nsString& aNewName); |
michael@0 | 147 | |
michael@0 | 148 | G_BEGIN_DECLS |
michael@0 | 149 | /* callbacks for MaiAtkObject */ |
michael@0 | 150 | static void classInitCB(AtkObjectClass *aClass); |
michael@0 | 151 | static void initializeCB(AtkObject *aAtkObj, gpointer aData); |
michael@0 | 152 | static void finalizeCB(GObject *aObj); |
michael@0 | 153 | |
michael@0 | 154 | /* callbacks for AtkObject virtual functions */ |
michael@0 | 155 | static const gchar* getNameCB (AtkObject *aAtkObj); |
michael@0 | 156 | /* getDescriptionCB is also used by image interface */ |
michael@0 | 157 | const gchar* getDescriptionCB (AtkObject *aAtkObj); |
michael@0 | 158 | static AtkRole getRoleCB(AtkObject *aAtkObj); |
michael@0 | 159 | static AtkAttributeSet* getAttributesCB(AtkObject *aAtkObj); |
michael@0 | 160 | static const gchar* GetLocaleCB(AtkObject*); |
michael@0 | 161 | static AtkObject* getParentCB(AtkObject *aAtkObj); |
michael@0 | 162 | static gint getChildCountCB(AtkObject *aAtkObj); |
michael@0 | 163 | static AtkObject* refChildCB(AtkObject *aAtkObj, gint aChildIndex); |
michael@0 | 164 | static gint getIndexInParentCB(AtkObject *aAtkObj); |
michael@0 | 165 | static AtkStateSet* refStateSetCB(AtkObject *aAtkObj); |
michael@0 | 166 | static AtkRelationSet* refRelationSetCB(AtkObject *aAtkObj); |
michael@0 | 167 | |
michael@0 | 168 | /* the missing atkobject virtual functions */ |
michael@0 | 169 | /* |
michael@0 | 170 | static AtkLayer getLayerCB(AtkObject *aAtkObj); |
michael@0 | 171 | static gint getMdiZorderCB(AtkObject *aAtkObj); |
michael@0 | 172 | static void SetNameCB(AtkObject *aAtkObj, |
michael@0 | 173 | const gchar *name); |
michael@0 | 174 | static void SetDescriptionCB(AtkObject *aAtkObj, |
michael@0 | 175 | const gchar *description); |
michael@0 | 176 | static void SetParentCB(AtkObject *aAtkObj, |
michael@0 | 177 | AtkObject *parent); |
michael@0 | 178 | static void SetRoleCB(AtkObject *aAtkObj, |
michael@0 | 179 | AtkRole role); |
michael@0 | 180 | static guint ConnectPropertyChangeHandlerCB( |
michael@0 | 181 | AtkObject *aObj, |
michael@0 | 182 | AtkPropertyChangeHandler *handler); |
michael@0 | 183 | static void RemovePropertyChangeHandlerCB( |
michael@0 | 184 | AtkObject *aAtkObj, |
michael@0 | 185 | guint handler_id); |
michael@0 | 186 | static void InitializeCB(AtkObject *aAtkObj, |
michael@0 | 187 | gpointer data); |
michael@0 | 188 | static void ChildrenChangedCB(AtkObject *aAtkObj, |
michael@0 | 189 | guint change_index, |
michael@0 | 190 | gpointer changed_child); |
michael@0 | 191 | static void FocusEventCB(AtkObject *aAtkObj, |
michael@0 | 192 | gboolean focus_in); |
michael@0 | 193 | static void PropertyChangeCB(AtkObject *aAtkObj, |
michael@0 | 194 | AtkPropertyValues *values); |
michael@0 | 195 | static void StateChangeCB(AtkObject *aAtkObj, |
michael@0 | 196 | const gchar *name, |
michael@0 | 197 | gboolean state_set); |
michael@0 | 198 | static void VisibleDataChangedCB(AtkObject *aAtkObj); |
michael@0 | 199 | */ |
michael@0 | 200 | G_END_DECLS |
michael@0 | 201 | |
michael@0 | 202 | static GType GetMaiAtkType(uint16_t interfacesBits); |
michael@0 | 203 | static const char * GetUniqueMaiAtkTypeName(uint16_t interfacesBits); |
michael@0 | 204 | |
michael@0 | 205 | static gpointer parent_class = nullptr; |
michael@0 | 206 | |
michael@0 | 207 | static GQuark quark_mai_hyperlink = 0; |
michael@0 | 208 | |
michael@0 | 209 | GType |
michael@0 | 210 | mai_atk_object_get_type(void) |
michael@0 | 211 | { |
michael@0 | 212 | static GType type = 0; |
michael@0 | 213 | |
michael@0 | 214 | if (!type) { |
michael@0 | 215 | static const GTypeInfo tinfo = { |
michael@0 | 216 | sizeof(MaiAtkObjectClass), |
michael@0 | 217 | (GBaseInitFunc)nullptr, |
michael@0 | 218 | (GBaseFinalizeFunc)nullptr, |
michael@0 | 219 | (GClassInitFunc)classInitCB, |
michael@0 | 220 | (GClassFinalizeFunc)nullptr, |
michael@0 | 221 | nullptr, /* class data */ |
michael@0 | 222 | sizeof(MaiAtkObject), /* instance size */ |
michael@0 | 223 | 0, /* nb preallocs */ |
michael@0 | 224 | (GInstanceInitFunc)nullptr, |
michael@0 | 225 | nullptr /* value table */ |
michael@0 | 226 | }; |
michael@0 | 227 | |
michael@0 | 228 | type = g_type_register_static(ATK_TYPE_OBJECT, |
michael@0 | 229 | "MaiAtkObject", &tinfo, GTypeFlags(0)); |
michael@0 | 230 | quark_mai_hyperlink = g_quark_from_static_string("MaiHyperlink"); |
michael@0 | 231 | } |
michael@0 | 232 | return type; |
michael@0 | 233 | } |
michael@0 | 234 | |
michael@0 | 235 | AccessibleWrap:: |
michael@0 | 236 | AccessibleWrap(nsIContent* aContent, DocAccessible* aDoc) : |
michael@0 | 237 | Accessible(aContent, aDoc), mAtkObject(nullptr) |
michael@0 | 238 | { |
michael@0 | 239 | } |
michael@0 | 240 | |
michael@0 | 241 | AccessibleWrap::~AccessibleWrap() |
michael@0 | 242 | { |
michael@0 | 243 | NS_ASSERTION(!mAtkObject, "ShutdownAtkObject() is not called"); |
michael@0 | 244 | } |
michael@0 | 245 | |
michael@0 | 246 | void |
michael@0 | 247 | AccessibleWrap::ShutdownAtkObject() |
michael@0 | 248 | { |
michael@0 | 249 | if (mAtkObject) { |
michael@0 | 250 | if (IS_MAI_OBJECT(mAtkObject)) { |
michael@0 | 251 | MAI_ATK_OBJECT(mAtkObject)->accWrap = nullptr; |
michael@0 | 252 | } |
michael@0 | 253 | SetMaiHyperlink(nullptr); |
michael@0 | 254 | g_object_unref(mAtkObject); |
michael@0 | 255 | mAtkObject = nullptr; |
michael@0 | 256 | } |
michael@0 | 257 | } |
michael@0 | 258 | |
michael@0 | 259 | void |
michael@0 | 260 | AccessibleWrap::Shutdown() |
michael@0 | 261 | { |
michael@0 | 262 | ShutdownAtkObject(); |
michael@0 | 263 | Accessible::Shutdown(); |
michael@0 | 264 | } |
michael@0 | 265 | |
michael@0 | 266 | MaiHyperlink* |
michael@0 | 267 | AccessibleWrap::GetMaiHyperlink(bool aCreate /* = true */) |
michael@0 | 268 | { |
michael@0 | 269 | // make sure mAtkObject is created |
michael@0 | 270 | GetAtkObject(); |
michael@0 | 271 | |
michael@0 | 272 | NS_ASSERTION(quark_mai_hyperlink, "quark_mai_hyperlink not initialized"); |
michael@0 | 273 | NS_ASSERTION(IS_MAI_OBJECT(mAtkObject), "Invalid AtkObject"); |
michael@0 | 274 | MaiHyperlink* maiHyperlink = nullptr; |
michael@0 | 275 | if (quark_mai_hyperlink && IS_MAI_OBJECT(mAtkObject)) { |
michael@0 | 276 | maiHyperlink = (MaiHyperlink*)g_object_get_qdata(G_OBJECT(mAtkObject), |
michael@0 | 277 | quark_mai_hyperlink); |
michael@0 | 278 | if (!maiHyperlink && aCreate) { |
michael@0 | 279 | maiHyperlink = new MaiHyperlink(this); |
michael@0 | 280 | SetMaiHyperlink(maiHyperlink); |
michael@0 | 281 | } |
michael@0 | 282 | } |
michael@0 | 283 | return maiHyperlink; |
michael@0 | 284 | } |
michael@0 | 285 | |
michael@0 | 286 | void |
michael@0 | 287 | AccessibleWrap::SetMaiHyperlink(MaiHyperlink* aMaiHyperlink) |
michael@0 | 288 | { |
michael@0 | 289 | NS_ASSERTION(quark_mai_hyperlink, "quark_mai_hyperlink not initialized"); |
michael@0 | 290 | NS_ASSERTION(IS_MAI_OBJECT(mAtkObject), "Invalid AtkObject"); |
michael@0 | 291 | if (quark_mai_hyperlink && IS_MAI_OBJECT(mAtkObject)) { |
michael@0 | 292 | MaiHyperlink* maiHyperlink = GetMaiHyperlink(false); |
michael@0 | 293 | if (!maiHyperlink && !aMaiHyperlink) { |
michael@0 | 294 | return; // Never set and we're shutting down |
michael@0 | 295 | } |
michael@0 | 296 | delete maiHyperlink; |
michael@0 | 297 | g_object_set_qdata(G_OBJECT(mAtkObject), quark_mai_hyperlink, |
michael@0 | 298 | aMaiHyperlink); |
michael@0 | 299 | } |
michael@0 | 300 | } |
michael@0 | 301 | |
michael@0 | 302 | NS_IMETHODIMP |
michael@0 | 303 | AccessibleWrap::GetNativeInterface(void** aOutAccessible) |
michael@0 | 304 | { |
michael@0 | 305 | *aOutAccessible = nullptr; |
michael@0 | 306 | |
michael@0 | 307 | if (!mAtkObject) { |
michael@0 | 308 | if (IsDefunct() || !nsAccUtils::IsEmbeddedObject(this)) { |
michael@0 | 309 | // We don't create ATK objects for node which has been shutdown, or |
michael@0 | 310 | // nsIAccessible plain text leaves |
michael@0 | 311 | return NS_ERROR_FAILURE; |
michael@0 | 312 | } |
michael@0 | 313 | |
michael@0 | 314 | GType type = GetMaiAtkType(CreateMaiInterfaces()); |
michael@0 | 315 | NS_ENSURE_TRUE(type, NS_ERROR_FAILURE); |
michael@0 | 316 | mAtkObject = |
michael@0 | 317 | reinterpret_cast<AtkObject *> |
michael@0 | 318 | (g_object_new(type, nullptr)); |
michael@0 | 319 | NS_ENSURE_TRUE(mAtkObject, NS_ERROR_OUT_OF_MEMORY); |
michael@0 | 320 | |
michael@0 | 321 | atk_object_initialize(mAtkObject, this); |
michael@0 | 322 | mAtkObject->role = ATK_ROLE_INVALID; |
michael@0 | 323 | mAtkObject->layer = ATK_LAYER_INVALID; |
michael@0 | 324 | } |
michael@0 | 325 | |
michael@0 | 326 | *aOutAccessible = mAtkObject; |
michael@0 | 327 | return NS_OK; |
michael@0 | 328 | } |
michael@0 | 329 | |
michael@0 | 330 | AtkObject * |
michael@0 | 331 | AccessibleWrap::GetAtkObject(void) |
michael@0 | 332 | { |
michael@0 | 333 | void *atkObj = nullptr; |
michael@0 | 334 | GetNativeInterface(&atkObj); |
michael@0 | 335 | return static_cast<AtkObject *>(atkObj); |
michael@0 | 336 | } |
michael@0 | 337 | |
michael@0 | 338 | // Get AtkObject from nsIAccessible interface |
michael@0 | 339 | /* static */ |
michael@0 | 340 | AtkObject * |
michael@0 | 341 | AccessibleWrap::GetAtkObject(nsIAccessible* acc) |
michael@0 | 342 | { |
michael@0 | 343 | void *atkObjPtr = nullptr; |
michael@0 | 344 | acc->GetNativeInterface(&atkObjPtr); |
michael@0 | 345 | return atkObjPtr ? ATK_OBJECT(atkObjPtr) : nullptr; |
michael@0 | 346 | } |
michael@0 | 347 | |
michael@0 | 348 | /* private */ |
michael@0 | 349 | uint16_t |
michael@0 | 350 | AccessibleWrap::CreateMaiInterfaces(void) |
michael@0 | 351 | { |
michael@0 | 352 | uint16_t interfacesBits = 0; |
michael@0 | 353 | |
michael@0 | 354 | // The Component interface is supported by all accessibles. |
michael@0 | 355 | interfacesBits |= 1 << MAI_INTERFACE_COMPONENT; |
michael@0 | 356 | |
michael@0 | 357 | // Add Action interface if the action count is more than zero. |
michael@0 | 358 | if (ActionCount() > 0) |
michael@0 | 359 | interfacesBits |= 1 << MAI_INTERFACE_ACTION; |
michael@0 | 360 | |
michael@0 | 361 | // Text, Editabletext, and Hypertext interface. |
michael@0 | 362 | HyperTextAccessible* hyperText = AsHyperText(); |
michael@0 | 363 | if (hyperText && hyperText->IsTextRole()) { |
michael@0 | 364 | interfacesBits |= 1 << MAI_INTERFACE_TEXT; |
michael@0 | 365 | interfacesBits |= 1 << MAI_INTERFACE_EDITABLE_TEXT; |
michael@0 | 366 | if (!nsAccUtils::MustPrune(this)) |
michael@0 | 367 | interfacesBits |= 1 << MAI_INTERFACE_HYPERTEXT; |
michael@0 | 368 | } |
michael@0 | 369 | |
michael@0 | 370 | // Value interface. |
michael@0 | 371 | nsCOMPtr<nsIAccessibleValue> accessInterfaceValue; |
michael@0 | 372 | QueryInterface(NS_GET_IID(nsIAccessibleValue), |
michael@0 | 373 | getter_AddRefs(accessInterfaceValue)); |
michael@0 | 374 | if (accessInterfaceValue) { |
michael@0 | 375 | interfacesBits |= 1 << MAI_INTERFACE_VALUE; |
michael@0 | 376 | } |
michael@0 | 377 | |
michael@0 | 378 | // Document interface. |
michael@0 | 379 | if (IsDoc()) |
michael@0 | 380 | interfacesBits |= 1 << MAI_INTERFACE_DOCUMENT; |
michael@0 | 381 | |
michael@0 | 382 | if (IsImage()) |
michael@0 | 383 | interfacesBits |= 1 << MAI_INTERFACE_IMAGE; |
michael@0 | 384 | |
michael@0 | 385 | // HyperLink interface. |
michael@0 | 386 | if (IsLink()) |
michael@0 | 387 | interfacesBits |= 1 << MAI_INTERFACE_HYPERLINK_IMPL; |
michael@0 | 388 | |
michael@0 | 389 | if (!nsAccUtils::MustPrune(this)) { // These interfaces require children |
michael@0 | 390 | // Table interface. |
michael@0 | 391 | if (AsTable()) |
michael@0 | 392 | interfacesBits |= 1 << MAI_INTERFACE_TABLE; |
michael@0 | 393 | |
michael@0 | 394 | // Selection interface. |
michael@0 | 395 | if (IsSelect()) { |
michael@0 | 396 | interfacesBits |= 1 << MAI_INTERFACE_SELECTION; |
michael@0 | 397 | } |
michael@0 | 398 | } |
michael@0 | 399 | |
michael@0 | 400 | return interfacesBits; |
michael@0 | 401 | } |
michael@0 | 402 | |
michael@0 | 403 | static GType |
michael@0 | 404 | GetMaiAtkType(uint16_t interfacesBits) |
michael@0 | 405 | { |
michael@0 | 406 | GType type; |
michael@0 | 407 | static const GTypeInfo tinfo = { |
michael@0 | 408 | sizeof(MaiAtkObjectClass), |
michael@0 | 409 | (GBaseInitFunc) nullptr, |
michael@0 | 410 | (GBaseFinalizeFunc) nullptr, |
michael@0 | 411 | (GClassInitFunc) nullptr, |
michael@0 | 412 | (GClassFinalizeFunc) nullptr, |
michael@0 | 413 | nullptr, /* class data */ |
michael@0 | 414 | sizeof(MaiAtkObject), /* instance size */ |
michael@0 | 415 | 0, /* nb preallocs */ |
michael@0 | 416 | (GInstanceInitFunc) nullptr, |
michael@0 | 417 | nullptr /* value table */ |
michael@0 | 418 | }; |
michael@0 | 419 | |
michael@0 | 420 | /* |
michael@0 | 421 | * The members we use to register GTypes are GetAtkTypeForMai |
michael@0 | 422 | * and atk_if_infos, which are constant values to each MaiInterface |
michael@0 | 423 | * So we can reuse the registered GType when having |
michael@0 | 424 | * the same MaiInterface types. |
michael@0 | 425 | */ |
michael@0 | 426 | const char *atkTypeName = GetUniqueMaiAtkTypeName(interfacesBits); |
michael@0 | 427 | type = g_type_from_name(atkTypeName); |
michael@0 | 428 | if (type) { |
michael@0 | 429 | return type; |
michael@0 | 430 | } |
michael@0 | 431 | |
michael@0 | 432 | /* |
michael@0 | 433 | * gobject limits the number of types that can directly derive from any |
michael@0 | 434 | * given object type to 4095. |
michael@0 | 435 | */ |
michael@0 | 436 | static uint16_t typeRegCount = 0; |
michael@0 | 437 | if (typeRegCount++ >= 4095) { |
michael@0 | 438 | return G_TYPE_INVALID; |
michael@0 | 439 | } |
michael@0 | 440 | type = g_type_register_static(MAI_TYPE_ATK_OBJECT, |
michael@0 | 441 | atkTypeName, |
michael@0 | 442 | &tinfo, GTypeFlags(0)); |
michael@0 | 443 | |
michael@0 | 444 | for (uint32_t index = 0; index < ArrayLength(atk_if_infos); index++) { |
michael@0 | 445 | if (interfacesBits & (1 << index)) { |
michael@0 | 446 | g_type_add_interface_static(type, |
michael@0 | 447 | GetAtkTypeForMai((MaiInterfaceType)index), |
michael@0 | 448 | &atk_if_infos[index]); |
michael@0 | 449 | } |
michael@0 | 450 | } |
michael@0 | 451 | |
michael@0 | 452 | return type; |
michael@0 | 453 | } |
michael@0 | 454 | |
michael@0 | 455 | static const char* |
michael@0 | 456 | GetUniqueMaiAtkTypeName(uint16_t interfacesBits) |
michael@0 | 457 | { |
michael@0 | 458 | #define MAI_ATK_TYPE_NAME_LEN (30) /* 10+sizeof(uint16_t)*8/4+1 < 30 */ |
michael@0 | 459 | |
michael@0 | 460 | static gchar namePrefix[] = "MaiAtkType"; /* size = 10 */ |
michael@0 | 461 | static gchar name[MAI_ATK_TYPE_NAME_LEN + 1]; |
michael@0 | 462 | |
michael@0 | 463 | PR_snprintf(name, MAI_ATK_TYPE_NAME_LEN, "%s%x", namePrefix, |
michael@0 | 464 | interfacesBits); |
michael@0 | 465 | name[MAI_ATK_TYPE_NAME_LEN] = '\0'; |
michael@0 | 466 | |
michael@0 | 467 | return name; |
michael@0 | 468 | } |
michael@0 | 469 | |
michael@0 | 470 | bool |
michael@0 | 471 | AccessibleWrap::IsValidObject() |
michael@0 | 472 | { |
michael@0 | 473 | // to ensure we are not shut down |
michael@0 | 474 | return !IsDefunct(); |
michael@0 | 475 | } |
michael@0 | 476 | |
michael@0 | 477 | /* static functions for ATK callbacks */ |
michael@0 | 478 | void |
michael@0 | 479 | classInitCB(AtkObjectClass *aClass) |
michael@0 | 480 | { |
michael@0 | 481 | GObjectClass *gobject_class = G_OBJECT_CLASS(aClass); |
michael@0 | 482 | |
michael@0 | 483 | parent_class = g_type_class_peek_parent(aClass); |
michael@0 | 484 | |
michael@0 | 485 | aClass->get_name = getNameCB; |
michael@0 | 486 | aClass->get_description = getDescriptionCB; |
michael@0 | 487 | aClass->get_parent = getParentCB; |
michael@0 | 488 | aClass->get_n_children = getChildCountCB; |
michael@0 | 489 | aClass->ref_child = refChildCB; |
michael@0 | 490 | aClass->get_index_in_parent = getIndexInParentCB; |
michael@0 | 491 | aClass->get_role = getRoleCB; |
michael@0 | 492 | aClass->get_attributes = getAttributesCB; |
michael@0 | 493 | aClass->get_object_locale = GetLocaleCB; |
michael@0 | 494 | aClass->ref_state_set = refStateSetCB; |
michael@0 | 495 | aClass->ref_relation_set = refRelationSetCB; |
michael@0 | 496 | |
michael@0 | 497 | aClass->initialize = initializeCB; |
michael@0 | 498 | |
michael@0 | 499 | gobject_class->finalize = finalizeCB; |
michael@0 | 500 | |
michael@0 | 501 | mai_atk_object_signals [ACTIVATE] = |
michael@0 | 502 | g_signal_new ("activate", |
michael@0 | 503 | MAI_TYPE_ATK_OBJECT, |
michael@0 | 504 | G_SIGNAL_RUN_LAST, |
michael@0 | 505 | 0, /* default signal handler */ |
michael@0 | 506 | nullptr, nullptr, |
michael@0 | 507 | g_cclosure_marshal_VOID__VOID, |
michael@0 | 508 | G_TYPE_NONE, 0); |
michael@0 | 509 | mai_atk_object_signals [CREATE] = |
michael@0 | 510 | g_signal_new ("create", |
michael@0 | 511 | MAI_TYPE_ATK_OBJECT, |
michael@0 | 512 | G_SIGNAL_RUN_LAST, |
michael@0 | 513 | 0, /* default signal handler */ |
michael@0 | 514 | nullptr, nullptr, |
michael@0 | 515 | g_cclosure_marshal_VOID__VOID, |
michael@0 | 516 | G_TYPE_NONE, 0); |
michael@0 | 517 | mai_atk_object_signals [DEACTIVATE] = |
michael@0 | 518 | g_signal_new ("deactivate", |
michael@0 | 519 | MAI_TYPE_ATK_OBJECT, |
michael@0 | 520 | G_SIGNAL_RUN_LAST, |
michael@0 | 521 | 0, /* default signal handler */ |
michael@0 | 522 | nullptr, nullptr, |
michael@0 | 523 | g_cclosure_marshal_VOID__VOID, |
michael@0 | 524 | G_TYPE_NONE, 0); |
michael@0 | 525 | mai_atk_object_signals [DESTROY] = |
michael@0 | 526 | g_signal_new ("destroy", |
michael@0 | 527 | MAI_TYPE_ATK_OBJECT, |
michael@0 | 528 | G_SIGNAL_RUN_LAST, |
michael@0 | 529 | 0, /* default signal handler */ |
michael@0 | 530 | nullptr, nullptr, |
michael@0 | 531 | g_cclosure_marshal_VOID__VOID, |
michael@0 | 532 | G_TYPE_NONE, 0); |
michael@0 | 533 | mai_atk_object_signals [MAXIMIZE] = |
michael@0 | 534 | g_signal_new ("maximize", |
michael@0 | 535 | MAI_TYPE_ATK_OBJECT, |
michael@0 | 536 | G_SIGNAL_RUN_LAST, |
michael@0 | 537 | 0, /* default signal handler */ |
michael@0 | 538 | nullptr, nullptr, |
michael@0 | 539 | g_cclosure_marshal_VOID__VOID, |
michael@0 | 540 | G_TYPE_NONE, 0); |
michael@0 | 541 | mai_atk_object_signals [MINIMIZE] = |
michael@0 | 542 | g_signal_new ("minimize", |
michael@0 | 543 | MAI_TYPE_ATK_OBJECT, |
michael@0 | 544 | G_SIGNAL_RUN_LAST, |
michael@0 | 545 | 0, /* default signal handler */ |
michael@0 | 546 | nullptr, nullptr, |
michael@0 | 547 | g_cclosure_marshal_VOID__VOID, |
michael@0 | 548 | G_TYPE_NONE, 0); |
michael@0 | 549 | mai_atk_object_signals [RESIZE] = |
michael@0 | 550 | g_signal_new ("resize", |
michael@0 | 551 | MAI_TYPE_ATK_OBJECT, |
michael@0 | 552 | G_SIGNAL_RUN_LAST, |
michael@0 | 553 | 0, /* default signal handler */ |
michael@0 | 554 | nullptr, nullptr, |
michael@0 | 555 | g_cclosure_marshal_VOID__VOID, |
michael@0 | 556 | G_TYPE_NONE, 0); |
michael@0 | 557 | mai_atk_object_signals [RESTORE] = |
michael@0 | 558 | g_signal_new ("restore", |
michael@0 | 559 | MAI_TYPE_ATK_OBJECT, |
michael@0 | 560 | G_SIGNAL_RUN_LAST, |
michael@0 | 561 | 0, /* default signal handler */ |
michael@0 | 562 | nullptr, nullptr, |
michael@0 | 563 | g_cclosure_marshal_VOID__VOID, |
michael@0 | 564 | G_TYPE_NONE, 0); |
michael@0 | 565 | |
michael@0 | 566 | } |
michael@0 | 567 | |
michael@0 | 568 | void |
michael@0 | 569 | initializeCB(AtkObject *aAtkObj, gpointer aData) |
michael@0 | 570 | { |
michael@0 | 571 | NS_ASSERTION((IS_MAI_OBJECT(aAtkObj)), "Invalid AtkObject"); |
michael@0 | 572 | NS_ASSERTION(aData, "Invalid Data to init AtkObject"); |
michael@0 | 573 | if (!aAtkObj || !aData) |
michael@0 | 574 | return; |
michael@0 | 575 | |
michael@0 | 576 | /* call parent init function */ |
michael@0 | 577 | /* AtkObjectClass has not a "initialize" function now, |
michael@0 | 578 | * maybe it has later |
michael@0 | 579 | */ |
michael@0 | 580 | |
michael@0 | 581 | if (ATK_OBJECT_CLASS(parent_class)->initialize) |
michael@0 | 582 | ATK_OBJECT_CLASS(parent_class)->initialize(aAtkObj, aData); |
michael@0 | 583 | |
michael@0 | 584 | /* initialize object */ |
michael@0 | 585 | MAI_ATK_OBJECT(aAtkObj)->accWrap = |
michael@0 | 586 | static_cast<AccessibleWrap*>(aData); |
michael@0 | 587 | } |
michael@0 | 588 | |
michael@0 | 589 | void |
michael@0 | 590 | finalizeCB(GObject *aObj) |
michael@0 | 591 | { |
michael@0 | 592 | if (!IS_MAI_OBJECT(aObj)) |
michael@0 | 593 | return; |
michael@0 | 594 | NS_ASSERTION(MAI_ATK_OBJECT(aObj)->accWrap == nullptr, "AccWrap NOT null"); |
michael@0 | 595 | |
michael@0 | 596 | // call parent finalize function |
michael@0 | 597 | // finalize of GObjectClass will unref the accessible parent if has |
michael@0 | 598 | if (G_OBJECT_CLASS (parent_class)->finalize) |
michael@0 | 599 | G_OBJECT_CLASS (parent_class)->finalize(aObj); |
michael@0 | 600 | } |
michael@0 | 601 | |
michael@0 | 602 | const gchar* |
michael@0 | 603 | getNameCB(AtkObject* aAtkObj) |
michael@0 | 604 | { |
michael@0 | 605 | AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj); |
michael@0 | 606 | if (!accWrap) |
michael@0 | 607 | return nullptr; |
michael@0 | 608 | |
michael@0 | 609 | nsAutoString name; |
michael@0 | 610 | accWrap->Name(name); |
michael@0 | 611 | |
michael@0 | 612 | // XXX Firing an event from here does not seem right |
michael@0 | 613 | MaybeFireNameChange(aAtkObj, name); |
michael@0 | 614 | |
michael@0 | 615 | return aAtkObj->name; |
michael@0 | 616 | } |
michael@0 | 617 | |
michael@0 | 618 | static void |
michael@0 | 619 | MaybeFireNameChange(AtkObject* aAtkObj, const nsString& aNewName) |
michael@0 | 620 | { |
michael@0 | 621 | NS_ConvertUTF16toUTF8 newNameUTF8(aNewName); |
michael@0 | 622 | if (aAtkObj->name && newNameUTF8.Equals(aAtkObj->name)) |
michael@0 | 623 | return; |
michael@0 | 624 | |
michael@0 | 625 | // Below we duplicate the functionality of atk_object_set_name(), |
michael@0 | 626 | // but without calling atk_object_get_name(). Instead of |
michael@0 | 627 | // atk_object_get_name() we directly access aAtkObj->name. This is because |
michael@0 | 628 | // atk_object_get_name() would call getNameCB() which would call |
michael@0 | 629 | // MaybeFireNameChange() (or atk_object_set_name() before this problem was |
michael@0 | 630 | // fixed) and we would get an infinite recursion. |
michael@0 | 631 | // See http://bugzilla.mozilla.org/733712 |
michael@0 | 632 | |
michael@0 | 633 | // Do not notify for initial name setting. |
michael@0 | 634 | // See bug http://bugzilla.gnome.org/665870 |
michael@0 | 635 | bool notify = !!aAtkObj->name; |
michael@0 | 636 | |
michael@0 | 637 | free(aAtkObj->name); |
michael@0 | 638 | aAtkObj->name = strdup(newNameUTF8.get()); |
michael@0 | 639 | |
michael@0 | 640 | if (notify) |
michael@0 | 641 | g_object_notify(G_OBJECT(aAtkObj), "accessible-name"); |
michael@0 | 642 | } |
michael@0 | 643 | |
michael@0 | 644 | const gchar * |
michael@0 | 645 | getDescriptionCB(AtkObject *aAtkObj) |
michael@0 | 646 | { |
michael@0 | 647 | AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj); |
michael@0 | 648 | if (!accWrap || accWrap->IsDefunct()) |
michael@0 | 649 | return nullptr; |
michael@0 | 650 | |
michael@0 | 651 | /* nsIAccessible is responsible for the nonnull description */ |
michael@0 | 652 | nsAutoString uniDesc; |
michael@0 | 653 | accWrap->Description(uniDesc); |
michael@0 | 654 | |
michael@0 | 655 | NS_ConvertUTF8toUTF16 objDesc(aAtkObj->description); |
michael@0 | 656 | if (!uniDesc.Equals(objDesc)) |
michael@0 | 657 | atk_object_set_description(aAtkObj, |
michael@0 | 658 | NS_ConvertUTF16toUTF8(uniDesc).get()); |
michael@0 | 659 | |
michael@0 | 660 | return aAtkObj->description; |
michael@0 | 661 | } |
michael@0 | 662 | |
michael@0 | 663 | AtkRole |
michael@0 | 664 | getRoleCB(AtkObject *aAtkObj) |
michael@0 | 665 | { |
michael@0 | 666 | AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj); |
michael@0 | 667 | if (!accWrap) |
michael@0 | 668 | return ATK_ROLE_INVALID; |
michael@0 | 669 | |
michael@0 | 670 | #ifdef DEBUG |
michael@0 | 671 | NS_ASSERTION(nsAccUtils::IsTextInterfaceSupportCorrect(accWrap), |
michael@0 | 672 | "Does not support nsIAccessibleText when it should"); |
michael@0 | 673 | #endif |
michael@0 | 674 | |
michael@0 | 675 | if (aAtkObj->role != ATK_ROLE_INVALID) |
michael@0 | 676 | return aAtkObj->role; |
michael@0 | 677 | |
michael@0 | 678 | #define ROLE(geckoRole, stringRole, atkRole, macRole, \ |
michael@0 | 679 | msaaRole, ia2Role, nameRule) \ |
michael@0 | 680 | case roles::geckoRole: \ |
michael@0 | 681 | aAtkObj->role = atkRole; \ |
michael@0 | 682 | break; |
michael@0 | 683 | |
michael@0 | 684 | switch (accWrap->Role()) { |
michael@0 | 685 | #include "RoleMap.h" |
michael@0 | 686 | default: |
michael@0 | 687 | MOZ_CRASH("Unknown role."); |
michael@0 | 688 | }; |
michael@0 | 689 | |
michael@0 | 690 | #undef ROLE |
michael@0 | 691 | |
michael@0 | 692 | if (aAtkObj->role == ATK_ROLE_LIST_BOX && !IsAtkVersionAtLeast(2, 1)) |
michael@0 | 693 | aAtkObj->role = ATK_ROLE_LIST; |
michael@0 | 694 | else if (aAtkObj->role == ATK_ROLE_TABLE_ROW && !IsAtkVersionAtLeast(2, 1)) |
michael@0 | 695 | aAtkObj->role = ATK_ROLE_LIST_ITEM; |
michael@0 | 696 | |
michael@0 | 697 | return aAtkObj->role; |
michael@0 | 698 | } |
michael@0 | 699 | |
michael@0 | 700 | static AtkAttributeSet* |
michael@0 | 701 | ConvertToAtkAttributeSet(nsIPersistentProperties* aAttributes) |
michael@0 | 702 | { |
michael@0 | 703 | if (!aAttributes) |
michael@0 | 704 | return nullptr; |
michael@0 | 705 | |
michael@0 | 706 | AtkAttributeSet *objAttributeSet = nullptr; |
michael@0 | 707 | nsCOMPtr<nsISimpleEnumerator> propEnum; |
michael@0 | 708 | nsresult rv = aAttributes->Enumerate(getter_AddRefs(propEnum)); |
michael@0 | 709 | NS_ENSURE_SUCCESS(rv, nullptr); |
michael@0 | 710 | |
michael@0 | 711 | bool hasMore; |
michael@0 | 712 | while (NS_SUCCEEDED(propEnum->HasMoreElements(&hasMore)) && hasMore) { |
michael@0 | 713 | nsCOMPtr<nsISupports> sup; |
michael@0 | 714 | rv = propEnum->GetNext(getter_AddRefs(sup)); |
michael@0 | 715 | NS_ENSURE_SUCCESS(rv, objAttributeSet); |
michael@0 | 716 | |
michael@0 | 717 | nsCOMPtr<nsIPropertyElement> propElem(do_QueryInterface(sup)); |
michael@0 | 718 | NS_ENSURE_TRUE(propElem, objAttributeSet); |
michael@0 | 719 | |
michael@0 | 720 | nsAutoCString name; |
michael@0 | 721 | rv = propElem->GetKey(name); |
michael@0 | 722 | NS_ENSURE_SUCCESS(rv, objAttributeSet); |
michael@0 | 723 | |
michael@0 | 724 | nsAutoString value; |
michael@0 | 725 | rv = propElem->GetValue(value); |
michael@0 | 726 | NS_ENSURE_SUCCESS(rv, objAttributeSet); |
michael@0 | 727 | |
michael@0 | 728 | AtkAttribute *objAttr = (AtkAttribute *)g_malloc(sizeof(AtkAttribute)); |
michael@0 | 729 | objAttr->name = g_strdup(name.get()); |
michael@0 | 730 | objAttr->value = g_strdup(NS_ConvertUTF16toUTF8(value).get()); |
michael@0 | 731 | objAttributeSet = g_slist_prepend(objAttributeSet, objAttr); |
michael@0 | 732 | } |
michael@0 | 733 | |
michael@0 | 734 | //libspi will free it |
michael@0 | 735 | return objAttributeSet; |
michael@0 | 736 | } |
michael@0 | 737 | |
michael@0 | 738 | AtkAttributeSet* |
michael@0 | 739 | GetAttributeSet(Accessible* aAccessible) |
michael@0 | 740 | { |
michael@0 | 741 | nsCOMPtr<nsIPersistentProperties> attributes = aAccessible->Attributes(); |
michael@0 | 742 | if (attributes) { |
michael@0 | 743 | // There is no ATK state for haspopup, must use object attribute to expose |
michael@0 | 744 | // the same info. |
michael@0 | 745 | if (aAccessible->State() & states::HASPOPUP) { |
michael@0 | 746 | nsAutoString unused; |
michael@0 | 747 | attributes->SetStringProperty(NS_LITERAL_CSTRING("haspopup"), |
michael@0 | 748 | NS_LITERAL_STRING("true"), unused); |
michael@0 | 749 | } |
michael@0 | 750 | |
michael@0 | 751 | return ConvertToAtkAttributeSet(attributes); |
michael@0 | 752 | } |
michael@0 | 753 | |
michael@0 | 754 | return nullptr; |
michael@0 | 755 | } |
michael@0 | 756 | |
michael@0 | 757 | AtkAttributeSet * |
michael@0 | 758 | getAttributesCB(AtkObject *aAtkObj) |
michael@0 | 759 | { |
michael@0 | 760 | AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj); |
michael@0 | 761 | return accWrap ? GetAttributeSet(accWrap) : nullptr; |
michael@0 | 762 | } |
michael@0 | 763 | |
michael@0 | 764 | const gchar* |
michael@0 | 765 | GetLocaleCB(AtkObject* aAtkObj) |
michael@0 | 766 | { |
michael@0 | 767 | AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj); |
michael@0 | 768 | if (!accWrap) |
michael@0 | 769 | return nullptr; |
michael@0 | 770 | |
michael@0 | 771 | nsAutoString locale; |
michael@0 | 772 | accWrap->Language(locale); |
michael@0 | 773 | return AccessibleWrap::ReturnString(locale); |
michael@0 | 774 | } |
michael@0 | 775 | |
michael@0 | 776 | AtkObject * |
michael@0 | 777 | getParentCB(AtkObject *aAtkObj) |
michael@0 | 778 | { |
michael@0 | 779 | if (!aAtkObj->accessible_parent) { |
michael@0 | 780 | AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj); |
michael@0 | 781 | if (!accWrap) |
michael@0 | 782 | return nullptr; |
michael@0 | 783 | |
michael@0 | 784 | Accessible* accParent = accWrap->Parent(); |
michael@0 | 785 | if (!accParent) |
michael@0 | 786 | return nullptr; |
michael@0 | 787 | |
michael@0 | 788 | AtkObject* parent = AccessibleWrap::GetAtkObject(accParent); |
michael@0 | 789 | if (parent) |
michael@0 | 790 | atk_object_set_parent(aAtkObj, parent); |
michael@0 | 791 | } |
michael@0 | 792 | return aAtkObj->accessible_parent; |
michael@0 | 793 | } |
michael@0 | 794 | |
michael@0 | 795 | gint |
michael@0 | 796 | getChildCountCB(AtkObject *aAtkObj) |
michael@0 | 797 | { |
michael@0 | 798 | AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj); |
michael@0 | 799 | if (!accWrap || nsAccUtils::MustPrune(accWrap)) { |
michael@0 | 800 | return 0; |
michael@0 | 801 | } |
michael@0 | 802 | |
michael@0 | 803 | return static_cast<gint>(accWrap->EmbeddedChildCount()); |
michael@0 | 804 | } |
michael@0 | 805 | |
michael@0 | 806 | AtkObject * |
michael@0 | 807 | refChildCB(AtkObject *aAtkObj, gint aChildIndex) |
michael@0 | 808 | { |
michael@0 | 809 | // aChildIndex should not be less than zero |
michael@0 | 810 | if (aChildIndex < 0) { |
michael@0 | 811 | return nullptr; |
michael@0 | 812 | } |
michael@0 | 813 | |
michael@0 | 814 | AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj); |
michael@0 | 815 | if (!accWrap || nsAccUtils::MustPrune(accWrap)) { |
michael@0 | 816 | return nullptr; |
michael@0 | 817 | } |
michael@0 | 818 | |
michael@0 | 819 | Accessible* accChild = accWrap->GetEmbeddedChildAt(aChildIndex); |
michael@0 | 820 | if (!accChild) |
michael@0 | 821 | return nullptr; |
michael@0 | 822 | |
michael@0 | 823 | AtkObject* childAtkObj = AccessibleWrap::GetAtkObject(accChild); |
michael@0 | 824 | |
michael@0 | 825 | NS_ASSERTION(childAtkObj, "Fail to get AtkObj"); |
michael@0 | 826 | if (!childAtkObj) |
michael@0 | 827 | return nullptr; |
michael@0 | 828 | g_object_ref(childAtkObj); |
michael@0 | 829 | |
michael@0 | 830 | if (aAtkObj != childAtkObj->accessible_parent) |
michael@0 | 831 | atk_object_set_parent(childAtkObj, aAtkObj); |
michael@0 | 832 | |
michael@0 | 833 | return childAtkObj; |
michael@0 | 834 | } |
michael@0 | 835 | |
michael@0 | 836 | gint |
michael@0 | 837 | getIndexInParentCB(AtkObject *aAtkObj) |
michael@0 | 838 | { |
michael@0 | 839 | // We don't use nsIAccessible::GetIndexInParent() because |
michael@0 | 840 | // for ATK we don't want to include text leaf nodes as children |
michael@0 | 841 | AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj); |
michael@0 | 842 | if (!accWrap) { |
michael@0 | 843 | return -1; |
michael@0 | 844 | } |
michael@0 | 845 | |
michael@0 | 846 | Accessible* parent = accWrap->Parent(); |
michael@0 | 847 | if (!parent) |
michael@0 | 848 | return -1; // No parent |
michael@0 | 849 | |
michael@0 | 850 | return parent->GetIndexOfEmbeddedChild(accWrap); |
michael@0 | 851 | } |
michael@0 | 852 | |
michael@0 | 853 | static void |
michael@0 | 854 | TranslateStates(uint64_t aState, AtkStateSet* aStateSet) |
michael@0 | 855 | { |
michael@0 | 856 | // atk doesn't have a read only state so read only things shouldn't be |
michael@0 | 857 | // editable. |
michael@0 | 858 | if (aState & states::READONLY) |
michael@0 | 859 | aState &= ~states::EDITABLE; |
michael@0 | 860 | |
michael@0 | 861 | // Convert every state to an entry in AtkStateMap |
michael@0 | 862 | uint32_t stateIndex = 0; |
michael@0 | 863 | uint64_t bitMask = 1; |
michael@0 | 864 | while (gAtkStateMap[stateIndex].stateMapEntryType != kNoSuchState) { |
michael@0 | 865 | if (gAtkStateMap[stateIndex].atkState) { // There's potentially an ATK state for this |
michael@0 | 866 | bool isStateOn = (aState & bitMask) != 0; |
michael@0 | 867 | if (gAtkStateMap[stateIndex].stateMapEntryType == kMapOpposite) { |
michael@0 | 868 | isStateOn = !isStateOn; |
michael@0 | 869 | } |
michael@0 | 870 | if (isStateOn) { |
michael@0 | 871 | atk_state_set_add_state(aStateSet, gAtkStateMap[stateIndex].atkState); |
michael@0 | 872 | } |
michael@0 | 873 | } |
michael@0 | 874 | bitMask <<= 1; |
michael@0 | 875 | ++ stateIndex; |
michael@0 | 876 | } |
michael@0 | 877 | } |
michael@0 | 878 | |
michael@0 | 879 | AtkStateSet * |
michael@0 | 880 | refStateSetCB(AtkObject *aAtkObj) |
michael@0 | 881 | { |
michael@0 | 882 | AtkStateSet *state_set = nullptr; |
michael@0 | 883 | state_set = ATK_OBJECT_CLASS(parent_class)->ref_state_set(aAtkObj); |
michael@0 | 884 | |
michael@0 | 885 | AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj); |
michael@0 | 886 | if (!accWrap) { |
michael@0 | 887 | TranslateStates(states::DEFUNCT, state_set); |
michael@0 | 888 | return state_set; |
michael@0 | 889 | } |
michael@0 | 890 | |
michael@0 | 891 | // Map states |
michael@0 | 892 | TranslateStates(accWrap->State(), state_set); |
michael@0 | 893 | |
michael@0 | 894 | return state_set; |
michael@0 | 895 | } |
michael@0 | 896 | |
michael@0 | 897 | static void |
michael@0 | 898 | UpdateAtkRelation(RelationType aType, Accessible* aAcc, |
michael@0 | 899 | AtkRelationType aAtkType, AtkRelationSet* aAtkSet) |
michael@0 | 900 | { |
michael@0 | 901 | if (aAtkType == ATK_RELATION_NULL) |
michael@0 | 902 | return; |
michael@0 | 903 | |
michael@0 | 904 | AtkRelation* atkRelation = |
michael@0 | 905 | atk_relation_set_get_relation_by_type(aAtkSet, aAtkType); |
michael@0 | 906 | if (atkRelation) |
michael@0 | 907 | atk_relation_set_remove(aAtkSet, atkRelation); |
michael@0 | 908 | |
michael@0 | 909 | Relation rel(aAcc->RelationByType(aType)); |
michael@0 | 910 | nsTArray<AtkObject*> targets; |
michael@0 | 911 | Accessible* tempAcc = nullptr; |
michael@0 | 912 | while ((tempAcc = rel.Next())) |
michael@0 | 913 | targets.AppendElement(AccessibleWrap::GetAtkObject(tempAcc)); |
michael@0 | 914 | |
michael@0 | 915 | if (targets.Length()) { |
michael@0 | 916 | atkRelation = atk_relation_new(targets.Elements(), |
michael@0 | 917 | targets.Length(), aAtkType); |
michael@0 | 918 | atk_relation_set_add(aAtkSet, atkRelation); |
michael@0 | 919 | g_object_unref(atkRelation); |
michael@0 | 920 | } |
michael@0 | 921 | } |
michael@0 | 922 | |
michael@0 | 923 | AtkRelationSet * |
michael@0 | 924 | refRelationSetCB(AtkObject *aAtkObj) |
michael@0 | 925 | { |
michael@0 | 926 | AtkRelationSet* relation_set = |
michael@0 | 927 | ATK_OBJECT_CLASS(parent_class)->ref_relation_set(aAtkObj); |
michael@0 | 928 | |
michael@0 | 929 | AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj); |
michael@0 | 930 | if (!accWrap) |
michael@0 | 931 | return relation_set; |
michael@0 | 932 | |
michael@0 | 933 | #define RELATIONTYPE(geckoType, geckoTypeName, atkType, msaaType, ia2Type) \ |
michael@0 | 934 | UpdateAtkRelation(RelationType::geckoType, accWrap, atkType, relation_set); |
michael@0 | 935 | |
michael@0 | 936 | #include "RelationTypeMap.h" |
michael@0 | 937 | |
michael@0 | 938 | #undef RELATIONTYPE |
michael@0 | 939 | |
michael@0 | 940 | return relation_set; |
michael@0 | 941 | } |
michael@0 | 942 | |
michael@0 | 943 | // Check if aAtkObj is a valid MaiAtkObject, and return the AccessibleWrap |
michael@0 | 944 | // for it. |
michael@0 | 945 | AccessibleWrap* |
michael@0 | 946 | GetAccessibleWrap(AtkObject* aAtkObj) |
michael@0 | 947 | { |
michael@0 | 948 | NS_ENSURE_TRUE(IS_MAI_OBJECT(aAtkObj), nullptr); |
michael@0 | 949 | AccessibleWrap* accWrap = MAI_ATK_OBJECT(aAtkObj)->accWrap; |
michael@0 | 950 | |
michael@0 | 951 | // Check if the accessible was deconstructed. |
michael@0 | 952 | if (!accWrap) |
michael@0 | 953 | return nullptr; |
michael@0 | 954 | |
michael@0 | 955 | NS_ENSURE_TRUE(accWrap->GetAtkObject() == aAtkObj, nullptr); |
michael@0 | 956 | |
michael@0 | 957 | AccessibleWrap* appAccWrap = ApplicationAcc(); |
michael@0 | 958 | if (appAccWrap != accWrap && !accWrap->IsValidObject()) |
michael@0 | 959 | return nullptr; |
michael@0 | 960 | |
michael@0 | 961 | return accWrap; |
michael@0 | 962 | } |
michael@0 | 963 | |
michael@0 | 964 | nsresult |
michael@0 | 965 | AccessibleWrap::HandleAccEvent(AccEvent* aEvent) |
michael@0 | 966 | { |
michael@0 | 967 | nsresult rv = Accessible::HandleAccEvent(aEvent); |
michael@0 | 968 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 969 | |
michael@0 | 970 | Accessible* accessible = aEvent->GetAccessible(); |
michael@0 | 971 | NS_ENSURE_TRUE(accessible, NS_ERROR_FAILURE); |
michael@0 | 972 | |
michael@0 | 973 | // The accessible can become defunct if we have an xpcom event listener |
michael@0 | 974 | // which decides it would be fun to change the DOM and flush layout. |
michael@0 | 975 | if (accessible->IsDefunct()) |
michael@0 | 976 | return NS_OK; |
michael@0 | 977 | |
michael@0 | 978 | uint32_t type = aEvent->GetEventType(); |
michael@0 | 979 | |
michael@0 | 980 | AtkObject* atkObj = AccessibleWrap::GetAtkObject(accessible); |
michael@0 | 981 | |
michael@0 | 982 | // We don't create ATK objects for nsIAccessible plain text leaves, |
michael@0 | 983 | // just return NS_OK in such case |
michael@0 | 984 | if (!atkObj) { |
michael@0 | 985 | NS_ASSERTION(type == nsIAccessibleEvent::EVENT_SHOW || |
michael@0 | 986 | type == nsIAccessibleEvent::EVENT_HIDE, |
michael@0 | 987 | "Event other than SHOW and HIDE fired for plain text leaves"); |
michael@0 | 988 | return NS_OK; |
michael@0 | 989 | } |
michael@0 | 990 | |
michael@0 | 991 | AccessibleWrap* accWrap = GetAccessibleWrap(atkObj); |
michael@0 | 992 | if (!accWrap) { |
michael@0 | 993 | return NS_OK; // Node is shut down |
michael@0 | 994 | } |
michael@0 | 995 | |
michael@0 | 996 | switch (type) { |
michael@0 | 997 | case nsIAccessibleEvent::EVENT_STATE_CHANGE: |
michael@0 | 998 | return FireAtkStateChangeEvent(aEvent, atkObj); |
michael@0 | 999 | |
michael@0 | 1000 | case nsIAccessibleEvent::EVENT_TEXT_REMOVED: |
michael@0 | 1001 | case nsIAccessibleEvent::EVENT_TEXT_INSERTED: |
michael@0 | 1002 | return FireAtkTextChangedEvent(aEvent, atkObj); |
michael@0 | 1003 | |
michael@0 | 1004 | case nsIAccessibleEvent::EVENT_FOCUS: |
michael@0 | 1005 | { |
michael@0 | 1006 | a11y::RootAccessible* rootAccWrap = accWrap->RootAccessible(); |
michael@0 | 1007 | if (rootAccWrap && rootAccWrap->mActivated) { |
michael@0 | 1008 | atk_focus_tracker_notify(atkObj); |
michael@0 | 1009 | // Fire state change event for focus |
michael@0 | 1010 | atk_object_notify_state_change(atkObj, ATK_STATE_FOCUSED, true); |
michael@0 | 1011 | return NS_OK; |
michael@0 | 1012 | } |
michael@0 | 1013 | } break; |
michael@0 | 1014 | |
michael@0 | 1015 | case nsIAccessibleEvent::EVENT_NAME_CHANGE: |
michael@0 | 1016 | { |
michael@0 | 1017 | nsAutoString newName; |
michael@0 | 1018 | accessible->Name(newName); |
michael@0 | 1019 | |
michael@0 | 1020 | MaybeFireNameChange(atkObj, newName); |
michael@0 | 1021 | |
michael@0 | 1022 | break; |
michael@0 | 1023 | } |
michael@0 | 1024 | case nsIAccessibleEvent::EVENT_VALUE_CHANGE: |
michael@0 | 1025 | { |
michael@0 | 1026 | nsCOMPtr<nsIAccessibleValue> value(do_QueryObject(accessible)); |
michael@0 | 1027 | if (value) { // Make sure this is a numeric value |
michael@0 | 1028 | // Don't fire for MSAA string value changes (e.g. text editing) |
michael@0 | 1029 | // ATK values are always numeric |
michael@0 | 1030 | g_object_notify( (GObject*)atkObj, "accessible-value" ); |
michael@0 | 1031 | } |
michael@0 | 1032 | } break; |
michael@0 | 1033 | |
michael@0 | 1034 | case nsIAccessibleEvent::EVENT_SELECTION: |
michael@0 | 1035 | case nsIAccessibleEvent::EVENT_SELECTION_ADD: |
michael@0 | 1036 | case nsIAccessibleEvent::EVENT_SELECTION_REMOVE: |
michael@0 | 1037 | { |
michael@0 | 1038 | // XXX: dupe events may be fired |
michael@0 | 1039 | AccSelChangeEvent* selChangeEvent = downcast_accEvent(aEvent); |
michael@0 | 1040 | g_signal_emit_by_name(AccessibleWrap::GetAtkObject(selChangeEvent->Widget()), |
michael@0 | 1041 | "selection_changed"); |
michael@0 | 1042 | break; |
michael@0 | 1043 | } |
michael@0 | 1044 | |
michael@0 | 1045 | case nsIAccessibleEvent::EVENT_SELECTION_WITHIN: |
michael@0 | 1046 | { |
michael@0 | 1047 | g_signal_emit_by_name(atkObj, "selection_changed"); |
michael@0 | 1048 | break; |
michael@0 | 1049 | } |
michael@0 | 1050 | |
michael@0 | 1051 | case nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED: |
michael@0 | 1052 | g_signal_emit_by_name(atkObj, "text_selection_changed"); |
michael@0 | 1053 | break; |
michael@0 | 1054 | |
michael@0 | 1055 | case nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED: |
michael@0 | 1056 | { |
michael@0 | 1057 | AccCaretMoveEvent* caretMoveEvent = downcast_accEvent(aEvent); |
michael@0 | 1058 | NS_ASSERTION(caretMoveEvent, "Event needs event data"); |
michael@0 | 1059 | if (!caretMoveEvent) |
michael@0 | 1060 | break; |
michael@0 | 1061 | |
michael@0 | 1062 | int32_t caretOffset = caretMoveEvent->GetCaretOffset(); |
michael@0 | 1063 | g_signal_emit_by_name(atkObj, "text_caret_moved", caretOffset); |
michael@0 | 1064 | } break; |
michael@0 | 1065 | |
michael@0 | 1066 | case nsIAccessibleEvent::EVENT_TEXT_ATTRIBUTE_CHANGED: |
michael@0 | 1067 | g_signal_emit_by_name(atkObj, "text-attributes-changed"); |
michael@0 | 1068 | break; |
michael@0 | 1069 | |
michael@0 | 1070 | case nsIAccessibleEvent::EVENT_TABLE_MODEL_CHANGED: |
michael@0 | 1071 | g_signal_emit_by_name(atkObj, "model_changed"); |
michael@0 | 1072 | break; |
michael@0 | 1073 | |
michael@0 | 1074 | case nsIAccessibleEvent::EVENT_TABLE_ROW_INSERT: |
michael@0 | 1075 | { |
michael@0 | 1076 | AccTableChangeEvent* tableEvent = downcast_accEvent(aEvent); |
michael@0 | 1077 | NS_ENSURE_TRUE(tableEvent, NS_ERROR_FAILURE); |
michael@0 | 1078 | |
michael@0 | 1079 | int32_t rowIndex = tableEvent->GetIndex(); |
michael@0 | 1080 | int32_t numRows = tableEvent->GetCount(); |
michael@0 | 1081 | |
michael@0 | 1082 | g_signal_emit_by_name(atkObj, "row_inserted", rowIndex, numRows); |
michael@0 | 1083 | } break; |
michael@0 | 1084 | |
michael@0 | 1085 | case nsIAccessibleEvent::EVENT_TABLE_ROW_DELETE: |
michael@0 | 1086 | { |
michael@0 | 1087 | AccTableChangeEvent* tableEvent = downcast_accEvent(aEvent); |
michael@0 | 1088 | NS_ENSURE_TRUE(tableEvent, NS_ERROR_FAILURE); |
michael@0 | 1089 | |
michael@0 | 1090 | int32_t rowIndex = tableEvent->GetIndex(); |
michael@0 | 1091 | int32_t numRows = tableEvent->GetCount(); |
michael@0 | 1092 | |
michael@0 | 1093 | g_signal_emit_by_name(atkObj, "row_deleted", rowIndex, numRows); |
michael@0 | 1094 | } break; |
michael@0 | 1095 | |
michael@0 | 1096 | case nsIAccessibleEvent::EVENT_TABLE_ROW_REORDER: |
michael@0 | 1097 | { |
michael@0 | 1098 | g_signal_emit_by_name(atkObj, "row_reordered"); |
michael@0 | 1099 | break; |
michael@0 | 1100 | } |
michael@0 | 1101 | |
michael@0 | 1102 | case nsIAccessibleEvent::EVENT_TABLE_COLUMN_INSERT: |
michael@0 | 1103 | { |
michael@0 | 1104 | AccTableChangeEvent* tableEvent = downcast_accEvent(aEvent); |
michael@0 | 1105 | NS_ENSURE_TRUE(tableEvent, NS_ERROR_FAILURE); |
michael@0 | 1106 | |
michael@0 | 1107 | int32_t colIndex = tableEvent->GetIndex(); |
michael@0 | 1108 | int32_t numCols = tableEvent->GetCount(); |
michael@0 | 1109 | g_signal_emit_by_name(atkObj, "column_inserted", colIndex, numCols); |
michael@0 | 1110 | } break; |
michael@0 | 1111 | |
michael@0 | 1112 | case nsIAccessibleEvent::EVENT_TABLE_COLUMN_DELETE: |
michael@0 | 1113 | { |
michael@0 | 1114 | AccTableChangeEvent* tableEvent = downcast_accEvent(aEvent); |
michael@0 | 1115 | NS_ENSURE_TRUE(tableEvent, NS_ERROR_FAILURE); |
michael@0 | 1116 | |
michael@0 | 1117 | int32_t colIndex = tableEvent->GetIndex(); |
michael@0 | 1118 | int32_t numCols = tableEvent->GetCount(); |
michael@0 | 1119 | g_signal_emit_by_name(atkObj, "column_deleted", colIndex, numCols); |
michael@0 | 1120 | } break; |
michael@0 | 1121 | |
michael@0 | 1122 | case nsIAccessibleEvent::EVENT_TABLE_COLUMN_REORDER: |
michael@0 | 1123 | g_signal_emit_by_name(atkObj, "column_reordered"); |
michael@0 | 1124 | break; |
michael@0 | 1125 | |
michael@0 | 1126 | case nsIAccessibleEvent::EVENT_SECTION_CHANGED: |
michael@0 | 1127 | g_signal_emit_by_name(atkObj, "visible_data_changed"); |
michael@0 | 1128 | break; |
michael@0 | 1129 | |
michael@0 | 1130 | case nsIAccessibleEvent::EVENT_SHOW: |
michael@0 | 1131 | return FireAtkShowHideEvent(aEvent, atkObj, true); |
michael@0 | 1132 | |
michael@0 | 1133 | case nsIAccessibleEvent::EVENT_HIDE: |
michael@0 | 1134 | // XXX - Handle native dialog accessibles. |
michael@0 | 1135 | if (!accessible->IsRoot() && accessible->HasARIARole() && |
michael@0 | 1136 | accessible->ARIARole() == roles::DIALOG) { |
michael@0 | 1137 | guint id = g_signal_lookup("deactivate", MAI_TYPE_ATK_OBJECT); |
michael@0 | 1138 | g_signal_emit(atkObj, id, 0); |
michael@0 | 1139 | } |
michael@0 | 1140 | return FireAtkShowHideEvent(aEvent, atkObj, false); |
michael@0 | 1141 | |
michael@0 | 1142 | /* |
michael@0 | 1143 | * Because dealing with menu is very different between nsIAccessible |
michael@0 | 1144 | * and ATK, and the menu activity is important, specially transfer the |
michael@0 | 1145 | * following two event. |
michael@0 | 1146 | * Need more verification by AT test. |
michael@0 | 1147 | */ |
michael@0 | 1148 | case nsIAccessibleEvent::EVENT_MENU_START: |
michael@0 | 1149 | case nsIAccessibleEvent::EVENT_MENU_END: |
michael@0 | 1150 | break; |
michael@0 | 1151 | |
michael@0 | 1152 | case nsIAccessibleEvent::EVENT_WINDOW_ACTIVATE: |
michael@0 | 1153 | { |
michael@0 | 1154 | accessible->AsRoot()->mActivated = true; |
michael@0 | 1155 | guint id = g_signal_lookup("activate", MAI_TYPE_ATK_OBJECT); |
michael@0 | 1156 | g_signal_emit(atkObj, id, 0); |
michael@0 | 1157 | |
michael@0 | 1158 | // Always fire a current focus event after activation. |
michael@0 | 1159 | FocusMgr()->ForceFocusEvent(); |
michael@0 | 1160 | } break; |
michael@0 | 1161 | |
michael@0 | 1162 | case nsIAccessibleEvent::EVENT_WINDOW_DEACTIVATE: |
michael@0 | 1163 | { |
michael@0 | 1164 | accessible->AsRoot()->mActivated = false; |
michael@0 | 1165 | guint id = g_signal_lookup("deactivate", MAI_TYPE_ATK_OBJECT); |
michael@0 | 1166 | g_signal_emit(atkObj, id, 0); |
michael@0 | 1167 | } break; |
michael@0 | 1168 | |
michael@0 | 1169 | case nsIAccessibleEvent::EVENT_WINDOW_MAXIMIZE: |
michael@0 | 1170 | { |
michael@0 | 1171 | guint id = g_signal_lookup("maximize", MAI_TYPE_ATK_OBJECT); |
michael@0 | 1172 | g_signal_emit(atkObj, id, 0); |
michael@0 | 1173 | } break; |
michael@0 | 1174 | |
michael@0 | 1175 | case nsIAccessibleEvent::EVENT_WINDOW_MINIMIZE: |
michael@0 | 1176 | { |
michael@0 | 1177 | guint id = g_signal_lookup("minimize", MAI_TYPE_ATK_OBJECT); |
michael@0 | 1178 | g_signal_emit(atkObj, id, 0); |
michael@0 | 1179 | } break; |
michael@0 | 1180 | |
michael@0 | 1181 | case nsIAccessibleEvent::EVENT_WINDOW_RESTORE: |
michael@0 | 1182 | { |
michael@0 | 1183 | guint id = g_signal_lookup("restore", MAI_TYPE_ATK_OBJECT); |
michael@0 | 1184 | g_signal_emit(atkObj, id, 0); |
michael@0 | 1185 | } break; |
michael@0 | 1186 | |
michael@0 | 1187 | case nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_COMPLETE: |
michael@0 | 1188 | g_signal_emit_by_name (atkObj, "load_complete"); |
michael@0 | 1189 | // XXX - Handle native dialog accessibles. |
michael@0 | 1190 | if (!accessible->IsRoot() && accessible->HasARIARole() && |
michael@0 | 1191 | accessible->ARIARole() == roles::DIALOG) { |
michael@0 | 1192 | guint id = g_signal_lookup("activate", MAI_TYPE_ATK_OBJECT); |
michael@0 | 1193 | g_signal_emit(atkObj, id, 0); |
michael@0 | 1194 | } |
michael@0 | 1195 | break; |
michael@0 | 1196 | |
michael@0 | 1197 | case nsIAccessibleEvent::EVENT_DOCUMENT_RELOAD: |
michael@0 | 1198 | g_signal_emit_by_name (atkObj, "reload"); |
michael@0 | 1199 | break; |
michael@0 | 1200 | |
michael@0 | 1201 | case nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_STOPPED: |
michael@0 | 1202 | g_signal_emit_by_name (atkObj, "load_stopped"); |
michael@0 | 1203 | break; |
michael@0 | 1204 | |
michael@0 | 1205 | case nsIAccessibleEvent::EVENT_MENUPOPUP_START: |
michael@0 | 1206 | atk_focus_tracker_notify(atkObj); // fire extra focus event |
michael@0 | 1207 | atk_object_notify_state_change(atkObj, ATK_STATE_VISIBLE, true); |
michael@0 | 1208 | atk_object_notify_state_change(atkObj, ATK_STATE_SHOWING, true); |
michael@0 | 1209 | break; |
michael@0 | 1210 | |
michael@0 | 1211 | case nsIAccessibleEvent::EVENT_MENUPOPUP_END: |
michael@0 | 1212 | atk_object_notify_state_change(atkObj, ATK_STATE_VISIBLE, false); |
michael@0 | 1213 | atk_object_notify_state_change(atkObj, ATK_STATE_SHOWING, false); |
michael@0 | 1214 | break; |
michael@0 | 1215 | } |
michael@0 | 1216 | |
michael@0 | 1217 | return NS_OK; |
michael@0 | 1218 | } |
michael@0 | 1219 | |
michael@0 | 1220 | nsresult |
michael@0 | 1221 | AccessibleWrap::FireAtkStateChangeEvent(AccEvent* aEvent, |
michael@0 | 1222 | AtkObject* aObject) |
michael@0 | 1223 | { |
michael@0 | 1224 | AccStateChangeEvent* event = downcast_accEvent(aEvent); |
michael@0 | 1225 | NS_ENSURE_TRUE(event, NS_ERROR_FAILURE); |
michael@0 | 1226 | |
michael@0 | 1227 | bool isEnabled = event->IsStateEnabled(); |
michael@0 | 1228 | int32_t stateIndex = AtkStateMap::GetStateIndexFor(event->GetState()); |
michael@0 | 1229 | if (stateIndex >= 0) { |
michael@0 | 1230 | NS_ASSERTION(gAtkStateMap[stateIndex].stateMapEntryType != kNoSuchState, |
michael@0 | 1231 | "No such state"); |
michael@0 | 1232 | |
michael@0 | 1233 | if (gAtkStateMap[stateIndex].atkState != kNone) { |
michael@0 | 1234 | NS_ASSERTION(gAtkStateMap[stateIndex].stateMapEntryType != kNoStateChange, |
michael@0 | 1235 | "State changes should not fired for this state"); |
michael@0 | 1236 | |
michael@0 | 1237 | if (gAtkStateMap[stateIndex].stateMapEntryType == kMapOpposite) |
michael@0 | 1238 | isEnabled = !isEnabled; |
michael@0 | 1239 | |
michael@0 | 1240 | // Fire state change for first state if there is one to map |
michael@0 | 1241 | atk_object_notify_state_change(aObject, |
michael@0 | 1242 | gAtkStateMap[stateIndex].atkState, |
michael@0 | 1243 | isEnabled); |
michael@0 | 1244 | } |
michael@0 | 1245 | } |
michael@0 | 1246 | |
michael@0 | 1247 | return NS_OK; |
michael@0 | 1248 | } |
michael@0 | 1249 | |
michael@0 | 1250 | nsresult |
michael@0 | 1251 | AccessibleWrap::FireAtkTextChangedEvent(AccEvent* aEvent, |
michael@0 | 1252 | AtkObject* aObject) |
michael@0 | 1253 | { |
michael@0 | 1254 | AccTextChangeEvent* event = downcast_accEvent(aEvent); |
michael@0 | 1255 | NS_ENSURE_TRUE(event, NS_ERROR_FAILURE); |
michael@0 | 1256 | |
michael@0 | 1257 | int32_t start = event->GetStartOffset(); |
michael@0 | 1258 | uint32_t length = event->GetLength(); |
michael@0 | 1259 | bool isInserted = event->IsTextInserted(); |
michael@0 | 1260 | bool isFromUserInput = aEvent->IsFromUserInput(); |
michael@0 | 1261 | char* signal_name = nullptr; |
michael@0 | 1262 | |
michael@0 | 1263 | if (gAvailableAtkSignals == eUnknown) |
michael@0 | 1264 | gAvailableAtkSignals = |
michael@0 | 1265 | g_signal_lookup("text-insert", G_OBJECT_TYPE(aObject)) ? |
michael@0 | 1266 | eHaveNewAtkTextSignals : eNoNewAtkSignals; |
michael@0 | 1267 | |
michael@0 | 1268 | if (gAvailableAtkSignals == eNoNewAtkSignals) { |
michael@0 | 1269 | // XXX remove this code and the gHaveNewTextSignals check when we can |
michael@0 | 1270 | // stop supporting old atk since it doesn't really work anyway |
michael@0 | 1271 | // see bug 619002 |
michael@0 | 1272 | signal_name = g_strconcat(isInserted ? "text_changed::insert" : |
michael@0 | 1273 | "text_changed::delete", |
michael@0 | 1274 | isFromUserInput ? "" : kNonUserInputEvent, nullptr); |
michael@0 | 1275 | g_signal_emit_by_name(aObject, signal_name, start, length); |
michael@0 | 1276 | } else { |
michael@0 | 1277 | nsAutoString text; |
michael@0 | 1278 | event->GetModifiedText(text); |
michael@0 | 1279 | signal_name = g_strconcat(isInserted ? "text-insert" : "text-remove", |
michael@0 | 1280 | isFromUserInput ? "" : "::system", nullptr); |
michael@0 | 1281 | g_signal_emit_by_name(aObject, signal_name, start, length, |
michael@0 | 1282 | NS_ConvertUTF16toUTF8(text).get()); |
michael@0 | 1283 | } |
michael@0 | 1284 | |
michael@0 | 1285 | g_free(signal_name); |
michael@0 | 1286 | return NS_OK; |
michael@0 | 1287 | } |
michael@0 | 1288 | |
michael@0 | 1289 | nsresult |
michael@0 | 1290 | AccessibleWrap::FireAtkShowHideEvent(AccEvent* aEvent, |
michael@0 | 1291 | AtkObject* aObject, bool aIsAdded) |
michael@0 | 1292 | { |
michael@0 | 1293 | int32_t indexInParent = getIndexInParentCB(aObject); |
michael@0 | 1294 | AtkObject *parentObject = getParentCB(aObject); |
michael@0 | 1295 | NS_ENSURE_STATE(parentObject); |
michael@0 | 1296 | |
michael@0 | 1297 | bool isFromUserInput = aEvent->IsFromUserInput(); |
michael@0 | 1298 | char *signal_name = g_strconcat(aIsAdded ? "children_changed::add" : "children_changed::remove", |
michael@0 | 1299 | isFromUserInput ? "" : kNonUserInputEvent, nullptr); |
michael@0 | 1300 | g_signal_emit_by_name(parentObject, signal_name, indexInParent, aObject, nullptr); |
michael@0 | 1301 | g_free(signal_name); |
michael@0 | 1302 | |
michael@0 | 1303 | return NS_OK; |
michael@0 | 1304 | } |