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