1. Overview
The FirewallChoiceDialog module provides a GTKmm (GTK4) modal dialog used by BastionGuard to select the firewall backend responsible for applying IP-based blocking (typically driven by the Anti-Phishing subsystem).
The dialog performs lightweight environment discovery and presents context-sensitive actions:
- Select firewalld when available
- Select UFW when available
- Show an installation guidance action when no firewall is detected (and a distro-specific install command is known)
- Allow cancel/close without making changes
The dialog emits a selection signal (signal_firewall_selected) and does not directly apply firewall rules; enforcement is delegated to higher-level backend components.
2. Dependencies and Integrated Components
The dialog integrates the following internal helpers and external libraries:
- GTKmm (GTK4) – UI composition (
Gtk::Window,Gtk::HeaderBar,Gtk::Box,Gtk::Button,Gtk::MessageDialog) - GDK Pixbuf – icon loading for the custom close button
- glib/gi18n – localization via
_() - FirewallDetector – firewall presence and distro detection
- FirewallInstaller – generation of distro-specific installation commands
- Resource loader –
resource("...")for CSS and image asset paths
3. Environment Detection
3.1 Firewall Detection
At construction time, the dialog determines the current firewall context:
detected = FirewallDetector::detectFirewall()– identifies the current firewall type (or none)FirewallDetector::isFirewalldPresent()– checks availability of firewalld tooling/servicesFirewallDetector::isUfwPresent()– checks availability of UFW tooling
The result controls which selection buttons are rendered.
3.2 Distribution Detection
The dialog also detects the distribution:
distro = FirewallDetector::detectDistro()
This value is used exclusively to determine the best-effort installation guidance command when no firewall is available.
4. Window and Styling
4.1 Window Properties
The dialog is configured as a modal, non-resizable window with a fixed default size:
set_default_size(520, 260)set_resizable(false)set_modal(true)
The window title is set to an empty string (set_title("")) to rely on custom header rendering.
4.2 CSS Classes and Theme Integration
Multiple style classes are applied to the window style context:
app-dialogmain-windowapp-window
A CSS provider is loaded using the same application stylesheet as other BastionGuard windows:
Gtk::CssProvider::create()
css->load_from_path(resource("BastionGuard.css"))
The provider is installed at application priority (GTK_STYLE_PROVIDER_PRIORITY_APPLICATION) for consistent theming.
If CSS loading fails, an error is logged and the dialog continues with default styling.
5. Header Bar Implementation
5.1 Custom HeaderBar
The dialog uses a custom header bar with title buttons disabled:
set_show_title_buttons(false)- CSS class
custom-headerbarapplied
5.2 Custom Close Button
A custom close button is implemented using an image asset:
- Loads
icon-close.png(28×28) viaGdk::Pixbuf::create_from_file() - Wraps the pixbuf in
Gtk::Imageand sets it as the button child - On click: closes the dialog using
hide()
If the icon cannot be loaded, a diagnostic message is logged and the dialog remains usable.
6. Content Layout
6.1 Main Container
The dialog content is built inside a vertical box (Gtk::Box) with spacing and margins:
- Orientation: vertical
- Spacing: 15
- Outer margin: 25
- Horizontal alignment: centered
6.2 Labels
The dialog displays:
- Title label centered and styled with CSS class
title - Description label with wrapping enabled and centered alignment
The labels are localized via _().
6.3 Action Buttons and Dynamic Availability
Buttons are placed in a dedicated vertical button container with centered alignment and spacing:
firewalldButton– shown only ifFirewallDetector::isFirewalldPresent()ufwButton– shown only ifFirewallDetector::isUfwPresent()installButton– shown only when no firewall is detected and an install command is availablecancelButton– always present
CSS styling classes are applied for semantic coloring:
btn-successfor selection actionsbtn-warningfor installation guidancebtn-dangerfor cancel action
7. Installation Guidance Workflow
7.1 Install Command Resolution
When no firewall is detected (detected == FirewallType::NONE), the dialog queries a distro-specific recommended installation command:
std::string cmd = FirewallInstaller::getInstallCommand(distro);
If the command is non-empty, the install button label is updated to include the command descriptor:
Install firewall (<cmd>)
7.2 Install Button Behavior
The install button does not execute privileged operations. Instead, it opens an informational dialog presenting the exact command to run:
- MessageType: INFO
- Buttons: OK
- Modal: true
On response, the message dialog is hidden and control returns to the selection dialog.
8. Selection Signals and Control Flow
8.1 Firewall Selection
When the user selects a firewall backend:
firewalldButtonemitsFirewallType::FIREWALLDufwButtonemitsFirewallType::UFW
In both cases, after emitting signal_firewall_selected, the dialog closes via hide().
8.2 Cancel and Close Semantics
The dialog can be dismissed without making a selection via:
- The Cancel button (invokes
hide()) - The custom close button in the header bar (invokes
hide())
No signal is emitted in these dismissal cases.
9. Runtime and Security Considerations
- Non-privileged UI: the dialog does not execute installation or firewall configuration commands; it only guides and emits user choices
- Context-aware rendering: buttons are displayed dynamically based on detected capabilities, reducing user confusion and invalid selections
- Distro-sensitive guidance: installation suggestions are tailored using distro detection, improving operational accuracy
- Consistent theming: application CSS is reused to maintain a unified UI surface across BastionGuard modules
- Graceful degradation: missing CSS or icon assets do not prevent dialog usage
- Localization readiness: user-facing strings are wrapped for translation via
_()