Kaydet (Commit) dd7a3147 authored tarafından Katarina Behrens's avatar Katarina Behrens Kaydeden (comit) Thorsten Behrens

kde5: copy basic kde4 blocks -> kde5 and build againt qt5/kf5 libs

Change-Id: I70f0c4147721a20459e1183ff40cf0ac8adf49e6
üst 07cd70c8
# -*- 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:
# -*- 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:
...@@ -81,6 +81,12 @@ $(eval $(call gb_Module_add_targets,vcl,\ ...@@ -81,6 +81,12 @@ $(eval $(call gb_Module_add_targets,vcl,\
Library_vclplug_kde4 \ Library_vclplug_kde4 \
)) ))
endif endif
ifneq ($(ENABLE_KDE5),)
$(eval $(call gb_Module_add_targets,vcl,\
CustomTarget_kde5_moc \
Library_vclplug_kde5 \
))
endif
endif endif
ifeq ($(OS),MACOSX) ifeq ($(OS),MACOSX)
......
/* -*- 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: */
/* -*- 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: */
/* -*- 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: */
/* -*- 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: */
/* -*- 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: */
/* -*- 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: */
/* -*- 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: */
/* -*- 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: */
/* -*- 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: */
/* -*- 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: */
/* -*- 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: */
/* -*- 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@lists.freedesktop.org"));
kAboutData->addAuthor( i18n( "Jan Holesovsky" ),
i18n( "Original author and maintainer of the KDE NWF." ),
"kendy@artax.karlin.mff.cuni.cz",
"http://artax.karlin.mff.cuni.cz/~kendy" );
kAboutData->addAuthor( i18n("Roman Shtylman"),
i18n( "Porting to KDE 4." ),
"shtylman@gmail.com", "http://shtylman.com" );
kAboutData->addAuthor( i18n("Eric Bischoff"),
i18n( "Accessibility fixes, porting to KDE 4." ),
"bischoff@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: */
/* -*- 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;
int m_postUserEventId;
private:
void setupEventLoop();
private Q_SLOTS:
void socketNotifierActivated( int fd );
void timeoutActivated();
void startTimeoutTimer();
static bool processYield( bool bWait, bool bHandleAllCurrentEvents );
Q_SIGNALS:
void startTimeoutTimerSignal();
void processYieldSignal( bool bWait, bool bHandleAllCurrentEvents );
css::uno::Reference< css::ui::dialogs::XFilePicker2 >
createFilePickerSignal( const css::uno::Reference< css::uno::XComponentContext >& );
public:
KDEXLib();
virtual ~KDEXLib() override;
virtual void Init() override;
virtual bool Yield( bool bWait, bool bHandleAllCurrentEvents ) override;
virtual void Insert( int fd, void* data, YieldFunc pending, YieldFunc queued, YieldFunc handle ) override;
virtual void Remove( int fd ) override;
virtual void StartTimer( sal_uLong nMS ) override;
virtual void StopTimer() override;
virtual void Wakeup() override;
virtual void PostUserEvent() override;
void doStartup();
bool allowKdeDialogs() { return m_allowKdeDialogs; }
virtual void customEvent(QEvent* e) override;
public Q_SLOTS:
css::uno::Reference< css::ui::dialogs::XFilePicker2 >
createFilePicker( const css::uno::Reference< css::uno::XComponentContext >& );
public:
virtual bool nativeEventFilter(const QByteArray &eventType, void *message, long *) override;
};
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
/* -*- 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 <QtGui/QClipboard>
#include <QtCore/QEvent>
#include "KDE5SalDisplay.hxx"
VCLKDEApplication::VCLKDEApplication() :
KApplication()
{
}
// various hacks to be performed before re-entering Qt's event loop
// because of showing a Qt dialog
void VCLKDEApplication::preDialogSetup()
{
// KFileDialog integration requires using event loop with QClipboard.
// Opening the KDE file dialog here can lead to QClipboard
// asking for clipboard contents. If LO core is the owner of the clipboard
// content, without event loop use this will block for 5 seconds and timeout,
// since the clipboard thread will not be able to acquire SolarMutex
// and thus won't be able to respond. If the event loops
// are properly integrated and QClipboard can use a nested event loop
// (see the KDE VCL plug), then this won't happen.
// We cannot simply release SolarMutex here, because the event loop started
// by the file dialog would also call back to LO code.
assert( QApplication::clipboard()->property( "useEventLoopWhenWaiting" ).toBool() );
}
// various hacks to be performed after a Qt dialog has been closed
void VCLKDEApplication::postDialogCleanup()
{
// HACK: KFileDialog uses KConfig("kdeglobals") for saving some settings
// (such as the auto-extension flag), but that doesn't update KGlobal::config()
// (which is probably a KDE bug), so force reading the new configuration,
// otherwise the next opening of the dialog would use the old settings.
KGlobal::config()->reparseConfiguration();
// HACK: If Qt owns clipboard or selection, give up on their ownership now. Otherwise
// LO core might ask for the contents, but it would block while doing so (i.e. it
// doesn't seem to have an equivalent of QClipboard's "useEventLoopWhenWaiting"),
// therefore QClipboard wouldn't be able to respond, and whole LO would block until
// a timeout. Given that Klipper is most probably running, giving up clipboard/selection
// ownership will not only avoid the blocking, but even pasting that content in LO
// will in fact work, if Klipper can handle it.
// Technically proper solution would be of course to allow Qt to process QClipboard
// events while LO waits for clipboard contents, or short-circuit to QClipboard somehow
// (it's a mystery why LO's clipboard handling has its own thread when whole LO can
// get blocked by both trying to send and receive clipboard contents anyway).
QClipboard* clipboard = QApplication::clipboard();
if( clipboard->ownsSelection())
clipboard->clear( QClipboard::Selection );
if( clipboard->ownsClipboard())
clipboard->clear();
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
/* -*- 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 .
*/
#ifndef _VCLKDE5APPLICATION_HXX_
#define _VCLKDE5APPLICATION_HXX_
#pragma once
#include <QtWidgets/QApplication>
#include <QtCore/QAbstractNativeEventFilter>
#undef Region
class VCLKDEApplication : public QApplication, public QAbstractNativeEventFilter
{
public:
VCLKDEApplication();
static void preDialogSetup();
static void postDialogCleanup();
};
#endif
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
/* -*- 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/QApplication>
#include "KDE5Data.hxx"
#include "KDE5SalInstance.hxx"
#include <vclpluginapi.h>
#include <rtl/string.hxx>
/// entry point for the KDE4 VCL plugin
extern "C" {
VCLPLUG_KDE4_PUBLIC SalInstance* create_SalInstance()
{
/* #i92121# workaround deadlocks in the X11 implementation
*/
static const char* pNoXInitThreads = getenv( "SAL_NO_XINITTHREADS" );
/* #i90094#
from now on we know that an X connection will be
established, so protect X against itself
*/
if( ! ( pNoXInitThreads && *pNoXInitThreads ) )
{
#if QT_VERSION >= 0x040800
// let Qt call XInitThreads(), so that also Qt knows it's been used
// (otherwise QPixmap may warn about threads not being initialized)
QApplication::setAttribute( Qt::AA_X11InitThreads );
#else
XInitThreads();
// just in case somebody builds with old version and then upgrades Qt,
// otherwise this is a no-op
QApplication::setAttribute( static_cast< Qt::ApplicationAttribute >( 10 ));
#endif
}
#if QT_VERSION < 0x050000
// Qt 4.x support needs >= 4.1.0
OString aVersion( qVersion() );
SAL_INFO( "vcl.kde4", "qt version string is " << aVersion );
sal_Int32 nIndex = 0, nMajor = 0, nMinor = 0;
nMajor = aVersion.getToken( 0, '.', nIndex ).toInt32();
if( nIndex > 0 )
nMinor = aVersion.getToken( 0, '.', nIndex ).toInt32();
if( nMajor != 4 || nMinor < 1 )
{
#if OSL_DEBUG_LEVEL > 1
sal_Int32 nMicro = 0;
if( nIndex > 0 )
nMicro = aVersion.getToken( 0, '.', nIndex ).toInt32();
SAL_INFO( "vcl.kde4", "unsuitable qt version " << nMajor << "." << nMinor << "." << nMicro );
#endif
return nullptr;
}
#endif
KDESalInstance* pInstance = new KDESalInstance( new SalYieldMutex() );
SAL_INFO( "vcl.kde4", "created KDESalInstance " << &pInstance );
// initialize SalData
KDEData *salData = new KDEData( pInstance );
salData->Init();
salData->initNWF();
pInstance->SetLib(salData->GetLib());
return pInstance;
}
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
/* -*- 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 .
*
* This code is based on the SocketEventsTester from the Qt4 test suite.
*/
#pragma once
#include <QtCore/QCoreApplication>
#include <QtCore/QEventLoop>
const QEvent::Type eventType = QEvent::User;
class TestExcludePostedEvents
: public QObject
{
Q_OBJECT
public:
TestExcludePostedEvents();
virtual bool event( QEvent* e ) override;
bool processed;
};
TestExcludePostedEvents::TestExcludePostedEvents()
: processed( false )
{
}
bool TestExcludePostedEvents::event( QEvent* e )
{
if( e->type() == eventType )
processed = true;
return QObject::event( e );
}
#define QVERIFY(a) \
if (!a) return 1;
static int tst_excludePostedEvents()
{
TestExcludePostedEvents test;
QCoreApplication::postEvent( &test, new QEvent( eventType ));
QEventLoop loop;
loop.processEvents(QEventLoop::ExcludeUserInputEvents
| QEventLoop::ExcludeSocketNotifiers
// | QEventLoop::WaitForMoreEvents
| QEventLoop::X11ExcludeTimers);
QVERIFY( !test.processed );
loop.processEvents();
QVERIFY( test.processed );
return 0;
}
/* -*- 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 .
*
* This code is based on the SocketEventsTester from the Qt4 test suite.
*/
#pragma once
#include <QtCore/QCoreApplication>
#include <QtCore/QEventLoop>
#include <QtCore/QSocketNotifier>
#include <unistd.h>
class TestExcludeSocketNotifiers
: public QObject
{
Q_OBJECT
public:
TestExcludeSocketNotifiers( const int* pipes );
virtual ~TestExcludeSocketNotifiers() override;
bool received;
public slots:
void slotReceived();
private:
const int* pipes;
};
TestExcludeSocketNotifiers::TestExcludeSocketNotifiers( const int* thePipes )
: received( false )
, pipes( thePipes )
{
}
TestExcludeSocketNotifiers::~TestExcludeSocketNotifiers()
{
close( pipes[ 0 ] );
close( pipes[ 1 ] );
}
void TestExcludeSocketNotifiers::slotReceived()
{
received = true;
}
#define QVERIFY(a) \
if (!a) return 1;
static int tst_processEventsExcludeSocket()
{
int pipes[ 2 ];
if( pipe( pipes ) < 0 )
return 1;
TestExcludeSocketNotifiers test( pipes );
QSocketNotifier notifier( pipes[ 0 ], QSocketNotifier::Read );
QObject::connect( &notifier, SIGNAL( activated( int )), &test, SLOT( slotReceived()));
char dummy = 'a';
if( 1 != write( pipes[ 1 ], &dummy, 1 ) )
return 1;
QEventLoop loop;
loop.processEvents( QEventLoop::ExcludeSocketNotifiers );
QVERIFY( !test.received );
loop.processEvents();
QVERIFY( test.received );
return 0;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment