Linux Platform Guide
The Linux backend uses GTK3 (C) for all native widgets, with Cairo for custom drawing. It is written in pure C and compiled with GCC, providing a native Linux experience that integrates with GNOME, XFCE, KDE, and other GTK-compatible desktop environments.
| Language | C |
|---|---|
| Lines of code | ~7,300 |
| HB_FUNC functions | ~132 |
| Native API | GTK3 (GtkWidget, GtkFixed) |
| Drawing | Cairo / Pango |
| Scintilla | 5.6.1 (shared library) |
| Supported Distros | Ubuntu, Debian, Fedora, openSUSE, Arch, etc. |
Architecture Overview
#xcommand preprocessor"] B --> C["TForm, TControl
Harbour OOP classes"] C --> D["HB_FUNC Bridge
~132 functions"] D --> E["GTK3 Backend
C / GtkWidget"] E --> F["GTK Widgets
GtkButton, GtkEntry, etc."] E --> G["Cairo / Pango
Custom drawing"] E --> H["Scintilla 5.6.1
Shared lib"] style A fill:#58a6ff,stroke:#388bfd,color:#0d1117 style B fill:#8b5cf6,stroke:#7c3aed,color:#fff style C fill:#f59e0b,stroke:#d97706,color:#0d1117 style D fill:#f59e0b,stroke:#d97706,color:#0d1117 style E fill:#e95420,stroke:#c34113,color:#fff style F fill:#e95420,stroke:#c34113,color:#fff style G fill:#e95420,stroke:#c34113,color:#fff style H fill:#555,stroke:#333,color:#fff
Native Window Creation
Every HarbourBuilder form is a GtkWindow with a GtkFixed container for
absolute-positioned child controls. The backend creates GTK widgets and stores their pointers
in a handle table:
// gtk3_backend.c - Creating a form window HB_FUNC( UI_FORMNEW ) { const char * cTitle = hb_parc( 1 ); gint nWidth = hb_parni( 2 ); gint nHeight = hb_parni( 3 ); GtkWidget * window = gtk_window_new( GTK_WINDOW_TOPLEVEL ); gtk_window_set_title( GTK_WINDOW( window ), cTitle ); gtk_window_set_default_size( GTK_WINDOW( window ), nWidth, nHeight ); gtk_window_set_position( GTK_WINDOW( window ), GTK_WIN_POS_NONE ); // Use GtkFixed for absolute positioning of child controls GtkWidget * fixed = gtk_fixed_new(); gtk_container_add( GTK_CONTAINER( window ), fixed ); // Store handle in Harbour-side object table hb_retnint( (gintptr) window ); }
Controls map to GTK3 widgets:
| HarbourBuilder Control | GTK3 Widget |
|---|---|
| Button | gtk_button_new_with_label() |
| Label | gtk_label_new() |
| Edit | gtk_entry_new() |
| Memo | gtk_text_view_new() (in GtkScrolledWindow) |
| CheckBox | gtk_check_button_new_with_label() |
| Radio | gtk_radio_button_new_with_label() |
| ComboBox | gtk_combo_box_text_new() |
| ListBox | gtk_list_box_new() (in GtkScrolledWindow) |
| GroupBox | gtk_frame_new() |
| ProgressBar | gtk_progress_bar_new() |
| Slider/TrackBar | gtk_scale_new_with_range() |
| Image | gtk_image_new_from_file() |
| TabControl | gtk_notebook_new() |
| TreeView | gtk_tree_view_new() (in GtkScrolledWindow) |
| Timer | g_timeout_add() |
| StatusBar | gtk_statusbar_new() |
| ToolBar | gtk_toolbar_new() |
Event Handling (g_signal)
The GTK3 backend uses GObject's signal system (g_signal_connect()) to connect
native widget events to Harbour event handlers:
// gtk3_backend.c - Signal-based event binding HB_FUNC( UI_ONEVENT ) { gint nHandle = hb_parnint( 1 ); gint nEventId = hb_parnint( 2 ); PHB_ITEM pBlock = hb_param( 3, HB_IT_BLOCK ); GtkWidget * widget = GTK_WIDGET( GetHandlePtr( nHandle ) ); // Store the Harbour code block StoreEventBlock( nHandle, nEventId, pBlock ); // Connect the GTK signal to our dispatch function switch( nEventId ) { case EVENT_CLICK: g_signal_connect( widget, "clicked", G_CALLBACK( on_clicked_signal ), GINT_TO_POINTER( nHandle ) ); break; case EVENT_CHANGE: g_signal_connect( widget, "changed", G_CALLBACK( on_changed_signal ), GINT_TO_POINTER( nHandle ) ); break; case EVENT_KEYDOWN: g_signal_connect( widget, "key-press-event", G_CALLBACK( on_key_signal ), GINT_TO_POINTER( nHandle ) ); break; case EVENT_MOUSEDOWN: g_signal_connect( widget, "button-press-event", G_CALLBACK( on_mouse_signal ), GINT_TO_POINTER( nHandle ) ); break; // ... additional signal connections } } // Signal callback dispatches to Harbour static void on_clicked_signal( GtkWidget * widget, gpointer user_data ) { gint nHandle = GPOINTER_TO_INT( user_data ); FireEvent( nHandle, EVENT_CLICK ); }
Dark Mode
GTK3 dark mode is controlled via GTK settings:
gtk-application-prefer-dark-theme— The backend sets this GTK property toTRUEwhen the system is in dark mode. GTK3 themes (like Adwaita-dark) respond by providing dark color schemes for all widgets.- GTK settings daemon — On desktop environments that support it (GNOME, XFCE), GTK3 reads the system theme preference from the settings daemon automatically.
- Manual override — Users can force dark mode by setting the environment variable:
export GTK_THEME=Adwaita:dark
- CSS styling — For fine-grained control, the backend can load a GTK CSS stylesheet that overrides widget colors for the dark theme.
// gtk3_backend.c - Dark theme setup void SetupDarkTheme( void ) { GtkSettings * settings = gtk_settings_get_default(); // Check system theme preference gboolean prefer_dark = IsSystemDarkMode(); g_object_set( settings, "gtk-application-prefer-dark-theme", prefer_dark, NULL ); }
On GNOME, the system theme is read from org.gnome.desktop.interface gtk-theme via
gsettings. The backend checks this at startup and sets
gtk-application-prefer-dark-theme accordingly. On other desktop environments, the
GTK settings daemon provides the same information through the standard GTK settings API.
Scintilla Integration
On Linux, Scintilla 5.6.1 is built as a shared library:
| File | Type | Purpose |
|---|---|---|
libscintilla.so | Shared library | Scintilla core editing component |
liblexilla.so | Shared library | Lexer library |
Scintilla is loaded with dlopen() and dlsym() at runtime. The GTK
Scintilla widget (ScintillaObject) is embedded in the code editor tab:
// Loading Scintilla on Linux void * hSci = dlopen( "libscintilla.so", RTLD_LAZY ); if( !hSci ) { fprintf( stderr, "Failed to load Scintilla: %s\n", dlerror() ); return; } // Creating the Scintilla GTK widget ScintillaObject * sci = scintilla_new(); gtk_container_add( GTK_CONTAINER( editor_scrolled ), GTK_WIDGET( sci ) ); scintilla_send_message( sci, SCI_SETLEXER, SCLEX_CPP, 0 );
Build Process
Prerequisites
- GCC compiler:
sudo apt install gcc g++
- GTK3 development libraries:
sudo apt install libgtk-3-dev
- Harbour 3.2+ — Install from your distro's package manager or build from source:
sudo apt install harbour
Or clone from github.com/harbour/core.
Build Script (build_linux.sh)
The script performs these steps:
- Check prerequisites — Verifies that GCC and GTK3 headers are available.
- Build Scintilla — Compiles Scintilla and Lexilla shared libraries from source.
- Compile Harbour source — Runs the Harbour compiler on the IDE source files.
- Compile the backend — Compiles
gtk3_backend.cwith GCC. - Link — Links everything together with GTK3, Cairo, Pango, and the Harbour runtime.
# build_linux.sh - Typical build session on Ubuntu/Debian # Install dependencies sudo apt update sudo apt install libgtk-3-dev gcc g++ harbour # Build cd HarbourBuilder/samples ./build_linux.sh # Run ../bin/hbbuilder_linux
On Fedora: sudo dnf install gtk3-devel gcc harbour
On Arch: sudo pacman -S gtk3 harbour harbour-contrib
On openSUSE: sudo zypper install gtk3-devel harbour
Compilation Details
# Manual compilation (what build_linux.sh does internally) # 1. Compile Harbour source to C harbour hbbuilder.prg -n -q -gc1 # 2. Compile C backend gcc -O2 -c gtk3_backend.c \ $(pkg-config --cflags gtk+-3.0) \ -I$HBDIR/include \ -I./include # 3. Compile Harbour-generated C code gcc -O2 -c hbbuilder.c \ -I$HBDIR/include # 4. Link gcc -o hbbuilder_linux hbbuilder.o gtk3_backend.o \ $(pkg-config --libs gtk+-3.0) \ -lcairo -lpango-1.0 \ -lscintilla -llexilla \ -L$HBDIR/lib -lharbour \ -ldl -lm
Platform-Specific Features
| Feature | Linux Implementation |
|---|---|
| File dialogs | gtk_file_chooser_dialog_new() with GtkFileChooserNative |
| Font dialog | GtkFontChooserDialog |
| Color dialog | GtkColorChooserDialog |
| Message dialogs | GtkMessageDialog |
| Clipboard | gtk_clipboard_get() / gtk_clipboard_set_text() |
| Drag and drop | GTK drag-and-drop API (gtk_drag_dest_set()) |
| System tray | GtkStatusIcon / AppIndicator (depending on DE) |
| Dark mode | gtk-application-prefer-dark-theme GTK setting |
| Desktop integration | .desktop file, MIME types, icon themes |
| Printing | GtkPrintOperation |
Known Limitations
- Desktop environment variance — GTK3 widgets look different on GNOME, XFCE, KDE, etc. The backend targets the default Adwaita theme. Other themes may produce slightly different appearances.
- GtkFixed layout &mdash> The backend uses
GtkFixedfor absolute positioning (matching the Windows/macOS model). This means controls do not automatically resize or reflow when the window size changes. Use theOnResizeevent for dynamic layout. - Scintilla shared library &mdash> The
libscintilla.somust be in the library search path (LD_LIBRARY_PATHor/usr/local/lib). Runsudo ldconfigafter installing. - Wayland &mdash> GTK3 supports Wayland, but some features (system tray, global menus) may not work under pure Wayland sessions. X11 is fully supported.
Dependencies
| Package/Library | Purpose |
|---|---|
libgtk-3-dev | GTK3 headers and libraries (widgets, windows, events) |
libcairo2-dev | Cairo 2D graphics library (custom drawing) |
libpango1.0-dev | Pango text layout and rendering |
libglib2.0-dev | GLib utility functions (timers, signals, memory) |
libgdk-pixbuf2.0-dev | Image loading and manipulation |
libscintilla.so | Code editing component (shared library) |
liblexilla.so | Lexer component (shared library) |
libharbour | Harbour runtime |
-ldl | Dynamic loading (dlopen/dlsym for Scintilla) |
-lm | Math library |