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
25 #include <gdk/gdkprivate.h>
28 //-----------------------------------------------------------------------------
30 //-----------------------------------------------------------------------------
32 #define USE_PAINT_REGION 1
34 //-----------------------------------------------------------------------------
36 //-----------------------------------------------------------------------------
46 #define IS_15_PIX_HATCH(s) ((s)==wxCROSSDIAG_HATCH || (s)==wxHORIZONTAL_HATCH || (s)==wxVERTICAL_HATCH)
47 #define IS_16_PIX_HATCH(s) ((s)!=wxCROSSDIAG_HATCH && (s)!=wxHORIZONTAL_HATCH && (s)!=wxVERTICAL_HATCH)
50 static GdkPixmap
*hatches
[num_hatches
];
51 static GdkPixmap
**hatch_bitmap
= (GdkPixmap
**) NULL
;
53 extern GtkWidget
*wxRootWindow
;
55 //-----------------------------------------------------------------------------
57 //-----------------------------------------------------------------------------
59 const double RAD2DEG
= 180.0 / M_PI
;
61 // ----------------------------------------------------------------------------
63 // ----------------------------------------------------------------------------
65 static inline double dmax(double a
, double b
) { return a
> b
? a
: b
; }
66 static inline double dmin(double a
, double b
) { return a
< b
? a
: b
; }
68 static inline double DegToRad(double deg
) { return (deg
* M_PI
) / 180.0; }
70 //-----------------------------------------------------------------------------
71 // temporary implementation of the missing GDK function
72 //-----------------------------------------------------------------------------
74 #include "gdk/gdkprivate.h"
76 void gdk_wx_draw_bitmap (GdkDrawable
*drawable
,
86 gint src_width
, src_height
;
88 GdkWindowPrivate
*drawable_private
;
89 GdkWindowPrivate
*src_private
;
90 GdkGCPrivate
*gc_private
;
93 g_return_if_fail (drawable
!= NULL
);
94 g_return_if_fail (src
!= NULL
);
95 g_return_if_fail (gc
!= NULL
);
98 if (GDK_WINDOW_DESTROYED(drawable
) || GDK_WINDOW_DESTROYED(src
))
101 gdk_drawable_get_size(src
, &src_width
, &src_height
);
103 drawable_private
= (GdkWindowPrivate
*) drawable
;
104 src_private
= (GdkWindowPrivate
*) src
;
105 if (drawable_private
->destroyed
|| src_private
->destroyed
)
108 src_width
= src_private
->width
;
109 src_height
= src_private
->height
;
111 gc_private
= (GdkGCPrivate
*) gc
;
114 if (width
== -1) width
= src_width
;
115 if (height
== -1) height
= src_height
;
118 XCopyPlane( GDK_WINDOW_XDISPLAY(drawable
),
120 GDK_WINDOW_XID(drawable
),
127 XCopyPlane( drawable_private
->xdisplay
,
128 src_private
->xwindow
,
129 drawable_private
->xwindow
,
138 //-----------------------------------------------------------------------------
139 // Implement Pool of Graphic contexts. Creating them takes too much time.
140 //-----------------------------------------------------------------------------
142 #define GC_POOL_SIZE 200
168 static wxGC wxGCPool
[GC_POOL_SIZE
];
170 static void wxInitGCPool()
172 memset( wxGCPool
, 0, GC_POOL_SIZE
*sizeof(wxGC
) );
175 static void wxCleanUpGCPool()
177 for (int i
= 0; i
< GC_POOL_SIZE
; i
++)
179 if (wxGCPool
[i
].m_gc
)
180 gdk_gc_unref( wxGCPool
[i
].m_gc
);
184 static GdkGC
* wxGetPoolGC( GdkWindow
*window
, wxPoolGCType type
)
186 for (int i
= 0; i
< GC_POOL_SIZE
; i
++)
188 if (!wxGCPool
[i
].m_gc
)
190 wxGCPool
[i
].m_gc
= gdk_gc_new( window
);
191 gdk_gc_set_exposures( wxGCPool
[i
].m_gc
, FALSE
);
192 wxGCPool
[i
].m_type
= type
;
193 wxGCPool
[i
].m_used
= FALSE
;
195 if ((!wxGCPool
[i
].m_used
) && (wxGCPool
[i
].m_type
== type
))
197 wxGCPool
[i
].m_used
= TRUE
;
198 return wxGCPool
[i
].m_gc
;
202 wxFAIL_MSG( wxT("No GC available") );
204 return (GdkGC
*) NULL
;
207 static void wxFreePoolGC( GdkGC
*gc
)
209 for (int i
= 0; i
< GC_POOL_SIZE
; i
++)
211 if (wxGCPool
[i
].m_gc
== gc
)
213 wxGCPool
[i
].m_used
= FALSE
;
218 wxFAIL_MSG( wxT("Wrong GC") );
221 //-----------------------------------------------------------------------------
223 //-----------------------------------------------------------------------------
225 IMPLEMENT_DYNAMIC_CLASS(wxWindowDC
, wxDC
)
227 wxWindowDC::wxWindowDC()
229 m_penGC
= (GdkGC
*) NULL
;
230 m_brushGC
= (GdkGC
*) NULL
;
231 m_textGC
= (GdkGC
*) NULL
;
232 m_bgGC
= (GdkGC
*) NULL
;
233 m_cmap
= (GdkColormap
*) NULL
;
235 m_isScreenDC
= FALSE
;
236 m_owner
= (wxWindow
*)NULL
;
238 m_context
= (PangoContext
*)NULL
;
239 m_fontdesc
= (PangoFontDescription
*)NULL
;
243 wxWindowDC::wxWindowDC( wxWindow
*window
)
245 m_penGC
= (GdkGC
*) NULL
;
246 m_brushGC
= (GdkGC
*) NULL
;
247 m_textGC
= (GdkGC
*) NULL
;
248 m_bgGC
= (GdkGC
*) NULL
;
249 m_cmap
= (GdkColormap
*) NULL
;
250 m_owner
= (wxWindow
*)NULL
;
252 m_isScreenDC
= FALSE
;
253 m_font
= window
->GetFont();
255 wxASSERT_MSG( window
, wxT("DC needs a window") );
257 GtkWidget
*widget
= window
->m_wxwindow
;
259 // some controls don't have m_wxwindow - like wxStaticBox, but the user
260 // code should still be able to create wxClientDCs for them, so we will
261 // use the parent window here then
264 window
= window
->GetParent();
265 widget
= window
->m_wxwindow
;
268 wxASSERT_MSG( widget
, wxT("DC needs a widget") );
271 m_context
= gtk_widget_get_pango_context( widget
);
272 m_fontdesc
= widget
->style
->font_desc
;
275 GtkPizza
*pizza
= GTK_PIZZA( widget
);
276 m_window
= pizza
->bin_window
;
281 /* don't report problems */
287 m_cmap
= gtk_widget_get_colormap( widget
? widget
: window
->m_widget
);
291 /* this must be done after SetUpDC, bacause SetUpDC calls the
292 repective SetBrush, SetPen, SetBackground etc functions
293 to set up the DC. SetBackground call m_owner->SetBackground
294 and this might not be desired as the standard dc background
295 is white whereas a window might assume gray to be the
296 standard (as e.g. wxStatusBar) */
301 wxWindowDC::~wxWindowDC()
306 void wxWindowDC::SetUpDC()
310 wxASSERT_MSG( !m_penGC
, wxT("GCs already created") );
314 m_penGC
= wxGetPoolGC( m_window
, wxPEN_SCREEN
);
315 m_brushGC
= wxGetPoolGC( m_window
, wxBRUSH_SCREEN
);
316 m_textGC
= wxGetPoolGC( m_window
, wxTEXT_SCREEN
);
317 m_bgGC
= wxGetPoolGC( m_window
, wxBG_SCREEN
);
320 if (m_isMemDC
&& (((wxMemoryDC
*)this)->m_selected
.GetDepth() == 1))
322 m_penGC
= wxGetPoolGC( m_window
, wxPEN_MONO
);
323 m_brushGC
= wxGetPoolGC( m_window
, wxBRUSH_MONO
);
324 m_textGC
= wxGetPoolGC( m_window
, wxTEXT_MONO
);
325 m_bgGC
= wxGetPoolGC( m_window
, wxBG_MONO
);
329 m_penGC
= wxGetPoolGC( m_window
, wxPEN_COLOUR
);
330 m_brushGC
= wxGetPoolGC( m_window
, wxBRUSH_COLOUR
);
331 m_textGC
= wxGetPoolGC( m_window
, wxTEXT_COLOUR
);
332 m_bgGC
= wxGetPoolGC( m_window
, wxBG_COLOUR
);
335 /* background colour */
336 m_backgroundBrush
= *wxWHITE_BRUSH
;
337 m_backgroundBrush
.GetColour().CalcPixel( m_cmap
);
338 GdkColor
*bg_col
= m_backgroundBrush
.GetColour().GetColor();
341 m_textForegroundColour
.CalcPixel( m_cmap
);
342 gdk_gc_set_foreground( m_textGC
, m_textForegroundColour
.GetColor() );
344 m_textBackgroundColour
.CalcPixel( m_cmap
);
345 gdk_gc_set_background( m_textGC
, m_textBackgroundColour
.GetColor() );
347 gdk_gc_set_fill( m_textGC
, GDK_SOLID
);
350 m_pen
.GetColour().CalcPixel( m_cmap
);
351 gdk_gc_set_foreground( m_penGC
, m_pen
.GetColour().GetColor() );
352 gdk_gc_set_background( m_penGC
, bg_col
);
354 gdk_gc_set_line_attributes( m_penGC
, 0, GDK_LINE_SOLID
, GDK_CAP_NOT_LAST
, GDK_JOIN_ROUND
);
357 m_brush
.GetColour().CalcPixel( m_cmap
);
358 gdk_gc_set_foreground( m_brushGC
, m_brush
.GetColour().GetColor() );
359 gdk_gc_set_background( m_brushGC
, bg_col
);
361 gdk_gc_set_fill( m_brushGC
, GDK_SOLID
);
364 gdk_gc_set_background( m_bgGC
, bg_col
);
365 gdk_gc_set_foreground( m_bgGC
, bg_col
);
367 gdk_gc_set_fill( m_bgGC
, GDK_SOLID
);
370 gdk_gc_set_function( m_textGC
, GDK_COPY
);
371 gdk_gc_set_function( m_brushGC
, GDK_COPY
);
372 gdk_gc_set_function( m_penGC
, GDK_COPY
);
375 gdk_gc_set_clip_rectangle( m_penGC
, (GdkRectangle
*) NULL
);
376 gdk_gc_set_clip_rectangle( m_brushGC
, (GdkRectangle
*) NULL
);
377 gdk_gc_set_clip_rectangle( m_textGC
, (GdkRectangle
*) NULL
);
378 gdk_gc_set_clip_rectangle( m_bgGC
, (GdkRectangle
*) NULL
);
382 hatch_bitmap
= hatches
;
383 hatch_bitmap
[0] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, bdiag_bits
, bdiag_width
, bdiag_height
);
384 hatch_bitmap
[1] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, cdiag_bits
, cdiag_width
, cdiag_height
);
385 hatch_bitmap
[2] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, fdiag_bits
, fdiag_width
, fdiag_height
);
386 hatch_bitmap
[3] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, cross_bits
, cross_width
, cross_height
);
387 hatch_bitmap
[4] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, horiz_bits
, horiz_width
, horiz_height
);
388 hatch_bitmap
[5] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, verti_bits
, verti_width
, verti_height
);
392 void wxWindowDC::DoFloodFill( wxCoord
WXUNUSED(x
), wxCoord
WXUNUSED(y
),
393 const wxColour
&WXUNUSED(col
), int WXUNUSED(style
) )
395 wxFAIL_MSG( wxT("wxWindowDC::DoFloodFill not implemented") );
398 bool wxWindowDC::DoGetPixel( wxCoord x1
, wxCoord y1
, wxColour
*col
) const
400 // Generic (and therefore rather inefficient) method.
401 // Could be improved.
403 wxBitmap
bitmap(1, 1);
404 memdc
.SelectObject(bitmap
);
405 memdc
.Blit(0, 0, 1, 1, (wxDC
*) this, x1
, y1
);
406 memdc
.SelectObject(wxNullBitmap
);
407 wxImage
image(bitmap
);
408 col
->Set(image
.GetRed(0, 0), image
.GetGreen(0, 0), image
.GetBlue(0, 0));
412 void wxWindowDC::DoDrawLine( wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
414 wxCHECK_RET( Ok(), wxT("invalid window dc") );
416 if (m_pen
.GetStyle() != wxTRANSPARENT
)
419 gdk_draw_line( m_window
, m_penGC
, XLOG2DEV(x1
), YLOG2DEV(y1
), XLOG2DEV(x2
), YLOG2DEV(y2
) );
421 CalcBoundingBox(x1
, y1
);
422 CalcBoundingBox(x2
, y2
);
426 void wxWindowDC::DoCrossHair( wxCoord x
, wxCoord y
)
428 wxCHECK_RET( Ok(), wxT("invalid window dc") );
430 if (m_pen
.GetStyle() != wxTRANSPARENT
)
435 wxCoord xx
= XLOG2DEV(x
);
436 wxCoord yy
= YLOG2DEV(y
);
439 gdk_draw_line( m_window
, m_penGC
, 0, yy
, XLOG2DEVREL(w
), yy
);
440 gdk_draw_line( m_window
, m_penGC
, xx
, 0, xx
, YLOG2DEVREL(h
) );
445 void wxWindowDC::DoDrawArc( wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
,
446 wxCoord xc
, wxCoord yc
)
448 wxCHECK_RET( Ok(), wxT("invalid window dc") );
450 wxCoord xx1
= XLOG2DEV(x1
);
451 wxCoord yy1
= YLOG2DEV(y1
);
452 wxCoord xx2
= XLOG2DEV(x2
);
453 wxCoord yy2
= YLOG2DEV(y2
);
454 wxCoord xxc
= XLOG2DEV(xc
);
455 wxCoord yyc
= YLOG2DEV(yc
);
456 double dx
= xx1
- xxc
;
457 double dy
= yy1
- yyc
;
458 double radius
= sqrt((double)(dx
*dx
+dy
*dy
));
459 wxCoord r
= (wxCoord
)radius
;
460 double radius1
, radius2
;
462 if (xx1
== xx2
&& yy1
== yy2
)
470 radius1
= radius2
= 0.0;
474 radius1
= (xx1
- xxc
== 0) ?
475 (yy1
- yyc
< 0) ? 90.0 : -90.0 :
476 -atan2(double(yy1
-yyc
), double(xx1
-xxc
)) * RAD2DEG
;
477 radius2
= (xx2
- xxc
== 0) ?
478 (yy2
- yyc
< 0) ? 90.0 : -90.0 :
479 -atan2(double(yy2
-yyc
), double(xx2
-xxc
)) * RAD2DEG
;
481 wxCoord alpha1
= wxCoord(radius1
* 64.0);
482 wxCoord alpha2
= wxCoord((radius2
- radius1
) * 64.0);
483 while (alpha2
<= 0) alpha2
+= 360*64;
484 while (alpha1
> 360*64) alpha1
-= 360*64;
488 if (m_brush
.GetStyle() != wxTRANSPARENT
)
490 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
492 gdk_gc_set_ts_origin( m_textGC
,
493 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
494 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
495 gdk_draw_arc( m_window
, m_textGC
, TRUE
, xxc
-r
, yyc
-r
, 2*r
,2*r
, alpha1
, alpha2
);
496 gdk_gc_set_ts_origin( m_textGC
, 0, 0 );
498 if (IS_15_PIX_HATCH(m_brush
.GetStyle()))
500 gdk_gc_set_ts_origin( m_brushGC
, m_deviceOriginX
% 15, m_deviceOriginY
% 15 );
501 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xxc
-r
, yyc
-r
, 2*r
,2*r
, alpha1
, alpha2
);
502 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
504 if (IS_16_PIX_HATCH(m_brush
.GetStyle()))
506 gdk_gc_set_ts_origin( m_brushGC
, m_deviceOriginX
% 16, m_deviceOriginY
% 16 );
507 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xxc
-r
, yyc
-r
, 2*r
,2*r
, alpha1
, alpha2
);
508 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
510 if (m_brush
.GetStyle() == wxSTIPPLE
)
512 gdk_gc_set_ts_origin( m_brushGC
,
513 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
514 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
515 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xxc
-r
, yyc
-r
, 2*r
,2*r
, alpha1
, alpha2
);
516 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
520 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xxc
-r
, yyc
-r
, 2*r
,2*r
, alpha1
, alpha2
);
524 if (m_pen
.GetStyle() != wxTRANSPARENT
)
525 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xxc
-r
, yyc
-r
, 2*r
,2*r
, alpha1
, alpha2
);
528 CalcBoundingBox (x1
, y1
);
529 CalcBoundingBox (x2
, y2
);
532 void wxWindowDC::DoDrawEllipticArc( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double sa
, double ea
)
534 wxCHECK_RET( Ok(), wxT("invalid window dc") );
536 wxCoord xx
= XLOG2DEV(x
);
537 wxCoord yy
= YLOG2DEV(y
);
538 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
539 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
541 // CMB: handle -ve width and/or height
542 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
543 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
547 wxCoord start
= wxCoord(sa
* 64.0);
548 wxCoord end
= wxCoord(ea
* 64.0);
550 if (m_brush
.GetStyle() != wxTRANSPARENT
)
552 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
554 gdk_gc_set_ts_origin( m_textGC
,
555 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
556 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
557 gdk_draw_arc( m_window
, m_textGC
, TRUE
, xx
, yy
, ww
, hh
, start
, end
);
558 gdk_gc_set_ts_origin( m_textGC
, 0, 0 );
560 if (IS_15_PIX_HATCH(m_brush
.GetStyle()))
562 gdk_gc_set_ts_origin( m_brushGC
, m_deviceOriginX
% 15, m_deviceOriginY
% 15 );
563 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, start
, end
);
564 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
566 if (IS_16_PIX_HATCH(m_brush
.GetStyle()))
568 gdk_gc_set_ts_origin( m_brushGC
, m_deviceOriginX
% 16, m_deviceOriginY
% 16 );
569 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, start
, end
);
570 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
572 if (m_brush
.GetStyle() == wxSTIPPLE
)
574 gdk_gc_set_ts_origin( m_brushGC
,
575 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
576 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
577 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, start
, end
);
578 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
582 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, start
, end
);
586 if (m_pen
.GetStyle() != wxTRANSPARENT
)
587 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
, hh
, start
, end
);
590 CalcBoundingBox (x
, y
);
591 CalcBoundingBox (x
+ width
, y
+ height
);
594 void wxWindowDC::DoDrawPoint( wxCoord x
, wxCoord y
)
596 wxCHECK_RET( Ok(), wxT("invalid window dc") );
598 if ((m_pen
.GetStyle() != wxTRANSPARENT
) && m_window
)
599 gdk_draw_point( m_window
, m_penGC
, XLOG2DEV(x
), YLOG2DEV(y
) );
601 CalcBoundingBox (x
, y
);
604 void wxWindowDC::DoDrawLines( int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
606 wxCHECK_RET( Ok(), wxT("invalid window dc") );
608 if (m_pen
.GetStyle() == wxTRANSPARENT
) return;
611 CalcBoundingBox( points
[0].x
+ xoffset
, points
[0].y
+ yoffset
);
613 for (int i
= 0; i
< n
-1; i
++)
615 wxCoord x1
= XLOG2DEV(points
[i
].x
+ xoffset
);
616 wxCoord x2
= XLOG2DEV(points
[i
+1].x
+ xoffset
);
617 wxCoord y1
= YLOG2DEV(points
[i
].y
+ yoffset
); // oh, what a waste
618 wxCoord y2
= YLOG2DEV(points
[i
+1].y
+ yoffset
);
621 gdk_draw_line( m_window
, m_penGC
, x1
, y1
, x2
, y2
);
623 CalcBoundingBox( points
[i
+1].x
+ xoffset
, points
[i
+1].y
+ yoffset
);
627 void wxWindowDC::DoDrawPolygon( int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
, int WXUNUSED(fillStyle
) )
629 wxCHECK_RET( Ok(), wxT("invalid window dc") );
633 GdkPoint
*gdkpoints
= new GdkPoint
[n
+1];
635 for (i
= 0 ; i
< n
; i
++)
637 gdkpoints
[i
].x
= XLOG2DEV(points
[i
].x
+ xoffset
);
638 gdkpoints
[i
].y
= YLOG2DEV(points
[i
].y
+ yoffset
);
640 CalcBoundingBox( points
[i
].x
+ xoffset
, points
[i
].y
+ yoffset
);
645 if (m_brush
.GetStyle() != wxTRANSPARENT
)
647 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
649 gdk_gc_set_ts_origin( m_textGC
,
650 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
651 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
652 gdk_draw_polygon( m_window
, m_textGC
, TRUE
, gdkpoints
, n
);
653 gdk_gc_set_ts_origin( m_textGC
, 0, 0 );
655 if (IS_15_PIX_HATCH(m_brush
.GetStyle()))
657 gdk_gc_set_ts_origin( m_brushGC
, m_deviceOriginX
% 15, m_deviceOriginY
% 15 );
658 gdk_draw_polygon( m_window
, m_brushGC
, TRUE
, gdkpoints
, n
);
659 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
661 if (IS_16_PIX_HATCH(m_brush
.GetStyle()))
663 gdk_gc_set_ts_origin( m_brushGC
, m_deviceOriginX
% 16, m_deviceOriginY
% 16 );
664 gdk_draw_polygon( m_window
, m_brushGC
, TRUE
, gdkpoints
, n
);
665 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
667 if (m_brush
.GetStyle() == wxSTIPPLE
)
669 gdk_gc_set_ts_origin( m_brushGC
,
670 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
671 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
672 gdk_draw_polygon( m_window
, m_brushGC
, TRUE
, gdkpoints
, n
);
673 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
677 gdk_draw_polygon( m_window
, m_brushGC
, TRUE
, gdkpoints
, n
);
681 if (m_pen
.GetStyle() != wxTRANSPARENT
)
683 for (i
= 0 ; i
< n
; i
++)
685 gdk_draw_line( m_window
, m_penGC
,
688 gdkpoints
[(i
+1)%n
].x
,
689 gdkpoints
[(i
+1)%n
].y
);
697 void wxWindowDC::DoDrawRectangle( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
699 wxCHECK_RET( Ok(), wxT("invalid window dc") );
701 wxCoord xx
= XLOG2DEV(x
);
702 wxCoord yy
= YLOG2DEV(y
);
703 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
704 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
706 // CMB: draw nothing if transformed w or h is 0
707 if (ww
== 0 || hh
== 0) return;
709 // CMB: handle -ve width and/or height
710 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
711 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
715 if (m_brush
.GetStyle() != wxTRANSPARENT
)
717 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
719 gdk_gc_set_ts_origin( m_textGC
,
720 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
721 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
722 gdk_draw_rectangle( m_window
, m_textGC
, TRUE
, xx
, yy
, ww
, hh
);
723 gdk_gc_set_ts_origin( m_textGC
, 0, 0 );
725 if (IS_15_PIX_HATCH(m_brush
.GetStyle()))
727 gdk_gc_set_ts_origin( m_brushGC
, m_deviceOriginX
% 15, m_deviceOriginY
% 15 );
728 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
);
729 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
731 if (IS_16_PIX_HATCH(m_brush
.GetStyle()))
733 gdk_gc_set_ts_origin( m_brushGC
, m_deviceOriginX
% 16, m_deviceOriginY
% 16 );
734 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
);
735 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
737 if (m_brush
.GetStyle() == wxSTIPPLE
)
739 gdk_gc_set_ts_origin( m_brushGC
,
740 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
741 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
742 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
);
743 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
747 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
);
751 if (m_pen
.GetStyle() != wxTRANSPARENT
)
752 gdk_draw_rectangle( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
-1, hh
-1 );
755 CalcBoundingBox( x
, y
);
756 CalcBoundingBox( x
+ width
, y
+ height
);
759 void wxWindowDC::DoDrawRoundedRectangle( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
761 wxCHECK_RET( Ok(), wxT("invalid window dc") );
763 if (radius
< 0.0) radius
= - radius
* ((width
< height
) ? width
: height
);
765 wxCoord xx
= XLOG2DEV(x
);
766 wxCoord yy
= YLOG2DEV(y
);
767 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
768 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
769 wxCoord rr
= XLOG2DEVREL((wxCoord
)radius
);
771 // CMB: handle -ve width and/or height
772 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
773 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
775 // CMB: if radius is zero use DrawRectangle() instead to avoid
776 // X drawing errors with small radii
779 DrawRectangle( x
, y
, width
, height
);
783 // CMB: draw nothing if transformed w or h is 0
784 if (ww
== 0 || hh
== 0) return;
786 // CMB: adjust size if outline is drawn otherwise the result is
787 // 1 pixel too wide and high
788 if (m_pen
.GetStyle() != wxTRANSPARENT
)
796 // CMB: ensure dd is not larger than rectangle otherwise we
797 // get an hour glass shape
799 if (dd
> ww
) dd
= ww
;
800 if (dd
> hh
) dd
= hh
;
803 if (m_brush
.GetStyle() != wxTRANSPARENT
)
805 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
807 gdk_gc_set_ts_origin( m_textGC
,
808 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
809 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
810 gdk_draw_rectangle( m_window
, m_textGC
, TRUE
, xx
+rr
, yy
, ww
-dd
+1, hh
);
811 gdk_draw_rectangle( m_window
, m_textGC
, TRUE
, xx
, yy
+rr
, ww
, hh
-dd
+1 );
812 gdk_draw_arc( m_window
, m_textGC
, TRUE
, xx
, yy
, dd
, dd
, 90*64, 90*64 );
813 gdk_draw_arc( m_window
, m_textGC
, TRUE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 );
814 gdk_draw_arc( m_window
, m_textGC
, TRUE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 );
815 gdk_draw_arc( m_window
, m_textGC
, TRUE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 );
816 gdk_gc_set_ts_origin( m_textGC
, 0, 0 );
818 if (IS_15_PIX_HATCH(m_brush
.GetStyle()))
820 gdk_gc_set_ts_origin( m_brushGC
, m_deviceOriginX
% 15, m_deviceOriginY
% 15 );
821 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
+rr
, yy
, ww
-dd
+1, hh
);
822 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
+rr
, ww
, hh
-dd
+1 );
823 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, dd
, dd
, 90*64, 90*64 );
824 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 );
825 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 );
826 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 );
827 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
829 if (IS_16_PIX_HATCH(m_brush
.GetStyle()))
831 gdk_gc_set_ts_origin( m_brushGC
, m_deviceOriginX
% 16, m_deviceOriginY
% 16 );
832 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
+rr
, yy
, ww
-dd
+1, hh
);
833 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
+rr
, ww
, hh
-dd
+1 );
834 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, dd
, dd
, 90*64, 90*64 );
835 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 );
836 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 );
837 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 );
838 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
840 if (m_brush
.GetStyle() == wxSTIPPLE
)
842 gdk_gc_set_ts_origin( m_brushGC
,
843 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
844 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
845 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
+rr
, yy
, ww
-dd
+1, hh
);
846 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
+rr
, ww
, hh
-dd
+1 );
847 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, dd
, dd
, 90*64, 90*64 );
848 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 );
849 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 );
850 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 );
851 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
855 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
+rr
, yy
, ww
-dd
+1, hh
);
856 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
+rr
, ww
, hh
-dd
+1 );
857 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, dd
, dd
, 90*64, 90*64 );
858 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 );
859 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 );
860 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 );
864 if (m_pen
.GetStyle() != wxTRANSPARENT
)
866 gdk_draw_line( m_window
, m_penGC
, xx
+rr
+1, yy
, xx
+ww
-rr
, yy
);
867 gdk_draw_line( m_window
, m_penGC
, xx
+rr
+1, yy
+hh
, xx
+ww
-rr
, yy
+hh
);
868 gdk_draw_line( m_window
, m_penGC
, xx
, yy
+rr
+1, xx
, yy
+hh
-rr
);
869 gdk_draw_line( m_window
, m_penGC
, xx
+ww
, yy
+rr
+1, xx
+ww
, yy
+hh
-rr
);
870 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
, dd
, dd
, 90*64, 90*64 );
871 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 );
872 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 );
873 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 );
877 // this ignores the radius
878 CalcBoundingBox( x
, y
);
879 CalcBoundingBox( x
+ width
, y
+ height
);
882 void wxWindowDC::DoDrawEllipse( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
884 wxCHECK_RET( Ok(), wxT("invalid window dc") );
886 wxCoord xx
= XLOG2DEV(x
);
887 wxCoord yy
= YLOG2DEV(y
);
888 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
889 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
891 // CMB: handle -ve width and/or height
892 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
893 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
897 if (m_brush
.GetStyle() != wxTRANSPARENT
)
899 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
901 gdk_gc_set_ts_origin( m_textGC
,
902 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
903 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
904 gdk_draw_arc( m_window
, m_textGC
, TRUE
, xx
, yy
, ww
, hh
, 0, 360*64 );
905 gdk_gc_set_ts_origin( m_textGC
, 0, 0 );
907 if (IS_15_PIX_HATCH(m_brush
.GetStyle()))
909 gdk_gc_set_ts_origin( m_brushGC
, m_deviceOriginX
% 15, m_deviceOriginY
% 15 );
910 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, 0, 360*64 );
911 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
913 if (IS_16_PIX_HATCH(m_brush
.GetStyle()))
915 gdk_gc_set_ts_origin( m_brushGC
, m_deviceOriginX
% 16, m_deviceOriginY
% 16 );
916 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, 0, 360*64 );
917 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
919 if (m_brush
.GetStyle() == wxSTIPPLE
)
921 gdk_gc_set_ts_origin( m_brushGC
,
922 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
923 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
924 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, 0, 360*64 );
925 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
929 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, 0, 360*64 );
933 if (m_pen
.GetStyle() != wxTRANSPARENT
)
934 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
, hh
, 0, 360*64 );
937 CalcBoundingBox( x
- width
, y
- height
);
938 CalcBoundingBox( x
+ width
, y
+ height
);
941 void wxWindowDC::DoDrawIcon( const wxIcon
&icon
, wxCoord x
, wxCoord y
)
943 // VZ: egcs 1.0.3 refuses to compile this without cast, no idea why
944 DoDrawBitmap( (const wxBitmap
&)icon
, x
, y
, (bool)TRUE
);
947 void wxWindowDC::DoDrawBitmap( const wxBitmap
&bitmap
,
948 wxCoord x
, wxCoord y
,
951 wxCHECK_RET( Ok(), wxT("invalid window dc") );
953 wxCHECK_RET( bitmap
.Ok(), wxT("invalid bitmap") );
955 bool is_mono
= (bitmap
.GetBitmap() != NULL
);
957 /* scale/translate size and position */
958 int xx
= XLOG2DEV(x
);
959 int yy
= YLOG2DEV(y
);
961 int w
= bitmap
.GetWidth();
962 int h
= bitmap
.GetHeight();
964 CalcBoundingBox( x
, y
);
965 CalcBoundingBox( x
+ w
, y
+ h
);
967 if (!m_window
) return;
969 int ww
= XLOG2DEVREL(w
);
970 int hh
= YLOG2DEVREL(h
);
972 /* compare to current clipping region */
973 if (!m_currentClippingRegion
.IsNull())
975 wxRegion
tmp( xx
,yy
,ww
,hh
);
976 tmp
.Intersect( m_currentClippingRegion
);
981 /* scale bitmap if required */
983 if ((w
!= ww
) || (h
!= hh
))
985 wxImage
image( bitmap
);
986 image
.Rescale( ww
, hh
);
988 use_bitmap
= image
.ConvertToMonoBitmap(255,255,255);
990 use_bitmap
= image
.ConvertToBitmap();
997 /* apply mask if any */
998 GdkBitmap
*mask
= (GdkBitmap
*) NULL
;
999 if (use_bitmap
.GetMask()) mask
= use_bitmap
.GetMask()->GetBitmap();
1001 if (useMask
&& mask
)
1003 GdkBitmap
*new_mask
= (GdkBitmap
*) NULL
;
1004 if (!m_currentClippingRegion
.IsNull())
1007 new_mask
= gdk_pixmap_new( wxRootWindow
->window
, ww
, hh
, 1 );
1008 GdkGC
*gc
= gdk_gc_new( new_mask
);
1010 gdk_gc_set_foreground( gc
, &col
);
1011 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, ww
, hh
);
1013 gdk_gc_set_background( gc
, &col
);
1015 gdk_gc_set_foreground( gc
, &col
);
1016 gdk_gc_set_clip_region( gc
, m_currentClippingRegion
.GetRegion() );
1017 gdk_gc_set_clip_origin( gc
, -xx
, -yy
);
1018 gdk_gc_set_fill( gc
, GDK_OPAQUE_STIPPLED
);
1019 gdk_gc_set_stipple( gc
, mask
);
1020 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, ww
, hh
);
1027 gdk_gc_set_clip_mask( m_textGC
, new_mask
);
1029 gdk_gc_set_clip_mask( m_textGC
, mask
);
1030 gdk_gc_set_clip_origin( m_textGC
, xx
, yy
);
1035 gdk_gc_set_clip_mask( m_penGC
, new_mask
);
1037 gdk_gc_set_clip_mask( m_penGC
, mask
);
1038 gdk_gc_set_clip_origin( m_penGC
, xx
, yy
);
1041 gdk_bitmap_unref( new_mask
);
1044 /* Draw XPixmap or XBitmap, depending on what the wxBitmap contains. For
1045 drawing a mono-bitmap (XBitmap) we use the current text GC */
1047 gdk_wx_draw_bitmap( m_window
, m_textGC
, use_bitmap
.GetBitmap(), 0, 0, xx
, yy
, -1, -1 );
1049 gdk_draw_pixmap( m_window
, m_penGC
, use_bitmap
.GetPixmap(), 0, 0, xx
, yy
, -1, -1 );
1051 /* remove mask again if any */
1052 if (useMask
&& mask
)
1056 gdk_gc_set_clip_mask( m_textGC
, (GdkBitmap
*) NULL
);
1057 gdk_gc_set_clip_origin( m_textGC
, 0, 0 );
1058 if (!m_currentClippingRegion
.IsNull())
1059 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
1063 gdk_gc_set_clip_mask( m_penGC
, (GdkBitmap
*) NULL
);
1064 gdk_gc_set_clip_origin( m_penGC
, 0, 0 );
1065 if (!m_currentClippingRegion
.IsNull())
1066 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
1071 bool wxWindowDC::DoBlit( wxCoord xdest
, wxCoord ydest
, wxCoord width
, wxCoord height
,
1072 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
,
1073 int logical_func
, bool useMask
)
1075 /* this is the nth try to get this utterly useless function to
1076 work. it now completely ignores the scaling or translation
1077 of the source dc, but scales correctly on the target dc and
1078 knows about possible mask information in a memory dc. */
1080 wxCHECK_MSG( Ok(), FALSE
, wxT("invalid window dc") );
1082 wxCHECK_MSG( source
, FALSE
, wxT("invalid source dc") );
1084 if (!m_window
) return FALSE
;
1086 wxClientDC
*srcDC
= (wxClientDC
*)source
;
1087 wxMemoryDC
*memDC
= (wxMemoryDC
*)source
;
1089 bool use_bitmap_method
= FALSE
;
1090 bool is_mono
= FALSE
;
1092 if (srcDC
->m_isMemDC
)
1094 if (!memDC
->m_selected
.Ok()) return FALSE
;
1096 /* we use the "XCopyArea" way to copy a memory dc into
1097 y different window if the memory dc BOTH
1098 a) doesn't have any mask or its mask isn't used
1102 if (useMask
&& (memDC
->m_selected
.GetMask()))
1104 /* we HAVE TO use the direct way for memory dcs
1105 that have mask since the XCopyArea doesn't know
1107 use_bitmap_method
= TRUE
;
1109 else if (memDC
->m_selected
.GetDepth() == 1)
1111 /* we HAVE TO use the direct way for memory dcs
1112 that are bitmaps because XCopyArea doesn't cope
1113 with different bit depths */
1115 use_bitmap_method
= TRUE
;
1117 else if ((xsrc
== 0) && (ysrc
== 0) &&
1118 (width
== memDC
->m_selected
.GetWidth()) &&
1119 (height
== memDC
->m_selected
.GetHeight()))
1121 /* we SHOULD use the direct way if all of the bitmap
1122 in the memory dc is copied in which case XCopyArea
1123 wouldn't be able able to boost performace by reducing
1124 the area to be scaled */
1125 use_bitmap_method
= TRUE
;
1129 use_bitmap_method
= FALSE
;
1133 CalcBoundingBox( xdest
, ydest
);
1134 CalcBoundingBox( xdest
+ width
, ydest
+ height
);
1136 /* scale/translate size and position */
1137 wxCoord xx
= XLOG2DEV(xdest
);
1138 wxCoord yy
= YLOG2DEV(ydest
);
1140 wxCoord ww
= XLOG2DEVREL(width
);
1141 wxCoord hh
= YLOG2DEVREL(height
);
1143 /* compare to current clipping region */
1144 if (!m_currentClippingRegion
.IsNull())
1146 wxRegion
tmp( xx
,yy
,ww
,hh
);
1147 tmp
.Intersect( m_currentClippingRegion
);
1152 int old_logical_func
= m_logicalFunction
;
1153 SetLogicalFunction( logical_func
);
1155 if (use_bitmap_method
)
1157 /* scale/translate bitmap size */
1158 wxCoord bm_width
= memDC
->m_selected
.GetWidth();
1159 wxCoord bm_height
= memDC
->m_selected
.GetHeight();
1161 wxCoord bm_ww
= XLOG2DEVREL( bm_width
);
1162 wxCoord bm_hh
= YLOG2DEVREL( bm_height
);
1164 /* scale bitmap if required */
1165 wxBitmap use_bitmap
;
1167 if ((bm_width
!= bm_ww
) || (bm_height
!= bm_hh
))
1169 wxImage
image( memDC
->m_selected
);
1170 image
= image
.Scale( bm_ww
, bm_hh
);
1173 use_bitmap
= image
.ConvertToMonoBitmap(255,255,255);
1175 use_bitmap
= image
.ConvertToBitmap();
1179 use_bitmap
= memDC
->m_selected
;
1182 /* apply mask if any */
1183 GdkBitmap
*mask
= (GdkBitmap
*) NULL
;
1184 if (use_bitmap
.GetMask()) mask
= use_bitmap
.GetMask()->GetBitmap();
1186 if (useMask
&& mask
)
1188 GdkBitmap
*new_mask
= (GdkBitmap
*) NULL
;
1189 if (!m_currentClippingRegion
.IsNull())
1192 new_mask
= gdk_pixmap_new( wxRootWindow
->window
, bm_ww
, bm_hh
, 1 );
1193 GdkGC
*gc
= gdk_gc_new( new_mask
);
1195 gdk_gc_set_foreground( gc
, &col
);
1196 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, bm_ww
, bm_hh
);
1198 gdk_gc_set_background( gc
, &col
);
1200 gdk_gc_set_foreground( gc
, &col
);
1201 gdk_gc_set_clip_region( gc
, m_currentClippingRegion
.GetRegion() );
1202 gdk_gc_set_clip_origin( gc
, -xx
, -yy
);
1203 gdk_gc_set_fill( gc
, GDK_OPAQUE_STIPPLED
);
1204 gdk_gc_set_stipple( gc
, mask
);
1205 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, bm_ww
, bm_hh
);
1212 gdk_gc_set_clip_mask( m_textGC
, new_mask
);
1214 gdk_gc_set_clip_mask( m_textGC
, mask
);
1215 gdk_gc_set_clip_origin( m_textGC
, xx
, yy
);
1220 gdk_gc_set_clip_mask( m_penGC
, new_mask
);
1222 gdk_gc_set_clip_mask( m_penGC
, mask
);
1223 gdk_gc_set_clip_origin( m_penGC
, xx
, yy
);
1226 gdk_bitmap_unref( new_mask
);
1229 /* Draw XPixmap or XBitmap, depending on what the wxBitmap contains. For
1230 drawing a mono-bitmap (XBitmap) we use the current text GC */
1233 gdk_wx_draw_bitmap( m_window
, m_textGC
, use_bitmap
.GetBitmap(), xsrc
, ysrc
, xx
, yy
, ww
, hh
);
1235 gdk_draw_pixmap( m_window
, m_penGC
, use_bitmap
.GetPixmap(), xsrc
, ysrc
, xx
, yy
, ww
, hh
);
1237 /* remove mask again if any */
1238 if (useMask
&& mask
)
1242 gdk_gc_set_clip_mask( m_textGC
, (GdkBitmap
*) NULL
);
1243 gdk_gc_set_clip_origin( m_textGC
, 0, 0 );
1244 if (!m_currentClippingRegion
.IsNull())
1245 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
1249 gdk_gc_set_clip_mask( m_penGC
, (GdkBitmap
*) NULL
);
1250 gdk_gc_set_clip_origin( m_penGC
, 0, 0 );
1251 if (!m_currentClippingRegion
.IsNull())
1252 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
1256 else /* use_bitmap_method */
1258 if ((width
!= ww
) || (height
!= hh
))
1260 /* draw source window into a bitmap as we cannot scale
1261 a window in contrast to a bitmap. this would actually
1262 work with memory dcs as well, but we'd lose the mask
1263 information and waste one step in this process since
1264 a memory already has a bitmap. all this is slightly
1265 inefficient as we could take an XImage directly from
1266 an X window, but we'd then also have to care that
1267 the window is not outside the screen (in which case
1268 we'd get a BadMatch or what not).
1269 Is a double XGetImage and combined XGetPixel and
1270 XPutPixel really faster? I'm not sure. look at wxXt
1271 for a different implementation of the same problem. */
1273 wxBitmap
bitmap( width
, height
);
1275 /* copy including child window contents */
1276 gdk_gc_set_subwindow( m_penGC
, GDK_INCLUDE_INFERIORS
);
1277 gdk_window_copy_area( bitmap
.GetPixmap(), m_penGC
, 0, 0,
1279 xsrc
, ysrc
, width
, height
);
1280 gdk_gc_set_subwindow( m_penGC
, GDK_CLIP_BY_CHILDREN
);
1283 wxImage
image( bitmap
);
1284 image
= image
.Scale( ww
, hh
);
1286 /* convert to bitmap */
1287 bitmap
= image
.ConvertToBitmap();
1289 /* draw scaled bitmap */
1290 gdk_draw_pixmap( m_window
, m_penGC
, bitmap
.GetPixmap(), 0, 0, xx
, yy
, -1, -1 );
1295 /* No scaling and not a memory dc with a mask either */
1297 /* copy including child window contents */
1298 gdk_gc_set_subwindow( m_penGC
, GDK_INCLUDE_INFERIORS
);
1299 gdk_window_copy_area( m_window
, m_penGC
, xx
, yy
,
1301 xsrc
, ysrc
, width
, height
);
1302 gdk_gc_set_subwindow( m_penGC
, GDK_CLIP_BY_CHILDREN
);
1306 SetLogicalFunction( old_logical_func
);
1310 void wxWindowDC::DoDrawText( const wxString
&text
, wxCoord x
, wxCoord y
)
1312 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1314 if (!m_window
) return;
1316 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
1318 wxCHECK_RET( font
, wxT("invalid font") );
1321 wxCHECK_RET( m_context
, wxT("no Pango context") );
1328 /* FIXME: the layout engine should probably be abstracted at a higher level in wxDC... */
1329 PangoLayout
*layout
= pango_layout_new(m_context
);
1330 pango_layout_set_font_description(layout
, m_fontdesc
);
1332 wxWX2MBbuf data
= text
.mb_str(wxConvUTF8
);
1333 pango_layout_set_text(layout
, data
, strlen(data
));
1335 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
1336 PangoRectangle rect
;
1337 pango_layout_line_get_extents(line
, NULL
, &rect
);
1338 wxCoord width
= rect
.width
;
1339 wxCoord height
= rect
.height
;
1340 gdk_draw_layout( m_window
, m_textGC
, x
, y
, layout
);
1342 wxCoord width
= gdk_string_width( font
, text
.mbc_str() );
1343 wxCoord height
= font
->ascent
+ font
->descent
;
1344 /* CMB 21/5/98: draw text background if mode is wxSOLID */
1345 if (m_backgroundMode
== wxSOLID
)
1347 gdk_gc_set_foreground( m_textGC
, m_textBackgroundColour
.GetColor() );
1348 gdk_draw_rectangle( m_window
, m_textGC
, TRUE
, x
, y
, width
, height
);
1349 gdk_gc_set_foreground( m_textGC
, m_textForegroundColour
.GetColor() );
1351 gdk_draw_string( m_window
, font
, m_textGC
, x
, y
+ font
->ascent
, text
.mbc_str() );
1354 /* CMB 17/7/98: simple underline: ignores scaling and underlying
1355 X font's XA_UNDERLINE_POSITION and XA_UNDERLINE_THICKNESS
1356 properties (see wxXt implementation) */
1357 if (m_font
.GetUnderlined())
1359 wxCoord ul_y
= y
+ font
->ascent
;
1360 if (font
->descent
> 0) ul_y
++;
1361 gdk_draw_line( m_window
, m_textGC
, x
, ul_y
, x
+ width
, ul_y
);
1365 g_object_unref( G_OBJECT( layout
) );
1368 width
= wxCoord(width
/ m_scaleX
);
1369 height
= wxCoord(height
/ m_scaleY
);
1370 CalcBoundingBox (x
+ width
, y
+ height
);
1371 CalcBoundingBox (x
, y
);
1374 void wxWindowDC::DoDrawRotatedText( const wxString
&text
, wxCoord x
, wxCoord y
, double angle
)
1378 DrawText(text
, x
, y
);
1382 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1384 if (!m_window
) return;
1386 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
1388 wxCHECK_RET( font
, wxT("invalid font") );
1390 // the size of the text
1391 wxCoord w
= gdk_string_width( font
, text
.mbc_str() );
1392 wxCoord h
= font
->ascent
+ font
->descent
;
1394 // draw the string normally
1397 dc
.SelectObject(src
);
1398 dc
.SetFont(GetFont());
1399 dc
.SetBackground(*wxWHITE_BRUSH
);
1400 dc
.SetBrush(*wxBLACK_BRUSH
);
1402 dc
.DrawText(text
, 0, 0);
1403 dc
.SetFont(wxNullFont
);
1404 dc
.SelectObject(wxNullBitmap
);
1406 // Calculate the size of the rotated bounding box.
1407 double rad
= DegToRad(angle
);
1408 double dx
= cos(rad
),
1411 // the rectngle vertices are counted clockwise with the first one being at
1412 // (0, 0) (or, rather, at (x, y))
1414 y2
= -w
*dy
; // y axis points to the bottom, hence minus
1417 double x3
= x4
+ x2
,
1421 wxCoord maxX
= (wxCoord
)(dmax(x2
, dmax(x3
, x4
)) + 0.5),
1422 maxY
= (wxCoord
)(dmax(y2
, dmax(y3
, y4
)) + 0.5),
1423 minX
= (wxCoord
)(dmin(x2
, dmin(x3
, x4
)) - 0.5),
1424 minY
= (wxCoord
)(dmin(y2
, dmin(y3
, y4
)) - 0.5);
1426 // prepare to blit-with-rotate the bitmap to the DC
1429 GdkColor
*colText
= m_textForegroundColour
.GetColor(),
1430 *colBack
= m_textBackgroundColour
.GetColor();
1432 bool textColSet
= TRUE
;
1434 unsigned char *data
= image
.GetData();
1436 // paint pixel by pixel
1437 for ( wxCoord srcX
= 0; srcX
< w
; srcX
++ )
1439 for ( wxCoord srcY
= 0; srcY
< h
; srcY
++ )
1441 // transform source coords to dest coords
1442 double r
= sqrt((double)srcX
*srcX
+ srcY
*srcY
);
1443 double angleOrig
= atan2((double)srcY
, (double)srcX
) - rad
;
1444 wxCoord dstX
= (wxCoord
)(r
*cos(angleOrig
) + 0.5),
1445 dstY
= (wxCoord
)(r
*sin(angleOrig
) + 0.5);
1448 bool textPixel
= data
[(srcY
*w
+ srcX
)*3] == 0;
1449 if ( textPixel
|| (m_backgroundMode
== wxSOLID
) )
1451 // change colour if needed
1452 if ( textPixel
!= textColSet
)
1454 gdk_gc_set_foreground( m_textGC
, textPixel
? colText
1457 textColSet
= textPixel
;
1460 // don't use DrawPoint() because it uses the current pen
1461 // colour, and we don't need it here
1462 gdk_draw_point( m_window
, m_textGC
,
1463 XLOG2DEV(x
+ dstX
), YLOG2DEV(y
+ dstY
) );
1468 // it would be better to draw with non underlined font and draw the line
1469 // manually here (it would be more straight...)
1471 if ( m_font
.GetUnderlined() )
1473 gdk_draw_line( m_window
, m_textGC
,
1474 XLOG2DEV(x
+ x4
), YLOG2DEV(y
+ y4
+ font
->descent
),
1475 XLOG2DEV(x
+ x3
), YLOG2DEV(y
+ y3
+ font
->descent
));
1479 // restore the font colour
1480 gdk_gc_set_foreground( m_textGC
, colText
);
1482 // update the bounding box
1483 CalcBoundingBox(x
+ minX
, y
+ minY
);
1484 CalcBoundingBox(x
+ maxX
, y
+ maxY
);
1487 void wxWindowDC::DoGetTextExtent(const wxString
&string
,
1488 wxCoord
*width
, wxCoord
*height
,
1489 wxCoord
*descent
, wxCoord
*externalLeading
,
1490 wxFont
*theFont
) const
1492 wxFont fontToUse
= m_font
;
1493 if (theFont
) fontToUse
= *theFont
;
1495 GdkFont
*font
= fontToUse
.GetInternalFont( m_scaleY
);
1496 if (width
) (*width
) = wxCoord(gdk_string_width( font
, string
.mbc_str() ) / m_scaleX
);
1497 if (height
) (*height
) = wxCoord((font
->ascent
+ font
->descent
) / m_scaleY
);
1498 if (descent
) (*descent
) = wxCoord(font
->descent
/ m_scaleY
);
1499 if (externalLeading
) (*externalLeading
) = 0; // ??
1502 wxCoord
wxWindowDC::GetCharWidth() const
1504 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
1505 wxCHECK_MSG( font
, -1, wxT("invalid font") );
1507 return wxCoord(gdk_string_width( font
, "H" ) / m_scaleX
);
1510 wxCoord
wxWindowDC::GetCharHeight() const
1512 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
1513 wxCHECK_MSG( font
, -1, wxT("invalid font") );
1515 return wxCoord((font
->ascent
+ font
->descent
) / m_scaleY
);
1518 void wxWindowDC::Clear()
1520 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1522 if (!m_window
) return;
1524 /* - we either are a memory dc or have a window as the
1525 owner. anything else shouldn't happen.
1526 - we don't use gdk_window_clear() as we don't set
1527 the window's background colour anymore. it is too
1528 much pain to keep the DC's and the window's back-
1529 ground colour in synch. */
1534 m_owner
->GetSize( &width
, &height
);
1535 gdk_draw_rectangle( m_window
, m_bgGC
, TRUE
, 0, 0, width
, height
);
1542 GetSize( &width
, &height
);
1543 gdk_draw_rectangle( m_window
, m_bgGC
, TRUE
, 0, 0, width
, height
);
1548 void wxWindowDC::SetFont( const wxFont
&font
)
1556 void wxWindowDC::SetPen( const wxPen
&pen
)
1558 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1560 if (m_pen
== pen
) return;
1564 if (!m_pen
.Ok()) return;
1566 if (!m_window
) return;
1568 gint width
= m_pen
.GetWidth();
1571 // CMB: if width is non-zero scale it with the dc
1576 // X doesn't allow different width in x and y and so we take
1579 ( fabs((double) XLOG2DEVREL(width
)) +
1580 fabs((double) YLOG2DEVREL(width
)) ) / 2.0;
1584 static const wxGTKDash dotted
[] = {1, 1};
1585 static const wxGTKDash short_dashed
[] = {2, 2};
1586 static const wxGTKDash wxCoord_dashed
[] = {2, 4};
1587 static const wxGTKDash dotted_dashed
[] = {3, 3, 1, 3};
1589 // We express dash pattern in pen width unit, so we are
1590 // independent of zoom factor and so on...
1592 const wxGTKDash
*req_dash
;
1594 GdkLineStyle lineStyle
= GDK_LINE_SOLID
;
1595 switch (m_pen
.GetStyle())
1599 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1600 req_nb_dash
= m_pen
.GetDashCount();
1601 req_dash
= (wxGTKDash
*)m_pen
.GetDash();
1606 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1613 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1615 req_dash
= wxCoord_dashed
;
1620 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1622 req_dash
= short_dashed
;
1627 // lineStyle = GDK_LINE_DOUBLE_DASH;
1628 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1630 req_dash
= dotted_dashed
;
1635 case wxSTIPPLE_MASK_OPAQUE
:
1640 lineStyle
= GDK_LINE_SOLID
;
1641 req_dash
= (wxGTKDash
*)NULL
;
1647 #if (GTK_MINOR_VERSION > 0) || (GTK_MAJOR_VERSION > 1)
1648 if (req_dash
&& req_nb_dash
)
1650 wxGTKDash
*real_req_dash
= new wxGTKDash
[req_nb_dash
];
1653 for (int i
= 0; i
< req_nb_dash
; i
++)
1654 real_req_dash
[i
] = req_dash
[i
] * width
;
1655 gdk_gc_set_dashes( m_penGC
, 0, real_req_dash
, req_nb_dash
);
1656 delete[] real_req_dash
;
1660 // No Memory. We use non-scaled dash pattern...
1661 gdk_gc_set_dashes( m_penGC
, 0, (wxGTKDash
*)req_dash
, req_nb_dash
);
1666 GdkCapStyle capStyle
= GDK_CAP_ROUND
;
1667 switch (m_pen
.GetCap())
1669 case wxCAP_PROJECTING
: { capStyle
= GDK_CAP_PROJECTING
; break; }
1670 case wxCAP_BUTT
: { capStyle
= GDK_CAP_BUTT
; break; }
1677 capStyle
= GDK_CAP_NOT_LAST
;
1681 capStyle
= GDK_CAP_ROUND
;
1687 GdkJoinStyle joinStyle
= GDK_JOIN_ROUND
;
1688 switch (m_pen
.GetJoin())
1690 case wxJOIN_BEVEL
: { joinStyle
= GDK_JOIN_BEVEL
; break; }
1691 case wxJOIN_MITER
: { joinStyle
= GDK_JOIN_MITER
; break; }
1693 default: { joinStyle
= GDK_JOIN_ROUND
; break; }
1696 gdk_gc_set_line_attributes( m_penGC
, width
, lineStyle
, capStyle
, joinStyle
);
1698 m_pen
.GetColour().CalcPixel( m_cmap
);
1699 gdk_gc_set_foreground( m_penGC
, m_pen
.GetColour().GetColor() );
1702 void wxWindowDC::SetBrush( const wxBrush
&brush
)
1704 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1706 if (m_brush
== brush
) return;
1710 if (!m_brush
.Ok()) return;
1712 if (!m_window
) return;
1714 m_brush
.GetColour().CalcPixel( m_cmap
);
1715 gdk_gc_set_foreground( m_brushGC
, m_brush
.GetColour().GetColor() );
1717 gdk_gc_set_fill( m_brushGC
, GDK_SOLID
);
1719 if ((m_brush
.GetStyle() == wxSTIPPLE
) && (m_brush
.GetStipple()->Ok()))
1721 if (m_brush
.GetStipple()->GetPixmap())
1723 gdk_gc_set_fill( m_brushGC
, GDK_TILED
);
1724 gdk_gc_set_tile( m_brushGC
, m_brush
.GetStipple()->GetPixmap() );
1728 gdk_gc_set_fill( m_brushGC
, GDK_STIPPLED
);
1729 gdk_gc_set_stipple( m_brushGC
, m_brush
.GetStipple()->GetBitmap() );
1733 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
1735 gdk_gc_set_fill( m_textGC
, GDK_OPAQUE_STIPPLED
);
1736 gdk_gc_set_stipple( m_textGC
, m_brush
.GetStipple()->GetMask()->GetBitmap() );
1739 if (IS_HATCH(m_brush
.GetStyle()))
1741 gdk_gc_set_fill( m_brushGC
, GDK_STIPPLED
);
1742 int num
= m_brush
.GetStyle() - wxBDIAGONAL_HATCH
;
1743 gdk_gc_set_stipple( m_brushGC
, hatches
[num
] );
1747 void wxWindowDC::SetBackground( const wxBrush
&brush
)
1749 /* CMB 21/7/98: Added SetBackground. Sets background brush
1750 * for Clear() and bg colour for shapes filled with cross-hatch brush */
1752 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1754 if (m_backgroundBrush
== brush
) return;
1756 m_backgroundBrush
= brush
;
1758 if (!m_backgroundBrush
.Ok()) return;
1760 if (!m_window
) return;
1762 m_backgroundBrush
.GetColour().CalcPixel( m_cmap
);
1763 gdk_gc_set_background( m_brushGC
, m_backgroundBrush
.GetColour().GetColor() );
1764 gdk_gc_set_background( m_penGC
, m_backgroundBrush
.GetColour().GetColor() );
1765 gdk_gc_set_background( m_bgGC
, m_backgroundBrush
.GetColour().GetColor() );
1766 gdk_gc_set_foreground( m_bgGC
, m_backgroundBrush
.GetColour().GetColor() );
1768 gdk_gc_set_fill( m_bgGC
, GDK_SOLID
);
1770 if ((m_backgroundBrush
.GetStyle() == wxSTIPPLE
) && (m_backgroundBrush
.GetStipple()->Ok()))
1772 if (m_backgroundBrush
.GetStipple()->GetPixmap())
1774 gdk_gc_set_fill( m_bgGC
, GDK_TILED
);
1775 gdk_gc_set_tile( m_bgGC
, m_backgroundBrush
.GetStipple()->GetPixmap() );
1779 gdk_gc_set_fill( m_bgGC
, GDK_STIPPLED
);
1780 gdk_gc_set_stipple( m_bgGC
, m_backgroundBrush
.GetStipple()->GetBitmap() );
1784 if (IS_HATCH(m_backgroundBrush
.GetStyle()))
1786 gdk_gc_set_fill( m_bgGC
, GDK_STIPPLED
);
1787 int num
= m_backgroundBrush
.GetStyle() - wxBDIAGONAL_HATCH
;
1788 gdk_gc_set_stipple( m_bgGC
, hatches
[num
] );
1792 void wxWindowDC::SetLogicalFunction( int function
)
1794 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1796 if (m_logicalFunction
== function
)
1799 // VZ: shouldn't this be a CHECK?
1803 GdkFunction mode
= GDK_COPY
;
1806 case wxXOR
: mode
= GDK_XOR
; break;
1807 case wxINVERT
: mode
= GDK_INVERT
; break;
1808 #if (GTK_MINOR_VERSION > 0)
1809 case wxOR_REVERSE
: mode
= GDK_OR_REVERSE
; break;
1810 case wxAND_REVERSE
: mode
= GDK_AND_REVERSE
; break;
1811 case wxCLEAR
: mode
= GDK_CLEAR
; break;
1812 case wxSET
: mode
= GDK_SET
; break;
1813 case wxOR_INVERT
: mode
= GDK_OR_INVERT
; break;
1814 case wxAND
: mode
= GDK_AND
; break;
1815 case wxOR
: mode
= GDK_OR
; break;
1816 case wxEQUIV
: mode
= GDK_EQUIV
; break;
1817 case wxNAND
: mode
= GDK_NAND
; break;
1818 case wxAND_INVERT
: mode
= GDK_AND_INVERT
; break;
1819 case wxCOPY
: mode
= GDK_COPY
; break;
1820 case wxNO_OP
: mode
= GDK_NOOP
; break;
1821 case wxSRC_INVERT
: mode
= GDK_COPY_INVERT
; break;
1823 // unsupported by GTK
1824 case wxNOR
: mode
= GDK_COPY
; break;
1828 wxFAIL_MSG( wxT("unsupported logical function") );
1833 m_logicalFunction
= function
;
1835 gdk_gc_set_function( m_penGC
, mode
);
1836 gdk_gc_set_function( m_brushGC
, mode
);
1838 // to stay compatible with wxMSW, we don't apply ROPs to the text
1839 // operations (i.e. DrawText/DrawRotatedText).
1840 // True, but mono-bitmaps use the m_textGC and they use ROPs as well.
1841 gdk_gc_set_function( m_textGC
, mode
);
1844 void wxWindowDC::SetTextForeground( const wxColour
&col
)
1846 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1848 if (m_textForegroundColour
== col
) return;
1850 m_textForegroundColour
= col
;
1851 if (!m_textForegroundColour
.Ok()) return;
1853 if (!m_window
) return;
1855 m_textForegroundColour
.CalcPixel( m_cmap
);
1856 gdk_gc_set_foreground( m_textGC
, m_textForegroundColour
.GetColor() );
1859 void wxWindowDC::SetTextBackground( const wxColour
&col
)
1861 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1863 if (m_textBackgroundColour
== col
) return;
1865 m_textBackgroundColour
= col
;
1866 if (!m_textBackgroundColour
.Ok()) return;
1868 if (!m_window
) return;
1870 m_textBackgroundColour
.CalcPixel( m_cmap
);
1871 gdk_gc_set_background( m_textGC
, m_textBackgroundColour
.GetColor() );
1874 void wxWindowDC::SetBackgroundMode( int mode
)
1876 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1878 m_backgroundMode
= mode
;
1880 if (!m_window
) return;
1882 // CMB 21/7/98: fill style of cross-hatch brushes is affected by
1883 // transparent/solid background mode
1885 if (m_brush
.GetStyle() != wxSOLID
&& m_brush
.GetStyle() != wxTRANSPARENT
)
1887 gdk_gc_set_fill( m_brushGC
,
1888 (m_backgroundMode
== wxTRANSPARENT
) ? GDK_STIPPLED
: GDK_OPAQUE_STIPPLED
);
1892 void wxWindowDC::SetPalette( const wxPalette
& WXUNUSED(palette
) )
1894 wxFAIL_MSG( wxT("wxWindowDC::SetPalette not implemented") );
1897 void wxWindowDC::DoSetClippingRegion( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
1899 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1901 if (!m_window
) return;
1904 rect
.x
= XLOG2DEV(x
);
1905 rect
.y
= YLOG2DEV(y
);
1906 rect
.width
= XLOG2DEVREL(width
);
1907 rect
.height
= YLOG2DEVREL(height
);
1909 if (!m_currentClippingRegion
.IsNull())
1910 m_currentClippingRegion
.Intersect( rect
);
1912 m_currentClippingRegion
.Union( rect
);
1914 #if USE_PAINT_REGION
1915 if (!m_paintClippingRegion
.IsNull())
1916 m_currentClippingRegion
.Intersect( m_paintClippingRegion
);
1919 wxCoord xx
, yy
, ww
, hh
;
1920 m_currentClippingRegion
.GetBox( xx
, yy
, ww
, hh
);
1921 wxDC::DoSetClippingRegion( xx
, yy
, ww
, hh
);
1923 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
1924 gdk_gc_set_clip_region( m_brushGC
, m_currentClippingRegion
.GetRegion() );
1925 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
1926 gdk_gc_set_clip_region( m_bgGC
, m_currentClippingRegion
.GetRegion() );
1929 void wxWindowDC::DoSetClippingRegionAsRegion( const wxRegion
®ion
)
1931 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1935 DestroyClippingRegion();
1939 if (!m_window
) return;
1941 if (!m_currentClippingRegion
.IsNull())
1942 m_currentClippingRegion
.Intersect( region
);
1944 m_currentClippingRegion
.Union( region
);
1946 #if USE_PAINT_REGION
1947 if (!m_paintClippingRegion
.IsNull())
1948 m_currentClippingRegion
.Intersect( m_paintClippingRegion
);
1951 wxCoord xx
, yy
, ww
, hh
;
1952 m_currentClippingRegion
.GetBox( xx
, yy
, ww
, hh
);
1953 wxDC::DoSetClippingRegion( xx
, yy
, ww
, hh
);
1955 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
1956 gdk_gc_set_clip_region( m_brushGC
, m_currentClippingRegion
.GetRegion() );
1957 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
1958 gdk_gc_set_clip_region( m_bgGC
, m_currentClippingRegion
.GetRegion() );
1961 void wxWindowDC::DestroyClippingRegion()
1963 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1965 wxDC::DestroyClippingRegion();
1967 m_currentClippingRegion
.Clear();
1969 #if USE_PAINT_REGION
1970 if (!m_paintClippingRegion
.IsEmpty())
1971 m_currentClippingRegion
.Union( m_paintClippingRegion
);
1974 if (!m_window
) return;
1976 if (m_currentClippingRegion
.IsEmpty())
1978 gdk_gc_set_clip_rectangle( m_penGC
, (GdkRectangle
*) NULL
);
1979 gdk_gc_set_clip_rectangle( m_brushGC
, (GdkRectangle
*) NULL
);
1980 gdk_gc_set_clip_rectangle( m_textGC
, (GdkRectangle
*) NULL
);
1981 gdk_gc_set_clip_rectangle( m_bgGC
, (GdkRectangle
*) NULL
);
1985 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
1986 gdk_gc_set_clip_region( m_brushGC
, m_currentClippingRegion
.GetRegion() );
1987 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
1988 gdk_gc_set_clip_region( m_bgGC
, m_currentClippingRegion
.GetRegion() );
1992 void wxWindowDC::Destroy()
1994 if (m_penGC
) wxFreePoolGC( m_penGC
);
1995 m_penGC
= (GdkGC
*) NULL
;
1996 if (m_brushGC
) wxFreePoolGC( m_brushGC
);
1997 m_brushGC
= (GdkGC
*) NULL
;
1998 if (m_textGC
) wxFreePoolGC( m_textGC
);
1999 m_textGC
= (GdkGC
*) NULL
;
2000 if (m_bgGC
) wxFreePoolGC( m_bgGC
);
2001 m_bgGC
= (GdkGC
*) NULL
;
2004 void wxWindowDC::ComputeScaleAndOrigin()
2006 /* CMB: copy scale to see if it changes */
2007 double origScaleX
= m_scaleX
;
2008 double origScaleY
= m_scaleY
;
2010 wxDC::ComputeScaleAndOrigin();
2012 /* CMB: if scale has changed call SetPen to recalulate the line width */
2013 if ((m_scaleX
!= origScaleX
|| m_scaleY
!= origScaleY
) &&
2016 /* this is a bit artificial, but we need to force wxDC to think
2017 the pen has changed */
2024 // Resolution in pixels per logical inch
2025 wxSize
wxWindowDC::GetPPI() const
2027 return wxSize(100, 100);
2030 int wxWindowDC::GetDepth() const
2032 wxFAIL_MSG(wxT("not implemented"));
2038 // ----------------------------------- spline code ----------------------------------------
2040 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
2041 double a3
, double b3
, double a4
, double b4
);
2042 void wx_clear_stack();
2043 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
2044 double *y3
, double *x4
, double *y4
);
2045 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
2046 double x4
, double y4
);
2047 static bool wx_spline_add_point(double x
, double y
);
2048 static void wx_spline_draw_point_array(wxDC
*dc
);
2050 wxList wx_spline_point_list
;
2052 #define half(z1, z2) ((z1+z2)/2.0)
2055 /* iterative version */
2057 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
2060 register double xmid
, ymid
;
2061 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
2064 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
2066 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
2067 xmid
= (double)half(x2
, x3
);
2068 ymid
= (double)half(y2
, y3
);
2069 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
2070 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
2071 wx_spline_add_point( x1
, y1
);
2072 wx_spline_add_point( xmid
, ymid
);
2074 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
2075 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
2076 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
2077 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
2082 /* utilities used by spline drawing routines */
2084 typedef struct wx_spline_stack_struct
{
2085 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
2088 #define SPLINE_STACK_DEPTH 20
2089 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
2090 static Stack
*wx_stack_top
;
2091 static int wx_stack_count
;
2093 void wx_clear_stack()
2095 wx_stack_top
= wx_spline_stack
;
2099 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
2101 wx_stack_top
->x1
= x1
;
2102 wx_stack_top
->y1
= y1
;
2103 wx_stack_top
->x2
= x2
;
2104 wx_stack_top
->y2
= y2
;
2105 wx_stack_top
->x3
= x3
;
2106 wx_stack_top
->y3
= y3
;
2107 wx_stack_top
->x4
= x4
;
2108 wx_stack_top
->y4
= y4
;
2113 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
2114 double *x3
, double *y3
, double *x4
, double *y4
)
2116 if (wx_stack_count
== 0)
2120 *x1
= wx_stack_top
->x1
;
2121 *y1
= wx_stack_top
->y1
;
2122 *x2
= wx_stack_top
->x2
;
2123 *y2
= wx_stack_top
->y2
;
2124 *x3
= wx_stack_top
->x3
;
2125 *y3
= wx_stack_top
->y3
;
2126 *x4
= wx_stack_top
->x4
;
2127 *y4
= wx_stack_top
->y4
;
2131 static bool wx_spline_add_point(double x
, double y
)
2133 wxPoint
*point
= new wxPoint
;
2136 wx_spline_point_list
.Append((wxObject
*)point
);
2140 static void wx_spline_draw_point_array(wxDC
*dc
)
2142 dc
->DrawLines(&wx_spline_point_list
, 0, 0 );
2143 wxNode
*node
= wx_spline_point_list
.First();
2146 wxPoint
*point
= (wxPoint
*)node
->Data();
2149 node
= wx_spline_point_list
.First();
2153 void wxWindowDC::DoDrawSpline( wxList
*points
)
2155 wxCHECK_RET( Ok(), wxT("invalid window dc") );
2158 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
2159 double x1
, y1
, x2
, y2
;
2161 wxNode
*node
= points
->First();
2162 p
= (wxPoint
*)node
->Data();
2167 node
= node
->Next();
2168 p
= (wxPoint
*)node
->Data();
2172 cx1
= (double)((x1
+ x2
) / 2);
2173 cy1
= (double)((y1
+ y2
) / 2);
2174 cx2
= (double)((cx1
+ x2
) / 2);
2175 cy2
= (double)((cy1
+ y2
) / 2);
2177 wx_spline_add_point(x1
, y1
);
2179 while ((node
= node
->Next()) != NULL
)
2181 p
= (wxPoint
*)node
->Data();
2186 cx4
= (double)(x1
+ x2
) / 2;
2187 cy4
= (double)(y1
+ y2
) / 2;
2188 cx3
= (double)(x1
+ cx4
) / 2;
2189 cy3
= (double)(y1
+ cy4
) / 2;
2191 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
2195 cx2
= (double)(cx1
+ x2
) / 2;
2196 cy2
= (double)(cy1
+ y2
) / 2;
2199 wx_spline_add_point( cx1
, cy1
);
2200 wx_spline_add_point( x2
, y2
);
2202 wx_spline_draw_point_array( this );
2205 #endif // wxUSE_SPLINE
2207 //-----------------------------------------------------------------------------
2209 //-----------------------------------------------------------------------------
2211 IMPLEMENT_DYNAMIC_CLASS(wxPaintDC
,wxWindowDC
)
2213 wxPaintDC::wxPaintDC()
2218 wxPaintDC::wxPaintDC( wxWindow
*win
)
2221 #if USE_PAINT_REGION
2222 if (!win
->m_clipPaintRegion
)
2225 m_paintClippingRegion
= win
->GetUpdateRegion();
2226 GdkRegion
*region
= m_paintClippingRegion
.GetRegion();
2229 m_currentClippingRegion
.Union( m_paintClippingRegion
);
2231 gdk_gc_set_clip_region( m_penGC
, region
);
2232 gdk_gc_set_clip_region( m_brushGC
, region
);
2233 gdk_gc_set_clip_region( m_textGC
, region
);
2234 gdk_gc_set_clip_region( m_bgGC
, region
);
2239 //-----------------------------------------------------------------------------
2241 //-----------------------------------------------------------------------------
2243 IMPLEMENT_DYNAMIC_CLASS(wxClientDC
,wxWindowDC
)
2245 wxClientDC::wxClientDC()
2250 wxClientDC::wxClientDC( wxWindow
*win
)
2255 // ----------------------------------------------------------------------------
2257 // ----------------------------------------------------------------------------
2259 class wxDCModule
: public wxModule
2266 DECLARE_DYNAMIC_CLASS(wxDCModule
)
2269 IMPLEMENT_DYNAMIC_CLASS(wxDCModule
, wxModule
)
2271 bool wxDCModule::OnInit()
2277 void wxDCModule::OnExit()