Skip to main content

Notice

Please note that most of the software linked on this forum is likely to be safe to use. If you are unsure, feel free to ask in the relevant topics, or send a private message to an administrator or moderator. To help curb the problems of false positives, or in the event that you do find actual malware, you can contribute through the article linked here.
Topic: Spider Monkey Panel (foo_spider_monkey_panel) (Read 348340 times) previous topic - next topic
0 Members and 1 Guest are viewing this topic.

Re: Spider Monkey Panel (foo_spider_monkey_panel)

Reply #1250
general tip for anyone else who may be experiencing panel crashes or SMP performance issues.

via @Regor (big thanks!)
in FB prefs>advanced>search "heap"
(under spider monkey panel) set Maximum Heap Size number by entering 999999999999 (it will auto populate with your max)
No, this is one of the worst advices I've seen and nobody should *ever* follow it if they want their SMP (and fb2k by extension) to remain stable.

What this "general tip" does, is it effectively removes all limits on RAM usage by SMP. Problem being that the same RAM is used by fb2k and other components as well. So, what will happen, is that after some time fb2k process will run out of memory, because SMP will use up every last bit of it, and fb2k will crash randomly during memory allocation (which can happen in fb2k itself, in other components or in SMP itself). And by crash I mean literal crash to desktop, not a script crash in SMP.

TLDR: do *not* ever do this. It will break your fb2k with almost 100% certainty.

PS: this "tip" makes scripts work "better" , because it almost totally disables garbage collection (i.e. cleanup of the stuff that uses RAM), it's akin to removing breaks from the car that runs downhill to make it go faster...

Re: Spider Monkey Panel (foo_spider_monkey_panel)

Reply #1251
general tip for anyone else who may be experiencing panel crashes or SMP performance issues.

via @Regor (big thanks!)
in FB prefs>advanced>search "heap"
(under spider monkey panel) set Maximum Heap Size number by entering 999999999999 (it will auto populate with your max)
No, this is one of the worst advices I've seen and nobody should *ever* follow it if they want their SMP (and fb2k by extension) to remain stable.

What this "general tip" does, is it effectively removes all limits on RAM usage by SMP. Problem being that the same RAM is used by fb2k and other components as well. So, what will happen, is that after some time fb2k process will run out of memory, because SMP will use up every last bit of it, and fb2k will crash randomly during memory allocation (which can happen in fb2k itself, in other components or in SMP itself). And by crash I mean literal crash to desktop, not a script crash in SMP.

TLDR: do *not* ever do this. It will break your fb2k with almost 100% certainty.

PS: this "tip" makes scripts work better, because it almost totally disables garbage collection (i.e. cleanup of the stuff that uses RAM), it's akin to removing breaks from the car that runs downhill to make it go faster...
+1

If I ask you to test something for testing on PMs, don't suppose that's a tip for everybody or a recommended setting for everyday usage  ::)

Anyway, in this particular case, the user was having ram allocation failures on handle list creation due to SMP, with the ram limit imposed.

Quote
Error: Spider Monkey Panel v1.6.1 ({B48F5B98-0687-4D8A-84E5-B5E3271D364B})
FbMetadbHandleList_Constructor failed:
allocation size overflow

Fb.getLibraryItems would fail at 340K tracks, also when retrieving tags.

Re: Spider Monkey Panel (foo_spider_monkey_panel)

Reply #1252
What this "general tip" does, is it effectively removes all limits on RAM usage by SMP. Problem being that the same RAM is used by fb2k and other components as well. So, what will happen, is that after some time fb2k process will run out of memory, because SMP will use up every last bit of it, and fb2k will crash randomly during memory allocation (which can happen in fb2k itself, in other components or in SMP itself). And by crash I mean literal crash to desktop, not a script crash in SMP.

I appreciate the add'l info - I was already experiencing FB memory crashes regularly via SMP. My comment was intended as a debugging tip, not perm setting.

Re: Spider Monkey Panel (foo_spider_monkey_panel)

Reply #1253
FB memory crashes regularly via SMP

You are conflating two different issues:
- SMP script crash: popup "your script uses too much memory X/Y" with SMP panel turning red. The player itself continues working normally and panel can be restarted.
- fb2k crash: whole player crashes. I.e. you can't continue using player and have to actually restart the application.

That "tip" turns the first scenario (SMP crash) into the second scenario (fb2k crash)

Re: Spider Monkey Panel (foo_spider_monkey_panel)

Reply #1254
You are conflating two different issues:
- SMP script crash: popup "your script uses too much memory X/Y" with SMP panel turning red. The player itself continues working normally and panel can be restarted.
- fb2k crash: whole player crashes. I.e. you can't continue using player and have to actually restart the application.

That "tip" turns the first scenario (SMP crash) into the second scenario (fb2k crash)
Please, re-read the report. The user was experiencing fb2k crashes before changing anything, so in fact you are conflating the issues (and probably some info is missing too). Hope this clarifies it:

- The user had fb2k crashes regularly, from time to time, with other scripts.

- The user had fb2k crashes at startup with my script: https://hydrogenaud.io/index.php/topic,120982.msg1022427.html#msg1022427

- The user had sometimes panel crashes with multiple scripts, included mine, while trying to process entire library at random points (reported by PM).

- FbMetadbHandleList_Constructor failed: allocation size overflow with standard settings with a 300K tracks size, which should work with default ram settings and worked fine on independent tests. (*) So the constructor fails when garbage collection has not freed enough ram on the panel (reaching the limit), although it could have simply take more ram from foobar, etc.. (I assume this with the following point)

- Then they tried changed the settings, following my suggestion, to find where the problem lied; since fb2k should not crash with the default config as you noted. They had no more FbMetadbHandleList_Constructor crashes AND no more fb2k crashes. So in fact crashes were gone with the debugging setting, not the opposite.

- Finally user reports here the "tip", which is obviously not applicable as a recommended setting.

(*) Blank panel with script getting library items in multiple iterations, it was able to fill up to 294.967.295 items on a handle list on the user's system. Which is obviously much higher than 300 K.

PD: this will obviously be a non-issue on x64 whenever there is a release, but it could be interesting to fix it on the actual release too since fb2k crashes are not expected as you noted.

Re: Spider Monkey Panel (foo_spider_monkey_panel)

Reply #1255
Btw, is it possible if SMP could delete created font objects from cache on window.Reload?
Well my theme is using "some" fonts and after the 20th window.Reload or so when using the new custom menu I've implemented,
I get a win API font crash.
I know from the docs it is limited by Windows, but I think there is nothing I could really do about it, I am reusing fonts where possible...

-TT

Re: Spider Monkey Panel (foo_spider_monkey_panel)

Reply #1256
Well my theme is using "some" fonts and after the 20th window.Reload or so when using the new custom menu I've implemented,
How many is "some"? Georgia calls GDI.font about 45 times at startup with 12 different font faces to cache all the fonts the theme uses, and I can window.reload as much as I want without ever having a single API font crash. I do have a fair amount of memory though, so maybe that's why?

Re: Spider Monkey Panel (foo_spider_monkey_panel)

Reply #1257
I don't think it's an ram issue but a GDI handle limit and good old GDI is just the culprit.
So if I close and reopen the new custom menu ( based on your Material design )
about 275 times ( didn't use window.Reload for this test ), and the menu uses one gdi.Font object:

Code: [Select]
Error: Spider Monkey Panel v1.6.2-dev+7c0928bf ({04620F16-1878-47A1-8EFE-0CE0B99566CC}: Georgia-ReBORN v2.3.0 by TT)
include failed:
Font failed:
WinAPI error:
  CreateFont failed with error (0x0):
    Function failed, but returned a `SUCCESS` error code, which is usually caused by a bugged WinAPI. One such case is when process runs out of GDI handles and can't create a new GDI object.

This isn't that much to be honest because when you're using the theme for hours and creating a new custom theme,
it will eventually crash. When the crash happened I've had enough ram, but it could be 32bit app ram limitation?
Afaik 32bit apps can only use max 4gb, but I've read somewhere that fb2k x86 only uses max 2gb if I'm not mistaken.
But I don't think it has anything to do with the GDI handle limit, not sure...

P.S Tested on a laptop...

-TT

Re: Spider Monkey Panel (foo_spider_monkey_panel)

Reply #1258
fgt what i said...
A rose will bloom, it then will fade.

Re: Spider Monkey Panel (foo_spider_monkey_panel)

Reply #1259
I don't think it's an ram issue but a GDI handle limit and good old GDI is just the culprit.
So if I close and reopen the new custom menu ( based on your Material design )
about 275 times ( didn't use window.Reload for this test ), and the menu uses one gdi.Font object:
So just so I understand, the menu is calling gdi.Font everytime it initializes? Definitely those fonts need to be cached so you aren't creating them every time the menu is expanded. If you look at my original code I'm creating all the fonts I plan to use, and then just passing those in when creating the underlying controls, instead of calling gdi.font once for each control (which it sounds like you might be doing).

Elia might have deleted their post but if you're doing something different than I think, a memoized function that only calls gdi.font could be another really good idea.

Re: Spider Monkey Panel (foo_spider_monkey_panel)

Reply #1260
I don't think it's an ram issue but a GDI handle limit and good old GDI is just the culprit.
So if I close and reopen the new custom menu ( based on your Material design )
about 275 times ( didn't use window.Reload for this test ), and the menu uses one gdi.Font object:
So just so I understand, the menu is calling gdi.Font everytime it initializes? Definitely those fonts need to be cached so you aren't creating them every time the menu is expanded. If you look at my original code I'm creating all the fonts I plan to use, and then just passing those in when creating the underlying controls, instead of calling gdi.font once for each control (which it sounds like you might be doing).

Elia might have deleted their post but if you're doing something different than I think, a memoized function that only calls gdi.font could be another really good idea.

i del my post because i found a 'gdi_font' function in his geogia_reborn repo.
A rose will bloom, it then will fade.

Re: Spider Monkey Panel (foo_spider_monkey_panel)

Reply #1261
Last he told me, the code from his betas isn't in the repo yet, so it's unclear what he's using in this particular instance.

Re: Spider Monkey Panel (foo_spider_monkey_panel)

Reply #1262
I don't think it's an ram issue but a GDI handle limit and good old GDI is just the culprit.
So if I close and reopen the new custom menu ( based on your Material design )
about 275 times ( didn't use window.Reload for this test ), and the menu uses one gdi.Font object:
So just so I understand, the menu is calling gdi.Font everytime it initializes? Definitely those fonts need to be cached so you aren't creating them every time the menu is expanded. If you look at my original code I'm creating all the fonts I plan to use, and then just passing those in when creating the underlying controls, instead of calling gdi.font once for each control (which it sounds like you might be doing).

Elia might have deleted their post but if you're doing something different than I think, a memoized function that only calls gdi.font could be another really good idea.
It seems so.

gr-helpers
Code: [Select]
function font(name, size, style) {
let font;
try {
font = gdi.Font(name, Math.round(scaleForDisplay(size)), style);
} catch (e) {
console.log('\nFailed to load font >>>', name, size, style);
}
return font;
}

Should be something like this: (as bonus, don't spam the console with font missing messages!)
Code: [Select]
function _gdiFont(name, size, style) {
let id = name.toLowerCase() + '_' + size + '_' + (style || 0);
if (!fonts[id]) {
fonts[id] = gdi.Font(name, size, style || 0);
}
if (fonts[id].Name !== name && fonts.notFound.indexOf(name) === -1) { // Display once per session, otherwise it floods the console with the same message...
fonts.notFound.push(name);
fb.ShowPopupMessage('Missing font: ' + name + '\n\nPlease install dependency found at (a restart is required):\n' + folders.xxx + '_resources', window.Name);
console.log('Missing font: ' + name);
}
return fonts[id];
}

gr-menu.js is also full of calls to gdi.Font. Which should be cached.

Btw, if you are lazy, you can simply edit the gdi.Font method to cache fonts. That ensures it will apply on any instance, instead of using a new function. (*)  For ex I did this on TitleFormat (adding a Expression property to retrieve the original string, and caching):
Code: [Select]
// Add caching
Object.defineProperty(fb, 'tfCache', {
  enumerable: false,
  configurable: false,
  writable: false,
  value: {}
});

// Augment fb.TitleFormat() with 'Expression' property and add caching
{
const old = fb.TitleFormat;
fb.TitleFormat = function TitleFormat() {
const bCache = fb.tfCache.hasOwnProperty(arguments[0]);
const that = bCache ? fb.tfCache[arguments[0]] : old.apply(fb, [...arguments]);
that.Expression = arguments[0];
if (!bCache) {fb.tfCache[arguments[0]] = that;}
return that;
}
}

Btw I'm confused with other point. you did report that window.Reload did not cleared the fonts (?) I mean, wether you cache them or not, they should be removed at window.Reload. Or at least that's what I always thought. Is not that method supposed to be the same than loading the script from zero?

 (*) While this is not recommended on JS for web, in SMP libraries are not shared -but unique to every script/developer-, so in fact this should be the recommended way IMO... also it would help unifying helpers use for developers (the conversation at SMP thread).

Re: Spider Monkey Panel (foo_spider_monkey_panel)

Reply #1263
Btw, is it possible if SMP could delete created font objects from cache on window.Reload?
It *should* delete everything allocated by the script after reload. Last time I checked (t'was quite a long time ago though) all corresponding GDI handles were removed between reloads. Maybe I've reintroduced the bug, or maybe it's Windows being buggy (you *are* on windows and not wine, right?) and not actually destroying objects, or maybe you are reloading too much too fast which causes garbage collector not being fast enough thus leaving Font object alive for too long (they do not occupy a lot of space, hence they are not a priority target for GC).

More testing is required...

- Then they tried changed the settings, following my suggestion, to find where the problem lied; since fb2k should not crash with the default config as you noted. They had no more FbMetadbHandleList_Constructor crashes AND no more fb2k crashes. So in fact crashes were gone with the debugging setting, not the opposite.
This is really weird. I'd have liked to debug that (but not yet, since I'm still not back). Maybe there is a bug in SMP with GC that causes dangling references of some sort.

Re: Spider Monkey Panel (foo_spider_monkey_panel)

Reply #1264
Thanks for the replies,

yes latest code is not yet available on the Georgia-ReBORN repo ( last commit was on Aug 28, 2022 )
but here "LATEST WORK IN PROGRESS VERSION: Georgia-ReBORN v2.3.0 Beta 11b":
https://github.com/TT-ReBORN/Georgia-ReBORN/discussions/74#discussion-4190799

So I have quite modified your Material code to my needs, full code is in gr-menu-custom.js

Basically class BaseControl constructor only has one declared font "this.font = ft.popup" that has been created via gdi.Font ( font helper in gr-setup.js ) on theme init startup:
Code: [Select]
class BaseControl {
constructor(x, y, label) {
/** @protected */ this.x = x;
/** @protected */ this.y = y;
/** @protected */ this.label = label;
this.state = {};
this.doubleClickTime = 300;
this.lastClickTime = null;
this.focus = false;
this.disabled = false;
this._hovered = false;
this.font = ft.popup;
this.popupFontSize = pref.layout === 'artwork' ? pref.popupFontSize_artwork : pref.popupFontSize_default;
this.closeBtn = this.label === '\u2715';
/** @protected @private */ this.i = gdi.CreateImage(1, 1);
/** @protected */ this.g = this.i.GetGraphics(); // GdiBitmap used for MeasureString and other functions
}

then all other child classes ( DropDownMenu, StringInput, ColorPicker and Info ) are using this.font.

When the custom theme menu will be opened by the user via top menu Options > Theme > Custom > Edit custom theme, or
when a custom theme slot was selected from top menu Options > Theme > Custom, via the quick navigation right click context menu > Edit custom theme :
Code: [Select]
function initCustomThemeMenu(playlist_section, main_section, library_section, biography_section, info) {
if (pref.libraryLayout   === 'full') pref.libraryLayout   = 'normal'; setLibrarySize();
if (pref.biographyLayout === 'full') pref.biographyLayout = 'normal'; setBiographySize();
if (pref.lyricsLayout    === 'full') pref.lyricsLayout    = 'normal'; resizeArtwork(true);

controlList = [];

const margin = scaleForDisplay(40);
const baseX = displayBiography || pref.displayLyrics ? ww * 0.5 + margin : !displayPlaylist && !displayLibrary && !displayBiography ? noAlbumArtStub ? ww * 0.3 : albumArtSize.x + margin : margin;
let x = baseX;
let y = geo.topMenuHeight + margin * 0.75;

const mainSection      = ['main_bg', 'main_bar', 'main_text', 'main_btns', 'main_btns2', 'main_style'].includes(main_section);
const playlistSection  = ['pl_bg',   'pl_text1', 'pl_text2',  'pl_misc', 'pl_btns'].includes(playlist_section);
const librarySection   = ['lib_bg',  'lib_text', 'lib_node',  'lib_btns'].includes(library_section);
const biographySection = ['bio_bg',  'bio_text', 'bio_misc',  'bio_btns'].includes(biography_section);

const menu = new DropDownMenu(x, y, 'Main', ['Bg', 'Bar', 'Text', 'Btns', 'Btns 2', 'Style'], 0);
controlList.push(menu);
x += controlList[controlList.length - 1].w + 1; controlList.push(new DropDownMenu(x, y, 'Playlist',  ['Bg', 'Text', 'Text 2', 'Misc', 'Btns'], 0));
x += controlList[controlList.length - 1].w + 1; controlList.push(new DropDownMenu(x, y, 'Library',   ['Bg', 'Text', 'Node', 'Btns'], 0));
x += controlList[controlList.length - 1].w + 1; controlList.push(new DropDownMenu(x, y, 'Biography', ['Bg', 'Text', 'Misc', 'Btns'], 0));
x += controlList[controlList.length - 1].w + 1; controlList.push(new DropDownMenu(x, y, 'Options',   ['Info', '', 'Theme 01', 'Theme 02', 'Theme 03', 'Theme 04', 'Theme 05', 'Theme 06', 'Theme 07', 'Theme 08', 'Theme 09', 'Theme 10', '', 'Reset'], 0));
x += controlList[controlList.length - 1].w + 1; controlList.push(new DropDownMenu(x, y, '\u2715',    ['']));
x = baseX;
y += menu.h + margin * 0.75;

switch (true) {
case playlistSection:  customPlaylistColors(x, y, ww * 0.5, wh - geo.topMenuHeight - geo.lowerBarHeight, playlist_section); break;
case mainSection:      customMainColors(x, y, ww * 0.5, wh - geo.topMenuHeight - geo.lowerBarHeight, main_section); break;
case librarySection:   customLibraryColors(x, y, ww * 0.5, wh - geo.topMenuHeight - geo.lowerBarHeight, library_section); break;
case biographySection: customBiographyColors(x, y, ww * 0.5, wh - geo.topMenuHeight - geo.lowerBarHeight, biography_section); break;
case info:             customThemeInfo(x, y, ww * 0.5, wh - geo.topMenuHeight - geo.lowerBarHeight); break;
}
}

Thanks for the tips @regor, I'll see what I can do with it.

-TT

Re: Spider Monkey Panel (foo_spider_monkey_panel)

Reply #1265
@TT your link doesn't include beta 11b, just beta 11, and that one doesn't have gr-menu-custom.js, just gr-menu.js.

Re: Spider Monkey Panel (foo_spider_monkey_panel)

Reply #1266
Both versions are in the first post, it is the second download link right beneath Beta 11 ;-)
@MordredKLB, check also my PM.

Re: Spider Monkey Panel (foo_spider_monkey_panel)

Reply #1267
Both versions are in the first post, it is the second download link right beneath Beta 11 ;-)
@MordredKLB, check also my PM.
Reading comprehension was never my strong suit. :) Thanks.

Depending on how gdi.font resources are garbage collected, you could run into problems when changing font sizes since many of your menu options generate multiple gdi.font calls.

I would hope that doing:
Code: [Select]
ft.cached =  gdi.Font('fontAwesome', 22,  0);
// and then
ft.cached =  gdi.Font('fontAwesome', 30,  0);
Would release the first gdiFont handle. But @TheQwertiest would have to confirm.

Re: Spider Monkey Panel (foo_spider_monkey_panel)

Reply #1268
So in the test I was doing on Windows 10, I did not even use the top menu Options at all.
That means no gdi.Font calls from gr-menu.js -> function fontSizeOptions(menu)

I was just always calling ( ~275 times until crash ) the right click context menu > Edit custom theme
from Control_ContextMenu.js and there are no gdi.Font calls at all.

I can reproduce it with this, put this code at the end ( after initMain ) in gr-main.js and start foobar:
Code: [Select]
setInterval(() => {
displayCustomThemeMenu = true;
displayPanel('playlist');
initCustomThemeMenu('pl_bg');
window.Repaint();
}, 500);

It will crash after some time with the WinAPI font error message...
Also, if you window reload after the crash, it will not free the GDI handles, the error message still remains.
Only a foobar program restart helps!

-TT

Re: Spider Monkey Panel (foo_spider_monkey_panel)

Reply #1269
It will crash after some time with the WinAPI font error message...
Repro'd. The issue isn't in your or my code, it's in biography. Your initCustomTheme calls setBiographySize, and inside interface.js's getFont function there's this block of code:
Code: [Select]
		this.font.items.forEach(v => {
const style = pptBio[v[0]] < 4 ? pptBio[v[0]] : (pptBio[v[0]] - 4) * 2;
this.font[v[1]] = gdi.Font(pptBio[v[0]] < 4 ? this.font.main.Name : 'Segoe UI Semibold', this.font.main.Size, style);
});

among others. gdi.Font is called 20x in that one single getFont from the on_size generated in setBiographySize. I'm guessing if you just displayed the biography panel and then resized the window multiple times you'd encounter the exact issue.

You should determine if setBiographySize should even be called first of all, and @WilB should probably use his own memoized version instead of gdi.Font inside getFont, and probably FSM itself should memoize the actual gdi.Font function if at all possible so that us programmers can continue doing dumb things :)


I can probably help you with that if need be.

Re: Spider Monkey Panel (foo_spider_monkey_panel)

Reply #1270
Do you mean this section here?

Code: [Select]
function initCustomThemeMenu(playlist_section, main_section, library_section, biography_section, info) {
if (pref.libraryLayout   === 'full') pref.libraryLayout   = 'normal'; setLibrarySize();
if (pref.biographyLayout === 'full') pref.biographyLayout = 'normal'; setBiographySize();
if (pref.lyricsLayout    === 'full') pref.lyricsLayout    = 'normal'; resizeArtwork(true);

That is the only time I use setBiographySize but ONLY if the biography layout is in full width. Because the custom theme menu is
on the album art so the biography can't be full width. But as you see that shouldn't be a problem at all ( well in the test case with the interval ) because it will be reset to normal width and the function won't be called at all. Also this crash happens when the biography is also in normal width, so setBiographySize won't be called at all, otherwise I'm missing something...

Edit: Just commented this out, it's the same crash.
Tried to resize the biography for 5 mins and no crash =)

-TT

Re: Spider Monkey Panel (foo_spider_monkey_panel)

Reply #1271
Do you mean this section here?

Code: [Select]
function initCustomThemeMenu(playlist_section, main_section, library_section, biography_section, info) {
if (pref.libraryLayout   === 'full') pref.libraryLayout   = 'normal'; setLibrarySize();
if (pref.biographyLayout === 'full') pref.biographyLayout = 'normal'; setBiographySize();
if (pref.lyricsLayout    === 'full') pref.lyricsLayout    = 'normal'; resizeArtwork(true);
That code isn't doing what you think it's doing. Put curly braces around the "then" portions of the if statement like so: { pref.biographyLayout = 'normal'; setBiographySize(); } and then it will.
As it's written it calls setLibrarySize, setBiographySize, and resizeArtwork every time that function is called, regardless of what the layout is.

Also I tracked it down to setBiographySize due to the stack trace on crash. Keep your console open when debugging and see if you get one.

 

Re: Spider Monkey Panel (foo_spider_monkey_panel)

Reply #1272
Haha, forgot the curly braces xD happens if you code till 3am and you should be sleeping.
But still as I've written, if you comment this out it still crashes with the interval...

Console output:
foo_spider_monkey_panel:
Error: Spider Monkey Panel v1.6.2-dev+7c0928bf ({04620F16-1878-47A1-8EFE-0CE0B99566CC}: Georgia-ReBORN v2.3.0 by TT)
SetTextRenderingHint failed:
GdiPlus error: SetTextRenderingHint failed with error (0x2): InvalidParameter

File: gr-main.js
Line: 21, Column: 5
Stack trace:
  drawBackgrounds@gr-main.js:21:5
  drawMain@gr-main.js:925:2
  on_paint@gr-main.js:991:2

Does not tell anything, only that GDI is out of handles for text rendering...

Re: Spider Monkey Panel (foo_spider_monkey_panel)

Reply #1273
Haha, forgot the curly braces xD happens if you code till 3am and you should be sleeping.
But still as I've written, if you comment this out it still crashes with the interval...
BaseControl badly leaks GDIHandles:
Code: [Select]
		/** @protected @private */ this.i = gdi.CreateImage(1, 1);
/** @protected */ this.g = this.i.GetGraphics(); // GdiBitmap used for MeasureString and other functions
That was a really dumb idea. The destructor has to be manually called before the object goes out of scope (which is obviously very hard to do), otherwise you leak that handle. Better would be to have written it so that this.i and this.g are singletons, and every BaseControl shares the same one. Alternately you could make .g not be a part of the the object, and instead just call this.GetGraphics before it's used and then immediately after. Not sure if there are any performance considerations there. CalcTextWidth/Height can get called frequently so that's what I was trying to avoid.

Edit:
Code: [Select]
let __i_ = undefined;
let __g_ = undefined;

class BaseControl {
constructor(x, y, label) {
                . . . clipped other class members here
/** @protected */ this.g;
if (!__i_) {
__i_ = gdi.CreateImage(1, 1);
__g_ = __i_.GetGraphics(); // GdiBitmap used for MeasureString and other functions
}
this.g = __g_;
}

destructor() {
}
Does not crash, or at least not for a very long time. Was able to call initCustomThemeMenu over 3000 times. Seems that gdi.Font handles are released when they go out of scope, so biography panel was just a symptom of this bug and nothing bad is actually happening there on resize.

Re: Spider Monkey Panel (foo_spider_monkey_panel)

Reply #1274
Yep that does it, hammering with 100ms and it goes smoothly =)
Thanks a lot for your first line support Kevin and also for your Material design<3
Would not been able to create custom themes without it, I owe you one.

P.S Sorry for polluting your thread @TheQwertiest ;-)

-Tom