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