forked from CastroFidel/winehelper
added control buttons for dxvk/vkd3d
This commit is contained in:
86
winehelper
86
winehelper
@@ -776,9 +776,10 @@ init_wined3d () {
|
|||||||
init_dxvk () {
|
init_dxvk () {
|
||||||
check_variables USE_DXVK_VER "$1"
|
check_variables USE_DXVK_VER "$1"
|
||||||
|
|
||||||
get_dxvk () {
|
get_dxvk() {
|
||||||
DXVK_URL="$1"
|
local DXVK_URL="$1"
|
||||||
DXVK_PACKAGE="${WH_VULKAN_LIBDIR}/dxvk-${DXVK_VAR_VER}.tar.$(echo ${DXVK_URL#*.tar.})"
|
local DXVK_VAR_VER="$2"
|
||||||
|
local DXVK_PACKAGE="${WH_VULKAN_LIBDIR}/${DXVK_VAR_VER}.tar.$(echo "${DXVK_URL#*.tar.}")"
|
||||||
if try_download "$DXVK_URL" "$DXVK_PACKAGE" check256sum \
|
if try_download "$DXVK_URL" "$DXVK_PACKAGE" check256sum \
|
||||||
&& unpack "$DXVK_PACKAGE" "$WH_VULKAN_LIBDIR"
|
&& unpack "$DXVK_PACKAGE" "$WH_VULKAN_LIBDIR"
|
||||||
then
|
then
|
||||||
@@ -789,8 +790,8 @@ init_dxvk () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for DXVK_VAR_VER in "$USE_DXVK_VER" $@ ; do
|
for DXVK_VAR_VER in "$USE_DXVK_VER" $@ ; do
|
||||||
if [[ ! -d "${WH_VULKAN_LIBDIR}/dxvk-$DXVK_VAR_VER" ]] ; then
|
if [[ ! -d "${WH_VULKAN_LIBDIR}/${DXVK_VAR_VER}" ]] ; then
|
||||||
get_dxvk "$CLOUD_URL/dxvk-${DXVK_VAR_VER}.tar.xz"
|
get_dxvk "$CLOUD_URL/${DXVK_VAR_VER}.tar.xz" "$DXVK_VAR_VER"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
@@ -803,8 +804,8 @@ init_dxvk () {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
for dxvkfiles in $DXVK_FILES ; do
|
for dxvkfiles in $DXVK_FILES ; do
|
||||||
try_copy_other_dll_to_pfx_64 "${WH_VULKAN_LIBDIR}/dxvk-$USE_DXVK_VER/x64/$dxvkfiles.dll"
|
try_copy_other_dll_to_pfx_64 "${WH_VULKAN_LIBDIR}/${USE_DXVK_VER}/x64/$dxvkfiles.dll"
|
||||||
if try_copy_other_dll_to_pfx_32 "${WH_VULKAN_LIBDIR}/dxvk-$USE_DXVK_VER/x32/$dxvkfiles.dll"
|
if try_copy_other_dll_to_pfx_32 "${WH_VULKAN_LIBDIR}/${USE_DXVK_VER}/x32/$dxvkfiles.dll"
|
||||||
then var_winedlloverride_update "$dxvkfiles=n"
|
then var_winedlloverride_update "$dxvkfiles=n"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
@@ -813,9 +814,10 @@ init_dxvk () {
|
|||||||
init_vkd3d () {
|
init_vkd3d () {
|
||||||
check_variables USE_VKD3D_VER "$1"
|
check_variables USE_VKD3D_VER "$1"
|
||||||
|
|
||||||
get_vkd3d () {
|
get_vkd3d() {
|
||||||
VKD3D_URL="$1"
|
local VKD3D_URL="$1"
|
||||||
VKD3D_PACKAGE="${WH_VULKAN_LIBDIR}/vkd3d-proton-${VKD3D_VAR_VER}.tar.$(echo ${VKD3D_URL#*.tar.})"
|
local VKD3D_VAR_VER="$2"
|
||||||
|
local VKD3D_PACKAGE="${WH_VULKAN_LIBDIR}/${VKD3D_VAR_VER}.tar.$(echo "${VKD3D_URL#*.tar.}")"
|
||||||
if try_download "$VKD3D_URL" "$VKD3D_PACKAGE" check256sum \
|
if try_download "$VKD3D_URL" "$VKD3D_PACKAGE" check256sum \
|
||||||
&& unpack "$VKD3D_PACKAGE" "$WH_VULKAN_LIBDIR"
|
&& unpack "$VKD3D_PACKAGE" "$WH_VULKAN_LIBDIR"
|
||||||
then
|
then
|
||||||
@@ -826,15 +828,15 @@ init_vkd3d () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for VKD3D_VAR_VER in "$USE_VKD3D_VER" $@ ; do
|
for VKD3D_VAR_VER in "$USE_VKD3D_VER" $@ ; do
|
||||||
if [[ ! -d "${WH_VULKAN_LIBDIR}/vkd3d-proton-$VKD3D_VAR_VER" ]] ; then
|
if [[ ! -d "${WH_VULKAN_LIBDIR}/${VKD3D_VAR_VER}" ]] ; then
|
||||||
get_vkd3d "$CLOUD_URL/vkd3d-proton-${VKD3D_VAR_VER}.tar.xz"
|
get_vkd3d "$CLOUD_URL/${VKD3D_VAR_VER}.tar.xz" "$VKD3D_VAR_VER"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
VKD3D_FILES="d3d12 d3d12core libvkd3d-shader-1 libvkd3d-1" # libvkd3d-proton-utils-3
|
VKD3D_FILES="d3d12 d3d12core libvkd3d-shader-1 libvkd3d-1" # libvkd3d-proton-utils-3
|
||||||
for vkd3dfiles in $VKD3D_FILES ; do
|
for vkd3dfiles in $VKD3D_FILES ; do
|
||||||
try_copy_other_dll_to_pfx_64 "${WH_VULKAN_LIBDIR}/vkd3d-proton-$USE_VKD3D_VER/x64/$vkd3dfiles.dll"
|
try_copy_other_dll_to_pfx_64 "${WH_VULKAN_LIBDIR}/${USE_VKD3D_VER}/x64/$vkd3dfiles.dll"
|
||||||
if try_copy_other_dll_to_pfx_32 "${WH_VULKAN_LIBDIR}/vkd3d-proton-$USE_VKD3D_VER/x86/$vkd3dfiles.dll"
|
if try_copy_other_dll_to_pfx_32 "${WH_VULKAN_LIBDIR}/${USE_VKD3D_VER}/x86/$vkd3dfiles.dll"
|
||||||
then var_winedlloverride_update "$vkd3dfiles=n"
|
then var_winedlloverride_update "$vkd3dfiles=n"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
@@ -2011,6 +2013,57 @@ restore_prefix() {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
update_last_conf_var() {
|
||||||
|
local var_name="$1"
|
||||||
|
local new_value="$2"
|
||||||
|
local conf_file="$WINEPREFIX/last.conf"
|
||||||
|
|
||||||
|
if [[ ! -f "$conf_file" ]]; then
|
||||||
|
print_warning "Файл last.conf не найден, не могу обновить переменную $var_name."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if grep -q "export $var_name=" "$conf_file"; then
|
||||||
|
sed -i "s|^export $var_name=.*|export $var_name=\"$new_value\"|" "$conf_file"
|
||||||
|
else
|
||||||
|
echo "export $var_name=\"$new_value\"" >> "$conf_file"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
run_install_dxvk() {
|
||||||
|
local version="$1"
|
||||||
|
check_prefix_var
|
||||||
|
init_database
|
||||||
|
init_wine_ver
|
||||||
|
init_wineprefix
|
||||||
|
if [[ "$version" == "none" ]] ; then
|
||||||
|
print_info "Удаление DXVK..."
|
||||||
|
init_wined3d
|
||||||
|
update_last_conf_var "DXVK_VER" ""
|
||||||
|
else
|
||||||
|
init_dxvk "$version"
|
||||||
|
update_last_conf_var "DXVK_VER" "$USE_DXVK_VER"
|
||||||
|
fi
|
||||||
|
wait_wineserver
|
||||||
|
}
|
||||||
|
|
||||||
|
run_install_vkd3d() {
|
||||||
|
local version="$1"
|
||||||
|
check_prefix_var
|
||||||
|
init_database
|
||||||
|
init_wine_ver
|
||||||
|
init_wineprefix
|
||||||
|
if [[ "$version" == "none" ]] ; then
|
||||||
|
print_info "Удаление VKD3D..."
|
||||||
|
init_wined3d
|
||||||
|
update_last_conf_var "VKD3D_VER" ""
|
||||||
|
else
|
||||||
|
init_vkd3d "$version"
|
||||||
|
update_last_conf_var "VKD3D_VER" "$USE_VKD3D_VER"
|
||||||
|
fi
|
||||||
|
wait_wineserver
|
||||||
|
}
|
||||||
|
|
||||||
wh_info () {
|
wh_info () {
|
||||||
echo "Использование: $SCRIPT_NAME [команда]
|
echo "Использование: $SCRIPT_NAME [команда]
|
||||||
|
|
||||||
@@ -2019,6 +2072,9 @@ wh_info () {
|
|||||||
install [скрипт] запустить скрипт установки программы
|
install [скрипт] запустить скрипт установки программы
|
||||||
install [скрипт] --clear-pfx не использовать готовый префикс для установки ПО
|
install [скрипт] --clear-pfx не использовать готовый префикс для установки ПО
|
||||||
|
|
||||||
|
install-dxvk [версия|none] установить/удалить DXVK в выбранный префикс
|
||||||
|
install-vkd3d [версия|none] установить/удалить VKD3D в выбранный префикс
|
||||||
|
|
||||||
installed список установленных программ
|
installed список установленных программ
|
||||||
run [программа] запуск программы (отладка)
|
run [программа] запуск программы (отладка)
|
||||||
remove-all удалить WineHelper и все связанные данные
|
remove-all удалить WineHelper и все связанные данные
|
||||||
@@ -2066,6 +2122,8 @@ case "$arg1" in
|
|||||||
winetricks) prepair_wine ; "$WH_WINETRICKS" -q "$@" ;;
|
winetricks) prepair_wine ; "$WH_WINETRICKS" -q "$@" ;;
|
||||||
desktop) create_desktop "$@" ; exit 0 ;;
|
desktop) create_desktop "$@" ; exit 0 ;;
|
||||||
install|-i) run_autoinstall "$@" ;;
|
install|-i) run_autoinstall "$@" ;;
|
||||||
|
install-dxvk) run_install_dxvk "$@" ;;
|
||||||
|
install-vkd3d) run_install_vkd3d "$@" ;;
|
||||||
installed) check_installed_programs "$1" ;;
|
installed) check_installed_programs "$1" ;;
|
||||||
run|-r) run_installed_programs "$1" ;;
|
run|-r) run_installed_programs "$1" ;;
|
||||||
backup-prefix) backup_prefix "$@" ;;
|
backup-prefix) backup_prefix "$@" ;;
|
||||||
|
@@ -1078,7 +1078,7 @@ class WineVersionSelectionDialog(QDialog):
|
|||||||
if not line:
|
if not line:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
match = re.match(r'^#+\s+([A-Z_]+)\s+#*$', line)
|
match = re.match(r'^#+\s*([^#]+?)\s*#*$', line)
|
||||||
if match:
|
if match:
|
||||||
group_name = match.group(1)
|
group_name = match.group(1)
|
||||||
allowed_groups = {"WINE", "WINE_LG", "PROTON_LG", "PROTON_STEAM"}
|
allowed_groups = {"WINE", "WINE_LG", "PROTON_LG", "PROTON_STEAM"}
|
||||||
@@ -1354,6 +1354,118 @@ class CreatePrefixDialog(QDialog):
|
|||||||
|
|
||||||
self.accept()
|
self.accept()
|
||||||
|
|
||||||
|
class ComponentVersionSelectionDialog(QDialog):
|
||||||
|
"""Диалог для выбора версии компонента (DXVK, VKD3D)."""
|
||||||
|
|
||||||
|
def __init__(self, component_group, title, parent=None, add_extra_options=True):
|
||||||
|
super().__init__(parent)
|
||||||
|
self.component_group = component_group
|
||||||
|
self.selected_version = None
|
||||||
|
self.versions_data = []
|
||||||
|
|
||||||
|
self.setWindowTitle(title)
|
||||||
|
self.setMinimumSize(600, 400)
|
||||||
|
self.setModal(True)
|
||||||
|
|
||||||
|
main_layout = QVBoxLayout(self)
|
||||||
|
|
||||||
|
self.search_edit = QLineEdit()
|
||||||
|
self.search_edit.setPlaceholderText("Поиск версии...")
|
||||||
|
self.search_edit.textChanged.connect(self.filter_versions)
|
||||||
|
main_layout.addWidget(self.search_edit)
|
||||||
|
|
||||||
|
self.scroll_area = QScrollArea()
|
||||||
|
self.scroll_area.setWidgetResizable(True)
|
||||||
|
main_layout.addWidget(self.scroll_area)
|
||||||
|
|
||||||
|
scroll_content = QWidget()
|
||||||
|
self.scroll_area.setWidget(scroll_content)
|
||||||
|
|
||||||
|
self.grid_layout = QGridLayout(scroll_content)
|
||||||
|
self.grid_layout.setAlignment(Qt.AlignTop)
|
||||||
|
|
||||||
|
self.buttons = []
|
||||||
|
# Кнопка "Удалить" теперь находится вне сетки, поэтому начинаем с 0 строки.
|
||||||
|
self.load_versions(start_row=0)
|
||||||
|
|
||||||
|
# --- Панель с кнопками действий внизу диалога ---
|
||||||
|
button_layout = QHBoxLayout()
|
||||||
|
|
||||||
|
if add_extra_options:
|
||||||
|
uninstall_btn = QPushButton("Удалить из префикса")
|
||||||
|
uninstall_btn.setToolTip("Удаляет текущую установленную версию компонента из префикса.")
|
||||||
|
uninstall_btn.clicked.connect(partial(self.on_version_selected, "none"))
|
||||||
|
# Добавляем кнопку слева
|
||||||
|
button_layout.addWidget(uninstall_btn)
|
||||||
|
|
||||||
|
button_layout.addStretch(1) # Растягиваем пространство, чтобы разнести кнопки
|
||||||
|
|
||||||
|
cancel_button = QPushButton("Отмена")
|
||||||
|
cancel_button.clicked.connect(self.reject)
|
||||||
|
button_layout.addWidget(cancel_button)
|
||||||
|
|
||||||
|
main_layout.addLayout(button_layout)
|
||||||
|
|
||||||
|
def load_versions(self, start_row):
|
||||||
|
"""Загружает и отображает версии."""
|
||||||
|
self._parse_sha256_list()
|
||||||
|
self.populate_ui(start_row)
|
||||||
|
|
||||||
|
def _parse_sha256_list(self):
|
||||||
|
"""Парсит sha256sum.list для получения списка версий."""
|
||||||
|
sha256_path = os.path.join(Var.DATA_PATH, "sha256sum.list")
|
||||||
|
if not os.path.exists(sha256_path):
|
||||||
|
self.versions_data = []
|
||||||
|
return
|
||||||
|
|
||||||
|
current_group = None
|
||||||
|
try:
|
||||||
|
with open(sha256_path, 'r', encoding='utf-8') as f:
|
||||||
|
for line in f:
|
||||||
|
line = line.strip()
|
||||||
|
if not line:
|
||||||
|
continue
|
||||||
|
match = re.match(r'^#+\s*([^#]+?)\s*#*$', line)
|
||||||
|
if match:
|
||||||
|
current_group = match.group(1).strip()
|
||||||
|
continue
|
||||||
|
if current_group == self.component_group and re.match(r'^[a-f0-9]{64}', line):
|
||||||
|
parts = line.split(maxsplit=1)
|
||||||
|
if len(parts) == 2:
|
||||||
|
filename = parts[1]
|
||||||
|
if filename.endswith('.tar.xz'):
|
||||||
|
version_name = filename[:-7]
|
||||||
|
self.versions_data.append(version_name)
|
||||||
|
except IOError:
|
||||||
|
self.versions_data = []
|
||||||
|
|
||||||
|
def populate_ui(self, start_row):
|
||||||
|
"""Заполняет UI кнопками версий."""
|
||||||
|
versions = sorted(self.versions_data, reverse=True)
|
||||||
|
num_columns = 3
|
||||||
|
row, col = start_row, 0
|
||||||
|
for version_name in versions:
|
||||||
|
btn = QPushButton(version_name)
|
||||||
|
btn.clicked.connect(partial(self.on_version_selected, version_name))
|
||||||
|
self.grid_layout.addWidget(btn, row, col)
|
||||||
|
self.buttons.append(btn)
|
||||||
|
col += 1
|
||||||
|
if col >= num_columns:
|
||||||
|
col = 0
|
||||||
|
row += 1
|
||||||
|
|
||||||
|
def filter_versions(self):
|
||||||
|
"""Фильтрует видимость кнопок версий на основе текста поиска."""
|
||||||
|
search_text = self.search_edit.text().lower()
|
||||||
|
for btn_widget in self.buttons:
|
||||||
|
is_match = search_text in btn_widget.text().lower()
|
||||||
|
btn_widget.setVisible(is_match)
|
||||||
|
|
||||||
|
def on_version_selected(self, version_name):
|
||||||
|
"""Обрабатывает выбор версии."""
|
||||||
|
self.selected_version = version_name
|
||||||
|
self.accept()
|
||||||
|
|
||||||
class WineHelperGUI(QMainWindow):
|
class WineHelperGUI(QMainWindow):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
@@ -1980,11 +2092,29 @@ class WineHelperGUI(QMainWindow):
|
|||||||
self.prefix_winefile_button.setToolTip("Запуск файлового менеджера Wine (winefile) для просмотра файлов внутри префикса.")
|
self.prefix_winefile_button.setToolTip("Запуск файлового менеджера Wine (winefile) для просмотра файлов внутри префикса.")
|
||||||
management_layout.addWidget(self.prefix_winefile_button, 2, 1)
|
management_layout.addWidget(self.prefix_winefile_button, 2, 1)
|
||||||
|
|
||||||
|
# Добавляем небольшой отступ
|
||||||
|
spacer_widget = QWidget()
|
||||||
|
spacer_widget.setFixedHeight(5)
|
||||||
|
management_layout.addWidget(spacer_widget, 3, 0, 1, 2)
|
||||||
|
|
||||||
|
self.dxvk_manage_button = QPushButton("Управление DXVK")
|
||||||
|
self.dxvk_manage_button.setMinimumHeight(32)
|
||||||
|
self.dxvk_manage_button.clicked.connect(lambda: self.open_component_version_manager('dxvk'))
|
||||||
|
self.dxvk_manage_button.setToolTip("Установка или удаление определенной версии DXVK в префиксе.")
|
||||||
|
management_layout.addWidget(self.dxvk_manage_button, 4, 0)
|
||||||
|
|
||||||
|
self.vkd3d_manage_button = QPushButton("Управление VKD3D")
|
||||||
|
self.vkd3d_manage_button.setMinimumHeight(32)
|
||||||
|
self.vkd3d_manage_button.clicked.connect(lambda: self.open_component_version_manager('vkd3d-proton'))
|
||||||
|
self.vkd3d_manage_button.setToolTip("Установка или удаление определенной версии vkd3d-proton в префиксе.")
|
||||||
|
management_layout.addWidget(self.vkd3d_manage_button, 4, 1)
|
||||||
|
|
||||||
# --- Правая сторона: Информационный блок ---
|
# --- Правая сторона: Информационный блок ---
|
||||||
self.prefix_info_display = QTextBrowser()
|
self.prefix_info_display = QTextBrowser()
|
||||||
self.prefix_info_display.setReadOnly(True)
|
self.prefix_info_display.setReadOnly(True)
|
||||||
self.prefix_info_display.setFrameStyle(QFrame.StyledPanel)
|
self.prefix_info_display.setFrameStyle(QFrame.StyledPanel)
|
||||||
management_layout.addWidget(self.prefix_info_display, 0, 2, 3, 1)
|
# Увеличиваем rowspan, чтобы учесть добавленный отступ
|
||||||
|
management_layout.addWidget(self.prefix_info_display, 0, 2, 5, 1)
|
||||||
|
|
||||||
management_layout.setColumnStretch(0, 1)
|
management_layout.setColumnStretch(0, 1)
|
||||||
management_layout.setColumnStretch(1, 1)
|
management_layout.setColumnStretch(1, 1)
|
||||||
@@ -1994,7 +2124,7 @@ class WineHelperGUI(QMainWindow):
|
|||||||
separator = QFrame()
|
separator = QFrame()
|
||||||
separator.setFrameShape(QFrame.HLine)
|
separator.setFrameShape(QFrame.HLine)
|
||||||
separator.setFrameShadow(QFrame.Sunken)
|
separator.setFrameShadow(QFrame.Sunken)
|
||||||
management_layout.addWidget(separator, 3, 0, 1, 3)
|
management_layout.addWidget(separator, 5, 0, 1, 3)
|
||||||
|
|
||||||
install_group = QWidget()
|
install_group = QWidget()
|
||||||
install_layout = QVBoxLayout(install_group)
|
install_layout = QVBoxLayout(install_group)
|
||||||
@@ -2027,7 +2157,7 @@ class WineHelperGUI(QMainWindow):
|
|||||||
action_buttons_layout.addWidget(self.create_launcher_button)
|
action_buttons_layout.addWidget(self.create_launcher_button)
|
||||||
install_layout.addLayout(action_buttons_layout)
|
install_layout.addLayout(action_buttons_layout)
|
||||||
|
|
||||||
management_layout.addWidget(install_group, 4, 0, 1, 3)
|
management_layout.addWidget(install_group, 6, 0, 1, 3)
|
||||||
|
|
||||||
container_layout.addWidget(self.prefix_management_groupbox)
|
container_layout.addWidget(self.prefix_management_groupbox)
|
||||||
layout.addWidget(self.management_container_groupbox)
|
layout.addWidget(self.management_container_groupbox)
|
||||||
@@ -2220,8 +2350,10 @@ class WineHelperGUI(QMainWindow):
|
|||||||
"WINEARCH": ("Архитектура", lambda v: "64-bit" if v == "win64" else "32-bit"),
|
"WINEARCH": ("Архитектура", lambda v: "64-bit" if v == "win64" else "32-bit"),
|
||||||
"WH_WINE_USE": ("Версия Wine", lambda v: "Системная" if v == "system" else v),
|
"WH_WINE_USE": ("Версия Wine", lambda v: "Системная" if v == "system" else v),
|
||||||
"BASE_PFX": ("Тип", lambda v: 'Чистый' if v == "none" else 'С рекомендуемыми библиотеками'),
|
"BASE_PFX": ("Тип", lambda v: 'Чистый' if v == "none" else 'С рекомендуемыми библиотеками'),
|
||||||
|
"DXVK_VER": ("Версия DXVK", lambda v: v if v else "Не установлено"),
|
||||||
|
"VKD3D_VER": ("Версия VKD3D", lambda v: v if v else "Не установлено"),
|
||||||
}
|
}
|
||||||
display_order = ["WINEPREFIX", "WINEARCH", "WH_WINE_USE", "BASE_PFX"]
|
display_order = ["WINEPREFIX", "WINEARCH", "WH_WINE_USE", "BASE_PFX", "DXVK_VER", "VKD3D_VER"]
|
||||||
|
|
||||||
html_content = f'<p style="line-height: 1.3; font-size: 9pt;">'
|
html_content = f'<p style="line-height: 1.3; font-size: 9pt;">'
|
||||||
html_content += f"<b>Имя:</b> {html.escape(prefix_name)}<br>"
|
html_content += f"<b>Имя:</b> {html.escape(prefix_name)}<br>"
|
||||||
@@ -2310,6 +2442,128 @@ class WineHelperGUI(QMainWindow):
|
|||||||
self.command_process.start(wine_executable, args)
|
self.command_process.start(wine_executable, args)
|
||||||
self.command_dialog.exec_()
|
self.command_dialog.exec_()
|
||||||
|
|
||||||
|
def _get_prefix_component_version(self, prefix_name, component_key):
|
||||||
|
"""
|
||||||
|
Читает last.conf префикса и возвращает версию указанного компонента.
|
||||||
|
:param prefix_name: Имя префикса.
|
||||||
|
:param component_key: Ключ компонента (например, 'DXVK_VER').
|
||||||
|
:return: Строку с версией или None, если не найдено или значение пустое.
|
||||||
|
"""
|
||||||
|
if not prefix_name:
|
||||||
|
return None
|
||||||
|
|
||||||
|
last_conf_path = os.path.join(Var.USER_WORK_PATH, "prefixes", prefix_name, "last.conf")
|
||||||
|
if not os.path.exists(last_conf_path):
|
||||||
|
return None
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(last_conf_path, 'r', encoding='utf-8') as f:
|
||||||
|
for line in f:
|
||||||
|
line = line.strip()
|
||||||
|
# Ищем строку вида 'export KEY="value"' или 'export KEY=value'
|
||||||
|
if line.startswith('export '):
|
||||||
|
parts = line[7:].split('=', 1)
|
||||||
|
if len(parts) == 2:
|
||||||
|
key = parts[0].strip()
|
||||||
|
if key == component_key:
|
||||||
|
value = parts[1].strip().strip('"\'')
|
||||||
|
# Возвращаем значение, только если оно не пустое.
|
||||||
|
return value if value else None
|
||||||
|
except IOError as e:
|
||||||
|
print(f"Ошибка чтения last.conf для {prefix_name}: {e}")
|
||||||
|
return None
|
||||||
|
return None
|
||||||
|
|
||||||
|
def open_component_version_manager(self, component):
|
||||||
|
"""Открывает диалог выбора версии для DXVK/VKD3D и запускает установку."""
|
||||||
|
prefix_name = self.current_managed_prefix_name
|
||||||
|
if not prefix_name:
|
||||||
|
QMessageBox.warning(self, "Ошибка", "Сначала выберите префикс.")
|
||||||
|
return
|
||||||
|
|
||||||
|
component_key = None
|
||||||
|
if component == 'dxvk':
|
||||||
|
group = 'DXVK'
|
||||||
|
title = f"Управление DXVK для префикса: {prefix_name}"
|
||||||
|
command = 'install-dxvk'
|
||||||
|
component_key = 'DXVK_VER'
|
||||||
|
elif component == 'vkd3d-proton':
|
||||||
|
group = 'VKD3D'
|
||||||
|
title = f"Управление vkd3d для префикса: {prefix_name}"
|
||||||
|
command = 'install-vkd3d'
|
||||||
|
component_key = 'VKD3D_VER'
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
|
||||||
|
dialog = ComponentVersionSelectionDialog(group, title, self)
|
||||||
|
if dialog.exec_() == QDialog.Accepted and dialog.selected_version:
|
||||||
|
version = dialog.selected_version
|
||||||
|
|
||||||
|
if version == "none":
|
||||||
|
# Удаление: сначала проверяем, есть ли что удалять.
|
||||||
|
installed_version = self._get_prefix_component_version(prefix_name, component_key)
|
||||||
|
if not installed_version:
|
||||||
|
QMessageBox.information(self, "Информация", "Установленных версий нет.")
|
||||||
|
return # Прерываем выполнение, т.к. удалять нечего
|
||||||
|
# Для удаления лицензия не нужна, запускаем сразу.
|
||||||
|
self.run_component_install_command(prefix_name, command, version)
|
||||||
|
else:
|
||||||
|
# Установка: сначала показываем лицензионное соглашение.
|
||||||
|
if not self._show_license_agreement_dialog():
|
||||||
|
return # Пользователь отклонил лицензию
|
||||||
|
|
||||||
|
# Если лицензия принята, запускаем установку.
|
||||||
|
self.run_component_install_command(prefix_name, command, version)
|
||||||
|
|
||||||
|
def run_component_install_command(self, prefix_name, command, version):
|
||||||
|
"""Выполняет команду установки компонента (DXVK/VKD3D) через winehelper."""
|
||||||
|
prefix_path = os.path.join(Var.USER_WORK_PATH, "prefixes", prefix_name)
|
||||||
|
|
||||||
|
self.command_dialog = QDialog(self)
|
||||||
|
self.command_dialog.setWindowTitle(f"Выполнение: {command} {version}")
|
||||||
|
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)
|
||||||
|
self.command_process.setProcessEnvironment(env)
|
||||||
|
|
||||||
|
args = [command, version]
|
||||||
|
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 _handle_component_install_finished(self, prefix_name, exit_code, exit_status):
|
||||||
|
"""Обрабатывает завершение установки компонента и обновляет информацию о префиксе."""
|
||||||
|
# Вызываем общий обработчик для обновления лога и кнопки закрытия
|
||||||
|
self._handle_command_finished(exit_code, exit_status)
|
||||||
|
|
||||||
|
# В случае успеха обновляем панель информации о префиксе
|
||||||
|
if exit_code == 0:
|
||||||
|
self.update_prefix_info_display(prefix_name)
|
||||||
|
|
||||||
def create_launcher_for_prefix(self):
|
def create_launcher_for_prefix(self):
|
||||||
"""
|
"""
|
||||||
Открывает диалог для создания ярлыка для приложения внутри выбранного префикса.
|
Открывает диалог для создания ярлыка для приложения внутри выбранного префикса.
|
||||||
|
Reference in New Issue
Block a user