View Issue Details

IDProjectCategoryView StatusLast Update
0027469LazarusLCLpublic2015-02-15 17:12
Reportertheo Assigned ToZeljan Rikalo  
PrioritynormalSeverityminorReproducibilityalways
Status closedResolutionfixed 
Product Version1.3 (SVN) 
Summary0027469: TImageList not working "on demand" on GTK2
DescriptionPlease see the attached demo project.
Click "Add Items".
The imagelist is initially empty. Images are added in a ListView.OnData event.
This Works on Win32 and Qt but not on GtK2. The images are not visible.

If you check the "Workaround" CB and "Add Items" again, images appear on GTK2.
Still works fine on Windows but SIGSEGVs on Qt.
Additional InformationLazarus 1.5 r47736M FPC 3.1.1 x86_64-linux-gtk 2
GTK 2.24.25-4.4.1
TagsNo tags attached.
Fixed in Revision47805
LazTarget-
WidgetsetGTK 2
Attached Files

Activities

theo

2015-02-14 16:09

reporter  

onthefly.zip (4,596 bytes)

Zeljan Rikalo

2015-02-14 22:54

developer   ~0081078

Qt segfault fixed in r47790

Zeljan Rikalo

2015-02-14 23:09

developer   ~0081080

hm..I don't see any way that this can work with gtk2.
in TGtk2WSCustomListView.SetImageList() gtk creates images which are drawn later (OwnerData).
Problem (for gtk2lcl) is that you change imagelist items in code later, and such changes does not send any notification to gtk2 that imagelist is changed.
That's why your "workaround" works. win32 and qt works totally different.
So, if TCustomListView can listen on TImageList.OnChange somehow and then call TWSCustomListView.SetImageList() on any change then it'll work.

theo

2015-02-14 23:35

reporter   ~0081082

Thank you Zeljan. I already thought that it has to do with how GTK2 works.
In my code, I have a workaround which is quite the same as your idea.
I'm using ImageList.OnChange and QueueAsyncCall to reduce updating like:

procedure TfrmMain.MILChange(Sender: TObject);
begin
  {$IFDEF LCLGTK2}
  if not fUpdatingImageList then
    begin
      fUpdatingImageList:=true;
    Application.QueueAsyncCall(@UpdateList,0);
    end;
  {$ENDIF}
end;

procedure TfrmMain.UpdateList(Data: PtrInt);
begin
  ListView1.SmallImages := nil;
  ListView1.SmallImages := MIL;
  fUpdatingImageList:=false;
end;


I have some other strange findings with ListView.OwnerData on Linux.

GTK2 calls OnData for _every_ Item initially even if not visible.
I think this is not the idea of a "virtual" view.

Qt calls OnData only for the visible Items, but never stops.
It calls OnData over and over again, which might use quite a lot of CPU time, depending on what you do in this event.

Shall I post a separate report for this?

Thanks

Zeljan Rikalo

2015-02-15 11:36

developer   ~0081091

Yes please. AFAIK qt is calling OnData on every paint event, maybe OnData triggers another paint event ? ... I've seen that last night while testing with this example. I can use this example to see what happens.

Zeljan Rikalo

2015-02-15 11:37

developer   ~0081092

Also, maybe (but just maybe), gtk2 can be fixed inside GtkCell paint function to ask imagelist bitmap and not FWidgets^.Images when OwnerData=True.

theo

2015-02-15 13:36

reporter   ~0081097

Last edited: 2015-02-15 14:00

View 3 revisions

Yes, you are right. I hacked this down for testing. It works.
GTK programming for me is a jungle.
So the following lines are not a patch, but only a proof of concept.
If you think it is the right way, you could probably improve/rewrite it.

gtk2wscustomlistview.inc, around line 429
(was: if (ImageIndex > -1) and (ImageIndex <= Images.Count-1) then ):

  if (WidgetInfo^.LCLObject) is TListView then
  begin
    if (ImageIndex > -1) and (ImageIndex <= TListView(WidgetInfo^.LCLObject).SmallImages.Count-1) then
    // if (ImageIndex > -1) and (ImageIndex <= Images.Count-1) then
    begin
      //PGtkCellRendererPixbuf(cell)^.pixbuf := PGdkPixbuf(Images.Items[ImageIndex]);
      BitImage:=TBitmap.create;;
      TListView(WidgetInfo^.LCLObject).SmallImages.GetBitmap(ImageIndex,BitImage);
      GDIObj := {%H-}PGDIObject(BitImage.Handle);
      case GDIObj^.GDIBitmapType of
        gbBitmap:
          begin
            bitmap := GDIObj^.GDIBitmapObject;
            gdk_drawable_get_size(bitmap, @Width, @Height);
            pixbuf := CreatePixbufFromDrawable(bitmap, nil, False, 0, 0, 0, 0, Width, Height);
          end;
        gbPixmap:
          begin
            pixmap := GDIObj^.GDIPixmapObject.Image;
            if pixmap <> nil then
            begin
              gdk_drawable_get_size(pixmap, @Width, @Height);
              bitmap := CreateGdkMaskBitmap(BitImage.Handle, 0);
              pixbuf := CreatePixbufFromImageAndMask(pixmap, 0, 0, Width, Height, nil, Bitmap);
            end;
          end;
        gbPixbuf:
          begin
            pixbuf := gdk_pixbuf_copy(GDIObj^.GDIPixbufObject);
          end;
      end;
     PGtkCellRendererPixbuf(cell)^.pixbuf :=pixbuf;
     bitimage.free;
    end
  end
  else
    PGtkCellRendererPixbuf(cell)^.pixbuf := nil;
end; //Gtk2WSLV_ListViewGetPixbufDataFuncForColumn

-------------------------------------------------------------------

var
....
  bitimage:TBitmap;
  GDIObj: PGDIObject;
  bitmap:PGdkBitmap;
  width, height:integer;
  pixbuf:PGdkPixbuf;
  pixmap: PGdkPixmap;

Zeljan Rikalo

2015-02-15 15:43

developer   ~0081101

More checks should be added there. eg. if SmallImages is assigned etc, but concept is ok. Try to write a patch.

Zeljan Rikalo

2015-02-15 16:01

developer   ~0081104

Please test and close if ok.

theo

2015-02-15 16:02

reporter   ~0081105

> More checks should be added there.

I didn't even bother to make any checks, because I don't really understand the whole thing.
What are we doing in ItemSetImage and SetImageList?
Why do you think we can safely bypass all that and copy TImageList.Bitmaps to the cell on the fly?
If we are caching images in Widgets^.Images (are we?), shouldn't we rather try to keep them in sync with the ImageList?

theo

2015-02-15 16:09

reporter   ~0081106

> Please test and close if ok.
Yes it works here, thank you! But I still don't understand... ;-)

Zeljan Rikalo

2015-02-15 16:51

developer   ~0081109

Widgets^.Images are used for normal TListView. They're setted up in SetImageList.
ItemSetImage is used when you change imageindex of an item in TListView, so then it changes item image. eg it sets icon on QTreeWidgetItem or QListWidgetItem.
You cannot compare win32 with others in this case. We are doing all stuff around VCL which is native for win32.

theo

2015-02-15 17:12

reporter   ~0081110

OK. Thank you Zeljko! Closing.

Issue History

Date Modified Username Field Change
2015-02-14 16:09 theo New Issue
2015-02-14 16:09 theo File Added: onthefly.zip
2015-02-14 22:32 Zeljan Rikalo Assigned To => Zeljan Rikalo
2015-02-14 22:32 Zeljan Rikalo Status new => assigned
2015-02-14 22:54 Zeljan Rikalo LazTarget => -
2015-02-14 22:54 Zeljan Rikalo Note Added: 0081078
2015-02-14 22:54 Zeljan Rikalo Status assigned => feedback
2015-02-14 23:09 Zeljan Rikalo Note Added: 0081080
2015-02-14 23:35 theo Note Added: 0081082
2015-02-14 23:35 theo Status feedback => assigned
2015-02-15 11:36 Zeljan Rikalo Note Added: 0081091
2015-02-15 11:37 Zeljan Rikalo Note Added: 0081092
2015-02-15 13:36 theo Note Added: 0081097
2015-02-15 13:38 theo Note Edited: 0081097 View Revisions
2015-02-15 14:00 theo Note Edited: 0081097 View Revisions
2015-02-15 15:43 Zeljan Rikalo Note Added: 0081101
2015-02-15 16:01 Zeljan Rikalo Fixed in Revision => 47805
2015-02-15 16:01 Zeljan Rikalo Note Added: 0081104
2015-02-15 16:01 Zeljan Rikalo Status assigned => resolved
2015-02-15 16:01 Zeljan Rikalo Resolution open => fixed
2015-02-15 16:02 theo Note Added: 0081105
2015-02-15 16:09 theo Note Added: 0081106
2015-02-15 16:51 Zeljan Rikalo Note Added: 0081109
2015-02-15 17:12 theo Note Added: 0081110
2015-02-15 17:12 theo Status resolved => closed