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