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