]> git.saurik.com Git - wxWidgets.git/blob - src/gtk/dcclient.cpp
another file I added on the wxUniv branch and forgot to merge
[wxWidgets.git] / src / gtk / dcclient.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: gtk/dcclient.cpp
3 // Purpose:
4 // Author: Robert Roebling
5 // RCS-ID: $Id$
6 // Copyright: (c) 1998 Robert Roebling, Markus Holzem, Chris Breeze
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 #ifdef __GNUG__
11 #pragma implementation "dcclient.h"
12 #endif
13
14 #ifdef __VMS
15 #define XCopyPlane XCOPYPLANE
16 #endif
17
18 #include "wx/dcclient.h"
19 #include "wx/dcmemory.h"
20 #include "wx/image.h"
21 #include "wx/module.h"
22
23 #include "wx/gtk/win_gtk.h"
24
25 #include <math.h> // for floating-point functions
26
27 #include <gdk/gdk.h>
28 #include <gdk/gdkx.h>
29 #include <gdk/gdkprivate.h>
30 #include <gtk/gtk.h>
31
32 //-----------------------------------------------------------------------------
33 // local defines
34 //-----------------------------------------------------------------------------
35
36 #define USE_PAINT_REGION 1
37
38 //-----------------------------------------------------------------------------
39 // local data
40 //-----------------------------------------------------------------------------
41
42 #include "bdiag.xbm"
43 #include "fdiag.xbm"
44 #include "cdiag.xbm"
45 #include "horiz.xbm"
46 #include "verti.xbm"
47 #include "cross.xbm"
48 #define num_hatches 6
49
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)
52
53
54 static GdkPixmap *hatches[num_hatches];
55 static GdkPixmap **hatch_bitmap = (GdkPixmap **) NULL;
56
57 extern GtkWidget *wxGetRootWindow();
58
59 //-----------------------------------------------------------------------------
60 // constants
61 //-----------------------------------------------------------------------------
62
63 const double RAD2DEG = 180.0 / M_PI;
64
65 // ----------------------------------------------------------------------------
66 // private functions
67 // ----------------------------------------------------------------------------
68
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; }
71
72 static inline double DegToRad(double deg) { return (deg * M_PI) / 180.0; }
73
74 //-----------------------------------------------------------------------------
75 // temporary implementation of the missing GDK function
76 //-----------------------------------------------------------------------------
77
78 #include "gdk/gdkprivate.h"
79
80 void gdk_wx_draw_bitmap(GdkDrawable *drawable,
81 GdkGC *gc,
82 GdkDrawable *src,
83 gint xsrc,
84 gint ysrc,
85 gint xdest,
86 gint ydest,
87 gint width,
88 gint height)
89 {
90 gint src_width, src_height;
91 #ifndef __WXGTK20__
92 GdkWindowPrivate *drawable_private;
93 GdkWindowPrivate *src_private;
94 GdkGCPrivate *gc_private;
95 #endif
96
97 g_return_if_fail (drawable != NULL);
98 g_return_if_fail (src != NULL);
99 g_return_if_fail (gc != NULL);
100
101 #ifdef __WXGTK20__
102 if (GDK_WINDOW_DESTROYED(drawable) || GDK_WINDOW_DESTROYED(src))
103 return;
104
105 gdk_drawable_get_size(src, &src_width, &src_height);
106 #else
107 drawable_private = (GdkWindowPrivate*) drawable;
108 src_private = (GdkWindowPrivate*) src;
109 if (drawable_private->destroyed || src_private->destroyed)
110 return;
111
112 src_width = src_private->width;
113 src_height = src_private->height;
114
115 gc_private = (GdkGCPrivate*) gc;
116 #endif
117
118 if (width == -1) width = src_width;
119 if (height == -1) height = src_height;
120
121 #ifdef __WXGTK20__
122 XCopyPlane( GDK_WINDOW_XDISPLAY(drawable),
123 GDK_WINDOW_XID(src),
124 GDK_WINDOW_XID(drawable),
125 GDK_GC_XGC(gc),
126 xsrc, ysrc,
127 width, height,
128 xdest, ydest,
129 1 );
130 #else
131 XCopyPlane( drawable_private->xdisplay,
132 src_private->xwindow,
133 drawable_private->xwindow,
134 gc_private->xgc,
135 xsrc, ysrc,
136 width, height,
137 xdest, ydest,
138 1 );
139 #endif
140 }
141
142 //-----------------------------------------------------------------------------
143 // Implement Pool of Graphic contexts. Creating them takes too much time.
144 //-----------------------------------------------------------------------------
145
146 #define GC_POOL_SIZE 200
147
148 enum wxPoolGCType
149 {
150 wxGC_ERROR = 0,
151 wxTEXT_MONO,
152 wxBG_MONO,
153 wxPEN_MONO,
154 wxBRUSH_MONO,
155 wxTEXT_COLOUR,
156 wxBG_COLOUR,
157 wxPEN_COLOUR,
158 wxBRUSH_COLOUR,
159 wxTEXT_SCREEN,
160 wxBG_SCREEN,
161 wxPEN_SCREEN,
162 wxBRUSH_SCREEN
163 };
164
165 struct wxGC
166 {
167 GdkGC *m_gc;
168 wxPoolGCType m_type;
169 bool m_used;
170 };
171
172 static wxGC wxGCPool[GC_POOL_SIZE];
173
174 static void wxInitGCPool()
175 {
176 memset( wxGCPool, 0, GC_POOL_SIZE*sizeof(wxGC) );
177 }
178
179 static void wxCleanUpGCPool()
180 {
181 for (int i = 0; i < GC_POOL_SIZE; i++)
182 {
183 if (wxGCPool[i].m_gc)
184 gdk_gc_unref( wxGCPool[i].m_gc );
185 }
186 }
187
188 static GdkGC* wxGetPoolGC( GdkWindow *window, wxPoolGCType type )
189 {
190 for (int i = 0; i < GC_POOL_SIZE; i++)
191 {
192 if (!wxGCPool[i].m_gc)
193 {
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;
198 }
199 if ((!wxGCPool[i].m_used) && (wxGCPool[i].m_type == type))
200 {
201 wxGCPool[i].m_used = TRUE;
202 return wxGCPool[i].m_gc;
203 }
204 }
205
206 wxFAIL_MSG( wxT("No GC available") );
207
208 return (GdkGC*) NULL;
209 }
210
211 static void wxFreePoolGC( GdkGC *gc )
212 {
213 for (int i = 0; i < GC_POOL_SIZE; i++)
214 {
215 if (wxGCPool[i].m_gc == gc)
216 {
217 wxGCPool[i].m_used = FALSE;
218 return;
219 }
220 }
221
222 wxFAIL_MSG( wxT("Wrong GC") );
223 }
224
225 //-----------------------------------------------------------------------------
226 // wxWindowDC
227 //-----------------------------------------------------------------------------
228
229 IMPLEMENT_DYNAMIC_CLASS(wxWindowDC, wxDC)
230
231 wxWindowDC::wxWindowDC()
232 {
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;
238 m_isMemDC = FALSE;
239 m_isScreenDC = FALSE;
240 m_owner = (wxWindow *)NULL;
241 #ifdef __WXGTK20__
242 m_context = (PangoContext *)NULL;
243 m_fontdesc = (PangoFontDescription *)NULL;
244 #endif
245 }
246
247 wxWindowDC::wxWindowDC( wxWindow *window )
248 {
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;
255 m_isMemDC = FALSE;
256 m_isScreenDC = FALSE;
257 m_font = window->GetFont();
258
259 wxASSERT_MSG( window, wxT("DC needs a window") );
260
261 GtkWidget *widget = window->m_wxwindow;
262
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
266 if ( !widget )
267 {
268 window = window->GetParent();
269 widget = window->m_wxwindow;
270 }
271
272 wxASSERT_MSG( widget, wxT("DC needs a widget") );
273
274 #ifdef __WXGTK20__
275 m_context = gtk_widget_get_pango_context( widget );
276 m_fontdesc = widget->style->font_desc;
277 #endif
278
279 GtkPizza *pizza = GTK_PIZZA( widget );
280 m_window = pizza->bin_window;
281
282 /* not realized ? */
283 if (!m_window)
284 {
285 /* don't report problems */
286 m_ok = TRUE;
287
288 return;
289 }
290
291 m_cmap = gtk_widget_get_colormap( widget ? widget : window->m_widget );
292
293 SetUpDC();
294
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) */
301
302 m_owner = window;
303 }
304
305 wxWindowDC::~wxWindowDC()
306 {
307 Destroy();
308 }
309
310 void wxWindowDC::SetUpDC()
311 {
312 m_ok = TRUE;
313
314 wxASSERT_MSG( !m_penGC, wxT("GCs already created") );
315
316 if (m_isScreenDC)
317 {
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 );
322 }
323 else
324 if (m_isMemDC && (((wxMemoryDC*)this)->m_selected.GetDepth() == 1))
325 {
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 );
330 }
331 else
332 {
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 );
337 }
338
339 /* background colour */
340 m_backgroundBrush = *wxWHITE_BRUSH;
341 m_backgroundBrush.GetColour().CalcPixel( m_cmap );
342 GdkColor *bg_col = m_backgroundBrush.GetColour().GetColor();
343
344 /* m_textGC */
345 m_textForegroundColour.CalcPixel( m_cmap );
346 gdk_gc_set_foreground( m_textGC, m_textForegroundColour.GetColor() );
347
348 m_textBackgroundColour.CalcPixel( m_cmap );
349 gdk_gc_set_background( m_textGC, m_textBackgroundColour.GetColor() );
350
351 gdk_gc_set_fill( m_textGC, GDK_SOLID );
352
353 /* m_penGC */
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 );
357
358 gdk_gc_set_line_attributes( m_penGC, 0, GDK_LINE_SOLID, GDK_CAP_NOT_LAST, GDK_JOIN_ROUND );
359
360 /* m_brushGC */
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 );
364
365 gdk_gc_set_fill( m_brushGC, GDK_SOLID );
366
367 /* m_bgGC */
368 gdk_gc_set_background( m_bgGC, bg_col );
369 gdk_gc_set_foreground( m_bgGC, bg_col );
370
371 gdk_gc_set_fill( m_bgGC, GDK_SOLID );
372
373 /* ROPs */
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 );
377
378 /* clipping */
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 );
383
384 if (!hatch_bitmap)
385 {
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 );
393 }
394 }
395
396 void wxWindowDC::DoGetSize( int* width, int* height ) const
397 {
398 wxCHECK_RET( m_owner, _T("GetSize() doesn't work without window") );
399
400 m_owner->GetSize(width, height);
401 }
402
403 void wxWindowDC::DoFloodFill( wxCoord WXUNUSED(x), wxCoord WXUNUSED(y),
404 const wxColour &WXUNUSED(col), int WXUNUSED(style) )
405 {
406 wxFAIL_MSG( wxT("wxWindowDC::DoFloodFill not implemented") );
407 }
408
409 bool wxWindowDC::DoGetPixel( wxCoord x1, wxCoord y1, wxColour *col ) const
410 {
411 // Generic (and therefore rather inefficient) method.
412 // Could be improved.
413 wxMemoryDC memdc;
414 wxBitmap bitmap(1, 1);
415 memdc.SelectObject(bitmap);
416 memdc.Blit(0, 0, 1, 1, (wxDC*) this, x1, y1);
417 memdc.SelectObject(wxNullBitmap);
418
419 wxImage image(bitmap);
420 col->Set(image.GetRed(0, 0), image.GetGreen(0, 0), image.GetBlue(0, 0));
421 return TRUE;
422 }
423
424 void wxWindowDC::DoDrawLine( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2 )
425 {
426 wxCHECK_RET( Ok(), wxT("invalid window dc") );
427
428 if (m_pen.GetStyle() != wxTRANSPARENT)
429 {
430 if (m_window)
431 gdk_draw_line( m_window, m_penGC, XLOG2DEV(x1), YLOG2DEV(y1), XLOG2DEV(x2), YLOG2DEV(y2) );
432
433 CalcBoundingBox(x1, y1);
434 CalcBoundingBox(x2, y2);
435 }
436 }
437
438 void wxWindowDC::DoCrossHair( wxCoord x, wxCoord y )
439 {
440 wxCHECK_RET( Ok(), wxT("invalid window dc") );
441
442 if (m_pen.GetStyle() != wxTRANSPARENT)
443 {
444 int w = 0;
445 int h = 0;
446 GetSize( &w, &h );
447 wxCoord xx = XLOG2DEV(x);
448 wxCoord yy = YLOG2DEV(y);
449 if (m_window)
450 {
451 gdk_draw_line( m_window, m_penGC, 0, yy, XLOG2DEVREL(w), yy );
452 gdk_draw_line( m_window, m_penGC, xx, 0, xx, YLOG2DEVREL(h) );
453 }
454 }
455 }
456
457 void wxWindowDC::DoDrawArc( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2,
458 wxCoord xc, wxCoord yc )
459 {
460 wxCHECK_RET( Ok(), wxT("invalid window dc") );
461
462 wxCoord xx1 = XLOG2DEV(x1);
463 wxCoord yy1 = YLOG2DEV(y1);
464 wxCoord xx2 = XLOG2DEV(x2);
465 wxCoord yy2 = YLOG2DEV(y2);
466 wxCoord xxc = XLOG2DEV(xc);
467 wxCoord yyc = YLOG2DEV(yc);
468 double dx = xx1 - xxc;
469 double dy = yy1 - yyc;
470 double radius = sqrt((double)(dx*dx+dy*dy));
471 wxCoord r = (wxCoord)radius;
472 double radius1, radius2;
473
474 if (xx1 == xx2 && yy1 == yy2)
475 {
476 radius1 = 0.0;
477 radius2 = 360.0;
478 }
479 else
480 if (radius == 0.0)
481 {
482 radius1 = radius2 = 0.0;
483 }
484 else
485 {
486 radius1 = (xx1 - xxc == 0) ?
487 (yy1 - yyc < 0) ? 90.0 : -90.0 :
488 -atan2(double(yy1-yyc), double(xx1-xxc)) * RAD2DEG;
489 radius2 = (xx2 - xxc == 0) ?
490 (yy2 - yyc < 0) ? 90.0 : -90.0 :
491 -atan2(double(yy2-yyc), double(xx2-xxc)) * RAD2DEG;
492 }
493 wxCoord alpha1 = wxCoord(radius1 * 64.0);
494 wxCoord alpha2 = wxCoord((radius2 - radius1) * 64.0);
495 while (alpha2 <= 0) alpha2 += 360*64;
496 while (alpha1 > 360*64) alpha1 -= 360*64;
497
498 if (m_window)
499 {
500 if (m_brush.GetStyle() != wxTRANSPARENT)
501 {
502 if ((m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE) && (m_brush.GetStipple()->GetMask()))
503 {
504 gdk_gc_set_ts_origin( m_textGC,
505 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
506 m_deviceOriginY % m_brush.GetStipple()->GetHeight() );
507 gdk_draw_arc( m_window, m_textGC, TRUE, xxc-r, yyc-r, 2*r,2*r, alpha1, alpha2 );
508 gdk_gc_set_ts_origin( m_textGC, 0, 0 );
509 } else
510 if (IS_15_PIX_HATCH(m_brush.GetStyle()))
511 {
512 gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 15, m_deviceOriginY % 15 );
513 gdk_draw_arc( m_window, m_brushGC, TRUE, xxc-r, yyc-r, 2*r,2*r, alpha1, alpha2 );
514 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
515 } else
516 if (IS_16_PIX_HATCH(m_brush.GetStyle()))
517 {
518 gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 16, m_deviceOriginY % 16 );
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 );
521 } else
522 if (m_brush.GetStyle() == wxSTIPPLE)
523 {
524 gdk_gc_set_ts_origin( m_brushGC,
525 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
526 m_deviceOriginY % m_brush.GetStipple()->GetHeight() );
527 gdk_draw_arc( m_window, m_brushGC, TRUE, xxc-r, yyc-r, 2*r,2*r, alpha1, alpha2 );
528 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
529 }
530 else
531 {
532 gdk_draw_arc( m_window, m_brushGC, TRUE, xxc-r, yyc-r, 2*r,2*r, alpha1, alpha2 );
533 }
534 }
535
536 if (m_pen.GetStyle() != wxTRANSPARENT)
537 {
538 gdk_draw_arc( m_window, m_penGC, FALSE, xxc-r, yyc-r, 2*r,2*r, alpha1, alpha2 );
539
540 gdk_draw_line( m_window, m_penGC, xx1, yy1, xxc, yyc );
541 gdk_draw_line( m_window, m_penGC, xxc, yyc, xx2, yy2 );
542 }
543 }
544
545 CalcBoundingBox (x1, y1);
546 CalcBoundingBox (x2, y2);
547 }
548
549 void wxWindowDC::DoDrawEllipticArc( wxCoord x, wxCoord y, wxCoord width, wxCoord height, double sa, double ea )
550 {
551 wxCHECK_RET( Ok(), wxT("invalid window dc") );
552
553 wxCoord xx = XLOG2DEV(x);
554 wxCoord yy = YLOG2DEV(y);
555 wxCoord ww = m_signX * XLOG2DEVREL(width);
556 wxCoord hh = m_signY * YLOG2DEVREL(height);
557
558 // CMB: handle -ve width and/or height
559 if (ww < 0) { ww = -ww; xx = xx - ww; }
560 if (hh < 0) { hh = -hh; yy = yy - hh; }
561
562 if (m_window)
563 {
564 wxCoord start = wxCoord(sa * 64.0);
565 wxCoord end = wxCoord((ea-sa) * 64.0);
566
567 if (m_brush.GetStyle() != wxTRANSPARENT)
568 {
569 if ((m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE) && (m_brush.GetStipple()->GetMask()))
570 {
571 gdk_gc_set_ts_origin( m_textGC,
572 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
573 m_deviceOriginY % m_brush.GetStipple()->GetHeight() );
574 gdk_draw_arc( m_window, m_textGC, TRUE, xx, yy, ww, hh, start, end );
575 gdk_gc_set_ts_origin( m_textGC, 0, 0 );
576 } else
577 if (IS_15_PIX_HATCH(m_brush.GetStyle()))
578 {
579 gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 15, m_deviceOriginY % 15 );
580 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, start, end );
581 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
582 } else
583 if (IS_16_PIX_HATCH(m_brush.GetStyle()))
584 {
585 gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 16, m_deviceOriginY % 16 );
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 );
588 } else
589 if (m_brush.GetStyle() == wxSTIPPLE)
590 {
591 gdk_gc_set_ts_origin( m_brushGC,
592 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
593 m_deviceOriginY % m_brush.GetStipple()->GetHeight() );
594 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, start, end );
595 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
596 }
597 else
598 {
599 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, start, end );
600 }
601 }
602
603 if (m_pen.GetStyle() != wxTRANSPARENT)
604 gdk_draw_arc( m_window, m_penGC, FALSE, xx, yy, ww, hh, start, end );
605 }
606
607 CalcBoundingBox (x, y);
608 CalcBoundingBox (x + width, y + height);
609 }
610
611 void wxWindowDC::DoDrawPoint( wxCoord x, wxCoord y )
612 {
613 wxCHECK_RET( Ok(), wxT("invalid window dc") );
614
615 if ((m_pen.GetStyle() != wxTRANSPARENT) && m_window)
616 gdk_draw_point( m_window, m_penGC, XLOG2DEV(x), YLOG2DEV(y) );
617
618 CalcBoundingBox (x, y);
619 }
620
621 void wxWindowDC::DoDrawLines( int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset )
622 {
623 wxCHECK_RET( Ok(), wxT("invalid window dc") );
624
625 if (m_pen.GetStyle() == wxTRANSPARENT) return;
626 if (n <= 0) return;
627
628 CalcBoundingBox( points[0].x + xoffset, points[0].y + yoffset );
629
630 for (int i = 0; i < n-1; i++)
631 {
632 wxCoord x1 = XLOG2DEV(points[i].x + xoffset);
633 wxCoord x2 = XLOG2DEV(points[i+1].x + xoffset);
634 wxCoord y1 = YLOG2DEV(points[i].y + yoffset); // oh, what a waste
635 wxCoord y2 = YLOG2DEV(points[i+1].y + yoffset);
636
637 if (m_window)
638 gdk_draw_line( m_window, m_penGC, x1, y1, x2, y2 );
639
640 CalcBoundingBox( points[i+1].x + xoffset, points[i+1].y + yoffset );
641 }
642 }
643
644 void wxWindowDC::DoDrawPolygon( int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset, int WXUNUSED(fillStyle) )
645 {
646 wxCHECK_RET( Ok(), wxT("invalid window dc") );
647
648 if (n <= 0) return;
649
650 GdkPoint *gdkpoints = new GdkPoint[n+1];
651 int i;
652 for (i = 0 ; i < n ; i++)
653 {
654 gdkpoints[i].x = XLOG2DEV(points[i].x + xoffset);
655 gdkpoints[i].y = YLOG2DEV(points[i].y + yoffset);
656
657 CalcBoundingBox( points[i].x + xoffset, points[i].y + yoffset );
658 }
659
660 if (m_window)
661 {
662 if (m_brush.GetStyle() != wxTRANSPARENT)
663 {
664 if ((m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE) && (m_brush.GetStipple()->GetMask()))
665 {
666 gdk_gc_set_ts_origin( m_textGC,
667 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
668 m_deviceOriginY % m_brush.GetStipple()->GetHeight() );
669 gdk_draw_polygon( m_window, m_textGC, TRUE, gdkpoints, n );
670 gdk_gc_set_ts_origin( m_textGC, 0, 0 );
671 } else
672 if (IS_15_PIX_HATCH(m_brush.GetStyle()))
673 {
674 gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 15, m_deviceOriginY % 15 );
675 gdk_draw_polygon( m_window, m_brushGC, TRUE, gdkpoints, n );
676 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
677 } else
678 if (IS_16_PIX_HATCH(m_brush.GetStyle()))
679 {
680 gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 16, m_deviceOriginY % 16 );
681 gdk_draw_polygon( m_window, m_brushGC, TRUE, gdkpoints, n );
682 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
683 } else
684 if (m_brush.GetStyle() == wxSTIPPLE)
685 {
686 gdk_gc_set_ts_origin( m_brushGC,
687 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
688 m_deviceOriginY % m_brush.GetStipple()->GetHeight() );
689 gdk_draw_polygon( m_window, m_brushGC, TRUE, gdkpoints, n );
690 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
691 }
692 else
693 {
694 gdk_draw_polygon( m_window, m_brushGC, TRUE, gdkpoints, n );
695 }
696 }
697
698 if (m_pen.GetStyle() != wxTRANSPARENT)
699 {
700 for (i = 0 ; i < n ; i++)
701 {
702 gdk_draw_line( m_window, m_penGC,
703 gdkpoints[i%n].x,
704 gdkpoints[i%n].y,
705 gdkpoints[(i+1)%n].x,
706 gdkpoints[(i+1)%n].y);
707 }
708 }
709 }
710
711 delete[] gdkpoints;
712 }
713
714 void wxWindowDC::DoDrawRectangle( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
715 {
716 wxCHECK_RET( Ok(), wxT("invalid window dc") );
717
718 wxCoord xx = XLOG2DEV(x);
719 wxCoord yy = YLOG2DEV(y);
720 wxCoord ww = m_signX * XLOG2DEVREL(width);
721 wxCoord hh = m_signY * YLOG2DEVREL(height);
722
723 // CMB: draw nothing if transformed w or h is 0
724 if (ww == 0 || hh == 0) return;
725
726 // CMB: handle -ve width and/or height
727 if (ww < 0) { ww = -ww; xx = xx - ww; }
728 if (hh < 0) { hh = -hh; yy = yy - hh; }
729
730 if (m_window)
731 {
732 if (m_brush.GetStyle() != wxTRANSPARENT)
733 {
734 if ((m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE) && (m_brush.GetStipple()->GetMask()))
735 {
736 gdk_gc_set_ts_origin( m_textGC,
737 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
738 m_deviceOriginY % m_brush.GetStipple()->GetHeight() );
739 gdk_draw_rectangle( m_window, m_textGC, TRUE, xx, yy, ww, hh );
740 gdk_gc_set_ts_origin( m_textGC, 0, 0 );
741 } else
742 if (IS_15_PIX_HATCH(m_brush.GetStyle()))
743 {
744 gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 15, m_deviceOriginY % 15 );
745 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx, yy, ww, hh );
746 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
747 } else
748 if (IS_16_PIX_HATCH(m_brush.GetStyle()))
749 {
750 gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 16, m_deviceOriginY % 16 );
751 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx, yy, ww, hh );
752 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
753 } else
754 if (m_brush.GetStyle() == wxSTIPPLE)
755 {
756 gdk_gc_set_ts_origin( m_brushGC,
757 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
758 m_deviceOriginY % m_brush.GetStipple()->GetHeight() );
759 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx, yy, ww, hh );
760 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
761 }
762 else
763 {
764 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx, yy, ww, hh );
765 }
766 }
767
768 if (m_pen.GetStyle() != wxTRANSPARENT)
769 gdk_draw_rectangle( m_window, m_penGC, FALSE, xx, yy, ww-1, hh-1 );
770 }
771
772 CalcBoundingBox( x, y );
773 CalcBoundingBox( x + width, y + height );
774 }
775
776 void wxWindowDC::DoDrawRoundedRectangle( wxCoord x, wxCoord y, wxCoord width, wxCoord height, double radius )
777 {
778 wxCHECK_RET( Ok(), wxT("invalid window dc") );
779
780 if (radius < 0.0) radius = - radius * ((width < height) ? width : height);
781
782 wxCoord xx = XLOG2DEV(x);
783 wxCoord yy = YLOG2DEV(y);
784 wxCoord ww = m_signX * XLOG2DEVREL(width);
785 wxCoord hh = m_signY * YLOG2DEVREL(height);
786 wxCoord rr = XLOG2DEVREL((wxCoord)radius);
787
788 // CMB: handle -ve width and/or height
789 if (ww < 0) { ww = -ww; xx = xx - ww; }
790 if (hh < 0) { hh = -hh; yy = yy - hh; }
791
792 // CMB: if radius is zero use DrawRectangle() instead to avoid
793 // X drawing errors with small radii
794 if (rr == 0)
795 {
796 DrawRectangle( x, y, width, height );
797 return;
798 }
799
800 // CMB: draw nothing if transformed w or h is 0
801 if (ww == 0 || hh == 0) return;
802
803 // CMB: adjust size if outline is drawn otherwise the result is
804 // 1 pixel too wide and high
805 if (m_pen.GetStyle() != wxTRANSPARENT)
806 {
807 ww--;
808 hh--;
809 }
810
811 if (m_window)
812 {
813 // CMB: ensure dd is not larger than rectangle otherwise we
814 // get an hour glass shape
815 wxCoord dd = 2 * rr;
816 if (dd > ww) dd = ww;
817 if (dd > hh) dd = hh;
818 rr = dd / 2;
819
820 if (m_brush.GetStyle() != wxTRANSPARENT)
821 {
822 if ((m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE) && (m_brush.GetStipple()->GetMask()))
823 {
824 gdk_gc_set_ts_origin( m_textGC,
825 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
826 m_deviceOriginY % m_brush.GetStipple()->GetHeight() );
827 gdk_draw_rectangle( m_window, m_textGC, TRUE, xx+rr, yy, ww-dd+1, hh );
828 gdk_draw_rectangle( m_window, m_textGC, TRUE, xx, yy+rr, ww, hh-dd+1 );
829 gdk_draw_arc( m_window, m_textGC, TRUE, xx, yy, dd, dd, 90*64, 90*64 );
830 gdk_draw_arc( m_window, m_textGC, TRUE, xx+ww-dd, yy, dd, dd, 0, 90*64 );
831 gdk_draw_arc( m_window, m_textGC, TRUE, xx+ww-dd, yy+hh-dd, dd, dd, 270*64, 90*64 );
832 gdk_draw_arc( m_window, m_textGC, TRUE, xx, yy+hh-dd, dd, dd, 180*64, 90*64 );
833 gdk_gc_set_ts_origin( m_textGC, 0, 0 );
834 } else
835 if (IS_15_PIX_HATCH(m_brush.GetStyle()))
836 {
837 gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 15, m_deviceOriginY % 15 );
838 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx+rr, yy, ww-dd+1, hh );
839 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx, yy+rr, ww, hh-dd+1 );
840 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, dd, dd, 90*64, 90*64 );
841 gdk_draw_arc( m_window, m_brushGC, TRUE, xx+ww-dd, yy, dd, dd, 0, 90*64 );
842 gdk_draw_arc( m_window, m_brushGC, TRUE, xx+ww-dd, yy+hh-dd, dd, dd, 270*64, 90*64 );
843 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy+hh-dd, dd, dd, 180*64, 90*64 );
844 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
845 } else
846 if (IS_16_PIX_HATCH(m_brush.GetStyle()))
847 {
848 gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 16, m_deviceOriginY % 16 );
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 );
856 } else
857 if (m_brush.GetStyle() == wxSTIPPLE)
858 {
859 gdk_gc_set_ts_origin( m_brushGC,
860 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
861 m_deviceOriginY % m_brush.GetStipple()->GetHeight() );
862 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx+rr, yy, ww-dd+1, hh );
863 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx, yy+rr, ww, hh-dd+1 );
864 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, dd, dd, 90*64, 90*64 );
865 gdk_draw_arc( m_window, m_brushGC, TRUE, xx+ww-dd, yy, dd, dd, 0, 90*64 );
866 gdk_draw_arc( m_window, m_brushGC, TRUE, xx+ww-dd, yy+hh-dd, dd, dd, 270*64, 90*64 );
867 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy+hh-dd, dd, dd, 180*64, 90*64 );
868 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
869 }
870 else
871 {
872 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx+rr, yy, ww-dd+1, hh );
873 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx, yy+rr, ww, hh-dd+1 );
874 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, dd, dd, 90*64, 90*64 );
875 gdk_draw_arc( m_window, m_brushGC, TRUE, xx+ww-dd, yy, dd, dd, 0, 90*64 );
876 gdk_draw_arc( m_window, m_brushGC, TRUE, xx+ww-dd, yy+hh-dd, dd, dd, 270*64, 90*64 );
877 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy+hh-dd, dd, dd, 180*64, 90*64 );
878 }
879 }
880
881 if (m_pen.GetStyle() != wxTRANSPARENT)
882 {
883 gdk_draw_line( m_window, m_penGC, xx+rr+1, yy, xx+ww-rr, yy );
884 gdk_draw_line( m_window, m_penGC, xx+rr+1, yy+hh, xx+ww-rr, yy+hh );
885 gdk_draw_line( m_window, m_penGC, xx, yy+rr+1, xx, yy+hh-rr );
886 gdk_draw_line( m_window, m_penGC, xx+ww, yy+rr+1, xx+ww, yy+hh-rr );
887 gdk_draw_arc( m_window, m_penGC, FALSE, xx, yy, dd, dd, 90*64, 90*64 );
888 gdk_draw_arc( m_window, m_penGC, FALSE, xx+ww-dd, yy, dd, dd, 0, 90*64 );
889 gdk_draw_arc( m_window, m_penGC, FALSE, xx+ww-dd, yy+hh-dd, dd, dd, 270*64, 90*64 );
890 gdk_draw_arc( m_window, m_penGC, FALSE, xx, yy+hh-dd, dd, dd, 180*64, 90*64 );
891 }
892 }
893
894 // this ignores the radius
895 CalcBoundingBox( x, y );
896 CalcBoundingBox( x + width, y + height );
897 }
898
899 void wxWindowDC::DoDrawEllipse( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
900 {
901 wxCHECK_RET( Ok(), wxT("invalid window dc") );
902
903 wxCoord xx = XLOG2DEV(x);
904 wxCoord yy = YLOG2DEV(y);
905 wxCoord ww = m_signX * XLOG2DEVREL(width);
906 wxCoord hh = m_signY * YLOG2DEVREL(height);
907
908 // CMB: handle -ve width and/or height
909 if (ww < 0) { ww = -ww; xx = xx - ww; }
910 if (hh < 0) { hh = -hh; yy = yy - hh; }
911
912 if (m_window)
913 {
914 if (m_brush.GetStyle() != wxTRANSPARENT)
915 {
916 if ((m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE) && (m_brush.GetStipple()->GetMask()))
917 {
918 gdk_gc_set_ts_origin( m_textGC,
919 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
920 m_deviceOriginY % m_brush.GetStipple()->GetHeight() );
921 gdk_draw_arc( m_window, m_textGC, TRUE, xx, yy, ww, hh, 0, 360*64 );
922 gdk_gc_set_ts_origin( m_textGC, 0, 0 );
923 } else
924 if (IS_15_PIX_HATCH(m_brush.GetStyle()))
925 {
926 gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 15, m_deviceOriginY % 15 );
927 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, 0, 360*64 );
928 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
929 } else
930 if (IS_16_PIX_HATCH(m_brush.GetStyle()))
931 {
932 gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 16, m_deviceOriginY % 16 );
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 );
935 } else
936 if (m_brush.GetStyle() == wxSTIPPLE)
937 {
938 gdk_gc_set_ts_origin( m_brushGC,
939 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
940 m_deviceOriginY % m_brush.GetStipple()->GetHeight() );
941 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, 0, 360*64 );
942 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
943 }
944 else
945 {
946 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, 0, 360*64 );
947 }
948 }
949
950 if (m_pen.GetStyle() != wxTRANSPARENT)
951 gdk_draw_arc( m_window, m_penGC, FALSE, xx, yy, ww, hh, 0, 360*64 );
952 }
953
954 CalcBoundingBox( x, y );
955 CalcBoundingBox( x + width, y + height );
956 }
957
958 void wxWindowDC::DoDrawIcon( const wxIcon &icon, wxCoord x, wxCoord y )
959 {
960 // VZ: egcs 1.0.3 refuses to compile this without cast, no idea why
961 DoDrawBitmap( (const wxBitmap&)icon, x, y, (bool)TRUE );
962 }
963
964 void wxWindowDC::DoDrawBitmap( const wxBitmap &bitmap,
965 wxCoord x, wxCoord y,
966 bool useMask )
967 {
968 wxCHECK_RET( Ok(), wxT("invalid window dc") );
969
970 wxCHECK_RET( bitmap.Ok(), wxT("invalid bitmap") );
971
972 bool is_mono = (bitmap.GetBitmap() != NULL);
973
974 /* scale/translate size and position */
975 int xx = XLOG2DEV(x);
976 int yy = YLOG2DEV(y);
977
978 int w = bitmap.GetWidth();
979 int h = bitmap.GetHeight();
980
981 CalcBoundingBox( x, y );
982 CalcBoundingBox( x + w, y + h );
983
984 if (!m_window) return;
985
986 int ww = XLOG2DEVREL(w);
987 int hh = YLOG2DEVREL(h);
988
989 /* compare to current clipping region */
990 if (!m_currentClippingRegion.IsNull())
991 {
992 wxRegion tmp( xx,yy,ww,hh );
993 tmp.Intersect( m_currentClippingRegion );
994 if (tmp.IsEmpty())
995 return;
996 }
997
998 /* scale bitmap if required */
999 wxBitmap use_bitmap;
1000 if ((w != ww) || (h != hh))
1001 {
1002 wxImage image( bitmap );
1003 image.Rescale( ww, hh );
1004 if (is_mono)
1005 use_bitmap = image.ConvertToMonoBitmap(255,255,255);
1006 else
1007 use_bitmap = image.ConvertToBitmap();
1008 }
1009 else
1010 {
1011 use_bitmap = bitmap;
1012 }
1013
1014 /* apply mask if any */
1015 GdkBitmap *mask = (GdkBitmap *) NULL;
1016 if (use_bitmap.GetMask()) mask = use_bitmap.GetMask()->GetBitmap();
1017
1018 if (useMask && mask)
1019 {
1020 GdkBitmap *new_mask = (GdkBitmap*) NULL;
1021 if (!m_currentClippingRegion.IsNull())
1022 {
1023 GdkColor col;
1024 new_mask = gdk_pixmap_new( wxGetRootWindow()->window, ww, hh, 1 );
1025 GdkGC *gc = gdk_gc_new( new_mask );
1026 col.pixel = 0;
1027 gdk_gc_set_foreground( gc, &col );
1028 gdk_draw_rectangle( new_mask, gc, TRUE, 0, 0, ww, hh );
1029 col.pixel = 0;
1030 gdk_gc_set_background( gc, &col );
1031 col.pixel = 1;
1032 gdk_gc_set_foreground( gc, &col );
1033 gdk_gc_set_clip_region( gc, m_currentClippingRegion.GetRegion() );
1034 gdk_gc_set_clip_origin( gc, -xx, -yy );
1035 gdk_gc_set_fill( gc, GDK_OPAQUE_STIPPLED );
1036 gdk_gc_set_stipple( gc, mask );
1037 gdk_draw_rectangle( new_mask, gc, TRUE, 0, 0, ww, hh );
1038 gdk_gc_unref( gc );
1039 }
1040
1041 if (is_mono)
1042 {
1043 if (new_mask)
1044 gdk_gc_set_clip_mask( m_textGC, new_mask );
1045 else
1046 gdk_gc_set_clip_mask( m_textGC, mask );
1047 gdk_gc_set_clip_origin( m_textGC, xx, yy );
1048 }
1049 else
1050 {
1051 if (new_mask)
1052 gdk_gc_set_clip_mask( m_penGC, new_mask );
1053 else
1054 gdk_gc_set_clip_mask( m_penGC, mask );
1055 gdk_gc_set_clip_origin( m_penGC, xx, yy );
1056 }
1057 if (new_mask)
1058 gdk_bitmap_unref( new_mask );
1059 }
1060
1061 /* Draw XPixmap or XBitmap, depending on what the wxBitmap contains. For
1062 drawing a mono-bitmap (XBitmap) we use the current text GC */
1063 if (is_mono)
1064 gdk_wx_draw_bitmap( m_window, m_textGC, use_bitmap.GetBitmap(), 0, 0, xx, yy, -1, -1 );
1065 else
1066 gdk_draw_pixmap( m_window, m_penGC, use_bitmap.GetPixmap(), 0, 0, xx, yy, -1, -1 );
1067
1068 /* remove mask again if any */
1069 if (useMask && mask)
1070 {
1071 if (is_mono)
1072 {
1073 gdk_gc_set_clip_mask( m_textGC, (GdkBitmap *) NULL );
1074 gdk_gc_set_clip_origin( m_textGC, 0, 0 );
1075 if (!m_currentClippingRegion.IsNull())
1076 gdk_gc_set_clip_region( m_textGC, m_currentClippingRegion.GetRegion() );
1077 }
1078 else
1079 {
1080 gdk_gc_set_clip_mask( m_penGC, (GdkBitmap *) NULL );
1081 gdk_gc_set_clip_origin( m_penGC, 0, 0 );
1082 if (!m_currentClippingRegion.IsNull())
1083 gdk_gc_set_clip_region( m_penGC, m_currentClippingRegion.GetRegion() );
1084 }
1085 }
1086 }
1087
1088 bool wxWindowDC::DoBlit( wxCoord xdest, wxCoord ydest,
1089 wxCoord width, wxCoord height,
1090 wxDC *source,
1091 wxCoord xsrc, wxCoord ysrc,
1092 int logical_func,
1093 bool useMask )
1094 {
1095 /* this is the nth try to get this utterly useless function to
1096 work. it now completely ignores the scaling or translation
1097 of the source dc, but scales correctly on the target dc and
1098 knows about possible mask information in a memory dc. */
1099
1100 wxCHECK_MSG( Ok(), FALSE, wxT("invalid window dc") );
1101
1102 wxCHECK_MSG( source, FALSE, wxT("invalid source dc") );
1103
1104 if (!m_window) return FALSE;
1105
1106 #if 0
1107 // transform the source DC coords to the device ones
1108 xsrc = XLOG2DEV(xsrc);
1109 ysrc = YLOG2DEV(ysrc);
1110 #endif
1111
1112 wxClientDC *srcDC = (wxClientDC*)source;
1113 wxMemoryDC *memDC = (wxMemoryDC*)source;
1114
1115 bool use_bitmap_method = FALSE;
1116 bool is_mono = FALSE;
1117
1118 if (srcDC->m_isMemDC)
1119 {
1120 if (!memDC->m_selected.Ok()) return FALSE;
1121
1122 /* we use the "XCopyArea" way to copy a memory dc into
1123 y different window if the memory dc BOTH
1124 a) doesn't have any mask or its mask isn't used
1125 b) it is clipped
1126 c) is not 1-bit */
1127
1128 if (useMask && (memDC->m_selected.GetMask()))
1129 {
1130 /* we HAVE TO use the direct way for memory dcs
1131 that have mask since the XCopyArea doesn't know
1132 about masks */
1133 use_bitmap_method = TRUE;
1134 }
1135 else if (memDC->m_selected.GetDepth() == 1)
1136 {
1137 /* we HAVE TO use the direct way for memory dcs
1138 that are bitmaps because XCopyArea doesn't cope
1139 with different bit depths */
1140 is_mono = TRUE;
1141 use_bitmap_method = TRUE;
1142 }
1143 else if ((xsrc == 0) && (ysrc == 0) &&
1144 (width == memDC->m_selected.GetWidth()) &&
1145 (height == memDC->m_selected.GetHeight()))
1146 {
1147 /* we SHOULD use the direct way if all of the bitmap
1148 in the memory dc is copied in which case XCopyArea
1149 wouldn't be able able to boost performace by reducing
1150 the area to be scaled */
1151 use_bitmap_method = TRUE;
1152 }
1153 else
1154 {
1155 use_bitmap_method = FALSE;
1156 }
1157 }
1158
1159 CalcBoundingBox( xdest, ydest );
1160 CalcBoundingBox( xdest + width, ydest + height );
1161
1162 /* scale/translate size and position */
1163 wxCoord xx = XLOG2DEV(xdest);
1164 wxCoord yy = YLOG2DEV(ydest);
1165
1166 wxCoord ww = XLOG2DEVREL(width);
1167 wxCoord hh = YLOG2DEVREL(height);
1168
1169 /* compare to current clipping region */
1170 if (!m_currentClippingRegion.IsNull())
1171 {
1172 wxRegion tmp( xx,yy,ww,hh );
1173 tmp.Intersect( m_currentClippingRegion );
1174 if (tmp.IsEmpty())
1175 return TRUE;
1176 }
1177
1178 int old_logical_func = m_logicalFunction;
1179 SetLogicalFunction( logical_func );
1180
1181 if (use_bitmap_method)
1182 {
1183 /* scale/translate bitmap size */
1184 wxCoord bm_width = memDC->m_selected.GetWidth();
1185 wxCoord bm_height = memDC->m_selected.GetHeight();
1186
1187 wxCoord bm_ww = XLOG2DEVREL( bm_width );
1188 wxCoord bm_hh = YLOG2DEVREL( bm_height );
1189
1190 /* scale bitmap if required */
1191 wxBitmap use_bitmap;
1192
1193 if ((bm_width != bm_ww) || (bm_height != bm_hh))
1194 {
1195 wxImage image( memDC->m_selected );
1196 image = image.Scale( bm_ww, bm_hh );
1197
1198 if (is_mono)
1199 use_bitmap = image.ConvertToMonoBitmap(255,255,255);
1200 else
1201 use_bitmap = image.ConvertToBitmap();
1202 }
1203 else
1204 {
1205 use_bitmap = memDC->m_selected;
1206 }
1207
1208 /* apply mask if any */
1209 GdkBitmap *mask = (GdkBitmap *) NULL;
1210 if (use_bitmap.GetMask()) mask = use_bitmap.GetMask()->GetBitmap();
1211
1212 if (useMask && mask)
1213 {
1214 GdkBitmap *new_mask = (GdkBitmap*) NULL;
1215 if (!m_currentClippingRegion.IsNull())
1216 {
1217 GdkColor col;
1218 new_mask = gdk_pixmap_new( wxGetRootWindow()->window, bm_ww, bm_hh, 1 );
1219 GdkGC *gc = gdk_gc_new( new_mask );
1220 col.pixel = 0;
1221 gdk_gc_set_foreground( gc, &col );
1222 gdk_draw_rectangle( new_mask, gc, TRUE, 0, 0, bm_ww, bm_hh );
1223 col.pixel = 0;
1224 gdk_gc_set_background( gc, &col );
1225 col.pixel = 1;
1226 gdk_gc_set_foreground( gc, &col );
1227 gdk_gc_set_clip_region( gc, m_currentClippingRegion.GetRegion() );
1228 gdk_gc_set_clip_origin( gc, -xx, -yy );
1229 gdk_gc_set_fill( gc, GDK_OPAQUE_STIPPLED );
1230 gdk_gc_set_stipple( gc, mask );
1231 gdk_draw_rectangle( new_mask, gc, TRUE, 0, 0, bm_ww, bm_hh );
1232 gdk_gc_unref( gc );
1233 }
1234
1235 if (is_mono)
1236 {
1237 if (new_mask)
1238 gdk_gc_set_clip_mask( m_textGC, new_mask );
1239 else
1240 gdk_gc_set_clip_mask( m_textGC, mask );
1241 gdk_gc_set_clip_origin( m_textGC, xx, yy );
1242 }
1243 else
1244 {
1245 if (new_mask)
1246 gdk_gc_set_clip_mask( m_penGC, new_mask );
1247 else
1248 gdk_gc_set_clip_mask( m_penGC, mask );
1249 gdk_gc_set_clip_origin( m_penGC, xx, yy );
1250 }
1251 if (new_mask)
1252 gdk_bitmap_unref( new_mask );
1253 }
1254
1255 /* Draw XPixmap or XBitmap, depending on what the wxBitmap contains. For
1256 drawing a mono-bitmap (XBitmap) we use the current text GC */
1257
1258 if (is_mono)
1259 gdk_wx_draw_bitmap( m_window, m_textGC, use_bitmap.GetBitmap(), xsrc, ysrc, xx, yy, ww, hh );
1260 else
1261 gdk_draw_pixmap( m_window, m_penGC, use_bitmap.GetPixmap(), xsrc, ysrc, xx, yy, ww, hh );
1262
1263 /* remove mask again if any */
1264 if (useMask && mask)
1265 {
1266 if (is_mono)
1267 {
1268 gdk_gc_set_clip_mask( m_textGC, (GdkBitmap *) NULL );
1269 gdk_gc_set_clip_origin( m_textGC, 0, 0 );
1270 if (!m_currentClippingRegion.IsNull())
1271 gdk_gc_set_clip_region( m_textGC, m_currentClippingRegion.GetRegion() );
1272 }
1273 else
1274 {
1275 gdk_gc_set_clip_mask( m_penGC, (GdkBitmap *) NULL );
1276 gdk_gc_set_clip_origin( m_penGC, 0, 0 );
1277 if (!m_currentClippingRegion.IsNull())
1278 gdk_gc_set_clip_region( m_penGC, m_currentClippingRegion.GetRegion() );
1279 }
1280 }
1281 }
1282 else /* use_bitmap_method */
1283 {
1284 if ((width != ww) || (height != hh))
1285 {
1286 /* draw source window into a bitmap as we cannot scale
1287 a window in contrast to a bitmap. this would actually
1288 work with memory dcs as well, but we'd lose the mask
1289 information and waste one step in this process since
1290 a memory already has a bitmap. all this is slightly
1291 inefficient as we could take an XImage directly from
1292 an X window, but we'd then also have to care that
1293 the window is not outside the screen (in which case
1294 we'd get a BadMatch or what not).
1295 Is a double XGetImage and combined XGetPixel and
1296 XPutPixel really faster? I'm not sure. look at wxXt
1297 for a different implementation of the same problem. */
1298
1299 wxBitmap bitmap( width, height );
1300
1301 /* copy including child window contents */
1302 gdk_gc_set_subwindow( m_penGC, GDK_INCLUDE_INFERIORS );
1303 gdk_window_copy_area( bitmap.GetPixmap(), m_penGC, 0, 0,
1304 srcDC->GetWindow(),
1305 xsrc, ysrc, width, height );
1306 gdk_gc_set_subwindow( m_penGC, GDK_CLIP_BY_CHILDREN );
1307
1308 /* scale image */
1309 wxImage image( bitmap );
1310 image = image.Scale( ww, hh );
1311
1312 /* convert to bitmap */
1313 bitmap = image.ConvertToBitmap();
1314
1315 /* draw scaled bitmap */
1316 gdk_draw_pixmap( m_window, m_penGC, bitmap.GetPixmap(), 0, 0, xx, yy, -1, -1 );
1317
1318 }
1319 else
1320 {
1321 /* No scaling and not a memory dc with a mask either */
1322
1323 /* copy including child window contents */
1324 gdk_gc_set_subwindow( m_penGC, GDK_INCLUDE_INFERIORS );
1325 gdk_window_copy_area( m_window, m_penGC, xx, yy,
1326 srcDC->GetWindow(),
1327 xsrc, ysrc, width, height );
1328 gdk_gc_set_subwindow( m_penGC, GDK_CLIP_BY_CHILDREN );
1329 }
1330 }
1331
1332 SetLogicalFunction( old_logical_func );
1333 return TRUE;
1334 }
1335
1336 void wxWindowDC::DoDrawText( const wxString &text, wxCoord x, wxCoord y )
1337 {
1338 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1339
1340 if (!m_window) return;
1341
1342 GdkFont *font = m_font.GetInternalFont( m_scaleY );
1343
1344 wxCHECK_RET( font, wxT("invalid font") );
1345
1346 #if defined(__WXGTK20__)
1347 wxCHECK_RET( m_context, wxT("no Pango context") );
1348 #endif
1349
1350 x = XLOG2DEV(x);
1351 y = YLOG2DEV(y);
1352
1353 #if defined(__WXGTK20__) && wxUSE_WCHAR_T
1354 /* FIXME: the layout engine should probably be abstracted at a higher level in wxDC... */
1355 PangoLayout *layout = pango_layout_new(m_context);
1356 pango_layout_set_font_description(layout, m_fontdesc);
1357 {
1358 wxWX2MBbuf data = text.mb_str(wxConvUTF8);
1359 pango_layout_set_text(layout, data, strlen(data));
1360 }
1361 PangoLayoutLine *line = (PangoLayoutLine *)pango_layout_get_lines(layout)->data;
1362 PangoRectangle rect;
1363 pango_layout_line_get_extents(line, NULL, &rect);
1364 wxCoord width = rect.width;
1365 wxCoord height = rect.height;
1366 gdk_draw_layout( m_window, m_textGC, x, y, layout );
1367 #else
1368 wxCoord width = gdk_string_width( font, text.mbc_str() );
1369 wxCoord height = font->ascent + font->descent;
1370 /* CMB 21/5/98: draw text background if mode is wxSOLID */
1371 if (m_backgroundMode == wxSOLID)
1372 {
1373 gdk_gc_set_foreground( m_textGC, m_textBackgroundColour.GetColor() );
1374 gdk_draw_rectangle( m_window, m_textGC, TRUE, x, y, width, height );
1375 gdk_gc_set_foreground( m_textGC, m_textForegroundColour.GetColor() );
1376 }
1377 gdk_draw_string( m_window, font, m_textGC, x, y + font->ascent, text.mbc_str() );
1378 #endif
1379
1380 /* CMB 17/7/98: simple underline: ignores scaling and underlying
1381 X font's XA_UNDERLINE_POSITION and XA_UNDERLINE_THICKNESS
1382 properties (see wxXt implementation) */
1383 if (m_font.GetUnderlined())
1384 {
1385 wxCoord ul_y = y + font->ascent;
1386 if (font->descent > 0) ul_y++;
1387 gdk_draw_line( m_window, m_textGC, x, ul_y, x + width, ul_y);
1388 }
1389
1390 #if defined(__WXGTK20__) && wxUSE_WCHAR_T
1391 g_object_unref( G_OBJECT( layout ) );
1392 #endif
1393
1394 width = wxCoord(width / m_scaleX);
1395 height = wxCoord(height / m_scaleY);
1396 CalcBoundingBox (x + width, y + height);
1397 CalcBoundingBox (x, y);
1398 }
1399
1400 void wxWindowDC::DoDrawRotatedText( const wxString &text, wxCoord x, wxCoord y, double angle )
1401 {
1402 if (angle == 0.0)
1403 {
1404 DrawText(text, x, y);
1405 return;
1406 }
1407
1408 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1409
1410 if (!m_window) return;
1411
1412 GdkFont *font = m_font.GetInternalFont( m_scaleY );
1413
1414 wxCHECK_RET( font, wxT("invalid font") );
1415
1416 // the size of the text
1417 wxCoord w = gdk_string_width( font, text.mbc_str() );
1418 wxCoord h = font->ascent + font->descent;
1419
1420 // draw the string normally
1421 wxBitmap src(w, h);
1422 wxMemoryDC dc;
1423 dc.SelectObject(src);
1424 dc.SetFont(GetFont());
1425 dc.SetBackground(*wxWHITE_BRUSH);
1426 dc.SetBrush(*wxBLACK_BRUSH);
1427 dc.Clear();
1428 dc.DrawText(text, 0, 0);
1429 dc.SetFont(wxNullFont);
1430 dc.SelectObject(wxNullBitmap);
1431
1432 // Calculate the size of the rotated bounding box.
1433 double rad = DegToRad(angle);
1434 double dx = cos(rad),
1435 dy = sin(rad);
1436
1437 // the rectngle vertices are counted clockwise with the first one being at
1438 // (0, 0) (or, rather, at (x, y))
1439 double x2 = w*dx,
1440 y2 = -w*dy; // y axis points to the bottom, hence minus
1441 double x4 = h*dy,
1442 y4 = h*dx;
1443 double x3 = x4 + x2,
1444 y3 = y4 + y2;
1445
1446 // calc max and min
1447 wxCoord maxX = (wxCoord)(dmax(x2, dmax(x3, x4)) + 0.5),
1448 maxY = (wxCoord)(dmax(y2, dmax(y3, y4)) + 0.5),
1449 minX = (wxCoord)(dmin(x2, dmin(x3, x4)) - 0.5),
1450 minY = (wxCoord)(dmin(y2, dmin(y3, y4)) - 0.5);
1451
1452 // prepare to blit-with-rotate the bitmap to the DC
1453 wxImage image(src);
1454
1455 GdkColor *colText = m_textForegroundColour.GetColor(),
1456 *colBack = m_textBackgroundColour.GetColor();
1457
1458 bool textColSet = TRUE;
1459
1460 unsigned char *data = image.GetData();
1461
1462 // paint pixel by pixel
1463 for ( wxCoord srcX = 0; srcX < w; srcX++ )
1464 {
1465 for ( wxCoord srcY = 0; srcY < h; srcY++ )
1466 {
1467 // transform source coords to dest coords
1468 double r = sqrt((double)srcX*srcX + srcY*srcY);
1469 double angleOrig = atan2((double)srcY, (double)srcX) - rad;
1470 wxCoord dstX = (wxCoord)(r*cos(angleOrig) + 0.5),
1471 dstY = (wxCoord)(r*sin(angleOrig) + 0.5);
1472
1473 // black pixel?
1474 bool textPixel = data[(srcY*w + srcX)*3] == 0;
1475 if ( textPixel || (m_backgroundMode == wxSOLID) )
1476 {
1477 // change colour if needed
1478 if ( textPixel != textColSet )
1479 {
1480 gdk_gc_set_foreground( m_textGC, textPixel ? colText
1481 : colBack );
1482
1483 textColSet = textPixel;
1484 }
1485
1486 // don't use DrawPoint() because it uses the current pen
1487 // colour, and we don't need it here
1488 gdk_draw_point( m_window, m_textGC,
1489 XLOG2DEV(x + dstX), YLOG2DEV(y + dstY) );
1490 }
1491 }
1492 }
1493
1494 // it would be better to draw with non underlined font and draw the line
1495 // manually here (it would be more straight...)
1496 #if 0
1497 if ( m_font.GetUnderlined() )
1498 {
1499 gdk_draw_line( m_window, m_textGC,
1500 XLOG2DEV(x + x4), YLOG2DEV(y + y4 + font->descent),
1501 XLOG2DEV(x + x3), YLOG2DEV(y + y3 + font->descent));
1502 }
1503 #endif // 0
1504
1505 // restore the font colour
1506 gdk_gc_set_foreground( m_textGC, colText );
1507
1508 // update the bounding box
1509 CalcBoundingBox(x + minX, y + minY);
1510 CalcBoundingBox(x + maxX, y + maxY);
1511 }
1512
1513 void wxWindowDC::DoGetTextExtent(const wxString &string,
1514 wxCoord *width, wxCoord *height,
1515 wxCoord *descent, wxCoord *externalLeading,
1516 wxFont *theFont) const
1517 {
1518 wxFont fontToUse = m_font;
1519 if (theFont) fontToUse = *theFont;
1520
1521 GdkFont *font = fontToUse.GetInternalFont( m_scaleY );
1522 if (width) (*width) = wxCoord(gdk_string_width( font, string.mbc_str() ) / m_scaleX);
1523 if (height) (*height) = wxCoord((font->ascent + font->descent) / m_scaleY);
1524 if (descent) (*descent) = wxCoord(font->descent / m_scaleY);
1525 if (externalLeading) (*externalLeading) = 0; // ??
1526 }
1527
1528 wxCoord wxWindowDC::GetCharWidth() const
1529 {
1530 GdkFont *font = m_font.GetInternalFont( m_scaleY );
1531 wxCHECK_MSG( font, -1, wxT("invalid font") );
1532
1533 return wxCoord(gdk_string_width( font, "H" ) / m_scaleX);
1534 }
1535
1536 wxCoord wxWindowDC::GetCharHeight() const
1537 {
1538 GdkFont *font = m_font.GetInternalFont( m_scaleY );
1539 wxCHECK_MSG( font, -1, wxT("invalid font") );
1540
1541 return wxCoord((font->ascent + font->descent) / m_scaleY);
1542 }
1543
1544 void wxWindowDC::Clear()
1545 {
1546 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1547
1548 if (!m_window) return;
1549
1550 /* - we either are a memory dc or have a window as the
1551 owner. anything else shouldn't happen.
1552 - we don't use gdk_window_clear() as we don't set
1553 the window's background colour anymore. it is too
1554 much pain to keep the DC's and the window's back-
1555 ground colour in synch. */
1556
1557 if (m_owner)
1558 {
1559 int width,height;
1560 m_owner->GetSize( &width, &height );
1561 gdk_draw_rectangle( m_window, m_bgGC, TRUE, 0, 0, width, height );
1562 return;
1563 }
1564
1565 if (m_isMemDC)
1566 {
1567 int width,height;
1568 GetSize( &width, &height );
1569 gdk_draw_rectangle( m_window, m_bgGC, TRUE, 0, 0, width, height );
1570 return;
1571 }
1572 }
1573
1574 void wxWindowDC::SetFont( const wxFont &font )
1575 {
1576 m_font = font;
1577 #ifdef __WXGTK20__
1578 // fix fontdesc?
1579 #endif
1580 }
1581
1582 void wxWindowDC::SetPen( const wxPen &pen )
1583 {
1584 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1585
1586 if (m_pen == pen) return;
1587
1588 m_pen = pen;
1589
1590 if (!m_pen.Ok()) return;
1591
1592 if (!m_window) return;
1593
1594 gint width = m_pen.GetWidth();
1595 if (width <= 0)
1596 {
1597 // CMB: if width is non-zero scale it with the dc
1598 width = 1;
1599 }
1600 else
1601 {
1602 // X doesn't allow different width in x and y and so we take
1603 // the average
1604 double w = 0.5 +
1605 ( fabs((double) XLOG2DEVREL(width)) +
1606 fabs((double) YLOG2DEVREL(width)) ) / 2.0;
1607 width = (int)w;
1608 }
1609
1610 static const wxGTKDash dotted[] = {1, 1};
1611 static const wxGTKDash short_dashed[] = {2, 2};
1612 static const wxGTKDash wxCoord_dashed[] = {2, 4};
1613 static const wxGTKDash dotted_dashed[] = {3, 3, 1, 3};
1614
1615 // We express dash pattern in pen width unit, so we are
1616 // independent of zoom factor and so on...
1617 int req_nb_dash;
1618 const wxGTKDash *req_dash;
1619
1620 GdkLineStyle lineStyle = GDK_LINE_SOLID;
1621 switch (m_pen.GetStyle())
1622 {
1623 case wxUSER_DASH:
1624 {
1625 lineStyle = GDK_LINE_ON_OFF_DASH;
1626 req_nb_dash = m_pen.GetDashCount();
1627 req_dash = (wxGTKDash*)m_pen.GetDash();
1628 break;
1629 }
1630 case wxDOT:
1631 {
1632 lineStyle = GDK_LINE_ON_OFF_DASH;
1633 req_nb_dash = 2;
1634 req_dash = dotted;
1635 break;
1636 }
1637 case wxLONG_DASH:
1638 {
1639 lineStyle = GDK_LINE_ON_OFF_DASH;
1640 req_nb_dash = 2;
1641 req_dash = wxCoord_dashed;
1642 break;
1643 }
1644 case wxSHORT_DASH:
1645 {
1646 lineStyle = GDK_LINE_ON_OFF_DASH;
1647 req_nb_dash = 2;
1648 req_dash = short_dashed;
1649 break;
1650 }
1651 case wxDOT_DASH:
1652 {
1653 // lineStyle = GDK_LINE_DOUBLE_DASH;
1654 lineStyle = GDK_LINE_ON_OFF_DASH;
1655 req_nb_dash = 4;
1656 req_dash = dotted_dashed;
1657 break;
1658 }
1659
1660 case wxTRANSPARENT:
1661 case wxSTIPPLE_MASK_OPAQUE:
1662 case wxSTIPPLE:
1663 case wxSOLID:
1664 default:
1665 {
1666 lineStyle = GDK_LINE_SOLID;
1667 req_dash = (wxGTKDash*)NULL;
1668 req_nb_dash = 0;
1669 break;
1670 }
1671 }
1672
1673 #if (GTK_MINOR_VERSION > 0) || (GTK_MAJOR_VERSION > 1)
1674 if (req_dash && req_nb_dash)
1675 {
1676 wxGTKDash *real_req_dash = new wxGTKDash[req_nb_dash];
1677 if (real_req_dash)
1678 {
1679 for (int i = 0; i < req_nb_dash; i++)
1680 real_req_dash[i] = req_dash[i] * width;
1681 gdk_gc_set_dashes( m_penGC, 0, real_req_dash, req_nb_dash );
1682 delete[] real_req_dash;
1683 }
1684 else
1685 {
1686 // No Memory. We use non-scaled dash pattern...
1687 gdk_gc_set_dashes( m_penGC, 0, (wxGTKDash*)req_dash, req_nb_dash );
1688 }
1689 }
1690 #endif
1691
1692 GdkCapStyle capStyle = GDK_CAP_ROUND;
1693 switch (m_pen.GetCap())
1694 {
1695 case wxCAP_PROJECTING: { capStyle = GDK_CAP_PROJECTING; break; }
1696 case wxCAP_BUTT: { capStyle = GDK_CAP_BUTT; break; }
1697 case wxCAP_ROUND:
1698 default:
1699 {
1700 if (width <= 1)
1701 {
1702 width = 0;
1703 capStyle = GDK_CAP_NOT_LAST;
1704 }
1705 else
1706 {
1707 capStyle = GDK_CAP_ROUND;
1708 }
1709 break;
1710 }
1711 }
1712
1713 GdkJoinStyle joinStyle = GDK_JOIN_ROUND;
1714 switch (m_pen.GetJoin())
1715 {
1716 case wxJOIN_BEVEL: { joinStyle = GDK_JOIN_BEVEL; break; }
1717 case wxJOIN_MITER: { joinStyle = GDK_JOIN_MITER; break; }
1718 case wxJOIN_ROUND:
1719 default: { joinStyle = GDK_JOIN_ROUND; break; }
1720 }
1721
1722 gdk_gc_set_line_attributes( m_penGC, width, lineStyle, capStyle, joinStyle );
1723
1724 m_pen.GetColour().CalcPixel( m_cmap );
1725 gdk_gc_set_foreground( m_penGC, m_pen.GetColour().GetColor() );
1726 }
1727
1728 void wxWindowDC::SetBrush( const wxBrush &brush )
1729 {
1730 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1731
1732 if (m_brush == brush) return;
1733
1734 m_brush = brush;
1735
1736 if (!m_brush.Ok()) return;
1737
1738 if (!m_window) return;
1739
1740 m_brush.GetColour().CalcPixel( m_cmap );
1741 gdk_gc_set_foreground( m_brushGC, m_brush.GetColour().GetColor() );
1742
1743 gdk_gc_set_fill( m_brushGC, GDK_SOLID );
1744
1745 if ((m_brush.GetStyle() == wxSTIPPLE) && (m_brush.GetStipple()->Ok()))
1746 {
1747 if (m_brush.GetStipple()->GetPixmap())
1748 {
1749 gdk_gc_set_fill( m_brushGC, GDK_TILED );
1750 gdk_gc_set_tile( m_brushGC, m_brush.GetStipple()->GetPixmap() );
1751 }
1752 else
1753 {
1754 gdk_gc_set_fill( m_brushGC, GDK_STIPPLED );
1755 gdk_gc_set_stipple( m_brushGC, m_brush.GetStipple()->GetBitmap() );
1756 }
1757 }
1758
1759 if ((m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE) && (m_brush.GetStipple()->GetMask()))
1760 {
1761 gdk_gc_set_fill( m_textGC, GDK_OPAQUE_STIPPLED);
1762 gdk_gc_set_stipple( m_textGC, m_brush.GetStipple()->GetMask()->GetBitmap() );
1763 }
1764
1765 if (IS_HATCH(m_brush.GetStyle()))
1766 {
1767 gdk_gc_set_fill( m_brushGC, GDK_STIPPLED );
1768 int num = m_brush.GetStyle() - wxBDIAGONAL_HATCH;
1769 gdk_gc_set_stipple( m_brushGC, hatches[num] );
1770 }
1771 }
1772
1773 void wxWindowDC::SetBackground( const wxBrush &brush )
1774 {
1775 /* CMB 21/7/98: Added SetBackground. Sets background brush
1776 * for Clear() and bg colour for shapes filled with cross-hatch brush */
1777
1778 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1779
1780 if (m_backgroundBrush == brush) return;
1781
1782 m_backgroundBrush = brush;
1783
1784 if (!m_backgroundBrush.Ok()) return;
1785
1786 if (!m_window) return;
1787
1788 m_backgroundBrush.GetColour().CalcPixel( m_cmap );
1789 gdk_gc_set_background( m_brushGC, m_backgroundBrush.GetColour().GetColor() );
1790 gdk_gc_set_background( m_penGC, m_backgroundBrush.GetColour().GetColor() );
1791 gdk_gc_set_background( m_bgGC, m_backgroundBrush.GetColour().GetColor() );
1792 gdk_gc_set_foreground( m_bgGC, m_backgroundBrush.GetColour().GetColor() );
1793
1794 gdk_gc_set_fill( m_bgGC, GDK_SOLID );
1795
1796 if ((m_backgroundBrush.GetStyle() == wxSTIPPLE) && (m_backgroundBrush.GetStipple()->Ok()))
1797 {
1798 if (m_backgroundBrush.GetStipple()->GetPixmap())
1799 {
1800 gdk_gc_set_fill( m_bgGC, GDK_TILED );
1801 gdk_gc_set_tile( m_bgGC, m_backgroundBrush.GetStipple()->GetPixmap() );
1802 }
1803 else
1804 {
1805 gdk_gc_set_fill( m_bgGC, GDK_STIPPLED );
1806 gdk_gc_set_stipple( m_bgGC, m_backgroundBrush.GetStipple()->GetBitmap() );
1807 }
1808 }
1809
1810 if (IS_HATCH(m_backgroundBrush.GetStyle()))
1811 {
1812 gdk_gc_set_fill( m_bgGC, GDK_STIPPLED );
1813 int num = m_backgroundBrush.GetStyle() - wxBDIAGONAL_HATCH;
1814 gdk_gc_set_stipple( m_bgGC, hatches[num] );
1815 }
1816 }
1817
1818 void wxWindowDC::SetLogicalFunction( int function )
1819 {
1820 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1821
1822 if (m_logicalFunction == function)
1823 return;
1824
1825 // VZ: shouldn't this be a CHECK?
1826 if (!m_window)
1827 return;
1828
1829 GdkFunction mode = GDK_COPY;
1830 switch (function)
1831 {
1832 case wxXOR: mode = GDK_XOR; break;
1833 case wxINVERT: mode = GDK_INVERT; break;
1834 #if (GTK_MINOR_VERSION > 0)
1835 case wxOR_REVERSE: mode = GDK_OR_REVERSE; break;
1836 case wxAND_REVERSE: mode = GDK_AND_REVERSE; break;
1837 case wxCLEAR: mode = GDK_CLEAR; break;
1838 case wxSET: mode = GDK_SET; break;
1839 case wxOR_INVERT: mode = GDK_OR_INVERT; break;
1840 case wxAND: mode = GDK_AND; break;
1841 case wxOR: mode = GDK_OR; break;
1842 case wxEQUIV: mode = GDK_EQUIV; break;
1843 case wxNAND: mode = GDK_NAND; break;
1844 case wxAND_INVERT: mode = GDK_AND_INVERT; break;
1845 case wxCOPY: mode = GDK_COPY; break;
1846 case wxNO_OP: mode = GDK_NOOP; break;
1847 case wxSRC_INVERT: mode = GDK_COPY_INVERT; break;
1848
1849 // unsupported by GTK
1850 case wxNOR: mode = GDK_COPY; break;
1851 #endif
1852 default:
1853 {
1854 wxFAIL_MSG( wxT("unsupported logical function") );
1855 break;
1856 }
1857 }
1858
1859 m_logicalFunction = function;
1860
1861 gdk_gc_set_function( m_penGC, mode );
1862 gdk_gc_set_function( m_brushGC, mode );
1863
1864 // to stay compatible with wxMSW, we don't apply ROPs to the text
1865 // operations (i.e. DrawText/DrawRotatedText).
1866 // True, but mono-bitmaps use the m_textGC and they use ROPs as well.
1867 gdk_gc_set_function( m_textGC, mode );
1868 }
1869
1870 void wxWindowDC::SetTextForeground( const wxColour &col )
1871 {
1872 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1873
1874 if (m_textForegroundColour == col) return;
1875
1876 m_textForegroundColour = col;
1877 if (!m_textForegroundColour.Ok()) return;
1878
1879 if (!m_window) return;
1880
1881 m_textForegroundColour.CalcPixel( m_cmap );
1882 gdk_gc_set_foreground( m_textGC, m_textForegroundColour.GetColor() );
1883 }
1884
1885 void wxWindowDC::SetTextBackground( const wxColour &col )
1886 {
1887 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1888
1889 if (m_textBackgroundColour == col) return;
1890
1891 m_textBackgroundColour = col;
1892 if (!m_textBackgroundColour.Ok()) return;
1893
1894 if (!m_window) return;
1895
1896 m_textBackgroundColour.CalcPixel( m_cmap );
1897 gdk_gc_set_background( m_textGC, m_textBackgroundColour.GetColor() );
1898 }
1899
1900 void wxWindowDC::SetBackgroundMode( int mode )
1901 {
1902 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1903
1904 m_backgroundMode = mode;
1905
1906 if (!m_window) return;
1907
1908 // CMB 21/7/98: fill style of cross-hatch brushes is affected by
1909 // transparent/solid background mode
1910
1911 if (m_brush.GetStyle() != wxSOLID && m_brush.GetStyle() != wxTRANSPARENT)
1912 {
1913 gdk_gc_set_fill( m_brushGC,
1914 (m_backgroundMode == wxTRANSPARENT) ? GDK_STIPPLED : GDK_OPAQUE_STIPPLED);
1915 }
1916 }
1917
1918 void wxWindowDC::SetPalette( const wxPalette& WXUNUSED(palette) )
1919 {
1920 wxFAIL_MSG( wxT("wxWindowDC::SetPalette not implemented") );
1921 }
1922
1923 void wxWindowDC::DoSetClippingRegion( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
1924 {
1925 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1926
1927 if (!m_window) return;
1928
1929 wxRect rect;
1930 rect.x = XLOG2DEV(x);
1931 rect.y = YLOG2DEV(y);
1932 rect.width = XLOG2DEVREL(width);
1933 rect.height = YLOG2DEVREL(height);
1934
1935 if (!m_currentClippingRegion.IsNull())
1936 m_currentClippingRegion.Intersect( rect );
1937 else
1938 m_currentClippingRegion.Union( rect );
1939
1940 #if USE_PAINT_REGION
1941 if (!m_paintClippingRegion.IsNull())
1942 m_currentClippingRegion.Intersect( m_paintClippingRegion );
1943 #endif
1944
1945 wxCoord xx, yy, ww, hh;
1946 m_currentClippingRegion.GetBox( xx, yy, ww, hh );
1947 wxDC::DoSetClippingRegion( xx, yy, ww, hh );
1948
1949 gdk_gc_set_clip_region( m_penGC, m_currentClippingRegion.GetRegion() );
1950 gdk_gc_set_clip_region( m_brushGC, m_currentClippingRegion.GetRegion() );
1951 gdk_gc_set_clip_region( m_textGC, m_currentClippingRegion.GetRegion() );
1952 gdk_gc_set_clip_region( m_bgGC, m_currentClippingRegion.GetRegion() );
1953 }
1954
1955 void wxWindowDC::DoSetClippingRegionAsRegion( const wxRegion &region )
1956 {
1957 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1958
1959 if (region.Empty())
1960 {
1961 DestroyClippingRegion();
1962 return;
1963 }
1964
1965 if (!m_window) return;
1966
1967 if (!m_currentClippingRegion.IsNull())
1968 m_currentClippingRegion.Intersect( region );
1969 else
1970 m_currentClippingRegion.Union( region );
1971
1972 #if USE_PAINT_REGION
1973 if (!m_paintClippingRegion.IsNull())
1974 m_currentClippingRegion.Intersect( m_paintClippingRegion );
1975 #endif
1976
1977 wxCoord xx, yy, ww, hh;
1978 m_currentClippingRegion.GetBox( xx, yy, ww, hh );
1979 wxDC::DoSetClippingRegion( xx, yy, ww, hh );
1980
1981 gdk_gc_set_clip_region( m_penGC, m_currentClippingRegion.GetRegion() );
1982 gdk_gc_set_clip_region( m_brushGC, m_currentClippingRegion.GetRegion() );
1983 gdk_gc_set_clip_region( m_textGC, m_currentClippingRegion.GetRegion() );
1984 gdk_gc_set_clip_region( m_bgGC, m_currentClippingRegion.GetRegion() );
1985 }
1986
1987 void wxWindowDC::DestroyClippingRegion()
1988 {
1989 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1990
1991 wxDC::DestroyClippingRegion();
1992
1993 m_currentClippingRegion.Clear();
1994
1995 #if USE_PAINT_REGION
1996 if (!m_paintClippingRegion.IsEmpty())
1997 m_currentClippingRegion.Union( m_paintClippingRegion );
1998 #endif
1999
2000 if (!m_window) return;
2001
2002 if (m_currentClippingRegion.IsEmpty())
2003 {
2004 gdk_gc_set_clip_rectangle( m_penGC, (GdkRectangle *) NULL );
2005 gdk_gc_set_clip_rectangle( m_brushGC, (GdkRectangle *) NULL );
2006 gdk_gc_set_clip_rectangle( m_textGC, (GdkRectangle *) NULL );
2007 gdk_gc_set_clip_rectangle( m_bgGC, (GdkRectangle *) NULL );
2008 }
2009 else
2010 {
2011 gdk_gc_set_clip_region( m_penGC, m_currentClippingRegion.GetRegion() );
2012 gdk_gc_set_clip_region( m_brushGC, m_currentClippingRegion.GetRegion() );
2013 gdk_gc_set_clip_region( m_textGC, m_currentClippingRegion.GetRegion() );
2014 gdk_gc_set_clip_region( m_bgGC, m_currentClippingRegion.GetRegion() );
2015 }
2016 }
2017
2018 void wxWindowDC::Destroy()
2019 {
2020 if (m_penGC) wxFreePoolGC( m_penGC );
2021 m_penGC = (GdkGC*) NULL;
2022 if (m_brushGC) wxFreePoolGC( m_brushGC );
2023 m_brushGC = (GdkGC*) NULL;
2024 if (m_textGC) wxFreePoolGC( m_textGC );
2025 m_textGC = (GdkGC*) NULL;
2026 if (m_bgGC) wxFreePoolGC( m_bgGC );
2027 m_bgGC = (GdkGC*) NULL;
2028 }
2029
2030 void wxWindowDC::ComputeScaleAndOrigin()
2031 {
2032 /* CMB: copy scale to see if it changes */
2033 double origScaleX = m_scaleX;
2034 double origScaleY = m_scaleY;
2035
2036 wxDC::ComputeScaleAndOrigin();
2037
2038 /* CMB: if scale has changed call SetPen to recalulate the line width */
2039 if ((m_scaleX != origScaleX || m_scaleY != origScaleY) &&
2040 (m_pen.Ok()))
2041 {
2042 /* this is a bit artificial, but we need to force wxDC to think
2043 the pen has changed */
2044 wxPen pen = m_pen;
2045 m_pen = wxNullPen;
2046 SetPen( pen );
2047 }
2048 }
2049
2050 // Resolution in pixels per logical inch
2051 wxSize wxWindowDC::GetPPI() const
2052 {
2053 return wxSize( (int) (m_mm_to_pix_x * 25.4 + 0.5), (int) (m_mm_to_pix_y * 25.4 + 0.5));
2054 }
2055
2056 int wxWindowDC::GetDepth() const
2057 {
2058 wxFAIL_MSG(wxT("not implemented"));
2059
2060 return -1;
2061 }
2062
2063
2064 //-----------------------------------------------------------------------------
2065 // wxPaintDC
2066 //-----------------------------------------------------------------------------
2067
2068 IMPLEMENT_DYNAMIC_CLASS(wxPaintDC, wxClientDC)
2069
2070 wxPaintDC::wxPaintDC( wxWindow *win )
2071 : wxClientDC( win )
2072 {
2073 #if USE_PAINT_REGION
2074 if (!win->m_clipPaintRegion)
2075 return;
2076
2077 m_paintClippingRegion = win->GetUpdateRegion();
2078 GdkRegion *region = m_paintClippingRegion.GetRegion();
2079 if ( region )
2080 {
2081 m_paintClippingRegion = win->GetUpdateRegion();
2082 GdkRegion *region = m_paintClippingRegion.GetRegion();
2083 if ( region )
2084 {
2085 m_currentClippingRegion.Union( m_paintClippingRegion );
2086
2087 gdk_gc_set_clip_region( m_penGC, region );
2088 gdk_gc_set_clip_region( m_brushGC, region );
2089 gdk_gc_set_clip_region( m_textGC, region );
2090 gdk_gc_set_clip_region( m_bgGC, region );
2091 }
2092 }
2093 #endif // USE_PAINT_REGION
2094 }
2095
2096 //-----------------------------------------------------------------------------
2097 // wxClientDC
2098 //-----------------------------------------------------------------------------
2099
2100 IMPLEMENT_DYNAMIC_CLASS(wxClientDC, wxWindowDC)
2101
2102 wxClientDC::wxClientDC( wxWindow *win )
2103 : wxWindowDC( win )
2104 {
2105 #ifdef __WXUNIVERSAL__
2106 wxPoint ptOrigin = win->GetClientAreaOrigin();
2107 SetDeviceOrigin(ptOrigin.x, ptOrigin.y);
2108 wxSize size = win->GetClientSize();
2109 SetClippingRegion(wxPoint(0, 0), size);
2110 #endif // __WXUNIVERSAL__
2111 }
2112
2113 // ----------------------------------------------------------------------------
2114 // wxDCModule
2115 // ----------------------------------------------------------------------------
2116
2117 class wxDCModule : public wxModule
2118 {
2119 public:
2120 bool OnInit();
2121 void OnExit();
2122
2123 private:
2124 DECLARE_DYNAMIC_CLASS(wxDCModule)
2125 };
2126
2127 IMPLEMENT_DYNAMIC_CLASS(wxDCModule, wxModule)
2128
2129 bool wxDCModule::OnInit()
2130 {
2131 wxInitGCPool();
2132 return TRUE;
2133 }
2134
2135 void wxDCModule::OnExit()
2136 {
2137 wxCleanUpGCPool();
2138 }