1{%MainUnit gtk2def.pp} 2 3{****************************************************************************** 4 TGtk2DeviceContext 5 ****************************************************************************** 6 7 ***************************************************************************** 8 This file is part of the Lazarus Component Library (LCL) 9 10 See the file COPYING.modifiedLGPL.txt, included in this distribution, 11 for details about the license. 12 ***************************************************************************** 13} 14 15{$IFOPT C-} 16// Uncomment for local trace 17// {$C+} 18// {$DEFINE ASSERT_IS_ON} 19{$ENDIF} 20 21{ TDeviceContext } 22 23procedure TGtkDeviceContext.SetClipRegion(const AValue: PGdiObject); 24begin 25 ChangeGDIObject(fClipRegion, AValue); 26end; 27 28function TGtkDeviceContext.GetGDIObjects(ID: TGDIType): PGdiObject; 29begin 30 case ID of 31 gdiBitmap: Result:=CurrentBitmap; 32 gdiFont: Result:=CurrentFont; 33 gdiBrush: Result:=CurrentBrush; 34 gdiPen: Result:=CurrentPen; 35 gdiPalette: Result:=CurrentPalette; 36 gdiRegion: Result:=ClipRegion; 37 end; 38end; 39 40function TGtkDeviceContext.GetClipRectangle: TGdkRectangle; 41var 42 X,Y: gint; 43begin 44 if FClipRegion = nil then 45 begin 46 if (PaintRectangle.Left<>0) or (PaintRectangle.Top<>0) or 47 (PaintRectangle.Right<>0) or (PaintRectangle.Bottom<>0) then 48 Result := GdkRectFromRect(PaintRectangle) 49 else 50 begin 51 gdk_window_get_size(Drawable, @X, @Y); 52 Result := GdkRectFromRect(Rect(0,0, X, Y)); 53 end; 54 end else 55 gdk_region_get_clipbox(FClipRegion^.GDIRegionObject, @Result); 56end; 57 58function TGtkDeviceContext.GetOffset: TPoint; 59var 60 Fixed: Pointer; 61 AChild: PGtkWidget; 62 AColumn: PGtkTreeViewColumn; 63 Area: TGdkRectangle; 64 h: gint; 65 w: gint; 66 yoffs: gint; 67 xoffs: gint; 68begin 69 Result := Point(0, 0); 70 if Assigned(FWidget) then 71 begin 72 Fixed := GetFixedWidget(FWidget); 73 if GTK_WIDGET_NO_WINDOW(FWidget) and 74 GTK_WIDGET_NO_WINDOW(Fixed) and 75 not GtkWidgetIsA(FWidget, GTKAPIWidget_GetType) then 76 begin 77 Inc(Result.X, FWidget^.Allocation.x); 78 Inc(Result.y, FWidget^.Allocation.y); 79 end; 80 if (GTK_IS_SCROLLED_WINDOW(FWidget) and GTK_IS_BIN(FWidget)) or (GTK_IS_TREE_VIEW(FWidget)) then 81 begin 82 if GTK_IS_TREE_VIEW(FWidget) then 83 AChild := FWidget 84 else 85 AChild := gtk_bin_get_child(PGtkBin(FWidget)); 86 if GTK_IS_TREE_VIEW(AChild) and gtk_tree_view_get_headers_visible(PGtkTreeView(AChild)) then 87 begin 88 AColumn := gtk_tree_view_get_column(PGtkTreeView(AChild), 0); 89 gtk_tree_view_column_cell_get_size(AColumn, @Area, @xoffs, @yoffs, @w, @h); 90 // borders are 2px 91 dec(Result.y, h - 2); 92 end; 93 end; 94 end; 95end; 96 97function TGtkDeviceContext.GetOwnedGDIObjects(ID: TGDIType): PGdiObject; 98begin 99 Result:=fOwnedGDIObjects[ID]; 100end; 101 102procedure TGtkDeviceContext.SetCurrentBitmap(const AValue: PGdiObject); 103begin 104 ChangeGDIObject(FCurrentBitmap,AValue); 105end; 106 107procedure TGtkDeviceContext.SetCurrentBrush(const AValue: PGdiObject); 108begin 109 ChangeGDIObject(FCurrentBrush,AValue); 110 if FSelectedColors = dcscBrush then 111 FSelectedColors := dcscCustom; 112end; 113 114procedure TGtkDeviceContext.SetCurrentFont(const AValue: PGdiObject); 115begin 116 ChangeGDIObject(FCurrentFont,AValue); 117 if FHasTransf then 118 TransfUpdateFont; 119end; 120 121procedure TGtkDeviceContext.SetCurrentPalette(const AValue: PGdiObject); 122begin 123 ChangeGDIObject(FCurrentPalette,AValue); 124end; 125 126procedure TGtkDeviceContext.SetCurrentPen(const AValue: PGdiObject); 127begin 128 ChangeGDIObject(FCurrentPen,AValue); 129 if FSelectedColors = dcscPen then 130 FSelectedColors := dcscCustom; 131 if FHasTransf then 132 TransfUpdatePen; 133end; 134 135procedure TGtkDeviceContext.ChangeGDIObject(var GDIObject: PGdiObject; 136 const NewValue: PGdiObject); 137begin 138 if GdiObject = NewValue then exit; 139 if GdiObject <> nil then 140 begin 141 dec(GdiObject^.DCCount); 142 if GdiObject^.DCCount < 0 then 143 RaiseGDBException(''); 144 ReleaseGDIObject(GDIObject); 145 end; 146 147 GdiObject := NewValue; 148 149 if GdiObject <> nil then 150 begin 151 inc(GdiObject^.DCCount); 152 ReferenceGDIObject(GDIObject); 153 end; 154end; 155 156procedure TGtkDeviceContext.SetGDIObjects(ID: TGDIType; const AValue: PGdiObject); 157begin 158 case ID of 159 gdiBitmap: ChangeGDIObject(fCurrentBitmap,AValue); 160 gdiFont: ChangeGDIObject(fCurrentFont,AValue); 161 gdiBrush: ChangeGDIObject(fCurrentBrush,AValue); 162 gdiPen: ChangeGDIObject(fCurrentPen,AValue); 163 gdiPalette: ChangeGDIObject(fCurrentPalette,AValue); 164 gdiRegion: ChangeGDIObject(fClipRegion,AValue); 165 end; 166end; 167 168procedure TGtkDeviceContext.SetMapMode(AValue: Integer); 169begin 170 if AValue <> FMapMode then 171 begin 172 case AValue of 173 MM_ANISOTROPIC:; // user's choice 174 MM_ISOTROPIC:; // adjusted after each SetViewPortExtEx call (see MSDN for details) 175 MM_HIENGLISH: FWindowExt := Point(1000, -1000); 176 MM_HIMETRIC: FWindowExt := Point(2540, -2540); 177 MM_LOENGLISH: FWindowExt := Point(100, -100); 178 MM_LOMETRIC: FWindowExt := Point(254, -254); 179 MM_TWIPS: FWindowExt := Point(1440, -1440); 180 else 181 AValue := MM_TEXT; 182 FWindowExt := Point(1, 1); 183 FViewPortExt := Point(1, 1); 184 end; 185 FMapMode := AValue; 186 // to do: combine with affine transformations here when they get implemented 187 FHasTransf := 188 (FMapMode <> MM_TEXT) or 189 (FViewPortOrg.x <> 0) or 190 (FViewPortOrg.y <> 0) or 191 (FWindowOrg.x <> 0) or 192 (FWindowOrg.y <> 0); 193 if not (FMapMode in [MM_TEXT, MM_ANISOTROPIC, MM_ISOTROPIC]) then 194 begin 195 FViewPortExt.X := Gtk2WidgetSet.GetDeviceCaps(HDC(Self), LOGPIXELSX); 196 FViewPortExt.Y := Gtk2WidgetSet.GetDeviceCaps(HDC(Self), LOGPIXELSY); 197 end; 198 TransfUpdateFont; 199 TransfUpdatePen; 200 end; 201end; 202 203procedure TGtkDeviceContext.SetOwnedGDIObjects(ID: TGDIType; 204 const AValue: PGdiObject); 205begin 206//MWE: this is not right. all objects except bitmaps can be selected in more than one DC 207 208 if fOwnedGDIObjects[ID]=AValue then exit; 209 if fOwnedGDIObjects[ID]<>nil then 210 fOwnedGDIObjects[ID]^.Owner:=nil; 211 fOwnedGDIObjects[ID]:=AValue; 212 if fOwnedGDIObjects[ID]<>nil then 213 fOwnedGDIObjects[ID]^.Owner:=Self; 214end; 215 216procedure TGtkDeviceContext.SetROP2(AROP: Integer); 217var 218 Func: TGdkFunction; 219begin 220 case AROP of 221 R2_COPYPEN: Func := GDK_COPY; 222 R2_NOT: Func := GDK_INVERT; 223 R2_XORPEN: Func := GDK_XOR; 224 R2_BLACK: Func := GDK_CLEAR; 225 R2_MASKPEN: Func := GDK_AND; 226 R2_MASKPENNOT: Func := GDK_AND_REVERSE; 227 R2_MASKNOTPEN: Func := GDK_AND_INVERT; 228 R2_NOP: Func := GDK_NOOP; 229 R2_MERGEPEN: Func := GDK_OR; 230 R2_NOTXORPEN: Func := GDK_EQUIV; 231 R2_MERGEPENNOT: Func := GDK_OR_REVERSE; 232 R2_NOTCOPYPEN: Func := GDK_COPY_INVERT; 233 R2_NOTMASKPEN: Func := GDK_NAND; 234 //R2_NOTMERGEPEN: Func := GDK_NOR; 235 R2_WHITE: Func := GDK_SET; 236 else 237 Func := GDK_COPY; 238 end; 239 240 gdk_gc_set_function(GC, Func); 241 gdk_gc_get_values(GC, @FGCValues); 242end; 243 244procedure TGtkDeviceContext.SetViewPortExt(const AValue: TPoint); 245var 246 Ratio: Single; 247begin 248 if (AValue.x <> FViewPortExt.x) or (AValue.y <> FViewPortExt.y) and 249 (FMapMode in [MM_ISOTROPIC, MM_ANISOTROPIC]) then 250 begin 251 if FMapMode = MM_ISOTROPIC then 252 begin 253 // TK: Is here also an adjustment on Windows if DPIX and DPIY are different? 254 Ratio := FWindowExt.x / FWindowExt.y; // no check, programmer cannot put nonsense 255 if AValue.y * Ratio > AValue.x then 256 FViewPortExt := Point(AValue.x, RoundToInt(AValue.x / Ratio)) 257 else if AValue.y * Ratio < AValue.x then 258 FViewPortExt := Point(RoundToInt(AValue.y * Ratio), AValue.y) 259 else 260 FViewPortExt := AValue; 261 end else 262 FViewPortExt := AValue; 263 TransfUpdateFont; 264 TransfUpdatePen; 265 end; 266end; 267 268procedure TGtkDeviceContext.SetViewPortOrg(const AValue: TPoint); 269begin 270 if (FViewPortOrg.x <> AValue.x) or 271 (FViewPortOrg.y <> AValue.y) then 272 begin 273 FViewPortOrg := AValue; 274 FHasTransf := True; 275 end; 276end; 277 278procedure TGtkDeviceContext.SetWindowExt(const AValue: TPoint); 279begin 280 if (AValue.x <> FWindowExt.x) or (AValue.y <> FWindowExt.y) and 281 (FMapMode in [MM_ISOTROPIC, MM_ANISOTROPIC]) then 282 begin 283 FWindowExt := AValue; 284 if FMapMode = MM_ANISOTROPIC then 285 begin 286 TransfUpdateFont; 287 TransfUpdatePen; 288 end; 289 end; 290end; 291 292procedure TGtkDeviceContext.SetWindowOrg(AValue: TPoint); 293begin 294 if (FWindowOrg.x <> AValue.x) or 295 (FWindowOrg.y <> AValue.y) then 296 begin 297 FWindowOrg := AValue; 298 FHasTransf := True; 299 end; 300end; 301 302procedure TGtkDeviceContext.SetSelectedColors(AValue: TDevContextSelectedColorsType); 303begin 304 if FSelectedColors = AValue then Exit; 305 FSelectedColors := AValue; 306 307 case FSelectedColors of 308 dcscPen: SelectPenProps; 309 dcscBrush: SelectBrushProps; 310 dcscFont: SelectTextProps; 311 end; 312end; 313 314procedure TGtkDeviceContext.SetTextMetricsValid(AValid: Boolean); 315begin 316 if AValid then 317 Include(FFlags, dcfTextMetricsValid) 318 else 319 Exclude(FFlags, dcfTextMetricsValid); 320end; 321 322procedure TGtkDeviceContext.RemovePixbuf; 323begin 324 if Assigned(FPixbuf) then 325 begin 326 gdk_pixbuf_unref(FPixbuf); 327 FPixbuf := nil; 328 end; 329end; 330 331procedure TGtkDeviceContext.InvTransfPoint(var X1, Y1: Integer); 332begin 333 X1 := MulDiv(X1 + FWindowOrg.x - FViewPortOrg.x, FWindowExt.x, FViewPortExt.x); 334 Y1 := MulDiv(Y1 + FWindowOrg.y - FViewPortOrg.y, FWindowExt.y, FViewPortExt.y); 335 // to do: put affine inverse transformation here (for all Inv.. methods) 336end; 337 338function TGtkDeviceContext.InvTransfPointIndirect(const P: TPoint): TPoint; 339begin 340 Result.X := MulDiv(P.X + FWindowOrg.x - FViewPortOrg.x, FWindowExt.x, FViewPortExt.x); 341 Result.Y := MulDiv(P.Y + FWindowOrg.y - FViewPortOrg.y, FWindowExt.y, FViewPortExt.y); 342end; 343 344procedure TGtkDeviceContext.InvTransfRect(var X1, Y1, X2, Y2: Integer); 345begin 346 X1 := MulDiv(X1 + FWindowOrg.x - FViewPortOrg.x, FWindowExt.x, FViewPortExt.x); 347 Y1 := MulDiv(Y1 + FWindowOrg.y - FViewPortOrg.y, FWindowExt.y, FViewPortExt.y); 348 X2 := MulDiv(X2 + FWindowOrg.x - FViewPortOrg.x, FWindowExt.x, FViewPortExt.x); 349 Y2 := MulDiv(Y2 + FWindowOrg.y - FViewPortOrg.y, FWindowExt.y, FViewPortExt.y); 350end; 351 352function TGtkDeviceContext.InvTransfRectIndirect(const R: TRect): TRect; 353begin 354 Result.Left := MulDiv(R.Left + FWindowOrg.x - FViewPortOrg.x, FWindowExt.x, FViewPortExt.x); 355 Result.Top := MulDiv(R.Top + FWindowOrg.y - FViewPortOrg.y, FWindowExt.y, FViewPortExt.y); 356 Result.Right := MulDiv(R.Right + FWindowOrg.x - FViewPortOrg.x, FWindowExt.x, FViewPortExt.x); 357 Result.Bottom := MulDiv(R.Bottom + FWindowOrg.y - FViewPortOrg.y, FWindowExt.y, FViewPortExt.y); 358end; 359 360procedure TGtkDeviceContext.InvTransfExtent(var ExtX, ExtY: Integer); 361begin 362 ExtX := MulDiv(ExtX, FWindowExt.x, FViewPortExt.x); 363 ExtY := MulDiv(ExtY, FWindowExt.y, FViewPortExt.y); 364end; 365 366function TGtkDeviceContext.InvTransfExtentIndirect(const Extent: TPoint): TPoint; 367begin 368 Result.X := MulDiv(Extent.X, FWindowExt.x, FViewPortExt.x); 369 Result.Y := MulDiv(Extent.Y, FWindowExt.y, FViewPortExt.y); 370end; 371 372procedure TGtkDeviceContext.TransfAngles(var Angle1, Angle2: Integer); 373begin 374 if FWindowExt.x * FViewPortExt.x < 0 then 375 begin 376 // flip angles along 90-270 degree axis 377 Angle1 := 2880 - Angle1; 378 Angle2 := 2880 - Angle2; 379 end; 380 if FWindowExt.y * FViewPortExt.y < 0 then 381 begin 382 // flip angles along 0-180 degree axis 383 Angle1 := 5760 - Angle1; 384 Angle2 := 5760 - Angle2; 385 end; 386end; 387 388procedure TGtkDeviceContext.TransfNormalize(var Lower, Higher: Integer); 389var 390 Tmp: Integer; 391begin 392 if Lower > Higher then 393 begin 394 Tmp := Lower; 395 Lower := Higher; 396 Higher := Tmp; 397 end; 398end; 399 400procedure TGtkDeviceContext.TransfPoint(var X1, Y1: Integer); 401begin 402 // to do: put affine transformation here (for all Transf.. methods) 403 X1 := MulDiv(X1, FViewPortExt.x, FWindowExt.x) + FViewPortOrg.x - FWindowOrg.x; 404 Y1 := MulDiv(Y1, FViewPortExt.y, FWindowExt.y) + FViewPortOrg.y - FWindowOrg.y; 405end; 406 407function TGtkDeviceContext.TransfPointIndirect(const P: TPoint): TPoint; 408begin 409 Result.x := MulDiv(P.x, FViewPortExt.x, FWindowExt.x) + FViewPortOrg.x - FWindowOrg.x; 410 Result.Y := MulDiv(P.y, FViewPortExt.y, FWindowExt.y) + FViewPortOrg.y - FWindowOrg.y; 411end; 412 413procedure TGtkDeviceContext.TransfRect(var X1, Y1, X2, Y2: Integer); 414begin 415 X1 := MulDiv(X1, FViewPortExt.x, FWindowExt.x) + FViewPortOrg.x - FWindowOrg.x; 416 Y1 := MulDiv(Y1, FViewPortExt.y, FWindowExt.y) + FViewPortOrg.y - FWindowOrg.y; 417 X2 := MulDiv(X2, FViewPortExt.x, FWindowExt.x) + FViewPortOrg.x - FWindowOrg.x; 418 Y2 := MulDiv(Y2, FViewPortExt.y, FWindowExt.y) + FViewPortOrg.y - FWindowOrg.y; 419end; 420 421function TGtkDeviceContext.TransfRectIndirect(const R: TRect): TRect; 422begin 423 Result.Left := MulDiv(R.Left, FViewPortExt.x, FWindowExt.x) + FViewPortOrg.x - FWindowOrg.x; 424 Result.Top := MulDiv(R.Top, FViewPortExt.y, FWindowExt.y) + FViewPortOrg.y - FWindowOrg.y; 425 Result.Right := MulDiv(R.Right, FViewPortExt.x, FWindowExt.x) + FViewPortOrg.x - FWindowOrg.x; 426 Result.Bottom := MulDiv(R.Bottom, FViewPortExt.y, FWindowExt.y) + FViewPortOrg.y - FWindowOrg.y; 427end; 428 429procedure TGtkDeviceContext.TransfExtent(var ExtX, ExtY: Integer); 430begin 431 ExtX := MulDiv(ExtX, FViewPortExt.x, FWindowExt.x); 432 ExtY := MulDiv(ExtY, FViewPortExt.y, FWindowExt.y); 433end; 434 435function TGtkDeviceContext.TransfExtentIndirect(const Extent: TPoint): TPoint; 436begin 437 Result.X := MulDiv(Extent.X, FViewPortExt.x, FWindowExt.x); 438 Result.Y := MulDiv(Extent.Y, FViewPortExt.y, FWindowExt.y); 439end; 440 441procedure TGtkDeviceContext.TransfUpdateFont; 442var 443 AWidth, AHeight: Integer; 444 TmpObj: PGdiObject; 445begin 446 if (FCurrentFont <> nil) and (FCurrentFont^.GDIFontObject <> nil) and (FCurrentFont^.LogFont.lfFaceName[0] <> #0) then 447 begin 448 if FCurrentFont^.UntransfFontHeight = 0 then 449 FCurrentFont^.UntransfFontHeight := FCurrentFont^.LogFont.lfHeight; 450 AWidth := 0; AHeight := FCurrentFont^.UntransfFontHeight; 451 TransfExtent(AWidth, AHeight); 452 if FCurrentFont^.UntransfFontHeight > 0 then 453 AHeight := Abs(AHeight) 454 else 455 AHeight := -Abs(AHeight); 456 if AHeight = 0 then 457 if FCurrentFont^.LogFont.lfHeight > 0 then 458 AHeight := 1 459 else 460 if FCurrentFont^.LogFont.lfHeight < 0 then 461 AHeight := -1 462 else 463 AHeight := 0; 464 if FCurrentFont^.LogFont.lfHeight <> AHeight then 465 begin 466 FontCache.Unreference(FCurrentFont^.GDIFontObject); 467 FCurrentFont^.LogFont.lfHeight := AHeight; 468 TmpObj := {%H-}PGdiObject(PtrUInt(GTK2WidgetSet.CreateFontIndirect(FCurrentFont^.LogFont))); 469 FCurrentFont^.GDIFontObject := TmpObj^.GDIFontObject; 470 TmpObj^.GDIFontObject := nil; 471 TmpObj^.RefCount := 0; 472 GTK2WidgetSet.DisposeGDIObject(TmpObj); 473 end; 474 end; 475end; 476 477procedure TGtkDeviceContext.TransfUpdatePen; 478var 479 AWidth, AHeight: Integer; 480begin 481 if FCurrentPen <> nil then 482 begin 483 if FCurrentPen^.UnTransfPenWidth = 0 then 484 FCurrentPen^.UnTransfPenWidth := FCurrentPen^.GDIPenWidth; 485 AWidth := FCurrentPen^.UnTransfPenWidth; 486 AHeight := FCurrentPen^.UnTransfPenWidth; 487 TransfExtent(AWidth, AHeight); 488 AWidth := Abs(AWidth); 489 AHeight := Abs(AHeight); 490 if AWidth > AHeight then AWidth := AHeight; 491 if AWidth <= 0 then AWidth := 1; 492 if FCurrentPen^.GDIPenWidth <> DWord(AWidth) then 493 begin 494 FCurrentPen^.GDIPenWidth := AWidth; 495 Exclude(FFlags, dcfPenSelected); 496 SelectPenProps; 497 end; 498 end; 499end; 500 501procedure TGtkDeviceContext.SetWidget(AWidget: PGtkWidget; AWindow: PGdkWindow; 502 AWithChildWindows: Boolean; ADoubleBuffer: PGdkDrawable); 503 504 procedure RaiseWidgetWithoutClientArea; 505 begin 506 RaiseGDBException('TGtkDeviceContext.SetWidget: widget ' + DbgS(AWidget) + ' has no client area'); 507 end; 508 509 procedure RaiseWidgetAlreadySet; 510 begin 511 RaiseGDBException('TGtkDeviceContext.SetWidget: widget already set'); 512 end; 513 514 procedure RaiseUnableToRealize; 515 begin 516 RaiseGDBException('TGtkDeviceContext.SetWidget: Unable to realize GdkWindow'); 517 end; 518 519var 520 ClientWidget: PGtkWidget; 521 W: PGtkWidget; 522begin 523 if FWidget <> nil then 524 RaiseWidgetAlreadySet; 525 526 FWithChildWindows := AWithChildWindows; 527 FWidget := AWidget; 528 FPixbuf := nil; 529 530 if (AWidget = nil) then 531 begin 532 // screen: ToDo: multiple desktops 533 FDrawable := gdk_screen_get_root_window(gdk_screen_get_default); 534 end else 535 begin 536 if ADoubleBuffer <> nil then 537 begin 538 Include(FFlags, dcfDoubleBuffer); 539 FOriginalDrawable := AWindow; 540 FDrawable := ADoubleBuffer; 541 end else 542 begin 543 // create a new devicecontext for this window 544 Exclude(FFlags, dcfDoubleBuffer); 545 546 if AWindow = nil then 547 begin 548 ClientWidget := GetFixedWidget(AWidget); 549 if ClientWidget = nil then RaiseWidgetWithoutClientArea; 550 551 AWindow := GetControlWindow(ClientWidget); 552 if AWindow = nil then 553 begin 554 W := gtk_widget_get_parent(AWidget); 555 //we are forcing window creation but not for GtkNotebook 556 //see issue #18754 and #20126 557 //Zeljko:This part should be NOT BE REMOVED since TToolbar, TFrame 558 //TGroupBox etc...depend on this. eg.TToolbar will lock 559 //mouse without realizing clientWidget.Also if THintWindow is 560 //visible it crashes sometimes. SO JUST NOTEBOOK ! 561 if (W <> nil) and not GTK_IS_NOTEBOOK(W) then 562 gtk_widget_realize(ClientWidget); 563 564 AWindow := GetControlWindow(ClientWidget); 565 // Don't raise an exception. Not all operations needs drawable. For example font metrics: 566 // http://bugs.freepascal.org/view.php?id=14035 567 //if AWindow = nil then RaiseUnableToRealize; 568 end; 569 end else 570 begin 571 ClientWidget := AWidget; 572 end; 573 574 FDrawable := AWindow; 575 // GC is created on demand 576 if (FDrawable = nil) and not GTK_WIDGET_MAPPED(AWidget) then 577 FDrawable := gdk_screen_get_root_window(gdk_screen_get_default); 578 end; 579 end; 580 581 gdk_color_black(gdk_colormap_get_system, @CurrentTextColor.Color); 582 BuildColorRefFromGDKColor(CurrentTextColor); 583 gdk_color_white(gdk_colormap_get_system, @CurrentBackColor.Color); 584 BuildColorRefFromGDKColor(CurrentBackColor); 585 // font, brush, pen are created on demand 586end; 587 588procedure TGtkDeviceContext.Clear; 589var 590 g: TGDIType; 591 592 procedure WarnOwnedGDIObject; 593 begin 594 DebugLn(['TDeviceContext.Clear ',dbghex(PtrInt(Self)),' OwnedGDIObjects[',ord(g),']<>nil']); 595 end; 596 597begin 598 if Assigned(FPixbuf) then gdk_pixbuf_unref(FPixbuf); 599 FWidget := nil; 600 FDrawable := nil; 601 FPixbuf := nil; 602 FGC := nil; 603 FillChar(FGCValues, SizeOf(FGCValues), 0); 604 605 FViewPortExt := Point(1, 1); 606 FViewPortOrg := Point(0, 0); 607 FWindowExt := Point(1, 1); 608 FWindowOrg := Point(0, 0); 609 FMapMode := MM_TEXT; 610 if FHasTransf then 611 begin 612 FHasTransf := False; 613 TransfUpdateFont; 614 TransfUpdatePen; 615 end; 616 617 PenPos := Point(0, 0); 618 619 CurrentBitmap:=nil; 620 CurrentFont:=nil; 621 CurrentPen:=nil; 622 CurrentBrush:=nil; 623 CurrentPalette:=nil; 624 ClipRegion:=nil; 625 FillChar(CurrentTextColor,SizeOf(CurrentTextColor),0); 626 FillChar(CurrentBackColor,SizeOf(CurrentBackColor),0); 627 FillChar(PaintRectangle, SizeOf(PaintRectangle), 0); 628 629 SelectedColors:=dcscCustom; 630 SavedContext:=nil; 631 FFlags := []; 632 633 for g:=Low(TGDIType) to high(TGDIType) do 634 if OwnedGDIObjects[g]<>nil then 635 WarnOwnedGDIObject; 636end; 637 638{------------------------------------------------------------------------------ 639 Function: CopyData - used by RestoreDC and SaveDC 640 Params: DestinationDC: a dc to copy data to 641 ClearSource: set true to make a move operation 642 MoveGDIOwnerShip: set true to pass the ownership of the GDI objects 643 to Destination 644 Returns: True if succesful 645 646 Creates a copy DC from the given DC 647 ------------------------------------------------------------------------------} 648function TGtkDeviceContext.CopyDataFrom(ASource: TGtkDeviceContext; AClearSource, AMoveGDIOwnerShip, ARestore: Boolean): Boolean; 649 procedure RaiseRestoreDifferentWidget; 650 begin 651 RaiseGDBException('TGtkDeviceContext.CopyDataFrom: restore widget differs'); 652 end; 653 654 procedure RaiseWidgetAlreadySet; 655 begin 656 RaiseGDBException('TGtkDeviceContext.CopyDataFrom: widget already set'); 657 end; 658 659var 660 g: TGDIType; 661 CurGDIObject: PGDIObject; 662begin 663 Result := Assigned(Self) and Assigned(ASource); 664 if not Result then Exit; 665 666 if ARestore then 667 begin 668 if FWidget <> ASource.FWidget then 669 RaiseRestoreDifferentWidget; 670 end else 671 begin 672 if Assigned(FWidget) then 673 RaiseWidgetAlreadySet; 674 FWidget := ASource.FWidget; 675 end; 676 677 FWithChildWindows := ASource.FWithChildWindows; 678 FDrawable := ASource.FDrawable; 679 FPixbuf := ASource.Pixbuf; 680 FOriginalDrawable := ASource.FOriginalDrawable; 681 682 if Assigned(FGC) then 683 begin 684 // free old GC 685 gdk_gc_unref(FGC); 686 FGC := nil; 687 Exclude(FFlags, dcfPenSelected); 688 end; 689 690 if Assigned(ASource.FGC) and Assigned(FDrawable) then 691 begin 692 gdk_gc_get_values(ASource.FGC, @FGCValues); 693 FGC := gdk_gc_new_with_values(FDrawable, @FGCValues, 694 GDK_GC_FOREGROUND or GDK_GC_BACKGROUND or GDK_GC_SUBWINDOW); 695 Exclude(FFlags, dcfPenSelected); 696 end; 697 698 if dcfTextMetricsValid in ASource.Flags then 699 begin 700 Include(FFlags, dcfTextMetricsValid); 701 DCTextMetric := ASource.DCTextMetric; 702 end 703 else 704 Exclude(FFlags, dcfTextMetricsValid); 705 706 for g := Low(TGDIType) to High(TGDIType) do 707 begin 708 GDIObjects[g] := ASource.GDIObjects[g]; 709 if AClearSource then 710 ASource.GDIObjects[g] := nil; 711 712 if AMoveGDIOwnerShip then 713 begin 714 if Assigned(OwnedGDIObjects[g]) then 715 DeleteObject(HGDIOBJ({%H-}PtrUInt(OwnedGDIObjects[g]))); 716 717 CurGDIObject := ASource.OwnedGDIObjects[g]; 718 719 if Assigned(CurGDIObject) then 720 begin 721 ASource.OwnedGDIObjects[g] := nil; 722 OwnedGDIObjects[g] := CurGDIObject; 723 end; 724 end; 725 end; 726 CopyGDIColor(ASource.CurrentTextColor, CurrentTextColor); 727 CopyGDIColor(ASource.CurrentBackColor, CurrentBackColor); 728 729 SelectedColors := dcscCustom; 730 PenPos := ASource.PenPos; 731 732 if FHasTransf then 733 begin 734 FHasTransf := False; 735 FMapMode := MM_TEXT; 736 FViewPortExt := Point(1, 1); 737 FViewPortOrg := Point(0, 0); 738 FWindowExt := Point(1, 1); 739 FWindowOrg := Point(0, 0); 740 TransfUpdateFont; 741 TransfUpdatePen; 742 end; 743 744 FHasTransf := ASource.HasTransf; 745 if FHasTransf then 746 begin 747 FMapMode := ASource.MapMode; 748 FViewPortExt := ASource.ViewPortExt; 749 FViewPortOrg := ASource.ViewPortOrg; 750 FWindowExt := ASource.WindowExt; 751 FWindowOrg := ASource.WindowOrg; 752 TransfUpdateFont; 753 TransfUpdatePen; 754 end; 755 756 SavedContext := nil; 757end; 758 759function TGtkDeviceContext.FillRect(ARect: TRect; ABrush: HBrush; SkipRop: Boolean): Boolean; 760var 761 Width, Height: Integer; 762 OldCurrentBrush: PGdiObject; 763 DCOrigin: TPoint; 764 BrushChanged: Boolean; 765 ClipArea: TGdkRectangle; 766begin 767 BrushChanged := False; 768 if not IsNullBrush then 769 begin 770 if FHasTransf then 771 begin 772 ARect := TransfRectIndirect(ARect); 773 TransfNormalize(ARect.Left, ARect.Right); 774 TransfNormalize(ARect.Top, ARect.Bottom); 775 end; 776 777 Width := ARect.Right - ARect.Left; 778 Height := ARect.Bottom - ARect.Top; 779 780 // Temporary hold the old brush to replace it with the given brush 781 OldCurrentBrush := GetBrush; 782 if not CompareGDIBrushes({%H-}PGdiObject(ABrush), OldCurrentBrush) then 783 begin 784 BrushChanged := True; 785 CurrentBrush := {%H-}PGdiObject(ABrush); 786 SelectedColors := dcscCustom; 787 end; 788 789 SelectBrushProps; 790 if SkipRop then 791 gdk_gc_set_function(GC, GDK_COPY); 792 793 DCOrigin := Offset; 794 ClipArea := ClipRect; 795 RemovePixbuf; 796 if (CurrentBrush^.GDIBrushFill = GDK_SOLID) and 797 (IsBackgroundColor(TColor(CurrentBrush^.GDIBrushColor.ColorRef))) then 798 StyleFillRectangle(Drawable, GC, 799 CurrentBrush^.GDIBrushColor.ColorRef, 800 ARect.Left + DCOrigin.X, ARect.Top + DCOrigin.Y, 801 Width, Height, @ClipArea) 802 else 803 gdk_draw_rectangle(Drawable, GC, 1, 804 ARect.Left + DCOrigin.X, ARect.Top + DCOrigin.Y, 805 Width, Height); 806 807 if SkipRop then 808 gdk_gc_set_function(GC, GetFunction); 809 810 // Restore current brush 811 if BrushChanged then 812 begin 813 SelectedColors := dcscCustom; 814 CurrentBrush := OldCurrentBrush; 815 end; 816 end; 817 818 Result := True; 819end; 820 821procedure TGtkDeviceContext.CreateBrush; 822begin 823 if FCurrentBrush <> nil then Exit; 824 CurrentBrush := Gtk2Widgetset.CreateDefaultBrush; 825 OwnedGDIObjects[gdiBrush] := FCurrentBrush; 826end; 827 828procedure TGtkDeviceContext.CreateFont; 829var 830 NewFont: PGDIObject; 831 ClientWidget: PGtkWidget; 832begin 833 if FCurrentFont <> nil then exit; 834 835 // create font 836 if FWidget <> nil then 837 begin 838 ClientWidget := GetFixedWidget(FWidget); 839 840 NewFont := Gtk2Widgetset.NewGDIObject(gdiFont); 841 NewFont^.UntransfFontHeight := 0; 842 CurrentFont := NewFont; 843 FCurrentFont^.GDIFontObject := gtk_widget_create_pango_layout(ClientWidget, nil); 844 845 {$ifdef fontconsistencychecks} 846 if FontCache.FindGTKFont(FCurrentFont^.GDIFontObject) <> nil then 847 RaiseGDBException('inconsistency: font already in cache, maybe freed, but not removed from cache'); 848 {$endif} 849 850 FontCache.AddWithoutName(FCurrentFont^.GDIFontObject); 851 852 // the gtk internal reference count was increased by 853 // gtk_widget_create_pango_layout and by FontCache.AddWithoutName 854 // reduce it to one, because only this DC is using them at this point 855 UnreferenceGtkIntfFont(FCurrentFont^.GDIFontObject); 856 857 {$ifdef fontconsistencychecks} 858 // MWE: are we paranoid or so ? (if you can't trust the cache, don't use it or stop coding) 859 // MG: some people are coding without knowing about the cache 860 if FontCache.FindGTKFont(FCurrentFont^.GDIFontObject) = nil then 861 RaiseGDBException('inconsistency: font added to cache, but can not be found'); 862 {$endif} 863 end 864 else 865 CurrentFont := Gtk2Widgetset.CreateDefaultFont; 866 OwnedGDIObjects[gdiFont] := FCurrentFont; 867end; 868 869function TGtkDeviceContext.CreateGC: PGdkGC; 870begin 871 // create GC 872 873 if Drawable <> nil then 874 begin 875 if FWithChildWindows then 876 begin 877 FillChar(FGCValues, SizeOf(FGCValues), 0); 878 FGCValues.subwindow_mode := GDK_INCLUDE_INFERIORS; 879 Result := gdk_gc_new_with_values(Drawable, @FGCValues, GDK_GC_FUNCTION or GDK_GC_SUBWINDOW); 880 end else 881 begin 882 Result := gdk_gc_new(Drawable); 883 end; 884 end else 885 begin 886 // create default GC 887 Result := gdk_gc_new(gdk_screen_get_root_window(gdk_screen_get_default)); 888 end; 889 if Result = nil then Exit; 890 891 gdk_gc_set_function(Result, GDK_COPY); 892 gdk_gc_get_values(Result, @FGCValues); 893end; 894 895procedure TGtkDeviceContext.CreateBitmap; 896begin 897 if FCurrentBitmap <> nil then Exit; 898 CurrentBitmap := GTK2Widgetset.CreateDefaultGDIBitmap; 899 OwnedGDIObjects[gdiBitmap] := FCurrentBitmap; 900end; 901 902procedure TGtkDeviceContext.CreateGDIObject(AGDIType: TGDIType); 903begin 904 case AGDIType of 905 gdiFont: CreateFont; 906 gdiBrush: CreateBrush; 907 gdiPen: CreatePen; 908 gdiBitmap: CreateBitmap; 909 else 910 RaiseGDBException('TGtkDeviceContext.CreateGDIObject'); 911 end; 912end; 913 914procedure TGtkDeviceContext.CreatePen; 915begin 916 if FCurrentPen <> nil then exit; 917 CurrentPen := Gtk2WidgetSet.CreateDefaultPen; 918 OwnedGDIObjects[gdiPen] := FCurrentPen; 919end; 920 921 922function TGtkDeviceContext.GetGC: pgdkGC; 923begin 924 if FGC = nil then 925 FGC := CreateGC; 926 Result := FGC; 927end; 928 929function TGtkDeviceContext.GetFont: PGdiObject; 930begin 931 if FCurrentFont = nil then 932 CreateFont; 933 934 Result := FCurrentFont; 935end; 936 937function TGtkDeviceContext.GetBrush: PGdiObject; 938begin 939 if FCurrentBrush = nil then 940 CreateBrush; 941 942 Result := FCurrentBrush; 943end; 944 945function TGtkDeviceContext.GetPen: PGdiObject; 946begin 947 if FCurrentPen = nil then 948 CreatePen; 949 950 Result := FCurrentPen; 951end; 952 953function TGtkDeviceContext.GetROP2: Integer; 954begin 955 case GetFunction of 956 GDK_COPY: result := R2_COPYPEN; 957 GDK_INVERT: result := R2_NOT; 958 GDK_XOR: result := R2_XORPEN; 959 GDK_CLEAR: result := R2_BLACK; 960 GDK_AND: result := R2_MASKPEN; 961 GDK_AND_REVERSE: result := R2_MASKPENNOT; 962 GDK_AND_INVERT: result := R2_MASKNOTPEN; 963 GDK_NOOP: result := R2_NOP; 964 GDK_OR: result := R2_MERGEPEN; 965 GDK_EQUIV: result := R2_NOTXORPEN; 966 GDK_OR_REVERSE: result := R2_MERGEPENNOT; 967 GDK_COPY_INVERT: result := R2_NOTCOPYPEN; 968 GDK_NAND: result := R2_NOTMASKPEN; 969 //GDK_NOR: result := R2_NOTMERGEPEN; 970 GDK_SET: result := R2_WHITE; 971 else 972 result := R2_COPYPEN; 973 end; 974end; 975 976function TGtkDeviceContext.HasGC: Boolean; 977begin 978 Result := FGC <> nil; 979end; 980 981function TGtkDeviceContext.IsNullBrush: boolean; 982begin 983 Result := (FCurrentBrush <> nil) and (FCurrentBrush^.IsNullBrush); 984end; 985 986 987function TGtkDeviceContext.IsNullPen: boolean; 988begin 989 Result := (FCurrentPen <> nil) and (FCurrentPen^.IsNullPen); 990end; 991 992procedure TGtkDeviceContext.ResetGCClipping; 993begin 994 if FGC = nil then Exit; 995 996 {$IFDEF DebugGDK}BeginGDKErrorTrap;{$endif} 997 gdk_gc_set_clip_mask(FGC, nil); 998 gdk_gc_set_clip_origin (FGC, 0,0); 999 {$IFDEF DebugGDK}EndGDKErrorTrap;{$endif} 1000 1001 SelectRegion; 1002end; 1003 1004function TGtkDeviceContext.SelectBitmap(AGdiObject: PGdiObject): PGdiObject; 1005var 1006 NewPixbuf: PGdkPixbuf; 1007 NewDrawable: PGdkPixmap; 1008 Mask: PGdkBitmap; 1009begin 1010 // always create, because a valid GDIObject is needed to restore 1011 Result := GetBitmap; 1012 if CurrentBitmap = AGDIObject then Exit; 1013 1014 NewPixbuf := nil; 1015 CurrentBitmap := AGDIObject; 1016 with FCurrentBitmap^ do 1017 case GDIBitmapType of 1018 gbPixmap: NewDrawable := GDIPixmapObject.Image; 1019 gbBitmap: NewDrawable := GDIBitmapObject; 1020 gbPixbuf: 1021 begin 1022 NewDrawable := nil; 1023 Mask := nil; 1024 NewPixbuf := GDIPixbufObject; 1025 gdk_pixbuf_render_pixmap_and_mask(GDIPixbufObject, NewDrawable, Mask, $80); 1026 GDIBitmapType := gbPixmap; 1027 GDIPixmapObject.Image := NewDrawable; 1028 GDIPixmapObject.Mask := Mask; 1029 if Visual <> nil then 1030 gdk_visual_unref(Visual); 1031 Visual := gdk_window_get_visual(NewDrawable); 1032 gdk_visual_ref(Visual); 1033 end; 1034 else 1035 DebugLn('[TGtkDeviceContext.SelectBitmap] - Unknown bitmaptype, DC=0x%p', [Pointer(Self)]); 1036 Exit; 1037 end; 1038 1039 // no drawable: this is normal, when restoring the default bitmap (FreeDC) 1040 if NewDrawable = nil then Exit; 1041 1042 if FGC <> nil then 1043 gdk_gc_unref(FGC); 1044 FDrawable := NewDrawable; 1045 FPixbuf := NewPixbuf; 1046 FGC := gdk_gc_new(FDrawable); 1047 gdk_gc_set_function(FGC, GDK_COPY); 1048 SelectedColors := dcscCustom; 1049end; 1050 1051{------------------------------------------------------------------------------ 1052 Procedure: TGtkDeviceContext.SelectBrushProps 1053 Params: 1054 Returns: Nothing 1055 1056 Sets the forecolor and fill according to the brush 1057 ------------------------------------------------------------------------------} 1058procedure TGtkDeviceContext.SelectBrushProps; 1059begin 1060 if IsNullBrush then Exit; 1061 1062 // Force brush 1063 GetBrush; 1064 1065 EnsureGCColor(HDC(Self), dccCurrentBackColor, True, True);//BKColor 1066 EnsureGCColor(HDC(Self), dccGDIBrushColor, CurrentBrush^.GDIBrushFill = GDK_Solid, False);//Brush Color 1067 1068 if CurrentBrush^.GDIBrushFill = GDK_Solid then Exit; 1069 if CurrentBrush^.GDIBrushPixmap = nil then Exit; 1070 1071 if CurrentBrush^.GDIBrushFill = GDK_STIPPLED then 1072 begin 1073 //invert background / foreground colors to match Windows.FillRect behavior 1074 //with a 1bit bitmap pattern brush (bit set -> back color, bit unset -> text color) 1075 EnsureGCColor(HDC(Self), dccCurrentTextColor, False, True); 1076 EnsureGCColor(HDC(Self), dccCurrentBackColor, True, True); 1077 gdk_gc_set_stipple(GC, CurrentBrush^.GDIBrushPixmap); 1078 //use GDK_OPAQUE_STIPPLED to draw both background and foreground color 1079 gdk_gc_set_fill(GC, GDK_OPAQUE_STIPPLED); 1080 end 1081 else 1082 begin 1083 gdk_gc_set_tile(GC, CurrentBrush^.GDIBrushPixmap); 1084 gdk_gc_set_fill(GC, GDK_TILED); 1085 end; 1086 1087 gdk_gc_get_values(GC, @FGCValues); 1088end; 1089 1090function TGtkDeviceContext.SelectObject(AGdiObject: PGdiObject): PGdiObject; 1091begin 1092 case AGdiObject^.GDIType of 1093 gdiBitmap: Result := SelectBitmap(AGdiObject); 1094 gdiPen: Result := SelectPen(AGdiObject); 1095 else 1096 // we only handle bitmaps here atm 1097 Result := {%H-}PGdiObject(GTK2WidgetSet.SelectObject(HDC(Self), {%H-}HGDIOBJ(AGdiObject))); 1098 end; 1099end; 1100 1101function TGtkDeviceContext.SelectPen(AGdiObject: PGdiObject): PGdiObject; 1102begin 1103 Result := GetPen;// always create, because a valid GDIObject is needed to restore 1104 if CurrentPen = AGDIObject then Exit; 1105 1106 CurrentPen := AGDIObject; 1107 Exclude(FFlags, dcfPenSelected); 1108 if FGC <> nil then 1109 SelectPenProps; 1110 SelectedColors := dcscCustom; 1111end; 1112 1113constructor TGtkDeviceContext.Create; 1114begin 1115 Clear; 1116 BkMode := OPAQUE; 1117end; 1118 1119destructor TGtkDeviceContext.Destroy; 1120begin 1121 if Assigned(FPixbuf) then gdk_pixbuf_unref(FPixbuf); 1122 inherited Destroy; 1123end; 1124 1125{------------------------------------------------------------------------------ 1126 Procedure: TGtkDeviceContext.SelectPenProps 1127 Params: DC: a (LCL)devicecontext 1128 Returns: Nothing 1129 1130 Sets the forecolor and fill according to the pen 1131 ------------------------------------------------------------------------------} 1132procedure TGtkDeviceContext.SelectPenProps; 1133var 1134 PenStyle: DWord; 1135 LineStyle: TGdkLineStyle; 1136 JoinStyle: TGdkJoinStyle; 1137 CapStyle: TGdkCapStyle; 1138 IsGeometric, IsExtPen: Boolean; 1139 PenWidth: gint; 1140 1141 procedure SetDashes(ADashes: array of gint8); 1142 var 1143 Multiplier: gint; 1144 i: integer; 1145 begin 1146 Multiplier := PenWidth; 1147 if Multiplier = 0 then 1148 Multiplier := 1; 1149 1150 // this works very well for geometric pens 1151 for i := Low(ADashes) to High(ADashes) do 1152 ADashes[i] := ADashes[i] * Multiplier; 1153 1154 laz_gdk_gc_set_dashes(GC, 0, @ADashes[0], Length(ADashes)); 1155 end; 1156 1157begin 1158// if IsNullPen then Exit; 1159 1160 EnsureGCColor(HDC(Self), dccCurrentBackColor, True, True); // BKColor 1161 EnsureGCColor(HDC(Self), dccGDIPenColor, False, False); // Pen Color 1162 1163 if dcfPenSelected in FFlags then Exit; 1164 Exclude(FFlags, dcfPenInvalid); 1165 if GC = nil then Exit; 1166 1167 // force pen 1168 GetPen; 1169 1170 PenStyle := CurrentPen^.GDIPenStyle and PS_STYLE_MASK; 1171 IsExtPen := CurrentPen^.IsExtPen; 1172 PenWidth := CurrentPen^.GDIPenWidth; 1173 1174 if IsExtPen then 1175 IsGeometric := (CurrentPen^.GDIPenStyle and PS_TYPE_MASK) = PS_GEOMETRIC 1176 else 1177 IsGeometric := PenWidth > 1; 1178 1179 if not IsGeometric then 1180 PenWidth := 0; 1181 1182 CurrentPen^.IsNullPen := PenStyle = PS_NULL; 1183 1184 if IsExtPen and IsGeometric then 1185 begin 1186 case CurrentPen^.GDIPenStyle and PS_JOIN_MASK of 1187 PS_JOIN_ROUND: JoinStyle := GDK_JOIN_ROUND; 1188 PS_JOIN_BEVEL: JoinStyle := GDK_JOIN_BEVEL; 1189 PS_JOIN_MITER: JoinStyle := GDK_JOIN_MITER; 1190 end; 1191 1192 case CurrentPen^.GDIPenStyle and PS_ENDCAP_MASK of 1193 PS_ENDCAP_ROUND: CapStyle := GDK_CAP_ROUND; 1194 PS_ENDCAP_SQUARE: CapStyle := GDK_CAP_PROJECTING; 1195 PS_ENDCAP_FLAT: CapStyle := GDK_CAP_NOT_LAST; 1196 end; 1197 end 1198 else 1199 begin 1200 JoinStyle := GDK_JOIN_ROUND; 1201 if IsGeometric then 1202 CapStyle := GDK_CAP_ROUND 1203 else 1204 CapStyle := GDK_CAP_NOT_LAST; 1205 end; 1206 1207 if (PenStyle = PS_USERSTYLE) and (not IsExtPen or (CurrentPen^.GDIPenDashesCount = 0)) then 1208 PenStyle := PS_SOLID; 1209 1210 if (PenStyle = PS_SOLID) or (PenStyle = PS_INSIDEFRAME) then 1211 LineStyle := GDK_LINE_SOLID 1212 else 1213 LineStyle := GDK_LINE_ON_OFF_DASH; 1214 1215 {$IFDEF DebugGDK}BeginGDKErrorTrap;{$ENDIF} 1216 gdk_gc_set_line_attributes(GC, PenWidth, LineStyle, CapStyle, JoinStyle); 1217 {$IFDEF DebugGDK}EndGDKErrorTrap;{$ENDIF} 1218 1219 // Paul Ishenin: I compared patterns with windows 1220 case PenStyle of 1221 PS_DASH: SetDashes([3,1]); 1222 PS_DOT: SetDashes([1,1]); 1223 PS_DASHDOT: SetDashes([3,1,1,1]); 1224 PS_DASHDOTDOT: SetDashes([3,1,1,1,1,1]); 1225 PS_USERSTYLE: laz_gdk_gc_set_dashes(GC, 0, CurrentPen^.GDIPenDashes, CurrentPen^.GDIPenDashesCount); 1226 end; 1227 {$IFDEF DebugGDK}EndGDKErrorTrap;{$ENDIF} 1228 gdk_gc_get_values(GC, @FGCValues); 1229 Include(FFlags, dcfPenSelected); 1230end; 1231 1232{------------------------------------------------------------------------------ 1233 procedure SelectRegion 1234 1235 Applies the current clipping region of the DC (DeviceContext) to the 1236 gc (GDK Graphic context - pgdkGC) 1237 ------------------------------------------------------------------------------} 1238procedure TGtkDeviceContext.SelectRegion; 1239var 1240 RGNType : Longint; 1241begin 1242 {$IFDEF DebugGDK}BeginGDKErrorTrap;{$ENDIF} 1243 1244 // force GC 1245 GetGC; 1246 1247 // Clear 1248 gdk_gc_set_clip_region(FGC, nil); 1249 gdk_gc_set_clip_rectangle(FGC, nil); 1250 1251 if ClipRegion <> nil then 1252 begin 1253 RGNType := RegionType(ClipRegion^.GDIRegionObject); 1254 if (RGNType <> ERROR) and (RGNType <> NULLREGION) then 1255 gdk_gc_set_clip_region(FGC, ClipRegion^.GDIRegionObject); 1256 end; 1257 1258 {$IFDEF DebugGDK}EndGDKErrorTrap;{$ENDIF} 1259end; 1260 1261{------------------------------------------------------------------------------ 1262 Procedure: TGtkDeviceContext.SelectTextProps 1263 Params: 1264 Returns: Nothing 1265 1266 Sets the forecolor and fill according to the Textcolor 1267 ------------------------------------------------------------------------------} 1268procedure TGtkDeviceContext.SelectTextProps; 1269begin 1270 EnsureGCColor(HDC(Self), dccCurrentBackColor, True, True);//BKColor 1271 EnsureGCColor(HDC(Self), dccCurrentTextColor, False, False);//Font Color 1272end; 1273 1274function TGtkDeviceContext.GetBitmap: PGdiObject; 1275begin 1276 if FCurrentBitmap = nil then 1277 CreateBitmap; 1278 1279 Result := FCurrentBitmap; 1280end; 1281 1282function TGtkDeviceContext.GetFunction: TGdkFunction; 1283begin 1284 Result := GCValues._function; 1285end; 1286 1287 1288procedure SetLayoutText(ALayout: PPangoLayout; AText: PChar; ALength: PtrInt); 1289var 1290 OldStr: PChar; 1291begin 1292 OldStr := pango_layout_get_text(ALayout); 1293 if (strlen(OldStr)<>ALength) or (strlcomp(AText, OldStr, ALength) <> 0) then 1294 pango_layout_set_text(ALayout, AText, ALength); 1295end; 1296 1297procedure TGtkDeviceContext.DrawTextWithColors(AText: PChar; ALength: LongInt; 1298 X, Y: Integer; FGColor, BGColor: PGdkColor); 1299var 1300 WidgetCont: PPangoContext; 1301 NewMatrix: TPangoMatrix; 1302 OldMatrix: PPangoMatrix; 1303 renderer: PGdkPangoRenderer; 1304 Direction : TPangoDirection; 1305 AFont: PGdiObject; 1306 1307 procedure SetColors(AFGColor, ABGColor: PGdkColor); inline; 1308 begin 1309 gdk_pango_renderer_set_override_color(renderer, PANGO_RENDER_PART_FOREGROUND, AFGColor); 1310 gdk_pango_renderer_set_override_color(renderer, PANGO_RENDER_PART_UNDERLINE, AFGColor); 1311 gdk_pango_renderer_set_override_color(renderer, PANGO_RENDER_PART_STRIKETHROUGH, AFGColor); 1312 gdk_pango_renderer_set_override_color(renderer, PANGO_RENDER_PART_BACKGROUND, ABGColor); 1313 end; 1314 1315begin 1316 AFont := GetFont; 1317 SetLayoutText(AFont^.GDIFontObject, AText, ALength); 1318 1319 WidgetCont := pango_layout_get_context(AFont^.GDIFontObject); 1320 Direction := pango_find_base_dir(AText, ALength); 1321 pango_context_set_base_dir(WidgetCont, Direction); 1322 1323 if AFont^.LogFont.lfEscapement <> 0 then 1324 begin 1325 if Widget <> nil then 1326 renderer := gdk_pango_renderer_get_default(gtk_widget_get_screen(Widget)) 1327 else 1328 renderer := gdk_pango_renderer_get_default(gdk_screen_get_default); 1329 RemovePixbuf; 1330 gdk_pango_renderer_set_drawable(renderer, drawable); 1331 gdk_pango_renderer_set_gc(renderer, GC); 1332 SetColors(FGColor, BGColor); 1333 1334 OldMatrix := pango_context_get_matrix(WidgetCont); 1335 NewMatrix.xx := 1.0; 1336 NewMatrix.xy := 0.0; 1337 NewMatrix.yx := 0.0; 1338 NewMatrix.yy := 1.0; 1339 NewMatrix.x0 := 0.0; 1340 NewMatrix.y0 := 0.0; 1341 pango_matrix_translate(@NewMatrix, X, Y); 1342 pango_matrix_rotate(@NewMatrix, AFont^.LogFont.lfEscapement div 10); 1343 1344 pango_context_set_matrix(WidgetCont, @NewMatrix); 1345 pango_layout_context_changed(AFont^.GDIFontObject); 1346 pango_renderer_draw_layout(PPangoRenderer(renderer), AFont^.GDIFontObject, X, Y); 1347 1348 //now reset 1349 pango_context_set_matrix(WidgetCont, OldMatrix); 1350 pango_layout_context_changed(AFont^.GDIFontObject); 1351 1352 SetColors(nil, nil); 1353 gdk_pango_renderer_set_drawable(renderer, nil); 1354 gdk_pango_renderer_set_gc(renderer, nil); 1355 end 1356 else 1357 gdk_draw_layout_with_colors(drawable, GC, X, Y, AFont^.GDIFontObject, FGColor, BGColor); 1358end; 1359 1360