xref: /AOO41X/main/vcl/unx/gtk/gdi/salnativewidgets-gtk.cxx (revision 707fc0d4d52eb4f69d89a98ffec6918ca5de6326)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_vcl.hxx"
26 
27 #include "vcl/svapp.hxx"
28 
29 #include "unx/gtk/gtkframe.hxx"
30 #include "unx/gtk/gtkdata.hxx"
31 #include "unx/gtk/gtkinst.hxx"
32 #include "unx/gtk/gtkgdi.hxx"
33 
34 #include "unx/pspgraphics.h"
35 #include "unx/saldata.hxx"
36 #include "unx/saldisp.hxx"
37 
38 #include <cstdio>
39 #include <cmath>
40 #include <vector>
41 #include <algorithm>
42 #include <hash_map>
43 
44 typedef struct _cairo_font_options cairo_font_options_t;
45 
46 // initialize statics
47 sal_Bool GtkSalGraphics::bThemeChanged = sal_True;
48 sal_Bool GtkSalGraphics::bNeedPixmapPaint = sal_False;
49 sal_Bool GtkSalGraphics::bGlobalNeedPixmapPaint = sal_False;
50 sal_Bool GtkSalGraphics::bToolbarGripWorkaround = sal_False;
51 sal_Bool GtkSalGraphics::bNeedButtonStyleAsEditBackgroundWorkaround = sal_False;
52 
53 GtkSalGraphics::~GtkSalGraphics()
54 {
55 }
56 
57 
58 using namespace rtl;
59 
60 /*************************************
61  * Cached native widget objects
62  *************************************/
63 class NWPixmapCacheList;
64 class NWPixmapCache;
65 struct NWFWidgetData
66 {
67     GtkWidget * gCacheWindow;
68     GtkWidget * gDumbContainer;
69 
70     GtkWidget * gBtnWidget;
71     GtkWidget * gRadioWidget;
72     GtkWidget * gRadioWidgetSibling;
73     GtkWidget * gCheckWidget;
74     GtkWidget * gScrollHorizWidget;
75     GtkWidget * gScrollVertWidget;
76     GtkWidget * gArrowWidget;
77     GtkWidget * gDropdownWidget;
78     GtkWidget * gEditBoxWidget;
79     GtkWidget * gSpinButtonWidget;
80     GtkWidget * gNotebookWidget;
81     GtkWidget * gOptionMenuWidget;
82     GtkWidget * gComboWidget;
83     GtkWidget * gScrolledWindowWidget;
84     GtkWidget *  gToolbarWidget;
85     GtkWidget *  gToolbarButtonWidget;
86     GtkWidget *  gToolbarToggleWidget;
87     GtkWidget *  gHandleBoxWidget;
88     GtkWidget *  gMenubarWidget;
89     GtkWidget *  gMenuItemMenubarWidget;
90     GtkWidget *  gMenuWidget;
91     GtkWidget *  gMenuItemMenuWidget;
92     GtkWidget *  gMenuItemCheckMenuWidget;
93     GtkWidget *  gMenuItemRadioMenuWidget;
94     GtkWidget *  gImageMenuItem;
95     GtkWidget *  gTooltipPopup;
96     GtkWidget *  gProgressBar;
97     GtkWidget *  gTreeView;
98     GtkWidget *  gHScale;
99     GtkWidget *  gVScale;
100 
101     NWPixmapCacheList* gNWPixmapCacheList;
102     NWPixmapCache* gCacheTabItems;
103     NWPixmapCache* gCacheTabPages;
104 
105     NWFWidgetData() :
106         gCacheWindow( NULL ),
107         gDumbContainer( NULL ),
108         gBtnWidget( NULL ),
109         gRadioWidget( NULL ),
110         gRadioWidgetSibling( NULL ),
111         gCheckWidget( NULL ),
112         gScrollHorizWidget( NULL ),
113         gScrollVertWidget( NULL ),
114         gArrowWidget( NULL ),
115         gDropdownWidget( NULL ),
116         gEditBoxWidget( NULL ),
117         gSpinButtonWidget( NULL ),
118         gNotebookWidget( NULL ),
119         gOptionMenuWidget( NULL ),
120         gComboWidget( NULL ),
121         gScrolledWindowWidget( NULL ),
122         gToolbarWidget( NULL ),
123         gToolbarButtonWidget( NULL ),
124         gToolbarToggleWidget( NULL ),
125         gHandleBoxWidget( NULL ),
126         gMenubarWidget( NULL ),
127         gMenuItemMenubarWidget( NULL ),
128         gMenuWidget( NULL ),
129         gMenuItemMenuWidget( NULL ),
130         gMenuItemCheckMenuWidget( NULL ),
131         gMenuItemRadioMenuWidget( NULL ),
132         gImageMenuItem( NULL ),
133         gTooltipPopup( NULL ),
134         gProgressBar( NULL ),
135         gTreeView( NULL ),
136         gHScale( NULL ),
137         gVScale( NULL ),
138         gNWPixmapCacheList( NULL ),
139         gCacheTabItems( NULL ),
140         gCacheTabPages( NULL )
141     {}
142 };
143 
144 // Keep a hash table of Widgets->default flags so that we can
145 // easily and quickly reset each to a default state before using
146 // them
147 static std::hash_map<long, guint>   gWidgetDefaultFlags;
148 static std::vector<NWFWidgetData>   gWidgetData;
149 
150 static const GtkBorder aDefDefBorder        = { 1, 1, 1, 1 };
151 
152 // Some GTK defaults
153 #define MIN_ARROW_SIZE                  11
154 #define BTN_CHILD_SPACING               1
155 #define MIN_SPIN_ARROW_WIDTH                6
156 
157 
158 static void NWEnsureGTKRadio            ( int nScreen );
159 static void NWEnsureGTKButton           ( int nScreen );
160 static void NWEnsureGTKCheck            ( int nScreen );
161 static void NWEnsureGTKScrollbars       ( int nScreen );
162 static void NWEnsureGTKArrow            ( int nScreen );
163 static void NWEnsureGTKEditBox          ( int nScreen );
164 static void NWEnsureGTKSpinButton       ( int nScreen );
165 static void NWEnsureGTKNotebook         ( int nScreen );
166 static void NWEnsureGTKOptionMenu       ( int nScreen );
167 static void NWEnsureGTKCombo            ( int nScreen );
168 static void NWEnsureGTKScrolledWindow   ( int nScreen );
169 static void NWEnsureGTKToolbar          ( int nScreen );
170 static void NWEnsureGTKMenubar          ( int nScreen );
171 static void NWEnsureGTKMenu             ( int nScreen );
172 static void NWEnsureGTKTooltip          ( int nScreen );
173 static void NWEnsureGTKProgressBar      ( int nScreen );
174 static void NWEnsureGTKTreeView         ( int nScreen );
175 static void NWEnsureGTKSlider           ( int nScreen );
176 
177 static void NWConvertVCLStateToGTKState( ControlState nVCLState, GtkStateType* nGTKState, GtkShadowType* nGTKShadow );
178 static void NWAddWidgetToCacheWindow( GtkWidget* widget, int nScreen );
179 static void NWSetWidgetState( GtkWidget* widget, ControlState nState, GtkStateType nGtkState );
180 
181 static void NWCalcArrowRect( const Rectangle& rButton, Rectangle& rArrow );
182 
183 /*
184  * Individual helper functions
185  *
186  */
187 
188 //---
189 static Rectangle NWGetButtonArea( int nScreen, ControlType nType, ControlPart nPart, Rectangle aAreaRect, ControlState nState,
190                                 const ImplControlValue& aValue, const OUString& rCaption );
191 
192 //---
193 static Rectangle NWGetEditBoxPixmapRect( int nScreen, ControlType nType, ControlPart nPart, Rectangle aAreaRect, ControlState nState,
194                             const ImplControlValue& aValue, const OUString& rCaption );
195 
196 static void NWPaintOneEditBox( int nScreen, GdkDrawable * gdkDrawable, GdkRectangle *gdkRect,
197                                ControlType nType, ControlPart nPart, Rectangle aEditBoxRect,
198                                ControlState nState, const ImplControlValue& aValue,
199                                const OUString& rCaption );
200 
201 //---
202 static Rectangle NWGetSpinButtonRect( int nScreen, ControlType nType, ControlPart nPart, Rectangle aAreaRect, ControlState nState,
203                             const ImplControlValue& aValue, const OUString& rCaption );
204 
205 static void NWPaintOneSpinButton( int nScreen, GdkPixmap * pixmap, ControlType nType, ControlPart nPart, Rectangle aAreaRect,
206                             ControlState nState, const ImplControlValue& aValue,
207                             const OUString& rCaption );
208 //---
209 static Rectangle NWGetComboBoxButtonRect( int nScreen, ControlType nType, ControlPart nPart, Rectangle aAreaRect, ControlState nState,
210                             const ImplControlValue& aValue, const OUString& rCaption );
211 
212 //---
213 static Rectangle NWGetListBoxButtonRect( int nScreen, ControlType nType, ControlPart nPart, Rectangle aAreaRect, ControlState nState,
214                             const ImplControlValue& aValue, const OUString& rCaption );
215 
216 static Rectangle NWGetListBoxIndicatorRect( int nScreen, ControlType nType, ControlPart nPart, Rectangle aAreaRect, ControlState nState,
217                             const ImplControlValue& aValue, const OUString& rCaption );
218 
219 static Rectangle NWGetToolbarRect( int nScreen,
220                                    ControlType nType,
221                                    ControlPart nPart,
222                                    Rectangle aAreaRect,
223                                    ControlState nState,
224                                    const ImplControlValue& aValue,
225                                    const OUString& rCaption );
226 //---
227 
228 static Rectangle NWGetScrollButtonRect( int nScreen, ControlPart nPart, Rectangle aAreaRect );
229 //---
230 
231 /*********************************************************
232  * PixmapCache
233  *********************************************************/
234 
235 // as some native widget drawing operations are pretty slow
236 // with certain themes (eg tabpages)
237 // this cache can be used to cache the corresponding pixmap
238 // see NWPaintGTKTabItem
239 
240 class NWPixmapCacheData
241 {
242 public:
243     ControlType m_nType;
244     ControlState m_nState;
245     Rectangle   m_pixmapRect;
246     GdkPixmap*  m_pixmap;
247 
248     NWPixmapCacheData() : m_nType(0), m_nState(0), m_pixmap(0) {}
249     ~NWPixmapCacheData()
250         { SetPixmap( NULL ); };
251     void SetPixmap( GdkPixmap* pPixmap );
252 };
253 
254 class NWPixmapCache
255 {
256     int m_size;
257     int m_idx;
258     int m_screen;
259     NWPixmapCacheData* pData;
260 public:
261     NWPixmapCache( int nScreen );
262     ~NWPixmapCache();
263 
264     void SetSize( int n)
265         { delete [] pData; m_idx = 0; m_size = n; pData = new NWPixmapCacheData[m_size]; }
266     int GetSize() { return m_size; }
267 
268     sal_Bool Find( ControlType aType, ControlState aState, const Rectangle& r_pixmapRect, GdkPixmap** pPixmap );
269     void Fill( ControlType aType, ControlState aState, const Rectangle& r_pixmapRect, GdkPixmap* pPixmap );
270 
271     void ThemeChanged();
272 };
273 
274 class NWPixmapCacheList
275 {
276 public:
277     ::std::vector< NWPixmapCache* > mCaches;
278 
279     void AddCache( NWPixmapCache *pCache );
280     void RemoveCache( NWPixmapCache *pCache );
281     void ThemeChanged();
282 };
283 
284 // --- implementation ---
285 
286 void NWPixmapCacheData::SetPixmap( GdkPixmap* pPixmap )
287 {
288     if( m_pixmap )
289         g_object_unref( m_pixmap );
290 
291     m_pixmap = pPixmap;
292 
293     if( m_pixmap )
294         g_object_ref( m_pixmap );
295 }
296 
297 
298 NWPixmapCache::NWPixmapCache( int nScreen )
299 {
300     m_idx = 0;
301     m_size = 0;
302     m_screen = nScreen;
303     pData = NULL;
304     if( gWidgetData[m_screen].gNWPixmapCacheList )
305         gWidgetData[m_screen].gNWPixmapCacheList->AddCache(this);
306 }
307 NWPixmapCache::~NWPixmapCache()
308 {
309     if( gWidgetData[m_screen].gNWPixmapCacheList )
310         gWidgetData[m_screen].gNWPixmapCacheList->RemoveCache(this);
311     delete[] pData;
312 }
313 void NWPixmapCache::ThemeChanged()
314 {
315     // throw away cached pixmaps
316     int i;
317     for(i=0; i<m_size; i++)
318         pData[i].SetPixmap( NULL );
319 }
320 
321 sal_Bool  NWPixmapCache::Find( ControlType aType, ControlState aState, const Rectangle& r_pixmapRect, GdkPixmap** pPixmap )
322 {
323     aState &= ~CTRL_CACHING_ALLOWED; // mask clipping flag
324     int i;
325     for(i=0; i<m_size; i++)
326     {
327         if( pData[i].m_nType == aType &&
328             pData[i].m_nState == aState &&
329             pData[i].m_pixmapRect.GetWidth() == r_pixmapRect.GetWidth() &&
330             pData[i].m_pixmapRect.GetHeight() == r_pixmapRect.GetHeight() &&
331             pData[i].m_pixmap != NULL )
332         {
333             *pPixmap = pData[i].m_pixmap;
334             return sal_True;
335         }
336     }
337     return sal_False;
338 }
339 
340 void NWPixmapCache::Fill( ControlType aType, ControlState aState, const Rectangle& r_pixmapRect, GdkPixmap* pPixmap )
341 {
342     if( !(aState & CTRL_CACHING_ALLOWED) )
343         return;
344 
345     aState &= ~CTRL_CACHING_ALLOWED; // mask clipping flag
346     m_idx = (m_idx+1) % m_size; // just wrap
347     pData[m_idx].m_nType = aType;
348     pData[m_idx].m_nState = aState;
349     pData[m_idx].m_pixmapRect = r_pixmapRect;
350     pData[m_idx].SetPixmap( pPixmap );
351 }
352 
353 
354 void NWPixmapCacheList::AddCache( NWPixmapCache* pCache )
355 {
356     mCaches.push_back( pCache );
357 }
358 void NWPixmapCacheList::RemoveCache( NWPixmapCache* pCache )
359 {
360     ::std::vector< NWPixmapCache* >::iterator p;
361     p = ::std::find( mCaches.begin(), mCaches.end(), pCache );
362     if( p != mCaches.end() )
363         mCaches.erase( p );
364 }
365 void NWPixmapCacheList::ThemeChanged( )
366 {
367     ::std::vector< NWPixmapCache* >::iterator p = mCaches.begin();
368     while( p != mCaches.end() )
369     {
370         (*p)->ThemeChanged();
371         p++;
372     }
373 }
374 
375 
376 /*********************************************************
377  * Make border manipulation easier
378  *********************************************************/
379 inline void NW_gtk_border_set_from_border( GtkBorder& aDst, const GtkBorder * pSrc )
380 {
381     aDst.left       = pSrc->left;
382     aDst.top        = pSrc->top;
383     aDst.right  = pSrc->right;
384     aDst.bottom = pSrc->bottom;
385 }
386 
387 
388 /*********************************************************
389  * Initialize GTK and local stuff
390  *********************************************************/
391 void GtkData::initNWF( void )
392 {
393     ImplSVData* pSVData = ImplGetSVData();
394 
395     // draw no border for popup menus (NWF draws its own)
396     pSVData->maNWFData.mbFlatMenu = true;
397 
398     // draw separate buttons for toolbox dropdown items
399     pSVData->maNWFData.mbToolboxDropDownSeparate = true;
400 
401     // small extra border around menu items
402     pSVData->maNWFData.mnMenuFormatExtraBorder = 1;
403 
404     // draw toolbars in separate lines
405     pSVData->maNWFData.mbDockingAreaSeparateTB = true;
406 
407     // open first menu on F10
408     pSVData->maNWFData.mbOpenMenuOnF10 = true;
409 
410     // omit GetNativeControl while painting (see brdwin.cxx)
411     pSVData->maNWFData.mbCanDrawWidgetAnySize = true;
412 
413     int nScreens = GetX11SalData()->GetDisplay()->GetScreenCount();
414     gWidgetData = std::vector<NWFWidgetData>( nScreens );
415     for( int i = 0; i < nScreens; i++ )
416         gWidgetData[i].gNWPixmapCacheList = new NWPixmapCacheList;
417 
418 
419     if( SalGetDesktopEnvironment().equalsAscii( "KDE" ) )
420     {
421         // #i97196# ensure a widget exists and the style engine was loaded
422         NWEnsureGTKButton( 0 );
423         if( g_type_from_name( "QtEngineStyle" ) )
424         {
425             // KDE 3.3 invented a bug in the qt<->gtk theme engine
426             // that makes direct rendering impossible: they totally
427             // ignore the clip rectangle passed to the paint methods
428             GtkSalGraphics::bNeedPixmapPaint = GtkSalGraphics::bGlobalNeedPixmapPaint = true;
429         }
430     }
431     static const char* pEnv = getenv( "SAL_GTK_USE_PIXMAPPAINT" );
432     if( pEnv && *pEnv )
433         GtkSalGraphics::bNeedPixmapPaint = GtkSalGraphics::bGlobalNeedPixmapPaint = true;
434 
435     #if OSL_DEBUG_LEVEL > 1
436     std::fprintf( stderr, "GtkPlugin: using %s NWF\n",
437              GtkSalGraphics::bNeedPixmapPaint ? "offscreen" : "direct" );
438     #endif
439 }
440 
441 
442 /*********************************************************
443  * Release GTK and local stuff
444  *********************************************************/
445 void GtkData::deInitNWF( void )
446 {
447 
448     for( unsigned int i = 0; i < gWidgetData.size(); i++ )
449     {
450         // free up global widgets
451         // gtk_widget_destroy will in turn destroy the child hierarchy
452         // so only destroy disjunct hierachies
453         if( gWidgetData[i].gCacheWindow )
454             gtk_widget_destroy( gWidgetData[i].gCacheWindow );
455         if( gWidgetData[i].gMenuWidget )
456             gtk_widget_destroy( gWidgetData[i].gMenuWidget );
457         if( gWidgetData[i].gTooltipPopup )
458             gtk_widget_destroy( gWidgetData[i].gTooltipPopup );
459         delete gWidgetData[i].gCacheTabPages;
460         gWidgetData[i].gCacheTabPages = NULL;
461         delete gWidgetData[i].gCacheTabItems;
462         gWidgetData[i].gCacheTabItems = NULL;
463         delete gWidgetData[i].gNWPixmapCacheList;
464         gWidgetData[i].gNWPixmapCacheList = NULL;
465     }
466 }
467 
468 
469 /**********************************************************
470  * track clip region
471  **********************************************************/
472 void GtkSalGraphics::ResetClipRegion()
473 {
474     m_aClipRegion.SetNull();
475     X11SalGraphics::ResetClipRegion();
476 }
477 
478 bool GtkSalGraphics::setClipRegion( const Region& i_rClip )
479 {
480     m_aClipRegion = i_rClip;
481     bool bRet = X11SalGraphics::setClipRegion( m_aClipRegion );
482     if( m_aClipRegion.IsEmpty() )
483         m_aClipRegion.SetNull();
484     return bRet;
485 }
486 
487 void GtkSalGraphics::copyBits( const SalTwoRect* pPosAry,
488                                SalGraphics* pSrcGraphics )
489 {
490     GtkSalFrame* pFrame = GetGtkFrame();
491     XLIB_Window aWin = None;
492     if( pFrame && m_pWindow )
493     {
494         /* #i64117# some themes set the background pixmap VERY frequently */
495         GdkWindow* pWin = GTK_WIDGET(m_pWindow)->window;
496         if( pWin )
497         {
498             aWin = GDK_WINDOW_XWINDOW(pWin);
499             if( aWin != None )
500                 XSetWindowBackgroundPixmap( pFrame->getDisplay()->GetDisplay(),
501                                             aWin,
502                                             None );
503         }
504     }
505     X11SalGraphics::copyBits( pPosAry, pSrcGraphics );
506     if( pFrame && pFrame->getBackgroundPixmap() != None )
507         XSetWindowBackgroundPixmap( pFrame->getDisplay()->GetDisplay(),
508                                     aWin,
509                                     pFrame->getBackgroundPixmap() );
510 }
511 
512 /*
513  * IsNativeControlSupported()
514  *
515  *  Returns sal_True if the platform supports native
516  *  drawing of the control defined by nPart
517  */
518 sal_Bool GtkSalGraphics::IsNativeControlSupported( ControlType nType, ControlPart nPart )
519 {
520     if (
521         ((nType==CTRL_PUSHBUTTON)  && (nPart==PART_ENTIRE_CONTROL))     ||
522         ((nType==CTRL_RADIOBUTTON) && (nPart==PART_ENTIRE_CONTROL))     ||
523         ((nType==CTRL_CHECKBOX)    && (nPart==PART_ENTIRE_CONTROL))     ||
524         ((nType==CTRL_SCROLLBAR) &&
525                 (  (nPart==PART_DRAW_BACKGROUND_HORZ)
526                 || (nPart==PART_DRAW_BACKGROUND_VERT)
527                 || (nPart==PART_ENTIRE_CONTROL)
528                 || (nPart==HAS_THREE_BUTTONS) )                 )   ||
529         ((nType==CTRL_EDITBOX) &&
530                 (  (nPart==PART_ENTIRE_CONTROL)
531                 || (nPart==HAS_BACKGROUND_TEXTURE) )            )   ||
532         ((nType==CTRL_MULTILINE_EDITBOX) &&
533                 (  (nPart==PART_ENTIRE_CONTROL)
534                 || (nPart==HAS_BACKGROUND_TEXTURE) )            )   ||
535         ((nType==CTRL_SPINBOX) &&
536                 (  (nPart==PART_ENTIRE_CONTROL)
537                 || (nPart==PART_ALL_BUTTONS)
538                 || (nPart==HAS_BACKGROUND_TEXTURE) )            )   ||
539         ((nType==CTRL_SPINBUTTONS) &&
540                 (  (nPart==PART_ENTIRE_CONTROL)
541                 || (nPart==PART_ALL_BUTTONS)    )               )   ||
542         ((nType==CTRL_COMBOBOX) &&
543                 (  (nPart==PART_ENTIRE_CONTROL)
544                 || (nPart==HAS_BACKGROUND_TEXTURE)  )           )   ||
545         (((nType==CTRL_TAB_ITEM) || (nType==CTRL_TAB_PANE) ||
546           (nType==CTRL_TAB_BODY) || (nType==CTRL_FIXEDBORDER)) &&
547                 (  (nPart==PART_ENTIRE_CONTROL)
548                 || (nPart==PART_TABS_DRAW_RTL) )                )   ||
549         ((nType==CTRL_LISTBOX) &&
550                 (  (nPart==PART_ENTIRE_CONTROL)
551                 || (nPart==PART_WINDOW)
552                 || (nPart==HAS_BACKGROUND_TEXTURE) )            )   ||
553         ((nType == CTRL_TOOLBAR) &&
554                 (   (nPart==PART_ENTIRE_CONTROL)
555                 ||  (nPart==PART_DRAW_BACKGROUND_HORZ)
556                 ||  (nPart==PART_DRAW_BACKGROUND_VERT)
557                 ||  (nPart==PART_THUMB_HORZ)
558                 ||  (nPart==PART_THUMB_VERT)
559                 ||  (nPart==PART_BUTTON)
560                 )
561                                                                 )   ||
562         ((nType == CTRL_MENUBAR) &&
563                 (   (nPart==PART_ENTIRE_CONTROL) )              )   ||
564         ((nType == CTRL_TOOLTIP) &&
565                 (   (nPart==PART_ENTIRE_CONTROL) )              )   ||
566         ((nType == CTRL_MENU_POPUP) &&
567                 (   (nPart==PART_ENTIRE_CONTROL)
568                 ||  (nPart==PART_MENU_ITEM)
569                 ||  (nPart==PART_MENU_ITEM_CHECK_MARK)
570                 ||  (nPart==PART_MENU_ITEM_RADIO_MARK)
571                 )
572                                                                 )   ||
573         ((nType == CTRL_PROGRESS) &&
574                 (   (nPart == PART_ENTIRE_CONTROL) )
575                 )                                                   ||
576         ((nType == CTRL_LISTNODE || nType == CTRL_LISTNET) &&
577                 (   (nPart == PART_ENTIRE_CONTROL) )
578                 )                                                   ||
579         ((nType == CTRL_SLIDER) &&
580                 (   (nPart == PART_TRACK_HORZ_AREA)
581                 ||  (nPart == PART_TRACK_VERT_AREA)
582                 )
583         )
584         )
585         return( sal_True );
586 
587     return( sal_False );
588 }
589 
590 
591 /*
592  * HitTestNativeControl()
593  *
594  *  bIsInside is set to sal_True if aPos is contained within the
595  *  given part of the control, whose bounding region is
596  *  given by rControlRegion (in VCL frame coordinates).
597  *
598  *  returns whether bIsInside was really set.
599  */
600 sal_Bool GtkSalGraphics::hitTestNativeControl( ControlType      nType,
601                                 ControlPart     nPart,
602                                 const Rectangle&        rControlRegion,
603                                 const Point&        aPos,
604                                 sal_Bool&           rIsInside )
605 {
606     if ( ( nType == CTRL_SCROLLBAR ) &&
607          ( ( nPart == PART_BUTTON_UP ) ||
608            ( nPart == PART_BUTTON_DOWN ) ||
609            ( nPart == PART_BUTTON_LEFT ) ||
610            ( nPart == PART_BUTTON_RIGHT ) ) )
611     {
612         NWEnsureGTKScrollbars( m_nScreen );
613 
614         // Grab some button style attributes
615         gboolean has_forward;
616         gboolean has_forward2;
617         gboolean has_backward;
618         gboolean has_backward2;
619 
620         gtk_widget_style_get( gWidgetData[m_nScreen].gScrollHorizWidget, "has-forward-stepper", &has_forward,
621                                         "has-secondary-forward-stepper", &has_forward2,
622                                         "has-backward-stepper", &has_backward,
623                                         "has-secondary-backward-stepper", &has_backward2, (char *)NULL );
624         Rectangle aForward;
625         Rectangle aBackward;
626 
627         rIsInside = sal_False;
628 
629         ControlPart nCounterPart = 0;
630         if ( nPart == PART_BUTTON_UP )
631             nCounterPart = PART_BUTTON_DOWN;
632         else if ( nPart == PART_BUTTON_DOWN )
633             nCounterPart = PART_BUTTON_UP;
634         else if ( nPart == PART_BUTTON_LEFT )
635             nCounterPart = PART_BUTTON_RIGHT;
636         else if ( nPart == PART_BUTTON_RIGHT )
637             nCounterPart = PART_BUTTON_LEFT;
638 
639         aBackward = NWGetScrollButtonRect( m_nScreen, nPart, rControlRegion );
640         aForward = NWGetScrollButtonRect( m_nScreen, nCounterPart, rControlRegion );
641 
642         if ( has_backward && has_forward2 )
643         {
644             Size aSize( aBackward.GetSize() );
645             if ( ( nPart == PART_BUTTON_UP ) || ( nPart == PART_BUTTON_DOWN ) )
646                 aSize.setHeight( aBackward.GetHeight() / 2 );
647             else
648                 aSize.setWidth( aBackward.GetWidth() / 2 );
649             aBackward.SetSize( aSize );
650 
651             if ( nPart == PART_BUTTON_DOWN )
652                 aBackward.Move( 0, aBackward.GetHeight() / 2 );
653             else if ( nPart == PART_BUTTON_RIGHT )
654                 aBackward.Move( aBackward.GetWidth() / 2, 0 );
655         }
656 
657         if ( has_backward2 && has_forward )
658         {
659             Size aSize( aForward.GetSize() );
660             if ( ( nPart == PART_BUTTON_UP ) || ( nPart == PART_BUTTON_DOWN ) )
661                 aSize.setHeight( aForward.GetHeight() / 2 );
662             else
663                 aSize.setWidth( aForward.GetWidth() / 2 );
664             aForward.SetSize( aSize );
665 
666             if ( nPart == PART_BUTTON_DOWN )
667                 aForward.Move( 0, aForward.GetHeight() / 2 );
668             else if ( nPart == PART_BUTTON_RIGHT )
669                 aForward.Move( aForward.GetWidth() / 2, 0 );
670         }
671 
672         if ( ( nPart == PART_BUTTON_UP ) || ( nPart == PART_BUTTON_LEFT ) )
673         {
674             if ( has_backward )
675                 rIsInside |= aBackward.IsInside( aPos );
676             if ( has_backward2 )
677                 rIsInside |= aForward.IsInside( aPos );
678         }
679         else
680         {
681             if ( has_forward )
682                 rIsInside |= aBackward.IsInside( aPos );
683             if ( has_forward2 )
684                 rIsInside |= aForward.IsInside( aPos );
685         }
686         return ( sal_True );
687     }
688 
689     if( IsNativeControlSupported(nType, nPart) )
690     {
691         rIsInside = rControlRegion.IsInside( aPos );
692         return( sal_True );
693     }
694     else
695     {
696         return( sal_False );
697     }
698 }
699 
700 
701 /*
702  * DrawNativeControl()
703  *
704  *  Draws the requested control described by nPart/nState.
705  *
706  *  rControlRegion: The bounding region of the complete control in VCL frame coordinates.
707  *  aValue:         An optional value (tristate/numerical/string)
708  *  rCaption:   A caption or title string (like button text etc)
709  */
710 sal_Bool GtkSalGraphics::drawNativeControl( ControlType nType,
711                             ControlPart nPart,
712                             const Rectangle& rControlRegion,
713                             ControlState nState,
714                             const ImplControlValue& aValue,
715                             const OUString& rCaption )
716 {
717     sal_Bool            returnVal = sal_False;
718     // get a GC with current clipping region set
719     GetFontGC();
720 
721 
722     // theme changed ?
723     if( GtkSalGraphics::bThemeChanged )
724     {
725         // invalidate caches
726         for( unsigned int i = 0; i < gWidgetData.size(); i++ )
727             if( gWidgetData[i].gNWPixmapCacheList )
728                 gWidgetData[i].gNWPixmapCacheList->ThemeChanged();
729         GtkSalGraphics::bThemeChanged = sal_False;
730     }
731 
732     Rectangle aCtrlRect( rControlRegion );
733     Region aClipRegion( m_aClipRegion );
734     if( aClipRegion.IsNull() )
735         aClipRegion = aCtrlRect;
736 
737     clipList aClip;
738     GdkDrawable* gdkDrawable = GDK_DRAWABLE( GetGdkWindow() );
739     GdkPixmap* pixmap = NULL;
740     Rectangle aPixmapRect;
741     if( ( bNeedPixmapPaint )
742         && nType != CTRL_SCROLLBAR
743         && nType != CTRL_SPINBOX
744         && nType != CTRL_TAB_ITEM
745         && nType != CTRL_TAB_PANE
746         && nType != CTRL_PROGRESS
747         && ! (bToolbarGripWorkaround && nType == CTRL_TOOLBAR && (nPart == PART_THUMB_HORZ || nPart == PART_THUMB_VERT) )
748         )
749     {
750         // make pixmap a little larger since some themes draw decoration
751         // outside the rectangle, see e.g. checkbox
752         aPixmapRect = Rectangle( Point( aCtrlRect.Left()-1, aCtrlRect.Top()-1 ),
753                                  Size( aCtrlRect.GetWidth()+2, aCtrlRect.GetHeight()+2) );
754         pixmap = NWGetPixmapFromScreen( aPixmapRect );
755         if( ! pixmap )
756             return sal_False;
757         gdkDrawable = GDK_DRAWABLE( pixmap );
758         aCtrlRect = Rectangle( Point(1,1), aCtrlRect.GetSize() );
759         aClip.push_back( aCtrlRect );
760     }
761     else
762     {
763         RegionHandle aHdl = aClipRegion.BeginEnumRects();
764         Rectangle aPaintRect;
765         while( aClipRegion.GetNextEnumRect( aHdl, aPaintRect ) )
766         {
767             aPaintRect = aCtrlRect.GetIntersection( aPaintRect );
768             if( aPaintRect.IsEmpty() )
769                 continue;
770             aClip.push_back( aPaintRect );
771         }
772         aClipRegion.EndEnumRects( aHdl );
773     }
774 
775     if ( (nType==CTRL_PUSHBUTTON) && (nPart==PART_ENTIRE_CONTROL) )
776     {
777         returnVal = NWPaintGTKButton( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
778     }
779     else if ( (nType==CTRL_RADIOBUTTON) && (nPart==PART_ENTIRE_CONTROL) )
780     {
781         returnVal = NWPaintGTKRadio( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
782     }
783     else if ( (nType==CTRL_CHECKBOX) && (nPart==PART_ENTIRE_CONTROL) )
784     {
785         returnVal = NWPaintGTKCheck( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
786     }
787     else if ( (nType==CTRL_SCROLLBAR) && ((nPart==PART_DRAW_BACKGROUND_HORZ) || (nPart==PART_DRAW_BACKGROUND_VERT)) )
788     {
789         returnVal = NWPaintGTKScrollbar( nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
790     }
791     else if ( ((nType==CTRL_EDITBOX) && ((nPart==PART_ENTIRE_CONTROL) || (nPart==HAS_BACKGROUND_TEXTURE)) )
792         || ((nType==CTRL_SPINBOX) && (nPart==HAS_BACKGROUND_TEXTURE))
793     || ((nType==CTRL_COMBOBOX) && (nPart==HAS_BACKGROUND_TEXTURE))
794     || ((nType==CTRL_LISTBOX) && (nPart==HAS_BACKGROUND_TEXTURE)) )
795     {
796         returnVal = NWPaintGTKEditBox( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
797     }
798     else if ( ((nType==CTRL_MULTILINE_EDITBOX) && ((nPart==PART_ENTIRE_CONTROL) || (nPart==HAS_BACKGROUND_TEXTURE)) ) )
799     {
800         returnVal = NWPaintGTKEditBox( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
801     }
802     else if ( ((nType==CTRL_SPINBOX) || (nType==CTRL_SPINBUTTONS))
803         && ((nPart==PART_ENTIRE_CONTROL) || (nPart==PART_ALL_BUTTONS)) )
804     {
805         returnVal = NWPaintGTKSpinBox( nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
806     }
807     else if ( (nType == CTRL_COMBOBOX) &&
808         ( (nPart==PART_ENTIRE_CONTROL)
809         ||(nPart==PART_BUTTON_DOWN)
810         ) )
811     {
812         returnVal = NWPaintGTKComboBox( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
813     }
814     else if ( (nType==CTRL_TAB_ITEM) || (nType==CTRL_TAB_PANE) || (nType==CTRL_TAB_BODY) || (nType==CTRL_FIXEDBORDER) )
815     {
816         if ( nType == CTRL_TAB_BODY )
817             returnVal = sal_True;
818         else
819             returnVal = NWPaintGTKTabItem( nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption);
820     }
821     else if ( (nType==CTRL_LISTBOX) && ((nPart==PART_ENTIRE_CONTROL) || (nPart==PART_WINDOW)) )
822     {
823         returnVal = NWPaintGTKListBox( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
824     }
825     else if ( (nType== CTRL_TOOLBAR) )
826     {
827         returnVal = NWPaintGTKToolbar( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
828     }
829     else if ( (nType== CTRL_MENUBAR) )
830     {
831         returnVal = NWPaintGTKMenubar( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
832     }
833     else if(    (nType == CTRL_MENU_POPUP)
834         && (  (nPart == PART_ENTIRE_CONTROL)
835     || (nPart == PART_MENU_ITEM)
836     || (nPart == PART_MENU_ITEM_CHECK_MARK)
837     || (nPart == PART_MENU_ITEM_RADIO_MARK)
838     )
839     )
840     {
841         returnVal = NWPaintGTKPopupMenu( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
842     }
843     else if( (nType == CTRL_TOOLTIP) && (nPart == PART_ENTIRE_CONTROL) )
844     {
845         returnVal = NWPaintGTKTooltip( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
846     }
847     else if( (nType == CTRL_PROGRESS) && (nPart == PART_ENTIRE_CONTROL) )
848     {
849         returnVal = NWPaintGTKProgress( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
850     }
851     else if( (nType == CTRL_LISTNODE) && (nPart == PART_ENTIRE_CONTROL) )
852     {
853         returnVal = NWPaintGTKListNode( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
854     }
855     else if( (nType == CTRL_LISTNET) && (nPart == PART_ENTIRE_CONTROL) )
856     {
857         // don't actually draw anything; gtk treeviews do not draw lines
858         returnVal = true;
859     }
860     else if( (nType == CTRL_SLIDER) )
861     {
862         returnVal = NWPaintGTKSlider( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
863     }
864 
865     if( pixmap )
866     {
867         returnVal = NWRenderPixmapToScreen( pixmap, aPixmapRect ) && returnVal;
868         g_object_unref( pixmap );
869     }
870 
871     return( returnVal );
872 }
873 
874 /*
875  * DrawNativeControlText()
876  *
877  *  OPTIONAL.  Draws the requested text for the control described by nPart/nState.
878  *     Used if text not drawn by DrawNativeControl().
879  *
880  *  rControlRegion: The bounding region of the complete control in VCL frame coordinates.
881  *  aValue:         An optional value (tristate/numerical/string)
882  *  rCaption:   A caption or title string (like button text etc)
883  */
884 sal_Bool GtkSalGraphics::drawNativeControlText( ControlType,
885                                 ControlPart,
886                                 const Rectangle&,
887                                 ControlState,
888                                 const ImplControlValue&,
889                                 const OUString& )
890 {
891     return( sal_False );
892 }
893 
894 
895 /*
896  * GetNativeControlRegion()
897  *
898  *  If the return value is sal_True, rNativeBoundingRegion
899  *  contains the true bounding region covered by the control
900  *  including any adornment, while rNativeContentRegion contains the area
901  *  within the control that can be safely drawn into without drawing over
902  *  the borders of the control.
903  *
904  *  rControlRegion: The bounding region of the control in VCL frame coordinates.
905  *  aValue:     An optional value (tristate/numerical/string)
906  *  rCaption:       A caption or title string (like button text etc)
907  */
908 sal_Bool GtkSalGraphics::getNativeControlRegion(  ControlType nType,
909                                 ControlPart nPart,
910                                 const Rectangle& rControlRegion,
911                                 ControlState nState,
912                                 const ImplControlValue& aValue,
913                                 const OUString& rCaption,
914                                 Rectangle &rNativeBoundingRegion,
915                                 Rectangle &rNativeContentRegion )
916 {
917     sal_Bool returnVal = sal_False;
918 
919     if ( (nType==CTRL_PUSHBUTTON) && (nPart==PART_ENTIRE_CONTROL)
920         && (rControlRegion.GetWidth() > 16)
921     && (rControlRegion.GetHeight() > 16) )
922     {
923         rNativeBoundingRegion = NWGetButtonArea( m_nScreen, nType, nPart, rControlRegion,
924         nState, aValue, rCaption );
925         rNativeContentRegion = rControlRegion;
926 
927         returnVal = sal_True;
928     }
929     if ( (nType==CTRL_COMBOBOX) && ((nPart==PART_BUTTON_DOWN) || (nPart==PART_SUB_EDIT)) )
930     {
931         rNativeBoundingRegion = NWGetComboBoxButtonRect( m_nScreen, nType, nPart, rControlRegion, nState,
932         aValue, rCaption );
933         rNativeContentRegion = rNativeBoundingRegion;
934 
935         returnVal = sal_True;
936     }
937     if ( (nType==CTRL_SPINBOX) && ((nPart==PART_BUTTON_UP) || (nPart==PART_BUTTON_DOWN) || (nPart==PART_SUB_EDIT)) )
938     {
939 
940         rNativeBoundingRegion = NWGetSpinButtonRect( m_nScreen, nType, nPart, rControlRegion, nState,
941         aValue, rCaption );
942         rNativeContentRegion = rNativeBoundingRegion;
943 
944         returnVal = sal_True;
945     }
946     if ( (nType==CTRL_LISTBOX) && ((nPart==PART_BUTTON_DOWN) || (nPart==PART_SUB_EDIT)) )
947     {
948         rNativeBoundingRegion = NWGetListBoxButtonRect( m_nScreen, nType, nPart, rControlRegion, nState,
949         aValue, rCaption );
950         rNativeContentRegion = rNativeBoundingRegion;
951 
952         returnVal = sal_True;
953     }
954     if ( (nType==CTRL_TOOLBAR) &&
955         ((nPart==PART_DRAW_BACKGROUND_HORZ) ||
956         (nPart==PART_DRAW_BACKGROUND_VERT)  ||
957         (nPart==PART_THUMB_HORZ)            ||
958         (nPart==PART_THUMB_VERT)            ||
959         (nPart==PART_BUTTON)
960         ))
961     {
962         rNativeBoundingRegion = NWGetToolbarRect( m_nScreen, nType, nPart, rControlRegion, nState, aValue, rCaption );
963         rNativeContentRegion = rNativeBoundingRegion;
964         returnVal = sal_True;
965     }
966     if ( (nType==CTRL_SCROLLBAR) && ((nPart==PART_BUTTON_LEFT) || (nPart==PART_BUTTON_RIGHT) ||
967         (nPart==PART_BUTTON_UP) || (nPart==PART_BUTTON_DOWN)  ) )
968     {
969         rNativeBoundingRegion = NWGetScrollButtonRect( m_nScreen, nPart, rControlRegion );
970         rNativeContentRegion = rNativeBoundingRegion;
971 
972         returnVal = sal_True;
973     }
974     if( (nType == CTRL_MENUBAR) && (nPart == PART_ENTIRE_CONTROL) )
975     {
976         NWEnsureGTKMenubar( m_nScreen );
977         GtkRequisition aReq;
978         gtk_widget_size_request( gWidgetData[m_nScreen].gMenubarWidget, &aReq );
979         Rectangle aMenuBarRect = rControlRegion;
980         aMenuBarRect = Rectangle( aMenuBarRect.TopLeft(),
981                                   Size( aMenuBarRect.GetWidth(), aReq.height+1 ) );
982         rNativeBoundingRegion = aMenuBarRect;
983         rNativeContentRegion = rNativeBoundingRegion;
984         returnVal = sal_True;
985     }
986     if( (nType == CTRL_MENU_POPUP) )
987     {
988         if( (nPart == PART_MENU_ITEM_CHECK_MARK) ||
989             (nPart == PART_MENU_ITEM_RADIO_MARK) )
990         {
991             NWEnsureGTKMenu( m_nScreen );
992 
993             gint indicator_size = 0;
994             GtkWidget* pWidget = (nPart == PART_MENU_ITEM_CHECK_MARK) ?
995                                  gWidgetData[m_nScreen].gMenuItemCheckMenuWidget : gWidgetData[m_nScreen].gMenuItemRadioMenuWidget;
996             gtk_widget_style_get( pWidget,
997                                   "indicator_size", &indicator_size,
998                                   (char *)NULL );
999             rNativeBoundingRegion = rControlRegion;
1000             Rectangle aIndicatorRect( Point( 0,
1001                                              (rControlRegion.GetHeight()-indicator_size)/2),
1002                                       Size( indicator_size, indicator_size ) );
1003             rNativeContentRegion = aIndicatorRect;
1004             returnVal = sal_True;
1005         }
1006     }
1007     if( (nType == CTRL_RADIOBUTTON || nType == CTRL_CHECKBOX) )
1008     {
1009         NWEnsureGTKRadio( m_nScreen );
1010         NWEnsureGTKCheck( m_nScreen );
1011         GtkWidget* widget = (nType == CTRL_RADIOBUTTON) ? gWidgetData[m_nScreen].gRadioWidget : gWidgetData[m_nScreen].gCheckWidget;
1012         gint indicator_size, indicator_spacing;
1013         gtk_widget_style_get( widget,
1014                               "indicator_size", &indicator_size,
1015                               "indicator_spacing", &indicator_spacing,
1016                               (char *)NULL);
1017         indicator_size += 2*indicator_spacing; // guess overpaint of theme
1018         rNativeBoundingRegion = rControlRegion;
1019         Rectangle aIndicatorRect( Point( 0,
1020                                          (rControlRegion.GetHeight()-indicator_size)/2),
1021                                   Size( indicator_size, indicator_size ) );
1022         rNativeContentRegion = aIndicatorRect;
1023         returnVal = sal_True;
1024     }
1025     if( (nType == CTRL_EDITBOX || nType == CTRL_SPINBOX) && nPart == PART_ENTIRE_CONTROL )
1026     {
1027         NWEnsureGTKEditBox( m_nScreen );
1028         GtkWidget* widget = gWidgetData[m_nScreen].gEditBoxWidget;
1029         GtkRequisition aReq;
1030         gtk_widget_size_request( widget, &aReq );
1031         Rectangle aEditRect = rControlRegion;
1032         long nHeight = (aEditRect.GetHeight() > aReq.height+1) ? aEditRect.GetHeight() : aReq.height+1;
1033         aEditRect = Rectangle( aEditRect.TopLeft(),
1034                                Size( aEditRect.GetWidth(), nHeight ) );
1035         rNativeBoundingRegion = aEditRect;
1036         rNativeContentRegion = rNativeBoundingRegion;
1037         returnVal = sal_True;
1038     }
1039     if( (nType == CTRL_SLIDER) && (nPart == PART_THUMB_HORZ || nPart == PART_THUMB_VERT) )
1040     {
1041         NWEnsureGTKSlider( m_nScreen );
1042         GtkWidget* widget = (nPart == PART_THUMB_HORZ) ? gWidgetData[m_nScreen].gHScale : gWidgetData[m_nScreen].gVScale;
1043         gint slider_length = 10;
1044         gint slider_width = 10;
1045         gtk_widget_style_get( widget,
1046                               "slider-width", &slider_width,
1047                               "slider-length", &slider_length,
1048                               (char *)NULL);
1049         Rectangle aRect( rControlRegion );
1050         if( nPart == PART_THUMB_HORZ )
1051         {
1052             aRect.Right() = aRect.Left() + slider_length - 1;
1053             aRect.Bottom() = aRect.Top() + slider_width - 1;
1054         }
1055         else
1056         {
1057             aRect.Bottom() = aRect.Top() + slider_length - 1;
1058             aRect.Right() = aRect.Left() + slider_width - 1;
1059         }
1060         rNativeBoundingRegion = rNativeContentRegion = aRect;
1061         returnVal = sal_True;
1062     }
1063 
1064     return( returnVal );
1065 }
1066 
1067 
1068 /************************************************************************
1069  * Individual control drawing functions
1070  ************************************************************************/
1071 sal_Bool GtkSalGraphics::NWPaintGTKButton(
1072             GdkDrawable* gdkDrawable,
1073             ControlType, ControlPart,
1074             const Rectangle& rControlRectangle,
1075             const clipList& rClipList,
1076             ControlState nState, const ImplControlValue&,
1077             const OUString& )
1078 {
1079     GtkStateType    stateType;
1080     GtkShadowType   shadowType;
1081     gboolean        interiorFocus;
1082     gint            focusWidth;
1083     gint            focusPad;
1084     sal_Bool            bDrawFocus = sal_True;
1085     gint            x, y, w, h;
1086     GtkBorder       aDefBorder;
1087     GtkBorder*      pBorder;
1088     GdkRectangle    clipRect;
1089 
1090     NWEnsureGTKButton( m_nScreen );
1091     NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
1092 
1093     x = rControlRectangle.Left();
1094     y = rControlRectangle.Top();
1095     w = rControlRectangle.GetWidth();
1096     h = rControlRectangle.GetHeight();
1097 
1098     // Grab some button style attributes
1099     gtk_widget_style_get( gWidgetData[m_nScreen].gBtnWidget,    "focus-line-width", &focusWidth,
1100                                 "focus-padding",    &focusPad,
1101                                 "interior_focus",   &interiorFocus,
1102                                 "default_border",   &pBorder,
1103                                 (char *)NULL );
1104 
1105     // Make sure the border values exist, otherwise use some defaults
1106     if ( pBorder )
1107     {
1108         NW_gtk_border_set_from_border( aDefBorder, pBorder );
1109         gtk_border_free( pBorder );
1110     }
1111     else NW_gtk_border_set_from_border( aDefBorder, &aDefDefBorder );
1112 
1113     // If the button is too small, don't ever draw focus or grab more space
1114     if ( (w < 16) || (h < 16) )
1115         bDrawFocus = sal_False;
1116 
1117     NWSetWidgetState( gWidgetData[m_nScreen].gBtnWidget, nState, stateType );
1118 
1119     gint xi = x, yi = y, wi = w, hi = h;
1120     if ( (nState & CTRL_STATE_DEFAULT) && bDrawFocus )
1121     {
1122         xi += aDefBorder.left;
1123         yi += aDefBorder.top;
1124         wi -= aDefBorder.left + aDefBorder.right;
1125         hi -= aDefBorder.top + aDefBorder.bottom;
1126     }
1127 
1128     if ( !interiorFocus && bDrawFocus )
1129     {
1130         xi += focusWidth + focusPad;
1131         yi += focusWidth + focusPad;
1132         wi -= 2 * (focusWidth + focusPad);
1133         hi -= 2 * (focusWidth + focusPad);
1134     }
1135 
1136     for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it)
1137     {
1138         clipRect.x = it->Left();
1139         clipRect.y = it->Top();
1140         clipRect.width = it->GetWidth();
1141         clipRect.height = it->GetHeight();
1142 
1143         // Buttons must paint opaque since some themes have alpha-channel enabled buttons
1144         gtk_paint_flat_box( gWidgetData[m_nScreen].gBtnWidget->style, gdkDrawable, GTK_STATE_NORMAL, GTK_SHADOW_NONE,
1145                             &clipRect, m_pWindow, "base", x, y, w, h );
1146 
1147         if ( (nState & CTRL_STATE_DEFAULT) && (GTK_BUTTON(gWidgetData[m_nScreen].gBtnWidget)->relief == GTK_RELIEF_NORMAL) )
1148         {
1149             gtk_paint_box( gWidgetData[m_nScreen].gBtnWidget->style, gdkDrawable, GTK_STATE_NORMAL, GTK_SHADOW_IN,
1150                            &clipRect, gWidgetData[m_nScreen].gBtnWidget, "buttondefault", x, y, w, h );
1151         }
1152 
1153         if ( (GTK_BUTTON(gWidgetData[m_nScreen].gBtnWidget)->relief != GTK_RELIEF_NONE)
1154             || (nState & CTRL_STATE_PRESSED)
1155             || (nState & CTRL_STATE_ROLLOVER) )
1156         {
1157             gtk_paint_box( gWidgetData[m_nScreen].gBtnWidget->style, gdkDrawable, stateType, shadowType,
1158                            &clipRect, gWidgetData[m_nScreen].gBtnWidget, "button", xi, yi, wi, hi );
1159         }
1160     }
1161 #if 0 // VCL draws focus rects
1162     // Draw focus rect
1163     if ( (nState & CTRL_STATE_FOCUSED) && (nState & CTRL_STATE_ENABLED) && bDrawFocus )
1164     {
1165         if (interiorFocus)
1166         {
1167             x += gWidgetData[m_nScreen].gBtnWidget->style->xthickness + focusPad;
1168             y += gWidgetData[m_nScreen].gBtnWidget->style->ythickness + focusPad;
1169             w -= 2 * (gWidgetData[m_nScreen].gBtnWidget->style->xthickness + focusPad);
1170             h -=  2 * (gWidgetData[m_nScreen].gBtnWidget->style->xthickness + focusPad);
1171         }
1172         else
1173         {
1174             x -= focusWidth + focusPad;
1175             y -= focusWidth + focusPad;
1176             w += 2 * (focusWidth + focusPad);
1177             h += 2 * (focusWidth + focusPad);
1178         }
1179         if ( !interiorFocus )
1180             gtk_paint_focus( gWidgetData[m_nScreen].gBtnWidget->style, gdkDrawable, stateType, &clipRect,
1181                              gWidgetData[m_nScreen].gBtnWidget, "button", x, y, w, h );
1182     }
1183 #endif
1184 
1185     return( sal_True );
1186 }
1187 
1188 static Rectangle NWGetButtonArea( int nScreen,
1189                                   ControlType, ControlPart, Rectangle aAreaRect, ControlState nState,
1190                                   const ImplControlValue&, const OUString& )
1191 {
1192     gboolean        interiorFocus;
1193     gint            focusWidth;
1194     gint            focusPad;
1195     GtkBorder       aDefBorder;
1196     GtkBorder * pBorder;
1197     sal_Bool            bDrawFocus = sal_True;
1198     Rectangle       aRect;
1199     gint            x, y, w, h;
1200 
1201     NWEnsureGTKButton( nScreen );
1202     gtk_widget_style_get( gWidgetData[nScreen].gBtnWidget,
1203                                 "focus-line-width", &focusWidth,
1204                                 "focus-padding",    &focusPad,
1205                                 "interior_focus",   &interiorFocus,
1206                                 "default_border",   &pBorder,
1207                                 (char *)NULL );
1208 
1209     // Make sure the border values exist, otherwise use some defaults
1210     if ( pBorder )
1211     {
1212         NW_gtk_border_set_from_border( aDefBorder, pBorder );
1213         gtk_border_free( pBorder );
1214     }
1215     else NW_gtk_border_set_from_border( aDefBorder, &aDefDefBorder );
1216 
1217     x = aAreaRect.Left();
1218     y = aAreaRect.Top();
1219     w = aAreaRect.GetWidth();
1220     h = aAreaRect.GetHeight();
1221 
1222     // If the button is too small, don't ever draw focus or grab more space
1223     if ( (w < 16) || (h < 16) )
1224         bDrawFocus = sal_False;
1225 
1226     if ( (nState & CTRL_STATE_DEFAULT) && bDrawFocus )
1227     {
1228         x -= aDefBorder.left;
1229         y -= aDefBorder.top;
1230         w += aDefBorder.left + aDefBorder.right;
1231         h += aDefBorder.top + aDefBorder.bottom;
1232     }
1233 
1234     aRect = Rectangle( Point( x, y ), Size( w, h ) );
1235 
1236     return( aRect );
1237 }
1238 
1239 //-------------------------------------
1240 
1241 sal_Bool GtkSalGraphics::NWPaintGTKRadio( GdkDrawable* gdkDrawable,
1242                                       ControlType, ControlPart,
1243                                       const Rectangle& rControlRectangle,
1244                                       const clipList& rClipList,
1245                                       ControlState nState,
1246                                       const ImplControlValue& aValue,
1247                                       const OUString& )
1248 {
1249     GtkStateType    stateType;
1250     GtkShadowType   shadowType;
1251     sal_Bool            isChecked = (aValue.getTristateVal()==BUTTONVALUE_ON);
1252     gint            x, y;
1253     GdkRectangle    clipRect;
1254 
1255     NWEnsureGTKButton( m_nScreen );
1256     NWEnsureGTKRadio( m_nScreen );
1257     NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
1258 
1259     gint indicator_size;
1260     gtk_widget_style_get( gWidgetData[m_nScreen].gRadioWidget, "indicator_size", &indicator_size, (char *)NULL);
1261 
1262     x = rControlRectangle.Left() + (rControlRectangle.GetWidth()-indicator_size)/2;
1263     y = rControlRectangle.Top() + (rControlRectangle.GetHeight()-indicator_size)/2;
1264 
1265     // Set the shadow based on if checked or not so we get a freakin checkmark.
1266     shadowType = isChecked ? GTK_SHADOW_IN : GTK_SHADOW_OUT;
1267     NWSetWidgetState( gWidgetData[m_nScreen].gRadioWidget, nState, stateType );
1268     NWSetWidgetState( gWidgetData[m_nScreen].gRadioWidgetSibling, nState, stateType );
1269 
1270     // GTK enforces radio groups, so that if we don't have 2 buttons in the group,
1271     // the single button will always be active.  So we have to have 2 buttons.
1272 
1273     // #i59666# set the members directly where we should use
1274     // gtk_toggle_button_set_active. reason: there are animated themes
1275     // which are in active state only after a while leading to painting
1276     // intermediate states between active/inactive. Let's hope that
1277     // GtkToggleButtone stays binary compatible.
1278     if (!isChecked)
1279         GTK_TOGGLE_BUTTON(gWidgetData[m_nScreen].gRadioWidgetSibling)->active = sal_True;
1280     GTK_TOGGLE_BUTTON(gWidgetData[m_nScreen].gRadioWidget)->active = isChecked;
1281 
1282     for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it )
1283     {
1284         clipRect.x = it->Left();
1285         clipRect.y = it->Top();
1286         clipRect.width = it->GetWidth();
1287         clipRect.height = it->GetHeight();
1288 
1289         gtk_paint_option( gWidgetData[m_nScreen].gRadioWidget->style, gdkDrawable, stateType, shadowType,
1290                           &clipRect, gWidgetData[m_nScreen].gRadioWidget, "radiobutton",
1291                           x, y, indicator_size, indicator_size );
1292     }
1293 
1294     return( sal_True );
1295 }
1296 
1297 //-------------------------------------
1298 
1299 sal_Bool GtkSalGraphics::NWPaintGTKCheck( GdkDrawable* gdkDrawable,
1300                                       ControlType, ControlPart,
1301                                       const Rectangle& rControlRectangle,
1302                                       const clipList& rClipList,
1303                                       ControlState nState,
1304                                       const ImplControlValue& aValue,
1305                                       const OUString& )
1306 {
1307     GtkStateType    stateType;
1308     GtkShadowType   shadowType;
1309     bool            isChecked = (aValue.getTristateVal() == BUTTONVALUE_ON);
1310     bool            isInconsistent = (aValue.getTristateVal() == BUTTONVALUE_MIXED);
1311     GdkRectangle    clipRect;
1312     gint            x,y;
1313 
1314     NWEnsureGTKButton( m_nScreen );
1315     NWEnsureGTKCheck( m_nScreen );
1316     NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
1317 
1318     gint indicator_size;
1319     gtk_widget_style_get( gWidgetData[m_nScreen].gCheckWidget, "indicator_size", &indicator_size, (char *)NULL);
1320 
1321     x = rControlRectangle.Left() + (rControlRectangle.GetWidth()-indicator_size)/2;
1322     y = rControlRectangle.Top() + (rControlRectangle.GetHeight()-indicator_size)/2;
1323 
1324     // Set the shadow based on if checked or not so we get a checkmark.
1325     shadowType = isChecked ? GTK_SHADOW_IN : isInconsistent ? GTK_SHADOW_ETCHED_IN : GTK_SHADOW_OUT;
1326     NWSetWidgetState( gWidgetData[m_nScreen].gCheckWidget, nState, stateType );
1327     GTK_TOGGLE_BUTTON(gWidgetData[m_nScreen].gCheckWidget)->active = isChecked;
1328 
1329     for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it )
1330     {
1331         clipRect.x = it->Left();
1332         clipRect.y = it->Top();
1333         clipRect.width = it->GetWidth();
1334         clipRect.height = it->GetHeight();
1335 
1336         gtk_paint_check( gWidgetData[m_nScreen].gCheckWidget->style, gdkDrawable, stateType, shadowType,
1337                          &clipRect, gWidgetData[m_nScreen].gCheckWidget, "checkbutton",
1338                          x, y, indicator_size, indicator_size );
1339     }
1340 
1341     return( sal_True );
1342 }
1343 
1344 //-------------------------------------
1345 static void NWCalcArrowRect( const Rectangle& rButton, Rectangle& rArrow )
1346 {
1347     // Size the arrow appropriately
1348     Size aSize( rButton.GetWidth()/2, rButton.GetHeight()/2 );
1349     rArrow.SetSize( aSize );
1350 
1351     rArrow.SetPos( Point(
1352         rButton.Left() + ( rButton.GetWidth()  - rArrow.GetWidth()  ) / 2,
1353         rButton.Top() + ( rButton.GetHeight() - rArrow.GetHeight() ) / 2
1354         ) );
1355 }
1356 
1357 sal_Bool GtkSalGraphics::NWPaintGTKScrollbar( ControlType, ControlPart nPart,
1358                                           const Rectangle& rControlRectangle,
1359                                           const clipList&,
1360                                           ControlState nState,
1361                                           const ImplControlValue& aValue,
1362                                           const OUString& )
1363 {
1364     OSL_ASSERT( aValue.getType() == CTRL_SCROLLBAR );
1365     const ScrollbarValue* pScrollbarVal = static_cast<const ScrollbarValue *>(&aValue);
1366     GdkPixmap*      pixmap = NULL;
1367     Rectangle       pixmapRect, scrollbarRect;
1368     GtkStateType    stateType;
1369     GtkShadowType   shadowType;
1370     GtkScrollbar *  scrollbarWidget;
1371     GtkStyle *  style;
1372     GtkAdjustment* scrollbarValues = NULL;
1373     GtkOrientation  scrollbarOrientation;
1374     Rectangle       thumbRect = pScrollbarVal->maThumbRect;
1375     Rectangle       button11BoundRect = pScrollbarVal->maButton1Rect;   // backward
1376     Rectangle       button22BoundRect = pScrollbarVal->maButton2Rect;   // forward
1377     Rectangle       button12BoundRect = pScrollbarVal->maButton1Rect;   // secondary forward
1378     Rectangle       button21BoundRect = pScrollbarVal->maButton2Rect;   // secondary backward
1379     GtkArrowType    button1Type;                                        // backward
1380     GtkArrowType    button2Type;                                        // forward
1381     gchar *     scrollbarTagH = (gchar *) "hscrollbar";
1382     gchar *     scrollbarTagV = (gchar *) "vscrollbar";
1383     gchar *     scrollbarTag = NULL;
1384     Rectangle       arrowRect;
1385     gint            slider_width = 0;
1386     gint            stepper_size = 0;
1387     gint            stepper_spacing = 0;
1388     gint            trough_border = 0;
1389     gint            min_slider_length = 0;
1390     gint            vShim = 0;
1391     gint            hShim = 0;
1392     gint            x,y,w,h;
1393 
1394     // make controlvalue rectangles relative to area
1395     thumbRect.Move( -rControlRectangle.Left(), -rControlRectangle.Top() );
1396     button11BoundRect.Move( -rControlRectangle.Left(), -rControlRectangle.Top() );
1397     button22BoundRect.Move( -rControlRectangle.Left(), -rControlRectangle.Top() );
1398     button12BoundRect.Move( -rControlRectangle.Left(), -rControlRectangle.Top() );
1399     button21BoundRect.Move( -rControlRectangle.Left(), -rControlRectangle.Top() );
1400 
1401     NWEnsureGTKButton( m_nScreen );
1402     NWEnsureGTKScrollbars( m_nScreen );
1403     NWEnsureGTKArrow( m_nScreen );
1404 
1405     // Find the overall bounding rect of the control
1406     pixmapRect = rControlRectangle;
1407     pixmapRect.SetSize( Size( pixmapRect.GetWidth() + 1,
1408                               pixmapRect.GetHeight() + 1 ) );
1409     scrollbarRect = pixmapRect;
1410 
1411     if ( (scrollbarRect.GetWidth() <= 1) || (scrollbarRect.GetHeight() <= 1) )
1412         return( sal_True );
1413 
1414     // Grab some button style attributes
1415     gtk_widget_style_get( gWidgetData[m_nScreen].gScrollHorizWidget,
1416                                       "slider_width", &slider_width,
1417                                       "stepper_size", &stepper_size,
1418                                       "trough_border", &trough_border,
1419                                       "stepper_spacing", &stepper_spacing,
1420                                       "min_slider_length", &min_slider_length, (char *)NULL );
1421     gboolean has_forward;
1422     gboolean has_forward2;
1423     gboolean has_backward;
1424     gboolean has_backward2;
1425 
1426     gtk_widget_style_get( gWidgetData[m_nScreen].gScrollHorizWidget, "has-forward-stepper", &has_forward,
1427                                       "has-secondary-forward-stepper", &has_forward2,
1428                                       "has-backward-stepper", &has_backward,
1429                                       "has-secondary-backward-stepper", &has_backward2, (char *)NULL );
1430     gint magic = trough_border ? 1 : 0;
1431     gint nFirst = 0;
1432 
1433     if ( has_backward )  nFirst  += 1;
1434     if ( has_forward2 )  nFirst  += 1;
1435 
1436     if ( nPart == PART_DRAW_BACKGROUND_HORZ )
1437     {
1438         unsigned int sliderHeight = slider_width + (trough_border * 2);
1439         vShim = (pixmapRect.GetHeight() - sliderHeight) / 2;
1440 
1441         scrollbarRect.Move( 0, vShim );
1442         scrollbarRect.SetSize( Size( scrollbarRect.GetWidth(), sliderHeight ) );
1443 
1444         scrollbarWidget = GTK_SCROLLBAR( gWidgetData[m_nScreen].gScrollHorizWidget );
1445         scrollbarOrientation = GTK_ORIENTATION_HORIZONTAL;
1446         scrollbarTag = scrollbarTagH;
1447         button1Type = GTK_ARROW_LEFT;
1448         button2Type = GTK_ARROW_RIGHT;
1449 
1450         if ( has_backward )
1451         {
1452             button12BoundRect.Move( stepper_size - trough_border,
1453                                     (scrollbarRect.GetHeight() - slider_width) / 2 );
1454         }
1455 
1456         button11BoundRect.Move( trough_border, (scrollbarRect.GetHeight() - slider_width) / 2 );
1457         button11BoundRect.SetSize( Size( stepper_size, slider_width ) );
1458         button12BoundRect.SetSize( Size( stepper_size, slider_width ) );
1459 
1460         if ( has_backward2 )
1461         {
1462             button22BoundRect.Move( stepper_size+(trough_border+1)/2, (scrollbarRect.GetHeight() - slider_width) / 2 );
1463             button21BoundRect.Move( (trough_border+1)/2, (scrollbarRect.GetHeight() - slider_width) / 2 );
1464         }
1465         else
1466         {
1467             button22BoundRect.Move( (trough_border+1)/2, (scrollbarRect.GetHeight() - slider_width) / 2 );
1468         }
1469 
1470         button21BoundRect.SetSize( Size( stepper_size, slider_width ) );
1471         button22BoundRect.SetSize( Size( stepper_size, slider_width ) );
1472 
1473         thumbRect.Bottom() = thumbRect.Top() + slider_width - 1;
1474         // Make sure the thumb is at least the default width (so we don't get tiny thumbs),
1475         // but if the VCL gives us a size smaller than the theme's default thumb size,
1476         // honor the VCL size
1477 #if 0
1478         if ( (thumbRect.GetWidth() < min_slider_length)
1479             && ((scrollbarRect.GetWidth()-button1BoundRect.GetWidth()-button2BoundRect.GetWidth()) > min_slider_length) )
1480             thumbRect.SetSize( Size( min_slider_length, thumbRect.GetHeight() ) );
1481 #endif
1482 
1483         thumbRect.Right() += magic;
1484         // Center vertically in the track
1485         thumbRect.Move( 0, (scrollbarRect.GetHeight() - slider_width) / 2 );
1486     }
1487     else
1488     {
1489         unsigned int sliderWidth = slider_width + (trough_border * 2);
1490         hShim = (pixmapRect.GetWidth() - sliderWidth) / 2;
1491 
1492         scrollbarRect.Move( hShim, 0 );
1493         scrollbarRect.SetSize( Size( sliderWidth, scrollbarRect.GetHeight() ) );
1494 
1495         scrollbarWidget = GTK_SCROLLBAR( gWidgetData[m_nScreen].gScrollVertWidget );
1496         scrollbarOrientation = GTK_ORIENTATION_VERTICAL;
1497         scrollbarTag = scrollbarTagV;
1498         button1Type = GTK_ARROW_UP;
1499         button2Type = GTK_ARROW_DOWN;
1500 
1501         if ( has_backward )
1502         {
1503             button12BoundRect.Move( (scrollbarRect.GetWidth() - slider_width) / 2,
1504                                     stepper_size + trough_border );
1505         }
1506         button11BoundRect.Move( (scrollbarRect.GetWidth() - slider_width) / 2, trough_border );
1507         button11BoundRect.SetSize( Size( slider_width, stepper_size ) );
1508         button12BoundRect.SetSize( Size( slider_width, stepper_size ) );
1509 
1510         if ( has_backward2 )
1511         {
1512             button22BoundRect.Move( (scrollbarRect.GetWidth() - slider_width) / 2, stepper_size+(trough_border+1)/2 );
1513             button21BoundRect.Move( (scrollbarRect.GetWidth() - slider_width) / 2, (trough_border+1)/2 );
1514         }
1515         else
1516         {
1517             button22BoundRect.Move( (scrollbarRect.GetWidth() - slider_width) / 2, (trough_border+1)/2 );
1518         }
1519 
1520         button21BoundRect.SetSize( Size( slider_width, stepper_size ) );
1521         button22BoundRect.SetSize( Size( slider_width, stepper_size ) );
1522 
1523         thumbRect.Right() = thumbRect.Left() + slider_width - 1;
1524 #if 0
1525         // Make sure the thumb is at least the default width (so we don't get tiny thumbs),
1526         // but if the VCL gives us a size smaller than the theme's default thumb size,
1527         // honor the VCL size
1528         if ( (thumbRect.GetHeight() < min_slider_length)
1529             && ((scrollbarRect.GetHeight()-button1BoundRect.GetHeight()-button2BoundRect.GetHeight()) > min_slider_length) )
1530             thumbRect.SetSize( Size( thumbRect.GetWidth(), min_slider_length ) );
1531 #endif
1532 
1533         thumbRect.Bottom() += magic;
1534         // Center horizontally in the track
1535         thumbRect.Move( (scrollbarRect.GetWidth() - slider_width) / 2, 0 );
1536     }
1537 
1538     sal_Bool has_slider = ( thumbRect.GetWidth() > 0 && thumbRect.GetHeight() > 0 );
1539 
1540     scrollbarValues = gtk_range_get_adjustment( GTK_RANGE(scrollbarWidget) );
1541     if ( scrollbarValues == NULL )
1542         scrollbarValues = GTK_ADJUSTMENT( gtk_adjustment_new(0, 0, 0, 0, 0, 0) );
1543     if ( nPart == PART_DRAW_BACKGROUND_HORZ )
1544     {
1545         scrollbarValues->lower = pScrollbarVal->mnMin;
1546         scrollbarValues->upper = pScrollbarVal->mnMax;
1547         scrollbarValues->value = pScrollbarVal->mnCur;
1548         scrollbarValues->page_size = scrollbarRect.GetWidth() / 2;
1549     }
1550     else
1551     {
1552         scrollbarValues->lower = pScrollbarVal->mnMin;
1553         scrollbarValues->upper = pScrollbarVal->mnMax;
1554         scrollbarValues->value = pScrollbarVal->mnCur;
1555         scrollbarValues->page_size = scrollbarRect.GetHeight() / 2;
1556     }
1557     gtk_adjustment_changed( scrollbarValues );
1558 
1559     // as multiple paints are required for the scrollbar
1560     // painting them directly to the window flickers
1561     pixmap = NWGetPixmapFromScreen( pixmapRect );
1562     if( ! pixmap )
1563         return sal_False;
1564     x = y = 0;
1565 
1566     w = pixmapRect.GetWidth();
1567     h = pixmapRect.GetHeight();
1568 
1569     GdkDrawable* const &gdkDrawable = GDK_DRAWABLE( pixmap );
1570     GdkRectangle* gdkRect = NULL;
1571 
1572     NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
1573     NWSetWidgetState( GTK_WIDGET(scrollbarWidget), nState, stateType );
1574     NWSetWidgetState( gWidgetData[m_nScreen].gBtnWidget, nState, stateType );
1575     style = GTK_WIDGET( scrollbarWidget )->style;
1576 
1577     // ----------------- TROUGH
1578     gtk_paint_flat_box( gWidgetData[m_nScreen].gBtnWidget->style, gdkDrawable,
1579                         GTK_STATE_NORMAL, GTK_SHADOW_NONE, gdkRect,
1580                         m_pWindow, "base", x, y,
1581                         w, h );
1582     gtk_paint_box( style, gdkDrawable, GTK_STATE_ACTIVE, GTK_SHADOW_IN,
1583                    gdkRect, GTK_WIDGET(scrollbarWidget), "trough",
1584                    x, y,
1585                    scrollbarRect.GetWidth(), scrollbarRect.GetHeight() );
1586 
1587     if ( nState & CTRL_STATE_FOCUSED )
1588     {
1589         gtk_paint_focus( style, gdkDrawable, GTK_STATE_ACTIVE,
1590                          gdkRect, GTK_WIDGET(scrollbarWidget), "trough",
1591                          x, y,
1592                          scrollbarRect.GetWidth(), scrollbarRect.GetHeight() );
1593     }
1594 
1595     // ----------------- THUMB
1596     if ( has_slider )
1597     {
1598         NWConvertVCLStateToGTKState( pScrollbarVal->mnThumbState, &stateType, &shadowType );
1599         if ( pScrollbarVal->mnThumbState & CTRL_STATE_PRESSED )  stateType = GTK_STATE_PRELIGHT;
1600         gtk_paint_slider( style, gdkDrawable, stateType, GTK_SHADOW_OUT,
1601                         gdkRect, GTK_WIDGET(scrollbarWidget), "slider",
1602                         x+hShim+thumbRect.Left(), y+vShim+thumbRect.Top(),
1603                         thumbRect.GetWidth(), thumbRect.GetHeight(), scrollbarOrientation );
1604     }
1605     // ----------------- BUTTON 1 //
1606     if ( has_backward )
1607     {
1608         NWConvertVCLStateToGTKState( pScrollbarVal->mnButton1State, &stateType, &shadowType );
1609         if ( stateType == GTK_STATE_INSENSITIVE )   stateType = GTK_STATE_NORMAL;
1610         gtk_paint_box( style, gdkDrawable, stateType, shadowType,
1611                        gdkRect, GTK_WIDGET(scrollbarWidget), "stepper",
1612                        x+hShim+button11BoundRect.Left(), y+vShim+button11BoundRect.Top(),
1613                        button11BoundRect.GetWidth(), button11BoundRect.GetHeight() );
1614         // ----------------- ARROW 1
1615         NWCalcArrowRect( button11BoundRect, arrowRect );
1616         gtk_paint_arrow( style, gdkDrawable, stateType, shadowType,
1617                          gdkRect, GTK_WIDGET(scrollbarWidget), scrollbarTag, button1Type, sal_True,
1618                          x+hShim+arrowRect.Left(), y+vShim+arrowRect.Top(),
1619                          arrowRect.GetWidth(), arrowRect.GetHeight() );
1620     }
1621     if ( has_forward2 )
1622     {
1623         NWConvertVCLStateToGTKState( pScrollbarVal->mnButton2State, &stateType, &shadowType );
1624         if ( stateType == GTK_STATE_INSENSITIVE )   stateType = GTK_STATE_NORMAL;
1625         gtk_paint_box( style, gdkDrawable, stateType, shadowType,
1626                        gdkRect, GTK_WIDGET(scrollbarWidget), "stepper",
1627                        x+hShim+button12BoundRect.Left(), y+vShim+button12BoundRect.Top(),
1628                        button12BoundRect.GetWidth(), button12BoundRect.GetHeight() );
1629         // ----------------- ARROW 1
1630         NWCalcArrowRect( button12BoundRect, arrowRect );
1631         gtk_paint_arrow( style, gdkDrawable, stateType, shadowType,
1632                          gdkRect, GTK_WIDGET(scrollbarWidget), scrollbarTag, button2Type, sal_True,
1633                          x+hShim+arrowRect.Left(), y+vShim+arrowRect.Top(),
1634                          arrowRect.GetWidth(), arrowRect.GetHeight() );
1635     }
1636     // ----------------- BUTTON 2
1637     if ( has_backward2 )
1638     {
1639         NWConvertVCLStateToGTKState( pScrollbarVal->mnButton1State, &stateType, &shadowType );
1640         if ( stateType == GTK_STATE_INSENSITIVE )   stateType = GTK_STATE_NORMAL;
1641         gtk_paint_box( style, gdkDrawable, stateType, shadowType, gdkRect,
1642                        GTK_WIDGET(scrollbarWidget), "stepper",
1643                        x+hShim+button21BoundRect.Left(), y+vShim+button21BoundRect.Top(),
1644                        button21BoundRect.GetWidth(), button21BoundRect.GetHeight() );
1645         // ----------------- ARROW 2
1646         NWCalcArrowRect( button21BoundRect, arrowRect );
1647         gtk_paint_arrow( style, gdkDrawable, stateType, shadowType,
1648                          gdkRect, GTK_WIDGET(scrollbarWidget), scrollbarTag, button1Type, sal_True,
1649                          x+hShim+arrowRect.Left(), y+vShim+arrowRect.Top(),
1650                          arrowRect.GetWidth(), arrowRect.GetHeight() );
1651     }
1652     if ( has_forward )
1653     {
1654         NWConvertVCLStateToGTKState( pScrollbarVal->mnButton2State, &stateType, &shadowType );
1655         if ( stateType == GTK_STATE_INSENSITIVE )   stateType = GTK_STATE_NORMAL;
1656         gtk_paint_box( style, gdkDrawable, stateType, shadowType, gdkRect,
1657                        GTK_WIDGET(scrollbarWidget), "stepper",
1658                        x+hShim+button22BoundRect.Left(), y+vShim+button22BoundRect.Top(),
1659                        button22BoundRect.GetWidth(), button22BoundRect.GetHeight() );
1660         // ----------------- ARROW 2
1661         NWCalcArrowRect( button22BoundRect, arrowRect );
1662         gtk_paint_arrow( style, gdkDrawable, stateType, shadowType,
1663                          gdkRect, GTK_WIDGET(scrollbarWidget), scrollbarTag, button2Type, sal_True,
1664                          x+hShim+arrowRect.Left(), y+vShim+arrowRect.Top(),
1665                          arrowRect.GetWidth(), arrowRect.GetHeight() );
1666     }
1667 
1668     if( !NWRenderPixmapToScreen(pixmap, pixmapRect) )
1669     {
1670         g_object_unref( pixmap );
1671         return( sal_False );
1672     }
1673     g_object_unref( pixmap );
1674 
1675     return( sal_True );
1676 }
1677 
1678 //---
1679 
1680 static Rectangle NWGetScrollButtonRect( int nScreen, ControlPart nPart, Rectangle aAreaRect )
1681 {
1682     gint slider_width;
1683     gint stepper_size;
1684     gint stepper_spacing;
1685     gint trough_border;
1686 
1687     NWEnsureGTKScrollbars( nScreen );
1688 
1689     // Grab some button style attributes
1690     gtk_widget_style_get( gWidgetData[nScreen].gScrollHorizWidget,
1691                                       "slider-width", &slider_width,
1692                                       "stepper-size", &stepper_size,
1693                                       "trough-border", &trough_border,
1694                                       "stepper-spacing", &stepper_spacing, (char *)NULL );
1695 
1696     gboolean has_forward;
1697     gboolean has_forward2;
1698     gboolean has_backward;
1699     gboolean has_backward2;
1700 
1701     gtk_widget_style_get( gWidgetData[nScreen].gScrollHorizWidget,
1702                                       "has-forward-stepper", &has_forward,
1703                                       "has-secondary-forward-stepper", &has_forward2,
1704                                       "has-backward-stepper", &has_backward,
1705                                       "has-secondary-backward-stepper", &has_backward2, (char *)NULL );
1706     gint       buttonWidth;
1707     gint       buttonHeight;
1708     Rectangle  buttonRect;
1709 
1710     gint nFirst = 0;
1711     gint nSecond = 0;
1712 
1713     if ( has_forward )   nSecond += 1;
1714     if ( has_forward2 )  nFirst  += 1;
1715     if ( has_backward )  nFirst  += 1;
1716     if ( has_backward2 ) nSecond += 1;
1717 
1718     if ( ( nPart == PART_BUTTON_UP ) || ( nPart == PART_BUTTON_DOWN ) )
1719     {
1720         buttonWidth = slider_width + 2 * trough_border;
1721         buttonHeight = stepper_size + trough_border + stepper_spacing;
1722     }
1723     else
1724     {
1725         buttonWidth = stepper_size + trough_border + stepper_spacing;
1726         buttonHeight = slider_width + 2 * trough_border;
1727     }
1728 
1729     if ( nPart == PART_BUTTON_UP )
1730     {
1731         buttonHeight *= nFirst;
1732         buttonHeight -= 1;
1733         buttonRect.setX( aAreaRect.Left() );
1734         buttonRect.setY( aAreaRect.Top() );
1735     }
1736     else if ( nPart == PART_BUTTON_LEFT )
1737     {
1738         buttonWidth *= nFirst;
1739         buttonWidth -= 1;
1740         buttonRect.setX( aAreaRect.Left() );
1741         buttonRect.setY( aAreaRect.Top() );
1742     }
1743     else if ( nPart == PART_BUTTON_DOWN )
1744     {
1745         buttonHeight *= nSecond;
1746         buttonRect.setX( aAreaRect.Left() );
1747         buttonRect.setY( aAreaRect.Top() + aAreaRect.GetHeight() - buttonHeight );
1748     }
1749     else if ( nPart == PART_BUTTON_RIGHT )
1750     {
1751         buttonWidth *= nSecond;
1752         buttonRect.setX( aAreaRect.Left() + aAreaRect.GetWidth() - buttonWidth );
1753         buttonRect.setY( aAreaRect.Top() );
1754     }
1755 
1756     buttonRect.SetSize( Size( buttonWidth, buttonHeight ) );
1757 
1758     return( buttonRect );
1759 }
1760 
1761 //-------------------------------------
1762 
1763 sal_Bool GtkSalGraphics::NWPaintGTKEditBox( GdkDrawable* gdkDrawable,
1764                                         ControlType nType, ControlPart nPart,
1765                                         const Rectangle& rControlRectangle,
1766                                         const clipList& rClipList,
1767                                         ControlState nState,
1768                                         const ImplControlValue& aValue,
1769                                         const OUString& rCaption )
1770 {
1771     Rectangle       pixmapRect;
1772     GdkRectangle    clipRect;
1773 
1774     // Find the overall bounding rect of the buttons's drawing area,
1775     // plus its actual draw rect excluding adornment
1776     pixmapRect = NWGetEditBoxPixmapRect( m_nScreen, nType, nPart, rControlRectangle,
1777                                          nState, aValue, rCaption );
1778     for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it )
1779     {
1780         clipRect.x = it->Left();
1781         clipRect.y = it->Top();
1782         clipRect.width = it->GetWidth();
1783         clipRect.height = it->GetHeight();
1784 
1785         NWPaintOneEditBox( m_nScreen, gdkDrawable, &clipRect, nType, nPart, pixmapRect, nState, aValue, rCaption );
1786     }
1787 
1788     return( sal_True );
1789 }
1790 
1791 
1792 /* Take interior/exterior focus into account and return
1793  * the bounding rectangle of the edit box including
1794  * any focus requirements.
1795  */
1796 static Rectangle NWGetEditBoxPixmapRect(int nScreen,
1797                                         ControlType,
1798                                         ControlPart,
1799                                         Rectangle aAreaRect,
1800                                         ControlState,
1801                                         const ImplControlValue&,
1802                                         const OUString& )
1803 {
1804     Rectangle       pixmapRect = aAreaRect;
1805     gboolean        interiorFocus;
1806     gint            focusWidth;
1807 
1808     NWEnsureGTKEditBox( nScreen );
1809 
1810     // Grab some entry style attributes
1811     gtk_widget_style_get( gWidgetData[nScreen].gEditBoxWidget,
1812                                     "focus-line-width", &focusWidth,
1813                                     "interior-focus",   &interiorFocus, (char *)NULL );
1814 
1815     if ( !interiorFocus )
1816     {
1817         pixmapRect.Move( -(focusWidth), -(focusWidth) );
1818         pixmapRect.SetSize( Size( pixmapRect.GetWidth() + (2*(focusWidth)),
1819                                   pixmapRect.GetHeight() + (2*(focusWidth)) ) );
1820     }
1821 
1822     return( pixmapRect );
1823 }
1824 
1825 
1826 /* Paint a GTK Entry widget into the specified GdkPixmap.
1827  * All coordinates should be local to the Pixmap, NOT
1828  * screen/window coordinates.
1829  */
1830 static void NWPaintOneEditBox(  int nScreen,
1831                                 GdkDrawable * gdkDrawable,
1832                                 GdkRectangle *  gdkRect,
1833                                 ControlType         nType,
1834                                 ControlPart,
1835                                 Rectangle               aEditBoxRect,
1836                                 ControlState            nState,
1837                                 const ImplControlValue&,
1838                                 const OUString& )
1839 {
1840     GtkStateType    stateType;
1841     GtkShadowType   shadowType;
1842     GtkWidget      *widget;
1843 
1844     NWEnsureGTKButton( nScreen );
1845     NWEnsureGTKEditBox( nScreen );
1846     NWEnsureGTKSpinButton( nScreen );
1847     NWEnsureGTKCombo( nScreen );
1848     NWEnsureGTKScrolledWindow( nScreen );
1849     NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
1850 
1851     /* border's shadowType for gtk entries is always GTK_SHADOW_IN (see gtkentry.c)
1852     shadowType = GTK_SHADOW_IN;
1853     */
1854 
1855     switch ( nType )
1856     {
1857         case CTRL_SPINBOX:
1858             widget = gWidgetData[nScreen].gSpinButtonWidget;
1859             break;
1860 
1861         case CTRL_MULTILINE_EDITBOX:
1862             widget = gWidgetData[nScreen].gScrolledWindowWidget;
1863             break;
1864         case CTRL_COMBOBOX:
1865             widget = GTK_COMBO(gWidgetData[nScreen].gComboWidget)->entry;
1866             break;
1867 
1868         default:
1869             widget = gWidgetData[nScreen].gEditBoxWidget;
1870             break;
1871     }
1872 
1873     if ( stateType == GTK_STATE_PRELIGHT )
1874         stateType = GTK_STATE_NORMAL;
1875 
1876     // Blueprint needs to paint entry_bg with a Button widget, not an Entry widget to get
1877     // a nice white (or whatever default color) background
1878     GtkWidget* pBGWidget = widget;
1879     if( GtkSalGraphics::bNeedButtonStyleAsEditBackgroundWorkaround )
1880     {
1881         NWSetWidgetState( gWidgetData[nScreen].gBtnWidget, nState, stateType );
1882         pBGWidget = gWidgetData[nScreen].gBtnWidget;
1883     }
1884     NWSetWidgetState( widget, nState, stateType );
1885 
1886     gtk_paint_flat_box( pBGWidget->style, gdkDrawable, stateType, GTK_SHADOW_NONE,
1887                         gdkRect, pBGWidget, "entry_bg",
1888                         aEditBoxRect.Left(), aEditBoxRect.Top(),
1889                         aEditBoxRect.GetWidth(), aEditBoxRect.GetHeight() );
1890     gtk_paint_shadow( widget->style, gdkDrawable, GTK_STATE_NORMAL, GTK_SHADOW_IN,
1891                       gdkRect, widget, "entry",
1892                       aEditBoxRect.Left(), aEditBoxRect.Top(),
1893                       aEditBoxRect.GetWidth(), aEditBoxRect.GetHeight() );
1894 
1895 }
1896 
1897 
1898 
1899 //-------------------------------------
1900 
1901 sal_Bool GtkSalGraphics::NWPaintGTKSpinBox( ControlType nType, ControlPart nPart,
1902                                         const Rectangle& rControlRectangle,
1903                                         const clipList&,
1904                                         ControlState nState,
1905                                         const ImplControlValue& aValue,
1906                                         const OUString& rCaption )
1907 {
1908     GdkPixmap   *       pixmap;
1909     Rectangle           pixmapRect;
1910     GtkStateType        stateType;
1911     GtkShadowType       shadowType;
1912     const SpinbuttonValue * pSpinVal = (aValue.getType() == CTRL_SPINBUTTONS) ? static_cast<const SpinbuttonValue *>(&aValue) : NULL;
1913     Rectangle           upBtnRect;
1914     ControlPart     upBtnPart = PART_BUTTON_UP;
1915     ControlState        upBtnState = CTRL_STATE_ENABLED;
1916     Rectangle           downBtnRect;
1917     ControlPart     downBtnPart = PART_BUTTON_DOWN;
1918     ControlState        downBtnState = CTRL_STATE_ENABLED;
1919 
1920     NWEnsureGTKButton( m_nScreen );
1921     NWEnsureGTKSpinButton( m_nScreen );
1922     NWEnsureGTKArrow( m_nScreen );
1923 
1924     NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
1925 
1926     if ( pSpinVal )
1927     {
1928         upBtnPart = pSpinVal->mnUpperPart;
1929         upBtnState = pSpinVal->mnUpperState;
1930 
1931         downBtnPart = pSpinVal->mnLowerPart;
1932         downBtnState = pSpinVal->mnLowerState;
1933     }
1934 
1935     // CTRL_SPINBUTTONS pass their area in pSpinVal, not in rControlRectangle
1936     if ( nType == CTRL_SPINBUTTONS )
1937     {
1938         if ( !pSpinVal )
1939         {
1940             std::fprintf( stderr, "Tried to draw CTRL_SPINBUTTONS, but the SpinButtons data structure didn't exist!\n" );
1941             return( false );
1942         }
1943         pixmapRect = pSpinVal->maUpperRect;
1944         pixmapRect.Union( pSpinVal->maLowerRect );
1945     }
1946     else
1947         pixmapRect = rControlRectangle;
1948 
1949 
1950     pixmap = NWGetPixmapFromScreen( pixmapRect );
1951     if ( !pixmap )
1952         return( sal_False );
1953 
1954     upBtnRect = NWGetSpinButtonRect( m_nScreen, nType, upBtnPart, pixmapRect, upBtnState, aValue, rCaption );
1955     downBtnRect = NWGetSpinButtonRect( m_nScreen, nType, downBtnPart, pixmapRect, downBtnState, aValue, rCaption );
1956 
1957     if ( (nType==CTRL_SPINBOX) && (nPart!=PART_ALL_BUTTONS) )
1958     {
1959         // Draw an edit field for SpinBoxes and ComboBoxes
1960         Rectangle aEditBoxRect( pixmapRect );
1961         aEditBoxRect.SetSize( Size( upBtnRect.Left() - pixmapRect.Left(), aEditBoxRect.GetHeight() ) );
1962         aEditBoxRect.setX( 0 );
1963         aEditBoxRect.setY( 0 );
1964 
1965         NWPaintOneEditBox( m_nScreen, pixmap, NULL, nType, nPart, aEditBoxRect, nState, aValue, rCaption );
1966     }
1967 
1968     NWSetWidgetState( gWidgetData[m_nScreen].gSpinButtonWidget, nState, stateType );
1969     gtk_widget_style_get( gWidgetData[m_nScreen].gSpinButtonWidget, "shadow_type", &shadowType, (char *)NULL );
1970 
1971     if ( shadowType != GTK_SHADOW_NONE )
1972     {
1973         Rectangle       shadowRect( upBtnRect );
1974 
1975         shadowRect.Union( downBtnRect );
1976         gtk_paint_box( gWidgetData[m_nScreen].gSpinButtonWidget->style, pixmap, GTK_STATE_NORMAL, shadowType, NULL,
1977             gWidgetData[m_nScreen].gSpinButtonWidget, "spinbutton",
1978             (shadowRect.Left() - pixmapRect.Left()), (shadowRect.Top() - pixmapRect.Top()),
1979             shadowRect.GetWidth(), shadowRect.GetHeight() );
1980     }
1981 
1982     NWPaintOneSpinButton( m_nScreen, pixmap, nType, upBtnPart, pixmapRect, upBtnState, aValue, rCaption );
1983     NWPaintOneSpinButton( m_nScreen, pixmap, nType, downBtnPart, pixmapRect, downBtnState, aValue, rCaption );
1984 
1985     if( !NWRenderPixmapToScreen(pixmap, pixmapRect) )
1986     {
1987         g_object_unref( pixmap );
1988         return( sal_False );
1989     }
1990 
1991     g_object_unref( pixmap );
1992     return( sal_True );
1993 }
1994 
1995 //---
1996 
1997 static Rectangle NWGetSpinButtonRect( int nScreen,
1998                                       ControlType,
1999                                       ControlPart           nPart,
2000                                       Rectangle             aAreaRect,
2001                                       ControlState,
2002                                       const ImplControlValue&,
2003                                       const OUString& )
2004 {
2005     gint            buttonSize;
2006     Rectangle       buttonRect;
2007 
2008     NWEnsureGTKSpinButton( nScreen );
2009 
2010     buttonSize = MAX( PANGO_PIXELS( pango_font_description_get_size(GTK_WIDGET(gWidgetData[nScreen].gSpinButtonWidget)->style->font_desc) ),
2011                    MIN_SPIN_ARROW_WIDTH );
2012     buttonSize -= buttonSize % 2 - 1; /* force odd */
2013     buttonRect.SetSize( Size( buttonSize + 2 * gWidgetData[nScreen].gSpinButtonWidget->style->xthickness,
2014                               buttonRect.GetHeight() ) );
2015     buttonRect.setX( aAreaRect.Left() + (aAreaRect.GetWidth() - buttonRect.GetWidth()) );
2016     if ( nPart == PART_BUTTON_UP )
2017     {
2018         buttonRect.setY( aAreaRect.Top() );
2019         buttonRect.Bottom() = buttonRect.Top() + (aAreaRect.GetHeight() / 2);
2020     }
2021     else if( nPart == PART_BUTTON_DOWN )
2022     {
2023         buttonRect.setY( aAreaRect.Top() + (aAreaRect.GetHeight() / 2) );
2024         buttonRect.Bottom() = aAreaRect.Bottom(); // cover area completely
2025     }
2026     else
2027     {
2028         buttonRect.Right()  = buttonRect.Left()-1;
2029         buttonRect.Left()   = aAreaRect.Left();
2030         buttonRect.Top()    = aAreaRect.Top();
2031         buttonRect.Bottom() = aAreaRect.Bottom();
2032     }
2033 
2034     return( buttonRect );
2035 }
2036 
2037 //---
2038 
2039 static void NWPaintOneSpinButton( int nScreen,
2040                                   GdkPixmap*            pixmap,
2041                                   ControlType           nType,
2042                                   ControlPart           nPart,
2043                                   Rectangle             aAreaRect,
2044                                   ControlState          nState,
2045                                   const ImplControlValue&   aValue,
2046                                   const OUString&               rCaption )
2047 {
2048     Rectangle           buttonRect;
2049     GtkStateType        stateType;
2050     GtkShadowType       shadowType;
2051     Rectangle           arrowRect;
2052     gint                arrowSize;
2053 
2054     NWEnsureGTKSpinButton( nScreen );
2055     NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
2056 
2057     buttonRect = NWGetSpinButtonRect( nScreen, nType, nPart, aAreaRect, nState, aValue, rCaption );
2058 
2059     NWSetWidgetState( gWidgetData[nScreen].gSpinButtonWidget, nState, stateType );
2060     gtk_paint_box( gWidgetData[nScreen].gSpinButtonWidget->style, pixmap, stateType, shadowType, NULL, gWidgetData[nScreen].gSpinButtonWidget,
2061             (nPart == PART_BUTTON_UP) ? "spinbutton_up" : "spinbutton_down",
2062             (buttonRect.Left() - aAreaRect.Left()), (buttonRect.Top() - aAreaRect.Top()),
2063             buttonRect.GetWidth(), buttonRect.GetHeight() );
2064 
2065     arrowSize = (buttonRect.GetWidth() - (2 * gWidgetData[nScreen].gSpinButtonWidget->style->xthickness)) - 4;
2066     arrowSize -= arrowSize % 2 - 1; /* force odd */
2067     arrowRect.SetSize( Size( arrowSize, arrowSize ) );
2068     arrowRect.setX( buttonRect.Left() + (buttonRect.GetWidth() - arrowRect.GetWidth()) / 2 );
2069     if ( nPart == PART_BUTTON_UP )
2070         arrowRect.setY( buttonRect.Top() + (buttonRect.GetHeight() - arrowRect.GetHeight()) / 2 + 1);
2071     else
2072         arrowRect.setY( buttonRect.Top() + (buttonRect.GetHeight() - arrowRect.GetHeight()) / 2 - 1);
2073 
2074     gtk_paint_arrow( gWidgetData[nScreen].gSpinButtonWidget->style, pixmap, stateType, GTK_SHADOW_OUT, NULL, gWidgetData[nScreen].gSpinButtonWidget,
2075             "spinbutton", (nPart == PART_BUTTON_UP) ? GTK_ARROW_UP : GTK_ARROW_DOWN, sal_True,
2076             (arrowRect.Left() - aAreaRect.Left()), (arrowRect.Top() - aAreaRect.Top()),
2077             arrowRect.GetWidth(), arrowRect.GetHeight() );
2078 }
2079 
2080 
2081 //-------------------------------------
2082 
2083 sal_Bool GtkSalGraphics::NWPaintGTKComboBox( GdkDrawable* gdkDrawable,
2084                                          ControlType nType, ControlPart nPart,
2085                                          const Rectangle& rControlRectangle,
2086                                          const clipList& rClipList,
2087                                          ControlState nState,
2088                                          const ImplControlValue& aValue,
2089                                          const OUString& rCaption )
2090 {
2091     Rectangle       pixmapRect;
2092     Rectangle       buttonRect;
2093     GtkStateType    stateType;
2094     GtkShadowType   shadowType;
2095     Rectangle       arrowRect;
2096     gint            x,y;
2097     GdkRectangle    clipRect;
2098 
2099     NWEnsureGTKButton( m_nScreen );
2100     NWEnsureGTKArrow( m_nScreen );
2101     NWEnsureGTKCombo( m_nScreen );
2102     NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
2103 
2104     // Find the overall bounding rect of the buttons's drawing area,
2105     // plus its actual draw rect excluding adornment
2106     pixmapRect = rControlRectangle;
2107     x = rControlRectangle.Left();
2108     y = rControlRectangle.Top();
2109 
2110     NWSetWidgetState( gWidgetData[m_nScreen].gBtnWidget, nState, stateType );
2111     NWSetWidgetState( gWidgetData[m_nScreen].gComboWidget, nState, stateType );
2112     NWSetWidgetState( gWidgetData[m_nScreen].gArrowWidget, nState, stateType );
2113 
2114     buttonRect = NWGetComboBoxButtonRect( m_nScreen, nType, PART_BUTTON_DOWN, pixmapRect, nState, aValue, rCaption );
2115     if( nPart == PART_BUTTON_DOWN )
2116         buttonRect.Left() += 1;
2117 
2118     Rectangle       aEditBoxRect( pixmapRect );
2119     aEditBoxRect.SetSize( Size( pixmapRect.GetWidth() - buttonRect.GetWidth(), aEditBoxRect.GetHeight() ) );
2120 
2121     #define ARROW_EXTENT        0.7
2122     arrowRect.SetSize( Size( (gint)(MIN_ARROW_SIZE * ARROW_EXTENT),
2123                              (gint)(MIN_ARROW_SIZE * ARROW_EXTENT) ) );
2124     arrowRect.SetPos( Point( buttonRect.Left() + (gint)((buttonRect.GetWidth() - arrowRect.GetWidth()) / 2),
2125                              buttonRect.Top() + (gint)((buttonRect.GetHeight() - arrowRect.GetHeight()) / 2) ) );
2126 
2127     for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it )
2128     {
2129         clipRect.x = it->Left();
2130         clipRect.y = it->Top();
2131         clipRect.width = it->GetWidth();
2132         clipRect.height = it->GetHeight();
2133 
2134         if( nPart == PART_ENTIRE_CONTROL )
2135             NWPaintOneEditBox( m_nScreen, gdkDrawable, &clipRect, nType, nPart, aEditBoxRect,
2136                                nState, aValue, rCaption );
2137 
2138         // Buttons must paint opaque since some themes have alpha-channel enabled buttons
2139         gtk_paint_flat_box( gWidgetData[m_nScreen].gBtnWidget->style, gdkDrawable, GTK_STATE_NORMAL, GTK_SHADOW_NONE,
2140                             &clipRect, m_pWindow, "base",
2141                             x+(buttonRect.Left() - pixmapRect.Left()),
2142                             y+(buttonRect.Top() - pixmapRect.Top()),
2143                             buttonRect.GetWidth(), buttonRect.GetHeight() );
2144         gtk_paint_box( GTK_COMBO(gWidgetData[m_nScreen].gComboWidget)->button->style, gdkDrawable, stateType, shadowType,
2145                        &clipRect, GTK_COMBO(gWidgetData[m_nScreen].gComboWidget)->button, "button",
2146                        x+(buttonRect.Left() - pixmapRect.Left()),
2147                        y+(buttonRect.Top() - pixmapRect.Top()),
2148                        buttonRect.GetWidth(), buttonRect.GetHeight() );
2149 
2150         gtk_paint_arrow( gWidgetData[m_nScreen].gArrowWidget->style, gdkDrawable, stateType, shadowType,
2151                          &clipRect, gWidgetData[m_nScreen].gArrowWidget, "arrow", GTK_ARROW_DOWN, sal_True,
2152                          x+(arrowRect.Left() - pixmapRect.Left()), y+(arrowRect.Top() - pixmapRect.Top()),
2153                          arrowRect.GetWidth(), arrowRect.GetHeight() );
2154     }
2155 
2156     return( sal_True );
2157 }
2158 
2159 //----
2160 
2161 static Rectangle NWGetComboBoxButtonRect( int nScreen,
2162                                           ControlType,
2163                                           ControlPart nPart,
2164                                           Rectangle             aAreaRect,
2165                                           ControlState,
2166                                           const ImplControlValue&,
2167                                           const OUString& )
2168 {
2169     Rectangle   aButtonRect;
2170     gint        nArrowWidth;
2171     gint        nButtonWidth;
2172     gint        nFocusWidth;
2173     gint        nFocusPad;
2174 
2175     NWEnsureGTKArrow( nScreen );
2176 
2177     // Grab some button style attributes
2178     gtk_widget_style_get( gWidgetData[nScreen].gDropdownWidget,
2179                                     "focus-line-width", &nFocusWidth,
2180                                     "focus-padding",    &nFocusPad, (char *)NULL );
2181 
2182     nArrowWidth = MIN_ARROW_SIZE + (GTK_MISC(gWidgetData[nScreen].gArrowWidget)->xpad * 2);
2183     nButtonWidth = nArrowWidth +
2184                    ((BTN_CHILD_SPACING + gWidgetData[nScreen].gDropdownWidget->style->xthickness) * 2)
2185                    + (2 * (nFocusWidth+nFocusPad));
2186     if( nPart == PART_BUTTON_DOWN )
2187     {
2188         aButtonRect.SetSize( Size( nButtonWidth, aAreaRect.GetHeight() ) );
2189         aButtonRect.SetPos( Point( aAreaRect.Left() + aAreaRect.GetWidth() - nButtonWidth,
2190                                    aAreaRect.Top() ) );
2191     }
2192     else if( nPart == PART_SUB_EDIT )
2193     {
2194         NWEnsureGTKCombo( nScreen );
2195 
2196         gint adjust_x = GTK_CONTAINER(gWidgetData[nScreen].gComboWidget)->border_width +
2197                         nFocusWidth +
2198                         nFocusPad;
2199         gint adjust_y = adjust_x + gWidgetData[nScreen].gComboWidget->style->ythickness;
2200         adjust_x     += gWidgetData[nScreen].gComboWidget->style->xthickness;
2201         aButtonRect.SetSize( Size( aAreaRect.GetWidth() - nButtonWidth - 2 * adjust_x,
2202                                    aAreaRect.GetHeight() - 2 * adjust_y ) );
2203         Point aEditPos = aAreaRect.TopLeft();
2204         aEditPos.X() += adjust_x;
2205         aEditPos.Y() += adjust_y;
2206         aButtonRect.SetPos( aEditPos );
2207     }
2208 
2209     return( aButtonRect );
2210 }
2211 
2212 //-------------------------------------
2213 
2214 
2215 
2216 sal_Bool GtkSalGraphics::NWPaintGTKTabItem( ControlType nType, ControlPart,
2217                                         const Rectangle& rControlRectangle,
2218                                         const clipList&,
2219                                         ControlState nState,
2220                                         const ImplControlValue& aValue,
2221                                         const OUString& )
2222 {
2223     OSL_ASSERT( nType != CTRL_TAB_ITEM || aValue.getType() == CTRL_TAB_ITEM );
2224     GdkPixmap * pixmap;
2225     Rectangle       pixmapRect;
2226     Rectangle       tabRect;
2227     GtkStateType    stateType;
2228     GtkShadowType   shadowType;
2229     if( ! gWidgetData[ m_nScreen ].gCacheTabItems )
2230     {
2231         gWidgetData[ m_nScreen ].gCacheTabItems = new NWPixmapCache( m_nScreen );
2232         gWidgetData[ m_nScreen ].gCacheTabPages = new NWPixmapCache( m_nScreen );
2233     }
2234     NWPixmapCache& aCacheItems = *gWidgetData[ m_nScreen ].gCacheTabItems;
2235     NWPixmapCache& aCachePage = *gWidgetData[ m_nScreen ].gCacheTabPages;
2236 
2237     if( !aCacheItems.GetSize() )
2238         aCacheItems.SetSize( 20 );
2239     if( !aCachePage.GetSize() )
2240         aCachePage.SetSize( 1 );
2241 
2242     if ( (nType == CTRL_TAB_ITEM) && (aValue.getType() != CTRL_TAB_ITEM) )
2243     {
2244         return( false );
2245     }
2246 
2247     NWEnsureGTKButton( m_nScreen );
2248     NWEnsureGTKNotebook( m_nScreen );
2249     NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
2250 
2251     // Find the overall bounding rect of the buttons's drawing area,
2252     // plus its actual draw rect excluding adornment
2253     pixmapRect = rControlRectangle;
2254     if ( nType == CTRL_TAB_ITEM )
2255     {
2256         const TabitemValue *    pTabitemValue = static_cast<const TabitemValue *>(&aValue);
2257         if ( !pTabitemValue->isFirst() )
2258         {
2259             // GTK+ tabs overlap on the right edge (the top tab obscures the
2260             // left edge of the tab right "below" it, so adjust the rectangle
2261             // to draw tabs slightly large so the overlap happens
2262             pixmapRect.Move( -2, 0 );
2263             pixmapRect.SetSize( Size( pixmapRect.GetWidth() + 2, pixmapRect.GetHeight() ) );
2264         }
2265         if ( nState & CTRL_STATE_SELECTED )
2266         {
2267             // In GTK+, the selected tab is 2px taller than all other tabs
2268             pixmapRect.Move( 0, -2 );
2269             pixmapRect.Bottom() += 2;
2270             tabRect = pixmapRect;
2271             // Only draw over 1 pixel of the tab pane that this tab is drawn on top of.
2272             tabRect.Bottom() -= 1;
2273         }
2274         else
2275             tabRect = pixmapRect;
2276 
2277         // Allow the tab to draw a right border if needed
2278         tabRect.Right() -= 1;
2279 
2280         // #129732# avoid degenerate cases which might lead to crashes
2281         if( tabRect.GetWidth() <= 1 || tabRect.GetHeight() <= 1 )
2282             return false;
2283     }
2284 
2285     if( nType == CTRL_TAB_ITEM )
2286     {
2287         if( aCacheItems.Find( nType, nState, pixmapRect, &pixmap ) )
2288             return NWRenderPixmapToScreen( pixmap, pixmapRect );
2289     }
2290     else
2291     {
2292         if( aCachePage.Find( nType, nState, pixmapRect, &pixmap ) )
2293             return NWRenderPixmapToScreen( pixmap, pixmapRect );
2294     }
2295 
2296 
2297 //  gtk_widget_set_state( gWidgetData[m_nScreen].gNotebookWidget, stateType );
2298 
2299     pixmap = gdk_pixmap_new( NULL, pixmapRect.GetWidth(), pixmapRect.GetHeight(),
2300                              GetX11SalData()->GetDisplay()->GetVisual( m_nScreen ).GetDepth() );
2301     GdkRectangle paintRect;
2302     paintRect.x = paintRect.y = 0;
2303     paintRect.width = pixmapRect.GetWidth();
2304     paintRect.height = pixmapRect.GetHeight();
2305 
2306     gtk_paint_flat_box( m_pWindow->style, pixmap, GTK_STATE_NORMAL,
2307                         GTK_SHADOW_NONE, &paintRect, m_pWindow, "base", 0, 0, -1, -1);
2308 
2309     NWSetWidgetState( gWidgetData[m_nScreen].gNotebookWidget, nState, stateType );
2310 
2311     switch( nType )
2312     {
2313         case CTRL_TAB_BODY:
2314             break;
2315 
2316         case CTRL_FIXEDBORDER:
2317         case CTRL_TAB_PANE:
2318             gtk_paint_box_gap( gWidgetData[m_nScreen].gNotebookWidget->style, pixmap, GTK_STATE_NORMAL, GTK_SHADOW_OUT, NULL, gWidgetData[m_nScreen].gNotebookWidget,
2319                 (char *)"notebook", 0, 0, pixmapRect.GetWidth(), pixmapRect.GetHeight(), GTK_POS_TOP, 0, 0 );
2320             break;
2321 
2322         case CTRL_TAB_ITEM:
2323             stateType = ( nState & CTRL_STATE_SELECTED ) ? GTK_STATE_NORMAL : GTK_STATE_ACTIVE;
2324 
2325             gtk_paint_extension( gWidgetData[m_nScreen].gNotebookWidget->style, pixmap, stateType, GTK_SHADOW_OUT, NULL, gWidgetData[m_nScreen].gNotebookWidget,
2326                 (char *)"tab", (tabRect.Left() - pixmapRect.Left()), (tabRect.Top() - pixmapRect.Top()),
2327                 tabRect.GetWidth(), tabRect.GetHeight(), GTK_POS_BOTTOM );
2328 
2329             if ( nState & CTRL_STATE_SELECTED )
2330             {
2331                 gtk_paint_flat_box( gWidgetData[m_nScreen].gNotebookWidget->style, pixmap, stateType, GTK_SHADOW_NONE, NULL, m_pWindow,
2332                     (char *)"base", 0, (pixmapRect.GetHeight() - 1), pixmapRect.GetWidth(), 1 );
2333             }
2334             break;
2335 
2336         default:
2337             break;
2338     }
2339 
2340     // Crux seems to think it can make the pane without a left edge
2341     if ( nType == CTRL_FIXEDBORDER )
2342         pixmapRect.Move( 1, 0 );
2343 
2344     // cache data
2345     if( nType == CTRL_TAB_ITEM )
2346         aCacheItems.Fill( nType, nState, pixmapRect, pixmap );
2347     else
2348         aCachePage.Fill( nType, nState, pixmapRect, pixmap );
2349 
2350     sal_Bool bSuccess = NWRenderPixmapToScreen(pixmap, pixmapRect);
2351     g_object_unref( pixmap );
2352     return bSuccess;
2353 }
2354 
2355 //-------------------------------------
2356 
2357 sal_Bool GtkSalGraphics::NWPaintGTKListBox( GdkDrawable* gdkDrawable,
2358                                         ControlType nType, ControlPart nPart,
2359                                         const Rectangle& rControlRectangle,
2360                                         const clipList& rClipList,
2361                                         ControlState nState,
2362                                         const ImplControlValue& aValue,
2363                                         const OUString& rCaption )
2364 {
2365     Rectangle       pixmapRect;
2366     Rectangle       widgetRect;
2367     Rectangle       aIndicatorRect;
2368     GtkStateType    stateType;
2369     GtkShadowType   shadowType;
2370     gint            bInteriorFocus;
2371     gint            nFocusLineWidth;
2372     gint            nFocusPadding;
2373     gint            x,y;
2374     GdkRectangle    clipRect;
2375 
2376     NWEnsureGTKButton( m_nScreen );
2377     NWEnsureGTKOptionMenu( m_nScreen );
2378     NWEnsureGTKScrolledWindow( m_nScreen );
2379     NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
2380 
2381     // Find the overall bounding rect of the buttons's drawing area,
2382     // plus its actual draw rect excluding adornment
2383     pixmapRect = rControlRectangle;
2384     if ( nPart == PART_WINDOW )
2385     {
2386         // Make the widget a _bit_ bigger
2387         pixmapRect.SetPos( Point( pixmapRect.Left() - 1,
2388                                   pixmapRect.Top() - 1 ) );
2389         pixmapRect.SetSize( Size( pixmapRect.GetWidth() + 2,
2390                                   pixmapRect.GetHeight() + 2 ) );
2391     }
2392 
2393     widgetRect = pixmapRect;
2394     x = pixmapRect.Left();
2395     y = pixmapRect.Top();
2396 
2397     // set up references to correct drawable and cliprect
2398     NWSetWidgetState( gWidgetData[m_nScreen].gBtnWidget, nState, stateType );
2399     NWSetWidgetState( gWidgetData[m_nScreen].gOptionMenuWidget, nState, stateType );
2400     NWSetWidgetState( gWidgetData[m_nScreen].gScrolledWindowWidget, nState, stateType );
2401 
2402     if ( nPart != PART_WINDOW )
2403     {
2404         gtk_widget_style_get( gWidgetData[m_nScreen].gOptionMenuWidget,
2405             "interior_focus",   &bInteriorFocus,
2406             "focus_line_width", &nFocusLineWidth,
2407             "focus_padding",    &nFocusPadding,
2408             (char *)NULL);
2409     }
2410 
2411     for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it )
2412     {
2413         clipRect.x = it->Left();
2414         clipRect.y = it->Top();
2415         clipRect.width = it->GetWidth();
2416         clipRect.height = it->GetHeight();
2417 
2418         if ( nPart != PART_WINDOW )
2419         {
2420             // Listboxes must paint opaque since some themes have alpha-channel enabled bodies
2421             gtk_paint_flat_box( gWidgetData[m_nScreen].gBtnWidget->style, gdkDrawable, GTK_STATE_NORMAL, GTK_SHADOW_NONE,
2422                                 &clipRect, m_pWindow, "base", x, y,
2423                                 pixmapRect.GetWidth(), pixmapRect.GetHeight() );
2424             gtk_paint_box( gWidgetData[m_nScreen].gOptionMenuWidget->style, gdkDrawable, stateType, shadowType, &clipRect,
2425                            gWidgetData[m_nScreen].gOptionMenuWidget, "optionmenu",
2426                            x+(widgetRect.Left() - pixmapRect.Left()),
2427                            y+(widgetRect.Top() - pixmapRect.Top()),
2428                            widgetRect.GetWidth(), widgetRect.GetHeight() );
2429             aIndicatorRect = NWGetListBoxIndicatorRect( m_nScreen, nType, nPart, widgetRect, nState,
2430                                                         aValue, rCaption );
2431             gtk_paint_tab( gWidgetData[m_nScreen].gOptionMenuWidget->style, gdkDrawable, stateType, shadowType, &clipRect,
2432                            gWidgetData[m_nScreen].gOptionMenuWidget, "optionmenutab",
2433                            x+(aIndicatorRect.Left() - pixmapRect.Left()),
2434                            y+(aIndicatorRect.Top() - pixmapRect.Top()),
2435                            aIndicatorRect.GetWidth(), aIndicatorRect.GetHeight() );
2436         }
2437         else
2438         {
2439             shadowType = GTK_SHADOW_IN;
2440 
2441             gtk_paint_shadow( gWidgetData[m_nScreen].gScrolledWindowWidget->style, gdkDrawable, GTK_STATE_NORMAL, shadowType,
2442                 &clipRect, gWidgetData[m_nScreen].gScrolledWindowWidget, "scrolled_window",
2443                 x+(widgetRect.Left() - pixmapRect.Left()), y+(widgetRect.Top() - pixmapRect.Top()),
2444                 widgetRect.GetWidth(), widgetRect.GetHeight() );
2445         }
2446     }
2447 
2448     return( sal_True );
2449 }
2450 
2451 sal_Bool GtkSalGraphics::NWPaintGTKToolbar(
2452             GdkDrawable* gdkDrawable,
2453             ControlType, ControlPart nPart,
2454             const Rectangle& rControlRectangle,
2455             const clipList& rClipList,
2456             ControlState nState, const ImplControlValue& aValue,
2457             const OUString& )
2458 {
2459     GtkStateType    stateType;
2460     GtkShadowType   shadowType;
2461     gint            x, y, w, h;
2462     gint            g_x=0, g_y=0, g_w=10, g_h=10;
2463     bool            bPaintButton = true;
2464     GtkWidget*      pButtonWidget = gWidgetData[m_nScreen].gToolbarButtonWidget;
2465     GdkRectangle    clipRect;
2466 
2467     NWEnsureGTKToolbar( m_nScreen );
2468     if( nPart == PART_BUTTON ) // toolbar buttons cannot focus in gtk
2469         nState &= ~CTRL_STATE_FOCUSED;
2470     NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
2471 
2472     x = rControlRectangle.Left();
2473     y = rControlRectangle.Top();
2474     w = rControlRectangle.GetWidth();
2475     h = rControlRectangle.GetHeight();
2476 
2477     // handle toolbar
2478     if( nPart == PART_DRAW_BACKGROUND_HORZ || nPart == PART_DRAW_BACKGROUND_VERT )
2479     {
2480         NWSetWidgetState( gWidgetData[m_nScreen].gToolbarWidget, nState, stateType );
2481 
2482         GTK_WIDGET_UNSET_FLAGS( gWidgetData[m_nScreen].gToolbarWidget, GTK_SENSITIVE );
2483         if ( nState & CTRL_STATE_ENABLED )
2484             GTK_WIDGET_SET_FLAGS( gWidgetData[m_nScreen].gToolbarWidget, GTK_SENSITIVE );
2485 
2486         if( nPart == PART_DRAW_BACKGROUND_HORZ )
2487             gtk_toolbar_set_orientation( GTK_TOOLBAR(gWidgetData[m_nScreen].gToolbarWidget), GTK_ORIENTATION_HORIZONTAL );
2488         else
2489             gtk_toolbar_set_orientation( GTK_TOOLBAR(gWidgetData[m_nScreen].gToolbarWidget), GTK_ORIENTATION_VERTICAL );
2490     }
2491     // handle grip
2492     else if( nPart == PART_THUMB_HORZ || nPart == PART_THUMB_VERT )
2493     {
2494         NWSetWidgetState( gWidgetData[m_nScreen].gHandleBoxWidget, nState, stateType );
2495 
2496         GTK_WIDGET_UNSET_FLAGS( gWidgetData[m_nScreen].gHandleBoxWidget, GTK_SENSITIVE );
2497         if ( nState & CTRL_STATE_ENABLED )
2498             GTK_WIDGET_SET_FLAGS( gWidgetData[m_nScreen].gHandleBoxWidget, GTK_SENSITIVE );
2499 
2500         gtk_handle_box_set_shadow_type( GTK_HANDLE_BOX(gWidgetData[m_nScreen].gHandleBoxWidget), shadowType );
2501 
2502         // evaluate grip rect
2503         if( aValue.getType() == CTRL_TOOLBAR )
2504         {
2505             const ToolbarValue* pVal = static_cast<const ToolbarValue*>(&aValue);
2506             g_x = pVal->maGripRect.Left();
2507             g_y = pVal->maGripRect.Top();
2508             g_w = pVal->maGripRect.GetWidth();
2509             g_h = pVal->maGripRect.GetHeight();
2510         }
2511     }
2512     // handle button
2513     else if( nPart == PART_BUTTON )
2514     {
2515         bPaintButton =
2516             (GTK_BUTTON(pButtonWidget)->relief != GTK_RELIEF_NONE)
2517             || (nState & CTRL_STATE_PRESSED)
2518             || (nState & CTRL_STATE_ROLLOVER);
2519         if( aValue.getTristateVal() == BUTTONVALUE_ON )
2520         {
2521             pButtonWidget = gWidgetData[m_nScreen].gToolbarToggleWidget;
2522             shadowType = GTK_SHADOW_IN;
2523             stateType = GTK_STATE_ACTIVE;
2524             // special case stateType value for depressed toggle buttons
2525             // cf. gtk+/gtk/gtktogglebutton.c (gtk_toggle_button_update_state)
2526             if( (nState & (CTRL_STATE_ROLLOVER|CTRL_STATE_PRESSED)) )
2527             {
2528                 stateType = GTK_STATE_PRELIGHT;
2529                 shadowType = GTK_SHADOW_OUT;
2530             }
2531             bPaintButton = true;
2532         }
2533         else
2534             stateType = GTK_STATE_PRELIGHT; // only for bPaintButton = true, in which case always rollver is meant
2535 
2536         NWSetWidgetState( pButtonWidget, nState, stateType );
2537         gtk_widget_ensure_style( pButtonWidget );
2538     }
2539 
2540     for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it )
2541     {
2542         clipRect.x = it->Left();
2543         clipRect.y = it->Top();
2544         clipRect.width = it->GetWidth();
2545         clipRect.height = it->GetHeight();
2546 
2547         // draw toolbar
2548         if( nPart == PART_DRAW_BACKGROUND_HORZ || nPart == PART_DRAW_BACKGROUND_VERT )
2549         {
2550             gtk_paint_flat_box( gWidgetData[m_nScreen].gToolbarWidget->style,
2551                                 gdkDrawable,
2552                                 (GtkStateType)GTK_STATE_NORMAL,
2553                                 GTK_SHADOW_NONE,
2554                                 &clipRect,
2555                                 gWidgetData[m_nScreen].gToolbarWidget,
2556                                 "base",
2557                                 x, y, w, h );
2558             gtk_paint_box( gWidgetData[m_nScreen].gToolbarWidget->style,
2559                            gdkDrawable,
2560                            stateType,
2561                            shadowType,
2562                            &clipRect,
2563                            gWidgetData[m_nScreen].gToolbarWidget,
2564                            "toolbar",
2565                            x, y, w, h );
2566         }
2567         // draw grip
2568         else if( nPart == PART_THUMB_HORZ || nPart == PART_THUMB_VERT )
2569         {
2570             gtk_paint_handle( gWidgetData[m_nScreen].gHandleBoxWidget->style,
2571                               gdkDrawable,
2572                               GTK_STATE_NORMAL,
2573                               GTK_SHADOW_OUT,
2574                               &clipRect,
2575                               gWidgetData[m_nScreen].gHandleBoxWidget,
2576                               "handlebox",
2577                               g_x, g_y, g_w, g_h,
2578                               nPart == PART_THUMB_HORZ ?
2579                               GTK_ORIENTATION_HORIZONTAL :
2580                               GTK_ORIENTATION_VERTICAL
2581                               );
2582         }
2583         // draw button
2584         else if( nPart == PART_BUTTON )
2585         {
2586             if( bPaintButton )
2587             {
2588                 gtk_paint_box( pButtonWidget->style, gdkDrawable,
2589                                stateType,
2590                                shadowType,
2591                                &clipRect,
2592                                pButtonWidget, "button", x, y, w, h );
2593             }
2594         }
2595     }
2596 
2597     return( sal_True );
2598 }
2599 
2600 //----
2601 
2602 sal_Bool GtkSalGraphics::NWPaintGTKMenubar(
2603             GdkDrawable* gdkDrawable,
2604             ControlType, ControlPart nPart,
2605             const Rectangle& rControlRectangle,
2606             const clipList& rClipList,
2607             ControlState nState, const ImplControlValue&,
2608             const OUString& )
2609 {
2610     GtkStateType    stateType;
2611     GtkShadowType   shadowType;
2612     GtkShadowType   selected_shadow_type = GTK_SHADOW_OUT;
2613     gint            x, y, w, h;
2614     GdkRectangle    clipRect;
2615 
2616     NWEnsureGTKMenubar( m_nScreen );
2617     NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
2618 
2619     x = rControlRectangle.Left();
2620     y = rControlRectangle.Top();
2621     w = rControlRectangle.GetWidth();
2622     h = rControlRectangle.GetHeight();
2623 
2624     if( nPart == PART_MENU_ITEM )
2625     {
2626         if( nState & (CTRL_STATE_SELECTED|CTRL_STATE_ROLLOVER) )
2627         {
2628             gtk_widget_style_get( gWidgetData[m_nScreen].gMenuItemMenubarWidget,
2629                                   "selected_shadow_type", &selected_shadow_type,
2630                                   (char *)NULL);
2631         }
2632     }
2633 
2634     for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it )
2635     {
2636         clipRect.x = it->Left();
2637         clipRect.y = it->Top();
2638         clipRect.width = it->GetWidth();
2639         clipRect.height = it->GetHeight();
2640 
2641         // handle Menubar
2642         if( nPart == PART_ENTIRE_CONTROL )
2643         {
2644             NWSetWidgetState( gWidgetData[m_nScreen].gMenubarWidget, nState, stateType );
2645 
2646             GTK_WIDGET_UNSET_FLAGS( gWidgetData[m_nScreen].gMenubarWidget, GTK_SENSITIVE );
2647             if ( nState & CTRL_STATE_ENABLED )
2648                 GTK_WIDGET_SET_FLAGS( gWidgetData[m_nScreen].gMenubarWidget, GTK_SENSITIVE );
2649 
2650             // #118704# for translucent menubar styles paint background first
2651             gtk_paint_flat_box( gWidgetData[m_nScreen].gMenubarWidget->style,
2652                                 gdkDrawable,
2653                                 GTK_STATE_NORMAL,
2654                                 GTK_SHADOW_NONE,
2655                                 &clipRect,
2656                                 GTK_WIDGET(m_pWindow),
2657                                 "base",
2658                                 x, y, w, h );
2659             gtk_paint_box( gWidgetData[m_nScreen].gMenubarWidget->style,
2660                            gdkDrawable,
2661                            stateType,
2662                            shadowType,
2663                            &clipRect,
2664                            gWidgetData[m_nScreen].gMenubarWidget,
2665                            "menubar",
2666                            x, y, w, h );
2667         }
2668         else if( nPart == PART_MENU_ITEM )
2669         {
2670             if( nState & (CTRL_STATE_SELECTED|CTRL_STATE_ROLLOVER) )
2671             {
2672                 gtk_paint_box( gWidgetData[m_nScreen].gMenuItemMenubarWidget->style,
2673                                gdkDrawable,
2674                                GTK_STATE_PRELIGHT,
2675                                selected_shadow_type,
2676                                &clipRect,
2677                                gWidgetData[m_nScreen].gMenuItemMenubarWidget,
2678                                "menuitem",
2679                                x, y, w, h);
2680             }
2681         }
2682     }
2683 
2684     return( sal_True );
2685 }
2686 
2687 sal_Bool GtkSalGraphics::NWPaintGTKPopupMenu(
2688             GdkDrawable* gdkDrawable,
2689             ControlType, ControlPart nPart,
2690             const Rectangle& rControlRectangle,
2691             const clipList& rClipList,
2692             ControlState nState, const ImplControlValue&,
2693             const OUString& )
2694 {
2695     // #i50745# gtk does not draw disabled menu entries (and crux theme
2696     // even crashes), draw them using vcl functionality.
2697     if( nPart == PART_MENU_ITEM && ! (nState & CTRL_STATE_ENABLED) )
2698         return sal_False;
2699 
2700     GtkStateType    stateType;
2701     GtkShadowType   shadowType;
2702     GtkShadowType   selected_shadow_type = GTK_SHADOW_OUT;
2703     gint            x, y, w, h;
2704     GdkRectangle    clipRect;
2705 
2706     NWEnsureGTKMenu( m_nScreen );
2707     NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
2708 
2709     x = rControlRectangle.Left();
2710     y = rControlRectangle.Top();
2711     w = rControlRectangle.GetWidth();
2712     h = rControlRectangle.GetHeight();
2713 
2714     if( nPart == PART_MENU_ITEM &&
2715         ( nState & (CTRL_STATE_SELECTED|CTRL_STATE_ROLLOVER) ) )
2716     {
2717         gtk_widget_style_get( gWidgetData[m_nScreen].gMenuItemMenuWidget,
2718                               "selected_shadow_type", &selected_shadow_type,
2719                               (char *)NULL);
2720     }
2721 
2722     NWSetWidgetState( gWidgetData[m_nScreen].gMenuWidget, nState, stateType );
2723 
2724     GTK_WIDGET_UNSET_FLAGS( gWidgetData[m_nScreen].gMenuWidget, GTK_SENSITIVE );
2725     if ( nState & CTRL_STATE_ENABLED )
2726         GTK_WIDGET_SET_FLAGS( gWidgetData[m_nScreen].gMenuWidget, GTK_SENSITIVE );
2727 
2728     for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it )
2729     {
2730         clipRect.x = it->Left();
2731         clipRect.y = it->Top();
2732         clipRect.width = it->GetWidth();
2733         clipRect.height = it->GetHeight();
2734 
2735         if( nPart == PART_ENTIRE_CONTROL )
2736         {
2737             // #118704# for translucent menubar styles paint background first
2738             gtk_paint_flat_box( gWidgetData[m_nScreen].gMenuWidget->style,
2739                                 gdkDrawable,
2740                                 GTK_STATE_NORMAL,
2741                                 GTK_SHADOW_NONE,
2742                                 &clipRect,
2743                                 GTK_WIDGET(m_pWindow),
2744                                 "base",
2745                                 x, y, w, h );
2746             gtk_paint_box( gWidgetData[m_nScreen].gMenuWidget->style,
2747                            gdkDrawable,
2748                            GTK_STATE_NORMAL,
2749                            GTK_SHADOW_OUT,
2750                            &clipRect,
2751                            gWidgetData[m_nScreen].gMenuWidget,
2752                            "menu",
2753                            x, y, w, h );
2754         }
2755         else if( nPart == PART_MENU_ITEM )
2756         {
2757             if( nState & (CTRL_STATE_SELECTED|CTRL_STATE_ROLLOVER) )
2758             {
2759                 if( nState & CTRL_STATE_ENABLED )
2760                 gtk_paint_box( gWidgetData[m_nScreen].gMenuItemMenuWidget->style,
2761                                gdkDrawable,
2762                                GTK_STATE_PRELIGHT,
2763                                selected_shadow_type,
2764                                &clipRect,
2765                                gWidgetData[m_nScreen].gMenuItemMenuWidget,
2766                                "menuitem",
2767                                x, y, w, h);
2768             }
2769         }
2770         else if( nPart == PART_MENU_ITEM_CHECK_MARK || nPart == PART_MENU_ITEM_RADIO_MARK )
2771         {
2772             GtkWidget* pWidget = (nPart == PART_MENU_ITEM_CHECK_MARK) ?
2773                                  gWidgetData[m_nScreen].gMenuItemCheckMenuWidget :
2774                                  gWidgetData[m_nScreen].gMenuItemRadioMenuWidget;
2775 
2776             GtkStateType nStateType = GTK_STATE_NORMAL;
2777             GtkShadowType nShadowType;
2778 
2779             if ( nState & CTRL_STATE_SELECTED )
2780                 nStateType = GTK_STATE_PRELIGHT;
2781 
2782             NWSetWidgetState( pWidget, nState, nStateType );
2783 
2784             if ( nState & CTRL_STATE_PRESSED )
2785                 nShadowType = GTK_SHADOW_IN;
2786             else
2787                 nShadowType = GTK_SHADOW_OUT;
2788 
2789             if ( nPart == PART_MENU_ITEM_CHECK_MARK )
2790             {
2791                 gtk_paint_check( pWidget->style,
2792                                  gdkDrawable,
2793                                  nStateType,
2794                                  nShadowType,
2795                                  &clipRect,
2796                                  gWidgetData[m_nScreen].gMenuItemMenuWidget,
2797                                  "check",
2798                                  x, y, w, h );
2799             }
2800             else
2801             {
2802                 gtk_paint_option( pWidget->style,
2803                                   gdkDrawable,
2804                                   nStateType,
2805                                   nShadowType,
2806                                   &clipRect,
2807                                   gWidgetData[m_nScreen].gMenuItemMenuWidget,
2808                                   "option",
2809                                   x, y, w, h );
2810             }
2811         }
2812     }
2813 
2814     return( sal_True );
2815 }
2816 
2817 sal_Bool GtkSalGraphics::NWPaintGTKTooltip(
2818             GdkDrawable* gdkDrawable,
2819             ControlType, ControlPart,
2820             const Rectangle& rControlRectangle,
2821             const clipList& rClipList,
2822             ControlState, const ImplControlValue&,
2823             const OUString& )
2824 {
2825     NWEnsureGTKTooltip( m_nScreen );
2826 
2827     gint            x, y, w, h;
2828     GdkRectangle    clipRect;
2829 
2830     x = rControlRectangle.Left();
2831     y = rControlRectangle.Top();
2832     w = rControlRectangle.GetWidth();
2833     h = rControlRectangle.GetHeight();
2834 
2835     for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it )
2836     {
2837         clipRect.x = it->Left();
2838         clipRect.y = it->Top();
2839         clipRect.width = it->GetWidth();
2840         clipRect.height = it->GetHeight();
2841 
2842         gtk_paint_flat_box( gWidgetData[m_nScreen].gTooltipPopup->style,
2843                             gdkDrawable,
2844                             GTK_STATE_NORMAL,
2845                             GTK_SHADOW_OUT,
2846                             &clipRect,
2847                             gWidgetData[m_nScreen].gTooltipPopup,
2848                             "tooltip",
2849                             x, y, w, h );
2850     }
2851 
2852     return( sal_True );
2853 }
2854 
2855 sal_Bool GtkSalGraphics::NWPaintGTKListNode(
2856             GdkDrawable*,
2857             ControlType, ControlPart,
2858             const Rectangle& rControlRectangle,
2859             const clipList&,
2860             ControlState nState, const ImplControlValue& rValue,
2861             const OUString& )
2862 {
2863     NWEnsureGTKTreeView( m_nScreen );
2864 
2865     Rectangle aRect( rControlRectangle );
2866     aRect.Left() -= 2;
2867     aRect.Right() += 2;
2868     aRect.Top() -= 2;
2869     aRect.Bottom() += 2;
2870     gint            w, h;
2871     w = aRect.GetWidth();
2872     h = aRect.GetHeight();
2873 
2874     GtkStateType    stateType;
2875     GtkShadowType   shadowType;
2876     NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
2877 
2878     ButtonValue aButtonValue = rValue.getTristateVal();
2879     GtkExpanderStyle eStyle = GTK_EXPANDER_EXPANDED;
2880 
2881     switch( aButtonValue )
2882     {
2883         case BUTTONVALUE_ON: eStyle = GTK_EXPANDER_EXPANDED;break;
2884         case BUTTONVALUE_OFF: eStyle = GTK_EXPANDER_COLLAPSED; break;
2885         default:
2886             break;
2887     }
2888 
2889     GdkPixmap* pixmap = NWGetPixmapFromScreen( aRect );
2890     if( ! pixmap )
2891         return sal_False;
2892 
2893     GdkDrawable* const &pixDrawable = GDK_DRAWABLE( pixmap );
2894     gtk_paint_expander( gWidgetData[m_nScreen].gTreeView->style,
2895                         pixDrawable,
2896                         stateType,
2897                         NULL,
2898                         gWidgetData[m_nScreen].gTreeView,
2899                         "treeview",
2900                         w/2, h/2,
2901                         eStyle );
2902 
2903     sal_Bool bRet = NWRenderPixmapToScreen( pixmap, aRect );
2904     g_object_unref( pixmap );
2905 
2906     return bRet;
2907 }
2908 
2909 sal_Bool GtkSalGraphics::NWPaintGTKProgress(
2910             GdkDrawable*,
2911             ControlType, ControlPart,
2912             const Rectangle& rControlRectangle,
2913             const clipList&,
2914             ControlState, const ImplControlValue& rValue,
2915             const OUString& )
2916 {
2917     NWEnsureGTKProgressBar( m_nScreen );
2918 
2919     gint            w, h;
2920     w = rControlRectangle.GetWidth();
2921     h = rControlRectangle.GetHeight();
2922 
2923     long nProgressWidth = rValue.getNumericVal();
2924 
2925     GdkPixmap* pixmap = NWGetPixmapFromScreen( Rectangle( Point( 0, 0 ), Size( w, h ) ) );
2926     if( ! pixmap )
2927         return sal_False;
2928 
2929     GdkDrawable* const &pixDrawable = GDK_DRAWABLE( pixmap );
2930 
2931     // paint background
2932     gtk_paint_flat_box( gWidgetData[m_nScreen].gProgressBar->style,
2933                         pixDrawable,
2934                         GTK_STATE_NORMAL,
2935                         GTK_SHADOW_NONE,
2936                         NULL,
2937                         gWidgetData[m_nScreen].gProgressBar,
2938                         "trough",
2939                         0, 0, w, h );
2940     if( nProgressWidth > 0 )
2941     {
2942         // paint progress
2943         if( Application::GetSettings().GetLayoutRTL() )
2944         {
2945             gtk_paint_box( gWidgetData[m_nScreen].gProgressBar->style,
2946                            pixDrawable,
2947                            GTK_STATE_PRELIGHT, GTK_SHADOW_OUT,
2948                            NULL,
2949                            gWidgetData[m_nScreen].gProgressBar,
2950                            "bar",
2951                            w-nProgressWidth, 0, nProgressWidth, h
2952                            );
2953         }
2954         else
2955         {
2956             gtk_paint_box( gWidgetData[m_nScreen].gProgressBar->style,
2957                            pixDrawable,
2958                            GTK_STATE_PRELIGHT, GTK_SHADOW_OUT,
2959                            NULL,
2960                            gWidgetData[m_nScreen].gProgressBar,
2961                            "bar",
2962                            0, 0, nProgressWidth, h
2963                            );
2964         }
2965     }
2966 
2967     sal_Bool bRet = NWRenderPixmapToScreen( pixmap, rControlRectangle );
2968     g_object_unref( pixmap );
2969 
2970     return bRet;
2971 }
2972 
2973 sal_Bool GtkSalGraphics::NWPaintGTKSlider(
2974             GdkDrawable*,
2975             ControlType, ControlPart nPart,
2976             const Rectangle& rControlRectangle,
2977             const clipList&,
2978             ControlState nState, const ImplControlValue& rValue,
2979             const OUString& )
2980 {
2981     OSL_ASSERT( rValue.getType() == CTRL_SLIDER );
2982     NWEnsureGTKSlider( m_nScreen );
2983 
2984     gint            w, h;
2985     w = rControlRectangle.GetWidth();
2986     h = rControlRectangle.GetHeight();
2987 
2988     const SliderValue* pVal = static_cast<const SliderValue*>(&rValue);
2989 
2990     GdkPixmap* pixmap = NWGetPixmapFromScreen( rControlRectangle );
2991     if( ! pixmap )
2992         return sal_False;
2993 
2994     GdkDrawable* const &pixDrawable = GDK_DRAWABLE( pixmap );
2995     GtkWidget* pWidget = (nPart == PART_TRACK_HORZ_AREA)
2996                          ? GTK_WIDGET(gWidgetData[m_nScreen].gHScale)
2997                          : GTK_WIDGET(gWidgetData[m_nScreen].gVScale);
2998     const gchar* pDetail = (nPart == PART_TRACK_HORZ_AREA) ? "hscale" : "vscale";
2999     GtkOrientation eOri = (nPart == PART_TRACK_HORZ_AREA) ? GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL;
3000     GtkStateType eState = (nState & CTRL_STATE_ENABLED) ? GTK_STATE_ACTIVE : GTK_STATE_INSENSITIVE;
3001     gint slider_width = 10;
3002     gint slider_length = 10;
3003     gint trough_border = 0;
3004     gtk_widget_style_get( pWidget,
3005                           "slider-width", &slider_width,
3006                           "slider-length", &slider_length,
3007                           "trough-border", &trough_border,
3008                           NULL);
3009 
3010     eState = (nState & CTRL_STATE_ENABLED) ? GTK_STATE_NORMAL : GTK_STATE_INSENSITIVE;
3011     if( nPart == PART_TRACK_HORZ_AREA )
3012     {
3013         gtk_paint_box( pWidget->style,
3014                        pixDrawable,
3015                        eState,
3016                        GTK_SHADOW_IN,
3017                        NULL,
3018                        pWidget,
3019                        "trough",
3020                        0, (h-slider_width-2*trough_border)/2, w, slider_width + 2*trough_border);
3021         gint x = (w - slider_length + 1) * (pVal->mnCur - pVal->mnMin) / (pVal->mnMax - pVal->mnMin);
3022         gtk_paint_slider( pWidget->style,
3023                           pixDrawable,
3024                           eState,
3025                           GTK_SHADOW_OUT,
3026                           NULL,
3027                           pWidget,
3028                           pDetail,
3029                           x, (h-slider_width)/2,
3030                           slider_length, slider_width,
3031                           eOri );
3032     }
3033     else
3034     {
3035         gtk_paint_box( pWidget->style,
3036                        pixDrawable,
3037                        eState,
3038                        GTK_SHADOW_IN,
3039                        NULL,
3040                        pWidget,
3041                        "trough",
3042                        (w-slider_width-2*trough_border)/2, 0, slider_width + 2*trough_border, h);
3043         gint y = (h - slider_length + 1) * (pVal->mnCur - pVal->mnMin) / (pVal->mnMax - pVal->mnMin);
3044         gtk_paint_slider( pWidget->style,
3045                           pixDrawable,
3046                           eState,
3047                           GTK_SHADOW_OUT,
3048                           NULL,
3049                           pWidget,
3050                           pDetail,
3051                           (w-slider_width)/2, y,
3052                           slider_width, slider_length,
3053                           eOri );
3054     }
3055     #if 0
3056     // paint background
3057     gtk_paint_flat_box( gWidgetData[m_nScreen].gProgressBar->style,
3058                         pixDrawable,
3059                         GTK_STATE_NORMAL,
3060                         GTK_SHADOW_NONE,
3061                         NULL,
3062                         gWidgetData[m_nScreen].gProgressBar,
3063                         "trough",
3064                         0, 0, w, h );
3065     if( nProgressWidth > 0 )
3066     {
3067         // paint progress
3068         if( Application::GetSettings().GetLayoutRTL() )
3069         {
3070             gtk_paint_box( gWidgetData[m_nScreen].gProgressBar->style,
3071                            pixDrawable,
3072                            GTK_STATE_PRELIGHT, GTK_SHADOW_OUT,
3073                            NULL,
3074                            gWidgetData[m_nScreen].gProgressBar,
3075                            "bar",
3076                            w-nProgressWidth, 0, nProgressWidth, h
3077                            );
3078         }
3079         else
3080         {
3081             gtk_paint_box( gWidgetData[m_nScreen].gProgressBar->style,
3082                            pixDrawable,
3083                            GTK_STATE_PRELIGHT, GTK_SHADOW_OUT,
3084                            NULL,
3085                            gWidgetData[m_nScreen].gProgressBar,
3086                            "bar",
3087                            0, 0, nProgressWidth, h
3088                            );
3089         }
3090     }
3091     #endif
3092 
3093     sal_Bool bRet = NWRenderPixmapToScreen( pixmap, rControlRectangle );
3094     g_object_unref( pixmap );
3095 
3096     return bRet;
3097 }
3098 
3099 //----
3100 
3101 static Rectangle NWGetListBoxButtonRect( int nScreen,
3102                                          ControlType,
3103                                          ControlPart    nPart,
3104                                          Rectangle      aAreaRect,
3105                                          ControlState,
3106                                          const ImplControlValue&,
3107                                          const OUString& )
3108 {
3109     Rectangle       aPartRect;
3110     GtkRequisition *pIndicatorSize = NULL;
3111     GtkBorder      *pIndicatorSpacing = NULL;
3112     gint            width = 13; // GTK+ default
3113     gint            right = 5;  // GTK+ default
3114     gint            nButtonAreaWidth = 0;
3115     gint            xthickness = 0;
3116 
3117     NWEnsureGTKOptionMenu( nScreen );
3118 
3119     gtk_widget_style_get( gWidgetData[nScreen].gOptionMenuWidget,
3120             "indicator_size",   &pIndicatorSize,
3121             "indicator_spacing",&pIndicatorSpacing, (char *)NULL);
3122 
3123     if ( pIndicatorSize )
3124         width = pIndicatorSize->width;
3125 
3126     if ( pIndicatorSpacing )
3127         right = pIndicatorSpacing->right;
3128 
3129     Size aPartSize( 0, aAreaRect.GetHeight() );
3130     Point aPartPos ( 0, aAreaRect.Top() );
3131 
3132     xthickness = gWidgetData[nScreen].gOptionMenuWidget->style->xthickness;
3133     nButtonAreaWidth = width + right + (xthickness * 2);
3134     switch( nPart )
3135     {
3136         case PART_BUTTON_DOWN:
3137             aPartSize.Width() = nButtonAreaWidth;
3138             aPartPos.X() = aAreaRect.Left() + aAreaRect.GetWidth() - aPartSize.Width();
3139             break;
3140 
3141         case PART_SUB_EDIT:
3142             aPartSize.Width() = aAreaRect.GetWidth() - nButtonAreaWidth - xthickness;
3143             aPartPos.X() = aAreaRect.Left() + xthickness;
3144             break;
3145 
3146         default:
3147             aPartSize.Width() = aAreaRect.GetWidth();
3148             aPartPos.X() = aAreaRect.Left();
3149             break;
3150     }
3151     aPartRect = Rectangle( aPartPos, aPartSize );
3152 
3153     if ( pIndicatorSize )
3154         gtk_requisition_free( pIndicatorSize );
3155     if ( pIndicatorSpacing )
3156         gtk_border_free( pIndicatorSpacing );
3157 
3158     return( aPartRect );
3159 }
3160 
3161 //----
3162 
3163 static Rectangle NWGetListBoxIndicatorRect( int nScreen,
3164                                             ControlType,
3165                                             ControlPart,
3166                                             Rectangle               aAreaRect,
3167                                             ControlState,
3168                                             const ImplControlValue&,
3169                                             const OUString& )
3170 {
3171     Rectangle       aIndicatorRect;
3172     GtkRequisition *pIndicatorSize = NULL;
3173     GtkBorder      *pIndicatorSpacing = NULL;
3174     gint            width = 13; // GTK+ default
3175     gint            height = 13;    // GTK+ default
3176     gint            right = 5;  // GTK+ default
3177 
3178     NWEnsureGTKOptionMenu( nScreen );
3179 
3180     gtk_widget_style_get( gWidgetData[nScreen].gOptionMenuWidget,
3181             "indicator_size",   &pIndicatorSize,
3182             "indicator_spacing",&pIndicatorSpacing, (char *)NULL);
3183 
3184     if ( pIndicatorSize )
3185     {
3186         width = pIndicatorSize->width;
3187         height = pIndicatorSize->height;
3188     }
3189 
3190     if ( pIndicatorSpacing )
3191         right = pIndicatorSpacing->right;
3192 
3193     aIndicatorRect.SetSize( Size( width, height ) );
3194     aIndicatorRect.SetPos( Point( aAreaRect.Left() + aAreaRect.GetWidth() - width - right - gWidgetData[nScreen].gOptionMenuWidget->style->xthickness,
3195                                   aAreaRect.Top() + ((aAreaRect.GetHeight() - height) / 2) ) );
3196 
3197     // If height is odd, move the indicator down 1 pixel
3198     if ( aIndicatorRect.GetHeight() % 2 )
3199         aIndicatorRect.Move( 0, 1 );
3200 
3201     if ( pIndicatorSize )
3202         gtk_requisition_free( pIndicatorSize );
3203     if ( pIndicatorSpacing )
3204         gtk_border_free( pIndicatorSpacing );
3205 
3206     return( aIndicatorRect );
3207 }
3208 
3209 static Rectangle NWGetToolbarRect(  int nScreen,
3210                                     ControlType,
3211                                     ControlPart             nPart,
3212                                     Rectangle               aAreaRect,
3213                                     ControlState,
3214                                     const ImplControlValue&,
3215                                     const OUString& )
3216 {
3217     Rectangle aRet;
3218 
3219     if( nPart == PART_DRAW_BACKGROUND_HORZ ||
3220         nPart == PART_DRAW_BACKGROUND_VERT )
3221         aRet = aAreaRect;
3222     else if( nPart == PART_THUMB_HORZ )
3223         aRet = Rectangle( Point( 0, 0 ), Size( aAreaRect.GetWidth(), 10 ) );
3224     else if( nPart == PART_THUMB_VERT )
3225         aRet = Rectangle( Point( 0, 0 ), Size( 10, aAreaRect.GetHeight() ) );
3226     else if( nPart == PART_BUTTON )
3227     {
3228         aRet = aAreaRect;
3229 
3230         NWEnsureGTKToolbar( nScreen );
3231 
3232         gint nMinWidth =
3233             2*gWidgetData[nScreen].gToolbarButtonWidget->style->xthickness
3234             + 1 // CHILD_SPACING constant, found in gtk_button.c
3235             + 3*gWidgetData[nScreen].gToolbarButtonWidget->style->xthickness; // Murphy factor
3236         gint nMinHeight =
3237             2*gWidgetData[nScreen].gToolbarButtonWidget->style->ythickness
3238             + 1 // CHILD_SPACING constant, found in gtk_button.c
3239             + 3*gWidgetData[nScreen].gToolbarButtonWidget->style->ythickness; // Murphy factor
3240 
3241         gtk_widget_ensure_style( gWidgetData[nScreen].gToolbarButtonWidget );
3242         if( aAreaRect.GetWidth() < nMinWidth )
3243             aRet.Right() = aRet.Left() + nMinWidth;
3244         if( aAreaRect.GetHeight() < nMinHeight  )
3245             aRet.Bottom() = aRet.Top() + nMinHeight;
3246     }
3247 
3248     return aRet;
3249 }
3250 
3251 /************************************************************************
3252  * helper for GtkSalFrame
3253  ************************************************************************/
3254 static inline Color getColor( const GdkColor& rCol )
3255 {
3256     return Color( rCol.red >> 8, rCol.green >> 8, rCol.blue >> 8 );
3257 }
3258 
3259 #if OSL_DEBUG_LEVEL > 1
3260 
3261 void printColor( const char* name, const GdkColor& rCol )
3262 {
3263     std::fprintf( stderr, "   %s = 0x%2x 0x%2x 0x%2x\n",
3264              name,
3265              rCol.red >> 8, rCol.green >> 8, rCol.blue >> 8 );
3266 }
3267 
3268 void printStyleColors( GtkStyle* pStyle )
3269 {
3270     static const char* pStates[] = { "NORMAL", "ACTIVE", "PRELIGHT", "SELECTED", "INSENSITIVE" };
3271 
3272     for( int i = 0; i < 5; i++ )
3273     {
3274         std::fprintf( stderr, "state %s colors:\n", pStates[i] );
3275         printColor( "bg     ", pStyle->bg[i] );
3276         printColor( "fg     ", pStyle->fg[i] );
3277         printColor( "light  ", pStyle->light[i] );
3278         printColor( "dark   ", pStyle->dark[i] );
3279         printColor( "mid    ", pStyle->mid[i] );
3280         printColor( "text   ", pStyle->text[i] );
3281         printColor( "base   ", pStyle->base[i] );
3282         printColor( "text_aa", pStyle->text_aa[i] );
3283     }
3284 }
3285 #endif
3286 
3287 void GtkSalGraphics::updateSettings( AllSettings& rSettings )
3288 {
3289     // get the widgets in place
3290     NWEnsureGTKMenu( m_nScreen );
3291     NWEnsureGTKMenubar( m_nScreen );
3292     NWEnsureGTKScrollbars( m_nScreen );
3293     NWEnsureGTKEditBox( m_nScreen );
3294     NWEnsureGTKTooltip( m_nScreen );
3295 
3296     gtk_widget_ensure_style( m_pWindow );
3297     GtkStyle* pStyle = gtk_widget_get_style( m_pWindow );
3298 
3299     StyleSettings aStyleSet = rSettings.GetStyleSettings();
3300 
3301 #if OSL_DEBUG_LEVEL > 2
3302     printStyleColors( pStyle );
3303 #endif
3304 
3305     // text colors
3306     Color aTextColor = getColor( pStyle->text[GTK_STATE_NORMAL] );
3307     aStyleSet.SetDialogTextColor( aTextColor );
3308     aStyleSet.SetButtonTextColor( aTextColor );
3309     aStyleSet.SetRadioCheckTextColor( aTextColor );
3310     aStyleSet.SetGroupTextColor( aTextColor );
3311     aStyleSet.SetLabelTextColor( aTextColor );
3312     aStyleSet.SetInfoTextColor( aTextColor );
3313     aStyleSet.SetWindowTextColor( aTextColor );
3314     aStyleSet.SetFieldTextColor( aTextColor );
3315 
3316     // Tooltip colors
3317     GtkStyle* pTooltipStyle = gtk_widget_get_style( gWidgetData[m_nScreen].gTooltipPopup );
3318     aTextColor = getColor( pTooltipStyle->fg[ GTK_STATE_NORMAL ] );
3319     aStyleSet.SetHelpTextColor( aTextColor );
3320 
3321     // mouse over text colors
3322     aTextColor = getColor( pStyle->fg[ GTK_STATE_PRELIGHT ] );
3323     aStyleSet.SetButtonRolloverTextColor( aTextColor );
3324     aStyleSet.SetFieldRolloverTextColor( aTextColor );
3325 
3326     // background colors
3327     Color aBackColor = getColor( pStyle->bg[GTK_STATE_NORMAL] );
3328     Color aBackFieldColor = getColor( pStyle->base[ GTK_STATE_NORMAL ] );
3329     aStyleSet.Set3DColors( aBackColor );
3330     aStyleSet.SetFaceColor( aBackColor );
3331     aStyleSet.SetDialogColor( aBackColor );
3332     aStyleSet.SetWorkspaceColor( aBackColor );
3333     aStyleSet.SetFieldColor( aBackFieldColor );
3334     aStyleSet.SetWindowColor( aBackFieldColor );
3335 //    aStyleSet.SetHelpColor( aBackColor );
3336     // ancient wisdom tells us a mystic algorithm how to set checked color
3337     if( aBackColor == COL_LIGHTGRAY )
3338         aStyleSet.SetCheckedColor( Color( 0xCC, 0xCC, 0xCC ) );
3339     else
3340     {
3341         Color aColor2 = aStyleSet.GetLightColor();
3342         Color aCheck( (sal_uInt8)(((sal_uInt16)aBackColor.GetRed()+(sal_uInt16)aColor2.GetRed())/2),
3343                       (sal_uInt8)(((sal_uInt16)aBackColor.GetGreen()+(sal_uInt16)aColor2.GetGreen())/2),
3344                       (sal_uInt8)(((sal_uInt16)aBackColor.GetBlue()+(sal_uInt16)aColor2.GetBlue())/2)
3345                       );
3346         aStyleSet.SetCheckedColor( aCheck );
3347     }
3348 
3349     // highlighting colors
3350     Color aHighlightColor = getColor( pStyle->base[GTK_STATE_SELECTED] );
3351     Color aHighlightTextColor = getColor( pStyle->text[GTK_STATE_SELECTED] );
3352     aStyleSet.SetHighlightColor( aHighlightColor );
3353     aStyleSet.SetHighlightTextColor( aHighlightTextColor );
3354 
3355     if( ! gtk_check_version( 2, 10, 0 ) ) // link colors came in with 2.10, avoid an assertion
3356     {
3357         // hyperlink colors
3358         GdkColor *link_color = NULL;
3359         gtk_widget_style_get (m_pWindow, "link-color", &link_color, NULL);
3360         if (link_color)
3361         {
3362             aStyleSet.SetLinkColor(getColor(*link_color));
3363             gdk_color_free (link_color);
3364             link_color = NULL;
3365         }
3366         gtk_widget_style_get (m_pWindow, "visited-link-color", &link_color, NULL);
3367         if (link_color)
3368         {
3369             aStyleSet.SetVisitedLinkColor(getColor(*link_color));
3370             gdk_color_free (link_color);
3371         }
3372     }
3373 
3374     // Tab colors
3375     aStyleSet.SetActiveTabColor( aBackFieldColor ); // same as the window color.
3376     Color aSelectedBackColor = getColor( pStyle->bg[GTK_STATE_ACTIVE] );
3377     aStyleSet.SetInactiveTabColor( aSelectedBackColor );
3378 
3379     // menu disabled entries handling
3380     aStyleSet.SetSkipDisabledInMenus( sal_True );
3381     // menu colors
3382     GtkStyle* pMenuStyle = gtk_widget_get_style( gWidgetData[m_nScreen].gMenuWidget );
3383     GtkStyle* pMenuItemStyle = gtk_rc_get_style( gWidgetData[m_nScreen].gMenuItemMenuWidget );
3384     GtkStyle* pMenubarStyle = gtk_rc_get_style( gWidgetData[m_nScreen].gMenubarWidget );
3385     GtkStyle* pMenuTextStyle = gtk_rc_get_style( gtk_bin_get_child( GTK_BIN(gWidgetData[m_nScreen].gMenuItemMenuWidget) ) );
3386 
3387     aBackColor = getColor( pMenubarStyle->bg[GTK_STATE_NORMAL] );
3388     aStyleSet.SetMenuBarColor( aBackColor );
3389     aBackColor = getColor( pMenuStyle->bg[GTK_STATE_NORMAL] );
3390     aTextColor = getColor( pMenuTextStyle->fg[GTK_STATE_NORMAL] );
3391     aStyleSet.SetMenuColor( aBackColor );
3392     aStyleSet.SetMenuTextColor( aTextColor );
3393 
3394     aTextColor = getColor( pMenubarStyle->fg[GTK_STATE_NORMAL] );
3395     aStyleSet.SetMenuBarTextColor( aTextColor );
3396 
3397 #if OSL_DEBUG_LEVEL > 1
3398     std::fprintf( stderr, "==\n" );
3399     std::fprintf( stderr, "MenuColor = %x (%d)\n", (int)aStyleSet.GetMenuColor().GetColor(), aStyleSet.GetMenuColor().GetLuminance() );
3400     std::fprintf( stderr, "MenuTextColor = %x (%d)\n", (int)aStyleSet.GetMenuTextColor().GetColor(), aStyleSet.GetMenuTextColor().GetLuminance() );
3401     std::fprintf( stderr, "MenuBarColor = %x (%d)\n", (int)aStyleSet.GetMenuBarColor().GetColor(), aStyleSet.GetMenuBarColor().GetLuminance() );
3402     std::fprintf( stderr, "MenuBarTextColor = %x (%d)\n", (int)aStyleSet.GetMenuBarTextColor().GetColor(), aStyleSet.GetMenuBarTextColor().GetLuminance() );
3403     std::fprintf( stderr, "LightColor = %x (%d)\n", (int)aStyleSet.GetLightColor().GetColor(), aStyleSet.GetLightColor().GetLuminance() );
3404     std::fprintf( stderr, "ShadowColor = %x (%d)\n", (int)aStyleSet.GetShadowColor().GetColor(), aStyleSet.GetShadowColor().GetLuminance() );
3405 #endif
3406 
3407     // Awful hack for menu separators in the Sonar and similar themes.
3408     // If the menu color is not too dark, and the menu text color is lighter,
3409     // make the "light" color lighter than the menu color and the "shadow"
3410     // color darker than it.
3411     if ( aStyleSet.GetMenuColor().GetLuminance() >= 32 &&
3412      aStyleSet.GetMenuColor().GetLuminance() <= aStyleSet.GetMenuTextColor().GetLuminance() )
3413     {
3414       Color temp = aStyleSet.GetMenuColor();
3415       temp.IncreaseLuminance( 8 );
3416       aStyleSet.SetLightColor( temp );
3417       temp = aStyleSet.GetMenuColor();
3418       temp.DecreaseLuminance( 16 );
3419       aStyleSet.SetShadowColor( temp );
3420     }
3421 
3422     aHighlightColor = getColor( pMenuItemStyle->bg[ GTK_STATE_SELECTED ] );
3423     aHighlightTextColor = getColor( pMenuTextStyle->fg[ GTK_STATE_PRELIGHT ] );
3424     if( aHighlightColor == aHighlightTextColor )
3425         aHighlightTextColor = (aHighlightColor.GetLuminance() < 128) ? Color( COL_WHITE ) : Color( COL_BLACK );
3426     aStyleSet.SetMenuHighlightColor( aHighlightColor );
3427     aStyleSet.SetMenuHighlightTextColor( aHighlightTextColor );
3428 
3429     // UI font
3430     OString aFamily     = pango_font_description_get_family( pStyle->font_desc );
3431     int nPangoHeight    = pango_font_description_get_size( pStyle->font_desc );
3432     PangoStyle  eStyle  = pango_font_description_get_style( pStyle->font_desc );
3433     PangoWeight eWeight = pango_font_description_get_weight( pStyle->font_desc );
3434     PangoStretch eStretch = pango_font_description_get_stretch( pStyle->font_desc );
3435 
3436     psp::FastPrintFontInfo aInfo;
3437     // set family name
3438     aInfo.m_aFamilyName = OStringToOUString( aFamily, RTL_TEXTENCODING_UTF8 );
3439     // set italic
3440     switch( eStyle )
3441     {
3442         case PANGO_STYLE_NORMAL:    aInfo.m_eItalic = psp::italic::Upright;break;
3443         case PANGO_STYLE_ITALIC:    aInfo.m_eItalic = psp::italic::Italic;break;
3444         case PANGO_STYLE_OBLIQUE:   aInfo.m_eItalic = psp::italic::Oblique;break;
3445     }
3446     // set weight
3447     if( eWeight <= PANGO_WEIGHT_ULTRALIGHT )
3448         aInfo.m_eWeight = psp::weight::UltraLight;
3449     else if( eWeight <= PANGO_WEIGHT_LIGHT )
3450         aInfo.m_eWeight = psp::weight::Light;
3451     else if( eWeight <= PANGO_WEIGHT_NORMAL )
3452         aInfo.m_eWeight = psp::weight::Normal;
3453     else if( eWeight <= PANGO_WEIGHT_BOLD )
3454         aInfo.m_eWeight = psp::weight::Bold;
3455     else
3456         aInfo.m_eWeight = psp::weight::UltraBold;
3457     // set width
3458     switch( eStretch )
3459     {
3460         case PANGO_STRETCH_ULTRA_CONDENSED: aInfo.m_eWidth = psp::width::UltraCondensed;break;
3461         case PANGO_STRETCH_EXTRA_CONDENSED: aInfo.m_eWidth = psp::width::ExtraCondensed;break;
3462         case PANGO_STRETCH_CONDENSED:       aInfo.m_eWidth = psp::width::Condensed;break;
3463         case PANGO_STRETCH_SEMI_CONDENSED:  aInfo.m_eWidth = psp::width::SemiCondensed;break;
3464         case PANGO_STRETCH_NORMAL:          aInfo.m_eWidth = psp::width::Normal;break;
3465         case PANGO_STRETCH_SEMI_EXPANDED:   aInfo.m_eWidth = psp::width::SemiExpanded;break;
3466         case PANGO_STRETCH_EXPANDED:        aInfo.m_eWidth = psp::width::Expanded;break;
3467         case PANGO_STRETCH_EXTRA_EXPANDED:  aInfo.m_eWidth = psp::width::ExtraExpanded;break;
3468         case PANGO_STRETCH_ULTRA_EXPANDED:  aInfo.m_eWidth = psp::width::UltraExpanded;break;
3469     }
3470 
3471 #if OSL_DEBUG_LEVEL > 1
3472     std::fprintf( stderr, "font name BEFORE system match: \"%s\"\n", aFamily.getStr() );
3473 #endif
3474 
3475     // match font to e.g. resolve "Sans"
3476     psp::PrintFontManager::get().matchFont( aInfo, rSettings.GetUILocale() );
3477 
3478 #if OSL_DEBUG_LEVEL > 1
3479     std::fprintf( stderr, "font match %s, name AFTER: \"%s\"\n",
3480              aInfo.m_nID != 0 ? "succeeded" : "failed",
3481              OUStringToOString( aInfo.m_aFamilyName, RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
3482 #endif
3483 
3484     sal_Int32 nDispDPIY = GetDisplay()->GetResolution().B();
3485     int nPointHeight = 0;
3486     static gboolean(*pAbso)(const PangoFontDescription*) =
3487         (gboolean(*)(const PangoFontDescription*))osl_getAsciiFunctionSymbol( GetSalData()->m_pPlugin, "pango_font_description_get_size_is_absolute" );
3488 
3489     if( pAbso && pAbso( pStyle->font_desc ) )
3490         nPointHeight = (nPangoHeight * 72 + nDispDPIY*PANGO_SCALE/2) / (nDispDPIY * PANGO_SCALE);
3491     else
3492         nPointHeight = nPangoHeight/PANGO_SCALE;
3493 
3494     Font aFont( aInfo.m_aFamilyName, Size( 0, nPointHeight ) );
3495     if( aInfo.m_eWeight != psp::weight::Unknown )
3496         aFont.SetWeight( PspGraphics::ToFontWeight( aInfo.m_eWeight ) );
3497     if( aInfo.m_eWidth != psp::width::Unknown )
3498         aFont.SetWidthType( PspGraphics::ToFontWidth( aInfo.m_eWidth ) );
3499     if( aInfo.m_eItalic != psp::italic::Unknown )
3500         aFont.SetItalic( PspGraphics::ToFontItalic( aInfo.m_eItalic ) );
3501     if( aInfo.m_ePitch != psp::pitch::Unknown )
3502         aFont.SetPitch( PspGraphics::ToFontPitch( aInfo.m_ePitch ) );
3503 
3504     aStyleSet.SetAppFont( aFont );
3505     aStyleSet.SetHelpFont( aFont );
3506     aStyleSet.SetTitleFont( aFont );
3507     aStyleSet.SetFloatTitleFont( aFont );
3508     aStyleSet.SetMenuFont( aFont );
3509     aStyleSet.SetToolFont( aFont );
3510     aStyleSet.SetLabelFont( aFont );
3511     aStyleSet.SetInfoFont( aFont );
3512     aStyleSet.SetRadioCheckFont( aFont );
3513     aStyleSet.SetPushButtonFont( aFont );
3514     aStyleSet.SetFieldFont( aFont );
3515     aStyleSet.SetIconFont( aFont );
3516     aStyleSet.SetGroupFont( aFont );
3517 
3518     // get cursor blink time
3519     GtkSettings *pSettings = gtk_widget_get_settings( gWidgetData[m_nScreen].gEditBoxWidget );
3520     gboolean blink = false;
3521 
3522     g_object_get( pSettings, "gtk-cursor-blink", &blink, (char *)NULL );
3523     if( blink )
3524     {
3525         gint blink_time = STYLE_CURSOR_NOBLINKTIME;
3526         g_object_get( pSettings, "gtk-cursor-blink-time", &blink_time, (char *)NULL );
3527         // set the blink_time if there is a setting and it is reasonable
3528         // else leave the default value
3529         if( blink_time > 100 && blink_time != gint(STYLE_CURSOR_NOBLINKTIME) )
3530             aStyleSet.SetCursorBlinkTime( blink_time/2 );
3531     }
3532     else
3533         aStyleSet.SetCursorBlinkTime( STYLE_CURSOR_NOBLINKTIME );
3534 
3535     gboolean showmenuicons = true;
3536     pSettings = gtk_widget_get_settings( gWidgetData[m_nScreen].gImageMenuItem );
3537     g_object_get( pSettings, "gtk-menu-images", &showmenuicons, (char *)NULL );
3538     aStyleSet.SetUseImagesInMenus( showmenuicons );
3539 
3540     // set scrollbar settings
3541     gint slider_width = 14;
3542     gint trough_border = 1;
3543     gint min_slider_length = 21;
3544 
3545     // Grab some button style attributes
3546     gtk_widget_style_get( gWidgetData[m_nScreen].gScrollHorizWidget,
3547                           "slider-width", &slider_width,
3548                           "trough-border", &trough_border,
3549                           "min-slider-length", &min_slider_length,
3550                           (char *)NULL );
3551     gint magic = trough_border ? 1 : 0;
3552     aStyleSet.SetScrollBarSize( slider_width + 2*trough_border );
3553     aStyleSet.SetMinThumbSize( min_slider_length - magic );
3554 
3555     // preferred icon style
3556     gchar* pIconThemeName = NULL;
3557     g_object_get( gtk_settings_get_default(), "gtk-icon-theme-name", &pIconThemeName, (char *)NULL );
3558     aStyleSet.SetPreferredSymbolsStyleName( OUString::createFromAscii( pIconThemeName ) );
3559     g_free( pIconThemeName );
3560 
3561     //  FIXME: need some way of fetching toolbar icon size.
3562 //  aStyleSet.SetToolbarIconSize( STYLE_TOOLBAR_ICONSIZE_SMALL );
3563 
3564     const cairo_font_options_t* pNewOptions = NULL;
3565     if( GdkScreen* pScreen = gdk_display_get_screen( gdk_display_get_default(), m_nScreen ) )
3566     {
3567 //#if !GTK_CHECK_VERSION(2,8,1)
3568 #if !GTK_CHECK_VERSION(2,9,0)
3569     static cairo_font_options_t* (*gdk_screen_get_font_options)(GdkScreen*) =
3570         (cairo_font_options_t*(*)(GdkScreen*))osl_getAsciiFunctionSymbol( GetSalData()->m_pPlugin, "gdk_screen_get_font_options" );
3571     if( gdk_screen_get_font_options != NULL )
3572 #endif
3573         pNewOptions = gdk_screen_get_font_options( pScreen );
3574     }
3575     aStyleSet.SetCairoFontOptions( pNewOptions );
3576 
3577     // finally update the collected settings
3578     rSettings.SetStyleSettings( aStyleSet );
3579 
3580     #if OSL_DEBUG_LEVEL > 1
3581     {
3582         GtkSettings* pGtkSettings = gtk_settings_get_default();
3583         GValue aValue;
3584         memset( &aValue, 0, sizeof(GValue) );
3585         g_value_init( &aValue, G_TYPE_STRING );
3586         g_object_get_property( G_OBJECT(pGtkSettings), "gtk-theme-name", &aValue );
3587         const gchar* pThemeName = g_value_get_string( &aValue );
3588         std::fprintf( stderr, "Theme name is \"%s\"\n", pThemeName );
3589         g_value_unset( &aValue );
3590     }
3591     #endif
3592     GtkSettings* pGtkSettings = gtk_settings_get_default();
3593     GValue aValue;
3594     memset( &aValue, 0, sizeof(GValue) );
3595     g_value_init( &aValue, G_TYPE_STRING );
3596     g_object_get_property( G_OBJECT(pGtkSettings), "gtk-theme-name", &aValue );
3597     const gchar* pThemeName = g_value_get_string( &aValue );
3598 
3599     // default behaviour
3600     bNeedPixmapPaint = bGlobalNeedPixmapPaint;
3601     bToolbarGripWorkaround = false;
3602     bNeedButtonStyleAsEditBackgroundWorkaround = false;
3603 
3604     // setup some workarounds for "blueprint" theme
3605     if( pThemeName && strncasecmp( pThemeName, "blueprint", 9 ) == 0 )
3606     {
3607         bNeedButtonStyleAsEditBackgroundWorkaround = true;
3608         if( GetX11SalData()->GetDisplay()->GetServerVendor() == vendor_sun )
3609         {
3610             // #i52570#, #i61532# workaround a weird paint issue;
3611             // on a Sunray Xserver sometimes painting buttons and edits
3612             // won't work when using the blueprint theme
3613             // not reproducible with simpler programs or other themes
3614             if( pThemeName && strncasecmp( pThemeName, "blueprint", 9 ) == 0 )
3615             {
3616                 bNeedPixmapPaint = true;
3617                 bToolbarGripWorkaround = true;
3618             }
3619         }
3620     }
3621     // clean up
3622     g_value_unset( &aValue );
3623 }
3624 
3625 
3626 /************************************************************************
3627  * Create a GdkPixmap filled with the contents of an area of an Xlib window
3628  ************************************************************************/
3629 
3630 GdkPixmap* GtkSalGraphics::NWGetPixmapFromScreen( Rectangle srcRect )
3631 {
3632     // Create a new pixmap to hold the composite of the window background and the control
3633     GdkPixmap * pPixmap     = gdk_pixmap_new( GDK_DRAWABLE(GetGdkWindow()), srcRect.GetWidth(), srcRect.GetHeight(), -1 );
3634     GdkGC *  pPixmapGC  = gdk_gc_new( pPixmap );
3635 
3636     if( !pPixmap || !pPixmapGC )
3637     {
3638         if ( pPixmap )
3639             g_object_unref( pPixmap );
3640         if ( pPixmapGC )
3641             g_object_unref( pPixmapGC );
3642         std::fprintf( stderr, "salnativewidgets-gtk.cxx: could not get valid pixmap from screen\n" );
3643         return( NULL );
3644     }
3645 
3646     // Copy the background of the screen into a composite pixmap
3647     CopyScreenArea( GetXDisplay(),
3648               GetDrawable(), GetScreenNumber(), GetVisual().GetDepth(),
3649               gdk_x11_drawable_get_xid(pPixmap),
3650               gdk_screen_get_number( gdk_drawable_get_screen( GDK_DRAWABLE(pPixmap) ) ),
3651               gdk_drawable_get_depth( GDK_DRAWABLE( pPixmap ) ),
3652               gdk_x11_gc_get_xgc(pPixmapGC),
3653               srcRect.Left(), srcRect.Top(), srcRect.GetWidth(), srcRect.GetHeight(), 0, 0 );
3654 
3655     g_object_unref( pPixmapGC );
3656     return( pPixmap );
3657 }
3658 
3659 
3660 
3661 
3662 /************************************************************************
3663  * Copy an alpha pixmap to screen using a gc with clipping
3664  ************************************************************************/
3665 
3666 sal_Bool GtkSalGraphics::NWRenderPixmapToScreen( GdkPixmap* pPixmap, Rectangle dstRect )
3667 {
3668     // The GC can't be null, otherwise we'd have no clip region
3669     GC aFontGC = GetFontGC();
3670     if( aFontGC == NULL )
3671     {
3672         std::fprintf(stderr, "salnativewidgets.cxx: no valid GC\n" );
3673         return( sal_False );
3674     }
3675 
3676     if ( !pPixmap )
3677         return( sal_False );
3678 
3679     // Copy the background of the screen into a composite pixmap
3680     CopyScreenArea( GetXDisplay(),
3681               GDK_DRAWABLE_XID(pPixmap),
3682               gdk_screen_get_number( gdk_drawable_get_screen( GDK_DRAWABLE(pPixmap) ) ),
3683               gdk_drawable_get_depth( GDK_DRAWABLE(pPixmap) ),
3684               GetDrawable(), m_nScreen, GetVisual().GetDepth(),
3685               aFontGC,
3686               0, 0, dstRect.GetWidth(), dstRect.GetHeight(), dstRect.Left(), dstRect.Top() );
3687 
3688     return( sal_True );
3689 }
3690 
3691 
3692 /************************************************************************
3693  * State conversion
3694  ************************************************************************/
3695 static void NWConvertVCLStateToGTKState( ControlState nVCLState,
3696             GtkStateType* nGTKState, GtkShadowType* nGTKShadow )
3697 {
3698     *nGTKShadow = GTK_SHADOW_OUT;
3699     *nGTKState = GTK_STATE_INSENSITIVE;
3700 
3701     if ( nVCLState & CTRL_STATE_ENABLED )
3702     {
3703         if ( nVCLState & CTRL_STATE_PRESSED )
3704         {
3705             *nGTKState = GTK_STATE_ACTIVE;
3706             *nGTKShadow = GTK_SHADOW_IN;
3707         }
3708         else if ( nVCLState & CTRL_STATE_ROLLOVER )
3709         {
3710             *nGTKState = GTK_STATE_PRELIGHT;
3711             *nGTKShadow = GTK_SHADOW_OUT;
3712         }
3713         else
3714         {
3715             *nGTKState = GTK_STATE_NORMAL;
3716             *nGTKShadow = GTK_SHADOW_OUT;
3717         }
3718     }
3719 }
3720 
3721 /************************************************************************
3722  * Set widget flags
3723  ************************************************************************/
3724 static void NWSetWidgetState( GtkWidget* widget, ControlState nState, GtkStateType nGtkState )
3725 {
3726     // Set to default state, then build up from there
3727     GTK_WIDGET_UNSET_FLAGS( widget, GTK_HAS_DEFAULT );
3728     GTK_WIDGET_UNSET_FLAGS( widget, GTK_HAS_FOCUS );
3729     GTK_WIDGET_UNSET_FLAGS( widget, GTK_SENSITIVE );
3730     GTK_WIDGET_SET_FLAGS( widget, gWidgetDefaultFlags[(long)widget] );
3731 
3732     if ( nState & CTRL_STATE_DEFAULT )
3733         GTK_WIDGET_SET_FLAGS( widget, GTK_HAS_DEFAULT );
3734     if ( !GTK_IS_TOGGLE_BUTTON(widget) && (nState & CTRL_STATE_FOCUSED) )
3735         GTK_WIDGET_SET_FLAGS( widget, GTK_HAS_FOCUS );
3736     if ( nState & CTRL_STATE_ENABLED )
3737         GTK_WIDGET_SET_FLAGS( widget, GTK_SENSITIVE );
3738     gtk_widget_set_state( widget, nGtkState );
3739 }
3740 
3741 /************************************************************************
3742  * Widget ensure functions - make sure cached objects are valid
3743  ************************************************************************/
3744 
3745 //-------------------------------------
3746 
3747 static void NWAddWidgetToCacheWindow( GtkWidget* widget, int nScreen )
3748 {
3749     NWFWidgetData& rData = gWidgetData[nScreen];
3750     if ( !rData.gCacheWindow || !rData.gDumbContainer )
3751     {
3752         if ( !rData.gCacheWindow )
3753         {
3754             rData.gCacheWindow = gtk_window_new( GTK_WINDOW_TOPLEVEL );
3755             GdkScreen* pScreen = gdk_display_get_screen( gdk_display_get_default(), nScreen );
3756             if( pScreen )
3757                 gtk_window_set_screen( GTK_WINDOW(rData.gCacheWindow), pScreen );
3758         }
3759         if ( !rData.gDumbContainer )
3760             rData.gDumbContainer = gtk_fixed_new();
3761         gtk_container_add( GTK_CONTAINER(rData.gCacheWindow), rData.gDumbContainer );
3762         gtk_widget_realize( rData.gDumbContainer );
3763         gtk_widget_realize( rData.gCacheWindow );
3764     }
3765 
3766     gtk_container_add( GTK_CONTAINER(rData.gDumbContainer), widget );
3767     gtk_widget_realize( widget );
3768     gtk_widget_ensure_style( widget );
3769 
3770     // Store widget's default flags
3771     gWidgetDefaultFlags[ (long)widget ] = GTK_WIDGET_FLAGS( widget );
3772 }
3773 
3774 //-------------------------------------
3775 
3776 static void NWEnsureGTKButton( int nScreen )
3777 {
3778     if ( !gWidgetData[nScreen].gBtnWidget )
3779     {
3780         gWidgetData[nScreen].gBtnWidget = gtk_button_new_with_label( "" );
3781         NWAddWidgetToCacheWindow( gWidgetData[nScreen].gBtnWidget, nScreen );
3782     }
3783 }
3784 
3785 //-------------------------------------
3786 
3787 static void NWEnsureGTKRadio( int nScreen )
3788 {
3789     if ( !gWidgetData[nScreen].gRadioWidget || !gWidgetData[nScreen].gRadioWidgetSibling )
3790     {
3791         gWidgetData[nScreen].gRadioWidget = gtk_radio_button_new( NULL );
3792         gWidgetData[nScreen].gRadioWidgetSibling = gtk_radio_button_new_from_widget( GTK_RADIO_BUTTON(gWidgetData[nScreen].gRadioWidget) );
3793         NWAddWidgetToCacheWindow( gWidgetData[nScreen].gRadioWidget, nScreen );
3794         NWAddWidgetToCacheWindow( gWidgetData[nScreen].gRadioWidgetSibling, nScreen );
3795     }
3796 }
3797 
3798 //-------------------------------------
3799 
3800 static void NWEnsureGTKCheck( int nScreen )
3801 {
3802     if ( !gWidgetData[nScreen].gCheckWidget )
3803     {
3804         gWidgetData[nScreen].gCheckWidget = gtk_check_button_new();
3805         NWAddWidgetToCacheWindow( gWidgetData[nScreen].gCheckWidget, nScreen );
3806     }
3807 }
3808 
3809 //-------------------------------------
3810 
3811 static void NWEnsureGTKScrollbars( int nScreen )
3812 {
3813     if ( !gWidgetData[nScreen].gScrollHorizWidget )
3814     {
3815         gWidgetData[nScreen].gScrollHorizWidget = gtk_hscrollbar_new( NULL );
3816         NWAddWidgetToCacheWindow( gWidgetData[nScreen].gScrollHorizWidget, nScreen );
3817     }
3818 
3819     if ( !gWidgetData[nScreen].gScrollVertWidget )
3820     {
3821         gWidgetData[nScreen].gScrollVertWidget = gtk_vscrollbar_new( NULL );
3822         NWAddWidgetToCacheWindow( gWidgetData[nScreen].gScrollVertWidget, nScreen );
3823     }
3824 }
3825 
3826 //-------------------------------------
3827 
3828 static void NWEnsureGTKArrow( int nScreen )
3829 {
3830     if ( !gWidgetData[nScreen].gArrowWidget || !gWidgetData[nScreen].gDropdownWidget )
3831     {
3832         gWidgetData[nScreen].gDropdownWidget = gtk_toggle_button_new();
3833         NWAddWidgetToCacheWindow( gWidgetData[nScreen].gDropdownWidget, nScreen );
3834         gWidgetData[nScreen].gArrowWidget = gtk_arrow_new( GTK_ARROW_DOWN, GTK_SHADOW_OUT );
3835         gtk_container_add( GTK_CONTAINER(gWidgetData[nScreen].gDropdownWidget), gWidgetData[nScreen].gArrowWidget );
3836         gtk_widget_set_rc_style( gWidgetData[nScreen].gArrowWidget );
3837         gtk_widget_realize( gWidgetData[nScreen].gArrowWidget );
3838     }
3839 }
3840 
3841 //-------------------------------------
3842 
3843 static void NWEnsureGTKEditBox( int nScreen )
3844 {
3845     if ( !gWidgetData[nScreen].gEditBoxWidget )
3846     {
3847         gWidgetData[nScreen].gEditBoxWidget = gtk_entry_new();
3848         NWAddWidgetToCacheWindow( gWidgetData[nScreen].gEditBoxWidget, nScreen );
3849     }
3850 }
3851 
3852 //-------------------------------------
3853 
3854 static void NWEnsureGTKSpinButton( int nScreen )
3855 {
3856     if ( !gWidgetData[nScreen].gSpinButtonWidget )
3857     {
3858         GtkAdjustment *adj = GTK_ADJUSTMENT( gtk_adjustment_new(0, 0, 1, 1, 1, 0) );
3859         gWidgetData[nScreen].gSpinButtonWidget = gtk_spin_button_new( adj, 1, 2 );
3860 
3861         //Setting non-editable means it doesn't blink, so there's no timeouts
3862         //running around to nobble us
3863         gtk_editable_set_editable(GTK_EDITABLE(gWidgetData[nScreen].gSpinButtonWidget), false);
3864 
3865         NWAddWidgetToCacheWindow( gWidgetData[nScreen].gSpinButtonWidget, nScreen );
3866     }
3867 }
3868 
3869 //-------------------------------------
3870 
3871 static void NWEnsureGTKNotebook( int nScreen )
3872 {
3873     if ( !gWidgetData[nScreen].gNotebookWidget )
3874     {
3875         gWidgetData[nScreen].gNotebookWidget = gtk_notebook_new();
3876         NWAddWidgetToCacheWindow( gWidgetData[nScreen].gNotebookWidget, nScreen );
3877     }
3878 }
3879 
3880 //-------------------------------------
3881 
3882 static void NWEnsureGTKOptionMenu( int nScreen )
3883 {
3884     if ( !gWidgetData[nScreen].gOptionMenuWidget )
3885     {
3886         gWidgetData[nScreen].gOptionMenuWidget = gtk_option_menu_new();
3887         NWAddWidgetToCacheWindow( gWidgetData[nScreen].gOptionMenuWidget, nScreen );
3888     }
3889 }
3890 
3891 //-------------------------------------
3892 
3893 static void NWEnsureGTKCombo( int nScreen )
3894 {
3895     if ( !gWidgetData[nScreen].gComboWidget )
3896     {
3897         gWidgetData[nScreen].gComboWidget = gtk_combo_new();
3898 
3899         // #i59129# Setting non-editable means it doesn't blink, so
3900         // there are no timeouts running around to nobble us
3901         gtk_editable_set_editable(GTK_EDITABLE(GTK_COMBO(gWidgetData[nScreen].gComboWidget)->entry), false);
3902 
3903         NWAddWidgetToCacheWindow( gWidgetData[nScreen].gComboWidget, nScreen );
3904         // Must realize the ComboBox's children, since GTK
3905         // does not do this for us in GtkCombo::gtk_widget_realize()
3906         gtk_widget_realize( GTK_COMBO(gWidgetData[nScreen].gComboWidget)->button );
3907         gtk_widget_realize( GTK_COMBO(gWidgetData[nScreen].gComboWidget)->entry );
3908     }
3909 }
3910 
3911 //-------------------------------------
3912 
3913 static void NWEnsureGTKScrolledWindow( int nScreen )
3914 {
3915     if ( !gWidgetData[nScreen].gScrolledWindowWidget )
3916     {
3917         GtkAdjustment *hadj = GTK_ADJUSTMENT( gtk_adjustment_new(0, 0, 0, 0, 0, 0) );
3918         GtkAdjustment *vadj = GTK_ADJUSTMENT( gtk_adjustment_new(0, 0, 0, 0, 0, 0) );
3919 
3920         gWidgetData[nScreen].gScrolledWindowWidget = gtk_scrolled_window_new( hadj, vadj );
3921         NWAddWidgetToCacheWindow( gWidgetData[nScreen].gScrolledWindowWidget, nScreen );
3922     }
3923 }
3924 
3925 //-------------------------------------
3926 
3927 static void NWEnsureGTKToolbar( int nScreen )
3928 {
3929     if( !gWidgetData[nScreen].gToolbarWidget )
3930     {
3931         gWidgetData[nScreen].gToolbarWidget = gtk_toolbar_new();
3932         NWAddWidgetToCacheWindow( gWidgetData[nScreen].gToolbarWidget, nScreen );
3933         gWidgetData[nScreen].gToolbarButtonWidget = gtk_button_new();
3934         gWidgetData[nScreen].gToolbarToggleWidget = gtk_toggle_button_new();
3935 
3936         GtkReliefStyle aRelief = GTK_RELIEF_NORMAL;
3937         gtk_widget_ensure_style( gWidgetData[nScreen].gToolbarWidget );
3938         gtk_widget_style_get( gWidgetData[nScreen].gToolbarWidget,
3939                               "button_relief", &aRelief,
3940                               (char *)NULL);
3941 
3942         gtk_button_set_relief( GTK_BUTTON(gWidgetData[nScreen].gToolbarButtonWidget), aRelief );
3943         GTK_WIDGET_UNSET_FLAGS( gWidgetData[nScreen].gToolbarButtonWidget, GTK_CAN_FOCUS );
3944         GTK_WIDGET_UNSET_FLAGS( gWidgetData[nScreen].gToolbarButtonWidget, GTK_CAN_DEFAULT );
3945         NWAddWidgetToCacheWindow( gWidgetData[nScreen].gToolbarButtonWidget, nScreen );
3946 
3947         gtk_button_set_relief( GTK_BUTTON(gWidgetData[nScreen].gToolbarToggleWidget), aRelief );
3948         GTK_WIDGET_UNSET_FLAGS( gWidgetData[nScreen].gToolbarToggleWidget, GTK_CAN_FOCUS );
3949         GTK_WIDGET_UNSET_FLAGS( gWidgetData[nScreen].gToolbarToggleWidget, GTK_CAN_DEFAULT );
3950         NWAddWidgetToCacheWindow( gWidgetData[nScreen].gToolbarToggleWidget, nScreen );
3951     }
3952     if( ! gWidgetData[nScreen].gHandleBoxWidget )
3953     {
3954         gWidgetData[nScreen].gHandleBoxWidget = gtk_handle_box_new();
3955         NWAddWidgetToCacheWindow( gWidgetData[nScreen].gHandleBoxWidget, nScreen );
3956     }
3957 }
3958 
3959 //-------------------------------------
3960 
3961 static void NWEnsureGTKMenubar( int nScreen )
3962 {
3963     if( !gWidgetData[nScreen].gMenubarWidget )
3964     {
3965         gWidgetData[nScreen].gMenubarWidget = gtk_menu_bar_new();
3966         gWidgetData[nScreen].gMenuItemMenubarWidget = gtk_menu_item_new_with_label( "b" );
3967         gtk_menu_shell_append( GTK_MENU_SHELL( gWidgetData[nScreen].gMenubarWidget ), gWidgetData[nScreen].gMenuItemMenubarWidget );
3968         gtk_widget_show( gWidgetData[nScreen].gMenuItemMenubarWidget );
3969         NWAddWidgetToCacheWindow( gWidgetData[nScreen].gMenubarWidget, nScreen );
3970         gtk_widget_show( gWidgetData[nScreen].gMenubarWidget );
3971 
3972         // do what NWAddWidgetToCacheWindow does except adding to def container
3973         gtk_widget_realize( gWidgetData[nScreen].gMenuItemMenubarWidget );
3974         gtk_widget_ensure_style( gWidgetData[nScreen].gMenuItemMenubarWidget );
3975 
3976         gWidgetDefaultFlags[ (long)gWidgetData[nScreen].gMenuItemMenubarWidget ] = GTK_WIDGET_FLAGS( gWidgetData[nScreen].gMenuItemMenubarWidget );
3977     }
3978 }
3979 
3980 static void NWEnsureGTKMenu( int nScreen )
3981 {
3982     if( !gWidgetData[nScreen].gMenuWidget )
3983     {
3984         gWidgetData[nScreen].gMenuWidget              = gtk_menu_new();
3985         gWidgetData[nScreen].gMenuItemMenuWidget      = gtk_menu_item_new_with_label( "b" );
3986         gWidgetData[nScreen].gMenuItemCheckMenuWidget = gtk_check_menu_item_new_with_label( "b" );
3987         gWidgetData[nScreen].gMenuItemRadioMenuWidget = gtk_radio_menu_item_new_with_label( NULL, "b" );
3988         gWidgetData[nScreen].gImageMenuItem           = gtk_image_menu_item_new();
3989 
3990         gtk_menu_shell_append( GTK_MENU_SHELL( gWidgetData[nScreen].gMenuWidget ), gWidgetData[nScreen].gMenuItemMenuWidget );
3991         gtk_menu_shell_append( GTK_MENU_SHELL( gWidgetData[nScreen].gMenuWidget ), gWidgetData[nScreen].gMenuItemCheckMenuWidget );
3992         gtk_menu_shell_append( GTK_MENU_SHELL( gWidgetData[nScreen].gMenuWidget ), gWidgetData[nScreen].gMenuItemRadioMenuWidget );
3993         gtk_menu_shell_append( GTK_MENU_SHELL( gWidgetData[nScreen].gMenuWidget ), gWidgetData[nScreen].gImageMenuItem );
3994 
3995         // do what NWAddWidgetToCacheWindow does except adding to def container
3996         gtk_widget_realize( gWidgetData[nScreen].gMenuWidget );
3997         gtk_widget_ensure_style( gWidgetData[nScreen].gMenuWidget );
3998 
3999         gtk_widget_realize( gWidgetData[nScreen].gMenuItemMenuWidget );
4000         gtk_widget_ensure_style( gWidgetData[nScreen].gMenuItemMenuWidget );
4001 
4002         gtk_widget_realize( gWidgetData[nScreen].gMenuItemCheckMenuWidget );
4003         gtk_widget_ensure_style( gWidgetData[nScreen].gMenuItemCheckMenuWidget );
4004 
4005         gtk_widget_realize( gWidgetData[nScreen].gMenuItemRadioMenuWidget );
4006         gtk_widget_ensure_style( gWidgetData[nScreen].gMenuItemRadioMenuWidget );
4007 
4008         gtk_widget_realize( gWidgetData[nScreen].gImageMenuItem );
4009         gtk_widget_ensure_style( gWidgetData[nScreen].gImageMenuItem );
4010 
4011         gWidgetDefaultFlags[ (long)gWidgetData[nScreen].gMenuWidget ] = GTK_WIDGET_FLAGS( gWidgetData[nScreen].gMenuWidget );
4012         gWidgetDefaultFlags[ (long)gWidgetData[nScreen].gMenuItemMenuWidget ] = GTK_WIDGET_FLAGS( gWidgetData[nScreen].gMenuItemMenuWidget );
4013         gWidgetDefaultFlags[ (long)gWidgetData[nScreen].gMenuItemCheckMenuWidget ] = GTK_WIDGET_FLAGS( gWidgetData[nScreen].gMenuItemCheckMenuWidget );
4014         gWidgetDefaultFlags[ (long)gWidgetData[nScreen].gMenuItemRadioMenuWidget ] = GTK_WIDGET_FLAGS( gWidgetData[nScreen].gMenuItemRadioMenuWidget );
4015         gWidgetDefaultFlags[ (long)gWidgetData[nScreen].gImageMenuItem ] = GTK_WIDGET_FLAGS( gWidgetData[nScreen].gImageMenuItem );
4016     }
4017 }
4018 
4019 static void NWEnsureGTKTooltip( int nScreen )
4020 {
4021     if( !gWidgetData[nScreen].gTooltipPopup )
4022     {
4023         gWidgetData[nScreen].gTooltipPopup = gtk_window_new (GTK_WINDOW_POPUP);
4024         GdkScreen* pScreen = gdk_display_get_screen( gdk_display_get_default(), nScreen );
4025         if( pScreen )
4026             gtk_window_set_screen( GTK_WINDOW(gWidgetData[nScreen].gTooltipPopup), pScreen );
4027         gtk_widget_set_name( gWidgetData[nScreen].gTooltipPopup, "gtk-tooltips");
4028         gtk_widget_realize( gWidgetData[nScreen].gTooltipPopup );
4029         gtk_widget_ensure_style( gWidgetData[nScreen].gTooltipPopup );
4030     }
4031 }
4032 
4033 static void NWEnsureGTKProgressBar( int nScreen )
4034 {
4035     if( !gWidgetData[nScreen].gProgressBar )
4036     {
4037         gWidgetData[nScreen].gProgressBar = gtk_progress_bar_new ();
4038         NWAddWidgetToCacheWindow( gWidgetData[nScreen].gProgressBar, nScreen );
4039     }
4040 }
4041 
4042 static void NWEnsureGTKTreeView( int nScreen )
4043 {
4044     if( !gWidgetData[nScreen].gTreeView )
4045     {
4046         gWidgetData[nScreen].gTreeView = gtk_tree_view_new ();
4047         NWAddWidgetToCacheWindow( gWidgetData[nScreen].gTreeView, nScreen );
4048     }
4049 }
4050 
4051 static void NWEnsureGTKSlider( int nScreen )
4052 {
4053     if( !gWidgetData[nScreen].gHScale )
4054     {
4055         gWidgetData[nScreen].gHScale = gtk_hscale_new_with_range(0, 10, 1);
4056         NWAddWidgetToCacheWindow( gWidgetData[nScreen].gHScale, nScreen );
4057     }
4058     if( !gWidgetData[nScreen].gVScale )
4059     {
4060         gWidgetData[nScreen].gVScale = gtk_vscale_new_with_range(0, 10, 1);
4061         NWAddWidgetToCacheWindow( gWidgetData[nScreen].gVScale, nScreen );
4062     }
4063 }
4064