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