1 /////////////////////////////////////////////////////////////////////////////
2 // Name: gtk/dcclient.cpp
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling, Markus Holzem, Chris Breeze
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
11 #pragma implementation "dcclient.h"
14 #include "wx/dcclient.h"
15 #include "wx/dcmemory.h"
17 #include "wx/module.h"
19 #include "wx/gtk/win_gtk.h"
21 #include <math.h> // for floating-point functions
27 //-----------------------------------------------------------------------------
29 //-----------------------------------------------------------------------------
31 #define USE_PAINT_REGION 1
33 //-----------------------------------------------------------------------------
35 //-----------------------------------------------------------------------------
45 static GdkPixmap
*hatches
[num_hatches
];
46 static GdkPixmap
**hatch_bitmap
= (GdkPixmap
**) NULL
;
48 extern GtkWidget
*wxRootWindow
;
50 //-----------------------------------------------------------------------------
52 //-----------------------------------------------------------------------------
54 const double RAD2DEG
= 180.0 / M_PI
;
56 // ----------------------------------------------------------------------------
58 // ----------------------------------------------------------------------------
60 static inline double dmax(double a
, double b
) { return a
> b
? a
: b
; }
61 static inline double dmin(double a
, double b
) { return a
< b
? a
: b
; }
63 static inline double DegToRad(double deg
) { return (deg
* M_PI
) / 180.0; }
65 //-----------------------------------------------------------------------------
66 // temporary implementation of the missing GDK function
67 //-----------------------------------------------------------------------------
69 #include "gdk/gdkprivate.h"
71 void gdk_draw_bitmap (GdkDrawable
*drawable
,
81 GdkWindowPrivate
*drawable_private
;
82 GdkWindowPrivate
*src_private
;
83 GdkGCPrivate
*gc_private
;
85 g_return_if_fail (drawable
!= NULL
);
86 g_return_if_fail (src
!= NULL
);
87 g_return_if_fail (gc
!= NULL
);
89 drawable_private
= (GdkWindowPrivate
*) drawable
;
90 src_private
= (GdkWindowPrivate
*) src
;
91 if (drawable_private
->destroyed
|| src_private
->destroyed
)
94 gc_private
= (GdkGCPrivate
*) gc
;
96 if (width
== -1) width
= src_private
->width
;
97 if (height
== -1) height
= src_private
->height
;
99 XCopyPlane( drawable_private
->xdisplay
,
100 src_private
->xwindow
,
101 drawable_private
->xwindow
,
109 //-----------------------------------------------------------------------------
110 // Implement Pool of Graphic contexts. Creating them takes too much time.
111 //-----------------------------------------------------------------------------
113 #define GC_POOL_SIZE 200
135 static wxGC wxGCPool
[GC_POOL_SIZE
];
137 static void wxInitGCPool()
139 memset( wxGCPool
, 0, GC_POOL_SIZE
*sizeof(wxGC
) );
142 static void wxCleanUpGCPool()
144 for (int i
= 0; i
< GC_POOL_SIZE
; i
++)
146 if (wxGCPool
[i
].m_gc
)
147 gdk_gc_unref( wxGCPool
[i
].m_gc
);
151 static GdkGC
* wxGetPoolGC( GdkWindow
*window
, wxPoolGCType type
)
153 for (int i
= 0; i
< GC_POOL_SIZE
; i
++)
155 if (!wxGCPool
[i
].m_gc
)
157 wxGCPool
[i
].m_gc
= gdk_gc_new( window
);
158 gdk_gc_set_exposures( wxGCPool
[i
].m_gc
, FALSE
);
159 wxGCPool
[i
].m_type
= type
;
160 wxGCPool
[i
].m_used
= FALSE
;
162 if ((!wxGCPool
[i
].m_used
) && (wxGCPool
[i
].m_type
== type
))
164 wxGCPool
[i
].m_used
= TRUE
;
165 return wxGCPool
[i
].m_gc
;
169 wxFAIL_MSG( wxT("No GC available") );
171 return (GdkGC
*) NULL
;
174 static void wxFreePoolGC( GdkGC
*gc
)
176 for (int i
= 0; i
< GC_POOL_SIZE
; i
++)
178 if (wxGCPool
[i
].m_gc
== gc
)
180 wxGCPool
[i
].m_used
= FALSE
;
185 wxFAIL_MSG( wxT("Wrong GC") );
188 //-----------------------------------------------------------------------------
190 //-----------------------------------------------------------------------------
192 IMPLEMENT_DYNAMIC_CLASS(wxWindowDC
, wxDC
)
194 wxWindowDC::wxWindowDC()
196 m_penGC
= (GdkGC
*) NULL
;
197 m_brushGC
= (GdkGC
*) NULL
;
198 m_textGC
= (GdkGC
*) NULL
;
199 m_bgGC
= (GdkGC
*) NULL
;
200 m_cmap
= (GdkColormap
*) NULL
;
202 m_isScreenDC
= FALSE
;
203 m_owner
= (wxWindow
*)NULL
;
206 wxWindowDC::wxWindowDC( wxWindow
*window
)
208 m_penGC
= (GdkGC
*) NULL
;
209 m_brushGC
= (GdkGC
*) NULL
;
210 m_textGC
= (GdkGC
*) NULL
;
211 m_bgGC
= (GdkGC
*) NULL
;
212 m_cmap
= (GdkColormap
*) NULL
;
213 m_owner
= (wxWindow
*)NULL
;
215 m_isScreenDC
= FALSE
;
216 m_font
= window
->GetFont();
218 wxASSERT_MSG( window
, wxT("DC needs a window") );
220 GtkWidget
*widget
= window
->m_wxwindow
;
222 // some controls don't have m_wxwindow - like wxStaticBox, but the user
223 // code should still be able to create wxClientDCs for them, so we will
224 // use the parent window here then
227 window
= window
->GetParent();
228 widget
= window
->m_wxwindow
;
231 wxASSERT_MSG( widget
, wxT("DC needs a widget") );
233 GtkPizza
*pizza
= GTK_PIZZA( widget
);
234 m_window
= pizza
->bin_window
;
239 /* don't report problems */
245 m_cmap
= gtk_widget_get_colormap( widget
? widget
: window
->m_widget
);
249 /* this must be done after SetUpDC, bacause SetUpDC calls the
250 repective SetBrush, SetPen, SetBackground etc functions
251 to set up the DC. SetBackground call m_owner->SetBackground
252 and this might not be desired as the standard dc background
253 is white whereas a window might assume gray to be the
254 standard (as e.g. wxStatusBar) */
259 wxWindowDC::~wxWindowDC()
264 void wxWindowDC::SetUpDC()
268 wxASSERT_MSG( !m_penGC
, wxT("GCs already created") );
270 if (m_isMemDC
&& (((wxMemoryDC
*)this)->m_selected
.GetDepth() == 1))
272 m_penGC
= wxGetPoolGC( m_window
, wxPEN_MONO
);
273 m_brushGC
= wxGetPoolGC( m_window
, wxBRUSH_MONO
);
274 m_textGC
= wxGetPoolGC( m_window
, wxTEXT_MONO
);
275 m_bgGC
= wxGetPoolGC( m_window
, wxBG_MONO
);
279 m_penGC
= wxGetPoolGC( m_window
, wxPEN_COLOUR
);
280 m_brushGC
= wxGetPoolGC( m_window
, wxBRUSH_COLOUR
);
281 m_textGC
= wxGetPoolGC( m_window
, wxTEXT_COLOUR
);
282 m_bgGC
= wxGetPoolGC( m_window
, wxBG_COLOUR
);
285 /* background colour */
286 m_backgroundBrush
= *wxWHITE_BRUSH
;
287 m_backgroundBrush
.GetColour().CalcPixel( m_cmap
);
288 GdkColor
*bg_col
= m_backgroundBrush
.GetColour().GetColor();
291 m_textForegroundColour
.CalcPixel( m_cmap
);
292 gdk_gc_set_foreground( m_textGC
, m_textForegroundColour
.GetColor() );
294 m_textBackgroundColour
.CalcPixel( m_cmap
);
295 gdk_gc_set_background( m_textGC
, m_textBackgroundColour
.GetColor() );
297 gdk_gc_set_fill( m_textGC
, GDK_SOLID
);
300 m_pen
.GetColour().CalcPixel( m_cmap
);
301 gdk_gc_set_foreground( m_penGC
, m_pen
.GetColour().GetColor() );
302 gdk_gc_set_background( m_penGC
, bg_col
);
304 gdk_gc_set_line_attributes( m_penGC
, 0, GDK_LINE_SOLID
, GDK_CAP_NOT_LAST
, GDK_JOIN_ROUND
);
308 m_brush
.GetColour().CalcPixel( m_cmap
);
309 gdk_gc_set_foreground( m_brushGC
, m_brush
.GetColour().GetColor() );
310 gdk_gc_set_background( m_brushGC
, bg_col
);
312 gdk_gc_set_fill( m_brushGC
, GDK_SOLID
);
316 gdk_gc_set_background( m_bgGC
, bg_col
);
317 gdk_gc_set_foreground( m_bgGC
, bg_col
);
319 gdk_gc_set_fill( m_bgGC
, GDK_SOLID
);
322 gdk_gc_set_function( m_textGC
, GDK_COPY
);
323 gdk_gc_set_function( m_brushGC
, GDK_COPY
);
324 gdk_gc_set_function( m_penGC
, GDK_COPY
);
327 gdk_gc_set_clip_rectangle( m_penGC
, (GdkRectangle
*) NULL
);
328 gdk_gc_set_clip_rectangle( m_brushGC
, (GdkRectangle
*) NULL
);
329 gdk_gc_set_clip_rectangle( m_textGC
, (GdkRectangle
*) NULL
);
330 gdk_gc_set_clip_rectangle( m_bgGC
, (GdkRectangle
*) NULL
);
334 hatch_bitmap
= hatches
;
335 hatch_bitmap
[0] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, bdiag_bits
, bdiag_width
, bdiag_height
);
336 hatch_bitmap
[1] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, cdiag_bits
, cdiag_width
, cdiag_height
);
337 hatch_bitmap
[2] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, fdiag_bits
, fdiag_width
, fdiag_height
);
338 hatch_bitmap
[3] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, cross_bits
, cross_width
, cross_height
);
339 hatch_bitmap
[4] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, horiz_bits
, horiz_width
, horiz_height
);
340 hatch_bitmap
[5] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, verti_bits
, verti_width
, verti_height
);
344 void wxWindowDC::DoFloodFill( wxCoord
WXUNUSED(x
), wxCoord
WXUNUSED(y
),
345 const wxColour
&WXUNUSED(col
), int WXUNUSED(style
) )
347 wxFAIL_MSG( wxT("wxWindowDC::DoFloodFill not implemented") );
350 bool wxWindowDC::DoGetPixel( wxCoord x1
, wxCoord y1
, wxColour
*col
) const
352 // Generic (and therefore rather inefficient) method.
353 // Could be improved.
355 wxBitmap
bitmap(1, 1);
356 memdc
.SelectObject(bitmap
);
357 memdc
.Blit(0, 0, 1, 1, (wxDC
*) this, x1
, y1
);
358 memdc
.SelectObject(wxNullBitmap
);
359 wxImage
image(bitmap
);
360 col
->Set(image
.GetRed(0, 0), image
.GetGreen(0, 0), image
.GetBlue(0, 0));
364 void wxWindowDC::DoDrawLine( wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
366 wxCHECK_RET( Ok(), wxT("invalid window dc") );
368 if (m_pen
.GetStyle() != wxTRANSPARENT
)
371 gdk_draw_line( m_window
, m_penGC
, XLOG2DEV(x1
), YLOG2DEV(y1
), XLOG2DEV(x2
), YLOG2DEV(y2
) );
373 CalcBoundingBox(x1
, y1
);
374 CalcBoundingBox(x2
, y2
);
378 void wxWindowDC::DoCrossHair( wxCoord x
, wxCoord y
)
380 wxCHECK_RET( Ok(), wxT("invalid window dc") );
382 if (m_pen
.GetStyle() != wxTRANSPARENT
)
387 wxCoord xx
= XLOG2DEV(x
);
388 wxCoord yy
= YLOG2DEV(y
);
391 gdk_draw_line( m_window
, m_penGC
, 0, yy
, XLOG2DEVREL(w
), yy
);
392 gdk_draw_line( m_window
, m_penGC
, xx
, 0, xx
, YLOG2DEVREL(h
) );
397 void wxWindowDC::DoDrawArc( wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
,
398 wxCoord xc
, wxCoord yc
)
400 wxCHECK_RET( Ok(), wxT("invalid window dc") );
402 wxCoord xx1
= XLOG2DEV(x1
);
403 wxCoord yy1
= YLOG2DEV(y1
);
404 wxCoord xx2
= XLOG2DEV(x2
);
405 wxCoord yy2
= YLOG2DEV(y2
);
406 wxCoord xxc
= XLOG2DEV(xc
);
407 wxCoord yyc
= YLOG2DEV(yc
);
408 double dx
= xx1
- xxc
;
409 double dy
= yy1
- yyc
;
410 double radius
= sqrt((double)(dx
*dx
+dy
*dy
));
411 wxCoord r
= (wxCoord
)radius
;
412 double radius1
, radius2
;
414 if (xx1
== xx2
&& yy1
== yy2
)
422 radius1
= radius2
= 0.0;
426 radius1
= (xx1
- xxc
== 0) ?
427 (yy1
- yyc
< 0) ? 90.0 : -90.0 :
428 -atan2(double(yy1
-yyc
), double(xx1
-xxc
)) * RAD2DEG
;
429 radius2
= (xx2
- xxc
== 0) ?
430 (yy2
- yyc
< 0) ? 90.0 : -90.0 :
431 -atan2(double(yy2
-yyc
), double(xx2
-xxc
)) * RAD2DEG
;
433 wxCoord alpha1
= wxCoord(radius1
* 64.0);
434 wxCoord alpha2
= wxCoord((radius2
- radius1
) * 64.0);
435 while (alpha2
<= 0) alpha2
+= 360*64;
436 while (alpha1
> 360*64) alpha1
-= 360*64;
440 if (m_brush
.GetStyle() != wxTRANSPARENT
)
441 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xxc
-r
, yyc
-r
, 2*r
,2*r
, alpha1
, alpha2
);
443 if (m_pen
.GetStyle() != wxTRANSPARENT
)
444 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xxc
-r
, yyc
-r
, 2*r
,2*r
, alpha1
, alpha2
);
447 CalcBoundingBox (x1
, y1
);
448 CalcBoundingBox (x2
, y2
);
451 void wxWindowDC::DoDrawEllipticArc( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double sa
, double ea
)
453 wxCHECK_RET( Ok(), wxT("invalid window dc") );
455 wxCoord xx
= XLOG2DEV(x
);
456 wxCoord yy
= YLOG2DEV(y
);
457 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
458 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
460 // CMB: handle -ve width and/or height
461 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
462 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
466 wxCoord start
= wxCoord(sa
* 64.0);
467 wxCoord end
= wxCoord(ea
* 64.0);
469 if (m_brush
.GetStyle() != wxTRANSPARENT
)
470 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, start
, end
);
472 if (m_pen
.GetStyle() != wxTRANSPARENT
)
473 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
, hh
, start
, end
);
476 CalcBoundingBox (x
, y
);
477 CalcBoundingBox (x
+ width
, y
+ height
);
480 void wxWindowDC::DoDrawPoint( wxCoord x
, wxCoord y
)
482 wxCHECK_RET( Ok(), wxT("invalid window dc") );
484 if ((m_pen
.GetStyle() != wxTRANSPARENT
) && m_window
)
485 gdk_draw_point( m_window
, m_penGC
, XLOG2DEV(x
), YLOG2DEV(y
) );
487 CalcBoundingBox (x
, y
);
490 void wxWindowDC::DoDrawLines( int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
492 wxCHECK_RET( Ok(), wxT("invalid window dc") );
494 if (m_pen
.GetStyle() == wxTRANSPARENT
) return;
497 CalcBoundingBox( points
[0].x
+ xoffset
, points
[0].y
+ yoffset
);
499 for (int i
= 0; i
< n
-1; i
++)
501 wxCoord x1
= XLOG2DEV(points
[i
].x
+ xoffset
);
502 wxCoord x2
= XLOG2DEV(points
[i
+1].x
+ xoffset
);
503 wxCoord y1
= YLOG2DEV(points
[i
].y
+ yoffset
); // oh, what a waste
504 wxCoord y2
= YLOG2DEV(points
[i
+1].y
+ yoffset
);
507 gdk_draw_line( m_window
, m_penGC
, x1
, y1
, x2
, y2
);
509 CalcBoundingBox( points
[i
+1].x
+ xoffset
, points
[i
+1].y
+ yoffset
);
513 void wxWindowDC::DoDrawPolygon( int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
, int WXUNUSED(fillStyle
) )
515 wxCHECK_RET( Ok(), wxT("invalid window dc") );
519 GdkPoint
*gdkpoints
= new GdkPoint
[n
+1];
521 for (i
= 0 ; i
< n
; i
++)
523 gdkpoints
[i
].x
= XLOG2DEV(points
[i
].x
+ xoffset
);
524 gdkpoints
[i
].y
= YLOG2DEV(points
[i
].y
+ yoffset
);
526 CalcBoundingBox( points
[i
].x
+ xoffset
, points
[i
].y
+ yoffset
);
531 if (m_brush
.GetStyle() != wxTRANSPARENT
)
533 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
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_polygon( m_window
, m_textGC
, TRUE
, gdkpoints
, n
);
539 gdk_gc_set_ts_origin( m_textGC
, 0, 0 );
541 if (m_brush
.GetStyle() == wxSTIPPLE
)
543 gdk_gc_set_ts_origin( m_brushGC
,
544 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
545 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
546 gdk_draw_polygon( m_window
, m_brushGC
, TRUE
, gdkpoints
, n
);
547 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
551 gdk_draw_polygon( m_window
, m_brushGC
, TRUE
, gdkpoints
, n
);
557 if (m_pen
.GetStyle() != wxTRANSPARENT
)
559 for (i
= 0 ; i
< n
; i
++)
561 gdk_draw_line( m_window
, m_penGC
,
564 gdkpoints
[(i
+1)%n
].x
,
565 gdkpoints
[(i
+1)%n
].y
);
573 void wxWindowDC::DoDrawRectangle( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
575 wxCHECK_RET( Ok(), wxT("invalid window dc") );
577 wxCoord xx
= XLOG2DEV(x
);
578 wxCoord yy
= YLOG2DEV(y
);
579 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
580 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
582 // CMB: draw nothing if transformed w or h is 0
583 if (ww
== 0 || hh
== 0) return;
585 // CMB: handle -ve width and/or height
586 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
587 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
591 if (m_brush
.GetStyle() != wxTRANSPARENT
)
593 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
595 gdk_gc_set_ts_origin( m_textGC
,
596 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
597 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
598 gdk_draw_rectangle( m_window
, m_textGC
, TRUE
, xx
, yy
, ww
, hh
);
599 gdk_gc_set_ts_origin( m_textGC
, 0, 0 );
601 else if (m_brush
.GetStyle() == wxSTIPPLE
)
603 gdk_gc_set_ts_origin( m_brushGC
,
604 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
605 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
606 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
);
607 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
611 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
);
615 if (m_pen
.GetStyle() != wxTRANSPARENT
)
616 gdk_draw_rectangle( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
-1, hh
-1 );
619 CalcBoundingBox( x
, y
);
620 CalcBoundingBox( x
+ width
, y
+ height
);
623 void wxWindowDC::DoDrawRoundedRectangle( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
625 wxCHECK_RET( Ok(), wxT("invalid window dc") );
627 if (radius
< 0.0) radius
= - radius
* ((width
< height
) ? width
: height
);
629 wxCoord xx
= XLOG2DEV(x
);
630 wxCoord yy
= YLOG2DEV(y
);
631 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
632 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
633 wxCoord rr
= XLOG2DEVREL((wxCoord
)radius
);
635 // CMB: handle -ve width and/or height
636 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
637 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
639 // CMB: if radius is zero use DrawRectangle() instead to avoid
640 // X drawing errors with small radii
643 DrawRectangle( x
, y
, width
, height
);
647 // CMB: draw nothing if transformed w or h is 0
648 if (ww
== 0 || hh
== 0) return;
650 // CMB: adjust size if outline is drawn otherwise the result is
651 // 1 pixel too wide and high
652 if (m_pen
.GetStyle() != wxTRANSPARENT
)
660 // CMB: ensure dd is not larger than rectangle otherwise we
661 // get an hour glass shape
663 if (dd
> ww
) dd
= ww
;
664 if (dd
> hh
) dd
= hh
;
667 if (m_brush
.GetStyle() != wxTRANSPARENT
)
669 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
+rr
, yy
, ww
-dd
+1, hh
);
670 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
+rr
, ww
, hh
-dd
+1 );
671 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, dd
, dd
, 90*64, 90*64 );
672 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 );
673 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 );
674 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 );
677 if (m_pen
.GetStyle() != wxTRANSPARENT
)
679 gdk_draw_line( m_window
, m_penGC
, xx
+rr
, yy
, xx
+ww
-rr
, yy
);
680 gdk_draw_line( m_window
, m_penGC
, xx
+rr
, yy
+hh
, xx
+ww
-rr
, yy
+hh
);
681 gdk_draw_line( m_window
, m_penGC
, xx
, yy
+rr
, xx
, yy
+hh
-rr
);
682 gdk_draw_line( m_window
, m_penGC
, xx
+ww
, yy
+rr
, xx
+ww
, yy
+hh
-rr
);
683 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
, dd
, dd
, 90*64, 90*64 );
684 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 );
685 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 );
686 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 );
690 // this ignores the radius
691 CalcBoundingBox( x
, y
);
692 CalcBoundingBox( x
+ width
, y
+ height
);
695 void wxWindowDC::DoDrawEllipse( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
697 wxCHECK_RET( Ok(), wxT("invalid window dc") );
699 wxCoord xx
= XLOG2DEV(x
);
700 wxCoord yy
= YLOG2DEV(y
);
701 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
702 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
704 // CMB: handle -ve width and/or height
705 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
706 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
710 if (m_brush
.GetStyle() != wxTRANSPARENT
)
711 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, 0, 360*64 );
713 if (m_pen
.GetStyle() != wxTRANSPARENT
)
714 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
, hh
, 0, 360*64 );
717 CalcBoundingBox( x
- width
, y
- height
);
718 CalcBoundingBox( x
+ width
, y
+ height
);
721 void wxWindowDC::DoDrawIcon( const wxIcon
&icon
, wxCoord x
, wxCoord y
)
723 // VZ: egcs 1.0.3 refuses to compile this without cast, no idea why
724 DoDrawBitmap( (const wxBitmap
&)icon
, x
, y
, (bool)TRUE
);
727 void wxWindowDC::DoDrawBitmap( const wxBitmap
&bitmap
,
728 wxCoord x
, wxCoord y
,
731 wxCHECK_RET( Ok(), wxT("invalid window dc") );
733 wxCHECK_RET( bitmap
.Ok(), wxT("invalid bitmap") );
735 bool is_mono
= (bitmap
.GetBitmap() != NULL
);
737 /* scale/translate size and position */
738 int xx
= XLOG2DEV(x
);
739 int yy
= YLOG2DEV(y
);
741 int w
= bitmap
.GetWidth();
742 int h
= bitmap
.GetHeight();
744 CalcBoundingBox( x
, y
);
745 CalcBoundingBox( x
+ w
, y
+ h
);
747 if (!m_window
) return;
749 int ww
= XLOG2DEVREL(w
);
750 int hh
= YLOG2DEVREL(h
);
752 /* compare to current clipping region */
753 if (!m_currentClippingRegion
.IsNull())
755 wxRegion
tmp( xx
,yy
,ww
,hh
);
756 tmp
.Intersect( m_currentClippingRegion
);
761 /* scale bitmap if required */
763 if ((w
!= ww
) || (h
!= hh
))
765 wxImage
image( bitmap
);
766 image
.Rescale( ww
, hh
);
768 use_bitmap
= image
.ConvertToMonoBitmap(255,255,255);
770 use_bitmap
= image
.ConvertToBitmap();
777 /* apply mask if any */
778 GdkBitmap
*mask
= (GdkBitmap
*) NULL
;
779 if (use_bitmap
.GetMask()) mask
= use_bitmap
.GetMask()->GetBitmap();
783 GdkBitmap
*new_mask
= (GdkBitmap
*) NULL
;
784 if (!m_currentClippingRegion
.IsNull())
787 new_mask
= gdk_pixmap_new( wxRootWindow
->window
, ww
, hh
, 1 );
788 GdkGC
*gc
= gdk_gc_new( new_mask
);
790 gdk_gc_set_foreground( gc
, &col
);
791 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, ww
, hh
);
793 gdk_gc_set_background( gc
, &col
);
795 gdk_gc_set_foreground( gc
, &col
);
796 gdk_gc_set_clip_region( gc
, m_currentClippingRegion
.GetRegion() );
797 gdk_gc_set_clip_origin( gc
, -xx
, -yy
);
798 gdk_gc_set_fill( gc
, GDK_OPAQUE_STIPPLED
);
799 gdk_gc_set_stipple( gc
, mask
);
800 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, ww
, hh
);
802 gdk_gc_set_clip_mask( m_brushGC, NULL );
803 gdk_gc_set_clip_mask( m_textGC, NULL );
804 SetBrush( *wxRED_BRUSH );
805 DrawRectangle( 70, 0, 70, 1000 );
806 gdk_draw_bitmap( m_window, m_textGC, new_mask, 0, 0, 100, 5, ww, hh );
807 gdk_draw_bitmap( m_window, m_textGC, mask, 0, 0, 80, 5, ww, hh );
815 gdk_gc_set_clip_mask( m_textGC
, new_mask
);
817 gdk_gc_set_clip_mask( m_textGC
, mask
);
818 gdk_gc_set_clip_origin( m_textGC
, xx
, yy
);
823 gdk_gc_set_clip_mask( m_penGC
, new_mask
);
825 gdk_gc_set_clip_mask( m_penGC
, mask
);
826 gdk_gc_set_clip_origin( m_penGC
, xx
, yy
);
829 gdk_bitmap_unref( new_mask
);
832 /* Draw XPixmap or XBitmap, depending on what the wxBitmap contains. For
833 drawing a mono-bitmap (XBitmap) we use the current text GC */
835 gdk_draw_bitmap( m_window
, m_textGC
, use_bitmap
.GetBitmap(), 0, 0, xx
, yy
, -1, -1 );
837 gdk_draw_pixmap( m_window
, m_penGC
, use_bitmap
.GetPixmap(), 0, 0, xx
, yy
, -1, -1 );
839 /* remove mask again if any */
844 gdk_gc_set_clip_mask( m_textGC
, (GdkBitmap
*) NULL
);
845 gdk_gc_set_clip_origin( m_textGC
, 0, 0 );
846 if (!m_currentClippingRegion
.IsNull())
847 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
851 gdk_gc_set_clip_mask( m_penGC
, (GdkBitmap
*) NULL
);
852 gdk_gc_set_clip_origin( m_penGC
, 0, 0 );
853 if (!m_currentClippingRegion
.IsNull())
854 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
859 bool wxWindowDC::DoBlit( wxCoord xdest
, wxCoord ydest
, wxCoord width
, wxCoord height
,
860 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
,
861 int logical_func
, bool useMask
)
863 /* this is the nth try to get this utterly useless function to
864 work. it now completely ignores the scaling or translation
865 of the source dc, but scales correctly on the target dc and
866 knows about possible mask information in a memory dc. */
868 wxCHECK_MSG( Ok(), FALSE
, wxT("invalid window dc") );
870 wxCHECK_MSG( source
, FALSE
, wxT("invalid source dc") );
872 if (!m_window
) return FALSE
;
874 wxClientDC
*srcDC
= (wxClientDC
*)source
;
875 wxMemoryDC
*memDC
= (wxMemoryDC
*)source
;
877 bool use_bitmap_method
= FALSE
;
878 bool is_mono
= FALSE
;
880 if (srcDC
->m_isMemDC
)
882 if (!memDC
->m_selected
.Ok()) return FALSE
;
884 /* we use the "XCopyArea" way to copy a memory dc into
885 y different window if the memory dc BOTH
886 a) doesn't have any mask or its mask isn't used
890 if (useMask
&& (memDC
->m_selected
.GetMask()))
892 /* we HAVE TO use the direct way for memory dcs
893 that have mask since the XCopyArea doesn't know
895 use_bitmap_method
= TRUE
;
897 else if (memDC
->m_selected
.GetDepth() == 1)
899 /* we HAVE TO use the direct way for memory dcs
900 that are bitmaps because XCopyArea doesn't cope
901 with different bit depths */
903 use_bitmap_method
= TRUE
;
905 else if ((xsrc
== 0) && (ysrc
== 0) &&
906 (width
== memDC
->m_selected
.GetWidth()) &&
907 (height
== memDC
->m_selected
.GetHeight()))
909 /* we SHOULD use the direct way if all of the bitmap
910 in the memory dc is copied in which case XCopyArea
911 wouldn't be able able to boost performace by reducing
912 the area to be scaled */
913 use_bitmap_method
= TRUE
;
917 use_bitmap_method
= FALSE
;
921 CalcBoundingBox( xdest
, ydest
);
922 CalcBoundingBox( xdest
+ width
, ydest
+ height
);
924 /* scale/translate size and position */
925 wxCoord xx
= XLOG2DEV(xdest
);
926 wxCoord yy
= YLOG2DEV(ydest
);
928 wxCoord ww
= XLOG2DEVREL(width
);
929 wxCoord hh
= YLOG2DEVREL(height
);
931 /* compare to current clipping region */
932 if (!m_currentClippingRegion
.IsNull())
934 wxRegion
tmp( xx
,yy
,ww
,hh
);
935 tmp
.Intersect( m_currentClippingRegion
);
940 int old_logical_func
= m_logicalFunction
;
941 SetLogicalFunction( logical_func
);
943 if (use_bitmap_method
)
945 /* scale/translate bitmap size */
946 wxCoord bm_width
= memDC
->m_selected
.GetWidth();
947 wxCoord bm_height
= memDC
->m_selected
.GetHeight();
949 wxCoord bm_ww
= XLOG2DEVREL( bm_width
);
950 wxCoord bm_hh
= YLOG2DEVREL( bm_height
);
952 /* scale bitmap if required */
955 if ((bm_width
!= bm_ww
) || (bm_height
!= bm_hh
))
957 wxImage
image( memDC
->m_selected
);
958 image
= image
.Scale( bm_ww
, bm_hh
);
961 use_bitmap
= image
.ConvertToMonoBitmap(255,255,255);
963 use_bitmap
= image
.ConvertToBitmap();
967 use_bitmap
= memDC
->m_selected
;
970 /* apply mask if any */
971 GdkBitmap
*mask
= (GdkBitmap
*) NULL
;
972 if (use_bitmap
.GetMask()) mask
= use_bitmap
.GetMask()->GetBitmap();
976 GdkBitmap
*new_mask
= (GdkBitmap
*) NULL
;
977 if (!m_currentClippingRegion
.IsNull())
980 new_mask
= gdk_pixmap_new( wxRootWindow
->window
, bm_ww
, bm_hh
, 1 );
981 GdkGC
*gc
= gdk_gc_new( new_mask
);
983 gdk_gc_set_foreground( gc
, &col
);
984 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, bm_ww
, bm_hh
);
986 gdk_gc_set_background( gc
, &col
);
988 gdk_gc_set_foreground( gc
, &col
);
989 gdk_gc_set_clip_region( gc
, m_currentClippingRegion
.GetRegion() );
990 gdk_gc_set_clip_origin( gc
, -xx
, -yy
);
991 gdk_gc_set_fill( gc
, GDK_OPAQUE_STIPPLED
);
992 gdk_gc_set_stipple( gc
, mask
);
993 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, bm_ww
, bm_hh
);
1000 gdk_gc_set_clip_mask( m_textGC
, new_mask
);
1002 gdk_gc_set_clip_mask( m_textGC
, mask
);
1003 gdk_gc_set_clip_origin( m_textGC
, xx
, yy
);
1008 gdk_gc_set_clip_mask( m_penGC
, new_mask
);
1010 gdk_gc_set_clip_mask( m_penGC
, mask
);
1011 gdk_gc_set_clip_origin( m_penGC
, xx
, yy
);
1014 gdk_bitmap_unref( new_mask
);
1017 /* Draw XPixmap or XBitmap, depending on what the wxBitmap contains. For
1018 drawing a mono-bitmap (XBitmap) we use the current text GC */
1021 gdk_draw_bitmap( m_window
, m_textGC
, use_bitmap
.GetBitmap(), xsrc
, ysrc
, xx
, yy
, ww
, hh
);
1023 gdk_draw_pixmap( m_window
, m_penGC
, use_bitmap
.GetPixmap(), xsrc
, ysrc
, xx
, yy
, ww
, hh
);
1025 /* remove mask again if any */
1026 if (useMask
&& mask
)
1030 gdk_gc_set_clip_mask( m_textGC
, (GdkBitmap
*) NULL
);
1031 gdk_gc_set_clip_origin( m_textGC
, 0, 0 );
1032 if (!m_currentClippingRegion
.IsNull())
1033 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
1037 gdk_gc_set_clip_mask( m_penGC
, (GdkBitmap
*) NULL
);
1038 gdk_gc_set_clip_origin( m_penGC
, 0, 0 );
1039 if (!m_currentClippingRegion
.IsNull())
1040 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
1044 else /* use_bitmap_method */
1046 if ((width
!= ww
) || (height
!= hh
))
1048 /* draw source window into a bitmap as we cannot scale
1049 a window in contrast to a bitmap. this would actually
1050 work with memory dcs as well, but we'd lose the mask
1051 information and waste one step in this process since
1052 a memory already has a bitmap. all this is slightly
1053 inefficient as we could take an XImage directly from
1054 an X window, but we'd then also have to care that
1055 the window is not outside the screen (in which case
1056 we'd get a BadMatch or what not).
1057 Is a double XGetImage and combined XGetPixel and
1058 XPutPixel really faster? I'm not sure. look at wxXt
1059 for a different implementation of the same problem. */
1061 wxBitmap
bitmap( width
, height
);
1063 if (srcDC
->m_isScreenDC
)
1064 gdk_gc_set_subwindow( m_penGC
, GDK_INCLUDE_INFERIORS
);
1066 gdk_window_copy_area( bitmap
.GetPixmap(), m_penGC
, 0, 0,
1068 xsrc
, ysrc
, width
, height
);
1070 if (srcDC
->m_isScreenDC
)
1071 gdk_gc_set_subwindow( m_penGC
, GDK_CLIP_BY_CHILDREN
);
1075 wxImage
image( bitmap
);
1076 image
= image
.Scale( ww
, hh
);
1078 /* convert to bitmap */
1080 bitmap
= image
.ConvertToBitmap();
1082 /* draw scaled bitmap */
1084 gdk_draw_pixmap( m_window
, m_penGC
, bitmap
.GetPixmap(), 0, 0, xx
, yy
, -1, -1 );
1089 /* No scaling and not a memory dc with a mask either */
1091 if (srcDC
->m_isScreenDC
)
1092 gdk_gc_set_subwindow( m_penGC
, GDK_INCLUDE_INFERIORS
);
1094 gdk_window_copy_area( m_window
, m_penGC
, xx
, yy
,
1096 xsrc
, ysrc
, width
, height
);
1098 if (srcDC
->m_isScreenDC
)
1099 gdk_gc_set_subwindow( m_penGC
, GDK_CLIP_BY_CHILDREN
);
1103 SetLogicalFunction( old_logical_func
);
1107 void wxWindowDC::DoDrawText( const wxString
&text
, wxCoord x
, wxCoord y
)
1109 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1111 if (!m_window
) return;
1113 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
1115 wxCHECK_RET( font
, wxT("invalid font") );
1120 /* CMB 21/5/98: draw text background if mode is wxSOLID */
1121 if (m_backgroundMode
== wxSOLID
)
1123 wxCoord width
= gdk_string_width( font
, text
.mbc_str() );
1124 wxCoord height
= font
->ascent
+ font
->descent
;
1125 gdk_gc_set_foreground( m_textGC
, m_textBackgroundColour
.GetColor() );
1126 gdk_draw_rectangle( m_window
, m_textGC
, TRUE
, x
, y
, width
, height
);
1127 gdk_gc_set_foreground( m_textGC
, m_textForegroundColour
.GetColor() );
1129 gdk_draw_string( m_window
, font
, m_textGC
, x
, y
+ font
->ascent
, text
.mbc_str() );
1131 /* CMB 17/7/98: simple underline: ignores scaling and underlying
1132 X font's XA_UNDERLINE_POSITION and XA_UNDERLINE_THICKNESS
1133 properties (see wxXt implementation) */
1134 if (m_font
.GetUnderlined())
1136 wxCoord width
= gdk_string_width( font
, text
.mbc_str() );
1137 wxCoord ul_y
= y
+ font
->ascent
;
1138 if (font
->descent
> 0) ul_y
++;
1139 gdk_draw_line( m_window
, m_textGC
, x
, ul_y
, x
+ width
, ul_y
);
1143 GetTextExtent (text
, &w
, &h
);
1144 CalcBoundingBox (x
+ w
, y
+ h
);
1145 CalcBoundingBox (x
, y
);
1148 void wxWindowDC::DoDrawRotatedText( const wxString
&text
, wxCoord x
, wxCoord y
, double angle
)
1152 DrawText(text
, x
, y
);
1156 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1158 if (!m_window
) return;
1160 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
1162 wxCHECK_RET( font
, wxT("invalid font") );
1164 // the size of the text
1165 wxCoord w
= gdk_string_width( font
, text
.mbc_str() );
1166 wxCoord h
= font
->ascent
+ font
->descent
;
1168 // draw the string normally
1171 dc
.SelectObject(src
);
1172 dc
.SetFont(GetFont());
1173 dc
.SetBackground(*wxWHITE_BRUSH
);
1174 dc
.SetBrush(*wxBLACK_BRUSH
);
1176 dc
.DrawText(text
, 0, 0);
1177 dc
.SetFont(wxNullFont
);
1178 dc
.SelectObject(wxNullBitmap
);
1180 // Calculate the size of the rotated bounding box.
1181 double rad
= DegToRad(angle
);
1182 double dx
= cos(rad
),
1185 // the rectngle vertices are counted clockwise with the first one being at
1186 // (0, 0) (or, rather, at (x, y))
1188 y2
= -w
*dy
; // y axis points to the bottom, hence minus
1191 double x3
= x4
+ x2
,
1195 wxCoord maxX
= (wxCoord
)(dmax(x2
, dmax(x3
, x4
)) + 0.5),
1196 maxY
= (wxCoord
)(dmax(y2
, dmax(y3
, y4
)) + 0.5),
1197 minX
= (wxCoord
)(dmin(x2
, dmin(x3
, x4
)) - 0.5),
1198 minY
= (wxCoord
)(dmin(y2
, dmin(y3
, y4
)) - 0.5);
1200 // prepare to blit-with-rotate the bitmap to the DC
1203 GdkColor
*colText
= m_textForegroundColour
.GetColor(),
1204 *colBack
= m_textBackgroundColour
.GetColor();
1206 bool textColSet
= TRUE
;
1208 unsigned char *data
= image
.GetData();
1210 // paint pixel by pixel
1211 for ( wxCoord srcX
= 0; srcX
< w
; srcX
++ )
1213 for ( wxCoord srcY
= 0; srcY
< h
; srcY
++ )
1215 // transform source coords to dest coords
1216 double r
= sqrt(srcX
*srcX
+ srcY
*srcY
);
1217 double angleOrig
= atan2(srcY
, srcX
) - rad
;
1218 wxCoord dstX
= (wxCoord
)(r
*cos(angleOrig
) + 0.5),
1219 dstY
= (wxCoord
)(r
*sin(angleOrig
) + 0.5);
1222 bool textPixel
= data
[(srcY
*w
+ srcX
)*3] == 0;
1223 if ( textPixel
|| (m_backgroundMode
== wxSOLID
) )
1225 // change colour if needed
1226 if ( textPixel
!= textColSet
)
1228 gdk_gc_set_foreground( m_textGC
, textPixel
? colText
1231 textColSet
= textPixel
;
1234 // don't use DrawPoint() because it uses the current pen
1235 // colour, and we don't need it here
1236 gdk_draw_point( m_window
, m_textGC
,
1237 XLOG2DEV(x
+ dstX
), YLOG2DEV(y
+ dstY
) );
1242 // it would be better to draw with non underlined font and draw the line
1243 // manually here (it would be more straight...)
1245 if ( m_font
.GetUnderlined() )
1247 gdk_draw_line( m_window
, m_textGC
,
1248 XLOG2DEV(x
+ x4
), YLOG2DEV(y
+ y4
+ font
->descent
),
1249 XLOG2DEV(x
+ x3
), YLOG2DEV(y
+ y3
+ font
->descent
));
1253 // restore the font colour
1254 gdk_gc_set_foreground( m_textGC
, colText
);
1256 // update the bounding box
1257 CalcBoundingBox(x
+ minX
, y
+ minY
);
1258 CalcBoundingBox(x
+ maxX
, y
+ maxY
);
1261 void wxWindowDC::DoGetTextExtent(const wxString
&string
,
1262 wxCoord
*width
, wxCoord
*height
,
1263 wxCoord
*descent
, wxCoord
*externalLeading
,
1264 wxFont
*theFont
) const
1266 wxFont fontToUse
= m_font
;
1267 if (theFont
) fontToUse
= *theFont
;
1269 GdkFont
*font
= fontToUse
.GetInternalFont( m_scaleY
);
1270 if (width
) (*width
) = wxCoord(gdk_string_width( font
, string
.mbc_str() ) / m_scaleX
);
1271 if (height
) (*height
) = wxCoord((font
->ascent
+ font
->descent
) / m_scaleY
);
1272 if (descent
) (*descent
) = wxCoord(font
->descent
/ m_scaleY
);
1273 if (externalLeading
) (*externalLeading
) = 0; // ??
1276 wxCoord
wxWindowDC::GetCharWidth() const
1278 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
1279 wxCHECK_MSG( font
, -1, wxT("invalid font") );
1281 return wxCoord(gdk_string_width( font
, "H" ) / m_scaleX
);
1284 wxCoord
wxWindowDC::GetCharHeight() const
1286 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
1287 wxCHECK_MSG( font
, -1, wxT("invalid font") );
1289 return wxCoord((font
->ascent
+ font
->descent
) / m_scaleY
);
1292 void wxWindowDC::Clear()
1294 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1296 if (!m_window
) return;
1298 /* - we either are a memory dc or have a window as the
1299 owner. anything else shouldn't happen.
1300 - we don't use gdk_window_clear() as we don't set
1301 the window's background colour anymore. it is too
1302 much pain to keep the DC's and the window's back-
1303 ground colour in synch. */
1308 m_owner
->GetSize( &width
, &height
);
1309 gdk_draw_rectangle( m_window
, m_bgGC
, TRUE
, 0, 0, width
, height
);
1316 GetSize( &width
, &height
);
1317 gdk_draw_rectangle( m_window
, m_bgGC
, TRUE
, 0, 0, width
, height
);
1322 void wxWindowDC::SetFont( const wxFont
&font
)
1327 void wxWindowDC::SetPen( const wxPen
&pen
)
1329 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1331 if (m_pen
== pen
) return;
1335 if (!m_pen
.Ok()) return;
1337 if (!m_window
) return;
1339 gint width
= m_pen
.GetWidth();
1342 // CMB: if width is non-zero scale it with the dc
1347 // X doesn't allow different width in x and y and so we take
1350 ( fabs((double) XLOG2DEVREL(width
)) +
1351 fabs((double) YLOG2DEVREL(width
)) ) / 2.0;
1355 static const char dotted
[] = {1, 1};
1356 static const char short_dashed
[] = {2, 2};
1357 static const char wxCoord_dashed
[] = {2, 4};
1358 static const char dotted_dashed
[] = {3, 3, 1, 3};
1360 // We express dash pattern in pen width unit, so we are
1361 // independent of zoom factor and so on...
1363 const char *req_dash
;
1365 GdkLineStyle lineStyle
= GDK_LINE_SOLID
;
1366 switch (m_pen
.GetStyle())
1370 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1371 req_nb_dash
= m_pen
.GetDashCount();
1372 req_dash
= m_pen
.GetDash();
1377 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1384 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1386 req_dash
= wxCoord_dashed
;
1391 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1393 req_dash
= short_dashed
;
1398 // lineStyle = GDK_LINE_DOUBLE_DASH;
1399 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1401 req_dash
= dotted_dashed
;
1406 case wxSTIPPLE_MASK_OPAQUE
:
1411 lineStyle
= GDK_LINE_SOLID
;
1412 req_dash
= (wxDash
*)NULL
;
1418 #if (GTK_MINOR_VERSION > 0)
1419 if (req_dash
&& req_nb_dash
)
1421 char *real_req_dash
= new char[req_nb_dash
];
1424 for (int i
= 0; i
< req_nb_dash
; i
++)
1425 real_req_dash
[i
] = req_dash
[i
] * width
;
1426 gdk_gc_set_dashes( m_penGC
, 0, real_req_dash
, req_nb_dash
);
1427 delete[] real_req_dash
;
1431 // No Memory. We use non-scaled dash pattern...
1432 gdk_gc_set_dashes( m_penGC
, 0, (char*)req_dash
, req_nb_dash
);
1437 GdkCapStyle capStyle
= GDK_CAP_ROUND
;
1438 switch (m_pen
.GetCap())
1440 case wxCAP_PROJECTING
: { capStyle
= GDK_CAP_PROJECTING
; break; }
1441 case wxCAP_BUTT
: { capStyle
= GDK_CAP_BUTT
; break; }
1448 capStyle
= GDK_CAP_NOT_LAST
;
1452 capStyle
= GDK_CAP_ROUND
;
1458 GdkJoinStyle joinStyle
= GDK_JOIN_ROUND
;
1459 switch (m_pen
.GetJoin())
1461 case wxJOIN_BEVEL
: { joinStyle
= GDK_JOIN_BEVEL
; break; }
1462 case wxJOIN_MITER
: { joinStyle
= GDK_JOIN_MITER
; break; }
1464 default: { joinStyle
= GDK_JOIN_ROUND
; break; }
1467 gdk_gc_set_line_attributes( m_penGC
, width
, lineStyle
, capStyle
, joinStyle
);
1469 m_pen
.GetColour().CalcPixel( m_cmap
);
1470 gdk_gc_set_foreground( m_penGC
, m_pen
.GetColour().GetColor() );
1473 void wxWindowDC::SetBrush( const wxBrush
&brush
)
1475 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1477 if (m_brush
== brush
) return;
1481 if (!m_brush
.Ok()) return;
1483 if (!m_window
) return;
1485 m_brush
.GetColour().CalcPixel( m_cmap
);
1486 gdk_gc_set_foreground( m_brushGC
, m_brush
.GetColour().GetColor() );
1488 gdk_gc_set_fill( m_brushGC
, GDK_SOLID
);
1490 if ((m_brush
.GetStyle() == wxSTIPPLE
) && (m_brush
.GetStipple()->Ok()))
1492 if (m_brush
.GetStipple()->GetPixmap())
1494 gdk_gc_set_fill( m_brushGC
, GDK_TILED
);
1495 gdk_gc_set_tile( m_brushGC
, m_brush
.GetStipple()->GetPixmap() );
1499 gdk_gc_set_fill( m_brushGC
, GDK_STIPPLED
);
1500 gdk_gc_set_stipple( m_brushGC
, m_brush
.GetStipple()->GetBitmap() );
1504 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
1506 gdk_gc_set_fill( m_textGC
, GDK_OPAQUE_STIPPLED
);
1507 gdk_gc_set_stipple( m_textGC
, m_brush
.GetStipple()->GetMask()->GetBitmap() );
1510 if (IS_HATCH(m_brush
.GetStyle()))
1512 gdk_gc_set_fill( m_brushGC
, GDK_STIPPLED
);
1513 int num
= m_brush
.GetStyle() - wxBDIAGONAL_HATCH
;
1514 gdk_gc_set_stipple( m_brushGC
, hatches
[num
] );
1518 void wxWindowDC::SetBackground( const wxBrush
&brush
)
1520 /* CMB 21/7/98: Added SetBackground. Sets background brush
1521 * for Clear() and bg colour for shapes filled with cross-hatch brush */
1523 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1525 if (m_backgroundBrush
== brush
) return;
1527 m_backgroundBrush
= brush
;
1529 if (!m_backgroundBrush
.Ok()) return;
1531 if (!m_window
) return;
1533 m_backgroundBrush
.GetColour().CalcPixel( m_cmap
);
1534 gdk_gc_set_background( m_brushGC
, m_backgroundBrush
.GetColour().GetColor() );
1535 gdk_gc_set_background( m_penGC
, m_backgroundBrush
.GetColour().GetColor() );
1536 gdk_gc_set_background( m_bgGC
, m_backgroundBrush
.GetColour().GetColor() );
1537 gdk_gc_set_foreground( m_bgGC
, m_backgroundBrush
.GetColour().GetColor() );
1539 gdk_gc_set_fill( m_bgGC
, GDK_SOLID
);
1541 if ((m_backgroundBrush
.GetStyle() == wxSTIPPLE
) && (m_backgroundBrush
.GetStipple()->Ok()))
1543 if (m_backgroundBrush
.GetStipple()->GetPixmap())
1545 gdk_gc_set_fill( m_bgGC
, GDK_TILED
);
1546 gdk_gc_set_tile( m_bgGC
, m_backgroundBrush
.GetStipple()->GetPixmap() );
1550 gdk_gc_set_fill( m_bgGC
, GDK_STIPPLED
);
1551 gdk_gc_set_stipple( m_bgGC
, m_backgroundBrush
.GetStipple()->GetBitmap() );
1555 if (IS_HATCH(m_backgroundBrush
.GetStyle()))
1557 gdk_gc_set_fill( m_bgGC
, GDK_STIPPLED
);
1558 int num
= m_backgroundBrush
.GetStyle() - wxBDIAGONAL_HATCH
;
1559 gdk_gc_set_stipple( m_bgGC
, hatches
[num
] );
1563 void wxWindowDC::SetLogicalFunction( int function
)
1565 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1567 if (m_logicalFunction
== function
)
1570 // VZ: shouldn't this be a CHECK?
1574 GdkFunction mode
= GDK_COPY
;
1577 case wxXOR
: mode
= GDK_XOR
; break;
1578 case wxINVERT
: mode
= GDK_INVERT
; break;
1579 #if (GTK_MINOR_VERSION > 0)
1580 case wxOR_REVERSE
: mode
= GDK_OR_REVERSE
; break;
1581 case wxAND_REVERSE
: mode
= GDK_AND_REVERSE
; break;
1582 case wxCLEAR
: mode
= GDK_CLEAR
; break;
1583 case wxSET
: mode
= GDK_SET
; break;
1584 case wxOR_INVERT
: mode
= GDK_OR_INVERT
; break;
1585 case wxAND
: mode
= GDK_AND
; break;
1586 case wxOR
: mode
= GDK_OR
; break;
1587 case wxEQUIV
: mode
= GDK_EQUIV
; break;
1588 case wxNAND
: mode
= GDK_NAND
; break;
1589 case wxAND_INVERT
: mode
= GDK_AND_INVERT
; break;
1590 case wxCOPY
: mode
= GDK_COPY
; break;
1591 case wxNO_OP
: mode
= GDK_NOOP
; break;
1592 case wxSRC_INVERT
: mode
= GDK_COPY_INVERT
; break;
1594 // unsupported by GTK
1595 case wxNOR
: mode
= GDK_COPY
; break;
1599 wxFAIL_MSG( wxT("unsupported logical function") );
1604 m_logicalFunction
= function
;
1606 gdk_gc_set_function( m_penGC
, mode
);
1607 gdk_gc_set_function( m_brushGC
, mode
);
1609 // to stay compatible with wxMSW, we don't apply ROPs to the text
1610 // operations (i.e. DrawText/DrawRotatedText).
1611 // True, but mono-bitmaps use the m_textGC and they use ROPs as well.
1612 gdk_gc_set_function( m_textGC
, mode
);
1615 void wxWindowDC::SetTextForeground( const wxColour
&col
)
1617 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1619 if (m_textForegroundColour
== col
) return;
1621 m_textForegroundColour
= col
;
1622 if (!m_textForegroundColour
.Ok()) return;
1624 if (!m_window
) return;
1626 m_textForegroundColour
.CalcPixel( m_cmap
);
1627 gdk_gc_set_foreground( m_textGC
, m_textForegroundColour
.GetColor() );
1630 void wxWindowDC::SetTextBackground( const wxColour
&col
)
1632 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1634 if (m_textBackgroundColour
== col
) return;
1636 m_textBackgroundColour
= col
;
1637 if (!m_textBackgroundColour
.Ok()) return;
1639 if (!m_window
) return;
1641 m_textBackgroundColour
.CalcPixel( m_cmap
);
1642 gdk_gc_set_background( m_textGC
, m_textBackgroundColour
.GetColor() );
1645 void wxWindowDC::SetBackgroundMode( int mode
)
1647 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1649 m_backgroundMode
= mode
;
1651 if (!m_window
) return;
1653 // CMB 21/7/98: fill style of cross-hatch brushes is affected by
1654 // transparent/solid background mode
1656 if (m_brush
.GetStyle() != wxSOLID
&& m_brush
.GetStyle() != wxTRANSPARENT
)
1658 gdk_gc_set_fill( m_brushGC
,
1659 (m_backgroundMode
== wxTRANSPARENT
) ? GDK_STIPPLED
: GDK_OPAQUE_STIPPLED
);
1663 void wxWindowDC::SetPalette( const wxPalette
& WXUNUSED(palette
) )
1665 wxFAIL_MSG( wxT("wxWindowDC::SetPalette not implemented") );
1668 void wxWindowDC::DoSetClippingRegion( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
1670 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1672 wxDC::DoSetClippingRegion( x
, y
, width
, height
);
1674 if (!m_window
) return;
1677 rect
.x
= XLOG2DEV(x
);
1678 rect
.y
= YLOG2DEV(y
);
1679 rect
.width
= XLOG2DEVREL(width
);
1680 rect
.height
= YLOG2DEVREL(height
);
1682 if (!m_currentClippingRegion
.IsNull())
1683 m_currentClippingRegion
.Intersect( rect
);
1685 m_currentClippingRegion
.Union( rect
);
1687 #if USE_PAINT_REGION
1688 if (!m_paintClippingRegion
.IsNull())
1689 m_currentClippingRegion
.Intersect( m_paintClippingRegion
);
1692 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
1693 gdk_gc_set_clip_region( m_brushGC
, m_currentClippingRegion
.GetRegion() );
1694 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
1695 gdk_gc_set_clip_region( m_bgGC
, m_currentClippingRegion
.GetRegion() );
1698 void wxWindowDC::DoSetClippingRegionAsRegion( const wxRegion
®ion
)
1700 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1704 DestroyClippingRegion();
1709 region
.GetBox( x
, y
, w
, h
);
1711 wxDC::DoSetClippingRegion( x
, y
, w
, h
);
1713 if (!m_window
) return;
1715 if (!m_currentClippingRegion
.IsNull())
1716 m_currentClippingRegion
.Intersect( region
);
1718 m_currentClippingRegion
.Union( region
);
1720 #if USE_PAINT_REGION
1721 if (!m_paintClippingRegion
.IsNull())
1722 m_currentClippingRegion
.Intersect( m_paintClippingRegion
);
1725 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
1726 gdk_gc_set_clip_region( m_brushGC
, m_currentClippingRegion
.GetRegion() );
1727 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
1728 gdk_gc_set_clip_region( m_bgGC
, m_currentClippingRegion
.GetRegion() );
1731 void wxWindowDC::DestroyClippingRegion()
1733 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1735 wxDC::DestroyClippingRegion();
1737 m_currentClippingRegion
.Clear();
1739 #if USE_PAINT_REGION
1740 if (!m_paintClippingRegion
.IsEmpty())
1741 m_currentClippingRegion
.Union( m_paintClippingRegion
);
1744 if (!m_window
) return;
1746 if (m_currentClippingRegion
.IsEmpty())
1748 gdk_gc_set_clip_rectangle( m_penGC
, (GdkRectangle
*) NULL
);
1749 gdk_gc_set_clip_rectangle( m_brushGC
, (GdkRectangle
*) NULL
);
1750 gdk_gc_set_clip_rectangle( m_textGC
, (GdkRectangle
*) NULL
);
1751 gdk_gc_set_clip_rectangle( m_bgGC
, (GdkRectangle
*) NULL
);
1755 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
1756 gdk_gc_set_clip_region( m_brushGC
, m_currentClippingRegion
.GetRegion() );
1757 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
1758 gdk_gc_set_clip_region( m_bgGC
, m_currentClippingRegion
.GetRegion() );
1762 void wxWindowDC::Destroy()
1764 if (m_penGC
) wxFreePoolGC( m_penGC
);
1765 m_penGC
= (GdkGC
*) NULL
;
1766 if (m_brushGC
) wxFreePoolGC( m_brushGC
);
1767 m_brushGC
= (GdkGC
*) NULL
;
1768 if (m_textGC
) wxFreePoolGC( m_textGC
);
1769 m_textGC
= (GdkGC
*) NULL
;
1770 if (m_bgGC
) wxFreePoolGC( m_bgGC
);
1771 m_bgGC
= (GdkGC
*) NULL
;
1774 void wxWindowDC::ComputeScaleAndOrigin()
1776 /* CMB: copy scale to see if it changes */
1777 double origScaleX
= m_scaleX
;
1778 double origScaleY
= m_scaleY
;
1780 wxDC::ComputeScaleAndOrigin();
1782 /* CMB: if scale has changed call SetPen to recalulate the line width */
1783 if ((m_scaleX
!= origScaleX
|| m_scaleY
!= origScaleY
) &&
1786 /* this is a bit artificial, but we need to force wxDC to think
1787 the pen has changed */
1794 // Resolution in pixels per logical inch
1795 wxSize
wxWindowDC::GetPPI() const
1797 return wxSize(100, 100);
1800 int wxWindowDC::GetDepth() const
1802 wxFAIL_MSG(wxT("not implemented"));
1808 // ----------------------------------- spline code ----------------------------------------
1810 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
1811 double a3
, double b3
, double a4
, double b4
);
1812 void wx_clear_stack();
1813 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
1814 double *y3
, double *x4
, double *y4
);
1815 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
1816 double x4
, double y4
);
1817 static bool wx_spline_add_point(double x
, double y
);
1818 static void wx_spline_draw_point_array(wxDC
*dc
);
1820 wxList wx_spline_point_list
;
1822 #define half(z1, z2) ((z1+z2)/2.0)
1825 /* iterative version */
1827 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
1830 register double xmid
, ymid
;
1831 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1834 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
1836 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
1837 xmid
= (double)half(x2
, x3
);
1838 ymid
= (double)half(y2
, y3
);
1839 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
1840 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
1841 wx_spline_add_point( x1
, y1
);
1842 wx_spline_add_point( xmid
, ymid
);
1844 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
1845 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
1846 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
1847 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
1852 /* utilities used by spline drawing routines */
1854 typedef struct wx_spline_stack_struct
{
1855 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1858 #define SPLINE_STACK_DEPTH 20
1859 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
1860 static Stack
*wx_stack_top
;
1861 static int wx_stack_count
;
1863 void wx_clear_stack()
1865 wx_stack_top
= wx_spline_stack
;
1869 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
1871 wx_stack_top
->x1
= x1
;
1872 wx_stack_top
->y1
= y1
;
1873 wx_stack_top
->x2
= x2
;
1874 wx_stack_top
->y2
= y2
;
1875 wx_stack_top
->x3
= x3
;
1876 wx_stack_top
->y3
= y3
;
1877 wx_stack_top
->x4
= x4
;
1878 wx_stack_top
->y4
= y4
;
1883 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
1884 double *x3
, double *y3
, double *x4
, double *y4
)
1886 if (wx_stack_count
== 0)
1890 *x1
= wx_stack_top
->x1
;
1891 *y1
= wx_stack_top
->y1
;
1892 *x2
= wx_stack_top
->x2
;
1893 *y2
= wx_stack_top
->y2
;
1894 *x3
= wx_stack_top
->x3
;
1895 *y3
= wx_stack_top
->y3
;
1896 *x4
= wx_stack_top
->x4
;
1897 *y4
= wx_stack_top
->y4
;
1901 static bool wx_spline_add_point(double x
, double y
)
1903 wxPoint
*point
= new wxPoint
;
1906 wx_spline_point_list
.Append((wxObject
*)point
);
1910 static void wx_spline_draw_point_array(wxDC
*dc
)
1912 dc
->DrawLines(&wx_spline_point_list
, 0, 0 );
1913 wxNode
*node
= wx_spline_point_list
.First();
1916 wxPoint
*point
= (wxPoint
*)node
->Data();
1919 node
= wx_spline_point_list
.First();
1923 void wxWindowDC::DoDrawSpline( wxList
*points
)
1925 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1928 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
1929 double x1
, y1
, x2
, y2
;
1931 wxNode
*node
= points
->First();
1932 p
= (wxPoint
*)node
->Data();
1937 node
= node
->Next();
1938 p
= (wxPoint
*)node
->Data();
1942 cx1
= (double)((x1
+ x2
) / 2);
1943 cy1
= (double)((y1
+ y2
) / 2);
1944 cx2
= (double)((cx1
+ x2
) / 2);
1945 cy2
= (double)((cy1
+ y2
) / 2);
1947 wx_spline_add_point(x1
, y1
);
1949 while ((node
= node
->Next()) != NULL
)
1951 p
= (wxPoint
*)node
->Data();
1956 cx4
= (double)(x1
+ x2
) / 2;
1957 cy4
= (double)(y1
+ y2
) / 2;
1958 cx3
= (double)(x1
+ cx4
) / 2;
1959 cy3
= (double)(y1
+ cy4
) / 2;
1961 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
1965 cx2
= (double)(cx1
+ x2
) / 2;
1966 cy2
= (double)(cy1
+ y2
) / 2;
1969 wx_spline_add_point( cx1
, cy1
);
1970 wx_spline_add_point( x2
, y2
);
1972 wx_spline_draw_point_array( this );
1975 #endif // wxUSE_SPLINE
1977 //-----------------------------------------------------------------------------
1979 //-----------------------------------------------------------------------------
1981 IMPLEMENT_DYNAMIC_CLASS(wxPaintDC
,wxWindowDC
)
1983 wxPaintDC::wxPaintDC()
1988 wxPaintDC::wxPaintDC( wxWindow
*win
)
1991 #if USE_PAINT_REGION
1992 m_paintClippingRegion
= win
->GetUpdateRegion();
1993 m_currentClippingRegion
.Union( m_paintClippingRegion
);
1995 gdk_gc_set_clip_region( m_penGC
, m_paintClippingRegion
.GetRegion() );
1996 gdk_gc_set_clip_region( m_brushGC
, m_paintClippingRegion
.GetRegion() );
1997 gdk_gc_set_clip_region( m_textGC
, m_paintClippingRegion
.GetRegion() );
1998 gdk_gc_set_clip_region( m_bgGC
, m_paintClippingRegion
.GetRegion() );
2002 //-----------------------------------------------------------------------------
2004 //-----------------------------------------------------------------------------
2006 IMPLEMENT_DYNAMIC_CLASS(wxClientDC
,wxWindowDC
)
2008 wxClientDC::wxClientDC()
2013 wxClientDC::wxClientDC( wxWindow
*win
)
2018 // ----------------------------------------------------------------------------
2020 // ----------------------------------------------------------------------------
2022 class wxDCModule
: public wxModule
2029 DECLARE_DYNAMIC_CLASS(wxDCModule
)
2032 IMPLEMENT_DYNAMIC_CLASS(wxDCModule
, wxModule
)
2034 bool wxDCModule::OnInit()
2040 void wxDCModule::OnExit()