Line data Source code
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 <unx/gtk/gtkframe.hxx>
21 : #include <vcl/svapp.hxx>
22 : #include <vcl/window.hxx>
23 : #include "vcl/popupmenuwindow.hxx"
24 :
25 : #include "atkwindow.hxx"
26 : #include "atkwrapper.hxx"
27 : #include "atkregistry.hxx"
28 :
29 : #include <com/sun/star/accessibility/AccessibleRole.hpp>
30 :
31 : using namespace ::com::sun::star::accessibility;
32 : using namespace ::com::sun::star::uno;
33 :
34 : extern "C" {
35 :
36 : static void (* window_real_initialize) (AtkObject *obj, gpointer data) = NULL;
37 : static void (* window_real_finalize) (GObject *obj) = NULL;
38 :
39 : static void
40 0 : init_from_window( AtkObject *accessible, vcl::Window *pWindow )
41 : {
42 : static AtkRole aDefaultRole = ATK_ROLE_INVALID;
43 :
44 : // Special role for sub-menu and combo-box popups that are exposed directly
45 : // by their parents already.
46 0 : if( aDefaultRole == ATK_ROLE_INVALID )
47 : {
48 : SAL_WNODEPRECATED_DECLARATIONS_PUSH
49 0 : aDefaultRole = atk_role_register( "redundant object" );
50 : SAL_WNODEPRECATED_DECLARATIONS_POP
51 : }
52 :
53 0 : AtkRole role = aDefaultRole;
54 :
55 : // Determine the appropriate role for the GtkWindow
56 0 : switch( pWindow->GetAccessibleRole() )
57 : {
58 : case AccessibleRole::ALERT:
59 0 : role = ATK_ROLE_ALERT;
60 0 : break;
61 :
62 : case AccessibleRole::DIALOG:
63 0 : role = ATK_ROLE_DIALOG;
64 0 : break;
65 :
66 : case AccessibleRole::FRAME:
67 0 : role = ATK_ROLE_FRAME;
68 0 : break;
69 :
70 : /* Ignore window objects for sub-menus, combo- and list boxes,
71 : * which are exposed as children of their parents.
72 : */
73 : case AccessibleRole::WINDOW:
74 : {
75 0 : sal_uInt16 type = WINDOW_WINDOW;
76 0 : bool parentIsMenuFloatingWindow = false;
77 :
78 0 : vcl::Window *pParent = pWindow->GetParent();
79 0 : if( pParent ) {
80 0 : type = pParent->GetType();
81 0 : parentIsMenuFloatingWindow = pParent->IsMenuFloatingWindow();
82 : }
83 :
84 0 : if( (WINDOW_LISTBOX != type) && (WINDOW_COMBOBOX != type) &&
85 0 : (WINDOW_MENUBARWINDOW != type) && ! parentIsMenuFloatingWindow )
86 : {
87 0 : role = ATK_ROLE_WINDOW;
88 : }
89 : }
90 0 : break;
91 :
92 : default:
93 : {
94 0 : vcl::Window *pChild = pWindow->GetWindow(GetWindowType::FirstChild);
95 0 : if( pChild )
96 : {
97 0 : if( WINDOW_HELPTEXTWINDOW == pChild->GetType() )
98 : {
99 0 : role = ATK_ROLE_TOOL_TIP;
100 0 : pChild->SetAccessibleRole( AccessibleRole::LABEL );
101 0 : accessible->name = g_strdup( OUStringToOString( pChild->GetText(), RTL_TEXTENCODING_UTF8 ).getStr() );
102 : }
103 0 : else if ( pWindow->GetType() == WINDOW_BORDERWINDOW && pChild->GetType() == WINDOW_FLOATINGWINDOW )
104 : {
105 0 : PopupMenuFloatingWindow* p = dynamic_cast<PopupMenuFloatingWindow*>(pChild);
106 0 : if (p && p->IsPopupMenu() && p->GetMenuStackLevel() == 0)
107 : {
108 : // This is a top-level menu popup. Register it.
109 0 : role = ATK_ROLE_POPUP_MENU;
110 0 : pChild->SetAccessibleRole( AccessibleRole::POPUP_MENU );
111 0 : accessible->name = g_strdup( OUStringToOString( pChild->GetText(), RTL_TEXTENCODING_UTF8 ).getStr() );
112 : }
113 : }
114 : }
115 0 : break;
116 : }
117 : }
118 :
119 0 : accessible->role = role;
120 0 : }
121 :
122 : /*****************************************************************************/
123 :
124 : static gint
125 0 : ooo_window_wrapper_clear_focus(gpointer)
126 : {
127 0 : SolarMutexGuard aGuard;
128 : SAL_WNODEPRECATED_DECLARATIONS_PUSH
129 0 : atk_focus_tracker_notify( NULL );
130 : SAL_WNODEPRECATED_DECLARATIONS_POP
131 0 : return FALSE;
132 : }
133 :
134 : /*****************************************************************************/
135 :
136 : static gboolean
137 0 : ooo_window_wrapper_real_focus_gtk (GtkWidget *, GdkEventFocus *)
138 : {
139 0 : g_idle_add( ooo_window_wrapper_clear_focus, NULL );
140 0 : return FALSE;
141 : }
142 :
143 0 : static gboolean ooo_tooltip_map( GtkWidget* pToolTip, gpointer )
144 : {
145 0 : AtkObject* pAccessible = gtk_widget_get_accessible( pToolTip );
146 0 : if( pAccessible )
147 0 : atk_object_notify_state_change( pAccessible, ATK_STATE_SHOWING, TRUE );
148 0 : return FALSE;
149 : }
150 :
151 0 : static gboolean ooo_tooltip_unmap( GtkWidget* pToolTip, gpointer )
152 : {
153 0 : AtkObject* pAccessible = gtk_widget_get_accessible( pToolTip );
154 0 : if( pAccessible )
155 0 : atk_object_notify_state_change( pAccessible, ATK_STATE_SHOWING, FALSE );
156 0 : return FALSE;
157 : }
158 :
159 : /*****************************************************************************/
160 :
161 : static bool
162 0 : isChildPopupMenu(vcl::Window* pWindow)
163 : {
164 0 : vcl::Window* pChild = pWindow->GetAccessibleChildWindow(0);
165 0 : if (!pChild)
166 0 : return false;
167 :
168 0 : if (WINDOW_FLOATINGWINDOW != pChild->GetType())
169 0 : return false;
170 :
171 0 : PopupMenuFloatingWindow* p = dynamic_cast<PopupMenuFloatingWindow*>(pChild);
172 0 : if (!p)
173 0 : return false;
174 :
175 0 : return p->IsPopupMenu();
176 : }
177 :
178 : static void
179 0 : ooo_window_wrapper_real_initialize(AtkObject *obj, gpointer data)
180 : {
181 0 : window_real_initialize(obj, data);
182 :
183 0 : GtkSalFrame *pFrame = GtkSalFrame::getFromWindow( GTK_WINDOW( data ) );
184 0 : if( pFrame )
185 : {
186 0 : vcl::Window *pWindow = pFrame->GetWindow();
187 0 : if( pWindow )
188 : {
189 0 : init_from_window( obj, pWindow );
190 :
191 0 : Reference< XAccessible > xAccessible( pWindow->GetAccessible(true) );
192 :
193 : /* We need the wrapper object for the top-level XAccessible to be
194 : * in the wrapper registry when atk traverses the hierarchy up on
195 : * focus events
196 : */
197 0 : if( WINDOW_BORDERWINDOW == pWindow->GetType() )
198 : {
199 0 : if ( isChildPopupMenu(pWindow) )
200 : {
201 0 : AtkObject *child = atk_object_wrapper_new( xAccessible, obj );
202 0 : ooo_wrapper_registry_add( xAccessible, child );
203 : }
204 : else
205 : {
206 0 : ooo_wrapper_registry_add( xAccessible, obj );
207 0 : g_object_set_data( G_OBJECT(obj), "ooo:atk-wrapper-key", xAccessible.get() );
208 : }
209 : }
210 : else
211 : {
212 0 : AtkObject *child = atk_object_wrapper_new( xAccessible, obj );
213 0 : child->role = ATK_ROLE_FILLER;
214 0 : if( (ATK_ROLE_DIALOG == obj->role) || (ATK_ROLE_ALERT == obj->role) )
215 0 : child->role = ATK_ROLE_OPTION_PANE;
216 0 : ooo_wrapper_registry_add( xAccessible, child );
217 0 : }
218 : }
219 : }
220 :
221 0 : g_signal_connect_after( GTK_WIDGET( data ), "focus-out-event",
222 : G_CALLBACK (ooo_window_wrapper_real_focus_gtk),
223 0 : NULL);
224 :
225 0 : if( obj->role == ATK_ROLE_TOOL_TIP )
226 : {
227 0 : g_signal_connect_after( GTK_WIDGET( data ), "map-event",
228 : G_CALLBACK (ooo_tooltip_map),
229 0 : NULL);
230 0 : g_signal_connect_after( GTK_WIDGET( data ), "unmap-event",
231 : G_CALLBACK (ooo_tooltip_unmap),
232 0 : NULL);
233 : }
234 0 : }
235 :
236 : /*****************************************************************************/
237 :
238 : static void
239 0 : ooo_window_wrapper_real_finalize (GObject *obj)
240 : {
241 0 : ooo_wrapper_registry_remove( static_cast<XAccessible *>(g_object_get_data( obj, "ooo:atk-wrapper-key" )));
242 0 : window_real_finalize( obj );
243 0 : }
244 :
245 : /*****************************************************************************/
246 :
247 : static void
248 0 : ooo_window_wrapper_class_init (AtkObjectClass *klass, gpointer)
249 : {
250 : AtkObjectClass *atk_class;
251 : GObjectClass *gobject_class;
252 : gpointer data;
253 :
254 : /*
255 : * Patch the gobject vtable of GailWindow to refer to our instance of
256 : * "initialize".
257 : */
258 :
259 0 : data = g_type_class_peek_parent( klass );
260 0 : atk_class = ATK_OBJECT_CLASS (data);
261 :
262 0 : window_real_initialize = atk_class->initialize;
263 0 : atk_class->initialize = ooo_window_wrapper_real_initialize;
264 :
265 0 : gobject_class = G_OBJECT_CLASS (data);
266 :
267 0 : window_real_finalize = gobject_class->finalize;
268 0 : gobject_class->finalize = ooo_window_wrapper_real_finalize;
269 0 : }
270 :
271 : } // extern "C"
272 :
273 : /*****************************************************************************/
274 :
275 : GType
276 0 : ooo_window_wrapper_get_type()
277 : {
278 : static GType type = 0;
279 :
280 0 : if (!type)
281 : {
282 0 : GType parent_type = g_type_from_name( "GailWindow" );
283 :
284 0 : if( ! parent_type )
285 : {
286 : SAL_INFO("vcl.a11y", "Unknown type: GailWindow");
287 0 : parent_type = ATK_TYPE_OBJECT;
288 : }
289 :
290 : GTypeQuery type_query;
291 0 : g_type_query( parent_type, &type_query );
292 :
293 : static const GTypeInfo typeInfo =
294 : {
295 : static_cast<guint16>(type_query.class_size),
296 : nullptr,
297 : nullptr,
298 : reinterpret_cast<GClassInitFunc>(ooo_window_wrapper_class_init),
299 : nullptr,
300 : NULL,
301 : static_cast<guint16>(type_query.instance_size),
302 : 0,
303 : nullptr,
304 : NULL
305 0 : } ;
306 :
307 0 : type = g_type_register_static (parent_type, "OOoWindowAtkObject", &typeInfo, (GTypeFlags)0) ;
308 : }
309 :
310 0 : return type;
311 : }
312 :
313 1 : void restore_gail_window_vtable()
314 : {
315 : AtkObjectClass *atk_class;
316 : gpointer data;
317 :
318 1 : GType type = g_type_from_name( "GailWindow" );
319 :
320 1 : if( type == G_TYPE_INVALID )
321 2 : return;
322 :
323 0 : data = g_type_class_peek( type );
324 0 : atk_class = ATK_OBJECT_CLASS (data);
325 :
326 0 : atk_class->initialize = window_real_initialize;
327 : }
328 :
329 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|