]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/dcclient.cpp
OS/2 updates for statusbar processing
[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 528 if (m_pen.GetStyle() != wxTRANSPARENT)
3d0c4d2e 529 {
6db90681 530 gdk_draw_arc( m_window, m_penGC, FALSE, xxc-r, yyc-r, 2*r,2*r, alpha1, alpha2 );
3d0c4d2e
RR
531
532 gdk_draw_line( m_window, m_penGC, xx1, yy1, xxc, yyc );
533 gdk_draw_line( m_window, m_penGC, xxc, yyc, xx2, yy2 );
534 }
6db90681 535 }
7d5af6fa 536
265898fd
RR
537 CalcBoundingBox (x1, y1);
538 CalcBoundingBox (x2, y2);
903f689b 539}
c801d85f 540
72cdf4c9 541void wxWindowDC::DoDrawEllipticArc( wxCoord x, wxCoord y, wxCoord width, wxCoord height, double sa, double ea )
c801d85f 542{
223d09f6 543 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 544
72cdf4c9
VZ
545 wxCoord xx = XLOG2DEV(x);
546 wxCoord yy = YLOG2DEV(y);
547 wxCoord ww = m_signX * XLOG2DEVREL(width);
548 wxCoord hh = m_signY * YLOG2DEVREL(height);
7d5af6fa 549
265898fd
RR
550 // CMB: handle -ve width and/or height
551 if (ww < 0) { ww = -ww; xx = xx - ww; }
552 if (hh < 0) { hh = -hh; yy = yy - hh; }
7d5af6fa 553
6db90681
RR
554 if (m_window)
555 {
72cdf4c9 556 wxCoord start = wxCoord(sa * 64.0);
3d0c4d2e 557 wxCoord end = wxCoord((ea-sa) * 64.0);
7d5af6fa 558
6db90681 559 if (m_brush.GetStyle() != wxTRANSPARENT)
e9f88d04
VZ
560 {
561 if ((m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE) && (m_brush.GetStipple()->GetMask()))
562 {
563 gdk_gc_set_ts_origin( m_textGC,
564 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
565 m_deviceOriginY % m_brush.GetStipple()->GetHeight() );
566 gdk_draw_arc( m_window, m_textGC, TRUE, xx, yy, ww, hh, start, end );
567 gdk_gc_set_ts_origin( m_textGC, 0, 0 );
568 } else
3ca6a5f0
BP
569 if (IS_15_PIX_HATCH(m_brush.GetStyle()))
570 {
571 gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 15, m_deviceOriginY % 15 );
572 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, start, end );
573 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
574 } else
575 if (IS_16_PIX_HATCH(m_brush.GetStyle()))
576 {
577 gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 16, m_deviceOriginY % 16 );
578 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, start, end );
579 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
580 } else
e9f88d04
VZ
581 if (m_brush.GetStyle() == wxSTIPPLE)
582 {
583 gdk_gc_set_ts_origin( m_brushGC,
584 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
585 m_deviceOriginY % m_brush.GetStipple()->GetHeight() );
586 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, start, end );
587 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
588 }
589 else
590 {
591 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, start, end );
592 }
593 }
7d5af6fa 594
6db90681
RR
595 if (m_pen.GetStyle() != wxTRANSPARENT)
596 gdk_draw_arc( m_window, m_penGC, FALSE, xx, yy, ww, hh, start, end );
597 }
7d5af6fa 598
265898fd
RR
599 CalcBoundingBox (x, y);
600 CalcBoundingBox (x + width, y + height);
903f689b 601}
c801d85f 602
72cdf4c9 603void wxWindowDC::DoDrawPoint( wxCoord x, wxCoord y )
c801d85f 604{
223d09f6 605 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 606
6db90681 607 if ((m_pen.GetStyle() != wxTRANSPARENT) && m_window)
265898fd 608 gdk_draw_point( m_window, m_penGC, XLOG2DEV(x), YLOG2DEV(y) );
7d5af6fa 609
265898fd 610 CalcBoundingBox (x, y);
903f689b 611}
c801d85f 612
72cdf4c9 613void wxWindowDC::DoDrawLines( int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset )
c801d85f 614{
223d09f6 615 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 616
265898fd
RR
617 if (m_pen.GetStyle() == wxTRANSPARENT) return;
618 if (n <= 0) return;
7d5af6fa 619
265898fd 620 CalcBoundingBox( points[0].x + xoffset, points[0].y + yoffset );
7d5af6fa 621
265898fd
RR
622 for (int i = 0; i < n-1; i++)
623 {
72cdf4c9
VZ
624 wxCoord x1 = XLOG2DEV(points[i].x + xoffset);
625 wxCoord x2 = XLOG2DEV(points[i+1].x + xoffset);
626 wxCoord y1 = YLOG2DEV(points[i].y + yoffset); // oh, what a waste
627 wxCoord y2 = YLOG2DEV(points[i+1].y + yoffset);
7d5af6fa
VZ
628
629 if (m_window)
6db90681 630 gdk_draw_line( m_window, m_penGC, x1, y1, x2, y2 );
7d5af6fa 631
265898fd
RR
632 CalcBoundingBox( points[i+1].x + xoffset, points[i+1].y + yoffset );
633 }
903f689b 634}
c801d85f 635
72cdf4c9 636void wxWindowDC::DoDrawPolygon( int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset, int WXUNUSED(fillStyle) )
cf7a7e13 637{
223d09f6 638 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 639
4bc67cc5 640 if (n <= 0) return;
7d5af6fa 641
265898fd
RR
642 GdkPoint *gdkpoints = new GdkPoint[n+1];
643 int i;
644 for (i = 0 ; i < n ; i++)
645 {
646 gdkpoints[i].x = XLOG2DEV(points[i].x + xoffset);
647 gdkpoints[i].y = YLOG2DEV(points[i].y + yoffset);
7d5af6fa 648
265898fd
RR
649 CalcBoundingBox( points[i].x + xoffset, points[i].y + yoffset );
650 }
7d5af6fa 651
de2d2cdc 652 if (m_window)
72174350 653 {
e1208c31 654 if (m_brush.GetStyle() != wxTRANSPARENT)
72174350 655 {
e1208c31
RR
656 if ((m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE) && (m_brush.GetStipple()->GetMask()))
657 {
5f170f33
VZ
658 gdk_gc_set_ts_origin( m_textGC,
659 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
e1208c31
RR
660 m_deviceOriginY % m_brush.GetStipple()->GetHeight() );
661 gdk_draw_polygon( m_window, m_textGC, TRUE, gdkpoints, n );
662 gdk_gc_set_ts_origin( m_textGC, 0, 0 );
663 } else
3ca6a5f0
BP
664 if (IS_15_PIX_HATCH(m_brush.GetStyle()))
665 {
666 gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 15, m_deviceOriginY % 15 );
667 gdk_draw_polygon( m_window, m_brushGC, TRUE, gdkpoints, n );
668 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
669 } else
670 if (IS_16_PIX_HATCH(m_brush.GetStyle()))
671 {
672 gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 16, m_deviceOriginY % 16 );
673 gdk_draw_polygon( m_window, m_brushGC, TRUE, gdkpoints, n );
674 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
675 } else
e1208c31
RR
676 if (m_brush.GetStyle() == wxSTIPPLE)
677 {
5f170f33
VZ
678 gdk_gc_set_ts_origin( m_brushGC,
679 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
e1208c31
RR
680 m_deviceOriginY % m_brush.GetStipple()->GetHeight() );
681 gdk_draw_polygon( m_window, m_brushGC, TRUE, gdkpoints, n );
682 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
683 }
684 else
685 {
686 gdk_draw_polygon( m_window, m_brushGC, TRUE, gdkpoints, n );
687 }
72174350 688 }
7d5af6fa 689
e1208c31 690 if (m_pen.GetStyle() != wxTRANSPARENT)
b0e0d661 691 {
e1208c31
RR
692 for (i = 0 ; i < n ; i++)
693 {
694 gdk_draw_line( m_window, m_penGC,
695 gdkpoints[i%n].x,
696 gdkpoints[i%n].y,
697 gdkpoints[(i+1)%n].x,
698 gdkpoints[(i+1)%n].y);
699 }
265898fd 700 }
6db90681 701 }
7d5af6fa 702
265898fd 703 delete[] gdkpoints;
903f689b 704}
c801d85f 705
72cdf4c9 706void wxWindowDC::DoDrawRectangle( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
c801d85f 707{
223d09f6 708 wxCHECK_RET( Ok(), wxT("invalid window dc") );
c801d85f 709
72cdf4c9
VZ
710 wxCoord xx = XLOG2DEV(x);
711 wxCoord yy = YLOG2DEV(y);
712 wxCoord ww = m_signX * XLOG2DEVREL(width);
713 wxCoord hh = m_signY * YLOG2DEVREL(height);
7d5af6fa 714
265898fd
RR
715 // CMB: draw nothing if transformed w or h is 0
716 if (ww == 0 || hh == 0) return;
6f65e337 717
265898fd
RR
718 // CMB: handle -ve width and/or height
719 if (ww < 0) { ww = -ww; xx = xx - ww; }
720 if (hh < 0) { hh = -hh; yy = yy - hh; }
6f65e337 721
6db90681
RR
722 if (m_window)
723 {
e1208c31 724 if (m_brush.GetStyle() != wxTRANSPARENT)
72174350 725 {
e1208c31
RR
726 if ((m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE) && (m_brush.GetStipple()->GetMask()))
727 {
5f170f33
VZ
728 gdk_gc_set_ts_origin( m_textGC,
729 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
e1208c31
RR
730 m_deviceOriginY % m_brush.GetStipple()->GetHeight() );
731 gdk_draw_rectangle( m_window, m_textGC, TRUE, xx, yy, ww, hh );
732 gdk_gc_set_ts_origin( m_textGC, 0, 0 );
3ca6a5f0
BP
733 } else
734 if (IS_15_PIX_HATCH(m_brush.GetStyle()))
735 {
736 gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 15, m_deviceOriginY % 15 );
737 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx, yy, ww, hh );
738 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
739 } else
740 if (IS_16_PIX_HATCH(m_brush.GetStyle()))
741 {
742 gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 16, m_deviceOriginY % 16 );
743 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx, yy, ww, hh );
744 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
745 } else
746 if (m_brush.GetStyle() == wxSTIPPLE)
e1208c31 747 {
5f170f33
VZ
748 gdk_gc_set_ts_origin( m_brushGC,
749 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
e1208c31 750 m_deviceOriginY % m_brush.GetStipple()->GetHeight() );
72174350 751 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx, yy, ww, hh );
e1208c31
RR
752 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
753 }
754 else
755 {
756 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx, yy, ww, hh );
757 }
72174350 758 }
e1208c31
RR
759
760 if (m_pen.GetStyle() != wxTRANSPARENT)
761 gdk_draw_rectangle( m_window, m_penGC, FALSE, xx, yy, ww-1, hh-1 );
6db90681 762 }
7d5af6fa 763
265898fd
RR
764 CalcBoundingBox( x, y );
765 CalcBoundingBox( x + width, y + height );
903f689b 766}
c801d85f 767
72cdf4c9 768void wxWindowDC::DoDrawRoundedRectangle( wxCoord x, wxCoord y, wxCoord width, wxCoord height, double radius )
c801d85f 769{
223d09f6 770 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 771
265898fd 772 if (radius < 0.0) radius = - radius * ((width < height) ? width : height);
7d5af6fa 773
72cdf4c9
VZ
774 wxCoord xx = XLOG2DEV(x);
775 wxCoord yy = YLOG2DEV(y);
776 wxCoord ww = m_signX * XLOG2DEVREL(width);
777 wxCoord hh = m_signY * YLOG2DEVREL(height);
778 wxCoord rr = XLOG2DEVREL((wxCoord)radius);
265898fd
RR
779
780 // CMB: handle -ve width and/or height
781 if (ww < 0) { ww = -ww; xx = xx - ww; }
782 if (hh < 0) { hh = -hh; yy = yy - hh; }
783
784 // CMB: if radius is zero use DrawRectangle() instead to avoid
785 // X drawing errors with small radii
786 if (rr == 0)
787 {
788 DrawRectangle( x, y, width, height );
789 return;
790 }
791
792 // CMB: draw nothing if transformed w or h is 0
793 if (ww == 0 || hh == 0) return;
794
795 // CMB: adjust size if outline is drawn otherwise the result is
796 // 1 pixel too wide and high
797 if (m_pen.GetStyle() != wxTRANSPARENT)
798 {
799 ww--;
800 hh--;
801 }
802
6db90681 803 if (m_window)
265898fd 804 {
6db90681
RR
805 // CMB: ensure dd is not larger than rectangle otherwise we
806 // get an hour glass shape
72cdf4c9 807 wxCoord dd = 2 * rr;
6db90681
RR
808 if (dd > ww) dd = ww;
809 if (dd > hh) dd = hh;
810 rr = dd / 2;
811
812 if (m_brush.GetStyle() != wxTRANSPARENT)
813 {
a56fcaaf
RR
814 if ((m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE) && (m_brush.GetStipple()->GetMask()))
815 {
5f170f33
VZ
816 gdk_gc_set_ts_origin( m_textGC,
817 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
a56fcaaf
RR
818 m_deviceOriginY % m_brush.GetStipple()->GetHeight() );
819 gdk_draw_rectangle( m_window, m_textGC, TRUE, xx+rr, yy, ww-dd+1, hh );
820 gdk_draw_rectangle( m_window, m_textGC, TRUE, xx, yy+rr, ww, hh-dd+1 );
821 gdk_draw_arc( m_window, m_textGC, TRUE, xx, yy, dd, dd, 90*64, 90*64 );
822 gdk_draw_arc( m_window, m_textGC, TRUE, xx+ww-dd, yy, dd, dd, 0, 90*64 );
823 gdk_draw_arc( m_window, m_textGC, TRUE, xx+ww-dd, yy+hh-dd, dd, dd, 270*64, 90*64 );
824 gdk_draw_arc( m_window, m_textGC, TRUE, xx, yy+hh-dd, dd, dd, 180*64, 90*64 );
825 gdk_gc_set_ts_origin( m_textGC, 0, 0 );
3ca6a5f0
BP
826 } else
827 if (IS_15_PIX_HATCH(m_brush.GetStyle()))
828 {
829 gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 15, m_deviceOriginY % 15 );
830 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx+rr, yy, ww-dd+1, hh );
831 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx, yy+rr, ww, hh-dd+1 );
832 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, dd, dd, 90*64, 90*64 );
833 gdk_draw_arc( m_window, m_brushGC, TRUE, xx+ww-dd, yy, dd, dd, 0, 90*64 );
834 gdk_draw_arc( m_window, m_brushGC, TRUE, xx+ww-dd, yy+hh-dd, dd, dd, 270*64, 90*64 );
835 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy+hh-dd, dd, dd, 180*64, 90*64 );
836 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
837 } else
838 if (IS_16_PIX_HATCH(m_brush.GetStyle()))
839 {
840 gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 16, m_deviceOriginY % 16 );
841 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx+rr, yy, ww-dd+1, hh );
842 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx, yy+rr, ww, hh-dd+1 );
843 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, dd, dd, 90*64, 90*64 );
844 gdk_draw_arc( m_window, m_brushGC, TRUE, xx+ww-dd, yy, dd, dd, 0, 90*64 );
845 gdk_draw_arc( m_window, m_brushGC, TRUE, xx+ww-dd, yy+hh-dd, dd, dd, 270*64, 90*64 );
846 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy+hh-dd, dd, dd, 180*64, 90*64 );
847 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
848 } else
849 if (m_brush.GetStyle() == wxSTIPPLE)
a56fcaaf 850 {
5f170f33
VZ
851 gdk_gc_set_ts_origin( m_brushGC,
852 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
a56fcaaf
RR
853 m_deviceOriginY % m_brush.GetStipple()->GetHeight() );
854 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx+rr, yy, ww-dd+1, hh );
855 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx, yy+rr, ww, hh-dd+1 );
856 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, dd, dd, 90*64, 90*64 );
857 gdk_draw_arc( m_window, m_brushGC, TRUE, xx+ww-dd, yy, dd, dd, 0, 90*64 );
858 gdk_draw_arc( m_window, m_brushGC, TRUE, xx+ww-dd, yy+hh-dd, dd, dd, 270*64, 90*64 );
859 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy+hh-dd, dd, dd, 180*64, 90*64 );
860 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
861 }
862 else
863 {
864 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx+rr, yy, ww-dd+1, hh );
865 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx, yy+rr, ww, hh-dd+1 );
866 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, dd, dd, 90*64, 90*64 );
867 gdk_draw_arc( m_window, m_brushGC, TRUE, xx+ww-dd, yy, dd, dd, 0, 90*64 );
868 gdk_draw_arc( m_window, m_brushGC, TRUE, xx+ww-dd, yy+hh-dd, dd, dd, 270*64, 90*64 );
869 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy+hh-dd, dd, dd, 180*64, 90*64 );
870 }
6db90681 871 }
7d5af6fa 872
6db90681 873 if (m_pen.GetStyle() != wxTRANSPARENT)
7d5af6fa 874 {
3ca6a5f0
BP
875 gdk_draw_line( m_window, m_penGC, xx+rr+1, yy, xx+ww-rr, yy );
876 gdk_draw_line( m_window, m_penGC, xx+rr+1, yy+hh, xx+ww-rr, yy+hh );
877 gdk_draw_line( m_window, m_penGC, xx, yy+rr+1, xx, yy+hh-rr );
878 gdk_draw_line( m_window, m_penGC, xx+ww, yy+rr+1, xx+ww, yy+hh-rr );
6db90681
RR
879 gdk_draw_arc( m_window, m_penGC, FALSE, xx, yy, dd, dd, 90*64, 90*64 );
880 gdk_draw_arc( m_window, m_penGC, FALSE, xx+ww-dd, yy, dd, dd, 0, 90*64 );
881 gdk_draw_arc( m_window, m_penGC, FALSE, xx+ww-dd, yy+hh-dd, dd, dd, 270*64, 90*64 );
882 gdk_draw_arc( m_window, m_penGC, FALSE, xx, yy+hh-dd, dd, dd, 180*64, 90*64 );
7d5af6fa 883 }
265898fd 884 }
7d5af6fa 885
265898fd
RR
886 // this ignores the radius
887 CalcBoundingBox( x, y );
888 CalcBoundingBox( x + width, y + height );
903f689b 889}
c801d85f 890
72cdf4c9 891void wxWindowDC::DoDrawEllipse( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
c801d85f 892{
223d09f6 893 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 894
72cdf4c9
VZ
895 wxCoord xx = XLOG2DEV(x);
896 wxCoord yy = YLOG2DEV(y);
897 wxCoord ww = m_signX * XLOG2DEVREL(width);
898 wxCoord hh = m_signY * YLOG2DEVREL(height);
6f65e337 899
265898fd
RR
900 // CMB: handle -ve width and/or height
901 if (ww < 0) { ww = -ww; xx = xx - ww; }
902 if (hh < 0) { hh = -hh; yy = yy - hh; }
7d5af6fa 903
6db90681
RR
904 if (m_window)
905 {
906 if (m_brush.GetStyle() != wxTRANSPARENT)
a56fcaaf
RR
907 {
908 if ((m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE) && (m_brush.GetStipple()->GetMask()))
909 {
5f170f33
VZ
910 gdk_gc_set_ts_origin( m_textGC,
911 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
a56fcaaf
RR
912 m_deviceOriginY % m_brush.GetStipple()->GetHeight() );
913 gdk_draw_arc( m_window, m_textGC, TRUE, xx, yy, ww, hh, 0, 360*64 );
914 gdk_gc_set_ts_origin( m_textGC, 0, 0 );
3ca6a5f0
BP
915 } else
916 if (IS_15_PIX_HATCH(m_brush.GetStyle()))
917 {
918 gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 15, m_deviceOriginY % 15 );
919 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, 0, 360*64 );
920 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
921 } else
922 if (IS_16_PIX_HATCH(m_brush.GetStyle()))
923 {
924 gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 16, m_deviceOriginY % 16 );
925 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, 0, 360*64 );
926 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
927 } else
928 if (m_brush.GetStyle() == wxSTIPPLE)
a56fcaaf 929 {
5f170f33
VZ
930 gdk_gc_set_ts_origin( m_brushGC,
931 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
a56fcaaf
RR
932 m_deviceOriginY % m_brush.GetStipple()->GetHeight() );
933 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, 0, 360*64 );
934 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
935 }
936 else
937 {
938 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, 0, 360*64 );
939 }
940 }
7d5af6fa 941
6db90681
RR
942 if (m_pen.GetStyle() != wxTRANSPARENT)
943 gdk_draw_arc( m_window, m_penGC, FALSE, xx, yy, ww, hh, 0, 360*64 );
944 }
7d5af6fa 945
ed880dd4 946 CalcBoundingBox( x - width, y - height );
265898fd 947 CalcBoundingBox( x + width, y + height );
903f689b 948}
c801d85f 949
72cdf4c9 950void wxWindowDC::DoDrawIcon( const wxIcon &icon, wxCoord x, wxCoord y )
c801d85f 951{
b0e0d661
VZ
952 // VZ: egcs 1.0.3 refuses to compile this without cast, no idea why
953 DoDrawBitmap( (const wxBitmap&)icon, x, y, (bool)TRUE );
903f689b 954}
c801d85f 955
b0e0d661 956void wxWindowDC::DoDrawBitmap( const wxBitmap &bitmap,
72cdf4c9 957 wxCoord x, wxCoord y,
b0e0d661 958 bool useMask )
4bc67cc5 959{
223d09f6 960 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 961
223d09f6 962 wxCHECK_RET( bitmap.Ok(), wxT("invalid bitmap") );
7d5af6fa 963
cf214c35 964 bool is_mono = (bitmap.GetBitmap() != NULL);
82ea63e6 965
6e13c196 966 /* scale/translate size and position */
265898fd
RR
967 int xx = XLOG2DEV(x);
968 int yy = YLOG2DEV(y);
7d5af6fa 969
4bc67cc5
RR
970 int w = bitmap.GetWidth();
971 int h = bitmap.GetHeight();
7d5af6fa 972
6453876e
RR
973 CalcBoundingBox( x, y );
974 CalcBoundingBox( x + w, y + h );
7d5af6fa 975
6453876e 976 if (!m_window) return;
7d5af6fa 977
4bc67cc5
RR
978 int ww = XLOG2DEVREL(w);
979 int hh = YLOG2DEVREL(h);
7d5af6fa 980
3d2d8da1 981 /* compare to current clipping region */
e1208c31 982 if (!m_currentClippingRegion.IsNull())
3d2d8da1
RR
983 {
984 wxRegion tmp( xx,yy,ww,hh );
985 tmp.Intersect( m_currentClippingRegion );
986 if (tmp.IsEmpty())
987 return;
988 }
5f170f33 989
6e13c196 990 /* scale bitmap if required */
4bc67cc5 991 wxBitmap use_bitmap;
4bc67cc5 992 if ((w != ww) || (h != hh))
265898fd 993 {
4bc67cc5 994 wxImage image( bitmap );
82ea63e6
RR
995 image.Rescale( ww, hh );
996 if (is_mono)
997 use_bitmap = image.ConvertToMonoBitmap(255,255,255);
998 else
999 use_bitmap = image.ConvertToBitmap();
265898fd 1000 }
4bc67cc5 1001 else
265898fd 1002 {
4bc67cc5 1003 use_bitmap = bitmap;
265898fd 1004 }
7d5af6fa 1005
6e13c196 1006 /* apply mask if any */
463c1fa1 1007 GdkBitmap *mask = (GdkBitmap *) NULL;
4bc67cc5 1008 if (use_bitmap.GetMask()) mask = use_bitmap.GetMask()->GetBitmap();
7d5af6fa 1009
3d2d8da1 1010 if (useMask && mask)
82ea63e6 1011 {
3d2d8da1 1012 GdkBitmap *new_mask = (GdkBitmap*) NULL;
e1208c31 1013 if (!m_currentClippingRegion.IsNull())
3d2d8da1
RR
1014 {
1015 GdkColor col;
1016 new_mask = gdk_pixmap_new( wxRootWindow->window, ww, hh, 1 );
1017 GdkGC *gc = gdk_gc_new( new_mask );
1018 col.pixel = 0;
1019 gdk_gc_set_foreground( gc, &col );
1020 gdk_draw_rectangle( new_mask, gc, TRUE, 0, 0, ww, hh );
1021 col.pixel = 0;
1022 gdk_gc_set_background( gc, &col );
1023 col.pixel = 1;
1024 gdk_gc_set_foreground( gc, &col );
1025 gdk_gc_set_clip_region( gc, m_currentClippingRegion.GetRegion() );
1026 gdk_gc_set_clip_origin( gc, -xx, -yy );
1027 gdk_gc_set_fill( gc, GDK_OPAQUE_STIPPLED );
1028 gdk_gc_set_stipple( gc, mask );
1029 gdk_draw_rectangle( new_mask, gc, TRUE, 0, 0, ww, hh );
1030 gdk_gc_unref( gc );
1031 }
5f170f33 1032
3d2d8da1
RR
1033 if (is_mono)
1034 {
1035 if (new_mask)
1036 gdk_gc_set_clip_mask( m_textGC, new_mask );
1037 else
1038 gdk_gc_set_clip_mask( m_textGC, mask );
1039 gdk_gc_set_clip_origin( m_textGC, xx, yy );
1040 }
1041 else
1042 {
1043 if (new_mask)
1044 gdk_gc_set_clip_mask( m_penGC, new_mask );
1045 else
1046 gdk_gc_set_clip_mask( m_penGC, mask );
1047 gdk_gc_set_clip_origin( m_penGC, xx, yy );
1048 }
1049 if (new_mask)
1050 gdk_bitmap_unref( new_mask );
b0e0d661 1051 }
7d5af6fa 1052
82ea63e6
RR
1053 /* Draw XPixmap or XBitmap, depending on what the wxBitmap contains. For
1054 drawing a mono-bitmap (XBitmap) we use the current text GC */
1055 if (is_mono)
f6bcfd97 1056 gdk_wx_draw_bitmap( m_window, m_textGC, use_bitmap.GetBitmap(), 0, 0, xx, yy, -1, -1 );
82ea63e6
RR
1057 else
1058 gdk_draw_pixmap( m_window, m_penGC, use_bitmap.GetPixmap(), 0, 0, xx, yy, -1, -1 );
72174350 1059
6e13c196 1060 /* remove mask again if any */
7d5af6fa 1061 if (useMask && mask)
463c1fa1 1062 {
82ea63e6
RR
1063 if (is_mono)
1064 {
1065 gdk_gc_set_clip_mask( m_textGC, (GdkBitmap *) NULL );
1066 gdk_gc_set_clip_origin( m_textGC, 0, 0 );
e1208c31 1067 if (!m_currentClippingRegion.IsNull())
3d2d8da1 1068 gdk_gc_set_clip_region( m_textGC, m_currentClippingRegion.GetRegion() );
82ea63e6
RR
1069 }
1070 else
1071 {
1072 gdk_gc_set_clip_mask( m_penGC, (GdkBitmap *) NULL );
1073 gdk_gc_set_clip_origin( m_penGC, 0, 0 );
e1208c31 1074 if (!m_currentClippingRegion.IsNull())
3d2d8da1 1075 gdk_gc_set_clip_region( m_penGC, m_currentClippingRegion.GetRegion() );
82ea63e6 1076 }
463c1fa1 1077 }
463c1fa1
RR
1078}
1079
72cdf4c9
VZ
1080bool wxWindowDC::DoBlit( wxCoord xdest, wxCoord ydest, wxCoord width, wxCoord height,
1081 wxDC *source, wxCoord xsrc, wxCoord ysrc,
b0e0d661 1082 int logical_func, bool useMask )
c801d85f 1083{
6e13c196
RR
1084 /* this is the nth try to get this utterly useless function to
1085 work. it now completely ignores the scaling or translation
1086 of the source dc, but scales correctly on the target dc and
1087 knows about possible mask information in a memory dc. */
1088
223d09f6 1089 wxCHECK_MSG( Ok(), FALSE, wxT("invalid window dc") );
7d5af6fa 1090
223d09f6 1091 wxCHECK_MSG( source, FALSE, wxT("invalid source dc") );
7d5af6fa 1092
6db90681 1093 if (!m_window) return FALSE;
7d5af6fa 1094
6e13c196
RR
1095 wxClientDC *srcDC = (wxClientDC*)source;
1096 wxMemoryDC *memDC = (wxMemoryDC*)source;
7d5af6fa 1097
6e13c196 1098 bool use_bitmap_method = FALSE;
82ea63e6 1099 bool is_mono = FALSE;
7d5af6fa 1100
6e13c196
RR
1101 if (srcDC->m_isMemDC)
1102 {
b0e0d661 1103 if (!memDC->m_selected.Ok()) return FALSE;
7d5af6fa 1104
6e13c196 1105 /* we use the "XCopyArea" way to copy a memory dc into
b0e0d661
VZ
1106 y different window if the memory dc BOTH
1107 a) doesn't have any mask or its mask isn't used
1108 b) it is clipped
1109 c) is not 1-bit */
7d5af6fa 1110
f234c60c 1111 if (useMask && (memDC->m_selected.GetMask()))
b0e0d661
VZ
1112 {
1113 /* we HAVE TO use the direct way for memory dcs
1114 that have mask since the XCopyArea doesn't know
1115 about masks */
1116 use_bitmap_method = TRUE;
1117 }
1118 else if (memDC->m_selected.GetDepth() == 1)
1119 {
1120 /* we HAVE TO use the direct way for memory dcs
1121 that are bitmaps because XCopyArea doesn't cope
1122 with different bit depths */
82ea63e6 1123 is_mono = TRUE;
b0e0d661
VZ
1124 use_bitmap_method = TRUE;
1125 }
1126 else if ((xsrc == 0) && (ysrc == 0) &&
1127 (width == memDC->m_selected.GetWidth()) &&
1128 (height == memDC->m_selected.GetHeight()))
1129 {
7d5af6fa
VZ
1130 /* we SHOULD use the direct way if all of the bitmap
1131 in the memory dc is copied in which case XCopyArea
1132 wouldn't be able able to boost performace by reducing
b0e0d661
VZ
1133 the area to be scaled */
1134 use_bitmap_method = TRUE;
1135 }
1136 else
1137 {
1138 use_bitmap_method = FALSE;
1139 }
6e13c196 1140 }
7d5af6fa 1141
265898fd
RR
1142 CalcBoundingBox( xdest, ydest );
1143 CalcBoundingBox( xdest + width, ydest + height );
7d5af6fa 1144
3d2d8da1
RR
1145 /* scale/translate size and position */
1146 wxCoord xx = XLOG2DEV(xdest);
1147 wxCoord yy = YLOG2DEV(ydest);
1148
1149 wxCoord ww = XLOG2DEVREL(width);
1150 wxCoord hh = YLOG2DEVREL(height);
1151
1152 /* compare to current clipping region */
e1208c31 1153 if (!m_currentClippingRegion.IsNull())
3d2d8da1
RR
1154 {
1155 wxRegion tmp( xx,yy,ww,hh );
1156 tmp.Intersect( m_currentClippingRegion );
1157 if (tmp.IsEmpty())
1158 return TRUE;
1159 }
1160
4bc67cc5
RR
1161 int old_logical_func = m_logicalFunction;
1162 SetLogicalFunction( logical_func );
5f170f33 1163
6e13c196 1164 if (use_bitmap_method)
6f65e337 1165 {
6e13c196 1166 /* scale/translate bitmap size */
72cdf4c9
VZ
1167 wxCoord bm_width = memDC->m_selected.GetWidth();
1168 wxCoord bm_height = memDC->m_selected.GetHeight();
7d5af6fa 1169
72cdf4c9
VZ
1170 wxCoord bm_ww = XLOG2DEVREL( bm_width );
1171 wxCoord bm_hh = YLOG2DEVREL( bm_height );
7d5af6fa 1172
6e13c196 1173 /* scale bitmap if required */
6e13c196 1174 wxBitmap use_bitmap;
7d5af6fa 1175
6e13c196
RR
1176 if ((bm_width != bm_ww) || (bm_height != bm_hh))
1177 {
1178 wxImage image( memDC->m_selected );
b0e0d661 1179 image = image.Scale( bm_ww, bm_hh );
7d5af6fa 1180
82ea63e6
RR
1181 if (is_mono)
1182 use_bitmap = image.ConvertToMonoBitmap(255,255,255);
1183 else
1184 use_bitmap = image.ConvertToBitmap();
6e13c196
RR
1185 }
1186 else
e23d0e95 1187 {
6e13c196
RR
1188 use_bitmap = memDC->m_selected;
1189 }
7d5af6fa 1190
6e13c196 1191 /* apply mask if any */
6e13c196
RR
1192 GdkBitmap *mask = (GdkBitmap *) NULL;
1193 if (use_bitmap.GetMask()) mask = use_bitmap.GetMask()->GetBitmap();
7d5af6fa
VZ
1194
1195 if (useMask && mask)
6e13c196 1196 {
3d2d8da1 1197 GdkBitmap *new_mask = (GdkBitmap*) NULL;
e1208c31 1198 if (!m_currentClippingRegion.IsNull())
3d2d8da1
RR
1199 {
1200 GdkColor col;
1201 new_mask = gdk_pixmap_new( wxRootWindow->window, bm_ww, bm_hh, 1 );
1202 GdkGC *gc = gdk_gc_new( new_mask );
1203 col.pixel = 0;
1204 gdk_gc_set_foreground( gc, &col );
1205 gdk_draw_rectangle( new_mask, gc, TRUE, 0, 0, bm_ww, bm_hh );
1206 col.pixel = 0;
1207 gdk_gc_set_background( gc, &col );
1208 col.pixel = 1;
1209 gdk_gc_set_foreground( gc, &col );
1210 gdk_gc_set_clip_region( gc, m_currentClippingRegion.GetRegion() );
1211 gdk_gc_set_clip_origin( gc, -xx, -yy );
1212 gdk_gc_set_fill( gc, GDK_OPAQUE_STIPPLED );
1213 gdk_gc_set_stipple( gc, mask );
1214 gdk_draw_rectangle( new_mask, gc, TRUE, 0, 0, bm_ww, bm_hh );
1215 gdk_gc_unref( gc );
1216 }
5f170f33 1217
82ea63e6
RR
1218 if (is_mono)
1219 {
3d2d8da1
RR
1220 if (new_mask)
1221 gdk_gc_set_clip_mask( m_textGC, new_mask );
1222 else
1223 gdk_gc_set_clip_mask( m_textGC, mask );
82ea63e6
RR
1224 gdk_gc_set_clip_origin( m_textGC, xx, yy );
1225 }
1226 else
6e13c196 1227 {
3d2d8da1
RR
1228 if (new_mask)
1229 gdk_gc_set_clip_mask( m_penGC, new_mask );
1230 else
1231 gdk_gc_set_clip_mask( m_penGC, mask );
82ea63e6 1232 gdk_gc_set_clip_origin( m_penGC, xx, yy );
b0e0d661 1233 }
3d2d8da1
RR
1234 if (new_mask)
1235 gdk_bitmap_unref( new_mask );
6e13c196 1236 }
7d5af6fa 1237
82ea63e6
RR
1238 /* Draw XPixmap or XBitmap, depending on what the wxBitmap contains. For
1239 drawing a mono-bitmap (XBitmap) we use the current text GC */
5f170f33 1240
82ea63e6 1241 if (is_mono)
f6bcfd97 1242 gdk_wx_draw_bitmap( m_window, m_textGC, use_bitmap.GetBitmap(), xsrc, ysrc, xx, yy, ww, hh );
82ea63e6
RR
1243 else
1244 gdk_draw_pixmap( m_window, m_penGC, use_bitmap.GetPixmap(), xsrc, ysrc, xx, yy, ww, hh );
1245
6e13c196 1246 /* remove mask again if any */
7d5af6fa 1247 if (useMask && mask)
6e13c196 1248 {
82ea63e6
RR
1249 if (is_mono)
1250 {
1251 gdk_gc_set_clip_mask( m_textGC, (GdkBitmap *) NULL );
1252 gdk_gc_set_clip_origin( m_textGC, 0, 0 );
e1208c31 1253 if (!m_currentClippingRegion.IsNull())
3d2d8da1 1254 gdk_gc_set_clip_region( m_textGC, m_currentClippingRegion.GetRegion() );
82ea63e6
RR
1255 }
1256 else
1257 {
1258 gdk_gc_set_clip_mask( m_penGC, (GdkBitmap *) NULL );
1259 gdk_gc_set_clip_origin( m_penGC, 0, 0 );
e1208c31 1260 if (!m_currentClippingRegion.IsNull())
3d2d8da1 1261 gdk_gc_set_clip_region( m_penGC, m_currentClippingRegion.GetRegion() );
82ea63e6 1262 }
265898fd 1263 }
6f65e337 1264 }
6e13c196
RR
1265 else /* use_bitmap_method */
1266 {
6e13c196 1267 if ((width != ww) || (height != hh))
b0e0d661
VZ
1268 {
1269 /* draw source window into a bitmap as we cannot scale
1270 a window in contrast to a bitmap. this would actually
1271 work with memory dcs as well, but we'd lose the mask
1272 information and waste one step in this process since
1273 a memory already has a bitmap. all this is slightly
1274 inefficient as we could take an XImage directly from
1275 an X window, but we'd then also have to care that
1276 the window is not outside the screen (in which case
1277 we'd get a BadMatch or what not).
1278 Is a double XGetImage and combined XGetPixel and
1279 XPutPixel really faster? I'm not sure. look at wxXt
1280 for a different implementation of the same problem. */
7d5af6fa 1281
b0e0d661 1282 wxBitmap bitmap( width, height );
5f170f33 1283
a56fcaaf
RR
1284 /* copy including child window contents */
1285 gdk_gc_set_subwindow( m_penGC, GDK_INCLUDE_INFERIORS );
e1208c31 1286 gdk_window_copy_area( bitmap.GetPixmap(), m_penGC, 0, 0,
6e13c196 1287 srcDC->GetWindow(),
b0e0d661 1288 xsrc, ysrc, width, height );
a56fcaaf 1289 gdk_gc_set_subwindow( m_penGC, GDK_CLIP_BY_CHILDREN );
5f170f33 1290
b0e0d661 1291 /* scale image */
6e13c196 1292 wxImage image( bitmap );
b0e0d661 1293 image = image.Scale( ww, hh );
7d5af6fa 1294
b0e0d661 1295 /* convert to bitmap */
b0e0d661 1296 bitmap = image.ConvertToBitmap();
7d5af6fa 1297
b0e0d661 1298 /* draw scaled bitmap */
6e13c196 1299 gdk_draw_pixmap( m_window, m_penGC, bitmap.GetPixmap(), 0, 0, xx, yy, -1, -1 );
7d5af6fa 1300
b0e0d661
VZ
1301 }
1302 else
1303 {
993f97ee
RR
1304 /* No scaling and not a memory dc with a mask either */
1305
a56fcaaf
RR
1306 /* copy including child window contents */
1307 gdk_gc_set_subwindow( m_penGC, GDK_INCLUDE_INFERIORS );
6e13c196
RR
1308 gdk_window_copy_area( m_window, m_penGC, xx, yy,
1309 srcDC->GetWindow(),
1310 xsrc, ysrc, width, height );
a56fcaaf 1311 gdk_gc_set_subwindow( m_penGC, GDK_CLIP_BY_CHILDREN );
b0e0d661 1312 }
6e13c196 1313 }
c801d85f 1314
4bc67cc5
RR
1315 SetLogicalFunction( old_logical_func );
1316 return TRUE;
903f689b 1317}
c801d85f 1318
72cdf4c9 1319void wxWindowDC::DoDrawText( const wxString &text, wxCoord x, wxCoord y )
c801d85f 1320{
223d09f6 1321 wxCHECK_RET( Ok(), wxT("invalid window dc") );
18a2fa37 1322
6db90681 1323 if (!m_window) return;
7d5af6fa 1324
265898fd 1325 GdkFont *font = m_font.GetInternalFont( m_scaleY );
6f65e337 1326
a1fffa9f
VZ
1327 wxCHECK_RET( font, wxT("invalid font") );
1328
8943b403
OK
1329#ifdef __WXGTK20__
1330 wxCHECK_RET( m_context, wxT("no Pango context") );
1331#endif
1332
265898fd
RR
1333 x = XLOG2DEV(x);
1334 y = YLOG2DEV(y);
18a2fa37 1335
8943b403
OK
1336#ifdef __WXGTK20__
1337 /* FIXME: the layout engine should probably be abstracted at a higher level in wxDC... */
1338 PangoLayout *layout = pango_layout_new(m_context);
1339 pango_layout_set_font_description(layout, m_fontdesc);
1340 {
1341 wxWX2MBbuf data = text.mb_str(wxConvUTF8);
1342 pango_layout_set_text(layout, data, strlen(data));
1343 }
1344 PangoLayoutLine *line = (PangoLayoutLine *)pango_layout_get_lines(layout)->data;
1345 PangoRectangle rect;
1346 pango_layout_line_get_extents(line, NULL, &rect);
1347 wxCoord width = rect.width;
1348 wxCoord height = rect.height;
1349 gdk_draw_layout( m_window, m_textGC, x, y, layout );
1350#else
1351 wxCoord width = gdk_string_width( font, text.mbc_str() );
1352 wxCoord height = font->ascent + font->descent;
bbbbe360 1353 /* CMB 21/5/98: draw text background if mode is wxSOLID */
265898fd
RR
1354 if (m_backgroundMode == wxSOLID)
1355 {
265898fd
RR
1356 gdk_gc_set_foreground( m_textGC, m_textBackgroundColour.GetColor() );
1357 gdk_draw_rectangle( m_window, m_textGC, TRUE, x, y, width, height );
1358 gdk_gc_set_foreground( m_textGC, m_textForegroundColour.GetColor() );
1359 }
93c5dd39 1360 gdk_draw_string( m_window, font, m_textGC, x, y + font->ascent, text.mbc_str() );
8943b403 1361#endif
18a2fa37 1362
bbbbe360
RR
1363 /* CMB 17/7/98: simple underline: ignores scaling and underlying
1364 X font's XA_UNDERLINE_POSITION and XA_UNDERLINE_THICKNESS
1365 properties (see wxXt implementation) */
265898fd
RR
1366 if (m_font.GetUnderlined())
1367 {
13111b2a 1368 wxCoord ul_y = y + font->ascent;
265898fd
RR
1369 if (font->descent > 0) ul_y++;
1370 gdk_draw_line( m_window, m_textGC, x, ul_y, x + width, ul_y);
1371 }
7d5af6fa 1372
8943b403
OK
1373#ifdef __WXGTK20__
1374 g_object_unref( G_OBJECT( layout ) );
1375#endif
1376
1377 width = wxCoord(width / m_scaleX);
1378 height = wxCoord(height / m_scaleY);
1379 CalcBoundingBox (x + width, y + height);
265898fd 1380 CalcBoundingBox (x, y);
903f689b 1381}
c801d85f 1382
95724b1a
VZ
1383void wxWindowDC::DoDrawRotatedText( const wxString &text, wxCoord x, wxCoord y, double angle )
1384{
1385 if (angle == 0.0)
1386 {
1387 DrawText(text, x, y);
1388 return;
1389 }
1390
1391 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1392
1393 if (!m_window) return;
1394
1395 GdkFont *font = m_font.GetInternalFont( m_scaleY );
1396
1397 wxCHECK_RET( font, wxT("invalid font") );
1398
9a8c7620 1399 // the size of the text
13111b2a
VZ
1400 wxCoord w = gdk_string_width( font, text.mbc_str() );
1401 wxCoord h = font->ascent + font->descent;
95724b1a 1402
9a8c7620
VZ
1403 // draw the string normally
1404 wxBitmap src(w, h);
95724b1a
VZ
1405 wxMemoryDC dc;
1406 dc.SelectObject(src);
1407 dc.SetFont(GetFont());
1408 dc.SetBackground(*wxWHITE_BRUSH);
1409 dc.SetBrush(*wxBLACK_BRUSH);
1410 dc.Clear();
1411 dc.DrawText(text, 0, 0);
1412 dc.SetFont(wxNullFont);
9a8c7620 1413 dc.SelectObject(wxNullBitmap);
95724b1a
VZ
1414
1415 // Calculate the size of the rotated bounding box.
9a8c7620
VZ
1416 double rad = DegToRad(angle);
1417 double dx = cos(rad),
1418 dy = sin(rad);
1419
1420 // the rectngle vertices are counted clockwise with the first one being at
1421 // (0, 0) (or, rather, at (x, y))
1422 double x2 = w*dx,
1423 y2 = -w*dy; // y axis points to the bottom, hence minus
1424 double x4 = h*dy,
1425 y4 = h*dx;
1426 double x3 = x4 + x2,
1427 y3 = y4 + y2;
1428
72174350 1429 // calc max and min
9a8c7620
VZ
1430 wxCoord maxX = (wxCoord)(dmax(x2, dmax(x3, x4)) + 0.5),
1431 maxY = (wxCoord)(dmax(y2, dmax(y3, y4)) + 0.5),
1432 minX = (wxCoord)(dmin(x2, dmin(x3, x4)) - 0.5),
1433 minY = (wxCoord)(dmin(y2, dmin(y3, y4)) - 0.5);
1434
1435 // prepare to blit-with-rotate the bitmap to the DC
1436 wxImage image(src);
1437
1438 GdkColor *colText = m_textForegroundColour.GetColor(),
1439 *colBack = m_textBackgroundColour.GetColor();
72174350 1440
9a8c7620
VZ
1441 bool textColSet = TRUE;
1442
1443 unsigned char *data = image.GetData();
1444
1445 // paint pixel by pixel
1446 for ( wxCoord srcX = 0; srcX < w; srcX++ )
95724b1a 1447 {
9a8c7620 1448 for ( wxCoord srcY = 0; srcY < h; srcY++ )
95724b1a 1449 {
9a8c7620 1450 // transform source coords to dest coords
f6bcfd97
BP
1451 double r = sqrt((double)srcX*srcX + srcY*srcY);
1452 double angleOrig = atan2((double)srcY, (double)srcX) - rad;
9a8c7620
VZ
1453 wxCoord dstX = (wxCoord)(r*cos(angleOrig) + 0.5),
1454 dstY = (wxCoord)(r*sin(angleOrig) + 0.5);
1455
1456 // black pixel?
1457 bool textPixel = data[(srcY*w + srcX)*3] == 0;
1458 if ( textPixel || (m_backgroundMode == wxSOLID) )
95724b1a 1459 {
9a8c7620
VZ
1460 // change colour if needed
1461 if ( textPixel != textColSet )
95724b1a 1462 {
9a8c7620
VZ
1463 gdk_gc_set_foreground( m_textGC, textPixel ? colText
1464 : colBack );
1465
1466 textColSet = textPixel;
95724b1a 1467 }
9a8c7620
VZ
1468
1469 // don't use DrawPoint() because it uses the current pen
1470 // colour, and we don't need it here
1471 gdk_draw_point( m_window, m_textGC,
1472 XLOG2DEV(x + dstX), YLOG2DEV(y + dstY) );
95724b1a
VZ
1473 }
1474 }
1475 }
1476
9a8c7620
VZ
1477 // it would be better to draw with non underlined font and draw the line
1478 // manually here (it would be more straight...)
1479#if 0
1480 if ( m_font.GetUnderlined() )
1481 {
1482 gdk_draw_line( m_window, m_textGC,
1483 XLOG2DEV(x + x4), YLOG2DEV(y + y4 + font->descent),
1484 XLOG2DEV(x + x3), YLOG2DEV(y + y3 + font->descent));
1485 }
1486#endif // 0
1487
1488 // restore the font colour
1489 gdk_gc_set_foreground( m_textGC, colText );
1490
1491 // update the bounding box
1492 CalcBoundingBox(x + minX, y + minY);
1493 CalcBoundingBox(x + maxX, y + maxY);
95724b1a
VZ
1494}
1495
72cdf4c9
VZ
1496void wxWindowDC::DoGetTextExtent(const wxString &string,
1497 wxCoord *width, wxCoord *height,
1498 wxCoord *descent, wxCoord *externalLeading,
1499 wxFont *theFont) const
c801d85f 1500{
265898fd
RR
1501 wxFont fontToUse = m_font;
1502 if (theFont) fontToUse = *theFont;
7d5af6fa 1503
265898fd 1504 GdkFont *font = fontToUse.GetInternalFont( m_scaleY );
72cdf4c9
VZ
1505 if (width) (*width) = wxCoord(gdk_string_width( font, string.mbc_str() ) / m_scaleX);
1506 if (height) (*height) = wxCoord((font->ascent + font->descent) / m_scaleY);
1507 if (descent) (*descent) = wxCoord(font->descent / m_scaleY);
265898fd 1508 if (externalLeading) (*externalLeading) = 0; // ??
903f689b 1509}
c801d85f 1510
72cdf4c9 1511wxCoord wxWindowDC::GetCharWidth() const
c801d85f 1512{
265898fd 1513 GdkFont *font = m_font.GetInternalFont( m_scaleY );
58c837a4 1514 wxCHECK_MSG( font, -1, wxT("invalid font") );
7beba2fc 1515
72cdf4c9 1516 return wxCoord(gdk_string_width( font, "H" ) / m_scaleX);
903f689b 1517}
c801d85f 1518
72cdf4c9 1519wxCoord wxWindowDC::GetCharHeight() const
c801d85f 1520{
265898fd 1521 GdkFont *font = m_font.GetInternalFont( m_scaleY );
58c837a4 1522 wxCHECK_MSG( font, -1, wxT("invalid font") );
7beba2fc 1523
72cdf4c9 1524 return wxCoord((font->ascent + font->descent) / m_scaleY);
903f689b 1525}
c801d85f 1526
4bc67cc5 1527void wxWindowDC::Clear()
c801d85f 1528{
223d09f6 1529 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1530
6db90681 1531 if (!m_window) return;
7d5af6fa 1532
f234c60c
RR
1533 /* - we either are a memory dc or have a window as the
1534 owner. anything else shouldn't happen.
1535 - we don't use gdk_window_clear() as we don't set
1536 the window's background colour anymore. it is too
1537 much pain to keep the DC's and the window's back-
1538 ground colour in synch. */
7d5af6fa 1539
f234c60c 1540 if (m_owner)
265898fd 1541 {
f234c60c
RR
1542 int width,height;
1543 m_owner->GetSize( &width, &height );
1544 gdk_draw_rectangle( m_window, m_bgGC, TRUE, 0, 0, width, height );
b0e0d661 1545 return;
265898fd 1546 }
f234c60c
RR
1547
1548 if (m_isMemDC)
265898fd
RR
1549 {
1550 int width,height;
1551 GetSize( &width, &height );
1552 gdk_draw_rectangle( m_window, m_bgGC, TRUE, 0, 0, width, height );
b0e0d661 1553 return;
265898fd 1554 }
903f689b 1555}
c801d85f 1556
ec758a20 1557void wxWindowDC::SetFont( const wxFont &font )
c801d85f 1558{
265898fd 1559 m_font = font;
8943b403
OK
1560#ifdef __WXGTK20__
1561 // fix fontdesc?
1562#endif
903f689b 1563}
c801d85f 1564
ec758a20 1565void wxWindowDC::SetPen( const wxPen &pen )
c801d85f 1566{
223d09f6 1567 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1568
265898fd 1569 if (m_pen == pen) return;
7d5af6fa 1570
265898fd 1571 m_pen = pen;
7d5af6fa 1572
265898fd 1573 if (!m_pen.Ok()) return;
7d5af6fa 1574
6db90681 1575 if (!m_window) return;
7d5af6fa 1576
265898fd 1577 gint width = m_pen.GetWidth();
265898fd
RR
1578 if (width <= 0)
1579 {
112c5086 1580 // CMB: if width is non-zero scale it with the dc
265898fd
RR
1581 width = 1;
1582 }
1583 else
1584 {
1585 // X doesn't allow different width in x and y and so we take
1586 // the average
503f414e
VZ
1587 double w = 0.5 +
1588 ( fabs((double) XLOG2DEVREL(width)) +
1589 fabs((double) YLOG2DEVREL(width)) ) / 2.0;
265898fd
RR
1590 width = (int)w;
1591 }
7d5af6fa 1592
2eca425d
RL
1593 static const wxGTKDash dotted[] = {1, 1};
1594 static const wxGTKDash short_dashed[] = {2, 2};
1595 static const wxGTKDash wxCoord_dashed[] = {2, 4};
1596 static const wxGTKDash dotted_dashed[] = {3, 3, 1, 3};
7d5af6fa 1597
112c5086
RR
1598 // We express dash pattern in pen width unit, so we are
1599 // independent of zoom factor and so on...
1600 int req_nb_dash;
2eca425d 1601 const wxGTKDash *req_dash;
7d5af6fa 1602
265898fd
RR
1603 GdkLineStyle lineStyle = GDK_LINE_SOLID;
1604 switch (m_pen.GetStyle())
1605 {
112c5086 1606 case wxUSER_DASH:
7d5af6fa
VZ
1607 {
1608 lineStyle = GDK_LINE_ON_OFF_DASH;
112c5086 1609 req_nb_dash = m_pen.GetDashCount();
2eca425d 1610 req_dash = (wxGTKDash*)m_pen.GetDash();
112c5086 1611 break;
7d5af6fa
VZ
1612 }
1613 case wxDOT:
1614 {
1615 lineStyle = GDK_LINE_ON_OFF_DASH;
112c5086
RR
1616 req_nb_dash = 2;
1617 req_dash = dotted;
7d5af6fa
VZ
1618 break;
1619 }
1620 case wxLONG_DASH:
1621 {
1622 lineStyle = GDK_LINE_ON_OFF_DASH;
112c5086 1623 req_nb_dash = 2;
72cdf4c9 1624 req_dash = wxCoord_dashed;
7d5af6fa
VZ
1625 break;
1626 }
1627 case wxSHORT_DASH:
1628 {
1629 lineStyle = GDK_LINE_ON_OFF_DASH;
112c5086
RR
1630 req_nb_dash = 2;
1631 req_dash = short_dashed;
7d5af6fa
VZ
1632 break;
1633 }
1634 case wxDOT_DASH:
1635 {
1636// lineStyle = GDK_LINE_DOUBLE_DASH;
1637 lineStyle = GDK_LINE_ON_OFF_DASH;
112c5086
RR
1638 req_nb_dash = 4;
1639 req_dash = dotted_dashed;
7d5af6fa
VZ
1640 break;
1641 }
1642
1643 case wxTRANSPARENT:
72174350 1644 case wxSTIPPLE_MASK_OPAQUE:
7d5af6fa
VZ
1645 case wxSTIPPLE:
1646 case wxSOLID:
1647 default:
1648 {
1649 lineStyle = GDK_LINE_SOLID;
2eca425d 1650 req_dash = (wxGTKDash*)NULL;
112c5086 1651 req_nb_dash = 0;
7d5af6fa
VZ
1652 break;
1653 }
265898fd 1654 }
7d5af6fa 1655
2eca425d 1656#if (GTK_MINOR_VERSION > 0) || (GTK_MAJOR_VERSION > 1)
112c5086
RR
1657 if (req_dash && req_nb_dash)
1658 {
2eca425d 1659 wxGTKDash *real_req_dash = new wxGTKDash[req_nb_dash];
112c5086
RR
1660 if (real_req_dash)
1661 {
1662 for (int i = 0; i < req_nb_dash; i++)
1663 real_req_dash[i] = req_dash[i] * width;
2eca425d 1664 gdk_gc_set_dashes( m_penGC, 0, real_req_dash, req_nb_dash );
112c5086
RR
1665 delete[] real_req_dash;
1666 }
1667 else
1668 {
1669 // No Memory. We use non-scaled dash pattern...
2eca425d 1670 gdk_gc_set_dashes( m_penGC, 0, (wxGTKDash*)req_dash, req_nb_dash );
112c5086
RR
1671 }
1672 }
953704c1 1673#endif
7d5af6fa 1674
265898fd
RR
1675 GdkCapStyle capStyle = GDK_CAP_ROUND;
1676 switch (m_pen.GetCap())
1677 {
265898fd
RR
1678 case wxCAP_PROJECTING: { capStyle = GDK_CAP_PROJECTING; break; }
1679 case wxCAP_BUTT: { capStyle = GDK_CAP_BUTT; break; }
d4aa3a4b
RR
1680 case wxCAP_ROUND:
1681 default:
72174350 1682 {
d4aa3a4b
RR
1683 if (width <= 1)
1684 {
1685 width = 0;
1686 capStyle = GDK_CAP_NOT_LAST;
1687 }
1688 else
1689 {
1690 capStyle = GDK_CAP_ROUND;
1691 }
72174350 1692 break;
d4aa3a4b 1693 }
265898fd 1694 }
7d5af6fa 1695
265898fd
RR
1696 GdkJoinStyle joinStyle = GDK_JOIN_ROUND;
1697 switch (m_pen.GetJoin())
1698 {
1699 case wxJOIN_BEVEL: { joinStyle = GDK_JOIN_BEVEL; break; }
265898fd 1700 case wxJOIN_MITER: { joinStyle = GDK_JOIN_MITER; break; }
d4aa3a4b
RR
1701 case wxJOIN_ROUND:
1702 default: { joinStyle = GDK_JOIN_ROUND; break; }
265898fd 1703 }
7d5af6fa 1704
265898fd 1705 gdk_gc_set_line_attributes( m_penGC, width, lineStyle, capStyle, joinStyle );
7d5af6fa 1706
265898fd
RR
1707 m_pen.GetColour().CalcPixel( m_cmap );
1708 gdk_gc_set_foreground( m_penGC, m_pen.GetColour().GetColor() );
903f689b 1709}
c801d85f 1710
ec758a20 1711void wxWindowDC::SetBrush( const wxBrush &brush )
c801d85f 1712{
223d09f6 1713 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1714
265898fd 1715 if (m_brush == brush) return;
7d5af6fa 1716
265898fd 1717 m_brush = brush;
7d5af6fa 1718
265898fd 1719 if (!m_brush.Ok()) return;
7d5af6fa 1720
6db90681 1721 if (!m_window) return;
7d5af6fa 1722
265898fd
RR
1723 m_brush.GetColour().CalcPixel( m_cmap );
1724 gdk_gc_set_foreground( m_brushGC, m_brush.GetColour().GetColor() );
7d5af6fa 1725
956dbab1 1726 gdk_gc_set_fill( m_brushGC, GDK_SOLID );
7d5af6fa 1727
4fcd73bd 1728 if ((m_brush.GetStyle() == wxSTIPPLE) && (m_brush.GetStipple()->Ok()))
265898fd 1729 {
4fcd73bd 1730 if (m_brush.GetStipple()->GetPixmap())
7d5af6fa 1731 {
956dbab1 1732 gdk_gc_set_fill( m_brushGC, GDK_TILED );
cd25b18c 1733 gdk_gc_set_tile( m_brushGC, m_brush.GetStipple()->GetPixmap() );
7d5af6fa 1734 }
b0e0d661 1735 else
7d5af6fa 1736 {
956dbab1 1737 gdk_gc_set_fill( m_brushGC, GDK_STIPPLED );
4fcd73bd 1738 gdk_gc_set_stipple( m_brushGC, m_brush.GetStipple()->GetBitmap() );
7d5af6fa 1739 }
265898fd 1740 }
7d5af6fa 1741
de2d2cdc
VZ
1742 if ((m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE) && (m_brush.GetStipple()->GetMask()))
1743 {
e1208c31
RR
1744 gdk_gc_set_fill( m_textGC, GDK_OPAQUE_STIPPLED);
1745 gdk_gc_set_stipple( m_textGC, m_brush.GetStipple()->GetMask()->GetBitmap() );
de2d2cdc
VZ
1746 }
1747
265898fd
RR
1748 if (IS_HATCH(m_brush.GetStyle()))
1749 {
956dbab1 1750 gdk_gc_set_fill( m_brushGC, GDK_STIPPLED );
265898fd
RR
1751 int num = m_brush.GetStyle() - wxBDIAGONAL_HATCH;
1752 gdk_gc_set_stipple( m_brushGC, hatches[num] );
1753 }
903f689b 1754}
c801d85f 1755
ec758a20 1756void wxWindowDC::SetBackground( const wxBrush &brush )
46dc76ba 1757{
bbbbe360
RR
1758 /* CMB 21/7/98: Added SetBackground. Sets background brush
1759 * for Clear() and bg colour for shapes filled with cross-hatch brush */
7d5af6fa 1760
223d09f6 1761 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1762
265898fd 1763 if (m_backgroundBrush == brush) return;
7d5af6fa 1764
265898fd 1765 m_backgroundBrush = brush;
7d5af6fa 1766
265898fd 1767 if (!m_backgroundBrush.Ok()) return;
7d5af6fa 1768
6db90681 1769 if (!m_window) return;
7d5af6fa 1770
265898fd
RR
1771 m_backgroundBrush.GetColour().CalcPixel( m_cmap );
1772 gdk_gc_set_background( m_brushGC, m_backgroundBrush.GetColour().GetColor() );
a802c3a1 1773 gdk_gc_set_background( m_penGC, m_backgroundBrush.GetColour().GetColor() );
031b2a7b 1774 gdk_gc_set_background( m_bgGC, m_backgroundBrush.GetColour().GetColor() );
265898fd 1775 gdk_gc_set_foreground( m_bgGC, m_backgroundBrush.GetColour().GetColor() );
3417c2cd
RR
1776
1777 gdk_gc_set_fill( m_bgGC, GDK_SOLID );
7d5af6fa 1778
cd25b18c 1779 if ((m_backgroundBrush.GetStyle() == wxSTIPPLE) && (m_backgroundBrush.GetStipple()->Ok()))
265898fd 1780 {
fd128b0c 1781 if (m_backgroundBrush.GetStipple()->GetPixmap())
7d5af6fa 1782 {
3417c2cd 1783 gdk_gc_set_fill( m_bgGC, GDK_TILED );
fd128b0c 1784 gdk_gc_set_tile( m_bgGC, m_backgroundBrush.GetStipple()->GetPixmap() );
7d5af6fa 1785 }
cd25b18c 1786 else
7d5af6fa 1787 {
3417c2cd 1788 gdk_gc_set_fill( m_bgGC, GDK_STIPPLED );
fd128b0c 1789 gdk_gc_set_stipple( m_bgGC, m_backgroundBrush.GetStipple()->GetBitmap() );
7d5af6fa 1790 }
265898fd 1791 }
7d5af6fa 1792
265898fd
RR
1793 if (IS_HATCH(m_backgroundBrush.GetStyle()))
1794 {
3417c2cd 1795 gdk_gc_set_fill( m_bgGC, GDK_STIPPLED );
265898fd
RR
1796 int num = m_backgroundBrush.GetStyle() - wxBDIAGONAL_HATCH;
1797 gdk_gc_set_stipple( m_bgGC, hatches[num] );
bbbbe360 1798 }
903f689b 1799}
46dc76ba 1800
ec758a20 1801void wxWindowDC::SetLogicalFunction( int function )
c801d85f 1802{
223d09f6 1803 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1804
72174350
VZ
1805 if (m_logicalFunction == function)
1806 return;
1807
1808 // VZ: shouldn't this be a CHECK?
1809 if (!m_window)
1810 return;
01eaf507 1811
265898fd
RR
1812 GdkFunction mode = GDK_COPY;
1813 switch (function)
1814 {
3c679789
RR
1815 case wxXOR: mode = GDK_XOR; break;
1816 case wxINVERT: mode = GDK_INVERT; break;
01eaf507 1817#if (GTK_MINOR_VERSION > 0)
3c679789
RR
1818 case wxOR_REVERSE: mode = GDK_OR_REVERSE; break;
1819 case wxAND_REVERSE: mode = GDK_AND_REVERSE; break;
1820 case wxCLEAR: mode = GDK_CLEAR; break;
1821 case wxSET: mode = GDK_SET; break;
1822 case wxOR_INVERT: mode = GDK_OR_INVERT; break;
1823 case wxAND: mode = GDK_AND; break;
1824 case wxOR: mode = GDK_OR; break;
1825 case wxEQUIV: mode = GDK_EQUIV; break;
1826 case wxNAND: mode = GDK_NAND; break;
1827 case wxAND_INVERT: mode = GDK_AND_INVERT; break;
7d5af6fa
VZ
1828 case wxCOPY: mode = GDK_COPY; break;
1829 case wxNO_OP: mode = GDK_NOOP; break;
1830 case wxSRC_INVERT: mode = GDK_COPY_INVERT; break;
72174350 1831
2d52841d
RR
1832 // unsupported by GTK
1833 case wxNOR: mode = GDK_COPY; break;
c96faa7c 1834#endif
01eaf507 1835 default:
7d5af6fa 1836 {
223d09f6 1837 wxFAIL_MSG( wxT("unsupported logical function") );
7d5af6fa
VZ
1838 break;
1839 }
265898fd 1840 }
7d5af6fa 1841
265898fd 1842 m_logicalFunction = function;
7d5af6fa 1843
265898fd
RR
1844 gdk_gc_set_function( m_penGC, mode );
1845 gdk_gc_set_function( m_brushGC, mode );
72174350
VZ
1846
1847 // to stay compatible with wxMSW, we don't apply ROPs to the text
3d2d8da1
RR
1848 // operations (i.e. DrawText/DrawRotatedText).
1849 // True, but mono-bitmaps use the m_textGC and they use ROPs as well.
1850 gdk_gc_set_function( m_textGC, mode );
903f689b 1851}
c801d85f 1852
ec758a20 1853void wxWindowDC::SetTextForeground( const wxColour &col )
c801d85f 1854{
223d09f6 1855 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1856
265898fd 1857 if (m_textForegroundColour == col) return;
7d5af6fa 1858
265898fd
RR
1859 m_textForegroundColour = col;
1860 if (!m_textForegroundColour.Ok()) return;
7d5af6fa 1861
6db90681 1862 if (!m_window) return;
7d5af6fa 1863
265898fd
RR
1864 m_textForegroundColour.CalcPixel( m_cmap );
1865 gdk_gc_set_foreground( m_textGC, m_textForegroundColour.GetColor() );
903f689b 1866}
c801d85f 1867
ec758a20 1868void wxWindowDC::SetTextBackground( const wxColour &col )
c801d85f 1869{
223d09f6 1870 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1871
265898fd 1872 if (m_textBackgroundColour == col) return;
7d5af6fa 1873
265898fd
RR
1874 m_textBackgroundColour = col;
1875 if (!m_textBackgroundColour.Ok()) return;
7d5af6fa 1876
6db90681 1877 if (!m_window) return;
7d5af6fa 1878
265898fd
RR
1879 m_textBackgroundColour.CalcPixel( m_cmap );
1880 gdk_gc_set_background( m_textGC, m_textBackgroundColour.GetColor() );
903f689b 1881}
c801d85f 1882
ec758a20 1883void wxWindowDC::SetBackgroundMode( int mode )
c801d85f 1884{
223d09f6 1885 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1886
265898fd 1887 m_backgroundMode = mode;
46dc76ba 1888
6db90681 1889 if (!m_window) return;
7d5af6fa 1890
265898fd
RR
1891 // CMB 21/7/98: fill style of cross-hatch brushes is affected by
1892 // transparent/solid background mode
7d5af6fa 1893
265898fd
RR
1894 if (m_brush.GetStyle() != wxSOLID && m_brush.GetStyle() != wxTRANSPARENT)
1895 {
1896 gdk_gc_set_fill( m_brushGC,
1897 (m_backgroundMode == wxTRANSPARENT) ? GDK_STIPPLED : GDK_OPAQUE_STIPPLED);
1898 }
903f689b 1899}
c801d85f 1900
ec758a20 1901void wxWindowDC::SetPalette( const wxPalette& WXUNUSED(palette) )
c801d85f 1902{
223d09f6 1903 wxFAIL_MSG( wxT("wxWindowDC::SetPalette not implemented") );
903f689b 1904}
c801d85f 1905
72cdf4c9 1906void wxWindowDC::DoSetClippingRegion( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
c801d85f 1907{
223d09f6 1908 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1909
6db90681 1910 if (!m_window) return;
7d5af6fa 1911
3d2d8da1 1912 wxRect rect;
265898fd
RR
1913 rect.x = XLOG2DEV(x);
1914 rect.y = YLOG2DEV(y);
1915 rect.width = XLOG2DEVREL(width);
1916 rect.height = YLOG2DEVREL(height);
5f170f33 1917
e1208c31 1918 if (!m_currentClippingRegion.IsNull())
993f97ee
RR
1919 m_currentClippingRegion.Intersect( rect );
1920 else
1921 m_currentClippingRegion.Union( rect );
5f170f33
VZ
1922
1923#if USE_PAINT_REGION
e1208c31 1924 if (!m_paintClippingRegion.IsNull())
3d2d8da1 1925 m_currentClippingRegion.Intersect( m_paintClippingRegion );
809934d2 1926#endif
3d2d8da1 1927
ee8dbe63
RL
1928 wxCoord xx, yy, ww, hh;
1929 m_currentClippingRegion.GetBox( xx, yy, ww, hh );
1930 wxDC::DoSetClippingRegion( xx, yy, ww, hh );
1931
3d2d8da1
RR
1932 gdk_gc_set_clip_region( m_penGC, m_currentClippingRegion.GetRegion() );
1933 gdk_gc_set_clip_region( m_brushGC, m_currentClippingRegion.GetRegion() );
1934 gdk_gc_set_clip_region( m_textGC, m_currentClippingRegion.GetRegion() );
1935 gdk_gc_set_clip_region( m_bgGC, m_currentClippingRegion.GetRegion() );
903f689b 1936}
c801d85f 1937
b0e0d661 1938void wxWindowDC::DoSetClippingRegionAsRegion( const wxRegion &region )
463c1fa1 1939{
223d09f6 1940 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1941
463c1fa1
RR
1942 if (region.Empty())
1943 {
1944 DestroyClippingRegion();
1945 return;
1946 }
7d5af6fa 1947
6db90681 1948 if (!m_window) return;
5f170f33 1949
e1208c31 1950 if (!m_currentClippingRegion.IsNull())
993f97ee
RR
1951 m_currentClippingRegion.Intersect( region );
1952 else
1953 m_currentClippingRegion.Union( region );
5f170f33
VZ
1954
1955#if USE_PAINT_REGION
e1208c31 1956 if (!m_paintClippingRegion.IsNull())
3d2d8da1 1957 m_currentClippingRegion.Intersect( m_paintClippingRegion );
809934d2 1958#endif
3d2d8da1 1959
ee8dbe63
RL
1960 wxCoord xx, yy, ww, hh;
1961 m_currentClippingRegion.GetBox( xx, yy, ww, hh );
1962 wxDC::DoSetClippingRegion( xx, yy, ww, hh );
1963
3d2d8da1
RR
1964 gdk_gc_set_clip_region( m_penGC, m_currentClippingRegion.GetRegion() );
1965 gdk_gc_set_clip_region( m_brushGC, m_currentClippingRegion.GetRegion() );
1966 gdk_gc_set_clip_region( m_textGC, m_currentClippingRegion.GetRegion() );
1967 gdk_gc_set_clip_region( m_bgGC, m_currentClippingRegion.GetRegion() );
463c1fa1
RR
1968}
1969
4bc67cc5 1970void wxWindowDC::DestroyClippingRegion()
c801d85f 1971{
223d09f6 1972 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1973
265898fd 1974 wxDC::DestroyClippingRegion();
7d5af6fa 1975
3d2d8da1 1976 m_currentClippingRegion.Clear();
5f170f33
VZ
1977
1978#if USE_PAINT_REGION
3d2d8da1
RR
1979 if (!m_paintClippingRegion.IsEmpty())
1980 m_currentClippingRegion.Union( m_paintClippingRegion );
993f97ee 1981#endif
3d2d8da1 1982
6db90681 1983 if (!m_window) return;
7d5af6fa 1984
3d2d8da1
RR
1985 if (m_currentClippingRegion.IsEmpty())
1986 {
1987 gdk_gc_set_clip_rectangle( m_penGC, (GdkRectangle *) NULL );
1988 gdk_gc_set_clip_rectangle( m_brushGC, (GdkRectangle *) NULL );
1989 gdk_gc_set_clip_rectangle( m_textGC, (GdkRectangle *) NULL );
1990 gdk_gc_set_clip_rectangle( m_bgGC, (GdkRectangle *) NULL );
1991 }
1992 else
1993 {
1994 gdk_gc_set_clip_region( m_penGC, m_currentClippingRegion.GetRegion() );
1995 gdk_gc_set_clip_region( m_brushGC, m_currentClippingRegion.GetRegion() );
1996 gdk_gc_set_clip_region( m_textGC, m_currentClippingRegion.GetRegion() );
1997 gdk_gc_set_clip_region( m_bgGC, m_currentClippingRegion.GetRegion() );
1998 }
903f689b 1999}
c801d85f 2000
4bc67cc5 2001void wxWindowDC::Destroy()
dbf858b5 2002{
3d2d8da1 2003 if (m_penGC) wxFreePoolGC( m_penGC );
265898fd 2004 m_penGC = (GdkGC*) NULL;
3d2d8da1 2005 if (m_brushGC) wxFreePoolGC( m_brushGC );
265898fd 2006 m_brushGC = (GdkGC*) NULL;
3d2d8da1 2007 if (m_textGC) wxFreePoolGC( m_textGC );
265898fd 2008 m_textGC = (GdkGC*) NULL;
3d2d8da1 2009 if (m_bgGC) wxFreePoolGC( m_bgGC );
265898fd 2010 m_bgGC = (GdkGC*) NULL;
dbf858b5
RR
2011}
2012
238d735d
RR
2013void wxWindowDC::ComputeScaleAndOrigin()
2014{
2015 /* CMB: copy scale to see if it changes */
2016 double origScaleX = m_scaleX;
2017 double origScaleY = m_scaleY;
2018
2019 wxDC::ComputeScaleAndOrigin();
2020
2021 /* CMB: if scale has changed call SetPen to recalulate the line width */
2022 if ((m_scaleX != origScaleX || m_scaleY != origScaleY) &&
2023 (m_pen.Ok()))
2024 {
2025 /* this is a bit artificial, but we need to force wxDC to think
2026 the pen has changed */
2027 wxPen pen = m_pen;
2028 m_pen = wxNullPen;
2029 SetPen( pen );
2030 }
2031}
2032
b0e0d661
VZ
2033// Resolution in pixels per logical inch
2034wxSize wxWindowDC::GetPPI() const
2035{
2036 return wxSize(100, 100);
2037}
2038
2039int wxWindowDC::GetDepth() const
c801d85f 2040{
223d09f6 2041 wxFAIL_MSG(wxT("not implemented"));
b0e0d661
VZ
2042
2043 return -1;
903f689b 2044}
c801d85f 2045
d54e4256 2046#if wxUSE_SPLINES
c801d85f
KB
2047// ----------------------------------- spline code ----------------------------------------
2048
2049void wx_quadratic_spline(double a1, double b1, double a2, double b2,
2050 double a3, double b3, double a4, double b4);
4bc67cc5 2051void wx_clear_stack();
c801d85f
KB
2052int wx_spline_pop(double *x1, double *y1, double *x2, double *y2, double *x3,
2053 double *y3, double *x4, double *y4);
2054void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3,
2055 double x4, double y4);
2056static bool wx_spline_add_point(double x, double y);
2057static void wx_spline_draw_point_array(wxDC *dc);
2058
2059wxList wx_spline_point_list;
2060
b0e0d661
VZ
2061#define half(z1, z2) ((z1+z2)/2.0)
2062#define THRESHOLD 5
c801d85f
KB
2063
2064/* iterative version */
2065
2066void wx_quadratic_spline(double a1, double b1, double a2, double b2, double a3, double b3, double a4,
2067 double b4)
2068{
2069 register double xmid, ymid;
2070 double x1, y1, x2, y2, x3, y3, x4, y4;
2071
2072 wx_clear_stack();
2073 wx_spline_push(a1, b1, a2, b2, a3, b3, a4, b4);
2074
2075 while (wx_spline_pop(&x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4)) {
2076 xmid = (double)half(x2, x3);
2077 ymid = (double)half(y2, y3);
b0e0d661
VZ
2078 if (fabs(x1 - xmid) < THRESHOLD && fabs(y1 - ymid) < THRESHOLD &&
2079 fabs(xmid - x4) < THRESHOLD && fabs(ymid - y4) < THRESHOLD) {
c801d85f
KB
2080 wx_spline_add_point( x1, y1 );
2081 wx_spline_add_point( xmid, ymid );
b0e0d661 2082 } else {
c801d85f
KB
2083 wx_spline_push(xmid, ymid, (double)half(xmid, x3), (double)half(ymid, y3),
2084 (double)half(x3, x4), (double)half(y3, y4), x4, y4);
2085 wx_spline_push(x1, y1, (double)half(x1, x2), (double)half(y1, y2),
2086 (double)half(x2, xmid), (double)half(y2, ymid), xmid, ymid);
b0e0d661 2087 }
c801d85f
KB
2088 }
2089}
2090
2091/* utilities used by spline drawing routines */
2092
2093typedef struct wx_spline_stack_struct {
2094 double x1, y1, x2, y2, x3, y3, x4, y4;
2095} Stack;
2096
2097#define SPLINE_STACK_DEPTH 20
2098static Stack wx_spline_stack[SPLINE_STACK_DEPTH];
2099static Stack *wx_stack_top;
2100static int wx_stack_count;
2101
4bc67cc5 2102void wx_clear_stack()
c801d85f
KB
2103{
2104 wx_stack_top = wx_spline_stack;
2105 wx_stack_count = 0;
2106}
2107
2108void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
2109{
2110 wx_stack_top->x1 = x1;
2111 wx_stack_top->y1 = y1;
2112 wx_stack_top->x2 = x2;
2113 wx_stack_top->y2 = y2;
2114 wx_stack_top->x3 = x3;
2115 wx_stack_top->y3 = y3;
2116 wx_stack_top->x4 = x4;
2117 wx_stack_top->y4 = y4;
2118 wx_stack_top++;
2119 wx_stack_count++;
2120}
2121
2122int wx_spline_pop(double *x1, double *y1, double *x2, double *y2,
2123 double *x3, double *y3, double *x4, double *y4)
2124{
2125 if (wx_stack_count == 0)
b0e0d661 2126 return (0);
c801d85f
KB
2127 wx_stack_top--;
2128 wx_stack_count--;
2129 *x1 = wx_stack_top->x1;
2130 *y1 = wx_stack_top->y1;
2131 *x2 = wx_stack_top->x2;
2132 *y2 = wx_stack_top->y2;
2133 *x3 = wx_stack_top->x3;
2134 *y3 = wx_stack_top->y3;
2135 *x4 = wx_stack_top->x4;
2136 *y4 = wx_stack_top->y4;
2137 return (1);
2138}
2139
2140static bool wx_spline_add_point(double x, double y)
2141{
2142 wxPoint *point = new wxPoint ;
2143 point->x = (int) x;
2144 point->y = (int) y;
2145 wx_spline_point_list.Append((wxObject*)point);
2146 return TRUE;
2147}
2148
2149static void wx_spline_draw_point_array(wxDC *dc)
2150{
2151 dc->DrawLines(&wx_spline_point_list, 0, 0 );
2152 wxNode *node = wx_spline_point_list.First();
2153 while (node)
2154 {
2155 wxPoint *point = (wxPoint *)node->Data();
2156 delete point;
2157 delete node;
2158 node = wx_spline_point_list.First();
2159 }
2160}
2161
b0e0d661 2162void wxWindowDC::DoDrawSpline( wxList *points )
c801d85f 2163{
223d09f6 2164 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 2165
c801d85f
KB
2166 wxPoint *p;
2167 double cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
2168 double x1, y1, x2, y2;
2169
2170 wxNode *node = points->First();
2171 p = (wxPoint *)node->Data();
2172
2173 x1 = p->x;
2174 y1 = p->y;
2175
2176 node = node->Next();
2177 p = (wxPoint *)node->Data();
2178
2179 x2 = p->x;
2180 y2 = p->y;
2181 cx1 = (double)((x1 + x2) / 2);
2182 cy1 = (double)((y1 + y2) / 2);
2183 cx2 = (double)((cx1 + x2) / 2);
2184 cy2 = (double)((cy1 + y2) / 2);
2185
2186 wx_spline_add_point(x1, y1);
2187
2188 while ((node = node->Next()) != NULL)
2189 {
2190 p = (wxPoint *)node->Data();
b0e0d661
VZ
2191 x1 = x2;
2192 y1 = y2;
2193 x2 = p->x;
2194 y2 = p->y;
c801d85f
KB
2195 cx4 = (double)(x1 + x2) / 2;
2196 cy4 = (double)(y1 + y2) / 2;
2197 cx3 = (double)(x1 + cx4) / 2;
2198 cy3 = (double)(y1 + cy4) / 2;
2199
2200 wx_quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4);
2201
b0e0d661
VZ
2202 cx1 = cx4;
2203 cy1 = cy4;
c801d85f
KB
2204 cx2 = (double)(cx1 + x2) / 2;
2205 cy2 = (double)(cy1 + y2) / 2;
2206 }
2207
2208 wx_spline_add_point( cx1, cy1 );
2209 wx_spline_add_point( x2, y2 );
2210
2211 wx_spline_draw_point_array( this );
903f689b 2212}
ec758a20 2213
b0e0d661 2214#endif // wxUSE_SPLINE
ec758a20
RR
2215
2216//-----------------------------------------------------------------------------
2217// wxPaintDC
2218//-----------------------------------------------------------------------------
2219
2220IMPLEMENT_DYNAMIC_CLASS(wxPaintDC,wxWindowDC)
2221
4bc67cc5 2222wxPaintDC::wxPaintDC()
ec758a20
RR
2223 : wxWindowDC()
2224{
2225}
2226
2227wxPaintDC::wxPaintDC( wxWindow *win )
2228 : wxWindowDC( win )
2229{
b6fa52db
RR
2230#if USE_PAINT_REGION
2231 if (!win->m_clipPaintRegion)
2232 return;
2233
e1208c31 2234 m_paintClippingRegion = win->GetUpdateRegion();
5f170f33
VZ
2235 GdkRegion *region = m_paintClippingRegion.GetRegion();
2236 if ( region )
2237 {
2238 m_currentClippingRegion.Union( m_paintClippingRegion );
2239
2240 gdk_gc_set_clip_region( m_penGC, region );
2241 gdk_gc_set_clip_region( m_brushGC, region );
2242 gdk_gc_set_clip_region( m_textGC, region );
2243 gdk_gc_set_clip_region( m_bgGC, region );
2244 }
809934d2 2245#endif
ec758a20
RR
2246}
2247
2248//-----------------------------------------------------------------------------
2249// wxClientDC
2250//-----------------------------------------------------------------------------
2251
2252IMPLEMENT_DYNAMIC_CLASS(wxClientDC,wxWindowDC)
2253
4bc67cc5 2254wxClientDC::wxClientDC()
ec758a20
RR
2255 : wxWindowDC()
2256{
2257}
2258
2259wxClientDC::wxClientDC( wxWindow *win )
2260 : wxWindowDC( win )
2261{
2262}
2263
3d2d8da1
RR
2264// ----------------------------------------------------------------------------
2265// wxDCModule
2266// ----------------------------------------------------------------------------
2267
2268class wxDCModule : public wxModule
2269{
2270public:
2271 bool OnInit();
2272 void OnExit();
2273
2274private:
2275 DECLARE_DYNAMIC_CLASS(wxDCModule)
2276};
2277
2278IMPLEMENT_DYNAMIC_CLASS(wxDCModule, wxModule)
2279
2280bool wxDCModule::OnInit()
2281{
2282 wxInitGCPool();
2283 return TRUE;
2284}
2285
2286void wxDCModule::OnExit()
2287{
2288 wxCleanUpGCPool();
2289}