Compare commits

..

32 Commits

Author SHA1 Message Date
Mikhail Tergoev
0475c7e058 added dialux to testinstall 2026-01-20 20:20:15 +03:00
Mikhail Tergoev
b146b01a82 fixed create and repair base pfx 2026-01-20 20:18:34 +03:00
Mikhail Tergoev
41232f2315 added skip check i586 dependencies if wine-wow64 2026-01-20 16:53:29 +03:00
Mikhail Tergoev
73696de876 dropped check dependencies from gui 2026-01-20 14:22:23 +03:00
Mikhail Tergoev
3cbdef4f00 disabled check dependencies if without terminal 2026-01-19 19:37:51 +03:00
Mikhail Tergoev
4b0fea887b added skip check dependencies if wine-wow64 in use 2026-01-19 18:47:49 +03:00
Mikhail Tergoev
4d77861863 ksamu: fixed pid variable 2026-01-16 14:15:20 +03:00
Mikhail Tergoev
2854f8751b ksamu: fixed open in background choose cert file 2026-01-16 13:31:33 +03:00
Mikhail Tergoev
53a09b13d7 dropped wine-10.18.1-alt2-wow64 2026-01-16 13:14:12 +03:00
Mikhail Tergoev
0df709380c updated dialux pfx to v2 2026-01-16 11:59:26 +03:00
Mikhail Tergoev
e49a267d4c added termination of background process if present 2026-01-16 00:31:41 +03:00
Mikhail Tergoev
9724b75fc2 WINEDEBUG=-all by default 2026-01-16 00:00:28 +03:00
Mikhail Tergoev
436e250932 added FREETYPE_PROPERTIES 2026-01-15 23:55:16 +03:00
Mikhail Tergoev
6160eef77b added dialux_pfx_x86_v01 2026-01-15 21:18:36 +03:00
Mikhail Tergoev
26a92bea4d updated variables for last.conf and .whdb 2026-01-15 19:12:26 +03:00
Mikhail Tergoev
de57b947bf ksamu: updated wine and added fix WINE_TOP_WINDOW 2026-01-15 19:02:45 +03:00
Mikhail Tergoev
e43678193a added wine-10.18.1-alt2-wow64 with WINE_TOP_WINDOW 2026-01-15 18:56:17 +03:00
Mikhail Tergoev
032c03fbb1 ved-control: updated url and file name 2026-01-15 18:53:10 +03:00
Mikhail Tergoev
8d82125e74 updated test script ksamu 2025-12-29 21:03:01 +03:00
Mikhail Tergoev
f067412a29 updated ksamu_pfx_x64 v02 2025-12-29 21:00:53 +03:00
Mikhail Tergoev
d9ffca88d1 fixed disable virtual desktop 2025-12-29 20:41:51 +03:00
Mikhail Tergoev
7d925bdd15 added WH_VIRTUAL_DESKTOP 2025-12-26 16:27:33 +03:00
Mikhail Tergoev
bcf53c361c updated ksamu (test without cades) 2025-12-23 14:34:53 +03:00
Mikhail Tergoev
5b38f2c10d added variables for enable/disable decorated 2025-12-23 14:31:44 +03:00
Mikhail Tergoev
aec21eda1e added wine-10.18.1-alt1-wow64 2025-12-23 12:18:07 +03:00
Mikhail Tergoev
f8ce14d725 added new default variables 2025-12-22 14:35:49 +03:00
Mikhail Tergoev
ce1fb05fc7 install win cades if WH_USE_CPCSP_CADES=1 2025-12-22 14:24:18 +03:00
Mikhail Tergoev
659b0b1f5b added more 32-bit dependencies 2025-12-19 12:42:01 +03:00
Mikhail Tergoev
3732f71b7b added version WH to log 2025-12-18 20:36:01 +03:00
Mikhail Tergoev
d4f2d367b5 Merge branch 'minergenon-devel' 2025-12-18 12:31:35 +03:00
Mikhail Tergoev
a75e6c4f83 added sorting for variables in log file 2025-12-18 12:31:14 +03:00
Sergey Palcheh
fd2759f52b horizontal scrollbar disabled:
- the Installed tab in the Wine version selection dialog
- download bookmarks (WINE AMD64, WINE WOW64, WINE I586)
- dialog for selecting the component version (DXVK/VKD3D)
- tabs of the main window: Automatic installation, Manual installation, Installed
2025-12-18 11:28:38 +06:00
8 changed files with 294 additions and 529 deletions

View File

@@ -16,11 +16,11 @@ prepair_wine
# фикс постоянного запроса обновления Windows
get_and_set_reg_file --add 'Software\CTM\CTMSETUP' 'SkipKBCheck' 'REG_DWORD' "1" "userdef"
AUTOINSTALL_EXE="${WH_TMP_DIR}/setup_cl.exe"
AUTOINSTALL_UNPACK="${WH_TMP_DIR}/setup_cl"
AUTOINSTALL_SETUP="${WH_TMP_DIR}/setup_cl/setup.exe"
AUTOINSTALL_EXE="${WH_TMP_DIR}/setup_ct.exe"
AUTOINSTALL_UNPACK="${WH_TMP_DIR}/setup_ct"
AUTOINSTALL_SETUP="${WH_TMP_DIR}/setup_ct/setup.exe"
if try_download "https://ftp.ctm.ru/CONTROL/SFX/setup_cl.exe" "${AUTOINSTALL_EXE}" ; then
if try_download "https://ftp.ctm.ru/CONTROL/SFX/setup_ct.exe" "${AUTOINSTALL_EXE}" ; then
unpack "${AUTOINSTALL_EXE}" "${AUTOINSTALL_UNPACK}"
try_remove_file "$AUTOINSTALL_EXE"

View File

@@ -7,23 +7,29 @@ if [[ $(id -u) -ne 0 ]] ; then
fi
##### MESSAGES FUNCTIONS #####
print_error () { printf "\E[31m%s ВНИМАНИЕ: $@ %s\e[0m\n" ;}
fatal () { print_error "$@" ; exit 1 ;}
if [[ -t 0 ]] ; then
print_error () { printf "\E[31m%s Ошибка: $* %s\e[0m\n" ;}
else
print_error () { echo -e "Ошибка: $*" ;}
fi
##### UPDATE SYSTEM #####
apt-get update || fatal "Не удалось обновить список доступных пакетов,"
fatal () {
print_error "$@ Аварийное завершение работы WineHelper!"
exit 1
}
##### CHECK AREPO (x86_64-i586) #####
apt-repo | grep -q "x86_64-i586" || fatal "Репозиторий x86_64-i586 не подключен. \
32-битные зависимости не будут установлены, а значит не будут работать и 32-битные \
windows приложения. Подробнее по ссылке: https://www.altlinux.org/Biarch"
##### UPDATE SYSTEM #####
apt-get update || fatal "Не удалось обновить список доступных пакетов,"
##### INSTALL DEPENDENCIES #####
# fonts-ttf-ms
apt-get install {i586-,}{glibc-core,libstdc++6,glibc-pthread,glibc-nss,\
libnss-mdns,libunixODBC2,ocl-icd,libfreetype,libfontconfig1,\
libgnutls30,libGL,libEGL,xorg-dri-swrast,xorg-dri-intel,xorg-dri-radeon,\
libvulkan1,libcups} || fatal "Не удалось установить зависимости."
apt-get install {i586-,}wine
apt-get install i586-{wine,glibc-core,libstdc++6,glibc-pthread,glibc-nss,\
libnm,libnss,libnss-mdns,libnsl1,libunwind,libunixODBC2,ocl-icd,libfreetype,\
libcups,libfontconfig1,libgnutls30,libGL,libEGL,libvulkan1,xorg-dri-swrast,\
xorg-dri-intel,xorg-dri-radeon} || fatal "Не удалось установить зависимости."

BIN
image/dialux.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@@ -1,6 +1,7 @@
##### WINE WOW64 #####
e9a8b79dfe12cad1304dca573d73aefe109e3d69b6fff739c8dbb8b2d3c271c6 wine-10.12.1-alt1-wow64.tar.xz
a862761c432f8619caf8100589678a1cbb523787259120ccd4388089d81e3b17 wine-10.18.1-tflex-alt2-wow64.tar.xz
349c707148a23e667970309248bbbf97b4e2a0db59c548e73d9fe9c3f585872c wine-10.18.1-alt1-wow64.tar.xz
##### WINE AMD64 #####
009c95bfe2df3f9264c9c5092f3e30ea7a168dd7869046058a718a70739602d4 wine_wh_tflex_10-9_amd64.tar.xz
@@ -190,10 +191,19 @@ ef7e8f1ba785d48e4ea287feed5b79bd630d423e59efadb43da9653adefef218 ais-lpu-client
# winetricks vcrun2005 vcrun2008 dotnet20sp2 dotnet40 mfc42 7zip
f18864014fdb2fead0b45b5e70e95073072b89168df8cd6debba89081ac51a2a ksamu_pfx_x64_v01.tar.xz
# create with wine_x_tkg_10-0_i586 (universal user: xuser)
# create with wine-10.12.1-alt1-wow64 (universal user: xuser)
# winetricks msxml6 msxml4 msxml3 riched30 msls31 riched20 msftedit richtx32 fontsmooth=gray
# + manuall installed riched32
7377159d7f21537e517ecc7bdd4c09d6ccab39f1368688506e78e11cfde7dc2a ksamu_pfx_x64_v02.tar.xz
# create with wine-10.18.1-alt1-wow64 (universal user: xuser)
# winetricks corefonts tahoma msxml6 msxml4 msxml3 riched30 msls31 riched20 msftedit richtx32 fontsmooth=gray
# + manuall installed riched32
06bb83c64ef5e749741fb009a12e07ad62865474c5c7db049894c7871a1471cc dialux_pfx_x86_v04.tar.xz
# create with wine_x_tkg_10-0_i586 (universal user: xuser)
# winetricks mdac27 wsh57 jet40 msxml6 mdac28 gdiplus msxml4 msxml3 vcrun2010 msls31 ie8 dotnet20sp1
##### ADDONS #####
# addons with ODBC, SSH, *.reg
0f4ef434df07bc338ae308af44330590eaa1d9c94b64850514e55b960642d0eb scadoffice_addons_v02.tar.xz

16
testinstall/dialux Normal file
View File

@@ -0,0 +1,16 @@
#!/usr/bin/env bash
# info_ru: Программное обеспечение для 3D-графики, предназначенное для проектирования освещения. (Версия 4.4.0.2)
########################################################################
export WH_WINE_USE="wine_x_tkg_10-0_i586"
export WINEPREFIX="dialux"
export PROG_NAME="DIALux"
export PROG_ICON="dialux"
export BASE_PFX="dialux_pfx_x86_v04"
export WH_WINDOWS_VER="xp"
export WINEARCH="win32"
export INSTALL_DLL="mdac28 jet40 vcrun2010 gdiplus dotnet20sp1 msxml3 msxml4 msxml6 ie8"
prepair_wine
WIN_FILE_EXEC="$DRIVE_C/Program Files/DIALux/DIALux.exe"
create_desktop "$PROG_NAME" "$WIN_FILE_EXEC" "$PROG_ICON"

View File

@@ -2,17 +2,41 @@
# info_ru: “КСАМУ” - Комплексная система автоматизации медицинского учреждения.
########################################################################
export PROG_URL="https://docs.medicine-it.ru/"
export WH_WINE_USE="wine-10.12.1-alt1-wow64"
export WH_WINE_USE="wine-10.18.1-alt1-wow64"
export WINEPREFIX="ksamu"
export PROG_NAME="КСАМУ"
export PROG_ICON="ksamu"
export BASE_PFX="ksamu_pfx_x64_v01"
export BASE_PFX="ksamu_pfx_x64_v02"
export WINEARCH="win64"
export INSTALL_DLL="richtx32 riched20 riched30 msls31 msftedit msxml6 msxml4 msxml3 fontsmooth=gray"
export INSTALL_DLL="corefonts tahoma richtx32 riched20 riched30 msls31 msftedit msxml6 msxml4 msxml3 fontsmooth=gray"
# riched32
export WH_USE_EXTRA_FONTS="1"
export WH_WINDOWS_VER="7"
export WH_USE_CPCSP_PROXY="1"
export WH_MAIN_DECORATED="1"
export WH_VIRTUAL_DESKTOP="0"
prepair_wine
create_desktop "$PROG_NAME" "$DRIVE_C/KSAMU/KSAMU.exe" "$PROG_ICON"
echo '
# хак для исправления открытия выбора файла сертификата в фоне
if ! command -v wmctrl &>/dev/null ; then
wmctrl_not_found="Для продолжения работы установите wmctrl:\n\nsu -\napt-get update\napt-get install wmctrl\nexit"
zenity --error --title="Ошибка" --text="$wmctrl_not_found" --ok-label="Выход"
fatal "$wmctrl_not_found"
fi
background_task() {
while true; do
sleep 1
OPEN_WIN_ID=$(wmctrl -xl | grep -i "ksamu" | grep -i "открыть" | cut -d" " -f1)
if [[ -n $OPEN_WIN_ID ]] ; then
wmctrl -i -r $OPEN_WIN_ID -b add,above
fi
done
}
background_task &
WH_BG_PID=$!
export WH_BG_PID
' >> "$DRIVE_C/KSAMU/KSAMU.exe.whdb"

View File

@@ -40,7 +40,6 @@ else
WH_WINETRICKS="/usr/bin/winetricks"
WH_DEVEL="1"
# минимальная проверка синтаксиса скриптов
for self_check_script in "$RUN_SCRIPT" \
"$DATA_PATH/dependencies.sh" "$DATA_PATH/autoinstall"/* \
@@ -101,7 +100,7 @@ if [[ "$1" == "--debug" ]] ; then
export DXVK_NVAPI_LOG_LEVEL="error"
shift
else
check_variables WINEDEBUG "-all,err+all"
check_variables WINEDEBUG "-all"
check_variables DXVK_LOG_LEVEL "none"
check_variables VKD3D_SHADER_DEBUG "none"
check_variables VKD3D_DEBUG "none"
@@ -144,9 +143,13 @@ check_variables WH_WINE_USE "wine_x_tkg_10-0_amd64" # or system
check_variables WH_USE_CPCSP_PROXY "0"
check_variables CPCSP_PROXY_X86_64_VER "0.6.1-alt1"
check_variables CPCSP_PROXY_WOW64_VER "0.7.7-alt1-wow64"
check_variables WH_USE_CPCSP_CADES "0"
check_variables WH_USE_EXTRA_FONTS "0"
check_variables EXTRA_FONTS_VER "01"
check_variables WH_FONT_MSS_REPLACE "0"
check_variables WH_FONT_SMOOTHING "0"
# check_variables FREETYPE_PROPERTIES "truetype:interpreter-version=35"
check_variables STAGING_SHARED_MEMORY "1"
check_variables WINE_LARGE_ADDRESS_AWARE "1"
@@ -162,6 +165,9 @@ check_variables WH_USE_SHADER_CACHE "1"
check_variables WH_USE_MESA_GL_OVERRIDE "0"
check_variables WH_USE_WINE_DXGI "0"
check_variables WH_DLL_INSTALL ""
check_variables WH_MAIN_DECORATED "default"
check_variables WH_MC_DECORATED "default"
check_variables WH_VIRTUAL_DESKTOP "default"
check_variables WINE_WIN_START "start /wait /high /unix"
@@ -202,17 +208,29 @@ su_run () {
}
##### CHECK DEPENDENCIES #####
# fonts-ttf-ms
if ! rpm -q {i586-,}{wine,glibc-core,libstdc++6,glibc-pthread,glibc-nss,\
libnss-mdns,libunixODBC2,ocl-icd,libfreetype,libfontconfig1,libgnutls30,libGL,\
libEGL,xorg-dri-swrast,xorg-dri-intel,xorg-dri-radeon,libvulkan1,libcups} 1>/dev/null
then
if su_run "$DATA_PATH/dependencies.sh"
then print_info "Зависимости успешно установлены. Продолжаем работу $SCRIPT_NAME"
else fatal "Не удалось установить зависимости. Работа $SCRIPT_NAME прервана."
check_deps_i586 () {
if [[ $WH_USE_GUI != "1" ]] && [[ ! -t 0 ]] ; then
print_warning "Скрипт запущен из desktop файла."
return 0
fi
fi
if [[ $WH_SKIP_DEPS == "1" ]] ; then
unset WH_SKIP_DEPS
return 0
fi
if ! rpm -q i586-{wine,glibc-core,libstdc++6,glibc-pthread,glibc-nss,\
libnm,libnss,libnss-mdns,libnsl1,libunwind,libunixODBC2,ocl-icd,libfreetype,\
libcups,libfontconfig1,libgnutls30,libGL,libEGL,libvulkan1,xorg-dri-swrast,\
xorg-dri-intel,xorg-dri-radeon} 1>/dev/null
then
print_warning "Необходимо установить 32-битные зависимости!"
if su_run "$DATA_PATH/dependencies.sh"
then print_info "Зависимости успешно установлены. Продолжаем работу $SCRIPT_NAME"
else fatal "Не удалось установить зависимости. Работа $SCRIPT_NAME прервана."
fi
fi
}
##### HELPER FUNCTIONS #####
add_to_var () {
@@ -714,8 +732,10 @@ EOF
} > "$exe_file".whdb
grep -e "info_" -e "#####" -e "PROG_URL=" -e "WINEPREFIX=" -e "INSTALL_DLL=" \
-e "PROG_NAME=" -e "PROG_ICON=" -e "var_" "$INSTALL_SCRIPT" \
| awk '{$1=$1;print}' >> "$exe_file".whdb
-e "PROG_NAME=" -e "PROG_ICON=" -e "var_" -e "WH_MAIN_DECORATED" \
-e "WH_VIRTUAL_DESKTOP" -e "WINE_TOP_WINDOW" -e "WH_FONT_SMOOTHING "\
-e "WH_FONT_MSS_REPLACE" \
"$INSTALL_SCRIPT" | awk '{$1=$1;print}' >> "$exe_file".whdb
print_info "Создан файл настроек для $exe_file"
fi
@@ -773,13 +793,6 @@ check_installed_programs () {
[[ -n $2 ]] && fatal "Не найден файл запуска для $2"
}
run_installed_programs () {
if check_installed_programs check_only "$1" ; then
/usr/bin/env bash -c "\"$RUN_SCRIPT\" \"$EXE_PATH\"" &
exit 0
fi
}
copy_wined3d () {
for wined3dfiles in $1 ; do
try_copy_wine_dll_to_pfx_64 "$wined3dfiles.dll"
@@ -871,19 +884,26 @@ init_wine_ver () {
try_download cloud "$download_url" "$wine_package" "check256sum"
unpack "$wine_package" "$WH_DIST_DIR/"
try_remove_file "$wine_package"
# Управление структурой подкаталога Proton "files", перемещая содержимое вверх
if [[ -d "$WINEDIR/files" ]]; then
print_info "Обнаружена структура каталогов Proton, исправляем пути..."
mv "$WINEDIR"/files/* "$WINEDIR/"
rmdir "$WINEDIR/files"
fi
fi
[[ ! -f "$WINEDIR/version" ]] && echo "$WH_WINE_USE" > "$WINEDIR/version"
if [[ $WH_WINE_USE =~ wow64 ]]
then export WH_WINE_WOW64="1"
else export WH_WINE_WOW64="0"
# Управление структурой подкаталога Proton "files", перемещая содержимое вверх
if [[ ${WINEDIR,,} =~ proton ]] \
&& [[ -d "$WINEDIR/files" ]]
then
print_info "Обнаружена структура каталогов Proton, исправляем пути..."
mv "$WINEDIR"/files/* "$WINEDIR/"
try_remove_dir "$WINEDIR/files"
fi
if [[ ! -f "$WINEDIR/version" ]] ; then
echo "$WH_WINE_USE" > "$WINEDIR/version"
fi
if [[ $WH_WINE_USE =~ wow64 ]] ; then
export WH_WINE_WOW64="1"
else
export WH_WINE_WOW64="0"
check_deps_i586
fi
export WINE="$WINEDIR/bin/wine"
@@ -1139,29 +1159,66 @@ 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
if [[ ! -d "$WINEPREFIX" ]] ; then
create_new_dir "$WINEPREFIX"
if [[ "$CLEAR_PREFIX" == "1" ]]
then print_warning "Используется переменная \"CLEAR_PREFIX=1\", которая принудительно создает чистый префикс с установкой компонентов с помощью winetricks."
elif [[ "$BASE_PFX" != "none" ]]
then get_base_pfx "$BASE_PFX"
fi
fi
if [[ ! -d "$WINEPREFIX/drive_c/windows" ]] ; then
print_info "Создание префикса $WINEPREFIX."
"$WINELOADER" wineboot -i
wait_wineserver
elif [[ ! -f "$WINEPREFIX/.update-timestamp" ]] \
|| [[ ! -d "$WINEPREFIX/drive_c/users" ]]
then
print_info "Обновление префикса $WINEPREFIX."
if [[ -d "$WINEPREFIX/drive_c/windows" ]]
then "$WINELOADER" wineboot -u
else "$WINELOADER" wineboot -i
fi
touch "$WINEPREFIX/.firstboot"
"$WINELOADER" wineboot -u
wait_wineserver
fi
if [[ -d "$XUSER_PATH" ]] && [[ ! -d "$DRIVE_C/users/$USER" ]]
then try_force_link_dir "$XUSER_PATH" "$DRIVE_C/users/$USER"
elif [[ ! -d "$XUSER_PATH" ]] && [[ -d "$DRIVE_C/users/$USER" ]]
then try_force_link_dir "$DRIVE_C/users/$USER" "$XUSER_PATH"
fi
if [[ -L "$XUSER_PATH/Desktop" ]]
then rm -f "$XUSER_PATH/Desktop"
fi
create_new_dir "$XUSER_PATH/Desktop"
create_new_dir "$XUSER_PATH/AppData/Local/Temp"
create_new_dir "$DRIVE_C/ProgramData/Package Cache"
create_new_dir "$DRIVE_C/windows/temp"
create_new_dir "$DRIVE_C/windows/Installer"
if [[ ! -d "$WINEPREFIX/dosdevices" ]] ; then
create_new_dir "$WINEPREFIX/dosdevices"
local run_wbr="1"
fi
if [[ ! -d "${WINEPREFIX}/dosdevices/c:" ]] ; then
try_force_link_dir "${WINEPREFIX}/drive_c/" "${WINEPREFIX}/dosdevices/c:"
fi
if [[ ! -d "${WINEPREFIX}/dosdevices/z:" ]] ; then
try_force_link_dir "/" "${WINEPREFIX}/dosdevices/z:"
fi
if [[ ! -d "${WINEPREFIX}/dosdevices/h:" ]] ; then
try_force_link_dir "$HOME" "${WINEPREFIX}/dosdevices/h:"
fi
if [[ $run_wbr == "1" ]] ; then
"$WINELOADER" wineboot -r
wait_wineserver
unset run_wbr
fi
if [[ -f "$WINEPREFIX/system.reg" ]] \
&& [[ -z $(grep "Windows $WH_WINDOWS_VER" "$WINEPREFIX/system.reg") ]]
&& ! grep -iq "Microsoft Windows $WH_WINDOWS_VER" "$WINEPREFIX/system.reg"
then
if [[ $(echo "$WH_WINDOWS_VER" | sed 's/.*/\L&/') == "xp" ]] \
&& [[ "$WINEARCH" != "win32" ]]
@@ -1172,33 +1229,11 @@ init_wineprefix () {
print_info "Windows версия изменена на win${WH_WINDOWS_VER}"
fi
if [[ -d "$XUSER_PATH" ]] && [[ ! -d "$DRIVE_C/users/$USER" ]]
then try_force_link_dir "$XUSER_PATH" "$DRIVE_C/users/$USER"
elif [[ ! -d "$XUSER_PATH" ]] && [[ -d "$DRIVE_C/users/$USER" ]]
then try_force_link_dir "$DRIVE_C/users/$USER" "$XUSER_PATH"
fi
if [[ ! -f "$WINEPREFIX/.update-timestamp" ]] ; then
print_info "Обновление префикса $WINEPREFIX."
"$WINELOADER" wineboot -u
wait_wineserver
fi
if [[ -L "$XUSER_PATH/Desktop" ]]
then rm -f "$XUSER_PATH/Desktop"
fi
create_new_dir "$XUSER_PATH/Desktop"
if [[ ! -L "$WINEPREFIX/dosdevices/h:" ]]
then try_force_link_dir "$HOME" "$WINEPREFIX/dosdevices/h:"
fi
if [[ $WH_USE_MESA_GL_OVERRIDE == "1" ]] \
&& ! lspci | grep -i nvidia > /dev/null
then
export MESA_GL_VERSION_OVERRIDE="3.3"
export MESA_GLSL_VERSION_OVERRIDE="330"
fi
if check_wayland_session ; then
@@ -1223,20 +1258,43 @@ init_wineprefix () {
get_and_set_reg_file --delete 'Software\Wine\X11 Driver' 'UseXVidMode'
fi
if [[ $WH_MC_NO_DECORATED = "1" ]] ; then
# отключаем декоратор для maincontroller.exe
# заменяет патч: https://git.altlinux.org/gears/w/wine.git?p=wine.git;a=blob;f=patches/0009-wine.inf.in-disable-decorated-window-for-maincontrol.patch;h=887a5e90e130cddeefdead831ef7a78a32588f11;hb=d097f4e4b64873c82ec31542c6f49f70829ab2b4
get_and_set_reg_file --add 'Software\Wine\AppDefaults\maincontroller.exe\X11 Driver' 'Decorated' 'REG_SZ' "N" "user"
# включаем виртуальный рабочий стол при необходимости
if [[ $WH_VIRTUAL_DESKTOP == "1" ]] ; then
get_and_set_reg_file --add 'Software\Wine\Explorer' 'Desktop' 'REG_SZ' "Default" "user"
WH_SCREEN_RESOLUTION="$(xrandr | sed -rn 's/^.*primary.* ([0-9]+x[0-9]+).*$/\1/p')"
[[ $WH_SCREEN_RESOLUTION != *x* ]] && WH_SCREEN_RESOLUTION="1920x1080"
get_and_set_reg_file --add 'Software\Wine\Explorer\Desktops' 'Default' 'REG_SZ' "$WH_SCREEN_RESOLUTION" "user"
elif [[ $WH_VIRTUAL_DESKTOP == *x* ]] ; then
get_and_set_reg_file --add 'Software\Wine\Explorer' 'Desktop' 'REG_SZ' "Default" "user"
get_and_set_reg_file --add 'Software\Wine\Explorer\Desktops' 'Default' 'REG_SZ' "$WH_VIRTUAL_DESKTOP" "user"
elif [[ $WH_VIRTUAL_DESKTOP == "0" ]] ; then
get_and_set_reg_file --delete 'Software\Wine\Explorer\Desktops' 'Default'
get_and_set_reg_file --delete 'Software\Wine\Explorer' 'Desktop'
fi
# управляем декоратором для ПО по умолчанию
if [[ $WH_MAIN_DECORATED = "0" ]] ; then
get_and_set_reg_file --add 'Software\Wine\X11 Driver' 'Decorated' 'REG_SZ' "N" "user"
elif [[ $WH_MAIN_DECORATED = "1" ]] ; then
get_and_set_reg_file --add 'Software\Wine\X11 Driver' 'Decorated' 'REG_SZ' "Y" "user"
fi
# управляем декоратором для maincontroller.exe
if [[ $WH_MC_DECORATED = "0" ]] ; then
# заменяет патч: https://git.altlinux.org/gears/w/wine.git?p=wine.git;a=blob;f=patches/0009-wine.inf.in-disable-decorated-window-for-maincontrol.patch;h=887a5e90e130cddeefdead831ef7a78a32588f11;hb=d097f4e4b64873c82ec31542c6f49f70829ab2b4
get_and_set_reg_file --add 'Software\Wine\AppDefaults\maincontroller.exe\X11 Driver' 'Decorated' 'REG_SZ' "N" "user"
elif [[ $WH_MC_DECORATED = "1" ]] ; then
get_and_set_reg_file --add 'Software\Wine\AppDefaults\maincontroller.exe\X11 Driver' 'Decorated' 'REG_SZ' "Y" "user"
fi
# заменям шрифт Microsoft Sans Serif на Tahoma
if [[ $WH_FONT_MSS_REPLACE = "1" ]] ; then
# заменям шрифт Microsoft Sans Serif на Tahoma
# заменяет патч: https://git.altlinux.org/gears/w/wine.git?p=wine.git;a=blob;f=patches/0003-wine.inf-Add-the-font-replacement-for-Microsoft-Sans.patch;h=26b8ae2192d94a2b8ddd8565b90b62a2c2b0ed52;hb=d097f4e4b64873c82ec31542c6f49f70829ab2b4
get_and_set_reg_file --add 'Software\Wine\Fonts\Replacements' 'Microsoft Sans Serif' 'REG_SZ' "Tahoma" "user"
fi
# добавляем сглаживание шрифтов
if [[ $WH_FONT_SMOOTHING = "1" ]] ; then
# добавляем сглаживание шрифтов
# заменяет патч: https://git.altlinux.org/gears/w/wine.git?p=wine.git;a=blob;f=patches/0002-Add-font-smoothing.patch;h=d7c252899499e9ee0e1a93f7c02548cc79025358;hb=d097f4e4b64873c82ec31542c6f49f70829ab2b4
get_and_set_reg_file --add 'Control Panel\Desktop' 'FontSmoothing' 'REG_SZ' "2" "user"
get_and_set_reg_file --add 'Control Panel\Desktop' 'FontSmoothingGamma' 'REG_DWORD' "0x00000578" "user"
@@ -1291,24 +1349,26 @@ init_wineprefix () {
# настраиваем префикс для работы с cpcsp_proxy
if [[ $WH_USE_CPCSP_PROXY == "1" ]] ; then
local cades_ver="release_2_0_14892"
local url_cades_dll="https://cryptopro.ru/sites/default/files/products/cades/$cades_ver"
if [[ $WH_USE_CPCSP_CADES == "1" ]] ; then
local cades_ver="release_2_0_14892"
local url_cades_dll="https://cryptopro.ru/sites/default/files/products/cades/$cades_ver"
if [[ ! -d "$DRIVE_C/Program Files (x86)/Common Files/Crypto Pro/Shared/" ]]
then
local msi_cades32="cades-win32.msi"
try_download cloud "$url_cades_dll/$msi_cades32" "$WH_TMP_DIR/$msi_cades32"
print_info "Установка КриптоПро ЭЦП Runtime ($msi_cades32)"
WINEDLLOVERRIDES="msxml3=b" wine_run "$WH_TMP_DIR/$msi_cades32" /q
fi
if [[ ! -d "$DRIVE_C/Program Files (x86)/Common Files/Crypto Pro/Shared/" ]]
then
local msi_cades32="cades-win32.msi"
try_download cloud "$url_cades_dll/$msi_cades32" "$WH_TMP_DIR/$msi_cades32"
print_info "Установка КриптоПро ЭЦП Runtime ($msi_cades32)"
WINEDLLOVERRIDES="msxml3=b" wine_run "$WH_TMP_DIR/$msi_cades32" /q
fi
if [[ "$WINEARCH" == "win64" ]] \
&& [[ ! -d "$DRIVE_C/Program Files/Common Files/Crypto Pro/Shared" ]]
then
local msi_cades64="cades-x64.msi"
try_download cloud "$url_cades_dll/$msi_cades64" "$WH_TMP_DIR/$msi_cades64"
print_info "Установка КриптоПро ЭЦП Runtime ($msi_cades64)"
WINEDLLOVERRIDES="msxml3=b" wine_run "$WH_TMP_DIR/$msi_cades64" /q
if [[ "$WINEARCH" == "win64" ]] \
&& [[ ! -d "$DRIVE_C/Program Files/Common Files/Crypto Pro/Shared" ]]
then
local msi_cades64="cades-x64.msi"
try_download cloud "$url_cades_dll/$msi_cades64" "$WH_TMP_DIR/$msi_cades64"
print_info "Установка КриптоПро ЭЦП Runtime ($msi_cades64)"
WINEDLLOVERRIDES="msxml3=b" wine_run "$WH_TMP_DIR/$msi_cades64" /q
fi
fi
if ! grep -q "cpcsp_proxy.dll" "$WINEPREFIX/system.reg" ; then
@@ -1380,7 +1440,7 @@ init_wineprefix () {
for var in WH_WINE_USE BASE_PFX WINEARCH WH_WINDOWS_VER WINEESYNC WINEFSYNC \
STAGING_SHARED_MEMORY WINE_LARGE_ADDRESS_AWARE WH_USE_SHADER_CACHE WH_USE_WINE_DXGI \
WINE_CPU_TOPOLOGY DXVK_VER VKD3D_VER WH_XDG_OPEN WH_USE_MESA_GL_OVERRIDE \
WH_USE_CPCSP_PROXY
WH_USE_CPCSP_PROXY WH_USE_EXTRA_FONTS
do
echo "export $var=\"${!var}\"" >> "$WINEPREFIX/last.conf"
done
@@ -1545,13 +1605,17 @@ wine_run () {
create_new_dir "$log_dir"
date > "$log_file"
echo -e "\n##### Версия установленного WineHelper #####" | tee -a "$log_file"
rpm -q winehelper | tee -a "$log_file"
print_warning "Включен режим логирования работы WINE."
print_warning "Лог будет сохранен по пути: $log_file"
echo "##### Основные переменные #####" | tee -a "$log_file"
env | grep -e "WH_" -e "WINE" -e "DXVK" -e "VKD3D" | tee -a "$log_file"
echo "##### Лог WINE #####" | tee -a "$log_file"
echo -e "\n##### Основные переменные #####" | tee -a "$log_file"
env | grep -e "WH_" -e "WINE" -e "DXVK" -e "VKD3D" -e "LD_" \
| grep -v "ICON" | sort | tee -a "$log_file"
echo -e "\n##### Лог WINE #####" | tee -a "$log_file"
$MANGOHUD_RUN "$WINELOADER" $wh_add_args "$win_file_exec" "$@" $LAUNCH_PARAMETERS 2>&1 | tee -a "$log_file"
else
$MANGOHUD_RUN "$WINELOADER" $wh_add_args "$win_file_exec" "$@" $LAUNCH_PARAMETERS
@@ -2076,8 +2140,6 @@ create_base_pfx () {
fi
# удаляем всё ненужное для переноса префикса
try_remove_file "$prefix_dir/.update-timestamp"
try_remove_file "$prefix_dir/.firstboot"
try_remove_file "$prefix_dir/last.conf"
try_remove_dir "$prefix_dir/dosdevices/"
try_remove_dir "$users_dir/$USER"
@@ -2094,7 +2156,7 @@ create_base_pfx () {
cd "$prefix_dir"
# запускаем сжатие префикса
if tar --no-xattrs -c -I 'xz --memlimit=8000MiB -9 -T0' -f "$archive_path" ./* ; then
if tar --no-xattrs -c -I 'xz --memlimit=8000MiB -9 -T0' -f "$archive_path" . ; then
print_ok "Архив создан по пути: $archive_path"
xdg-open "$(dirname "$archive_path")" &
cd -
@@ -2126,7 +2188,6 @@ backup_prefix() {
print_info "Подготовка префикса к упаковке..."
if cp -a "$WINEPREFIX" "$temp_prefix_dir" ; then
try_remove_dir "$temp_prefix_dir/dosdevices"
try_remove_file "$temp_prefix_dir/.update-timestamp"
if [[ -d "$temp_users_dir/$USER" ]] \
&& [[ ! -L "$temp_users_dir/$USER" ]]
then
@@ -2575,7 +2636,6 @@ case "$arg1" in
install-vkd3d) run_install_vkd3d "$@" ;;
change-wine) run_change_wine_version "$@" ;;
installed) check_installed_programs "$1" ;;
run|-r) run_installed_programs "$1" ;;
backup-prefix) backup_prefix "$@" ;;
restore-prefix) restore_prefix "$@" ;;
remove-all) remove_winehelper "$@" ;;
@@ -2584,6 +2644,14 @@ case "$arg1" in
create-base-pfx) create_base_pfx "$@" ;;
init-prefix) prepair_wine ; wait_wineserver ;;
clear-winetricks-cache) clear_winetricks_cache "$@" ;;
run|-r)
if check_installed_programs check_only "$1" ; then
WIN_FILE_EXEC="$(readlink -f "$EXE_PATH")"
shift
prepair_wine
wine_run "$WIN_FILE_EXEC" "$@"
fi
;;
*)
if [[ -f "$arg1" ]] ; then
WIN_FILE_EXEC="$(readlink -f "$arg1")"
@@ -2604,3 +2672,8 @@ case "$arg1" in
fi
;;
esac
if [[ -n "$WH_BG_PID" ]] ; then
print_info "Завершение фонового процесса: $WH_BG_PID"
kill "$WH_BG_PID" 2>/dev/null
fi

View File

@@ -33,393 +33,6 @@ class Var:
GENERAL = os.environ.get("GENERAL")
WH_WINETRICKS = os.environ.get("WH_WINETRICKS")
class DependencyManager:
"""Класс для управления проверкой и установкой системных зависимостей."""
def __init__(self):
"""Инициализирует менеджер, определяя необходимые пути."""
self.dependencies_script_path = self._get_dependencies_path()
self.config_dir = os.path.join(os.path.expanduser("~"), ".config", "winehelper")
self.hash_flag_file = os.path.join(self.config_dir, "dependencies_hash.txt")
os.makedirs(self.config_dir, exist_ok=True)
self.app_icon = QIcon(Var.WH_ICON_PATH) if Var.WH_ICON_PATH and os.path.exists(Var.WH_ICON_PATH) else QIcon()
def _get_dependencies_path(self):
"""Определяет и возвращает путь к скрипту dependencies.sh."""
if not Var.DATA_PATH:
return None
return os.path.join(Var.DATA_PATH, 'dependencies.sh')
def _calculate_file_hash(self):
"""Вычисляет хэш SHA256 файла зависимостей."""
if not self.dependencies_script_path or not os.path.exists(self.dependencies_script_path):
return None
hasher = hashlib.sha256()
try:
with open(self.dependencies_script_path, 'rb') as f:
while chunk := f.read(4096):
hasher.update(chunk)
return hasher.hexdigest()
except IOError:
return None
def _parse_dependencies_from_script(self):
"""
Парсит скрипт dependencies.sh для извлечения списка базовых пакетов.
Возвращает список пакетов или None в случае ошибки.
"""
if not os.path.exists(self.dependencies_script_path):
return None
base_packages = []
try:
with open(self.dependencies_script_path, 'r', encoding='utf-8') as f:
content = f.read()
content = content.replace('\\\n', '')
pattern = r'apt-get install\s+\{i586-,\}(\{.*?\}|[\w.-]+)'
matches = re.findall(pattern, content)
for match in matches:
match = match.strip()
if match.startswith('{') and match.endswith('}'):
group_content = match[1:-1]
packages = [pkg.strip() for pkg in group_content.split(',')]
base_packages.extend(packages)
else:
base_packages.append(match)
return sorted(list(set(pkg for pkg in base_packages if pkg))) or None
except Exception:
return None
def _parse_repo_error_from_script(self):
"""
Парсит скрипт dependencies.sh для извлечения сообщения об ошибке репозитория.
Возвращает сообщение или None в случае ошибки.
"""
if not os.path.exists(self.dependencies_script_path):
return None
try:
with open(self.dependencies_script_path, 'r', encoding='utf-8') as f:
content = f.read()
content = content.replace('\\\n', ' ')
match = re.search(r'apt-repo.*\|\|.*fatal\s+"([^"]+)"', content)
if match:
error_message = match.group(1).strip()
return re.sub(r'\s+', ' ', error_message)
return None
except Exception:
return None
def _show_startup_messages(self):
"""
Проверяет, является ли это первым запуском или обновлением,
и показывает соответствующие сообщения.
"""
current_hash = self._calculate_file_hash()
stored_hash = None
hash_file_exists = os.path.exists(self.hash_flag_file)
if hash_file_exists:
try:
with open(self.hash_flag_file, 'r', encoding='utf-8') as f:
stored_hash = f.read().strip()
except IOError:
pass
if not hash_file_exists:
msg_box = QMessageBox(QMessageBox.Information, "Первый запуск WineHelper",
"Поскольку это первый запуск, программа проверит наличие необходимых системных зависимостей.")
msg_box.setWindowIcon(self.app_icon)
msg_box.exec_()
elif current_hash != stored_hash:
msg_box = QMessageBox(QMessageBox.Information, "Обновление зависимостей",
"Обнаружены изменения в системных требованиях.\n\n"
"Программа выполнит проверку, чтобы убедиться, что все компоненты на месте.")
msg_box.setWindowIcon(self.app_icon)
msg_box.exec_()
def _save_dependency_hash(self):
"""Сохраняет хэш зависимостей в конфигурационный файл."""
current_hash = self._calculate_file_hash()
if not current_hash:
return
try:
with open(self.hash_flag_file, 'w', encoding='utf-8') as f:
f.write(current_hash)
except IOError:
print("Предупреждение: не удалось записать файл с хэшем зависимостей.")
def _perform_check_and_install(self):
"""
Выполняет основную логику проверки и установки зависимостей.
Возвращает True в случае успеха, иначе False.
"""
# Проверка наличия ключевых утилит
if not shutil.which('apt-repo') or not shutil.which('rpm'):
return True
if not self.dependencies_script_path or not os.path.exists(self.dependencies_script_path):
msg_box = QMessageBox(QMessageBox.Critical, "Критическая ошибка",
f"Файл зависимостей не найден по пути:\n'{self.dependencies_script_path}'.\n\n"
"Программа не может продолжить работу."
)
msg_box.setWindowIcon(self.app_icon)
msg_box.exec_()
return False
# 1. Проверка наличия репозитория x86_64-i586
try:
result = subprocess.run(['apt-repo'], capture_output=True, text=True, check=False, encoding='utf-8')
if result.returncode != 0 or 'x86_64-i586' not in result.stdout:
error_message = self._parse_repo_error_from_script()
if not error_message:
msg_box = QMessageBox(QMessageBox.Critical, "Критическая ошибка",
f"Репозиторий x86_64-i586 не подключен, но не удалось извлечь текст ошибки из файла:\n'{self.dependencies_script_path}'.\n\n"
"Проверьте целостность скрипта. Работа программы будет прекращена."
)
msg_box.setWindowIcon(self.app_icon)
msg_box.exec_()
return False
msg_box = QMessageBox(QMessageBox.Critical, "Ошибка репозитория",
f"{error_message}\n\nРабота программы будет прекращена.")
msg_box.setWindowIcon(self.app_icon)
msg_box.exec_()
return False
except FileNotFoundError:
return True
# 2. Определение списка пакетов из dependencies.sh
base_packages = self._parse_dependencies_from_script()
# Если парсинг не удался или скрипт не найден, прерываем работу.
if not base_packages:
msg_box = QMessageBox(QMessageBox.Critical, "Критическая ошибка",
f"Не удалось найти или проанализировать файл зависимостей:\n'{self.dependencies_script_path}'.\n\n"
"Программа не может продолжить работу без списка необходимых пакетов."
)
msg_box.setWindowIcon(self.app_icon)
msg_box.exec_()
return False
required_packages = [f"i586-{pkg}" for pkg in base_packages] + base_packages
# 3. Проверка, какие пакеты отсутствуют
try:
# Запрашиваем список всех установленных пакетов один раз для эффективности
result = subprocess.run(
['rpm', '-qa', '--queryformat', '%{NAME}\n'],
capture_output=True, text=True, check=True, encoding='utf-8'
)
installed_packages_set = set(result.stdout.splitlines())
required_packages_set = set(required_packages)
# Находим разницу между требуемыми и установленными пакетами
missing_packages = sorted(list(required_packages_set - installed_packages_set))
except (subprocess.CalledProcessError, FileNotFoundError) as e:
# В случае ошибки (например, rpm не найден), показываем критическое сообщение
msg_box = QMessageBox(QMessageBox.Critical, "Критическая ошибка",
f"Не удалось получить список установленных пакетов с помощью rpm.\n\nОшибка: {e}\n\n"
"Программа не может проверить зависимости и будет закрыта."
)
msg_box.setWindowIcon(self.app_icon)
msg_box.exec_()
return False
if not missing_packages:
return True
# 4. Запрос у пользователя на установку
msg_box = QMessageBox()
msg_box.setWindowIcon(self.app_icon)
msg_box.setIcon(QMessageBox.Warning)
msg_box.setWindowTitle("Отсутствуют зависимости")
# Устанавливаем формат текста в RichText, чтобы QMessageBox корректно обрабатывал HTML-теги.
msg_box.setTextFormat(Qt.RichText)
# Формируем весь текст как единый HTML-блок для корректного отображения.
full_html_text = (
"Для корректной работы WineHelper требуются дополнительные системные компоненты.<br><br>"
"Отсутствуют следующие пакеты:<br>"
# Ограничиваем высоту блока с пакетами и добавляем прокрутку, если список длинный.
f"""<div style="font-family: monospace; max-height: 150px; overflow-y: auto; margin-top: 5px; margin-bottom: 10px;">
{'<br>'.join(sorted(missing_packages))}
</div>"""
"Нажмите <b>'Установить'</b>, чтобы запустить установку с правами администратора. "
"Вам потребуется ввести пароль. Этот процесс может занять некоторое время."
)
msg_box.setText(full_html_text)
install_button = msg_box.addButton("Установить", QMessageBox.AcceptRole)
cancel_button = msg_box.addButton("Отмена", QMessageBox.RejectRole)
msg_box.setDefaultButton(install_button)
msg_box.exec_()
if msg_box.clickedButton() != install_button:
cancel_box = QMessageBox(QMessageBox.Warning, "Отмена",
"Установка отменена.\n\n"
"WineHelper не может продолжить работу\nбез необходимых зависимостей.")
cancel_box.setWindowIcon(self.app_icon)
cancel_box.exec_()
return False
# 5. Запуск установки с отображением лога в диалоговом окне
if not shutil.which('pkexec'):
error_box = QMessageBox(QMessageBox.Critical, "Ошибка",
"Не найден компонент 'pkexec' для повышения прав.\n"
"Пожалуйста, установите пакет 'polkit-pkexec', "
f"а затем установите зависимости вручную:\n\n sudo apt-get install {' '.join(missing_packages)}"
)
error_box.setWindowIcon(self.app_icon)
error_box.exec_()
return False
install_cmd_str = f"apt-get update && apt-get install -y {' '.join(missing_packages)}"
# Этот флаг будет установлен в True, если установка и проверка пройдут успешно.
installation_successful = False
# Создаем диалог для вывода лога установки
dialog = QDialog()
dialog.setWindowIcon(self.app_icon)
dialog.setWindowTitle("Установка зависимостей")
dialog.setMinimumSize(680, 400)
dialog.setModal(True)
# Центрирование окна по центру экрана
screen_geometry = QApplication.primaryScreen().availableGeometry()
dialog.move(
(screen_geometry.width() - dialog.width()) // 2,
(screen_geometry.height() - dialog.height()) // 2
)
layout = QVBoxLayout(dialog)
log_output = QTextEdit()
log_output.setReadOnly(True)
log_output.setFont(QFont("DejaVu Sans Mono", 10))
layout.addWidget(log_output)
close_button = QPushButton("Закрыть")
close_button.setEnabled(False)
close_button.clicked.connect(dialog.accept)
layout.addWidget(close_button)
process = QProcess(dialog)
process.setProcessChannelMode(QProcess.MergedChannels)
def handle_output():
# Используем insertPlainText для корректного отображения потокового вывода (например, прогресс-баров)
log_output.insertPlainText(process.readAll().data().decode('utf-8', 'ignore'))
log_output.moveCursor(QTextCursor.End)
def handle_finish(exit_code, exit_status):
nonlocal installation_successful
log_output.moveCursor(QTextCursor.End)
if exit_code == 0 and exit_status == QProcess.NormalExit:
log_output.append("\n<b><font color='green'>=== Установка успешно завершена ===</font></b>")
log_output.ensureCursorVisible()
# Повторная проверка зависимостей сразу после установки
try:
result = subprocess.run(
['rpm', '-qa', '--queryformat', '%{NAME}\n'],
capture_output=True, text=True, check=True, encoding='utf-8'
)
installed_packages_set = set(result.stdout.splitlines())
missing_packages_set = set(missing_packages)
still_missing = sorted(list(missing_packages_set - installed_packages_set))
except (subprocess.CalledProcessError, FileNotFoundError):
warn_box = QMessageBox(dialog)
warn_box.setWindowIcon(self.app_icon)
warn_box.setIcon(QMessageBox.Warning)
warn_box.setWindowTitle("Проверка не удалась")
warn_box.setText("Не удалось повторно проверить зависимости после установки.")
warn_box.exec_()
still_missing = missing_packages
if not still_missing:
installation_successful = True
close_button.setText("Запустить WineHelper")
else:
warn_box = QMessageBox(dialog)
warn_box.setWindowIcon(self.app_icon)
warn_box.setIcon(QMessageBox.Warning)
warn_box.setWindowTitle("Установка не завершена")
warn_box.setText(
"Не все зависимости были установлены. WineHelper может работать некорректно.\n\n"
f"Отсутствуют: {', '.join(sorted(still_missing))}\n\n"
"Попробуйте запустить установку снова или установите пакеты вручную."
)
warn_box.exec_()
else:
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)
def dialog_close_handler(event):
"""Обрабатывает закрытие окна во время установки зависимостей."""
if process.state() == QProcess.Running:
# QMessageBox без кнопок может некорректно обрабатывать закрытие.
# Используем простой QDialog для надежности.
info_dialog = QDialog(dialog)
info_dialog.setWindowTitle("Идет установка")
info_dialog.setModal(True)
info_dialog.setFixedSize(450, 150)
layout = QVBoxLayout(info_dialog)
label = QLabel(
"<h3>Установка зависимостей еще не завершена.</h3>"
"<p>Пожалуйста, дождитесь окончания процесса.</p>"
"<p>Закрыть основное окно можно будет после завершения установки.</p>"
)
label.setTextFormat(Qt.RichText)
label.setAlignment(Qt.AlignCenter)
layout.addWidget(label)
info_dialog.exec_()
event.ignore()
else:
event.accept()
process.readyRead.connect(handle_output)
process.finished.connect(handle_finish)
log_output.append(f"Выполнение команды:\npkexec sh -c \"{install_cmd_str}\"\n")
log_output.append("Пожалуйста, введите пароль в появившемся окне аутентификации...")
log_output.append("-" * 40 + "\n")
dialog.closeEvent = dialog_close_handler
process.start('pkexec', ['sh', '-c', install_cmd_str])
dialog.exec_()
return installation_successful
def run(self):
"""
Основной публичный метод для запуска полной проверки зависимостей.
Возвращает True, если все зависимости удовлетворены, иначе False.
"""
self._show_startup_messages()
if self._perform_check_and_install():
self._save_dependency_hash()
return True
return False
class WinetricksManagerDialog(QDialog):
"""Диалог для управления компонентами Winetricks."""
@@ -1224,6 +837,7 @@ class WineVersionSelectionDialog(QDialog):
installed_layout = QVBoxLayout(installed_tab)
installed_scroll_area = QScrollArea()
installed_scroll_area.setWidgetResizable(True)
installed_scroll_area.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
installed_layout.addWidget(installed_scroll_area)
installed_content = QWidget()
installed_scroll_area.setWidget(installed_content)
@@ -1296,6 +910,7 @@ class WineVersionSelectionDialog(QDialog):
scroll_area = QScrollArea()
scroll_area.setWidgetResizable(True)
scroll_area.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
tab_layout.addWidget(scroll_area)
scroll_content = QWidget()
@@ -1724,6 +1339,7 @@ class ComponentVersionSelectionDialog(QDialog):
self.scroll_area = QScrollArea()
self.scroll_area.setWidgetResizable(True)
self.scroll_area.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
main_layout.addWidget(self.scroll_area)
scroll_content = QWidget()
@@ -2399,7 +2015,27 @@ class WineHelperGUI(QMainWindow):
scroll_area = QScrollArea()
scroll_area.setWidgetResizable(True)
scroll_area.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
scroll_area.setContentsMargins(0, 0, 0, 0)
# Уменьшаем ширину вертикального скроллбара
scroll_area.setStyleSheet("""
QScrollBar:vertical {
width: 10px;
background: transparent;
margin: 0px;
}
QScrollBar::handle:vertical {
background: #555;
min-height: 20px;
border-radius: 5px;
}
QScrollBar::handle:vertical:hover {
background: #666;
}
QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical {
height: 0px;
}
""")
layout.addWidget(scroll_area)
scroll_content_widget = QWidget()
@@ -4312,6 +3948,8 @@ class WineHelperGUI(QMainWindow):
QMessageBox.critical(self, "Ошибка", f"Не удалось модифицировать команду для отладки: {e}")
return
os.environ["WH_SKIP_DEPS"] = "1"
process = QProcess()
env = QProcessEnvironment.systemEnvironment()
@@ -4344,6 +3982,7 @@ class WineHelperGUI(QMainWindow):
self.running_apps[desktop_path] = process
self._set_run_button_state(True)
print(f"Запущено: {program} {' '.join(arguments)}")
os.environ["WH_SKIP_DEPS"] = "0"
except Exception as e:
QMessageBox.critical(self, "Ошибка запуска",
f"Не удалось запустить команду:\n{command_str}\n\nОшибка: {str(e)}")
@@ -5178,38 +4817,35 @@ def main():
# На всякий случай удаляем старый файл сокета, если он остался от сбоя.
QLocalServer.removeServer(socket_name)
dependency_manager = DependencyManager()
if dependency_manager.run():
window = WineHelperGUI()
window = WineHelperGUI()
# Создаем локальный сервер для приема "сигналов" от последующих запусков
server = QLocalServer(window)
# Создаем локальный сервер для приема "сигналов" от последующих запусков
server = QLocalServer(window)
# Функция для обработки входящих подключений
def handle_new_connection():
client_socket = server.nextPendingConnection()
if client_socket:
# Ждем данные (не обязательно, но для надежности)
client_socket.waitForReadyRead(100)
client_socket.readAll() # Очищаем буфер
window.activate()
client_socket.close()
# Функция для обработки входящих подключений
def handle_new_connection():
client_socket = server.nextPendingConnection()
if client_socket:
# Ждем данные (не обязательно, но для надежности)
client_socket.waitForReadyRead(100)
client_socket.readAll() # Очищаем буфер
window.activate()
client_socket.close()
server.newConnection.connect(handle_new_connection)
server.newConnection.connect(handle_new_connection)
# Начинаем слушать. Если не удалось, программа все равно будет работать,
# но без функции активации существующего окна.
if not server.listen(socket_name):
print(f"Предупреждение: не удалось запустить сервер {socket_name}: {server.errorString()}")
# Начинаем слушать. Если не удалось, программа все равно будет работать,
# но без функции активации существующего окна.
if not server.listen(socket_name):
print(f"Предупреждение: не удалось запустить сервер {socket_name}: {server.errorString()}")
# Сохраняем ссылку на сервер, чтобы он не был удален сборщиком мусора
window.server = server
window.show()
# Создаем иконку в системном трее после создания окна
# window.create_tray_icon() # Временно отключено
return app.exec_()
# Сохраняем ссылку на сервер, чтобы он не был удален сборщиком мусора
window.server = server
window.show()
# Создаем иконку в системном трее после создания окна
# window.create_tray_icon() # Временно отключено
return app.exec_()
return 1
if __name__ == "__main__":
sys.exit(main())