1 /////////////////////////////////////////////////////////////////////////////
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/gtk/win_gtk.h"
19 #include <math.h> // for floating-point functions
23 //-----------------------------------------------------------------------------
25 //-----------------------------------------------------------------------------
35 static GdkPixmap
*hatches
[num_hatches
];
36 static GdkPixmap
**hatch_bitmap
= (GdkPixmap
**) NULL
;
38 extern GtkWidget
*wxRootWindow
;
40 //-----------------------------------------------------------------------------
42 //-----------------------------------------------------------------------------
44 const double RAD2DEG
= 180.0 / M_PI
;
46 // ----------------------------------------------------------------------------
48 // ----------------------------------------------------------------------------
50 static inline double dmax(double a
, double b
) { return a
> b
? a
: b
; }
51 static inline double dmin(double a
, double b
) { return a
< b
? a
: b
; }
53 static inline double DegToRad(double deg
) { return (deg
* M_PI
) / 180.0; }
55 //-----------------------------------------------------------------------------
56 // temporary implementation of the missing GDK function
57 //-----------------------------------------------------------------------------
59 #include "gdk/gdkprivate.h"
61 void gdk_draw_bitmap (GdkDrawable
*drawable
,
71 GdkWindowPrivate
*drawable_private
;
72 GdkWindowPrivate
*src_private
;
73 GdkGCPrivate
*gc_private
;
75 g_return_if_fail (drawable
!= NULL
);
76 g_return_if_fail (src
!= NULL
);
77 g_return_if_fail (gc
!= NULL
);
79 drawable_private
= (GdkWindowPrivate
*) drawable
;
80 src_private
= (GdkWindowPrivate
*) src
;
81 if (drawable_private
->destroyed
|| src_private
->destroyed
)
84 gc_private
= (GdkGCPrivate
*) gc
;
86 if (width
== -1) width
= src_private
->width
;
87 if (height
== -1) height
= src_private
->height
;
89 XCopyPlane( drawable_private
->xdisplay
,
91 drawable_private
->xwindow
,
99 //-----------------------------------------------------------------------------
100 // Implement Pool of Graphic contexts. Creating them takes too much time.
101 //-----------------------------------------------------------------------------
123 static wxGC wxGCPool
[200];
125 static void wxInitGCPool()
127 memset( wxGCPool
, 0, 200*sizeof(wxGC
) );
130 static void wxCleanUpGCPool()
132 for (int i
= 0; i
< 200; i
++)
134 if (wxGCPool
[i
].m_gc
)
135 gdk_gc_unref( wxGCPool
[i
].m_gc
);
139 static GdkGC
* wxGetPoolGC( GdkWindow
*window
, wxPoolGCType type
)
141 for (int i
= 0; i
< 200; i
++)
143 if (!wxGCPool
[i
].m_gc
)
145 wxGCPool
[i
].m_gc
= gdk_gc_new( window
);
146 gdk_gc_set_exposures( wxGCPool
[i
].m_gc
, FALSE
);
147 wxGCPool
[i
].m_type
= type
;
148 wxGCPool
[i
].m_used
= FALSE
;
150 if ((!wxGCPool
[i
].m_used
) && (wxGCPool
[i
].m_type
== type
))
152 wxGCPool
[i
].m_used
= TRUE
;
153 return wxGCPool
[i
].m_gc
;
157 wxFAIL_MSG( wxT("No GC available") );
159 return (GdkGC
*) NULL
;
162 static void wxFreePoolGC( GdkGC
*gc
)
164 for (int i
= 0; i
< 200; i
++)
166 if (wxGCPool
[i
].m_gc
== gc
)
168 wxGCPool
[i
].m_used
= FALSE
;
173 wxFAIL_MSG( wxT("Wrong GC") );
176 //-----------------------------------------------------------------------------
178 //-----------------------------------------------------------------------------
180 IMPLEMENT_DYNAMIC_CLASS(wxWindowDC
, wxDC
)
182 wxWindowDC::wxWindowDC()
184 m_penGC
= (GdkGC
*) NULL
;
185 m_brushGC
= (GdkGC
*) NULL
;
186 m_textGC
= (GdkGC
*) NULL
;
187 m_bgGC
= (GdkGC
*) NULL
;
188 m_cmap
= (GdkColormap
*) NULL
;
190 m_owner
= (wxWindow
*)NULL
;
193 wxWindowDC::wxWindowDC( wxWindow
*window
)
195 m_penGC
= (GdkGC
*) NULL
;
196 m_brushGC
= (GdkGC
*) NULL
;
197 m_textGC
= (GdkGC
*) NULL
;
198 m_bgGC
= (GdkGC
*) NULL
;
199 m_cmap
= (GdkColormap
*) NULL
;
200 m_owner
= (wxWindow
*)NULL
;
202 m_font
= window
->GetFont();
204 wxASSERT_MSG( window
, wxT("DC needs a window") );
206 GtkWidget
*widget
= window
->m_wxwindow
;
208 // some controls don't have m_wxwindow - like wxStaticBox, but the user
209 // code should still be able to create wxClientDCs for them, so we will
210 // use the parent window here then
213 window
= window
->GetParent();
214 widget
= window
->m_wxwindow
;
217 wxASSERT_MSG( widget
, wxT("DC needs a widget") );
219 GtkPizza
*pizza
= GTK_PIZZA( widget
);
220 m_window
= pizza
->bin_window
;
225 /* don't report problems */
231 m_cmap
= gtk_widget_get_colormap( widget
? widget
: window
->m_widget
);
235 /* this must be done after SetUpDC, bacause SetUpDC calls the
236 repective SetBrush, SetPen, SetBackground etc functions
237 to set up the DC. SetBackground call m_owner->SetBackground
238 and this might not be desired as the standard dc background
239 is white whereas a window might assume gray to be the
240 standard (as e.g. wxStatusBar) */
245 wxWindowDC::~wxWindowDC()
250 void wxWindowDC::DoFloodFill( wxCoord
WXUNUSED(x
), wxCoord
WXUNUSED(y
),
251 const wxColour
&WXUNUSED(col
), int WXUNUSED(style
) )
253 wxFAIL_MSG( wxT("wxWindowDC::DoFloodFill not implemented") );
256 bool wxWindowDC::DoGetPixel( wxCoord
WXUNUSED(x1
), wxCoord
WXUNUSED(y1
), wxColour
*WXUNUSED(col
) ) const
258 wxFAIL_MSG( wxT("wxWindowDC::DoGetPixel not implemented") );
262 void wxWindowDC::DoDrawLine( wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
264 wxCHECK_RET( Ok(), wxT("invalid window dc") );
266 if (m_pen
.GetStyle() != wxTRANSPARENT
)
269 gdk_draw_line( m_window
, m_penGC
, XLOG2DEV(x1
), YLOG2DEV(y1
), XLOG2DEV(x2
), YLOG2DEV(y2
) );
271 CalcBoundingBox(x1
, y1
);
272 CalcBoundingBox(x2
, y2
);
276 void wxWindowDC::DoCrossHair( wxCoord x
, wxCoord y
)
278 wxCHECK_RET( Ok(), wxT("invalid window dc") );
280 if (m_pen
.GetStyle() != wxTRANSPARENT
)
285 wxCoord xx
= XLOG2DEV(x
);
286 wxCoord yy
= YLOG2DEV(y
);
289 gdk_draw_line( m_window
, m_penGC
, 0, yy
, XLOG2DEVREL(w
), yy
);
290 gdk_draw_line( m_window
, m_penGC
, xx
, 0, xx
, YLOG2DEVREL(h
) );
295 void wxWindowDC::DoDrawArc( wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
,
296 wxCoord xc
, wxCoord yc
)
298 wxCHECK_RET( Ok(), wxT("invalid window dc") );
300 wxCoord xx1
= XLOG2DEV(x1
);
301 wxCoord yy1
= YLOG2DEV(y1
);
302 wxCoord xx2
= XLOG2DEV(x2
);
303 wxCoord yy2
= YLOG2DEV(y2
);
304 wxCoord xxc
= XLOG2DEV(xc
);
305 wxCoord yyc
= YLOG2DEV(yc
);
306 double dx
= xx1
- xxc
;
307 double dy
= yy1
- yyc
;
308 double radius
= sqrt((double)(dx
*dx
+dy
*dy
));
309 wxCoord r
= (wxCoord
)radius
;
310 double radius1
, radius2
;
312 if (xx1
== xx2
&& yy1
== yy2
)
320 radius1
= radius2
= 0.0;
324 radius1
= (xx1
- xxc
== 0) ?
325 (yy1
- yyc
< 0) ? 90.0 : -90.0 :
326 -atan2(double(yy1
-yyc
), double(xx1
-xxc
)) * RAD2DEG
;
327 radius2
= (xx2
- xxc
== 0) ?
328 (yy2
- yyc
< 0) ? 90.0 : -90.0 :
329 -atan2(double(yy2
-yyc
), double(xx2
-xxc
)) * RAD2DEG
;
331 wxCoord alpha1
= wxCoord(radius1
* 64.0);
332 wxCoord alpha2
= wxCoord((radius2
- radius1
) * 64.0);
333 while (alpha2
<= 0) alpha2
+= 360*64;
334 while (alpha1
> 360*64) alpha1
-= 360*64;
338 if (m_brush
.GetStyle() != wxTRANSPARENT
)
339 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xxc
-r
, yyc
-r
, 2*r
,2*r
, alpha1
, alpha2
);
341 if (m_pen
.GetStyle() != wxTRANSPARENT
)
342 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xxc
-r
, yyc
-r
, 2*r
,2*r
, alpha1
, alpha2
);
345 CalcBoundingBox (x1
, y1
);
346 CalcBoundingBox (x2
, y2
);
349 void wxWindowDC::DoDrawEllipticArc( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double sa
, double ea
)
351 wxCHECK_RET( Ok(), wxT("invalid window dc") );
353 wxCoord xx
= XLOG2DEV(x
);
354 wxCoord yy
= YLOG2DEV(y
);
355 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
356 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
358 // CMB: handle -ve width and/or height
359 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
360 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
364 wxCoord start
= wxCoord(sa
* 64.0);
365 wxCoord end
= wxCoord(ea
* 64.0);
367 if (m_brush
.GetStyle() != wxTRANSPARENT
)
368 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, start
, end
);
370 if (m_pen
.GetStyle() != wxTRANSPARENT
)
371 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
, hh
, start
, end
);
374 CalcBoundingBox (x
, y
);
375 CalcBoundingBox (x
+ width
, y
+ height
);
378 void wxWindowDC::DoDrawPoint( wxCoord x
, wxCoord y
)
380 wxCHECK_RET( Ok(), wxT("invalid window dc") );
382 if ((m_pen
.GetStyle() != wxTRANSPARENT
) && m_window
)
383 gdk_draw_point( m_window
, m_penGC
, XLOG2DEV(x
), YLOG2DEV(y
) );
385 CalcBoundingBox (x
, y
);
388 void wxWindowDC::DoDrawLines( int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
390 wxCHECK_RET( Ok(), wxT("invalid window dc") );
392 if (m_pen
.GetStyle() == wxTRANSPARENT
) return;
395 CalcBoundingBox( points
[0].x
+ xoffset
, points
[0].y
+ yoffset
);
397 for (int i
= 0; i
< n
-1; i
++)
399 wxCoord x1
= XLOG2DEV(points
[i
].x
+ xoffset
);
400 wxCoord x2
= XLOG2DEV(points
[i
+1].x
+ xoffset
);
401 wxCoord y1
= YLOG2DEV(points
[i
].y
+ yoffset
); // oh, what a waste
402 wxCoord y2
= YLOG2DEV(points
[i
+1].y
+ yoffset
);
405 gdk_draw_line( m_window
, m_penGC
, x1
, y1
, x2
, y2
);
407 CalcBoundingBox( points
[i
+1].x
+ xoffset
, points
[i
+1].y
+ yoffset
);
411 void wxWindowDC::DoDrawPolygon( int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
, int WXUNUSED(fillStyle
) )
413 wxCHECK_RET( Ok(), wxT("invalid window dc") );
417 GdkPoint
*gdkpoints
= new GdkPoint
[n
+1];
419 for (i
= 0 ; i
< n
; i
++)
421 gdkpoints
[i
].x
= XLOG2DEV(points
[i
].x
+ xoffset
);
422 gdkpoints
[i
].y
= YLOG2DEV(points
[i
].y
+ yoffset
);
424 CalcBoundingBox( points
[i
].x
+ xoffset
, points
[i
].y
+ yoffset
);
429 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
430 gdk_draw_polygon (m_window
, m_textGC
, TRUE
, gdkpoints
, n
);
433 if ((m_brush
.GetStyle() != wxTRANSPARENT
))
434 gdk_draw_polygon (m_window
, m_brushGC
, TRUE
, gdkpoints
, n
);
440 if ((m_pen
.GetStyle() != wxTRANSPARENT
) && m_window
)
442 for (i
= 0 ; i
< n
; i
++)
444 gdk_draw_line( m_window
, m_penGC
,
447 gdkpoints
[(i
+1)%n
].x
,
448 gdkpoints
[(i
+1)%n
].y
);
455 void wxWindowDC::DoDrawRectangle( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
457 wxCHECK_RET( Ok(), wxT("invalid window dc") );
459 wxCoord xx
= XLOG2DEV(x
);
460 wxCoord yy
= YLOG2DEV(y
);
461 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
462 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
464 // CMB: draw nothing if transformed w or h is 0
465 if (ww
== 0 || hh
== 0) return;
467 // CMB: handle -ve width and/or height
468 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
469 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
473 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
475 gdk_draw_rectangle( m_window
, m_textGC
, TRUE
, xx
, yy
, ww
, hh
);
476 gdk_draw_rectangle( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
-1, hh
-1 );
480 if (m_brush
.GetStyle() != wxTRANSPARENT
)
481 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
);
483 if (m_pen
.GetStyle() != wxTRANSPARENT
)
484 gdk_draw_rectangle( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
-1, hh
-1 );
488 CalcBoundingBox( x
, y
);
489 CalcBoundingBox( x
+ width
, y
+ height
);
492 void wxWindowDC::DoDrawRoundedRectangle( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
494 wxCHECK_RET( Ok(), wxT("invalid window dc") );
496 if (radius
< 0.0) radius
= - radius
* ((width
< height
) ? width
: height
);
498 wxCoord xx
= XLOG2DEV(x
);
499 wxCoord yy
= YLOG2DEV(y
);
500 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
501 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
502 wxCoord rr
= XLOG2DEVREL((wxCoord
)radius
);
504 // CMB: handle -ve width and/or height
505 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
506 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
508 // CMB: if radius is zero use DrawRectangle() instead to avoid
509 // X drawing errors with small radii
512 DrawRectangle( x
, y
, width
, height
);
516 // CMB: draw nothing if transformed w or h is 0
517 if (ww
== 0 || hh
== 0) return;
519 // CMB: adjust size if outline is drawn otherwise the result is
520 // 1 pixel too wide and high
521 if (m_pen
.GetStyle() != wxTRANSPARENT
)
529 // CMB: ensure dd is not larger than rectangle otherwise we
530 // get an hour glass shape
532 if (dd
> ww
) dd
= ww
;
533 if (dd
> hh
) dd
= hh
;
536 if (m_brush
.GetStyle() != wxTRANSPARENT
)
538 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
+rr
, yy
, ww
-dd
+1, hh
);
539 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
+rr
, ww
, hh
-dd
+1 );
540 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, dd
, dd
, 90*64, 90*64 );
541 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 );
542 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 );
543 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 );
546 if (m_pen
.GetStyle() != wxTRANSPARENT
)
548 gdk_draw_line( m_window
, m_penGC
, xx
+rr
, yy
, xx
+ww
-rr
, yy
);
549 gdk_draw_line( m_window
, m_penGC
, xx
+rr
, yy
+hh
, xx
+ww
-rr
, yy
+hh
);
550 gdk_draw_line( m_window
, m_penGC
, xx
, yy
+rr
, xx
, yy
+hh
-rr
);
551 gdk_draw_line( m_window
, m_penGC
, xx
+ww
, yy
+rr
, xx
+ww
, yy
+hh
-rr
);
552 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
, dd
, dd
, 90*64, 90*64 );
553 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 );
554 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 );
555 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 );
559 // this ignores the radius
560 CalcBoundingBox( x
, y
);
561 CalcBoundingBox( x
+ width
, y
+ height
);
564 void wxWindowDC::DoDrawEllipse( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
566 wxCHECK_RET( Ok(), wxT("invalid window dc") );
568 wxCoord xx
= XLOG2DEV(x
);
569 wxCoord yy
= YLOG2DEV(y
);
570 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
571 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
573 // CMB: handle -ve width and/or height
574 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
575 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
579 if (m_brush
.GetStyle() != wxTRANSPARENT
)
580 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, 0, 360*64 );
582 if (m_pen
.GetStyle() != wxTRANSPARENT
)
583 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
, hh
, 0, 360*64 );
586 CalcBoundingBox( x
- width
, y
- height
);
587 CalcBoundingBox( x
+ width
, y
+ height
);
590 void wxWindowDC::DoDrawIcon( const wxIcon
&icon
, wxCoord x
, wxCoord y
)
592 // VZ: egcs 1.0.3 refuses to compile this without cast, no idea why
593 DoDrawBitmap( (const wxBitmap
&)icon
, x
, y
, (bool)TRUE
);
596 void wxWindowDC::DoDrawBitmap( const wxBitmap
&bitmap
,
597 wxCoord x
, wxCoord y
,
600 wxCHECK_RET( Ok(), wxT("invalid window dc") );
602 wxCHECK_RET( bitmap
.Ok(), wxT("invalid bitmap") );
604 bool is_mono
= (bitmap
.GetBitmap() != NULL
);
606 /* scale/translate size and position */
607 int xx
= XLOG2DEV(x
);
608 int yy
= YLOG2DEV(y
);
610 int w
= bitmap
.GetWidth();
611 int h
= bitmap
.GetHeight();
613 CalcBoundingBox( x
, y
);
614 CalcBoundingBox( x
+ w
, y
+ h
);
616 if (!m_window
) return;
618 int ww
= XLOG2DEVREL(w
);
619 int hh
= YLOG2DEVREL(h
);
621 /* compare to current clipping region */
622 if (!m_currentClippingRegion
.IsEmpty())
624 wxRegion
tmp( xx
,yy
,ww
,hh
);
625 tmp
.Intersect( m_currentClippingRegion
);
630 /* scale bitmap if required */
632 if ((w
!= ww
) || (h
!= hh
))
634 wxImage
image( bitmap
);
635 image
.Rescale( ww
, hh
);
637 use_bitmap
= image
.ConvertToMonoBitmap(255,255,255);
639 use_bitmap
= image
.ConvertToBitmap();
646 /* apply mask if any */
647 GdkBitmap
*mask
= (GdkBitmap
*) NULL
;
648 if (use_bitmap
.GetMask()) mask
= use_bitmap
.GetMask()->GetBitmap();
652 GdkBitmap
*new_mask
= (GdkBitmap
*) NULL
;
653 if (!m_currentClippingRegion
.IsEmpty())
656 new_mask
= gdk_pixmap_new( wxRootWindow
->window
, ww
, hh
, 1 );
657 GdkGC
*gc
= gdk_gc_new( new_mask
);
659 gdk_gc_set_foreground( gc
, &col
);
660 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, ww
, hh
);
662 gdk_gc_set_background( gc
, &col
);
664 gdk_gc_set_foreground( gc
, &col
);
665 gdk_gc_set_clip_region( gc
, m_currentClippingRegion
.GetRegion() );
666 gdk_gc_set_clip_origin( gc
, -xx
, -yy
);
667 gdk_gc_set_fill( gc
, GDK_OPAQUE_STIPPLED
);
668 gdk_gc_set_stipple( gc
, mask
);
669 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, ww
, hh
);
671 gdk_gc_set_clip_mask( m_brushGC, NULL );
672 gdk_gc_set_clip_mask( m_textGC, NULL );
673 SetBrush( *wxRED_BRUSH );
674 DrawRectangle( 70, 0, 70, 1000 );
675 gdk_draw_bitmap( m_window, m_textGC, new_mask, 0, 0, 100, 5, ww, hh );
676 gdk_draw_bitmap( m_window, m_textGC, mask, 0, 0, 80, 5, ww, hh );
684 gdk_gc_set_clip_mask( m_textGC
, new_mask
);
686 gdk_gc_set_clip_mask( m_textGC
, mask
);
687 gdk_gc_set_clip_origin( m_textGC
, xx
, yy
);
692 gdk_gc_set_clip_mask( m_penGC
, new_mask
);
694 gdk_gc_set_clip_mask( m_penGC
, mask
);
695 gdk_gc_set_clip_origin( m_penGC
, xx
, yy
);
698 gdk_bitmap_unref( new_mask
);
701 /* Draw XPixmap or XBitmap, depending on what the wxBitmap contains. For
702 drawing a mono-bitmap (XBitmap) we use the current text GC */
704 gdk_draw_bitmap( m_window
, m_textGC
, use_bitmap
.GetBitmap(), 0, 0, xx
, yy
, -1, -1 );
706 gdk_draw_pixmap( m_window
, m_penGC
, use_bitmap
.GetPixmap(), 0, 0, xx
, yy
, -1, -1 );
708 /* remove mask again if any */
713 gdk_gc_set_clip_mask( m_textGC
, (GdkBitmap
*) NULL
);
714 gdk_gc_set_clip_origin( m_textGC
, 0, 0 );
715 if (!m_currentClippingRegion
.IsEmpty())
716 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
720 gdk_gc_set_clip_mask( m_penGC
, (GdkBitmap
*) NULL
);
721 gdk_gc_set_clip_origin( m_penGC
, 0, 0 );
722 if (!m_currentClippingRegion
.IsEmpty())
723 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
728 bool wxWindowDC::DoBlit( wxCoord xdest
, wxCoord ydest
, wxCoord width
, wxCoord height
,
729 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
,
730 int logical_func
, bool useMask
)
732 /* this is the nth try to get this utterly useless function to
733 work. it now completely ignores the scaling or translation
734 of the source dc, but scales correctly on the target dc and
735 knows about possible mask information in a memory dc. */
737 wxCHECK_MSG( Ok(), FALSE
, wxT("invalid window dc") );
739 wxCHECK_MSG( source
, FALSE
, wxT("invalid source dc") );
741 if (!m_window
) return FALSE
;
743 wxClientDC
*srcDC
= (wxClientDC
*)source
;
744 wxMemoryDC
*memDC
= (wxMemoryDC
*)source
;
746 bool use_bitmap_method
= FALSE
;
747 bool is_mono
= FALSE
;
749 if (srcDC
->m_isMemDC
)
751 if (!memDC
->m_selected
.Ok()) return FALSE
;
753 /* we use the "XCopyArea" way to copy a memory dc into
754 y different window if the memory dc BOTH
755 a) doesn't have any mask or its mask isn't used
759 if (useMask
&& (memDC
->m_selected
.GetMask()))
761 /* we HAVE TO use the direct way for memory dcs
762 that have mask since the XCopyArea doesn't know
764 use_bitmap_method
= TRUE
;
766 else if (memDC
->m_selected
.GetDepth() == 1)
768 /* we HAVE TO use the direct way for memory dcs
769 that are bitmaps because XCopyArea doesn't cope
770 with different bit depths */
772 use_bitmap_method
= TRUE
;
774 else if ((xsrc
== 0) && (ysrc
== 0) &&
775 (width
== memDC
->m_selected
.GetWidth()) &&
776 (height
== memDC
->m_selected
.GetHeight()))
778 /* we SHOULD use the direct way if all of the bitmap
779 in the memory dc is copied in which case XCopyArea
780 wouldn't be able able to boost performace by reducing
781 the area to be scaled */
782 use_bitmap_method
= TRUE
;
786 use_bitmap_method
= FALSE
;
790 CalcBoundingBox( xdest
, ydest
);
791 CalcBoundingBox( xdest
+ width
, ydest
+ height
);
793 /* scale/translate size and position */
794 wxCoord xx
= XLOG2DEV(xdest
);
795 wxCoord yy
= YLOG2DEV(ydest
);
797 wxCoord ww
= XLOG2DEVREL(width
);
798 wxCoord hh
= YLOG2DEVREL(height
);
800 /* compare to current clipping region */
801 if (!m_currentClippingRegion
.IsEmpty())
803 wxRegion
tmp( xx
,yy
,ww
,hh
);
804 tmp
.Intersect( m_currentClippingRegion
);
809 int old_logical_func
= m_logicalFunction
;
810 SetLogicalFunction( logical_func
);
812 if (use_bitmap_method
)
814 /* scale/translate bitmap size */
815 wxCoord bm_width
= memDC
->m_selected
.GetWidth();
816 wxCoord bm_height
= memDC
->m_selected
.GetHeight();
818 wxCoord bm_ww
= XLOG2DEVREL( bm_width
);
819 wxCoord bm_hh
= YLOG2DEVREL( bm_height
);
821 /* scale bitmap if required */
824 if ((bm_width
!= bm_ww
) || (bm_height
!= bm_hh
))
826 wxImage
image( memDC
->m_selected
);
827 image
= image
.Scale( bm_ww
, bm_hh
);
830 use_bitmap
= image
.ConvertToMonoBitmap(255,255,255);
832 use_bitmap
= image
.ConvertToBitmap();
836 use_bitmap
= memDC
->m_selected
;
839 /* apply mask if any */
840 GdkBitmap
*mask
= (GdkBitmap
*) NULL
;
841 if (use_bitmap
.GetMask()) mask
= use_bitmap
.GetMask()->GetBitmap();
845 GdkBitmap
*new_mask
= (GdkBitmap
*) NULL
;
846 if (!m_currentClippingRegion
.IsEmpty())
849 new_mask
= gdk_pixmap_new( wxRootWindow
->window
, bm_ww
, bm_hh
, 1 );
850 GdkGC
*gc
= gdk_gc_new( new_mask
);
852 gdk_gc_set_foreground( gc
, &col
);
853 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, bm_ww
, bm_hh
);
855 gdk_gc_set_background( gc
, &col
);
857 gdk_gc_set_foreground( gc
, &col
);
858 gdk_gc_set_clip_region( gc
, m_currentClippingRegion
.GetRegion() );
859 gdk_gc_set_clip_origin( gc
, -xx
, -yy
);
860 gdk_gc_set_fill( gc
, GDK_OPAQUE_STIPPLED
);
861 gdk_gc_set_stipple( gc
, mask
);
862 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, bm_ww
, bm_hh
);
869 gdk_gc_set_clip_mask( m_textGC
, new_mask
);
871 gdk_gc_set_clip_mask( m_textGC
, mask
);
872 gdk_gc_set_clip_origin( m_textGC
, xx
, yy
);
877 gdk_gc_set_clip_mask( m_penGC
, new_mask
);
879 gdk_gc_set_clip_mask( m_penGC
, mask
);
880 gdk_gc_set_clip_origin( m_penGC
, xx
, yy
);
883 gdk_bitmap_unref( new_mask
);
886 /* Draw XPixmap or XBitmap, depending on what the wxBitmap contains. For
887 drawing a mono-bitmap (XBitmap) we use the current text GC */
889 gdk_draw_bitmap( m_window
, m_textGC
, use_bitmap
.GetBitmap(), xsrc
, ysrc
, xx
, yy
, ww
, hh
);
891 gdk_draw_pixmap( m_window
, m_penGC
, use_bitmap
.GetPixmap(), xsrc
, ysrc
, xx
, yy
, ww
, hh
);
893 /* remove mask again if any */
898 gdk_gc_set_clip_mask( m_textGC
, (GdkBitmap
*) NULL
);
899 gdk_gc_set_clip_origin( m_textGC
, 0, 0 );
900 if (!m_currentClippingRegion
.IsEmpty())
901 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
905 gdk_gc_set_clip_mask( m_penGC
, (GdkBitmap
*) NULL
);
906 gdk_gc_set_clip_origin( m_penGC
, 0, 0 );
907 if (!m_currentClippingRegion
.IsEmpty())
908 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
912 else /* use_bitmap_method */
914 if ((width
!= ww
) || (height
!= hh
))
916 /* draw source window into a bitmap as we cannot scale
917 a window in contrast to a bitmap. this would actually
918 work with memory dcs as well, but we'd lose the mask
919 information and waste one step in this process since
920 a memory already has a bitmap. all this is slightly
921 inefficient as we could take an XImage directly from
922 an X window, but we'd then also have to care that
923 the window is not outside the screen (in which case
924 we'd get a BadMatch or what not).
925 Is a double XGetImage and combined XGetPixel and
926 XPutPixel really faster? I'm not sure. look at wxXt
927 for a different implementation of the same problem. */
929 wxBitmap
bitmap( width
, height
);
930 gdk_window_copy_area( bitmap
.GetPixmap(), m_penGC
, 0, 0,
932 xsrc
, ysrc
, width
, height
);
936 wxImage
image( bitmap
);
937 image
= image
.Scale( ww
, hh
);
939 /* convert to bitmap */
941 bitmap
= image
.ConvertToBitmap();
943 /* draw scaled bitmap */
945 gdk_draw_pixmap( m_window
, m_penGC
, bitmap
.GetPixmap(), 0, 0, xx
, yy
, -1, -1 );
950 /* no scaling and not a memory dc with a mask either */
952 gdk_window_copy_area( m_window
, m_penGC
, xx
, yy
,
954 xsrc
, ysrc
, width
, height
);
958 SetLogicalFunction( old_logical_func
);
962 void wxWindowDC::DoDrawText( const wxString
&text
, wxCoord x
, wxCoord y
)
964 wxCHECK_RET( Ok(), wxT("invalid window dc") );
966 if (!m_window
) return;
968 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
970 wxCHECK_RET( font
, wxT("invalid font") );
975 /* CMB 21/5/98: draw text background if mode is wxSOLID */
976 if (m_backgroundMode
== wxSOLID
)
978 wxCoord width
= gdk_string_width( font
, text
.mbc_str() );
979 wxCoord height
= font
->ascent
+ font
->descent
;
980 gdk_gc_set_foreground( m_textGC
, m_textBackgroundColour
.GetColor() );
981 gdk_draw_rectangle( m_window
, m_textGC
, TRUE
, x
, y
, width
, height
);
982 gdk_gc_set_foreground( m_textGC
, m_textForegroundColour
.GetColor() );
984 gdk_draw_string( m_window
, font
, m_textGC
, x
, y
+ font
->ascent
, text
.mbc_str() );
986 /* CMB 17/7/98: simple underline: ignores scaling and underlying
987 X font's XA_UNDERLINE_POSITION and XA_UNDERLINE_THICKNESS
988 properties (see wxXt implementation) */
989 if (m_font
.GetUnderlined())
991 wxCoord width
= gdk_string_width( font
, text
.mbc_str() );
992 wxCoord ul_y
= y
+ font
->ascent
;
993 if (font
->descent
> 0) ul_y
++;
994 gdk_draw_line( m_window
, m_textGC
, x
, ul_y
, x
+ width
, ul_y
);
998 GetTextExtent (text
, &w
, &h
);
999 CalcBoundingBox (x
+ w
, y
+ h
);
1000 CalcBoundingBox (x
, y
);
1003 void wxWindowDC::DoDrawRotatedText( const wxString
&text
, wxCoord x
, wxCoord y
, double angle
)
1007 DrawText(text
, x
, y
);
1011 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1013 if (!m_window
) return;
1015 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
1017 wxCHECK_RET( font
, wxT("invalid font") );
1019 // the size of the text
1020 wxCoord w
= gdk_string_width( font
, text
.mbc_str() );
1021 wxCoord h
= font
->ascent
+ font
->descent
;
1023 // draw the string normally
1026 dc
.SelectObject(src
);
1027 dc
.SetFont(GetFont());
1028 dc
.SetBackground(*wxWHITE_BRUSH
);
1029 dc
.SetBrush(*wxBLACK_BRUSH
);
1031 dc
.DrawText(text
, 0, 0);
1032 dc
.SetFont(wxNullFont
);
1033 dc
.SelectObject(wxNullBitmap
);
1035 // Calculate the size of the rotated bounding box.
1036 double rad
= DegToRad(angle
);
1037 double dx
= cos(rad
),
1040 // the rectngle vertices are counted clockwise with the first one being at
1041 // (0, 0) (or, rather, at (x, y))
1043 y2
= -w
*dy
; // y axis points to the bottom, hence minus
1046 double x3
= x4
+ x2
,
1050 wxCoord maxX
= (wxCoord
)(dmax(x2
, dmax(x3
, x4
)) + 0.5),
1051 maxY
= (wxCoord
)(dmax(y2
, dmax(y3
, y4
)) + 0.5),
1052 minX
= (wxCoord
)(dmin(x2
, dmin(x3
, x4
)) - 0.5),
1053 minY
= (wxCoord
)(dmin(y2
, dmin(y3
, y4
)) - 0.5);
1055 // prepare to blit-with-rotate the bitmap to the DC
1058 GdkColor
*colText
= m_textForegroundColour
.GetColor(),
1059 *colBack
= m_textBackgroundColour
.GetColor();
1061 bool textColSet
= TRUE
;
1063 unsigned char *data
= image
.GetData();
1065 // paint pixel by pixel
1066 for ( wxCoord srcX
= 0; srcX
< w
; srcX
++ )
1068 for ( wxCoord srcY
= 0; srcY
< h
; srcY
++ )
1070 // transform source coords to dest coords
1071 double r
= sqrt(srcX
*srcX
+ srcY
*srcY
);
1072 double angleOrig
= atan2(srcY
, srcX
) - rad
;
1073 wxCoord dstX
= (wxCoord
)(r
*cos(angleOrig
) + 0.5),
1074 dstY
= (wxCoord
)(r
*sin(angleOrig
) + 0.5);
1077 bool textPixel
= data
[(srcY
*w
+ srcX
)*3] == 0;
1078 if ( textPixel
|| (m_backgroundMode
== wxSOLID
) )
1080 // change colour if needed
1081 if ( textPixel
!= textColSet
)
1083 gdk_gc_set_foreground( m_textGC
, textPixel
? colText
1086 textColSet
= textPixel
;
1089 // don't use DrawPoint() because it uses the current pen
1090 // colour, and we don't need it here
1091 gdk_draw_point( m_window
, m_textGC
,
1092 XLOG2DEV(x
+ dstX
), YLOG2DEV(y
+ dstY
) );
1097 // it would be better to draw with non underlined font and draw the line
1098 // manually here (it would be more straight...)
1100 if ( m_font
.GetUnderlined() )
1102 gdk_draw_line( m_window
, m_textGC
,
1103 XLOG2DEV(x
+ x4
), YLOG2DEV(y
+ y4
+ font
->descent
),
1104 XLOG2DEV(x
+ x3
), YLOG2DEV(y
+ y3
+ font
->descent
));
1108 // restore the font colour
1109 gdk_gc_set_foreground( m_textGC
, colText
);
1111 // update the bounding box
1112 CalcBoundingBox(x
+ minX
, y
+ minY
);
1113 CalcBoundingBox(x
+ maxX
, y
+ maxY
);
1116 void wxWindowDC::DoGetTextExtent(const wxString
&string
,
1117 wxCoord
*width
, wxCoord
*height
,
1118 wxCoord
*descent
, wxCoord
*externalLeading
,
1119 wxFont
*theFont
) const
1121 wxFont fontToUse
= m_font
;
1122 if (theFont
) fontToUse
= *theFont
;
1124 GdkFont
*font
= fontToUse
.GetInternalFont( m_scaleY
);
1125 if (width
) (*width
) = wxCoord(gdk_string_width( font
, string
.mbc_str() ) / m_scaleX
);
1126 if (height
) (*height
) = wxCoord((font
->ascent
+ font
->descent
) / m_scaleY
);
1127 if (descent
) (*descent
) = wxCoord(font
->descent
/ m_scaleY
);
1128 if (externalLeading
) (*externalLeading
) = 0; // ??
1131 wxCoord
wxWindowDC::GetCharWidth() const
1133 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
1134 wxCHECK_MSG( font
, -1, wxT("invalid font") );
1136 return wxCoord(gdk_string_width( font
, "H" ) / m_scaleX
);
1139 wxCoord
wxWindowDC::GetCharHeight() const
1141 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
1142 wxCHECK_MSG( font
, -1, wxT("invalid font") );
1144 return wxCoord((font
->ascent
+ font
->descent
) / m_scaleY
);
1147 void wxWindowDC::Clear()
1149 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1151 if (!m_window
) return;
1153 /* - we either are a memory dc or have a window as the
1154 owner. anything else shouldn't happen.
1155 - we don't use gdk_window_clear() as we don't set
1156 the window's background colour anymore. it is too
1157 much pain to keep the DC's and the window's back-
1158 ground colour in synch. */
1163 m_owner
->GetSize( &width
, &height
);
1164 gdk_draw_rectangle( m_window
, m_bgGC
, TRUE
, 0, 0, width
, height
);
1171 GetSize( &width
, &height
);
1172 gdk_draw_rectangle( m_window
, m_bgGC
, TRUE
, 0, 0, width
, height
);
1177 void wxWindowDC::SetFont( const wxFont
&font
)
1182 void wxWindowDC::SetPen( const wxPen
&pen
)
1184 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1186 if (m_pen
== pen
) return;
1190 if (!m_pen
.Ok()) return;
1192 if (!m_window
) return;
1194 gint width
= m_pen
.GetWidth();
1197 // CMB: if width is non-zero scale it with the dc
1202 // X doesn't allow different width in x and y and so we take
1205 ( fabs((double) XLOG2DEVREL(width
)) +
1206 fabs((double) YLOG2DEVREL(width
)) ) / 2.0;
1210 static const char dotted
[] = {1, 1};
1211 static const char short_dashed
[] = {2, 2};
1212 static const char wxCoord_dashed
[] = {2, 4};
1213 static const char dotted_dashed
[] = {3, 3, 1, 3};
1215 // We express dash pattern in pen width unit, so we are
1216 // independent of zoom factor and so on...
1218 const char *req_dash
;
1220 GdkLineStyle lineStyle
= GDK_LINE_SOLID
;
1221 switch (m_pen
.GetStyle())
1225 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1226 req_nb_dash
= m_pen
.GetDashCount();
1227 req_dash
= m_pen
.GetDash();
1232 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1239 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1241 req_dash
= wxCoord_dashed
;
1246 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1248 req_dash
= short_dashed
;
1253 // lineStyle = GDK_LINE_DOUBLE_DASH;
1254 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1256 req_dash
= dotted_dashed
;
1261 case wxSTIPPLE_MASK_OPAQUE
:
1266 lineStyle
= GDK_LINE_SOLID
;
1267 req_dash
= (wxDash
*)NULL
;
1273 #if (GTK_MINOR_VERSION > 0)
1274 if (req_dash
&& req_nb_dash
)
1276 char *real_req_dash
= new char[req_nb_dash
];
1279 for (int i
= 0; i
< req_nb_dash
; i
++)
1280 real_req_dash
[i
] = req_dash
[i
] * width
;
1281 gdk_gc_set_dashes( m_penGC
, 0, real_req_dash
, req_nb_dash
);
1282 delete[] real_req_dash
;
1286 // No Memory. We use non-scaled dash pattern...
1287 gdk_gc_set_dashes( m_penGC
, 0, (char*)req_dash
, req_nb_dash
);
1292 GdkCapStyle capStyle
= GDK_CAP_ROUND
;
1293 switch (m_pen
.GetCap())
1295 case wxCAP_PROJECTING
: { capStyle
= GDK_CAP_PROJECTING
; break; }
1296 case wxCAP_BUTT
: { capStyle
= GDK_CAP_BUTT
; break; }
1303 capStyle
= GDK_CAP_NOT_LAST
;
1307 capStyle
= GDK_CAP_ROUND
;
1313 GdkJoinStyle joinStyle
= GDK_JOIN_ROUND
;
1314 switch (m_pen
.GetJoin())
1316 case wxJOIN_BEVEL
: { joinStyle
= GDK_JOIN_BEVEL
; break; }
1317 case wxJOIN_MITER
: { joinStyle
= GDK_JOIN_MITER
; break; }
1319 default: { joinStyle
= GDK_JOIN_ROUND
; break; }
1322 gdk_gc_set_line_attributes( m_penGC
, width
, lineStyle
, capStyle
, joinStyle
);
1324 m_pen
.GetColour().CalcPixel( m_cmap
);
1325 gdk_gc_set_foreground( m_penGC
, m_pen
.GetColour().GetColor() );
1328 void wxWindowDC::SetBrush( const wxBrush
&brush
)
1330 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1332 if (m_brush
== brush
) return;
1336 if (!m_brush
.Ok()) return;
1338 if (!m_window
) return;
1340 m_brush
.GetColour().CalcPixel( m_cmap
);
1341 gdk_gc_set_foreground( m_brushGC
, m_brush
.GetColour().GetColor() );
1343 gdk_gc_set_fill( m_brushGC
, GDK_SOLID
);
1345 if ((m_brush
.GetStyle() == wxSTIPPLE
) && (m_brush
.GetStipple()->Ok()))
1347 if (m_brush
.GetStipple()->GetPixmap())
1349 gdk_gc_set_fill( m_brushGC
, GDK_TILED
);
1350 gdk_gc_set_tile( m_brushGC
, m_brush
.GetStipple()->GetPixmap() );
1354 gdk_gc_set_fill( m_brushGC
, GDK_STIPPLED
);
1355 gdk_gc_set_stipple( m_brushGC
, m_brush
.GetStipple()->GetBitmap() );
1359 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
1361 gdk_gc_set_fill( m_textGC
, GDK_OPAQUE_STIPPLED
);
1362 gdk_gc_set_stipple( m_textGC
, m_brush
.GetStipple()->GetMask()->GetBitmap() );
1365 if (IS_HATCH(m_brush
.GetStyle()))
1367 gdk_gc_set_fill( m_brushGC
, GDK_STIPPLED
);
1368 int num
= m_brush
.GetStyle() - wxBDIAGONAL_HATCH
;
1369 gdk_gc_set_stipple( m_brushGC
, hatches
[num
] );
1373 void wxWindowDC::SetBackground( const wxBrush
&brush
)
1375 /* CMB 21/7/98: Added SetBackground. Sets background brush
1376 * for Clear() and bg colour for shapes filled with cross-hatch brush */
1378 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1380 if (m_backgroundBrush
== brush
) return;
1382 m_backgroundBrush
= brush
;
1384 if (!m_backgroundBrush
.Ok()) return;
1386 if (!m_window
) return;
1388 m_backgroundBrush
.GetColour().CalcPixel( m_cmap
);
1389 gdk_gc_set_background( m_brushGC
, m_backgroundBrush
.GetColour().GetColor() );
1390 gdk_gc_set_background( m_penGC
, m_backgroundBrush
.GetColour().GetColor() );
1391 gdk_gc_set_background( m_bgGC
, m_backgroundBrush
.GetColour().GetColor() );
1392 gdk_gc_set_foreground( m_bgGC
, m_backgroundBrush
.GetColour().GetColor() );
1394 gdk_gc_set_fill( m_bgGC
, GDK_SOLID
);
1396 if ((m_backgroundBrush
.GetStyle() == wxSTIPPLE
) && (m_backgroundBrush
.GetStipple()->Ok()))
1398 if (m_backgroundBrush
.GetStipple()->GetPixmap())
1400 gdk_gc_set_fill( m_bgGC
, GDK_TILED
);
1401 gdk_gc_set_tile( m_bgGC
, m_backgroundBrush
.GetStipple()->GetPixmap() );
1405 gdk_gc_set_fill( m_bgGC
, GDK_STIPPLED
);
1406 gdk_gc_set_stipple( m_bgGC
, m_backgroundBrush
.GetStipple()->GetBitmap() );
1410 if (IS_HATCH(m_backgroundBrush
.GetStyle()))
1412 gdk_gc_set_fill( m_bgGC
, GDK_STIPPLED
);
1413 int num
= m_backgroundBrush
.GetStyle() - wxBDIAGONAL_HATCH
;
1414 gdk_gc_set_stipple( m_bgGC
, hatches
[num
] );
1418 void wxWindowDC::SetLogicalFunction( int function
)
1420 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1422 if (m_logicalFunction
== function
)
1425 // VZ: shouldn't this be a CHECK?
1429 GdkFunction mode
= GDK_COPY
;
1432 case wxXOR
: mode
= GDK_XOR
; break;
1433 case wxINVERT
: mode
= GDK_INVERT
; break;
1434 #if (GTK_MINOR_VERSION > 0)
1435 case wxOR_REVERSE
: mode
= GDK_OR_REVERSE
; break;
1436 case wxAND_REVERSE
: mode
= GDK_AND_REVERSE
; break;
1437 case wxCLEAR
: mode
= GDK_CLEAR
; break;
1438 case wxSET
: mode
= GDK_SET
; break;
1439 case wxOR_INVERT
: mode
= GDK_OR_INVERT
; break;
1440 case wxAND
: mode
= GDK_AND
; break;
1441 case wxOR
: mode
= GDK_OR
; break;
1442 case wxEQUIV
: mode
= GDK_EQUIV
; break;
1443 case wxNAND
: mode
= GDK_NAND
; break;
1444 case wxAND_INVERT
: mode
= GDK_AND_INVERT
; break;
1445 case wxCOPY
: mode
= GDK_COPY
; break;
1446 case wxNO_OP
: mode
= GDK_NOOP
; break;
1447 case wxSRC_INVERT
: mode
= GDK_COPY_INVERT
; break;
1449 // unsupported by GTK
1450 case wxNOR
: mode
= GDK_COPY
; break;
1454 wxFAIL_MSG( wxT("unsupported logical function") );
1459 m_logicalFunction
= function
;
1461 gdk_gc_set_function( m_penGC
, mode
);
1462 gdk_gc_set_function( m_brushGC
, mode
);
1464 // to stay compatible with wxMSW, we don't apply ROPs to the text
1465 // operations (i.e. DrawText/DrawRotatedText).
1466 // True, but mono-bitmaps use the m_textGC and they use ROPs as well.
1467 gdk_gc_set_function( m_textGC
, mode
);
1470 void wxWindowDC::SetTextForeground( const wxColour
&col
)
1472 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1474 if (m_textForegroundColour
== col
) return;
1476 m_textForegroundColour
= col
;
1477 if (!m_textForegroundColour
.Ok()) return;
1479 if (!m_window
) return;
1481 m_textForegroundColour
.CalcPixel( m_cmap
);
1482 gdk_gc_set_foreground( m_textGC
, m_textForegroundColour
.GetColor() );
1485 void wxWindowDC::SetTextBackground( const wxColour
&col
)
1487 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1489 if (m_textBackgroundColour
== col
) return;
1491 m_textBackgroundColour
= col
;
1492 if (!m_textBackgroundColour
.Ok()) return;
1494 if (!m_window
) return;
1496 m_textBackgroundColour
.CalcPixel( m_cmap
);
1497 gdk_gc_set_background( m_textGC
, m_textBackgroundColour
.GetColor() );
1500 void wxWindowDC::SetBackgroundMode( int mode
)
1502 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1504 m_backgroundMode
= mode
;
1506 if (!m_window
) return;
1508 // CMB 21/7/98: fill style of cross-hatch brushes is affected by
1509 // transparent/solid background mode
1511 if (m_brush
.GetStyle() != wxSOLID
&& m_brush
.GetStyle() != wxTRANSPARENT
)
1513 gdk_gc_set_fill( m_brushGC
,
1514 (m_backgroundMode
== wxTRANSPARENT
) ? GDK_STIPPLED
: GDK_OPAQUE_STIPPLED
);
1518 void wxWindowDC::SetPalette( const wxPalette
& WXUNUSED(palette
) )
1520 wxFAIL_MSG( wxT("wxWindowDC::SetPalette not implemented") );
1523 void wxWindowDC::DoSetClippingRegion( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
1525 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1527 wxDC::DoSetClippingRegion( x
, y
, width
, height
);
1529 if (!m_window
) return;
1532 rect
.x
= XLOG2DEV(x
);
1533 rect
.y
= YLOG2DEV(y
);
1534 rect
.width
= XLOG2DEVREL(width
);
1535 rect
.height
= YLOG2DEVREL(height
);
1537 m_currentClippingRegion
.Clear();
1538 m_currentClippingRegion
.Union( rect
);
1539 if (!m_paintClippingRegion
.IsEmpty())
1540 m_currentClippingRegion
.Intersect( m_paintClippingRegion
);
1542 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
1543 gdk_gc_set_clip_region( m_brushGC
, m_currentClippingRegion
.GetRegion() );
1544 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
1545 gdk_gc_set_clip_region( m_bgGC
, m_currentClippingRegion
.GetRegion() );
1548 void wxWindowDC::DoSetClippingRegionAsRegion( const wxRegion
®ion
)
1550 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1554 DestroyClippingRegion();
1559 region
.GetBox( x
, y
, w
, h
);
1561 wxDC::DoSetClippingRegion( x
, y
, w
, h
);
1563 if (!m_window
) return;
1565 m_currentClippingRegion
.Clear();
1566 m_currentClippingRegion
.Union( region
);
1567 if (!m_paintClippingRegion
.IsEmpty())
1568 m_currentClippingRegion
.Intersect( m_paintClippingRegion
);
1570 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
1571 gdk_gc_set_clip_region( m_brushGC
, m_currentClippingRegion
.GetRegion() );
1572 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
1573 gdk_gc_set_clip_region( m_bgGC
, m_currentClippingRegion
.GetRegion() );
1576 void wxWindowDC::DestroyClippingRegion()
1578 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1580 wxDC::DestroyClippingRegion();
1582 m_currentClippingRegion
.Clear();
1584 if (!m_paintClippingRegion
.IsEmpty())
1585 m_currentClippingRegion
.Union( m_paintClippingRegion
);
1587 if (!m_window
) return;
1589 if (m_currentClippingRegion
.IsEmpty())
1591 gdk_gc_set_clip_rectangle( m_penGC
, (GdkRectangle
*) NULL
);
1592 gdk_gc_set_clip_rectangle( m_brushGC
, (GdkRectangle
*) NULL
);
1593 gdk_gc_set_clip_rectangle( m_textGC
, (GdkRectangle
*) NULL
);
1594 gdk_gc_set_clip_rectangle( m_bgGC
, (GdkRectangle
*) NULL
);
1598 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
1599 gdk_gc_set_clip_region( m_brushGC
, m_currentClippingRegion
.GetRegion() );
1600 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
1601 gdk_gc_set_clip_region( m_bgGC
, m_currentClippingRegion
.GetRegion() );
1605 void wxWindowDC::SetUpDC()
1611 m_penGC
= wxGetPoolGC( m_window
, wxPEN_COLOUR
);
1612 m_brushGC
= wxGetPoolGC( m_window
, wxBRUSH_COLOUR
);
1613 m_textGC
= wxGetPoolGC( m_window
, wxTEXT_COLOUR
);
1614 m_bgGC
= wxGetPoolGC( m_window
, wxBG_COLOUR
);
1617 /* background colour */
1618 m_backgroundBrush
= *wxWHITE_BRUSH
;
1619 m_backgroundBrush
.GetColour().CalcPixel( m_cmap
);
1620 GdkColor
*bg_col
= m_backgroundBrush
.GetColour().GetColor();
1623 m_textForegroundColour
.CalcPixel( m_cmap
);
1624 gdk_gc_set_foreground( m_textGC
, m_textForegroundColour
.GetColor() );
1626 m_textBackgroundColour
.CalcPixel( m_cmap
);
1627 gdk_gc_set_background( m_textGC
, m_textBackgroundColour
.GetColor() );
1629 gdk_gc_set_fill( m_textGC
, GDK_SOLID
);
1632 m_pen
.GetColour().CalcPixel( m_cmap
);
1633 gdk_gc_set_foreground( m_penGC
, m_pen
.GetColour().GetColor() );
1634 gdk_gc_set_background( m_penGC
, bg_col
);
1636 gdk_gc_set_line_attributes( m_penGC
, 0, GDK_LINE_SOLID
, GDK_CAP_NOT_LAST
, GDK_JOIN_ROUND
);
1640 m_brush
.GetColour().CalcPixel( m_cmap
);
1641 gdk_gc_set_foreground( m_brushGC
, m_brush
.GetColour().GetColor() );
1642 gdk_gc_set_background( m_brushGC
, bg_col
);
1644 gdk_gc_set_fill( m_brushGC
, GDK_SOLID
);
1648 gdk_gc_set_background( m_bgGC
, bg_col
);
1649 gdk_gc_set_foreground( m_bgGC
, bg_col
);
1651 gdk_gc_set_fill( m_bgGC
, GDK_SOLID
);
1654 gdk_gc_set_function( m_textGC
, GDK_COPY
);
1655 gdk_gc_set_function( m_brushGC
, GDK_COPY
);
1656 gdk_gc_set_function( m_penGC
, GDK_COPY
);
1659 gdk_gc_set_clip_rectangle( m_penGC
, (GdkRectangle
*) NULL
);
1660 gdk_gc_set_clip_rectangle( m_brushGC
, (GdkRectangle
*) NULL
);
1661 gdk_gc_set_clip_rectangle( m_textGC
, (GdkRectangle
*) NULL
);
1662 gdk_gc_set_clip_rectangle( m_bgGC
, (GdkRectangle
*) NULL
);
1666 hatch_bitmap
= hatches
;
1667 hatch_bitmap
[0] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, bdiag_bits
, bdiag_width
, bdiag_height
);
1668 hatch_bitmap
[1] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, cdiag_bits
, cdiag_width
, cdiag_height
);
1669 hatch_bitmap
[2] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, fdiag_bits
, fdiag_width
, fdiag_height
);
1670 hatch_bitmap
[3] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, cross_bits
, cross_width
, cross_height
);
1671 hatch_bitmap
[4] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, horiz_bits
, horiz_width
, horiz_height
);
1672 hatch_bitmap
[5] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, verti_bits
, verti_width
, verti_height
);
1676 void wxWindowDC::Destroy()
1678 if (m_penGC
) wxFreePoolGC( m_penGC
);
1679 m_penGC
= (GdkGC
*) NULL
;
1680 if (m_brushGC
) wxFreePoolGC( m_brushGC
);
1681 m_brushGC
= (GdkGC
*) NULL
;
1682 if (m_textGC
) wxFreePoolGC( m_textGC
);
1683 m_textGC
= (GdkGC
*) NULL
;
1684 if (m_bgGC
) wxFreePoolGC( m_bgGC
);
1685 m_bgGC
= (GdkGC
*) NULL
;
1688 void wxWindowDC::ComputeScaleAndOrigin()
1690 /* CMB: copy scale to see if it changes */
1691 double origScaleX
= m_scaleX
;
1692 double origScaleY
= m_scaleY
;
1694 wxDC::ComputeScaleAndOrigin();
1696 /* CMB: if scale has changed call SetPen to recalulate the line width */
1697 if ((m_scaleX
!= origScaleX
|| m_scaleY
!= origScaleY
) &&
1700 /* this is a bit artificial, but we need to force wxDC to think
1701 the pen has changed */
1708 // Resolution in pixels per logical inch
1709 wxSize
wxWindowDC::GetPPI() const
1711 return wxSize(100, 100);
1714 int wxWindowDC::GetDepth() const
1716 wxFAIL_MSG(wxT("not implemented"));
1722 // ----------------------------------- spline code ----------------------------------------
1724 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
1725 double a3
, double b3
, double a4
, double b4
);
1726 void wx_clear_stack();
1727 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
1728 double *y3
, double *x4
, double *y4
);
1729 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
1730 double x4
, double y4
);
1731 static bool wx_spline_add_point(double x
, double y
);
1732 static void wx_spline_draw_point_array(wxDC
*dc
);
1734 wxList wx_spline_point_list
;
1736 #define half(z1, z2) ((z1+z2)/2.0)
1739 /* iterative version */
1741 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
1744 register double xmid
, ymid
;
1745 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1748 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
1750 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
1751 xmid
= (double)half(x2
, x3
);
1752 ymid
= (double)half(y2
, y3
);
1753 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
1754 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
1755 wx_spline_add_point( x1
, y1
);
1756 wx_spline_add_point( xmid
, ymid
);
1758 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
1759 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
1760 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
1761 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
1766 /* utilities used by spline drawing routines */
1768 typedef struct wx_spline_stack_struct
{
1769 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1772 #define SPLINE_STACK_DEPTH 20
1773 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
1774 static Stack
*wx_stack_top
;
1775 static int wx_stack_count
;
1777 void wx_clear_stack()
1779 wx_stack_top
= wx_spline_stack
;
1783 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
1785 wx_stack_top
->x1
= x1
;
1786 wx_stack_top
->y1
= y1
;
1787 wx_stack_top
->x2
= x2
;
1788 wx_stack_top
->y2
= y2
;
1789 wx_stack_top
->x3
= x3
;
1790 wx_stack_top
->y3
= y3
;
1791 wx_stack_top
->x4
= x4
;
1792 wx_stack_top
->y4
= y4
;
1797 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
1798 double *x3
, double *y3
, double *x4
, double *y4
)
1800 if (wx_stack_count
== 0)
1804 *x1
= wx_stack_top
->x1
;
1805 *y1
= wx_stack_top
->y1
;
1806 *x2
= wx_stack_top
->x2
;
1807 *y2
= wx_stack_top
->y2
;
1808 *x3
= wx_stack_top
->x3
;
1809 *y3
= wx_stack_top
->y3
;
1810 *x4
= wx_stack_top
->x4
;
1811 *y4
= wx_stack_top
->y4
;
1815 static bool wx_spline_add_point(double x
, double y
)
1817 wxPoint
*point
= new wxPoint
;
1820 wx_spline_point_list
.Append((wxObject
*)point
);
1824 static void wx_spline_draw_point_array(wxDC
*dc
)
1826 dc
->DrawLines(&wx_spline_point_list
, 0, 0 );
1827 wxNode
*node
= wx_spline_point_list
.First();
1830 wxPoint
*point
= (wxPoint
*)node
->Data();
1833 node
= wx_spline_point_list
.First();
1837 void wxWindowDC::DoDrawSpline( wxList
*points
)
1839 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1842 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
1843 double x1
, y1
, x2
, y2
;
1845 wxNode
*node
= points
->First();
1846 p
= (wxPoint
*)node
->Data();
1851 node
= node
->Next();
1852 p
= (wxPoint
*)node
->Data();
1856 cx1
= (double)((x1
+ x2
) / 2);
1857 cy1
= (double)((y1
+ y2
) / 2);
1858 cx2
= (double)((cx1
+ x2
) / 2);
1859 cy2
= (double)((cy1
+ y2
) / 2);
1861 wx_spline_add_point(x1
, y1
);
1863 while ((node
= node
->Next()) != NULL
)
1865 p
= (wxPoint
*)node
->Data();
1870 cx4
= (double)(x1
+ x2
) / 2;
1871 cy4
= (double)(y1
+ y2
) / 2;
1872 cx3
= (double)(x1
+ cx4
) / 2;
1873 cy3
= (double)(y1
+ cy4
) / 2;
1875 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
1879 cx2
= (double)(cx1
+ x2
) / 2;
1880 cy2
= (double)(cy1
+ y2
) / 2;
1883 wx_spline_add_point( cx1
, cy1
);
1884 wx_spline_add_point( x2
, y2
);
1886 wx_spline_draw_point_array( this );
1889 #endif // wxUSE_SPLINE
1891 //-----------------------------------------------------------------------------
1893 //-----------------------------------------------------------------------------
1895 IMPLEMENT_DYNAMIC_CLASS(wxPaintDC
,wxWindowDC
)
1897 wxPaintDC::wxPaintDC()
1902 wxPaintDC::wxPaintDC( wxWindow
*win
)
1905 if (!win
->GetUpdateRegion().IsEmpty())
1907 m_paintClippingRegion
= win
->GetUpdateRegion();
1908 m_currentClippingRegion
.Union( m_paintClippingRegion
);
1910 gdk_gc_set_clip_region( m_penGC
, m_paintClippingRegion
.GetRegion() );
1911 gdk_gc_set_clip_region( m_brushGC
, m_paintClippingRegion
.GetRegion() );
1912 gdk_gc_set_clip_region( m_textGC
, m_paintClippingRegion
.GetRegion() );
1913 gdk_gc_set_clip_region( m_bgGC
, m_paintClippingRegion
.GetRegion() );
1917 //-----------------------------------------------------------------------------
1919 //-----------------------------------------------------------------------------
1921 IMPLEMENT_DYNAMIC_CLASS(wxClientDC
,wxWindowDC
)
1923 wxClientDC::wxClientDC()
1928 wxClientDC::wxClientDC( wxWindow
*win
)
1933 // ----------------------------------------------------------------------------
1935 // ----------------------------------------------------------------------------
1937 class wxDCModule
: public wxModule
1944 DECLARE_DYNAMIC_CLASS(wxDCModule
)
1947 IMPLEMENT_DYNAMIC_CLASS(wxDCModule
, wxModule
)
1949 bool wxDCModule::OnInit()
1955 void wxDCModule::OnExit()