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