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