]> git.saurik.com Git - wxWidgets.git/blame - src/gtk1/dcclient.cpp
Add short-cut for wxDataViewListIndexModel for generic code
[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
c801d85f 17#include "wx/dcclient.h"
e4db172a
WS
18
19#ifndef WX_PRECOMP
20 #include "wx/log.h"
f38924e8 21 #include "wx/dcmemory.h"
18680f86 22 #include "wx/math.h" // for floating-point functions
155ecd4c 23 #include "wx/image.h"
02761f6c 24 #include "wx/module.h"
e4db172a
WS
25#endif
26
db16cab4 27#include "wx/fontutil.h"
e5131165 28
3cbab641 29#include "wx/gtk1/win_gtk.h"
c801d85f 30
071a2d78 31#include <gdk/gdk.h>
993f97ee 32#include <gdk/gdkx.h>
8943b403 33#include <gdk/gdkprivate.h>
071a2d78 34#include <gtk/gtk.h>
83624f79 35
809934d2
RR
36//-----------------------------------------------------------------------------
37// local defines
38//-----------------------------------------------------------------------------
39
e1208c31 40#define USE_PAINT_REGION 1
809934d2 41
c801d85f
KB
42//-----------------------------------------------------------------------------
43// local data
44//-----------------------------------------------------------------------------
45
46#include "bdiag.xbm"
47#include "fdiag.xbm"
48#include "cdiag.xbm"
49#include "horiz.xbm"
50#include "verti.xbm"
51#include "cross.xbm"
52#define num_hatches 6
53
3ca6a5f0
BP
54#define IS_15_PIX_HATCH(s) ((s)==wxCROSSDIAG_HATCH || (s)==wxHORIZONTAL_HATCH || (s)==wxVERTICAL_HATCH)
55#define IS_16_PIX_HATCH(s) ((s)!=wxCROSSDIAG_HATCH && (s)!=wxHORIZONTAL_HATCH && (s)!=wxVERTICAL_HATCH)
56
57
c801d85f 58static GdkPixmap *hatches[num_hatches];
c67daf87 59static GdkPixmap **hatch_bitmap = (GdkPixmap **) NULL;
c801d85f 60
c2fa61e8 61extern GtkWidget *wxGetRootWindow();
3d2d8da1 62
c801d85f
KB
63//-----------------------------------------------------------------------------
64// constants
65//-----------------------------------------------------------------------------
66
95724b1a 67const double RAD2DEG = 180.0 / M_PI;
c801d85f 68
9a8c7620
VZ
69// ----------------------------------------------------------------------------
70// private functions
71// ----------------------------------------------------------------------------
72
73static inline double dmax(double a, double b) { return a > b ? a : b; }
74static inline double dmin(double a, double b) { return a < b ? a : b; }
75
76static inline double DegToRad(double deg) { return (deg * M_PI) / 180.0; }
77
6f65e337
JS
78//-----------------------------------------------------------------------------
79// temporary implementation of the missing GDK function
80//-----------------------------------------------------------------------------
b0e0d661 81
6f65e337 82#include "gdk/gdkprivate.h"
b0e0d661 83
1e6feb95
VZ
84void gdk_wx_draw_bitmap(GdkDrawable *drawable,
85 GdkGC *gc,
86 GdkDrawable *src,
87 gint xsrc,
88 gint ysrc,
89 gint xdest,
90 gint ydest,
91 gint width,
92 gint height)
6f65e337 93{
17a1ebd1
VZ
94 wxCHECK_RET( drawable, _T("NULL drawable in gdk_wx_draw_bitmap") );
95 wxCHECK_RET( src, _T("NULL src in gdk_wx_draw_bitmap") );
96 wxCHECK_RET( gc, _T("NULL gc in gdk_wx_draw_bitmap") );
ab9d0a8c 97
d90c9596
RR
98 GdkWindowPrivate *drawable_private;
99 GdkWindowPrivate *src_private;
100 GdkGCPrivate *gc_private;
ab9d0a8c 101
d90c9596
RR
102 drawable_private = (GdkWindowPrivate*) drawable;
103 src_private = (GdkWindowPrivate*) src;
104 if (drawable_private->destroyed || src_private->destroyed)
105 return;
106
107 gint src_width = src_private->width;
108 gint src_height = src_private->height;
109
110 gc_private = (GdkGCPrivate*) gc;
ab9d0a8c 111
d90c9596
RR
112 if (width == -1) width = src_width;
113 if (height == -1) height = src_height;
ab9d0a8c 114
265898fd 115 XCopyPlane( drawable_private->xdisplay,
b0e0d661
VZ
116 src_private->xwindow,
117 drawable_private->xwindow,
118 gc_private->xgc,
119 xsrc, ysrc,
120 width, height,
121 xdest, ydest,
122 1 );
6f65e337
JS
123}
124
3d2d8da1
RR
125//-----------------------------------------------------------------------------
126// Implement Pool of Graphic contexts. Creating them takes too much time.
127//-----------------------------------------------------------------------------
128
0e09f76e
RR
129enum wxPoolGCType
130{
131 wxGC_ERROR = 0,
132 wxTEXT_MONO,
133 wxBG_MONO,
134 wxPEN_MONO,
135 wxBRUSH_MONO,
136 wxTEXT_COLOUR,
137 wxBG_COLOUR,
138 wxPEN_COLOUR,
f6bcfd97
BP
139 wxBRUSH_COLOUR,
140 wxTEXT_SCREEN,
141 wxBG_SCREEN,
142 wxPEN_SCREEN,
143 wxBRUSH_SCREEN
0e09f76e
RR
144};
145
3d2d8da1
RR
146struct wxGC
147{
0e09f76e
RR
148 GdkGC *m_gc;
149 wxPoolGCType m_type;
150 bool m_used;
3d2d8da1
RR
151};
152
696f36b7
JS
153#define GC_POOL_ALLOC_SIZE 100
154
155static int wxGCPoolSize = 0;
156
157static wxGC *wxGCPool = NULL;
3d2d8da1
RR
158
159static void wxInitGCPool()
160{
696f36b7
JS
161 // This really could wait until the first call to
162 // wxGetPoolGC, but we will make the first allocation
163 // now when other initialization is being performed.
ab9d0a8c 164
696f36b7
JS
165 // Set initial pool size.
166 wxGCPoolSize = GC_POOL_ALLOC_SIZE;
ab9d0a8c 167
696f36b7
JS
168 // Allocate initial pool.
169 wxGCPool = (wxGC *)malloc(wxGCPoolSize * sizeof(wxGC));
170 if (wxGCPool == NULL)
171 {
172 // If we cannot malloc, then fail with error
173 // when debug is enabled. If debug is not enabled,
174 // the problem will eventually get caught
551b5391 175 // in wxGetPoolGC.
696f36b7
JS
176 wxFAIL_MSG( wxT("Cannot allocate GC pool") );
177 return;
178 }
ab9d0a8c 179
696f36b7
JS
180 // Zero initial pool.
181 memset(wxGCPool, 0, wxGCPoolSize * sizeof(wxGC));
3d2d8da1
RR
182}
183
184static void wxCleanUpGCPool()
185{
f6116855 186 for (int i = 0; i < wxGCPoolSize; i++)
3d2d8da1
RR
187 {
188 if (wxGCPool[i].m_gc)
189 gdk_gc_unref( wxGCPool[i].m_gc );
190 }
696f36b7
JS
191
192 free(wxGCPool);
193 wxGCPool = NULL;
194 wxGCPoolSize = 0;
3d2d8da1
RR
195}
196
0e09f76e 197static GdkGC* wxGetPoolGC( GdkWindow *window, wxPoolGCType type )
3d2d8da1 198{
696f36b7 199 wxGC *pptr;
ab9d0a8c 200
696f36b7
JS
201 // Look for an available GC.
202 for (int i = 0; i < wxGCPoolSize; i++)
3d2d8da1
RR
203 {
204 if (!wxGCPool[i].m_gc)
205 {
206 wxGCPool[i].m_gc = gdk_gc_new( window );
207 gdk_gc_set_exposures( wxGCPool[i].m_gc, FALSE );
0e09f76e 208 wxGCPool[i].m_type = type;
ab9d0a8c 209 wxGCPool[i].m_used = false;
3d2d8da1 210 }
0e09f76e 211 if ((!wxGCPool[i].m_used) && (wxGCPool[i].m_type == type))
3d2d8da1 212 {
ab9d0a8c 213 wxGCPool[i].m_used = true;
3d2d8da1
RR
214 return wxGCPool[i].m_gc;
215 }
216 }
5f170f33 217
696f36b7
JS
218 // We did not find an available GC.
219 // We need to grow the GC pool.
220 pptr = (wxGC *)realloc(wxGCPool,
551b5391 221 (wxGCPoolSize + GC_POOL_ALLOC_SIZE)*sizeof(wxGC));
696f36b7
JS
222 if (pptr != NULL)
223 {
224 // Initialize newly allocated pool.
225 wxGCPool = pptr;
551b5391
RR
226 memset(&wxGCPool[wxGCPoolSize], 0,
227 GC_POOL_ALLOC_SIZE*sizeof(wxGC));
ab9d0a8c
WS
228
229 // Initialize entry we will return.
696f36b7
JS
230 wxGCPool[wxGCPoolSize].m_gc = gdk_gc_new( window );
231 gdk_gc_set_exposures( wxGCPool[wxGCPoolSize].m_gc, FALSE );
232 wxGCPool[wxGCPoolSize].m_type = type;
ab9d0a8c
WS
233 wxGCPool[wxGCPoolSize].m_used = true;
234
696f36b7
JS
235 // Set new value of pool size.
236 wxGCPoolSize += GC_POOL_ALLOC_SIZE;
ab9d0a8c 237
696f36b7
JS
238 // Return newly allocated entry.
239 return wxGCPool[wxGCPoolSize-GC_POOL_ALLOC_SIZE].m_gc;
240 }
ab9d0a8c 241
696f36b7 242 // The realloc failed. Fall through to error.
3d2d8da1 243 wxFAIL_MSG( wxT("No GC available") );
5f170f33 244
3d2d8da1
RR
245 return (GdkGC*) NULL;
246}
247
248static void wxFreePoolGC( GdkGC *gc )
249{
696f36b7 250 for (int i = 0; i < wxGCPoolSize; i++)
3d2d8da1
RR
251 {
252 if (wxGCPool[i].m_gc == gc)
253 {
ab9d0a8c 254 wxGCPool[i].m_used = false;
3d2d8da1
RR
255 return;
256 }
257 }
5f170f33 258
3d2d8da1
RR
259 wxFAIL_MSG( wxT("Wrong GC") );
260}
261
c801d85f 262//-----------------------------------------------------------------------------
ec758a20 263// wxWindowDC
c801d85f
KB
264//-----------------------------------------------------------------------------
265
b0e0d661 266IMPLEMENT_DYNAMIC_CLASS(wxWindowDC, wxDC)
c801d85f 267
4bc67cc5 268wxWindowDC::wxWindowDC()
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
ec758a20 280wxWindowDC::wxWindowDC( wxWindow *window )
c801d85f 281{
3cd0b8c5
RR
282 wxASSERT_MSG( window, wxT("DC needs a window") );
283
265898fd
RR
284 m_penGC = (GdkGC *) NULL;
285 m_brushGC = (GdkGC *) NULL;
286 m_textGC = (GdkGC *) NULL;
287 m_bgGC = (GdkGC *) NULL;
288 m_cmap = (GdkColormap *) NULL;
bbbbe360 289 m_owner = (wxWindow *)NULL;
ab9d0a8c
WS
290 m_isMemDC = false;
291 m_isScreenDC = false;
3b245d60 292 m_font = window->GetFont();
7d5af6fa 293
a2053b27 294 GtkWidget *widget = window->m_wxwindow;
7d5af6fa 295
cfcc3932 296 // Some controls don't have m_wxwindow - like wxStaticBox, but the user
b7f1f77f 297 // code should still be able to create wxClientDCs for them, so we will
cfcc3932 298 // use the parent window here then.
b7f1f77f
VZ
299 if ( !widget )
300 {
301 window = window->GetParent();
302 widget = window->m_wxwindow;
303 }
304
223d09f6 305 wxASSERT_MSG( widget, wxT("DC needs a widget") );
7d5af6fa 306
da048e3d
RR
307 GtkPizza *pizza = GTK_PIZZA( widget );
308 m_window = pizza->bin_window;
7d5af6fa 309
cfcc3932 310 // Window not realized ?
1e133b7d
RR
311 if (!m_window)
312 {
cfcc3932 313 // Don't report problems as per MSW.
ab9d0a8c 314 m_ok = true;
7d5af6fa
VZ
315
316 return;
1e133b7d 317 }
7d5af6fa 318
b7f1f77f 319 m_cmap = gtk_widget_get_colormap( widget ? widget : window->m_widget );
7d5af6fa 320
265898fd 321 SetUpDC();
bbbbe360
RR
322
323 /* this must be done after SetUpDC, bacause SetUpDC calls the
324 repective SetBrush, SetPen, SetBackground etc functions
325 to set up the DC. SetBackground call m_owner->SetBackground
326 and this might not be desired as the standard dc background
327 is white whereas a window might assume gray to be the
328 standard (as e.g. wxStatusBar) */
7d5af6fa 329
bbbbe360 330 m_owner = window;
903f689b 331}
c801d85f 332
4bc67cc5 333wxWindowDC::~wxWindowDC()
c801d85f 334{
265898fd 335 Destroy();
903f689b 336}
c801d85f 337
809934d2
RR
338void wxWindowDC::SetUpDC()
339{
ab9d0a8c 340 m_ok = true;
5f170f33 341
809934d2 342 wxASSERT_MSG( !m_penGC, wxT("GCs already created") );
5f170f33 343
f6bcfd97
BP
344 if (m_isScreenDC)
345 {
346 m_penGC = wxGetPoolGC( m_window, wxPEN_SCREEN );
347 m_brushGC = wxGetPoolGC( m_window, wxBRUSH_SCREEN );
348 m_textGC = wxGetPoolGC( m_window, wxTEXT_SCREEN );
349 m_bgGC = wxGetPoolGC( m_window, wxBG_SCREEN );
350 }
351 else
809934d2
RR
352 if (m_isMemDC && (((wxMemoryDC*)this)->m_selected.GetDepth() == 1))
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
376aa62a
VZ
424void wxWindowDC::DoGetSize( int* width, int* height ) const
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
387ebd3e 434bool wxWindowDC::DoFloodFill(wxCoord x, wxCoord y,
06cf7c08
VS
435 const wxColour& col, int style)
436{
387ebd3e 437 return wxDoFloodFill(this, x, y, col, style);
903f689b 438}
c801d85f 439
dc1efb1d 440bool wxWindowDC::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);
447 memdc.Blit(0, 0, 1, 1, (wxDC*) this, x1, y1);
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
72cdf4c9 455void wxWindowDC::DoDrawLine( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2 )
c801d85f 456{
223d09f6 457 wxCHECK_RET( Ok(), 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
72cdf4c9 469void wxWindowDC::DoCrossHair( wxCoord x, wxCoord y )
c801d85f 470{
223d09f6 471 wxCHECK_RET( Ok(), 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
72cdf4c9
VZ
488void wxWindowDC::DoDrawArc( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2,
489 wxCoord xc, wxCoord yc )
c801d85f 490{
223d09f6 491 wxCHECK_RET( Ok(), 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
72cdf4c9 580void wxWindowDC::DoDrawEllipticArc( wxCoord x, wxCoord y, wxCoord width, wxCoord height, double sa, double ea )
c801d85f 581{
223d09f6 582 wxCHECK_RET( Ok(), 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
72cdf4c9 642void wxWindowDC::DoDrawPoint( wxCoord x, wxCoord y )
c801d85f 643{
223d09f6 644 wxCHECK_RET( Ok(), 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
72cdf4c9 652void wxWindowDC::DoDrawLines( int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset )
c801d85f 653{
223d09f6 654 wxCHECK_RET( Ok(), 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
72cdf4c9 683void wxWindowDC::DoDrawPolygon( int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset, int WXUNUSED(fillStyle) )
cf7a7e13 684{
223d09f6 685 wxCHECK_RET( Ok(), 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
72cdf4c9 751void wxWindowDC::DoDrawRectangle( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
c801d85f 752{
223d09f6 753 wxCHECK_RET( Ok(), 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
72cdf4c9 813void wxWindowDC::DoDrawRoundedRectangle( wxCoord x, wxCoord y, wxCoord width, wxCoord height, double radius )
c801d85f 814{
223d09f6 815 wxCHECK_RET( Ok(), 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 {
833 DrawRectangle( x, y, width, height );
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
72cdf4c9 936void wxWindowDC::DoDrawEllipse( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
c801d85f 937{
223d09f6 938 wxCHECK_RET( Ok(), 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
72cdf4c9 995void wxWindowDC::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
b0e0d661 1001void wxWindowDC::DoDrawBitmap( const wxBitmap &bitmap,
72cdf4c9 1002 wxCoord x, wxCoord y,
b0e0d661 1003 bool useMask )
4bc67cc5 1004{
223d09f6 1005 wxCHECK_RET( Ok(), 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
1e6feb95
VZ
1128bool wxWindowDC::DoBlit( wxCoord xdest, wxCoord ydest,
1129 wxCoord width, wxCoord height,
1130 wxDC *source,
1131 wxCoord xsrc, wxCoord ysrc,
1132 int logical_func,
0cbff120
JS
1133 bool useMask,
1134 wxCoord xsrcMask, wxCoord ysrcMask )
c801d85f 1135{
ab9d0a8c 1136 wxCHECK_MSG( Ok(), 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
06201c35
RR
1143 xsrc = source->XLOG2DEV(xsrc);
1144 ysrc = source->YLOG2DEV(ysrc);
1e6feb95 1145
6e13c196
RR
1146 wxClientDC *srcDC = (wxClientDC*)source;
1147 wxMemoryDC *memDC = (wxMemoryDC*)source;
7d5af6fa 1148
ab9d0a8c
WS
1149 bool use_bitmap_method = false;
1150 bool is_mono = false;
7d5af6fa 1151
0cbff120
JS
1152 if (xsrcMask == -1 && ysrcMask == -1)
1153 {
d90c9596
RR
1154 xsrcMask = xsrc;
1155 ysrcMask = ysrc;
0cbff120
JS
1156 }
1157
6e13c196
RR
1158 if (srcDC->m_isMemDC)
1159 {
ab9d0a8c 1160 if (!memDC->m_selected.Ok()) return false;
7d5af6fa 1161
d90c9596
RR
1162 is_mono = (memDC->m_selected.GetDepth() == 1);
1163
1164 // we use the "XCopyArea" way to copy a memory dc into
1165 // a different window if the memory dc BOTH
1166 // a) doesn't have any mask or its mask isn't used
1167 // b) it is clipped
1168 // c) is not 1-bit
7d5af6fa 1169
f234c60c 1170 if (useMask && (memDC->m_selected.GetMask()))
b0e0d661 1171 {
d90c9596
RR
1172 // we HAVE TO use the direct way for memory dcs
1173 // that have mask since the XCopyArea doesn't know
1174 // about masks
ab9d0a8c 1175 use_bitmap_method = true;
b0e0d661 1176 }
d90c9596 1177 else if (is_mono)
b0e0d661 1178 {
d90c9596
RR
1179 // we HAVE TO use the direct way for memory dcs
1180 // that are bitmaps because XCopyArea doesn't cope
1181 // with different bit depths
ab9d0a8c 1182 use_bitmap_method = true;
b0e0d661
VZ
1183 }
1184 else if ((xsrc == 0) && (ysrc == 0) &&
1185 (width == memDC->m_selected.GetWidth()) &&
1186 (height == memDC->m_selected.GetHeight()))
1187 {
d90c9596
RR
1188 // we SHOULD use the direct way if all of the bitmap
1189 // in the memory dc is copied in which case XCopyArea
1190 // wouldn't be able able to boost performace by reducing
1191 // the area to be scaled
ab9d0a8c 1192 use_bitmap_method = true;
b0e0d661
VZ
1193 }
1194 else
1195 {
ab9d0a8c 1196 use_bitmap_method = false;
b0e0d661 1197 }
6e13c196 1198 }
7d5af6fa 1199
265898fd
RR
1200 CalcBoundingBox( xdest, ydest );
1201 CalcBoundingBox( xdest + width, ydest + height );
7d5af6fa 1202
d90c9596 1203 // scale/translate size and position
3d2d8da1
RR
1204 wxCoord xx = XLOG2DEV(xdest);
1205 wxCoord yy = YLOG2DEV(ydest);
1206
1207 wxCoord ww = XLOG2DEVREL(width);
1208 wxCoord hh = YLOG2DEVREL(height);
1209
d90c9596 1210 // compare to current clipping region
e1208c31 1211 if (!m_currentClippingRegion.IsNull())
3d2d8da1
RR
1212 {
1213 wxRegion tmp( xx,yy,ww,hh );
1214 tmp.Intersect( m_currentClippingRegion );
1215 if (tmp.IsEmpty())
ab9d0a8c 1216 return true;
3d2d8da1
RR
1217 }
1218
4bc67cc5
RR
1219 int old_logical_func = m_logicalFunction;
1220 SetLogicalFunction( logical_func );
5f170f33 1221
6e13c196 1222 if (use_bitmap_method)
6f65e337 1223 {
d90c9596 1224 // scale/translate bitmap size
72cdf4c9
VZ
1225 wxCoord bm_width = memDC->m_selected.GetWidth();
1226 wxCoord bm_height = memDC->m_selected.GetHeight();
7d5af6fa 1227
551b5391
RR
1228 // Get clip coords for the bitmap. If we don't
1229 // use wxBitmap::Rescale(), which can clip the
1230 // bitmap, these are the same as the original
1231 // coordinates
1232 wxCoord cx = xx;
1233 wxCoord cy = yy;
1234 wxCoord cw = ww;
1235 wxCoord ch = hh;
ab9d0a8c 1236
d90c9596
RR
1237 // interpret userscale of src too
1238 double xsc,ysc;
1239 memDC->GetUserScale(&xsc,&ysc);
1240 bm_width = (int) (bm_width / xsc);
1241 bm_height = (int) (bm_height / ysc);
1242
72cdf4c9
VZ
1243 wxCoord bm_ww = XLOG2DEVREL( bm_width );
1244 wxCoord bm_hh = YLOG2DEVREL( bm_height );
7d5af6fa 1245
551b5391 1246 // Scale bitmap if required
6e13c196 1247 wxBitmap use_bitmap;
f53df133 1248 if ((memDC->m_selected.GetWidth()!= bm_ww) || ( memDC->m_selected.GetHeight()!= bm_hh))
6e13c196 1249 {
551b5391
RR
1250 // This indicates that the blitting code below will get
1251 // a clipped bitmap and therefore needs to move the origin
1252 // accordingly
1253 wxRegion tmp( xx,yy,ww,hh );
1254 tmp.Intersect( m_currentClippingRegion );
1255 tmp.GetBox(cx,cy,cw,ch);
ab9d0a8c 1256
551b5391
RR
1257 // Scale and clipped bitmap
1258 use_bitmap = memDC->m_selected.Rescale(cx-xx,cy-yy,cw,ch,bm_ww,bm_hh);
6e13c196
RR
1259 }
1260 else
e23d0e95 1261 {
551b5391 1262 // Don't scale bitmap
6e13c196
RR
1263 use_bitmap = memDC->m_selected;
1264 }
7d5af6fa 1265
d90c9596 1266 // apply mask if any
6e13c196
RR
1267 GdkBitmap *mask = (GdkBitmap *) NULL;
1268 if (use_bitmap.GetMask()) mask = use_bitmap.GetMask()->GetBitmap();
7d5af6fa 1269
d90c9596 1270 GdkBitmap *new_mask = (GdkBitmap*) NULL;
ab9d0a8c 1271
7d5af6fa 1272 if (useMask && mask)
6e13c196 1273 {
e1208c31 1274 if (!m_currentClippingRegion.IsNull())
3d2d8da1
RR
1275 {
1276 GdkColor col;
c2fa61e8 1277 new_mask = gdk_pixmap_new( wxGetRootWindow()->window, bm_ww, bm_hh, 1 );
3d2d8da1
RR
1278 GdkGC *gc = gdk_gc_new( new_mask );
1279 col.pixel = 0;
1280 gdk_gc_set_foreground( gc, &col );
b7a49654 1281 gdk_gc_set_ts_origin( gc, -xsrcMask, -ysrcMask);
3d2d8da1
RR
1282 gdk_draw_rectangle( new_mask, gc, TRUE, 0, 0, bm_ww, bm_hh );
1283 col.pixel = 0;
1284 gdk_gc_set_background( gc, &col );
1285 col.pixel = 1;
1286 gdk_gc_set_foreground( gc, &col );
1287 gdk_gc_set_clip_region( gc, m_currentClippingRegion.GetRegion() );
d90c9596
RR
1288 // was: gdk_gc_set_clip_origin( gc, -xx, -yy );
1289 gdk_gc_set_clip_origin( gc, -cx, -cy );
3d2d8da1
RR
1290 gdk_gc_set_fill( gc, GDK_OPAQUE_STIPPLED );
1291 gdk_gc_set_stipple( gc, mask );
1292 gdk_draw_rectangle( new_mask, gc, TRUE, 0, 0, bm_ww, bm_hh );
1293 gdk_gc_unref( gc );
1294 }
d90c9596 1295
82ea63e6
RR
1296 if (is_mono)
1297 {
3d2d8da1 1298 if (new_mask)
b7a49654 1299 {
3d2d8da1 1300 gdk_gc_set_clip_mask( m_textGC, new_mask );
b7a49654
RR
1301 gdk_gc_set_clip_origin( m_textGC, cx, cy );
1302 }
3d2d8da1 1303 else
b7a49654 1304 {
3d2d8da1 1305 gdk_gc_set_clip_mask( m_textGC, mask );
b7a49654 1306 gdk_gc_set_clip_origin( m_textGC, cx-xsrcMask, cy-ysrcMask );
0a164d4c 1307 }
82ea63e6
RR
1308 }
1309 else
6e13c196 1310 {
3d2d8da1 1311 if (new_mask)
b7a49654 1312 {
3d2d8da1 1313 gdk_gc_set_clip_mask( m_penGC, new_mask );
b7a49654
RR
1314 gdk_gc_set_clip_origin( m_penGC, cx, cy );
1315 }
3d2d8da1 1316 else
b7a49654 1317 {
3d2d8da1 1318 gdk_gc_set_clip_mask( m_penGC, mask );
b7a49654 1319 gdk_gc_set_clip_origin( m_penGC, cx-xsrcMask, cy-ysrcMask );
0a164d4c 1320 }
b0e0d661 1321 }
6e13c196 1322 }
7d5af6fa 1323
d90c9596
RR
1324 // Draw XPixmap or XBitmap, depending on what the wxBitmap contains. For
1325 // drawing a mono-bitmap (XBitmap) we use the current text GC
5f170f33 1326
82ea63e6 1327 if (is_mono)
d90c9596 1328 {
d90c9596
RR
1329 // was: gdk_wx_draw_bitmap( m_window, m_textGC, use_bitmap.GetBitmap(), xsrc, ysrc, xx, yy, ww, hh );
1330 gdk_wx_draw_bitmap( m_window, m_textGC, use_bitmap.GetBitmap(), xsrc, ysrc, cx, cy, cw, ch );
d90c9596 1331 }
82ea63e6 1332 else
d90c9596
RR
1333 {
1334 // was: gdk_draw_pixmap( m_window, m_penGC, use_bitmap.GetPixmap(), xsrc, ysrc, xx, yy, ww, hh );
1335 gdk_draw_pixmap( m_window, m_penGC, use_bitmap.GetPixmap(), xsrc, ysrc, cx, cy, cw, ch );
1336 }
82ea63e6 1337
d90c9596 1338 // remove mask again if any
7d5af6fa 1339 if (useMask && mask)
6e13c196 1340 {
82ea63e6
RR
1341 if (is_mono)
1342 {
1343 gdk_gc_set_clip_mask( m_textGC, (GdkBitmap *) NULL );
1344 gdk_gc_set_clip_origin( m_textGC, 0, 0 );
e1208c31 1345 if (!m_currentClippingRegion.IsNull())
3d2d8da1 1346 gdk_gc_set_clip_region( m_textGC, m_currentClippingRegion.GetRegion() );
82ea63e6
RR
1347 }
1348 else
1349 {
1350 gdk_gc_set_clip_mask( m_penGC, (GdkBitmap *) NULL );
1351 gdk_gc_set_clip_origin( m_penGC, 0, 0 );
e1208c31 1352 if (!m_currentClippingRegion.IsNull())
3d2d8da1 1353 gdk_gc_set_clip_region( m_penGC, m_currentClippingRegion.GetRegion() );
82ea63e6 1354 }
265898fd 1355 }
ab9d0a8c 1356
d90c9596
RR
1357 if (new_mask)
1358 gdk_bitmap_unref( new_mask );
6f65e337 1359 }
d90c9596 1360 else // use_bitmap_method
6e13c196 1361 {
bf9848e7 1362 if ((width != ww) || (height != hh))
b0e0d661 1363 {
d90c9596
RR
1364 // get clip coords
1365 wxRegion tmp( xx,yy,ww,hh );
1366 tmp.Intersect( m_currentClippingRegion );
1367 wxCoord cx,cy,cw,ch;
1368 tmp.GetBox(cx,cy,cw,ch);
ab9d0a8c
WS
1369
1370 // rescale bitmap
d90c9596 1371 wxBitmap bitmap = memDC->m_selected.Rescale( cx-xx, cy-yy, cw, ch, ww, hh );
7d5af6fa 1372
d90c9596
RR
1373 // draw scaled bitmap
1374 // was: gdk_draw_pixmap( m_window, m_penGC, bitmap.GetPixmap(), 0, 0, xx, yy, -1, -1 );
1375 gdk_draw_pixmap( m_window, m_penGC, bitmap.GetPixmap(), 0, 0, cx, cy, -1, -1 );
b0e0d661
VZ
1376 }
1377 else
1378 {
ab9d0a8c 1379 // No scaling and not a memory dc with a mask either
993f97ee 1380
d90c9596 1381 // copy including child window contents
a56fcaaf 1382 gdk_gc_set_subwindow( m_penGC, GDK_INCLUDE_INFERIORS );
6e13c196
RR
1383 gdk_window_copy_area( m_window, m_penGC, xx, yy,
1384 srcDC->GetWindow(),
1385 xsrc, ysrc, width, height );
a56fcaaf 1386 gdk_gc_set_subwindow( m_penGC, GDK_CLIP_BY_CHILDREN );
b0e0d661 1387 }
6e13c196 1388 }
c801d85f 1389
4bc67cc5 1390 SetLogicalFunction( old_logical_func );
ab9d0a8c
WS
1391
1392 return true;
903f689b 1393}
c801d85f 1394
72cdf4c9 1395void wxWindowDC::DoDrawText( const wxString &text, wxCoord x, wxCoord y )
c801d85f 1396{
223d09f6 1397 wxCHECK_RET( Ok(), wxT("invalid window dc") );
18a2fa37 1398
6db90681 1399 if (!m_window) return;
ab9d0a8c 1400
2b5f62a0 1401 if (text.empty()) return;
7d5af6fa 1402
265898fd 1403 GdkFont *font = m_font.GetInternalFont( m_scaleY );
6f65e337 1404
a1fffa9f
VZ
1405 wxCHECK_RET( font, wxT("invalid font") );
1406
265898fd
RR
1407 x = XLOG2DEV(x);
1408 y = YLOG2DEV(y);
18a2fa37 1409
8943b403
OK
1410 wxCoord width = gdk_string_width( font, text.mbc_str() );
1411 wxCoord height = font->ascent + font->descent;
2c37aade
VZ
1412
1413 if ( m_backgroundMode == wxSOLID )
265898fd 1414 {
265898fd
RR
1415 gdk_gc_set_foreground( m_textGC, m_textBackgroundColour.GetColor() );
1416 gdk_draw_rectangle( m_window, m_textGC, TRUE, x, y, width, height );
2c37aade 1417 gdk_gc_set_foreground( m_textGC, m_textForegroundColour.GetColor() );
265898fd 1418 }
93c5dd39 1419 gdk_draw_string( m_window, font, m_textGC, x, y + font->ascent, text.mbc_str() );
18a2fa37 1420
bbbbe360
RR
1421 /* CMB 17/7/98: simple underline: ignores scaling and underlying
1422 X font's XA_UNDERLINE_POSITION and XA_UNDERLINE_THICKNESS
1423 properties (see wxXt implementation) */
265898fd
RR
1424 if (m_font.GetUnderlined())
1425 {
13111b2a 1426 wxCoord ul_y = y + font->ascent;
265898fd
RR
1427 if (font->descent > 0) ul_y++;
1428 gdk_draw_line( m_window, m_textGC, x, ul_y, x + width, ul_y);
1429 }
7d5af6fa 1430
8943b403
OK
1431 width = wxCoord(width / m_scaleX);
1432 height = wxCoord(height / m_scaleY);
1433 CalcBoundingBox (x + width, y + height);
265898fd 1434 CalcBoundingBox (x, y);
903f689b 1435}
c801d85f 1436
bf47e398
RD
1437
1438// TODO: There is an example of rotating text with GTK2 that would probably be
1439// a better approach here:
1440// http://www.daa.com.au/pipermail/pygtk/2003-April/005052.html
1441
95724b1a
VZ
1442void wxWindowDC::DoDrawRotatedText( const wxString &text, wxCoord x, wxCoord y, double angle )
1443{
c77a6796 1444 if ( wxIsNullDouble(angle) )
95724b1a
VZ
1445 {
1446 DrawText(text, x, y);
1447 return;
1448 }
1449
1450 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1451
1452 if (!m_window) return;
1453
bf47e398
RD
1454 wxCoord w;
1455 wxCoord h;
1456
95724b1a
VZ
1457 GdkFont *font = m_font.GetInternalFont( m_scaleY );
1458
1459 wxCHECK_RET( font, wxT("invalid font") );
1460
9a8c7620 1461 // the size of the text
bf47e398
RD
1462 w = gdk_string_width( font, text.mbc_str() );
1463 h = font->ascent + font->descent;
3cbab641 1464
9a8c7620
VZ
1465 // draw the string normally
1466 wxBitmap src(w, h);
95724b1a
VZ
1467 wxMemoryDC dc;
1468 dc.SelectObject(src);
1469 dc.SetFont(GetFont());
f1c72f0c 1470 dc.SetBackground(*wxBLACK_BRUSH);
95724b1a
VZ
1471 dc.SetBrush(*wxBLACK_BRUSH);
1472 dc.Clear();
f1c72f0c 1473 dc.SetTextForeground( *wxWHITE );
95724b1a 1474 dc.DrawText(text, 0, 0);
9a8c7620 1475 dc.SelectObject(wxNullBitmap);
95724b1a
VZ
1476
1477 // Calculate the size of the rotated bounding box.
9a8c7620
VZ
1478 double rad = DegToRad(angle);
1479 double dx = cos(rad),
1480 dy = sin(rad);
1481
1482 // the rectngle vertices are counted clockwise with the first one being at
1483 // (0, 0) (or, rather, at (x, y))
1484 double x2 = w*dx,
1485 y2 = -w*dy; // y axis points to the bottom, hence minus
1486 double x4 = h*dy,
1487 y4 = h*dx;
1488 double x3 = x4 + x2,
1489 y3 = y4 + y2;
ab9d0a8c 1490
72174350 1491 // calc max and min
9a8c7620
VZ
1492 wxCoord maxX = (wxCoord)(dmax(x2, dmax(x3, x4)) + 0.5),
1493 maxY = (wxCoord)(dmax(y2, dmax(y3, y4)) + 0.5),
1494 minX = (wxCoord)(dmin(x2, dmin(x3, x4)) - 0.5),
1495 minY = (wxCoord)(dmin(y2, dmin(y3, y4)) - 0.5);
1496
72174350 1497
f1c72f0c 1498 wxImage image = src.ConvertToImage();
9a8c7620 1499
f1c72f0c
RR
1500 image.ConvertColourToAlpha( m_textForegroundColour.Red(),
1501 m_textForegroundColour.Green(),
1502 m_textForegroundColour.Blue() );
1503 image = image.Rotate( rad, wxPoint(0,0) );
ab9d0a8c 1504
1d65e535
RR
1505 int i_angle = (int) angle;
1506 i_angle = i_angle % 360;
c2cb80c8
KH
1507 if (i_angle < 0)
1508 i_angle += 360;
1d65e535
RR
1509 int xoffset = 0;
1510 if ((i_angle >= 90.0) && (i_angle < 270.0))
1511 xoffset = image.GetWidth();
1512 int yoffset = 0;
1513 if ((i_angle >= 0.0) && (i_angle < 180.0))
1514 yoffset = image.GetHeight();
ab9d0a8c 1515
1d65e535
RR
1516 if ((i_angle >= 0) && (i_angle < 90))
1517 yoffset -= (int)( cos(rad)*h );
1518 if ((i_angle >= 90) && (i_angle < 180))
ab9d0a8c 1519 xoffset -= (int)( sin(rad)*h );
1d65e535
RR
1520 if ((i_angle >= 180) && (i_angle < 270))
1521 yoffset -= (int)( cos(rad)*h );
1522 if ((i_angle >= 270) && (i_angle < 360))
1523 xoffset -= (int)( sin(rad)*h );
ab9d0a8c 1524
1d65e535
RR
1525 int i_x = x - xoffset;
1526 int i_y = y - yoffset;
ab9d0a8c 1527
f1c72f0c 1528 src = image;
1d65e535 1529 DoDrawBitmap( src, i_x, i_y, true );
9a8c7620 1530
95724b1a 1531
9a8c7620
VZ
1532 // it would be better to draw with non underlined font and draw the line
1533 // manually here (it would be more straight...)
1534#if 0
1535 if ( m_font.GetUnderlined() )
1536 {
1537 gdk_draw_line( m_window, m_textGC,
1538 XLOG2DEV(x + x4), YLOG2DEV(y + y4 + font->descent),
1539 XLOG2DEV(x + x3), YLOG2DEV(y + y3 + font->descent));
1540 }
1541#endif // 0
1542
9a8c7620
VZ
1543 // update the bounding box
1544 CalcBoundingBox(x + minX, y + minY);
1545 CalcBoundingBox(x + maxX, y + maxY);
95724b1a
VZ
1546}
1547
72cdf4c9
VZ
1548void wxWindowDC::DoGetTextExtent(const wxString &string,
1549 wxCoord *width, wxCoord *height,
1550 wxCoord *descent, wxCoord *externalLeading,
c94f845b 1551 const wxFont *theFont) const
c801d85f 1552{
b1f0abe4
VZ
1553 if ( width )
1554 *width = 0;
1555 if ( height )
1556 *height = 0;
1557 if ( descent )
1558 *descent = 0;
1559 if ( externalLeading )
1560 *externalLeading = 0;
1561
ab9d0a8c 1562 if (string.empty())
48d011c8 1563 {
48d011c8
RR
1564 return;
1565 }
ab9d0a8c 1566
2b5f62a0 1567 wxFont fontToUse = m_font;
b1f0abe4
VZ
1568 if (theFont)
1569 fontToUse = *theFont;
ab9d0a8c 1570
265898fd 1571 GdkFont *font = fontToUse.GetInternalFont( m_scaleY );
b1f0abe4
VZ
1572 if ( !font )
1573 return;
1574
1575 if (width)
1576 *width = wxCoord(gdk_string_width( font, string.mbc_str() ) / m_scaleX);
1577 if (height)
1578 *height = wxCoord((font->ascent + font->descent) / m_scaleY);
1579 if (descent)
1580 *descent = wxCoord(font->descent / m_scaleY);
903f689b 1581}
c801d85f 1582
72cdf4c9 1583wxCoord wxWindowDC::GetCharWidth() const
c801d85f 1584{
265898fd 1585 GdkFont *font = m_font.GetInternalFont( m_scaleY );
58c837a4 1586 wxCHECK_MSG( font, -1, wxT("invalid font") );
7beba2fc 1587
72cdf4c9 1588 return wxCoord(gdk_string_width( font, "H" ) / m_scaleX);
903f689b 1589}
c801d85f 1590
72cdf4c9 1591wxCoord wxWindowDC::GetCharHeight() const
c801d85f 1592{
265898fd 1593 GdkFont *font = m_font.GetInternalFont( m_scaleY );
58c837a4 1594 wxCHECK_MSG( font, -1, wxT("invalid font") );
7beba2fc 1595
72cdf4c9 1596 return wxCoord((font->ascent + font->descent) / m_scaleY);
903f689b 1597}
c801d85f 1598
4bc67cc5 1599void wxWindowDC::Clear()
c801d85f 1600{
223d09f6 1601 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1602
6db90681 1603 if (!m_window) return;
7d5af6fa 1604
f60e7fdd
VZ
1605 // VZ: the code below results in infinite recursion and crashes when
1606 // dc.Clear() is done from OnPaint() so I disable it for now.
1607 // I don't know what the correct fix is but Clear() surely should not
1608 // reenter OnPaint()!
1609#if 0
f234c60c
RR
1610 /* - we either are a memory dc or have a window as the
1611 owner. anything else shouldn't happen.
1612 - we don't use gdk_window_clear() as we don't set
1613 the window's background colour anymore. it is too
1614 much pain to keep the DC's and the window's back-
1615 ground colour in synch. */
7d5af6fa 1616
f234c60c 1617 if (m_owner)
265898fd 1618 {
f90566f5 1619 m_owner->Clear();
b0e0d661 1620 return;
265898fd 1621 }
f234c60c
RR
1622
1623 if (m_isMemDC)
265898fd
RR
1624 {
1625 int width,height;
1626 GetSize( &width, &height );
1627 gdk_draw_rectangle( m_window, m_bgGC, TRUE, 0, 0, width, height );
b0e0d661 1628 return;
265898fd 1629 }
f60e7fdd
VZ
1630#else // 1
1631 int width,height;
1632 GetSize( &width, &height );
1633 gdk_draw_rectangle( m_window, m_bgGC, TRUE, 0, 0, width, height );
1634#endif // 0/1
903f689b 1635}
c801d85f 1636
ec758a20 1637void wxWindowDC::SetFont( const wxFont &font )
c801d85f 1638{
265898fd 1639 m_font = font;
903f689b 1640}
c801d85f 1641
ec758a20 1642void wxWindowDC::SetPen( const wxPen &pen )
c801d85f 1643{
223d09f6 1644 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1645
265898fd 1646 if (m_pen == pen) return;
7d5af6fa 1647
265898fd 1648 m_pen = pen;
7d5af6fa 1649
265898fd 1650 if (!m_pen.Ok()) return;
7d5af6fa 1651
6db90681 1652 if (!m_window) return;
7d5af6fa 1653
265898fd 1654 gint width = m_pen.GetWidth();
265898fd
RR
1655 if (width <= 0)
1656 {
112c5086 1657 // CMB: if width is non-zero scale it with the dc
265898fd
RR
1658 width = 1;
1659 }
1660 else
1661 {
1662 // X doesn't allow different width in x and y and so we take
1663 // the average
503f414e
VZ
1664 double w = 0.5 +
1665 ( fabs((double) XLOG2DEVREL(width)) +
1666 fabs((double) YLOG2DEVREL(width)) ) / 2.0;
265898fd 1667 width = (int)w;
375fc5a9
VZ
1668 if ( !width )
1669 {
1670 // width can't be 0 or an internal GTK error occurs inside
1671 // gdk_gc_set_dashes() below
1672 width = 1;
1673 }
265898fd 1674 }
7d5af6fa 1675
2eca425d
RL
1676 static const wxGTKDash dotted[] = {1, 1};
1677 static const wxGTKDash short_dashed[] = {2, 2};
1678 static const wxGTKDash wxCoord_dashed[] = {2, 4};
1679 static const wxGTKDash dotted_dashed[] = {3, 3, 1, 3};
7d5af6fa 1680
112c5086
RR
1681 // We express dash pattern in pen width unit, so we are
1682 // independent of zoom factor and so on...
1683 int req_nb_dash;
2eca425d 1684 const wxGTKDash *req_dash;
7d5af6fa 1685
265898fd
RR
1686 GdkLineStyle lineStyle = GDK_LINE_SOLID;
1687 switch (m_pen.GetStyle())
1688 {
112c5086 1689 case wxUSER_DASH:
7d5af6fa
VZ
1690 {
1691 lineStyle = GDK_LINE_ON_OFF_DASH;
112c5086 1692 req_nb_dash = m_pen.GetDashCount();
2eca425d 1693 req_dash = (wxGTKDash*)m_pen.GetDash();
112c5086 1694 break;
7d5af6fa
VZ
1695 }
1696 case wxDOT:
1697 {
1698 lineStyle = GDK_LINE_ON_OFF_DASH;
112c5086
RR
1699 req_nb_dash = 2;
1700 req_dash = dotted;
7d5af6fa
VZ
1701 break;
1702 }
1703 case wxLONG_DASH:
1704 {
1705 lineStyle = GDK_LINE_ON_OFF_DASH;
112c5086 1706 req_nb_dash = 2;
72cdf4c9 1707 req_dash = wxCoord_dashed;
7d5af6fa
VZ
1708 break;
1709 }
1710 case wxSHORT_DASH:
1711 {
1712 lineStyle = GDK_LINE_ON_OFF_DASH;
112c5086
RR
1713 req_nb_dash = 2;
1714 req_dash = short_dashed;
7d5af6fa
VZ
1715 break;
1716 }
1717 case wxDOT_DASH:
1718 {
1719// lineStyle = GDK_LINE_DOUBLE_DASH;
1720 lineStyle = GDK_LINE_ON_OFF_DASH;
112c5086
RR
1721 req_nb_dash = 4;
1722 req_dash = dotted_dashed;
7d5af6fa
VZ
1723 break;
1724 }
1725
1726 case wxTRANSPARENT:
72174350 1727 case wxSTIPPLE_MASK_OPAQUE:
7d5af6fa
VZ
1728 case wxSTIPPLE:
1729 case wxSOLID:
1730 default:
1731 {
1732 lineStyle = GDK_LINE_SOLID;
2eca425d 1733 req_dash = (wxGTKDash*)NULL;
112c5086 1734 req_nb_dash = 0;
7d5af6fa
VZ
1735 break;
1736 }
265898fd 1737 }
7d5af6fa 1738
112c5086
RR
1739 if (req_dash && req_nb_dash)
1740 {
2eca425d 1741 wxGTKDash *real_req_dash = new wxGTKDash[req_nb_dash];
112c5086
RR
1742 if (real_req_dash)
1743 {
1744 for (int i = 0; i < req_nb_dash; i++)
1745 real_req_dash[i] = req_dash[i] * width;
2eca425d 1746 gdk_gc_set_dashes( m_penGC, 0, real_req_dash, req_nb_dash );
112c5086
RR
1747 delete[] real_req_dash;
1748 }
1749 else
1750 {
1751 // No Memory. We use non-scaled dash pattern...
2eca425d 1752 gdk_gc_set_dashes( m_penGC, 0, (wxGTKDash*)req_dash, req_nb_dash );
112c5086
RR
1753 }
1754 }
7d5af6fa 1755
265898fd
RR
1756 GdkCapStyle capStyle = GDK_CAP_ROUND;
1757 switch (m_pen.GetCap())
1758 {
265898fd
RR
1759 case wxCAP_PROJECTING: { capStyle = GDK_CAP_PROJECTING; break; }
1760 case wxCAP_BUTT: { capStyle = GDK_CAP_BUTT; break; }
d4aa3a4b
RR
1761 case wxCAP_ROUND:
1762 default:
72174350 1763 {
d4aa3a4b
RR
1764 if (width <= 1)
1765 {
1766 width = 0;
1767 capStyle = GDK_CAP_NOT_LAST;
1768 }
1769 else
1770 {
1771 capStyle = GDK_CAP_ROUND;
1772 }
72174350 1773 break;
d4aa3a4b 1774 }
265898fd 1775 }
7d5af6fa 1776
265898fd
RR
1777 GdkJoinStyle joinStyle = GDK_JOIN_ROUND;
1778 switch (m_pen.GetJoin())
1779 {
1780 case wxJOIN_BEVEL: { joinStyle = GDK_JOIN_BEVEL; break; }
265898fd 1781 case wxJOIN_MITER: { joinStyle = GDK_JOIN_MITER; break; }
d4aa3a4b
RR
1782 case wxJOIN_ROUND:
1783 default: { joinStyle = GDK_JOIN_ROUND; break; }
265898fd 1784 }
7d5af6fa 1785
265898fd 1786 gdk_gc_set_line_attributes( m_penGC, width, lineStyle, capStyle, joinStyle );
7d5af6fa 1787
265898fd
RR
1788 m_pen.GetColour().CalcPixel( m_cmap );
1789 gdk_gc_set_foreground( m_penGC, m_pen.GetColour().GetColor() );
903f689b 1790}
c801d85f 1791
ec758a20 1792void wxWindowDC::SetBrush( const wxBrush &brush )
c801d85f 1793{
223d09f6 1794 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1795
265898fd 1796 if (m_brush == brush) return;
7d5af6fa 1797
265898fd 1798 m_brush = brush;
7d5af6fa 1799
265898fd 1800 if (!m_brush.Ok()) return;
7d5af6fa 1801
6db90681 1802 if (!m_window) return;
7d5af6fa 1803
265898fd
RR
1804 m_brush.GetColour().CalcPixel( m_cmap );
1805 gdk_gc_set_foreground( m_brushGC, m_brush.GetColour().GetColor() );
7d5af6fa 1806
956dbab1 1807 gdk_gc_set_fill( m_brushGC, GDK_SOLID );
7d5af6fa 1808
4fcd73bd 1809 if ((m_brush.GetStyle() == wxSTIPPLE) && (m_brush.GetStipple()->Ok()))
265898fd 1810 {
4fcd73bd 1811 if (m_brush.GetStipple()->GetPixmap())
7d5af6fa 1812 {
956dbab1 1813 gdk_gc_set_fill( m_brushGC, GDK_TILED );
cd25b18c 1814 gdk_gc_set_tile( m_brushGC, m_brush.GetStipple()->GetPixmap() );
7d5af6fa 1815 }
b0e0d661 1816 else
7d5af6fa 1817 {
956dbab1 1818 gdk_gc_set_fill( m_brushGC, GDK_STIPPLED );
4fcd73bd 1819 gdk_gc_set_stipple( m_brushGC, m_brush.GetStipple()->GetBitmap() );
7d5af6fa 1820 }
265898fd 1821 }
7d5af6fa 1822
de2d2cdc
VZ
1823 if ((m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE) && (m_brush.GetStipple()->GetMask()))
1824 {
e1208c31
RR
1825 gdk_gc_set_fill( m_textGC, GDK_OPAQUE_STIPPLED);
1826 gdk_gc_set_stipple( m_textGC, m_brush.GetStipple()->GetMask()->GetBitmap() );
de2d2cdc
VZ
1827 }
1828
ab9d0a8c 1829 if (m_brush.IsHatch())
265898fd 1830 {
956dbab1 1831 gdk_gc_set_fill( m_brushGC, GDK_STIPPLED );
265898fd
RR
1832 int num = m_brush.GetStyle() - wxBDIAGONAL_HATCH;
1833 gdk_gc_set_stipple( m_brushGC, hatches[num] );
1834 }
903f689b 1835}
c801d85f 1836
ec758a20 1837void wxWindowDC::SetBackground( const wxBrush &brush )
46dc76ba 1838{
bbbbe360
RR
1839 /* CMB 21/7/98: Added SetBackground. Sets background brush
1840 * for Clear() and bg colour for shapes filled with cross-hatch brush */
7d5af6fa 1841
223d09f6 1842 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1843
265898fd 1844 if (m_backgroundBrush == brush) return;
7d5af6fa 1845
265898fd 1846 m_backgroundBrush = brush;
7d5af6fa 1847
265898fd 1848 if (!m_backgroundBrush.Ok()) return;
7d5af6fa 1849
6db90681 1850 if (!m_window) return;
7d5af6fa 1851
265898fd
RR
1852 m_backgroundBrush.GetColour().CalcPixel( m_cmap );
1853 gdk_gc_set_background( m_brushGC, m_backgroundBrush.GetColour().GetColor() );
a802c3a1 1854 gdk_gc_set_background( m_penGC, m_backgroundBrush.GetColour().GetColor() );
031b2a7b 1855 gdk_gc_set_background( m_bgGC, m_backgroundBrush.GetColour().GetColor() );
265898fd 1856 gdk_gc_set_foreground( m_bgGC, m_backgroundBrush.GetColour().GetColor() );
3417c2cd
RR
1857
1858 gdk_gc_set_fill( m_bgGC, GDK_SOLID );
7d5af6fa 1859
cd25b18c 1860 if ((m_backgroundBrush.GetStyle() == wxSTIPPLE) && (m_backgroundBrush.GetStipple()->Ok()))
265898fd 1861 {
fd128b0c 1862 if (m_backgroundBrush.GetStipple()->GetPixmap())
7d5af6fa 1863 {
3417c2cd 1864 gdk_gc_set_fill( m_bgGC, GDK_TILED );
fd128b0c 1865 gdk_gc_set_tile( m_bgGC, m_backgroundBrush.GetStipple()->GetPixmap() );
7d5af6fa 1866 }
cd25b18c 1867 else
7d5af6fa 1868 {
3417c2cd 1869 gdk_gc_set_fill( m_bgGC, GDK_STIPPLED );
fd128b0c 1870 gdk_gc_set_stipple( m_bgGC, m_backgroundBrush.GetStipple()->GetBitmap() );
7d5af6fa 1871 }
265898fd 1872 }
7d5af6fa 1873
ab9d0a8c 1874 if (m_backgroundBrush.IsHatch())
265898fd 1875 {
3417c2cd 1876 gdk_gc_set_fill( m_bgGC, GDK_STIPPLED );
265898fd
RR
1877 int num = m_backgroundBrush.GetStyle() - wxBDIAGONAL_HATCH;
1878 gdk_gc_set_stipple( m_bgGC, hatches[num] );
bbbbe360 1879 }
903f689b 1880}
46dc76ba 1881
ec758a20 1882void wxWindowDC::SetLogicalFunction( int function )
c801d85f 1883{
223d09f6 1884 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1885
72174350
VZ
1886 if (m_logicalFunction == function)
1887 return;
1888
1889 // VZ: shouldn't this be a CHECK?
1890 if (!m_window)
1891 return;
01eaf507 1892
2b5f62a0 1893 GdkFunction mode;
265898fd
RR
1894 switch (function)
1895 {
3c679789
RR
1896 case wxXOR: mode = GDK_XOR; break;
1897 case wxINVERT: mode = GDK_INVERT; break;
3c679789
RR
1898 case wxOR_REVERSE: mode = GDK_OR_REVERSE; break;
1899 case wxAND_REVERSE: mode = GDK_AND_REVERSE; break;
1900 case wxCLEAR: mode = GDK_CLEAR; break;
1901 case wxSET: mode = GDK_SET; break;
1902 case wxOR_INVERT: mode = GDK_OR_INVERT; break;
1903 case wxAND: mode = GDK_AND; break;
1904 case wxOR: mode = GDK_OR; break;
1905 case wxEQUIV: mode = GDK_EQUIV; break;
1906 case wxNAND: mode = GDK_NAND; break;
1907 case wxAND_INVERT: mode = GDK_AND_INVERT; break;
7d5af6fa
VZ
1908 case wxCOPY: mode = GDK_COPY; break;
1909 case wxNO_OP: mode = GDK_NOOP; break;
1910 case wxSRC_INVERT: mode = GDK_COPY_INVERT; break;
72174350 1911
2d52841d
RR
1912 // unsupported by GTK
1913 case wxNOR: mode = GDK_COPY; break;
01eaf507 1914 default:
223d09f6 1915 wxFAIL_MSG( wxT("unsupported logical function") );
2b5f62a0 1916 mode = GDK_COPY;
265898fd 1917 }
7d5af6fa 1918
265898fd 1919 m_logicalFunction = function;
7d5af6fa 1920
265898fd
RR
1921 gdk_gc_set_function( m_penGC, mode );
1922 gdk_gc_set_function( m_brushGC, mode );
72174350
VZ
1923
1924 // to stay compatible with wxMSW, we don't apply ROPs to the text
3d2d8da1
RR
1925 // operations (i.e. DrawText/DrawRotatedText).
1926 // True, but mono-bitmaps use the m_textGC and they use ROPs as well.
1927 gdk_gc_set_function( m_textGC, mode );
903f689b 1928}
c801d85f 1929
ec758a20 1930void wxWindowDC::SetTextForeground( const wxColour &col )
c801d85f 1931{
223d09f6 1932 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1933
71ec83d2
VZ
1934 // don't set m_textForegroundColour to an invalid colour as we'd crash
1935 // later then (we use m_textForegroundColour.GetColor() without checking
1936 // in a few places)
1937 if ( !col.Ok() || (m_textForegroundColour == col) )
1938 return;
7d5af6fa 1939
265898fd 1940 m_textForegroundColour = col;
7d5af6fa 1941
71ec83d2
VZ
1942 if ( m_window )
1943 {
1944 m_textForegroundColour.CalcPixel( m_cmap );
1945 gdk_gc_set_foreground( m_textGC, m_textForegroundColour.GetColor() );
1946 }
903f689b 1947}
c801d85f 1948
ec758a20 1949void wxWindowDC::SetTextBackground( const wxColour &col )
c801d85f 1950{
223d09f6 1951 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1952
71ec83d2
VZ
1953 // same as above
1954 if ( !col.Ok() || (m_textBackgroundColour == col) )
1955 return;
7d5af6fa 1956
265898fd 1957 m_textBackgroundColour = col;
7d5af6fa 1958
71ec83d2
VZ
1959 if ( m_window )
1960 {
1961 m_textBackgroundColour.CalcPixel( m_cmap );
1962 gdk_gc_set_background( m_textGC, m_textBackgroundColour.GetColor() );
1963 }
903f689b 1964}
c801d85f 1965
ec758a20 1966void wxWindowDC::SetBackgroundMode( int mode )
c801d85f 1967{
223d09f6 1968 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1969
265898fd 1970 m_backgroundMode = mode;
46dc76ba 1971
6db90681 1972 if (!m_window) return;
7d5af6fa 1973
265898fd
RR
1974 // CMB 21/7/98: fill style of cross-hatch brushes is affected by
1975 // transparent/solid background mode
7d5af6fa 1976
265898fd
RR
1977 if (m_brush.GetStyle() != wxSOLID && m_brush.GetStyle() != wxTRANSPARENT)
1978 {
1979 gdk_gc_set_fill( m_brushGC,
1980 (m_backgroundMode == wxTRANSPARENT) ? GDK_STIPPLED : GDK_OPAQUE_STIPPLED);
1981 }
903f689b 1982}
c801d85f 1983
ec758a20 1984void wxWindowDC::SetPalette( const wxPalette& WXUNUSED(palette) )
c801d85f 1985{
223d09f6 1986 wxFAIL_MSG( wxT("wxWindowDC::SetPalette not implemented") );
903f689b 1987}
c801d85f 1988
72cdf4c9 1989void wxWindowDC::DoSetClippingRegion( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
c801d85f 1990{
223d09f6 1991 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1992
6db90681 1993 if (!m_window) return;
7d5af6fa 1994
3d2d8da1 1995 wxRect rect;
265898fd
RR
1996 rect.x = XLOG2DEV(x);
1997 rect.y = YLOG2DEV(y);
1998 rect.width = XLOG2DEVREL(width);
1999 rect.height = YLOG2DEVREL(height);
5f170f33 2000
e1208c31 2001 if (!m_currentClippingRegion.IsNull())
993f97ee
RR
2002 m_currentClippingRegion.Intersect( rect );
2003 else
2004 m_currentClippingRegion.Union( rect );
5f170f33
VZ
2005
2006#if USE_PAINT_REGION
e1208c31 2007 if (!m_paintClippingRegion.IsNull())
3d2d8da1 2008 m_currentClippingRegion.Intersect( m_paintClippingRegion );
809934d2 2009#endif
3d2d8da1 2010
ee8dbe63
RL
2011 wxCoord xx, yy, ww, hh;
2012 m_currentClippingRegion.GetBox( xx, yy, ww, hh );
2013 wxDC::DoSetClippingRegion( xx, yy, ww, hh );
2014
3d2d8da1
RR
2015 gdk_gc_set_clip_region( m_penGC, m_currentClippingRegion.GetRegion() );
2016 gdk_gc_set_clip_region( m_brushGC, m_currentClippingRegion.GetRegion() );
2017 gdk_gc_set_clip_region( m_textGC, m_currentClippingRegion.GetRegion() );
2018 gdk_gc_set_clip_region( m_bgGC, m_currentClippingRegion.GetRegion() );
903f689b 2019}
c801d85f 2020
b0e0d661 2021void wxWindowDC::DoSetClippingRegionAsRegion( const wxRegion &region )
463c1fa1 2022{
223d09f6 2023 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 2024
463c1fa1
RR
2025 if (region.Empty())
2026 {
2027 DestroyClippingRegion();
2028 return;
2029 }
7d5af6fa 2030
6db90681 2031 if (!m_window) return;
5f170f33 2032
e1208c31 2033 if (!m_currentClippingRegion.IsNull())
993f97ee
RR
2034 m_currentClippingRegion.Intersect( region );
2035 else
2036 m_currentClippingRegion.Union( region );
5f170f33
VZ
2037
2038#if USE_PAINT_REGION
e1208c31 2039 if (!m_paintClippingRegion.IsNull())
3d2d8da1 2040 m_currentClippingRegion.Intersect( m_paintClippingRegion );
809934d2 2041#endif
3d2d8da1 2042
ee8dbe63
RL
2043 wxCoord xx, yy, ww, hh;
2044 m_currentClippingRegion.GetBox( xx, yy, ww, hh );
2045 wxDC::DoSetClippingRegion( xx, yy, ww, hh );
2046
3d2d8da1
RR
2047 gdk_gc_set_clip_region( m_penGC, m_currentClippingRegion.GetRegion() );
2048 gdk_gc_set_clip_region( m_brushGC, m_currentClippingRegion.GetRegion() );
2049 gdk_gc_set_clip_region( m_textGC, m_currentClippingRegion.GetRegion() );
2050 gdk_gc_set_clip_region( m_bgGC, m_currentClippingRegion.GetRegion() );
463c1fa1
RR
2051}
2052
4bc67cc5 2053void wxWindowDC::DestroyClippingRegion()
c801d85f 2054{
223d09f6 2055 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 2056
265898fd 2057 wxDC::DestroyClippingRegion();
7d5af6fa 2058
3d2d8da1 2059 m_currentClippingRegion.Clear();
5f170f33
VZ
2060
2061#if USE_PAINT_REGION
3d2d8da1
RR
2062 if (!m_paintClippingRegion.IsEmpty())
2063 m_currentClippingRegion.Union( m_paintClippingRegion );
993f97ee 2064#endif
3d2d8da1 2065
6db90681 2066 if (!m_window) return;
7d5af6fa 2067
3d2d8da1
RR
2068 if (m_currentClippingRegion.IsEmpty())
2069 {
2070 gdk_gc_set_clip_rectangle( m_penGC, (GdkRectangle *) NULL );
2071 gdk_gc_set_clip_rectangle( m_brushGC, (GdkRectangle *) NULL );
2072 gdk_gc_set_clip_rectangle( m_textGC, (GdkRectangle *) NULL );
2073 gdk_gc_set_clip_rectangle( m_bgGC, (GdkRectangle *) NULL );
2074 }
2075 else
2076 {
2077 gdk_gc_set_clip_region( m_penGC, m_currentClippingRegion.GetRegion() );
2078 gdk_gc_set_clip_region( m_brushGC, m_currentClippingRegion.GetRegion() );
2079 gdk_gc_set_clip_region( m_textGC, m_currentClippingRegion.GetRegion() );
2080 gdk_gc_set_clip_region( m_bgGC, m_currentClippingRegion.GetRegion() );
2081 }
903f689b 2082}
c801d85f 2083
4bc67cc5 2084void wxWindowDC::Destroy()
dbf858b5 2085{
3d2d8da1 2086 if (m_penGC) wxFreePoolGC( m_penGC );
265898fd 2087 m_penGC = (GdkGC*) NULL;
3d2d8da1 2088 if (m_brushGC) wxFreePoolGC( m_brushGC );
265898fd 2089 m_brushGC = (GdkGC*) NULL;
3d2d8da1 2090 if (m_textGC) wxFreePoolGC( m_textGC );
265898fd 2091 m_textGC = (GdkGC*) NULL;
3d2d8da1 2092 if (m_bgGC) wxFreePoolGC( m_bgGC );
265898fd 2093 m_bgGC = (GdkGC*) NULL;
dbf858b5
RR
2094}
2095
238d735d
RR
2096void wxWindowDC::ComputeScaleAndOrigin()
2097{
c77a6796 2098 const wxRealPoint origScale(m_scaleX, m_scaleY);
238d735d
RR
2099
2100 wxDC::ComputeScaleAndOrigin();
2101
c77a6796
VZ
2102 // if scale has changed call SetPen to recalulate the line width
2103 if ( wxRealPoint(m_scaleX, m_scaleY) != origScale && m_pen.Ok() )
238d735d 2104 {
c77a6796
VZ
2105 // this is a bit artificial, but we need to force wxDC to think the pen
2106 // has changed
0a164d4c
WS
2107 wxPen pen = m_pen;
2108 m_pen = wxNullPen;
2109 SetPen( pen );
2110 }
238d735d
RR
2111}
2112
b0e0d661
VZ
2113// Resolution in pixels per logical inch
2114wxSize wxWindowDC::GetPPI() const
2115{
7a5e6267 2116 return wxSize( (int) (m_mm_to_pix_x * 25.4 + 0.5), (int) (m_mm_to_pix_y * 25.4 + 0.5));
b0e0d661
VZ
2117}
2118
2119int wxWindowDC::GetDepth() const
c801d85f 2120{
223d09f6 2121 wxFAIL_MSG(wxT("not implemented"));
b0e0d661
VZ
2122
2123 return -1;
903f689b 2124}
c801d85f 2125
ec758a20
RR
2126
2127//-----------------------------------------------------------------------------
2128// wxPaintDC
2129//-----------------------------------------------------------------------------
2130
f469b27c 2131IMPLEMENT_DYNAMIC_CLASS(wxPaintDC, wxClientDC)
ec758a20 2132
2cfddfe7
JS
2133// Limit the paint region to the window size. Sometimes
2134// the paint region is too big, and this risks X11 errors
2135static void wxLimitRegionToSize(wxRegion& region, const wxSize& sz)
2136{
2137 wxRect originalRect = region.GetBox();
2138 wxRect rect(originalRect);
2139 if (rect.width + rect.x > sz.x)
2140 rect.width = sz.x - rect.x;
2141 if (rect.height + rect.y > sz.y)
2142 rect.height = sz.y - rect.y;
2143 if (rect != originalRect)
2144 {
2145 region = wxRegion(rect);
2146 wxLogTrace(wxT("painting"), wxT("Limiting region from %d, %d, %d, %d to %d, %d, %d, %d\n"),
2147 originalRect.x, originalRect.y, originalRect.width, originalRect.height,
2148 rect.x, rect.y, rect.width, rect.height);
2149 }
2150}
2151
ec758a20 2152wxPaintDC::wxPaintDC( wxWindow *win )
f469b27c 2153 : wxClientDC( win )
ec758a20 2154{
b6fa52db
RR
2155#if USE_PAINT_REGION
2156 if (!win->m_clipPaintRegion)
2157 return;
f469b27c 2158
2cfddfe7 2159 wxSize sz = win->GetSize();
e1208c31 2160 m_paintClippingRegion = win->GetUpdateRegion();
2cfddfe7 2161 wxLimitRegionToSize(m_paintClippingRegion, sz);
ab9d0a8c 2162
5f170f33
VZ
2163 GdkRegion *region = m_paintClippingRegion.GetRegion();
2164 if ( region )
2165 {
823faac3 2166 m_currentClippingRegion.Union( m_paintClippingRegion );
2cfddfe7
JS
2167 wxLimitRegionToSize(m_currentClippingRegion, sz);
2168
2169 if (sz.x <= 0 || sz.y <= 0)
2170 return ;
5f170f33 2171
823faac3
JS
2172 gdk_gc_set_clip_region( m_penGC, region );
2173 gdk_gc_set_clip_region( m_brushGC, region );
2174 gdk_gc_set_clip_region( m_textGC, region );
2175 gdk_gc_set_clip_region( m_bgGC, region );
5f170f33 2176 }
1e6feb95 2177#endif // USE_PAINT_REGION
ec758a20
RR
2178}
2179
2180//-----------------------------------------------------------------------------
2181// wxClientDC
2182//-----------------------------------------------------------------------------
2183
f469b27c 2184IMPLEMENT_DYNAMIC_CLASS(wxClientDC, wxWindowDC)
ec758a20 2185
f469b27c
VZ
2186wxClientDC::wxClientDC( wxWindow *win )
2187 : wxWindowDC( win )
ec758a20 2188{
4f55a07f
VZ
2189 wxCHECK_RET( win, _T("NULL window in wxClientDC::wxClientDC") );
2190
1e6feb95
VZ
2191#ifdef __WXUNIVERSAL__
2192 wxPoint ptOrigin = win->GetClientAreaOrigin();
2193 SetDeviceOrigin(ptOrigin.x, ptOrigin.y);
2194 wxSize size = win->GetClientSize();
2195 SetClippingRegion(wxPoint(0, 0), size);
2196#endif // __WXUNIVERSAL__
ec758a20
RR
2197}
2198
4f55a07f
VZ
2199void wxClientDC::DoGetSize(int *width, int *height) const
2200{
2201 wxCHECK_RET( m_owner, _T("GetSize() doesn't work without window") );
2202
2203 m_owner->GetClientSize( width, height );
2204}
2205
3d2d8da1
RR
2206// ----------------------------------------------------------------------------
2207// wxDCModule
2208// ----------------------------------------------------------------------------
2209
2210class wxDCModule : public wxModule
2211{
2212public:
2213 bool OnInit();
2214 void OnExit();
2215
2216private:
2217 DECLARE_DYNAMIC_CLASS(wxDCModule)
2218};
2219
2220IMPLEMENT_DYNAMIC_CLASS(wxDCModule, wxModule)
2221
2222bool wxDCModule::OnInit()
2223{
2224 wxInitGCPool();
ab9d0a8c 2225 return true;
3d2d8da1
RR
2226}
2227
2228void wxDCModule::OnExit()
2229{
2230 wxCleanUpGCPool();
2231}