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