From 76147c8a4e2d711d04b9d8a0e71780b4763f4b5b Mon Sep 17 00:00:00 2001 From: zeljan1 Date: Wed, 5 Feb 2025 19:41:43 +0100 Subject: [PATCH] Gtk3: implemented LargeImages in TCustomListView.ViewStyle = vsIcon, fixed memleak. --- lcl/interfaces/gtk3/gtk3caret.pas | 2 +- lcl/interfaces/gtk3/gtk3widgets.pas | 25 ++++-- lcl/interfaces/gtk3/gtk3wscomctrls.pp | 125 ++++++++++++++++++-------- lcl/interfaces/gtk3/gtk3wsstdctrls.pp | 4 +- 4 files changed, 107 insertions(+), 49 deletions(-) diff --git a/lcl/interfaces/gtk3/gtk3caret.pas b/lcl/interfaces/gtk3/gtk3caret.pas index 5cb243ffc5..d102a4cc0b 100644 --- a/lcl/interfaces/gtk3/gtk3caret.pas +++ b/lcl/interfaces/gtk3/gtk3caret.pas @@ -77,7 +77,7 @@ begin ASettings := gtk_settings_get_default; - FillByte(AValue, SizeOf(AValue), 0); + FillByte(AValue{%H-}, SizeOf(AValue), 0); AValue.init(G_TYPE_INT); ASettings^.get_property('gtk-cursor-blink-time', @AValue); FBlinkInterval := (AValue.get_int div CURSOR_ON_MULTIPLIER); diff --git a/lcl/interfaces/gtk3/gtk3widgets.pas b/lcl/interfaces/gtk3/gtk3widgets.pas index 2696224f54..3dff5eefec 100644 --- a/lcl/interfaces/gtk3/gtk3widgets.pas +++ b/lcl/interfaces/gtk3/gtk3widgets.pas @@ -6987,7 +6987,7 @@ begin begin for i := FImages.Count - 1 downto 0 do if FImages[i] <> nil then - TGtk3Object(FImages[i]).Free; + g_object_unref(FImages[i]); FImages.Clear; end; end; @@ -7356,14 +7356,18 @@ begin gtk_icon_size_lookup(Ord(GTK_ICON_SIZE_LARGE_TOOLBAR), @w, @h); bmp.SetSize(w, h); end; - pxb:=TGtk3Image(bmp.Handle).Handle; + pxb:=TGtk3Image(bmp.Handle).Handle^.copy; gtk_list_store_insert_with_values(PGtkListStore(AModel), @Iter, NewIndex, [0, Pointer(AItem), 1, PChar(AItem.Caption), 2, pxb, -1] ); + // list_store takes ownership, so unref and ref again. + g_object_unref(pxb); if not Assigned(FImages) then FImages := TFPList.Create; - fImages.Add(bmp); + g_object_ref(pxb); + FImages.Add(pxb); + bmp.Free; end; end; @@ -7403,21 +7407,26 @@ begin AModel:=PGtkIconView(GetContainerWidget)^.get_model; AModel^.get_iter(@iter,path); - bmp:=TBitmap.Create; - if Assigned(TListView(LCLObject).LargeImages) then - TListView(LCLObject).LargeImages.GetBitmap(AItem.ImageIndex,bmp) + bmp := TBitmap.Create; + if Assigned(TCustomListViewHack(LCLObject).LargeImages) then + TCustomListViewHack(LCLObject).LargeImages.GetBitmap(AItem.ImageIndex, bmp) else begin gtk_icon_size_lookup(Ord(GTK_ICON_SIZE_LARGE_TOOLBAR), @w, @h); bmp.SetSize(w, h); end; - pxb:=TGtk3Image(bmp.Handle).Handle; + pxb := TGtk3Image(Bmp.Handle).Handle^.copy; gtk_list_store_set(PGtkListStore(AModel), @Iter, [0, Pointer(AItem), 1, PChar(AItem.Caption), 2, pxb, -1] ); - fImages.Add(bmp); + g_object_unref(pxb); + if not Assigned(FImages) then + FImages := TFPList.Create; + g_object_ref(pxb); + FImages.Add(pxb); gtk_tree_path_free(Path); + bmp.Free; end; end; diff --git a/lcl/interfaces/gtk3/gtk3wscomctrls.pp b/lcl/interfaces/gtk3/gtk3wscomctrls.pp index 67d5d419e2..ac7e28c686 100644 --- a/lcl/interfaces/gtk3/gtk3wscomctrls.pp +++ b/lcl/interfaces/gtk3/gtk3wscomctrls.pp @@ -24,15 +24,15 @@ uses // libs LazGtk3, LazGdk3, LazGlib2, LazGObject2, LazGdkPixbuf2, // RTL, FCL - Types, Classes, Math, Sysutils, ctypes, + Types, Classes, Math, Sysutils, // LCL - LCLType, LMessages, Controls, Graphics, StdCtrls, ComCtrls, Forms, + LCLType, Controls, Graphics, StdCtrls, ComCtrls, Forms, ImgList, InterfaceBase, // LazUtils LazLogger, // widgetset WSComCtrls, WSLCLClasses, WSControls, WSProc, - Gtk3WSControls, Gtk3Int, gtk3widgets; + gtk3widgets; type { TGtk3WSCustomPage } @@ -449,15 +449,17 @@ var PixbufValue: TGValue; begin PixbufValue:=Default(TGValue); - g_value_init(@PixbufValue, gdk_pixbuf_get_type); + g_value_init(@PixbufValue, gdk_pixbuf_get_type()); g_object_set_property(PgObject(cell), PChar('pixbuf'), @PixbufValue); - g_value_unset(@PixbufValue); gtk_tree_model_get(tree_model, iter, [0, @ListItem, -1]); ListColumn := TListColumn(g_object_get_data(PGObject(tree_column), 'TListColumn')); if ListColumn = nil then + begin + g_value_unset(@PixbufValue); Exit; + end; ColumnIndex := ListColumn.Index; ImageList := nil; Images := TGtk3ListView(aData).Images; @@ -465,6 +467,7 @@ begin ImageList := TLVHack(TGtk3ListView(aData).LCLObject).SmallImages; if (Images = nil) and (ImageList = nil) then begin + g_value_unset(@PixbufValue); Exit; end; ImageIndex := -1; @@ -477,7 +480,10 @@ begin end; if ListItem = nil then + begin + g_value_unset(@PixbufValue); Exit; + end; if ColumnIndex = 0 then ImageIndex := ListItem.ImageIndex @@ -492,19 +498,27 @@ begin try pixbuf := nil; ImageList.GetBitmap(ImageIndex, Bmp); - pixbuf := TGtk3Image(Bmp.Handle).Handle; - g_value_init(@PixbufValue, gdk_pixbuf_get_type); - g_value_set_object(@PixbufValue, pixbuf); - g_object_set_property(PGObject(cell), PChar('pixbuf'), @PixbufValue); - g_value_unset(@PixbufValue); + pixbuf := TGtk3Image(Bmp.Handle).Handle^.copy; + if pixbuf <> nil then + begin + g_value_unset(@PixbufValue); + g_value_init(@PixbufValue, gdk_pixbuf_get_type()); + g_value_set_object(@PixbufValue, pixbuf); + g_object_set_property(PGObject(cell), PChar('pixbuf'), @PixbufValue); + end; finally Bmp.Free; end; - end else - g_value_init(@PixbufValue, gdk_pixbuf_get_type); + end; if (ImageIndex > -1) and (ImageIndex <= Images.Count-1) and (Images.Items[ImageIndex] <> nil) then - g_value_set_object(@PixbufValue, PGdkPixbuf(Images.Items[ImageIndex])); - g_object_set_property(PGObject(cell), PChar('pixbuf'), @PixbufValue); + begin + Pixbuf := PGdkPixbuf(Images.Items[ImageIndex]); + if Assigned(pixBuf) then + begin + g_value_set_object(@PixbufValue, pixbuf); + g_object_set_property(PGObject(cell), PChar('pixbuf'), @PixbufValue); + end; + end; g_value_unset(@PixbufValue); end; @@ -653,6 +667,10 @@ begin begin // TODO: implement ??? end; + lvpToolTips: + begin + // TODO: + end; else DebugLn(Format('WARNING: TGtk3WSCustomListView.SetPropertyInternal property %d not handled.',[Ord(AProp)])); end; @@ -1026,9 +1044,14 @@ end; class function TGtk3WSCustomListView.GetViewOrigin(const ALV: TCustomListView ): TPoint; begin - DebugLn('TGtk3WSCustomListView.GetViewOrigin '); + // DebugLn('TGtk3WSCustomListView.GetViewOrigin '); + Result := Point(0, 0); - // Result:=inherited GetViewOrigin(ALV); + if ALV.HandleAllocated then + begin + Result := Point(Round(TGtk3ListView(ALV.Handle).getHorizontalScrollbar^.get_value), + Round(TGtk3ListView(ALV.Handle).getVerticalScrollbar^.get_value)); + end; end; class function TGtk3WSCustomListView.GetVisibleRowCount( @@ -1073,36 +1096,62 @@ end; class procedure TGtk3WSCustomListView.SetImageList(const ALV: TCustomListView; const AList: TListViewImageList; const AValue: TCustomImageListResolution); var - AView: TGtk3ListView; + BitImage: TBitmap; + pixbuf: PGDKPixBuf; i: Integer; - Bmp: TBitmap; + pixrenderer: PGtkCellRenderer; + AColumn: PGtkTreeViewColumn; begin if not WSCheckHandleAllocated(ALV, 'SetImageList') then exit; - DebugLn('TGtk3WSCustomListView.SetImageList '); - AView := TGtk3ListView(ALV.Handle); - // inherited SetImageList(ALV, AList, AValue); - if ((AList = lvilLarge) and not AView.IsTreeView) or - ((AList = lvilSmall) and AView.IsTreeView) then + + TGtk3ListView(ALV.Handle).GetContainerWidget^.realize; + TGtk3ListView(ALV.Handle).GetContainerWidget^.queue_draw; + + if ((AList = lvilLarge) and (TLVHack(ALV).ViewStyle = vsIcon)) or + ((AList = lvilSmall) and (TLVHack(ALV).ViewStyle <> vsIcon)) then begin - if Assigned(AView.Images) then - AView.ClearImages - else - AView.Images := TFPList.Create; - if Assigned(AValue) then + if TGtk3ListView(ALV.Handle).Images <> nil then + TGtk3ListView(ALV.Handle).ClearImages; + if AValue = nil then + exit; + + if TGtk3ListView(ALV.Handle).Images = nil then + TGtk3ListView(ALV.Handle).Images := TFPList.Create; + + if (AValue.Count = 0) and TGtk3ListView(ALV.Handle).IsTreeView and (TLVHack(ALV).Columns.Count > 0) and + not TLVHack(ALV).OwnerDraw then begin - for i := 0 to AValue.Count - 1 do - begin - Bmp := TBitmap.Create; - AValue.GetBitmap(i, Bmp); - AView.Images.Add(Bmp); - end; + AColumn := PGtkTreeView(TGtk3ListView(ALV.Handle).GetContainerWidget)^.get_column(0); + PixRenderer := PGtkCellRenderer(g_object_get_data(PgObject(AColumn), 'pix_renderer')); + PixRenderer^.set_fixed_size(AValue.Width + 2, AValue.Height + 2); + AColumn^.queue_resize; end; - if AView.IsTreeView then - AView.UpdateImageCellsSize; + for i := 0 to AValue.Count-1 do + begin + pixbuf := nil; + BitImage := TBitmap.Create; + try + AValue.GetBitmap(i, BitImage); + pixbuf := TGtk3Image(BitImage.Handle).Handle^.copy; - AView.Update(nil); + if TGtk3ListView(ALV.Handle).IsTreeView and (TLVHack(ALV).Columns.Count > 0) and + not TLVHack(ALV).OwnerDraw then + begin + AColumn := PGtkTreeView(TGtk3ListView(ALV.Handle).GetContainerWidget)^.get_column(0); + PixRenderer := PGtkCellRenderer(g_object_get_data(PgObject(AColumn), 'pix_renderer')); + if Assigned(PixRenderer) then + begin + PixRenderer^.set_fixed_size(AValue.Width + 2, AValue.Height + 2); + AColumn^.queue_resize; + end; + end; + TGtk3ListView(ALV.Handle).Images.Add(pixbuf); + finally + BitImage.Free; + end; + end; end; end; @@ -1177,7 +1226,7 @@ class procedure TGtk3WSCustomListView.SetViewStyle(const ALV: TCustomListView; begin if not WSCheckHandleAllocated(ALV, 'SetViewStyle') then Exit; - DebugLn('TGtk3WSCustomListView.SetViewStyle '); + // DebugLn('TGtk3WSCustomListView.SetViewStyle '); RecreateWnd(ALV); // inherited SetViewStyle(ALV, AValue); end; diff --git a/lcl/interfaces/gtk3/gtk3wsstdctrls.pp b/lcl/interfaces/gtk3/gtk3wsstdctrls.pp index f270ec8d48..a7af4f2f3b 100644 --- a/lcl/interfaces/gtk3/gtk3wsstdctrls.pp +++ b/lcl/interfaces/gtk3/gtk3wsstdctrls.pp @@ -40,8 +40,8 @@ uses //////////////////////////////////////////////////// Graphics, Controls, StdCtrls, LCLType, LCLProc, //////////////////////////////////////////////////// - WSLCLClasses, WSControls, WSStdCtrls, WSProc, Classes, WSFactory, Clipbrd, - gtk3widgets, gtk3procs, LazGdk3; + WSLCLClasses, WSControls, WSStdCtrls, WSProc, Classes, Clipbrd, + gtk3widgets, gtk3procs; type { TGtk3WSScrollBar }