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