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