xref: /aoo41x/main/vcl/unx/gtk/a11y/atkutil.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_vcl.hxx"
30 
31 #include <com/sun/star/accessibility/XAccessibleContext.hpp>
32 #include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp>
33 #include <com/sun/star/accessibility/XAccessibleSelection.hpp>
34 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
35 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
36 // --> OD 2009-04-14 #i93269#
37 #include <com/sun/star/accessibility/XAccessibleText.hpp>
38 // <--
39 #include <cppuhelper/implbase1.hxx>
40 #include <vos/mutex.hxx>
41 #include <rtl/ref.hxx>
42 
43 #include <vcl/svapp.hxx>
44 #include <vcl/window.hxx>
45 #include <vcl/menu.hxx>
46 #include <vcl/toolbox.hxx>
47 
48 #include "atkwrapper.hxx"
49 #include "atkutil.hxx"
50 
51 #include <gtk/gtk.h>
52 
53 #include <set>
54 
55 // #define ENABLE_TRACING
56 
57 #ifdef ENABLE_TRACING
58 #include <stdio.h>
59 #endif
60 
61 using namespace ::com::sun::star;
62 
63 static uno::WeakReference< accessibility::XAccessible > xNextFocusObject;
64 static guint focus_notify_handler = 0;
65 
66 /*****************************************************************************/
67 
68 extern "C" {
69 
70 static gint
71 atk_wrapper_focus_idle_handler (gpointer data)
72 {
73     vos::OGuard aGuard( Application::GetSolarMutex() );
74 
75     focus_notify_handler = 0;
76 
77     uno::Reference< accessibility::XAccessible > xAccessible = xNextFocusObject;
78     if( xAccessible.get() == reinterpret_cast < accessibility::XAccessible * > (data) )
79     {
80         AtkObject *atk_obj = xAccessible.is() ? atk_object_wrapper_ref( xAccessible ) : NULL;
81         // Gail does not notify focus changes to NULL, so do we ..
82         if( atk_obj )
83         {
84 #ifdef ENABLE_TRACING
85             fprintf(stderr, "notifying focus event for %p\n", atk_obj);
86 #endif
87             atk_focus_tracker_notify(atk_obj);
88             // --> OD 2009-04-14 #i93269#
89             // emit text_caret_moved event for <XAccessibleText> object,
90             // if cursor is inside the <XAccessibleText> object.
91             // also emit state-changed:focused event under the same condition.
92             {
93                 AtkObjectWrapper* wrapper_obj = ATK_OBJECT_WRAPPER (atk_obj);
94                 if( wrapper_obj && !wrapper_obj->mpText && wrapper_obj->mpContext )
95                 {
96                     uno::Any any = wrapper_obj->mpContext->queryInterface( accessibility::XAccessibleText::static_type(NULL) );
97                     if ( typelib_TypeClass_INTERFACE == any.pType->eTypeClass &&
98                          any.pReserved != 0 )
99                     {
100                         wrapper_obj->mpText = reinterpret_cast< accessibility::XAccessibleText * > (any.pReserved);
101                         if ( wrapper_obj->mpText != 0 )
102                         {
103                             wrapper_obj->mpText->acquire();
104                             gint caretPos = wrapper_obj->mpText->getCaretPosition();
105 
106                             if ( caretPos != -1 )
107                             {
108                                 atk_object_notify_state_change( atk_obj, ATK_STATE_FOCUSED, TRUE );
109                                 g_signal_emit_by_name( atk_obj, "text_caret_moved", caretPos );
110                             }
111                         }
112                     }
113                 }
114             }
115             // <--
116             g_object_unref(atk_obj);
117         }
118     }
119 
120     return FALSE;
121 }
122 
123 } // extern "C"
124 
125 /*****************************************************************************/
126 
127 static void
128 atk_wrapper_focus_tracker_notify_when_idle( const uno::Reference< accessibility::XAccessible > &xAccessible )
129 {
130     if( focus_notify_handler )
131         g_source_remove(focus_notify_handler);
132 
133     xNextFocusObject = xAccessible;
134 
135     focus_notify_handler = g_idle_add (atk_wrapper_focus_idle_handler, xAccessible.get());
136 }
137 
138 /*****************************************************************************/
139 
140 class DocumentFocusListener :
141     public ::cppu::WeakImplHelper1< accessibility::XAccessibleEventListener >
142 {
143 
144     std::set< uno::Reference< uno::XInterface > > m_aRefList;
145 
146 public:
147     void attachRecursive(
148         const uno::Reference< accessibility::XAccessible >& xAccessible
149     ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException);
150 
151     void attachRecursive(
152         const uno::Reference< accessibility::XAccessible >& xAccessible,
153         const uno::Reference< accessibility::XAccessibleContext >& xContext
154     ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException);
155 
156     void attachRecursive(
157         const uno::Reference< accessibility::XAccessible >& xAccessible,
158         const uno::Reference< accessibility::XAccessibleContext >& xContext,
159         const uno::Reference< accessibility::XAccessibleStateSet >& xStateSet
160     ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException);
161 
162     void detachRecursive(
163         const uno::Reference< accessibility::XAccessible >& xAccessible
164     ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException);
165 
166     void detachRecursive(
167         const uno::Reference< accessibility::XAccessible >& xAccessible,
168         const uno::Reference< accessibility::XAccessibleContext >& xContext
169     ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException);
170 
171     void detachRecursive(
172         const uno::Reference< accessibility::XAccessible >& xAccessible,
173         const uno::Reference< accessibility::XAccessibleContext >& xContext,
174         const uno::Reference< accessibility::XAccessibleStateSet >& xStateSet
175     ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException);
176 
177     static uno::Reference< accessibility::XAccessible > getAccessible(const lang::EventObject& aEvent )
178         throw (lang::IndexOutOfBoundsException, uno::RuntimeException);
179 
180     // XEventListener
181     virtual void disposing( const lang::EventObject& Source ) throw (uno::RuntimeException);
182 
183     // XAccessibleEventListener
184     virtual void notifyEvent( const accessibility::AccessibleEventObject& aEvent ) throw( uno::RuntimeException );
185 };
186 
187 /*****************************************************************************/
188 
189 void DocumentFocusListener::disposing( const lang::EventObject& aEvent )
190     throw (uno::RuntimeException)
191 {
192 //    fprintf(stderr, "In DocumentFocusListener::disposing (%p)\n", this);
193 //    fprintf(stderr, "m_aRefList has %d entries\n", m_aRefList.size());
194 
195     // Unref the object here, but do not remove as listener since the object
196     // might no longer be in a state that safely allows this.
197     if( aEvent.Source.is() )
198         m_aRefList.erase(aEvent.Source);
199 
200 //    fprintf(stderr, "m_aRefList has %d entries\n", m_aRefList.size());
201 
202 }
203 
204 /*****************************************************************************/
205 
206 void DocumentFocusListener::notifyEvent( const accessibility::AccessibleEventObject& aEvent )
207     throw( uno::RuntimeException )
208 {
209     switch( aEvent.EventId )
210     {
211         case accessibility::AccessibleEventId::STATE_CHANGED:
212             try
213             {
214                 sal_Int16 nState = accessibility::AccessibleStateType::INVALID;
215                 aEvent.NewValue >>= nState;
216 
217                 if( accessibility::AccessibleStateType::FOCUSED == nState )
218                     atk_wrapper_focus_tracker_notify_when_idle( getAccessible(aEvent) );
219             }
220             catch(const lang::IndexOutOfBoundsException &e)
221             {
222                 g_warning("Focused object has invalid index in parent");
223             }
224             break;
225 
226         case accessibility::AccessibleEventId::CHILD:
227         {
228             uno::Reference< accessibility::XAccessible > xChild;
229             if( (aEvent.OldValue >>= xChild) && xChild.is() )
230                 detachRecursive(xChild);
231 
232             if( (aEvent.NewValue >>= xChild) && xChild.is() )
233                 attachRecursive(xChild);
234         }
235             break;
236 
237         case accessibility::AccessibleEventId::INVALIDATE_ALL_CHILDREN:
238 /*        {
239             uno::Reference< accessibility::XAccessible > xAccessible( getAccessible(aEvent) );
240             detachRecursive(xAccessible);
241             attachRecursive(xAccessible);
242         }
243 */
244             g_warning( "Invalidate all children called\n" );
245             break;
246         default:
247             break;
248     }
249 }
250 
251 /*****************************************************************************/
252 
253 uno::Reference< accessibility::XAccessible > DocumentFocusListener::getAccessible(const lang::EventObject& aEvent )
254     throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
255 {
256     uno::Reference< accessibility::XAccessible > xAccessible(aEvent.Source, uno::UNO_QUERY);
257 
258     if( xAccessible.is() )
259         return xAccessible;
260 
261     uno::Reference< accessibility::XAccessibleContext > xContext(aEvent.Source, uno::UNO_QUERY);
262 
263     if( xContext.is() )
264     {
265         uno::Reference< accessibility::XAccessible > xParent( xContext->getAccessibleParent() );
266         if( xParent.is() )
267         {
268             uno::Reference< accessibility::XAccessibleContext > xParentContext( xParent->getAccessibleContext() );
269             if( xParentContext.is() )
270             {
271                 return xParentContext->getAccessibleChild( xContext->getAccessibleIndexInParent() );
272             }
273         }
274     }
275 
276     return uno::Reference< accessibility::XAccessible >();
277 }
278 
279 /*****************************************************************************/
280 
281 void DocumentFocusListener::attachRecursive(
282     const uno::Reference< accessibility::XAccessible >& xAccessible
283 ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
284 {
285     uno::Reference< accessibility::XAccessibleContext > xContext =
286         xAccessible->getAccessibleContext();
287 
288     if( xContext.is() )
289         attachRecursive(xAccessible, xContext);
290 }
291 
292 /*****************************************************************************/
293 
294 void DocumentFocusListener::attachRecursive(
295     const uno::Reference< accessibility::XAccessible >& xAccessible,
296     const uno::Reference< accessibility::XAccessibleContext >& xContext
297 )  throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
298 {
299     uno::Reference< accessibility::XAccessibleStateSet > xStateSet =
300         xContext->getAccessibleStateSet();
301 
302     if( xStateSet.is() )
303         attachRecursive(xAccessible, xContext, xStateSet);
304 }
305 
306 /*****************************************************************************/
307 
308 void DocumentFocusListener::attachRecursive(
309     const uno::Reference< accessibility::XAccessible >& xAccessible,
310     const uno::Reference< accessibility::XAccessibleContext >& xContext,
311     const uno::Reference< accessibility::XAccessibleStateSet >& xStateSet
312 ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
313 {
314     if( xStateSet->contains(accessibility::AccessibleStateType::FOCUSED ) )
315         atk_wrapper_focus_tracker_notify_when_idle( xAccessible );
316 
317     uno::Reference< accessibility::XAccessibleEventBroadcaster > xBroadcaster =
318         uno::Reference< accessibility::XAccessibleEventBroadcaster >(xContext, uno::UNO_QUERY);
319 
320     // If not already done, add the broadcaster to the list and attach as listener.
321     if( xBroadcaster.is() && m_aRefList.insert(xBroadcaster).second )
322     {
323         xBroadcaster->addEventListener(static_cast< accessibility::XAccessibleEventListener *>(this));
324 
325         if( ! xStateSet->contains(accessibility::AccessibleStateType::MANAGES_DESCENDANTS ) )
326         {
327             sal_Int32 n, nmax = xContext->getAccessibleChildCount();
328             for( n = 0; n < nmax; n++ )
329             {
330                 uno::Reference< accessibility::XAccessible > xChild( xContext->getAccessibleChild( n ) );
331 
332                 if( xChild.is() )
333                     attachRecursive(xChild);
334             }
335         }
336     }
337 }
338 
339 /*****************************************************************************/
340 
341 void DocumentFocusListener::detachRecursive(
342     const uno::Reference< accessibility::XAccessible >& xAccessible
343 ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
344 {
345     uno::Reference< accessibility::XAccessibleContext > xContext =
346         xAccessible->getAccessibleContext();
347 
348     if( xContext.is() )
349         detachRecursive(xAccessible, xContext);
350 }
351 
352 /*****************************************************************************/
353 
354 void DocumentFocusListener::detachRecursive(
355     const uno::Reference< accessibility::XAccessible >& xAccessible,
356     const uno::Reference< accessibility::XAccessibleContext >& xContext
357 )  throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
358 {
359     uno::Reference< accessibility::XAccessibleStateSet > xStateSet =
360         xContext->getAccessibleStateSet();
361 
362     if( xStateSet.is() )
363         detachRecursive(xAccessible, xContext, xStateSet);
364 }
365 
366 /*****************************************************************************/
367 
368 void DocumentFocusListener::detachRecursive(
369     const uno::Reference< accessibility::XAccessible >&,
370     const uno::Reference< accessibility::XAccessibleContext >& xContext,
371     const uno::Reference< accessibility::XAccessibleStateSet >& xStateSet
372 ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
373 {
374     uno::Reference< accessibility::XAccessibleEventBroadcaster > xBroadcaster =
375         uno::Reference< accessibility::XAccessibleEventBroadcaster >(xContext, uno::UNO_QUERY);
376 
377     if( xBroadcaster.is() && 0 < m_aRefList.erase(xBroadcaster) )
378     {
379         xBroadcaster->removeEventListener(static_cast< accessibility::XAccessibleEventListener *>(this));
380 
381         if( ! xStateSet->contains(accessibility::AccessibleStateType::MANAGES_DESCENDANTS ) )
382         {
383             sal_Int32 n, nmax = xContext->getAccessibleChildCount();
384             for( n = 0; n < nmax; n++ )
385             {
386                 uno::Reference< accessibility::XAccessible > xChild( xContext->getAccessibleChild( n ) );
387 
388                 if( xChild.is() )
389                     detachRecursive(xChild);
390             }
391         }
392     }
393 }
394 
395 /*****************************************************************************/
396 
397 /*
398  * page tabs in gtk are widgets, so we need to simulate focus events for those
399  */
400 
401 static void handle_tabpage_activated(Window *pWindow)
402 {
403     uno::Reference< accessibility::XAccessible > xAccessible =
404         pWindow->GetAccessible();
405 
406     if( ! xAccessible.is() )
407         return;
408 
409     uno::Reference< accessibility::XAccessibleSelection > xSelection(
410         xAccessible->getAccessibleContext(), uno::UNO_QUERY);
411 
412     if( xSelection.is() )
413         atk_wrapper_focus_tracker_notify_when_idle( xSelection->getSelectedAccessibleChild(0) );
414 }
415 
416 /*****************************************************************************/
417 
418 /*
419  * toolbar items in gtk are widgets, so we need to simulate focus events for those
420  */
421 
422 static void notify_toolbox_item_focus(ToolBox *pToolBox)
423 {
424     uno::Reference< accessibility::XAccessible > xAccessible =
425         pToolBox->GetAccessible();
426 
427     if( ! xAccessible.is() )
428         return;
429 
430     uno::Reference< accessibility::XAccessibleContext > xContext =
431         xAccessible->getAccessibleContext();
432 
433     if( ! xContext.is() )
434         return;
435 
436     sal_Int32 nPos = pToolBox->GetItemPos( pToolBox->GetHighlightItemId() );
437     if( nPos != TOOLBOX_ITEM_NOTFOUND )
438         atk_wrapper_focus_tracker_notify_when_idle( xContext->getAccessibleChild( nPos ) );
439 }
440 
441 static void handle_toolbox_highlight(Window *pWindow)
442 {
443     ToolBox *pToolBox = static_cast <ToolBox *> (pWindow);
444 
445     // Make sure either the toolbox or its parent toolbox has the focus
446     if ( ! pToolBox->HasFocus() )
447     {
448         ToolBox* pToolBoxParent = dynamic_cast< ToolBox* >( pToolBox->GetParent() );
449         if ( ! pToolBoxParent || ! pToolBoxParent->HasFocus() )
450             return;
451     }
452 
453     notify_toolbox_item_focus(pToolBox);
454 }
455 
456 static void handle_toolbox_highlightoff(Window *pWindow)
457 {
458     ToolBox *pToolBox = static_cast <ToolBox *> (pWindow);
459     ToolBox* pToolBoxParent = dynamic_cast< ToolBox* >( pToolBox->GetParent() );
460 
461     // Notify when leaving sub toolboxes
462     if( pToolBoxParent && pToolBoxParent->HasFocus() )
463         notify_toolbox_item_focus( pToolBoxParent );
464 }
465 
466 /*****************************************************************************/
467 
468 static void create_wrapper_for_child(
469     const uno::Reference< accessibility::XAccessibleContext >& xContext,
470     sal_Int32 index)
471 {
472     if( xContext.is() )
473     {
474         uno::Reference< accessibility::XAccessible > xChild(xContext->getAccessibleChild(index));
475         if( xChild.is() )
476         {
477             // create the wrapper object - it will survive the unref unless it is a transient object
478             g_object_unref( atk_object_wrapper_ref( xChild ) );
479         }
480     }
481 }
482 
483 /*****************************************************************************/
484 
485 static void handle_toolbox_buttonchange(VclWindowEvent const *pEvent)
486 {
487     Window* pWindow = pEvent->GetWindow();
488     sal_Int32 index = (sal_Int32)(sal_IntPtr) pEvent->GetData();
489 
490     if( pWindow && pWindow->IsReallyVisible() )
491     {
492         uno::Reference< accessibility::XAccessible > xAccessible(pWindow->GetAccessible());
493         if( xAccessible.is() )
494         {
495             create_wrapper_for_child(xAccessible->getAccessibleContext(), index);
496         }
497     }
498 }
499 
500 /*****************************************************************************/
501 
502 /* currently not needed anymore...
503 static void create_wrapper_for_children(Window *pWindow)
504 {
505     if( pWindow && pWindow->IsReallyVisible() )
506     {
507         uno::Reference< accessibility::XAccessible > xAccessible(pWindow->GetAccessible());
508         if( xAccessible.is() )
509         {
510             uno::Reference< accessibility::XAccessibleContext > xContext(xAccessible->getAccessibleContext());
511             if( xContext.is() )
512             {
513                 sal_Int32 nChildren = xContext->getAccessibleChildCount();
514                 for( sal_Int32 i = 0; i < nChildren; ++i )
515                     create_wrapper_for_child(xContext, i);
516             }
517         }
518     }
519 }
520 */
521 
522 /*****************************************************************************/
523 
524 static std::set< Window * > g_aWindowList;
525 
526 static void handle_get_focus(::VclWindowEvent const * pEvent)
527 {
528     static rtl::Reference< DocumentFocusListener > aDocumentFocusListener =
529         new DocumentFocusListener();
530 
531     Window *pWindow = pEvent->GetWindow();
532 
533     // The menu bar is handled through VCLEVENT_MENU_HIGHLIGHTED
534     if( ! pWindow || !pWindow->IsReallyVisible() || pWindow->GetType() == WINDOW_MENUBARWINDOW )
535         return;
536 
537     // ToolBoxes are handled through VCLEVENT_TOOLBOX_HIGHLIGHT
538     if( pWindow->GetType() == WINDOW_TOOLBOX )
539         return;
540 
541     if( pWindow->GetType() == WINDOW_TABCONTROL )
542     {
543         handle_tabpage_activated( pWindow );
544         return;
545     }
546 
547     uno::Reference< accessibility::XAccessible > xAccessible =
548         pWindow->GetAccessible();
549 
550     if( ! xAccessible.is() )
551         return;
552 
553     uno::Reference< accessibility::XAccessibleContext > xContext =
554         xAccessible->getAccessibleContext();
555 
556     if( ! xContext.is() )
557         return;
558 
559     uno::Reference< accessibility::XAccessibleStateSet > xStateSet =
560         xContext->getAccessibleStateSet();
561 
562     if( ! xStateSet.is() )
563         return;
564 
565 /* the UNO ToolBox wrapper does not (yet?) support XAccessibleSelection, so we
566  * need to add listeners to the children instead of re-using the tabpage stuff
567  */
568     if( xStateSet->contains(accessibility::AccessibleStateType::FOCUSED) &&
569         ( pWindow->GetType() != WINDOW_TREELISTBOX ) )
570     {
571         atk_wrapper_focus_tracker_notify_when_idle( xAccessible );
572     }
573     else
574     {
575         if( g_aWindowList.find(pWindow) == g_aWindowList.end() )
576         {
577             g_aWindowList.insert(pWindow);
578             try
579             {
580                 aDocumentFocusListener->attachRecursive(xAccessible, xContext, xStateSet);
581             }
582             catch( const uno::Exception &e )
583             {
584                 g_warning( "Exception caught processing focus events" );
585             }
586         }
587 #ifdef ENABLE_TRACING
588         else
589             fprintf(stderr, "Window %p already in the list\n", pWindow );
590 #endif
591     }
592 }
593 
594 /*****************************************************************************/
595 
596 static void handle_menu_highlighted(::VclMenuEvent const * pEvent)
597 {
598     try
599     {
600         Menu* pMenu = pEvent->GetMenu();
601         sal_uInt16 nPos = pEvent->GetItemPos();
602 
603         if( pMenu &&  nPos != 0xFFFF)
604         {
605             uno::Reference< accessibility::XAccessible > xAccessible ( pMenu->GetAccessible() );
606 
607             if( xAccessible.is() )
608             {
609                 uno::Reference< accessibility::XAccessibleContext > xContext ( xAccessible->getAccessibleContext() );
610 
611                 if( xContext.is() )
612                     atk_wrapper_focus_tracker_notify_when_idle( xContext->getAccessibleChild( nPos ) );
613             }
614         }
615     }
616     catch( const uno::Exception& e )
617     {
618         g_warning( "Exception caught processing menu highlight events" );
619     }
620 }
621 
622 /*****************************************************************************/
623 
624 long WindowEventHandler(void *, ::VclSimpleEvent const * pEvent)
625 {
626     switch (pEvent->GetId())
627     {
628     case VCLEVENT_WINDOW_SHOW:
629 //        fprintf(stderr, "got VCLEVENT_WINDOW_SHOW for %p\n",
630 //            static_cast< ::VclWindowEvent const * >(pEvent)->GetWindow());
631         break;
632     case VCLEVENT_WINDOW_HIDE:
633 //        fprintf(stderr, "got VCLEVENT_WINDOW_HIDE for %p\n",
634 //            static_cast< ::VclWindowEvent const * >(pEvent)->GetWindow());
635         break;
636     case VCLEVENT_WINDOW_CLOSE:
637 //        fprintf(stderr, "got VCLEVENT_WINDOW_CLOSE for %p\n",
638 //            static_cast< ::VclWindowEvent const * >(pEvent)->GetWindow());
639         break;
640     case VCLEVENT_WINDOW_GETFOCUS:
641         handle_get_focus(static_cast< ::VclWindowEvent const * >(pEvent));
642         break;
643     case VCLEVENT_WINDOW_LOSEFOCUS:
644 //        fprintf(stderr, "got VCLEVENT_WINDOW_LOSEFOCUS for %p\n",
645 //            static_cast< ::VclWindowEvent const * >(pEvent)->GetWindow());
646         break;
647     case VCLEVENT_WINDOW_MINIMIZE:
648 //        fprintf(stderr, "got VCLEVENT_WINDOW_MINIMIZE for %p\n",
649 //            static_cast< ::VclWindowEvent const * >(pEvent)->GetWindow());
650         break;
651     case VCLEVENT_WINDOW_NORMALIZE:
652 //        fprintf(stderr, "got VCLEVENT_WINDOW_NORMALIZE for %p\n",
653 //            static_cast< ::VclWindowEvent const * >(pEvent)->GetWindow());
654         break;
655     case VCLEVENT_WINDOW_KEYINPUT:
656     case VCLEVENT_WINDOW_KEYUP:
657     case VCLEVENT_WINDOW_COMMAND:
658     case VCLEVENT_WINDOW_MOUSEMOVE:
659         break;
660  /*
661         fprintf(stderr, "got VCLEVENT_WINDOW_COMMAND (%d) for %p\n",
662             static_cast< ::CommandEvent const * > (
663                 static_cast< ::VclWindowEvent const * >(pEvent)->GetData())->GetCommand(),
664             static_cast< ::VclWindowEvent const * >(pEvent)->GetWindow());
665  */
666     case VCLEVENT_MENU_HIGHLIGHT:
667         if (const VclMenuEvent* pMenuEvent = dynamic_cast<const VclMenuEvent*>(pEvent))
668         {
669             handle_menu_highlighted(pMenuEvent);
670         }
671         else if (const VclAccessibleEvent* pAccEvent = dynamic_cast<const VclAccessibleEvent*>(pEvent))
672         {
673             uno::Reference< accessibility::XAccessible > xAccessible = pAccEvent->GetAccessible();
674             if (xAccessible.is())
675                 atk_wrapper_focus_tracker_notify_when_idle(xAccessible);
676         }
677         break;
678 
679     case VCLEVENT_TOOLBOX_HIGHLIGHT:
680         handle_toolbox_highlight(static_cast< ::VclWindowEvent const * >(pEvent)->GetWindow());
681         break;
682 
683     case VCLEVENT_TOOLBOX_BUTTONSTATECHANGED:
684         handle_toolbox_buttonchange(static_cast< ::VclWindowEvent const * >(pEvent));
685         break;
686 
687     case VCLEVENT_OBJECT_DYING:
688         g_aWindowList.erase( static_cast< ::VclWindowEvent const * >(pEvent)->GetWindow() );
689         // fallthrough intentional !
690     case VCLEVENT_TOOLBOX_HIGHLIGHTOFF:
691         handle_toolbox_highlightoff(static_cast< ::VclWindowEvent const * >(pEvent)->GetWindow());
692         break;
693 
694     case VCLEVENT_TABPAGE_ACTIVATE:
695         handle_tabpage_activated(static_cast< ::VclWindowEvent const * >(pEvent)->GetWindow());
696         break;
697 
698     case VCLEVENT_COMBOBOX_SETTEXT:
699         // MT 2010/02: This looks quite strange to me. Stumbled over this when fixing #i104290#.
700         // This kicked in when leaving the combobox in the toolbar, after that the events worked.
701         // I guess this was a try to work around missing combobox events, which didn't do the full job, and shouldn't be necessary anymore.
702         // Fix for #i104290# was done in toolkit/source/awt/vclxaccessiblecomponent, FOCUSED state for compound controls in general.
703         // create_wrapper_for_children(static_cast< ::VclWindowEvent const * >(pEvent)->GetWindow());
704         break;
705 
706     default:
707 //        OSL_TRACE("got event %d \n", pEvent->GetId());
708         break;
709     }
710     return 0;
711 }
712 
713 static Link g_aEventListenerLink( NULL, (PSTUB) WindowEventHandler );
714 
715 /*****************************************************************************/
716 
717 extern "C" {
718 
719 static G_CONST_RETURN gchar *
720 ooo_atk_util_get_toolkit_name (void)
721 {
722     return "VCL";
723 }
724 
725 /*****************************************************************************/
726 
727 static G_CONST_RETURN gchar *
728 ooo_atk_util_get_toolkit_version (void)
729 {
730     /*
731      * Version is passed in as a -D flag when this file is
732      * compiled.
733      */
734 
735     return VERSION;
736 }
737 
738 /*****************************************************************************/
739 
740 /*
741  * GObject inheritance
742  */
743 
744 static void
745 ooo_atk_util_class_init (AtkUtilClass *)
746 {
747     AtkUtilClass *atk_class;
748     gpointer data;
749 
750     data = g_type_class_peek (ATK_TYPE_UTIL);
751     atk_class = ATK_UTIL_CLASS (data);
752 
753     atk_class->get_toolkit_name = ooo_atk_util_get_toolkit_name;
754     atk_class->get_toolkit_version = ooo_atk_util_get_toolkit_version;
755 
756     Application::AddEventListener( g_aEventListenerLink );
757 }
758 
759 } // extern "C"
760 
761 /*****************************************************************************/
762 
763 GType
764 ooo_atk_util_get_type (void)
765 {
766     static GType type = 0;
767 
768     if (!type)
769     {
770         GType parent_type = g_type_from_name( "GailUtil" );
771 
772         if( ! parent_type )
773         {
774             g_warning( "Unknown type: GailUtil" );
775             parent_type = ATK_TYPE_UTIL;
776         }
777 
778         GTypeQuery type_query;
779         g_type_query( parent_type, &type_query );
780 
781         static const GTypeInfo typeInfo =
782         {
783             type_query.class_size,
784             (GBaseInitFunc) NULL,
785             (GBaseFinalizeFunc) NULL,
786             (GClassInitFunc) ooo_atk_util_class_init,
787             (GClassFinalizeFunc) NULL,
788             NULL,
789             type_query.instance_size,
790             0,
791             (GInstanceInitFunc) NULL,
792             NULL
793         } ;
794 
795         type = g_type_register_static (parent_type, "OOoUtil", &typeInfo, (GTypeFlags)0) ;
796   }
797 
798   return type;
799 }
800 
801 
802