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