Avoid unrealizing a frozen window
[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 wxPoint pt = wxGetMousePosition();
143 wxRect rect(ClientToScreen(wxPoint(0, 0)), GetSize());
144 if (!onlyIfUnderMouse || rect.Contains(pt))
145 {
146 Hide();
147 Show();
148 }
149 }
150 #endif
151 }
152
153 // ----------------------------------------------------------------------------
154 // wxControl dealing with labels
155 // ----------------------------------------------------------------------------
156
157 void wxControl::GTKSetLabelForLabel(GtkLabel *w, const wxString& label)
158 {
159 const wxString labelGTK = GTKConvertMnemonics(label);
160 gtk_label_set_text_with_mnemonic(w, wxGTK_CONV(labelGTK));
161 }
162
163 #if wxUSE_MARKUP
164
165 void wxControl::GTKSetLabelWithMarkupForLabel(GtkLabel *w, const wxString& label)
166 {
167 const wxString labelGTK = GTKConvertMnemonicsWithMarkup(label);
168 gtk_label_set_markup_with_mnemonic(w, wxGTK_CONV(labelGTK));
169 }
170
171 #endif // wxUSE_MARKUP
172
173 // ----------------------------------------------------------------------------
174 // GtkFrame helpers
175 //
176 // GtkFrames do in fact support mnemonics in GTK2+ but not through
177 // gtk_frame_set_label, rather you need to use a custom label widget
178 // instead (idea gleaned from the native gtk font dialog code in GTK)
179 // ----------------------------------------------------------------------------
180
181 GtkWidget* wxControl::GTKCreateFrame(const wxString& label)
182 {
183 const wxString labelGTK = GTKConvertMnemonics(label);
184 GtkWidget* labelwidget = gtk_label_new_with_mnemonic(wxGTK_CONV(labelGTK));
185 gtk_widget_show(labelwidget); // without this it won't show...
186
187 GtkWidget* framewidget = gtk_frame_new(NULL);
188 gtk_frame_set_label_widget(GTK_FRAME(framewidget), labelwidget);
189
190 return framewidget; // note that the label is already set so you'll
191 // only need to call wxControl::SetLabel afterwards
192 }
193
194 void wxControl::GTKSetLabelForFrame(GtkFrame *w, const wxString& label)
195 {
196 wxControlBase::SetLabel(label);
197
198 GtkLabel* labelwidget = GTK_LABEL(gtk_frame_get_label_widget(w));
199 GTKSetLabelForLabel(labelwidget, label);
200 }
201
202 void wxControl::GTKFrameApplyWidgetStyle(GtkFrame* w, GtkRcStyle* style)
203 {
204 GTKApplyStyle(GTK_WIDGET(w), style);
205 GTKApplyStyle(gtk_frame_get_label_widget(w), style);
206 }
207
208 void wxControl::GTKFrameSetMnemonicWidget(GtkFrame* w, GtkWidget* widget)
209 {
210 GtkLabel* labelwidget = GTK_LABEL(gtk_frame_get_label_widget(w));
211
212 gtk_label_set_mnemonic_widget(labelwidget, widget);
213 }
214
215 // ----------------------------------------------------------------------------
216 // worker function implementing GTK*Mnemonics() functions
217 // ----------------------------------------------------------------------------
218
219 /* static */
220 wxString wxControl::GTKRemoveMnemonics(const wxString& label)
221 {
222 return wxGTKRemoveMnemonics(label);
223 }
224
225 /* static */
226 wxString wxControl::GTKConvertMnemonics(const wxString& label)
227 {
228 return wxConvertMnemonicsToGTK(label);
229 }
230
231 /* static */
232 wxString wxControl::GTKConvertMnemonicsWithMarkup(const wxString& label)
233 {
234 return wxConvertMnemonicsToGTKMarkup(label);
235 }
236
237 // ----------------------------------------------------------------------------
238 // wxControl styles (a.k.a. attributes)
239 // ----------------------------------------------------------------------------
240
241 wxVisualAttributes wxControl::GetDefaultAttributes() const
242 {
243 return GetDefaultAttributesFromGTKWidget(m_widget,
244 UseGTKStyleBase());
245 }
246
247 // static
248 wxVisualAttributes
249 wxControl::GetDefaultAttributesFromGTKWidget(GtkWidget* widget,
250 bool WXUNUSED_IN_GTK3(useBase),
251 int state)
252 {
253 wxVisualAttributes attr;
254 #ifdef __WXGTK3__
255 GtkStateFlags stateFlag = GTK_STATE_FLAG_NORMAL;
256 if (state)
257 {
258 wxASSERT(state == GTK_STATE_ACTIVE);
259 stateFlag = GTK_STATE_FLAG_ACTIVE;
260 }
261 GtkStyleContext* sc = gtk_widget_get_style_context(widget);
262 GdkRGBA c;
263 gtk_style_context_get_color(sc, stateFlag, &c);
264 attr.colFg = wxColour(c);
265 gtk_style_context_get_background_color(sc, stateFlag, &c);
266 attr.colBg = wxColour(c);
267 wxNativeFontInfo info;
268 info.description = const_cast<PangoFontDescription*>(gtk_style_context_get_font(sc, stateFlag));
269 attr.font = wxFont(info);
270 info.description = NULL;
271 #else
272 GtkStyle* style;
273
274 style = gtk_rc_get_style(widget);
275 if (!style)
276 style = gtk_widget_get_default_style();
277
278 if (!style)
279 {
280 return wxWindow::GetClassDefaultAttributes(wxWINDOW_VARIANT_NORMAL);
281 }
282
283 // get the style's colours
284 attr.colFg = wxColour(style->fg[state]);
285 if (useBase)
286 attr.colBg = wxColour(style->base[state]);
287 else
288 attr.colBg = wxColour(style->bg[state]);
289
290 // get the style's font
291 if ( !style->font_desc )
292 style = gtk_widget_get_default_style();
293 if ( style && style->font_desc )
294 {
295 wxNativeFontInfo info;
296 info.description = style->font_desc;
297 attr.font = wxFont(info);
298 info.description = NULL;
299 }
300 #endif
301 if (!attr.font.IsOk())
302 {
303 GtkSettings *settings = gtk_settings_get_default();
304 gchar *font_name = NULL;
305 g_object_get ( settings,
306 "gtk-font-name",
307 &font_name,
308 NULL);
309 if (!font_name)
310 attr.font = wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT );
311 else
312 attr.font = wxFont(wxString::FromAscii(font_name));
313 g_free (font_name);
314 }
315
316 return attr;
317 }
318
319
320 //static
321 wxVisualAttributes
322 wxControl::GetDefaultAttributesFromGTKWidget(wxGtkWidgetNew_t widget_new,
323 bool useBase,
324 int state)
325 {
326 wxVisualAttributes attr;
327 // NB: we need toplevel window so that GTK+ can find the right style
328 GtkWidget *wnd = gtk_window_new(GTK_WINDOW_TOPLEVEL);
329 GtkWidget* widget = widget_new();
330 gtk_container_add(GTK_CONTAINER(wnd), widget);
331 attr = GetDefaultAttributesFromGTKWidget(widget, useBase, state);
332 gtk_widget_destroy(wnd);
333 return attr;
334 }
335
336 //static
337 wxVisualAttributes
338 wxControl::GetDefaultAttributesFromGTKWidget(wxGtkWidgetNewFromStr_t widget_new,
339 bool useBase,
340 int state)
341 {
342 wxVisualAttributes attr;
343 // NB: we need toplevel window so that GTK+ can find the right style
344 GtkWidget *wnd = gtk_window_new(GTK_WINDOW_TOPLEVEL);
345 GtkWidget* widget = widget_new("");
346 gtk_container_add(GTK_CONTAINER(wnd), widget);
347 attr = GetDefaultAttributesFromGTKWidget(widget, useBase, state);
348 gtk_widget_destroy(wnd);
349 return attr;
350 }
351
352
353 //static
354 wxVisualAttributes
355 wxControl::GetDefaultAttributesFromGTKWidget(wxGtkWidgetNewFromAdj_t widget_new,
356 bool useBase,
357 int state)
358 {
359 wxVisualAttributes attr;
360 // NB: we need toplevel window so that GTK+ can find the right style
361 GtkWidget *wnd = gtk_window_new(GTK_WINDOW_TOPLEVEL);
362 GtkWidget* widget = widget_new(NULL);
363 gtk_container_add(GTK_CONTAINER(wnd), widget);
364 attr = GetDefaultAttributesFromGTKWidget(widget, useBase, state);
365 gtk_widget_destroy(wnd);
366 return attr;
367 }
368
369 #endif // wxUSE_CONTROLS