Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
49f3359
Fix Linux IDE build
zerkawei May 8, 2025
ccf4521
Fix Linux IDE crash at launch
zerkawei May 8, 2025
b638c72
SDL handle window resize
zerkawei May 8, 2025
eb5545f
Merge branch 'master' into linux-ide
zerkawei May 12, 2025
34d4081
Handle GLContext between windows
zerkawei May 12, 2025
3525d95
Fix unhandled nulls
zerkawei May 12, 2025
ad1f573
Fix mouse buttons with SDL
zerkawei May 12, 2025
74e2afb
SDL scrolling, return, backspace and tab
zerkawei May 12, 2025
2f4a44f
Disable debugger Evaluate on linux
zerkawei May 12, 2025
13c795c
Merge branch 'beefytech:master' into linux-ide
zerkawei Jul 14, 2025
fb87a98
Cleaner SDL mouse buttons and tooltips
zerkawei Jul 14, 2025
77c8f60
MIgrate to SDL3
zerkawei Jul 19, 2025
9303759
Fix SDL text input
zerkawei Jul 20, 2025
97d8d8a
Fix SDL window closing
zerkawei Jul 20, 2025
d10b952
Handle focus in SDLApp
zerkawei Jul 24, 2025
9e9df3f
Fix SDLApp autocomplete
zerkawei Jul 25, 2025
627dcc4
Move focus to parent on close
zerkawei Aug 13, 2025
2970638
Merge branch 'beefytech:master' into linux-ide
zerkawei Oct 10, 2025
de4ec1b
Fix Zip.bf build on Linux
zerkawei Oct 11, 2025
2db901e
Reimplement SDL app clipboard data
zerkawei Oct 13, 2025
b51366f
Implement MenuBar widget
zerkawei Nov 2, 2025
64e833c
Add bold font failover
zerkawei Nov 7, 2025
67f8037
Merge branch 'beefytech:master' into linux-ide
zerkawei Nov 7, 2025
e09f856
Handle SDL multi clicks
zerkawei Nov 8, 2025
90f5fdd
Implement recent menu in MenuBar
zerkawei Nov 8, 2025
1ea3cbf
SDL Fix autocomplete closing on self resize
zerkawei Nov 13, 2025
8a57422
SDL Restore save dialog on quit
zerkawei Nov 14, 2025
1b2878b
Let system locate libSDL3
zerkawei Nov 14, 2025
0aa0eb6
Use layout aware SDL_Keycode
zerkawei Nov 15, 2025
8b09920
Add font cache on linux using fontconfig
Fusioon Nov 15, 2025
93ed5df
Linux themes support, ImgCreate cmake
Fusioon Nov 16, 2025
b1326a8
SDL: Fix alt, diacritics and ctrl + backspace
Fusioon Nov 17, 2025
1bd64f4
SDL: Implement changing cursor
Fusioon Nov 18, 2025
8374e71
SDL fix menu/popup positioning
zerkawei Nov 21, 2025
9a01cd3
SDL Faster scroll
zerkawei Nov 21, 2025
c5fc962
SDL Implement title, min size, mouse visibility
zerkawei Nov 21, 2025
5ec1a97
Linux: Implement open file explorer and docs link
Fusioon Nov 23, 2025
a208c9f
Merge branch 'master' into linux-ide
zerkawei Nov 26, 2025
abdba32
SDL per window cursor visibility
zerkawei Nov 26, 2025
69aa751
Rework autocomplete resize handling
zerkawei Nov 27, 2025
85a5626
Close auto complete if parent window is moved
zerkawei Nov 28, 2025
7673b8d
SDL add app icon
zerkawei Nov 28, 2025
fc6a291
Remove SDL_image dependency for app icon
zerkawei Dec 2, 2025
64ba7b1
Merge branch 'beefytech:master' into linux-ide
zerkawei Dec 5, 2025
3fb6e5e
Prevent linux crash when renaming projects
zerkawei Dec 6, 2025
f8ef39f
Merge branch 'beefytech:master' into linux-ide
zerkawei Dec 22, 2025
4c078c1
Merge pull request #1 from Fusioon/linux-fontcache
zerkawei Dec 23, 2025
a520e11
Merge pull request #2 from Fusioon/linux-themes
zerkawei Dec 23, 2025
881343a
Merge pull request #3 from Fusioon/linux-kbfixes
zerkawei Dec 23, 2025
8960698
Merge pull request #4 from Fusioon/sdl-cursors
zerkawei Dec 23, 2025
5e8cdf4
Merge pull request #5 from Fusioon/linux-openfm
zerkawei Dec 23, 2025
d453969
Merge branch 'beefytech:master' into linux-ide
zerkawei Dec 23, 2025
50ed9a3
Merge branch 'beefytech:master' into linux-ide
zerkawei Dec 25, 2025
1e0f325
SDL Fix mouse staying hidden
zerkawei Dec 26, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions BeefBuild/BeefProj.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ TargetName = "$(ProjectName)_d"
OtherLinkFlags = "$(LinkFlags) ./libIDEHelper_d.a ./libBeefySysLib_d.a ./libhunspell.so $(Var IDEHelperLibs) -Wl,-rpath -Wl,$ORIGIN"
CLibType = "Dynamic"
PreBuildCmds = ["ReadFile(\"$(WorkspaceDir)/../IDE/dist/IDEHelper_libs_d.txt\", \"IDEHelperLibs\")"]
DebugCommandArguments = "-proddir=..\\ -config=Debug -platform=Win64"
DebugCommandArguments = "-proddir=..\\ -config=Debug -platform=Linux64"
DebugWorkingDirectory = "$(WorkspaceDir)/../IDE/dist"
PreprocessorMacros = ["DEBUG", "CLI"]

Expand All @@ -58,7 +58,7 @@ TargetDirectory = "$(WorkspaceDir)/../IDE/dist"
OtherLinkFlags = "$(LinkFlags) ./libIDEHelper.a ./libBeefySysLib.a ./libhunspell.so $(Var IDEHelperLibs) -Wl,-rpath -Wl,$ORIGIN"
CLibType = "Dynamic"
PreBuildCmds = ["ReadFile(\"$(WorkspaceDir)/../IDE/dist/IDEHelper_libs.txt\", \"IDEHelperLibs\")"]
DebugCommandArguments = "-proddir=..\\ -config=Debug -platform=Win64"
DebugCommandArguments = "-proddir=..\\ -config=Debug -platform=Linux64"
DebugWorkingDirectory = "$(WorkspaceDir)/../IDE/dist"
PreprocessorMacros = ["CLI"]

Expand Down
12 changes: 12 additions & 0 deletions BeefLibs/Beefy2D/BeefProj.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ CLibType = "Static"
BeefLibType = "Static"
PostBuildCmds = ["CopyToDependents(\"$(ProjectDir)/dist/BeefySysLib64_d.dll\")", "CopyToDependents(\"$(ProjectDir)/dist/BeefySysLib64_d.pdb\")"]

[Configs.Debug.Linux64]
OtherLinkFlags = "$(LinkFlags) \"$(ProjectDir)/dist/libBeefySysLib_d.a\""
CLibType = "Static"
BeefLibType = "Static"
PostBuildCmds = ["CopyToDependents(\"$(ProjectDir)/dist/libBeefySysLib_d.a\")"]

[Configs.Release.Win32]
OtherLinkFlags = ""
PreprocessorMacros = ["RELEASE", "BF32"]
Expand All @@ -24,6 +30,12 @@ PreprocessorMacros = ["RELEASE", "BF32"]
OtherLinkFlags = "$(LinkFlags) \"$(ProjectDir)/dist/BeefySysLib64.lib\""
PostBuildCmds = ["CopyToDependents(\"$(ProjectDir)/dist/BeefySysLib64.dll\")", "CopyToDependents(\"$(ProjectDir)/dist/BeefySysLib64.pdb\")"]

[Configs.Release.Linux64]
OtherLinkFlags = "$(LinkFlags) \"$(ProjectDir)/dist/libBeefySysLib.a\""
CLibType = "Static"
BeefLibType = "Static"
PostBuildCmds = ["CopyToDependents(\"$(ProjectDir)/dist/libBeefySysLib.a\")"]

[Configs.Paranoid.Win32]
CLibType = "Static"
BeefLibType = "Static"
Expand Down
1 change: 1 addition & 0 deletions BeefLibs/Beefy2D/src/BFWindow.bf
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ namespace Beefy
AcceptFiles = 0x1000'0000,
NoShow = 0x2000'0000,
NoMouse = 0x4000'0000,
Tooltip = 0x8000'0000
};

[AllowDuplicates]
Expand Down
283 changes: 224 additions & 59 deletions BeefLibs/Beefy2D/src/gfx/Font.bf
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Interop;
using System.Collections;
using System.Text;
using System.IO;
Expand Down Expand Up @@ -259,6 +260,86 @@ namespace Beefy.gfx
List<FontEffect> mFontEffectStack ~ delete _;
DisposeProxy mFontEffectDisposeProxy = new .(new () => { PopFontEffect(); }) ~ delete _;

#if BF_PLATFORM_LINUX

const String FONTCONFIG_LIB = "libfontconfig.so";
static bool IsFontconfigAvailable { get; private set; } = true;

[StaticInitPriority(100)]
private static class FontconfigAllowFail
{
static this()
{
Runtime.AddErrorHandler(new (stage, error) => {
if (stage == .PreFail)
{
if (let err = error as Runtime.LoadSharedLibraryError && err.mPath == FONTCONFIG_LIB)
{
SelfOuter.IsFontconfigAvailable = false;
return .Ignore;
}
}

return .ContinueFailure;
});
}
}

struct FcConfig;
struct FcPattern;
struct FcObjectSet;

[CRepr]
struct FcFontSet
{
public c_int nfont;
public c_int sfont;
public FcPattern** fonts;
}

enum FcResult : c_int
{
Match,
NoMatch,
TypeMismatch,
NoId,
OutOfMemory
}

const String FC_FAMILY = "family";
const String FC_STYLE = "style";
const String FC_WEIGHT = "weight";
const String FC_SLANT = "slant";
const String FC_FILE = "file";

[CLink, Import(FONTCONFIG_LIB)]
static extern c_int FcInit();
[CLink, Import(FONTCONFIG_LIB)]
static extern void FcFini();

[CLink, Import(FONTCONFIG_LIB)]
static extern FcPattern* FcPatternCreate();
[CLink, Import(FONTCONFIG_LIB)]
static extern void FcPatternDestroy(FcPattern* p);

[CLink, Import(FONTCONFIG_LIB)]
static extern FcObjectSet* FcObjectSetBuild(c_char* first, ...);
[CLink, Import(FONTCONFIG_LIB)]
static extern void FcObjectSetDestroy(FcObjectSet* os);

[CLink, Import(FONTCONFIG_LIB)]
static extern FcFontSet* FcFontList(FcConfig* config, FcPattern* p, FcObjectSet* os);
[CLink, Import(FONTCONFIG_LIB)]
static extern void FcFontSetDestroy(FcFontSet* fs);

[CLink, Import(FONTCONFIG_LIB)]
static extern FcResult FcPatternGetString(FcPattern* p, c_char* object, c_int n, char8** s);

[CLink, Import(FONTCONFIG_LIB)]
static extern FcResult FcPatternGetInteger(FcPattern* p, c_char* object, c_int n, c_int *i);

#endif

public this()
{
}
Expand Down Expand Up @@ -288,84 +369,156 @@ namespace Beefy.gfx

static void BuildFontNameCache()
{
#if BF_PLATFORM_WINDOWS
using (sMonitor.Enter())
{
sFontNameMap = new .();

for (int pass < 2)
#if BF_PLATFORM_WINDOWS

for (int pass < 2)
{
Windows.HKey hkey;

if (pass == 0)
{
Windows.HKey hkey;
if (Windows.RegOpenKeyExA(Windows.HKEY_LOCAL_MACHINE, @"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts", 0,
Windows.KEY_QUERY_VALUE | Windows.KEY_WOW64_32KEY | Windows.KEY_ENUMERATE_SUB_KEYS, out hkey) != Windows.S_OK)
continue;
}
else
{
if (Windows.RegOpenKeyExA(Windows.HKEY_CURRENT_USER, @"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts", 0,
Windows.KEY_QUERY_VALUE | Windows.KEY_WOW64_32KEY | Windows.KEY_ENUMERATE_SUB_KEYS, out hkey) != Windows.S_OK)
continue;
}

if (pass == 0)
defer Windows.RegCloseKey(hkey);

for (int32 i = 0; true; i++)
{
char16[256] fontNameArr;
uint32 nameLen = 255;
uint32 valType = 0;

char16[256] data;
uint32 dataLen = 256 * 2;
int32 result = Windows.RegEnumValueW(hkey, i, &fontNameArr, &nameLen, null, &valType, &data, &dataLen);
if (result == 0)
{
if (Windows.RegOpenKeyExA(Windows.HKEY_LOCAL_MACHINE, @"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts", 0,
Windows.KEY_QUERY_VALUE | Windows.KEY_WOW64_32KEY | Windows.KEY_ENUMERATE_SUB_KEYS, out hkey) != Windows.S_OK)
continue;
if (valType == 1)
{
String fontName = scope String(&fontNameArr);
int parenPos = fontName.IndexOf(" (");
if (parenPos != -1)
fontName.RemoveToEnd(parenPos);
fontName.ToUpper();
String fontPath = scope String(&data);
if ((!fontPath.EndsWith(".TTF", .OrdinalIgnoreCase)) && (!fontPath.EndsWith(".TTC", .OrdinalIgnoreCase)))
continue;

if (fontName.Contains('&'))
{
int collectionIdx = 0;
for (var namePart in fontName.Split('&', .RemoveEmptyEntries))
{
namePart.Trim();
if (sFontNameMap.TryAddAlt(namePart, var keyPtr, var valuePtr))
{
*keyPtr = new String(namePart);
*valuePtr = new $"{fontPath}@{collectionIdx}";
collectionIdx++;
}
}
}
else if (sFontNameMap.TryAdd(fontName, var keyPtr, var valuePtr))
{
*keyPtr = new String(fontName);
*valuePtr = new String(fontPath);
}
}
}
else
{
if (Windows.RegOpenKeyExA(Windows.HKEY_CURRENT_USER, @"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts", 0,
Windows.KEY_QUERY_VALUE | Windows.KEY_WOW64_32KEY | Windows.KEY_ENUMERATE_SUB_KEYS, out hkey) != Windows.S_OK)
if (result == Windows.ERROR_MORE_DATA)
continue;

break;
}
}
}
#elif BF_PLATFORM_LINUX
if (!IsFontconfigAvailable)
return;

defer Windows.RegCloseKey(hkey);
if (FcInit() == 0)
return;

defer FcFini();

let pattern = FcPatternCreate();
defer FcPatternDestroy(pattern);
let objectset = FcObjectSetBuild(FC_FAMILY, FC_STYLE, FC_WEIGHT, FC_SLANT, FC_FILE, null);
defer FcObjectSetDestroy(objectset);

for (int32 i = 0; true; i++)
let fontSet = FcFontList(null, pattern, objectset);
if (fontSet == null)
return;
defer FcFontSetDestroy(fontSet);

for (let i < fontSet.nfont)
{
let font = fontSet.fonts[i];

char8* pFile = null;
if (FcPatternGetString(font, FC_FILE, 0, &pFile) != .Match)
{
continue;
}

char8* pFamily = null;
if (FcPatternGetString(font, FC_FAMILY, 0, &pFamily) != .Match)
{
continue;
}

char8* pStyle = null;
FcPatternGetString(font, FC_STYLE, 0, &pStyle);
c_int weight = 0;
let isRegular = (FcPatternGetInteger(font, FC_WEIGHT, 0, &weight) == .Match) && (weight == 80);
c_int slant = 0;
let isRoman = (FcPatternGetInteger(font, FC_SLANT, 0, &slant) == .Match) && (slant == 0);

let filepath = StringView(pFile);
let familyName = StringView(pFamily);

String fontName = scope .(48);
fontName.Append(familyName);
if (pStyle != null)
{
char16[256] fontNameArr;
uint32 nameLen = 255;
uint32 valType = 0;

char16[256] data;
uint32 dataLen = 256 * 2;
int32 result = Windows.RegEnumValueW(hkey, i, &fontNameArr, &nameLen, null, &valType, &data, &dataLen);
if (result == 0)
if (isRegular && isRoman)
{
if (valType == 1)
fontName.ToUpper();

if (sFontNameMap.TryAdd(fontName, let pKey, let pVal))
{
String fontName = scope String(&fontNameArr);
int parenPos = fontName.IndexOf(" (");
if (parenPos != -1)
fontName.RemoveToEnd(parenPos);
fontName.ToUpper();
String fontPath = scope String(&data);
if ((!fontPath.EndsWith(".TTF", .OrdinalIgnoreCase)) && (!fontPath.EndsWith(".TTC", .OrdinalIgnoreCase)))
continue;

if (fontName.Contains('&'))
{
int collectionIdx = 0;
for (var namePart in fontName.Split('&', .RemoveEmptyEntries))
{
namePart.Trim();
if (sFontNameMap.TryAddAlt(namePart, var keyPtr, var valuePtr))
{
*keyPtr = new String(namePart);
*valuePtr = new $"{fontPath}@{collectionIdx}";
collectionIdx++;
}
}
}
else if (sFontNameMap.TryAdd(fontName, var keyPtr, var valuePtr))
{
*keyPtr = new String(fontName);
*valuePtr = new String(fontPath);
}
(*pKey) = new String(fontName);
(*pVal) = new String(filepath);
}
}
else
{
if (result == Windows.ERROR_MORE_DATA)
continue;

break;
}
fontName..Append(' ').Append(pStyle);
}

fontName.ToUpper();

if (sFontNameMap.TryAdd(fontName, let pKey, let pVal))
{
(*pKey) = new String(fontName);
(*pVal) = new String(filepath);
}
}
}
}
#endif
}
}

public static void ClearFontNameCache()
Expand Down Expand Up @@ -536,24 +689,36 @@ namespace Beefy.gfx
BuildFontNameCache();
String pathStr;
let lookupStr = scope String(fontName)..ToUpper();
#if BF_PLATFORM_WINDOWS
if (sFontNameMap.TryGetValue(lookupStr, out pathStr))
{
#if BF_PLATFORM_WINDOWS
if (!pathStr.Contains(':'))
{
char8[256] windowsDir;
Windows.GetWindowsDirectoryA(&windowsDir, 256);
path.Append(&windowsDir);
path.Append(@"\Fonts\");
}
#endif

path.Append(pathStr);
return;
}
#endif
if ((sFontFailMap != null) && (sFontFailMap.TryGetValue(lookupStr, out pathStr)))
{
path.Append(pathStr);
StringView lastPath = pathStr;
for (let fontFailName in pathStr.Split('\0', .RemoveEmptyEntries))
{
let failName = scope String(fontFailName)..ToUpper();
if (sFontNameMap.TryGetValue(failName, out pathStr))
{
GetFontPath(fontFailName, path);
return;
}
lastPath = fontFailName;
}

path.Append(lastPath);
return;
}
}
Expand Down
Loading