]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/dcclient.cpp
corrected ::Clear
[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
f9862abd 1425#if defined(__WXGTK20__) && wxUSE_WCHAR_T
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 {
9e691f46 1430 const wxWX2MBbuf data = text.mb_str(wxConvUTF8);
8943b403
OK
1431 pango_layout_set_text(layout, data, strlen(data));
1432 }
1433 PangoLayoutLine *line = (PangoLayoutLine *)pango_layout_get_lines(layout)->data;
1434 PangoRectangle rect;
1435 pango_layout_line_get_extents(line, NULL, &rect);
1436 wxCoord width = rect.width;
1437 wxCoord height = rect.height;
1438 gdk_draw_layout( m_window, m_textGC, x, y, layout );
9e691f46 1439#else // GTK+ 1.x
8943b403
OK
1440 wxCoord width = gdk_string_width( font, text.mbc_str() );
1441 wxCoord height = font->ascent + font->descent;
2c37aade
VZ
1442
1443 if ( m_backgroundMode == wxSOLID )
265898fd 1444 {
265898fd
RR
1445 gdk_gc_set_foreground( m_textGC, m_textBackgroundColour.GetColor() );
1446 gdk_draw_rectangle( m_window, m_textGC, TRUE, x, y, width, height );
2c37aade 1447 gdk_gc_set_foreground( m_textGC, m_textForegroundColour.GetColor() );
265898fd 1448 }
93c5dd39 1449 gdk_draw_string( m_window, font, m_textGC, x, y + font->ascent, text.mbc_str() );
9e691f46 1450#endif // GTK+ 2.0/1.x
18a2fa37 1451
bbbbe360
RR
1452 /* CMB 17/7/98: simple underline: ignores scaling and underlying
1453 X font's XA_UNDERLINE_POSITION and XA_UNDERLINE_THICKNESS
1454 properties (see wxXt implementation) */
265898fd
RR
1455 if (m_font.GetUnderlined())
1456 {
13111b2a 1457 wxCoord ul_y = y + font->ascent;
265898fd
RR
1458 if (font->descent > 0) ul_y++;
1459 gdk_draw_line( m_window, m_textGC, x, ul_y, x + width, ul_y);
1460 }
7d5af6fa 1461
90fae67d 1462#if defined(__WXGTK20__) && wxUSE_WCHAR_T
8943b403
OK
1463 g_object_unref( G_OBJECT( layout ) );
1464#endif
1465
1466 width = wxCoord(width / m_scaleX);
1467 height = wxCoord(height / m_scaleY);
1468 CalcBoundingBox (x + width, y + height);
265898fd 1469 CalcBoundingBox (x, y);
903f689b 1470}
c801d85f 1471
95724b1a
VZ
1472void wxWindowDC::DoDrawRotatedText( const wxString &text, wxCoord x, wxCoord y, double angle )
1473{
1474 if (angle == 0.0)
1475 {
1476 DrawText(text, x, y);
1477 return;
1478 }
1479
1480 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1481
1482 if (!m_window) return;
1483
1484 GdkFont *font = m_font.GetInternalFont( m_scaleY );
1485
1486 wxCHECK_RET( font, wxT("invalid font") );
1487
9a8c7620 1488 // the size of the text
13111b2a
VZ
1489 wxCoord w = gdk_string_width( font, text.mbc_str() );
1490 wxCoord h = font->ascent + font->descent;
95724b1a 1491
9a8c7620
VZ
1492 // draw the string normally
1493 wxBitmap src(w, h);
95724b1a
VZ
1494 wxMemoryDC dc;
1495 dc.SelectObject(src);
1496 dc.SetFont(GetFont());
1497 dc.SetBackground(*wxWHITE_BRUSH);
1498 dc.SetBrush(*wxBLACK_BRUSH);
1499 dc.Clear();
1500 dc.DrawText(text, 0, 0);
9a8c7620 1501 dc.SelectObject(wxNullBitmap);
95724b1a
VZ
1502
1503 // Calculate the size of the rotated bounding box.
9a8c7620
VZ
1504 double rad = DegToRad(angle);
1505 double dx = cos(rad),
1506 dy = sin(rad);
1507
1508 // the rectngle vertices are counted clockwise with the first one being at
1509 // (0, 0) (or, rather, at (x, y))
1510 double x2 = w*dx,
1511 y2 = -w*dy; // y axis points to the bottom, hence minus
1512 double x4 = h*dy,
1513 y4 = h*dx;
1514 double x3 = x4 + x2,
1515 y3 = y4 + y2;
1516
72174350 1517 // calc max and min
9a8c7620
VZ
1518 wxCoord maxX = (wxCoord)(dmax(x2, dmax(x3, x4)) + 0.5),
1519 maxY = (wxCoord)(dmax(y2, dmax(y3, y4)) + 0.5),
1520 minX = (wxCoord)(dmin(x2, dmin(x3, x4)) - 0.5),
1521 minY = (wxCoord)(dmin(y2, dmin(y3, y4)) - 0.5);
1522
1523 // prepare to blit-with-rotate the bitmap to the DC
368d59f0 1524 wxImage image = src.ConvertToImage();
9a8c7620
VZ
1525
1526 GdkColor *colText = m_textForegroundColour.GetColor(),
1527 *colBack = m_textBackgroundColour.GetColor();
72174350 1528
9a8c7620
VZ
1529 bool textColSet = TRUE;
1530
1531 unsigned char *data = image.GetData();
1532
1533 // paint pixel by pixel
1534 for ( wxCoord srcX = 0; srcX < w; srcX++ )
95724b1a 1535 {
9a8c7620 1536 for ( wxCoord srcY = 0; srcY < h; srcY++ )
95724b1a 1537 {
9a8c7620 1538 // transform source coords to dest coords
f6bcfd97
BP
1539 double r = sqrt((double)srcX*srcX + srcY*srcY);
1540 double angleOrig = atan2((double)srcY, (double)srcX) - rad;
9a8c7620
VZ
1541 wxCoord dstX = (wxCoord)(r*cos(angleOrig) + 0.5),
1542 dstY = (wxCoord)(r*sin(angleOrig) + 0.5);
1543
1544 // black pixel?
1545 bool textPixel = data[(srcY*w + srcX)*3] == 0;
1546 if ( textPixel || (m_backgroundMode == wxSOLID) )
95724b1a 1547 {
9a8c7620
VZ
1548 // change colour if needed
1549 if ( textPixel != textColSet )
95724b1a 1550 {
9a8c7620
VZ
1551 gdk_gc_set_foreground( m_textGC, textPixel ? colText
1552 : colBack );
1553
1554 textColSet = textPixel;
95724b1a 1555 }
9a8c7620
VZ
1556
1557 // don't use DrawPoint() because it uses the current pen
1558 // colour, and we don't need it here
1559 gdk_draw_point( m_window, m_textGC,
a57a1fb7 1560 XLOG2DEV(x) + dstX, YLOG2DEV(y) + dstY );
95724b1a
VZ
1561 }
1562 }
1563 }
1564
9a8c7620
VZ
1565 // it would be better to draw with non underlined font and draw the line
1566 // manually here (it would be more straight...)
1567#if 0
1568 if ( m_font.GetUnderlined() )
1569 {
1570 gdk_draw_line( m_window, m_textGC,
1571 XLOG2DEV(x + x4), YLOG2DEV(y + y4 + font->descent),
1572 XLOG2DEV(x + x3), YLOG2DEV(y + y3 + font->descent));
1573 }
1574#endif // 0
1575
1576 // restore the font colour
1577 gdk_gc_set_foreground( m_textGC, colText );
1578
1579 // update the bounding box
1580 CalcBoundingBox(x + minX, y + minY);
1581 CalcBoundingBox(x + maxX, y + maxY);
95724b1a
VZ
1582}
1583
72cdf4c9
VZ
1584void wxWindowDC::DoGetTextExtent(const wxString &string,
1585 wxCoord *width, wxCoord *height,
1586 wxCoord *descent, wxCoord *externalLeading,
1587 wxFont *theFont) const
c801d85f 1588{
265898fd
RR
1589 wxFont fontToUse = m_font;
1590 if (theFont) fontToUse = *theFont;
7d5af6fa 1591
265898fd 1592 GdkFont *font = fontToUse.GetInternalFont( m_scaleY );
72cdf4c9
VZ
1593 if (width) (*width) = wxCoord(gdk_string_width( font, string.mbc_str() ) / m_scaleX);
1594 if (height) (*height) = wxCoord((font->ascent + font->descent) / m_scaleY);
1595 if (descent) (*descent) = wxCoord(font->descent / m_scaleY);
265898fd 1596 if (externalLeading) (*externalLeading) = 0; // ??
903f689b 1597}
c801d85f 1598
72cdf4c9 1599wxCoord wxWindowDC::GetCharWidth() const
c801d85f 1600{
265898fd 1601 GdkFont *font = m_font.GetInternalFont( m_scaleY );
58c837a4 1602 wxCHECK_MSG( font, -1, wxT("invalid font") );
7beba2fc 1603
72cdf4c9 1604 return wxCoord(gdk_string_width( font, "H" ) / m_scaleX);
903f689b 1605}
c801d85f 1606
72cdf4c9 1607wxCoord wxWindowDC::GetCharHeight() const
c801d85f 1608{
265898fd 1609 GdkFont *font = m_font.GetInternalFont( m_scaleY );
58c837a4 1610 wxCHECK_MSG( font, -1, wxT("invalid font") );
7beba2fc 1611
72cdf4c9 1612 return wxCoord((font->ascent + font->descent) / m_scaleY);
903f689b 1613}
c801d85f 1614
4bc67cc5 1615void wxWindowDC::Clear()
c801d85f 1616{
223d09f6 1617 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1618
6db90681 1619 if (!m_window) return;
7d5af6fa 1620
f60e7fdd
VZ
1621 // VZ: the code below results in infinite recursion and crashes when
1622 // dc.Clear() is done from OnPaint() so I disable it for now.
1623 // I don't know what the correct fix is but Clear() surely should not
1624 // reenter OnPaint()!
1625#if 0
f234c60c
RR
1626 /* - we either are a memory dc or have a window as the
1627 owner. anything else shouldn't happen.
1628 - we don't use gdk_window_clear() as we don't set
1629 the window's background colour anymore. it is too
1630 much pain to keep the DC's and the window's back-
1631 ground colour in synch. */
7d5af6fa 1632
f234c60c 1633 if (m_owner)
265898fd 1634 {
f90566f5 1635 m_owner->Clear();
b0e0d661 1636 return;
265898fd 1637 }
f234c60c
RR
1638
1639 if (m_isMemDC)
265898fd
RR
1640 {
1641 int width,height;
1642 GetSize( &width, &height );
1643 gdk_draw_rectangle( m_window, m_bgGC, TRUE, 0, 0, width, height );
b0e0d661 1644 return;
265898fd 1645 }
f60e7fdd
VZ
1646#else // 1
1647 int width,height;
1648 GetSize( &width, &height );
1649 gdk_draw_rectangle( m_window, m_bgGC, TRUE, 0, 0, width, height );
1650#endif // 0/1
903f689b 1651}
c801d85f 1652
ec758a20 1653void wxWindowDC::SetFont( const wxFont &font )
c801d85f 1654{
4855a477
JS
1655 // It is common practice to set the font to wxNullFont, so
1656 // don't consider it to be an error
1657 // wxCHECK_RET( font.Ok(), _T("invalid font in wxWindowDC::SetFont") );
6a41b213 1658
265898fd 1659 m_font = font;
8943b403 1660#ifdef __WXGTK20__
db16cab4 1661 m_fontdesc = m_font.GetNativeFontInfo()->description;
8943b403 1662#endif
903f689b 1663}
c801d85f 1664
ec758a20 1665void wxWindowDC::SetPen( const wxPen &pen )
c801d85f 1666{
223d09f6 1667 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1668
265898fd 1669 if (m_pen == pen) return;
7d5af6fa 1670
265898fd 1671 m_pen = pen;
7d5af6fa 1672
265898fd 1673 if (!m_pen.Ok()) return;
7d5af6fa 1674
6db90681 1675 if (!m_window) return;
7d5af6fa 1676
265898fd 1677 gint width = m_pen.GetWidth();
265898fd
RR
1678 if (width <= 0)
1679 {
112c5086 1680 // CMB: if width is non-zero scale it with the dc
265898fd
RR
1681 width = 1;
1682 }
1683 else
1684 {
1685 // X doesn't allow different width in x and y and so we take
1686 // the average
503f414e
VZ
1687 double w = 0.5 +
1688 ( fabs((double) XLOG2DEVREL(width)) +
1689 fabs((double) YLOG2DEVREL(width)) ) / 2.0;
265898fd
RR
1690 width = (int)w;
1691 }
7d5af6fa 1692
2eca425d
RL
1693 static const wxGTKDash dotted[] = {1, 1};
1694 static const wxGTKDash short_dashed[] = {2, 2};
1695 static const wxGTKDash wxCoord_dashed[] = {2, 4};
1696 static const wxGTKDash dotted_dashed[] = {3, 3, 1, 3};
7d5af6fa 1697
112c5086
RR
1698 // We express dash pattern in pen width unit, so we are
1699 // independent of zoom factor and so on...
1700 int req_nb_dash;
2eca425d 1701 const wxGTKDash *req_dash;
7d5af6fa 1702
265898fd
RR
1703 GdkLineStyle lineStyle = GDK_LINE_SOLID;
1704 switch (m_pen.GetStyle())
1705 {
112c5086 1706 case wxUSER_DASH:
7d5af6fa
VZ
1707 {
1708 lineStyle = GDK_LINE_ON_OFF_DASH;
112c5086 1709 req_nb_dash = m_pen.GetDashCount();
2eca425d 1710 req_dash = (wxGTKDash*)m_pen.GetDash();
112c5086 1711 break;
7d5af6fa
VZ
1712 }
1713 case wxDOT:
1714 {
1715 lineStyle = GDK_LINE_ON_OFF_DASH;
112c5086
RR
1716 req_nb_dash = 2;
1717 req_dash = dotted;
7d5af6fa
VZ
1718 break;
1719 }
1720 case wxLONG_DASH:
1721 {
1722 lineStyle = GDK_LINE_ON_OFF_DASH;
112c5086 1723 req_nb_dash = 2;
72cdf4c9 1724 req_dash = wxCoord_dashed;
7d5af6fa
VZ
1725 break;
1726 }
1727 case wxSHORT_DASH:
1728 {
1729 lineStyle = GDK_LINE_ON_OFF_DASH;
112c5086
RR
1730 req_nb_dash = 2;
1731 req_dash = short_dashed;
7d5af6fa
VZ
1732 break;
1733 }
1734 case wxDOT_DASH:
1735 {
1736// lineStyle = GDK_LINE_DOUBLE_DASH;
1737 lineStyle = GDK_LINE_ON_OFF_DASH;
112c5086
RR
1738 req_nb_dash = 4;
1739 req_dash = dotted_dashed;
7d5af6fa
VZ
1740 break;
1741 }
1742
1743 case wxTRANSPARENT:
72174350 1744 case wxSTIPPLE_MASK_OPAQUE:
7d5af6fa
VZ
1745 case wxSTIPPLE:
1746 case wxSOLID:
1747 default:
1748 {
1749 lineStyle = GDK_LINE_SOLID;
2eca425d 1750 req_dash = (wxGTKDash*)NULL;
112c5086 1751 req_nb_dash = 0;
7d5af6fa
VZ
1752 break;
1753 }
265898fd 1754 }
7d5af6fa 1755
2eca425d 1756#if (GTK_MINOR_VERSION > 0) || (GTK_MAJOR_VERSION > 1)
112c5086
RR
1757 if (req_dash && req_nb_dash)
1758 {
2eca425d 1759 wxGTKDash *real_req_dash = new wxGTKDash[req_nb_dash];
112c5086
RR
1760 if (real_req_dash)
1761 {
1762 for (int i = 0; i < req_nb_dash; i++)
1763 real_req_dash[i] = req_dash[i] * width;
2eca425d 1764 gdk_gc_set_dashes( m_penGC, 0, real_req_dash, req_nb_dash );
112c5086
RR
1765 delete[] real_req_dash;
1766 }
1767 else
1768 {
1769 // No Memory. We use non-scaled dash pattern...
2eca425d 1770 gdk_gc_set_dashes( m_penGC, 0, (wxGTKDash*)req_dash, req_nb_dash );
112c5086
RR
1771 }
1772 }
953704c1 1773#endif
7d5af6fa 1774
265898fd
RR
1775 GdkCapStyle capStyle = GDK_CAP_ROUND;
1776 switch (m_pen.GetCap())
1777 {
265898fd
RR
1778 case wxCAP_PROJECTING: { capStyle = GDK_CAP_PROJECTING; break; }
1779 case wxCAP_BUTT: { capStyle = GDK_CAP_BUTT; break; }
d4aa3a4b
RR
1780 case wxCAP_ROUND:
1781 default:
72174350 1782 {
d4aa3a4b
RR
1783 if (width <= 1)
1784 {
1785 width = 0;
1786 capStyle = GDK_CAP_NOT_LAST;
1787 }
1788 else
1789 {
1790 capStyle = GDK_CAP_ROUND;
1791 }
72174350 1792 break;
d4aa3a4b 1793 }
265898fd 1794 }
7d5af6fa 1795
265898fd
RR
1796 GdkJoinStyle joinStyle = GDK_JOIN_ROUND;
1797 switch (m_pen.GetJoin())
1798 {
1799 case wxJOIN_BEVEL: { joinStyle = GDK_JOIN_BEVEL; break; }
265898fd 1800 case wxJOIN_MITER: { joinStyle = GDK_JOIN_MITER; break; }
d4aa3a4b
RR
1801 case wxJOIN_ROUND:
1802 default: { joinStyle = GDK_JOIN_ROUND; break; }
265898fd 1803 }
7d5af6fa 1804
265898fd 1805 gdk_gc_set_line_attributes( m_penGC, width, lineStyle, capStyle, joinStyle );
7d5af6fa 1806
265898fd
RR
1807 m_pen.GetColour().CalcPixel( m_cmap );
1808 gdk_gc_set_foreground( m_penGC, m_pen.GetColour().GetColor() );
903f689b 1809}
c801d85f 1810
ec758a20 1811void wxWindowDC::SetBrush( const wxBrush &brush )
c801d85f 1812{
223d09f6 1813 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1814
265898fd 1815 if (m_brush == brush) return;
7d5af6fa 1816
265898fd 1817 m_brush = brush;
7d5af6fa 1818
265898fd 1819 if (!m_brush.Ok()) return;
7d5af6fa 1820
6db90681 1821 if (!m_window) return;
7d5af6fa 1822
265898fd
RR
1823 m_brush.GetColour().CalcPixel( m_cmap );
1824 gdk_gc_set_foreground( m_brushGC, m_brush.GetColour().GetColor() );
7d5af6fa 1825
956dbab1 1826 gdk_gc_set_fill( m_brushGC, GDK_SOLID );
7d5af6fa 1827
4fcd73bd 1828 if ((m_brush.GetStyle() == wxSTIPPLE) && (m_brush.GetStipple()->Ok()))
265898fd 1829 {
4fcd73bd 1830 if (m_brush.GetStipple()->GetPixmap())
7d5af6fa 1831 {
956dbab1 1832 gdk_gc_set_fill( m_brushGC, GDK_TILED );
cd25b18c 1833 gdk_gc_set_tile( m_brushGC, m_brush.GetStipple()->GetPixmap() );
7d5af6fa 1834 }
b0e0d661 1835 else
7d5af6fa 1836 {
956dbab1 1837 gdk_gc_set_fill( m_brushGC, GDK_STIPPLED );
4fcd73bd 1838 gdk_gc_set_stipple( m_brushGC, m_brush.GetStipple()->GetBitmap() );
7d5af6fa 1839 }
265898fd 1840 }
7d5af6fa 1841
de2d2cdc
VZ
1842 if ((m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE) && (m_brush.GetStipple()->GetMask()))
1843 {
e1208c31
RR
1844 gdk_gc_set_fill( m_textGC, GDK_OPAQUE_STIPPLED);
1845 gdk_gc_set_stipple( m_textGC, m_brush.GetStipple()->GetMask()->GetBitmap() );
de2d2cdc
VZ
1846 }
1847
265898fd
RR
1848 if (IS_HATCH(m_brush.GetStyle()))
1849 {
956dbab1 1850 gdk_gc_set_fill( m_brushGC, GDK_STIPPLED );
265898fd
RR
1851 int num = m_brush.GetStyle() - wxBDIAGONAL_HATCH;
1852 gdk_gc_set_stipple( m_brushGC, hatches[num] );
1853 }
903f689b 1854}
c801d85f 1855
ec758a20 1856void wxWindowDC::SetBackground( const wxBrush &brush )
46dc76ba 1857{
bbbbe360
RR
1858 /* CMB 21/7/98: Added SetBackground. Sets background brush
1859 * for Clear() and bg colour for shapes filled with cross-hatch brush */
7d5af6fa 1860
223d09f6 1861 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1862
265898fd 1863 if (m_backgroundBrush == brush) return;
7d5af6fa 1864
265898fd 1865 m_backgroundBrush = brush;
7d5af6fa 1866
265898fd 1867 if (!m_backgroundBrush.Ok()) return;
7d5af6fa 1868
6db90681 1869 if (!m_window) return;
7d5af6fa 1870
265898fd
RR
1871 m_backgroundBrush.GetColour().CalcPixel( m_cmap );
1872 gdk_gc_set_background( m_brushGC, m_backgroundBrush.GetColour().GetColor() );
a802c3a1 1873 gdk_gc_set_background( m_penGC, m_backgroundBrush.GetColour().GetColor() );
031b2a7b 1874 gdk_gc_set_background( m_bgGC, m_backgroundBrush.GetColour().GetColor() );
265898fd 1875 gdk_gc_set_foreground( m_bgGC, m_backgroundBrush.GetColour().GetColor() );
3417c2cd
RR
1876
1877 gdk_gc_set_fill( m_bgGC, GDK_SOLID );
7d5af6fa 1878
cd25b18c 1879 if ((m_backgroundBrush.GetStyle() == wxSTIPPLE) && (m_backgroundBrush.GetStipple()->Ok()))
265898fd 1880 {
fd128b0c 1881 if (m_backgroundBrush.GetStipple()->GetPixmap())
7d5af6fa 1882 {
3417c2cd 1883 gdk_gc_set_fill( m_bgGC, GDK_TILED );
fd128b0c 1884 gdk_gc_set_tile( m_bgGC, m_backgroundBrush.GetStipple()->GetPixmap() );
7d5af6fa 1885 }
cd25b18c 1886 else
7d5af6fa 1887 {
3417c2cd 1888 gdk_gc_set_fill( m_bgGC, GDK_STIPPLED );
fd128b0c 1889 gdk_gc_set_stipple( m_bgGC, m_backgroundBrush.GetStipple()->GetBitmap() );
7d5af6fa 1890 }
265898fd 1891 }
7d5af6fa 1892
265898fd
RR
1893 if (IS_HATCH(m_backgroundBrush.GetStyle()))
1894 {
3417c2cd 1895 gdk_gc_set_fill( m_bgGC, GDK_STIPPLED );
265898fd
RR
1896 int num = m_backgroundBrush.GetStyle() - wxBDIAGONAL_HATCH;
1897 gdk_gc_set_stipple( m_bgGC, hatches[num] );
bbbbe360 1898 }
903f689b 1899}
46dc76ba 1900
ec758a20 1901void wxWindowDC::SetLogicalFunction( int function )
c801d85f 1902{
223d09f6 1903 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1904
72174350
VZ
1905 if (m_logicalFunction == function)
1906 return;
1907
1908 // VZ: shouldn't this be a CHECK?
1909 if (!m_window)
1910 return;
01eaf507 1911
265898fd
RR
1912 GdkFunction mode = GDK_COPY;
1913 switch (function)
1914 {
3c679789
RR
1915 case wxXOR: mode = GDK_XOR; break;
1916 case wxINVERT: mode = GDK_INVERT; break;
01eaf507 1917#if (GTK_MINOR_VERSION > 0)
3c679789
RR
1918 case wxOR_REVERSE: mode = GDK_OR_REVERSE; break;
1919 case wxAND_REVERSE: mode = GDK_AND_REVERSE; break;
1920 case wxCLEAR: mode = GDK_CLEAR; break;
1921 case wxSET: mode = GDK_SET; break;
1922 case wxOR_INVERT: mode = GDK_OR_INVERT; break;
1923 case wxAND: mode = GDK_AND; break;
1924 case wxOR: mode = GDK_OR; break;
1925 case wxEQUIV: mode = GDK_EQUIV; break;
1926 case wxNAND: mode = GDK_NAND; break;
1927 case wxAND_INVERT: mode = GDK_AND_INVERT; break;
7d5af6fa
VZ
1928 case wxCOPY: mode = GDK_COPY; break;
1929 case wxNO_OP: mode = GDK_NOOP; break;
1930 case wxSRC_INVERT: mode = GDK_COPY_INVERT; break;
72174350 1931
2d52841d
RR
1932 // unsupported by GTK
1933 case wxNOR: mode = GDK_COPY; break;
c96faa7c 1934#endif
01eaf507 1935 default:
7d5af6fa 1936 {
223d09f6 1937 wxFAIL_MSG( wxT("unsupported logical function") );
7d5af6fa
VZ
1938 break;
1939 }
265898fd 1940 }
7d5af6fa 1941
265898fd 1942 m_logicalFunction = function;
7d5af6fa 1943
265898fd
RR
1944 gdk_gc_set_function( m_penGC, mode );
1945 gdk_gc_set_function( m_brushGC, mode );
72174350
VZ
1946
1947 // to stay compatible with wxMSW, we don't apply ROPs to the text
3d2d8da1
RR
1948 // operations (i.e. DrawText/DrawRotatedText).
1949 // True, but mono-bitmaps use the m_textGC and they use ROPs as well.
1950 gdk_gc_set_function( m_textGC, mode );
903f689b 1951}
c801d85f 1952
ec758a20 1953void wxWindowDC::SetTextForeground( const wxColour &col )
c801d85f 1954{
223d09f6 1955 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1956
71ec83d2
VZ
1957 // don't set m_textForegroundColour to an invalid colour as we'd crash
1958 // later then (we use m_textForegroundColour.GetColor() without checking
1959 // in a few places)
1960 if ( !col.Ok() || (m_textForegroundColour == col) )
1961 return;
7d5af6fa 1962
265898fd 1963 m_textForegroundColour = col;
7d5af6fa 1964
71ec83d2
VZ
1965 if ( m_window )
1966 {
1967 m_textForegroundColour.CalcPixel( m_cmap );
1968 gdk_gc_set_foreground( m_textGC, m_textForegroundColour.GetColor() );
1969 }
903f689b 1970}
c801d85f 1971
ec758a20 1972void wxWindowDC::SetTextBackground( const wxColour &col )
c801d85f 1973{
223d09f6 1974 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1975
71ec83d2
VZ
1976 // same as above
1977 if ( !col.Ok() || (m_textBackgroundColour == col) )
1978 return;
7d5af6fa 1979
265898fd 1980 m_textBackgroundColour = col;
7d5af6fa 1981
71ec83d2
VZ
1982 if ( m_window )
1983 {
1984 m_textBackgroundColour.CalcPixel( m_cmap );
1985 gdk_gc_set_background( m_textGC, m_textBackgroundColour.GetColor() );
1986 }
903f689b 1987}
c801d85f 1988
ec758a20 1989void wxWindowDC::SetBackgroundMode( int mode )
c801d85f 1990{
223d09f6 1991 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1992
265898fd 1993 m_backgroundMode = mode;
46dc76ba 1994
6db90681 1995 if (!m_window) return;
7d5af6fa 1996
265898fd
RR
1997 // CMB 21/7/98: fill style of cross-hatch brushes is affected by
1998 // transparent/solid background mode
7d5af6fa 1999
265898fd
RR
2000 if (m_brush.GetStyle() != wxSOLID && m_brush.GetStyle() != wxTRANSPARENT)
2001 {
2002 gdk_gc_set_fill( m_brushGC,
2003 (m_backgroundMode == wxTRANSPARENT) ? GDK_STIPPLED : GDK_OPAQUE_STIPPLED);
2004 }
903f689b 2005}
c801d85f 2006
ec758a20 2007void wxWindowDC::SetPalette( const wxPalette& WXUNUSED(palette) )
c801d85f 2008{
223d09f6 2009 wxFAIL_MSG( wxT("wxWindowDC::SetPalette not implemented") );
903f689b 2010}
c801d85f 2011
72cdf4c9 2012void wxWindowDC::DoSetClippingRegion( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
c801d85f 2013{
223d09f6 2014 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 2015
6db90681 2016 if (!m_window) return;
7d5af6fa 2017
3d2d8da1 2018 wxRect rect;
265898fd
RR
2019 rect.x = XLOG2DEV(x);
2020 rect.y = YLOG2DEV(y);
2021 rect.width = XLOG2DEVREL(width);
2022 rect.height = YLOG2DEVREL(height);
5f170f33 2023
e1208c31 2024 if (!m_currentClippingRegion.IsNull())
993f97ee
RR
2025 m_currentClippingRegion.Intersect( rect );
2026 else
2027 m_currentClippingRegion.Union( rect );
5f170f33
VZ
2028
2029#if USE_PAINT_REGION
e1208c31 2030 if (!m_paintClippingRegion.IsNull())
3d2d8da1 2031 m_currentClippingRegion.Intersect( m_paintClippingRegion );
809934d2 2032#endif
3d2d8da1 2033
ee8dbe63
RL
2034 wxCoord xx, yy, ww, hh;
2035 m_currentClippingRegion.GetBox( xx, yy, ww, hh );
2036 wxDC::DoSetClippingRegion( xx, yy, ww, hh );
2037
3d2d8da1
RR
2038 gdk_gc_set_clip_region( m_penGC, m_currentClippingRegion.GetRegion() );
2039 gdk_gc_set_clip_region( m_brushGC, m_currentClippingRegion.GetRegion() );
2040 gdk_gc_set_clip_region( m_textGC, m_currentClippingRegion.GetRegion() );
2041 gdk_gc_set_clip_region( m_bgGC, m_currentClippingRegion.GetRegion() );
903f689b 2042}
c801d85f 2043
b0e0d661 2044void wxWindowDC::DoSetClippingRegionAsRegion( const wxRegion &region )
463c1fa1 2045{
223d09f6 2046 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 2047
463c1fa1
RR
2048 if (region.Empty())
2049 {
2050 DestroyClippingRegion();
2051 return;
2052 }
7d5af6fa 2053
6db90681 2054 if (!m_window) return;
5f170f33 2055
e1208c31 2056 if (!m_currentClippingRegion.IsNull())
993f97ee
RR
2057 m_currentClippingRegion.Intersect( region );
2058 else
2059 m_currentClippingRegion.Union( region );
5f170f33
VZ
2060
2061#if USE_PAINT_REGION
e1208c31 2062 if (!m_paintClippingRegion.IsNull())
3d2d8da1 2063 m_currentClippingRegion.Intersect( m_paintClippingRegion );
809934d2 2064#endif
3d2d8da1 2065
ee8dbe63
RL
2066 wxCoord xx, yy, ww, hh;
2067 m_currentClippingRegion.GetBox( xx, yy, ww, hh );
2068 wxDC::DoSetClippingRegion( xx, yy, ww, hh );
2069
3d2d8da1
RR
2070 gdk_gc_set_clip_region( m_penGC, m_currentClippingRegion.GetRegion() );
2071 gdk_gc_set_clip_region( m_brushGC, m_currentClippingRegion.GetRegion() );
2072 gdk_gc_set_clip_region( m_textGC, m_currentClippingRegion.GetRegion() );
2073 gdk_gc_set_clip_region( m_bgGC, m_currentClippingRegion.GetRegion() );
463c1fa1
RR
2074}
2075
4bc67cc5 2076void wxWindowDC::DestroyClippingRegion()
c801d85f 2077{
223d09f6 2078 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 2079
265898fd 2080 wxDC::DestroyClippingRegion();
7d5af6fa 2081
3d2d8da1 2082 m_currentClippingRegion.Clear();
5f170f33
VZ
2083
2084#if USE_PAINT_REGION
3d2d8da1
RR
2085 if (!m_paintClippingRegion.IsEmpty())
2086 m_currentClippingRegion.Union( m_paintClippingRegion );
993f97ee 2087#endif
3d2d8da1 2088
6db90681 2089 if (!m_window) return;
7d5af6fa 2090
3d2d8da1
RR
2091 if (m_currentClippingRegion.IsEmpty())
2092 {
2093 gdk_gc_set_clip_rectangle( m_penGC, (GdkRectangle *) NULL );
2094 gdk_gc_set_clip_rectangle( m_brushGC, (GdkRectangle *) NULL );
2095 gdk_gc_set_clip_rectangle( m_textGC, (GdkRectangle *) NULL );
2096 gdk_gc_set_clip_rectangle( m_bgGC, (GdkRectangle *) NULL );
2097 }
2098 else
2099 {
2100 gdk_gc_set_clip_region( m_penGC, m_currentClippingRegion.GetRegion() );
2101 gdk_gc_set_clip_region( m_brushGC, m_currentClippingRegion.GetRegion() );
2102 gdk_gc_set_clip_region( m_textGC, m_currentClippingRegion.GetRegion() );
2103 gdk_gc_set_clip_region( m_bgGC, m_currentClippingRegion.GetRegion() );
2104 }
903f689b 2105}
c801d85f 2106
4bc67cc5 2107void wxWindowDC::Destroy()
dbf858b5 2108{
3d2d8da1 2109 if (m_penGC) wxFreePoolGC( m_penGC );
265898fd 2110 m_penGC = (GdkGC*) NULL;
3d2d8da1 2111 if (m_brushGC) wxFreePoolGC( m_brushGC );
265898fd 2112 m_brushGC = (GdkGC*) NULL;
3d2d8da1 2113 if (m_textGC) wxFreePoolGC( m_textGC );
265898fd 2114 m_textGC = (GdkGC*) NULL;
3d2d8da1 2115 if (m_bgGC) wxFreePoolGC( m_bgGC );
265898fd 2116 m_bgGC = (GdkGC*) NULL;
dbf858b5
RR
2117}
2118
238d735d
RR
2119void wxWindowDC::ComputeScaleAndOrigin()
2120{
2121 /* CMB: copy scale to see if it changes */
2122 double origScaleX = m_scaleX;
2123 double origScaleY = m_scaleY;
2124
2125 wxDC::ComputeScaleAndOrigin();
2126
2127 /* CMB: if scale has changed call SetPen to recalulate the line width */
2128 if ((m_scaleX != origScaleX || m_scaleY != origScaleY) &&
2129 (m_pen.Ok()))
2130 {
2131 /* this is a bit artificial, but we need to force wxDC to think
2132 the pen has changed */
2133 wxPen pen = m_pen;
2134 m_pen = wxNullPen;
2135 SetPen( pen );
2136 }
2137}
2138
b0e0d661
VZ
2139// Resolution in pixels per logical inch
2140wxSize wxWindowDC::GetPPI() const
2141{
7a5e6267 2142 return wxSize( (int) (m_mm_to_pix_x * 25.4 + 0.5), (int) (m_mm_to_pix_y * 25.4 + 0.5));
b0e0d661
VZ
2143}
2144
2145int wxWindowDC::GetDepth() const
c801d85f 2146{
223d09f6 2147 wxFAIL_MSG(wxT("not implemented"));
b0e0d661
VZ
2148
2149 return -1;
903f689b 2150}
c801d85f 2151
ec758a20
RR
2152
2153//-----------------------------------------------------------------------------
2154// wxPaintDC
2155//-----------------------------------------------------------------------------
2156
f469b27c 2157IMPLEMENT_DYNAMIC_CLASS(wxPaintDC, wxClientDC)
ec758a20
RR
2158
2159wxPaintDC::wxPaintDC( wxWindow *win )
f469b27c 2160 : wxClientDC( win )
ec758a20 2161{
b6fa52db
RR
2162#if USE_PAINT_REGION
2163 if (!win->m_clipPaintRegion)
2164 return;
f469b27c 2165
e1208c31 2166 m_paintClippingRegion = win->GetUpdateRegion();
5f170f33
VZ
2167 GdkRegion *region = m_paintClippingRegion.GetRegion();
2168 if ( region )
2169 {
1e6feb95
VZ
2170 m_paintClippingRegion = win->GetUpdateRegion();
2171 GdkRegion *region = m_paintClippingRegion.GetRegion();
2172 if ( region )
2173 {
2174 m_currentClippingRegion.Union( m_paintClippingRegion );
5f170f33 2175
1e6feb95
VZ
2176 gdk_gc_set_clip_region( m_penGC, region );
2177 gdk_gc_set_clip_region( m_brushGC, region );
2178 gdk_gc_set_clip_region( m_textGC, region );
2179 gdk_gc_set_clip_region( m_bgGC, region );
2180 }
5f170f33 2181 }
1e6feb95 2182#endif // USE_PAINT_REGION
ec758a20
RR
2183}
2184
2185//-----------------------------------------------------------------------------
2186// wxClientDC
2187//-----------------------------------------------------------------------------
2188
f469b27c 2189IMPLEMENT_DYNAMIC_CLASS(wxClientDC, wxWindowDC)
ec758a20 2190
f469b27c
VZ
2191wxClientDC::wxClientDC( wxWindow *win )
2192 : wxWindowDC( win )
ec758a20 2193{
4f55a07f
VZ
2194 wxCHECK_RET( win, _T("NULL window in wxClientDC::wxClientDC") );
2195
1e6feb95
VZ
2196#ifdef __WXUNIVERSAL__
2197 wxPoint ptOrigin = win->GetClientAreaOrigin();
2198 SetDeviceOrigin(ptOrigin.x, ptOrigin.y);
2199 wxSize size = win->GetClientSize();
2200 SetClippingRegion(wxPoint(0, 0), size);
2201#endif // __WXUNIVERSAL__
ec758a20
RR
2202}
2203
4f55a07f
VZ
2204void wxClientDC::DoGetSize(int *width, int *height) const
2205{
2206 wxCHECK_RET( m_owner, _T("GetSize() doesn't work without window") );
2207
2208 m_owner->GetClientSize( width, height );
2209}
2210
3d2d8da1
RR
2211// ----------------------------------------------------------------------------
2212// wxDCModule
2213// ----------------------------------------------------------------------------
2214
2215class wxDCModule : public wxModule
2216{
2217public:
2218 bool OnInit();
2219 void OnExit();
2220
2221private:
2222 DECLARE_DYNAMIC_CLASS(wxDCModule)
2223};
2224
2225IMPLEMENT_DYNAMIC_CLASS(wxDCModule, wxModule)
2226
2227bool wxDCModule::OnInit()
2228{
2229 wxInitGCPool();
2230 return TRUE;
2231}
2232
2233void wxDCModule::OnExit()
2234{
2235 wxCleanUpGCPool();
2236}