]> git.saurik.com Git - wxWidgets.git/blame - src/gtk1/renderer.cpp
revert nested event loop support for wxGTK1 because it causes applications hangs
[wxWidgets.git] / src / gtk1 / renderer.cpp
CommitLineData
9c7f49f5 1///////////////////////////////////////////////////////////////////////////////
cdccdfab 2// Name: src/gtk1/renderer.cpp
38c4cb6a 3// Purpose: implementation of wxRendererNative for wxGTK
9c7f49f5
VZ
4// Author: Vadim Zeitlin
5// Modified by:
6// Created: 20.07.2003
9c7f49f5 7// Copyright: (c) 2003 Vadim Zeitlin <vadim@wxwindows.org>
526954c5 8// Licence: wxWindows licence
9c7f49f5
VZ
9///////////////////////////////////////////////////////////////////////////////
10
11// ============================================================================
12// declarations
13// ============================================================================
14
15// ----------------------------------------------------------------------------
16// headers
17// ----------------------------------------------------------------------------
18
19// for compilers that support precompilation, includes "wx.h".
20#include "wx/wxprec.h"
21
22#ifdef __BORLANDC__
23 #pragma hdrstop
24#endif
25
e1bf3ad3 26#include "wx/renderer.h"
cdccdfab
WS
27
28#ifndef WX_PRECOMP
29 #include "wx/window.h"
da80ae71 30 #include "wx/dc.h"
cdccdfab
WS
31#endif
32
9c7f49f5 33#include <gtk/gtk.h>
3cbab641 34#include "wx/gtk1/win_gtk.h"
10d30222 35#include "wx/gtk1/dcclient.h"
9c7f49f5 36
91af0895
WS
37// RR: After a correction to the orientation of the sash
38// this doesn't seem to be required anymore and it
39// seems to confuse some themes so USE_ERASE_RECT=0
40#define USE_ERASE_RECT 0
41
9c7f49f5 42// ----------------------------------------------------------------------------
38c4cb6a 43// wxRendererGTK: our wxRendererNative implementation
9c7f49f5
VZ
44// ----------------------------------------------------------------------------
45
38c4cb6a 46class WXDLLEXPORT wxRendererGTK : public wxDelegateRendererNative
9c7f49f5
VZ
47{
48public:
49 // draw the header control button (used by wxListCtrl)
87ebb0b7
VZ
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);
9c7f49f5 56
d16cf3cd
VZ
57 virtual void DrawSplitterBorder(wxWindow *win,
58 wxDC& dc,
af99040c
VZ
59 const wxRect& rect,
60 int flags = 0);
95155e75
VZ
61 virtual void DrawSplitterSash(wxWindow *win,
62 wxDC& dc,
63 const wxSize& size,
d16cf3cd 64 wxCoord position,
af99040c
VZ
65 wxOrientation orient,
66 int flags = 0);
d16cf3cd 67
38511687
VZ
68 virtual void DrawComboBoxDropButton(wxWindow *win,
69 wxDC& dc,
70 const wxRect& rect,
71 int flags = 0);
72
4c85ab75
VZ
73 virtual void DrawDropArrow(wxWindow *win,
74 wxDC& dc,
75 const wxRect& rect,
76 int flags = 0);
77
af99040c 78 virtual wxSplitterRenderParams GetSplitterParams(const wxWindow *win);
e1befae3
VZ
79
80private:
bc13e772
VZ
81 // FIXME: shouldn't we destroy these windows somewhere?
82
e1befae3 83 // used by DrawHeaderButton and DrawComboBoxDropButton
bc13e772 84 static GtkWidget *GetButtonWidget();
9c7f49f5
VZ
85};
86
87// ============================================================================
88// implementation
89// ============================================================================
90
91/* static */
f0244295 92wxRendererNative& wxRendererNative::GetDefault()
9c7f49f5
VZ
93{
94 static wxRendererGTK s_rendererGTK;
95
96 return s_rendererGTK;
97}
98
a4622f29 99// ----------------------------------------------------------------------------
bc13e772 100// helper functions
a4622f29
VZ
101// ----------------------------------------------------------------------------
102
bc13e772
VZ
103GtkWidget *
104wxRendererGTK::GetButtonWidget()
105{
106 static GtkWidget *s_button = NULL;
107 static GtkWidget *s_window = NULL;
a4622f29 108
bc13e772
VZ
109 if ( !s_button )
110 {
111 s_window = gtk_window_new( GTK_WINDOW_POPUP );
112 gtk_widget_realize( s_window );
113 s_button = gtk_button_new();
114 gtk_container_add( GTK_CONTAINER(s_window), s_button );
115 gtk_widget_realize( s_button );
116 }
117
118 return s_button;
119}
120
d16cf3cd
VZ
121// ----------------------------------------------------------------------------
122// list/tree controls drawing
123// ----------------------------------------------------------------------------
124
87ebb0b7 125int
9c7f49f5
VZ
126wxRendererGTK::DrawHeaderButton(wxWindow *win,
127 wxDC& dc,
128 const wxRect& rect,
d1b8a743
VZ
129 int flags,
130 wxHeaderSortIconType WXUNUSED(sortArrow),
131 wxHeaderButtonParams* WXUNUSED(params))
9c7f49f5 132{
9b311923 133
bc13e772 134 GtkWidget *button = GetButtonWidget();
9b311923 135
9c7f49f5
VZ
136 gtk_paint_box
137 (
bc13e772 138 button->style,
a4622f29
VZ
139 // FIXME: I suppose GTK_PIZZA(win->m_wxwindow)->bin_window doesn't work with wxMemoryDC.
140 // Maybe use code similar as in DrawComboBoxDropButton below?
9c7f49f5
VZ
141 GTK_PIZZA(win->m_wxwindow)->bin_window,
142 flags & wxCONTROL_DISABLED ? GTK_STATE_INSENSITIVE : GTK_STATE_NORMAL,
143 GTK_SHADOW_OUT,
38511687 144 NULL,
bc13e772 145 button,
9b311923 146 "button",
10d30222 147 dc.LogicalToDeviceX(rect.x) -1, rect.y -1, rect.width +2, rect.height +2
9c7f49f5 148 );
87ebb0b7
VZ
149
150 return rect.width + 2;
9c7f49f5
VZ
151}
152
d16cf3cd
VZ
153// ----------------------------------------------------------------------------
154// splitter sash drawing
155// ----------------------------------------------------------------------------
156
3cbab641
MR
157// the full sash width (should be even)
158static const wxCoord SASH_SIZE = 8;
af99040c 159
3cbab641
MR
160// margin around the sash
161static const wxCoord SASH_MARGIN = 2;
d16cf3cd 162
38418827
RR
163static int GetGtkSplitterFullSize()
164{
38418827 165 return SASH_SIZE + SASH_MARGIN;
38418827
RR
166}
167
af99040c 168wxSplitterRenderParams
38418827 169wxRendererGTK::GetSplitterParams(const wxWindow *WXUNUSED(win))
d16cf3cd 170{
af99040c
VZ
171 // we don't draw any border, hence 0 for the second field
172 return wxSplitterRenderParams
173 (
38418827 174 GetGtkSplitterFullSize(),
af99040c 175 0,
af99040c 176 false // not
af99040c 177 );
d16cf3cd
VZ
178}
179
180void
181wxRendererGTK::DrawSplitterBorder(wxWindow * WXUNUSED(win),
182 wxDC& WXUNUSED(dc),
af99040c
VZ
183 const wxRect& WXUNUSED(rect),
184 int WXUNUSED(flags))
d16cf3cd
VZ
185{
186 // nothing to do
187}
95155e75 188
95155e75
VZ
189void
190wxRendererGTK::DrawSplitterSash(wxWindow *win,
89954433 191 wxDC& WXUNUSED(dc),
95155e75 192 const wxSize& size,
d16cf3cd 193 wxCoord position,
af99040c 194 wxOrientation orient,
3cbab641 195 int WXUNUSED(flags))
95155e75
VZ
196{
197 if ( !win->m_wxwindow->window )
198 {
0100b858 199 // window not realized yet
95155e75
VZ
200 return;
201 }
91af0895 202
38418827 203 wxCoord full_size = GetGtkSplitterFullSize();
95155e75 204
d16cf3cd
VZ
205 // are we drawing vertical or horizontal splitter?
206 const bool isVert = orient == wxVERTICAL;
207
d16cf3cd 208 GdkRectangle rect;
91af0895 209#if USE_ERASE_RECT
35468934 210 GdkRectangle erase_rect;
91af0895
WS
211#endif
212
d16cf3cd
VZ
213 if ( isVert )
214 {
0100b858 215 int h = win->GetClientSize().GetHeight();
e1befae3 216
d16cf3cd 217 rect.x = position;
0100b858 218 rect.y = 0;
38418827 219 rect.width = full_size;
0100b858 220 rect.height = h;
e1befae3 221
91af0895 222#if USE_ERASE_RECT
35468934
RR
223 erase_rect.x = position;
224 erase_rect.y = 0;
38418827 225 erase_rect.width = full_size;
35468934 226 erase_rect.height = h;
91af0895 227#endif
d16cf3cd
VZ
228 }
229 else // horz
230 {
0100b858 231 int w = win->GetClientSize().GetWidth();
e1befae3 232
0100b858 233 rect.x = 0;
d16cf3cd 234 rect.y = position;
38418827 235 rect.height = full_size;
0100b858 236 rect.width = w;
e1befae3 237
91af0895 238#if USE_ERASE_RECT
35468934
RR
239 erase_rect.y = position;
240 erase_rect.x = 0;
38418827 241 erase_rect.height = full_size;
35468934 242 erase_rect.width = w;
91af0895 243#endif
d16cf3cd
VZ
244 }
245
91af0895 246#if USE_ERASE_RECT
ab5ea030
RR
247 // we must erase everything first, otherwise the garbage
248 // from the old sash is left when dragging it
35468934
RR
249 gtk_paint_flat_box
250 (
251 win->m_wxwindow->style,
252 GTK_PIZZA(win->m_wxwindow)->bin_window,
253 GTK_STATE_NORMAL,
254 GTK_SHADOW_NONE,
255 NULL,
256 win->m_wxwindow,
ab5ea030 257 (char *)"viewportbin", // const_cast
35468934
RR
258 erase_rect.x,
259 erase_rect.y,
260 erase_rect.width,
261 erase_rect.height
262 );
ab5ea030 263#endif
35468934 264
d16cf3cd
VZ
265
266 // leave some margin before sash itself
267 position += SASH_MARGIN / 2;
268
269 // and finally draw it using GTK paint functions
270 typedef void (*GtkPaintLineFunc)(GtkStyle *, GdkWindow *,
271 GtkStateType,
272 GdkRectangle *, GtkWidget *,
ef9bfb71 273 gchar *,
ef9bfb71 274 gint, gint, gint);
d16cf3cd
VZ
275
276 GtkPaintLineFunc func = isVert ? gtk_paint_vline : gtk_paint_hline;
277
278 (*func)
95155e75
VZ
279 (
280 win->m_wxwindow->style,
d16cf3cd 281 GTK_PIZZA(win->m_wxwindow)->bin_window,
95155e75 282 GTK_STATE_NORMAL,
d16cf3cd 283 NULL,
95155e75 284 win->m_wxwindow,
d16cf3cd
VZ
285 (char *)"paned", // const_cast
286 0, isVert ? size.y : size.x, position + SASH_SIZE / 2 - 1
95155e75
VZ
287 );
288
289 gtk_paint_box
290 (
291 win->m_wxwindow->style,
d16cf3cd 292 GTK_PIZZA(win->m_wxwindow)->bin_window,
95155e75
VZ
293 GTK_STATE_NORMAL,
294 GTK_SHADOW_OUT,
d3b9f782 295 NULL,
95155e75
VZ
296 win->m_wxwindow,
297 (char *)"paned", // const_cast
d16cf3cd
VZ
298 isVert ? position : size.x - 2*SASH_SIZE,
299 isVert ? size.y - 2*SASH_SIZE : position,
300 SASH_SIZE, SASH_SIZE
95155e75
VZ
301 );
302}
303
4c85ab75 304void
89954433 305wxRendererGTK::DrawDropArrow(wxWindow *WXUNUSED(win),
4c85ab75
VZ
306 wxDC& dc,
307 const wxRect& rect,
308 int flags)
38511687 309{
bc13e772 310 GtkWidget *button = GetButtonWidget();
38511687 311
4c85ab75
VZ
312 // If we give GTK_PIZZA(win->m_wxwindow)->bin_window as
313 // a window for gtk_paint_xxx function, then it won't
314 // work for wxMemoryDC. So that is why we assume wxDC
315 // is wxWindowDC (wxClientDC, wxMemoryDC and wxPaintDC
316 // are derived from it) and use its m_window.
10d30222
VZ
317 wxWindowDCImpl * const impl = wxDynamicCast(dc.GetImpl(), wxWindowDCImpl);
318 wxCHECK_RET( impl, "must have a window DC" );
319
320 GdkWindow* gdk_window = impl->GetGDKWindow();
a4622f29 321
4c85ab75
VZ
322 // draw arrow so that there is even space horizontally
323 // on both sides
324 int arrowX = rect.width/4 + 1;
325 int arrowWidth = rect.width - (arrowX*2);
326
327 // scale arrow's height accoording to the width
328 int arrowHeight = rect.width/3;
329 int arrowY = (rect.height-arrowHeight)/2 +
330 ((rect.height-arrowHeight) & 1);
331
e1befae3 332 GtkStateType state;
a4622f29 333
3203621a
JS
334 if ( flags & wxCONTROL_PRESSED )
335 state = GTK_STATE_ACTIVE;
a4622f29
VZ
336 else if ( flags & wxCONTROL_DISABLED )
337 state = GTK_STATE_INSENSITIVE;
3203621a
JS
338 else if ( flags & wxCONTROL_CURRENT )
339 state = GTK_STATE_PRELIGHT;
e1befae3
VZ
340 else
341 state = GTK_STATE_NORMAL;
a4622f29 342
a4622f29 343 // draw arrow on button
a4622f29
VZ
344 gtk_paint_arrow
345 (
bc13e772 346 button->style,
2e992e06 347 gdk_window,
a4622f29 348 state,
e1befae3 349 flags & wxCONTROL_PRESSED ? GTK_SHADOW_IN : GTK_SHADOW_OUT,
a4622f29 350 NULL,
bc13e772 351 button,
a4622f29
VZ
352 "arrow",
353 GTK_ARROW_DOWN,
a8ac548e 354 FALSE,
4c85ab75
VZ
355 rect.x + arrowX,
356 rect.y + arrowY,
357 arrowWidth,
358 arrowHeight
a4622f29 359 );
38511687
VZ
360}
361
4c85ab75
VZ
362void
363wxRendererGTK::DrawComboBoxDropButton(wxWindow *win,
364 wxDC& dc,
365 const wxRect& rect,
366 int flags)
367{
368 GtkWidget *button = GetButtonWidget();
369
370 // for reason why we do this, see DrawDropArrow
10d30222
VZ
371 wxWindowDCImpl * const impl = wxDynamicCast(dc.GetImpl(), wxWindowDCImpl);
372 wxCHECK_RET( impl, "must have a window DC" );
373
374 GdkWindow* gdk_window = impl->GetGDKWindow();
4c85ab75
VZ
375
376 // draw button
377 GtkStateType state;
378
3203621a
JS
379 if ( flags & wxCONTROL_PRESSED )
380 state = GTK_STATE_ACTIVE;
4c85ab75
VZ
381 else if ( flags & wxCONTROL_DISABLED )
382 state = GTK_STATE_INSENSITIVE;
3203621a
JS
383 else if ( flags & wxCONTROL_CURRENT )
384 state = GTK_STATE_PRELIGHT;
4c85ab75
VZ
385 else
386 state = GTK_STATE_NORMAL;
387
388 gtk_paint_box
389 (
390 button->style,
2e992e06 391 gdk_window,
4c85ab75
VZ
392 state,
393 flags & wxCONTROL_PRESSED ? GTK_SHADOW_IN : GTK_SHADOW_OUT,
394 NULL,
395 button,
396 "button",
397 rect.x, rect.y, rect.width, rect.height
398 );
399
400 // draw arrow on button
401 DrawDropArrow(win,dc,rect,flags);
402
403}