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