summaryrefslogtreecommitdiff
path: root/vcl/unx/gtk
diff options
context:
space:
mode:
Diffstat (limited to 'vcl/unx/gtk')
-rw-r--r--vcl/unx/gtk/a11y/TODO49
-rw-r--r--vcl/unx/gtk/a11y/atkaction.cxx278
-rw-r--r--vcl/unx/gtk/a11y/atkbridge.cxx78
-rw-r--r--vcl/unx/gtk/a11y/atkcomponent.cxx382
-rw-r--r--vcl/unx/gtk/a11y/atkeditabletext.cxx202
-rw-r--r--vcl/unx/gtk/a11y/atkfactory.cxx183
-rw-r--r--vcl/unx/gtk/a11y/atkfactory.hxx41
-rw-r--r--vcl/unx/gtk/a11y/atkhypertext.cxx291
-rw-r--r--vcl/unx/gtk/a11y/atkimage.cxx138
-rw-r--r--vcl/unx/gtk/a11y/atklistener.cxx537
-rw-r--r--vcl/unx/gtk/a11y/atklistener.hxx79
-rw-r--r--vcl/unx/gtk/a11y/atkregistry.cxx71
-rw-r--r--vcl/unx/gtk/a11y/atkregistry.hxx40
-rw-r--r--vcl/unx/gtk/a11y/atkselection.cxx195
-rw-r--r--vcl/unx/gtk/a11y/atktable.cxx721
-rw-r--r--vcl/unx/gtk/a11y/atktext.cxx876
-rw-r--r--vcl/unx/gtk/a11y/atktextattributes.cxx1456
-rw-r--r--vcl/unx/gtk/a11y/atktextattributes.hxx54
-rw-r--r--vcl/unx/gtk/a11y/atkutil.cxx801
-rw-r--r--vcl/unx/gtk/a11y/atkutil.hxx37
-rw-r--r--vcl/unx/gtk/a11y/atkvalue.cxx147
-rw-r--r--vcl/unx/gtk/a11y/atkwindow.cxx331
-rw-r--r--vcl/unx/gtk/a11y/atkwindow.hxx38
-rw-r--r--vcl/unx/gtk/a11y/atkwrapper.cxx953
-rw-r--r--vcl/unx/gtk/a11y/atkwrapper.hxx125
-rw-r--r--vcl/unx/gtk/a11y/makefile.mk93
-rw-r--r--vcl/unx/gtk/app/gtkdata.cxx1019
-rw-r--r--vcl/unx/gtk/app/gtkinst.cxx367
-rw-r--r--vcl/unx/gtk/app/gtksys.cxx96
-rw-r--r--vcl/unx/gtk/app/makefile.mk76
-rw-r--r--vcl/unx/gtk/gdi/makefile.mk67
-rw-r--r--vcl/unx/gtk/gdi/salnativewidgets-gtk.cxx4084
-rw-r--r--vcl/unx/gtk/window/gtkframe.cxx3814
-rw-r--r--vcl/unx/gtk/window/gtkobject.cxx216
-rw-r--r--vcl/unx/gtk/window/makefile.mk79
35 files changed, 18014 insertions, 0 deletions
diff --git a/vcl/unx/gtk/a11y/TODO b/vcl/unx/gtk/a11y/TODO
new file mode 100644
index 000000000000..1048bd96ef75
--- /dev/null
+++ b/vcl/unx/gtk/a11y/TODO
@@ -0,0 +1,49 @@
+cws 'atkbridge'
+#Issue number: i#47890#
+Submitted by: mmeeks
+
+Hacked up prototype of atk bridge
+
+
+Serious problems
+ + Threading/locking:
+ + incoming CORBA calls & the GDK lock
+ + how are these being processed & on what thread ?
+ + are we holding the GDK_THREADS lock ?
+ + can we even do that ?
+ + is it really necessary to be thread safe ?
+ + how does this work in combination with the (unsafe) GAIL code ?
+ + what should incoming CORBA calls be doing ?
+ + esp. since we can't tell if they're coming from
+ in-proc or not either [ though this is unlikely ]
+
+
+Test:
+ + in-line text editing, does the TEXT_CHANGED signal get it right,
+ + why not copy/paste/delete etc. ?
+ + check vs. writer & other bits ...
+ + AtkSelection
+ + AtkHyper*
+
+* At-poke
+ + implement non-gui mode - for to-console event logging
+ + logging
+ + more detail from remaining events
+ + add a Tree navigation thing instead (?)
+ + poke a sub-child (?)
+ + embed a tree widget inside the tree view ?
+ + AtkHyperText testing (?)
+
+
+Known bugs:
+ + AtkText
+ + selection interface - multiple selections ?
+ + word boundary issues
+ + copy AccessibleTextImpl.java's getAfterIndex eg.
+ + the 'getFoo' methods need to use UNO_QUERY_THROW &
+ throw an exception to avoid null pointer dereferences.
+ + AtkAttributeSet (etc.)
+ + AtkEditableText
+ + finish/test AtkTable
+ + HyperLink 'link_activated', HyperText 'link_selected' (?)
+ + tooltips create new toplevels with broken roles.
diff --git a/vcl/unx/gtk/a11y/atkaction.cxx b/vcl/unx/gtk/a11y/atkaction.cxx
new file mode 100644
index 000000000000..4329dd345d14
--- /dev/null
+++ b/vcl/unx/gtk/a11y/atkaction.cxx
@@ -0,0 +1,278 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "atkwrapper.hxx"
+
+#include <com/sun/star/accessibility/XAccessibleAction.hpp>
+#include <com/sun/star/accessibility/XAccessibleKeyBinding.hpp>
+
+#include <com/sun/star/awt/Key.hpp>
+#include <com/sun/star/awt/KeyModifier.hpp>
+
+#include <rtl/strbuf.hxx>
+#include <algorithm>
+#include <map>
+
+#include <stdio.h>
+
+using namespace ::com::sun::star;
+
+// FIXME
+static G_CONST_RETURN gchar *
+getAsConst( const rtl::OString& rString )
+{
+ static const int nMax = 10;
+ static rtl::OString aUgly[nMax];
+ static int nIdx = 0;
+ nIdx = (nIdx + 1) % nMax;
+ aUgly[nIdx] = rString;
+ return aUgly[ nIdx ];
+}
+
+static accessibility::XAccessibleAction*
+ getAction( AtkAction *action ) throw (uno::RuntimeException)
+{
+ AtkObjectWrapper *pWrap = ATK_OBJECT_WRAPPER( action );
+
+ if( pWrap )
+ {
+ if( !pWrap->mpAction && pWrap->mpContext )
+ {
+ uno::Any any = pWrap->mpContext->queryInterface( accessibility::XAccessibleAction::static_type(NULL) );
+ pWrap->mpAction = reinterpret_cast< accessibility::XAccessibleAction * > (any.pReserved);
+ pWrap->mpAction->acquire();
+ }
+
+ return pWrap->mpAction;
+ }
+
+ return NULL;
+}
+
+extern "C" {
+
+static gboolean
+action_wrapper_do_action (AtkAction *action,
+ gint i)
+{
+ try {
+ accessibility::XAccessibleAction* pAction = getAction( action );
+ if( pAction )
+ return pAction->doAccessibleAction( i );
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in doAccessibleAction()" );
+ }
+
+ return FALSE;
+}
+
+static gint
+action_wrapper_get_n_actions (AtkAction *action)
+{
+ try {
+ accessibility::XAccessibleAction* pAction = getAction( action );
+ if( pAction )
+ return pAction->getAccessibleActionCount();
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getAccessibleActionCount()" );
+ }
+
+ return 0;
+}
+
+static G_CONST_RETURN gchar *
+action_wrapper_get_description (AtkAction *, gint)
+{
+ // GAIL implement this only for cells
+ g_warning( "Not implemented: get_description()" );
+ return "";
+}
+
+static G_CONST_RETURN gchar *
+action_wrapper_get_localized_name (AtkAction *, gint)
+{
+ // GAIL doesn't implement this as well
+ g_warning( "Not implemented: get_localized_name()" );
+ return "";
+}
+
+#define ACTION_NAME_PAIR( OOoName, AtkName ) \
+ std::pair< const rtl::OUString, const gchar * > ( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OOoName ) ), AtkName )
+
+static G_CONST_RETURN gchar *
+action_wrapper_get_name (AtkAction *action,
+ gint i)
+{
+ static std::map< rtl::OUString, const gchar * > aNameMap;
+
+ if( aNameMap.empty() )
+ {
+ aNameMap.insert( ACTION_NAME_PAIR( "click", "click" ) );
+ aNameMap.insert( ACTION_NAME_PAIR( "select", "click" ) );
+ aNameMap.insert( ACTION_NAME_PAIR( "togglePopup", "push" ) );
+ }
+
+ try {
+ accessibility::XAccessibleAction* pAction = getAction( action );
+ if( pAction )
+ {
+ std::map< rtl::OUString, const gchar * >::iterator iter;
+
+ rtl::OUString aDesc( pAction->getAccessibleActionDescription( i ) );
+
+ iter = aNameMap.find( aDesc );
+ if( iter != aNameMap.end() )
+ return iter->second;
+
+ std::pair< const rtl::OUString, const gchar * > aNewVal( aDesc,
+ g_strdup( OUStringToConstGChar(aDesc) ) );
+
+ if( aNameMap.insert( aNewVal ).second )
+ return aNewVal.second;
+ }
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getAccessibleActionDescription()" );
+ }
+
+ return "";
+}
+
+/*
+* GNOME Expects a string in the format:
+*
+* <nmemonic>;<full-path>;<accelerator>
+*
+* The keybindings in <full-path> should be separated by ":"
+*/
+
+static inline void
+appendKeyStrokes(rtl::OStringBuffer& rBuffer, const uno::Sequence< awt::KeyStroke >& rKeyStrokes)
+{
+ for( sal_Int32 i = 0; i < rKeyStrokes.getLength(); i++ )
+ {
+ if( rKeyStrokes[i].Modifiers & awt::KeyModifier::SHIFT )
+ rBuffer.append("<Shift>");
+ if( rKeyStrokes[i].Modifiers & awt::KeyModifier::MOD1 )
+ rBuffer.append("<Control>");
+ if( rKeyStrokes[i].Modifiers & awt::KeyModifier::MOD2 )
+ rBuffer.append("<Alt>");
+
+ if( ( rKeyStrokes[i].KeyCode >= awt::Key::A ) && ( rKeyStrokes[i].KeyCode <= awt::Key::Z ) )
+ rBuffer.append( (sal_Char) ( 'a' + ( rKeyStrokes[i].KeyCode - awt::Key::A ) ) );
+ else
+ {
+ sal_Char c = '\0';
+
+ switch( rKeyStrokes[i].KeyCode )
+ {
+ case awt::Key::TAB: c = '\t'; break;
+ case awt::Key::SPACE: c = ' '; break;
+ case awt::Key::ADD: c = '+'; break;
+ case awt::Key::SUBTRACT: c = '-'; break;
+ case awt::Key::MULTIPLY: c = '*'; break;
+ case awt::Key::DIVIDE: c = '/'; break;
+ case awt::Key::POINT: c = '.'; break;
+ case awt::Key::COMMA: c = ','; break;
+ case awt::Key::LESS: c = '<'; break;
+ case awt::Key::GREATER: c = '>'; break;
+ case awt::Key::EQUAL: c = '='; break;
+ case 0:
+ break;
+ default:
+ g_warning( "Unmapped KeyCode: %d", rKeyStrokes[i].KeyCode );
+ break;
+ }
+
+ if( c != '\0' )
+ rBuffer.append( c );
+ }
+ }
+}
+
+
+static G_CONST_RETURN gchar *
+action_wrapper_get_keybinding (AtkAction *action,
+ gint i)
+{
+ try {
+ accessibility::XAccessibleAction* pAction = getAction( action );
+ if( pAction )
+ {
+ uno::Reference< accessibility::XAccessibleKeyBinding > xBinding( pAction->getAccessibleActionKeyBinding( i ));
+
+ if( xBinding.is() )
+ {
+ rtl::OStringBuffer aRet;
+
+ sal_Int32 nmax = std::min( xBinding->getAccessibleKeyBindingCount(), (sal_Int32) 3 );
+ for( sal_Int32 n = 0; n < nmax; n++ )
+ {
+ appendKeyStrokes( aRet, xBinding->getAccessibleKeyBinding( n ) );
+
+ if( n < 2 )
+ aRet.append( (sal_Char) ';' );
+ }
+
+ // !! FIXME !! remember keystroke in wrapper object ?
+ return getAsConst( aRet.makeStringAndClear() );
+ }
+ }
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in get_keybinding()" );
+ }
+
+ return "";
+}
+
+static gboolean
+action_wrapper_set_description (AtkAction *, gint, const gchar *)
+{
+ return FALSE;
+}
+
+} // extern "C"
+
+void
+actionIfaceInit (AtkActionIface *iface)
+{
+ g_return_if_fail (iface != NULL);
+
+ iface->do_action = action_wrapper_do_action;
+ iface->get_n_actions = action_wrapper_get_n_actions;
+ iface->get_description = action_wrapper_get_description;
+ iface->get_keybinding = action_wrapper_get_keybinding;
+ iface->get_name = action_wrapper_get_name;
+ iface->get_localized_name = action_wrapper_get_localized_name;
+ iface->set_description = action_wrapper_set_description;
+}
diff --git a/vcl/unx/gtk/a11y/atkbridge.cxx b/vcl/unx/gtk/a11y/atkbridge.cxx
new file mode 100644
index 000000000000..25add8e0dd18
--- /dev/null
+++ b/vcl/unx/gtk/a11y/atkbridge.cxx
@@ -0,0 +1,78 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <plugins/gtk/atkbridge.hxx>
+#include <plugins/gtk/gtkframe.hxx>
+
+#include "atkfactory.hxx"
+#include "atkutil.hxx"
+#include "atkwindow.hxx"
+#include <stdio.h>
+
+bool InitAtkBridge(void)
+{
+ const char* pVersion = atk_get_toolkit_version();
+ if( ! pVersion )
+ return false;
+
+ unsigned int major, minor, micro;
+
+ /* check gail minimum version requirements */
+ if( sscanf( pVersion, "%u.%u.%u", &major, &minor, &micro) < 3 )
+ {
+ // g_warning( "unable to parse gail version number" );
+ return false;
+ }
+
+ if( ( (major << 16) | (minor << 8) | micro ) < ( (1 << 16) | 8 << 8 | 6 ) )
+ {
+ g_warning( "libgail >= 1.8.6 required for accessibility support" );
+ return false;
+ }
+
+ /* Initialize the AtkUtilityWrapper class */
+ g_type_class_unref( g_type_class_ref( OOO_TYPE_ATK_UTIL ) );
+
+ /* Initialize the GailWindow wrapper class */
+ g_type_class_unref( g_type_class_ref( OOO_TYPE_WINDOW_WRAPPER ) );
+
+ /* Register AtkObject wrapper factory */
+ AtkRegistry * registry = atk_get_default_registry();
+ if( registry )
+ atk_registry_set_factory_type( registry, OOO_TYPE_FIXED, OOO_TYPE_WRAPPER_FACTORY );
+
+ return true;
+}
+
+void DeInitAtkBridge()
+{
+ restore_gail_window_vtable();
+}
+
diff --git a/vcl/unx/gtk/a11y/atkcomponent.cxx b/vcl/unx/gtk/a11y/atkcomponent.cxx
new file mode 100644
index 000000000000..24cf335ebeb0
--- /dev/null
+++ b/vcl/unx/gtk/a11y/atkcomponent.cxx
@@ -0,0 +1,382 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "atkwrapper.hxx"
+
+#include <com/sun/star/accessibility/XAccessibleComponent.hpp>
+
+#ifdef ENABLE_TRACING
+#include <stdio.h>
+#endif
+
+using namespace ::com::sun::star;
+
+static accessibility::XAccessibleComponent*
+ getComponent( AtkComponent *pComponent ) throw (uno::RuntimeException)
+{
+ AtkObjectWrapper *pWrap = ATK_OBJECT_WRAPPER( pComponent );
+ if( pWrap )
+ {
+ if( !pWrap->mpComponent && pWrap->mpContext )
+ {
+ uno::Any any = pWrap->mpContext->queryInterface( accessibility::XAccessibleComponent::static_type(NULL) );
+ pWrap->mpComponent = reinterpret_cast< accessibility::XAccessibleComponent * > (any.pReserved);
+ pWrap->mpComponent->acquire();
+ }
+
+ return pWrap->mpComponent;
+ }
+
+ return NULL;
+}
+
+/*****************************************************************************/
+
+static awt::Point
+translatePoint( accessibility::XAccessibleComponent *pComponent,
+ gint x, gint y, AtkCoordType t)
+{
+ awt::Point aOrigin( 0, 0 );
+ if( t == ATK_XY_SCREEN )
+ aOrigin = pComponent->getLocationOnScreen();
+
+#ifdef ENABLE_TRACING
+ fprintf(stderr, "coordinates ( %u, %u ) translated to: ( %u, %u )\n",
+ x, y, x - aOrigin.X, y - aOrigin.Y);
+#endif
+
+ return awt::Point( x - aOrigin.X, y - aOrigin.Y );
+}
+
+/*****************************************************************************/
+
+extern "C" {
+
+static gboolean
+component_wrapper_grab_focus (AtkComponent *component)
+{
+ try
+ {
+ accessibility::XAccessibleComponent* pComponent = getComponent( component );
+ if( pComponent )
+ {
+ pComponent->grabFocus();
+ return TRUE;
+ }
+ }
+ catch( const uno::Exception &e )
+ {
+ g_warning( "Exception in grabFocus()" );
+ }
+
+ return FALSE;
+}
+
+/*****************************************************************************/
+
+static gboolean
+component_wrapper_contains (AtkComponent *component,
+ gint x,
+ gint y,
+ AtkCoordType coord_type)
+{
+ try
+ {
+ accessibility::XAccessibleComponent* pComponent = getComponent( component );
+ if( pComponent )
+ return pComponent->containsPoint( translatePoint( pComponent, x, y, coord_type ) );
+ }
+ catch( const uno::Exception &e )
+ {
+ g_warning( "Exception in containsPoint()" );
+ }
+
+ return FALSE;
+}
+
+/*****************************************************************************/
+
+static AtkObject *
+component_wrapper_ref_accessible_at_point (AtkComponent *component,
+ gint x,
+ gint y,
+ AtkCoordType coord_type)
+{
+ try
+ {
+ accessibility::XAccessibleComponent* pComponent = getComponent( component );
+
+ if( pComponent )
+ {
+ uno::Reference< accessibility::XAccessible > xAccessible;
+ xAccessible = pComponent->getAccessibleAtPoint(
+ translatePoint( pComponent, x, y, coord_type ) );
+
+#ifdef ENABLE_TRACING
+ fprintf(stderr, "getAccessibleAtPoint( %u, %u ) returned %p\n",
+ x, y, xAccessible.get());
+
+ uno::Reference< accessibility::XAccessibleComponent > xComponent(
+ xAccessible->getAccessibleContext(), uno::UNO_QUERY );
+
+ if( xComponent.is() )
+ {
+ awt::Rectangle rect = xComponent->getBounds();
+ fprintf(stderr, "%p->getBounds() returned: ( %u, %u, %u, %u )\n",
+ xAccessible.get(), rect.X, rect.Y, rect.Width, rect.Height );
+ }
+#endif
+
+ return atk_object_wrapper_ref( xAccessible );
+ }
+ }
+ catch( const uno::Exception &e )
+ {
+ g_warning( "Exception in getAccessibleAtPoint()" );
+ }
+
+ return NULL;
+}
+
+/*****************************************************************************/
+
+static void
+component_wrapper_get_position (AtkComponent *component,
+ gint *x,
+ gint *y,
+ AtkCoordType coord_type)
+{
+ try
+ {
+ accessibility::XAccessibleComponent* pComponent = getComponent( component );
+ if( pComponent )
+ {
+ awt::Point aPos;
+
+ if( coord_type == ATK_XY_SCREEN )
+ aPos = pComponent->getLocationOnScreen();
+ else
+ aPos = pComponent->getLocation();
+
+ *x = aPos.X;
+ *y = aPos.Y;
+
+#ifdef ENABLE_TRACING
+ fprintf(stderr, "getLocation[OnScreen]() returned: ( %u, %u )\n", *x, *y );
+#endif
+ }
+ }
+ catch( const uno::Exception &e )
+ {
+ g_warning( "Exception in getLocation[OnScreen]()" );
+ }
+}
+
+/*****************************************************************************/
+
+static void
+component_wrapper_get_size (AtkComponent *component,
+ gint *width,
+ gint *height)
+{
+ try
+ {
+ accessibility::XAccessibleComponent* pComponent = getComponent( component );
+ if( pComponent )
+ {
+ awt::Size aSize = pComponent->getSize();
+ *width = aSize.Width;
+ *height = aSize.Height;
+
+#ifdef ENABLE_TRACING
+ fprintf(stderr, "getSize() returned: ( %u, %u )\n", *width, *height );
+#endif
+ }
+ }
+ catch( const uno::Exception &e )
+ {
+ g_warning( "Exception in getSize()" );
+ }
+}
+
+/*****************************************************************************/
+
+static void
+component_wrapper_get_extents (AtkComponent *component,
+ gint *x,
+ gint *y,
+ gint *width,
+ gint *height,
+ AtkCoordType coord_type)
+{
+ component_wrapper_get_position( component, x, y, coord_type );
+ component_wrapper_get_size( component, width, height );
+}
+
+/*****************************************************************************/
+
+static gboolean
+component_wrapper_set_extents (AtkComponent *, gint, gint, gint, gint, AtkCoordType)
+{
+ g_warning( "AtkComponent::set_extents unimplementable" );
+ return FALSE;
+}
+
+/*****************************************************************************/
+
+static gboolean
+component_wrapper_set_position (AtkComponent *, gint, gint, AtkCoordType)
+{
+ g_warning( "AtkComponent::set_position unimplementable" );
+ return FALSE;
+}
+
+/*****************************************************************************/
+
+static gboolean
+component_wrapper_set_size (AtkComponent *, gint, gint)
+{
+ g_warning( "AtkComponent::set_size unimplementable" );
+ return FALSE;
+}
+
+/*****************************************************************************/
+
+static AtkLayer
+component_wrapper_get_layer (AtkComponent *component)
+{
+ AtkRole role = atk_object_get_role( ATK_OBJECT( component ) );
+ AtkLayer layer = ATK_LAYER_WIDGET;
+
+ switch (role)
+ {
+ case ATK_ROLE_POPUP_MENU:
+ case ATK_ROLE_MENU_ITEM:
+ case ATK_ROLE_CHECK_MENU_ITEM:
+ case ATK_ROLE_SEPARATOR:
+ case ATK_ROLE_LIST_ITEM:
+ layer = ATK_LAYER_POPUP;
+ break;
+ case ATK_ROLE_MENU:
+ {
+ AtkObject * parent = atk_object_get_parent( ATK_OBJECT( component ) );
+ if( atk_object_get_role( parent ) != ATK_ROLE_MENU_BAR )
+ layer = ATK_LAYER_POPUP;
+ }
+ break;
+
+ case ATK_ROLE_LIST:
+ {
+ AtkObject * parent = atk_object_get_parent( ATK_OBJECT( component ) );
+ if( atk_object_get_role( parent ) == ATK_ROLE_COMBO_BOX )
+ layer = ATK_LAYER_POPUP;
+ }
+ break;
+
+ default:
+ ;
+ }
+
+ return layer;
+}
+
+/*****************************************************************************/
+
+static gint
+component_wrapper_get_mdi_zorder (AtkComponent *)
+{
+ // only needed for ATK_LAYER_MDI (not used) or ATK_LAYER_WINDOW (inherited from GAIL)
+ return G_MININT;
+}
+
+/*****************************************************************************/
+
+// This code is mostly stolen from libgail ..
+
+static guint
+component_wrapper_add_focus_handler (AtkComponent *component,
+ AtkFocusHandler handler)
+{
+ GSignalMatchType match_type;
+ gulong ret;
+ guint signal_id;
+
+ match_type = (GSignalMatchType) (G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_FUNC);
+ signal_id = g_signal_lookup( "focus-event", ATK_TYPE_OBJECT );
+
+ ret = g_signal_handler_find( component, match_type, signal_id, 0, NULL,
+ (gpointer) &handler, NULL);
+ if (!ret)
+ {
+ return g_signal_connect_closure_by_id (component,
+ signal_id, 0,
+ g_cclosure_new (
+ G_CALLBACK (handler), NULL,
+ (GClosureNotify) NULL),
+ FALSE);
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+/*****************************************************************************/
+
+static void
+component_wrapper_remove_focus_handler (AtkComponent *component,
+ guint handler_id)
+{
+ g_signal_handler_disconnect (component, handler_id);
+}
+
+/*****************************************************************************/
+
+} // extern "C"
+
+void
+componentIfaceInit (AtkComponentIface *iface)
+{
+ g_return_if_fail (iface != NULL);
+
+ iface->add_focus_handler = component_wrapper_add_focus_handler;
+ iface->contains = component_wrapper_contains;
+ iface->get_extents = component_wrapper_get_extents;
+ iface->get_layer = component_wrapper_get_layer;
+ iface->get_mdi_zorder = component_wrapper_get_mdi_zorder;
+ iface->get_position = component_wrapper_get_position;
+ iface->get_size = component_wrapper_get_size;
+ iface->grab_focus = component_wrapper_grab_focus;
+ iface->ref_accessible_at_point = component_wrapper_ref_accessible_at_point;
+ iface->remove_focus_handler = component_wrapper_remove_focus_handler;
+ iface->set_extents = component_wrapper_set_extents;
+ iface->set_position = component_wrapper_set_position;
+ iface->set_size = component_wrapper_set_size;
+}
diff --git a/vcl/unx/gtk/a11y/atkeditabletext.cxx b/vcl/unx/gtk/a11y/atkeditabletext.cxx
new file mode 100644
index 000000000000..c0399145b07c
--- /dev/null
+++ b/vcl/unx/gtk/a11y/atkeditabletext.cxx
@@ -0,0 +1,202 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "atkwrapper.hxx"
+#include "atktextattributes.hxx"
+
+#include <com/sun/star/accessibility/XAccessibleEditableText.hpp>
+#include <com/sun/star/accessibility/TextSegment.hpp>
+
+// #include <functional>
+// #include <hash_map>
+
+#include <stdio.h>
+#include <string.h>
+
+using namespace ::com::sun::star;
+
+static accessibility::XAccessibleEditableText*
+ getEditableText( AtkEditableText *pEditableText ) throw (uno::RuntimeException)
+{
+ AtkObjectWrapper *pWrap = ATK_OBJECT_WRAPPER( pEditableText );
+ if( pWrap )
+ {
+ if( !pWrap->mpEditableText && pWrap->mpContext )
+ {
+ uno::Any any = pWrap->mpContext->queryInterface( accessibility::XAccessibleEditableText::static_type(NULL) );
+ pWrap->mpEditableText = reinterpret_cast< accessibility::XAccessibleEditableText * > (any.pReserved);
+ pWrap->mpEditableText->acquire();
+ }
+
+ return pWrap->mpEditableText;
+ }
+
+ return NULL;
+}
+
+
+/*****************************************************************************/
+
+extern "C" {
+
+static gboolean
+editable_text_wrapper_set_run_attributes( AtkEditableText *text,
+ AtkAttributeSet *attribute_set,
+ gint nStartOffset,
+ gint nEndOffset)
+{
+ try {
+ accessibility::XAccessibleEditableText* pEditableText = getEditableText( text );
+ if( pEditableText )
+ {
+ uno::Sequence< beans::PropertyValue > aAttributeList;
+
+ if( attribute_set_map_to_property_values( attribute_set, aAttributeList ) )
+ return pEditableText->setAttributes(nStartOffset, nEndOffset, aAttributeList);
+ }
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in setAttributes()" );
+ }
+
+ return FALSE;
+}
+
+static void
+editable_text_wrapper_set_text_contents( AtkEditableText *text,
+ const gchar *string )
+{
+ try {
+ accessibility::XAccessibleEditableText* pEditableText = getEditableText( text );
+ if( pEditableText )
+ {
+ rtl::OUString aString ( string, strlen(string), RTL_TEXTENCODING_UTF8 );
+ pEditableText->setText( aString );
+ }
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in setText()" );
+ }
+}
+
+static void
+editable_text_wrapper_insert_text( AtkEditableText *text,
+ const gchar *string,
+ gint length,
+ gint *pos )
+{
+ try {
+ accessibility::XAccessibleEditableText* pEditableText = getEditableText( text );
+ if( pEditableText )
+ {
+ rtl::OUString aString ( string, length, RTL_TEXTENCODING_UTF8 );
+ if( pEditableText->insertText( aString, *pos ) )
+ *pos += length;
+ }
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in insertText()" );
+ }
+}
+
+static void
+editable_text_wrapper_cut_text( AtkEditableText *text,
+ gint start,
+ gint end )
+{
+ try {
+ accessibility::XAccessibleEditableText* pEditableText = getEditableText( text );
+ if( pEditableText )
+ pEditableText->cutText( start, end );
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in cutText()" );
+ }
+}
+
+static void
+editable_text_wrapper_delete_text( AtkEditableText *text,
+ gint start,
+ gint end )
+{
+ try {
+ accessibility::XAccessibleEditableText* pEditableText = getEditableText( text );
+ if( pEditableText )
+ pEditableText->deleteText( start, end );
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in deleteText()" );
+ }
+}
+
+static void
+editable_text_wrapper_paste_text( AtkEditableText *text,
+ gint pos )
+{
+ try {
+ accessibility::XAccessibleEditableText* pEditableText = getEditableText( text );
+ if( pEditableText )
+ pEditableText->pasteText( pos );
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in pasteText()" );
+ }
+}
+
+static void
+editable_text_wrapper_copy_text( AtkEditableText *text,
+ gint start,
+ gint end )
+{
+ try {
+ accessibility::XAccessibleEditableText* pEditableText = getEditableText( text );
+ if( pEditableText )
+ pEditableText->copyText( start, end );
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in copyText()" );
+ }
+}
+
+} // extern "C"
+
+void
+editableTextIfaceInit (AtkEditableTextIface *iface)
+{
+ g_return_if_fail (iface != NULL);
+
+ iface->set_text_contents = editable_text_wrapper_set_text_contents;
+ iface->insert_text = editable_text_wrapper_insert_text;
+ iface->copy_text = editable_text_wrapper_copy_text;
+ iface->cut_text = editable_text_wrapper_cut_text;
+ iface->delete_text = editable_text_wrapper_delete_text;
+ iface->paste_text = editable_text_wrapper_paste_text;
+ iface->set_run_attributes = editable_text_wrapper_set_run_attributes;
+}
diff --git a/vcl/unx/gtk/a11y/atkfactory.cxx b/vcl/unx/gtk/a11y/atkfactory.cxx
new file mode 100644
index 000000000000..d2574f616539
--- /dev/null
+++ b/vcl/unx/gtk/a11y/atkfactory.cxx
@@ -0,0 +1,183 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <plugins/gtk/gtkframe.hxx>
+#include <vcl/window.hxx>
+#include "atkwrapper.hxx"
+#include "atkfactory.hxx"
+#include "atkregistry.hxx"
+
+using namespace ::com::sun::star;
+
+extern "C" {
+
+/*
+ * Instances of this dummy object class are returned whenever we have to
+ * create an AtkObject, but can't touch the OOo object anymore since it
+ * is already disposed.
+ */
+
+static AtkStateSet *
+noop_wrapper_ref_state_set( AtkObject * )
+{
+ AtkStateSet *state_set = atk_state_set_new();
+ atk_state_set_add_state( state_set, ATK_STATE_DEFUNCT );
+ return state_set;
+}
+
+static void
+atk_noop_object_wrapper_class_init(AtkNoOpObjectClass *klass)
+{
+ AtkObjectClass *atk_class = ATK_OBJECT_CLASS( klass );
+ atk_class->ref_state_set = noop_wrapper_ref_state_set;
+}
+
+static GType
+atk_noop_object_wrapper_get_type(void)
+{
+ static GType type = 0;
+
+ if (!type)
+ {
+ static const GTypeInfo typeInfo =
+ {
+ sizeof (AtkNoOpObjectClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) atk_noop_object_wrapper_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL,
+ sizeof (AtkObjectWrapper),
+ 0,
+ (GInstanceInitFunc) NULL,
+ NULL
+ } ;
+
+ type = g_type_register_static (ATK_TYPE_OBJECT, "OOoAtkNoOpObj", &typeInfo, (GTypeFlags)0) ;
+ }
+ return type;
+}
+
+AtkObject*
+atk_noop_object_wrapper_new()
+{
+ AtkObject *accessible;
+
+ accessible = (AtkObject *) g_object_new (atk_noop_object_wrapper_get_type(), NULL);
+ g_return_val_if_fail (accessible != NULL, NULL);
+
+ accessible->role = ATK_ROLE_INVALID;
+ accessible->layer = ATK_LAYER_INVALID;
+
+ return accessible;
+}
+
+/*
+ * The wrapper factory
+ */
+
+static GType
+wrapper_factory_get_accessible_type(void)
+{
+ return atk_object_wrapper_get_type();
+}
+
+static AtkObject*
+wrapper_factory_create_accessible( GObject *obj )
+{
+ GtkWidget* parent_widget = gtk_widget_get_parent( GTK_WIDGET( obj ) );
+
+ // gail_container_real_remove_gtk tries to re-instanciate an accessible
+ // for a widget that is about to vanish ..
+ if( ! parent_widget )
+ return atk_noop_object_wrapper_new();
+
+ GtkSalFrame* pFrame = GtkSalFrame::getFromWindow( GTK_WINDOW( parent_widget ) );
+ g_return_val_if_fail( pFrame != NULL, NULL );
+
+ Window* pFrameWindow = pFrame->GetWindow();
+ if( pFrameWindow )
+ {
+ Window* pWindow = pFrameWindow;
+
+ // skip accessible objects already exposed by the frame objects
+ if( WINDOW_BORDERWINDOW == pWindow->GetType() )
+ pWindow = pFrameWindow->GetAccessibleChildWindow(0);
+
+ if( pWindow )
+ {
+ uno::Reference< accessibility::XAccessible > xAccessible = pWindow->GetAccessible(true);
+ if( xAccessible.is() )
+ {
+ AtkObject *accessible = ooo_wrapper_registry_get( xAccessible );
+
+ if( accessible )
+ g_object_ref( G_OBJECT(accessible) );
+ else
+ accessible = atk_object_wrapper_new( xAccessible, gtk_widget_get_accessible(parent_widget) );
+
+ return accessible;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+static void
+wrapper_factory_class_init( AtkObjectFactoryClass *klass )
+{
+ klass->create_accessible = wrapper_factory_create_accessible;
+ klass->get_accessible_type = wrapper_factory_get_accessible_type;
+}
+
+GType
+wrapper_factory_get_type (void)
+{
+ static GType t = 0;
+
+ if (!t) {
+ static const GTypeInfo tinfo =
+ {
+ sizeof (AtkObjectFactoryClass),
+ NULL, NULL, (GClassInitFunc) wrapper_factory_class_init,
+ NULL, NULL, sizeof (AtkObjectFactory), 0, NULL, NULL
+ };
+
+ t = g_type_register_static (
+ ATK_TYPE_OBJECT_FACTORY, "OOoAtkObjectWrapperFactory",
+ &tinfo, (GTypeFlags) 0);
+ }
+
+ return t;
+}
+
+} // extern C
+
diff --git a/vcl/unx/gtk/a11y/atkfactory.hxx b/vcl/unx/gtk/a11y/atkfactory.hxx
new file mode 100644
index 000000000000..82be08cfad1b
--- /dev/null
+++ b/vcl/unx/gtk/a11y/atkfactory.hxx
@@ -0,0 +1,41 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef __ATK_FACTORY_HXX__
+#define __ATK_FACTORY_HXX__
+
+#include <atk/atk.h>
+
+#define OOO_TYPE_WRAPPER_FACTORY wrapper_factory_get_type()
+
+extern "C" {
+
+GType wrapper_factory_get_type (void);
+
+} // extern "C"
+
+#endif
diff --git a/vcl/unx/gtk/a11y/atkhypertext.cxx b/vcl/unx/gtk/a11y/atkhypertext.cxx
new file mode 100644
index 000000000000..90d735890655
--- /dev/null
+++ b/vcl/unx/gtk/a11y/atkhypertext.cxx
@@ -0,0 +1,291 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "atkwrapper.hxx"
+
+#include <com/sun/star/accessibility/XAccessibleHypertext.hpp>
+
+#include <stdio.h>
+
+using namespace ::com::sun::star;
+
+
+// ---------------------- AtkHyperlink ----------------------
+
+typedef struct {
+ AtkHyperlink atk_hyper_link;
+
+ uno::Reference< accessibility::XAccessibleHyperlink > xLink;
+} HyperLink;
+
+static uno::Reference< accessibility::XAccessibleHyperlink >
+ getHyperlink( AtkHyperlink *pHyperlink )
+{
+ HyperLink *pLink = (HyperLink *) pHyperlink;
+ return pLink->xLink;
+}
+
+static GObjectClass *hyper_parent_class = NULL;
+
+extern "C" {
+
+static void
+hyper_link_finalize (GObject *obj)
+{
+ HyperLink *hl = (HyperLink *) obj;
+ hl->xLink.clear();
+ hyper_parent_class->finalize (obj);
+}
+
+static gchar *
+hyper_link_get_uri( AtkHyperlink *pLink,
+ gint i )
+{
+ try {
+ uno::Any aAny = getHyperlink( pLink )->getAccessibleActionObject( i );
+ rtl::OUString aUri = aAny.get< rtl::OUString > ();
+ return OUStringToGChar(aUri);
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in hyper_link_get_uri" );
+ }
+ return NULL;
+}
+
+static AtkObject *
+hyper_link_get_object( AtkHyperlink *pLink,
+ gint i)
+{
+ try {
+ uno::Any aAny = getHyperlink( pLink )->getAccessibleActionObject( i );
+ uno::Reference< accessibility::XAccessible > xObj( aAny, uno::UNO_QUERY_THROW );
+ return atk_object_wrapper_ref( xObj );
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in hyper_link_get_object" );
+ }
+ return NULL;
+}
+static gint
+hyper_link_get_end_index( AtkHyperlink *pLink )
+{
+ try {
+ return getHyperlink( pLink )->getEndIndex();
+ }
+ catch(const uno::Exception& e) {
+ }
+ return -1;
+}
+static gint
+hyper_link_get_start_index( AtkHyperlink *pLink )
+{
+ try {
+ return getHyperlink( pLink )->getStartIndex();
+ }
+ catch(const uno::Exception& e) {
+ }
+ return -1;
+}
+static gboolean
+hyper_link_is_valid( AtkHyperlink *pLink )
+{
+ try {
+ return getHyperlink( pLink )->isValid();
+ }
+ catch(const uno::Exception& e) {
+ }
+ return FALSE;
+}
+static gint
+hyper_link_get_n_anchors( AtkHyperlink *pLink )
+{
+ try {
+ return getHyperlink( pLink )->getAccessibleActionCount();
+ }
+ catch(const uno::Exception& e) {
+ }
+ return 0;
+}
+
+static guint
+hyper_link_link_state( AtkHyperlink * )
+{
+ g_warning( "FIXME: hyper_link_link_state unimplemented" );
+ return 0;
+}
+static gboolean
+hyper_link_is_selected_link( AtkHyperlink * )
+{
+ g_warning( "FIXME: hyper_link_is_selected_link unimplemented" );
+ return FALSE;
+}
+
+static void
+hyper_link_class_init (AtkHyperlinkClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->finalize = hyper_link_finalize;
+
+ hyper_parent_class = (GObjectClass *)g_type_class_peek_parent (klass);
+
+ klass->get_uri = hyper_link_get_uri;
+ klass->get_object = hyper_link_get_object;
+ klass->get_end_index = hyper_link_get_end_index;
+ klass->get_start_index = hyper_link_get_start_index;
+ klass->is_valid = hyper_link_is_valid;
+ klass->get_n_anchors = hyper_link_get_n_anchors;
+ klass->link_state = hyper_link_link_state;
+ klass->is_selected_link = hyper_link_is_selected_link;
+}
+
+static GType
+hyper_link_get_type (void)
+{
+ static GType type = 0;
+
+ if (!type) {
+ static const GTypeInfo tinfo = {
+ sizeof (AtkHyperlinkClass),
+ NULL, /* base init */
+ NULL, /* base finalize */
+ (GClassInitFunc) hyper_link_class_init,
+ NULL, /* class finalize */
+ NULL, /* class data */
+ sizeof (HyperLink), /* instance size */
+ 0, /* nb preallocs */
+ NULL, /* instance init */
+ NULL /* value table */
+ };
+
+ static const GInterfaceInfo atk_action_info = {
+ (GInterfaceInitFunc) actionIfaceInit,
+ (GInterfaceFinalizeFunc) NULL,
+ NULL
+ };
+
+ type = g_type_register_static (ATK_TYPE_HYPERLINK,
+ "OOoAtkObjHyperLink", &tinfo,
+ (GTypeFlags)0);
+ g_type_add_interface_static (type, ATK_TYPE_ACTION,
+ &atk_action_info);
+ }
+
+ return type;
+}
+
+// ---------------------- AtkHyperText ----------------------
+
+static accessibility::XAccessibleHypertext*
+ getHypertext( AtkHypertext *pHypertext ) throw (uno::RuntimeException)
+{
+ AtkObjectWrapper *pWrap = ATK_OBJECT_WRAPPER( pHypertext );
+ if( pWrap )
+ {
+ if( !pWrap->mpHypertext && pWrap->mpContext )
+ {
+ uno::Any any = pWrap->mpContext->queryInterface( accessibility::XAccessibleHypertext::static_type(NULL) );
+ pWrap->mpHypertext = reinterpret_cast< accessibility::XAccessibleHypertext * > (any.pReserved);
+ pWrap->mpHypertext->acquire();
+ }
+
+ return pWrap->mpHypertext;
+ }
+
+ return NULL;
+}
+
+
+static AtkHyperlink *
+hypertext_get_link( AtkHypertext *hypertext,
+ gint link_index)
+{
+ try {
+ accessibility::XAccessibleHypertext* pHypertext = getHypertext( hypertext );
+ if( pHypertext )
+ {
+ HyperLink *pLink = (HyperLink *)g_object_new( hyper_link_get_type(), NULL );
+ pLink->xLink = pHypertext->getHyperLink( link_index );
+ if( !pLink->xLink.is() ) {
+ g_object_unref( G_OBJECT( pLink ) );
+ pLink = NULL;
+ }
+ return ATK_HYPERLINK( pLink );
+ }
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getHyperLink()" );
+ }
+
+ return NULL;
+}
+
+static gint
+hypertext_get_n_links( AtkHypertext *hypertext )
+{
+ try {
+ accessibility::XAccessibleHypertext* pHypertext = getHypertext( hypertext );
+ if( pHypertext )
+ return pHypertext->getHyperLinkCount();
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getHyperLinkCount()" );
+ }
+
+ return 0;
+}
+
+static gint
+hypertext_get_link_index( AtkHypertext *hypertext,
+ gint index)
+{
+ try {
+ accessibility::XAccessibleHypertext* pHypertext = getHypertext( hypertext );
+ if( pHypertext )
+ return pHypertext->getHyperLinkIndex( index );
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getHyperLinkIndex()" );
+ }
+
+ return 0;
+}
+
+} // extern "C"
+
+void
+hypertextIfaceInit (AtkHypertextIface *iface)
+{
+ g_return_if_fail (iface != NULL);
+
+ iface->get_link = hypertext_get_link;
+ iface->get_n_links = hypertext_get_n_links;
+ iface->get_link_index = hypertext_get_link_index;
+}
diff --git a/vcl/unx/gtk/a11y/atkimage.cxx b/vcl/unx/gtk/a11y/atkimage.cxx
new file mode 100644
index 000000000000..b48c59555a29
--- /dev/null
+++ b/vcl/unx/gtk/a11y/atkimage.cxx
@@ -0,0 +1,138 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "atkwrapper.hxx"
+
+#include <com/sun/star/accessibility/XAccessibleImage.hpp>
+
+#include <stdio.h>
+
+using namespace ::com::sun::star;
+
+// FIXME
+static G_CONST_RETURN gchar *
+getAsConst( rtl::OUString rString )
+{
+ static const int nMax = 10;
+ static rtl::OString aUgly[nMax];
+ static int nIdx = 0;
+ nIdx = (nIdx + 1) % nMax;
+ aUgly[nIdx] = rtl::OUStringToOString( rString, RTL_TEXTENCODING_UTF8 );
+ return aUgly[ nIdx ];
+}
+
+static accessibility::XAccessibleImage*
+ getImage( AtkImage *pImage ) throw (uno::RuntimeException)
+{
+ AtkObjectWrapper *pWrap = ATK_OBJECT_WRAPPER( pImage );
+ if( pWrap )
+ {
+ if( !pWrap->mpImage && pWrap->mpContext )
+ {
+ uno::Any any = pWrap->mpContext->queryInterface( accessibility::XAccessibleImage::static_type(NULL) );
+ pWrap->mpImage = reinterpret_cast< accessibility::XAccessibleImage * > (any.pReserved);
+ pWrap->mpImage->acquire();
+ }
+
+ return pWrap->mpImage;
+ }
+
+ return NULL;
+}
+
+extern "C" {
+
+static G_CONST_RETURN gchar *
+image_get_image_description( AtkImage *image )
+{
+ try {
+ accessibility::XAccessibleImage* pImage = getImage( image );
+ if( pImage )
+ return getAsConst( pImage->getAccessibleImageDescription() );
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getAccessibleImageDescription()" );
+ }
+
+ return NULL;
+}
+
+static void
+image_get_image_position( AtkImage *image,
+ gint *x,
+ gint *y,
+ AtkCoordType coord_type )
+{
+ *x = *y = 0;
+ if( ATK_IS_COMPONENT( image ) )
+ atk_component_get_position( ATK_COMPONENT( image ), x, y, coord_type );
+ else
+ g_warning( "FIXME: no image position information" );
+}
+
+static void
+image_get_image_size( AtkImage *image,
+ gint *width,
+ gint *height )
+{
+ *width = 0;
+ *height = 0;
+ try {
+ accessibility::XAccessibleImage* pImage = getImage( image );
+ if( pImage )
+ {
+ *width = pImage->getAccessibleImageWidth();
+ *height = pImage->getAccessibleImageHeight();
+ }
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getAccessibleImageHeight() or Width" );
+ }
+}
+
+static gboolean
+image_set_image_description( AtkImage *, const gchar * )
+{
+ g_warning ("FIXME: no set image description");
+ return FALSE;
+}
+
+} // extern "C"
+
+void
+imageIfaceInit (AtkImageIface *iface)
+{
+ g_return_if_fail (iface != NULL);
+
+ iface->set_image_description = image_set_image_description;
+ iface->get_image_description = image_get_image_description;
+ iface->get_image_position = image_get_image_position;
+ iface->get_image_size = image_get_image_size;
+}
diff --git a/vcl/unx/gtk/a11y/atklistener.cxx b/vcl/unx/gtk/a11y/atklistener.cxx
new file mode 100644
index 000000000000..e02478ac8ad8
--- /dev/null
+++ b/vcl/unx/gtk/a11y/atklistener.cxx
@@ -0,0 +1,537 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <com/sun/star/accessibility/TextSegment.hpp>
+#include <com/sun/star/accessibility/AccessibleEventId.hpp>
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+#include <com/sun/star/accessibility/AccessibleTableModelChange.hpp>
+#include <com/sun/star/accessibility/AccessibleTableModelChangeType.hpp>
+#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp>
+
+#include "atklistener.hxx"
+#include "atkwrapper.hxx"
+
+#include <rtl/ref.hxx>
+#include <stdio.h>
+
+using namespace com::sun::star;
+
+
+#define CSTRING_FROM_ANY(i) rtl::OUStringToOString( i.get< rtl::OUString >(), RTL_TEXTENCODING_UTF8 ).getStr()
+
+AtkListener::AtkListener( AtkObjectWrapper* pWrapper ) : mpWrapper( pWrapper )
+{
+ if( mpWrapper )
+ {
+ g_object_ref( mpWrapper );
+ updateChildList( mpWrapper->mpContext );
+ }
+}
+
+AtkListener::~AtkListener()
+{
+ if( mpWrapper )
+ g_object_unref( mpWrapper );
+}
+
+/*****************************************************************************/
+
+AtkStateType mapState( const uno::Any &rAny )
+{
+ sal_Int16 nState = accessibility::AccessibleStateType::INVALID;
+ rAny >>= nState;
+ return mapAtkState( nState );
+}
+
+/*****************************************************************************/
+
+// XEventListener implementation
+void AtkListener::disposing( const lang::EventObject& ) throw (uno::RuntimeException)
+{
+ if( mpWrapper )
+ {
+ AtkObject *atk_obj = ATK_OBJECT( mpWrapper );
+
+ // Release all interface references to avoid shutdown problems with
+ // global mutex
+ atk_object_wrapper_dispose( mpWrapper );
+
+ // This is an equivalent to a state change to DEFUNC(T).
+ atk_object_notify_state_change( atk_obj, ATK_STATE_DEFUNCT, TRUE );
+
+ if( atk_get_focus_object() == atk_obj )
+ atk_focus_tracker_notify( NULL );
+
+ // Release the wrapper object so that it can vanish ..
+ g_object_unref( mpWrapper );
+ mpWrapper = NULL;
+ }
+}
+
+/*****************************************************************************/
+
+static AtkObject *getObjFromAny( const uno::Any &rAny )
+{
+ uno::Reference< accessibility::XAccessible > xAccessible;
+ rAny >>= xAccessible;
+ return xAccessible.is() ? atk_object_wrapper_ref( xAccessible ) : NULL;
+}
+
+/*****************************************************************************/
+
+// Updates the child list held to provide the old IndexInParent on children_changed::remove
+void AtkListener::updateChildList(accessibility::XAccessibleContext* pContext)
+{
+ m_aChildList.clear();
+
+ uno::Reference< accessibility::XAccessibleStateSet > xStateSet = pContext->getAccessibleStateSet();
+ if( xStateSet.is()
+ && !xStateSet->contains(accessibility::AccessibleStateType::DEFUNC)
+ && !xStateSet->contains(accessibility::AccessibleStateType::MANAGES_DESCENDANTS) )
+ {
+ sal_Int32 nChildren = pContext->getAccessibleChildCount();
+ m_aChildList.resize(nChildren);
+ for(sal_Int32 n = 0; n < nChildren; n++)
+ {
+ m_aChildList[n] = pContext->getAccessibleChild(n);
+ OSL_ASSERT(m_aChildList[n].is());
+ }
+ }
+}
+
+/*****************************************************************************/
+
+void AtkListener::handleChildAdded(
+ const uno::Reference< accessibility::XAccessibleContext >& rxParent,
+ const uno::Reference< accessibility::XAccessible>& rxAccessible)
+{
+ AtkObject * pChild = atk_object_wrapper_ref( rxAccessible );
+
+ if( pChild )
+ {
+ updateChildList(rxParent.get());
+
+ atk_object_wrapper_add_child( mpWrapper, pChild,
+ atk_object_get_index_in_parent( pChild ));
+
+ g_object_unref( pChild );
+ }
+}
+
+/*****************************************************************************/
+
+void AtkListener::handleChildRemoved(
+ const uno::Reference< accessibility::XAccessibleContext >& rxParent,
+ const uno::Reference< accessibility::XAccessible>& rxChild)
+{
+ sal_Int32 nIndex = -1;
+
+ // Locate the child in the children list
+ size_t n, nmax = m_aChildList.size();
+ for( n = 0; n < nmax; ++n )
+ {
+ if( rxChild == m_aChildList[n] )
+ {
+ nIndex = n;
+ break;
+ }
+ }
+
+ // FIXME: two problems here:
+ // a) we get child-removed events for objects that are no real childs
+ // in the accessibility hierarchy or have been removed before due to
+ // some child removing batch.
+ // b) spi_atk_bridge_signal_listener ignores the given parameters
+ // for children_changed events and always asks the parent for the
+ // 0. child, which breaks somehow on vanishing list boxes.
+ // Ignoring "remove" events for objects not in the m_aChildList
+ // for now.
+ if( nIndex >= 0 )
+ {
+ updateChildList(rxParent.get());
+
+ AtkObject * pChild = atk_object_wrapper_ref( rxChild, false );
+ if( pChild )
+ {
+ atk_object_wrapper_remove_child( mpWrapper, pChild, nIndex );
+ g_object_unref( pChild );
+ }
+ }
+}
+
+/*****************************************************************************/
+
+void AtkListener::handleInvalidateChildren(
+ const uno::Reference< accessibility::XAccessibleContext >& rxParent)
+{
+ // Send notifications for all previous children
+ size_t n = m_aChildList.size();
+ while( n-- > 0 )
+ {
+ if( m_aChildList[n].is() )
+ {
+ AtkObject * pChild = atk_object_wrapper_ref( m_aChildList[n], false );
+ if( pChild )
+ {
+ atk_object_wrapper_remove_child( mpWrapper, pChild, n );
+ g_object_unref( pChild );
+ }
+ }
+ }
+
+ updateChildList(rxParent.get());
+
+ // Send notifications for all new children
+ size_t nmax = m_aChildList.size();
+ for( n = 0; n < nmax; ++n )
+ {
+ if( m_aChildList[n].is() )
+ {
+ AtkObject * pChild = atk_object_wrapper_ref( m_aChildList[n] );
+
+ if( pChild )
+ {
+ atk_object_wrapper_add_child( mpWrapper, pChild, n );
+ g_object_unref( pChild );
+ }
+ }
+ }
+}
+
+/*****************************************************************************/
+
+static uno::Reference< accessibility::XAccessibleContext >
+getAccessibleContextFromSource( const uno::Reference< uno::XInterface >& rxSource )
+{
+ uno::Reference< accessibility::XAccessibleContext > xContext(rxSource, uno::UNO_QUERY);
+ if( ! xContext.is() )
+ {
+ g_warning( "ERROR: Event source does not implement XAccessibleContext" );
+
+ // Second try - query for XAccessible, which should give us access to
+ // XAccessibleContext.
+ uno::Reference< accessibility::XAccessible > xAccessible(rxSource, uno::UNO_QUERY);
+ if( xAccessible.is() )
+ xContext = xAccessible->getAccessibleContext();
+ }
+
+ return xContext;
+}
+
+/*****************************************************************************/
+
+// XAccessibleEventListener
+void AtkListener::notifyEvent( const accessibility::AccessibleEventObject& aEvent ) throw( uno::RuntimeException )
+{
+ if( !mpWrapper )
+ return;
+
+ AtkObject *atk_obj = ATK_OBJECT( mpWrapper );
+
+ switch( aEvent.EventId )
+ {
+ // AtkObject signals:
+ // Hierarchy signals
+ case accessibility::AccessibleEventId::CHILD:
+ {
+ uno::Reference< accessibility::XAccessibleContext > xParent;
+ uno::Reference< accessibility::XAccessible > xChild;
+
+ xParent = getAccessibleContextFromSource(aEvent.Source);
+ g_return_if_fail( xParent.is() );
+
+ if( aEvent.OldValue >>= xChild )
+ handleChildRemoved(xParent, xChild);
+
+ if( aEvent.NewValue >>= xChild )
+ handleChildAdded(xParent, xChild);
+ }
+ break;
+
+ case accessibility::AccessibleEventId::INVALIDATE_ALL_CHILDREN:
+ {
+ uno::Reference< accessibility::XAccessibleContext > xParent;
+
+ xParent = getAccessibleContextFromSource(aEvent.Source);
+ g_return_if_fail( xParent.is() );
+
+ handleInvalidateChildren(xParent);
+ }
+ break;
+
+ case accessibility::AccessibleEventId::NAME_CHANGED:
+ {
+ rtl::OUString aName;
+ if( aEvent.NewValue >>= aName )
+ {
+ atk_object_set_name(atk_obj,
+ rtl::OUStringToOString(aName, RTL_TEXTENCODING_UTF8).getStr());
+ }
+ }
+ break;
+
+ case accessibility::AccessibleEventId::DESCRIPTION_CHANGED:
+ {
+ rtl::OUString aDescription;
+ if( aEvent.NewValue >>= aDescription )
+ {
+ atk_object_set_description(atk_obj,
+ rtl::OUStringToOString(aDescription, RTL_TEXTENCODING_UTF8).getStr());
+ }
+ }
+ break;
+
+ case accessibility::AccessibleEventId::STATE_CHANGED:
+ {
+ AtkStateType eOldState = mapState( aEvent.OldValue );
+ AtkStateType eNewState = mapState( aEvent.NewValue );
+
+ gboolean bState = eNewState != ATK_STATE_INVALID;
+ AtkStateType eRealState = bState ? eNewState : eOldState;
+
+ atk_object_notify_state_change( atk_obj, eRealState, bState );
+ break;
+ }
+
+ case accessibility::AccessibleEventId::BOUNDRECT_CHANGED:
+
+#ifdef HAS_ATKRECTANGLE
+ if( ATK_IS_COMPONENT( atk_obj ) )
+ {
+ AtkRectangle rect;
+
+ atk_component_get_extents( ATK_COMPONENT( atk_obj ),
+ &rect.x,
+ &rect.y,
+ &rect.width,
+ &rect.height,
+ ATK_XY_SCREEN );
+
+ g_signal_emit_by_name( atk_obj, "bounds_changed", &rect );
+ }
+ else
+ g_warning( "bounds_changed event for object not implementing AtkComponent\n");
+#endif
+
+ break;
+
+ case accessibility::AccessibleEventId::VISIBLE_DATA_CHANGED:
+ g_signal_emit_by_name( atk_obj, "visible-data-changed" );
+ break;
+
+ case accessibility::AccessibleEventId::ACTIVE_DESCENDANT_CHANGED:
+ {
+ AtkObject *pChild = getObjFromAny( aEvent.NewValue );
+ if( pChild )
+ {
+ g_signal_emit_by_name( atk_obj, "active-descendant-changed", pChild );
+ g_object_unref( pChild );
+ }
+ break;
+ }
+
+ // --> OD 2009-05-26 #i92103#
+ case accessibility::AccessibleEventId::LISTBOX_ENTRY_EXPANDED:
+ {
+ AtkObject *pChild = getObjFromAny( aEvent.NewValue );
+ if( pChild )
+ {
+ AtkStateType eExpandedState = ATK_STATE_EXPANDED;
+ atk_object_notify_state_change( pChild, eExpandedState, true );
+ g_object_unref( pChild );
+ }
+ break;
+ }
+
+ case accessibility::AccessibleEventId::LISTBOX_ENTRY_COLLAPSED:
+ {
+ AtkObject *pChild = getObjFromAny( aEvent.NewValue );
+ if( pChild )
+ {
+ AtkStateType eExpandedState = ATK_STATE_EXPANDED;
+ atk_object_notify_state_change( pChild, eExpandedState, false );
+ g_object_unref( pChild );
+ }
+ break;
+ }
+ // <--
+
+ // AtkAction signals ...
+ case accessibility::AccessibleEventId::ACTION_CHANGED:
+ g_signal_emit_by_name( G_OBJECT( atk_obj ), "property_change::accessible-actions");
+ break;
+
+ // AtkText
+ case accessibility::AccessibleEventId::CARET_CHANGED:
+ {
+ sal_Int32 nPos=0;
+ aEvent.NewValue >>= nPos;
+ g_signal_emit_by_name( atk_obj, "text_caret_moved", nPos );
+ break;
+ }
+ case accessibility::AccessibleEventId::TEXT_CHANGED:
+ {
+ // TESTME: and remove this comment:
+ // cf. comphelper/source/misc/accessibletexthelper.cxx (implInitTextChangedEvent)
+ accessibility::TextSegment aDeletedText;
+ accessibility::TextSegment aInsertedText;
+
+ // TODO: when GNOME starts to send "update" kind of events, change
+ // we need to re-think this implementation as well
+ if( aEvent.OldValue >>= aDeletedText )
+ {
+ /* Remember the text segment here to be able to return removed text in get_text().
+ * This is clearly a hack to be used until appropriate API exists in atk to pass
+ * the string value directly or we find a compelling reason to start caching the
+ * UTF-8 converted strings in the atk wrapper object.
+ */
+
+ g_object_set_data( G_OBJECT(atk_obj), "ooo::text_changed::delete", &aDeletedText);
+
+ g_signal_emit_by_name( atk_obj, "text_changed::delete",
+ (gint) aDeletedText.SegmentStart,
+ (gint)( aDeletedText.SegmentEnd - aDeletedText.SegmentStart ) );
+
+ g_object_steal_data( G_OBJECT(atk_obj), "ooo::text_changed::delete" );
+ }
+
+ if( aEvent.NewValue >>= aInsertedText )
+ g_signal_emit_by_name( atk_obj, "text_changed::insert",
+ (gint) aInsertedText.SegmentStart,
+ (gint)( aInsertedText.SegmentEnd - aInsertedText.SegmentStart ) );
+ break;
+ }
+
+ case accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED:
+ {
+ g_signal_emit_by_name( atk_obj, "text-selection-changed" );
+ break;
+ }
+
+ case accessibility::AccessibleEventId::TEXT_ATTRIBUTE_CHANGED:
+ g_signal_emit_by_name( atk_obj, "text-attributes-changed" );
+ break;
+
+ // AtkValue
+ case accessibility::AccessibleEventId::VALUE_CHANGED:
+ g_object_notify( G_OBJECT( atk_obj ), "accessible-value" );
+ break;
+
+ case accessibility::AccessibleEventId::CONTENT_FLOWS_FROM_RELATION_CHANGED:
+ case accessibility::AccessibleEventId::CONTENT_FLOWS_TO_RELATION_CHANGED:
+ case accessibility::AccessibleEventId::CONTROLLED_BY_RELATION_CHANGED:
+ case accessibility::AccessibleEventId::CONTROLLER_FOR_RELATION_CHANGED:
+ case accessibility::AccessibleEventId::LABEL_FOR_RELATION_CHANGED:
+ case accessibility::AccessibleEventId::LABELED_BY_RELATION_CHANGED:
+ case accessibility::AccessibleEventId::MEMBER_OF_RELATION_CHANGED:
+ case accessibility::AccessibleEventId::SUB_WINDOW_OF_RELATION_CHANGED:
+ // FIXME: ask Bill how Atk copes with this little lot ...
+ break;
+
+ // AtkTable
+ case accessibility::AccessibleEventId::TABLE_MODEL_CHANGED:
+ {
+ accessibility::AccessibleTableModelChange aChange;
+ aEvent.NewValue >>= aChange;
+
+ sal_Int32 nRowsChanged = aChange.LastRow - aChange.FirstRow + 1;
+ sal_Int32 nColumnsChanged = aChange.LastColumn - aChange.FirstColumn + 1;
+
+ static const struct {
+ const char *row;
+ const char *col;
+ } aSignalNames[] =
+ {
+ { NULL, NULL }, // dummy
+ { "row_inserted", "column_inserted" }, // INSERT = 1
+ { "row_deleted", "column_deleted" } // DELETE = 2
+ };
+ switch( aChange.Type )
+ {
+ case accessibility::AccessibleTableModelChangeType::INSERT:
+ case accessibility::AccessibleTableModelChangeType::DELETE:
+ if( nRowsChanged > 0 )
+ g_signal_emit_by_name( G_OBJECT( atk_obj ),
+ aSignalNames[aChange.Type].row,
+ aChange.FirstRow, nRowsChanged );
+ if( nColumnsChanged > 0 )
+ g_signal_emit_by_name( G_OBJECT( atk_obj ),
+ aSignalNames[aChange.Type].col,
+ aChange.FirstColumn, nColumnsChanged );
+ break;
+
+ case accessibility::AccessibleTableModelChangeType::UPDATE:
+ // This is not really a model change, is it ?
+ break;
+ default:
+ g_warning( "TESTME: unusual table model change %d\n", aChange.Type );
+ break;
+ }
+ g_signal_emit_by_name( G_OBJECT( atk_obj ), "model-changed" );
+ break;
+ }
+
+ case accessibility::AccessibleEventId::TABLE_COLUMN_HEADER_CHANGED:
+ g_signal_emit_by_name( G_OBJECT( atk_obj ), "property_change::accessible-table-column-header");
+ break;
+
+ case accessibility::AccessibleEventId::TABLE_CAPTION_CHANGED:
+ g_signal_emit_by_name( G_OBJECT( atk_obj ), "property_change::accessible-table-caption");
+ break;
+
+ case accessibility::AccessibleEventId::TABLE_COLUMN_DESCRIPTION_CHANGED:
+ g_signal_emit_by_name( G_OBJECT( atk_obj ), "property_change::accessible-table-column-description");
+ break;
+
+ case accessibility::AccessibleEventId::TABLE_ROW_DESCRIPTION_CHANGED:
+ g_signal_emit_by_name( G_OBJECT( atk_obj ), "property_change::accessible-table-row-description");
+ break;
+
+ case accessibility::AccessibleEventId::TABLE_ROW_HEADER_CHANGED:
+ g_signal_emit_by_name( G_OBJECT( atk_obj ), "property_change::accessible-table-row-header");
+ break;
+
+ case accessibility::AccessibleEventId::TABLE_SUMMARY_CHANGED:
+ g_signal_emit_by_name( G_OBJECT( atk_obj ), "property_change::accessible-table-summary");
+ break;
+
+ case accessibility::AccessibleEventId::SELECTION_CHANGED:
+ g_signal_emit_by_name( G_OBJECT( atk_obj ), "selection_changed");
+ break;
+
+ case accessibility::AccessibleEventId::HYPERTEXT_CHANGED:
+ g_signal_emit_by_name( G_OBJECT( atk_obj ), "property_change::accessible-hypertext-offset");
+ break;
+
+ default:
+ g_warning( "Unknown event notification %d", aEvent.EventId );
+ break;
+ }
+}
diff --git a/vcl/unx/gtk/a11y/atklistener.hxx b/vcl/unx/gtk/a11y/atklistener.hxx
new file mode 100644
index 000000000000..d2889caa3e24
--- /dev/null
+++ b/vcl/unx/gtk/a11y/atklistener.hxx
@@ -0,0 +1,79 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _ATK_LISTENER_HXX_
+#define _ATK_LISTENER_HXX_
+
+#include <com/sun/star/accessibility/XAccessibleEventListener.hpp>
+#include <cppuhelper/implbase1.hxx>
+
+#include <vector>
+
+#include "atkwrapper.hxx"
+
+typedef std::vector< ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > > AccessibleVector;
+
+class AtkListener : public ::cppu::WeakImplHelper1< ::com::sun::star::accessibility::XAccessibleEventListener >
+{
+public:
+ AtkListener(AtkObjectWrapper * pWrapper);
+
+ // XEventListener
+ virtual void disposing( const ::com::sun::star::lang::EventObject& Source )
+ throw (::com::sun::star::uno::RuntimeException);
+
+ // XAccessibleEventListener
+ virtual void notifyEvent( const ::com::sun::star::accessibility::AccessibleEventObject& aEvent )
+ throw( ::com::sun::star::uno::RuntimeException );
+
+ AtkObjectWrapper *mpWrapper;
+ AccessibleVector m_aChildList;
+
+private:
+
+ virtual ~AtkListener();
+
+ // Updates the child list held to provide the old IndexInParent on children_changed::remove
+ void updateChildList(::com::sun::star::accessibility::XAccessibleContext* pContext);
+
+ // Process CHILD_EVENT notifications with a new child added
+ void handleChildAdded(
+ const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleContext >& rxParent,
+ const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible>& rxChild);
+
+ // Process CHILD_EVENT notifications with a child removed
+ void handleChildRemoved(
+ const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleContext >& rxParent,
+ const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible>& rxChild);
+
+ // Process INVALIDATE_ALL_CHILDREN notification
+ void handleInvalidateChildren(
+ const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleContext >& rxParent);
+};
+
+#endif /* _ATK_LISTENER_HXX_ */
+
diff --git a/vcl/unx/gtk/a11y/atkregistry.cxx b/vcl/unx/gtk/a11y/atkregistry.cxx
new file mode 100644
index 000000000000..81ec22dc4ce1
--- /dev/null
+++ b/vcl/unx/gtk/a11y/atkregistry.cxx
@@ -0,0 +1,71 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "atkregistry.hxx"
+
+using namespace ::com::sun::star::accessibility;
+using namespace ::com::sun::star::uno;
+
+static GHashTable *uno_to_gobject = NULL;
+
+/*****************************************************************************/
+
+AtkObject *
+ooo_wrapper_registry_get(const Reference< XAccessible >& rxAccessible)
+{
+ if( uno_to_gobject )
+ {
+ gpointer cached =
+ g_hash_table_lookup(uno_to_gobject, (gpointer) rxAccessible.get());
+
+ if( cached )
+ return ATK_OBJECT( cached );
+ }
+
+ return NULL;
+}
+
+/*****************************************************************************/
+
+void
+ooo_wrapper_registry_add(const Reference< XAccessible >& rxAccessible, AtkObject *obj)
+{
+ if( !uno_to_gobject )
+ uno_to_gobject = g_hash_table_new (NULL, NULL);
+
+ g_hash_table_insert( uno_to_gobject, (gpointer) rxAccessible.get(), obj );
+}
+
+/*****************************************************************************/
+
+void
+ooo_wrapper_registry_remove(XAccessible *pAccessible)
+{
+ if( uno_to_gobject )
+ g_hash_table_remove( uno_to_gobject, (gpointer) pAccessible );
+}
+
diff --git a/vcl/unx/gtk/a11y/atkregistry.hxx b/vcl/unx/gtk/a11y/atkregistry.hxx
new file mode 100644
index 000000000000..f4de3b2e4c1e
--- /dev/null
+++ b/vcl/unx/gtk/a11y/atkregistry.hxx
@@ -0,0 +1,40 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef __ATK_REGISTRY_HXX__
+#define __ATK_REGISTRY_HXX__
+
+#include <com/sun/star/accessibility/XAccessible.hpp>
+#include <atk/atk.h>
+
+AtkObject * ooo_wrapper_registry_get(const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >& rxAccessible);
+
+void ooo_wrapper_registry_add(const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >& rxAccessible, AtkObject *obj);
+
+void ooo_wrapper_registry_remove(::com::sun::star::accessibility::XAccessible *pAccessible);
+
+#endif // __ATK_REGISTRY_HXX_
diff --git a/vcl/unx/gtk/a11y/atkselection.cxx b/vcl/unx/gtk/a11y/atkselection.cxx
new file mode 100644
index 000000000000..172faac4c704
--- /dev/null
+++ b/vcl/unx/gtk/a11y/atkselection.cxx
@@ -0,0 +1,195 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "atkwrapper.hxx"
+
+#include <com/sun/star/accessibility/XAccessibleSelection.hpp>
+
+#include <stdio.h>
+
+using namespace ::com::sun::star;
+
+static accessibility::XAccessibleSelection*
+ getSelection( AtkSelection *pSelection ) throw (uno::RuntimeException)
+{
+ AtkObjectWrapper *pWrap = ATK_OBJECT_WRAPPER( pSelection );
+ if( pWrap )
+ {
+ if( !pWrap->mpSelection && pWrap->mpContext )
+ {
+ uno::Any any = pWrap->mpContext->queryInterface( accessibility::XAccessibleSelection::static_type(NULL) );
+ pWrap->mpSelection = reinterpret_cast< accessibility::XAccessibleSelection * > (any.pReserved);
+ pWrap->mpSelection->acquire();
+ }
+
+ return pWrap->mpSelection;
+ }
+
+ return NULL;
+}
+
+extern "C" {
+
+static gboolean
+selection_add_selection( AtkSelection *selection,
+ gint i )
+{
+ try {
+ accessibility::XAccessibleSelection* pSelection = getSelection( selection );
+ if( pSelection )
+ {
+ pSelection->selectAccessibleChild( i );
+ return TRUE;
+ }
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in selectAccessibleChild()" );
+ }
+
+ return FALSE;
+}
+
+static gboolean
+selection_clear_selection( AtkSelection *selection )
+{
+ try {
+ accessibility::XAccessibleSelection* pSelection = getSelection( selection );
+ if( pSelection )
+ {
+ pSelection->clearAccessibleSelection();
+ return TRUE;
+ }
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in selectAccessibleChild()" );
+ }
+
+ return FALSE;
+}
+
+static AtkObject*
+selection_ref_selection( AtkSelection *selection,
+ gint i )
+{
+ try {
+ accessibility::XAccessibleSelection* pSelection = getSelection( selection );
+ if( pSelection )
+ return atk_object_wrapper_ref( pSelection->getSelectedAccessibleChild( i ) );
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getSelectedAccessibleChild()" );
+ }
+
+ return NULL;
+}
+
+static gint
+selection_get_selection_count( AtkSelection *selection)
+{
+ try {
+ accessibility::XAccessibleSelection* pSelection = getSelection( selection );
+ if( pSelection )
+ return pSelection->getSelectedAccessibleChildCount();
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getSelectedAccessibleChildCount()" );
+ }
+
+ return -1;
+}
+
+static gboolean
+selection_is_child_selected( AtkSelection *selection,
+ gint i)
+{
+ try {
+ accessibility::XAccessibleSelection* pSelection = getSelection( selection );
+ if( pSelection )
+ return pSelection->isAccessibleChildSelected( i );
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getSelectedAccessibleChildCount()" );
+ }
+
+ return FALSE;
+}
+
+static gboolean
+selection_remove_selection( AtkSelection *selection,
+ gint i )
+{
+ try {
+ accessibility::XAccessibleSelection* pSelection = getSelection( selection );
+ if( pSelection )
+ {
+ pSelection->deselectAccessibleChild( i );
+ return TRUE;
+ }
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getSelectedAccessibleChildCount()" );
+ }
+
+ return FALSE;
+}
+
+static gboolean
+selection_select_all_selection( AtkSelection *selection)
+{
+ try {
+ accessibility::XAccessibleSelection* pSelection = getSelection( selection );
+ if( pSelection )
+ {
+ pSelection->selectAllAccessibleChildren();
+ return TRUE;
+ }
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getSelectedAccessibleChildCount()" );
+ }
+
+ return FALSE;
+}
+
+} // extern "C"
+
+void
+selectionIfaceInit( AtkSelectionIface *iface)
+{
+ g_return_if_fail (iface != NULL);
+
+ iface->add_selection = selection_add_selection;
+ iface->clear_selection = selection_clear_selection;
+ iface->ref_selection = selection_ref_selection;
+ iface->get_selection_count = selection_get_selection_count;
+ iface->is_child_selected = selection_is_child_selected;
+ iface->remove_selection = selection_remove_selection;
+ iface->select_all_selection = selection_select_all_selection;
+}
diff --git a/vcl/unx/gtk/a11y/atktable.cxx b/vcl/unx/gtk/a11y/atktable.cxx
new file mode 100644
index 000000000000..78571ff11c34
--- /dev/null
+++ b/vcl/unx/gtk/a11y/atktable.cxx
@@ -0,0 +1,721 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "atkwrapper.hxx"
+
+#include <com/sun/star/accessibility/XAccessibleTable.hpp>
+
+#ifdef ENABLE_TRACING
+#include <stdio.h>
+#endif
+
+using namespace ::com::sun::star;
+
+static inline AtkObject *
+atk_object_wrapper_conditional_ref( const uno::Reference< accessibility::XAccessible >& rxAccessible )
+{
+#ifdef ENABLE_TRACING
+ fprintf( stderr, ": %p\n", rxAccessible.get() );
+#endif
+
+ if( rxAccessible.is() )
+ return atk_object_wrapper_ref( rxAccessible );
+
+ return NULL;
+}
+
+/*****************************************************************************/
+
+// FIXME
+static G_CONST_RETURN gchar *
+getAsConst( rtl::OUString rString )
+{
+ static const int nMax = 10;
+ static rtl::OString aUgly[nMax];
+ static int nIdx = 0;
+ nIdx = (nIdx + 1) % nMax;
+ aUgly[nIdx] = rtl::OUStringToOString( rString, RTL_TEXTENCODING_UTF8 );
+ return aUgly[ nIdx ];
+}
+
+/*****************************************************************************/
+
+static accessibility::XAccessibleTable*
+ getTable( AtkTable *pTable ) throw (uno::RuntimeException)
+{
+ AtkObjectWrapper *pWrap = ATK_OBJECT_WRAPPER( pTable );
+ if( pWrap )
+ {
+ if( !pWrap->mpTable && pWrap->mpContext )
+ {
+ uno::Any any = pWrap->mpContext->queryInterface( accessibility::XAccessibleTable::static_type(NULL) );
+ pWrap->mpTable = reinterpret_cast< accessibility::XAccessibleTable * > (any.pReserved);
+ pWrap->mpTable->acquire();
+ }
+
+ return pWrap->mpTable;
+ }
+
+ return NULL;
+}
+
+/*****************************************************************************/
+
+extern "C" {
+
+static AtkObject*
+table_wrapper_ref_at (AtkTable *table,
+ gint row,
+ gint column)
+{
+ try {
+ accessibility::XAccessibleTable* pTable = getTable( table );
+
+#ifdef ENABLE_TRACING
+ if( pTable )
+ fprintf(stderr, "getAccessibleCellAt( %u, %u ) returns", row, column );
+
+ if( column >= 255 )
+ fprintf(stderr, "getAccessibleCellAt( %u, %u ) returns", row, column );
+
+#endif
+
+ if( pTable )
+ return atk_object_wrapper_conditional_ref( pTable->getAccessibleCellAt( row, column ) );
+ }
+
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getAccessibleCellAt()" );
+ }
+
+ return NULL;
+}
+
+/*****************************************************************************/
+
+static gint
+table_wrapper_get_index_at (AtkTable *table,
+ gint row,
+ gint column)
+{
+ try {
+ accessibility::XAccessibleTable* pTable = getTable( table );
+
+#ifdef ENABLE_TRACING
+ if( pTable )
+ fprintf(stderr, "getAccessibleIndex( %u, %u ) returns %u\n",
+ row, column, pTable->getAccessibleIndex( row, column ) );
+#endif
+
+ if( pTable )
+ return pTable->getAccessibleIndex( row, column );
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getAccessibleIndex()" );
+ }
+
+ return -1;
+}
+
+/*****************************************************************************/
+
+static gint
+table_wrapper_get_column_at_index (AtkTable *table,
+ gint nIndex)
+{
+ try {
+ accessibility::XAccessibleTable* pTable = getTable( table );
+
+#ifdef ENABLE_TRACING
+ if( pTable )
+ fprintf(stderr, "getAccessibleColumn( %u ) returns %u\n",
+ nIndex, pTable->getAccessibleColumn( nIndex ) );
+#endif
+
+ if( pTable )
+ return pTable->getAccessibleColumn( nIndex );
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getAccessibleColumn()" );
+ }
+
+ return -1;
+}
+
+/*****************************************************************************/
+
+static gint
+table_wrapper_get_row_at_index( AtkTable *table,
+ gint nIndex )
+{
+ try {
+ accessibility::XAccessibleTable* pTable = getTable( table );
+
+#ifdef ENABLE_TRACING
+ if( pTable )
+ fprintf(stderr, "getAccessibleRow( %u ) returns %u\n",
+ nIndex, pTable->getAccessibleRow( nIndex ) );
+#endif
+
+ if( pTable )
+ return pTable->getAccessibleRow( nIndex );
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getAccessibleRow()" );
+ }
+
+ return -1;
+}
+
+/*****************************************************************************/
+
+static gint
+table_wrapper_get_n_columns( AtkTable *table )
+{
+ try {
+ accessibility::XAccessibleTable* pTable = getTable( table );
+
+#ifdef ENABLE_TRACING
+ if( pTable )
+ fprintf(stderr, "XAccessibleTable::getAccessibleColumnCount returns %u\n",
+ pTable->getAccessibleColumnCount() );
+#endif
+
+ if( pTable )
+ return pTable->getAccessibleColumnCount();
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getAccessibleColumnCount()" );
+ }
+
+ return -1;
+}
+
+/*****************************************************************************/
+
+static gint
+table_wrapper_get_n_rows( AtkTable *table )
+{
+ try {
+ accessibility::XAccessibleTable* pTable = getTable( table );
+
+#ifdef ENABLE_TRACING
+ if( pTable )
+ fprintf(stderr, "getAccessibleRowCount() returns %u\n",
+ pTable->getAccessibleRowCount() );
+#endif
+
+ if( pTable )
+ return pTable->getAccessibleRowCount();
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getAccessibleRowCount()" );
+ }
+
+ return -1;
+}
+
+/*****************************************************************************/
+
+static gint
+table_wrapper_get_column_extent_at( AtkTable *table,
+ gint row,
+ gint column )
+{
+ try {
+ accessibility::XAccessibleTable* pTable = getTable( table );
+
+#ifdef ENABLE_TRACING
+ if( pTable )
+ fprintf(stderr, "getAccessibleColumnExtentAt( %u, %u ) returns %u\n",
+ row, column, pTable->getAccessibleColumnExtentAt( row, column ) );
+#endif
+
+ if( pTable )
+ return pTable->getAccessibleColumnExtentAt( row, column );
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getAccessibleColumnExtentAt()" );
+ }
+
+ return -1;
+}
+
+/*****************************************************************************/
+
+static gint
+table_wrapper_get_row_extent_at( AtkTable *table,
+ gint row,
+ gint column )
+{
+ try {
+ accessibility::XAccessibleTable* pTable = getTable( table );
+
+#ifdef ENABLE_TRACING
+ if( pTable )
+ fprintf(stderr, "getAccessibleRowExtentAt( %u, %u ) returns %u\n",
+ row, column, pTable->getAccessibleRowExtentAt( row, column ) );
+#endif
+
+ if( pTable )
+ return pTable->getAccessibleRowExtentAt( row, column );
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getAccessibleRowExtentAt()" );
+ }
+
+ return -1;
+}
+
+/*****************************************************************************/
+
+static AtkObject *
+table_wrapper_get_caption( AtkTable *table )
+{
+ try {
+ accessibility::XAccessibleTable* pTable = getTable( table );
+
+#ifdef ENABLE_TRACING
+ if( pTable )
+ fprintf(stderr, "getAccessibleCaption() returns" );
+#endif
+
+ if( pTable )
+ return atk_object_wrapper_conditional_ref( pTable->getAccessibleCaption() );
+ }
+
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getAccessibleCaption()" );
+ }
+
+ return NULL;
+}
+
+/*****************************************************************************/
+
+static G_CONST_RETURN gchar *
+table_wrapper_get_row_description( AtkTable *table,
+ gint row )
+{
+ try {
+ accessibility::XAccessibleTable* pTable = getTable( table );
+
+#ifdef ENABLE_TRACING
+ if( pTable )
+ fprintf(stderr, "getAccessibleRowDescription( %u ) returns %s\n",
+ row, getAsConst( pTable->getAccessibleRowDescription( row ) ) );
+#endif
+
+ if( pTable )
+ return getAsConst( pTable->getAccessibleRowDescription( row ) );
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getAccessibleRowDescription()" );
+ }
+
+ return NULL;
+}
+
+/*****************************************************************************/
+
+static G_CONST_RETURN gchar *
+table_wrapper_get_column_description( AtkTable *table,
+ gint column )
+{
+ try {
+ accessibility::XAccessibleTable* pTable = getTable( table );
+
+#ifdef ENABLE_TRACING
+ if( pTable )
+ fprintf(stderr, "getAccessibleColumnDescription( %u ) returns %s\n",
+ column, getAsConst( pTable->getAccessibleColumnDescription( column ) ) );
+#endif
+
+ if( pTable )
+ return getAsConst( pTable->getAccessibleColumnDescription( column ) );
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getAccessibleColumnDescription()" );
+ }
+
+ return NULL;
+}
+
+/*****************************************************************************/
+
+static AtkObject *
+table_wrapper_get_row_header( AtkTable *table,
+ gint row )
+{
+ try {
+ accessibility::XAccessibleTable* pTable = getTable( table );
+ if( pTable )
+ {
+ uno::Reference< accessibility::XAccessibleTable > xRowHeaders( pTable->getAccessibleRowHeaders() );
+
+#ifdef ENABLE_TRACING
+ if( xRowHeaders.is() )
+ fprintf(stderr, "getAccessibleRowHeader( %u )->getAccessibleCellAt( 0, %u ) returns",
+ row, row );
+ else
+ fprintf(stderr, "getAccessibleRowHeader( %u ) returns %p\n", row, xRowHeaders.get() );
+#endif
+
+ if( xRowHeaders.is() )
+ return atk_object_wrapper_conditional_ref( xRowHeaders->getAccessibleCellAt( row, 0 ) );
+ }
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getAccessibleRowHeaders()" );
+ }
+
+ return NULL;
+}
+
+/*****************************************************************************/
+
+static AtkObject *
+table_wrapper_get_column_header( AtkTable *table,
+ gint column )
+{
+ try {
+ accessibility::XAccessibleTable* pTable = getTable( table );
+
+ if( pTable )
+ {
+ uno::Reference< accessibility::XAccessibleTable > xColumnHeaders( pTable->getAccessibleColumnHeaders() );
+
+#ifdef ENABLE_TRACING
+ if( xColumnHeaders.is() )
+ fprintf(stderr, "getAccessibleColumnHeader( %u )->getAccessibleCellAt( 0, %u ) returns",
+ column, column );
+ else
+ fprintf(stderr, "getAccessibleColumnHeader( %u ) returns %p\n", column, xColumnHeaders.get() );
+#endif
+
+ if( xColumnHeaders.is() )
+ return atk_object_wrapper_conditional_ref( xColumnHeaders->getAccessibleCellAt( 0, column ) );
+ }
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getAccessibleColumnHeaders()" );
+ }
+
+ return NULL;
+}
+
+/*****************************************************************************/
+
+static AtkObject *
+table_wrapper_get_summary( AtkTable *table )
+{
+ try {
+ accessibility::XAccessibleTable* pTable = getTable( table );
+
+#ifdef ENABLE_TRACING
+ if( pTable )
+ fprintf(stderr, "getAccessibleSummary() returns" );
+#endif
+
+ if( pTable )
+ {
+ // FIXME: Summary ??
+// AtkObject* summary;
+ return atk_object_wrapper_conditional_ref( pTable->getAccessibleSummary() );
+ }
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getAccessibleSummary()" );
+ }
+
+ return NULL;
+}
+
+/*****************************************************************************/
+
+static gint
+convertToGIntArray( const uno::Sequence< ::sal_Int32 >& aSequence, gint **pSelected )
+{
+ if( aSequence.getLength() )
+ {
+ *pSelected = g_new( gint, aSequence.getLength() );
+
+ for( sal_Int32 i = 0; i < aSequence.getLength(); i++ )
+ (*pSelected) [i] = aSequence[i];
+ }
+
+ return aSequence.getLength();
+}
+
+/*****************************************************************************/
+
+static gint
+table_wrapper_get_selected_columns( AtkTable *table,
+ gint **pSelected )
+{
+ *pSelected = NULL;
+ try {
+ accessibility::XAccessibleTable* pTable = getTable( table );
+
+#ifdef ENABLE_TRACING
+ if( pTable )
+ fprintf(stderr, "getSelectedAccessibleColumns() \n" );
+#endif
+
+ if( pTable )
+ return convertToGIntArray( pTable->getSelectedAccessibleColumns(), pSelected );
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getSelectedAccessibleColumns()" );
+ }
+
+ return 0;
+}
+
+/*****************************************************************************/
+
+static gint
+table_wrapper_get_selected_rows( AtkTable *table,
+ gint **pSelected )
+{
+ *pSelected = NULL;
+ try {
+ accessibility::XAccessibleTable* pTable = getTable( table );
+
+#ifdef ENABLE_TRACING
+ if( pTable )
+ fprintf(stderr, "getSelectedAccessibleRows() \n" );
+#endif
+
+ if( pTable )
+ return convertToGIntArray( pTable->getSelectedAccessibleRows(), pSelected );
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getSelectedAccessibleRows()" );
+ }
+
+ return 0;
+}
+
+/*****************************************************************************/
+
+static gboolean
+table_wrapper_is_column_selected( AtkTable *table,
+ gint column )
+{
+ try {
+ accessibility::XAccessibleTable* pTable = getTable( table );
+
+#ifdef ENABLE_TRACING
+ if( pTable )
+ fprintf(stderr, "isAccessibleColumnSelected( %u ) returns %s\n",
+ column, pTable->isAccessibleColumnSelected( column ) ? "true" : "false" );
+#endif
+
+ if( pTable )
+ return pTable->isAccessibleColumnSelected( column );
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in isAccessibleColumnSelected()" );
+ }
+
+ return 0;
+}
+
+/*****************************************************************************/
+
+static gboolean
+table_wrapper_is_row_selected( AtkTable *table,
+ gint row )
+{
+ try {
+ accessibility::XAccessibleTable* pTable = getTable( table );
+
+#ifdef ENABLE_TRACING
+ if( pTable )
+ fprintf(stderr, "isAccessibleRowSelected( %u ) returns %s\n",
+ row, pTable->isAccessibleRowSelected( row ) ? "true" : "false" );
+#endif
+
+ if( pTable )
+ return pTable->isAccessibleRowSelected( row );
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in isAccessibleRowSelected()" );
+ }
+
+ return FALSE;
+}
+
+/*****************************************************************************/
+
+static gboolean
+table_wrapper_is_selected( AtkTable *table,
+ gint row,
+ gint column )
+{
+ try {
+ accessibility::XAccessibleTable* pTable = getTable( table );
+
+#ifdef ENABLE_TRACING
+ if( pTable )
+ fprintf(stderr, "isAccessibleSelected( %u, %u ) returns %s\n",
+ row, column, pTable->isAccessibleSelected( row , column ) ? "true" : "false" );
+#endif
+
+ if( pTable )
+ return pTable->isAccessibleSelected( row, column );
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in isAccessibleSelected()" );
+ }
+
+ return FALSE;
+}
+
+/*****************************************************************************/
+
+static gboolean
+table_wrapper_add_row_selection( AtkTable *, gint )
+{
+ g_warning( "FIXME: no simple analogue for add_row_selection" );
+ return 0;
+}
+
+/*****************************************************************************/
+
+static gboolean
+table_wrapper_remove_row_selection( AtkTable *, gint )
+{
+ g_warning( "FIXME: no simple analogue for remove_row_selection" );
+ return 0;
+}
+
+/*****************************************************************************/
+
+static gboolean
+table_wrapper_add_column_selection( AtkTable *, gint )
+{
+ g_warning( "FIXME: no simple analogue for add_column_selection" );
+ return 0;
+}
+
+/*****************************************************************************/
+
+static gboolean
+table_wrapper_remove_column_selection( AtkTable *, gint )
+{
+ g_warning( "FIXME: no simple analogue for remove_column_selection" );
+ return 0;
+}
+
+/*****************************************************************************/
+
+static void
+table_wrapper_set_caption( AtkTable *, AtkObject * )
+{ // meaningless helper
+}
+
+/*****************************************************************************/
+
+static void
+table_wrapper_set_column_description( AtkTable *, gint, const gchar * )
+{ // meaningless helper
+}
+
+
+/*****************************************************************************/
+
+static void
+table_wrapper_set_column_header( AtkTable *, gint, AtkObject * )
+{ // meaningless helper
+}
+
+
+/*****************************************************************************/
+
+static void
+table_wrapper_set_row_description( AtkTable *, gint, const gchar * )
+{ // meaningless helper
+}
+
+/*****************************************************************************/
+
+static void
+table_wrapper_set_row_header( AtkTable *, gint, AtkObject * )
+{ // meaningless helper
+}
+
+/*****************************************************************************/
+
+static void
+table_wrapper_set_summary( AtkTable *, AtkObject * )
+{ // meaningless helper
+}
+
+/*****************************************************************************/
+
+} // extern "C"
+
+void
+tableIfaceInit (AtkTableIface *iface)
+{
+ g_return_if_fail (iface != NULL);
+
+ iface->ref_at = table_wrapper_ref_at;
+ iface->get_n_rows = table_wrapper_get_n_rows;
+ iface->get_n_columns = table_wrapper_get_n_columns;
+ iface->get_index_at = table_wrapper_get_index_at;
+ iface->get_column_at_index = table_wrapper_get_column_at_index;
+ iface->get_row_at_index = table_wrapper_get_row_at_index;
+ iface->is_row_selected = table_wrapper_is_row_selected;
+ iface->is_selected = table_wrapper_is_selected;
+ iface->get_selected_rows = table_wrapper_get_selected_rows;
+ iface->add_row_selection = table_wrapper_add_row_selection;
+ iface->remove_row_selection = table_wrapper_remove_row_selection;
+ iface->add_column_selection = table_wrapper_add_column_selection;
+ iface->remove_column_selection = table_wrapper_remove_column_selection;
+ iface->get_selected_columns = table_wrapper_get_selected_columns;
+ iface->is_column_selected = table_wrapper_is_column_selected;
+ iface->get_column_extent_at = table_wrapper_get_column_extent_at;
+ iface->get_row_extent_at = table_wrapper_get_row_extent_at;
+ iface->get_row_header = table_wrapper_get_row_header;
+ iface->set_row_header = table_wrapper_set_row_header;
+ iface->get_column_header = table_wrapper_get_column_header;
+ iface->set_column_header = table_wrapper_set_column_header;
+ iface->get_caption = table_wrapper_get_caption;
+ iface->set_caption = table_wrapper_set_caption;
+ iface->get_summary = table_wrapper_get_summary;
+ iface->set_summary = table_wrapper_set_summary;
+ iface->get_row_description = table_wrapper_get_row_description;
+ iface->set_row_description = table_wrapper_set_row_description;
+ iface->get_column_description = table_wrapper_get_column_description;
+ iface->set_column_description = table_wrapper_set_column_description;
+}
diff --git a/vcl/unx/gtk/a11y/atktext.cxx b/vcl/unx/gtk/a11y/atktext.cxx
new file mode 100644
index 000000000000..e6d3276891de
--- /dev/null
+++ b/vcl/unx/gtk/a11y/atktext.cxx
@@ -0,0 +1,876 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "atkwrapper.hxx"
+#include "atktextattributes.hxx"
+#include <algorithm>
+
+#include <com/sun/star/accessibility/AccessibleTextType.hpp>
+#include <com/sun/star/accessibility/TextSegment.hpp>
+#include <com/sun/star/accessibility/XAccessibleMultiLineText.hpp>
+#include <com/sun/star/accessibility/XAccessibleText.hpp>
+#include <com/sun/star/accessibility/XAccessibleTextAttributes.hpp>
+#include <com/sun/star/accessibility/XAccessibleTextMarkup.hpp>
+#include <com/sun/star/text/TextMarkupType.hpp>
+
+// #define ENABLE_TRACING
+
+#ifdef ENABLE_TRACING
+#include <stdio.h>
+#endif
+
+using namespace ::com::sun::star;
+
+static sal_Int16
+text_type_from_boundary(AtkTextBoundary boundary_type)
+{
+ switch(boundary_type)
+ {
+ case ATK_TEXT_BOUNDARY_CHAR:
+ return accessibility::AccessibleTextType::CHARACTER;
+ case ATK_TEXT_BOUNDARY_WORD_START:
+ case ATK_TEXT_BOUNDARY_WORD_END:
+ return accessibility::AccessibleTextType::WORD;
+ case ATK_TEXT_BOUNDARY_SENTENCE_START:
+ case ATK_TEXT_BOUNDARY_SENTENCE_END:
+ return accessibility::AccessibleTextType::SENTENCE;
+ case ATK_TEXT_BOUNDARY_LINE_START:
+ case ATK_TEXT_BOUNDARY_LINE_END:
+ return accessibility::AccessibleTextType::LINE;
+ default:
+ return -1;
+ }
+}
+
+/*****************************************************************************/
+
+static gchar *
+adjust_boundaries( accessibility::XAccessibleText* pText,
+ accessibility::TextSegment& rTextSegment,
+ AtkTextBoundary boundary_type,
+ gint * start_offset, gint * end_offset )
+{
+ accessibility::TextSegment aTextSegment;
+ rtl::OUString aString;
+ gint start = 0, end = 0;
+
+ if( rTextSegment.SegmentText.getLength() > 0 )
+ {
+ switch(boundary_type)
+ {
+ case ATK_TEXT_BOUNDARY_CHAR:
+ case ATK_TEXT_BOUNDARY_LINE_START:
+ case ATK_TEXT_BOUNDARY_LINE_END:
+ case ATK_TEXT_BOUNDARY_SENTENCE_START:
+ start = rTextSegment.SegmentStart;
+ end = rTextSegment.SegmentEnd;
+ aString = rTextSegment.SegmentText;
+ break;
+
+ // the OOo break iterator behaves as SENTENCE_START
+ case ATK_TEXT_BOUNDARY_SENTENCE_END:
+ start = rTextSegment.SegmentStart;
+ end = rTextSegment.SegmentEnd;
+
+ if( start > 0 )
+ --start;
+ if( end > 0 && end < pText->getCharacterCount() - 1 )
+ --end;
+
+ aString = pText->getTextRange(start, end);
+ break;
+
+ case ATK_TEXT_BOUNDARY_WORD_START:
+ start = rTextSegment.SegmentStart;
+
+ // Determine the start index of the next segment
+ aTextSegment = pText->getTextBehindIndex(rTextSegment.SegmentEnd,
+ text_type_from_boundary(boundary_type));
+ if( aTextSegment.SegmentText.getLength() > 0 )
+ end = aTextSegment.SegmentStart;
+ else
+ end = pText->getCharacterCount();
+
+ aString = pText->getTextRange(start, end);
+ break;
+
+ case ATK_TEXT_BOUNDARY_WORD_END:
+ end = rTextSegment.SegmentEnd;
+
+ // Determine the end index of the previous segment
+ aTextSegment = pText->getTextBeforeIndex(rTextSegment.SegmentStart,
+ text_type_from_boundary(boundary_type));
+ if( aTextSegment.SegmentText.getLength() > 0 )
+ start = aTextSegment.SegmentEnd;
+ else
+ start = 0;
+
+ aString = pText->getTextRange(start, end);
+ break;
+
+ default:
+ return NULL;
+ }
+ }
+
+ *start_offset = start;
+ *end_offset = end;
+
+#ifdef ENABLE_TRACING
+ fprintf(stderr, "adjust_boundaries( %d, %d, %d ) returns %d, %d\n",
+ rTextSegment.SegmentStart, rTextSegment.SegmentEnd, boundary_type,
+ start, end);
+#endif
+
+ return OUStringToGChar(aString);
+}
+
+/*****************************************************************************/
+
+static accessibility::XAccessibleText*
+ getText( AtkText *pText ) throw (uno::RuntimeException)
+{
+ AtkObjectWrapper *pWrap = ATK_OBJECT_WRAPPER( pText );
+ if( pWrap )
+ {
+ if( !pWrap->mpText && pWrap->mpContext )
+ {
+ uno::Any any = pWrap->mpContext->queryInterface( accessibility::XAccessibleText::static_type(NULL) );
+ pWrap->mpText = reinterpret_cast< accessibility::XAccessibleText * > (any.pReserved);
+ pWrap->mpText->acquire();
+ }
+
+ return pWrap->mpText;
+ }
+
+ return NULL;
+}
+
+/*****************************************************************************/
+
+static accessibility::XAccessibleTextMarkup*
+ getTextMarkup( AtkText *pText ) throw (uno::RuntimeException)
+{
+ AtkObjectWrapper *pWrap = ATK_OBJECT_WRAPPER( pText );
+ if( pWrap )
+ {
+ if( !pWrap->mpTextMarkup && pWrap->mpContext )
+ {
+ uno::Any any = pWrap->mpContext->queryInterface( accessibility::XAccessibleTextMarkup::static_type(NULL) );
+ /* Since this not a dedicated interface in Atk and thus has not
+ * been queried during wrapper initialization, we need to check
+ * the return value here.
+ */
+ if( typelib_TypeClass_INTERFACE == any.pType->eTypeClass )
+ {
+ pWrap->mpTextMarkup = reinterpret_cast< accessibility::XAccessibleTextMarkup * > (any.pReserved);
+ if( pWrap->mpTextMarkup )
+ pWrap->mpTextMarkup->acquire();
+ }
+ }
+
+ return pWrap->mpTextMarkup;
+ }
+
+ return NULL;
+}
+
+/*****************************************************************************/
+
+static accessibility::XAccessibleTextAttributes*
+ getTextAttributes( AtkText *pText ) throw (uno::RuntimeException)
+{
+ AtkObjectWrapper *pWrap = ATK_OBJECT_WRAPPER( pText );
+ if( pWrap )
+ {
+ if( !pWrap->mpTextAttributes && pWrap->mpContext )
+ {
+ uno::Any any = pWrap->mpContext->queryInterface( accessibility::XAccessibleTextAttributes::static_type(NULL) );
+ /* Since this not a dedicated interface in Atk and thus has not
+ * been queried during wrapper initialization, we need to check
+ * the return value here.
+ */
+ if( typelib_TypeClass_INTERFACE == any.pType->eTypeClass )
+ {
+ pWrap->mpTextAttributes = reinterpret_cast< accessibility::XAccessibleTextAttributes * > (any.pReserved);
+ pWrap->mpTextAttributes->acquire();
+ }
+ }
+
+ return pWrap->mpTextAttributes;
+ }
+
+ return NULL;
+}
+
+/*****************************************************************************/
+
+static accessibility::XAccessibleMultiLineText*
+ getMultiLineText( AtkText *pText ) throw (uno::RuntimeException)
+{
+ AtkObjectWrapper *pWrap = ATK_OBJECT_WRAPPER( pText );
+ if( pWrap )
+ {
+ if( !pWrap->mpMultiLineText && pWrap->mpContext )
+ {
+ uno::Any any = pWrap->mpContext->queryInterface( accessibility::XAccessibleMultiLineText::static_type(NULL) );
+ /* Since this not a dedicated interface in Atk and thus has not
+ * been queried during wrapper initialization, we need to check
+ * the return value here.
+ */
+ if( typelib_TypeClass_INTERFACE == any.pType->eTypeClass )
+ {
+ pWrap->mpMultiLineText = reinterpret_cast< accessibility::XAccessibleMultiLineText * > (any.pReserved);
+ pWrap->mpMultiLineText->acquire();
+ }
+ }
+
+ return pWrap->mpMultiLineText;
+ }
+
+ return NULL;
+}
+
+/*****************************************************************************/
+
+extern "C" {
+
+static gchar *
+text_wrapper_get_text (AtkText *text,
+ gint start_offset,
+ gint end_offset)
+{
+ gchar * ret = NULL;
+
+ g_return_val_if_fail( (end_offset == -1) || (end_offset >= start_offset), NULL );
+
+ /* at-spi expects the delete event to be send before the deletion happened
+ * so we save the deleted string object in the UNO event notification and
+ * fool libatk-bridge.so here ..
+ */
+ void * pData = g_object_get_data( G_OBJECT(text), "ooo::text_changed::delete" );
+ if( pData != NULL )
+ {
+ accessibility::TextSegment * pTextSegment =
+ reinterpret_cast <accessibility::TextSegment *> (pData);
+
+ if( pTextSegment->SegmentStart == start_offset &&
+ pTextSegment->SegmentEnd == end_offset )
+ {
+ rtl::OString aUtf8 = rtl::OUStringToOString( pTextSegment->SegmentText, RTL_TEXTENCODING_UTF8 );
+ return g_strdup( aUtf8.getStr() );
+ }
+ }
+
+ try {
+ accessibility::XAccessibleText* pText = getText( text );
+ if( pText )
+ {
+ rtl::OUString aText;
+ sal_Int32 n = pText->getCharacterCount();
+
+ if( -1 == end_offset )
+ aText = pText->getText();
+ else if( start_offset < n )
+ aText = pText->getTextRange(start_offset, end_offset);
+
+ ret = g_strdup( rtl::OUStringToOString(aText, RTL_TEXTENCODING_UTF8 ).getStr() );
+ }
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getText()" );
+ }
+
+#ifdef ENABLE_TRACING
+ fprintf(stderr, "text_wrapper_get_text( %d,%d ) returns %s\n", start_offset, end_offset, ret ? ret : "null" );
+#endif
+ return ret;
+}
+
+static gchar *
+text_wrapper_get_text_after_offset (AtkText *text,
+ gint offset,
+ AtkTextBoundary boundary_type,
+ gint *start_offset,
+ gint *end_offset)
+{
+ try {
+ accessibility::XAccessibleText* pText = getText( text );
+ if( pText )
+ {
+ accessibility::TextSegment aTextSegment = pText->getTextBehindIndex(offset, text_type_from_boundary(boundary_type));
+ return adjust_boundaries(pText, aTextSegment, boundary_type, start_offset, end_offset);
+ }
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in get_text_after_offset()" );
+ }
+
+ return NULL;
+}
+
+static gchar *
+text_wrapper_get_text_at_offset (AtkText *text,
+ gint offset,
+ AtkTextBoundary boundary_type,
+ gint *start_offset,
+ gint *end_offset)
+{
+ try {
+ accessibility::XAccessibleText* pText = getText( text );
+ if( pText )
+ {
+ /* If the user presses the 'End' key, the caret will be placed behind the last character,
+ * which is the same index as the first character of the next line. In atk the magic offset
+ * '-2' is used to cover this special case.
+ */
+ if (
+ -2 == offset &&
+ (ATK_TEXT_BOUNDARY_LINE_START == boundary_type ||
+ ATK_TEXT_BOUNDARY_LINE_END == boundary_type)
+ )
+ {
+ accessibility::XAccessibleMultiLineText* pMultiLineText = getMultiLineText( text );
+ if( pMultiLineText )
+ {
+ accessibility::TextSegment aTextSegment = pMultiLineText->getTextAtLineWithCaret();
+ return adjust_boundaries(pText, aTextSegment, boundary_type, start_offset, end_offset);
+ }
+ }
+
+ accessibility::TextSegment aTextSegment = pText->getTextAtIndex(offset, text_type_from_boundary(boundary_type));
+ return adjust_boundaries(pText, aTextSegment, boundary_type, start_offset, end_offset);
+ }
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in get_text_at_offset()" );
+ }
+
+ return NULL;
+}
+
+static gunichar
+text_wrapper_get_character_at_offset (AtkText *text,
+ gint offset)
+{
+ gint start, end;
+ gunichar uc = 0;
+
+ gchar * char_as_string =
+ text_wrapper_get_text_at_offset(text, offset, ATK_TEXT_BOUNDARY_CHAR,
+ &start, &end);
+ if( char_as_string )
+ {
+ uc = g_utf8_get_char( char_as_string );
+ g_free( char_as_string );
+ }
+
+ return uc;
+}
+
+static gchar *
+text_wrapper_get_text_before_offset (AtkText *text,
+ gint offset,
+ AtkTextBoundary boundary_type,
+ gint *start_offset,
+ gint *end_offset)
+{
+ try {
+ accessibility::XAccessibleText* pText = getText( text );
+ if( pText )
+ {
+ accessibility::TextSegment aTextSegment = pText->getTextBeforeIndex(offset, text_type_from_boundary(boundary_type));
+ return adjust_boundaries(pText, aTextSegment, boundary_type, start_offset, end_offset);
+ }
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in text_before_offset()" );
+ }
+
+ return NULL;
+}
+
+static gint
+text_wrapper_get_caret_offset (AtkText *text)
+{
+ gint offset = -1;
+
+ try {
+ accessibility::XAccessibleText* pText = getText( text );
+ if( pText )
+ offset = pText->getCaretPosition();
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getCaretPosition()" );
+ }
+
+#ifdef ENABLE_TRACING
+ fprintf(stderr, "get_caret_offset(%p) returns %d\n", text, offset);
+#endif
+
+ return offset;
+}
+
+static gboolean
+text_wrapper_set_caret_offset (AtkText *text,
+ gint offset)
+{
+ try {
+ accessibility::XAccessibleText* pText = getText( text );
+ if( pText )
+ return pText->setCaretPosition( offset );
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in setCaretPosition()" );
+ }
+
+ return FALSE;
+}
+
+// --> OD 2010-03-04 #i92232#
+AtkAttributeSet*
+handle_text_markup_as_run_attribute( accessibility::XAccessibleTextMarkup* pTextMarkup,
+ const gint nTextMarkupType,
+ const gint offset,
+ AtkAttributeSet* pSet,
+ gint *start_offset,
+ gint *end_offset )
+{
+ const gint nTextMarkupCount( pTextMarkup->getTextMarkupCount( nTextMarkupType ) );
+ if ( nTextMarkupCount > 0 )
+ {
+ for ( gint nTextMarkupIndex = 0;
+ nTextMarkupIndex < nTextMarkupCount;
+ ++nTextMarkupIndex )
+ {
+ accessibility::TextSegment aTextSegment =
+ pTextMarkup->getTextMarkup( nTextMarkupIndex, nTextMarkupType );
+ const gint nStartOffsetTextMarkup = aTextSegment.SegmentStart;
+ const gint nEndOffsetTextMarkup = aTextSegment.SegmentEnd;
+ if ( nStartOffsetTextMarkup <= offset )
+ {
+ if ( offset < nEndOffsetTextMarkup )
+ {
+ // text markup at <offset>
+ *start_offset = ::std::max( *start_offset,
+ nStartOffsetTextMarkup );
+ *end_offset = ::std::min( *end_offset,
+ nEndOffsetTextMarkup );
+ switch ( nTextMarkupType )
+ {
+ case com::sun::star::text::TextMarkupType::SPELLCHECK:
+ {
+ pSet = attribute_set_prepend_misspelled( pSet );
+ }
+ break;
+ case com::sun::star::text::TextMarkupType::TRACK_CHANGE_INSERTION:
+ {
+ pSet = attribute_set_prepend_tracked_change_insertion( pSet );
+ }
+ break;
+ case com::sun::star::text::TextMarkupType::TRACK_CHANGE_DELETION:
+ {
+ pSet = attribute_set_prepend_tracked_change_deletion( pSet );
+ }
+ break;
+ case com::sun::star::text::TextMarkupType::TRACK_CHANGE_FORMATCHANGE:
+ {
+ pSet = attribute_set_prepend_tracked_change_formatchange( pSet );
+ }
+ break;
+ default:
+ {
+ OSL_ASSERT( false );
+ }
+ }
+ break; // no further iteration needed.
+ }
+ else
+ {
+ *start_offset = ::std::max( *start_offset,
+ nEndOffsetTextMarkup );
+ // continue iteration.
+ }
+ }
+ else
+ {
+ *end_offset = ::std::min( *end_offset,
+ nStartOffsetTextMarkup );
+ break; // no further iteration.
+ }
+ } // eof iteration over text markups
+ }
+
+ return pSet;
+}
+// <--
+
+static AtkAttributeSet *
+text_wrapper_get_run_attributes( AtkText *text,
+ gint offset,
+ gint *start_offset,
+ gint *end_offset)
+{
+ AtkAttributeSet *pSet = NULL;
+
+ try {
+ bool bOffsetsAreValid = false;
+
+ accessibility::XAccessibleText* pText = getText( text );
+ accessibility::XAccessibleTextAttributes* pTextAttributes = getTextAttributes( text );
+ if( pText && pTextAttributes )
+ {
+ uno::Sequence< beans::PropertyValue > aAttributeList =
+ pTextAttributes->getRunAttributes( offset, uno::Sequence< rtl::OUString > () );
+
+ pSet = attribute_set_new_from_property_values( aAttributeList, true, text );
+ // --> OD 2009-06-22 #i100938#
+ // - always provide start_offset and end_offset
+// if( pSet )
+ // <--
+ {
+ accessibility::TextSegment aTextSegment =
+ pText->getTextAtIndex(offset, accessibility::AccessibleTextType::ATTRIBUTE_RUN);
+
+ *start_offset = aTextSegment.SegmentStart;
+ // --> OD 2009-06-22 #i100938#
+ // Do _not_ increment the end_offset provide by <accessibility::TextSegment> instance
+// *end_offset = aTextSegment.SegmentEnd + 1; // FIXME: TESTME
+ *end_offset = aTextSegment.SegmentEnd;
+ // <--
+ bOffsetsAreValid = true;
+ }
+ }
+
+ // Special handling for misspelled text
+ // --> OD 2010-03-01 #i92232#
+ // - add special handling for tracked changes and refactor the
+ // corresponding code for handling misspelled text.
+ accessibility::XAccessibleTextMarkup* pTextMarkup = getTextMarkup( text );
+ if( pTextMarkup )
+ {
+ // Get attribute run here if it hasn't been done before
+ if( !bOffsetsAreValid )
+ {
+ accessibility::TextSegment aAttributeTextSegment =
+ pText->getTextAtIndex(offset, accessibility::AccessibleTextType::ATTRIBUTE_RUN);
+ *start_offset = aAttributeTextSegment.SegmentStart;
+ *end_offset = aAttributeTextSegment.SegmentEnd;
+ }
+ // handle misspelled text
+ pSet = handle_text_markup_as_run_attribute(
+ pTextMarkup,
+ com::sun::star::text::TextMarkupType::SPELLCHECK,
+ offset, pSet, start_offset, end_offset );
+ // handle tracked changes
+ pSet = handle_text_markup_as_run_attribute(
+ pTextMarkup,
+ com::sun::star::text::TextMarkupType::TRACK_CHANGE_INSERTION,
+ offset, pSet, start_offset, end_offset );
+ pSet = handle_text_markup_as_run_attribute(
+ pTextMarkup,
+ com::sun::star::text::TextMarkupType::TRACK_CHANGE_DELETION,
+ offset, pSet, start_offset, end_offset );
+ pSet = handle_text_markup_as_run_attribute(
+ pTextMarkup,
+ com::sun::star::text::TextMarkupType::TRACK_CHANGE_FORMATCHANGE,
+ offset, pSet, start_offset, end_offset );
+ }
+ // <--
+ }
+ catch(const uno::Exception& e){
+
+ g_warning( "Exception in get_run_attributes()" );
+
+ if( pSet )
+ {
+ atk_attribute_set_free( pSet );
+ pSet = NULL;
+ }
+ }
+
+ return pSet;
+}
+
+/*****************************************************************************/
+
+static AtkAttributeSet *
+text_wrapper_get_default_attributes( AtkText *text )
+{
+ AtkAttributeSet *pSet = NULL;
+
+ try {
+ accessibility::XAccessibleTextAttributes* pTextAttributes = getTextAttributes( text );
+ if( pTextAttributes )
+ {
+ uno::Sequence< beans::PropertyValue > aAttributeList =
+ pTextAttributes->getDefaultAttributes( uno::Sequence< rtl::OUString > () );
+
+ pSet = attribute_set_new_from_property_values( aAttributeList, false, text );
+ }
+ }
+ catch(const uno::Exception& e) {
+
+ g_warning( "Exception in get_default_attributes()" );
+
+ if( pSet )
+ {
+ atk_attribute_set_free( pSet );
+ pSet = NULL;
+ }
+ }
+
+ return pSet;
+}
+
+/*****************************************************************************/
+
+static void
+text_wrapper_get_character_extents( AtkText *text,
+ gint offset,
+ gint *x,
+ gint *y,
+ gint *width,
+ gint *height,
+ AtkCoordType coords )
+{
+ try {
+ accessibility::XAccessibleText* pText = getText( text );
+ if( pText )
+ {
+ *x = *y = *width = *height = 0;
+ awt::Rectangle aRect = pText->getCharacterBounds( offset );
+
+ gint origin_x = 0;
+ gint origin_y = 0;
+
+ if( coords == ATK_XY_SCREEN )
+ {
+ g_return_if_fail( ATK_IS_COMPONENT( text ) );
+ atk_component_get_position( ATK_COMPONENT( text ), &origin_x, &origin_y, coords);
+ }
+
+ *x = aRect.X + origin_x;
+ *y = aRect.Y + origin_y;
+ *width = aRect.Width;
+ *height = aRect.Height;
+
+#ifdef ENABLE_TRACING
+ fprintf(stderr, "get_character_extents(%d, %d) returns: %d,%d,%d,%d ",
+ offset, coords, *x, *y, *width, *height);
+#endif
+ }
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getCharacterBounds" );
+ }
+}
+
+static gint
+text_wrapper_get_character_count (AtkText *text)
+{
+ gint rv = 0;
+
+ try {
+ accessibility::XAccessibleText* pText = getText( text );
+ if( pText )
+ rv = pText->getCharacterCount();
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getCharacterCount" );
+ }
+
+#ifdef ENABLE_TRACING
+ fprintf(stderr, "get_character_count(%p) returns: %d\n", text, rv);
+#endif
+
+ return rv;
+}
+
+static gint
+text_wrapper_get_offset_at_point (AtkText *text,
+ gint x,
+ gint y,
+ AtkCoordType coords)
+{
+ try {
+ accessibility::XAccessibleText* pText = getText( text );
+ if( pText )
+ {
+ gint origin_x = 0;
+ gint origin_y = 0;
+
+ if( coords == ATK_XY_SCREEN )
+ {
+ g_return_val_if_fail( ATK_IS_COMPONENT( text ), -1 );
+ atk_component_get_position( ATK_COMPONENT( text ), &origin_x, &origin_y, coords);
+ }
+
+ return pText->getIndexAtPoint( awt::Point(x - origin_x, y - origin_y) );
+ }
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getIndexAtPoint" );
+ }
+
+ return -1;
+}
+
+// FIXME: the whole series of selections API is problematic ...
+
+static gint
+text_wrapper_get_n_selections (AtkText *text)
+{
+ gint rv = 0;
+
+ try {
+ accessibility::XAccessibleText* pText = getText( text );
+ if( pText )
+ rv = ( pText->getSelectionEnd() > pText->getSelectionStart() ) ? 1 : 0;
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getSelectionEnd() or getSelectionStart()" );
+ }
+
+#ifdef ENABLE_TRACING
+ fprintf(stderr, "get_n_selections(%p) returns %d\n", text, rv);
+#endif
+
+ return rv;
+}
+
+static gchar *
+text_wrapper_get_selection (AtkText *text,
+ gint selection_num,
+ gint *start_offset,
+ gint *end_offset)
+{
+ g_return_val_if_fail( selection_num == 0, FALSE );
+
+ try {
+ accessibility::XAccessibleText* pText = getText( text );
+ if( pText )
+ {
+ *start_offset = pText->getSelectionStart();
+ *end_offset = pText->getSelectionEnd();
+
+ return OUStringToGChar( pText->getSelectedText() );
+ }
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getSelectionEnd(), getSelectionStart() or getSelectedText()" );
+ }
+
+ return NULL;
+}
+
+static gboolean
+text_wrapper_add_selection (AtkText *text,
+ gint start_offset,
+ gint end_offset)
+{
+ // FIXME: can we try to be more compatible by expanding an
+ // existing adjacent selection ?
+
+ try {
+ accessibility::XAccessibleText* pText = getText( text );
+ if( pText )
+ return pText->setSelection( start_offset, end_offset ); // ?
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in setSelection()" );
+ }
+
+ return FALSE;
+}
+
+static gboolean
+text_wrapper_remove_selection (AtkText *text,
+ gint selection_num)
+{
+ g_return_val_if_fail( selection_num == 0, FALSE );
+
+ try {
+ accessibility::XAccessibleText* pText = getText( text );
+ if( pText )
+ return pText->setSelection( 0, 0 ); // ?
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in setSelection()" );
+ }
+
+ return FALSE;
+}
+
+static gboolean
+text_wrapper_set_selection (AtkText *text,
+ gint selection_num,
+ gint start_offset,
+ gint end_offset)
+{
+ g_return_val_if_fail( selection_num == 0, FALSE );
+
+ try {
+ accessibility::XAccessibleText* pText = getText( text );
+ if( pText )
+ return pText->setSelection( start_offset, end_offset );
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in setSelection()" );
+ }
+
+ return FALSE;
+}
+
+} // extern "C"
+
+void
+textIfaceInit (AtkTextIface *iface)
+{
+ g_return_if_fail (iface != NULL);
+
+ iface->get_text = text_wrapper_get_text;
+ iface->get_character_at_offset = text_wrapper_get_character_at_offset;
+ iface->get_text_before_offset = text_wrapper_get_text_before_offset;
+ iface->get_text_at_offset = text_wrapper_get_text_at_offset;
+ iface->get_text_after_offset = text_wrapper_get_text_after_offset;
+ iface->get_caret_offset = text_wrapper_get_caret_offset;
+ iface->set_caret_offset = text_wrapper_set_caret_offset;
+ iface->get_character_count = text_wrapper_get_character_count;
+ iface->get_n_selections = text_wrapper_get_n_selections;
+ iface->get_selection = text_wrapper_get_selection;
+ iface->add_selection = text_wrapper_add_selection;
+ iface->remove_selection = text_wrapper_remove_selection;
+ iface->set_selection = text_wrapper_set_selection;
+ iface->get_run_attributes = text_wrapper_get_run_attributes;
+ iface->get_default_attributes = text_wrapper_get_default_attributes;
+ iface->get_character_extents = text_wrapper_get_character_extents;
+ iface->get_offset_at_point = text_wrapper_get_offset_at_point;
+}
diff --git a/vcl/unx/gtk/a11y/atktextattributes.cxx b/vcl/unx/gtk/a11y/atktextattributes.cxx
new file mode 100644
index 000000000000..04498810597f
--- /dev/null
+++ b/vcl/unx/gtk/a11y/atktextattributes.cxx
@@ -0,0 +1,1456 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "atktextattributes.hxx"
+
+#include <com/sun/star/awt/FontSlant.hpp>
+#include <com/sun/star/awt/FontStrikeout.hpp>
+#include <com/sun/star/awt/FontUnderline.hpp>
+
+#include <com/sun/star/style/CaseMap.hpp>
+#include <com/sun/star/style/LineSpacing.hpp>
+#include <com/sun/star/style/LineSpacingMode.hpp>
+#include <com/sun/star/style/ParagraphAdjust.hpp>
+#include <com/sun/star/style/TabAlign.hpp>
+#include <com/sun/star/style/TabStop.hpp>
+
+#include <com/sun/star/text/WritingMode2.hpp>
+
+#include "atkwrapper.hxx"
+
+#include <com/sun/star/accessibility/XAccessibleComponent.hpp>
+
+#include <vcl/svapp.hxx>
+#include <vcl/outdev.hxx>
+
+#include <stdio.h>
+#include <string.h>
+
+using namespace ::com::sun::star;
+
+typedef gchar* (* AtkTextAttrFunc) ( const uno::Any& rAny );
+typedef bool (* TextPropertyValueFunc) ( uno::Any& rAny, const gchar * value );
+
+#define STRNCMP_PARAM( s ) s,sizeof( s )-1
+
+
+/*****************************************************************************/
+
+static AtkTextAttribute atk_text_attribute_paragraph_style = ATK_TEXT_ATTR_INVALID;
+static AtkTextAttribute atk_text_attribute_font_effect = ATK_TEXT_ATTR_INVALID;
+static AtkTextAttribute atk_text_attribute_decoration = ATK_TEXT_ATTR_INVALID;
+static AtkTextAttribute atk_text_attribute_line_height = ATK_TEXT_ATTR_INVALID;
+static AtkTextAttribute atk_text_attribute_rotation = ATK_TEXT_ATTR_INVALID;
+static AtkTextAttribute atk_text_attribute_shadow = ATK_TEXT_ATTR_INVALID;
+static AtkTextAttribute atk_text_attribute_tab_interval = ATK_TEXT_ATTR_INVALID;
+static AtkTextAttribute atk_text_attribute_tab_stops = ATK_TEXT_ATTR_INVALID;
+static AtkTextAttribute atk_text_attribute_writing_mode = ATK_TEXT_ATTR_INVALID;
+static AtkTextAttribute atk_text_attribute_vertical_align = ATK_TEXT_ATTR_INVALID;
+static AtkTextAttribute atk_text_attribute_misspelled = ATK_TEXT_ATTR_INVALID;
+// --> OD 2010-03-01 #i92232#
+static AtkTextAttribute atk_text_attribute_tracked_change = ATK_TEXT_ATTR_INVALID;
+// <--
+// --> OD 2010-03-05 #i92233#
+static AtkTextAttribute atk_text_attribute_mm_to_pixel_ratio = ATK_TEXT_ATTR_INVALID;
+// <--
+
+/*****************************************************************************/
+
+/**
+ * !! IMPORTANT NOTE !! : when adding items to this list, KEEP THE LIST SORTED
+ * and re-arrange the enum values accordingly.
+ */
+
+enum ExportedAttribute
+{
+ TEXT_ATTRIBUTE_BACKGROUND_COLOR = 0,
+ TEXT_ATTRIBUTE_CASEMAP,
+ TEXT_ATTRIBUTE_FOREGROUND_COLOR,
+ TEXT_ATTRIBUTE_CONTOURED,
+ TEXT_ATTRIBUTE_CHAR_ESCAPEMENT,
+ TEXT_ATTRIBUTE_BLINKING,
+ TEXT_ATTRIBUTE_FONT_NAME,
+ TEXT_ATTRIBUTE_HEIGHT,
+ TEXT_ATTRIBUTE_HIDDEN,
+ TEXT_ATTRIBUTE_KERNING,
+ TEXT_ATTRIBUTE_LOCALE,
+ TEXT_ATTRIBUTE_POSTURE,
+ TEXT_ATTRIBUTE_RELIEF,
+ TEXT_ATTRIBUTE_ROTATION,
+ TEXT_ATTRIBUTE_SCALE,
+ TEXT_ATTRIBUTE_SHADOWED,
+ TEXT_ATTRIBUTE_STRIKETHROUGH,
+ TEXT_ATTRIBUTE_UNDERLINE,
+ TEXT_ATTRIBUTE_WEIGHT,
+ // --> OD 2010-03-05 #i92233#
+ TEXT_ATTRIBUTE_MM_TO_PIXEL_RATIO,
+ // <--
+ TEXT_ATTRIBUTE_JUSTIFICATION,
+ TEXT_ATTRIBUTE_BOTTOM_MARGIN,
+ TEXT_ATTRIBUTE_FIRST_LINE_INDENT,
+ TEXT_ATTRIBUTE_LEFT_MARGIN,
+ TEXT_ATTRIBUTE_LINE_SPACING,
+ TEXT_ATTRIBUTE_RIGHT_MARGIN,
+ TEXT_ATTRIBUTE_STYLE_NAME,
+ TEXT_ATTRIBUTE_TAB_STOPS,
+ TEXT_ATTRIBUTE_TOP_MARGIN,
+ TEXT_ATTRIBUTE_WRITING_MODE,
+ TEXT_ATTRIBUTE_LAST
+};
+
+static const char * ExportedTextAttributes[TEXT_ATTRIBUTE_LAST] =
+{
+ "CharBackColor", // TEXT_ATTRIBUTE_BACKGROUND_COLOR
+ "CharCaseMap", // TEXT_ATTRIBUTE_CASEMAP
+ "CharColor", // TEXT_ATTRIBUTE_FOREGROUND_COLOR
+ "CharContoured", // TEXT_ATTRIBUTE_CONTOURED
+ "CharEscapement", // TEXT_ATTRIBUTE_CHAR_ESCAPEMENT
+ "CharFlash", // TEXT_ATTRIBUTE_BLINKING
+ "CharFontName", // TEXT_ATTRIBUTE_FONT_NAME
+ "CharHeight", // TEXT_ATTRIBUTE_HEIGHT
+ "CharHidden", // TEXT_ATTRIBUTE_HIDDEN
+ "CharKerning", // TEXT_ATTRIBUTE_KERNING
+ "CharLocale", // TEXT_ATTRIBUTE_LOCALE
+ "CharPosture", // TEXT_ATTRIBUTE_POSTURE
+ "CharRelief", // TEXT_ATTRIBUTE_RELIEF
+ "CharRotation", // TEXT_ATTRIBUTE_ROTATION
+ "CharScaleWidth", // TEXT_ATTRIBUTE_SCALE
+ "CharShadowed", // TEXT_ATTRIBUTE_SHADOWED
+ "CharStrikeout", // TEXT_ATTRIBUTE_STRIKETHROUGH
+ "CharUnderline", // TEXT_ATTRIBUTE_UNDERLINE
+ "CharWeight", // TEXT_ATTRIBUTE_WEIGHT
+ // --> OD 2010-03-05 #i92233#
+ "MMToPixelRatio", // TEXT_ATTRIBUTE_MM_TO_PIXEL_RATIO
+ // <--
+ "ParaAdjust", // TEXT_ATTRIBUTE_JUSTIFICATION
+ "ParaBottomMargin", // TEXT_ATTRIBUTE_BOTTOM_MARGIN
+ "ParaFirstLineIndent", // TEXT_ATTRIBUTE_FIRST_LINE_INDENT
+ "ParaLeftMargin", // TEXT_ATTRIBUTE_LEFT_MARGIN
+ "ParaLineSpacing", // TEXT_ATTRIBUTE_LINE_SPACING
+ "ParaRightMargin", // TEXT_ATTRIBUTE_RIGHT_MARGIN
+ "ParaStyleName", // TEXT_ATTRIBUTE_STYLE_NAME
+ "ParaTabStops", // TEXT_ATTRIBUTE_TAB_STOPS
+ "ParaTopMargin", // TEXT_ATTRIBUTE_TOP_MARGIN
+ "WritingMode" // TEXT_ATTRIBUTE_WRITING_MODE
+};
+
+
+/*****************************************************************************/
+
+static gchar*
+get_value( const uno::Sequence< beans::PropertyValue >& rAttributeList,
+ sal_Int32 nIndex, AtkTextAttrFunc func )
+{
+ if( nIndex != -1 )
+ return func(rAttributeList[nIndex].Value);
+
+ return NULL;
+}
+
+#define get_bool_value( list, index ) get_value( list, index, Bool2String )
+#define get_short_value( list, index ) get_value( list, index, Short2String )
+//#define get_long_value( list, index ) get_value( list, index, Long2String ) pb: not used (warning on linux)
+#define get_height_value( list, index ) get_value( list, index, Float2String )
+#define get_justification_value( list, index ) get_value( list, index, Adjust2Justification )
+#define get_cmm_value( list, index ) get_value( list, index, CMM2UnitString )
+#define get_scale_width( list, index ) get_value( list, index, Scale2String )
+#define get_strikethrough_value( list, index ) get_value( list, index, Strikeout2String )
+#define get_string_value( list, index ) get_value( list, index, GetString )
+#define get_style_value( list, index ) get_value( list, index, FontSlant2Style )
+#define get_underline_value( list, index ) get_value( list, index, Underline2String )
+#define get_variant_value( list, index ) get_value( list, index, CaseMap2String )
+#define get_weight_value( list, index ) get_value( list, index, Weight2String )
+#define get_language_string( list, index ) get_value( list, index, Locale2String )
+
+/*
+static gchar*
+dump_value( const uno::Sequence< beans::PropertyValue >& rAttributeList, sal_Int32 nIndex )
+{
+ if( nIndex != -1 )
+ {
+ rtl::OString aName = rtl::OUStringToOString(rAttributeList[nIndex].Name, RTL_TEXTENCODING_UTF8);
+
+ if( rAttributeList[nIndex].Value.has<sal_Int16> () )
+ OSL_TRACE( "%s = %d (short value)", aName.getStr(),
+ rAttributeList[nIndex].Value.get<sal_Int16> () );
+
+ else if( rAttributeList[nIndex].Value.has<sal_Int8> () )
+ OSL_TRACE( "%s = %d (byte value)", aName.getStr(),
+ rAttributeList[nIndex].Value.get<sal_Int8> () );
+
+ else if( rAttributeList[nIndex].Value.has<sal_Bool> () )
+ OSL_TRACE( "%s = %s (bool value)", aName.getStr(),
+ rAttributeList[nIndex].Value.get<sal_Bool> () ? "true" : "false" );
+
+ else if( rAttributeList[nIndex].Value.has<rtl::OUString> () )
+ OSL_TRACE( "%s = %s", aName.getStr(),
+ rtl::OUStringToOString(rAttributeList[nIndex].Value.get<rtl::OUString> (),
+ RTL_TEXTENCODING_UTF8).getStr() );
+ }
+
+ return NULL;
+}
+*/
+
+static inline
+double toPoint(sal_Int16 n)
+{
+ // 100th mm -> pt
+ return (double) (n * 72) / 2540;
+}
+
+
+/*****************************************************************************/
+
+/*
+static gchar*
+NullString(const uno::Any&)
+{
+ return NULL;
+}
+*/
+
+static bool
+InvalidValue( uno::Any&, const gchar * )
+{
+ return false;
+}
+
+/*****************************************************************************/
+
+static gchar*
+Float2String(const uno::Any& rAny)
+{
+ return g_strdup_printf( "%g", rAny.get<float>() );
+}
+
+static bool
+String2Float( uno::Any& rAny, const gchar * value )
+{
+ float fval;
+
+ if( 1 != sscanf( value, "%g", &fval ) )
+ return false;
+
+ rAny = uno::makeAny( fval );
+ return true;
+}
+
+/*****************************************************************************/
+
+/*
+static gchar*
+Short2String(const uno::Any& rAny)
+{
+ return g_strdup_printf( "%d", rAny.get<sal_Int16>() );
+}
+
+static bool
+String2Short( uno::Any& rAny, const gchar * value )
+{
+ sal_Int32 lval;
+
+ if( 1 != sscanf( value, "%d", &lval ) )
+ return false;
+
+ rAny = uno::makeAny( (sal_Int16) lval );
+ return true;
+}
+*/
+
+/*****************************************************************************/
+/* pb: not used (warning on linux)
+static gchar*
+Long2String(const uno::Any& rAny)
+{
+ return g_strdup_printf( "%ld", rAny.get<sal_Int32>() );
+}
+
+static bool
+String2Long( uno::Any& rAny, const gchar * value )
+{
+ sal_Int32 lval;
+
+ if( 1 != sscanf( value, "%ld", &lval ) )
+ return false;
+
+ rAny = uno::makeAny( lval );
+ return true;
+}
+*/
+/*****************************************************************************/
+
+static accessibility::XAccessibleComponent*
+ getComponent( AtkText *pText ) throw (uno::RuntimeException)
+{
+ AtkObjectWrapper *pWrap = ATK_OBJECT_WRAPPER( pText );
+ if( pWrap )
+ {
+ if( !pWrap->mpComponent && pWrap->mpContext )
+ {
+ uno::Any any = pWrap->mpContext->queryInterface( accessibility::XAccessibleComponent::static_type(NULL) );
+ pWrap->mpComponent = reinterpret_cast< accessibility::XAccessibleComponent * > (any.pReserved);
+ pWrap->mpComponent->acquire();
+ }
+
+ return pWrap->mpComponent;
+ }
+
+ return NULL;
+}
+
+static gchar*
+get_color_value(const uno::Sequence< beans::PropertyValue >& rAttributeList,
+ const sal_Int32 * pIndexArray,
+ ExportedAttribute attr,
+ AtkText * text)
+{
+ sal_Int32 nColor = -1; // AUTOMATIC
+ sal_Int32 nIndex = pIndexArray[attr];
+
+ if( nIndex != -1 )
+ nColor = rAttributeList[nIndex].Value.get<sal_Int32>();
+
+ /*
+ * Check for color value for 100% alpha white, which means
+ * "automatic". Grab the RGB value from XAccessibleComponent
+ * in this case.
+ */
+
+ if( (nColor == -1) && text )
+ {
+ try
+ {
+ accessibility::XAccessibleComponent *pComponent = getComponent( text );
+ if( pComponent )
+ {
+ switch( attr )
+ {
+ case TEXT_ATTRIBUTE_BACKGROUND_COLOR:
+ nColor = pComponent->getBackground();
+ break;
+ case TEXT_ATTRIBUTE_FOREGROUND_COLOR:
+ nColor = pComponent->getForeground();
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in get[Fore|Back]groundColor()" );
+ }
+ }
+
+ if( nColor != -1 )
+ {
+ sal_uInt8 blue = nColor & 0xFF;
+ sal_uInt8 green = (nColor >> 8) & 0xFF;
+ sal_uInt8 red = (nColor >> 16) & 0xFF;
+
+ return g_strdup_printf( "%u,%u,%u", red, green, blue );
+ }
+
+ return NULL;
+}
+
+static bool
+String2Color( uno::Any& rAny, const gchar * value )
+{
+ int red, green, blue;
+
+ if( 3 != sscanf( value, "%d,%d,%d", &red, &green, &blue ) )
+ return false;
+
+ sal_Int32 nColor = (sal_Int32) blue | ( (sal_Int32) green << 8 ) | ( ( sal_Int32 ) red << 16 );
+ rAny = uno::makeAny( nColor );
+ return true;
+}
+
+/*****************************************************************************/
+
+static gchar*
+FontSlant2Style(const uno::Any& rAny)
+{
+ const gchar * value = NULL;
+
+ switch( rAny.get<awt::FontSlant>() )
+ {
+ case awt::FontSlant_NONE:
+ value = "normal";
+ break;
+
+ case awt::FontSlant_OBLIQUE:
+ value = "oblique";
+ break;
+
+ case awt::FontSlant_ITALIC:
+ value = "italic";
+ break;
+
+ case awt::FontSlant_REVERSE_OBLIQUE:
+ value = "reverse oblique";
+ break;
+
+ case awt::FontSlant_REVERSE_ITALIC:
+ value = "reverse italic";
+ break;
+
+ default:
+ break;
+ }
+
+ if( value )
+ return g_strdup( value );
+
+ return NULL;
+}
+
+static bool
+Style2FontSlant( uno::Any& rAny, const gchar * value )
+{
+ awt::FontSlant aFontSlant;
+
+ if( strncmp( value, STRNCMP_PARAM( "normal" ) ) )
+ aFontSlant = awt::FontSlant_NONE;
+ else if( strncmp( value, STRNCMP_PARAM( "oblique" ) ) )
+ aFontSlant = awt::FontSlant_OBLIQUE;
+ else if( strncmp( value, STRNCMP_PARAM( "italic" ) ) )
+ aFontSlant = awt::FontSlant_ITALIC;
+ else if( strncmp( value, STRNCMP_PARAM( "reverse oblique" ) ) )
+ aFontSlant = awt::FontSlant_REVERSE_OBLIQUE;
+ else if( strncmp( value, STRNCMP_PARAM( "reverse italic" ) ) )
+ aFontSlant = awt::FontSlant_REVERSE_ITALIC;
+ else
+ return false;
+
+ rAny = uno::makeAny( aFontSlant );
+ return true;
+}
+
+/*****************************************************************************/
+
+static gchar*
+Weight2String(const uno::Any& rAny)
+{
+ return g_strdup_printf( "%g", rAny.get<float>() * 4 );
+}
+
+static bool
+String2Weight( uno::Any& rAny, const gchar * value )
+{
+ float weight;
+
+ if( 1 != sscanf( value, "%g", &weight ) )
+ return false;
+
+ rAny = uno::makeAny( weight / 4 );
+ return true;
+}
+
+
+/*****************************************************************************/
+
+static gchar*
+Adjust2Justification(const uno::Any& rAny)
+{
+ const gchar * value = NULL;
+
+ switch( rAny.get<short>() )
+ {
+ case style::ParagraphAdjust_LEFT:
+ value = "left";
+ break;
+
+ case style::ParagraphAdjust_RIGHT:
+ value = "right";
+ break;
+
+ case style::ParagraphAdjust_BLOCK:
+ case style::ParagraphAdjust_STRETCH:
+ value = "fill";
+ break;
+
+ case style::ParagraphAdjust_CENTER:
+ value = "center";
+ break;
+
+ default:
+ break;
+ }
+
+ if( value )
+ return g_strdup( value );
+
+ return NULL;
+}
+
+static bool
+Justification2Adjust( uno::Any& rAny, const gchar * value )
+{
+ short nParagraphAdjust;
+
+ if( strncmp( value, STRNCMP_PARAM( "left" ) ) )
+ nParagraphAdjust = style::ParagraphAdjust_LEFT;
+ else if( strncmp( value, STRNCMP_PARAM( "right" ) ) )
+ nParagraphAdjust = style::ParagraphAdjust_RIGHT;
+ else if( strncmp( value, STRNCMP_PARAM( "fill" ) ) )
+ nParagraphAdjust = style::ParagraphAdjust_BLOCK;
+ else if( strncmp( value, STRNCMP_PARAM( "center" ) ) )
+ nParagraphAdjust = style::ParagraphAdjust_CENTER;
+ else
+ return false;
+
+ rAny = uno::makeAny( nParagraphAdjust );
+ return true;
+}
+
+/*****************************************************************************/
+
+const gchar * font_strikethrough[] = {
+ "none", // FontStrikeout::NONE
+ "single", // FontStrikeout::SINGLE
+ "double", // FontStrikeout::DOUBLE
+ NULL, // FontStrikeout::DONTKNOW
+ "bold", // FontStrikeout::BOLD
+ "with /", // FontStrikeout::SLASH
+ "with X" // FontStrikeout::X
+};
+
+const sal_Int16 n_strikeout_constants = sizeof(font_strikethrough) / sizeof(gchar*);
+
+static gchar*
+Strikeout2String(const uno::Any& rAny)
+{
+ sal_Int16 n = rAny.get<sal_Int16>();
+
+ if( n >= 0 && n < n_strikeout_constants )
+ return g_strdup( font_strikethrough[n] );
+
+ return NULL;
+}
+
+static bool
+String2Strikeout( uno::Any& rAny, const gchar * value )
+{
+ for( sal_Int16 n=0; n < n_strikeout_constants; ++n )
+ {
+ if( ( NULL != font_strikethrough[n] ) &&
+ 0 == strncmp( value, font_strikethrough[n], strlen( font_strikethrough[n] ) ) )
+ {
+ rAny = uno::makeAny( n );
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/*****************************************************************************/
+
+static gchar*
+Underline2String(const uno::Any& rAny)
+{
+ const gchar * value = NULL;
+
+ switch( rAny.get<sal_Int16>() )
+ {
+ case awt::FontUnderline::NONE:
+ value = "none";
+ break;
+
+ case awt::FontUnderline::SINGLE:
+ value = "single";
+ break;
+
+ case awt::FontUnderline::DOUBLE:
+ value = "double";
+ break;
+
+ default:
+ break;
+ }
+
+ if( value )
+ return g_strdup( value );
+
+ return NULL;
+}
+
+static bool
+String2Underline( uno::Any& rAny, const gchar * value )
+{
+ short nUnderline;
+
+ if( strncmp( value, STRNCMP_PARAM( "none" ) ) )
+ nUnderline = awt::FontUnderline::NONE;
+ else if( strncmp( value, STRNCMP_PARAM( "single" ) ) )
+ nUnderline = awt::FontUnderline::SINGLE;
+ else if( strncmp( value, STRNCMP_PARAM( "double" ) ) )
+ nUnderline = awt::FontUnderline::DOUBLE;
+ else
+ return false;
+
+ rAny = uno::makeAny( nUnderline );
+ return true;
+}
+
+/*****************************************************************************/
+
+static gchar*
+GetString(const uno::Any& rAny)
+{
+ rtl::OString aFontName = rtl::OUStringToOString( rAny.get< rtl::OUString > (), RTL_TEXTENCODING_UTF8 );
+
+ if( aFontName.getLength() )
+ return g_strdup( aFontName.getStr() );
+
+ return NULL;
+}
+
+static bool
+SetString( uno::Any& rAny, const gchar * value )
+{
+ rtl::OString aFontName( value );
+
+ if( aFontName.getLength() )
+ {
+ rAny = uno::makeAny( rtl::OStringToOUString( aFontName, RTL_TEXTENCODING_UTF8 ) );
+ return true;
+ }
+
+ return false;
+}
+
+/*****************************************************************************/
+
+// @see http://developer.gnome.org/doc/API/2.0/atk/AtkText.html#AtkTextAttribute
+
+// CMM = 100th of mm
+static gchar*
+CMM2UnitString(const uno::Any& rAny)
+{
+ double fValue = rAny.get<sal_Int32>();
+ fValue = fValue * 0.01;
+
+ return g_strdup_printf( "%gmm", fValue );
+}
+
+static bool
+UnitString2CMM( uno::Any& rAny, const gchar * value )
+{
+ float fValue = 0.0; // pb: dont use double here because of warning on linux
+
+ if( 1 != sscanf( value, "%gmm", &fValue ) )
+ return false;
+
+ fValue = fValue * 100;
+
+ rAny = uno::makeAny( (sal_Int32) fValue);
+ return true;
+}
+
+/*****************************************************************************/
+
+static const gchar * bool_values[] = { "true", "false" };
+
+static gchar *
+Bool2String( const uno::Any& rAny )
+{
+ int n = 1;
+
+ if( rAny.get<sal_Bool>() )
+ n = 0;
+
+ return g_strdup( bool_values[n] );
+}
+
+static bool
+String2Bool( uno::Any& rAny, const gchar * value )
+{
+ sal_Bool bValue;
+
+ if( strncmp( value, STRNCMP_PARAM( "true" ) ) )
+ bValue = sal_True;
+ else if( strncmp( value, STRNCMP_PARAM( "false" ) ) )
+ bValue = sal_False;
+ else
+ return false;
+
+ rAny = uno::makeAny(bValue);
+ return true;
+}
+
+/*****************************************************************************/
+
+static gchar*
+Scale2String( const uno::Any& rAny )
+{
+ return g_strdup_printf( "%g", (double) (rAny.get< sal_Int16 > ()) / 100 );
+}
+
+static bool
+String2Scale( uno::Any& rAny, const gchar * value )
+{
+ double dval;
+
+ if( 1 != sscanf( value, "%lg", &dval ) )
+ return false;
+
+ rAny = uno::makeAny((sal_Int16) (dval * 100));
+ return true;
+}
+
+/*****************************************************************************/
+
+static gchar *
+CaseMap2String( const uno::Any& rAny )
+{
+ const gchar * value = NULL;
+
+ switch( rAny.get<short>() )
+ {
+ case style::CaseMap::SMALLCAPS:
+ value = "small_caps";
+ break;
+
+ default:
+ value = "normal";
+ break;
+ }
+
+ if( value )
+ return g_strdup( value );
+
+ return NULL;
+}
+
+static bool
+String2CaseMap( uno::Any& rAny, const gchar * value )
+{
+ short nCaseMap;
+
+ if( strncmp( value, STRNCMP_PARAM( "normal" ) ) )
+ nCaseMap = style::CaseMap::NONE;
+ else if( strncmp( value, STRNCMP_PARAM( "small_caps" ) ) )
+ nCaseMap = style::CaseMap::SMALLCAPS;
+ else
+ return false;
+
+ rAny = uno::makeAny( nCaseMap );
+ return true;
+}
+
+/*****************************************************************************/
+
+const gchar * font_stretch[] = {
+ "ultra_condensed",
+ "extra_condensed",
+ "condensed",
+ "semi_condensed",
+ "normal",
+ "semi_expanded",
+ "expanded",
+ "extra_expanded",
+ "ultra_expanded"
+};
+
+static gchar*
+Kerning2Stretch(const uno::Any& rAny)
+{
+ sal_Int16 n = rAny.get<sal_Int16>();
+ int i = 4;
+
+ // No good idea for a mapping - just return the basic info
+ if( n < 0 )
+ i=2;
+ else if( n > 0 )
+ i=6;
+
+ return g_strdup(font_stretch[i]);
+}
+
+/*****************************************************************************/
+
+static gchar*
+Locale2String(const uno::Any& rAny)
+{
+ lang::Locale aLocale = rAny.get<lang::Locale> ();
+ return g_strdup_printf( "%s-%s",
+ rtl::OUStringToOString( aLocale.Language, RTL_TEXTENCODING_ASCII_US).getStr(),
+ rtl::OUStringToOString( aLocale.Country, RTL_TEXTENCODING_ASCII_US).toAsciiLowerCase().getStr() );
+}
+
+static bool
+String2Locale( uno::Any& rAny, const gchar * value )
+{
+ bool ret = false;
+
+ gchar ** str_array = g_strsplit_set( value, "-.@", -1 );
+ if( str_array[0] != NULL )
+ {
+ ret = true;
+
+ lang::Locale aLocale;
+
+ aLocale.Language = rtl::OUString::createFromAscii(str_array[0]);
+ if( str_array[1] != NULL )
+ {
+ gchar * country = g_ascii_strup(str_array[1], -1);
+ aLocale.Country = rtl::OUString::createFromAscii(country);
+ g_free(country);
+ }
+
+ rAny = uno::makeAny(aLocale);
+ }
+
+ g_strfreev(str_array);
+ return ret;
+}
+
+/*****************************************************************************/
+
+// @see http://www.w3.org/TR/2002/WD-css3-fonts-20020802/#font-effect-prop
+static const gchar * relief[] = { "none", "emboss", "engrave" };
+static const gchar * outline = "outline";
+
+static gchar *
+get_font_effect(const uno::Sequence< beans::PropertyValue >& rAttributeList,
+ sal_Int32 nContourIndex, sal_Int32 nReliefIndex)
+{
+ if( nContourIndex != -1 )
+ {
+ if( rAttributeList[nContourIndex].Value.get<sal_Bool>() )
+ return g_strdup(outline);
+ }
+
+ if( nReliefIndex != -1 )
+ {
+ sal_Int16 n = rAttributeList[nReliefIndex].Value.get<sal_Int16>();
+ if( n < 3)
+ return g_strdup(relief[n]);
+ }
+
+ return NULL;
+}
+
+/*****************************************************************************/
+
+// @see http://www.w3.org/TR/REC-CSS2/text.html#lining-striking-props
+
+
+enum
+{
+ DECORATION_NONE = 0,
+ DECORATION_BLINK,
+ DECORATION_UNDERLINE,
+ DECORATION_LINE_THROUGH
+};
+
+
+static const gchar * decorations[] = { "none", "blink", "underline", "line-through" };
+
+static gchar *
+get_text_decoration(const uno::Sequence< beans::PropertyValue >& rAttributeList,
+ sal_Int32 nBlinkIndex, sal_Int32 nUnderlineIndex,
+ sal_Int16 nStrikeoutIndex)
+{
+ gchar * value_list[4] = { NULL, NULL, NULL, NULL };
+ gint count = 0;
+
+ // no property value found
+ if( ( nBlinkIndex == -1 ) && (nUnderlineIndex == -1 ) && (nStrikeoutIndex == -1))
+ return NULL;
+
+ if( nBlinkIndex != -1 )
+ {
+ if( rAttributeList[nBlinkIndex].Value.get<sal_Bool>() )
+ value_list[count++] = const_cast <gchar *> (decorations[DECORATION_BLINK]);
+ }
+ if( nUnderlineIndex != -1 )
+ {
+ sal_Int16 n = rAttributeList[nUnderlineIndex].Value.get<sal_Int16> ();
+ if( n != awt::FontUnderline::NONE )
+ value_list[count++] = const_cast <gchar *> (decorations[DECORATION_UNDERLINE]);
+ }
+ if( nStrikeoutIndex != -1 )
+ {
+ sal_Int16 n = rAttributeList[nStrikeoutIndex].Value.get<sal_Int16> ();
+ if( n != awt::FontStrikeout::NONE && n != awt::FontStrikeout::DONTKNOW )
+ value_list[count++] = const_cast <gchar *> (decorations[DECORATION_LINE_THROUGH]);
+ }
+
+ if( count == 0 )
+ value_list[count++] = const_cast <gchar *> (decorations[DECORATION_NONE]);
+
+ return g_strjoinv(" ", value_list);
+}
+
+
+/*****************************************************************************/
+
+// @see http://www.w3.org/TR/REC-CSS2/text.html#propdef-text-shadow
+
+static const gchar * shadow_values[] = { "none", "black" };
+
+static gchar *
+Bool2Shadow( const uno::Any& rAny )
+{
+ int n = 0;
+
+ if( rAny.get<sal_Bool>() )
+ n = 1;
+
+ return g_strdup( shadow_values[n] );
+}
+
+/*****************************************************************************/
+
+static gchar *
+Short2Degree( const uno::Any& rAny )
+{
+ float f = rAny.get<sal_Int16>() / 10;
+ return g_strdup_printf( "%g", f );
+}
+
+/*****************************************************************************/
+
+const gchar * directions[] = { "ltr", "rtl", "rtl", "ltr", "none" };
+
+static gchar *
+WritingMode2Direction( const uno::Any& rAny )
+{
+ sal_Int16 n = rAny.get<sal_Int16>();
+
+ if( 0 <= n && n <= text::WritingMode2::PAGE )
+ return g_strdup(directions[n]);
+
+ return NULL;
+}
+
+// @see http://www.w3.org/TR/2001/WD-css3-text-20010517/#PrimaryTextAdvanceDirection
+
+const gchar * writing_modes[] = { "lr-tb", "rl-tb", "tb-rl", "tb-lr", "none" };
+static gchar *
+WritingMode2String( const uno::Any& rAny )
+{
+ sal_Int16 n = rAny.get<sal_Int16>();
+
+ if( 0 <= n && n <= text::WritingMode2::PAGE )
+ return g_strdup(writing_modes[n]);
+
+ return NULL;
+}
+
+/*****************************************************************************/
+
+const char * baseline_values[] = { "baseline", "sub", "super" };
+
+// @see http://www.w3.org/TR/REC-CSS2/visudet.html#propdef-vertical-align
+static gchar *
+Escapement2VerticalAlign( const uno::Any& rAny )
+{
+ sal_Int16 n = rAny.get<sal_Int16>();
+ gchar * ret = NULL;
+
+ // Values are in %, 101% means "automatic"
+ if( n == 0 )
+ ret = g_strdup(baseline_values[0]);
+ else if( n == 101 )
+ ret = g_strdup(baseline_values[2]);
+ else if( n == -101 )
+ ret = g_strdup(baseline_values[1]);
+ else
+ ret = g_strdup_printf( "%d%%", n );
+
+ return ret;
+}
+
+/*****************************************************************************/
+
+// @see http://www.w3.org/TR/REC-CSS2/visudet.html#propdef-line-height
+static gchar *
+LineSpacing2LineHeight( const uno::Any& rAny )
+{
+ style::LineSpacing ls;
+ gchar * ret = NULL;
+
+ if( rAny >>= ls )
+ {
+ if( ls.Mode == style::LineSpacingMode::PROP )
+ ret = g_strdup_printf( "%d%%", ls.Height );
+ else if( ls.Mode == style::LineSpacingMode::FIX )
+ ret = g_strdup_printf( "%.3gpt", toPoint(ls.Height) );
+ }
+
+ return ret;
+}
+
+/*****************************************************************************/
+
+// @see http://www.w3.org/People/howcome/t/970224HTMLERB-CSS/WD-tabs-970117.html
+static gchar *
+TabStopList2String( const uno::Any& rAny, bool default_tabs )
+{
+ uno::Sequence< style::TabStop > theTabStops;
+ gchar * ret = NULL;
+
+ if( rAny >>= theTabStops)
+ {
+ sal_Int32 indexOfTab = 0;
+ sal_Int32 numberOfTabs = theTabStops.getLength();
+ sal_Unicode lastFillChar = (sal_Unicode) ' ';
+
+ for( ; indexOfTab < numberOfTabs; ++indexOfTab )
+ {
+ bool is_default_tab = (style::TabAlign_DEFAULT == theTabStops[indexOfTab].Alignment);
+
+ if( is_default_tab != default_tabs )
+ continue;
+
+ double fValue = theTabStops[indexOfTab].Position;
+ fValue = fValue * 0.01;
+
+ const gchar * tab_align = "";
+ switch( theTabStops[indexOfTab].Alignment )
+ {
+ case style::TabAlign_LEFT :
+ tab_align = "left ";
+ break;
+ case style::TabAlign_CENTER :
+ tab_align = "center ";
+ break;
+ case style::TabAlign_RIGHT :
+ tab_align = "right ";
+ break;
+ case style::TabAlign_DECIMAL :
+ tab_align = "decimal ";
+ break;
+ default:
+ break;
+ }
+
+ const gchar * lead_char = "";
+
+ if( theTabStops[indexOfTab].FillChar != lastFillChar )
+ {
+ lastFillChar = theTabStops[indexOfTab].FillChar;
+ switch (lastFillChar)
+ {
+ case (sal_Unicode) ' ':
+ lead_char = "blank ";
+ break;
+
+ case (sal_Unicode) '.':
+ lead_char = "dotted ";
+ break;
+
+ case (sal_Unicode) '-':
+ lead_char = "dashed ";
+ break;
+
+ case (sal_Unicode) '_':
+ lead_char = "lined ";
+ break;
+
+ default:
+ lead_char = "custom ";
+ break;
+ }
+ }
+
+ gchar * tab_str = g_strdup_printf( "%s%s%gmm", lead_char, tab_align, fValue );
+
+ if( ret )
+ {
+ gchar * old_tab_str = ret;
+ ret = g_strconcat(old_tab_str, " ", tab_str, NULL /* terminated */);
+ g_free( old_tab_str );
+ }
+ else
+ ret = tab_str;
+ }
+ }
+
+ return ret;
+}
+
+static gchar *
+TabStops2String( const uno::Any& rAny )
+{
+ return TabStopList2String(rAny, false);
+}
+
+static gchar *
+DefaultTabStops2String( const uno::Any& rAny )
+{
+ return TabStopList2String(rAny, true);
+}
+
+/*****************************************************************************/
+
+extern "C" int
+attr_compare(const void *p1,const void *p2)
+{
+ const rtl_uString * pustr = (const rtl_uString *) p1;
+ const char * pc = *((const char **) p2);
+
+ return rtl_ustr_ascii_compare_WithLength(pustr->buffer, pustr->length, pc);
+}
+
+static void
+find_exported_attributes( sal_Int32 *pArray,
+ const com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue >& rAttributeList )
+{
+ for( sal_Int32 i = 0; i < rAttributeList.getLength(); i++ )
+ {
+ const char ** pAttr = (const char **) bsearch(rAttributeList[i].Name.pData,
+ ExportedTextAttributes, TEXT_ATTRIBUTE_LAST, sizeof(const char *),
+ attr_compare);
+
+ if( pAttr )
+ {
+ sal_Int32 nIndex = pAttr - ExportedTextAttributes;
+ pArray[nIndex] = i;
+ }
+ }
+}
+
+/*****************************************************************************/
+
+static AtkAttributeSet*
+attribute_set_prepend( AtkAttributeSet* attribute_set,
+ AtkTextAttribute attribute,
+ gchar * value )
+{
+ if( value )
+ {
+ AtkAttribute *at = (AtkAttribute *) g_malloc( sizeof (AtkAttribute) );
+ at->name = g_strdup( atk_text_attribute_get_name( attribute ) );
+ at->value = value;
+
+ return g_slist_prepend(attribute_set, at);
+ }
+
+ return attribute_set;
+}
+
+/*****************************************************************************/
+
+AtkAttributeSet*
+attribute_set_new_from_property_values(
+ const uno::Sequence< beans::PropertyValue >& rAttributeList,
+ bool run_attributes_only,
+ AtkText *text)
+{
+ AtkAttributeSet* attribute_set = NULL;
+
+ sal_Int32 aIndexList[TEXT_ATTRIBUTE_LAST] = { -1 };
+
+ // Initialize index array with -1
+ for( sal_Int32 attr = 0; attr < TEXT_ATTRIBUTE_LAST; ++attr )
+ aIndexList[attr] = -1;
+
+ find_exported_attributes(aIndexList, rAttributeList);
+
+ attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_BG_COLOR,
+ get_color_value(rAttributeList, aIndexList, TEXT_ATTRIBUTE_BACKGROUND_COLOR, run_attributes_only ? NULL : text ) );
+
+ attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_FG_COLOR,
+ get_color_value(rAttributeList, aIndexList, TEXT_ATTRIBUTE_FOREGROUND_COLOR, run_attributes_only ? NULL : text) );
+
+ attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_INVISIBLE,
+ get_bool_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_HIDDEN]));
+
+ attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_UNDERLINE,
+ get_underline_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_UNDERLINE]));
+
+ attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_STRIKETHROUGH,
+ get_strikethrough_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_STRIKETHROUGH]));
+
+ attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_SIZE,
+ get_height_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_HEIGHT]));
+
+ attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_WEIGHT,
+ get_weight_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_WEIGHT]));
+
+ attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_FAMILY_NAME,
+ get_string_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_FONT_NAME]));
+
+ attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_VARIANT,
+ get_variant_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_CASEMAP]));
+
+ attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_STYLE,
+ get_style_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_POSTURE]));
+
+ attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_SCALE,
+ get_scale_width(rAttributeList, aIndexList[TEXT_ATTRIBUTE_SCALE]));
+
+ attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_LANGUAGE,
+ get_language_string(rAttributeList, aIndexList[TEXT_ATTRIBUTE_LOCALE]));
+
+ attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_DIRECTION,
+ get_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_WRITING_MODE], WritingMode2Direction));
+
+ attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_STRETCH,
+ get_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_KERNING], Kerning2Stretch));
+
+ if( ATK_TEXT_ATTR_INVALID == atk_text_attribute_font_effect )
+ atk_text_attribute_font_effect = atk_text_attribute_register("font-effect");
+
+ attribute_set = attribute_set_prepend(attribute_set, atk_text_attribute_font_effect,
+ get_font_effect(rAttributeList, aIndexList[TEXT_ATTRIBUTE_CONTOURED], aIndexList[TEXT_ATTRIBUTE_RELIEF]));
+
+ if( ATK_TEXT_ATTR_INVALID == atk_text_attribute_decoration )
+ atk_text_attribute_decoration = atk_text_attribute_register("text-decoration");
+
+ attribute_set = attribute_set_prepend(attribute_set, atk_text_attribute_decoration,
+ get_text_decoration(rAttributeList, aIndexList[TEXT_ATTRIBUTE_BLINKING],
+ aIndexList[TEXT_ATTRIBUTE_UNDERLINE], aIndexList[TEXT_ATTRIBUTE_STRIKETHROUGH]));
+
+ if( ATK_TEXT_ATTR_INVALID == atk_text_attribute_rotation )
+ atk_text_attribute_rotation = atk_text_attribute_register("text-rotation");
+
+ attribute_set = attribute_set_prepend(attribute_set, atk_text_attribute_rotation,
+ get_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_ROTATION], Short2Degree));
+
+ if( ATK_TEXT_ATTR_INVALID == atk_text_attribute_shadow )
+ atk_text_attribute_shadow = atk_text_attribute_register("text-shadow");
+
+ attribute_set = attribute_set_prepend(attribute_set, atk_text_attribute_shadow,
+ get_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_SHADOWED], Bool2Shadow));
+
+ if( ATK_TEXT_ATTR_INVALID == atk_text_attribute_writing_mode )
+ atk_text_attribute_writing_mode = atk_text_attribute_register("writing-mode");
+
+ attribute_set = attribute_set_prepend(attribute_set, atk_text_attribute_writing_mode,
+ get_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_WRITING_MODE], WritingMode2String));
+
+ if( ATK_TEXT_ATTR_INVALID == atk_text_attribute_vertical_align )
+ atk_text_attribute_vertical_align = atk_text_attribute_register("vertical-align");
+
+ attribute_set = attribute_set_prepend(attribute_set, atk_text_attribute_vertical_align,
+ get_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_CHAR_ESCAPEMENT], Escapement2VerticalAlign));
+
+ if( run_attributes_only )
+ return attribute_set;
+
+ attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_LEFT_MARGIN,
+ get_cmm_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_LEFT_MARGIN]));
+
+ attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_RIGHT_MARGIN,
+ get_cmm_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_RIGHT_MARGIN]));
+
+ attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_INDENT,
+ get_cmm_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_FIRST_LINE_INDENT]));
+
+ attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_PIXELS_ABOVE_LINES,
+ get_cmm_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_TOP_MARGIN]));
+
+ attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_PIXELS_BELOW_LINES,
+ get_cmm_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_BOTTOM_MARGIN]));
+
+ attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_JUSTIFICATION,
+ get_justification_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_JUSTIFICATION]));
+
+ if( ATK_TEXT_ATTR_INVALID == atk_text_attribute_paragraph_style )
+ atk_text_attribute_paragraph_style = atk_text_attribute_register("paragraph-style");
+
+ attribute_set = attribute_set_prepend(attribute_set, atk_text_attribute_paragraph_style,
+ get_string_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_STYLE_NAME]));
+
+ if( ATK_TEXT_ATTR_INVALID == atk_text_attribute_line_height )
+ atk_text_attribute_line_height = atk_text_attribute_register("line-height");
+
+ attribute_set = attribute_set_prepend(attribute_set, atk_text_attribute_line_height,
+ get_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_LINE_SPACING], LineSpacing2LineHeight));
+
+ if( ATK_TEXT_ATTR_INVALID == atk_text_attribute_tab_interval )
+ atk_text_attribute_tab_interval = atk_text_attribute_register("tab-interval");
+
+ attribute_set = attribute_set_prepend(attribute_set, atk_text_attribute_tab_interval,
+ get_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_TAB_STOPS], DefaultTabStops2String));
+
+ if( ATK_TEXT_ATTR_INVALID == atk_text_attribute_tab_stops )
+ atk_text_attribute_tab_stops = atk_text_attribute_register("tab-stops");
+
+ attribute_set = attribute_set_prepend(attribute_set, atk_text_attribute_tab_stops,
+ get_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_TAB_STOPS], TabStops2String));
+
+ // --> OD 2010-03-05 #i92233#
+ if( ATK_TEXT_ATTR_INVALID == atk_text_attribute_mm_to_pixel_ratio )
+ atk_text_attribute_mm_to_pixel_ratio = atk_text_attribute_register("mm-to-pixel-ratio");
+
+ attribute_set = attribute_set_prepend( attribute_set, atk_text_attribute_mm_to_pixel_ratio,
+ get_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_MM_TO_PIXEL_RATIO], Float2String));
+ // <--
+
+ return attribute_set;
+}
+
+
+AtkAttributeSet* attribute_set_prepend_misspelled( AtkAttributeSet* attribute_set )
+{
+ if( ATK_TEXT_ATTR_INVALID == atk_text_attribute_misspelled )
+ atk_text_attribute_misspelled = atk_text_attribute_register( "text-spelling" );
+
+ attribute_set = attribute_set_prepend( attribute_set, atk_text_attribute_misspelled,
+ g_strdup_printf( "misspelled" ) );
+
+ return attribute_set;
+}
+
+// --> OD 2010-03-01 #i92232#
+AtkAttributeSet* attribute_set_prepend_tracked_change_insertion( AtkAttributeSet* attribute_set )
+{
+ if ( ATK_TEXT_ATTR_INVALID == atk_text_attribute_tracked_change )
+ {
+ atk_text_attribute_tracked_change = atk_text_attribute_register( "text-tracked-change" );
+ }
+
+ attribute_set = attribute_set_prepend( attribute_set,
+ atk_text_attribute_tracked_change,
+ g_strdup_printf( "insertion" ) );
+
+ return attribute_set;
+}
+
+AtkAttributeSet* attribute_set_prepend_tracked_change_deletion( AtkAttributeSet* attribute_set )
+{
+ if ( ATK_TEXT_ATTR_INVALID == atk_text_attribute_tracked_change )
+ {
+ atk_text_attribute_tracked_change = atk_text_attribute_register( "text-tracked-change" );
+ }
+
+ attribute_set = attribute_set_prepend( attribute_set,
+ atk_text_attribute_tracked_change,
+ g_strdup_printf( "deletion" ) );
+
+ return attribute_set;
+}
+
+AtkAttributeSet* attribute_set_prepend_tracked_change_formatchange( AtkAttributeSet* attribute_set )
+{
+ if ( ATK_TEXT_ATTR_INVALID == atk_text_attribute_tracked_change )
+ {
+ atk_text_attribute_tracked_change = atk_text_attribute_register( "text-tracked-change" );
+ }
+
+ attribute_set = attribute_set_prepend( attribute_set,
+ atk_text_attribute_tracked_change,
+ g_strdup_printf( "attribute-change" ) );
+
+ return attribute_set;
+}
+// <--
+
+/*****************************************************************************/
+
+struct AtkTextAttrMapping
+{
+ const char * name;
+ TextPropertyValueFunc toPropertyValue;
+};
+
+const AtkTextAttrMapping g_TextAttrMap[] =
+{
+ { "", InvalidValue }, // ATK_TEXT_ATTR_INVALID = 0
+ { "ParaLeftMargin", UnitString2CMM }, // ATK_TEXT_ATTR_LEFT_MARGIN
+ { "ParaRightMargin", UnitString2CMM }, // ATK_TEXT_ATTR_RIGHT_MARGIN
+ { "ParaFirstLineIndent", UnitString2CMM }, // ATK_TEXT_ATTR_INDENT
+ { "CharHidden", String2Bool }, // ATK_TEXT_ATTR_INVISIBLE
+ { "", InvalidValue }, // ATK_TEXT_ATTR_EDITABLE
+ { "ParaTopMargin", UnitString2CMM }, // ATK_TEXT_ATTR_PIXELS_ABOVE_LINES
+ { "ParaBottomMargin", UnitString2CMM }, // ATK_TEXT_ATTR_PIXELS_BELOW_LINES
+ { "", InvalidValue }, // ATK_TEXT_ATTR_PIXELS_INSIDE_WRAP
+ { "", InvalidValue }, // ATK_TEXT_ATTR_BG_FULL_HEIGHT
+ { "", InvalidValue }, // ATK_TEXT_ATTR_RISE
+ { "CharUnderline", String2Underline }, // ATK_TEXT_ATTR_UNDERLINE
+ { "CharStrikeout", String2Strikeout }, // ATK_TEXT_ATTR_STRIKETHROUGH
+ { "CharHeight", String2Float }, // ATK_TEXT_ATTR_SIZE
+ { "CharScaleWidth", String2Scale }, // ATK_TEXT_ATTR_SCALE
+ { "CharWeight", String2Weight }, // ATK_TEXT_ATTR_WEIGHT
+ { "CharLocale", String2Locale }, // ATK_TEXT_ATTR_LANGUAGE
+ { "CharFontName", SetString }, // ATK_TEXT_ATTR_FAMILY_NAME
+ { "CharBackColor", String2Color }, // ATK_TEXT_ATTR_BG_COLOR
+ { "CharColor", String2Color }, // ATK_TEXT_ATTR_FG_COLOR
+ { "", InvalidValue }, // ATK_TEXT_ATTR_BG_STIPPLE
+ { "", InvalidValue }, // ATK_TEXT_ATTR_FG_STIPPLE
+ { "", InvalidValue }, // ATK_TEXT_ATTR_WRAP_MODE
+ { "", InvalidValue }, // ATK_TEXT_ATTR_DIRECTION
+ { "ParaAdjust", Justification2Adjust }, // ATK_TEXT_ATTR_JUSTIFICATION
+ { "", InvalidValue }, // ATK_TEXT_ATTR_STRETCH
+ { "CharCaseMap", String2CaseMap }, // ATK_TEXT_ATTR_VARIANT
+ { "CharPosture", Style2FontSlant } // ATK_TEXT_ATTR_STYLE
+};
+
+static const sal_Int32 g_TextAttrMapSize = sizeof( g_TextAttrMap ) / sizeof( AtkTextAttrMapping );
+
+/*****************************************************************************/
+
+bool
+attribute_set_map_to_property_values(
+ AtkAttributeSet* attribute_set,
+ uno::Sequence< beans::PropertyValue >& rValueList )
+{
+ // Ensure enough space ..
+ uno::Sequence< beans::PropertyValue > aAttributeList (g_TextAttrMapSize);
+
+ sal_Int32 nIndex = 0;
+ for( GSList * item = attribute_set; item != NULL; item = g_slist_next( item ) )
+ {
+ AtkAttribute* attribute = (AtkAttribute *) item;
+
+ AtkTextAttribute text_attr = atk_text_attribute_for_name( attribute->name );
+ if( text_attr < g_TextAttrMapSize )
+ {
+ if( g_TextAttrMap[text_attr].name[0] != '\0' )
+ {
+ if( ! g_TextAttrMap[text_attr].toPropertyValue( aAttributeList[nIndex].Value, attribute->value) )
+ return false;
+
+ aAttributeList[nIndex].Name = rtl::OUString::createFromAscii( g_TextAttrMap[text_attr].name );
+ aAttributeList[nIndex].State = beans::PropertyState_DIRECT_VALUE;
+ ++nIndex;
+ }
+ }
+ else
+ {
+ // Unsupported text attribute
+ return false;
+ }
+ }
+
+ aAttributeList.realloc( nIndex );
+ rValueList = aAttributeList;
+ return true;
+}
+
diff --git a/vcl/unx/gtk/a11y/atktextattributes.hxx b/vcl/unx/gtk/a11y/atktextattributes.hxx
new file mode 100644
index 000000000000..9c7628bf927e
--- /dev/null
+++ b/vcl/unx/gtk/a11y/atktextattributes.hxx
@@ -0,0 +1,54 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef __ATK_ATKTEXTATTRIBUTES_HXX__
+#define __ATK_ATKTEXTATTRIBUTES_HXX__
+
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/beans/PropertyValue.hpp>
+
+#include <atk/atk.h>
+
+AtkAttributeSet*
+attribute_set_new_from_property_values(
+ const com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue >& rAttributeList,
+ bool run_attributes_only,
+ AtkText *text);
+
+bool
+attribute_set_map_to_property_values(
+ AtkAttributeSet* attribute_set,
+ com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue >& rValueList );
+
+AtkAttributeSet* attribute_set_prepend_misspelled( AtkAttributeSet* attribute_set );
+// --> OD 2010-03-01 #i92232#
+AtkAttributeSet* attribute_set_prepend_tracked_change_insertion( AtkAttributeSet* attribute_set );
+AtkAttributeSet* attribute_set_prepend_tracked_change_deletion( AtkAttributeSet* attribute_set );
+AtkAttributeSet* attribute_set_prepend_tracked_change_formatchange( AtkAttributeSet* attribute_set );
+// <--
+
+#endif
diff --git a/vcl/unx/gtk/a11y/atkutil.cxx b/vcl/unx/gtk/a11y/atkutil.cxx
new file mode 100644
index 000000000000..076e36291ae6
--- /dev/null
+++ b/vcl/unx/gtk/a11y/atkutil.cxx
@@ -0,0 +1,801 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <com/sun/star/accessibility/XAccessibleContext.hpp>
+#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp>
+#include <com/sun/star/accessibility/XAccessibleSelection.hpp>
+#include <com/sun/star/accessibility/AccessibleEventId.hpp>
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+// --> OD 2009-04-14 #i93269#
+#include <com/sun/star/accessibility/XAccessibleText.hpp>
+// <--
+#include <cppuhelper/implbase1.hxx>
+#include <vos/mutex.hxx>
+#include <rtl/ref.hxx>
+
+#include <vcl/svapp.hxx>
+#include <vcl/window.hxx>
+#include <vcl/menu.hxx>
+#include <vcl/toolbox.hxx>
+
+#include "atkwrapper.hxx"
+#include "atkutil.hxx"
+
+#include <gtk/gtk.h>
+
+#include <set>
+
+// #define ENABLE_TRACING
+
+#ifdef ENABLE_TRACING
+#include <stdio.h>
+#endif
+
+using namespace ::com::sun::star;
+
+static uno::WeakReference< accessibility::XAccessible > xNextFocusObject;
+static guint focus_notify_handler = 0;
+
+/*****************************************************************************/
+
+extern "C" {
+
+static gint
+atk_wrapper_focus_idle_handler (gpointer data)
+{
+ vos::OGuard aGuard( Application::GetSolarMutex() );
+
+ focus_notify_handler = 0;
+
+ uno::Reference< accessibility::XAccessible > xAccessible = xNextFocusObject;
+ if( xAccessible.get() == reinterpret_cast < accessibility::XAccessible * > (data) )
+ {
+ AtkObject *atk_obj = xAccessible.is() ? atk_object_wrapper_ref( xAccessible ) : NULL;
+ // Gail does not notify focus changes to NULL, so do we ..
+ if( atk_obj )
+ {
+#ifdef ENABLE_TRACING
+ fprintf(stderr, "notifying focus event for %p\n", atk_obj);
+#endif
+ atk_focus_tracker_notify(atk_obj);
+ // --> OD 2009-04-14 #i93269#
+ // emit text_caret_moved event for <XAccessibleText> object,
+ // if cursor is inside the <XAccessibleText> object.
+ // also emit state-changed:focused event under the same condition.
+ {
+ AtkObjectWrapper* wrapper_obj = ATK_OBJECT_WRAPPER (atk_obj);
+ if( wrapper_obj && !wrapper_obj->mpText && wrapper_obj->mpContext )
+ {
+ uno::Any any = wrapper_obj->mpContext->queryInterface( accessibility::XAccessibleText::static_type(NULL) );
+ if ( typelib_TypeClass_INTERFACE == any.pType->eTypeClass &&
+ any.pReserved != 0 )
+ {
+ wrapper_obj->mpText = reinterpret_cast< accessibility::XAccessibleText * > (any.pReserved);
+ if ( wrapper_obj->mpText != 0 )
+ {
+ wrapper_obj->mpText->acquire();
+ gint caretPos = wrapper_obj->mpText->getCaretPosition();
+
+ if ( caretPos != -1 )
+ {
+ atk_object_notify_state_change( atk_obj, ATK_STATE_FOCUSED, TRUE );
+ g_signal_emit_by_name( atk_obj, "text_caret_moved", caretPos );
+ }
+ }
+ }
+ }
+ }
+ // <--
+ g_object_unref(atk_obj);
+ }
+ }
+
+ return FALSE;
+}
+
+} // extern "C"
+
+/*****************************************************************************/
+
+static void
+atk_wrapper_focus_tracker_notify_when_idle( const uno::Reference< accessibility::XAccessible > &xAccessible )
+{
+ if( focus_notify_handler )
+ g_source_remove(focus_notify_handler);
+
+ xNextFocusObject = xAccessible;
+
+ focus_notify_handler = g_idle_add (atk_wrapper_focus_idle_handler, xAccessible.get());
+}
+
+/*****************************************************************************/
+
+class DocumentFocusListener :
+ public ::cppu::WeakImplHelper1< accessibility::XAccessibleEventListener >
+{
+
+ std::set< uno::Reference< uno::XInterface > > m_aRefList;
+
+public:
+ void attachRecursive(
+ const uno::Reference< accessibility::XAccessible >& xAccessible
+ ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException);
+
+ void attachRecursive(
+ const uno::Reference< accessibility::XAccessible >& xAccessible,
+ const uno::Reference< accessibility::XAccessibleContext >& xContext
+ ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException);
+
+ void attachRecursive(
+ const uno::Reference< accessibility::XAccessible >& xAccessible,
+ const uno::Reference< accessibility::XAccessibleContext >& xContext,
+ const uno::Reference< accessibility::XAccessibleStateSet >& xStateSet
+ ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException);
+
+ void detachRecursive(
+ const uno::Reference< accessibility::XAccessible >& xAccessible
+ ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException);
+
+ void detachRecursive(
+ const uno::Reference< accessibility::XAccessible >& xAccessible,
+ const uno::Reference< accessibility::XAccessibleContext >& xContext
+ ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException);
+
+ void detachRecursive(
+ const uno::Reference< accessibility::XAccessible >& xAccessible,
+ const uno::Reference< accessibility::XAccessibleContext >& xContext,
+ const uno::Reference< accessibility::XAccessibleStateSet >& xStateSet
+ ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException);
+
+ static uno::Reference< accessibility::XAccessible > getAccessible(const lang::EventObject& aEvent )
+ throw (lang::IndexOutOfBoundsException, uno::RuntimeException);
+
+ // XEventListener
+ virtual void disposing( const lang::EventObject& Source ) throw (uno::RuntimeException);
+
+ // XAccessibleEventListener
+ virtual void notifyEvent( const accessibility::AccessibleEventObject& aEvent ) throw( uno::RuntimeException );
+};
+
+/*****************************************************************************/
+
+void DocumentFocusListener::disposing( const lang::EventObject& aEvent )
+ throw (uno::RuntimeException)
+{
+// fprintf(stderr, "In DocumentFocusListener::disposing (%p)\n", this);
+// fprintf(stderr, "m_aRefList has %d entries\n", m_aRefList.size());
+
+ // Unref the object here, but do not remove as listener since the object
+ // might no longer be in a state that safely allows this.
+ if( aEvent.Source.is() )
+ m_aRefList.erase(aEvent.Source);
+
+// fprintf(stderr, "m_aRefList has %d entries\n", m_aRefList.size());
+
+}
+
+/*****************************************************************************/
+
+void DocumentFocusListener::notifyEvent( const accessibility::AccessibleEventObject& aEvent )
+ throw( uno::RuntimeException )
+{
+ switch( aEvent.EventId )
+ {
+ case accessibility::AccessibleEventId::STATE_CHANGED:
+ try
+ {
+ sal_Int16 nState = accessibility::AccessibleStateType::INVALID;
+ aEvent.NewValue >>= nState;
+
+ if( accessibility::AccessibleStateType::FOCUSED == nState )
+ atk_wrapper_focus_tracker_notify_when_idle( getAccessible(aEvent) );
+ }
+ catch(const lang::IndexOutOfBoundsException &e)
+ {
+ g_warning("Focused object has invalid index in parent");
+ }
+ break;
+
+ case accessibility::AccessibleEventId::CHILD:
+ {
+ uno::Reference< accessibility::XAccessible > xChild;
+ if( (aEvent.OldValue >>= xChild) && xChild.is() )
+ detachRecursive(xChild);
+
+ if( (aEvent.NewValue >>= xChild) && xChild.is() )
+ attachRecursive(xChild);
+ }
+ break;
+
+ case accessibility::AccessibleEventId::INVALIDATE_ALL_CHILDREN:
+/* {
+ uno::Reference< accessibility::XAccessible > xAccessible( getAccessible(aEvent) );
+ detachRecursive(xAccessible);
+ attachRecursive(xAccessible);
+ }
+*/
+ g_warning( "Invalidate all children called\n" );
+ break;
+ default:
+ break;
+ }
+}
+
+/*****************************************************************************/
+
+uno::Reference< accessibility::XAccessible > DocumentFocusListener::getAccessible(const lang::EventObject& aEvent )
+ throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
+{
+ uno::Reference< accessibility::XAccessible > xAccessible(aEvent.Source, uno::UNO_QUERY);
+
+ if( xAccessible.is() )
+ return xAccessible;
+
+ uno::Reference< accessibility::XAccessibleContext > xContext(aEvent.Source, uno::UNO_QUERY);
+
+ if( xContext.is() )
+ {
+ uno::Reference< accessibility::XAccessible > xParent( xContext->getAccessibleParent() );
+ if( xParent.is() )
+ {
+ uno::Reference< accessibility::XAccessibleContext > xParentContext( xParent->getAccessibleContext() );
+ if( xParentContext.is() )
+ {
+ return xParentContext->getAccessibleChild( xContext->getAccessibleIndexInParent() );
+ }
+ }
+ }
+
+ return uno::Reference< accessibility::XAccessible >();
+}
+
+/*****************************************************************************/
+
+void DocumentFocusListener::attachRecursive(
+ const uno::Reference< accessibility::XAccessible >& xAccessible
+) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
+{
+ uno::Reference< accessibility::XAccessibleContext > xContext =
+ xAccessible->getAccessibleContext();
+
+ if( xContext.is() )
+ attachRecursive(xAccessible, xContext);
+}
+
+/*****************************************************************************/
+
+void DocumentFocusListener::attachRecursive(
+ const uno::Reference< accessibility::XAccessible >& xAccessible,
+ const uno::Reference< accessibility::XAccessibleContext >& xContext
+) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
+{
+ uno::Reference< accessibility::XAccessibleStateSet > xStateSet =
+ xContext->getAccessibleStateSet();
+
+ if( xStateSet.is() )
+ attachRecursive(xAccessible, xContext, xStateSet);
+}
+
+/*****************************************************************************/
+
+void DocumentFocusListener::attachRecursive(
+ const uno::Reference< accessibility::XAccessible >& xAccessible,
+ const uno::Reference< accessibility::XAccessibleContext >& xContext,
+ const uno::Reference< accessibility::XAccessibleStateSet >& xStateSet
+) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
+{
+ if( xStateSet->contains(accessibility::AccessibleStateType::FOCUSED ) )
+ atk_wrapper_focus_tracker_notify_when_idle( xAccessible );
+
+ uno::Reference< accessibility::XAccessibleEventBroadcaster > xBroadcaster =
+ uno::Reference< accessibility::XAccessibleEventBroadcaster >(xContext, uno::UNO_QUERY);
+
+ // If not already done, add the broadcaster to the list and attach as listener.
+ if( xBroadcaster.is() && m_aRefList.insert(xBroadcaster).second )
+ {
+ xBroadcaster->addEventListener(static_cast< accessibility::XAccessibleEventListener *>(this));
+
+ if( ! xStateSet->contains(accessibility::AccessibleStateType::MANAGES_DESCENDANTS ) )
+ {
+ sal_Int32 n, nmax = xContext->getAccessibleChildCount();
+ for( n = 0; n < nmax; n++ )
+ {
+ uno::Reference< accessibility::XAccessible > xChild( xContext->getAccessibleChild( n ) );
+
+ if( xChild.is() )
+ attachRecursive(xChild);
+ }
+ }
+ }
+}
+
+/*****************************************************************************/
+
+void DocumentFocusListener::detachRecursive(
+ const uno::Reference< accessibility::XAccessible >& xAccessible
+) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
+{
+ uno::Reference< accessibility::XAccessibleContext > xContext =
+ xAccessible->getAccessibleContext();
+
+ if( xContext.is() )
+ detachRecursive(xAccessible, xContext);
+}
+
+/*****************************************************************************/
+
+void DocumentFocusListener::detachRecursive(
+ const uno::Reference< accessibility::XAccessible >& xAccessible,
+ const uno::Reference< accessibility::XAccessibleContext >& xContext
+) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
+{
+ uno::Reference< accessibility::XAccessibleStateSet > xStateSet =
+ xContext->getAccessibleStateSet();
+
+ if( xStateSet.is() )
+ detachRecursive(xAccessible, xContext, xStateSet);
+}
+
+/*****************************************************************************/
+
+void DocumentFocusListener::detachRecursive(
+ const uno::Reference< accessibility::XAccessible >&,
+ const uno::Reference< accessibility::XAccessibleContext >& xContext,
+ const uno::Reference< accessibility::XAccessibleStateSet >& xStateSet
+) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
+{
+ uno::Reference< accessibility::XAccessibleEventBroadcaster > xBroadcaster =
+ uno::Reference< accessibility::XAccessibleEventBroadcaster >(xContext, uno::UNO_QUERY);
+
+ if( xBroadcaster.is() && 0 < m_aRefList.erase(xBroadcaster) )
+ {
+ xBroadcaster->removeEventListener(static_cast< accessibility::XAccessibleEventListener *>(this));
+
+ if( ! xStateSet->contains(accessibility::AccessibleStateType::MANAGES_DESCENDANTS ) )
+ {
+ sal_Int32 n, nmax = xContext->getAccessibleChildCount();
+ for( n = 0; n < nmax; n++ )
+ {
+ uno::Reference< accessibility::XAccessible > xChild( xContext->getAccessibleChild( n ) );
+
+ if( xChild.is() )
+ detachRecursive(xChild);
+ }
+ }
+ }
+}
+
+/*****************************************************************************/
+
+/*
+ * page tabs in gtk are widgets, so we need to simulate focus events for those
+ */
+
+static void handle_tabpage_activated(Window *pWindow)
+{
+ uno::Reference< accessibility::XAccessible > xAccessible =
+ pWindow->GetAccessible();
+
+ if( ! xAccessible.is() )
+ return;
+
+ uno::Reference< accessibility::XAccessibleSelection > xSelection(
+ xAccessible->getAccessibleContext(), uno::UNO_QUERY);
+
+ if( xSelection.is() )
+ atk_wrapper_focus_tracker_notify_when_idle( xSelection->getSelectedAccessibleChild(0) );
+}
+
+/*****************************************************************************/
+
+/*
+ * toolbar items in gtk are widgets, so we need to simulate focus events for those
+ */
+
+static void notify_toolbox_item_focus(ToolBox *pToolBox)
+{
+ uno::Reference< accessibility::XAccessible > xAccessible =
+ pToolBox->GetAccessible();
+
+ if( ! xAccessible.is() )
+ return;
+
+ uno::Reference< accessibility::XAccessibleContext > xContext =
+ xAccessible->getAccessibleContext();
+
+ if( ! xContext.is() )
+ return;
+
+ sal_Int32 nPos = pToolBox->GetItemPos( pToolBox->GetHighlightItemId() );
+ if( nPos != TOOLBOX_ITEM_NOTFOUND )
+ atk_wrapper_focus_tracker_notify_when_idle( xContext->getAccessibleChild( nPos ) );
+}
+
+static void handle_toolbox_highlight(Window *pWindow)
+{
+ ToolBox *pToolBox = static_cast <ToolBox *> (pWindow);
+
+ // Make sure either the toolbox or its parent toolbox has the focus
+ if ( ! pToolBox->HasFocus() )
+ {
+ ToolBox* pToolBoxParent = dynamic_cast< ToolBox* >( pToolBox->GetParent() );
+ if ( ! pToolBoxParent || ! pToolBoxParent->HasFocus() )
+ return;
+ }
+
+ notify_toolbox_item_focus(pToolBox);
+}
+
+static void handle_toolbox_highlightoff(Window *pWindow)
+{
+ ToolBox *pToolBox = static_cast <ToolBox *> (pWindow);
+ ToolBox* pToolBoxParent = dynamic_cast< ToolBox* >( pToolBox->GetParent() );
+
+ // Notify when leaving sub toolboxes
+ if( pToolBoxParent && pToolBoxParent->HasFocus() )
+ notify_toolbox_item_focus( pToolBoxParent );
+}
+
+/*****************************************************************************/
+
+static void create_wrapper_for_child(
+ const uno::Reference< accessibility::XAccessibleContext >& xContext,
+ sal_Int32 index)
+{
+ if( xContext.is() )
+ {
+ uno::Reference< accessibility::XAccessible > xChild(xContext->getAccessibleChild(index));
+ if( xChild.is() )
+ {
+ // create the wrapper object - it will survive the unref unless it is a transient object
+ g_object_unref( atk_object_wrapper_ref( xChild ) );
+ }
+ }
+}
+
+/*****************************************************************************/
+
+static void handle_toolbox_buttonchange(VclWindowEvent const *pEvent)
+{
+ Window* pWindow = pEvent->GetWindow();
+ sal_Int32 index = (sal_Int32)(sal_IntPtr) pEvent->GetData();
+
+ if( pWindow && pWindow->IsReallyVisible() )
+ {
+ uno::Reference< accessibility::XAccessible > xAccessible(pWindow->GetAccessible());
+ if( xAccessible.is() )
+ {
+ create_wrapper_for_child(xAccessible->getAccessibleContext(), index);
+ }
+ }
+}
+
+/*****************************************************************************/
+
+/* currently not needed anymore...
+static void create_wrapper_for_children(Window *pWindow)
+{
+ if( pWindow && pWindow->IsReallyVisible() )
+ {
+ uno::Reference< accessibility::XAccessible > xAccessible(pWindow->GetAccessible());
+ if( xAccessible.is() )
+ {
+ uno::Reference< accessibility::XAccessibleContext > xContext(xAccessible->getAccessibleContext());
+ if( xContext.is() )
+ {
+ sal_Int32 nChildren = xContext->getAccessibleChildCount();
+ for( sal_Int32 i = 0; i < nChildren; ++i )
+ create_wrapper_for_child(xContext, i);
+ }
+ }
+ }
+}
+*/
+
+/*****************************************************************************/
+
+static std::set< Window * > g_aWindowList;
+
+static void handle_get_focus(::VclWindowEvent const * pEvent)
+{
+ static rtl::Reference< DocumentFocusListener > aDocumentFocusListener =
+ new DocumentFocusListener();
+
+ Window *pWindow = pEvent->GetWindow();
+
+ // The menu bar is handled through VCLEVENT_MENU_HIGHLIGHTED
+ if( ! pWindow || !pWindow->IsReallyVisible() || pWindow->GetType() == WINDOW_MENUBARWINDOW )
+ return;
+
+ // ToolBoxes are handled through VCLEVENT_TOOLBOX_HIGHLIGHT
+ if( pWindow->GetType() == WINDOW_TOOLBOX )
+ return;
+
+ if( pWindow->GetType() == WINDOW_TABCONTROL )
+ {
+ handle_tabpage_activated( pWindow );
+ return;
+ }
+
+ uno::Reference< accessibility::XAccessible > xAccessible =
+ pWindow->GetAccessible();
+
+ if( ! xAccessible.is() )
+ return;
+
+ uno::Reference< accessibility::XAccessibleContext > xContext =
+ xAccessible->getAccessibleContext();
+
+ if( ! xContext.is() )
+ return;
+
+ uno::Reference< accessibility::XAccessibleStateSet > xStateSet =
+ xContext->getAccessibleStateSet();
+
+ if( ! xStateSet.is() )
+ return;
+
+/* the UNO ToolBox wrapper does not (yet?) support XAccessibleSelection, so we
+ * need to add listeners to the children instead of re-using the tabpage stuff
+ */
+ if( xStateSet->contains(accessibility::AccessibleStateType::FOCUSED) &&
+ ( pWindow->GetType() != WINDOW_TREELISTBOX ) )
+ {
+ atk_wrapper_focus_tracker_notify_when_idle( xAccessible );
+ }
+ else
+ {
+ if( g_aWindowList.find(pWindow) == g_aWindowList.end() )
+ {
+ g_aWindowList.insert(pWindow);
+ try
+ {
+ aDocumentFocusListener->attachRecursive(xAccessible, xContext, xStateSet);
+ }
+ catch( const uno::Exception &e )
+ {
+ g_warning( "Exception caught processing focus events" );
+ }
+ }
+#ifdef ENABLE_TRACING
+ else
+ fprintf(stderr, "Window %p already in the list\n", pWindow );
+#endif
+ }
+}
+
+/*****************************************************************************/
+
+static void handle_menu_highlighted(::VclMenuEvent const * pEvent)
+{
+ try
+ {
+ Menu* pMenu = pEvent->GetMenu();
+ USHORT nPos = pEvent->GetItemPos();
+
+ if( pMenu && nPos != 0xFFFF)
+ {
+ uno::Reference< accessibility::XAccessible > xAccessible ( pMenu->GetAccessible() );
+
+ if( xAccessible.is() )
+ {
+ uno::Reference< accessibility::XAccessibleContext > xContext ( xAccessible->getAccessibleContext() );
+
+ if( xContext.is() )
+ atk_wrapper_focus_tracker_notify_when_idle( xContext->getAccessibleChild( nPos ) );
+ }
+ }
+ }
+ catch( const uno::Exception& e )
+ {
+ g_warning( "Exception caught processing menu highlight events" );
+ }
+}
+
+/*****************************************************************************/
+
+long WindowEventHandler(void *, ::VclSimpleEvent const * pEvent)
+{
+ switch (pEvent->GetId())
+ {
+ case VCLEVENT_WINDOW_SHOW:
+// fprintf(stderr, "got VCLEVENT_WINDOW_SHOW for %p\n",
+// static_cast< ::VclWindowEvent const * >(pEvent)->GetWindow());
+ break;
+ case VCLEVENT_WINDOW_HIDE:
+// fprintf(stderr, "got VCLEVENT_WINDOW_HIDE for %p\n",
+// static_cast< ::VclWindowEvent const * >(pEvent)->GetWindow());
+ break;
+ case VCLEVENT_WINDOW_CLOSE:
+// fprintf(stderr, "got VCLEVENT_WINDOW_CLOSE for %p\n",
+// static_cast< ::VclWindowEvent const * >(pEvent)->GetWindow());
+ break;
+ case VCLEVENT_WINDOW_GETFOCUS:
+ handle_get_focus(static_cast< ::VclWindowEvent const * >(pEvent));
+ break;
+ case VCLEVENT_WINDOW_LOSEFOCUS:
+// fprintf(stderr, "got VCLEVENT_WINDOW_LOSEFOCUS for %p\n",
+// static_cast< ::VclWindowEvent const * >(pEvent)->GetWindow());
+ break;
+ case VCLEVENT_WINDOW_MINIMIZE:
+// fprintf(stderr, "got VCLEVENT_WINDOW_MINIMIZE for %p\n",
+// static_cast< ::VclWindowEvent const * >(pEvent)->GetWindow());
+ break;
+ case VCLEVENT_WINDOW_NORMALIZE:
+// fprintf(stderr, "got VCLEVENT_WINDOW_NORMALIZE for %p\n",
+// static_cast< ::VclWindowEvent const * >(pEvent)->GetWindow());
+ break;
+ case VCLEVENT_WINDOW_KEYINPUT:
+ case VCLEVENT_WINDOW_KEYUP:
+ case VCLEVENT_WINDOW_COMMAND:
+ case VCLEVENT_WINDOW_MOUSEMOVE:
+ break;
+ /*
+ fprintf(stderr, "got VCLEVENT_WINDOW_COMMAND (%d) for %p\n",
+ static_cast< ::CommandEvent const * > (
+ static_cast< ::VclWindowEvent const * >(pEvent)->GetData())->GetCommand(),
+ static_cast< ::VclWindowEvent const * >(pEvent)->GetWindow());
+ */
+ case VCLEVENT_MENU_HIGHLIGHT:
+ if (const VclMenuEvent* pMenuEvent = dynamic_cast<const VclMenuEvent*>(pEvent))
+ {
+ handle_menu_highlighted(pMenuEvent);
+ }
+ else if (const VclAccessibleEvent* pAccEvent = dynamic_cast<const VclAccessibleEvent*>(pEvent))
+ {
+ uno::Reference< accessibility::XAccessible > xAccessible = pAccEvent->GetAccessible();
+ if (xAccessible.is())
+ atk_wrapper_focus_tracker_notify_when_idle(xAccessible);
+ }
+ break;
+
+ case VCLEVENT_TOOLBOX_HIGHLIGHT:
+ handle_toolbox_highlight(static_cast< ::VclWindowEvent const * >(pEvent)->GetWindow());
+ break;
+
+ case VCLEVENT_TOOLBOX_BUTTONSTATECHANGED:
+ handle_toolbox_buttonchange(static_cast< ::VclWindowEvent const * >(pEvent));
+ break;
+
+ case VCLEVENT_OBJECT_DYING:
+ g_aWindowList.erase( static_cast< ::VclWindowEvent const * >(pEvent)->GetWindow() );
+ // fallthrough intentional !
+ case VCLEVENT_TOOLBOX_HIGHLIGHTOFF:
+ handle_toolbox_highlightoff(static_cast< ::VclWindowEvent const * >(pEvent)->GetWindow());
+ break;
+
+ case VCLEVENT_TABPAGE_ACTIVATE:
+ handle_tabpage_activated(static_cast< ::VclWindowEvent const * >(pEvent)->GetWindow());
+ break;
+
+ case VCLEVENT_COMBOBOX_SETTEXT:
+ // MT 2010/02: This looks quite strange to me. Stumbled over this when fixing #i104290#.
+ // This kicked in when leaving the combobox in the toolbar, after that the events worked.
+ // 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.
+ // Fix for #i104290# was done in toolkit/source/awt/vclxaccessiblecomponent, FOCUSED state for compound controls in general.
+ // create_wrapper_for_children(static_cast< ::VclWindowEvent const * >(pEvent)->GetWindow());
+ break;
+
+ default:
+// OSL_TRACE("got event %d \n", pEvent->GetId());
+ break;
+ }
+ return 0;
+}
+
+static Link g_aEventListenerLink( NULL, (PSTUB) WindowEventHandler );
+
+/*****************************************************************************/
+
+extern "C" {
+
+static G_CONST_RETURN gchar *
+ooo_atk_util_get_toolkit_name (void)
+{
+ return "VCL";
+}
+
+/*****************************************************************************/
+
+static G_CONST_RETURN gchar *
+ooo_atk_util_get_toolkit_version (void)
+{
+ /*
+ * Version is passed in as a -D flag when this file is
+ * compiled.
+ */
+
+ return VERSION;
+}
+
+/*****************************************************************************/
+
+/*
+ * GObject inheritance
+ */
+
+static void
+ooo_atk_util_class_init (AtkUtilClass *)
+{
+ AtkUtilClass *atk_class;
+ gpointer data;
+
+ data = g_type_class_peek (ATK_TYPE_UTIL);
+ atk_class = ATK_UTIL_CLASS (data);
+
+ atk_class->get_toolkit_name = ooo_atk_util_get_toolkit_name;
+ atk_class->get_toolkit_version = ooo_atk_util_get_toolkit_version;
+
+ Application::AddEventListener( g_aEventListenerLink );
+}
+
+} // extern "C"
+
+/*****************************************************************************/
+
+GType
+ooo_atk_util_get_type (void)
+{
+ static GType type = 0;
+
+ if (!type)
+ {
+ GType parent_type = g_type_from_name( "GailUtil" );
+
+ if( ! parent_type )
+ {
+ g_warning( "Unknown type: GailUtil" );
+ parent_type = ATK_TYPE_UTIL;
+ }
+
+ GTypeQuery type_query;
+ g_type_query( parent_type, &type_query );
+
+ static const GTypeInfo typeInfo =
+ {
+ type_query.class_size,
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) ooo_atk_util_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL,
+ type_query.instance_size,
+ 0,
+ (GInstanceInitFunc) NULL,
+ NULL
+ } ;
+
+ type = g_type_register_static (parent_type, "OOoUtil", &typeInfo, (GTypeFlags)0) ;
+ }
+
+ return type;
+}
+
+
diff --git a/vcl/unx/gtk/a11y/atkutil.hxx b/vcl/unx/gtk/a11y/atkutil.hxx
new file mode 100644
index 000000000000..8c8ddf59c65f
--- /dev/null
+++ b/vcl/unx/gtk/a11y/atkutil.hxx
@@ -0,0 +1,37 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef __ATK_UTIL_HXX__
+#define __ATK_UTIL_HXX__
+
+#include <atk/atk.h>
+
+#define OOO_TYPE_ATK_UTIL ooo_atk_util_get_type()
+
+GType ooo_atk_util_get_type (void);
+
+#endif
diff --git a/vcl/unx/gtk/a11y/atkvalue.cxx b/vcl/unx/gtk/a11y/atkvalue.cxx
new file mode 100644
index 000000000000..9b8e9743eb18
--- /dev/null
+++ b/vcl/unx/gtk/a11y/atkvalue.cxx
@@ -0,0 +1,147 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "atkwrapper.hxx"
+
+#include <com/sun/star/accessibility/XAccessibleValue.hpp>
+
+#include <stdio.h>
+#include <string.h>
+
+using namespace ::com::sun::star;
+
+static accessibility::XAccessibleValue*
+ getValue( AtkValue *pValue ) throw (uno::RuntimeException)
+{
+ AtkObjectWrapper *pWrap = ATK_OBJECT_WRAPPER( pValue );
+ if( pWrap )
+ {
+ if( !pWrap->mpValue && pWrap->mpContext )
+ {
+ uno::Any any = pWrap->mpContext->queryInterface( accessibility::XAccessibleValue::static_type(NULL) );
+ pWrap->mpValue = reinterpret_cast< accessibility::XAccessibleValue * > (any.pReserved);
+ pWrap->mpValue->acquire();
+ }
+
+ return pWrap->mpValue;
+ }
+
+ return NULL;
+}
+
+static void anyToGValue( uno::Any aAny, GValue *pValue )
+{
+ // FIXME: expand to lots of types etc.
+ double aDouble=0;
+ aAny >>= aDouble;
+
+ memset( pValue, 0, sizeof( GValue ) );
+ g_value_init( pValue, G_TYPE_DOUBLE );
+ g_value_set_double( pValue, aDouble );
+}
+
+extern "C" {
+
+static void
+value_wrapper_get_current_value( AtkValue *value,
+ GValue *gval )
+{
+ try {
+ accessibility::XAccessibleValue* pValue = getValue( value );
+ if( pValue )
+ anyToGValue( pValue->getCurrentValue(), gval );
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getCurrentValue()" );
+ }
+}
+
+static void
+value_wrapper_get_maximum_value( AtkValue *value,
+ GValue *gval )
+{
+ try {
+ accessibility::XAccessibleValue* pValue = getValue( value );
+ if( pValue )
+ anyToGValue( pValue->getMaximumValue(), gval );
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getCurrentValue()" );
+ }
+}
+
+static void
+value_wrapper_get_minimum_value( AtkValue *value,
+ GValue *gval )
+{
+ try {
+ accessibility::XAccessibleValue* pValue = getValue( value );
+ if( pValue )
+ anyToGValue( pValue->getMinimumValue(), gval );
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getCurrentValue()" );
+ }
+}
+
+static gboolean
+value_wrapper_set_current_value( AtkValue *value,
+ const GValue *gval )
+{
+ try {
+ accessibility::XAccessibleValue* pValue = getValue( value );
+ if( pValue )
+ {
+ // FIXME - this needs expanding
+ double aDouble = g_value_get_double( gval );
+ uno::Any aAny;
+ aAny <<= aDouble;
+ return pValue->setCurrentValue( aAny );
+ }
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getCurrentValue()" );
+ }
+
+ return FALSE;
+}
+
+} // extern "C"
+
+void
+valueIfaceInit (AtkValueIface *iface)
+{
+ g_return_if_fail (iface != NULL);
+
+ iface->get_current_value = value_wrapper_get_current_value;
+ iface->get_maximum_value = value_wrapper_get_maximum_value;
+ iface->get_minimum_value = value_wrapper_get_minimum_value;
+ iface->set_current_value = value_wrapper_set_current_value;
+}
diff --git a/vcl/unx/gtk/a11y/atkwindow.cxx b/vcl/unx/gtk/a11y/atkwindow.cxx
new file mode 100644
index 000000000000..5448235998e8
--- /dev/null
+++ b/vcl/unx/gtk/a11y/atkwindow.cxx
@@ -0,0 +1,331 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <plugins/gtk/gtkframe.hxx>
+#include <vcl/window.hxx>
+#include "vcl/popupmenuwindow.hxx"
+
+#include "atkwindow.hxx"
+#include "atkwrapper.hxx"
+#include "atkregistry.hxx"
+
+#include <com/sun/star/accessibility/AccessibleRole.hpp>
+
+using namespace ::com::sun::star::accessibility;
+using namespace ::com::sun::star::uno;
+
+extern "C" {
+
+static void (* window_real_initialize) (AtkObject *obj, gpointer data) = NULL;
+static void (* window_real_finalize) (GObject *obj) = NULL;
+
+static void
+init_from_window( AtkObject *accessible, Window *pWindow )
+{
+ static AtkRole aDefaultRole = ATK_ROLE_INVALID;
+
+ // Special role for sub-menu and combo-box popups that are exposed directly
+ // by their parents already.
+ if( aDefaultRole == ATK_ROLE_INVALID )
+ aDefaultRole = atk_role_register( "redundant object" );
+
+ AtkRole role = aDefaultRole;
+
+ // Determine the appropriate role for the GtkWindow
+ switch( pWindow->GetAccessibleRole() )
+ {
+ case AccessibleRole::ALERT:
+ role = ATK_ROLE_ALERT;
+ break;
+
+ case AccessibleRole::DIALOG:
+ role = ATK_ROLE_DIALOG;
+ break;
+
+ case AccessibleRole::FRAME:
+ role = ATK_ROLE_FRAME;
+ break;
+
+ /* Ignore window objects for sub-menus, combo- and list boxes,
+ * which are exposed as children of their parents.
+ */
+ case AccessibleRole::WINDOW:
+ {
+ USHORT type = WINDOW_WINDOW;
+ bool parentIsMenuFloatingWindow = false;
+
+ Window *pParent = pWindow->GetParent();
+ if( pParent ) {
+ type = pParent->GetType();
+ parentIsMenuFloatingWindow = ( TRUE == pParent->IsMenuFloatingWindow() );
+ }
+
+ if( (WINDOW_LISTBOX != type) && (WINDOW_COMBOBOX != type) &&
+ (WINDOW_MENUBARWINDOW != type) && ! parentIsMenuFloatingWindow )
+ {
+ role = ATK_ROLE_WINDOW;
+ }
+ }
+ break;
+
+ default:
+ {
+ Window *pChild = pWindow->GetChild( 0 );
+ if( pChild )
+ {
+ if( WINDOW_HELPTEXTWINDOW == pChild->GetType() )
+ {
+ role = ATK_ROLE_TOOL_TIP;
+ pChild->SetAccessibleRole( AccessibleRole::LABEL );
+ accessible->name = g_strdup( rtl::OUStringToOString( pChild->GetText(), RTL_TEXTENCODING_UTF8 ).getStr() );
+ }
+ else if ( pWindow->GetType() == WINDOW_BORDERWINDOW && pChild->GetType() == WINDOW_FLOATINGWINDOW )
+ {
+ PopupMenuFloatingWindow* p = dynamic_cast<PopupMenuFloatingWindow*>(pChild);
+ if (p && p->IsPopupMenu() && p->GetMenuStackLevel() == 0)
+ {
+ // This is a top-level menu popup. Register it.
+ role = ATK_ROLE_POPUP_MENU;
+ pChild->SetAccessibleRole( AccessibleRole::POPUP_MENU );
+ accessible->name = g_strdup( rtl::OUStringToOString( pChild->GetText(), RTL_TEXTENCODING_UTF8 ).getStr() );
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ accessible->role = role;
+}
+
+/*****************************************************************************/
+
+static gint
+ooo_window_wrapper_clear_focus(gpointer)
+{
+ atk_focus_tracker_notify( NULL );
+ return FALSE;
+}
+
+/*****************************************************************************/
+
+static gboolean
+ooo_window_wrapper_real_focus_gtk (GtkWidget *, GdkEventFocus *)
+{
+ g_idle_add( ooo_window_wrapper_clear_focus, NULL );
+ return FALSE;
+}
+
+static gboolean ooo_tooltip_map( GtkWidget* pToolTip, gpointer )
+{
+ AtkObject* pAccessible = gtk_widget_get_accessible( pToolTip );
+ if( pAccessible )
+ atk_object_notify_state_change( pAccessible, ATK_STATE_SHOWING, TRUE );
+ return FALSE;
+}
+
+static gboolean ooo_tooltip_unmap( GtkWidget* pToolTip, gpointer )
+{
+ AtkObject* pAccessible = gtk_widget_get_accessible( pToolTip );
+ if( pAccessible )
+ atk_object_notify_state_change( pAccessible, ATK_STATE_SHOWING, FALSE );
+ return FALSE;
+}
+
+/*****************************************************************************/
+
+static bool
+isChildPopupMenu(Window* pWindow)
+{
+ Window* pChild = pWindow->GetAccessibleChildWindow(0);
+ if (!pChild)
+ return false;
+
+ if (WINDOW_FLOATINGWINDOW != pChild->GetType())
+ return false;
+
+ PopupMenuFloatingWindow* p = dynamic_cast<PopupMenuFloatingWindow*>(pChild);
+ if (!p)
+ return false;
+
+ return p->IsPopupMenu();
+}
+
+static void
+ooo_window_wrapper_real_initialize(AtkObject *obj, gpointer data)
+{
+ window_real_initialize(obj, data);
+
+ GtkSalFrame *pFrame = GtkSalFrame::getFromWindow( GTK_WINDOW( data ) );
+ if( pFrame )
+ {
+ Window *pWindow = pFrame->GetWindow();
+ if( pWindow )
+ {
+ init_from_window( obj, pWindow );
+
+ Reference< XAccessible > xAccessible( pWindow->GetAccessible(true) );
+
+ /* We need the wrapper object for the top-level XAccessible to be
+ * in the wrapper registry when atk traverses the hierachy up on
+ * focus events
+ */
+ if( WINDOW_BORDERWINDOW == pWindow->GetType() )
+ {
+ if ( isChildPopupMenu(pWindow) )
+ {
+ AtkObject *child = atk_object_wrapper_new( xAccessible, obj );
+ ooo_wrapper_registry_add( xAccessible, child );
+ }
+ else
+ {
+ ooo_wrapper_registry_add( xAccessible, obj );
+ g_object_set_data( G_OBJECT(obj), "ooo:atk-wrapper-key", xAccessible.get() );
+ }
+ }
+ else
+ {
+ AtkObject *child = atk_object_wrapper_new( xAccessible, obj );
+ child->role = ATK_ROLE_FILLER;
+ if( (ATK_ROLE_DIALOG == obj->role) || (ATK_ROLE_ALERT == obj->role) )
+ child->role = ATK_ROLE_OPTION_PANE;
+ ooo_wrapper_registry_add( xAccessible, child );
+ }
+ }
+ }
+
+ g_signal_connect_after( GTK_WIDGET( data ), "focus-out-event",
+ G_CALLBACK (ooo_window_wrapper_real_focus_gtk),
+ NULL);
+
+ if( obj->role == ATK_ROLE_TOOL_TIP )
+ {
+ g_signal_connect_after( GTK_WIDGET( data ), "map-event",
+ G_CALLBACK (ooo_tooltip_map),
+ NULL);
+ g_signal_connect_after( GTK_WIDGET( data ), "unmap-event",
+ G_CALLBACK (ooo_tooltip_unmap),
+ NULL);
+ }
+}
+
+/*****************************************************************************/
+
+static void
+ooo_window_wrapper_real_finalize (GObject *obj)
+{
+ ooo_wrapper_registry_remove( (XAccessible *) g_object_get_data( obj, "ooo:atk-wrapper-key" ));
+ window_real_finalize( obj );
+}
+
+/*****************************************************************************/
+
+static void
+ooo_window_wrapper_class_init (AtkObjectClass *klass, gpointer)
+{
+ AtkObjectClass *atk_class;
+ GObjectClass *gobject_class;
+ gpointer data;
+
+ /*
+ * Patch the gobject vtable of GailWindow to refer to our instance of
+ * "initialize".
+ */
+
+ data = g_type_class_peek_parent( klass );
+ atk_class = ATK_OBJECT_CLASS (data);
+
+ window_real_initialize = atk_class->initialize;
+ atk_class->initialize = ooo_window_wrapper_real_initialize;
+
+ gobject_class = G_OBJECT_CLASS (data);
+
+ window_real_finalize = gobject_class->finalize;
+ gobject_class->finalize = ooo_window_wrapper_real_finalize;
+}
+
+} // extern "C"
+
+/*****************************************************************************/
+
+GType
+ooo_window_wrapper_get_type (void)
+{
+ static GType type = 0;
+
+ if (!type)
+ {
+ GType parent_type = g_type_from_name( "GailWindow" );
+
+ if( ! parent_type )
+ {
+ g_warning( "Unknown type: GailWindow" );
+ parent_type = ATK_TYPE_OBJECT;
+ }
+
+ GTypeQuery type_query;
+ g_type_query( parent_type, &type_query );
+
+ static const GTypeInfo typeInfo =
+ {
+ type_query.class_size,
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) ooo_window_wrapper_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL,
+ type_query.instance_size,
+ 0,
+ (GInstanceInitFunc) NULL,
+ NULL
+ } ;
+
+ type = g_type_register_static (parent_type, "OOoWindowAtkObject", &typeInfo, (GTypeFlags)0) ;
+ }
+
+ return type;
+}
+
+void restore_gail_window_vtable (void)
+{
+ AtkObjectClass *atk_class;
+ gpointer data;
+
+ GType type = g_type_from_name( "GailWindow" );
+
+ if( type == G_TYPE_INVALID )
+ return;
+
+ data = g_type_class_peek( type );
+ atk_class = ATK_OBJECT_CLASS (data);
+
+ atk_class->initialize = window_real_initialize;
+}
+
diff --git a/vcl/unx/gtk/a11y/atkwindow.hxx b/vcl/unx/gtk/a11y/atkwindow.hxx
new file mode 100644
index 000000000000..6a9862256999
--- /dev/null
+++ b/vcl/unx/gtk/a11y/atkwindow.hxx
@@ -0,0 +1,38 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef __ATK_WINDOW_HXX__
+#define __ATK_WINDOW_HXX__
+
+#include <atk/atk.h>
+
+#define OOO_TYPE_WINDOW_WRAPPER ooo_window_wrapper_get_type()
+
+GType ooo_window_wrapper_get_type (void);
+void restore_gail_window_vtable (void);
+
+#endif
diff --git a/vcl/unx/gtk/a11y/atkwrapper.cxx b/vcl/unx/gtk/a11y/atkwrapper.cxx
new file mode 100644
index 000000000000..10f75309708d
--- /dev/null
+++ b/vcl/unx/gtk/a11y/atkwrapper.cxx
@@ -0,0 +1,953 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <com/sun/star/uno/Any.hxx>
+#include <com/sun/star/uno/Type.hxx>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/accessibility/AccessibleRole.hpp>
+#include <com/sun/star/accessibility/AccessibleRelation.hpp>
+#include <com/sun/star/accessibility/AccessibleRelationType.hpp>
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+#include <com/sun/star/accessibility/XAccessible.hpp>
+#include <com/sun/star/accessibility/XAccessibleText.hpp>
+#include <com/sun/star/accessibility/XAccessibleTextMarkup.hpp>
+#include <com/sun/star/accessibility/XAccessibleTextAttributes.hpp>
+#include <com/sun/star/accessibility/XAccessibleValue.hpp>
+#include <com/sun/star/accessibility/XAccessibleAction.hpp>
+#include <com/sun/star/accessibility/XAccessibleContext.hpp>
+#include <com/sun/star/accessibility/XAccessibleComponent.hpp>
+#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp>
+#include <com/sun/star/accessibility/XAccessibleMultiLineText.hpp>
+#include <com/sun/star/accessibility/XAccessibleStateSet.hpp>
+#include <com/sun/star/accessibility/XAccessibleRelationSet.hpp>
+#include <com/sun/star/accessibility/XAccessibleTable.hpp>
+#include <com/sun/star/accessibility/XAccessibleEditableText.hpp>
+#include <com/sun/star/accessibility/XAccessibleImage.hpp>
+#include <com/sun/star/accessibility/XAccessibleHyperlink.hpp>
+#include <com/sun/star/accessibility/XAccessibleHypertext.hpp>
+#include <com/sun/star/accessibility/XAccessibleSelection.hpp>
+#include <com/sun/star/awt/XExtendedToolkit.hpp>
+#include <com/sun/star/awt/XTopWindow.hpp>
+#include <com/sun/star/awt/XTopWindowListener.hpp>
+#include <com/sun/star/awt/XWindow.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/lang/XSingleServiceFactory.hpp>
+#include <com/sun/star/beans/Property.hpp>
+
+#include <rtl/ref.hxx>
+#include <cppuhelper/factory.hxx>
+#include <cppuhelper/queryinterface.hxx>
+
+#include "atkwrapper.hxx"
+#include "atkregistry.hxx"
+#include "atklistener.hxx"
+
+#ifdef ENABLE_TRACING
+#include <stdio.h>
+#endif
+
+#include <string.h>
+
+using namespace ::com::sun::star;
+
+static GObjectClass *parent_class = NULL;
+
+static AtkRelationType mapRelationType( sal_Int16 nRelation )
+{
+ AtkRelationType type = ATK_RELATION_NULL;
+
+ switch( nRelation )
+ {
+ case accessibility::AccessibleRelationType::CONTENT_FLOWS_FROM:
+ type = ATK_RELATION_FLOWS_FROM;
+ break;
+
+ case accessibility::AccessibleRelationType::CONTENT_FLOWS_TO:
+ type = ATK_RELATION_FLOWS_TO;
+ break;
+
+ case accessibility::AccessibleRelationType::CONTROLLED_BY:
+ type = ATK_RELATION_CONTROLLED_BY;
+ break;
+
+ case accessibility::AccessibleRelationType::CONTROLLER_FOR:
+ type = ATK_RELATION_CONTROLLER_FOR;
+ break;
+
+ case accessibility::AccessibleRelationType::LABEL_FOR:
+ type = ATK_RELATION_LABEL_FOR;
+ break;
+
+ case accessibility::AccessibleRelationType::LABELED_BY:
+ type = ATK_RELATION_LABELLED_BY;
+ break;
+
+ case accessibility::AccessibleRelationType::MEMBER_OF:
+ type = ATK_RELATION_MEMBER_OF;
+ break;
+
+ case accessibility::AccessibleRelationType::SUB_WINDOW_OF:
+ type = ATK_RELATION_SUBWINDOW_OF;
+ break;
+
+ case accessibility::AccessibleRelationType::NODE_CHILD_OF:
+ type = ATK_RELATION_NODE_CHILD_OF;
+ break;
+
+ default:
+ break;
+ }
+#if 0
+ ATK_RELATION_NODE_CHILD_OF,
+ ATK_RELATION_EMBEDS,
+ ATK_RELATION_EMBEDDED_BY,
+ ATK_RELATION_POPUP_FOR,
+#endif
+ return type;
+}
+
+
+AtkStateType mapAtkState( sal_Int16 nState )
+{
+ AtkStateType type = ATK_STATE_INVALID;
+
+ // A perfect / complete mapping ...
+ switch( nState )
+ {
+#define MAP_DIRECT( a ) \
+ case accessibility::AccessibleStateType::a: \
+ type = ATK_STATE_##a; break
+
+ MAP_DIRECT( INVALID );
+ MAP_DIRECT( ACTIVE );
+ MAP_DIRECT( ARMED );
+ MAP_DIRECT( BUSY );
+ MAP_DIRECT( CHECKED );
+ MAP_DIRECT( EDITABLE );
+ MAP_DIRECT( ENABLED );
+ MAP_DIRECT( EXPANDABLE );
+ MAP_DIRECT( EXPANDED );
+ MAP_DIRECT( FOCUSABLE );
+ MAP_DIRECT( FOCUSED );
+ MAP_DIRECT( HORIZONTAL );
+ MAP_DIRECT( ICONIFIED );
+ MAP_DIRECT( INDETERMINATE );
+ MAP_DIRECT( MANAGES_DESCENDANTS );
+ MAP_DIRECT( MODAL );
+ MAP_DIRECT( MULTI_LINE );
+ MAP_DIRECT( OPAQUE );
+ MAP_DIRECT( PRESSED );
+ MAP_DIRECT( RESIZABLE );
+ MAP_DIRECT( SELECTABLE );
+ MAP_DIRECT( SELECTED );
+ MAP_DIRECT( SENSITIVE );
+ MAP_DIRECT( SHOWING );
+ MAP_DIRECT( SINGLE_LINE );
+ MAP_DIRECT( STALE );
+ MAP_DIRECT( TRANSIENT );
+ MAP_DIRECT( VERTICAL );
+ MAP_DIRECT( VISIBLE );
+ // a spelling error ...
+ case accessibility::AccessibleStateType::DEFUNC:
+ type = ATK_STATE_DEFUNCT; break;
+ case accessibility::AccessibleStateType::MULTI_SELECTABLE:
+ type = ATK_STATE_MULTISELECTABLE; break;
+ default:
+ break;
+ }
+
+ return type;
+}
+
+static inline AtkRole registerRole( const gchar * name )
+{
+ AtkRole ret = atk_role_for_name( name );
+ if( ATK_ROLE_INVALID == ret )
+ ret = atk_role_register( name );
+
+ return ret;
+}
+
+static AtkRole mapToAtkRole( sal_Int16 nRole )
+{
+ AtkRole role = ATK_ROLE_UNKNOWN;
+
+ static AtkRole roleMap[] = {
+ ATK_ROLE_UNKNOWN,
+ ATK_ROLE_ALERT,
+ ATK_ROLE_COLUMN_HEADER,
+ ATK_ROLE_CANVAS,
+ ATK_ROLE_CHECK_BOX,
+ ATK_ROLE_CHECK_MENU_ITEM,
+ ATK_ROLE_COLOR_CHOOSER,
+ ATK_ROLE_COMBO_BOX,
+ ATK_ROLE_DATE_EDITOR,
+ ATK_ROLE_DESKTOP_ICON,
+ ATK_ROLE_DESKTOP_FRAME, // ? pane
+ ATK_ROLE_DIRECTORY_PANE,
+ ATK_ROLE_DIALOG,
+ ATK_ROLE_UNKNOWN, // DOCUMENT - registered below
+ ATK_ROLE_UNKNOWN, // EMBEDDED_OBJECT - registered below
+ ATK_ROLE_UNKNOWN, // END_NOTE - registered below
+ ATK_ROLE_FILE_CHOOSER,
+ ATK_ROLE_FILLER,
+ ATK_ROLE_FONT_CHOOSER,
+ ATK_ROLE_FOOTER,
+ ATK_ROLE_TEXT, // FOOTNOTE - registered below
+ ATK_ROLE_FRAME,
+ ATK_ROLE_GLASS_PANE,
+ ATK_ROLE_IMAGE, // GRAPHIC
+ ATK_ROLE_UNKNOWN, // GROUP_BOX - registered below
+ ATK_ROLE_HEADER,
+ ATK_ROLE_PARAGRAPH, // HEADING - registered below
+ ATK_ROLE_TEXT, // HYPER_LINK - registered below
+ ATK_ROLE_ICON,
+ ATK_ROLE_INTERNAL_FRAME,
+ ATK_ROLE_LABEL,
+ ATK_ROLE_LAYERED_PANE,
+ ATK_ROLE_LIST,
+ ATK_ROLE_LIST_ITEM,
+ ATK_ROLE_MENU,
+ ATK_ROLE_MENU_BAR,
+ ATK_ROLE_MENU_ITEM,
+ ATK_ROLE_OPTION_PANE,
+ ATK_ROLE_PAGE_TAB,
+ ATK_ROLE_PAGE_TAB_LIST,
+ ATK_ROLE_PANEL,
+ ATK_ROLE_PARAGRAPH,
+ ATK_ROLE_PASSWORD_TEXT,
+ ATK_ROLE_POPUP_MENU,
+ ATK_ROLE_PUSH_BUTTON,
+ ATK_ROLE_PROGRESS_BAR,
+ ATK_ROLE_RADIO_BUTTON,
+ ATK_ROLE_RADIO_MENU_ITEM,
+ ATK_ROLE_ROW_HEADER,
+ ATK_ROLE_ROOT_PANE,
+ ATK_ROLE_SCROLL_BAR,
+ ATK_ROLE_SCROLL_PANE,
+ ATK_ROLE_UNKNOWN, // SHAPE - registered below
+ ATK_ROLE_SEPARATOR,
+ ATK_ROLE_SLIDER,
+ ATK_ROLE_SPIN_BUTTON, // SPIN_BOX ?
+ ATK_ROLE_SPLIT_PANE,
+ ATK_ROLE_STATUSBAR,
+ ATK_ROLE_TABLE,
+ ATK_ROLE_TABLE_CELL,
+ ATK_ROLE_TEXT,
+ ATK_ROLE_INTERNAL_FRAME, // TEXT_FRAME - registered below
+ ATK_ROLE_TOGGLE_BUTTON,
+ ATK_ROLE_TOOL_BAR,
+ ATK_ROLE_TOOL_TIP,
+ ATK_ROLE_TREE,
+ ATK_ROLE_VIEWPORT,
+ ATK_ROLE_WINDOW,
+ ATK_ROLE_PUSH_BUTTON, // BUTTON_DROPDOWN
+ ATK_ROLE_PUSH_BUTTON, // BUTTON_MENU
+ ATK_ROLE_UNKNOWN, // CAPTION - registered below
+ ATK_ROLE_UNKNOWN, // CHART - registered below
+ ATK_ROLE_UNKNOWN, // EDIT_BAR - registered below
+ ATK_ROLE_UNKNOWN, // FORM - registered below
+ ATK_ROLE_UNKNOWN, // IMAGE_MAP - registered below
+ ATK_ROLE_UNKNOWN, // NOTE - registered below
+ ATK_ROLE_UNKNOWN, // PAGE - registered below
+ ATK_ROLE_RULER,
+ ATK_ROLE_UNKNOWN, // SECTION - registered below
+ ATK_ROLE_UNKNOWN, // TREE_ITEM - registered below
+ ATK_ROLE_TREE_TABLE,
+ ATK_ROLE_SCROLL_PANE, // COMMENT - mapped to atk_role_scroll_pane
+ ATK_ROLE_UNKNOWN // COMMENT_END - mapped to atk_role_unknown
+ };
+
+ static bool initialized = false;
+
+ if( ! initialized )
+ {
+ // re-use strings from ATK library
+ roleMap[accessibility::AccessibleRole::EDIT_BAR] = registerRole("edit bar");
+ roleMap[accessibility::AccessibleRole::EMBEDDED_OBJECT] = registerRole("embedded component");
+ roleMap[accessibility::AccessibleRole::CHART] = registerRole("chart");
+ roleMap[accessibility::AccessibleRole::CAPTION] = registerRole("caption");
+ roleMap[accessibility::AccessibleRole::DOCUMENT] = registerRole("document frame");
+ roleMap[accessibility::AccessibleRole::HEADING] = registerRole("heading");
+ roleMap[accessibility::AccessibleRole::PAGE] = registerRole("page");
+ roleMap[accessibility::AccessibleRole::SECTION] = registerRole("section");
+ roleMap[accessibility::AccessibleRole::FORM] = registerRole("form");
+
+ // these don't exist in ATK yet
+ roleMap[accessibility::AccessibleRole::END_NOTE] = registerRole("end note");
+ roleMap[accessibility::AccessibleRole::FOOTNOTE] = registerRole("foot note");
+ roleMap[accessibility::AccessibleRole::GROUP_BOX] = registerRole("group box");
+ roleMap[accessibility::AccessibleRole::HYPER_LINK] = registerRole("hyper link");
+ roleMap[accessibility::AccessibleRole::SHAPE] = registerRole("shape");
+ roleMap[accessibility::AccessibleRole::TEXT_FRAME] = registerRole("text frame");
+ roleMap[accessibility::AccessibleRole::IMAGE_MAP] = registerRole("image map");
+ roleMap[accessibility::AccessibleRole::NOTE] = registerRole("note");
+ roleMap[accessibility::AccessibleRole::TREE_ITEM] = registerRole("tree item");
+
+ initialized = true;
+ }
+
+ static const sal_Int32 nMapSize = sizeof(roleMap)/sizeof(sal_Int16);
+ if( 0 <= nRole && nMapSize > nRole )
+ role = roleMap[nRole];
+
+ return role;
+}
+
+
+/*****************************************************************************/
+
+extern "C" {
+
+/*****************************************************************************/
+
+static G_CONST_RETURN gchar*
+wrapper_get_name( AtkObject *atk_obj )
+{
+ AtkObjectWrapper *obj = ATK_OBJECT_WRAPPER (atk_obj);
+
+ if( obj->mpContext )
+ {
+ try {
+ rtl::OString aName =
+ rtl::OUStringToOString(
+ obj->mpContext->getAccessibleName(),
+ RTL_TEXTENCODING_UTF8);
+
+ int nCmp = atk_obj->name ? rtl_str_compare( atk_obj->name, aName.getStr() ) : -1;
+ if( nCmp != 0 )
+ {
+ if( atk_obj->name )
+ g_free(atk_obj->name);
+ atk_obj->name = g_strdup(aName.getStr());
+ }
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getAccessibleName()" );
+ }
+ }
+
+ return ATK_OBJECT_CLASS (parent_class)->get_name(atk_obj);
+}
+
+/*****************************************************************************/
+
+static G_CONST_RETURN gchar*
+wrapper_get_description( AtkObject *atk_obj )
+{
+ AtkObjectWrapper *obj = ATK_OBJECT_WRAPPER (atk_obj);
+
+ if( obj->mpContext )
+ {
+ try {
+ rtl::OString aDescription =
+ rtl::OUStringToOString(
+ obj->mpContext->getAccessibleDescription(),
+ RTL_TEXTENCODING_UTF8);
+
+ g_free(atk_obj->description);
+ atk_obj->description = g_strdup(aDescription.getStr());
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getAccessibleDescription()" );
+ }
+ }
+
+ return ATK_OBJECT_CLASS (parent_class)->get_description(atk_obj);
+
+}
+
+/*****************************************************************************/
+
+static gint
+wrapper_get_n_children( AtkObject *atk_obj )
+{
+ AtkObjectWrapper *obj = ATK_OBJECT_WRAPPER (atk_obj);
+ gint n = 0;
+
+ if( obj->mpContext )
+ {
+ try {
+ n = obj->mpContext->getAccessibleChildCount();
+ }
+ catch(const uno::Exception& e) {
+ OSL_ENSURE(0, "Exception in getAccessibleChildCount()" );
+ }
+ }
+
+ return n;
+}
+
+/*****************************************************************************/
+
+static AtkObject *
+wrapper_ref_child( AtkObject *atk_obj,
+ gint i )
+{
+ AtkObjectWrapper *obj = ATK_OBJECT_WRAPPER (atk_obj);
+ AtkObject* child = NULL;
+
+ // see comments above atk_object_wrapper_remove_child
+ if( -1 < i && obj->index_of_child_about_to_be_removed == i )
+ {
+ g_object_ref( obj->child_about_to_be_removed );
+ return obj->child_about_to_be_removed;
+ }
+
+ if( obj->mpContext )
+ {
+ try {
+ uno::Reference< accessibility::XAccessible > xAccessible =
+ obj->mpContext->getAccessibleChild( i );
+
+ child = atk_object_wrapper_ref( xAccessible );
+ }
+ catch(const uno::Exception& e) {
+ OSL_ENSURE(0, "Exception in getAccessibleChild");
+ }
+ }
+
+ return child;
+}
+
+/*****************************************************************************/
+
+static gint
+wrapper_get_index_in_parent( AtkObject *atk_obj )
+{
+ AtkObjectWrapper *obj = ATK_OBJECT_WRAPPER (atk_obj);
+ gint i = -1;
+
+ if( obj->mpContext )
+ {
+ try {
+ i = obj->mpContext->getAccessibleIndexInParent();
+
+#ifdef ENABLE_TRACING
+ fprintf(stderr, "%p->getAccessibleIndexInParent() returned: %u\n",
+ obj->mpAccessible, i);
+#endif
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getAccessibleIndexInParent()" );
+ }
+ }
+ return i;
+}
+
+/*****************************************************************************/
+
+static AtkRelationSet *
+wrapper_ref_relation_set( AtkObject *atk_obj )
+{
+ AtkObjectWrapper *obj = ATK_OBJECT_WRAPPER (atk_obj);
+ AtkRelationSet *pSet = atk_relation_set_new();
+
+ if( obj->mpContext )
+ {
+ try {
+ uno::Reference< accessibility::XAccessibleRelationSet > xRelationSet(
+ obj->mpContext->getAccessibleRelationSet()
+ );
+
+ sal_Int32 nRelations = xRelationSet.is() ? xRelationSet->getRelationCount() : 0;
+ for( sal_Int32 n = 0; n < nRelations; n++ )
+ {
+ accessibility::AccessibleRelation aRelation = xRelationSet->getRelation( n );
+ sal_uInt32 nTargetCount = aRelation.TargetSet.getLength();
+ AtkObject **pTargets = (AtkObject **) alloca( nTargetCount * sizeof(AtkObject *) );
+
+ for( sal_uInt32 i = 0; i < nTargetCount; i++ )
+ {
+ uno::Reference< accessibility::XAccessible > xAccessible(
+ aRelation.TargetSet[i], uno::UNO_QUERY );
+ pTargets[i] = atk_object_wrapper_ref( xAccessible );
+ }
+
+ AtkRelation *pRel =
+ atk_relation_new(
+ pTargets, nTargetCount,
+ mapRelationType( aRelation.RelationType )
+ );
+ atk_relation_set_add( pSet, pRel );
+ g_object_unref( G_OBJECT( pRel ) );
+ }
+ }
+ catch(const uno::Exception &e) {
+ g_object_unref( G_OBJECT( pSet ) );
+ pSet = NULL;
+ }
+ }
+
+ return pSet;
+}
+
+/*****************************************************************************/
+
+#if 0
+struct {
+ sal_Int16 value;
+ const sal_Char* name;
+} aStateTypeTable[] = {
+ { accessibility::AccessibleStateType::INVALID, "INVALID" },
+ { accessibility::AccessibleStateType::ACTIVE, "ACTIVE" },
+ { accessibility::AccessibleStateType::ARMED, "ARMED" },
+ { accessibility::AccessibleStateType::BUSY, "BUSY" },
+ { accessibility::AccessibleStateType::CHECKED, "CHECKED" },
+ { accessibility::AccessibleStateType::DEFUNC, "DEFUNC" },
+ { accessibility::AccessibleStateType::EDITABLE, "EDITABLE" },
+ { accessibility::AccessibleStateType::ENABLED, "ENABLED" },
+ { accessibility::AccessibleStateType::EXPANDABLE, "EXPANDABLE" },
+ { accessibility::AccessibleStateType::EXPANDED, "EXPANDED" },
+ { accessibility::AccessibleStateType::FOCUSABLE, "FOCUSABLE" },
+ { accessibility::AccessibleStateType::FOCUSED, "FOCUSED" },
+ { accessibility::AccessibleStateType::HORIZONTAL, "HORIZONTAL" },
+ { accessibility::AccessibleStateType::ICONIFIED, "ICONIFIED" },
+ { accessibility::AccessibleStateType::INDETERMINATE, "INDETERMINATE" },
+ { accessibility::AccessibleStateType::MANAGES_DESCENDANTS, "MANAGES_DESCENDANTS" },
+ { accessibility::AccessibleStateType::MODAL, "MODAL" },
+ { accessibility::AccessibleStateType::MULTI_LINE, "MULTI_LINE" },
+ { accessibility::AccessibleStateType::MULTI_SELECTABLE, "MULTI_SELECTABLE" },
+ { accessibility::AccessibleStateType::OPAQUE, "OPAQUE" },
+ { accessibility::AccessibleStateType::PRESSED, "PRESSED" },
+ { accessibility::AccessibleStateType::RESIZABLE, "RESIZABLE" },
+ { accessibility::AccessibleStateType::SELECTABLE, "SELECTABLE" },
+ { accessibility::AccessibleStateType::SELECTED, "SELECTED" },
+ { accessibility::AccessibleStateType::SENSITIVE, "SENSITIVE" },
+ { accessibility::AccessibleStateType::SHOWING, "SHOWING" },
+ { accessibility::AccessibleStateType::SINGLE_LINE, "SINGLE_LINE" },
+ { accessibility::AccessibleStateType::STALE, "STALE" },
+ { accessibility::AccessibleStateType::TRANSIENT, "TRANSIENT" },
+ { accessibility::AccessibleStateType::VERTICAL, "VERTICAL" },
+ { accessibility::AccessibleStateType::VISIBLE, "VISIBLE" }
+};
+
+static void printStates(const uno::Sequence<sal_Int16>& rStates)
+{
+ sal_Int32 n = rStates.getLength();
+ size_t nTypes = sizeof(aStateTypeTable)/sizeof(aStateTypeTable[0]);
+ for (sal_Int32 i = 0; i < n; ++i)
+ {
+ for (size_t j = 0; j < nTypes; ++j)
+ {
+ if (aStateTypeTable[j].value == rStates[i])
+ printf("%s ", aStateTypeTable[j].name);
+ }
+ }
+ printf("\n");
+}
+#endif
+
+static AtkStateSet *
+wrapper_ref_state_set( AtkObject *atk_obj )
+{
+ AtkObjectWrapper *obj = ATK_OBJECT_WRAPPER (atk_obj);
+ AtkStateSet *pSet = atk_state_set_new();
+
+ if( obj->mpContext )
+ {
+ try {
+ uno::Reference< accessibility::XAccessibleStateSet > xStateSet(
+ obj->mpContext->getAccessibleStateSet());
+
+ if( xStateSet.is() )
+ {
+ uno::Sequence< sal_Int16 > aStates = xStateSet->getStates();
+
+ for( sal_Int32 n = 0; n < aStates.getLength(); n++ )
+ atk_state_set_add_state( pSet, mapAtkState( aStates[n] ) );
+
+ // We need to emulate FOCUS state for menus, menu-items etc.
+ if( atk_obj == atk_get_focus_object() )
+ atk_state_set_add_state( pSet, ATK_STATE_FOCUSED );
+/* FIXME - should we do this ?
+ else
+ atk_state_set_remove_state( pSet, ATK_STATE_FOCUSED );
+*/
+ }
+ }
+
+ catch(const uno::Exception &e) {
+ g_warning( "Exception in wrapper_ref_state_set" );
+ atk_state_set_add_state( pSet, ATK_STATE_DEFUNCT );
+ }
+ }
+ else
+ atk_state_set_add_state( pSet, ATK_STATE_DEFUNCT );
+
+ return pSet;
+}
+
+/*****************************************************************************/
+
+
+static void
+atk_object_wrapper_finalize (GObject *obj)
+{
+ AtkObjectWrapper *pWrap = ATK_OBJECT_WRAPPER (obj);
+
+ if( pWrap->mpAccessible )
+ {
+ ooo_wrapper_registry_remove( pWrap->mpAccessible );
+ pWrap->mpAccessible->release();
+ pWrap->mpAccessible = NULL;
+ }
+
+ atk_object_wrapper_dispose( pWrap );
+
+ parent_class->finalize( obj );
+}
+
+static void
+atk_object_wrapper_class_init (AtkObjectWrapperClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS( klass );
+ AtkObjectClass *atk_class = ATK_OBJECT_CLASS( klass );
+
+ parent_class = (GObjectClass *) g_type_class_peek_parent (klass);
+
+ // GObject methods
+ gobject_class->finalize = atk_object_wrapper_finalize;
+
+ // AtkObject methods
+ atk_class->get_name = wrapper_get_name;
+ atk_class->get_description = wrapper_get_description;
+ atk_class->get_n_children = wrapper_get_n_children;
+ atk_class->ref_child = wrapper_ref_child;
+ atk_class->get_index_in_parent = wrapper_get_index_in_parent;
+ atk_class->ref_relation_set = wrapper_ref_relation_set;
+ atk_class->ref_state_set = wrapper_ref_state_set;
+}
+
+static void
+atk_object_wrapper_init (AtkObjectWrapper *wrapper,
+ AtkObjectWrapperClass)
+{
+ wrapper->mpAction = NULL;
+ wrapper->mpComponent = NULL;
+ wrapper->mpEditableText = NULL;
+ wrapper->mpHypertext = NULL;
+ wrapper->mpImage = NULL;
+ wrapper->mpSelection = NULL;
+ wrapper->mpTable = NULL;
+ wrapper->mpText = NULL;
+ wrapper->mpValue = NULL;
+}
+
+} // extern "C"
+
+GType
+atk_object_wrapper_get_type (void)
+{
+ static GType type = 0;
+
+ if (!type)
+ {
+ static const GTypeInfo typeInfo =
+ {
+ sizeof (AtkObjectWrapperClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) atk_object_wrapper_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL,
+ sizeof (AtkObjectWrapper),
+ 0,
+ (GInstanceInitFunc) atk_object_wrapper_init,
+ NULL
+ } ;
+ type = g_type_register_static (ATK_TYPE_OBJECT,
+ "OOoAtkObj",
+ &typeInfo, (GTypeFlags)0) ;
+ }
+ return type;
+}
+
+static bool
+isOfType( uno::XInterface *pInterface, const uno::Type & rType )
+{
+ g_return_val_if_fail( pInterface != NULL, false );
+
+ bool bIs = false;
+ try {
+ uno::Any aRet = pInterface->queryInterface( rType );
+
+ bIs = ( ( typelib_TypeClass_INTERFACE == aRet.pType->eTypeClass ) &&
+ ( aRet.pReserved != NULL ) );
+ } catch( const uno::Exception &e) { }
+
+ return bIs;
+}
+
+extern "C" {
+typedef GType (* GetGIfaceType ) (void);
+}
+const struct {
+ const char *name;
+ GInterfaceInitFunc aInit;
+ GetGIfaceType aGetGIfaceType;
+ const uno::Type & (*aGetUnoType) (void *);
+} aTypeTable[] = {
+// re-location heaven:
+ {
+ "Comp", (GInterfaceInitFunc) componentIfaceInit,
+ atk_component_get_type,
+ accessibility::XAccessibleComponent::static_type
+ },
+ {
+ "Act", (GInterfaceInitFunc) actionIfaceInit,
+ atk_action_get_type,
+ accessibility::XAccessibleAction::static_type
+ },
+ {
+ "Txt", (GInterfaceInitFunc) textIfaceInit,
+ atk_text_get_type,
+ accessibility::XAccessibleText::static_type
+ },
+ {
+ "Val", (GInterfaceInitFunc) valueIfaceInit,
+ atk_value_get_type,
+ accessibility::XAccessibleValue::static_type
+ },
+ {
+ "Tab", (GInterfaceInitFunc) tableIfaceInit,
+ atk_table_get_type,
+ accessibility::XAccessibleTable::static_type
+ },
+ {
+ "Edt", (GInterfaceInitFunc) editableTextIfaceInit,
+ atk_editable_text_get_type,
+ accessibility::XAccessibleEditableText::static_type
+ },
+ {
+ "Img", (GInterfaceInitFunc) imageIfaceInit,
+ atk_image_get_type,
+ accessibility::XAccessibleImage::static_type
+ },
+ {
+ "Hyp", (GInterfaceInitFunc) hypertextIfaceInit,
+ atk_hypertext_get_type,
+ accessibility::XAccessibleHypertext::static_type
+ },
+ {
+ "Sel", (GInterfaceInitFunc) selectionIfaceInit,
+ atk_selection_get_type,
+ accessibility::XAccessibleSelection::static_type
+ }
+ // AtkDocument is a nastily broken interface (so far)
+ // we could impl. get_document_type perhaps though.
+};
+
+const int aTypeTableSize = G_N_ELEMENTS( aTypeTable );
+
+static GType
+ensureTypeFor( uno::XInterface *pAccessible )
+{
+ int i;
+ int bTypes[ aTypeTableSize ] = { 0, };
+ rtl::OString aTypeName( "OOoAtkObj" );
+
+ for( i = 0; i < aTypeTableSize; i++ )
+ {
+ if( isOfType( pAccessible, aTypeTable[i].aGetUnoType(0) ) )
+ {
+ aTypeName += aTypeTable[i].name;
+ bTypes[i] = TRUE;
+ }
+// g_message( "Accessible %p has type '%s' (%d)",
+// pAccessible, aTypeTable[i].name, bTypes[i] );
+ }
+
+ GType nType = g_type_from_name( aTypeName );
+ if( nType == G_TYPE_INVALID )
+ {
+ GTypeInfo aTypeInfo = {
+ sizeof( AtkObjectWrapperClass ),
+ NULL, NULL, NULL, NULL, NULL,
+ sizeof( AtkObjectWrapper ),
+ 0, NULL, NULL
+ } ;
+ nType = g_type_register_static( ATK_TYPE_OBJECT_WRAPPER,
+ aTypeName, &aTypeInfo, (GTypeFlags)0 ) ;
+
+ for( int j = 0; j < aTypeTableSize; j++ )
+ if( bTypes[j] )
+ {
+ GInterfaceInfo aIfaceInfo = { NULL, NULL, NULL };
+ aIfaceInfo.interface_init = aTypeTable[j].aInit;
+ g_type_add_interface_static (nType, aTypeTable[j].aGetGIfaceType(),
+ &aIfaceInfo);
+ }
+ }
+ return nType;
+}
+
+AtkObject *
+atk_object_wrapper_ref( const uno::Reference< accessibility::XAccessible > &rxAccessible, bool create )
+{
+ g_return_val_if_fail( rxAccessible.get() != NULL, NULL );
+
+ AtkObject *obj = ooo_wrapper_registry_get(rxAccessible);
+ if( obj )
+ {
+ g_object_ref( obj );
+ return obj;
+ }
+
+ if( create )
+ return atk_object_wrapper_new( rxAccessible );
+
+ return NULL;
+}
+
+
+AtkObject *
+atk_object_wrapper_new( const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >& rxAccessible,
+ AtkObject* parent )
+{
+ g_return_val_if_fail( rxAccessible.get() != NULL, NULL );
+
+ AtkObjectWrapper *pWrap = NULL;
+
+ try {
+ uno::Reference< accessibility::XAccessibleContext > xContext(rxAccessible->getAccessibleContext());
+
+ g_return_val_if_fail( xContext.get() != NULL, NULL );
+
+ GType nType = ensureTypeFor( xContext.get() );
+ gpointer obj = g_object_new( nType, NULL);
+
+ pWrap = ATK_OBJECT_WRAPPER( obj );
+ pWrap->mpAccessible = rxAccessible.get();
+ rxAccessible->acquire();
+
+ pWrap->index_of_child_about_to_be_removed = -1;
+ pWrap->child_about_to_be_removed = NULL;
+
+ xContext->acquire();
+ pWrap->mpContext = xContext.get();
+
+ AtkObject* atk_obj = ATK_OBJECT(pWrap);
+ atk_obj->role = mapToAtkRole( xContext->getAccessibleRole() );
+ atk_obj->accessible_parent = parent;
+
+ ooo_wrapper_registry_add( rxAccessible, atk_obj );
+
+ if( parent )
+ g_object_ref( atk_obj->accessible_parent );
+ else
+ {
+ /* gail_focus_tracker remembers the focused object at the first
+ * parent in the hierachy that is a Gtk+ widget, but at the time the
+ * event gets processed (at idle), it may be too late to create the
+ * hierachy, so doing it now ..
+ */
+ uno::Reference< accessibility::XAccessible > xParent( xContext->getAccessibleParent() );
+
+ /* The top-level objects should never be of this class */
+ OSL_ASSERT( xParent.is() );
+
+ if( xParent.is() )
+ atk_obj->accessible_parent = atk_object_wrapper_ref( xParent );
+ }
+
+ // Attach a listener to the UNO object if it's not TRANSIENT
+ uno::Reference< accessibility::XAccessibleStateSet > xStateSet( xContext->getAccessibleStateSet() );
+ if( xStateSet.is() && ! xStateSet->contains( accessibility::AccessibleStateType::TRANSIENT ) )
+ {
+ uno::Reference< accessibility::XAccessibleEventBroadcaster > xBroadcaster(xContext, uno::UNO_QUERY);
+ if( xBroadcaster.is() )
+ xBroadcaster->addEventListener( static_cast< accessibility::XAccessibleEventListener * > ( new AtkListener(pWrap) ) );
+ else
+ OSL_ASSERT( false );
+ }
+
+ return ATK_OBJECT( pWrap );
+ }
+ catch (const uno::Exception &e)
+ {
+ if( pWrap )
+ g_object_unref( pWrap );
+
+ return NULL;
+ }
+}
+
+
+/*****************************************************************************/
+
+void atk_object_wrapper_add_child(AtkObjectWrapper* wrapper, AtkObject *child, gint index)
+{
+ AtkObject *atk_obj = ATK_OBJECT( wrapper );
+
+ atk_object_set_parent( child, atk_obj );
+ g_signal_emit_by_name( atk_obj, "children_changed::add", index, child, NULL );
+}
+
+/*****************************************************************************/
+
+void atk_object_wrapper_remove_child(AtkObjectWrapper* wrapper, AtkObject *child, gint index)
+{
+ /*
+ * the atk-bridge GTK+ module get's back to the event source to ref the child just
+ * vanishing, so we keep this reference because the semantic on OOo side is different.
+ */
+ wrapper->child_about_to_be_removed = child;
+ wrapper->index_of_child_about_to_be_removed = index;
+
+ g_signal_emit_by_name( ATK_OBJECT( wrapper ), "children_changed::remove", index, child, NULL );
+
+ wrapper->index_of_child_about_to_be_removed = -1;
+ wrapper->child_about_to_be_removed = NULL;
+}
+
+/*****************************************************************************/
+
+#define RELEASE(i) if( i ) { i->release(); i = NULL; }
+
+void atk_object_wrapper_dispose(AtkObjectWrapper* wrapper)
+{
+ RELEASE( wrapper->mpContext )
+ RELEASE( wrapper->mpAction )
+ RELEASE( wrapper->mpComponent )
+ RELEASE( wrapper->mpEditableText )
+ RELEASE( wrapper->mpHypertext )
+ RELEASE( wrapper->mpImage )
+ RELEASE( wrapper->mpSelection )
+ RELEASE( wrapper->mpMultiLineText )
+ RELEASE( wrapper->mpTable )
+ RELEASE( wrapper->mpText )
+ RELEASE( wrapper->mpTextMarkup )
+ RELEASE( wrapper->mpTextAttributes )
+ RELEASE( wrapper->mpValue )
+}
diff --git a/vcl/unx/gtk/a11y/atkwrapper.hxx b/vcl/unx/gtk/a11y/atkwrapper.hxx
new file mode 100644
index 000000000000..4252c0404833
--- /dev/null
+++ b/vcl/unx/gtk/a11y/atkwrapper.hxx
@@ -0,0 +1,125 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef __ATK_WRAPPER_HXX__
+#define __ATK_WRAPPER_HXX__
+
+#include <atk/atk.h>
+#include <com/sun/star/accessibility/XAccessible.hpp>
+
+extern "C" {
+
+typedef struct _AtkObjectWrapper AtkObjectWrapper;
+typedef struct _AtkObjectWrapperClass AtkObjectWrapperClass;
+
+namespace com { namespace sun { namespace star { namespace accessibility {
+ class XAccessibleAction;
+ class XAccessibleComponent;
+ class XAccessibleEditableText;
+ class XAccessibleHypertext;
+ class XAccessibleImage;
+ class XAccessibleMultiLineText;
+ class XAccessibleSelection;
+ class XAccessibleTable;
+ class XAccessibleText;
+ class XAccessibleTextMarkup;
+ class XAccessibleTextAttributes;
+ class XAccessibleValue;
+} } } }
+
+
+struct _AtkObjectWrapper
+{
+ AtkObject aParent;
+
+ ::com::sun::star::accessibility::XAccessible *mpAccessible;
+ ::com::sun::star::accessibility::XAccessibleContext *mpContext;
+ ::com::sun::star::accessibility::XAccessibleAction *mpAction;
+ ::com::sun::star::accessibility::XAccessibleComponent *mpComponent;
+ ::com::sun::star::accessibility::XAccessibleEditableText *mpEditableText;
+ ::com::sun::star::accessibility::XAccessibleHypertext *mpHypertext;
+ ::com::sun::star::accessibility::XAccessibleImage *mpImage;
+ ::com::sun::star::accessibility::XAccessibleMultiLineText *mpMultiLineText;
+ ::com::sun::star::accessibility::XAccessibleSelection *mpSelection;
+ ::com::sun::star::accessibility::XAccessibleTable *mpTable;
+ ::com::sun::star::accessibility::XAccessibleText *mpText;
+ ::com::sun::star::accessibility::XAccessibleTextMarkup *mpTextMarkup;
+ ::com::sun::star::accessibility::XAccessibleTextAttributes *mpTextAttributes;
+ ::com::sun::star::accessibility::XAccessibleValue *mpValue;
+
+ AtkObject *child_about_to_be_removed;
+ gint index_of_child_about_to_be_removed;
+// ::rtl::OString * m_pKeyBindings
+};
+
+struct _AtkObjectWrapperClass
+{
+ AtkObjectClass aParentClass;
+};
+
+GType atk_object_wrapper_get_type (void) G_GNUC_CONST;
+AtkObject * atk_object_wrapper_ref(
+ const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >& rxAccessible,
+ bool create = true );
+
+AtkObject * atk_object_wrapper_new(
+ const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >& rxAccessible,
+ AtkObject* parent = NULL );
+
+void atk_object_wrapper_add_child(AtkObjectWrapper* wrapper, AtkObject *child, gint index);
+void atk_object_wrapper_remove_child(AtkObjectWrapper* wrapper, AtkObject *child, gint index);
+
+void atk_object_wrapper_dispose(AtkObjectWrapper* wrapper);
+
+AtkStateType mapAtkState( sal_Int16 nState );
+
+void actionIfaceInit(AtkActionIface *iface);
+void componentIfaceInit(AtkComponentIface *iface);
+void editableTextIfaceInit(AtkEditableTextIface *iface);
+void hypertextIfaceInit(AtkHypertextIface *iface);
+void imageIfaceInit(AtkImageIface *iface);
+void selectionIfaceInit(AtkSelectionIface *iface);
+void tableIfaceInit(AtkTableIface *iface);
+void textIfaceInit(AtkTextIface *iface);
+void valueIfaceInit(AtkValueIface *iface);
+
+} // extern "C"
+
+#define ATK_TYPE_OBJECT_WRAPPER atk_object_wrapper_get_type()
+#define ATK_OBJECT_WRAPPER(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), ATK_TYPE_OBJECT_WRAPPER, AtkObjectWrapper))
+
+static inline gchar *
+OUStringToGChar(const rtl::OUString& rString )
+{
+ rtl::OString aUtf8 = rtl::OUStringToOString( rString, RTL_TEXTENCODING_UTF8 );
+ return g_strdup( aUtf8 );
+}
+
+#define OUStringToConstGChar( string ) rtl::OUStringToOString( string, RTL_TEXTENCODING_UTF8 ).getStr()
+
+#endif /* __ATK_WRAPPER_HXX__ */
diff --git a/vcl/unx/gtk/a11y/makefile.mk b/vcl/unx/gtk/a11y/makefile.mk
new file mode 100644
index 000000000000..14d3014ddf11
--- /dev/null
+++ b/vcl/unx/gtk/a11y/makefile.mk
@@ -0,0 +1,93 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#*************************************************************************
+
+PRJ=..$/..$/..
+
+PRJNAME=vcl
+TARGET=gtka11y
+ENABLE_EXCEPTIONS=TRUE
+
+# workaround for makedepend hang
+MKDEPENDSOLVER=
+NO_DEFAULT_STL=YES
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+
+# --- Files --------------------------------------------------------
+
+.IF "$(GUIBASE)"!="unx"
+
+dummy:
+ @echo "Nothing to build for GUIBASE $(GUIBASE)"
+
+.ELSE # "$(GUIBASE)"!="unx"
+
+.IF "$(ENABLE_GTK)" != ""
+
+PKGCONFIG_MODULES=gtk+-2.0
+.INCLUDE : pkg_config.mk
+
+CFLAGS+=-DVERSION=$(EMQ)"$(UPD)$(LAST_MINOR)$(EMQ)"
+
+ATKVERSION:=$(shell @$(PKG_CONFIG) --modversion atk | $(AWK) -v num=true -f $(SOLARENV)$/bin$/getcompver.awk)
+
+.IF "$(ATKVERSION)" >= "000100070000"
+CFLAGS+=-DHAS_ATKRECTANGLE
+.ENDIF
+
+SLOFILES=\
+ $(SLO)$/atkaction.obj \
+ $(SLO)$/atkbridge.obj \
+ $(SLO)$/atkcomponent.obj \
+ $(SLO)$/atkeditabletext.obj \
+ $(SLO)$/atkfactory.obj \
+ $(SLO)$/atkhypertext.obj \
+ $(SLO)$/atkimage.obj \
+ $(SLO)$/atklistener.obj \
+ $(SLO)$/atkregistry.obj \
+ $(SLO)$/atkselection.obj \
+ $(SLO)$/atktable.obj \
+ $(SLO)$/atktext.obj \
+ $(SLO)$/atktextattributes.obj \
+ $(SLO)$/atkutil.obj \
+ $(SLO)$/atkvalue.obj \
+ $(SLO)$/atkwindow.obj \
+ $(SLO)$/atkwrapper.obj
+
+.ELSE # "$(ENABLE_GTK)" != ""
+
+dummy:
+ @echo GTK disabled - nothing to build
+.ENDIF
+.ENDIF # "$(GUIBASE)"!="unx"
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
+
diff --git a/vcl/unx/gtk/app/gtkdata.cxx b/vcl/unx/gtk/app/gtkdata.cxx
new file mode 100644
index 000000000000..f308822df147
--- /dev/null
+++ b/vcl/unx/gtk/app/gtkdata.cxx
@@ -0,0 +1,1019 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#define _SV_SALDATA_CXX
+
+// -=-= #includes =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <errno.h>
+#include <poll.h>
+#ifdef FREEBSD
+#include <sys/types.h>
+#include <sys/time.h>
+#include <unistd.h>
+#endif
+#include <plugins/gtk/gtkdata.hxx>
+#include <plugins/gtk/gtkinst.hxx>
+#include <plugins/gtk/gtkframe.hxx>
+#include <salobj.h>
+#include <osl/thread.h>
+#include <osl/process.h>
+
+#include <tools/debug.hxx>
+#include "i18n_im.hxx"
+#include "i18n_xkb.hxx"
+#include <wmadaptor.hxx>
+
+#include "../../unx/source/inc/salcursors.h"
+
+#include <vcl/svapp.hxx>
+
+using namespace rtl;
+using namespace vcl_sal;
+
+/***************************************************************************
+ * class GtkDisplay *
+ ***************************************************************************/
+
+GtkSalDisplay::GtkSalDisplay( GdkDisplay* pDisplay )
+ : SalDisplay( gdk_x11_display_get_xdisplay( pDisplay ) ),
+ m_pGdkDisplay( pDisplay ),
+ m_bStartupCompleted( false )
+{
+ m_bUseRandRWrapper = false; // use gdk signal instead
+ for(int i = 0; i < POINTER_COUNT; i++)
+ m_aCursors[ i ] = NULL;
+ Init ();
+}
+
+GtkSalDisplay::~GtkSalDisplay()
+{
+ if( !m_bStartupCompleted )
+ gdk_notify_startup_complete();
+ doDestruct();
+
+ for(int i = 0; i < POINTER_COUNT; i++)
+ if( m_aCursors[ i ] )
+ gdk_cursor_unref( m_aCursors[ i ] );
+
+ pDisp_ = NULL;
+}
+
+void GtkSalDisplay::deregisterFrame( SalFrame* pFrame )
+{
+ if( m_pCapture == pFrame )
+ {
+ static_cast<GtkSalFrame*>(m_pCapture)->grabPointer( FALSE );
+ m_pCapture = NULL;
+ }
+ SalDisplay::deregisterFrame( pFrame );
+}
+
+extern "C" {
+GdkFilterReturn call_filterGdkEvent( GdkXEvent* sys_event,
+ GdkEvent* event,
+ gpointer data )
+{
+ return GtkSalDisplay::filterGdkEvent( sys_event, event, data );
+}
+
+void signalKeysChanged( GdkKeymap*, gpointer data )
+{
+ GtkSalDisplay* pDisp = (GtkSalDisplay*)data;
+ pDisp->GetKeyboardName(TRUE);
+}
+
+void signalScreenSizeChanged( GdkScreen* pScreen, gpointer data )
+{
+ GtkSalDisplay* pDisp = (GtkSalDisplay*)data;
+ pDisp->screenSizeChanged( pScreen );
+}
+
+void signalMonitorsChanged( GdkScreen* pScreen, gpointer data )
+{
+ GtkSalDisplay* pDisp = (GtkSalDisplay*)data;
+ pDisp->monitorsChanged( pScreen );
+}
+
+}
+
+GdkFilterReturn GtkSalDisplay::filterGdkEvent( GdkXEvent* sys_event,
+ GdkEvent*,
+ gpointer data )
+{
+ GdkFilterReturn aFilterReturn = GDK_FILTER_CONTINUE;
+
+ XEvent *pEvent = (XEvent *)sys_event;
+ GtkSalDisplay *pDisplay = (GtkSalDisplay *)data;
+
+ // dispatch all XEvents to event callback
+ if( GetSalData()->m_pInstance->
+ CallEventCallback( pEvent, sizeof( XEvent ) ) )
+ aFilterReturn = GDK_FILTER_REMOVE;
+
+ GTK_YIELD_GRAB();
+
+ if (pDisplay->GetDisplay() == pEvent->xany.display )
+ {
+ // #i53471# gtk has no callback mechanism that lets us be notified
+ // when settings (as in XSETTING and opposed to styles) are changed.
+ // so we need to listen for corresponding property notifications here
+ // these should be rare enough so that we can assume that the settings
+ // actually change when a corresponding PropertyNotify occurs
+ if( pEvent->type == PropertyNotify &&
+ pEvent->xproperty.atom == pDisplay->getWMAdaptor()->getAtom( WMAdaptor::XSETTINGS ) &&
+ ! pDisplay->m_aFrames.empty()
+ )
+ {
+ pDisplay->SendInternalEvent( pDisplay->m_aFrames.front(), NULL, SALEVENT_SETTINGSCHANGED );
+ }
+ // let's see if one of our frames wants to swallow these events
+ // get the frame
+ for( std::list< SalFrame* >::const_iterator it = pDisplay->m_aFrames.begin();
+ it != pDisplay->m_aFrames.end(); ++it )
+ {
+ GtkSalFrame* pFrame = static_cast<GtkSalFrame*>(*it);
+ if( (GdkNativeWindow)pFrame->GetSystemData()->aWindow == pEvent->xany.window ||
+ ( pFrame->getForeignParent() && pFrame->getForeignParentWindow() == pEvent->xany.window ) ||
+ ( pFrame->getForeignTopLevel() && pFrame->getForeignTopLevelWindow() == pEvent->xany.window )
+ )
+ {
+ if( ! pFrame->Dispatch( pEvent ) )
+ aFilterReturn = GDK_FILTER_REMOVE;
+ break;
+ }
+ }
+ X11SalObject::Dispatch( pEvent );
+ }
+
+ return aFilterReturn;
+}
+
+void GtkSalDisplay::screenSizeChanged( GdkScreen* pScreen )
+{
+ if( pScreen )
+ {
+ int nScreen = gdk_screen_get_number( pScreen );
+ if( nScreen < static_cast<int>(m_aScreens.size()) )
+ {
+ ScreenData& rSD = const_cast<ScreenData&>(m_aScreens[nScreen]);
+ if( rSD.m_bInit )
+ {
+ rSD.m_aSize = Size( gdk_screen_get_width( pScreen ),
+ gdk_screen_get_height( pScreen ) );
+ if( ! m_aFrames.empty() )
+ m_aFrames.front()->CallCallback( SALEVENT_DISPLAYCHANGED, 0 );
+ }
+ }
+ else
+ {
+ DBG_ERROR( "unknown screen changed size" );
+ }
+ }
+}
+
+void GtkSalDisplay::monitorsChanged( GdkScreen* pScreen )
+{
+ if( pScreen )
+ {
+ if( gdk_display_get_n_screens(m_pGdkDisplay) == 1 )
+ {
+ int nScreen = gdk_screen_get_number( pScreen );
+ if( nScreen == m_nDefaultScreen ) //To-Do, make m_aXineramaScreens a per-screen thing ?
+ {
+ gint nMonitors = gdk_screen_get_n_monitors(pScreen);
+ m_aXineramaScreens = std::vector<Rectangle>();
+ m_aXineramaScreenIndexMap = std::vector<int>(nMonitors);
+ for (gint i = 0; i < nMonitors; ++i)
+ {
+ GdkRectangle dest;
+ gdk_screen_get_monitor_geometry(pScreen, i, &dest);
+ m_aXineramaScreenIndexMap[i] = addXineramaScreenUnique( dest.x, dest.y, dest.width, dest.height );
+ }
+ m_bXinerama = m_aXineramaScreens.size() > 1;
+ if( ! m_aFrames.empty() )
+ m_aFrames.front()->CallCallback( SALEVENT_DISPLAYCHANGED, 0 );
+ }
+ else
+ {
+ DBG_ERROR( "monitors for non-default screen changed, extend-me" );
+ }
+ }
+ }
+}
+
+extern "C"
+{
+ typedef gint(* screen_get_primary_monitor)(GdkScreen *screen);
+}
+
+int GtkSalDisplay::GetDefaultMonitorNumber() const
+{
+ int n = 0;
+ GdkScreen* pScreen = gdk_display_get_screen( m_pGdkDisplay, m_nDefaultScreen );
+#if GTK_CHECK_VERSION(2,20,0)
+ n = m_aXineramaScreenIndexMap[gdk_screen_get_primary_monitor(pScreen)];
+#else
+ static screen_get_primary_monitor sym_gdk_screen_get_primary_monitor =
+ (screen_get_primary_monitor)osl_getAsciiFunctionSymbol( GetSalData()->m_pPlugin, "gdk_screen_get_primary_monitor" );
+ if (sym_gdk_screen_get_primary_monitor)
+ n = m_aXineramaScreenIndexMap[sym_gdk_screen_get_primary_monitor( pScreen )];
+#endif
+ return n;
+}
+
+void GtkSalDisplay::initScreen( int nScreen ) const
+{
+ if( nScreen < 0 || nScreen >= static_cast<int>(m_aScreens.size()) )
+ nScreen = m_nDefaultScreen;
+ ScreenData& rSD = const_cast<ScreenData&>(m_aScreens[nScreen]);
+ if( rSD.m_bInit )
+ return;
+
+ // choose visual for screen
+ SalDisplay::initScreen( nScreen );
+ // now set a gdk default colormap matching the chosen visual to the screen
+ GdkVisual* pVis = gdkx_visual_get( rSD.m_aVisual.visualid );
+ GdkScreen* pScreen = gdk_display_get_screen( m_pGdkDisplay, nScreen );
+ if( pVis )
+ {
+ GdkColormap* pDefCol = gdk_screen_get_default_colormap( pScreen );
+ GdkVisual* pDefVis = gdk_colormap_get_visual( pDefCol );
+ if( pDefVis != pVis )
+ {
+ pDefCol = gdk_x11_colormap_foreign_new( pVis, rSD.m_aColormap.GetXColormap() );
+ gdk_screen_set_default_colormap( pScreen, pDefCol );
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "set new gdk color map for screen %d\n", nScreen );
+ #endif
+ }
+ }
+ #if OSL_DEBUG_LEVEL > 1
+ else
+ fprintf( stderr, "not GdkVisual for visual id %d\n", (int)rSD.m_aVisual.visualid );
+ #endif
+}
+
+long GtkSalDisplay::Dispatch( XEvent* pEvent )
+{
+ if( GetDisplay() == pEvent->xany.display )
+ {
+ // let's see if one of our frames wants to swallow these events
+ // get the child frame
+ for( std::list< SalFrame* >::const_iterator it = m_aFrames.begin();
+ it != m_aFrames.end(); ++it )
+ {
+ if( (GdkNativeWindow)(*it)->GetSystemData()->aWindow == pEvent->xany.window )
+ return static_cast<GtkSalFrame*>(*it)->Dispatch( pEvent );
+ }
+ }
+
+ return GDK_FILTER_CONTINUE;
+}
+
+GdkCursor* GtkSalDisplay::getFromXPM( const char *pBitmap,
+ const char *pMask,
+ int nWidth, int nHeight,
+ int nXHot, int nYHot )
+{
+ GdkScreen *pScreen = gdk_display_get_default_screen( m_pGdkDisplay );
+ GdkDrawable *pDrawable = GDK_DRAWABLE( gdk_screen_get_root_window (pScreen) );
+ GdkBitmap *pBitmapPix = gdk_bitmap_create_from_data
+ ( pDrawable, pBitmap, nWidth, nHeight );
+ GdkBitmap *pMaskPix = gdk_bitmap_create_from_data
+ ( pDrawable, pMask, nWidth, nHeight );
+ GdkColormap *pColormap = gdk_drawable_get_colormap( pDrawable );
+
+ GdkColor aWhite = { 0, 0xffff, 0xffff, 0xffff };
+ GdkColor aBlack = { 0, 0, 0, 0 };
+
+ gdk_colormap_alloc_color( pColormap, &aBlack, FALSE, TRUE);
+ gdk_colormap_alloc_color( pColormap, &aWhite, FALSE, TRUE);
+
+ return gdk_cursor_new_from_pixmap
+ ( pBitmapPix, pMaskPix,
+ &aBlack, &aWhite, nXHot, nYHot);
+}
+
+#define MAKE_CURSOR( vcl_name, name ) \
+ case vcl_name: \
+ pCursor = getFromXPM( name##curs##_bits, name##mask##_bits, \
+ name##curs_width, name##curs_height, \
+ name##curs_x_hot, name##curs_y_hot ); \
+ break
+#define MAP_BUILTIN( vcl_name, gdk_name ) \
+ case vcl_name: \
+ pCursor = gdk_cursor_new_for_display( m_pGdkDisplay, gdk_name ); \
+ break
+
+GdkCursor *GtkSalDisplay::getCursor( PointerStyle ePointerStyle )
+{
+ if( ePointerStyle > POINTER_COUNT )
+ return NULL;
+
+ if ( !m_aCursors[ ePointerStyle ] )
+ {
+ GdkCursor *pCursor = NULL;
+
+ switch( ePointerStyle )
+ {
+ MAP_BUILTIN( POINTER_ARROW, GDK_LEFT_PTR );
+ MAP_BUILTIN( POINTER_TEXT, GDK_XTERM );
+ MAP_BUILTIN( POINTER_HELP, GDK_QUESTION_ARROW );
+ MAP_BUILTIN( POINTER_CROSS, GDK_CROSSHAIR );
+ MAP_BUILTIN( POINTER_WAIT, GDK_WATCH );
+
+ MAP_BUILTIN( POINTER_NSIZE, GDK_SB_V_DOUBLE_ARROW );
+ MAP_BUILTIN( POINTER_SSIZE, GDK_SB_V_DOUBLE_ARROW );
+ MAP_BUILTIN( POINTER_WSIZE, GDK_SB_H_DOUBLE_ARROW );
+ MAP_BUILTIN( POINTER_ESIZE, GDK_SB_H_DOUBLE_ARROW );
+
+ MAP_BUILTIN( POINTER_NWSIZE, GDK_TOP_LEFT_CORNER );
+ MAP_BUILTIN( POINTER_NESIZE, GDK_TOP_RIGHT_CORNER );
+ MAP_BUILTIN( POINTER_SWSIZE, GDK_BOTTOM_LEFT_CORNER );
+ MAP_BUILTIN( POINTER_SESIZE, GDK_BOTTOM_RIGHT_CORNER );
+
+ MAP_BUILTIN( POINTER_WINDOW_NSIZE, GDK_TOP_SIDE );
+ MAP_BUILTIN( POINTER_WINDOW_SSIZE, GDK_BOTTOM_SIDE );
+ MAP_BUILTIN( POINTER_WINDOW_WSIZE, GDK_LEFT_SIDE );
+ MAP_BUILTIN( POINTER_WINDOW_ESIZE, GDK_RIGHT_SIDE );
+
+ MAP_BUILTIN( POINTER_WINDOW_NWSIZE, GDK_TOP_LEFT_CORNER );
+ MAP_BUILTIN( POINTER_WINDOW_NESIZE, GDK_TOP_RIGHT_CORNER );
+ MAP_BUILTIN( POINTER_WINDOW_SWSIZE, GDK_BOTTOM_LEFT_CORNER );
+ MAP_BUILTIN( POINTER_WINDOW_SESIZE, GDK_BOTTOM_RIGHT_CORNER );
+
+ MAP_BUILTIN( POINTER_HSIZEBAR, GDK_SB_H_DOUBLE_ARROW );
+ MAP_BUILTIN( POINTER_VSIZEBAR, GDK_SB_V_DOUBLE_ARROW );
+
+ MAP_BUILTIN( POINTER_REFHAND, GDK_HAND1 );
+ MAP_BUILTIN( POINTER_HAND, GDK_HAND2 );
+ MAP_BUILTIN( POINTER_PEN, GDK_PENCIL );
+
+ MAP_BUILTIN( POINTER_HSPLIT, GDK_SB_H_DOUBLE_ARROW );
+ MAP_BUILTIN( POINTER_VSPLIT, GDK_SB_V_DOUBLE_ARROW );
+
+ MAP_BUILTIN( POINTER_MOVE, GDK_FLEUR );
+
+ MAKE_CURSOR( POINTER_NULL, null );
+ MAKE_CURSOR( POINTER_MAGNIFY, magnify_ );
+ MAKE_CURSOR( POINTER_FILL, fill_ );
+ MAKE_CURSOR( POINTER_MOVEDATA, movedata_ );
+ MAKE_CURSOR( POINTER_COPYDATA, copydata_ );
+ MAKE_CURSOR( POINTER_MOVEFILE, movefile_ );
+ MAKE_CURSOR( POINTER_COPYFILE, copyfile_ );
+ MAKE_CURSOR( POINTER_MOVEFILES, movefiles_ );
+ MAKE_CURSOR( POINTER_COPYFILES, copyfiles_ );
+ MAKE_CURSOR( POINTER_NOTALLOWED, nodrop_ );
+ MAKE_CURSOR( POINTER_ROTATE, rotate_ );
+ MAKE_CURSOR( POINTER_HSHEAR, hshear_ );
+ MAKE_CURSOR( POINTER_VSHEAR, vshear_ );
+ MAKE_CURSOR( POINTER_DRAW_LINE, drawline_ );
+ MAKE_CURSOR( POINTER_DRAW_RECT, drawrect_ );
+ MAKE_CURSOR( POINTER_DRAW_POLYGON, drawpolygon_ );
+ MAKE_CURSOR( POINTER_DRAW_BEZIER, drawbezier_ );
+ MAKE_CURSOR( POINTER_DRAW_ARC, drawarc_ );
+ MAKE_CURSOR( POINTER_DRAW_PIE, drawpie_ );
+ MAKE_CURSOR( POINTER_DRAW_CIRCLECUT, drawcirclecut_ );
+ MAKE_CURSOR( POINTER_DRAW_ELLIPSE, drawellipse_ );
+ MAKE_CURSOR( POINTER_DRAW_CONNECT, drawconnect_ );
+ MAKE_CURSOR( POINTER_DRAW_TEXT, drawtext_ );
+ MAKE_CURSOR( POINTER_MIRROR, mirror_ );
+ MAKE_CURSOR( POINTER_CROOK, crook_ );
+ MAKE_CURSOR( POINTER_CROP, crop_ );
+ MAKE_CURSOR( POINTER_MOVEPOINT, movepoint_ );
+ MAKE_CURSOR( POINTER_MOVEBEZIERWEIGHT, movebezierweight_ );
+ MAKE_CURSOR( POINTER_DRAW_FREEHAND, drawfreehand_ );
+ MAKE_CURSOR( POINTER_DRAW_CAPTION, drawcaption_ );
+ MAKE_CURSOR( POINTER_LINKDATA, linkdata_ );
+ MAKE_CURSOR( POINTER_MOVEDATALINK, movedlnk_ );
+ MAKE_CURSOR( POINTER_COPYDATALINK, copydlnk_ );
+ MAKE_CURSOR( POINTER_LINKFILE, linkfile_ );
+ MAKE_CURSOR( POINTER_MOVEFILELINK, moveflnk_ );
+ MAKE_CURSOR( POINTER_COPYFILELINK, copyflnk_ );
+ MAKE_CURSOR( POINTER_CHART, chart_ );
+ MAKE_CURSOR( POINTER_DETECTIVE, detective_ );
+ MAKE_CURSOR( POINTER_PIVOT_COL, pivotcol_ );
+ MAKE_CURSOR( POINTER_PIVOT_ROW, pivotrow_ );
+ MAKE_CURSOR( POINTER_PIVOT_FIELD, pivotfld_ );
+ MAKE_CURSOR( POINTER_PIVOT_DELETE, pivotdel_ );
+ MAKE_CURSOR( POINTER_CHAIN, chain_ );
+ MAKE_CURSOR( POINTER_CHAIN_NOTALLOWED, chainnot_ );
+ MAKE_CURSOR( POINTER_TIMEEVENT_MOVE, timemove_ );
+ MAKE_CURSOR( POINTER_TIMEEVENT_SIZE, timesize_ );
+ MAKE_CURSOR( POINTER_AUTOSCROLL_N, asn_ );
+ MAKE_CURSOR( POINTER_AUTOSCROLL_S, ass_ );
+ MAKE_CURSOR( POINTER_AUTOSCROLL_W, asw_ );
+ MAKE_CURSOR( POINTER_AUTOSCROLL_E, ase_ );
+ MAKE_CURSOR( POINTER_AUTOSCROLL_NW, asnw_ );
+ MAKE_CURSOR( POINTER_AUTOSCROLL_NE, asne_ );
+ MAKE_CURSOR( POINTER_AUTOSCROLL_SW, assw_ );
+ MAKE_CURSOR( POINTER_AUTOSCROLL_SE, asse_ );
+ MAKE_CURSOR( POINTER_AUTOSCROLL_NS, asns_ );
+ MAKE_CURSOR( POINTER_AUTOSCROLL_WE, aswe_ );
+ MAKE_CURSOR( POINTER_AUTOSCROLL_NSWE, asnswe_ );
+ MAKE_CURSOR( POINTER_AIRBRUSH, airbrush_ );
+ MAKE_CURSOR( POINTER_TEXT_VERTICAL, vertcurs_ );
+
+ // --> FME 2004-07-30 #i32329# Enhanced table selection
+ MAKE_CURSOR( POINTER_TAB_SELECT_S, tblsels_ );
+ MAKE_CURSOR( POINTER_TAB_SELECT_E, tblsele_ );
+ MAKE_CURSOR( POINTER_TAB_SELECT_SE, tblselse_ );
+ MAKE_CURSOR( POINTER_TAB_SELECT_W, tblselw_ );
+ MAKE_CURSOR( POINTER_TAB_SELECT_SW, tblselsw_ );
+ // <--
+
+ // --> FME 2004-08-16 #i20119# Paintbrush tool
+ MAKE_CURSOR( POINTER_PAINTBRUSH, paintbrush_ );
+ // <--
+
+ default:
+ fprintf( stderr, "pointer %d not implemented", ePointerStyle );
+ break;
+ }
+ if( !pCursor )
+ pCursor = gdk_cursor_new_for_display( m_pGdkDisplay, GDK_LEFT_PTR );
+
+ m_aCursors[ ePointerStyle ] = pCursor;
+ }
+
+ return m_aCursors[ ePointerStyle ];
+}
+
+int GtkSalDisplay::CaptureMouse( SalFrame* pSFrame )
+{
+ GtkSalFrame* pFrame = static_cast<GtkSalFrame*>(pSFrame);
+
+ if( !pFrame )
+ {
+ if( m_pCapture )
+ static_cast<GtkSalFrame*>(m_pCapture)->grabPointer( FALSE );
+ m_pCapture = NULL;
+ return 0;
+ }
+
+ if( m_pCapture )
+ {
+ if( pFrame == m_pCapture )
+ return 1;
+ static_cast<GtkSalFrame*>(m_pCapture)->grabPointer( FALSE );
+ }
+
+ m_pCapture = pFrame;
+ static_cast<GtkSalFrame*>(pFrame)->grabPointer( TRUE );
+ return 1;
+}
+
+/***************************************************************************
+ * class GtkXLib *
+ ***************************************************************************/
+
+class GtkXLib : public SalXLib
+{
+ GtkSalDisplay *m_pGtkSalDisplay;
+ std::list<GSource *> m_aSources;
+ GSource *m_pTimeout;
+ GSource *m_pUserEvent;
+ oslMutex m_aDispatchMutex;
+ oslCondition m_aDispatchCondition;
+ XIOErrorHandler m_aOrigGTKXIOErrorHandler;
+
+public:
+ static gboolean timeoutFn(gpointer data);
+ static gboolean userEventFn(gpointer data);
+
+ GtkXLib();
+ virtual ~GtkXLib();
+
+ virtual void Init();
+ virtual void Yield( bool bWait, bool bHandleAllCurrentEvents );
+ virtual void Insert( int fd, void* data,
+ YieldFunc pending,
+ YieldFunc queued,
+ YieldFunc handle );
+ virtual void Remove( int fd );
+
+ virtual void StartTimer( ULONG nMS );
+ virtual void StopTimer();
+ virtual void Wakeup();
+ virtual void PostUserEvent();
+};
+
+GtkXLib::GtkXLib()
+{
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "GtkXLib::GtkXLib()\n" );
+#endif
+ m_pGtkSalDisplay = NULL;
+ m_pTimeout = NULL;
+ m_nTimeoutMS = 0;
+ m_pUserEvent = NULL;
+ m_aDispatchCondition = osl_createCondition();
+ m_aDispatchMutex = osl_createMutex();
+ m_aOrigGTKXIOErrorHandler = NULL;
+}
+
+GtkXLib::~GtkXLib()
+{
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "GtkXLib::~GtkXLib()\n" );
+#endif
+ StopTimer();
+ // sanity check: at this point nobody should be yielding, but wake them
+ // up anyway before the condition they're waiting on gets destroyed.
+ osl_setCondition( m_aDispatchCondition );
+ osl_destroyCondition( m_aDispatchCondition );
+ osl_destroyMutex( m_aDispatchMutex );
+
+ PopXErrorLevel();
+ XSetIOErrorHandler (m_aOrigGTKXIOErrorHandler);
+}
+
+void GtkXLib::Init()
+{
+ int i;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "GtkXLib::Init()\n" );
+#endif
+ XrmInitialize();
+
+ gtk_set_locale();
+
+ /*
+ * open connection to X11 Display
+ * try in this order:
+ * o -display command line parameter,
+ * o $DISPLAY environment variable
+ * o default display
+ */
+
+ GdkDisplay *pGdkDisp = NULL;
+
+ // is there a -display command line parameter?
+ rtl_TextEncoding aEnc = osl_getThreadTextEncoding();
+ int nParams = osl_getCommandArgCount();
+ rtl::OString aDisplay;
+ rtl::OUString aParam, aBin;
+ char** pCmdLineAry = new char*[ nParams+1 ];
+ osl_getExecutableFile( &aParam.pData );
+ osl_getSystemPathFromFileURL( aParam.pData, &aBin.pData );
+ pCmdLineAry[0] = g_strdup( OUStringToOString( aBin, aEnc ).getStr() );
+ for (i=0; i<nParams; i++)
+ {
+ osl_getCommandArg(i, &aParam.pData );
+ OString aBParam( OUStringToOString( aParam, aEnc ) );
+
+ if( aParam.equalsAscii( "-display" ) || aParam.equalsAscii( "--display" ) )
+ {
+ pCmdLineAry[i+1] = g_strdup( "--display" );
+ osl_getCommandArg(i+1, &aParam.pData );
+ aDisplay = rtl::OUStringToOString( aParam, aEnc );
+ }
+ else
+ pCmdLineAry[i+1] = g_strdup( aBParam.getStr() );
+ }
+ // add executable
+ nParams++;
+
+ g_set_application_name(X11SalData::getFrameClassName());
+
+ // Set consistant name of the root accessible
+ rtl::OUString aAppName = Application::GetAppName();
+ if( aAppName.getLength() > 0 )
+ {
+ rtl::OString aPrgName = rtl::OUStringToOString(aAppName, aEnc);
+ g_set_prgname(aPrgName);
+ }
+
+ // init gtk/gdk
+ gtk_init_check( &nParams, &pCmdLineAry );
+
+ //gtk_init_check sets XError/XIOError handlers, we want our own one
+ m_aOrigGTKXIOErrorHandler = XSetIOErrorHandler ( (XIOErrorHandler)X11SalData::XIOErrorHdl );
+ PushXErrorLevel( !!getenv( "SAL_IGNOREXERRORS" ) );
+
+ for (i = 0; i < nParams; i++ )
+ g_free( pCmdLineAry[i] );
+ delete [] pCmdLineAry;
+
+#if OSL_DEBUG_LEVEL > 1
+ if (g_getenv ("SAL_DEBUG_UPDATES"))
+ gdk_window_set_debug_updates (TRUE);
+#endif
+
+ pGdkDisp = gdk_display_get_default();
+ if ( !pGdkDisp )
+ {
+ rtl::OUString aProgramFileURL;
+ osl_getExecutableFile( &aProgramFileURL.pData );
+ rtl::OUString aProgramSystemPath;
+ osl_getSystemPathFromFileURL (aProgramFileURL.pData, &aProgramSystemPath.pData);
+ rtl::OString aProgramName = rtl::OUStringToOString(
+ aProgramSystemPath,
+ osl_getThreadTextEncoding() );
+ fprintf( stderr, "%s X11 error: Can't open display: %s\n",
+ aProgramName.getStr(), aDisplay.getStr());
+ fprintf( stderr, " Set DISPLAY environment variable, use -display option\n");
+ fprintf( stderr, " or check permissions of your X-Server\n");
+ fprintf( stderr, " (See \"man X\" resp. \"man xhost\" for details)\n");
+ fflush( stderr );
+ exit(0);
+ }
+
+ /*
+ * if a -display switch was used, we need
+ * to set the environment accoringly since
+ * the clipboard build another connection
+ * to the xserver using $DISPLAY
+ */
+ rtl::OUString envVar(RTL_CONSTASCII_USTRINGPARAM("DISPLAY"));
+ const gchar *name = gdk_display_get_name( pGdkDisp );
+ rtl::OUString envValue(name, strlen(name), aEnc);
+ osl_setEnvironment(envVar.pData, envValue.pData);
+
+ Display *pDisp = gdk_x11_display_get_xdisplay( pGdkDisp );
+
+ m_pGtkSalDisplay = new GtkSalDisplay( pGdkDisp );
+
+ gdk_window_add_filter( NULL, call_filterGdkEvent, m_pGtkSalDisplay );
+
+ PushXErrorLevel( true );
+ SalI18N_KeyboardExtension *pKbdExtension = new SalI18N_KeyboardExtension( pDisp );
+ XSync( pDisp, False );
+
+ pKbdExtension->UseExtension( ! HasXErrorOccured() );
+ PopXErrorLevel();
+
+ m_pGtkSalDisplay->SetKbdExtension( pKbdExtension );
+
+ g_signal_connect( G_OBJECT(gdk_keymap_get_default()), "keys_changed", G_CALLBACK(signalKeysChanged), m_pGtkSalDisplay );
+
+ // add signal handler to notify screen size changes
+ int nScreens = gdk_display_get_n_screens( pGdkDisp );
+ for( int n = 0; n < nScreens; n++ )
+ {
+ GdkScreen *pScreen = gdk_display_get_screen( pGdkDisp, n );
+ if( pScreen )
+ {
+ g_signal_connect( G_OBJECT(pScreen), "size-changed", G_CALLBACK(signalScreenSizeChanged), m_pGtkSalDisplay );
+ if( ! gtk_check_version( 2, 14, 0 ) ) // monitors-changed came in with 2.14, avoid an assertion
+ g_signal_connect( G_OBJECT(pScreen), "monitors-changed", G_CALLBACK(signalMonitorsChanged), m_pGtkSalDisplay );
+ }
+ }
+}
+
+extern "C"
+{
+ gboolean call_timeoutFn(gpointer data)
+ {
+ return GtkXLib::timeoutFn(data);
+ }
+}
+
+gboolean GtkXLib::timeoutFn(gpointer data)
+{
+ SalData *pSalData = GetSalData();
+ GtkXLib *pThis = (GtkXLib *) data;
+
+ pSalData->m_pInstance->GetYieldMutex()->acquire();
+
+ if( pThis->m_pTimeout )
+ {
+ g_source_unref (pThis->m_pTimeout);
+ pThis->m_pTimeout = NULL;
+ }
+
+ // Auto-restart immediately
+ pThis->StartTimer( pThis->m_nTimeoutMS );
+
+ GetX11SalData()->Timeout();
+
+ pSalData->m_pInstance->GetYieldMutex()->release();
+
+ return FALSE;
+}
+
+void GtkXLib::StartTimer( ULONG nMS )
+{
+ m_nTimeoutMS = nMS; // for restarting
+
+ if (m_pTimeout)
+ {
+ g_source_destroy (m_pTimeout);
+ g_source_unref (m_pTimeout);
+ }
+
+ m_pTimeout = g_timeout_source_new (m_nTimeoutMS);
+ // #i36226# timers should be executed with lower priority
+ // than XEvents like in generic plugin
+ g_source_set_priority( m_pTimeout, G_PRIORITY_LOW );
+ g_source_set_can_recurse (m_pTimeout, TRUE);
+ g_source_set_callback (m_pTimeout, call_timeoutFn,
+ (gpointer) this, NULL);
+ g_source_attach (m_pTimeout, g_main_context_default ());
+
+ SalXLib::StartTimer( nMS );
+}
+
+void GtkXLib::StopTimer()
+{
+ SalXLib::StopTimer();
+
+ if (m_pTimeout)
+ {
+ g_source_destroy (m_pTimeout);
+ g_source_unref (m_pTimeout);
+ m_pTimeout = NULL;
+ }
+}
+
+extern "C"
+{
+ gboolean call_userEventFn( gpointer data )
+ {
+ return GtkXLib::userEventFn( data );
+ }
+}
+
+gboolean GtkXLib::userEventFn(gpointer data)
+{
+ gboolean bContinue;
+ GtkXLib *pThis = (GtkXLib *) data;
+ SalData *pSalData = GetSalData();
+
+ pSalData->m_pInstance->GetYieldMutex()->acquire();
+ pThis->m_pGtkSalDisplay->EventGuardAcquire();
+
+ if( !pThis->m_pGtkSalDisplay->HasMoreEvents() )
+ {
+ if( pThis->m_pUserEvent )
+ {
+ g_source_unref (pThis->m_pUserEvent);
+ pThis->m_pUserEvent = NULL;
+ }
+ bContinue = FALSE;
+ }
+ else
+ bContinue = TRUE;
+
+ pThis->m_pGtkSalDisplay->EventGuardRelease();
+
+ pThis->m_pGtkSalDisplay->DispatchInternalEvent();
+
+ pSalData->m_pInstance->GetYieldMutex()->release();
+
+ return bContinue;
+}
+
+// hEventGuard_ held during this invocation
+void GtkXLib::PostUserEvent()
+{
+ if( !m_pUserEvent ) // not pending anyway
+ {
+ m_pUserEvent = g_idle_source_new();
+ g_source_set_priority( m_pUserEvent, G_PRIORITY_HIGH );
+ g_source_set_can_recurse (m_pUserEvent, TRUE);
+ g_source_set_callback (m_pUserEvent, call_userEventFn,
+ (gpointer) this, NULL);
+ g_source_attach (m_pUserEvent, g_main_context_default ());
+ }
+ Wakeup();
+}
+
+void GtkXLib::Wakeup()
+{
+ g_main_context_wakeup( g_main_context_default () );
+}
+
+void GtkXLib::Yield( bool bWait, bool bHandleAllCurrentEvents )
+{
+ /* #i33212# only enter g_main_context_iteration in one thread at any one
+ * time, else one of them potentially will never end as long as there is
+ * another thread in in there. Having only one yieldin thread actually dispatch
+ * fits the vcl event model (see e.g. the generic plugin).
+ */
+
+ bool bDispatchThread = false;
+ gboolean wasEvent = FALSE;
+ {
+ // release YieldMutex (and re-acquire at block end)
+ YieldMutexReleaser aReleaser;
+ if( osl_tryToAcquireMutex( m_aDispatchMutex ) )
+ bDispatchThread = true;
+ else if( ! bWait )
+ return; // someone else is waiting already, return
+
+
+ if( bDispatchThread )
+ {
+ int nMaxEvents = bHandleAllCurrentEvents ? 100 : 1;
+ gboolean wasOneEvent = TRUE;
+ while( nMaxEvents-- && wasOneEvent )
+ {
+ wasOneEvent = g_main_context_iteration( NULL, FALSE );
+ if( wasOneEvent )
+ wasEvent = TRUE;
+ }
+ if( bWait && ! wasEvent )
+ wasEvent = g_main_context_iteration( NULL, TRUE );
+ }
+ else if( bWait )
+ {
+ /* #i41693# in case the dispatch thread hangs in join
+ * for this thread the condition will never be set
+ * workaround: timeout of 1 second a emergency exit
+ */
+ // we are the dispatch thread
+ osl_resetCondition( m_aDispatchCondition );
+ TimeValue aValue = { 1, 0 };
+ osl_waitCondition( m_aDispatchCondition, &aValue );
+ }
+ }
+
+ if( bDispatchThread )
+ {
+ osl_releaseMutex( m_aDispatchMutex );
+ if( wasEvent )
+ osl_setCondition( m_aDispatchCondition ); // trigger non dispatch thread yields
+ }
+}
+
+extern "C" {
+
+typedef struct {
+ GSource source;
+
+ GPollFD pollfd;
+ GIOCondition condition;
+
+ YieldFunc pending;
+ YieldFunc handle;
+ gpointer user_data;
+} SalWatch;
+
+static gboolean
+sal_source_prepare (GSource *source,
+ gint *timeout)
+{
+ SalWatch *watch = (SalWatch *)source;
+
+ *timeout = -1;
+
+ if (watch->pending &&
+ watch->pending (watch->pollfd.fd, watch->user_data)) {
+ watch->pollfd.revents |= watch->condition;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+sal_source_check (GSource *source)
+{
+ SalWatch *watch = (SalWatch *)source;
+
+ return watch->pollfd.revents & watch->condition;
+}
+
+static gboolean
+sal_source_dispatch (GSource *source,
+ GSourceFunc,
+ gpointer)
+{
+ SalData *pSalData = GetSalData();
+ SalWatch *watch = (SalWatch *) source;
+
+ pSalData->m_pInstance->GetYieldMutex()->acquire();
+
+ watch->handle (watch->pollfd.fd, watch->user_data);
+
+ pSalData->m_pInstance->GetYieldMutex()->release();
+
+ return TRUE;
+}
+
+static void
+sal_source_finalize (GSource*)
+{
+}
+
+static GSourceFuncs sal_source_watch_funcs = {
+ sal_source_prepare,
+ sal_source_check,
+ sal_source_dispatch,
+ sal_source_finalize,
+ NULL,
+ NULL
+};
+
+static GSource *
+sal_source_create_watch (int fd,
+ GIOCondition condition,
+ YieldFunc pending,
+ YieldFunc handle,
+ gpointer user_data)
+{
+ GSource *source;
+ SalWatch *watch;
+ GMainContext *context = g_main_context_default ();
+
+ source = g_source_new (&sal_source_watch_funcs,
+ sizeof (SalWatch));
+ watch = (SalWatch *) source;
+
+ watch->pollfd.fd = fd;
+ watch->pollfd.events = condition;
+ watch->condition = condition;
+ watch->pending = pending;
+ watch->handle = handle;
+ watch->user_data = user_data;
+
+ g_source_set_can_recurse (source, TRUE);
+ g_source_add_poll (source, &watch->pollfd);
+ g_source_attach (source, context);
+
+ return source;
+}
+
+} // extern "C"
+
+void GtkXLib::Insert( int nFD,
+ void *data,
+ YieldFunc pending,
+ YieldFunc,
+ YieldFunc handle )
+{
+ GSource *source = sal_source_create_watch
+ ( nFD, (GIOCondition) ((G_IO_IN|G_IO_PRI) |
+ (G_IO_ERR|G_IO_HUP|G_IO_NVAL)),
+ pending, handle, data );
+ m_aSources.push_back( source );
+}
+
+void GtkXLib::Remove( int nFD )
+{
+ ::std::list< GSource * >::iterator it;
+
+ for (it = m_aSources.begin(); it != m_aSources.end(); ++it)
+ {
+ SalWatch *watch = (SalWatch *) *it;
+
+ if (watch->pollfd.fd == nFD)
+ {
+ m_aSources.erase( it );
+
+ g_source_destroy ((GSource *)watch);
+ g_source_unref ((GSource *)watch);
+ return;
+ }
+ }
+}
+
+/**********************************************************************
+ * class GtkData *
+ **********************************************************************/
+
+GtkData::~GtkData()
+{
+}
+
+void GtkData::Init()
+{
+ pXLib_ = new GtkXLib();
+ pXLib_->Init();
+}
diff --git a/vcl/unx/gtk/app/gtkinst.cxx b/vcl/unx/gtk/app/gtkinst.cxx
new file mode 100644
index 000000000000..2cb92ecd8292
--- /dev/null
+++ b/vcl/unx/gtk/app/gtkinst.cxx
@@ -0,0 +1,367 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <osl/module.h>
+#include <plugins/gtk/gtkdata.hxx>
+#include <plugins/gtk/gtkinst.hxx>
+#include <salframe.h>
+#include <salobj.h>
+#include <plugins/gtk/gtkframe.hxx>
+#include <plugins/gtk/gtkobject.hxx>
+#include <plugins/gtk/atkbridge.hxx>
+
+#include <rtl/strbuf.hxx>
+
+#include <rtl/uri.hxx>
+
+#if OSL_DEBUG_LEVEL > 1
+#include <stdio.h>
+#endif
+
+#include <dlfcn.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+GtkHookedYieldMutex::GtkHookedYieldMutex()
+{
+}
+
+/*
+ * These methods always occur in pairs
+ * A ThreadsEnter is followed by a ThreadsLeave
+ * We need to queue up the recursive lock count
+ * for each pair, so we can accurately restore
+ * it later.
+ */
+void GtkHookedYieldMutex::ThreadsEnter()
+{
+ acquire();
+ if( !aYieldStack.empty() )
+ { /* Previously called ThreadsLeave() */
+ ULONG nCount = aYieldStack.front();
+ aYieldStack.pop_front();
+ while( nCount-- > 1 )
+ acquire();
+ }
+}
+
+void GtkHookedYieldMutex::ThreadsLeave()
+{
+ aYieldStack.push_front( mnCount );
+
+#if OSL_DEBUG_LEVEL > 1
+ if( mnThreadId &&
+ mnThreadId != vos::OThread::getCurrentIdentifier())
+ fprintf( stderr, "\n\n--- A different thread owns the mutex ...---\n\n\n");
+#endif
+
+ while( mnCount > 1 )
+ release();
+ release();
+}
+
+void GtkHookedYieldMutex::acquire()
+{
+ SalYieldMutex::acquire();
+}
+
+void GtkHookedYieldMutex::release()
+{
+ SalYieldMutex::release();
+}
+
+extern "C"
+{
+ #define GET_YIELD_MUTEX() static_cast<GtkHookedYieldMutex*>(GetSalData()->m_pInstance->GetYieldMutex())
+ static void GdkThreadsEnter( void )
+ {
+ GtkHookedYieldMutex *pYieldMutex = GET_YIELD_MUTEX();
+ pYieldMutex->ThreadsEnter();
+ }
+ static void GdkThreadsLeave( void )
+ {
+ GtkHookedYieldMutex *pYieldMutex = GET_YIELD_MUTEX();
+ pYieldMutex->ThreadsLeave();
+ }
+ static bool hookLocks( oslModule pModule )
+ {
+ typedef void (*GdkLockFn) (GCallback enter_fn, GCallback leave_fn);
+
+ GdkLockFn gdk_threads_set_lock_functions =
+ (GdkLockFn) osl_getAsciiFunctionSymbol( pModule, "gdk_threads_set_lock_functions" );
+ if ( !gdk_threads_set_lock_functions )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "Failed to hook gdk threads locks\n" );
+#endif
+ return false;
+ }
+
+ gdk_threads_set_lock_functions (GdkThreadsEnter, GdkThreadsLeave);
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "Hooked gdk threads locks\n" );
+#endif
+ return true;
+ }
+
+ VCL_DLLPUBLIC SalInstance* create_SalInstance( oslModule pModule )
+ {
+ /* #i92121# workaround deadlocks in the X11 implementation
+ */
+ static const char* pNoXInitThreads = getenv( "SAL_NO_XINITTHREADS" );
+ /* #i90094#
+ from now on we know that an X connection will be
+ established, so protect X against itself
+ */
+ if( ! ( pNoXInitThreads && *pNoXInitThreads ) )
+ XInitThreads();
+
+ const gchar* pVersion = gtk_check_version( 2, 2, 0 );
+ if( pVersion )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "gtk version conflict: %s\n", pVersion );
+#endif
+ return NULL;
+ }
+
+ GtkYieldMutex *pYieldMutex;
+
+ // init gdk thread protection
+ if ( !g_thread_supported() )
+ g_thread_init( NULL );
+
+ if ( hookLocks( pModule ) )
+ pYieldMutex = new GtkHookedYieldMutex();
+ else
+ pYieldMutex = new GtkYieldMutex();
+
+ gdk_threads_init();
+
+ GtkInstance* pInstance = new GtkInstance( pYieldMutex );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "creating GtkSalInstance 0x%p\n", pInstance );
+#endif
+
+ // initialize SalData
+ GtkData *pSalData = new GtkData();
+ SetSalData( pSalData );
+ pSalData->m_pInstance = pInstance;
+ pSalData->Init();
+ pSalData->initNWF();
+
+ InitAtkBridge();
+
+ return pInstance;
+ }
+}
+
+GtkInstance::~GtkInstance()
+{
+ DeInitAtkBridge();
+}
+
+SalFrame* GtkInstance::CreateFrame( SalFrame* pParent, ULONG nStyle )
+{
+ return new GtkSalFrame( pParent, nStyle );
+}
+
+SalFrame* GtkInstance::CreateChildFrame( SystemParentData* pParentData, ULONG )
+{
+ SalFrame* pFrame = new GtkSalFrame( pParentData );
+
+ return pFrame;
+}
+
+SalObject* GtkInstance::CreateObject( SalFrame* pParent, SystemWindowData* pWindowData, BOOL bShow )
+{
+ // there is no method to set a visual for a GtkWidget
+ // so we need the X11SalObject in that case
+ if( pWindowData )
+ return X11SalObject::CreateObject( pParent, pWindowData, bShow );
+
+ return new GtkSalObject( static_cast<GtkSalFrame*>(pParent), bShow );
+}
+
+extern "C"
+{
+ typedef void*(* getDefaultFnc)();
+ typedef void(* addItemFnc)(void *, const char *);
+}
+
+void GtkInstance::AddToRecentDocumentList(const rtl::OUString& rFileUrl, const rtl::OUString& rMimeType)
+{
+ rtl::OString sGtkURL;
+ rtl_TextEncoding aSystemEnc = osl_getThreadTextEncoding();
+ if ((aSystemEnc == RTL_TEXTENCODING_UTF8) || (rFileUrl.compareToAscii( "file://", 7 ) != 0))
+ sGtkURL = rtl::OUStringToOString(rFileUrl, RTL_TEXTENCODING_UTF8);
+ else
+ {
+ //Non-utf8 locales are a bad idea if trying to work with non-ascii filenames
+ //Decode %XX components
+ rtl::OUString sDecodedUri = Uri::decode(rFileUrl.copy(7), rtl_UriDecodeToIuri, RTL_TEXTENCODING_UTF8);
+ //Convert back to system locale encoding
+ rtl::OString sSystemUrl = rtl::OUStringToOString(sDecodedUri, aSystemEnc);
+ //Encode to an escaped ASCII-encoded URI
+ gchar *g_uri = g_filename_to_uri(sSystemUrl.getStr(), NULL, NULL);
+ sGtkURL = rtl::OString(g_uri);
+ g_free(g_uri);
+ }
+#if GTK_CHECK_VERSION(2,10,0)
+ GtkRecentManager *manager = gtk_recent_manager_get_default ();
+ gtk_recent_manager_add_item (manager, sGtkURL);
+ (void)rMimeType;
+#else
+ static getDefaultFnc sym_gtk_recent_manager_get_default =
+ (getDefaultFnc)osl_getAsciiFunctionSymbol( GetSalData()->m_pPlugin, "gtk_recent_manager_get_default" );
+
+ static addItemFnc sym_gtk_recent_manager_add_item =
+ (addItemFnc)osl_getAsciiFunctionSymbol( GetSalData()->m_pPlugin, "gtk_recent_manager_add_item");
+ if (sym_gtk_recent_manager_get_default && sym_gtk_recent_manager_add_item)
+ sym_gtk_recent_manager_add_item(sym_gtk_recent_manager_get_default(), sGtkURL);
+ else
+ X11SalInstance::AddToRecentDocumentList(rFileUrl, rMimeType);
+#endif
+}
+
+GtkYieldMutex::GtkYieldMutex()
+{
+}
+
+void GtkYieldMutex::acquire()
+{
+ vos::OThread::TThreadIdentifier aCurrentThread = vos::OThread::getCurrentIdentifier();
+ // protect member manipulation
+ OMutex::acquire();
+ if( mnCount > 0 && mnThreadId == aCurrentThread )
+ {
+ mnCount++;
+ OMutex::release();
+ return;
+ }
+ OMutex::release();
+
+ // obtain gdk mutex
+ gdk_threads_enter();
+
+ // obtained gdk mutex, now lock count is one by definition
+ OMutex::acquire();
+ mnCount = 1;
+ mnThreadId = aCurrentThread;
+ OMutex::release();
+}
+
+void GtkYieldMutex::release()
+{
+ vos::OThread::TThreadIdentifier aCurrentThread = vos::OThread::getCurrentIdentifier();
+ // protect member manipulation
+ OMutex::acquire();
+ // strange things happen, do nothing if we don't own the mutex
+ if( mnThreadId == aCurrentThread )
+ {
+ mnCount--;
+ if( mnCount == 0 )
+ {
+ gdk_threads_leave();
+ mnThreadId = 0;
+ }
+ }
+ OMutex::release();
+}
+
+sal_Bool GtkYieldMutex::tryToAcquire()
+{
+ vos::OThread::TThreadIdentifier aCurrentThread = vos::OThread::getCurrentIdentifier();
+ // protect member manipulation
+ OMutex::acquire();
+ if( mnCount > 0 )
+ {
+ if( mnThreadId == aCurrentThread )
+ {
+ mnCount++;
+ OMutex::release();
+ return sal_True;
+ }
+ else
+ {
+ OMutex::release();
+ return sal_False;
+ }
+ }
+ OMutex::release();
+
+ // HACK: gdk_threads_mutex is private, we shouldn't use it.
+ // how to we do a try_lock without having a gdk_threads_try_enter ?
+ if( ! g_mutex_trylock( gdk_threads_mutex ) )
+ return sal_False;
+
+ // obtained gdk mutex, now lock count is one by definition
+ OMutex::acquire();
+ mnCount = 1;
+ mnThreadId = aCurrentThread;
+ OMutex::release();
+
+ return sal_True;
+}
+
+int GtkYieldMutex::Grab()
+{
+ // this MUST only be called by gdk/gtk callbacks:
+ // they are entered with gdk mutex locked; the mutex
+ // was unlocked by GtkYieldMutex befor yielding which
+ // is now locked again by gtk implicitly
+
+ // obtained gdk mutex, now lock count is one by definition
+ OMutex::acquire();
+ int nRet = mnCount;
+ if( mnCount == 0 ) // recursive else
+ mnThreadId = vos::OThread::getCurrentIdentifier();
+#if OSL_DEBUG_LEVEL > 1
+ else if( mnThreadId != vos::OThread::getCurrentIdentifier() )
+ {
+ fprintf( stderr, "Yield mutex grabbed in different thread !\n" );
+ abort();
+ }
+#endif
+ mnCount = 1;
+ OMutex::release();
+ return nRet;
+}
+
+void GtkYieldMutex::Ungrab( int nGrabs )
+{
+ // this MUST only be called when leaving the callback
+ // that locked the mutex with Grab()
+ OMutex::acquire();
+ mnCount = nGrabs;
+ if( mnCount == 0 )
+ mnThreadId = 0;
+ OMutex::release();
+}
diff --git a/vcl/unx/gtk/app/gtksys.cxx b/vcl/unx/gtk/app/gtksys.cxx
new file mode 100644
index 000000000000..272af20d0886
--- /dev/null
+++ b/vcl/unx/gtk/app/gtksys.cxx
@@ -0,0 +1,96 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <svunx.h>
+#include <vcl/svdata.hxx>
+#include <vcl/window.hxx>
+#include <plugins/gtk/gtkinst.hxx>
+#include <cstdio>
+#include <gdk/gdk.h>
+#include <gtk/gtk.h>
+#include <X11/Xlib.h>
+
+SalSystem *GtkInstance::CreateSalSystem()
+{
+ return new GtkSalSystem();
+}
+
+GtkSalSystem::~GtkSalSystem()
+{
+}
+
+int GtkSalSystem::ShowNativeDialog( const String& rTitle,
+ const String& rMessage,
+ const std::list< String >& rButtons,
+ int nDefButton )
+{
+
+ ImplSVData* pSVData = ImplGetSVData();
+ if( pSVData->mpIntroWindow )
+ pSVData->mpIntroWindow->Hide();
+
+#if OSL_DEBUG_LEVEL > 1
+ std::fprintf( stderr, "GtkSalSystem::ShowNativeDialog\n");
+#endif
+
+ ByteString aTitle( rTitle, RTL_TEXTENCODING_UTF8 );
+ ByteString aMessage( rMessage, RTL_TEXTENCODING_UTF8 );
+
+ /* Create the dialogue */
+ GtkWidget* mainwin = gtk_message_dialog_new
+ ( NULL, (GtkDialogFlags)0, GTK_MESSAGE_WARNING,
+ GTK_BUTTONS_NONE, aMessage.GetBuffer(), NULL );
+ gtk_window_set_title( GTK_WINDOW( mainwin ), aTitle.GetBuffer() );
+
+ gint nButtons = 0, nResponse;
+
+ int nButton = 0;
+ for( std::list< String >::const_iterator it = rButtons.begin(); it != rButtons.end(); ++it )
+ {
+ ByteString aLabel( *it, RTL_TEXTENCODING_UTF8 );
+
+ if( nButton == nDefButton )
+ {
+ gtk_dialog_add_button( GTK_DIALOG( mainwin ), aLabel.GetBuffer(), nButtons );
+ gtk_dialog_set_default_response( GTK_DIALOG( mainwin ), nButtons );
+ }
+ else
+ gtk_dialog_add_button( GTK_DIALOG( mainwin ), aLabel.GetBuffer(), nButtons );
+ nButtons++;
+ }
+
+ nResponse = gtk_dialog_run( GTK_DIALOG(mainwin) );
+ if( nResponse == GTK_RESPONSE_NONE || nResponse == GTK_RESPONSE_DELETE_EVENT )
+ nResponse = -1;
+
+ gtk_widget_destroy( GTK_WIDGET(mainwin) );
+
+ return nResponse;
+}
diff --git a/vcl/unx/gtk/app/makefile.mk b/vcl/unx/gtk/app/makefile.mk
new file mode 100644
index 000000000000..3e8cd750bf7a
--- /dev/null
+++ b/vcl/unx/gtk/app/makefile.mk
@@ -0,0 +1,76 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#*************************************************************************
+
+PRJ=..$/..$/..
+
+PRJNAME=vcl
+TARGET=gtkapp
+.INCLUDE : $(PRJ)$/util$/makefile.pmk
+
+# workaround for makedepend hang
+MKDEPENDSOLVER=
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+.INCLUDE : $(PRJ)$/util$/makefile2.pmk
+
+# --- Files --------------------------------------------------------
+
+.IF "$(GUIBASE)"!="unx"
+
+dummy:
+ @echo "Nothing to build for GUIBASE $(GUIBASE)"
+
+.ELSE # "$(GUIBASE)"!="unx"
+
+.IF "$(ENABLE_GTK)" != ""
+
+PKGCONFIG_MODULES=gtk+-2.0
+.INCLUDE : pkg_config.mk
+
+SLOFILES=\
+ $(SLO)$/gtkdata.obj \
+ $(SLO)$/gtkinst.obj \
+ $(SLO)$/gtksys.obj
+
+EXCEPTIONSFILES=\
+ $(SLO)$/gtkdata.obj\
+ $(SLO)$/gtkinst.obj
+
+.ELSE # "$(ENABLE_GTK)" != ""
+
+dummy:
+ @echo GTK disabled - nothing to build
+.ENDIF
+.ENDIF # "$(GUIBASE)"!="unx"
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
+
+.INCLUDE : $(PRJ)$/util$/target.pmk
diff --git a/vcl/unx/gtk/gdi/makefile.mk b/vcl/unx/gtk/gdi/makefile.mk
new file mode 100644
index 000000000000..ec6b4e1d205e
--- /dev/null
+++ b/vcl/unx/gtk/gdi/makefile.mk
@@ -0,0 +1,67 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#*************************************************************************
+
+PRJ=..$/..$/..
+
+PRJNAME=vcl
+TARGET=gtkgdi
+.INCLUDE : $(PRJ)$/util$/makefile.pmk
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+.INCLUDE : $(PRJ)$/util$/makefile2.pmk
+
+# --- Files --------------------------------------------------------
+
+.IF "$(GUIBASE)"!="unx"
+
+dummy:
+ @echo "Nothing to build for GUIBASE $(GUIBASE)"
+
+.ELSE # "$(GUIBASE)"!="unx"
+
+.IF "$(ENABLE_GTK)" != ""
+
+PKGCONFIG_MODULES=gtk+-2.0
+.INCLUDE : pkg_config.mk
+
+SLOFILES=$(SLO)$/salnativewidgets-gtk.obj
+EXCEPTIONSFILES=$(SLO)$/salnativewidgets-gtk.obj
+
+.ELSE # "$(ENABLE_GTK)" != ""
+dummy:
+ @echo GTK disabled - nothing to build
+.ENDIF
+
+.ENDIF # "$(GUIBASE)"!="unx"
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
+
+.INCLUDE : $(PRJ)$/util$/target.pmk
diff --git a/vcl/unx/gtk/gdi/salnativewidgets-gtk.cxx b/vcl/unx/gtk/gdi/salnativewidgets-gtk.cxx
new file mode 100644
index 000000000000..ff615f5ede74
--- /dev/null
+++ b/vcl/unx/gtk/gdi/salnativewidgets-gtk.cxx
@@ -0,0 +1,4084 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "plugins/gtk/gtkframe.hxx"
+#include "plugins/gtk/gtkdata.hxx"
+#include "plugins/gtk/gtkinst.hxx"
+#include "plugins/gtk/gtkgdi.hxx"
+
+#include "pspgraphics.h"
+
+#include <cstdio>
+#include <cmath>
+#include <vector>
+#include <algorithm>
+#include <hash_map>
+
+#include "saldata.hxx"
+#include "saldisp.hxx"
+#include "vcl/svapp.hxx"
+
+typedef struct _cairo_font_options cairo_font_options_t;
+
+// initialize statics
+BOOL GtkSalGraphics::bThemeChanged = TRUE;
+BOOL GtkSalGraphics::bNeedPixmapPaint = FALSE;
+BOOL GtkSalGraphics::bGlobalNeedPixmapPaint = FALSE;
+BOOL GtkSalGraphics::bToolbarGripWorkaround = FALSE;
+BOOL GtkSalGraphics::bNeedButtonStyleAsEditBackgroundWorkaround = FALSE;
+
+GtkSalGraphics::~GtkSalGraphics()
+{
+}
+
+
+using namespace rtl;
+
+/*************************************
+ * Cached native widget objects
+ *************************************/
+class NWPixmapCacheList;
+class NWPixmapCache;
+struct NWFWidgetData
+{
+ GtkWidget * gCacheWindow;
+ GtkWidget * gDumbContainer;
+
+ GtkWidget * gBtnWidget;
+ GtkWidget * gRadioWidget;
+ GtkWidget * gRadioWidgetSibling;
+ GtkWidget * gCheckWidget;
+ GtkWidget * gScrollHorizWidget;
+ GtkWidget * gScrollVertWidget;
+ GtkWidget * gArrowWidget;
+ GtkWidget * gDropdownWidget;
+ GtkWidget * gEditBoxWidget;
+ GtkWidget * gSpinButtonWidget;
+ GtkWidget * gNotebookWidget;
+ GtkWidget * gOptionMenuWidget;
+ GtkWidget * gComboWidget;
+ GtkWidget * gScrolledWindowWidget;
+ GtkWidget * gToolbarWidget;
+ GtkWidget * gToolbarButtonWidget;
+ GtkWidget * gToolbarToggleWidget;
+ GtkWidget * gHandleBoxWidget;
+ GtkWidget * gMenubarWidget;
+ GtkWidget * gMenuItemMenubarWidget;
+ GtkWidget * gMenuWidget;
+ GtkWidget * gMenuItemMenuWidget;
+ GtkWidget * gMenuItemCheckMenuWidget;
+ GtkWidget * gMenuItemRadioMenuWidget;
+ GtkWidget * gImageMenuItem;
+ GtkWidget * gTooltipPopup;
+ GtkWidget * gProgressBar;
+ GtkWidget * gTreeView;
+ GtkWidget * gHScale;
+ GtkWidget * gVScale;
+
+ NWPixmapCacheList* gNWPixmapCacheList;
+ NWPixmapCache* gCacheTabItems;
+ NWPixmapCache* gCacheTabPages;
+
+ NWFWidgetData() :
+ gCacheWindow( NULL ),
+ gDumbContainer( NULL ),
+ gBtnWidget( NULL ),
+ gRadioWidget( NULL ),
+ gRadioWidgetSibling( NULL ),
+ gCheckWidget( NULL ),
+ gScrollHorizWidget( NULL ),
+ gScrollVertWidget( NULL ),
+ gArrowWidget( NULL ),
+ gDropdownWidget( NULL ),
+ gEditBoxWidget( NULL ),
+ gSpinButtonWidget( NULL ),
+ gNotebookWidget( NULL ),
+ gOptionMenuWidget( NULL ),
+ gComboWidget( NULL ),
+ gScrolledWindowWidget( NULL ),
+ gToolbarWidget( NULL ),
+ gToolbarButtonWidget( NULL ),
+ gToolbarToggleWidget( NULL ),
+ gHandleBoxWidget( NULL ),
+ gMenubarWidget( NULL ),
+ gMenuItemMenubarWidget( NULL ),
+ gMenuWidget( NULL ),
+ gMenuItemMenuWidget( NULL ),
+ gMenuItemCheckMenuWidget( NULL ),
+ gMenuItemRadioMenuWidget( NULL ),
+ gImageMenuItem( NULL ),
+ gTooltipPopup( NULL ),
+ gProgressBar( NULL ),
+ gTreeView( NULL ),
+ gHScale( NULL ),
+ gVScale( NULL ),
+ gNWPixmapCacheList( NULL ),
+ gCacheTabItems( NULL ),
+ gCacheTabPages( NULL )
+ {}
+};
+
+// Keep a hash table of Widgets->default flags so that we can
+// easily and quickly reset each to a default state before using
+// them
+static std::hash_map<long, guint> gWidgetDefaultFlags;
+static std::vector<NWFWidgetData> gWidgetData;
+
+static const GtkBorder aDefDefBorder = { 1, 1, 1, 1 };
+
+// Some GTK defaults
+#define MIN_ARROW_SIZE 11
+#define BTN_CHILD_SPACING 1
+#define MIN_SPIN_ARROW_WIDTH 6
+
+
+static void NWEnsureGTKRadio ( int nScreen );
+static void NWEnsureGTKButton ( int nScreen );
+static void NWEnsureGTKCheck ( int nScreen );
+static void NWEnsureGTKScrollbars ( int nScreen );
+static void NWEnsureGTKArrow ( int nScreen );
+static void NWEnsureGTKEditBox ( int nScreen );
+static void NWEnsureGTKSpinButton ( int nScreen );
+static void NWEnsureGTKNotebook ( int nScreen );
+static void NWEnsureGTKOptionMenu ( int nScreen );
+static void NWEnsureGTKCombo ( int nScreen );
+static void NWEnsureGTKScrolledWindow ( int nScreen );
+static void NWEnsureGTKToolbar ( int nScreen );
+static void NWEnsureGTKMenubar ( int nScreen );
+static void NWEnsureGTKMenu ( int nScreen );
+static void NWEnsureGTKTooltip ( int nScreen );
+static void NWEnsureGTKProgressBar ( int nScreen );
+static void NWEnsureGTKTreeView ( int nScreen );
+static void NWEnsureGTKSlider ( int nScreen );
+
+static void NWConvertVCLStateToGTKState( ControlState nVCLState, GtkStateType* nGTKState, GtkShadowType* nGTKShadow );
+static void NWAddWidgetToCacheWindow( GtkWidget* widget, int nScreen );
+static void NWSetWidgetState( GtkWidget* widget, ControlState nState, GtkStateType nGtkState );
+
+static void NWCalcArrowRect( const Rectangle& rButton, Rectangle& rArrow );
+
+/*
+ * Individual helper functions
+ *
+ */
+
+//---
+static Rectangle NWGetButtonArea( int nScreen, ControlType nType, ControlPart nPart, Rectangle aAreaRect, ControlState nState,
+ const ImplControlValue& aValue, const OUString& rCaption );
+
+//---
+static Rectangle NWGetEditBoxPixmapRect( int nScreen, ControlType nType, ControlPart nPart, Rectangle aAreaRect, ControlState nState,
+ const ImplControlValue& aValue, const OUString& rCaption );
+
+static void NWPaintOneEditBox( int nScreen, GdkDrawable * gdkDrawable, GdkRectangle *gdkRect,
+ ControlType nType, ControlPart nPart, Rectangle aEditBoxRect,
+ ControlState nState, const ImplControlValue& aValue,
+ const OUString& rCaption );
+
+//---
+static Rectangle NWGetSpinButtonRect( int nScreen, ControlType nType, ControlPart nPart, Rectangle aAreaRect, ControlState nState,
+ const ImplControlValue& aValue, const OUString& rCaption );
+
+static void NWPaintOneSpinButton( int nScreen, GdkPixmap * pixmap, ControlType nType, ControlPart nPart, Rectangle aAreaRect,
+ ControlState nState, const ImplControlValue& aValue,
+ const OUString& rCaption );
+//---
+static Rectangle NWGetComboBoxButtonRect( int nScreen, ControlType nType, ControlPart nPart, Rectangle aAreaRect, ControlState nState,
+ const ImplControlValue& aValue, const OUString& rCaption );
+
+//---
+static Rectangle NWGetListBoxButtonRect( int nScreen, ControlType nType, ControlPart nPart, Rectangle aAreaRect, ControlState nState,
+ const ImplControlValue& aValue, const OUString& rCaption );
+
+static Rectangle NWGetListBoxIndicatorRect( int nScreen, ControlType nType, ControlPart nPart, Rectangle aAreaRect, ControlState nState,
+ const ImplControlValue& aValue, const OUString& rCaption );
+
+static Rectangle NWGetToolbarRect( int nScreen,
+ ControlType nType,
+ ControlPart nPart,
+ Rectangle aAreaRect,
+ ControlState nState,
+ const ImplControlValue& aValue,
+ const OUString& rCaption );
+//---
+
+static Rectangle NWGetScrollButtonRect( int nScreen, ControlPart nPart, Rectangle aAreaRect );
+//---
+
+/*********************************************************
+ * PixmapCache
+ *********************************************************/
+
+// as some native widget drawing operations are pretty slow
+// with certain themes (eg tabpages)
+// this cache can be used to cache the corresponding pixmap
+// see NWPaintGTKTabItem
+
+class NWPixmapCacheData
+{
+public:
+ ControlType m_nType;
+ ControlState m_nState;
+ Rectangle m_pixmapRect;
+ GdkPixmap* m_pixmap;
+
+ NWPixmapCacheData() : m_nType(0), m_nState(0), m_pixmap(0) {}
+ ~NWPixmapCacheData()
+ { SetPixmap( NULL ); };
+ void SetPixmap( GdkPixmap* pPixmap );
+};
+
+class NWPixmapCache
+{
+ int m_size;
+ int m_idx;
+ int m_screen;
+ NWPixmapCacheData* pData;
+public:
+ NWPixmapCache( int nScreen );
+ ~NWPixmapCache();
+
+ void SetSize( int n)
+ { delete [] pData; m_idx = 0; m_size = n; pData = new NWPixmapCacheData[m_size]; }
+ int GetSize() { return m_size; }
+
+ BOOL Find( ControlType aType, ControlState aState, const Rectangle& r_pixmapRect, GdkPixmap** pPixmap );
+ void Fill( ControlType aType, ControlState aState, const Rectangle& r_pixmapRect, GdkPixmap* pPixmap );
+
+ void ThemeChanged();
+};
+
+class NWPixmapCacheList
+{
+public:
+ ::std::vector< NWPixmapCache* > mCaches;
+
+ void AddCache( NWPixmapCache *pCache );
+ void RemoveCache( NWPixmapCache *pCache );
+ void ThemeChanged();
+};
+
+// --- implementation ---
+
+void NWPixmapCacheData::SetPixmap( GdkPixmap* pPixmap )
+{
+ if( m_pixmap )
+ g_object_unref( m_pixmap );
+
+ m_pixmap = pPixmap;
+
+ if( m_pixmap )
+ g_object_ref( m_pixmap );
+}
+
+
+NWPixmapCache::NWPixmapCache( int nScreen )
+{
+ m_idx = 0;
+ m_size = 0;
+ m_screen = nScreen;
+ pData = NULL;
+ if( gWidgetData[m_screen].gNWPixmapCacheList )
+ gWidgetData[m_screen].gNWPixmapCacheList->AddCache(this);
+}
+NWPixmapCache::~NWPixmapCache()
+{
+ if( gWidgetData[m_screen].gNWPixmapCacheList )
+ gWidgetData[m_screen].gNWPixmapCacheList->RemoveCache(this);
+ delete[] pData;
+}
+void NWPixmapCache::ThemeChanged()
+{
+ // throw away cached pixmaps
+ int i;
+ for(i=0; i<m_size; i++)
+ pData[i].SetPixmap( NULL );
+}
+
+BOOL NWPixmapCache::Find( ControlType aType, ControlState aState, const Rectangle& r_pixmapRect, GdkPixmap** pPixmap )
+{
+ aState &= ~CTRL_CACHING_ALLOWED; // mask clipping flag
+ int i;
+ for(i=0; i<m_size; i++)
+ {
+ if( pData[i].m_nType == aType &&
+ pData[i].m_nState == aState &&
+ pData[i].m_pixmapRect.GetWidth() == r_pixmapRect.GetWidth() &&
+ pData[i].m_pixmapRect.GetHeight() == r_pixmapRect.GetHeight() &&
+ pData[i].m_pixmap != NULL )
+ {
+ *pPixmap = pData[i].m_pixmap;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+void NWPixmapCache::Fill( ControlType aType, ControlState aState, const Rectangle& r_pixmapRect, GdkPixmap* pPixmap )
+{
+ if( !(aState & CTRL_CACHING_ALLOWED) )
+ return;
+
+ aState &= ~CTRL_CACHING_ALLOWED; // mask clipping flag
+ m_idx = (m_idx+1) % m_size; // just wrap
+ pData[m_idx].m_nType = aType;
+ pData[m_idx].m_nState = aState;
+ pData[m_idx].m_pixmapRect = r_pixmapRect;
+ pData[m_idx].SetPixmap( pPixmap );
+}
+
+
+void NWPixmapCacheList::AddCache( NWPixmapCache* pCache )
+{
+ mCaches.push_back( pCache );
+}
+void NWPixmapCacheList::RemoveCache( NWPixmapCache* pCache )
+{
+ ::std::vector< NWPixmapCache* >::iterator p;
+ p = ::std::find( mCaches.begin(), mCaches.end(), pCache );
+ if( p != mCaches.end() )
+ mCaches.erase( p );
+}
+void NWPixmapCacheList::ThemeChanged( )
+{
+ ::std::vector< NWPixmapCache* >::iterator p = mCaches.begin();
+ while( p != mCaches.end() )
+ {
+ (*p)->ThemeChanged();
+ p++;
+ }
+}
+
+
+/*********************************************************
+ * Make border manipulation easier
+ *********************************************************/
+inline void NW_gtk_border_set_from_border( GtkBorder& aDst, const GtkBorder * pSrc )
+{
+ aDst.left = pSrc->left;
+ aDst.top = pSrc->top;
+ aDst.right = pSrc->right;
+ aDst.bottom = pSrc->bottom;
+}
+
+
+/*********************************************************
+ * Initialize GTK and local stuff
+ *********************************************************/
+void GtkData::initNWF( void )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+
+ // draw no border for popup menus (NWF draws its own)
+ pSVData->maNWFData.mbFlatMenu = true;
+
+ // draw separate buttons for toolbox dropdown items
+ pSVData->maNWFData.mbToolboxDropDownSeparate = true;
+
+ // small extra border around menu items
+ pSVData->maNWFData.mnMenuFormatExtraBorder = 1;
+
+ // draw toolbars in separate lines
+ pSVData->maNWFData.mbDockingAreaSeparateTB = true;
+
+ // open first menu on F10
+ pSVData->maNWFData.mbOpenMenuOnF10 = true;
+
+ // omit GetNativeControl while painting (see brdwin.cxx)
+ pSVData->maNWFData.mbCanDrawWidgetAnySize = true;
+
+ int nScreens = GetX11SalData()->GetDisplay()->GetScreenCount();
+ gWidgetData = std::vector<NWFWidgetData>( nScreens );
+ for( int i = 0; i < nScreens; i++ )
+ gWidgetData[i].gNWPixmapCacheList = new NWPixmapCacheList;
+
+
+ if( SalGetDesktopEnvironment().equalsAscii( "KDE" ) )
+ {
+ // #i97196# ensure a widget exists and the style engine was loaded
+ NWEnsureGTKButton( 0 );
+ if( g_type_from_name( "QtEngineStyle" ) )
+ {
+ // KDE 3.3 invented a bug in the qt<->gtk theme engine
+ // that makes direct rendering impossible: they totally
+ // ignore the clip rectangle passed to the paint methods
+ GtkSalGraphics::bNeedPixmapPaint = GtkSalGraphics::bGlobalNeedPixmapPaint = true;
+ }
+ }
+ static const char* pEnv = getenv( "SAL_GTK_USE_PIXMAPPAINT" );
+ if( pEnv && *pEnv )
+ GtkSalGraphics::bNeedPixmapPaint = GtkSalGraphics::bGlobalNeedPixmapPaint = true;
+
+ #if OSL_DEBUG_LEVEL > 1
+ std::fprintf( stderr, "GtkPlugin: using %s NWF\n",
+ GtkSalGraphics::bNeedPixmapPaint ? "offscreen" : "direct" );
+ #endif
+}
+
+
+/*********************************************************
+ * Release GTK and local stuff
+ *********************************************************/
+void GtkData::deInitNWF( void )
+{
+
+ for( unsigned int i = 0; i < gWidgetData.size(); i++ )
+ {
+ // free up global widgets
+ // gtk_widget_destroy will in turn destroy the child hierarchy
+ // so only destroy disjunct hierachies
+ if( gWidgetData[i].gCacheWindow )
+ gtk_widget_destroy( gWidgetData[i].gCacheWindow );
+ if( gWidgetData[i].gMenuWidget )
+ gtk_widget_destroy( gWidgetData[i].gMenuWidget );
+ if( gWidgetData[i].gTooltipPopup )
+ gtk_widget_destroy( gWidgetData[i].gTooltipPopup );
+ delete gWidgetData[i].gCacheTabPages;
+ gWidgetData[i].gCacheTabPages = NULL;
+ delete gWidgetData[i].gCacheTabItems;
+ gWidgetData[i].gCacheTabItems = NULL;
+ delete gWidgetData[i].gNWPixmapCacheList;
+ gWidgetData[i].gNWPixmapCacheList = NULL;
+ }
+}
+
+
+/**********************************************************
+ * track clip region
+ **********************************************************/
+void GtkSalGraphics::ResetClipRegion()
+{
+ m_aClipRegion.SetNull();
+ X11SalGraphics::ResetClipRegion();
+}
+
+void GtkSalGraphics::BeginSetClipRegion( ULONG nCount )
+{
+ m_aClipRegion.SetNull();
+ X11SalGraphics::BeginSetClipRegion( nCount );
+}
+
+BOOL GtkSalGraphics::unionClipRegion( long nX, long nY, long nWidth, long nHeight )
+{
+ Rectangle aRect( Point( nX, nY ), Size( nWidth, nHeight ) );
+ m_aClipRegion.Union( aRect );
+ return X11SalGraphics::unionClipRegion( nX, nY, nWidth, nHeight );
+}
+
+bool GtkSalGraphics::unionClipRegion( const ::basegfx::B2DPolyPolygon& )
+{
+ // TODO: implement and advertise OutDevSupport_B2DClip support
+ return false;
+}
+
+void GtkSalGraphics::EndSetClipRegion()
+{
+ if( m_aClipRegion.IsEmpty() )
+ m_aClipRegion.SetNull();
+ X11SalGraphics::EndSetClipRegion();
+}
+
+void GtkSalGraphics::copyBits( const SalTwoRect* pPosAry,
+ SalGraphics* pSrcGraphics )
+{
+ GtkSalFrame* pFrame = GetGtkFrame();
+ XLIB_Window aWin = None;
+ if( pFrame && m_pWindow )
+ {
+ /* #i64117# some themes set the background pixmap VERY frequently */
+ GdkWindow* pWin = GTK_WIDGET(m_pWindow)->window;
+ if( pWin )
+ {
+ aWin = GDK_WINDOW_XWINDOW(pWin);
+ if( aWin != None )
+ XSetWindowBackgroundPixmap( pFrame->getDisplay()->GetDisplay(),
+ aWin,
+ None );
+ }
+ }
+ X11SalGraphics::copyBits( pPosAry, pSrcGraphics );
+ if( pFrame && pFrame->getBackgroundPixmap() != None )
+ XSetWindowBackgroundPixmap( pFrame->getDisplay()->GetDisplay(),
+ aWin,
+ pFrame->getBackgroundPixmap() );
+}
+
+/*
+ * IsNativeControlSupported()
+ *
+ * Returns TRUE if the platform supports native
+ * drawing of the control defined by nPart
+ */
+BOOL GtkSalGraphics::IsNativeControlSupported( ControlType nType, ControlPart nPart )
+{
+ if (
+ ((nType==CTRL_PUSHBUTTON) && (nPart==PART_ENTIRE_CONTROL)) ||
+ ((nType==CTRL_RADIOBUTTON) && (nPart==PART_ENTIRE_CONTROL)) ||
+ ((nType==CTRL_CHECKBOX) && (nPart==PART_ENTIRE_CONTROL)) ||
+ ((nType==CTRL_SCROLLBAR) &&
+ ( (nPart==PART_DRAW_BACKGROUND_HORZ)
+ || (nPart==PART_DRAW_BACKGROUND_VERT)
+ || (nPart==PART_ENTIRE_CONTROL)
+ || (nPart==HAS_THREE_BUTTONS) ) ) ||
+ ((nType==CTRL_EDITBOX) &&
+ ( (nPart==PART_ENTIRE_CONTROL)
+ || (nPart==HAS_BACKGROUND_TEXTURE) ) ) ||
+ ((nType==CTRL_MULTILINE_EDITBOX) &&
+ ( (nPart==PART_ENTIRE_CONTROL)
+ || (nPart==HAS_BACKGROUND_TEXTURE) ) ) ||
+ ((nType==CTRL_SPINBOX) &&
+ ( (nPart==PART_ENTIRE_CONTROL)
+ || (nPart==PART_ALL_BUTTONS)
+ || (nPart==HAS_BACKGROUND_TEXTURE) ) ) ||
+ ((nType==CTRL_SPINBUTTONS) &&
+ ( (nPart==PART_ENTIRE_CONTROL)
+ || (nPart==PART_ALL_BUTTONS) ) ) ||
+ ((nType==CTRL_COMBOBOX) &&
+ ( (nPart==PART_ENTIRE_CONTROL)
+ || (nPart==HAS_BACKGROUND_TEXTURE) ) ) ||
+ (((nType==CTRL_TAB_ITEM) || (nType==CTRL_TAB_PANE) ||
+ (nType==CTRL_TAB_BODY) || (nType==CTRL_FIXEDBORDER)) &&
+ ( (nPart==PART_ENTIRE_CONTROL)
+ || (nPart==PART_TABS_DRAW_RTL) ) ) ||
+ ((nType==CTRL_LISTBOX) &&
+ ( (nPart==PART_ENTIRE_CONTROL)
+ || (nPart==PART_WINDOW)
+ || (nPart==HAS_BACKGROUND_TEXTURE) ) ) ||
+ ((nType == CTRL_TOOLBAR) &&
+ ( (nPart==PART_ENTIRE_CONTROL)
+ || (nPart==PART_DRAW_BACKGROUND_HORZ)
+ || (nPart==PART_DRAW_BACKGROUND_VERT)
+ || (nPart==PART_THUMB_HORZ)
+ || (nPart==PART_THUMB_VERT)
+ || (nPart==PART_BUTTON)
+ )
+ ) ||
+ ((nType == CTRL_MENUBAR) &&
+ ( (nPart==PART_ENTIRE_CONTROL) ) ) ||
+ ((nType == CTRL_TOOLTIP) &&
+ ( (nPart==PART_ENTIRE_CONTROL) ) ) ||
+ ((nType == CTRL_MENU_POPUP) &&
+ ( (nPart==PART_ENTIRE_CONTROL)
+ || (nPart==PART_MENU_ITEM)
+ || (nPart==PART_MENU_ITEM_CHECK_MARK)
+ || (nPart==PART_MENU_ITEM_RADIO_MARK)
+ )
+ ) ||
+ ((nType == CTRL_PROGRESS) &&
+ ( (nPart == PART_ENTIRE_CONTROL) )
+ ) ||
+ ((nType == CTRL_LISTNODE || nType == CTRL_LISTNET) &&
+ ( (nPart == PART_ENTIRE_CONTROL) )
+ ) ||
+ ((nType == CTRL_SLIDER) &&
+ ( (nPart == PART_TRACK_HORZ_AREA)
+ || (nPart == PART_TRACK_VERT_AREA)
+ )
+ )
+ )
+ return( TRUE );
+
+ return( FALSE );
+}
+
+
+/*
+ * HitTestNativeControl()
+ *
+ * bIsInside is set to TRUE if aPos is contained within the
+ * given part of the control, whose bounding region is
+ * given by rControlRegion (in VCL frame coordinates).
+ *
+ * returns whether bIsInside was really set.
+ */
+BOOL GtkSalGraphics::hitTestNativeControl( ControlType nType,
+ ControlPart nPart,
+ const Rectangle& rControlRegion,
+ const Point& aPos,
+ BOOL& rIsInside )
+{
+ if ( ( nType == CTRL_SCROLLBAR ) &&
+ ( ( nPart == PART_BUTTON_UP ) ||
+ ( nPart == PART_BUTTON_DOWN ) ||
+ ( nPart == PART_BUTTON_LEFT ) ||
+ ( nPart == PART_BUTTON_RIGHT ) ) )
+ {
+ NWEnsureGTKScrollbars( m_nScreen );
+
+ // Grab some button style attributes
+ gboolean has_forward;
+ gboolean has_forward2;
+ gboolean has_backward;
+ gboolean has_backward2;
+
+ gtk_widget_style_get( gWidgetData[m_nScreen].gScrollHorizWidget, "has-forward-stepper", &has_forward,
+ "has-secondary-forward-stepper", &has_forward2,
+ "has-backward-stepper", &has_backward,
+ "has-secondary-backward-stepper", &has_backward2, (char *)NULL );
+ Rectangle aForward;
+ Rectangle aBackward;
+
+ rIsInside = FALSE;
+
+ ControlPart nCounterPart = 0;
+ if ( nPart == PART_BUTTON_UP )
+ nCounterPart = PART_BUTTON_DOWN;
+ else if ( nPart == PART_BUTTON_DOWN )
+ nCounterPart = PART_BUTTON_UP;
+ else if ( nPart == PART_BUTTON_LEFT )
+ nCounterPart = PART_BUTTON_RIGHT;
+ else if ( nPart == PART_BUTTON_RIGHT )
+ nCounterPart = PART_BUTTON_LEFT;
+
+ aBackward = NWGetScrollButtonRect( m_nScreen, nPart, rControlRegion );
+ aForward = NWGetScrollButtonRect( m_nScreen, nCounterPart, rControlRegion );
+
+ if ( has_backward && has_forward2 )
+ {
+ Size aSize( aBackward.GetSize() );
+ if ( ( nPart == PART_BUTTON_UP ) || ( nPart == PART_BUTTON_DOWN ) )
+ aSize.setHeight( aBackward.GetHeight() / 2 );
+ else
+ aSize.setWidth( aBackward.GetWidth() / 2 );
+ aBackward.SetSize( aSize );
+
+ if ( nPart == PART_BUTTON_DOWN )
+ aBackward.Move( 0, aBackward.GetHeight() / 2 );
+ else if ( nPart == PART_BUTTON_RIGHT )
+ aBackward.Move( aBackward.GetWidth() / 2, 0 );
+ }
+
+ if ( has_backward2 && has_forward )
+ {
+ Size aSize( aForward.GetSize() );
+ if ( ( nPart == PART_BUTTON_UP ) || ( nPart == PART_BUTTON_DOWN ) )
+ aSize.setHeight( aForward.GetHeight() / 2 );
+ else
+ aSize.setWidth( aForward.GetWidth() / 2 );
+ aForward.SetSize( aSize );
+
+ if ( nPart == PART_BUTTON_DOWN )
+ aForward.Move( 0, aForward.GetHeight() / 2 );
+ else if ( nPart == PART_BUTTON_RIGHT )
+ aForward.Move( aForward.GetWidth() / 2, 0 );
+ }
+
+ if ( ( nPart == PART_BUTTON_UP ) || ( nPart == PART_BUTTON_LEFT ) )
+ {
+ if ( has_backward )
+ rIsInside |= aBackward.IsInside( aPos );
+ if ( has_backward2 )
+ rIsInside |= aForward.IsInside( aPos );
+ }
+ else
+ {
+ if ( has_forward )
+ rIsInside |= aBackward.IsInside( aPos );
+ if ( has_forward2 )
+ rIsInside |= aForward.IsInside( aPos );
+ }
+ return ( TRUE );
+ }
+
+ if( IsNativeControlSupported(nType, nPart) )
+ {
+ rIsInside = rControlRegion.IsInside( aPos );
+ return( TRUE );
+ }
+ else
+ {
+ return( FALSE );
+ }
+}
+
+
+/*
+ * DrawNativeControl()
+ *
+ * Draws the requested control described by nPart/nState.
+ *
+ * rControlRegion: The bounding region of the complete control in VCL frame coordinates.
+ * aValue: An optional value (tristate/numerical/string)
+ * rCaption: A caption or title string (like button text etc)
+ */
+BOOL GtkSalGraphics::drawNativeControl( ControlType nType,
+ ControlPart nPart,
+ const Rectangle& rControlRegion,
+ ControlState nState,
+ const ImplControlValue& aValue,
+ const OUString& rCaption )
+{
+ BOOL returnVal = FALSE;
+ // get a GC with current clipping region set
+ GetFontGC();
+
+
+ // theme changed ?
+ if( GtkSalGraphics::bThemeChanged )
+ {
+ // invalidate caches
+ for( unsigned int i = 0; i < gWidgetData.size(); i++ )
+ if( gWidgetData[i].gNWPixmapCacheList )
+ gWidgetData[i].gNWPixmapCacheList->ThemeChanged();
+ GtkSalGraphics::bThemeChanged = FALSE;
+ }
+
+ Rectangle aCtrlRect( rControlRegion );
+ Region aClipRegion( m_aClipRegion );
+ if( aClipRegion.IsNull() )
+ aClipRegion = aCtrlRect;
+
+ clipList aClip;
+ GdkDrawable* gdkDrawable = GDK_DRAWABLE( GetGdkWindow() );
+ GdkPixmap* pixmap = NULL;
+ Rectangle aPixmapRect;
+ if( ( bNeedPixmapPaint )
+ && nType != CTRL_SCROLLBAR
+ && nType != CTRL_SPINBOX
+ && nType != CTRL_TAB_ITEM
+ && nType != CTRL_TAB_PANE
+ && nType != CTRL_PROGRESS
+ && ! (bToolbarGripWorkaround && nType == CTRL_TOOLBAR && (nPart == PART_THUMB_HORZ || nPart == PART_THUMB_VERT) )
+ )
+ {
+ // make pixmap a little larger since some themes draw decoration
+ // outside the rectangle, see e.g. checkbox
+ aPixmapRect = Rectangle( Point( aCtrlRect.Left()-1, aCtrlRect.Top()-1 ),
+ Size( aCtrlRect.GetWidth()+2, aCtrlRect.GetHeight()+2) );
+ pixmap = NWGetPixmapFromScreen( aPixmapRect );
+ if( ! pixmap )
+ return FALSE;
+ gdkDrawable = GDK_DRAWABLE( pixmap );
+ aCtrlRect = Rectangle( Point(1,1), aCtrlRect.GetSize() );
+ aClip.push_back( aCtrlRect );
+ }
+ else
+ {
+ RegionHandle aHdl = aClipRegion.BeginEnumRects();
+ Rectangle aPaintRect;
+ while( aClipRegion.GetNextEnumRect( aHdl, aPaintRect ) )
+ {
+ aPaintRect = aCtrlRect.GetIntersection( aPaintRect );
+ if( aPaintRect.IsEmpty() )
+ continue;
+ aClip.push_back( aPaintRect );
+ }
+ aClipRegion.EndEnumRects( aHdl );
+ }
+
+ if ( (nType==CTRL_PUSHBUTTON) && (nPart==PART_ENTIRE_CONTROL) )
+ {
+ returnVal = NWPaintGTKButton( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
+ }
+ else if ( (nType==CTRL_RADIOBUTTON) && (nPart==PART_ENTIRE_CONTROL) )
+ {
+ returnVal = NWPaintGTKRadio( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
+ }
+ else if ( (nType==CTRL_CHECKBOX) && (nPart==PART_ENTIRE_CONTROL) )
+ {
+ returnVal = NWPaintGTKCheck( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
+ }
+ else if ( (nType==CTRL_SCROLLBAR) && ((nPart==PART_DRAW_BACKGROUND_HORZ) || (nPart==PART_DRAW_BACKGROUND_VERT)) )
+ {
+ returnVal = NWPaintGTKScrollbar( nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
+ }
+ else if ( ((nType==CTRL_EDITBOX) && ((nPart==PART_ENTIRE_CONTROL) || (nPart==HAS_BACKGROUND_TEXTURE)) )
+ || ((nType==CTRL_SPINBOX) && (nPart==HAS_BACKGROUND_TEXTURE))
+ || ((nType==CTRL_COMBOBOX) && (nPart==HAS_BACKGROUND_TEXTURE))
+ || ((nType==CTRL_LISTBOX) && (nPart==HAS_BACKGROUND_TEXTURE)) )
+ {
+ returnVal = NWPaintGTKEditBox( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
+ }
+ else if ( ((nType==CTRL_MULTILINE_EDITBOX) && ((nPart==PART_ENTIRE_CONTROL) || (nPart==HAS_BACKGROUND_TEXTURE)) ) )
+ {
+ returnVal = NWPaintGTKEditBox( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
+ }
+ else if ( ((nType==CTRL_SPINBOX) || (nType==CTRL_SPINBUTTONS))
+ && ((nPart==PART_ENTIRE_CONTROL) || (nPart==PART_ALL_BUTTONS)) )
+ {
+ returnVal = NWPaintGTKSpinBox( nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
+ }
+ else if ( (nType == CTRL_COMBOBOX) &&
+ ( (nPart==PART_ENTIRE_CONTROL)
+ ||(nPart==PART_BUTTON_DOWN)
+ ) )
+ {
+ returnVal = NWPaintGTKComboBox( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
+ }
+ else if ( (nType==CTRL_TAB_ITEM) || (nType==CTRL_TAB_PANE) || (nType==CTRL_TAB_BODY) || (nType==CTRL_FIXEDBORDER) )
+ {
+ if ( nType == CTRL_TAB_BODY )
+ returnVal = TRUE;
+ else
+ returnVal = NWPaintGTKTabItem( nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption);
+ }
+ else if ( (nType==CTRL_LISTBOX) && ((nPart==PART_ENTIRE_CONTROL) || (nPart==PART_WINDOW)) )
+ {
+ returnVal = NWPaintGTKListBox( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
+ }
+ else if ( (nType== CTRL_TOOLBAR) )
+ {
+ returnVal = NWPaintGTKToolbar( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
+ }
+ else if ( (nType== CTRL_MENUBAR) )
+ {
+ returnVal = NWPaintGTKMenubar( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
+ }
+ else if( (nType == CTRL_MENU_POPUP)
+ && ( (nPart == PART_ENTIRE_CONTROL)
+ || (nPart == PART_MENU_ITEM)
+ || (nPart == PART_MENU_ITEM_CHECK_MARK)
+ || (nPart == PART_MENU_ITEM_RADIO_MARK)
+ )
+ )
+ {
+ returnVal = NWPaintGTKPopupMenu( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
+ }
+ else if( (nType == CTRL_TOOLTIP) && (nPart == PART_ENTIRE_CONTROL) )
+ {
+ returnVal = NWPaintGTKTooltip( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
+ }
+ else if( (nType == CTRL_PROGRESS) && (nPart == PART_ENTIRE_CONTROL) )
+ {
+ returnVal = NWPaintGTKProgress( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
+ }
+ else if( (nType == CTRL_LISTNODE) && (nPart == PART_ENTIRE_CONTROL) )
+ {
+ returnVal = NWPaintGTKListNode( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
+ }
+ else if( (nType == CTRL_LISTNET) && (nPart == PART_ENTIRE_CONTROL) )
+ {
+ // don't actually draw anything; gtk treeviews do not draw lines
+ returnVal = true;
+ }
+ else if( (nType == CTRL_SLIDER) )
+ {
+ returnVal = NWPaintGTKSlider( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
+ }
+
+ if( pixmap )
+ {
+ returnVal = NWRenderPixmapToScreen( pixmap, aPixmapRect ) && returnVal;
+ g_object_unref( pixmap );
+ }
+
+ return( returnVal );
+}
+
+/*
+ * DrawNativeControlText()
+ *
+ * OPTIONAL. Draws the requested text for the control described by nPart/nState.
+ * Used if text not drawn by DrawNativeControl().
+ *
+ * rControlRegion: The bounding region of the complete control in VCL frame coordinates.
+ * aValue: An optional value (tristate/numerical/string)
+ * rCaption: A caption or title string (like button text etc)
+ */
+BOOL GtkSalGraphics::drawNativeControlText( ControlType,
+ ControlPart,
+ const Rectangle&,
+ ControlState,
+ const ImplControlValue&,
+ const OUString& )
+{
+ return( FALSE );
+}
+
+
+/*
+ * GetNativeControlRegion()
+ *
+ * If the return value is TRUE, rNativeBoundingRegion
+ * contains the TRUE bounding region covered by the control
+ * including any adornment, while rNativeContentRegion contains the area
+ * within the control that can be safely drawn into without drawing over
+ * the borders of the control.
+ *
+ * rControlRegion: The bounding region of the control in VCL frame coordinates.
+ * aValue: An optional value (tristate/numerical/string)
+ * rCaption: A caption or title string (like button text etc)
+ */
+BOOL GtkSalGraphics::getNativeControlRegion( ControlType nType,
+ ControlPart nPart,
+ const Rectangle& rControlRegion,
+ ControlState nState,
+ const ImplControlValue& aValue,
+ const OUString& rCaption,
+ Rectangle &rNativeBoundingRegion,
+ Rectangle &rNativeContentRegion )
+{
+ BOOL returnVal = FALSE;
+
+ if ( (nType==CTRL_PUSHBUTTON) && (nPart==PART_ENTIRE_CONTROL)
+ && (rControlRegion.GetWidth() > 16)
+ && (rControlRegion.GetHeight() > 16) )
+ {
+ rNativeBoundingRegion = NWGetButtonArea( m_nScreen, nType, nPart, rControlRegion,
+ nState, aValue, rCaption );
+ rNativeContentRegion = rControlRegion;
+
+ returnVal = TRUE;
+ }
+ if ( (nType==CTRL_COMBOBOX) && ((nPart==PART_BUTTON_DOWN) || (nPart==PART_SUB_EDIT)) )
+ {
+ rNativeBoundingRegion = NWGetComboBoxButtonRect( m_nScreen, nType, nPart, rControlRegion, nState,
+ aValue, rCaption );
+ rNativeContentRegion = rNativeBoundingRegion;
+
+ returnVal = TRUE;
+ }
+ if ( (nType==CTRL_SPINBOX) && ((nPart==PART_BUTTON_UP) || (nPart==PART_BUTTON_DOWN) || (nPart==PART_SUB_EDIT)) )
+ {
+
+ rNativeBoundingRegion = NWGetSpinButtonRect( m_nScreen, nType, nPart, rControlRegion, nState,
+ aValue, rCaption );
+ rNativeContentRegion = rNativeBoundingRegion;
+
+ returnVal = TRUE;
+ }
+ if ( (nType==CTRL_LISTBOX) && ((nPart==PART_BUTTON_DOWN) || (nPart==PART_SUB_EDIT)) )
+ {
+ rNativeBoundingRegion = NWGetListBoxButtonRect( m_nScreen, nType, nPart, rControlRegion, nState,
+ aValue, rCaption );
+ rNativeContentRegion = rNativeBoundingRegion;
+
+ returnVal = TRUE;
+ }
+ if ( (nType==CTRL_TOOLBAR) &&
+ ((nPart==PART_DRAW_BACKGROUND_HORZ) ||
+ (nPart==PART_DRAW_BACKGROUND_VERT) ||
+ (nPart==PART_THUMB_HORZ) ||
+ (nPart==PART_THUMB_VERT) ||
+ (nPart==PART_BUTTON)
+ ))
+ {
+ rNativeBoundingRegion = NWGetToolbarRect( m_nScreen, nType, nPart, rControlRegion, nState, aValue, rCaption );
+ rNativeContentRegion = rNativeBoundingRegion;
+ returnVal = TRUE;
+ }
+ if ( (nType==CTRL_SCROLLBAR) && ((nPart==PART_BUTTON_LEFT) || (nPart==PART_BUTTON_RIGHT) ||
+ (nPart==PART_BUTTON_UP) || (nPart==PART_BUTTON_DOWN) ) )
+ {
+ rNativeBoundingRegion = NWGetScrollButtonRect( m_nScreen, nPart, rControlRegion );
+ rNativeContentRegion = rNativeBoundingRegion;
+
+ returnVal = TRUE;
+ }
+ if( (nType == CTRL_MENUBAR) && (nPart == PART_ENTIRE_CONTROL) )
+ {
+ NWEnsureGTKMenubar( m_nScreen );
+ GtkRequisition aReq;
+ gtk_widget_size_request( gWidgetData[m_nScreen].gMenubarWidget, &aReq );
+ Rectangle aMenuBarRect = rControlRegion;
+ aMenuBarRect = Rectangle( aMenuBarRect.TopLeft(),
+ Size( aMenuBarRect.GetWidth(), aReq.height+1 ) );
+ rNativeBoundingRegion = aMenuBarRect;
+ rNativeContentRegion = rNativeBoundingRegion;
+ returnVal = TRUE;
+ }
+ if( (nType == CTRL_MENU_POPUP) )
+ {
+ if( (nPart == PART_MENU_ITEM_CHECK_MARK) ||
+ (nPart == PART_MENU_ITEM_RADIO_MARK) )
+ {
+ NWEnsureGTKMenu( m_nScreen );
+
+ gint indicator_size = 0;
+ GtkWidget* pWidget = (nPart == PART_MENU_ITEM_CHECK_MARK) ?
+ gWidgetData[m_nScreen].gMenuItemCheckMenuWidget : gWidgetData[m_nScreen].gMenuItemRadioMenuWidget;
+ gtk_widget_style_get( pWidget,
+ "indicator_size", &indicator_size,
+ (char *)NULL );
+ rNativeBoundingRegion = rControlRegion;
+ Rectangle aIndicatorRect( Point( 0,
+ (rControlRegion.GetHeight()-indicator_size)/2),
+ Size( indicator_size, indicator_size ) );
+ rNativeContentRegion = aIndicatorRect;
+ returnVal = TRUE;
+ }
+ }
+ if( (nType == CTRL_RADIOBUTTON || nType == CTRL_CHECKBOX) )
+ {
+ NWEnsureGTKRadio( m_nScreen );
+ NWEnsureGTKCheck( m_nScreen );
+ GtkWidget* widget = (nType == CTRL_RADIOBUTTON) ? gWidgetData[m_nScreen].gRadioWidget : gWidgetData[m_nScreen].gCheckWidget;
+ gint indicator_size, indicator_spacing;
+ gtk_widget_style_get( widget,
+ "indicator_size", &indicator_size,
+ "indicator_spacing", &indicator_spacing,
+ (char *)NULL);
+ indicator_size += 2*indicator_spacing; // guess overpaint of theme
+ rNativeBoundingRegion = rControlRegion;
+ Rectangle aIndicatorRect( Point( 0,
+ (rControlRegion.GetHeight()-indicator_size)/2),
+ Size( indicator_size, indicator_size ) );
+ rNativeContentRegion = aIndicatorRect;
+ returnVal = TRUE;
+ }
+ if( (nType == CTRL_EDITBOX || nType == CTRL_SPINBOX) && nPart == PART_ENTIRE_CONTROL )
+ {
+ NWEnsureGTKEditBox( m_nScreen );
+ GtkWidget* widget = gWidgetData[m_nScreen].gEditBoxWidget;
+ GtkRequisition aReq;
+ gtk_widget_size_request( widget, &aReq );
+ Rectangle aEditRect = rControlRegion;
+ long nHeight = (aEditRect.GetHeight() > aReq.height+1) ? aEditRect.GetHeight() : aReq.height+1;
+ aEditRect = Rectangle( aEditRect.TopLeft(),
+ Size( aEditRect.GetWidth(), nHeight ) );
+ rNativeBoundingRegion = aEditRect;
+ rNativeContentRegion = rNativeBoundingRegion;
+ returnVal = TRUE;
+ }
+ if( (nType == CTRL_SLIDER) && (nPart == PART_THUMB_HORZ || nPart == PART_THUMB_VERT) )
+ {
+ NWEnsureGTKSlider( m_nScreen );
+ GtkWidget* widget = (nPart == PART_THUMB_HORZ) ? gWidgetData[m_nScreen].gHScale : gWidgetData[m_nScreen].gVScale;
+ gint slider_length = 10;
+ gint slider_width = 10;
+ gtk_widget_style_get( widget,
+ "slider-width", &slider_width,
+ "slider-length", &slider_length,
+ (char *)NULL);
+ Rectangle aRect( rControlRegion );
+ if( nPart == PART_THUMB_HORZ )
+ {
+ aRect.Right() = aRect.Left() + slider_length - 1;
+ aRect.Bottom() = aRect.Top() + slider_width - 1;
+ }
+ else
+ {
+ aRect.Bottom() = aRect.Top() + slider_length - 1;
+ aRect.Right() = aRect.Left() + slider_width - 1;
+ }
+ rNativeBoundingRegion = rNativeContentRegion = aRect;
+ returnVal = TRUE;
+ }
+
+ return( returnVal );
+}
+
+
+/************************************************************************
+ * Individual control drawing functions
+ ************************************************************************/
+BOOL GtkSalGraphics::NWPaintGTKButton(
+ GdkDrawable* gdkDrawable,
+ ControlType, ControlPart,
+ const Rectangle& rControlRectangle,
+ const clipList& rClipList,
+ ControlState nState, const ImplControlValue&,
+ const OUString& )
+{
+ GtkStateType stateType;
+ GtkShadowType shadowType;
+ gboolean interiorFocus;
+ gint focusWidth;
+ gint focusPad;
+ BOOL bDrawFocus = TRUE;
+ gint x, y, w, h;
+ GtkBorder aDefBorder;
+ GtkBorder* pBorder;
+ GdkRectangle clipRect;
+
+ NWEnsureGTKButton( m_nScreen );
+ NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
+
+ x = rControlRectangle.Left();
+ y = rControlRectangle.Top();
+ w = rControlRectangle.GetWidth();
+ h = rControlRectangle.GetHeight();
+
+ // Grab some button style attributes
+ gtk_widget_style_get( gWidgetData[m_nScreen].gBtnWidget, "focus-line-width", &focusWidth,
+ "focus-padding", &focusPad,
+ "interior_focus", &interiorFocus,
+ "default_border", &pBorder,
+ (char *)NULL );
+
+ // Make sure the border values exist, otherwise use some defaults
+ if ( pBorder )
+ {
+ NW_gtk_border_set_from_border( aDefBorder, pBorder );
+ gtk_border_free( pBorder );
+ }
+ else NW_gtk_border_set_from_border( aDefBorder, &aDefDefBorder );
+
+ // If the button is too small, don't ever draw focus or grab more space
+ if ( (w < 16) || (h < 16) )
+ bDrawFocus = FALSE;
+
+ NWSetWidgetState( gWidgetData[m_nScreen].gBtnWidget, nState, stateType );
+
+ gint xi = x, yi = y, wi = w, hi = h;
+ if ( (nState & CTRL_STATE_DEFAULT) && bDrawFocus )
+ {
+ xi += aDefBorder.left;
+ yi += aDefBorder.top;
+ wi -= aDefBorder.left + aDefBorder.right;
+ hi -= aDefBorder.top + aDefBorder.bottom;
+ }
+
+ if ( !interiorFocus && bDrawFocus )
+ {
+ xi += focusWidth + focusPad;
+ yi += focusWidth + focusPad;
+ wi -= 2 * (focusWidth + focusPad);
+ hi -= 2 * (focusWidth + focusPad);
+ }
+
+ for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it)
+ {
+ clipRect.x = it->Left();
+ clipRect.y = it->Top();
+ clipRect.width = it->GetWidth();
+ clipRect.height = it->GetHeight();
+
+ // Buttons must paint opaque since some themes have alpha-channel enabled buttons
+ gtk_paint_flat_box( gWidgetData[m_nScreen].gBtnWidget->style, gdkDrawable, GTK_STATE_NORMAL, GTK_SHADOW_NONE,
+ &clipRect, m_pWindow, "base", x, y, w, h );
+
+ if ( (nState & CTRL_STATE_DEFAULT) && (GTK_BUTTON(gWidgetData[m_nScreen].gBtnWidget)->relief == GTK_RELIEF_NORMAL) )
+ {
+ gtk_paint_box( gWidgetData[m_nScreen].gBtnWidget->style, gdkDrawable, GTK_STATE_NORMAL, GTK_SHADOW_IN,
+ &clipRect, gWidgetData[m_nScreen].gBtnWidget, "buttondefault", x, y, w, h );
+ }
+
+ if ( (GTK_BUTTON(gWidgetData[m_nScreen].gBtnWidget)->relief != GTK_RELIEF_NONE)
+ || (nState & CTRL_STATE_PRESSED)
+ || (nState & CTRL_STATE_ROLLOVER) )
+ {
+ gtk_paint_box( gWidgetData[m_nScreen].gBtnWidget->style, gdkDrawable, stateType, shadowType,
+ &clipRect, gWidgetData[m_nScreen].gBtnWidget, "button", xi, yi, wi, hi );
+ }
+ }
+#if 0 // VCL draws focus rects
+ // Draw focus rect
+ if ( (nState & CTRL_STATE_FOCUSED) && (nState & CTRL_STATE_ENABLED) && bDrawFocus )
+ {
+ if (interiorFocus)
+ {
+ x += gWidgetData[m_nScreen].gBtnWidget->style->xthickness + focusPad;
+ y += gWidgetData[m_nScreen].gBtnWidget->style->ythickness + focusPad;
+ w -= 2 * (gWidgetData[m_nScreen].gBtnWidget->style->xthickness + focusPad);
+ h -= 2 * (gWidgetData[m_nScreen].gBtnWidget->style->xthickness + focusPad);
+ }
+ else
+ {
+ x -= focusWidth + focusPad;
+ y -= focusWidth + focusPad;
+ w += 2 * (focusWidth + focusPad);
+ h += 2 * (focusWidth + focusPad);
+ }
+ if ( !interiorFocus )
+ gtk_paint_focus( gWidgetData[m_nScreen].gBtnWidget->style, gdkDrawable, stateType, &clipRect,
+ gWidgetData[m_nScreen].gBtnWidget, "button", x, y, w, h );
+ }
+#endif
+
+ return( TRUE );
+}
+
+static Rectangle NWGetButtonArea( int nScreen,
+ ControlType, ControlPart, Rectangle aAreaRect, ControlState nState,
+ const ImplControlValue&, const OUString& )
+{
+ gboolean interiorFocus;
+ gint focusWidth;
+ gint focusPad;
+ GtkBorder aDefBorder;
+ GtkBorder * pBorder;
+ BOOL bDrawFocus = TRUE;
+ Rectangle aRect;
+ gint x, y, w, h;
+
+ NWEnsureGTKButton( nScreen );
+ gtk_widget_style_get( gWidgetData[nScreen].gBtnWidget,
+ "focus-line-width", &focusWidth,
+ "focus-padding", &focusPad,
+ "interior_focus", &interiorFocus,
+ "default_border", &pBorder,
+ (char *)NULL );
+
+ // Make sure the border values exist, otherwise use some defaults
+ if ( pBorder )
+ {
+ NW_gtk_border_set_from_border( aDefBorder, pBorder );
+ gtk_border_free( pBorder );
+ }
+ else NW_gtk_border_set_from_border( aDefBorder, &aDefDefBorder );
+
+ x = aAreaRect.Left();
+ y = aAreaRect.Top();
+ w = aAreaRect.GetWidth();
+ h = aAreaRect.GetHeight();
+
+ // If the button is too small, don't ever draw focus or grab more space
+ if ( (w < 16) || (h < 16) )
+ bDrawFocus = FALSE;
+
+ if ( (nState & CTRL_STATE_DEFAULT) && bDrawFocus )
+ {
+ x -= aDefBorder.left;
+ y -= aDefBorder.top;
+ w += aDefBorder.left + aDefBorder.right;
+ h += aDefBorder.top + aDefBorder.bottom;
+ }
+
+ aRect = Rectangle( Point( x, y ), Size( w, h ) );
+
+ return( aRect );
+}
+
+//-------------------------------------
+
+BOOL GtkSalGraphics::NWPaintGTKRadio( GdkDrawable* gdkDrawable,
+ ControlType, ControlPart,
+ const Rectangle& rControlRectangle,
+ const clipList& rClipList,
+ ControlState nState,
+ const ImplControlValue& aValue,
+ const OUString& )
+{
+ GtkStateType stateType;
+ GtkShadowType shadowType;
+ BOOL isChecked = (aValue.getTristateVal()==BUTTONVALUE_ON);
+ gint x, y;
+ GdkRectangle clipRect;
+
+ NWEnsureGTKButton( m_nScreen );
+ NWEnsureGTKRadio( m_nScreen );
+ NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
+
+ gint indicator_size;
+ gtk_widget_style_get( gWidgetData[m_nScreen].gRadioWidget, "indicator_size", &indicator_size, (char *)NULL);
+
+ x = rControlRectangle.Left() + (rControlRectangle.GetWidth()-indicator_size)/2;
+ y = rControlRectangle.Top() + (rControlRectangle.GetHeight()-indicator_size)/2;
+
+ // Set the shadow based on if checked or not so we get a freakin checkmark.
+ shadowType = isChecked ? GTK_SHADOW_IN : GTK_SHADOW_OUT;
+ NWSetWidgetState( gWidgetData[m_nScreen].gRadioWidget, nState, stateType );
+ NWSetWidgetState( gWidgetData[m_nScreen].gRadioWidgetSibling, nState, stateType );
+
+ // GTK enforces radio groups, so that if we don't have 2 buttons in the group,
+ // the single button will always be active. So we have to have 2 buttons.
+
+ // #i59666# set the members directly where we should use
+ // gtk_toggle_button_set_active. reason: there are animated themes
+ // which are in active state only after a while leading to painting
+ // intermediate states between active/inactive. Let's hope that
+ // GtkToggleButtone stays binary compatible.
+ if (!isChecked)
+ GTK_TOGGLE_BUTTON(gWidgetData[m_nScreen].gRadioWidgetSibling)->active = TRUE;
+ GTK_TOGGLE_BUTTON(gWidgetData[m_nScreen].gRadioWidget)->active = isChecked;
+
+ for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it )
+ {
+ clipRect.x = it->Left();
+ clipRect.y = it->Top();
+ clipRect.width = it->GetWidth();
+ clipRect.height = it->GetHeight();
+
+ gtk_paint_option( gWidgetData[m_nScreen].gRadioWidget->style, gdkDrawable, stateType, shadowType,
+ &clipRect, gWidgetData[m_nScreen].gRadioWidget, "radiobutton",
+ x, y, indicator_size, indicator_size );
+ }
+
+ return( TRUE );
+}
+
+//-------------------------------------
+
+BOOL GtkSalGraphics::NWPaintGTKCheck( GdkDrawable* gdkDrawable,
+ ControlType, ControlPart,
+ const Rectangle& rControlRectangle,
+ const clipList& rClipList,
+ ControlState nState,
+ const ImplControlValue& aValue,
+ const OUString& )
+{
+ GtkStateType stateType;
+ GtkShadowType shadowType;
+ bool isChecked = (aValue.getTristateVal() == BUTTONVALUE_ON);
+ bool isInconsistent = (aValue.getTristateVal() == BUTTONVALUE_MIXED);
+ GdkRectangle clipRect;
+ gint x,y;
+
+ NWEnsureGTKButton( m_nScreen );
+ NWEnsureGTKCheck( m_nScreen );
+ NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
+
+ gint indicator_size;
+ gtk_widget_style_get( gWidgetData[m_nScreen].gCheckWidget, "indicator_size", &indicator_size, (char *)NULL);
+
+ x = rControlRectangle.Left() + (rControlRectangle.GetWidth()-indicator_size)/2;
+ y = rControlRectangle.Top() + (rControlRectangle.GetHeight()-indicator_size)/2;
+
+ // Set the shadow based on if checked or not so we get a checkmark.
+ shadowType = isChecked ? GTK_SHADOW_IN : isInconsistent ? GTK_SHADOW_ETCHED_IN : GTK_SHADOW_OUT;
+ NWSetWidgetState( gWidgetData[m_nScreen].gCheckWidget, nState, stateType );
+ GTK_TOGGLE_BUTTON(gWidgetData[m_nScreen].gCheckWidget)->active = isChecked;
+
+ for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it )
+ {
+ clipRect.x = it->Left();
+ clipRect.y = it->Top();
+ clipRect.width = it->GetWidth();
+ clipRect.height = it->GetHeight();
+
+ gtk_paint_check( gWidgetData[m_nScreen].gCheckWidget->style, gdkDrawable, stateType, shadowType,
+ &clipRect, gWidgetData[m_nScreen].gCheckWidget, "checkbutton",
+ x, y, indicator_size, indicator_size );
+ }
+
+ return( TRUE );
+}
+
+//-------------------------------------
+static void NWCalcArrowRect( const Rectangle& rButton, Rectangle& rArrow )
+{
+ // Size the arrow appropriately
+ Size aSize( rButton.GetWidth()/2, rButton.GetHeight()/2 );
+ rArrow.SetSize( aSize );
+
+ rArrow.SetPos( Point(
+ rButton.Left() + ( rButton.GetWidth() - rArrow.GetWidth() ) / 2,
+ rButton.Top() + ( rButton.GetHeight() - rArrow.GetHeight() ) / 2
+ ) );
+}
+
+BOOL GtkSalGraphics::NWPaintGTKScrollbar( ControlType, ControlPart nPart,
+ const Rectangle& rControlRectangle,
+ const clipList&,
+ ControlState nState,
+ const ImplControlValue& aValue,
+ const OUString& )
+{
+ OSL_ASSERT( aValue.getType() == CTRL_SCROLLBAR );
+ const ScrollbarValue* pScrollbarVal = static_cast<const ScrollbarValue *>(&aValue);
+ GdkPixmap* pixmap = NULL;
+ Rectangle pixmapRect, scrollbarRect;
+ GtkStateType stateType;
+ GtkShadowType shadowType;
+ GtkScrollbar * scrollbarWidget;
+ GtkStyle * style;
+ GtkAdjustment* scrollbarValues = NULL;
+ GtkOrientation scrollbarOrientation;
+ Rectangle thumbRect = pScrollbarVal->maThumbRect;
+ Rectangle button11BoundRect = pScrollbarVal->maButton1Rect; // backward
+ Rectangle button22BoundRect = pScrollbarVal->maButton2Rect; // forward
+ Rectangle button12BoundRect = pScrollbarVal->maButton1Rect; // secondary forward
+ Rectangle button21BoundRect = pScrollbarVal->maButton2Rect; // secondary backward
+ GtkArrowType button1Type; // backward
+ GtkArrowType button2Type; // forward
+ gchar * scrollbarTagH = (gchar *) "hscrollbar";
+ gchar * scrollbarTagV = (gchar *) "vscrollbar";
+ gchar * scrollbarTag = NULL;
+ Rectangle arrowRect;
+ gint slider_width = 0;
+ gint stepper_size = 0;
+ gint stepper_spacing = 0;
+ gint trough_border = 0;
+ gint min_slider_length = 0;
+ gint vShim = 0;
+ gint hShim = 0;
+ gint x,y,w,h;
+
+ // make controlvalue rectangles relative to area
+ thumbRect.Move( -rControlRectangle.Left(), -rControlRectangle.Top() );
+ button11BoundRect.Move( -rControlRectangle.Left(), -rControlRectangle.Top() );
+ button22BoundRect.Move( -rControlRectangle.Left(), -rControlRectangle.Top() );
+ button12BoundRect.Move( -rControlRectangle.Left(), -rControlRectangle.Top() );
+ button21BoundRect.Move( -rControlRectangle.Left(), -rControlRectangle.Top() );
+
+ NWEnsureGTKButton( m_nScreen );
+ NWEnsureGTKScrollbars( m_nScreen );
+ NWEnsureGTKArrow( m_nScreen );
+
+ // Find the overall bounding rect of the control
+ pixmapRect = rControlRectangle;
+ pixmapRect.SetSize( Size( pixmapRect.GetWidth() + 1,
+ pixmapRect.GetHeight() + 1 ) );
+ scrollbarRect = pixmapRect;
+
+ if ( (scrollbarRect.GetWidth() <= 1) || (scrollbarRect.GetHeight() <= 1) )
+ return( TRUE );
+
+ // Grab some button style attributes
+ gtk_widget_style_get( gWidgetData[m_nScreen].gScrollHorizWidget,
+ "slider_width", &slider_width,
+ "stepper_size", &stepper_size,
+ "trough_border", &trough_border,
+ "stepper_spacing", &stepper_spacing,
+ "min_slider_length", &min_slider_length, (char *)NULL );
+ gboolean has_forward;
+ gboolean has_forward2;
+ gboolean has_backward;
+ gboolean has_backward2;
+
+ gtk_widget_style_get( gWidgetData[m_nScreen].gScrollHorizWidget, "has-forward-stepper", &has_forward,
+ "has-secondary-forward-stepper", &has_forward2,
+ "has-backward-stepper", &has_backward,
+ "has-secondary-backward-stepper", &has_backward2, (char *)NULL );
+ gint magic = trough_border ? 1 : 0;
+ gint nFirst = 0;
+
+ if ( has_backward ) nFirst += 1;
+ if ( has_forward2 ) nFirst += 1;
+
+ if ( nPart == PART_DRAW_BACKGROUND_HORZ )
+ {
+ unsigned int sliderHeight = slider_width + (trough_border * 2);
+ vShim = (pixmapRect.GetHeight() - sliderHeight) / 2;
+
+ scrollbarRect.Move( 0, vShim );
+ scrollbarRect.SetSize( Size( scrollbarRect.GetWidth(), sliderHeight ) );
+
+ scrollbarWidget = GTK_SCROLLBAR( gWidgetData[m_nScreen].gScrollHorizWidget );
+ scrollbarOrientation = GTK_ORIENTATION_HORIZONTAL;
+ scrollbarTag = scrollbarTagH;
+ button1Type = GTK_ARROW_LEFT;
+ button2Type = GTK_ARROW_RIGHT;
+
+ if ( has_backward )
+ {
+ button12BoundRect.Move( stepper_size - trough_border,
+ (scrollbarRect.GetHeight() - slider_width) / 2 );
+ }
+
+ button11BoundRect.Move( trough_border, (scrollbarRect.GetHeight() - slider_width) / 2 );
+ button11BoundRect.SetSize( Size( stepper_size, slider_width ) );
+ button12BoundRect.SetSize( Size( stepper_size, slider_width ) );
+
+ if ( has_backward2 )
+ {
+ button22BoundRect.Move( stepper_size+(trough_border+1)/2, (scrollbarRect.GetHeight() - slider_width) / 2 );
+ button21BoundRect.Move( (trough_border+1)/2, (scrollbarRect.GetHeight() - slider_width) / 2 );
+ }
+ else
+ {
+ button22BoundRect.Move( (trough_border+1)/2, (scrollbarRect.GetHeight() - slider_width) / 2 );
+ }
+
+ button21BoundRect.SetSize( Size( stepper_size, slider_width ) );
+ button22BoundRect.SetSize( Size( stepper_size, slider_width ) );
+
+ thumbRect.Bottom() = thumbRect.Top() + slider_width - 1;
+ // Make sure the thumb is at least the default width (so we don't get tiny thumbs),
+ // but if the VCL gives us a size smaller than the theme's default thumb size,
+ // honor the VCL size
+#if 0
+ if ( (thumbRect.GetWidth() < min_slider_length)
+ && ((scrollbarRect.GetWidth()-button1BoundRect.GetWidth()-button2BoundRect.GetWidth()) > min_slider_length) )
+ thumbRect.SetSize( Size( min_slider_length, thumbRect.GetHeight() ) );
+#endif
+
+ thumbRect.Right() += magic;
+ // Center vertically in the track
+ thumbRect.Move( 0, (scrollbarRect.GetHeight() - slider_width) / 2 );
+ }
+ else
+ {
+ unsigned int sliderWidth = slider_width + (trough_border * 2);
+ hShim = (pixmapRect.GetWidth() - sliderWidth) / 2;
+
+ scrollbarRect.Move( hShim, 0 );
+ scrollbarRect.SetSize( Size( sliderWidth, scrollbarRect.GetHeight() ) );
+
+ scrollbarWidget = GTK_SCROLLBAR( gWidgetData[m_nScreen].gScrollVertWidget );
+ scrollbarOrientation = GTK_ORIENTATION_VERTICAL;
+ scrollbarTag = scrollbarTagV;
+ button1Type = GTK_ARROW_UP;
+ button2Type = GTK_ARROW_DOWN;
+
+ if ( has_backward )
+ {
+ button12BoundRect.Move( (scrollbarRect.GetWidth() - slider_width) / 2,
+ stepper_size + trough_border );
+ }
+ button11BoundRect.Move( (scrollbarRect.GetWidth() - slider_width) / 2, trough_border );
+ button11BoundRect.SetSize( Size( slider_width, stepper_size ) );
+ button12BoundRect.SetSize( Size( slider_width, stepper_size ) );
+
+ if ( has_backward2 )
+ {
+ button22BoundRect.Move( (scrollbarRect.GetWidth() - slider_width) / 2, stepper_size+(trough_border+1)/2 );
+ button21BoundRect.Move( (scrollbarRect.GetWidth() - slider_width) / 2, (trough_border+1)/2 );
+ }
+ else
+ {
+ button22BoundRect.Move( (scrollbarRect.GetWidth() - slider_width) / 2, (trough_border+1)/2 );
+ }
+
+ button21BoundRect.SetSize( Size( slider_width, stepper_size ) );
+ button22BoundRect.SetSize( Size( slider_width, stepper_size ) );
+
+ thumbRect.Right() = thumbRect.Left() + slider_width - 1;
+#if 0
+ // Make sure the thumb is at least the default width (so we don't get tiny thumbs),
+ // but if the VCL gives us a size smaller than the theme's default thumb size,
+ // honor the VCL size
+ if ( (thumbRect.GetHeight() < min_slider_length)
+ && ((scrollbarRect.GetHeight()-button1BoundRect.GetHeight()-button2BoundRect.GetHeight()) > min_slider_length) )
+ thumbRect.SetSize( Size( thumbRect.GetWidth(), min_slider_length ) );
+#endif
+
+ thumbRect.Bottom() += magic;
+ // Center horizontally in the track
+ thumbRect.Move( (scrollbarRect.GetWidth() - slider_width) / 2, 0 );
+ }
+
+ BOOL has_slider = ( thumbRect.GetWidth() > 0 && thumbRect.GetHeight() > 0 );
+
+ scrollbarValues = gtk_range_get_adjustment( GTK_RANGE(scrollbarWidget) );
+ if ( scrollbarValues == NULL )
+ scrollbarValues = GTK_ADJUSTMENT( gtk_adjustment_new(0, 0, 0, 0, 0, 0) );
+ if ( nPart == PART_DRAW_BACKGROUND_HORZ )
+ {
+ scrollbarValues->lower = pScrollbarVal->mnMin;
+ scrollbarValues->upper = pScrollbarVal->mnMax;
+ scrollbarValues->value = pScrollbarVal->mnCur;
+ scrollbarValues->page_size = scrollbarRect.GetWidth() / 2;
+ }
+ else
+ {
+ scrollbarValues->lower = pScrollbarVal->mnMin;
+ scrollbarValues->upper = pScrollbarVal->mnMax;
+ scrollbarValues->value = pScrollbarVal->mnCur;
+ scrollbarValues->page_size = scrollbarRect.GetHeight() / 2;
+ }
+ gtk_adjustment_changed( scrollbarValues );
+
+ // as multiple paints are required for the scrollbar
+ // painting them directly to the window flickers
+ pixmap = NWGetPixmapFromScreen( pixmapRect );
+ if( ! pixmap )
+ return FALSE;
+ x = y = 0;
+
+ w = pixmapRect.GetWidth();
+ h = pixmapRect.GetHeight();
+
+ GdkDrawable* const &gdkDrawable = GDK_DRAWABLE( pixmap );
+ GdkRectangle* gdkRect = NULL;
+
+ NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
+ NWSetWidgetState( GTK_WIDGET(scrollbarWidget), nState, stateType );
+ NWSetWidgetState( gWidgetData[m_nScreen].gBtnWidget, nState, stateType );
+ style = GTK_WIDGET( scrollbarWidget )->style;
+
+ // ----------------- TROUGH
+ gtk_paint_flat_box( gWidgetData[m_nScreen].gBtnWidget->style, gdkDrawable,
+ GTK_STATE_NORMAL, GTK_SHADOW_NONE, gdkRect,
+ m_pWindow, "base", x, y,
+ w, h );
+ gtk_paint_box( style, gdkDrawable, GTK_STATE_ACTIVE, GTK_SHADOW_IN,
+ gdkRect, GTK_WIDGET(scrollbarWidget), "trough",
+ x, y,
+ scrollbarRect.GetWidth(), scrollbarRect.GetHeight() );
+
+ if ( nState & CTRL_STATE_FOCUSED )
+ {
+ gtk_paint_focus( style, gdkDrawable, GTK_STATE_ACTIVE,
+ gdkRect, GTK_WIDGET(scrollbarWidget), "trough",
+ x, y,
+ scrollbarRect.GetWidth(), scrollbarRect.GetHeight() );
+ }
+
+ // ----------------- THUMB
+ if ( has_slider )
+ {
+ NWConvertVCLStateToGTKState( pScrollbarVal->mnThumbState, &stateType, &shadowType );
+ if ( pScrollbarVal->mnThumbState & CTRL_STATE_PRESSED ) stateType = GTK_STATE_PRELIGHT;
+ gtk_paint_slider( style, gdkDrawable, stateType, GTK_SHADOW_OUT,
+ gdkRect, GTK_WIDGET(scrollbarWidget), "slider",
+ x+hShim+thumbRect.Left(), y+vShim+thumbRect.Top(),
+ thumbRect.GetWidth(), thumbRect.GetHeight(), scrollbarOrientation );
+ }
+ // ----------------- BUTTON 1 //
+ if ( has_backward )
+ {
+ NWConvertVCLStateToGTKState( pScrollbarVal->mnButton1State, &stateType, &shadowType );
+ if ( stateType == GTK_STATE_INSENSITIVE ) stateType = GTK_STATE_NORMAL;
+ gtk_paint_box( style, gdkDrawable, stateType, shadowType,
+ gdkRect, GTK_WIDGET(scrollbarWidget), "stepper",
+ x+hShim+button11BoundRect.Left(), y+vShim+button11BoundRect.Top(),
+ button11BoundRect.GetWidth(), button11BoundRect.GetHeight() );
+ // ----------------- ARROW 1
+ NWCalcArrowRect( button11BoundRect, arrowRect );
+ gtk_paint_arrow( style, gdkDrawable, stateType, shadowType,
+ gdkRect, GTK_WIDGET(scrollbarWidget), scrollbarTag, button1Type, TRUE,
+ x+hShim+arrowRect.Left(), y+vShim+arrowRect.Top(),
+ arrowRect.GetWidth(), arrowRect.GetHeight() );
+ }
+ if ( has_forward2 )
+ {
+ NWConvertVCLStateToGTKState( pScrollbarVal->mnButton2State, &stateType, &shadowType );
+ if ( stateType == GTK_STATE_INSENSITIVE ) stateType = GTK_STATE_NORMAL;
+ gtk_paint_box( style, gdkDrawable, stateType, shadowType,
+ gdkRect, GTK_WIDGET(scrollbarWidget), "stepper",
+ x+hShim+button12BoundRect.Left(), y+vShim+button12BoundRect.Top(),
+ button12BoundRect.GetWidth(), button12BoundRect.GetHeight() );
+ // ----------------- ARROW 1
+ NWCalcArrowRect( button12BoundRect, arrowRect );
+ gtk_paint_arrow( style, gdkDrawable, stateType, shadowType,
+ gdkRect, GTK_WIDGET(scrollbarWidget), scrollbarTag, button2Type, TRUE,
+ x+hShim+arrowRect.Left(), y+vShim+arrowRect.Top(),
+ arrowRect.GetWidth(), arrowRect.GetHeight() );
+ }
+ // ----------------- BUTTON 2
+ if ( has_backward2 )
+ {
+ NWConvertVCLStateToGTKState( pScrollbarVal->mnButton1State, &stateType, &shadowType );
+ if ( stateType == GTK_STATE_INSENSITIVE ) stateType = GTK_STATE_NORMAL;
+ gtk_paint_box( style, gdkDrawable, stateType, shadowType, gdkRect,
+ GTK_WIDGET(scrollbarWidget), "stepper",
+ x+hShim+button21BoundRect.Left(), y+vShim+button21BoundRect.Top(),
+ button21BoundRect.GetWidth(), button21BoundRect.GetHeight() );
+ // ----------------- ARROW 2
+ NWCalcArrowRect( button21BoundRect, arrowRect );
+ gtk_paint_arrow( style, gdkDrawable, stateType, shadowType,
+ gdkRect, GTK_WIDGET(scrollbarWidget), scrollbarTag, button1Type, TRUE,
+ x+hShim+arrowRect.Left(), y+vShim+arrowRect.Top(),
+ arrowRect.GetWidth(), arrowRect.GetHeight() );
+ }
+ if ( has_forward )
+ {
+ NWConvertVCLStateToGTKState( pScrollbarVal->mnButton2State, &stateType, &shadowType );
+ if ( stateType == GTK_STATE_INSENSITIVE ) stateType = GTK_STATE_NORMAL;
+ gtk_paint_box( style, gdkDrawable, stateType, shadowType, gdkRect,
+ GTK_WIDGET(scrollbarWidget), "stepper",
+ x+hShim+button22BoundRect.Left(), y+vShim+button22BoundRect.Top(),
+ button22BoundRect.GetWidth(), button22BoundRect.GetHeight() );
+ // ----------------- ARROW 2
+ NWCalcArrowRect( button22BoundRect, arrowRect );
+ gtk_paint_arrow( style, gdkDrawable, stateType, shadowType,
+ gdkRect, GTK_WIDGET(scrollbarWidget), scrollbarTag, button2Type, TRUE,
+ x+hShim+arrowRect.Left(), y+vShim+arrowRect.Top(),
+ arrowRect.GetWidth(), arrowRect.GetHeight() );
+ }
+
+ if( !NWRenderPixmapToScreen(pixmap, pixmapRect) )
+ {
+ g_object_unref( pixmap );
+ return( FALSE );
+ }
+ g_object_unref( pixmap );
+
+ return( TRUE );
+}
+
+//---
+
+static Rectangle NWGetScrollButtonRect( int nScreen, ControlPart nPart, Rectangle aAreaRect )
+{
+ gint slider_width;
+ gint stepper_size;
+ gint stepper_spacing;
+ gint trough_border;
+
+ NWEnsureGTKScrollbars( nScreen );
+
+ // Grab some button style attributes
+ gtk_widget_style_get( gWidgetData[nScreen].gScrollHorizWidget,
+ "slider-width", &slider_width,
+ "stepper-size", &stepper_size,
+ "trough-border", &trough_border,
+ "stepper-spacing", &stepper_spacing, (char *)NULL );
+
+ gboolean has_forward;
+ gboolean has_forward2;
+ gboolean has_backward;
+ gboolean has_backward2;
+
+ gtk_widget_style_get( gWidgetData[nScreen].gScrollHorizWidget,
+ "has-forward-stepper", &has_forward,
+ "has-secondary-forward-stepper", &has_forward2,
+ "has-backward-stepper", &has_backward,
+ "has-secondary-backward-stepper", &has_backward2, (char *)NULL );
+ gint buttonWidth;
+ gint buttonHeight;
+ Rectangle buttonRect;
+
+ gint nFirst = 0;
+ gint nSecond = 0;
+
+ if ( has_forward ) nSecond += 1;
+ if ( has_forward2 ) nFirst += 1;
+ if ( has_backward ) nFirst += 1;
+ if ( has_backward2 ) nSecond += 1;
+
+ if ( ( nPart == PART_BUTTON_UP ) || ( nPart == PART_BUTTON_DOWN ) )
+ {
+ buttonWidth = slider_width + 2 * trough_border;
+ buttonHeight = stepper_size + trough_border + stepper_spacing;
+ }
+ else
+ {
+ buttonWidth = stepper_size + trough_border + stepper_spacing;
+ buttonHeight = slider_width + 2 * trough_border;
+ }
+
+ if ( nPart == PART_BUTTON_UP )
+ {
+ buttonHeight *= nFirst;
+ buttonHeight -= 1;
+ buttonRect.setX( aAreaRect.Left() );
+ buttonRect.setY( aAreaRect.Top() );
+ }
+ else if ( nPart == PART_BUTTON_LEFT )
+ {
+ buttonWidth *= nFirst;
+ buttonWidth -= 1;
+ buttonRect.setX( aAreaRect.Left() );
+ buttonRect.setY( aAreaRect.Top() );
+ }
+ else if ( nPart == PART_BUTTON_DOWN )
+ {
+ buttonHeight *= nSecond;
+ buttonRect.setX( aAreaRect.Left() );
+ buttonRect.setY( aAreaRect.Top() + aAreaRect.GetHeight() - buttonHeight );
+ }
+ else if ( nPart == PART_BUTTON_RIGHT )
+ {
+ buttonWidth *= nSecond;
+ buttonRect.setX( aAreaRect.Left() + aAreaRect.GetWidth() - buttonWidth );
+ buttonRect.setY( aAreaRect.Top() );
+ }
+
+ buttonRect.SetSize( Size( buttonWidth, buttonHeight ) );
+
+ return( buttonRect );
+}
+
+//-------------------------------------
+
+BOOL GtkSalGraphics::NWPaintGTKEditBox( GdkDrawable* gdkDrawable,
+ ControlType nType, ControlPart nPart,
+ const Rectangle& rControlRectangle,
+ const clipList& rClipList,
+ ControlState nState,
+ const ImplControlValue& aValue,
+ const OUString& rCaption )
+{
+ Rectangle pixmapRect;
+ GdkRectangle clipRect;
+
+ // Find the overall bounding rect of the buttons's drawing area,
+ // plus its actual draw rect excluding adornment
+ pixmapRect = NWGetEditBoxPixmapRect( m_nScreen, nType, nPart, rControlRectangle,
+ nState, aValue, rCaption );
+ for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it )
+ {
+ clipRect.x = it->Left();
+ clipRect.y = it->Top();
+ clipRect.width = it->GetWidth();
+ clipRect.height = it->GetHeight();
+
+ NWPaintOneEditBox( m_nScreen, gdkDrawable, &clipRect, nType, nPart, pixmapRect, nState, aValue, rCaption );
+ }
+
+ return( TRUE );
+}
+
+
+/* Take interior/exterior focus into account and return
+ * the bounding rectangle of the edit box including
+ * any focus requirements.
+ */
+static Rectangle NWGetEditBoxPixmapRect(int nScreen,
+ ControlType,
+ ControlPart,
+ Rectangle aAreaRect,
+ ControlState,
+ const ImplControlValue&,
+ const OUString& )
+{
+ Rectangle pixmapRect = aAreaRect;
+ gboolean interiorFocus;
+ gint focusWidth;
+
+ NWEnsureGTKEditBox( nScreen );
+
+ // Grab some entry style attributes
+ gtk_widget_style_get( gWidgetData[nScreen].gEditBoxWidget,
+ "focus-line-width", &focusWidth,
+ "interior-focus", &interiorFocus, (char *)NULL );
+
+ if ( !interiorFocus )
+ {
+ pixmapRect.Move( -(focusWidth), -(focusWidth) );
+ pixmapRect.SetSize( Size( pixmapRect.GetWidth() + (2*(focusWidth)),
+ pixmapRect.GetHeight() + (2*(focusWidth)) ) );
+ }
+
+ return( pixmapRect );
+}
+
+
+/* Paint a GTK Entry widget into the specified GdkPixmap.
+ * All coordinates should be local to the Pixmap, NOT
+ * screen/window coordinates.
+ */
+static void NWPaintOneEditBox( int nScreen,
+ GdkDrawable * gdkDrawable,
+ GdkRectangle * gdkRect,
+ ControlType nType,
+ ControlPart,
+ Rectangle aEditBoxRect,
+ ControlState nState,
+ const ImplControlValue&,
+ const OUString& )
+{
+ GtkStateType stateType;
+ GtkShadowType shadowType;
+ GtkWidget *widget;
+
+ NWEnsureGTKButton( nScreen );
+ NWEnsureGTKEditBox( nScreen );
+ NWEnsureGTKSpinButton( nScreen );
+ NWEnsureGTKCombo( nScreen );
+ NWEnsureGTKScrolledWindow( nScreen );
+ NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
+
+ /* border's shadowType for gtk entries is always GTK_SHADOW_IN (see gtkentry.c)
+ shadowType = GTK_SHADOW_IN;
+ */
+
+ switch ( nType )
+ {
+ case CTRL_SPINBOX:
+ widget = gWidgetData[nScreen].gSpinButtonWidget;
+ break;
+
+ case CTRL_MULTILINE_EDITBOX:
+ widget = gWidgetData[nScreen].gScrolledWindowWidget;
+ break;
+ case CTRL_COMBOBOX:
+ widget = GTK_COMBO(gWidgetData[nScreen].gComboWidget)->entry;
+ break;
+
+ default:
+ widget = gWidgetData[nScreen].gEditBoxWidget;
+ break;
+ }
+
+ if ( stateType == GTK_STATE_PRELIGHT )
+ stateType = GTK_STATE_NORMAL;
+
+ // Blueprint needs to paint entry_bg with a Button widget, not an Entry widget to get
+ // a nice white (or whatever default color) background
+ GtkWidget* pBGWidget = widget;
+ if( GtkSalGraphics::bNeedButtonStyleAsEditBackgroundWorkaround )
+ {
+ NWSetWidgetState( gWidgetData[nScreen].gBtnWidget, nState, stateType );
+ pBGWidget = gWidgetData[nScreen].gBtnWidget;
+ }
+ NWSetWidgetState( widget, nState, stateType );
+
+ gtk_paint_flat_box( pBGWidget->style, gdkDrawable, stateType, GTK_SHADOW_NONE,
+ gdkRect, pBGWidget, "entry_bg",
+ aEditBoxRect.Left(), aEditBoxRect.Top(),
+ aEditBoxRect.GetWidth(), aEditBoxRect.GetHeight() );
+ gtk_paint_shadow( widget->style, gdkDrawable, GTK_STATE_NORMAL, GTK_SHADOW_IN,
+ gdkRect, widget, "entry",
+ aEditBoxRect.Left(), aEditBoxRect.Top(),
+ aEditBoxRect.GetWidth(), aEditBoxRect.GetHeight() );
+
+}
+
+
+
+//-------------------------------------
+
+BOOL GtkSalGraphics::NWPaintGTKSpinBox( ControlType nType, ControlPart nPart,
+ const Rectangle& rControlRectangle,
+ const clipList&,
+ ControlState nState,
+ const ImplControlValue& aValue,
+ const OUString& rCaption )
+{
+ GdkPixmap * pixmap;
+ Rectangle pixmapRect;
+ GtkStateType stateType;
+ GtkShadowType shadowType;
+ const SpinbuttonValue * pSpinVal = (aValue.getType() == CTRL_SPINBUTTONS) ? static_cast<const SpinbuttonValue *>(&aValue) : NULL;
+ Rectangle upBtnRect;
+ ControlPart upBtnPart = PART_BUTTON_UP;
+ ControlState upBtnState = CTRL_STATE_ENABLED;
+ Rectangle downBtnRect;
+ ControlPart downBtnPart = PART_BUTTON_DOWN;
+ ControlState downBtnState = CTRL_STATE_ENABLED;
+
+ NWEnsureGTKButton( m_nScreen );
+ NWEnsureGTKSpinButton( m_nScreen );
+ NWEnsureGTKArrow( m_nScreen );
+
+ NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
+
+ if ( pSpinVal )
+ {
+ upBtnPart = pSpinVal->mnUpperPart;
+ upBtnState = pSpinVal->mnUpperState;
+
+ downBtnPart = pSpinVal->mnLowerPart;
+ downBtnState = pSpinVal->mnLowerState;
+ }
+
+ // CTRL_SPINBUTTONS pass their area in pSpinVal, not in rControlRectangle
+ if ( nType == CTRL_SPINBUTTONS )
+ {
+ if ( !pSpinVal )
+ {
+ std::fprintf( stderr, "Tried to draw CTRL_SPINBUTTONS, but the SpinButtons data structure didn't exist!\n" );
+ return( false );
+ }
+ pixmapRect = pSpinVal->maUpperRect;
+ pixmapRect.Union( pSpinVal->maLowerRect );
+ }
+ else
+ pixmapRect = rControlRectangle;
+
+
+ pixmap = NWGetPixmapFromScreen( pixmapRect );
+ if ( !pixmap )
+ return( FALSE );
+
+ upBtnRect = NWGetSpinButtonRect( m_nScreen, nType, upBtnPart, pixmapRect, upBtnState, aValue, rCaption );
+ downBtnRect = NWGetSpinButtonRect( m_nScreen, nType, downBtnPart, pixmapRect, downBtnState, aValue, rCaption );
+
+ if ( (nType==CTRL_SPINBOX) && (nPart!=PART_ALL_BUTTONS) )
+ {
+ // Draw an edit field for SpinBoxes and ComboBoxes
+ Rectangle aEditBoxRect( pixmapRect );
+ aEditBoxRect.SetSize( Size( upBtnRect.Left() - pixmapRect.Left(), aEditBoxRect.GetHeight() ) );
+ aEditBoxRect.setX( 0 );
+ aEditBoxRect.setY( 0 );
+
+ NWPaintOneEditBox( m_nScreen, pixmap, NULL, nType, nPart, aEditBoxRect, nState, aValue, rCaption );
+ }
+
+ NWSetWidgetState( gWidgetData[m_nScreen].gSpinButtonWidget, nState, stateType );
+ gtk_widget_style_get( gWidgetData[m_nScreen].gSpinButtonWidget, "shadow_type", &shadowType, (char *)NULL );
+
+ if ( shadowType != GTK_SHADOW_NONE )
+ {
+ Rectangle shadowRect( upBtnRect );
+
+ shadowRect.Union( downBtnRect );
+ gtk_paint_box( gWidgetData[m_nScreen].gSpinButtonWidget->style, pixmap, GTK_STATE_NORMAL, shadowType, NULL,
+ gWidgetData[m_nScreen].gSpinButtonWidget, "spinbutton",
+ (shadowRect.Left() - pixmapRect.Left()), (shadowRect.Top() - pixmapRect.Top()),
+ shadowRect.GetWidth(), shadowRect.GetHeight() );
+ }
+
+ NWPaintOneSpinButton( m_nScreen, pixmap, nType, upBtnPart, pixmapRect, upBtnState, aValue, rCaption );
+ NWPaintOneSpinButton( m_nScreen, pixmap, nType, downBtnPart, pixmapRect, downBtnState, aValue, rCaption );
+
+ if( !NWRenderPixmapToScreen(pixmap, pixmapRect) )
+ {
+ g_object_unref( pixmap );
+ return( FALSE );
+ }
+
+ g_object_unref( pixmap );
+ return( TRUE );
+}
+
+//---
+
+static Rectangle NWGetSpinButtonRect( int nScreen,
+ ControlType,
+ ControlPart nPart,
+ Rectangle aAreaRect,
+ ControlState,
+ const ImplControlValue&,
+ const OUString& )
+{
+ gint buttonSize;
+ Rectangle buttonRect;
+
+ NWEnsureGTKSpinButton( nScreen );
+
+ buttonSize = MAX( PANGO_PIXELS( pango_font_description_get_size(GTK_WIDGET(gWidgetData[nScreen].gSpinButtonWidget)->style->font_desc) ),
+ MIN_SPIN_ARROW_WIDTH );
+ buttonSize -= buttonSize % 2 - 1; /* force odd */
+ buttonRect.SetSize( Size( buttonSize + 2 * gWidgetData[nScreen].gSpinButtonWidget->style->xthickness,
+ buttonRect.GetHeight() ) );
+ buttonRect.setX( aAreaRect.Left() + (aAreaRect.GetWidth() - buttonRect.GetWidth()) );
+ if ( nPart == PART_BUTTON_UP )
+ {
+ buttonRect.setY( aAreaRect.Top() );
+ buttonRect.Bottom() = buttonRect.Top() + (aAreaRect.GetHeight() / 2);
+ }
+ else if( nPart == PART_BUTTON_DOWN )
+ {
+ buttonRect.setY( aAreaRect.Top() + (aAreaRect.GetHeight() / 2) );
+ buttonRect.Bottom() = aAreaRect.Bottom(); // cover area completely
+ }
+ else
+ {
+ buttonRect.Right() = buttonRect.Left()-1;
+ buttonRect.Left() = aAreaRect.Left();
+ buttonRect.Top() = aAreaRect.Top();
+ buttonRect.Bottom() = aAreaRect.Bottom();
+ }
+
+ return( buttonRect );
+}
+
+//---
+
+static void NWPaintOneSpinButton( int nScreen,
+ GdkPixmap* pixmap,
+ ControlType nType,
+ ControlPart nPart,
+ Rectangle aAreaRect,
+ ControlState nState,
+ const ImplControlValue& aValue,
+ const OUString& rCaption )
+{
+ Rectangle buttonRect;
+ GtkStateType stateType;
+ GtkShadowType shadowType;
+ Rectangle arrowRect;
+ gint arrowSize;
+
+ NWEnsureGTKSpinButton( nScreen );
+ NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
+
+ buttonRect = NWGetSpinButtonRect( nScreen, nType, nPart, aAreaRect, nState, aValue, rCaption );
+
+ NWSetWidgetState( gWidgetData[nScreen].gSpinButtonWidget, nState, stateType );
+ gtk_paint_box( gWidgetData[nScreen].gSpinButtonWidget->style, pixmap, stateType, shadowType, NULL, gWidgetData[nScreen].gSpinButtonWidget,
+ (nPart == PART_BUTTON_UP) ? "spinbutton_up" : "spinbutton_down",
+ (buttonRect.Left() - aAreaRect.Left()), (buttonRect.Top() - aAreaRect.Top()),
+ buttonRect.GetWidth(), buttonRect.GetHeight() );
+
+ arrowSize = (buttonRect.GetWidth() - (2 * gWidgetData[nScreen].gSpinButtonWidget->style->xthickness)) - 4;
+ arrowSize -= arrowSize % 2 - 1; /* force odd */
+ arrowRect.SetSize( Size( arrowSize, arrowSize ) );
+ arrowRect.setX( buttonRect.Left() + (buttonRect.GetWidth() - arrowRect.GetWidth()) / 2 );
+ if ( nPart == PART_BUTTON_UP )
+ arrowRect.setY( buttonRect.Top() + (buttonRect.GetHeight() - arrowRect.GetHeight()) / 2 + 1);
+ else
+ arrowRect.setY( buttonRect.Top() + (buttonRect.GetHeight() - arrowRect.GetHeight()) / 2 - 1);
+
+ gtk_paint_arrow( gWidgetData[nScreen].gSpinButtonWidget->style, pixmap, stateType, GTK_SHADOW_OUT, NULL, gWidgetData[nScreen].gSpinButtonWidget,
+ "spinbutton", (nPart == PART_BUTTON_UP) ? GTK_ARROW_UP : GTK_ARROW_DOWN, TRUE,
+ (arrowRect.Left() - aAreaRect.Left()), (arrowRect.Top() - aAreaRect.Top()),
+ arrowRect.GetWidth(), arrowRect.GetHeight() );
+}
+
+
+//-------------------------------------
+
+BOOL GtkSalGraphics::NWPaintGTKComboBox( GdkDrawable* gdkDrawable,
+ ControlType nType, ControlPart nPart,
+ const Rectangle& rControlRectangle,
+ const clipList& rClipList,
+ ControlState nState,
+ const ImplControlValue& aValue,
+ const OUString& rCaption )
+{
+ Rectangle pixmapRect;
+ Rectangle buttonRect;
+ GtkStateType stateType;
+ GtkShadowType shadowType;
+ Rectangle arrowRect;
+ gint x,y;
+ GdkRectangle clipRect;
+
+ NWEnsureGTKButton( m_nScreen );
+ NWEnsureGTKArrow( m_nScreen );
+ NWEnsureGTKCombo( m_nScreen );
+ NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
+
+ // Find the overall bounding rect of the buttons's drawing area,
+ // plus its actual draw rect excluding adornment
+ pixmapRect = rControlRectangle;
+ x = rControlRectangle.Left();
+ y = rControlRectangle.Top();
+
+ NWSetWidgetState( gWidgetData[m_nScreen].gBtnWidget, nState, stateType );
+ NWSetWidgetState( gWidgetData[m_nScreen].gComboWidget, nState, stateType );
+ NWSetWidgetState( gWidgetData[m_nScreen].gArrowWidget, nState, stateType );
+
+ buttonRect = NWGetComboBoxButtonRect( m_nScreen, nType, PART_BUTTON_DOWN, pixmapRect, nState, aValue, rCaption );
+ if( nPart == PART_BUTTON_DOWN )
+ buttonRect.Left() += 1;
+
+ Rectangle aEditBoxRect( pixmapRect );
+ aEditBoxRect.SetSize( Size( pixmapRect.GetWidth() - buttonRect.GetWidth(), aEditBoxRect.GetHeight() ) );
+
+ #define ARROW_EXTENT 0.7
+ arrowRect.SetSize( Size( (gint)(MIN_ARROW_SIZE * ARROW_EXTENT),
+ (gint)(MIN_ARROW_SIZE * ARROW_EXTENT) ) );
+ arrowRect.SetPos( Point( buttonRect.Left() + (gint)((buttonRect.GetWidth() - arrowRect.GetWidth()) / 2),
+ buttonRect.Top() + (gint)((buttonRect.GetHeight() - arrowRect.GetHeight()) / 2) ) );
+
+ for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it )
+ {
+ clipRect.x = it->Left();
+ clipRect.y = it->Top();
+ clipRect.width = it->GetWidth();
+ clipRect.height = it->GetHeight();
+
+ if( nPart == PART_ENTIRE_CONTROL )
+ NWPaintOneEditBox( m_nScreen, gdkDrawable, &clipRect, nType, nPart, aEditBoxRect,
+ nState, aValue, rCaption );
+
+ // Buttons must paint opaque since some themes have alpha-channel enabled buttons
+ gtk_paint_flat_box( gWidgetData[m_nScreen].gBtnWidget->style, gdkDrawable, GTK_STATE_NORMAL, GTK_SHADOW_NONE,
+ &clipRect, m_pWindow, "base",
+ x+(buttonRect.Left() - pixmapRect.Left()),
+ y+(buttonRect.Top() - pixmapRect.Top()),
+ buttonRect.GetWidth(), buttonRect.GetHeight() );
+ gtk_paint_box( GTK_COMBO(gWidgetData[m_nScreen].gComboWidget)->button->style, gdkDrawable, stateType, shadowType,
+ &clipRect, GTK_COMBO(gWidgetData[m_nScreen].gComboWidget)->button, "button",
+ x+(buttonRect.Left() - pixmapRect.Left()),
+ y+(buttonRect.Top() - pixmapRect.Top()),
+ buttonRect.GetWidth(), buttonRect.GetHeight() );
+
+ gtk_paint_arrow( gWidgetData[m_nScreen].gArrowWidget->style, gdkDrawable, stateType, shadowType,
+ &clipRect, gWidgetData[m_nScreen].gArrowWidget, "arrow", GTK_ARROW_DOWN, TRUE,
+ x+(arrowRect.Left() - pixmapRect.Left()), y+(arrowRect.Top() - pixmapRect.Top()),
+ arrowRect.GetWidth(), arrowRect.GetHeight() );
+ }
+
+ return( TRUE );
+}
+
+//----
+
+static Rectangle NWGetComboBoxButtonRect( int nScreen,
+ ControlType,
+ ControlPart nPart,
+ Rectangle aAreaRect,
+ ControlState,
+ const ImplControlValue&,
+ const OUString& )
+{
+ Rectangle aButtonRect;
+ gint nArrowWidth;
+ gint nButtonWidth;
+ gint nFocusWidth;
+ gint nFocusPad;
+
+ NWEnsureGTKArrow( nScreen );
+
+ // Grab some button style attributes
+ gtk_widget_style_get( gWidgetData[nScreen].gDropdownWidget,
+ "focus-line-width", &nFocusWidth,
+ "focus-padding", &nFocusPad, (char *)NULL );
+
+ nArrowWidth = MIN_ARROW_SIZE + (GTK_MISC(gWidgetData[nScreen].gArrowWidget)->xpad * 2);
+ nButtonWidth = nArrowWidth +
+ ((BTN_CHILD_SPACING + gWidgetData[nScreen].gDropdownWidget->style->xthickness) * 2)
+ + (2 * (nFocusWidth+nFocusPad));
+ if( nPart == PART_BUTTON_DOWN )
+ {
+ aButtonRect.SetSize( Size( nButtonWidth, aAreaRect.GetHeight() ) );
+ aButtonRect.SetPos( Point( aAreaRect.Left() + aAreaRect.GetWidth() - nButtonWidth,
+ aAreaRect.Top() ) );
+ }
+ else if( nPart == PART_SUB_EDIT )
+ {
+ NWEnsureGTKCombo( nScreen );
+
+ gint adjust_x = GTK_CONTAINER(gWidgetData[nScreen].gComboWidget)->border_width +
+ nFocusWidth +
+ nFocusPad;
+ gint adjust_y = adjust_x + gWidgetData[nScreen].gComboWidget->style->ythickness;
+ adjust_x += gWidgetData[nScreen].gComboWidget->style->xthickness;
+ aButtonRect.SetSize( Size( aAreaRect.GetWidth() - nButtonWidth - 2 * adjust_x,
+ aAreaRect.GetHeight() - 2 * adjust_y ) );
+ Point aEditPos = aAreaRect.TopLeft();
+ aEditPos.X() += adjust_x;
+ aEditPos.Y() += adjust_y;
+ aButtonRect.SetPos( aEditPos );
+ }
+
+ return( aButtonRect );
+}
+
+//-------------------------------------
+
+
+
+BOOL GtkSalGraphics::NWPaintGTKTabItem( ControlType nType, ControlPart,
+ const Rectangle& rControlRectangle,
+ const clipList&,
+ ControlState nState,
+ const ImplControlValue& aValue,
+ const OUString& )
+{
+ OSL_ASSERT( nType != CTRL_TAB_ITEM || aValue.getType() == CTRL_TAB_ITEM );
+ GdkPixmap * pixmap;
+ Rectangle pixmapRect;
+ Rectangle tabRect;
+ GtkStateType stateType;
+ GtkShadowType shadowType;
+ if( ! gWidgetData[ m_nScreen ].gCacheTabItems )
+ {
+ gWidgetData[ m_nScreen ].gCacheTabItems = new NWPixmapCache( m_nScreen );
+ gWidgetData[ m_nScreen ].gCacheTabPages = new NWPixmapCache( m_nScreen );
+ }
+ NWPixmapCache& aCacheItems = *gWidgetData[ m_nScreen ].gCacheTabItems;
+ NWPixmapCache& aCachePage = *gWidgetData[ m_nScreen ].gCacheTabPages;
+
+ if( !aCacheItems.GetSize() )
+ aCacheItems.SetSize( 20 );
+ if( !aCachePage.GetSize() )
+ aCachePage.SetSize( 1 );
+
+ if ( (nType == CTRL_TAB_ITEM) && (aValue.getType() != CTRL_TAB_ITEM) )
+ {
+ return( false );
+ }
+
+ NWEnsureGTKButton( m_nScreen );
+ NWEnsureGTKNotebook( m_nScreen );
+ NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
+
+ // Find the overall bounding rect of the buttons's drawing area,
+ // plus its actual draw rect excluding adornment
+ pixmapRect = rControlRectangle;
+ if ( nType == CTRL_TAB_ITEM )
+ {
+ const TabitemValue * pTabitemValue = static_cast<const TabitemValue *>(&aValue);
+ if ( !pTabitemValue->isFirst() )
+ {
+ // GTK+ tabs overlap on the right edge (the top tab obscures the
+ // left edge of the tab right "below" it, so adjust the rectangle
+ // to draw tabs slightly large so the overlap happens
+ pixmapRect.Move( -2, 0 );
+ pixmapRect.SetSize( Size( pixmapRect.GetWidth() + 2, pixmapRect.GetHeight() ) );
+ }
+ if ( nState & CTRL_STATE_SELECTED )
+ {
+ // In GTK+, the selected tab is 2px taller than all other tabs
+ pixmapRect.Move( 0, -2 );
+ pixmapRect.Bottom() += 2;
+ tabRect = pixmapRect;
+ // Only draw over 1 pixel of the tab pane that this tab is drawn on top of.
+ tabRect.Bottom() -= 1;
+ }
+ else
+ tabRect = pixmapRect;
+
+ // Allow the tab to draw a right border if needed
+ tabRect.Right() -= 1;
+
+ // #129732# avoid degenerate cases which might lead to crashes
+ if( tabRect.GetWidth() <= 1 || tabRect.GetHeight() <= 1 )
+ return false;
+ }
+
+ if( nType == CTRL_TAB_ITEM )
+ {
+ if( aCacheItems.Find( nType, nState, pixmapRect, &pixmap ) )
+ return NWRenderPixmapToScreen( pixmap, pixmapRect );
+ }
+ else
+ {
+ if( aCachePage.Find( nType, nState, pixmapRect, &pixmap ) )
+ return NWRenderPixmapToScreen( pixmap, pixmapRect );
+ }
+
+
+// gtk_widget_set_state( gWidgetData[m_nScreen].gNotebookWidget, stateType );
+
+ pixmap = gdk_pixmap_new( NULL, pixmapRect.GetWidth(), pixmapRect.GetHeight(),
+ GetX11SalData()->GetDisplay()->GetVisual( m_nScreen ).GetDepth() );
+ GdkRectangle paintRect;
+ paintRect.x = paintRect.y = 0;
+ paintRect.width = pixmapRect.GetWidth();
+ paintRect.height = pixmapRect.GetHeight();
+
+ gtk_paint_flat_box( m_pWindow->style, pixmap, GTK_STATE_NORMAL,
+ GTK_SHADOW_NONE, &paintRect, m_pWindow, "base", 0, 0, -1, -1);
+
+ NWSetWidgetState( gWidgetData[m_nScreen].gNotebookWidget, nState, stateType );
+
+ switch( nType )
+ {
+ case CTRL_TAB_BODY:
+ break;
+
+ case CTRL_FIXEDBORDER:
+ case CTRL_TAB_PANE:
+ gtk_paint_box_gap( gWidgetData[m_nScreen].gNotebookWidget->style, pixmap, GTK_STATE_NORMAL, GTK_SHADOW_OUT, NULL, gWidgetData[m_nScreen].gNotebookWidget,
+ (char *)"notebook", 0, 0, pixmapRect.GetWidth(), pixmapRect.GetHeight(), GTK_POS_TOP, 0, 0 );
+ break;
+
+ case CTRL_TAB_ITEM:
+ stateType = ( nState & CTRL_STATE_SELECTED ) ? GTK_STATE_NORMAL : GTK_STATE_ACTIVE;
+
+ gtk_paint_extension( gWidgetData[m_nScreen].gNotebookWidget->style, pixmap, stateType, GTK_SHADOW_OUT, NULL, gWidgetData[m_nScreen].gNotebookWidget,
+ (char *)"tab", (tabRect.Left() - pixmapRect.Left()), (tabRect.Top() - pixmapRect.Top()),
+ tabRect.GetWidth(), tabRect.GetHeight(), GTK_POS_BOTTOM );
+
+ if ( nState & CTRL_STATE_SELECTED )
+ {
+ gtk_paint_flat_box( gWidgetData[m_nScreen].gNotebookWidget->style, pixmap, stateType, GTK_SHADOW_NONE, NULL, m_pWindow,
+ (char *)"base", 0, (pixmapRect.GetHeight() - 1), pixmapRect.GetWidth(), 1 );
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ // Crux seems to think it can make the pane without a left edge
+ if ( nType == CTRL_FIXEDBORDER )
+ pixmapRect.Move( 1, 0 );
+
+ // cache data
+ if( nType == CTRL_TAB_ITEM )
+ aCacheItems.Fill( nType, nState, pixmapRect, pixmap );
+ else
+ aCachePage.Fill( nType, nState, pixmapRect, pixmap );
+
+ BOOL bSuccess = NWRenderPixmapToScreen(pixmap, pixmapRect);
+ g_object_unref( pixmap );
+ return bSuccess;
+}
+
+//-------------------------------------
+
+BOOL GtkSalGraphics::NWPaintGTKListBox( GdkDrawable* gdkDrawable,
+ ControlType nType, ControlPart nPart,
+ const Rectangle& rControlRectangle,
+ const clipList& rClipList,
+ ControlState nState,
+ const ImplControlValue& aValue,
+ const OUString& rCaption )
+{
+ Rectangle pixmapRect;
+ Rectangle widgetRect;
+ Rectangle aIndicatorRect;
+ GtkStateType stateType;
+ GtkShadowType shadowType;
+ gint bInteriorFocus;
+ gint nFocusLineWidth;
+ gint nFocusPadding;
+ gint x,y;
+ GdkRectangle clipRect;
+
+ NWEnsureGTKButton( m_nScreen );
+ NWEnsureGTKOptionMenu( m_nScreen );
+ NWEnsureGTKScrolledWindow( m_nScreen );
+ NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
+
+ // Find the overall bounding rect of the buttons's drawing area,
+ // plus its actual draw rect excluding adornment
+ pixmapRect = rControlRectangle;
+ if ( nPart == PART_WINDOW )
+ {
+ // Make the widget a _bit_ bigger
+ pixmapRect.SetPos( Point( pixmapRect.Left() - 1,
+ pixmapRect.Top() - 1 ) );
+ pixmapRect.SetSize( Size( pixmapRect.GetWidth() + 2,
+ pixmapRect.GetHeight() + 2 ) );
+ }
+
+ widgetRect = pixmapRect;
+ x = pixmapRect.Left();
+ y = pixmapRect.Top();
+
+ // set up references to correct drawable and cliprect
+ NWSetWidgetState( gWidgetData[m_nScreen].gBtnWidget, nState, stateType );
+ NWSetWidgetState( gWidgetData[m_nScreen].gOptionMenuWidget, nState, stateType );
+ NWSetWidgetState( gWidgetData[m_nScreen].gScrolledWindowWidget, nState, stateType );
+
+ if ( nPart != PART_WINDOW )
+ {
+ gtk_widget_style_get( gWidgetData[m_nScreen].gOptionMenuWidget,
+ "interior_focus", &bInteriorFocus,
+ "focus_line_width", &nFocusLineWidth,
+ "focus_padding", &nFocusPadding,
+ (char *)NULL);
+ }
+
+ for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it )
+ {
+ clipRect.x = it->Left();
+ clipRect.y = it->Top();
+ clipRect.width = it->GetWidth();
+ clipRect.height = it->GetHeight();
+
+ if ( nPart != PART_WINDOW )
+ {
+ // Listboxes must paint opaque since some themes have alpha-channel enabled bodies
+ gtk_paint_flat_box( gWidgetData[m_nScreen].gBtnWidget->style, gdkDrawable, GTK_STATE_NORMAL, GTK_SHADOW_NONE,
+ &clipRect, m_pWindow, "base", x, y,
+ pixmapRect.GetWidth(), pixmapRect.GetHeight() );
+ gtk_paint_box( gWidgetData[m_nScreen].gOptionMenuWidget->style, gdkDrawable, stateType, shadowType, &clipRect,
+ gWidgetData[m_nScreen].gOptionMenuWidget, "optionmenu",
+ x+(widgetRect.Left() - pixmapRect.Left()),
+ y+(widgetRect.Top() - pixmapRect.Top()),
+ widgetRect.GetWidth(), widgetRect.GetHeight() );
+ aIndicatorRect = NWGetListBoxIndicatorRect( m_nScreen, nType, nPart, widgetRect, nState,
+ aValue, rCaption );
+ gtk_paint_tab( gWidgetData[m_nScreen].gOptionMenuWidget->style, gdkDrawable, stateType, shadowType, &clipRect,
+ gWidgetData[m_nScreen].gOptionMenuWidget, "optionmenutab",
+ x+(aIndicatorRect.Left() - pixmapRect.Left()),
+ y+(aIndicatorRect.Top() - pixmapRect.Top()),
+ aIndicatorRect.GetWidth(), aIndicatorRect.GetHeight() );
+ }
+ else
+ {
+ shadowType = GTK_SHADOW_IN;
+
+ gtk_paint_shadow( gWidgetData[m_nScreen].gScrolledWindowWidget->style, gdkDrawable, GTK_STATE_NORMAL, shadowType,
+ &clipRect, gWidgetData[m_nScreen].gScrolledWindowWidget, "scrolled_window",
+ x+(widgetRect.Left() - pixmapRect.Left()), y+(widgetRect.Top() - pixmapRect.Top()),
+ widgetRect.GetWidth(), widgetRect.GetHeight() );
+ }
+ }
+
+ return( TRUE );
+}
+
+BOOL GtkSalGraphics::NWPaintGTKToolbar(
+ GdkDrawable* gdkDrawable,
+ ControlType, ControlPart nPart,
+ const Rectangle& rControlRectangle,
+ const clipList& rClipList,
+ ControlState nState, const ImplControlValue& aValue,
+ const OUString& )
+{
+ GtkStateType stateType;
+ GtkShadowType shadowType;
+ gint x, y, w, h;
+ gint g_x=0, g_y=0, g_w=10, g_h=10;
+ bool bPaintButton = true;
+ GtkWidget* pButtonWidget = gWidgetData[m_nScreen].gToolbarButtonWidget;
+ GdkRectangle clipRect;
+
+ NWEnsureGTKToolbar( m_nScreen );
+ if( nPart == PART_BUTTON ) // toolbar buttons cannot focus in gtk
+ nState &= ~CTRL_STATE_FOCUSED;
+ NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
+
+ x = rControlRectangle.Left();
+ y = rControlRectangle.Top();
+ w = rControlRectangle.GetWidth();
+ h = rControlRectangle.GetHeight();
+
+ // handle toolbar
+ if( nPart == PART_DRAW_BACKGROUND_HORZ || nPart == PART_DRAW_BACKGROUND_VERT )
+ {
+ NWSetWidgetState( gWidgetData[m_nScreen].gToolbarWidget, nState, stateType );
+
+ GTK_WIDGET_UNSET_FLAGS( gWidgetData[m_nScreen].gToolbarWidget, GTK_SENSITIVE );
+ if ( nState & CTRL_STATE_ENABLED )
+ GTK_WIDGET_SET_FLAGS( gWidgetData[m_nScreen].gToolbarWidget, GTK_SENSITIVE );
+
+ if( nPart == PART_DRAW_BACKGROUND_HORZ )
+ gtk_toolbar_set_orientation( GTK_TOOLBAR(gWidgetData[m_nScreen].gToolbarWidget), GTK_ORIENTATION_HORIZONTAL );
+ else
+ gtk_toolbar_set_orientation( GTK_TOOLBAR(gWidgetData[m_nScreen].gToolbarWidget), GTK_ORIENTATION_VERTICAL );
+ }
+ // handle grip
+ else if( nPart == PART_THUMB_HORZ || nPart == PART_THUMB_VERT )
+ {
+ NWSetWidgetState( gWidgetData[m_nScreen].gHandleBoxWidget, nState, stateType );
+
+ GTK_WIDGET_UNSET_FLAGS( gWidgetData[m_nScreen].gHandleBoxWidget, GTK_SENSITIVE );
+ if ( nState & CTRL_STATE_ENABLED )
+ GTK_WIDGET_SET_FLAGS( gWidgetData[m_nScreen].gHandleBoxWidget, GTK_SENSITIVE );
+
+ gtk_handle_box_set_shadow_type( GTK_HANDLE_BOX(gWidgetData[m_nScreen].gHandleBoxWidget), shadowType );
+
+ // evaluate grip rect
+ if( aValue.getType() == CTRL_TOOLBAR )
+ {
+ const ToolbarValue* pVal = static_cast<const ToolbarValue*>(&aValue);
+ g_x = pVal->maGripRect.Left();
+ g_y = pVal->maGripRect.Top();
+ g_w = pVal->maGripRect.GetWidth();
+ g_h = pVal->maGripRect.GetHeight();
+ }
+ }
+ // handle button
+ else if( nPart == PART_BUTTON )
+ {
+ bPaintButton =
+ (GTK_BUTTON(pButtonWidget)->relief != GTK_RELIEF_NONE)
+ || (nState & CTRL_STATE_PRESSED)
+ || (nState & CTRL_STATE_ROLLOVER);
+ if( aValue.getTristateVal() == BUTTONVALUE_ON )
+ {
+ pButtonWidget = gWidgetData[m_nScreen].gToolbarToggleWidget;
+ shadowType = GTK_SHADOW_IN;
+ stateType = GTK_STATE_ACTIVE;
+ // special case stateType value for depressed toggle buttons
+ // cf. gtk+/gtk/gtktogglebutton.c (gtk_toggle_button_update_state)
+ if( (nState & (CTRL_STATE_ROLLOVER|CTRL_STATE_PRESSED)) )
+ {
+ stateType = GTK_STATE_PRELIGHT;
+ shadowType = GTK_SHADOW_OUT;
+ }
+ bPaintButton = true;
+ }
+ else
+ stateType = GTK_STATE_PRELIGHT; // only for bPaintButton = true, in which case always rollver is meant
+
+ NWSetWidgetState( pButtonWidget, nState, stateType );
+ gtk_widget_ensure_style( pButtonWidget );
+ }
+
+ for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it )
+ {
+ clipRect.x = it->Left();
+ clipRect.y = it->Top();
+ clipRect.width = it->GetWidth();
+ clipRect.height = it->GetHeight();
+
+ // draw toolbar
+ if( nPart == PART_DRAW_BACKGROUND_HORZ || nPart == PART_DRAW_BACKGROUND_VERT )
+ {
+ gtk_paint_flat_box( gWidgetData[m_nScreen].gToolbarWidget->style,
+ gdkDrawable,
+ (GtkStateType)GTK_STATE_NORMAL,
+ GTK_SHADOW_NONE,
+ &clipRect,
+ gWidgetData[m_nScreen].gToolbarWidget,
+ "base",
+ x, y, w, h );
+ gtk_paint_box( gWidgetData[m_nScreen].gToolbarWidget->style,
+ gdkDrawable,
+ stateType,
+ shadowType,
+ &clipRect,
+ gWidgetData[m_nScreen].gToolbarWidget,
+ "toolbar",
+ x, y, w, h );
+ }
+ // draw grip
+ else if( nPart == PART_THUMB_HORZ || nPart == PART_THUMB_VERT )
+ {
+ gtk_paint_handle( gWidgetData[m_nScreen].gHandleBoxWidget->style,
+ gdkDrawable,
+ GTK_STATE_NORMAL,
+ GTK_SHADOW_OUT,
+ &clipRect,
+ gWidgetData[m_nScreen].gHandleBoxWidget,
+ "handlebox",
+ g_x, g_y, g_w, g_h,
+ nPart == PART_THUMB_HORZ ?
+ GTK_ORIENTATION_HORIZONTAL :
+ GTK_ORIENTATION_VERTICAL
+ );
+ }
+ // draw button
+ else if( nPart == PART_BUTTON )
+ {
+ if( bPaintButton )
+ {
+ gtk_paint_box( pButtonWidget->style, gdkDrawable,
+ stateType,
+ shadowType,
+ &clipRect,
+ pButtonWidget, "button", x, y, w, h );
+ }
+ }
+ }
+
+ return( TRUE );
+}
+
+//----
+
+BOOL GtkSalGraphics::NWPaintGTKMenubar(
+ GdkDrawable* gdkDrawable,
+ ControlType, ControlPart nPart,
+ const Rectangle& rControlRectangle,
+ const clipList& rClipList,
+ ControlState nState, const ImplControlValue&,
+ const OUString& )
+{
+ GtkStateType stateType;
+ GtkShadowType shadowType;
+ GtkShadowType selected_shadow_type = GTK_SHADOW_OUT;
+ gint x, y, w, h;
+ GdkRectangle clipRect;
+
+ NWEnsureGTKMenubar( m_nScreen );
+ NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
+
+ x = rControlRectangle.Left();
+ y = rControlRectangle.Top();
+ w = rControlRectangle.GetWidth();
+ h = rControlRectangle.GetHeight();
+
+ if( nPart == PART_MENU_ITEM )
+ {
+ if( nState & (CTRL_STATE_SELECTED|CTRL_STATE_ROLLOVER) )
+ {
+ gtk_widget_style_get( gWidgetData[m_nScreen].gMenuItemMenubarWidget,
+ "selected_shadow_type", &selected_shadow_type,
+ (char *)NULL);
+ }
+ }
+
+ for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it )
+ {
+ clipRect.x = it->Left();
+ clipRect.y = it->Top();
+ clipRect.width = it->GetWidth();
+ clipRect.height = it->GetHeight();
+
+ // handle Menubar
+ if( nPart == PART_ENTIRE_CONTROL )
+ {
+ NWSetWidgetState( gWidgetData[m_nScreen].gMenubarWidget, nState, stateType );
+
+ GTK_WIDGET_UNSET_FLAGS( gWidgetData[m_nScreen].gMenubarWidget, GTK_SENSITIVE );
+ if ( nState & CTRL_STATE_ENABLED )
+ GTK_WIDGET_SET_FLAGS( gWidgetData[m_nScreen].gMenubarWidget, GTK_SENSITIVE );
+
+ // #118704# for translucent menubar styles paint background first
+ gtk_paint_flat_box( gWidgetData[m_nScreen].gMenubarWidget->style,
+ gdkDrawable,
+ GTK_STATE_NORMAL,
+ GTK_SHADOW_NONE,
+ &clipRect,
+ GTK_WIDGET(m_pWindow),
+ "base",
+ x, y, w, h );
+ gtk_paint_box( gWidgetData[m_nScreen].gMenubarWidget->style,
+ gdkDrawable,
+ stateType,
+ shadowType,
+ &clipRect,
+ gWidgetData[m_nScreen].gMenubarWidget,
+ "menubar",
+ x, y, w, h );
+ }
+ else if( nPart == PART_MENU_ITEM )
+ {
+ if( nState & (CTRL_STATE_SELECTED|CTRL_STATE_ROLLOVER) )
+ {
+ gtk_paint_box( gWidgetData[m_nScreen].gMenuItemMenubarWidget->style,
+ gdkDrawable,
+ GTK_STATE_PRELIGHT,
+ selected_shadow_type,
+ &clipRect,
+ gWidgetData[m_nScreen].gMenuItemMenubarWidget,
+ "menuitem",
+ x, y, w, h);
+ }
+ }
+ }
+
+ return( TRUE );
+}
+
+BOOL GtkSalGraphics::NWPaintGTKPopupMenu(
+ GdkDrawable* gdkDrawable,
+ ControlType, ControlPart nPart,
+ const Rectangle& rControlRectangle,
+ const clipList& rClipList,
+ ControlState nState, const ImplControlValue&,
+ const OUString& )
+{
+ // #i50745# gtk does not draw disabled menu entries (and crux theme
+ // even crashes), draw them using vcl functionality.
+ if( nPart == PART_MENU_ITEM && ! (nState & CTRL_STATE_ENABLED) )
+ return FALSE;
+
+ GtkStateType stateType;
+ GtkShadowType shadowType;
+ GtkShadowType selected_shadow_type = GTK_SHADOW_OUT;
+ gint x, y, w, h;
+ GdkRectangle clipRect;
+
+ NWEnsureGTKMenu( m_nScreen );
+ NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
+
+ x = rControlRectangle.Left();
+ y = rControlRectangle.Top();
+ w = rControlRectangle.GetWidth();
+ h = rControlRectangle.GetHeight();
+
+ if( nPart == PART_MENU_ITEM &&
+ ( nState & (CTRL_STATE_SELECTED|CTRL_STATE_ROLLOVER) ) )
+ {
+ gtk_widget_style_get( gWidgetData[m_nScreen].gMenuItemMenuWidget,
+ "selected_shadow_type", &selected_shadow_type,
+ (char *)NULL);
+ }
+
+ NWSetWidgetState( gWidgetData[m_nScreen].gMenuWidget, nState, stateType );
+
+ GTK_WIDGET_UNSET_FLAGS( gWidgetData[m_nScreen].gMenuWidget, GTK_SENSITIVE );
+ if ( nState & CTRL_STATE_ENABLED )
+ GTK_WIDGET_SET_FLAGS( gWidgetData[m_nScreen].gMenuWidget, GTK_SENSITIVE );
+
+ for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it )
+ {
+ clipRect.x = it->Left();
+ clipRect.y = it->Top();
+ clipRect.width = it->GetWidth();
+ clipRect.height = it->GetHeight();
+
+ if( nPart == PART_ENTIRE_CONTROL )
+ {
+ // #118704# for translucent menubar styles paint background first
+ gtk_paint_flat_box( gWidgetData[m_nScreen].gMenuWidget->style,
+ gdkDrawable,
+ GTK_STATE_NORMAL,
+ GTK_SHADOW_NONE,
+ &clipRect,
+ GTK_WIDGET(m_pWindow),
+ "base",
+ x, y, w, h );
+ gtk_paint_box( gWidgetData[m_nScreen].gMenuWidget->style,
+ gdkDrawable,
+ GTK_STATE_NORMAL,
+ GTK_SHADOW_OUT,
+ &clipRect,
+ gWidgetData[m_nScreen].gMenuWidget,
+ "menu",
+ x, y, w, h );
+ }
+ else if( nPart == PART_MENU_ITEM )
+ {
+ if( nState & (CTRL_STATE_SELECTED|CTRL_STATE_ROLLOVER) )
+ {
+ if( nState & CTRL_STATE_ENABLED )
+ gtk_paint_box( gWidgetData[m_nScreen].gMenuItemMenuWidget->style,
+ gdkDrawable,
+ GTK_STATE_PRELIGHT,
+ selected_shadow_type,
+ &clipRect,
+ gWidgetData[m_nScreen].gMenuItemMenuWidget,
+ "menuitem",
+ x, y, w, h);
+ }
+ }
+ else if( nPart == PART_MENU_ITEM_CHECK_MARK || nPart == PART_MENU_ITEM_RADIO_MARK )
+ {
+ GtkWidget* pWidget = (nPart == PART_MENU_ITEM_CHECK_MARK) ?
+ gWidgetData[m_nScreen].gMenuItemCheckMenuWidget :
+ gWidgetData[m_nScreen].gMenuItemRadioMenuWidget;
+
+ GtkStateType nStateType = GTK_STATE_NORMAL;
+ GtkShadowType nShadowType;
+
+ if ( nState & CTRL_STATE_SELECTED )
+ nStateType = GTK_STATE_PRELIGHT;
+
+ NWSetWidgetState( pWidget, nState, nStateType );
+
+ if ( nState & CTRL_STATE_PRESSED )
+ nShadowType = GTK_SHADOW_IN;
+ else
+ nShadowType = GTK_SHADOW_OUT;
+
+ if ( nPart == PART_MENU_ITEM_CHECK_MARK )
+ {
+ gtk_paint_check( pWidget->style,
+ gdkDrawable,
+ nStateType,
+ nShadowType,
+ &clipRect,
+ gWidgetData[m_nScreen].gMenuItemMenuWidget,
+ "check",
+ x, y, w, h );
+ }
+ else
+ {
+ gtk_paint_option( pWidget->style,
+ gdkDrawable,
+ nStateType,
+ nShadowType,
+ &clipRect,
+ gWidgetData[m_nScreen].gMenuItemMenuWidget,
+ "option",
+ x, y, w, h );
+ }
+ }
+ }
+
+ return( TRUE );
+}
+
+BOOL GtkSalGraphics::NWPaintGTKTooltip(
+ GdkDrawable* gdkDrawable,
+ ControlType, ControlPart,
+ const Rectangle& rControlRectangle,
+ const clipList& rClipList,
+ ControlState, const ImplControlValue&,
+ const OUString& )
+{
+ NWEnsureGTKTooltip( m_nScreen );
+
+ gint x, y, w, h;
+ GdkRectangle clipRect;
+
+ x = rControlRectangle.Left();
+ y = rControlRectangle.Top();
+ w = rControlRectangle.GetWidth();
+ h = rControlRectangle.GetHeight();
+
+ for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it )
+ {
+ clipRect.x = it->Left();
+ clipRect.y = it->Top();
+ clipRect.width = it->GetWidth();
+ clipRect.height = it->GetHeight();
+
+ gtk_paint_flat_box( gWidgetData[m_nScreen].gTooltipPopup->style,
+ gdkDrawable,
+ GTK_STATE_NORMAL,
+ GTK_SHADOW_OUT,
+ &clipRect,
+ gWidgetData[m_nScreen].gTooltipPopup,
+ "tooltip",
+ x, y, w, h );
+ }
+
+ return( TRUE );
+}
+
+BOOL GtkSalGraphics::NWPaintGTKListNode(
+ GdkDrawable*,
+ ControlType, ControlPart,
+ const Rectangle& rControlRectangle,
+ const clipList&,
+ ControlState nState, const ImplControlValue& rValue,
+ const OUString& )
+{
+ NWEnsureGTKTreeView( m_nScreen );
+
+ Rectangle aRect( rControlRectangle );
+ aRect.Left() -= 2;
+ aRect.Right() += 2;
+ aRect.Top() -= 2;
+ aRect.Bottom() += 2;
+ gint w, h;
+ w = aRect.GetWidth();
+ h = aRect.GetHeight();
+
+ GtkStateType stateType;
+ GtkShadowType shadowType;
+ NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
+
+ ButtonValue aButtonValue = rValue.getTristateVal();
+ GtkExpanderStyle eStyle = GTK_EXPANDER_EXPANDED;
+
+ switch( aButtonValue )
+ {
+ case BUTTONVALUE_ON: eStyle = GTK_EXPANDER_EXPANDED;break;
+ case BUTTONVALUE_OFF: eStyle = GTK_EXPANDER_COLLAPSED; break;
+ default:
+ break;
+ }
+
+ GdkPixmap* pixmap = NWGetPixmapFromScreen( aRect );
+ if( ! pixmap )
+ return FALSE;
+
+ GdkDrawable* const &pixDrawable = GDK_DRAWABLE( pixmap );
+ gtk_paint_expander( gWidgetData[m_nScreen].gTreeView->style,
+ pixDrawable,
+ stateType,
+ NULL,
+ gWidgetData[m_nScreen].gTreeView,
+ "treeview",
+ w/2, h/2,
+ eStyle );
+
+ BOOL bRet = NWRenderPixmapToScreen( pixmap, aRect );
+ g_object_unref( pixmap );
+
+ return bRet;
+}
+
+BOOL GtkSalGraphics::NWPaintGTKProgress(
+ GdkDrawable*,
+ ControlType, ControlPart,
+ const Rectangle& rControlRectangle,
+ const clipList&,
+ ControlState, const ImplControlValue& rValue,
+ const OUString& )
+{
+ NWEnsureGTKProgressBar( m_nScreen );
+
+ gint w, h;
+ w = rControlRectangle.GetWidth();
+ h = rControlRectangle.GetHeight();
+
+ long nProgressWidth = rValue.getNumericVal();
+
+ GdkPixmap* pixmap = NWGetPixmapFromScreen( Rectangle( Point( 0, 0 ), Size( w, h ) ) );
+ if( ! pixmap )
+ return FALSE;
+
+ GdkDrawable* const &pixDrawable = GDK_DRAWABLE( pixmap );
+
+ // paint background
+ gtk_paint_flat_box( gWidgetData[m_nScreen].gProgressBar->style,
+ pixDrawable,
+ GTK_STATE_NORMAL,
+ GTK_SHADOW_NONE,
+ NULL,
+ gWidgetData[m_nScreen].gProgressBar,
+ "trough",
+ 0, 0, w, h );
+ if( nProgressWidth > 0 )
+ {
+ // paint progress
+ if( Application::GetSettings().GetLayoutRTL() )
+ {
+ gtk_paint_box( gWidgetData[m_nScreen].gProgressBar->style,
+ pixDrawable,
+ GTK_STATE_PRELIGHT, GTK_SHADOW_OUT,
+ NULL,
+ gWidgetData[m_nScreen].gProgressBar,
+ "bar",
+ w-nProgressWidth, 0, nProgressWidth, h
+ );
+ }
+ else
+ {
+ gtk_paint_box( gWidgetData[m_nScreen].gProgressBar->style,
+ pixDrawable,
+ GTK_STATE_PRELIGHT, GTK_SHADOW_OUT,
+ NULL,
+ gWidgetData[m_nScreen].gProgressBar,
+ "bar",
+ 0, 0, nProgressWidth, h
+ );
+ }
+ }
+
+ BOOL bRet = NWRenderPixmapToScreen( pixmap, rControlRectangle );
+ g_object_unref( pixmap );
+
+ return bRet;
+}
+
+BOOL GtkSalGraphics::NWPaintGTKSlider(
+ GdkDrawable*,
+ ControlType, ControlPart nPart,
+ const Rectangle& rControlRectangle,
+ const clipList&,
+ ControlState nState, const ImplControlValue& rValue,
+ const OUString& )
+{
+ OSL_ASSERT( rValue.getType() == CTRL_SLIDER );
+ NWEnsureGTKSlider( m_nScreen );
+
+ gint w, h;
+ w = rControlRectangle.GetWidth();
+ h = rControlRectangle.GetHeight();
+
+ const SliderValue* pVal = static_cast<const SliderValue*>(&rValue);
+
+ GdkPixmap* pixmap = NWGetPixmapFromScreen( rControlRectangle );
+ if( ! pixmap )
+ return FALSE;
+
+ GdkDrawable* const &pixDrawable = GDK_DRAWABLE( pixmap );
+ GtkWidget* pWidget = (nPart == PART_TRACK_HORZ_AREA)
+ ? GTK_WIDGET(gWidgetData[m_nScreen].gHScale)
+ : GTK_WIDGET(gWidgetData[m_nScreen].gVScale);
+ const gchar* pDetail = (nPart == PART_TRACK_HORZ_AREA) ? "hscale" : "vscale";
+ GtkOrientation eOri = (nPart == PART_TRACK_HORZ_AREA) ? GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL;
+ GtkStateType eState = (nState & CTRL_STATE_ENABLED) ? GTK_STATE_ACTIVE : GTK_STATE_INSENSITIVE;
+ gint slider_width = 10;
+ gint slider_length = 10;
+ gint trough_border = 0;
+ gtk_widget_style_get( pWidget,
+ "slider-width", &slider_width,
+ "slider-length", &slider_length,
+ "trough-border", &trough_border,
+ NULL);
+
+ eState = (nState & CTRL_STATE_ENABLED) ? GTK_STATE_NORMAL : GTK_STATE_INSENSITIVE;
+ if( nPart == PART_TRACK_HORZ_AREA )
+ {
+ gtk_paint_box( pWidget->style,
+ pixDrawable,
+ eState,
+ GTK_SHADOW_IN,
+ NULL,
+ pWidget,
+ "trough",
+ 0, (h-slider_width-2*trough_border)/2, w, slider_width + 2*trough_border);
+ gint x = (w - slider_length + 1) * (pVal->mnCur - pVal->mnMin) / (pVal->mnMax - pVal->mnMin);
+ gtk_paint_slider( pWidget->style,
+ pixDrawable,
+ eState,
+ GTK_SHADOW_OUT,
+ NULL,
+ pWidget,
+ pDetail,
+ x, (h-slider_width)/2,
+ slider_length, slider_width,
+ eOri );
+ }
+ else
+ {
+ gtk_paint_box( pWidget->style,
+ pixDrawable,
+ eState,
+ GTK_SHADOW_IN,
+ NULL,
+ pWidget,
+ "trough",
+ (w-slider_width-2*trough_border)/2, 0, slider_width + 2*trough_border, h);
+ gint y = (h - slider_length + 1) * (pVal->mnCur - pVal->mnMin) / (pVal->mnMax - pVal->mnMin);
+ gtk_paint_slider( pWidget->style,
+ pixDrawable,
+ eState,
+ GTK_SHADOW_OUT,
+ NULL,
+ pWidget,
+ pDetail,
+ (w-slider_width)/2, y,
+ slider_width, slider_length,
+ eOri );
+ }
+ #if 0
+ // paint background
+ gtk_paint_flat_box( gWidgetData[m_nScreen].gProgressBar->style,
+ pixDrawable,
+ GTK_STATE_NORMAL,
+ GTK_SHADOW_NONE,
+ NULL,
+ gWidgetData[m_nScreen].gProgressBar,
+ "trough",
+ 0, 0, w, h );
+ if( nProgressWidth > 0 )
+ {
+ // paint progress
+ if( Application::GetSettings().GetLayoutRTL() )
+ {
+ gtk_paint_box( gWidgetData[m_nScreen].gProgressBar->style,
+ pixDrawable,
+ GTK_STATE_PRELIGHT, GTK_SHADOW_OUT,
+ NULL,
+ gWidgetData[m_nScreen].gProgressBar,
+ "bar",
+ w-nProgressWidth, 0, nProgressWidth, h
+ );
+ }
+ else
+ {
+ gtk_paint_box( gWidgetData[m_nScreen].gProgressBar->style,
+ pixDrawable,
+ GTK_STATE_PRELIGHT, GTK_SHADOW_OUT,
+ NULL,
+ gWidgetData[m_nScreen].gProgressBar,
+ "bar",
+ 0, 0, nProgressWidth, h
+ );
+ }
+ }
+ #endif
+
+ BOOL bRet = NWRenderPixmapToScreen( pixmap, rControlRectangle );
+ g_object_unref( pixmap );
+
+ return bRet;
+}
+
+//----
+
+static Rectangle NWGetListBoxButtonRect( int nScreen,
+ ControlType,
+ ControlPart nPart,
+ Rectangle aAreaRect,
+ ControlState,
+ const ImplControlValue&,
+ const OUString& )
+{
+ Rectangle aPartRect;
+ GtkRequisition *pIndicatorSize = NULL;
+ GtkBorder *pIndicatorSpacing = NULL;
+ gint width = 13; // GTK+ default
+ gint right = 5; // GTK+ default
+ gint nButtonAreaWidth = 0;
+ gint xthickness = 0;
+
+ NWEnsureGTKOptionMenu( nScreen );
+
+ gtk_widget_style_get( gWidgetData[nScreen].gOptionMenuWidget,
+ "indicator_size", &pIndicatorSize,
+ "indicator_spacing",&pIndicatorSpacing, (char *)NULL);
+
+ if ( pIndicatorSize )
+ width = pIndicatorSize->width;
+
+ if ( pIndicatorSpacing )
+ right = pIndicatorSpacing->right;
+
+ Size aPartSize( 0, aAreaRect.GetHeight() );
+ Point aPartPos ( 0, aAreaRect.Top() );
+
+ xthickness = gWidgetData[nScreen].gOptionMenuWidget->style->xthickness;
+ nButtonAreaWidth = width + right + (xthickness * 2);
+ switch( nPart )
+ {
+ case PART_BUTTON_DOWN:
+ aPartSize.Width() = nButtonAreaWidth;
+ aPartPos.X() = aAreaRect.Left() + aAreaRect.GetWidth() - aPartSize.Width();
+ break;
+
+ case PART_SUB_EDIT:
+ aPartSize.Width() = aAreaRect.GetWidth() - nButtonAreaWidth - xthickness;
+ aPartPos.X() = aAreaRect.Left() + xthickness;
+ break;
+
+ default:
+ aPartSize.Width() = aAreaRect.GetWidth();
+ aPartPos.X() = aAreaRect.Left();
+ break;
+ }
+ aPartRect = Rectangle( aPartPos, aPartSize );
+
+ if ( pIndicatorSize )
+ gtk_requisition_free( pIndicatorSize );
+ if ( pIndicatorSpacing )
+ gtk_border_free( pIndicatorSpacing );
+
+ return( aPartRect );
+}
+
+//----
+
+static Rectangle NWGetListBoxIndicatorRect( int nScreen,
+ ControlType,
+ ControlPart,
+ Rectangle aAreaRect,
+ ControlState,
+ const ImplControlValue&,
+ const OUString& )
+{
+ Rectangle aIndicatorRect;
+ GtkRequisition *pIndicatorSize = NULL;
+ GtkBorder *pIndicatorSpacing = NULL;
+ gint width = 13; // GTK+ default
+ gint height = 13; // GTK+ default
+ gint right = 5; // GTK+ default
+
+ NWEnsureGTKOptionMenu( nScreen );
+
+ gtk_widget_style_get( gWidgetData[nScreen].gOptionMenuWidget,
+ "indicator_size", &pIndicatorSize,
+ "indicator_spacing",&pIndicatorSpacing, (char *)NULL);
+
+ if ( pIndicatorSize )
+ {
+ width = pIndicatorSize->width;
+ height = pIndicatorSize->height;
+ }
+
+ if ( pIndicatorSpacing )
+ right = pIndicatorSpacing->right;
+
+ aIndicatorRect.SetSize( Size( width, height ) );
+ aIndicatorRect.SetPos( Point( aAreaRect.Left() + aAreaRect.GetWidth() - width - right - gWidgetData[nScreen].gOptionMenuWidget->style->xthickness,
+ aAreaRect.Top() + ((aAreaRect.GetHeight() - height) / 2) ) );
+
+ // If height is odd, move the indicator down 1 pixel
+ if ( aIndicatorRect.GetHeight() % 2 )
+ aIndicatorRect.Move( 0, 1 );
+
+ if ( pIndicatorSize )
+ gtk_requisition_free( pIndicatorSize );
+ if ( pIndicatorSpacing )
+ gtk_border_free( pIndicatorSpacing );
+
+ return( aIndicatorRect );
+}
+
+static Rectangle NWGetToolbarRect( int nScreen,
+ ControlType,
+ ControlPart nPart,
+ Rectangle aAreaRect,
+ ControlState,
+ const ImplControlValue&,
+ const OUString& )
+{
+ Rectangle aRet;
+
+ if( nPart == PART_DRAW_BACKGROUND_HORZ ||
+ nPart == PART_DRAW_BACKGROUND_VERT )
+ aRet = aAreaRect;
+ else if( nPart == PART_THUMB_HORZ )
+ aRet = Rectangle( Point( 0, 0 ), Size( aAreaRect.GetWidth(), 10 ) );
+ else if( nPart == PART_THUMB_VERT )
+ aRet = Rectangle( Point( 0, 0 ), Size( 10, aAreaRect.GetHeight() ) );
+ else if( nPart == PART_BUTTON )
+ {
+ aRet = aAreaRect;
+
+ NWEnsureGTKToolbar( nScreen );
+
+ gint nMinWidth =
+ 2*gWidgetData[nScreen].gToolbarButtonWidget->style->xthickness
+ + 1 // CHILD_SPACING constant, found in gtk_button.c
+ + 3*gWidgetData[nScreen].gToolbarButtonWidget->style->xthickness; // Murphy factor
+ gint nMinHeight =
+ 2*gWidgetData[nScreen].gToolbarButtonWidget->style->ythickness
+ + 1 // CHILD_SPACING constant, found in gtk_button.c
+ + 3*gWidgetData[nScreen].gToolbarButtonWidget->style->ythickness; // Murphy factor
+
+ gtk_widget_ensure_style( gWidgetData[nScreen].gToolbarButtonWidget );
+ if( aAreaRect.GetWidth() < nMinWidth )
+ aRet.Right() = aRet.Left() + nMinWidth;
+ if( aAreaRect.GetHeight() < nMinHeight )
+ aRet.Bottom() = aRet.Top() + nMinHeight;
+ }
+
+ return aRet;
+}
+
+/************************************************************************
+ * helper for GtkSalFrame
+ ************************************************************************/
+static inline Color getColor( const GdkColor& rCol )
+{
+ return Color( rCol.red >> 8, rCol.green >> 8, rCol.blue >> 8 );
+}
+
+#if OSL_DEBUG_LEVEL > 1
+
+void printColor( const char* name, const GdkColor& rCol )
+{
+ std::fprintf( stderr, " %s = 0x%2x 0x%2x 0x%2x\n",
+ name,
+ rCol.red >> 8, rCol.green >> 8, rCol.blue >> 8 );
+}
+
+void printStyleColors( GtkStyle* pStyle )
+{
+ static const char* pStates[] = { "NORMAL", "ACTIVE", "PRELIGHT", "SELECTED", "INSENSITIVE" };
+
+ for( int i = 0; i < 5; i++ )
+ {
+ std::fprintf( stderr, "state %s colors:\n", pStates[i] );
+ printColor( "bg ", pStyle->bg[i] );
+ printColor( "fg ", pStyle->fg[i] );
+ printColor( "light ", pStyle->light[i] );
+ printColor( "dark ", pStyle->dark[i] );
+ printColor( "mid ", pStyle->mid[i] );
+ printColor( "text ", pStyle->text[i] );
+ printColor( "base ", pStyle->base[i] );
+ printColor( "text_aa", pStyle->text_aa[i] );
+ }
+}
+#endif
+
+void GtkSalGraphics::updateSettings( AllSettings& rSettings )
+{
+ // get the widgets in place
+ NWEnsureGTKMenu( m_nScreen );
+ NWEnsureGTKMenubar( m_nScreen );
+ NWEnsureGTKScrollbars( m_nScreen );
+ NWEnsureGTKEditBox( m_nScreen );
+ NWEnsureGTKTooltip( m_nScreen );
+
+ gtk_widget_ensure_style( m_pWindow );
+ GtkStyle* pStyle = gtk_widget_get_style( m_pWindow );
+
+ StyleSettings aStyleSet = rSettings.GetStyleSettings();
+
+#if OSL_DEBUG_LEVEL > 2
+ printStyleColors( pStyle );
+#endif
+
+ // text colors
+ Color aTextColor = getColor( pStyle->text[GTK_STATE_NORMAL] );
+ aStyleSet.SetDialogTextColor( aTextColor );
+ aStyleSet.SetButtonTextColor( aTextColor );
+ aStyleSet.SetRadioCheckTextColor( aTextColor );
+ aStyleSet.SetGroupTextColor( aTextColor );
+ aStyleSet.SetLabelTextColor( aTextColor );
+ aStyleSet.SetInfoTextColor( aTextColor );
+ aStyleSet.SetWindowTextColor( aTextColor );
+ aStyleSet.SetFieldTextColor( aTextColor );
+
+ // Tooltip colors
+ GtkStyle* pTooltipStyle = gtk_widget_get_style( gWidgetData[m_nScreen].gTooltipPopup );
+ aTextColor = getColor( pTooltipStyle->fg[ GTK_STATE_NORMAL ] );
+ aStyleSet.SetHelpTextColor( aTextColor );
+
+ // mouse over text colors
+ aTextColor = getColor( pStyle->fg[ GTK_STATE_PRELIGHT ] );
+ aStyleSet.SetButtonRolloverTextColor( aTextColor );
+ aStyleSet.SetFieldRolloverTextColor( aTextColor );
+
+ // background colors
+ Color aBackColor = getColor( pStyle->bg[GTK_STATE_NORMAL] );
+ Color aBackFieldColor = getColor( pStyle->base[ GTK_STATE_NORMAL ] );
+ aStyleSet.Set3DColors( aBackColor );
+ aStyleSet.SetFaceColor( aBackColor );
+ aStyleSet.SetDialogColor( aBackColor );
+ aStyleSet.SetWorkspaceColor( aBackColor );
+ aStyleSet.SetFieldColor( aBackFieldColor );
+ aStyleSet.SetWindowColor( aBackFieldColor );
+// aStyleSet.SetHelpColor( aBackColor );
+ // ancient wisdom tells us a mystic algorithm how to set checked color
+ if( aBackColor == COL_LIGHTGRAY )
+ aStyleSet.SetCheckedColor( Color( 0xCC, 0xCC, 0xCC ) );
+ else
+ {
+ Color aColor2 = aStyleSet.GetLightColor();
+ Color aCheck( (BYTE)(((USHORT)aBackColor.GetRed()+(USHORT)aColor2.GetRed())/2),
+ (BYTE)(((USHORT)aBackColor.GetGreen()+(USHORT)aColor2.GetGreen())/2),
+ (BYTE)(((USHORT)aBackColor.GetBlue()+(USHORT)aColor2.GetBlue())/2)
+ );
+ aStyleSet.SetCheckedColor( aCheck );
+ }
+
+ // highlighting colors
+ Color aHighlightColor = getColor( pStyle->base[GTK_STATE_SELECTED] );
+ Color aHighlightTextColor = getColor( pStyle->text[GTK_STATE_SELECTED] );
+ aStyleSet.SetHighlightColor( aHighlightColor );
+ aStyleSet.SetHighlightTextColor( aHighlightTextColor );
+
+ if( ! gtk_check_version( 2, 10, 0 ) ) // link colors came in with 2.10, avoid an assertion
+ {
+ // hyperlink colors
+ GdkColor *link_color = NULL;
+ gtk_widget_style_get (m_pWindow, "link-color", &link_color, NULL);
+ if (link_color)
+ {
+ aStyleSet.SetLinkColor(getColor(*link_color));
+ gdk_color_free (link_color);
+ link_color = NULL;
+ }
+ gtk_widget_style_get (m_pWindow, "visited-link-color", &link_color, NULL);
+ if (link_color)
+ {
+ aStyleSet.SetVisitedLinkColor(getColor(*link_color));
+ gdk_color_free (link_color);
+ }
+ }
+
+ // Tab colors
+ aStyleSet.SetActiveTabColor( aBackFieldColor ); // same as the window color.
+ Color aSelectedBackColor = getColor( pStyle->bg[GTK_STATE_ACTIVE] );
+ aStyleSet.SetInactiveTabColor( aSelectedBackColor );
+
+ // menu disabled entries handling
+ aStyleSet.SetSkipDisabledInMenus( TRUE );
+ // menu colors
+ GtkStyle* pMenuStyle = gtk_widget_get_style( gWidgetData[m_nScreen].gMenuWidget );
+ GtkStyle* pMenuItemStyle = gtk_rc_get_style( gWidgetData[m_nScreen].gMenuItemMenuWidget );
+ GtkStyle* pMenubarStyle = gtk_rc_get_style( gWidgetData[m_nScreen].gMenubarWidget );
+ GtkStyle* pMenuTextStyle = gtk_rc_get_style( gtk_bin_get_child( GTK_BIN(gWidgetData[m_nScreen].gMenuItemMenuWidget) ) );
+
+ aBackColor = getColor( pMenubarStyle->bg[GTK_STATE_NORMAL] );
+ aStyleSet.SetMenuBarColor( aBackColor );
+ aBackColor = getColor( pMenuStyle->bg[GTK_STATE_NORMAL] );
+ aTextColor = getColor( pMenuTextStyle->fg[GTK_STATE_NORMAL] );
+ aStyleSet.SetMenuColor( aBackColor );
+ aStyleSet.SetMenuTextColor( aTextColor );
+
+ aTextColor = getColor( pMenubarStyle->fg[GTK_STATE_NORMAL] );
+ aStyleSet.SetMenuBarTextColor( aTextColor );
+
+#if OSL_DEBUG_LEVEL > 1
+ std::fprintf( stderr, "==\n" );
+ std::fprintf( stderr, "MenuColor = %x (%d)\n", (int)aStyleSet.GetMenuColor().GetColor(), aStyleSet.GetMenuColor().GetLuminance() );
+ std::fprintf( stderr, "MenuTextColor = %x (%d)\n", (int)aStyleSet.GetMenuTextColor().GetColor(), aStyleSet.GetMenuTextColor().GetLuminance() );
+ std::fprintf( stderr, "MenuBarColor = %x (%d)\n", (int)aStyleSet.GetMenuBarColor().GetColor(), aStyleSet.GetMenuBarColor().GetLuminance() );
+ std::fprintf( stderr, "MenuBarTextColor = %x (%d)\n", (int)aStyleSet.GetMenuBarTextColor().GetColor(), aStyleSet.GetMenuBarTextColor().GetLuminance() );
+ std::fprintf( stderr, "LightColor = %x (%d)\n", (int)aStyleSet.GetLightColor().GetColor(), aStyleSet.GetLightColor().GetLuminance() );
+ std::fprintf( stderr, "ShadowColor = %x (%d)\n", (int)aStyleSet.GetShadowColor().GetColor(), aStyleSet.GetShadowColor().GetLuminance() );
+#endif
+
+ // Awful hack for menu separators in the Sonar and similar themes.
+ // If the menu color is not too dark, and the menu text color is lighter,
+ // make the "light" color lighter than the menu color and the "shadow"
+ // color darker than it.
+ if ( aStyleSet.GetMenuColor().GetLuminance() >= 32 &&
+ aStyleSet.GetMenuColor().GetLuminance() <= aStyleSet.GetMenuTextColor().GetLuminance() )
+ {
+ Color temp = aStyleSet.GetMenuColor();
+ temp.IncreaseLuminance( 8 );
+ aStyleSet.SetLightColor( temp );
+ temp = aStyleSet.GetMenuColor();
+ temp.DecreaseLuminance( 16 );
+ aStyleSet.SetShadowColor( temp );
+ }
+
+ aHighlightColor = getColor( pMenuItemStyle->bg[ GTK_STATE_SELECTED ] );
+ aHighlightTextColor = getColor( pMenuTextStyle->fg[ GTK_STATE_PRELIGHT ] );
+ if( aHighlightColor == aHighlightTextColor )
+ aHighlightTextColor = (aHighlightColor.GetLuminance() < 128) ? Color( COL_WHITE ) : Color( COL_BLACK );
+ aStyleSet.SetMenuHighlightColor( aHighlightColor );
+ aStyleSet.SetMenuHighlightTextColor( aHighlightTextColor );
+
+ // UI font
+ OString aFamily = pango_font_description_get_family( pStyle->font_desc );
+ int nPangoHeight = pango_font_description_get_size( pStyle->font_desc );
+ PangoStyle eStyle = pango_font_description_get_style( pStyle->font_desc );
+ PangoWeight eWeight = pango_font_description_get_weight( pStyle->font_desc );
+ PangoStretch eStretch = pango_font_description_get_stretch( pStyle->font_desc );
+
+ psp::FastPrintFontInfo aInfo;
+ // set family name
+ aInfo.m_aFamilyName = OStringToOUString( aFamily, RTL_TEXTENCODING_UTF8 );
+ // set italic
+ switch( eStyle )
+ {
+ case PANGO_STYLE_NORMAL: aInfo.m_eItalic = psp::italic::Upright;break;
+ case PANGO_STYLE_ITALIC: aInfo.m_eItalic = psp::italic::Italic;break;
+ case PANGO_STYLE_OBLIQUE: aInfo.m_eItalic = psp::italic::Oblique;break;
+ }
+ // set weight
+ if( eWeight <= PANGO_WEIGHT_ULTRALIGHT )
+ aInfo.m_eWeight = psp::weight::UltraLight;
+ else if( eWeight <= PANGO_WEIGHT_LIGHT )
+ aInfo.m_eWeight = psp::weight::Light;
+ else if( eWeight <= PANGO_WEIGHT_NORMAL )
+ aInfo.m_eWeight = psp::weight::Normal;
+ else if( eWeight <= PANGO_WEIGHT_BOLD )
+ aInfo.m_eWeight = psp::weight::Bold;
+ else
+ aInfo.m_eWeight = psp::weight::UltraBold;
+ // set width
+ switch( eStretch )
+ {
+ case PANGO_STRETCH_ULTRA_CONDENSED: aInfo.m_eWidth = psp::width::UltraCondensed;break;
+ case PANGO_STRETCH_EXTRA_CONDENSED: aInfo.m_eWidth = psp::width::ExtraCondensed;break;
+ case PANGO_STRETCH_CONDENSED: aInfo.m_eWidth = psp::width::Condensed;break;
+ case PANGO_STRETCH_SEMI_CONDENSED: aInfo.m_eWidth = psp::width::SemiCondensed;break;
+ case PANGO_STRETCH_NORMAL: aInfo.m_eWidth = psp::width::Normal;break;
+ case PANGO_STRETCH_SEMI_EXPANDED: aInfo.m_eWidth = psp::width::SemiExpanded;break;
+ case PANGO_STRETCH_EXPANDED: aInfo.m_eWidth = psp::width::Expanded;break;
+ case PANGO_STRETCH_EXTRA_EXPANDED: aInfo.m_eWidth = psp::width::ExtraExpanded;break;
+ case PANGO_STRETCH_ULTRA_EXPANDED: aInfo.m_eWidth = psp::width::UltraExpanded;break;
+ }
+
+#if OSL_DEBUG_LEVEL > 1
+ std::fprintf( stderr, "font name BEFORE system match: \"%s\"\n", aFamily.getStr() );
+#endif
+
+ // match font to e.g. resolve "Sans"
+ psp::PrintFontManager::get().matchFont( aInfo, rSettings.GetUILocale() );
+
+#if OSL_DEBUG_LEVEL > 1
+ std::fprintf( stderr, "font match %s, name AFTER: \"%s\"\n",
+ aInfo.m_nID != 0 ? "succeeded" : "failed",
+ OUStringToOString( aInfo.m_aFamilyName, RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+#endif
+
+ sal_Int32 nDispDPIY = GetDisplay()->GetResolution().B();
+ int nPointHeight = 0;
+ static gboolean(*pAbso)(const PangoFontDescription*) =
+ (gboolean(*)(const PangoFontDescription*))osl_getAsciiFunctionSymbol( GetSalData()->m_pPlugin, "pango_font_description_get_size_is_absolute" );
+
+ if( pAbso && pAbso( pStyle->font_desc ) )
+ nPointHeight = (nPangoHeight * 72 + nDispDPIY*PANGO_SCALE/2) / (nDispDPIY * PANGO_SCALE);
+ else
+ nPointHeight = nPangoHeight/PANGO_SCALE;
+
+ Font aFont( aInfo.m_aFamilyName, Size( 0, nPointHeight ) );
+ if( aInfo.m_eWeight != psp::weight::Unknown )
+ aFont.SetWeight( PspGraphics::ToFontWeight( aInfo.m_eWeight ) );
+ if( aInfo.m_eWidth != psp::width::Unknown )
+ aFont.SetWidthType( PspGraphics::ToFontWidth( aInfo.m_eWidth ) );
+ if( aInfo.m_eItalic != psp::italic::Unknown )
+ aFont.SetItalic( PspGraphics::ToFontItalic( aInfo.m_eItalic ) );
+ if( aInfo.m_ePitch != psp::pitch::Unknown )
+ aFont.SetPitch( PspGraphics::ToFontPitch( aInfo.m_ePitch ) );
+
+ aStyleSet.SetAppFont( aFont );
+ aStyleSet.SetHelpFont( aFont );
+ aStyleSet.SetTitleFont( aFont );
+ aStyleSet.SetFloatTitleFont( aFont );
+ aStyleSet.SetMenuFont( aFont );
+ aStyleSet.SetToolFont( aFont );
+ aStyleSet.SetLabelFont( aFont );
+ aStyleSet.SetInfoFont( aFont );
+ aStyleSet.SetRadioCheckFont( aFont );
+ aStyleSet.SetPushButtonFont( aFont );
+ aStyleSet.SetFieldFont( aFont );
+ aStyleSet.SetIconFont( aFont );
+ aStyleSet.SetGroupFont( aFont );
+
+ // get cursor blink time
+ GtkSettings *pSettings = gtk_widget_get_settings( gWidgetData[m_nScreen].gEditBoxWidget );
+ gboolean blink = false;
+
+ g_object_get( pSettings, "gtk-cursor-blink", &blink, (char *)NULL );
+ if( blink )
+ {
+ gint blink_time = STYLE_CURSOR_NOBLINKTIME;
+ g_object_get( pSettings, "gtk-cursor-blink-time", &blink_time, (char *)NULL );
+ // set the blink_time if there is a setting and it is reasonable
+ // else leave the default value
+ if( blink_time > 100 && blink_time != gint(STYLE_CURSOR_NOBLINKTIME) )
+ aStyleSet.SetCursorBlinkTime( blink_time/2 );
+ }
+ else
+ aStyleSet.SetCursorBlinkTime( STYLE_CURSOR_NOBLINKTIME );
+
+ gboolean showmenuicons = true;
+ pSettings = gtk_widget_get_settings( gWidgetData[m_nScreen].gImageMenuItem );
+ g_object_get( pSettings, "gtk-menu-images", &showmenuicons, (char *)NULL );
+ aStyleSet.SetUseImagesInMenus( showmenuicons );
+
+ // set scrollbar settings
+ gint slider_width = 14;
+ gint trough_border = 1;
+ gint min_slider_length = 21;
+
+ // Grab some button style attributes
+ gtk_widget_style_get( gWidgetData[m_nScreen].gScrollHorizWidget,
+ "slider-width", &slider_width,
+ "trough-border", &trough_border,
+ "min-slider-length", &min_slider_length,
+ (char *)NULL );
+ gint magic = trough_border ? 1 : 0;
+ aStyleSet.SetScrollBarSize( slider_width + 2*trough_border );
+ aStyleSet.SetMinThumbSize( min_slider_length - magic );
+
+ // preferred icon style
+ gchar* pIconThemeName = NULL;
+ g_object_get( gtk_settings_get_default(), "gtk-icon-theme-name", &pIconThemeName, (char *)NULL );
+ aStyleSet.SetPreferredSymbolsStyleName( OUString::createFromAscii( pIconThemeName ) );
+ g_free( pIconThemeName );
+
+ // FIXME: need some way of fetching toolbar icon size.
+// aStyleSet.SetToolbarIconSize( STYLE_TOOLBAR_ICONSIZE_SMALL );
+
+ const cairo_font_options_t* pNewOptions = NULL;
+ if( GdkScreen* pScreen = gdk_display_get_screen( gdk_display_get_default(), m_nScreen ) )
+ {
+//#if !GTK_CHECK_VERSION(2,8,1)
+#if !GTK_CHECK_VERSION(2,9,0)
+ static cairo_font_options_t* (*gdk_screen_get_font_options)(GdkScreen*) =
+ (cairo_font_options_t*(*)(GdkScreen*))osl_getAsciiFunctionSymbol( GetSalData()->m_pPlugin, "gdk_screen_get_font_options" );
+ if( gdk_screen_get_font_options != NULL )
+#endif
+ pNewOptions = gdk_screen_get_font_options( pScreen );
+ }
+ aStyleSet.SetCairoFontOptions( pNewOptions );
+
+ // finally update the collected settings
+ rSettings.SetStyleSettings( aStyleSet );
+
+ #if OSL_DEBUG_LEVEL > 1
+ {
+ GtkSettings* pGtkSettings = gtk_settings_get_default();
+ GValue aValue;
+ memset( &aValue, 0, sizeof(GValue) );
+ g_value_init( &aValue, G_TYPE_STRING );
+ g_object_get_property( G_OBJECT(pGtkSettings), "gtk-theme-name", &aValue );
+ const gchar* pThemeName = g_value_get_string( &aValue );
+ std::fprintf( stderr, "Theme name is \"%s\"\n", pThemeName );
+ g_value_unset( &aValue );
+ }
+ #endif
+ GtkSettings* pGtkSettings = gtk_settings_get_default();
+ GValue aValue;
+ memset( &aValue, 0, sizeof(GValue) );
+ g_value_init( &aValue, G_TYPE_STRING );
+ g_object_get_property( G_OBJECT(pGtkSettings), "gtk-theme-name", &aValue );
+ const gchar* pThemeName = g_value_get_string( &aValue );
+
+ // default behaviour
+ bNeedPixmapPaint = bGlobalNeedPixmapPaint;
+ bToolbarGripWorkaround = false;
+ bNeedButtonStyleAsEditBackgroundWorkaround = false;
+
+ // setup some workarounds for "blueprint" theme
+ if( pThemeName && strncasecmp( pThemeName, "blueprint", 9 ) == 0 )
+ {
+ bNeedButtonStyleAsEditBackgroundWorkaround = true;
+ if( GetX11SalData()->GetDisplay()->GetServerVendor() == vendor_sun )
+ {
+ // #i52570#, #i61532# workaround a weird paint issue;
+ // on a Sunray Xserver sometimes painting buttons and edits
+ // won't work when using the blueprint theme
+ // not reproducible with simpler programs or other themes
+ if( pThemeName && strncasecmp( pThemeName, "blueprint", 9 ) == 0 )
+ {
+ bNeedPixmapPaint = true;
+ bToolbarGripWorkaround = true;
+ }
+ }
+ }
+ // clean up
+ g_value_unset( &aValue );
+}
+
+
+/************************************************************************
+ * Create a GdkPixmap filled with the contents of an area of an Xlib window
+ ************************************************************************/
+
+GdkPixmap* GtkSalGraphics::NWGetPixmapFromScreen( Rectangle srcRect )
+{
+ // Create a new pixmap to hold the composite of the window background and the control
+ GdkPixmap * pPixmap = gdk_pixmap_new( GDK_DRAWABLE(GetGdkWindow()), srcRect.GetWidth(), srcRect.GetHeight(), -1 );
+ GdkGC * pPixmapGC = gdk_gc_new( pPixmap );
+
+ if( !pPixmap || !pPixmapGC )
+ {
+ if ( pPixmap )
+ g_object_unref( pPixmap );
+ if ( pPixmapGC )
+ g_object_unref( pPixmapGC );
+ std::fprintf( stderr, "salnativewidgets-gtk.cxx: could not get valid pixmap from screen\n" );
+ return( NULL );
+ }
+
+ // Copy the background of the screen into a composite pixmap
+ CopyScreenArea( GetXDisplay(),
+ GetDrawable(), GetScreenNumber(), GetVisual().GetDepth(),
+ gdk_x11_drawable_get_xid(pPixmap),
+ gdk_screen_get_number( gdk_drawable_get_screen( GDK_DRAWABLE(pPixmap) ) ),
+ gdk_drawable_get_depth( GDK_DRAWABLE( pPixmap ) ),
+ gdk_x11_gc_get_xgc(pPixmapGC),
+ srcRect.Left(), srcRect.Top(), srcRect.GetWidth(), srcRect.GetHeight(), 0, 0 );
+
+ g_object_unref( pPixmapGC );
+ return( pPixmap );
+}
+
+
+
+
+/************************************************************************
+ * Copy an alpha pixmap to screen using a gc with clipping
+ ************************************************************************/
+
+BOOL GtkSalGraphics::NWRenderPixmapToScreen( GdkPixmap* pPixmap, Rectangle dstRect )
+{
+ // The GC can't be null, otherwise we'd have no clip region
+ GC aFontGC = GetFontGC();
+ if( aFontGC == NULL )
+ {
+ std::fprintf(stderr, "salnativewidgets.cxx: no valid GC\n" );
+ return( FALSE );
+ }
+
+ if ( !pPixmap )
+ return( FALSE );
+
+ // Copy the background of the screen into a composite pixmap
+ CopyScreenArea( GetXDisplay(),
+ GDK_DRAWABLE_XID(pPixmap),
+ gdk_screen_get_number( gdk_drawable_get_screen( GDK_DRAWABLE(pPixmap) ) ),
+ gdk_drawable_get_depth( GDK_DRAWABLE(pPixmap) ),
+ GetDrawable(), m_nScreen, GetVisual().GetDepth(),
+ aFontGC,
+ 0, 0, dstRect.GetWidth(), dstRect.GetHeight(), dstRect.Left(), dstRect.Top() );
+
+ return( TRUE );
+}
+
+
+/************************************************************************
+ * State conversion
+ ************************************************************************/
+static void NWConvertVCLStateToGTKState( ControlState nVCLState,
+ GtkStateType* nGTKState, GtkShadowType* nGTKShadow )
+{
+ *nGTKShadow = GTK_SHADOW_OUT;
+ *nGTKState = GTK_STATE_INSENSITIVE;
+
+ if ( nVCLState & CTRL_STATE_ENABLED )
+ {
+ if ( nVCLState & CTRL_STATE_PRESSED )
+ {
+ *nGTKState = GTK_STATE_ACTIVE;
+ *nGTKShadow = GTK_SHADOW_IN;
+ }
+ else if ( nVCLState & CTRL_STATE_ROLLOVER )
+ {
+ *nGTKState = GTK_STATE_PRELIGHT;
+ *nGTKShadow = GTK_SHADOW_OUT;
+ }
+ else
+ {
+ *nGTKState = GTK_STATE_NORMAL;
+ *nGTKShadow = GTK_SHADOW_OUT;
+ }
+ }
+}
+
+/************************************************************************
+ * Set widget flags
+ ************************************************************************/
+static void NWSetWidgetState( GtkWidget* widget, ControlState nState, GtkStateType nGtkState )
+{
+ // Set to default state, then build up from there
+ GTK_WIDGET_UNSET_FLAGS( widget, GTK_HAS_DEFAULT );
+ GTK_WIDGET_UNSET_FLAGS( widget, GTK_HAS_FOCUS );
+ GTK_WIDGET_UNSET_FLAGS( widget, GTK_SENSITIVE );
+ GTK_WIDGET_SET_FLAGS( widget, gWidgetDefaultFlags[(long)widget] );
+
+ if ( nState & CTRL_STATE_DEFAULT )
+ GTK_WIDGET_SET_FLAGS( widget, GTK_HAS_DEFAULT );
+ if ( !GTK_IS_TOGGLE_BUTTON(widget) && (nState & CTRL_STATE_FOCUSED) )
+ GTK_WIDGET_SET_FLAGS( widget, GTK_HAS_FOCUS );
+ if ( nState & CTRL_STATE_ENABLED )
+ GTK_WIDGET_SET_FLAGS( widget, GTK_SENSITIVE );
+ gtk_widget_set_state( widget, nGtkState );
+}
+
+/************************************************************************
+ * Widget ensure functions - make sure cached objects are valid
+ ************************************************************************/
+
+//-------------------------------------
+
+static void NWAddWidgetToCacheWindow( GtkWidget* widget, int nScreen )
+{
+ NWFWidgetData& rData = gWidgetData[nScreen];
+ if ( !rData.gCacheWindow || !rData.gDumbContainer )
+ {
+ if ( !rData.gCacheWindow )
+ {
+ rData.gCacheWindow = gtk_window_new( GTK_WINDOW_TOPLEVEL );
+ GdkScreen* pScreen = gdk_display_get_screen( gdk_display_get_default(), nScreen );
+ if( pScreen )
+ gtk_window_set_screen( GTK_WINDOW(rData.gCacheWindow), pScreen );
+ }
+ if ( !rData.gDumbContainer )
+ rData.gDumbContainer = gtk_fixed_new();
+ gtk_container_add( GTK_CONTAINER(rData.gCacheWindow), rData.gDumbContainer );
+ gtk_widget_realize( rData.gDumbContainer );
+ gtk_widget_realize( rData.gCacheWindow );
+ }
+
+ gtk_container_add( GTK_CONTAINER(rData.gDumbContainer), widget );
+ gtk_widget_realize( widget );
+ gtk_widget_ensure_style( widget );
+
+ // Store widget's default flags
+ gWidgetDefaultFlags[ (long)widget ] = GTK_WIDGET_FLAGS( widget );
+}
+
+//-------------------------------------
+
+static void NWEnsureGTKButton( int nScreen )
+{
+ if ( !gWidgetData[nScreen].gBtnWidget )
+ {
+ gWidgetData[nScreen].gBtnWidget = gtk_button_new_with_label( "" );
+ NWAddWidgetToCacheWindow( gWidgetData[nScreen].gBtnWidget, nScreen );
+ }
+}
+
+//-------------------------------------
+
+static void NWEnsureGTKRadio( int nScreen )
+{
+ if ( !gWidgetData[nScreen].gRadioWidget || !gWidgetData[nScreen].gRadioWidgetSibling )
+ {
+ gWidgetData[nScreen].gRadioWidget = gtk_radio_button_new( NULL );
+ gWidgetData[nScreen].gRadioWidgetSibling = gtk_radio_button_new_from_widget( GTK_RADIO_BUTTON(gWidgetData[nScreen].gRadioWidget) );
+ NWAddWidgetToCacheWindow( gWidgetData[nScreen].gRadioWidget, nScreen );
+ NWAddWidgetToCacheWindow( gWidgetData[nScreen].gRadioWidgetSibling, nScreen );
+ }
+}
+
+//-------------------------------------
+
+static void NWEnsureGTKCheck( int nScreen )
+{
+ if ( !gWidgetData[nScreen].gCheckWidget )
+ {
+ gWidgetData[nScreen].gCheckWidget = gtk_check_button_new();
+ NWAddWidgetToCacheWindow( gWidgetData[nScreen].gCheckWidget, nScreen );
+ }
+}
+
+//-------------------------------------
+
+static void NWEnsureGTKScrollbars( int nScreen )
+{
+ if ( !gWidgetData[nScreen].gScrollHorizWidget )
+ {
+ gWidgetData[nScreen].gScrollHorizWidget = gtk_hscrollbar_new( NULL );
+ NWAddWidgetToCacheWindow( gWidgetData[nScreen].gScrollHorizWidget, nScreen );
+ }
+
+ if ( !gWidgetData[nScreen].gScrollVertWidget )
+ {
+ gWidgetData[nScreen].gScrollVertWidget = gtk_vscrollbar_new( NULL );
+ NWAddWidgetToCacheWindow( gWidgetData[nScreen].gScrollVertWidget, nScreen );
+ }
+}
+
+//-------------------------------------
+
+static void NWEnsureGTKArrow( int nScreen )
+{
+ if ( !gWidgetData[nScreen].gArrowWidget || !gWidgetData[nScreen].gDropdownWidget )
+ {
+ gWidgetData[nScreen].gDropdownWidget = gtk_toggle_button_new();
+ NWAddWidgetToCacheWindow( gWidgetData[nScreen].gDropdownWidget, nScreen );
+ gWidgetData[nScreen].gArrowWidget = gtk_arrow_new( GTK_ARROW_DOWN, GTK_SHADOW_OUT );
+ gtk_container_add( GTK_CONTAINER(gWidgetData[nScreen].gDropdownWidget), gWidgetData[nScreen].gArrowWidget );
+ gtk_widget_set_rc_style( gWidgetData[nScreen].gArrowWidget );
+ gtk_widget_realize( gWidgetData[nScreen].gArrowWidget );
+ }
+}
+
+//-------------------------------------
+
+static void NWEnsureGTKEditBox( int nScreen )
+{
+ if ( !gWidgetData[nScreen].gEditBoxWidget )
+ {
+ gWidgetData[nScreen].gEditBoxWidget = gtk_entry_new();
+ NWAddWidgetToCacheWindow( gWidgetData[nScreen].gEditBoxWidget, nScreen );
+ }
+}
+
+//-------------------------------------
+
+static void NWEnsureGTKSpinButton( int nScreen )
+{
+ if ( !gWidgetData[nScreen].gSpinButtonWidget )
+ {
+ GtkAdjustment *adj = GTK_ADJUSTMENT( gtk_adjustment_new(0, 0, 1, 1, 1, 0) );
+ gWidgetData[nScreen].gSpinButtonWidget = gtk_spin_button_new( adj, 1, 2 );
+
+ //Setting non-editable means it doesn't blink, so there's no timeouts
+ //running around to nobble us
+ gtk_editable_set_editable(GTK_EDITABLE(gWidgetData[nScreen].gSpinButtonWidget), false);
+
+ NWAddWidgetToCacheWindow( gWidgetData[nScreen].gSpinButtonWidget, nScreen );
+ }
+}
+
+//-------------------------------------
+
+static void NWEnsureGTKNotebook( int nScreen )
+{
+ if ( !gWidgetData[nScreen].gNotebookWidget )
+ {
+ gWidgetData[nScreen].gNotebookWidget = gtk_notebook_new();
+ NWAddWidgetToCacheWindow( gWidgetData[nScreen].gNotebookWidget, nScreen );
+ }
+}
+
+//-------------------------------------
+
+static void NWEnsureGTKOptionMenu( int nScreen )
+{
+ if ( !gWidgetData[nScreen].gOptionMenuWidget )
+ {
+ gWidgetData[nScreen].gOptionMenuWidget = gtk_option_menu_new();
+ NWAddWidgetToCacheWindow( gWidgetData[nScreen].gOptionMenuWidget, nScreen );
+ }
+}
+
+//-------------------------------------
+
+static void NWEnsureGTKCombo( int nScreen )
+{
+ if ( !gWidgetData[nScreen].gComboWidget )
+ {
+ gWidgetData[nScreen].gComboWidget = gtk_combo_new();
+
+ // #i59129# Setting non-editable means it doesn't blink, so
+ // there are no timeouts running around to nobble us
+ gtk_editable_set_editable(GTK_EDITABLE(GTK_COMBO(gWidgetData[nScreen].gComboWidget)->entry), false);
+
+ NWAddWidgetToCacheWindow( gWidgetData[nScreen].gComboWidget, nScreen );
+ // Must realize the ComboBox's children, since GTK
+ // does not do this for us in GtkCombo::gtk_widget_realize()
+ gtk_widget_realize( GTK_COMBO(gWidgetData[nScreen].gComboWidget)->button );
+ gtk_widget_realize( GTK_COMBO(gWidgetData[nScreen].gComboWidget)->entry );
+ }
+}
+
+//-------------------------------------
+
+static void NWEnsureGTKScrolledWindow( int nScreen )
+{
+ if ( !gWidgetData[nScreen].gScrolledWindowWidget )
+ {
+ GtkAdjustment *hadj = GTK_ADJUSTMENT( gtk_adjustment_new(0, 0, 0, 0, 0, 0) );
+ GtkAdjustment *vadj = GTK_ADJUSTMENT( gtk_adjustment_new(0, 0, 0, 0, 0, 0) );
+
+ gWidgetData[nScreen].gScrolledWindowWidget = gtk_scrolled_window_new( hadj, vadj );
+ NWAddWidgetToCacheWindow( gWidgetData[nScreen].gScrolledWindowWidget, nScreen );
+ }
+}
+
+//-------------------------------------
+
+static void NWEnsureGTKToolbar( int nScreen )
+{
+ if( !gWidgetData[nScreen].gToolbarWidget )
+ {
+ gWidgetData[nScreen].gToolbarWidget = gtk_toolbar_new();
+ NWAddWidgetToCacheWindow( gWidgetData[nScreen].gToolbarWidget, nScreen );
+ gWidgetData[nScreen].gToolbarButtonWidget = gtk_button_new();
+ gWidgetData[nScreen].gToolbarToggleWidget = gtk_toggle_button_new();
+
+ GtkReliefStyle aRelief = GTK_RELIEF_NORMAL;
+ gtk_widget_ensure_style( gWidgetData[nScreen].gToolbarWidget );
+ gtk_widget_style_get( gWidgetData[nScreen].gToolbarWidget,
+ "button_relief", &aRelief,
+ (char *)NULL);
+
+ gtk_button_set_relief( GTK_BUTTON(gWidgetData[nScreen].gToolbarButtonWidget), aRelief );
+ GTK_WIDGET_UNSET_FLAGS( gWidgetData[nScreen].gToolbarButtonWidget, GTK_CAN_FOCUS );
+ GTK_WIDGET_UNSET_FLAGS( gWidgetData[nScreen].gToolbarButtonWidget, GTK_CAN_DEFAULT );
+ NWAddWidgetToCacheWindow( gWidgetData[nScreen].gToolbarButtonWidget, nScreen );
+
+ gtk_button_set_relief( GTK_BUTTON(gWidgetData[nScreen].gToolbarToggleWidget), aRelief );
+ GTK_WIDGET_UNSET_FLAGS( gWidgetData[nScreen].gToolbarToggleWidget, GTK_CAN_FOCUS );
+ GTK_WIDGET_UNSET_FLAGS( gWidgetData[nScreen].gToolbarToggleWidget, GTK_CAN_DEFAULT );
+ NWAddWidgetToCacheWindow( gWidgetData[nScreen].gToolbarToggleWidget, nScreen );
+ }
+ if( ! gWidgetData[nScreen].gHandleBoxWidget )
+ {
+ gWidgetData[nScreen].gHandleBoxWidget = gtk_handle_box_new();
+ NWAddWidgetToCacheWindow( gWidgetData[nScreen].gHandleBoxWidget, nScreen );
+ }
+}
+
+//-------------------------------------
+
+static void NWEnsureGTKMenubar( int nScreen )
+{
+ if( !gWidgetData[nScreen].gMenubarWidget )
+ {
+ gWidgetData[nScreen].gMenubarWidget = gtk_menu_bar_new();
+ gWidgetData[nScreen].gMenuItemMenubarWidget = gtk_menu_item_new_with_label( "b" );
+ gtk_menu_shell_append( GTK_MENU_SHELL( gWidgetData[nScreen].gMenubarWidget ), gWidgetData[nScreen].gMenuItemMenubarWidget );
+ gtk_widget_show( gWidgetData[nScreen].gMenuItemMenubarWidget );
+ NWAddWidgetToCacheWindow( gWidgetData[nScreen].gMenubarWidget, nScreen );
+ gtk_widget_show( gWidgetData[nScreen].gMenubarWidget );
+
+ // do what NWAddWidgetToCacheWindow does except adding to def container
+ gtk_widget_realize( gWidgetData[nScreen].gMenuItemMenubarWidget );
+ gtk_widget_ensure_style( gWidgetData[nScreen].gMenuItemMenubarWidget );
+
+ gWidgetDefaultFlags[ (long)gWidgetData[nScreen].gMenuItemMenubarWidget ] = GTK_WIDGET_FLAGS( gWidgetData[nScreen].gMenuItemMenubarWidget );
+ }
+}
+
+static void NWEnsureGTKMenu( int nScreen )
+{
+ if( !gWidgetData[nScreen].gMenuWidget )
+ {
+ gWidgetData[nScreen].gMenuWidget = gtk_menu_new();
+ gWidgetData[nScreen].gMenuItemMenuWidget = gtk_menu_item_new_with_label( "b" );
+ gWidgetData[nScreen].gMenuItemCheckMenuWidget = gtk_check_menu_item_new_with_label( "b" );
+ gWidgetData[nScreen].gMenuItemRadioMenuWidget = gtk_radio_menu_item_new_with_label( NULL, "b" );
+ gWidgetData[nScreen].gImageMenuItem = gtk_image_menu_item_new();
+
+ gtk_menu_shell_append( GTK_MENU_SHELL( gWidgetData[nScreen].gMenuWidget ), gWidgetData[nScreen].gMenuItemMenuWidget );
+ gtk_menu_shell_append( GTK_MENU_SHELL( gWidgetData[nScreen].gMenuWidget ), gWidgetData[nScreen].gMenuItemCheckMenuWidget );
+ gtk_menu_shell_append( GTK_MENU_SHELL( gWidgetData[nScreen].gMenuWidget ), gWidgetData[nScreen].gMenuItemRadioMenuWidget );
+ gtk_menu_shell_append( GTK_MENU_SHELL( gWidgetData[nScreen].gMenuWidget ), gWidgetData[nScreen].gImageMenuItem );
+
+ // do what NWAddWidgetToCacheWindow does except adding to def container
+ gtk_widget_realize( gWidgetData[nScreen].gMenuWidget );
+ gtk_widget_ensure_style( gWidgetData[nScreen].gMenuWidget );
+
+ gtk_widget_realize( gWidgetData[nScreen].gMenuItemMenuWidget );
+ gtk_widget_ensure_style( gWidgetData[nScreen].gMenuItemMenuWidget );
+
+ gtk_widget_realize( gWidgetData[nScreen].gMenuItemCheckMenuWidget );
+ gtk_widget_ensure_style( gWidgetData[nScreen].gMenuItemCheckMenuWidget );
+
+ gtk_widget_realize( gWidgetData[nScreen].gMenuItemRadioMenuWidget );
+ gtk_widget_ensure_style( gWidgetData[nScreen].gMenuItemRadioMenuWidget );
+
+ gtk_widget_realize( gWidgetData[nScreen].gImageMenuItem );
+ gtk_widget_ensure_style( gWidgetData[nScreen].gImageMenuItem );
+
+ gWidgetDefaultFlags[ (long)gWidgetData[nScreen].gMenuWidget ] = GTK_WIDGET_FLAGS( gWidgetData[nScreen].gMenuWidget );
+ gWidgetDefaultFlags[ (long)gWidgetData[nScreen].gMenuItemMenuWidget ] = GTK_WIDGET_FLAGS( gWidgetData[nScreen].gMenuItemMenuWidget );
+ gWidgetDefaultFlags[ (long)gWidgetData[nScreen].gMenuItemCheckMenuWidget ] = GTK_WIDGET_FLAGS( gWidgetData[nScreen].gMenuItemCheckMenuWidget );
+ gWidgetDefaultFlags[ (long)gWidgetData[nScreen].gMenuItemRadioMenuWidget ] = GTK_WIDGET_FLAGS( gWidgetData[nScreen].gMenuItemRadioMenuWidget );
+ gWidgetDefaultFlags[ (long)gWidgetData[nScreen].gImageMenuItem ] = GTK_WIDGET_FLAGS( gWidgetData[nScreen].gImageMenuItem );
+ }
+}
+
+static void NWEnsureGTKTooltip( int nScreen )
+{
+ if( !gWidgetData[nScreen].gTooltipPopup )
+ {
+ gWidgetData[nScreen].gTooltipPopup = gtk_window_new (GTK_WINDOW_POPUP);
+ GdkScreen* pScreen = gdk_display_get_screen( gdk_display_get_default(), nScreen );
+ if( pScreen )
+ gtk_window_set_screen( GTK_WINDOW(gWidgetData[nScreen].gTooltipPopup), pScreen );
+ gtk_widget_set_name( gWidgetData[nScreen].gTooltipPopup, "gtk-tooltips");
+ gtk_widget_realize( gWidgetData[nScreen].gTooltipPopup );
+ gtk_widget_ensure_style( gWidgetData[nScreen].gTooltipPopup );
+ }
+}
+
+static void NWEnsureGTKProgressBar( int nScreen )
+{
+ if( !gWidgetData[nScreen].gProgressBar )
+ {
+ gWidgetData[nScreen].gProgressBar = gtk_progress_bar_new ();
+ NWAddWidgetToCacheWindow( gWidgetData[nScreen].gProgressBar, nScreen );
+ }
+}
+
+static void NWEnsureGTKTreeView( int nScreen )
+{
+ if( !gWidgetData[nScreen].gTreeView )
+ {
+ gWidgetData[nScreen].gTreeView = gtk_tree_view_new ();
+ NWAddWidgetToCacheWindow( gWidgetData[nScreen].gTreeView, nScreen );
+ }
+}
+
+static void NWEnsureGTKSlider( int nScreen )
+{
+ if( !gWidgetData[nScreen].gHScale )
+ {
+ gWidgetData[nScreen].gHScale = gtk_hscale_new_with_range(0, 10, 1);
+ NWAddWidgetToCacheWindow( gWidgetData[nScreen].gHScale, nScreen );
+ }
+ if( !gWidgetData[nScreen].gVScale )
+ {
+ gWidgetData[nScreen].gVScale = gtk_vscale_new_with_range(0, 10, 1);
+ NWAddWidgetToCacheWindow( gWidgetData[nScreen].gVScale, nScreen );
+ }
+}
diff --git a/vcl/unx/gtk/window/gtkframe.cxx b/vcl/unx/gtk/window/gtkframe.cxx
new file mode 100644
index 000000000000..9181ee3fd40d
--- /dev/null
+++ b/vcl/unx/gtk/window/gtkframe.cxx
@@ -0,0 +1,3814 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <plugins/gtk/gtkframe.hxx>
+#include <plugins/gtk/gtkdata.hxx>
+#include <plugins/gtk/gtkinst.hxx>
+#include <plugins/gtk/gtkgdi.hxx>
+#include <vcl/keycodes.hxx>
+#include <wmadaptor.hxx>
+#include <sm.hxx>
+#include <salbmp.h>
+#include <salprn.h>
+#include <vcl/floatwin.hxx>
+#include <salprn.h>
+#include <vcl/svapp.hxx>
+#include <vcl/window.hxx>
+
+#include <tools/prex.h>
+#include <X11/Xatom.h>
+#include <tools/postx.h>
+
+#include <dlfcn.h>
+#include <vcl/salbtype.hxx>
+#include <vcl/bitmapex.hxx>
+#include <vcl/impbmp.hxx>
+#include <vcl/svids.hrc>
+
+#include <algorithm>
+
+#if OSL_DEBUG_LEVEL > 1
+#include <cstdio>
+#endif
+
+#include <com/sun/star/accessibility/XAccessibleContext.hpp>
+#include <com/sun/star/accessibility/AccessibleRole.hpp>
+#include <com/sun/star/accessibility/XAccessibleStateSet.hpp>
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+#include <com/sun/star/accessibility/XAccessibleEditableText.hpp>
+
+#ifdef ENABLE_DBUS
+#include <dbus/dbus-glib.h>
+
+#define GSM_DBUS_SERVICE "org.gnome.SessionManager"
+#define GSM_DBUS_PATH "/org/gnome/SessionManager"
+#define GSM_DBUS_INTERFACE "org.gnome.SessionManager"
+#endif
+
+// make compile on gtk older than 2.10
+#if GTK_MINOR_VERSION < 10
+#define GDK_SUPER_MASK (1 << 26)
+#define GDK_HYPER_MASK (1 << 27)
+#define GDK_META_MASK (1 << 28)
+#endif
+
+using namespace com::sun::star;
+
+int GtkSalFrame::m_nFloats = 0;
+
+static USHORT GetKeyModCode( guint state )
+{
+ USHORT nCode = 0;
+ if( (state & GDK_SHIFT_MASK) )
+ nCode |= KEY_SHIFT;
+ if( (state & GDK_CONTROL_MASK) )
+ nCode |= KEY_MOD1;
+ if( (state & GDK_MOD1_MASK) )
+ nCode |= KEY_MOD2;
+
+ // Map Meta/Super keys to MOD3 modifier on all Unix systems
+ // except Mac OS X
+ if ( (state & GDK_META_MASK ) || ( state & GDK_SUPER_MASK ) )
+ nCode |= KEY_MOD3;
+ return nCode;
+}
+
+static USHORT GetMouseModCode( guint state )
+{
+ USHORT nCode = GetKeyModCode( state );
+ if( (state & GDK_BUTTON1_MASK) )
+ nCode |= MOUSE_LEFT;
+ if( (state & GDK_BUTTON2_MASK) )
+ nCode |= MOUSE_MIDDLE;
+ if( (state & GDK_BUTTON3_MASK) )
+ nCode |= MOUSE_RIGHT;
+
+ return nCode;
+}
+
+static USHORT GetKeyCode( guint keyval )
+{
+ USHORT nCode = 0;
+ if( keyval >= GDK_0 && keyval <= GDK_9 )
+ nCode = KEY_0 + (keyval-GDK_0);
+ else if( keyval >= GDK_KP_0 && keyval <= GDK_KP_9 )
+ nCode = KEY_0 + (keyval-GDK_KP_0);
+ else if( keyval >= GDK_A && keyval <= GDK_Z )
+ nCode = KEY_A + (keyval-GDK_A );
+ else if( keyval >= GDK_a && keyval <= GDK_z )
+ nCode = KEY_A + (keyval-GDK_a );
+ else if( keyval >= GDK_F1 && keyval <= GDK_F26 )
+ {
+ if( GetX11SalData()->GetDisplay()->IsNumLockFromXS() )
+ {
+ nCode = KEY_F1 + (keyval-GDK_F1);
+ }
+ else
+ {
+ switch( keyval )
+ {
+ // - - - - - Sun keyboard, see vcl/unx/source/app/saldisp.cxx
+ case GDK_L2:
+ if( GetX11SalData()->GetDisplay()->GetServerVendor() == vendor_sun )
+ nCode = KEY_REPEAT;
+ else
+ nCode = KEY_F12;
+ break;
+ case GDK_L3: nCode = KEY_PROPERTIES; break;
+ case GDK_L4: nCode = KEY_UNDO; break;
+ case GDK_L6: nCode = KEY_COPY; break; // KEY_F16
+ case GDK_L8: nCode = KEY_PASTE; break; // KEY_F18
+ case GDK_L10: nCode = KEY_CUT; break; // KEY_F20
+ default:
+ nCode = KEY_F1 + (keyval-GDK_F1); break;
+ }
+ }
+ }
+ else
+ {
+ switch( keyval )
+ {
+ case GDK_KP_Down:
+ case GDK_Down: nCode = KEY_DOWN; break;
+ case GDK_KP_Up:
+ case GDK_Up: nCode = KEY_UP; break;
+ case GDK_KP_Left:
+ case GDK_Left: nCode = KEY_LEFT; break;
+ case GDK_KP_Right:
+ case GDK_Right: nCode = KEY_RIGHT; break;
+ case GDK_KP_Begin:
+ case GDK_KP_Home:
+ case GDK_Begin:
+ case GDK_Home: nCode = KEY_HOME; break;
+ case GDK_KP_End:
+ case GDK_End: nCode = KEY_END; break;
+ case GDK_KP_Page_Up:
+ case GDK_Page_Up: nCode = KEY_PAGEUP; break;
+ case GDK_KP_Page_Down:
+ case GDK_Page_Down: nCode = KEY_PAGEDOWN; break;
+ case GDK_KP_Enter:
+ case GDK_Return: nCode = KEY_RETURN; break;
+ case GDK_Escape: nCode = KEY_ESCAPE; break;
+ case GDK_ISO_Left_Tab:
+ case GDK_KP_Tab:
+ case GDK_Tab: nCode = KEY_TAB; break;
+ case GDK_BackSpace: nCode = KEY_BACKSPACE; break;
+ case GDK_KP_Space:
+ case GDK_space: nCode = KEY_SPACE; break;
+ case GDK_KP_Insert:
+ case GDK_Insert: nCode = KEY_INSERT; break;
+ case GDK_KP_Delete:
+ case GDK_Delete: nCode = KEY_DELETE; break;
+ case GDK_plus:
+ case GDK_KP_Add: nCode = KEY_ADD; break;
+ case GDK_minus:
+ case GDK_KP_Subtract: nCode = KEY_SUBTRACT; break;
+ case GDK_asterisk:
+ case GDK_KP_Multiply: nCode = KEY_MULTIPLY; break;
+ case GDK_slash:
+ case GDK_KP_Divide: nCode = KEY_DIVIDE; break;
+ case GDK_period:
+ case GDK_decimalpoint: nCode = KEY_POINT; break;
+ case GDK_comma: nCode = KEY_COMMA; break;
+ case GDK_less: nCode = KEY_LESS; break;
+ case GDK_greater: nCode = KEY_GREATER; break;
+ case GDK_KP_Equal:
+ case GDK_equal: nCode = KEY_EQUAL; break;
+ case GDK_Find: nCode = KEY_FIND; break;
+ case GDK_Menu: nCode = KEY_CONTEXTMENU;break;
+ case GDK_Help: nCode = KEY_HELP; break;
+ case GDK_Undo: nCode = KEY_UNDO; break;
+ case GDK_Redo: nCode = KEY_REPEAT; break;
+ case GDK_KP_Decimal:
+ case GDK_KP_Separator: nCode = KEY_DECIMAL; break;
+ case GDK_asciitilde: nCode = KEY_TILDE; break;
+ case GDK_leftsinglequotemark:
+ case GDK_quoteleft: nCode = KEY_QUOTELEFT; break;
+ // some special cases, also see saldisp.cxx
+ // - - - - - - - - - - - - - Apollo - - - - - - - - - - - - - 0x1000
+ case 0x1000FF02: // apXK_Copy
+ nCode = KEY_COPY;
+ break;
+ case 0x1000FF03: // apXK_Cut
+ nCode = KEY_CUT;
+ break;
+ case 0x1000FF04: // apXK_Paste
+ nCode = KEY_PASTE;
+ break;
+ case 0x1000FF14: // apXK_Repeat
+ nCode = KEY_REPEAT;
+ break;
+ // Exit, Save
+ // - - - - - - - - - - - - - - D E C - - - - - - - - - - - - - 0x1000
+ case 0x1000FF00:
+ nCode = KEY_DELETE;
+ break;
+ // - - - - - - - - - - - - - - H P - - - - - - - - - - - - - 0x1000
+ case 0x1000FF73: // hpXK_DeleteChar
+ nCode = KEY_DELETE;
+ break;
+ case 0x1000FF74: // hpXK_BackTab
+ case 0x1000FF75: // hpXK_KP_BackTab
+ nCode = KEY_TAB;
+ break;
+ // - - - - - - - - - - - - - - I B M - - - - - - - - - - - - -
+ // - - - - - - - - - - - - - - O S F - - - - - - - - - - - - - 0x1004
+ case 0x1004FF02: // osfXK_Copy
+ nCode = KEY_COPY;
+ break;
+ case 0x1004FF03: // osfXK_Cut
+ nCode = KEY_CUT;
+ break;
+ case 0x1004FF04: // osfXK_Paste
+ nCode = KEY_PASTE;
+ break;
+ case 0x1004FF07: // osfXK_BackTab
+ nCode = KEY_TAB;
+ break;
+ case 0x1004FF08: // osfXK_BackSpace
+ nCode = KEY_BACKSPACE;
+ break;
+ case 0x1004FF1B: // osfXK_Escape
+ nCode = KEY_ESCAPE;
+ break;
+ // Up, Down, Left, Right, PageUp, PageDown
+ // - - - - - - - - - - - - - - S C O - - - - - - - - - - - - -
+ // - - - - - - - - - - - - - - S G I - - - - - - - - - - - - - 0x1007
+ // - - - - - - - - - - - - - - S N I - - - - - - - - - - - - -
+ // - - - - - - - - - - - - - - S U N - - - - - - - - - - - - - 0x1005
+ case 0x1005FF10: // SunXK_F36
+ nCode = KEY_F11;
+ break;
+ case 0x1005FF11: // SunXK_F37
+ nCode = KEY_F12;
+ break;
+ case 0x1005FF70: // SunXK_Props
+ nCode = KEY_PROPERTIES;
+ break;
+ case 0x1005FF71: // SunXK_Front
+ nCode = KEY_FRONT;
+ break;
+ case 0x1005FF72: // SunXK_Copy
+ nCode = KEY_COPY;
+ break;
+ case 0x1005FF73: // SunXK_Open
+ nCode = KEY_OPEN;
+ break;
+ case 0x1005FF74: // SunXK_Paste
+ nCode = KEY_PASTE;
+ break;
+ case 0x1005FF75: // SunXK_Cut
+ nCode = KEY_CUT;
+ break;
+ }
+ }
+
+ return nCode;
+}
+
+// F10 means either KEY_F10 or KEY_MENU, which has to be decided
+// in the independent part.
+struct KeyAlternate
+{
+ USHORT nKeyCode;
+ sal_Unicode nCharCode;
+ KeyAlternate() : nKeyCode( 0 ), nCharCode( 0 ) {}
+ KeyAlternate( USHORT nKey, sal_Unicode nChar = 0 ) : nKeyCode( nKey ), nCharCode( nChar ) {}
+};
+
+inline KeyAlternate
+GetAlternateKeyCode( const USHORT nKeyCode )
+{
+ KeyAlternate aAlternate;
+
+ switch( nKeyCode )
+ {
+ case KEY_F10: aAlternate = KeyAlternate( KEY_MENU );break;
+ case KEY_F24: aAlternate = KeyAlternate( KEY_SUBTRACT, '-' );break;
+ }
+
+ return aAlternate;
+}
+
+void GtkSalFrame::doKeyCallback( guint state,
+ guint keyval,
+ guint16 hardware_keycode,
+ guint8 /*group*/,
+ guint32 time,
+ sal_Unicode aOrigCode,
+ bool bDown,
+ bool bSendRelease
+ )
+{
+ SalKeyEvent aEvent;
+
+ aEvent.mnTime = time;
+ aEvent.mnCharCode = aOrigCode;
+ aEvent.mnRepeat = 0;
+
+ vcl::DeletionListener aDel( this );
+ /* #i42122# translate all keys with Ctrl and/or Alt to group 0
+ * else shortcuts (e.g. Ctrl-o) will not work but be inserted by
+ * the application
+ */
+ /* #i52338# do this for all keys that the independent part has no key code for
+ */
+ aEvent.mnCode = GetKeyCode( keyval );
+ if( aEvent.mnCode == 0 )
+ {
+ // check other mapping
+ gint eff_group, level;
+ GdkModifierType consumed;
+ guint updated_keyval = 0;
+ // use gdk_keymap_get_default instead of NULL;
+ // workaround a crahs fixed in gtk 2.4
+ if( gdk_keymap_translate_keyboard_state( gdk_keymap_get_default(),
+ hardware_keycode,
+ (GdkModifierType)0,
+ 0,
+ &updated_keyval,
+ &eff_group,
+ &level,
+ &consumed ) )
+ {
+ aEvent.mnCode = GetKeyCode( updated_keyval );
+ }
+ }
+ aEvent.mnCode |= GetKeyModCode( state );
+
+ if( bDown )
+ {
+ bool bHandled = CallCallback( SALEVENT_KEYINPUT, &aEvent );
+ // #i46889# copy AlternatKeyCode handling from generic plugin
+ if( ! bHandled )
+ {
+ KeyAlternate aAlternate = GetAlternateKeyCode( aEvent.mnCode );
+ if( aAlternate.nKeyCode )
+ {
+ aEvent.mnCode = aAlternate.nKeyCode;
+ if( aAlternate.nCharCode )
+ aEvent.mnCharCode = aAlternate.nCharCode;
+ bHandled = CallCallback( SALEVENT_KEYINPUT, &aEvent );
+ }
+ }
+ if( bSendRelease && ! aDel.isDeleted() )
+ {
+ CallCallback( SALEVENT_KEYUP, &aEvent );
+ }
+ }
+ else
+ CallCallback( SALEVENT_KEYUP, &aEvent );
+}
+
+GtkSalFrame::GraphicsHolder::~GraphicsHolder()
+{
+ delete pGraphics;
+}
+
+GtkSalFrame::GtkSalFrame( SalFrame* pParent, ULONG nStyle )
+{
+ m_nScreen = getDisplay()->GetDefaultScreenNumber();
+ getDisplay()->registerFrame( this );
+ m_bDefaultPos = true;
+ m_bDefaultSize = ( (nStyle & SAL_FRAME_STYLE_SIZEABLE) && ! pParent );
+ m_bWindowIsGtkPlug = false;
+ Init( pParent, nStyle );
+}
+
+GtkSalFrame::GtkSalFrame( SystemParentData* pSysData )
+{
+ m_nScreen = getDisplay()->GetDefaultScreenNumber();
+ getDisplay()->registerFrame( this );
+ getDisplay()->setHaveSystemChildFrame();
+ m_bDefaultPos = true;
+ m_bDefaultSize = true;
+ Init( pSysData );
+}
+
+GtkSalFrame::~GtkSalFrame()
+{
+ for( unsigned int i = 0; i < sizeof(m_aGraphics)/sizeof(m_aGraphics[0]); ++i )
+ {
+ if( !m_aGraphics[i].pGraphics )
+ continue;
+ m_aGraphics[i].pGraphics->SetDrawable( None, m_nScreen );
+ m_aGraphics[i].bInUse = false;
+ }
+
+ if( m_pParent )
+ m_pParent->m_aChildren.remove( this );
+
+ getDisplay()->deregisterFrame( this );
+
+ if( m_pRegion )
+ gdk_region_destroy( m_pRegion );
+
+ if( m_hBackgroundPixmap )
+ {
+ XSetWindowBackgroundPixmap( getDisplay()->GetDisplay(),
+ GDK_WINDOW_XWINDOW(m_pWindow->window),
+ None );
+ XFreePixmap( getDisplay()->GetDisplay(), m_hBackgroundPixmap );
+ }
+
+ if( m_pIMHandler )
+ delete m_pIMHandler;
+
+ if( m_pFixedContainer )
+ gtk_widget_destroy( GTK_WIDGET(m_pFixedContainer) );
+ if( m_pWindow )
+ {
+ g_object_set_data( G_OBJECT( m_pWindow ), "SalFrame", NULL );
+ gtk_widget_destroy( m_pWindow );
+ }
+ if( m_pForeignParent )
+ g_object_unref( G_OBJECT(m_pForeignParent) );
+ if( m_pForeignTopLevel )
+ g_object_unref(G_OBJECT( m_pForeignTopLevel) );
+}
+
+void GtkSalFrame::moveWindow( long nX, long nY )
+{
+ if( isChild( false, true ) )
+ {
+ if( m_pParent )
+ gtk_fixed_move( m_pParent->getFixedContainer(),
+ m_pWindow,
+ nX - m_pParent->maGeometry.nX, nY - m_pParent->maGeometry.nY );
+ }
+ else
+ gtk_window_move( GTK_WINDOW(m_pWindow), nX, nY );
+}
+
+void GtkSalFrame::resizeWindow( long nWidth, long nHeight )
+{
+ if( isChild( false, true ) )
+ gtk_widget_set_size_request( m_pWindow, nWidth, nHeight );
+ else if( ! isChild( true, false ) )
+ gtk_window_resize( GTK_WINDOW(m_pWindow), nWidth, nHeight );
+}
+
+/*
+ * Always use a sub-class of GtkFixed we can tag for a11y. This allows us to
+ * utilize GAIL for the toplevel window and toolkit implementation incl.
+ * key event listener support ..
+ */
+
+GType
+ooo_fixed_get_type()
+{
+ static GType type = 0;
+
+ if (!type) {
+ static const GTypeInfo tinfo =
+ {
+ sizeof (GtkFixedClass),
+ (GBaseInitFunc) NULL, /* base init */
+ (GBaseFinalizeFunc) NULL, /* base finalize */
+ (GClassInitFunc) NULL, /* class init */
+ (GClassFinalizeFunc) NULL, /* class finalize */
+ NULL, /* class data */
+ sizeof (GtkFixed), /* instance size */
+ 0, /* nb preallocs */
+ (GInstanceInitFunc) NULL, /* instance init */
+ NULL /* value table */
+ };
+
+ type = g_type_register_static( GTK_TYPE_FIXED, "OOoFixed",
+ &tinfo, (GTypeFlags) 0);
+ }
+
+ return type;
+}
+
+void GtkSalFrame::updateScreenNumber()
+{
+ if( getDisplay()->IsXinerama() && getDisplay()->GetXineramaScreens().size() > 1 )
+ {
+ Point aPoint( maGeometry.nX, maGeometry.nY );
+ const std::vector<Rectangle>& rScreenRects( getDisplay()->GetXineramaScreens() );
+ size_t nScreens = rScreenRects.size();
+ for( size_t i = 0; i < nScreens; i++ )
+ {
+ if( rScreenRects[i].IsInside( aPoint ) )
+ {
+ maGeometry.nScreenNumber = static_cast<unsigned int>(i);
+ break;
+ }
+ }
+ }
+ else
+ maGeometry.nScreenNumber = static_cast<unsigned int>(m_nScreen);
+}
+
+void GtkSalFrame::InitCommon()
+{
+ // connect signals
+ g_signal_connect( G_OBJECT(m_pWindow), "style-set", G_CALLBACK(signalStyleSet), this );
+ g_signal_connect( G_OBJECT(m_pWindow), "button-press-event", G_CALLBACK(signalButton), this );
+ g_signal_connect( G_OBJECT(m_pWindow), "button-release-event", G_CALLBACK(signalButton), this );
+ g_signal_connect( G_OBJECT(m_pWindow), "expose-event", G_CALLBACK(signalExpose), this );
+ g_signal_connect( G_OBJECT(m_pWindow), "focus-in-event", G_CALLBACK(signalFocus), this );
+ g_signal_connect( G_OBJECT(m_pWindow), "focus-out-event", G_CALLBACK(signalFocus), this );
+ g_signal_connect( G_OBJECT(m_pWindow), "map-event", G_CALLBACK(signalMap), this );
+ g_signal_connect( G_OBJECT(m_pWindow), "unmap-event", G_CALLBACK(signalUnmap), this );
+ g_signal_connect( G_OBJECT(m_pWindow), "configure-event", G_CALLBACK(signalConfigure), this );
+ g_signal_connect( G_OBJECT(m_pWindow), "motion-notify-event", G_CALLBACK(signalMotion), this );
+ g_signal_connect( G_OBJECT(m_pWindow), "key-press-event", G_CALLBACK(signalKey), this );
+ g_signal_connect( G_OBJECT(m_pWindow), "key-release-event", G_CALLBACK(signalKey), this );
+ g_signal_connect( G_OBJECT(m_pWindow), "delete-event", G_CALLBACK(signalDelete), this );
+ g_signal_connect( G_OBJECT(m_pWindow), "window-state-event", G_CALLBACK(signalState), this );
+ g_signal_connect( G_OBJECT(m_pWindow), "scroll-event", G_CALLBACK(signalScroll), this );
+ g_signal_connect( G_OBJECT(m_pWindow), "leave-notify-event", G_CALLBACK(signalCrossing), this );
+ g_signal_connect( G_OBJECT(m_pWindow), "enter-notify-event", G_CALLBACK(signalCrossing), this );
+ g_signal_connect( G_OBJECT(m_pWindow), "visibility-notify-event", G_CALLBACK(signalVisibility), this );
+ g_signal_connect( G_OBJECT(m_pWindow), "destroy", G_CALLBACK(signalDestroy), this );
+
+ // init members
+ m_pCurrentCursor = NULL;
+ m_nKeyModifiers = 0;
+ m_bSingleAltPress = false;
+ m_bFullscreen = false;
+ m_nState = GDK_WINDOW_STATE_WITHDRAWN;
+ m_nVisibility = GDK_VISIBILITY_FULLY_OBSCURED;
+ m_bSendModChangeOnRelease = false;
+ m_pIMHandler = NULL;
+ m_hBackgroundPixmap = None;
+ m_nSavedScreenSaverTimeout = 0;
+ m_nGSMCookie = 0;
+ m_nExtStyle = 0;
+ m_pRegion = NULL;
+ m_ePointerStyle = 0xffff;
+ m_bSetFocusOnMap = false;
+
+ gtk_widget_set_app_paintable( m_pWindow, TRUE );
+ gtk_widget_set_double_buffered( m_pWindow, FALSE );
+ gtk_widget_set_redraw_on_allocate( m_pWindow, FALSE );
+ gtk_widget_add_events( m_pWindow,
+ GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
+ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK |
+ GDK_VISIBILITY_NOTIFY_MASK
+ );
+
+ // add the fixed container child,
+ // fixed is needed since we have to position plugin windows
+ m_pFixedContainer = GTK_FIXED(g_object_new( ooo_fixed_get_type(), NULL ));
+ gtk_container_add( GTK_CONTAINER(m_pWindow), GTK_WIDGET(m_pFixedContainer) );
+
+ // show the widgets
+ gtk_widget_show( GTK_WIDGET(m_pFixedContainer) );
+
+ // realize the window, we need an XWindow id
+ gtk_widget_realize( m_pWindow );
+
+ //system data
+ SalDisplay* pDisp = GetX11SalData()->GetDisplay();
+ m_aSystemData.nSize = sizeof( SystemChildData );
+ m_aSystemData.pDisplay = pDisp->GetDisplay();
+ m_aSystemData.aWindow = GDK_WINDOW_XWINDOW(m_pWindow->window);
+ m_aSystemData.pSalFrame = this;
+ m_aSystemData.pWidget = m_pWindow;
+ m_aSystemData.pVisual = pDisp->GetVisual( m_nScreen ).GetVisual();
+ m_aSystemData.nScreen = m_nScreen;
+ m_aSystemData.nDepth = pDisp->GetVisual( m_nScreen ).GetDepth();
+ m_aSystemData.aColormap = pDisp->GetColormap( m_nScreen ).GetXColormap();
+ m_aSystemData.pAppContext = NULL;
+ m_aSystemData.aShellWindow = m_aSystemData.aWindow;
+ m_aSystemData.pShellWidget = m_aSystemData.pWidget;
+
+
+ // fake an initial geometry, gets updated via configure event or SetPosSize
+ if( m_bDefaultPos || m_bDefaultSize )
+ {
+ Size aDefSize = calcDefaultSize();
+ maGeometry.nX = -1;
+ maGeometry.nY = -1;
+ maGeometry.nWidth = aDefSize.Width();
+ maGeometry.nHeight = aDefSize.Height();
+ if( m_pParent )
+ {
+ // approximation
+ maGeometry.nTopDecoration = m_pParent->maGeometry.nTopDecoration;
+ maGeometry.nBottomDecoration = m_pParent->maGeometry.nBottomDecoration;
+ maGeometry.nLeftDecoration = m_pParent->maGeometry.nLeftDecoration;
+ maGeometry.nRightDecoration = m_pParent->maGeometry.nRightDecoration;
+ }
+ else
+ {
+ maGeometry.nTopDecoration = 0;
+ maGeometry.nBottomDecoration = 0;
+ maGeometry.nLeftDecoration = 0;
+ maGeometry.nRightDecoration = 0;
+ }
+ }
+ else
+ {
+ resizeWindow( maGeometry.nWidth, maGeometry.nHeight );
+ moveWindow( maGeometry.nX, maGeometry.nY );
+ }
+ updateScreenNumber();
+
+ SetIcon(1);
+ m_nWorkArea = pDisp->getWMAdaptor()->getCurrentWorkArea();
+
+ /* #i64117# gtk sets a nice background pixmap
+ * but we actually don't really want that, so save
+ * some time on the Xserver as well as prevent
+ * some paint issues
+ */
+ XSetWindowBackgroundPixmap( getDisplay()->GetDisplay(),
+ GDK_WINDOW_XWINDOW(m_pWindow->window),
+ m_hBackgroundPixmap );
+}
+
+/* Sadly gtk_window_set_accept_focus exists only since gtk 2.4
+ * for achieving the same effect we will remove the WM_TAKE_FOCUS
+ * protocol from the window and set the input hint to false.
+ * But gtk_window_set_accept_focus needs to be called before
+ * window realization whereas the removal obviously can only happen
+ * after realization.
+ */
+
+extern "C" {
+ typedef void(*setAcceptFn)( GtkWindow*, gboolean );
+ static setAcceptFn p_gtk_window_set_accept_focus = NULL;
+ static bool bGetAcceptFocusFn = true;
+
+ typedef void(*setUserTimeFn)( GdkWindow*, guint32 );
+ static setUserTimeFn p_gdk_x11_window_set_user_time = NULL;
+ static bool bGetSetUserTimeFn = true;
+}
+
+static void lcl_set_accept_focus( GtkWindow* pWindow, gboolean bAccept, bool bBeforeRealize )
+{
+ if( bGetAcceptFocusFn )
+ {
+ bGetAcceptFocusFn = false;
+ p_gtk_window_set_accept_focus = (setAcceptFn)osl_getAsciiFunctionSymbol( GetSalData()->m_pPlugin, "gtk_window_set_accept_focus" );
+ }
+ if( p_gtk_window_set_accept_focus && bBeforeRealize )
+ p_gtk_window_set_accept_focus( pWindow, bAccept );
+ else if( ! bBeforeRealize )
+ {
+ Display* pDisplay = GetX11SalData()->GetDisplay()->GetDisplay();
+ XLIB_Window aWindow = GDK_WINDOW_XWINDOW( GTK_WIDGET(pWindow)->window );
+ XWMHints* pHints = XGetWMHints( pDisplay, aWindow );
+ if( ! pHints )
+ {
+ pHints = XAllocWMHints();
+ pHints->flags = 0;
+ }
+ pHints->flags |= InputHint;
+ pHints->input = bAccept ? True : False;
+ XSetWMHints( pDisplay, aWindow, pHints );
+ XFree( pHints );
+
+ if (GetX11SalData()->GetDisplay()->getWMAdaptor()->getWindowManagerName().EqualsAscii("compiz"))
+ return;
+
+ /* remove WM_TAKE_FOCUS protocol; this would usually be the
+ * right thing, but gtk handles it internally whereas we
+ * want to handle it ourselves (as to sometimes not get
+ * the focus)
+ */
+ Atom* pProtocols = NULL;
+ int nProtocols = 0;
+ XGetWMProtocols( pDisplay,
+ aWindow,
+ &pProtocols, &nProtocols );
+ if( pProtocols )
+ {
+ bool bSet = false;
+ Atom nTakeFocus = XInternAtom( pDisplay, "WM_TAKE_FOCUS", True );
+ if( nTakeFocus )
+ {
+ for( int i = 0; i < nProtocols; i++ )
+ {
+ if( pProtocols[i] == nTakeFocus )
+ {
+ for( int n = i; n < nProtocols-1; n++ )
+ pProtocols[n] = pProtocols[n+1];
+ nProtocols--;
+ i--;
+ bSet = true;
+ }
+ }
+ }
+ if( bSet )
+ XSetWMProtocols( pDisplay, aWindow, pProtocols, nProtocols );
+ XFree( pProtocols );
+ }
+ }
+}
+static void lcl_set_user_time( GdkWindow* i_pWindow, guint32 i_nTime )
+{
+ if( bGetSetUserTimeFn )
+ {
+ bGetSetUserTimeFn = false;
+ p_gdk_x11_window_set_user_time = (setUserTimeFn)osl_getAsciiFunctionSymbol( GetSalData()->m_pPlugin, "gdk_x11_window_set_user_time" );
+ }
+ if( p_gdk_x11_window_set_user_time )
+ p_gdk_x11_window_set_user_time( i_pWindow, i_nTime );
+ else
+ {
+ Display* pDisplay = GetX11SalData()->GetDisplay()->GetDisplay();
+ XLIB_Window aWindow = GDK_WINDOW_XWINDOW( i_pWindow );
+ Atom nUserTime = XInternAtom( pDisplay, "_NET_WM_USER_TIME", True );
+ if( nUserTime )
+ {
+ XChangeProperty( pDisplay, aWindow,
+ nUserTime, XA_CARDINAL, 32,
+ PropModeReplace, (unsigned char*)&i_nTime, 1 );
+ }
+ }
+};
+
+GtkSalFrame *GtkSalFrame::getFromWindow( GtkWindow *pWindow )
+{
+ return (GtkSalFrame *) g_object_get_data( G_OBJECT( pWindow ), "SalFrame" );
+}
+
+void GtkSalFrame::Init( SalFrame* pParent, ULONG nStyle )
+{
+ if( nStyle & SAL_FRAME_STYLE_DEFAULT ) // ensure default style
+ {
+ nStyle |= SAL_FRAME_STYLE_MOVEABLE | SAL_FRAME_STYLE_SIZEABLE | SAL_FRAME_STYLE_CLOSEABLE;
+ nStyle &= ~SAL_FRAME_STYLE_FLOAT;
+ }
+
+ m_pParent = static_cast<GtkSalFrame*>(pParent);
+ m_pForeignParent = NULL;
+ m_aForeignParentWindow = None;
+ m_pForeignTopLevel = NULL;
+ m_aForeignTopLevelWindow = None;
+ m_nStyle = nStyle;
+
+ GtkWindowType eWinType = ( (nStyle & SAL_FRAME_STYLE_FLOAT) &&
+ ! (nStyle & (SAL_FRAME_STYLE_OWNERDRAWDECORATION|
+ SAL_FRAME_STYLE_FLOAT_FOCUSABLE))
+ )
+ ? GTK_WINDOW_POPUP : GTK_WINDOW_TOPLEVEL;
+
+ if( nStyle & SAL_FRAME_STYLE_SYSTEMCHILD )
+ {
+ m_pWindow = gtk_event_box_new();
+ if( m_pParent )
+ {
+ // insert into container
+ gtk_fixed_put( m_pParent->getFixedContainer(),
+ m_pWindow, 0, 0 );
+
+ }
+ }
+ else
+ m_pWindow = gtk_widget_new( GTK_TYPE_WINDOW, "type", eWinType, "visible", FALSE, NULL );
+ g_object_set_data( G_OBJECT( m_pWindow ), "SalFrame", this );
+
+ // force wm class hint
+ m_nExtStyle = ~0;
+ SetExtendedFrameStyle( 0 );
+
+ if( m_pParent && m_pParent->m_pWindow && ! isChild() )
+ gtk_window_set_screen( GTK_WINDOW(m_pWindow), gtk_window_get_screen( GTK_WINDOW(m_pParent->m_pWindow) ) );
+
+ // set window type
+ bool bDecoHandling =
+ ! isChild() &&
+ ( ! (nStyle & SAL_FRAME_STYLE_FLOAT) ||
+ (nStyle & (SAL_FRAME_STYLE_OWNERDRAWDECORATION|SAL_FRAME_STYLE_FLOAT_FOCUSABLE) ) );
+
+ if( bDecoHandling )
+ {
+ bool bNoDecor = ! (nStyle & (SAL_FRAME_STYLE_MOVEABLE | SAL_FRAME_STYLE_SIZEABLE | SAL_FRAME_STYLE_CLOSEABLE ) );
+ GdkWindowTypeHint eType = GDK_WINDOW_TYPE_HINT_NORMAL;
+ if( (nStyle & SAL_FRAME_STYLE_DIALOG) && m_pParent != 0 )
+ eType = GDK_WINDOW_TYPE_HINT_DIALOG;
+ if( (nStyle & SAL_FRAME_STYLE_INTRO) )
+ {
+ gtk_window_set_role( GTK_WINDOW(m_pWindow), "splashscreen" );
+ eType = GDK_WINDOW_TYPE_HINT_SPLASHSCREEN;
+ }
+ else if( (nStyle & SAL_FRAME_STYLE_TOOLWINDOW ) )
+ {
+ eType = GDK_WINDOW_TYPE_HINT_UTILITY;
+ gtk_window_set_skip_taskbar_hint( GTK_WINDOW(m_pWindow), true );
+ }
+ else if( (nStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) )
+ {
+ eType = GDK_WINDOW_TYPE_HINT_TOOLBAR;
+ lcl_set_accept_focus( GTK_WINDOW(m_pWindow), FALSE, true );
+ bNoDecor = true;
+ }
+ else if( (nStyle & SAL_FRAME_STYLE_FLOAT_FOCUSABLE) )
+ {
+ eType = GDK_WINDOW_TYPE_HINT_UTILITY;
+ }
+
+ if( (nStyle & SAL_FRAME_STYLE_PARTIAL_FULLSCREEN )
+ && getDisplay()->getWMAdaptor()->isLegacyPartialFullscreen() )
+ {
+ eType = GDK_WINDOW_TYPE_HINT_TOOLBAR;
+ gtk_window_set_keep_above( GTK_WINDOW(m_pWindow), true );
+ }
+
+ gtk_window_set_type_hint( GTK_WINDOW(m_pWindow), eType );
+ if( bNoDecor )
+ gtk_window_set_decorated( GTK_WINDOW(m_pWindow), FALSE );
+ gtk_window_set_gravity( GTK_WINDOW(m_pWindow), GDK_GRAVITY_STATIC );
+ if( m_pParent && ! (m_pParent->m_nStyle & SAL_FRAME_STYLE_PLUG) )
+ gtk_window_set_transient_for( GTK_WINDOW(m_pWindow), GTK_WINDOW(m_pParent->m_pWindow) );
+ }
+ else if( (nStyle & SAL_FRAME_STYLE_FLOAT) )
+ {
+ gtk_window_set_type_hint( GTK_WINDOW(m_pWindow), GDK_WINDOW_TYPE_HINT_UTILITY );
+ }
+ if( m_pParent )
+ m_pParent->m_aChildren.push_back( this );
+
+ InitCommon();
+
+ if( eWinType == GTK_WINDOW_TOPLEVEL )
+ {
+ guint32 nUserTime = 0;
+ if( (nStyle & (SAL_FRAME_STYLE_OWNERDRAWDECORATION|SAL_FRAME_STYLE_TOOLWINDOW)) == 0 )
+ {
+ /* #i99360# ugly workaround an X11 library bug */
+ nUserTime= getDisplay()->GetLastUserEventTime( true );
+ // nUserTime = gdk_x11_get_server_time(GTK_WIDGET (m_pWindow)->window);
+ }
+ lcl_set_user_time(GTK_WIDGET(m_pWindow)->window, nUserTime);
+ }
+
+ if( bDecoHandling )
+ {
+ gtk_window_set_resizable( GTK_WINDOW(m_pWindow), (nStyle & SAL_FRAME_STYLE_SIZEABLE) ? TRUE : FALSE );
+ if( ( (nStyle & (SAL_FRAME_STYLE_OWNERDRAWDECORATION)) ) )
+ lcl_set_accept_focus( GTK_WINDOW(m_pWindow), FALSE, false );
+ }
+
+}
+
+GdkNativeWindow GtkSalFrame::findTopLevelSystemWindow( GdkNativeWindow aWindow )
+{
+ XLIB_Window aRoot, aParent;
+ XLIB_Window* pChildren;
+ unsigned int nChildren;
+ bool bBreak = false;
+ do
+ {
+ pChildren = NULL;
+ nChildren = 0;
+ aParent = aRoot = None;
+ XQueryTree( getDisplay()->GetDisplay(), aWindow,
+ &aRoot, &aParent, &pChildren, &nChildren );
+ XFree( pChildren );
+ if( aParent != aRoot )
+ aWindow = aParent;
+ int nCount = 0;
+ Atom* pProps = XListProperties( getDisplay()->GetDisplay(),
+ aWindow,
+ &nCount );
+ for( int i = 0; i < nCount && ! bBreak; ++i )
+ bBreak = (pProps[i] == XA_WM_HINTS);
+ if( pProps )
+ XFree( pProps );
+ } while( aParent != aRoot && ! bBreak );
+
+ return aWindow;
+}
+
+void GtkSalFrame::Init( SystemParentData* pSysData )
+{
+ m_pParent = NULL;
+ m_aForeignParentWindow = (GdkNativeWindow)pSysData->aWindow;
+ m_pForeignParent = NULL;
+ m_aForeignTopLevelWindow = findTopLevelSystemWindow( (GdkNativeWindow)pSysData->aWindow );
+ m_pForeignTopLevel = gdk_window_foreign_new_for_display( getGdkDisplay(), m_aForeignTopLevelWindow );
+ gdk_window_set_events( m_pForeignTopLevel, GDK_STRUCTURE_MASK );
+
+ if( pSysData->nSize > sizeof(pSysData->nSize)+sizeof(pSysData->aWindow) && pSysData->bXEmbedSupport )
+ {
+ m_pWindow = gtk_plug_new( pSysData->aWindow );
+ m_bWindowIsGtkPlug = true;
+ GTK_WIDGET_SET_FLAGS( m_pWindow, GTK_CAN_FOCUS | GTK_SENSITIVE | GTK_CAN_DEFAULT );
+ gtk_widget_set_sensitive( m_pWindow, true );
+ }
+ else
+ {
+ m_pWindow = gtk_window_new( GTK_WINDOW_POPUP );
+ m_bWindowIsGtkPlug = false;
+ }
+ m_nStyle = SAL_FRAME_STYLE_PLUG;
+ InitCommon();
+
+ m_pForeignParent = gdk_window_foreign_new_for_display( getGdkDisplay(), m_aForeignParentWindow );
+ gdk_window_set_events( m_pForeignParent, GDK_STRUCTURE_MASK );
+ int x_ret, y_ret;
+ unsigned int w, h, bw, d;
+ XLIB_Window aRoot;
+ XGetGeometry( getDisplay()->GetDisplay(), pSysData->aWindow,
+ &aRoot, &x_ret, &y_ret, &w, &h, &bw, &d );
+ maGeometry.nWidth = w;
+ maGeometry.nHeight = h;
+ gtk_window_resize( GTK_WINDOW(m_pWindow), w, h );
+ gtk_window_move( GTK_WINDOW(m_pWindow), 0, 0 );
+ if( ! m_bWindowIsGtkPlug )
+ {
+ XReparentWindow( getDisplay()->GetDisplay(),
+ GDK_WINDOW_XWINDOW(m_pWindow->window),
+ (XLIB_Window)pSysData->aWindow,
+ 0, 0 );
+ }
+}
+
+void GtkSalFrame::askForXEmbedFocus( sal_Int32 i_nTimeCode )
+{
+ XEvent aEvent;
+
+ rtl_zeroMemory( &aEvent, sizeof(aEvent) );
+ aEvent.xclient.window = m_aForeignParentWindow;
+ aEvent.xclient.type = ClientMessage;
+ aEvent.xclient.message_type = getDisplay()->getWMAdaptor()->getAtom( vcl_sal::WMAdaptor::XEMBED );
+ aEvent.xclient.format = 32;
+ aEvent.xclient.data.l[0] = i_nTimeCode ? i_nTimeCode : CurrentTime;
+ aEvent.xclient.data.l[1] = 3; // XEMBED_REQUEST_FOCUS
+ aEvent.xclient.data.l[2] = 0;
+ aEvent.xclient.data.l[3] = 0;
+ aEvent.xclient.data.l[4] = 0;
+
+ getDisplay()->GetXLib()->PushXErrorLevel( true );
+ XSendEvent( getDisplay()->GetDisplay(),
+ m_aForeignParentWindow,
+ False, NoEventMask, &aEvent );
+ XSync( getDisplay()->GetDisplay(), False );
+ getDisplay()->GetXLib()->PopXErrorLevel();
+}
+
+void GtkSalFrame::SetExtendedFrameStyle( SalExtStyle nStyle )
+{
+ if( nStyle != m_nExtStyle && ! isChild() )
+ {
+ m_nExtStyle = nStyle;
+ if( GTK_WIDGET_REALIZED( m_pWindow ) )
+ {
+ XClassHint* pClass = XAllocClassHint();
+ rtl::OString aResHint = X11SalData::getFrameResName( m_nExtStyle );
+ pClass->res_name = const_cast<char*>(aResHint.getStr());
+ pClass->res_class = const_cast<char*>(X11SalData::getFrameClassName());
+ XSetClassHint( getDisplay()->GetDisplay(),
+ GDK_WINDOW_XWINDOW(m_pWindow->window),
+ pClass );
+ XFree( pClass );
+ }
+ else
+ gtk_window_set_wmclass( GTK_WINDOW(m_pWindow),
+ X11SalData::getFrameResName( m_nExtStyle ),
+ X11SalData::getFrameClassName() );
+ }
+}
+
+
+SalGraphics* GtkSalFrame::GetGraphics()
+{
+ if( m_pWindow )
+ {
+ for( int i = 0; i < nMaxGraphics; i++ )
+ {
+ if( ! m_aGraphics[i].bInUse )
+ {
+ m_aGraphics[i].bInUse = true;
+ if( ! m_aGraphics[i].pGraphics )
+ {
+ m_aGraphics[i].pGraphics = new GtkSalGraphics( m_pWindow );
+ m_aGraphics[i].pGraphics->Init( this, GDK_WINDOW_XWINDOW(m_pWindow->window), m_nScreen );
+ }
+ return m_aGraphics[i].pGraphics;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+void GtkSalFrame::ReleaseGraphics( SalGraphics* pGraphics )
+{
+ for( int i = 0; i < nMaxGraphics; i++ )
+ {
+ if( m_aGraphics[i].pGraphics == pGraphics )
+ {
+ m_aGraphics[i].bInUse = false;
+ break;
+ }
+ }
+}
+
+BOOL GtkSalFrame::PostEvent( void* pData )
+{
+ getDisplay()->SendInternalEvent( this, pData );
+ return TRUE;
+}
+
+void GtkSalFrame::SetTitle( const String& rTitle )
+{
+ m_aTitle = rTitle;
+ if( m_pWindow && ! isChild() )
+ gtk_window_set_title( GTK_WINDOW(m_pWindow), rtl::OUStringToOString( rTitle, RTL_TEXTENCODING_UTF8 ).getStr() );
+}
+
+static inline BYTE *
+getRow( BitmapBuffer *pBuffer, ULONG nRow )
+{
+ if( BMP_SCANLINE_ADJUSTMENT( pBuffer->mnFormat ) == BMP_FORMAT_TOP_DOWN )
+ return pBuffer->mpBits + nRow * pBuffer->mnScanlineSize;
+ else
+ return pBuffer->mpBits + ( pBuffer->mnHeight - nRow - 1 ) * pBuffer->mnScanlineSize;
+}
+
+static GdkPixbuf *
+bitmapToPixbuf( SalBitmap *pSalBitmap, SalBitmap *pSalAlpha )
+{
+ g_return_val_if_fail( pSalBitmap != NULL, NULL );
+ g_return_val_if_fail( pSalAlpha != NULL, NULL );
+
+ BitmapBuffer *pBitmap = pSalBitmap->AcquireBuffer( TRUE );
+ g_return_val_if_fail( pBitmap != NULL, NULL );
+ g_return_val_if_fail( pBitmap->mnBitCount == 24, NULL );
+
+ BitmapBuffer *pAlpha = pSalAlpha->AcquireBuffer( TRUE );
+ g_return_val_if_fail( pAlpha != NULL, NULL );
+ g_return_val_if_fail( pAlpha->mnBitCount == 8, NULL );
+
+ Size aSize = pSalBitmap->GetSize();
+ g_return_val_if_fail( pSalAlpha->GetSize() == aSize, NULL );
+
+ int nX, nY;
+ guchar *pPixbufData = (guchar *)g_malloc (4 * aSize.Width() * aSize.Height() );
+ guchar *pDestData = pPixbufData;
+
+ for( nY = 0; nY < pBitmap->mnHeight; nY++ )
+ {
+ BYTE *pData = getRow( pBitmap, nY );
+ BYTE *pAlphaData = getRow( pAlpha, nY );
+
+ for( nX = 0; nX < pBitmap->mnWidth; nX++ )
+ {
+ if( pBitmap->mnFormat == BMP_FORMAT_24BIT_TC_BGR )
+ {
+ pDestData[2] = *pData++;
+ pDestData[1] = *pData++;
+ pDestData[0] = *pData++;
+ }
+ else // BMP_FORMAT_24BIT_TC_RGB
+ {
+ pDestData[0] = *pData++;
+ pDestData[1] = *pData++;
+ pDestData[2] = *pData++;
+ }
+ pDestData += 3;
+ *pDestData++ = 255 - *pAlphaData++;
+ }
+ }
+
+ pSalBitmap->ReleaseBuffer( pBitmap, TRUE );
+ pSalAlpha->ReleaseBuffer( pAlpha, TRUE );
+
+ return gdk_pixbuf_new_from_data( pPixbufData,
+ GDK_COLORSPACE_RGB, TRUE, 8,
+ aSize.Width(), aSize.Height(),
+ aSize.Width() * 4,
+ (GdkPixbufDestroyNotify) g_free,
+ NULL );
+}
+
+void GtkSalFrame::SetIcon( USHORT nIcon )
+{
+ if( (m_nStyle & (SAL_FRAME_STYLE_PLUG|SAL_FRAME_STYLE_SYSTEMCHILD|SAL_FRAME_STYLE_FLOAT|SAL_FRAME_STYLE_INTRO|SAL_FRAME_STYLE_OWNERDRAWDECORATION))
+ || ! m_pWindow )
+ return;
+
+ if( !ImplGetResMgr() )
+ return;
+
+ GdkPixbuf *pBuf;
+ GList *pIcons = NULL;
+
+ USHORT nOffsets[2] = { SV_ICON_SMALL_START, SV_ICON_LARGE_START };
+ USHORT nIndex;
+
+ // Use high contrast icons where appropriate
+ if( Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
+ {
+ nOffsets[0] = SV_ICON_LARGE_HC_START;
+ nOffsets[1] = SV_ICON_SMALL_HC_START;
+ }
+
+ for( nIndex = 0; nIndex < sizeof(nOffsets)/ sizeof(USHORT); nIndex++ )
+ {
+ // #i44723# workaround gcc temporary problem
+ ResId aResId( nOffsets[nIndex] + nIcon, *ImplGetResMgr() );
+ BitmapEx aIcon( aResId );
+
+ // #i81083# convert to 24bit/8bit alpha bitmap
+ Bitmap aBmp = aIcon.GetBitmap();
+ if( aBmp.GetBitCount() != 24 || ! aIcon.IsAlpha() )
+ {
+ if( aBmp.GetBitCount() != 24 )
+ aBmp.Convert( BMP_CONVERSION_24BIT );
+ AlphaMask aMask;
+ if( ! aIcon.IsAlpha() )
+ {
+ switch( aIcon.GetTransparentType() )
+ {
+ case TRANSPARENT_NONE:
+ {
+ BYTE nTrans = 0;
+ aMask = AlphaMask( aBmp.GetSizePixel(), &nTrans );
+ }
+ break;
+ case TRANSPARENT_COLOR:
+ aMask = AlphaMask( aBmp.CreateMask( aIcon.GetTransparentColor() ) );
+ break;
+ case TRANSPARENT_BITMAP:
+ aMask = AlphaMask( aIcon.GetMask() );
+ break;
+ default:
+ DBG_ERROR( "unhandled transparent type" );
+ break;
+ }
+ }
+ else
+ aMask = aIcon.GetAlpha();
+ aIcon = BitmapEx( aBmp, aMask );
+ }
+
+ ImpBitmap *pIconImpBitmap = aIcon.ImplGetBitmapImpBitmap();
+ ImpBitmap *pIconImpMask = aIcon.ImplGetMaskImpBitmap();
+
+
+ if( pIconImpBitmap && pIconImpMask )
+ {
+ SalBitmap *pIconBitmap =
+ pIconImpBitmap->ImplGetSalBitmap();
+ SalBitmap *pIconMask =
+ pIconImpMask->ImplGetSalBitmap();
+
+ if( ( pBuf = bitmapToPixbuf( pIconBitmap, pIconMask ) ) )
+ pIcons = g_list_prepend( pIcons, pBuf );
+ }
+ }
+
+ gtk_window_set_icon_list( GTK_WINDOW(m_pWindow), pIcons );
+
+ g_list_foreach( pIcons, (GFunc) g_object_unref, NULL );
+ g_list_free( pIcons );
+}
+
+void GtkSalFrame::SetMenu( SalMenu* )
+{
+}
+
+void GtkSalFrame::DrawMenuBar()
+{
+}
+
+void GtkSalFrame::Center()
+{
+ long nX, nY;
+
+ if( m_pParent )
+ {
+ nX = ((long)m_pParent->maGeometry.nWidth - (long)maGeometry.nWidth)/2;
+ nY = ((long)m_pParent->maGeometry.nHeight - (long)maGeometry.nHeight)/2;
+
+ }
+ else
+ {
+ long nScreenWidth, nScreenHeight;
+ long nScreenX = 0, nScreenY = 0;
+
+ Size aScreenSize = GetX11SalData()->GetDisplay()->GetScreenSize( m_nScreen );
+ nScreenWidth = aScreenSize.Width();
+ nScreenHeight = aScreenSize.Height();
+ if( GetX11SalData()->GetDisplay()->IsXinerama() )
+ {
+ // get xinerama screen we are on
+ // if there is a parent, use its center for screen determination
+ // else use the pointer
+ GdkScreen* pScreen;
+ gint x, y;
+ GdkModifierType aMask;
+ gdk_display_get_pointer( getGdkDisplay(), &pScreen, &x, &y, &aMask );
+
+ const std::vector< Rectangle >& rScreens = GetX11SalData()->GetDisplay()->GetXineramaScreens();
+ for( unsigned int i = 0; i < rScreens.size(); i++ )
+ if( rScreens[i].IsInside( Point( x, y ) ) )
+ {
+ nScreenX = rScreens[i].Left();
+ nScreenY = rScreens[i].Top();
+ nScreenWidth = rScreens[i].GetWidth();
+ nScreenHeight = rScreens[i].GetHeight();
+ break;
+ }
+ }
+ nX = nScreenX + (nScreenWidth - (long)maGeometry.nWidth)/2;
+ nY = nScreenY + (nScreenHeight - (long)maGeometry.nHeight)/2;
+ }
+ SetPosSize( nX, nY, 0, 0, SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y );
+}
+
+Size GtkSalFrame::calcDefaultSize()
+{
+ Size aScreenSize = GetX11SalData()->GetDisplay()->GetScreenSize( m_nScreen );
+ long w = aScreenSize.Width();
+ long h = aScreenSize.Height();
+
+ // fill in holy default values brought to us by product management
+ if( aScreenSize.Width() >= 800 )
+ w = 785;
+ if( aScreenSize.Width() >= 1024 )
+ w = 920;
+
+ if( aScreenSize.Height() >= 600 )
+ h = 550;
+ if( aScreenSize.Height() >= 768 )
+ h = 630;
+ if( aScreenSize.Height() >= 1024 )
+ h = 875;
+
+ return Size( w, h );
+}
+
+void GtkSalFrame::SetDefaultSize()
+{
+ Size aDefSize = calcDefaultSize();
+
+ SetPosSize( 0, 0, aDefSize.Width(), aDefSize.Height(),
+ SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT );
+
+ if( (m_nStyle & SAL_FRAME_STYLE_DEFAULT) && m_pWindow )
+ gtk_window_maximize( GTK_WINDOW(m_pWindow) );
+}
+
+static void initClientId()
+{
+ static bool bOnce = false;
+ if( ! bOnce )
+ {
+ bOnce = true;
+ const ByteString& rID = SessionManagerClient::getSessionID();
+ if( rID.Len() > 0 )
+ gdk_set_sm_client_id(rID.GetBuffer());
+ }
+}
+
+void GtkSalFrame::Show( BOOL bVisible, BOOL bNoActivate )
+{
+ if( m_pWindow )
+ {
+ if( m_pParent && (m_pParent->m_nStyle & SAL_FRAME_STYLE_PARTIAL_FULLSCREEN)
+ && getDisplay()->getWMAdaptor()->isLegacyPartialFullscreen() )
+ gtk_window_set_keep_above( GTK_WINDOW(m_pWindow), bVisible );
+ if( bVisible )
+ {
+ SessionManagerClient::open(); // will simply return after the first time
+ initClientId();
+ getDisplay()->startupNotificationCompleted();
+
+ if( m_bDefaultPos )
+ Center();
+ if( m_bDefaultSize )
+ SetDefaultSize();
+ setMinMaxSize();
+
+ // #i45160# switch to desktop where a dialog with parent will appear
+ if( m_pParent && m_pParent->m_nWorkArea != m_nWorkArea && GTK_WIDGET_MAPPED(m_pParent->m_pWindow) )
+ getDisplay()->getWMAdaptor()->switchToWorkArea( m_pParent->m_nWorkArea );
+
+ if( isFloatGrabWindow() &&
+ m_pParent &&
+ m_nFloats == 0 &&
+ ! getDisplay()->GetCaptureFrame() )
+ {
+ /* #i63086#
+ * outsmart Metacity's "focus:mouse" mode
+ * which insists on taking the focus from the document
+ * to the new float. Grab focus to parent frame BEFORE
+ * showing the float (cannot grab it to the float
+ * before show).
+ */
+ m_pParent->grabPointer( TRUE, TRUE );
+ }
+
+ guint32 nUserTime = 0;
+ if( ! bNoActivate && (m_nStyle & (SAL_FRAME_STYLE_OWNERDRAWDECORATION|SAL_FRAME_STYLE_TOOLWINDOW)) == 0 )
+ /* #i99360# ugly workaround an X11 library bug */
+ nUserTime= getDisplay()->GetLastUserEventTime( true );
+ //nUserTime = gdk_x11_get_server_time(GTK_WIDGET (m_pWindow)->window);
+
+ //For these floating windows we don't want the main window to lose focus, and metacity has...
+ // metacity-2.24.0/src/core/window.c
+ //
+ // if ((focus_window != NULL) && XSERVER_TIME_IS_BEFORE (compare, focus_window->net_wm_user_time))
+ // "compare" window focus prevented by other activity
+ //
+ // where "compare" is this window
+
+ // which leads to...
+
+ // /* This happens for error dialogs or alerts; these need to remain on
+ // * top, but it would be confusing to have its ancestor remain
+ // * focused.
+ // */
+ // if (meta_window_is_ancestor_of_transient (focus_window, window))
+ // "The focus window %s is an ancestor of the newly mapped "
+ // "window %s which isn't being focused. Unfocusing the "
+ // "ancestor.\n",
+ //
+ // i.e. having a time < that of the toplevel frame means that the toplevel frame gets unfocused.
+ // awesome.
+ if( nUserTime == 0 )
+ {
+ /* #i99360# ugly workaround an X11 library bug */
+ nUserTime= getDisplay()->GetLastUserEventTime( true );
+ //nUserTime = gdk_x11_get_server_time(GTK_WIDGET (m_pWindow)->window);
+ }
+ lcl_set_user_time( GTK_WIDGET(m_pWindow)->window, nUserTime );
+
+ if( ! bNoActivate && (m_nStyle & SAL_FRAME_STYLE_TOOLWINDOW) )
+ m_bSetFocusOnMap = true;
+
+ gtk_widget_show( m_pWindow );
+
+ if( isFloatGrabWindow() )
+ {
+ m_nFloats++;
+ if( ! getDisplay()->GetCaptureFrame() && m_nFloats == 1 )
+ grabPointer( TRUE, TRUE );
+ // #i44068# reset parent's IM context
+ if( m_pParent )
+ m_pParent->EndExtTextInput(0);
+ }
+ if( m_bWindowIsGtkPlug )
+ askForXEmbedFocus( 0 );
+ }
+ else
+ {
+ if( isFloatGrabWindow() )
+ {
+ m_nFloats--;
+ if( ! getDisplay()->GetCaptureFrame() && m_nFloats == 0)
+ grabPointer( FALSE );
+ }
+ gtk_widget_hide( m_pWindow );
+ if( m_pIMHandler )
+ m_pIMHandler->focusChanged( false );
+ // flush here; there may be a very seldom race between
+ // the display connection used for clipboard and our connection
+ Flush();
+ }
+ CallCallback( SALEVENT_RESIZE, NULL );
+ }
+}
+
+void GtkSalFrame::Enable( BOOL /*bEnable*/ )
+{
+ // Not implemented by X11SalFrame either
+}
+
+void GtkSalFrame::setMinMaxSize()
+{
+/* FIXME: for yet unknown reasons the reported size is a little smaller
+ * than the max size hint; one would guess that this was due to the border
+ * sizes of the widgets involved (GtkWindow and GtkFixed), but setting the
+ * their border to 0 (which is the default anyway) does not change the
+ * behaviour. Until the reason is known we'll add some pixels here.
+ */
+#define CONTAINER_ADJUSTMENT 6
+
+ /* #i34504# metacity (and possibly others) do not treat
+ * _NET_WM_STATE_FULLSCREEN and max_width/heigth independently;
+ * whether they should is undefined. So don't set the max size hint
+ * for a full screen window.
+ */
+ if( m_pWindow && ! isChild() )
+ {
+ GdkGeometry aGeo;
+ int aHints = 0;
+ if( m_nStyle & SAL_FRAME_STYLE_SIZEABLE )
+ {
+ if( m_aMinSize.Width() && m_aMinSize.Height() )
+ {
+ aGeo.min_width = m_aMinSize.Width()+CONTAINER_ADJUSTMENT;
+ aGeo.min_height = m_aMinSize.Height()+CONTAINER_ADJUSTMENT;
+ aHints |= GDK_HINT_MIN_SIZE;
+ }
+ if( m_aMaxSize.Width() && m_aMaxSize.Height() && ! m_bFullscreen )
+ {
+ aGeo.max_width = m_aMaxSize.Width()+CONTAINER_ADJUSTMENT;
+ aGeo.max_height = m_aMaxSize.Height()+CONTAINER_ADJUSTMENT;
+ aHints |= GDK_HINT_MAX_SIZE;
+ }
+ }
+ else
+ {
+ aGeo.min_width = maGeometry.nWidth;
+ aGeo.min_height = maGeometry.nHeight;
+ aHints |= GDK_HINT_MIN_SIZE;
+ if( ! m_bFullscreen )
+ {
+ aGeo.max_width = maGeometry.nWidth;
+ aGeo.max_height = maGeometry.nHeight;
+ aHints |= GDK_HINT_MAX_SIZE;
+ }
+ }
+ if( m_bFullscreen && m_aMaxSize.Width() && m_aMaxSize.Height() )
+ {
+ aGeo.max_width = m_aMaxSize.Width();
+ aGeo.max_height = m_aMaxSize.Height();
+ aHints |= GDK_HINT_MAX_SIZE;
+ }
+ if( aHints )
+ gtk_window_set_geometry_hints( GTK_WINDOW(m_pWindow),
+ NULL,
+ &aGeo,
+ GdkWindowHints( aHints ) );
+ }
+}
+
+void GtkSalFrame::SetMaxClientSize( long nWidth, long nHeight )
+{
+ if( ! isChild() )
+ {
+ m_aMaxSize = Size( nWidth, nHeight );
+ // Show does a setMinMaxSize
+ if( GTK_WIDGET_MAPPED( m_pWindow ) )
+ setMinMaxSize();
+ }
+}
+void GtkSalFrame::SetMinClientSize( long nWidth, long nHeight )
+{
+ if( ! isChild() )
+ {
+ m_aMinSize = Size( nWidth, nHeight );
+ if( m_pWindow )
+ {
+ gtk_widget_set_size_request( m_pWindow, nWidth, nHeight );
+ // Show does a setMinMaxSize
+ if( GTK_WIDGET_MAPPED( m_pWindow ) )
+ setMinMaxSize();
+ }
+ }
+}
+
+void GtkSalFrame::SetPosSize( long nX, long nY, long nWidth, long nHeight, USHORT nFlags )
+{
+ if( !m_pWindow || isChild( true, false ) )
+ return;
+
+ bool bSized = false, bMoved = false;
+
+ if( (nFlags & ( SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT )) &&
+ (nWidth > 0 && nHeight > 0 ) // sometimes stupid things happen
+ )
+ {
+ m_bDefaultSize = false;
+
+ if( (unsigned long)nWidth != maGeometry.nWidth || (unsigned long)nHeight != maGeometry.nHeight )
+ bSized = true;
+ maGeometry.nWidth = nWidth;
+ maGeometry.nHeight = nHeight;
+
+ if( isChild( false, true ) )
+ gtk_widget_set_size_request( m_pWindow, nWidth, nHeight );
+ else if( ! ( m_nState & GDK_WINDOW_STATE_MAXIMIZED ) )
+ gtk_window_resize( GTK_WINDOW(m_pWindow), nWidth, nHeight );
+ setMinMaxSize();
+ }
+ else if( m_bDefaultSize )
+ SetDefaultSize();
+
+ m_bDefaultSize = false;
+
+ if( nFlags & ( SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y ) )
+ {
+ if( m_pParent )
+ {
+ if( Application::GetSettings().GetLayoutRTL() )
+ nX = m_pParent->maGeometry.nWidth-maGeometry.nWidth-1-nX;
+ nX += m_pParent->maGeometry.nX;
+ nY += m_pParent->maGeometry.nY;
+ }
+
+ // adjust position to avoid off screen windows
+ // but allow toolbars to be positioned partly off screen by the user
+ Size aScreenSize = GetX11SalData()->GetDisplay()->GetScreenSize( m_nScreen );
+ if( ! (m_nStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) )
+ {
+ if( nX < (long)maGeometry.nLeftDecoration )
+ nX = maGeometry.nLeftDecoration;
+ if( nY < (long)maGeometry.nTopDecoration )
+ nY = maGeometry.nTopDecoration;
+ if( (nX + (long)maGeometry.nWidth + (long)maGeometry.nRightDecoration) > (long)aScreenSize.Width() )
+ nX = aScreenSize.Width() - maGeometry.nWidth - maGeometry.nRightDecoration;
+ if( (nY + (long)maGeometry.nHeight + (long)maGeometry.nBottomDecoration) > (long)aScreenSize.Height() )
+ nY = aScreenSize.Height() - maGeometry.nHeight - maGeometry.nBottomDecoration;
+ }
+ else
+ {
+ if( nX + (long)maGeometry.nWidth < 10 )
+ nX = 10 - (long)maGeometry.nWidth;
+ if( nY + (long)maGeometry.nHeight < 10 )
+ nY = 10 - (long)maGeometry.nHeight;
+ if( nX > (long)aScreenSize.Width() - 10 )
+ nX = (long)aScreenSize.Width() - 10;
+ if( nY > (long)aScreenSize.Height() - 10 )
+ nY = (long)aScreenSize.Height() - 10;
+ }
+
+ if( nX != maGeometry.nX || nY != maGeometry.nY )
+ bMoved = true;
+ maGeometry.nX = nX;
+ maGeometry.nY = nY;
+
+ m_bDefaultPos = false;
+
+ moveWindow( maGeometry.nX, maGeometry.nY );
+
+ updateScreenNumber();
+ }
+ else if( m_bDefaultPos )
+ Center();
+
+ m_bDefaultPos = false;
+
+ if( bSized && ! bMoved )
+ CallCallback( SALEVENT_RESIZE, NULL );
+ else if( bMoved && ! bSized )
+ CallCallback( SALEVENT_MOVE, NULL );
+ else if( bMoved && bSized )
+ CallCallback( SALEVENT_MOVERESIZE, NULL );
+}
+
+void GtkSalFrame::GetClientSize( long& rWidth, long& rHeight )
+{
+ if( m_pWindow && !(m_nState & GDK_WINDOW_STATE_ICONIFIED) )
+ {
+ rWidth = maGeometry.nWidth;
+ rHeight = maGeometry.nHeight;
+ }
+ else
+ rWidth = rHeight = 0;
+}
+
+void GtkSalFrame::GetWorkArea( Rectangle& rRect )
+{
+ rRect = GetX11SalData()->GetDisplay()->getWMAdaptor()->getWorkArea( 0 );
+}
+
+SalFrame* GtkSalFrame::GetParent() const
+{
+ return m_pParent;
+}
+
+void GtkSalFrame::SetWindowState( const SalFrameState* pState )
+{
+ if( ! m_pWindow || ! pState || isChild( true, false ) )
+ return;
+
+ const ULONG nMaxGeometryMask =
+ SAL_FRAMESTATE_MASK_X | SAL_FRAMESTATE_MASK_Y |
+ SAL_FRAMESTATE_MASK_WIDTH | SAL_FRAMESTATE_MASK_HEIGHT |
+ SAL_FRAMESTATE_MASK_MAXIMIZED_X | SAL_FRAMESTATE_MASK_MAXIMIZED_Y |
+ SAL_FRAMESTATE_MASK_MAXIMIZED_WIDTH | SAL_FRAMESTATE_MASK_MAXIMIZED_HEIGHT;
+
+ if( (pState->mnMask & SAL_FRAMESTATE_MASK_STATE) &&
+ ! ( m_nState & GDK_WINDOW_STATE_MAXIMIZED ) &&
+ (pState->mnState & SAL_FRAMESTATE_MAXIMIZED) &&
+ (pState->mnMask & nMaxGeometryMask) == nMaxGeometryMask )
+ {
+ resizeWindow( pState->mnWidth, pState->mnHeight );
+ moveWindow( pState->mnX, pState->mnY );
+ m_bDefaultPos = m_bDefaultSize = false;
+
+ maGeometry.nX = pState->mnMaximizedX;
+ maGeometry.nY = pState->mnMaximizedY;
+ maGeometry.nWidth = pState->mnMaximizedWidth;
+ maGeometry.nHeight = pState->mnMaximizedHeight;
+ updateScreenNumber();
+
+ m_nState = GdkWindowState( m_nState | GDK_WINDOW_STATE_MAXIMIZED );
+ m_aRestorePosSize = Rectangle( Point( pState->mnX, pState->mnY ),
+ Size( pState->mnWidth, pState->mnHeight ) );
+ }
+ else if( pState->mnMask & (SAL_FRAMESTATE_MASK_X | SAL_FRAMESTATE_MASK_Y |
+ SAL_FRAMESTATE_MASK_WIDTH | SAL_FRAMESTATE_MASK_HEIGHT ) )
+ {
+ USHORT nPosSizeFlags = 0;
+ long nX = pState->mnX - (m_pParent ? m_pParent->maGeometry.nX : 0);
+ long nY = pState->mnY - (m_pParent ? m_pParent->maGeometry.nY : 0);
+ long nWidth = pState->mnWidth;
+ long nHeight = pState->mnHeight;
+ if( pState->mnMask & SAL_FRAMESTATE_MASK_X )
+ nPosSizeFlags |= SAL_FRAME_POSSIZE_X;
+ else
+ nX = maGeometry.nX - (m_pParent ? m_pParent->maGeometry.nX : 0);
+ if( pState->mnMask & SAL_FRAMESTATE_MASK_Y )
+ nPosSizeFlags |= SAL_FRAME_POSSIZE_Y;
+ else
+ nY = maGeometry.nY - (m_pParent ? m_pParent->maGeometry.nY : 0);
+ if( pState->mnMask & SAL_FRAMESTATE_MASK_WIDTH )
+ nPosSizeFlags |= SAL_FRAME_POSSIZE_WIDTH;
+ else
+ nWidth = maGeometry.nWidth;
+ if( pState->mnMask & SAL_FRAMESTATE_MASK_HEIGHT )
+ nPosSizeFlags |= SAL_FRAME_POSSIZE_HEIGHT;
+ else
+ nHeight = maGeometry.nHeight;
+ SetPosSize( nX, nY, pState->mnWidth, pState->mnHeight, nPosSizeFlags );
+ }
+ if( pState->mnMask & SAL_FRAMESTATE_MASK_STATE && ! isChild() )
+ {
+ if( pState->mnState & SAL_FRAMESTATE_MAXIMIZED )
+ gtk_window_maximize( GTK_WINDOW(m_pWindow) );
+ else
+ gtk_window_unmaximize( GTK_WINDOW(m_pWindow) );
+ /* #i42379# there is no rollup state in GDK; and rolled up windows are
+ * (probably depending on the WM) reported as iconified. If we iconify a
+ * window here that was e.g. a dialog, then it will be unmapped but still
+ * not be displayed in the task list, so it's an iconified window that
+ * the user cannot get out of this state. So do not set the iconified state
+ * on windows with a parent (that is transient frames) since these tend
+ * to not be represented in an icon task list.
+ */
+ if( (pState->mnState & SAL_FRAMESTATE_MINIMIZED)
+ && ! m_pParent )
+ gtk_window_iconify( GTK_WINDOW(m_pWindow) );
+ else
+ gtk_window_deiconify( GTK_WINDOW(m_pWindow) );
+ }
+}
+
+BOOL GtkSalFrame::GetWindowState( SalFrameState* pState )
+{
+ pState->mnState = SAL_FRAMESTATE_NORMAL;
+ pState->mnMask = SAL_FRAMESTATE_MASK_STATE;
+ // rollup ? gtk 2.2 does not seem to support the shaded state
+ if( (m_nState & GDK_WINDOW_STATE_ICONIFIED) )
+ pState->mnState |= SAL_FRAMESTATE_MINIMIZED;
+ if( m_nState & GDK_WINDOW_STATE_MAXIMIZED )
+ {
+ pState->mnState |= SAL_FRAMESTATE_MAXIMIZED;
+ pState->mnX = m_aRestorePosSize.Left();
+ pState->mnY = m_aRestorePosSize.Top();
+ pState->mnWidth = m_aRestorePosSize.GetWidth();
+ pState->mnHeight = m_aRestorePosSize.GetHeight();
+ pState->mnMaximizedX = maGeometry.nX;
+ pState->mnMaximizedY = maGeometry.nY;
+ pState->mnMaximizedWidth = maGeometry.nWidth;
+ pState->mnMaximizedHeight = maGeometry.nHeight;
+ pState->mnMask |= SAL_FRAMESTATE_MASK_MAXIMIZED_X |
+ SAL_FRAMESTATE_MASK_MAXIMIZED_Y |
+ SAL_FRAMESTATE_MASK_MAXIMIZED_WIDTH |
+ SAL_FRAMESTATE_MASK_MAXIMIZED_HEIGHT;
+ }
+ else
+ {
+
+ pState->mnX = maGeometry.nX;
+ pState->mnY = maGeometry.nY;
+ pState->mnWidth = maGeometry.nWidth;
+ pState->mnHeight = maGeometry.nHeight;
+ }
+ pState->mnMask |= SAL_FRAMESTATE_MASK_X |
+ SAL_FRAMESTATE_MASK_Y |
+ SAL_FRAMESTATE_MASK_WIDTH |
+ SAL_FRAMESTATE_MASK_HEIGHT;
+
+ return TRUE;
+}
+
+void GtkSalFrame::moveToScreen( int nScreen )
+{
+ if( isChild() )
+ return;
+
+ if( nScreen < 0 || nScreen >= gdk_display_get_n_screens( getGdkDisplay() ) )
+ nScreen = m_nScreen;
+ if( nScreen == m_nScreen )
+ return;
+
+ GdkScreen* pScreen = gdk_display_get_screen( getGdkDisplay(), nScreen );
+ if( pScreen )
+ {
+ m_nScreen = nScreen;
+ gtk_window_set_screen( GTK_WINDOW(m_pWindow), pScreen );
+ // realize the window, we need an XWindow id
+ gtk_widget_realize( m_pWindow );
+ // update system data
+ GtkSalDisplay* pDisp = getDisplay();
+ m_aSystemData.aWindow = GDK_WINDOW_XWINDOW(m_pWindow->window);
+ m_aSystemData.pVisual = pDisp->GetVisual( m_nScreen ).GetVisual();
+ m_aSystemData.nScreen = nScreen;
+ m_aSystemData.nDepth = pDisp->GetVisual( m_nScreen ).GetDepth();
+ m_aSystemData.aColormap = pDisp->GetColormap( m_nScreen ).GetXColormap();
+ m_aSystemData.pAppContext = NULL;
+ m_aSystemData.aShellWindow = m_aSystemData.aWindow;
+ // update graphics if necessary
+ for( unsigned int i = 0; i < sizeof(m_aGraphics)/sizeof(m_aGraphics[0]); i++ )
+ {
+ if( m_aGraphics[i].bInUse )
+ m_aGraphics[i].pGraphics->SetDrawable( GDK_WINDOW_XWINDOW(m_pWindow->window), m_nScreen );
+ }
+ updateScreenNumber();
+ }
+
+ if( m_pParent && m_pParent->m_nScreen != m_nScreen )
+ SetParent( NULL );
+ std::list< GtkSalFrame* > aChildren = m_aChildren;
+ for( std::list< GtkSalFrame* >::iterator it = aChildren.begin(); it != aChildren.end(); ++it )
+ (*it)->moveToScreen( m_nScreen );
+
+ // FIXME: SalObjects
+}
+
+void GtkSalFrame::SetScreenNumber( unsigned int nNewScreen )
+{
+ if( nNewScreen == maGeometry.nScreenNumber )
+ return;
+
+ if( m_pWindow && ! isChild() )
+ {
+ GtkSalDisplay* pDisp = getDisplay();
+ if( pDisp->IsXinerama() && pDisp->GetXineramaScreens().size() > 1 )
+ {
+ if( nNewScreen >= pDisp->GetXineramaScreens().size() )
+ return;
+
+ Rectangle aOldScreenRect( pDisp->GetXineramaScreens()[maGeometry.nScreenNumber] );
+ Rectangle aNewScreenRect( pDisp->GetXineramaScreens()[nNewScreen] );
+ bool bVisible = GTK_WIDGET_MAPPED(m_pWindow);
+ if( bVisible )
+ Show( FALSE );
+ maGeometry.nX = aNewScreenRect.Left() + (maGeometry.nX - aOldScreenRect.Left());
+ maGeometry.nY = aNewScreenRect.Top() + (maGeometry.nY - aOldScreenRect.Top());
+ createNewWindow( None, false, m_nScreen );
+ gtk_window_move( GTK_WINDOW(m_pWindow), maGeometry.nX, maGeometry.nY );
+ if( bVisible )
+ Show( TRUE );
+ maGeometry.nScreenNumber = nNewScreen;
+ }
+ else if( sal_Int32(nNewScreen) < pDisp->GetScreenCount() )
+ {
+ moveToScreen( (int)nNewScreen );
+ maGeometry.nScreenNumber = nNewScreen;
+ gtk_window_move( GTK_WINDOW(m_pWindow), maGeometry.nX, maGeometry.nY );
+ }
+ }
+}
+
+void GtkSalFrame::ShowFullScreen( BOOL bFullScreen, sal_Int32 nScreen )
+{
+ if( m_pWindow && ! isChild() )
+ {
+ GtkSalDisplay* pDisp = getDisplay();
+ // xinerama ?
+ if( pDisp->IsXinerama() && pDisp->GetXineramaScreens().size() > 1 )
+ {
+ if( bFullScreen )
+ {
+ m_aRestorePosSize = Rectangle( Point( maGeometry.nX, maGeometry.nY ),
+ Size( maGeometry.nWidth, maGeometry.nHeight ) );
+ bool bVisible = GTK_WIDGET_MAPPED(m_pWindow);
+ if( bVisible )
+ Show( FALSE );
+ m_nStyle |= SAL_FRAME_STYLE_PARTIAL_FULLSCREEN;
+ createNewWindow( None, false, m_nScreen );
+ Rectangle aNewPosSize;
+ if( nScreen < 0 || nScreen >= static_cast<int>(pDisp->GetXineramaScreens().size()) )
+ aNewPosSize = Rectangle( Point( 0, 0 ), pDisp->GetScreenSize(m_nScreen) );
+ else
+ aNewPosSize = pDisp->GetXineramaScreens()[ nScreen ];
+ gtk_window_resize( GTK_WINDOW(m_pWindow),
+ maGeometry.nWidth = aNewPosSize.GetWidth(),
+ maGeometry.nHeight = aNewPosSize.GetHeight() );
+ gtk_window_move( GTK_WINDOW(m_pWindow),
+ maGeometry.nX = aNewPosSize.Left(),
+ maGeometry.nY = aNewPosSize.Top() );
+ // #i110881# for the benefit of compiz set a max size here
+ // else setting to fullscreen fails for unknown reasons
+ m_aMaxSize.Width() = aNewPosSize.GetWidth()+100;
+ m_aMaxSize.Height() = aNewPosSize.GetHeight()+100;
+ // workaround different legacy version window managers have different opinions about
+ // _NET_WM_STATE_FULLSCREEN (Metacity <-> KWin)
+ if( ! getDisplay()->getWMAdaptor()->isLegacyPartialFullscreen() )
+ {
+ if( !(m_nStyle & SAL_FRAME_STYLE_SIZEABLE) )
+ gtk_window_set_resizable( GTK_WINDOW(m_pWindow), TRUE );
+ gtk_window_fullscreen( GTK_WINDOW( m_pWindow ) );
+ }
+ if( bVisible )
+ Show( TRUE );
+ }
+ else
+ {
+ bool bVisible = GTK_WIDGET_MAPPED(m_pWindow);
+ if( ! getDisplay()->getWMAdaptor()->isLegacyPartialFullscreen() )
+ gtk_window_unfullscreen( GTK_WINDOW(m_pWindow) );
+ if( bVisible )
+ Show( FALSE );
+ m_nStyle &= ~SAL_FRAME_STYLE_PARTIAL_FULLSCREEN;
+ createNewWindow( None, false, m_nScreen );
+ if( ! m_aRestorePosSize.IsEmpty() )
+ {
+ gtk_window_resize( GTK_WINDOW(m_pWindow),
+ maGeometry.nWidth = m_aRestorePosSize.GetWidth(),
+ maGeometry.nHeight = m_aRestorePosSize.GetHeight() );
+ gtk_window_move( GTK_WINDOW(m_pWindow),
+ maGeometry.nX = m_aRestorePosSize.Left(),
+ maGeometry.nY = m_aRestorePosSize.Top() );
+ m_aRestorePosSize = Rectangle();
+ }
+ if( bVisible )
+ Show( TRUE );
+ }
+ }
+ else
+ {
+ if( bFullScreen )
+ {
+ if( !(m_nStyle & SAL_FRAME_STYLE_SIZEABLE) )
+ gtk_window_set_resizable( GTK_WINDOW(m_pWindow), TRUE );
+ gtk_window_fullscreen( GTK_WINDOW(m_pWindow) );
+ moveToScreen( nScreen );
+ Size aScreenSize = pDisp->GetScreenSize( m_nScreen );
+ maGeometry.nX = 0;
+ maGeometry.nY = 0;
+ maGeometry.nWidth = aScreenSize.Width();
+ maGeometry.nHeight = aScreenSize.Height();
+ }
+ else
+ {
+ gtk_window_unfullscreen( GTK_WINDOW(m_pWindow) );
+ if( !(m_nStyle & SAL_FRAME_STYLE_SIZEABLE) )
+ gtk_window_set_resizable( GTK_WINDOW(m_pWindow), FALSE );
+ moveToScreen( nScreen );
+ }
+ }
+ m_bDefaultPos = m_bDefaultSize = false;
+ updateScreenNumber();
+ CallCallback( SALEVENT_MOVERESIZE, NULL );
+ }
+ m_bFullscreen = bFullScreen;
+}
+
+/* definitions from xautolock.c (pl15) */
+#define XAUTOLOCK_DISABLE 1
+#define XAUTOLOCK_ENABLE 2
+
+void GtkSalFrame::setAutoLock( bool bLock )
+{
+ if( isChild() )
+ return;
+
+ GdkScreen *pScreen = gtk_window_get_screen( GTK_WINDOW(m_pWindow) );
+ GdkDisplay *pDisplay = gdk_screen_get_display( pScreen );
+ GdkWindow *pRootWin = gdk_screen_get_root_window( pScreen );
+
+ Atom nAtom = XInternAtom( GDK_DISPLAY_XDISPLAY( pDisplay ),
+ "XAUTOLOCK_MESSAGE", False );
+
+ int nMessage = bLock ? XAUTOLOCK_ENABLE : XAUTOLOCK_DISABLE;
+
+ XChangeProperty( GDK_DISPLAY_XDISPLAY( pDisplay ),
+ GDK_WINDOW_XID( pRootWin ),
+ nAtom, XA_INTEGER,
+ 8, PropModeReplace,
+ (unsigned char*)&nMessage,
+ sizeof( nMessage ) );
+}
+
+#ifdef ENABLE_DBUS
+/** cookie is returned as an unsigned integer */
+static guint
+dbus_inhibit_gsm (const gchar *appname,
+ const gchar *reason,
+ guint xid)
+{
+ gboolean res;
+ guint cookie;
+ GError *error = NULL;
+ DBusGProxy *proxy = NULL;
+ DBusGConnection *session_connection = NULL;
+
+ /* get the DBUS session connection */
+ session_connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
+ if (error != NULL) {
+ g_warning ("DBUS cannot connect : %s", error->message);
+ g_error_free (error);
+ return -1;
+ }
+
+ /* get the proxy with gnome-session-manager */
+ proxy = dbus_g_proxy_new_for_name (session_connection,
+ GSM_DBUS_SERVICE,
+ GSM_DBUS_PATH,
+ GSM_DBUS_INTERFACE);
+ if (proxy == NULL) {
+ g_warning ("Could not get DBUS proxy: %s", GSM_DBUS_SERVICE);
+ return -1;
+ }
+
+ res = dbus_g_proxy_call (proxy,
+ "Inhibit", &error,
+ G_TYPE_STRING, appname,
+ G_TYPE_UINT, xid,
+ G_TYPE_STRING, reason,
+ G_TYPE_UINT, 8, //Inhibit the session being marked as idle
+ G_TYPE_INVALID,
+ G_TYPE_UINT, &cookie,
+ G_TYPE_INVALID);
+
+ /* check the return value */
+ if (! res) {
+ cookie = -1;
+ g_warning ("Inhibit method failed");
+ }
+
+ /* check the error value */
+ if (error != NULL) {
+ g_warning ("Inhibit problem : %s", error->message);
+ g_error_free (error);
+ cookie = -1;
+ }
+
+ g_object_unref (G_OBJECT (proxy));
+ return cookie;
+}
+
+static void
+dbus_uninhibit_gsm (guint cookie)
+{
+ gboolean res;
+ GError *error = NULL;
+ DBusGProxy *proxy = NULL;
+ DBusGConnection *session_connection = NULL;
+
+ if (cookie == guint(-1)) {
+ g_warning ("Invalid cookie");
+ return;
+ }
+
+ /* get the DBUS session connection */
+ session_connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
+ if (error) {
+ g_warning ("DBUS cannot connect : %s", error->message);
+ g_error_free (error);
+ return;
+ }
+
+ /* get the proxy with gnome-session-manager */
+ proxy = dbus_g_proxy_new_for_name (session_connection,
+ GSM_DBUS_SERVICE,
+ GSM_DBUS_PATH,
+ GSM_DBUS_INTERFACE);
+ if (proxy == NULL) {
+ g_warning ("Could not get DBUS proxy: %s", GSM_DBUS_SERVICE);
+ return;
+ }
+
+ res = dbus_g_proxy_call (proxy,
+ "Uninhibit",
+ &error,
+ G_TYPE_UINT, cookie,
+ G_TYPE_INVALID,
+ G_TYPE_INVALID);
+
+ /* check the return value */
+ if (! res) {
+ g_warning ("Uninhibit method failed");
+ }
+
+ /* check the error value */
+ if (error != NULL) {
+ g_warning ("Uninhibit problem : %s", error->message);
+ g_error_free (error);
+ cookie = -1;
+ }
+ g_object_unref (G_OBJECT (proxy));
+}
+#endif
+
+void GtkSalFrame::StartPresentation( BOOL bStart )
+{
+ Display *pDisplay = GDK_DISPLAY_XDISPLAY( getGdkDisplay() );
+
+ setAutoLock( !bStart );
+
+ int nTimeout, nInterval, bPreferBlanking, bAllowExposures;
+
+ XGetScreenSaver( pDisplay, &nTimeout, &nInterval,
+ &bPreferBlanking, &bAllowExposures );
+ if( bStart )
+ {
+ if ( nTimeout )
+ {
+ m_nSavedScreenSaverTimeout = nTimeout;
+ XResetScreenSaver( pDisplay );
+ XSetScreenSaver( pDisplay, 0, nInterval,
+ bPreferBlanking, bAllowExposures );
+ }
+#ifdef ENABLE_DBUS
+ m_nGSMCookie = dbus_inhibit_gsm(g_get_application_name(), "presentation",
+ GDK_WINDOW_XID(m_pWindow->window));
+#endif
+ }
+ else
+ {
+ if( m_nSavedScreenSaverTimeout )
+ XSetScreenSaver( pDisplay, m_nSavedScreenSaverTimeout,
+ nInterval, bPreferBlanking,
+ bAllowExposures );
+ m_nSavedScreenSaverTimeout = 0;
+#ifdef ENABLE_DBUS
+ dbus_uninhibit_gsm(m_nGSMCookie);
+#endif
+ }
+}
+
+void GtkSalFrame::SetAlwaysOnTop( BOOL /*bOnTop*/ )
+{
+}
+
+void GtkSalFrame::ToTop( USHORT nFlags )
+{
+ if( m_pWindow )
+ {
+ if( isChild( false, true ) )
+ gtk_widget_grab_focus( m_pWindow );
+ else if( GTK_WIDGET_MAPPED( m_pWindow ) )
+ {
+ if( ! (nFlags & SAL_FRAME_TOTOP_GRABFOCUS_ONLY) )
+ gtk_window_present( GTK_WINDOW(m_pWindow) );
+ else
+ {
+ // gdk_window_focus( m_pWindow->window, gdk_x11_get_server_time(GTK_WIDGET (m_pWindow)->window) );
+ /* #i99360# ugly workaround an X11 library bug */
+ guint32 nUserTime= getDisplay()->GetLastUserEventTime( true );
+ gdk_window_focus( m_pWindow->window, nUserTime );
+ }
+ /* need to do an XSetInputFocus here because
+ * gdk_window_focus will ask a EWMH compliant WM to put the focus
+ * to our window - which it of course won't since our input hint
+ * is set to false.
+ */
+ if( (m_nStyle & (SAL_FRAME_STYLE_OWNERDRAWDECORATION|SAL_FRAME_STYLE_FLOAT_FOCUSABLE)) )
+ {
+ // sad but true: this can cause an XError, we need to catch that
+ // to do this we need to synchronize with the XServer
+ getDisplay()->GetXLib()->PushXErrorLevel( true );
+ XSetInputFocus( getDisplay()->GetDisplay(), GDK_WINDOW_XWINDOW( m_pWindow->window ), RevertToParent, CurrentTime );
+ XSync( getDisplay()->GetDisplay(), False );
+ getDisplay()->GetXLib()->PopXErrorLevel();
+ }
+ }
+ else
+ {
+ if( nFlags & SAL_FRAME_TOTOP_RESTOREWHENMIN )
+ gtk_window_present( GTK_WINDOW(m_pWindow) );
+ }
+ }
+}
+
+void GtkSalFrame::SetPointer( PointerStyle ePointerStyle )
+{
+ if( m_pWindow && ePointerStyle != m_ePointerStyle )
+ {
+ m_ePointerStyle = ePointerStyle;
+ GdkCursor *pCursor = getDisplay()->getCursor( ePointerStyle );
+ gdk_window_set_cursor( m_pWindow->window, pCursor );
+ m_pCurrentCursor = pCursor;
+
+ // #i80791# use grabPointer the same way as CaptureMouse, respective float grab
+ if( getDisplay()->MouseCaptured( this ) )
+ grabPointer( TRUE, FALSE );
+ else if( m_nFloats > 0 )
+ grabPointer( TRUE, TRUE );
+ }
+}
+
+void GtkSalFrame::grabPointer( BOOL bGrab, BOOL bOwnerEvents )
+{
+ if( m_pWindow )
+ {
+ if( bGrab )
+ {
+ bool bUseGdkGrab = true;
+ if( getDisplay()->getHaveSystemChildFrame() )
+ {
+ const std::list< SalFrame* >& rFrames = getDisplay()->getFrames();
+ for( std::list< SalFrame* >::const_iterator it = rFrames.begin(); it != rFrames.end(); ++it )
+ {
+ const GtkSalFrame* pFrame = static_cast< const GtkSalFrame* >(*it);
+ if( pFrame->m_bWindowIsGtkPlug )
+ {
+ bUseGdkGrab = false;
+ break;
+ }
+ }
+ }
+ if( bUseGdkGrab )
+ {
+ const int nMask = ( GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK );
+
+ gdk_pointer_grab( m_pWindow->window, bOwnerEvents,
+ (GdkEventMask) nMask, NULL, m_pCurrentCursor,
+ GDK_CURRENT_TIME );
+ }
+ else
+ {
+ // FIXME: for some unknown reason gdk_pointer_grab does not
+ // really produce owner events for GtkPlug windows
+ // the cause is yet unknown
+ //
+ // this is of course a bad hack, especially as we cannot
+ // set the right cursor this way
+ XGrabPointer( getDisplay()->GetDisplay(),
+ GDK_WINDOW_XWINDOW( m_pWindow->window),
+ bOwnerEvents,
+ PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
+ GrabModeAsync,
+ GrabModeAsync,
+ None,
+ None,
+ CurrentTime
+ );
+
+ }
+ }
+ else
+ {
+ // Two GdkDisplays may be open
+ gdk_display_pointer_ungrab( getGdkDisplay(), GDK_CURRENT_TIME);
+ }
+ }
+}
+
+void GtkSalFrame::CaptureMouse( BOOL bCapture )
+{
+ getDisplay()->CaptureMouse( bCapture ? this : NULL );
+}
+
+void GtkSalFrame::SetPointerPos( long nX, long nY )
+{
+ GtkSalFrame* pFrame = this;
+ while( pFrame && pFrame->isChild( false, true ) )
+ pFrame = pFrame->m_pParent;
+ if( ! pFrame )
+ return;
+
+ GdkScreen *pScreen = gtk_window_get_screen( GTK_WINDOW(pFrame->m_pWindow) );
+ GdkDisplay *pDisplay = gdk_screen_get_display( pScreen );
+
+ /* #87921# when the application tries to center the mouse in the dialog the
+ * window isn't mapped already. So use coordinates relative to the root window.
+ */
+ unsigned int nWindowLeft = maGeometry.nX + nX;
+ unsigned int nWindowTop = maGeometry.nY + nY;
+
+ XWarpPointer( GDK_DISPLAY_XDISPLAY (pDisplay), None,
+ GDK_WINDOW_XID (gdk_screen_get_root_window( pScreen ) ),
+ 0, 0, 0, 0, nWindowLeft, nWindowTop);
+ // #i38648# ask for the next motion hint
+ gint x, y;
+ GdkModifierType mask;
+ gdk_window_get_pointer( pFrame->m_pWindow->window, &x, &y, &mask );
+}
+
+void GtkSalFrame::Flush()
+{
+#ifdef HAVE_A_RECENT_GTK
+ gdk_display_flush( getGdkDisplay() );
+#else
+ XFlush (GDK_DISPLAY_XDISPLAY (getGdkDisplay()));
+#endif
+}
+
+void GtkSalFrame::Sync()
+{
+ gdk_display_sync( getGdkDisplay() );
+}
+
+String GtkSalFrame::GetSymbolKeyName( const String&, USHORT nKeyCode )
+{
+ return getDisplay()->GetKeyName( nKeyCode );
+}
+
+String GtkSalFrame::GetKeyName( USHORT nKeyCode )
+{
+ return getDisplay()->GetKeyName( nKeyCode );
+}
+
+GdkDisplay *GtkSalFrame::getGdkDisplay()
+{
+ return static_cast<GtkSalDisplay*>(GetX11SalData()->GetDisplay())->GetGdkDisplay();
+}
+
+GtkSalDisplay *GtkSalFrame::getDisplay()
+{
+ return static_cast<GtkSalDisplay*>(GetX11SalData()->GetDisplay());
+}
+
+SalFrame::SalPointerState GtkSalFrame::GetPointerState()
+{
+ SalPointerState aState;
+ GdkScreen* pScreen;
+ gint x, y;
+ GdkModifierType aMask;
+ gdk_display_get_pointer( getGdkDisplay(), &pScreen, &x, &y, &aMask );
+ aState.maPos = Point( x - maGeometry.nX, y - maGeometry.nY );
+ aState.mnState = GetMouseModCode( aMask );
+ return aState;
+}
+
+void GtkSalFrame::SetInputContext( SalInputContext* pContext )
+{
+ if( ! pContext )
+ return;
+
+ if( ! (pContext->mnOptions & SAL_INPUTCONTEXT_TEXT) )
+ return;
+
+ // create a new im context
+ if( ! m_pIMHandler )
+ m_pIMHandler = new IMHandler( this );
+ m_pIMHandler->setInputContext( pContext );
+}
+
+void GtkSalFrame::EndExtTextInput( USHORT nFlags )
+{
+ if( m_pIMHandler )
+ m_pIMHandler->endExtTextInput( nFlags );
+}
+
+BOOL GtkSalFrame::MapUnicodeToKeyCode( sal_Unicode , LanguageType , KeyCode& )
+{
+ // not supported yet
+ return FALSE;
+}
+
+LanguageType GtkSalFrame::GetInputLanguage()
+{
+ return LANGUAGE_DONTKNOW;
+}
+
+SalBitmap* GtkSalFrame::SnapShot()
+{
+ if( !m_pWindow )
+ return NULL;
+
+ X11SalBitmap *pBmp = new X11SalBitmap;
+ GdkWindow *pWin = m_pWindow->window;
+ if( pBmp->SnapShot( GDK_DISPLAY_XDISPLAY( getGdkDisplay() ),
+ GDK_WINDOW_XID( pWin ) ) )
+ return pBmp;
+ else
+ delete pBmp;
+
+ return NULL;
+}
+
+void GtkSalFrame::UpdateSettings( AllSettings& rSettings )
+{
+ if( ! m_pWindow )
+ return;
+
+ GtkSalGraphics* pGraphics = static_cast<GtkSalGraphics*>(m_aGraphics[0].pGraphics);
+ bool bFreeGraphics = false;
+ if( ! pGraphics )
+ {
+ pGraphics = static_cast<GtkSalGraphics*>(GetGraphics());
+ bFreeGraphics = true;
+ }
+
+ pGraphics->updateSettings( rSettings );
+
+ if( bFreeGraphics )
+ ReleaseGraphics( pGraphics );
+}
+
+void GtkSalFrame::Beep( SoundType eType )
+{
+ switch( eType )
+ {
+ case SOUND_DEFAULT:
+ case SOUND_ERROR:
+ gdk_display_beep( getGdkDisplay() );
+ break;
+ default:
+ break;
+ }
+}
+
+const SystemEnvData* GtkSalFrame::GetSystemData() const
+{
+ return &m_aSystemData;
+}
+
+void GtkSalFrame::SetParent( SalFrame* pNewParent )
+{
+ if( m_pParent )
+ m_pParent->m_aChildren.remove( this );
+ m_pParent = static_cast<GtkSalFrame*>(pNewParent);
+ if( m_pParent )
+ m_pParent->m_aChildren.push_back( this );
+ if( ! isChild() )
+ gtk_window_set_transient_for( GTK_WINDOW(m_pWindow),
+ (m_pParent && ! m_pParent->isChild(true,false)) ? GTK_WINDOW(m_pParent->m_pWindow) : NULL
+ );
+}
+
+void GtkSalFrame::createNewWindow( XLIB_Window aNewParent, bool bXEmbed, int nScreen )
+{
+ bool bWasVisible = GTK_WIDGET_MAPPED(m_pWindow);
+ if( bWasVisible )
+ Show( FALSE );
+
+ if( nScreen < 0 || nScreen >= getDisplay()->GetScreenCount() )
+ nScreen = m_nScreen;
+
+ SystemParentData aParentData;
+ aParentData.aWindow = aNewParent;
+ aParentData.bXEmbedSupport = bXEmbed;
+ if( aNewParent == None )
+ {
+ aNewParent = getDisplay()->GetRootWindow(nScreen);
+ aParentData.aWindow = None;
+ aParentData.bXEmbedSupport = false;
+ }
+ else
+ {
+ // is new parent a root window ?
+ Display* pDisp = getDisplay()->GetDisplay();
+ int nScreens = getDisplay()->GetScreenCount();
+ for( int i = 0; i < nScreens; i++ )
+ {
+ if( aNewParent == RootWindow( pDisp, i ) )
+ {
+ nScreen = i;
+ aParentData.aWindow = None;
+ aParentData.bXEmbedSupport = false;
+ break;
+ }
+ }
+ }
+
+ // free xrender resources
+ for( unsigned int i = 0; i < sizeof(m_aGraphics)/sizeof(m_aGraphics[0]); i++ )
+ if( m_aGraphics[i].bInUse )
+ m_aGraphics[i].pGraphics->SetDrawable( None, m_nScreen );
+
+ // first deinit frame
+ if( m_pIMHandler )
+ {
+ delete m_pIMHandler;
+ m_pIMHandler = NULL;
+ }
+ if( m_pRegion )
+ gdk_region_destroy( m_pRegion );
+ if( m_pFixedContainer )
+ gtk_widget_destroy( GTK_WIDGET(m_pFixedContainer) );
+ if( m_pWindow )
+ gtk_widget_destroy( m_pWindow );
+ if( m_pForeignParent )
+ g_object_unref( G_OBJECT(m_pForeignParent) );
+ if( m_pForeignTopLevel )
+ g_object_unref( G_OBJECT(m_pForeignTopLevel) );
+
+ // init new window
+ m_bDefaultPos = m_bDefaultSize = false;
+ if( aParentData.aWindow != None )
+ {
+ m_nStyle |= SAL_FRAME_STYLE_PLUG;
+ Init( &aParentData );
+ }
+ else
+ {
+ m_nStyle &= ~SAL_FRAME_STYLE_PLUG;
+ Init( (m_pParent && m_pParent->m_nScreen == m_nScreen) ? m_pParent : NULL, m_nStyle );
+ }
+
+ // update graphics
+ for( unsigned int i = 0; i < sizeof(m_aGraphics)/sizeof(m_aGraphics[0]); i++ )
+ {
+ if( m_aGraphics[i].bInUse )
+ {
+ m_aGraphics[i].pGraphics->SetDrawable( GDK_WINDOW_XWINDOW(m_pWindow->window), m_nScreen );
+ m_aGraphics[i].pGraphics->SetWindow( m_pWindow );
+ }
+ }
+
+ if( m_aTitle.Len() )
+ SetTitle( m_aTitle );
+
+ if( bWasVisible )
+ Show( TRUE );
+
+ std::list< GtkSalFrame* > aChildren = m_aChildren;
+ m_aChildren.clear();
+ for( std::list< GtkSalFrame* >::iterator it = aChildren.begin(); it != aChildren.end(); ++it )
+ (*it)->createNewWindow( None, false, m_nScreen );
+
+ // FIXME: SalObjects
+}
+
+bool GtkSalFrame::SetPluginParent( SystemParentData* pSysParent )
+{
+ if( pSysParent ) // this may be the first system child frame now
+ getDisplay()->setHaveSystemChildFrame();
+ createNewWindow( pSysParent->aWindow, (pSysParent->nSize > sizeof(long)) ? pSysParent->bXEmbedSupport : false, m_nScreen );
+ return true;
+}
+
+void GtkSalFrame::ResetClipRegion()
+{
+ if( m_pWindow )
+ gdk_window_shape_combine_region( m_pWindow->window, NULL, 0, 0 );
+}
+
+void GtkSalFrame::BeginSetClipRegion( ULONG )
+{
+ if( m_pRegion )
+ gdk_region_destroy( m_pRegion );
+ m_pRegion = gdk_region_new();
+}
+
+void GtkSalFrame::UnionClipRegion( long nX, long nY, long nWidth, long nHeight )
+{
+ if( m_pRegion )
+ {
+ GdkRectangle aRect;
+ aRect.x = nX;
+ aRect.y = nY;
+ aRect.width = nWidth;
+ aRect.height = nHeight;
+
+ gdk_region_union_with_rect( m_pRegion, &aRect );
+ }
+}
+
+void GtkSalFrame::EndSetClipRegion()
+{
+ if( m_pWindow && m_pRegion )
+ gdk_window_shape_combine_region( m_pWindow->window, m_pRegion, 0, 0 );
+}
+
+bool GtkSalFrame::Dispatch( const XEvent* pEvent )
+{
+ bool bContinueDispatch = true;
+
+ if( pEvent->type == PropertyNotify )
+ {
+ vcl_sal::WMAdaptor* pAdaptor = getDisplay()->getWMAdaptor();
+ Atom nDesktopAtom = pAdaptor->getAtom( vcl_sal::WMAdaptor::NET_WM_DESKTOP );
+ if( pEvent->xproperty.atom == nDesktopAtom &&
+ pEvent->xproperty.state == PropertyNewValue )
+ {
+ m_nWorkArea = pAdaptor->getWindowWorkArea( GDK_WINDOW_XWINDOW( m_pWindow->window) );
+ }
+ }
+ else if( pEvent->type == ConfigureNotify )
+ {
+ if( m_pForeignParent && pEvent->xconfigure.window == m_aForeignParentWindow )
+ {
+ bContinueDispatch = false;
+ gtk_window_resize( GTK_WINDOW(m_pWindow), pEvent->xconfigure.width, pEvent->xconfigure.height );
+ if( ( sal::static_int_cast< int >(maGeometry.nWidth) !=
+ pEvent->xconfigure.width ) ||
+ ( sal::static_int_cast< int >(maGeometry.nHeight) !=
+ pEvent->xconfigure.height ) )
+ {
+ maGeometry.nWidth = pEvent->xconfigure.width;
+ maGeometry.nHeight = pEvent->xconfigure.height;
+ setMinMaxSize();
+ getDisplay()->SendInternalEvent( this, NULL, SALEVENT_RESIZE );
+ }
+ }
+ else if( m_pForeignTopLevel && pEvent->xconfigure.window == m_aForeignTopLevelWindow )
+ {
+ bContinueDispatch = false;
+ // update position
+ int x = 0, y = 0;
+ XLIB_Window aChild;
+ XTranslateCoordinates( getDisplay()->GetDisplay(),
+ GDK_WINDOW_XWINDOW( m_pWindow->window),
+ getDisplay()->GetRootWindow( getDisplay()->GetDefaultScreenNumber() ),
+ 0, 0,
+ &x, &y,
+ &aChild );
+ if( x != maGeometry.nX || y != maGeometry.nY )
+ {
+ maGeometry.nX = x;
+ maGeometry.nY = y;
+ getDisplay()->SendInternalEvent( this, NULL, SALEVENT_MOVE );
+ }
+ }
+ }
+ else if( pEvent->type == ClientMessage &&
+ pEvent->xclient.message_type == getDisplay()->getWMAdaptor()->getAtom( vcl_sal::WMAdaptor::XEMBED ) &&
+ pEvent->xclient.window == GDK_WINDOW_XWINDOW(m_pWindow->window) &&
+ m_bWindowIsGtkPlug
+ )
+ {
+ // FIXME: this should not be necessary, GtkPlug should do this
+ // transparently for us
+ if( pEvent->xclient.data.l[1] == 1 || // XEMBED_WINDOW_ACTIVATE
+ pEvent->xclient.data.l[1] == 2 // XEMBED_WINDOW_DEACTIVATE
+ )
+ {
+ GdkEventFocus aEvent;
+ aEvent.type = GDK_FOCUS_CHANGE;
+ aEvent.window = m_pWindow->window;
+ aEvent.send_event = TRUE;
+ aEvent.in = (pEvent->xclient.data.l[1] == 1);
+ signalFocus( m_pWindow, &aEvent, this );
+ }
+ }
+
+ return bContinueDispatch;
+}
+
+void GtkSalFrame::SetBackgroundBitmap( SalBitmap* pBitmap )
+{
+ if( m_hBackgroundPixmap )
+ {
+ XSetWindowBackgroundPixmap( getDisplay()->GetDisplay(),
+ GDK_WINDOW_XWINDOW(m_pWindow->window),
+ None );
+ XFreePixmap( getDisplay()->GetDisplay(), m_hBackgroundPixmap );
+ m_hBackgroundPixmap = None;
+ }
+ if( pBitmap )
+ {
+ X11SalBitmap* pBM = static_cast<X11SalBitmap*>(pBitmap);
+ Size aSize = pBM->GetSize();
+ if( aSize.Width() && aSize.Height() )
+ {
+ m_hBackgroundPixmap =
+ XCreatePixmap( getDisplay()->GetDisplay(),
+ GDK_WINDOW_XWINDOW(m_pWindow->window),
+ aSize.Width(),
+ aSize.Height(),
+ getDisplay()->GetVisual(m_nScreen).GetDepth() );
+ if( m_hBackgroundPixmap )
+ {
+ SalTwoRect aTwoRect;
+ aTwoRect.mnSrcX = aTwoRect.mnSrcY = aTwoRect.mnDestX = aTwoRect.mnDestY = 0;
+ aTwoRect.mnSrcWidth = aTwoRect.mnDestWidth = aSize.Width();
+ aTwoRect.mnSrcHeight = aTwoRect.mnDestHeight = aSize.Height();
+ pBM->ImplDraw( m_hBackgroundPixmap,
+ m_nScreen,
+ getDisplay()->GetVisual(m_nScreen).GetDepth(),
+ aTwoRect,
+ getDisplay()->GetCopyGC(m_nScreen) );
+ XSetWindowBackgroundPixmap( getDisplay()->GetDisplay(),
+ GDK_WINDOW_XWINDOW(m_pWindow->window),
+ m_hBackgroundPixmap );
+ }
+ }
+ }
+}
+
+gboolean GtkSalFrame::signalButton( GtkWidget*, GdkEventButton* pEvent, gpointer frame )
+{
+ GtkSalFrame* pThis = (GtkSalFrame*)frame;
+ SalMouseEvent aEvent;
+ USHORT nEventType = 0;
+ switch( pEvent->type )
+ {
+ case GDK_BUTTON_PRESS:
+ nEventType = SALEVENT_MOUSEBUTTONDOWN;
+ break;
+ case GDK_BUTTON_RELEASE:
+ nEventType = SALEVENT_MOUSEBUTTONUP;
+ break;
+ default:
+ return FALSE;
+ }
+ switch( pEvent->button )
+ {
+ case 1: aEvent.mnButton = MOUSE_LEFT; break;
+ case 2: aEvent.mnButton = MOUSE_MIDDLE; break;
+ case 3: aEvent.mnButton = MOUSE_RIGHT; break;
+ default: return FALSE;
+ }
+ aEvent.mnTime = pEvent->time;
+ aEvent.mnX = (long)pEvent->x_root - pThis->maGeometry.nX;
+ aEvent.mnY = (long)pEvent->y_root - pThis->maGeometry.nY;
+ aEvent.mnCode = GetMouseModCode( pEvent->state );
+
+ bool bClosePopups = false;
+ if( pEvent->type == GDK_BUTTON_PRESS &&
+ (pThis->m_nStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) == 0
+ )
+ {
+ if( m_nFloats > 0 )
+ {
+ // close popups if user clicks outside our application
+ gint x, y;
+ bClosePopups = (gdk_display_get_window_at_pointer( pThis->getGdkDisplay(), &x, &y ) == NULL);
+ }
+ /* #i30306# release implicit pointer grab if no popups are open; else
+ * Drag cannot grab the pointer and will fail.
+ */
+ if( m_nFloats < 1 || bClosePopups )
+ gdk_display_pointer_ungrab( pThis->getGdkDisplay(), GDK_CURRENT_TIME );
+ }
+
+ GTK_YIELD_GRAB();
+
+ if( pThis->m_bWindowIsGtkPlug &&
+ pEvent->type == GDK_BUTTON_PRESS &&
+ pEvent->button == 1 )
+ {
+ pThis->askForXEmbedFocus( pEvent->time );
+ }
+
+ // --- RTL --- (mirror mouse pos)
+ if( Application::GetSettings().GetLayoutRTL() )
+ aEvent.mnX = pThis->maGeometry.nWidth-1-aEvent.mnX;
+
+ vcl::DeletionListener aDel( pThis );
+
+ pThis->CallCallback( nEventType, &aEvent );
+
+ if( ! aDel.isDeleted() )
+ {
+ if( bClosePopups )
+ {
+ ImplSVData* pSVData = ImplGetSVData();
+ if ( pSVData->maWinData.mpFirstFloat )
+ {
+ static const char* pEnv = getenv( "SAL_FLOATWIN_NOAPPFOCUSCLOSE" );
+ if ( !(pSVData->maWinData.mpFirstFloat->GetPopupModeFlags() & FLOATWIN_POPUPMODE_NOAPPFOCUSCLOSE) && !(pEnv && *pEnv) )
+ pSVData->maWinData.mpFirstFloat->EndPopupMode( FLOATWIN_POPUPMODEEND_CANCEL | FLOATWIN_POPUPMODEEND_CLOSEALL );
+ }
+ }
+
+ if( ! aDel.isDeleted() )
+ {
+ int frame_x = (int)(pEvent->x_root - pEvent->x);
+ int frame_y = (int)(pEvent->y_root - pEvent->y);
+ if( frame_x != pThis->maGeometry.nX || frame_y != pThis->maGeometry.nY )
+ {
+ pThis->maGeometry.nX = frame_x;
+ pThis->maGeometry.nY = frame_y;
+ pThis->CallCallback( SALEVENT_MOVE, NULL );
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+gboolean GtkSalFrame::signalScroll( GtkWidget*, GdkEvent* pEvent, gpointer frame )
+{
+ GtkSalFrame* pThis = (GtkSalFrame*)frame;
+ GdkEventScroll* pSEvent = (GdkEventScroll*)pEvent;
+
+ static ULONG nLines = 0;
+ if( ! nLines )
+ {
+ char* pEnv = getenv( "SAL_WHEELLINES" );
+ nLines = pEnv ? atoi( pEnv ) : 3;
+ if( nLines > 10 )
+ nLines = SAL_WHEELMOUSE_EVENT_PAGESCROLL;
+ }
+
+ bool bNeg = (pSEvent->direction == GDK_SCROLL_DOWN || pSEvent->direction == GDK_SCROLL_RIGHT );
+ SalWheelMouseEvent aEvent;
+ aEvent.mnTime = pSEvent->time;
+ aEvent.mnX = (ULONG)pSEvent->x;
+ aEvent.mnY = (ULONG)pSEvent->y;
+ aEvent.mnDelta = bNeg ? -120 : 120;
+ aEvent.mnNotchDelta = bNeg ? -1 : 1;
+ aEvent.mnScrollLines = nLines;
+ aEvent.mnCode = GetMouseModCode( pSEvent->state );
+ aEvent.mbHorz = (pSEvent->direction == GDK_SCROLL_LEFT || pSEvent->direction == GDK_SCROLL_RIGHT);
+
+ GTK_YIELD_GRAB();
+
+ // --- RTL --- (mirror mouse pos)
+ if( Application::GetSettings().GetLayoutRTL() )
+ aEvent.mnX = pThis->maGeometry.nWidth-1-aEvent.mnX;
+
+ pThis->CallCallback( SALEVENT_WHEELMOUSE, &aEvent );
+
+ return FALSE;
+}
+
+gboolean GtkSalFrame::signalMotion( GtkWidget*, GdkEventMotion* pEvent, gpointer frame )
+{
+ GtkSalFrame* pThis = (GtkSalFrame*)frame;
+
+ SalMouseEvent aEvent;
+ aEvent.mnTime = pEvent->time;
+ aEvent.mnX = (long)pEvent->x_root - pThis->maGeometry.nX;
+ aEvent.mnY = (long)pEvent->y_root - pThis->maGeometry.nY;
+ aEvent.mnCode = GetMouseModCode( pEvent->state );
+ aEvent.mnButton = 0;
+
+
+ GTK_YIELD_GRAB();
+
+ // --- RTL --- (mirror mouse pos)
+ if( Application::GetSettings().GetLayoutRTL() )
+ aEvent.mnX = pThis->maGeometry.nWidth-1-aEvent.mnX;
+
+ vcl::DeletionListener aDel( pThis );
+
+ pThis->CallCallback( SALEVENT_MOUSEMOVE, &aEvent );
+
+ if( ! aDel.isDeleted() )
+ {
+ int frame_x = (int)(pEvent->x_root - pEvent->x);
+ int frame_y = (int)(pEvent->y_root - pEvent->y);
+ if( frame_x != pThis->maGeometry.nX || frame_y != pThis->maGeometry.nY )
+ {
+ pThis->maGeometry.nX = frame_x;
+ pThis->maGeometry.nY = frame_y;
+ pThis->CallCallback( SALEVENT_MOVE, NULL );
+ }
+
+ if( ! aDel.isDeleted() )
+ {
+ // ask for the next hint
+ gint x, y;
+ GdkModifierType mask;
+ gdk_window_get_pointer( GTK_WIDGET(pThis->m_pWindow)->window, &x, &y, &mask );
+ }
+ }
+
+ return TRUE;
+}
+
+gboolean GtkSalFrame::signalCrossing( GtkWidget*, GdkEventCrossing* pEvent, gpointer frame )
+{
+ GtkSalFrame* pThis = (GtkSalFrame*)frame;
+ SalMouseEvent aEvent;
+ aEvent.mnTime = pEvent->time;
+ aEvent.mnX = (long)pEvent->x_root - pThis->maGeometry.nX;
+ aEvent.mnY = (long)pEvent->y_root - pThis->maGeometry.nY;
+ aEvent.mnCode = GetMouseModCode( pEvent->state );
+ aEvent.mnButton = 0;
+
+ GTK_YIELD_GRAB();
+ pThis->CallCallback( (pEvent->type == GDK_ENTER_NOTIFY) ? SALEVENT_MOUSEMOVE : SALEVENT_MOUSELEAVE, &aEvent );
+
+ return TRUE;
+}
+
+
+gboolean GtkSalFrame::signalExpose( GtkWidget*, GdkEventExpose* pEvent, gpointer frame )
+{
+ GtkSalFrame* pThis = (GtkSalFrame*)frame;
+
+ struct SalPaintEvent aEvent( pEvent->area.x, pEvent->area.y, pEvent->area.width, pEvent->area.height );
+
+ GTK_YIELD_GRAB();
+ pThis->CallCallback( SALEVENT_PAINT, &aEvent );
+
+ return FALSE;
+}
+
+gboolean GtkSalFrame::signalFocus( GtkWidget*, GdkEventFocus* pEvent, gpointer frame )
+{
+ GtkSalFrame* pThis = (GtkSalFrame*)frame;
+
+ GTK_YIELD_GRAB();
+
+ // check if printers have changed (analogous to salframe focus handler)
+ vcl_sal::PrinterUpdate::update();
+
+ if( !pEvent->in )
+ {
+ pThis->m_nKeyModifiers = 0;
+ pThis->m_bSingleAltPress = false;
+ pThis->m_bSendModChangeOnRelease = false;
+ }
+
+ if( pThis->m_pIMHandler )
+ pThis->m_pIMHandler->focusChanged( pEvent->in );
+
+ // ask for changed printers like generic implementation
+ if( pEvent->in )
+ if( static_cast< X11SalInstance* >(GetSalData()->m_pInstance)->isPrinterInit() )
+ vcl_sal::PrinterUpdate::update();
+
+ // FIXME: find out who the hell steals the focus from our frame
+ // while we have the pointer grabbed, this should not come from
+ // the window manager. Is this an event that was still queued ?
+ // The focus does not seem to get set inside our process
+ //
+ // in the meantime do not propagate focus get/lose if floats are open
+ if( m_nFloats == 0 )
+ pThis->CallCallback( pEvent->in ? SALEVENT_GETFOCUS : SALEVENT_LOSEFOCUS, NULL );
+
+ return FALSE;
+}
+
+IMPL_LINK( GtkSalFrame, ImplDelayedFullScreenHdl, void*, EMPTYARG )
+{
+ Atom nStateAtom = getDisplay()->getWMAdaptor()->getAtom(vcl_sal::WMAdaptor::NET_WM_STATE);
+ Atom nFSAtom = getDisplay()->getWMAdaptor()->getAtom(vcl_sal::WMAdaptor::NET_WM_STATE_FULLSCREEN );
+ if( nStateAtom && nFSAtom )
+ {
+ /* #i110881# workaround a gtk issue (see https://bugzilla.redhat.com/show_bug.cgi?id=623191#c8)
+ gtk_window_fullscreen can fail due to a race condition, request an additional status change
+ to fullscreen to be safe
+ */
+ XEvent aEvent;
+ aEvent.type = ClientMessage;
+ aEvent.xclient.display = getDisplay()->GetDisplay();
+ aEvent.xclient.window = GDK_WINDOW_XWINDOW(m_pWindow->window);
+ aEvent.xclient.message_type = nStateAtom;
+ aEvent.xclient.format = 32;
+ aEvent.xclient.data.l[0] = 1;
+ aEvent.xclient.data.l[1] = nFSAtom;
+ aEvent.xclient.data.l[2] = 0;
+ aEvent.xclient.data.l[3] = 0;
+ aEvent.xclient.data.l[4] = 0;
+ XSendEvent( getDisplay()->GetDisplay(),
+ getDisplay()->GetRootWindow( m_nScreen ),
+ False,
+ SubstructureNotifyMask | SubstructureRedirectMask,
+ &aEvent
+ );
+ }
+
+ return 0;
+}
+
+gboolean GtkSalFrame::signalMap( GtkWidget*, GdkEvent*, gpointer frame )
+{
+ GtkSalFrame* pThis = (GtkSalFrame*)frame;
+
+ GTK_YIELD_GRAB();
+
+ if( pThis->m_bFullscreen )
+ {
+ /* #i110881# workaorund a gtk issue (see https://bugzilla.redhat.com/show_bug.cgi?id=623191#c8)
+ gtk_window_fullscreen can run into a race condition with the window's showstate
+ */
+ Application::PostUserEvent( LINK( pThis, GtkSalFrame, ImplDelayedFullScreenHdl ) );
+ }
+
+ bool bSetFocus = pThis->m_bSetFocusOnMap;
+ pThis->m_bSetFocusOnMap = false;
+ if( ImplGetSVData()->mbIsTestTool )
+ {
+ /* #i76541# testtool needs the focus to be in a new document
+ * however e.g. metacity does not necessarily put the focus into
+ * a newly shown window. An extra little hint seems to help here.
+ * however we don't want to interfere with the normal user experience
+ * so this is done when running in testtool only
+ */
+ if( ! pThis->m_pParent && (pThis->m_nStyle & SAL_FRAME_STYLE_MOVEABLE) != 0 )
+ bSetFocus = true;
+ }
+
+ if( bSetFocus )
+ {
+ XSetInputFocus( pThis->getDisplay()->GetDisplay(),
+ GDK_WINDOW_XWINDOW( GTK_WIDGET(pThis->m_pWindow)->window),
+ RevertToParent, CurrentTime );
+ }
+
+ pThis->CallCallback( SALEVENT_RESIZE, NULL );
+
+ return FALSE;
+}
+
+gboolean GtkSalFrame::signalUnmap( GtkWidget*, GdkEvent*, gpointer frame )
+{
+ GtkSalFrame* pThis = (GtkSalFrame*)frame;
+
+ GTK_YIELD_GRAB();
+ pThis->CallCallback( SALEVENT_RESIZE, NULL );
+
+ return FALSE;
+}
+
+gboolean GtkSalFrame::signalConfigure( GtkWidget*, GdkEventConfigure* pEvent, gpointer frame )
+{
+ GtkSalFrame* pThis = (GtkSalFrame*)frame;
+
+ bool bMoved = false, bSized = false;
+ int x = pEvent->x, y = pEvent->y;
+
+ /* HACK: during sizing/moving a toolbar pThis->maGeometry is actually
+ * already exact; even worse: due to the asynchronicity of configure
+ * events the borderwindow which would evaluate this event
+ * would size/move based on wrong data if we would actually evaluate
+ * this event. So let's swallow it; this is also a performance
+ * improvement as one can omit the synchronous XTranslateCoordinates
+ * call below.
+ */
+ if( (pThis->m_nStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) &&
+ pThis->getDisplay()->GetCaptureFrame() == pThis )
+ return FALSE;
+
+
+ // in child case the coordinates are not root coordinates,
+ // need to transform
+
+ /* #i31785# sadly one cannot really trust the x,y members of the event;
+ * they are e.g. not set correctly on maximize/demaximize; this rather
+ * sounds like a bug in gtk we have to workaround.
+ */
+ XLIB_Window aChild;
+ XTranslateCoordinates( pThis->getDisplay()->GetDisplay(),
+ GDK_WINDOW_XWINDOW(GTK_WIDGET(pThis->m_pWindow)->window),
+ pThis->getDisplay()->GetRootWindow( pThis->getDisplay()->GetDefaultScreenNumber() ),
+ 0, 0,
+ &x, &y,
+ &aChild );
+
+ if( x != pThis->maGeometry.nX || y != pThis->maGeometry.nY )
+ {
+ bMoved = true;
+ pThis->maGeometry.nX = x;
+ pThis->maGeometry.nY = y;
+ }
+ /* #i86302#
+ * for non sizeable windows we set the min and max hint for the window manager to
+ * achieve correct sizing. However this is asynchronous and e.g. on Compiz
+ * it sometimes happens that the window gets resized to another size (some default)
+ * if we update the size here, subsequent setMinMaxSize will use this wrong size
+ * - which is not good since the window manager will now size the window back to this
+ * wrong size at some point.
+ */
+ if( (pThis->m_nStyle & (SAL_FRAME_STYLE_SIZEABLE | SAL_FRAME_STYLE_PLUG)) == SAL_FRAME_STYLE_SIZEABLE )
+ {
+ if( pEvent->width != (int)pThis->maGeometry.nWidth || pEvent->height != (int)pThis->maGeometry.nHeight )
+ {
+ bSized = true;
+ pThis->maGeometry.nWidth = pEvent->width;
+ pThis->maGeometry.nHeight = pEvent->height;
+ }
+ }
+
+ // update decoration hints
+ if( ! (pThis->m_nStyle & SAL_FRAME_STYLE_PLUG) )
+ {
+ GdkRectangle aRect;
+ gdk_window_get_frame_extents( GTK_WIDGET(pThis->m_pWindow)->window, &aRect );
+ pThis->maGeometry.nTopDecoration = y - aRect.y;
+ pThis->maGeometry.nBottomDecoration = aRect.y + aRect.height - y - pEvent->height;
+ pThis->maGeometry.nLeftDecoration = x - aRect.x;
+ pThis->maGeometry.nRightDecoration = aRect.x + aRect.width - x - pEvent->width;
+ }
+ else
+ {
+ pThis->maGeometry.nTopDecoration =
+ pThis->maGeometry.nBottomDecoration =
+ pThis->maGeometry.nLeftDecoration =
+ pThis->maGeometry.nRightDecoration = 0;
+ }
+
+ GTK_YIELD_GRAB();
+ pThis->updateScreenNumber();
+ if( bMoved && bSized )
+ pThis->CallCallback( SALEVENT_MOVERESIZE, NULL );
+ else if( bMoved )
+ pThis->CallCallback( SALEVENT_MOVE, NULL );
+ else if( bSized )
+ pThis->CallCallback( SALEVENT_RESIZE, NULL );
+
+ return FALSE;
+}
+
+gboolean GtkSalFrame::signalKey( GtkWidget*, GdkEventKey* pEvent, gpointer frame )
+{
+ GtkSalFrame* pThis = (GtkSalFrame*)frame;
+
+ vcl::DeletionListener aDel( pThis );
+
+ if( pThis->m_pIMHandler )
+ {
+ if( pThis->m_pIMHandler->handleKeyEvent( pEvent ) )
+ {
+ pThis->m_bSingleAltPress = false;
+ return TRUE;
+ }
+ }
+ GTK_YIELD_GRAB();
+
+ // handle modifiers
+ if( pEvent->keyval == GDK_Shift_L || pEvent->keyval == GDK_Shift_R ||
+ pEvent->keyval == GDK_Control_L || pEvent->keyval == GDK_Control_R ||
+ pEvent->keyval == GDK_Alt_L || pEvent->keyval == GDK_Alt_R ||
+ pEvent->keyval == GDK_Meta_L || pEvent->keyval == GDK_Meta_R ||
+ pEvent->keyval == GDK_Super_L || pEvent->keyval == GDK_Super_R )
+ {
+ SalKeyModEvent aModEvt;
+
+ USHORT nModCode = GetKeyModCode( pEvent->state );
+
+ aModEvt.mnModKeyCode = 0; // emit no MODKEYCHANGE events
+ if( pEvent->type == GDK_KEY_PRESS && !pThis->m_nKeyModifiers )
+ pThis->m_bSendModChangeOnRelease = true;
+
+ else if( pEvent->type == GDK_KEY_RELEASE &&
+ pThis->m_bSendModChangeOnRelease )
+ {
+ aModEvt.mnModKeyCode = pThis->m_nKeyModifiers;
+ pThis->m_nKeyModifiers = 0;
+ }
+
+ USHORT nExtModMask = 0;
+ USHORT nModMask = 0;
+ // pressing just the ctrl key leads to a keysym of XK_Control but
+ // the event state does not contain ControlMask. In the release
+ // event its the other way round: it does contain the Control mask.
+ // The modifier mode therefore has to be adapted manually.
+ switch( pEvent->keyval )
+ {
+ case GDK_Control_L:
+ nExtModMask = MODKEY_LMOD1;
+ nModMask = KEY_MOD1;
+ break;
+ case GDK_Control_R:
+ nExtModMask = MODKEY_RMOD1;
+ nModMask = KEY_MOD1;
+ break;
+ case GDK_Alt_L:
+ nExtModMask = MODKEY_LMOD2;
+ nModMask = KEY_MOD2;
+ break;
+ case GDK_Alt_R:
+ nExtModMask = MODKEY_RMOD2;
+ nModMask = KEY_MOD2;
+ break;
+ case GDK_Shift_L:
+ nExtModMask = MODKEY_LSHIFT;
+ nModMask = KEY_SHIFT;
+ break;
+ case GDK_Shift_R:
+ nExtModMask = MODKEY_RSHIFT;
+ nModMask = KEY_SHIFT;
+ break;
+ // Map Meta/Super to MOD3 modifier on all Unix systems
+ // except Mac OS X
+ case GDK_Meta_L:
+ case GDK_Super_L:
+ nExtModMask = MODKEY_LMOD3;
+ nModMask = KEY_MOD3;
+ break;
+ case GDK_Meta_R:
+ case GDK_Super_R:
+ nExtModMask = MODKEY_RMOD3;
+ nModMask = KEY_MOD3;
+ break;
+ }
+ if( pEvent->type == GDK_KEY_RELEASE )
+ {
+ nModCode &= ~nModMask;
+ pThis->m_nKeyModifiers &= ~nExtModMask;
+ }
+ else
+ {
+ nModCode |= nModMask;
+ pThis->m_nKeyModifiers |= nExtModMask;
+ }
+
+ aModEvt.mnCode = nModCode;
+ aModEvt.mnTime = pEvent->time;
+
+ pThis->CallCallback( SALEVENT_KEYMODCHANGE, &aModEvt );
+
+ if( ! aDel.isDeleted() )
+ {
+ // emulate KEY_MENU
+ if( ( pEvent->keyval == GDK_Alt_L || pEvent->keyval == GDK_Alt_R ) &&
+ ( nModCode & ~(KEY_MOD3|KEY_MOD2)) == 0 )
+ {
+ if( pEvent->type == GDK_KEY_PRESS )
+ pThis->m_bSingleAltPress = true;
+
+ else if( pThis->m_bSingleAltPress )
+ {
+ SalKeyEvent aKeyEvt;
+
+ aKeyEvt.mnCode = KEY_MENU | nModCode;
+ aKeyEvt.mnRepeat = 0;
+ aKeyEvt.mnTime = pEvent->time;
+ aKeyEvt.mnCharCode = 0;
+
+ // simulate KEY_MENU
+ pThis->CallCallback( SALEVENT_KEYINPUT, &aKeyEvt );
+ if( ! aDel.isDeleted() )
+ {
+ pThis->CallCallback( SALEVENT_KEYUP, &aKeyEvt );
+ pThis->m_bSingleAltPress = false;
+ }
+ }
+ }
+ else
+ pThis->m_bSingleAltPress = false;
+ }
+ }
+ else
+ {
+ pThis->doKeyCallback( pEvent->state,
+ pEvent->keyval,
+ pEvent->hardware_keycode,
+ pEvent->group,
+ pEvent->time,
+ sal_Unicode(gdk_keyval_to_unicode( pEvent->keyval )),
+ (pEvent->type == GDK_KEY_PRESS),
+ false );
+ if( ! aDel.isDeleted() )
+ {
+ pThis->m_bSendModChangeOnRelease = false;
+ pThis->m_bSingleAltPress = false;
+ }
+ }
+
+ if( !aDel.isDeleted() && pThis->m_pIMHandler )
+ pThis->m_pIMHandler->updateIMSpotLocation();
+
+ return TRUE;
+}
+
+gboolean GtkSalFrame::signalDelete( GtkWidget*, GdkEvent*, gpointer frame )
+{
+ GtkSalFrame* pThis = (GtkSalFrame*)frame;
+
+ GTK_YIELD_GRAB();
+ pThis->CallCallback( SALEVENT_CLOSE, NULL );
+
+ return TRUE;
+}
+
+void GtkSalFrame::signalStyleSet( GtkWidget*, GtkStyle* pPrevious, gpointer frame )
+{
+ GtkSalFrame* pThis = (GtkSalFrame*)frame;
+
+ // every frame gets an initial style set on creation
+ // do not post these as the whole application tends to
+ // redraw itself to adjust to the new style
+ // where there IS no new style resulting in tremendous unnecessary flickering
+ if( pPrevious != NULL )
+ {
+ // signalStyleSet does NOT usually have the gdk lock
+ // so post user event to safely dispatch the SALEVENT_SETTINGSCHANGED
+ // note: settings changed for multiple frames is avoided in winproc.cxx ImplHandleSettings
+ pThis->getDisplay()->SendInternalEvent( pThis, NULL, SALEVENT_SETTINGSCHANGED );
+ pThis->getDisplay()->SendInternalEvent( pThis, NULL, SALEVENT_FONTCHANGED );
+ }
+
+ /* #i64117# gtk sets a nice background pixmap
+ * but we actually don't really want that, so save
+ * some time on the Xserver as well as prevent
+ * some paint issues
+ */
+ GdkWindow* pWin = GTK_WIDGET(pThis->getWindow())->window;
+ if( pWin )
+ {
+ XLIB_Window aWin = GDK_WINDOW_XWINDOW(pWin);
+ if( aWin != None )
+ XSetWindowBackgroundPixmap( pThis->getDisplay()->GetDisplay(),
+ aWin,
+ pThis->m_hBackgroundPixmap );
+ }
+
+ if( ! pThis->m_pParent )
+ {
+ // signalize theme changed for NWF caches
+ // FIXME: should be called only once for a style change
+ GtkSalGraphics::bThemeChanged = TRUE;
+ }
+}
+
+gboolean GtkSalFrame::signalState( GtkWidget*, GdkEvent* pEvent, gpointer frame )
+{
+ GtkSalFrame* pThis = (GtkSalFrame*)frame;
+ if( (pThis->m_nState & GDK_WINDOW_STATE_ICONIFIED) != (pEvent->window_state.new_window_state & GDK_WINDOW_STATE_ICONIFIED ) )
+ pThis->getDisplay()->SendInternalEvent( pThis, NULL, SALEVENT_RESIZE );
+
+ if( (pEvent->window_state.new_window_state & GDK_WINDOW_STATE_MAXIMIZED) &&
+ ! (pThis->m_nState & GDK_WINDOW_STATE_MAXIMIZED) )
+ {
+ pThis->m_aRestorePosSize =
+ Rectangle( Point( pThis->maGeometry.nX, pThis->maGeometry.nY ),
+ Size( pThis->maGeometry.nWidth, pThis->maGeometry.nHeight ) );
+ }
+ pThis->m_nState = pEvent->window_state.new_window_state;
+
+ #if OSL_DEBUG_LEVEL > 1
+ if( (pEvent->window_state.changed_mask & GDK_WINDOW_STATE_FULLSCREEN) )
+ {
+ fprintf( stderr, "window %p %s full screen state\n",
+ pThis,
+ (pEvent->window_state.new_window_state & GDK_WINDOW_STATE_FULLSCREEN) ? "enters" : "leaves");
+ }
+ #endif
+
+ return FALSE;
+}
+
+gboolean GtkSalFrame::signalVisibility( GtkWidget*, GdkEventVisibility* pEvent, gpointer frame )
+{
+ GtkSalFrame* pThis = (GtkSalFrame*)frame;
+ pThis->m_nVisibility = pEvent->state;
+
+ return FALSE;
+}
+
+void GtkSalFrame::signalDestroy( GtkObject* pObj, gpointer frame )
+{
+ GtkSalFrame* pThis = (GtkSalFrame*)frame;
+ if( GTK_WIDGET( pObj ) == pThis->m_pWindow )
+ {
+ pThis->m_pFixedContainer = NULL;
+ pThis->m_pWindow = NULL;
+ }
+}
+
+// ----------------------------------------------------------------------
+// GtkSalFrame::IMHandler
+// ----------------------------------------------------------------------
+
+GtkSalFrame::IMHandler::IMHandler( GtkSalFrame* pFrame )
+: m_pFrame(pFrame),
+ m_nPrevKeyPresses( 0 ),
+ m_pIMContext( NULL ),
+ m_bFocused( true ),
+ m_bPreeditJustChanged( false )
+{
+ m_aInputEvent.mpTextAttr = NULL;
+ createIMContext();
+}
+
+GtkSalFrame::IMHandler::~IMHandler()
+{
+ // cancel an eventual event posted to begin preedit again
+ m_pFrame->getDisplay()->CancelInternalEvent( m_pFrame, &m_aInputEvent, SALEVENT_EXTTEXTINPUT );
+ deleteIMContext();
+}
+
+void GtkSalFrame::IMHandler::createIMContext()
+{
+ if( ! m_pIMContext )
+ {
+ m_pIMContext = gtk_im_multicontext_new ();
+ g_signal_connect( m_pIMContext, "commit",
+ G_CALLBACK (signalIMCommit), this );
+ g_signal_connect( m_pIMContext, "preedit_changed",
+ G_CALLBACK (signalIMPreeditChanged), this );
+ g_signal_connect( m_pIMContext, "retrieve_surrounding",
+ G_CALLBACK (signalIMRetrieveSurrounding), this );
+ g_signal_connect( m_pIMContext, "delete_surrounding",
+ G_CALLBACK (signalIMDeleteSurrounding), this );
+ g_signal_connect( m_pIMContext, "preedit_start",
+ G_CALLBACK (signalIMPreeditStart), this );
+ g_signal_connect( m_pIMContext, "preedit_end",
+ G_CALLBACK (signalIMPreeditEnd), this );
+
+ m_pFrame->getDisplay()->GetXLib()->PushXErrorLevel( true );
+ gtk_im_context_set_client_window( m_pIMContext, GTK_WIDGET(m_pFrame->m_pWindow)->window );
+ gtk_im_context_focus_in( m_pIMContext );
+ m_pFrame->getDisplay()->GetXLib()->PopXErrorLevel();
+ m_bFocused = true;
+ }
+}
+
+void GtkSalFrame::IMHandler::deleteIMContext()
+{
+ if( m_pIMContext )
+ {
+ // first give IC a chance to deinitialize
+ m_pFrame->getDisplay()->GetXLib()->PushXErrorLevel( true );
+ gtk_im_context_set_client_window( m_pIMContext, NULL );
+ m_pFrame->getDisplay()->GetXLib()->PopXErrorLevel();
+ // destroy old IC
+ g_object_unref( m_pIMContext );
+ m_pIMContext = NULL;
+ }
+}
+
+void GtkSalFrame::IMHandler::doCallEndExtTextInput()
+{
+ m_aInputEvent.mpTextAttr = NULL;
+ m_pFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, NULL );
+}
+
+void GtkSalFrame::IMHandler::updateIMSpotLocation()
+{
+ SalExtTextInputPosEvent aPosEvent;
+ m_pFrame->CallCallback( SALEVENT_EXTTEXTINPUTPOS, (void*)&aPosEvent );
+ GdkRectangle aArea;
+ aArea.x = aPosEvent.mnX;
+ aArea.y = aPosEvent.mnY;
+ aArea.width = aPosEvent.mnWidth;
+ aArea.height = aPosEvent.mnHeight;
+ m_pFrame->getDisplay()->GetXLib()->PushXErrorLevel( true );
+ gtk_im_context_set_cursor_location( m_pIMContext, &aArea );
+ m_pFrame->getDisplay()->GetXLib()->PopXErrorLevel();
+}
+
+void GtkSalFrame::IMHandler::setInputContext( SalInputContext* )
+{
+}
+
+void GtkSalFrame::IMHandler::sendEmptyCommit()
+{
+ vcl::DeletionListener aDel( m_pFrame );
+
+ SalExtTextInputEvent aEmptyEv;
+ aEmptyEv.mnTime = 0;
+ aEmptyEv.mpTextAttr = 0;
+ aEmptyEv.maText = String();
+ aEmptyEv.mnCursorPos = 0;
+ aEmptyEv.mnCursorFlags = 0;
+ aEmptyEv.mnDeltaStart = 0;
+ aEmptyEv.mbOnlyCursor = False;
+ m_pFrame->CallCallback( SALEVENT_EXTTEXTINPUT, (void*)&aEmptyEv );
+ if( ! aDel.isDeleted() )
+ m_pFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, NULL );
+}
+
+void GtkSalFrame::IMHandler::endExtTextInput( USHORT /*nFlags*/ )
+{
+ gtk_im_context_reset ( m_pIMContext );
+
+ if( m_aInputEvent.mpTextAttr )
+ {
+ vcl::DeletionListener aDel( m_pFrame );
+ // delete preedit in sal (commit an empty string)
+ sendEmptyCommit();
+ if( ! aDel.isDeleted() )
+ {
+ // mark previous preedit state again (will e.g. be sent at focus gain)
+ m_aInputEvent.mpTextAttr = &m_aInputFlags[0];
+ if( m_bFocused )
+ {
+ // begin preedit again
+ m_pFrame->getDisplay()->SendInternalEvent( m_pFrame, &m_aInputEvent, SALEVENT_EXTTEXTINPUT );
+ }
+ }
+ }
+}
+
+void GtkSalFrame::IMHandler::focusChanged( bool bFocusIn )
+{
+ m_bFocused = bFocusIn;
+ if( bFocusIn )
+ {
+ m_pFrame->getDisplay()->GetXLib()->PushXErrorLevel( true );
+ gtk_im_context_focus_in( m_pIMContext );
+ m_pFrame->getDisplay()->GetXLib()->PopXErrorLevel();
+ if( m_aInputEvent.mpTextAttr )
+ {
+ sendEmptyCommit();
+ // begin preedit again
+ m_pFrame->getDisplay()->SendInternalEvent( m_pFrame, &m_aInputEvent, SALEVENT_EXTTEXTINPUT );
+ }
+ }
+ else
+ {
+ m_pFrame->getDisplay()->GetXLib()->PushXErrorLevel( true );
+ gtk_im_context_focus_out( m_pIMContext );
+ m_pFrame->getDisplay()->GetXLib()->PopXErrorLevel();
+ // cancel an eventual event posted to begin preedit again
+ m_pFrame->getDisplay()->CancelInternalEvent( m_pFrame, &m_aInputEvent, SALEVENT_EXTTEXTINPUT );
+ }
+}
+
+bool GtkSalFrame::IMHandler::handleKeyEvent( GdkEventKey* pEvent )
+{
+ vcl::DeletionListener aDel( m_pFrame );
+
+ if( pEvent->type == GDK_KEY_PRESS )
+ {
+ // Add this key press event to the list of previous key presses
+ // to which we compare key release events. If a later key release
+ // event has a matching key press event in this list, we swallow
+ // the key release because some GTK Input Methods don't swallow it
+ // for us.
+ m_aPrevKeyPresses.push_back( PreviousKeyPress(pEvent) );
+ m_nPrevKeyPresses++;
+
+ // Also pop off the earliest key press event if there are more than 10
+ // already.
+ while (m_nPrevKeyPresses > 10)
+ {
+ m_aPrevKeyPresses.pop_front();
+ m_nPrevKeyPresses--;
+ }
+
+ GObject* pRef = G_OBJECT( g_object_ref( G_OBJECT( m_pIMContext ) ) );
+
+ // #i51353# update spot location on every key input since we cannot
+ // know which key may activate a preedit choice window
+ updateIMSpotLocation();
+ if( aDel.isDeleted() )
+ return true;
+
+ gboolean bResult = gtk_im_context_filter_keypress( m_pIMContext, pEvent );
+ g_object_unref( pRef );
+
+ if( aDel.isDeleted() )
+ return true;
+
+ m_bPreeditJustChanged = false;
+
+ if( bResult )
+ return true;
+ else
+ {
+ DBG_ASSERT( m_nPrevKeyPresses > 0, "key press has vanished !" );
+ if( ! m_aPrevKeyPresses.empty() ) // sanity check
+ {
+ // event was not swallowed, do not filter a following
+ // key release event
+ // note: this relies on gtk_im_context_filter_keypress
+ // returning without calling a handler (in the "not swallowed"
+ // case ) which might change the previous key press list so
+ // we would pop the wrong event here
+ m_aPrevKeyPresses.pop_back();
+ m_nPrevKeyPresses--;
+ }
+ }
+ }
+
+ // Determine if we got an earlier key press event corresponding to this key release
+ if (pEvent->type == GDK_KEY_RELEASE)
+ {
+ GObject* pRef = G_OBJECT( g_object_ref( G_OBJECT( m_pIMContext ) ) );
+ gboolean bResult = gtk_im_context_filter_keypress( m_pIMContext, pEvent );
+ g_object_unref( pRef );
+
+ if( aDel.isDeleted() )
+ return true;
+
+ m_bPreeditJustChanged = false;
+
+ std::list<PreviousKeyPress>::iterator iter = m_aPrevKeyPresses.begin();
+ std::list<PreviousKeyPress>::iterator iter_end = m_aPrevKeyPresses.end();
+ while (iter != iter_end)
+ {
+ // If we found a corresponding previous key press event, swallow the release
+ // and remove the earlier key press from our list
+ if (*iter == pEvent)
+ {
+ m_aPrevKeyPresses.erase(iter);
+ m_nPrevKeyPresses--;
+ return true;
+ }
+ ++iter;
+ }
+
+ if( bResult )
+ return true;
+ }
+
+ return false;
+}
+
+/* FIXME:
+* #122282# still more hacking: some IMEs never start a preedit but simply commit
+* in this case we cannot commit a single character. Workaround: do not do the
+* single key hack for enter or space if the unicode commited does not match
+*/
+
+static bool checkSingleKeyCommitHack( guint keyval, sal_Unicode cCode )
+{
+ bool bRet = true;
+ switch( keyval )
+ {
+ case GDK_KP_Enter:
+ case GDK_Return:
+ if( cCode != '\n' && cCode != '\r' )
+ bRet = false;
+ break;
+ case GDK_space:
+ case GDK_KP_Space:
+ if( cCode != ' ' )
+ bRet = false;
+ break;
+ default:
+ break;
+ }
+ return bRet;
+}
+
+#ifdef SOLARIS
+#define CONTEXT_ARG pContext
+#else
+#define CONTEXT_ARG EMPTYARG
+#endif
+void GtkSalFrame::IMHandler::signalIMCommit( GtkIMContext* CONTEXT_ARG, gchar* pText, gpointer im_handler )
+{
+ GtkSalFrame::IMHandler* pThis = (GtkSalFrame::IMHandler*)im_handler;
+
+ vcl::DeletionListener aDel( pThis->m_pFrame );
+ // open a block that will end the GTK_YIELD_GRAB before calling preedit changed again
+ {
+ GTK_YIELD_GRAB();
+
+ pThis->m_aInputEvent.mnTime = 0;
+ pThis->m_aInputEvent.mpTextAttr = 0;
+ pThis->m_aInputEvent.maText = String( pText, RTL_TEXTENCODING_UTF8 );
+ pThis->m_aInputEvent.mnCursorPos = pThis->m_aInputEvent.maText.Len();
+ pThis->m_aInputEvent.mnCursorFlags = 0;
+ pThis->m_aInputEvent.mnDeltaStart = 0;
+ pThis->m_aInputEvent.mbOnlyCursor = False;
+
+ pThis->m_aInputFlags.clear();
+
+ /* necessary HACK: all keyboard input comes in here as soon as a IMContext is set
+ * which is logical and consequent. But since even simple input like
+ * <space> comes through the commit signal instead of signalKey
+ * and all kinds of windows only implement KeyInput (e.g. PushButtons,
+ * RadioButtons and a lot of other Controls), will send a single
+ * KeyInput/KeyUp sequence instead of an ExtText event if there
+ * never was a preedit and the text is only one character.
+ *
+ * In this case there the last ExtText event must have been
+ * SALEVENT_ENDEXTTEXTINPUT, either because of a regular commit
+ * or because there never was a preedit.
+ */
+ bool bSingleCommit = false;
+ bool bWasPreedit =
+ (pThis->m_aInputEvent.mpTextAttr != 0) ||
+ pThis->m_bPreeditJustChanged;
+ if( ! bWasPreedit
+ && pThis->m_aInputEvent.maText.Len() == 1
+ && ! pThis->m_aPrevKeyPresses.empty()
+ )
+ {
+ const PreviousKeyPress& rKP = pThis->m_aPrevKeyPresses.back();
+ sal_Unicode aOrigCode = pThis->m_aInputEvent.maText.GetChar(0);
+
+ if( checkSingleKeyCommitHack( rKP.keyval, aOrigCode ) )
+ {
+ pThis->m_pFrame->doKeyCallback( rKP.state, rKP.keyval, rKP.hardware_keycode, rKP.group, rKP.time, aOrigCode, true, true );
+ bSingleCommit = true;
+ }
+ }
+ if( ! bSingleCommit )
+ {
+ pThis->m_pFrame->CallCallback( SALEVENT_EXTTEXTINPUT, (void*)&pThis->m_aInputEvent);
+ if( ! aDel.isDeleted() )
+ pThis->doCallEndExtTextInput();
+ }
+ if( ! aDel.isDeleted() )
+ {
+ // reset input event
+ pThis->m_aInputEvent.maText = String();
+ pThis->m_aInputEvent.mnCursorPos = 0;
+ pThis->updateIMSpotLocation();
+ }
+ }
+ #ifdef SOLARIS
+ // #i51356# workaround a solaris IIIMP bug
+ // in case of partial commits the preedit changed signal
+ // and commit signal come in wrong order
+ if( ! aDel.isDeleted() )
+ signalIMPreeditChanged( pContext, im_handler );
+ #endif
+}
+
+void GtkSalFrame::IMHandler::signalIMPreeditChanged( GtkIMContext*, gpointer im_handler )
+{
+ GtkSalFrame::IMHandler* pThis = (GtkSalFrame::IMHandler*)im_handler;
+
+ char* pText = NULL;
+ PangoAttrList* pAttrs = NULL;
+ gint nCursorPos = 0;
+
+ gtk_im_context_get_preedit_string( pThis->m_pIMContext,
+ &pText,
+ &pAttrs,
+ &nCursorPos );
+ if( pText && ! *pText ) // empty string
+ {
+ // change from nothing to nothing -> do not start preedit
+ // e.g. this will activate input into a calc cell without
+ // user input
+ if( pThis->m_aInputEvent.maText.Len() == 0 )
+ {
+ g_free( pText );
+ return;
+ }
+ }
+
+ pThis->m_bPreeditJustChanged = true;
+
+ bool bEndPreedit = (!pText || !*pText) && pThis->m_aInputEvent.mpTextAttr != NULL;
+ pThis->m_aInputEvent.mnTime = 0;
+ pThis->m_aInputEvent.maText = String( pText, RTL_TEXTENCODING_UTF8 );
+ pThis->m_aInputEvent.mnCursorPos = nCursorPos;
+ pThis->m_aInputEvent.mnCursorFlags = 0;
+ pThis->m_aInputEvent.mnDeltaStart = 0;
+ pThis->m_aInputEvent.mbOnlyCursor = False;
+
+ pThis->m_aInputFlags = std::vector<USHORT>( std::max( 1, (int)pThis->m_aInputEvent.maText.Len() ), 0 );
+
+ PangoAttrIterator *iter = pango_attr_list_get_iterator (pAttrs);
+ do
+ {
+ GSList *attr_list = NULL;
+ GSList *tmp_list = NULL;
+ gint start, end;
+ guint sal_attr = 0;
+
+ pango_attr_iterator_range (iter, &start, &end);
+ if (end == G_MAXINT)
+ end = pText ? strlen (pText) : 0;
+ if (end == start)
+ continue;
+
+ start = g_utf8_pointer_to_offset (pText, pText + start);
+ end = g_utf8_pointer_to_offset (pText, pText + end);
+
+ tmp_list = attr_list = pango_attr_iterator_get_attrs (iter);
+ while (tmp_list)
+ {
+ PangoAttribute *pango_attr = (PangoAttribute *)(tmp_list->data);
+
+ switch (pango_attr->klass->type)
+ {
+ case PANGO_ATTR_BACKGROUND:
+ sal_attr |= (SAL_EXTTEXTINPUT_ATTR_HIGHLIGHT | SAL_EXTTEXTINPUT_CURSOR_INVISIBLE);
+ break;
+ case PANGO_ATTR_UNDERLINE:
+ sal_attr |= SAL_EXTTEXTINPUT_ATTR_UNDERLINE;
+ break;
+ case PANGO_ATTR_STRIKETHROUGH:
+ sal_attr |= SAL_EXTTEXTINPUT_ATTR_REDTEXT;
+ break;
+ default:
+ break;
+ }
+ pango_attribute_destroy (pango_attr);
+ tmp_list = tmp_list->next;
+ }
+ if (sal_attr == 0)
+ sal_attr |= SAL_EXTTEXTINPUT_ATTR_UNDERLINE;
+ g_slist_free (attr_list);
+
+ // Set the sal attributes on our text
+ for (int i = start; i < end; i++)
+ pThis->m_aInputFlags[i] |= sal_attr;
+ } while (pango_attr_iterator_next (iter));
+
+ pThis->m_aInputEvent.mpTextAttr = &pThis->m_aInputFlags[0];
+
+ g_free( pText );
+ pango_attr_list_unref( pAttrs );
+
+ GTK_YIELD_GRAB();
+
+ vcl::DeletionListener aDel( pThis->m_pFrame );
+
+ pThis->m_pFrame->CallCallback( SALEVENT_EXTTEXTINPUT, (void*)&pThis->m_aInputEvent);
+ if( bEndPreedit && ! aDel.isDeleted() )
+ pThis->doCallEndExtTextInput();
+ if( ! aDel.isDeleted() )
+ pThis->updateIMSpotLocation();
+}
+
+void GtkSalFrame::IMHandler::signalIMPreeditStart( GtkIMContext*, gpointer /*im_handler*/ )
+{
+}
+
+void GtkSalFrame::IMHandler::signalIMPreeditEnd( GtkIMContext*, gpointer im_handler )
+{
+ GtkSalFrame::IMHandler* pThis = (GtkSalFrame::IMHandler*)im_handler;
+ GTK_YIELD_GRAB();
+
+ pThis->m_bPreeditJustChanged = true;
+
+ vcl::DeletionListener aDel( pThis->m_pFrame );
+ pThis->doCallEndExtTextInput();
+ if( ! aDel.isDeleted() )
+ pThis->updateIMSpotLocation();
+}
+
+uno::Reference<accessibility::XAccessibleEditableText>
+ FindFocus(uno::Reference< accessibility::XAccessibleContext > xContext)
+{
+ if (!xContext.is())
+ uno::Reference< accessibility::XAccessibleEditableText >();
+
+ uno::Reference<accessibility::XAccessibleStateSet> xState = xContext->getAccessibleStateSet();
+ if (xState.is())
+ {
+ if (xState->contains(accessibility::AccessibleStateType::FOCUSED))
+ return uno::Reference<accessibility::XAccessibleEditableText>(xContext, uno::UNO_QUERY);
+ }
+
+ for (sal_Int32 i = 0; i < xContext->getAccessibleChildCount(); ++i)
+ {
+ uno::Reference< accessibility::XAccessible > xChild = xContext->getAccessibleChild(i);
+ if (!xChild.is())
+ continue;
+ uno::Reference< accessibility::XAccessibleContext > xChildContext = xChild->getAccessibleContext();
+ if (!xChildContext.is())
+ continue;
+ uno::Reference< accessibility::XAccessibleEditableText > xText = FindFocus(xChildContext);
+ if (xText.is())
+ return xText;
+ }
+ return uno::Reference< accessibility::XAccessibleEditableText >();
+}
+
+uno::Reference<accessibility::XAccessibleEditableText> lcl_GetxText()
+{
+ uno::Reference<accessibility::XAccessibleEditableText> xText;
+ Window* pFocusWin = ImplGetSVData()->maWinData.mpFocusWin;
+ if (!pFocusWin)
+ return xText;
+
+ uno::Reference< accessibility::XAccessible > xAccessible( pFocusWin->GetAccessible( true ) );
+ if (xAccessible.is())
+ xText = FindFocus(xAccessible->getAccessibleContext());
+ return xText;
+}
+
+gboolean GtkSalFrame::IMHandler::signalIMRetrieveSurrounding( GtkIMContext* pContext, gpointer /*im_handler*/ )
+{
+ uno::Reference<accessibility::XAccessibleEditableText> xText = lcl_GetxText();
+
+ if (xText.is())
+ {
+ sal_uInt32 nPosition = xText->getCaretPosition();
+ rtl::OUString sAllText = xText->getText();
+ if (!sAllText.getLength())
+ return FALSE;
+ rtl::OString sUTF = rtl::OUStringToOString(sAllText, RTL_TEXTENCODING_UTF8);
+ rtl::OUString sCursorText(sAllText, nPosition);
+ gtk_im_context_set_surrounding(pContext, sUTF.getStr(), sUTF.getLength(),
+ rtl::OUStringToOString(sCursorText, RTL_TEXTENCODING_UTF8).getLength());
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+gboolean GtkSalFrame::IMHandler::signalIMDeleteSurrounding( GtkIMContext*, gint offset, gint nchars,
+ gpointer /*im_handler*/ )
+{
+ uno::Reference<accessibility::XAccessibleEditableText> xText = lcl_GetxText();
+
+ if (xText.is())
+ {
+ sal_uInt32 nPosition = xText->getCaretPosition();
+ // --> OD 2010-06-04 #i111768# - apply patch from kstribley:
+ // range checking
+// xText->deleteText(nPosition + offset, nPosition + offset + nchars);
+ sal_Int32 nDeletePos = nPosition + offset;
+ sal_Int32 nDeleteEnd = nDeletePos + nchars;
+ if (nDeletePos < 0)
+ nDeletePos = 0;
+ if (nDeleteEnd < 0)
+ nDeleteEnd = 0;
+ if (nDeleteEnd > xText->getCharacterCount())
+ nDeleteEnd = xText->getCharacterCount();
+
+ xText->deleteText(nDeletePos, nDeleteEnd);
+ // <--
+ return TRUE;
+ }
+
+ return FALSE;
+}
diff --git a/vcl/unx/gtk/window/gtkobject.cxx b/vcl/unx/gtk/window/gtkobject.cxx
new file mode 100644
index 000000000000..c5f5a168f653
--- /dev/null
+++ b/vcl/unx/gtk/window/gtkobject.cxx
@@ -0,0 +1,216 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <plugins/gtk/gtkobject.hxx>
+#include <plugins/gtk/gtkframe.hxx>
+#include <plugins/gtk/gtkdata.hxx>
+#include <plugins/gtk/gtkinst.hxx>
+
+GtkSalObject::GtkSalObject( GtkSalFrame* pParent, BOOL bShow )
+ : m_pSocket( NULL ),
+ m_pRegion( NULL )
+{
+ if( pParent )
+ {
+ // our plug window
+ m_pSocket = gtk_drawing_area_new();
+ Show( bShow );
+ // insert into container
+ gtk_fixed_put( pParent->getFixedContainer(),
+ m_pSocket,
+ 0, 0 );
+ // realize so we can get a window id
+ gtk_widget_realize( m_pSocket );
+
+
+ // make it transparent; some plugins may not insert
+ // their own window here but use the socket window itself
+ gtk_widget_set_app_paintable( m_pSocket, TRUE );
+
+ //system data
+ SalDisplay* pDisp = GetX11SalData()->GetDisplay();
+ m_aSystemData.nSize = sizeof( SystemChildData );
+ m_aSystemData.pDisplay = pDisp->GetDisplay();
+ m_aSystemData.aWindow = GDK_WINDOW_XWINDOW(m_pSocket->window);
+ m_aSystemData.pSalFrame = NULL;
+ m_aSystemData.pWidget = m_pSocket;
+ m_aSystemData.pVisual = pDisp->GetVisual(pParent->getScreenNumber()).GetVisual();
+ m_aSystemData.nScreen = pParent->getScreenNumber();
+ m_aSystemData.nDepth = pDisp->GetVisual(pParent->getScreenNumber()).GetDepth();
+ m_aSystemData.aColormap = pDisp->GetColormap(pParent->getScreenNumber()).GetXColormap();
+ m_aSystemData.pAppContext = NULL;
+ m_aSystemData.aShellWindow = GDK_WINDOW_XWINDOW(GTK_WIDGET(pParent->getWindow())->window);
+ m_aSystemData.pShellWidget = GTK_WIDGET(pParent->getWindow());
+
+ g_signal_connect( G_OBJECT(m_pSocket), "button-press-event", G_CALLBACK(signalButton), this );
+ g_signal_connect( G_OBJECT(m_pSocket), "button-release-event", G_CALLBACK(signalButton), this );
+ g_signal_connect( G_OBJECT(m_pSocket), "focus-in-event", G_CALLBACK(signalFocus), this );
+ g_signal_connect( G_OBJECT(m_pSocket), "focus-out-event", G_CALLBACK(signalFocus), this );
+ g_signal_connect( G_OBJECT(m_pSocket), "destroy", G_CALLBACK(signalDestroy), this );
+
+ // #i59255# necessary due to sync effects with java child windows
+ pParent->Sync();
+ }
+}
+
+GtkSalObject::~GtkSalObject()
+{
+ if( m_pRegion )
+ gdk_region_destroy( m_pRegion );
+ if( m_pSocket )
+ {
+ // remove socket from parent frame's fixed container
+ gtk_container_remove( GTK_CONTAINER(gtk_widget_get_parent(m_pSocket)),
+ m_pSocket );
+ // get rid of the socket
+ // actually the gtk_container_remove should let the ref count
+ // of the socket sink to 0 and destroy it (see signalDestroy)
+ // this is just a sanity check
+ if( m_pSocket )
+ gtk_widget_destroy( m_pSocket );
+ }
+}
+
+void GtkSalObject::ResetClipRegion()
+{
+ if( m_pSocket )
+ gdk_window_shape_combine_region( m_pSocket->window, NULL, 0, 0 );
+}
+
+USHORT GtkSalObject::GetClipRegionType()
+{
+ return SAL_OBJECT_CLIP_INCLUDERECTS;
+}
+
+void GtkSalObject::BeginSetClipRegion( ULONG )
+{
+ if( m_pRegion )
+ gdk_region_destroy( m_pRegion );
+ m_pRegion = gdk_region_new();
+}
+
+void GtkSalObject::UnionClipRegion( long nX, long nY, long nWidth, long nHeight )
+{
+ GdkRectangle aRect;
+ aRect.x = nX;
+ aRect.y = nY;
+ aRect.width = nWidth;
+ aRect.height = nHeight;
+
+ gdk_region_union_with_rect( m_pRegion, &aRect );
+}
+
+void GtkSalObject::EndSetClipRegion()
+{
+ if( m_pSocket )
+ gdk_window_shape_combine_region( m_pSocket->window, m_pRegion, 0, 0 );
+}
+
+void GtkSalObject::SetPosSize( long nX, long nY, long nWidth, long nHeight )
+{
+ if( m_pSocket )
+ {
+ GtkFixed* pContainer = GTK_FIXED(gtk_widget_get_parent(m_pSocket));
+ gtk_fixed_move( pContainer, m_pSocket, nX, nY );
+ gtk_widget_set_size_request( m_pSocket, nWidth, nHeight );
+ gtk_container_resize_children( GTK_CONTAINER(pContainer) );
+ }
+}
+
+void GtkSalObject::Show( BOOL bVisible )
+{
+ if( m_pSocket )
+ {
+ if( bVisible )
+ gtk_widget_show( m_pSocket );
+ else
+ gtk_widget_hide( m_pSocket );
+ }
+}
+
+void GtkSalObject::Enable( BOOL )
+{
+}
+
+void GtkSalObject::GrabFocus()
+{
+}
+
+void GtkSalObject::SetBackground()
+{
+}
+
+void GtkSalObject::SetBackground( SalColor )
+{
+}
+
+const SystemEnvData* GtkSalObject::GetSystemData() const
+{
+ return &m_aSystemData;
+}
+
+
+gboolean GtkSalObject::signalButton( GtkWidget*, GdkEventButton* pEvent, gpointer object )
+{
+ GtkSalObject* pThis = (GtkSalObject*)object;
+
+ if( pEvent->type == GDK_BUTTON_PRESS )
+ {
+ GTK_YIELD_GRAB();
+ pThis->CallCallback( SALOBJ_EVENT_TOTOP, NULL );
+ }
+
+ return FALSE;
+}
+
+gboolean GtkSalObject::signalFocus( GtkWidget*, GdkEventFocus* pEvent, gpointer object )
+{
+ GtkSalObject* pThis = (GtkSalObject*)object;
+
+ GTK_YIELD_GRAB();
+
+ pThis->CallCallback( pEvent->in ? SALOBJ_EVENT_GETFOCUS : SALOBJ_EVENT_LOSEFOCUS, NULL );
+
+ return FALSE;
+}
+
+void GtkSalObject::signalDestroy( GtkObject* pObj, gpointer object )
+{
+ GtkSalObject* pThis = (GtkSalObject*)object;
+ if( GTK_WIDGET(pObj) == pThis->m_pSocket )
+ {
+ pThis->m_pSocket = NULL;
+ }
+}
+
+void GtkSalObject::InterceptChildWindowKeyDown( sal_Bool /*bIntercept*/ )
+{
+}
+
diff --git a/vcl/unx/gtk/window/makefile.mk b/vcl/unx/gtk/window/makefile.mk
new file mode 100644
index 000000000000..ac23e9363eef
--- /dev/null
+++ b/vcl/unx/gtk/window/makefile.mk
@@ -0,0 +1,79 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#*************************************************************************
+
+PRJ=..$/..$/..
+
+PRJNAME=vcl
+TARGET=gtkwin
+.INCLUDE : $(PRJ)$/util$/makefile.pmk
+
+# workaround for makedepend hang
+MKDEPENDSOLVER=
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+.INCLUDE : $(PRJ)$/util$/makefile2.pmk
+
+# --- Files --------------------------------------------------------
+
+.IF "$(GUIBASE)"!="unx"
+
+dummy:
+ @echo "Nothing to build for GUIBASE $(GUIBASE)"
+
+.ELSE # "$(GUIBASE)"!="unx"
+
+.IF "$(ENABLE_GTK)" != ""
+
+PKGCONFIG_MODULES=gtk+-2.0
+.IF "$(ENABLE_DBUS)" != ""
+CDEFS+=-DENABLE_DBUS
+PKGCONFIG_MODULES+= dbus-glib-1
+.ENDIF
+.INCLUDE : pkg_config.mk
+
+.IF "$(COM)" == "C52"
+NOOPTFILES=$(SLO)$/gtkframe.obj
+.ENDIF
+
+SLOFILES=\
+ $(SLO)$/gtkframe.obj \
+ $(SLO)$/gtkobject.obj
+EXCEPTIONSFILES=$(SLO)$/gtkframe.obj
+.ELSE # "$(ENABLE_GTK)" != ""
+
+dummy:
+ @echo GTK disabled - nothing to build
+.ENDIF
+.ENDIF # "$(GUIBASE)"!="unx"
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
+
+.INCLUDE : $(PRJ)$/util$/target.pmk