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