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