xref: /trunk/main/vcl/unx/gtk/a11y/atkutil.cxx (revision 9f62ea84)
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     switch( aEvent.EventId )
206     {
207         case accessibility::AccessibleEventId::STATE_CHANGED:
208             try
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             catch(const lang::IndexOutOfBoundsException &e)
217             {
218                 g_warning("Focused object has invalid index in parent");
219             }
220             break;
221 
222         case accessibility::AccessibleEventId::CHILD:
223         {
224             uno::Reference< accessibility::XAccessible > xChild;
225             if( (aEvent.OldValue >>= xChild) && xChild.is() )
226                 detachRecursive(xChild);
227 
228             if( (aEvent.NewValue >>= xChild) && xChild.is() )
229                 attachRecursive(xChild);
230         }
231             break;
232 
233         case accessibility::AccessibleEventId::INVALIDATE_ALL_CHILDREN:
234 /*        {
235             uno::Reference< accessibility::XAccessible > xAccessible( getAccessible(aEvent) );
236             detachRecursive(xAccessible);
237             attachRecursive(xAccessible);
238         }
239 */
240             g_warning( "Invalidate all children called\n" );
241             break;
242         default:
243             break;
244     }
245 }
246 
247 /*****************************************************************************/
248 
249 uno::Reference< accessibility::XAccessible > DocumentFocusListener::getAccessible(const lang::EventObject& aEvent )
250     throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
251 {
252     uno::Reference< accessibility::XAccessible > xAccessible(aEvent.Source, uno::UNO_QUERY);
253 
254     if( xAccessible.is() )
255         return xAccessible;
256 
257     uno::Reference< accessibility::XAccessibleContext > xContext(aEvent.Source, uno::UNO_QUERY);
258 
259     if( xContext.is() )
260     {
261         uno::Reference< accessibility::XAccessible > xParent( xContext->getAccessibleParent() );
262         if( xParent.is() )
263         {
264             uno::Reference< accessibility::XAccessibleContext > xParentContext( xParent->getAccessibleContext() );
265             if( xParentContext.is() )
266             {
267                 return xParentContext->getAccessibleChild( xContext->getAccessibleIndexInParent() );
268             }
269         }
270     }
271 
272     return uno::Reference< accessibility::XAccessible >();
273 }
274 
275 /*****************************************************************************/
276 
277 void DocumentFocusListener::attachRecursive(
278     const uno::Reference< accessibility::XAccessible >& xAccessible
279 ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
280 {
281     uno::Reference< accessibility::XAccessibleContext > xContext =
282         xAccessible->getAccessibleContext();
283 
284     if( xContext.is() )
285         attachRecursive(xAccessible, xContext);
286 }
287 
288 /*****************************************************************************/
289 
290 void DocumentFocusListener::attachRecursive(
291     const uno::Reference< accessibility::XAccessible >& xAccessible,
292     const uno::Reference< accessibility::XAccessibleContext >& xContext
293 )  throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
294 {
295     uno::Reference< accessibility::XAccessibleStateSet > xStateSet =
296         xContext->getAccessibleStateSet();
297 
298     if( xStateSet.is() )
299         attachRecursive(xAccessible, xContext, xStateSet);
300 }
301 
302 /*****************************************************************************/
303 
304 void DocumentFocusListener::attachRecursive(
305     const uno::Reference< accessibility::XAccessible >& xAccessible,
306     const uno::Reference< accessibility::XAccessibleContext >& xContext,
307     const uno::Reference< accessibility::XAccessibleStateSet >& xStateSet
308 ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
309 {
310     if( xStateSet->contains(accessibility::AccessibleStateType::FOCUSED ) )
311         atk_wrapper_focus_tracker_notify_when_idle( xAccessible );
312 
313     uno::Reference< accessibility::XAccessibleEventBroadcaster > xBroadcaster =
314         uno::Reference< accessibility::XAccessibleEventBroadcaster >(xContext, uno::UNO_QUERY);
315 
316     // If not already done, add the broadcaster to the list and attach as listener.
317     if( xBroadcaster.is() && m_aRefList.insert(xBroadcaster).second )
318     {
319         xBroadcaster->addEventListener(static_cast< accessibility::XAccessibleEventListener *>(this));
320 
321         if( ! xStateSet->contains(accessibility::AccessibleStateType::MANAGES_DESCENDANTS ) )
322         {
323             sal_Int32 n, nmax = xContext->getAccessibleChildCount();
324             for( n = 0; n < nmax; n++ )
325             {
326                 uno::Reference< accessibility::XAccessible > xChild( xContext->getAccessibleChild( n ) );
327 
328                 if( xChild.is() )
329                     attachRecursive(xChild);
330             }
331         }
332     }
333 }
334 
335 /*****************************************************************************/
336 
337 void DocumentFocusListener::detachRecursive(
338     const uno::Reference< accessibility::XAccessible >& xAccessible
339 ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
340 {
341     uno::Reference< accessibility::XAccessibleContext > xContext =
342         xAccessible->getAccessibleContext();
343 
344     if( xContext.is() )
345         detachRecursive(xAccessible, xContext);
346 }
347 
348 /*****************************************************************************/
349 
350 void DocumentFocusListener::detachRecursive(
351     const uno::Reference< accessibility::XAccessible >& xAccessible,
352     const uno::Reference< accessibility::XAccessibleContext >& xContext
353 )  throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
354 {
355     uno::Reference< accessibility::XAccessibleStateSet > xStateSet =
356         xContext->getAccessibleStateSet();
357 
358     if( xStateSet.is() )
359         detachRecursive(xAccessible, xContext, xStateSet);
360 }
361 
362 /*****************************************************************************/
363 
364 void DocumentFocusListener::detachRecursive(
365     const uno::Reference< accessibility::XAccessible >&,
366     const uno::Reference< accessibility::XAccessibleContext >& xContext,
367     const uno::Reference< accessibility::XAccessibleStateSet >& xStateSet
368 ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
369 {
370     uno::Reference< accessibility::XAccessibleEventBroadcaster > xBroadcaster =
371         uno::Reference< accessibility::XAccessibleEventBroadcaster >(xContext, uno::UNO_QUERY);
372 
373     if( xBroadcaster.is() && 0 < m_aRefList.erase(xBroadcaster) )
374     {
375         xBroadcaster->removeEventListener(static_cast< accessibility::XAccessibleEventListener *>(this));
376 
377         if( ! xStateSet->contains(accessibility::AccessibleStateType::MANAGES_DESCENDANTS ) )
378         {
379             sal_Int32 n, nmax = xContext->getAccessibleChildCount();
380             for( n = 0; n < nmax; n++ )
381             {
382                 uno::Reference< accessibility::XAccessible > xChild( xContext->getAccessibleChild( n ) );
383 
384                 if( xChild.is() )
385                     detachRecursive(xChild);
386             }
387         }
388     }
389 }
390 
391 /*****************************************************************************/
392 
393 /*
394  * page tabs in gtk are widgets, so we need to simulate focus events for those
395  */
396 
397 static void handle_tabpage_activated(Window *pWindow)
398 {
399     uno::Reference< accessibility::XAccessible > xAccessible =
400         pWindow->GetAccessible();
401 
402     if( ! xAccessible.is() )
403         return;
404 
405     uno::Reference< accessibility::XAccessibleSelection > xSelection(
406         xAccessible->getAccessibleContext(), uno::UNO_QUERY);
407 
408     if( xSelection.is() )
409         atk_wrapper_focus_tracker_notify_when_idle( xSelection->getSelectedAccessibleChild(0) );
410 }
411 
412 /*****************************************************************************/
413 
414 /*
415  * toolbar items in gtk are widgets, so we need to simulate focus events for those
416  */
417 
418 static void notify_toolbox_item_focus(ToolBox *pToolBox)
419 {
420     uno::Reference< accessibility::XAccessible > xAccessible =
421         pToolBox->GetAccessible();
422 
423     if( ! xAccessible.is() )
424         return;
425 
426     uno::Reference< accessibility::XAccessibleContext > xContext =
427         xAccessible->getAccessibleContext();
428 
429     if( ! xContext.is() )
430         return;
431 
432     sal_Int32 nPos = pToolBox->GetItemPos( pToolBox->GetHighlightItemId() );
433     if( nPos != TOOLBOX_ITEM_NOTFOUND )
434         atk_wrapper_focus_tracker_notify_when_idle( xContext->getAccessibleChild( nPos ) );
435 }
436 
437 static void handle_toolbox_highlight(Window *pWindow)
438 {
439     ToolBox *pToolBox = static_cast <ToolBox *> (pWindow);
440 
441     // Make sure either the toolbox or its parent toolbox has the focus
442     if ( ! pToolBox->HasFocus() )
443     {
444         ToolBox* pToolBoxParent = dynamic_cast< ToolBox* >( pToolBox->GetParent() );
445         if ( ! pToolBoxParent || ! pToolBoxParent->HasFocus() )
446             return;
447     }
448 
449     notify_toolbox_item_focus(pToolBox);
450 }
451 
452 static void handle_toolbox_highlightoff(Window *pWindow)
453 {
454     ToolBox *pToolBox = static_cast <ToolBox *> (pWindow);
455     ToolBox* pToolBoxParent = dynamic_cast< ToolBox* >( pToolBox->GetParent() );
456 
457     // Notify when leaving sub toolboxes
458     if( pToolBoxParent && pToolBoxParent->HasFocus() )
459         notify_toolbox_item_focus( pToolBoxParent );
460 }
461 
462 /*****************************************************************************/
463 
464 static void create_wrapper_for_child(
465     const uno::Reference< accessibility::XAccessibleContext >& xContext,
466     sal_Int32 index)
467 {
468     if( xContext.is() )
469     {
470         uno::Reference< accessibility::XAccessible > xChild(xContext->getAccessibleChild(index));
471         if( xChild.is() )
472         {
473             // create the wrapper object - it will survive the unref unless it is a transient object
474             g_object_unref( atk_object_wrapper_ref( xChild ) );
475         }
476     }
477 }
478 
479 /*****************************************************************************/
480 
481 static void handle_toolbox_buttonchange(VclWindowEvent const *pEvent)
482 {
483     Window* pWindow = pEvent->GetWindow();
484     sal_Int32 index = (sal_Int32)(sal_IntPtr) pEvent->GetData();
485 
486     if( pWindow && pWindow->IsReallyVisible() )
487     {
488         uno::Reference< accessibility::XAccessible > xAccessible(pWindow->GetAccessible());
489         if( xAccessible.is() )
490         {
491             create_wrapper_for_child(xAccessible->getAccessibleContext(), index);
492         }
493     }
494 }
495 
496 /*****************************************************************************/
497 
498 /* currently not needed anymore...
499 static void create_wrapper_for_children(Window *pWindow)
500 {
501     if( pWindow && pWindow->IsReallyVisible() )
502     {
503         uno::Reference< accessibility::XAccessible > xAccessible(pWindow->GetAccessible());
504         if( xAccessible.is() )
505         {
506             uno::Reference< accessibility::XAccessibleContext > xContext(xAccessible->getAccessibleContext());
507             if( xContext.is() )
508             {
509                 sal_Int32 nChildren = xContext->getAccessibleChildCount();
510                 for( sal_Int32 i = 0; i < nChildren; ++i )
511                     create_wrapper_for_child(xContext, i);
512             }
513         }
514     }
515 }
516 */
517 
518 /*****************************************************************************/
519 
520 static std::set< Window * > g_aWindowList;
521 
522 static void handle_get_focus(::VclWindowEvent const * pEvent)
523 {
524     static rtl::Reference< DocumentFocusListener > aDocumentFocusListener =
525         new DocumentFocusListener();
526 
527     Window *pWindow = pEvent->GetWindow();
528 
529     // The menu bar is handled through VCLEVENT_MENU_HIGHLIGHTED
530     if( ! pWindow || !pWindow->IsReallyVisible() || pWindow->GetType() == WINDOW_MENUBARWINDOW )
531         return;
532 
533     // ToolBoxes are handled through VCLEVENT_TOOLBOX_HIGHLIGHT
534     if( pWindow->GetType() == WINDOW_TOOLBOX )
535         return;
536 
537     if( pWindow->GetType() == WINDOW_TABCONTROL )
538     {
539         handle_tabpage_activated( pWindow );
540         return;
541     }
542 
543     uno::Reference< accessibility::XAccessible > xAccessible =
544         pWindow->GetAccessible();
545 
546     if( ! xAccessible.is() )
547         return;
548 
549     uno::Reference< accessibility::XAccessibleContext > xContext =
550         xAccessible->getAccessibleContext();
551 
552     if( ! xContext.is() )
553         return;
554 
555     uno::Reference< accessibility::XAccessibleStateSet > xStateSet =
556         xContext->getAccessibleStateSet();
557 
558     if( ! xStateSet.is() )
559         return;
560 
561 /* the UNO ToolBox wrapper does not (yet?) support XAccessibleSelection, so we
562  * need to add listeners to the children instead of re-using the tabpage stuff
563  */
564     if( xStateSet->contains(accessibility::AccessibleStateType::FOCUSED) &&
565         ( pWindow->GetType() != WINDOW_TREELISTBOX ) )
566     {
567         atk_wrapper_focus_tracker_notify_when_idle( xAccessible );
568     }
569     else
570     {
571         if( g_aWindowList.find(pWindow) == g_aWindowList.end() )
572         {
573             g_aWindowList.insert(pWindow);
574             try
575             {
576                 aDocumentFocusListener->attachRecursive(xAccessible, xContext, xStateSet);
577             }
578             catch( const uno::Exception &e )
579             {
580                 g_warning( "Exception caught processing focus events" );
581             }
582         }
583 #ifdef ENABLE_TRACING
584         else
585             fprintf(stderr, "Window %p already in the list\n", pWindow );
586 #endif
587     }
588 }
589 
590 /*****************************************************************************/
591 
592 static void handle_menu_highlighted(::VclMenuEvent const * pEvent)
593 {
594     try
595     {
596         Menu* pMenu = pEvent->GetMenu();
597         sal_uInt16 nPos = pEvent->GetItemPos();
598 
599         if( pMenu &&  nPos != 0xFFFF)
600         {
601             uno::Reference< accessibility::XAccessible > xAccessible ( pMenu->GetAccessible() );
602 
603             if( xAccessible.is() )
604             {
605                 uno::Reference< accessibility::XAccessibleContext > xContext ( xAccessible->getAccessibleContext() );
606 
607                 if( xContext.is() )
608                     atk_wrapper_focus_tracker_notify_when_idle( xContext->getAccessibleChild( nPos ) );
609             }
610         }
611     }
612     catch( const uno::Exception& e )
613     {
614         g_warning( "Exception caught processing menu highlight events" );
615     }
616 }
617 
618 /*****************************************************************************/
619 
620 long WindowEventHandler(void *, ::VclSimpleEvent const * pEvent)
621 {
622     switch (pEvent->GetId())
623     {
624     case VCLEVENT_WINDOW_SHOW:
625 //        fprintf(stderr, "got VCLEVENT_WINDOW_SHOW for %p\n",
626 //            static_cast< ::VclWindowEvent const * >(pEvent)->GetWindow());
627         break;
628     case VCLEVENT_WINDOW_HIDE:
629 //        fprintf(stderr, "got VCLEVENT_WINDOW_HIDE for %p\n",
630 //            static_cast< ::VclWindowEvent const * >(pEvent)->GetWindow());
631         break;
632     case VCLEVENT_WINDOW_CLOSE:
633 //        fprintf(stderr, "got VCLEVENT_WINDOW_CLOSE for %p\n",
634 //            static_cast< ::VclWindowEvent const * >(pEvent)->GetWindow());
635         break;
636     case VCLEVENT_WINDOW_GETFOCUS:
637         handle_get_focus(static_cast< ::VclWindowEvent const * >(pEvent));
638         break;
639     case VCLEVENT_WINDOW_LOSEFOCUS:
640 //        fprintf(stderr, "got VCLEVENT_WINDOW_LOSEFOCUS for %p\n",
641 //            static_cast< ::VclWindowEvent const * >(pEvent)->GetWindow());
642         break;
643     case VCLEVENT_WINDOW_MINIMIZE:
644 //        fprintf(stderr, "got VCLEVENT_WINDOW_MINIMIZE for %p\n",
645 //            static_cast< ::VclWindowEvent const * >(pEvent)->GetWindow());
646         break;
647     case VCLEVENT_WINDOW_NORMALIZE:
648 //        fprintf(stderr, "got VCLEVENT_WINDOW_NORMALIZE for %p\n",
649 //            static_cast< ::VclWindowEvent const * >(pEvent)->GetWindow());
650         break;
651     case VCLEVENT_WINDOW_KEYINPUT:
652     case VCLEVENT_WINDOW_KEYUP:
653     case VCLEVENT_WINDOW_COMMAND:
654     case VCLEVENT_WINDOW_MOUSEMOVE:
655         break;
656  /*
657         fprintf(stderr, "got VCLEVENT_WINDOW_COMMAND (%d) for %p\n",
658             static_cast< ::CommandEvent const * > (
659                 static_cast< ::VclWindowEvent const * >(pEvent)->GetData())->GetCommand(),
660             static_cast< ::VclWindowEvent const * >(pEvent)->GetWindow());
661  */
662     case VCLEVENT_MENU_HIGHLIGHT:
663         if (const VclMenuEvent* pMenuEvent = dynamic_cast<const VclMenuEvent*>(pEvent))
664         {
665             handle_menu_highlighted(pMenuEvent);
666         }
667         else if (const VclAccessibleEvent* pAccEvent = dynamic_cast<const VclAccessibleEvent*>(pEvent))
668         {
669             uno::Reference< accessibility::XAccessible > xAccessible = pAccEvent->GetAccessible();
670             if (xAccessible.is())
671                 atk_wrapper_focus_tracker_notify_when_idle(xAccessible);
672         }
673         break;
674 
675     case VCLEVENT_TOOLBOX_HIGHLIGHT:
676         handle_toolbox_highlight(static_cast< ::VclWindowEvent const * >(pEvent)->GetWindow());
677         break;
678 
679     case VCLEVENT_TOOLBOX_BUTTONSTATECHANGED:
680         handle_toolbox_buttonchange(static_cast< ::VclWindowEvent const * >(pEvent));
681         break;
682 
683     case VCLEVENT_OBJECT_DYING:
684         g_aWindowList.erase( static_cast< ::VclWindowEvent const * >(pEvent)->GetWindow() );
685         // fallthrough intentional !
686     case VCLEVENT_TOOLBOX_HIGHLIGHTOFF:
687         handle_toolbox_highlightoff(static_cast< ::VclWindowEvent const * >(pEvent)->GetWindow());
688         break;
689 
690     case VCLEVENT_TABPAGE_ACTIVATE:
691         handle_tabpage_activated(static_cast< ::VclWindowEvent const * >(pEvent)->GetWindow());
692         break;
693 
694     case VCLEVENT_COMBOBOX_SETTEXT:
695         // MT 2010/02: This looks quite strange to me. Stumbled over this when fixing #i104290#.
696         // This kicked in when leaving the combobox in the toolbar, after that the events worked.
697         // 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.
698         // Fix for #i104290# was done in toolkit/source/awt/vclxaccessiblecomponent, FOCUSED state for compound controls in general.
699         // create_wrapper_for_children(static_cast< ::VclWindowEvent const * >(pEvent)->GetWindow());
700         break;
701 
702     default:
703 //        OSL_TRACE("got event %d \n", pEvent->GetId());
704         break;
705     }
706     return 0;
707 }
708 
709 static Link g_aEventListenerLink( NULL, (PSTUB) WindowEventHandler );
710 
711 /*****************************************************************************/
712 
713 extern "C" {
714 
715 static G_CONST_RETURN gchar *
716 ooo_atk_util_get_toolkit_name (void)
717 {
718     return "VCL";
719 }
720 
721 /*****************************************************************************/
722 
723 static G_CONST_RETURN gchar *
724 ooo_atk_util_get_toolkit_version (void)
725 {
726     /*
727      * Version is passed in as a -D flag when this file is
728      * compiled.
729      */
730 
731     return VERSION;
732 }
733 
734 /*****************************************************************************/
735 
736 /*
737  * GObject inheritance
738  */
739 
740 static void
741 ooo_atk_util_class_init (AtkUtilClass *)
742 {
743     AtkUtilClass *atk_class;
744     gpointer data;
745 
746     data = g_type_class_peek (ATK_TYPE_UTIL);
747     atk_class = ATK_UTIL_CLASS (data);
748 
749     atk_class->get_toolkit_name = ooo_atk_util_get_toolkit_name;
750     atk_class->get_toolkit_version = ooo_atk_util_get_toolkit_version;
751 
752     Application::AddEventListener( g_aEventListenerLink );
753 }
754 
755 } // extern "C"
756 
757 /*****************************************************************************/
758 
759 GType
760 ooo_atk_util_get_type (void)
761 {
762     static GType type = 0;
763 
764     if (!type)
765     {
766         GType parent_type = g_type_from_name( "GailUtil" );
767 
768         if( ! parent_type )
769         {
770             g_warning( "Unknown type: GailUtil" );
771             parent_type = ATK_TYPE_UTIL;
772         }
773 
774         GTypeQuery type_query;
775         g_type_query( parent_type, &type_query );
776 
777         static const GTypeInfo typeInfo =
778         {
779             type_query.class_size,
780             (GBaseInitFunc) NULL,
781             (GBaseFinalizeFunc) NULL,
782             (GClassInitFunc) ooo_atk_util_class_init,
783             (GClassFinalizeFunc) NULL,
784             NULL,
785             type_query.instance_size,
786             0,
787             (GInstanceInitFunc) NULL,
788             NULL
789         } ;
790 
791         type = g_type_register_static (parent_type, "OOoUtil", &typeInfo, (GTypeFlags)0) ;
792   }
793 
794   return type;
795 }
796 
797 
798