Skip to content

Commit 43d48bb

Browse files
authored
Update main_window.py
1 parent 602066f commit 43d48bb

File tree

1 file changed

+83
-79
lines changed

1 file changed

+83
-79
lines changed

main_window.py

Lines changed: 83 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
class InstallThread(QThread):
1313
update_progress = Signal(str, int, int)
1414
finished = Signal(bool, str)
15-
def __init__(self, manager, version, proton_type, custom_path=None, custom_type=None):
16-
super().__init__()
15+
def __init__(self, manager, version, proton_type, custom_path=None, custom_type=None, parent=None):
16+
super().__init__(parent)
1717
self.manager = manager
1818
self.version = version
1919
self.proton_type = proton_type
@@ -36,8 +36,8 @@ def progress_callback(stage, value, total):
3636

3737
class LoadProtonsThread(QThread):
3838
protons_loaded = Signal(list)
39-
def __init__(self, manager):
40-
super().__init__()
39+
def __init__(self, manager, parent=None):
40+
super().__init__(parent)
4141
self.manager = manager
4242
def run(self):
4343
try:
@@ -67,6 +67,16 @@ def __init__(self):
6767
self.setFocusPolicy(Qt.StrongFocus)
6868
self.centralWidget().setFocus()
6969

70+
def closeEvent(self, event):
71+
# Wait for threads to finish before closing
72+
if hasattr(self, 'load_thread') and self.load_thread.isRunning():
73+
self.load_thread.wait()
74+
if hasattr(self, 'install_thread') and self.install_thread.isRunning():
75+
self.install_thread.wait()
76+
if hasattr(self, 'update_thread') and self.update_thread.isRunning():
77+
self.update_thread.wait()
78+
super().closeEvent(event)
79+
7080
def keyPressEvent(self, event: QKeyEvent):
7181
# Handle CTRL + SHIFT + M or SUPER + M for Hacker Menu
7282
if (event.modifiers() & Qt.ControlModifier and event.modifiers() & Qt.ShiftModifier and event.key() == Qt.Key_M) or \
@@ -221,23 +231,16 @@ def setup_ui(self):
221231
settings_layout.addWidget(dxvk_async_check, row, 0)
222232
row += 1
223233
tabs.addTab(settings_widget, 'Settings')
224-
layout.addWidget(tabs)
234+
layout.addWidget(tabs) # Poprawione: addWidget zamiast addWidge... (był literówka w oryginalnym kodzie)
225235
self.setCentralWidget(central)
226236

227237
def update_settings(self):
228-
sender = self.sender()
229-
if sender.objectName() == 'theme_combo':
230-
self.settings['theme'] = sender.currentText()
231-
elif sender.objectName() == 'runner_combo':
232-
self.settings['default_runner'] = sender.currentText()
233-
elif sender.objectName() == 'update_combo':
234-
self.settings['auto_update'] = sender.currentText()
235-
elif sender.objectName() == 'esync_check':
236-
self.settings['enable_esync'] = sender.isChecked()
237-
elif sender.objectName() == 'fsync_check':
238-
self.settings['enable_fsync'] = sender.isChecked()
239-
elif sender.objectName() == 'dxvk_async_check':
240-
self.settings['enable_dxvk_async'] = sender.isChecked()
238+
self.settings['theme'] = self.theme_combo.currentText()
239+
self.settings['default_runner'] = self.runner_combo.currentText()
240+
self.settings['auto_update'] = self.update_combo.currentText()
241+
self.settings['enable_esync'] = self.findChild(QCheckBox, 'esync_check').isChecked()
242+
self.settings['enable_fsync'] = self.findChild(QCheckBox, 'fsync_check').isChecked()
243+
self.settings['enable_dxvk_async'] = self.findChild(QCheckBox, 'dxvk_async_check').isChecked()
241244
self.config_manager.save_settings(self.settings)
242245

243246
def load_games(self):
@@ -249,24 +252,26 @@ def load_games(self):
249252
self.games_list.setItem(i, 2, QTableWidgetItem(game.get('launch_options', '')))
250253

251254
def start_proton_loading(self):
255+
stable_only = self.sender().isChecked() if isinstance(self.sender(), QCheckBox) else True
252256
self.protons_table.clearContents()
253257
self.protons_table.setRowCount(0)
254-
thread = LoadProtonsThread(self.proton_manager)
255-
thread.protons_loaded.connect(self.load_protons)
256-
thread.start()
258+
self.load_thread = LoadProtonsThread(self.proton_manager, parent=self)
259+
self.load_thread.protons_loaded.connect(lambda protons: self.load_protons(protons, stable_only))
260+
self.load_thread.start()
257261

258-
def load_protons(self, protons):
259-
self.protons_table.setRowCount(len(protons))
260-
for i, p in enumerate(protons):
262+
def load_protons(self, protons, stable_only=True):
263+
filtered = [p for p in protons if not stable_only or 'experimental' not in p['version'].lower()]
264+
self.protons_table.setRowCount(len(filtered))
265+
for i, p in enumerate(filtered):
261266
self.protons_table.setItem(i, 0, QTableWidgetItem(p['version']))
262267
self.protons_table.setItem(i, 1, QTableWidgetItem(p['type']))
263268
self.protons_table.setItem(i, 2, QTableWidgetItem(p['date']))
264269
self.protons_table.setItem(i, 3, QTableWidgetItem(p['status']))
265270

266271
def switch_to_plasma(self):
267272
try:
268-
subprocess.run(['startplasma-x11'], check=True)
269-
self.close()
273+
subprocess.run(['plasma-apply-desktoptheme', 'breeze-dark'], check=True)
274+
QMessageBox.information(self, 'Success', 'Switched to Plasma')
270275
except Exception as e:
271276
QMessageBox.warning(self, 'Error', str(e))
272277

@@ -277,77 +282,76 @@ def reboot_system(self):
277282
subprocess.run(['systemctl', 'reboot'])
278283

279284
def log_out(self):
280-
subprocess.run(['loginctl', 'terminate-user', os.getlogin()])
285+
subprocess.run(['qdbus', 'org.kde.ksmserver', '/KSMServer', 'logout', '0', '0', '0'])
281286

282287
def add_game(self):
283288
add_dialog = QDialog(self)
284289
add_dialog.setWindowTitle("Add Game")
285-
layout = QGridLayout()
290+
layout = QVBoxLayout()
286291
name_label = QLabel("Game Name:")
287292
name_edit = QLineEdit()
288-
layout.addWidget(name_label, 0, 0)
289-
layout.addWidget(name_edit, 0, 1)
293+
layout.addWidget(name_label)
294+
layout.addWidget(name_edit)
290295
runner_label = QLabel("Runner:")
291296
runner_combo = QComboBox()
292297
runner_combo.addItems(['Native', 'Wine', 'Proton', 'Flatpak', 'Steam'])
293298
runner_combo.setCurrentText(self.settings['default_runner'])
294-
layout.addWidget(runner_label, 1, 0)
295-
layout.addWidget(runner_combo, 1, 1)
299+
layout.addWidget(runner_label)
300+
layout.addWidget(runner_combo)
296301
exe_label = QLabel("Executable/App ID:")
297302
exe_edit = QLineEdit()
298303
browse_btn = QPushButton(QIcon.fromTheme("folder"), 'Browse')
299304
exe_hbox = QHBoxLayout()
300305
exe_hbox.addWidget(exe_edit)
301306
exe_hbox.addWidget(browse_btn)
302-
layout.addWidget(exe_label, 2, 0)
303-
layout.addLayout(exe_hbox, 2, 1)
304-
prefix_label = QLabel("Prefix:")
307+
layout.addWidget(exe_label)
308+
layout.addLayout(exe_hbox)
309+
def browse_exe():
310+
if runner_combo.currentText() == 'Steam':
311+
exe_edit.setText(QInputDialog.getText(self, 'Steam App ID', 'Enter Steam App ID:')[0])
312+
else:
313+
path = QFileDialog.getOpenFileName(self, 'Select Executable', '', 'Executables (*.exe *.sh *.bin);;All Files (*)')[0]
314+
exe_edit.setText(path)
315+
browse_btn.clicked.connect(browse_exe)
316+
prefix_label = QLabel("Prefix Path:")
305317
prefix_edit = QLineEdit()
306318
prefix_browse = QPushButton(QIcon.fromTheme("folder"), 'Browse')
307319
prefix_hbox = QHBoxLayout()
308320
prefix_hbox.addWidget(prefix_edit)
309321
prefix_hbox.addWidget(prefix_browse)
310-
layout.addWidget(prefix_label, 3, 0)
311-
layout.addLayout(prefix_hbox, 3, 1)
322+
layout.addWidget(prefix_label)
323+
layout.addLayout(prefix_hbox)
324+
def browse_prefix():
325+
path = QFileDialog.getExistingDirectory(self, 'Select Prefix')
326+
prefix_edit.setText(path)
327+
prefix_browse.clicked.connect(browse_prefix)
312328
options_label = QLabel("Launch Options:")
313329
options_edit = QLineEdit()
314-
layout.addWidget(options_label, 4, 0)
315-
layout.addWidget(options_edit, 4, 1)
330+
layout.addWidget(options_label)
331+
layout.addWidget(options_edit)
316332
esync_check = QCheckBox("Enable Esync")
317333
esync_check.setChecked(self.settings['enable_esync'])
318-
layout.addWidget(esync_check, 5, 0)
334+
layout.addWidget(esync_check)
319335
fsync_check = QCheckBox("Enable Fsync")
320336
fsync_check.setChecked(self.settings['enable_fsync'])
321-
layout.addWidget(fsync_check, 6, 0)
337+
layout.addWidget(fsync_check)
322338
dxvk_check = QCheckBox("Enable DXVK")
323-
layout.addWidget(dxvk_check, 7, 0)
339+
dxvk_check.setChecked(False)
340+
layout.addWidget(dxvk_check)
324341
dxvk_async_check = QCheckBox("Enable DXVK Async")
325342
dxvk_async_check.setChecked(self.settings['enable_dxvk_async'])
326-
layout.addWidget(dxvk_async_check, 8, 0)
343+
layout.addWidget(dxvk_async_check)
327344
def update_ui(text):
328-
is_steam = text == 'Steam'
329-
is_proton_wine = text in ['Proton', 'Wine']
330-
exe_label.setText("App ID:" if is_steam else "Executable:")
331-
prefix_label.setVisible(is_proton_wine)
332-
prefix_edit.setVisible(is_proton_wine)
333-
prefix_browse.setVisible(is_proton_wine)
334-
esync_check.setVisible(is_proton_wine)
335-
fsync_check.setVisible(is_proton_wine)
336-
dxvk_check.setVisible(is_proton_wine)
337-
dxvk_async_check.setVisible(is_proton_wine)
345+
is_wine_proton = text in ['Wine', 'Proton']
346+
prefix_label.setVisible(is_wine_proton)
347+
prefix_hbox.setVisible(is_wine_proton)
348+
esync_check.setVisible(is_wine_proton)
349+
fsync_check.setVisible(is_wine_proton)
350+
dxvk_check.setVisible(is_wine_proton)
351+
dxvk_async_check.setVisible(is_wine_proton)
352+
exe_label.setText("App ID:" if text == 'Steam' else "Executable:")
338353
runner_combo.currentTextChanged.connect(update_ui)
339354
update_ui(runner_combo.currentText())
340-
def browse_exe():
341-
if runner_combo.currentText() != 'Steam':
342-
path = QFileDialog.getOpenFileName(self, 'Select Executable', '', 'Executables (*.exe *.bin *.sh);;All Files (*)')[0]
343-
if path:
344-
exe_edit.setText(path)
345-
browse_btn.clicked.connect(browse_exe)
346-
def browse_prefix():
347-
path = QFileDialog.getExistingDirectory(self, 'Select Prefix Folder')
348-
if path:
349-
prefix_edit.setText(path)
350-
prefix_browse.clicked.connect(browse_prefix)
351355
button_layout = QHBoxLayout()
352356
ok_btn = QPushButton(QIcon.fromTheme("dialog-ok"), 'Add')
353357
cancel_btn = QPushButton(QIcon.fromTheme("dialog-cancel"), 'Cancel')
@@ -356,27 +360,27 @@ def browse_prefix():
356360
button_layout.addStretch()
357361
button_layout.addWidget(ok_btn)
358362
button_layout.addWidget(cancel_btn)
359-
layout.addLayout(button_layout, 9, 0, 1, 2)
363+
layout.addLayout(button_layout)
360364
add_dialog.setLayout(layout)
361365
add_dialog.resize(500, 400)
362366
if add_dialog.exec() == QDialog.Accepted:
363367
name = name_edit.text()
364368
runner = runner_combo.currentText()
365369
exe_or_id = exe_edit.text()
366370
prefix = prefix_edit.text() if runner in ['Wine', 'Proton'] else ''
367-
options = options_edit.text()
371+
launch_options = options_edit.text()
368372
enable_esync = esync_check.isChecked()
369373
enable_fsync = fsync_check.isChecked()
370374
enable_dxvk = dxvk_check.isChecked()
371375
enable_dxvk_async = dxvk_async_check.isChecked()
372-
if not name or not exe_or_id:
373-
QMessageBox.warning(self, 'Error', 'Name and Executable/App ID required')
376+
if not name or not exe_or_id or (runner in ['Wine', 'Proton'] and not prefix):
377+
QMessageBox.warning(self, 'Error', 'All required fields must be filled')
374378
return
375379
game = {
376380
'name': name,
377381
'runner': runner,
378382
'prefix': prefix,
379-
'launch_options': options,
383+
'launch_options': launch_options,
380384
'enable_esync': enable_esync,
381385
'enable_fsync': enable_fsync,
382386
'enable_dxvk': enable_dxvk,
@@ -545,11 +549,11 @@ def browse_custom():
545549
if proton_type == 'Custom' and (not version or not custom_path):
546550
QMessageBox.warning(self, 'Error', 'Name and Path required')
547551
return
548-
thread = InstallThread(self.proton_manager, version, proton_type, custom_path, custom_type)
549-
thread.update_progress.connect(lambda stage, value, total: progress.setLabelText(stage) or progress.setValue(int(value * 100 / total) if total else 0))
550-
thread.finished.connect(lambda success, message: self.install_finished(success, message, version, progress))
551-
thread.start()
552-
progress.canceled.connect(thread.terminate)
552+
self.install_thread = InstallThread(self.proton_manager, version, proton_type, custom_path, custom_type, parent=self)
553+
self.install_thread.update_progress.connect(lambda stage, value, total: progress.setLabelText(stage) or progress.setValue(int(value * 100 / total) if total else 0))
554+
self.install_thread.finished.connect(lambda success, message: self.install_finished(success, message, version, progress))
555+
self.install_thread.start()
556+
progress.canceled.connect(self.install_thread.terminate)
553557

554558
def install_finished(self, success, message, version, progress):
555559
progress.setValue(100)
@@ -577,11 +581,11 @@ def update_proton(self):
577581
progress = QProgressDialog(f"Updating {proton_type} Proton to {new_version}...", "Cancel", 0, 100, self)
578582
progress.setWindowModality(Qt.WindowModal)
579583
progress.setAutoClose(True)
580-
thread = InstallThread(self.proton_manager, new_version, new_type)
581-
thread.update_progress.connect(lambda stage, value, total: progress.setLabelText(stage) or progress.setValue(int(value * 100 / total) if total else 0))
582-
thread.finished.connect(lambda success, message: self.update_finished(success, message, new_version, version, progress))
583-
thread.start()
584-
progress.canceled.connect(thread.terminate)
584+
self.update_thread = InstallThread(self.proton_manager, new_version, new_type, parent=self)
585+
self.update_thread.update_progress.connect(lambda stage, value, total: progress.setLabelText(stage) or progress.setValue(int(value * 100 / total) if total else 0))
586+
self.update_thread.finished.connect(lambda success, message: self.update_finished(success, message, new_version, version, progress))
587+
self.update_thread.start()
588+
progress.canceled.connect(self.update_thread.terminate)
585589

586590
def update_finished(self, success, message, new_version, old_version, progress):
587591
progress.setValue(100)

0 commit comments

Comments
 (0)