Move GDK_META_MASK definition in the header in which it is also used.
[wxWidgets.git] / src / gtk / renderer.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/renderer.cpp
3 // Purpose: implementation of wxRendererNative for wxGTK
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 20.07.2003
7 // RCS-ID: $Id$
8 // Copyright: (c) 2003 Vadim Zeitlin <vadim@wxwindows.org>
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 // for compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #ifdef __BORLANDC__
24 #pragma hdrstop
25 #endif
26
27 #include "wx/renderer.h"
28
29 #ifndef WX_PRECOMP
30 #include "wx/window.h"
31 #include "wx/dcclient.h"
32 #include "wx/settings.h"
33 #include "wx/module.h"
34 #endif
35
36 #include "wx/dcgraph.h"
37 #include "wx/gtk/dc.h"
38 #include "wx/gtk/private.h"
39
40 #include <gtk/gtk.h>
41
42 // ----------------------------------------------------------------------------
43 // wxRendererGTK: our wxRendererNative implementation
44 // ----------------------------------------------------------------------------
45
46 class WXDLLEXPORT wxRendererGTK : public wxDelegateRendererNative
47 {
48 public:
49 // draw the header control button (used by wxListCtrl)
50 virtual int DrawHeaderButton(wxWindow *win,
51 wxDC& dc,
52 const wxRect& rect,
53 int flags = 0,
54 wxHeaderSortIconType sortArrow = wxHDR_SORT_ICON_NONE,
55 wxHeaderButtonParams* params = NULL);
56
57 virtual int GetHeaderButtonHeight(wxWindow *win);
58
59 virtual int GetHeaderButtonMargin(wxWindow *win);
60
61
62 // draw the expanded/collapsed icon for a tree control item
63 virtual void DrawTreeItemButton(wxWindow *win,
64 wxDC& dc,
65 const wxRect& rect,
66 int flags = 0);
67
68 virtual void DrawSplitterBorder(wxWindow *win,
69 wxDC& dc,
70 const wxRect& rect,
71 int flags = 0);
72 virtual void DrawSplitterSash(wxWindow *win,
73 wxDC& dc,
74 const wxSize& size,
75 wxCoord position,
76 wxOrientation orient,
77 int flags = 0);
78
79 virtual void DrawComboBoxDropButton(wxWindow *win,
80 wxDC& dc,
81 const wxRect& rect,
82 int flags = 0);
83
84 virtual void DrawDropArrow(wxWindow *win,
85 wxDC& dc,
86 const wxRect& rect,
87 int flags = 0);
88
89 virtual void DrawCheckBox(wxWindow *win,
90 wxDC& dc,
91 const wxRect& rect,
92 int flags = 0);
93
94 virtual void DrawPushButton(wxWindow *win,
95 wxDC& dc,
96 const wxRect& rect,
97 int flags = 0);
98
99 virtual void DrawItemSelectionRect(wxWindow *win,
100 wxDC& dc,
101 const wxRect& rect,
102 int flags = 0);
103
104 virtual void DrawChoice(wxWindow* win,
105 wxDC& dc,
106 const wxRect& rect,
107 int flags=0);
108
109 virtual void DrawComboBox(wxWindow* win,
110 wxDC& dc,
111 const wxRect& rect,
112 int flags=0);
113
114 virtual void DrawTextCtrl(wxWindow* win,
115 wxDC& dc,
116 const wxRect& rect,
117 int flags=0);
118
119 virtual void DrawRadioBitmap(wxWindow* win,
120 wxDC& dc,
121 const wxRect& rect,
122 int flags=0);
123
124 virtual void DrawFocusRect(wxWindow* win, wxDC& dc, const wxRect& rect, int flags = 0);
125
126 virtual wxSize GetCheckBoxSize(wxWindow *win);
127
128 virtual wxSplitterRenderParams GetSplitterParams(const wxWindow *win);
129 };
130
131 // ============================================================================
132 // implementation
133 // ============================================================================
134
135 /* static */
136 wxRendererNative& wxRendererNative::GetDefault()
137 {
138 static wxRendererGTK s_rendererGTK;
139
140 return s_rendererGTK;
141 }
142
143 static GdkWindow* wxGetGdkWindowForDC(wxWindow* win, wxDC& dc)
144 {
145 GdkWindow* gdk_window = NULL;
146
147 #if wxUSE_GRAPHICS_CONTEXT
148 if ( dc.IsKindOf( CLASSINFO(wxGCDC) ) )
149 gdk_window = win->GTKGetDrawingWindow();
150 else
151 #endif
152 {
153 #if wxUSE_NEW_DC
154 wxDCImpl *impl = dc.GetImpl();
155 wxGTKDCImpl *gtk_impl = wxDynamicCast( impl, wxGTKDCImpl );
156 if (gtk_impl)
157 gdk_window = gtk_impl->GetGDKWindow();
158 #else
159 gdk_window = dc.GetGDKWindow();
160 #endif
161 }
162
163 #if !wxUSE_GRAPHICS_CONTEXT
164 wxUnusedVar(win);
165 #endif
166
167 return gdk_window;
168 }
169
170 // ----------------------------------------------------------------------------
171 // list/tree controls drawing
172 // ----------------------------------------------------------------------------
173
174 int
175 wxRendererGTK::DrawHeaderButton(wxWindow *win,
176 wxDC& dc,
177 const wxRect& rect,
178 int flags,
179 wxHeaderSortIconType sortArrow,
180 wxHeaderButtonParams* params)
181 {
182
183 GtkWidget *button = wxGTKPrivate::GetHeaderButtonWidget();
184 if (flags & wxCONTROL_SPECIAL)
185 button = wxGTKPrivate::GetHeaderButtonWidgetFirst();
186 if (flags & wxCONTROL_DIRTY)
187 button = wxGTKPrivate::GetHeaderButtonWidgetLast();
188
189 GdkWindow* gdk_window = wxGetGdkWindowForDC(win, dc);
190 wxASSERT_MSG( gdk_window,
191 wxT("cannot use wxRendererNative on wxDC of this type") );
192
193 int x_diff = 0;
194 if (win->GetLayoutDirection() == wxLayout_RightToLeft)
195 x_diff = rect.width;
196
197 GtkStateType state = GTK_STATE_NORMAL;
198 if (flags & wxCONTROL_DISABLED)
199 state = GTK_STATE_INSENSITIVE;
200 else
201 {
202 if (flags & wxCONTROL_CURRENT)
203 state = GTK_STATE_PRELIGHT;
204 }
205
206 gtk_paint_box
207 (
208 gtk_widget_get_style(button),
209 gdk_window,
210 state,
211 GTK_SHADOW_OUT,
212 NULL,
213 button,
214 "button",
215 dc.LogicalToDeviceX(rect.x) - x_diff, rect.y, rect.width, rect.height
216 );
217
218 return DrawHeaderButtonContents(win, dc, rect, flags, sortArrow, params);
219 }
220
221 int wxRendererGTK::GetHeaderButtonHeight(wxWindow *WXUNUSED(win))
222 {
223 GtkWidget *button = wxGTKPrivate::GetHeaderButtonWidget();
224
225 GtkRequisition req;
226 GTK_WIDGET_GET_CLASS(button)->size_request(button, &req);
227
228 return req.height;
229 }
230
231 int wxRendererGTK::GetHeaderButtonMargin(wxWindow *WXUNUSED(win))
232 {
233 wxFAIL_MSG( "GetHeaderButtonMargin() not implemented" );
234 return -1;
235 }
236
237
238 // draw a ">" or "v" button
239 void
240 wxRendererGTK::DrawTreeItemButton(wxWindow* win,
241 wxDC& dc, const wxRect& rect, int flags)
242 {
243 GtkWidget *tree = wxGTKPrivate::GetTreeWidget();
244
245 GdkWindow* gdk_window = wxGetGdkWindowForDC(win, dc);
246 wxASSERT_MSG( gdk_window,
247 wxT("cannot use wxRendererNative on wxDC of this type") );
248
249 GtkStateType state;
250 if ( flags & wxCONTROL_CURRENT )
251 state = GTK_STATE_PRELIGHT;
252 else
253 state = GTK_STATE_NORMAL;
254
255 int x_diff = 0;
256 if (win->GetLayoutDirection() == wxLayout_RightToLeft)
257 x_diff = rect.width;
258
259 // VZ: I don't know how to get the size of the expander so as to centre it
260 // in the given rectangle, +2/3 below is just what looks good here...
261 gtk_paint_expander
262 (
263 gtk_widget_get_style(tree),
264 gdk_window,
265 state,
266 NULL,
267 tree,
268 "treeview",
269 dc.LogicalToDeviceX(rect.x) + 6 - x_diff,
270 dc.LogicalToDeviceY(rect.y) + 3,
271 flags & wxCONTROL_EXPANDED ? GTK_EXPANDER_EXPANDED
272 : GTK_EXPANDER_COLLAPSED
273 );
274 }
275
276
277 // ----------------------------------------------------------------------------
278 // splitter sash drawing
279 // ----------------------------------------------------------------------------
280
281 static int GetGtkSplitterFullSize(GtkWidget* widget)
282 {
283 gint handle_size;
284 gtk_widget_style_get(widget, "handle_size", &handle_size, NULL);
285
286 return handle_size;
287 }
288
289 wxSplitterRenderParams
290 wxRendererGTK::GetSplitterParams(const wxWindow *WXUNUSED(win))
291 {
292 // we don't draw any border, hence 0 for the second field
293 return wxSplitterRenderParams
294 (
295 GetGtkSplitterFullSize(wxGTKPrivate::GetSplitterWidget()),
296 0,
297 true // hot sensitive
298 );
299 }
300
301 void
302 wxRendererGTK::DrawSplitterBorder(wxWindow * WXUNUSED(win),
303 wxDC& WXUNUSED(dc),
304 const wxRect& WXUNUSED(rect),
305 int WXUNUSED(flags))
306 {
307 // nothing to do
308 }
309
310 void
311 wxRendererGTK::DrawSplitterSash(wxWindow* win,
312 wxDC& dc,
313 const wxSize& size,
314 wxCoord position,
315 wxOrientation orient,
316 int flags)
317 {
318 if (gtk_widget_get_window(win->m_wxwindow) == NULL)
319 {
320 // window not realized yet
321 return;
322 }
323
324 GdkWindow* gdk_window = wxGetGdkWindowForDC(win, dc);
325 wxASSERT_MSG( gdk_window,
326 wxT("cannot use wxRendererNative on wxDC of this type") );
327
328 wxCoord full_size = GetGtkSplitterFullSize(wxGTKPrivate::GetSplitterWidget());
329
330 // are we drawing vertical or horizontal splitter?
331 const bool isVert = orient == wxVERTICAL;
332
333 GdkRectangle rect;
334
335 if ( isVert )
336 {
337 rect.x = position;
338 rect.y = 0;
339 rect.width = full_size;
340 rect.height = size.y;
341 }
342 else // horz
343 {
344 rect.x = 0;
345 rect.y = position;
346 rect.height = full_size;
347 rect.width = size.x;
348 }
349
350 int x_diff = 0;
351 if (win->GetLayoutDirection() == wxLayout_RightToLeft)
352 x_diff = rect.width;
353
354 gtk_paint_handle
355 (
356 gtk_widget_get_style(win->m_wxwindow),
357 gdk_window,
358 flags & wxCONTROL_CURRENT ? GTK_STATE_PRELIGHT : GTK_STATE_NORMAL,
359 GTK_SHADOW_NONE,
360 NULL /* no clipping */,
361 win->m_wxwindow,
362 "paned",
363 dc.LogicalToDeviceX(rect.x) - x_diff,
364 dc.LogicalToDeviceY(rect.y),
365 rect.width,
366 rect.height,
367 isVert ? GTK_ORIENTATION_VERTICAL : GTK_ORIENTATION_HORIZONTAL
368 );
369 }
370
371 void
372 wxRendererGTK::DrawDropArrow(wxWindow* win,
373 wxDC& dc,
374 const wxRect& rect,
375 int flags)
376 {
377 GtkWidget *button = wxGTKPrivate::GetButtonWidget();
378
379 // If we give WX_PIZZA(win->m_wxwindow)->bin_window as
380 // a window for gtk_paint_xxx function, then it won't
381 // work for wxMemoryDC. So that is why we assume wxDC
382 // is wxWindowDC (wxClientDC, wxMemoryDC and wxPaintDC
383 // are derived from it) and use its m_window.
384 GdkWindow* gdk_window = wxGetGdkWindowForDC(win, dc);
385 wxASSERT_MSG( gdk_window,
386 wxT("cannot use wxRendererNative on wxDC of this type") );
387
388 // draw arrow so that there is even space horizontally
389 // on both sides
390 int arrowX = rect.width/4 + 1;
391 int arrowWidth = rect.width - (arrowX*2);
392
393 // scale arrow's height accoording to the width
394 int arrowHeight = rect.width/3;
395 int arrowY = (rect.height-arrowHeight)/2 +
396 ((rect.height-arrowHeight) & 1);
397
398 GtkStateType state;
399
400 if ( flags & wxCONTROL_PRESSED )
401 state = GTK_STATE_ACTIVE;
402 else if ( flags & wxCONTROL_DISABLED )
403 state = GTK_STATE_INSENSITIVE;
404 else if ( flags & wxCONTROL_CURRENT )
405 state = GTK_STATE_PRELIGHT;
406 else
407 state = GTK_STATE_NORMAL;
408
409 // draw arrow on button
410 gtk_paint_arrow
411 (
412 gtk_widget_get_style(button),
413 gdk_window,
414 state,
415 flags & wxCONTROL_PRESSED ? GTK_SHADOW_IN : GTK_SHADOW_OUT,
416 NULL,
417 button,
418 "arrow",
419 GTK_ARROW_DOWN,
420 FALSE,
421 rect.x + arrowX,
422 rect.y + arrowY,
423 arrowWidth,
424 arrowHeight
425 );
426 }
427
428 void
429 wxRendererGTK::DrawComboBoxDropButton(wxWindow *win,
430 wxDC& dc,
431 const wxRect& rect,
432 int flags)
433 {
434 DrawPushButton(win,dc,rect,flags);
435 DrawDropArrow(win,dc,rect);
436 }
437
438 wxSize
439 wxRendererGTK::GetCheckBoxSize(wxWindow *WXUNUSED(win))
440 {
441 gint indicator_size, indicator_spacing;
442 gtk_widget_style_get(wxGTKPrivate::GetCheckButtonWidget(),
443 "indicator_size", &indicator_size,
444 "indicator_spacing", &indicator_spacing,
445 NULL);
446
447 int size = indicator_size + indicator_spacing * 2;
448 return wxSize(size, size);
449 }
450
451 void
452 wxRendererGTK::DrawCheckBox(wxWindow* win,
453 wxDC& dc,
454 const wxRect& rect,
455 int flags )
456 {
457 GtkWidget *button = wxGTKPrivate::GetCheckButtonWidget();
458
459 GdkWindow* gdk_window = wxGetGdkWindowForDC(win, dc);
460 wxASSERT_MSG( gdk_window,
461 wxT("cannot use wxRendererNative on wxDC of this type") );
462
463 gint indicator_size, indicator_spacing;
464 gtk_widget_style_get(button,
465 "indicator_size", &indicator_size,
466 "indicator_spacing", &indicator_spacing,
467 NULL);
468
469 GtkStateType state;
470
471 if ( flags & wxCONTROL_PRESSED )
472 state = GTK_STATE_ACTIVE;
473 else if ( flags & wxCONTROL_DISABLED )
474 state = GTK_STATE_INSENSITIVE;
475 else if ( flags & wxCONTROL_CURRENT )
476 state = GTK_STATE_PRELIGHT;
477 else
478 state = GTK_STATE_NORMAL;
479
480 GtkShadowType shadow_type;
481
482 if ( flags & wxCONTROL_UNDETERMINED )
483 shadow_type = GTK_SHADOW_ETCHED_IN;
484 else if ( flags & wxCONTROL_CHECKED )
485 shadow_type = GTK_SHADOW_IN;
486 else
487 shadow_type = GTK_SHADOW_OUT;
488
489 gtk_paint_check
490 (
491 gtk_widget_get_style(button),
492 gdk_window,
493 state,
494 shadow_type,
495 NULL,
496 button,
497 "cellcheck",
498 dc.LogicalToDeviceX(rect.x) + indicator_spacing,
499 dc.LogicalToDeviceY(rect.y) + indicator_spacing,
500 indicator_size, indicator_size
501 );
502 }
503
504 void
505 wxRendererGTK::DrawPushButton(wxWindow* win,
506 wxDC& dc,
507 const wxRect& rect,
508 int flags)
509 {
510 GtkWidget *button = wxGTKPrivate::GetButtonWidget();
511
512 GdkWindow* gdk_window = wxGetGdkWindowForDC(win, dc);
513 wxASSERT_MSG( gdk_window,
514 wxT("cannot use wxRendererNative on wxDC of this type") );
515
516 // draw button
517 GtkStateType state;
518
519 if ( flags & wxCONTROL_PRESSED )
520 state = GTK_STATE_ACTIVE;
521 else if ( flags & wxCONTROL_DISABLED )
522 state = GTK_STATE_INSENSITIVE;
523 else if ( flags & wxCONTROL_CURRENT )
524 state = GTK_STATE_PRELIGHT;
525 else
526 state = GTK_STATE_NORMAL;
527
528 gtk_paint_box
529 (
530 gtk_widget_get_style(button),
531 gdk_window,
532 state,
533 flags & wxCONTROL_PRESSED ? GTK_SHADOW_IN : GTK_SHADOW_OUT,
534 NULL,
535 button,
536 "button",
537 dc.LogicalToDeviceX(rect.x),
538 dc.LogicalToDeviceY(rect.y),
539 rect.width,
540 rect.height
541 );
542 }
543
544 void
545 wxRendererGTK::DrawItemSelectionRect(wxWindow* win,
546 wxDC& dc,
547 const wxRect& rect,
548 int flags )
549 {
550 GdkWindow* gdk_window = wxGetGdkWindowForDC(win, dc);
551 wxASSERT_MSG( gdk_window,
552 wxT("cannot use wxRendererNative on wxDC of this type") );
553
554 if (flags & wxCONTROL_SELECTED)
555 {
556 int x_diff = 0;
557 if (win->GetLayoutDirection() == wxLayout_RightToLeft)
558 x_diff = rect.width;
559
560 // the wxCONTROL_FOCUSED state is deduced
561 // directly from the m_wxwindow by GTK+
562 gtk_paint_flat_box(gtk_widget_get_style(wxGTKPrivate::GetTreeWidget()),
563 gdk_window,
564 GTK_STATE_SELECTED,
565 GTK_SHADOW_NONE,
566 NULL,
567 win->m_wxwindow,
568 "cell_even",
569 dc.LogicalToDeviceX(rect.x) - x_diff,
570 dc.LogicalToDeviceY(rect.y),
571 rect.width,
572 rect.height );
573 }
574
575 if ((flags & wxCONTROL_CURRENT) && (flags & wxCONTROL_FOCUSED))
576 DrawFocusRect(win, dc, rect, flags);
577 }
578
579 void wxRendererGTK::DrawFocusRect(wxWindow* win, wxDC& dc, const wxRect& rect, int flags)
580 {
581 GdkWindow* gdk_window = wxGetGdkWindowForDC(win, dc);
582 wxASSERT_MSG( gdk_window,
583 wxT("cannot use wxRendererNative on wxDC of this type") );
584
585 GtkStateType state;
586 if (flags & wxCONTROL_SELECTED)
587 state = GTK_STATE_SELECTED;
588 else
589 state = GTK_STATE_NORMAL;
590
591 gtk_paint_focus( gtk_widget_get_style(win->m_widget),
592 gdk_window,
593 state,
594 NULL,
595 win->m_wxwindow,
596 NULL,
597 dc.LogicalToDeviceX(rect.x),
598 dc.LogicalToDeviceY(rect.y),
599 rect.width,
600 rect.height );
601 }
602
603 // Uses the theme to draw the border and fill for something like a wxTextCtrl
604 void wxRendererGTK::DrawTextCtrl(wxWindow* win, wxDC& dc, const wxRect& rect, int flags)
605 {
606 GtkWidget *entry = wxGTKPrivate::GetTextEntryWidget();
607
608 GdkWindow* gdk_window = wxGetGdkWindowForDC(win, dc);
609
610 GtkStateType state = GTK_STATE_NORMAL;
611 if ( flags & wxCONTROL_DISABLED )
612 state = GTK_STATE_INSENSITIVE;
613
614 gtk_widget_set_can_focus(entry, (flags & wxCONTROL_CURRENT) != 0);
615
616 gtk_paint_shadow
617 (
618 gtk_widget_get_style(entry),
619 gdk_window,
620 state,
621 GTK_SHADOW_OUT,
622 NULL,
623 entry,
624 "entry",
625 dc.LogicalToDeviceX(rect.x),
626 dc.LogicalToDeviceY(rect.y),
627 rect.width,
628 rect.height
629 );
630 }
631
632 // Draw the equivalent of a wxComboBox
633 void wxRendererGTK::DrawComboBox(wxWindow* win, wxDC& dc, const wxRect& rect, int flags)
634 {
635 GtkWidget *combo = wxGTKPrivate::GetComboBoxWidget();
636
637 GdkWindow* gdk_window = wxGetGdkWindowForDC(win, dc);
638
639 GtkStateType state = GTK_STATE_NORMAL;
640 if ( flags & wxCONTROL_DISABLED )
641 state = GTK_STATE_INSENSITIVE;
642
643 gtk_widget_set_can_focus(combo, (flags & wxCONTROL_CURRENT) != 0);
644
645 gtk_paint_shadow
646 (
647 gtk_widget_get_style(combo),
648 gdk_window,
649 state,
650 GTK_SHADOW_OUT,
651 NULL,
652 combo,
653 "combobox",
654 dc.LogicalToDeviceX(rect.x),
655 dc.LogicalToDeviceY(rect.y),
656 rect.width,
657 rect.height
658 );
659
660 wxRect r = rect;
661 int extent = rect.height / 2;
662 r.x += rect.width - extent - extent/2;
663 r.y += extent/2;
664 r.width = extent;
665 r.height = extent;
666
667 gtk_paint_arrow
668 (
669 gtk_widget_get_style(combo),
670 gdk_window,
671 state,
672 GTK_SHADOW_OUT,
673 NULL,
674 combo,
675 "arrow",
676 GTK_ARROW_DOWN,
677 TRUE,
678 dc.LogicalToDeviceX(r.x),
679 dc.LogicalToDeviceY(r.y),
680 r.width,
681 r.height
682 );
683
684 r = rect;
685 r.x += rect.width - 2*extent;
686 r.width = 2;
687
688 gtk_paint_box
689 (
690 gtk_widget_get_style(combo),
691 gdk_window,
692 state,
693 GTK_SHADOW_ETCHED_OUT,
694 NULL,
695 combo,
696 "vseparator",
697 dc.LogicalToDeviceX(r.x),
698 dc.LogicalToDeviceY(r.y+1),
699 r.width,
700 r.height-2
701 );
702 }
703
704
705 void wxRendererGTK::DrawChoice(wxWindow* win, wxDC& dc,
706 const wxRect& rect, int flags)
707 {
708 DrawComboBox( win, dc, rect, flags );
709 }
710
711
712 // Draw a themed radio button
713 void wxRendererGTK::DrawRadioBitmap(wxWindow* win, wxDC& dc, const wxRect& rect, int flags)
714 {
715 GtkWidget *button = wxGTKPrivate::GetRadioButtonWidget();
716
717 GdkWindow* gdk_window = wxGetGdkWindowForDC(win, dc);
718
719 GtkShadowType shadow_type = GTK_SHADOW_OUT;
720 if ( flags & wxCONTROL_CHECKED )
721 shadow_type = GTK_SHADOW_IN;
722 else if ( flags & wxCONTROL_UNDETERMINED )
723 shadow_type = GTK_SHADOW_ETCHED_IN;
724
725 GtkStateType state = GTK_STATE_NORMAL;
726 if ( flags & wxCONTROL_DISABLED )
727 state = GTK_STATE_INSENSITIVE;
728 if ( flags & wxCONTROL_PRESSED )
729 state = GTK_STATE_ACTIVE;
730 /*
731 Don't know when to set this
732 state_type = GTK_STATE_PRELIGHT;
733 */
734
735 gtk_paint_option
736 (
737 gtk_widget_get_style(button),
738 gdk_window,
739 state,
740 shadow_type,
741 NULL,
742 button,
743 "radiobutton",
744 dc.LogicalToDeviceX(rect.x),
745 dc.LogicalToDeviceY(rect.y),
746 rect.width, rect.height
747 );
748 }