def run_gui(config: CoreConfig): logger.info("Starting UI") app = QApplication([]) app.setOrganizationName("Scille") app.setOrganizationDomain("parsec.cloud") app.setApplicationName("Parsec") f = QFont("Arial") app.setFont(f) # splash = QSplashScreen(QPixmap(':/logos/images/logos/parsec.png')) # splash.show() # app.processEvents() lang.switch_language() win = MainWindow(core_config=config) # QTimer wakes up the event loop periodically which allows us to close # the window even when it is in background. signal.signal(signal.SIGINT, kill_window(win)) timer = QTimer() timer.start(400) timer.timeout.connect(lambda: None) win.showMaximized() # splash.finish(win) return app.exec_()
def _create_main_window(): # Pass minimize_on_close to avoid having test blocked by the # closing confirmation prompt switch_language(core_config, "en") monkeypatch.setattr( "parsec.core.gui.main_window.list_available_devices", lambda *args, **kwargs: (["a"]), ) main_w = MainWindow(qt_thread_gateway._job_scheduler, event_bus, core_config, minimize_on_close=True) qtbot.add_widget(main_w) main_w.showMaximized() main_w.show_top() windows.append(main_w) main_w.add_instance(start_arg) def right_main_window(): assert ParsecApp.get_main_window() is main_w # For some reasons, the main window from the previous test might # still be around. Simply wait for things to settle down until # our freshly created window is detected as the app main window. qtbot.wait_until(right_main_window) return main_w
def _create_main_window(): # Pass minimize_on_close to avoid having test blocked by the # closing confirmation prompt switch_language(core_config, "en") main_w = MainWindow(qt_thread_gateway._job_scheduler, event_bus, core_config, minimize_on_close=True) qtbot.add_widget(main_w) main_w.showMaximized() main_w.show_top() windows.append(main_w) main_w.add_instance(start_arg) return main_w
def _create_main_window(): # Pass minimize_on_close to avoid having test blocked by the # closing confirmation prompt switch_language(core_config, "en") monkeypatch.setattr( "parsec.core.gui.main_window.list_available_devices", lambda *args, **kwargs: (["a"]), ) main_w = MainWindow(qt_thread_gateway._job_scheduler, event_bus, core_config, minimize_on_close=True) qtbot.add_widget(main_w) main_w.showMaximized() main_w.show_top() windows.append(main_w) main_w.add_instance(start_arg) return main_w
def run_gui(config: CoreConfig, start_arg: str = None, diagnose: bool = False): logger.info("Starting UI") # Needed for High DPI usage of QIcons, otherwise only QImages are well scaled QApplication.setAttribute(Qt.AA_EnableHighDpiScaling) QApplication.setAttribute(Qt.AA_UseHighDpiPixmaps) app = QApplication(["-stylesheet"]) app.setOrganizationName("Scille") app.setOrganizationDomain("parsec.cloud") app.setApplicationName("Parsec") QFontDatabase.addApplicationFont(":/fonts/fonts/Roboto-Regular.ttf") f = QFont("Roboto") app.setFont(f) rc = QFile(":/styles/styles/main.css") rc.open(QFile.ReadOnly) content = rc.readAll().data() app.setStyleSheet(str(content, "utf-8")) lang_key = lang.switch_language(config) event_bus = EventBus() with run_trio_thread() as jobs_ctx: win = MainWindow( jobs_ctx=jobs_ctx, event_bus=event_bus, config=config, minimize_on_close=config.gui_tray_enabled and systray_available(), ) result_queue = Queue(maxsize=1) class ThreadSafeNoQtSignal(ThreadSafeQtSignal): def __init__(self): self.qobj = None self.signal_name = "" self.args_types = () def emit(self, *args): pass jobs_ctx.submit_job( ThreadSafeNoQtSignal(), ThreadSafeNoQtSignal(), _start_ipc_server, config, win, start_arg, result_queue, ) if result_queue.get() == "already_running": # Another instance of Parsec already started, nothing more to do return if systray_available(): systray = Systray(parent=win) win.systray_notification.connect(systray.on_systray_notification) systray.on_close.connect(win.close_app) systray.on_show.connect(win.show_top) app.aboutToQuit.connect(before_quit(systray)) if config.gui_tray_enabled: app.setQuitOnLastWindowClosed(False) if config.gui_check_version_at_startup and not diagnose: CheckNewVersion(jobs_ctx=jobs_ctx, event_bus=event_bus, config=config, parent=win) win.showMaximized(skip_dialogs=diagnose) win.show_top() win.new_instance_needed.emit(start_arg) def kill_window(*args): win.close_app(force=True) QApplication.quit() signal.signal(signal.SIGINT, kill_window) # QTimer wakes up the event loop periodically which allows us to close # the window even when it is in background. timer = QTimer() timer.start(1000 if diagnose else 400) timer.timeout.connect(kill_window if diagnose else lambda: None) if diagnose: diagnose_timer = QTimer() diagnose_timer.start(1000) diagnose_timer.timeout.connect(kill_window) if lang_key: event_bus.send("gui.config.changed", gui_language=lang_key) if diagnose: with fail_on_first_exception(kill_window): return app.exec_() else: return app.exec_()
def run_gui(config: CoreConfig, start_arg: str = None, diagnose: bool = False): logger.info("Starting UI") # Needed for High DPI usage of QIcons, otherwise only QImages are well scaled QApplication.setAttribute(Qt.AA_EnableHighDpiScaling) QApplication.setAttribute(Qt.AA_UseHighDpiPixmaps) QApplication.setHighDpiScaleFactorRoundingPolicy( Qt.HighDpiScaleFactorRoundingPolicy.PassThrough) app = ParsecApp() app.load_stylesheet() app.load_font() lang_key = lang.switch_language(config) event_bus = EventBus() with run_trio_thread() as jobs_ctx: win = MainWindow( jobs_ctx=jobs_ctx, event_bus=event_bus, config=config, minimize_on_close=config.gui_tray_enabled and systray_available(), ) result_queue = Queue(maxsize=1) class ThreadSafeNoQtSignal(ThreadSafeQtSignal): def __init__(self): self.qobj = None self.signal_name = "" self.args_types = () def emit(self, *args): pass jobs_ctx.submit_job( ThreadSafeNoQtSignal(), ThreadSafeNoQtSignal(), _start_ipc_server, config, win, start_arg, result_queue, ) if result_queue.get() == "already_running": # Another instance of Parsec already started, nothing more to do return if systray_available(): systray = Systray(parent=win) win.systray_notification.connect(systray.on_systray_notification) systray.on_close.connect(win.close_app) systray.on_show.connect(win.show_top) app.aboutToQuit.connect(before_quit(systray)) if config.gui_tray_enabled: app.setQuitOnLastWindowClosed(False) if config.gui_check_version_at_startup and not diagnose: CheckNewVersion(jobs_ctx=jobs_ctx, event_bus=event_bus, config=config, parent=win) win.show_window(skip_dialogs=diagnose, invitation_link=start_arg) win.show_top() win.new_instance_needed.emit(start_arg) def kill_window(*args): win.close_app(force=True) QApplication.quit() signal.signal(signal.SIGINT, kill_window) # QTimer wakes up the event loop periodically which allows us to close # the window even when it is in background. timer = QTimer() timer.start(1000 if diagnose else 400) timer.timeout.connect(kill_window if diagnose else lambda: None) if diagnose: diagnose_timer = QTimer() diagnose_timer.start(1000) diagnose_timer.timeout.connect(kill_window) if lang_key: event_bus.send(CoreEvent.GUI_CONFIG_CHANGED, gui_language=lang_key) if diagnose: with fail_on_first_exception(kill_window): return app.exec_() else: with log_pyqt_exceptions(): return app.exec_()
async def _run_gui(app: ParsecApp, config: CoreConfig, start_arg: str = None, diagnose: bool = False): app.load_stylesheet() app.load_font() lang_key = lang.switch_language(config) event_bus = EventBus() async with run_trio_job_scheduler() as jobs_ctx: win = MainWindow( jobs_ctx=jobs_ctx, quit_callback=jobs_ctx.close, event_bus=event_bus, config=config, minimize_on_close=config.gui_tray_enabled and systray_available(), ) # Attempt to run an IPC server if Parsec is not already started try: await jobs_ctx.nursery.start(_run_ipc_server, config, win, start_arg) # Another instance of Parsec already started, nothing more to do except IPCServerAlreadyRunning: return # If we are here, it's either the IPC server has successfully started # or it has crashed without being able to communicate with an existing # IPC server. Such case is of course not supposed to happen but if it # does we nevertheless keep the application running as a kind of # failsafe mode (and the crash reason is logged and sent to telemetry). # Systray is not displayed on MacOS, having natively a menu with similar functions. if systray_available() and sys.platform != "darwin": systray = Systray(parent=win) win.systray_notification.connect(systray.on_systray_notification) systray.on_close.connect(win.close_app) systray.on_show.connect(win.show_top) app.aboutToQuit.connect(before_quit(systray)) if config.gui_tray_enabled: app.setQuitOnLastWindowClosed(False) if config.gui_check_version_at_startup and not diagnose: CheckNewVersion(jobs_ctx=jobs_ctx, event_bus=event_bus, config=config, parent=win) win.show_window(skip_dialogs=diagnose) win.show_top() win.new_instance_needed.emit(start_arg) if sys.platform == "darwin": # macFUSE is not bundled with Parsec and must be manually installed by the user # so we detect early such need to provide a help dialogue ;-) # TODO: provide a similar mechanism on Windows&Linux to handle mountpoint runner not available from parsec.core.gui.instance_widget import ensure_macfuse_available_or_show_dialogue ensure_macfuse_available_or_show_dialogue(win) def kill_window(*args): win.close_app(force=True) signal.signal(signal.SIGINT, kill_window) # QTimer wakes up the event loop periodically which allows us to close # the window even when it is in background. timer = QTimer() timer.start(400) timer.timeout.connect(lambda: None) if diagnose: diagnose_timer = QTimer() diagnose_timer.start(1000) diagnose_timer.timeout.connect(kill_window) if lang_key: event_bus.send(CoreEvent.GUI_CONFIG_CHANGED, gui_language=lang_key) with QDialogInProcess.manage_pools(): if diagnose: with fail_on_first_exception(kill_window): await trio.sleep_forever() else: with log_pyqt_exceptions(): await trio.sleep_forever()