Recent

Author Topic: GTK3. Get Widget? Get XID?  (Read 659 times)

Seenkao

  • Hero Member
  • *****
  • Posts: 751
    • New ZenGL.
GTK3. Get Widget? Get XID?
« on: February 22, 2026, 12:59:58 am »
Hi all!
Linux.
Используя GTK3 как мне получить либо значение Widget (например формы или панели) или получить XID данного widget?
Есть функции в LazGTK3 - это "gtk_window_get_default_widget" или "get_default_widget", но они не возвращают значения Widget, хотя Handle задаётся правильно.
TGTK3Widget содержит функцию "GetContainerWidget", но как я понимаю, она предназначена не для возврата своего же значения.

Каким ещё образом можно получить XID (ну или хотя бы Widget) созданного окна?

------------------------------------
Google translate:
Linux.
Using GTK3, how can I get the value of a Widget (for example, a form or panel) or get the XID of a given widget?
There are functions in LazGTK3 - these are "gtk_window_get_default_widget" or "get_default_widget", but they do not return the Widget value, although the Handle is set correctly.
TGTK3Widget contains the "GetContainerWidget" function, but as far as I understand, it's not intended to return its own value.

How else can I get the XID (or at least the Widget) of a created window?

My code:
Code: Pascal  [Select][+][-]
  1. var
  2.   widget : PGtkWidget;
  3. ...
  4.       widget := gtk_window_get_default_widget( PGtkWindow( Panel1.Handle ) );
  5.       gtk_widget_realize( widget );
  6. ...

Errors:
Quote
gtk_window_get_default_widget: assertion 'GTK_IS_WINDOW (window)' failed
gtk_widget_realize: assertion 'GTK_IS_WIDGET (widget)' failed
« Last Edit: February 22, 2026, 01:18:54 am by Seenkao »
Rus: Стремлюсь к созданию минимальных и достаточно быстрых приложений.

Eng: I strive to create applications that are minimal and reasonably fast.
Working on ZenGL

zeljko

  • Hero Member
  • *****
  • Posts: 1905
    • http://wiki.lazarus.freepascal.org/User:Zeljan
Re: GTK3. Get Widget? Get XID?
« Reply #1 on: February 22, 2026, 09:32:22 am »
TGtk3Widget(Wincontrol.Handle).GetContainerWidget, if you want XID then search for GDK function which returns xid from PGtkWidget.

Seenkao

  • Hero Member
  • *****
  • Posts: 751
    • New ZenGL.
Re: GTK3. Get Widget? Get XID?
« Reply #2 on: February 22, 2026, 01:25:48 pm »
TGtk3Widget(Wincontrol.Handle).GetContainerWidget
Thanks! Works!

Quote
if you want XID then search for GDK function which returns xid from PGtkWidget.
Это не проблема. Она была решена ранее.

Google translate:
This is not a problem. It was resolved earlier.

Code: Pascal  [Select][+][-]
  1. unit demo18;
  2.  
  3. {$mode objfpc}{$H+}
  4. // RU: В данной демке свои файлы настроек "zglCustomConfig.cfg" и "zgl_config.cfg". В файле "zgl_config.cfg" включено определение "USE_INIT_HANDLE" для работы с LCL(VCL).
  5. // EN: This demo has its own settings files "zglCustomConfig.cfg" and "zgl_config.cfg". The "zgl_config.cfg" file includes a definition of "USE_INIT_HANDLE" to work with LCL(VCL).
  6. {$I zglCustomConfig.cfg}
  7. {$I zgl_config.cfg}
  8.  
  9. interface
  10.  
  11. // RU: обратите внимание!!!
  12. //     Проекты LCL имеют свои конфигурационные файлы "zgl_config.cfg". Лучше всего для каждого вашего проекта иметь свой
  13. //     конфигурационный файл, это может решить многие проблемы, если вдруг вы будете вносить изменения в конфигурацию проекта
  14. //     и, это отобразится на других ваших проектах использующих тот же конфигурационный файл.
  15. // EN: note!!!
  16. //     LCL projects have their own configuration files "zgl_config.cfg". It's best to have a separate config file for each of
  17. //     your projects, this can solve many problems if you suddenly make changes to the project config and it will show up on
  18. //     your other projects using the same config file.
  19.  
  20. uses
  21.   Classes,
  22.   SysUtils,
  23.   Forms,
  24.   Controls,
  25.   Graphics,
  26.   Dialogs,
  27.   ExtCtrls,
  28.  
  29. {$IFDEF LINUX}
  30.   {$IFDEF LCLGTK2}
  31.   GTK2, GDK2x, GTK2Proc,
  32.   {$ENDIF}
  33.   {$IfDef LCLGTK3}
  34.   Gtk3Widgets, LazGdk3, LazGtk3, x,
  35.   {$EndIf}
  36. {$ENDIF}
  37.  
  38.   {$IFDEF USE_ZENGL_STATIC}
  39.   zgl_application,
  40.   zgl_window,
  41.   zgl_screen,
  42.   zgl_render_2d,
  43.   zgl_joystick,
  44.   zgl_fx,
  45.   zgl_font,
  46.   zgl_text,
  47.   zgl_textures,
  48.  
  49.   zgl_collision_2d,
  50.   zgl_sprite_2d,
  51.   // sound
  52.   zgl_sound,
  53.   zgl_sound_wav,
  54.   zgl_sound_ogg,
  55.   zgl_utils,
  56.   {$ELSE}
  57.   zglHeader,
  58.   {$ENDIF}
  59.   zgl_types,
  60.   LCLType;
  61.  
  62. type
  63.  
  64.   { TForm1 }
  65.  
  66.   TForm1 = class(TForm)
  67.     Timer1: TTimer;
  68.     procedure FormActivate(Sender: TObject);
  69.     procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
  70.     procedure FormCreate(Sender: TObject);
  71.     procedure FormDeactivate(Sender: TObject);
  72.     procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
  73.     procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
  74.       Shift: TShiftState; X, Y: Integer);
  75.     procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
  76.     procedure Timer1Timer(Sender: TObject);
  77.   private
  78.  
  79.   public
  80.     mouseX, mouseY: Integer;
  81.   end;
  82.   {$IfDef LCLGTK3}
  83.   function gdk_x11_window_get_xid(window: PGdkWindow): TXID; cdecl; external LazGtk3_library name 'gdk_x11_window_get_xid';
  84.   {$EndIf}
  85.  
  86. var
  87.   Form1: TForm1;
  88.  
  89. //-----------------------------------------
  90.   dirRes    : UTF8String {$IFNDEF MACOSX} = '../data/' {$ENDIF};
  91.  
  92.   fntMain   : Integer;
  93.   MyIcon    : array[ 0..1 ] of Cardinal;
  94.   sound, audio   : zglPSound;
  95.   audioPlay : Boolean = false;
  96.   state     : Integer;
  97.  
  98.   text      : UTF8String;
  99.   textX     : Single;
  100.   textY     : Single;
  101.   r         : zglTRect2D;
  102.   p         : Integer;
  103.   r1, r2    : zglTRect2D;
  104.  
  105.   // добавляем номер звука, пока для одного звука
  106.   IDSound: array[0..1] of Integer;
  107.  
  108.   joyCount   : Integer;
  109.   // для возможности изменения экрана
  110.   ScreenWidth : integer = 800;
  111.   ScreenHeight : integer = 600;
  112.  
  113. //------------------------------------------
  114.  
  115. implementation
  116.  
  117. {$R *.lfm}
  118.  
  119. // RU: Т.к. звуковая подсистема нацелена на 3D, для позиционирования звуков в 2D нужны некоторые ухищрения.
  120. // EN: Because sound subsystem using 3D, there is some tricky way to calculate sound position in 2D.
  121. function CalcX2D( const X : Single ) : Single;
  122. begin
  123.   Result := ( X - ScreenWidth / 2 ) * ( 5 / ScreenHeight / 2 );
  124. end;
  125.  
  126. function CalcY2D( const Y : Single ) : Single;
  127. begin
  128.   Result := ( Y - ScreenWidth / 2 ) * ( 5 / ScreenHeight / 2 );
  129. end;
  130.  
  131. procedure Draw;
  132. begin
  133.   setFontSize(20, fntMain);
  134.   text_Draw( fntMain, 0, 0, 'Escape - Exit' );
  135.  
  136.   // RU: Координаты мыши можно получить при помощи функций mouse_X и mouse_Y.
  137.   // EN: Mouse coordinates can be got using functions mouse_X and mouse_Y.
  138.   text_Draw( fntMain, 0, 18, 'Mouse X, Y: ' + u_IntToStr( Form1.mouseX ) + '; ' + u_IntToStr( Form1.mouseY ) );
  139.  
  140.   ssprite2d_Draw(MyIcon[ state ], r1, 0);
  141.   text_Draw(fntMain, textX, textY, text);
  142.  
  143.   if col2d_PointInRect( Form1.mouseX, Form1.mouseY, r ) Then
  144.     begin
  145.       fx_SetBlendMode( FX_BLEND_ADD );
  146.       ssprite2d_Draw(MyIcon[state], r2, 0, 155);
  147.       fx_SetBlendMode( FX_BLEND_NORMAL );
  148.     end;
  149.   Application.ProcessMessages;
  150. end;
  151.  
  152. procedure Init;
  153. begin
  154.   wnd_SetSize( Form1.ClientWidth, Form1.ClientHeight );
  155.   // RU: Инициализируем звуковую подсистему. Для Windows можно сделать выбор между DirectSound и OpenAL отредактировав файл zgl_config.cfg.
  156.   // EN: Initializing sound subsystem. For Windows can be used DirectSound or OpenAL, see zgl_config.cfg.
  157.   snd_Init();
  158.  
  159.   // RU: Инициализируем обработку ввода джойстиков и получаем количество подключенных джойстиков.
  160.   // EN: Initialize processing joystick input and get count of plugged joysticks.
  161.   joyCount := joy_Init();
  162.  
  163.   // RU: Загружаем текстуры, которые будут индикаторами.
  164.   // EN: Load the textures, that will be indicators.
  165.   MyIcon[ 0 ] := tex_LoadFromFile( dirRes + 'audio-stop.png' );
  166.   MyIcon[ 1 ] := tex_LoadFromFile( dirRes + 'audio-play.png' );
  167.  
  168.   fntMain := font_LoadFromFile( dirRes + 'font.zfi' );
  169.  
  170.   // RU: Загружаем звуковой файл и устанавливаем для него максимальноe количество проигрываемых источников в 2.
  171.   // EN: Load the sound file and set maximum count of sources that can be played to 2.
  172.   sound := snd_LoadFromFile( dirRes + 'click.wav', 2 );
  173.   audio := snd_LoadFromFile(dirRes + 'music.ogg', 2);
  174.  
  175.   r1.X := ( ScreenWidth - 128 ) / 2;                r1.Y := ( ScreenHeight - 128 ) / 2;
  176.   r1.W := 128;                                      r1.H := 128;
  177.   r2.X := ( ScreenWidth - 132 ) / 2;                r2.Y := ( ScreenHeight - 132 ) / 2;
  178.   r2.W := 132;                                      r2.H := 132;
  179.  
  180.   scr_SetClearColor($7090af);
  181.   text := 'Skillet - Comatose - Whispers In The Dark';
  182.   textX := zgl_Get(WINDOW_WIDTH) / 2 - text_GetWidth(fntMain, text) / 2;
  183.   textY := zgl_get(WINDOW_HEIGHT) / 2 + 64;
  184. end;
  185.  
  186. { TForm1 }
  187.  
  188. procedure TForm1.FormCreate(Sender: TObject);
  189. begin
  190.   {$IFNDEF USE_ZENGL_STATIC}
  191.   if not zglLoad( libZenGL ) then
  192.   begin
  193.     Application.Terminate;
  194.     Exit;
  195.   end;
  196.   {$ENDIF}
  197.   // RU: вариант для неизменного окна или выбирайте нужный вариант в настройках формы.
  198.   // EN: option for a fixed window or select the desired option in the form settings.
  199.   // Form1.BorderStyle := bsSingle;
  200. end;
  201.  
  202. procedure TForm1.FormDeactivate(Sender: TObject);
  203. begin
  204.   Timer1.Enabled := false;
  205. end;
  206.  
  207. // закрываем форму
  208. procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);
  209. begin
  210.   Timer1.Enabled := false;
  211.  
  212.   zgl_Exit;
  213.   {$IFNDEF USE_ZENGL_STATIC}
  214.   zglFree;
  215.   {$EndIf}
  216.  
  217.   Application.Terminate;
  218. end;
  219.  
  220. procedure TForm1.FormActivate(Sender: TObject);
  221. {$IFDEF LINUX}
  222.   var
  223.     widget : PGtkWidget;
  224. {$ENDIF}
  225. begin
  226.   Timer1.Enabled := False;
  227.   // Rus: если инициализации ещё не было, то производим инициализацию окна.
  228.   // Eng: if initialization has not yet taken place, then we initialize the window.
  229.   if zgl_Get(APP_INITED_TO_HANDLE) = 0 then
  230.   begin
  231.     // Производим инициализацию -------------------------------------------
  232.     // RU: Вертикальная синхронизация поможет избежать загрузки процессора.
  233.     // EN: Vertical synchronization will decrease a CPU loading.
  234.     zgl_SetParam(Form1.ClientWidth, Form1.ClientHeight, False, True);
  235.  
  236.     // RU: Перед стартом необходимо настроить viewport.
  237.     // EN: Before the start need to configure a viewport.
  238.     wnd_SetPos( Form1.Left, Form1.Top );
  239.   //  wnd_SetSize( Form1.ClientWidth, Form1.ClientHeight );
  240.  
  241.     Form1.BringToFront();
  242.     r.X := ( Form1.ClientWidth - 128 ) / 2;
  243.     r.Y := ( Form1.ClientHeight - 128 ) / 2;
  244.     r.W := 128;
  245.     r.H := 128;
  246.     //------------------------------------------------------------
  247.  
  248.     zgl_Reg(SYS_LOAD, @Init);
  249.     zgl_Reg( SYS_DRAW, @Draw );
  250.  
  251.     {$IFDEF LINUX}
  252.       {$IFDEF LCLGTK2}
  253.       widget := GetFixedWidget( PGtkWidget( Handle ) );
  254.       gtk_widget_realize( widget );
  255.       if not zgl_InitToHandle( GDK_WINDOW_XID( widget^.window ) ) then
  256.       begin
  257.         Application.Terminate;
  258.         Exit;
  259.       end;
  260.       {$ENDIF}
  261.       {$IfDef LCLGTK3}
  262.       widget := TGtk3Window(Handle).GetContainerWidget;
  263.       //gtk_widget_realize( widget );                                           // это нужно здесь???
  264.       if not zgl_InitToHandle( gdk_x11_window_get_xid(  widget^.window ) ) then
  265.       begin
  266.         Application.Terminate;
  267.         Exit;
  268.       end;
  269.       {$EndIf}
  270.     {$ENDIF}
  271.  
  272.     {$IFDEF WINDOWS}
  273.       if not zgl_InitToHandle( Handle ) then
  274.       begin
  275.         Application.Terminate;
  276.         Exit;
  277.       end;
  278.     {$ENDIF}
  279.   end;
  280.  
  281.   // RU: таймер должен быть изначально выключен! Включаем таймер только когда окно инициализировано.
  282.   // EN: the timer must be initially turned off! We turn on the timer only when the window is initialized.
  283.   Timer1.Enabled := True;
  284. end;
  285.  
  286. // RU: проверка нажатия клавиши.
  287. // EN: keypress check.
  288. procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
  289. begin
  290.   if Key = 27 then
  291.     Form1.Close;
  292. end;
  293.  
  294. // RU: обработка мыши и проигрывание музыки.
  295. // EN: mouse handling and music playback.
  296. procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
  297.   Shift: TShiftState; X, Y: Integer);
  298. begin
  299.   Timer1.Enabled := false;
  300.   if Button = mbLeft then
  301.   begin
  302.     mouseX := X;
  303.     mouseY := Y;
  304.     // RU: В данном случае мы начинаем воспроизводить звук сразу в указанных координатах, но их можно менять и в процессе используя процедуру snd_SetPos.
  305.     //     Важно: Для OpenAL можно позиционировать только mono-звуки.
  306.     //
  307.     // EN: In this case, we begin to play the sound directly in these coordinates, but they can be changed later using procedure snd_SetPos.
  308.     //     Important: OpenAL can position only mono-sounds.
  309.  
  310. // !!! -------------------------------------------------------------------------
  311. // RU: эта часть изменена!!! Теперь можно заново воспроизводить звуки, даже если они не закончили играть.
  312. // EN: this part has changed! Sounds can now be replayed even if they haven't finished playing.
  313.     if snd_Get(sound, IDSound[0], SND_STATE_PLAYING) = IDSound[0] then
  314.       snd_Stop(sound, IDSound[0]);
  315.     IDSound[0] := snd_Play(sound, FALSE, CalcX2D(X), CalcY2D(Y));
  316. // !!! -------------------------------------------------------------------------
  317.  
  318. // RU: добавляем проверку на проигрывание звука, только если много разных звуков/музыки, то номера надо менять (не только 1!!!).
  319. // EN: we add a check for sound playback, only if there are many different sounds / music, then the numbers must be changed (not only 1 !!!).
  320.     if col2d_PointInRect(X, Y, r) Then
  321.     begin
  322.       if audioPlay then
  323.         snd_Stop(audio, IDSound[1])
  324.       else
  325.         IDSound[1] := snd_Play(audio, False);
  326.       audioPlay := not audioPlay;
  327.     end;
  328.   end;
  329.   Timer1.Enabled := true;
  330. end;
  331.  
  332. // RU: для примера использования перемещения мышки.
  333. // EN: for an example of using mouse movement.
  334. procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
  335.   Y: Integer);
  336. begin
  337.   // RU: это пример если вы создаёте корректированное окно для LCL.
  338.   // EN: This is an example if you are creating an adjusted window for LCL.
  339.   mouseX := X;
  340.   mouseY := Y;
  341.   app_MouseProc(mouseX, mouseY);
  342. end;
  343.  
  344. procedure TForm1.Timer1Timer(Sender: TObject);
  345. begin
  346.   Timer1.Enabled := False;
  347.   app_MainLoopHandle;
  348.  
  349.   // RU: Проверяем играет ли музыка(1 - играет, 0 - не играет). Так же можно проверить и звуки - подставив zglPSound и ID вот так:
  350.   //     snd_Get( Sound, ID...
  351.   //     ID возвращается функцией snd_Play.
  352.   //
  353.   // EN: Check if music playing(1 - playing, 0 - not playing). Sounds also can be checked this way - just use zglPSound and ID:
  354.   //     snd_Get( Sound, ID...
  355.   //     ID returns by function snd_Play.
  356.   state := snd_Get( audio, IDSound[1], SND_STATE_PLAYING );
  357.   if state = 0 Then
  358.     audioPlay := False;
  359.  
  360.   // RU: Получаем в процентах позицию проигрывания аудиопотока и ставим громкость для плавных переходов.
  361.   // EN: Get position in percent's for audio stream and set volume for smooth playing.
  362.   p := snd_Get( audio, IDSound[1], SND_STATE_PERCENT );
  363.   if ( p >= 0 ) and ( p < 25 ) Then
  364.     snd_SetVolume(audio, IDSound[1], ( 1 / 24 ) * p );
  365.   if ( p >= 75 ) and ( p < 100 ) Then
  366.     snd_SetVolume(audio, IDSound[1], 1 - ( 1 / 24 ) * ( p - 75 ) );
  367.   Timer1.Enabled := True;
  368. end;
  369.  
  370. end.
  371.  

Quote
function gdk_x11_window_get_xid(window: PGdkWindow): TXID; cdecl; external LazGtk3_library name 'gdk_x11_window_get_xid';
Разработчикам, добавьте пожалуйста, в LazGtk3 отсутствующую функциональность (желательно не только ту, что я указал). Есть вероятность, что она понадобится разработчикам.

Google translate:
Developers, please add missing functionality to LazGtk3 (preferably not only the one I specified). There's a chance the developers will need it.
Rus: Стремлюсь к созданию минимальных и достаточно быстрых приложений.

Eng: I strive to create applications that are minimal and reasonably fast.
Working on ZenGL

tetrastes

  • Hero Member
  • *****
  • Posts: 761
Re: GTK3. Get Widget? Get XID?
« Reply #3 on: February 22, 2026, 07:44:00 pm »
Разработчикам, добавьте пожалуйста, в LazGtk3 отсутствующую функциональность (желательно не только ту, что я указал). Есть вероятность, что она понадобится разработчикам.
Ага, щаз  :D

 

TinyPortal © 2005-2018