1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/gtk/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 <gtk/gtkversion.h>
24 #if GTK_CHECK_VERSION(2, 9, 0)
25     // gtk_object_sink
26     #undef GTK_DISABLE_DEPRECATED
27 #endif
28 #include <gtk/gtk.h>
29 #include <gdk/gdkx.h>
30 
31 #include <X11/Xatom.h>
32 
33 // ----------------------------------------------------------------------------
34 // wxSystemObjects
35 // ----------------------------------------------------------------------------
36 
37 struct wxSystemObjects
38 {
39     wxColour m_colBtnFace,
40              m_colBtnShadow,
41              m_colBtnHighlight,
42              m_colHighlight,
43              m_colHighlightText,
44              m_colListBox,
45              m_colWindow,
46              m_colBtnText,
47              m_colMenuItemHighlight,
48              m_colTooltip,
49              m_colTooltipText,
50              m_colMenubarBg,
51              m_colListBoxText,
52              m_colListBoxUnfocusedText;
53 
54     wxFont m_fontSystem;
55 };
56 
57 static wxSystemObjects gs_objects;
58 
wxClearGtkSystemObjects()59 void wxClearGtkSystemObjects()
60 {
61     gs_objects.m_colBtnFace = wxColour();
62     gs_objects.m_colBtnShadow = wxColour();
63     gs_objects.m_colBtnHighlight = wxColour();
64     gs_objects.m_colHighlightText = wxColour();
65     gs_objects.m_colListBox = wxColour();
66     gs_objects.m_colWindow = wxColour();
67     gs_objects.m_colBtnText = wxColour();
68     gs_objects.m_colMenuItemHighlight = wxColour();
69     gs_objects.m_colTooltip = wxColour();
70     gs_objects.m_colTooltipText = wxColour();
71     gs_objects.m_colMenubarBg = wxColour();
72     gs_objects.m_fontSystem = wxNullFont;
73     gs_objects.m_colListBoxText = wxColour();
74 }
75 
76 // ----------------------------------------------------------------------------
77 // wxSystemSettings implementation
78 // ----------------------------------------------------------------------------
79 
80 // kind of widget to use in GetColourFromGTKWidget
81 enum wxGtkWidgetType
82 {
83     wxGTK_BUTTON,
84     wxGTK_LIST,
85     wxGTK_MENUITEM,
86     wxGTK_TEXTCTRL,
87     wxGTK_MENUBAR,
88 };
89 
90 // the colour we need
91 enum wxGtkColourType
92 {
93     wxGTK_FG,
94     wxGTK_BG,
95     wxGTK_BASE,
96     wxGTK_TEXT
97 };
98 
99 // wxSystemSettings::GetColour() helper: get the colours from a GTK+
100 // widget style, return true if we did get them
GetColourFromGTKWidget(GdkColor & gdkColor,wxGtkWidgetType type=wxGTK_BUTTON,GtkStateType state=GTK_STATE_NORMAL,wxGtkColourType colour=wxGTK_BG)101 static bool GetColourFromGTKWidget(GdkColor& gdkColor,
102                                    wxGtkWidgetType type = wxGTK_BUTTON,
103                                    GtkStateType state = GTK_STATE_NORMAL,
104                                    wxGtkColourType colour = wxGTK_BG)
105 {
106     GtkWidget *widget;
107     switch ( type )
108     {
109         default:
110             wxFAIL_MSG( _T("unexpected GTK widget type") );
111             // fall through
112 
113         case wxGTK_BUTTON:
114             widget = gtk_button_new();
115             break;
116 
117         case wxGTK_TEXTCTRL:
118             widget = gtk_text_view_new();
119             break;
120 
121         case wxGTK_LIST:
122             widget = gtk_tree_view_new_with_model(
123                 (GtkTreeModel*)gtk_list_store_new(1, G_TYPE_INT));
124             break;
125 
126         case wxGTK_MENUITEM:
127             widget = gtk_menu_item_new();
128             break;
129 
130         case wxGTK_MENUBAR:
131             widget = gtk_menu_bar_new();
132             break;
133     }
134 
135     GtkStyle *def = gtk_rc_get_style( widget );
136     if ( !def )
137         def = gtk_widget_get_default_style();
138 
139     const bool ok = def != NULL;
140     if (ok)
141     {
142         switch ( colour )
143         {
144             default:
145                 wxFAIL_MSG( _T("unexpected GTK colour type") );
146                 // fall through
147 
148             case wxGTK_FG:
149                 gdkColor = def->fg[state];
150                 break;
151 
152             case wxGTK_BG:
153                 gdkColor = def->bg[state];
154                 break;
155 
156             case wxGTK_BASE:
157                 gdkColor = def->base[state];
158                 break;
159 
160             case wxGTK_TEXT:
161                 gdkColor = def->text[state];
162                 break;
163         }
164     }
165 
166     gtk_object_sink((GtkObject*)widget);
167 
168     return ok;
169 }
170 
GetTooltipColors()171 static void GetTooltipColors()
172 {
173     GtkWidget* widget = gtk_window_new(GTK_WINDOW_POPUP);
174     const char* name = "gtk-tooltip";
175     if (gtk_check_version(2, 11, 0))
176         name = "gtk-tooltips";
177     gtk_widget_set_name(widget, name);
178     gtk_widget_ensure_style(widget);
179 
180     GdkColor c = widget->style->bg[GTK_STATE_NORMAL];
181     gs_objects.m_colTooltip = wxColor(c);
182     c = widget->style->fg[GTK_STATE_NORMAL];
183     gs_objects.m_colTooltipText = wxColor(c);
184 
185     gtk_widget_destroy(widget);
186 }
187 
GetColour(wxSystemColour index)188 wxColour wxSystemSettingsNative::GetColour( wxSystemColour index )
189 {
190     wxColor color;
191     GdkColor gdkColor;
192     switch (index)
193     {
194         case wxSYS_COLOUR_SCROLLBAR:
195         case wxSYS_COLOUR_BACKGROUND:
196         case wxSYS_COLOUR_INACTIVECAPTION:
197         case wxSYS_COLOUR_MENU:
198         case wxSYS_COLOUR_WINDOWFRAME:
199         case wxSYS_COLOUR_ACTIVEBORDER:
200         case wxSYS_COLOUR_INACTIVEBORDER:
201         case wxSYS_COLOUR_BTNFACE:
202         case wxSYS_COLOUR_3DLIGHT:
203             if (!gs_objects.m_colBtnFace.Ok())
204             {
205                 gdkColor.red =
206                 gdkColor.green = 0;
207                 gdkColor.blue = 0x9c40;
208                 GetColourFromGTKWidget(gdkColor);
209                 gs_objects.m_colBtnFace = wxColor(gdkColor);
210             }
211             color = gs_objects.m_colBtnFace;
212             break;
213 
214         case wxSYS_COLOUR_WINDOW:
215             if (!gs_objects.m_colWindow.Ok())
216             {
217                 gdkColor.red =
218                 gdkColor.green =
219                 gdkColor.blue = 0xFFFF;
220                 GetColourFromGTKWidget(gdkColor, wxGTK_TEXTCTRL, GTK_STATE_NORMAL, wxGTK_BASE);
221                 gs_objects.m_colWindow = wxColor(gdkColor);
222             }
223             color = gs_objects.m_colWindow;
224             break;
225 
226 
227         case wxSYS_COLOUR_MENUBAR:
228             if (!gs_objects.m_colMenubarBg.Ok())
229             {
230                 gdkColor.red =
231                 gdkColor.green = 0;
232                 gdkColor.blue = 0x9c40;
233                 GetColourFromGTKWidget(gdkColor,wxGTK_MENUBAR);
234                 gs_objects.m_colMenubarBg = wxColor(gdkColor);
235             }
236             color = gs_objects.m_colMenubarBg;
237             break;
238 
239         case wxSYS_COLOUR_3DDKSHADOW:
240             color = *wxBLACK;
241             break;
242 
243         case wxSYS_COLOUR_GRAYTEXT:
244         case wxSYS_COLOUR_BTNSHADOW:
245         //case wxSYS_COLOUR_3DSHADOW:
246             if (!gs_objects.m_colBtnShadow.Ok())
247             {
248                 wxColour faceColour(GetColour(wxSYS_COLOUR_3DFACE));
249                 gs_objects.m_colBtnShadow =
250                    wxColour((unsigned char) (faceColour.Red() * 2 / 3),
251                             (unsigned char) (faceColour.Green() * 2 / 3),
252                             (unsigned char) (faceColour.Blue() * 2 / 3));
253             }
254             color = gs_objects.m_colBtnShadow;
255             break;
256 
257         case wxSYS_COLOUR_3DHIGHLIGHT:
258         //case wxSYS_COLOUR_BTNHIGHLIGHT:
259             color = *wxWHITE;
260             break;
261 
262         case wxSYS_COLOUR_HIGHLIGHT:
263             if (!gs_objects.m_colHighlight.Ok())
264             {
265                 gdkColor.red =
266                 gdkColor.green = 0;
267                 gdkColor.blue = 0x9c40;
268                 GetColourFromGTKWidget(
269                     gdkColor, wxGTK_BUTTON, GTK_STATE_SELECTED);
270                 gs_objects.m_colHighlight = wxColour(gdkColor);
271             }
272             color = gs_objects.m_colHighlight;
273             break;
274 
275         case wxSYS_COLOUR_LISTBOX:
276             if (!gs_objects.m_colListBox.Ok())
277             {
278                 if ( GetColourFromGTKWidget(gdkColor,
279                                             wxGTK_LIST,
280                                             GTK_STATE_NORMAL,
281                                             wxGTK_BASE) )
282                 {
283                     gs_objects.m_colListBox = wxColour(gdkColor);
284                 }
285                 else
286                 {
287                     gs_objects.m_colListBox = *wxWHITE;
288                 }
289             }
290             color = gs_objects.m_colListBox;
291             break;
292 
293         case wxSYS_COLOUR_LISTBOXTEXT:
294             if (!gs_objects.m_colListBoxText.Ok())
295             {
296                 if ( GetColourFromGTKWidget(gdkColor,
297                                             wxGTK_LIST,
298                                             GTK_STATE_NORMAL,
299                                             wxGTK_TEXT) )
300                 {
301                     gs_objects.m_colListBoxText = wxColour(gdkColor);
302                 }
303                 else
304                 {
305                     gs_objects.m_colListBoxText = GetColour(wxSYS_COLOUR_WINDOWTEXT);
306                 }
307             }
308             color = gs_objects.m_colListBoxText;
309             break;
310 
311         case wxSYS_COLOUR_LISTBOXHIGHLIGHTTEXT:
312         {
313             // This is for the text in a list control (or tree) when the
314             // item is selected, but not focused
315             if (!gs_objects.m_colListBoxUnfocusedText.Ok())
316             {
317                 if (GetColourFromGTKWidget(gdkColor, wxGTK_LIST, GTK_STATE_ACTIVE, wxGTK_TEXT))
318                     gs_objects.m_colListBoxUnfocusedText = wxColour(gdkColor);
319                 else
320                     gs_objects.m_colListBoxUnfocusedText = GetColour(wxSYS_COLOUR_WINDOWTEXT);
321             }
322             color = gs_objects.m_colListBoxUnfocusedText;
323             break;
324         }
325         case wxSYS_COLOUR_MENUTEXT:
326         case wxSYS_COLOUR_WINDOWTEXT:
327         case wxSYS_COLOUR_CAPTIONTEXT:
328         case wxSYS_COLOUR_INACTIVECAPTIONTEXT:
329         case wxSYS_COLOUR_BTNTEXT:
330             if (!gs_objects.m_colBtnText.Ok())
331             {
332                 gdkColor.red =
333                 gdkColor.green =
334                 gdkColor.blue = 0;
335                 GetColourFromGTKWidget(
336                     gdkColor, wxGTK_BUTTON, GTK_STATE_NORMAL, wxGTK_FG);
337                 gs_objects.m_colBtnText = wxColour(gdkColor);
338             }
339             color = gs_objects.m_colBtnText;
340             break;
341 
342         case wxSYS_COLOUR_INFOBK:
343             if (!gs_objects.m_colTooltip.Ok()) {
344                 GetTooltipColors();
345             }
346             color = gs_objects.m_colTooltip;
347             break;
348 
349         case wxSYS_COLOUR_INFOTEXT:
350             if (!gs_objects.m_colTooltipText.Ok()) {
351                 GetTooltipColors();
352             }
353             color = gs_objects.m_colTooltipText;
354             break;
355 
356         case wxSYS_COLOUR_HIGHLIGHTTEXT:
357             if (!gs_objects.m_colHighlightText.Ok())
358             {
359                 gdkColor.red =
360                 gdkColor.green =
361                 gdkColor.blue = 0;
362                 GetColourFromGTKWidget(
363                     gdkColor, wxGTK_BUTTON, GTK_STATE_SELECTED, wxGTK_FG);
364                 gs_objects.m_colHighlightText = wxColour(gdkColor);
365             }
366             color = gs_objects.m_colHighlightText;
367             break;
368 
369         case wxSYS_COLOUR_APPWORKSPACE:
370             color = *wxWHITE;    // ?
371             break;
372 
373         case wxSYS_COLOUR_ACTIVECAPTION:
374         case wxSYS_COLOUR_MENUHILIGHT:
375             if (!gs_objects.m_colMenuItemHighlight.Ok())
376             {
377                 gdkColor.red =
378                 gdkColor.green =
379                 gdkColor.blue = 0;
380                 GetColourFromGTKWidget(
381                     gdkColor, wxGTK_MENUITEM, GTK_STATE_SELECTED, wxGTK_BG);
382                 gs_objects.m_colMenuItemHighlight = wxColour(gdkColor);
383             }
384             color = gs_objects.m_colMenuItemHighlight;
385             break;
386 
387         case wxSYS_COLOUR_HOTLIGHT:
388         case wxSYS_COLOUR_GRADIENTACTIVECAPTION:
389         case wxSYS_COLOUR_GRADIENTINACTIVECAPTION:
390             // TODO
391             color = *wxBLACK;
392             break;
393 
394         case wxSYS_COLOUR_MAX:
395         default:
396             wxFAIL_MSG( _T("unknown system colour index") );
397             color = *wxWHITE;
398             break;
399     }
400 
401     return color;
402 }
403 
GetFont(wxSystemFont index)404 wxFont wxSystemSettingsNative::GetFont( wxSystemFont index )
405 {
406     wxFont font;
407     switch (index)
408     {
409         case wxSYS_OEM_FIXED_FONT:
410         case wxSYS_ANSI_FIXED_FONT:
411         case wxSYS_SYSTEM_FIXED_FONT:
412             font = *wxNORMAL_FONT;
413             break;
414 
415         case wxSYS_ANSI_VAR_FONT:
416         case wxSYS_SYSTEM_FONT:
417         case wxSYS_DEVICE_DEFAULT_FONT:
418         case wxSYS_DEFAULT_GUI_FONT:
419             if (!gs_objects.m_fontSystem.Ok())
420             {
421                 GtkWidget *widget = gtk_button_new();
422                 GtkStyle *def = gtk_rc_get_style( widget );
423                 if ( !def || !def->font_desc )
424                     def = gtk_widget_get_default_style();
425                 if ( def && def->font_desc )
426                 {
427                     wxNativeFontInfo info;
428                     info.description =
429                         pango_font_description_copy(def->font_desc);
430                     gs_objects.m_fontSystem = wxFont(info);
431                 }
432                 else
433                 {
434                     GtkSettings *settings = gtk_settings_get_default();
435                     gchar *font_name = NULL;
436                     g_object_get ( settings,
437                                    "gtk-font-name",
438                                    &font_name,
439                                    NULL);
440                     if (!font_name)
441                         gs_objects.m_fontSystem = wxFont( 12, wxSWISS, wxNORMAL, wxNORMAL );
442                     else
443                         gs_objects.m_fontSystem = wxFont(wxString::FromAscii(font_name));
444                     g_free (font_name);
445                 }
446                 gtk_object_sink((GtkObject*)widget);
447             }
448             font = gs_objects.m_fontSystem;
449             break;
450 
451         default:
452             break;
453     }
454     return font;
455 }
456 
wxXGetWindowProperty(GdkWindow * window,Atom & type,int & format,gulong & nitems,guchar * & data)457 static bool wxXGetWindowProperty(GdkWindow* window, Atom& type, int& format, gulong& nitems, guchar*& data)
458 {
459     bool success = false;
460 #if GTK_CHECK_VERSION(2, 2, 0)
461     if (gtk_check_version(2, 2, 0) == NULL)
462     {
463         gulong bytes_after;
464         success = XGetWindowProperty(
465             GDK_DISPLAY_XDISPLAY(gdk_drawable_get_display(window)),
466             GDK_WINDOW_XWINDOW(window),
467             gdk_x11_get_xatom_by_name_for_display(
468                 gdk_drawable_get_display(window),
469                 "_NET_FRAME_EXTENTS"),
470             0, // left, right, top, bottom, CARDINAL[4]/32
471             G_MAXLONG, // size of long
472             false, // do not delete property
473             XA_CARDINAL, // 32 bit
474             &type, &format, &nitems, &bytes_after, &data
475             ) == Success;
476     }
477 #endif
478     return success;
479 }
480 
GetMetric(wxSystemMetric index,wxWindow * win)481 int wxSystemSettingsNative::GetMetric( wxSystemMetric index, wxWindow* win )
482 {
483     guchar *data = NULL;
484     Atom type;
485     int format;
486     gulong nitems;
487     GdkWindow *window = NULL;
488     if(win && GTK_WIDGET_REALIZED(win->GetHandle()))
489         window = win->GetHandle()->window;
490 
491     switch (index)
492     {
493         case wxSYS_BORDER_X:
494         case wxSYS_BORDER_Y:
495         case wxSYS_EDGE_X:
496         case wxSYS_EDGE_Y:
497         case wxSYS_FRAMESIZE_X:
498         case wxSYS_FRAMESIZE_Y:
499             // If a window is specified/realized, and it is a toplevel window, we can query from wm.
500             // The returned border thickness is outside the client area in that case.
501             if (window)
502             {
503                 wxTopLevelWindow *tlw = wxDynamicCast(win, wxTopLevelWindow);
504                 if (!tlw)
505                     return -1; // not a tlw, not sure how to approach
506                 else
507                 {
508                     // Check if wm supports frame extents - we can't know
509                     // the border widths if it does not.
510 #if GTK_CHECK_VERSION(2,2,0)
511                     if (!gtk_check_version(2,2,0))
512                     {
513                         if (!gdk_x11_screen_supports_net_wm_hint(
514                                 gdk_drawable_get_screen(window),
515                                 gdk_atom_intern("_NET_FRAME_EXTENTS", false) ) )
516                             return -1;
517                     }
518                     else
519 #endif
520                     {
521                         if (!gdk_net_wm_supports(gdk_atom_intern("_NET_FRAME_EXTENTS", false)))
522                             return -1;
523                     }
524 
525                     // Get the frame extents from the windowmanager.
526                     // In most cases the top extent is the titlebar, so we use the bottom extent
527                     // for the heights.
528                     if (wxXGetWindowProperty(window, type, format, nitems, data))
529                     {
530                         int border_return = -1;
531 
532                         if ((type == XA_CARDINAL) && (format == 32) && (nitems >= 4) && (data))
533                         {
534                             switch(index)
535                             {
536                                 case wxSYS_BORDER_X:
537                                 case wxSYS_EDGE_X:
538                                 case wxSYS_FRAMESIZE_X:
539                                     border_return = ((long*)data)[1]; // width of right extent
540                                     break;
541                                 default:
542                                     border_return = ((long*)data)[3]; // height of bottom extent
543                                     break;
544                             }
545                         }
546 
547                         if (data)
548                             XFree(data);
549 
550                         return border_return;
551                     }
552                 }
553             }
554 
555             return -1; // no window specified
556 
557         case wxSYS_CURSOR_X:
558         case wxSYS_CURSOR_Y:
559 #ifdef __WXGTK24__
560             if (!gtk_check_version(2,4,0))
561             {
562                 if (window)
563                     return gdk_display_get_default_cursor_size(gdk_drawable_get_display(window));
564                 else
565                     return gdk_display_get_default_cursor_size(gdk_display_get_default());
566             }
567             else
568 #endif
569                 return 16;
570 
571         case wxSYS_DCLICK_X:
572         case wxSYS_DCLICK_Y:
573             gint dclick_distance;
574 #if GTK_CHECK_VERSION(2,2,0)
575             if (window && !gtk_check_version(2,2,0))
576                 g_object_get(gtk_settings_get_for_screen(gdk_drawable_get_screen(window)),
577                                 "gtk-double-click-distance", &dclick_distance, NULL);
578             else
579 #endif
580                 g_object_get(gtk_settings_get_default(),
581                                 "gtk-double-click-distance", &dclick_distance, NULL);
582 
583             return dclick_distance * 2;
584 
585         case wxSYS_DRAG_X:
586         case wxSYS_DRAG_Y:
587             gint drag_threshold;
588 #if GTK_CHECK_VERSION(2,2,0)
589             if (window && !gtk_check_version(2,2,0))
590             {
591                 g_object_get(
592                         gtk_settings_get_for_screen(gdk_drawable_get_screen(window)),
593                         "gtk-dnd-drag-threshold",
594                         &drag_threshold, NULL);
595             }
596             else
597 #endif
598             {
599                 g_object_get(gtk_settings_get_default(),
600                              "gtk-dnd-drag-threshold", &drag_threshold, NULL);
601             }
602 
603             // The correct thing here would be to double the value
604             // since that is what the API wants. But the values
605             // are much bigger under GNOME than under Windows and
606             // just seem to much in many cases to be useful.
607             // drag_threshold *= 2;
608 
609             return drag_threshold;
610 
611         // MBN: ditto for icons
612         case wxSYS_ICON_X:     return 32;
613         case wxSYS_ICON_Y:     return 32;
614 
615         case wxSYS_SCREEN_X:
616 #if GTK_CHECK_VERSION(2,2,0)
617             if (window && !gtk_check_version(2,2,0))
618                 return gdk_screen_get_width(gdk_drawable_get_screen(window));
619             else
620 #endif
621                 return gdk_screen_width();
622 
623         case wxSYS_SCREEN_Y:
624 #if GTK_CHECK_VERSION(2,2,0)
625             if (window && !gtk_check_version(2,2,0))
626                 return gdk_screen_get_height(gdk_drawable_get_screen(window));
627             else
628 #endif
629                 return gdk_screen_height();
630 
631         case wxSYS_HSCROLL_Y:  return 15;
632         case wxSYS_VSCROLL_X:  return 15;
633 
634         case wxSYS_CAPTION_Y:
635             if (!window)
636                 // No realized window specified, and no implementation for that case yet.
637                 return -1;
638 
639             // Check if wm supports frame extents - we can't know the caption height if it does not.
640 #if GTK_CHECK_VERSION(2,2,0)
641             if (!gtk_check_version(2,2,0))
642             {
643                 if (!gdk_x11_screen_supports_net_wm_hint(
644                         gdk_drawable_get_screen(window),
645                         gdk_atom_intern("_NET_FRAME_EXTENTS", false) ) )
646                     return -1;
647             }
648             else
649 #endif
650             {
651                 if (!gdk_net_wm_supports(gdk_atom_intern("_NET_FRAME_EXTENTS", false)))
652                     return -1;
653             }
654 
655             wxASSERT_MSG( wxDynamicCast(win, wxTopLevelWindow),
656                           wxT("Asking for caption height of a non toplevel window") );
657 
658             // Get the height of the top windowmanager border.
659             // This is the titlebar in most cases. The titlebar might be elsewhere, and
660             // we could check which is the thickest wm border to decide on which side the
661             // titlebar is, but this might lead to interesting behaviours in used code.
662             // Reconsider when we have a way to report to the user on which side it is.
663             if (wxXGetWindowProperty(window, type, format, nitems, data))
664             {
665                 int caption_height = -1;
666 
667                 if ((type == XA_CARDINAL) && (format == 32) && (nitems >= 3) && (data))
668                 {
669                     caption_height = ((long*)data)[2]; // top frame extent
670                 }
671 
672                 if (data)
673                     XFree(data);
674 
675                 return caption_height;
676             }
677 
678             // Try a default approach without a window pointer, if possible
679             // ...
680 
681             return -1;
682 
683         case wxSYS_PENWINDOWS_PRESENT:
684             // No MS Windows for Pen computing extension available in X11 based gtk+.
685             return 0;
686 
687         default:
688             return -1;   // metric is unknown
689     }
690 }
691 
HasFeature(wxSystemFeature index)692 bool wxSystemSettingsNative::HasFeature(wxSystemFeature index)
693 {
694     switch (index)
695     {
696         case wxSYS_CAN_ICONIZE_FRAME:
697             return false;
698 
699         case wxSYS_CAN_DRAW_FRAME_DECORATIONS:
700             return true;
701 
702         default:
703             return false;
704     }
705 }
706