diff options
Diffstat (limited to 'vcl/unx/kde4')
-rw-r--r-- | vcl/unx/kde4/KDEData.cxx | 57 | ||||
-rw-r--r-- | vcl/unx/kde4/KDEData.hxx | 45 | ||||
-rw-r--r-- | vcl/unx/kde4/KDESalDisplay.cxx | 97 | ||||
-rw-r--r-- | vcl/unx/kde4/KDESalDisplay.hxx | 55 | ||||
-rw-r--r-- | vcl/unx/kde4/KDESalFrame.cxx | 407 | ||||
-rw-r--r-- | vcl/unx/kde4/KDESalFrame.hxx | 61 | ||||
-rw-r--r-- | vcl/unx/kde4/KDESalGraphics.cxx | 992 | ||||
-rw-r--r-- | vcl/unx/kde4/KDESalGraphics.hxx | 117 | ||||
-rw-r--r-- | vcl/unx/kde4/KDESalInstance.cxx | 38 | ||||
-rw-r--r-- | vcl/unx/kde4/KDESalInstance.hxx | 44 | ||||
-rw-r--r-- | vcl/unx/kde4/KDEXLib.cxx | 422 | ||||
-rw-r--r-- | vcl/unx/kde4/KDEXLib.hxx | 94 | ||||
-rw-r--r-- | vcl/unx/kde4/VCLKDEApplication.cxx | 54 | ||||
-rw-r--r-- | vcl/unx/kde4/VCLKDEApplication.hxx | 52 | ||||
-rw-r--r-- | vcl/unx/kde4/main.cxx | 96 | ||||
-rw-r--r-- | vcl/unx/kde4/makefile.mk | 96 |
16 files changed, 2727 insertions, 0 deletions
diff --git a/vcl/unx/kde4/KDEData.cxx b/vcl/unx/kde4/KDEData.cxx new file mode 100644 index 000000000000..97654cf41e76 --- /dev/null +++ b/vcl/unx/kde4/KDEData.cxx @@ -0,0 +1,57 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "KDEData.hxx" + +#include "KDEXLib.hxx" + +KDEData::~KDEData() +{ +} + +void KDEData::Init() +{ + pXLib_ = new KDEXLib(); + pXLib_->Init(); +} + +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; +} + +void KDEData::deInitNWF() +{ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/unx/kde4/KDEData.hxx b/vcl/unx/kde4/KDEData.hxx new file mode 100644 index 000000000000..31dc7b9dcba7 --- /dev/null +++ b/vcl/unx/kde4/KDEData.hxx @@ -0,0 +1,45 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#pragma once + +#include <saldisp.hxx> +#include <saldata.hxx> + +class KDEData : public X11SalData +{ + public: + KDEData() {} + virtual ~KDEData(); + + virtual void Init(); + virtual void initNWF(); + virtual void deInitNWF(); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/unx/kde4/KDESalDisplay.cxx b/vcl/unx/kde4/KDESalDisplay.cxx new file mode 100644 index 000000000000..29292b68f142 --- /dev/null +++ b/vcl/unx/kde4/KDESalDisplay.cxx @@ -0,0 +1,97 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "KDESalDisplay.hxx" + +#include "KDEXLib.hxx" +#include "VCLKDEApplication.hxx" + +#include <assert.h> +#include <saldata.hxx> + +SalKDEDisplay* SalKDEDisplay::selfptr = NULL; + +SalKDEDisplay::SalKDEDisplay( Display* pDisp ) + : SalX11Display( pDisp ) +{ + assert( selfptr == NULL ); + 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 = NULL; + // prevent SalDisplay from closing KApplication's display + pDisp_ = NULL; +} + +void SalKDEDisplay::Yield() +{ + if( DispatchInternalEvent() ) + 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( XEvent* ev ) +{ + if( ev->xany.type == XLIB_KeyPress || ev->xany.type == KeyRelease + || ( ev->xany.type == ClientMessage && ev->xclient.message_type == xim_protocol )) + { + if( qApp->activeWindow() == NULL ) + { + Dispatch(ev); + return true; + } + } + return false; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/unx/kde4/KDESalDisplay.hxx b/vcl/unx/kde4/KDESalDisplay.hxx new file mode 100644 index 000000000000..3b7117684942 --- /dev/null +++ b/vcl/unx/kde4/KDESalDisplay.hxx @@ -0,0 +1,55 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#pragma once + +#include <saldisp.hxx> + +class SalKDEDisplay : public SalX11Display +{ + public: + SalKDEDisplay( Display* pDisp ); + virtual ~SalKDEDisplay(); + static SalKDEDisplay* self(); + inline int userEventsCount() const { return m_aUserEvents.size(); } + inline void EventGuardAcquire() { osl_acquireMutex( hEventGuard_ ); } + inline void EventGuardRelease() { osl_releaseMutex( hEventGuard_ ); } +// virtual long Dispatch( XEvent *event ); + virtual void Yield(); + bool checkDirectInputEvent( XEvent* ev ); + private: + Atom xim_protocol; + static SalKDEDisplay* selfptr; +}; + +inline SalKDEDisplay* SalKDEDisplay::self() +{ + return selfptr; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/unx/kde4/KDESalFrame.cxx b/vcl/unx/kde4/KDESalFrame.cxx new file mode 100644 index 000000000000..69826443a6c2 --- /dev/null +++ b/vcl/unx/kde4/KDESalFrame.cxx @@ -0,0 +1,407 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#define Region QtXRegion + +#include <QColor> +#include <QStyle> + +#include <kconfig.h> +#include <kglobal.h> +#include <kmenubar.h> +#include <kconfiggroup.h> +#include <kmainwindow.h> +#include <kapplication.h> +#include <ktoolbar.h> + +#undef Region + +#include "KDESalFrame.hxx" +#include "KDEXLib.hxx" +#include "KDESalGraphics.hxx" + +#include <vcl/settings.hxx> +#include <vcl/font.hxx> +#include <tools/color.hxx> + +#include <vcl/svdata.hxx> + +#include <pspgraphics.h> + +#if OSL_DEBUG_LEVEL > 1 +#include <stdio.h> +#endif + +KDESalFrame::KDESalFrame( SalFrame* pParent, sal_uLong nState ) : + X11SalFrame( pParent, nState ) +{ +} + +void KDESalFrame::Show( sal_Bool bVisible, sal_Bool bNoActivate ) +{ + if ( !GetParent() && ! (GetStyle() & SAL_FRAME_STYLE_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 read untranslated text entry from KConfig configuration repository. +*/ +static OUString readEntryUntranslated( KConfigGroup *pGroup, const char *pKey ) +{ + return OUString::createFromAscii( (const char *) pGroup->readEntryUntranslated( pKey ).toAscii() ); +} + +#if 0 +#endif +/** Helper function to add information to Font from QFont. + + Mostly grabbed from the Gtk+ vclplug (salnativewidgets-gtk.cxx). +*/ +static Font toFont( const QFont &rQFont, const ::com::sun::star::lang::Locale& rLocale ) +{ + psp::FastPrintFontInfo aInfo; + QFontInfo qFontInfo( rQFont ); + + // set family name + aInfo.m_aFamilyName = String( (const char *) rQFont.family().toUtf8(), RTL_TEXTENCODING_UTF8 ); + + // set italic + aInfo.m_eItalic = ( qFontInfo.italic()? psp::italic::Italic: psp::italic::Upright ); + + // set weight + int nWeight = qFontInfo.weight(); + if ( nWeight <= QFont::Light ) + aInfo.m_eWeight = psp::weight::Light; + else if ( nWeight <= QFont::Normal ) + aInfo.m_eWeight = psp::weight::Normal; + else if ( nWeight <= QFont::DemiBold ) + aInfo.m_eWeight = psp::weight::SemiBold; + else if ( nWeight <= QFont::Bold ) + aInfo.m_eWeight = psp::weight::Bold; + else + aInfo.m_eWeight = psp::weight::UltraBold; + + // set width + int nStretch = rQFont.stretch(); + if ( nStretch <= QFont::UltraCondensed ) + aInfo.m_eWidth = psp::width::UltraCondensed; + else if ( nStretch <= QFont::ExtraCondensed ) + aInfo.m_eWidth = psp::width::ExtraCondensed; + else if ( nStretch <= QFont::Condensed ) + aInfo.m_eWidth = psp::width::Condensed; + else if ( nStretch <= QFont::SemiCondensed ) + aInfo.m_eWidth = psp::width::SemiCondensed; + else if ( nStretch <= QFont::Unstretched ) + aInfo.m_eWidth = psp::width::Normal; + else if ( nStretch <= QFont::SemiExpanded ) + aInfo.m_eWidth = psp::width::SemiExpanded; + else if ( nStretch <= QFont::Expanded ) + aInfo.m_eWidth = psp::width::Expanded; + else if ( nStretch <= QFont::ExtraExpanded ) + aInfo.m_eWidth = psp::width::ExtraExpanded; + else + aInfo.m_eWidth = psp::width::UltraExpanded; + +#if OSL_DEBUG_LEVEL > 1 + fprintf( stderr, "font name BEFORE system match: \"%s\"\n", OUStringToOString( aInfo.m_aFamilyName, RTL_TEXTENCODING_ISO_8859_1 ).getStr() ); +#endif + + // match font to e.g. resolve "Sans" + psp::PrintFontManager::get().matchFont( aInfo, rLocale ); + +#if OSL_DEBUG_LEVEL > 1 + fprintf( stderr, "font match %s, name AFTER: \"%s\"\n", + aInfo.m_nID != 0 ? "succeeded" : "failed", + OUStringToOString( aInfo.m_aFamilyName, RTL_TEXTENCODING_ISO_8859_1 ).getStr() ); +#endif + + // font height + int nPointHeight = qFontInfo.pointSize(); + if ( nPointHeight <= 0 ) + nPointHeight = rQFont.pointSize(); + + // Create the font + Font aFont( aInfo.m_aFamilyName, Size( 0, nPointHeight ) ); + if( aInfo.m_eWeight != psp::weight::Unknown ) + aFont.SetWeight( PspGraphics::ToFontWeight( aInfo.m_eWeight ) ); + if( aInfo.m_eWidth != psp::width::Unknown ) + aFont.SetWidthType( PspGraphics::ToFontWidth( aInfo.m_eWidth ) ); + if( aInfo.m_eItalic != psp::italic::Unknown ) + aFont.SetItalic( PspGraphics::ToFontItalic( aInfo.m_eItalic ) ); + if( aInfo.m_ePitch != psp::pitch::Unknown ) + aFont.SetPitch( PspGraphics::ToFontPitch( aInfo.m_ePitch ) ); + + 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 = kapp->palette(); + + style.SetToolbarIconSize( STYLE_TOOLBAR_ICONSIZE_LARGE ); + + style.SetActiveColor(toColor(pal.color(QPalette::Active, QPalette::Window))); + style.SetDeactiveColor(toColor(pal.color(QPalette::Inactive, QPalette::Window))); + + style.SetActiveColor2(toColor(pal.color(QPalette::Active, QPalette::Window))); + style.SetDeactiveColor2(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 ) + { + KConfigGroup aGroup = pConfig->group( "WM" ); + const char *pKey; + + pKey = "titleFont"; + if ( aGroup.hasKey( pKey ) ) + { + Font aFont = toFont( aGroup.readEntry( pKey, QFont() ), rSettings.GetUILocale() ); + style.SetTitleFont( aFont ); + bSetTitleFont = true; + } + + aGroup = pConfig->group( "Icons" ); + + pKey = "Theme"; + if ( aGroup.hasKey( pKey ) ) + style.SetPreferredSymbolsStyleName( readEntryUntranslated( &aGroup, pKey ) ); + + //toolbar + pKey = "toolbarFont"; + if ( aGroup.hasKey( pKey ) ) + { + Font aFont = toFont( aGroup.readEntry( pKey, QFont() ), rSettings.GetUILocale() ); + 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 ) ); + + // Foreground + style.SetRadioCheckTextColor( aFore ); + style.SetLabelTextColor( aFore ); + style.SetInfoTextColor( aFore ); + style.SetDialogTextColor( aFore ); + style.SetGroupTextColor( aFore ); + + // Text + style.SetFieldTextColor( aText ); + style.SetFieldRolloverTextColor( aText ); + style.SetWindowTextColor( aText ); + style.SetHelpTextColor( aText ); + + // Base + style.SetFieldColor( aBase ); + style.SetHelpColor( aBase ); + style.SetWindowColor( aBase ); + style.SetActiveTabColor( aBase ); + + // Buttons + style.SetButtonTextColor( aButn ); + style.SetButtonRolloverTextColor( aButn ); + + // Disable color + style.SetDisableColor( aMid ); + + // Workspace + style.SetWorkspaceColor( aMid ); + + // Background + style.Set3DColors( aBack ); + style.SetFaceColor( aBack ); + style.SetInactiveTabColor( aBack ); + style.SetDialogColor( aBack ); + + if( aBack == COL_LIGHTGRAY ) + style.SetCheckedColor( Color( 0xCC, 0xCC, 0xCC ) ); + else + { + Color aColor2 = style.GetLightColor(); + style. + SetCheckedColor( Color( (sal_uInt8)(((sal_uInt16)aBack.GetRed()+(sal_uInt16)aColor2.GetRed())/2), + (sal_uInt8)(((sal_uInt16)aBack.GetGreen()+(sal_uInt16)aColor2.GetGreen())/2), + (sal_uInt8)(((sal_uInt16)aBack.GetBlue()+(sal_uInt16)aColor2.GetBlue())/2) + ) ); + } + + // Selection + style.SetHighlightColor( aHigh ); + style.SetHighlightTextColor( toColor(pal.color( QPalette::HighlightedText)) ); + + // Font + Font aFont = toFont( kapp->font(), rSettings.GetUILocale() ); + + style.SetAppFont( aFont ); + style.SetHelpFont( aFont ); + + style.SetMenuFont( aFont ); // will be changed according to pMenuBar + //style.SetToolFont( aFont ); //already set above + style.SetLabelFont( aFont ); + style.SetInfoFont( aFont ); + style.SetRadioCheckFont( aFont ); + style.SetPushButtonFont( aFont ); + style.SetFieldFont( aFont ); + style.SetIconFont( aFont ); + style.SetGroupFont( aFont ); + + aFont.SetWeight( WEIGHT_BOLD ); + if( !bSetTitleFont ) + { + style.SetTitleFont( aFont ); + } + style.SetFloatTitleFont( aFont ); + + int flash_time = QApplication::cursorFlashTime(); + style.SetCursorBlinkTime( flash_time != 0 ? flash_time/2 : STYLE_CURSOR_NOBLINKTIME ); + + // Menu + style.SetSkipDisabledInMenus( TRUE ); + KMenuBar* pMenuBar = new KMenuBar(); + if ( pMenuBar ) + { + // Color + 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 ) ); + + aMenuFore = toColor( qMenuCG.color( QPalette::ButtonText ) ); + aMenuBack = toColor( qMenuCG.color( QPalette::Button ) ); + + style.SetMenuTextColor( aMenuFore ); + style.SetMenuBarTextColor( aMenuFore ); + style.SetMenuColor( aMenuBack ); + style.SetMenuBarColor( aMenuBack ); + + style.SetMenuHighlightColor( toColor ( qMenuCG.color( QPalette::Highlight ) ) ); + + style.SetMenuHighlightTextColor( aMenuFore ); + + // set special menubar higlight text color + if ( kapp->style()->inherits( "HighContrastStyle" ) ) + ImplGetSVData()->maNWFData.maMenuBarHighlightTextColor = toColor( qMenuCG.color( QPalette::HighlightedText ) ); + else + ImplGetSVData()->maNWFData.maMenuBarHighlightTextColor = aMenuFore; + + // Font + aFont = toFont( pMenuBar->font(), rSettings.GetUILocale() ); + style.SetMenuFont( aFont ); + } + + delete pMenuBar; + + // Scroll bar size + style.SetScrollBarSize( kapp->style()->pixelMetric( QStyle::PM_ScrollBarExtent ) ); + style.SetMinThumbSize( kapp->style()->pixelMetric( QStyle::PM_ScrollBarSliderMin )); + + rSettings.SetStyleSettings( style ); +} + + +void KDESalFrame::ReleaseGraphics( SalGraphics *pGraphics ) +{ + for( int i = 0; i < nMaxGraphics; i++ ) + { + if( m_aGraphics[i].pGraphics == 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() ); + } +} + +KDESalFrame::~KDESalFrame() +{ +} + +KDESalFrame::GraphicsHolder::~GraphicsHolder() +{ + delete pGraphics; +} + +SalGraphics* KDESalFrame::GetGraphics() +{ + 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 = new KDESalGraphics(); + m_aGraphics[i].pGraphics->Init( this, GetWindow(), GetScreenNumber() ); + } + return m_aGraphics[i].pGraphics; + } + } + } + + return NULL; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/unx/kde4/KDESalFrame.hxx b/vcl/unx/kde4/KDESalFrame.hxx new file mode 100644 index 000000000000..f006a6e0d796 --- /dev/null +++ b/vcl/unx/kde4/KDESalFrame.hxx @@ -0,0 +1,61 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#pragma once + +#include <saldisp.hxx> +#include <salframe.h> + +class KDESalFrame : public X11SalFrame +{ + private: + static const int nMaxGraphics = 2; + + struct GraphicsHolder + { + X11SalGraphics* pGraphics; + bool bInUse; + + GraphicsHolder() : pGraphics(0),bInUse( false ) {} + ~GraphicsHolder(); + }; + + GraphicsHolder m_aGraphics[ nMaxGraphics ]; + + public: + KDESalFrame( SalFrame* pParent, sal_uLong nStyle ); + virtual ~KDESalFrame(); + + virtual SalGraphics* GetGraphics(); + virtual void ReleaseGraphics( SalGraphics *pGraphics ); + virtual void updateGraphics( bool bClear ); + virtual void UpdateSettings( AllSettings& rSettings ); + virtual void Show( sal_Bool bVisible, sal_Bool bNoActivate ); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/unx/kde4/KDESalGraphics.cxx b/vcl/unx/kde4/KDESalGraphics.cxx new file mode 100644 index 000000000000..04f71bfbed3d --- /dev/null +++ b/vcl/unx/kde4/KDESalGraphics.cxx @@ -0,0 +1,992 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_vcl.hxx" + +#define _SV_SALNATIVEWIDGETS_KDE_CXX + +#define Region QtXRegion + +#include <QStyle> +#include <QStyleOption> +#include <QPainter> +#include <QFrame> +#include <QLabel> + +#include <kapplication.h> +#include <kdebug.h> + +#undef Region + +#include "KDESalGraphics.hxx" + +#include "vcl/settings.hxx" +#include "vcl/decoview.hxx" +#include "rtl/ustrbuf.hxx" + +using namespace ::rtl; + +/** + 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 & CTRL_STATE_DEFAULT)? QStyle::State_None: QStyle::State_None ) | + ( (nControlState & CTRL_STATE_ENABLED)? QStyle::State_Enabled: QStyle::State_None ) | + ( (nControlState & CTRL_STATE_FOCUSED)? QStyle::State_HasFocus: QStyle::State_None ) | + ( (nControlState & CTRL_STATE_PRESSED)? QStyle::State_Sunken: QStyle::State_None ) | + ( (nControlState & CTRL_STATE_SELECTED)? QStyle::State_Selected : QStyle::State_None ) | + ( (nControlState & CTRL_STATE_ROLLOVER)? QStyle::State_MouseOver: QStyle::State_None ); + //TODO ( (nControlState & CTRL_STATE_HIDDEN)? QStyle::State_: 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 VCL Rectangle to QRect. + @param rControlRegion The Rectangle to convert. + @return The matching QRect +*/ +QRect region2QRect( const Rectangle& rControlRegion ) +{ + return QRect(rControlRegion.Left(), rControlRegion.Top(), rControlRegion.GetWidth(), rControlRegion.GetHeight()); +} + +KDESalGraphics::KDESalGraphics() : + m_image(0) +{ +} + +KDESalGraphics::~KDESalGraphics() +{ + if (m_image) + delete m_image; +} + +sal_Bool KDESalGraphics::IsNativeControlSupported( ControlType type, ControlPart part ) +{ + if (type == CTRL_PUSHBUTTON) return true; + + if (type == CTRL_MENUBAR) return true; + + if (type == CTRL_MENU_POPUP) return true; + + if (type == CTRL_EDITBOX) return true; + + if (type == CTRL_COMBOBOX) return true; + + if (type == CTRL_TOOLBAR) return true; + + if (type == CTRL_CHECKBOX) return true; + + if (type == CTRL_LISTBOX) return true; + + if (type == CTRL_LISTNODE) return true; + + if (type == CTRL_FRAME) return true; + + if (type == CTRL_SCROLLBAR) return true; + + if (type == CTRL_WINDOW_BACKGROUND) return true; + + if (type == CTRL_SPINBOX && (part == PART_ENTIRE_CONTROL || part == HAS_BACKGROUND_TEXTURE) ) return true; + + // no spinbuttons for KDE, paint spinbox complete + //if (type == CTRL_SPINBUTTONS) return true; + + if (type == CTRL_GROUPBOX) return true; + + if (type == CTRL_FIXEDLINE) return true; + + if (type == CTRL_FIXEDBORDER) return true; + + if (type == CTRL_TOOLTIP) return true; + + if (type == CTRL_RADIOBUTTON) return true; + + if (type == CTRL_SLIDER && (part == PART_TRACK_HORZ_AREA || part == PART_TRACK_VERT_AREA) ) + return true; + + if ( (type == CTRL_PROGRESS) && (part == PART_ENTIRE_CONTROL) ) return true; + + return false; + + if ( (type == CTRL_TAB_ITEM) && (part == PART_ENTIRE_CONTROL) ) return true; + if ( (type == CTRL_TAB_PANE) && (part == PART_ENTIRE_CONTROL) ) return true; + // no CTRL_TAB_BODY for KDE + + return false; +} + +/// helper drawing methods +namespace +{ + void draw( QStyle::ControlElement element, QStyleOption* option, QImage* image, QStyle::State state, QRect rect = QRect()) + { + option->state |= state; + option->rect = !rect.isNull() ? rect : image->rect(); + + QPainter painter(image); + kapp->style()->drawControl(element, option, &painter); + } + + void draw( QStyle::PrimitiveElement element, QStyleOption* option, QImage* image, QStyle::State state, QRect rect = QRect()) + { + option->state |= state; + option->rect = !rect.isNull() ? rect : image->rect(); + + QPainter painter(image); + kapp->style()->drawPrimitive(element, option, &painter); + } + + void draw( QStyle::ComplexControl element, QStyleOptionComplex* option, QImage* image, QStyle::State state ) + { + option->state |= state; + option->rect = image->rect(); + + QPainter painter(image); + kapp->style()->drawComplexControl(element, option, &painter); + } + + int getFrameWidth() + { + static int s_nFrameWidth = -1; + if( s_nFrameWidth < 0 ) + { + // fill in a default + s_nFrameWidth = 2; + QFrame aFrame( NULL ); + aFrame.setFrameRect( QRect(0, 0, 100, 30) ); + aFrame.setFrameStyle( QFrame::StyledPanel | QFrame::Sunken ); + aFrame.ensurePolished(); + s_nFrameWidth = aFrame.frameWidth(); + } + return s_nFrameWidth; + } + + void lcl_drawFrame(QStyle::PrimitiveElement element, QImage* image, QStyle::State state) + { + #if ( QT_VERSION >= QT_VERSION_CHECK( 4, 5, 0 ) ) + QStyleOptionFrameV3 option; + option.frameShape = QFrame::StyledPanel; + option.state = QStyle::State_Sunken; + #else + QStyleOptionFrame option; + + QFrame aFrame( NULL ); + 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 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( XLIB_Region xr ) +{ + QRegion qr; + for( int 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 + +sal_Bool KDESalGraphics::drawNativeControl( ControlType type, ControlPart part, + const Rectangle& rControlRegion, ControlState nControlState, + const ImplControlValue& value, + const OUString& ) +{ + if( lastPopupRect.isValid() && ( type != CTRL_MENU_POPUP || part != PART_MENU_ITEM )) + lastPopupRect = QRect(); + + // put not implemented types here + if (type == CTRL_SPINBUTTONS) + { + return false; + } + + sal_Bool returnVal = true; + + QRect widgetRect = region2QRect(rControlRegion); + if( type == CTRL_SPINBOX && part == PART_ALL_BUTTONS ) + type = CTRL_SPINBUTTONS; + if( type == CTRL_SPINBUTTONS ) + { + OSL_ASSERT( value.getType() != CTRL_SPINBUTTONS ); + const SpinbuttonValue* pSpinVal = static_cast<const SpinbuttonValue *>(&value); + Rectangle aButtonRect( pSpinVal->maUpperRect); + aButtonRect.Union( pSpinVal->maLowerRect );; + widgetRect = QRect( aButtonRect.Left(), aButtonRect.Top(), + aButtonRect.Right(), aButtonRect.Bottom() ); + } + + //if no image, or resized, make a new image + if (!m_image || m_image->size() != widgetRect.size()) + { + if (m_image) + delete m_image; + + m_image = new QImage( widgetRect.width(), + widgetRect.height(), + QImage::Format_ARGB32 ); + } + m_image->fill(KApplication::palette().color(QPalette::Window).rgb()); + + QRegion* clipRegion = NULL; + + if (type == CTRL_PUSHBUTTON) + { + QStyleOptionButton option; + draw( QStyle::CE_PushButton, &option, m_image, + vclStateValue2StateFlag(nControlState, value) ); + } + else if ( (type == CTRL_MENUBAR)) + { + if (part == PART_MENU_ITEM) + { + QStyleOptionMenuItem option; + draw( QStyle::CE_MenuBarItem, &option, m_image, + vclStateValue2StateFlag(nControlState, value) ); + } + else if (part == PART_ENTIRE_CONTROL) + { + } + else + { + returnVal = false; + } + } + else if (type == CTRL_MENU_POPUP) + { + OSL_ASSERT( part == PART_MENU_ITEM ? lastPopupRect.isValid() : !lastPopupRect.isValid()); + if( part == PART_MENU_ITEM ) + { + QStyleOptionMenuItem option; + draw( QStyle::CE_MenuItem, &option, m_image, + 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 PART_MENU_ITEM + // are always preceded by calls to PART_ENTIRE_CONTROL, 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, vclStateValue2StateFlag( nControlState, value ), framerect ); + } + else if( part == PART_MENU_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 = kapp->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 = kapp->style()->pixelMetric( QStyle::PM_MenuPanelWidth ); + clipRegion = new QRegion( rect.translated( widgetRect.topLeft()).adjusted( fw, 0, -fw, 0 )); + draw( QStyle::CE_MenuItem, &option, m_image, + vclStateValue2StateFlag(nControlState, value), rect ); + } + else if( part == PART_MENU_ITEM_CHECK_MARK || part == PART_MENU_ITEM_RADIO_MARK ) + { + QStyleOptionMenuItem option; + option.checkType = ( part == PART_MENU_ITEM_CHECK_MARK ) + ? QStyleOptionMenuItem::NonExclusive : QStyleOptionMenuItem::Exclusive; + option.checked = ( nControlState & CTRL_STATE_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 + const MenupopupValue* menuVal = static_cast<const MenupopupValue*>(&value); + QRect menuItemRect( region2QRect( menuVal->maItemRect )); + QRect rect( menuItemRect.topLeft() - widgetRect.topLeft(), + widgetRect.size().expandedTo( menuItemRect.size())); + m_image->fill( Qt::transparent ); + draw( QStyle::CE_MenuItem, &option, m_image, + vclStateValue2StateFlag(nControlState, value), rect ); + } + else if( part == PART_ENTIRE_CONTROL ) + { + QStyleOptionMenuItem option; + draw( QStyle::PE_PanelMenu, &option, m_image, vclStateValue2StateFlag( nControlState, value )); + QStyleOptionFrame frame; + draw( QStyle::PE_FrameMenu, &frame, m_image, vclStateValue2StateFlag( nControlState, value )); + lastPopupRect = widgetRect; + } + else + returnVal = false; + } + else if ( (type == CTRL_TOOLBAR) && (part == PART_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, + vclStateValue2StateFlag(nControlState, value) ); + } + else if ( (type == CTRL_TOOLBAR) && (part == PART_ENTIRE_CONTROL) ) + { + QStyleOptionToolBar option; + + option.rect = QRect(0, 0, widgetRect.width(), widgetRect.height()); + option.state = vclStateValue2StateFlag( nControlState, value ); + + draw( QStyle::CE_ToolBar, &option, m_image, + vclStateValue2StateFlag(nControlState, value) ); + } + else if ( (type == CTRL_TOOLBAR) && (part == PART_THUMB_VERT) ) + { // reduce paint area only to the handle area + const int width = kapp->style()->pixelMetric(QStyle::PM_ToolBarHandleExtent); + QRect rect( 0, 0, width, widgetRect.height()); + clipRegion = new QRegion( widgetRect.x(), widgetRect.y(), width, widgetRect.height()); + + QStyleOption option; + option.state = QStyle::State_Horizontal; + + draw( QStyle::PE_IndicatorToolBarHandle, &option, m_image, + vclStateValue2StateFlag(nControlState, value), rect ); + } + else if (type == CTRL_EDITBOX) + { + QStyleOptionFrameV2 option; + draw( QStyle::PE_PanelLineEdit, &option, m_image, + vclStateValue2StateFlag(nControlState, value), m_image->rect().adjusted( 2, 2, -2, -2 )); + + draw( QStyle::PE_FrameLineEdit, &option, m_image, + vclStateValue2StateFlag(nControlState, value)); + } + else if (type == CTRL_COMBOBOX) + { + QStyleOptionComboBox option; + option.editable = true; + + draw( QStyle::CC_ComboBox, &option, m_image, + vclStateValue2StateFlag(nControlState, value) ); + } + else if (type == CTRL_LISTBOX) + { + if( part == PART_WINDOW ) + { + lcl_drawFrame( QStyle::PE_Frame, m_image, + vclStateValue2StateFlag(nControlState, value) ); + } + else + { + QStyleOptionComboBox option; + if (part == PART_SUB_EDIT) + { + draw( QStyle::CE_ComboBoxLabel, &option, m_image, + vclStateValue2StateFlag(nControlState, value) ); + } + else + { + draw( QStyle::CC_ComboBox, &option, m_image, + vclStateValue2StateFlag(nControlState, value) ); + } + } + } + else if (type == CTRL_LISTNODE) + { + QStyleOption option; + option.state = QStyle::State_Item | QStyle::State_Children; + + if (nControlState & CTRL_STATE_PRESSED) + option.state |= QStyle::State_Open; + + draw( QStyle::PE_IndicatorBranch, &option, m_image, + vclStateValue2StateFlag(nControlState, value) ); + } + else if (type == CTRL_CHECKBOX) + { + QStyleOptionButton option; + draw( QStyle::CE_CheckBox, &option, m_image, + vclStateValue2StateFlag(nControlState, value) ); + } + else if (type == CTRL_SCROLLBAR) + { + if ((part == PART_DRAW_BACKGROUND_VERT) || (part == PART_DRAW_BACKGROUND_HORZ)) + { + QStyleOptionSlider option; + OSL_ASSERT( value.getType() == CTRL_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; + + //horizontal or vertical + if (part == PART_DRAW_BACKGROUND_VERT) + option.orientation = Qt::Vertical; + else + 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; + + //setup the active control...always the slider + if (sbVal->mnThumbState & CTRL_STATE_ROLLOVER) + option.activeSubControls = QStyle::SC_ScrollBarSlider; + + draw( QStyle::CC_ScrollBar, &option, m_image, + vclStateValue2StateFlag(nControlState, value) ); + } + else + { + returnVal = false; + } + } + else if (type == CTRL_SPINBOX) + { + QStyleOptionSpinBox option; + + // determine active control + if( value.getType() == CTRL_SPINBUTTONS ) + { + const SpinbuttonValue* pSpinVal = static_cast<const SpinbuttonValue *>(&value); + if( (pSpinVal->mnUpperState & CTRL_STATE_PRESSED) ) + option.activeSubControls |= QStyle::SC_SpinBoxUp; + if( (pSpinVal->mnLowerState & CTRL_STATE_PRESSED) ) + option.activeSubControls |= QStyle::SC_SpinBoxDown; + } + + draw( QStyle::CC_SpinBox, &option, m_image, + vclStateValue2StateFlag(nControlState, value) ); + } + else if (type == CTRL_GROUPBOX) + { + QStyleOptionGroupBox option; + draw( QStyle::CC_GroupBox, &option, m_image, + vclStateValue2StateFlag(nControlState, value) ); + } + else if (type == CTRL_RADIOBUTTON) + { + QStyleOptionButton option; + draw( QStyle::CE_RadioButton, &option, m_image, + vclStateValue2StateFlag(nControlState, value) ); + } + else if (type == CTRL_TOOLTIP) + { + QStyleOption option; + draw( QStyle::PE_PanelTipLabel, &option, m_image, + vclStateValue2StateFlag(nControlState, value) ); + } + else if (type == CTRL_FRAME) + { + lcl_drawFrame( QStyle::PE_Frame, m_image, + vclStateValue2StateFlag(nControlState, value) ); + + // draw just the border, see http://qa.openoffice.org/issues/show_bug.cgi?id=107945 + int fw = getFrameWidth(); + clipRegion = new QRegion( QRegion( widgetRect ).subtracted( widgetRect.adjusted( fw, fw, -fw, -fw ))); + } + else if (type == CTRL_FIXEDBORDER) + { + lcl_drawFrame( QStyle::PE_FrameWindow, m_image, + vclStateValue2StateFlag(nControlState, value) ); + } + else if (type == CTRL_WINDOW_BACKGROUND) + { + m_image->fill(KApplication::palette().color(QPalette::Window).rgb()); + } + else if (type == CTRL_FIXEDLINE) + { + QStyleOptionMenuItem option; + option.menuItemType = QStyleOptionMenuItem::Separator; + option.state |= QStyle::State_Item; + + draw( QStyle::CE_MenuItem, &option, m_image, + vclStateValue2StateFlag(nControlState, value) ); + } + else if (type == CTRL_SLIDER && (part == PART_TRACK_HORZ_AREA || part == PART_TRACK_VERT_AREA)) + { + OSL_ASSERT( value.getType() == CTRL_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; + option.orientation = (part == PART_TRACK_HORZ_AREA) ? Qt::Horizontal : Qt::Vertical; + + draw( QStyle::CC_Slider, &option, m_image, vclStateValue2StateFlag(nControlState, value) ); + } + else if( type == CTRL_PROGRESS && part == PART_ENTIRE_CONTROL ) + { + 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, + vclStateValue2StateFlag(nControlState, value) ); + } + else + { + returnVal = false; + } + + if (returnVal) + { +#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( clipRegion && mpClipRegion ) + paint.setClipRegion( clipRegion->intersected( XRegionToQRegion( mpClipRegion ))); + else if( clipRegion ) + paint.setClipRegion( *clipRegion ); + 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 = SelectFont(); + if( gc ) + { + XLIB_Region pTempClipRegion = NULL; + if( clipRegion ) + { + pTempClipRegion = XCreateRegion(); + foreach( const QRect& r, clipRegion->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 + } + delete clipRegion; + return returnVal; +} + +sal_Bool KDESalGraphics::getNativeControlRegion( ControlType type, ControlPart part, + const Rectangle& controlRegion, ControlState controlState, + const ImplControlValue& val, + const OUString&, + Rectangle &nativeBoundingRegion, Rectangle &nativeContentRegion ) +{ + sal_Bool retVal = false; + + QRect boundingRect = region2QRect( controlRegion ); + QRect contentRect = boundingRect; + QStyleOptionComplex styleOption; + + switch ( type ) + { + // Metrics of the push button + case CTRL_PUSHBUTTON: + if (part == PART_ENTIRE_CONTROL) + { + styleOption.state = vclStateValue2StateFlag(controlState, val); + + if ( controlState & CTRL_STATE_DEFAULT ) + { + int size = kapp->style()->pixelMetric( + QStyle::PM_ButtonDefaultIndicator, &styleOption ); + + boundingRect.adjust( -size, -size, size, size ); + + retVal = true; + } + } + break; + case CTRL_EDITBOX: + { + int nFontHeight = kapp->fontMetrics().height(); + //int nFrameSize = kapp->style()->pixelMetric(QStyle::PM_DefaultFrameWidth); + int nLayoutTop = kapp->style()->pixelMetric(QStyle::PM_LayoutTopMargin); + int nLayoutBottom = kapp->style()->pixelMetric(QStyle::PM_LayoutBottomMargin); + int nLayoutLeft = kapp->style()->pixelMetric(QStyle::PM_LayoutLeftMargin); + int nLayoutRight = kapp->style()->pixelMetric(QStyle::PM_LayoutRightMargin); + + int nMinHeight = (nFontHeight + nLayoutTop + nLayoutBottom); + if( boundingRect.height() < nMinHeight ) + { + int delta = nMinHeight - boundingRect.height(); + boundingRect.adjust( 0, 0, 0, delta ); + } + contentRect = boundingRect; + contentRect.adjust( -nLayoutLeft+1, -nLayoutTop+1, nLayoutRight-1, nLayoutBottom-1 ); + retVal = true; + + break; + } + case CTRL_CHECKBOX: + if (part == PART_ENTIRE_CONTROL) + { + styleOption.state = vclStateValue2StateFlag(controlState, val); + + contentRect.setWidth(kapp->style()->pixelMetric( + QStyle::PM_IndicatorWidth, &styleOption)); + contentRect.setHeight(kapp->style()->pixelMetric( + QStyle::PM_IndicatorHeight, &styleOption)); + + contentRect.adjust(0, 0, + 2 * kapp->style()->pixelMetric( + QStyle::PM_FocusFrameHMargin, &styleOption), + 2 * kapp->style()->pixelMetric( + QStyle::PM_FocusFrameVMargin, &styleOption) + ); + + boundingRect = contentRect; + + retVal = true; + + break; + } + case CTRL_COMBOBOX: + case CTRL_LISTBOX: + { + QStyleOptionComboBox cbo; + + cbo.rect = QRect(0, 0, contentRect.width(), contentRect.height()); + cbo.state = vclStateValue2StateFlag(controlState, val); + + switch ( part ) + { + case PART_ENTIRE_CONTROL: + { + int size = kapp->style()->pixelMetric(QStyle::PM_ComboBoxFrameWidth) - 2; + + // find out the minimum size that should be used + // assume contents is a text ling + int nHeight = kapp->fontMetrics().height(); + QSize aContentSize( contentRect.width(), nHeight ); + QSize aMinSize = kapp->style()-> + sizeFromContents( QStyle::CT_ComboBox, &cbo, aContentSize ); + if( aMinSize.height() > contentRect.height() ) + contentRect.adjust( 0, 0, 0, aMinSize.height() - contentRect.height() ); + boundingRect = contentRect; + // FIXME: why this difference between comboboxes and listboxes ? + // because a combobox has a sub edit and that is positioned + // inside the outer bordered control ? + if( type == CTRL_COMBOBOX ) + contentRect.adjust(-size,-size,size,size); + retVal = true; + break; + } + case PART_BUTTON_DOWN: + //the entire control can be used as the "down" button + retVal = true; + break; + case PART_SUB_EDIT: + contentRect = kapp->style()->subControlRect( + QStyle::CC_ComboBox, &cbo, QStyle::SC_ComboBoxEditField ); + + contentRect.translate( boundingRect.left(), boundingRect.top() ); + + retVal = true; + break; + case PART_WINDOW: + retVal = true; + break; + } + break; + } + case CTRL_SPINBOX: + { + QStyleOptionSpinBox sbo; + + sbo.rect = QRect(0, 0, contentRect.width(), contentRect.height()); + sbo.state = vclStateValue2StateFlag(controlState, val); + + switch ( part ) + { + case PART_BUTTON_UP: + contentRect = kapp->style()->subControlRect( + QStyle::CC_SpinBox, &sbo, QStyle::SC_SpinBoxUp ); + contentRect.translate( boundingRect.left(), boundingRect.top() ); + retVal = true; + boundingRect = QRect(); + break; + + case PART_BUTTON_DOWN: + contentRect = kapp->style()->subControlRect( + QStyle::CC_SpinBox, &sbo, QStyle::SC_SpinBoxDown ); + retVal = true; + contentRect.translate( boundingRect.left(), boundingRect.top() ); + boundingRect = QRect(); + break; + + case PART_SUB_EDIT: + contentRect = kapp->style()->subControlRect( + QStyle::CC_SpinBox, &sbo, QStyle::SC_SpinBoxEditField ); + retVal = true; + contentRect.translate( boundingRect.left(), boundingRect.top() ); + break; + default: + retVal = true; + } + break; + } + case CTRL_MENU_POPUP: + if (part == PART_MENU_ITEM_CHECK_MARK || part == PART_MENU_ITEM_RADIO_MARK) + { // core uses this to detect radio/checkbox sizes, so just set a square + contentRect.setWidth(contentRect.height()); + retVal = true; + } + break; + case CTRL_FRAME: + { + if( part == PART_BORDER ) + { + int nFrameWidth = getFrameWidth(); + sal_uInt16 nStyle = val.getNumericVal(); + if( nStyle & FRAME_DRAW_NODRAW ) + { + // in this case the question is: how thick would a frame be + // see brdwin.cxx, decoview.cxx + // most probably the behavior in decoview.cxx is wrong. + contentRect.adjust(nFrameWidth, nFrameWidth, -nFrameWidth, -nFrameWidth); + } + retVal = true; + } + break; + } + case CTRL_RADIOBUTTON: + { + const int h = kapp->style()->pixelMetric(QStyle::PM_ExclusiveIndicatorHeight); + const int w = kapp->style()->pixelMetric(QStyle::PM_ExclusiveIndicatorWidth); + + contentRect = QRect(boundingRect.left(), boundingRect.top(), w, h); + contentRect.adjust(0, 0, + 2 * kapp->style()->pixelMetric( + QStyle::PM_FocusFrameHMargin, &styleOption), + 2 * kapp->style()->pixelMetric( + QStyle::PM_FocusFrameVMargin, &styleOption) + ); + boundingRect = contentRect; + + retVal = true; + break; + } + case CTRL_SLIDER: + { + const int w = kapp->style()->pixelMetric(QStyle::PM_SliderLength); + if( part == PART_THUMB_HORZ ) + { + contentRect = QRect(boundingRect.left(), boundingRect.top(), w, boundingRect.height()); + boundingRect = contentRect; + retVal = true; + } + else if( part == PART_THUMB_VERT ) + { + contentRect = QRect(boundingRect.left(), boundingRect.top(), boundingRect.width(), w); + boundingRect = contentRect; + retVal = true; + } + break; + } + case CTRL_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 == PART_TRACK_VERT_AREA || part == PART_TRACK_HORZ_AREA ) + { + QStyleOptionSlider option; + OSL_ASSERT( val.getType() == CTRL_SCROLLBAR ); + const ScrollbarValue* sbVal = static_cast<const ScrollbarValue *>(&val); + option.orientation = ( part == PART_TRACK_HORZ_AREA ) ? Qt::Horizontal : Qt::Vertical; + option.minimum = sbVal->mnMin; + option.maximum = sbVal->mnMax; + option.sliderValue = sbVal->mnCur; + option.sliderPosition = sbVal->mnCur; + option.pageStep = sbVal->mnVisibleSize; + // 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 = kapp->style()->subControlRect( QStyle::CC_ScrollBar, &option, + QStyle::SC_ScrollBarGroove ); + rect.translate( contentRect.topLeft()); // reverse the workaround above + contentRect = boundingRect = rect; + retVal = true; + } + } + default: + break; + } + if (retVal) + { + // Bounding region + Point aBPoint( boundingRect.x(), boundingRect.y() ); + Size aBSize( boundingRect.width(), boundingRect.height() ); + nativeBoundingRegion = Rectangle( aBPoint, aBSize ); + + // Region of the content + Point aPoint( contentRect.x(), contentRect.y() ); + Size aSize( contentRect.width(), contentRect.height() ); + nativeContentRegion = 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. +*/ +sal_Bool KDESalGraphics::hitTestNativeControl( ControlType nType, ControlPart nPart, + const Rectangle& rControlRegion, const Point& rPos, + sal_Bool& rIsInside ) +{ + if ( nType == CTRL_SCROLLBAR ) + { + if( nPart != PART_BUTTON_UP && nPart != PART_BUTTON_DOWN + && nPart != PART_BUTTON_LEFT && nPart != PART_BUTTON_RIGHT ) + { // 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 == PART_BUTTON_LEFT || nPart == PART_BUTTON_RIGHT ); + 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; + 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 = kapp->style()->hitTestComplexControl( QStyle::CC_ScrollBar, &options, pos ); + if( nPart == PART_BUTTON_UP || nPart == PART_BUTTON_LEFT ) + rIsInside = ( control == QStyle::SC_ScrollBarSubLine ); + else // DOWN, RIGHT + rIsInside = ( control == QStyle::SC_ScrollBarAddLine ); + return TRUE; + } + return FALSE; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/unx/kde4/KDESalGraphics.hxx b/vcl/unx/kde4/KDESalGraphics.hxx new file mode 100644 index 000000000000..5d1f3541a9b5 --- /dev/null +++ b/vcl/unx/kde4/KDESalGraphics.hxx @@ -0,0 +1,117 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#pragma once + +#include <rtl/string.hxx> +#include <saldisp.hxx> +#include <salgdi.h> + +#define Region QtXRegion +#include <QImage> +#undef Region + +/** handles graphics drawings requests and performs the needed drawing operations */ +class KDESalGraphics : public X11SalGraphics +{ + QImage* m_image; + QRect lastPopupRect; + + public: + KDESalGraphics(); + virtual ~KDESalGraphics(); + + /** + What widgets can be drawn the native way. + @param type Type of the widget. + @param part Specification of the widget's part if it consists of more than one. + @return true if the platform supports native drawing of the widget type defined by part. + */ + virtual sal_Bool IsNativeControlSupported( ControlType type, ControlPart part ); + + /** 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 + type/part combination. + */ + virtual sal_Bool hitTestNativeControl( ControlType type, ControlPart part, + const Rectangle& rControlRegion, const Point& aPos, + sal_Bool& rIsInside ); + /** Draw the requested control described by part/nControlState. + + @param rControlRegion + The bounding Rectangle of the complete control in VCL frame coordinates. + + @param aValue + An optional value (tristate/numerical/string). + + @param aCaption + A caption or title string (like button text etc.) + */ + virtual sal_Bool drawNativeControl( ControlType type, ControlPart part, + const Rectangle& rControlRegion, ControlState nControlState, + const ImplControlValue& aValue, + const rtl::OUString& aCaption ); + + /** Draw text on the widget. + OPTIONAL. Draws the requested text for the control described by part/nControlState. + Used if text is not drawn by DrawNativeControl(). + + @param rControlRegion The bounding region of the complete control in VCL frame coordinates. + @param aValue An optional value (tristate/numerical/string) + @param aCaption A caption or title string (like button text etc.) + */ + virtual sal_Bool drawNativeControlText( ControlType, ControlPart, + const Rectangle&, ControlState, + const ImplControlValue&, + const rtl::OUString& ) { return false; } + /** Check if the bounding regions match. + + If the return value is TRUE, rNativeBoundingRegion + contains the true bounding region covered by the control + including any adornment, while rNativeContentRegion contains the area + within the control that can be safely drawn into without drawing over + the borders of the control. + + @param rControlRegion + The bounding region of the control in VCL frame coordinates. + + @param aValue + An optional value (tristate/numerical/string) + + @param aCaption + A caption or title string (like button text etc.) + */ + virtual sal_Bool getNativeControlRegion( ControlType type, ControlPart part, + const Rectangle& rControlRegion, ControlState nControlState, + const ImplControlValue& aValue, + const rtl::OUString& aCaption, + Rectangle &rNativeBoundingRegion, Rectangle &rNativeContentRegion ); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/unx/kde4/KDESalInstance.cxx b/vcl/unx/kde4/KDESalInstance.cxx new file mode 100644 index 000000000000..c63d328e29c3 --- /dev/null +++ b/vcl/unx/kde4/KDESalInstance.cxx @@ -0,0 +1,38 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "KDESalInstance.hxx" + +#include "KDESalFrame.hxx" + +SalFrame* KDESalInstance::CreateFrame( SalFrame *pParent, sal_uLong nState ) +{ + return new KDESalFrame( pParent, nState ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/unx/kde4/KDESalInstance.hxx b/vcl/unx/kde4/KDESalInstance.hxx new file mode 100644 index 000000000000..9f35557061bb --- /dev/null +++ b/vcl/unx/kde4/KDESalInstance.hxx @@ -0,0 +1,44 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#pragma once + +#include <salinst.h> + +class SalYieldMutex; +class SalFrame; + +class KDESalInstance : public X11SalInstance +{ + public: + KDESalInstance( SalYieldMutex* pMutex ) : X11SalInstance( pMutex ) {} + virtual ~KDESalInstance() {} + virtual SalFrame* CreateFrame( SalFrame* pParent, sal_uLong nStyle ); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/unx/kde4/KDEXLib.cxx b/vcl/unx/kde4/KDEXLib.cxx new file mode 100644 index 000000000000..ce4ea14dadb5 --- /dev/null +++ b/vcl/unx/kde4/KDEXLib.cxx @@ -0,0 +1,422 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "VCLKDEApplication.hxx" + +#define Region QtXRegion + +#include <kapplication.h> +#include <klocale.h> +#include <kaboutdata.h> +#include <kcmdlineargs.h> +#include <kstartupinfo.h> +#include <qabstracteventdispatcher.h> +#include <qclipboard.h> +#include <qthread.h> + +#undef Region + +#include "KDEXLib.hxx" + +#include <i18n_im.hxx> +#include <i18n_xkb.hxx> + +#include <saldata.hxx> +#include <osl/process.h> + +#include "KDESalDisplay.hxx" + +#if OSL_DEBUG_LEVEL > 1 +#include <stdio.h> +#endif + +#include <stdio.h> + +#if QT_VERSION >= QT_VERSION_CHECK( 4, 8, 0 ) +#define QT_UNIX_EVENT_LOOP_SUPPORT +#ifdef KDE_HAVE_GLIB +#define GLIB_EVENT_LOOP_SUPPORT +#endif +#endif + +#ifdef GLIB_EVENT_LOOP_SUPPORT +#include <glib-2.0/glib.h> +#endif + +KDEXLib::KDEXLib() : + SalXLib(), m_bStartupDone(false), m_pApplication(0), + m_pFreeCmdLineArgs(0), m_pAppCmdLineArgs(0), m_nFakeCmdLineArgs( 0 ), + eventLoopType( LibreOfficeEventLoop ) +{ + // the timers created here means they belong to the main thread + connect( &timeoutTimer, SIGNAL( timeout()), this, SLOT( timeoutActivated())); + connect( &userEventTimer, SIGNAL( timeout()), this, SLOT( userEventActivated())); + // 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 ); + connect( this, SIGNAL( startUserEventTimerSignal()), this, SLOT( startUserEventTimer()), 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 ); +} + +KDEXLib::~KDEXLib() +{ + delete m_pApplication; + + // free the faked cmdline arguments no longer needed by KApplication + for( int i = 0; i < m_nFakeCmdLineArgs; i++ ) + { + free( m_pFreeCmdLineArgs[i] ); + } + + delete [] m_pFreeCmdLineArgs; + delete [] m_pAppCmdLineArgs; +} + +void KDEXLib::Init() +{ + SalI18N_InputMethod* pInputMethod = new SalI18N_InputMethod; + pInputMethod->SetLocale(); + XrmInitialize(); + + KAboutData *kAboutData = new KAboutData("LibreOffice", + "kdelibs4", + ki18n( "LibreOffice" ), + "3.3.0", + ki18n( "LibreOffice with KDE Native Widget Support." ), + KAboutData::License_LGPL, + ki18n( "Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Novell, Inc"), + ki18n( "LibreOffice is an office suite.\n" ), + "http://libreoffice.org", + "libreoffice@lists.freedesktop.org" ); + + kAboutData->addAuthor( ki18n( "Jan Holesovsky" ), + ki18n( "Original author and maintainer of the KDE NWF." ), + "kendy@artax.karlin.mff.cuni.cz", + "http://artax.karlin.mff.cuni.cz/~kendy" ); + kAboutData->addAuthor( ki18n("Roman Shtylman"), + ki18n( "Porting to KDE 4." ), + "shtylman@gmail.com", "http://shtylman.com" ); + kAboutData->addAuthor( ki18n("Eric Bischoff"), + ki18n( "Accessibility fixes, porting to KDE 4." ), + "bischoff@kde.org" ); + + //kAboutData->setProgramIconName("OpenOffice"); + + m_nFakeCmdLineArgs = 2; + sal_uInt16 nIdx; + + int nParams = osl_getCommandArgCount(); + rtl::OString aDisplay; + rtl::OUString aParam, aBin; + + for ( nIdx = 0; nIdx < nParams; ++nIdx ) + { + osl_getCommandArg( nIdx, &aParam.pData ); + if ( !m_pFreeCmdLineArgs && aParam.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "-display" ) ) && nIdx + 1 < nParams ) + { + osl_getCommandArg( nIdx + 1, &aParam.pData ); + aDisplay = rtl::OUStringToOString( aParam, osl_getThreadTextEncoding() ); + + m_pFreeCmdLineArgs = new 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 = new char*[ m_nFakeCmdLineArgs ]; + + osl_getExecutableFile( &aParam.pData ); + osl_getSystemPathFromFileURL( aParam.pData, &aBin.pData ); + rtl::OString aExec = rtl::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 = new char*[ m_nFakeCmdLineArgs ]; + for( int i = 0; i < m_nFakeCmdLineArgs; i++ ) + m_pAppCmdLineArgs[i] = m_pFreeCmdLineArgs[i]; + + KCmdLineArgs::init( m_nFakeCmdLineArgs, m_pAppCmdLineArgs, kAboutData ); + + m_pApplication = new VCLKDEApplication(); + kapp->disableSessionManagement(); + KApplication::setQuitOnLastWindowClosed(false); + setupEventLoop(); + + Display* pDisp = QX11Info::display(); + SalKDEDisplay *pSalDisplay = new SalKDEDisplay(pDisp); + + pInputMethod->CreateMethod( pDisp ); + pInputMethod->AddConnectionWatch( pDisp, (void*)this ); + pSalDisplay->SetInputMethod( pInputMethod ); + + PushXErrorLevel( true ); + SalI18N_KeyboardExtension *pKbdExtension = new SalI18N_KeyboardExtension( pDisp ); + XSync( pDisp, False ); + + pKbdExtension->UseExtension( ! HasXErrorOccurred() ); + PopXErrorLevel(); + + pSalDisplay->SetKbdExtension( pKbdExtension ); +} + +// 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 +// immediatelly after. So we need to know which event loop implementation is used and +// hook accordingly. +#ifdef GLIB_EVENT_LOOP_SUPPORT +static GPollFunc old_gpoll = NULL; +static gint gpoll_wrapper( GPollFD*, guint, gint ); +#endif +#ifdef QT_UNIX_EVENT_LOOP_SUPPORT +static int (*qt_select)(int nfds, fd_set *fdread, fd_set *fdwrite, fd_set *fdexcept, + const struct timeval *orig_timeout); +static int lo_select(int nfds, fd_set *fdread, fd_set *fdwrite, fd_set *fdexcept, + const struct timeval *orig_timeout); +#endif + +static bool ( *old_qt_event_filter )( void* ); +static bool qt_event_filter( void* m ) +{ + if( old_qt_event_filter != NULL && old_qt_event_filter( m )) + return true; + if( SalKDEDisplay::self() && SalKDEDisplay::self()->checkDirectInputEvent( static_cast< XEvent* >( m ))) + return true; + return false; +} + +void KDEXLib::setupEventLoop() +{ + old_qt_event_filter = QAbstractEventDispatcher::instance()->setEventFilter( qt_event_filter ); +#ifdef GLIB_EVENT_LOOP_SUPPORT +// Glib is simple, it has g_main_context_set_poll_func() for wrapping the sleep call. +// The catch is that Qt has a bug that allows triggering timers even when they should +// not be, leading to crashes caused by QClipboard re-entering the event loop. +// (http://bugreports.qt.nokia.com/browse/QTBUG-14461), so enable only with Qt>=4.8.0, +// where it is(?) fixed. + if( QAbstractEventDispatcher::instance()->inherits( "QEventDispatcherGlib" )) + { + eventLoopType = GlibEventLoop; + old_gpoll = g_main_context_get_poll_func( NULL ); + g_main_context_set_poll_func( NULL, gpoll_wrapper ); + // set QClipboard to use event loop, otherwise the main thread will hold + // SolarMutex locked, which will prevent the clipboard thread from answering + m_pApplication->clipboard()->setProperty( "useEventLoopWhenWaiting", true ); + return; + } +#endif +#ifdef QT_UNIX_EVENT_LOOP_SUPPORT +// When Qt does not use Glib support, it uses its own Unix event dispatcher. +// That one has aboutToBlock() and awake() signals, but they are broken (either +// functionality or semantics), as e.g. awake() is not emitted right after the dispatcher +// is woken up from sleep again, but only later (which is too late for re-acquiring SolarMutex). +// This should be fixed with Qt-4.8.0 (?) where support for adding custom select() function +// has been added too (http://bugreports.qt.nokia.com/browse/QTBUG-16934). + if( QAbstractEventDispatcher::instance()->inherits( "QEventDispatcherUNIX" )) + { + eventLoopType = QtUnixEventLoop; + QInternal::callFunction( QInternal::GetUnixSelectFunction, reinterpret_cast< void** >( &qt_select )); + QInternal::callFunction( QInternal::SetUnixSelectFunction, reinterpret_cast< void** >( lo_select )); + // set QClipboard to use event loop, otherwise the main thread will hold + // SolarMutex locked, which will prevent the clipboard thread from answering + m_pApplication->clipboard()->setProperty( "useEventLoopWhenWaiting", true ); + return; + } +#endif +} + +#ifdef GLIB_EVENT_LOOP_SUPPORT +gint gpoll_wrapper( GPollFD* ufds, guint nfds, gint timeout ) +{ + YieldMutexReleaser release; // release YieldMutex (and re-acquire at block end) + return old_gpoll( ufds, nfds, timeout ); +} +#endif + +#ifdef QT_UNIX_EVENT_LOOP_SUPPORT +int lo_select(int nfds, fd_set *fdread, fd_set *fdwrite, fd_set *fdexcept, + const struct timeval *orig_timeout) +{ + YieldMutexReleaser release; // release YieldMutex (and re-acquire at block end) + return qt_select( nfds, fdread, fdwrite, fdexcept, orig_timeout ); +} +#endif + +void KDEXLib::Insert( int fd, void* data, YieldFunc pending, YieldFunc queued, YieldFunc handle ) +{ + if( eventLoopType == LibreOfficeEventLoop ) + 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( eventLoopType == LibreOfficeEventLoop ) + 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 ); +} + +void KDEXLib::Yield( bool bWait, bool bHandleAllCurrentEvents ) +{ + if( eventLoopType == LibreOfficeEventLoop ) + { + 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 + processYield( false, bHandleAllCurrentEvents ); + } + return SalXLib::Yield( bWait, bHandleAllCurrentEvents ); + } + // if we are the main thread (which is where the event processing is done), + // good, just do it + if( qApp->thread() == QThread::currentThread()) + processYield( bWait, bHandleAllCurrentEvents ); + else + { // if this deadlocks, event processing needs to go into a separate thread + // or some other solution needs to be found + emit processYieldSignal( bWait, bHandleAllCurrentEvents ); + } +} + +bool KDEXLib::processYield( bool bWait, bool bHandleAllCurrentEvents ) +{ + QAbstractEventDispatcher* dispatcher = QAbstractEventDispatcher::instance( qApp->thread()); + bool wasEvent = false; + for( int cnt = bHandleAllCurrentEvents ? 100 : 1; + cnt > 0; + --cnt ) + { + if( !dispatcher->processEvents( QEventLoop::AllEvents )) + break; + wasEvent = true; + } + if( bWait && !wasEvent ) + wasEvent = dispatcher->processEvents( QEventLoop::WaitForMoreEvents ); + return wasEvent; +} + +void KDEXLib::StartTimer( sal_uLong nMS ) +{ + if( eventLoopType == LibreOfficeEventLoop ) + 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 + emit startTimeoutTimerSignal(); +} + +void KDEXLib::startTimeoutTimer() +{ + timeoutTimer.start(); +} + +void KDEXLib::StopTimer() +{ + if( eventLoopType == LibreOfficeEventLoop ) + return SalXLib::StopTimer(); + timeoutTimer.stop(); +} + +void KDEXLib::timeoutActivated() +{ + GetX11SalData()->Timeout(); + // QTimer is not single shot, so will be restarted immediatelly +} + +void KDEXLib::Wakeup() +{ + if( eventLoopType == LibreOfficeEventLoop ) + return SalXLib::Wakeup(); + QAbstractEventDispatcher::instance( qApp->thread())->wakeUp(); // main thread event loop +} + +void KDEXLib::PostUserEvent() +{ + if( eventLoopType == LibreOfficeEventLoop ) + return SalXLib::PostUserEvent(); + if( qApp->thread() == QThread::currentThread()) + startUserEventTimer(); + else + emit startUserEventTimerSignal(); +} + +void KDEXLib::startUserEventTimer() +{ + userEventTimer.start( 0 ); +} + +void KDEXLib::userEventActivated() +{ + SalKDEDisplay::self()->EventGuardAcquire(); + if( SalKDEDisplay::self()->userEventsCount() <= 1 ) + userEventTimer.stop(); + SalKDEDisplay::self()->EventGuardRelease(); + SalKDEDisplay::self()->DispatchInternalEvent(); + // QTimer is not single shot, so will be restarted immediatelly +} + +void KDEXLib::doStartup() +{ + if( ! m_bStartupDone ) + { + KStartupInfo::appStarted(); + m_bStartupDone = true; + #if OSL_DEBUG_LEVEL > 1 + fprintf( stderr, "called KStartupInfo::appStarted()\n" ); + #endif + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/unx/kde4/KDEXLib.hxx b/vcl/unx/kde4/KDEXLib.hxx new file mode 100644 index 000000000000..72848ed4084c --- /dev/null +++ b/vcl/unx/kde4/KDEXLib.hxx @@ -0,0 +1,94 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#pragma once + +#include <saldisp.hxx> + +#include <fixx11h.h> + +#include <qhash.h> +#include <qsocketnotifier.h> +#include <qtimer.h> + +class VCLKDEApplication; + +class KDEXLib : public QObject, public SalXLib +{ + Q_OBJECT + private: + bool m_bStartupDone; + VCLKDEApplication* m_pApplication; + char** m_pFreeCmdLineArgs; + 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; + QTimer userEventTimer; + enum { LibreOfficeEventLoop, GlibEventLoop, QtUnixEventLoop } eventLoopType; + + private: + void setupEventLoop(); + + private slots: + void socketNotifierActivated( int fd ); + void timeoutActivated(); + void userEventActivated(); + void startTimeoutTimer(); + void startUserEventTimer(); + bool processYield( bool bWait, bool bHandleAllCurrentEvents ); + signals: + void startTimeoutTimerSignal(); + void startUserEventTimerSignal(); + void processYieldSignal( bool bWait, bool bHandleAllCurrentEvents ); + + public: + KDEXLib(); + virtual ~KDEXLib(); + + virtual void Init(); + virtual void Yield( bool bWait, bool bHandleAllCurrentEvents ); + virtual void Insert( int fd, void* data, YieldFunc pending, YieldFunc queued, YieldFunc handle ); + virtual void Remove( int fd ); + virtual void StartTimer( sal_uLong nMS ); + virtual void StopTimer(); + virtual void Wakeup(); + virtual void PostUserEvent(); + + void doStartup(); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/unx/kde4/VCLKDEApplication.cxx b/vcl/unx/kde4/VCLKDEApplication.cxx new file mode 100644 index 000000000000..c923598736e8 --- /dev/null +++ b/vcl/unx/kde4/VCLKDEApplication.cxx @@ -0,0 +1,54 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "VCLKDEApplication.hxx" + +#define Region QtXRegion +#include <QEvent> +#undef Region + +#include "KDESalDisplay.hxx" + +VCLKDEApplication::VCLKDEApplication() : + KApplication() +{ +} + +bool VCLKDEApplication::x11EventFilter(XEvent* event) +{ + //if we have a display and the display consumes the event + //do not process the event in qt + if (SalKDEDisplay::self() && SalKDEDisplay::self()->Dispatch(event) > 0) + { + return true; + } + + return false; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/unx/kde4/VCLKDEApplication.hxx b/vcl/unx/kde4/VCLKDEApplication.hxx new file mode 100644 index 000000000000..17a9b6eb0917 --- /dev/null +++ b/vcl/unx/kde4/VCLKDEApplication.hxx @@ -0,0 +1,52 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#pragma once + +#define Region QtXRegion + +#include <QSessionManager> + +#include <kapplication.h> + +#undef Region + +/* #i59042# override KApplications method for session management + * since it will interfere badly with our own. + */ +class VCLKDEApplication : public KApplication +{ + public: + VCLKDEApplication(); + + virtual void commitData(QSessionManager&) {}; + + virtual bool x11EventFilter(XEvent* event); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/unx/kde4/main.cxx b/vcl/unx/kde4/main.cxx new file mode 100644 index 000000000000..d38c346c21b8 --- /dev/null +++ b/vcl/unx/kde4/main.cxx @@ -0,0 +1,96 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_vcl.hxx" + +#define Region QtXRegion +#include <QApplication> +#undef Region + +#include "KDEData.hxx" +#include "KDESalInstance.hxx" + +#if OSL_DEBUG_LEVEL > 1 +#include <stdio.h> +#endif + +#include <rtl/string.hxx> + +/// entry point for the KDE4 VCL plugin +extern "C" { + VCL_DLLPUBLIC SalInstance* create_SalInstance( oslModule ) + { + /* #i92121# workaround deadlocks in the X11 implementation + */ + static const char* pNoXInitThreads = getenv( "SAL_NO_XINITTHREADS" ); + /* #i90094# + from now on we know that an X connection will be + established, so protect X against itself + */ + if( ! ( pNoXInitThreads && *pNoXInitThreads ) ) + XInitThreads(); + +#if QT_VERSION < 0x050000 + // Qt 4.x support needs >= 4.1.0 + rtl::OString aVersion( qVersion() ); +#if OSL_DEBUG_LEVEL > 1 + fprintf( stderr, "qt version string is \"%s\"\n", aVersion.getStr() ); +#endif + sal_Int32 nIndex = 0, nMajor = 0, nMinor = 0, nMicro = 0; + nMajor = aVersion.getToken( 0, '.', nIndex ).toInt32(); + if( nIndex > 0 ) + nMinor = aVersion.getToken( 0, '.', nIndex ).toInt32(); + if( nIndex > 0 ) + nMicro = aVersion.getToken( 0, '.', nIndex ).toInt32(); + if( nMajor != 4 || nMinor < 1 ) + { +#if OSL_DEBUG_LEVEL > 1 + fprintf( stderr, "unsuitable qt version %d.%d.%d\n", nMajor, nMinor, nMicro ); +#endif + return NULL; + } +#endif + + KDESalInstance* pInstance = new KDESalInstance( new SalYieldMutex() ); +#if OSL_DEBUG_LEVEL > 1 + fprintf( stderr, "created KDESalInstance 0x%p\n", pInstance ); +#endif + + // initialize SalData + KDEData *salData = new KDEData(); + SetSalData(salData); + salData->m_pInstance = pInstance; + salData->Init(); + salData->initNWF(); + + return pInstance; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/unx/kde4/makefile.mk b/vcl/unx/kde4/makefile.mk new file mode 100644 index 000000000000..83ac1c0e6802 --- /dev/null +++ b/vcl/unx/kde4/makefile.mk @@ -0,0 +1,96 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=..$/.. + +PRJNAME=vcl +TARGET=kde4plug +.INCLUDE : $(PRJ)$/util$/makefile.pmk + +# workaround for makedepend hang +MKDEPENDSOLVER= + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/util$/makefile2.pmk + +# For some of the included external KDE headers, GCC complains about shadowed +# symbols in instantiated template code only at the end of a compilation unit, +# so the only solution is to disable that warning here: +.IF "$(COM)" == "GCC" +CFLAGSCXX+=-Wno-shadow +.ENDIF + +# --- Files -------------------------------------------------------- + +.IF "$(GUIBASE)"!="unx" + +dummy: + @echo "Nothing to build for GUIBASE $(GUIBASE)" + +.ELSE # "$(GUIBASE)"!="unx" + +.IF "$(ENABLE_KDE4)" != "" + +CFLAGS+=$(KDE4_CFLAGS) $(KDE_GLIB_CFLAGS) + +.IF "$(ENABLE_RANDR)" != "" +CDEFS+=-DUSE_RANDR +.ENDIF + +.IF "$(KDE_HAVE_GLIB)" != "" +CDEFS+=-DKDE_HAVE_GLIB +.ENDIF + +SLOFILES=\ + $(SLO)$/main.obj \ + $(SLO)$/VCLKDEApplication.obj \ + $(SLO)$/KDEXLib.obj \ + $(SLO)$/KDEXLib.moc.obj \ + $(SLO)$/KDESalDisplay.obj \ + $(SLO)$/KDESalFrame.obj \ + $(SLO)$/KDESalGraphics.obj \ + $(SLO)$/KDESalInstance.obj \ + $(SLO)$/KDEData.obj + + +.ELSE # "$(ENABLE_KDE4)" != "" + +dummy: + @echo KDE disabled - nothing to build +.ENDIF +.ENDIF # "$(GUIBASE)"!="unx" + +# --- Targets ------------------------------------------------------ + +.INCLUDE : target.mk + +.INCLUDE : $(PRJ)$/util$/target.pmk + +$(MISC)$/KDEXLib.moc.cxx : KDEXLib.hxx + $(MOC4) $< -o $@ |