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