[Libreoffice-commits] core.git: Branch 'feature/kde5' - vcl/CustomTarget_kde5_moc.mk vcl/Library_vclplug_kde5.mk vcl/Module_vcl.mk vcl/unx

Katarina Behrens Katarina.Behrens at cib.de
Thu Sep 7 13:28:11 UTC 2017


 vcl/CustomTarget_kde5_moc.mk                  |   23 
 vcl/Library_vclplug_kde5.mk                   |   96 ++
 vcl/Module_vcl.mk                             |    6 
 vcl/unx/kde5/FPServiceInfo.hxx                |   28 
 vcl/unx/kde5/KDE5Data.cxx                     |   68 +
 vcl/unx/kde5/KDE5Data.hxx                     |   37 
 vcl/unx/kde5/KDE5SalDisplay.cxx               |   98 ++
 vcl/unx/kde5/KDE5SalDisplay.hxx               |   47 +
 vcl/unx/kde5/KDE5SalFrame.cxx                 |  381 +++++++++
 vcl/unx/kde5/KDE5SalFrame.hxx                 |   53 +
 vcl/unx/kde5/KDE5SalGraphics.cxx              | 1020 ++++++++++++++++++++++++++
 vcl/unx/kde5/KDE5SalGraphics.hxx              |   53 +
 vcl/unx/kde5/KDE5SalInstance.cxx              |   70 +
 vcl/unx/kde5/KDE5SalInstance.hxx              |   45 +
 vcl/unx/kde5/KDE5XLib.cxx                     |  407 ++++++++++
 vcl/unx/kde5/KDE5XLib.hxx                     |  102 ++
 vcl/unx/kde5/VCLKDE5Application.cxx           |   75 +
 vcl/unx/kde5/VCLKDE5Application.hxx           |   40 +
 vcl/unx/kde5/main.cxx                         |   88 ++
 vcl/unx/kde5/tst_exclude_posted_events.hxx    |   67 +
 vcl/unx/kde5/tst_exclude_socket_notifiers.hxx |   67 +
 21 files changed, 2871 insertions(+)

New commits:
commit 5c561c13652838e373e520e8438c2787e8f1fb19
Author: Katarina Behrens <Katarina.Behrens at cib.de>
Date:   Mon Aug 28 18:29:20 2017 +0200

    Copy basic kde4 blocks -> kde5 and build againt qt5/kf5 libs
    
    Change-Id: I70f0c4147721a20459e1183ff40cf0ac8adf49e6

diff --git a/vcl/CustomTarget_kde5_moc.mk b/vcl/CustomTarget_kde5_moc.mk
new file mode 100644
index 000000000000..2c8540cb065a
--- /dev/null
+++ b/vcl/CustomTarget_kde5_moc.mk
@@ -0,0 +1,23 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_CustomTarget_CustomTarget,vcl/unx/kde5))
+
+$(call gb_CustomTarget_get_target,vcl/unx/kde5) : \
+	$(call gb_CustomTarget_get_workdir,vcl/unx/kde5)/KDE5XLib.moc \
+	$(call gb_CustomTarget_get_workdir,vcl/unx/kde5)/tst_exclude_socket_notifiers.moc \
+	$(call gb_CustomTarget_get_workdir,vcl/unx/kde5)/tst_exclude_posted_events.moc
+
+$(call gb_CustomTarget_get_workdir,vcl/unx/kde5)/%.moc : \
+		$(SRCDIR)/vcl/unx/kde5/%.hxx \
+		| $(call gb_CustomTarget_get_workdir,vcl/unx/kde5)/.dir
+	$(call gb_Output_announce,$(subst $(WORKDIR)/,,$@),$(true),MOC,1)
+	$(MOC5) $< -o $@
+
+# vim: set noet sw=4:
diff --git a/vcl/Library_vclplug_kde5.mk b/vcl/Library_vclplug_kde5.mk
new file mode 100644
index 000000000000..7775fbf9a71a
--- /dev/null
+++ b/vcl/Library_vclplug_kde5.mk
@@ -0,0 +1,96 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This file incorporates work covered by the following license notice:
+#
+#   Licensed to the Apache Software Foundation (ASF) under one or more
+#   contributor license agreements. See the NOTICE file distributed
+#   with this work for additional information regarding copyright
+#   ownership. The ASF licenses this file to you under the Apache
+#   License, Version 2.0 (the "License"); you may not use this file
+#   except in compliance with the License. You may obtain a copy of
+#   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+#
+
+$(eval $(call gb_Library_Library,vclplug_kde5))
+
+$(eval $(call gb_Library_use_custom_headers,vclplug_kde5,vcl/unx/kde5))
+
+$(eval $(call gb_Library_set_include,vclplug_kde5,\
+    $$(INCLUDE) \
+    -I$(SRCDIR)/vcl/inc \
+))
+
+$(eval $(call gb_Library_add_defs,vclplug_kde5,\
+    -DVCLPLUG_KDE5_IMPLEMENTATION \
+))
+
+$(eval $(call gb_Library_use_sdk_api,vclplug_kde5))
+
+$(eval $(call gb_Library_use_libraries,vclplug_kde5,\
+    vclplug_gen \
+    vcl \
+    tl \
+    utl \
+    sot \
+    ucbhelper \
+    basegfx \
+    comphelper \
+    cppuhelper \
+    i18nlangtag \
+    i18nutil \
+    $(if $(ENABLE_JAVA), \
+        jvmaccess) \
+    cppu \
+    sal \
+))
+
+$(eval $(call gb_Library_use_externals,vclplug_kde5,\
+	boost_headers \
+	icuuc \
+	kde5 \
+	epoxy \
+))
+
+$(eval $(call gb_Library_add_libs,vclplug_kde5,\
+	-lX11 \
+	-lXext \
+	-lSM \
+	-lICE \
+))
+
+ifneq ($(KF5_HAVE_GLIB),)
+$(eval $(call gb_Library_add_defs,vclplug_kde5,\
+    $(KF5_GLIB_CFLAGS) \
+))
+
+$(eval $(call gb_Library_add_libs,vclplug_kde5,\
+    $(KF5_GLIB_LIBS) \
+))
+endif
+
+
+$(eval $(call gb_Library_add_exception_objects,vclplug_kde5,\
+    vcl/unx/kde5/KDE5Data \
+    vcl/unx/kde5/KDE5SalDisplay \
+    vcl/unx/kde5/KDE5SalFrame \
+    vcl/unx/kde5/KDE5SalGraphics \
+    vcl/unx/kde5/KDE5SalInstance \
+    vcl/unx/kde5/KDE5XLib \
+    vcl/unx/kde5/main \
+))
+
+ifeq ($(OS),LINUX)
+$(eval $(call gb_Library_add_libs,vclplug_kde5,\
+	-lm \
+	-ldl \
+	-lpthread \
+))
+endif
+
+# vim: set noet sw=4 ts=4:
diff --git a/vcl/Module_vcl.mk b/vcl/Module_vcl.mk
index 086328dbf466..a8159d5dd083 100644
--- a/vcl/Module_vcl.mk
+++ b/vcl/Module_vcl.mk
@@ -81,6 +81,12 @@ $(eval $(call gb_Module_add_targets,vcl,\
     Library_vclplug_kde4 \
 ))
 endif
+ifneq ($(ENABLE_KDE5),)
+$(eval $(call gb_Module_add_targets,vcl,\
+    CustomTarget_kde5_moc \
+    Library_vclplug_kde5 \
+))
+endif
 endif
 
 ifeq ($(OS),MACOSX)
diff --git a/vcl/unx/kde5/FPServiceInfo.hxx b/vcl/unx/kde5/FPServiceInfo.hxx
new file mode 100644
index 000000000000..fdb285144343
--- /dev/null
+++ b/vcl/unx/kde5/FPServiceInfo.hxx
@@ -0,0 +1,28 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+// the service names
+#define FILE_PICKER_SERVICE_NAME "com.sun.star.ui.dialogs.KDE4FilePicker"
+
+// the implementation names
+#define FILE_PICKER_IMPL_NAME    "com.sun.star.ui.dialogs.KDE4FilePicker"
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/kde5/KDE5Data.cxx b/vcl/unx/kde5/KDE5Data.cxx
new file mode 100644
index 000000000000..487a0b254af3
--- /dev/null
+++ b/vcl/unx/kde5/KDE5Data.cxx
@@ -0,0 +1,68 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <QtWidgets/QStyle>
+#include <QtWidgets/QApplication>
+
+#undef Region
+
+#include "KDE5Data.hxx"
+
+#include "KDE5XLib.hxx"
+#include "KDE5SalDisplay.hxx"
+
+KDEData::~KDEData()
+{
+}
+
+void KDEData::Init()
+{
+    pXLib_ = new KDEXLib();
+    pXLib_->Init();
+    SetDisplay( SalKDEDisplay::self() );
+}
+
+void KDEData::initNWF()
+{
+    ImplSVData *pSVData = ImplGetSVData();
+
+    // draw toolbars on separate lines
+    pSVData->maNWFData.mbDockingAreaSeparateTB = true;
+    // no borders for menu, theming does that
+    pSVData->maNWFData.mbFlatMenu = true;
+    // Qt theme engines may support a rollover menubar
+    pSVData->maNWFData.mbRolloverMenubar = true;
+
+    pSVData->maNWFData.mbNoFocusRects = true;
+
+    // Styled menus need additional space
+    QStyle *style = QApplication::style();
+    pSVData->maNWFData.mnMenuFormatBorderX =
+       style->pixelMetric( QStyle::PM_MenuPanelWidth ) +
+       style->pixelMetric( QStyle::PM_MenuHMargin );
+    pSVData->maNWFData.mnMenuFormatBorderY =
+       style->pixelMetric( QStyle::PM_MenuPanelWidth ) +
+       style->pixelMetric( QStyle::PM_MenuVMargin );
+}
+
+void KDEData::deInitNWF()
+{
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/kde5/KDE5Data.hxx b/vcl/unx/kde5/KDE5Data.hxx
new file mode 100644
index 000000000000..4efd23a7df34
--- /dev/null
+++ b/vcl/unx/kde5/KDE5Data.hxx
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <unx/saldisp.hxx>
+#include <unx/saldata.hxx>
+
+class KDEData : public X11SalData
+{
+    public:
+        explicit KDEData( SalInstance *pInstance )
+                        : X11SalData( SAL_DATA_KDE4, pInstance ) {}
+        virtual ~KDEData() override;
+
+        virtual void Init() override;
+        virtual void initNWF() override;
+        virtual void deInitNWF() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/kde5/KDE5SalDisplay.cxx b/vcl/unx/kde5/KDE5SalDisplay.cxx
new file mode 100644
index 000000000000..eddac063048f
--- /dev/null
+++ b/vcl/unx/kde5/KDE5SalDisplay.cxx
@@ -0,0 +1,98 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "VCLKDE5Application.hxx"
+#include "KDE5SalDisplay.hxx"
+
+#ifdef Bool
+#undef Bool
+#endif
+
+#include "KDE5XLib.hxx"
+
+#include <assert.h>
+
+SalKDEDisplay* SalKDEDisplay::selfptr = nullptr;
+
+SalKDEDisplay::SalKDEDisplay( Display* pDisp )
+    : SalX11Display( pDisp )
+{
+    assert( selfptr == nullptr );
+    selfptr = this;
+    xim_protocol = XInternAtom( pDisp_, "_XIM_PROTOCOL", False );
+}
+
+SalKDEDisplay::~SalKDEDisplay()
+{
+    // in case never a frame opened
+    static_cast<KDEXLib*>(GetXLib())->doStartup();
+    // clean up own members
+    doDestruct();
+    selfptr = nullptr;
+    // prevent SalDisplay from closing KApplication's display
+    pDisp_ = nullptr;
+}
+
+void SalKDEDisplay::Yield()
+{
+    if( DispatchInternalEvent() )
+        return;
+
+    // Prevent blocking from Drag'n'Drop events, which may have already have processed the event
+    if (XEventsQueued( pDisp_, QueuedAfterReading ) == 0)
+        return;
+
+    DBG_ASSERT( static_cast<SalYieldMutex*>(GetSalData()->m_pInstance->GetYieldMutex())->GetThreadId() ==
+                osl::Thread::getCurrentIdentifier(),
+                "will crash soon since solar mutex not locked in SalKDEDisplay::Yield" );
+
+    /*XEvent event;
+    XNextEvent( pDisp_, &event );
+    if( checkDirectInputEvent( &event ))
+        return;
+    qApp->x11ProcessEvent( &event );*/
+}
+
+// HACK: When using Qt event loop, input methods (japanese, etc.) will get broken because
+// of XFilterEvent() getting called twice, once by Qt, once by LO (bnc#665112).
+// This function is therefore called before any XEvent is passed to Qt event handling
+// and if it is a keyboard event and no Qt widget is the active window (i.e. we are
+// processing events for some LO window), then feed the event only to LO directly and skip Qt
+// completely. Skipped events are KeyPress, KeyRelease and also _XIM_PROTOCOL client message
+// (seems to be necessary too, hopefully there are not other internal XIM messages that
+// would need this handling).
+bool SalKDEDisplay::checkDirectInputEvent( xcb_generic_event_t* ev )
+{
+    switch (ev->response_type & ~0x80)
+    {
+        case XCB_CLIENT_MESSAGE:
+        case XCB_KEY_PRESS:
+        case XCB_KEY_RELEASE:
+            if( QApplication::activeWindow() == nullptr )
+            {
+//                Dispatch(ev);
+                return true;
+            }
+            break;
+    }
+    return false;
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/kde5/KDE5SalDisplay.hxx b/vcl/unx/kde5/KDE5SalDisplay.hxx
new file mode 100644
index 000000000000..0a31dcedc10d
--- /dev/null
+++ b/vcl/unx/kde5/KDE5SalDisplay.hxx
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <unx/saldisp.hxx>
+#include <xcb/xcb.h>
+
+#ifdef CursorShape
+#undef CursorShape
+#endif
+
+class SalKDEDisplay : public SalX11Display
+{
+    public:
+        explicit SalKDEDisplay( Display* pDisp );
+        virtual ~SalKDEDisplay() override;
+        static SalKDEDisplay* self();
+        virtual void Yield() override;
+        bool checkDirectInputEvent( xcb_generic_event_t* ev );
+    private:
+        Atom xim_protocol;
+        static SalKDEDisplay* selfptr;
+};
+
+inline SalKDEDisplay* SalKDEDisplay::self()
+{
+    return selfptr;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/kde5/KDE5SalFrame.cxx b/vcl/unx/kde5/KDE5SalFrame.cxx
new file mode 100644
index 000000000000..090abbc240d1
--- /dev/null
+++ b/vcl/unx/kde5/KDE5SalFrame.cxx
@@ -0,0 +1,381 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <memory>
+#include <QtGui/QColor>
+#include <QtWidgets/QStyle>
+#include <QtCore/QDebug>
+#include <QtWidgets/QToolTip>
+#include <QtWidgets/QApplication>
+#include <QtWidgets/QMenuBar>
+
+#include <KConfig>
+#include <KConfigGroup>
+#include <KSharedConfig>
+
+#undef Region
+
+#include "KDE5SalFrame.hxx"
+#include "KDE5XLib.hxx"
+#include "KDE5SalGraphics.hxx"
+
+#include <tools/color.hxx>
+
+#include <vcl/font.hxx>
+#include <vcl/settings.hxx>
+
+#include "unx/fontmanager.hxx"
+
+#include <svdata.hxx>
+
+#include <boost/optional.hpp>
+
+
+KDESalFrame::KDESalFrame( SalFrame* pParent, SalFrameStyleFlags nState ) :
+    X11SalFrame( pParent, nState )
+{
+}
+
+void KDESalFrame::Show( bool bVisible, bool bNoActivate )
+{
+    if ( !GetParent() && ! (GetStyle() & SalFrameStyleFlags::INTRO) )
+    {
+        KDEXLib* pXLib = static_cast<KDEXLib*>(GetDisplay()->GetXLib());
+        pXLib->doStartup();
+    }
+
+    X11SalFrame::Show( bVisible, bNoActivate );
+}
+
+/** Helper function to convert colors.
+*/
+static Color toColor( const QColor &rColor )
+{
+    return Color( rColor.red(), rColor.green(), rColor.blue() );
+}
+
+
+/** Helper function to add information to Font from QFont.
+
+    Mostly grabbed from the Gtk+ vclplug (salnativewidgets-gtk.cxx).
+*/
+static vcl::Font toFont( const QFont &rQFont, const css::lang::Locale& rLocale )
+{
+    psp::FastPrintFontInfo aInfo;
+    QFontInfo qFontInfo( rQFont );
+
+    // set family name
+    aInfo.m_aFamilyName = OUString( static_cast<const char *>(rQFont.family().toUtf8()), strlen( static_cast<const char *>(rQFont.family().toUtf8()) ), RTL_TEXTENCODING_UTF8 );
+
+    // set italic
+    aInfo.m_eItalic = ( qFontInfo.italic()? ITALIC_NORMAL: ITALIC_NONE );
+
+    // set weight
+    int nWeight = qFontInfo.weight();
+    if ( nWeight <= QFont::Light )
+        aInfo.m_eWeight = WEIGHT_LIGHT;
+    else if ( nWeight <= QFont::Normal )
+        aInfo.m_eWeight = WEIGHT_NORMAL;
+    else if ( nWeight <= QFont::DemiBold )
+        aInfo.m_eWeight = WEIGHT_SEMIBOLD;
+    else if ( nWeight <= QFont::Bold )
+        aInfo.m_eWeight = WEIGHT_BOLD;
+    else
+        aInfo.m_eWeight = WEIGHT_ULTRABOLD;
+
+    // set width
+    int nStretch = rQFont.stretch();
+    if ( nStretch <= QFont::UltraCondensed )
+        aInfo.m_eWidth = WIDTH_ULTRA_CONDENSED;
+    else if ( nStretch <= QFont::ExtraCondensed )
+        aInfo.m_eWidth = WIDTH_EXTRA_CONDENSED;
+    else if ( nStretch <= QFont::Condensed )
+        aInfo.m_eWidth = WIDTH_CONDENSED;
+    else if ( nStretch <= QFont::SemiCondensed )
+        aInfo.m_eWidth = WIDTH_SEMI_CONDENSED;
+    else if ( nStretch <= QFont::Unstretched )
+        aInfo.m_eWidth = WIDTH_NORMAL;
+    else if ( nStretch <= QFont::SemiExpanded )
+        aInfo.m_eWidth = WIDTH_SEMI_EXPANDED;
+    else if ( nStretch <= QFont::Expanded )
+        aInfo.m_eWidth = WIDTH_EXPANDED;
+    else if ( nStretch <= QFont::ExtraExpanded )
+        aInfo.m_eWidth = WIDTH_EXTRA_EXPANDED;
+    else
+        aInfo.m_eWidth = WIDTH_ULTRA_EXPANDED;
+
+    SAL_INFO( "vcl.kde4", "font name BEFORE system match: \"" << aInfo.m_aFamilyName << "\"" );
+
+    // match font to e.g. resolve "Sans"
+    psp::PrintFontManager::get().matchFont( aInfo, rLocale );
+
+    SAL_INFO( "vcl.kde4", "font match " <<
+              (aInfo.m_nID != 0 ? "succeeded" : "failed") <<
+              ", name AFTER: \"" << aInfo.m_aFamilyName << "\"" );
+
+    // font height
+    int nPointHeight = qFontInfo.pointSize();
+    if ( nPointHeight <= 0 )
+        nPointHeight = rQFont.pointSize();
+
+    // Create the font
+    vcl::Font aFont( aInfo.m_aFamilyName, Size( 0, nPointHeight ) );
+    if( aInfo.m_eWeight != WEIGHT_DONTKNOW )
+        aFont.SetWeight( aInfo.m_eWeight );
+    if( aInfo.m_eWidth != WIDTH_DONTKNOW )
+        aFont.SetWidthType( aInfo.m_eWidth );
+    if( aInfo.m_eItalic != ITALIC_DONTKNOW )
+        aFont.SetItalic( aInfo.m_eItalic );
+    if( aInfo.m_ePitch != PITCH_DONTKNOW )
+        aFont.SetPitch( aInfo.m_ePitch );
+
+    return aFont;
+}
+
+/** Implementation of KDE integration's main method.
+*/
+void KDESalFrame::UpdateSettings( AllSettings& rSettings )
+{
+    StyleSettings style( rSettings.GetStyleSettings() );
+    bool bSetTitleFont = false;
+
+    // General settings
+    QPalette pal = QApplication::palette();
+
+    style.SetToolbarIconSize( ToolbarIconSize::Large );
+
+    style.SetActiveColor(toColor(pal.color(QPalette::Active, QPalette::Window)));
+    style.SetDeactiveColor(toColor(pal.color(QPalette::Inactive, QPalette::Window)));
+
+    style.SetActiveTextColor(toColor(pal.color(QPalette::Active, QPalette::WindowText)));
+    style.SetDeactiveTextColor(toColor(pal.color(QPalette::Inactive, QPalette::WindowText)));
+
+    // WM settings
+    /*KConfig *pConfig = KGlobal::config().data();
+    if ( pConfig )
+    {
+        const char *pKey;
+
+        {
+            KConfigGroup aWMGroup = pConfig->group( "WM" );
+
+            pKey = "titleFont";
+            if (aWMGroup.hasKey(pKey))
+            {
+                vcl::Font aFont = toFont(aWMGroup.readEntry(pKey, QFont()),
+                                         rSettings.GetUILanguageTag().getLocale());
+                style.SetTitleFont( aFont );
+                bSetTitleFont = true;
+            }
+        }
+
+        KConfigGroup aIconsGroup = pConfig->group("Icons");
+
+        pKey = "Theme";
+        if (aIconsGroup.hasKey(pKey))
+            style.SetPreferredIconTheme( readEntryUntranslated(&aIconsGroup, pKey));
+
+        //toolbar
+        pKey = "toolbarFont";
+        if (aIconsGroup.hasKey(pKey))
+        {
+            vcl::Font aFont = toFont(aIconsGroup.readEntry(pKey, QFont()),
+                                     rSettings.GetUILanguageTag().getLocale());
+            style.SetToolFont( aFont );
+        }
+    }*/
+
+    Color aFore = toColor( pal.color( QPalette::Active, QPalette::WindowText ) );
+    Color aBack = toColor( pal.color( QPalette::Active, QPalette::Window ) );
+    Color aText = toColor( pal.color( QPalette::Active, QPalette::Text ) );
+    Color aBase = toColor( pal.color( QPalette::Active, QPalette::Base ) );
+    Color aButn = toColor( pal.color( QPalette::Active, QPalette::ButtonText ) );
+    Color aMid = toColor( pal.color( QPalette::Active, QPalette::Mid ) );
+    Color aHigh = toColor( pal.color( QPalette::Active, QPalette::Highlight ) );
+    Color aHighText = toColor( pal.color( QPalette::Active, QPalette::HighlightedText ) );
+
+    style.SetSkipDisabledInMenus( true );
+
+    // Foreground
+    style.SetRadioCheckTextColor( aFore );
+    style.SetLabelTextColor( aFore );
+    style.SetDialogTextColor( aFore );
+    style.SetGroupTextColor( aFore );
+
+    // Text
+    style.SetFieldTextColor( aText );
+    style.SetFieldRolloverTextColor( aText );
+    style.SetWindowTextColor( aText );
+    style.SetToolTextColor( aText );
+
+    // Base
+    style.SetFieldColor( aBase );
+    style.SetWindowColor( aBase );
+    style.SetActiveTabColor( aBase );
+
+    // Buttons
+    style.SetButtonTextColor( aButn );
+    style.SetButtonRolloverTextColor( aButn );
+
+    // Tabs
+    style.SetTabTextColor( aButn );
+    style.SetTabRolloverTextColor( aButn );
+    style.SetTabHighlightTextColor( aButn );
+
+    // Disable color
+    style.SetDisableColor( toColor( pal.color( QPalette::Disabled, QPalette::WindowText ) ) );
+
+    // Workspace
+    style.SetWorkspaceColor( aMid );
+
+    // Background
+    style.Set3DColors( aBack );
+    style.SetFaceColor( aBack );
+    style.SetInactiveTabColor( aBack );
+    style.SetDialogColor( aBack );
+    style.SetCheckedColorSpecialCase( );
+
+    // Selection
+    style.SetHighlightColor( aHigh );
+    style.SetHighlightTextColor( aHighText );
+
+    // Tooltip
+    style.SetHelpColor( toColor( QToolTip::palette().color( QPalette::Active, QPalette::ToolTipBase )));
+    style.SetHelpTextColor( toColor( QToolTip::palette().color( QPalette::Active, QPalette::ToolTipText )));
+
+    // Font
+    vcl::Font aFont = toFont( QApplication::font(), rSettings.GetUILanguageTag().getLocale() );
+
+    style.SetAppFont( aFont );
+
+    style.SetMenuFont( aFont ); // will be changed according to pMenuBar
+    style.SetLabelFont( aFont );
+    style.SetRadioCheckFont( aFont );
+    style.SetPushButtonFont( aFont );
+    style.SetFieldFont( aFont );
+    style.SetIconFont( aFont );
+    style.SetTabFont( aFont );
+    style.SetGroupFont( aFont );
+
+    aFont.SetWeight( WEIGHT_BOLD );
+    if( !bSetTitleFont )
+    {
+        style.SetTitleFont( aFont );
+    }
+    style.SetFloatTitleFont( aFont );
+
+    style.SetHelpFont( toFont( QToolTip::font(), rSettings.GetUILanguageTag().getLocale()));
+
+    int flash_time = QApplication::cursorFlashTime();
+    style.SetCursorBlinkTime( flash_time != 0 ? flash_time/2 : STYLE_CURSOR_NOBLINKTIME );
+
+    // Menu
+    std::unique_ptr<QMenuBar> pMenuBar = std::unique_ptr<QMenuBar>( new QMenuBar() );
+    QPalette qMenuCG = pMenuBar->palette();
+
+    // Menu text and background color, theme specific
+    Color aMenuFore = toColor( qMenuCG.color( QPalette::WindowText ) );
+    Color aMenuBack = toColor( qMenuCG.color( QPalette::Window ) );
+
+    style.SetMenuTextColor( aMenuFore );
+    style.SetMenuBarTextColor( style.GetPersonaMenuBarTextColor().get_value_or( aMenuFore ) );
+    style.SetMenuColor( aMenuBack );
+    style.SetMenuBarColor( aMenuBack );
+    style.SetMenuHighlightColor( toColor ( qMenuCG.color( QPalette::Highlight ) ) );
+    style.SetMenuHighlightTextColor( toColor ( qMenuCG.color( QPalette::HighlightedText ) ) );
+
+    // set special menubar highlight text color
+    if ( QApplication::style()->inherits( "HighContrastStyle" ) )
+        ImplGetSVData()->maNWFData.maMenuBarHighlightTextColor = toColor( qMenuCG.color( QPalette::HighlightedText ) );
+    else
+        ImplGetSVData()->maNWFData.maMenuBarHighlightTextColor = aMenuFore;
+
+    // set menubar rollover color
+    if ( pMenuBar->style()->styleHint( QStyle::SH_MenuBar_MouseTracking ) )
+    {
+        style.SetMenuBarRolloverColor( toColor ( qMenuCG.color( QPalette::Highlight ) ) );
+        style.SetMenuBarRolloverTextColor( ImplGetSVData()->maNWFData.maMenuBarHighlightTextColor );
+    }
+    else
+    {
+        style.SetMenuBarRolloverColor( aMenuBack );
+        style.SetMenuBarRolloverTextColor( aMenuFore );
+    }
+    style.SetMenuBarHighlightTextColor(style.GetMenuHighlightTextColor());
+
+    // Font
+    aFont = toFont( pMenuBar->font(), rSettings.GetUILanguageTag().getLocale() );
+    style.SetMenuFont( aFont );
+
+    // Scroll bar size
+    style.SetScrollBarSize( QApplication::style()->pixelMetric( QStyle::PM_ScrollBarExtent ) );
+    style.SetMinThumbSize( QApplication::style()->pixelMetric( QStyle::PM_ScrollBarSliderMin ));
+
+    // These colors are used for the ruler text and marks
+    style.SetShadowColor(toColor(pal.color(QPalette::Disabled, QPalette::WindowText)));
+    style.SetDarkShadowColor(toColor(pal.color(QPalette::Inactive, QPalette::WindowText)));
+
+    rSettings.SetStyleSettings( style );
+}
+
+void KDESalFrame::ReleaseGraphics( SalGraphics *pGraphics )
+{
+    for( int i = 0; i < nMaxGraphics; i++ )
+    {
+        if( m_aGraphics[i].pGraphics.get() == pGraphics )
+        {
+            m_aGraphics[i].bInUse = false;
+            break;
+        }
+    }
+}
+
+void KDESalFrame::updateGraphics( bool bClear )
+{
+    Drawable aDrawable = bClear ? None : GetWindow();
+    for( int i = 0; i < nMaxGraphics; i++ )
+    {
+        if( m_aGraphics[i].bInUse )
+            m_aGraphics[i].pGraphics->SetDrawable( aDrawable, GetScreenNumber() );
+    }
+}
+
+SalGraphics* KDESalFrame::AcquireGraphics()
+{
+    if( GetWindow() )
+    {
+        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.reset( new KDESalGraphics );
+                    m_aGraphics[i].pGraphics->Init( this, GetWindow(), GetScreenNumber() );
+                }
+                return m_aGraphics[i].pGraphics.get();
+            }
+        }
+    }
+
+    return nullptr;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/kde5/KDE5SalFrame.hxx b/vcl/unx/kde5/KDE5SalFrame.hxx
new file mode 100644
index 000000000000..114cd49bd8d2
--- /dev/null
+++ b/vcl/unx/kde5/KDE5SalFrame.hxx
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <memory>
+
+#include <unx/saldisp.hxx>
+#include <unx/salframe.h>
+#include <unx/salgdi.h>
+
+class KDESalFrame : public X11SalFrame
+{
+    private:
+        static const int nMaxGraphics = 2;
+
+        struct GraphicsHolder
+        {
+            std::unique_ptr<X11SalGraphics> pGraphics;
+            bool bInUse;
+
+            GraphicsHolder() : bInUse( false ) {}
+        };
+
+        GraphicsHolder m_aGraphics[ nMaxGraphics ];
+
+    public:
+        KDESalFrame( SalFrame* pParent, SalFrameStyleFlags nStyle );
+
+        virtual SalGraphics* AcquireGraphics() override;
+        virtual void ReleaseGraphics( SalGraphics *pGraphics ) override;
+        virtual void updateGraphics( bool bClear ) override;
+        virtual void UpdateSettings( AllSettings& rSettings ) override;
+        virtual void Show( bool bVisible, bool bNoActivate = false ) override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/kde5/KDE5SalGraphics.cxx b/vcl/unx/kde5/KDE5SalGraphics.cxx
new file mode 100644
index 000000000000..85642f6f91df
--- /dev/null
+++ b/vcl/unx/kde5/KDE5SalGraphics.cxx
@@ -0,0 +1,1020 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <QtGui/QPainter>
+#include <QtWidgets/QApplication>
+#include <QtWidgets/QStyle>
+#include <QtWidgets/QStyleOption>
+#include <QtWidgets/QFrame>
+#include <QtWidgets/QLabel>
+
+#undef Region
+
+#include "KDE5SalGraphics.hxx"
+#include "KDE5SalInstance.hxx"
+
+#include <vcl/settings.hxx>
+#include <vcl/decoview.hxx>
+#include <rtl/ustrbuf.hxx>
+
+/**
+  Conversion function between VCL ControlState together with
+  ImplControlValue and Qt state flags.
+  @param nControlState State of the widget (default, focused, ...) in Native Widget Framework.
+  @param aValue Value held by the widget (on, off, ...)
+*/
+QStyle::State vclStateValue2StateFlag( ControlState nControlState,
+    const ImplControlValue& aValue )
+{
+    QStyle::State nState =
+        ( (nControlState & ControlState::ENABLED)?  QStyle::State_Enabled:   QStyle::State_None ) |
+        ( (nControlState & ControlState::FOCUSED)?  QStyle::State_HasFocus:  QStyle::State_None ) |
+        ( (nControlState & ControlState::PRESSED)?  QStyle::State_Sunken:    QStyle::State_None ) |
+        ( (nControlState & ControlState::SELECTED)? QStyle::State_Selected : QStyle::State_None ) |
+        ( (nControlState & ControlState::ROLLOVER)? QStyle::State_MouseOver: QStyle::State_None );
+
+    switch ( aValue.getTristateVal() )
+    {
+        case ButtonValue::On:    nState |= QStyle::State_On;       break;
+        case ButtonValue::Off:   nState |= QStyle::State_Off;      break;
+        case ButtonValue::Mixed: nState |= QStyle::State_NoChange; break;
+        default: break;
+    }
+
+    return nState;
+}
+
+/**
+ Convert tools::Rectangle to QRect.
+ @param rControlRegion The tools::Rectangle to convert.
+ @return The matching QRect
+*/
+QRect region2QRect( const tools::Rectangle& rControlRegion )
+{
+    return QRect(rControlRegion.Left(), rControlRegion.Top(), rControlRegion.GetWidth(), rControlRegion.GetHeight());
+}
+
+bool KDESalGraphics::IsNativeControlSupported( ControlType type, ControlPart part )
+{
+    switch (type)
+    {
+        case ControlType::Pushbutton:
+        case ControlType::Radiobutton:
+        case ControlType::Checkbox:
+        case ControlType::Tooltip:
+        case ControlType::Progress:
+        case ControlType::ListNode:
+            return (part == ControlPart::Entire);
+
+        case ControlType::Menubar:
+        case ControlType::MenuPopup:
+        case ControlType::Editbox:
+        case ControlType::MultilineEditbox:
+        case ControlType::Combobox:
+        case ControlType::Toolbar:
+        case ControlType::Frame:
+        case ControlType::Scrollbar:
+        case ControlType::WindowBackground:
+        case ControlType::Fixedline:
+            return true;
+
+        case ControlType::Listbox:
+            return (part == ControlPart::Entire || part == ControlPart::HasBackgroundTexture);
+
+        case ControlType::Spinbox:
+            return (part == ControlPart::Entire || part == ControlPart::HasBackgroundTexture);
+
+        case ControlType::Slider:
+            return (part == ControlPart::TrackHorzArea || part == ControlPart::TrackVertArea);
+
+        default:
+            break;
+    }
+
+    return false;
+}
+
+/// helper drawing methods
+namespace
+{
+    void draw( QStyle::ControlElement element, QStyleOption* option, QImage* image, QStyle::State const & state, QRect rect = QRect())
+    {
+        option->state |= state;
+        option->rect = !rect.isNull() ? rect : image->rect();
+
+        QPainter painter(image);
+        QApplication::style()->drawControl(element, option, &painter);
+    }
+
+    void draw( QStyle::PrimitiveElement element, QStyleOption* option, QImage* image, QStyle::State const & state, QRect rect = QRect())
+    {
+        option->state |= state;
+        option->rect = !rect.isNull() ? rect : image->rect();
+
+        QPainter painter(image);
+        QApplication::style()->drawPrimitive(element, option, &painter);
+    }
+
+    void draw( QStyle::ComplexControl element, QStyleOptionComplex* option, QImage* image, QStyle::State const & state )
+    {
+        option->state |= state;
+        option->rect = image->rect();
+
+        QPainter painter(image);
+        QApplication::style()->drawComplexControl(element, option, &painter);
+    }
+
+    void lcl_drawFrame( QStyle::PrimitiveElement element, QImage* image, QStyle::State const & state,
+                        QStyle::PixelMetric eLineMetric = QStyle::PM_DefaultFrameWidth )
+    {
+    #if ( QT_VERSION >= QT_VERSION_CHECK( 4, 5, 0 ) )
+        QStyleOptionFrameV3 option;
+        option.frameShape = QFrame::StyledPanel;
+        option.state = QStyle::State_Sunken;
+        option.lineWidth = QApplication::style()->pixelMetric( eLineMetric );
+    #else
+        QStyleOptionFrame option;
+
+        QFrame aFrame( nullptr );
+        aFrame.setFrameRect( QRect(0, 0, image->width(), image->height()) );
+        aFrame.setFrameStyle( QFrame::StyledPanel | QFrame::Sunken );
+        aFrame.ensurePolished();
+
+        option.initFrom( &aFrame );
+        option.lineWidth = aFrame.lineWidth();
+        option.midLineWidth = aFrame.midLineWidth();
+    #endif
+        draw(element, &option, image, state);
+    }
+}
+
+#if QT_VERSION >= QT_VERSION_CHECK( 4, 5, 0 )
+#define IMAGE_BASED_PAINTING
+#else
+#undef IMAGE_BASED_PAINTING
+#endif
+
+#ifdef IMAGE_BASED_PAINTING
+// There is a small catch with this function, although hopefully only philosophical.
+// Officially Xlib's vcl::Region is an opaque data type, with only functions for manipulating it.
+// However, whoever designed it apparently didn't give it that much thought, as it's impossible
+// to find out what exactly a region actually is (except for really weird ways like XClipBox()
+// and repeated XPointInRegion(), which would be awfully slow). Fortunately, the header file
+// describing the structure actually happens to be installed too, and there's at least one
+// widely used software using it (Compiz). So access the data directly too and assume that
+// everybody who compiles with Qt4 support has Xlib new enough and good enough to support this.
+// In case this doesn't work for somebody, try #include <X11/region.h> instead, or build
+// without IMAGE_BASED_PAINTING (in which case QApplication::setGraphicsSystem( "native" ) may
+// be needed too).
+#include <X11/Xregion.h>
+static QRegion XRegionToQRegion( Region xr )
+{
+    QRegion qr;
+    for( long i = 0;
+         i < xr->numRects;
+         ++i )
+    {
+        BOX& b = xr->rects[ i ];
+        qr |= QRect( b.x1, b.y1, b.x2 - b.x1, b.y2 - b.y1 ); // x2,y2 is outside, not the bottom-right corner
+    }
+    return qr;
+}
+#endif
+
+bool KDESalGraphics::drawNativeControl( ControlType type, ControlPart part,
+                                        const tools::Rectangle& rControlRegion, ControlState nControlState,
+                                        const ImplControlValue& value,
+                                        const OUString& )
+{
+    bool nativeSupport = IsNativeControlSupported( type, part );
+    if( ! nativeSupport ) {
+        assert( ! nativeSupport && "drawNativeControl called without native support!" );
+        return false;
+    }
+
+    if( lastPopupRect.isValid() && ( type != ControlType::MenuPopup || part != ControlPart::MenuItem ))
+        lastPopupRect = QRect();
+
+    bool returnVal = true;
+
+    QRect widgetRect = region2QRect(rControlRegion);
+
+    //if no image, or resized, make a new image
+    if (!m_image || m_image->size() != widgetRect.size())
+    {
+        m_image.reset(new QImage( widgetRect.width(), widgetRect.height(), QImage::Format_ARGB32 ) );
+    }
+
+    // Default image color - just once
+    switch (type)
+    {
+        case ControlType::MenuPopup:
+            if( part == ControlPart::MenuItemCheckMark || part == ControlPart::MenuItemRadioMark )
+            {
+                // it is necessary to fill the background transparently first, as this
+                // is painted after menuitem highlight, otherwise there would be a grey area
+                m_image->fill( Qt::transparent );
+                break;
+            }
+            SAL_FALLTHROUGH; // QPalette::Window
+        case ControlType::Menubar:
+        case ControlType::WindowBackground:
+            m_image->fill( QApplication::palette().color(QPalette::Window).rgb() );
+            break;
+        case ControlType::Tooltip:
+            m_image->fill(QApplication::palette().color(QPalette::ToolTipBase).rgb());
+            break;
+        case ControlType::Pushbutton:
+            m_image->fill(QApplication::palette().color(QPalette::Button).rgb());
+            break;
+        case ControlType::Scrollbar:
+            if ((part == ControlPart::DrawBackgroundVert)
+                || (part == ControlPart::DrawBackgroundHorz))
+            {
+                m_image->fill( QApplication::palette().color(QPalette::Window).rgb() );
+                break;
+            }
+            SAL_FALLTHROUGH; // Qt::transparent
+        default:
+            m_image->fill( Qt::transparent );
+            break;
+    }
+
+    QRegion* localClipRegion = nullptr;
+
+    if (type == ControlType::Pushbutton)
+    {
+        QStyleOptionButton option;
+        draw( QStyle::CE_PushButton, &option, m_image.get(),
+              vclStateValue2StateFlag(nControlState, value) );
+    }
+    else if (type == ControlType::Menubar)
+    {
+        if (part == ControlPart::MenuItem)
+        {
+            QStyleOptionMenuItem option;
+            if ( ( nControlState & ControlState::ROLLOVER )
+                && QApplication::style()->styleHint( QStyle::SH_MenuBar_MouseTracking ) )
+                option.state |= QStyle::State_Selected;
+
+            if ( nControlState & ControlState::SELECTED ) // Passing State_Sunken is currently not documented.
+                option.state |= QStyle::State_Sunken;  // But some kinds of QStyle interpret it.
+
+            draw( QStyle::CE_MenuBarItem, &option, m_image.get(),
+                  vclStateValue2StateFlag(nControlState, value) );
+        }
+        else if (part == ControlPart::Entire)
+        {
+            QStyleOptionMenuItem option;
+            draw( QStyle::CE_MenuBarEmptyArea, &option, m_image.get(),
+                  vclStateValue2StateFlag(nControlState, value) );
+        }
+        else
+        {
+            returnVal = false;
+        }
+    }
+    else if (type == ControlType::MenuPopup)
+    {
+        OSL_ASSERT( part == ControlPart::MenuItem ? lastPopupRect.isValid() : !lastPopupRect.isValid());
+        if( part == ControlPart::MenuItem )
+        {
+            QStyleOptionMenuItem option;
+            draw( QStyle::CE_MenuItem, &option, m_image.get(),
+                  vclStateValue2StateFlag(nControlState, value) );
+            // HACK: LO core first paints the entire popup and only then it paints menu items,
+            // but QMenu::paintEvent() paints popup frame after all items. That means highlighted
+            // items here would paint the highlight over the frame border. Since calls to ControlPart::MenuItem
+            // are always preceded by calls to ControlPart::Entire, just remember the size for the whole
+            // popup (otherwise not possible to get here) and draw the border afterwards.
+            QRect framerect( lastPopupRect.topLeft() - widgetRect.topLeft(),
+                widgetRect.size().expandedTo( lastPopupRect.size()));
+            QStyleOptionFrame frame;
+            draw( QStyle::PE_FrameMenu, &frame, m_image.get(), vclStateValue2StateFlag( nControlState, value ), framerect );
+        }
+        else if( part == ControlPart::Separator )
+        {
+            QStyleOptionMenuItem option;
+            option.menuItemType = QStyleOptionMenuItem::Separator;
+            // Painting the whole menu item area results in different background
+            // with at least Plastique style, so clip only to the separator itself
+            // (QSize( 2, 2 ) is hardcoded in Qt)
+            option.rect = m_image->rect();
+            QSize size = QApplication::style()->sizeFromContents( QStyle::CT_MenuItem, &option, QSize( 2, 2 ));
+            QRect rect = m_image->rect();
+            QPoint center = rect.center();
+            rect.setHeight( size.height());
+            rect.moveCenter( center );
+            // don't paint over popup frame border (like the hack above, but here it can be simpler)
+            int fw = QApplication::style()->pixelMetric( QStyle::PM_MenuPanelWidth );
+            localClipRegion = new QRegion(rect.translated(widgetRect.topLeft()).adjusted(fw, 0, -fw, 0));
+            draw( QStyle::CE_MenuItem, &option, m_image.get(),
+                  vclStateValue2StateFlag(nControlState, value), rect );
+        }
+        else if( part == ControlPart::MenuItemCheckMark || part == ControlPart::MenuItemRadioMark )
+        {
+            QStyleOptionMenuItem option;
+            option.checkType = ( part == ControlPart::MenuItemCheckMark )
+                ? QStyleOptionMenuItem::NonExclusive : QStyleOptionMenuItem::Exclusive;
+            option.checked = bool( nControlState & ControlState::PRESSED );
+            // widgetRect is now the rectangle for the checkbox/radiobutton itself, but Qt
+            // paints the whole menu item, so translate position (and it'll be clipped);
+            // it is also necessary to fill the background transparently first, as this
+            // is painted after menuitem highlight, otherwise there would be a grey area
+            assert( value.getType() == ControlType::MenuPopup );
+            const MenupopupValue* menuVal = static_cast<const MenupopupValue*>(&value);
+            QRect menuItemRect( region2QRect( menuVal->maItemRect ));
+            QRect rect( menuItemRect.topLeft() - widgetRect.topLeft(),
+                widgetRect.size().expandedTo( menuItemRect.size()));
+            // checkboxes are always displayed next to images in menus, so are never centered
+            const int focus_size = QApplication::style()->pixelMetric( QStyle::PM_FocusFrameHMargin );
+            rect.moveTo( -focus_size, rect.y() );
+            draw( QStyle::CE_MenuItem, &option, m_image.get(),
+                  vclStateValue2StateFlag(nControlState & ~ControlState::PRESSED, value), rect );
+        }
+        else if( part == ControlPart::Entire )
+        {
+            QStyleOptionMenuItem option;
+            draw( QStyle::PE_PanelMenu, &option, m_image.get(), vclStateValue2StateFlag( nControlState, value ));
+            // Try hard to get any frame!
+            QStyleOptionFrame frame;
+            draw( QStyle::PE_FrameMenu, &frame, m_image.get(), vclStateValue2StateFlag( nControlState, value ));
+            draw( QStyle::PE_FrameWindow, &frame, m_image.get(), vclStateValue2StateFlag( nControlState, value ));
+            lastPopupRect = widgetRect;
+        }
+        else
+            returnVal = false;
+    }
+    else if ( (type == ControlType::Toolbar) && (part == ControlPart::Button) )
+    {
+        QStyleOptionToolButton option;
+
+        option.arrowType = Qt::NoArrow;
+        option.subControls = QStyle::SC_ToolButton;
+
+        option.state = vclStateValue2StateFlag( nControlState, value );
+        option.state |= QStyle::State_Raised | QStyle::State_Enabled | QStyle::State_AutoRaise;
+
+        draw( QStyle::CC_ToolButton, &option, m_image.get(),
+              vclStateValue2StateFlag(nControlState, value) );
+    }
+    else if ( (type == ControlType::Toolbar) && (part == ControlPart::Entire) )
+    {
+        QStyleOptionToolBar option;
+
+        option.rect = QRect(0, 0, widgetRect.width(), widgetRect.height());
+        option.state = vclStateValue2StateFlag( nControlState, value );
+
+        draw( QStyle::CE_ToolBar, &option, m_image.get(),
+              vclStateValue2StateFlag(nControlState, value) );
+    }
+    else if ( (type == ControlType::Toolbar)
+            && (part == ControlPart::ThumbVert || part == ControlPart::ThumbHorz) )
+    {   // reduce paint area only to the handle area
+        const int handleExtend = QApplication::style()->pixelMetric(QStyle::PM_ToolBarHandleExtent);
+        QRect rect;
+        QStyleOption option;
+
+        if (part == ControlPart::ThumbVert)
+        {
+            rect = QRect( 0, 0, handleExtend, widgetRect.height());
+            localClipRegion = new QRegion(widgetRect.x(), widgetRect.y(), handleExtend, widgetRect.height());
+            option.state = QStyle::State_Horizontal;
+        }
+        else
+        {
+            rect = QRect( 0, 0, widgetRect.width(), handleExtend);
+            localClipRegion = new QRegion(widgetRect.x(), widgetRect.y(), widgetRect.width(), handleExtend);
+        }
+
+        draw( QStyle::PE_IndicatorToolBarHandle, &option, m_image.get(),
+              vclStateValue2StateFlag(nControlState, value), rect );
+    }
+    else if (type == ControlType::Editbox || type == ControlType::MultilineEditbox)
+    {
+        lcl_drawFrame( QStyle::PE_FrameLineEdit, m_image.get(),
+                       vclStateValue2StateFlag(nControlState, value));
+    }
+    else if (type == ControlType::Combobox)
+    {
+        QStyleOptionComboBox option;
+        option.editable = true;
+        draw( QStyle::CC_ComboBox, &option, m_image.get(),
+              vclStateValue2StateFlag(nControlState, value) );
+    }
+    else if (type == ControlType::Listbox)
+    {
+        QStyleOptionComboBox option;
+        option.editable = false;
+        switch (part) {
+            case ControlPart::ListboxWindow:
+                lcl_drawFrame( QStyle::PE_Frame, m_image.get(),
+                               vclStateValue2StateFlag(nControlState, value),
+                               QStyle::PM_ComboBoxFrameWidth );
+                break;
+            case ControlPart::SubEdit:
+                draw( QStyle::CE_ComboBoxLabel, &option, m_image.get(),
+                      vclStateValue2StateFlag(nControlState, value) );
+                break;
+            case ControlPart::Entire:
+                draw( QStyle::CC_ComboBox, &option, m_image.get(),
+                      vclStateValue2StateFlag(nControlState, value) );
+                break;
+            case ControlPart::ButtonDown:
+                option.subControls = QStyle::SC_ComboBoxArrow;
+                draw( QStyle::CC_ComboBox, &option, m_image.get(),
+                      vclStateValue2StateFlag(nControlState, value) );
+                break;
+            default:
+                returnVal = false;
+                break;
+        }
+    }
+    else if (type == ControlType::ListNode)
+    {
+        QStyleOption option;
+        option.state = QStyle::State_Item | QStyle::State_Children;
+
+        if (value.getTristateVal() == ButtonValue::On)
+            option.state |= QStyle::State_Open;
+
+        draw( QStyle::PE_IndicatorBranch, &option, m_image.get(),
+              vclStateValue2StateFlag(nControlState, value) );
+    }
+    else if (type == ControlType::Checkbox)
+    {
+        QStyleOptionButton option;
+        draw( QStyle::CE_CheckBox, &option, m_image.get(),
+               vclStateValue2StateFlag(nControlState, value) );
+    }
+    else if (type == ControlType::Scrollbar)
+    {
+        if ((part == ControlPart::DrawBackgroundVert) || (part == ControlPart::DrawBackgroundHorz))
+        {
+            QStyleOptionSlider option;
+            OSL_ASSERT( value.getType() == ControlType::Scrollbar );
+            const ScrollbarValue* sbVal = static_cast<const ScrollbarValue *>(&value);
+
+            //if the scroll bar is active (aka not degenrate...allow for hover events
+            if (sbVal->mnVisibleSize < sbVal->mnMax)
+                option.state = QStyle::State_MouseOver;
+
+            bool horizontal = ( part == ControlPart::DrawBackgroundHorz ); //horizontal or vertical
+            option.orientation = horizontal ? Qt::Horizontal : Qt::Vertical;
+            if( horizontal )
+                option.state |= QStyle::State_Horizontal;
+
+            //setup parameters from the OO values
+            option.minimum = sbVal->mnMin;
+            option.maximum = sbVal->mnMax - sbVal->mnVisibleSize;
+            option.maximum = qMax( option.maximum, option.minimum ); // bnc#619772
+            option.sliderValue = sbVal->mnCur;
+            option.sliderPosition = sbVal->mnCur;
+            option.pageStep = sbVal->mnVisibleSize;
+            if (part == ControlPart::DrawBackgroundHorz)
+                option.upsideDown = sbVal->maButton1Rect.Left() > sbVal->maButton2Rect.Left();
+
+            //setup the active control...always the slider
+            if (sbVal->mnThumbState & ControlState::ROLLOVER)
+                option.activeSubControls = QStyle::SC_ScrollBarSlider;
+
+            draw( QStyle::CC_ScrollBar, &option, m_image.get(),
+                  vclStateValue2StateFlag(nControlState, value) );
+        }
+        else
+        {
+            returnVal = false;
+        }
+    }
+    else if (type == ControlType::Spinbox)
+    {
+        QStyleOptionSpinBox option;
+        option.frame = true;
+
+        // determine active control
+        if( value.getType() == ControlType::SpinButtons )
+        {
+            const SpinbuttonValue* pSpinVal = static_cast<const SpinbuttonValue *>(&value);
+            if( (pSpinVal->mnUpperState & ControlState::PRESSED) )
+                option.activeSubControls |= QStyle::SC_SpinBoxUp;
+            if( (pSpinVal->mnLowerState & ControlState::PRESSED) )
+                option.activeSubControls |= QStyle::SC_SpinBoxDown;
+            if( (pSpinVal->mnUpperState & ControlState::ENABLED) )
+                option.stepEnabled |= QAbstractSpinBox::StepUpEnabled;
+            if( (pSpinVal->mnLowerState & ControlState::ENABLED) )
+                option.stepEnabled |= QAbstractSpinBox::StepDownEnabled;
+            if( (pSpinVal->mnUpperState & ControlState::ROLLOVER) )
+                option.state = QStyle::State_MouseOver;
+            if( (pSpinVal->mnLowerState & ControlState::ROLLOVER) )
+                option.state = QStyle::State_MouseOver;
+        }
+
+        draw( QStyle::CC_SpinBox, &option, m_image.get(),
+              vclStateValue2StateFlag(nControlState, value) );
+    }
+    else if (type == ControlType::Radiobutton)
+    {
+        QStyleOptionButton option;
+        draw( QStyle::CE_RadioButton, &option, m_image.get(),
+              vclStateValue2StateFlag(nControlState, value) );
+    }
+    else if (type == ControlType::Tooltip)
+    {
+        QStyleOption option;
+        draw( QStyle::PE_PanelTipLabel, &option, m_image.get(),
+              vclStateValue2StateFlag(nControlState, value) );
+    }
+    else if (type == ControlType::Frame)
+    {
+        lcl_drawFrame( QStyle::PE_Frame, m_image.get(),
+                       vclStateValue2StateFlag(nControlState, value) );
+        // draw just the border, see http://qa.openoffice.org/issues/show_bug.cgi?id=107945
+        int fw = QApplication::style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
+        localClipRegion = new QRegion(QRegion(widgetRect).subtracted(widgetRect.adjusted(fw, fw, -fw, -fw)));
+    }
+    else if (type == ControlType::WindowBackground)
+    {
+        // Nothing to do - see "Default image color" switch ^^
+    }
+    else if (type == ControlType::Fixedline)
+    {
+        QStyleOptionMenuItem option;
+        option.menuItemType = QStyleOptionMenuItem::Separator;
+        option.state |= QStyle::State_Item;
+
+        draw( QStyle::CE_MenuItem, &option, m_image.get(),
+              vclStateValue2StateFlag(nControlState, value) );
+    }
+    else if (type == ControlType::Slider && (part == ControlPart::TrackHorzArea || part == ControlPart::TrackVertArea))
+    {
+        OSL_ASSERT( value.getType() == ControlType::Slider );
+        const SliderValue* slVal = static_cast<const SliderValue *>(&value);
+        QStyleOptionSlider option;
+
+        option.rect = QRect(0, 0, widgetRect.width(), widgetRect.height());
+        option.state = vclStateValue2StateFlag( nControlState, value );
+        option.maximum     = slVal->mnMax;
+        option.minimum     = slVal->mnMin;
+        option.sliderPosition = option.sliderValue = slVal->mnCur;
+        bool horizontal = ( part == ControlPart::TrackHorzArea ); //horizontal or vertical
+        option.orientation = horizontal ? Qt::Horizontal : Qt::Vertical;
+        if( horizontal )
+            option.state |= QStyle::State_Horizontal;
+
+        draw( QStyle::CC_Slider, &option, m_image.get(), vclStateValue2StateFlag(nControlState, value) );
+    }
+    else if( type == ControlType::Progress && part == ControlPart::Entire )
+    {
+        QStyleOptionProgressBarV2 option;
+        option.minimum = 0;
+        option.maximum = widgetRect.width();
+        option.progress = value.getNumericVal();
+        option.rect = QRect(0, 0, widgetRect.width(), widgetRect.height());
+        option.state = vclStateValue2StateFlag( nControlState, value );
+
+        draw( QStyle::CE_ProgressBar, &option, m_image.get(),
+              vclStateValue2StateFlag(nControlState, value) );
+    }
+    else
+    {
+        returnVal = false;
+    }
+
+    if (returnVal)
+    {
+#if 0
+#ifdef IMAGE_BASED_PAINTING
+        // Create a wrapper QPixmap around the destination pixmap, allowing the use of QPainter.
+        // Using X11SalGraphics::CopyScreenArea() would require using QPixmap and if Qt uses
+        // other graphics system than native, QPixmap::handle() would be 0 (i.e. it wouldn't work),
+        // I have no idea how to create QPixmap with non-null handle() in such case, so go this way.
+        // See XRegionToQRegion() comment for a small catch (although not real hopefully).
+        QPixmap destPixmap = QPixmap::fromX11Pixmap( GetDrawable(), QPixmap::ExplicitlyShared );
+        QPainter paint( &destPixmap );
+        if (localClipRegion && mpClipRegion)
+            paint.setClipRegion(localClipRegion->intersected(XRegionToQRegion(mpClipRegion)));
+        else if (localClipRegion)
+            paint.setClipRegion(*localClipRegion);
+        else if( mpClipRegion )
+            paint.setClipRegion( XRegionToQRegion( mpClipRegion ));
+        paint.drawImage( widgetRect.left(), widgetRect.top(), *m_image,
+            0, 0, widgetRect.width(), widgetRect.height(),
+            Qt::ColorOnly | Qt::OrderedDither | Qt::OrderedAlphaDither );
+#else
+        GC gc = GetFontGC();
+        if( gc )
+        {
+            Region pTempClipRegion = NULL;
+            if (localClipRegion)
+            {
+                pTempClipRegion = XCreateRegion();
+                foreach(const QRect& r, localClipRegion->rects())
+                {
+                    XRectangle xr;
+                    xr.x = r.x();
+                    xr.y = r.y();
+                    xr.width = r.width();
+                    xr.height = r.height();
+                    XUnionRectWithRegion( &xr, pTempClipRegion, pTempClipRegion );
+                }
+                if( mpClipRegion )
+                    XIntersectRegion( pTempClipRegion, mpClipRegion, pTempClipRegion );
+                XSetRegion( GetXDisplay(), gc, pTempClipRegion );
+            }
+            QPixmap pixmap = QPixmap::fromImage(*m_image, Qt::ColorOnly | Qt::OrderedDither | Qt::OrderedAlphaDither);
+            X11SalGraphics::CopyScreenArea( GetXDisplay(),
+                pixmap.handle(), pixmap.x11Info().screen(), pixmap.x11Info().depth(),
+                GetDrawable(), GetScreenNumber(), GetVisual().GetDepth(),
+                gc, 0, 0, widgetRect.width(), widgetRect.height(), widgetRect.left(), widgetRect.top());
+
+            if( pTempClipRegion )
+            {
+                if( mpClipRegion )
+                    XSetRegion( GetXDisplay(), gc, mpClipRegion );
+                else
+                    XSetClipMask( GetXDisplay(), gc, None );
+                XDestroyRegion( pTempClipRegion );
+            }
+        }
+        else
+            returnVal = false;
+#endif
+#endif
+    }
+    delete localClipRegion;
+    return returnVal;
+}
+
+bool KDESalGraphics::getNativeControlRegion( ControlType type, ControlPart part,
+                                             const tools::Rectangle& controlRegion, ControlState controlState,
+                                             const ImplControlValue& val,
+                                             const OUString&,
+                                             tools::Rectangle &nativeBoundingRegion, tools::Rectangle &nativeContentRegion )
+{
+    bool retVal = false;
+
+    QRect boundingRect = region2QRect( controlRegion );
+    QRect contentRect = boundingRect;
+    QStyleOptionComplex styleOption;
+
+    switch ( type )
+    {
+        // Metrics of the push button
+        case ControlType::Pushbutton:
+            if (part == ControlPart::Entire)
+            {
+                styleOption.state = vclStateValue2StateFlag(controlState, val);
+
+                if ( controlState & ControlState::DEFAULT )
+                {
+                    int size = QApplication::style()->pixelMetric(
+                        QStyle::PM_ButtonDefaultIndicator, &styleOption );
+                    boundingRect.adjust( -size, -size, size, size );
+                    retVal = true;
+                }
+            }
+            break;
+        case ControlType::Editbox:
+        case ControlType::MultilineEditbox:
+        {
+            QStyleOptionFrameV3 fo;
+            fo.frameShape = QFrame::StyledPanel;
+            fo.state = QStyle::State_Sunken;
+            fo.lineWidth = QApplication::style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
+            QSize aMinSize = QApplication::style()->
+                sizeFromContents( QStyle::CT_LineEdit, &fo, contentRect.size() );
+            if( aMinSize.height() > boundingRect.height() )
+            {
+                int nHeight = (aMinSize.height() - boundingRect.height()) / 2;
+                assert( 0 == (aMinSize.height() - boundingRect.height()) % 2 );
+                boundingRect.adjust( 0, -nHeight, 0, nHeight );
+            }
+            if( aMinSize.width() > boundingRect.width() )
+            {
+                int nWidth = (aMinSize.width() - boundingRect.width()) / 2;
+                assert( 0 == (aMinSize.width() - boundingRect.width()) % 2 );
+                boundingRect.adjust( -nWidth, 0, nWidth, 0 );
+            }
+            retVal = true;
+            break;
+        }
+        case ControlType::Checkbox:
+            if (part == ControlPart::Entire)
+            {
+                styleOption.state = vclStateValue2StateFlag(controlState, val);
+
+                contentRect.setWidth(QApplication::style()->pixelMetric(
+                    QStyle::PM_IndicatorWidth, &styleOption));
+                contentRect.setHeight(QApplication::style()->pixelMetric(
+                    QStyle::PM_IndicatorHeight, &styleOption));
+
+                contentRect.adjust(0, 0,
+                    2 * QApplication::style()->pixelMetric(
+                        QStyle::PM_FocusFrameHMargin, &styleOption),
+                    2 * QApplication::style()->pixelMetric(
+                        QStyle::PM_FocusFrameVMargin, &styleOption)
+                    );
+
+                boundingRect = contentRect;
+
+                retVal = true;
+            }
+            break;
+        case ControlType::Combobox:
+        case ControlType::Listbox:
+        {
+            QStyleOptionComboBox cbo;
+
+            cbo.rect = QRect(0, 0, contentRect.width(), contentRect.height());
+            cbo.state = vclStateValue2StateFlag(controlState, val);
+
+            switch ( part )
+            {
+                case ControlPart::Entire:
+                {
+                    // find out the minimum size that should be used
+                    // assume contents is a text ling
+                    int nHeight = QApplication::fontMetrics().height();
+                    QSize aContentSize( contentRect.width(), nHeight );
+                    QSize aMinSize = QApplication::style()->
+                        sizeFromContents( QStyle::CT_ComboBox, &cbo, aContentSize );
+                    if( aMinSize.height() > contentRect.height() )
+                        contentRect.adjust( 0, 0, 0, aMinSize.height() - contentRect.height() );
+                    boundingRect = contentRect;
+                    retVal = true;
+                    break;
+                }
+                case ControlPart::ButtonDown:
+                    contentRect = QApplication::style()->subControlRect(
+                        QStyle::CC_ComboBox, &cbo, QStyle::SC_ComboBoxArrow );
+                    contentRect.translate( boundingRect.left(), boundingRect.top() );
+                    retVal = true;
+                    break;
+                case ControlPart::SubEdit:
+                {
+                    contentRect = QApplication::style()->subControlRect(
+                        QStyle::CC_ComboBox, &cbo, QStyle::SC_ComboBoxEditField );
+                    contentRect.translate( boundingRect.left(), boundingRect.top() );
+                    retVal = true;
+                    break;
+                }
+                default:
+                    break;
+            }
+            break;
+        }
+        case ControlType::Spinbox:
+        {
+            QStyleOptionSpinBox sbo;
+            sbo.frame = true;
+
+            sbo.rect = QRect(0, 0, contentRect.width(), contentRect.height());
+            sbo.state = vclStateValue2StateFlag(controlState, val);
+
+            switch ( part )
+            {
+                case ControlPart::Entire:
+                {
+                    int nHeight = QApplication::fontMetrics().height();
+                    QSize aContentSize( contentRect.width(), nHeight );
+                    QSize aMinSize = QApplication::style()->
+                        sizeFromContents( QStyle::CT_SpinBox, &sbo, aContentSize );
+                    if( aMinSize.height() > contentRect.height() )
+                        contentRect.adjust( 0, 0, 0, aMinSize.height() - contentRect.height() );
+                    boundingRect = contentRect;
+                    retVal = true;
+                    break;
+                }
+                case ControlPart::ButtonUp:
+                    contentRect = QApplication::style()->subControlRect(
+                        QStyle::CC_SpinBox, &sbo, QStyle::SC_SpinBoxUp );
+                    contentRect.translate( boundingRect.left(), boundingRect.top() );
+                    retVal = true;
+                    boundingRect = QRect();
+                    break;
+
+                case ControlPart::ButtonDown:
+                    contentRect = QApplication::style()->subControlRect(
+                        QStyle::CC_SpinBox, &sbo, QStyle::SC_SpinBoxDown );
+                    retVal = true;
+                    contentRect.translate( boundingRect.left(), boundingRect.top() );
+                    boundingRect = QRect();
+                    break;
+
+                case ControlPart::SubEdit:
+                    contentRect = QApplication::style()->subControlRect(
+                        QStyle::CC_SpinBox, &sbo, QStyle::SC_SpinBoxEditField );
+                    retVal = true;
+                    contentRect.translate( boundingRect.left(), boundingRect.top() );
+                    break;
+                default:
+                    break;
+            }
+            break;
+        }
+        case ControlType::MenuPopup:
+        {
+            int h, w;
+            switch ( part ) {
+            case ControlPart::MenuItemCheckMark:
+                h = QApplication::style()->pixelMetric(QStyle::PM_IndicatorHeight);
+                w = QApplication::style()->pixelMetric(QStyle::PM_IndicatorWidth);
+                retVal = true;
+                break;
+            case ControlPart::MenuItemRadioMark:
+                h = QApplication::style()->pixelMetric(QStyle::PM_ExclusiveIndicatorHeight);
+                w = QApplication::style()->pixelMetric(QStyle::PM_ExclusiveIndicatorWidth);
+                retVal = true;
+                break;
+            default:
+                break;
+            }
+            if (retVal) {
+                contentRect = QRect(0, 0, w, h);
+                boundingRect = contentRect;
+            }
+            break;
+        }
+        case ControlType::Frame:
+        {
+            if( part == ControlPart::Border )
+            {
+                auto nStyle = static_cast<DrawFrameFlags>(
+                    val.getNumericVal() & 0xFFF0);
+                if( nStyle & DrawFrameFlags::NoDraw )
+                {
+                    int nFrameWidth = QApplication::style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
+                    contentRect.adjust(nFrameWidth, nFrameWidth, -nFrameWidth, -nFrameWidth);
+                }
+                retVal = true;
+            }
+            break;
+        }
+        case ControlType::Radiobutton:
+        {
+            const int h = QApplication::style()->pixelMetric(QStyle::PM_ExclusiveIndicatorHeight);
+            const int w = QApplication::style()->pixelMetric(QStyle::PM_ExclusiveIndicatorWidth);
+
+            contentRect = QRect(boundingRect.left(), boundingRect.top(), w, h);
+            contentRect.adjust(0, 0,
+                2 * QApplication::style()->pixelMetric(
+                    QStyle::PM_FocusFrameHMargin, &styleOption),
+                2 * QApplication::style()->pixelMetric(
+                    QStyle::PM_FocusFrameVMargin, &styleOption)
+                );
+            boundingRect = contentRect;
+
+            retVal = true;
+            break;
+        }
+        case ControlType::Slider:
+        {
+            const int w = QApplication::style()->pixelMetric(QStyle::PM_SliderLength);
+            if( part == ControlPart::ThumbHorz )
+            {
+                contentRect = QRect(boundingRect.left(), boundingRect.top(), w, boundingRect.height());
+                boundingRect = contentRect;
+                retVal = true;
+            }
+            else if( part == ControlPart::ThumbVert )
+            {
+                contentRect = QRect(boundingRect.left(), boundingRect.top(), boundingRect.width(), w);
+                boundingRect = contentRect;
+                retVal = true;
+            }
+            break;
+        }
+        case ControlType::Toolbar:
+        {
+            const int nWorH = QApplication::style()->pixelMetric(QStyle::PM_ToolBarHandleExtent);
+            if( part == ControlPart::ThumbHorz )
+            {
+                contentRect = QRect(boundingRect.left(), boundingRect.top(), boundingRect.width(), nWorH );
+                boundingRect = contentRect;
+                retVal = true;
+            }
+            else if( part == ControlPart::ThumbVert )
+            {
+                contentRect = QRect(boundingRect.left(), boundingRect.top(), nWorH, boundingRect.height() );
+                boundingRect = contentRect;
+                retVal = true;
+            }
+            break;
+        }
+        case ControlType::Scrollbar:
+        {
+            // core can't handle 3-button scrollbars well, so we fix that in hitTestNativeControl(),
+            // for the rest also provide the track area (i.e. area not taken by buttons)
+            if( part == ControlPart::TrackVertArea || part == ControlPart::TrackHorzArea )
+            {
+                QStyleOptionSlider option;
+                bool horizontal = ( part == ControlPart::TrackHorzArea ); //horizontal or vertical
+                option.orientation = horizontal ? Qt::Horizontal : Qt::Vertical;
+                if( horizontal )
+                    option.state |= QStyle::State_Horizontal;
+                // getNativeControlRegion usually gets ImplControlValue as 'val' (i.e. not the proper
+                // subclass), so use random sensible values (doesn't matter anyway, as the wanted
+                // geometry here depends only on button sizes)
+                option.maximum = 10;
+                option.minimum = 0;
+                option.sliderPosition = option.sliderValue = 4;
+                option.pageStep = 2;
+                // Adjust coordinates to make the widget appear to be at (0,0), i.e. make
+                // widget and screen coordinates the same. QStyle functions should use screen
+                // coordinates but at least QPlastiqueStyle::subControlRect() is buggy
+                // and sometimes uses widget coordinates.
+                QRect rect = contentRect;
+                rect.moveTo( 0, 0 );
+                option.rect = rect;
+                rect = QApplication::style()->subControlRect( QStyle::CC_ScrollBar, &option,
+                    QStyle::SC_ScrollBarGroove );
+                rect.translate( contentRect.topLeft()); // reverse the workaround above
+                contentRect = boundingRect = rect;
+                retVal = true;
+            }
+            break;
+        }
+        default:
+            break;
+    }
+    if (retVal)
+    {
+        // Bounding region
+        Point aBPoint( boundingRect.x(), boundingRect.y() );
+        Size aBSize( boundingRect.width(), boundingRect.height() );
+        nativeBoundingRegion = tools::Rectangle( aBPoint, aBSize );
+
+        // vcl::Region of the content
+        Point aPoint( contentRect.x(), contentRect.y() );
+        Size  aSize( contentRect.width(), contentRect.height() );
+        nativeContentRegion = tools::Rectangle( aPoint, aSize );
+    }
+
+    return retVal;
+}
+
+/** Test whether the position is in the native widget.
+    If the return value is TRUE, bIsInside contains information whether
+    aPos was or was not inside the native widget specified by the
+    nType/nPart combination.
+*/
+bool KDESalGraphics::hitTestNativeControl( ControlType nType, ControlPart nPart,
+                                           const tools::Rectangle& rControlRegion, const Point& rPos,
+                                           bool& rIsInside )
+{
+    if ( nType == ControlType::Scrollbar )
+    {
+        if( nPart != ControlPart::ButtonUp && nPart != ControlPart::ButtonDown
+            && nPart != ControlPart::ButtonLeft && nPart != ControlPart::ButtonRight )
+        { // we adjust only for buttons (because some scrollbars have 3 buttons,
+          // and LO core doesn't handle such scrollbars well)
+            return FALSE;
+        }
+        rIsInside = FALSE;
+        bool bHorizontal = ( nPart == ControlPart::ButtonLeft || nPart == ControlPart::ButtonRight );
+        QRect rect = region2QRect( rControlRegion );
+        QPoint pos( rPos.X(), rPos.Y());
+        // Adjust coordinates to make the widget appear to be at (0,0), i.e. make
+        // widget and screen coordinates the same. QStyle functions should use screen
+        // coordinates but at least QPlastiqueStyle::subControlRect() is buggy
+        // and sometimes uses widget coordinates.
+        pos -= rect.topLeft();
+        rect.moveTo( 0, 0 );
+        QStyleOptionSlider options;
+        options.orientation = bHorizontal ? Qt::Horizontal : Qt::Vertical;
+        if( bHorizontal )
+            options.state |= QStyle::State_Horizontal;
+        options.rect = rect;
+        // some random sensible values, since we call this code only for scrollbar buttons,
+        // the slider position does not exactly matter
+        options.maximum = 10;
+        options.minimum = 0;
+        options.sliderPosition = options.sliderValue = 4;
+        options.pageStep = 2;
+        QStyle::SubControl control = QApplication::style()->hitTestComplexControl( QStyle::CC_ScrollBar, &options, pos );
+        if( nPart == ControlPart::ButtonUp || nPart == ControlPart::ButtonLeft )
+            rIsInside = ( control == QStyle::SC_ScrollBarSubLine );
+        else // DOWN, RIGHT
+            rIsInside = ( control == QStyle::SC_ScrollBarAddLine );
+        return TRUE;
+    }
+    return FALSE;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/kde5/KDE5SalGraphics.hxx b/vcl/unx/kde5/KDE5SalGraphics.hxx
new file mode 100644
index 000000000000..eb513388f369
--- /dev/null
+++ b/vcl/unx/kde5/KDE5SalGraphics.hxx
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <memory>
+
+#include <rtl/string.hxx>
+#include <unx/saldisp.hxx>
+#include <unx/salgdi.h>
+
+#include <QtGui/QImage>
+
+/**
+ * Handles native graphics requests and performs the needed drawing operations.
+ */
+class KDESalGraphics : public X11SalGraphics
+{
+public:
+    virtual bool IsNativeControlSupported( ControlType, ControlPart ) override;
+
+    virtual bool hitTestNativeControl( ControlType, ControlPart,
+                                       const tools::Rectangle&, const Point&, bool& ) override;
+
+    virtual bool drawNativeControl( ControlType, ControlPart, const tools::Rectangle&,
+                                    ControlState, const ImplControlValue&, const OUString& ) override;
+
+    virtual bool getNativeControlRegion( ControlType, ControlPart, const tools::Rectangle&,
+                                         ControlState, const ImplControlValue&,
+                                         const OUString&, tools::Rectangle&, tools::Rectangle& ) override;
+
+private:
+    std::unique_ptr<QImage> m_image;
+    QRect lastPopupRect;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/kde5/KDE5SalInstance.cxx b/vcl/unx/kde5/KDE5SalInstance.cxx
new file mode 100644
index 000000000000..5d4bc5eec5dd
--- /dev/null
+++ b/vcl/unx/kde5/KDE5SalInstance.cxx
@@ -0,0 +1,70 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+//#include "KDE4FilePicker.hxx"
+#include <QtCore/QAbstractEventDispatcher>
+#include <QtCore/QThread>
+#include <QtGui/QClipboard>
+#include <QtWidgets/QApplication>
+#include <QtWidgets/QFrame>
+#include <QtX11Extras/QX11Info>
+
+
+#include "KDE5SalInstance.hxx"
+#include "KDE5SalFrame.hxx"
+#include "KDE5XLib.hxx"
+#include "KDE5SalDisplay.hxx"
+
+using namespace com::sun::star;
+
+KDESalInstance::KDESalInstance(SalYieldMutex* pMutex)
+    : X11SalInstance(pMutex)
+{
+    ImplSVData* pSVData = ImplGetSVData();
+    delete pSVData->maAppData.mpToolkitName;
+    pSVData->maAppData.mpToolkitName = new OUString("kde4");
+}
+
+SalFrame* KDESalInstance::CreateFrame( SalFrame *pParent, SalFrameStyleFlags nState )
+{
+    return new KDESalFrame( pParent, nState );
+}
+
+uno::Reference< ui::dialogs::XFilePicker2 > KDESalInstance::createFilePicker(
+    const uno::Reference< uno::XComponentContext >& xMSF )
+{
+    /*KDEXLib* kdeXLib = static_cast<KDEXLib*>( mpXLib );
+    if (kdeXLib->allowKdeDialogs())
+        return uno::Reference< ui::dialogs::XFilePicker2 >(
+            kdeXLib->createFilePicker(xMSF) );
+    else*/
+        return X11SalInstance::createFilePicker( xMSF );
+}
+
+SalX11Display* KDESalInstance::CreateDisplay() const
+{
+    return new SalKDEDisplay( QX11Info::display() );
+}
+
+bool KDESalInstance::IsMainThread() const
+{
+    return qApp->thread() == QThread::currentThread();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/kde5/KDE5SalInstance.hxx b/vcl/unx/kde5/KDE5SalInstance.hxx
new file mode 100644
index 000000000000..7b7417caaaf1
--- /dev/null
+++ b/vcl/unx/kde5/KDE5SalInstance.hxx
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <unx/salinst.h>
+
+class SalYieldMutex;
+class SalFrame;
+
+class KDESalInstance : public X11SalInstance
+{
+protected:
+    virtual SalX11Display* CreateDisplay() const override;
+
+public:
+    explicit KDESalInstance(SalYieldMutex* pMutex);
+    virtual SalFrame* CreateFrame( SalFrame* pParent, SalFrameStyleFlags nStyle ) override;
+
+    virtual bool hasNativeFileSelection() const override { return true; }
+
+    virtual css::uno::Reference< css::ui::dialogs::XFilePicker2 >
+        createFilePicker( const css::uno::Reference<
+                              css::uno::XComponentContext >& ) override;
+
+    virtual bool IsMainThread() const override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/kde5/KDE5XLib.cxx b/vcl/unx/kde5/KDE5XLib.cxx
new file mode 100644
index 000000000000..b05e8e6ed047
--- /dev/null
+++ b/vcl/unx/kde5/KDE5XLib.cxx
@@ -0,0 +1,407 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <QtCore/QAbstractEventDispatcher>
+#include <QtCore/QThread>
+#include <QtWidgets/QApplication>
+#include <QtWidgets/QFrame>
+#include <QtGui/QClipboard>
+#include <QtGui/QFrame>
+#include <QtX11Extras/QX11Info>
+
+
+#include "config_kde5.h"
+
+#include "KDE5XLib.hxx"
+#include "VCLKDE5Application.hxx"
+#include "KDE5SalInstance.hxx"
+
+#include <KAboutData>
+#include <KLocalizedString>
+
+#include "unx/i18n_im.hxx"
+#include "unx/i18n_xkb.hxx"
+#include "unx/saldata.hxx"
+#include <o3tl/make_unique.hxx>
+#include "osl/process.h"
+
+#include "KDE5SalDisplay.hxx"
+
+#undef Bool
+
+#if KF5_HAVE_GLIB
+//#include "KDE4FilePicker.hxx"
+#include "tst_exclude_socket_notifiers.moc"
+#include "tst_exclude_posted_events.moc"
+#endif
+
+KDEXLib::KDEXLib() :
+    SalXLib(),  m_bStartupDone(false),
+    m_nFakeCmdLineArgs( 0 ),
+    m_isGlibEventLoopType(false), m_allowKdeDialogs(false),
+    m_timerEventId( -1 ), m_postUserEventId( -1 )
+{
+    m_timerEventId = QEvent::registerEventType();
+    m_postUserEventId = QEvent::registerEventType();
+
+    // the timers created here means they belong to the main thread.
+    // As the timeoutTimer runs the LO event queue, which may block on a dialog,
+    // the timer has to use a Qt::QueuedConnection, otherwise the nested event
+    // loop will detect the blocking timer and drop it from the polling
+    // freezing LO X11 processing.
+    timeoutTimer.setSingleShot( true );
+    connect( &timeoutTimer, SIGNAL( timeout()), this, SLOT( timeoutActivated()), Qt::QueuedConnection );
+
+    // QTimer::start() can be called only in its (here main) thread, so this will
+    // forward between threads if needed
+    connect( this, SIGNAL( startTimeoutTimerSignal()), this, SLOT( startTimeoutTimer()), Qt::QueuedConnection );
+
+    // this one needs to be blocking, so that the handling in main thread is processed before
+    // the thread emitting the signal continues
+    connect( this, SIGNAL( processYieldSignal( bool, bool )), this, SLOT( processYield( bool, bool )),
+        Qt::BlockingQueuedConnection );
+
+    // Create the File picker in the main / GUI thread and block the calling thread until
+    // the FilePicker is created.
+    connect( this, SIGNAL( createFilePickerSignal( const css::uno::Reference< css::uno::XComponentContext >&) ),
+             this, SLOT( createFilePicker( const css::uno::Reference< css::uno::XComponentContext >&) ),
+             Qt::BlockingQueuedConnection );
+}
+
+KDEXLib::~KDEXLib()
+{
+
+    // free the faked cmdline arguments no longer needed by KApplication
+    for( int i = 0; i < m_nFakeCmdLineArgs; i++ )
+    {
+        free( m_pFreeCmdLineArgs[i] );
+    }
+}
+
+void KDEXLib::Init()
+{
+    m_pInputMethod = new SalI18N_InputMethod;
+    m_pInputMethod->SetLocale();
+    XrmInitialize();
+
+    KAboutData *kAboutData = new KAboutData( I18N_NOOP("LibreOffice"),
+            i18n( "LibreOffice" ),
+            "5.1.0",
+            i18n( "LibreOffice with KDE Native Widget Support." ),
+            KAboutLicense::File,
+            i18n("Copyright (c) 2000, 2014 LibreOffice contributors" ),
+            i18n( "LibreOffice is an office suite.\n" ),
+            "http://libreoffice.org",
+            QLatin1String("libreoffice at lists.freedesktop.org"));
+
+    kAboutData->addAuthor( i18n( "Jan Holesovsky" ),
+            i18n( "Original author and maintainer of the KDE NWF." ),
+            "kendy at artax.karlin.mff.cuni.cz",
+            "http://artax.karlin.mff.cuni.cz/~kendy" );
+    kAboutData->addAuthor( i18n("Roman Shtylman"),
+            i18n( "Porting to KDE 4." ),
+            "shtylman at gmail.com", "http://shtylman.com" );
+    kAboutData->addAuthor( i18n("Eric Bischoff"),
+            i18n( "Accessibility fixes, porting to KDE 4." ),
+            "bischoff at kde.org" );
+
+    m_nFakeCmdLineArgs = 2;
+
+    sal_uInt32 nParams = osl_getCommandArgCount();
+    OString aDisplay;
+    OUString aParam, aBin;
+
+    for ( sal_uInt32 nIdx = 0; nIdx < nParams; ++nIdx )
+    {
+        osl_getCommandArg( nIdx, &aParam.pData );
+        if ( !m_pFreeCmdLineArgs && aParam == "-display" && nIdx + 1 < nParams )
+        {
+            osl_getCommandArg( nIdx + 1, &aParam.pData );
+            aDisplay = OUStringToOString( aParam, osl_getThreadTextEncoding() );
+
+            m_pFreeCmdLineArgs = o3tl::make_unique<char*[]>(m_nFakeCmdLineArgs + 2);
+            m_pFreeCmdLineArgs[ m_nFakeCmdLineArgs + 0 ] = strdup( "-display" );
+            m_pFreeCmdLineArgs[ m_nFakeCmdLineArgs + 1 ] = strdup( aDisplay.getStr() );
+            m_nFakeCmdLineArgs += 2;
+        }
+    }
+    if ( !m_pFreeCmdLineArgs )
+        m_pFreeCmdLineArgs = o3tl::make_unique<char*[]>(m_nFakeCmdLineArgs);
+
+    osl_getExecutableFile( &aParam.pData );
+    osl_getSystemPathFromFileURL( aParam.pData, &aBin.pData );
+    OString aExec = OUStringToOString( aBin, osl_getThreadTextEncoding() );
+    m_pFreeCmdLineArgs[0] = strdup( aExec.getStr() );
+    m_pFreeCmdLineArgs[1] = strdup( "--nocrashhandler" );
+
+    // make a copy of the string list for freeing it since
+    // KApplication manipulates the pointers inside the argument vector
+    // note: KApplication bad !
+    m_pAppCmdLineArgs = o3tl::make_unique<char*[]>(m_nFakeCmdLineArgs);
+    for( int i = 0; i < m_nFakeCmdLineArgs; i++ )
+        m_pAppCmdLineArgs[i] = m_pFreeCmdLineArgs[i];
+
+    // LO does its own session management, so prevent KDE/Qt from interfering
+    // (QApplication::disableSessionManagement(false) wouldn't quite do,
+    // since that still actually connects to the session manager, it just
+    // won't save the application data on session shutdown).
+    char* session_manager = nullptr;
+    if( getenv( "SESSION_MANAGER" ) != nullptr )
+    {
+        session_manager = strdup( getenv( "SESSION_MANAGER" ));
+        unsetenv( "SESSION_MANAGER" );
+    }
+    //m_pApplication.reset( new VCLKDEApplication() );
+    if( session_manager != nullptr )
+    {
+        // coverity[tainted_string] - trusted source for setenv
+        setenv( "SESSION_MANAGER", session_manager, 1 );
+        free( session_manager );
+    }
+
+    //KApplication::setQuitOnLastWindowClosed(false);
+
+#if KF5_HAVE_GLIB
+    m_isGlibEventLoopType = QAbstractEventDispatcher::instance()->inherits( "QEventDispatcherGlib" );
+    // Using KDE dialogs (and their nested event loops) works only with a proper event loop integration
+    // that will release SolarMutex when waiting for more events.
+    // Moreover there are bugs in Qt event loop code that allow QClipboard recursing because the event
+    // loop processes also events that it should not at that point, so no dialogs in that case either.
+    // https://bugreports.qt-project.org/browse/QTBUG-37380
+    // https://bugreports.qt-project.org/browse/QTBUG-34614
+    if (m_isGlibEventLoopType && (0 == tst_processEventsExcludeSocket()) && tst_excludePostedEvents() == 0 )
+        m_allowKdeDialogs = true;
+#endif
+
+    setupEventLoop();
+
+    m_pDisplay = QX11Info::display();
+}
+
+// When we use Qt event loop, it can actually use its own event loop handling, or wrap
+// the Glib event loop (the latter is the default is Qt is built with Glib support
+// and $QT_NO_GLIB is not set). We mostly do not care which one it is, as QSocketNotifier's
+// and QTimer's can handle it transparently, but it matters for the SolarMutex, which
+// needs to be unlocked shortly before entering the main sleep (e.g. select()) and locked
+// immediately after. So we need to know which event loop implementation is used and
+// hook accordingly.
+#if KF5_HAVE_GLIB
+#include <glib.h>
+
+static GPollFunc old_gpoll = nullptr;
+
+static gint gpoll_wrapper( GPollFD* ufds, guint nfds, gint timeout )
+{
+    SalYieldMutexReleaser release; // release YieldMutex (and re-acquire at block end)
+    return old_gpoll( ufds, nfds, timeout );
+}
+#endif
+
+/*static bool ( *old_qt_event_filter )( void* );
+static bool qt_event_filter( void* m )
+{
+    if( old_qt_event_filter != nullptr && old_qt_event_filter( m ))
+        return true;
+    if( SalKDEDisplay::self() && SalKDEDisplay::self()->checkDirectInputEvent( static_cast< XEvent* >( m )))
+        return true;
+    return false;
+}*/
+
+bool KDEXLib::nativeEventFilter(const QByteArray &eventType, void *message, long *)
+{
+    if (eventType == "xcb_generic_event_t") {
+        xcb_generic_event_t* ev = static_cast<xcb_generic_event_t *>(message);
+        if( SalKDEDisplay::self() && SalKDEDisplay::self()->checkDirectInputEvent( ev ))
+            return true;
+    }
+    return false;
+}
+
+void KDEXLib::setupEventLoop()
+{
+    QAbstractEventDispatcher::instance()->installNativeEventFilter( this );
+#if KF5_HAVE_GLIB
+    if( m_isGlibEventLoopType )
+    {
+        old_gpoll = g_main_context_get_poll_func( nullptr );
+        g_main_context_set_poll_func( nullptr, gpoll_wrapper );
+        if( m_allowKdeDialogs )
+            QApplication::clipboard()->setProperty( "useEventLoopWhenWaiting", true );
+        return;
+    }
+#endif
+}
+
+void KDEXLib::Insert( int fd, void* data, YieldFunc pending, YieldFunc queued, YieldFunc handle )
+{
+    if( !m_isGlibEventLoopType )
+        return SalXLib::Insert( fd, data, pending, queued, handle );
+    SocketData sdata;
+    sdata.data = data;
+    sdata.pending = pending;
+    sdata.queued = queued;
+    sdata.handle = handle;
+    // qApp as parent to make sure it uses the main thread event loop
+    sdata.notifier = new QSocketNotifier( fd, QSocketNotifier::Read, qApp );
+    connect( sdata.notifier, SIGNAL( activated( int )), this, SLOT( socketNotifierActivated( int )));
+    socketData[ fd ] = sdata;
+}
+
+void KDEXLib::Remove( int fd )
+{
+    if( !m_isGlibEventLoopType )
+        return SalXLib::Remove( fd );
+    SocketData sdata = socketData.take( fd );// according to SalXLib::Remove() this should be safe
+    delete sdata.notifier;
+}
+
+void KDEXLib::socketNotifierActivated( int fd )
+{
+    const SocketData& sdata = socketData[ fd ];
+    sdata.handle( fd, sdata.data );
+}
+
+bool KDEXLib::Yield( bool bWait, bool bHandleAllCurrentEvents )
+{
+    if( !m_isGlibEventLoopType )
+    {
+        bool wasEvent = false;
+        if( qApp->thread() == QThread::currentThread())
+        {
+            // even if we use the LO event loop, still process Qt's events,
+            // otherwise they can remain unhandled for quite a long while
+            wasEvent = processYield( false, bHandleAllCurrentEvents );
+        }
+        return SalXLib::Yield(bWait, bHandleAllCurrentEvents) || wasEvent;
+    }
+    // if we are the main thread (which is where the event processing is done),
+    // good, just do it
+    if( qApp->thread() == QThread::currentThread())
+    {
+        return processYield( bWait, bHandleAllCurrentEvents );
+    }
+    else
+    {
+        // we were called from another thread;
+        // release the yield lock to prevent deadlock with the main thread
+        // (it's ok to release it here, since even normal processYield() would
+        // temporarily do it while checking for new events)
+        SalYieldMutexReleaser aReleaser;
+        Q_EMIT processYieldSignal( bWait, bHandleAllCurrentEvents );
+        return false;
+    }
+}
+
+/**
+ * Quoting the Qt docs: [QAbstractEventDispatcher::processEvents] processes
+ * pending events that match flags until there are no more events to process.
+ */
+bool KDEXLib::processYield( bool bWait, bool )
+{
+    QAbstractEventDispatcher* dispatcher = QAbstractEventDispatcher::instance( qApp->thread());
+    bool wasEvent = false;
+    if ( bWait )
+        wasEvent = dispatcher->processEvents( QEventLoop::WaitForMoreEvents );
+    else
+        wasEvent = dispatcher->processEvents( QEventLoop::AllEvents );
+    return wasEvent;
+}
+
+void KDEXLib::StartTimer( sal_uLong nMS )
+{
+    if( !m_isGlibEventLoopType )
+        return SalXLib::StartTimer( nMS );
+    timeoutTimer.setInterval( nMS );
+    // QTimer's can be started only in their thread (main thread here)
+    if( qApp->thread() == QThread::currentThread())
+        startTimeoutTimer();
+    else
+        Q_EMIT startTimeoutTimerSignal();
+}
+
+void KDEXLib::startTimeoutTimer()
+{
+    timeoutTimer.start();
+}
+
+void KDEXLib::StopTimer()
+{
+    if( !m_isGlibEventLoopType )
+        return SalXLib::StopTimer();
+    timeoutTimer.stop();
+}
+
+void KDEXLib::timeoutActivated()
+{
+    // don't potentially wait in timeout, as QTimer is non-recursive
+    QApplication::postEvent(this, new QEvent(QEvent::Type( m_timerEventId )));
+}
+
+void KDEXLib::customEvent(QEvent* e)
+{
+    if( e->type() == m_timerEventId )
+        X11SalData::Timeout();
+    else if( e->type() == m_postUserEventId )
+        SalKDEDisplay::self()->DispatchInternalEvent();
+}
+
+void KDEXLib::Wakeup()
+{
+    if( !m_isGlibEventLoopType )
+        return SalXLib::Wakeup();
+    QAbstractEventDispatcher::instance( qApp->thread())->wakeUp(); // main thread event loop
+}
+
+void KDEXLib::PostUserEvent()
+{
+    if( !m_isGlibEventLoopType )
+        return SalXLib::PostUserEvent();
+    QApplication::postEvent(this, new QEvent(QEvent::Type( m_postUserEventId )));
+}
+
+void KDEXLib::doStartup()
+{
+    if( ! m_bStartupDone )
+    {
+        //KStartupInfo::appStarted();
+        m_bStartupDone = true;
+        SAL_INFO( "vcl.kde4", "called KStartupInfo::appStarted()" );
+    }
+}
+
+using namespace com::sun::star;
+
+uno::Reference< ui::dialogs::XFilePicker2 > KDEXLib::createFilePicker(
+        const uno::Reference< uno::XComponentContext >& xMSF )
+{
+#if KF5_HAVE_GLIB
+    if( qApp->thread() != QThread::currentThread()) {
+        SalYieldMutexReleaser aReleaser;
+        return Q_EMIT createFilePickerSignal( xMSF );
+    }
+    return uno::Reference< ui::dialogs::XFilePicker2 >( new KDE4FilePicker( xMSF ) );
+#else
+    (void)xMSF;
+    return NULL;
+#endif
+}
+
+#include "KDE5XLib.moc"
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/kde5/KDE5XLib.hxx b/vcl/unx/kde5/KDE5XLib.hxx
new file mode 100644
index 000000000000..cb506edea1c6
--- /dev/null
+++ b/vcl/unx/kde5/KDE5XLib.hxx
@@ -0,0 +1,102 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <memory>
+
+#include <unx/saldisp.hxx>
+
+//#include <fixx11h.h>
+//
+#include <QtCore/QObject>
+#include <QtCore/QHash>
+#include <QtCore/QSocketNotifier>
+#include <QtCore/QTimer>
+#include <QtCore/QAbstractNativeEventFilter>
+
+#include <unx/salinst.h>
+
+class VCLKDEApplication;
+
+class KDEXLib : public QObject, public QAbstractNativeEventFilter, public SalXLib
+{
+    Q_OBJECT
+    private:
+        bool m_bStartupDone;
+        std::unique_ptr<VCLKDEApplication> m_pApplication;
+        std::unique_ptr<char*[]> m_pFreeCmdLineArgs;
+        std::unique_ptr<char*[]> m_pAppCmdLineArgs;
+        int m_nFakeCmdLineArgs;
+        struct SocketData
+            {
+            void* data;
+            YieldFunc pending;
+            YieldFunc queued;
+            YieldFunc handle;
+            QSocketNotifier* notifier;
+            };
+        QHash< int, SocketData > socketData; // key is fd
+        QTimer timeoutTimer;
+        bool m_isGlibEventLoopType;
+        bool m_allowKdeDialogs;
+        int m_timerEventId;

... etc. - the rest is truncated


More information about the Libreoffice-commits mailing list