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"
15 #define XCopyPlane XCOPYPLANE
18 #include "wx/dcclient.h"
19 #include "wx/dcmemory.h"
21 #include "wx/module.h"
23 #include "wx/gtk/win_gtk.h"
25 #include <math.h> // for floating-point functions
29 #include <gdk/gdkprivate.h>
32 //-----------------------------------------------------------------------------
34 //-----------------------------------------------------------------------------
36 #define USE_PAINT_REGION 1
38 //-----------------------------------------------------------------------------
40 //-----------------------------------------------------------------------------
50 #define IS_15_PIX_HATCH(s) ((s)==wxCROSSDIAG_HATCH || (s)==wxHORIZONTAL_HATCH || (s)==wxVERTICAL_HATCH)
51 #define IS_16_PIX_HATCH(s) ((s)!=wxCROSSDIAG_HATCH && (s)!=wxHORIZONTAL_HATCH && (s)!=wxVERTICAL_HATCH)
54 static GdkPixmap
*hatches
[num_hatches
];
55 static GdkPixmap
**hatch_bitmap
= (GdkPixmap
**) NULL
;
57 extern GtkWidget
*wxRootWindow
;
59 //-----------------------------------------------------------------------------
61 //-----------------------------------------------------------------------------
63 const double RAD2DEG
= 180.0 / M_PI
;
65 // ----------------------------------------------------------------------------
67 // ----------------------------------------------------------------------------
69 static inline double dmax(double a
, double b
) { return a
> b
? a
: b
; }
70 static inline double dmin(double a
, double b
) { return a
< b
? a
: b
; }
72 static inline double DegToRad(double deg
) { return (deg
* M_PI
) / 180.0; }
74 //-----------------------------------------------------------------------------
75 // temporary implementation of the missing GDK function
76 //-----------------------------------------------------------------------------
78 #include "gdk/gdkprivate.h"
80 void gdk_wx_draw_bitmap (GdkDrawable
*drawable
,
90 gint src_width
, src_height
;
92 GdkWindowPrivate
*drawable_private
;
93 GdkWindowPrivate
*src_private
;
94 GdkGCPrivate
*gc_private
;
97 g_return_if_fail (drawable
!= NULL
);
98 g_return_if_fail (src
!= NULL
);
99 g_return_if_fail (gc
!= NULL
);
102 if (GDK_WINDOW_DESTROYED(drawable
) || GDK_WINDOW_DESTROYED(src
))
105 gdk_drawable_get_size(src
, &src_width
, &src_height
);
107 drawable_private
= (GdkWindowPrivate
*) drawable
;
108 src_private
= (GdkWindowPrivate
*) src
;
109 if (drawable_private
->destroyed
|| src_private
->destroyed
)
112 src_width
= src_private
->width
;
113 src_height
= src_private
->height
;
115 gc_private
= (GdkGCPrivate
*) gc
;
118 if (width
== -1) width
= src_width
;
119 if (height
== -1) height
= src_height
;
122 XCopyPlane( GDK_WINDOW_XDISPLAY(drawable
),
124 GDK_WINDOW_XID(drawable
),
131 XCopyPlane( drawable_private
->xdisplay
,
132 src_private
->xwindow
,
133 drawable_private
->xwindow
,
142 //-----------------------------------------------------------------------------
143 // Implement Pool of Graphic contexts. Creating them takes too much time.
144 //-----------------------------------------------------------------------------
146 #define GC_POOL_SIZE 200
172 static wxGC wxGCPool
[GC_POOL_SIZE
];
174 static void wxInitGCPool()
176 memset( wxGCPool
, 0, GC_POOL_SIZE
*sizeof(wxGC
) );
179 static void wxCleanUpGCPool()
181 for (int i
= 0; i
< GC_POOL_SIZE
; i
++)
183 if (wxGCPool
[i
].m_gc
)
184 gdk_gc_unref( wxGCPool
[i
].m_gc
);
188 static GdkGC
* wxGetPoolGC( GdkWindow
*window
, wxPoolGCType type
)
190 for (int i
= 0; i
< GC_POOL_SIZE
; i
++)
192 if (!wxGCPool
[i
].m_gc
)
194 wxGCPool
[i
].m_gc
= gdk_gc_new( window
);
195 gdk_gc_set_exposures( wxGCPool
[i
].m_gc
, FALSE
);
196 wxGCPool
[i
].m_type
= type
;
197 wxGCPool
[i
].m_used
= FALSE
;
199 if ((!wxGCPool
[i
].m_used
) && (wxGCPool
[i
].m_type
== type
))
201 wxGCPool
[i
].m_used
= TRUE
;
202 return wxGCPool
[i
].m_gc
;
206 wxFAIL_MSG( wxT("No GC available") );
208 return (GdkGC
*) NULL
;
211 static void wxFreePoolGC( GdkGC
*gc
)
213 for (int i
= 0; i
< GC_POOL_SIZE
; i
++)
215 if (wxGCPool
[i
].m_gc
== gc
)
217 wxGCPool
[i
].m_used
= FALSE
;
222 wxFAIL_MSG( wxT("Wrong GC") );
225 //-----------------------------------------------------------------------------
227 //-----------------------------------------------------------------------------
229 IMPLEMENT_DYNAMIC_CLASS(wxWindowDC
, wxDC
)
231 wxWindowDC::wxWindowDC()
233 m_penGC
= (GdkGC
*) NULL
;
234 m_brushGC
= (GdkGC
*) NULL
;
235 m_textGC
= (GdkGC
*) NULL
;
236 m_bgGC
= (GdkGC
*) NULL
;
237 m_cmap
= (GdkColormap
*) NULL
;
239 m_isScreenDC
= FALSE
;
240 m_owner
= (wxWindow
*)NULL
;
242 m_context
= (PangoContext
*)NULL
;
243 m_fontdesc
= (PangoFontDescription
*)NULL
;
247 wxWindowDC::wxWindowDC( wxWindow
*window
)
249 m_penGC
= (GdkGC
*) NULL
;
250 m_brushGC
= (GdkGC
*) NULL
;
251 m_textGC
= (GdkGC
*) NULL
;
252 m_bgGC
= (GdkGC
*) NULL
;
253 m_cmap
= (GdkColormap
*) NULL
;
254 m_owner
= (wxWindow
*)NULL
;
256 m_isScreenDC
= FALSE
;
257 m_font
= window
->GetFont();
259 wxASSERT_MSG( window
, wxT("DC needs a window") );
261 GtkWidget
*widget
= window
->m_wxwindow
;
263 // some controls don't have m_wxwindow - like wxStaticBox, but the user
264 // code should still be able to create wxClientDCs for them, so we will
265 // use the parent window here then
268 window
= window
->GetParent();
269 widget
= window
->m_wxwindow
;
272 wxASSERT_MSG( widget
, wxT("DC needs a widget") );
275 m_context
= gtk_widget_get_pango_context( widget
);
276 m_fontdesc
= widget
->style
->font_desc
;
279 GtkPizza
*pizza
= GTK_PIZZA( widget
);
280 m_window
= pizza
->bin_window
;
285 /* don't report problems */
291 m_cmap
= gtk_widget_get_colormap( widget
? widget
: window
->m_widget
);
295 /* this must be done after SetUpDC, bacause SetUpDC calls the
296 repective SetBrush, SetPen, SetBackground etc functions
297 to set up the DC. SetBackground call m_owner->SetBackground
298 and this might not be desired as the standard dc background
299 is white whereas a window might assume gray to be the
300 standard (as e.g. wxStatusBar) */
305 wxWindowDC::~wxWindowDC()
310 void wxWindowDC::SetUpDC()
314 wxASSERT_MSG( !m_penGC
, wxT("GCs already created") );
318 m_penGC
= wxGetPoolGC( m_window
, wxPEN_SCREEN
);
319 m_brushGC
= wxGetPoolGC( m_window
, wxBRUSH_SCREEN
);
320 m_textGC
= wxGetPoolGC( m_window
, wxTEXT_SCREEN
);
321 m_bgGC
= wxGetPoolGC( m_window
, wxBG_SCREEN
);
324 if (m_isMemDC
&& (((wxMemoryDC
*)this)->m_selected
.GetDepth() == 1))
326 m_penGC
= wxGetPoolGC( m_window
, wxPEN_MONO
);
327 m_brushGC
= wxGetPoolGC( m_window
, wxBRUSH_MONO
);
328 m_textGC
= wxGetPoolGC( m_window
, wxTEXT_MONO
);
329 m_bgGC
= wxGetPoolGC( m_window
, wxBG_MONO
);
333 m_penGC
= wxGetPoolGC( m_window
, wxPEN_COLOUR
);
334 m_brushGC
= wxGetPoolGC( m_window
, wxBRUSH_COLOUR
);
335 m_textGC
= wxGetPoolGC( m_window
, wxTEXT_COLOUR
);
336 m_bgGC
= wxGetPoolGC( m_window
, wxBG_COLOUR
);
339 /* background colour */
340 m_backgroundBrush
= *wxWHITE_BRUSH
;
341 m_backgroundBrush
.GetColour().CalcPixel( m_cmap
);
342 GdkColor
*bg_col
= m_backgroundBrush
.GetColour().GetColor();
345 m_textForegroundColour
.CalcPixel( m_cmap
);
346 gdk_gc_set_foreground( m_textGC
, m_textForegroundColour
.GetColor() );
348 m_textBackgroundColour
.CalcPixel( m_cmap
);
349 gdk_gc_set_background( m_textGC
, m_textBackgroundColour
.GetColor() );
351 gdk_gc_set_fill( m_textGC
, GDK_SOLID
);
354 m_pen
.GetColour().CalcPixel( m_cmap
);
355 gdk_gc_set_foreground( m_penGC
, m_pen
.GetColour().GetColor() );
356 gdk_gc_set_background( m_penGC
, bg_col
);
358 gdk_gc_set_line_attributes( m_penGC
, 0, GDK_LINE_SOLID
, GDK_CAP_NOT_LAST
, GDK_JOIN_ROUND
);
361 m_brush
.GetColour().CalcPixel( m_cmap
);
362 gdk_gc_set_foreground( m_brushGC
, m_brush
.GetColour().GetColor() );
363 gdk_gc_set_background( m_brushGC
, bg_col
);
365 gdk_gc_set_fill( m_brushGC
, GDK_SOLID
);
368 gdk_gc_set_background( m_bgGC
, bg_col
);
369 gdk_gc_set_foreground( m_bgGC
, bg_col
);
371 gdk_gc_set_fill( m_bgGC
, GDK_SOLID
);
374 gdk_gc_set_function( m_textGC
, GDK_COPY
);
375 gdk_gc_set_function( m_brushGC
, GDK_COPY
);
376 gdk_gc_set_function( m_penGC
, GDK_COPY
);
379 gdk_gc_set_clip_rectangle( m_penGC
, (GdkRectangle
*) NULL
);
380 gdk_gc_set_clip_rectangle( m_brushGC
, (GdkRectangle
*) NULL
);
381 gdk_gc_set_clip_rectangle( m_textGC
, (GdkRectangle
*) NULL
);
382 gdk_gc_set_clip_rectangle( m_bgGC
, (GdkRectangle
*) NULL
);
386 hatch_bitmap
= hatches
;
387 hatch_bitmap
[0] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, bdiag_bits
, bdiag_width
, bdiag_height
);
388 hatch_bitmap
[1] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, cdiag_bits
, cdiag_width
, cdiag_height
);
389 hatch_bitmap
[2] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, fdiag_bits
, fdiag_width
, fdiag_height
);
390 hatch_bitmap
[3] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, cross_bits
, cross_width
, cross_height
);
391 hatch_bitmap
[4] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, horiz_bits
, horiz_width
, horiz_height
);
392 hatch_bitmap
[5] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, verti_bits
, verti_width
, verti_height
);
396 void wxWindowDC::DoFloodFill( wxCoord
WXUNUSED(x
), wxCoord
WXUNUSED(y
),
397 const wxColour
&WXUNUSED(col
), int WXUNUSED(style
) )
399 wxFAIL_MSG( wxT("wxWindowDC::DoFloodFill not implemented") );
402 bool wxWindowDC::DoGetPixel( wxCoord x1
, wxCoord y1
, wxColour
*col
) const
404 // Generic (and therefore rather inefficient) method.
405 // Could be improved.
407 wxBitmap
bitmap(1, 1);
408 memdc
.SelectObject(bitmap
);
409 memdc
.Blit(0, 0, 1, 1, (wxDC
*) this, x1
, y1
);
410 memdc
.SelectObject(wxNullBitmap
);
411 wxImage
image(bitmap
);
412 col
->Set(image
.GetRed(0, 0), image
.GetGreen(0, 0), image
.GetBlue(0, 0));
416 void wxWindowDC::DoDrawLine( wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
418 wxCHECK_RET( Ok(), wxT("invalid window dc") );
420 if (m_pen
.GetStyle() != wxTRANSPARENT
)
423 gdk_draw_line( m_window
, m_penGC
, XLOG2DEV(x1
), YLOG2DEV(y1
), XLOG2DEV(x2
), YLOG2DEV(y2
) );
425 CalcBoundingBox(x1
, y1
);
426 CalcBoundingBox(x2
, y2
);
430 void wxWindowDC::DoCrossHair( wxCoord x
, wxCoord y
)
432 wxCHECK_RET( Ok(), wxT("invalid window dc") );
434 if (m_pen
.GetStyle() != wxTRANSPARENT
)
439 wxCoord xx
= XLOG2DEV(x
);
440 wxCoord yy
= YLOG2DEV(y
);
443 gdk_draw_line( m_window
, m_penGC
, 0, yy
, XLOG2DEVREL(w
), yy
);
444 gdk_draw_line( m_window
, m_penGC
, xx
, 0, xx
, YLOG2DEVREL(h
) );
449 void wxWindowDC::DoDrawArc( wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
,
450 wxCoord xc
, wxCoord yc
)
452 wxCHECK_RET( Ok(), wxT("invalid window dc") );
454 wxCoord xx1
= XLOG2DEV(x1
);
455 wxCoord yy1
= YLOG2DEV(y1
);
456 wxCoord xx2
= XLOG2DEV(x2
);
457 wxCoord yy2
= YLOG2DEV(y2
);
458 wxCoord xxc
= XLOG2DEV(xc
);
459 wxCoord yyc
= YLOG2DEV(yc
);
460 double dx
= xx1
- xxc
;
461 double dy
= yy1
- yyc
;
462 double radius
= sqrt((double)(dx
*dx
+dy
*dy
));
463 wxCoord r
= (wxCoord
)radius
;
464 double radius1
, radius2
;
466 if (xx1
== xx2
&& yy1
== yy2
)
474 radius1
= radius2
= 0.0;
478 radius1
= (xx1
- xxc
== 0) ?
479 (yy1
- yyc
< 0) ? 90.0 : -90.0 :
480 -atan2(double(yy1
-yyc
), double(xx1
-xxc
)) * RAD2DEG
;
481 radius2
= (xx2
- xxc
== 0) ?
482 (yy2
- yyc
< 0) ? 90.0 : -90.0 :
483 -atan2(double(yy2
-yyc
), double(xx2
-xxc
)) * RAD2DEG
;
485 wxCoord alpha1
= wxCoord(radius1
* 64.0);
486 wxCoord alpha2
= wxCoord((radius2
- radius1
) * 64.0);
487 while (alpha2
<= 0) alpha2
+= 360*64;
488 while (alpha1
> 360*64) alpha1
-= 360*64;
492 if (m_brush
.GetStyle() != wxTRANSPARENT
)
494 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
496 gdk_gc_set_ts_origin( m_textGC
,
497 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
498 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
499 gdk_draw_arc( m_window
, m_textGC
, TRUE
, xxc
-r
, yyc
-r
, 2*r
,2*r
, alpha1
, alpha2
);
500 gdk_gc_set_ts_origin( m_textGC
, 0, 0 );
502 if (IS_15_PIX_HATCH(m_brush
.GetStyle()))
504 gdk_gc_set_ts_origin( m_brushGC
, m_deviceOriginX
% 15, m_deviceOriginY
% 15 );
505 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xxc
-r
, yyc
-r
, 2*r
,2*r
, alpha1
, alpha2
);
506 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
508 if (IS_16_PIX_HATCH(m_brush
.GetStyle()))
510 gdk_gc_set_ts_origin( m_brushGC
, m_deviceOriginX
% 16, m_deviceOriginY
% 16 );
511 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xxc
-r
, yyc
-r
, 2*r
,2*r
, alpha1
, alpha2
);
512 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
514 if (m_brush
.GetStyle() == wxSTIPPLE
)
516 gdk_gc_set_ts_origin( m_brushGC
,
517 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
518 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
519 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xxc
-r
, yyc
-r
, 2*r
,2*r
, alpha1
, alpha2
);
520 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
524 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xxc
-r
, yyc
-r
, 2*r
,2*r
, alpha1
, alpha2
);
528 if (m_pen
.GetStyle() != wxTRANSPARENT
)
529 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xxc
-r
, yyc
-r
, 2*r
,2*r
, alpha1
, alpha2
);
532 CalcBoundingBox (x1
, y1
);
533 CalcBoundingBox (x2
, y2
);
536 void wxWindowDC::DoDrawEllipticArc( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double sa
, double ea
)
538 wxCHECK_RET( Ok(), wxT("invalid window dc") );
540 wxCoord xx
= XLOG2DEV(x
);
541 wxCoord yy
= YLOG2DEV(y
);
542 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
543 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
545 // CMB: handle -ve width and/or height
546 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
547 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
551 wxCoord start
= wxCoord(sa
* 64.0);
552 wxCoord end
= wxCoord(ea
* 64.0);
554 if (m_brush
.GetStyle() != wxTRANSPARENT
)
556 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
558 gdk_gc_set_ts_origin( m_textGC
,
559 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
560 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
561 gdk_draw_arc( m_window
, m_textGC
, TRUE
, xx
, yy
, ww
, hh
, start
, end
);
562 gdk_gc_set_ts_origin( m_textGC
, 0, 0 );
564 if (IS_15_PIX_HATCH(m_brush
.GetStyle()))
566 gdk_gc_set_ts_origin( m_brushGC
, m_deviceOriginX
% 15, m_deviceOriginY
% 15 );
567 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, start
, end
);
568 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
570 if (IS_16_PIX_HATCH(m_brush
.GetStyle()))
572 gdk_gc_set_ts_origin( m_brushGC
, m_deviceOriginX
% 16, m_deviceOriginY
% 16 );
573 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, start
, end
);
574 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
576 if (m_brush
.GetStyle() == wxSTIPPLE
)
578 gdk_gc_set_ts_origin( m_brushGC
,
579 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
580 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
581 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, start
, end
);
582 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
586 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, start
, end
);
590 if (m_pen
.GetStyle() != wxTRANSPARENT
)
591 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
, hh
, start
, end
);
594 CalcBoundingBox (x
, y
);
595 CalcBoundingBox (x
+ width
, y
+ height
);
598 void wxWindowDC::DoDrawPoint( wxCoord x
, wxCoord y
)
600 wxCHECK_RET( Ok(), wxT("invalid window dc") );
602 if ((m_pen
.GetStyle() != wxTRANSPARENT
) && m_window
)
603 gdk_draw_point( m_window
, m_penGC
, XLOG2DEV(x
), YLOG2DEV(y
) );
605 CalcBoundingBox (x
, y
);
608 void wxWindowDC::DoDrawLines( int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
610 wxCHECK_RET( Ok(), wxT("invalid window dc") );
612 if (m_pen
.GetStyle() == wxTRANSPARENT
) return;
615 CalcBoundingBox( points
[0].x
+ xoffset
, points
[0].y
+ yoffset
);
617 for (int i
= 0; i
< n
-1; i
++)
619 wxCoord x1
= XLOG2DEV(points
[i
].x
+ xoffset
);
620 wxCoord x2
= XLOG2DEV(points
[i
+1].x
+ xoffset
);
621 wxCoord y1
= YLOG2DEV(points
[i
].y
+ yoffset
); // oh, what a waste
622 wxCoord y2
= YLOG2DEV(points
[i
+1].y
+ yoffset
);
625 gdk_draw_line( m_window
, m_penGC
, x1
, y1
, x2
, y2
);
627 CalcBoundingBox( points
[i
+1].x
+ xoffset
, points
[i
+1].y
+ yoffset
);
631 void wxWindowDC::DoDrawPolygon( int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
, int WXUNUSED(fillStyle
) )
633 wxCHECK_RET( Ok(), wxT("invalid window dc") );
637 GdkPoint
*gdkpoints
= new GdkPoint
[n
+1];
639 for (i
= 0 ; i
< n
; i
++)
641 gdkpoints
[i
].x
= XLOG2DEV(points
[i
].x
+ xoffset
);
642 gdkpoints
[i
].y
= YLOG2DEV(points
[i
].y
+ yoffset
);
644 CalcBoundingBox( points
[i
].x
+ xoffset
, points
[i
].y
+ yoffset
);
649 if (m_brush
.GetStyle() != wxTRANSPARENT
)
651 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
653 gdk_gc_set_ts_origin( m_textGC
,
654 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
655 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
656 gdk_draw_polygon( m_window
, m_textGC
, TRUE
, gdkpoints
, n
);
657 gdk_gc_set_ts_origin( m_textGC
, 0, 0 );
659 if (IS_15_PIX_HATCH(m_brush
.GetStyle()))
661 gdk_gc_set_ts_origin( m_brushGC
, m_deviceOriginX
% 15, m_deviceOriginY
% 15 );
662 gdk_draw_polygon( m_window
, m_brushGC
, TRUE
, gdkpoints
, n
);
663 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
665 if (IS_16_PIX_HATCH(m_brush
.GetStyle()))
667 gdk_gc_set_ts_origin( m_brushGC
, m_deviceOriginX
% 16, m_deviceOriginY
% 16 );
668 gdk_draw_polygon( m_window
, m_brushGC
, TRUE
, gdkpoints
, n
);
669 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
671 if (m_brush
.GetStyle() == wxSTIPPLE
)
673 gdk_gc_set_ts_origin( m_brushGC
,
674 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
675 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
676 gdk_draw_polygon( m_window
, m_brushGC
, TRUE
, gdkpoints
, n
);
677 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
681 gdk_draw_polygon( m_window
, m_brushGC
, TRUE
, gdkpoints
, n
);
685 if (m_pen
.GetStyle() != wxTRANSPARENT
)
687 for (i
= 0 ; i
< n
; i
++)
689 gdk_draw_line( m_window
, m_penGC
,
692 gdkpoints
[(i
+1)%n
].x
,
693 gdkpoints
[(i
+1)%n
].y
);
701 void wxWindowDC::DoDrawRectangle( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
703 wxCHECK_RET( Ok(), wxT("invalid window dc") );
705 wxCoord xx
= XLOG2DEV(x
);
706 wxCoord yy
= YLOG2DEV(y
);
707 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
708 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
710 // CMB: draw nothing if transformed w or h is 0
711 if (ww
== 0 || hh
== 0) return;
713 // CMB: handle -ve width and/or height
714 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
715 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
719 if (m_brush
.GetStyle() != wxTRANSPARENT
)
721 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
723 gdk_gc_set_ts_origin( m_textGC
,
724 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
725 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
726 gdk_draw_rectangle( m_window
, m_textGC
, TRUE
, xx
, yy
, ww
, hh
);
727 gdk_gc_set_ts_origin( m_textGC
, 0, 0 );
729 if (IS_15_PIX_HATCH(m_brush
.GetStyle()))
731 gdk_gc_set_ts_origin( m_brushGC
, m_deviceOriginX
% 15, m_deviceOriginY
% 15 );
732 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
);
733 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
735 if (IS_16_PIX_HATCH(m_brush
.GetStyle()))
737 gdk_gc_set_ts_origin( m_brushGC
, m_deviceOriginX
% 16, m_deviceOriginY
% 16 );
738 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
);
739 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
741 if (m_brush
.GetStyle() == wxSTIPPLE
)
743 gdk_gc_set_ts_origin( m_brushGC
,
744 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
745 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
746 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
);
747 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
751 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
);
755 if (m_pen
.GetStyle() != wxTRANSPARENT
)
756 gdk_draw_rectangle( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
-1, hh
-1 );
759 CalcBoundingBox( x
, y
);
760 CalcBoundingBox( x
+ width
, y
+ height
);
763 void wxWindowDC::DoDrawRoundedRectangle( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
765 wxCHECK_RET( Ok(), wxT("invalid window dc") );
767 if (radius
< 0.0) radius
= - radius
* ((width
< height
) ? width
: height
);
769 wxCoord xx
= XLOG2DEV(x
);
770 wxCoord yy
= YLOG2DEV(y
);
771 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
772 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
773 wxCoord rr
= XLOG2DEVREL((wxCoord
)radius
);
775 // CMB: handle -ve width and/or height
776 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
777 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
779 // CMB: if radius is zero use DrawRectangle() instead to avoid
780 // X drawing errors with small radii
783 DrawRectangle( x
, y
, width
, height
);
787 // CMB: draw nothing if transformed w or h is 0
788 if (ww
== 0 || hh
== 0) return;
790 // CMB: adjust size if outline is drawn otherwise the result is
791 // 1 pixel too wide and high
792 if (m_pen
.GetStyle() != wxTRANSPARENT
)
800 // CMB: ensure dd is not larger than rectangle otherwise we
801 // get an hour glass shape
803 if (dd
> ww
) dd
= ww
;
804 if (dd
> hh
) dd
= hh
;
807 if (m_brush
.GetStyle() != wxTRANSPARENT
)
809 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
811 gdk_gc_set_ts_origin( m_textGC
,
812 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
813 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
814 gdk_draw_rectangle( m_window
, m_textGC
, TRUE
, xx
+rr
, yy
, ww
-dd
+1, hh
);
815 gdk_draw_rectangle( m_window
, m_textGC
, TRUE
, xx
, yy
+rr
, ww
, hh
-dd
+1 );
816 gdk_draw_arc( m_window
, m_textGC
, TRUE
, xx
, yy
, dd
, dd
, 90*64, 90*64 );
817 gdk_draw_arc( m_window
, m_textGC
, TRUE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 );
818 gdk_draw_arc( m_window
, m_textGC
, TRUE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 );
819 gdk_draw_arc( m_window
, m_textGC
, TRUE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 );
820 gdk_gc_set_ts_origin( m_textGC
, 0, 0 );
822 if (IS_15_PIX_HATCH(m_brush
.GetStyle()))
824 gdk_gc_set_ts_origin( m_brushGC
, m_deviceOriginX
% 15, m_deviceOriginY
% 15 );
825 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
+rr
, yy
, ww
-dd
+1, hh
);
826 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
+rr
, ww
, hh
-dd
+1 );
827 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, dd
, dd
, 90*64, 90*64 );
828 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 );
829 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 );
830 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 );
831 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
833 if (IS_16_PIX_HATCH(m_brush
.GetStyle()))
835 gdk_gc_set_ts_origin( m_brushGC
, m_deviceOriginX
% 16, m_deviceOriginY
% 16 );
836 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
+rr
, yy
, ww
-dd
+1, hh
);
837 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
+rr
, ww
, hh
-dd
+1 );
838 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, dd
, dd
, 90*64, 90*64 );
839 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 );
840 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 );
841 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 );
842 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
844 if (m_brush
.GetStyle() == wxSTIPPLE
)
846 gdk_gc_set_ts_origin( m_brushGC
,
847 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
848 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
849 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
+rr
, yy
, ww
-dd
+1, hh
);
850 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
+rr
, ww
, hh
-dd
+1 );
851 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, dd
, dd
, 90*64, 90*64 );
852 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 );
853 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 );
854 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 );
855 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
859 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
+rr
, yy
, ww
-dd
+1, hh
);
860 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
+rr
, ww
, hh
-dd
+1 );
861 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, dd
, dd
, 90*64, 90*64 );
862 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 );
863 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 );
864 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 );
868 if (m_pen
.GetStyle() != wxTRANSPARENT
)
870 gdk_draw_line( m_window
, m_penGC
, xx
+rr
+1, yy
, xx
+ww
-rr
, yy
);
871 gdk_draw_line( m_window
, m_penGC
, xx
+rr
+1, yy
+hh
, xx
+ww
-rr
, yy
+hh
);
872 gdk_draw_line( m_window
, m_penGC
, xx
, yy
+rr
+1, xx
, yy
+hh
-rr
);
873 gdk_draw_line( m_window
, m_penGC
, xx
+ww
, yy
+rr
+1, xx
+ww
, yy
+hh
-rr
);
874 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
, dd
, dd
, 90*64, 90*64 );
875 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 );
876 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 );
877 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 );
881 // this ignores the radius
882 CalcBoundingBox( x
, y
);
883 CalcBoundingBox( x
+ width
, y
+ height
);
886 void wxWindowDC::DoDrawEllipse( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
888 wxCHECK_RET( Ok(), wxT("invalid window dc") );
890 wxCoord xx
= XLOG2DEV(x
);
891 wxCoord yy
= YLOG2DEV(y
);
892 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
893 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
895 // CMB: handle -ve width and/or height
896 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
897 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
901 if (m_brush
.GetStyle() != wxTRANSPARENT
)
903 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
905 gdk_gc_set_ts_origin( m_textGC
,
906 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
907 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
908 gdk_draw_arc( m_window
, m_textGC
, TRUE
, xx
, yy
, ww
, hh
, 0, 360*64 );
909 gdk_gc_set_ts_origin( m_textGC
, 0, 0 );
911 if (IS_15_PIX_HATCH(m_brush
.GetStyle()))
913 gdk_gc_set_ts_origin( m_brushGC
, m_deviceOriginX
% 15, m_deviceOriginY
% 15 );
914 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, 0, 360*64 );
915 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
917 if (IS_16_PIX_HATCH(m_brush
.GetStyle()))
919 gdk_gc_set_ts_origin( m_brushGC
, m_deviceOriginX
% 16, m_deviceOriginY
% 16 );
920 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, 0, 360*64 );
921 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
923 if (m_brush
.GetStyle() == wxSTIPPLE
)
925 gdk_gc_set_ts_origin( m_brushGC
,
926 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
927 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
928 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, 0, 360*64 );
929 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
933 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, 0, 360*64 );
937 if (m_pen
.GetStyle() != wxTRANSPARENT
)
938 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
, hh
, 0, 360*64 );
941 CalcBoundingBox( x
- width
, y
- height
);
942 CalcBoundingBox( x
+ width
, y
+ height
);
945 void wxWindowDC::DoDrawIcon( const wxIcon
&icon
, wxCoord x
, wxCoord y
)
947 // VZ: egcs 1.0.3 refuses to compile this without cast, no idea why
948 DoDrawBitmap( (const wxBitmap
&)icon
, x
, y
, (bool)TRUE
);
951 void wxWindowDC::DoDrawBitmap( const wxBitmap
&bitmap
,
952 wxCoord x
, wxCoord y
,
955 wxCHECK_RET( Ok(), wxT("invalid window dc") );
957 wxCHECK_RET( bitmap
.Ok(), wxT("invalid bitmap") );
959 bool is_mono
= (bitmap
.GetBitmap() != NULL
);
961 /* scale/translate size and position */
962 int xx
= XLOG2DEV(x
);
963 int yy
= YLOG2DEV(y
);
965 int w
= bitmap
.GetWidth();
966 int h
= bitmap
.GetHeight();
968 CalcBoundingBox( x
, y
);
969 CalcBoundingBox( x
+ w
, y
+ h
);
971 if (!m_window
) return;
973 int ww
= XLOG2DEVREL(w
);
974 int hh
= YLOG2DEVREL(h
);
976 /* compare to current clipping region */
977 if (!m_currentClippingRegion
.IsNull())
979 wxRegion
tmp( xx
,yy
,ww
,hh
);
980 tmp
.Intersect( m_currentClippingRegion
);
985 /* scale bitmap if required */
987 if ((w
!= ww
) || (h
!= hh
))
989 wxImage
image( bitmap
);
990 image
.Rescale( ww
, hh
);
992 use_bitmap
= image
.ConvertToMonoBitmap(255,255,255);
994 use_bitmap
= image
.ConvertToBitmap();
1001 /* apply mask if any */
1002 GdkBitmap
*mask
= (GdkBitmap
*) NULL
;
1003 if (use_bitmap
.GetMask()) mask
= use_bitmap
.GetMask()->GetBitmap();
1005 if (useMask
&& mask
)
1007 GdkBitmap
*new_mask
= (GdkBitmap
*) NULL
;
1008 if (!m_currentClippingRegion
.IsNull())
1011 new_mask
= gdk_pixmap_new( wxRootWindow
->window
, ww
, hh
, 1 );
1012 GdkGC
*gc
= gdk_gc_new( new_mask
);
1014 gdk_gc_set_foreground( gc
, &col
);
1015 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, ww
, hh
);
1017 gdk_gc_set_background( gc
, &col
);
1019 gdk_gc_set_foreground( gc
, &col
);
1020 gdk_gc_set_clip_region( gc
, m_currentClippingRegion
.GetRegion() );
1021 gdk_gc_set_clip_origin( gc
, -xx
, -yy
);
1022 gdk_gc_set_fill( gc
, GDK_OPAQUE_STIPPLED
);
1023 gdk_gc_set_stipple( gc
, mask
);
1024 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, ww
, hh
);
1031 gdk_gc_set_clip_mask( m_textGC
, new_mask
);
1033 gdk_gc_set_clip_mask( m_textGC
, mask
);
1034 gdk_gc_set_clip_origin( m_textGC
, xx
, yy
);
1039 gdk_gc_set_clip_mask( m_penGC
, new_mask
);
1041 gdk_gc_set_clip_mask( m_penGC
, mask
);
1042 gdk_gc_set_clip_origin( m_penGC
, xx
, yy
);
1045 gdk_bitmap_unref( new_mask
);
1048 /* Draw XPixmap or XBitmap, depending on what the wxBitmap contains. For
1049 drawing a mono-bitmap (XBitmap) we use the current text GC */
1051 gdk_wx_draw_bitmap( m_window
, m_textGC
, use_bitmap
.GetBitmap(), 0, 0, xx
, yy
, -1, -1 );
1053 gdk_draw_pixmap( m_window
, m_penGC
, use_bitmap
.GetPixmap(), 0, 0, xx
, yy
, -1, -1 );
1055 /* remove mask again if any */
1056 if (useMask
&& mask
)
1060 gdk_gc_set_clip_mask( m_textGC
, (GdkBitmap
*) NULL
);
1061 gdk_gc_set_clip_origin( m_textGC
, 0, 0 );
1062 if (!m_currentClippingRegion
.IsNull())
1063 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
1067 gdk_gc_set_clip_mask( m_penGC
, (GdkBitmap
*) NULL
);
1068 gdk_gc_set_clip_origin( m_penGC
, 0, 0 );
1069 if (!m_currentClippingRegion
.IsNull())
1070 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
1075 bool wxWindowDC::DoBlit( wxCoord xdest
, wxCoord ydest
, wxCoord width
, wxCoord height
,
1076 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
,
1077 int logical_func
, bool useMask
)
1079 /* this is the nth try to get this utterly useless function to
1080 work. it now completely ignores the scaling or translation
1081 of the source dc, but scales correctly on the target dc and
1082 knows about possible mask information in a memory dc. */
1084 wxCHECK_MSG( Ok(), FALSE
, wxT("invalid window dc") );
1086 wxCHECK_MSG( source
, FALSE
, wxT("invalid source dc") );
1088 if (!m_window
) return FALSE
;
1090 wxClientDC
*srcDC
= (wxClientDC
*)source
;
1091 wxMemoryDC
*memDC
= (wxMemoryDC
*)source
;
1093 bool use_bitmap_method
= FALSE
;
1094 bool is_mono
= FALSE
;
1096 if (srcDC
->m_isMemDC
)
1098 if (!memDC
->m_selected
.Ok()) return FALSE
;
1100 /* we use the "XCopyArea" way to copy a memory dc into
1101 y different window if the memory dc BOTH
1102 a) doesn't have any mask or its mask isn't used
1106 if (useMask
&& (memDC
->m_selected
.GetMask()))
1108 /* we HAVE TO use the direct way for memory dcs
1109 that have mask since the XCopyArea doesn't know
1111 use_bitmap_method
= TRUE
;
1113 else if (memDC
->m_selected
.GetDepth() == 1)
1115 /* we HAVE TO use the direct way for memory dcs
1116 that are bitmaps because XCopyArea doesn't cope
1117 with different bit depths */
1119 use_bitmap_method
= TRUE
;
1121 else if ((xsrc
== 0) && (ysrc
== 0) &&
1122 (width
== memDC
->m_selected
.GetWidth()) &&
1123 (height
== memDC
->m_selected
.GetHeight()))
1125 /* we SHOULD use the direct way if all of the bitmap
1126 in the memory dc is copied in which case XCopyArea
1127 wouldn't be able able to boost performace by reducing
1128 the area to be scaled */
1129 use_bitmap_method
= TRUE
;
1133 use_bitmap_method
= FALSE
;
1137 CalcBoundingBox( xdest
, ydest
);
1138 CalcBoundingBox( xdest
+ width
, ydest
+ height
);
1140 /* scale/translate size and position */
1141 wxCoord xx
= XLOG2DEV(xdest
);
1142 wxCoord yy
= YLOG2DEV(ydest
);
1144 wxCoord ww
= XLOG2DEVREL(width
);
1145 wxCoord hh
= YLOG2DEVREL(height
);
1147 /* compare to current clipping region */
1148 if (!m_currentClippingRegion
.IsNull())
1150 wxRegion
tmp( xx
,yy
,ww
,hh
);
1151 tmp
.Intersect( m_currentClippingRegion
);
1156 int old_logical_func
= m_logicalFunction
;
1157 SetLogicalFunction( logical_func
);
1159 if (use_bitmap_method
)
1161 /* scale/translate bitmap size */
1162 wxCoord bm_width
= memDC
->m_selected
.GetWidth();
1163 wxCoord bm_height
= memDC
->m_selected
.GetHeight();
1165 wxCoord bm_ww
= XLOG2DEVREL( bm_width
);
1166 wxCoord bm_hh
= YLOG2DEVREL( bm_height
);
1168 /* scale bitmap if required */
1169 wxBitmap use_bitmap
;
1171 if ((bm_width
!= bm_ww
) || (bm_height
!= bm_hh
))
1173 wxImage
image( memDC
->m_selected
);
1174 image
= image
.Scale( bm_ww
, bm_hh
);
1177 use_bitmap
= image
.ConvertToMonoBitmap(255,255,255);
1179 use_bitmap
= image
.ConvertToBitmap();
1183 use_bitmap
= memDC
->m_selected
;
1186 /* apply mask if any */
1187 GdkBitmap
*mask
= (GdkBitmap
*) NULL
;
1188 if (use_bitmap
.GetMask()) mask
= use_bitmap
.GetMask()->GetBitmap();
1190 if (useMask
&& mask
)
1192 GdkBitmap
*new_mask
= (GdkBitmap
*) NULL
;
1193 if (!m_currentClippingRegion
.IsNull())
1196 new_mask
= gdk_pixmap_new( wxRootWindow
->window
, bm_ww
, bm_hh
, 1 );
1197 GdkGC
*gc
= gdk_gc_new( new_mask
);
1199 gdk_gc_set_foreground( gc
, &col
);
1200 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, bm_ww
, bm_hh
);
1202 gdk_gc_set_background( gc
, &col
);
1204 gdk_gc_set_foreground( gc
, &col
);
1205 gdk_gc_set_clip_region( gc
, m_currentClippingRegion
.GetRegion() );
1206 gdk_gc_set_clip_origin( gc
, -xx
, -yy
);
1207 gdk_gc_set_fill( gc
, GDK_OPAQUE_STIPPLED
);
1208 gdk_gc_set_stipple( gc
, mask
);
1209 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, bm_ww
, bm_hh
);
1216 gdk_gc_set_clip_mask( m_textGC
, new_mask
);
1218 gdk_gc_set_clip_mask( m_textGC
, mask
);
1219 gdk_gc_set_clip_origin( m_textGC
, xx
, yy
);
1224 gdk_gc_set_clip_mask( m_penGC
, new_mask
);
1226 gdk_gc_set_clip_mask( m_penGC
, mask
);
1227 gdk_gc_set_clip_origin( m_penGC
, xx
, yy
);
1230 gdk_bitmap_unref( new_mask
);
1233 /* Draw XPixmap or XBitmap, depending on what the wxBitmap contains. For
1234 drawing a mono-bitmap (XBitmap) we use the current text GC */
1237 gdk_wx_draw_bitmap( m_window
, m_textGC
, use_bitmap
.GetBitmap(), xsrc
, ysrc
, xx
, yy
, ww
, hh
);
1239 gdk_draw_pixmap( m_window
, m_penGC
, use_bitmap
.GetPixmap(), xsrc
, ysrc
, xx
, yy
, ww
, hh
);
1241 /* remove mask again if any */
1242 if (useMask
&& mask
)
1246 gdk_gc_set_clip_mask( m_textGC
, (GdkBitmap
*) NULL
);
1247 gdk_gc_set_clip_origin( m_textGC
, 0, 0 );
1248 if (!m_currentClippingRegion
.IsNull())
1249 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
1253 gdk_gc_set_clip_mask( m_penGC
, (GdkBitmap
*) NULL
);
1254 gdk_gc_set_clip_origin( m_penGC
, 0, 0 );
1255 if (!m_currentClippingRegion
.IsNull())
1256 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
1260 else /* use_bitmap_method */
1262 if ((width
!= ww
) || (height
!= hh
))
1264 /* draw source window into a bitmap as we cannot scale
1265 a window in contrast to a bitmap. this would actually
1266 work with memory dcs as well, but we'd lose the mask
1267 information and waste one step in this process since
1268 a memory already has a bitmap. all this is slightly
1269 inefficient as we could take an XImage directly from
1270 an X window, but we'd then also have to care that
1271 the window is not outside the screen (in which case
1272 we'd get a BadMatch or what not).
1273 Is a double XGetImage and combined XGetPixel and
1274 XPutPixel really faster? I'm not sure. look at wxXt
1275 for a different implementation of the same problem. */
1277 wxBitmap
bitmap( width
, height
);
1279 /* copy including child window contents */
1280 gdk_gc_set_subwindow( m_penGC
, GDK_INCLUDE_INFERIORS
);
1281 gdk_window_copy_area( bitmap
.GetPixmap(), m_penGC
, 0, 0,
1283 xsrc
, ysrc
, width
, height
);
1284 gdk_gc_set_subwindow( m_penGC
, GDK_CLIP_BY_CHILDREN
);
1287 wxImage
image( bitmap
);
1288 image
= image
.Scale( ww
, hh
);
1290 /* convert to bitmap */
1291 bitmap
= image
.ConvertToBitmap();
1293 /* draw scaled bitmap */
1294 gdk_draw_pixmap( m_window
, m_penGC
, bitmap
.GetPixmap(), 0, 0, xx
, yy
, -1, -1 );
1299 /* No scaling and not a memory dc with a mask either */
1301 /* copy including child window contents */
1302 gdk_gc_set_subwindow( m_penGC
, GDK_INCLUDE_INFERIORS
);
1303 gdk_window_copy_area( m_window
, m_penGC
, xx
, yy
,
1305 xsrc
, ysrc
, width
, height
);
1306 gdk_gc_set_subwindow( m_penGC
, GDK_CLIP_BY_CHILDREN
);
1310 SetLogicalFunction( old_logical_func
);
1314 void wxWindowDC::DoDrawText( const wxString
&text
, wxCoord x
, wxCoord y
)
1316 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1318 if (!m_window
) return;
1320 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
1322 wxCHECK_RET( font
, wxT("invalid font") );
1325 wxCHECK_RET( m_context
, wxT("no Pango context") );
1332 /* FIXME: the layout engine should probably be abstracted at a higher level in wxDC... */
1333 PangoLayout
*layout
= pango_layout_new(m_context
);
1334 pango_layout_set_font_description(layout
, m_fontdesc
);
1336 wxWX2MBbuf data
= text
.mb_str(wxConvUTF8
);
1337 pango_layout_set_text(layout
, data
, strlen(data
));
1339 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
1340 PangoRectangle rect
;
1341 pango_layout_line_get_extents(line
, NULL
, &rect
);
1342 wxCoord width
= rect
.width
;
1343 wxCoord height
= rect
.height
;
1344 gdk_draw_layout( m_window
, m_textGC
, x
, y
, layout
);
1346 wxCoord width
= gdk_string_width( font
, text
.mbc_str() );
1347 wxCoord height
= font
->ascent
+ font
->descent
;
1348 /* CMB 21/5/98: draw text background if mode is wxSOLID */
1349 if (m_backgroundMode
== wxSOLID
)
1351 gdk_gc_set_foreground( m_textGC
, m_textBackgroundColour
.GetColor() );
1352 gdk_draw_rectangle( m_window
, m_textGC
, TRUE
, x
, y
, width
, height
);
1353 gdk_gc_set_foreground( m_textGC
, m_textForegroundColour
.GetColor() );
1355 gdk_draw_string( m_window
, font
, m_textGC
, x
, y
+ font
->ascent
, text
.mbc_str() );
1358 /* CMB 17/7/98: simple underline: ignores scaling and underlying
1359 X font's XA_UNDERLINE_POSITION and XA_UNDERLINE_THICKNESS
1360 properties (see wxXt implementation) */
1361 if (m_font
.GetUnderlined())
1363 wxCoord ul_y
= y
+ font
->ascent
;
1364 if (font
->descent
> 0) ul_y
++;
1365 gdk_draw_line( m_window
, m_textGC
, x
, ul_y
, x
+ width
, ul_y
);
1369 g_object_unref( G_OBJECT( layout
) );
1372 width
= wxCoord(width
/ m_scaleX
);
1373 height
= wxCoord(height
/ m_scaleY
);
1374 CalcBoundingBox (x
+ width
, y
+ height
);
1375 CalcBoundingBox (x
, y
);
1378 void wxWindowDC::DoDrawRotatedText( const wxString
&text
, wxCoord x
, wxCoord y
, double angle
)
1382 DrawText(text
, x
, y
);
1386 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1388 if (!m_window
) return;
1390 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
1392 wxCHECK_RET( font
, wxT("invalid font") );
1394 // the size of the text
1395 wxCoord w
= gdk_string_width( font
, text
.mbc_str() );
1396 wxCoord h
= font
->ascent
+ font
->descent
;
1398 // draw the string normally
1401 dc
.SelectObject(src
);
1402 dc
.SetFont(GetFont());
1403 dc
.SetBackground(*wxWHITE_BRUSH
);
1404 dc
.SetBrush(*wxBLACK_BRUSH
);
1406 dc
.DrawText(text
, 0, 0);
1407 dc
.SetFont(wxNullFont
);
1408 dc
.SelectObject(wxNullBitmap
);
1410 // Calculate the size of the rotated bounding box.
1411 double rad
= DegToRad(angle
);
1412 double dx
= cos(rad
),
1415 // the rectngle vertices are counted clockwise with the first one being at
1416 // (0, 0) (or, rather, at (x, y))
1418 y2
= -w
*dy
; // y axis points to the bottom, hence minus
1421 double x3
= x4
+ x2
,
1425 wxCoord maxX
= (wxCoord
)(dmax(x2
, dmax(x3
, x4
)) + 0.5),
1426 maxY
= (wxCoord
)(dmax(y2
, dmax(y3
, y4
)) + 0.5),
1427 minX
= (wxCoord
)(dmin(x2
, dmin(x3
, x4
)) - 0.5),
1428 minY
= (wxCoord
)(dmin(y2
, dmin(y3
, y4
)) - 0.5);
1430 // prepare to blit-with-rotate the bitmap to the DC
1433 GdkColor
*colText
= m_textForegroundColour
.GetColor(),
1434 *colBack
= m_textBackgroundColour
.GetColor();
1436 bool textColSet
= TRUE
;
1438 unsigned char *data
= image
.GetData();
1440 // paint pixel by pixel
1441 for ( wxCoord srcX
= 0; srcX
< w
; srcX
++ )
1443 for ( wxCoord srcY
= 0; srcY
< h
; srcY
++ )
1445 // transform source coords to dest coords
1446 double r
= sqrt((double)srcX
*srcX
+ srcY
*srcY
);
1447 double angleOrig
= atan2((double)srcY
, (double)srcX
) - rad
;
1448 wxCoord dstX
= (wxCoord
)(r
*cos(angleOrig
) + 0.5),
1449 dstY
= (wxCoord
)(r
*sin(angleOrig
) + 0.5);
1452 bool textPixel
= data
[(srcY
*w
+ srcX
)*3] == 0;
1453 if ( textPixel
|| (m_backgroundMode
== wxSOLID
) )
1455 // change colour if needed
1456 if ( textPixel
!= textColSet
)
1458 gdk_gc_set_foreground( m_textGC
, textPixel
? colText
1461 textColSet
= textPixel
;
1464 // don't use DrawPoint() because it uses the current pen
1465 // colour, and we don't need it here
1466 gdk_draw_point( m_window
, m_textGC
,
1467 XLOG2DEV(x
+ dstX
), YLOG2DEV(y
+ dstY
) );
1472 // it would be better to draw with non underlined font and draw the line
1473 // manually here (it would be more straight...)
1475 if ( m_font
.GetUnderlined() )
1477 gdk_draw_line( m_window
, m_textGC
,
1478 XLOG2DEV(x
+ x4
), YLOG2DEV(y
+ y4
+ font
->descent
),
1479 XLOG2DEV(x
+ x3
), YLOG2DEV(y
+ y3
+ font
->descent
));
1483 // restore the font colour
1484 gdk_gc_set_foreground( m_textGC
, colText
);
1486 // update the bounding box
1487 CalcBoundingBox(x
+ minX
, y
+ minY
);
1488 CalcBoundingBox(x
+ maxX
, y
+ maxY
);
1491 void wxWindowDC::DoGetTextExtent(const wxString
&string
,
1492 wxCoord
*width
, wxCoord
*height
,
1493 wxCoord
*descent
, wxCoord
*externalLeading
,
1494 wxFont
*theFont
) const
1496 wxFont fontToUse
= m_font
;
1497 if (theFont
) fontToUse
= *theFont
;
1499 GdkFont
*font
= fontToUse
.GetInternalFont( m_scaleY
);
1500 if (width
) (*width
) = wxCoord(gdk_string_width( font
, string
.mbc_str() ) / m_scaleX
);
1501 if (height
) (*height
) = wxCoord((font
->ascent
+ font
->descent
) / m_scaleY
);
1502 if (descent
) (*descent
) = wxCoord(font
->descent
/ m_scaleY
);
1503 if (externalLeading
) (*externalLeading
) = 0; // ??
1506 wxCoord
wxWindowDC::GetCharWidth() const
1508 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
1509 wxCHECK_MSG( font
, -1, wxT("invalid font") );
1511 return wxCoord(gdk_string_width( font
, "H" ) / m_scaleX
);
1514 wxCoord
wxWindowDC::GetCharHeight() const
1516 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
1517 wxCHECK_MSG( font
, -1, wxT("invalid font") );
1519 return wxCoord((font
->ascent
+ font
->descent
) / m_scaleY
);
1522 void wxWindowDC::Clear()
1524 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1526 if (!m_window
) return;
1528 /* - we either are a memory dc or have a window as the
1529 owner. anything else shouldn't happen.
1530 - we don't use gdk_window_clear() as we don't set
1531 the window's background colour anymore. it is too
1532 much pain to keep the DC's and the window's back-
1533 ground colour in synch. */
1538 m_owner
->GetSize( &width
, &height
);
1539 gdk_draw_rectangle( m_window
, m_bgGC
, TRUE
, 0, 0, width
, height
);
1546 GetSize( &width
, &height
);
1547 gdk_draw_rectangle( m_window
, m_bgGC
, TRUE
, 0, 0, width
, height
);
1552 void wxWindowDC::SetFont( const wxFont
&font
)
1560 void wxWindowDC::SetPen( const wxPen
&pen
)
1562 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1564 if (m_pen
== pen
) return;
1568 if (!m_pen
.Ok()) return;
1570 if (!m_window
) return;
1572 gint width
= m_pen
.GetWidth();
1575 // CMB: if width is non-zero scale it with the dc
1580 // X doesn't allow different width in x and y and so we take
1583 ( fabs((double) XLOG2DEVREL(width
)) +
1584 fabs((double) YLOG2DEVREL(width
)) ) / 2.0;
1588 static const wxGTKDash dotted
[] = {1, 1};
1589 static const wxGTKDash short_dashed
[] = {2, 2};
1590 static const wxGTKDash wxCoord_dashed
[] = {2, 4};
1591 static const wxGTKDash dotted_dashed
[] = {3, 3, 1, 3};
1593 // We express dash pattern in pen width unit, so we are
1594 // independent of zoom factor and so on...
1596 const wxGTKDash
*req_dash
;
1598 GdkLineStyle lineStyle
= GDK_LINE_SOLID
;
1599 switch (m_pen
.GetStyle())
1603 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1604 req_nb_dash
= m_pen
.GetDashCount();
1605 req_dash
= (wxGTKDash
*)m_pen
.GetDash();
1610 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1617 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1619 req_dash
= wxCoord_dashed
;
1624 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1626 req_dash
= short_dashed
;
1631 // lineStyle = GDK_LINE_DOUBLE_DASH;
1632 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1634 req_dash
= dotted_dashed
;
1639 case wxSTIPPLE_MASK_OPAQUE
:
1644 lineStyle
= GDK_LINE_SOLID
;
1645 req_dash
= (wxGTKDash
*)NULL
;
1651 #if (GTK_MINOR_VERSION > 0) || (GTK_MAJOR_VERSION > 1)
1652 if (req_dash
&& req_nb_dash
)
1654 wxGTKDash
*real_req_dash
= new wxGTKDash
[req_nb_dash
];
1657 for (int i
= 0; i
< req_nb_dash
; i
++)
1658 real_req_dash
[i
] = req_dash
[i
] * width
;
1659 gdk_gc_set_dashes( m_penGC
, 0, real_req_dash
, req_nb_dash
);
1660 delete[] real_req_dash
;
1664 // No Memory. We use non-scaled dash pattern...
1665 gdk_gc_set_dashes( m_penGC
, 0, (wxGTKDash
*)req_dash
, req_nb_dash
);
1670 GdkCapStyle capStyle
= GDK_CAP_ROUND
;
1671 switch (m_pen
.GetCap())
1673 case wxCAP_PROJECTING
: { capStyle
= GDK_CAP_PROJECTING
; break; }
1674 case wxCAP_BUTT
: { capStyle
= GDK_CAP_BUTT
; break; }
1681 capStyle
= GDK_CAP_NOT_LAST
;
1685 capStyle
= GDK_CAP_ROUND
;
1691 GdkJoinStyle joinStyle
= GDK_JOIN_ROUND
;
1692 switch (m_pen
.GetJoin())
1694 case wxJOIN_BEVEL
: { joinStyle
= GDK_JOIN_BEVEL
; break; }
1695 case wxJOIN_MITER
: { joinStyle
= GDK_JOIN_MITER
; break; }
1697 default: { joinStyle
= GDK_JOIN_ROUND
; break; }
1700 gdk_gc_set_line_attributes( m_penGC
, width
, lineStyle
, capStyle
, joinStyle
);
1702 m_pen
.GetColour().CalcPixel( m_cmap
);
1703 gdk_gc_set_foreground( m_penGC
, m_pen
.GetColour().GetColor() );
1706 void wxWindowDC::SetBrush( const wxBrush
&brush
)
1708 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1710 if (m_brush
== brush
) return;
1714 if (!m_brush
.Ok()) return;
1716 if (!m_window
) return;
1718 m_brush
.GetColour().CalcPixel( m_cmap
);
1719 gdk_gc_set_foreground( m_brushGC
, m_brush
.GetColour().GetColor() );
1721 gdk_gc_set_fill( m_brushGC
, GDK_SOLID
);
1723 if ((m_brush
.GetStyle() == wxSTIPPLE
) && (m_brush
.GetStipple()->Ok()))
1725 if (m_brush
.GetStipple()->GetPixmap())
1727 gdk_gc_set_fill( m_brushGC
, GDK_TILED
);
1728 gdk_gc_set_tile( m_brushGC
, m_brush
.GetStipple()->GetPixmap() );
1732 gdk_gc_set_fill( m_brushGC
, GDK_STIPPLED
);
1733 gdk_gc_set_stipple( m_brushGC
, m_brush
.GetStipple()->GetBitmap() );
1737 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
1739 gdk_gc_set_fill( m_textGC
, GDK_OPAQUE_STIPPLED
);
1740 gdk_gc_set_stipple( m_textGC
, m_brush
.GetStipple()->GetMask()->GetBitmap() );
1743 if (IS_HATCH(m_brush
.GetStyle()))
1745 gdk_gc_set_fill( m_brushGC
, GDK_STIPPLED
);
1746 int num
= m_brush
.GetStyle() - wxBDIAGONAL_HATCH
;
1747 gdk_gc_set_stipple( m_brushGC
, hatches
[num
] );
1751 void wxWindowDC::SetBackground( const wxBrush
&brush
)
1753 /* CMB 21/7/98: Added SetBackground. Sets background brush
1754 * for Clear() and bg colour for shapes filled with cross-hatch brush */
1756 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1758 if (m_backgroundBrush
== brush
) return;
1760 m_backgroundBrush
= brush
;
1762 if (!m_backgroundBrush
.Ok()) return;
1764 if (!m_window
) return;
1766 m_backgroundBrush
.GetColour().CalcPixel( m_cmap
);
1767 gdk_gc_set_background( m_brushGC
, m_backgroundBrush
.GetColour().GetColor() );
1768 gdk_gc_set_background( m_penGC
, m_backgroundBrush
.GetColour().GetColor() );
1769 gdk_gc_set_background( m_bgGC
, m_backgroundBrush
.GetColour().GetColor() );
1770 gdk_gc_set_foreground( m_bgGC
, m_backgroundBrush
.GetColour().GetColor() );
1772 gdk_gc_set_fill( m_bgGC
, GDK_SOLID
);
1774 if ((m_backgroundBrush
.GetStyle() == wxSTIPPLE
) && (m_backgroundBrush
.GetStipple()->Ok()))
1776 if (m_backgroundBrush
.GetStipple()->GetPixmap())
1778 gdk_gc_set_fill( m_bgGC
, GDK_TILED
);
1779 gdk_gc_set_tile( m_bgGC
, m_backgroundBrush
.GetStipple()->GetPixmap() );
1783 gdk_gc_set_fill( m_bgGC
, GDK_STIPPLED
);
1784 gdk_gc_set_stipple( m_bgGC
, m_backgroundBrush
.GetStipple()->GetBitmap() );
1788 if (IS_HATCH(m_backgroundBrush
.GetStyle()))
1790 gdk_gc_set_fill( m_bgGC
, GDK_STIPPLED
);
1791 int num
= m_backgroundBrush
.GetStyle() - wxBDIAGONAL_HATCH
;
1792 gdk_gc_set_stipple( m_bgGC
, hatches
[num
] );
1796 void wxWindowDC::SetLogicalFunction( int function
)
1798 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1800 if (m_logicalFunction
== function
)
1803 // VZ: shouldn't this be a CHECK?
1807 GdkFunction mode
= GDK_COPY
;
1810 case wxXOR
: mode
= GDK_XOR
; break;
1811 case wxINVERT
: mode
= GDK_INVERT
; break;
1812 #if (GTK_MINOR_VERSION > 0)
1813 case wxOR_REVERSE
: mode
= GDK_OR_REVERSE
; break;
1814 case wxAND_REVERSE
: mode
= GDK_AND_REVERSE
; break;
1815 case wxCLEAR
: mode
= GDK_CLEAR
; break;
1816 case wxSET
: mode
= GDK_SET
; break;
1817 case wxOR_INVERT
: mode
= GDK_OR_INVERT
; break;
1818 case wxAND
: mode
= GDK_AND
; break;
1819 case wxOR
: mode
= GDK_OR
; break;
1820 case wxEQUIV
: mode
= GDK_EQUIV
; break;
1821 case wxNAND
: mode
= GDK_NAND
; break;
1822 case wxAND_INVERT
: mode
= GDK_AND_INVERT
; break;
1823 case wxCOPY
: mode
= GDK_COPY
; break;
1824 case wxNO_OP
: mode
= GDK_NOOP
; break;
1825 case wxSRC_INVERT
: mode
= GDK_COPY_INVERT
; break;
1827 // unsupported by GTK
1828 case wxNOR
: mode
= GDK_COPY
; break;
1832 wxFAIL_MSG( wxT("unsupported logical function") );
1837 m_logicalFunction
= function
;
1839 gdk_gc_set_function( m_penGC
, mode
);
1840 gdk_gc_set_function( m_brushGC
, mode
);
1842 // to stay compatible with wxMSW, we don't apply ROPs to the text
1843 // operations (i.e. DrawText/DrawRotatedText).
1844 // True, but mono-bitmaps use the m_textGC and they use ROPs as well.
1845 gdk_gc_set_function( m_textGC
, mode
);
1848 void wxWindowDC::SetTextForeground( const wxColour
&col
)
1850 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1852 if (m_textForegroundColour
== col
) return;
1854 m_textForegroundColour
= col
;
1855 if (!m_textForegroundColour
.Ok()) return;
1857 if (!m_window
) return;
1859 m_textForegroundColour
.CalcPixel( m_cmap
);
1860 gdk_gc_set_foreground( m_textGC
, m_textForegroundColour
.GetColor() );
1863 void wxWindowDC::SetTextBackground( const wxColour
&col
)
1865 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1867 if (m_textBackgroundColour
== col
) return;
1869 m_textBackgroundColour
= col
;
1870 if (!m_textBackgroundColour
.Ok()) return;
1872 if (!m_window
) return;
1874 m_textBackgroundColour
.CalcPixel( m_cmap
);
1875 gdk_gc_set_background( m_textGC
, m_textBackgroundColour
.GetColor() );
1878 void wxWindowDC::SetBackgroundMode( int mode
)
1880 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1882 m_backgroundMode
= mode
;
1884 if (!m_window
) return;
1886 // CMB 21/7/98: fill style of cross-hatch brushes is affected by
1887 // transparent/solid background mode
1889 if (m_brush
.GetStyle() != wxSOLID
&& m_brush
.GetStyle() != wxTRANSPARENT
)
1891 gdk_gc_set_fill( m_brushGC
,
1892 (m_backgroundMode
== wxTRANSPARENT
) ? GDK_STIPPLED
: GDK_OPAQUE_STIPPLED
);
1896 void wxWindowDC::SetPalette( const wxPalette
& WXUNUSED(palette
) )
1898 wxFAIL_MSG( wxT("wxWindowDC::SetPalette not implemented") );
1901 void wxWindowDC::DoSetClippingRegion( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
1903 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1905 if (!m_window
) return;
1908 rect
.x
= XLOG2DEV(x
);
1909 rect
.y
= YLOG2DEV(y
);
1910 rect
.width
= XLOG2DEVREL(width
);
1911 rect
.height
= YLOG2DEVREL(height
);
1913 if (!m_currentClippingRegion
.IsNull())
1914 m_currentClippingRegion
.Intersect( rect
);
1916 m_currentClippingRegion
.Union( rect
);
1918 #if USE_PAINT_REGION
1919 if (!m_paintClippingRegion
.IsNull())
1920 m_currentClippingRegion
.Intersect( m_paintClippingRegion
);
1923 wxCoord xx
, yy
, ww
, hh
;
1924 m_currentClippingRegion
.GetBox( xx
, yy
, ww
, hh
);
1925 wxDC::DoSetClippingRegion( xx
, yy
, ww
, hh
);
1927 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
1928 gdk_gc_set_clip_region( m_brushGC
, m_currentClippingRegion
.GetRegion() );
1929 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
1930 gdk_gc_set_clip_region( m_bgGC
, m_currentClippingRegion
.GetRegion() );
1933 void wxWindowDC::DoSetClippingRegionAsRegion( const wxRegion
®ion
)
1935 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1939 DestroyClippingRegion();
1943 if (!m_window
) return;
1945 if (!m_currentClippingRegion
.IsNull())
1946 m_currentClippingRegion
.Intersect( region
);
1948 m_currentClippingRegion
.Union( region
);
1950 #if USE_PAINT_REGION
1951 if (!m_paintClippingRegion
.IsNull())
1952 m_currentClippingRegion
.Intersect( m_paintClippingRegion
);
1955 wxCoord xx
, yy
, ww
, hh
;
1956 m_currentClippingRegion
.GetBox( xx
, yy
, ww
, hh
);
1957 wxDC::DoSetClippingRegion( xx
, yy
, ww
, hh
);
1959 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
1960 gdk_gc_set_clip_region( m_brushGC
, m_currentClippingRegion
.GetRegion() );
1961 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
1962 gdk_gc_set_clip_region( m_bgGC
, m_currentClippingRegion
.GetRegion() );
1965 void wxWindowDC::DestroyClippingRegion()
1967 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1969 wxDC::DestroyClippingRegion();
1971 m_currentClippingRegion
.Clear();
1973 #if USE_PAINT_REGION
1974 if (!m_paintClippingRegion
.IsEmpty())
1975 m_currentClippingRegion
.Union( m_paintClippingRegion
);
1978 if (!m_window
) return;
1980 if (m_currentClippingRegion
.IsEmpty())
1982 gdk_gc_set_clip_rectangle( m_penGC
, (GdkRectangle
*) NULL
);
1983 gdk_gc_set_clip_rectangle( m_brushGC
, (GdkRectangle
*) NULL
);
1984 gdk_gc_set_clip_rectangle( m_textGC
, (GdkRectangle
*) NULL
);
1985 gdk_gc_set_clip_rectangle( m_bgGC
, (GdkRectangle
*) NULL
);
1989 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
1990 gdk_gc_set_clip_region( m_brushGC
, m_currentClippingRegion
.GetRegion() );
1991 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
1992 gdk_gc_set_clip_region( m_bgGC
, m_currentClippingRegion
.GetRegion() );
1996 void wxWindowDC::Destroy()
1998 if (m_penGC
) wxFreePoolGC( m_penGC
);
1999 m_penGC
= (GdkGC
*) NULL
;
2000 if (m_brushGC
) wxFreePoolGC( m_brushGC
);
2001 m_brushGC
= (GdkGC
*) NULL
;
2002 if (m_textGC
) wxFreePoolGC( m_textGC
);
2003 m_textGC
= (GdkGC
*) NULL
;
2004 if (m_bgGC
) wxFreePoolGC( m_bgGC
);
2005 m_bgGC
= (GdkGC
*) NULL
;
2008 void wxWindowDC::ComputeScaleAndOrigin()
2010 /* CMB: copy scale to see if it changes */
2011 double origScaleX
= m_scaleX
;
2012 double origScaleY
= m_scaleY
;
2014 wxDC::ComputeScaleAndOrigin();
2016 /* CMB: if scale has changed call SetPen to recalulate the line width */
2017 if ((m_scaleX
!= origScaleX
|| m_scaleY
!= origScaleY
) &&
2020 /* this is a bit artificial, but we need to force wxDC to think
2021 the pen has changed */
2028 // Resolution in pixels per logical inch
2029 wxSize
wxWindowDC::GetPPI() const
2031 return wxSize(100, 100);
2034 int wxWindowDC::GetDepth() const
2036 wxFAIL_MSG(wxT("not implemented"));
2042 // ----------------------------------- spline code ----------------------------------------
2044 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
2045 double a3
, double b3
, double a4
, double b4
);
2046 void wx_clear_stack();
2047 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
2048 double *y3
, double *x4
, double *y4
);
2049 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
2050 double x4
, double y4
);
2051 static bool wx_spline_add_point(double x
, double y
);
2052 static void wx_spline_draw_point_array(wxDC
*dc
);
2054 wxList wx_spline_point_list
;
2056 #define half(z1, z2) ((z1+z2)/2.0)
2059 /* iterative version */
2061 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
2064 register double xmid
, ymid
;
2065 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
2068 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
2070 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
2071 xmid
= (double)half(x2
, x3
);
2072 ymid
= (double)half(y2
, y3
);
2073 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
2074 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
2075 wx_spline_add_point( x1
, y1
);
2076 wx_spline_add_point( xmid
, ymid
);
2078 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
2079 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
2080 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
2081 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
2086 /* utilities used by spline drawing routines */
2088 typedef struct wx_spline_stack_struct
{
2089 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
2092 #define SPLINE_STACK_DEPTH 20
2093 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
2094 static Stack
*wx_stack_top
;
2095 static int wx_stack_count
;
2097 void wx_clear_stack()
2099 wx_stack_top
= wx_spline_stack
;
2103 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
2105 wx_stack_top
->x1
= x1
;
2106 wx_stack_top
->y1
= y1
;
2107 wx_stack_top
->x2
= x2
;
2108 wx_stack_top
->y2
= y2
;
2109 wx_stack_top
->x3
= x3
;
2110 wx_stack_top
->y3
= y3
;
2111 wx_stack_top
->x4
= x4
;
2112 wx_stack_top
->y4
= y4
;
2117 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
2118 double *x3
, double *y3
, double *x4
, double *y4
)
2120 if (wx_stack_count
== 0)
2124 *x1
= wx_stack_top
->x1
;
2125 *y1
= wx_stack_top
->y1
;
2126 *x2
= wx_stack_top
->x2
;
2127 *y2
= wx_stack_top
->y2
;
2128 *x3
= wx_stack_top
->x3
;
2129 *y3
= wx_stack_top
->y3
;
2130 *x4
= wx_stack_top
->x4
;
2131 *y4
= wx_stack_top
->y4
;
2135 static bool wx_spline_add_point(double x
, double y
)
2137 wxPoint
*point
= new wxPoint
;
2140 wx_spline_point_list
.Append((wxObject
*)point
);
2144 static void wx_spline_draw_point_array(wxDC
*dc
)
2146 dc
->DrawLines(&wx_spline_point_list
, 0, 0 );
2147 wxNode
*node
= wx_spline_point_list
.First();
2150 wxPoint
*point
= (wxPoint
*)node
->Data();
2153 node
= wx_spline_point_list
.First();
2157 void wxWindowDC::DoDrawSpline( wxList
*points
)
2159 wxCHECK_RET( Ok(), wxT("invalid window dc") );
2162 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
2163 double x1
, y1
, x2
, y2
;
2165 wxNode
*node
= points
->First();
2166 p
= (wxPoint
*)node
->Data();
2171 node
= node
->Next();
2172 p
= (wxPoint
*)node
->Data();
2176 cx1
= (double)((x1
+ x2
) / 2);
2177 cy1
= (double)((y1
+ y2
) / 2);
2178 cx2
= (double)((cx1
+ x2
) / 2);
2179 cy2
= (double)((cy1
+ y2
) / 2);
2181 wx_spline_add_point(x1
, y1
);
2183 while ((node
= node
->Next()) != NULL
)
2185 p
= (wxPoint
*)node
->Data();
2190 cx4
= (double)(x1
+ x2
) / 2;
2191 cy4
= (double)(y1
+ y2
) / 2;
2192 cx3
= (double)(x1
+ cx4
) / 2;
2193 cy3
= (double)(y1
+ cy4
) / 2;
2195 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
2199 cx2
= (double)(cx1
+ x2
) / 2;
2200 cy2
= (double)(cy1
+ y2
) / 2;
2203 wx_spline_add_point( cx1
, cy1
);
2204 wx_spline_add_point( x2
, y2
);
2206 wx_spline_draw_point_array( this );
2209 #endif // wxUSE_SPLINE
2211 //-----------------------------------------------------------------------------
2213 //-----------------------------------------------------------------------------
2215 IMPLEMENT_DYNAMIC_CLASS(wxPaintDC
,wxWindowDC
)
2217 wxPaintDC::wxPaintDC()
2222 wxPaintDC::wxPaintDC( wxWindow
*win
)
2225 #if USE_PAINT_REGION
2226 if (!win
->m_clipPaintRegion
)
2229 m_paintClippingRegion
= win
->GetUpdateRegion();
2230 GdkRegion
*region
= m_paintClippingRegion
.GetRegion();
2233 m_currentClippingRegion
.Union( m_paintClippingRegion
);
2235 gdk_gc_set_clip_region( m_penGC
, region
);
2236 gdk_gc_set_clip_region( m_brushGC
, region
);
2237 gdk_gc_set_clip_region( m_textGC
, region
);
2238 gdk_gc_set_clip_region( m_bgGC
, region
);
2243 //-----------------------------------------------------------------------------
2245 //-----------------------------------------------------------------------------
2247 IMPLEMENT_DYNAMIC_CLASS(wxClientDC
,wxWindowDC
)
2249 wxClientDC::wxClientDC()
2254 wxClientDC::wxClientDC( wxWindow
*win
)
2259 // ----------------------------------------------------------------------------
2261 // ----------------------------------------------------------------------------
2263 class wxDCModule
: public wxModule
2270 DECLARE_DYNAMIC_CLASS(wxDCModule
)
2273 IMPLEMENT_DYNAMIC_CLASS(wxDCModule
, wxModule
)
2275 bool wxDCModule::OnInit()
2281 void wxDCModule::OnExit()