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