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