### Command-Line Usage for Proton VPN App (Bash) Source: https://context7.com/protonvpn/proton-vpn-gtk-app/llms.txt Provides examples of how to launch the Proton VPN application from the command line. It covers standard launch, displaying version information, starting minimized, running from source, and executing integration tests. ```bash # Standard launch protonvpn-app # Display version and exit protonvpn-app --version protonvpn-app -v # Start minimized to system tray protonvpn-app --start-minimized # Running from source (development) python -m proton.vpn.app.gtk # Run integration tests with virtual framebuffer (headless) xvfb-run -a behave tests/integration/features ``` -------------------------------- ### Set Up Virtual Environment and Install Dependencies Source: https://github.com/protonvpn/proton-vpn-gtk-app/blob/stable/README.md Creates a Python virtual environment named 'venv', activates it, and installs project dependencies from 'requirements.txt'. ```shell python3 -m venv venv source venv/bin/activate pip install -r requirements.txt ``` -------------------------------- ### Run Integration Tests with Xvfb Source: https://github.com/protonvpn/proton-vpn-gtk-app/blob/stable/README.md Runs integration tests on headless systems using Xvfb (virtual framebuffer). Requires the 'xvfb' package to be installed on Debian-based systems. ```shell xvfb-run -a behave integration_tests/features ``` -------------------------------- ### Configure Internal Python Package Registry Source: https://github.com/protonvpn/proton-vpn-gtk-app/blob/stable/README.md Configures pip to use an internal Python package registry, which is necessary for installing Proton VPN components. Requires a GitLab token and group ID. ```shell pip config set global.index-url https://__token__:{GITLAB_TOKEN}@{GITLAB_INSTANCE}/api/v4/groups/{GROUP_ID}/-/packages/pypi/simple ``` -------------------------------- ### Initialize Git Submodules Source: https://github.com/protonvpn/proton-vpn-gtk-app/blob/stable/README.md This command is used to clone necessary submodules after cloning the main repository. It ensures all required external components are downloaded. ```shell git submodule update --init --recursive ``` -------------------------------- ### Application Entry Point - Python Source: https://context7.com/protonvpn/proton-vpn-gtk-app/llms.txt The main entry point for the Proton VPN GTK application. It initializes the asynchronous executor, exception handler, and controller before launching the GTK application. This bootstraps all necessary services for VPN connectivity. ```python #!/usr/bin/env python # Entry point: proton/vpn/app/gtk/__main__.py import sys from proton.vpn.app.gtk.app import App from proton.vpn.app.gtk.controller import Controller from proton.vpn.app.gtk.utils.exception_handler import ExceptionHandler from proton.vpn.app.gtk.utils.executor import AsyncExecutor def main(): """Runs the Proton VPN GTK application.""" with AsyncExecutor() as executor, ExceptionHandler() as exception_handler: controller = Controller.get(executor, exception_handler) sys.exit(App(controller).run(sys.argv)) if __name__ == "__main__": main() ``` -------------------------------- ### Configure Quick Connect Widget Source: https://context7.com/protonvpn/proton-vpn-gtk-app/llms.txt Implements the QuickConnectWidget for one-click server connections. It dynamically displays connect, cancel, or disconnect buttons based on the current VPN connection state. ```python from proton.vpn.app.gtk.widgets.vpn.quick_connect_widget import QuickConnectWidget from proton.vpn.connection import states # Create quick connect widget quick_connect = QuickConnectWidget(controller=controller) # Widget automatically shows/hides buttons based on state: # - Disconnected: Shows "Quick Connect" button # - Connecting: Shows "Cancel Connection" button # - Connected: Shows "Disconnect" button # - Error: Shows "Cancel Connection" button # Manually update connection state (usually automatic) quick_connect.connection_status_update(states.Disconnected()) # Shows: Quick Connect button quick_connect.connection_status_update(states.Connecting()) # Shows: Cancel Connection button quick_connect.connection_status_update(states.Connected()) # Shows: Disconnect button # Access current state current_state = quick_connect.connection_state ``` -------------------------------- ### Initialize and Run GTK Application Source: https://context7.com/protonvpn/proton-vpn-gtk-app/llms.txt Initializes and runs the main GTK application, handling single-instance enforcement, CSS styling, tray integration, and command-line options. It utilizes the App class which extends Gtk.Application. ```python from gi.repository import Gtk, GLib from proton.vpn.app.gtk.app import App from proton.vpn.app.gtk.controller import Controller from proton.vpn.app.gtk.util import APPLICATION_ID # "com.protonvpn.www" # Create and run the application controller = Controller.get(executor, exception_handler) app = App(controller) # The app supports command-line options: # --version, -v Display version and exit # --start-minimized Start minimized in system tray # Run the application exit_code = app.run(["protonvpn-app", "--start-minimized"]) # Application signals # "app-ready" - Emitted when the app is ready for interaction # Access tray indicator (if available) if app.tray_indicator: app.tray_indicator.reload_pinned_servers() # Access main window if app.window: app.window.present() ``` -------------------------------- ### Manage Settings Window in GTK App Source: https://context7.com/protonvpn/proton-vpn-gtk-app/llms.txt Illustrates the creation and presentation of the `SettingsWindow`, which provides access to account, VPN features, connection, and general preferences. It shows how to set the window as modal and present it, and mentions the different settings sections available. ```python from proton.vpn.app.gtk.widgets.headerbar.menu.settings.settings_window import SettingsWindow # Create settings window settings_window = SettingsWindow( controller=controller, tray_indicator=tray_indicator # Optional ) # Set as modal (blocks parent window interaction) settings_window.set_modal(True) # Show the window settings_window.present() # Settings sections: # - AccountSettings: Display name, plan, usage # - FeatureSettings: NetShield, VPN Accelerator, Port Forwarding # - ConnectionSettings: Protocol, Kill Switch, Custom DNS # - GeneralSettings: Auto-connect, Start minimized, Early access # Notify user when reconnection is needed after settings change settings_window.notify_user_with_reconnect_message( force_notify=False, only_notify_on_active_connection=True ) ``` -------------------------------- ### Integrate System Tray with GTK App Source: https://context7.com/protonvpn/proton-vpn-gtk-app/llms.txt Shows how to create and set up a `TrayIndicator` for system tray integration. It covers programmatic actions like showing/hiding the window, quitting the app, quick connect/disconnect, activating pinned servers, and reloading pinned servers. It also mentions connection status icons. ```python from proton.vpn.app.gtk.widgets.main.tray_indicator import TrayIndicator, TrayIndicatorNotSupported # Create tray indicator tray = TrayIndicator(controller=controller) # Setup with main window (may raise TrayIndicatorNotSupported) try: tray.setup(main_window=window) except TrayIndicatorNotSupported as e: print(f"Tray not available: {e}") # Programmatic actions tray.activate_toggle_app_visibility_menu_entry() # Show/Hide window tray.activate_quit_menu_entry() # Quit application tray.active_connect_entry() # Quick connect tray.activate_disconnect_entry() # Disconnect # Pinned servers if tray.top_most_pinned_server_label: print(f"First pinned: {tray.top_most_pinned_server_label}") tray.activate_top_most_pinned_server_entry() # Connect to first pinned # Reload pinned servers after configuration change tray.reload_pinned_servers() # Connection status icons (automatically updated) # DISCONNECTED_ICON - Gray icon # CONNECTED_ICON - Green icon # ERROR_ICON - Red icon ``` -------------------------------- ### Configure Main Application Window Source: https://context7.com/protonvpn/proton-vpn-gtk-app/llms.txt Configures the primary application window, including the header bar, main widget container, and keyboard shortcuts. It demonstrates how to set window dimensions and add custom keyboard shortcuts. ```python from gi.repository import Gtk from proton.vpn.app.gtk.widgets.main.main_window import MainWindow # MainWindow is created by App.do_activate() window = MainWindow( application=app, controller=controller, notifications=notifications, header_bar=header_bar, main_widget=main_widget, overlay_widget=overlay_widget ) # Window dimensions print(f"Size: {MainWindow.WIDTH}x{MainWindow.HEIGHT}") # 400x600 # Add keyboard shortcuts window.add_keyboard_shortcut( target_widget=search_widget, target_signal="request_focus", shortcut="f" # Ctrl+F to focus search ) # Configure close button behavior # With tray: hide window instead of closing window.configure_close_button_behaviour(tray_indicator_enabled=True) # Without tray: trigger quit confirmation window.configure_close_button_behaviour(tray_indicator_enabled=False) # Quit the application window.quit() # Disconnects close handler and closes window ``` -------------------------------- ### Handle User Authentication with Login Widget Source: https://context7.com/protonvpn/proton-vpn-gtk-app/llms.txt Details the usage of the `LoginWidget` for user authentication, including support for credentials, 2FA, and FIDO2/U2F keys. It shows how to create the widget, listen for the 'user-logged-in' signal, reset the widget, and outlines the typical login flow and kill switch handling on logout. ```python from proton.vpn.app.gtk.widgets.login.login_widget import LoginWidget # Create login widget login_widget = LoginWidget( controller=controller, notifications=notifications, overlay_widget=overlay_widget, main_window=main_window ) # Listen for successful login login_widget.connect("user-logged-in", lambda w: print("User logged in!")) # Reset widget to initial state login_widget.reset() # The login flow: # 1. User enters username/password in login_stack.login_form # 2. If 2FA required, shows two_factor_auth widget # 3. User enters TOTP code or uses security key # 4. On success, emits "user-logged-in" signal # Kill switch handling on logout # If permanent kill switch is enabled, shows disable_killswitch widget # User must disable kill switch before logging in again ``` -------------------------------- ### Display and Interact with Server List in GTK App Source: https://context7.com/protonvpn/proton-vpn-gtk-app/llms.txt Demonstrates how to display a list of available VPN servers based on user tier, iterate through country rows, focus on specific entries, connect to widget signals for updates, and unload the widget. This is primarily for the main server list UI component. ```python # Display servers for a user tier server_list_widget.display( user_tier=2, # Plus tier server_list=controller.server_list ) # Access country rows for country_row in server_list_widget.country_rows: print(f"Country: {country_row.country_name} ({country_row.country_code})") # Focus on specific entry (server or country) server_list_widget.focus_on_entry(widget=None, name_to_search="United States") server_list_widget.focus_on_entry(widget=None, name_to_search="US-CA#1") # Widget signals server_list_widget.connect("ui-updated", lambda w: print("Server list updated")) server_list_widget.connect("filter-complete", lambda w: print("Filter complete")) # Cleanup server_list_widget.unload() ``` -------------------------------- ### Configure Server List Widget Source: https://context7.com/protonvpn/proton-vpn-gtk-app/llms.txt Initializes the ServerListWidget, which displays VPN servers grouped by country. It allows users to expand countries to see individual servers with load indicators and connection buttons. ```python from proton.vpn.app.gtk.widgets.vpn.serverlist.serverlist import ServerListWidget from proton.vpn.session.servers import ServerList # Create server list widget server_list_widget = ServerListWidget(controller=controller) ``` -------------------------------- ### Build Packages using Script Source: https://github.com/protonvpn/proton-vpn-gtk-app/blob/stable/README.md This command executes a Python script to automatically generate package specification files (e.g., for rpmbuild) and changelog files for Debian. ```shell scripts/build_packages.py ``` -------------------------------- ### Configure VPN Widget Interface Source: https://context7.com/protonvpn/proton-vpn-gtk-app/llms.txt Sets up the main VPN widget, which serves as the interface for connection status, quick connect, and server browsing. It includes methods for loading, unloading, and handling connection status updates. ```python from proton.vpn.app.gtk.widgets.vpn.vpn_widget import VPNWidget from proton.vpn.connection.states import State, Connected, Disconnected # VPNWidget is created within MainWidget vpn_widget = VPNWidget( controller=controller, main_window=main_window, overlay_widget=overlay_widget, notifications=notifications ) # Load and display the widget (triggers API calls) vpn_widget.load() # Handle connection status updates (called automatically) def on_status_update(connection_state: State): if isinstance(connection_state, Connected): print("VPN Connected!") elif isinstance(connection_state, Disconnected): print("VPN Disconnected") # Widget ready signal vpn_widget.connect("vpn-widget-ready", lambda w: print("Widget ready")) # Access child widgets status_widget = vpn_widget.connection_status_widget quick_connect = vpn_widget.quick_connect_widget server_list = vpn_widget.server_list_widget search_entry = vpn_widget.search_widget search_results = vpn_widget.search_results_widget # Get user tier user_tier = vpn_widget.user_tier # 0=free, 1=basic, 2=plus, etc. # Unload widget (cleanup) vpn_widget.unload() ``` -------------------------------- ### Run Integration Tests with Behave Source: https://github.com/protonvpn/proton-vpn-gtk-app/blob/stable/README.md Executes integration tests using the Behave framework. This command points to the feature files located in 'tests/integration/features'. ```shell behave tests/integration/features ``` -------------------------------- ### Manage VPN Settings with Controller Source: https://context7.com/protonvpn/proton-vpn-gtk-app/llms.txt The Controller class provides methods for managing VPN settings, including reading and saving general and app-specific configurations with conflict detection. It allows access to nested settings via path notation and offers convenience methods like disabling the kill switch and retrieving available VPN protocols. ```python from proton.vpn.core.settings import Settings from proton.vpn.connection.enum import KillSwitchSetting as KillSwitchSettingEnum # Get current settings settings = controller.get_settings() # Access nested settings using path notation protocol = controller.get_setting_attr("settings.protocol") netshield = controller.get_setting_attr("settings.features.netshield") killswitch = controller.get_setting_attr("settings.killswitch") # Access app configuration settings auto_connect = controller.get_setting_attr("app_configuration.connect_at_app_startup") minimized = controller.get_setting_attr("app_configuration.start_app_minimized") # Save individual settings with automatic conflict resolution controller.save_setting_attr("settings.protocol", "wireguard") controller.save_setting_attr("settings.features.netshield", 1) # 0=off, 1=malware, 2=ads+malware controller.save_setting_attr("settings.killswitch", KillSwitchSettingEnum.ON) # Check for conflicts before changing a setting conflict = controller.setting_attr_has_conflict( "settings.features.netshield", new_value=2 # Enable ad blocking ) if conflict: print(f"Conflict detected: {conflict}") # Save complete settings object settings.protocol = "openvpn-tcp" settings.killswitch = KillSwitchSettingEnum.PERMANENT future = controller.save_settings(settings) future.result() # Wait for save to complete # Disable kill switch (convenience method) controller.disable_killswitch() # Get available VPN protocols protocols = controller.get_available_protocols() for protocol in protocols: print(f"Available: {protocol.cls.ui_protocol}") ``` -------------------------------- ### Manage App Configuration with AppConfig Source: https://context7.com/protonvpn/proton-vpn-gtk-app/llms.txt The AppConfig dataclass handles application-specific settings that persist across sessions. It manages settings like pinned tray servers, auto-connect preferences, and startup behavior. This snippet demonstrates creating default configurations, loading from dictionaries, converting back to dictionaries for persistence, and using a controller to manage these settings. ```python from proton.vpn.app.gtk.config import AppConfig, APP_CONFIG from proton.vpn.core.cache_handler import CacheHandler # Default configuration values DEFAULT_APP_CONFIG = { "tray_pinned_servers": [], "connect_at_app_startup": None, # None, "FASTEST", or server name "start_app_minimized": False } # Create default configuration config = AppConfig.default() print(config.tray_pinned_servers) # [] print(config.connect_at_app_startup) # None print(config.start_app_minimized) # False # Create from dictionary (e.g., loaded from disk) config_data = { "tray_pinned_servers": ["US#1", "CH#5", "JP#3"], "connect_at_app_startup": "fastest", "start_app_minimized": True } config = AppConfig.from_dict(config_data) print(config.connect_at_app_startup) # "FASTEST" (uppercased) # Convert back to dictionary for persistence config_dict = config.to_dict() # Using controller to manage configuration config = controller.get_app_configuration() config.tray_pinned_servers = ["DE#1", "NL#2"] config.start_app_minimized = True controller.save_app_configuration(config) ``` -------------------------------- ### Subscribe to VPN Connection Status Updates (Python) Source: https://context7.com/protonvpn/proton-vpn-gtk-app/llms.txt Demonstrates how to subscribe to VPN connection status changes using an observer pattern in Python. This allows UI widgets to react to states like connecting, connected, disconnected, and errors. It requires the 'proton.vpn.connection.states' module. ```python from proton.vpn.connection.states import State, Connecting, Connected, Disconnecting, Disconnected, Error class MyConnectionStatusWidget: """Example widget that subscribes to connection status updates.""" def __init__(self, controller): self.controller = controller # Register as subscriber controller.register_connection_status_subscriber(self) def status_update(self, connection_state: State): """Called whenever the VPN connection status changes.""" if isinstance(connection_state, Disconnected): if connection_state.context.reconnection: print("Reconnecting...") else: print("Disconnected") elif isinstance(connection_state, Connecting): print("Connecting...") elif isinstance(connection_state, Connected): server_name = connection_state.context.connection.server_name print(f"Connected to {server_name}") elif isinstance(connection_state, Disconnecting): print("Disconnecting...") elif isinstance(connection_state, Error): event = connection_state.context.event print(f"Error: {event}") def cleanup(self): # Unregister when done self.controller.unregister_connection_status_subscriber(self) # Usage widget = MyConnectionStatusWidget(controller) # ... widget receives status_update() calls automatically widget.cleanup() ``` -------------------------------- ### Submit Bug Reports via GTK App Controller Source: https://context7.com/protonvpn/proton-vpn-gtk-app/llms.txt Demonstrates how to create a `BugReportForm` object with necessary details like username, description, and client information, and then submit it using the `controller.submit_bug_report` method. It includes error handling for the submission process with a timeout. ```python from proton.vpn.app.gtk.widgets.headerbar.menu.bug_report_dialog import BugReportForm # Create bug report form data bug_report = BugReportForm( username="user@proton.me", email="user@example.com", description="VPN disconnects randomly when watching video streams. " "Issue occurs after approximately 30 minutes of use.", client_version=controller.app_version, client="Linux GTK App", title="Random disconnections during streaming" ) # Submit bug report future = controller.submit_bug_report(bug_report) try: result = future.result(timeout=30) # Wait up to 30 seconds print("Bug report submitted successfully") except Exception as e: print(f"Failed to submit bug report: {e}") ``` -------------------------------- ### Controller - Core VPN Operations - Python Source: https://context7.com/protonvpn/proton-vpn-gtk-app/llms.txt Demonstrates the core functionalities of the Controller class, which manages VPN operations such as user authentication, connection management, settings, and server list access. It utilizes asynchronous API calls and returns Future objects for non-blocking operations. ```python from proton.vpn.app.gtk.controller import Controller from proton.vpn.app.gtk.utils.executor import AsyncExecutor # Initialize controller (typically done via Controller.get()) executor = AsyncExecutor() executor.start() controller = Controller(executor, exception_handler) # User Authentication login_future = controller.login(username="user@proton.me", password="password123") login_result = login_future.result() # Blocks until complete # Submit 2FA code if required twofa_future = controller.submit_2fa_code(code="123456") twofa_result = twofa_future.result() # Check login status if controller.user_logged_in: print(f"Logged in as: {controller.account_name}") print(f"User tier: {controller.user_tier}") # Connect to VPN servers fastest_future = controller.connect_to_fastest_server() country_future = controller.connect_to_country(country_code="US") server_future = controller.connect_to_server(server_name="US-CA#1") # Disconnect from VPN disconnect_future = controller.disconnect() # Get current connection status current_status = controller.current_connection_status is_active = controller.is_connection_active server_id = controller.current_server_id # Access server list server_list = controller.server_list feature_flags = controller.feature_flags # Logout logout_future = controller.logout() ``` -------------------------------- ### Update Version Information in versions.yml Source: https://github.com/protonvpn/proton-vpn-gtk-app/blob/stable/README.md Adds new versioning information to the 'versions.yml' file. This includes the version number, timestamp, author details, and a description of changes. Requires a '---' separator at the end of the block. ```yaml version: time: