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
)
530 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xxc
-r
, yyc
-r
, 2*r
,2*r
, alpha1
, alpha2
);
532 gdk_draw_line( m_window
, m_penGC
, xx1
, yy1
, xxc
, yyc
);
533 gdk_draw_line( m_window
, m_penGC
, xxc
, yyc
, xx2
, yy2
);
537 CalcBoundingBox (x1
, y1
);
538 CalcBoundingBox (x2
, y2
);
541 void wxWindowDC::DoDrawEllipticArc( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double sa
, double ea
)
543 wxCHECK_RET( Ok(), wxT("invalid window dc") );
545 wxCoord xx
= XLOG2DEV(x
);
546 wxCoord yy
= YLOG2DEV(y
);
547 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
548 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
550 // CMB: handle -ve width and/or height
551 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
552 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
556 wxCoord start
= wxCoord(sa
* 64.0);
557 wxCoord end
= wxCoord((ea
-sa
) * 64.0);
559 if (m_brush
.GetStyle() != wxTRANSPARENT
)
561 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
563 gdk_gc_set_ts_origin( m_textGC
,
564 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
565 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
566 gdk_draw_arc( m_window
, m_textGC
, TRUE
, xx
, yy
, ww
, hh
, start
, end
);
567 gdk_gc_set_ts_origin( m_textGC
, 0, 0 );
569 if (IS_15_PIX_HATCH(m_brush
.GetStyle()))
571 gdk_gc_set_ts_origin( m_brushGC
, m_deviceOriginX
% 15, m_deviceOriginY
% 15 );
572 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, start
, end
);
573 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
575 if (IS_16_PIX_HATCH(m_brush
.GetStyle()))
577 gdk_gc_set_ts_origin( m_brushGC
, m_deviceOriginX
% 16, m_deviceOriginY
% 16 );
578 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, start
, end
);
579 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
581 if (m_brush
.GetStyle() == wxSTIPPLE
)
583 gdk_gc_set_ts_origin( m_brushGC
,
584 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
585 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
586 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, start
, end
);
587 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
591 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, start
, end
);
595 if (m_pen
.GetStyle() != wxTRANSPARENT
)
596 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
, hh
, start
, end
);
599 CalcBoundingBox (x
, y
);
600 CalcBoundingBox (x
+ width
, y
+ height
);
603 void wxWindowDC::DoDrawPoint( wxCoord x
, wxCoord y
)
605 wxCHECK_RET( Ok(), wxT("invalid window dc") );
607 if ((m_pen
.GetStyle() != wxTRANSPARENT
) && m_window
)
608 gdk_draw_point( m_window
, m_penGC
, XLOG2DEV(x
), YLOG2DEV(y
) );
610 CalcBoundingBox (x
, y
);
613 void wxWindowDC::DoDrawLines( int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
615 wxCHECK_RET( Ok(), wxT("invalid window dc") );
617 if (m_pen
.GetStyle() == wxTRANSPARENT
) return;
620 CalcBoundingBox( points
[0].x
+ xoffset
, points
[0].y
+ yoffset
);
622 for (int i
= 0; i
< n
-1; i
++)
624 wxCoord x1
= XLOG2DEV(points
[i
].x
+ xoffset
);
625 wxCoord x2
= XLOG2DEV(points
[i
+1].x
+ xoffset
);
626 wxCoord y1
= YLOG2DEV(points
[i
].y
+ yoffset
); // oh, what a waste
627 wxCoord y2
= YLOG2DEV(points
[i
+1].y
+ yoffset
);
630 gdk_draw_line( m_window
, m_penGC
, x1
, y1
, x2
, y2
);
632 CalcBoundingBox( points
[i
+1].x
+ xoffset
, points
[i
+1].y
+ yoffset
);
636 void wxWindowDC::DoDrawPolygon( int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
, int WXUNUSED(fillStyle
) )
638 wxCHECK_RET( Ok(), wxT("invalid window dc") );
642 GdkPoint
*gdkpoints
= new GdkPoint
[n
+1];
644 for (i
= 0 ; i
< n
; i
++)
646 gdkpoints
[i
].x
= XLOG2DEV(points
[i
].x
+ xoffset
);
647 gdkpoints
[i
].y
= YLOG2DEV(points
[i
].y
+ yoffset
);
649 CalcBoundingBox( points
[i
].x
+ xoffset
, points
[i
].y
+ yoffset
);
654 if (m_brush
.GetStyle() != wxTRANSPARENT
)
656 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
658 gdk_gc_set_ts_origin( m_textGC
,
659 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
660 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
661 gdk_draw_polygon( m_window
, m_textGC
, TRUE
, gdkpoints
, n
);
662 gdk_gc_set_ts_origin( m_textGC
, 0, 0 );
664 if (IS_15_PIX_HATCH(m_brush
.GetStyle()))
666 gdk_gc_set_ts_origin( m_brushGC
, m_deviceOriginX
% 15, m_deviceOriginY
% 15 );
667 gdk_draw_polygon( m_window
, m_brushGC
, TRUE
, gdkpoints
, n
);
668 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
670 if (IS_16_PIX_HATCH(m_brush
.GetStyle()))
672 gdk_gc_set_ts_origin( m_brushGC
, m_deviceOriginX
% 16, m_deviceOriginY
% 16 );
673 gdk_draw_polygon( m_window
, m_brushGC
, TRUE
, gdkpoints
, n
);
674 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
676 if (m_brush
.GetStyle() == wxSTIPPLE
)
678 gdk_gc_set_ts_origin( m_brushGC
,
679 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
680 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
681 gdk_draw_polygon( m_window
, m_brushGC
, TRUE
, gdkpoints
, n
);
682 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
686 gdk_draw_polygon( m_window
, m_brushGC
, TRUE
, gdkpoints
, n
);
690 if (m_pen
.GetStyle() != wxTRANSPARENT
)
692 for (i
= 0 ; i
< n
; i
++)
694 gdk_draw_line( m_window
, m_penGC
,
697 gdkpoints
[(i
+1)%n
].x
,
698 gdkpoints
[(i
+1)%n
].y
);
706 void wxWindowDC::DoDrawRectangle( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
708 wxCHECK_RET( Ok(), wxT("invalid window dc") );
710 wxCoord xx
= XLOG2DEV(x
);
711 wxCoord yy
= YLOG2DEV(y
);
712 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
713 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
715 // CMB: draw nothing if transformed w or h is 0
716 if (ww
== 0 || hh
== 0) return;
718 // CMB: handle -ve width and/or height
719 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
720 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
724 if (m_brush
.GetStyle() != wxTRANSPARENT
)
726 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
728 gdk_gc_set_ts_origin( m_textGC
,
729 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
730 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
731 gdk_draw_rectangle( m_window
, m_textGC
, TRUE
, xx
, yy
, ww
, hh
);
732 gdk_gc_set_ts_origin( m_textGC
, 0, 0 );
734 if (IS_15_PIX_HATCH(m_brush
.GetStyle()))
736 gdk_gc_set_ts_origin( m_brushGC
, m_deviceOriginX
% 15, m_deviceOriginY
% 15 );
737 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
);
738 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
740 if (IS_16_PIX_HATCH(m_brush
.GetStyle()))
742 gdk_gc_set_ts_origin( m_brushGC
, m_deviceOriginX
% 16, m_deviceOriginY
% 16 );
743 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
);
744 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
746 if (m_brush
.GetStyle() == wxSTIPPLE
)
748 gdk_gc_set_ts_origin( m_brushGC
,
749 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
750 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
751 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
);
752 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
756 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
);
760 if (m_pen
.GetStyle() != wxTRANSPARENT
)
761 gdk_draw_rectangle( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
-1, hh
-1 );
764 CalcBoundingBox( x
, y
);
765 CalcBoundingBox( x
+ width
, y
+ height
);
768 void wxWindowDC::DoDrawRoundedRectangle( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
770 wxCHECK_RET( Ok(), wxT("invalid window dc") );
772 if (radius
< 0.0) radius
= - radius
* ((width
< height
) ? width
: height
);
774 wxCoord xx
= XLOG2DEV(x
);
775 wxCoord yy
= YLOG2DEV(y
);
776 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
777 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
778 wxCoord rr
= XLOG2DEVREL((wxCoord
)radius
);
780 // CMB: handle -ve width and/or height
781 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
782 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
784 // CMB: if radius is zero use DrawRectangle() instead to avoid
785 // X drawing errors with small radii
788 DrawRectangle( x
, y
, width
, height
);
792 // CMB: draw nothing if transformed w or h is 0
793 if (ww
== 0 || hh
== 0) return;
795 // CMB: adjust size if outline is drawn otherwise the result is
796 // 1 pixel too wide and high
797 if (m_pen
.GetStyle() != wxTRANSPARENT
)
805 // CMB: ensure dd is not larger than rectangle otherwise we
806 // get an hour glass shape
808 if (dd
> ww
) dd
= ww
;
809 if (dd
> hh
) dd
= hh
;
812 if (m_brush
.GetStyle() != wxTRANSPARENT
)
814 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
816 gdk_gc_set_ts_origin( m_textGC
,
817 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
818 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
819 gdk_draw_rectangle( m_window
, m_textGC
, TRUE
, xx
+rr
, yy
, ww
-dd
+1, hh
);
820 gdk_draw_rectangle( m_window
, m_textGC
, TRUE
, xx
, yy
+rr
, ww
, hh
-dd
+1 );
821 gdk_draw_arc( m_window
, m_textGC
, TRUE
, xx
, yy
, dd
, dd
, 90*64, 90*64 );
822 gdk_draw_arc( m_window
, m_textGC
, TRUE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 );
823 gdk_draw_arc( m_window
, m_textGC
, TRUE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 );
824 gdk_draw_arc( m_window
, m_textGC
, TRUE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 );
825 gdk_gc_set_ts_origin( m_textGC
, 0, 0 );
827 if (IS_15_PIX_HATCH(m_brush
.GetStyle()))
829 gdk_gc_set_ts_origin( m_brushGC
, m_deviceOriginX
% 15, m_deviceOriginY
% 15 );
830 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
+rr
, yy
, ww
-dd
+1, hh
);
831 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
+rr
, ww
, hh
-dd
+1 );
832 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, dd
, dd
, 90*64, 90*64 );
833 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 );
834 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 );
835 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 );
836 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
838 if (IS_16_PIX_HATCH(m_brush
.GetStyle()))
840 gdk_gc_set_ts_origin( m_brushGC
, m_deviceOriginX
% 16, m_deviceOriginY
% 16 );
841 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
+rr
, yy
, ww
-dd
+1, hh
);
842 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
+rr
, ww
, hh
-dd
+1 );
843 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, dd
, dd
, 90*64, 90*64 );
844 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 );
845 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 );
846 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 );
847 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
849 if (m_brush
.GetStyle() == wxSTIPPLE
)
851 gdk_gc_set_ts_origin( m_brushGC
,
852 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
853 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
854 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
+rr
, yy
, ww
-dd
+1, hh
);
855 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
+rr
, ww
, hh
-dd
+1 );
856 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, dd
, dd
, 90*64, 90*64 );
857 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 );
858 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 );
859 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 );
860 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
864 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
+rr
, yy
, ww
-dd
+1, hh
);
865 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
+rr
, ww
, hh
-dd
+1 );
866 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, dd
, dd
, 90*64, 90*64 );
867 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 );
868 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 );
869 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 );
873 if (m_pen
.GetStyle() != wxTRANSPARENT
)
875 gdk_draw_line( m_window
, m_penGC
, xx
+rr
+1, yy
, xx
+ww
-rr
, yy
);
876 gdk_draw_line( m_window
, m_penGC
, xx
+rr
+1, yy
+hh
, xx
+ww
-rr
, yy
+hh
);
877 gdk_draw_line( m_window
, m_penGC
, xx
, yy
+rr
+1, xx
, yy
+hh
-rr
);
878 gdk_draw_line( m_window
, m_penGC
, xx
+ww
, yy
+rr
+1, xx
+ww
, yy
+hh
-rr
);
879 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
, dd
, dd
, 90*64, 90*64 );
880 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 );
881 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 );
882 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 );
886 // this ignores the radius
887 CalcBoundingBox( x
, y
);
888 CalcBoundingBox( x
+ width
, y
+ height
);
891 void wxWindowDC::DoDrawEllipse( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
893 wxCHECK_RET( Ok(), wxT("invalid window dc") );
895 wxCoord xx
= XLOG2DEV(x
);
896 wxCoord yy
= YLOG2DEV(y
);
897 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
898 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
900 // CMB: handle -ve width and/or height
901 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
902 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
906 if (m_brush
.GetStyle() != wxTRANSPARENT
)
908 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
910 gdk_gc_set_ts_origin( m_textGC
,
911 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
912 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
913 gdk_draw_arc( m_window
, m_textGC
, TRUE
, xx
, yy
, ww
, hh
, 0, 360*64 );
914 gdk_gc_set_ts_origin( m_textGC
, 0, 0 );
916 if (IS_15_PIX_HATCH(m_brush
.GetStyle()))
918 gdk_gc_set_ts_origin( m_brushGC
, m_deviceOriginX
% 15, m_deviceOriginY
% 15 );
919 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, 0, 360*64 );
920 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
922 if (IS_16_PIX_HATCH(m_brush
.GetStyle()))
924 gdk_gc_set_ts_origin( m_brushGC
, m_deviceOriginX
% 16, m_deviceOriginY
% 16 );
925 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, 0, 360*64 );
926 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
928 if (m_brush
.GetStyle() == wxSTIPPLE
)
930 gdk_gc_set_ts_origin( m_brushGC
,
931 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
932 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
933 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, 0, 360*64 );
934 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
938 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, 0, 360*64 );
942 if (m_pen
.GetStyle() != wxTRANSPARENT
)
943 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
, hh
, 0, 360*64 );
946 CalcBoundingBox( x
- width
, y
- height
);
947 CalcBoundingBox( x
+ width
, y
+ height
);
950 void wxWindowDC::DoDrawIcon( const wxIcon
&icon
, wxCoord x
, wxCoord y
)
952 // VZ: egcs 1.0.3 refuses to compile this without cast, no idea why
953 DoDrawBitmap( (const wxBitmap
&)icon
, x
, y
, (bool)TRUE
);
956 void wxWindowDC::DoDrawBitmap( const wxBitmap
&bitmap
,
957 wxCoord x
, wxCoord y
,
960 wxCHECK_RET( Ok(), wxT("invalid window dc") );
962 wxCHECK_RET( bitmap
.Ok(), wxT("invalid bitmap") );
964 bool is_mono
= (bitmap
.GetBitmap() != NULL
);
966 /* scale/translate size and position */
967 int xx
= XLOG2DEV(x
);
968 int yy
= YLOG2DEV(y
);
970 int w
= bitmap
.GetWidth();
971 int h
= bitmap
.GetHeight();
973 CalcBoundingBox( x
, y
);
974 CalcBoundingBox( x
+ w
, y
+ h
);
976 if (!m_window
) return;
978 int ww
= XLOG2DEVREL(w
);
979 int hh
= YLOG2DEVREL(h
);
981 /* compare to current clipping region */
982 if (!m_currentClippingRegion
.IsNull())
984 wxRegion
tmp( xx
,yy
,ww
,hh
);
985 tmp
.Intersect( m_currentClippingRegion
);
990 /* scale bitmap if required */
992 if ((w
!= ww
) || (h
!= hh
))
994 wxImage
image( bitmap
);
995 image
.Rescale( ww
, hh
);
997 use_bitmap
= image
.ConvertToMonoBitmap(255,255,255);
999 use_bitmap
= image
.ConvertToBitmap();
1003 use_bitmap
= bitmap
;
1006 /* apply mask if any */
1007 GdkBitmap
*mask
= (GdkBitmap
*) NULL
;
1008 if (use_bitmap
.GetMask()) mask
= use_bitmap
.GetMask()->GetBitmap();
1010 if (useMask
&& mask
)
1012 GdkBitmap
*new_mask
= (GdkBitmap
*) NULL
;
1013 if (!m_currentClippingRegion
.IsNull())
1016 new_mask
= gdk_pixmap_new( wxRootWindow
->window
, ww
, hh
, 1 );
1017 GdkGC
*gc
= gdk_gc_new( new_mask
);
1019 gdk_gc_set_foreground( gc
, &col
);
1020 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, ww
, hh
);
1022 gdk_gc_set_background( gc
, &col
);
1024 gdk_gc_set_foreground( gc
, &col
);
1025 gdk_gc_set_clip_region( gc
, m_currentClippingRegion
.GetRegion() );
1026 gdk_gc_set_clip_origin( gc
, -xx
, -yy
);
1027 gdk_gc_set_fill( gc
, GDK_OPAQUE_STIPPLED
);
1028 gdk_gc_set_stipple( gc
, mask
);
1029 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, ww
, hh
);
1036 gdk_gc_set_clip_mask( m_textGC
, new_mask
);
1038 gdk_gc_set_clip_mask( m_textGC
, mask
);
1039 gdk_gc_set_clip_origin( m_textGC
, xx
, yy
);
1044 gdk_gc_set_clip_mask( m_penGC
, new_mask
);
1046 gdk_gc_set_clip_mask( m_penGC
, mask
);
1047 gdk_gc_set_clip_origin( m_penGC
, xx
, yy
);
1050 gdk_bitmap_unref( new_mask
);
1053 /* Draw XPixmap or XBitmap, depending on what the wxBitmap contains. For
1054 drawing a mono-bitmap (XBitmap) we use the current text GC */
1056 gdk_wx_draw_bitmap( m_window
, m_textGC
, use_bitmap
.GetBitmap(), 0, 0, xx
, yy
, -1, -1 );
1058 gdk_draw_pixmap( m_window
, m_penGC
, use_bitmap
.GetPixmap(), 0, 0, xx
, yy
, -1, -1 );
1060 /* remove mask again if any */
1061 if (useMask
&& mask
)
1065 gdk_gc_set_clip_mask( m_textGC
, (GdkBitmap
*) NULL
);
1066 gdk_gc_set_clip_origin( m_textGC
, 0, 0 );
1067 if (!m_currentClippingRegion
.IsNull())
1068 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
1072 gdk_gc_set_clip_mask( m_penGC
, (GdkBitmap
*) NULL
);
1073 gdk_gc_set_clip_origin( m_penGC
, 0, 0 );
1074 if (!m_currentClippingRegion
.IsNull())
1075 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
1080 bool wxWindowDC::DoBlit( wxCoord xdest
, wxCoord ydest
, wxCoord width
, wxCoord height
,
1081 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
,
1082 int logical_func
, bool useMask
)
1084 /* this is the nth try to get this utterly useless function to
1085 work. it now completely ignores the scaling or translation
1086 of the source dc, but scales correctly on the target dc and
1087 knows about possible mask information in a memory dc. */
1089 wxCHECK_MSG( Ok(), FALSE
, wxT("invalid window dc") );
1091 wxCHECK_MSG( source
, FALSE
, wxT("invalid source dc") );
1093 if (!m_window
) return FALSE
;
1095 wxClientDC
*srcDC
= (wxClientDC
*)source
;
1096 wxMemoryDC
*memDC
= (wxMemoryDC
*)source
;
1098 bool use_bitmap_method
= FALSE
;
1099 bool is_mono
= FALSE
;
1101 if (srcDC
->m_isMemDC
)
1103 if (!memDC
->m_selected
.Ok()) return FALSE
;
1105 /* we use the "XCopyArea" way to copy a memory dc into
1106 y different window if the memory dc BOTH
1107 a) doesn't have any mask or its mask isn't used
1111 if (useMask
&& (memDC
->m_selected
.GetMask()))
1113 /* we HAVE TO use the direct way for memory dcs
1114 that have mask since the XCopyArea doesn't know
1116 use_bitmap_method
= TRUE
;
1118 else if (memDC
->m_selected
.GetDepth() == 1)
1120 /* we HAVE TO use the direct way for memory dcs
1121 that are bitmaps because XCopyArea doesn't cope
1122 with different bit depths */
1124 use_bitmap_method
= TRUE
;
1126 else if ((xsrc
== 0) && (ysrc
== 0) &&
1127 (width
== memDC
->m_selected
.GetWidth()) &&
1128 (height
== memDC
->m_selected
.GetHeight()))
1130 /* we SHOULD use the direct way if all of the bitmap
1131 in the memory dc is copied in which case XCopyArea
1132 wouldn't be able able to boost performace by reducing
1133 the area to be scaled */
1134 use_bitmap_method
= TRUE
;
1138 use_bitmap_method
= FALSE
;
1142 CalcBoundingBox( xdest
, ydest
);
1143 CalcBoundingBox( xdest
+ width
, ydest
+ height
);
1145 /* scale/translate size and position */
1146 wxCoord xx
= XLOG2DEV(xdest
);
1147 wxCoord yy
= YLOG2DEV(ydest
);
1149 wxCoord ww
= XLOG2DEVREL(width
);
1150 wxCoord hh
= YLOG2DEVREL(height
);
1152 /* compare to current clipping region */
1153 if (!m_currentClippingRegion
.IsNull())
1155 wxRegion
tmp( xx
,yy
,ww
,hh
);
1156 tmp
.Intersect( m_currentClippingRegion
);
1161 int old_logical_func
= m_logicalFunction
;
1162 SetLogicalFunction( logical_func
);
1164 if (use_bitmap_method
)
1166 /* scale/translate bitmap size */
1167 wxCoord bm_width
= memDC
->m_selected
.GetWidth();
1168 wxCoord bm_height
= memDC
->m_selected
.GetHeight();
1170 wxCoord bm_ww
= XLOG2DEVREL( bm_width
);
1171 wxCoord bm_hh
= YLOG2DEVREL( bm_height
);
1173 /* scale bitmap if required */
1174 wxBitmap use_bitmap
;
1176 if ((bm_width
!= bm_ww
) || (bm_height
!= bm_hh
))
1178 wxImage
image( memDC
->m_selected
);
1179 image
= image
.Scale( bm_ww
, bm_hh
);
1182 use_bitmap
= image
.ConvertToMonoBitmap(255,255,255);
1184 use_bitmap
= image
.ConvertToBitmap();
1188 use_bitmap
= memDC
->m_selected
;
1191 /* apply mask if any */
1192 GdkBitmap
*mask
= (GdkBitmap
*) NULL
;
1193 if (use_bitmap
.GetMask()) mask
= use_bitmap
.GetMask()->GetBitmap();
1195 if (useMask
&& mask
)
1197 GdkBitmap
*new_mask
= (GdkBitmap
*) NULL
;
1198 if (!m_currentClippingRegion
.IsNull())
1201 new_mask
= gdk_pixmap_new( wxRootWindow
->window
, bm_ww
, bm_hh
, 1 );
1202 GdkGC
*gc
= gdk_gc_new( new_mask
);
1204 gdk_gc_set_foreground( gc
, &col
);
1205 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, bm_ww
, bm_hh
);
1207 gdk_gc_set_background( gc
, &col
);
1209 gdk_gc_set_foreground( gc
, &col
);
1210 gdk_gc_set_clip_region( gc
, m_currentClippingRegion
.GetRegion() );
1211 gdk_gc_set_clip_origin( gc
, -xx
, -yy
);
1212 gdk_gc_set_fill( gc
, GDK_OPAQUE_STIPPLED
);
1213 gdk_gc_set_stipple( gc
, mask
);
1214 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, bm_ww
, bm_hh
);
1221 gdk_gc_set_clip_mask( m_textGC
, new_mask
);
1223 gdk_gc_set_clip_mask( m_textGC
, mask
);
1224 gdk_gc_set_clip_origin( m_textGC
, xx
, yy
);
1229 gdk_gc_set_clip_mask( m_penGC
, new_mask
);
1231 gdk_gc_set_clip_mask( m_penGC
, mask
);
1232 gdk_gc_set_clip_origin( m_penGC
, xx
, yy
);
1235 gdk_bitmap_unref( new_mask
);
1238 /* Draw XPixmap or XBitmap, depending on what the wxBitmap contains. For
1239 drawing a mono-bitmap (XBitmap) we use the current text GC */
1242 gdk_wx_draw_bitmap( m_window
, m_textGC
, use_bitmap
.GetBitmap(), xsrc
, ysrc
, xx
, yy
, ww
, hh
);
1244 gdk_draw_pixmap( m_window
, m_penGC
, use_bitmap
.GetPixmap(), xsrc
, ysrc
, xx
, yy
, ww
, hh
);
1246 /* remove mask again if any */
1247 if (useMask
&& mask
)
1251 gdk_gc_set_clip_mask( m_textGC
, (GdkBitmap
*) NULL
);
1252 gdk_gc_set_clip_origin( m_textGC
, 0, 0 );
1253 if (!m_currentClippingRegion
.IsNull())
1254 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
1258 gdk_gc_set_clip_mask( m_penGC
, (GdkBitmap
*) NULL
);
1259 gdk_gc_set_clip_origin( m_penGC
, 0, 0 );
1260 if (!m_currentClippingRegion
.IsNull())
1261 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
1265 else /* use_bitmap_method */
1267 if ((width
!= ww
) || (height
!= hh
))
1269 /* draw source window into a bitmap as we cannot scale
1270 a window in contrast to a bitmap. this would actually
1271 work with memory dcs as well, but we'd lose the mask
1272 information and waste one step in this process since
1273 a memory already has a bitmap. all this is slightly
1274 inefficient as we could take an XImage directly from
1275 an X window, but we'd then also have to care that
1276 the window is not outside the screen (in which case
1277 we'd get a BadMatch or what not).
1278 Is a double XGetImage and combined XGetPixel and
1279 XPutPixel really faster? I'm not sure. look at wxXt
1280 for a different implementation of the same problem. */
1282 wxBitmap
bitmap( width
, height
);
1284 /* copy including child window contents */
1285 gdk_gc_set_subwindow( m_penGC
, GDK_INCLUDE_INFERIORS
);
1286 gdk_window_copy_area( bitmap
.GetPixmap(), m_penGC
, 0, 0,
1288 xsrc
, ysrc
, width
, height
);
1289 gdk_gc_set_subwindow( m_penGC
, GDK_CLIP_BY_CHILDREN
);
1292 wxImage
image( bitmap
);
1293 image
= image
.Scale( ww
, hh
);
1295 /* convert to bitmap */
1296 bitmap
= image
.ConvertToBitmap();
1298 /* draw scaled bitmap */
1299 gdk_draw_pixmap( m_window
, m_penGC
, bitmap
.GetPixmap(), 0, 0, xx
, yy
, -1, -1 );
1304 /* No scaling and not a memory dc with a mask either */
1306 /* copy including child window contents */
1307 gdk_gc_set_subwindow( m_penGC
, GDK_INCLUDE_INFERIORS
);
1308 gdk_window_copy_area( m_window
, m_penGC
, xx
, yy
,
1310 xsrc
, ysrc
, width
, height
);
1311 gdk_gc_set_subwindow( m_penGC
, GDK_CLIP_BY_CHILDREN
);
1315 SetLogicalFunction( old_logical_func
);
1319 void wxWindowDC::DoDrawText( const wxString
&text
, wxCoord x
, wxCoord y
)
1321 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1323 if (!m_window
) return;
1325 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
1327 wxCHECK_RET( font
, wxT("invalid font") );
1330 wxCHECK_RET( m_context
, wxT("no Pango context") );
1337 /* FIXME: the layout engine should probably be abstracted at a higher level in wxDC... */
1338 PangoLayout
*layout
= pango_layout_new(m_context
);
1339 pango_layout_set_font_description(layout
, m_fontdesc
);
1341 wxWX2MBbuf data
= text
.mb_str(wxConvUTF8
);
1342 pango_layout_set_text(layout
, data
, strlen(data
));
1344 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
1345 PangoRectangle rect
;
1346 pango_layout_line_get_extents(line
, NULL
, &rect
);
1347 wxCoord width
= rect
.width
;
1348 wxCoord height
= rect
.height
;
1349 gdk_draw_layout( m_window
, m_textGC
, x
, y
, layout
);
1351 wxCoord width
= gdk_string_width( font
, text
.mbc_str() );
1352 wxCoord height
= font
->ascent
+ font
->descent
;
1353 /* CMB 21/5/98: draw text background if mode is wxSOLID */
1354 if (m_backgroundMode
== wxSOLID
)
1356 gdk_gc_set_foreground( m_textGC
, m_textBackgroundColour
.GetColor() );
1357 gdk_draw_rectangle( m_window
, m_textGC
, TRUE
, x
, y
, width
, height
);
1358 gdk_gc_set_foreground( m_textGC
, m_textForegroundColour
.GetColor() );
1360 gdk_draw_string( m_window
, font
, m_textGC
, x
, y
+ font
->ascent
, text
.mbc_str() );
1363 /* CMB 17/7/98: simple underline: ignores scaling and underlying
1364 X font's XA_UNDERLINE_POSITION and XA_UNDERLINE_THICKNESS
1365 properties (see wxXt implementation) */
1366 if (m_font
.GetUnderlined())
1368 wxCoord ul_y
= y
+ font
->ascent
;
1369 if (font
->descent
> 0) ul_y
++;
1370 gdk_draw_line( m_window
, m_textGC
, x
, ul_y
, x
+ width
, ul_y
);
1374 g_object_unref( G_OBJECT( layout
) );
1377 width
= wxCoord(width
/ m_scaleX
);
1378 height
= wxCoord(height
/ m_scaleY
);
1379 CalcBoundingBox (x
+ width
, y
+ height
);
1380 CalcBoundingBox (x
, y
);
1383 void wxWindowDC::DoDrawRotatedText( const wxString
&text
, wxCoord x
, wxCoord y
, double angle
)
1387 DrawText(text
, x
, y
);
1391 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1393 if (!m_window
) return;
1395 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
1397 wxCHECK_RET( font
, wxT("invalid font") );
1399 // the size of the text
1400 wxCoord w
= gdk_string_width( font
, text
.mbc_str() );
1401 wxCoord h
= font
->ascent
+ font
->descent
;
1403 // draw the string normally
1406 dc
.SelectObject(src
);
1407 dc
.SetFont(GetFont());
1408 dc
.SetBackground(*wxWHITE_BRUSH
);
1409 dc
.SetBrush(*wxBLACK_BRUSH
);
1411 dc
.DrawText(text
, 0, 0);
1412 dc
.SetFont(wxNullFont
);
1413 dc
.SelectObject(wxNullBitmap
);
1415 // Calculate the size of the rotated bounding box.
1416 double rad
= DegToRad(angle
);
1417 double dx
= cos(rad
),
1420 // the rectngle vertices are counted clockwise with the first one being at
1421 // (0, 0) (or, rather, at (x, y))
1423 y2
= -w
*dy
; // y axis points to the bottom, hence minus
1426 double x3
= x4
+ x2
,
1430 wxCoord maxX
= (wxCoord
)(dmax(x2
, dmax(x3
, x4
)) + 0.5),
1431 maxY
= (wxCoord
)(dmax(y2
, dmax(y3
, y4
)) + 0.5),
1432 minX
= (wxCoord
)(dmin(x2
, dmin(x3
, x4
)) - 0.5),
1433 minY
= (wxCoord
)(dmin(y2
, dmin(y3
, y4
)) - 0.5);
1435 // prepare to blit-with-rotate the bitmap to the DC
1438 GdkColor
*colText
= m_textForegroundColour
.GetColor(),
1439 *colBack
= m_textBackgroundColour
.GetColor();
1441 bool textColSet
= TRUE
;
1443 unsigned char *data
= image
.GetData();
1445 // paint pixel by pixel
1446 for ( wxCoord srcX
= 0; srcX
< w
; srcX
++ )
1448 for ( wxCoord srcY
= 0; srcY
< h
; srcY
++ )
1450 // transform source coords to dest coords
1451 double r
= sqrt((double)srcX
*srcX
+ srcY
*srcY
);
1452 double angleOrig
= atan2((double)srcY
, (double)srcX
) - rad
;
1453 wxCoord dstX
= (wxCoord
)(r
*cos(angleOrig
) + 0.5),
1454 dstY
= (wxCoord
)(r
*sin(angleOrig
) + 0.5);
1457 bool textPixel
= data
[(srcY
*w
+ srcX
)*3] == 0;
1458 if ( textPixel
|| (m_backgroundMode
== wxSOLID
) )
1460 // change colour if needed
1461 if ( textPixel
!= textColSet
)
1463 gdk_gc_set_foreground( m_textGC
, textPixel
? colText
1466 textColSet
= textPixel
;
1469 // don't use DrawPoint() because it uses the current pen
1470 // colour, and we don't need it here
1471 gdk_draw_point( m_window
, m_textGC
,
1472 XLOG2DEV(x
+ dstX
), YLOG2DEV(y
+ dstY
) );
1477 // it would be better to draw with non underlined font and draw the line
1478 // manually here (it would be more straight...)
1480 if ( m_font
.GetUnderlined() )
1482 gdk_draw_line( m_window
, m_textGC
,
1483 XLOG2DEV(x
+ x4
), YLOG2DEV(y
+ y4
+ font
->descent
),
1484 XLOG2DEV(x
+ x3
), YLOG2DEV(y
+ y3
+ font
->descent
));
1488 // restore the font colour
1489 gdk_gc_set_foreground( m_textGC
, colText
);
1491 // update the bounding box
1492 CalcBoundingBox(x
+ minX
, y
+ minY
);
1493 CalcBoundingBox(x
+ maxX
, y
+ maxY
);
1496 void wxWindowDC::DoGetTextExtent(const wxString
&string
,
1497 wxCoord
*width
, wxCoord
*height
,
1498 wxCoord
*descent
, wxCoord
*externalLeading
,
1499 wxFont
*theFont
) const
1501 wxFont fontToUse
= m_font
;
1502 if (theFont
) fontToUse
= *theFont
;
1504 GdkFont
*font
= fontToUse
.GetInternalFont( m_scaleY
);
1505 if (width
) (*width
) = wxCoord(gdk_string_width( font
, string
.mbc_str() ) / m_scaleX
);
1506 if (height
) (*height
) = wxCoord((font
->ascent
+ font
->descent
) / m_scaleY
);
1507 if (descent
) (*descent
) = wxCoord(font
->descent
/ m_scaleY
);
1508 if (externalLeading
) (*externalLeading
) = 0; // ??
1511 wxCoord
wxWindowDC::GetCharWidth() const
1513 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
1514 wxCHECK_MSG( font
, -1, wxT("invalid font") );
1516 return wxCoord(gdk_string_width( font
, "H" ) / m_scaleX
);
1519 wxCoord
wxWindowDC::GetCharHeight() const
1521 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
1522 wxCHECK_MSG( font
, -1, wxT("invalid font") );
1524 return wxCoord((font
->ascent
+ font
->descent
) / m_scaleY
);
1527 void wxWindowDC::Clear()
1529 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1531 if (!m_window
) return;
1533 /* - we either are a memory dc or have a window as the
1534 owner. anything else shouldn't happen.
1535 - we don't use gdk_window_clear() as we don't set
1536 the window's background colour anymore. it is too
1537 much pain to keep the DC's and the window's back-
1538 ground colour in synch. */
1543 m_owner
->GetSize( &width
, &height
);
1544 gdk_draw_rectangle( m_window
, m_bgGC
, TRUE
, 0, 0, width
, height
);
1551 GetSize( &width
, &height
);
1552 gdk_draw_rectangle( m_window
, m_bgGC
, TRUE
, 0, 0, width
, height
);
1557 void wxWindowDC::SetFont( const wxFont
&font
)
1565 void wxWindowDC::SetPen( const wxPen
&pen
)
1567 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1569 if (m_pen
== pen
) return;
1573 if (!m_pen
.Ok()) return;
1575 if (!m_window
) return;
1577 gint width
= m_pen
.GetWidth();
1580 // CMB: if width is non-zero scale it with the dc
1585 // X doesn't allow different width in x and y and so we take
1588 ( fabs((double) XLOG2DEVREL(width
)) +
1589 fabs((double) YLOG2DEVREL(width
)) ) / 2.0;
1593 static const wxGTKDash dotted
[] = {1, 1};
1594 static const wxGTKDash short_dashed
[] = {2, 2};
1595 static const wxGTKDash wxCoord_dashed
[] = {2, 4};
1596 static const wxGTKDash dotted_dashed
[] = {3, 3, 1, 3};
1598 // We express dash pattern in pen width unit, so we are
1599 // independent of zoom factor and so on...
1601 const wxGTKDash
*req_dash
;
1603 GdkLineStyle lineStyle
= GDK_LINE_SOLID
;
1604 switch (m_pen
.GetStyle())
1608 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1609 req_nb_dash
= m_pen
.GetDashCount();
1610 req_dash
= (wxGTKDash
*)m_pen
.GetDash();
1615 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1622 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1624 req_dash
= wxCoord_dashed
;
1629 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1631 req_dash
= short_dashed
;
1636 // lineStyle = GDK_LINE_DOUBLE_DASH;
1637 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1639 req_dash
= dotted_dashed
;
1644 case wxSTIPPLE_MASK_OPAQUE
:
1649 lineStyle
= GDK_LINE_SOLID
;
1650 req_dash
= (wxGTKDash
*)NULL
;
1656 #if (GTK_MINOR_VERSION > 0) || (GTK_MAJOR_VERSION > 1)
1657 if (req_dash
&& req_nb_dash
)
1659 wxGTKDash
*real_req_dash
= new wxGTKDash
[req_nb_dash
];
1662 for (int i
= 0; i
< req_nb_dash
; i
++)
1663 real_req_dash
[i
] = req_dash
[i
] * width
;
1664 gdk_gc_set_dashes( m_penGC
, 0, real_req_dash
, req_nb_dash
);
1665 delete[] real_req_dash
;
1669 // No Memory. We use non-scaled dash pattern...
1670 gdk_gc_set_dashes( m_penGC
, 0, (wxGTKDash
*)req_dash
, req_nb_dash
);
1675 GdkCapStyle capStyle
= GDK_CAP_ROUND
;
1676 switch (m_pen
.GetCap())
1678 case wxCAP_PROJECTING
: { capStyle
= GDK_CAP_PROJECTING
; break; }
1679 case wxCAP_BUTT
: { capStyle
= GDK_CAP_BUTT
; break; }
1686 capStyle
= GDK_CAP_NOT_LAST
;
1690 capStyle
= GDK_CAP_ROUND
;
1696 GdkJoinStyle joinStyle
= GDK_JOIN_ROUND
;
1697 switch (m_pen
.GetJoin())
1699 case wxJOIN_BEVEL
: { joinStyle
= GDK_JOIN_BEVEL
; break; }
1700 case wxJOIN_MITER
: { joinStyle
= GDK_JOIN_MITER
; break; }
1702 default: { joinStyle
= GDK_JOIN_ROUND
; break; }
1705 gdk_gc_set_line_attributes( m_penGC
, width
, lineStyle
, capStyle
, joinStyle
);
1707 m_pen
.GetColour().CalcPixel( m_cmap
);
1708 gdk_gc_set_foreground( m_penGC
, m_pen
.GetColour().GetColor() );
1711 void wxWindowDC::SetBrush( const wxBrush
&brush
)
1713 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1715 if (m_brush
== brush
) return;
1719 if (!m_brush
.Ok()) return;
1721 if (!m_window
) return;
1723 m_brush
.GetColour().CalcPixel( m_cmap
);
1724 gdk_gc_set_foreground( m_brushGC
, m_brush
.GetColour().GetColor() );
1726 gdk_gc_set_fill( m_brushGC
, GDK_SOLID
);
1728 if ((m_brush
.GetStyle() == wxSTIPPLE
) && (m_brush
.GetStipple()->Ok()))
1730 if (m_brush
.GetStipple()->GetPixmap())
1732 gdk_gc_set_fill( m_brushGC
, GDK_TILED
);
1733 gdk_gc_set_tile( m_brushGC
, m_brush
.GetStipple()->GetPixmap() );
1737 gdk_gc_set_fill( m_brushGC
, GDK_STIPPLED
);
1738 gdk_gc_set_stipple( m_brushGC
, m_brush
.GetStipple()->GetBitmap() );
1742 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
1744 gdk_gc_set_fill( m_textGC
, GDK_OPAQUE_STIPPLED
);
1745 gdk_gc_set_stipple( m_textGC
, m_brush
.GetStipple()->GetMask()->GetBitmap() );
1748 if (IS_HATCH(m_brush
.GetStyle()))
1750 gdk_gc_set_fill( m_brushGC
, GDK_STIPPLED
);
1751 int num
= m_brush
.GetStyle() - wxBDIAGONAL_HATCH
;
1752 gdk_gc_set_stipple( m_brushGC
, hatches
[num
] );
1756 void wxWindowDC::SetBackground( const wxBrush
&brush
)
1758 /* CMB 21/7/98: Added SetBackground. Sets background brush
1759 * for Clear() and bg colour for shapes filled with cross-hatch brush */
1761 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1763 if (m_backgroundBrush
== brush
) return;
1765 m_backgroundBrush
= brush
;
1767 if (!m_backgroundBrush
.Ok()) return;
1769 if (!m_window
) return;
1771 m_backgroundBrush
.GetColour().CalcPixel( m_cmap
);
1772 gdk_gc_set_background( m_brushGC
, m_backgroundBrush
.GetColour().GetColor() );
1773 gdk_gc_set_background( m_penGC
, m_backgroundBrush
.GetColour().GetColor() );
1774 gdk_gc_set_background( m_bgGC
, m_backgroundBrush
.GetColour().GetColor() );
1775 gdk_gc_set_foreground( m_bgGC
, m_backgroundBrush
.GetColour().GetColor() );
1777 gdk_gc_set_fill( m_bgGC
, GDK_SOLID
);
1779 if ((m_backgroundBrush
.GetStyle() == wxSTIPPLE
) && (m_backgroundBrush
.GetStipple()->Ok()))
1781 if (m_backgroundBrush
.GetStipple()->GetPixmap())
1783 gdk_gc_set_fill( m_bgGC
, GDK_TILED
);
1784 gdk_gc_set_tile( m_bgGC
, m_backgroundBrush
.GetStipple()->GetPixmap() );
1788 gdk_gc_set_fill( m_bgGC
, GDK_STIPPLED
);
1789 gdk_gc_set_stipple( m_bgGC
, m_backgroundBrush
.GetStipple()->GetBitmap() );
1793 if (IS_HATCH(m_backgroundBrush
.GetStyle()))
1795 gdk_gc_set_fill( m_bgGC
, GDK_STIPPLED
);
1796 int num
= m_backgroundBrush
.GetStyle() - wxBDIAGONAL_HATCH
;
1797 gdk_gc_set_stipple( m_bgGC
, hatches
[num
] );
1801 void wxWindowDC::SetLogicalFunction( int function
)
1803 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1805 if (m_logicalFunction
== function
)
1808 // VZ: shouldn't this be a CHECK?
1812 GdkFunction mode
= GDK_COPY
;
1815 case wxXOR
: mode
= GDK_XOR
; break;
1816 case wxINVERT
: mode
= GDK_INVERT
; break;
1817 #if (GTK_MINOR_VERSION > 0)
1818 case wxOR_REVERSE
: mode
= GDK_OR_REVERSE
; break;
1819 case wxAND_REVERSE
: mode
= GDK_AND_REVERSE
; break;
1820 case wxCLEAR
: mode
= GDK_CLEAR
; break;
1821 case wxSET
: mode
= GDK_SET
; break;
1822 case wxOR_INVERT
: mode
= GDK_OR_INVERT
; break;
1823 case wxAND
: mode
= GDK_AND
; break;
1824 case wxOR
: mode
= GDK_OR
; break;
1825 case wxEQUIV
: mode
= GDK_EQUIV
; break;
1826 case wxNAND
: mode
= GDK_NAND
; break;
1827 case wxAND_INVERT
: mode
= GDK_AND_INVERT
; break;
1828 case wxCOPY
: mode
= GDK_COPY
; break;
1829 case wxNO_OP
: mode
= GDK_NOOP
; break;
1830 case wxSRC_INVERT
: mode
= GDK_COPY_INVERT
; break;
1832 // unsupported by GTK
1833 case wxNOR
: mode
= GDK_COPY
; break;
1837 wxFAIL_MSG( wxT("unsupported logical function") );
1842 m_logicalFunction
= function
;
1844 gdk_gc_set_function( m_penGC
, mode
);
1845 gdk_gc_set_function( m_brushGC
, mode
);
1847 // to stay compatible with wxMSW, we don't apply ROPs to the text
1848 // operations (i.e. DrawText/DrawRotatedText).
1849 // True, but mono-bitmaps use the m_textGC and they use ROPs as well.
1850 gdk_gc_set_function( m_textGC
, mode
);
1853 void wxWindowDC::SetTextForeground( const wxColour
&col
)
1855 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1857 if (m_textForegroundColour
== col
) return;
1859 m_textForegroundColour
= col
;
1860 if (!m_textForegroundColour
.Ok()) return;
1862 if (!m_window
) return;
1864 m_textForegroundColour
.CalcPixel( m_cmap
);
1865 gdk_gc_set_foreground( m_textGC
, m_textForegroundColour
.GetColor() );
1868 void wxWindowDC::SetTextBackground( const wxColour
&col
)
1870 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1872 if (m_textBackgroundColour
== col
) return;
1874 m_textBackgroundColour
= col
;
1875 if (!m_textBackgroundColour
.Ok()) return;
1877 if (!m_window
) return;
1879 m_textBackgroundColour
.CalcPixel( m_cmap
);
1880 gdk_gc_set_background( m_textGC
, m_textBackgroundColour
.GetColor() );
1883 void wxWindowDC::SetBackgroundMode( int mode
)
1885 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1887 m_backgroundMode
= mode
;
1889 if (!m_window
) return;
1891 // CMB 21/7/98: fill style of cross-hatch brushes is affected by
1892 // transparent/solid background mode
1894 if (m_brush
.GetStyle() != wxSOLID
&& m_brush
.GetStyle() != wxTRANSPARENT
)
1896 gdk_gc_set_fill( m_brushGC
,
1897 (m_backgroundMode
== wxTRANSPARENT
) ? GDK_STIPPLED
: GDK_OPAQUE_STIPPLED
);
1901 void wxWindowDC::SetPalette( const wxPalette
& WXUNUSED(palette
) )
1903 wxFAIL_MSG( wxT("wxWindowDC::SetPalette not implemented") );
1906 void wxWindowDC::DoSetClippingRegion( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
1908 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1910 if (!m_window
) return;
1913 rect
.x
= XLOG2DEV(x
);
1914 rect
.y
= YLOG2DEV(y
);
1915 rect
.width
= XLOG2DEVREL(width
);
1916 rect
.height
= YLOG2DEVREL(height
);
1918 if (!m_currentClippingRegion
.IsNull())
1919 m_currentClippingRegion
.Intersect( rect
);
1921 m_currentClippingRegion
.Union( rect
);
1923 #if USE_PAINT_REGION
1924 if (!m_paintClippingRegion
.IsNull())
1925 m_currentClippingRegion
.Intersect( m_paintClippingRegion
);
1928 wxCoord xx
, yy
, ww
, hh
;
1929 m_currentClippingRegion
.GetBox( xx
, yy
, ww
, hh
);
1930 wxDC::DoSetClippingRegion( xx
, yy
, ww
, hh
);
1932 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
1933 gdk_gc_set_clip_region( m_brushGC
, m_currentClippingRegion
.GetRegion() );
1934 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
1935 gdk_gc_set_clip_region( m_bgGC
, m_currentClippingRegion
.GetRegion() );
1938 void wxWindowDC::DoSetClippingRegionAsRegion( const wxRegion
®ion
)
1940 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1944 DestroyClippingRegion();
1948 if (!m_window
) return;
1950 if (!m_currentClippingRegion
.IsNull())
1951 m_currentClippingRegion
.Intersect( region
);
1953 m_currentClippingRegion
.Union( region
);
1955 #if USE_PAINT_REGION
1956 if (!m_paintClippingRegion
.IsNull())
1957 m_currentClippingRegion
.Intersect( m_paintClippingRegion
);
1960 wxCoord xx
, yy
, ww
, hh
;
1961 m_currentClippingRegion
.GetBox( xx
, yy
, ww
, hh
);
1962 wxDC::DoSetClippingRegion( xx
, yy
, ww
, hh
);
1964 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
1965 gdk_gc_set_clip_region( m_brushGC
, m_currentClippingRegion
.GetRegion() );
1966 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
1967 gdk_gc_set_clip_region( m_bgGC
, m_currentClippingRegion
.GetRegion() );
1970 void wxWindowDC::DestroyClippingRegion()
1972 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1974 wxDC::DestroyClippingRegion();
1976 m_currentClippingRegion
.Clear();
1978 #if USE_PAINT_REGION
1979 if (!m_paintClippingRegion
.IsEmpty())
1980 m_currentClippingRegion
.Union( m_paintClippingRegion
);
1983 if (!m_window
) return;
1985 if (m_currentClippingRegion
.IsEmpty())
1987 gdk_gc_set_clip_rectangle( m_penGC
, (GdkRectangle
*) NULL
);
1988 gdk_gc_set_clip_rectangle( m_brushGC
, (GdkRectangle
*) NULL
);
1989 gdk_gc_set_clip_rectangle( m_textGC
, (GdkRectangle
*) NULL
);
1990 gdk_gc_set_clip_rectangle( m_bgGC
, (GdkRectangle
*) NULL
);
1994 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
1995 gdk_gc_set_clip_region( m_brushGC
, m_currentClippingRegion
.GetRegion() );
1996 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
1997 gdk_gc_set_clip_region( m_bgGC
, m_currentClippingRegion
.GetRegion() );
2001 void wxWindowDC::Destroy()
2003 if (m_penGC
) wxFreePoolGC( m_penGC
);
2004 m_penGC
= (GdkGC
*) NULL
;
2005 if (m_brushGC
) wxFreePoolGC( m_brushGC
);
2006 m_brushGC
= (GdkGC
*) NULL
;
2007 if (m_textGC
) wxFreePoolGC( m_textGC
);
2008 m_textGC
= (GdkGC
*) NULL
;
2009 if (m_bgGC
) wxFreePoolGC( m_bgGC
);
2010 m_bgGC
= (GdkGC
*) NULL
;
2013 void wxWindowDC::ComputeScaleAndOrigin()
2015 /* CMB: copy scale to see if it changes */
2016 double origScaleX
= m_scaleX
;
2017 double origScaleY
= m_scaleY
;
2019 wxDC::ComputeScaleAndOrigin();
2021 /* CMB: if scale has changed call SetPen to recalulate the line width */
2022 if ((m_scaleX
!= origScaleX
|| m_scaleY
!= origScaleY
) &&
2025 /* this is a bit artificial, but we need to force wxDC to think
2026 the pen has changed */
2033 // Resolution in pixels per logical inch
2034 wxSize
wxWindowDC::GetPPI() const
2036 return wxSize(100, 100);
2039 int wxWindowDC::GetDepth() const
2041 wxFAIL_MSG(wxT("not implemented"));
2047 // ----------------------------------- spline code ----------------------------------------
2049 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
2050 double a3
, double b3
, double a4
, double b4
);
2051 void wx_clear_stack();
2052 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
2053 double *y3
, double *x4
, double *y4
);
2054 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
2055 double x4
, double y4
);
2056 static bool wx_spline_add_point(double x
, double y
);
2057 static void wx_spline_draw_point_array(wxDC
*dc
);
2059 wxList wx_spline_point_list
;
2061 #define half(z1, z2) ((z1+z2)/2.0)
2064 /* iterative version */
2066 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
2069 register double xmid
, ymid
;
2070 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
2073 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
2075 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
2076 xmid
= (double)half(x2
, x3
);
2077 ymid
= (double)half(y2
, y3
);
2078 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
2079 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
2080 wx_spline_add_point( x1
, y1
);
2081 wx_spline_add_point( xmid
, ymid
);
2083 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
2084 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
2085 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
2086 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
2091 /* utilities used by spline drawing routines */
2093 typedef struct wx_spline_stack_struct
{
2094 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
2097 #define SPLINE_STACK_DEPTH 20
2098 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
2099 static Stack
*wx_stack_top
;
2100 static int wx_stack_count
;
2102 void wx_clear_stack()
2104 wx_stack_top
= wx_spline_stack
;
2108 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
2110 wx_stack_top
->x1
= x1
;
2111 wx_stack_top
->y1
= y1
;
2112 wx_stack_top
->x2
= x2
;
2113 wx_stack_top
->y2
= y2
;
2114 wx_stack_top
->x3
= x3
;
2115 wx_stack_top
->y3
= y3
;
2116 wx_stack_top
->x4
= x4
;
2117 wx_stack_top
->y4
= y4
;
2122 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
2123 double *x3
, double *y3
, double *x4
, double *y4
)
2125 if (wx_stack_count
== 0)
2129 *x1
= wx_stack_top
->x1
;
2130 *y1
= wx_stack_top
->y1
;
2131 *x2
= wx_stack_top
->x2
;
2132 *y2
= wx_stack_top
->y2
;
2133 *x3
= wx_stack_top
->x3
;
2134 *y3
= wx_stack_top
->y3
;
2135 *x4
= wx_stack_top
->x4
;
2136 *y4
= wx_stack_top
->y4
;
2140 static bool wx_spline_add_point(double x
, double y
)
2142 wxPoint
*point
= new wxPoint
;
2145 wx_spline_point_list
.Append((wxObject
*)point
);
2149 static void wx_spline_draw_point_array(wxDC
*dc
)
2151 dc
->DrawLines(&wx_spline_point_list
, 0, 0 );
2152 wxNode
*node
= wx_spline_point_list
.First();
2155 wxPoint
*point
= (wxPoint
*)node
->Data();
2158 node
= wx_spline_point_list
.First();
2162 void wxWindowDC::DoDrawSpline( wxList
*points
)
2164 wxCHECK_RET( Ok(), wxT("invalid window dc") );
2167 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
2168 double x1
, y1
, x2
, y2
;
2170 wxNode
*node
= points
->First();
2171 p
= (wxPoint
*)node
->Data();
2176 node
= node
->Next();
2177 p
= (wxPoint
*)node
->Data();
2181 cx1
= (double)((x1
+ x2
) / 2);
2182 cy1
= (double)((y1
+ y2
) / 2);
2183 cx2
= (double)((cx1
+ x2
) / 2);
2184 cy2
= (double)((cy1
+ y2
) / 2);
2186 wx_spline_add_point(x1
, y1
);
2188 while ((node
= node
->Next()) != NULL
)
2190 p
= (wxPoint
*)node
->Data();
2195 cx4
= (double)(x1
+ x2
) / 2;
2196 cy4
= (double)(y1
+ y2
) / 2;
2197 cx3
= (double)(x1
+ cx4
) / 2;
2198 cy3
= (double)(y1
+ cy4
) / 2;
2200 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
2204 cx2
= (double)(cx1
+ x2
) / 2;
2205 cy2
= (double)(cy1
+ y2
) / 2;
2208 wx_spline_add_point( cx1
, cy1
);
2209 wx_spline_add_point( x2
, y2
);
2211 wx_spline_draw_point_array( this );
2214 #endif // wxUSE_SPLINE
2216 //-----------------------------------------------------------------------------
2218 //-----------------------------------------------------------------------------
2220 IMPLEMENT_DYNAMIC_CLASS(wxPaintDC
,wxWindowDC
)
2222 wxPaintDC::wxPaintDC()
2227 wxPaintDC::wxPaintDC( wxWindow
*win
)
2230 #if USE_PAINT_REGION
2231 if (!win
->m_clipPaintRegion
)
2234 m_paintClippingRegion
= win
->GetUpdateRegion();
2235 GdkRegion
*region
= m_paintClippingRegion
.GetRegion();
2238 m_currentClippingRegion
.Union( m_paintClippingRegion
);
2240 gdk_gc_set_clip_region( m_penGC
, region
);
2241 gdk_gc_set_clip_region( m_brushGC
, region
);
2242 gdk_gc_set_clip_region( m_textGC
, region
);
2243 gdk_gc_set_clip_region( m_bgGC
, region
);
2248 //-----------------------------------------------------------------------------
2250 //-----------------------------------------------------------------------------
2252 IMPLEMENT_DYNAMIC_CLASS(wxClientDC
,wxWindowDC
)
2254 wxClientDC::wxClientDC()
2259 wxClientDC::wxClientDC( wxWindow
*win
)
2264 // ----------------------------------------------------------------------------
2266 // ----------------------------------------------------------------------------
2268 class wxDCModule
: public wxModule
2275 DECLARE_DYNAMIC_CLASS(wxDCModule
)
2278 IMPLEMENT_DYNAMIC_CLASS(wxDCModule
, wxModule
)
2280 bool wxDCModule::OnInit()
2286 void wxDCModule::OnExit()