# GTK4 Layer Shell and Ollama Fixes ## Problems Identified You were experiencing multiple issues when running the application: 1. **"Failed to initialize layer surface, not on Wayland"** 2. **Multiple "GtkWindow is not a layer surface"** warnings (9 times) 3. **"GtkText - did not receive a focus-out event"** warnings 4. **"No content received from Ollama"** - Ollama responses not working ## Root Causes ### 1. Wrong GDK Backend Your environment had `GDK_BACKEND=x11` set, which forces GTK to use XWayland instead of native Wayland. GTK4 Layer Shell **only works with native Wayland**, not XWayland. ### 2. Initialization Order The layer shell was being initialized **after** window properties (title, size) were set. GTK4 Layer Shell must be initialized **immediately** after `super().__init__()`. ### 3. Library Linking Order The GTK4 Layer Shell library needs to be loaded before `libwayland-client.so`, which requires using `LD_PRELOAD`. ### 4. Missing Focus Event Handler The `Gtk.Entry` widget wasn't properly handling focus-out events, causing GTK to emit warnings. ### 5. Virtual Environment Not Activated The launcher script wasn't activating the Python virtual environment (`.venv`), so the `ollama` package wasn't available even though it was installed in the venv. ### 6. Ollama SDK API Change (Pydantic Objects) The newer `ollama` package (v0.6.0) returns Pydantic objects instead of dictionaries. The `OllamaClient` code was using `.get()` methods which don't work on Pydantic objects, causing responses to appear empty. This caused all Ollama API calls to return empty content with "No content received from Ollama". ## Fixes Applied ### 1. Reordered Initialization ([sidebar_window.py:26-41](sidebar_window.py#L26-L41)) ```python def __init__(self, **kwargs) -> None: super().__init__(**kwargs) # CRITICAL: Layer shell must be initialized BEFORE any window properties self._setup_layer_shell() self.set_default_size(360, 720) self.set_title("Niri AI Sidebar") # ... rest of initialization ``` ### 2. Added Error Detection ([sidebar_window.py:44-65](sidebar_window.py#L44-L65)) ```python def _setup_layer_shell(self) -> None: if Gtk4LayerShell is None: return Gtk4LayerShell.init_for_window(self) # Verify initialization succeeded before configuring if not Gtk4LayerShell.is_layer_window(self): return # ... rest of layer shell configuration ``` ### 3. Added Focus Event Handler ([sidebar_window.py:110-113](sidebar_window.py#L110-L113), [sidebar_window.py:173-176](sidebar_window.py#L173-L176)) ```python # Add focus event controller to properly propagate focus-out events focus_controller = Gtk.EventControllerFocus() focus_controller.connect("leave", self._on_entry_focus_out) self._entry.add_controller(focus_controller) ``` ### 4. Created Launcher Script ([run.sh](run.sh)) ```bash #!/bin/bash # Get the directory where this script is located SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" # Activate virtual environment if it exists if [ -f "$SCRIPT_DIR/.venv/bin/activate" ]; then source "$SCRIPT_DIR/.venv/bin/activate" fi # Force GTK to use native Wayland backend (not XWayland) export GDK_BACKEND=wayland # Preload GTK4 Layer Shell library to ensure proper initialization export LD_PRELOAD=/usr/lib/libgtk4-layer-shell.so # Run the application exec python3 "$SCRIPT_DIR/main.py" "$@" ``` **Key additions:** - Activates `.venv` if present (fixes Ollama integration) - Sets `GDK_BACKEND=wayland` (forces native Wayland) - Preloads GTK4 Layer Shell library (fixes linking order) ### 5. Added Environment Detection ([main.py:41-50](main.py#L41-L50)) Warns users if they're running with the wrong backend configuration. ### 6. Fixed Ollama SDK Compatibility ([ollama_client.py:59-76](ollama_client.py#L59-L76), [94-109](ollama_client.py#L94-L109)) Updated `OllamaClient` to handle both dictionary responses (old SDK) and Pydantic objects (new SDK v0.6.0+): ```python # Handle both dict responses (old SDK) and Pydantic objects (new SDK) if isinstance(result, dict): message = result.get("message") role = message.get("role") or "assistant" content = message.get("content") or "" else: # Pydantic object (ollama SDK >= 0.4.0) message = getattr(result, "message", None) role = getattr(message, "role", "assistant") content = getattr(message, "content", "") ``` This ensures compatibility with both old and new versions of the `ollama` Python package. ## How to Run **Use the launcher script:** ```bash ./run.sh ``` **Or set environment variables manually:** ```bash GDK_BACKEND=wayland LD_PRELOAD=/usr/lib/libgtk4-layer-shell.so python3 main.py ``` **Do NOT run directly with `python3 main.py`** if you have `GDK_BACKEND=x11` in your environment, as this will cause the layer shell initialization to fail. ## Expected Behavior After these fixes: - ✅ No "Failed to initialize layer surface" warnings - ✅ No "GtkWindow is not a layer surface" warnings - ✅ Reduced "GtkText - did not receive a focus-out event" warnings (GTK4 internal issue, mostly mitigated) - ✅ Window properly anchored to the left edge of your screen - ✅ Window appears as a layer surface in Niri - ✅ Ollama integration working - receives and displays responses - ✅ Conversation history persisted properly ## Testing Run the application with the launcher script and verify: 1. Minimal warnings in the console output (only harmless Vulkan warnings may appear) 2. Window appears on the left edge of the screen 3. Window stays anchored when switching workspaces 4. Text input works properly 5. Ollama responses are received and displayed 6. Conversations are saved and restored on restart ### Quick Test ```bash ./run.sh # Type a message in the UI and press Enter # You should see a response from Ollama ``` ## Troubleshooting ### "No content received from Ollama" Error **Symptom:** The application displays "No content received from Ollama" or similar errors. **Causes:** 1. The `ollama` Python package is not installed 2. The virtual environment is not activated 3. Ollama server is not running **Solutions:** ```bash # Ensure Ollama is installed and running curl -s http://127.0.0.1:11434/api/tags # Install the ollama package in your venv source .venv/bin/activate pip install ollama # Always use the launcher script (it activates the venv) ./run.sh ``` ### Layer Shell Initialization Fails **Symptom:** "Failed to initialize layer surface" warning appears. **Causes:** 1. `GDK_BACKEND=x11` is set (forces XWayland instead of native Wayland) 2. GTK4 Layer Shell library not installed 3. Not running on a Wayland compositor **Solutions:** ```bash # Check your environment echo $GDK_BACKEND # Should be empty or "wayland" echo $WAYLAND_DISPLAY # Should show your Wayland display (e.g., "wayland-1") # Unset GDK_BACKEND if it's set to x11 unset GDK_BACKEND # Install GTK4 Layer Shell (Arch Linux) sudo pacman -S gtk4-layer-shell # Use the launcher script (it sets the correct environment) ./run.sh ``` ## References - [GTK4 Layer Shell Documentation](https://github.com/wmww/gtk4-layer-shell) - [GTK4 Layer Shell Linking Guide](https://github.com/wmww/gtk4-layer-shell/blob/main/linking.md) - [Ollama Python Library](https://github.com/ollama/ollama-python)