79557137

Date: 2025-04-05 15:00:46
Score: 0.5
Natty:
Report link

Okay, after testing for hours, i got it..
I have to free the reference hold by GJS in a destroy signal handler, all other tries result in memory leaks.
I dont know why, but simply setting your references in GJS to null after using Gtk.widget.destroy() doesnt work and if you try to remove the element first from the parent and then set its reference to null and let GJS destroy it, also results in memory leaks.

This works:

#!/usr/bin/cjs
"use strict";
import Gtk from 'gi://Gtk?version=3.0';
 
Gtk.init (null);

const window=  new Gtk.Window ();
let buttons=[], button, box=new Gtk.Box ({ orientation:1}), remove=true;

function finalize_destroy (button)
    {
    buttons[button.index]=null;
    }

function construct_buttons ()
   {
   for (let i=0;i<500;i++)
      {
      button=new Gtk.Button ({label:"hello"});
      box.add (button);
      button.index=i;
      button.connect ("destroy", finalize_destroy)
      buttons.push (button);
      }
   }
   
setInterval (function ()   
   {
   if (remove)
      {
      for (let i=0;i<500;i++) buttons[i].destroy ();
      buttons=[];
      }
   else
      {
      construct_buttons ();
      window.show_all ();
      }
   remove=!remove;
   }, 2000);

construct_buttons ();
      
window.add(box);
window.set_title ("Test");
window.connect ('destroy', () => { Gtk.main_quit (); });
window.set_size_request (740, 600);
window.show_all ();

Gtk.main ();

So if i construct my own widget, which consists of a lot of Gtk widgets, i collect all widgets in a "widgets" namespace container object.
After construction i connect a handler for every widget to the destroy signal and release the references in the destroy handler.
I dont know, if that is the right way, but it works.
A more complex example:

#!/usr/bin/cjs
"use strict";
import Gtk from 'gi://Gtk?version=3.0';
 
Gtk.init (null);

const window=  new Gtk.Window ();
let top_box=new Gtk.Box ({ orientation:1}), own_widgets= [], remove=true;

//-- constructor own widgets: which is a collection of structured gtk widgets
function OwnWidget ()
   {
   var widgets=new Object ();
   
   //-- collecting all widgets i construct in container namespace widgets
   widgets.eventbox_for_hbox= new Gtk.EventBox ();                                                           
    widgets.eventbox_for_vbox= new Gtk.EventBox ({halign:1,valign:1});                                          
    widgets.hbox=              new Gtk.Box ({ spacing: 2});
    widgets.vbox=              new Gtk.Box ({ orientation:1, spacing: 2});
    widgets.button_A=          new Gtk.Button ({ label:"Button_A", halign:3, valign:3 }),         
    widgets.button_B=          new Gtk.Button ({ label:"Button_B", halign:3, valign:3 }), 
    widgets.button_C=          new Gtk.Button ({ label:"Button_C", halign:3, valign:3 }), 
   
   //-- some structure: eventbox_for_vbox (top container) -> vbox -> eventbox_for_hbox -> hbox -> buttons                                       
   widgets.hbox.add(widgets.button_A);
   widgets.hbox.add(widgets.button_B);
   widgets.hbox.add(widgets.button_C);
   widgets.eventbox_for_hbox.add (widgets.hbox);
    widgets.vbox.add (widgets.eventbox_for_hbox);
    widgets.eventbox_for_vbox.add (widgets.vbox);
    
    /* connecting destroy handler for every widget -> OwnWidget.prototype.destroy.finalize_destroy is the template function
       and adding a property to every widget called OWNWIDGET_propertyID, which is the widgets property name in the "widgets" object.
       This is needed in finalie_destroy see below. */
    for (let propertyID in widgets)
       {
       widgets[propertyID].connect ("destroy", OwnWidget.prototype.destroy.finalize_destroy.bind (this));
       widgets[propertyID].OWNWIDGET_propertyID=propertyID;
       }
       
    this.widgets=widgets;
    this.top_container=widgets.eventbox_for_vbox;
   }

//-- destroys your own widget
OwnWidget.prototype.destroy=function ()
   {
   this.top_container.destroy ();
   this.top_container=null;
   }

//-- called on signal destroy, releaving the references of GJS in instance.widgets object
OwnWidget.prototype.destroy.finalize_destroy=function destroy (widget)
   {
   this.widgets[widget.OWNWIDGET_propertyID]=null;
   }
   
//-- construct 100 own widgets with the above structure
function construct ()
   {
   let own_widget;
 
   for (let i=0;i<250;i++)
      {
      own_widget=new OwnWidget ();
      top_box.add (own_widget.widgets.eventbox_for_vbox);
      own_widgets[i]=own_widget;
      }
   window.show_all();
   }

//-- removes the 100 own widgets from the top-box and destroys it
function remove_and_destroy ()
   {
   for (let i=0;i<250;i++) 
      {
      own_widgets[i].destroy ();
      /* to be sure, that all is freed, i also set the array reference on the own widget instance null,
         but this will be overwritten by the next construct () call, so i think its not necessary. */
      own_widgets[i]=null;
      }
   }
 
setInterval (function ()   
   {
   if (remove) remove_and_destroy ();
   else construct ();

   remove=!remove;
   }, 3000);

construct ();
window.add(top_box);
window.set_title ("Test");
window.connect ('destroy', () => { Gtk.main_quit (); });
window.set_size_request (740, 600);
window.show_all ();

Gtk.main ();
Reasons:
  • Blacklisted phrase (1): doesnt work
  • Long answer (-1):
  • Has code block (-0.5):
  • Self-answer (0.5):
  • Low reputation (0.5):
Posted by: Schmaehgrunza