1# Lagrange
2
3Lagrange is a desktop GUI client for browsing [Geminispace](https://gemini.circumlunar.space/). 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.
4
5Like 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](https://libsdl.org/) for hardware-accelerated graphics. [OpenSSL](https://openssl.org/) is used for secure communications.
6
7![Lagrange window open on URL "about:lagrange"](lagrange_about.png)
8
9## Features
10
11* Beautiful typography with full Unicode support
12* Autogenerated page style and symbol for each Gemini domain
13* Smart suggestions when typing the URL — search bookmarks, history, identities
14* Sidebar for page outline, managing bookmarks and identities, and viewing history
15* Multiple tabs
16* Identity management — create and use TLS client certificates
17* Audio playback: MP3, Ogg Vorbis, WAV
18* And much more! Open `about:help` in the app, or see [help.gmi](https://git.skyjake.fi/gemini/lagrange/raw/branch/release/res/about/help.gmi)
19
20## Downloads
21
22Prebuilt binaries for Windows, macOS and Linux can be found in [Releases][rel]. You can also find [Lagrange on Flathub for Linux](https://flathub.org/apps/details/fi.skyjake.Lagrange).
23
24On macOS you can install and upgrade via Homebrew:
25
26    brew install --cask lagrange
27
28On openSUSE Tumbleweed:
29
30    sudo zypper install lagrange
31
32## How to compile
33
34You need a POSIX-compatible environment to compile Lagrange.
35
36The 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).
37
381. Download and extract a source tarball from [Releases][rel]. Please note that the GitHub/Gitea-generated tarballs do not contain HarfBuzz, GNU FriBidi, or [the_Foundation](https://git.skyjake.fi/skyjake/the_Foundation) submodules; check which tarball you are getting. Alternatively, you may also clone the repository and its submodules: `git clone --recursive --branch release https://git.skyjake.fi/gemini/lagrange`
392. 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 openssl@1.1 pcre libunistring fribidi``` Or on Ubuntu: ```sudo apt install cmake libsdl2-dev libssl-dev libpcre3-dev zlib1g-dev libunistring-dev libfribidi-dev```
403. 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`.
414. Create a build directory.
425. In your empty build directory, run CMake: ```cmake {path_of_lagrange_sources} -DCMAKE_BUILD_TYPE=Release```
436. Build it: ```cmake --build .```
447. Now you can run `lagrange`, `lagrange.exe`, or `Lagrange.app`.
45
46### Unicode text rendering
47
48Lagrange relies on the [HarfBuzz](https://harfbuzz.github.io) and [GNU FriBidi](https://github.com/fribidi/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.
49
50Note that compiling these libraries has the following requirements:
51
52* HarfBuzz requires a C++ compiler.
53* GNU FriBidi cannot be compiled with CMake; you need to have [Meson](https://mesonbuild.com) and [Ninja](https://ninja-build.org).
54
55If 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.
56
57You 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.
58
59### Installing to a custom directory
60
61By default, the compiled app will be installed to a system-wide location determined by CMake.
62
63Set `CMAKE_INSTALL_PREFIX` to install to a directory of your choosing:
64
651. `cmake {path_of_lagrange_sources} -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/dest/path`
662. `cmake --build . --target install`
67
68Note that the `install` target also deploys an XDG .desktop file for launching the app.
69
70### Build options
71
72| CMake Option | Description |
73| ------------ | ----------- |
74| `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. |
75| `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). |
76| `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. |
77| `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. |
78| `ENABLE_FRIBIDI` | Use the GNU FriBidi library for processing bidirectional text. FriBidi implements the Unicode Bidirectional Algorithm to determine text directions. |
79| `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. |
80| `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. |
81| `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. |
82| `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. |
83| `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. |
84| `ENABLE_MPG123` | Use the mpg123 library for decoding MPEG audio files. |
85| `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. |
86| `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. |
87| `ENABLE_WEBP` | Use libwebp to decode .webp images, if `pkg-config` can find the library. |
88| `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. |
89| `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. |
90
91### Compiling on macOS
92
93When using OpenSSL 1.1.1 from Homebrew, you must add its pkgconfig path to your `PKG_CONFIG_PATH` environment variable, for example:
94
95    export PKG_CONFIG_PATH=/opt/homebrew/Cellar/openssl@1.1/1.1.1i/lib/pkgconfig
96
97Also, 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](https://git.skyjake.fi/gemini/lagrange/raw/branch/dev/sdl2-macos-ios.diff) 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.
98
99### Compiling on Windows
100
101Windows builds require [MSYS2](https://www.msys2.org). In theory, [Clang](https://clang.llvm.org/docs/MSVCCompatibility.html) or GCC (on [MinGW](http://mingw.org)) 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](http://cygwin.org) is a possible alternative to MSYS2, although Cygwin builds have not been tested.
102
103You 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 [libsdl.org](https://libsdl.org/). 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:
104
105    prefix=/c/SDK/SDL2-2.0.12/
106    arch=x64
107    libdir=${prefix}/lib/${arch}/
108    incdir=${prefix}/include/
109
110    Name: sdl2
111    Description: Simple DirectMedia Layer
112    Version: 2.0.12-msvc
113    Libs: ${libdir}/SDL2.dll -mwindows
114    Cflags: -I${incdir}
115
116The *-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.
117
118`pkg-config` will find your .pc file if it is on `PKG_CONFIG_PATH` or you place it in a system-wide pkgconfig directory.
119
120Once 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.
121
122### Compiling on Raspberry Pi
123
124On 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.
125
126On 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
127slow/experimental. When running under X11, software rendering is the best choice and the SDL from Raspbian etc. is sufficient.
128
129The following build options are recommended on Raspberry Pi 2/3:
130
131* `ENABLE_KERNING=NO`: faster text rendering without noticeable loss of quality
132* `ENABLE_WINDOWPOS_FIX=YES`: workaround for window position restore issues (SDL bug)
133* `ENABLE_X11_SWRENDER=YES`: use software rendering under X11
134
135[rel]: https://git.skyjake.fi/gemini/lagrange/releases
136[tf]:  https://git.skyjake.fi/skyjake/the_Foundation
137
138## User files
139
140On 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.
141
142On macOS, user files are stored in `~/Library/Application Support/fi.skyjake.Lagrange/`.
143
144On 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.
145
146The 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.
147
148One instance of Lagrange can be running at a time per user directory.
149