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