1/////////////////////////////////////////////////////////////////////////////
2// Name:        src/gtk1/settings.cpp
3// Purpose:
4// Author:      Robert Roebling
5// Modified by: Mart Raudsepp (GetMetric)
6// Id:          $Id: settings.cpp 67017 2011-02-25 09:37:28Z JS $
7// Copyright:   (c) 1998 Robert Roebling
8// Licence:     wxWindows licence
9/////////////////////////////////////////////////////////////////////////////
10
11// For compilers that support precompilation, includes "wx.h".
12#include "wx/wxprec.h"
13
14#include "wx/settings.h"
15
16#ifndef WX_PRECOMP
17    #include "wx/cmndata.h"
18    #include "wx/toplevel.h"
19#endif
20
21#include "wx/fontutil.h"
22
23#include <gdk/gdk.h>
24#include <gdk/gdkx.h>
25#include <gdk/gdkprivate.h>
26#include <gtk/gtk.h>
27
28#include <X11/Xatom.h>
29
30#define SHIFT (8*(sizeof(short int)-sizeof(char)))
31
32// ----------------------------------------------------------------------------
33// wxSystemObjects
34// ----------------------------------------------------------------------------
35
36struct wxSystemObjects
37{
38    wxColour m_colBtnFace,
39             m_colBtnShadow,
40             m_colBtnHighlight,
41             m_colHighlight,
42             m_colHighlightText,
43             m_colListBox,
44             m_colBtnText,
45             m_colMenuItemHighlight,
46             m_colTooltip,
47             m_colTooltipText;
48
49    wxFont m_fontSystem;
50};
51
52static wxSystemObjects gs_objects;
53
54// ----------------------------------------------------------------------------
55// wxSystemSettings implementation
56// ----------------------------------------------------------------------------
57
58// kind of widget to use in GetColourFromGTKWidget
59enum wxGtkWidgetType
60{
61    wxGTK_BUTTON,
62    wxGTK_LIST,
63    wxGTK_MENUITEM
64};
65
66// the colour we need
67enum wxGtkColourType
68{
69    wxGTK_FG,
70    wxGTK_BG,
71    wxGTK_BASE
72};
73
74// wxSystemSettings::GetColour() helper: get the colours from a GTK+
75// widget style, return true if we did get them, false to use defaults
76static bool GetColourFromGTKWidget(int& red, int& green, int& blue,
77                                   wxGtkWidgetType type = wxGTK_BUTTON,
78                                   GtkStateType state = GTK_STATE_NORMAL,
79                                   wxGtkColourType colour = wxGTK_BG)
80{
81    GtkWidget *widget;
82    switch ( type )
83    {
84        default:
85            wxFAIL_MSG( _T("unexpected GTK widget type") );
86            // fall through
87
88        case wxGTK_BUTTON:
89            widget = gtk_button_new();
90            break;
91
92        case wxGTK_LIST:
93            widget = gtk_list_new();
94            break;
95
96        case wxGTK_MENUITEM:
97            widget = gtk_menu_item_new();
98    }
99
100    GtkStyle *def = gtk_rc_get_style( widget );
101    if ( !def )
102        def = gtk_widget_get_default_style();
103
104    bool ok;
105    if ( def )
106    {
107        GdkColor *col;
108        switch ( colour )
109        {
110            default:
111                wxFAIL_MSG( _T("unexpected GTK colour type") );
112                // fall through
113
114            case wxGTK_FG:
115                col = def->fg;
116                break;
117
118            case wxGTK_BG:
119                col = def->bg;
120                break;
121
122            case wxGTK_BASE:
123                col = def->base;
124                break;
125        }
126
127        red = col[state].red;
128        green = col[state].green;
129        blue = col[state].blue;
130
131        ok = true;
132    }
133    else
134    {
135        ok = false;
136    }
137
138    gtk_widget_destroy( widget );
139
140    return ok;
141}
142
143static void GetTooltipColors()
144{
145    GtkTooltips* tooltips = gtk_tooltips_new();
146    gtk_tooltips_force_window(tooltips);
147    gtk_widget_ensure_style(tooltips->tip_window);
148    GdkColor c = tooltips->tip_window->style->bg[GTK_STATE_NORMAL];
149    gs_objects.m_colTooltip = wxColor(c.red >> SHIFT, c.green >> SHIFT, c.blue >> SHIFT);
150    c = tooltips->tip_window->style->fg[GTK_STATE_NORMAL];
151    gs_objects.m_colTooltipText = wxColor(c.red >> SHIFT, c.green >> SHIFT, c.blue >> SHIFT);
152    gtk_object_sink(wx_reinterpret_cast(GtkObject*, tooltips));
153}
154
155wxColour wxSystemSettingsNative::GetColour( wxSystemColour index )
156{
157    switch (index)
158    {
159        case wxSYS_COLOUR_SCROLLBAR:
160        case wxSYS_COLOUR_BACKGROUND:
161        case wxSYS_COLOUR_INACTIVECAPTION:
162        case wxSYS_COLOUR_MENU:
163        case wxSYS_COLOUR_WINDOWFRAME:
164        case wxSYS_COLOUR_ACTIVEBORDER:
165        case wxSYS_COLOUR_INACTIVEBORDER:
166        case wxSYS_COLOUR_BTNFACE:
167        case wxSYS_COLOUR_MENUBAR:
168        case wxSYS_COLOUR_3DLIGHT:
169            if (!gs_objects.m_colBtnFace.Ok())
170            {
171                int red, green, blue;
172                if ( !GetColourFromGTKWidget(red, green, blue) )
173                {
174                    red =
175                    green = 0;
176                    blue = 0x9c40;
177                }
178
179                gs_objects.m_colBtnFace = wxColour( red   >> SHIFT,
180                                                   green >> SHIFT,
181                                                   blue  >> SHIFT );
182            }
183            return gs_objects.m_colBtnFace;
184
185        case wxSYS_COLOUR_WINDOW:
186            return *wxWHITE;
187
188        case wxSYS_COLOUR_3DDKSHADOW:
189            return *wxBLACK;
190
191        case wxSYS_COLOUR_GRAYTEXT:
192        case wxSYS_COLOUR_BTNSHADOW:
193        //case wxSYS_COLOUR_3DSHADOW:
194            if (!gs_objects.m_colBtnShadow.Ok())
195            {
196                wxColour faceColour(GetColour(wxSYS_COLOUR_3DFACE));
197                gs_objects.m_colBtnShadow =
198                   wxColour((unsigned char) (faceColour.Red() * 0.666),
199                            (unsigned char) (faceColour.Green() * 0.666),
200                            (unsigned char) (faceColour.Blue() * 0.666));
201            }
202
203            return gs_objects.m_colBtnShadow;
204
205        case wxSYS_COLOUR_3DHIGHLIGHT:
206        //case wxSYS_COLOUR_BTNHIGHLIGHT:
207            return * wxWHITE;
208
209        case wxSYS_COLOUR_HIGHLIGHT:
210            if (!gs_objects.m_colHighlight.Ok())
211            {
212                int red, green, blue;
213                if ( !GetColourFromGTKWidget(red, green, blue,
214                                             wxGTK_BUTTON,
215                                             GTK_STATE_SELECTED) )
216                {
217                    red =
218                    green = 0;
219                    blue = 0x9c40;
220                }
221
222                gs_objects.m_colHighlight = wxColour( red   >> SHIFT,
223                                                        green >> SHIFT,
224                                                        blue  >> SHIFT );
225            }
226            return gs_objects.m_colHighlight;
227
228        case wxSYS_COLOUR_LISTBOX:
229            if (!gs_objects.m_colListBox.Ok())
230            {
231                int red, green, blue;
232                if ( GetColourFromGTKWidget(red, green, blue,
233                                            wxGTK_LIST,
234                                            GTK_STATE_NORMAL,
235                                            wxGTK_BASE) )
236                {
237                    gs_objects.m_colListBox = wxColour( red   >> SHIFT,
238                                                          green >> SHIFT,
239                                                          blue  >> SHIFT );
240                }
241                else
242                {
243                    gs_objects.m_colListBox = wxColour(*wxWHITE);
244                }
245            }
246            return gs_objects.m_colListBox;
247
248        case wxSYS_COLOUR_MENUTEXT:
249        case wxSYS_COLOUR_WINDOWTEXT:
250        case wxSYS_COLOUR_CAPTIONTEXT:
251        case wxSYS_COLOUR_INACTIVECAPTIONTEXT:
252        case wxSYS_COLOUR_BTNTEXT:
253        case wxSYS_COLOUR_LISTBOXTEXT:
254            if (!gs_objects.m_colBtnText.Ok())
255            {
256                int red, green, blue;
257                if ( !GetColourFromGTKWidget(red, green, blue,
258                                             wxGTK_BUTTON,
259                                             GTK_STATE_NORMAL,
260                                             wxGTK_FG) )
261                {
262                    red =
263                    green =
264                    blue = 0;
265                }
266
267                gs_objects.m_colBtnText = wxColour( red   >> SHIFT,
268                                                      green >> SHIFT,
269                                                      blue  >> SHIFT );
270            }
271            return gs_objects.m_colBtnText;
272
273        case wxSYS_COLOUR_INFOBK:
274            if (!gs_objects.m_colTooltip.Ok()) {
275                GetTooltipColors();
276            }
277            return gs_objects.m_colTooltip;
278
279        case wxSYS_COLOUR_INFOTEXT:
280            if (!gs_objects.m_colTooltipText.Ok()) {
281                GetTooltipColors();
282            }
283            return gs_objects.m_colTooltipText;
284
285        case wxSYS_COLOUR_HIGHLIGHTTEXT:
286        case wxSYS_COLOUR_LISTBOXHIGHLIGHTTEXT:
287            if (!gs_objects.m_colHighlightText.Ok())
288            {
289                wxColour hclr = GetColour(wxSYS_COLOUR_HIGHLIGHT);
290                if (hclr.Red() > 200 && hclr.Green() > 200 && hclr.Blue() > 200)
291                    gs_objects.m_colHighlightText = wxColour(*wxBLACK);
292                else
293                    gs_objects.m_colHighlightText = wxColour(*wxWHITE);
294            }
295            return gs_objects.m_colHighlightText;
296
297        case wxSYS_COLOUR_APPWORKSPACE:
298            return *wxWHITE;    // ?
299
300        case wxSYS_COLOUR_ACTIVECAPTION:
301        case wxSYS_COLOUR_MENUHILIGHT:
302            if (!gs_objects.m_colMenuItemHighlight.Ok())
303            {
304                int red, green, blue;
305                if ( !GetColourFromGTKWidget(red, green, blue,
306                                             wxGTK_MENUITEM,
307                                             GTK_STATE_SELECTED,
308                                             wxGTK_BG) )
309                {
310                    red =
311                    green =
312                    blue = 0;
313                }
314
315                gs_objects.m_colMenuItemHighlight = wxColour( red  >> SHIFT,
316                                                              green >> SHIFT,
317                                                              blue  >> SHIFT );
318            }
319            return gs_objects.m_colMenuItemHighlight;
320
321        case wxSYS_COLOUR_HOTLIGHT:
322        case wxSYS_COLOUR_GRADIENTACTIVECAPTION:
323        case wxSYS_COLOUR_GRADIENTINACTIVECAPTION:
324            // TODO
325            return *wxBLACK;
326
327        case wxSYS_COLOUR_MAX:
328        default:
329            wxFAIL_MSG( _T("unknown system colour index") );
330    }
331
332    return *wxWHITE;
333}
334
335wxFont wxSystemSettingsNative::GetFont( wxSystemFont index )
336{
337    switch (index)
338    {
339        case wxSYS_OEM_FIXED_FONT:
340        case wxSYS_ANSI_FIXED_FONT:
341        case wxSYS_SYSTEM_FIXED_FONT:
342        {
343            return *wxNORMAL_FONT;
344        }
345        case wxSYS_ANSI_VAR_FONT:
346        case wxSYS_SYSTEM_FONT:
347        case wxSYS_DEVICE_DEFAULT_FONT:
348        case wxSYS_DEFAULT_GUI_FONT:
349        {
350            if (!gs_objects.m_fontSystem.Ok())
351            {
352                gs_objects.m_fontSystem = wxFont( 12, wxSWISS, wxNORMAL, wxNORMAL );
353            }
354            return gs_objects.m_fontSystem;
355        }
356
357        default:
358            return wxNullFont;
359    }
360}
361
362int wxSystemSettingsNative::GetMetric( wxSystemMetric index, wxWindow* win )
363{
364    switch (index)
365    {
366        case wxSYS_CURSOR_X:
367        case wxSYS_CURSOR_Y:
368            return 16;
369
370        // MBN: ditto for icons
371        case wxSYS_ICON_X:     return 32;
372        case wxSYS_ICON_Y:     return 32;
373
374        case wxSYS_SCREEN_X:
375            return gdk_screen_width();
376
377        case wxSYS_SCREEN_Y:
378            return gdk_screen_height();
379
380        case wxSYS_HSCROLL_Y:  return 15;
381        case wxSYS_VSCROLL_X:  return 15;
382
383// a gtk1 implementation should be possible too if gtk2 efficiency/convenience functions aren't used
384#if 0
385        case wxSYS_CAPTION_Y:
386            if (!window)
387                // No realized window specified, and no implementation for that case yet.
388                return -1;
389
390            // Check if wm supports frame extents - we can't know the caption height if it does not.
391#if GTK_CHECK_VERSION(2,2,0)
392            if (!gtk_check_version(2,2,0))
393            {
394                if (!gdk_x11_screen_supports_net_wm_hint(
395                        gdk_drawable_get_screen(window),
396                        gdk_atom_intern("_NET_FRAME_EXTENTS", false) ) )
397                    return -1;
398            }
399            else
400#endif
401            {
402                if (!gdk_net_wm_supports(gdk_atom_intern("_NET_FRAME_EXTENTS", false)))
403                    return -1;
404            }
405
406            wxASSERT_MSG( wxDynamicCast(win, wxTopLevelWindow),
407                          wxT("Asking for caption height of a non toplevel window") );
408
409            // Get the height of the top windowmanager border.
410            // This is the titlebar in most cases. The titlebar might be elsewhere, and
411            // we could check which is the thickest wm border to decide on which side the
412            // titlebar is, but this might lead to interesting behaviours in used code.
413            // Reconsider when we have a way to report to the user on which side it is.
414
415            Atom type;
416            gint format;
417            gulong nitems;
418
419#if GTK_CHECK_VERSION(2,2,0)
420            if (!gtk_check_version(2,2,0))
421            {
422                gulong bytes_after;
423                success = (XGetWindowProperty (GDK_DISPLAY_XDISPLAY(gdk_drawable_get_display(window)),
424                                    GDK_WINDOW_XWINDOW(window),
425                                    gdk_x11_get_xatom_by_name_for_display (
426                                            gdk_drawable_get_display(window),
427                                            "_NET_FRAME_EXTENTS" ),
428                                    0, // left, right, top, bottom, CARDINAL[4]/32
429                                    G_MAXLONG, // size of long
430                                    false, // do not delete property
431                                    XA_CARDINAL, // 32 bit
432                                    &type, &format, &nitems, &bytes_after, &data
433                                   ) == Success);
434            }
435#endif
436            if (success)
437            {
438                int caption_height = -1;
439
440                if ((type == XA_CARDINAL) && (format == 32) && (nitems >= 3) && (data))
441                {
442                    long *borders;
443                    borders = (long*)data;
444                    caption_height = borders[2]; // top frame extent
445                }
446
447                if (data)
448                    XFree(data);
449
450                return caption_height;
451            }
452
453            // Try a default approach without a window pointer, if possible
454            // ...
455
456            return -1;
457#endif // gtk2
458
459        case wxSYS_PENWINDOWS_PRESENT:
460            // No MS Windows for Pen computing extension available in X11 based gtk+.
461            return 0;
462
463        default:
464            return -1;   // metric is unknown
465    }
466}
467
468bool wxSystemSettingsNative::HasFeature(wxSystemFeature index)
469{
470    switch (index)
471    {
472        case wxSYS_CAN_ICONIZE_FRAME:
473            return false;
474
475        case wxSYS_CAN_DRAW_FRAME_DECORATIONS:
476            return true;
477
478        default:
479            return false;
480    }
481}
482