added a button to create a program shortcut

the function of extracting an icon from an exe file is combined with the creation of a desktop file
added the function of automatic prefix detection if it is not specified
This commit is contained in:
Sergey Palcheh
2025-09-02 16:23:39 +06:00
parent 92a682ba8a
commit ab0e23952e
2 changed files with 254 additions and 79 deletions

View File

@@ -509,63 +509,29 @@ var_ld_library_path_update () {
return 0 return 0
} }
extract_icon() {
check_prefix_var
local exe_file="$1"
local ico_name="$(basename "$exe_file" .exe).ico"
local png_name="$(basename "$exe_file" .exe).png"
local tmp_ico_dir="$WH_TMP_DIR/icons"
local user_icons="$WINEPREFIX/icons"
create_new_dir "$tmp_ico_dir"
if ! wrestool -x -t 14 "$exe_file" -o "$tmp_ico_dir/$ico_name" ; then
print_warning "Не удалось извлечь иконку из $exe_file"
try_remove_file "$tmp_ico_dir"
return 1
fi
if ! icotool -x -i 1 "$tmp_ico_dir/$ico_name" -o "$tmp_ico_dir/$png_name" ; then
print_warning "Не удалось извлечь иконку из $ico_name"
try_remove_file "$tmp_ico_dir"
return 1
fi
create_new_dir "$user_icons"
if ! try_copy_file "$tmp_ico_dir/$png_name" "$user_icons" ; then
print_warning "Не удалось копировать иконку в префикс"
try_remove_file "$user_icons"
return 1
fi
try_remove_dir "$tmp_ico_dir"
print_ok "Иконка сохранена: $user_icons/$png_name"
return 0
}
create_desktop () { create_desktop () {
local name_desktop exe_file desktop_filename icon_file desktop_path local name_desktop exe_file desktop_filename icon_file desktop_path icon_arg desktop_filename_arg
name_desktop="$1" name_desktop="$1"
exe_file="$2" exe_file="$2"
if [[ -n $4 ]] && [[ $4 != "nocopy" ]]; icon_arg="$3"
then desktop_filename="$4" desktop_filename_arg="$4"
else desktop_filename="$(basename "$exe_file" .exe | sed "s| |_|")"
fi # Определяем имя desktop-файла
if [[ "$RESTORE_FROM_BACKUP" == "1" ]] && [[ -f "$3" ]] if [[ -n "$desktop_filename_arg" ]] && [[ "$desktop_filename_arg" != "nocopy" ]]; then
then icon_file="$3" desktop_filename="$desktop_filename_arg"
elif [[ -f "$WH_IMAGE_PATH/$3.png" ]] else
then icon_file="$WH_IMAGE_PATH/$3.png" desktop_filename="$(basename "$exe_file" .exe | sed "s| |_|g")"
else icon_file="wine"
fi fi
# Проверяем обязательные аргументы и наличие exe-файла
if [[ -z "$name_desktop" ]] || [[ -z "$exe_file" ]] ; then if [[ -z "$name_desktop" ]] || [[ -z "$exe_file" ]] ; then
fatal "Used: $SCRIPT_NAME --desktop \"desktop_name\" \"path_to_exe\" \"name_png_from_image\"" fatal "Использование: $0 create-desktop \"Имя ярлыка\" \"/путь/к/файлу.exe\" [иконка|auto] [имя_desktop_файла]"
elif [[ ! -f "$exe_file" ]] ; then elif [[ ! -f "$exe_file" ]] ; then
print_warning "Для создания ярлыка не найден исполняемый файл: $exe_file" print_warning "Для создания ярлыка не найден исполняемый файл: $exe_file"
BASENAME_EXE="$(basename "$exe_file")" local BASENAME_EXE="$(basename "$exe_file")"
print_info "Запускаем поиск $BASENAME_EXE" print_info "Запускаем поиск $BASENAME_EXE"
local FIND_PATH
if [[ -z "$DRIVE_C" ]] || [[ ! -d "$DRIVE_C" ]] if [[ -z "$DRIVE_C" ]] || [[ ! -d "$DRIVE_C" ]]
then FIND_PATH="$WH_PREFIXES_DIR" then FIND_PATH="$WH_PREFIXES_DIR"
else FIND_PATH="$DRIVE_C" else FIND_PATH="$DRIVE_C"
@@ -575,11 +541,55 @@ create_desktop () {
-iname "$BASENAME_EXE")" -iname "$BASENAME_EXE")"
if [[ -z "$exe_file" ]] || [[ ! -f "$exe_file" ]] if [[ -z "$exe_file" ]] || [[ ! -f "$exe_file" ]]
then fatal "Для создания ярлыка не найден исполняемый файл: $BASENAME_EXE" then fatal "Для создания ярлыка не найден исполняемый файл: $BASENAME_EXE"
else print_ok "Исполняемый файл $BASENAME_EXE найден по пути $(dirname "$exe_file")/" else print_ok "Исполняемый файл $BASENAME_EXE найден по пути: $(dirname "$exe_file")/"
fi fi
fi fi
# создаем .desktop файл # --- Логика обработки иконки ---
local user_icons_dir="$WINEPREFIX/icons"
create_new_dir "$user_icons_dir"
# Случай 1: Восстановление из бэкапа (передан явный путь)
if [[ "$RESTORE_FROM_BACKUP" == "1" ]] && [[ -f "$icon_arg" ]]; then
icon_file="$icon_arg"
# Случай 2: 'auto' или пустой аргумент - пытаемся извлечь из EXE
elif [[ -z "$icon_arg" ]] || [[ "$icon_arg" == "auto" ]]; then
print_info "Попытка извлечь иконку из $exe_file..."
local png_name="$(basename "$exe_file" .exe).png"
local extracted_icon_path="$user_icons_dir/$png_name"
# Проверяем, существует ли иконка, чтобы избежать повторного извлечения
if [[ -f "$extracted_icon_path" ]]; then
print_info "Иконка уже существует: $extracted_icon_path"
icon_file="$extracted_icon_path"
else
local tmp_ico_dir="$WH_TMP_DIR/icons_$$" # Используем PID для временного каталога
create_new_dir "$tmp_ico_dir"
local ico_name="$(basename "$exe_file" .exe).ico"
if wrestool -x -t 14 "$exe_file" -o "$tmp_ico_dir/$ico_name" &>/dev/null && \
icotool -x -i 1 "$tmp_ico_dir/$ico_name" -o "$tmp_ico_dir/$png_name" &>/dev/null && \
try_copy_file "$tmp_ico_dir/$png_name" "$user_icons_dir/"; then
icon_file="$extracted_icon_path"
print_ok "Иконка успешно извлечена и сохранена: $icon_file"
else
print_warning "Не удалось извлечь иконку из $exe_file. Используется иконка по умолчанию."
icon_file="wine" # Запасной вариант
fi
try_remove_dir "$tmp_ico_dir"
fi
# Случай 3: Передано конкретное имя иконки
elif [[ -f "$WH_IMAGE_PATH/$icon_arg.png" ]]; then
icon_file="$WH_IMAGE_PATH/$icon_arg.png"
# Случай 4: Запасной вариант по умолчанию
else
print_info "Иконка '$icon_arg' не найдена. Используется иконка по умолчанию."
icon_file="wine"
fi
# --- Конец логики обработки иконки ---
# Создаем .desktop файл
create_new_dir "$WH_MENU_DIR" create_new_dir "$WH_MENU_DIR"
{ {
echo "[Desktop Entry]" echo "[Desktop Entry]"
@@ -596,19 +606,29 @@ create_desktop () {
cp -f "$USER_WORK_PATH/$desktop_filename.desktop" "$WH_MENU_DIR/" cp -f "$USER_WORK_PATH/$desktop_filename.desktop" "$WH_MENU_DIR/"
if [[ "$RESTORE_FROM_BACKUP" == "1" ]] ; then if [[ "$RESTORE_FROM_BACKUP" == "1" ]] ; then
print_info "Пропускаем обновление desktop.list (режим восстановления из бэкапа)" print_info "Пропускаем обновление desktop.list (режим восстановления)"
else else
# добавляем информацию о приложении в "$WINEPREFIX/desktop.list" # Добавляем информацию о приложении в "$WINEPREFIX/desktop.list"
if [[ -f "$WINEPREFIX/desktop.list" ]] \ if [[ -f "$WINEPREFIX/desktop.list" ]] \
&& grep -qe "^${name_desktop}=" "$WINEPREFIX/desktop.list" && grep -qe "^${name_desktop}=" "$WINEPREFIX/desktop.list"
then sed -i "/^$name_desktop=/d" "$WINEPREFIX/desktop.list" then sed -i "/^$name_desktop=/d" "$WINEPREFIX/desktop.list"
fi fi
create_new_dir "$WINEPREFIX/icons"
try_copy_file "$icon_file" "$WINEPREFIX/icons/" # Копируем финальную иконку в директорию иконок префикса, если ее там нет
echo "$name_desktop=${exe_file//$WINEPREFIX/}=$(basename "$icon_file")" >> "$WINEPREFIX/desktop.list" local final_icon_name
if [[ -f "$icon_file" ]]; then
final_icon_name=$(basename "$icon_file")
if [[ ! -f "$user_icons_dir/$final_icon_name" ]]; then
try_copy_file "$icon_file" "$user_icons_dir/"
fi
else
final_icon_name="$icon_file" # например, "wine"
fi
echo "$name_desktop=${exe_file//$WINEPREFIX/}=${final_icon_name}" >> "$WINEPREFIX/desktop.list"
fi fi
# создаем файл категории для меню # Создаем файл категории для меню
create_new_dir "$HOME/.local/share/desktop-directories" create_new_dir "$HOME/.local/share/desktop-directories"
if [[ ! -f "$WH_MENU_CATEGORY" ]] ; then if [[ ! -f "$WH_MENU_CATEGORY" ]] ; then
cat > "$WH_MENU_CATEGORY" <<EOF cat > "$WH_MENU_CATEGORY" <<EOF
@@ -619,7 +639,7 @@ Icon=wine
EOF EOF
fi fi
# Создаем файл меню для всех приложений # Создаем файл меню для всех приложений WineHelper
create_new_dir "$HOME/.config/menus/applications-merged" create_new_dir "$HOME/.config/menus/applications-merged"
if [[ ! -f "$WH_MENU_CONFIG" ]] ; then if [[ ! -f "$WH_MENU_CONFIG" ]] ; then
cat > "$WH_MENU_CONFIG" <<EOF cat > "$WH_MENU_CONFIG" <<EOF
@@ -638,15 +658,15 @@ EOF
EOF EOF
fi fi
# Обновляем кэш desktop файлов # Обновляем кэш desktop-файлов
update-desktop-database "$HOME/.local/share/applications" update-desktop-database "$HOME/.local/share/applications"
if [[ $4 != "nocopy" ]] ; then if [[ "$desktop_filename_arg" != "nocopy" ]] ; then
desktop_path="$(xdg-user-dir DESKTOP)" desktop_path="$(xdg-user-dir DESKTOP)"
print_info "В меню и на рабочем столе создан $desktop_filename.desktop" print_info "В меню и на рабочем столе создан ярлык: $desktop_filename.desktop"
cp -f "$USER_WORK_PATH/$desktop_filename.desktop" "$desktop_path" cp -f "$USER_WORK_PATH/$desktop_filename.desktop" "$desktop_path"
else else
print_info "В меню создан $desktop_filename.desktop" print_info "В меню создан ярлык: $desktop_filename.desktop"
fi fi
if [[ -n "$INSTALL_SCRIPT_NAME" ]] \ if [[ -n "$INSTALL_SCRIPT_NAME" ]] \
@@ -2044,6 +2064,16 @@ case "$arg1" in
*) *)
if [[ -f "$arg1" ]] ; then if [[ -f "$arg1" ]] ; then
WIN_FILE_EXEC="$(readlink -f "$arg1")" WIN_FILE_EXEC="$(readlink -f "$arg1")"
# Автоматическое определение префикса, если он не задан
if [[ -z "$WINEPREFIX" ]] && [[ "$WIN_FILE_EXEC" == "$WH_PREFIXES_DIR"* ]]; then
extracted_prefix="$(echo "$WIN_FILE_EXEC" | grep -o ".*/prefixes/[^/]*")"
if [[ -d "$extracted_prefix" ]]; then
export WINEPREFIX="$extracted_prefix"
print_info "Префикс автоматически определен: $(basename "$WINEPREFIX")"
fi
fi
WIN_FILE_NAME="$(basename "$arg1")" WIN_FILE_NAME="$(basename "$arg1")"
case "${WIN_FILE_NAME,,}" in case "${WIN_FILE_NAME,,}" in
*.exe) prepair_wine ; wine_run $WINE_WIN_START "$WIN_FILE_EXEC" "$@" ;; *.exe) prepair_wine ; wine_run $WINE_WIN_START "$WIN_FILE_EXEC" "$@" ;;

View File

@@ -12,7 +12,7 @@ import hashlib
from functools import partial from functools import partial
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,QPushButton, QLabel, QTabWidget, QTabBar, from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,QPushButton, QLabel, QTabWidget, QTabBar,
QTextEdit, QFileDialog, QMessageBox, QLineEdit, QCheckBox, QStackedWidget, QScrollArea, QFormLayout, QGroupBox, QRadioButton, QComboBox, QTextEdit, QFileDialog, QMessageBox, QLineEdit, QCheckBox, QStackedWidget, QScrollArea, QFormLayout, QGroupBox, QRadioButton, QComboBox,
QListWidget, QListWidgetItem, QGridLayout, QFrame, QDialog, QTextBrowser) QListWidget, QListWidgetItem, QGridLayout, QFrame, QDialog, QTextBrowser, QInputDialog)
from PyQt5.QtCore import Qt, QProcess, QSize, QTimer, QProcessEnvironment, QPropertyAnimation, QEasingCurve from PyQt5.QtCore import Qt, QProcess, QSize, QTimer, QProcessEnvironment, QPropertyAnimation, QEasingCurve
from PyQt5.QtGui import QIcon, QFont, QTextCursor, QPixmap, QPainter, QDesktopServices from PyQt5.QtGui import QIcon, QFont, QTextCursor, QPixmap, QPainter, QDesktopServices
from PyQt5.QtNetwork import QLocalServer, QLocalSocket from PyQt5.QtNetwork import QLocalServer, QLocalSocket
@@ -965,7 +965,8 @@ class ScriptParser:
if part == 'create_desktop': if part == 'create_desktop':
if len(parts) > i + 3: if len(parts) > i + 3:
icon_name = parts[i + 3] icon_name = parts[i + 3]
if icon_name: # Игнорируем служебные слова, которые не являются иконками
if icon_name and icon_name.lower() not in ('auto', 'nocopy'):
icon_names.append(icon_name) icon_names.append(icon_name)
except (ValueError, IndexError): except (ValueError, IndexError):
continue continue
@@ -1975,7 +1976,7 @@ class WineHelperGUI(QMainWindow):
install_path_layout = QHBoxLayout() install_path_layout = QHBoxLayout()
self.prefix_install_path_edit = QLineEdit() self.prefix_install_path_edit = QLineEdit()
self.prefix_install_path_edit.setPlaceholderText("Путь к .exe или .msi файлу...") self.prefix_install_path_edit.setPlaceholderText("Укажите путь к установочному файлу .exe или .msi...")
install_path_layout.addWidget(self.prefix_install_path_edit) install_path_layout.addWidget(self.prefix_install_path_edit)
self.prefix_browse_button = QPushButton("Обзор...") self.prefix_browse_button = QPushButton("Обзор...")
@@ -1983,10 +1984,21 @@ class WineHelperGUI(QMainWindow):
install_path_layout.addWidget(self.prefix_browse_button) install_path_layout.addWidget(self.prefix_browse_button)
install_layout.addLayout(install_path_layout) install_layout.addLayout(install_path_layout)
# Layout для кнопок установки и создания ярлыка
action_buttons_layout = QHBoxLayout()
self.prefix_install_button = QPushButton("Установить приложение в префикс") self.prefix_install_button = QPushButton("Установить приложение в префикс")
self.prefix_install_button.setEnabled(False) self.prefix_install_button.setEnabled(False)
self.prefix_install_button.clicked.connect(self.run_prefix_installer) self.prefix_install_button.clicked.connect(self.run_prefix_installer)
install_layout.addWidget(self.prefix_install_button) action_buttons_layout.addWidget(self.prefix_install_button)
self.create_launcher_button = QPushButton("Создать ярлык для приложения в префиксе")
self.create_launcher_button.setToolTip(
"Создает ярлык в меню и на вкладке 'Установленные' для .exe файла внутри префикса.")
self.create_launcher_button.clicked.connect(self.create_launcher_for_prefix)
self.create_launcher_button.setEnabled(False) # Изначально неактивна
action_buttons_layout.addWidget(self.create_launcher_button)
install_layout.addLayout(action_buttons_layout)
management_layout.addWidget(install_group, 4, 0, 1, 3) management_layout.addWidget(install_group, 4, 0, 1, 3)
@@ -2001,6 +2013,19 @@ class WineHelperGUI(QMainWindow):
self.wine_version_edit.textChanged.connect(self.update_create_prefix_button_state) self.wine_version_edit.textChanged.connect(self.update_create_prefix_button_state)
self.prefix_install_path_edit.textChanged.connect(self.update_prefix_install_button_state) self.prefix_install_path_edit.textChanged.connect(self.update_prefix_install_button_state)
def _remove_prefix_from_gui_state(self, prefix_name):
"""Удаляет префикс из внутреннего состояния и пользовательского интерфейса вкладки 'Создать префикс'."""
if prefix_name in self.created_prefixes_info:
del self.created_prefixes_info[prefix_name]
index_to_remove = self.created_prefix_selector.findText(prefix_name)
if index_to_remove != -1:
self.created_prefix_selector.removeItem(index_to_remove)
# Сохраняем состояние после удаления. on_created_prefix_selected также вызовет сохранение,
# но этот вызов гарантирует сохранение, даже если сигналы были заблокированы.
self._save_state()
def _load_state(self): def _load_state(self):
"""Загружает последнее состояние GUI из файла.""" """Загружает последнее состояние GUI из файла."""
if not os.path.exists(self.state_file): if not os.path.exists(self.state_file):
@@ -2075,31 +2100,59 @@ class WineHelperGUI(QMainWindow):
msg_box.setIcon(QMessageBox.Question) msg_box.setIcon(QMessageBox.Question)
msg_box.setWindowTitle('Подтверждение удаления') msg_box.setWindowTitle('Подтверждение удаления')
msg_box.setText(f'Вы уверены, что хотите удалить префикс "{prefix_name}"?\n\n' msg_box.setText(f'Вы уверены, что хотите удалить префикс "{prefix_name}"?\n\n'
'Это действие необратимо и удалит все данные внутри префикса.') 'Это действие необратимо и удалит все данные внутри префикса, а также все связанные с ним ярлыки.')
yes_button = msg_box.addButton("Да", QMessageBox.YesRole) yes_button = msg_box.addButton("Да, удалить", QMessageBox.YesRole)
no_button = msg_box.addButton("Нет", QMessageBox.NoRole) no_button = msg_box.addButton("Нет", QMessageBox.NoRole)
msg_box.setDefaultButton(no_button) msg_box.setDefaultButton(no_button)
msg_box.exec_() msg_box.exec_()
# Если пользователь нажал не "Да", выходим
if msg_box.clickedButton() != yes_button: if msg_box.clickedButton() != yes_button:
return return
prefix_path = os.path.join(Var.USER_WORK_PATH, "prefixes", prefix_name) # Используем модальный диалог для отображения процесса удаления
self.command_dialog = QDialog(self)
self.command_dialog.setWindowTitle(f"Удаление префикса: {prefix_name}")
self.command_dialog.setMinimumSize(750, 400)
self.command_dialog.setModal(True)
self.command_dialog.setWindowFlags(self.command_dialog.windowFlags() & ~Qt.WindowCloseButtonHint)
try: layout = QVBoxLayout()
if os.path.isdir(prefix_path): self.command_log_output = QTextEdit()
shutil.rmtree(prefix_path) self.command_log_output.setReadOnly(True)
if prefix_name in self.created_prefixes_info: self.command_log_output.setFont(QFont('DejaVu Sans Mono', 10))
del self.created_prefixes_info[prefix_name] layout.addWidget(self.command_log_output)
index_to_remove = self.created_prefix_selector.findText(prefix_name)
if index_to_remove != -1: self.command_close_button = QPushButton("Закрыть")
self.created_prefix_selector.removeItem(index_to_remove) self.command_close_button.setEnabled(False)
QMessageBox.information(self, "Успех", f"Префикс '{prefix_name}' был успешно удален.") self.command_close_button.clicked.connect(self.command_dialog.close)
except Exception as e: layout.addWidget(self.command_close_button)
QMessageBox.critical(self, "Ошибка удаления", f"Не удалось удалить префикс '{prefix_name}':\n{e}") 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_prefix_deletion_finished(prefix_name, exit_code, exit_status)
)
args = ["remove-prefix", prefix_name, "--force"]
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_prefix_deletion_finished(self, prefix_name, exit_code, exit_status):
"""Обрабатывает завершение процесса удаления префикса."""
self._handle_command_finished(exit_code, exit_status)
if exit_code == 0:
# Успешное удаление, обновляем GUI
self._remove_prefix_from_gui_state(prefix_name)
self.update_installed_apps()
QMessageBox.information(self, "Успех", f"Префикс '{prefix_name}' и все связанные с ним данные были успешно удалены.")
else:
QMessageBox.critical(self, "Ошибка удаления", f"Не удалось удалить префикс '{prefix_name}'.\nПодробности смотрите в логе.")
def on_prefix_name_edited(self, text): def on_prefix_name_edited(self, text):
"""Сбрасывает состояние управления префиксом, когда пользователь вводит новое имя.""" """Сбрасывает состояние управления префиксом, когда пользователь вводит новое имя."""
@@ -2116,6 +2169,9 @@ class WineHelperGUI(QMainWindow):
self.prefix_management_groupbox.setEnabled(False) self.prefix_management_groupbox.setEnabled(False)
self.prefix_info_display.clear() self.prefix_info_display.clear()
self.prefix_install_path_edit.clear() self.prefix_install_path_edit.clear()
# Кнопка "Создать ярлык" должна быть активна, если выбран действительный префикс
is_prefix_selected = bool(prefix_name and prefix_name in self.created_prefixes_info)
self.create_launcher_button.setEnabled(is_prefix_selected)
self.update_prefix_install_button_state() self.update_prefix_install_button_state()
def update_prefix_info_display(self, prefix_name): def update_prefix_info_display(self, prefix_name):
@@ -2197,6 +2253,79 @@ 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 create_launcher_for_prefix(self):
"""
Открывает диалог для создания ярлыка для приложения внутри выбранного префикса.
"""
prefix_name = self.current_managed_prefix_name
if not prefix_name:
QMessageBox.warning(self, "Ошибка", "Сначала выберите префикс.")
return
prefix_path = os.path.join(Var.USER_WORK_PATH, "prefixes", prefix_name)
drive_c_path = os.path.join(prefix_path, "drive_c")
if not os.path.isdir(drive_c_path):
QMessageBox.critical(self, "Ошибка", f"Диск C: для префикса '{prefix_name}' не найден.")
return
# 1. Открываем диалог выбора файла для .exe
exe_path, _ = QFileDialog.getOpenFileName(
self,
"Выберите исполняемый файл (.exe) для создания ярлыка",
drive_c_path,
"Исполняемые файлы (*.exe)"
)
if not exe_path:
return # Пользователь отменил
# 2. Запрашиваем имя для ярлыка
app_name, ok = QInputDialog.getText(
self,
"Имя ярлыка",
"Введите имя для нового ярлыка:",
QLineEdit.Normal,
os.path.splitext(os.path.basename(exe_path))[0] # Предлагаем имя из .exe
)
if not ok or not app_name.strip():
return # Пользователь отменил или ввел пустое имя
# 3. Вызываем winehelper.sh create-desktop
self.command_dialog = QDialog(self)
self.command_dialog.setWindowTitle(f"Создание ярлыка для: {app_name}")
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(self._handle_launcher_creation_finished)
env = QProcessEnvironment.systemEnvironment()
env.insert("WINEPREFIX", prefix_path)
self.command_process.setProcessEnvironment(env)
args = ["desktop", app_name, exe_path, "auto"]
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_help_tab(self): def create_help_tab(self):
"""Создает вкладку 'Справка' с подвкладками""" """Создает вкладку 'Справка' с подвкладками"""
help_tab = QWidget() help_tab = QWidget()
@@ -2503,6 +2632,7 @@ class WineHelperGUI(QMainWindow):
"""Обрабатывает завершение установки в префикс.""" """Обрабатывает завершение установки в префикс."""
if exit_code == 0: if exit_code == 0:
self.command_log_output.append("\n=== Установка успешно завершена ===") self.command_log_output.append("\n=== Установка успешно завершена ===")
self.create_launcher_button.setEnabled(True) # Активируем кнопку создания ярлыка
else: else:
self.command_log_output.append(f"\n=== Ошибка выполнения (код: {exit_code}) ===") self.command_log_output.append(f"\n=== Ошибка выполнения (код: {exit_code}) ===")
@@ -2962,6 +3092,9 @@ class WineHelperGUI(QMainWindow):
except Exception as e: except Exception as e:
raise RuntimeError(f"Ошибка удаления префикса: {str(e)}") raise RuntimeError(f"Ошибка удаления префикса: {str(e)}")
# Обновляем состояние на вкладке "Создать префикс"
self._remove_prefix_from_gui_state(prefix_name)
# 3. Удаляем ВСЕ найденные .desktop файлы, связанные с этим префиксом # 3. Удаляем ВСЕ найденные .desktop файлы, связанные с этим префиксом
removed_files = [] removed_files = []
for file_path in all_desktop_files: for file_path in all_desktop_files:
@@ -3514,6 +3647,18 @@ class WineHelperGUI(QMainWindow):
self.command_process = None self.command_process = None
self.command_close_button.setEnabled(True) self.command_close_button.setEnabled(True)
def _handle_launcher_creation_finished(self, exit_code, exit_status):
"""Обрабатывает завершение создания ярлыка."""
self._handle_command_finished(exit_code, exit_status)
if exit_code == 0:
QMessageBox.information(self, "Успех", "Ярлык успешно создан.")
self.update_installed_apps()
# Переключаемся на вкладку "Установленные"
for i in range(self.tab_bar.count()):
if self.tab_bar.tabText(i) == "Установленные":
self.tab_bar.setCurrentIndex(i)
break
def _handle_restore_finished(self, exit_code, exit_status): def _handle_restore_finished(self, exit_code, exit_status):
"""Обрабатывает завершение для диалога команды восстановления.""" """Обрабатывает завершение для диалога команды восстановления."""
if exit_code == 0: if exit_code == 0: