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