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
26 //-----------------------------------------------------------------------------
28 //-----------------------------------------------------------------------------
38 static GdkPixmap
*hatches
[num_hatches
];
39 static GdkPixmap
**hatch_bitmap
= (GdkPixmap
**) NULL
;
41 extern GtkWidget
*wxRootWindow
;
43 //-----------------------------------------------------------------------------
45 //-----------------------------------------------------------------------------
47 const double RAD2DEG
= 180.0 / M_PI
;
49 // ----------------------------------------------------------------------------
51 // ----------------------------------------------------------------------------
53 static inline double dmax(double a
, double b
) { return a
> b
? a
: b
; }
54 static inline double dmin(double a
, double b
) { return a
< b
? a
: b
; }
56 static inline double DegToRad(double deg
) { return (deg
* M_PI
) / 180.0; }
58 //-----------------------------------------------------------------------------
59 // temporary implementation of the missing GDK function
60 //-----------------------------------------------------------------------------
62 #include "gdk/gdkprivate.h"
64 void gdk_draw_bitmap (GdkDrawable
*drawable
,
74 GdkWindowPrivate
*drawable_private
;
75 GdkWindowPrivate
*src_private
;
76 GdkGCPrivate
*gc_private
;
78 g_return_if_fail (drawable
!= NULL
);
79 g_return_if_fail (src
!= NULL
);
80 g_return_if_fail (gc
!= NULL
);
82 drawable_private
= (GdkWindowPrivate
*) drawable
;
83 src_private
= (GdkWindowPrivate
*) src
;
84 if (drawable_private
->destroyed
|| src_private
->destroyed
)
87 gc_private
= (GdkGCPrivate
*) gc
;
89 if (width
== -1) width
= src_private
->width
;
90 if (height
== -1) height
= src_private
->height
;
92 XCopyPlane( drawable_private
->xdisplay
,
94 drawable_private
->xwindow
,
102 //-----------------------------------------------------------------------------
103 // Implement Pool of Graphic contexts. Creating them takes too much time.
104 //-----------------------------------------------------------------------------
126 static wxGC wxGCPool
[200];
128 static void wxInitGCPool()
130 memset( wxGCPool
, 0, 200*sizeof(wxGC
) );
133 static void wxCleanUpGCPool()
135 for (int i
= 0; i
< 200; i
++)
137 if (wxGCPool
[i
].m_gc
)
138 gdk_gc_unref( wxGCPool
[i
].m_gc
);
142 static GdkGC
* wxGetPoolGC( GdkWindow
*window
, wxPoolGCType type
)
144 for (int i
= 0; i
< 200; i
++)
146 if (!wxGCPool
[i
].m_gc
)
148 wxGCPool
[i
].m_gc
= gdk_gc_new( window
);
149 gdk_gc_set_exposures( wxGCPool
[i
].m_gc
, FALSE
);
150 wxGCPool
[i
].m_type
= type
;
151 wxGCPool
[i
].m_used
= FALSE
;
153 if ((!wxGCPool
[i
].m_used
) && (wxGCPool
[i
].m_type
== type
))
155 wxGCPool
[i
].m_used
= TRUE
;
156 return wxGCPool
[i
].m_gc
;
160 wxFAIL_MSG( wxT("No GC available") );
162 return (GdkGC
*) NULL
;
165 static void wxFreePoolGC( GdkGC
*gc
)
167 for (int i
= 0; i
< 200; i
++)
169 if (wxGCPool
[i
].m_gc
== gc
)
171 wxGCPool
[i
].m_used
= FALSE
;
176 wxFAIL_MSG( wxT("Wrong GC") );
179 //-----------------------------------------------------------------------------
181 //-----------------------------------------------------------------------------
183 IMPLEMENT_DYNAMIC_CLASS(wxWindowDC
, wxDC
)
185 wxWindowDC::wxWindowDC()
187 m_penGC
= (GdkGC
*) NULL
;
188 m_brushGC
= (GdkGC
*) NULL
;
189 m_textGC
= (GdkGC
*) NULL
;
190 m_bgGC
= (GdkGC
*) NULL
;
191 m_cmap
= (GdkColormap
*) NULL
;
193 m_owner
= (wxWindow
*)NULL
;
196 wxWindowDC::wxWindowDC( wxWindow
*window
)
198 m_penGC
= (GdkGC
*) NULL
;
199 m_brushGC
= (GdkGC
*) NULL
;
200 m_textGC
= (GdkGC
*) NULL
;
201 m_bgGC
= (GdkGC
*) NULL
;
202 m_cmap
= (GdkColormap
*) NULL
;
203 m_owner
= (wxWindow
*)NULL
;
205 m_font
= window
->GetFont();
207 wxASSERT_MSG( window
, wxT("DC needs a window") );
209 GtkWidget
*widget
= window
->m_wxwindow
;
211 // some controls don't have m_wxwindow - like wxStaticBox, but the user
212 // code should still be able to create wxClientDCs for them, so we will
213 // use the parent window here then
216 window
= window
->GetParent();
217 widget
= window
->m_wxwindow
;
220 wxASSERT_MSG( widget
, wxT("DC needs a widget") );
222 GtkPizza
*pizza
= GTK_PIZZA( widget
);
223 m_window
= pizza
->bin_window
;
228 /* don't report problems */
234 m_cmap
= gtk_widget_get_colormap( widget
? widget
: window
->m_widget
);
238 /* this must be done after SetUpDC, bacause SetUpDC calls the
239 repective SetBrush, SetPen, SetBackground etc functions
240 to set up the DC. SetBackground call m_owner->SetBackground
241 and this might not be desired as the standard dc background
242 is white whereas a window might assume gray to be the
243 standard (as e.g. wxStatusBar) */
248 wxWindowDC::~wxWindowDC()
253 void wxWindowDC::DoFloodFill( wxCoord
WXUNUSED(x
), wxCoord
WXUNUSED(y
),
254 const wxColour
&WXUNUSED(col
), int WXUNUSED(style
) )
256 wxFAIL_MSG( wxT("wxWindowDC::DoFloodFill not implemented") );
259 bool wxWindowDC::DoGetPixel( wxCoord
WXUNUSED(x1
), wxCoord
WXUNUSED(y1
), wxColour
*WXUNUSED(col
) ) const
261 wxFAIL_MSG( wxT("wxWindowDC::DoGetPixel not implemented") );
265 void wxWindowDC::DoDrawLine( wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
267 wxCHECK_RET( Ok(), wxT("invalid window dc") );
269 if (m_pen
.GetStyle() != wxTRANSPARENT
)
272 gdk_draw_line( m_window
, m_penGC
, XLOG2DEV(x1
), YLOG2DEV(y1
), XLOG2DEV(x2
), YLOG2DEV(y2
) );
274 CalcBoundingBox(x1
, y1
);
275 CalcBoundingBox(x2
, y2
);
279 void wxWindowDC::DoCrossHair( wxCoord x
, wxCoord y
)
281 wxCHECK_RET( Ok(), wxT("invalid window dc") );
283 if (m_pen
.GetStyle() != wxTRANSPARENT
)
288 wxCoord xx
= XLOG2DEV(x
);
289 wxCoord yy
= YLOG2DEV(y
);
292 gdk_draw_line( m_window
, m_penGC
, 0, yy
, XLOG2DEVREL(w
), yy
);
293 gdk_draw_line( m_window
, m_penGC
, xx
, 0, xx
, YLOG2DEVREL(h
) );
298 void wxWindowDC::DoDrawArc( wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
,
299 wxCoord xc
, wxCoord yc
)
301 wxCHECK_RET( Ok(), wxT("invalid window dc") );
303 wxCoord xx1
= XLOG2DEV(x1
);
304 wxCoord yy1
= YLOG2DEV(y1
);
305 wxCoord xx2
= XLOG2DEV(x2
);
306 wxCoord yy2
= YLOG2DEV(y2
);
307 wxCoord xxc
= XLOG2DEV(xc
);
308 wxCoord yyc
= YLOG2DEV(yc
);
309 double dx
= xx1
- xxc
;
310 double dy
= yy1
- yyc
;
311 double radius
= sqrt((double)(dx
*dx
+dy
*dy
));
312 wxCoord r
= (wxCoord
)radius
;
313 double radius1
, radius2
;
315 if (xx1
== xx2
&& yy1
== yy2
)
323 radius1
= radius2
= 0.0;
327 radius1
= (xx1
- xxc
== 0) ?
328 (yy1
- yyc
< 0) ? 90.0 : -90.0 :
329 -atan2(double(yy1
-yyc
), double(xx1
-xxc
)) * RAD2DEG
;
330 radius2
= (xx2
- xxc
== 0) ?
331 (yy2
- yyc
< 0) ? 90.0 : -90.0 :
332 -atan2(double(yy2
-yyc
), double(xx2
-xxc
)) * RAD2DEG
;
334 wxCoord alpha1
= wxCoord(radius1
* 64.0);
335 wxCoord alpha2
= wxCoord((radius2
- radius1
) * 64.0);
336 while (alpha2
<= 0) alpha2
+= 360*64;
337 while (alpha1
> 360*64) alpha1
-= 360*64;
341 if (m_brush
.GetStyle() != wxTRANSPARENT
)
342 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xxc
-r
, yyc
-r
, 2*r
,2*r
, alpha1
, alpha2
);
344 if (m_pen
.GetStyle() != wxTRANSPARENT
)
345 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xxc
-r
, yyc
-r
, 2*r
,2*r
, alpha1
, alpha2
);
348 CalcBoundingBox (x1
, y1
);
349 CalcBoundingBox (x2
, y2
);
352 void wxWindowDC::DoDrawEllipticArc( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double sa
, double ea
)
354 wxCHECK_RET( Ok(), wxT("invalid window dc") );
356 wxCoord xx
= XLOG2DEV(x
);
357 wxCoord yy
= YLOG2DEV(y
);
358 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
359 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
361 // CMB: handle -ve width and/or height
362 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
363 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
367 wxCoord start
= wxCoord(sa
* 64.0);
368 wxCoord end
= wxCoord(ea
* 64.0);
370 if (m_brush
.GetStyle() != wxTRANSPARENT
)
371 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, start
, end
);
373 if (m_pen
.GetStyle() != wxTRANSPARENT
)
374 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
, hh
, start
, end
);
377 CalcBoundingBox (x
, y
);
378 CalcBoundingBox (x
+ width
, y
+ height
);
381 void wxWindowDC::DoDrawPoint( wxCoord x
, wxCoord y
)
383 wxCHECK_RET( Ok(), wxT("invalid window dc") );
385 if ((m_pen
.GetStyle() != wxTRANSPARENT
) && m_window
)
386 gdk_draw_point( m_window
, m_penGC
, XLOG2DEV(x
), YLOG2DEV(y
) );
388 CalcBoundingBox (x
, y
);
391 void wxWindowDC::DoDrawLines( int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
393 wxCHECK_RET( Ok(), wxT("invalid window dc") );
395 if (m_pen
.GetStyle() == wxTRANSPARENT
) return;
398 CalcBoundingBox( points
[0].x
+ xoffset
, points
[0].y
+ yoffset
);
400 for (int i
= 0; i
< n
-1; i
++)
402 wxCoord x1
= XLOG2DEV(points
[i
].x
+ xoffset
);
403 wxCoord x2
= XLOG2DEV(points
[i
+1].x
+ xoffset
);
404 wxCoord y1
= YLOG2DEV(points
[i
].y
+ yoffset
); // oh, what a waste
405 wxCoord y2
= YLOG2DEV(points
[i
+1].y
+ yoffset
);
408 gdk_draw_line( m_window
, m_penGC
, x1
, y1
, x2
, y2
);
410 CalcBoundingBox( points
[i
+1].x
+ xoffset
, points
[i
+1].y
+ yoffset
);
414 void wxWindowDC::DoDrawPolygon( int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
, int WXUNUSED(fillStyle
) )
416 wxCHECK_RET( Ok(), wxT("invalid window dc") );
420 GdkPoint
*gdkpoints
= new GdkPoint
[n
+1];
422 for (i
= 0 ; i
< n
; i
++)
424 gdkpoints
[i
].x
= XLOG2DEV(points
[i
].x
+ xoffset
);
425 gdkpoints
[i
].y
= YLOG2DEV(points
[i
].y
+ yoffset
);
427 CalcBoundingBox( points
[i
].x
+ xoffset
, points
[i
].y
+ yoffset
);
432 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
433 gdk_draw_polygon (m_window
, m_textGC
, TRUE
, gdkpoints
, n
);
436 if ((m_brush
.GetStyle() != wxTRANSPARENT
))
437 gdk_draw_polygon (m_window
, m_brushGC
, TRUE
, gdkpoints
, n
);
443 if ((m_pen
.GetStyle() != wxTRANSPARENT
) && m_window
)
445 for (i
= 0 ; i
< n
; i
++)
447 gdk_draw_line( m_window
, m_penGC
,
450 gdkpoints
[(i
+1)%n
].x
,
451 gdkpoints
[(i
+1)%n
].y
);
458 void wxWindowDC::DoDrawRectangle( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
460 wxCHECK_RET( Ok(), wxT("invalid window dc") );
462 wxCoord xx
= XLOG2DEV(x
);
463 wxCoord yy
= YLOG2DEV(y
);
464 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
465 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
467 // CMB: draw nothing if transformed w or h is 0
468 if (ww
== 0 || hh
== 0) return;
470 // CMB: handle -ve width and/or height
471 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
472 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
476 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
478 gdk_draw_rectangle( m_window
, m_textGC
, TRUE
, xx
, yy
, ww
, hh
);
479 gdk_draw_rectangle( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
-1, hh
-1 );
483 if (m_brush
.GetStyle() != wxTRANSPARENT
)
484 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
);
486 if (m_pen
.GetStyle() != wxTRANSPARENT
)
487 gdk_draw_rectangle( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
-1, hh
-1 );
491 CalcBoundingBox( x
, y
);
492 CalcBoundingBox( x
+ width
, y
+ height
);
495 void wxWindowDC::DoDrawRoundedRectangle( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
497 wxCHECK_RET( Ok(), wxT("invalid window dc") );
499 if (radius
< 0.0) radius
= - radius
* ((width
< height
) ? width
: height
);
501 wxCoord xx
= XLOG2DEV(x
);
502 wxCoord yy
= YLOG2DEV(y
);
503 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
504 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
505 wxCoord rr
= XLOG2DEVREL((wxCoord
)radius
);
507 // CMB: handle -ve width and/or height
508 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
509 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
511 // CMB: if radius is zero use DrawRectangle() instead to avoid
512 // X drawing errors with small radii
515 DrawRectangle( x
, y
, width
, height
);
519 // CMB: draw nothing if transformed w or h is 0
520 if (ww
== 0 || hh
== 0) return;
522 // CMB: adjust size if outline is drawn otherwise the result is
523 // 1 pixel too wide and high
524 if (m_pen
.GetStyle() != wxTRANSPARENT
)
532 // CMB: ensure dd is not larger than rectangle otherwise we
533 // get an hour glass shape
535 if (dd
> ww
) dd
= ww
;
536 if (dd
> hh
) dd
= hh
;
539 if (m_brush
.GetStyle() != wxTRANSPARENT
)
541 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
+rr
, yy
, ww
-dd
+1, hh
);
542 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
+rr
, ww
, hh
-dd
+1 );
543 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, dd
, dd
, 90*64, 90*64 );
544 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 );
545 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 );
546 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 );
549 if (m_pen
.GetStyle() != wxTRANSPARENT
)
551 gdk_draw_line( m_window
, m_penGC
, xx
+rr
, yy
, xx
+ww
-rr
, yy
);
552 gdk_draw_line( m_window
, m_penGC
, xx
+rr
, yy
+hh
, xx
+ww
-rr
, yy
+hh
);
553 gdk_draw_line( m_window
, m_penGC
, xx
, yy
+rr
, xx
, yy
+hh
-rr
);
554 gdk_draw_line( m_window
, m_penGC
, xx
+ww
, yy
+rr
, xx
+ww
, yy
+hh
-rr
);
555 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
, dd
, dd
, 90*64, 90*64 );
556 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 );
557 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 );
558 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 );
562 // this ignores the radius
563 CalcBoundingBox( x
, y
);
564 CalcBoundingBox( x
+ width
, y
+ height
);
567 void wxWindowDC::DoDrawEllipse( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
569 wxCHECK_RET( Ok(), wxT("invalid window dc") );
571 wxCoord xx
= XLOG2DEV(x
);
572 wxCoord yy
= YLOG2DEV(y
);
573 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
574 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
576 // CMB: handle -ve width and/or height
577 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
578 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
582 if (m_brush
.GetStyle() != wxTRANSPARENT
)
583 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, 0, 360*64 );
585 if (m_pen
.GetStyle() != wxTRANSPARENT
)
586 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
, hh
, 0, 360*64 );
589 CalcBoundingBox( x
- width
, y
- height
);
590 CalcBoundingBox( x
+ width
, y
+ height
);
593 void wxWindowDC::DoDrawIcon( const wxIcon
&icon
, wxCoord x
, wxCoord y
)
595 // VZ: egcs 1.0.3 refuses to compile this without cast, no idea why
596 DoDrawBitmap( (const wxBitmap
&)icon
, x
, y
, (bool)TRUE
);
599 void wxWindowDC::DoDrawBitmap( const wxBitmap
&bitmap
,
600 wxCoord x
, wxCoord y
,
603 wxCHECK_RET( Ok(), wxT("invalid window dc") );
605 wxCHECK_RET( bitmap
.Ok(), wxT("invalid bitmap") );
607 bool is_mono
= (bitmap
.GetBitmap() != NULL
);
609 /* scale/translate size and position */
610 int xx
= XLOG2DEV(x
);
611 int yy
= YLOG2DEV(y
);
613 int w
= bitmap
.GetWidth();
614 int h
= bitmap
.GetHeight();
616 CalcBoundingBox( x
, y
);
617 CalcBoundingBox( x
+ w
, y
+ h
);
619 if (!m_window
) return;
621 int ww
= XLOG2DEVREL(w
);
622 int hh
= YLOG2DEVREL(h
);
624 /* compare to current clipping region */
625 if (!m_currentClippingRegion
.IsEmpty())
627 wxRegion
tmp( xx
,yy
,ww
,hh
);
628 tmp
.Intersect( m_currentClippingRegion
);
633 /* scale bitmap if required */
635 if ((w
!= ww
) || (h
!= hh
))
637 wxImage
image( bitmap
);
638 image
.Rescale( ww
, hh
);
640 use_bitmap
= image
.ConvertToMonoBitmap(255,255,255);
642 use_bitmap
= image
.ConvertToBitmap();
649 /* apply mask if any */
650 GdkBitmap
*mask
= (GdkBitmap
*) NULL
;
651 if (use_bitmap
.GetMask()) mask
= use_bitmap
.GetMask()->GetBitmap();
655 GdkBitmap
*new_mask
= (GdkBitmap
*) NULL
;
656 if (!m_currentClippingRegion
.IsEmpty())
659 new_mask
= gdk_pixmap_new( wxRootWindow
->window
, ww
, hh
, 1 );
660 GdkGC
*gc
= gdk_gc_new( new_mask
);
662 gdk_gc_set_foreground( gc
, &col
);
663 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, ww
, hh
);
665 gdk_gc_set_background( gc
, &col
);
667 gdk_gc_set_foreground( gc
, &col
);
668 gdk_gc_set_clip_region( gc
, m_currentClippingRegion
.GetRegion() );
669 gdk_gc_set_clip_origin( gc
, -xx
, -yy
);
670 gdk_gc_set_fill( gc
, GDK_OPAQUE_STIPPLED
);
671 gdk_gc_set_stipple( gc
, mask
);
672 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, ww
, hh
);
674 gdk_gc_set_clip_mask( m_brushGC, NULL );
675 gdk_gc_set_clip_mask( m_textGC, NULL );
676 SetBrush( *wxRED_BRUSH );
677 DrawRectangle( 70, 0, 70, 1000 );
678 gdk_draw_bitmap( m_window, m_textGC, new_mask, 0, 0, 100, 5, ww, hh );
679 gdk_draw_bitmap( m_window, m_textGC, mask, 0, 0, 80, 5, ww, hh );
687 gdk_gc_set_clip_mask( m_textGC
, new_mask
);
689 gdk_gc_set_clip_mask( m_textGC
, mask
);
690 gdk_gc_set_clip_origin( m_textGC
, xx
, yy
);
695 gdk_gc_set_clip_mask( m_penGC
, new_mask
);
697 gdk_gc_set_clip_mask( m_penGC
, mask
);
698 gdk_gc_set_clip_origin( m_penGC
, xx
, yy
);
701 gdk_bitmap_unref( new_mask
);
704 /* Draw XPixmap or XBitmap, depending on what the wxBitmap contains. For
705 drawing a mono-bitmap (XBitmap) we use the current text GC */
707 gdk_draw_bitmap( m_window
, m_textGC
, use_bitmap
.GetBitmap(), 0, 0, xx
, yy
, -1, -1 );
709 gdk_draw_pixmap( m_window
, m_penGC
, use_bitmap
.GetPixmap(), 0, 0, xx
, yy
, -1, -1 );
711 /* remove mask again if any */
716 gdk_gc_set_clip_mask( m_textGC
, (GdkBitmap
*) NULL
);
717 gdk_gc_set_clip_origin( m_textGC
, 0, 0 );
718 if (!m_currentClippingRegion
.IsEmpty())
719 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
723 gdk_gc_set_clip_mask( m_penGC
, (GdkBitmap
*) NULL
);
724 gdk_gc_set_clip_origin( m_penGC
, 0, 0 );
725 if (!m_currentClippingRegion
.IsEmpty())
726 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
731 bool wxWindowDC::DoBlit( wxCoord xdest
, wxCoord ydest
, wxCoord width
, wxCoord height
,
732 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
,
733 int logical_func
, bool useMask
)
735 /* this is the nth try to get this utterly useless function to
736 work. it now completely ignores the scaling or translation
737 of the source dc, but scales correctly on the target dc and
738 knows about possible mask information in a memory dc. */
740 wxCHECK_MSG( Ok(), FALSE
, wxT("invalid window dc") );
742 wxCHECK_MSG( source
, FALSE
, wxT("invalid source dc") );
744 if (!m_window
) return FALSE
;
746 wxClientDC
*srcDC
= (wxClientDC
*)source
;
747 wxMemoryDC
*memDC
= (wxMemoryDC
*)source
;
749 bool use_bitmap_method
= FALSE
;
750 bool is_mono
= FALSE
;
752 if (srcDC
->m_isMemDC
)
754 if (!memDC
->m_selected
.Ok()) return FALSE
;
756 /* we use the "XCopyArea" way to copy a memory dc into
757 y different window if the memory dc BOTH
758 a) doesn't have any mask or its mask isn't used
762 if (useMask
&& (memDC
->m_selected
.GetMask()))
764 /* we HAVE TO use the direct way for memory dcs
765 that have mask since the XCopyArea doesn't know
767 use_bitmap_method
= TRUE
;
769 else if (memDC
->m_selected
.GetDepth() == 1)
771 /* we HAVE TO use the direct way for memory dcs
772 that are bitmaps because XCopyArea doesn't cope
773 with different bit depths */
775 use_bitmap_method
= TRUE
;
777 else if ((xsrc
== 0) && (ysrc
== 0) &&
778 (width
== memDC
->m_selected
.GetWidth()) &&
779 (height
== memDC
->m_selected
.GetHeight()))
781 /* we SHOULD use the direct way if all of the bitmap
782 in the memory dc is copied in which case XCopyArea
783 wouldn't be able able to boost performace by reducing
784 the area to be scaled */
785 use_bitmap_method
= TRUE
;
789 use_bitmap_method
= FALSE
;
793 CalcBoundingBox( xdest
, ydest
);
794 CalcBoundingBox( xdest
+ width
, ydest
+ height
);
796 /* scale/translate size and position */
797 wxCoord xx
= XLOG2DEV(xdest
);
798 wxCoord yy
= YLOG2DEV(ydest
);
800 wxCoord ww
= XLOG2DEVREL(width
);
801 wxCoord hh
= YLOG2DEVREL(height
);
803 /* compare to current clipping region */
804 if (!m_currentClippingRegion
.IsEmpty())
806 wxRegion
tmp( xx
,yy
,ww
,hh
);
807 tmp
.Intersect( m_currentClippingRegion
);
812 int old_logical_func
= m_logicalFunction
;
813 SetLogicalFunction( logical_func
);
815 if (use_bitmap_method
)
817 /* scale/translate bitmap size */
818 wxCoord bm_width
= memDC
->m_selected
.GetWidth();
819 wxCoord bm_height
= memDC
->m_selected
.GetHeight();
821 wxCoord bm_ww
= XLOG2DEVREL( bm_width
);
822 wxCoord bm_hh
= YLOG2DEVREL( bm_height
);
824 /* scale bitmap if required */
827 if ((bm_width
!= bm_ww
) || (bm_height
!= bm_hh
))
829 wxImage
image( memDC
->m_selected
);
830 image
= image
.Scale( bm_ww
, bm_hh
);
833 use_bitmap
= image
.ConvertToMonoBitmap(255,255,255);
835 use_bitmap
= image
.ConvertToBitmap();
839 use_bitmap
= memDC
->m_selected
;
842 /* apply mask if any */
843 GdkBitmap
*mask
= (GdkBitmap
*) NULL
;
844 if (use_bitmap
.GetMask()) mask
= use_bitmap
.GetMask()->GetBitmap();
848 GdkBitmap
*new_mask
= (GdkBitmap
*) NULL
;
849 if (!m_currentClippingRegion
.IsEmpty())
852 new_mask
= gdk_pixmap_new( wxRootWindow
->window
, bm_ww
, bm_hh
, 1 );
853 GdkGC
*gc
= gdk_gc_new( new_mask
);
855 gdk_gc_set_foreground( gc
, &col
);
856 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, bm_ww
, bm_hh
);
858 gdk_gc_set_background( gc
, &col
);
860 gdk_gc_set_foreground( gc
, &col
);
861 gdk_gc_set_clip_region( gc
, m_currentClippingRegion
.GetRegion() );
862 gdk_gc_set_clip_origin( gc
, -xx
, -yy
);
863 gdk_gc_set_fill( gc
, GDK_OPAQUE_STIPPLED
);
864 gdk_gc_set_stipple( gc
, mask
);
865 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, bm_ww
, bm_hh
);
872 gdk_gc_set_clip_mask( m_textGC
, new_mask
);
874 gdk_gc_set_clip_mask( m_textGC
, mask
);
875 gdk_gc_set_clip_origin( m_textGC
, xx
, yy
);
880 gdk_gc_set_clip_mask( m_penGC
, new_mask
);
882 gdk_gc_set_clip_mask( m_penGC
, mask
);
883 gdk_gc_set_clip_origin( m_penGC
, xx
, yy
);
886 gdk_bitmap_unref( new_mask
);
889 /* Draw XPixmap or XBitmap, depending on what the wxBitmap contains. For
890 drawing a mono-bitmap (XBitmap) we use the current text GC */
892 gdk_draw_bitmap( m_window
, m_textGC
, use_bitmap
.GetBitmap(), xsrc
, ysrc
, xx
, yy
, ww
, hh
);
894 gdk_draw_pixmap( m_window
, m_penGC
, use_bitmap
.GetPixmap(), xsrc
, ysrc
, xx
, yy
, ww
, hh
);
896 /* remove mask again if any */
901 gdk_gc_set_clip_mask( m_textGC
, (GdkBitmap
*) NULL
);
902 gdk_gc_set_clip_origin( m_textGC
, 0, 0 );
903 if (!m_currentClippingRegion
.IsEmpty())
904 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
908 gdk_gc_set_clip_mask( m_penGC
, (GdkBitmap
*) NULL
);
909 gdk_gc_set_clip_origin( m_penGC
, 0, 0 );
910 if (!m_currentClippingRegion
.IsEmpty())
911 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
915 else /* use_bitmap_method */
917 if ((width
!= ww
) || (height
!= hh
))
919 /* draw source window into a bitmap as we cannot scale
920 a window in contrast to a bitmap. this would actually
921 work with memory dcs as well, but we'd lose the mask
922 information and waste one step in this process since
923 a memory already has a bitmap. all this is slightly
924 inefficient as we could take an XImage directly from
925 an X window, but we'd then also have to care that
926 the window is not outside the screen (in which case
927 we'd get a BadMatch or what not).
928 Is a double XGetImage and combined XGetPixel and
929 XPutPixel really faster? I'm not sure. look at wxXt
930 for a different implementation of the same problem. */
932 wxBitmap
bitmap( width
, height
);
933 gdk_window_copy_area( bitmap
.GetPixmap(), m_penGC
, 0, 0,
935 xsrc
, ysrc
, width
, height
);
939 wxImage
image( bitmap
);
940 image
= image
.Scale( ww
, hh
);
942 /* convert to bitmap */
944 bitmap
= image
.ConvertToBitmap();
946 /* draw scaled bitmap */
948 gdk_draw_pixmap( m_window
, m_penGC
, bitmap
.GetPixmap(), 0, 0, xx
, yy
, -1, -1 );
953 /* no scaling and not a memory dc with a mask either */
955 gdk_window_copy_area( m_window
, m_penGC
, xx
, yy
,
957 xsrc
, ysrc
, width
, height
);
961 SetLogicalFunction( old_logical_func
);
965 void wxWindowDC::DoDrawText( const wxString
&text
, wxCoord x
, wxCoord y
)
967 wxCHECK_RET( Ok(), wxT("invalid window dc") );
969 if (!m_window
) return;
971 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
973 wxCHECK_RET( font
, wxT("invalid font") );
978 /* CMB 21/5/98: draw text background if mode is wxSOLID */
979 if (m_backgroundMode
== wxSOLID
)
981 wxCoord width
= gdk_string_width( font
, text
.mbc_str() );
982 wxCoord height
= font
->ascent
+ font
->descent
;
983 gdk_gc_set_foreground( m_textGC
, m_textBackgroundColour
.GetColor() );
984 gdk_draw_rectangle( m_window
, m_textGC
, TRUE
, x
, y
, width
, height
);
985 gdk_gc_set_foreground( m_textGC
, m_textForegroundColour
.GetColor() );
987 gdk_draw_string( m_window
, font
, m_textGC
, x
, y
+ font
->ascent
, text
.mbc_str() );
989 /* CMB 17/7/98: simple underline: ignores scaling and underlying
990 X font's XA_UNDERLINE_POSITION and XA_UNDERLINE_THICKNESS
991 properties (see wxXt implementation) */
992 if (m_font
.GetUnderlined())
994 wxCoord width
= gdk_string_width( font
, text
.mbc_str() );
995 wxCoord ul_y
= y
+ font
->ascent
;
996 if (font
->descent
> 0) ul_y
++;
997 gdk_draw_line( m_window
, m_textGC
, x
, ul_y
, x
+ width
, ul_y
);
1001 GetTextExtent (text
, &w
, &h
);
1002 CalcBoundingBox (x
+ w
, y
+ h
);
1003 CalcBoundingBox (x
, y
);
1006 void wxWindowDC::DoDrawRotatedText( const wxString
&text
, wxCoord x
, wxCoord y
, double angle
)
1010 DrawText(text
, x
, y
);
1014 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1016 if (!m_window
) return;
1018 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
1020 wxCHECK_RET( font
, wxT("invalid font") );
1022 // the size of the text
1023 wxCoord w
= gdk_string_width( font
, text
.mbc_str() );
1024 wxCoord h
= font
->ascent
+ font
->descent
;
1026 // draw the string normally
1029 dc
.SelectObject(src
);
1030 dc
.SetFont(GetFont());
1031 dc
.SetBackground(*wxWHITE_BRUSH
);
1032 dc
.SetBrush(*wxBLACK_BRUSH
);
1034 dc
.DrawText(text
, 0, 0);
1035 dc
.SetFont(wxNullFont
);
1036 dc
.SelectObject(wxNullBitmap
);
1038 // Calculate the size of the rotated bounding box.
1039 double rad
= DegToRad(angle
);
1040 double dx
= cos(rad
),
1043 // the rectngle vertices are counted clockwise with the first one being at
1044 // (0, 0) (or, rather, at (x, y))
1046 y2
= -w
*dy
; // y axis points to the bottom, hence minus
1049 double x3
= x4
+ x2
,
1053 wxCoord maxX
= (wxCoord
)(dmax(x2
, dmax(x3
, x4
)) + 0.5),
1054 maxY
= (wxCoord
)(dmax(y2
, dmax(y3
, y4
)) + 0.5),
1055 minX
= (wxCoord
)(dmin(x2
, dmin(x3
, x4
)) - 0.5),
1056 minY
= (wxCoord
)(dmin(y2
, dmin(y3
, y4
)) - 0.5);
1058 // prepare to blit-with-rotate the bitmap to the DC
1061 GdkColor
*colText
= m_textForegroundColour
.GetColor(),
1062 *colBack
= m_textBackgroundColour
.GetColor();
1064 bool textColSet
= TRUE
;
1066 unsigned char *data
= image
.GetData();
1068 // paint pixel by pixel
1069 for ( wxCoord srcX
= 0; srcX
< w
; srcX
++ )
1071 for ( wxCoord srcY
= 0; srcY
< h
; srcY
++ )
1073 // transform source coords to dest coords
1074 double r
= sqrt(srcX
*srcX
+ srcY
*srcY
);
1075 double angleOrig
= atan2(srcY
, srcX
) - rad
;
1076 wxCoord dstX
= (wxCoord
)(r
*cos(angleOrig
) + 0.5),
1077 dstY
= (wxCoord
)(r
*sin(angleOrig
) + 0.5);
1080 bool textPixel
= data
[(srcY
*w
+ srcX
)*3] == 0;
1081 if ( textPixel
|| (m_backgroundMode
== wxSOLID
) )
1083 // change colour if needed
1084 if ( textPixel
!= textColSet
)
1086 gdk_gc_set_foreground( m_textGC
, textPixel
? colText
1089 textColSet
= textPixel
;
1092 // don't use DrawPoint() because it uses the current pen
1093 // colour, and we don't need it here
1094 gdk_draw_point( m_window
, m_textGC
,
1095 XLOG2DEV(x
+ dstX
), YLOG2DEV(y
+ dstY
) );
1100 // it would be better to draw with non underlined font and draw the line
1101 // manually here (it would be more straight...)
1103 if ( m_font
.GetUnderlined() )
1105 gdk_draw_line( m_window
, m_textGC
,
1106 XLOG2DEV(x
+ x4
), YLOG2DEV(y
+ y4
+ font
->descent
),
1107 XLOG2DEV(x
+ x3
), YLOG2DEV(y
+ y3
+ font
->descent
));
1111 // restore the font colour
1112 gdk_gc_set_foreground( m_textGC
, colText
);
1114 // update the bounding box
1115 CalcBoundingBox(x
+ minX
, y
+ minY
);
1116 CalcBoundingBox(x
+ maxX
, y
+ maxY
);
1119 void wxWindowDC::DoGetTextExtent(const wxString
&string
,
1120 wxCoord
*width
, wxCoord
*height
,
1121 wxCoord
*descent
, wxCoord
*externalLeading
,
1122 wxFont
*theFont
) const
1124 wxFont fontToUse
= m_font
;
1125 if (theFont
) fontToUse
= *theFont
;
1127 GdkFont
*font
= fontToUse
.GetInternalFont( m_scaleY
);
1128 if (width
) (*width
) = wxCoord(gdk_string_width( font
, string
.mbc_str() ) / m_scaleX
);
1129 if (height
) (*height
) = wxCoord((font
->ascent
+ font
->descent
) / m_scaleY
);
1130 if (descent
) (*descent
) = wxCoord(font
->descent
/ m_scaleY
);
1131 if (externalLeading
) (*externalLeading
) = 0; // ??
1134 wxCoord
wxWindowDC::GetCharWidth() const
1136 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
1137 wxCHECK_MSG( font
, -1, wxT("invalid font") );
1139 return wxCoord(gdk_string_width( font
, "H" ) / m_scaleX
);
1142 wxCoord
wxWindowDC::GetCharHeight() const
1144 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
1145 wxCHECK_MSG( font
, -1, wxT("invalid font") );
1147 return wxCoord((font
->ascent
+ font
->descent
) / m_scaleY
);
1150 void wxWindowDC::Clear()
1152 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1154 if (!m_window
) return;
1156 /* - we either are a memory dc or have a window as the
1157 owner. anything else shouldn't happen.
1158 - we don't use gdk_window_clear() as we don't set
1159 the window's background colour anymore. it is too
1160 much pain to keep the DC's and the window's back-
1161 ground colour in synch. */
1166 m_owner
->GetSize( &width
, &height
);
1167 gdk_draw_rectangle( m_window
, m_bgGC
, TRUE
, 0, 0, width
, height
);
1174 GetSize( &width
, &height
);
1175 gdk_draw_rectangle( m_window
, m_bgGC
, TRUE
, 0, 0, width
, height
);
1180 void wxWindowDC::SetFont( const wxFont
&font
)
1185 void wxWindowDC::SetPen( const wxPen
&pen
)
1187 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1189 if (m_pen
== pen
) return;
1193 if (!m_pen
.Ok()) return;
1195 if (!m_window
) return;
1197 gint width
= m_pen
.GetWidth();
1200 // CMB: if width is non-zero scale it with the dc
1205 // X doesn't allow different width in x and y and so we take
1208 ( fabs((double) XLOG2DEVREL(width
)) +
1209 fabs((double) YLOG2DEVREL(width
)) ) / 2.0;
1213 static const char dotted
[] = {1, 1};
1214 static const char short_dashed
[] = {2, 2};
1215 static const char wxCoord_dashed
[] = {2, 4};
1216 static const char dotted_dashed
[] = {3, 3, 1, 3};
1218 // We express dash pattern in pen width unit, so we are
1219 // independent of zoom factor and so on...
1221 const char *req_dash
;
1223 GdkLineStyle lineStyle
= GDK_LINE_SOLID
;
1224 switch (m_pen
.GetStyle())
1228 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1229 req_nb_dash
= m_pen
.GetDashCount();
1230 req_dash
= m_pen
.GetDash();
1235 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1242 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1244 req_dash
= wxCoord_dashed
;
1249 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1251 req_dash
= short_dashed
;
1256 // lineStyle = GDK_LINE_DOUBLE_DASH;
1257 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1259 req_dash
= dotted_dashed
;
1264 case wxSTIPPLE_MASK_OPAQUE
:
1269 lineStyle
= GDK_LINE_SOLID
;
1270 req_dash
= (wxDash
*)NULL
;
1276 #if (GTK_MINOR_VERSION > 0)
1277 if (req_dash
&& req_nb_dash
)
1279 char *real_req_dash
= new char[req_nb_dash
];
1282 for (int i
= 0; i
< req_nb_dash
; i
++)
1283 real_req_dash
[i
] = req_dash
[i
] * width
;
1284 gdk_gc_set_dashes( m_penGC
, 0, real_req_dash
, req_nb_dash
);
1285 delete[] real_req_dash
;
1289 // No Memory. We use non-scaled dash pattern...
1290 gdk_gc_set_dashes( m_penGC
, 0, (char*)req_dash
, req_nb_dash
);
1295 GdkCapStyle capStyle
= GDK_CAP_ROUND
;
1296 switch (m_pen
.GetCap())
1298 case wxCAP_PROJECTING
: { capStyle
= GDK_CAP_PROJECTING
; break; }
1299 case wxCAP_BUTT
: { capStyle
= GDK_CAP_BUTT
; break; }
1306 capStyle
= GDK_CAP_NOT_LAST
;
1310 capStyle
= GDK_CAP_ROUND
;
1316 GdkJoinStyle joinStyle
= GDK_JOIN_ROUND
;
1317 switch (m_pen
.GetJoin())
1319 case wxJOIN_BEVEL
: { joinStyle
= GDK_JOIN_BEVEL
; break; }
1320 case wxJOIN_MITER
: { joinStyle
= GDK_JOIN_MITER
; break; }
1322 default: { joinStyle
= GDK_JOIN_ROUND
; break; }
1325 gdk_gc_set_line_attributes( m_penGC
, width
, lineStyle
, capStyle
, joinStyle
);
1327 m_pen
.GetColour().CalcPixel( m_cmap
);
1328 gdk_gc_set_foreground( m_penGC
, m_pen
.GetColour().GetColor() );
1331 void wxWindowDC::SetBrush( const wxBrush
&brush
)
1333 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1335 if (m_brush
== brush
) return;
1339 if (!m_brush
.Ok()) return;
1341 if (!m_window
) return;
1343 m_brush
.GetColour().CalcPixel( m_cmap
);
1344 gdk_gc_set_foreground( m_brushGC
, m_brush
.GetColour().GetColor() );
1346 gdk_gc_set_fill( m_brushGC
, GDK_SOLID
);
1348 if ((m_brush
.GetStyle() == wxSTIPPLE
) && (m_brush
.GetStipple()->Ok()))
1350 if (m_brush
.GetStipple()->GetPixmap())
1352 gdk_gc_set_fill( m_brushGC
, GDK_TILED
);
1353 gdk_gc_set_tile( m_brushGC
, m_brush
.GetStipple()->GetPixmap() );
1357 gdk_gc_set_fill( m_brushGC
, GDK_STIPPLED
);
1358 gdk_gc_set_stipple( m_brushGC
, m_brush
.GetStipple()->GetBitmap() );
1362 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
1364 gdk_gc_set_fill( m_textGC
, GDK_OPAQUE_STIPPLED
);
1365 gdk_gc_set_stipple( m_textGC
, m_brush
.GetStipple()->GetMask()->GetBitmap() );
1368 if (IS_HATCH(m_brush
.GetStyle()))
1370 gdk_gc_set_fill( m_brushGC
, GDK_STIPPLED
);
1371 int num
= m_brush
.GetStyle() - wxBDIAGONAL_HATCH
;
1372 gdk_gc_set_stipple( m_brushGC
, hatches
[num
] );
1376 void wxWindowDC::SetBackground( const wxBrush
&brush
)
1378 /* CMB 21/7/98: Added SetBackground. Sets background brush
1379 * for Clear() and bg colour for shapes filled with cross-hatch brush */
1381 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1383 if (m_backgroundBrush
== brush
) return;
1385 m_backgroundBrush
= brush
;
1387 if (!m_backgroundBrush
.Ok()) return;
1389 if (!m_window
) return;
1391 m_backgroundBrush
.GetColour().CalcPixel( m_cmap
);
1392 gdk_gc_set_background( m_brushGC
, m_backgroundBrush
.GetColour().GetColor() );
1393 gdk_gc_set_background( m_penGC
, m_backgroundBrush
.GetColour().GetColor() );
1394 gdk_gc_set_background( m_bgGC
, m_backgroundBrush
.GetColour().GetColor() );
1395 gdk_gc_set_foreground( m_bgGC
, m_backgroundBrush
.GetColour().GetColor() );
1397 gdk_gc_set_fill( m_bgGC
, GDK_SOLID
);
1399 if ((m_backgroundBrush
.GetStyle() == wxSTIPPLE
) && (m_backgroundBrush
.GetStipple()->Ok()))
1401 if (m_backgroundBrush
.GetStipple()->GetPixmap())
1403 gdk_gc_set_fill( m_bgGC
, GDK_TILED
);
1404 gdk_gc_set_tile( m_bgGC
, m_backgroundBrush
.GetStipple()->GetPixmap() );
1408 gdk_gc_set_fill( m_bgGC
, GDK_STIPPLED
);
1409 gdk_gc_set_stipple( m_bgGC
, m_backgroundBrush
.GetStipple()->GetBitmap() );
1413 if (IS_HATCH(m_backgroundBrush
.GetStyle()))
1415 gdk_gc_set_fill( m_bgGC
, GDK_STIPPLED
);
1416 int num
= m_backgroundBrush
.GetStyle() - wxBDIAGONAL_HATCH
;
1417 gdk_gc_set_stipple( m_bgGC
, hatches
[num
] );
1421 void wxWindowDC::SetLogicalFunction( int function
)
1423 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1425 if (m_logicalFunction
== function
)
1428 // VZ: shouldn't this be a CHECK?
1432 GdkFunction mode
= GDK_COPY
;
1435 case wxXOR
: mode
= GDK_XOR
; break;
1436 case wxINVERT
: mode
= GDK_INVERT
; break;
1437 #if (GTK_MINOR_VERSION > 0)
1438 case wxOR_REVERSE
: mode
= GDK_OR_REVERSE
; break;
1439 case wxAND_REVERSE
: mode
= GDK_AND_REVERSE
; break;
1440 case wxCLEAR
: mode
= GDK_CLEAR
; break;
1441 case wxSET
: mode
= GDK_SET
; break;
1442 case wxOR_INVERT
: mode
= GDK_OR_INVERT
; break;
1443 case wxAND
: mode
= GDK_AND
; break;
1444 case wxOR
: mode
= GDK_OR
; break;
1445 case wxEQUIV
: mode
= GDK_EQUIV
; break;
1446 case wxNAND
: mode
= GDK_NAND
; break;
1447 case wxAND_INVERT
: mode
= GDK_AND_INVERT
; break;
1448 case wxCOPY
: mode
= GDK_COPY
; break;
1449 case wxNO_OP
: mode
= GDK_NOOP
; break;
1450 case wxSRC_INVERT
: mode
= GDK_COPY_INVERT
; break;
1452 // unsupported by GTK
1453 case wxNOR
: mode
= GDK_COPY
; break;
1457 wxFAIL_MSG( wxT("unsupported logical function") );
1462 m_logicalFunction
= function
;
1464 gdk_gc_set_function( m_penGC
, mode
);
1465 gdk_gc_set_function( m_brushGC
, mode
);
1467 // to stay compatible with wxMSW, we don't apply ROPs to the text
1468 // operations (i.e. DrawText/DrawRotatedText).
1469 // True, but mono-bitmaps use the m_textGC and they use ROPs as well.
1470 gdk_gc_set_function( m_textGC
, mode
);
1473 void wxWindowDC::SetTextForeground( const wxColour
&col
)
1475 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1477 if (m_textForegroundColour
== col
) return;
1479 m_textForegroundColour
= col
;
1480 if (!m_textForegroundColour
.Ok()) return;
1482 if (!m_window
) return;
1484 m_textForegroundColour
.CalcPixel( m_cmap
);
1485 gdk_gc_set_foreground( m_textGC
, m_textForegroundColour
.GetColor() );
1488 void wxWindowDC::SetTextBackground( const wxColour
&col
)
1490 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1492 if (m_textBackgroundColour
== col
) return;
1494 m_textBackgroundColour
= col
;
1495 if (!m_textBackgroundColour
.Ok()) return;
1497 if (!m_window
) return;
1499 m_textBackgroundColour
.CalcPixel( m_cmap
);
1500 gdk_gc_set_background( m_textGC
, m_textBackgroundColour
.GetColor() );
1503 void wxWindowDC::SetBackgroundMode( int mode
)
1505 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1507 m_backgroundMode
= mode
;
1509 if (!m_window
) return;
1511 // CMB 21/7/98: fill style of cross-hatch brushes is affected by
1512 // transparent/solid background mode
1514 if (m_brush
.GetStyle() != wxSOLID
&& m_brush
.GetStyle() != wxTRANSPARENT
)
1516 gdk_gc_set_fill( m_brushGC
,
1517 (m_backgroundMode
== wxTRANSPARENT
) ? GDK_STIPPLED
: GDK_OPAQUE_STIPPLED
);
1521 void wxWindowDC::SetPalette( const wxPalette
& WXUNUSED(palette
) )
1523 wxFAIL_MSG( wxT("wxWindowDC::SetPalette not implemented") );
1526 void wxWindowDC::DoSetClippingRegion( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
1528 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1530 wxDC::DoSetClippingRegion( x
, y
, width
, height
);
1532 if (!m_window
) return;
1535 rect
.x
= XLOG2DEV(x
);
1536 rect
.y
= YLOG2DEV(y
);
1537 rect
.width
= XLOG2DEVREL(width
);
1538 rect
.height
= YLOG2DEVREL(height
);
1540 m_currentClippingRegion
.Clear();
1541 m_currentClippingRegion
.Union( rect
);
1542 if (!m_paintClippingRegion
.IsEmpty())
1543 m_currentClippingRegion
.Intersect( m_paintClippingRegion
);
1545 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
1546 gdk_gc_set_clip_region( m_brushGC
, m_currentClippingRegion
.GetRegion() );
1547 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
1548 gdk_gc_set_clip_region( m_bgGC
, m_currentClippingRegion
.GetRegion() );
1551 void wxWindowDC::DoSetClippingRegionAsRegion( const wxRegion
®ion
)
1553 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1557 DestroyClippingRegion();
1562 region
.GetBox( x
, y
, w
, h
);
1564 wxDC::DoSetClippingRegion( x
, y
, w
, h
);
1566 if (!m_window
) return;
1568 m_currentClippingRegion
.Clear();
1569 m_currentClippingRegion
.Union( region
);
1570 if (!m_paintClippingRegion
.IsEmpty())
1571 m_currentClippingRegion
.Intersect( m_paintClippingRegion
);
1573 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
1574 gdk_gc_set_clip_region( m_brushGC
, m_currentClippingRegion
.GetRegion() );
1575 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
1576 gdk_gc_set_clip_region( m_bgGC
, m_currentClippingRegion
.GetRegion() );
1579 void wxWindowDC::DestroyClippingRegion()
1581 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1583 wxDC::DestroyClippingRegion();
1585 m_currentClippingRegion
.Clear();
1587 if (!m_paintClippingRegion
.IsEmpty())
1588 m_currentClippingRegion
.Union( m_paintClippingRegion
);
1590 if (!m_window
) return;
1592 if (m_currentClippingRegion
.IsEmpty())
1594 gdk_gc_set_clip_rectangle( m_penGC
, (GdkRectangle
*) NULL
);
1595 gdk_gc_set_clip_rectangle( m_brushGC
, (GdkRectangle
*) NULL
);
1596 gdk_gc_set_clip_rectangle( m_textGC
, (GdkRectangle
*) NULL
);
1597 gdk_gc_set_clip_rectangle( m_bgGC
, (GdkRectangle
*) NULL
);
1601 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
1602 gdk_gc_set_clip_region( m_brushGC
, m_currentClippingRegion
.GetRegion() );
1603 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
1604 gdk_gc_set_clip_region( m_bgGC
, m_currentClippingRegion
.GetRegion() );
1608 void wxWindowDC::SetUpDC()
1614 m_penGC
= wxGetPoolGC( m_window
, wxPEN_COLOUR
);
1615 m_brushGC
= wxGetPoolGC( m_window
, wxBRUSH_COLOUR
);
1616 m_textGC
= wxGetPoolGC( m_window
, wxTEXT_COLOUR
);
1617 m_bgGC
= wxGetPoolGC( m_window
, wxBG_COLOUR
);
1620 /* background colour */
1621 m_backgroundBrush
= *wxWHITE_BRUSH
;
1622 m_backgroundBrush
.GetColour().CalcPixel( m_cmap
);
1623 GdkColor
*bg_col
= m_backgroundBrush
.GetColour().GetColor();
1626 m_textForegroundColour
.CalcPixel( m_cmap
);
1627 gdk_gc_set_foreground( m_textGC
, m_textForegroundColour
.GetColor() );
1629 m_textBackgroundColour
.CalcPixel( m_cmap
);
1630 gdk_gc_set_background( m_textGC
, m_textBackgroundColour
.GetColor() );
1632 gdk_gc_set_fill( m_textGC
, GDK_SOLID
);
1635 m_pen
.GetColour().CalcPixel( m_cmap
);
1636 gdk_gc_set_foreground( m_penGC
, m_pen
.GetColour().GetColor() );
1637 gdk_gc_set_background( m_penGC
, bg_col
);
1639 gdk_gc_set_line_attributes( m_penGC
, 0, GDK_LINE_SOLID
, GDK_CAP_NOT_LAST
, GDK_JOIN_ROUND
);
1643 m_brush
.GetColour().CalcPixel( m_cmap
);
1644 gdk_gc_set_foreground( m_brushGC
, m_brush
.GetColour().GetColor() );
1645 gdk_gc_set_background( m_brushGC
, bg_col
);
1647 gdk_gc_set_fill( m_brushGC
, GDK_SOLID
);
1651 gdk_gc_set_background( m_bgGC
, bg_col
);
1652 gdk_gc_set_foreground( m_bgGC
, bg_col
);
1654 gdk_gc_set_fill( m_bgGC
, GDK_SOLID
);
1657 gdk_gc_set_function( m_textGC
, GDK_COPY
);
1658 gdk_gc_set_function( m_brushGC
, GDK_COPY
);
1659 gdk_gc_set_function( m_penGC
, GDK_COPY
);
1662 gdk_gc_set_clip_rectangle( m_penGC
, (GdkRectangle
*) NULL
);
1663 gdk_gc_set_clip_rectangle( m_brushGC
, (GdkRectangle
*) NULL
);
1664 gdk_gc_set_clip_rectangle( m_textGC
, (GdkRectangle
*) NULL
);
1665 gdk_gc_set_clip_rectangle( m_bgGC
, (GdkRectangle
*) NULL
);
1669 hatch_bitmap
= hatches
;
1670 hatch_bitmap
[0] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, bdiag_bits
, bdiag_width
, bdiag_height
);
1671 hatch_bitmap
[1] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, cdiag_bits
, cdiag_width
, cdiag_height
);
1672 hatch_bitmap
[2] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, fdiag_bits
, fdiag_width
, fdiag_height
);
1673 hatch_bitmap
[3] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, cross_bits
, cross_width
, cross_height
);
1674 hatch_bitmap
[4] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, horiz_bits
, horiz_width
, horiz_height
);
1675 hatch_bitmap
[5] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, verti_bits
, verti_width
, verti_height
);
1679 void wxWindowDC::Destroy()
1681 if (m_penGC
) wxFreePoolGC( m_penGC
);
1682 m_penGC
= (GdkGC
*) NULL
;
1683 if (m_brushGC
) wxFreePoolGC( m_brushGC
);
1684 m_brushGC
= (GdkGC
*) NULL
;
1685 if (m_textGC
) wxFreePoolGC( m_textGC
);
1686 m_textGC
= (GdkGC
*) NULL
;
1687 if (m_bgGC
) wxFreePoolGC( m_bgGC
);
1688 m_bgGC
= (GdkGC
*) NULL
;
1691 void wxWindowDC::ComputeScaleAndOrigin()
1693 /* CMB: copy scale to see if it changes */
1694 double origScaleX
= m_scaleX
;
1695 double origScaleY
= m_scaleY
;
1697 wxDC::ComputeScaleAndOrigin();
1699 /* CMB: if scale has changed call SetPen to recalulate the line width */
1700 if ((m_scaleX
!= origScaleX
|| m_scaleY
!= origScaleY
) &&
1703 /* this is a bit artificial, but we need to force wxDC to think
1704 the pen has changed */
1711 // Resolution in pixels per logical inch
1712 wxSize
wxWindowDC::GetPPI() const
1714 return wxSize(100, 100);
1717 int wxWindowDC::GetDepth() const
1719 wxFAIL_MSG(wxT("not implemented"));
1725 // ----------------------------------- spline code ----------------------------------------
1727 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
1728 double a3
, double b3
, double a4
, double b4
);
1729 void wx_clear_stack();
1730 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
1731 double *y3
, double *x4
, double *y4
);
1732 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
1733 double x4
, double y4
);
1734 static bool wx_spline_add_point(double x
, double y
);
1735 static void wx_spline_draw_point_array(wxDC
*dc
);
1737 wxList wx_spline_point_list
;
1739 #define half(z1, z2) ((z1+z2)/2.0)
1742 /* iterative version */
1744 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
1747 register double xmid
, ymid
;
1748 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1751 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
1753 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
1754 xmid
= (double)half(x2
, x3
);
1755 ymid
= (double)half(y2
, y3
);
1756 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
1757 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
1758 wx_spline_add_point( x1
, y1
);
1759 wx_spline_add_point( xmid
, ymid
);
1761 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
1762 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
1763 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
1764 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
1769 /* utilities used by spline drawing routines */
1771 typedef struct wx_spline_stack_struct
{
1772 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1775 #define SPLINE_STACK_DEPTH 20
1776 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
1777 static Stack
*wx_stack_top
;
1778 static int wx_stack_count
;
1780 void wx_clear_stack()
1782 wx_stack_top
= wx_spline_stack
;
1786 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
1788 wx_stack_top
->x1
= x1
;
1789 wx_stack_top
->y1
= y1
;
1790 wx_stack_top
->x2
= x2
;
1791 wx_stack_top
->y2
= y2
;
1792 wx_stack_top
->x3
= x3
;
1793 wx_stack_top
->y3
= y3
;
1794 wx_stack_top
->x4
= x4
;
1795 wx_stack_top
->y4
= y4
;
1800 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
1801 double *x3
, double *y3
, double *x4
, double *y4
)
1803 if (wx_stack_count
== 0)
1807 *x1
= wx_stack_top
->x1
;
1808 *y1
= wx_stack_top
->y1
;
1809 *x2
= wx_stack_top
->x2
;
1810 *y2
= wx_stack_top
->y2
;
1811 *x3
= wx_stack_top
->x3
;
1812 *y3
= wx_stack_top
->y3
;
1813 *x4
= wx_stack_top
->x4
;
1814 *y4
= wx_stack_top
->y4
;
1818 static bool wx_spline_add_point(double x
, double y
)
1820 wxPoint
*point
= new wxPoint
;
1823 wx_spline_point_list
.Append((wxObject
*)point
);
1827 static void wx_spline_draw_point_array(wxDC
*dc
)
1829 dc
->DrawLines(&wx_spline_point_list
, 0, 0 );
1830 wxNode
*node
= wx_spline_point_list
.First();
1833 wxPoint
*point
= (wxPoint
*)node
->Data();
1836 node
= wx_spline_point_list
.First();
1840 void wxWindowDC::DoDrawSpline( wxList
*points
)
1842 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1845 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
1846 double x1
, y1
, x2
, y2
;
1848 wxNode
*node
= points
->First();
1849 p
= (wxPoint
*)node
->Data();
1854 node
= node
->Next();
1855 p
= (wxPoint
*)node
->Data();
1859 cx1
= (double)((x1
+ x2
) / 2);
1860 cy1
= (double)((y1
+ y2
) / 2);
1861 cx2
= (double)((cx1
+ x2
) / 2);
1862 cy2
= (double)((cy1
+ y2
) / 2);
1864 wx_spline_add_point(x1
, y1
);
1866 while ((node
= node
->Next()) != NULL
)
1868 p
= (wxPoint
*)node
->Data();
1873 cx4
= (double)(x1
+ x2
) / 2;
1874 cy4
= (double)(y1
+ y2
) / 2;
1875 cx3
= (double)(x1
+ cx4
) / 2;
1876 cy3
= (double)(y1
+ cy4
) / 2;
1878 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
1882 cx2
= (double)(cx1
+ x2
) / 2;
1883 cy2
= (double)(cy1
+ y2
) / 2;
1886 wx_spline_add_point( cx1
, cy1
);
1887 wx_spline_add_point( x2
, y2
);
1889 wx_spline_draw_point_array( this );
1892 #endif // wxUSE_SPLINE
1894 //-----------------------------------------------------------------------------
1896 //-----------------------------------------------------------------------------
1898 IMPLEMENT_DYNAMIC_CLASS(wxPaintDC
,wxWindowDC
)
1900 wxPaintDC::wxPaintDC()
1905 wxPaintDC::wxPaintDC( wxWindow
*win
)
1908 if (!win
->GetUpdateRegion().IsEmpty())
1910 m_paintClippingRegion
= win
->GetUpdateRegion();
1911 m_currentClippingRegion
.Union( m_paintClippingRegion
);
1913 gdk_gc_set_clip_region( m_penGC
, m_paintClippingRegion
.GetRegion() );
1914 gdk_gc_set_clip_region( m_brushGC
, m_paintClippingRegion
.GetRegion() );
1915 gdk_gc_set_clip_region( m_textGC
, m_paintClippingRegion
.GetRegion() );
1916 gdk_gc_set_clip_region( m_bgGC
, m_paintClippingRegion
.GetRegion() );
1920 //-----------------------------------------------------------------------------
1922 //-----------------------------------------------------------------------------
1924 IMPLEMENT_DYNAMIC_CLASS(wxClientDC
,wxWindowDC
)
1926 wxClientDC::wxClientDC()
1931 wxClientDC::wxClientDC( wxWindow
*win
)
1936 // ----------------------------------------------------------------------------
1938 // ----------------------------------------------------------------------------
1940 class wxDCModule
: public wxModule
1947 DECLARE_DYNAMIC_CLASS(wxDCModule
)
1950 IMPLEMENT_DYNAMIC_CLASS(wxDCModule
, wxModule
)
1952 bool wxDCModule::OnInit()
1958 void wxDCModule::OnExit()