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