Recent

Author Topic: How to get xlib's window icon using BGRABitmap?  (Read 1511 times)

AFFRIZA 亜風実

  • Full Member
  • ***
  • Posts: 144
How to get xlib's window icon using BGRABitmap?
« on: June 14, 2022, 12:27:59 pm »
So, long story short, I'm interested to make my own docked taskbar for KDE :-[

I tried to C++ mimic code from here to read the icon: https://stackoverflow.com/questions/55413341/get-applications-icon-using-xlib

and the result is like this:
Code: Pascal  [Select][+][-]
  1. function ReadBitmap(Val: PByte; W, H, Size: integer): TBGRABitmap;
  2. var
  3.   bmp: TBGRABitmap;
  4.   a, r, g, b: byte;
  5.   argb: PByte;
  6.   x, y: Integer;
  7. begin
  8.   bmp := TBGRABitmap.Create(w, h);
  9.   argb := Val;
  10.   for y := 0 to H -1 do
  11.   begin
  12.     for x := 0 to W -1 do
  13.     begin
  14.       a := argb[3];
  15.       r := argb[2] * a div 255;
  16.       g := argb[1] * a div 255;
  17.       b := argb[0] * a div 255;
  18.       //bmp.Canvas.DrawPixel(x, y, FPImage.FPColor(r, g, b, a));
  19.       bmp.DrawPixel(x, y, BGRA(r, g, b, a));
  20.  
  21.       Inc(argb, 4);
  22.     end;
  23.   end;
  24.  
  25.   Result := bmp;
  26. end;
  27.  
  28. function TWindowData.GetIcon: TBGRABitmap;
  29. var
  30.   ActualTypeReturn: TAtom;
  31.   ActualFormatReturn: LongInt;
  32.   NItemsReturn, BytesAfterReturn: Cardinal;
  33.   Ptr: PByte;
  34.   IconAtom: TAtom;
  35.   PropResult: boolean;
  36.   i: integer;
  37.   Width, Height, Size: Cardinal;
  38. begin
  39.   Width := 0;
  40.   Height := 0;
  41.   IconAtom := XInternAtom(fXWindowList.Display, '_NET_WM_ICON', LongBool(1));
  42.  
  43.   PropResult := XGetWindowProperty(fXWindowList.Display, fWindow, IconAtom,
  44.     0, 1, 0, AnyPropertyType, @ActualTypeReturn, @ActualFormatReturn,
  45.     @NItemsReturn, @BytesAfterReturn, @Ptr) = Success;
  46.   if PropResult then
  47.     Width := PCardinal(Ptr)^;
  48.   if Assigned(Ptr) then XFree(Ptr);
  49.  
  50.   PropResult := XGetWindowProperty(fXWindowList.Display, fWindow, IconAtom,
  51.     1, 1, 0, AnyPropertyType, @ActualTypeReturn, @ActualFormatReturn,
  52.     @NItemsReturn, @BytesAfterReturn, @Ptr) = Success;
  53.   if PropResult then
  54.     Height := PCardinal(Ptr)^;
  55.   Size := Width * Height;
  56.   if Assigned(Ptr) then XFree(Ptr);
  57.  
  58.   PropResult := XGetWindowProperty(fXWindowList.Display, fWindow, IconAtom,
  59.     2, Size, 0, AnyPropertyType, @ActualTypeReturn, @ActualFormatReturn,
  60.     @NItemsReturn, @BytesAfterReturn, @Ptr) = Success;
  61.  
  62.   if PropResult then
  63.   begin
  64.     Result := ReadBitmap(Ptr, Width, Height, Size);
  65.   end;
  66.   if Assigned(Ptr) then XFree(Ptr);
  67. end;
  68.  

The icons is kind of broken in the result (in the attachment). Maybe someone can help?  :D

I really want to attach the full source but it's become big, so I put that in a Github:
https://github.com/kirana-a2district/samarinda-dock
https://github.com/kirana-a2district/kiranacore-pkg
Kyoukai Framework: https://github.com/afuriza/kyoukai_framework

Dukung kemerdekaan Donetsk dan Lugansk! Tidak membalas profil berbendera biru-kuning apalagi ber-Bandera.

AFFRIZA 亜風実

  • Full Member
  • ***
  • Posts: 144
Re: How to get xlib's window icon using BGRABitmap?
« Reply #1 on: June 14, 2022, 03:23:22 pm »
I just modified the code to:
Code: Pascal  [Select][+][-]
  1. function ReadBitmap(Val: PByte; W, H, Size: integer): TBGRABitmap;
  2. var
  3.   bmp: TBGRABitmap;
  4.   a, r, g, b: byte;
  5.   argb: PByte;
  6.   i, f, x, y: Integer;
  7.   imgBuffer: TBytes;
  8. begin
  9.   bmp := TBGRABitmap.Create(w, h);
  10.   SetLength(imgBuffer, Length(TBytes(Val)) div 2);
  11.   argb := PByte(imgBuffer);
  12.   i := 0;
  13.   while i < Length(TBytes(Val)) div 2 do
  14.   begin
  15.     argb[i] := Val[(i*2)];
  16.     argb[i+1] := Val[(i*2)+1];
  17.     argb[i+2] := Val[(i*2)+2];
  18.     argb[i+3] := Val[(i*2)+3];
  19.     i += 4;
  20.   end;
  21.   for y := 0 to H -1 do
  22.   begin
  23.     for x := 0 to W -1 do
  24.     begin
  25.       a := argb[3];
  26.       r := argb[2];
  27.       g := argb[1];
  28.       b := argb[0];
  29.       //bmp.Canvas.DrawPixel(x, y, FPImage.FPColor(r, g, b, a));
  30.       bmp.DrawPixel(x, y, BGRA(r, g, b, a));
  31.  
  32.       Inc(argb, 4);
  33.     end;
  34.   end;
  35.  
  36.   Result := bmp;
  37. end;
  38.  

The colors is much better now  :D
But the icons are still has distortion thingy  %)
Kyoukai Framework: https://github.com/afuriza/kyoukai_framework

Dukung kemerdekaan Donetsk dan Lugansk! Tidak membalas profil berbendera biru-kuning apalagi ber-Bandera.

Roland57

  • Sr. Member
  • ****
  • Posts: 423
    • msegui.net
Re: How to get xlib's window icon using BGRABitmap?
« Reply #2 on: June 14, 2022, 05:44:19 pm »
Hello! Very interesting stuff.

Unfortunately, I get an access violation at application start. (I had to remove the reference to qt5 unit. My Lazarus is gtk2.)
My projects are on Gitlab and on Codeberg.

AFFRIZA 亜風実

  • Full Member
  • ***
  • Posts: 144
Re: How to get xlib's window icon using BGRABitmap?
« Reply #3 on: June 14, 2022, 06:01:30 pm »
Hello! Very interesting stuff.

Unfortunately, I get an access violation at application start. (I had to remove the reference to qt5 unit. My Lazarus is gtk2.)
Sorry but it supposed to run under Qt5, since I wrote this for KDE, and also... I need the Qt5's translucent window thing to make the form transparent without affecting the components inside.

If you want, maybe I can help you to setup the Lazarus to run with Qt5.  :D
Kyoukai Framework: https://github.com/afuriza/kyoukai_framework

Dukung kemerdekaan Donetsk dan Lugansk! Tidak membalas profil berbendera biru-kuning apalagi ber-Bandera.

circular

  • Hero Member
  • *****
  • Posts: 4221
    • Personal webpage
Re: How to get xlib's window icon using BGRABitmap?
« Reply #4 on: June 15, 2022, 01:30:17 am »
Ok so each pixel is represented by 8 bytes. Well 4 bytes padded with 4 more bytes if the CPU is 64bits.

First version was almost correct except step between values.

I suppose the following would work as well:

Code: Pascal  [Select][+][-]
  1. function ReadBitmap(Val: PByte; W, H, Size: integer): TBGRABitmap;
  2. var
  3.   bmp: TBGRABitmap;
  4.   argb: PByte;
  5.   pdest: PBGRAPixel;
  6.   x, y: Integer;
  7. begin
  8.   bmp := TBGRABitmap.Create(w, h);
  9.   argb := Val;
  10.   for y := 0 to H -1 do
  11.   begin
  12.     pdest := bmp.ScanLine[y];
  13.     for x := 0 to W -1 do
  14.     begin
  15.       pdest^.alpha := argb[3];
  16.       pdest^.red := argb[2];
  17.       pdest^.green := argb[1];
  18.       pdest^.blue := argb[0];
  19.       Inc(argb, {$IFDEF CPU64}8{$ELSE}4{$ENDIF});
  20.       inc(pdest);
  21.     end;
  22.   end;
  23.   bmp.InvalidateBitmap;
  24.   Result := bmp;
  25. end;

I am not sure about the distortion but maybe you can assume that alpha is in fact 255 when alpha is zero and red/green/blue are non zero.
Conscience is the debugger of the mind

Fred vS

  • Hero Member
  • *****
  • Posts: 3168
    • StrumPract is the musicians best friend
Re: How to get xlib's window icon using BGRABitmap?
« Reply #5 on: June 15, 2022, 04:09:43 am »
I need the Qt5's translucent window thing to make the form transparent without affecting the components inside.

You may use a custom shape of form for this (available for all LCL included GTK2).
I use Lazarus 2.2.0 32/64 and FPC 3.2.2 32/64 on Debian 11 64 bit, Windows 10, Windows 7 32/64, Windows XP 32,  FreeBSD 64.
Widgetset: fpGUI, MSEgui, Win32, GTK2, Qt.

https://github.com/fredvs
https://gitlab.com/fredvs
https://codeberg.org/fredvs

AFFRIZA 亜風実

  • Full Member
  • ***
  • Posts: 144
Re: How to get xlib's window icon using BGRABitmap?
« Reply #6 on: June 15, 2022, 07:27:01 am »
Ok so each pixel is represented by 8 bytes. Well 4 bytes padded with 4 more bytes if the CPU is 64bits.

First version was almost correct except step between values.

I suppose the following would work as well:

Code: Pascal  [Select][+][-]
  1. function ReadBitmap(Val: PByte; W, H, Size: integer): TBGRABitmap;
  2. var
  3.   bmp: TBGRABitmap;
  4.   argb: PByte;
  5.   pdest: PBGRAPixel;
  6.   x, y: Integer;
  7. begin
  8.   bmp := TBGRABitmap.Create(w, h);
  9.   argb := Val;
  10.   for y := 0 to H -1 do
  11.   begin
  12.     pdest := bmp.ScanLine[y];
  13.     for x := 0 to W -1 do
  14.     begin
  15.       pdest^.alpha := argb[3];
  16.       pdest^.red := argb[2];
  17.       pdest^.green := argb[1];
  18.       pdest^.blue := argb[0];
  19.       Inc(argb, {$IFDEF CPU64}8{$ELSE}4{$ENDIF});
  20.       inc(pdest);
  21.     end;
  22.   end;
  23.   bmp.InvalidateBitmap;
  24.   Result := bmp;
  25. end;

I am not sure about the distortion but maybe you can assume that alpha is in fact 255 when alpha is zero and red/green/blue are non zero.
Wow, that scanline method is way more simpler. Thankyou.  :D

But the distortion is still there. I'm not sure about the alpha. But, when I didn't touched the alpha, there's still some lines or rows of pixels are missing that make the icons distorted. Is the image is compressed or something?

Anyway, this is the file that I've dumped from the PByte (not a text file, it's directly from TFileStream from PByte).
edit: I forgot to mention to height and width is 32x32.


You may use a custom shape of form for this (available for all LCL included GTK2).
Thanks, I'll check that later  ;)
« Last Edit: June 15, 2022, 10:09:41 am by Dio Affriza »
Kyoukai Framework: https://github.com/afuriza/kyoukai_framework

Dukung kemerdekaan Donetsk dan Lugansk! Tidak membalas profil berbendera biru-kuning apalagi ber-Bandera.

circular

  • Hero Member
  • *****
  • Posts: 4221
    • Personal webpage
Re: How to get xlib's window icon using BGRABitmap?
« Reply #7 on: June 15, 2022, 08:19:16 am »
Hmmm ok.

Maybe you can dump the data to see what it looks like.
Conscience is the debugger of the mind

AFFRIZA 亜風実

  • Full Member
  • ***
  • Posts: 144
Re: How to get xlib's window icon using BGRABitmap?
« Reply #8 on: June 15, 2022, 10:16:32 am »
Hmmm ok.

Maybe you can dump the data to see what it looks like.
Here's I dumped all images and make a project to load one of. The width and height in the file name but the pixels is more destroyed than accessed directly.

I dumped by adding
Code: Pascal  [Select][+][-]
  1.   ms := TMemoryStream.Create;
  2.   try
  3.     ms.Position := 0;
  4.  
  5.     ms.WriteBuffer(Val, Size);
  6.     ms.SaveToFile(ExtractFilePath(ParamStr(0)) + 'dumpedimages/w'+Width.ToString+'h'+Height.ToString+'_'+fWindowPID.ToString);
  7.   finally
  8.     ms.Free;
  9.   end;
  10.  
« Last Edit: June 15, 2022, 10:45:54 am by Dio Affriza »
Kyoukai Framework: https://github.com/afuriza/kyoukai_framework

Dukung kemerdekaan Donetsk dan Lugansk! Tidak membalas profil berbendera biru-kuning apalagi ber-Bandera.

AFFRIZA 亜風実

  • Full Member
  • ***
  • Posts: 144
Re: How to get xlib's window icon using BGRABitmap?
« Reply #9 on: June 15, 2022, 05:40:40 pm »
I think the problem is in the code how I show the TBGRABitmap, not the xlib. I think this is wrong, I should not use assign.  %)
Code: Pascal  [Select][+][-]
  1. DockButton: TBCButton;
  2. .....
  3. bmp := GetIcon;
  4. DockButton.Glyph.Assign(bmp);
  5.  

Edit:
NO, I think that's correct, I just didn't use bmp.Bitmap. After I read this https://forum.lazarus.freepascal.org/index.php?topic=54282.0, now it works. It works!  :D

Thankyou everybody.  O:-)
« Last Edit: June 15, 2022, 05:45:33 pm by Dio Affriza »
Kyoukai Framework: https://github.com/afuriza/kyoukai_framework

Dukung kemerdekaan Donetsk dan Lugansk! Tidak membalas profil berbendera biru-kuning apalagi ber-Bandera.

AFFRIZA 亜風実

  • Full Member
  • ***
  • Posts: 144
Re: How to get xlib's window icon using BGRABitmap?
« Reply #10 on: June 15, 2022, 08:14:12 pm »
Hello! Very interesting stuff.

Unfortunately, I get an access violation at application start. (I had to remove the reference to qt5 unit. My Lazarus is gtk2.)
Hello, Roland. I've updated the example here so you don't need to deal with QT5 things https://github.com/kirana-a2district/kiranacore-pkg/tree/main/examples/form-test
Kyoukai Framework: https://github.com/afuriza/kyoukai_framework

Dukung kemerdekaan Donetsk dan Lugansk! Tidak membalas profil berbendera biru-kuning apalagi ber-Bandera.

Roland57

  • Sr. Member
  • ****
  • Posts: 423
    • msegui.net
Re: How to get xlib's window icon using BGRABitmap?
« Reply #11 on: June 15, 2022, 11:25:55 pm »
Hello, Roland. I've updated the example here so you don't need to deal with QT5 things https://github.com/kirana-a2district/kiranacore-pkg/tree/main/examples/form-test

Thanks! Could compile and run it successfully.
My projects are on Gitlab and on Codeberg.

circular

  • Hero Member
  • *****
  • Posts: 4221
    • Personal webpage
Re: How to get xlib's window icon using BGRABitmap?
« Reply #12 on: June 16, 2022, 07:09:49 am »
After I read this https://forum.lazarus.freepascal.org/index.php?topic=54282.0, now it works. It works!  :D

Thankyou everybody.  O:-)
Congrats  :)
Conscience is the debugger of the mind

Roland57

  • Sr. Member
  • ****
  • Posts: 423
    • msegui.net
Re: How to get xlib's window icon using BGRABitmap?
« Reply #13 on: June 16, 2022, 11:41:13 am »
I took a closer look at your project. Very interesting, once again! I can't wait to see the sequel.  :)

I spent some time collecting all the code examples related to X11/Xlib that I could find. I'm adding your project to my collection.  :)
My projects are on Gitlab and on Codeberg.

AFFRIZA 亜風実

  • Full Member
  • ***
  • Posts: 144
Re: How to get xlib's window icon using BGRABitmap?
« Reply #14 on: June 16, 2022, 04:35:58 pm »
I took a closer look at your project. Very interesting, once again! I can't wait to see the sequel.  :)

I spent some time collecting all the code examples related to X11/Xlib that I could find. I'm adding your project to my collection.  :)
Thanks! I hope I can make this docked taskbar functional at the end of this year.  :D

Congrats  :)
Thank you.  ;)
Kyoukai Framework: https://github.com/afuriza/kyoukai_framework

Dukung kemerdekaan Donetsk dan Lugansk! Tidak membalas profil berbendera biru-kuning apalagi ber-Bandera.

 

TinyPortal © 2005-2018