forked from CastroFidel/winehelper
Compare commits
19 Commits
504be8ea5b
...
0.5.4
Author | SHA1 | Date | |
---|---|---|---|
|
a15b2621b6 | ||
|
fd00b61c71 | ||
|
74eaf34c00 | ||
|
a69493df73 | ||
|
6b958dd7f1 | ||
|
2483f4c66c | ||
|
ab0e23952e | ||
|
92a682ba8a | ||
|
3381054c21 | ||
|
76b7d4f046 | ||
|
aeae544640 | ||
|
eeb94523b3 | ||
|
a2186b63cb | ||
|
839b480c39 | ||
|
83fe362b37 | ||
|
f7fdfca743 | ||
|
ffc7098aba | ||
|
50de9bdb14 | ||
|
ddea68c11c |
@@ -1,5 +1,14 @@
|
||||
История изменений:
|
||||
|
||||
0.5.4:
|
||||
* обновлен графический режим Qt5:
|
||||
- добавлена возможность установки системных зависимостей
|
||||
- исправлены/улучшены основные функции
|
||||
- добавлено управление префиксами (в разработке)
|
||||
- добавлена возможность создания ярлыка
|
||||
* добавлено автоматическое создание иконки для ярлыков (desktop файлов)
|
||||
* префикс tflex17 переименован в tflex (т.к. 18-я версия работает в том же префиксе)
|
||||
|
||||
0.5.3:
|
||||
* исправлена установка grdcontrol для t-flex-*
|
||||
* обновлен графический режим Qt5
|
||||
|
@@ -1,14 +1,14 @@
|
||||
Лицензионные соглашения использования сторонних компонентов:
|
||||
Отказ от ответственности:
|
||||
|
||||
Некоторые компоненты, установленные в префикс и необходимые для запуска приложений,
|
||||
могут быть защищены авторским правом или лицензионными соглашениями. Вы обязаны
|
||||
самостоятельно убедиться в законности использования этих компонентов в вашей
|
||||
юрисдикции.
|
||||
Некоторые компоненты, устанавливаемые в префикс и необходимые для запуска
|
||||
приложений, могут быть защищены авторским правом или лицензионными
|
||||
соглашениями. Вы обязаны самостоятельно убедиться в законности использования
|
||||
этих компонентов в вашей юрисдикции.
|
||||
|
||||
Мы не несём ответственности за нарушение лицензионных соглашений, связанное с
|
||||
использованием подготовленного префикса, а так же за программное обеспечение,
|
||||
поставляемое из сторонних источников.
|
||||
использованием подготовленного префикса, а также за программное обеспечение,
|
||||
полученное из сторонних источников.
|
||||
|
||||
Подтверждая продолжение установки, вы соглашаетесь, что ознакомились с данным
|
||||
отказом от ответственности и принимаете все риски, связанные с использованием
|
||||
программного обеспечения.
|
||||
Продолжая установку, вы подтверждаете, что ознакомились с данным отказом от
|
||||
ответственности и принимаете все риски, связанные с использованием программного
|
||||
обеспечения.
|
||||
|
@@ -8,7 +8,7 @@ export WH_WINE_USE="wine_wh_tflex_10-9_amd64"
|
||||
export BASE_PFX="tflex17_pfx_x64_v02"
|
||||
export WINEARCH="win64"
|
||||
export WH_WINDOWS_VER="10"
|
||||
export WINEPREFIX="tflex17"
|
||||
export WINEPREFIX="tflex"
|
||||
export WH_XDG_OPEN="log"
|
||||
export WH_USE_MESA_GL_OVERRIDE="1"
|
||||
|
||||
|
@@ -8,7 +8,7 @@ export WH_WINE_USE="wine_wh_tflex_10-9_amd64"
|
||||
export BASE_PFX="tflex17_pfx_x64_v02"
|
||||
export WINEARCH="win64"
|
||||
export WH_WINDOWS_VER="10"
|
||||
export WINEPREFIX="tflex17"
|
||||
export WINEPREFIX="tflex"
|
||||
export WH_XDG_OPEN="log"
|
||||
export WH_USE_MESA_GL_OVERRIDE="1"
|
||||
|
||||
|
@@ -8,7 +8,7 @@ export WH_WINDOWS_VER="10"
|
||||
export WH_WINE_USE="wine_wh_tflex_10-9_amd64"
|
||||
export BASE_PFX="tflex17_pfx_x64_v02"
|
||||
export WINEARCH="win64"
|
||||
export WINEPREFIX="tflex17"
|
||||
export WINEPREFIX="tflex"
|
||||
export WH_XDG_OPEN="log"
|
||||
export WH_USE_MESA_GL_OVERRIDE="1"
|
||||
|
||||
|
@@ -8,7 +8,7 @@ export WH_WINDOWS_VER="10"
|
||||
export WH_WINE_USE="wine_wh_tflex_10-9_amd64"
|
||||
export BASE_PFX="tflex17_pfx_x64_v02"
|
||||
export WINEARCH="win64"
|
||||
export WINEPREFIX="tflex17"
|
||||
export WINEPREFIX="tflex"
|
||||
export WH_XDG_OPEN="log"
|
||||
export WH_USE_MESA_GL_OVERRIDE="1"
|
||||
|
||||
|
@@ -8,7 +8,7 @@ export WH_WINE_USE="wine_wh_tflex_10-9_amd64"
|
||||
export BASE_PFX="tflex17_pfx_x64_v02"
|
||||
export WINEARCH="win64"
|
||||
export WH_WINDOWS_VER="10"
|
||||
export WINEPREFIX="tflex17"
|
||||
export WINEPREFIX="tflex"
|
||||
export WH_XDG_OPEN="log"
|
||||
export WH_USE_MESA_GL_OVERRIDE="1"
|
||||
|
||||
|
@@ -8,7 +8,7 @@ export WH_WINE_USE="wine_wh_tflex_10-9_amd64"
|
||||
export BASE_PFX="tflex17_pfx_x64_v02"
|
||||
export WINEARCH="win64"
|
||||
export WH_WINDOWS_VER="10"
|
||||
export WINEPREFIX="tflex17"
|
||||
export WINEPREFIX="tflex"
|
||||
export WH_XDG_OPEN="log"
|
||||
export WH_USE_MESA_GL_OVERRIDE="1"
|
||||
|
||||
|
@@ -8,7 +8,7 @@ export WH_WINE_USE="wine_wh_tflex_10-9_amd64"
|
||||
export BASE_PFX="tflex17_pfx_x64_v02"
|
||||
export WINEARCH="win64"
|
||||
export WH_WINDOWS_VER="10"
|
||||
export WINEPREFIX="tflex17"
|
||||
export WINEPREFIX="tflex"
|
||||
export WH_XDG_OPEN="log"
|
||||
export WH_USE_MESA_GL_OVERRIDE="1"
|
||||
|
||||
|
@@ -5,7 +5,7 @@ export WH_WINDOWS_VER="10"
|
||||
export WH_WINE_USE="wine_wh_tflex_10-9_amd64"
|
||||
export BASE_PFX="tflex17_pfx_x64_v02"
|
||||
export WINEARCH="win64"
|
||||
export WINEPREFIX="tflex17"
|
||||
export WINEPREFIX="tflex"
|
||||
export PROG_VERSION=""
|
||||
export WH_XDG_OPEN="log"
|
||||
export INSTALL_DLL="corefonts d3dcompiler_47 dotnet48 vcrun2022 ucrtbase2019 msxml6 fontsmooth=rgb baekmuk droid eufonts ipamona liberation lucida opensymbol sourcehansans tahoma takao uff unifont vlgothic wenquanyi wenquanyizenhei"
|
||||
|
@@ -7,7 +7,7 @@ export WH_WINE_USE="wine_wh_tflex_10-9_amd64"
|
||||
export BASE_PFX="tflex17_pfx_x64_v02"
|
||||
export WINEARCH="win64"
|
||||
export WH_WINDOWS_VER="10"
|
||||
export WINEPREFIX="tflex17"
|
||||
export WINEPREFIX="tflex"
|
||||
export WH_XDG_OPEN="log"
|
||||
export WH_USE_MESA_GL_OVERRIDE="1"
|
||||
|
||||
|
0
sha256sum.list
Executable file → Normal file
0
sha256sum.list
Executable file → Normal file
181
winehelper
181
winehelper
@@ -177,7 +177,7 @@ fi
|
||||
|
||||
##### CHECK NOEXEC FOR /HOME #####
|
||||
if mount -l | grep -E "[[:space:]]/home[[:space:]]" | grep -q "noexec" ; then
|
||||
fatal "/home примонтирован в /etc/fstab с аргументом noexec.\nЗапуск портативной версии wine не возможен из домашнего каталога."
|
||||
fatal "/home примонтирован в /etc/fstab с аргументом noexec.\nЗапуск портативной версии wine невозможен из домашнего каталога."
|
||||
fi
|
||||
|
||||
##### ROOT #####
|
||||
@@ -190,7 +190,7 @@ su_run () {
|
||||
((i++))
|
||||
done
|
||||
else
|
||||
pkexec "$@" && return 0
|
||||
pkexec bash -c "$@" && return 0
|
||||
fi
|
||||
fatal "Не удалось установить необходимые компоненты!"
|
||||
}
|
||||
@@ -259,13 +259,13 @@ try_copy_dir () {
|
||||
|
||||
try_force_link_file () {
|
||||
if [[ ! -f "$1" ]] ; then
|
||||
print_warning "нет файла для создания символьной ссылки: $1"
|
||||
print_warning "нет файла для создания символической ссылки: $1"
|
||||
if [[ -f "$2" ]] ; then
|
||||
try_remove_file "$2"
|
||||
print_warning "удаляем символьную ссылку: $2"
|
||||
print_warning "удаляем символическую ссылку: $2"
|
||||
fi
|
||||
return 1
|
||||
elif [[ -z "$2" ]] ; then fatal "нет пути для создания символьной ссылки на файл $1"
|
||||
elif [[ -z "$2" ]] ; then fatal "нет пути для создания символической ссылки на файл $1"
|
||||
else
|
||||
try_remove_file "$2"
|
||||
ln -s -f -r "$1" "$2"
|
||||
@@ -275,11 +275,11 @@ try_force_link_file () {
|
||||
}
|
||||
|
||||
try_force_link_dir () {
|
||||
if [[ ! -d "$1" ]] ; then print_info "каталога $1 не существует для создания символьной сссылки"
|
||||
elif [[ -z "$2" ]] ; then fatal "не указан путь для создания символьной ссылки на каталог $1"
|
||||
if [[ ! -d "$1" ]] ; then print_info "каталога $1 не существует для создания символической сссылки"
|
||||
elif [[ -z "$2" ]] ; then fatal "не указан путь для создания символической ссылки на каталог $1"
|
||||
else
|
||||
ln -s -f -r "$1" "$2"
|
||||
[[ "$?" != 0 ]] && print_error "не удалось сделать символьную ссылку на каталог $1 по пути $2" || return 0
|
||||
[[ "$?" != 0 ]] && print_error "не удалось сделать символическую ссылку на каталог $1 по пути $2" || return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
@@ -328,7 +328,7 @@ try_get_page () {
|
||||
|| grep -q "Forbidden" "$OUT_PAGE_TMP"
|
||||
then
|
||||
try_remove_file "$OUT_PAGE_TMP"
|
||||
fatal "Страница сайта $1 не доступна, или превышено количество запросов к странице."
|
||||
fatal "Страница сайта $1 не доступна или превышено количество запросов к странице."
|
||||
else
|
||||
return 0
|
||||
fi
|
||||
@@ -509,63 +509,41 @@ var_ld_library_path_update () {
|
||||
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
|
||||
find_prefix () {
|
||||
# Автоматическое определение префикса, если он не задан
|
||||
if [[ -z "$WINEPREFIX" ]] && [[ "$1" == "$WH_PREFIXES_DIR"* ]]; then
|
||||
local extracted_prefix
|
||||
extracted_prefix="$(echo "$1" | grep -o ".*/prefixes/[^/]*")"
|
||||
if [[ -d "$extracted_prefix" ]]; then
|
||||
export WINEPREFIX="$extracted_prefix"
|
||||
print_info "Префикс автоматически определен: $(basename "$WINEPREFIX")"
|
||||
fi
|
||||
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 () {
|
||||
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"
|
||||
exe_file="$2"
|
||||
if [[ -n $4 ]] && [[ $4 != "nocopy" ]];
|
||||
then desktop_filename="$4"
|
||||
else desktop_filename="$(basename "$exe_file" .exe | sed "s| |_|")"
|
||||
fi
|
||||
if [[ "$RESTORE_FROM_BACKUP" == "1" ]] && [[ -f "$3" ]]
|
||||
then icon_file="$3"
|
||||
elif [[ -f "$WH_IMAGE_PATH/$3.png" ]]
|
||||
then icon_file="$WH_IMAGE_PATH/$3.png"
|
||||
else icon_file="wine"
|
||||
icon_arg="$3"
|
||||
desktop_filename_arg="$4"
|
||||
|
||||
# Определяем имя desktop-файла
|
||||
if [[ -n "$desktop_filename_arg" ]] && [[ "$desktop_filename_arg" != "nocopy" ]]; then
|
||||
desktop_filename="$desktop_filename_arg"
|
||||
else
|
||||
desktop_filename="$(basename "$exe_file" .exe | sed "s| |_|g")"
|
||||
fi
|
||||
|
||||
# Проверяем обязательные аргументы и наличие exe-файла
|
||||
if [[ -z "$name_desktop" ]] || [[ -z "$exe_file" ]] ; then
|
||||
fatal "Used: $SCRIPT_NAME --desktop \"desktop_name\" \"path_to_exe\" \"name_png_from_image\""
|
||||
fatal "Использование: $0 desktop \"Имя ярлыка\" \"/путь/к/файлу.exe\" [иконка|auto] [имя_desktop_файла]"
|
||||
elif [[ ! -f "$exe_file" ]] ; then
|
||||
print_warning "Для создания ярлыка не найден исполняемый файл: $exe_file"
|
||||
|
||||
BASENAME_EXE="$(basename "$exe_file")"
|
||||
local BASENAME_EXE="$(basename "$exe_file")"
|
||||
print_info "Запускаем поиск $BASENAME_EXE"
|
||||
local FIND_PATH
|
||||
if [[ -z "$DRIVE_C" ]] || [[ ! -d "$DRIVE_C" ]]
|
||||
then FIND_PATH="$WH_PREFIXES_DIR"
|
||||
else FIND_PATH="$DRIVE_C"
|
||||
@@ -575,11 +553,57 @@ create_desktop () {
|
||||
-iname "$BASENAME_EXE")"
|
||||
if [[ -z "$exe_file" ]] || [[ ! -f "$exe_file" ]]
|
||||
then fatal "Для создания ярлыка не найден исполняемый файл: $BASENAME_EXE"
|
||||
else print_ok "Исполняемый файл $BASENAME_EXE найден по пути $(dirname "$exe_file")/"
|
||||
else print_ok "Исполняемый файл $BASENAME_EXE найден по пути: $(dirname "$exe_file")/"
|
||||
fi
|
||||
fi
|
||||
|
||||
# создаем .desktop файл
|
||||
find_prefix "$exe_file"
|
||||
|
||||
# --- Логика обработки иконки ---
|
||||
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"
|
||||
{
|
||||
echo "[Desktop Entry]"
|
||||
@@ -596,19 +620,29 @@ create_desktop () {
|
||||
cp -f "$USER_WORK_PATH/$desktop_filename.desktop" "$WH_MENU_DIR/"
|
||||
|
||||
if [[ "$RESTORE_FROM_BACKUP" == "1" ]] ; then
|
||||
print_info "Пропускаем обновление desktop.list (режим восстановления из бэкапа)"
|
||||
print_info "Пропускаем обновление desktop.list (режим восстановления)"
|
||||
else
|
||||
# добавляем информацию о приложении в "$WINEPREFIX/desktop.list"
|
||||
# Добавляем информацию о приложении в "$WINEPREFIX/desktop.list"
|
||||
if [[ -f "$WINEPREFIX/desktop.list" ]] \
|
||||
&& grep -qe "^${name_desktop}=" "$WINEPREFIX/desktop.list"
|
||||
then sed -i "/^$name_desktop=/d" "$WINEPREFIX/desktop.list"
|
||||
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
|
||||
|
||||
# создаем файл категории для меню
|
||||
# Создаем файл категории для меню
|
||||
create_new_dir "$HOME/.local/share/desktop-directories"
|
||||
if [[ ! -f "$WH_MENU_CATEGORY" ]] ; then
|
||||
cat > "$WH_MENU_CATEGORY" <<EOF
|
||||
@@ -619,7 +653,7 @@ Icon=wine
|
||||
EOF
|
||||
fi
|
||||
|
||||
# Создаем файл меню для всех приложений
|
||||
# Создаем файл меню для всех приложений WineHelper
|
||||
create_new_dir "$HOME/.config/menus/applications-merged"
|
||||
if [[ ! -f "$WH_MENU_CONFIG" ]] ; then
|
||||
cat > "$WH_MENU_CONFIG" <<EOF
|
||||
@@ -638,15 +672,15 @@ EOF
|
||||
EOF
|
||||
fi
|
||||
|
||||
# Обновляем кэш desktop файлов
|
||||
# Обновляем кэш desktop-файлов
|
||||
update-desktop-database "$HOME/.local/share/applications"
|
||||
|
||||
if [[ $4 != "nocopy" ]] ; then
|
||||
if [[ "$desktop_filename_arg" != "nocopy" ]] ; then
|
||||
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"
|
||||
else
|
||||
print_info "В меню создан $desktop_filename.desktop"
|
||||
print_info "В меню создан ярлык: $desktop_filename.desktop"
|
||||
fi
|
||||
|
||||
if [[ -n "$INSTALL_SCRIPT_NAME" ]] \
|
||||
@@ -1074,7 +1108,7 @@ init_wineprefix () {
|
||||
if [[ ! -f "$WINEPREFIX/.firstboot" ]] ; then
|
||||
create_new_dir "$WINEPREFIX"
|
||||
if [[ "$CLEAR_PREFIX" == "1" ]]
|
||||
then print_warning "Используется переменная \"CLEAR_PREFIX=1\" что принудительно создает чистый префикс с установкой компонентов с помощью winetricks."
|
||||
then print_warning "Используется переменная \"CLEAR_PREFIX=1\", которая принудительно создает чистый префикс с установкой компонентов с помощью winetricks."
|
||||
elif [[ "$BASE_PFX" != "none" ]]
|
||||
then get_base_pfx "$BASE_PFX"
|
||||
fi
|
||||
@@ -1165,7 +1199,7 @@ init_wineprefix () {
|
||||
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\""
|
||||
print_info "Используются ассоциации с нативными приложениями для файлов: \"$WH_XDG_OPEN\""
|
||||
else
|
||||
# удаление команды xdg-open из реестра
|
||||
get_and_set_reg_file --delete "$XDG_OPEN_REG" '@='
|
||||
@@ -1193,7 +1227,7 @@ init_wineprefix () {
|
||||
"${cpcsp_proxy_cmd[@]}" | tee "$WINEPREFIX/cpcsp_setup.log"
|
||||
local CPCSP_EXIT_STATUS="${PIPESTATUS[0]}"
|
||||
if grep -q "failed to load /opt/cprocsp/" "$WINEPREFIX/cpcsp_setup.log" ; then
|
||||
fatal "Проверьте правильность установки CryptoPro в системе.\n Инструкция: https://www.altlinux.org/CryptoPro"
|
||||
fatal "Проверьте правильность установки КриптоПро в системе.\n Инструкция: https://www.altlinux.org/CryptoPro"
|
||||
fi
|
||||
|
||||
if [[ $CPCSP_EXIT_STATUS == "0" ]] ; then
|
||||
@@ -1535,9 +1569,7 @@ select_wine_version() {
|
||||
group_versions+=("$version_name")
|
||||
fi
|
||||
else # win32
|
||||
if [[ "$version_name" =~ i[3-6]86 ]]; then
|
||||
group_versions+=("$version_name")
|
||||
fi
|
||||
group_versions+=("$version_name")
|
||||
fi
|
||||
fi
|
||||
done < "$sha256_file"
|
||||
@@ -1717,7 +1749,7 @@ remove_winehelper () {
|
||||
echo " Это удалит:"
|
||||
echo " - Все настройки WineHelper"
|
||||
echo " - Все приложения/программы, установленные через WineHelper"
|
||||
echo " - Все ярлыки из меню и с рабочего стола созданные с помощью WineHelper"
|
||||
echo " - Все ярлыки из меню и с рабочего стола, созданные с помощью WineHelper"
|
||||
echo "======================================================"
|
||||
if print_confirmation "Продолжить?" ; then
|
||||
echo "----------------------------------------------"
|
||||
@@ -2046,7 +2078,8 @@ case "$arg1" in
|
||||
*)
|
||||
if [[ -f "$arg1" ]] ; then
|
||||
WIN_FILE_EXEC="$(readlink -f "$arg1")"
|
||||
WIN_FILE_NAME="$(basename "$arg1")"
|
||||
WIN_FILE_NAME="$(basename "$WIN_FILE_EXEC")"
|
||||
find_prefix "$WIN_FILE_EXEC"
|
||||
case "${WIN_FILE_NAME,,}" in
|
||||
*.exe) prepair_wine ; wine_run $WINE_WIN_START "$WIN_FILE_EXEC" "$@" ;;
|
||||
*.msi) prepair_wine ; wine_run msiexec /i "$WIN_FILE_EXEC" "$@" ;;
|
||||
|
@@ -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)
|
||||
QListWidget, QListWidgetItem, QGridLayout, QFrame, QDialog, QTextBrowser, QInputDialog)
|
||||
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
|
||||
@@ -340,13 +340,8 @@ class DependencyManager:
|
||||
still_missing = missing_packages
|
||||
|
||||
if not still_missing:
|
||||
info_box = QMessageBox(dialog)
|
||||
info_box.setWindowIcon(self.app_icon)
|
||||
info_box.setIcon(QMessageBox.Information)
|
||||
info_box.setWindowTitle("Успех")
|
||||
info_box.setText("Все необходимые зависимости были успешно установлены.")
|
||||
info_box.exec_()
|
||||
installation_successful = True
|
||||
close_button.setText("Запустить WineHelper")
|
||||
else:
|
||||
warn_box = QMessageBox(dialog)
|
||||
warn_box.setWindowIcon(self.app_icon)
|
||||
@@ -359,8 +354,16 @@ class DependencyManager:
|
||||
)
|
||||
warn_box.exec_()
|
||||
else:
|
||||
log_tag = "ПРЕРВАНО" if exit_status == QProcess.CrashExit else "ОШИБКА"
|
||||
log_output.append(f"\n<b><font color='red'>=== {log_tag} (код: {exit_code}) ===</font></b>")
|
||||
if exit_code == 127: # pkexec: пользователь отменил аутентификацию
|
||||
log_output.append("\n<b><font color='orange'>=== УСТАНОВКА ОТМЕНЕНА ПОЛЬЗОВАТЕЛЕМ ===</font></b>")
|
||||
log_output.append("Вы отменили ввод пароля. Установка зависимостей не была выполнена.")
|
||||
elif exit_code == 126: # pkexec: у пользователя нет прав
|
||||
log_output.append("\n<b><font color='red'>=== ОШИБКА: НЕДОСТАТОЧНО ПРАВ ===</font></b>")
|
||||
log_output.append("У вашего пользователя нет прав для выполнения этой операции.")
|
||||
else:
|
||||
log_tag = "ПРЕРВАНО" if exit_status == QProcess.CrashExit else "ОШИБКА"
|
||||
log_output.append(f"\n<b><font color='red'>=== {log_tag} (код: {exit_code}) ===</font></b>")
|
||||
log_output.append("Произошла непредвиденная ошибка во время установки.")
|
||||
log_output.ensureCursorVisible()
|
||||
|
||||
close_button.setEnabled(True)
|
||||
@@ -962,7 +965,8 @@ class ScriptParser:
|
||||
if part == 'create_desktop':
|
||||
if len(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)
|
||||
except (ValueError, IndexError):
|
||||
continue
|
||||
@@ -1035,13 +1039,6 @@ class WineVersionSelectionDialog(QDialog):
|
||||
|
||||
self.version_tabs = QTabWidget()
|
||||
main_layout.addWidget(self.version_tabs)
|
||||
button_layout = QHBoxLayout()
|
||||
self.refresh_button = QPushButton("Обновить список")
|
||||
self.refresh_button.setIcon(QIcon.fromTheme("view-refresh"))
|
||||
self.refresh_button.clicked.connect(self.load_versions)
|
||||
button_layout.addStretch()
|
||||
button_layout.addWidget(self.refresh_button)
|
||||
main_layout.addLayout(button_layout)
|
||||
|
||||
self.load_versions()
|
||||
|
||||
@@ -1055,14 +1052,12 @@ class WineVersionSelectionDialog(QDialog):
|
||||
loading_layout.addWidget(status_label)
|
||||
self.version_tabs.addTab(loading_widget, "Загрузка...")
|
||||
self.version_tabs.setEnabled(False)
|
||||
self.refresh_button.setEnabled(False)
|
||||
|
||||
QApplication.processEvents()
|
||||
|
||||
self._parse_sha256_list()
|
||||
self.populate_ui()
|
||||
|
||||
self.refresh_button.setEnabled(True)
|
||||
self.version_tabs.setEnabled(True)
|
||||
|
||||
def _parse_sha256_list(self):
|
||||
@@ -1150,14 +1145,16 @@ class WineVersionSelectionDialog(QDialog):
|
||||
if is_win64:
|
||||
if re_64bit.search(name) or not re_32bit.search(name):
|
||||
filtered_versions.append(name)
|
||||
else: # win32
|
||||
if re_32bit.search(name):
|
||||
filtered_versions.append(name)
|
||||
else:
|
||||
filtered_versions.append(name)
|
||||
|
||||
if not filtered_versions:
|
||||
continue
|
||||
|
||||
pretty_key = key.replace('_', ' ').title()
|
||||
if key.endswith('_LG'):
|
||||
pretty_key = pretty_key.replace(' Lg', ' LG')
|
||||
|
||||
self._create_version_tab(pretty_key, filtered_versions)
|
||||
|
||||
self.filter_versions()
|
||||
@@ -1979,7 +1976,7 @@ class WineHelperGUI(QMainWindow):
|
||||
|
||||
install_path_layout = QHBoxLayout()
|
||||
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)
|
||||
|
||||
self.prefix_browse_button = QPushButton("Обзор...")
|
||||
@@ -1987,10 +1984,21 @@ class WineHelperGUI(QMainWindow):
|
||||
install_path_layout.addWidget(self.prefix_browse_button)
|
||||
install_layout.addLayout(install_path_layout)
|
||||
|
||||
# Layout для кнопок установки и создания ярлыка
|
||||
action_buttons_layout = QHBoxLayout()
|
||||
|
||||
self.prefix_install_button = QPushButton("Установить приложение в префикс")
|
||||
self.prefix_install_button.setEnabled(False)
|
||||
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)
|
||||
|
||||
@@ -2005,6 +2013,19 @@ class WineHelperGUI(QMainWindow):
|
||||
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)
|
||||
|
||||
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):
|
||||
"""Загружает последнее состояние GUI из файла."""
|
||||
if not os.path.exists(self.state_file):
|
||||
@@ -2079,31 +2100,59 @@ class WineHelperGUI(QMainWindow):
|
||||
msg_box.setIcon(QMessageBox.Question)
|
||||
msg_box.setWindowTitle('Подтверждение удаления')
|
||||
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)
|
||||
msg_box.setDefaultButton(no_button)
|
||||
|
||||
msg_box.exec_()
|
||||
|
||||
# Если пользователь нажал не "Да", выходим
|
||||
if msg_box.clickedButton() != yes_button:
|
||||
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:
|
||||
if os.path.isdir(prefix_path):
|
||||
shutil.rmtree(prefix_path)
|
||||
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)
|
||||
QMessageBox.information(self, "Успех", f"Префикс '{prefix_name}' был успешно удален.")
|
||||
except Exception as e:
|
||||
QMessageBox.critical(self, "Ошибка удаления", f"Не удалось удалить префикс '{prefix_name}':\n{e}")
|
||||
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_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):
|
||||
"""Сбрасывает состояние управления префиксом, когда пользователь вводит новое имя."""
|
||||
@@ -2120,6 +2169,9 @@ class WineHelperGUI(QMainWindow):
|
||||
self.prefix_management_groupbox.setEnabled(False)
|
||||
self.prefix_info_display.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()
|
||||
|
||||
def update_prefix_info_display(self, prefix_name):
|
||||
@@ -2201,6 +2253,79 @@ class WineHelperGUI(QMainWindow):
|
||||
self.command_process.start(wine_executable, args)
|
||||
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):
|
||||
"""Создает вкладку 'Справка' с подвкладками"""
|
||||
help_tab = QWidget()
|
||||
@@ -2507,6 +2632,7 @@ class WineHelperGUI(QMainWindow):
|
||||
"""Обрабатывает завершение установки в префикс."""
|
||||
if exit_code == 0:
|
||||
self.command_log_output.append("\n=== Установка успешно завершена ===")
|
||||
self.create_launcher_button.setEnabled(True) # Активируем кнопку создания ярлыка
|
||||
else:
|
||||
self.command_log_output.append(f"\n=== Ошибка выполнения (код: {exit_code}) ===")
|
||||
|
||||
@@ -2966,6 +3092,9 @@ class WineHelperGUI(QMainWindow):
|
||||
except Exception as e:
|
||||
raise RuntimeError(f"Ошибка удаления префикса: {str(e)}")
|
||||
|
||||
# Обновляем состояние на вкладке "Создать префикс"
|
||||
self._remove_prefix_from_gui_state(prefix_name)
|
||||
|
||||
# 3. Удаляем ВСЕ найденные .desktop файлы, связанные с этим префиксом
|
||||
removed_files = []
|
||||
for file_path in all_desktop_files:
|
||||
@@ -3518,6 +3647,18 @@ class WineHelperGUI(QMainWindow):
|
||||
self.command_process = None
|
||||
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):
|
||||
"""Обрабатывает завершение для диалога команды восстановления."""
|
||||
if exit_code == 0:
|
||||
|
Reference in New Issue
Block a user