xref: /aoo41x/main/vcl/unx/gtk/a11y/atkwindow.cxx (revision cdf0e10c)
1*cdf0e10cSrcweir /*************************************************************************
2*cdf0e10cSrcweir  *
3*cdf0e10cSrcweir  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4*cdf0e10cSrcweir  *
5*cdf0e10cSrcweir  * Copyright 2000, 2010 Oracle and/or its affiliates.
6*cdf0e10cSrcweir  *
7*cdf0e10cSrcweir  * OpenOffice.org - a multi-platform office productivity suite
8*cdf0e10cSrcweir  *
9*cdf0e10cSrcweir  * This file is part of OpenOffice.org.
10*cdf0e10cSrcweir  *
11*cdf0e10cSrcweir  * OpenOffice.org is free software: you can redistribute it and/or modify
12*cdf0e10cSrcweir  * it under the terms of the GNU Lesser General Public License version 3
13*cdf0e10cSrcweir  * only, as published by the Free Software Foundation.
14*cdf0e10cSrcweir  *
15*cdf0e10cSrcweir  * OpenOffice.org is distributed in the hope that it will be useful,
16*cdf0e10cSrcweir  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17*cdf0e10cSrcweir  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18*cdf0e10cSrcweir  * GNU Lesser General Public License version 3 for more details
19*cdf0e10cSrcweir  * (a copy is included in the LICENSE file that accompanied this code).
20*cdf0e10cSrcweir  *
21*cdf0e10cSrcweir  * You should have received a copy of the GNU Lesser General Public License
22*cdf0e10cSrcweir  * version 3 along with OpenOffice.org.  If not, see
23*cdf0e10cSrcweir  * <http://www.openoffice.org/license.html>
24*cdf0e10cSrcweir  * for a copy of the LGPLv3 License.
25*cdf0e10cSrcweir  *
26*cdf0e10cSrcweir  ************************************************************************/
27*cdf0e10cSrcweir 
28*cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
29*cdf0e10cSrcweir #include "precompiled_vcl.hxx"
30*cdf0e10cSrcweir 
31*cdf0e10cSrcweir #include <unx/gtk/gtkframe.hxx>
32*cdf0e10cSrcweir #include <vcl/window.hxx>
33*cdf0e10cSrcweir #include "vcl/popupmenuwindow.hxx"
34*cdf0e10cSrcweir 
35*cdf0e10cSrcweir #include "atkwindow.hxx"
36*cdf0e10cSrcweir #include "atkwrapper.hxx"
37*cdf0e10cSrcweir #include "atkregistry.hxx"
38*cdf0e10cSrcweir 
39*cdf0e10cSrcweir #include <com/sun/star/accessibility/AccessibleRole.hpp>
40*cdf0e10cSrcweir 
41*cdf0e10cSrcweir using namespace ::com::sun::star::accessibility;
42*cdf0e10cSrcweir using namespace ::com::sun::star::uno;
43*cdf0e10cSrcweir 
44*cdf0e10cSrcweir extern "C" {
45*cdf0e10cSrcweir 
46*cdf0e10cSrcweir static void (* window_real_initialize) (AtkObject *obj, gpointer data) = NULL;
47*cdf0e10cSrcweir static void (* window_real_finalize) (GObject *obj) = NULL;
48*cdf0e10cSrcweir 
49*cdf0e10cSrcweir static void
50*cdf0e10cSrcweir init_from_window( AtkObject *accessible, Window *pWindow )
51*cdf0e10cSrcweir {
52*cdf0e10cSrcweir     static AtkRole aDefaultRole = ATK_ROLE_INVALID;
53*cdf0e10cSrcweir 
54*cdf0e10cSrcweir     // Special role for sub-menu and combo-box popups that are exposed directly
55*cdf0e10cSrcweir     // by their parents already.
56*cdf0e10cSrcweir     if( aDefaultRole == ATK_ROLE_INVALID )
57*cdf0e10cSrcweir         aDefaultRole = atk_role_register( "redundant object" );
58*cdf0e10cSrcweir 
59*cdf0e10cSrcweir     AtkRole role = aDefaultRole;
60*cdf0e10cSrcweir 
61*cdf0e10cSrcweir     // Determine the appropriate role for the GtkWindow
62*cdf0e10cSrcweir     switch( pWindow->GetAccessibleRole() )
63*cdf0e10cSrcweir     {
64*cdf0e10cSrcweir         case AccessibleRole::ALERT:
65*cdf0e10cSrcweir             role = ATK_ROLE_ALERT;
66*cdf0e10cSrcweir             break;
67*cdf0e10cSrcweir 
68*cdf0e10cSrcweir         case AccessibleRole::DIALOG:
69*cdf0e10cSrcweir             role = ATK_ROLE_DIALOG;
70*cdf0e10cSrcweir             break;
71*cdf0e10cSrcweir 
72*cdf0e10cSrcweir         case AccessibleRole::FRAME:
73*cdf0e10cSrcweir             role = ATK_ROLE_FRAME;
74*cdf0e10cSrcweir             break;
75*cdf0e10cSrcweir 
76*cdf0e10cSrcweir         /* Ignore window objects for sub-menus, combo- and list boxes,
77*cdf0e10cSrcweir          *  which are exposed as children of their parents.
78*cdf0e10cSrcweir          */
79*cdf0e10cSrcweir         case AccessibleRole::WINDOW:
80*cdf0e10cSrcweir         {
81*cdf0e10cSrcweir             sal_uInt16 type = WINDOW_WINDOW;
82*cdf0e10cSrcweir             bool parentIsMenuFloatingWindow = false;
83*cdf0e10cSrcweir 
84*cdf0e10cSrcweir             Window *pParent = pWindow->GetParent();
85*cdf0e10cSrcweir             if( pParent ) {
86*cdf0e10cSrcweir                 type = pParent->GetType();
87*cdf0e10cSrcweir                 parentIsMenuFloatingWindow = ( TRUE == pParent->IsMenuFloatingWindow() );
88*cdf0e10cSrcweir             }
89*cdf0e10cSrcweir 
90*cdf0e10cSrcweir             if( (WINDOW_LISTBOX != type) && (WINDOW_COMBOBOX != type) &&
91*cdf0e10cSrcweir                 (WINDOW_MENUBARWINDOW != type) && ! parentIsMenuFloatingWindow )
92*cdf0e10cSrcweir             {
93*cdf0e10cSrcweir                 role = ATK_ROLE_WINDOW;
94*cdf0e10cSrcweir             }
95*cdf0e10cSrcweir         }
96*cdf0e10cSrcweir         break;
97*cdf0e10cSrcweir 
98*cdf0e10cSrcweir         default:
99*cdf0e10cSrcweir         {
100*cdf0e10cSrcweir             Window *pChild = pWindow->GetChild( 0 );
101*cdf0e10cSrcweir             if( pChild )
102*cdf0e10cSrcweir             {
103*cdf0e10cSrcweir                 if( WINDOW_HELPTEXTWINDOW == pChild->GetType() )
104*cdf0e10cSrcweir                 {
105*cdf0e10cSrcweir                     role = ATK_ROLE_TOOL_TIP;
106*cdf0e10cSrcweir                     pChild->SetAccessibleRole( AccessibleRole::LABEL );
107*cdf0e10cSrcweir                     accessible->name = g_strdup( rtl::OUStringToOString( pChild->GetText(), RTL_TEXTENCODING_UTF8 ).getStr() );
108*cdf0e10cSrcweir                 }
109*cdf0e10cSrcweir                 else if ( pWindow->GetType() == WINDOW_BORDERWINDOW && pChild->GetType() == WINDOW_FLOATINGWINDOW )
110*cdf0e10cSrcweir                 {
111*cdf0e10cSrcweir                     PopupMenuFloatingWindow* p = dynamic_cast<PopupMenuFloatingWindow*>(pChild);
112*cdf0e10cSrcweir                     if (p && p->IsPopupMenu() && p->GetMenuStackLevel() == 0)
113*cdf0e10cSrcweir                     {
114*cdf0e10cSrcweir                         // This is a top-level menu popup.  Register it.
115*cdf0e10cSrcweir                         role = ATK_ROLE_POPUP_MENU;
116*cdf0e10cSrcweir                         pChild->SetAccessibleRole( AccessibleRole::POPUP_MENU );
117*cdf0e10cSrcweir                         accessible->name = g_strdup( rtl::OUStringToOString( pChild->GetText(), RTL_TEXTENCODING_UTF8 ).getStr() );
118*cdf0e10cSrcweir                     }
119*cdf0e10cSrcweir                 }
120*cdf0e10cSrcweir             }
121*cdf0e10cSrcweir             break;
122*cdf0e10cSrcweir         }
123*cdf0e10cSrcweir     }
124*cdf0e10cSrcweir 
125*cdf0e10cSrcweir     accessible->role = role;
126*cdf0e10cSrcweir }
127*cdf0e10cSrcweir 
128*cdf0e10cSrcweir /*****************************************************************************/
129*cdf0e10cSrcweir 
130*cdf0e10cSrcweir static gint
131*cdf0e10cSrcweir ooo_window_wrapper_clear_focus(gpointer)
132*cdf0e10cSrcweir {
133*cdf0e10cSrcweir     atk_focus_tracker_notify( NULL );
134*cdf0e10cSrcweir     return FALSE;
135*cdf0e10cSrcweir }
136*cdf0e10cSrcweir 
137*cdf0e10cSrcweir /*****************************************************************************/
138*cdf0e10cSrcweir 
139*cdf0e10cSrcweir static gboolean
140*cdf0e10cSrcweir ooo_window_wrapper_real_focus_gtk (GtkWidget *, GdkEventFocus *)
141*cdf0e10cSrcweir {
142*cdf0e10cSrcweir     g_idle_add( ooo_window_wrapper_clear_focus, NULL );
143*cdf0e10cSrcweir     return FALSE;
144*cdf0e10cSrcweir }
145*cdf0e10cSrcweir 
146*cdf0e10cSrcweir static gboolean ooo_tooltip_map( GtkWidget* pToolTip, gpointer )
147*cdf0e10cSrcweir {
148*cdf0e10cSrcweir     AtkObject* pAccessible = gtk_widget_get_accessible( pToolTip );
149*cdf0e10cSrcweir     if( pAccessible )
150*cdf0e10cSrcweir         atk_object_notify_state_change( pAccessible, ATK_STATE_SHOWING, TRUE );
151*cdf0e10cSrcweir     return FALSE;
152*cdf0e10cSrcweir }
153*cdf0e10cSrcweir 
154*cdf0e10cSrcweir static gboolean ooo_tooltip_unmap( GtkWidget* pToolTip, gpointer )
155*cdf0e10cSrcweir {
156*cdf0e10cSrcweir     AtkObject* pAccessible = gtk_widget_get_accessible( pToolTip );
157*cdf0e10cSrcweir     if( pAccessible )
158*cdf0e10cSrcweir         atk_object_notify_state_change( pAccessible, ATK_STATE_SHOWING, FALSE );
159*cdf0e10cSrcweir     return FALSE;
160*cdf0e10cSrcweir }
161*cdf0e10cSrcweir 
162*cdf0e10cSrcweir /*****************************************************************************/
163*cdf0e10cSrcweir 
164*cdf0e10cSrcweir static bool
165*cdf0e10cSrcweir isChildPopupMenu(Window* pWindow)
166*cdf0e10cSrcweir {
167*cdf0e10cSrcweir     Window* pChild = pWindow->GetAccessibleChildWindow(0);
168*cdf0e10cSrcweir     if (!pChild)
169*cdf0e10cSrcweir         return false;
170*cdf0e10cSrcweir 
171*cdf0e10cSrcweir     if (WINDOW_FLOATINGWINDOW != pChild->GetType())
172*cdf0e10cSrcweir         return false;
173*cdf0e10cSrcweir 
174*cdf0e10cSrcweir     PopupMenuFloatingWindow* p = dynamic_cast<PopupMenuFloatingWindow*>(pChild);
175*cdf0e10cSrcweir     if (!p)
176*cdf0e10cSrcweir         return false;
177*cdf0e10cSrcweir 
178*cdf0e10cSrcweir     return p->IsPopupMenu();
179*cdf0e10cSrcweir }
180*cdf0e10cSrcweir 
181*cdf0e10cSrcweir static void
182*cdf0e10cSrcweir ooo_window_wrapper_real_initialize(AtkObject *obj, gpointer data)
183*cdf0e10cSrcweir {
184*cdf0e10cSrcweir     window_real_initialize(obj, data);
185*cdf0e10cSrcweir 
186*cdf0e10cSrcweir     GtkSalFrame *pFrame = GtkSalFrame::getFromWindow( GTK_WINDOW( data ) );
187*cdf0e10cSrcweir     if( pFrame )
188*cdf0e10cSrcweir     {
189*cdf0e10cSrcweir         Window *pWindow = pFrame->GetWindow();
190*cdf0e10cSrcweir         if( pWindow )
191*cdf0e10cSrcweir         {
192*cdf0e10cSrcweir             init_from_window( obj, pWindow );
193*cdf0e10cSrcweir 
194*cdf0e10cSrcweir             Reference< XAccessible > xAccessible( pWindow->GetAccessible(true) );
195*cdf0e10cSrcweir 
196*cdf0e10cSrcweir             /* We need the wrapper object for the top-level XAccessible to be
197*cdf0e10cSrcweir              * in the wrapper registry when atk traverses the hierachy up on
198*cdf0e10cSrcweir              * focus events
199*cdf0e10cSrcweir              */
200*cdf0e10cSrcweir             if( WINDOW_BORDERWINDOW == pWindow->GetType() )
201*cdf0e10cSrcweir             {
202*cdf0e10cSrcweir                 if ( isChildPopupMenu(pWindow) )
203*cdf0e10cSrcweir                 {
204*cdf0e10cSrcweir                     AtkObject *child = atk_object_wrapper_new( xAccessible, obj );
205*cdf0e10cSrcweir                     ooo_wrapper_registry_add( xAccessible, child );
206*cdf0e10cSrcweir                 }
207*cdf0e10cSrcweir                 else
208*cdf0e10cSrcweir                 {
209*cdf0e10cSrcweir                     ooo_wrapper_registry_add( xAccessible, obj );
210*cdf0e10cSrcweir                     g_object_set_data( G_OBJECT(obj), "ooo:atk-wrapper-key", xAccessible.get() );
211*cdf0e10cSrcweir                 }
212*cdf0e10cSrcweir             }
213*cdf0e10cSrcweir             else
214*cdf0e10cSrcweir             {
215*cdf0e10cSrcweir                 AtkObject *child = atk_object_wrapper_new( xAccessible, obj );
216*cdf0e10cSrcweir                 child->role = ATK_ROLE_FILLER;
217*cdf0e10cSrcweir                 if( (ATK_ROLE_DIALOG == obj->role) || (ATK_ROLE_ALERT == obj->role) )
218*cdf0e10cSrcweir                     child->role = ATK_ROLE_OPTION_PANE;
219*cdf0e10cSrcweir                 ooo_wrapper_registry_add( xAccessible, child );
220*cdf0e10cSrcweir             }
221*cdf0e10cSrcweir         }
222*cdf0e10cSrcweir     }
223*cdf0e10cSrcweir 
224*cdf0e10cSrcweir     g_signal_connect_after( GTK_WIDGET( data ), "focus-out-event",
225*cdf0e10cSrcweir                             G_CALLBACK (ooo_window_wrapper_real_focus_gtk),
226*cdf0e10cSrcweir                             NULL);
227*cdf0e10cSrcweir 
228*cdf0e10cSrcweir     if( obj->role == ATK_ROLE_TOOL_TIP )
229*cdf0e10cSrcweir     {
230*cdf0e10cSrcweir         g_signal_connect_after( GTK_WIDGET( data ), "map-event",
231*cdf0e10cSrcweir                                 G_CALLBACK (ooo_tooltip_map),
232*cdf0e10cSrcweir                                 NULL);
233*cdf0e10cSrcweir         g_signal_connect_after( GTK_WIDGET( data ), "unmap-event",
234*cdf0e10cSrcweir                                 G_CALLBACK (ooo_tooltip_unmap),
235*cdf0e10cSrcweir                                 NULL);
236*cdf0e10cSrcweir     }
237*cdf0e10cSrcweir }
238*cdf0e10cSrcweir 
239*cdf0e10cSrcweir /*****************************************************************************/
240*cdf0e10cSrcweir 
241*cdf0e10cSrcweir static void
242*cdf0e10cSrcweir ooo_window_wrapper_real_finalize (GObject *obj)
243*cdf0e10cSrcweir {
244*cdf0e10cSrcweir     ooo_wrapper_registry_remove( (XAccessible *) g_object_get_data( obj, "ooo:atk-wrapper-key" ));
245*cdf0e10cSrcweir     window_real_finalize( obj );
246*cdf0e10cSrcweir }
247*cdf0e10cSrcweir 
248*cdf0e10cSrcweir /*****************************************************************************/
249*cdf0e10cSrcweir 
250*cdf0e10cSrcweir static void
251*cdf0e10cSrcweir ooo_window_wrapper_class_init (AtkObjectClass *klass, gpointer)
252*cdf0e10cSrcweir {
253*cdf0e10cSrcweir     AtkObjectClass *atk_class;
254*cdf0e10cSrcweir     GObjectClass *gobject_class;
255*cdf0e10cSrcweir     gpointer data;
256*cdf0e10cSrcweir 
257*cdf0e10cSrcweir     /*
258*cdf0e10cSrcweir      * Patch the gobject vtable of GailWindow to refer to our instance of
259*cdf0e10cSrcweir      * "initialize".
260*cdf0e10cSrcweir      */
261*cdf0e10cSrcweir 
262*cdf0e10cSrcweir     data = g_type_class_peek_parent( klass );
263*cdf0e10cSrcweir     atk_class = ATK_OBJECT_CLASS (data);
264*cdf0e10cSrcweir 
265*cdf0e10cSrcweir     window_real_initialize = atk_class->initialize;
266*cdf0e10cSrcweir     atk_class->initialize = ooo_window_wrapper_real_initialize;
267*cdf0e10cSrcweir 
268*cdf0e10cSrcweir     gobject_class = G_OBJECT_CLASS (data);
269*cdf0e10cSrcweir 
270*cdf0e10cSrcweir     window_real_finalize = gobject_class->finalize;
271*cdf0e10cSrcweir     gobject_class->finalize = ooo_window_wrapper_real_finalize;
272*cdf0e10cSrcweir }
273*cdf0e10cSrcweir 
274*cdf0e10cSrcweir } // extern "C"
275*cdf0e10cSrcweir 
276*cdf0e10cSrcweir /*****************************************************************************/
277*cdf0e10cSrcweir 
278*cdf0e10cSrcweir GType
279*cdf0e10cSrcweir ooo_window_wrapper_get_type (void)
280*cdf0e10cSrcweir {
281*cdf0e10cSrcweir     static GType type = 0;
282*cdf0e10cSrcweir 
283*cdf0e10cSrcweir     if (!type)
284*cdf0e10cSrcweir     {
285*cdf0e10cSrcweir         GType parent_type = g_type_from_name( "GailWindow" );
286*cdf0e10cSrcweir 
287*cdf0e10cSrcweir         if( ! parent_type )
288*cdf0e10cSrcweir         {
289*cdf0e10cSrcweir             g_warning( "Unknown type: GailWindow" );
290*cdf0e10cSrcweir             parent_type = ATK_TYPE_OBJECT;
291*cdf0e10cSrcweir         }
292*cdf0e10cSrcweir 
293*cdf0e10cSrcweir         GTypeQuery type_query;
294*cdf0e10cSrcweir         g_type_query( parent_type, &type_query );
295*cdf0e10cSrcweir 
296*cdf0e10cSrcweir         static const GTypeInfo typeInfo =
297*cdf0e10cSrcweir         {
298*cdf0e10cSrcweir             type_query.class_size,
299*cdf0e10cSrcweir             (GBaseInitFunc) NULL,
300*cdf0e10cSrcweir             (GBaseFinalizeFunc) NULL,
301*cdf0e10cSrcweir             (GClassInitFunc) ooo_window_wrapper_class_init,
302*cdf0e10cSrcweir             (GClassFinalizeFunc) NULL,
303*cdf0e10cSrcweir             NULL,
304*cdf0e10cSrcweir             type_query.instance_size,
305*cdf0e10cSrcweir             0,
306*cdf0e10cSrcweir             (GInstanceInitFunc) NULL,
307*cdf0e10cSrcweir             NULL
308*cdf0e10cSrcweir         } ;
309*cdf0e10cSrcweir 
310*cdf0e10cSrcweir         type = g_type_register_static (parent_type, "OOoWindowAtkObject", &typeInfo, (GTypeFlags)0) ;
311*cdf0e10cSrcweir     }
312*cdf0e10cSrcweir 
313*cdf0e10cSrcweir     return type;
314*cdf0e10cSrcweir }
315*cdf0e10cSrcweir 
316*cdf0e10cSrcweir void restore_gail_window_vtable (void)
317*cdf0e10cSrcweir {
318*cdf0e10cSrcweir     AtkObjectClass *atk_class;
319*cdf0e10cSrcweir     gpointer data;
320*cdf0e10cSrcweir 
321*cdf0e10cSrcweir     GType type = g_type_from_name( "GailWindow" );
322*cdf0e10cSrcweir 
323*cdf0e10cSrcweir     if( type == G_TYPE_INVALID )
324*cdf0e10cSrcweir         return;
325*cdf0e10cSrcweir 
326*cdf0e10cSrcweir     data = g_type_class_peek( type );
327*cdf0e10cSrcweir     atk_class = ATK_OBJECT_CLASS (data);
328*cdf0e10cSrcweir 
329*cdf0e10cSrcweir     atk_class->initialize = window_real_initialize;
330*cdf0e10cSrcweir }
331*cdf0e10cSrcweir 
332