Compare commits
4 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
97996fb67b | ||
|
9f994a8cc3 | ||
|
463306d0cf | ||
|
940cface08 |
@@ -6,10 +6,10 @@ export WH_WINE_USE="wine_x_tkg_10-0_amd64"
|
||||
export WINEPREFIX="scadoffice"
|
||||
export PROG_NAME="SCAD Office"
|
||||
export PROG_ICON="scadoffice"
|
||||
export BASE_PFX="scadaoffice_pfx_x64_v04"
|
||||
export BASE_PFX="scadaoffice_pfx_x64_v03"
|
||||
export WH_WINDOWS_VER="10"
|
||||
export WINEARCH="win64"
|
||||
export INSTALL_DLL="dotnet20 dotnet48 gdiplus vcrun6sp6 vcrun2005 vcrun2019 d3dx11_42 d3dx11_43 d3dx9 d3dcompiler_42 d3dcompiler_43 d3dcompiler_46 d3dcompiler_47 richtx32 riched30 riched20 msxml6"
|
||||
export INSTALL_DLL="dotnet20 dotnet472 dotnet48 gdiplus vcrun6sp6 vcrun2005 vcrun2019 d3dx11_42 d3dx11_43 d3dx9 d3dcompiler_42 d3dcompiler_43 d3dcompiler_46 d3dcompiler_47 richtx32 riched30 riched20 msxml6"
|
||||
export WH_XDG_OPEN="rtf"
|
||||
AUTOINSTALL_EXE="${WH_TMP_DIR}/SCADOffice_installer.exe"
|
||||
SCADOFFICE_ADDONS_URL="https://cloud.linux-gaming.ru/portproton/scadoffice_addons_v02.tar.xz"
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 2.9 KiB |
Binary file not shown.
Before Width: | Height: | Size: 4.7 KiB |
@@ -1,34 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# info_ru: Установщик программного комплекса NetTest (демо-версия)
|
||||
########################################################################
|
||||
export PROG_URL="https://www.kpolyakov.spb.ru/prog/nettest/nettget.htm"
|
||||
export WH_WINE_USE="wine_x_tkg_10-0_amd64"
|
||||
export WINEPREFIX="nettest"
|
||||
export PROG_NAME="NetTest"
|
||||
export PROG_ICON="nettest"
|
||||
export BASE_PFX="none"
|
||||
export WINEARCH="win64"
|
||||
export INSTALL_DLL=""
|
||||
export WH_WINDOWS_VER="10"
|
||||
|
||||
ZIP_FILE="$2"
|
||||
|
||||
if [[ -f "$ZIP_FILE" ]] \
|
||||
&& [[ $ZIP_FILE =~ ".zip" ]]
|
||||
then
|
||||
prepair_wine
|
||||
PROG_PATH="$DRIVE_C/nettest"
|
||||
unpack "$2" "$PROG_PATH"
|
||||
|
||||
cp -fr "$PROG_PATH/fonts/"* "$DRIVE_C/windows/Fonts/"
|
||||
|
||||
create_desktop "$PROG_NAME (Сервер)" "$PROG_PATH/testser.exe" "nettest_server"
|
||||
create_desktop "$PROG_NAME (Клиент)" "$PROG_PATH/testcli.exe" "nettest_client"
|
||||
else
|
||||
fatal "Не найден файл архива для $PROG_NAME. Перезапустите по примеру:
|
||||
winehelper install $1 \"/путь/до/архива\""
|
||||
fi
|
||||
|
||||
|
||||
|
||||
|
@@ -5,7 +5,6 @@
|
||||
fb7fdfde96de10a1b3b051bdf2727b6a7c1768b878483726454dd6726e9e0193 wine-9.0.14-alt1-i586-spravkibk.tar.xz
|
||||
e0a84bb4908c3927954d7eef6b8ac7212e442b8c107d000c6890fec340f96183 wine-9.0.14-alt1-amd64.tar.xz
|
||||
6f86d2220b65b709bf88c6f829a4998de3b929cc2091cd1333a51c32e1491b79 wine-9.0.9-alt1-i586.tar.xz
|
||||
f1bf1261550ca2928cefacdb724926d3d6d103433d0ff6882ee9783a50d8f4e4 wine-8.8-staging-amd64.tar.xz
|
||||
61bec1230b37b8fcc69fd45f848b44fd88cc41fcdd5dc3080336d7da63660f40 wine-7.16.1-alt1-amd64.tar.xz
|
||||
6fea17fd131f57c2ebf7ca4c60d3c5a9e819afe16e5d0b77ecb750da99ae0e38 wine-7.16.1-alt1-i586.tar.xz
|
||||
|
||||
@@ -212,8 +211,8 @@ dfb44ce5e5af7dba1686932c63d6b05e5dd6919a21c78130a7d1d0271b93958e audiorecstatio
|
||||
# create with wine_x_tkg_10-0_i586 (universal user: xuser)
|
||||
# winetricks arial dotnet7 dotnetdesktop7 renderer=gdi
|
||||
|
||||
4fa93434c5c15440014357323257ddcee7d28b94ad6a56bd6f5a08b33ae4c3cb scadaoffice_pfx_x64_v04.tar.xz
|
||||
# create with wine-8.8-staging-amd64
|
||||
25e277c7afa4a9afc5f013cb05f872c12a7f381c4f0503a423dcacccca9a14c6 scadaoffice_pfx_x64_v03.tar.xz
|
||||
# create with wine_x_tkg_10-0_i586 (universal user: xuser)
|
||||
# winetricks dotnet48 gdiplus vcrun6sp6 vcrun2005 vcrun2019 d3dx11_42 d3dx11_43 d3dx9 d3dcompiler_42 d3dcompiler_43 d3dcompiler_46 d3dcompiler_47 richtx32 riched30 riched20 msxml6 dotnet20
|
||||
# + addons with ODBC, SSH, *.reg
|
||||
0f4ef434df07bc338ae308af44330590eaa1d9c94b64850514e55b960642d0eb scadoffice_addons_v02.tar.xz
|
||||
|
53
winehelper
53
winehelper
@@ -1111,11 +1111,6 @@ init_wineprefix () {
|
||||
export DRIVE_C="$WINEPREFIX/drive_c"
|
||||
export XUSER_PATH="$DRIVE_C/users/xuser"
|
||||
|
||||
if [[ -d "$XUSER_PATH" ]] \
|
||||
&& [[ ! -d "$DRIVE_C/users/$USER" ]]
|
||||
then try_force_link_dir "$XUSER_PATH" "$DRIVE_C/users/$USER"
|
||||
fi
|
||||
|
||||
if [[ ! -f "$WINEPREFIX/.firstboot" ]] ; then
|
||||
create_new_dir "$WINEPREFIX"
|
||||
if [[ "$CLEAR_PREFIX" == "1" ]]
|
||||
@@ -1184,6 +1179,16 @@ init_wineprefix () {
|
||||
# добавление ассоциаций файлов для запуска нативного приложения из wine
|
||||
# пример переменной: WH_XDG_OPEN="txt doc pdf"
|
||||
check_variables WH_XDG_OPEN "0"
|
||||
# Сохраняем старые ассоциации, чтобы потом удалить те, что больше не нужны
|
||||
local old_xdg_open
|
||||
if [[ -f "$WINEPREFIX/last.conf" ]]; then
|
||||
old_xdg_open=$(grep "WH_XDG_OPEN=" "$WINEPREFIX/last.conf" | sed -e 's/.*WH_XDG_OPEN="//' -e 's/"$//')
|
||||
fi
|
||||
|
||||
# Если переменная WH_XDG_OPEN была установлена извне (например, из GUI),
|
||||
# то мы должны принудительно установить ее значение в "0", если она пуста,
|
||||
# чтобы корректно удалить старые ассоциации.
|
||||
[[ -z "$WH_XDG_OPEN" ]] && WH_XDG_OPEN="0"
|
||||
local WRAPPER="${WH_TMP_DIR}/wh-xdg-open.sh"
|
||||
local XDG_OPEN_REG="Software\Classes\xdg-open\shell\open\command"
|
||||
if [[ $WH_XDG_OPEN != "0" ]] ; then
|
||||
@@ -1206,13 +1211,25 @@ init_wineprefix () {
|
||||
# добавляем новую команду xdg-open в реестр
|
||||
get_and_set_reg_file --add "$XDG_OPEN_REG" '@=' 'REG_SZ' "$WRAPPER %1" "system"
|
||||
|
||||
# Удаляем старые ассоциации, которых нет в новом списке
|
||||
if [[ -n "$old_xdg_open" ]]; then
|
||||
for old_ext in $old_xdg_open; do
|
||||
if ! echo " $WH_XDG_OPEN " | grep -q " $old_ext "; then
|
||||
get_and_set_reg_file --delete "Software\Classes\.$old_ext" '@='
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# добавляем ассоциации файлов для запуска с помощью xdg-open
|
||||
for ext in $WH_XDG_OPEN ; do
|
||||
get_and_set_reg_file --add "Software\Classes\.$ext" '@=' 'REG_SZ' "xdg-open" "system"
|
||||
done
|
||||
print_info "Используются ассоциации с нативными приложениями для файлов: \"$WH_XDG_OPEN\""
|
||||
else
|
||||
# удаление команды xdg-open из реестра
|
||||
# удаление всех ассоциаций
|
||||
for old_ext in $old_xdg_open; do
|
||||
get_and_set_reg_file --delete "Software\Classes\.$old_ext" '@='
|
||||
done
|
||||
get_and_set_reg_file --delete "$XDG_OPEN_REG" '@='
|
||||
# удаяем скрипт-обёртку
|
||||
try_remove_file "$WRAPPER"
|
||||
@@ -1353,6 +1370,13 @@ init_database () {
|
||||
. "$WHDB_FILE"
|
||||
elif check_prefix_var && [[ -f "$WINEPREFIX/last.conf" ]] ; then
|
||||
print_info "Найдены настройки из предыдущего использования префикса: $WINEPREFIX"
|
||||
# Сохраняем значение WH_XDG_OPEN, если оно было установлено извне (например, из GUI).
|
||||
# Это предотвращает его перезапись старым значением из last.conf.
|
||||
# Используем `declare -p` для надежного определения, была ли переменная установлена,
|
||||
# даже если она пустая (что означает "удалить все ассоциации").
|
||||
if declare -p WH_XDG_OPEN &>/dev/null; then
|
||||
wh_xdg_open_from_env="$WH_XDG_OPEN"
|
||||
fi
|
||||
cat "$WINEPREFIX/last.conf"
|
||||
. "$WINEPREFIX/last.conf"
|
||||
else
|
||||
@@ -1361,10 +1385,19 @@ init_database () {
|
||||
}
|
||||
|
||||
prepair_wine () {
|
||||
# Объявляем переменную здесь, чтобы она была доступна после вызова init_database
|
||||
local wh_xdg_open_from_env
|
||||
|
||||
if [[ -n "$INSTALL_SCRIPT_NAME" ]]
|
||||
then print_info "Используются настройки из скрипта установки: $INSTALL_SCRIPT_NAME"
|
||||
else init_database
|
||||
fi
|
||||
# Восстанавливаем значение WH_XDG_OPEN, если оно было установлено извне.
|
||||
# Проверяем, была ли переменная сохранена, а не ее значение.
|
||||
# Это позволяет корректно передать пустую строку.
|
||||
if declare -p wh_xdg_open_from_env &>/dev/null; then
|
||||
export WH_XDG_OPEN="$wh_xdg_open_from_env"
|
||||
fi
|
||||
init_wine_ver
|
||||
init_wineprefix
|
||||
use_winetricks
|
||||
@@ -1394,9 +1427,9 @@ wine_run () {
|
||||
echo "##### Лог WINE #####" | tee -a "$LOG_FILE"
|
||||
$MANGOHUD_RUN "$WINELOADER" "$@" $LAUNCH_PARAMETERS 2>&1 | tee -a "$LOG_FILE"
|
||||
else
|
||||
$MANGOHUD_RUN "$WINELOADER" "$@" $LAUNCH_PARAMETERS
|
||||
exec $MANGOHUD_RUN "$WINELOADER" "$@" $LAUNCH_PARAMETERS
|
||||
fi
|
||||
wait_wineserver
|
||||
# wait_wineserver
|
||||
}
|
||||
|
||||
wine_run_install () {
|
||||
@@ -1818,9 +1851,9 @@ create_base_pfx () {
|
||||
&& [[ ! -L "$users_dir/$USER" ]]
|
||||
then
|
||||
if [[ -L "$users_dir/xuser" ]]
|
||||
then try_remove_dir "$users_dir/xuser"
|
||||
then try_remove_dir "$users_dir/xuser/"
|
||||
fi
|
||||
create_new_dir "$users_dir/xuser"
|
||||
create_new_dir "$users_dir/xuser/"
|
||||
cp -fr "$users_dir/$USER"/* "$users_dir/xuser/"
|
||||
fi
|
||||
|
||||
|
@@ -12,7 +12,7 @@ import hashlib
|
||||
from functools import partial
|
||||
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,QPushButton, QLabel, QTabWidget, QTabBar,
|
||||
QTextEdit, QFileDialog, QMessageBox, QLineEdit, QCheckBox, QStackedWidget, QScrollArea, QFormLayout, QGroupBox, QRadioButton, QComboBox,
|
||||
QListWidget, QListWidgetItem, QGridLayout, QFrame, QDialog, QTextBrowser, QInputDialog)
|
||||
QListWidget, QListWidgetItem, QGridLayout, QFrame, QDialog, QTextBrowser, QInputDialog, QDialogButtonBox)
|
||||
from PyQt5.QtCore import Qt, QProcess, QSize, QTimer, QProcessEnvironment, QPropertyAnimation, QEasingCurve
|
||||
from PyQt5.QtGui import QIcon, QFont, QTextCursor, QPixmap, QPainter, QDesktopServices
|
||||
from PyQt5.QtNetwork import QLocalServer, QLocalSocket
|
||||
@@ -474,10 +474,9 @@ class WinetricksManagerDialog(QDialog):
|
||||
self.log_output.setText(self.INFO_TEXT)
|
||||
main_layout.addWidget(self.log_output)
|
||||
|
||||
# Кнопки управления
|
||||
# Кнопки управления, выровненные по правому краю
|
||||
button_layout = QHBoxLayout()
|
||||
self.status_label = QLabel("Загрузка компонентов...")
|
||||
button_layout.addWidget(self.status_label, 1)
|
||||
button_layout.addStretch(1)
|
||||
|
||||
self.apply_button = QPushButton("Применить")
|
||||
self.apply_button.setEnabled(False)
|
||||
@@ -548,7 +547,6 @@ class WinetricksManagerDialog(QDialog):
|
||||
def load_all_categories(self):
|
||||
"""Запускает загрузку всех категорий."""
|
||||
self.loading_count = len(self.categories)
|
||||
self.category_statuses = {name: "загрузка..." for name in self.categories.keys()}
|
||||
for internal_name in self.categories.values():
|
||||
self._start_load_process(internal_name)
|
||||
|
||||
@@ -602,13 +600,6 @@ class WinetricksManagerDialog(QDialog):
|
||||
process.finished.connect(partial(self._on_load_finished, category))
|
||||
process.start(self.winetricks_path, [category, "list"])
|
||||
|
||||
def _update_status_label(self):
|
||||
"""Обновляет текстовую метку состояния загрузки."""
|
||||
status_parts = []
|
||||
for name, status in self.category_statuses.items():
|
||||
status_parts.append(f"{name}: {status}")
|
||||
self.status_label.setText(" | ".join(status_parts))
|
||||
|
||||
def _parse_winetricks_log(self):
|
||||
"""Читает winetricks.log и возвращает множество установленных компонентов."""
|
||||
installed_verbs = set()
|
||||
@@ -681,22 +672,15 @@ class WinetricksManagerDialog(QDialog):
|
||||
|
||||
if exit_code != 0 or exit_status != QProcess.NormalExit:
|
||||
error_string = process.errorString() if process else "N/A"
|
||||
self._log(f"--- Ошибка загрузки категории '{category}' (код: {exit_code}) ---", "red")
|
||||
self.category_statuses[category_display_name] = "ошибка"
|
||||
self._update_status_label() # Показываем ошибку в статусе
|
||||
self._log(f"--- Ошибка загрузки категории '{category_display_name}' (код: {exit_code}) ---", "red")
|
||||
if exit_status == QProcess.CrashExit:
|
||||
self._log("--- Процесс winetricks завершился аварийно. ---", "red")
|
||||
# По умолчанию используется "Неизвестная ошибка", которая не очень полезна.
|
||||
if error_string != "Неизвестная ошибка":
|
||||
self._log(f"--- Системная ошибка: {error_string} ---", "red")
|
||||
self._log(output if output.strip() else "Winetricks не вернул вывод. Проверьте, что он работает корректно.")
|
||||
self._log("--------------------------------------------------", "red")
|
||||
else:
|
||||
self.category_statuses[category_display_name] = "готово"
|
||||
installed_verbs = self._parse_winetricks_log()
|
||||
# Обновляем статус только если это была сетевая загрузка
|
||||
if from_cache is None:
|
||||
self._update_status_label()
|
||||
found_items = self._parse_winetricks_list_output(output, installed_verbs, list_widget)
|
||||
|
||||
if from_cache is None: # Только если мы не читали из кэша
|
||||
@@ -721,7 +705,6 @@ class WinetricksManagerDialog(QDialog):
|
||||
|
||||
self.loading_count -= 1
|
||||
if self.loading_count == 0:
|
||||
self.status_label.setText("Готово.")
|
||||
self._update_ui_state()
|
||||
|
||||
def _on_item_changed(self, item):
|
||||
@@ -862,11 +845,6 @@ class WinetricksManagerDialog(QDialog):
|
||||
|
||||
# 3. Обрабатываем успех
|
||||
self._log("\n=== Все операции успешно завершены ===")
|
||||
self._show_message_box("Успех",
|
||||
"Операции с компонентами были успешно выполнены.",
|
||||
QMessageBox.Information,
|
||||
{"buttons": {"Да": QMessageBox.AcceptRole}})
|
||||
|
||||
self.apply_button.setEnabled(True)
|
||||
self.reinstall_button.setEnabled(False) # Сбрасываем в неактивное состояние
|
||||
self.close_button.setEnabled(True)
|
||||
@@ -876,7 +854,6 @@ class WinetricksManagerDialog(QDialog):
|
||||
search_edit.clear()
|
||||
|
||||
# Перезагружаем данные, чтобы обновить состояние
|
||||
self.status_label.setText("Обновление данных...")
|
||||
self.initial_states.clear()
|
||||
self.load_all_categories()
|
||||
self.installation_finished = True
|
||||
@@ -1355,6 +1332,75 @@ class CreatePrefixDialog(QDialog):
|
||||
|
||||
self.accept()
|
||||
|
||||
class FileAssociationsDialog(QDialog):
|
||||
"""Диалог для управления ассоциациями файлов (WH_XDG_OPEN)."""
|
||||
|
||||
def __init__(self, current_associations, parent=None):
|
||||
super().__init__(parent)
|
||||
self.setWindowTitle("Настройка ассоциаций файлов")
|
||||
self.setMinimumWidth(450)
|
||||
self.setModal(True)
|
||||
|
||||
self.new_associations = current_associations
|
||||
|
||||
layout = QVBoxLayout(self)
|
||||
layout.setSpacing(10) # Добавляем вертикальный отступ между виджетами
|
||||
|
||||
info_label = QLabel(
|
||||
"Укажите расширения файлов, которые должны открываться нативными<br>"
|
||||
"приложениями Linux. Чтобы удалить все ассоциации, очистите поле.<br><br>"
|
||||
"<b>Пример:</b> <code>pdf docx txt</code>"
|
||||
)
|
||||
info_label.setWordWrap(True)
|
||||
info_label.setTextFormat(Qt.RichText)
|
||||
layout.addWidget(info_label)
|
||||
|
||||
self.associations_edit = QLineEdit()
|
||||
# Если ассоциации не заданы (значение "0"), поле будет пустым, чтобы показать подсказку
|
||||
if current_associations != "0":
|
||||
self.associations_edit.setText(current_associations)
|
||||
|
||||
self.associations_edit.setPlaceholderText("Введите расширения через пробел...")
|
||||
layout.addWidget(self.associations_edit)
|
||||
|
||||
# Запрещенные расширения
|
||||
forbidden_label = QLabel(
|
||||
"<small><b>Запрещено использовать:</b> cpl, dll, exe, lnk, msi</small>"
|
||||
)
|
||||
forbidden_label.setTextFormat(Qt.RichText) # Включаем обработку HTML
|
||||
layout.addWidget(forbidden_label)
|
||||
|
||||
button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
|
||||
button_box.accepted.connect(self.validate_and_accept)
|
||||
button_box.rejected.connect(self.reject)
|
||||
layout.addWidget(button_box)
|
||||
|
||||
def validate_and_accept(self):
|
||||
"""Проверяет введенные данные перед закрытием."""
|
||||
forbidden_extensions = {"cpl", "dll", "exe", "lnk", "msi"}
|
||||
|
||||
# Получаем введенные расширения, очищаем от лишних пробелов
|
||||
input_text = self.associations_edit.text().lower().strip()
|
||||
entered_extensions = {ext.strip() for ext in input_text.split() if ext.strip()}
|
||||
|
||||
found_forbidden = entered_extensions.intersection(forbidden_extensions)
|
||||
|
||||
if found_forbidden:
|
||||
msg_box = QMessageBox(self)
|
||||
msg_box.setIcon(QMessageBox.Warning)
|
||||
msg_box.setWindowTitle("Недопустимые расширения")
|
||||
msg_box.setTextFormat(Qt.RichText)
|
||||
msg_box.setText(
|
||||
"Следующие расширения запрещены и не могут быть использованы:<br><br>"
|
||||
f"<b>{', '.join(sorted(list(found_forbidden)))}</b>"
|
||||
)
|
||||
msg_box.exec_()
|
||||
return
|
||||
|
||||
# Сохраняем результат в виде отсортированной строки
|
||||
self.new_associations = " ".join(sorted(list(entered_extensions)))
|
||||
self.accept()
|
||||
|
||||
class ComponentVersionSelectionDialog(QDialog):
|
||||
"""Диалог для выбора версии компонента (DXVK, VKD3D)."""
|
||||
|
||||
@@ -2142,6 +2188,13 @@ class WineHelperGUI(QMainWindow):
|
||||
self.vkd3d_manage_button.setToolTip("Установка или удаление определенной версии vkd3d-proton в префиксе.")
|
||||
management_layout.addWidget(self.vkd3d_manage_button, 5, 1)
|
||||
|
||||
self.file_associations_button = QPushButton("Ассоциации файлов")
|
||||
self.file_associations_button.setMinimumHeight(32)
|
||||
self.file_associations_button.clicked.connect(self.open_file_associations_manager)
|
||||
self.file_associations_button.setToolTip(
|
||||
"Настройка открытия определенных типов файлов с помощью нативных приложений Linux.")
|
||||
management_layout.addWidget(self.file_associations_button, 6, 0, 1, 2)
|
||||
|
||||
# --- Правая сторона: Информационный блок и кнопки установки ---
|
||||
right_column_widget = QWidget()
|
||||
right_column_layout = QVBoxLayout(right_column_widget)
|
||||
@@ -2174,7 +2227,7 @@ class WineHelperGUI(QMainWindow):
|
||||
right_column_layout.setStretch(0, 1) # Информационное окно растягивается
|
||||
right_column_layout.setStretch(1, 0) # Группа кнопок не растягивается
|
||||
|
||||
management_layout.addWidget(right_column_widget, 0, 2, 6, 1)
|
||||
management_layout.addWidget(right_column_widget, 0, 2, 7, 1)
|
||||
|
||||
management_layout.setColumnStretch(0, 1)
|
||||
management_layout.setColumnStretch(1, 1)
|
||||
@@ -2381,8 +2434,9 @@ class WineHelperGUI(QMainWindow):
|
||||
"VKD3D_VER": ("Версия VKD3D", lambda v: v if v else "Не установлено"),
|
||||
"WINEESYNC": ("ESync", lambda v: "Включен" if v == "1" else "Выключен"),
|
||||
"WINEFSYNC": ("FSync", lambda v: "Включен" if v == "1" else "Выключен"),
|
||||
"WH_XDG_OPEN": ("Ассоциации файлов", lambda v: v if v and v != "0" else "Не заданы"),
|
||||
}
|
||||
display_order = ["WINEPREFIX", "WINEARCH", "WH_WINE_USE", "BASE_PFX", "DXVK_VER", "VKD3D_VER", "WINEESYNC", "WINEFSYNC"]
|
||||
display_order = ["WINEPREFIX", "WINEARCH", "WH_WINE_USE", "BASE_PFX", "DXVK_VER", "VKD3D_VER", "WINEESYNC", "WINEFSYNC", "WH_XDG_OPEN"]
|
||||
|
||||
html_content = f'<p style="line-height: 1.3; font-size: 9pt;">'
|
||||
html_content += f"<b>Имя:</b> {html.escape(prefix_name)}<br>"
|
||||
@@ -2682,6 +2736,64 @@ class WineHelperGUI(QMainWindow):
|
||||
if exit_code == 0:
|
||||
self.update_prefix_info_display(prefix_name)
|
||||
|
||||
def open_file_associations_manager(self):
|
||||
"""Открывает диалог для управления ассоциациями файлов."""
|
||||
prefix_name = self.current_managed_prefix_name
|
||||
if not prefix_name:
|
||||
QMessageBox.warning(self, "Ошибка", "Сначала выберите префикс.")
|
||||
return
|
||||
|
||||
current_associations = self._get_prefix_component_version(prefix_name, "WH_XDG_OPEN") or ""
|
||||
|
||||
dialog = FileAssociationsDialog(current_associations, self)
|
||||
if dialog.exec_() == QDialog.Accepted:
|
||||
new_associations = dialog.new_associations
|
||||
# Запускаем обновление, только если значение изменилось
|
||||
if new_associations != current_associations:
|
||||
self.run_update_associations_command(prefix_name, new_associations)
|
||||
|
||||
def run_update_associations_command(self, prefix_name, new_associations):
|
||||
"""Выполняет команду обновления ассоциаций файлов."""
|
||||
prefix_path = os.path.join(Var.USER_WORK_PATH, "prefixes", prefix_name)
|
||||
|
||||
self.command_dialog = QDialog(self)
|
||||
self.command_dialog.setWindowTitle("Обновление ассоциаций файлов")
|
||||
self.command_dialog.setMinimumSize(750, 400)
|
||||
self.command_dialog.setModal(True)
|
||||
self.command_dialog.setWindowFlags(self.command_dialog.windowFlags() & ~Qt.WindowCloseButtonHint)
|
||||
|
||||
layout = QVBoxLayout()
|
||||
self.command_log_output = QTextEdit()
|
||||
self.command_log_output.setReadOnly(True)
|
||||
self.command_log_output.setFont(QFont('DejaVu Sans Mono', 10))
|
||||
layout.addWidget(self.command_log_output)
|
||||
|
||||
self.command_close_button = QPushButton("Закрыть")
|
||||
self.command_close_button.setEnabled(False)
|
||||
self.command_close_button.clicked.connect(self.command_dialog.close)
|
||||
layout.addWidget(self.command_close_button)
|
||||
self.command_dialog.setLayout(layout)
|
||||
|
||||
self.command_process = QProcess(self.command_dialog)
|
||||
self.command_process.setProcessChannelMode(QProcess.MergedChannels)
|
||||
self.command_process.readyReadStandardOutput.connect(self._handle_command_output)
|
||||
self.command_process.finished.connect(
|
||||
lambda exit_code, exit_status: self._handle_component_install_finished(
|
||||
prefix_name, exit_code, exit_status
|
||||
)
|
||||
)
|
||||
|
||||
env = QProcessEnvironment.systemEnvironment()
|
||||
env.insert("WINEPREFIX", prefix_path)
|
||||
# Устанавливаем новую переменную окружения для скрипта
|
||||
env.insert("WH_XDG_OPEN", new_associations)
|
||||
self.command_process.setProcessEnvironment(env)
|
||||
|
||||
args = ["init-prefix"]
|
||||
self.command_log_output.append(f"Выполнение: {shlex.quote(self.winehelper_path)} {' '.join(shlex.quote(a) for a in args)}")
|
||||
self.command_process.start(self.winehelper_path, args)
|
||||
self.command_dialog.exec_()
|
||||
|
||||
def create_launcher_for_prefix(self):
|
||||
"""
|
||||
Открывает диалог для создания ярлыка для приложения внутри выбранного префикса.
|
||||
@@ -3514,7 +3626,7 @@ class WineHelperGUI(QMainWindow):
|
||||
QMessageBox.critical(self, "Ошибка", f"Не удалось модифицировать команду для отладки: {e}")
|
||||
return
|
||||
|
||||
process = QProcess(self)
|
||||
process = QProcess()
|
||||
env = QProcessEnvironment.systemEnvironment()
|
||||
|
||||
cmd_start_index = 0
|
||||
@@ -3532,7 +3644,10 @@ class WineHelperGUI(QMainWindow):
|
||||
arguments = clean_command[cmd_start_index + 1:]
|
||||
|
||||
process.setProcessEnvironment(env)
|
||||
process.finished.connect(lambda: self._on_app_process_finished(desktop_path))
|
||||
# Используем functools.partial для надежной передачи аргументов
|
||||
# и избегания проблем с замыканием в lambda.
|
||||
process.finished.connect(partial(self._on_app_process_finished, desktop_path))
|
||||
|
||||
|
||||
try:
|
||||
process.start(program, arguments)
|
||||
@@ -3551,6 +3666,36 @@ class WineHelperGUI(QMainWindow):
|
||||
QMessageBox.critical(self, "Ошибка",
|
||||
f"Не удалось обработать команду запуска:\n{command_str}\n\nОшибка: {str(e)}")
|
||||
|
||||
def closeEvent(self, event):
|
||||
"""Обрабатывает событие закрытия главного окна."""
|
||||
if self.running_apps:
|
||||
msg_box = QMessageBox(self)
|
||||
msg_box.setWindowTitle('Подтверждение выхода')
|
||||
msg_box.setTextFormat(Qt.RichText)
|
||||
msg_box.setText('<font color="red">Все запущенные приложения будут закрыты вместе с WineHelper.</font><br><br>'
|
||||
"Вы уверены, что хотите выйти?")
|
||||
msg_box.setIcon(QMessageBox.Question)
|
||||
|
||||
yes_button = msg_box.addButton("Да", QMessageBox.YesRole)
|
||||
no_button = msg_box.addButton("Нет", QMessageBox.NoRole)
|
||||
msg_box.setDefaultButton(no_button)
|
||||
|
||||
msg_box.exec_()
|
||||
|
||||
if msg_box.clickedButton() == yes_button:
|
||||
# Корректно завершаем все дочерние процессы
|
||||
for desktop_path, process in list(self.running_apps.items()):
|
||||
if process.state() == QProcess.Running:
|
||||
print(f"Завершение процесса для {desktop_path}...")
|
||||
process.terminate()
|
||||
if not process.waitForFinished(2000): # Ждем 2 сек
|
||||
process.kill() # Если не закрылся, убиваем
|
||||
event.accept()
|
||||
else:
|
||||
event.ignore()
|
||||
else:
|
||||
super().closeEvent(event)
|
||||
|
||||
def uninstall_app(self):
|
||||
"""Удаляет выбранное установленное приложение и его префикс"""
|
||||
if not self.current_selected_app or 'desktop_path' not in self.current_selected_app:
|
||||
|
Reference in New Issue
Block a user