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