]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/dcclient.cpp
Fix bug [1297817] - applied suggested patch
[wxWidgets.git] / src / gtk / dcclient.cpp
CommitLineData
c801d85f 1/////////////////////////////////////////////////////////////////////////////
e5131165 2// Name: gtk/dcclient.cpp
c801d85f
KB
3// Purpose:
4// Author: Robert Roebling
6f65e337 5// RCS-ID: $Id$
6c9a19aa 6// Copyright: (c) 1998 Robert Roebling, Chris Breeze
65571936 7// Licence: wxWindows licence
c801d85f
KB
8/////////////////////////////////////////////////////////////////////////////
9
14f355c2
VS
10// For compilers that support precompilation, includes "wx.h".
11#include "wx/wxprec.h"
12
d02af7bb
JJ
13#ifdef __VMS
14#define XCopyPlane XCOPYPLANE
15#endif
16
c801d85f 17#include "wx/dcclient.h"
6f65e337 18#include "wx/dcmemory.h"
4bc67cc5 19#include "wx/image.h"
e5131165 20#include "wx/module.h"
b1699cd3 21#include "wx/log.h"
db16cab4 22#include "wx/fontutil.h"
e5131165 23
ed673c6a 24#include "wx/gtk/win_gtk.h"
c801d85f 25
463c4d71 26#include "wx/math.h" // for floating-point functions
e5131165 27
071a2d78 28#include <gdk/gdk.h>
993f97ee 29#include <gdk/gdkx.h>
8943b403 30#include <gdk/gdkprivate.h>
071a2d78 31#include <gtk/gtk.h>
83624f79 32
809934d2
RR
33//-----------------------------------------------------------------------------
34// local defines
35//-----------------------------------------------------------------------------
36
e1208c31 37#define USE_PAINT_REGION 1
809934d2 38
c801d85f
KB
39//-----------------------------------------------------------------------------
40// local data
41//-----------------------------------------------------------------------------
42
43#include "bdiag.xbm"
44#include "fdiag.xbm"
45#include "cdiag.xbm"
46#include "horiz.xbm"
47#include "verti.xbm"
48#include "cross.xbm"
49#define num_hatches 6
50
3ca6a5f0
BP
51#define IS_15_PIX_HATCH(s) ((s)==wxCROSSDIAG_HATCH || (s)==wxHORIZONTAL_HATCH || (s)==wxVERTICAL_HATCH)
52#define IS_16_PIX_HATCH(s) ((s)!=wxCROSSDIAG_HATCH && (s)!=wxHORIZONTAL_HATCH && (s)!=wxVERTICAL_HATCH)
53
54
c801d85f 55static GdkPixmap *hatches[num_hatches];
c67daf87 56static GdkPixmap **hatch_bitmap = (GdkPixmap **) NULL;
c801d85f 57
c2fa61e8 58extern GtkWidget *wxGetRootWindow();
3d2d8da1 59
c801d85f
KB
60//-----------------------------------------------------------------------------
61// constants
62//-----------------------------------------------------------------------------
63
95724b1a 64const double RAD2DEG = 180.0 / M_PI;
c801d85f 65
9a8c7620
VZ
66// ----------------------------------------------------------------------------
67// private functions
68// ----------------------------------------------------------------------------
69
70static inline double dmax(double a, double b) { return a > b ? a : b; }
71static inline double dmin(double a, double b) { return a < b ? a : b; }
72
73static inline double DegToRad(double deg) { return (deg * M_PI) / 180.0; }
74
6f65e337
JS
75//-----------------------------------------------------------------------------
76// temporary implementation of the missing GDK function
77//-----------------------------------------------------------------------------
b0e0d661 78
6f65e337 79#include "gdk/gdkprivate.h"
b0e0d661 80
1e6feb95
VZ
81void gdk_wx_draw_bitmap(GdkDrawable *drawable,
82 GdkGC *gc,
83 GdkDrawable *src,
84 gint xsrc,
85 gint ysrc,
86 gint xdest,
87 gint ydest,
88 gint width,
89 gint height)
6f65e337 90{
17a1ebd1
VZ
91 wxCHECK_RET( drawable, _T("NULL drawable in gdk_wx_draw_bitmap") );
92 wxCHECK_RET( src, _T("NULL src in gdk_wx_draw_bitmap") );
93 wxCHECK_RET( gc, _T("NULL gc in gdk_wx_draw_bitmap") );
ab9d0a8c 94
8943b403 95#ifdef __WXGTK20__
d90c9596 96 gint src_width, src_height;
8943b403 97 gdk_drawable_get_size(src, &src_width, &src_height);
8943b403
OK
98 if (width == -1) width = src_width;
99 if (height == -1) height = src_height;
265898fd 100
8943b403
OK
101 XCopyPlane( GDK_WINDOW_XDISPLAY(drawable),
102 GDK_WINDOW_XID(src),
103 GDK_WINDOW_XID(drawable),
104 GDK_GC_XGC(gc),
105 xsrc, ysrc,
106 width, height,
d90c9596 107 0, 0,
8943b403
OK
108 1 );
109#else
d90c9596
RR
110 GdkWindowPrivate *drawable_private;
111 GdkWindowPrivate *src_private;
112 GdkGCPrivate *gc_private;
ab9d0a8c 113
d90c9596
RR
114 drawable_private = (GdkWindowPrivate*) drawable;
115 src_private = (GdkWindowPrivate*) src;
116 if (drawable_private->destroyed || src_private->destroyed)
117 return;
118
119 gint src_width = src_private->width;
120 gint src_height = src_private->height;
121
122 gc_private = (GdkGCPrivate*) gc;
ab9d0a8c 123
d90c9596
RR
124 if (width == -1) width = src_width;
125 if (height == -1) height = src_height;
ab9d0a8c 126
265898fd 127 XCopyPlane( drawable_private->xdisplay,
b0e0d661
VZ
128 src_private->xwindow,
129 drawable_private->xwindow,
130 gc_private->xgc,
131 xsrc, ysrc,
132 width, height,
133 xdest, ydest,
134 1 );
8943b403 135#endif
6f65e337
JS
136}
137
3d2d8da1
RR
138//-----------------------------------------------------------------------------
139// Implement Pool of Graphic contexts. Creating them takes too much time.
140//-----------------------------------------------------------------------------
141
0e09f76e
RR
142enum wxPoolGCType
143{
144 wxGC_ERROR = 0,
145 wxTEXT_MONO,
146 wxBG_MONO,
147 wxPEN_MONO,
148 wxBRUSH_MONO,
149 wxTEXT_COLOUR,
150 wxBG_COLOUR,
151 wxPEN_COLOUR,
f6bcfd97
BP
152 wxBRUSH_COLOUR,
153 wxTEXT_SCREEN,
154 wxBG_SCREEN,
155 wxPEN_SCREEN,
156 wxBRUSH_SCREEN
0e09f76e
RR
157};
158
3d2d8da1
RR
159struct wxGC
160{
0e09f76e
RR
161 GdkGC *m_gc;
162 wxPoolGCType m_type;
163 bool m_used;
3d2d8da1
RR
164};
165
696f36b7
JS
166#define GC_POOL_ALLOC_SIZE 100
167
168static int wxGCPoolSize = 0;
169
170static wxGC *wxGCPool = NULL;
3d2d8da1
RR
171
172static void wxInitGCPool()
173{
696f36b7
JS
174 // This really could wait until the first call to
175 // wxGetPoolGC, but we will make the first allocation
176 // now when other initialization is being performed.
ab9d0a8c 177
696f36b7
JS
178 // Set initial pool size.
179 wxGCPoolSize = GC_POOL_ALLOC_SIZE;
ab9d0a8c 180
696f36b7
JS
181 // Allocate initial pool.
182 wxGCPool = (wxGC *)malloc(wxGCPoolSize * sizeof(wxGC));
183 if (wxGCPool == NULL)
184 {
185 // If we cannot malloc, then fail with error
186 // when debug is enabled. If debug is not enabled,
187 // the problem will eventually get caught
551b5391 188 // in wxGetPoolGC.
696f36b7
JS
189 wxFAIL_MSG( wxT("Cannot allocate GC pool") );
190 return;
191 }
ab9d0a8c 192
696f36b7
JS
193 // Zero initial pool.
194 memset(wxGCPool, 0, wxGCPoolSize * sizeof(wxGC));
3d2d8da1
RR
195}
196
197static void wxCleanUpGCPool()
198{
f6116855 199 for (int i = 0; i < wxGCPoolSize; i++)
3d2d8da1
RR
200 {
201 if (wxGCPool[i].m_gc)
202 gdk_gc_unref( wxGCPool[i].m_gc );
203 }
696f36b7
JS
204
205 free(wxGCPool);
206 wxGCPool = NULL;
207 wxGCPoolSize = 0;
3d2d8da1
RR
208}
209
0e09f76e 210static GdkGC* wxGetPoolGC( GdkWindow *window, wxPoolGCType type )
3d2d8da1 211{
696f36b7 212 wxGC *pptr;
ab9d0a8c 213
696f36b7
JS
214 // Look for an available GC.
215 for (int i = 0; i < wxGCPoolSize; i++)
3d2d8da1
RR
216 {
217 if (!wxGCPool[i].m_gc)
218 {
219 wxGCPool[i].m_gc = gdk_gc_new( window );
220 gdk_gc_set_exposures( wxGCPool[i].m_gc, FALSE );
0e09f76e 221 wxGCPool[i].m_type = type;
ab9d0a8c 222 wxGCPool[i].m_used = false;
3d2d8da1 223 }
0e09f76e 224 if ((!wxGCPool[i].m_used) && (wxGCPool[i].m_type == type))
3d2d8da1 225 {
ab9d0a8c 226 wxGCPool[i].m_used = true;
3d2d8da1
RR
227 return wxGCPool[i].m_gc;
228 }
229 }
5f170f33 230
696f36b7
JS
231 // We did not find an available GC.
232 // We need to grow the GC pool.
233 pptr = (wxGC *)realloc(wxGCPool,
551b5391 234 (wxGCPoolSize + GC_POOL_ALLOC_SIZE)*sizeof(wxGC));
696f36b7
JS
235 if (pptr != NULL)
236 {
237 // Initialize newly allocated pool.
238 wxGCPool = pptr;
551b5391
RR
239 memset(&wxGCPool[wxGCPoolSize], 0,
240 GC_POOL_ALLOC_SIZE*sizeof(wxGC));
ab9d0a8c
WS
241
242 // Initialize entry we will return.
696f36b7
JS
243 wxGCPool[wxGCPoolSize].m_gc = gdk_gc_new( window );
244 gdk_gc_set_exposures( wxGCPool[wxGCPoolSize].m_gc, FALSE );
245 wxGCPool[wxGCPoolSize].m_type = type;
ab9d0a8c
WS
246 wxGCPool[wxGCPoolSize].m_used = true;
247
696f36b7
JS
248 // Set new value of pool size.
249 wxGCPoolSize += GC_POOL_ALLOC_SIZE;
ab9d0a8c 250
696f36b7
JS
251 // Return newly allocated entry.
252 return wxGCPool[wxGCPoolSize-GC_POOL_ALLOC_SIZE].m_gc;
253 }
ab9d0a8c 254
696f36b7 255 // The realloc failed. Fall through to error.
3d2d8da1 256 wxFAIL_MSG( wxT("No GC available") );
5f170f33 257
3d2d8da1
RR
258 return (GdkGC*) NULL;
259}
260
261static void wxFreePoolGC( GdkGC *gc )
262{
696f36b7 263 for (int i = 0; i < wxGCPoolSize; i++)
3d2d8da1
RR
264 {
265 if (wxGCPool[i].m_gc == gc)
266 {
ab9d0a8c 267 wxGCPool[i].m_used = false;
3d2d8da1
RR
268 return;
269 }
270 }
5f170f33 271
3d2d8da1
RR
272 wxFAIL_MSG( wxT("Wrong GC") );
273}
274
c801d85f 275//-----------------------------------------------------------------------------
ec758a20 276// wxWindowDC
c801d85f
KB
277//-----------------------------------------------------------------------------
278
b0e0d661 279IMPLEMENT_DYNAMIC_CLASS(wxWindowDC, wxDC)
c801d85f 280
4bc67cc5 281wxWindowDC::wxWindowDC()
c801d85f 282{
265898fd
RR
283 m_penGC = (GdkGC *) NULL;
284 m_brushGC = (GdkGC *) NULL;
285 m_textGC = (GdkGC *) NULL;
286 m_bgGC = (GdkGC *) NULL;
287 m_cmap = (GdkColormap *) NULL;
ab9d0a8c
WS
288 m_isMemDC = false;
289 m_isScreenDC = false;
bbbbe360 290 m_owner = (wxWindow *)NULL;
8943b403
OK
291#ifdef __WXGTK20__
292 m_context = (PangoContext *)NULL;
cfcc3932 293 m_layout = (PangoLayout *)NULL;
8943b403
OK
294 m_fontdesc = (PangoFontDescription *)NULL;
295#endif
903f689b 296}
c801d85f 297
ec758a20 298wxWindowDC::wxWindowDC( wxWindow *window )
c801d85f 299{
3cd0b8c5
RR
300 wxASSERT_MSG( window, wxT("DC needs a window") );
301
265898fd
RR
302 m_penGC = (GdkGC *) NULL;
303 m_brushGC = (GdkGC *) NULL;
304 m_textGC = (GdkGC *) NULL;
305 m_bgGC = (GdkGC *) NULL;
306 m_cmap = (GdkColormap *) NULL;
bbbbe360 307 m_owner = (wxWindow *)NULL;
ab9d0a8c
WS
308 m_isMemDC = false;
309 m_isScreenDC = false;
3b245d60 310 m_font = window->GetFont();
7d5af6fa 311
a2053b27 312 GtkWidget *widget = window->m_wxwindow;
7d5af6fa 313
cfcc3932 314 // Some controls don't have m_wxwindow - like wxStaticBox, but the user
b7f1f77f 315 // code should still be able to create wxClientDCs for them, so we will
cfcc3932 316 // use the parent window here then.
b7f1f77f
VZ
317 if ( !widget )
318 {
319 window = window->GetParent();
320 widget = window->m_wxwindow;
321 }
322
223d09f6 323 wxASSERT_MSG( widget, wxT("DC needs a widget") );
7d5af6fa 324
8943b403 325#ifdef __WXGTK20__
2b5f62a0 326 m_context = window->GtkGetPangoDefaultContext();
cfcc3932
RR
327 m_layout = pango_layout_new( m_context );
328 m_fontdesc = pango_font_description_copy( widget->style->font_desc );
8943b403
OK
329#endif
330
da048e3d
RR
331 GtkPizza *pizza = GTK_PIZZA( widget );
332 m_window = pizza->bin_window;
7d5af6fa 333
cfcc3932 334 // Window not realized ?
1e133b7d
RR
335 if (!m_window)
336 {
cfcc3932 337 // Don't report problems as per MSW.
ab9d0a8c 338 m_ok = true;
7d5af6fa
VZ
339
340 return;
1e133b7d 341 }
7d5af6fa 342
b7f1f77f 343 m_cmap = gtk_widget_get_colormap( widget ? widget : window->m_widget );
7d5af6fa 344
265898fd 345 SetUpDC();
bbbbe360
RR
346
347 /* this must be done after SetUpDC, bacause SetUpDC calls the
348 repective SetBrush, SetPen, SetBackground etc functions
349 to set up the DC. SetBackground call m_owner->SetBackground
350 and this might not be desired as the standard dc background
351 is white whereas a window might assume gray to be the
352 standard (as e.g. wxStatusBar) */
7d5af6fa 353
bbbbe360 354 m_owner = window;
903f689b 355}
c801d85f 356
4bc67cc5 357wxWindowDC::~wxWindowDC()
c801d85f 358{
265898fd 359 Destroy();
ab9d0a8c 360
cfcc3932
RR
361#ifdef __WXGTK20__
362 if (m_layout)
363 g_object_unref( G_OBJECT( m_layout ) );
364 if (m_fontdesc)
365 pango_font_description_free( m_fontdesc );
366#endif
903f689b 367}
c801d85f 368
809934d2
RR
369void wxWindowDC::SetUpDC()
370{
ab9d0a8c 371 m_ok = true;
5f170f33 372
809934d2 373 wxASSERT_MSG( !m_penGC, wxT("GCs already created") );
5f170f33 374
f6bcfd97
BP
375 if (m_isScreenDC)
376 {
377 m_penGC = wxGetPoolGC( m_window, wxPEN_SCREEN );
378 m_brushGC = wxGetPoolGC( m_window, wxBRUSH_SCREEN );
379 m_textGC = wxGetPoolGC( m_window, wxTEXT_SCREEN );
380 m_bgGC = wxGetPoolGC( m_window, wxBG_SCREEN );
381 }
382 else
809934d2
RR
383 if (m_isMemDC && (((wxMemoryDC*)this)->m_selected.GetDepth() == 1))
384 {
385 m_penGC = wxGetPoolGC( m_window, wxPEN_MONO );
386 m_brushGC = wxGetPoolGC( m_window, wxBRUSH_MONO );
387 m_textGC = wxGetPoolGC( m_window, wxTEXT_MONO );
388 m_bgGC = wxGetPoolGC( m_window, wxBG_MONO );
389 }
390 else
391 {
392 m_penGC = wxGetPoolGC( m_window, wxPEN_COLOUR );
393 m_brushGC = wxGetPoolGC( m_window, wxBRUSH_COLOUR );
394 m_textGC = wxGetPoolGC( m_window, wxTEXT_COLOUR );
395 m_bgGC = wxGetPoolGC( m_window, wxBG_COLOUR );
396 }
397
398 /* background colour */
399 m_backgroundBrush = *wxWHITE_BRUSH;
400 m_backgroundBrush.GetColour().CalcPixel( m_cmap );
401 GdkColor *bg_col = m_backgroundBrush.GetColour().GetColor();
402
403 /* m_textGC */
404 m_textForegroundColour.CalcPixel( m_cmap );
405 gdk_gc_set_foreground( m_textGC, m_textForegroundColour.GetColor() );
406
407 m_textBackgroundColour.CalcPixel( m_cmap );
408 gdk_gc_set_background( m_textGC, m_textBackgroundColour.GetColor() );
409
410 gdk_gc_set_fill( m_textGC, GDK_SOLID );
411
412 /* m_penGC */
413 m_pen.GetColour().CalcPixel( m_cmap );
414 gdk_gc_set_foreground( m_penGC, m_pen.GetColour().GetColor() );
415 gdk_gc_set_background( m_penGC, bg_col );
5f170f33 416
809934d2 417 gdk_gc_set_line_attributes( m_penGC, 0, GDK_LINE_SOLID, GDK_CAP_NOT_LAST, GDK_JOIN_ROUND );
5f170f33 418
809934d2
RR
419 /* m_brushGC */
420 m_brush.GetColour().CalcPixel( m_cmap );
421 gdk_gc_set_foreground( m_brushGC, m_brush.GetColour().GetColor() );
422 gdk_gc_set_background( m_brushGC, bg_col );
5f170f33 423
809934d2 424 gdk_gc_set_fill( m_brushGC, GDK_SOLID );
5f170f33 425
809934d2
RR
426 /* m_bgGC */
427 gdk_gc_set_background( m_bgGC, bg_col );
428 gdk_gc_set_foreground( m_bgGC, bg_col );
429
430 gdk_gc_set_fill( m_bgGC, GDK_SOLID );
5f170f33 431
809934d2
RR
432 /* ROPs */
433 gdk_gc_set_function( m_textGC, GDK_COPY );
434 gdk_gc_set_function( m_brushGC, GDK_COPY );
435 gdk_gc_set_function( m_penGC, GDK_COPY );
5f170f33 436
809934d2
RR
437 /* clipping */
438 gdk_gc_set_clip_rectangle( m_penGC, (GdkRectangle *) NULL );
439 gdk_gc_set_clip_rectangle( m_brushGC, (GdkRectangle *) NULL );
440 gdk_gc_set_clip_rectangle( m_textGC, (GdkRectangle *) NULL );
441 gdk_gc_set_clip_rectangle( m_bgGC, (GdkRectangle *) NULL );
442
443 if (!hatch_bitmap)
444 {
445 hatch_bitmap = hatches;
446 hatch_bitmap[0] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, bdiag_bits, bdiag_width, bdiag_height );
447 hatch_bitmap[1] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, cdiag_bits, cdiag_width, cdiag_height );
448 hatch_bitmap[2] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, fdiag_bits, fdiag_width, fdiag_height );
449 hatch_bitmap[3] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, cross_bits, cross_width, cross_height );
450 hatch_bitmap[4] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, horiz_bits, horiz_width, horiz_height );
451 hatch_bitmap[5] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, verti_bits, verti_width, verti_height );
452 }
453}
454
376aa62a
VZ
455void wxWindowDC::DoGetSize( int* width, int* height ) const
456{
457 wxCHECK_RET( m_owner, _T("GetSize() doesn't work without window") );
458
459 m_owner->GetSize(width, height);
460}
461
ab9d0a8c 462extern bool wxDoFloodFill(wxDC *dc, wxCoord x, wxCoord y,
06cf7c08 463 const wxColour & col, int style);
b1699cd3 464
387ebd3e 465bool wxWindowDC::DoFloodFill(wxCoord x, wxCoord y,
06cf7c08
VS
466 const wxColour& col, int style)
467{
387ebd3e 468 return wxDoFloodFill(this, x, y, col, style);
903f689b 469}
c801d85f 470
dc1efb1d 471bool wxWindowDC::DoGetPixel( wxCoord x1, wxCoord y1, wxColour *col ) const
c801d85f 472{
dc1efb1d
JS
473 // Generic (and therefore rather inefficient) method.
474 // Could be improved.
475 wxMemoryDC memdc;
476 wxBitmap bitmap(1, 1);
477 memdc.SelectObject(bitmap);
478 memdc.Blit(0, 0, 1, 1, (wxDC*) this, x1, y1);
479 memdc.SelectObject(wxNullBitmap);
c2fa61e8 480
368d59f0 481 wxImage image = bitmap.ConvertToImage();
dc1efb1d 482 col->Set(image.GetRed(0, 0), image.GetGreen(0, 0), image.GetBlue(0, 0));
ab9d0a8c 483 return true;
903f689b 484}
c801d85f 485
72cdf4c9 486void wxWindowDC::DoDrawLine( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2 )
c801d85f 487{
223d09f6 488 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 489
265898fd
RR
490 if (m_pen.GetStyle() != wxTRANSPARENT)
491 {
6db90681
RR
492 if (m_window)
493 gdk_draw_line( m_window, m_penGC, XLOG2DEV(x1), YLOG2DEV(y1), XLOG2DEV(x2), YLOG2DEV(y2) );
7d5af6fa 494
ed880dd4
RR
495 CalcBoundingBox(x1, y1);
496 CalcBoundingBox(x2, y2);
265898fd 497 }
903f689b 498}
c801d85f 499
72cdf4c9 500void wxWindowDC::DoCrossHair( wxCoord x, wxCoord y )
c801d85f 501{
223d09f6 502 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 503
265898fd
RR
504 if (m_pen.GetStyle() != wxTRANSPARENT)
505 {
506 int w = 0;
507 int h = 0;
508 GetSize( &w, &h );
72cdf4c9
VZ
509 wxCoord xx = XLOG2DEV(x);
510 wxCoord yy = YLOG2DEV(y);
6db90681 511 if (m_window)
7d5af6fa 512 {
6db90681
RR
513 gdk_draw_line( m_window, m_penGC, 0, yy, XLOG2DEVREL(w), yy );
514 gdk_draw_line( m_window, m_penGC, xx, 0, xx, YLOG2DEVREL(h) );
7d5af6fa 515 }
265898fd 516 }
903f689b 517}
c801d85f 518
72cdf4c9
VZ
519void wxWindowDC::DoDrawArc( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2,
520 wxCoord xc, wxCoord yc )
c801d85f 521{
223d09f6 522 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 523
72cdf4c9
VZ
524 wxCoord xx1 = XLOG2DEV(x1);
525 wxCoord yy1 = YLOG2DEV(y1);
526 wxCoord xx2 = XLOG2DEV(x2);
527 wxCoord yy2 = YLOG2DEV(y2);
528 wxCoord xxc = XLOG2DEV(xc);
529 wxCoord yyc = YLOG2DEV(yc);
7d5af6fa 530 double dx = xx1 - xxc;
265898fd 531 double dy = yy1 - yyc;
de87c353 532 double radius = sqrt((double)(dx*dx+dy*dy));
72cdf4c9 533 wxCoord r = (wxCoord)radius;
265898fd
RR
534 double radius1, radius2;
535
7d5af6fa 536 if (xx1 == xx2 && yy1 == yy2)
265898fd
RR
537 {
538 radius1 = 0.0;
539 radius2 = 360.0;
7d5af6fa 540 }
c77a6796 541 else if ( wxIsNullDouble(radius) )
265898fd 542 {
c77a6796
VZ
543 radius1 =
544 radius2 = 0.0;
7d5af6fa
VZ
545 }
546 else
265898fd
RR
547 {
548 radius1 = (xx1 - xxc == 0) ?
b0e0d661
VZ
549 (yy1 - yyc < 0) ? 90.0 : -90.0 :
550 -atan2(double(yy1-yyc), double(xx1-xxc)) * RAD2DEG;
265898fd 551 radius2 = (xx2 - xxc == 0) ?
b0e0d661
VZ
552 (yy2 - yyc < 0) ? 90.0 : -90.0 :
553 -atan2(double(yy2-yyc), double(xx2-xxc)) * RAD2DEG;
265898fd 554 }
72cdf4c9
VZ
555 wxCoord alpha1 = wxCoord(radius1 * 64.0);
556 wxCoord alpha2 = wxCoord((radius2 - radius1) * 64.0);
265898fd
RR
557 while (alpha2 <= 0) alpha2 += 360*64;
558 while (alpha1 > 360*64) alpha1 -= 360*64;
559
6db90681
RR
560 if (m_window)
561 {
562 if (m_brush.GetStyle() != wxTRANSPARENT)
e9f88d04
VZ
563 {
564 if ((m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE) && (m_brush.GetStipple()->GetMask()))
565 {
566 gdk_gc_set_ts_origin( m_textGC,
567 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
568 m_deviceOriginY % m_brush.GetStipple()->GetHeight() );
569 gdk_draw_arc( m_window, m_textGC, TRUE, xxc-r, yyc-r, 2*r,2*r, alpha1, alpha2 );
570 gdk_gc_set_ts_origin( m_textGC, 0, 0 );
571 } else
3ca6a5f0
BP
572 if (IS_15_PIX_HATCH(m_brush.GetStyle()))
573 {
574 gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 15, m_deviceOriginY % 15 );
575 gdk_draw_arc( m_window, m_brushGC, TRUE, xxc-r, yyc-r, 2*r,2*r, alpha1, alpha2 );
576 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
577 } else
578 if (IS_16_PIX_HATCH(m_brush.GetStyle()))
579 {
580 gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 16, m_deviceOriginY % 16 );
581 gdk_draw_arc( m_window, m_brushGC, TRUE, xxc-r, yyc-r, 2*r,2*r, alpha1, alpha2 );
582 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
583 } else
e9f88d04
VZ
584 if (m_brush.GetStyle() == wxSTIPPLE)
585 {
586 gdk_gc_set_ts_origin( m_brushGC,
587 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
588 m_deviceOriginY % m_brush.GetStipple()->GetHeight() );
589 gdk_draw_arc( m_window, m_brushGC, TRUE, xxc-r, yyc-r, 2*r,2*r, alpha1, alpha2 );
590 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
591 }
592 else
593 {
594 gdk_draw_arc( m_window, m_brushGC, TRUE, xxc-r, yyc-r, 2*r,2*r, alpha1, alpha2 );
595 }
596 }
7d5af6fa 597
6db90681 598 if (m_pen.GetStyle() != wxTRANSPARENT)
3d0c4d2e 599 {
6db90681 600 gdk_draw_arc( m_window, m_penGC, FALSE, xxc-r, yyc-r, 2*r,2*r, alpha1, alpha2 );
f469b27c 601
3d0c4d2e
RR
602 gdk_draw_line( m_window, m_penGC, xx1, yy1, xxc, yyc );
603 gdk_draw_line( m_window, m_penGC, xxc, yyc, xx2, yy2 );
604 }
6db90681 605 }
7d5af6fa 606
265898fd
RR
607 CalcBoundingBox (x1, y1);
608 CalcBoundingBox (x2, y2);
903f689b 609}
c801d85f 610
72cdf4c9 611void wxWindowDC::DoDrawEllipticArc( wxCoord x, wxCoord y, wxCoord width, wxCoord height, double sa, double ea )
c801d85f 612{
223d09f6 613 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 614
72cdf4c9
VZ
615 wxCoord xx = XLOG2DEV(x);
616 wxCoord yy = YLOG2DEV(y);
617 wxCoord ww = m_signX * XLOG2DEVREL(width);
618 wxCoord hh = m_signY * YLOG2DEVREL(height);
7d5af6fa 619
265898fd
RR
620 // CMB: handle -ve width and/or height
621 if (ww < 0) { ww = -ww; xx = xx - ww; }
622 if (hh < 0) { hh = -hh; yy = yy - hh; }
7d5af6fa 623
6db90681
RR
624 if (m_window)
625 {
72cdf4c9 626 wxCoord start = wxCoord(sa * 64.0);
3d0c4d2e 627 wxCoord end = wxCoord((ea-sa) * 64.0);
7d5af6fa 628
6db90681 629 if (m_brush.GetStyle() != wxTRANSPARENT)
e9f88d04
VZ
630 {
631 if ((m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE) && (m_brush.GetStipple()->GetMask()))
632 {
633 gdk_gc_set_ts_origin( m_textGC,
634 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
635 m_deviceOriginY % m_brush.GetStipple()->GetHeight() );
636 gdk_draw_arc( m_window, m_textGC, TRUE, xx, yy, ww, hh, start, end );
637 gdk_gc_set_ts_origin( m_textGC, 0, 0 );
638 } else
3ca6a5f0
BP
639 if (IS_15_PIX_HATCH(m_brush.GetStyle()))
640 {
641 gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 15, m_deviceOriginY % 15 );
642 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, start, end );
643 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
644 } else
645 if (IS_16_PIX_HATCH(m_brush.GetStyle()))
646 {
647 gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 16, m_deviceOriginY % 16 );
648 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, start, end );
649 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
650 } else
e9f88d04
VZ
651 if (m_brush.GetStyle() == wxSTIPPLE)
652 {
653 gdk_gc_set_ts_origin( m_brushGC,
654 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
655 m_deviceOriginY % m_brush.GetStipple()->GetHeight() );
656 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, start, end );
657 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
658 }
659 else
660 {
661 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, start, end );
662 }
663 }
7d5af6fa 664
6db90681
RR
665 if (m_pen.GetStyle() != wxTRANSPARENT)
666 gdk_draw_arc( m_window, m_penGC, FALSE, xx, yy, ww, hh, start, end );
667 }
7d5af6fa 668
265898fd
RR
669 CalcBoundingBox (x, y);
670 CalcBoundingBox (x + width, y + height);
903f689b 671}
c801d85f 672
72cdf4c9 673void wxWindowDC::DoDrawPoint( wxCoord x, wxCoord y )
c801d85f 674{
223d09f6 675 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 676
6db90681 677 if ((m_pen.GetStyle() != wxTRANSPARENT) && m_window)
265898fd 678 gdk_draw_point( m_window, m_penGC, XLOG2DEV(x), YLOG2DEV(y) );
7d5af6fa 679
265898fd 680 CalcBoundingBox (x, y);
903f689b 681}
c801d85f 682
72cdf4c9 683void wxWindowDC::DoDrawLines( int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset )
c801d85f 684{
223d09f6 685 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 686
265898fd
RR
687 if (m_pen.GetStyle() == wxTRANSPARENT) return;
688 if (n <= 0) return;
7d5af6fa 689
e90411c2
JS
690 //Check, if scaling is necessary
691 bool doScale(true);
692 long val(10);
693 if (!xoffset)
694 if (!yoffset)
695 if (XLOG2DEV(val)==val)
696 if (YLOG2DEV(val)==val)
697 doScale = false;
698
699 GdkPoint *gpts = NULL;
700
701 if (doScale){
702 gpts = new GdkPoint[n];
6eb37239
VZ
703 if (! gpts)
704 {
705 wxFAIL_MSG( wxT("Cannot allocate PolyLine") );
706 return;
707 }
7d5af6fa 708
ab9d0a8c 709 for (int i = 0; i < n; i++)
265898fd 710 {
72cdf4c9 711 wxCoord x1 = XLOG2DEV(points[i].x + xoffset);
6eb37239 712 wxCoord y1 = YLOG2DEV(points[i].y + yoffset);
7d5af6fa 713
6eb37239 714 CalcBoundingBox( x1 + xoffset, y1 + yoffset );
7d5af6fa 715
6eb37239
VZ
716 gpts[i].x = x1;
717 gpts[i].y = y1;
265898fd 718 }
e90411c2
JS
719 }
720 else {
721 for (int i = 0; i < n; i++) {
722 CalcBoundingBox( points[i].x, points[i].y );
723 }
724
725 //GdkPoint and wxPoint have the same memory allignment, so we can cast one into another
726 gpts = reinterpret_cast<GdkPoint*>(points);
727 }
6eb37239
VZ
728
729 if (m_window)
730 gdk_draw_lines( m_window, m_penGC, gpts, n);
731
e90411c2 732 if (doScale)
6eb37239 733 delete[] gpts;
903f689b 734}
c801d85f 735
72cdf4c9 736void wxWindowDC::DoDrawPolygon( int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset, int WXUNUSED(fillStyle) )
cf7a7e13 737{
223d09f6 738 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 739
4bc67cc5 740 if (n <= 0) return;
7d5af6fa 741
e90411c2
JS
742 //Check, if scaling is necessary
743 bool doScale(true);
744 long val(10);
745 if (!xoffset)
746 if (!yoffset)
747 if (XLOG2DEV(val)==val)
748 if (YLOG2DEV(val)==val){
749 doScale = false;
750 }
751
752 GdkPoint *gdkpoints = NULL;
753
754 if (doScale){
755 gdkpoints = new GdkPoint[n+1]; //FIXME: Why the "+1"
756
265898fd
RR
757 int i;
758 for (i = 0 ; i < n ; i++)
759 {
760 gdkpoints[i].x = XLOG2DEV(points[i].x + xoffset);
761 gdkpoints[i].y = YLOG2DEV(points[i].y + yoffset);
7d5af6fa 762
265898fd
RR
763 CalcBoundingBox( points[i].x + xoffset, points[i].y + yoffset );
764 }
e90411c2
JS
765 }
766 else {
767 int i(0);
768 for (; i < n ; ++i) {
769 CalcBoundingBox( points[i].x, points[i].y );
770 }
771 //GdkPoint and wxPoint have the same memory allignment, so we can cast one into another
772 gdkpoints = reinterpret_cast<GdkPoint*> (points);
773 }
7d5af6fa 774
de2d2cdc 775 if (m_window)
72174350 776 {
e90411c2
JS
777 //I think wxSOLID is the most often used style (it is for me),
778 //so I put it in front of the if ... ifelse's
779 if (m_brush.GetStyle() == wxSOLID)
780 {
781 gdk_draw_polygon( m_window, m_brushGC, TRUE, gdkpoints, n );
782 }else
e1208c31 783 if (m_brush.GetStyle() != wxTRANSPARENT)
72174350 784 {
e1208c31
RR
785 if ((m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE) && (m_brush.GetStipple()->GetMask()))
786 {
5f170f33
VZ
787 gdk_gc_set_ts_origin( m_textGC,
788 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
e1208c31
RR
789 m_deviceOriginY % m_brush.GetStipple()->GetHeight() );
790 gdk_draw_polygon( m_window, m_textGC, TRUE, gdkpoints, n );
791 gdk_gc_set_ts_origin( m_textGC, 0, 0 );
792 } else
3ca6a5f0
BP
793 if (IS_15_PIX_HATCH(m_brush.GetStyle()))
794 {
795 gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 15, m_deviceOriginY % 15 );
796 gdk_draw_polygon( m_window, m_brushGC, TRUE, gdkpoints, n );
797 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
798 } else
799 if (IS_16_PIX_HATCH(m_brush.GetStyle()))
800 {
801 gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 16, m_deviceOriginY % 16 );
802 gdk_draw_polygon( m_window, m_brushGC, TRUE, gdkpoints, n );
803 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
804 } else
e1208c31
RR
805 if (m_brush.GetStyle() == wxSTIPPLE)
806 {
5f170f33
VZ
807 gdk_gc_set_ts_origin( m_brushGC,
808 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
e1208c31
RR
809 m_deviceOriginY % m_brush.GetStipple()->GetHeight() );
810 gdk_draw_polygon( m_window, m_brushGC, TRUE, gdkpoints, n );
811 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
812 }
813 else
814 {
815 gdk_draw_polygon( m_window, m_brushGC, TRUE, gdkpoints, n );
816 }
72174350 817 }
7d5af6fa 818
e1208c31 819 if (m_pen.GetStyle() != wxTRANSPARENT)
b0e0d661 820 {
bb56b0a8 821/*
e1208c31
RR
822 for (i = 0 ; i < n ; i++)
823 {
824 gdk_draw_line( m_window, m_penGC,
825 gdkpoints[i%n].x,
826 gdkpoints[i%n].y,
827 gdkpoints[(i+1)%n].x,
828 gdkpoints[(i+1)%n].y);
829 }
bb56b0a8
JS
830*/
831 gdk_draw_polygon( m_window, m_penGC, FALSE, gdkpoints, n );
ab9d0a8c 832
265898fd 833 }
6db90681 834 }
7d5af6fa 835
e90411c2 836 if (doScale)
265898fd 837 delete[] gdkpoints;
903f689b 838}
c801d85f 839
72cdf4c9 840void wxWindowDC::DoDrawRectangle( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
c801d85f 841{
223d09f6 842 wxCHECK_RET( Ok(), wxT("invalid window dc") );
c801d85f 843
72cdf4c9
VZ
844 wxCoord xx = XLOG2DEV(x);
845 wxCoord yy = YLOG2DEV(y);
846 wxCoord ww = m_signX * XLOG2DEVREL(width);
847 wxCoord hh = m_signY * YLOG2DEVREL(height);
7d5af6fa 848
265898fd
RR
849 // CMB: draw nothing if transformed w or h is 0
850 if (ww == 0 || hh == 0) return;
6f65e337 851
265898fd
RR
852 // CMB: handle -ve width and/or height
853 if (ww < 0) { ww = -ww; xx = xx - ww; }
854 if (hh < 0) { hh = -hh; yy = yy - hh; }
6f65e337 855
6db90681
RR
856 if (m_window)
857 {
e1208c31 858 if (m_brush.GetStyle() != wxTRANSPARENT)
72174350 859 {
e1208c31
RR
860 if ((m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE) && (m_brush.GetStipple()->GetMask()))
861 {
5f170f33
VZ
862 gdk_gc_set_ts_origin( m_textGC,
863 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
e1208c31
RR
864 m_deviceOriginY % m_brush.GetStipple()->GetHeight() );
865 gdk_draw_rectangle( m_window, m_textGC, TRUE, xx, yy, ww, hh );
866 gdk_gc_set_ts_origin( m_textGC, 0, 0 );
3ca6a5f0
BP
867 } else
868 if (IS_15_PIX_HATCH(m_brush.GetStyle()))
869 {
870 gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 15, m_deviceOriginY % 15 );
871 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx, yy, ww, hh );
872 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
873 } else
874 if (IS_16_PIX_HATCH(m_brush.GetStyle()))
875 {
876 gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 16, m_deviceOriginY % 16 );
877 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx, yy, ww, hh );
878 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
879 } else
880 if (m_brush.GetStyle() == wxSTIPPLE)
e1208c31 881 {
5f170f33
VZ
882 gdk_gc_set_ts_origin( m_brushGC,
883 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
e1208c31 884 m_deviceOriginY % m_brush.GetStipple()->GetHeight() );
72174350 885 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx, yy, ww, hh );
e1208c31
RR
886 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
887 }
888 else
889 {
890 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx, yy, ww, hh );
891 }
72174350 892 }
e1208c31
RR
893
894 if (m_pen.GetStyle() != wxTRANSPARENT)
895 gdk_draw_rectangle( m_window, m_penGC, FALSE, xx, yy, ww-1, hh-1 );
6db90681 896 }
7d5af6fa 897
265898fd
RR
898 CalcBoundingBox( x, y );
899 CalcBoundingBox( x + width, y + height );
903f689b 900}
c801d85f 901
72cdf4c9 902void wxWindowDC::DoDrawRoundedRectangle( wxCoord x, wxCoord y, wxCoord width, wxCoord height, double radius )
c801d85f 903{
223d09f6 904 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 905
265898fd 906 if (radius < 0.0) radius = - radius * ((width < height) ? width : height);
7d5af6fa 907
72cdf4c9
VZ
908 wxCoord xx = XLOG2DEV(x);
909 wxCoord yy = YLOG2DEV(y);
910 wxCoord ww = m_signX * XLOG2DEVREL(width);
911 wxCoord hh = m_signY * YLOG2DEVREL(height);
912 wxCoord rr = XLOG2DEVREL((wxCoord)radius);
265898fd
RR
913
914 // CMB: handle -ve width and/or height
915 if (ww < 0) { ww = -ww; xx = xx - ww; }
916 if (hh < 0) { hh = -hh; yy = yy - hh; }
917
918 // CMB: if radius is zero use DrawRectangle() instead to avoid
919 // X drawing errors with small radii
920 if (rr == 0)
921 {
922 DrawRectangle( x, y, width, height );
923 return;
924 }
925
926 // CMB: draw nothing if transformed w or h is 0
927 if (ww == 0 || hh == 0) return;
928
929 // CMB: adjust size if outline is drawn otherwise the result is
930 // 1 pixel too wide and high
931 if (m_pen.GetStyle() != wxTRANSPARENT)
932 {
933 ww--;
934 hh--;
935 }
936
6db90681 937 if (m_window)
265898fd 938 {
6db90681
RR
939 // CMB: ensure dd is not larger than rectangle otherwise we
940 // get an hour glass shape
72cdf4c9 941 wxCoord dd = 2 * rr;
6db90681
RR
942 if (dd > ww) dd = ww;
943 if (dd > hh) dd = hh;
944 rr = dd / 2;
945
946 if (m_brush.GetStyle() != wxTRANSPARENT)
947 {
a56fcaaf
RR
948 if ((m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE) && (m_brush.GetStipple()->GetMask()))
949 {
5f170f33
VZ
950 gdk_gc_set_ts_origin( m_textGC,
951 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
a56fcaaf
RR
952 m_deviceOriginY % m_brush.GetStipple()->GetHeight() );
953 gdk_draw_rectangle( m_window, m_textGC, TRUE, xx+rr, yy, ww-dd+1, hh );
954 gdk_draw_rectangle( m_window, m_textGC, TRUE, xx, yy+rr, ww, hh-dd+1 );
955 gdk_draw_arc( m_window, m_textGC, TRUE, xx, yy, dd, dd, 90*64, 90*64 );
956 gdk_draw_arc( m_window, m_textGC, TRUE, xx+ww-dd, yy, dd, dd, 0, 90*64 );
957 gdk_draw_arc( m_window, m_textGC, TRUE, xx+ww-dd, yy+hh-dd, dd, dd, 270*64, 90*64 );
958 gdk_draw_arc( m_window, m_textGC, TRUE, xx, yy+hh-dd, dd, dd, 180*64, 90*64 );
959 gdk_gc_set_ts_origin( m_textGC, 0, 0 );
3ca6a5f0
BP
960 } else
961 if (IS_15_PIX_HATCH(m_brush.GetStyle()))
962 {
963 gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 15, m_deviceOriginY % 15 );
964 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx+rr, yy, ww-dd+1, hh );
965 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx, yy+rr, ww, hh-dd+1 );
966 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, dd, dd, 90*64, 90*64 );
967 gdk_draw_arc( m_window, m_brushGC, TRUE, xx+ww-dd, yy, dd, dd, 0, 90*64 );
968 gdk_draw_arc( m_window, m_brushGC, TRUE, xx+ww-dd, yy+hh-dd, dd, dd, 270*64, 90*64 );
969 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy+hh-dd, dd, dd, 180*64, 90*64 );
970 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
971 } else
972 if (IS_16_PIX_HATCH(m_brush.GetStyle()))
973 {
974 gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 16, m_deviceOriginY % 16 );
975 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx+rr, yy, ww-dd+1, hh );
976 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx, yy+rr, ww, hh-dd+1 );
977 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, dd, dd, 90*64, 90*64 );
978 gdk_draw_arc( m_window, m_brushGC, TRUE, xx+ww-dd, yy, dd, dd, 0, 90*64 );
979 gdk_draw_arc( m_window, m_brushGC, TRUE, xx+ww-dd, yy+hh-dd, dd, dd, 270*64, 90*64 );
980 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy+hh-dd, dd, dd, 180*64, 90*64 );
981 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
982 } else
983 if (m_brush.GetStyle() == wxSTIPPLE)
a56fcaaf 984 {
5f170f33
VZ
985 gdk_gc_set_ts_origin( m_brushGC,
986 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
a56fcaaf
RR
987 m_deviceOriginY % m_brush.GetStipple()->GetHeight() );
988 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx+rr, yy, ww-dd+1, hh );
989 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx, yy+rr, ww, hh-dd+1 );
990 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, dd, dd, 90*64, 90*64 );
991 gdk_draw_arc( m_window, m_brushGC, TRUE, xx+ww-dd, yy, dd, dd, 0, 90*64 );
992 gdk_draw_arc( m_window, m_brushGC, TRUE, xx+ww-dd, yy+hh-dd, dd, dd, 270*64, 90*64 );
993 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy+hh-dd, dd, dd, 180*64, 90*64 );
994 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
995 }
996 else
997 {
998 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx+rr, yy, ww-dd+1, hh );
999 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx, yy+rr, ww, hh-dd+1 );
1000 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, dd, dd, 90*64, 90*64 );
1001 gdk_draw_arc( m_window, m_brushGC, TRUE, xx+ww-dd, yy, dd, dd, 0, 90*64 );
1002 gdk_draw_arc( m_window, m_brushGC, TRUE, xx+ww-dd, yy+hh-dd, dd, dd, 270*64, 90*64 );
1003 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy+hh-dd, dd, dd, 180*64, 90*64 );
1004 }
6db90681 1005 }
7d5af6fa 1006
6db90681 1007 if (m_pen.GetStyle() != wxTRANSPARENT)
7d5af6fa 1008 {
3ca6a5f0
BP
1009 gdk_draw_line( m_window, m_penGC, xx+rr+1, yy, xx+ww-rr, yy );
1010 gdk_draw_line( m_window, m_penGC, xx+rr+1, yy+hh, xx+ww-rr, yy+hh );
1011 gdk_draw_line( m_window, m_penGC, xx, yy+rr+1, xx, yy+hh-rr );
1012 gdk_draw_line( m_window, m_penGC, xx+ww, yy+rr+1, xx+ww, yy+hh-rr );
6db90681
RR
1013 gdk_draw_arc( m_window, m_penGC, FALSE, xx, yy, dd, dd, 90*64, 90*64 );
1014 gdk_draw_arc( m_window, m_penGC, FALSE, xx+ww-dd, yy, dd, dd, 0, 90*64 );
1015 gdk_draw_arc( m_window, m_penGC, FALSE, xx+ww-dd, yy+hh-dd, dd, dd, 270*64, 90*64 );
1016 gdk_draw_arc( m_window, m_penGC, FALSE, xx, yy+hh-dd, dd, dd, 180*64, 90*64 );
7d5af6fa 1017 }
265898fd 1018 }
7d5af6fa 1019
265898fd
RR
1020 // this ignores the radius
1021 CalcBoundingBox( x, y );
1022 CalcBoundingBox( x + width, y + height );
903f689b 1023}
c801d85f 1024
72cdf4c9 1025void wxWindowDC::DoDrawEllipse( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
c801d85f 1026{
223d09f6 1027 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1028
72cdf4c9
VZ
1029 wxCoord xx = XLOG2DEV(x);
1030 wxCoord yy = YLOG2DEV(y);
1031 wxCoord ww = m_signX * XLOG2DEVREL(width);
1032 wxCoord hh = m_signY * YLOG2DEVREL(height);
6f65e337 1033
265898fd
RR
1034 // CMB: handle -ve width and/or height
1035 if (ww < 0) { ww = -ww; xx = xx - ww; }
1036 if (hh < 0) { hh = -hh; yy = yy - hh; }
7d5af6fa 1037
6db90681
RR
1038 if (m_window)
1039 {
1040 if (m_brush.GetStyle() != wxTRANSPARENT)
a56fcaaf
RR
1041 {
1042 if ((m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE) && (m_brush.GetStipple()->GetMask()))
1043 {
5f170f33
VZ
1044 gdk_gc_set_ts_origin( m_textGC,
1045 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
a56fcaaf
RR
1046 m_deviceOriginY % m_brush.GetStipple()->GetHeight() );
1047 gdk_draw_arc( m_window, m_textGC, TRUE, xx, yy, ww, hh, 0, 360*64 );
1048 gdk_gc_set_ts_origin( m_textGC, 0, 0 );
3ca6a5f0
BP
1049 } else
1050 if (IS_15_PIX_HATCH(m_brush.GetStyle()))
1051 {
1052 gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 15, m_deviceOriginY % 15 );
1053 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, 0, 360*64 );
1054 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
1055 } else
1056 if (IS_16_PIX_HATCH(m_brush.GetStyle()))
1057 {
1058 gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 16, m_deviceOriginY % 16 );
1059 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, 0, 360*64 );
1060 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
1061 } else
1062 if (m_brush.GetStyle() == wxSTIPPLE)
a56fcaaf 1063 {
5f170f33
VZ
1064 gdk_gc_set_ts_origin( m_brushGC,
1065 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
a56fcaaf
RR
1066 m_deviceOriginY % m_brush.GetStipple()->GetHeight() );
1067 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, 0, 360*64 );
1068 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
1069 }
1070 else
1071 {
1072 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, 0, 360*64 );
1073 }
1074 }
7d5af6fa 1075
6db90681
RR
1076 if (m_pen.GetStyle() != wxTRANSPARENT)
1077 gdk_draw_arc( m_window, m_penGC, FALSE, xx, yy, ww, hh, 0, 360*64 );
1078 }
7d5af6fa 1079
44856297 1080 CalcBoundingBox( x, y );
265898fd 1081 CalcBoundingBox( x + width, y + height );
903f689b 1082}
c801d85f 1083
72cdf4c9 1084void wxWindowDC::DoDrawIcon( const wxIcon &icon, wxCoord x, wxCoord y )
c801d85f 1085{
b0e0d661 1086 // VZ: egcs 1.0.3 refuses to compile this without cast, no idea why
ab9d0a8c 1087 DoDrawBitmap( (const wxBitmap&)icon, x, y, true );
903f689b 1088}
c801d85f 1089
b0e0d661 1090void wxWindowDC::DoDrawBitmap( const wxBitmap &bitmap,
72cdf4c9 1091 wxCoord x, wxCoord y,
b0e0d661 1092 bool useMask )
4bc67cc5 1093{
223d09f6 1094 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1095
223d09f6 1096 wxCHECK_RET( bitmap.Ok(), wxT("invalid bitmap") );
7d5af6fa 1097
cf214c35 1098 bool is_mono = (bitmap.GetBitmap() != NULL);
82ea63e6 1099
d90c9596 1100 // scale/translate size and position
265898fd
RR
1101 int xx = XLOG2DEV(x);
1102 int yy = YLOG2DEV(y);
7d5af6fa 1103
4bc67cc5
RR
1104 int w = bitmap.GetWidth();
1105 int h = bitmap.GetHeight();
7d5af6fa 1106
6453876e
RR
1107 CalcBoundingBox( x, y );
1108 CalcBoundingBox( x + w, y + h );
7d5af6fa 1109
6453876e 1110 if (!m_window) return;
7d5af6fa 1111
4bc67cc5
RR
1112 int ww = XLOG2DEVREL(w);
1113 int hh = YLOG2DEVREL(h);
7d5af6fa 1114
d90c9596 1115 // compare to current clipping region
e1208c31 1116 if (!m_currentClippingRegion.IsNull())
3d2d8da1
RR
1117 {
1118 wxRegion tmp( xx,yy,ww,hh );
1119 tmp.Intersect( m_currentClippingRegion );
1120 if (tmp.IsEmpty())
1121 return;
1122 }
5f170f33 1123
ab9d0a8c 1124 // scale bitmap if required
d90c9596 1125 wxBitmap use_bitmap = bitmap;
4bc67cc5 1126 if ((w != ww) || (h != hh))
d90c9596 1127 use_bitmap = use_bitmap.Rescale( 0, 0, ww, hh, ww, hh );
ab9d0a8c 1128
1abedc32
VS
1129#if !GTK_CHECK_VERSION(2,2,0)
1130 // NB: We can't render pixbufs with GTK+ < 2.2, we need to use pixmaps code.
1131 // Pixbufs-based bitmaps with alpha channel don't have a mask, so we
1132 // have to call GetPixmap() here -- it converts the pixbuf into pixmap
1133 // and also creates the mask as a side-effect:
1134 use_bitmap.GetPixmap();
1135#endif
ab9d0a8c 1136
d90c9596 1137 // apply mask if any
463c1fa1 1138 GdkBitmap *mask = (GdkBitmap *) NULL;
4bc67cc5 1139 if (use_bitmap.GetMask()) mask = use_bitmap.GetMask()->GetBitmap();
7d5af6fa 1140
d90c9596 1141 GdkBitmap *new_mask = (GdkBitmap*) NULL;
ab9d0a8c 1142
d90c9596
RR
1143 if (useMask && mask)
1144 {
1145 if (!m_currentClippingRegion.IsNull())
82ea63e6 1146 {
d90c9596
RR
1147 GdkColor col;
1148 new_mask = gdk_pixmap_new( wxGetRootWindow()->window, ww, hh, 1 );
1149 GdkGC *gc = gdk_gc_new( new_mask );
1150 col.pixel = 0;
1151 gdk_gc_set_foreground( gc, &col );
1152 gdk_draw_rectangle( new_mask, gc, TRUE, 0, 0, ww, hh );
1153 col.pixel = 0;
1154 gdk_gc_set_background( gc, &col );
1155 col.pixel = 1;
1156 gdk_gc_set_foreground( gc, &col );
1157 gdk_gc_set_clip_region( gc, m_currentClippingRegion.GetRegion() );
1158 gdk_gc_set_clip_origin( gc, -xx, -yy );
1159 gdk_gc_set_fill( gc, GDK_OPAQUE_STIPPLED );
1160 gdk_gc_set_stipple( gc, mask );
1161 gdk_draw_rectangle( new_mask, gc, TRUE, 0, 0, ww, hh );
1162 gdk_gc_unref( gc );
1163 }
ab9d0a8c 1164
d90c9596
RR
1165 if (is_mono)
1166 {
1167 if (new_mask)
1168 gdk_gc_set_clip_mask( m_textGC, new_mask );
3d2d8da1 1169 else
d90c9596
RR
1170 gdk_gc_set_clip_mask( m_textGC, mask );
1171 gdk_gc_set_clip_origin( m_textGC, xx, yy );
1172 }
1173 else
1174 {
3d2d8da1 1175 if (new_mask)
d90c9596
RR
1176 gdk_gc_set_clip_mask( m_penGC, new_mask );
1177 else
1178 gdk_gc_set_clip_mask( m_penGC, mask );
1179 gdk_gc_set_clip_origin( m_penGC, xx, yy );
b0e0d661 1180 }
d90c9596 1181 }
7d5af6fa 1182
d90c9596
RR
1183 // Draw XPixmap or XBitmap, depending on what the wxBitmap contains. For
1184 // drawing a mono-bitmap (XBitmap) we use the current text GC
82ea63e6 1185 if (is_mono)
d90c9596
RR
1186 {
1187#ifdef __WXGTK20__
4e115ed2
VZ
1188 GdkPixmap *bitmap2 = gdk_pixmap_new( wxGetRootWindow()->window, ww, hh, -1 );
1189 GdkGC *gc = gdk_gc_new( bitmap2 );
d90c9596
RR
1190 gdk_gc_set_foreground( gc, m_textForegroundColour.GetColor() );
1191 gdk_gc_set_background( gc, m_textBackgroundColour.GetColor() );
4e115ed2 1192 gdk_wx_draw_bitmap( bitmap2, gc, use_bitmap.GetBitmap(), 0, 0, 0, 0, -1, -1 );
ab9d0a8c 1193
4e115ed2 1194 gdk_draw_drawable( m_window, m_textGC, bitmap2, 0, 0, xx, yy, -1, -1 );
ab9d0a8c 1195
4e115ed2 1196 gdk_bitmap_unref( bitmap2 );
d90c9596
RR
1197 gdk_gc_unref( gc );
1198#else
f6bcfd97 1199 gdk_wx_draw_bitmap( m_window, m_textGC, use_bitmap.GetBitmap(), 0, 0, xx, yy, -1, -1 );
d90c9596
RR
1200#endif
1201 }
82ea63e6 1202 else
d90c9596 1203 {
feac7937 1204#if GTK_CHECK_VERSION(2,2,0)
cc35003a 1205 if (!gtk_check_version(2,2,0) && use_bitmap.HasPixbuf())
feac7937
VS
1206 {
1207 gdk_draw_pixbuf(m_window, m_penGC,
1208 use_bitmap.GetPixbuf(),
1209 0, 0, xx, yy, -1, -1,
1210 GDK_RGB_DITHER_NORMAL, xx, yy);
1211 }
1212 else
1213#endif
1214 {
1215 gdk_draw_pixmap(m_window, m_penGC,
1216 use_bitmap.GetPixmap(),
1217 0, 0, xx, yy, -1, -1);
1218 }
d90c9596 1219 }
72174350 1220
d90c9596 1221 // remove mask again if any
7d5af6fa 1222 if (useMask && mask)
463c1fa1 1223 {
82ea63e6
RR
1224 if (is_mono)
1225 {
1226 gdk_gc_set_clip_mask( m_textGC, (GdkBitmap *) NULL );
1227 gdk_gc_set_clip_origin( m_textGC, 0, 0 );
e1208c31 1228 if (!m_currentClippingRegion.IsNull())
3d2d8da1 1229 gdk_gc_set_clip_region( m_textGC, m_currentClippingRegion.GetRegion() );
82ea63e6
RR
1230 }
1231 else
1232 {
1233 gdk_gc_set_clip_mask( m_penGC, (GdkBitmap *) NULL );
1234 gdk_gc_set_clip_origin( m_penGC, 0, 0 );
e1208c31 1235 if (!m_currentClippingRegion.IsNull())
3d2d8da1 1236 gdk_gc_set_clip_region( m_penGC, m_currentClippingRegion.GetRegion() );
82ea63e6 1237 }
463c1fa1 1238 }
ab9d0a8c 1239
d90c9596
RR
1240 if (new_mask)
1241 gdk_bitmap_unref( new_mask );
463c1fa1
RR
1242}
1243
1e6feb95
VZ
1244bool wxWindowDC::DoBlit( wxCoord xdest, wxCoord ydest,
1245 wxCoord width, wxCoord height,
1246 wxDC *source,
1247 wxCoord xsrc, wxCoord ysrc,
1248 int logical_func,
0cbff120
JS
1249 bool useMask,
1250 wxCoord xsrcMask, wxCoord ysrcMask )
c801d85f 1251{
ab9d0a8c 1252 wxCHECK_MSG( Ok(), false, wxT("invalid window dc") );
7d5af6fa 1253
ab9d0a8c 1254 wxCHECK_MSG( source, false, wxT("invalid source dc") );
7d5af6fa 1255
ab9d0a8c 1256 if (!m_window) return false;
7d5af6fa 1257
1e6feb95 1258 // transform the source DC coords to the device ones
06201c35
RR
1259 xsrc = source->XLOG2DEV(xsrc);
1260 ysrc = source->YLOG2DEV(ysrc);
1e6feb95 1261
6e13c196
RR
1262 wxClientDC *srcDC = (wxClientDC*)source;
1263 wxMemoryDC *memDC = (wxMemoryDC*)source;
7d5af6fa 1264
ab9d0a8c
WS
1265 bool use_bitmap_method = false;
1266 bool is_mono = false;
7d5af6fa 1267
0cbff120
JS
1268 if (xsrcMask == -1 && ysrcMask == -1)
1269 {
d90c9596
RR
1270 xsrcMask = xsrc;
1271 ysrcMask = ysrc;
0cbff120
JS
1272 }
1273
6e13c196
RR
1274 if (srcDC->m_isMemDC)
1275 {
ab9d0a8c 1276 if (!memDC->m_selected.Ok()) return false;
7d5af6fa 1277
d90c9596
RR
1278 is_mono = (memDC->m_selected.GetDepth() == 1);
1279
1280 // we use the "XCopyArea" way to copy a memory dc into
1281 // a different window if the memory dc BOTH
1282 // a) doesn't have any mask or its mask isn't used
1283 // b) it is clipped
1284 // c) is not 1-bit
7d5af6fa 1285
f234c60c 1286 if (useMask && (memDC->m_selected.GetMask()))
b0e0d661 1287 {
d90c9596
RR
1288 // we HAVE TO use the direct way for memory dcs
1289 // that have mask since the XCopyArea doesn't know
1290 // about masks
ab9d0a8c 1291 use_bitmap_method = true;
b0e0d661 1292 }
d90c9596 1293 else if (is_mono)
b0e0d661 1294 {
d90c9596
RR
1295 // we HAVE TO use the direct way for memory dcs
1296 // that are bitmaps because XCopyArea doesn't cope
1297 // with different bit depths
ab9d0a8c 1298 use_bitmap_method = true;
b0e0d661
VZ
1299 }
1300 else if ((xsrc == 0) && (ysrc == 0) &&
1301 (width == memDC->m_selected.GetWidth()) &&
1302 (height == memDC->m_selected.GetHeight()))
1303 {
d90c9596
RR
1304 // we SHOULD use the direct way if all of the bitmap
1305 // in the memory dc is copied in which case XCopyArea
1306 // wouldn't be able able to boost performace by reducing
1307 // the area to be scaled
ab9d0a8c 1308 use_bitmap_method = true;
b0e0d661
VZ
1309 }
1310 else
1311 {
ab9d0a8c 1312 use_bitmap_method = false;
b0e0d661 1313 }
6e13c196 1314 }
7d5af6fa 1315
265898fd
RR
1316 CalcBoundingBox( xdest, ydest );
1317 CalcBoundingBox( xdest + width, ydest + height );
7d5af6fa 1318
d90c9596 1319 // scale/translate size and position
3d2d8da1
RR
1320 wxCoord xx = XLOG2DEV(xdest);
1321 wxCoord yy = YLOG2DEV(ydest);
1322
1323 wxCoord ww = XLOG2DEVREL(width);
1324 wxCoord hh = YLOG2DEVREL(height);
1325
d90c9596 1326 // compare to current clipping region
e1208c31 1327 if (!m_currentClippingRegion.IsNull())
3d2d8da1
RR
1328 {
1329 wxRegion tmp( xx,yy,ww,hh );
1330 tmp.Intersect( m_currentClippingRegion );
1331 if (tmp.IsEmpty())
ab9d0a8c 1332 return true;
3d2d8da1
RR
1333 }
1334
4bc67cc5
RR
1335 int old_logical_func = m_logicalFunction;
1336 SetLogicalFunction( logical_func );
5f170f33 1337
6e13c196 1338 if (use_bitmap_method)
6f65e337 1339 {
d90c9596 1340 // scale/translate bitmap size
72cdf4c9
VZ
1341 wxCoord bm_width = memDC->m_selected.GetWidth();
1342 wxCoord bm_height = memDC->m_selected.GetHeight();
7d5af6fa 1343
551b5391
RR
1344 // Get clip coords for the bitmap. If we don't
1345 // use wxBitmap::Rescale(), which can clip the
1346 // bitmap, these are the same as the original
1347 // coordinates
1348 wxCoord cx = xx;
1349 wxCoord cy = yy;
1350 wxCoord cw = ww;
1351 wxCoord ch = hh;
ab9d0a8c 1352
d90c9596
RR
1353 // interpret userscale of src too
1354 double xsc,ysc;
1355 memDC->GetUserScale(&xsc,&ysc);
1356 bm_width = (int) (bm_width / xsc);
1357 bm_height = (int) (bm_height / ysc);
1358
72cdf4c9
VZ
1359 wxCoord bm_ww = XLOG2DEVREL( bm_width );
1360 wxCoord bm_hh = YLOG2DEVREL( bm_height );
7d5af6fa 1361
551b5391 1362 // Scale bitmap if required
6e13c196 1363 wxBitmap use_bitmap;
f53df133 1364 if ((memDC->m_selected.GetWidth()!= bm_ww) || ( memDC->m_selected.GetHeight()!= bm_hh))
6e13c196 1365 {
551b5391
RR
1366 // This indicates that the blitting code below will get
1367 // a clipped bitmap and therefore needs to move the origin
1368 // accordingly
1369 wxRegion tmp( xx,yy,ww,hh );
1370 tmp.Intersect( m_currentClippingRegion );
1371 tmp.GetBox(cx,cy,cw,ch);
ab9d0a8c 1372
551b5391
RR
1373 // Scale and clipped bitmap
1374 use_bitmap = memDC->m_selected.Rescale(cx-xx,cy-yy,cw,ch,bm_ww,bm_hh);
6e13c196
RR
1375 }
1376 else
e23d0e95 1377 {
551b5391 1378 // Don't scale bitmap
6e13c196
RR
1379 use_bitmap = memDC->m_selected;
1380 }
7d5af6fa 1381
d90c9596 1382 // apply mask if any
6e13c196
RR
1383 GdkBitmap *mask = (GdkBitmap *) NULL;
1384 if (use_bitmap.GetMask()) mask = use_bitmap.GetMask()->GetBitmap();
7d5af6fa 1385
d90c9596 1386 GdkBitmap *new_mask = (GdkBitmap*) NULL;
ab9d0a8c 1387
7d5af6fa 1388 if (useMask && mask)
6e13c196 1389 {
e1208c31 1390 if (!m_currentClippingRegion.IsNull())
3d2d8da1
RR
1391 {
1392 GdkColor col;
c2fa61e8 1393 new_mask = gdk_pixmap_new( wxGetRootWindow()->window, bm_ww, bm_hh, 1 );
3d2d8da1
RR
1394 GdkGC *gc = gdk_gc_new( new_mask );
1395 col.pixel = 0;
1396 gdk_gc_set_foreground( gc, &col );
b7a49654 1397 gdk_gc_set_ts_origin( gc, -xsrcMask, -ysrcMask);
3d2d8da1
RR
1398 gdk_draw_rectangle( new_mask, gc, TRUE, 0, 0, bm_ww, bm_hh );
1399 col.pixel = 0;
1400 gdk_gc_set_background( gc, &col );
1401 col.pixel = 1;
1402 gdk_gc_set_foreground( gc, &col );
1403 gdk_gc_set_clip_region( gc, m_currentClippingRegion.GetRegion() );
d90c9596
RR
1404 // was: gdk_gc_set_clip_origin( gc, -xx, -yy );
1405 gdk_gc_set_clip_origin( gc, -cx, -cy );
3d2d8da1
RR
1406 gdk_gc_set_fill( gc, GDK_OPAQUE_STIPPLED );
1407 gdk_gc_set_stipple( gc, mask );
1408 gdk_draw_rectangle( new_mask, gc, TRUE, 0, 0, bm_ww, bm_hh );
1409 gdk_gc_unref( gc );
1410 }
d90c9596 1411
82ea63e6
RR
1412 if (is_mono)
1413 {
3d2d8da1 1414 if (new_mask)
b7a49654 1415 {
3d2d8da1 1416 gdk_gc_set_clip_mask( m_textGC, new_mask );
b7a49654
RR
1417 gdk_gc_set_clip_origin( m_textGC, cx, cy );
1418 }
3d2d8da1 1419 else
b7a49654 1420 {
3d2d8da1 1421 gdk_gc_set_clip_mask( m_textGC, mask );
b7a49654 1422 gdk_gc_set_clip_origin( m_textGC, cx-xsrcMask, cy-ysrcMask );
0a164d4c 1423 }
82ea63e6
RR
1424 }
1425 else
6e13c196 1426 {
3d2d8da1 1427 if (new_mask)
b7a49654 1428 {
3d2d8da1 1429 gdk_gc_set_clip_mask( m_penGC, new_mask );
b7a49654
RR
1430 gdk_gc_set_clip_origin( m_penGC, cx, cy );
1431 }
3d2d8da1 1432 else
b7a49654 1433 {
3d2d8da1 1434 gdk_gc_set_clip_mask( m_penGC, mask );
b7a49654 1435 gdk_gc_set_clip_origin( m_penGC, cx-xsrcMask, cy-ysrcMask );
0a164d4c 1436 }
b0e0d661 1437 }
6e13c196 1438 }
7d5af6fa 1439
d90c9596
RR
1440 // Draw XPixmap or XBitmap, depending on what the wxBitmap contains. For
1441 // drawing a mono-bitmap (XBitmap) we use the current text GC
5f170f33 1442
82ea63e6 1443 if (is_mono)
d90c9596
RR
1444 {
1445#ifdef __WXGTK20__
1446 GdkPixmap *bitmap = gdk_pixmap_new( wxGetRootWindow()->window, bm_ww, bm_hh, -1 );
1447 GdkGC *gc = gdk_gc_new( bitmap );
1448 gdk_gc_set_foreground( gc, m_textForegroundColour.GetColor() );
1449 gdk_gc_set_background( gc, m_textBackgroundColour.GetColor() );
1450 gdk_wx_draw_bitmap( bitmap, gc, use_bitmap.GetBitmap(), 0, 0, 0, 0, -1, -1 );
ab9d0a8c 1451
d90c9596 1452 gdk_draw_drawable( m_window, m_textGC, bitmap, xsrc, ysrc, cx, cy, cw, ch );
ab9d0a8c 1453
d90c9596
RR
1454 gdk_bitmap_unref( bitmap );
1455 gdk_gc_unref( gc );
1456#else
1457 // was: gdk_wx_draw_bitmap( m_window, m_textGC, use_bitmap.GetBitmap(), xsrc, ysrc, xx, yy, ww, hh );
1458 gdk_wx_draw_bitmap( m_window, m_textGC, use_bitmap.GetBitmap(), xsrc, ysrc, cx, cy, cw, ch );
1459#endif
1460 }
82ea63e6 1461 else
d90c9596
RR
1462 {
1463 // was: gdk_draw_pixmap( m_window, m_penGC, use_bitmap.GetPixmap(), xsrc, ysrc, xx, yy, ww, hh );
1464 gdk_draw_pixmap( m_window, m_penGC, use_bitmap.GetPixmap(), xsrc, ysrc, cx, cy, cw, ch );
1465 }
82ea63e6 1466
d90c9596 1467 // remove mask again if any
7d5af6fa 1468 if (useMask && mask)
6e13c196 1469 {
82ea63e6
RR
1470 if (is_mono)
1471 {
1472 gdk_gc_set_clip_mask( m_textGC, (GdkBitmap *) NULL );
1473 gdk_gc_set_clip_origin( m_textGC, 0, 0 );
e1208c31 1474 if (!m_currentClippingRegion.IsNull())
3d2d8da1 1475 gdk_gc_set_clip_region( m_textGC, m_currentClippingRegion.GetRegion() );
82ea63e6
RR
1476 }
1477 else
1478 {
1479 gdk_gc_set_clip_mask( m_penGC, (GdkBitmap *) NULL );
1480 gdk_gc_set_clip_origin( m_penGC, 0, 0 );
e1208c31 1481 if (!m_currentClippingRegion.IsNull())
3d2d8da1 1482 gdk_gc_set_clip_region( m_penGC, m_currentClippingRegion.GetRegion() );
82ea63e6 1483 }
265898fd 1484 }
ab9d0a8c 1485
d90c9596
RR
1486 if (new_mask)
1487 gdk_bitmap_unref( new_mask );
6f65e337 1488 }
d90c9596 1489 else // use_bitmap_method
6e13c196 1490 {
bf9848e7 1491 if ((width != ww) || (height != hh))
b0e0d661 1492 {
d90c9596
RR
1493 // get clip coords
1494 wxRegion tmp( xx,yy,ww,hh );
1495 tmp.Intersect( m_currentClippingRegion );
1496 wxCoord cx,cy,cw,ch;
1497 tmp.GetBox(cx,cy,cw,ch);
ab9d0a8c
WS
1498
1499 // rescale bitmap
d90c9596 1500 wxBitmap bitmap = memDC->m_selected.Rescale( cx-xx, cy-yy, cw, ch, ww, hh );
7d5af6fa 1501
d90c9596
RR
1502 // draw scaled bitmap
1503 // was: gdk_draw_pixmap( m_window, m_penGC, bitmap.GetPixmap(), 0, 0, xx, yy, -1, -1 );
1504 gdk_draw_pixmap( m_window, m_penGC, bitmap.GetPixmap(), 0, 0, cx, cy, -1, -1 );
b0e0d661
VZ
1505 }
1506 else
1507 {
ab9d0a8c 1508 // No scaling and not a memory dc with a mask either
993f97ee 1509
d90c9596 1510 // copy including child window contents
a56fcaaf 1511 gdk_gc_set_subwindow( m_penGC, GDK_INCLUDE_INFERIORS );
6e13c196
RR
1512 gdk_window_copy_area( m_window, m_penGC, xx, yy,
1513 srcDC->GetWindow(),
1514 xsrc, ysrc, width, height );
a56fcaaf 1515 gdk_gc_set_subwindow( m_penGC, GDK_CLIP_BY_CHILDREN );
b0e0d661 1516 }
6e13c196 1517 }
c801d85f 1518
4bc67cc5 1519 SetLogicalFunction( old_logical_func );
ab9d0a8c
WS
1520
1521 return true;
903f689b 1522}
c801d85f 1523
72cdf4c9 1524void wxWindowDC::DoDrawText( const wxString &text, wxCoord x, wxCoord y )
c801d85f 1525{
223d09f6 1526 wxCHECK_RET( Ok(), wxT("invalid window dc") );
18a2fa37 1527
6db90681 1528 if (!m_window) return;
ab9d0a8c 1529
2b5f62a0 1530 if (text.empty()) return;
7d5af6fa 1531
2b5f62a0 1532#ifndef __WXGTK20__
265898fd 1533 GdkFont *font = m_font.GetInternalFont( m_scaleY );
6f65e337 1534
a1fffa9f 1535 wxCHECK_RET( font, wxT("invalid font") );
2b5f62a0 1536#endif
a1fffa9f 1537
265898fd
RR
1538 x = XLOG2DEV(x);
1539 y = YLOG2DEV(y);
18a2fa37 1540
2b5f62a0 1541#ifdef __WXGTK20__
cfcc3932 1542 wxCHECK_RET( m_context, wxT("no Pango context") );
61850501 1543 wxCHECK_RET( m_layout, wxT("no Pango layout") );
cfcc3932 1544 wxCHECK_RET( m_fontdesc, wxT("no Pango font description") );
e4da1035 1545
1dbeee57
VS
1546 bool underlined = m_font.Ok() && m_font.GetUnderlined();
1547
fb3ed106 1548#if wxUSE_UNICODE
e4da1035 1549 const wxCharBuffer data = wxConvUTF8.cWC2MB( text );
fb3ed106 1550#else
e4da1035 1551 const wxWCharBuffer wdata = wxConvLocal.cMB2WC( text );
7706daf3
VS
1552 if ( !wdata )
1553 return;
e4da1035 1554 const wxCharBuffer data = wxConvUTF8.cWC2MB( wdata );
fb3ed106 1555#endif
1dbeee57
VS
1556 size_t datalen = strlen((const char*)data);
1557 pango_layout_set_text( m_layout, (const char*) data, datalen);
ab9d0a8c 1558
1dbeee57
VS
1559 if (underlined)
1560 {
1561 PangoAttrList *attrs = pango_attr_list_new();
1562 PangoAttribute *a = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
1563 a->start_index = 0;
1564 a->end_index = datalen;
1565 pango_attr_list_insert(attrs, a);
1566 pango_layout_set_attributes(m_layout, attrs);
1567 pango_attr_list_unref(attrs);
1568 }
e4da1035 1569
76b20467 1570 int w,h;
fa499247
RR
1571
1572 if (fabs(m_scaleY - 1.0) > 0.00001)
e4da1035
RR
1573 {
1574 // If there is a user or actually any scale applied to
1575 // the device context, scale the font.
ab9d0a8c 1576
e4da1035
RR
1577 // scale font description
1578 gint oldSize = pango_font_description_get_size( m_fontdesc );
1579 double size = oldSize;
1580 size = size * m_scaleY;
1581 pango_font_description_set_size( m_fontdesc, (gint)size );
ab9d0a8c 1582
e4da1035
RR
1583 // actually apply scaled font
1584 pango_layout_set_font_description( m_layout, m_fontdesc );
ab9d0a8c 1585
76b20467
VS
1586 pango_layout_get_pixel_size( m_layout, &w, &h );
1587 if ( m_backgroundMode == wxSOLID )
1588 {
1589 gdk_gc_set_foreground(m_textGC, m_textBackgroundColour.GetColor());
1590 gdk_draw_rectangle(m_window, m_textGC, TRUE, x, y, w, h);
1591 gdk_gc_set_foreground(m_textGC, m_textForegroundColour.GetColor());
1592 }
ab9d0a8c 1593
e4da1035
RR
1594 // Draw layout.
1595 gdk_draw_layout( m_window, m_textGC, x, y, m_layout );
ab9d0a8c 1596
e4da1035
RR
1597 // reset unscaled size
1598 pango_font_description_set_size( m_fontdesc, oldSize );
ab9d0a8c 1599
61850501 1600 // actually apply unscaled font
e4da1035
RR
1601 pango_layout_set_font_description( m_layout, m_fontdesc );
1602 }
1603 else
1604 {
76b20467
VS
1605 pango_layout_get_pixel_size( m_layout, &w, &h );
1606 if ( m_backgroundMode == wxSOLID )
1607 {
1608 gdk_gc_set_foreground(m_textGC, m_textBackgroundColour.GetColor());
1609 gdk_draw_rectangle(m_window, m_textGC, TRUE, x, y, w, h);
1610 gdk_gc_set_foreground(m_textGC, m_textForegroundColour.GetColor());
1611 }
1612 // Draw layout.
1613 gdk_draw_layout( m_window, m_textGC, x, y, m_layout );
8943b403 1614 }
1dbeee57
VS
1615
1616 if (underlined)
1617 {
1618 // undo underline attributes setting:
1619 pango_layout_set_attributes(m_layout, NULL);
1620 }
ab9d0a8c 1621
2b5f62a0
VZ
1622 wxCoord width = w;
1623 wxCoord height = h;
ab9d0a8c 1624
9e691f46 1625#else // GTK+ 1.x
8943b403
OK
1626 wxCoord width = gdk_string_width( font, text.mbc_str() );
1627 wxCoord height = font->ascent + font->descent;
2c37aade
VZ
1628
1629 if ( m_backgroundMode == wxSOLID )
265898fd 1630 {
265898fd
RR
1631 gdk_gc_set_foreground( m_textGC, m_textBackgroundColour.GetColor() );
1632 gdk_draw_rectangle( m_window, m_textGC, TRUE, x, y, width, height );
2c37aade 1633 gdk_gc_set_foreground( m_textGC, m_textForegroundColour.GetColor() );
265898fd 1634 }
93c5dd39 1635 gdk_draw_string( m_window, font, m_textGC, x, y + font->ascent, text.mbc_str() );
18a2fa37 1636
bbbbe360
RR
1637 /* CMB 17/7/98: simple underline: ignores scaling and underlying
1638 X font's XA_UNDERLINE_POSITION and XA_UNDERLINE_THICKNESS
1639 properties (see wxXt implementation) */
265898fd
RR
1640 if (m_font.GetUnderlined())
1641 {
13111b2a 1642 wxCoord ul_y = y + font->ascent;
265898fd
RR
1643 if (font->descent > 0) ul_y++;
1644 gdk_draw_line( m_window, m_textGC, x, ul_y, x + width, ul_y);
1645 }
48d011c8 1646#endif // GTK+ 2.0/1.x
7d5af6fa 1647
8943b403
OK
1648 width = wxCoord(width / m_scaleX);
1649 height = wxCoord(height / m_scaleY);
1650 CalcBoundingBox (x + width, y + height);
265898fd 1651 CalcBoundingBox (x, y);
903f689b 1652}
c801d85f 1653
bf47e398
RD
1654
1655// TODO: There is an example of rotating text with GTK2 that would probably be
1656// a better approach here:
1657// http://www.daa.com.au/pipermail/pygtk/2003-April/005052.html
1658
95724b1a
VZ
1659void wxWindowDC::DoDrawRotatedText( const wxString &text, wxCoord x, wxCoord y, double angle )
1660{
c77a6796 1661 if ( wxIsNullDouble(angle) )
95724b1a
VZ
1662 {
1663 DrawText(text, x, y);
1664 return;
1665 }
1666
1667 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1668
1669 if (!m_window) return;
1670
bf47e398
RD
1671 wxCoord w;
1672 wxCoord h;
1673
1674#ifdef __WXGTK20__
bbd006c0 1675 // implement later without GdkFont for GTK 2.0
bf47e398 1676 GetTextExtent(text, &w, &h, NULL,NULL, &m_font);
ab9d0a8c 1677
cfcc3932 1678#else
95724b1a
VZ
1679 GdkFont *font = m_font.GetInternalFont( m_scaleY );
1680
1681 wxCHECK_RET( font, wxT("invalid font") );
1682
9a8c7620 1683 // the size of the text
bf47e398
RD
1684 w = gdk_string_width( font, text.mbc_str() );
1685 h = font->ascent + font->descent;
1686#endif
9a8c7620
VZ
1687 // draw the string normally
1688 wxBitmap src(w, h);
95724b1a
VZ
1689 wxMemoryDC dc;
1690 dc.SelectObject(src);
1691 dc.SetFont(GetFont());
f1c72f0c 1692 dc.SetBackground(*wxBLACK_BRUSH);
95724b1a
VZ
1693 dc.SetBrush(*wxBLACK_BRUSH);
1694 dc.Clear();
f1c72f0c 1695 dc.SetTextForeground( *wxWHITE );
95724b1a 1696 dc.DrawText(text, 0, 0);
9a8c7620 1697 dc.SelectObject(wxNullBitmap);
95724b1a
VZ
1698
1699 // Calculate the size of the rotated bounding box.
9a8c7620
VZ
1700 double rad = DegToRad(angle);
1701 double dx = cos(rad),
1702 dy = sin(rad);
1703
1704 // the rectngle vertices are counted clockwise with the first one being at
1705 // (0, 0) (or, rather, at (x, y))
1706 double x2 = w*dx,
1707 y2 = -w*dy; // y axis points to the bottom, hence minus
1708 double x4 = h*dy,
1709 y4 = h*dx;
1710 double x3 = x4 + x2,
1711 y3 = y4 + y2;
ab9d0a8c 1712
72174350 1713 // calc max and min
9a8c7620
VZ
1714 wxCoord maxX = (wxCoord)(dmax(x2, dmax(x3, x4)) + 0.5),
1715 maxY = (wxCoord)(dmax(y2, dmax(y3, y4)) + 0.5),
1716 minX = (wxCoord)(dmin(x2, dmin(x3, x4)) - 0.5),
1717 minY = (wxCoord)(dmin(y2, dmin(y3, y4)) - 0.5);
1718
72174350 1719
f1c72f0c 1720 wxImage image = src.ConvertToImage();
9a8c7620 1721
f1c72f0c
RR
1722 image.ConvertColourToAlpha( m_textForegroundColour.Red(),
1723 m_textForegroundColour.Green(),
1724 m_textForegroundColour.Blue() );
1725 image = image.Rotate( rad, wxPoint(0,0) );
ab9d0a8c 1726
1d65e535
RR
1727 int i_angle = (int) angle;
1728 i_angle = i_angle % 360;
c2cb80c8
KH
1729 if (i_angle < 0)
1730 i_angle += 360;
1d65e535
RR
1731 int xoffset = 0;
1732 if ((i_angle >= 90.0) && (i_angle < 270.0))
1733 xoffset = image.GetWidth();
1734 int yoffset = 0;
1735 if ((i_angle >= 0.0) && (i_angle < 180.0))
1736 yoffset = image.GetHeight();
ab9d0a8c 1737
1d65e535
RR
1738 if ((i_angle >= 0) && (i_angle < 90))
1739 yoffset -= (int)( cos(rad)*h );
1740 if ((i_angle >= 90) && (i_angle < 180))
ab9d0a8c 1741 xoffset -= (int)( sin(rad)*h );
1d65e535
RR
1742 if ((i_angle >= 180) && (i_angle < 270))
1743 yoffset -= (int)( cos(rad)*h );
1744 if ((i_angle >= 270) && (i_angle < 360))
1745 xoffset -= (int)( sin(rad)*h );
ab9d0a8c 1746
1d65e535
RR
1747 int i_x = x - xoffset;
1748 int i_y = y - yoffset;
ab9d0a8c 1749
f1c72f0c 1750 src = image;
1d65e535 1751 DoDrawBitmap( src, i_x, i_y, true );
9a8c7620 1752
95724b1a 1753
9a8c7620
VZ
1754 // it would be better to draw with non underlined font and draw the line
1755 // manually here (it would be more straight...)
1756#if 0
1757 if ( m_font.GetUnderlined() )
1758 {
1759 gdk_draw_line( m_window, m_textGC,
1760 XLOG2DEV(x + x4), YLOG2DEV(y + y4 + font->descent),
1761 XLOG2DEV(x + x3), YLOG2DEV(y + y3 + font->descent));
1762 }
1763#endif // 0
1764
9a8c7620
VZ
1765 // update the bounding box
1766 CalcBoundingBox(x + minX, y + minY);
1767 CalcBoundingBox(x + maxX, y + maxY);
95724b1a
VZ
1768}
1769
72cdf4c9
VZ
1770void wxWindowDC::DoGetTextExtent(const wxString &string,
1771 wxCoord *width, wxCoord *height,
1772 wxCoord *descent, wxCoord *externalLeading,
1773 wxFont *theFont) const
c801d85f 1774{
b1f0abe4
VZ
1775 if ( width )
1776 *width = 0;
1777 if ( height )
1778 *height = 0;
1779 if ( descent )
1780 *descent = 0;
1781 if ( externalLeading )
1782 *externalLeading = 0;
1783
ab9d0a8c 1784 if (string.empty())
48d011c8 1785 {
48d011c8
RR
1786 return;
1787 }
ab9d0a8c 1788
48d011c8 1789#ifdef __WXGTK20__
cfcc3932 1790 // Set new font description
2b5f62a0 1791 if (theFont)
cfcc3932 1792 pango_layout_set_font_description( m_layout, theFont->GetNativeFontInfo()->description );
ab9d0a8c 1793
2b5f62a0 1794 // Set layout's text
fb3ed106 1795#if wxUSE_UNICODE
e4da1035 1796 const wxCharBuffer data = wxConvUTF8.cWC2MB( string );
a1e101d0 1797 const char *dataUTF8 = (const char *)data;
fb3ed106 1798#else
e4da1035 1799 const wxWCharBuffer wdata = wxConvLocal.cMB2WC( string );
a1e101d0
VZ
1800 if ( !wdata )
1801 return;
ace35c62 1802
e4da1035 1803 const wxCharBuffer data = wxConvUTF8.cWC2MB( wdata );
a1e101d0 1804 const char *dataUTF8 = (const char *)data;
fb3ed106 1805#endif
a1e101d0
VZ
1806
1807 if ( !dataUTF8 )
1808 {
1809 // hardly ideal, but what else can we do if conversion failed?
1810 return;
1811 }
1812
1813 pango_layout_set_text( m_layout, dataUTF8, strlen(dataUTF8) );
ab9d0a8c 1814
48d011c8
RR
1815 if (descent)
1816 {
ace35c62
RR
1817 int h;
1818 pango_layout_get_pixel_size( m_layout, width, &h );
f69e2009
VS
1819 PangoLayoutIter *iter = pango_layout_get_iter(m_layout);
1820 int baseline = pango_layout_iter_get_baseline(iter);
1821 pango_layout_iter_free(iter);
1822 *descent = h - PANGO_PIXELS(baseline);
ace35c62
RR
1823
1824 if (height)
1825 *height = (wxCoord) h;
1826 }
1827 else
1828 {
1829 pango_layout_get_pixel_size( m_layout, width, height );
48d011c8 1830 }
ab9d0a8c 1831
cfcc3932
RR
1832 // Reset old font description
1833 if (theFont)
1834 pango_layout_set_font_description( m_layout, m_fontdesc );
a1e101d0 1835#else // GTK+ 1.x
2b5f62a0 1836 wxFont fontToUse = m_font;
b1f0abe4
VZ
1837 if (theFont)
1838 fontToUse = *theFont;
ab9d0a8c 1839
265898fd 1840 GdkFont *font = fontToUse.GetInternalFont( m_scaleY );
b1f0abe4
VZ
1841 if ( !font )
1842 return;
1843
1844 if (width)
1845 *width = wxCoord(gdk_string_width( font, string.mbc_str() ) / m_scaleX);
1846 if (height)
1847 *height = wxCoord((font->ascent + font->descent) / m_scaleY);
1848 if (descent)
1849 *descent = wxCoord(font->descent / m_scaleY);
a1e101d0 1850#endif // GTK+ 2/1
903f689b 1851}
c801d85f 1852
72cdf4c9 1853wxCoord wxWindowDC::GetCharWidth() const
c801d85f 1854{
2b5f62a0 1855#ifdef __WXGTK20__
cfcc3932 1856 pango_layout_set_text( m_layout, "H", 1 );
ace35c62
RR
1857 int w;
1858 pango_layout_get_pixel_size( m_layout, &w, NULL );
2b5f62a0
VZ
1859 return w;
1860#else
265898fd 1861 GdkFont *font = m_font.GetInternalFont( m_scaleY );
58c837a4 1862 wxCHECK_MSG( font, -1, wxT("invalid font") );
7beba2fc 1863
72cdf4c9 1864 return wxCoord(gdk_string_width( font, "H" ) / m_scaleX);
2b5f62a0 1865#endif
903f689b 1866}
c801d85f 1867
72cdf4c9 1868wxCoord wxWindowDC::GetCharHeight() const
c801d85f 1869{
2b5f62a0 1870#ifdef __WXGTK20__
cfcc3932 1871 pango_layout_set_text( m_layout, "H", 1 );
ace35c62
RR
1872 int h;
1873 pango_layout_get_pixel_size( m_layout, NULL, &h );
2b5f62a0
VZ
1874 return h;
1875#else
265898fd 1876 GdkFont *font = m_font.GetInternalFont( m_scaleY );
58c837a4 1877 wxCHECK_MSG( font, -1, wxT("invalid font") );
7beba2fc 1878
72cdf4c9 1879 return wxCoord((font->ascent + font->descent) / m_scaleY);
2b5f62a0 1880#endif
903f689b 1881}
c801d85f 1882
4bc67cc5 1883void wxWindowDC::Clear()
c801d85f 1884{
223d09f6 1885 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1886
6db90681 1887 if (!m_window) return;
7d5af6fa 1888
f60e7fdd
VZ
1889 // VZ: the code below results in infinite recursion and crashes when
1890 // dc.Clear() is done from OnPaint() so I disable it for now.
1891 // I don't know what the correct fix is but Clear() surely should not
1892 // reenter OnPaint()!
1893#if 0
f234c60c
RR
1894 /* - we either are a memory dc or have a window as the
1895 owner. anything else shouldn't happen.
1896 - we don't use gdk_window_clear() as we don't set
1897 the window's background colour anymore. it is too
1898 much pain to keep the DC's and the window's back-
1899 ground colour in synch. */
7d5af6fa 1900
f234c60c 1901 if (m_owner)
265898fd 1902 {
f90566f5 1903 m_owner->Clear();
b0e0d661 1904 return;
265898fd 1905 }
f234c60c
RR
1906
1907 if (m_isMemDC)
265898fd
RR
1908 {
1909 int width,height;
1910 GetSize( &width, &height );
1911 gdk_draw_rectangle( m_window, m_bgGC, TRUE, 0, 0, width, height );
b0e0d661 1912 return;
265898fd 1913 }
f60e7fdd
VZ
1914#else // 1
1915 int width,height;
1916 GetSize( &width, &height );
1917 gdk_draw_rectangle( m_window, m_bgGC, TRUE, 0, 0, width, height );
1918#endif // 0/1
903f689b 1919}
c801d85f 1920
ec758a20 1921void wxWindowDC::SetFont( const wxFont &font )
c801d85f 1922{
265898fd 1923 m_font = font;
ab9d0a8c 1924
8943b403 1925#ifdef __WXGTK20__
77416abd 1926 if (m_font.Ok())
2b5f62a0 1927 {
cfcc3932
RR
1928 if (m_fontdesc)
1929 pango_font_description_free( m_fontdesc );
ab9d0a8c 1930
cfcc3932 1931 m_fontdesc = pango_font_description_copy( m_font.GetNativeFontInfo()->description );
ab9d0a8c
WS
1932
1933
77416abd
JS
1934 if (m_owner)
1935 {
cfcc3932 1936 PangoContext *oldContext = m_context;
ab9d0a8c 1937
f26623c8 1938 m_context = m_owner->GtkGetPangoDefaultContext();
ab9d0a8c 1939
cfcc3932
RR
1940 // If we switch back/forth between different contexts
1941 // we also have to create a new layout. I think so,
ab9d0a8c 1942 // at least, and it doesn't hurt to do it.
cfcc3932
RR
1943 if (oldContext != m_context)
1944 {
1945 if (m_layout)
1946 g_object_unref( G_OBJECT( m_layout ) );
ab9d0a8c 1947
cfcc3932
RR
1948 m_layout = pango_layout_new( m_context );
1949 }
77416abd 1950 }
ab9d0a8c 1951
cfcc3932 1952 pango_layout_set_font_description( m_layout, m_fontdesc );
2b5f62a0 1953 }
8943b403 1954#endif
903f689b 1955}
c801d85f 1956
ec758a20 1957void wxWindowDC::SetPen( const wxPen &pen )
c801d85f 1958{
223d09f6 1959 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1960
265898fd 1961 if (m_pen == pen) return;
7d5af6fa 1962
265898fd 1963 m_pen = pen;
7d5af6fa 1964
265898fd 1965 if (!m_pen.Ok()) return;
7d5af6fa 1966
6db90681 1967 if (!m_window) return;
7d5af6fa 1968
265898fd 1969 gint width = m_pen.GetWidth();
265898fd
RR
1970 if (width <= 0)
1971 {
112c5086 1972 // CMB: if width is non-zero scale it with the dc
265898fd
RR
1973 width = 1;
1974 }
1975 else
1976 {
1977 // X doesn't allow different width in x and y and so we take
1978 // the average
503f414e
VZ
1979 double w = 0.5 +
1980 ( fabs((double) XLOG2DEVREL(width)) +
1981 fabs((double) YLOG2DEVREL(width)) ) / 2.0;
265898fd 1982 width = (int)w;
375fc5a9
VZ
1983 if ( !width )
1984 {
1985 // width can't be 0 or an internal GTK error occurs inside
1986 // gdk_gc_set_dashes() below
1987 width = 1;
1988 }
265898fd 1989 }
7d5af6fa 1990
2eca425d
RL
1991 static const wxGTKDash dotted[] = {1, 1};
1992 static const wxGTKDash short_dashed[] = {2, 2};
1993 static const wxGTKDash wxCoord_dashed[] = {2, 4};
1994 static const wxGTKDash dotted_dashed[] = {3, 3, 1, 3};
7d5af6fa 1995
112c5086
RR
1996 // We express dash pattern in pen width unit, so we are
1997 // independent of zoom factor and so on...
1998 int req_nb_dash;
2eca425d 1999 const wxGTKDash *req_dash;
7d5af6fa 2000
265898fd
RR
2001 GdkLineStyle lineStyle = GDK_LINE_SOLID;
2002 switch (m_pen.GetStyle())
2003 {
112c5086 2004 case wxUSER_DASH:
7d5af6fa
VZ
2005 {
2006 lineStyle = GDK_LINE_ON_OFF_DASH;
112c5086 2007 req_nb_dash = m_pen.GetDashCount();
2eca425d 2008 req_dash = (wxGTKDash*)m_pen.GetDash();
112c5086 2009 break;
7d5af6fa
VZ
2010 }
2011 case wxDOT:
2012 {
2013 lineStyle = GDK_LINE_ON_OFF_DASH;
112c5086
RR
2014 req_nb_dash = 2;
2015 req_dash = dotted;
7d5af6fa
VZ
2016 break;
2017 }
2018 case wxLONG_DASH:
2019 {
2020 lineStyle = GDK_LINE_ON_OFF_DASH;
112c5086 2021 req_nb_dash = 2;
72cdf4c9 2022 req_dash = wxCoord_dashed;
7d5af6fa
VZ
2023 break;
2024 }
2025 case wxSHORT_DASH:
2026 {
2027 lineStyle = GDK_LINE_ON_OFF_DASH;
112c5086
RR
2028 req_nb_dash = 2;
2029 req_dash = short_dashed;
7d5af6fa
VZ
2030 break;
2031 }
2032 case wxDOT_DASH:
2033 {
2034// lineStyle = GDK_LINE_DOUBLE_DASH;
2035 lineStyle = GDK_LINE_ON_OFF_DASH;
112c5086
RR
2036 req_nb_dash = 4;
2037 req_dash = dotted_dashed;
7d5af6fa
VZ
2038 break;
2039 }
2040
2041 case wxTRANSPARENT:
72174350 2042 case wxSTIPPLE_MASK_OPAQUE:
7d5af6fa
VZ
2043 case wxSTIPPLE:
2044 case wxSOLID:
2045 default:
2046 {
2047 lineStyle = GDK_LINE_SOLID;
2eca425d 2048 req_dash = (wxGTKDash*)NULL;
112c5086 2049 req_nb_dash = 0;
7d5af6fa
VZ
2050 break;
2051 }
265898fd 2052 }
7d5af6fa 2053
112c5086
RR
2054 if (req_dash && req_nb_dash)
2055 {
2eca425d 2056 wxGTKDash *real_req_dash = new wxGTKDash[req_nb_dash];
112c5086
RR
2057 if (real_req_dash)
2058 {
2059 for (int i = 0; i < req_nb_dash; i++)
2060 real_req_dash[i] = req_dash[i] * width;
2eca425d 2061 gdk_gc_set_dashes( m_penGC, 0, real_req_dash, req_nb_dash );
112c5086
RR
2062 delete[] real_req_dash;
2063 }
2064 else
2065 {
2066 // No Memory. We use non-scaled dash pattern...
2eca425d 2067 gdk_gc_set_dashes( m_penGC, 0, (wxGTKDash*)req_dash, req_nb_dash );
112c5086
RR
2068 }
2069 }
7d5af6fa 2070
265898fd
RR
2071 GdkCapStyle capStyle = GDK_CAP_ROUND;
2072 switch (m_pen.GetCap())
2073 {
265898fd
RR
2074 case wxCAP_PROJECTING: { capStyle = GDK_CAP_PROJECTING; break; }
2075 case wxCAP_BUTT: { capStyle = GDK_CAP_BUTT; break; }
d4aa3a4b
RR
2076 case wxCAP_ROUND:
2077 default:
72174350 2078 {
d4aa3a4b
RR
2079 if (width <= 1)
2080 {
2081 width = 0;
2082 capStyle = GDK_CAP_NOT_LAST;
2083 }
2084 else
2085 {
2086 capStyle = GDK_CAP_ROUND;
2087 }
72174350 2088 break;
d4aa3a4b 2089 }
265898fd 2090 }
7d5af6fa 2091
265898fd
RR
2092 GdkJoinStyle joinStyle = GDK_JOIN_ROUND;
2093 switch (m_pen.GetJoin())
2094 {
2095 case wxJOIN_BEVEL: { joinStyle = GDK_JOIN_BEVEL; break; }
265898fd 2096 case wxJOIN_MITER: { joinStyle = GDK_JOIN_MITER; break; }
d4aa3a4b
RR
2097 case wxJOIN_ROUND:
2098 default: { joinStyle = GDK_JOIN_ROUND; break; }
265898fd 2099 }
7d5af6fa 2100
265898fd 2101 gdk_gc_set_line_attributes( m_penGC, width, lineStyle, capStyle, joinStyle );
7d5af6fa 2102
265898fd
RR
2103 m_pen.GetColour().CalcPixel( m_cmap );
2104 gdk_gc_set_foreground( m_penGC, m_pen.GetColour().GetColor() );
903f689b 2105}
c801d85f 2106
ec758a20 2107void wxWindowDC::SetBrush( const wxBrush &brush )
c801d85f 2108{
223d09f6 2109 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 2110
265898fd 2111 if (m_brush == brush) return;
7d5af6fa 2112
265898fd 2113 m_brush = brush;
7d5af6fa 2114
265898fd 2115 if (!m_brush.Ok()) return;
7d5af6fa 2116
6db90681 2117 if (!m_window) return;
7d5af6fa 2118
265898fd
RR
2119 m_brush.GetColour().CalcPixel( m_cmap );
2120 gdk_gc_set_foreground( m_brushGC, m_brush.GetColour().GetColor() );
7d5af6fa 2121
956dbab1 2122 gdk_gc_set_fill( m_brushGC, GDK_SOLID );
7d5af6fa 2123
4fcd73bd 2124 if ((m_brush.GetStyle() == wxSTIPPLE) && (m_brush.GetStipple()->Ok()))
265898fd 2125 {
4fcd73bd 2126 if (m_brush.GetStipple()->GetPixmap())
7d5af6fa 2127 {
956dbab1 2128 gdk_gc_set_fill( m_brushGC, GDK_TILED );
cd25b18c 2129 gdk_gc_set_tile( m_brushGC, m_brush.GetStipple()->GetPixmap() );
7d5af6fa 2130 }
b0e0d661 2131 else
7d5af6fa 2132 {
956dbab1 2133 gdk_gc_set_fill( m_brushGC, GDK_STIPPLED );
4fcd73bd 2134 gdk_gc_set_stipple( m_brushGC, m_brush.GetStipple()->GetBitmap() );
7d5af6fa 2135 }
265898fd 2136 }
7d5af6fa 2137
de2d2cdc
VZ
2138 if ((m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE) && (m_brush.GetStipple()->GetMask()))
2139 {
e1208c31
RR
2140 gdk_gc_set_fill( m_textGC, GDK_OPAQUE_STIPPLED);
2141 gdk_gc_set_stipple( m_textGC, m_brush.GetStipple()->GetMask()->GetBitmap() );
de2d2cdc
VZ
2142 }
2143
ab9d0a8c 2144 if (m_brush.IsHatch())
265898fd 2145 {
956dbab1 2146 gdk_gc_set_fill( m_brushGC, GDK_STIPPLED );
265898fd
RR
2147 int num = m_brush.GetStyle() - wxBDIAGONAL_HATCH;
2148 gdk_gc_set_stipple( m_brushGC, hatches[num] );
2149 }
903f689b 2150}
c801d85f 2151
ec758a20 2152void wxWindowDC::SetBackground( const wxBrush &brush )
46dc76ba 2153{
bbbbe360
RR
2154 /* CMB 21/7/98: Added SetBackground. Sets background brush
2155 * for Clear() and bg colour for shapes filled with cross-hatch brush */
7d5af6fa 2156
223d09f6 2157 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 2158
265898fd 2159 if (m_backgroundBrush == brush) return;
7d5af6fa 2160
265898fd 2161 m_backgroundBrush = brush;
7d5af6fa 2162
265898fd 2163 if (!m_backgroundBrush.Ok()) return;
7d5af6fa 2164
6db90681 2165 if (!m_window) return;
7d5af6fa 2166
265898fd
RR
2167 m_backgroundBrush.GetColour().CalcPixel( m_cmap );
2168 gdk_gc_set_background( m_brushGC, m_backgroundBrush.GetColour().GetColor() );
a802c3a1 2169 gdk_gc_set_background( m_penGC, m_backgroundBrush.GetColour().GetColor() );
031b2a7b 2170 gdk_gc_set_background( m_bgGC, m_backgroundBrush.GetColour().GetColor() );
265898fd 2171 gdk_gc_set_foreground( m_bgGC, m_backgroundBrush.GetColour().GetColor() );
3417c2cd
RR
2172
2173 gdk_gc_set_fill( m_bgGC, GDK_SOLID );
7d5af6fa 2174
cd25b18c 2175 if ((m_backgroundBrush.GetStyle() == wxSTIPPLE) && (m_backgroundBrush.GetStipple()->Ok()))
265898fd 2176 {
fd128b0c 2177 if (m_backgroundBrush.GetStipple()->GetPixmap())
7d5af6fa 2178 {
3417c2cd 2179 gdk_gc_set_fill( m_bgGC, GDK_TILED );
fd128b0c 2180 gdk_gc_set_tile( m_bgGC, m_backgroundBrush.GetStipple()->GetPixmap() );
7d5af6fa 2181 }
cd25b18c 2182 else
7d5af6fa 2183 {
3417c2cd 2184 gdk_gc_set_fill( m_bgGC, GDK_STIPPLED );
fd128b0c 2185 gdk_gc_set_stipple( m_bgGC, m_backgroundBrush.GetStipple()->GetBitmap() );
7d5af6fa 2186 }
265898fd 2187 }
7d5af6fa 2188
ab9d0a8c 2189 if (m_backgroundBrush.IsHatch())
265898fd 2190 {
3417c2cd 2191 gdk_gc_set_fill( m_bgGC, GDK_STIPPLED );
265898fd
RR
2192 int num = m_backgroundBrush.GetStyle() - wxBDIAGONAL_HATCH;
2193 gdk_gc_set_stipple( m_bgGC, hatches[num] );
bbbbe360 2194 }
903f689b 2195}
46dc76ba 2196
ec758a20 2197void wxWindowDC::SetLogicalFunction( int function )
c801d85f 2198{
223d09f6 2199 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 2200
72174350
VZ
2201 if (m_logicalFunction == function)
2202 return;
2203
2204 // VZ: shouldn't this be a CHECK?
2205 if (!m_window)
2206 return;
01eaf507 2207
2b5f62a0 2208 GdkFunction mode;
265898fd
RR
2209 switch (function)
2210 {
3c679789
RR
2211 case wxXOR: mode = GDK_XOR; break;
2212 case wxINVERT: mode = GDK_INVERT; break;
3c679789
RR
2213 case wxOR_REVERSE: mode = GDK_OR_REVERSE; break;
2214 case wxAND_REVERSE: mode = GDK_AND_REVERSE; break;
2215 case wxCLEAR: mode = GDK_CLEAR; break;
2216 case wxSET: mode = GDK_SET; break;
2217 case wxOR_INVERT: mode = GDK_OR_INVERT; break;
2218 case wxAND: mode = GDK_AND; break;
2219 case wxOR: mode = GDK_OR; break;
2220 case wxEQUIV: mode = GDK_EQUIV; break;
2221 case wxNAND: mode = GDK_NAND; break;
2222 case wxAND_INVERT: mode = GDK_AND_INVERT; break;
7d5af6fa
VZ
2223 case wxCOPY: mode = GDK_COPY; break;
2224 case wxNO_OP: mode = GDK_NOOP; break;
2225 case wxSRC_INVERT: mode = GDK_COPY_INVERT; break;
72174350 2226
2d52841d
RR
2227 // unsupported by GTK
2228 case wxNOR: mode = GDK_COPY; break;
01eaf507 2229 default:
223d09f6 2230 wxFAIL_MSG( wxT("unsupported logical function") );
2b5f62a0 2231 mode = GDK_COPY;
265898fd 2232 }
7d5af6fa 2233
265898fd 2234 m_logicalFunction = function;
7d5af6fa 2235
265898fd
RR
2236 gdk_gc_set_function( m_penGC, mode );
2237 gdk_gc_set_function( m_brushGC, mode );
72174350
VZ
2238
2239 // to stay compatible with wxMSW, we don't apply ROPs to the text
3d2d8da1
RR
2240 // operations (i.e. DrawText/DrawRotatedText).
2241 // True, but mono-bitmaps use the m_textGC and they use ROPs as well.
2242 gdk_gc_set_function( m_textGC, mode );
903f689b 2243}
c801d85f 2244
ec758a20 2245void wxWindowDC::SetTextForeground( const wxColour &col )
c801d85f 2246{
223d09f6 2247 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 2248
71ec83d2
VZ
2249 // don't set m_textForegroundColour to an invalid colour as we'd crash
2250 // later then (we use m_textForegroundColour.GetColor() without checking
2251 // in a few places)
2252 if ( !col.Ok() || (m_textForegroundColour == col) )
2253 return;
7d5af6fa 2254
265898fd 2255 m_textForegroundColour = col;
7d5af6fa 2256
71ec83d2
VZ
2257 if ( m_window )
2258 {
2259 m_textForegroundColour.CalcPixel( m_cmap );
2260 gdk_gc_set_foreground( m_textGC, m_textForegroundColour.GetColor() );
2261 }
903f689b 2262}
c801d85f 2263
ec758a20 2264void wxWindowDC::SetTextBackground( const wxColour &col )
c801d85f 2265{
223d09f6 2266 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 2267
71ec83d2
VZ
2268 // same as above
2269 if ( !col.Ok() || (m_textBackgroundColour == col) )
2270 return;
7d5af6fa 2271
265898fd 2272 m_textBackgroundColour = col;
7d5af6fa 2273
71ec83d2
VZ
2274 if ( m_window )
2275 {
2276 m_textBackgroundColour.CalcPixel( m_cmap );
2277 gdk_gc_set_background( m_textGC, m_textBackgroundColour.GetColor() );
2278 }
903f689b 2279}
c801d85f 2280
ec758a20 2281void wxWindowDC::SetBackgroundMode( int mode )
c801d85f 2282{
223d09f6 2283 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 2284
265898fd 2285 m_backgroundMode = mode;
46dc76ba 2286
6db90681 2287 if (!m_window) return;
7d5af6fa 2288
265898fd
RR
2289 // CMB 21/7/98: fill style of cross-hatch brushes is affected by
2290 // transparent/solid background mode
7d5af6fa 2291
265898fd
RR
2292 if (m_brush.GetStyle() != wxSOLID && m_brush.GetStyle() != wxTRANSPARENT)
2293 {
2294 gdk_gc_set_fill( m_brushGC,
2295 (m_backgroundMode == wxTRANSPARENT) ? GDK_STIPPLED : GDK_OPAQUE_STIPPLED);
2296 }
903f689b 2297}
c801d85f 2298
ec758a20 2299void wxWindowDC::SetPalette( const wxPalette& WXUNUSED(palette) )
c801d85f 2300{
223d09f6 2301 wxFAIL_MSG( wxT("wxWindowDC::SetPalette not implemented") );
903f689b 2302}
c801d85f 2303
72cdf4c9 2304void wxWindowDC::DoSetClippingRegion( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
c801d85f 2305{
223d09f6 2306 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 2307
6db90681 2308 if (!m_window) return;
7d5af6fa 2309
3d2d8da1 2310 wxRect rect;
265898fd
RR
2311 rect.x = XLOG2DEV(x);
2312 rect.y = YLOG2DEV(y);
2313 rect.width = XLOG2DEVREL(width);
2314 rect.height = YLOG2DEVREL(height);
5f170f33 2315
e1208c31 2316 if (!m_currentClippingRegion.IsNull())
993f97ee
RR
2317 m_currentClippingRegion.Intersect( rect );
2318 else
2319 m_currentClippingRegion.Union( rect );
5f170f33
VZ
2320
2321#if USE_PAINT_REGION
e1208c31 2322 if (!m_paintClippingRegion.IsNull())
3d2d8da1 2323 m_currentClippingRegion.Intersect( m_paintClippingRegion );
809934d2 2324#endif
3d2d8da1 2325
ee8dbe63
RL
2326 wxCoord xx, yy, ww, hh;
2327 m_currentClippingRegion.GetBox( xx, yy, ww, hh );
2328 wxDC::DoSetClippingRegion( xx, yy, ww, hh );
2329
3d2d8da1
RR
2330 gdk_gc_set_clip_region( m_penGC, m_currentClippingRegion.GetRegion() );
2331 gdk_gc_set_clip_region( m_brushGC, m_currentClippingRegion.GetRegion() );
2332 gdk_gc_set_clip_region( m_textGC, m_currentClippingRegion.GetRegion() );
2333 gdk_gc_set_clip_region( m_bgGC, m_currentClippingRegion.GetRegion() );
903f689b 2334}
c801d85f 2335
b0e0d661 2336void wxWindowDC::DoSetClippingRegionAsRegion( const wxRegion &region )
463c1fa1 2337{
223d09f6 2338 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 2339
463c1fa1
RR
2340 if (region.Empty())
2341 {
2342 DestroyClippingRegion();
2343 return;
2344 }
7d5af6fa 2345
6db90681 2346 if (!m_window) return;
5f170f33 2347
e1208c31 2348 if (!m_currentClippingRegion.IsNull())
993f97ee
RR
2349 m_currentClippingRegion.Intersect( region );
2350 else
2351 m_currentClippingRegion.Union( region );
5f170f33
VZ
2352
2353#if USE_PAINT_REGION
e1208c31 2354 if (!m_paintClippingRegion.IsNull())
3d2d8da1 2355 m_currentClippingRegion.Intersect( m_paintClippingRegion );
809934d2 2356#endif
3d2d8da1 2357
ee8dbe63
RL
2358 wxCoord xx, yy, ww, hh;
2359 m_currentClippingRegion.GetBox( xx, yy, ww, hh );
2360 wxDC::DoSetClippingRegion( xx, yy, ww, hh );
2361
3d2d8da1
RR
2362 gdk_gc_set_clip_region( m_penGC, m_currentClippingRegion.GetRegion() );
2363 gdk_gc_set_clip_region( m_brushGC, m_currentClippingRegion.GetRegion() );
2364 gdk_gc_set_clip_region( m_textGC, m_currentClippingRegion.GetRegion() );
2365 gdk_gc_set_clip_region( m_bgGC, m_currentClippingRegion.GetRegion() );
463c1fa1
RR
2366}
2367
4bc67cc5 2368void wxWindowDC::DestroyClippingRegion()
c801d85f 2369{
223d09f6 2370 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 2371
265898fd 2372 wxDC::DestroyClippingRegion();
7d5af6fa 2373
3d2d8da1 2374 m_currentClippingRegion.Clear();
5f170f33
VZ
2375
2376#if USE_PAINT_REGION
3d2d8da1
RR
2377 if (!m_paintClippingRegion.IsEmpty())
2378 m_currentClippingRegion.Union( m_paintClippingRegion );
993f97ee 2379#endif
3d2d8da1 2380
6db90681 2381 if (!m_window) return;
7d5af6fa 2382
3d2d8da1
RR
2383 if (m_currentClippingRegion.IsEmpty())
2384 {
2385 gdk_gc_set_clip_rectangle( m_penGC, (GdkRectangle *) NULL );
2386 gdk_gc_set_clip_rectangle( m_brushGC, (GdkRectangle *) NULL );
2387 gdk_gc_set_clip_rectangle( m_textGC, (GdkRectangle *) NULL );
2388 gdk_gc_set_clip_rectangle( m_bgGC, (GdkRectangle *) NULL );
2389 }
2390 else
2391 {
2392 gdk_gc_set_clip_region( m_penGC, m_currentClippingRegion.GetRegion() );
2393 gdk_gc_set_clip_region( m_brushGC, m_currentClippingRegion.GetRegion() );
2394 gdk_gc_set_clip_region( m_textGC, m_currentClippingRegion.GetRegion() );
2395 gdk_gc_set_clip_region( m_bgGC, m_currentClippingRegion.GetRegion() );
2396 }
903f689b 2397}
c801d85f 2398
4bc67cc5 2399void wxWindowDC::Destroy()
dbf858b5 2400{
3d2d8da1 2401 if (m_penGC) wxFreePoolGC( m_penGC );
265898fd 2402 m_penGC = (GdkGC*) NULL;
3d2d8da1 2403 if (m_brushGC) wxFreePoolGC( m_brushGC );
265898fd 2404 m_brushGC = (GdkGC*) NULL;
3d2d8da1 2405 if (m_textGC) wxFreePoolGC( m_textGC );
265898fd 2406 m_textGC = (GdkGC*) NULL;
3d2d8da1 2407 if (m_bgGC) wxFreePoolGC( m_bgGC );
265898fd 2408 m_bgGC = (GdkGC*) NULL;
dbf858b5
RR
2409}
2410
238d735d
RR
2411void wxWindowDC::ComputeScaleAndOrigin()
2412{
c77a6796 2413 const wxRealPoint origScale(m_scaleX, m_scaleY);
238d735d
RR
2414
2415 wxDC::ComputeScaleAndOrigin();
2416
c77a6796
VZ
2417 // if scale has changed call SetPen to recalulate the line width
2418 if ( wxRealPoint(m_scaleX, m_scaleY) != origScale && m_pen.Ok() )
238d735d 2419 {
c77a6796
VZ
2420 // this is a bit artificial, but we need to force wxDC to think the pen
2421 // has changed
0a164d4c
WS
2422 wxPen pen = m_pen;
2423 m_pen = wxNullPen;
2424 SetPen( pen );
2425 }
238d735d
RR
2426}
2427
b0e0d661
VZ
2428// Resolution in pixels per logical inch
2429wxSize wxWindowDC::GetPPI() const
2430{
7a5e6267 2431 return wxSize( (int) (m_mm_to_pix_x * 25.4 + 0.5), (int) (m_mm_to_pix_y * 25.4 + 0.5));
b0e0d661
VZ
2432}
2433
2434int wxWindowDC::GetDepth() const
c801d85f 2435{
ace35c62
RR
2436#ifdef __WXGTK20__
2437 return gdk_drawable_get_depth(m_window);
2438#else
223d09f6 2439 wxFAIL_MSG(wxT("not implemented"));
b0e0d661
VZ
2440
2441 return -1;
ace35c62 2442#endif
903f689b 2443}
c801d85f 2444
ec758a20
RR
2445
2446//-----------------------------------------------------------------------------
2447// wxPaintDC
2448//-----------------------------------------------------------------------------
2449
f469b27c 2450IMPLEMENT_DYNAMIC_CLASS(wxPaintDC, wxClientDC)
ec758a20 2451
2cfddfe7
JS
2452// Limit the paint region to the window size. Sometimes
2453// the paint region is too big, and this risks X11 errors
2454static void wxLimitRegionToSize(wxRegion& region, const wxSize& sz)
2455{
2456 wxRect originalRect = region.GetBox();
2457 wxRect rect(originalRect);
2458 if (rect.width + rect.x > sz.x)
2459 rect.width = sz.x - rect.x;
2460 if (rect.height + rect.y > sz.y)
2461 rect.height = sz.y - rect.y;
2462 if (rect != originalRect)
2463 {
2464 region = wxRegion(rect);
2465 wxLogTrace(wxT("painting"), wxT("Limiting region from %d, %d, %d, %d to %d, %d, %d, %d\n"),
2466 originalRect.x, originalRect.y, originalRect.width, originalRect.height,
2467 rect.x, rect.y, rect.width, rect.height);
2468 }
2469}
2470
ec758a20 2471wxPaintDC::wxPaintDC( wxWindow *win )
f469b27c 2472 : wxClientDC( win )
ec758a20 2473{
b6fa52db
RR
2474#if USE_PAINT_REGION
2475 if (!win->m_clipPaintRegion)
2476 return;
f469b27c 2477
2cfddfe7 2478 wxSize sz = win->GetSize();
e1208c31 2479 m_paintClippingRegion = win->GetUpdateRegion();
2cfddfe7 2480 wxLimitRegionToSize(m_paintClippingRegion, sz);
ab9d0a8c 2481
5f170f33
VZ
2482 GdkRegion *region = m_paintClippingRegion.GetRegion();
2483 if ( region )
2484 {
823faac3 2485 m_currentClippingRegion.Union( m_paintClippingRegion );
2cfddfe7
JS
2486 wxLimitRegionToSize(m_currentClippingRegion, sz);
2487
2488 if (sz.x <= 0 || sz.y <= 0)
2489 return ;
5f170f33 2490
823faac3
JS
2491 gdk_gc_set_clip_region( m_penGC, region );
2492 gdk_gc_set_clip_region( m_brushGC, region );
2493 gdk_gc_set_clip_region( m_textGC, region );
2494 gdk_gc_set_clip_region( m_bgGC, region );
5f170f33 2495 }
1e6feb95 2496#endif // USE_PAINT_REGION
ec758a20
RR
2497}
2498
2499//-----------------------------------------------------------------------------
2500// wxClientDC
2501//-----------------------------------------------------------------------------
2502
f469b27c 2503IMPLEMENT_DYNAMIC_CLASS(wxClientDC, wxWindowDC)
ec758a20 2504
f469b27c
VZ
2505wxClientDC::wxClientDC( wxWindow *win )
2506 : wxWindowDC( win )
ec758a20 2507{
4f55a07f
VZ
2508 wxCHECK_RET( win, _T("NULL window in wxClientDC::wxClientDC") );
2509
1e6feb95
VZ
2510#ifdef __WXUNIVERSAL__
2511 wxPoint ptOrigin = win->GetClientAreaOrigin();
2512 SetDeviceOrigin(ptOrigin.x, ptOrigin.y);
2513 wxSize size = win->GetClientSize();
2514 SetClippingRegion(wxPoint(0, 0), size);
2515#endif // __WXUNIVERSAL__
ec758a20
RR
2516}
2517
4f55a07f
VZ
2518void wxClientDC::DoGetSize(int *width, int *height) const
2519{
2520 wxCHECK_RET( m_owner, _T("GetSize() doesn't work without window") );
2521
2522 m_owner->GetClientSize( width, height );
2523}
2524
3d2d8da1
RR
2525// ----------------------------------------------------------------------------
2526// wxDCModule
2527// ----------------------------------------------------------------------------
2528
2529class wxDCModule : public wxModule
2530{
2531public:
2532 bool OnInit();
2533 void OnExit();
2534
2535private:
2536 DECLARE_DYNAMIC_CLASS(wxDCModule)
2537};
2538
2539IMPLEMENT_DYNAMIC_CLASS(wxDCModule, wxModule)
2540
2541bool wxDCModule::OnInit()
2542{
2543 wxInitGCPool();
ab9d0a8c 2544 return true;
3d2d8da1
RR
2545}
2546
2547void wxDCModule::OnExit()
2548{
2549 wxCleanUpGCPool();
2550}