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