diff --git a/portprotonqt/game_library_manager.py b/portprotonqt/game_library_manager.py index 1213aac..38b328d 100644 --- a/portprotonqt/game_library_manager.py +++ b/portprotonqt/game_library_manager.py @@ -167,12 +167,18 @@ class GameLibraryManager: if is_focused: if self.main_window.current_hovered_card and self.main_window.current_hovered_card != card: - self.main_window.current_hovered_card._hovered = False - self.main_window.current_hovered_card.leaveEvent(None) + try: + self.main_window.current_hovered_card._hovered = False + self.main_window.current_hovered_card.leaveEvent(None) + except RuntimeError: + pass # Card already deleted self.main_window.current_hovered_card = None if self.main_window.current_focused_card and self.main_window.current_focused_card != card: - self.main_window.current_focused_card._focused = False - self.main_window.current_focused_card.clearFocus() + try: + self.main_window.current_focused_card._focused = False + self.main_window.current_focused_card.clearFocus() + except RuntimeError: + pass # Card already deleted self.main_window.current_focused_card = card else: if self.main_window.current_focused_card == card: @@ -193,11 +199,19 @@ class GameLibraryManager: if is_hovered: if self.main_window.current_focused_card and self.main_window.current_focused_card != card: - self.main_window.current_focused_card._focused = False - self.main_window.current_focused_card.clearFocus() + try: + if self.main_window.current_focused_card: + self.main_window.current_focused_card._focused = False + self.main_window.current_focused_card.clearFocus() + except RuntimeError: + pass # Card already deleted if self.main_window.current_hovered_card and self.main_window.current_hovered_card != card: - self.main_window.current_hovered_card._hovered = False - self.main_window.current_hovered_card.leaveEvent(None) + try: + if self.main_window.current_hovered_card: + self.main_window.current_hovered_card._hovered = False + self.main_window.current_hovered_card.leaveEvent(None) + except RuntimeError: + pass # Card already deleted self.main_window.current_hovered_card = card else: if self.main_window.current_hovered_card == card: @@ -498,6 +512,11 @@ class GameLibraryManager: def _flush_deletions(self): """Delete pending widgets off the main update cycle.""" for card in list(self.pending_deletions): + # Clear any references to this card if it's currently focused/hovered + if self.main_window.current_focused_card == card: + self.main_window.current_focused_card = None + if self.main_window.current_hovered_card == card: + self.main_window.current_hovered_card = None card.deleteLater() self.pending_deletions.remove(card) diff --git a/portprotonqt/main_window.py b/portprotonqt/main_window.py index 43319bf..eff7a2f 100644 --- a/portprotonqt/main_window.py +++ b/portprotonqt/main_window.py @@ -3229,7 +3229,10 @@ class MainWindow(QMainWindow): # Игра стартовала – устанавливаем флаг, обновляем кнопку на "Stop" self._gameLaunched = True if self.current_running_button is not None: - self.current_running_button.setText(_("Stop")) + try: + self.current_running_button.setText(_("Stop")) + except RuntimeError: + self.current_running_button = None #self._inhibit_screensaver() elif not child_running: # Игра завершилась – сбрасываем флаг, сбрасываем кнопку и останавливаем таймер @@ -3248,13 +3251,16 @@ class MainWindow(QMainWindow): Вызывается, когда игра завершилась (не по нажатию кнопки). """ if self.current_running_button is not None: - self.current_running_button.setText(_("Play")) - icon = self.theme_manager.get_icon("play") - if isinstance(icon, str): - icon = QIcon(icon) # Convert path to QIcon - elif icon is None: - icon = QIcon() # Use empty QIcon as fallback - self.current_running_button.setIcon(icon) + try: + self.current_running_button.setText(_("Play")) + icon = self.theme_manager.get_icon("play") + if isinstance(icon, str): + icon = QIcon(icon) # Convert path to QIcon + elif icon is None: + icon = QIcon() # Use empty QIcon as fallback + self.current_running_button.setIcon(icon) + except RuntimeError: + pass self.current_running_button = None self.target_exe = None @@ -3307,13 +3313,16 @@ class MainWindow(QMainWindow): pass self.game_processes = [] if update_button: - update_button.setText(_("Play")) - icon = self.theme_manager.get_icon("play") - if isinstance(icon, str): - icon = QIcon(icon) - elif icon is None: - icon = QIcon() - update_button.setIcon(icon) + try: + update_button.setText(_("Play")) + icon = self.theme_manager.get_icon("play") + if isinstance(icon, str): + icon = QIcon(icon) + elif icon is None: + icon = QIcon() + update_button.setIcon(icon) + except RuntimeError: + pass if hasattr(self, 'checkProcessTimer') and self.checkProcessTimer is not None: self.checkProcessTimer.stop() self.checkProcessTimer.deleteLater() @@ -3335,13 +3344,16 @@ class MainWindow(QMainWindow): self.game_processes.append(process) save_last_launch(exe_name, datetime.now()) if update_button: - update_button.setText(_("Launching")) - icon = self.theme_manager.get_icon("stop") - if isinstance(icon, str): - icon = QIcon(icon) - elif icon is None: - icon = QIcon() - update_button.setIcon(icon) + try: + update_button.setText(_("Launching")) + icon = self.theme_manager.get_icon("stop") + if isinstance(icon, str): + icon = QIcon(icon) + elif icon is None: + icon = QIcon() + update_button.setIcon(icon) + except RuntimeError: + pass self.checkProcessTimer = QTimer(self) self.checkProcessTimer.timeout.connect(self.checkTargetExe) @@ -3398,13 +3410,16 @@ class MainWindow(QMainWindow): pass self.game_processes = [] if update_button: - update_button.setText(_("Play")) - icon = self.theme_manager.get_icon("play") - if isinstance(icon, str): - icon = QIcon(icon) - elif icon is None: - icon = QIcon() - update_button.setIcon(icon) + try: + update_button.setText(_("Play")) + icon = self.theme_manager.get_icon("play") + if isinstance(icon, str): + icon = QIcon(icon) + elif icon is None: + icon = QIcon() + update_button.setIcon(icon) + except RuntimeError: + pass if hasattr(self, 'checkProcessTimer') and self.checkProcessTimer is not None: self.checkProcessTimer.stop() self.checkProcessTimer.deleteLater() @@ -3426,13 +3441,16 @@ class MainWindow(QMainWindow): self.game_processes.append(process) save_last_launch(exe_name, datetime.now()) if update_button: - update_button.setText(_("Launching")) - icon = self.theme_manager.get_icon("stop") - if isinstance(icon, str): - icon = QIcon(icon) - elif icon is None: - icon = QIcon() - update_button.setIcon(icon) + try: + update_button.setText(_("Launching")) + icon = self.theme_manager.get_icon("stop") + if isinstance(icon, str): + icon = QIcon(icon) + elif icon is None: + icon = QIcon() + update_button.setIcon(icon) + except RuntimeError: + pass self.checkProcessTimer = QTimer(self) self.checkProcessTimer.timeout.connect(self.checkTargetExe) diff --git a/portprotonqt/virtual_keyboard.py b/portprotonqt/virtual_keyboard.py index 5567305..b7f5924 100644 --- a/portprotonqt/virtual_keyboard.py +++ b/portprotonqt/virtual_keyboard.py @@ -66,8 +66,11 @@ class VirtualKeyboard(QFrame): if not self.current_input_widget or not isinstance(self.current_input_widget, QLineEdit): return - # Просто устанавливаем курсор на нужную позицию без выделения - self.current_input_widget.setCursorPosition(self.current_input_widget.cursorPosition()) + try: + # Просто устанавливаем курсор на нужную позицию без выделения + self.current_input_widget.setCursorPosition(self.current_input_widget.cursorPosition()) + except RuntimeError: + self.current_input_widget = None def initUI(self): layout = QVBoxLayout() @@ -290,31 +293,43 @@ class VirtualKeyboard(QFrame): def up_key(self): """Перемещает курсор в QLineEdit вверх/в начало, если клавиатура видима""" if self.current_input_widget and isinstance(self.current_input_widget, QLineEdit): - self.current_input_widget.setCursorPosition(0) - self.current_input_widget.setFocus() + try: + self.current_input_widget.setCursorPosition(0) + self.current_input_widget.setFocus() + except RuntimeError: + self.current_input_widget = None def down_key(self): """Перемещает курсор в QLineEdit вниз/в конец, если клавиатура видима""" if self.current_input_widget and isinstance(self.current_input_widget, QLineEdit): - self.current_input_widget.setCursorPosition(len(self.current_input_widget.text())) - self.current_input_widget.setFocus() + try: + self.current_input_widget.setCursorPosition(len(self.current_input_widget.text())) + self.current_input_widget.setFocus() + except RuntimeError: + self.current_input_widget = None def left_key(self): """Перемещает курсор в QLineEdit влево, если клавиатура видима""" if self.current_input_widget and isinstance(self.current_input_widget, QLineEdit): - pos = self.current_input_widget.cursorPosition() - if pos > 0: - self.current_input_widget.setCursorPosition(pos - 1) - self.current_input_widget.setFocus() + try: + pos = self.current_input_widget.cursorPosition() + if pos > 0: + self.current_input_widget.setCursorPosition(pos - 1) + self.current_input_widget.setFocus() + except RuntimeError: + self.current_input_widget = None def right_key(self): """Перемещает курсор в QLineEdit вправо, если клавиатура видима""" if self.current_input_widget and isinstance(self.current_input_widget, QLineEdit): - pos = self.current_input_widget.cursorPosition() - text_len = len(self.current_input_widget.text()) - if pos < text_len: - self.current_input_widget.setCursorPosition(pos + 1) - self.current_input_widget.setFocus() + try: + pos = self.current_input_widget.cursorPosition() + text_len = len(self.current_input_widget.text()) + if pos < text_len: + self.current_input_widget.setCursorPosition(pos + 1) + self.current_input_widget.setFocus() + except RuntimeError: + self.current_input_widget = None def move_focus_up(self): """Перемещает фокус по кнопкам клавиатуры вверх с фиксированной скоростью""" @@ -370,35 +385,41 @@ class VirtualKeyboard(QFrame): self.on_shift_click(not self.shift_pressed) self.highlight_cursor_position() elif self.current_input_widget is not None: - # Сохраняем текущую кнопку с фокусом - focused_button = self.focusWidget() - key_to_restore = None - if isinstance(focused_button, QPushButton) and focused_button in self.buttons.values(): - key_to_restore = next((k for k, btn in self.buttons.items() if btn == focused_button), None) + try: + # Сохраняем текущую кнопку с фокусом + focused_button = self.focusWidget() + key_to_restore = None + if isinstance(focused_button, QPushButton) and focused_button in self.buttons.values(): + key_to_restore = next((k for k, btn in self.buttons.items() if btn == focused_button), None) - key = "&" if key == "&&" else key - cursor_pos = self.current_input_widget.cursorPosition() - text = self.current_input_widget.text() - new_text = text[:cursor_pos] + key + text[cursor_pos:] - self.current_input_widget.setText(new_text) - self.current_input_widget.setCursorPosition(cursor_pos + len(key)) - self.keyPressed.emit(key) - self.highlight_cursor_position() + key = "&" if key == "&&" else key + cursor_pos = self.current_input_widget.cursorPosition() + text = self.current_input_widget.text() + new_text = text[:cursor_pos] + key + text[cursor_pos:] + self.current_input_widget.setText(new_text) + self.current_input_widget.setCursorPosition(cursor_pos + len(key)) + self.keyPressed.emit(key) + self.highlight_cursor_position() - # Если был нажат SHIFT, но не CapsLock, отключаем его после ввода символа - if self.shift_pressed and not self.caps_lock: - self.shift_pressed = False - self.update_keyboard() - if key_to_restore and key_to_restore in self.buttons: - self.buttons[key_to_restore].setFocus() + # Если был нажат SHIFT, но не CapsLock, отключаем его после ввода символа + if self.shift_pressed and not self.caps_lock: + self.shift_pressed = False + self.update_keyboard() + if key_to_restore and key_to_restore in self.buttons: + self.buttons[key_to_restore].setFocus() + except RuntimeError: + self.current_input_widget = None def on_tab_click(self): if self.current_input_widget is not None: - self.current_input_widget.insert('\t') - self.keyPressed.emit('Tab') - if self.current_input_widget: - self.current_input_widget.setFocus() - self.highlight_cursor_position() + try: + self.current_input_widget.insert('\t') + self.keyPressed.emit('Tab') + if self.current_input_widget: + self.current_input_widget.setFocus() + self.highlight_cursor_position() + except RuntimeError: + self.current_input_widget = None def on_caps_click(self): """Включаем/выключаем CapsLock""" @@ -417,15 +438,18 @@ class VirtualKeyboard(QFrame): def on_backspace_click(self): """Обработка одного нажатия Backspace""" if self.current_input_widget is not None: - cursor_pos = self.current_input_widget.cursorPosition() - text = self.current_input_widget.text() + try: + cursor_pos = self.current_input_widget.cursorPosition() + text = self.current_input_widget.text() - if cursor_pos > 0: - new_text = text[:cursor_pos - 1] + text[cursor_pos:] - self.current_input_widget.setText(new_text) - self.current_input_widget.setCursorPosition(cursor_pos - 1) - self.keyPressed.emit('Backspace') - self.highlight_cursor_position() + if cursor_pos > 0: + new_text = text[:cursor_pos - 1] + text[cursor_pos:] + self.current_input_widget.setText(new_text) + self.current_input_widget.setCursorPosition(cursor_pos - 1) + self.keyPressed.emit('Backspace') + self.highlight_cursor_position() + except RuntimeError: + self.current_input_widget = None def on_backspace_pressed(self): """Обработка зажатого Backspace""" @@ -449,15 +473,21 @@ class VirtualKeyboard(QFrame): # TODO: тут подумать, как обрабатывать нажатие. # Пока болванка перехода на новую строку, в QlineEdit работает как нажатие пробела if self.current_input_widget is not None: - self.current_input_widget.insert('\n') - self.keyPressed.emit('Enter') + try: + self.current_input_widget.insert('\n') + self.keyPressed.emit('Enter') + except RuntimeError: + self.current_input_widget = None def on_clear_click(self): """Чистим строку от введённого текста""" if self.current_input_widget is not None: - self.current_input_widget.clear() - self.keyPressed.emit('Clear') - self.highlight_cursor_position() + try: + self.current_input_widget.clear() + self.keyPressed.emit('Clear') + self.highlight_cursor_position() + except RuntimeError: + self.current_input_widget = None def on_lang_click(self): """Переключение раскладки""" @@ -483,8 +513,11 @@ class VirtualKeyboard(QFrame): def show_for_widget(self, widget): self.current_input_widget = widget if widget: - widget.setFocus() - self.highlight_cursor_position() + try: + widget.setFocus() + self.highlight_cursor_position() + except RuntimeError: + self.current_input_widget = None # Позиционирование клавиатуры внизу родительского виджета if self._parent and isinstance(self._parent, QWidget):