fix setting background color in wxGTK3 with themes which use background images or...
[wxWidgets.git] / src / gtk / control.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/control.cpp
3 // Purpose: wxControl implementation for wxGTK
4 // Author: Robert Roebling
5 // Id: $Id$
6 // Copyright: (c) 1998 Robert Roebling, Julian Smart and Vadim Zeitlin
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
12
13 #if wxUSE_CONTROLS
14
15 #include "wx/control.h"
16
17 #ifndef WX_PRECOMP
18 #include "wx/log.h"
19 #include "wx/settings.h"
20 #endif
21
22 #include "wx/fontutil.h"
23 #include "wx/utils.h"
24 #include "wx/sysopt.h"
25
26 #include <gtk/gtk.h>
27 #include "wx/gtk/private.h"
28 #include "wx/gtk/private/mnemonics.h"
29
30 // ============================================================================
31 // wxControl implementation
32 // ============================================================================
33
34 // ----------------------------------------------------------------------------
35 // wxControl creation
36 // ----------------------------------------------------------------------------
37
38 IMPLEMENT_DYNAMIC_CLASS(wxControl, wxWindow)
39
40 wxControl::wxControl()
41 {
42 }
43
44 bool wxControl::Create( wxWindow *parent,
45 wxWindowID id,
46 const wxPoint &pos,
47 const wxSize &size,
48 long style,
49 const wxValidator& validator,
50 const wxString &name )
51 {
52 bool ret = wxWindow::Create(parent, id, pos, size, style, name);
53
54 #if wxUSE_VALIDATORS
55 SetValidator(validator);
56 #endif
57
58 return ret;
59 }
60
61 #ifdef __WXGTK3__
62 bool wxControl::SetFont(const wxFont& font)
63 {
64 const bool changed = base_type::SetFont(font);
65 if (changed && !gtk_widget_get_realized(m_widget))
66 {
67 // GTK defers sending "style-updated" until widget is realized, but
68 // GetBestSize() won't compute correct result until the signal is sent,
69 // so we have to do it now
70 g_signal_emit_by_name(m_widget, "style-updated");
71 }
72 return changed;
73 }
74 #endif
75
76 wxSize wxControl::DoGetBestSize() const
77 {
78 // Do not return any arbitrary default value...
79 wxASSERT_MSG( m_widget, wxT("DoGetBestSize called before creation") );
80
81 wxSize best;
82 if (m_wxwindow)
83 {
84 // this is not a native control, size_request is likely to be (0,0)
85 best = wxControlBase::DoGetBestSize();
86 }
87 else
88 {
89 GtkRequisition req;
90 #ifdef __WXGTK3__
91 if (gtk_widget_get_request_mode(m_widget) != GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH)
92 {
93 gtk_widget_get_preferred_height(m_widget, NULL, &req.height);
94 gtk_widget_get_preferred_width_for_height(m_widget, req.height, NULL, &req.width);
95 }
96 else
97 {
98 gtk_widget_get_preferred_width(m_widget, NULL, &req.width);
99 gtk_widget_get_preferred_height_for_width(m_widget, req.width, NULL, &req.height);
100 }
101 #else
102 GTK_WIDGET_GET_CLASS(m_widget)->size_request(m_widget, &req);
103 #endif
104 best.Set(req.width, req.height);
105 }
106 CacheBestSize(best);
107 return best;
108 }
109
110 void wxControl::PostCreation(const wxSize& size)
111 {
112 wxWindow::PostCreation();
113
114 #ifndef __WXGTK3__
115 // NB: GetBestSize needs to know the style, otherwise it will assume
116 // default font and if the user uses a different font, determined
117 // best size will be different (typically, smaller) than the desired
118 // size. This call ensure that a style is available at the time
119 // GetBestSize is called.
120 gtk_widget_ensure_style(m_widget);
121 #endif
122
123 GTKApplyWidgetStyle();
124 SetInitialSize(size);
125 }
126
127 // ----------------------------------------------------------------------------
128 // Work around a GTK+ bug whereby button is insensitive after being
129 // enabled
130 // ----------------------------------------------------------------------------
131
132 // Fix sensitivity due to bug in GTK+ < 2.14
133 void wxControl::GTKFixSensitivity(bool WXUNUSED_IN_GTK3(onlyIfUnderMouse))
134 {
135 #ifndef __WXGTK3__
136 if (gtk_check_version(2,14,0)
137 #if wxUSE_SYSTEM_OPTIONS
138 && (wxSystemOptions::GetOptionInt(wxT("gtk.control.disable-sensitivity-fix")) != 1)
139 #endif
140 )
141 {
142 if (!onlyIfUnderMouse || GetScreenRect().Contains(wxGetMousePosition()))
143 {
144 Hide();
145 Show();
146 }
147 }
148 #endif
149 }
150
151 // ----------------------------------------------------------------------------
152 // wxControl dealing with labels
153 // ----------------------------------------------------------------------------
154
155 void wxControl::GTKSetLabelForLabel(GtkLabel *w, const wxString& label)
156 {
157 const wxString labelGTK = GTKConvertMnemonics(label);
158 gtk_label_set_text_with_mnemonic(w, wxGTK_CONV(labelGTK));
159 }
160
161 #if wxUSE_MARKUP
162
163 void wxControl::GTKSetLabelWithMarkupForLabel(GtkLabel *w, const wxString& label)
164 {
165 const wxString labelGTK = GTKConvertMnemonicsWithMarkup(label);
166 gtk_label_set_markup_with_mnemonic(w, wxGTK_CONV(labelGTK));
167 }
168
169 #endif // wxUSE_MARKUP
170
171 // ----------------------------------------------------------------------------
172 // GtkFrame helpers
173 //
174 // GtkFrames do in fact support mnemonics in GTK2+ but not through
175 // gtk_frame_set_label, rather you need to use a custom label widget
176 // instead (idea gleaned from the native gtk font dialog code in GTK)
177 // ----------------------------------------------------------------------------
178
179 GtkWidget* wxControl::GTKCreateFrame(const wxString& label)
180 {
181 const wxString labelGTK = GTKConvertMnemonics(label);
182 GtkWidget* labelwidget = gtk_label_new_with_mnemonic(wxGTK_CONV(labelGTK));
183 gtk_widget_show(labelwidget); // without this it won't show...
184
185 GtkWidget* framewidget = gtk_frame_new(NULL);
186 gtk_frame_set_label_widget(GTK_FRAME(framewidget), labelwidget);
187
188 return framewidget; // note that the label is already set so you'll
189 // only need to call wxControl::SetLabel afterwards
190 }
191
192 void wxControl::GTKSetLabelForFrame(GtkFrame *w, const wxString& label)
193 {
194 wxControlBase::SetLabel(label);
195
196 GtkLabel* labelwidget = GTK_LABEL(gtk_frame_get_label_widget(w));
197 GTKSetLabelForLabel(labelwidget, label);
198 }
199
200 void wxControl::GTKFrameApplyWidgetStyle(GtkFrame* w, GtkRcStyle* style)
201 {
202 GTKApplyStyle(GTK_WIDGET(w), style);
203 GTKApplyStyle(gtk_frame_get_label_widget(w), style);
204 }
205
206 void wxControl::GTKFrameSetMnemonicWidget(GtkFrame* w, GtkWidget* widget)
207 {
208 GtkLabel* labelwidget = GTK_LABEL(gtk_frame_get_label_widget(w));
209
210 gtk_label_set_mnemonic_widget(labelwidget, widget);
211 }
212
213 // ----------------------------------------------------------------------------
214 // worker function implementing GTK*Mnemonics() functions
215 // ----------------------------------------------------------------------------
216
217 /* static */
218 wxString wxControl::GTKRemoveMnemonics(const wxString& label)
219 {
220 return wxGTKRemoveMnemonics(label);
221 }
222
223 /* static */
224 wxString wxControl::GTKConvertMnemonics(const wxString& label)
225 {
226 return wxConvertMnemonicsToGTK(label);
227 }
228
229 /* static */
230 wxString wxControl::GTKConvertMnemonicsWithMarkup(const wxString& label)
231 {
232 return wxConvertMnemonicsToGTKMarkup(label);
233 }
234
235 // ----------------------------------------------------------------------------
236 // wxControl styles (a.k.a. attributes)
237 // ----------------------------------------------------------------------------
238
239 wxVisualAttributes wxControl::GetDefaultAttributes() const
240 {
241 return GetDefaultAttributesFromGTKWidget(m_widget,
242 UseGTKStyleBase());
243 }
244
245 // static
246 wxVisualAttributes
247 wxControl::GetDefaultAttributesFromGTKWidget(GtkWidget* widget,
248 bool WXUNUSED_IN_GTK3(useBase),
249 int state)
250 {
251 wxVisualAttributes attr;
252 #ifdef __WXGTK3__
253 GtkStateFlags stateFlag = GTK_STATE_FLAG_NORMAL;
254 if (state)
255 {
256 wxASSERT(state == GTK_STATE_ACTIVE);
257 stateFlag = GTK_STATE_FLAG_ACTIVE;
258 }
259 GtkStyleContext* sc = gtk_widget_get_style_context(widget);
260 GdkRGBA c;
261 gtk_style_context_get_color(sc, stateFlag, &c);
262 attr.colFg = wxColour(c);
263 gtk_style_context_get_background_color(sc, stateFlag, &c);
264 attr.colBg = wxColour(c);
265 wxNativeFontInfo info;
266 info.description = const_cast<PangoFontDescription*>(gtk_style_context_get_font(sc, stateFlag));
267 attr.font = wxFont(info);
268 info.description = NULL;
269 #else
270 GtkStyle* style;
271
272 style = gtk_rc_get_style(widget);
273 if (!style)
274 style = gtk_widget_get_default_style();
275
276 if (!style)
277 {
278 return wxWindow::GetClassDefaultAttributes(wxWINDOW_VARIANT_NORMAL);
279 }
280
281 // get the style's colours
282 attr.colFg = wxColour(style->fg[state]);
283 if (useBase)
284 attr.colBg = wxColour(style->base[state]);
285 else
286 attr.colBg = wxColour(style->bg[state]);
287
288 // get the style's font
289 if ( !style->font_desc )
290 style = gtk_widget_get_default_style();
291 if ( style && style->font_desc )
292 {
293 wxNativeFontInfo info;
294 info.description = style->font_desc;
295 attr.font = wxFont(info);
296 info.description = NULL;
297 }
298 #endif
299 if (!attr.font.IsOk())
300 {
301 GtkSettings *settings = gtk_settings_get_default();
302 gchar *font_name = NULL;
303 g_object_get ( settings,
304 "gtk-font-name",
305 &font_name,
306 NULL);
307 if (!font_name)
308 attr.font = wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT );
309 else
310 attr.font = wxFont(wxString::FromAscii(font_name));
311 g_free (font_name);
312 }
313
314 return attr;
315 }
316
317
318 //static
319 wxVisualAttributes
320 wxControl::GetDefaultAttributesFromGTKWidget(wxGtkWidgetNew_t widget_new,
321 bool useBase,
322 int state)
323 {
324 wxVisualAttributes attr;
325 // NB: we need toplevel window so that GTK+ can find the right style
326 GtkWidget *wnd = gtk_window_new(GTK_WINDOW_TOPLEVEL);
327 GtkWidget* widget = widget_new();
328 gtk_container_add(GTK_CONTAINER(wnd), widget);
329 attr = GetDefaultAttributesFromGTKWidget(widget, useBase, state);
330 gtk_widget_destroy(wnd);
331 return attr;
332 }
333
334 //static
335 wxVisualAttributes
336 wxControl::GetDefaultAttributesFromGTKWidget(wxGtkWidgetNewFromStr_t widget_new,
337 bool useBase,
338 int state)
339 {
340 wxVisualAttributes attr;
341 // NB: we need toplevel window so that GTK+ can find the right style
342 GtkWidget *wnd = gtk_window_new(GTK_WINDOW_TOPLEVEL);
343 GtkWidget* widget = widget_new("");
344 gtk_container_add(GTK_CONTAINER(wnd), widget);
345 attr = GetDefaultAttributesFromGTKWidget(widget, useBase, state);
346 gtk_widget_destroy(wnd);
347 return attr;
348 }
349
350
351 //static
352 wxVisualAttributes
353 wxControl::GetDefaultAttributesFromGTKWidget(wxGtkWidgetNewFromAdj_t widget_new,
354 bool useBase,
355 int state)
356 {
357 wxVisualAttributes attr;
358 // NB: we need toplevel window so that GTK+ can find the right style
359 GtkWidget *wnd = gtk_window_new(GTK_WINDOW_TOPLEVEL);
360 GtkWidget* widget = widget_new(NULL);
361 gtk_container_add(GTK_CONTAINER(wnd), widget);
362 attr = GetDefaultAttributesFromGTKWidget(widget, useBase, state);
363 gtk_widget_destroy(wnd);
364 return attr;
365 }
366
367 #endif // wxUSE_CONTROLS