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