bump product version to 5.0.4.1
[LibreOffice.git] / vcl / unx / gtk / gdi / salnativewidgets-gtk.cxx
blob122059656f890db5c45ac3bd67efb08ef3c501f0
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <config_version.h>
22 #include "vcl/svapp.hxx"
24 #include "unx/gtk/gtkframe.hxx"
25 #include "unx/gtk/gtkdata.hxx"
26 #include "unx/gtk/gtkinst.hxx"
27 #include "unx/gtk/gtkgdi.hxx"
29 #include "unx/pixmap.hxx"
30 #include "unx/saldata.hxx"
31 #include "unx/saldisp.hxx"
33 #include <cstdio>
34 #include <cmath>
35 #include <vector>
36 #include <algorithm>
37 #include <unordered_map>
39 #include "vcl/vclenum.hxx"
40 #include <vcl/settings.hxx>
41 #include "fontmanager.hxx"
42 #include <vcl/decoview.hxx>
44 #include <vcl/opengl/OpenGLHelper.hxx>
46 typedef struct _cairo_font_options cairo_font_options_t;
47 const char* const tabPrelitDataName="libreoffice-tab-is-prelit";
49 // initialize statics
50 bool GtkSalGraphics::bThemeChanged = true;
51 bool GtkSalGraphics::bNeedPixmapPaint = false;
52 bool GtkSalGraphics::bNeedTwoPasses = false;
54 enum
56 BG_NONE = 0,
57 BG_FILL,
58 BG_WHITE,
59 BG_BLACK
62 GtkSalGraphics::GtkSalGraphics( GtkSalFrame *pFrame, GtkWidget *pWindow )
63 : X11SalGraphics(),
64 m_pWindow( pWindow ),
65 m_aClipRegion(true)
67 Init( pFrame, GDK_WINDOW_XID( widget_get_window( pWindow ) ),
68 SalX11Screen( gdk_x11_screen_get_screen_number(
69 gtk_widget_get_screen( pWindow ) ) ) );
72 GtkSalGraphics::GtkSalGraphics( GtkSalFrame *pFrame, GtkWidget *pWindow,
73 SalX11Screen nXScreen )
74 : X11SalGraphics(),
75 m_pWindow( pWindow ),
76 m_aClipRegion(true)
78 Init( pFrame, GDK_WINDOW_XID( widget_get_window( pWindow ) ), nXScreen );
81 GtkSalGraphics::~GtkSalGraphics()
85 /*************************************
86 * Cached native widget objects
87 *************************************/
88 class NWPixmapCacheList;
89 class NWPixmapCache;
90 struct NWFWidgetData
92 GtkWidget * gCacheWindow;
93 GtkWidget * gDumbContainer;
95 GtkWidget * gBtnWidget;
96 GtkWidget * gRadioWidget;
97 GtkWidget * gRadioWidgetSibling;
98 GtkWidget * gCheckWidget;
99 GtkWidget * gScrollHorizWidget;
100 GtkWidget * gScrollVertWidget;
101 GtkWidget * gArrowWidget;
102 GtkWidget * gDropdownWidget;
103 GtkWidget * gEditBoxWidget;
104 GtkWidget * gSpinButtonWidget;
105 GtkWidget * gNotebookWidget;
106 GtkWidget * gOptionMenuWidget;
107 GtkWidget * gComboWidget;
108 GtkWidget * gScrolledWindowWidget;
109 GtkWidget * gToolbarWidget;
110 GtkWidget * gToolbarButtonWidget;
111 GtkWidget * gHandleBoxWidget;
112 GtkWidget * gMenubarWidget;
113 GtkWidget * gMenuItemMenubarWidget;
114 GtkWidget * gMenuWidget;
115 GtkWidget * gMenuItemMenuWidget;
116 GtkWidget * gMenuItemCheckMenuWidget;
117 GtkWidget * gMenuItemRadioMenuWidget;
118 GtkWidget * gMenuItemSeparatorMenuWidget;
119 GtkWidget * gImageMenuItem;
120 GtkWidget * gTooltipPopup;
121 GtkWidget * gProgressBar;
122 GtkWidget * gTreeView;
123 GtkWidget * gHScale;
124 GtkWidget * gVScale;
125 GtkWidget * gSeparator;
126 GtkWidget * gDialog;
127 GtkWidget * gFrame;
129 NWPixmapCacheList* gNWPixmapCacheList;
130 NWPixmapCache* gCacheTabItems;
131 NWPixmapCache* gCacheTabPages;
133 NWFWidgetData() :
134 gCacheWindow( NULL ),
135 gDumbContainer( NULL ),
136 gBtnWidget( NULL ),
137 gRadioWidget( NULL ),
138 gRadioWidgetSibling( NULL ),
139 gCheckWidget( NULL ),
140 gScrollHorizWidget( NULL ),
141 gScrollVertWidget( NULL ),
142 gArrowWidget( NULL ),
143 gDropdownWidget( NULL ),
144 gEditBoxWidget( NULL ),
145 gSpinButtonWidget( NULL ),
146 gNotebookWidget( NULL ),
147 gOptionMenuWidget( NULL ),
148 gComboWidget( NULL ),
149 gScrolledWindowWidget( NULL ),
150 gToolbarWidget( NULL ),
151 gToolbarButtonWidget( NULL ),
152 gHandleBoxWidget( NULL ),
153 gMenubarWidget( NULL ),
154 gMenuItemMenubarWidget( NULL ),
155 gMenuWidget( NULL ),
156 gMenuItemMenuWidget( NULL ),
157 gMenuItemCheckMenuWidget( NULL ),
158 gMenuItemRadioMenuWidget( NULL ),
159 gMenuItemSeparatorMenuWidget( NULL ),
160 gImageMenuItem( NULL ),
161 gTooltipPopup( NULL ),
162 gProgressBar( NULL ),
163 gTreeView( NULL ),
164 gHScale( NULL ),
165 gVScale( NULL ),
166 gSeparator( NULL ),
167 gDialog( NULL ),
168 gFrame( NULL ),
169 gNWPixmapCacheList( NULL ),
170 gCacheTabItems( NULL ),
171 gCacheTabPages( NULL )
175 // Keep a hash table of Widgets->default flags so that we can
176 // easily and quickly reset each to a default state before using
177 // them
178 static std::unordered_map<long, guint> gWidgetDefaultFlags;
179 class WidgetDataVector
181 private:
182 std::vector<NWFWidgetData> mData;
184 public:
185 WidgetDataVector(size_t nElems = 0) : mData( nElems ) {}
186 size_t size() const { return mData.size(); }
187 NWFWidgetData &operator [](size_t i) { return mData.at(i); }
188 NWFWidgetData &operator [](const SalX11Screen &s) { return mData.at(s.getXScreen()); }
190 static WidgetDataVector gWidgetData;
192 static const GtkBorder aDefDefBorder = { 1, 1, 1, 1 };
194 // Some GTK defaults
195 #define MIN_ARROW_SIZE 11
196 #define BTN_CHILD_SPACING 1
197 #define MIN_SPIN_ARROW_WIDTH 6
199 static void NWEnsureGTKRadio ( SalX11Screen nScreen );
200 static void NWEnsureGTKButton ( SalX11Screen nScreen );
201 static void NWEnsureGTKCheck ( SalX11Screen nScreen );
202 static void NWEnsureGTKScrollbars ( SalX11Screen nScreen );
203 static void NWEnsureGTKArrow ( SalX11Screen nScreen );
204 static void NWEnsureGTKEditBox ( SalX11Screen nScreen );
205 static void NWEnsureGTKSpinButton ( SalX11Screen nScreen );
206 static void NWEnsureGTKNotebook ( SalX11Screen nScreen );
207 static void NWEnsureGTKOptionMenu ( SalX11Screen nScreen );
208 static void NWEnsureGTKCombo ( SalX11Screen nScreen );
209 static void NWEnsureGTKScrolledWindow ( SalX11Screen nScreen );
210 static void NWEnsureGTKToolbar ( SalX11Screen nScreen );
211 static void NWEnsureGTKMenubar ( SalX11Screen nScreen );
212 static void NWEnsureGTKMenu ( SalX11Screen nScreen );
213 static void NWEnsureGTKTooltip ( SalX11Screen nScreen );
214 static void NWEnsureGTKDialog ( SalX11Screen nScreen );
215 static void NWEnsureGTKFrame ( SalX11Screen nScreen );
216 static void NWEnsureGTKProgressBar ( SalX11Screen nScreen );
217 static void NWEnsureGTKTreeView ( SalX11Screen nScreen );
218 static void NWEnsureGTKSlider ( SalX11Screen nScreen );
220 static void NWConvertVCLStateToGTKState( ControlState nVCLState, GtkStateType* nGTKState, GtkShadowType* nGTKShadow );
221 static void NWAddWidgetToCacheWindow( GtkWidget* widget, SalX11Screen nScreen );
222 static void NWSetWidgetState( GtkWidget* widget, ControlState nState, GtkStateType nGtkState );
224 static void NWCalcArrowRect( const Rectangle& rButton, Rectangle& rArrow );
227 * Individual helper functions
231 static Rectangle NWGetButtonArea( SalX11Screen nScreen, ControlType nType, ControlPart nPart, Rectangle aAreaRect, ControlState nState,
232 const ImplControlValue& aValue, const OUString& rCaption );
234 static Rectangle NWGetTabItemRect( SalX11Screen nScreen, Rectangle aAreaRect );
236 static Rectangle NWGetEditBoxPixmapRect( SalX11Screen nScreen, ControlType nType, ControlPart nPart, Rectangle aAreaRect, ControlState nState,
237 const ImplControlValue& aValue, const OUString& rCaption );
239 static void NWPaintOneEditBox( SalX11Screen nScreen, GdkDrawable * gdkDrawable, GdkRectangle *gdkRect,
240 ControlType nType, ControlPart nPart, Rectangle aEditBoxRect,
241 ControlState nState, const ImplControlValue& aValue,
242 const OUString& rCaption );
244 static Rectangle NWGetSpinButtonRect( SalX11Screen nScreen, ControlType nType, ControlPart nPart, Rectangle aAreaRect, ControlState nState,
245 const ImplControlValue& aValue, const OUString& rCaption );
247 static void NWPaintOneSpinButton( SalX11Screen nScreen, GdkPixmap * pixmap, ControlType nType, ControlPart nPart, Rectangle aAreaRect,
248 ControlState nState, const ImplControlValue& aValue,
249 const OUString& rCaption );
251 static Rectangle NWGetComboBoxButtonRect( SalX11Screen nScreen, ControlType nType, ControlPart nPart, Rectangle aAreaRect, ControlState nState,
252 const ImplControlValue& aValue, const OUString& rCaption );
254 static Rectangle NWGetListBoxButtonRect( SalX11Screen nScreen, ControlType nType, ControlPart nPart, Rectangle aAreaRect, ControlState nState,
255 const ImplControlValue& aValue, const OUString& rCaption );
257 static Rectangle NWGetListBoxIndicatorRect( SalX11Screen nScreen, ControlType nType, ControlPart nPart, Rectangle aAreaRect, ControlState nState,
258 const ImplControlValue& aValue, const OUString& rCaption );
260 static Rectangle NWGetToolbarRect( SalX11Screen nScreen,
261 ControlType nType,
262 ControlPart nPart,
263 Rectangle aAreaRect,
264 ControlState nState,
265 const ImplControlValue& aValue,
266 const OUString& rCaption );
268 static int getFrameWidth(GtkWidget* widget);
270 static Rectangle NWGetScrollButtonRect( SalX11Screen nScreen, ControlPart nPart, Rectangle aAreaRect );
273 /************************************************************************
274 * GDK implementation of X11Pixmap
275 ************************************************************************/
277 class GdkX11Pixmap : public X11Pixmap
279 public:
280 GdkX11Pixmap( int nWidth, int nHeight, int nDepth );
281 virtual ~GdkX11Pixmap();
283 virtual int GetDepth() const SAL_OVERRIDE;
284 virtual SalX11Screen GetScreen() const SAL_OVERRIDE;
285 virtual Pixmap GetPixmap() const SAL_OVERRIDE;
286 GdkPixmap* GetGdkPixmap() const;
287 GdkDrawable* GetGdkDrawable() const;
289 protected:
290 GdkPixmap* mpGdkPixmap;
291 int mnDepth;
294 GdkX11Pixmap::GdkX11Pixmap( int nWidth, int nHeight, int nDepth )
295 : X11Pixmap( nWidth, nHeight )
297 mpGdkPixmap = gdk_pixmap_new( NULL, nWidth, nHeight, nDepth );
298 mnDepth = gdk_drawable_get_depth( GDK_DRAWABLE( mpGdkPixmap ) );
300 GdkScreen *pScreen = gdk_drawable_get_screen( GDK_DRAWABLE( mpGdkPixmap ) );
301 gdk_drawable_set_colormap( GDK_DRAWABLE( mpGdkPixmap ), gdk_screen_get_default_colormap( pScreen ) );
304 GdkX11Pixmap::~GdkX11Pixmap()
306 g_object_unref( mpGdkPixmap );
309 int GdkX11Pixmap::GetDepth() const
311 return mnDepth;
314 SalX11Screen GdkX11Pixmap::GetScreen() const
316 return SalX11Screen( gdk_screen_get_number( gdk_drawable_get_screen( GDK_DRAWABLE(mpGdkPixmap) ) ) );
319 Pixmap GdkX11Pixmap::GetPixmap() const
321 return GDK_PIXMAP_XID( mpGdkPixmap );
324 GdkPixmap* GdkX11Pixmap::GetGdkPixmap() const
326 return mpGdkPixmap;
329 GdkDrawable* GdkX11Pixmap::GetGdkDrawable() const
331 return GDK_DRAWABLE( mpGdkPixmap );
335 /*********************************************************
336 * PixmapCache
337 *********************************************************/
339 // as some native widget drawing operations are pretty slow
340 // with certain themes (eg tabpages)
341 // this cache can be used to cache the corresponding pixmap
342 // see NWPaintGTKTabItem
344 class NWPixmapCacheData
346 public:
347 ControlType m_nType;
348 ControlState m_nState;
349 Rectangle m_pixmapRect;
350 GdkX11Pixmap* m_pixmap;
351 GdkX11Pixmap* m_mask;
353 NWPixmapCacheData() : m_nType(0), m_nState(ControlState::NONE), m_pixmap(0), m_mask(0) {}
354 ~NWPixmapCacheData()
355 { SetPixmap( NULL, NULL ); };
356 void SetPixmap( GdkX11Pixmap* pPixmap, GdkX11Pixmap* pMask );
359 class NWPixmapCache
361 int m_size;
362 int m_idx;
363 int m_screen;
364 NWPixmapCacheData* pData;
365 public:
366 NWPixmapCache( SalX11Screen nScreen );
367 ~NWPixmapCache();
369 void SetSize( int n)
370 { delete [] pData; m_idx = 0; m_size = n; pData = new NWPixmapCacheData[m_size]; }
371 int GetSize() const { return m_size; }
373 bool Find( ControlType aType, ControlState aState, const Rectangle& r_pixmapRect, GdkX11Pixmap** pPixmap, GdkX11Pixmap** pMask );
374 void Fill( ControlType aType, ControlState aState, const Rectangle& r_pixmapRect, GdkX11Pixmap* pPixmap, GdkX11Pixmap* pMask );
376 void ThemeChanged();
379 class NWPixmapCacheList
381 public:
382 ::std::vector< NWPixmapCache* > mCaches;
384 void AddCache( NWPixmapCache *pCache );
385 void RemoveCache( NWPixmapCache *pCache );
386 void ThemeChanged();
389 // --- implementation ---
391 void NWPixmapCacheData::SetPixmap( GdkX11Pixmap* pPixmap, GdkX11Pixmap* pMask )
393 if( m_pixmap )
394 delete m_pixmap;
395 if( m_mask )
396 delete m_mask;
398 m_pixmap = pPixmap;
399 m_mask = pMask;
402 NWPixmapCache::NWPixmapCache( SalX11Screen nScreen )
404 m_idx = 0;
405 m_size = 0;
406 m_screen = nScreen.getXScreen();
407 pData = NULL;
408 if( gWidgetData[m_screen].gNWPixmapCacheList )
409 gWidgetData[m_screen].gNWPixmapCacheList->AddCache(this);
411 NWPixmapCache::~NWPixmapCache()
413 if( gWidgetData[m_screen].gNWPixmapCacheList )
414 gWidgetData[m_screen].gNWPixmapCacheList->RemoveCache(this);
415 delete[] pData;
417 void NWPixmapCache::ThemeChanged()
419 // throw away cached pixmaps
420 int i;
421 for(i=0; i<m_size; i++)
422 pData[i].SetPixmap( NULL, NULL );
425 bool NWPixmapCache::Find( ControlType aType, ControlState aState, const Rectangle& r_pixmapRect, GdkX11Pixmap** pPixmap, GdkX11Pixmap** pMask )
427 aState &= ~ControlState::CACHING_ALLOWED; // mask clipping flag
428 int i;
429 for(i=0; i<m_size; i++)
431 if( pData[i].m_nType == aType &&
432 pData[i].m_nState == aState &&
433 pData[i].m_pixmapRect.GetWidth() == r_pixmapRect.GetWidth() &&
434 pData[i].m_pixmapRect.GetHeight() == r_pixmapRect.GetHeight() &&
435 pData[i].m_pixmap != NULL )
437 *pPixmap = pData[i].m_pixmap;
438 *pMask = pData[i].m_mask;
439 return true;
442 return false;
445 void NWPixmapCache::Fill( ControlType aType, ControlState aState, const Rectangle& r_pixmapRect, GdkX11Pixmap* pPixmap, GdkX11Pixmap* pMask )
447 if( !(aState & ControlState::CACHING_ALLOWED) )
448 return;
450 aState &= ~ControlState::CACHING_ALLOWED; // mask clipping flag
451 m_idx = (m_idx+1) % m_size; // just wrap
452 pData[m_idx].m_nType = aType;
453 pData[m_idx].m_nState = aState;
454 pData[m_idx].m_pixmapRect = r_pixmapRect;
455 pData[m_idx].SetPixmap( pPixmap, pMask );
458 void NWPixmapCacheList::AddCache( NWPixmapCache* pCache )
460 mCaches.push_back( pCache );
462 void NWPixmapCacheList::RemoveCache( NWPixmapCache* pCache )
464 ::std::vector< NWPixmapCache* >::iterator p;
465 p = ::std::find( mCaches.begin(), mCaches.end(), pCache );
466 if( p != mCaches.end() )
467 mCaches.erase( p );
469 void NWPixmapCacheList::ThemeChanged( )
471 ::std::vector< NWPixmapCache* >::iterator p = mCaches.begin();
472 while( p != mCaches.end() )
474 (*p)->ThemeChanged();
475 ++p;
479 /*********************************************************
480 * Make border manipulation easier
481 *********************************************************/
482 inline void NW_gtk_border_set_from_border( GtkBorder& aDst, const GtkBorder * pSrc )
484 aDst.left = pSrc->left;
485 aDst.top = pSrc->top;
486 aDst.right = pSrc->right;
487 aDst.bottom = pSrc->bottom;
490 /*********************************************************
491 * Initialize GTK and local stuff
492 *********************************************************/
493 void GtkData::initNWF()
495 ImplSVData* pSVData = ImplGetSVData();
497 // draw no border for popup menus (NWF draws its own)
498 pSVData->maNWFData.mbFlatMenu = true;
500 // draw separate buttons for toolbox dropdown items
501 pSVData->maNWFData.mbToolboxDropDownSeparate = true;
503 // draw toolbars in separate lines
504 pSVData->maNWFData.mbDockingAreaSeparateTB = true;
506 // open first menu on F10
507 pSVData->maNWFData.mbOpenMenuOnF10 = true;
509 // omit GetNativeControl while painting (see brdwin.cxx)
510 pSVData->maNWFData.mbCanDrawWidgetAnySize = true;
512 pSVData->maNWFData.mbDDListBoxNoTextArea = true;
514 // use offscreen rendering when using OpenGL backend
515 if( OpenGLHelper::isVCLOpenGLEnabled() )
517 GtkSalGraphics::bNeedPixmapPaint = true;
518 GtkSalGraphics::bNeedTwoPasses = true;
521 int nScreens = GetGtkSalData()->GetGtkDisplay()->GetXScreenCount();
522 gWidgetData = WidgetDataVector( nScreens );
523 for( int i = 0; i < nScreens; i++ )
524 gWidgetData[i].gNWPixmapCacheList = new NWPixmapCacheList;
526 // small extra border around menu items
527 NWEnsureGTKMenu( SalX11Screen( 0 ) );
528 gint horizontal_padding = 1;
529 gint vertical_padding = 1;
530 gint separator_padding = 1;
531 gtk_widget_style_get( gWidgetData[0].gMenuWidget,
532 "horizontal-padding", &horizontal_padding,
533 nullptr);
534 gtk_widget_style_get( gWidgetData[0].gMenuWidget,
535 "vertical-padding", &vertical_padding,
536 nullptr);
537 gtk_widget_style_get( gWidgetData[0].gMenuItemSeparatorMenuWidget,
538 "horizontal-padding", &separator_padding,
539 nullptr);
540 gint xthickness = gWidgetData[0].gMenuWidget->style->xthickness;
541 gint ythickness = gWidgetData[0].gMenuWidget->style->ythickness;
542 pSVData->maNWFData.mnMenuFormatBorderX = xthickness + horizontal_padding;
543 pSVData->maNWFData.mnMenuFormatBorderY = ythickness + vertical_padding;
544 pSVData->maNWFData.mnMenuSeparatorBorderX = separator_padding;
546 pSVData->maNWFData.mbCheckBoxNeedsErase = true;
548 if( SalGetDesktopEnvironment() == "KDE" )
550 // #i97196# ensure a widget exists and the style engine was loaded
551 NWEnsureGTKButton( SalX11Screen( 0 ) );
552 if( g_type_from_name( "QtEngineStyle" ) )
554 // KDE 3.3 invented a bug in the qt<->gtk theme engine
555 // that makes direct rendering impossible: they totally
556 // ignore the clip rectangle passed to the paint methods
557 GtkSalGraphics::bNeedPixmapPaint = true;
560 static const char* pEnv = getenv( "SAL_GTK_USE_PIXMAPPAINT" );
561 if( pEnv && *pEnv )
562 GtkSalGraphics::bNeedPixmapPaint = true;
564 #if OSL_DEBUG_LEVEL > 1
565 std::fprintf( stderr, "GtkPlugin: using %s NWF\n",
566 GtkSalGraphics::bNeedPixmapPaint ? "offscreen" : "direct" );
567 #endif
570 /*********************************************************
571 * Release GTK and local stuff
572 *********************************************************/
573 void GtkData::deInitNWF()
575 for( unsigned int i = 0; i < gWidgetData.size(); i++ )
577 // free up global widgets
578 // gtk_widget_destroy will in turn destroy the child hierarchy
579 // so only destroy disjunct hierarchies
580 if( gWidgetData[i].gCacheWindow )
581 gtk_widget_destroy( gWidgetData[i].gCacheWindow );
582 if( gWidgetData[i].gMenuWidget )
583 g_object_unref (gWidgetData[i].gMenuWidget);
584 if( gWidgetData[i].gTooltipPopup )
585 gtk_widget_destroy( gWidgetData[i].gTooltipPopup );
586 if( gWidgetData[i].gDialog )
587 gtk_widget_destroy( gWidgetData[i].gDialog );
588 delete gWidgetData[i].gCacheTabPages;
589 gWidgetData[i].gCacheTabPages = NULL;
590 delete gWidgetData[i].gCacheTabItems;
591 gWidgetData[i].gCacheTabItems = NULL;
592 delete gWidgetData[i].gNWPixmapCacheList;
593 gWidgetData[i].gNWPixmapCacheList = NULL;
597 /**********************************************************
598 * track clip region
599 **********************************************************/
600 void GtkSalGraphics::ResetClipRegion()
602 m_aClipRegion.SetNull();
603 X11SalGraphics::ResetClipRegion();
606 bool GtkSalGraphics::setClipRegion( const vcl::Region& i_rClip )
608 m_aClipRegion = i_rClip;
609 bool bRet = X11SalGraphics::setClipRegion( m_aClipRegion );
610 if( m_aClipRegion.IsEmpty() )
611 m_aClipRegion.SetNull();
612 return bRet;
615 void GtkSalGraphics::copyBits( const SalTwoRect& rPosAry,
616 SalGraphics* pSrcGraphics )
618 GtkSalFrame* pFrame = GetGtkFrame();
619 ::Window aWin = None;
620 if( pFrame && m_pWindow )
622 /* #i64117# some themes set the background pixmap VERY frequently */
623 GdkWindow* pWin = GTK_WIDGET(m_pWindow)->window;
624 if( pWin )
626 aWin = GDK_WINDOW_XWINDOW(pWin);
627 if( aWin != None )
628 XSetWindowBackgroundPixmap( GtkSalFrame::getDisplay()->GetDisplay(),
629 aWin,
630 None );
633 X11SalGraphics::copyBits( rPosAry, pSrcGraphics );
634 if( pFrame && pFrame->getBackgroundPixmap() != None )
635 XSetWindowBackgroundPixmap( GtkSalFrame::getDisplay()->GetDisplay(),
636 aWin,
637 pFrame->getBackgroundPixmap() );
641 * IsNativeControlSupported()
643 * Returns true if the platform supports native
644 * drawing of the control defined by nPart
646 bool GtkSalGraphics::IsNativeControlSupported( ControlType nType, ControlPart nPart )
648 switch(nType)
650 case CTRL_PUSHBUTTON:
651 case CTRL_RADIOBUTTON:
652 case CTRL_CHECKBOX:
653 case CTRL_TOOLTIP:
654 case CTRL_PROGRESS:
655 case CTRL_LISTNODE:
656 case CTRL_LISTNET:
657 if(nPart==PART_ENTIRE_CONTROL)
658 return true;
659 break;
661 case CTRL_SCROLLBAR:
662 if(nPart==PART_DRAW_BACKGROUND_HORZ || nPart==PART_DRAW_BACKGROUND_VERT ||
663 nPart==PART_ENTIRE_CONTROL || nPart==HAS_THREE_BUTTONS)
664 return true;
665 break;
667 case CTRL_EDITBOX:
668 case CTRL_MULTILINE_EDITBOX:
669 case CTRL_COMBOBOX:
670 if(nPart==PART_ENTIRE_CONTROL || nPart==HAS_BACKGROUND_TEXTURE)
671 return true;
672 break;
674 case CTRL_SPINBOX:
675 if(nPart==PART_ENTIRE_CONTROL || nPart==PART_ALL_BUTTONS || nPart==HAS_BACKGROUND_TEXTURE)
676 return true;
677 break;
679 case CTRL_SPINBUTTONS:
680 if(nPart==PART_ENTIRE_CONTROL || nPart==PART_ALL_BUTTONS)
681 return true;
682 break;
684 case CTRL_FRAME:
685 case CTRL_WINDOW_BACKGROUND:
686 return true;
688 case CTRL_TAB_ITEM:
689 case CTRL_TAB_PANE:
690 case CTRL_TAB_BODY:
691 if(nPart==PART_ENTIRE_CONTROL || nPart==PART_TABS_DRAW_RTL)
692 return true;
693 break;
695 case CTRL_LISTBOX:
696 if(nPart==PART_ENTIRE_CONTROL || nPart==PART_WINDOW || nPart==HAS_BACKGROUND_TEXTURE)
697 return true;
698 break;
700 case CTRL_TOOLBAR:
701 if( nPart==PART_ENTIRE_CONTROL
702 || nPart==PART_DRAW_BACKGROUND_HORZ
703 || nPart==PART_DRAW_BACKGROUND_VERT
704 || nPart==PART_THUMB_HORZ
705 || nPart==PART_THUMB_VERT
706 || nPart==PART_BUTTON
707 || nPart==PART_SEPARATOR_HORZ
708 || nPart==PART_SEPARATOR_VERT
710 return true;
711 break;
713 case CTRL_MENUBAR:
714 if(nPart==PART_ENTIRE_CONTROL || nPart==PART_MENU_ITEM)
715 return true;
716 break;
718 case CTRL_MENU_POPUP:
719 if (nPart==PART_ENTIRE_CONTROL
720 || nPart==PART_MENU_ITEM
721 || nPart==PART_MENU_ITEM_CHECK_MARK
722 || nPart==PART_MENU_ITEM_RADIO_MARK
723 || nPart==PART_MENU_SEPARATOR
724 || nPart==PART_MENU_SUBMENU_ARROW
726 return true;
727 break;
729 case CTRL_SLIDER:
730 if(nPart == PART_TRACK_HORZ_AREA || nPart == PART_TRACK_VERT_AREA)
731 return true;
732 break;
734 case CTRL_FIXEDLINE:
735 if(nPart == PART_SEPARATOR_VERT || nPart == PART_SEPARATOR_HORZ)
736 return true;
737 break;
739 case CTRL_LISTHEADER:
740 if(nPart == PART_BUTTON || nPart == PART_ARROW)
741 return true;
742 break;
745 return false;
749 * HitTestNativeControl()
751 * bIsInside is set to true if aPos is contained within the
752 * given part of the control, whose bounding region is
753 * given by rControlRegion (in VCL frame coordinates).
755 * returns whether bIsInside was really set.
757 bool GtkSalGraphics::hitTestNativeControl( ControlType nType,
758 ControlPart nPart,
759 const Rectangle& rControlRegion,
760 const Point& aPos,
761 bool& rIsInside )
763 if ( ( nType == CTRL_SCROLLBAR ) &&
764 ( ( nPart == PART_BUTTON_UP ) ||
765 ( nPart == PART_BUTTON_DOWN ) ||
766 ( nPart == PART_BUTTON_LEFT ) ||
767 ( nPart == PART_BUTTON_RIGHT ) ) )
769 NWEnsureGTKScrollbars( m_nXScreen );
771 // Grab some button style attributes
772 gboolean has_forward;
773 gboolean has_forward2;
774 gboolean has_backward;
775 gboolean has_backward2;
777 gtk_widget_style_get( gWidgetData[m_nXScreen].gScrollHorizWidget,
778 "has-forward-stepper", &has_forward,
779 "has-secondary-forward-stepper", &has_forward2,
780 "has-backward-stepper", &has_backward,
781 "has-secondary-backward-stepper", &has_backward2,
782 (char *)NULL );
783 Rectangle aForward;
784 Rectangle aBackward;
786 rIsInside = false;
788 ControlPart nCounterPart = 0;
789 if ( nPart == PART_BUTTON_UP )
790 nCounterPart = PART_BUTTON_DOWN;
791 else if ( nPart == PART_BUTTON_DOWN )
792 nCounterPart = PART_BUTTON_UP;
793 else if ( nPart == PART_BUTTON_LEFT )
794 nCounterPart = PART_BUTTON_RIGHT;
795 else if ( nPart == PART_BUTTON_RIGHT )
796 nCounterPart = PART_BUTTON_LEFT;
798 aBackward = NWGetScrollButtonRect( m_nXScreen, nPart, rControlRegion );
799 aForward = NWGetScrollButtonRect( m_nXScreen, nCounterPart, rControlRegion );
801 if ( has_backward && has_forward2 )
803 Size aSize( aBackward.GetSize() );
804 if ( ( nPart == PART_BUTTON_UP ) || ( nPart == PART_BUTTON_DOWN ) )
805 aSize.setHeight( aBackward.GetHeight() / 2 );
806 else
807 aSize.setWidth( aBackward.GetWidth() / 2 );
808 aBackward.SetSize( aSize );
810 if ( nPart == PART_BUTTON_DOWN )
811 aBackward.Move( 0, aBackward.GetHeight() / 2 );
812 else if ( nPart == PART_BUTTON_RIGHT )
813 aBackward.Move( aBackward.GetWidth() / 2, 0 );
816 if ( has_backward2 && has_forward )
818 Size aSize( aForward.GetSize() );
819 if ( ( nPart == PART_BUTTON_UP ) || ( nPart == PART_BUTTON_DOWN ) )
820 aSize.setHeight( aForward.GetHeight() / 2 );
821 else
822 aSize.setWidth( aForward.GetWidth() / 2 );
823 aForward.SetSize( aSize );
825 if ( nPart == PART_BUTTON_DOWN )
826 aForward.Move( 0, aForward.GetHeight() / 2 );
827 else if ( nPart == PART_BUTTON_RIGHT )
828 aForward.Move( aForward.GetWidth() / 2, 0 );
831 if ( ( nPart == PART_BUTTON_UP ) || ( nPart == PART_BUTTON_LEFT ) )
833 if ( has_backward )
834 rIsInside |= aBackward.IsInside( aPos );
835 if ( has_backward2 )
836 rIsInside |= aForward.IsInside( aPos );
838 else
840 if ( has_forward )
841 rIsInside |= aBackward.IsInside( aPos );
842 if ( has_forward2 )
843 rIsInside |= aForward.IsInside( aPos );
845 return true;
848 if( IsNativeControlSupported(nType, nPart) )
850 rIsInside = rControlRegion.IsInside( aPos );
851 return true;
853 else
855 return false;
860 * DrawNativeControl()
862 * Draws the requested control described by nPart/nState.
864 * rControlRegion: The bounding region of the complete control in VCL frame coordinates.
865 * aValue: An optional value (tristate/numerical/string)
866 * rCaption: A caption or title string (like button text etc)
868 bool GtkSalGraphics::drawNativeControl(ControlType nType, ControlPart nPart,
869 const Rectangle& rControlRegion, ControlState nState,
870 const ImplControlValue& aValue, const OUString& rCaption)
872 // get a GC with current clipping region set
873 GetFontGC();
875 // theme changed ?
876 if( GtkSalGraphics::bThemeChanged )
878 // invalidate caches
879 for( unsigned int i = 0; i < gWidgetData.size(); i++ )
880 if( gWidgetData[i].gNWPixmapCacheList )
881 gWidgetData[i].gNWPixmapCacheList->ThemeChanged();
882 GtkSalGraphics::bThemeChanged = false;
885 Rectangle aCtrlRect( rControlRegion );
886 vcl::Region aClipRegion( m_aClipRegion );
887 if( aClipRegion.IsNull() )
888 aClipRegion = aCtrlRect;
890 Rectangle aPixmapRect;
892 // make pixmap a little larger since some themes draw decoration
893 // outside the rectangle, see e.g. checkbox
894 aPixmapRect = Rectangle(Point( aCtrlRect.Left()-1, aCtrlRect.Top()-1 ),
895 Size( aCtrlRect.GetWidth()+2, aCtrlRect.GetHeight()+2) );
897 ControlCacheKey aControlCacheKey(nType, nPart, nState, aPixmapRect.GetSize());
898 if (aControlCacheKey.canCacheControl()
899 && TryRenderCachedNativeControl(aControlCacheKey, aPixmapRect.Left(), aPixmapRect.Top()))
901 return true;
904 clipList aClip;
905 int nPasses = 0;
906 GdkDrawable* gdkDrawable[2];
907 std::unique_ptr<GdkX11Pixmap> xPixmap;
908 std::unique_ptr<GdkX11Pixmap> xMask;
910 if ((bNeedPixmapPaint || (nState & ControlState::DOUBLEBUFFERING))
911 && nType != CTRL_SCROLLBAR
912 && nType != CTRL_SPINBOX
913 && nType != CTRL_TAB_ITEM
914 && nType != CTRL_TAB_PANE
915 && nType != CTRL_PROGRESS
916 && ! (nType == CTRL_TOOLBAR && (nPart == PART_THUMB_HORZ || nPart == PART_THUMB_VERT) )
919 if( bNeedTwoPasses )
921 xPixmap.reset( NWGetPixmapFromScreen( aPixmapRect, BG_WHITE ) );
922 xMask.reset( NWGetPixmapFromScreen( aPixmapRect, BG_BLACK ) );
923 if( !xPixmap || !xMask )
924 return false;
925 nPasses = 2;
926 gdkDrawable[0] = xPixmap->GetGdkDrawable();
927 gdkDrawable[1] = xMask->GetGdkDrawable();
929 else
931 xPixmap.reset( NWGetPixmapFromScreen( aPixmapRect, BG_FILL ) );
932 if( !xPixmap )
933 return false;
934 nPasses = 1;
935 gdkDrawable[0] = xPixmap->GetGdkDrawable();
938 aCtrlRect = Rectangle( Point(1,1), aCtrlRect.GetSize() );
939 aClip.push_back( aCtrlRect );
941 else
943 nPasses = 1;
944 gdkDrawable[0] = GDK_DRAWABLE( GetGdkWindow() );
945 RectangleVector aRectangles;
946 aClipRegion.GetRegionRectangles(aRectangles);
948 for(RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); ++aRectIter)
950 Rectangle aPaintRect = aCtrlRect.GetIntersection(*aRectIter);
951 if( aPaintRect.IsEmpty() )
952 continue;
953 aClip.push_back( aPaintRect );
957 bool returnVal = false;
959 for( int i = 0; i < nPasses; ++i )
961 assert(gdkDrawable[i] && "rhbz#1050162");
962 if( gdkDrawable[i] == 0 )
963 return false;
965 returnVal = DoDrawNativeControl( gdkDrawable[i], nType, nPart, aCtrlRect, aClip,
966 nState, aValue, rCaption );
967 if( !returnVal )
968 break;
971 if( xPixmap )
972 returnVal = returnVal && RenderAndCacheNativeControl(xPixmap.get(), xMask.get(),
973 aPixmapRect.Left(), aPixmapRect.Top(),
974 aControlCacheKey);
976 return returnVal;
980 bool GtkSalGraphics::DoDrawNativeControl(
981 GdkDrawable* pDrawable,
982 ControlType nType,
983 ControlPart nPart,
984 const Rectangle& aCtrlRect,
985 const clipList& aClip,
986 ControlState nState,
987 const ImplControlValue& aValue,
988 const OUString& rCaption )
990 if ( (nType==CTRL_PUSHBUTTON) && (nPart==PART_ENTIRE_CONTROL) )
992 return NWPaintGTKButton( pDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
994 else if ( (nType==CTRL_RADIOBUTTON) && (nPart==PART_ENTIRE_CONTROL) )
996 return NWPaintGTKRadio( pDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
998 else if ( (nType==CTRL_CHECKBOX) && (nPart==PART_ENTIRE_CONTROL) )
1000 return NWPaintGTKCheck( pDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
1002 else if ( (nType==CTRL_SCROLLBAR) && ((nPart==PART_DRAW_BACKGROUND_HORZ) || (nPart==PART_DRAW_BACKGROUND_VERT)) )
1004 return NWPaintGTKScrollbar( nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
1006 else if ( ((nType==CTRL_EDITBOX) && ((nPart==PART_ENTIRE_CONTROL) || (nPart==HAS_BACKGROUND_TEXTURE)) )
1007 || ((nType==CTRL_SPINBOX) && (nPart==HAS_BACKGROUND_TEXTURE))
1008 || ((nType==CTRL_COMBOBOX) && (nPart==HAS_BACKGROUND_TEXTURE))
1009 || ((nType==CTRL_LISTBOX) && (nPart==HAS_BACKGROUND_TEXTURE)) )
1011 return NWPaintGTKEditBox( pDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
1013 else if ( ((nType==CTRL_MULTILINE_EDITBOX) && ((nPart==PART_ENTIRE_CONTROL) || (nPart==HAS_BACKGROUND_TEXTURE)) ) )
1015 return NWPaintGTKEditBox( pDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
1017 else if ( ((nType==CTRL_SPINBOX) || (nType==CTRL_SPINBUTTONS))
1018 && ((nPart==PART_ENTIRE_CONTROL) || (nPart==PART_ALL_BUTTONS)) )
1020 return NWPaintGTKSpinBox( nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
1022 else if ( (nType == CTRL_COMBOBOX) &&
1023 ( (nPart==PART_ENTIRE_CONTROL)
1024 ||(nPart==PART_BUTTON_DOWN)
1027 return NWPaintGTKComboBox( pDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
1029 else if ( (nType==CTRL_TAB_ITEM) || (nType==CTRL_TAB_PANE) || (nType==CTRL_TAB_BODY) )
1031 if ( nType == CTRL_TAB_BODY )
1032 return true;
1033 else
1034 return NWPaintGTKTabItem( nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption);
1036 else if ( (nType==CTRL_LISTBOX) && ((nPart==PART_ENTIRE_CONTROL) || (nPart==PART_WINDOW)) )
1038 return NWPaintGTKListBox( pDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
1040 else if ( nType== CTRL_TOOLBAR )
1042 return NWPaintGTKToolbar( pDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
1044 else if ( nType== CTRL_MENUBAR )
1046 return NWPaintGTKMenubar( pDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
1048 else if( (nType == CTRL_MENU_POPUP)
1049 && ( (nPart == PART_ENTIRE_CONTROL)
1050 || (nPart == PART_MENU_ITEM)
1051 || (nPart == PART_MENU_ITEM_CHECK_MARK)
1052 || (nPart == PART_MENU_ITEM_RADIO_MARK)
1053 || (nPart == PART_MENU_SEPARATOR)
1054 || (nPart == PART_MENU_SUBMENU_ARROW)
1058 return NWPaintGTKPopupMenu( pDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
1060 else if( (nType == CTRL_TOOLTIP) && (nPart == PART_ENTIRE_CONTROL) )
1062 return NWPaintGTKTooltip( pDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
1064 else if( (nType == CTRL_PROGRESS) && (nPart == PART_ENTIRE_CONTROL) )
1066 return NWPaintGTKProgress( pDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
1068 else if( (nType == CTRL_LISTNODE) && (nPart == PART_ENTIRE_CONTROL) )
1070 return NWPaintGTKListNode( pDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
1072 else if( (nType == CTRL_LISTNET) && (nPart == PART_ENTIRE_CONTROL) )
1074 // don't actually draw anything; gtk treeviews do not draw lines
1075 return TRUE;
1077 else if( nType == CTRL_SLIDER )
1079 return NWPaintGTKSlider( pDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
1081 else if( nType == CTRL_WINDOW_BACKGROUND )
1083 return NWPaintGTKWindowBackground( pDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
1085 else if( nType == CTRL_FIXEDLINE )
1087 return NWPaintGTKFixedLine( pDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
1089 else if(nType==CTRL_FRAME)
1091 return NWPaintGTKFrame( pDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption);
1093 else if(nType==CTRL_LISTHEADER)
1095 if(nPart == PART_BUTTON)
1096 return NWPaintGTKListHeader( pDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
1097 else if(nPart == PART_ARROW)
1098 return NWPaintGTKArrow( pDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
1101 return false;
1105 * GetNativeControlRegion()
1107 * If the return value is true, rNativeBoundingRegion
1108 * contains the true bounding region covered by the control
1109 * including any adornment, while rNativeContentRegion contains the area
1110 * within the control that can be safely drawn into without drawing over
1111 * the borders of the control.
1113 * rControlRegion: The bounding region of the control in VCL frame coordinates.
1114 * aValue: An optional value (tristate/numerical/string)
1115 * rCaption: A caption or title string (like button text etc)
1117 bool GtkSalGraphics::getNativeControlRegion( ControlType nType,
1118 ControlPart nPart,
1119 const Rectangle& rControlRegion,
1120 ControlState nState,
1121 const ImplControlValue& aValue,
1122 const OUString& rCaption,
1123 Rectangle &rNativeBoundingRegion,
1124 Rectangle &rNativeContentRegion )
1126 bool returnVal = false;
1128 if ( (nType==CTRL_PUSHBUTTON) && (nPart==PART_ENTIRE_CONTROL)
1129 && (rControlRegion.GetWidth() > 16)
1130 && (rControlRegion.GetHeight() > 16) )
1132 rNativeBoundingRegion = NWGetButtonArea( m_nXScreen, nType, nPart, rControlRegion,
1133 nState, aValue, rCaption );
1134 rNativeContentRegion = rControlRegion;
1136 returnVal = true;
1138 if (nType == CTRL_TAB_ITEM && nPart == PART_ENTIRE_CONTROL)
1140 rNativeBoundingRegion = NWGetTabItemRect(m_nXScreen, rControlRegion);
1141 rNativeContentRegion = rNativeBoundingRegion;
1142 returnVal = true;
1144 if ( (nType==CTRL_COMBOBOX) && ((nPart==PART_BUTTON_DOWN) || (nPart==PART_SUB_EDIT)) )
1146 rNativeBoundingRegion = NWGetComboBoxButtonRect( m_nXScreen, nType, nPart, rControlRegion, nState,
1147 aValue, rCaption );
1148 rNativeContentRegion = rNativeBoundingRegion;
1150 returnVal = true;
1152 if ( (nType==CTRL_SPINBOX) && ((nPart==PART_BUTTON_UP) || (nPart==PART_BUTTON_DOWN) || (nPart==PART_SUB_EDIT)) )
1155 rNativeBoundingRegion = NWGetSpinButtonRect( m_nXScreen, nType, nPart, rControlRegion, nState,
1156 aValue, rCaption );
1157 rNativeContentRegion = rNativeBoundingRegion;
1159 returnVal = true;
1161 if ( (nType==CTRL_LISTBOX) && ((nPart==PART_BUTTON_DOWN) || (nPart==PART_SUB_EDIT)) )
1163 rNativeBoundingRegion = NWGetListBoxButtonRect( m_nXScreen, nType, nPart, rControlRegion, nState,
1164 aValue, rCaption );
1165 rNativeContentRegion = rNativeBoundingRegion;
1167 returnVal = true;
1169 if ( (nType==CTRL_TOOLBAR) &&
1170 ((nPart==PART_DRAW_BACKGROUND_HORZ) ||
1171 (nPart==PART_DRAW_BACKGROUND_VERT) ||
1172 (nPart==PART_THUMB_HORZ) ||
1173 (nPart==PART_THUMB_VERT) ||
1174 (nPart==PART_BUTTON)
1177 rNativeBoundingRegion = NWGetToolbarRect( m_nXScreen, nType, nPart, rControlRegion, nState, aValue, rCaption );
1178 rNativeContentRegion = rNativeBoundingRegion;
1179 returnVal = true;
1181 if ( (nType==CTRL_SCROLLBAR) && ((nPart==PART_BUTTON_LEFT) || (nPart==PART_BUTTON_RIGHT) ||
1182 (nPart==PART_BUTTON_UP) || (nPart==PART_BUTTON_DOWN) ) )
1184 rNativeBoundingRegion = NWGetScrollButtonRect( m_nXScreen, nPart, rControlRegion );
1185 rNativeContentRegion = rNativeBoundingRegion;
1187 //See fdo#33523, possibly makes sense to do this test for all return values
1188 if (!rNativeContentRegion.GetWidth())
1189 rNativeContentRegion.Right() = rNativeContentRegion.Left() + 1;
1190 if (!rNativeContentRegion.GetHeight())
1191 rNativeContentRegion.Bottom() = rNativeContentRegion.Top() + 1;
1192 returnVal = true;
1194 if( (nType == CTRL_MENUBAR) && (nPart == PART_ENTIRE_CONTROL) )
1196 NWEnsureGTKMenubar( m_nXScreen );
1197 GtkRequisition aReq;
1198 gtk_widget_size_request( gWidgetData[m_nXScreen].gMenubarWidget, &aReq );
1199 Rectangle aMenuBarRect = rControlRegion;
1200 aMenuBarRect = Rectangle( aMenuBarRect.TopLeft(),
1201 Size( aMenuBarRect.GetWidth(), aReq.height+1 ) );
1202 rNativeBoundingRegion = aMenuBarRect;
1203 rNativeContentRegion = rNativeBoundingRegion;
1204 returnVal = true;
1206 if( nType == CTRL_MENU_POPUP )
1208 if( (nPart == PART_MENU_ITEM_CHECK_MARK) ||
1209 (nPart == PART_MENU_ITEM_RADIO_MARK) )
1211 NWEnsureGTKMenu( m_nXScreen );
1213 gint indicator_size = 0;
1214 GtkWidget* pWidget = (nPart == PART_MENU_ITEM_CHECK_MARK) ?
1215 gWidgetData[m_nXScreen].gMenuItemCheckMenuWidget : gWidgetData[m_nXScreen].gMenuItemRadioMenuWidget;
1216 gtk_widget_style_get( pWidget,
1217 "indicator_size", &indicator_size,
1218 (char *)NULL );
1219 rNativeBoundingRegion = rControlRegion;
1220 Rectangle aIndicatorRect( Point( 0,
1221 (rControlRegion.GetHeight()-indicator_size)/2),
1222 Size( indicator_size, indicator_size ) );
1223 rNativeContentRegion = aIndicatorRect;
1224 returnVal = true;
1226 else if( nPart == PART_MENU_SUBMENU_ARROW )
1228 GtkWidget* widget = gWidgetData[m_nXScreen].gMenuItemMenuWidget;
1229 GtkWidget* child;
1230 PangoContext *context;
1231 PangoFontMetrics *metrics;
1232 gint arrow_size;
1233 gint arrow_extent;
1234 guint horizontal_padding;
1235 gfloat arrow_scaling = 0.4; // Default for early GTK versions
1237 gtk_widget_style_get( widget,
1238 "horizontal-padding", &horizontal_padding,
1239 NULL );
1241 // Use arrow-scaling property if available (2.15+), avoid warning otherwise
1242 if ( gtk_widget_class_find_style_property( GTK_WIDGET_GET_CLASS( widget ),
1243 "arrow-scaling" ) )
1245 gtk_widget_style_get( widget,
1246 "arrow-scaling", &arrow_scaling,
1247 NULL );
1250 child = GTK_BIN( widget )->child;
1252 context = gtk_widget_get_pango_context( child );
1253 metrics = pango_context_get_metrics( context,
1254 child->style->font_desc,
1255 pango_context_get_language( context ) );
1257 arrow_size = ( PANGO_PIXELS( pango_font_metrics_get_ascent( metrics ) +
1258 pango_font_metrics_get_descent( metrics ) ));
1260 pango_font_metrics_unref( metrics );
1262 arrow_extent = static_cast<gint>(arrow_size * arrow_scaling);
1264 rNativeContentRegion = Rectangle( Point( 0, 0 ),
1265 Size( arrow_extent, arrow_extent ));
1266 rNativeBoundingRegion = Rectangle( Point( 0, 0 ),
1267 Size( arrow_extent + horizontal_padding, arrow_extent ));
1268 returnVal = true;
1271 if( (nType == CTRL_RADIOBUTTON || nType == CTRL_CHECKBOX) )
1273 NWEnsureGTKRadio( m_nXScreen );
1274 NWEnsureGTKCheck( m_nXScreen );
1275 GtkWidget* widget = (nType == CTRL_RADIOBUTTON) ? gWidgetData[m_nXScreen].gRadioWidget : gWidgetData[m_nXScreen].gCheckWidget;
1276 gint indicator_size, indicator_spacing, focusPad, focusWidth;
1277 gtk_widget_style_get( widget,
1278 "indicator_size", &indicator_size,
1279 "indicator_spacing", &indicator_spacing,
1280 "focus-line-width", &focusWidth,
1281 "focus-padding", &focusPad,
1282 (char *)NULL);
1283 indicator_size += 2*indicator_spacing + 2*(focusWidth + focusWidth);
1284 rNativeBoundingRegion = rControlRegion;
1285 Rectangle aIndicatorRect( Point( 0,
1286 (rControlRegion.GetHeight()-indicator_size)/2),
1287 Size( indicator_size, indicator_size ) );
1288 rNativeContentRegion = aIndicatorRect;
1289 returnVal = true;
1291 if( (nType == CTRL_EDITBOX || nType == CTRL_SPINBOX || nType == CTRL_COMBOBOX) && nPart == PART_ENTIRE_CONTROL )
1293 NWEnsureGTKEditBox( m_nXScreen );
1294 GtkWidget* widget = gWidgetData[m_nXScreen].gEditBoxWidget;
1295 GtkRequisition aReq;
1296 gtk_widget_size_request( widget, &aReq );
1297 Rectangle aEditRect = rControlRegion;
1298 long nHeight = (aEditRect.GetHeight() > aReq.height) ? aEditRect.GetHeight() : aReq.height;
1299 aEditRect = Rectangle( aEditRect.TopLeft(),
1300 Size( aEditRect.GetWidth(), nHeight ) );
1301 rNativeBoundingRegion = aEditRect;
1302 rNativeContentRegion = rNativeBoundingRegion;
1303 returnVal = true;
1305 if( (nType == CTRL_SLIDER) && (nPart == PART_THUMB_HORZ || nPart == PART_THUMB_VERT) )
1307 NWEnsureGTKSlider( m_nXScreen );
1308 GtkWidget* widget = (nPart == PART_THUMB_HORZ) ? gWidgetData[m_nXScreen].gHScale : gWidgetData[m_nXScreen].gVScale;
1309 gint slider_length = 10;
1310 gint slider_width = 10;
1311 gtk_widget_style_get( widget,
1312 "slider-width", &slider_width,
1313 "slider-length", &slider_length,
1314 (char *)NULL);
1315 Rectangle aRect( rControlRegion );
1316 if( nPart == PART_THUMB_HORZ )
1318 aRect.Right() = aRect.Left() + slider_length - 1;
1319 aRect.Bottom() = aRect.Top() + slider_width - 1;
1321 else
1323 aRect.Bottom() = aRect.Top() + slider_length - 1;
1324 aRect.Right() = aRect.Left() + slider_width - 1;
1326 rNativeBoundingRegion = rNativeContentRegion = aRect;
1327 returnVal = true;
1329 if( nType == CTRL_FRAME && nPart == PART_BORDER )
1331 int frameWidth = getFrameWidth(gWidgetData[m_nXScreen].gFrame);
1332 rNativeBoundingRegion = rControlRegion;
1333 DrawFrameFlags nStyle = static_cast<DrawFrameFlags>(aValue.getNumericVal() & 0xfff0);
1334 int x1=rControlRegion.Left();
1335 int y1=rControlRegion.Top();
1336 int x2=rControlRegion.Right();
1337 int y2=rControlRegion.Bottom();
1339 if( nStyle & DrawFrameFlags::NoDraw )
1341 rNativeContentRegion = Rectangle(x1+frameWidth,
1342 y1+frameWidth,
1343 x2-frameWidth,
1344 y2-frameWidth);
1346 else
1347 rNativeContentRegion = rControlRegion;
1348 returnVal=true;
1351 return returnVal;
1354 /************************************************************************
1355 * Individual control drawing functions
1356 ************************************************************************/
1358 // macros to call before and after the rendering code for a widget
1359 // it takes care of creating the needed pixmaps
1360 #define BEGIN_PIXMAP_RENDER(aRect, gdkPixmap) \
1361 std::unique_ptr<GdkX11Pixmap> _pixmap, _mask; \
1362 int _nPasses = 0; \
1363 if( bNeedTwoPasses ) \
1365 _nPasses = 2; \
1366 _pixmap.reset( NWGetPixmapFromScreen( aRect, BG_WHITE ) ); \
1367 _mask.reset( NWGetPixmapFromScreen( aRect, BG_BLACK ) ); \
1369 else \
1371 _nPasses = 1; \
1372 _pixmap.reset( NWGetPixmapFromScreen( aRect, BG_FILL ) ); \
1374 if( !_pixmap || ( bNeedTwoPasses && !_mask ) ) \
1375 return false; \
1376 for( int i = 0; i < _nPasses; ++i ) \
1378 GdkPixmap* gdkPixmap = (i == 0) ? _pixmap->GetGdkPixmap() \
1379 : _mask->GetGdkPixmap();
1381 #define END_PIXMAP_RENDER(aRect) \
1383 if( !NWRenderPixmapToScreen( _pixmap.get(), _mask.get(), aRect ) ) \
1384 return false;
1386 // same as above but with pixmaps that should be kept for caching
1387 #define BEGIN_CACHE_PIXMAP_RENDER(aRect, pixmap, mask, gdkPixmap) \
1388 int _nPasses = 0; \
1389 if( bNeedTwoPasses ) \
1391 _nPasses = 2; \
1392 pixmap = NWGetPixmapFromScreen( aRect, BG_WHITE ); \
1393 mask = NWGetPixmapFromScreen( aRect, BG_BLACK ); \
1395 else \
1397 _nPasses = 1; \
1398 pixmap = NWGetPixmapFromScreen( aRect, BG_FILL ); \
1399 mask = NULL; \
1401 if( !pixmap || ( bNeedTwoPasses && !mask ) ) \
1402 return false; \
1403 for( int i = 0; i < _nPasses; ++i ) \
1405 GdkPixmap* gdkPixmap = (i == 0) ? pixmap->GetGdkPixmap() \
1406 : mask->GetGdkPixmap();
1408 #define END_CACHE_PIXMAP_RENDER(aRect, pixmap, mask) \
1410 if( !NWRenderPixmapToScreen( pixmap, mask, aRect ) ) \
1411 return false;
1413 bool GtkSalGraphics::NWPaintGTKArrow(
1414 GdkDrawable* gdkDrawable,
1415 ControlType, ControlPart,
1416 const Rectangle& rControlRectangle,
1417 const clipList& rClipList,
1418 ControlState nState, const ImplControlValue& aValue,
1419 const OUString& )
1421 GtkArrowType arrowType(aValue.getNumericVal()&1?GTK_ARROW_DOWN:GTK_ARROW_UP);
1422 GtkStateType stateType(nState&ControlState::PRESSED?GTK_STATE_ACTIVE:GTK_STATE_NORMAL);
1424 GdkRectangle clipRect;
1425 for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it )
1427 clipRect.x = it->Left();
1428 clipRect.y = it->Top();
1429 clipRect.width = it->GetWidth();
1430 clipRect.height = it->GetHeight();
1432 gtk_paint_arrow(m_pWindow->style,gdkDrawable,stateType,GTK_SHADOW_NONE,&clipRect,
1433 m_pWindow,"arrow",arrowType,true,
1434 rControlRectangle.Left(),
1435 rControlRectangle.Top(),
1436 rControlRectangle.GetWidth(),
1437 rControlRectangle.GetHeight());
1439 return true;
1442 bool GtkSalGraphics::NWPaintGTKListHeader(
1443 GdkDrawable* gdkDrawable,
1444 ControlType, ControlPart,
1445 const Rectangle& rControlRectangle,
1446 const clipList& rClipList,
1447 ControlState nState, const ImplControlValue&,
1448 const OUString& )
1450 GtkStateType stateType;
1451 GtkShadowType shadowType;
1452 NWEnsureGTKTreeView( m_nXScreen );
1453 GtkWidget* &treeview(gWidgetData[m_nXScreen].gTreeView);
1454 GtkTreeViewColumn* column=gtk_tree_view_get_column(GTK_TREE_VIEW(treeview),0);
1455 GtkWidget* button=gtk_tree_view_column_get_widget(column);
1456 while(button && !GTK_IS_BUTTON(button))
1457 button=gtk_widget_get_parent(button);
1458 if(!button)
1459 // Shouldn't ever happen
1460 return false;
1461 gtk_widget_realize(button);
1462 NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
1463 NWSetWidgetState( button, nState, stateType );
1465 GdkRectangle clipRect;
1466 for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it )
1468 clipRect.x = it->Left();
1469 clipRect.y = it->Top();
1470 clipRect.width = it->GetWidth();
1471 clipRect.height = it->GetHeight();
1473 gtk_paint_box(button->style,gdkDrawable,stateType,shadowType,&clipRect,
1474 button,"button",
1475 rControlRectangle.Left()-1,
1476 rControlRectangle.Top(),
1477 rControlRectangle.GetWidth()+1,
1478 rControlRectangle.GetHeight());
1480 return true;
1483 bool GtkSalGraphics::NWPaintGTKFixedLine(
1484 GdkDrawable* gdkDrawable,
1485 ControlType, ControlPart nPart,
1486 const Rectangle& rControlRectangle,
1487 const clipList&,
1488 ControlState, const ImplControlValue&,
1489 const OUString& )
1491 if(nPart == PART_SEPARATOR_HORZ)
1492 gtk_paint_hline(m_pWindow->style,gdkDrawable,GTK_STATE_NORMAL,NULL,m_pWindow,"hseparator",rControlRectangle.Left(),rControlRectangle.Right(),rControlRectangle.Top());
1493 else
1494 gtk_paint_vline(m_pWindow->style,gdkDrawable,GTK_STATE_NORMAL,NULL,m_pWindow,"vseparator",rControlRectangle.Top(),rControlRectangle.Bottom(),rControlRectangle.Left());
1496 return true;
1499 bool GtkSalGraphics::NWPaintGTKFrame(
1500 GdkDrawable* gdkDrawable,
1501 ControlType, ControlPart,
1502 const Rectangle& rControlRectangle,
1503 const clipList& rClipList,
1504 ControlState /* nState */, const ImplControlValue& aValue,
1505 const OUString& )
1507 GdkRectangle clipRect;
1508 int frameWidth=getFrameWidth(gWidgetData[m_nXScreen].gFrame);
1509 GtkShadowType shadowType=GTK_SHADOW_IN;
1510 DrawFrameStyle nStyle = static_cast<DrawFrameStyle>(aValue.getNumericVal() & 0x0f);
1511 if( nStyle == DrawFrameStyle::In )
1512 shadowType=GTK_SHADOW_OUT;
1513 if( nStyle == DrawFrameStyle::Out )
1514 shadowType=GTK_SHADOW_IN;
1516 for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it )
1518 clipRect.x = it->Left();
1519 clipRect.y = it->Top();
1520 clipRect.width = it->GetWidth();
1521 clipRect.height = it->GetHeight();
1523 // Draw background first
1525 // Top
1526 gtk_paint_flat_box(m_pWindow->style,gdkDrawable,GTK_STATE_NORMAL,GTK_SHADOW_OUT,&clipRect,
1527 m_pWindow,"base",
1528 rControlRectangle.Left(),
1529 rControlRectangle.Top(),
1530 rControlRectangle.GetWidth(),
1531 frameWidth);
1532 // Bottom
1533 gtk_paint_flat_box(m_pWindow->style,gdkDrawable,GTK_STATE_NORMAL,GTK_SHADOW_OUT,&clipRect,
1534 m_pWindow,"base",
1535 rControlRectangle.Left(),
1536 rControlRectangle.Top()+rControlRectangle.GetHeight()-frameWidth,
1537 rControlRectangle.GetWidth(),
1538 frameWidth);
1539 // Left
1540 gtk_paint_flat_box(m_pWindow->style,gdkDrawable,GTK_STATE_NORMAL,GTK_SHADOW_OUT,&clipRect,
1541 m_pWindow,"base",
1542 rControlRectangle.Left(),
1543 rControlRectangle.Top(),
1544 2*frameWidth,
1545 rControlRectangle.GetHeight());
1546 // Right
1547 gtk_paint_flat_box(m_pWindow->style,gdkDrawable,GTK_STATE_NORMAL,GTK_SHADOW_OUT,&clipRect,
1548 m_pWindow,"base",
1549 rControlRectangle.Left()+rControlRectangle.GetWidth()-frameWidth,
1550 rControlRectangle.Top(),
1551 2*frameWidth,
1552 rControlRectangle.GetHeight());
1554 // Now render the frame
1555 gtk_paint_shadow(gWidgetData[m_nXScreen].gFrame->style,gdkDrawable,GTK_STATE_NORMAL,shadowType,&clipRect,
1556 gWidgetData[m_nXScreen].gFrame,"base",
1557 rControlRectangle.Left(),
1558 rControlRectangle.Top(),
1559 rControlRectangle.GetWidth(),
1560 rControlRectangle.GetHeight());
1563 return true;
1566 bool GtkSalGraphics::NWPaintGTKWindowBackground(
1567 GdkDrawable* gdkDrawable,
1568 ControlType, ControlPart,
1569 const Rectangle& rControlRectangle,
1570 const clipList& rClipList,
1571 ControlState /* nState */, const ImplControlValue&,
1572 const OUString& )
1574 GdkRectangle clipRect;
1575 for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it )
1577 clipRect.x = it->Left();
1578 clipRect.y = it->Top();
1579 clipRect.width = it->GetWidth();
1580 clipRect.height = it->GetHeight();
1582 gtk_paint_flat_box(m_pWindow->style,gdkDrawable,GTK_STATE_NORMAL,GTK_SHADOW_NONE,&clipRect,
1583 m_pWindow,"base",
1584 rControlRectangle.Left(),
1585 rControlRectangle.Top(),
1586 rControlRectangle.GetWidth(),
1587 rControlRectangle.GetHeight());
1590 return true;
1593 bool GtkSalGraphics::NWPaintGTKButtonReal(
1594 GtkWidget* button,
1595 GdkDrawable* gdkDrawable,
1596 ControlType, ControlPart,
1597 const Rectangle& rControlRectangle,
1598 const clipList& rClipList,
1599 ControlState nState, const ImplControlValue&,
1600 const OUString& )
1602 GtkStateType stateType;
1603 GtkShadowType shadowType;
1604 gboolean interiorFocus;
1605 gint focusWidth;
1606 gint focusPad;
1607 bool bDrawFocus = true;
1608 gint x, y, w, h;
1609 GtkBorder aDefBorder;
1610 GtkBorder* pBorder;
1611 GdkRectangle clipRect;
1613 NWEnsureGTKButton( m_nXScreen );
1614 NWEnsureGTKToolbar( m_nXScreen );
1616 // Flat toolbutton has a bit bigger variety of states than normal buttons, so handle it differently
1617 if(GTK_IS_TOGGLE_BUTTON(button))
1619 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)))
1620 shadowType=GTK_SHADOW_IN;
1621 else
1622 shadowType=GTK_SHADOW_OUT;
1624 if(nState & ControlState::ROLLOVER)
1625 stateType=GTK_STATE_PRELIGHT;
1626 else
1627 stateType=GTK_STATE_NORMAL;
1629 if(nState & ControlState::PRESSED)
1631 stateType=GTK_STATE_ACTIVE;
1632 shadowType=GTK_SHADOW_IN;
1635 else
1637 NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
1638 NWSetWidgetState( gWidgetData[m_nXScreen].gBtnWidget, nState, stateType );
1641 x = rControlRectangle.Left();
1642 y = rControlRectangle.Top();
1643 w = rControlRectangle.GetWidth();
1644 h = rControlRectangle.GetHeight();
1646 gint internal_padding = 0;
1647 if(GTK_IS_TOOL_ITEM(button))
1649 gtk_widget_style_get (GTK_WIDGET (gWidgetData[m_nXScreen].gToolbarWidget),
1650 "internal-padding", &internal_padding,
1651 NULL);
1652 x += internal_padding/2;
1653 w -= internal_padding;
1654 stateType = GTK_STATE_PRELIGHT;
1657 // Grab some button style attributes
1658 gtk_widget_style_get( gWidgetData[m_nXScreen].gBtnWidget, "focus-line-width", &focusWidth,
1659 "focus-padding", &focusPad,
1660 "interior_focus", &interiorFocus,
1661 (char *)NULL );
1662 gtk_widget_style_get( gWidgetData[m_nXScreen].gBtnWidget,
1663 "default_border", &pBorder,
1664 (char *)NULL );
1666 // Make sure the border values exist, otherwise use some defaults
1667 if ( pBorder )
1669 NW_gtk_border_set_from_border( aDefBorder, pBorder );
1670 gtk_border_free( pBorder );
1672 else NW_gtk_border_set_from_border( aDefBorder, &aDefDefBorder );
1674 // If the button is too small, don't ever draw focus or grab more space
1675 if ( (w < 16) || (h < 16) )
1676 bDrawFocus = false;
1678 gint xi = x, yi = y, wi = w, hi = h;
1679 if ( (nState & ControlState::DEFAULT) && bDrawFocus )
1681 xi += aDefBorder.left;
1682 yi += aDefBorder.top;
1683 wi -= aDefBorder.left + aDefBorder.right;
1684 hi -= aDefBorder.top + aDefBorder.bottom;
1687 if ( !interiorFocus && bDrawFocus )
1689 xi += focusWidth + focusPad;
1690 yi += focusWidth + focusPad;
1691 wi -= 2 * (focusWidth + focusPad);
1692 hi -= 2 * (focusWidth + focusPad);
1694 for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it)
1696 clipRect.x = it->Left();
1697 clipRect.y = it->Top();
1698 clipRect.width = it->GetWidth();
1699 clipRect.height = it->GetHeight();
1701 // Buttons must paint opaque since some themes have alpha-channel enabled buttons
1702 if(button == gWidgetData[m_nXScreen].gToolbarButtonWidget)
1704 gtk_paint_box( gWidgetData[m_nXScreen].gToolbarWidget->style, gdkDrawable, GTK_STATE_NORMAL, GTK_SHADOW_NONE,
1705 &clipRect, gWidgetData[m_nXScreen].gToolbarWidget, "toolbar", x, y, w, h );
1707 else
1709 gtk_paint_box( m_pWindow->style, gdkDrawable, GTK_STATE_NORMAL, GTK_SHADOW_NONE,
1710 &clipRect, m_pWindow, "base", x, y, w, h );
1713 if ( GTK_IS_BUTTON(button) )
1715 if ( (nState & ControlState::DEFAULT) )
1716 gtk_paint_box( button->style, gdkDrawable, GTK_STATE_NORMAL, GTK_SHADOW_IN,
1717 &clipRect, button, "buttondefault", x, y, w, h );
1719 /* don't draw "button", because it can be a tool_button, and
1720 * it causes some weird things, so, the default button is
1721 * just fine */
1722 gtk_paint_box( button->style, gdkDrawable, stateType, shadowType,
1723 &clipRect, button, "button", xi, yi, wi, hi );
1727 return true;
1730 bool GtkSalGraphics::NWPaintGTKButton(
1731 GdkDrawable* gdkDrawable,
1732 ControlType type, ControlPart part,
1733 const Rectangle& rControlRectangle,
1734 const clipList& rClipList,
1735 ControlState nState, const ImplControlValue& value,
1736 const OUString& string)
1738 return NWPaintGTKButtonReal(
1739 gWidgetData[m_nXScreen].gBtnWidget,
1740 gdkDrawable,
1741 type, part,
1742 rControlRectangle,
1743 rClipList,
1744 nState, value,
1745 string );
1748 static Rectangle NWGetButtonArea( SalX11Screen nScreen,
1749 ControlType, ControlPart, Rectangle aAreaRect, ControlState nState,
1750 const ImplControlValue&, const OUString& )
1752 gboolean interiorFocus;
1753 gint focusWidth;
1754 gint focusPad;
1755 GtkBorder aDefBorder;
1756 GtkBorder * pBorder;
1757 bool bDrawFocus = true;
1758 Rectangle aRect;
1759 gint x, y, w, h;
1761 NWEnsureGTKButton( nScreen );
1762 gtk_widget_style_get( gWidgetData[nScreen].gBtnWidget,
1763 "focus-line-width", &focusWidth,
1764 "focus-padding", &focusPad,
1765 "interior_focus", &interiorFocus,
1766 "default_border", &pBorder,
1767 (char *)NULL );
1769 // Make sure the border values exist, otherwise use some defaults
1770 if ( pBorder )
1772 NW_gtk_border_set_from_border( aDefBorder, pBorder );
1773 gtk_border_free( pBorder );
1775 else NW_gtk_border_set_from_border( aDefBorder, &aDefDefBorder );
1777 x = aAreaRect.Left();
1778 y = aAreaRect.Top();
1779 w = aAreaRect.GetWidth();
1780 h = aAreaRect.GetHeight();
1782 // If the button is too small, don't ever draw focus or grab more space
1783 if ( (w < 16) || (h < 16) )
1784 bDrawFocus = false;
1786 if ( (nState & ControlState::DEFAULT) && bDrawFocus )
1788 x -= aDefBorder.left;
1789 y -= aDefBorder.top;
1790 w += aDefBorder.left + aDefBorder.right;
1791 h += aDefBorder.top + aDefBorder.bottom;
1794 aRect = Rectangle( Point( x, y ), Size( w, h ) );
1796 return aRect;
1799 static Rectangle NWGetTabItemRect( SalX11Screen nScreen, Rectangle aAreaRect )
1801 NWEnsureGTKNotebook( nScreen );
1803 gint x, y, w, h;
1805 x = aAreaRect.Left();
1806 y = aAreaRect.Top();
1807 w = aAreaRect.GetWidth();
1808 h = aAreaRect.GetHeight();
1810 gint xthickness = gWidgetData[nScreen].gNotebookWidget->style->xthickness;
1811 gint ythickness = gWidgetData[nScreen].gNotebookWidget->style->ythickness;
1813 x -= xthickness;
1814 y -= ythickness;
1815 w += xthickness*2;
1816 h += ythickness*2;
1818 return Rectangle( Point( x, y ), Size( w, h ) );
1821 bool GtkSalGraphics::NWPaintGTKRadio( GdkDrawable* gdkDrawable,
1822 ControlType, ControlPart,
1823 const Rectangle& rControlRectangle,
1824 const clipList& rClipList,
1825 ControlState nState,
1826 const ImplControlValue& aValue,
1827 const OUString& )
1829 GtkStateType stateType;
1830 GtkShadowType shadowType;
1831 bool isChecked = (aValue.getTristateVal()==BUTTONVALUE_ON);
1832 gint x, y;
1833 GdkRectangle clipRect;
1835 NWEnsureGTKButton( m_nXScreen );
1836 NWEnsureGTKRadio( m_nXScreen );
1837 NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
1839 gint indicator_size;
1840 gtk_widget_style_get( gWidgetData[m_nXScreen].gRadioWidget, "indicator_size", &indicator_size, (char *)NULL);
1842 x = rControlRectangle.Left() + (rControlRectangle.GetWidth()-indicator_size)/2;
1843 y = rControlRectangle.Top() + (rControlRectangle.GetHeight()-indicator_size)/2;
1845 // Set the shadow based on if checked or not so we get a freakin checkmark.
1846 shadowType = isChecked ? GTK_SHADOW_IN : GTK_SHADOW_OUT;
1847 NWSetWidgetState( gWidgetData[m_nXScreen].gRadioWidget, nState, stateType );
1848 NWSetWidgetState( gWidgetData[m_nXScreen].gRadioWidgetSibling, nState, stateType );
1850 // GTK enforces radio groups, so that if we don't have 2 buttons in the group,
1851 // the single button will always be active. So we have to have 2 buttons.
1853 // #i59666# set the members directly where we should use
1854 // gtk_toggle_button_set_active. reason: there are animated themes
1855 // which are in active state only after a while leading to painting
1856 // intermediate states between active/inactive. Let's hope that
1857 // GtkToggleButtone stays binary compatible.
1858 if (!isChecked)
1859 GTK_TOGGLE_BUTTON(gWidgetData[m_nXScreen].gRadioWidgetSibling)->active = true;
1860 GTK_TOGGLE_BUTTON(gWidgetData[m_nXScreen].gRadioWidget)->active = isChecked;
1862 for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it )
1864 clipRect.x = it->Left();
1865 clipRect.y = it->Top();
1866 clipRect.width = it->GetWidth();
1867 clipRect.height = it->GetHeight();
1869 gtk_paint_option( gWidgetData[m_nXScreen].gRadioWidget->style, gdkDrawable, stateType, shadowType,
1870 &clipRect, gWidgetData[m_nXScreen].gRadioWidget, "radiobutton",
1871 x, y, indicator_size, indicator_size );
1874 return true;
1877 bool GtkSalGraphics::NWPaintGTKCheck( GdkDrawable* gdkDrawable,
1878 ControlType, ControlPart,
1879 const Rectangle& rControlRectangle,
1880 const clipList& rClipList,
1881 ControlState nState,
1882 const ImplControlValue& aValue,
1883 const OUString& )
1885 GtkStateType stateType;
1886 GtkShadowType shadowType;
1887 bool isChecked = (aValue.getTristateVal() == BUTTONVALUE_ON);
1888 bool isInconsistent = (aValue.getTristateVal() == BUTTONVALUE_MIXED);
1889 GdkRectangle clipRect;
1890 gint x,y;
1892 NWEnsureGTKButton( m_nXScreen );
1893 NWEnsureGTKCheck( m_nXScreen );
1894 NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
1896 gint indicator_size;
1897 gtk_widget_style_get( gWidgetData[m_nXScreen].gCheckWidget, "indicator_size", &indicator_size, (char *)NULL);
1899 x = rControlRectangle.Left() + (rControlRectangle.GetWidth()-indicator_size)/2;
1900 y = rControlRectangle.Top() + (rControlRectangle.GetHeight()-indicator_size)/2;
1902 // Set the shadow based on if checked or not so we get a checkmark.
1903 shadowType = isChecked ? GTK_SHADOW_IN : isInconsistent ? GTK_SHADOW_ETCHED_IN : GTK_SHADOW_OUT;
1904 NWSetWidgetState( gWidgetData[m_nXScreen].gCheckWidget, nState, stateType );
1905 GTK_TOGGLE_BUTTON(gWidgetData[m_nXScreen].gCheckWidget)->active = isChecked;
1907 for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it )
1909 clipRect.x = it->Left();
1910 clipRect.y = it->Top();
1911 clipRect.width = it->GetWidth();
1912 clipRect.height = it->GetHeight();
1914 gtk_paint_check( gWidgetData[m_nXScreen].gCheckWidget->style, gdkDrawable, stateType, shadowType,
1915 &clipRect, gWidgetData[m_nXScreen].gCheckWidget, "checkbutton",
1916 x, y, indicator_size, indicator_size );
1919 return true;
1922 static void NWCalcArrowRect( const Rectangle& rButton, Rectangle& rArrow )
1924 // Size the arrow appropriately
1925 Size aSize( rButton.GetWidth()/2, rButton.GetHeight()/2 );
1926 rArrow.SetSize( aSize );
1928 rArrow.SetPos( Point(
1929 rButton.Left() + ( rButton.GetWidth() - rArrow.GetWidth() ) / 2,
1930 rButton.Top() + ( rButton.GetHeight() - rArrow.GetHeight() ) / 2
1931 ) );
1934 bool GtkSalGraphics::NWPaintGTKScrollbar( ControlType, ControlPart nPart,
1935 const Rectangle& rControlRectangle,
1936 const clipList&,
1937 ControlState nState,
1938 const ImplControlValue& aValue,
1939 const OUString& )
1941 assert(aValue.getType() == CTRL_SCROLLBAR);
1942 const ScrollbarValue& rScrollbarVal = static_cast<const ScrollbarValue&>(aValue);
1943 GdkX11Pixmap* pixmap = NULL;
1944 Rectangle pixmapRect, scrollbarRect;
1945 GtkStateType stateType;
1946 GtkShadowType shadowType;
1947 GtkScrollbar * scrollbarWidget;
1948 GtkStyle * style;
1949 GtkAdjustment* scrollbarValues = NULL;
1950 GtkOrientation scrollbarOrientation;
1951 Rectangle thumbRect = rScrollbarVal.maThumbRect;
1952 Rectangle button11BoundRect = rScrollbarVal.maButton1Rect; // backward
1953 Rectangle button22BoundRect = rScrollbarVal.maButton2Rect; // forward
1954 Rectangle button12BoundRect = rScrollbarVal.maButton1Rect; // secondary forward
1955 Rectangle button21BoundRect = rScrollbarVal.maButton2Rect; // secondary backward
1956 GtkArrowType button1Type; // backward
1957 GtkArrowType button2Type; // forward
1958 gchar * scrollbarTagH = const_cast<gchar *>("hscrollbar");
1959 gchar * scrollbarTagV = const_cast<gchar *>("vscrollbar");
1960 gchar * scrollbarTag = NULL;
1961 Rectangle arrowRect;
1962 gint slider_width = 0;
1963 gint stepper_size = 0;
1964 gint stepper_spacing = 0;
1965 gint trough_border = 0;
1966 gint min_slider_length = 0;
1967 gint vShim = 0;
1968 gint hShim = 0;
1969 gint x,y,w,h;
1971 // make controlvalue rectangles relative to area
1972 thumbRect.Move( -rControlRectangle.Left(), -rControlRectangle.Top() );
1973 button11BoundRect.Move( -rControlRectangle.Left(), -rControlRectangle.Top() );
1974 button22BoundRect.Move( -rControlRectangle.Left(), -rControlRectangle.Top() );
1975 button12BoundRect.Move( -rControlRectangle.Left(), -rControlRectangle.Top() );
1976 button21BoundRect.Move( -rControlRectangle.Left(), -rControlRectangle.Top() );
1978 NWEnsureGTKButton( m_nXScreen );
1979 NWEnsureGTKScrollbars( m_nXScreen );
1980 NWEnsureGTKArrow( m_nXScreen );
1982 // Find the overall bounding rect of the control
1983 pixmapRect = rControlRectangle;
1984 scrollbarRect = pixmapRect;
1986 if ( (scrollbarRect.GetWidth() <= 1) || (scrollbarRect.GetHeight() <= 1) )
1987 return true;
1989 // Grab some button style attributes
1990 gtk_widget_style_get( gWidgetData[m_nXScreen].gScrollHorizWidget,
1991 "slider_width", &slider_width,
1992 "stepper_size", &stepper_size,
1993 "trough_border", &trough_border,
1994 "stepper_spacing", &stepper_spacing,
1995 "min_slider_length", &min_slider_length, (char *)NULL );
1996 gboolean has_forward;
1997 gboolean has_forward2;
1998 gboolean has_backward;
1999 gboolean has_backward2;
2001 gtk_widget_style_get( gWidgetData[m_nXScreen].gScrollHorizWidget, "has-forward-stepper", &has_forward,
2002 "has-secondary-forward-stepper", &has_forward2,
2003 "has-backward-stepper", &has_backward,
2004 "has-secondary-backward-stepper", &has_backward2, (char *)NULL );
2005 gint magic = trough_border ? 1 : 0;
2006 gint nFirst = 0;
2008 if ( has_backward ) nFirst += 1;
2009 if ( has_forward2 ) nFirst += 1;
2011 if ( nPart == PART_DRAW_BACKGROUND_HORZ )
2013 unsigned int sliderHeight = slider_width + (trough_border * 2);
2014 vShim = (pixmapRect.GetHeight() - sliderHeight) / 2;
2015 bool bRTLSwap = button11BoundRect.Left() > button22BoundRect.Left();
2017 scrollbarRect.Move( 0, vShim );
2018 scrollbarRect.SetSize( Size( scrollbarRect.GetWidth(), sliderHeight ) );
2020 scrollbarWidget = GTK_SCROLLBAR( gWidgetData[m_nXScreen].gScrollHorizWidget );
2021 scrollbarOrientation = GTK_ORIENTATION_HORIZONTAL;
2022 scrollbarTag = scrollbarTagH;
2023 button1Type = bRTLSwap? GTK_ARROW_RIGHT: GTK_ARROW_LEFT;
2024 button2Type = bRTLSwap? GTK_ARROW_LEFT: GTK_ARROW_RIGHT;
2026 if ( has_backward )
2028 button12BoundRect.Move( stepper_size - trough_border,
2029 (scrollbarRect.GetHeight() - slider_width) / 2 );
2032 button11BoundRect.Move( trough_border, (scrollbarRect.GetHeight() - slider_width) / 2 );
2033 button11BoundRect.SetSize( Size( stepper_size, slider_width ) );
2034 button12BoundRect.SetSize( Size( stepper_size, slider_width ) );
2036 if ( has_backward2 )
2038 button22BoundRect.Move( stepper_size+(trough_border+1)/2, (scrollbarRect.GetHeight() - slider_width) / 2 );
2039 button21BoundRect.Move( (trough_border+1)/2, (scrollbarRect.GetHeight() - slider_width) / 2 );
2041 else
2043 button22BoundRect.Move( (trough_border+1)/2, (scrollbarRect.GetHeight() - slider_width) / 2 );
2046 button21BoundRect.SetSize( Size( stepper_size, slider_width ) );
2047 button22BoundRect.SetSize( Size( stepper_size, slider_width ) );
2049 thumbRect.Bottom() = thumbRect.Top() + slider_width - 1;
2050 // Make sure the thumb is at least the default width (so we don't get tiny thumbs),
2051 // but if the VCL gives us a size smaller than the theme's default thumb size,
2052 // honor the VCL size
2053 thumbRect.Right() += magic;
2054 // Center vertically in the track
2055 thumbRect.Move( 0, (scrollbarRect.GetHeight() - slider_width) / 2 );
2057 else
2059 unsigned int sliderWidth = slider_width + (trough_border * 2);
2060 hShim = (pixmapRect.GetWidth() - sliderWidth) / 2;
2062 scrollbarRect.Move( hShim, 0 );
2063 scrollbarRect.SetSize( Size( sliderWidth, scrollbarRect.GetHeight() ) );
2065 scrollbarWidget = GTK_SCROLLBAR( gWidgetData[m_nXScreen].gScrollVertWidget );
2066 scrollbarOrientation = GTK_ORIENTATION_VERTICAL;
2067 scrollbarTag = scrollbarTagV;
2068 button1Type = GTK_ARROW_UP;
2069 button2Type = GTK_ARROW_DOWN;
2071 if ( has_backward )
2073 button12BoundRect.Move( (scrollbarRect.GetWidth() - slider_width) / 2,
2074 stepper_size + trough_border );
2076 button11BoundRect.Move( (scrollbarRect.GetWidth() - slider_width) / 2, trough_border );
2077 button11BoundRect.SetSize( Size( slider_width, stepper_size ) );
2078 button12BoundRect.SetSize( Size( slider_width, stepper_size ) );
2080 if ( has_backward2 )
2082 button22BoundRect.Move( (scrollbarRect.GetWidth() - slider_width) / 2, stepper_size+(trough_border+1)/2 );
2083 button21BoundRect.Move( (scrollbarRect.GetWidth() - slider_width) / 2, (trough_border+1)/2 );
2085 else
2087 button22BoundRect.Move( (scrollbarRect.GetWidth() - slider_width) / 2, (trough_border+1)/2 );
2090 button21BoundRect.SetSize( Size( slider_width, stepper_size ) );
2091 button22BoundRect.SetSize( Size( slider_width, stepper_size ) );
2093 thumbRect.Right() = thumbRect.Left() + slider_width - 1;
2095 thumbRect.Bottom() += magic;
2096 // Center horizontally in the track
2097 thumbRect.Move( (scrollbarRect.GetWidth() - slider_width) / 2, 0 );
2100 bool has_slider = ( thumbRect.GetWidth() > 0 && thumbRect.GetHeight() > 0 );
2102 scrollbarValues = gtk_range_get_adjustment( GTK_RANGE(scrollbarWidget) );
2103 if ( scrollbarValues == NULL )
2104 scrollbarValues = GTK_ADJUSTMENT( gtk_adjustment_new(0, 0, 0, 0, 0, 0) );
2105 if ( nPart == PART_DRAW_BACKGROUND_HORZ )
2107 scrollbarValues->lower = rScrollbarVal.mnMin;
2108 scrollbarValues->upper = rScrollbarVal.mnMax;
2109 scrollbarValues->value = rScrollbarVal.mnCur;
2110 scrollbarValues->page_size = scrollbarRect.GetWidth() / 2;
2112 else
2114 scrollbarValues->lower = rScrollbarVal.mnMin;
2115 scrollbarValues->upper = rScrollbarVal.mnMax;
2116 scrollbarValues->value = rScrollbarVal.mnCur;
2117 scrollbarValues->page_size = scrollbarRect.GetHeight() / 2;
2119 gtk_adjustment_changed( scrollbarValues );
2121 // as multiple paints are required for the scrollbar
2122 // painting them directly to the window flickers
2123 pixmap = NWGetPixmapFromScreen( pixmapRect );
2124 if( ! pixmap )
2125 return false;
2126 x = y = 0;
2128 w = pixmapRect.GetWidth();
2129 h = pixmapRect.GetHeight();
2131 GdkDrawable* const &gdkDrawable = pixmap->GetGdkDrawable();
2132 GdkRectangle* gdkRect = NULL;
2134 NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
2135 NWSetWidgetState( GTK_WIDGET(scrollbarWidget), nState, stateType );
2136 NWSetWidgetState( gWidgetData[m_nXScreen].gBtnWidget, nState, stateType );
2137 style = GTK_WIDGET( scrollbarWidget )->style;
2139 gtk_style_apply_default_background( m_pWindow->style, gdkDrawable, TRUE,
2140 GTK_STATE_NORMAL, gdkRect,
2141 x, y, w, h );
2143 // ----------------- TROUGH
2144 // Pass coordinates of draw rect: window(0,0) -> widget(bottom-right) (coords relative to widget)
2145 gtk_paint_flat_box(m_pWindow->style, gdkDrawable,
2146 GTK_STATE_NORMAL, GTK_SHADOW_NONE, gdkRect,
2147 m_pWindow, "base", x-pixmapRect.Left(),y-pixmapRect.Top(),x+pixmapRect.Right(),y+pixmapRect.Bottom());
2149 gtk_paint_box( style, gdkDrawable, GTK_STATE_ACTIVE, GTK_SHADOW_IN,
2150 gdkRect, GTK_WIDGET(scrollbarWidget), "trough",
2151 x, y,
2152 scrollbarRect.GetWidth(), scrollbarRect.GetHeight() );
2154 if ( nState & ControlState::FOCUSED )
2156 gtk_paint_focus( style, gdkDrawable, GTK_STATE_ACTIVE,
2157 gdkRect, GTK_WIDGET(scrollbarWidget), "trough",
2158 x, y,
2159 scrollbarRect.GetWidth(), scrollbarRect.GetHeight() );
2162 // ----------------- THUMB
2163 if ( has_slider )
2165 NWConvertVCLStateToGTKState( rScrollbarVal.mnThumbState, &stateType, &shadowType );
2166 gtk_paint_slider( style, gdkDrawable, stateType, GTK_SHADOW_OUT,
2167 gdkRect, GTK_WIDGET(scrollbarWidget), "slider",
2168 x+hShim+thumbRect.Left(), y+vShim+thumbRect.Top(),
2169 thumbRect.GetWidth(), thumbRect.GetHeight(), scrollbarOrientation );
2172 // Some engines require allocation, e.g. Clearlooks uses it to identify
2173 // positions of the buttons, whereupon the first and the last button will
2174 // have rounded corners.
2175 GTK_WIDGET(scrollbarWidget)->allocation.x = x;
2176 GTK_WIDGET(scrollbarWidget)->allocation.y = y;
2177 GTK_WIDGET(scrollbarWidget)->allocation.width = w;
2178 GTK_WIDGET(scrollbarWidget)->allocation.height = h;
2180 bool backwardButtonInsensitive =
2181 rScrollbarVal.mnCur == rScrollbarVal.mnMin;
2182 bool forwardButtonInsensitive = rScrollbarVal.mnMax == 0 ||
2183 rScrollbarVal.mnCur + rScrollbarVal.mnVisibleSize >= rScrollbarVal.mnMax;
2185 // ----------------- BUTTON 1
2186 if ( has_backward )
2188 NWConvertVCLStateToGTKState( rScrollbarVal.mnButton1State, &stateType, &shadowType );
2189 if ( backwardButtonInsensitive )
2190 stateType = GTK_STATE_INSENSITIVE;
2191 gtk_paint_box( style, gdkDrawable, stateType, shadowType,
2192 gdkRect, GTK_WIDGET(scrollbarWidget), scrollbarTag,
2193 x+hShim+button11BoundRect.Left(), y+vShim+button11BoundRect.Top(),
2194 button11BoundRect.GetWidth(), button11BoundRect.GetHeight() );
2195 // ----------------- ARROW 1
2196 NWCalcArrowRect( button11BoundRect, arrowRect );
2197 gtk_paint_arrow( style, gdkDrawable, stateType, shadowType,
2198 gdkRect, GTK_WIDGET(scrollbarWidget), scrollbarTag, button1Type, true,
2199 x+hShim+arrowRect.Left(), y+vShim+arrowRect.Top(),
2200 arrowRect.GetWidth(), arrowRect.GetHeight() );
2202 if ( has_forward2 )
2204 NWConvertVCLStateToGTKState( rScrollbarVal.mnButton2State, &stateType, &shadowType );
2205 if ( forwardButtonInsensitive )
2206 stateType = GTK_STATE_INSENSITIVE;
2207 gtk_paint_box( style, gdkDrawable, stateType, shadowType,
2208 gdkRect, GTK_WIDGET(scrollbarWidget), scrollbarTag,
2209 x+hShim+button12BoundRect.Left(), y+vShim+button12BoundRect.Top(),
2210 button12BoundRect.GetWidth(), button12BoundRect.GetHeight() );
2211 // ----------------- ARROW 1
2212 NWCalcArrowRect( button12BoundRect, arrowRect );
2213 gtk_paint_arrow( style, gdkDrawable, stateType, shadowType,
2214 gdkRect, GTK_WIDGET(scrollbarWidget), scrollbarTag, button2Type, true,
2215 x+hShim+arrowRect.Left(), y+vShim+arrowRect.Top(),
2216 arrowRect.GetWidth(), arrowRect.GetHeight() );
2218 // ----------------- BUTTON 2
2219 if ( has_backward2 )
2221 NWConvertVCLStateToGTKState( rScrollbarVal.mnButton1State, &stateType, &shadowType );
2222 if ( backwardButtonInsensitive )
2223 stateType = GTK_STATE_INSENSITIVE;
2224 gtk_paint_box( style, gdkDrawable, stateType, shadowType, gdkRect,
2225 GTK_WIDGET(scrollbarWidget), scrollbarTag,
2226 x+hShim+button21BoundRect.Left(), y+vShim+button21BoundRect.Top(),
2227 button21BoundRect.GetWidth(), button21BoundRect.GetHeight() );
2228 // ----------------- ARROW 2
2229 NWCalcArrowRect( button21BoundRect, arrowRect );
2230 gtk_paint_arrow( style, gdkDrawable, stateType, shadowType,
2231 gdkRect, GTK_WIDGET(scrollbarWidget), scrollbarTag, button1Type, true,
2232 x+hShim+arrowRect.Left(), y+vShim+arrowRect.Top(),
2233 arrowRect.GetWidth(), arrowRect.GetHeight() );
2235 if ( has_forward )
2237 NWConvertVCLStateToGTKState( rScrollbarVal.mnButton2State, &stateType, &shadowType );
2238 if ( forwardButtonInsensitive )
2239 stateType = GTK_STATE_INSENSITIVE;
2240 gtk_paint_box( style, gdkDrawable, stateType, shadowType, gdkRect,
2241 GTK_WIDGET(scrollbarWidget), scrollbarTag,
2242 x+hShim+button22BoundRect.Left(), y+vShim+button22BoundRect.Top(),
2243 button22BoundRect.GetWidth(), button22BoundRect.GetHeight() );
2244 // ----------------- ARROW 2
2245 NWCalcArrowRect( button22BoundRect, arrowRect );
2246 gtk_paint_arrow( style, gdkDrawable, stateType, shadowType,
2247 gdkRect, GTK_WIDGET(scrollbarWidget), scrollbarTag, button2Type, true,
2248 x+hShim+arrowRect.Left(), y+vShim+arrowRect.Top(),
2249 arrowRect.GetWidth(), arrowRect.GetHeight() );
2252 bool bRet = NWRenderPixmapToScreen( pixmap, NULL, pixmapRect );
2253 delete pixmap;
2255 return bRet;
2258 static Rectangle NWGetScrollButtonRect( SalX11Screen nScreen, ControlPart nPart, Rectangle aAreaRect )
2260 gint slider_width;
2261 gint stepper_size;
2262 gint stepper_spacing;
2263 gint trough_border;
2265 NWEnsureGTKScrollbars( nScreen );
2267 // Grab some button style attributes
2268 gtk_widget_style_get( gWidgetData[nScreen].gScrollHorizWidget,
2269 "slider-width", &slider_width,
2270 "stepper-size", &stepper_size,
2271 "trough-border", &trough_border,
2272 "stepper-spacing", &stepper_spacing, (char *)NULL );
2274 gboolean has_forward;
2275 gboolean has_forward2;
2276 gboolean has_backward;
2277 gboolean has_backward2;
2279 gtk_widget_style_get( gWidgetData[nScreen].gScrollHorizWidget,
2280 "has-forward-stepper", &has_forward,
2281 "has-secondary-forward-stepper", &has_forward2,
2282 "has-backward-stepper", &has_backward,
2283 "has-secondary-backward-stepper", &has_backward2, (char *)NULL );
2284 gint buttonWidth;
2285 gint buttonHeight;
2286 Rectangle buttonRect;
2288 gint nFirst = 0;
2289 gint nSecond = 0;
2291 if ( has_forward ) nSecond += 1;
2292 if ( has_forward2 ) nFirst += 1;
2293 if ( has_backward ) nFirst += 1;
2294 if ( has_backward2 ) nSecond += 1;
2296 if ( ( nPart == PART_BUTTON_UP ) || ( nPart == PART_BUTTON_DOWN ) )
2298 buttonWidth = slider_width + 2 * trough_border;
2299 buttonHeight = stepper_size + trough_border + stepper_spacing;
2301 else
2303 buttonWidth = stepper_size + trough_border + stepper_spacing;
2304 buttonHeight = slider_width + 2 * trough_border;
2307 if ( nPart == PART_BUTTON_UP )
2309 buttonHeight *= nFirst;
2310 buttonHeight -= 1;
2311 buttonRect.setX( aAreaRect.Left() );
2312 buttonRect.setY( aAreaRect.Top() );
2314 else if ( nPart == PART_BUTTON_LEFT )
2316 buttonWidth *= nFirst;
2317 buttonWidth -= 1;
2318 buttonRect.setX( aAreaRect.Left() );
2319 buttonRect.setY( aAreaRect.Top() );
2321 else if ( nPart == PART_BUTTON_DOWN )
2323 buttonHeight *= nSecond;
2324 buttonRect.setX( aAreaRect.Left() );
2325 buttonRect.setY( aAreaRect.Top() + aAreaRect.GetHeight() - buttonHeight );
2327 else if ( nPart == PART_BUTTON_RIGHT )
2329 buttonWidth *= nSecond;
2330 buttonRect.setX( aAreaRect.Left() + aAreaRect.GetWidth() - buttonWidth );
2331 buttonRect.setY( aAreaRect.Top() );
2334 buttonRect.SetSize( Size( buttonWidth, buttonHeight ) );
2336 return buttonRect;
2339 bool GtkSalGraphics::NWPaintGTKEditBox( GdkDrawable* gdkDrawable,
2340 ControlType nType, ControlPart nPart,
2341 const Rectangle& rControlRectangle,
2342 const clipList& rClipList,
2343 ControlState nState,
2344 const ImplControlValue& aValue,
2345 const OUString& rCaption )
2347 Rectangle pixmapRect;
2348 GdkRectangle clipRect;
2350 // Find the overall bounding rect of the buttons's drawing area,
2351 // plus its actual draw rect excluding adornment
2352 pixmapRect = NWGetEditBoxPixmapRect( m_nXScreen, nType, nPart, rControlRectangle,
2353 nState, aValue, rCaption );
2354 for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it )
2356 clipRect.x = it->Left();
2357 clipRect.y = it->Top();
2358 clipRect.width = it->GetWidth();
2359 clipRect.height = it->GetHeight();
2361 NWPaintOneEditBox( m_nXScreen, gdkDrawable, &clipRect, nType, nPart, pixmapRect, nState, aValue, rCaption );
2364 return true;
2367 /* Take interior/exterior focus into account and return
2368 * the bounding rectangle of the edit box including
2369 * any focus requirements.
2371 static Rectangle NWGetEditBoxPixmapRect(SalX11Screen nScreen,
2372 ControlType,
2373 ControlPart,
2374 Rectangle aAreaRect,
2375 ControlState,
2376 const ImplControlValue&,
2377 const OUString& )
2379 Rectangle pixmapRect = aAreaRect;
2380 gboolean interiorFocus;
2381 gint focusWidth;
2383 NWEnsureGTKEditBox( nScreen );
2385 // Grab some entry style attributes
2386 gtk_widget_style_get( gWidgetData[nScreen].gEditBoxWidget,
2387 "focus-line-width", &focusWidth,
2388 "interior-focus", &interiorFocus, (char *)NULL );
2390 if ( !interiorFocus )
2392 pixmapRect.Move( -(focusWidth), -(focusWidth) );
2393 pixmapRect.SetSize( Size( pixmapRect.GetWidth() + (2*(focusWidth)),
2394 pixmapRect.GetHeight() + (2*(focusWidth)) ) );
2397 return pixmapRect;
2400 /* Paint a GTK Entry widget into the specified GdkPixmap.
2401 * All coordinates should be local to the Pixmap, NOT
2402 * screen/window coordinates.
2404 static void NWPaintOneEditBox( SalX11Screen nScreen,
2405 GdkDrawable * gdkDrawable,
2406 GdkRectangle * gdkRect,
2407 ControlType nType,
2408 ControlPart,
2409 Rectangle aEditBoxRect,
2410 ControlState nState,
2411 const ImplControlValue&,
2412 const OUString& )
2414 GtkStateType stateType;
2415 GtkShadowType shadowType;
2416 GtkWidget *widget;
2418 NWEnsureGTKButton( nScreen );
2419 NWEnsureGTKEditBox( nScreen );
2420 NWEnsureGTKSpinButton( nScreen );
2421 NWEnsureGTKCombo( nScreen );
2422 NWEnsureGTKScrolledWindow( nScreen );
2423 NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
2425 switch ( nType )
2427 case CTRL_SPINBOX:
2428 widget = gWidgetData[nScreen].gSpinButtonWidget;
2429 break;
2431 case CTRL_MULTILINE_EDITBOX:
2432 widget = gWidgetData[nScreen].gScrolledWindowWidget;
2433 break;
2434 case CTRL_COMBOBOX:
2435 widget = GTK_COMBO(gWidgetData[nScreen].gComboWidget)->entry;
2436 break;
2438 default:
2439 widget = gWidgetData[nScreen].gEditBoxWidget;
2440 break;
2443 if ( stateType == GTK_STATE_PRELIGHT )
2444 stateType = GTK_STATE_NORMAL;
2446 NWSetWidgetState( widget, nState, stateType );
2448 gint xborder = widget->style->xthickness;
2449 gint yborder = widget->style->ythickness;
2450 gint bInteriorFocus, nFocusLineWidth;
2451 gtk_widget_style_get( widget,
2452 "interior-focus", &bInteriorFocus,
2453 "focus-line-width", &nFocusLineWidth,
2454 (char *)NULL);
2455 if ( !bInteriorFocus )
2457 xborder += nFocusLineWidth;
2458 yborder += nFocusLineWidth;
2461 gtk_paint_flat_box( widget->style, gdkDrawable, stateType, GTK_SHADOW_NONE,
2462 gdkRect, widget, "entry_bg",
2463 aEditBoxRect.Left() + xborder, aEditBoxRect.Top() + yborder,
2464 aEditBoxRect.GetWidth() - 2*xborder, aEditBoxRect.GetHeight() - 2*yborder );
2465 gtk_paint_shadow( widget->style, gdkDrawable, GTK_STATE_NORMAL, GTK_SHADOW_IN,
2466 gdkRect, widget, "entry",
2467 aEditBoxRect.Left(), aEditBoxRect.Top(),
2468 aEditBoxRect.GetWidth(), aEditBoxRect.GetHeight() );
2472 bool GtkSalGraphics::NWPaintGTKSpinBox( ControlType nType, ControlPart nPart,
2473 const Rectangle& rControlRectangle,
2474 const clipList&,
2475 ControlState nState,
2476 const ImplControlValue& aValue,
2477 const OUString& rCaption )
2479 Rectangle pixmapRect;
2480 GtkStateType stateType;
2481 GtkShadowType shadowType;
2482 const SpinbuttonValue * pSpinVal = (aValue.getType() == CTRL_SPINBUTTONS) ? static_cast<const SpinbuttonValue *>(&aValue) : NULL;
2483 Rectangle upBtnRect;
2484 ControlPart upBtnPart = PART_BUTTON_UP;
2485 ControlState upBtnState = ControlState::ENABLED;
2486 Rectangle downBtnRect;
2487 ControlPart downBtnPart = PART_BUTTON_DOWN;
2488 ControlState downBtnState = ControlState::ENABLED;
2490 NWEnsureGTKButton( m_nXScreen );
2491 NWEnsureGTKSpinButton( m_nXScreen );
2492 NWEnsureGTKArrow( m_nXScreen );
2494 NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
2496 if ( pSpinVal )
2498 upBtnPart = pSpinVal->mnUpperPart;
2499 upBtnState = pSpinVal->mnUpperState;
2501 downBtnPart = pSpinVal->mnLowerPart;
2502 downBtnState = pSpinVal->mnLowerState;
2505 // CTRL_SPINBUTTONS pass their area in pSpinVal, not in rControlRectangle
2506 if ( nType == CTRL_SPINBUTTONS )
2508 if ( !pSpinVal )
2510 std::fprintf( stderr, "Tried to draw CTRL_SPINBUTTONS, but the SpinButtons data structure didn't exist!\n" );
2511 return false;
2513 pixmapRect = pSpinVal->maUpperRect;
2514 pixmapRect.Union( pSpinVal->maLowerRect );
2516 else
2517 pixmapRect = rControlRectangle;
2519 BEGIN_PIXMAP_RENDER( pixmapRect, gdkPixmap )
2521 // First render background
2522 gtk_paint_flat_box(m_pWindow->style,gdkPixmap,GTK_STATE_NORMAL,GTK_SHADOW_NONE,NULL,m_pWindow,"base",
2523 -pixmapRect.Left(),
2524 -pixmapRect.Top(),
2525 pixmapRect.Right(),
2526 pixmapRect.Bottom() );
2528 upBtnRect = NWGetSpinButtonRect( m_nXScreen, nType, upBtnPart, pixmapRect, upBtnState, aValue, rCaption );
2529 downBtnRect = NWGetSpinButtonRect( m_nXScreen, nType, downBtnPart, pixmapRect, downBtnState, aValue, rCaption );
2531 if ( (nType==CTRL_SPINBOX) && (nPart!=PART_ALL_BUTTONS) )
2533 // Draw an edit field for SpinBoxes and ComboBoxes
2534 Rectangle aEditBoxRect( pixmapRect );
2535 aEditBoxRect.SetSize( Size( pixmapRect.GetWidth() - upBtnRect.GetWidth(), aEditBoxRect.GetHeight() ) );
2536 if( AllSettings::GetLayoutRTL() )
2537 aEditBoxRect.setX( upBtnRect.GetWidth() );
2538 else
2539 aEditBoxRect.setX( 0 );
2540 aEditBoxRect.setY( 0 );
2542 NWPaintOneEditBox( m_nXScreen, gdkPixmap, NULL, nType, nPart, aEditBoxRect, nState, aValue, rCaption );
2545 NWSetWidgetState( gWidgetData[m_nXScreen].gSpinButtonWidget, nState, stateType );
2546 gtk_widget_style_get( gWidgetData[m_nXScreen].gSpinButtonWidget, "shadow_type", &shadowType, (char *)NULL );
2548 if ( shadowType != GTK_SHADOW_NONE )
2550 Rectangle shadowRect( upBtnRect );
2552 shadowRect.Union( downBtnRect );
2553 gtk_paint_box( gWidgetData[m_nXScreen].gSpinButtonWidget->style, gdkPixmap, GTK_STATE_NORMAL, shadowType, NULL,
2554 gWidgetData[m_nXScreen].gSpinButtonWidget, "spinbutton",
2555 (shadowRect.Left() - pixmapRect.Left()), (shadowRect.Top() - pixmapRect.Top()),
2556 shadowRect.GetWidth(), shadowRect.GetHeight() );
2559 NWPaintOneSpinButton( m_nXScreen, gdkPixmap, nType, upBtnPart, pixmapRect, upBtnState, aValue, rCaption );
2560 NWPaintOneSpinButton( m_nXScreen, gdkPixmap, nType, downBtnPart, pixmapRect, downBtnState, aValue, rCaption );
2562 END_PIXMAP_RENDER( pixmapRect );
2564 return true;
2567 static Rectangle NWGetSpinButtonRect( SalX11Screen nScreen,
2568 ControlType,
2569 ControlPart nPart,
2570 Rectangle aAreaRect,
2571 ControlState,
2572 const ImplControlValue&,
2573 const OUString& )
2575 gint buttonSize;
2576 Rectangle buttonRect;
2578 NWEnsureGTKSpinButton( nScreen );
2580 buttonSize = MAX( PANGO_PIXELS( pango_font_description_get_size(GTK_WIDGET(gWidgetData[nScreen].gSpinButtonWidget)->style->font_desc) ),
2581 MIN_SPIN_ARROW_WIDTH );
2582 buttonSize -= buttonSize % 2 - 1; /* force odd */
2583 buttonRect.SetSize( Size( buttonSize + 2 * gWidgetData[nScreen].gSpinButtonWidget->style->xthickness,
2584 buttonRect.GetHeight() ) );
2585 if( AllSettings::GetLayoutRTL() )
2586 buttonRect.setX( aAreaRect.Left() );
2587 else
2588 buttonRect.setX( aAreaRect.Left() + (aAreaRect.GetWidth() - buttonRect.GetWidth()) );
2589 if ( nPart == PART_BUTTON_UP )
2591 buttonRect.setY( aAreaRect.Top() );
2592 buttonRect.Bottom() = buttonRect.Top() + (aAreaRect.GetHeight() / 2);
2594 else if( nPart == PART_BUTTON_DOWN )
2596 buttonRect.setY( aAreaRect.Top() + (aAreaRect.GetHeight() / 2) );
2597 buttonRect.Bottom() = aAreaRect.Bottom(); // cover area completely
2599 else
2601 if( AllSettings::GetLayoutRTL() ) {
2602 buttonRect.Left() = buttonRect.Right()+1;
2603 buttonRect.Right() = aAreaRect.Right();
2604 } else {
2605 buttonRect.Right() = buttonRect.Left()-1;
2606 buttonRect.Left() = aAreaRect.Left();
2608 buttonRect.Top() = aAreaRect.Top();
2609 buttonRect.Bottom() = aAreaRect.Bottom();
2612 return buttonRect;
2615 static void NWPaintOneSpinButton( SalX11Screen nScreen,
2616 GdkPixmap* pixmap,
2617 ControlType nType,
2618 ControlPart nPart,
2619 Rectangle aAreaRect,
2620 ControlState nState,
2621 const ImplControlValue& aValue,
2622 const OUString& rCaption )
2624 Rectangle buttonRect;
2625 GtkStateType stateType;
2626 GtkShadowType shadowType;
2627 Rectangle arrowRect;
2628 gint arrowSize;
2630 NWEnsureGTKSpinButton( nScreen );
2631 NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
2633 buttonRect = NWGetSpinButtonRect( nScreen, nType, nPart, aAreaRect, nState, aValue, rCaption );
2635 NWSetWidgetState( gWidgetData[nScreen].gSpinButtonWidget, nState, stateType );
2636 gtk_paint_box( gWidgetData[nScreen].gSpinButtonWidget->style, pixmap, stateType, shadowType, NULL, gWidgetData[nScreen].gSpinButtonWidget,
2637 (nPart == PART_BUTTON_UP) ? "spinbutton_up" : "spinbutton_down",
2638 (buttonRect.Left() - aAreaRect.Left()), (buttonRect.Top() - aAreaRect.Top()),
2639 buttonRect.GetWidth(), buttonRect.GetHeight() );
2641 arrowSize = (buttonRect.GetWidth() - (2 * gWidgetData[nScreen].gSpinButtonWidget->style->xthickness)) - 4;
2642 arrowSize -= arrowSize % 2 - 1; /* force odd */
2643 arrowRect.SetSize( Size( arrowSize, arrowSize ) );
2644 arrowRect.setX( buttonRect.Left() + (buttonRect.GetWidth() - arrowRect.GetWidth()) / 2 );
2645 if ( nPart == PART_BUTTON_UP )
2646 arrowRect.setY( buttonRect.Top() + (buttonRect.GetHeight() - arrowRect.GetHeight()) / 2 + 1);
2647 else
2648 arrowRect.setY( buttonRect.Top() + (buttonRect.GetHeight() - arrowRect.GetHeight()) / 2 - 1);
2650 gtk_paint_arrow( gWidgetData[nScreen].gSpinButtonWidget->style, pixmap, stateType, GTK_SHADOW_OUT, NULL, gWidgetData[nScreen].gSpinButtonWidget,
2651 "spinbutton", (nPart == PART_BUTTON_UP) ? GTK_ARROW_UP : GTK_ARROW_DOWN, true,
2652 (arrowRect.Left() - aAreaRect.Left()), (arrowRect.Top() - aAreaRect.Top()),
2653 arrowRect.GetWidth(), arrowRect.GetHeight() );
2656 bool GtkSalGraphics::NWPaintGTKComboBox( GdkDrawable* gdkDrawable,
2657 ControlType nType, ControlPart nPart,
2658 const Rectangle& rControlRectangle,
2659 const clipList& rClipList,
2660 ControlState nState,
2661 const ImplControlValue& aValue,
2662 const OUString& rCaption )
2664 Rectangle pixmapRect;
2665 Rectangle buttonRect;
2666 GtkStateType stateType;
2667 GtkShadowType shadowType;
2668 Rectangle arrowRect;
2669 gint x,y;
2670 GdkRectangle clipRect;
2672 NWEnsureGTKButton( m_nXScreen );
2673 NWEnsureGTKArrow( m_nXScreen );
2674 NWEnsureGTKCombo( m_nXScreen );
2675 NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
2677 // Find the overall bounding rect of the buttons's drawing area,
2678 // plus its actual draw rect excluding adornment
2679 pixmapRect = rControlRectangle;
2680 x = rControlRectangle.Left();
2681 y = rControlRectangle.Top();
2683 NWSetWidgetState( gWidgetData[m_nXScreen].gBtnWidget, nState, stateType );
2684 NWSetWidgetState( gWidgetData[m_nXScreen].gComboWidget, nState, stateType );
2685 NWSetWidgetState( gWidgetData[m_nXScreen].gArrowWidget, nState, stateType );
2687 buttonRect = NWGetComboBoxButtonRect( m_nXScreen, nType, PART_BUTTON_DOWN, pixmapRect, nState, aValue, rCaption );
2688 if( nPart == PART_BUTTON_DOWN )
2689 buttonRect.Left() += 1;
2691 Rectangle aEditBoxRect( pixmapRect );
2692 aEditBoxRect.SetSize( Size( pixmapRect.GetWidth() - buttonRect.GetWidth(), aEditBoxRect.GetHeight() ) );
2693 if( AllSettings::GetLayoutRTL() )
2694 aEditBoxRect.SetPos( Point( x + buttonRect.GetWidth() , y ) );
2696 #define ARROW_EXTENT 0.7
2697 arrowRect.SetSize( Size( (gint)(MIN_ARROW_SIZE * ARROW_EXTENT),
2698 (gint)(MIN_ARROW_SIZE * ARROW_EXTENT) ) );
2699 arrowRect.SetPos( Point( buttonRect.Left() + (gint)((buttonRect.GetWidth() - arrowRect.GetWidth()) / 2),
2700 buttonRect.Top() + (gint)((buttonRect.GetHeight() - arrowRect.GetHeight()) / 2) ) );
2702 for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it )
2704 clipRect.x = it->Left();
2705 clipRect.y = it->Top();
2706 clipRect.width = it->GetWidth();
2707 clipRect.height = it->GetHeight();
2709 if( nPart == PART_ENTIRE_CONTROL )
2710 NWPaintOneEditBox( m_nXScreen, gdkDrawable, &clipRect, nType, nPart, aEditBoxRect,
2711 nState, aValue, rCaption );
2713 // Buttons must paint opaque since some themes have alpha-channel enabled buttons
2714 gtk_paint_flat_box( m_pWindow->style, gdkDrawable, GTK_STATE_NORMAL, GTK_SHADOW_NONE,
2715 &clipRect, m_pWindow, "base",
2716 x+(buttonRect.Left() - pixmapRect.Left()),
2717 y+(buttonRect.Top() - pixmapRect.Top()),
2718 buttonRect.GetWidth(), buttonRect.GetHeight() );
2719 gtk_paint_box( GTK_COMBO(gWidgetData[m_nXScreen].gComboWidget)->button->style, gdkDrawable, stateType, shadowType,
2720 &clipRect, GTK_COMBO(gWidgetData[m_nXScreen].gComboWidget)->button, "button",
2721 x+(buttonRect.Left() - pixmapRect.Left()),
2722 y+(buttonRect.Top() - pixmapRect.Top()),
2723 buttonRect.GetWidth(), buttonRect.GetHeight() );
2725 gtk_paint_arrow( gWidgetData[m_nXScreen].gArrowWidget->style, gdkDrawable, stateType, shadowType,
2726 &clipRect, gWidgetData[m_nXScreen].gArrowWidget, "arrow", GTK_ARROW_DOWN, true,
2727 x+(arrowRect.Left() - pixmapRect.Left()), y+(arrowRect.Top() - pixmapRect.Top()),
2728 arrowRect.GetWidth(), arrowRect.GetHeight() );
2731 return true;
2734 static Rectangle NWGetComboBoxButtonRect( SalX11Screen nScreen,
2735 ControlType,
2736 ControlPart nPart,
2737 Rectangle aAreaRect,
2738 ControlState,
2739 const ImplControlValue&,
2740 const OUString& )
2742 Rectangle aButtonRect;
2743 gint nArrowWidth;
2744 gint nButtonWidth;
2745 gint nFocusWidth;
2746 gint nFocusPad;
2748 NWEnsureGTKArrow( nScreen );
2750 // Grab some button style attributes
2751 gtk_widget_style_get( gWidgetData[nScreen].gDropdownWidget,
2752 "focus-line-width", &nFocusWidth,
2753 "focus-padding", &nFocusPad, (char *)NULL );
2755 nArrowWidth = MIN_ARROW_SIZE + (GTK_MISC(gWidgetData[nScreen].gArrowWidget)->xpad * 2);
2756 nButtonWidth = nArrowWidth +
2757 ((BTN_CHILD_SPACING + gWidgetData[nScreen].gDropdownWidget->style->xthickness) * 2)
2758 + (2 * (nFocusWidth+nFocusPad));
2759 if( nPart == PART_BUTTON_DOWN )
2761 aButtonRect.SetSize( Size( nButtonWidth, aAreaRect.GetHeight() ) );
2762 if( AllSettings::GetLayoutRTL() )
2763 aButtonRect.SetPos( Point( aAreaRect.Left(), aAreaRect.Top() ) );
2764 else
2765 aButtonRect.SetPos( Point( aAreaRect.Left() + aAreaRect.GetWidth() - nButtonWidth,
2766 aAreaRect.Top() ) );
2768 else if( nPart == PART_SUB_EDIT )
2770 NWEnsureGTKCombo( nScreen );
2772 gint adjust_x = GTK_CONTAINER(gWidgetData[nScreen].gComboWidget)->border_width +
2773 nFocusWidth +
2774 nFocusPad;
2775 gint adjust_y = adjust_x + gWidgetData[nScreen].gComboWidget->style->ythickness;
2776 adjust_x += gWidgetData[nScreen].gComboWidget->style->xthickness;
2777 aButtonRect.SetSize( Size( aAreaRect.GetWidth() - nButtonWidth - 2 * adjust_x,
2778 aAreaRect.GetHeight() - 2 * adjust_y ) );
2779 Point aEditPos = aAreaRect.TopLeft();
2780 aEditPos.X() += adjust_x;
2781 aEditPos.Y() += adjust_y;
2782 if( AllSettings::GetLayoutRTL() )
2783 aEditPos.X() += nButtonWidth;
2784 aButtonRect.SetPos( aEditPos );
2787 return aButtonRect;
2790 bool GtkSalGraphics::NWPaintGTKTabItem( ControlType nType, ControlPart,
2791 const Rectangle& rControlRectangle,
2792 const clipList&,
2793 ControlState nState,
2794 const ImplControlValue& aValue,
2795 const OUString& )
2797 OSL_ASSERT( nType != CTRL_TAB_ITEM || aValue.getType() == CTRL_TAB_ITEM );
2798 GdkX11Pixmap * pixmap;
2799 GdkX11Pixmap * mask;
2800 Rectangle pixmapRect;
2801 Rectangle tabRect;
2802 GtkStateType stateType;
2803 GtkShadowType shadowType;
2804 if( ! gWidgetData[ m_nXScreen ].gCacheTabItems )
2806 gWidgetData[ m_nXScreen ].gCacheTabItems = new NWPixmapCache( m_nXScreen );
2807 gWidgetData[ m_nXScreen ].gCacheTabPages = new NWPixmapCache( m_nXScreen );
2809 NWPixmapCache& aCacheItems = *gWidgetData[ m_nXScreen ].gCacheTabItems;
2810 NWPixmapCache& aCachePage = *gWidgetData[ m_nXScreen ].gCacheTabPages;
2812 if( !aCacheItems.GetSize() )
2813 aCacheItems.SetSize( 20 );
2814 if( !aCachePage.GetSize() )
2815 aCachePage.SetSize( 1 );
2817 if ( (nType == CTRL_TAB_ITEM) && (aValue.getType() != CTRL_TAB_ITEM) )
2819 return false;
2822 NWEnsureGTKButton( m_nXScreen );
2823 NWEnsureGTKNotebook( m_nXScreen );
2824 NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
2826 // Find the overall bounding rect of the buttons's drawing area,
2827 // plus its actual draw rect excluding adornment
2828 pixmapRect = rControlRectangle;
2829 if ( nType == CTRL_TAB_ITEM )
2831 const TabitemValue * pTabitemValue = static_cast<const TabitemValue *>(&aValue);
2832 if ( !pTabitemValue->isFirst() )
2834 // GTK+ tabs overlap on the right edge (the top tab obscures the
2835 // left edge of the tab right "below" it, so adjust the rectangle
2836 // to draw tabs slightly large so the overlap happens
2837 pixmapRect.Move( -2, 0 );
2838 pixmapRect.SetSize( Size( pixmapRect.GetWidth() + 2, pixmapRect.GetHeight() ) );
2840 if ( nState & ControlState::SELECTED )
2842 // In GTK+, the selected tab is 2px taller than all other tabs
2843 pixmapRect.Move( 0, -2 );
2844 pixmapRect.Bottom() += 2;
2845 tabRect = pixmapRect;
2846 // Only draw over 1 pixel of the tab pane that this tab is drawn on top of.
2847 tabRect.Bottom() -= 1;
2849 else
2850 tabRect = pixmapRect;
2852 // Allow the tab to draw a right border if needed
2853 tabRect.Right() -= 1;
2855 // avoid degenerate cases which might lead to crashes
2856 if( tabRect.GetWidth() <= 1 || tabRect.GetHeight() <= 1 )
2857 return false;
2860 if( nType == CTRL_TAB_ITEM )
2862 if( aCacheItems.Find( nType, nState, pixmapRect, &pixmap, &mask ) )
2863 return NWRenderPixmapToScreen( pixmap, mask, pixmapRect );
2865 else
2867 if( aCachePage.Find( nType, nState, pixmapRect, &pixmap, &mask ) )
2868 return NWRenderPixmapToScreen( pixmap, mask, pixmapRect );
2871 GdkRectangle paintRect;
2872 paintRect.x = paintRect.y = 0;
2873 paintRect.width = pixmapRect.GetWidth();
2874 paintRect.height = pixmapRect.GetHeight();
2876 BEGIN_CACHE_PIXMAP_RENDER( pixmapRect, pixmap, mask, gdkPixmap )
2878 gtk_paint_flat_box( m_pWindow->style, gdkPixmap, GTK_STATE_NORMAL,
2879 GTK_SHADOW_NONE, &paintRect, m_pWindow, "base",
2880 -rControlRectangle.Left(),
2881 -rControlRectangle.Top(),
2882 pixmapRect.GetWidth()+rControlRectangle.Left(),
2883 pixmapRect.GetHeight()+rControlRectangle.Top());
2885 NWSetWidgetState( gWidgetData[m_nXScreen].gNotebookWidget, nState, stateType );
2887 switch( nType )
2889 case CTRL_TAB_BODY:
2890 break;
2892 case CTRL_TAB_PANE:
2893 gtk_paint_box_gap( gWidgetData[m_nXScreen].gNotebookWidget->style, gdkPixmap, GTK_STATE_NORMAL, GTK_SHADOW_OUT, NULL, gWidgetData[m_nXScreen].gNotebookWidget,
2894 "notebook", 0, 0, pixmapRect.GetWidth(), pixmapRect.GetHeight(), GTK_POS_TOP, 0, 0 );
2895 break;
2897 case CTRL_TAB_ITEM:
2899 stateType = ( nState & ControlState::SELECTED ) ? GTK_STATE_NORMAL : GTK_STATE_ACTIVE;
2901 // First draw the background
2902 gtk_paint_flat_box(gWidgetData[m_nXScreen].gNotebookWidget->style, gdkPixmap,
2903 GTK_STATE_NORMAL, GTK_SHADOW_NONE, NULL, m_pWindow, "base",
2904 -rControlRectangle.Left(),
2905 -rControlRectangle.Top(),
2906 pixmapRect.GetWidth()+rControlRectangle.Left(),
2907 pixmapRect.GetHeight()+rControlRectangle.Top());
2909 // Now the tab itself
2910 if( nState & ControlState::ROLLOVER )
2911 g_object_set_data(G_OBJECT(gdkPixmap),tabPrelitDataName,reinterpret_cast<gpointer>(TRUE));
2913 gtk_paint_extension( gWidgetData[m_nXScreen].gNotebookWidget->style, gdkPixmap, stateType, GTK_SHADOW_OUT, NULL, gWidgetData[m_nXScreen].gNotebookWidget,
2914 "tab", (tabRect.Left() - pixmapRect.Left()), (tabRect.Top() - pixmapRect.Top()),
2915 tabRect.GetWidth(), tabRect.GetHeight(), GTK_POS_BOTTOM );
2917 g_object_steal_data(G_OBJECT(gdkPixmap),tabPrelitDataName);
2919 if ( nState & ControlState::SELECTED )
2921 gtk_paint_flat_box( m_pWindow->style, gdkPixmap, stateType, GTK_SHADOW_NONE, NULL, m_pWindow,
2922 "base", 0, (pixmapRect.GetHeight() - 1), pixmapRect.GetWidth(), 1 );
2924 break;
2927 default:
2928 break;
2931 END_CACHE_PIXMAP_RENDER( pixmapRect, pixmap, mask )
2933 // tdf#91301 workaround
2935 // After introduction of the Idle processing, something has changed so
2936 // that the underlying GetGdkWindow() does not update its size fast enough;
2937 // even though the gtk_window_resize is called before the Window::Erase()
2938 // (that actually paints the background) etc.
2940 // The consequence of the not-yet-updated gdkDrawable is that we cache
2941 // something that has the correct background in the top left 200x200
2942 // pixels, but the rest is just copied from the screen.
2944 // Let's for now just not cache when the GetGdkWindow() is smaller than
2945 // what we actually paint; TODO find the root cause.
2946 gint width, height;
2947 gdk_drawable_get_size(GetGdkWindow(), &width, &height);
2948 bool bAllowCaching = (pixmapRect.Right() < width) && (pixmapRect.Bottom() < height);
2950 // cache data
2951 if (bAllowCaching)
2953 if (nType == CTRL_TAB_ITEM)
2954 aCacheItems.Fill(nType, nState, pixmapRect, pixmap, mask);
2955 else
2956 aCachePage.Fill(nType, nState, pixmapRect, pixmap, mask);
2959 return true;
2962 bool GtkSalGraphics::NWPaintGTKListBox( GdkDrawable* gdkDrawable,
2963 ControlType nType, ControlPart nPart,
2964 const Rectangle& rControlRectangle,
2965 const clipList& rClipList,
2966 ControlState nState,
2967 const ImplControlValue& aValue,
2968 const OUString& rCaption )
2970 Rectangle aIndicatorRect;
2971 GtkStateType stateType;
2972 GtkShadowType shadowType;
2973 gint bInteriorFocus;
2974 gint nFocusLineWidth;
2975 gint nFocusPadding;
2976 gint x,y,w,h;
2977 GdkRectangle clipRect;
2979 NWEnsureGTKButton( m_nXScreen );
2980 NWEnsureGTKOptionMenu( m_nXScreen );
2981 NWEnsureGTKScrolledWindow( m_nXScreen );
2982 NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
2984 // set up references to correct drawable and cliprect
2985 NWSetWidgetState( gWidgetData[m_nXScreen].gBtnWidget, nState, stateType );
2986 NWSetWidgetState( gWidgetData[m_nXScreen].gOptionMenuWidget, nState, stateType );
2987 NWSetWidgetState( gWidgetData[m_nXScreen].gScrolledWindowWidget, nState, stateType );
2989 x = rControlRectangle.Left();
2990 y = rControlRectangle.Top();
2991 w = rControlRectangle.GetWidth();
2992 h = rControlRectangle.GetHeight();
2994 if ( nPart != PART_WINDOW )
2996 gtk_widget_style_get( gWidgetData[m_nXScreen].gOptionMenuWidget,
2997 "interior_focus", &bInteriorFocus,
2998 "focus_line_width", &nFocusLineWidth,
2999 "focus_padding", &nFocusPadding,
3000 (char *)NULL);
3003 for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it )
3005 clipRect.x = it->Left();
3006 clipRect.y = it->Top();
3007 clipRect.width = it->GetWidth();
3008 clipRect.height = it->GetHeight();
3010 if ( nPart != PART_WINDOW )
3012 // Listboxes must paint opaque since some themes have alpha-channel enabled bodies
3013 gtk_paint_flat_box( m_pWindow->style, gdkDrawable, GTK_STATE_NORMAL, GTK_SHADOW_NONE,
3014 &clipRect, m_pWindow, "base", x, y, w, h);
3015 gtk_paint_box( gWidgetData[m_nXScreen].gOptionMenuWidget->style, gdkDrawable, stateType, shadowType, &clipRect,
3016 gWidgetData[m_nXScreen].gOptionMenuWidget, "optionmenu",
3017 x, y, w, h);
3018 aIndicatorRect = NWGetListBoxIndicatorRect( m_nXScreen, nType, nPart, rControlRectangle, nState,
3019 aValue, rCaption );
3020 gtk_paint_tab( gWidgetData[m_nXScreen].gOptionMenuWidget->style, gdkDrawable, stateType, shadowType, &clipRect,
3021 gWidgetData[m_nXScreen].gOptionMenuWidget, "optionmenutab",
3022 aIndicatorRect.Left(), aIndicatorRect.Top(),
3023 aIndicatorRect.GetWidth(), aIndicatorRect.GetHeight() );
3025 else
3027 shadowType = GTK_SHADOW_IN;
3029 gtk_paint_shadow( gWidgetData[m_nXScreen].gScrolledWindowWidget->style, gdkDrawable, GTK_STATE_NORMAL, shadowType,
3030 &clipRect, gWidgetData[m_nXScreen].gScrolledWindowWidget, "scrolled_window",
3031 x, y, w, h );
3035 return true;
3038 bool GtkSalGraphics::NWPaintGTKToolbar(
3039 GdkDrawable* gdkDrawable,
3040 ControlType, ControlPart nPart,
3041 const Rectangle& rControlRectangle,
3042 const clipList& rClipList,
3043 ControlState nState, const ImplControlValue& aValue,
3044 const OUString& string)
3046 GtkStateType stateType;
3047 GtkShadowType shadowType;
3048 gint x, y, w, h;
3049 gint g_x=0, g_y=0, g_w=10, g_h=10;
3050 GtkWidget* pButtonWidget = gWidgetData[m_nXScreen].gToolbarButtonWidget;
3051 GdkRectangle clipRect;
3053 NWEnsureGTKToolbar( m_nXScreen );
3054 if( nPart == PART_BUTTON ) // toolbar buttons cannot focus in gtk
3055 nState &= ~ControlState::FOCUSED;
3056 NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
3058 x = rControlRectangle.Left();
3059 y = rControlRectangle.Top();
3060 w = rControlRectangle.GetWidth();
3061 h = rControlRectangle.GetHeight();
3063 // handle toolbar
3064 if( nPart == PART_DRAW_BACKGROUND_HORZ || nPart == PART_DRAW_BACKGROUND_VERT )
3066 NWSetWidgetState( gWidgetData[m_nXScreen].gToolbarWidget, nState, stateType );
3068 GTK_WIDGET_UNSET_FLAGS( gWidgetData[m_nXScreen].gToolbarWidget, GTK_SENSITIVE );
3069 if ( nState & ControlState::ENABLED )
3070 GTK_WIDGET_SET_FLAGS( gWidgetData[m_nXScreen].gToolbarWidget, GTK_SENSITIVE );
3072 if( nPart == PART_DRAW_BACKGROUND_HORZ )
3073 gtk_toolbar_set_orientation( GTK_TOOLBAR(gWidgetData[m_nXScreen].gToolbarWidget), GTK_ORIENTATION_HORIZONTAL );
3074 else
3075 gtk_toolbar_set_orientation( GTK_TOOLBAR(gWidgetData[m_nXScreen].gToolbarWidget), GTK_ORIENTATION_VERTICAL );
3077 // handle grip
3078 else if( nPart == PART_THUMB_HORZ || nPart == PART_THUMB_VERT )
3080 NWSetWidgetState( gWidgetData[m_nXScreen].gHandleBoxWidget, nState, stateType );
3082 GTK_WIDGET_UNSET_FLAGS( gWidgetData[m_nXScreen].gHandleBoxWidget, GTK_SENSITIVE );
3083 if ( nState & ControlState::ENABLED )
3084 GTK_WIDGET_SET_FLAGS( gWidgetData[m_nXScreen].gHandleBoxWidget, GTK_SENSITIVE );
3086 gtk_handle_box_set_shadow_type( GTK_HANDLE_BOX(gWidgetData[m_nXScreen].gHandleBoxWidget), shadowType );
3088 // evaluate grip rect
3089 if( aValue.getType() == CTRL_TOOLBAR )
3091 const ToolbarValue* pVal = static_cast<const ToolbarValue*>(&aValue);
3092 g_x = pVal->maGripRect.Left();
3093 g_y = pVal->maGripRect.Top();
3094 g_w = pVal->maGripRect.GetWidth();
3095 g_h = pVal->maGripRect.GetHeight();
3098 // handle button
3099 else if( nPart == PART_BUTTON )
3101 bool bPaintButton = (nState & ControlState::PRESSED)
3102 || (nState & ControlState::ROLLOVER);
3103 if( aValue.getTristateVal() == BUTTONVALUE_ON )
3105 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pButtonWidget),TRUE);
3106 bPaintButton = true;
3108 else
3109 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pButtonWidget),FALSE);
3111 NWSetWidgetState( pButtonWidget, nState, stateType );
3112 gtk_widget_ensure_style( pButtonWidget );
3113 if(bPaintButton)
3114 NWPaintGTKButtonReal(pButtonWidget, gdkDrawable, 0, 0, rControlRectangle, rClipList, nState, aValue, string);
3117 if( nPart != PART_BUTTON )
3119 for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it )
3121 clipRect.x = it->Left();
3122 clipRect.y = it->Top();
3123 clipRect.width = it->GetWidth();
3124 clipRect.height = it->GetHeight();
3126 // draw toolbar
3127 if( nPart == PART_DRAW_BACKGROUND_HORZ || nPart == PART_DRAW_BACKGROUND_VERT )
3129 gtk_paint_flat_box( gWidgetData[m_nXScreen].gToolbarWidget->style,
3130 gdkDrawable,
3131 (GtkStateType)GTK_STATE_NORMAL,
3132 GTK_SHADOW_NONE,
3133 &clipRect,
3134 gWidgetData[m_nXScreen].gToolbarWidget,
3135 "base",
3136 x, y, w, h );
3137 gtk_paint_box( gWidgetData[m_nXScreen].gToolbarWidget->style,
3138 gdkDrawable,
3139 stateType,
3140 shadowType,
3141 &clipRect,
3142 gWidgetData[m_nXScreen].gToolbarWidget,
3143 "toolbar",
3144 x, y, w, h );
3146 // draw grip
3147 else if( nPart == PART_THUMB_HORZ || nPart == PART_THUMB_VERT )
3149 gtk_paint_handle( gWidgetData[m_nXScreen].gHandleBoxWidget->style,
3150 gdkDrawable,
3151 GTK_STATE_NORMAL,
3152 GTK_SHADOW_OUT,
3153 &clipRect,
3154 gWidgetData[m_nXScreen].gHandleBoxWidget,
3155 "handlebox",
3156 g_x, g_y, g_w, g_h,
3157 nPart == PART_THUMB_HORZ ?
3158 GTK_ORIENTATION_HORIZONTAL :
3159 GTK_ORIENTATION_VERTICAL
3162 else if( nPart == PART_SEPARATOR_HORZ || nPart == PART_SEPARATOR_VERT )
3164 const double shim = 0.2;
3166 #if GTK_CHECK_VERSION(2,10,0)
3167 gint separator_height, separator_width, wide_separators = 0;
3169 gtk_widget_style_get (gWidgetData[m_nXScreen].gSeparator,
3170 "wide-separators", &wide_separators,
3171 "separator-width", &separator_width,
3172 "separator-height", &separator_height,
3173 NULL);
3175 if (wide_separators)
3177 if (nPart == PART_SEPARATOR_VERT)
3178 gtk_paint_box (gWidgetData[m_nXScreen].gSeparator->style, gdkDrawable,
3179 GTK_STATE_NORMAL, GTK_SHADOW_ETCHED_OUT,
3180 &clipRect, gWidgetData[m_nXScreen].gSeparator, "vseparator",
3181 x + (w - separator_width) / 2, y + h * shim,
3182 separator_width, h * (1 - 2*shim));
3183 else
3184 gtk_paint_box (gWidgetData[m_nXScreen].gSeparator->style, gdkDrawable,
3185 GTK_STATE_NORMAL, GTK_SHADOW_ETCHED_OUT,
3186 &clipRect, gWidgetData[m_nXScreen].gSeparator, "hseparator",
3187 x + w * shim, y + (h - separator_width) / 2,
3188 w * (1 - 2*shim), separator_width);
3190 else
3191 #endif
3193 if (nPart == PART_SEPARATOR_VERT)
3194 gtk_paint_vline (gWidgetData[m_nXScreen].gSeparator->style, gdkDrawable,
3195 GTK_STATE_NORMAL,
3196 &clipRect, gWidgetData[m_nXScreen].gSeparator, "vseparator",
3197 y + h * shim, y + h * (1 - shim), x + w/2 - 1);
3198 else
3199 gtk_paint_hline (gWidgetData[m_nXScreen].gSeparator->style, gdkDrawable,
3200 GTK_STATE_NORMAL,
3201 &clipRect, gWidgetData[m_nXScreen].gSeparator, "hseparator",
3202 x + w * shim, x + w * (1 - shim), y + h/2 - 1);
3208 return true;
3211 /// Converts a VCL Rectangle to a GdkRectangle.
3212 static void lcl_rectangleToGdkRectangle(const Rectangle& rRectangle, GdkRectangle& rGdkRectangle)
3214 rGdkRectangle.x = rRectangle.Left();
3215 rGdkRectangle.y = rRectangle.Top();
3216 rGdkRectangle.width = rRectangle.GetWidth();
3217 rGdkRectangle.height = rRectangle.GetHeight();
3220 bool GtkSalGraphics::NWPaintGTKMenubar(
3221 GdkDrawable* gdkDrawable,
3222 ControlType, ControlPart nPart,
3223 const Rectangle& rControlRectangle,
3224 const clipList& rClipList,
3225 ControlState nState, const ImplControlValue&,
3226 const OUString& )
3228 GtkStateType stateType;
3229 GtkShadowType shadowType;
3230 GtkShadowType selected_shadow_type = GTK_SHADOW_OUT;
3231 gint x, y, w, h;
3232 GdkRectangle clipRect;
3234 NWEnsureGTKMenubar( m_nXScreen );
3235 NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
3237 x = rControlRectangle.Left();
3238 y = rControlRectangle.Top();
3239 w = rControlRectangle.GetWidth();
3240 h = rControlRectangle.GetHeight();
3242 if( nPart == PART_MENU_ITEM )
3244 if( nState & ControlState::SELECTED )
3246 gtk_widget_style_get( gWidgetData[m_nXScreen].gMenuItemMenubarWidget,
3247 "selected_shadow_type", &selected_shadow_type,
3248 (char *)NULL);
3252 for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it )
3254 lcl_rectangleToGdkRectangle(*it, clipRect);
3256 // handle Menubar
3257 if( nPart == PART_ENTIRE_CONTROL )
3259 NWSetWidgetState( gWidgetData[m_nXScreen].gMenubarWidget, nState, stateType );
3261 GTK_WIDGET_UNSET_FLAGS( gWidgetData[m_nXScreen].gMenubarWidget, GTK_SENSITIVE );
3262 if ( nState & ControlState::ENABLED )
3263 GTK_WIDGET_SET_FLAGS( gWidgetData[m_nXScreen].gMenubarWidget, GTK_SENSITIVE );
3265 // for translucent menubar styles paint background first
3266 gtk_paint_flat_box( gWidgetData[m_nXScreen].gMenubarWidget->style,
3267 gdkDrawable,
3268 GTK_STATE_NORMAL,
3269 GTK_SHADOW_NONE,
3270 &clipRect,
3271 GTK_WIDGET(m_pWindow),
3272 "base",
3273 x, y, w, h );
3275 // Do the conversion again, in case clipRect has been modified.
3276 lcl_rectangleToGdkRectangle(*it, clipRect);
3278 gtk_paint_box( gWidgetData[m_nXScreen].gMenubarWidget->style,
3279 gdkDrawable,
3280 stateType,
3281 shadowType,
3282 &clipRect,
3283 gWidgetData[m_nXScreen].gMenubarWidget,
3284 "menubar",
3285 x, y, w, h );
3288 else if( nPart == PART_MENU_ITEM )
3290 if( nState & ControlState::SELECTED )
3292 gtk_paint_box( gWidgetData[m_nXScreen].gMenuItemMenubarWidget->style,
3293 gdkDrawable,
3294 GTK_STATE_PRELIGHT,
3295 selected_shadow_type,
3296 &clipRect,
3297 gWidgetData[m_nXScreen].gMenuItemMenubarWidget,
3298 "menuitem",
3299 x, y, w, h);
3304 return true;
3307 bool GtkSalGraphics::NWPaintGTKPopupMenu(
3308 GdkDrawable* gdkDrawable,
3309 ControlType, ControlPart nPart,
3310 const Rectangle& rControlRectangle,
3311 const clipList& rClipList,
3312 ControlState nState, const ImplControlValue&,
3313 const OUString& )
3315 // #i50745# gtk does not draw disabled menu entries (and crux theme
3316 // even crashes) in very old (Fedora Core 4 vintage) gtk's
3317 if (gtk_major_version <= 2 && gtk_minor_version <= 8 &&
3318 nPart == PART_MENU_ITEM && ! (nState & ControlState::ENABLED) )
3319 return true;
3321 GtkStateType stateType;
3322 GtkShadowType shadowType;
3323 GtkShadowType selected_shadow_type = GTK_SHADOW_OUT;
3324 gint x, y, w, h;
3325 GdkRectangle clipRect;
3327 NWEnsureGTKMenu( m_nXScreen );
3328 NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
3330 x = rControlRectangle.Left();
3331 y = rControlRectangle.Top();
3332 w = rControlRectangle.GetWidth();
3333 h = rControlRectangle.GetHeight();
3335 if( nPart == PART_MENU_ITEM &&
3336 ( nState & (ControlState::SELECTED|ControlState::ROLLOVER) ) )
3338 gtk_widget_style_get( gWidgetData[m_nXScreen].gMenuItemMenuWidget,
3339 "selected_shadow_type", &selected_shadow_type,
3340 (char *)NULL);
3343 NWSetWidgetState( gWidgetData[m_nXScreen].gMenuWidget, nState, stateType );
3345 GTK_WIDGET_UNSET_FLAGS( gWidgetData[m_nXScreen].gMenuWidget, GTK_SENSITIVE );
3346 if ( nState & ControlState::ENABLED )
3347 GTK_WIDGET_SET_FLAGS( gWidgetData[m_nXScreen].gMenuWidget, GTK_SENSITIVE );
3349 for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it )
3351 clipRect.x = it->Left();
3352 clipRect.y = it->Top();
3353 clipRect.width = it->GetWidth();
3354 clipRect.height = it->GetHeight();
3356 if( nPart == PART_ENTIRE_CONTROL )
3358 // for translucent menubar styles paint background first
3359 gtk_paint_flat_box( gWidgetData[m_nXScreen].gMenuWidget->style,
3360 gdkDrawable,
3361 GTK_STATE_NORMAL,
3362 GTK_SHADOW_NONE,
3363 &clipRect,
3364 GTK_WIDGET(m_pWindow),
3365 "base",
3366 x, y, w, h );
3367 gtk_paint_box( gWidgetData[m_nXScreen].gMenuWidget->style,
3368 gdkDrawable,
3369 GTK_STATE_NORMAL,
3370 GTK_SHADOW_OUT,
3371 &clipRect,
3372 gWidgetData[m_nXScreen].gMenuWidget,
3373 "menu",
3374 x, y, w, h );
3376 else if( nPart == PART_MENU_ITEM )
3378 if( nState & (ControlState::SELECTED|ControlState::ROLLOVER) )
3380 if( nState & ControlState::ENABLED )
3381 gtk_paint_box( gWidgetData[m_nXScreen].gMenuItemMenuWidget->style,
3382 gdkDrawable,
3383 GTK_STATE_PRELIGHT,
3384 selected_shadow_type,
3385 &clipRect,
3386 gWidgetData[m_nXScreen].gMenuItemMenuWidget,
3387 "menuitem",
3388 x, y, w, h);
3391 else if( nPart == PART_MENU_ITEM_CHECK_MARK || nPart == PART_MENU_ITEM_RADIO_MARK )
3393 GtkWidget* pWidget = (nPart == PART_MENU_ITEM_CHECK_MARK) ?
3394 gWidgetData[m_nXScreen].gMenuItemCheckMenuWidget :
3395 gWidgetData[m_nXScreen].gMenuItemRadioMenuWidget;
3397 GtkStateType nStateType;
3398 GtkShadowType nShadowType;
3399 NWConvertVCLStateToGTKState( nState, &nStateType, &nShadowType );
3401 if ( (nState & ControlState::SELECTED) && (nState & ControlState::ENABLED) )
3402 nStateType = GTK_STATE_PRELIGHT;
3404 NWSetWidgetState( pWidget, nState, nStateType );
3406 if ( nPart == PART_MENU_ITEM_CHECK_MARK )
3408 gtk_paint_check( pWidget->style,
3409 gdkDrawable,
3410 nStateType,
3411 nShadowType,
3412 &clipRect,
3413 gWidgetData[m_nXScreen].gMenuItemMenuWidget,
3414 "check",
3415 x, y, w, h );
3417 else
3419 gtk_paint_option( pWidget->style,
3420 gdkDrawable,
3421 nStateType,
3422 nShadowType,
3423 &clipRect,
3424 gWidgetData[m_nXScreen].gMenuItemMenuWidget,
3425 "option",
3426 x, y, w, h );
3429 else if( nPart == PART_MENU_SEPARATOR )
3431 gtk_paint_hline( gWidgetData[m_nXScreen].gMenuItemSeparatorMenuWidget->style,
3432 gdkDrawable,
3433 GTK_STATE_NORMAL,
3434 &clipRect,
3435 gWidgetData[m_nXScreen].gMenuItemSeparatorMenuWidget,
3436 "menuitem",
3437 x, x + w, y + h / 2);
3439 else if( nPart == PART_MENU_SUBMENU_ARROW )
3441 GtkStateType nStateType;
3442 GtkShadowType nShadowType;
3443 NWConvertVCLStateToGTKState( nState, &nStateType, &nShadowType );
3445 if ( (nState & ControlState::SELECTED) && (nState & ControlState::ENABLED) )
3446 nStateType = GTK_STATE_PRELIGHT;
3448 NWSetWidgetState( gWidgetData[m_nXScreen].gMenuItemMenuWidget,
3449 nState, nStateType );
3451 GtkArrowType eArrow;
3452 if( AllSettings::GetLayoutRTL() )
3453 eArrow = GTK_ARROW_LEFT;
3454 else
3455 eArrow = GTK_ARROW_RIGHT;
3457 gtk_paint_arrow( gWidgetData[m_nXScreen].gMenuItemMenuWidget->style,
3458 gdkDrawable,
3459 nStateType,
3460 nShadowType,
3461 &clipRect,
3462 gWidgetData[m_nXScreen].gMenuItemMenuWidget,
3463 "menuitem",
3464 eArrow, TRUE,
3465 x, y, w, h);
3469 return true;
3472 bool GtkSalGraphics::NWPaintGTKTooltip(
3473 GdkDrawable* gdkDrawable,
3474 ControlType, ControlPart,
3475 const Rectangle& rControlRectangle,
3476 const clipList& rClipList,
3477 ControlState, const ImplControlValue&,
3478 const OUString& )
3480 NWEnsureGTKTooltip( m_nXScreen );
3482 gint x, y, w, h;
3483 GdkRectangle clipRect;
3485 x = rControlRectangle.Left();
3486 y = rControlRectangle.Top();
3487 w = rControlRectangle.GetWidth();
3488 h = rControlRectangle.GetHeight();
3490 for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it )
3492 clipRect.x = it->Left();
3493 clipRect.y = it->Top();
3494 clipRect.width = it->GetWidth();
3495 clipRect.height = it->GetHeight();
3497 gtk_paint_flat_box( gWidgetData[m_nXScreen].gTooltipPopup->style,
3498 gdkDrawable,
3499 GTK_STATE_NORMAL,
3500 GTK_SHADOW_OUT,
3501 &clipRect,
3502 gWidgetData[m_nXScreen].gTooltipPopup,
3503 "tooltip",
3504 x, y, w, h );
3507 return true;
3510 bool GtkSalGraphics::NWPaintGTKListNode(
3511 GdkDrawable*,
3512 ControlType, ControlPart,
3513 const Rectangle& rControlRectangle,
3514 const clipList&,
3515 ControlState nState, const ImplControlValue& rValue,
3516 const OUString& )
3518 NWEnsureGTKTreeView( m_nXScreen );
3520 Rectangle aRect( rControlRectangle );
3521 aRect.Left() -= 2;
3522 aRect.Right() += 2;
3523 aRect.Top() -= 2;
3524 aRect.Bottom() += 2;
3525 gint w, h;
3526 w = aRect.GetWidth();
3527 h = aRect.GetHeight();
3529 GtkStateType stateType;
3530 GtkShadowType shadowType;
3531 NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
3533 ButtonValue aButtonValue = rValue.getTristateVal();
3534 GtkExpanderStyle eStyle = GTK_EXPANDER_EXPANDED;
3536 switch( aButtonValue )
3538 case BUTTONVALUE_ON: eStyle = GTK_EXPANDER_EXPANDED;break;
3539 case BUTTONVALUE_OFF: eStyle = GTK_EXPANDER_COLLAPSED; break;
3540 default:
3541 break;
3544 BEGIN_PIXMAP_RENDER( aRect, pixDrawable )
3546 gtk_paint_expander( gWidgetData[m_nXScreen].gTreeView->style,
3547 pixDrawable,
3548 stateType,
3549 NULL,
3550 gWidgetData[m_nXScreen].gTreeView,
3551 "treeview",
3552 w/2, h/2,
3553 eStyle );
3555 END_PIXMAP_RENDER( aRect )
3557 return true;
3560 bool GtkSalGraphics::NWPaintGTKProgress(
3561 GdkDrawable*,
3562 ControlType, ControlPart,
3563 const Rectangle& rControlRectangle,
3564 const clipList&,
3565 ControlState, const ImplControlValue& rValue,
3566 const OUString& )
3568 NWEnsureGTKProgressBar( m_nXScreen );
3570 gint w, h;
3571 w = rControlRectangle.GetWidth();
3572 h = rControlRectangle.GetHeight();
3573 Rectangle aRect( Point( 0, 0 ), Size( w, h ) );
3575 long nProgressWidth = rValue.getNumericVal();
3577 BEGIN_PIXMAP_RENDER( aRect, pixDrawable )
3579 // paint background
3580 gtk_paint_flat_box(gWidgetData[m_nXScreen].gProgressBar->style, pixDrawable,
3581 GTK_STATE_NORMAL, GTK_SHADOW_NONE, NULL, m_pWindow, "base",
3582 -rControlRectangle.Left(),-rControlRectangle.Top(),
3583 rControlRectangle.Left()+w,rControlRectangle.Top()+h);
3585 gtk_paint_flat_box( gWidgetData[m_nXScreen].gProgressBar->style,
3586 pixDrawable,
3587 GTK_STATE_NORMAL,
3588 GTK_SHADOW_NONE,
3589 NULL,
3590 gWidgetData[m_nXScreen].gProgressBar,
3591 "trough",
3592 0, 0, w, h );
3593 if( nProgressWidth > 0 )
3595 // paint progress
3596 if( AllSettings::GetLayoutRTL() )
3598 gtk_paint_box( gWidgetData[m_nXScreen].gProgressBar->style,
3599 pixDrawable,
3600 GTK_STATE_PRELIGHT, GTK_SHADOW_OUT,
3601 NULL,
3602 gWidgetData[m_nXScreen].gProgressBar,
3603 "bar",
3604 w-nProgressWidth, 0, nProgressWidth, h
3607 else
3609 gtk_paint_box( gWidgetData[m_nXScreen].gProgressBar->style,
3610 pixDrawable,
3611 GTK_STATE_PRELIGHT, GTK_SHADOW_OUT,
3612 NULL,
3613 gWidgetData[m_nXScreen].gProgressBar,
3614 "bar",
3615 0, 0, nProgressWidth, h
3620 END_PIXMAP_RENDER( rControlRectangle )
3622 return true;
3625 bool GtkSalGraphics::NWPaintGTKSlider(
3626 GdkDrawable*,
3627 ControlType, ControlPart nPart,
3628 const Rectangle& rControlRectangle,
3629 const clipList&,
3630 ControlState nState, const ImplControlValue& rValue,
3631 const OUString& )
3633 OSL_ASSERT( rValue.getType() == CTRL_SLIDER );
3634 NWEnsureGTKSlider( m_nXScreen );
3636 gint w, h;
3637 w = rControlRectangle.GetWidth();
3638 h = rControlRectangle.GetHeight();
3640 const SliderValue* pVal = static_cast<const SliderValue*>(&rValue);
3642 BEGIN_PIXMAP_RENDER( rControlRectangle, pixDrawable )
3644 GtkWidget* pWidget = (nPart == PART_TRACK_HORZ_AREA)
3645 ? GTK_WIDGET(gWidgetData[m_nXScreen].gHScale)
3646 : GTK_WIDGET(gWidgetData[m_nXScreen].gVScale);
3647 const gchar* pDetail = (nPart == PART_TRACK_HORZ_AREA) ? "hscale" : "vscale";
3648 GtkOrientation eOri = (nPart == PART_TRACK_HORZ_AREA) ? GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL;
3649 gint slider_width = 10;
3650 gint slider_length = 10;
3651 gint trough_border = 0;
3652 gtk_widget_style_get( pWidget,
3653 "slider-width", &slider_width,
3654 "slider-length", &slider_length,
3655 "trough-border", &trough_border,
3656 NULL);
3658 GtkStateType eState = (nState & ControlState::ENABLED) ? GTK_STATE_NORMAL : GTK_STATE_INSENSITIVE;
3659 if( nPart == PART_TRACK_HORZ_AREA )
3661 gtk_paint_box( pWidget->style,
3662 pixDrawable,
3663 eState,
3664 GTK_SHADOW_IN,
3665 NULL,
3666 pWidget,
3667 "trough",
3668 0, (h-slider_width-2*trough_border)/2, w, slider_width + 2*trough_border);
3669 gint x = (w - slider_length + 1) * (pVal->mnCur - pVal->mnMin) / (pVal->mnMax - pVal->mnMin);
3670 gtk_paint_slider( pWidget->style,
3671 pixDrawable,
3672 eState,
3673 GTK_SHADOW_OUT,
3674 NULL,
3675 pWidget,
3676 pDetail,
3677 x, (h-slider_width)/2,
3678 slider_length, slider_width,
3679 eOri );
3681 else
3683 gtk_paint_box( pWidget->style,
3684 pixDrawable,
3685 eState,
3686 GTK_SHADOW_IN,
3687 NULL,
3688 pWidget,
3689 "trough",
3690 (w-slider_width-2*trough_border)/2, 0, slider_width + 2*trough_border, h);
3691 gint y = (h - slider_length + 1) * (pVal->mnCur - pVal->mnMin) / (pVal->mnMax - pVal->mnMin);
3692 gtk_paint_slider( pWidget->style,
3693 pixDrawable,
3694 eState,
3695 GTK_SHADOW_OUT,
3696 NULL,
3697 pWidget,
3698 pDetail,
3699 (w-slider_width)/2, y,
3700 slider_width, slider_length,
3701 eOri );
3704 END_PIXMAP_RENDER( rControlRectangle )
3706 return true;
3709 static int getFrameWidth(GtkWidget* widget)
3711 return widget->style->xthickness;
3714 static Rectangle NWGetListBoxButtonRect( SalX11Screen nScreen,
3715 ControlType,
3716 ControlPart nPart,
3717 Rectangle aAreaRect,
3718 ControlState,
3719 const ImplControlValue&,
3720 const OUString& )
3722 Rectangle aPartRect;
3723 GtkRequisition *pIndicatorSize = NULL;
3724 GtkBorder *pIndicatorSpacing = NULL;
3725 gint width = 13; // GTK+ default
3726 gint right = 5; // GTK+ default
3727 gint nButtonAreaWidth = 0;
3728 gint xthickness = 0;
3730 NWEnsureGTKOptionMenu( nScreen );
3732 gtk_widget_style_get( gWidgetData[nScreen].gOptionMenuWidget,
3733 "indicator_size", &pIndicatorSize,
3734 "indicator_spacing",&pIndicatorSpacing, (char *)NULL);
3736 if ( pIndicatorSize )
3737 width = pIndicatorSize->width;
3739 if ( pIndicatorSpacing )
3740 right = pIndicatorSpacing->right;
3742 Size aPartSize( 0, aAreaRect.GetHeight() );
3743 Point aPartPos ( 0, aAreaRect.Top() );
3745 xthickness = gWidgetData[nScreen].gOptionMenuWidget->style->xthickness;
3746 nButtonAreaWidth = width + right + (xthickness * 2);
3747 switch( nPart )
3749 case PART_BUTTON_DOWN:
3750 aPartSize.Width() = nButtonAreaWidth;
3751 aPartPos.X() = aAreaRect.Left() + aAreaRect.GetWidth() - aPartSize.Width();
3752 break;
3754 case PART_SUB_EDIT:
3755 aPartSize.Width() = aAreaRect.GetWidth() - nButtonAreaWidth - xthickness;
3756 if( AllSettings::GetLayoutRTL() )
3757 aPartPos.X() = aAreaRect.Left() + nButtonAreaWidth;
3758 else
3759 aPartPos.X() = aAreaRect.Left() + xthickness;
3760 break;
3762 default:
3763 aPartSize.Width() = aAreaRect.GetWidth();
3764 aPartPos.X() = aAreaRect.Left();
3765 break;
3767 aPartRect = Rectangle( aPartPos, aPartSize );
3769 if ( pIndicatorSize )
3770 gtk_requisition_free( pIndicatorSize );
3771 if ( pIndicatorSpacing )
3772 gtk_border_free( pIndicatorSpacing );
3774 return aPartRect;
3777 static Rectangle NWGetListBoxIndicatorRect( SalX11Screen nScreen,
3778 ControlType,
3779 ControlPart,
3780 Rectangle aAreaRect,
3781 ControlState,
3782 const ImplControlValue&,
3783 const OUString& )
3785 Rectangle aIndicatorRect;
3786 GtkRequisition *pIndicatorSize = NULL;
3787 GtkBorder *pIndicatorSpacing = NULL;
3788 gint width = 13; // GTK+ default
3789 gint height = 13; // GTK+ default
3790 gint right = 5; // GTK+ default
3791 gint x;
3793 NWEnsureGTKOptionMenu( nScreen );
3795 gtk_widget_style_get( gWidgetData[nScreen].gOptionMenuWidget,
3796 "indicator_size", &pIndicatorSize,
3797 "indicator_spacing",&pIndicatorSpacing, (char *)NULL);
3799 if ( pIndicatorSize )
3801 width = pIndicatorSize->width;
3802 height = pIndicatorSize->height;
3805 if ( pIndicatorSpacing )
3806 right = pIndicatorSpacing->right;
3808 aIndicatorRect.SetSize( Size( width, height ) );
3809 if( AllSettings::GetLayoutRTL() )
3810 x = aAreaRect.Left() + right;
3811 else
3812 x = aAreaRect.Left() + aAreaRect.GetWidth() - width - right - gWidgetData[nScreen].gOptionMenuWidget->style->xthickness;
3813 aIndicatorRect.SetPos( Point( x, aAreaRect.Top() + ((aAreaRect.GetHeight() - height) / 2) ) );
3815 // If height is odd, move the indicator down 1 pixel
3816 if ( aIndicatorRect.GetHeight() % 2 )
3817 aIndicatorRect.Move( 0, 1 );
3819 if ( pIndicatorSize )
3820 gtk_requisition_free( pIndicatorSize );
3821 if ( pIndicatorSpacing )
3822 gtk_border_free( pIndicatorSpacing );
3824 return aIndicatorRect;
3827 static Rectangle NWGetToolbarRect( SalX11Screen nScreen,
3828 ControlType,
3829 ControlPart nPart,
3830 Rectangle aAreaRect,
3831 ControlState,
3832 const ImplControlValue&,
3833 const OUString& )
3835 Rectangle aRet;
3837 if( nPart == PART_DRAW_BACKGROUND_HORZ ||
3838 nPart == PART_DRAW_BACKGROUND_VERT )
3839 aRet = aAreaRect;
3840 else if( nPart == PART_THUMB_HORZ )
3841 aRet = Rectangle( Point( 0, 0 ), Size( aAreaRect.GetWidth(), 10 ) );
3842 else if( nPart == PART_THUMB_VERT )
3843 aRet = Rectangle( Point( 0, 0 ), Size( 10, aAreaRect.GetHeight() ) );
3844 else if( nPart == PART_BUTTON )
3846 aRet = aAreaRect;
3848 NWEnsureGTKToolbar( nScreen );
3850 gint nMinWidth =
3851 2*gWidgetData[nScreen].gToolbarButtonWidget->style->xthickness
3852 + 1 // CHILD_SPACING constant, found in gtk_button.c
3853 + 3*gWidgetData[nScreen].gToolbarButtonWidget->style->xthickness; // Murphy factor
3854 gint nMinHeight =
3855 2*gWidgetData[nScreen].gToolbarButtonWidget->style->ythickness
3856 + 1 // CHILD_SPACING constant, found in gtk_button.c
3857 + 3*gWidgetData[nScreen].gToolbarButtonWidget->style->ythickness; // Murphy factor
3859 gtk_widget_ensure_style( gWidgetData[nScreen].gToolbarButtonWidget );
3860 if( aAreaRect.GetWidth() < nMinWidth )
3861 aRet.Right() = aRet.Left() + nMinWidth;
3862 if( aAreaRect.GetHeight() < nMinHeight )
3863 aRet.Bottom() = aRet.Top() + nMinHeight;
3866 return aRet;
3869 /************************************************************************
3870 * helper for GtkSalFrame
3871 ************************************************************************/
3872 static inline Color getColor( const GdkColor& rCol )
3874 return Color( rCol.red >> 8, rCol.green >> 8, rCol.blue >> 8 );
3877 #if OSL_DEBUG_LEVEL > 1
3879 void printColor( const char* name, const GdkColor& rCol )
3881 std::fprintf( stderr, " %s = 0x%2x 0x%2x 0x%2x\n",
3882 name,
3883 rCol.red >> 8, rCol.green >> 8, rCol.blue >> 8 );
3886 void printStyleColors( GtkStyle* pStyle )
3888 static const char* pStates[] = { "NORMAL", "ACTIVE", "PRELIGHT", "SELECTED", "INSENSITIVE" };
3890 for( int i = 0; i < 5; i++ )
3892 std::fprintf( stderr, "state %s colors:\n", pStates[i] );
3893 printColor( "bg ", pStyle->bg[i] );
3894 printColor( "fg ", pStyle->fg[i] );
3895 printColor( "light ", pStyle->light[i] );
3896 printColor( "dark ", pStyle->dark[i] );
3897 printColor( "mid ", pStyle->mid[i] );
3898 printColor( "text ", pStyle->text[i] );
3899 printColor( "base ", pStyle->base[i] );
3900 printColor( "text_aa", pStyle->text_aa[i] );
3903 #endif
3905 void GtkSalGraphics::signalSettingsNotify( GObject *pSettings, GParamSpec *pSpec, gpointer )
3907 g_return_if_fail( pSpec != NULL );
3909 if( !strcmp( pSpec->name, "gtk-fontconfig-timestamp" ) )
3910 GtkSalGraphics::refreshFontconfig( GTK_SETTINGS( pSettings ) );
3913 void GtkSalGraphics::refreshFontconfig( GtkSettings *pSettings )
3915 guint latest_fontconfig_timestamp = 0;
3916 static guint our_fontconfig_timestamp = 0;
3917 g_object_get( pSettings, "gtk-fontconfig-timestamp", &latest_fontconfig_timestamp, (char *)NULL );
3918 if (latest_fontconfig_timestamp != our_fontconfig_timestamp)
3920 bool bFirstTime = our_fontconfig_timestamp == 0;
3921 our_fontconfig_timestamp = latest_fontconfig_timestamp;
3922 if (!bFirstTime)
3924 psp::PrintFontManager::get().initialize();
3929 void GtkSalGraphics::updateSettings( AllSettings& rSettings )
3931 GdkScreen* pScreen = gtk_widget_get_screen( m_pWindow );
3932 gtk_widget_ensure_style( m_pWindow );
3933 GtkStyle* pStyle = gtk_widget_get_style( m_pWindow );
3934 GtkSettings* pSettings = gtk_widget_get_settings( m_pWindow );
3935 StyleSettings aStyleSet = rSettings.GetStyleSettings();
3937 // Listen for font changes
3938 if( !g_object_get_data( G_OBJECT( pSettings ), "libo:listening" ) )
3940 g_object_set_data( G_OBJECT( pSettings ), "libo:listening",
3941 GUINT_TO_POINTER( 1 ) );
3942 g_signal_connect_data( G_OBJECT( pSettings ), "notify",
3943 G_CALLBACK( signalSettingsNotify ),
3944 NULL, NULL, G_CONNECT_AFTER );
3947 refreshFontconfig( pSettings );
3949 // get the widgets in place
3950 NWEnsureGTKMenu( m_nXScreen );
3951 NWEnsureGTKMenubar( m_nXScreen );
3952 NWEnsureGTKScrollbars( m_nXScreen );
3953 NWEnsureGTKEditBox( m_nXScreen );
3954 NWEnsureGTKTooltip( m_nXScreen );
3955 NWEnsureGTKDialog( m_nXScreen );
3956 NWEnsureGTKFrame( m_nXScreen );
3958 #if OSL_DEBUG_LEVEL > 2
3959 printStyleColors( pStyle );
3960 #endif
3962 // text colors
3963 Color aTextColor = getColor( pStyle->text[GTK_STATE_NORMAL] );
3964 aStyleSet.SetDialogTextColor( aTextColor );
3965 aStyleSet.SetWindowTextColor( aTextColor );
3966 aStyleSet.SetFieldTextColor( aTextColor );
3967 aTextColor = getColor( pStyle->fg[GTK_STATE_NORMAL] );
3968 aStyleSet.SetButtonTextColor( aTextColor );
3969 aStyleSet.SetRadioCheckTextColor( aTextColor );
3970 aStyleSet.SetGroupTextColor( aTextColor );
3971 aStyleSet.SetLabelTextColor( aTextColor );
3972 aStyleSet.SetInfoTextColor( aTextColor );
3973 aStyleSet.SetTabTextColor( aTextColor );
3974 aStyleSet.SetTabRolloverTextColor( aTextColor );
3975 aStyleSet.SetTabHighlightTextColor( aTextColor );
3977 // Tooltip colors
3978 GtkStyle* pTooltipStyle = gtk_widget_get_style( gWidgetData[m_nXScreen].gTooltipPopup );
3979 aTextColor = getColor( pTooltipStyle->fg[ GTK_STATE_NORMAL ] );
3980 aStyleSet.SetHelpTextColor( aTextColor );
3982 DialogStyle aDialogStyle(aStyleSet.GetDialogStyle());
3983 gtk_widget_style_get (gWidgetData[m_nXScreen].gDialog,
3984 "content-area-border", &aDialogStyle.content_area_border,
3985 "content-area-spacing", &aDialogStyle.content_area_spacing,
3986 "button-spacing", &aDialogStyle.button_spacing,
3987 "action-area-border", &aDialogStyle.action_area_border,
3988 NULL);
3989 aStyleSet.SetDialogStyle(aDialogStyle);
3991 FrameStyle aFrameStyle(aStyleSet.GetFrameStyle());
3992 aFrameStyle.left = aFrameStyle.right =
3993 gWidgetData[m_nXScreen].gFrame->style->xthickness;
3994 aFrameStyle.top = aFrameStyle.bottom =
3995 gWidgetData[m_nXScreen].gFrame->style->ythickness;
3996 aStyleSet.SetFrameStyle(aFrameStyle);
3998 // mouse over text colors
3999 aTextColor = getColor( pStyle->fg[ GTK_STATE_PRELIGHT ] );
4000 aStyleSet.SetButtonRolloverTextColor( aTextColor );
4001 aStyleSet.SetFieldRolloverTextColor( aTextColor );
4003 // background colors
4004 Color aBackColor = getColor( pStyle->bg[GTK_STATE_NORMAL] );
4005 Color aBackFieldColor = getColor( pStyle->base[ GTK_STATE_NORMAL ] );
4006 aStyleSet.Set3DColors( aBackColor );
4007 aStyleSet.SetFaceColor( aBackColor );
4008 aStyleSet.SetDialogColor( aBackColor );
4009 aStyleSet.SetWorkspaceColor( aBackColor );
4010 aStyleSet.SetFieldColor( aBackFieldColor );
4011 aStyleSet.SetWindowColor( aBackFieldColor );
4012 aStyleSet.SetCheckedColorSpecialCase( );
4014 // highlighting colors
4015 Color aHighlightColor = getColor( pStyle->base[GTK_STATE_SELECTED] );
4016 Color aHighlightTextColor = getColor( pStyle->text[GTK_STATE_SELECTED] );
4017 aStyleSet.SetHighlightColor( aHighlightColor );
4018 aStyleSet.SetHighlightTextColor( aHighlightTextColor );
4020 if( ! gtk_check_version( 2, 10, 0 ) ) // link colors came in with 2.10, avoid an assertion
4022 // hyperlink colors
4023 GdkColor *link_color = NULL;
4024 gtk_widget_style_get (m_pWindow, "link-color", &link_color, NULL);
4025 if (link_color)
4027 aStyleSet.SetLinkColor(getColor(*link_color));
4028 gdk_color_free (link_color);
4029 link_color = NULL;
4031 gtk_widget_style_get (m_pWindow, "visited-link-color", &link_color, NULL);
4032 if (link_color)
4034 aStyleSet.SetVisitedLinkColor(getColor(*link_color));
4035 gdk_color_free (link_color);
4039 // Tab colors
4040 aStyleSet.SetActiveTabColor( aBackFieldColor ); // same as the window color.
4041 Color aSelectedBackColor = getColor( pStyle->bg[GTK_STATE_ACTIVE] );
4042 aStyleSet.SetInactiveTabColor( aSelectedBackColor );
4044 // menu disabled entries handling
4045 aStyleSet.SetSkipDisabledInMenus( true );
4046 aStyleSet.SetAcceleratorsInContextMenus( false );
4047 // menu colors
4048 GtkStyle* pMenuStyle = gtk_widget_get_style( gWidgetData[m_nXScreen].gMenuWidget );
4049 GtkStyle* pMenuItemStyle = gtk_rc_get_style( gWidgetData[m_nXScreen].gMenuItemMenuWidget );
4050 GtkStyle* pMenubarStyle = gtk_rc_get_style( gWidgetData[m_nXScreen].gMenubarWidget );
4051 GtkStyle* pMenuTextStyle = gtk_rc_get_style( gtk_bin_get_child( GTK_BIN(gWidgetData[m_nXScreen].gMenuItemMenuWidget) ) );
4053 aBackColor = getColor( pMenubarStyle->bg[GTK_STATE_NORMAL] );
4054 aStyleSet.SetMenuBarColor( aBackColor );
4055 aStyleSet.SetMenuBarRolloverColor( aBackColor );
4056 aBackColor = getColor( pMenuStyle->bg[GTK_STATE_NORMAL] );
4057 aTextColor = getColor( pMenuTextStyle->fg[GTK_STATE_NORMAL] );
4058 aStyleSet.SetMenuColor( aBackColor );
4059 aStyleSet.SetMenuTextColor( aTextColor );
4061 aTextColor = aStyleSet.GetPersonaMenuBarTextColor().get_value_or( getColor( pMenubarStyle->fg[GTK_STATE_NORMAL] ) );
4062 aStyleSet.SetMenuBarTextColor( aTextColor );
4063 aStyleSet.SetMenuBarRolloverTextColor(getColor(pMenubarStyle->fg[GTK_STATE_PRELIGHT]));
4064 aStyleSet.SetMenuBarHighlightTextColor(getColor(pMenubarStyle->fg[GTK_STATE_SELECTED]));
4066 #if OSL_DEBUG_LEVEL > 1
4067 std::fprintf( stderr, "==\n" );
4068 std::fprintf( stderr, "MenuColor = %x (%d)\n", (int)aStyleSet.GetMenuColor().GetColor(), aStyleSet.GetMenuColor().GetLuminance() );
4069 std::fprintf( stderr, "MenuTextColor = %x (%d)\n", (int)aStyleSet.GetMenuTextColor().GetColor(), aStyleSet.GetMenuTextColor().GetLuminance() );
4070 std::fprintf( stderr, "MenuBarColor = %x (%d)\n", (int)aStyleSet.GetMenuBarColor().GetColor(), aStyleSet.GetMenuBarColor().GetLuminance() );
4071 std::fprintf( stderr, "MenuBarRolloverColor = %x (%d)\n", (int)aStyleSet.GetMenuBarRolloverColor().GetColor(), aStyleSet.GetMenuBarRolloverColor().GetLuminance() );
4072 std::fprintf( stderr, "MenuBarTextColor = %x (%d)\n", (int)aStyleSet.GetMenuBarTextColor().GetColor(), aStyleSet.GetMenuBarTextColor().GetLuminance() );
4073 std::fprintf( stderr, "MenuBarRolloverTextColor = %x (%d)\n", (int)aStyleSet.GetMenuBarRolloverTextColor().GetColor(), aStyleSet.GetMenuBarRolloverTextColor().GetLuminance() );
4074 std::fprintf( stderr, "LightColor = %x (%d)\n", (int)aStyleSet.GetLightColor().GetColor(), aStyleSet.GetLightColor().GetLuminance() );
4075 std::fprintf( stderr, "ShadowColor = %x (%d)\n", (int)aStyleSet.GetShadowColor().GetColor(), aStyleSet.GetShadowColor().GetLuminance() );
4076 std::fprintf( stderr, "DarkShadowColor = %x (%d)\n", (int)aStyleSet.GetDarkShadowColor().GetColor(), aStyleSet.GetDarkShadowColor().GetLuminance() );
4077 #endif
4079 // Awful hack for menu separators in the Sonar and similar themes.
4080 // If the menu color is not too dark, and the menu text color is lighter,
4081 // make the "light" color lighter than the menu color and the "shadow"
4082 // color darker than it.
4083 if ( aStyleSet.GetMenuColor().GetLuminance() >= 32 &&
4084 aStyleSet.GetMenuColor().GetLuminance() <= aStyleSet.GetMenuTextColor().GetLuminance() )
4086 Color temp = aStyleSet.GetMenuColor();
4087 temp.IncreaseLuminance( 8 );
4088 aStyleSet.SetLightColor( temp );
4089 temp = aStyleSet.GetMenuColor();
4090 temp.DecreaseLuminance( 16 );
4091 aStyleSet.SetShadowColor( temp );
4094 aHighlightColor = getColor( pMenuItemStyle->bg[ GTK_STATE_SELECTED ] );
4095 aHighlightTextColor = getColor( pMenuItemStyle->fg[ GTK_STATE_SELECTED ] );
4096 aStyleSet.SetMenuHighlightColor( aHighlightColor );
4097 aStyleSet.SetMenuHighlightTextColor( aHighlightTextColor );
4099 // UI font
4100 OString aFamily = pango_font_description_get_family( pStyle->font_desc );
4101 int nPangoHeight = pango_font_description_get_size( pStyle->font_desc );
4102 PangoStyle eStyle = pango_font_description_get_style( pStyle->font_desc );
4103 PangoWeight eWeight = pango_font_description_get_weight( pStyle->font_desc );
4104 PangoStretch eStretch = pango_font_description_get_stretch( pStyle->font_desc );
4106 psp::FastPrintFontInfo aInfo;
4107 // set family name
4108 aInfo.m_aFamilyName = OStringToOUString( aFamily, RTL_TEXTENCODING_UTF8 );
4109 // set italic
4110 switch( eStyle )
4112 case PANGO_STYLE_NORMAL: aInfo.m_eItalic = ITALIC_NONE;break;
4113 case PANGO_STYLE_ITALIC: aInfo.m_eItalic = ITALIC_NORMAL;break;
4114 case PANGO_STYLE_OBLIQUE: aInfo.m_eItalic = ITALIC_OBLIQUE;break;
4116 // set weight
4117 if( eWeight <= PANGO_WEIGHT_ULTRALIGHT )
4118 aInfo.m_eWeight = WEIGHT_ULTRALIGHT;
4119 else if( eWeight <= PANGO_WEIGHT_LIGHT )
4120 aInfo.m_eWeight = WEIGHT_LIGHT;
4121 else if( eWeight <= PANGO_WEIGHT_NORMAL )
4122 aInfo.m_eWeight = WEIGHT_NORMAL;
4123 else if( eWeight <= PANGO_WEIGHT_BOLD )
4124 aInfo.m_eWeight = WEIGHT_BOLD;
4125 else
4126 aInfo.m_eWeight = WEIGHT_ULTRABOLD;
4127 // set width
4128 switch( eStretch )
4130 case PANGO_STRETCH_ULTRA_CONDENSED: aInfo.m_eWidth = WIDTH_ULTRA_CONDENSED;break;
4131 case PANGO_STRETCH_EXTRA_CONDENSED: aInfo.m_eWidth = WIDTH_EXTRA_CONDENSED;break;
4132 case PANGO_STRETCH_CONDENSED: aInfo.m_eWidth = WIDTH_CONDENSED;break;
4133 case PANGO_STRETCH_SEMI_CONDENSED: aInfo.m_eWidth = WIDTH_SEMI_CONDENSED;break;
4134 case PANGO_STRETCH_NORMAL: aInfo.m_eWidth = WIDTH_NORMAL;break;
4135 case PANGO_STRETCH_SEMI_EXPANDED: aInfo.m_eWidth = WIDTH_SEMI_EXPANDED;break;
4136 case PANGO_STRETCH_EXPANDED: aInfo.m_eWidth = WIDTH_EXPANDED;break;
4137 case PANGO_STRETCH_EXTRA_EXPANDED: aInfo.m_eWidth = WIDTH_EXTRA_EXPANDED;break;
4138 case PANGO_STRETCH_ULTRA_EXPANDED: aInfo.m_eWidth = WIDTH_ULTRA_EXPANDED;break;
4141 #if OSL_DEBUG_LEVEL > 1
4142 std::fprintf( stderr, "font name BEFORE system match: \"%s\"\n", aFamily.getStr() );
4143 #endif
4145 // match font to e.g. resolve "Sans"
4146 psp::PrintFontManager::get().matchFont( aInfo, rSettings.GetUILanguageTag().getLocale() );
4148 #if OSL_DEBUG_LEVEL > 1
4149 std::fprintf( stderr, "font match %s, name AFTER: \"%s\"\n",
4150 aInfo.m_nID != 0 ? "succeeded" : "failed",
4151 OUStringToOString( aInfo.m_aFamilyName, RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
4152 #endif
4154 sal_Int32 nDispDPIY = GetDisplay()->GetResolution().B();
4155 int nPointHeight = 0;
4156 static gboolean(*pAbso)(const PangoFontDescription*) =
4157 reinterpret_cast<gboolean(*)(const PangoFontDescription*)>(osl_getAsciiFunctionSymbol( GetSalData()->m_pPlugin, "pango_font_description_get_size_is_absolute" ));
4159 if( pAbso && pAbso( pStyle->font_desc ) )
4160 nPointHeight = (nPangoHeight * 72 + nDispDPIY*PANGO_SCALE/2) / (nDispDPIY * PANGO_SCALE);
4161 else
4162 nPointHeight = nPangoHeight/PANGO_SCALE;
4164 vcl::Font aFont( aInfo.m_aFamilyName, Size( 0, nPointHeight ) );
4165 if( aInfo.m_eWeight != WEIGHT_DONTKNOW )
4166 aFont.SetWeight( aInfo.m_eWeight );
4167 if( aInfo.m_eWidth != WIDTH_DONTKNOW )
4168 aFont.SetWidthType( aInfo.m_eWidth );
4169 if( aInfo.m_eItalic != ITALIC_DONTKNOW )
4170 aFont.SetItalic( aInfo.m_eItalic );
4171 if( aInfo.m_ePitch != PITCH_DONTKNOW )
4172 aFont.SetPitch( aInfo.m_ePitch );
4174 aStyleSet.SetAppFont( aFont );
4175 aStyleSet.SetHelpFont( aFont );
4176 aStyleSet.SetMenuFont( aFont );
4177 aStyleSet.SetToolFont( aFont );
4178 aStyleSet.SetLabelFont( aFont );
4179 aStyleSet.SetInfoFont( aFont );
4180 aStyleSet.SetRadioCheckFont( aFont );
4181 aStyleSet.SetPushButtonFont( aFont );
4182 aStyleSet.SetFieldFont( aFont );
4183 aStyleSet.SetIconFont( aFont );
4184 aStyleSet.SetTabFont( aFont );
4185 aStyleSet.SetGroupFont( aFont );
4187 aFont.SetWeight( WEIGHT_BOLD );
4188 aStyleSet.SetTitleFont( aFont );
4189 aStyleSet.SetFloatTitleFont( aFont );
4191 // get cursor blink time
4192 gboolean blink = false;
4194 g_object_get( pSettings, "gtk-cursor-blink", &blink, (char *)NULL );
4195 if( blink )
4197 gint blink_time = static_cast<gint>(STYLE_CURSOR_NOBLINKTIME);
4198 g_object_get( pSettings, "gtk-cursor-blink-time", &blink_time, (char *)NULL );
4199 // set the blink_time if there is a setting and it is reasonable
4200 // else leave the default value
4201 if( blink_time > 100 && blink_time != gint(STYLE_CURSOR_NOBLINKTIME) )
4202 aStyleSet.SetCursorBlinkTime( blink_time/2 );
4204 else
4205 aStyleSet.SetCursorBlinkTime( STYLE_CURSOR_NOBLINKTIME );
4207 MouseSettings aMouseSettings = rSettings.GetMouseSettings();
4208 int iDoubleClickTime, iDoubleClickDistance, iDragThreshold, iMenuPopupDelay;
4209 g_object_get( pSettings,
4210 "gtk-double-click-time", &iDoubleClickTime,
4211 "gtk-double-click-distance", &iDoubleClickDistance,
4212 "gtk-dnd-drag-threshold", &iDragThreshold,
4213 "gtk-menu-popup-delay", &iMenuPopupDelay,
4214 (char *)NULL );
4215 aMouseSettings.SetDoubleClickTime( iDoubleClickTime );
4216 aMouseSettings.SetDoubleClickWidth( iDoubleClickDistance );
4217 aMouseSettings.SetDoubleClickHeight( iDoubleClickDistance );
4218 aMouseSettings.SetStartDragWidth( iDragThreshold );
4219 aMouseSettings.SetStartDragHeight( iDragThreshold );
4220 aMouseSettings.SetMenuDelay( iMenuPopupDelay );
4221 rSettings.SetMouseSettings( aMouseSettings );
4223 gboolean showmenuicons = true, primarybuttonwarps = false;
4224 g_object_get( pSettings,
4225 "gtk-menu-images", &showmenuicons,
4226 (char *)NULL );
4227 if( g_object_class_find_property(
4228 G_OBJECT_GET_CLASS(pSettings), "gtk-primary-button-warps-slider") )
4230 g_object_get( pSettings,
4231 "gtk-primary-button-warps-slider", &primarybuttonwarps,
4232 (char *)NULL );
4234 aStyleSet.SetPreferredUseImagesInMenus(showmenuicons);
4235 aStyleSet.SetPrimaryButtonWarpsSlider(primarybuttonwarps);
4237 // set scrollbar settings
4238 gint slider_width = 14;
4239 gint trough_border = 1;
4240 gint min_slider_length = 21;
4242 // Grab some button style attributes
4243 gtk_widget_style_get( gWidgetData[m_nXScreen].gScrollHorizWidget,
4244 "slider-width", &slider_width,
4245 "trough-border", &trough_border,
4246 "min-slider-length", &min_slider_length,
4247 (char *)NULL );
4248 gint magic = trough_border ? 1 : 0;
4249 aStyleSet.SetScrollBarSize( slider_width + 2*trough_border );
4250 aStyleSet.SetMinThumbSize( min_slider_length - magic );
4252 // preferred icon style
4253 gchar* pIconThemeName = NULL;
4254 g_object_get( pSettings, "gtk-icon-theme-name", &pIconThemeName, (char *)NULL );
4255 aStyleSet.SetPreferredIconTheme( OUString::createFromAscii( pIconThemeName ) );
4256 g_free( pIconThemeName );
4258 aStyleSet.SetToolbarIconSize( ToolbarIconSize::Large );
4260 const cairo_font_options_t* pNewOptions = gdk_screen_get_font_options( pScreen );
4261 aStyleSet.SetCairoFontOptions( pNewOptions );
4263 // finally update the collected settings
4264 rSettings.SetStyleSettings( aStyleSet );
4267 /************************************************************************
4268 * Create a GdkPixmap filled with the contents of an area of an Xlib window
4269 ************************************************************************/
4271 GdkX11Pixmap* GtkSalGraphics::NWGetPixmapFromScreen( Rectangle srcRect, int nBgColor )
4273 GdkX11Pixmap* pPixmap;
4274 int nDepth = vcl_sal::getSalDisplay(GetGenericData())->GetVisual( m_nXScreen ).GetDepth();
4276 pPixmap = new GdkX11Pixmap( srcRect.GetWidth(), srcRect.GetHeight(), nDepth );
4278 if( nBgColor == BG_FILL )
4280 FillPixmapFromScreen( pPixmap, srcRect.Left(), srcRect.Top() );
4282 else if( nBgColor != BG_NONE )
4284 cairo_t *cr = gdk_cairo_create( pPixmap->GetGdkDrawable() );
4285 if( nBgColor == BG_BLACK)
4286 cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 1.0);
4287 else
4288 cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 1.0);
4289 cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
4290 cairo_paint (cr);
4291 cairo_destroy(cr);
4294 return pPixmap;
4297 /************************************************************************
4298 * Copy an alpha pixmap to screen using a gc with clipping
4299 ************************************************************************/
4301 bool GtkSalGraphics::NWRenderPixmapToScreen( GdkX11Pixmap* pPixmap, GdkX11Pixmap* pMask, Rectangle dstRect )
4303 return RenderPixmapToScreen( pPixmap, pMask, dstRect.Left(), dstRect.Top() );
4306 /************************************************************************
4307 * State conversion
4308 ************************************************************************/
4309 static void NWConvertVCLStateToGTKState( ControlState nVCLState,
4310 GtkStateType* nGTKState, GtkShadowType* nGTKShadow )
4312 *nGTKShadow = GTK_SHADOW_OUT;
4313 *nGTKState = GTK_STATE_INSENSITIVE;
4315 if ( nVCLState & ControlState::ENABLED )
4317 if ( nVCLState & ControlState::PRESSED )
4319 *nGTKState = GTK_STATE_ACTIVE;
4320 *nGTKShadow = GTK_SHADOW_IN;
4322 else if ( nVCLState & ControlState::ROLLOVER )
4324 *nGTKState = GTK_STATE_PRELIGHT;
4325 *nGTKShadow = GTK_SHADOW_OUT;
4327 else
4329 *nGTKState = GTK_STATE_NORMAL;
4330 *nGTKShadow = GTK_SHADOW_OUT;
4335 /************************************************************************
4336 * Set widget flags
4337 ************************************************************************/
4338 static void NWSetWidgetState( GtkWidget* widget, ControlState nState, GtkStateType nGtkState )
4340 // Set to default state, then build up from there
4341 GTK_WIDGET_UNSET_FLAGS( widget, GTK_HAS_DEFAULT );
4342 GTK_WIDGET_UNSET_FLAGS( widget, GTK_HAS_FOCUS );
4343 GTK_WIDGET_UNSET_FLAGS( widget, GTK_SENSITIVE );
4344 GTK_WIDGET_SET_FLAGS( widget, gWidgetDefaultFlags[reinterpret_cast<long>(widget)] );
4346 if ( nState & ControlState::DEFAULT )
4347 GTK_WIDGET_SET_FLAGS( widget, GTK_HAS_DEFAULT );
4348 if ( !GTK_IS_TOGGLE_BUTTON(widget) && (nState & ControlState::FOCUSED) )
4349 GTK_WIDGET_SET_FLAGS( widget, GTK_HAS_FOCUS );
4350 if ( nState & ControlState::ENABLED )
4351 GTK_WIDGET_SET_FLAGS( widget, GTK_SENSITIVE );
4352 gtk_widget_set_state( widget, nGtkState );
4355 /************************************************************************
4356 * Widget ensure functions - make sure cached objects are valid
4357 ************************************************************************/
4359 static void NWAddWidgetToCacheWindow( GtkWidget* widget, SalX11Screen nScreen )
4361 NWFWidgetData& rData = gWidgetData[nScreen];
4362 if ( !rData.gCacheWindow || !rData.gDumbContainer )
4364 if ( !rData.gCacheWindow )
4366 rData.gCacheWindow = gtk_window_new( GTK_WINDOW_TOPLEVEL );
4367 g_object_set_data( G_OBJECT( rData.gCacheWindow ), "libo-version",
4368 (gpointer)LIBO_VERSION_DOTTED );
4370 GdkScreen* pScreen = gdk_display_get_screen( gdk_display_get_default(),
4371 nScreen.getXScreen() );
4372 if( pScreen )
4373 gtk_window_set_screen( GTK_WINDOW(rData.gCacheWindow), pScreen );
4375 if ( !rData.gDumbContainer )
4376 rData.gDumbContainer = gtk_fixed_new();
4377 gtk_container_add( GTK_CONTAINER(rData.gCacheWindow), rData.gDumbContainer );
4378 gtk_widget_realize( rData.gDumbContainer );
4379 gtk_widget_realize( rData.gCacheWindow );
4382 gtk_container_add( GTK_CONTAINER(rData.gDumbContainer), widget );
4383 gtk_widget_realize( widget );
4384 gtk_widget_ensure_style( widget );
4386 // Store widget's default flags
4387 gWidgetDefaultFlags[ reinterpret_cast<long>(widget) ] = GTK_WIDGET_FLAGS( widget );
4390 static void NWEnsureGTKButton( SalX11Screen nScreen )
4392 if ( !gWidgetData[nScreen].gBtnWidget )
4394 gWidgetData[nScreen].gBtnWidget = gtk_button_new_with_label( "" );
4395 NWAddWidgetToCacheWindow( gWidgetData[nScreen].gBtnWidget, nScreen );
4399 static void NWEnsureGTKRadio( SalX11Screen nScreen )
4401 if ( !gWidgetData[nScreen].gRadioWidget || !gWidgetData[nScreen].gRadioWidgetSibling )
4403 gWidgetData[nScreen].gRadioWidget = gtk_radio_button_new( NULL );
4404 gWidgetData[nScreen].gRadioWidgetSibling = gtk_radio_button_new_from_widget( GTK_RADIO_BUTTON(gWidgetData[nScreen].gRadioWidget) );
4405 NWAddWidgetToCacheWindow( gWidgetData[nScreen].gRadioWidget, nScreen );
4406 NWAddWidgetToCacheWindow( gWidgetData[nScreen].gRadioWidgetSibling, nScreen );
4410 static void NWEnsureGTKCheck( SalX11Screen nScreen )
4412 if ( !gWidgetData[nScreen].gCheckWidget )
4414 gWidgetData[nScreen].gCheckWidget = gtk_check_button_new();
4415 NWAddWidgetToCacheWindow( gWidgetData[nScreen].gCheckWidget, nScreen );
4419 static void NWEnsureGTKScrollbars( SalX11Screen nScreen )
4421 if ( !gWidgetData[nScreen].gScrollHorizWidget )
4423 gWidgetData[nScreen].gScrollHorizWidget = gtk_hscrollbar_new( NULL );
4424 NWAddWidgetToCacheWindow( gWidgetData[nScreen].gScrollHorizWidget, nScreen );
4427 if ( !gWidgetData[nScreen].gScrollVertWidget )
4429 gWidgetData[nScreen].gScrollVertWidget = gtk_vscrollbar_new( NULL );
4430 NWAddWidgetToCacheWindow( gWidgetData[nScreen].gScrollVertWidget, nScreen );
4434 static void NWEnsureGTKArrow( SalX11Screen nScreen )
4436 if ( !gWidgetData[nScreen].gArrowWidget || !gWidgetData[nScreen].gDropdownWidget )
4438 gWidgetData[nScreen].gDropdownWidget = gtk_toggle_button_new();
4439 NWAddWidgetToCacheWindow( gWidgetData[nScreen].gDropdownWidget, nScreen );
4440 gWidgetData[nScreen].gArrowWidget = gtk_arrow_new( GTK_ARROW_DOWN, GTK_SHADOW_OUT );
4441 gtk_container_add( GTK_CONTAINER(gWidgetData[nScreen].gDropdownWidget), gWidgetData[nScreen].gArrowWidget );
4442 gtk_widget_set_rc_style( gWidgetData[nScreen].gArrowWidget );
4443 gtk_widget_realize( gWidgetData[nScreen].gArrowWidget );
4447 static void NWEnsureGTKEditBox( SalX11Screen nScreen )
4449 if ( !gWidgetData[nScreen].gEditBoxWidget )
4451 gWidgetData[nScreen].gEditBoxWidget = gtk_entry_new();
4452 NWAddWidgetToCacheWindow( gWidgetData[nScreen].gEditBoxWidget, nScreen );
4456 static void NWEnsureGTKSpinButton( SalX11Screen nScreen )
4458 if ( !gWidgetData[nScreen].gSpinButtonWidget )
4460 GtkAdjustment *adj = GTK_ADJUSTMENT( gtk_adjustment_new(0, 0, 1, 1, 1, 0) );
4461 gWidgetData[nScreen].gSpinButtonWidget = gtk_spin_button_new( adj, 1, 2 );
4463 //Setting non-editable means it doesn't blink, so there's no timeouts
4464 //running around to nobble us
4465 gtk_editable_set_editable(GTK_EDITABLE(gWidgetData[nScreen].gSpinButtonWidget), false);
4467 NWAddWidgetToCacheWindow( gWidgetData[nScreen].gSpinButtonWidget, nScreen );
4471 static void NWEnsureGTKNotebook( SalX11Screen nScreen )
4473 if ( !gWidgetData[nScreen].gNotebookWidget )
4475 gWidgetData[nScreen].gNotebookWidget = gtk_notebook_new();
4476 NWAddWidgetToCacheWindow( gWidgetData[nScreen].gNotebookWidget, nScreen );
4480 static void NWEnsureGTKOptionMenu( SalX11Screen nScreen )
4482 if ( !gWidgetData[nScreen].gOptionMenuWidget )
4484 gWidgetData[nScreen].gOptionMenuWidget = gtk_option_menu_new();
4485 NWAddWidgetToCacheWindow( gWidgetData[nScreen].gOptionMenuWidget, nScreen );
4489 static void NWEnsureGTKCombo( SalX11Screen nScreen )
4491 if ( !gWidgetData[nScreen].gComboWidget )
4493 gWidgetData[nScreen].gComboWidget = gtk_combo_new();
4495 // #i59129# Setting non-editable means it doesn't blink, so
4496 // there are no timeouts running around to nobble us
4497 gtk_editable_set_editable(GTK_EDITABLE(GTK_COMBO(gWidgetData[nScreen].gComboWidget)->entry), false);
4499 NWAddWidgetToCacheWindow( gWidgetData[nScreen].gComboWidget, nScreen );
4500 // Must realize the ComboBox's children, since GTK
4501 // does not do this for us in GtkCombo::gtk_widget_realize()
4502 gtk_widget_realize( GTK_COMBO(gWidgetData[nScreen].gComboWidget)->button );
4503 gtk_widget_realize( GTK_COMBO(gWidgetData[nScreen].gComboWidget)->entry );
4507 static void NWEnsureGTKScrolledWindow( SalX11Screen nScreen )
4509 if ( !gWidgetData[nScreen].gScrolledWindowWidget )
4511 GtkAdjustment *hadj = GTK_ADJUSTMENT( gtk_adjustment_new(0, 0, 0, 0, 0, 0) );
4512 GtkAdjustment *vadj = GTK_ADJUSTMENT( gtk_adjustment_new(0, 0, 0, 0, 0, 0) );
4514 gWidgetData[nScreen].gScrolledWindowWidget = gtk_scrolled_window_new( hadj, vadj );
4515 NWAddWidgetToCacheWindow( gWidgetData[nScreen].gScrolledWindowWidget, nScreen );
4519 static void NWEnsureGTKToolbar( SalX11Screen nScreen )
4521 if( !gWidgetData[nScreen].gToolbarWidget )
4523 gWidgetData[nScreen].gToolbarWidget = gtk_toolbar_new();
4524 NWAddWidgetToCacheWindow( gWidgetData[nScreen].gToolbarWidget, nScreen );
4525 gWidgetData[nScreen].gToolbarButtonWidget = GTK_WIDGET(gtk_toggle_button_new());
4526 gWidgetData[nScreen].gSeparator = GTK_WIDGET(gtk_separator_tool_item_new());
4527 NWAddWidgetToCacheWindow( gWidgetData[nScreen].gSeparator, nScreen );
4529 GtkReliefStyle aRelief = GTK_RELIEF_NORMAL;
4530 gtk_widget_ensure_style( gWidgetData[nScreen].gToolbarWidget );
4531 gtk_widget_style_get( gWidgetData[nScreen].gToolbarWidget,
4532 "button_relief", &aRelief,
4533 (char *)NULL);
4535 gtk_button_set_relief( GTK_BUTTON(gWidgetData[nScreen].gToolbarButtonWidget), aRelief );
4536 GTK_WIDGET_UNSET_FLAGS( gWidgetData[nScreen].gToolbarButtonWidget, GTK_CAN_FOCUS );
4537 GTK_WIDGET_UNSET_FLAGS( gWidgetData[nScreen].gToolbarButtonWidget, GTK_CAN_DEFAULT );
4538 NWAddWidgetToCacheWindow( gWidgetData[nScreen].gToolbarButtonWidget, nScreen );
4541 if( ! gWidgetData[nScreen].gHandleBoxWidget )
4543 gWidgetData[nScreen].gHandleBoxWidget = gtk_handle_box_new();
4544 NWAddWidgetToCacheWindow( gWidgetData[nScreen].gHandleBoxWidget, nScreen );
4548 static void NWEnsureGTKMenubar( SalX11Screen nScreen )
4550 if( !gWidgetData[nScreen].gMenubarWidget )
4552 gWidgetData[nScreen].gMenubarWidget = gtk_menu_bar_new();
4553 gWidgetData[nScreen].gMenuItemMenubarWidget = gtk_menu_item_new_with_label( "b" );
4554 gtk_menu_shell_append( GTK_MENU_SHELL( gWidgetData[nScreen].gMenubarWidget ), gWidgetData[nScreen].gMenuItemMenubarWidget );
4555 gtk_widget_show( gWidgetData[nScreen].gMenuItemMenubarWidget );
4556 NWAddWidgetToCacheWindow( gWidgetData[nScreen].gMenubarWidget, nScreen );
4557 gtk_widget_show( gWidgetData[nScreen].gMenubarWidget );
4559 // do what NWAddWidgetToCacheWindow does except adding to def container
4560 gtk_widget_realize( gWidgetData[nScreen].gMenuItemMenubarWidget );
4561 gtk_widget_ensure_style( gWidgetData[nScreen].gMenuItemMenubarWidget );
4563 gWidgetDefaultFlags[ reinterpret_cast<long>(gWidgetData[nScreen].gMenuItemMenubarWidget) ] = GTK_WIDGET_FLAGS( gWidgetData[nScreen].gMenuItemMenubarWidget );
4567 static void NWEnsureGTKMenu( SalX11Screen nScreen )
4569 if( !gWidgetData[nScreen].gMenuWidget )
4571 gWidgetData[nScreen].gMenuWidget = gtk_menu_new();
4572 gWidgetData[nScreen].gMenuItemMenuWidget = gtk_menu_item_new_with_label( "b" );
4573 gWidgetData[nScreen].gMenuItemCheckMenuWidget = gtk_check_menu_item_new_with_label( "b" );
4574 gWidgetData[nScreen].gMenuItemRadioMenuWidget = gtk_radio_menu_item_new_with_label( NULL, "b" );
4575 gWidgetData[nScreen].gMenuItemSeparatorMenuWidget = gtk_separator_menu_item_new();
4576 gWidgetData[nScreen].gImageMenuItem = gtk_image_menu_item_new();
4578 g_object_ref_sink (gWidgetData[nScreen].gMenuWidget);
4580 gtk_menu_shell_append( GTK_MENU_SHELL( gWidgetData[nScreen].gMenuWidget ), gWidgetData[nScreen].gMenuItemMenuWidget );
4581 gtk_menu_shell_append( GTK_MENU_SHELL( gWidgetData[nScreen].gMenuWidget ), gWidgetData[nScreen].gMenuItemCheckMenuWidget );
4582 gtk_menu_shell_append( GTK_MENU_SHELL( gWidgetData[nScreen].gMenuWidget ), gWidgetData[nScreen].gMenuItemRadioMenuWidget );
4583 gtk_menu_shell_append( GTK_MENU_SHELL( gWidgetData[nScreen].gMenuWidget ), gWidgetData[nScreen].gMenuItemSeparatorMenuWidget );
4584 gtk_menu_shell_append( GTK_MENU_SHELL( gWidgetData[nScreen].gMenuWidget ), gWidgetData[nScreen].gImageMenuItem );
4586 // do what NWAddWidgetToCacheWindow does except adding to def container
4587 gtk_widget_realize( gWidgetData[nScreen].gMenuWidget );
4588 gtk_widget_ensure_style( gWidgetData[nScreen].gMenuWidget );
4590 gtk_widget_realize( gWidgetData[nScreen].gMenuItemMenuWidget );
4591 gtk_widget_ensure_style( gWidgetData[nScreen].gMenuItemMenuWidget );
4593 gtk_widget_realize( gWidgetData[nScreen].gMenuItemCheckMenuWidget );
4594 gtk_widget_ensure_style( gWidgetData[nScreen].gMenuItemCheckMenuWidget );
4596 gtk_widget_realize( gWidgetData[nScreen].gMenuItemRadioMenuWidget );
4597 gtk_widget_ensure_style( gWidgetData[nScreen].gMenuItemRadioMenuWidget );
4599 gtk_widget_realize( gWidgetData[nScreen].gMenuItemSeparatorMenuWidget );
4600 gtk_widget_ensure_style( gWidgetData[nScreen].gMenuItemSeparatorMenuWidget );
4602 gtk_widget_realize( gWidgetData[nScreen].gImageMenuItem );
4603 gtk_widget_ensure_style( gWidgetData[nScreen].gImageMenuItem );
4605 gWidgetDefaultFlags[ reinterpret_cast<long>(gWidgetData[nScreen].gMenuWidget) ] = GTK_WIDGET_FLAGS( gWidgetData[nScreen].gMenuWidget );
4606 gWidgetDefaultFlags[ reinterpret_cast<long>(gWidgetData[nScreen].gMenuItemMenuWidget) ] = GTK_WIDGET_FLAGS( gWidgetData[nScreen].gMenuItemMenuWidget );
4607 gWidgetDefaultFlags[ reinterpret_cast<long>(gWidgetData[nScreen].gMenuItemCheckMenuWidget) ] = GTK_WIDGET_FLAGS( gWidgetData[nScreen].gMenuItemCheckMenuWidget );
4608 gWidgetDefaultFlags[ reinterpret_cast<long>(gWidgetData[nScreen].gMenuItemRadioMenuWidget) ] = GTK_WIDGET_FLAGS( gWidgetData[nScreen].gMenuItemRadioMenuWidget );
4609 gWidgetDefaultFlags[ reinterpret_cast<long>(gWidgetData[nScreen].gMenuItemSeparatorMenuWidget) ] = GTK_WIDGET_FLAGS( gWidgetData[nScreen].gMenuItemSeparatorMenuWidget );
4610 gWidgetDefaultFlags[ reinterpret_cast<long>(gWidgetData[nScreen].gImageMenuItem) ] = GTK_WIDGET_FLAGS( gWidgetData[nScreen].gImageMenuItem );
4614 static void NWEnsureGTKTooltip( SalX11Screen nScreen )
4616 if( !gWidgetData[nScreen].gTooltipPopup )
4618 gWidgetData[nScreen].gTooltipPopup = gtk_window_new (GTK_WINDOW_POPUP);
4619 GdkScreen* pScreen = gdk_display_get_screen( gdk_display_get_default(),
4620 nScreen.getXScreen() );
4621 if( pScreen )
4622 gtk_window_set_screen( GTK_WINDOW(gWidgetData[nScreen].gTooltipPopup), pScreen );
4623 gtk_widget_set_name( gWidgetData[nScreen].gTooltipPopup, "gtk-tooltips");
4624 gtk_widget_realize( gWidgetData[nScreen].gTooltipPopup );
4625 gtk_widget_ensure_style( gWidgetData[nScreen].gTooltipPopup );
4629 static void NWEnsureGTKDialog( SalX11Screen nScreen )
4631 if( !gWidgetData[nScreen].gDialog )
4633 gWidgetData[nScreen].gDialog = gtk_dialog_new();
4634 GdkScreen* pScreen = gdk_display_get_screen( gdk_display_get_default(),
4635 nScreen.getXScreen() );
4636 if( pScreen )
4637 gtk_window_set_screen( GTK_WINDOW(gWidgetData[nScreen].gDialog), pScreen );
4638 gtk_widget_realize(gWidgetData[nScreen].gDialog);
4639 gtk_widget_ensure_style(gWidgetData[nScreen].gDialog);
4643 static void NWEnsureGTKFrame( SalX11Screen nScreen )
4645 if( !gWidgetData[nScreen].gFrame )
4647 gWidgetData[nScreen].gFrame = gtk_frame_new(NULL);
4648 NWAddWidgetToCacheWindow( gWidgetData[nScreen].gFrame, nScreen );
4652 static void NWEnsureGTKProgressBar( SalX11Screen nScreen )
4654 if( !gWidgetData[nScreen].gProgressBar )
4656 gWidgetData[nScreen].gProgressBar = gtk_progress_bar_new ();
4657 NWAddWidgetToCacheWindow( gWidgetData[nScreen].gProgressBar, nScreen );
4661 static void NWEnsureGTKTreeView( SalX11Screen nScreen )
4663 if( !gWidgetData[nScreen].gTreeView )
4665 gWidgetData[nScreen].gTreeView = gtk_tree_view_new ();
4667 // Columns will be used for tree header rendering
4668 GtkCellRenderer* renderer=gtk_cell_renderer_text_new();
4669 GtkTreeViewColumn* column=gtk_tree_view_column_new_with_attributes("",renderer,"text",0,NULL);
4670 gtk_tree_view_column_set_widget(column,gtk_label_new(""));
4671 gtk_tree_view_append_column(GTK_TREE_VIEW(gWidgetData[nScreen].gTreeView), column);
4673 // Add one more column so that some engines like clearlooks did render separators between columns
4674 column=gtk_tree_view_column_new_with_attributes("",renderer,"text",0,NULL);
4675 gtk_tree_view_append_column(GTK_TREE_VIEW(gWidgetData[nScreen].gTreeView), column);
4677 NWAddWidgetToCacheWindow( gWidgetData[nScreen].gTreeView, nScreen );
4681 static void NWEnsureGTKSlider( SalX11Screen nScreen )
4683 if( !gWidgetData[nScreen].gHScale )
4685 gWidgetData[nScreen].gHScale = gtk_hscale_new_with_range(0, 10, 1);
4686 NWAddWidgetToCacheWindow( gWidgetData[nScreen].gHScale, nScreen );
4688 if( !gWidgetData[nScreen].gVScale )
4690 gWidgetData[nScreen].gVScale = gtk_vscale_new_with_range(0, 10, 1);
4691 NWAddWidgetToCacheWindow( gWidgetData[nScreen].gVScale, nScreen );
4695 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */