1{ $Id$} 2{ 3 ***************************************************************************** 4 * Gtk2WSControls.pp * 5 * ----------------- * 6 * * 7 * * 8 ***************************************************************************** 9 10 ***************************************************************************** 11 This file is part of the Lazarus Component Library (LCL) 12 13 See the file COPYING.modifiedLGPL.txt, included in this distribution, 14 for details about the license. 15 ***************************************************************************** 16} 17unit Gtk2WSControls; 18 19{$mode objfpc}{$H+} 20{$I gtk2defines.inc} 21 22interface 23 24uses 25 // RTL 26 Classes, SysUtils, 27 Gtk2, Gdk2, Glib2, gdk2pixbuf, 28 // LCL 29//////////////////////////////////////////////////// 30// I M P O R T A N T 31//////////////////////////////////////////////////// 32// To get as little as posible circles, 33// uncomment only when needed for registration 34//////////////////////////////////////////////////// 35 Controls, ComCtrls, 36//////////////////////////////////////////////////// 37 Graphics, 38 39 Gtk2Globals, Gtk2Def, 40 Gtk2Proc, LCLType, LCLProc, 41 WSControls, WSProc, Gtk2WinapiWindow; 42 43 44type 45 46 { TGtk2WSDragImageListResolution } 47 48 TGtk2WSDragImageListResolution = class(TWSDragImageListResolution) 49 published 50 class function BeginDrag(const ADragImageList: TDragImageListResolution; {%H-}Window: HWND; AIndex, X, Y: Integer): Boolean; override; 51 class function DragMove(const {%H-}ADragImageList: TDragImageListResolution; X, Y: Integer): Boolean; override; 52 class procedure EndDrag(const {%H-}ADragImageList: TDragImageListResolution); override; 53 class function HideDragImage(const {%H-}ADragImageList: TDragImageListResolution; 54 {%H-}ALockedWindow: HWND; {%H-}DoUnLock: Boolean): Boolean; override; 55 class function ShowDragImage(const {%H-}ADragImageList: TDragImageListResolution; 56 {%H-}ALockedWindow: HWND; X, Y: Integer; {%H-}DoLock: Boolean): Boolean; override; 57 end; 58 59 { TGtkWSControl } 60 61 TGtk2WSControl = class(TWSControl) 62 published 63 end; 64 65 66 { TGtk2WSWinControl } 67 68 TGtk2WSWinControl = class(TWSWinControl) 69 private 70 protected 71 public 72 // Internal public 73 class procedure SetCallbacks(const AGTKObject: PGTKObject; const AComponent: TComponent); 74 published 75 class function CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): HWND; override; 76 77 class procedure AddControl(const AControl: TControl); override; 78 class function CanFocus(const AWinControl: TWinControl): Boolean; override; 79 class procedure ConstraintsChange(const AWinControl: TWinControl); override; 80 class procedure DestroyHandle(const AWinControl: TWinControl); override; 81 class procedure Invalidate(const AWinControl: TWinControl); override; 82 83 class function GetText(const AWinControl: TWinControl; var AText: String): Boolean; override; 84 85 class procedure SetBorderStyle(const AWinControl: TWinControl; const ABorderStyle: TBorderStyle); override; 86 class procedure SetBounds(const AWinControl: TWinControl; const ALeft, ATop, AWidth, AHeight: Integer); override; 87 class procedure SetChildZPosition(const AWinControl, AChild: TWinControl; const {%H-}AOldPos, ANewPos: Integer; const AChildren: TFPList); override; 88 class procedure SetColor(const AWinControl: TWinControl); override; 89 class procedure SetCursor(const AWinControl: TWinControl; const ACursor: HCursor); override; 90 class procedure SetFont(const AWinControl: TWinControl; const AFont: TFont); override; 91 class procedure SetSize(const AWinControl: TWinControl; const AWidth, AHeight: Integer); override; 92 class procedure SetPos(const AWinControl: TWinControl; const ALeft, ATop: Integer); override; 93 class procedure SetText(const AWinControl: TWinControl; const AText: string); override; 94 class procedure SetShape(const AWinControl: TWinControl; const AShape: HBITMAP); override; 95 class procedure SetBiDiMode(const AWinControl: TWinControl; UseRightToLeftAlign, {%H-}UseRightToLeftReading, {%H-}UseRightToLeftScrollBar : Boolean); override; 96 97 class procedure PaintTo(const AWinControl: TWinControl; ADC: HDC; X, Y: Integer); override; 98 class procedure Repaint(const AWinControl: TWinControl); override; 99 class procedure ShowHide(const AWinControl: TWinControl); override; 100 class procedure ScrollBy(const AWinControl: TWinControl; DeltaX, DeltaY: integer); override; 101 end; 102 103 { TGtk2WSGraphicControl } 104 105 TGtk2WSGraphicControl = class(TWSGraphicControl) 106 published 107 end; 108 109 { TGtk2WSCustomControl } 110 111 TGtk2WSCustomControl = class(TWSCustomControl) 112 published 113 end; 114 115 { TGtk2WSImageList } 116 117 TGtk2WSImageList = class(TWSImageList) 118 published 119 end; 120 121 { TGtkWSBaseScrollingWinControl } 122 { 123 TGtkWSBaseScrollingWinControl is a shared gtk only base implementation of 124 all scrolling widgets, like TListView, TScrollingWinControl etc. 125 It only creates a scrolling widget and handles the LM_HSCROLL and LM_VSCROLL 126 messages 127 } 128 PBaseScrollingWinControlData = ^TBaseScrollingWinControlData; 129 TBaseScrollingWinControlData = record 130 HValue: Integer; 131 HScroll: PGTKWidget; 132 VValue: Integer; 133 VScroll: PGTKWidget; 134 end; 135 136 { TGtk2WSBaseScrollingWinControl } 137 138 TGtk2WSBaseScrollingWinControl = class(TWSWinControl) 139 public 140 class procedure SetCallbacks(const AWidget: PGtkWidget; const AWidgetInfo: PWidgetInfo); virtual; 141 published 142 class function CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): HWND; override; 143 end; 144 145function GetWidgetHAdjustment(AWidget: PGTKWidget): PGTKAdjustment; 146function GetWidgetVAdjustment(AWidget: PGTKWidget): PGTKAdjustment; 147 148var 149 HasWarnedLibOverlay: boolean = false; 150 151implementation 152 153uses 154 Gtk2Int, LMessages, Gtk2WSPrivate, Forms; 155 156{ TGtk2WSWinControl } 157 158 159class function TGtk2WSWinControl.CreateHandle(const AWinControl: TWinControl; 160 const AParams: TCreateParams): HWND; 161var 162 Widget: PGtkWidget; 163 WidgetInfo: PWidgetInfo; 164 Allocation: TGTKAllocation; 165 ScrollBar: PGtkWidget; 166 Adjustment: PGtkAdjustment; 167begin 168 Widget := GTK2WidgetSet.CreateAPIWidget(AWinControl); 169 {$IFDEF DebugLCLComponents} 170 DebugGtkWidgets.MarkCreated(Widget, dbgsName(AWinControl)); 171 {$ENDIF} 172 173 Result := THandle({%H-}PtrUInt(Widget)); 174 if Result = 0 then Exit; 175 176 WidgetInfo := GetWidgetInfo(Widget); // Widget info already created in CreateAPIWidget 177 WidgetInfo^.Style := AParams.Style; 178 WidgetInfo^.ExStyle := AParams.ExStyle; 179 WidgetInfo^.WndProc := {%H-}PtrUInt(AParams.WindowClass.lpfnWndProc); 180 181 // set allocation 182 Allocation.X := AParams.X; 183 Allocation.Y := AParams.Y; 184 Allocation.Width := AParams.Width; 185 Allocation.Height := AParams.Height; 186 gtk_widget_size_allocate(Widget, @Allocation); 187 188 Set_RC_Name(AWinControl, Widget); 189 190 TGtk2WSWinControl.SetCallbacks(GTK_OBJECT(Widget), AWinControl); 191 192 // scrollbars 193 if (GetWidgetClassName(GTK_SCROLLED_WINDOW(Widget)^.vscrollbar)='OsScrollbar') 194 or (GetWidgetClassName(GTK_SCROLLED_WINDOW(Widget)^.hscrollbar)='OsScrollbar') 195 then begin 196 // ubuntu liboverlay scrollbar is active 197 if not HasWarnedLibOverlay then begin 198 HasWarnedLibOverlay:=true; 199 debugln(['WARNING: liboverlay_scrollbar is active for control=',AWinControl,'. Set environment option LIBOVERLAY_SCROLLBAR=0 before starting this application, otherwise scrollbars will not work properly.']); 200 end; 201 end; 202 203 ScrollBar:=GTK_SCROLLED_WINDOW(Widget)^.hscrollbar; 204 if (GetWidgetClassName(ScrollBar)='OsScrollbar') 205 then begin 206 // the ubuntu scroll bar eats the change-value signal => use value-changed 207 Adjustment:=gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(Widget)); 208 g_signal_connect_after(Adjustment, 'value-changed',TGCallback(@Gtk2RangeUbuntuScrollCB), WidgetInfo); 209 end else begin 210 g_signal_connect_after(ScrollBar, 'change-value', 211 TGCallback(@Gtk2RangeScrollCB), WidgetInfo); 212 end; 213 214 ScrollBar:=GTK_SCROLLED_WINDOW(Widget)^.vscrollbar; 215 if (GetWidgetClassName(ScrollBar)='OsScrollbar') 216 then begin 217 // the ubuntu scroll bar eats the change-value signal => use value-changed 218 Adjustment:=gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(Widget)); 219 g_signal_connect_after(Adjustment, 'value-changed',TGCallback(@Gtk2RangeUbuntuScrollCB), WidgetInfo); 220 end else begin 221 g_signal_connect_after(ScrollBar, 'change-value', 222 TGCallback(@Gtk2RangeScrollCB), WidgetInfo); 223 end; 224 225 g_signal_connect(GTK_SCROLLED_WINDOW(Widget)^.hscrollbar, 'button-press-event', 226 TGCallback(@Gtk2RangeScrollPressCB), WidgetInfo); 227 g_signal_connect(GTK_SCROLLED_WINDOW(Widget)^.hscrollbar, 'button-release-event', 228 TGCallback(@Gtk2RangeScrollReleaseCB), WidgetInfo); 229 g_signal_connect(GTK_SCROLLED_WINDOW(Widget)^.vscrollbar, 'button-press-event', 230 TGCallback(@Gtk2RangeScrollPressCB), WidgetInfo); 231 g_signal_connect(GTK_SCROLLED_WINDOW(Widget)^.vscrollbar, 'button-release-event', 232 TGCallback(@Gtk2RangeScrollReleaseCB), WidgetInfo); 233 234 g_signal_connect(Widget, 'scroll-event', TGCallback(@Gtk2ScrolledWindowScrollCB), WidgetInfo); 235end; 236 237class procedure TGtk2WSWinControl.SetBiDiMode(const AWinControl : TWinControl; 238 UseRightToLeftAlign, UseRightToLeftReading, UseRightToLeftScrollBar : Boolean 239 ); 240const 241 WidgetDirection : array[boolean] of longint = (GTK_TEXT_DIR_LTR, GTK_TEXT_DIR_RTL); 242var 243 Info: PWidgetInfo; 244begin 245 if not WSCheckHandleAllocated(AWinControl, 'SetBiDiMode') then 246 Exit; 247 gtk_widget_set_direction({%H-}PGtkWidget(AWinControl.Handle), 248 WidgetDirection[UseRightToLeftAlign]); 249 Info := GetWidgetInfo({%H-}PGtkWidget(AWinControl.Handle)); 250 if Info <> nil then 251 begin 252 if Info^.CoreWidget <> nil then 253 gtk_widget_set_direction(Info^.CoreWidget, 254 WidgetDirection[UseRightToLeftAlign]); 255 if Info^.ClientWidget <> nil then 256 gtk_widget_set_direction(Info^.ClientWidget, 257 WidgetDirection[UseRightToLeftAlign]); 258 end; 259end; 260 261function Gtk1GetText(const AWinControl: TWinControl; var AText: String): Boolean; 262var 263 CS: PChar; 264 Handle: HWND; 265begin 266 if not WSCheckHandleAllocated(AWinControl, 'GetText') 267 then Exit(False); 268 Result := true; 269 Handle := AWinControl.Handle; 270 case AWinControl.fCompStyle of 271 csComboBox: 272 begin 273 AText := StrPas(gtk_entry_get_text(PGtkEntry({%H-}PGtkCombo(Handle)^.entry))); 274 end; 275 csEdit: AText:= StrPas(gtk_entry_get_text({%H-}PgtkEntry(Handle))); 276 csSpinEdit: AText:= StrPas(gtk_entry_get_text(@{%H-}PGtkSpinButton(Handle)^.entry)); 277 csMemo: 278 begin 279 CS := gtk_editable_get_chars(PGtkEditable( 280 GetOrCreateWidgetInfo({%H-}Pointer(Handle))^.CoreWidget), 0, -1); 281 AText := StrPas(CS); 282 g_free(CS); 283 end; 284 else 285 Result := false; 286 end; 287end; 288 289 290class function TGtk2WSWinControl.GetText(const AWinControl: TWinControl; 291 var AText: String): Boolean; 292var 293 TextBuf: PGtkTextBuffer; 294 StartIter, 295 EndIter: TGtkTextIter; 296 CS: PChar; 297 Handle: HWND; 298begin 299 Result := true; 300 Handle := AWinControl.Handle; 301 case AWinControl.fCompStyle of 302 csMemo: 303 begin 304 TextBuf := gtk_text_view_get_buffer(PGtkTextView(GetOrCreateWidgetInfo({%H-}Pointer(Handle))^.CoreWidget)); 305 gtk_text_buffer_get_start_iter(TextBuf, @StartIter); 306 gtk_text_buffer_get_end_iter(TextBuf, @EndIter); 307 CS := gtk_text_buffer_get_text(TextBuf, @StartIter, @EndIter, False); 308 AText := StrPas(CS); 309 g_free(CS); 310 end; 311 else 312 Result:=Gtk1GetText(AWinControl, AText); 313 end; 314end; 315 316 317procedure Gtk1SetBorderStyle(const AWinControl: TWinControl; const ABorderStyle: TBorderStyle); 318var 319 Widget: PGtkWidget; 320begin 321 if not WSCheckHandleAllocated(AWinControl, 'SetBorderStyle') 322 then Exit; 323 324 Widget := {%H-}PGtkWidget(AWinControl.Handle); 325 if GtkWidgetIsA(Widget, GTKAPIWidget_GetType) then 326 GTKAPIWidget_SetShadowType(PGTKAPIWidget(Widget), BorderStyleShadowMap[ABorderStyle]) 327 else 328 if GTK_IS_FRAME(Widget) then 329 gtk_frame_set_shadow_type(PGtkFrame(Widget), BorderStyleShadowMap[ABorderStyle]) 330 else 331 if GTK_IS_VIEWPORT(Widget) then 332 gtk_viewport_set_shadow_type(PGtkViewport(Widget), BorderStyleShadowMap[ABorderStyle]); 333end; 334 335class procedure TGtk2WSWinControl.SetBorderStyle( 336 const AWinControl: TWinControl; const ABorderStyle: TBorderStyle); 337var 338 Widget: PGtkWidget; 339begin 340 if not WSCheckHandleAllocated(AWinControl, 'SetBorderStyle') 341 then Exit; 342 343 Widget := {%H-}PGtkWidget(AWinControl.Handle); 344 if GTK_IS_SCROLLED_WINDOW(Widget) then 345 gtk_scrolled_window_set_shadow_type(PGtkScrolledWindow(Widget), BorderStyleShadowMap[ABorderStyle]) 346 else 347 if GTK_IS_ENTRY(Widget) then 348 gtk_entry_set_has_frame(PGtkEntry(Widget), ABorderStyle <> bsNone) 349 else 350 Gtk1SetBorderStyle(AWinControl, ABorderStyle); 351end; 352 353function GetWidgetHAdjustment(AWidget: PGTKWidget): PGTKAdjustment; 354begin 355 if GtkWidgetIsA(AWidget,GTK_TYPE_SCROLLED_WINDOW) then 356 Result:=gtk_scrolled_window_get_hadjustment(PGTKScrolledWindow(AWidget)) 357 else if GtkWidgetIsA(AWidget,GTK_TYPE_TREE_VIEW) then 358 Result:=gtk_tree_view_get_hadjustment(PGtkTreeView(AWidget)) 359 else 360 Result:=nil; 361end; 362 363function GetWidgetVAdjustment(AWidget: PGTKWidget): PGTKAdjustment; 364begin 365 if GtkWidgetIsA(AWidget,GTK_TYPE_SCROLLED_WINDOW) then 366 Result:=gtk_scrolled_window_get_vadjustment(PGTKScrolledWindow(AWidget)) 367 else if GtkWidgetIsA(AWidget,GTK_TYPE_TREE_VIEW) then 368 Result:=gtk_tree_view_get_vadjustment(PGtkTreeView(AWidget)) 369 else 370 Result:=nil; 371end; 372 373{ TGtk2WSDragImageListResolution } 374 375class function TGtk2WSDragImageListResolution.BeginDrag( 376 const ADragImageList: TDragImageListResolution; Window: HWND; AIndex, X, Y: Integer 377 ): Boolean; 378var 379 ABitmap: TBitmap; 380 GDIObject: PGDIObject; 381 Pixmap: PGdkPixmap; 382 Mask: PGdkBitmap; 383begin 384 ABitmap := TBitmap.Create; 385 ADragImageList.GetBitmap(AIndex, ABitmap); 386 387 if (ABitmap.Handle = 0) or (ABitmap.Width = 0) or (ABitmap.Height = 0) then 388 begin 389 Result := False; 390 Exit; 391 end; 392 393 GDIObject := {%H-}PGDIObject(ABitmap.Handle); 394 395 Pixmap := nil; 396 Mask := nil; 397 case GDIObject^.GDIBitmapType of 398 gbBitmap: 399 begin 400 Pixmap := GDIObject^.GDIBitmapObject; 401 gdk_bitmap_ref(Pixmap); 402 Mask := nil; 403 end; 404 gbPixmap: 405 begin 406 Pixmap := GDIObject^.GDIPixmapObject.Image; 407 Mask := GDIObject^.GDIPixmapObject.Mask; 408 gdk_pixmap_ref(Pixmap); 409 gdk_bitmap_ref(Mask); 410 end; 411 gbPixbuf: 412 begin 413 Pixmap := nil; 414 Mask := nil; 415 // todo: TEST 416 //gdk_pixbuf_render_pixmap_and_mask(GDIObject^.GDIPixbufObject, Pixmap, Mask, $80); 417 gdk_pixbuf_render_pixmap_and_mask(GDIObject^.GDIPixbufObject, Pixmap, Mask, $80); 418 end; 419 end; 420 421 Result := Gtk2Widgetset.DragImageList_BeginDrag(Pixmap, Mask, ADragImageList.DragHotSpot); 422 if Result then 423 Gtk2Widgetset.DragImageList_DragMove(X, Y); 424 gdk_pixmap_unref(Pixmap); 425 gdk_bitmap_unref(Mask); 426 ABitmap.Free; 427end; 428 429class function TGtk2WSDragImageListResolution.DragMove( 430 const ADragImageList: TDragImageListResolution; X, Y: Integer): Boolean; 431begin 432 Result := Gtk2Widgetset.DragImageList_DragMove(X, Y); 433end; 434 435class procedure TGtk2WSDragImageListResolution.EndDrag( 436 const ADragImageList: TDragImageListResolution); 437begin 438 Gtk2Widgetset.DragImageList_EndDrag; 439end; 440 441class function TGtk2WSDragImageListResolution.HideDragImage( 442 const ADragImageList: TDragImageListResolution; ALockedWindow: HWND; DoUnLock: Boolean 443 ): Boolean; 444begin 445 Result := Gtk2Widgetset.DragImageList_SetVisible(False); 446end; 447 448class function TGtk2WSDragImageListResolution.ShowDragImage( 449 const ADragImageList: TDragImageListResolution; ALockedWindow: HWND; X, Y: Integer; 450 DoLock: Boolean): Boolean; 451begin 452 Result := Gtk2Widgetset.DragImageList_DragMove(X, Y) and Gtk2Widgetset.DragImageList_SetVisible(True); 453end; 454 455 456{ TGtk2WSWinControl } 457 458type 459 TWinControlHack = class(TWinControl) 460 end; 461 462function Gtk2TreeViewEditorEvent(widget: PGtkWidget; event: PGdkEvent; data: GPointer): gboolean; cdecl; 463var 464 R: TRect; 465 Alloc: TGtkAllocation; 466 w: PGtkWidget; 467 AOrientation: TGtkOrientation; 468begin 469 Result := CallBackDefaultReturn; 470 case event^._type of 471 GDK_FOCUS_CHANGE: 472 begin 473 // cheat GtkTreeView container , so we are visible and ready for input. 474 if event^.focus_change._in = 1 then 475 begin 476 R := TWinControl(Data).BoundsRect; 477 Alloc.x := R.Left; 478 Alloc.y := R.Top; 479 Alloc.width := R.Right - R.Left; 480 Alloc.height := R.Bottom - R.Top; 481 gtk_widget_size_allocate(Widget, @Alloc); 482 end else 483 begin 484 w := gtk_widget_get_parent(Widget); 485 if Assigned(w) and GTK_IS_ICON_VIEW(w) then 486 begin 487 //gtk2 does not layout items correctly when iconArrangement is iaTop. 488 //so we force it to do so. 489 AOrientation := gtk_icon_view_get_orientation(PGtkIconView(w)); 490 if AOrientation = GTK_ORIENTATION_HORIZONTAL then 491 gtk_icon_view_set_orientation(PGtkIconView(w), GTK_ORIENTATION_VERTICAL) 492 else 493 gtk_icon_view_set_orientation(PGtkIconView(w), GTK_ORIENTATION_HORIZONTAL); 494 gtk_icon_view_set_orientation(PGtkIconView(w), AOrientation) 495 end; 496 end; 497 end; 498 end; 499end; 500 501class procedure TGtk2WSWinControl.AddControl(const AControl: TControl); 502var 503 AParent: TWinControl; 504 ParentWidget: PGTKWidget; 505 ChildWidget: PGTKWidget; 506 pFixed: PGTKWidget; 507begin 508 AParent := TWinControl(AControl).Parent; 509 // DebugLn('LM_AddChild: ',dbgsName(AControl),' ',dbgs(AParent<>nil)); 510 if not Assigned(AParent) then 511 Assert(true, Format('Trace: [TGtkWSWinControl.AddControl] %s --> Parent is not assigned', [AControl.ClassName])) 512 else 513 begin 514 // DebugLn(Format('Trace: [TGtkWSWinControl.AddControl] %s --> Calling Add Child: %s', [AParent.ClassName, AControl.ClassName])); 515 516 ParentWidget := {%H-}PGtkwidget(AParent.Handle); 517 pFixed := GetFixedWidget(ParentWidget); 518 519 // gtk2 is pretty tricky about adding editor into control 520 if (AParent.FCompStyle = csListView) and 521 (TWinControl(AControl).FCompStyle = csEdit) then 522 begin 523 ChildWidget := {%H-}PGtkWidget(TWinControl(AControl).Handle); 524 ParentWidget := gtk_bin_get_child(PGtkBin(PFixed)); // treeview 525 // MUST allocate some size before adding it to container ! 526 gtk_widget_set_size_request(ChildWidget, 80, 25); 527 gtk_widget_set_parent(ChildWidget, ParentWidget); 528 // now we connect our GtkEntry directly to event filter 529 g_signal_connect(PGtkObject(ChildWidget), 'event', 530 gtk_signal_func(@Gtk2TreeViewEditorEvent), AControl); 531 end else 532 begin 533 if pFixed <> ParentWidget then 534 begin 535 // parent changed for child 536 ChildWidget := {%H-}PGtkWidget(TWinControl(AControl).Handle); 537 FixedPutControl(pFixed, ChildWidget, AControl.Left, AControl.Top); 538 RegroupAccelerator(ChildWidget); 539 end; 540 end; 541 end; 542end; 543 544class function TGtk2WSWinControl.CanFocus(const AWinControl: TWinControl): Boolean; 545var 546 Widget, FocusWidget: PGtkWidget; 547begin 548 if AWinControl.HandleAllocated then 549 begin 550 Widget := {%H-}PGtkWidget(AWinControl.Handle); 551 FocusWidget := FindFocusWidget(Widget); 552 Result := (FocusWidget <> nil) and GTK_WIDGET_CAN_FOCUS(FocusWidget); 553 end else 554 Result := False; 555end; 556 557class procedure TGtk2WSWinControl.ConstraintsChange(const AWinControl: TWinControl); 558var 559 Widget: PGtkWidget; 560 Geometry: TGdkGeometry; 561begin 562 Widget := {%H-}PGtkWidget(AWinControl.Handle); 563 if (Widget <> nil) and (GtkWidgetIsA(Widget, gtk_window_get_type)) then 564 begin 565 with Geometry do 566 begin 567 if AWinControl.Constraints.MinWidth > 0 then 568 min_width := AWinControl.Constraints.MinWidth 569 else 570 min_width := 1; 571 if AWinControl.Constraints.MaxWidth > 0 then 572 max_width := AWinControl.Constraints.MaxWidth 573 else 574 max_width := 32767; 575 if AWinControl.Constraints.MinHeight > 0 then 576 min_height := AWinControl.Constraints.MinHeight 577 else 578 min_height := 1; 579 if AWinControl.Constraints.MaxHeight > 0 then 580 max_height := AWinControl.Constraints.MaxHeight 581 else 582 max_height := 32767; 583 584 base_width := AWinControl.Width; 585 base_height := AWinControl.Height; 586 width_inc := 1; 587 height_inc := 1; 588 min_aspect := 0; 589 max_aspect := 1; 590 win_gravity := gtk_window_get_gravity(PGtkWindow(Widget)); 591 end; 592 //debugln('TGtk2WSWinControl.ConstraintsChange A ',GetWidgetDebugReport(Widget),' max=',dbgs(Geometry.max_width),'x',dbgs(Geometry.max_height)); 593 gtk_window_set_geometry_hints(PGtkWindow(Widget), nil, @Geometry, 594 GDK_HINT_POS or GDK_HINT_MIN_SIZE or GDK_HINT_MAX_SIZE); 595 end; 596end; 597 598class procedure TGtk2WSWinControl.DestroyHandle(const AWinControl: TWinControl); 599begin 600 //DebugLn('TGtk2WSWinControl.DestroyHandle ',DbgSName(AWinControl)); 601 Gtk2WidgetSet.DestroyLCLComponent(AWinControl); 602end; 603 604class procedure TGtk2WSWinControl.Invalidate(const AWinControl: TWinControl); 605begin 606 if not WSCheckHandleAllocated(AWinControl, 'Invalidate') 607 then Exit; 608 609 //DebugLn('Trace:Trying to invalidate window... !!!'); 610 gtk_widget_queue_draw({%H-}PGtkWidget(AWinControl.Handle)); 611end; 612 613class procedure TGtk2WSWinControl.ShowHide(const AWinControl: TWinControl); 614begin 615 // other methods use ShowHide also, can't move code 616 Gtk2WidgetSet.SetVisible(AWinControl, AWinControl.HandleObjectShouldBeVisible); 617 InvalidateLastWFPResult(AWinControl, AWinControl.BoundsRect); 618end; 619 620class procedure TGtk2WSWinControl.ScrollBy(const AWinControl: TWinControl; 621 DeltaX, DeltaY: integer); 622var 623 Scrolled: PGtkScrolledWindow; 624 Adjustment: PGtkAdjustment; 625 h, v: Double; 626 NewPos: Double; 627begin 628 if not AWinControl.HandleAllocated then exit; 629 Scrolled := GTK_SCROLLED_WINDOW({%H-}Pointer(AWinControl.Handle)); 630 if not GTK_IS_SCROLLED_WINDOW(Scrolled) then 631 exit; 632 Adjustment := gtk_scrolled_window_get_hadjustment(Scrolled); 633 if Adjustment <> nil then 634 begin 635 h := gtk_adjustment_get_value(Adjustment); 636 NewPos := Adjustment^.upper - Adjustment^.page_size; 637 if h - DeltaX <= NewPos then 638 NewPos := h - DeltaX; 639 gtk_adjustment_set_value(Adjustment, NewPos); 640 end; 641 Adjustment := gtk_scrolled_window_get_vadjustment(Scrolled); 642 if Adjustment <> nil then 643 begin 644 v := gtk_adjustment_get_value(Adjustment); 645 NewPos := Adjustment^.upper - Adjustment^.page_size; 646 if v - DeltaY <= NewPos then 647 NewPos := v - DeltaY; 648 gtk_adjustment_set_value(Adjustment, NewPos); 649 end; 650 AWinControl.Invalidate; 651end; 652 653class procedure TGtk2WSWinControl.SetBounds(const AWinControl: TWinControl; 654 const ALeft, ATop, AWidth, AHeight: Integer); 655var 656 AForm: TCustomForm; 657 Geometry: TGdkGeometry; 658 AHints: TGdkWindowHints; 659 AFixedWidthHeight: Boolean; 660begin 661 if not WSCheckHandleAllocated(AWinControl, 'SetBounds') 662 then Exit; 663 ResizeHandle(AWinControl); 664 InvalidateLastWFPResult(AWinControl, Rect(ALeft, ATop, AWidth, AHeight)); 665 if not AWinControl.Visible then // Gtk2WSForms.ShowHide will correct visibility 666 exit; 667 if (not (AWinControl is TCustomForm)) or (AWinControl.Parent<>nil) 668 or (AWinControl.ParentWindow<>0) then 669 exit; 670 AForm := TCustomForm(AWinControl); 671 if not (csDesigning in AForm.ComponentState) and 672 AForm.HandleObjectShouldBeVisible then 673 begin 674 // we must set fixed size, gtk_window_set_resizable does not work 675 // as expected for some reason.issue #20741. 676 // Constraints fix issue #29563 677 AFixedWidthHeight := AForm.BorderStyle in [bsDialog, bsSingle, bsToolWindow]; 678 FillChar(Geometry{%H-}, SizeOf(TGdkGeometry), 0); 679 with Geometry do 680 begin 681 if not AFixedWidthHeight and (AForm.Constraints.MinWidth > 0) then 682 min_width := AForm.Constraints.MinWidth 683 else 684 if AFixedWidthHeight then 685 min_width := AForm.Width; 686 if not AFixedWidthHeight and (AForm.Constraints.MaxWidth > 0) then 687 max_width := AForm.Constraints.MaxWidth 688 else 689 if AFixedWidthHeight then 690 max_width := AForm.Width; 691 if not AFixedWidthHeight and (AForm.Constraints.MinHeight > 0) then 692 min_height := AForm.Constraints.MinHeight 693 else 694 if AFixedWidthHeight then 695 min_height := AForm.Height; 696 if not AFixedWidthHeight and (AForm.Constraints.MaxHeight > 0) then 697 max_height := AForm.Constraints.MaxHeight 698 else 699 if AFixedWidthHeight then 700 max_height := AForm.Height; 701 702 if not AFixedWidthHeight and (AForm.Constraints.MaxHeight = 0) then 703 max_height := 32767; 704 if not AFixedWidthHeight and (AForm.Constraints.MaxWidth = 0) then 705 max_width := 32767; 706 707 base_width := AForm.Width; 708 base_height := AForm.Height; 709 width_inc := 1; 710 height_inc := 1; 711 min_aspect := 0; 712 max_aspect := 1; 713 win_gravity := gtk_window_get_gravity({%H-}PGtkWindow(AForm.Handle)); 714 end; 715 //debugln('TGtk2WSWinControl.SetBounds A maxw=',dbgs(Geometry.max_width),' maxh=',dbgs(Geometry.max_height), 716 //' base w=',dbgs(Geometry.base_width),' h=',dbgs(Geometry.base_height)); 717 if AFixedWidthHeight then 718 gtk_window_set_geometry_hints({%H-}PGtkWindow(AForm.Handle), nil, @Geometry, 719 GDK_HINT_POS or GDK_HINT_MIN_SIZE or GDK_HINT_MAX_SIZE) 720 else 721 begin 722 if AForm.BorderStyle <> bsNone then 723 begin 724 AHints := GDK_HINT_POS or GDK_HINT_BASE_SIZE; 725 if (AForm.Constraints.MinHeight > 0) or (AForm.Constraints.MinWidth > 0) then 726 AHints := AHints or GDK_HINT_MIN_SIZE; 727 if (AForm.Constraints.MaxHeight > 0) or (AForm.Constraints.MaxWidth > 0) then begin 728 AHints := AHints or GDK_HINT_MAX_SIZE; 729 { Work around for only one maximum specified; see TGtk2WSWinControl.ConstraintsChange } 730 if AForm.Constraints.MaxHeight = 0 then 731 Geometry.max_height := 32767; 732 if AForm.Constraints.MaxWidth = 0 then 733 Geometry.max_width := 32767; 734 end; 735 {$IFDEF HASX} 736 if (AHints and GDK_HINT_MIN_SIZE = 0) and (AHints and GDK_HINT_MAX_SIZE = 0) and 737 (Gtk2WidgetSet.GetWindowManager = 'openbox') then 738 else 739 {$ENDIF} 740 gtk_window_set_geometry_hints({%H-}PGtkWindow(AForm.Handle), nil, @Geometry, 741 AHints); 742 end; 743 gtk_window_resize({%H-}PGtkWindow(AForm.Handle), AForm.Width, AForm.Height); 744 end; 745 end; 746end; 747 748 749class procedure TGtk2WSWinControl.SetCallbacks(const AGTKObject: PGTKObject; 750 const AComponent: TComponent); 751begin 752 Gtk2WidgetSet.SetCommonCallbacks(AGtkObject, AComponent); 753end; 754 755class procedure TGtk2WSWinControl.SetChildZPosition( 756 const AWinControl, AChild: TWinControl; 757 const AOldPos, ANewPos: Integer; const AChildren: TFPList); 758var 759 n: Integer; 760 child: TWinControlHack; 761begin 762 if not WSCheckHandleAllocated(AWincontrol, 'SetChildZPosition') 763 then Exit; 764 765 if not WSCheckHandleAllocated(AChild, 'SetChildZPosition (child)') then 766 Exit; 767 768 if (ANewPos <= 0) or (ANewPos >= AChildren.Count - 1) then 769 begin 770 // simple 771 Child := TWinControlHack(AChild); 772 if ANewPos <= 0 then // bottom 773 TGtkPrivateWidgetClass( 774 Child.WidgetSetClass.WSPrivate).SetZPosition(Child, wszpBack) 775 else 776 TGtkPrivateWidgetClass( 777 Child.WidgetSetClass.WSPrivate).SetZPosition(Child, wszpFront); 778 end else 779 begin 780 for n := 1 to AChildren.Count - 1 do 781 begin 782 Child := TWinControlHack(AChildren[n]); 783 if Child.HandleAllocated then 784 TGtkPrivateWidgetClass( 785 Child.WidgetSetClass.WSPrivate).SetZPosition(Child, wszpBack); 786 end; 787 end; 788end; 789 790class procedure TGtk2WSWinControl.SetCursor(const AWinControl: TWinControl; const ACursor: HCursor); 791var 792 WidgetInfo: PWidgetInfo; 793begin 794 if not WSCheckHandleAllocated(AWinControl, 'SetCursor') 795 then Exit; 796 797 WidgetInfo := GetWidgetInfo({%H-}Pointer(AWinControl.Handle)); 798 if WidgetInfo^.ControlCursor <> ACursor then 799 begin 800 WidgetInfo^.ControlCursor := ACursor; 801 TGtkPrivateWidgetClass(AWinControl.WidgetSetClass.WSPrivate).UpdateCursor(WidgetInfo); 802 end; 803end; 804 805class procedure TGtk2WSWinControl.SetFont(const AWinControl: TWinControl; 806 const AFont: TFont); 807var 808 Widget: PGtkWidget; 809begin 810 if not WSCheckHandleAllocated(AWinControl, 'SetFont') 811 then Exit; 812 813 Widget := {%H-}PGtkWidget(AWinControl.Handle); 814 if GtkWidgetIsA(Widget, GTKAPIWidget_GetType) then 815 exit; 816 817 //DebugLn('TGtk2WSWinControl.SetFont ',DbgSName(AWinControl)); 818 Gtk2WidgetSet.SetWidgetFont(Widget, AFont); 819 Gtk2WidgetSet.SetWidgetColor(Widget, AFont.Color, clNone, 820 [GTK_STATE_NORMAL,GTK_STATE_ACTIVE, 821 GTK_STATE_PRELIGHT,GTK_STATE_SELECTED, 822 GTK_STYLE_TEXT]); 823end; 824 825class procedure TGtk2WSWinControl.SetPos(const AWinControl: TWinControl; 826 const ALeft, ATop: Integer); 827var 828 Widget: PGtkWidget; 829 Allocation: TGTKAllocation; 830begin 831 if not WSCheckHandleAllocated(AWinControl, 'SetPos') 832 then Exit; 833 {$IFDEF VerboseSizeMsg} 834 DebugLn(['TGtk2WSWinControl.SetPos ',DbgSName(AWinControl),' ',ALeft,',',ATop]); 835 {$ENDIF} 836 837 Widget := {%H-}PGtkWidget(AWinControl.Handle); 838 Allocation.X := gint16(ALeft); 839 Allocation.Y := gint16(ATop); 840 Allocation.Width := guint16(Widget^.Allocation.Width); 841 Allocation.Height := guint16(Widget^.Allocation.Height); 842 gtk_widget_size_allocate(Widget, @Allocation);// Beware: this triggers callbacks 843end; 844 845class procedure TGtk2WSWinControl.SetSize(const AWinControl: TWinControl; 846 const AWidth, AHeight: Integer); 847var 848 Widget: PGtkWidget; 849 Allocation: TGTKAllocation; 850begin 851 if not WSCheckHandleAllocated(AWinControl, 'SetSize') 852 then Exit; 853 {$IFDEF VerboseSizeMsg} 854 DebugLn(['TGtk2WSWinControl.SetSize ',DbgSName(AWinControl),' ',AWidth,',',AHeight]); 855 {$ENDIF} 856 857 Widget := {%H-}PGtkWidget(AWinControl.Handle); 858 Allocation.X := Widget^.Allocation.X; 859 Allocation.Y := Widget^.Allocation.Y; 860 Allocation.Width := guint16(AWidth); 861 Allocation.Height := guint16(AHeight); 862 gtk_widget_size_allocate(Widget, @Allocation);// Beware: this triggers callbacks 863end; 864 865class procedure TGtk2WSWinControl.SetColor(const AWinControl: TWinControl); 866begin 867 if not WSCheckHandleAllocated(AWinControl, 'SetColor') 868 then Exit; 869 870 // do not change color of scrollbar. issue #22996 871 if (AWinControl.FCompStyle = csScrollBar) then 872 exit; 873 874 if ((csOpaque in AWinControl.ControlStyle) and 875 GtkWidgetIsA({%H-}pGtkWidget(AWinControl.handle),GTKAPIWidget_GetType)) then 876 Exit; 877 878 //DebugLn('TGtk2WSWinControl.SetColor ',DbgSName(AWinControl)); 879 Gtk2WidgetSet.SetWidgetColor({%H-}PGtkWidget(AWinControl.Handle), 880 AWinControl.Font.Color, AWinControl.Color, 881 [GTK_STATE_NORMAL, GTK_STATE_ACTIVE, 882 GTK_STATE_PRELIGHT, GTK_STATE_SELECTED]); 883// GtkWidgetSet.setWidgetFont(pGtkWidget(AWinControl.handle),aWinControl.font); 884 UpdateWidgetStyleOfControl(AWinControl); 885end; 886 887class procedure TGtk2WSWinControl.SetText(const AWinControl: TWinControl; 888 const AText: string); 889 890 procedure SetNotebookPageTabLabel; 891 var 892 NoteBookWidget: PGtkWidget; // the notebook 893 PageWidget: PGtkWidget; // the page (content widget) 894 TabWidget: PGtkWidget; // the tab (hbox containing a pixmap, a label 895 // and a close button) 896 TabLabelWidget: PGtkWidget; // the label in the tab 897 MenuWidget: PGtkWidget; // the popup menu (hbox containing a pixmap and 898 // a label) 899 MenuLabelWidget: PGtkWidget; // the label in the popup menu item 900 NewText: PChar; 901 begin 902 if (AWinControl.Parent <> nil) and (AWinControl.Parent is TTabControl) then 903 exit; 904 905 // dig through the hierachy to get the labels 906 NoteBookWidget:={%H-}PGtkWidget((AWinControl.Parent).Handle); 907 PageWidget:={%H-}PGtkWidget(AWinControl.Handle); 908 TabWidget:=gtk_notebook_get_tab_label(PGtkNoteBook(NotebookWidget), 909 PageWidget); 910 if TabWidget<>nil then 911 TabLabelWidget:=g_object_get_data(PGObject(TabWidget), 'TabLabel') 912 else 913 TabLabelWidget:=nil; 914 MenuWidget:=gtk_notebook_get_menu_label(PGtkNoteBook(NotebookWidget), 915 PageWidget); 916 if MenuWidget<>nil then 917 MenuLabelWidget:=g_object_get_data(PGObject(MenuWidget), 'TabMenuLabel') 918 else 919 MenuLabelWidget:=nil; 920 // set new text 921 NewText:=PChar(AText); 922 if TabLabelWidget<>nil then 923 gtk_label_set_text(pGtkLabel(TabLabelWidget), NewText); 924 if MenuLabelWidget<>nil then 925 gtk_label_set_text(pGtkLabel(MenuLabelWidget), NewText); 926 end; 927 928var 929 P : Pointer; 930 aLabel, pLabel: pchar; 931begin 932 if not WSCheckHandleAllocated(AWinControl, 'SetText') 933 then Exit; 934 935 //TODO: create classprocedures for this in the corresponding classes 936 937 P := {%H-}Pointer(AWinControl.Handle); 938 Assert(p <> nil, 'Trace:WARNING: [TGtkWidgetSet.SetLabel] --> got nil pointer'); 939 //DebugLn('Trace:Setting Str1 in SetLabel'); 940 pLabel := pchar(AText); 941 942 case AWinControl.fCompStyle of 943 csBitBtn, 944 csButton: DebugLn('[WARNING] Obsolete call to TGTKOBject.SetLabel for ', AWinControl.ClassName); 945 946 csForm, 947 csFileDialog, csOpenFileDialog, csSaveFileDialog, csSelectDirectoryDialog, 948 csPreviewFileDialog, 949 csColorDialog, 950 csFontDialog: 951 if GtkWidgetIsA(p,gtk_window_get_type) then 952 gtk_window_set_title(pGtkWindow(p),PLabel); 953 954 csCheckBox, 955 csToggleBox, 956 csRadioButton: 957 begin 958 aLabel := Ampersands2Underscore(PLabel); 959 try 960 gtk_label_set_text( 961 pGtkLabel(gtk_bin_get_child(PGtkBin(@PGTKToggleButton(p)^.Button))), 962 aLabel); 963 gtk_label_parse_uline( 964 pGtkLabel(gtk_bin_get_child(PGtkBin(@PGTKToggleButton(p)^.Button))), 965 aLabel); 966 finally 967 StrDispose(aLabel); 968 end; 969 end; 970 971 csEdit: 972 begin 973 LockOnChange(PGtkObject(p),+1); 974 gtk_entry_set_text(pGtkEntry(P), pLabel); 975 LockOnChange(PGtkObject(p),-1); 976 end; 977 978 csSpinEdit: 979 begin 980 LockOnChange(PGtkObject(p),+1); 981 gtk_entry_set_text(pGtkEntry(P), pLabel); 982 gtk_spin_button_update(PGtkSpinButton(p)); 983 LockOnChange(PGtkObject(p),-1); 984 end; 985 986 csMemo: 987 begin 988 P:= GetOrCreateWidgetInfo(P)^.CoreWidget; 989 //debugln('TGtk2WSWinControl.SetText A ',dbgs(gtk_text_get_length(PGtkText(P))),' AText="',AText,'"'); 990 gtk_text_freeze(PGtkText(P)); 991 gtk_text_set_point(PGtkText(P), 0); 992 gtk_text_forward_delete(PGtkText(P), gtk_text_get_length(PGtkText(P))); 993 gtk_text_insert(PGtkText(P), nil, nil, nil, pLabel, -1); 994 gtk_text_thaw(PGtkText(P)); 995 //debugln('TGtk2WSWinControl.SetText B ',dbgs(gtk_text_get_length(PGtkText(P)))); 996 end; 997 998 csPage: 999 SetNotebookPageTabLabel; 1000 1001 // else 1002 // DebugLn('WARNING: [TGtkWidgetSet.SetLabel] --> not handled for class ',Sender.ClassName); 1003 end; 1004 //DebugLn(Format('trace: [TGtkWidgetSet.SetLabel] %s --> END', [AWinControl.ClassName])); 1005end; 1006 1007class procedure TGtk2WSWinControl.SetShape(const AWinControl: TWinControl; 1008 const AShape: HBITMAP); 1009var 1010 GtkWidget, FixedWidget: PGtkWidget; 1011 GdkBitmap: PGDKBitmap; 1012begin 1013 if not WSCheckHandleAllocated(AWinControl, 'SetShape') then 1014 Exit; 1015 1016 GtkWidget := {%H-}PGtkWidget(AWinControl.Handle); 1017 FixedWidget := GetFixedWidget(GtkWidget); 1018 1019 if AShape <> 0 then 1020 begin 1021 if Gtk2Widgetset.IsValidGDIObjectType(AShape, gdiBitmap) then 1022 GdkBitmap := {%H-}PGdiObject(AShape)^.GDIBitmapObject 1023 else 1024 GdkBitmap := nil; 1025 end 1026 else 1027 GdkBitmap := nil; 1028 1029 gtk_widget_shape_combine_mask(GtkWidget, GdkBitmap, 0, 0); 1030 if FixedWidget <> GtkWidget then 1031 gtk_widget_shape_combine_mask(FixedWidget, GdkBitmap, 0, 0); 1032end; 1033 1034{ 1035 Paint control to X, Y point of device context. 1036} 1037class procedure TGtk2WSWinControl.PaintTo(const AWinControl: TWinControl; 1038 ADC: HDC; X, Y: Integer); 1039var 1040 DC: TGtkDeviceContext absolute ADC; 1041 1042 procedure PaintGtkForm(AWindow: PGdkWindow); 1043 var 1044 W, H: gint; 1045 Pixbuf: PGdkPixbuf; 1046 MenuPixBuf: PGdkPixBuf; 1047 AMenuBar: PGtkWidget; 1048 OffsetY: Integer; 1049 begin 1050 OffsetY := 0; 1051 MenuPixBuf := nil; 1052 1053 if Assigned(TCustomForm(AWinControl).Menu) then 1054 begin 1055 AMenuBar := {%H-}PGtkWidget(TCustomForm(AWinControl).Menu.Handle); 1056 if GTK_IS_MENU_BAR(AMenuBar) and GTK_WIDGET_VISIBLE(AMenuBar) then 1057 begin 1058 OffsetY := AMenuBar^.allocation.height; 1059 MenuPixbuf := gdk_pixbuf_get_from_drawable(nil, AMenuBar^.Window, nil, 1060 0, 0, 0, 0, AMenuBar^.allocation.Width, AMenuBar^.Allocation.Height); 1061 1062 gdk_pixbuf_render_to_drawable(MenuPixbuf, DC.Drawable, DC.GC, 0, 0, X, Y + OffsetY, 1063 AMenuBar^.allocation.Width, AMenuBar^.Allocation.Height, GDK_RGB_DITHER_NONE, 0, 0); 1064 1065 gdk_pixbuf_unref(MenuPixbuf); 1066 end; 1067 end; 1068 gdk_window_get_size(AWindow, @W, @H); 1069 1070 Pixbuf := gdk_pixbuf_get_from_drawable(nil, AWindow, nil, 1071 0, 0, 0, 0, W, H); 1072 1073 // put menubar into form screenshoot too 1074 if OffsetY <> 0 then 1075 begin 1076 MenuPixBuf := gdk_pixbuf_scale_simple(PixBuf, W, H - OffsetY,GDK_INTERP_NEAREST); 1077 gdk_pixbuf_render_to_drawable(MenuPixbuf, DC.Drawable, DC.GC, 0, 0, X, Y + (OffsetY * 2), 1078 -1, -1, GDK_RGB_DITHER_NONE, 0, 0); 1079 if MenuPixBuf <> nil then 1080 gdk_pixbuf_unref(MenuPixBuf); 1081 end else 1082 gdk_pixbuf_render_to_drawable(Pixbuf, DC.Drawable, DC.GC, 0, 0, X, Y, 1083 -1, -1, GDK_RGB_DITHER_NONE, 0, 0); 1084 1085 gdk_pixbuf_unref(Pixbuf); 1086 end; 1087 1088 procedure PaintWindow(AWindow: PGdkWindow); 1089 var 1090 W, H: gint; 1091 Pixbuf: PGdkPixbuf; 1092 begin 1093 gdk_window_get_size(AWindow, @W, @H); 1094 // for some reason gdk_window_copy_area does not work 1095 Pixbuf := gdk_pixbuf_get_from_drawable(nil, AWindow, nil, 1096 0, 0, 0, 0, W, H); 1097 gdk_pixbuf_render_to_drawable(Pixbuf, DC.Drawable, DC.GC, 0, 0, X, Y, 1098 -1, -1, GDK_RGB_DITHER_NONE, 0, 0); 1099 gdk_pixbuf_unref(Pixbuf); 1100 end; 1101 1102 procedure PaintWidget(AWidget: PGtkWidget); 1103 var 1104 AWindow: PGdkWindow; 1105 begin 1106 if (AWinControl.FCompStyle = csForm) then 1107 PaintGtkForm(AWidget^.window) 1108 else 1109 begin 1110 AWindow := GetControlWindow(AWidget); 1111 if AWindow <> nil then 1112 PaintWindow(AWindow); 1113 end; 1114 end; 1115 1116begin 1117 if not WSCheckHandleAllocated(AWinControl, 'PaintTo') then 1118 Exit; 1119 PaintWidget(GetFixedWidget({%H-}PGtkWidget(AWinControl.Handle))); 1120end; 1121 1122class procedure TGtk2WSWinControl.Repaint(const AWinControl: TWinControl); 1123begin 1124 if not WSCheckHandleAllocated(AWinControl, 'Repaint') 1125 then Exit; 1126 gtk_widget_queue_draw({%H-}PGtkWidget(AWinControl.Handle)); 1127end; 1128 1129{ TGtk2WSBaseScrollingWinControl } 1130 1131function Gtk2WSBaseScrollingWinControl_HValueChanged(AAdjustment: PGTKAdjustment; AInfo: PWidgetInfo): GBoolean; cdecl; 1132var 1133 ScrollingData: PBaseScrollingWinControlData; 1134 Msg: TLMHScroll; 1135 OldValue, V, U, L, StepI, PageI: Integer; 1136 X, Y: GInt; 1137 Mask: TGdkModifierType; 1138begin 1139 Result := CallBackDefaultReturn; 1140 if AInfo^.ChangeLock > 0 then Exit; 1141 1142 ScrollingData := AInfo^.UserData; 1143 1144 // round values 1145 V := Round(AAdjustment^.Value); 1146 U := Round(AAdjustment^.Upper); 1147 L := Round(AAdjustment^.Lower); 1148 StepI := Round(AAdjustment^.Step_Increment); 1149 PageI := Round(AAdjustment^.Page_Increment); 1150 1151 OldValue := ScrollingData^.HValue; 1152 ScrollingData^.HValue := V; 1153 1154 // get keystates 1155 Mask := 0; 1156 if ScrollingData^.HScroll <> nil then 1157 begin 1158 {$IFDEF UseGDKErrorTrap} 1159 BeginGDKErrorTrap; 1160 {$ENDIF} 1161 gdk_window_get_pointer(GetControlWindow(ScrollingData^.HScroll), @X, @Y, @Mask); 1162 {$IFDEF UseGDKErrorTrap} 1163 EndGDKErrorTrap; 1164 {$ENDIF} 1165 end; 1166 1167 Msg.msg := LM_HSCROLL; 1168 // get scrollcode 1169 if ssLeft in GTKEventStateToShiftState(Word(Mask)) 1170 then Msg.ScrollCode := SB_THUMBTRACK 1171 else if V <= L 1172 then Msg.ScrollCode := SB_TOP 1173 else if V >= U 1174 then Msg.ScrollCode := SB_BOTTOM 1175 else if V - OldValue = StepI 1176 then Msg.ScrollCode := SB_LINERIGHT 1177 else if OldValue - V = StepI 1178 then Msg.ScrollCode := SB_LINELEFT 1179 else if V - OldValue = PageI 1180 then Msg.ScrollCode := SB_PAGERIGHT 1181 else if OldValue - V = PageI 1182 then Msg.ScrollCode := SB_PAGELEFT 1183 else Msg.ScrollCode := SB_THUMBPOSITION; 1184 Msg.Pos := V; 1185 if V < High(Msg.SmallPos) 1186 then Msg.SmallPos := V 1187 else Msg.SmallPos := High(Msg.SmallPos); 1188 Msg.ScrollBar := HWND({%H-}PtrUInt(ScrollingData^.HScroll)); 1189 1190 Result := (DeliverMessage(AInfo^.LCLObject, Msg) <> 0) xor CallBackDefaultReturn; 1191end; 1192 1193function Gtk2WSBaseScrollingWinControl_VValueChanged(AAdjustment: PGTKAdjustment; AInfo: PWidgetInfo): GBoolean; cdecl; 1194var 1195 ScrollingData: PBaseScrollingWinControlData; 1196 Msg: TLMHScroll; 1197 OldValue, V, U, L, StepI, PageI: Integer; 1198 X, Y: GInt; 1199 Mask: TGdkModifierType; 1200begin 1201 Result := CallBackDefaultReturn; 1202 if AInfo^.ChangeLock > 0 then Exit; 1203 1204 ScrollingData := AInfo^.UserData; 1205 1206 // round values 1207 V := Round(AAdjustment^.Value); 1208 U := Round(AAdjustment^.Upper); 1209 L := Round(AAdjustment^.Lower); 1210 StepI := Round(AAdjustment^.Step_Increment); 1211 PageI := Round(AAdjustment^.Page_Increment); 1212 1213 OldValue := ScrollingData^.VValue; 1214 ScrollingData^.VValue := V; 1215 1216 // get keystates 1217 Mask := 0; 1218 if ScrollingData^.VScroll <> nil then 1219 begin 1220 {$IFDEF UseGDKErrorTrap} 1221 BeginGDKErrorTrap; 1222 {$ENDIF} 1223 gdk_window_get_pointer(GetControlWindow(ScrollingData^.VScroll), @X, @Y, @Mask); 1224 {$IFDEF UseGDKErrorTrap} 1225 EndGDKErrorTrap; 1226 {$ENDIF} 1227 end; 1228 1229 Msg.msg := LM_VSCROLL; 1230 // Get scrollcode 1231 if ssLeft in GTKEventStateToShiftState(Word(Mask)) 1232 then Msg.ScrollCode := SB_THUMBTRACK 1233 else if V <= L 1234 then Msg.ScrollCode := SB_TOP 1235 else if V >= U 1236 then Msg.ScrollCode := SB_BOTTOM 1237 else if V - OldValue = StepI 1238 then Msg.ScrollCode := SB_LINEDOWN 1239 else if OldValue - V = StepI 1240 then Msg.ScrollCode := SB_LINEUP 1241 else if V - OldValue = PageI 1242 then Msg.ScrollCode := SB_PAGEDOWN 1243 else if OldValue - V = PageI 1244 then Msg.ScrollCode := SB_PAGEUP 1245 else Msg.ScrollCode := SB_THUMBPOSITION; 1246 Msg.Pos := V; 1247 if V < High(Msg.SmallPos) 1248 then Msg.SmallPos := V 1249 else Msg.SmallPos := High(Msg.SmallPos); 1250 Msg.ScrollBar := HWND({%H-}PtrUInt(ScrollingData^.HScroll)); 1251 1252 Result := (DeliverMessage(AInfo^.LCLObject, Msg) <> 0) xor CallBackDefaultReturn; 1253end; 1254 1255class function TGtk2WSBaseScrollingWinControl.CreateHandle( 1256 const AWinControl: TWinControl; const AParams: TCreateParams): HWND; 1257var 1258 Widget: PGtkWidget; 1259 WidgetInfo: PWidgetInfo; 1260 ScrollingData: PBaseScrollingWinControlData; 1261 Allocation: TGTKAllocation; 1262begin 1263 Widget := gtk_scrolled_window_new(nil, nil); 1264 {$IFDEF DebugLCLComponents} 1265 DebugGtkWidgets.MarkCreated(Widget,dbgsName(AWinControl)); 1266 {$ENDIF} 1267 1268 Result := THandle({%H-}PtrUInt(Widget)); 1269 if Result = 0 then Exit; 1270 1271 gtk_widget_show(Widget); 1272 1273 WidgetInfo := CreateWidgetInfo(Widget, AWinControl, AParams); 1274 New(ScrollingData); 1275 ScrollingData^.HValue := 0; 1276 ScrollingData^.VValue := 0; 1277 ScrollingData^.HScroll := PGtkScrolledWindow(Widget)^.HScrollbar; 1278 ScrollingData^.VScroll := PGtkScrolledWindow(Widget)^.VScrollbar; 1279 WidgetInfo^.UserData := ScrollingData; 1280 WidgetInfo^.DataOwner := True; 1281 1282 // set allocation 1283 Allocation.X := AParams.X; 1284 Allocation.Y := AParams.Y; 1285 Allocation.Width := AParams.Width; 1286 Allocation.Height := AParams.Height; 1287 gtk_widget_size_allocate(Widget, @Allocation); 1288 Set_RC_Name(AWinControl, Widget); 1289 1290 // SetCallbacks isn't called here, it should be done in the 'derived' class 1291end; 1292 1293class procedure TGtk2WSBaseScrollingWinControl.SetCallbacks( 1294 const AWidget: PGtkWidget; const AWidgetInfo: PWidgetInfo); 1295begin 1296 TGtk2WSWinControl.SetCallbacks(PGtkObject(AWidget), 1297 TComponent(AWidgetInfo^.LCLObject)); 1298 SignalConnect( 1299 PGtkWidget(GetWidgetHAdjustment(AWidget)), 1300 'value-changed', 1301 @Gtk2WSBaseScrollingWinControl_HValueChanged, 1302 AWidgetInfo 1303 ); 1304 SignalConnect( 1305 PGtkWidget(GetWidgetVAdjustment(AWidget)), 1306 'value-changed', 1307 @Gtk2WSBaseScrollingWinControl_VValueChanged, 1308 AWidgetInfo 1309 ); 1310end; 1311 1312 1313end. 1314