1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20 #include "atkwrapper.hxx"
21 #include <com/sun/star/accessibility/XAccessibleComponent.hpp>
22 #include <gtk/gtk.h>
23
24 using namespace ::com::sun::star;
25
getObjectWrapper(AtkComponent * pComponent)26 static AtkObjectWrapper* getObjectWrapper(AtkComponent *pComponent)
27 {
28 AtkObjectWrapper *pWrap = nullptr;
29 if (ATK_IS_OBJECT_WRAPPER(pComponent))
30 pWrap = ATK_OBJECT_WRAPPER(pComponent);
31 else if (GTK_IS_DRAWING_AREA(pComponent)) //when using a GtkDrawingArea as a custom widget in welded gtk3
32 {
33 GtkWidget* pDrawingArea = GTK_WIDGET(pComponent);
34 AtkObject* pAtkObject = gtk_widget_get_accessible(pDrawingArea);
35 pWrap = ATK_IS_OBJECT_WRAPPER(pAtkObject) ? ATK_OBJECT_WRAPPER(pAtkObject) : nullptr;
36 }
37 return pWrap;
38 }
39
40 /// @throws uno::RuntimeException
41 static css::uno::Reference<css::accessibility::XAccessibleComponent>
getComponent(AtkObjectWrapper * pWrap)42 getComponent(AtkObjectWrapper *pWrap)
43 {
44 if (pWrap)
45 {
46 if (!pWrap->mpComponent.is())
47 pWrap->mpComponent.set(pWrap->mpContext, css::uno::UNO_QUERY);
48 return pWrap->mpComponent;
49 }
50
51 return css::uno::Reference<css::accessibility::XAccessibleComponent>();
52 }
53
54 /*****************************************************************************/
55
56 static awt::Point
translatePoint(css::uno::Reference<accessibility::XAccessibleComponent> const & pComponent,gint x,gint y,AtkCoordType t)57 translatePoint( css::uno::Reference<accessibility::XAccessibleComponent> const & pComponent,
58 gint x, gint y, AtkCoordType t)
59 {
60 awt::Point aOrigin( 0, 0 );
61 if( t == ATK_XY_SCREEN )
62 aOrigin = pComponent->getLocationOnScreen();
63 return awt::Point( x - aOrigin.X, y - aOrigin.Y );
64 }
65
66 /*****************************************************************************/
67
68 extern "C" {
69
70 static gboolean
component_wrapper_grab_focus(AtkComponent * component)71 component_wrapper_grab_focus (AtkComponent *component)
72 {
73 AtkObjectWrapper* obj = getObjectWrapper(component);
74 //if we're a native GtkDrawingArea with custom a11y, use the default toolkit a11y
75 if (obj && obj->mpOrig)
76 return atk_component_grab_focus(ATK_COMPONENT(obj->mpOrig));
77
78 try
79 {
80 css::uno::Reference<css::accessibility::XAccessibleComponent> pComponent
81 = getComponent(obj);
82 if( pComponent.is() )
83 {
84 pComponent->grabFocus();
85 return TRUE;
86 }
87 }
88 catch( const uno::Exception & )
89 {
90 g_warning( "Exception in grabFocus()" );
91 }
92
93 return FALSE;
94 }
95
96 /*****************************************************************************/
97
98 static gboolean
component_wrapper_contains(AtkComponent * component,gint x,gint y,AtkCoordType coord_type)99 component_wrapper_contains (AtkComponent *component,
100 gint x,
101 gint y,
102 AtkCoordType coord_type)
103 {
104 AtkObjectWrapper* obj = getObjectWrapper(component);
105 //if we're a native GtkDrawingArea with custom a11y, use the default toolkit a11y
106 if (obj && obj->mpOrig)
107 return atk_component_contains(ATK_COMPONENT(obj->mpOrig), x, y, coord_type);
108
109 try
110 {
111 css::uno::Reference<css::accessibility::XAccessibleComponent> pComponent
112 = getComponent(obj);
113 if( pComponent.is() )
114 return pComponent->containsPoint( translatePoint( pComponent, x, y, coord_type ) );
115 }
116 catch( const uno::Exception & )
117 {
118 g_warning( "Exception in containsPoint()" );
119 }
120
121 return FALSE;
122 }
123
124 /*****************************************************************************/
125
126 static AtkObject *
component_wrapper_ref_accessible_at_point(AtkComponent * component,gint x,gint y,AtkCoordType coord_type)127 component_wrapper_ref_accessible_at_point (AtkComponent *component,
128 gint x,
129 gint y,
130 AtkCoordType coord_type)
131 {
132 AtkObjectWrapper* obj = getObjectWrapper(component);
133 //if we're a native GtkDrawingArea with custom a11y, use the default toolkit a11y
134 if (obj && obj->mpOrig)
135 return atk_component_ref_accessible_at_point(ATK_COMPONENT(obj->mpOrig), x, y, coord_type);
136
137 try
138 {
139 css::uno::Reference<css::accessibility::XAccessibleComponent> pComponent
140 = getComponent(obj);
141
142 if( pComponent.is() )
143 {
144 uno::Reference< accessibility::XAccessible > xAccessible = pComponent->getAccessibleAtPoint(
145 translatePoint( pComponent, x, y, coord_type ) );
146 return atk_object_wrapper_ref( xAccessible );
147 }
148 }
149 catch( const uno::Exception & )
150 {
151 g_warning( "Exception in getAccessibleAtPoint()" );
152 }
153
154 return nullptr;
155 }
156
157 /*****************************************************************************/
158
159 static void
component_wrapper_get_position(AtkComponent * component,gint * x,gint * y,AtkCoordType coord_type)160 component_wrapper_get_position (AtkComponent *component,
161 gint *x,
162 gint *y,
163 AtkCoordType coord_type)
164 {
165 AtkObjectWrapper* obj = getObjectWrapper(component);
166 //if we're a native GtkDrawingArea with custom a11y, use the default toolkit a11y
167 if (obj && obj->mpOrig)
168 {
169 atk_component_get_extents(ATK_COMPONENT(obj->mpOrig), x, y, nullptr, nullptr, coord_type);
170 return;
171 }
172
173 *x = *y = -1;
174
175 try
176 {
177 css::uno::Reference<css::accessibility::XAccessibleComponent> pComponent
178 = getComponent(obj);
179 if( pComponent.is() )
180 {
181 awt::Point aPos;
182
183 if( coord_type == ATK_XY_SCREEN )
184 aPos = pComponent->getLocationOnScreen();
185 else
186 aPos = pComponent->getLocation();
187
188 *x = aPos.X;
189 *y = aPos.Y;
190 }
191 }
192 catch( const uno::Exception & )
193 {
194 g_warning( "Exception in getLocation[OnScreen]()" );
195 }
196 }
197
198 /*****************************************************************************/
199
200 static void
component_wrapper_get_size(AtkComponent * component,gint * width,gint * height)201 component_wrapper_get_size (AtkComponent *component,
202 gint *width,
203 gint *height)
204 {
205 AtkObjectWrapper* obj = getObjectWrapper(component);
206 //if we're a native GtkDrawingArea with custom a11y, use the default toolkit a11y
207 if (obj && obj->mpOrig)
208 {
209 atk_component_get_extents(ATK_COMPONENT(obj->mpOrig), nullptr, nullptr, width, height, ATK_XY_WINDOW);
210 return;
211 }
212
213 *width = *height = -1;
214
215 try
216 {
217 css::uno::Reference<css::accessibility::XAccessibleComponent> pComponent
218 = getComponent(obj);
219 if( pComponent.is() )
220 {
221 awt::Size aSize = pComponent->getSize();
222 *width = aSize.Width;
223 *height = aSize.Height;
224 }
225 }
226 catch( const uno::Exception & )
227 {
228 g_warning( "Exception in getSize()" );
229 }
230 }
231
232 /*****************************************************************************/
233
234 static void
component_wrapper_get_extents(AtkComponent * component,gint * x,gint * y,gint * width,gint * height,AtkCoordType coord_type)235 component_wrapper_get_extents (AtkComponent *component,
236 gint *x,
237 gint *y,
238 gint *width,
239 gint *height,
240 AtkCoordType coord_type)
241 {
242 component_wrapper_get_position( component, x, y, coord_type );
243 component_wrapper_get_size( component, width, height );
244 }
245
246 /*****************************************************************************/
247
248 static gboolean
component_wrapper_set_extents(AtkComponent *,gint,gint,gint,gint,AtkCoordType)249 component_wrapper_set_extents (AtkComponent *, gint, gint, gint, gint, AtkCoordType)
250 {
251 g_warning( "AtkComponent::set_extents unimplementable" );
252 return FALSE;
253 }
254
255 /*****************************************************************************/
256
257 static gboolean
component_wrapper_set_position(AtkComponent *,gint,gint,AtkCoordType)258 component_wrapper_set_position (AtkComponent *, gint, gint, AtkCoordType)
259 {
260 g_warning( "AtkComponent::set_position unimplementable" );
261 return FALSE;
262 }
263
264 /*****************************************************************************/
265
266 static gboolean
component_wrapper_set_size(AtkComponent *,gint,gint)267 component_wrapper_set_size (AtkComponent *, gint, gint)
268 {
269 g_warning( "AtkComponent::set_size unimplementable" );
270 return FALSE;
271 }
272
273 /*****************************************************************************/
274
275 static AtkLayer
component_wrapper_get_layer(AtkComponent * component)276 component_wrapper_get_layer (AtkComponent *component)
277 {
278 AtkRole role = atk_object_get_role( ATK_OBJECT( component ) );
279 AtkLayer layer = ATK_LAYER_WIDGET;
280
281 switch (role)
282 {
283 case ATK_ROLE_POPUP_MENU:
284 case ATK_ROLE_MENU_ITEM:
285 case ATK_ROLE_CHECK_MENU_ITEM:
286 case ATK_ROLE_SEPARATOR:
287 case ATK_ROLE_LIST_ITEM:
288 layer = ATK_LAYER_POPUP;
289 break;
290 case ATK_ROLE_MENU:
291 {
292 AtkObject * parent = atk_object_get_parent( ATK_OBJECT( component ) );
293 if( atk_object_get_role( parent ) != ATK_ROLE_MENU_BAR )
294 layer = ATK_LAYER_POPUP;
295 }
296 break;
297
298 case ATK_ROLE_LIST:
299 {
300 AtkObject * parent = atk_object_get_parent( ATK_OBJECT( component ) );
301 if( atk_object_get_role( parent ) == ATK_ROLE_COMBO_BOX )
302 layer = ATK_LAYER_POPUP;
303 }
304 break;
305
306 default:
307 ;
308 }
309
310 return layer;
311 }
312
313 /*****************************************************************************/
314
315 static gint
component_wrapper_get_mdi_zorder(AtkComponent *)316 component_wrapper_get_mdi_zorder (AtkComponent *)
317 {
318 // only needed for ATK_LAYER_MDI (not used) or ATK_LAYER_WINDOW (inherited from GAIL)
319 return G_MININT;
320 }
321
322 /*****************************************************************************/
323
324 // This code is mostly stolen from libgail ..
325
326 static guint
component_wrapper_add_focus_handler(AtkComponent * component,AtkFocusHandler handler)327 component_wrapper_add_focus_handler (AtkComponent *component,
328 AtkFocusHandler handler)
329 {
330 GSignalMatchType match_type;
331 gulong ret;
332 guint signal_id;
333
334 match_type = GSignalMatchType(G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_FUNC);
335 signal_id = g_signal_lookup( "focus-event", ATK_TYPE_OBJECT );
336
337 ret = g_signal_handler_find( component, match_type, signal_id, 0, nullptr,
338 static_cast<gpointer>(&handler), nullptr);
339 if (!ret)
340 {
341 return g_signal_connect_closure_by_id (component,
342 signal_id, 0,
343 g_cclosure_new (
344 G_CALLBACK (handler), nullptr,
345 nullptr),
346 FALSE);
347 }
348 else
349 {
350 return 0;
351 }
352 }
353
354 /*****************************************************************************/
355
356 static void
component_wrapper_remove_focus_handler(AtkComponent * component,guint handler_id)357 component_wrapper_remove_focus_handler (AtkComponent *component,
358 guint handler_id)
359 {
360 g_signal_handler_disconnect (component, handler_id);
361 }
362
363 /*****************************************************************************/
364
365 } // extern "C"
366
367 void
componentIfaceInit(AtkComponentIface * iface)368 componentIfaceInit (AtkComponentIface *iface)
369 {
370 g_return_if_fail (iface != nullptr);
371
372 iface->add_focus_handler = component_wrapper_add_focus_handler;
373 iface->contains = component_wrapper_contains;
374 iface->get_extents = component_wrapper_get_extents;
375 iface->get_layer = component_wrapper_get_layer;
376 iface->get_mdi_zorder = component_wrapper_get_mdi_zorder;
377 iface->get_position = component_wrapper_get_position;
378 iface->get_size = component_wrapper_get_size;
379 iface->grab_focus = component_wrapper_grab_focus;
380 iface->ref_accessible_at_point = component_wrapper_ref_accessible_at_point;
381 iface->remove_focus_handler = component_wrapper_remove_focus_handler;
382 iface->set_extents = component_wrapper_set_extents;
383 iface->set_position = component_wrapper_set_position;
384 iface->set_size = component_wrapper_set_size;
385 }
386
387 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
388