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