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