Lagrange is a desktop GUI client for browsing Geminispace.



Lagrange is a desktop GUI client for browsing Geminispace. It offers modern conveniences familiar from web browsers, such as smooth scrolling, inline image viewing, multiple tabs, visual themes, Unicode fonts, bookmarks, history, and page outlines.

Like Gemini, Lagrange has been designed with minimalism in mind. It depends on a small number of essential libraries. It is written in C and uses SDL for hardware-accelerated graphics. OpenSSL is used for secure communications.

Lagrange window open on URL


  • Beautiful typography with full Unicode support
  • Autogenerated page style and symbol for each Gemini domain
  • Smart suggestions when typing the URL — search bookmarks, history, identities
  • Sidebar for page outline, managing bookmarks and identities, and viewing history
  • Multiple tabs
  • Identity management — create and use TLS client certificates
  • Audio playback: MP3, Ogg Vorbis, WAV
  • And much more! Open about:help in the app, or see help.gmi


Prebuilt binaries for Windows, macOS (10.13 or later) and Linux can be found in Releases. You can also find Lagrange on Flathub for Linux.

On macOS you can install and upgrade via Homebrew:

brew install --cask lagrange

Please check MacPorts if you are using macOS 10.12 or older.

On openSUSE Tumbleweed:

sudo zypper install lagrange

How to compile

You need a POSIX-compatible environment to compile Lagrange.

The required tools are a C11 compiler (e.g., Clang or GCC), CMake and pkg-config. Additional tools are required for the optional compilation of HarfBuzz and GNU FriBidi (see next section for details).

  1. Download and extract a source tarball from Releases. Please note that the GitHub/Gitea-generated tarballs do not contain HarfBuzz, GNU FriBidi, or the_Foundation submodules; check which tarball you are getting. Alternatively, you may also clone the repository and its submodules: git clone --recursive --branch release
  2. Check that you have the recommended build tools and dependencies installed: CMake, SDL 2, OpenSSL 1.1.1, libpcre, libunistring, GNU FriBidi, and zlib. For example, on macOS this would do the trick (using Homebrew): brew install cmake sdl2 [email protected] pcre libunistring fribidi Or on Ubuntu: sudo apt install cmake libsdl2-dev libssl-dev libpcre3-dev zlib1g-dev libunistring-dev libfribidi-dev
  3. Optionally, install the mpg123 decoder library for MPEG audio support. For example, the macOS Homebrew package is mpg123 and on Ubuntu it is libmpg123-dev.
  4. Create a build directory.
  5. In your empty build directory, run CMake: cmake {path_of_lagrange_sources} -DCMAKE_BUILD_TYPE=Release
  6. Build it: cmake --build .
  7. Now you can run lagrange, lagrange.exe, or

Unicode text rendering

Lagrange relies on the HarfBuzz and GNU FriBidi libraries for handling complex scripts and bidirectional text. This repository includes these two libraries as submodules. By default, if HarfBuzz and GNU FriBidi are not available on the system, they will be compiled as part of the app without any additional dependencies.

Note that compiling these libraries has the following requirements:

  • HarfBuzz requires a C++ compiler.
  • GNU FriBidi cannot be compiled with CMake; you need to have Meson and Ninja.

If these requirements cannot be met, or you would prefer the use the system-provided HarfBuzz and GNU FriBidi, please refer to the list of build options below: ENABLE_HARFBUZZ_MINIMAL and ENABLE_FRIBIDI_BUILD should both be set to NO. Note that a system-provided HarfBuzz likely has dependencies to other libraries, such as FreeType and GLib.

You also may disable HarfBuzz and/or GNU FriBidi entirely. The old text renderer that only supports non-complex left-to-right scripts is then used.

Installing to a custom directory

By default, the compiled app will be installed to a system-wide location determined by CMake.

Set CMAKE_INSTALL_PREFIX to install to a directory of your choosing:

  1. cmake {path_of_lagrange_sources} -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/dest/path
  2. cmake --build . --target install

Note that the install target also deploys an XDG .desktop file for launching the app.

Build options

CMake Option Description
ENABLE_BINCAT_SH Merge resource files (fonts, etc.) together using a Bash shell script. By default this is OFF, so res/bincat.c is compiled as a native executable for this purpose. However, when cross-compiling, native binaries built during the CMake run may be targeted for the wrong architecture. Set this to ON if you are having problems with bincat while running CMake.
ENABLE_CUSTOM_FRAME Draw a custom window frame. (Only on Microsoft Windows.) The custom frame is more in line with the visual style of the rest of the UI, but does not implement all of the native window behaviors (e.g., snapping, system menu).
ENABLE_DOWNLOAD_EDIT Allow changing the Downloads directory via the Preferences dialog. This should be set to OFF in sandboxed environments where downloaded files must be saved into a specific place.
ENABLE_IDLE_SLEEP Sleep in the main thread instead of waiting for events. On some platforms, SDL_WaitEvent() may have a relatively high CPU usage. Setting this to ON polls for events periodically but otherwise keeps the main thread sleeping, reducing CPU usage. The drawback is that there is a slightly increased latency reacting to new events after idle mode ends.
ENABLE_FRIBIDI Use the GNU FriBidi library for processing bidirectional text. FriBidi implements the Unicode Bidirectional Algorithm to determine text directions.
ENABLE_FRIBIDI_BUILD Compile the GNU FriBidi library as part of the build. If set to OFF, pkg-config is used instead to locate the library.
ENABLE_HARFBUZZ Use the HarfBuzz library for shaping Unicode text. This is required for correctly rendering complex scripts and combining glyphs. If disabled, a simplified text shaping algorithm is used that only works for non-complex languages like English.
ENABLE_HARFBUZZ_MINIMAL Build the HarfBuzz library with all dependencies disabled. Useful when building the app for distribution so that the number of deployed dependencies will be minimized. A system-provided version of HarfBuzz is likely built with dependencies on FreeType and ICU at least. If set to OFF, pkg-config will be used to find HarfBuzz.
ENABLE_IPC Instances of the Lagrange executable communicate via signals or (on Windows) a system-provided IPC mechanism. This is used for controlling an existing Lagrange window via the CLI. If set to OFF, each instance of the app runs without knowledge of other instances. This may cause them to overwrite each other's runtime files.
ENABLE_KERNING Use kerning information in the fonts to adjust glyph placement. Setting this ON improves text appearance in subtle ways but slows down text rendering. It may be a good idea to set this to OFF when running on a slow CPU. This option only affects the simple built-in text renderer, and has no effect on HarfBuzz.
ENABLE_MPG123 Use the mpg123 library for decoding MPEG audio files.
ENABLE_RELATIVE_EMBED Locate resources only in relation to the executable. Useful when any system/predefined directories are not supposed to be accessed, e.g., in the Windows portable build.
ENABLE_RESOURCE_EMBED Embed all resource files into the Lagrange executable instead of keeping them in a separate file that gets loaded at launch. Setting this ON makes it much slower to run CMake and to compile Lagrange.
ENABLE_WEBP Use libwebp to decode .webp images, if pkg-config can find the library.
ENABLE_WINDOWPOS_FIX Set correct window position after the window has already been shown. This may be necessary on some platforms to prevent the window from being restored to the wrong position.
ENABLE_X11_SWRENDER Default to software rendering when running under X11. By default Lagrange attempts to use the GPU for rendering the user interface. You can also use the --sw option at launch to force software rendering.

Compiling on macOS

When using OpenSSL 1.1.1 from Homebrew, you must add its pkgconfig path to your PKG_CONFIG_PATH environment variable, for example:

export PKG_CONFIG_PATH=/opt/homebrew/Cellar/[email protected]/1.1.1i/lib/pkgconfig

Also, SDL's trackpad scrolling behavior on macOS is not optimal for regular GUI apps because it emulates a physical mouse wheel. This may change in a future release of SDL, but at least in 2.0.14 (and earlier) a small patch is required to allow momentum scrolling to come through as single-pixel mouse wheel events. Note that SDL comes with an Xcode project; use the "Shared Library" target and check that you are doing a Release build.

Compiling on Windows

Windows builds require MSYS2. In theory, Clang or GCC (on MinGW) could be set up natively on Windows for compiling everything, but the_Foundation still lacks Win32 implementations for the Socket and Process classes and these are required by Lagrange. Cygwin is a possible alternative to MSYS2, although Cygwin builds have not been tested.

You should use a version of the SDL 2 library that is compiled for native Windows (i.e., the MSVC variant) instead of the version from MSYS2 or MinGW. You can download a copy of the SDL binaries from To make configuration easier in your MSYS2 environment, consider writing a custom sdl2.pc file so pkg-config can automatically find the correct version of SDL. Below is an example of what your sdl2.pc might look like:


Name: sdl2
Description: Simple DirectMedia Layer
Version: 2.0.12-msvc
Libs: ${libdir}/SDL2.dll -mwindows
Cflags: -I${incdir}

The -mwindows option is particularly important as that specifies the target is a GUI application. Also note that you are linking directly against the Windows DLL — do not use any prebuilt .lib files if available, as those as specific to MSVC.

pkg-config will find your .pc file if it is on PKG_CONFIG_PATH or you place it in a system-wide pkgconfig directory.

Once you have compiled a working binary under MSYS2, there is still an additional step required to allow running it directly from the Windows shell: the shared libraries from MSYS2 must be found either via PATH or by copying them to the same directory where lagrange.exe is located.

Compiling on Raspberry Pi

On Raspberry Pi 4/400, you can compile and run Lagrange just like on a regular desktop PC. Accelerated OpenGL graphics should work fine under X11.

On Raspberry Pi 3 or earlier, you should use a version of SDL that is compiled to take advantage of the Broadcom VideoCore OpenGL ES hardware. This provides the best performance when running Lagrange in a console. OpenGL under X11 on Raspberry Pi 2/3 is quite slow/experimental. When running under X11, software rendering is the best choice and the SDL from Raspbian etc. is sufficient.

The following build options are recommended on Raspberry Pi 2/3:

  • ENABLE_KERNING=NO: faster text rendering without noticeable loss of quality
  • ENABLE_WINDOWPOS_FIX=YES: workaround for window position restore issues (SDL bug)
  • ENABLE_X11_SWRENDER=YES: use software rendering under X11

Compiling on iOS

Compiling Lagrange on iOS is moderately difficult.

As a prerequisite, you will need to have an iOS toolchain configuration for CMake. CMake is required for Lagrange itself and for the_Foundation. You will also need Autotools helpers for iOS because HarfBuzz, libiconv, libunistring, and libpcre use Automake. Meson and Ninja are used for GNU FriBidi. The iconfigure script in the Autotools helpers needs to be patched.

After these utilities are available, the scripts in ios/ can be used as a basis for the build. Unfortunately there is no ready-made high-level script for performing all these steps, so you'll need to adapt them individually to your needs.

  1. Meson cross-compilation is controlled with ios/cross-mac-arm64-ios-arm64.ini. Modify it to be compatible with your build system and target device.
  2. ios/ compiles most of the dependencies using Meson, Ninja, and iconfigure. Note that the simulator build has not been set up in these scripts, only the os build.
  3. Clone OpenSSL for iPhone and build it with iOS 9.0 as the minimum version. Deploy the static libraries in $HOME/SDK/ios/$arch/, or wherever you've set IOS_DIR to be.
  4. Create an empty build directory for the_Foundation and run ios/ from there. You may need to adjust the source directory path in the script depending on where you place your build directory.
  5. Now you can make install to build and deploy the_Foundation to IOS_DIR.
  6. Finally, you can run CMake like in ios/ to generate an Xcode project that builds the app.

If FriBidi and HarfBuzz are not used (disabling RTL and complex text rendering), the first step can be skipped and the corresponding build steps in ios/ can be removed. In this case, Meson and Ninja are not needed at all.

User files

On Windows, user files are stored in %HOMEPATH%/AppData/Roaming/fi.skyjake.Lagrange/, unless one is using the portable distribution and there is a userdata/ subdirectory present in the executable directory.

On macOS, user files are stored in ~/Library/Application Support/fi.skyjake.Lagrange/.

On Linux/*BSD/other operating systems, user files stored in ~/.config/lagrange/ unless you have customized the XDG directories, in which case the XDG_CONFIG_HOME environment variable is used to determine where user files saved.

The usage and contents of the user files are described in the Help document. You can delete one or more of the files while Lagrange is not running to reset the corresponding data to the default/empty state.

One instance of Lagrange can be running at a time per user directory.

  • User interface localization

    User interface localization

    All user-visible strings should be looked up via a translation table so the UI can be localized to different languages.

    In practice, wherever there is a user-visible string, it should be replaced with a lookup key. The keys could start with a special symbol, for instance $ Widgets could then perform the lookup from the translation table and keep a pointer to the user-visible string. When the language is changed at runtime, widgets can then just redo the lookup and everything will instantly update.

    Dynamically formatted text is a challenge of its own, but one solution is to translate the format string and use numbered arguments so the order can be changed in the translation (like in Qt).

    EDIT: There is now a Weblate server where you can contribute translations: Contact me if you want to start translating a new language.

    enhancement help wanted 
    opened by skyjake 66
  • Does not build on FreeBSD

    Does not build on FreeBSD

    This is the error I get on FreeBSD 12.1-RELEASE r354233 GENERIC amd64

    > cmake --build .
    Scanning dependencies of target the_Foundation
    [  1%] Building C object lib/the_Foundation/CMakeFiles/the_Foundation.dir/src/the_foundation.c.o
    [  2%] Building C object lib/the_Foundation/CMakeFiles/the_Foundation.dir/src/audience.c.o
    [  3%] Building C object lib/the_Foundation/CMakeFiles/the_Foundation.dir/src/array.c.o
    [  4%] Building C object lib/the_Foundation/CMakeFiles/the_Foundation.dir/src/block.c.o
    [  5%] Building C object lib/the_Foundation/CMakeFiles/the_Foundation.dir/src/blockhash.c.o
    [  6%] Building C object lib/the_Foundation/CMakeFiles/the_Foundation.dir/src/buffer.c.o
    [  7%] Building C object lib/the_Foundation/CMakeFiles/the_Foundation.dir/src/class.c.o
    [  8%] Building C object lib/the_Foundation/CMakeFiles/the_Foundation.dir/src/commandline.c.o
    [  9%] Building C object lib/the_Foundation/CMakeFiles/the_Foundation.dir/src/crc32.c.o
    [ 10%] Building C object lib/the_Foundation/CMakeFiles/the_Foundation.dir/src/file.c.o
    [ 12%] Building C object lib/the_Foundation/CMakeFiles/the_Foundation.dir/src/fileinfo.c.o
    In file included from /usr/home/samuel/src/lagrange/lib/the_Foundation/src/fileinfo.c:39:
    /usr/include/sys/dir.h:41:2: error: "The information in this file should be obtained from <dirent.h>" [-Werror,-W#warnings]
    #warning "The information in this file should be obtained from <dirent.h>"
    /usr/include/sys/dir.h:42:2: error: "and is provided solely (and temporarily) for backward compatibility." [-Werror,-W#warnings]
    #warning "and is provided solely (and temporarily) for backward compatibility."
    2 errors generated.
    gmake[2]: *** [lib/the_Foundation/CMakeFiles/the_Foundation.dir/build.make:212: lib/the_Foundation/CMakeFiles/the_Foundation.dir/src/fileinfo.c.o] Error 1
    gmake[1]: *** [CMakeFiles/Makefile2:142: lib/the_Foundation/CMakeFiles/the_Foundation.dir/all] Error 2
    gmake: *** [Makefile:149: all] Error 2
    opened by samebchase 32
  • Lagrange crashes when it gets redirect response immediately after entering input

    Lagrange crashes when it gets redirect response immediately after entering input

    Hey! Lagrange keeps crashing from time to time after I do one very specific scenario. It happens not immediately but like after 5th or so attempt (I know, very specific... sorry). I discovered this issue while testing my framework and I wouldn't be suprised if I am doing something wrong but I think crash is not expected anyway. I will paste server code snippet that maybe will help to understand scenario.

      app.OnRequest("/input", (request, response) => {
          if (request.Parameters == null)
              response.SetInputHint("Please enter something: ");
              response.Status = StatusCode.Input;
              // redirect with parameters to /show route
              response.SetRedirectURL(request.BaseURL + "/show?" + request.Parameters);
              response.Status = StatusCode.RedirectTemp;
      app.OnRequest("/show", (request, response) => {
          if (request.Parameters == null)
              // redirect back to /input
              response.SetRedirectURL(request.BaseURL + "/input");
              response.Status = StatusCode.RedirectTemp;
              // show what you entered
              response.RenderPlainTextLine("# " + request.Parameters);

    Steps to reproduce:

    1. access route which responds with status code "10", in this case "/input"
    2. enter anything
    3. server gets request with "/input?something" and immediately redirects to "/show?something" (I've tried relative and absolute URL - reproducible with both)
    4. repeat until Lagrange crashes - usually 4-8 attempts.

    I've tried other browsers and I couldn't reproduce the issue.

    Please let me know if you need any additional info.

    P.S. I love your browser!

    opened by aegis-dev 26
  • Network/TLS Failure

    Network/TLS Failure


    I can't access to any gemini website because of this error.

    🖧 Network/TLS Failure
    Failed to communicate with the host. Here is the error message:
    >TLS/SSL handshake failed

    Did i missed something in the parameters ?

    bug needs testing 
    opened by stemy2 20
  • Rasperry Pi touchscreen issue: flinging sensitivity

    Rasperry Pi touchscreen issue: flinging sensitivity

    Probably something to do with SDL, but I cannot use the interface with touch, the taps don't register at all. Long-press for context menu doesn't work either. These work in other apps. I am using a Waveshare HDMI screen with USB touch interface.

    Plugging in a mouse works, but it would be nice if I could browse gemini in tablet mode.

    opened by tobykurien 19
  • Crash building Lagrange from source without installing system wide with older Lagrange installed system wide

    Crash building Lagrange from source without installing system wide with older Lagrange installed system wide

    Current main

    Thread 1 "lagrange" received signal SIGSEGV, Segmentation fault.
    0x0000aaaaaaad3c50 in load_Lang_ (d=0xaaaaaac034e0 <lang_>, id=0xaaaaaabaa380 "en") at /home/alyssa/lagrange/src/lang.c:128
    128	        while (*++ptr) {}
    (gdb) bt
    #0  0x0000aaaaaaad3c50 in load_Lang_ (d=0xaaaaaac034e0 <lang_>, id=0xaaaaaabaa380 "en") at /home/alyssa/lagrange/src/lang.c:128
    #1  0x0000aaaaaaad3db0 in setCurrent_Lang (language=0xaaaaaabaa380 "en") at /home/alyssa/lagrange/src/lang.c:159
    #2  0x0000aaaaaaad3d44 in init_Lang () at /home/alyssa/lagrange/src/lang.c:147
    #3  0x0000aaaaaaab0ca4 in init_App_ (d=0xaaaaaac03160 <app_>, argc=1, argv=0xfffffffff878) at /home/alyssa/lagrange/src/app.c:682
    #4  0x0000aaaaaaab2eb0 in run_App (argc=1, argv=0xfffffffff878) at /home/alyssa/lagrange/src/app.c:1531
    #5  0x0000aaaaaaaae300 in main (argc=1, argv=0xfffffffff878) at /home/alyssa/lagrange/src/main.c:78
    opened by alyssarosenzweig 15
  • Failed to build 1.7.0 on macOS

    Failed to build 1.7.0 on macOS

    Using nix:

    /tmp/nix-build-lagrange-1.7.0.drv-0/source/src/macos.m:573:32: error: use of undeclared identifier 'NSControlStateValueOn'
                    [item setState:NSControlStateValueOn];
    /tmp/nix-build-lagrange-1.7.0.drv-0/source/src/macos.m:667:37: warning: instance method '-convertPointToScreen:' not found (return type defaults to 'id') [-Wobjc-method-access]
        NSPoint screenPoint = [nsWindow convertPointToScreen:(CGPoint){ windowCoord.x, windowCoord.y }];
    /nix/store/3w9lpx6pblj3v9m4fjk2sirfpigjlvlw-apple-framework-AppKit/Library/Frameworks/AppKit.framework/Headers/NSWindow.h:193:12: note: receiver is instance of class declared here
    @interface NSWindow : NSResponder <NSAnimatablePropertyContainer, NSUserInterfaceValidations, NSUserInterfaceItemIdentification, NSAppearanceCustomization, NSAccessibilityElement, NSAccessibility>
    /tmp/nix-build-lagrange-1.7.0.drv-0/source/src/macos.m:667:13: error: initializing 'NSPoint' (aka 'struct CGPoint') with an expression of incompatible type 'id'
        NSPoint screenPoint = [nsWindow convertPointToScreen:(CGPoint){ windowCoord.x, windowCoord.y }];
                ^             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    /tmp/nix-build-lagrange-1.7.0.drv-0/source/src/macos.m:692:33: warning: class method '+controlAccentColor' not found (return type defaults to 'id') [-Wobjc-method-access]
        NSColor *accent = [[NSColor controlAccentColor] colorUsingColorSpace:
    2 warnings and 2 errors generated.

    Using macports:

    :info:build /opt/local/var/macports/build/_Users_sikmir_Projects_macports-ports_net_lagrange/lagrange/work/lagrange-1.7.0/src/macos.m:667:37: warning: instance method '-convertPointToScreen:' not found (return type defaults to 'id') [-Wobjc-method-access]
    :info:build     NSPoint screenPoint = [nsWindow convertPointToScreen:(CGPoint){ windowCoord.x, windowCoord.y }];
    :info:build                                     ^~~~~~~~~~~~~~~~~~~~
    :info:build /System/Library/Frameworks/AppKit.framework/Headers/NSWindow.h:191:12: note: receiver is instance of class declared here
    :info:build @interface NSWindow : NSResponder <NSAnimatablePropertyContainer, NSUserInterfaceValidations, NSUserInterfaceItemIdentification, NSAppearanceCustomization, NSAccessibilityElement, NSAccessibility>
    :info:build            ^
    :info:build /opt/local/var/macports/build/_Users_sikmir_Projects_macports-ports_net_lagrange/lagrange/work/lagrange-1.7.0/src/macos.m:667:13: error: initializing 'NSPoint' (aka 'struct CGPoint') with an expression of incompatible type 'id'
    :info:build     NSPoint screenPoint = [nsWindow convertPointToScreen:(CGPoint){ windowCoord.x, windowCoord.y }];
    :info:build             ^             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    :info:build /opt/local/var/macports/build/_Users_sikmir_Projects_macports-ports_net_lagrange/lagrange/work/lagrange-1.7.0/src/macos.m:692:33: warning: class method '+controlAccentColor' not found (return type defaults to 'id') [-Wobjc-method-access]
    :info:build     NSColor *accent = [[NSColor controlAccentColor] colorUsingColorSpace:
    :info:build                                 ^~~~~~~~~~~~~~~~~~
    :info:build 2 warnings and 1 error generated.
    opened by sikmir 14
  • SDL_VIDEODRIVER=wayland breaks lagrange: no window expose event, no window redraw after move/resize

    SDL_VIDEODRIVER=wayland breaks lagrange: no window expose event, no window redraw after move/resize

    Hiya, I tried forcing lagrange to run under Wayland by setting SDL_VIDEODRIVER=wayland (from the arch wiki). When run under Wayland, Lagrange acts kinda strange, as demonstrated in this video:

    It doesn't render pages properly, doesn't resize/move properly, etc. I'm running Sway WM on Parabola.

    Setting SDL_VIDEODRIVER=x11 (aka running under XWayland) makes it act completely fine again.

    Not sure how I can help debug this, let me know!

    bug wayland 
    opened by sseneca 14
  • Add Atom feed support

    Add Atom feed support

    Even though there is a companion spec for subscribing to Gemini pages, many Gemini sites still use Atom for feeds. Atom and RSS also provide more information that would be useful for feeds. It would be helpful if Lagrange would support Atom and RSS feeds, either directly or by transcoding to Gemini text.

    opened by coldacid 14
  • An errant pixel lights up on selected toolbar icons (XUbuntu 20.04)

    An errant pixel lights up on selected toolbar icons (XUbuntu 20.04)

    I am on XUbuntu 20.04, Lagrange 1.6.5 locally compiled.

    When mousing over the top toolbar over any icon (back-arrow, outline of a personl, home, etc (but not the URL bar), an errant pixel lights up, same color as the frame surrounding the icon. The pixel is located upper-leftish.

    opened by stacksmith 13
  • Broken window on Gnu/Linux Flatpak: top bar missing

    Broken window on Gnu/Linux Flatpak: top bar missing

    On my Fedora 34 with gnome desktop, I am using the Lagrange flatpak from Flathub version 1.6.1 and the top bar is missing: therefor there is no way to move the window arround or to minizise, maximize or close it from the top bar.

    linux wayland flatpak 
    opened by Altonss 13
  • [


    Hi Skyjake,

    this morning I just noticed that Lagrange is crashing clicking the X on any tabs. I usually use ctrl+w to close tabs...

    I am using a local version: Lagrange version 1.13.7

    Built on: FreeBSD 13.1-RELEASE releng/13.1-n250148-fc952ac2212 GENERIC amd64 -- Latest repo --

    Here the output, just launched Lagrange, opened a tab a closed the same tab. Closing tabs with ctrl+w doesn't affect Lagrange.

    ./lagrange -E
    Lagrange: A Beautiful Gemini Client
    <Ln> <Pr> [command] {0:0} window.retain arg:1
    <Ln> <Pr> [command] {0:0} prefs.dialogtab arg:4
    <Ln> <Pr> [command] {0:0} font.changed
    <Ln> <Pr> [command] {0:0} zoom.set arg:100
    <Ln> <Pr> [command] {0:0} smoothscroll arg:1
    <Ln> <Pr> [command] {0:0} scrollspeed arg:10 type:0
    <Ln> <Pr> [command] {0:0} scrollspeed arg:10 type:1
    <Ln> <Pr> [command] {0:0} imageloadscroll arg:0
    <Ln> <Pr> [command] {0:0} cachesize.set arg:10
    <Ln> <Pr> [command] {0:0} memorysize.set arg:200
    <Ln> <Pr> [command] {0:0} urlsize.set arg:8192
    <Ln> <Pr> [command] {0:0} decodeurls arg:1
    <Ln> <Pr> [command] {0:0} linewidth.set arg:38
    <Ln> <Pr> [command] {0:0} linespacing.set arg:1.000000
    <Ln> <Pr> [command] {0:0} tabwidth.set arg:8
    <Ln> <Pr> [command] {0:0} returnkey.set arg:32
    <Ln> <Pr> [command] {0:0} navbar.action.set arg:0 button:0
    <Ln> <Pr> [command] {0:0} navbar.action.set arg:1 button:1
    <Ln> <Pr> [command] {0:0} navbar.action.set arg:13 button:2
    <Ln> <Pr> [command] {0:0} navbar.action.set arg:2 button:3
    <Ln> <Pr> [command] {0:0} ansiescape arg:1
    <Ln> <Pr> [command] {0:0} prefs.animate.changed arg:1
    <Ln> <Pr> [command] {0:0} prefs.archive.openindex.changed arg:1
    <Ln> <Pr> [command] {0:0} prefs.biglede.changed arg:1
    <Ln> <Pr> [command] {0:0} prefs.blink.changed arg:1
    <Ln> <Pr> [command] {0:0} prefs.bottomnavbar.changed arg:0
    <Ln> <Pr> [command] {0:0} prefs.bottomtabbar.changed arg:0
    <Ln> <Pr> [command] {0:0} prefs.evensplit.changed arg:0
    <Ln> <Pr> [command] {0:0} prefs.boldlink.dark.changed arg:1
    <Ln> <Pr> [command] {0:0} prefs.boldlink.light.changed arg:1
    <Ln> <Pr> [command] {0:0} prefs.boldlink.visited.changed arg:0
    <Ln> <Pr> [command] {0:0} prefs.bookmarks.addbottom.changed arg:1
    <Ln> <Pr> [command] {0:0} prefs.centershort.changed arg:1
    <Ln> <Pr> [command] {0:0} prefs.collapsepreonload.changed arg:0
    <Ln> <Pr> [command] {0:0} prefs.dataurl.openimages.changed arg:0
    <Ln> <Pr> [command] {0:0} prefs.font.smooth.changed arg:1
    <Ln> <Pr> [command] {0:0} prefs.font.warnmissing.changed arg:1
    <Ln> <Pr> [command] {0:0} prefs.hoverlink.changed arg:1
    <Ln> <Pr> [command] {0:0} prefs.justify.changed arg:0
    <Ln> <Pr> [command] {0:0} prefs.markdown.viewsource.changed arg:1
    <Ln> <Pr> [command] {0:0} prefs.mono.gemini.changed arg:0
    <Ln> <Pr> [command] {0:0} prefs.mono.gopher.changed arg:0
    <Ln> <Pr> [command] {0:0} prefs.plaintext.wrap.changed arg:1
    <Ln> <Pr> [command] {0:0} prefs.sideicon.changed arg:1
    <Ln> <Pr> [command] {0:0} prefs.time.24h.changed arg:1
    <Ln> <Pr> [command] {0:0} arg:1
    <Ln> <Pr> [command] {0:0} parentnavskipindex arg:1
    <Ln> <Pr> [command] {0:0} quoteicon.set arg:1
    <Ln> <Pr> [command] {0:0} theme.set arg:1 auto:1
    <Ln> <Pr> [command] {0:0} accent.set arg:1
    <Ln> <Pr> [command] {0:0} ostheme arg:0 preferdark:-1 preferlight:-1
    <Ln> <Pr> [command] {0:0} doctheme.dark.set arg:0
    <Ln> <Pr> [command] {0:0} doctheme.light.set arg:5
    <Ln> <Pr> [command] {0:0} saturation.set arg:100
    <Ln> <Pr> [command] {0:0} imagestyle.set arg:0
    <Ln> <Pr> [command] {0:0} proxy.gemini address:
    <Ln> <Pr> [command] {0:0} proxy.gopher address:
    <Ln> <Pr> [command] {0:0} proxy.http address:
    <Ln> <Pr> [command] {0:0} downloads path:/home/freezer/Downloads
    <Ln> <Pr> [command] {0:0} searchurl address:gemini://
    <Ln> <Pr> [command] {0:0} translation.languages from:3 to:2
    [window] renderer: opengl (accelerated)
    <Ln> [command] {0:1} input.resized ptr:0x801a63380 arg:1
    <Ln> [command] {0:1} input.resized ptr:0x80e9a2c80 arg:1
    <Ln> [command] {0:0} window.resized
    <Ln> [command] {0:1} layout.changed ptr:0x80e86aac0 id:navbar
    <Ln> [command] {0:0} document.layout.changed
    <Ln> [command] {0:0} document.layout.changed redo:1
    <Ln> [command] {0:0} document.layout.changed redo:1
    <Ln> [command] {0:0} document.layout.changed
    <Ln> [command] {0:0} font.changed
    <Ln> [command] {0:0} font.changed
    <Ln> [command] {0:0} font.changed
    <Ln> [command] {0:0} document.layout.changed
    <Ln> [command] {0:0} document.layout.changed
    <Ln> [command] {0:0} document.layout.changed redo:1
    <Ln> [command] {0:0} theme.changed auto:1
    <Ln> [command] {1:1} layout.changed ptr:0x80e86aac0 id:navbar
    <Ln> [command] {1:1} sidebar.mode arg:4
    <Ln> [command] {1:1} sidebar2.mode arg:0
    <Ln> [command] {1:1} sidebar.toggle noanim:1
    <Ln> [command] {1:1} document.changed doc:0x804b54100 url:gemini://
    <Ln> [command] {1:1} tab.created id:document002
    <Ln> [command] {1:1} document.changed doc:0x80e994300 url:gemini://
    <Ln> [command] {1:1} tab.created id:document003
    <Ln> [command] {1:1} document.changed doc:0x80e994800 url:gemini://
    <Ln> [command] {1:1} tab.created id:document004
    <Ln> [command] {1:1} document.changed doc:0x80e994d00 url:gemini://
    <Ln> [command] {1:1} tab.created id:document005
    <Ln> [command] {1:1} document.changed doc:0x80e995200 url:gemini://
    <Ln> [command] {1:1} tab.created id:document006
    <Ln> [command] {1:1} document.changed doc:0x80e995700 url:gemini://
    <Ln> [command] {1:1} tab.created id:document007
    <Ln> [command] {1:1} document.changed doc:0x80e996100 url:gemini://
    <Ln> [command] {1:1} tab.created id:document008
    <Ln> [command] {1:1} document.changed doc:0x80e995c00 url:gemini://
    <Ln> [command] {1:1} tab.created id:document009
    <Ln> [command] {1:1} document.changed doc:0x80e996600 url:gemini://
    <Ln> [command] {1:1} tabs.switch page:0x80e996600
    <Ln> [command] {0:0} tabs.switch page:0x0
    <Ln> [command] {0:0} font.reset
    <Ln> [command] {0:0} document.autoreload
    [command] {0:0} sidebar.update
    [command] {0:0} bindings.changed
    [command] {0:0} navbar.actions.changed
    [command] {0:0} toolbar.actions.changed
    [command] {0:0} root.movable
    [command] {0:0} window.unfreeze
    [command] {0:0} focus.set id:
    [command] {0:0} sidebar.mode.changed arg:4
    [command] {1:1} focus.gained ptr:0x80e982400
    [command] {0:0} visited.changed
    [command] {0:0} document.openurls.changed
    [command] {0:0} document.openurls.changed
    [command] {0:0} document.openurls.changed
    [command] {0:0} document.openurls.changed
    [command] {0:0} document.openurls.changed
    [command] {0:0} document.openurls.changed
    [command] {0:0} document.openurls.changed
    [command] {0:0} document.openurls.changed
    [command] {0:0} document.openurls.changed
    [command] {0:0} document.openurls.changed
    [command] {0:0} document.openurls.changed
    [command] {0:0} document.openurls.changed
    [command] {0:0} document.openurls.changed
    [command] {0:0} document.openurls.changed
    [command] {0:0} document.openurls.changed
    [command] {0:0} document.openurls.changed
    [command] {0:0} document.openurls.changed
    [command] {0:0} document.openurls.changed
    [command] {1:1} tabs.changed id:document009
    [command] {1:1} focus.lost ptr:0x80e982400
    [command] {1:1} focus.gained ptr:0x80e9b1f40
    [command] {0:0} window.resized width:896 height:568 horiz:1 vert:1
    [command] {0:0} widget.overflow
    [command] {0:0} theme.changed auto:1
    [command] {0:0} window.resized
    [command] {0:0} media.player.update
    [command] {1:1} focus.lost ptr:0x80e9b1f40
    [command] {0:0} window.focus.gained
    [command] {1:1} layout.changed ptr:0x80e86aac0 id:navbar
    [command] {1:1} layout.changed ptr:0x80e86aac0 id:navbar
    [command] {0:0} bookmarks.request.finished req:0x80e978d40
    [command] {0:0} bookmarks.changed
    [command] {0:0} window.mouse.entered
    [command] {1:1} ptr:0x80e9b21c0
    [command] {0:0} tabs.switch page:0x80f196800
    [command] {1:1} tab.created id:document010
    [command] {0:0} navigate.home focus:1
    [command] {1:1} tabs.changed id:document010
    [command] {1:1} open url:about:lagrange
    [command] {1:1} navigate.focus
    [command] {1:1} document.request.started doc:0x80f196800 url:about:lagrange
    [command] {1:1} document.request.updated ptr:0x80f196800 doc:0x80f196800 reqid:2 request:0x80ebf3760
    [command] {1:1} document.request.finished ptr:0x80f196800 doc:0x80f196800 reqid:2 request:0x80ebf3760
    [command] {1:1} focus.gained ptr:0x801a63380
    [command] {1:1} document.changed doc:0x80f196800 status:20 url:about:lagrange
    [command] {0:0} visited.changed
    [command] {0:0} document.openurls.changed
    [command] {0:0} document.openurls.changed
    [command] {1:1} tabs.close ptr:0x80eb72900 id:document010
    [command] {1:1} focus.lost ptr:0x801a63380
    [command] {0:0} document.openurls.changed
    [command] {0:0} tabs.switch page:0x80e996600
    [command] {1:1} input.ended ptr:0x801a63380 id:url enter:0 arg:1
    fish: Job 1, './lagrange -E' terminated by signal SIGSEGV (Address boundary error)
    opened by Cicorione 3
  • SVG support

    SVG support

    Just searched the issues/PRs and nothing came up. Also searched the repo and the only hit seems to be something to do with fonts. Weird...

    Are there plans to support SVG images? Or am I perhaps missing something?

    I'm using Lagrange v1.13.7 installed with Nix, and I get this:


    So apparently Lagrange knows it's an image, just can't load it. Here's an example file, genereated with GraphViz:

    <?xml version="1.0" encoding="UTF-8" standalone="no"?>
    <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
    <!-- Generated by graphviz version 2.43.0 (0)
    <!-- Title: folder1 Pages: 1 -->
    <svg width="465pt" height="91pt"
     viewBox="0.00 0.00 465.38 91.19" xmlns="" xmlns:xlink="">
    <g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 87.19)">
    <polygon fill="white" stroke="transparent" points="-4,4 -4,-87.19 461.38,-87.19 461.38,4 -4,4"/>
    <!-- input -->
    <g id="node1" class="node">
    <ellipse fill="none" stroke="black" cx="35.1" cy="-41.6" rx="35.19" ry="35.19"/>
    <text text-anchor="middle" x="35.1" y="-37.9" font-family="Times,serif" font-size="14.00">input</text>
    <!-- kons -->
    <g id="node4" class="node">
    <polygon fill="none" stroke="black" points="160.19,-59.6 106.19,-59.6 106.19,-23.6 160.19,-23.6 160.19,-59.6"/>
    <text text-anchor="middle" x="133.19" y="-37.9" font-family="Times,serif" font-size="14.00">kons</text>
    <!-- input&#45;&gt;kons -->
    <g id="edge1" class="edge">
    <path fill="none" stroke="black" d="M70.25,-41.6C78.52,-41.6 87.39,-41.6 95.76,-41.6"/>
    <polygon fill="black" stroke="black" points="96.01,-45.1 106.01,-41.6 96.01,-38.1 96.01,-45.1"/>
    <!-- output -->
    <g id="node2" class="node">
    <ellipse fill="none" stroke="black" cx="415.79" cy="-41.6" rx="41.69" ry="41.69"/>
    <text text-anchor="middle" x="415.79" y="-37.9" font-family="Times,serif" font-size="14.00">output</text>
    <!-- acc -->
    <g id="node3" class="node">
    <ellipse fill="none" stroke="black" cx="222.19" cy="-41.6" rx="26" ry="26"/>
    <text text-anchor="middle" x="222.19" y="-37.9" font-family="Times,serif" font-size="14.00">acc</text>
    <!-- acc&#45;&gt;kons -->
    <g id="edge2" class="edge">
    <path fill="none" stroke="black" d="M196.89,-47.72C188.7,-48.29 179.38,-48.47 170.47,-48.26"/>
    <polygon fill="black" stroke="black" points="170.43,-44.76 160.3,-47.84 170.14,-51.75 170.43,-44.76"/>
    <!-- peek -->
    <g id="node5" class="node">
    <polygon fill="none" stroke="black" points="338.19,-59.6 284.19,-59.6 284.19,-23.6 338.19,-23.6 338.19,-59.6"/>
    <text text-anchor="middle" x="311.19" y="-37.9" font-family="Times,serif" font-size="14.00">peek</text>
    <!-- acc&#45;&gt;peek -->
    <g id="edge4" class="edge">
    <path fill="none" stroke="black" d="M247.89,-35.44C255.98,-34.9 265.14,-34.73 273.9,-34.93"/>
    <polygon fill="black" stroke="black" points="273.77,-38.43 283.91,-35.34 274.06,-31.43 273.77,-38.43"/>
    <!-- kons&#45;&gt;acc -->
    <g id="edge3" class="edge">
    <path fill="none" stroke="black" d="M160.3,-35.35C168.64,-34.84 178.01,-34.72 186.85,-34.98"/>
    <polygon fill="black" stroke="black" points="186.73,-38.48 196.89,-35.47 187.07,-31.49 186.73,-38.48"/>
    <!-- peek&#45;&gt;output -->
    <g id="edge6" class="edge">
    <path fill="none" stroke="black" d="M338.34,-41.6C346.11,-41.6 354.9,-41.6 363.68,-41.6"/>
    <polygon fill="black" stroke="black" points="363.92,-45.1 373.92,-41.6 363.92,-38.1 363.92,-45.1"/>
    <!-- peek&#45;&gt;acc -->
    <g id="edge5" class="edge">
    <path fill="none" stroke="black" d="M283.91,-47.85C275.78,-48.34 266.69,-48.47 258.07,-48.23"/>
    <polygon fill="black" stroke="black" points="258.04,-44.72 247.89,-47.75 257.71,-51.71 258.04,-44.72"/>

    Thanks for the awesome browser!

    opened by siiky 1
  • Feature request: Search keywords for the NavBar

    Feature request: Search keywords for the NavBar

    Please add a keyword search feature to the navbar.

    Usecase: quick searches, such as using newswaffle to read a page from the old-web within gemini, without distractions.

    I didn't quite have a pressing need for that features, but with newswaffle "search-engine" (aka cgi-script aka web-to-gemini-proxy, aka web-reader-mode for gemini :-) ), this has definitely changed.

    Example use: E.g. find a web link mentioned in the text, copy it, open a new tab, go to navbar, type a searchkeyword of your choice a space and paste the link (ok, ensure prefix https://, as newswaffle seems to require it). Lagrange is looking for the keyword and the associated search machine url, and replaces the %s in gemini:// with the text after the keyword from the navbar, and displays the output for that modified url. Basically firefox or chrome keyword-search behaviour.

    This is likely a generalization of [] (Issue 157). And it also permits to leave the global search engine unset, so you've navbar searches without leaking by accidental searches from the navbar: just unset the global search url in the preferences.

    Optional extension would be to offer context-menu search for highlighted words in one of the <top 5 or e.g. somehow flagged search engines from the search engine table>, again similar to firefox.

    Thx, Peter

    opened by jakobi 0
  • seeing crashes opening gopher pages in Lagrange on macos

    seeing crashes opening gopher pages in Lagrange on macos

    MacOS 12.4 Lagrange 1.13.7

    I'm a new user and the first 3 or 4 different gopher pages I tried crashed Lagrange. I've tried opening from other apps and pasting the url into Lagrange, same result.

    Ah ha! If Lagrange is not running, then links open okay. But if the app is already running whenI try to open a gopher page then it crashes

    macos gopher 
    opened by cquenelle 2
  • Setting for feed refresh frequency

    Setting for feed refresh frequency

    There should be a setting for specifying how often subscribed feeds are refreshed. For example:

    • never (only manually)
    • once per hour
    • every 4 hours (current behavior)
    • once per day
    opened by skyjake 0
  • Possible Titan Bug

    Possible Titan Bug

    If the Titan server errors out (for example, because the file size is too big, or wrong mimetype, or no certificate or token) while a relatively big file (e.g. 5MB) upload is still uploading, instead of showing the error message sent by the server, this message is shown:


    There's a chance this could just be a problem with my own server, but I'm not entirely sure.

    opened by krixano 1
This is a collection of widgets and utilities for the immediate mode GUI (imgui) that I am developing for the critic2 GUI

ImGui Goodies This is a collection of widgets and utilities for the immediate mode GUI (imgui) that I am developing for the critic2 GUI. Currently, th

null 95 Jun 22, 2022
DeskGap is a framework for building cross-platform desktop apps with web technologies (JavaScript, HTML and CSS).

A cross-platform desktop app framework based on Node.js and the system webview

Wang, Chi 1.8k Jul 28, 2022
AirPods desktop user experience enhancement program

AirPodsDesktop AirPods desktop user experience enhancement program

Sprite 246 Aug 6, 2022
Modern Window Sitter for X11 based Desktop Environments

Modern Window Sitter for X11 based Desktop Environments (Coming to Wayland, Windows and Mac soon-ish). But using with a terminal emulator is recommended.

Antony Jr 34 Jul 2, 2022
Electron framework lets you write cross-platform desktop applications using JavaScript, HTML and CSS.

?? Available Translations: ???? ???? ???? ???? ???? ???? ???? ???? . View these docs in other languages at electron/i18n. The Electron framework lets

Electron 102.8k Jul 30, 2022
Build performant, native and cross-platform desktop applications with Node.js and CSS like styling. 🚀

NodeGui Build performant, native and cross-platform desktop applications with Node.js and CSS like styling. ?? NodeGUI is powered by Qt5 ?? which make

NodeGui 7.8k Jul 27, 2022
Neutralinojs is a lightweight and portable desktop application development framework

Neutralinojs is a lightweight and portable desktop application development framework. It lets you develop lightweight cross-platform desktop applications using JavaScript, HTML and CSS.

Neutralinojs 5.9k Aug 4, 2022
Radio.Garden desktop app and game overlay

Radio.Garten A desktop client and overlay written with SDL2 and ImGui Overlay Example Overlay Compatibility Please check the compatibilit

null 9 May 31, 2022
Purely native C++ cross-platform GUI framework for Android and iOS development.

BODEN CROSS-PLATFORM FRAMEWORK Build purely native cross-platform experiences with Boden Website ⬡ Getting Started ⬡ API Reference ⬡ Guides ⬡ Twitter

Ashampoo Systems GmbH & Co KG 1.5k Jul 31, 2022
Elements C++ GUI library

Elements C++ GUI library Introduction Elements is a lightweight, fine-grained, resolution independent, modular GUI library. Elements is designed with

Cycfi Research 2.3k Aug 5, 2022
Minimalistic C++/Python GUI library for OpenGL, GLES2/3, Metal, and WebAssembly/WebGL

NanoGUI NanoGUI is a minimalistic cross-platform widget library for OpenGL 3+, GLES 2/3, and Metal. It supports automatic layout generation, stateful

Mitsuba Physically Based Renderer 1.1k Jul 29, 2022
A single-header ANSI C immediate mode cross-platform GUI library

Nuklear This is a minimal-state, immediate-mode graphical user interface toolkit written in ANSI C and licensed under public domain. It was designed a

Immediate Mode UIs, Nuklear, etc. 5.9k Aug 4, 2022
A library for creating native cross-platform GUI apps

Yue A library for creating native cross-platform GUI apps. Getting started Documentations FAQ Development Examples Sample apps (with screenshots) Muba

Yue 2.8k Jul 27, 2022
A barebones single-header GUI library for Win32 and X11.

luigi A barebones single-header GUI library for Win32 and X11. Building example Windows Update luigi_example.c to #define UI_WINDOWS at the top of the

Nakst 182 Jul 24, 2022
Clight GUI written in Qt.

CLight GUI Clight GUI written in Qt. Huge thanks to @FedeDP for writing Clight and Clightd, the daemons upon which this is built on.

null 56 Aug 5, 2022
YARA pattern matching scannner GUI

YARA GUI This is a GUI for the binary pattern matching scanner YARA. Features Drag and drop targets Directory scanning Compiled rule cache Favorite/re

null 9 Jul 2, 2021
It's a simple Canvas GUI for Unreal Engine 4 with mouse operation

ue4-canvas-gui It's a simple Canvas GUI for Unreal Engine 4 with mouse operation. Included elements: Rendering Text (left/center); Rendering Rects; Re

Superior. 43 Jul 28, 2022
Proof-of-concept code to reconstruct the GUI of a Xen guest running Windows

vmi-reconstruct-gui A proof-of-concept to reconstruct the GUI of a Xen VM running Windows 7. ❗ Disclaimer This repository is work in progress. It curr

Jan 12 Oct 22, 2021
Nvui: A NeoVim GUI written in C++ and Qt

Nvui: A NeoVim GUI written in C++ and Qt

Rohit Pradhan 1.6k Aug 6, 2022