Compare commits
	
		
			44 Commits
		
	
	
		
			fd3442888d
			...
			0.6.0
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | dd2901c85e | ||
|  | 9f28363ac2 | ||
|  | 756c9e6d9e | ||
|  | 663cd10a5f | ||
|  | 86beb9eaee | ||
|  | 4610f6a6da | ||
|  | 4563d5641f | ||
| 17a8f3c63d | |||
|  | 08ef246712 | ||
|  | 07e220794d | ||
|  | 15432ace98 | ||
|  | e04a59507b | ||
|  | d5f337e6b4 | ||
|  | 904c9c9895 | ||
|  | 1d4ee1fd70 | ||
|  | 02a2256c8c | ||
|  | cbcdba204e | ||
|  | 66c56f6ecf | ||
|  | 221b59eda7 | ||
|  | adf5f78360 | ||
|  | 01f19cd94d | ||
|  | 117e497f94 | ||
|  | 3527846c6c | ||
|  | 553d427d66 | ||
|  | 0f8f192634 | ||
|  | 7f64378670 | ||
|  | 165c4ee110 | ||
|  | 843b90c1c2 | ||
|  | e3ac6dd967 | ||
|  | 5763749aa0 | ||
|  | b1f192b2ff | ||
|  | 42aa29d208 | ||
|  | 3ad737e27d | ||
|  | 97996fb67b | ||
|  | 151b6d6e30 | ||
|  | 9f994a8cc3 | ||
|  | 463306d0cf | ||
|  | 940cface08 | ||
|  | c8049efd37 | ||
|  | 8eb5a0aa86 | ||
|  | 7edc205b66 | ||
|  | b36cadd54d | ||
|  | 48d870979f | ||
|  | cbe535b878 | 
							
								
								
									
										17
									
								
								CHANGELOG
									
									
									
									
									
								
							
							
						
						| @@ -1,5 +1,22 @@ | |||||||
| История изменений: | История изменений: | ||||||
|  |  | ||||||
|  | 0.6.0 | ||||||
|  | * обновлен графический режим Qt5 | ||||||
|  | * добавлен иконка в трее для графического режима Qt5 | ||||||
|  | * обновлены скрипты установки для t-flex-* | ||||||
|  | * обновлен скрипт установки для scadoffice | ||||||
|  | * добавлена ручная установка NetTest (демо версия) | ||||||
|  | * добавлены скрипты установки ARM-KT: | ||||||
|  |     winehelper install arm-kt-att - "АРМ КТ ПРОФ АТТЕСТАТ" | ||||||
|  |     winehelper install arm-kt-dpp - "АРМ КТ ПРОФ ДПП" | ||||||
|  |     winehelper install arm-kt-es - "АРМ КТ ПРОФ НШ" | ||||||
|  |     winehelper install arm-kt-med - "АРМ КТ ПРОФ МЕД" | ||||||
|  |     winehelper install arm-kt-prof - "АРМ КТ ПРОФ ПРОФЕССИЯ" | ||||||
|  |     winehelper install arm-kt-spo - "АРМ КТ ПРОФ СПО" | ||||||
|  |     winehelper install arm-kt-vuz - "АРМ КТ ПРОФ ВУЗ" | ||||||
|  | * winehelper killal - убивает только процессы запущенные в WinwHelper | ||||||
|  | * другие небольшие улучшения и оптимизации скриптов | ||||||
|  |  | ||||||
| 0.5.4: | 0.5.4: | ||||||
| * обновлен графический режим Qt5: | * обновлен графический режим Qt5: | ||||||
|     - добавлена возможность установки системных зависимостей |     - добавлена возможность установки системных зависимостей | ||||||
|   | |||||||
							
								
								
									
										364
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,364 @@ | |||||||
|  | <div align="center"> | ||||||
|  |   <img src="image/gui/winehelper.svg" width="64"> | ||||||
|  |   <h1 align="center">WineHelper</h1> | ||||||
|  |   <p align="center">Инструмент для упрощения установки Windows-приложений на Linux. Он использует подготовленные скрипты, портативные версии Wine и изолированные префиксы, обеспечивая максимальную идентичность на различных операционных системах основанных на Alt Linux, начиная с релиза p10 и выше.</p> | ||||||
|  | </div> | ||||||
|  |  | ||||||
|  | <p align="center"> | ||||||
|  |   <img src="image/handbook/auto_install.png" alt="WineHelper GUI" width="80%"> | ||||||
|  | </p> | ||||||
|  |  | ||||||
|  | ## Основные возможности | ||||||
|  |  | ||||||
|  | *   **Простая установка**: Устанавливайте Windows-приложения с помощью готовых скриптов, как в автоматическом, так и в ручном режиме. | ||||||
|  | *   **Изолированные окружения**: Каждое приложение устанавливается в свой собственный, изолированный префикс, что предотвращает конфликты. | ||||||
|  | *   **Управление версиями Wine**: Легко переключайтесь между различными версиями Wine и Proton для достижения наилучшей совместимости. | ||||||
|  | *   **Графический и консольный интерфейсы**: Используйте удобный GUI для повседневных задач или мощный CLI для автоматизации. | ||||||
|  | *   **Резервное копирование**: Создавайте и восстанавливайте полные резервные копии ваших префиксов. | ||||||
|  | *   **Встроенные утилиты**: Быстрый доступ к `winecfg`, `regedit`, `Winetricks` и другим инструментам для каждого префикса. | ||||||
|  |  | ||||||
|  | --- | ||||||
|  |  | ||||||
|  |  | ||||||
|  | <!-- Описание установки WineHelper--> | ||||||
|  | <details> | ||||||
|  |  <summary style="font-size: 35px; font-weight: bold;">Установка</summary> | ||||||
|  |  | ||||||
|  | ``` | ||||||
|  |  $ su - | ||||||
|  |  # apt-get update && apt-get dist-upgrade | ||||||
|  |  # apt-get install winehelper | ||||||
|  |  # exit | ||||||
|  |  ``` | ||||||
|  | </details> | ||||||
|  |  | ||||||
|  |  | ||||||
|  | <!-- Описание использования CLI --> | ||||||
|  | <details> | ||||||
|  |   <summary style="font-size: 35px; font-weight: bold;">Использование WineHelper (CLI)</summary> | ||||||
|  |  | ||||||
|  | ### Список приложений для установки | ||||||
|  |  | ||||||
|  | Вывод списка приложений, доступных к установке: | ||||||
|  | ``` | ||||||
|  |  $ winehelper install list | ||||||
|  |  ``` | ||||||
|  | или сокращенная команда: | ||||||
|  | ``` | ||||||
|  |  $ winehelper -i | ||||||
|  |  ``` | ||||||
|  |  | ||||||
|  | ### Запуск установки приложений | ||||||
|  |  | ||||||
|  | Скрипты установки разделены на два типа: | ||||||
|  |  | ||||||
|  | 1. **Список программ с возможностью автоматической установки** — содержит полностью автоматизированные скрипты установок программ у которыx есть дистрибутивы (установщики) в свободном доступе. | ||||||
|  | Процесс полностью автоматизирован. | ||||||
|  | Пример: | ||||||
|  | ``` | ||||||
|  |  $ winehelper install spravki-bk | ||||||
|  |  ``` | ||||||
|  | или сокращенная команда: | ||||||
|  | ``` | ||||||
|  |  $ winehelper -i spravki-bk | ||||||
|  | ``` | ||||||
|  | 2. **Список программ с возможностью установки из существующего дистрибутива** — содержит скрипты установок для программ, которых нет в свободном доступе. | ||||||
|  | Пример: | ||||||
|  | ``` | ||||||
|  |  $ winehelper install is-record-station "/путь/до/установочного_файла" | ||||||
|  |  ``` | ||||||
|  | или сокращенная команда: | ||||||
|  | ``` | ||||||
|  |  $ winehelper -i is-record-station "/путь/до/установочного_файла" | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | ### Процесс установки приложений | ||||||
|  |  | ||||||
|  | При первом запуске **WineHelper** проверяются и при необходимости устанавливаются дополнительные зависимости (запрашиваются права root). | ||||||
|  |  | ||||||
|  | Процесс установки приложений: | ||||||
|  | 1. Отображаются лицензионные соглашения на сторонние компоненты. Для продолжения введите **y** и нажмите **Enter**. | ||||||
|  | 2. Далее процесс проходит автоматически с подробным выводом в терминал: | ||||||
|  | - Загрузка и проверка хэш-суммы нужной версии Wine. | ||||||
|  | - Загрузка и проверка хэш-суммы базового префикса. | ||||||
|  | - Инициализация и подготовка префикса. | ||||||
|  | - Скачивание дистрибутива (установщика) программы с официального сайта (если применимо). | ||||||
|  | - Установка приложения. | ||||||
|  | - Создание .desktop-файла (ярлыка) на рабочем столе и в меню приложений. | ||||||
|  |  | ||||||
|  | Если устанавливаемое приложение требует дополнительных действий от пользователя (ввод лицензии, настройка), это будет явно указано в терминале. | ||||||
|  |  | ||||||
|  | ### Удаление префикса с приложением | ||||||
|  |  | ||||||
|  | Для удаления префикса выполните команду: | ||||||
|  | ``` | ||||||
|  |  $ winehelper remove-prefix [имя_префикса] | ||||||
|  |  ``` | ||||||
|  | Если имя префикса не указано, будет выведен список существующих префиксов: | ||||||
|  | ``` | ||||||
|  |  0 - Отмена | ||||||
|  |  1 - Префикс1 | ||||||
|  |  2 - Префикс2 | ||||||
|  |  Выберите префикс (0-2): | ||||||
|  | ``` | ||||||
|  | Необходимо указать номер удаляемого префикса и нажать клавишу **Enter**.Далее потребуется подтвердить удаление префикса вводом **y**. | ||||||
|  |  | ||||||
|  | В результате будут удалены: | ||||||
|  | - сам префикс; | ||||||
|  | - установленное ПО; | ||||||
|  | - desktop-файлы (ярлыки для установленного ПО в префиксе). | ||||||
|  |  | ||||||
|  | ###  | ||||||
|  |  | ||||||
|  | Команда создания резервной копии префикса: | ||||||
|  | ``` | ||||||
|  |  $ winehelper backup-prefix [имя_префикса] | ||||||
|  |  ``` | ||||||
|  | Если имя префикса не указано, будет выведен список существующих префиксов: | ||||||
|  | ``` | ||||||
|  |  0 - Отмена | ||||||
|  |  1 - Префикс1 | ||||||
|  |  2 - Префикс2 | ||||||
|  |  Выберите префикс (0-2): | ||||||
|  |  ``` | ||||||
|  | Необходимо указать номер удаляемого префикса и нажать клавишу **Enter**.   | ||||||
|  | После выбора префикса автоматически: | ||||||
|  | - Создаётся копия префикса. | ||||||
|  | - Внутри префикса сохраняется используемая версия WINE. | ||||||
|  | - Копируются иконки для ярлыков (.desktop-файлов). | ||||||
|  | - Сохраняется информация о ярлыках (.desktop-файлах) для будущей распаковки/восстановления префикса. | ||||||
|  | - Резервная копия сохраняется на рабочем столе с именем: {{path|backup_имя_префикса_дата_создания.whpack}} | ||||||
|  |  | ||||||
|  | ### Восстановление префикса из резервной копии | ||||||
|  |  | ||||||
|  | Команда восстановления префикса из резервной копии: | ||||||
|  | ``` | ||||||
|  |  $ winehelper restore-prefix "путь/до/файла.whpack" | ||||||
|  | ``` | ||||||
|  | Восстановление префикса не требует подключение к интернету и происходит в автоматическом режиме: | ||||||
|  | - Распаковка префикса. | ||||||
|  | - Восстановление версии WINE. | ||||||
|  | - Восстановление ярлыков (.desktop-файdлов). | ||||||
|  |  | ||||||
|  | После завершения восстановления приложение будет доступно для запуска через меню или рабочий стол. | ||||||
|  |  | ||||||
|  | ### Использование команд WINE в WineHelper | ||||||
|  |  | ||||||
|  | WineHelper предоставляет доступ к основным инструментам WINE: | ||||||
|  | ``` | ||||||
|  |  winehelper winefile                  # запуск файлового менеджера wine | ||||||
|  |  winehelper winecfg                   # запуск wine конфигуратора для префикса | ||||||
|  |  winehelper winereg                   # запуск редактора реестра для префикса | ||||||
|  |  winehelper wineconsole               # запуск терминала wine (cmd.exe) | ||||||
|  |  winehelper winetricks                # запуск графического интерфейса winetricks | ||||||
|  |  winehelper winetricks [компонент]    # автоматическая установка дополнительного компонента в префикс | ||||||
|  | ``` | ||||||
|  | После выполнения любой из вышеперечисленных команд отображается список существующих префиксов: | ||||||
|  |  ``` | ||||||
|  | 0 - Отмена | ||||||
|  |  1 - Префикс1 | ||||||
|  |  2 - Префикс2 | ||||||
|  |  Выберите префикс (0-2): | ||||||
|  |  ``` | ||||||
|  | Команда выполняется в выбранном вами префиксе. | ||||||
|  |  | ||||||
|  | ### Запуск стороннего *.exe файла в WineHelper | ||||||
|  |  | ||||||
|  | Есть два варианта: | ||||||
|  | 1. В командной строке выполнить команду: | ||||||
|  |  ``` | ||||||
|  |  $ winehelper "путь/до/файла.exe" | ||||||
|  |  0 - Отмена | ||||||
|  |  1 - Префикс1 | ||||||
|  |  2 - Префикс2 | ||||||
|  |  Выберите префикс (0-2): | ||||||
|  |  ``` | ||||||
|  | Файл будет запущен в выбранном префиксе. | ||||||
|  |  | ||||||
|  | 2. С помощью файлового менеджера WINE:''' | ||||||
|  |  ``` | ||||||
|  |  $ winehelper winefile | ||||||
|  |  0 - Отмена | ||||||
|  |  1 - Префикс1 | ||||||
|  |  2 - Префикс2 | ||||||
|  |  Выберите префикс (0-2): | ||||||
|  |  ``` | ||||||
|  | В файловом менеджере найти и запустить нужный exe-файл. | ||||||
|  |  | ||||||
|  | ### Дополнительные команды | ||||||
|  |  | ||||||
|  |  ``` | ||||||
|  |  $ winehelper help | ||||||
|  |  ``` | ||||||
|  | Вывод: | ||||||
|  | <pre> | ||||||
|  | Использование: winehelper [команда] | ||||||
|  |  | ||||||
|  | Команды: | ||||||
|  |     install list                    список возможных установочных скриптов | ||||||
|  |     install [скрипт]                запустить скрипт установки программы | ||||||
|  |     install [скрипт] --clear-pfx    не использовать готовый префикс для установки ПО | ||||||
|  |  | ||||||
|  |     install-dxvk [версия|none|list] установить, удалить или показать версии DXVK | ||||||
|  |     install-vkd3d [версия|none|list] установить, удалить или показать версии VKD3D | ||||||
|  |     change-wine [версия]            изменить версию Wine/Proton для текущего префикса | ||||||
|  |  | ||||||
|  |     installed                       список установленных программ | ||||||
|  |     run [программа]                 запуск программы (отладка) | ||||||
|  |     remove-all                      удалить WineHelper и все связанные данные | ||||||
|  |     create-prefix                   создать префикс | ||||||
|  |     remove-prefix [имя_префикса]    удалить префикс и все связанные данные | ||||||
|  |     backup-prefix [имя_префикса]    создать резервную копию префикса | ||||||
|  |     restore-prefix \"путь/до/whpack\" восстановить префикс из резервной копии | ||||||
|  |  | ||||||
|  | Параметры: | ||||||
|  |     --help                          показать эту справку и выйти | ||||||
|  |     --version                       показать информацию о пакете и его версии | ||||||
|  |     --changelog                     показать историю изменений | ||||||
|  |     --debug [команда]               включить режим логирования работы WINE | ||||||
|  | </pre> | ||||||
|  |  | ||||||
|  | </details> | ||||||
|  |  | ||||||
|  |  | ||||||
|  | <!-- Описание использования GUI --> | ||||||
|  | <details> | ||||||
|  |   <summary style="font-size: 35px; font-weight: bold;">Использование WineHelper (GUI)</summary> | ||||||
|  |  | ||||||
|  | ### Вкладки «Автоматическая установка» и «Ручная установка» | ||||||
|  |  | ||||||
|  | При использовании графического интерфейса списки приложений расположены во вкладках **Автоматическая установка** и **Ручная установка**. | ||||||
|  |  | ||||||
|  | <div align="center"> | ||||||
|  |   <img src="image/handbook/auto_install.png"> | ||||||
|  |   <p><em>Вкладка "Автоматическая установка"</em></p> | ||||||
|  | </div> | ||||||
|  |  | ||||||
|  | <div align="center"> | ||||||
|  |   <img src="image/handbook/manual_install.png"> | ||||||
|  |   <p><em>Вкладка "Ручная установка"</em></p> | ||||||
|  | </div> | ||||||
|  |  | ||||||
|  | Для поиска нужной программы введите название в поле поиска. | ||||||
|  |  | ||||||
|  | <div align="center"> | ||||||
|  |   <img src="image/handbook/search.png"> | ||||||
|  |   <p><em>Поле поиска</em></p> | ||||||
|  | </div> | ||||||
|  |  | ||||||
|  | При выборе программы из списка слева, в правой части окна отображается подробная информация о ней: описание, иконка и ссылка на официальный сайт. | ||||||
|  |  | ||||||
|  | <div align="center"> | ||||||
|  |   <img src="image/handbook/info.png"> | ||||||
|  |   <p><em>Информация о выбранной программе</em></p> | ||||||
|  | </div> | ||||||
|  |  | ||||||
|  | Для установки программы нажмите кнопку **Установить**. | ||||||
|  |  | ||||||
|  | Для **ручной установки** дополнительно потребуется указать путь к установочному файлу (`.exe` или `.msi`), который вы скачали самостоятельно. | ||||||
|  |  | ||||||
|  | <div align="center"> | ||||||
|  |   <img src="image/handbook/manual_install_1.png"> | ||||||
|  |   <p><em>Вкладка "Ручная установка" с указанием пути к дистрибутиву</em></p> | ||||||
|  | </div> | ||||||
|  |  | ||||||
|  | После нажатия кнопки **Установить** появится окно с лицензионным соглашением. После его принятия начнется процесс установки, который будет подробно логироваться в отдельном окне. | ||||||
|  |  | ||||||
|  | <div align="center"> | ||||||
|  |   <img src="image/handbook/license_agreement.png"> | ||||||
|  |   <p><em>Окно с лицензионным соглашением</em></p> | ||||||
|  | </div> | ||||||
|  |  | ||||||
|  | <div align="center"> | ||||||
|  |   <img src="image/handbook/log.png"> | ||||||
|  |   <p><em>Окно установки с логом</em></м</em></p> | ||||||
|  | </div> | ||||||
|  |  | ||||||
|  | После установки приложения и нажатия кнопки **Закрыть** в окне установки приложения, ярлык приложения появится в списке установленных приложений во вкладке **Установленные** а также в меню приложений и на рабочем столе если это разрешено в рабочем окружении. | ||||||
|  |  | ||||||
|  | ### Вкладка «Установленные» | ||||||
|  |  | ||||||
|  | На этой вкладке отображаются все приложения, которые были установлены с помощью WineHelper. | ||||||
|  |  | ||||||
|  | <div align="center"> | ||||||
|  |   <img src="image/handbook/installed.png"> | ||||||
|  |   <p><em>Вкладка "Установленные"</em></p> | ||||||
|  | </div> | ||||||
|  |  | ||||||
|  | При выборе приложения в правой панели становятся доступны следующие действия: | ||||||
|  | *   **Запустить/Остановить**: Запускает или останавливает/закрывает выбранное приложение. | ||||||
|  | *   **Создать лог запуска программы**: Запускает приложение в режиме отладки. После закрытия приложения в вашем домашнем каталоге будет создан файл `winehelper.log`. | ||||||
|  | *   **Создать резервную копию префикса**: Создает полный бэкап префикса приложения (включая версию Wine) в формате `.whpack` на вашем рабочем столе если это разрешено в рабочем окружении. | ||||||
|  | *   **Удалить префикс**: Полностью удаляет приложение вместе с его префиксом и всеми связанными ярлыками. | ||||||
|  |  | ||||||
|  | Также на этой вкладке доступна кнопка **«Восстановить префикс из резервной копии»**, которая позволяет восстановить любое приложение из ранее созданного `.whpack` файла. | ||||||
|  |  | ||||||
|  | <div align="center"> | ||||||
|  |   <img src="image/handbook/election_installed.png"> | ||||||
|  |   <p><em>Выбранное приложение во вкладке "Установленные"</em></p> | ||||||
|  | </div> | ||||||
|  |  | ||||||
|  | ### Вкладка «Менеджер префиксов» | ||||||
|  |  | ||||||
|  | Эта вкладка предоставляет мощные инструменты для управления префиксами Wine. | ||||||
|  |  | ||||||
|  | <div align="center"> | ||||||
|  |   <img src="image/handbook/prefix_manager.png"> | ||||||
|  |   <p><em>Вкладка "Менеджер префиксов"</em></p> | ||||||
|  | </div> | ||||||
|  |  | ||||||
|  | #### Создание нового префикса | ||||||
|  |  | ||||||
|  | Нажав кнопку **«Создать новый префикс»**, вы откроете диалог, где можно задать: | ||||||
|  | *   **Имя префикса**. | ||||||
|  | *   **Разрядность** (32-bit или 64-bit). | ||||||
|  | *   **Наполнение** (чистый префикс или с рекомендуемыми библиотеками). | ||||||
|  | *   **Версию Wine/Proton** из доступного списка. | ||||||
|  |  | ||||||
|  | <div align="center"> | ||||||
|  |   <img src="image/handbook/create_prefix.png"> | ||||||
|  |   <p><em>Диалог создания нового префикса</em></p> | ||||||
|  | </div> | ||||||
|  |  | ||||||
|  | #### Управление существующим префиксом | ||||||
|  |  | ||||||
|  | Выбрав префикс из выпадающего списка, вы получаете доступ к панели управления, которая позволяет: | ||||||
|  |  | ||||||
|  | *   **Запускать стандартные утилиты Wine**: | ||||||
|  |     *   `Редактор настроек (winecfg)` | ||||||
|  |     *   `Редактор реестра (regedit)` | ||||||
|  |     *   `Удаление программ (uninstaller)` | ||||||
|  |     *   `Командная строка (cmd)` | ||||||
|  |     *   `Файловый менеджер (winefile)` | ||||||
|  | *   **Управлять компонентами**: | ||||||
|  |     *   **Менеджер компонентов (Winetricks)**: Удобный интерфейс для установки и переустановки библиотек, шрифтов и настроек. | ||||||
|  |     *   **Управление Wine/Proton**: Смена версии Wine или Proton для выбранного префикса. | ||||||
|  |     *   **Управление DXVK/VKD3D**: Установка или удаление конкретных версий DXVK и VKD3D. | ||||||
|  |     *   **Ассоциации файлов**: Настройка открытия определенных типов файлов (например, `.pdf`, `.docx`) нативными приложениями Linux. | ||||||
|  | *   **Включать/выключать ESync и FSync**. | ||||||
|  | *   **Устанавливать приложения**: Установить любой `.exe` или `.msi` файл напрямую в выбранный префикс. | ||||||
|  | *   **Создавать ярлыки**: Создать ярлык для любого исполняемого файла внутри префикса. | ||||||
|  | *   **Удалять префикс** или **создавать из него шаблон**. | ||||||
|  |  | ||||||
|  | Справа отображается подробная информация о конфигурации выбранного префикса. | ||||||
|  |  | ||||||
|  | ### Вкладка «Справка» | ||||||
|  |  | ||||||
|  | Содержит полезную информацию о проекте: | ||||||
|  | *   **Руководство**: Ссылка на официальную документацию. | ||||||
|  | *   **Авторы**: Список разработчиков и участников проекта. | ||||||
|  | *   **Лицензия**: Текст лицензии WineHelper и информация о сторонних компонентах. | ||||||
|  | *   **История изменений**: Changelog пакета. | ||||||
|  |  | ||||||
|  | <div align="center"> | ||||||
|  |   <img src="image/handbook/help.png"> | ||||||
|  |   <p><em>Вкладка "Справка"</em></p> | ||||||
|  | </div> | ||||||
|  |  | ||||||
|  | </details> | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ### Примечание | ||||||
|  |  | ||||||
|  | > [!WARNING] | ||||||
|  | > Проект находится на стадии WIP (work in progress) | ||||||
| @@ -6,10 +6,10 @@ export WH_WINE_USE="wine_x_tkg_10-0_amd64" | |||||||
| export WINEPREFIX="scadoffice" | export WINEPREFIX="scadoffice" | ||||||
| export PROG_NAME="SCAD Office" | export PROG_NAME="SCAD Office" | ||||||
| export PROG_ICON="scadoffice" | export PROG_ICON="scadoffice" | ||||||
| export BASE_PFX="scadaoffice_pfx_x64_v03" | export BASE_PFX="scadaoffice_pfx_x64_v04" | ||||||
| export WH_WINDOWS_VER="10" | export WH_WINDOWS_VER="10" | ||||||
| export WINEARCH="win64" | export WINEARCH="win64" | ||||||
| export INSTALL_DLL="dotnet20 dotnet472 dotnet48 gdiplus vcrun6sp6 vcrun2005 vcrun2019 d3dx11_42 d3dx11_43 d3dx9 d3dcompiler_42 d3dcompiler_43 d3dcompiler_46 d3dcompiler_47 richtx32 riched30 riched20 msxml6" | export INSTALL_DLL="dotnet20 dotnet48 gdiplus vcrun6sp6 vcrun2005 vcrun2019 d3dx11_42 d3dx11_43 d3dx9 d3dcompiler_42 d3dcompiler_43 d3dcompiler_46 d3dcompiler_47 richtx32 riched30 riched20 msxml6" | ||||||
| export WH_XDG_OPEN="rtf" | export WH_XDG_OPEN="rtf" | ||||||
| AUTOINSTALL_EXE="${WH_TMP_DIR}/SCADOffice_installer.exe" | AUTOINSTALL_EXE="${WH_TMP_DIR}/SCADOffice_installer.exe" | ||||||
| SCADOFFICE_ADDONS_URL="https://cloud.linux-gaming.ru/portproton/scadoffice_addons_v02.tar.xz" | SCADOFFICE_ADDONS_URL="https://cloud.linux-gaming.ru/portproton/scadoffice_addons_v02.tar.xz" | ||||||
|   | |||||||
| @@ -5,7 +5,7 @@ export PROG_URL="https://www.tflexcad.ru" | |||||||
| export PROG_NAME="T-FLEX CAD Учебная Версия 17" | export PROG_NAME="T-FLEX CAD Учебная Версия 17" | ||||||
| export PROG_ICON="tflexcad" | export PROG_ICON="tflexcad" | ||||||
| export WH_WINE_USE="wine_wh_tflex_10-9_amd64" | export WH_WINE_USE="wine_wh_tflex_10-9_amd64" | ||||||
| export BASE_PFX="tflex17_pfx_x64_v02" | export BASE_PFX="tflex_pfx_x64_v03" | ||||||
| export WINEARCH="win64" | export WINEARCH="win64" | ||||||
| export WH_WINDOWS_VER="10" | export WH_WINDOWS_VER="10" | ||||||
| export WINEPREFIX="tflex" | export WINEPREFIX="tflex" | ||||||
| @@ -14,7 +14,7 @@ export WH_USE_MESA_GL_OVERRIDE="1" | |||||||
|  |  | ||||||
| # используем общий whdb файл для подготовки префикса и сервисов | # используем общий whdb файл для подготовки префикса и сервисов | ||||||
| # prepair_wine используется из файла настроек | # prepair_wine используется из файла настроек | ||||||
| source "$WH_DB_DIR/t-flex-cad17.whdb" | source "$WH_DB_DIR/t-flex-cad.whdb" | ||||||
|  |  | ||||||
| # Программа T-FLEX CAD Учебная Версия | # Программа T-FLEX CAD Учебная Версия | ||||||
| export AUTOINSTALL_ZIP="${WH_TMP_DIR}/TFCAD_ST_17x64_PACK.zip" | export AUTOINSTALL_ZIP="${WH_TMP_DIR}/TFCAD_ST_17x64_PACK.zip" | ||||||
|   | |||||||
| @@ -5,7 +5,7 @@ export PROG_URL="https://www.tflexcad.ru" | |||||||
| export PROG_NAME="T-FLEX CAD 17" | export PROG_NAME="T-FLEX CAD 17" | ||||||
| export PROG_ICON="tflexcad" | export PROG_ICON="tflexcad" | ||||||
| export WH_WINE_USE="wine_wh_tflex_10-9_amd64" | export WH_WINE_USE="wine_wh_tflex_10-9_amd64" | ||||||
| export BASE_PFX="tflex17_pfx_x64_v02" | export BASE_PFX="tflex_pfx_x64_v03" | ||||||
| export WINEARCH="win64" | export WINEARCH="win64" | ||||||
| export WH_WINDOWS_VER="10" | export WH_WINDOWS_VER="10" | ||||||
| export WINEPREFIX="tflex" | export WINEPREFIX="tflex" | ||||||
| @@ -14,7 +14,7 @@ export WH_USE_MESA_GL_OVERRIDE="1" | |||||||
|  |  | ||||||
| # используем общий whdb файл для подготовки префикса и сервисов | # используем общий whdb файл для подготовки префикса и сервисов | ||||||
| # prepair_wine используется из файла настроек | # prepair_wine используется из файла настроек | ||||||
| source "$WH_DB_DIR/t-flex-cad17.whdb" | source "$WH_DB_DIR/t-flex-cad.whdb" | ||||||
|  |  | ||||||
| # Программа T-FLEX CAD | # Программа T-FLEX CAD | ||||||
| export AUTOINSTALL_ZIP="${WH_TMP_DIR}/T-FLEX CAD 17.zip" | export AUTOINSTALL_ZIP="${WH_TMP_DIR}/T-FLEX CAD 17.zip" | ||||||
|   | |||||||
| @@ -6,7 +6,7 @@ export PROG_NAME="Приложения для T-FLEX CAD 17" | |||||||
| export PROG_ICON="tflexcad" | export PROG_ICON="tflexcad" | ||||||
| export WH_WINDOWS_VER="10" | export WH_WINDOWS_VER="10" | ||||||
| export WH_WINE_USE="wine_wh_tflex_10-9_amd64" | export WH_WINE_USE="wine_wh_tflex_10-9_amd64" | ||||||
| export BASE_PFX="tflex17_pfx_x64_v02" | export BASE_PFX="tflex_pfx_x64_v03" | ||||||
| export WINEARCH="win64" | export WINEARCH="win64" | ||||||
| export WINEPREFIX="tflex" | export WINEPREFIX="tflex" | ||||||
| export WH_XDG_OPEN="log" | export WH_XDG_OPEN="log" | ||||||
|   | |||||||
| @@ -6,7 +6,7 @@ export PROG_NAME="Ресурсы для T-FLEX CAD 17" | |||||||
| export PROG_ICON="tflexcad" | export PROG_ICON="tflexcad" | ||||||
| export WH_WINDOWS_VER="10" | export WH_WINDOWS_VER="10" | ||||||
| export WH_WINE_USE="wine_wh_tflex_10-9_amd64" | export WH_WINE_USE="wine_wh_tflex_10-9_amd64" | ||||||
| export BASE_PFX="tflex17_pfx_x64_v02" | export BASE_PFX="tflex_pfx_x64_v03" | ||||||
| export WINEARCH="win64" | export WINEARCH="win64" | ||||||
| export WINEPREFIX="tflex" | export WINEPREFIX="tflex" | ||||||
| export WH_XDG_OPEN="log" | export WH_XDG_OPEN="log" | ||||||
|   | |||||||
| @@ -5,7 +5,7 @@ export PROG_URL="https://www.tflexcad.ru" | |||||||
| export PROG_NAME="T-FLEX CAD 2D+ 17" | export PROG_NAME="T-FLEX CAD 2D+ 17" | ||||||
| export PROG_ICON="tflexcad" | export PROG_ICON="tflexcad" | ||||||
| export WH_WINE_USE="wine_wh_tflex_10-9_amd64" | export WH_WINE_USE="wine_wh_tflex_10-9_amd64" | ||||||
| export BASE_PFX="tflex17_pfx_x64_v02" | export BASE_PFX="tflex_pfx_x64_v03" | ||||||
| export WINEARCH="win64" | export WINEARCH="win64" | ||||||
| export WH_WINDOWS_VER="10" | export WH_WINDOWS_VER="10" | ||||||
| export WINEPREFIX="tflex" | export WINEPREFIX="tflex" | ||||||
| @@ -14,7 +14,7 @@ export WH_USE_MESA_GL_OVERRIDE="1" | |||||||
|  |  | ||||||
| # используем общий whdb файл для подготовки префикса и сервисов | # используем общий whdb файл для подготовки префикса и сервисов | ||||||
| # prepair_wine используется из файла настроек | # prepair_wine используется из файла настроек | ||||||
| source "$WH_DB_DIR/t-flex-cad17.whdb" | source "$WH_DB_DIR/t-flex-cad.whdb" | ||||||
|  |  | ||||||
| # Программа T-FLEX CAD 2D+ 17 | # Программа T-FLEX CAD 2D+ 17 | ||||||
| export AUTOINSTALL_ZIP="${WH_TMP_DIR}/T-FLEX CAD 2D+ 17.zip" | export AUTOINSTALL_ZIP="${WH_TMP_DIR}/T-FLEX CAD 2D+ 17.zip" | ||||||
|   | |||||||
| @@ -5,7 +5,7 @@ export PROG_URL="https://www.tflexcad.ru" | |||||||
| export PROG_NAME="T-FLEX DOCs 17" | export PROG_NAME="T-FLEX DOCs 17" | ||||||
| export PROG_ICON="tflexdoc" | export PROG_ICON="tflexdoc" | ||||||
| export WH_WINE_USE="wine_wh_tflex_10-9_amd64" | export WH_WINE_USE="wine_wh_tflex_10-9_amd64" | ||||||
| export BASE_PFX="tflex17_pfx_x64_v02" | export BASE_PFX="tflex_pfx_x64_v03" | ||||||
| export WINEARCH="win64" | export WINEARCH="win64" | ||||||
| export WH_WINDOWS_VER="10" | export WH_WINDOWS_VER="10" | ||||||
| export WINEPREFIX="tflex" | export WINEPREFIX="tflex" | ||||||
| @@ -14,7 +14,7 @@ export WH_USE_MESA_GL_OVERRIDE="1" | |||||||
|  |  | ||||||
| # используем общий whdb файл для подготовки префикса и сервисов | # используем общий whdb файл для подготовки префикса и сервисов | ||||||
| # prepair_wine используется из файла настроек | # prepair_wine используется из файла настроек | ||||||
| source "$WH_DB_DIR/t-flex-cad17.whdb" | source "$WH_DB_DIR/t-flex-cad.whdb" | ||||||
|  |  | ||||||
| # Программа T-FLEX DOC | # Программа T-FLEX DOC | ||||||
| AUTOINSTALL_ZIP="${WH_TMP_DIR}/T-FLEX DOCs 17 Client.zip" | AUTOINSTALL_ZIP="${WH_TMP_DIR}/T-FLEX DOCs 17 Client.zip" | ||||||
|   | |||||||
| @@ -5,7 +5,7 @@ export PROG_URL="https://www.tflexcad.ru" | |||||||
| export PROG_NAME="T-FLEX Viewer 17" | export PROG_NAME="T-FLEX Viewer 17" | ||||||
| export PROG_ICON="tflexcad" | export PROG_ICON="tflexcad" | ||||||
| export WH_WINE_USE="wine_wh_tflex_10-9_amd64" | export WH_WINE_USE="wine_wh_tflex_10-9_amd64" | ||||||
| export BASE_PFX="tflex17_pfx_x64_v02" | export BASE_PFX="tflex_pfx_x64_v03" | ||||||
| export WINEARCH="win64" | export WINEARCH="win64" | ||||||
| export WH_WINDOWS_VER="10" | export WH_WINDOWS_VER="10" | ||||||
| export WINEPREFIX="tflex" | export WINEPREFIX="tflex" | ||||||
| @@ -14,7 +14,7 @@ export WH_USE_MESA_GL_OVERRIDE="1" | |||||||
|  |  | ||||||
| # используем общий whdb файл для подготовки префикса и сервисов | # используем общий whdb файл для подготовки префикса и сервисов | ||||||
| # prepair_wine используется из файла настроек | # prepair_wine используется из файла настроек | ||||||
| source "$WH_DB_DIR/t-flex-cad17.whdb" | source "$WH_DB_DIR/t-flex-cad.whdb" | ||||||
|  |  | ||||||
| # Программа T-FLEX Viewer | # Программа T-FLEX Viewer | ||||||
| export AUTOINSTALL_ZIP="${WH_TMP_DIR}/T-FLEX Viewer 17.zip" | export AUTOINSTALL_ZIP="${WH_TMP_DIR}/T-FLEX Viewer 17.zip" | ||||||
|   | |||||||
| @@ -1,28 +1,24 @@ | |||||||
| #!/usr/bin/env bash | #!/usr/bin/env bash | ||||||
| # info_ru: Компоненты сервисов поддержки T-FLEX 17 | # info_ru: Компоненты сервисов поддержки T-FLEX 17 и 18 | ||||||
| ######################################################################## | ######################################################################## | ||||||
| export WH_WINDOWS_VER="10" | export WH_WINDOWS_VER="10" | ||||||
| export WH_WINE_USE="wine_wh_tflex_10-9_amd64" | export WH_WINE_USE="wine_wh_tflex_10-9_amd64" | ||||||
| export BASE_PFX="tflex17_pfx_x64_v02" | export BASE_PFX="tflex_pfx_x64_v03" | ||||||
| export WINEARCH="win64" | export WINEARCH="win64" | ||||||
| export WINEPREFIX="tflex" | export WINEPREFIX="tflex" | ||||||
| export PROG_VERSION="" | export PROG_VERSION="" | ||||||
| export WH_XDG_OPEN="log" | 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" | export INSTALL_DLL="corefonts d3dcompiler_47 dotnet48 dotnet20 vcrun2019 ucrtbase2019 msxml6 fontsmooth=rgb baekmuk droid eufonts ipamona liberation lucida opensymbol sourcehansans tahoma takao uff unifont vlgothic wenquanyi wenquanyizenhei" | ||||||
| export WH_USE_MESA_GL_OVERRIDE="1" | export WH_USE_MESA_GL_OVERRIDE="1" | ||||||
| 
 | 
 | ||||||
| # Компоненты поддержки T-FLEX PLM (Linux) |  | ||||||
| GRDCONTROL_VER="4.3.0-0" | GRDCONTROL_VER="4.3.0-0" | ||||||
| AUTOINSTALL_ZIP_LIN="$WH_TMP_DIR/Prerequisites_T-FLEX_Linux.zip" | AUTOINSTALL_ZIP_LIN="$WH_TMP_DIR/Prerequisites_T-FLEX_Linux.zip" | ||||||
| AUTOINSTALL_DIR_LIN="$WH_TMP_DIR/Prerequisites_T-FLEX_Linux" | AUTOINSTALL_DIR_LIN="$WH_TMP_DIR/Prerequisites_T-FLEX_Linux" | ||||||
| AUTOINSTALL_REG_LIN="$AUTOINSTALL_DIR_LIN/Components/fake_hasp.reg" |  | ||||||
| 
 | 
 | ||||||
| # Компоненты поддержки T-FLEX PLM (Windows) | AUTOINSTALL_EXE_ADE2007="$AUTOINSTALL_DIR_LIN/Components/AccessDatabaseEngine.exe" | ||||||
| AUTOINSTALL_ZIP_WIN="$WH_TMP_DIR/T-FLEX 17 Prerequisites.zip" | AUTOINSTALL_EXE_TSC2="$AUTOINSTALL_DIR_LIN/Components/Setup_TSC2.msi" | ||||||
| AUTOINSTALL_DIR_WIN="$WH_TMP_DIR/Компоненты поддержки T-FLEX 17" | AUTOINSTALL_EXE_VC_X86="$AUTOINSTALL_DIR_LIN/Components/vc_redist.x86.exe" | ||||||
| AUTOINSTALL_EXE_WIN1="$AUTOINSTALL_DIR_WIN/Access Database Engine 2007/AccessDatabaseEngine.exe" | AUTOINSTALL_EXE_VC_X64="$AUTOINSTALL_DIR_LIN/Components/vc_redist.x64.exe" | ||||||
| AUTOINSTALL_EXE_WIN_MSI="$AUTOINSTALL_DIR_WIN/Access Database Engine 2007" |  | ||||||
| AUTOINSTALL_EXE_WIN2="$AUTOINSTALL_DIR_WIN/TSC2/Setup_TSC2.msi" |  | ||||||
| 
 | 
 | ||||||
| prepair_wine | prepair_wine | ||||||
| 
 | 
 | ||||||
| @@ -42,11 +38,8 @@ else | |||||||
|     || ! systemctl list-units --type service --state running | grep hasplmd \ |     || ! systemctl list-units --type service --state running | grep hasplmd \ | ||||||
|     || ! rpm -q grdcontrol | grep -q "$GRDCONTROL_VER" |     || ! rpm -q grdcontrol | grep -q "$GRDCONTROL_VER" | ||||||
|     then |     then | ||||||
|         # Компоненты поддержки T-FLEX PLM (Linux) |         try_download "https://www.tflex.ru/downloads/Prerequisites_T-FLEX_Linux.zip" "${AUTOINSTALL_ZIP_LIN}" | ||||||
|         if try_download "https://www.tflex.ru/downloads/Prerequisites_T-FLEX_Linux.zip" "${AUTOINSTALL_ZIP_LIN}" ; then |  | ||||||
|         unpack "$AUTOINSTALL_ZIP_LIN" "$AUTOINSTALL_DIR_LIN" |         unpack "$AUTOINSTALL_ZIP_LIN" "$AUTOINSTALL_DIR_LIN" | ||||||
|             "$WINELOADER" regedit "$AUTOINSTALL_REG_LIN" |  | ||||||
|         fi |  | ||||||
| 
 | 
 | ||||||
|         if rpm -q grdcontrol | grep -q "$GRDCONTROL_VER" |         if rpm -q grdcontrol | grep -q "$GRDCONTROL_VER" | ||||||
|         then print_info "grdcontrol-$GRDCONTROL_VER уже установлен в системе." |         then print_info "grdcontrol-$GRDCONTROL_VER уже установлен в системе." | ||||||
| @@ -55,14 +48,14 @@ else | |||||||
| 
 | 
 | ||||||
|         if [[ "$BASE_PFX" == "none" ]] ; then |         if [[ "$BASE_PFX" == "none" ]] ; then | ||||||
|             print_info "Запускаем подготовку префикса." |             print_info "Запускаем подготовку префикса." | ||||||
|             # Компоненты поддержки T-FLEX PLM (Windows) |  | ||||||
|             if try_download "https://www.tflex.ru/downloads/T-FLEX%2017%20Prerequisites.zip" "${AUTOINSTALL_ZIP_WIN}" ; then |  | ||||||
|                 unpack "$AUTOINSTALL_ZIP_WIN" "$WH_TMP_DIR" |  | ||||||
|                 unpack "$AUTOINSTALL_EXE_WIN1" "$AUTOINSTALL_EXE_WIN_MSI" |  | ||||||
| 
 | 
 | ||||||
|                 wine_run_install "$AUTOINSTALL_EXE_WIN_MSI/AceRedist.msi" /q |             unpack "$AUTOINSTALL_EXE_ADE2007" "$AUTOINSTALL_DIR_LIN/ADE2007" | ||||||
|                 wine_run_install "$AUTOINSTALL_EXE_WIN2" /q |             wine_run_install "$AUTOINSTALL_DIR_LIN/ADE2007/AceRedist.msi" /q | ||||||
|             fi | 
 | ||||||
|  |             wine_run_install "$AUTOINSTALL_EXE_VC_X86" /quiet | ||||||
|  |             wine_run_install "$AUTOINSTALL_EXE_VC_X64" /quiet | ||||||
|  |             wine_run_install "$AUTOINSTALL_EXE_TSC2" /q | ||||||
|  | 
 | ||||||
|             rm -fR "$DRIVE_C/Program Files/Common Files/System" |             rm -fR "$DRIVE_C/Program Files/Common Files/System" | ||||||
|             rm -fR "$DRIVE_C/Program Files (x86)/Common Files/System" |             rm -fR "$DRIVE_C/Program Files (x86)/Common Files/System" | ||||||
| 
 | 
 | ||||||
| @@ -74,9 +67,9 @@ else | |||||||
|             mv -f "$AUTOINSTALL_DIR_LIN/Components/Windows/System32/"*.dll \ |             mv -f "$AUTOINSTALL_DIR_LIN/Components/Windows/System32/"*.dll \ | ||||||
|                   "$DRIVE_C/windows/system32" |                   "$DRIVE_C/windows/system32" | ||||||
| 
 | 
 | ||||||
|  |             "$WINELOADER" regedit "$AUTOINSTALL_DIR_LIN/Components/fake_hasp.reg" | ||||||
|             "$WINELOADER" regedit "$AUTOINSTALL_DIR_LIN/Components/ado-32.reg" |             "$WINELOADER" regedit "$AUTOINSTALL_DIR_LIN/Components/ado-32.reg" | ||||||
|             "$WINELOADER"64 regedit "$AUTOINSTALL_DIR_LIN/Components/ado-64.reg" |             "$WINELOADER" regedit "$AUTOINSTALL_DIR_LIN/Components/ado-64.reg" | ||||||
|             "$WINELOADER" regedit "$AUTOINSTALL_DIR_LIN/Components/tflex.reg" |  | ||||||
|         fi |         fi | ||||||
| 
 | 
 | ||||||
|         if systemctl list-units --type service --state running | grep aksusbd \ |         if systemctl list-units --type service --state running | grep aksusbd \ | ||||||
| @@ -98,14 +91,12 @@ else | |||||||
|     fi |     fi | ||||||
| 
 | 
 | ||||||
|     try_remove_dir "$AUTOINSTALL_DIR_LIN" |     try_remove_dir "$AUTOINSTALL_DIR_LIN" | ||||||
|     try_remove_dir "$AUTOINSTALL_DIR_WIN" |  | ||||||
| 
 | 
 | ||||||
|     if [[ $TFLEX_ERROR == "1" ]] ; then |     if [[ $TFLEX_ERROR == "1" ]] ; then | ||||||
|         fatal "Произошла ошибка во время подготовки префикса, или установки компонентов ПО." |         fatal "Произошла ошибка во время подготовки префикса, или установки компонентов ПО." | ||||||
|     else |     else | ||||||
|         echo "t-flex-cad-prepair" >> "$WINEPREFIX/winetricks.log" |         echo "t-flex-cad-prepair" >> "$WINEPREFIX/winetricks.log" | ||||||
|         try_remove_file "$AUTOINSTALL_ZIP_LIN" | #         try_remove_file "$AUTOINSTALL_ZIP_LIN" | ||||||
|         try_remove_file "$AUTOINSTALL_ZIP_WIN" |  | ||||||
|         print_info "Подготовка префикса и установка компонентов завершены." |         print_info "Подготовка префикса и установка компонентов завершены." | ||||||
|     fi |     fi | ||||||
| fi | fi | ||||||
							
								
								
									
										
											BIN
										
									
								
								image/handbook/auto_install.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 184 KiB | 
							
								
								
									
										
											BIN
										
									
								
								image/handbook/create_prefix.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 153 KiB | 
							
								
								
									
										
											BIN
										
									
								
								image/handbook/election_installed.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 110 KiB | 
							
								
								
									
										
											BIN
										
									
								
								image/handbook/help.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 91 KiB | 
							
								
								
									
										
											BIN
										
									
								
								image/handbook/info.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 227 KiB | 
							
								
								
									
										
											BIN
										
									
								
								image/handbook/installed.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 133 KiB | 
							
								
								
									
										
											BIN
										
									
								
								image/handbook/license_agreement.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 236 KiB | 
							
								
								
									
										
											BIN
										
									
								
								image/handbook/log.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 336 KiB | 
							
								
								
									
										
											BIN
										
									
								
								image/handbook/manual_install.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 110 KiB | 
							
								
								
									
										
											BIN
										
									
								
								image/handbook/manual_install_1.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 144 KiB | 
							
								
								
									
										
											BIN
										
									
								
								image/handbook/prefix_manager.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 160 KiB | 
							
								
								
									
										
											BIN
										
									
								
								image/handbook/search.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 93 KiB | 
							
								
								
									
										
											BIN
										
									
								
								image/nettest_client.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 2.9 KiB | 
							
								
								
									
										
											BIN
										
									
								
								image/nettest_server.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 4.7 KiB | 
							
								
								
									
										39
									
								
								manualinstall/nettest
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,39 @@ | |||||||
|  | #!/usr/bin/env bash | ||||||
|  | # info_ru: Установщик программного комплекса NetTest (демо-версия) | ||||||
|  | ######################################################################## | ||||||
|  | export PROG_URL="https://www.kpolyakov.spb.ru/prog/nettest/nettget.htm" | ||||||
|  | export WH_WINE_USE="wine_x_tkg_10-0_amd64" | ||||||
|  | export WINEPREFIX="nettest" | ||||||
|  | export PROG_NAME="NetTest" | ||||||
|  | export BASE_PFX="none" | ||||||
|  | export WINEARCH="win64" | ||||||
|  | export INSTALL_DLL="" | ||||||
|  | export WH_WINDOWS_VER="10" | ||||||
|  |  | ||||||
|  | ZIP_FILE="$2" | ||||||
|  |  | ||||||
|  | if [[ -f "$ZIP_FILE" ]] \ | ||||||
|  | && [[ $ZIP_FILE =~ ".zip" ]] | ||||||
|  | then | ||||||
|  |     prepair_wine | ||||||
|  |     PROG_PATH="$DRIVE_C/nettest" | ||||||
|  |     if [[ $ZIP_FILE =~ "tests" ]] ; then | ||||||
|  |         unpack "$2" "$PROG_PATH/tests" | ||||||
|  |         print_info "Тесты $(basename "$ZIP_FILE") установлены." | ||||||
|  |         exit 0 | ||||||
|  |     else | ||||||
|  |         unpack "$2" "$PROG_PATH" | ||||||
|  |     fi | ||||||
|  |  | ||||||
|  |     cp -fr "$PROG_PATH/fonts/"* "$DRIVE_C/windows/Fonts/" | ||||||
|  |  | ||||||
|  |     create_desktop "$PROG_NAME (Сервер)" "$PROG_PATH/testser.exe" "nettest_server" | ||||||
|  |     create_desktop "$PROG_NAME (Клиент)" "$PROG_PATH/testcli.exe" "nettest_client" | ||||||
|  | else | ||||||
|  |     fatal "Не найден файл архива для $PROG_NAME. Перезапустите по примеру: | ||||||
|  |     winehelper install $1 \"/путь/до/архива\"" | ||||||
|  | fi | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
							
								
								
									
										23
									
								
								manualinstall/t-flex-cad-manual
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,23 @@ | |||||||
|  | #!/usr/bin/env bash | ||||||
|  | # info_ru: Ручная установка дополнений для T-FLEX DOCS 17 или 18 | ||||||
|  | ######################################################################## | ||||||
|  | export PROG_NAME="T-FLEX CAD 17/18" | ||||||
|  | export PROG_ICON="tflexcad" | ||||||
|  | export WH_WINE_USE="wine_wh_tflex_10-9_amd64" | ||||||
|  | export BASE_PFX="tflex_pfx_x64_v03" | ||||||
|  | export WINEARCH="win64" | ||||||
|  | export WH_WINDOWS_VER="10" | ||||||
|  | export WINEPREFIX="tflex" | ||||||
|  | export WH_XDG_OPEN="log" | ||||||
|  | export WH_USE_MESA_GL_OVERRIDE="1" | ||||||
|  |  | ||||||
|  | if [[ -f "$2" ]] ; then | ||||||
|  |     # используем общий whdb файл для подготовки префикса и сервисов | ||||||
|  |     # prepair_wine используется из файла настроек | ||||||
|  |     source "$WH_DB_DIR/t-flex-cad.whdb" | ||||||
|  |  | ||||||
|  |     wine_run_install "$2" | ||||||
|  | else | ||||||
|  |     fatal "Не найден файл установки. Перезапустите по примеру: | ||||||
|  |     winehelper install $1 \"/путь/до/файла\"" | ||||||
|  | fi | ||||||
| @@ -1,10 +1,10 @@ | |||||||
| #!/usr/bin/env bash | #!/usr/bin/env bash | ||||||
| # info_ru: Ручная установка дополнений для T-FLEX CAD 17 | # info_ru: Ручная установка дополнений для T-FLEX CAD 17 или 18 | ||||||
| ######################################################################## | ######################################################################## | ||||||
| export PROG_NAME="T-FLEX CAD 17" | export PROG_NAME="T-FLEX CAD 17/18" | ||||||
| export PROG_ICON="tflexcad" | export PROG_ICON="tflexcad" | ||||||
| export WH_WINE_USE="wine_wh_tflex_10-9_amd64" | export WH_WINE_USE="wine_wh_tflex_10-9_amd64" | ||||||
| export BASE_PFX="tflex17_pfx_x64_v02" | export BASE_PFX="tflex_pfx_x64_v03" | ||||||
| export WINEARCH="win64" | export WINEARCH="win64" | ||||||
| export WH_WINDOWS_VER="10" | export WH_WINDOWS_VER="10" | ||||||
| export WINEPREFIX="tflex" | export WINEPREFIX="tflex" | ||||||
| @@ -14,7 +14,7 @@ export WH_USE_MESA_GL_OVERRIDE="1" | |||||||
| if [[ -f "$2" ]] ; then | if [[ -f "$2" ]] ; then | ||||||
|     # используем общий whdb файл для подготовки префикса и сервисов |     # используем общий whdb файл для подготовки префикса и сервисов | ||||||
|     # prepair_wine используется из файла настроек |     # prepair_wine используется из файла настроек | ||||||
|     source "$WH_DB_DIR/t-flex-cad17.whdb" |     source "$WH_DB_DIR/t-flex-cad.whdb" | ||||||
| 
 | 
 | ||||||
|     wine_run_install "$2" |     wine_run_install "$2" | ||||||
| else | else | ||||||
| @@ -5,6 +5,7 @@ | |||||||
| fb7fdfde96de10a1b3b051bdf2727b6a7c1768b878483726454dd6726e9e0193  wine-9.0.14-alt1-i586-spravkibk.tar.xz | fb7fdfde96de10a1b3b051bdf2727b6a7c1768b878483726454dd6726e9e0193  wine-9.0.14-alt1-i586-spravkibk.tar.xz | ||||||
| e0a84bb4908c3927954d7eef6b8ac7212e442b8c107d000c6890fec340f96183  wine-9.0.14-alt1-amd64.tar.xz | e0a84bb4908c3927954d7eef6b8ac7212e442b8c107d000c6890fec340f96183  wine-9.0.14-alt1-amd64.tar.xz | ||||||
| 6f86d2220b65b709bf88c6f829a4998de3b929cc2091cd1333a51c32e1491b79  wine-9.0.9-alt1-i586.tar.xz | 6f86d2220b65b709bf88c6f829a4998de3b929cc2091cd1333a51c32e1491b79  wine-9.0.9-alt1-i586.tar.xz | ||||||
|  | f1bf1261550ca2928cefacdb724926d3d6d103433d0ff6882ee9783a50d8f4e4  wine-8.8-staging-amd64.tar.xz | ||||||
| 61bec1230b37b8fcc69fd45f848b44fd88cc41fcdd5dc3080336d7da63660f40  wine-7.16.1-alt1-amd64.tar.xz | 61bec1230b37b8fcc69fd45f848b44fd88cc41fcdd5dc3080336d7da63660f40  wine-7.16.1-alt1-amd64.tar.xz | ||||||
| 6fea17fd131f57c2ebf7ca4c60d3c5a9e819afe16e5d0b77ecb750da99ae0e38  wine-7.16.1-alt1-i586.tar.xz | 6fea17fd131f57c2ebf7ca4c60d3c5a9e819afe16e5d0b77ecb750da99ae0e38  wine-7.16.1-alt1-i586.tar.xz | ||||||
|  |  | ||||||
| @@ -170,13 +171,9 @@ d62225f6a23e49355a59a2bd9a495390694bd70d4be6d6527cfb7fb2e2d65f0d  defpfx_x64_v01 | |||||||
| # create with wine_x_tkg_10-0_amd64 (universal user: xuser and isolate_home by default) | # create with wine_x_tkg_10-0_amd64 (universal user: xuser and isolate_home by default) | ||||||
| # winetricks msxml3 msxml4 msxml6 andale arial comicsans courier georgia impact times trebuchet verdana webdings corefonts wsh57 vcrun6 gdiplus lucida tahoma ucrtbase2019 vcrun2019 dotnet40 dotnet48 dotnet20sp2 d3dcompiler_47 | # winetricks msxml3 msxml4 msxml6 andale arial comicsans courier georgia impact times trebuchet verdana webdings corefonts wsh57 vcrun6 gdiplus lucida tahoma ucrtbase2019 vcrun2019 dotnet40 dotnet48 dotnet20sp2 d3dcompiler_47 | ||||||
|  |  | ||||||
| f4cb2f380ad8887f334c6eb3c272b343ae8de327764945266e9e74f8acbac69f  tflex17_pfx_x64_v01.tar.xz | 68ad589a3e6d8a845c2e3bd4c2672cf97982b3fea0ca4b4f2fb6da126d8b3075  tflex_pfx_x64_v03.tar.xz | ||||||
| # create with wine_x_tkg_10-0_amd64 (universal user: xuser) |  | ||||||
| # winetricks isolate_home msxml6 ipamona opensymbol wenquanyi ucrtbase2019 uff unifont droid wenquanyizenhei remove_mono internal dotnet40 dotnet48 dotnet20sp2 eufonts takao d3dcompiler_47 fontsmooth=rgb vcrun2022 vlgothic andale arial comicsans courier georgia impact times trebuchet verdana webdings corefonts liberation sourcehansans baekmuk tahoma lucida |  | ||||||
|  |  | ||||||
| be09f25bb795c5f912fad2d122c68c8aed937821255f161c2d75a4773d11a044  tflex17_pfx_x64_v02.tar.xz |  | ||||||
| # create with wine_wh_tflex_10-9_amd64 | # create with wine_wh_tflex_10-9_amd64 | ||||||
| # winetricks isolate_home msxml6 ipamona opensymbol wenquanyi ucrtbase2019 uff unifont droid wenquanyizenhei remove_mono internal dotnet40 dotnet48 dotnet20 eufonts takao d3dcompiler_47 fontsmooth=rgb vcrun2022 vlgothic andale arial comicsans courier georgia impact times trebuchet verdana webdings corefonts liberation sourcehansans baekmuk tahoma lucida | # winetricks isolate_home msxml6 ipamona opensymbol wenquanyi ucrtbase2019 uff unifont droid wenquanyizenhei internal dotnet48 dotnet20 eufonts takao d3dcompiler_47 fontsmooth=rgb vcrun2019 vlgothic andale arial comicsans courier georgia impact times trebuchet verdana webdings corefonts liberation sourcehansans baekmuk tahoma lucida t-flex-cad-prepair | ||||||
|  |  | ||||||
| 7edbd69b40b8ca3fb3594933c6cd37030180c494c08fd13cbd1a5b46565d65e6  ved_ctm_pfx_x86_v03.tar.xz | 7edbd69b40b8ca3fb3594933c6cd37030180c494c08fd13cbd1a5b46565d65e6  ved_ctm_pfx_x86_v03.tar.xz | ||||||
| # create with wine_x_tkg_10-0_amd64 (universal user: xuser) | # create with wine_x_tkg_10-0_amd64 (universal user: xuser) | ||||||
| @@ -211,8 +208,8 @@ dfb44ce5e5af7dba1686932c63d6b05e5dd6919a21c78130a7d1d0271b93958e  audiorecstatio | |||||||
| # create with wine_x_tkg_10-0_i586 (universal user: xuser) | # create with wine_x_tkg_10-0_i586 (universal user: xuser) | ||||||
| # winetricks arial dotnet7 dotnetdesktop7 renderer=gdi | # winetricks arial dotnet7 dotnetdesktop7 renderer=gdi | ||||||
|  |  | ||||||
| 25e277c7afa4a9afc5f013cb05f872c12a7f381c4f0503a423dcacccca9a14c6  scadaoffice_pfx_x64_v03.tar.xz | 4fa93434c5c15440014357323257ddcee7d28b94ad6a56bd6f5a08b33ae4c3cb  scadaoffice_pfx_x64_v04.tar.xz | ||||||
| # create with wine_x_tkg_10-0_i586 (universal user: xuser) | # create with wine-8.8-staging-amd64 | ||||||
| # winetricks dotnet48 gdiplus vcrun6sp6 vcrun2005 vcrun2019 d3dx11_42 d3dx11_43 d3dx9 d3dcompiler_42 d3dcompiler_43 d3dcompiler_46 d3dcompiler_47 richtx32 riched30 riched20 msxml6 dotnet20 | # winetricks dotnet48 gdiplus vcrun6sp6 vcrun2005 vcrun2019 d3dx11_42 d3dx11_43 d3dx9 d3dcompiler_42 d3dcompiler_43 d3dcompiler_46 d3dcompiler_47 richtx32 riched30 riched20 msxml6 dotnet20 | ||||||
| # + addons with ODBC, SSH, *.reg | # + addons with ODBC, SSH, *.reg | ||||||
| 0f4ef434df07bc338ae308af44330590eaa1d9c94b64850514e55b960642d0eb  scadoffice_addons_v02.tar.xz | 0f4ef434df07bc338ae308af44330590eaa1d9c94b64850514e55b960642d0eb  scadoffice_addons_v02.tar.xz | ||||||
|   | |||||||
							
								
								
									
										148
									
								
								winehelper
									
									
									
									
									
								
							
							
						
						| @@ -16,7 +16,7 @@ if [[ "$(realpath "$0")" == "/usr/bin/$SCRIPT_NAME" ]] ; then | |||||||
|     USER_WORK_PATH="$HOME/.local/share/$SCRIPT_NAME" |     USER_WORK_PATH="$HOME/.local/share/$SCRIPT_NAME" | ||||||
|     RUN_SCRIPT="/usr/bin/$SCRIPT_NAME" |     RUN_SCRIPT="/usr/bin/$SCRIPT_NAME" | ||||||
|     DATA_PATH="/usr/share/$SCRIPT_NAME" |     DATA_PATH="/usr/share/$SCRIPT_NAME" | ||||||
|     WH_ICON_PATH="$DATA_PATH/image/gui/winehelper.svg" |     WH_ICON_PATH="/usr/share/icons/hicolor/scalable/apps/winehelper.svg" | ||||||
|     CHANGELOG_FILE="/usr/share/doc/winehelper-$WH_VERSION/CHANGELOG" |     CHANGELOG_FILE="/usr/share/doc/winehelper-$WH_VERSION/CHANGELOG" | ||||||
|     LICENSE_FILE="/usr/share/doc/winehelper-$WH_VERSION/LICENSE" |     LICENSE_FILE="/usr/share/doc/winehelper-$WH_VERSION/LICENSE" | ||||||
|     AGREEMENT="/usr/share/doc/winehelper-$WH_VERSION/LICENSE_AGREEMENT" |     AGREEMENT="/usr/share/doc/winehelper-$WH_VERSION/LICENSE_AGREEMENT" | ||||||
| @@ -126,6 +126,12 @@ WH_TESTINSTALL_DIR="$DATA_PATH/testinstall" | |||||||
| WH_WINETRICKS="$DATA_PATH/winetricks_$WINETRICKS_VERSION" | WH_WINETRICKS="$DATA_PATH/winetricks_$WINETRICKS_VERSION" | ||||||
|  |  | ||||||
| WH_MENU_DIR="$HOME/.local/share/applications/WineHelper" | WH_MENU_DIR="$HOME/.local/share/applications/WineHelper" | ||||||
|  |  | ||||||
|  | # TODO: system menu directory | ||||||
|  | # /usr/share/desktop-directories/WineHelper.directory | ||||||
|  | # /etc/xdg/menus/applications-merged/WineHelper.menu | ||||||
|  |  | ||||||
|  | # user menu directory | ||||||
| WH_MENU_CATEGORY="$HOME/.local/share/desktop-directories/WineHelper.directory" | WH_MENU_CATEGORY="$HOME/.local/share/desktop-directories/WineHelper.directory" | ||||||
| WH_MENU_CONFIG="$HOME/.config/menus/applications-merged/WineHelper.menu" | WH_MENU_CONFIG="$HOME/.config/menus/applications-merged/WineHelper.menu" | ||||||
|  |  | ||||||
| @@ -162,12 +168,10 @@ check_variables WINE_WIN_START "start /wait /high /unix" | |||||||
|  |  | ||||||
| check_variables WINE_CPU_TOPOLOGY "8" | check_variables WINE_CPU_TOPOLOGY "8" | ||||||
|  |  | ||||||
| check_variables USE_RENDERER "opengl" # opengl, damavand, proton | check_variables DXVK_VER "none" | ||||||
|  |  | ||||||
| check_variables DXVK_VER "1.10.3-28" |  | ||||||
| # check_variables DXVK_CONFIG_FILE "path/to/dxvk.conf" | # check_variables DXVK_CONFIG_FILE "path/to/dxvk.conf" | ||||||
|  |  | ||||||
| check_variables VKD3D_VER "1.1-2602" | check_variables VKD3D_VER "none" | ||||||
| # check_variables VKD3D_LIMIT_TESS_FACTORS 64 | # check_variables VKD3D_LIMIT_TESS_FACTORS 64 | ||||||
| # check_variables VKD3D_FEATURE_LEVEL "12_0" | # check_variables VKD3D_FEATURE_LEVEL "12_0" | ||||||
|  |  | ||||||
| @@ -395,11 +399,15 @@ print_license_agreement () { | |||||||
| } | } | ||||||
|  |  | ||||||
| try_download () { | try_download () { | ||||||
|  |     if [[ $1 != "cloud" ]] ; then | ||||||
|         if [[ $WH_USE_GUI == "1" ]] \ |         if [[ $WH_USE_GUI == "1" ]] \ | ||||||
|         && [[ $(ps -o command= -p "$PPID" | awk '{print $2}') =~ "$DATA_PATH/winehelper_gui.py" ]] |         && [[ $(ps -o command= -p "$PPID" | awk '{print $2}') =~ "$DATA_PATH/winehelper_gui.py" ]] | ||||||
|         then print_ok "Соглашения приняты из графического интерфейса." |         then print_ok "Соглашения приняты из графического интерфейса." | ||||||
|         else print_license_agreement |         else print_license_agreement | ||||||
|         fi |         fi | ||||||
|  |     else | ||||||
|  |         shift | ||||||
|  |     fi | ||||||
|     local download_file_url output_file output_file_name |     local download_file_url output_file output_file_name | ||||||
|     download_file_url="${1// /%20}" |     download_file_url="${1// /%20}" | ||||||
|     output_file="$2" |     output_file="$2" | ||||||
| @@ -694,9 +702,11 @@ EOF | |||||||
|             echo '#!/usr/bin/env bash' |             echo '#!/usr/bin/env bash' | ||||||
|             echo "# cmd_name: $INSTALL_SCRIPT_NAME" |             echo "# cmd_name: $INSTALL_SCRIPT_NAME" | ||||||
|         } > "$exe_file".whdb |         } > "$exe_file".whdb | ||||||
|         grep -e "info_" -e "#####" -e "export" -e "var_" "$INSTALL_SCRIPT" \ |  | ||||||
|         | grep -vE "LAUNCH_PARAMETERS|AUTOINSTALL|WIN_FILE_EXEC|echo" \ |         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 |         | awk '{$1=$1;print}' >> "$exe_file".whdb | ||||||
|  |  | ||||||
|         print_info "Создан файл настроек для $exe_file" |         print_info "Создан файл настроек для $exe_file" | ||||||
|     fi |     fi | ||||||
| } | } | ||||||
| @@ -760,31 +770,25 @@ run_installed_programs () { | |||||||
|     fi |     fi | ||||||
| } | } | ||||||
|  |  | ||||||
| init_wined3d () { | copy_wined3d () { | ||||||
|     if [[ "$USE_RENDERER" != "proton" ]] ; then |     for wined3dfiles in $1 ; do | ||||||
|         WINED3D_FILES="d3d8 d3d9 d3d10_1 d3d10 d3d10core d3d11 dxgi d3d12 d3d12core" |  | ||||||
|         for wined3dfiles in $WINED3D_FILES ; do |  | ||||||
|         try_copy_wine_dll_to_pfx_64 "$wined3dfiles.dll" |         try_copy_wine_dll_to_pfx_64 "$wined3dfiles.dll" | ||||||
|         try_copy_wine_dll_to_pfx_32 "$wined3dfiles.dll" |         try_copy_wine_dll_to_pfx_32 "$wined3dfiles.dll" | ||||||
|     done |     done | ||||||
| #         if [[ "$USE_RENDERER" == "damavand" ]] |  | ||||||
| #         then export WINE_D3D_CONFIG="renderer=vulkan" |  | ||||||
| #         else export WINE_D3D_CONFIG="renderer=gl" |  | ||||||
| #         fi |  | ||||||
|         return 0 |  | ||||||
|     else |  | ||||||
|         return 1 |  | ||||||
|     fi |  | ||||||
| } | } | ||||||
|  |  | ||||||
| init_dxvk () { | init_dxvk () { | ||||||
|     check_variables USE_DXVK_VER "$1" |     DXVK_VER="$1" | ||||||
|  |     if [[ $DXVK_VER == "none" ]] ; then | ||||||
|  |         copy_wined3d "d3d8 d3d9 d3d10_1 d3d10 d3d10core d3d11 dxgi" | ||||||
|  |         return 0 | ||||||
|  |     fi | ||||||
|  |  | ||||||
|     get_dxvk() { |     get_dxvk() { | ||||||
|         local DXVK_URL="$1" |         local DXVK_URL="$1" | ||||||
|         local DXVK_VAR_VER="$2" |         local DXVK_VAR_VER="$2" | ||||||
|         local DXVK_PACKAGE="${WH_VULKAN_LIBDIR}/${DXVK_VAR_VER}.tar.$(echo "${DXVK_URL#*.tar.}")" |         local DXVK_PACKAGE="${WH_VULKAN_LIBDIR}/${DXVK_VAR_VER}.tar.$(echo "${DXVK_URL#*.tar.}")" | ||||||
|         if try_download "$DXVK_URL" "$DXVK_PACKAGE" check256sum \ |         if try_download cloud "$DXVK_URL" "$DXVK_PACKAGE" check256sum \ | ||||||
|         && unpack "$DXVK_PACKAGE" "$WH_VULKAN_LIBDIR" |         && unpack "$DXVK_PACKAGE" "$WH_VULKAN_LIBDIR" | ||||||
|         then |         then | ||||||
|             try_remove_file "$DXVK_PACKAGE" |             try_remove_file "$DXVK_PACKAGE" | ||||||
| @@ -793,36 +797,37 @@ init_dxvk () { | |||||||
|         return 1 |         return 1 | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     for DXVK_VAR_VER in "$USE_DXVK_VER" $@ ; do |     if [[ ! -d "${WH_VULKAN_LIBDIR}/${DXVK_VER}" ]] ; then | ||||||
|         if [[ ! -d "${WH_VULKAN_LIBDIR}/${DXVK_VAR_VER}" ]] ; then |         get_dxvk "$CLOUD_URL/${DXVK_VER}.tar.xz" "$DXVK_VER" | ||||||
|             get_dxvk "$CLOUD_URL/${DXVK_VAR_VER}.tar.xz" "$DXVK_VAR_VER" |  | ||||||
|     fi |     fi | ||||||
|     done |  | ||||||
|  |  | ||||||
|     if [[ "${WH_USE_WINE_DXGI}" == 1 ]] ; then |     if [[ $WH_USE_WINE_DXGI == "1" ]] ; then | ||||||
|         DXVK_FILES="d3d9 d3d10_1 d3d10 d3d11" # dxvk_config openvr_api_dxvk" |         DXVK_FILES="d3d9 d3d10_1 d3d10 d3d11" # dxvk_config openvr_api_dxvk" | ||||||
|         try_copy_wine_dll_to_pfx_64 "dxgi.dll" |         copy_wined3d "dxgi" | ||||||
|         try_copy_wine_dll_to_pfx_32 "dxgi.dll" |  | ||||||
|     else |     else | ||||||
|         DXVK_FILES="d3d9 d3d10_1 d3d10 d3d11 dxgi" # dxvk_config openvr_api_dxvk" |         DXVK_FILES="d3d9 d3d10_1 d3d10 d3d11 dxgi" # dxvk_config openvr_api_dxvk" | ||||||
|     fi |     fi | ||||||
|  |  | ||||||
|     for dxvkfiles in $DXVK_FILES ; do |     for dxvkfiles in $DXVK_FILES ; do | ||||||
|         try_copy_other_dll_to_pfx_64 "${WH_VULKAN_LIBDIR}/${USE_DXVK_VER}/x64/$dxvkfiles.dll" |         try_copy_other_dll_to_pfx_64 "${WH_VULKAN_LIBDIR}/${DXVK_VER}/x64/$dxvkfiles.dll" | ||||||
|         if try_copy_other_dll_to_pfx_32 "${WH_VULKAN_LIBDIR}/${USE_DXVK_VER}/x32/$dxvkfiles.dll" |         if try_copy_other_dll_to_pfx_32 "${WH_VULKAN_LIBDIR}/${DXVK_VER}/x32/$dxvkfiles.dll" | ||||||
|         then var_winedlloverride_update "$dxvkfiles=n" |         then var_winedlloverride_update "$dxvkfiles=n" | ||||||
|         fi |         fi | ||||||
|     done |     done | ||||||
| } | } | ||||||
|  |  | ||||||
| init_vkd3d () { | init_vkd3d () { | ||||||
|     check_variables USE_VKD3D_VER "$1" |     VKD3D_VER="$1" | ||||||
|  |     if [[ $VKD3D_VER == "none" ]] ; then | ||||||
|  |         copy_wined3d "d3d12 d3d12core" | ||||||
|  |         return 0 | ||||||
|  |     fi | ||||||
|  |  | ||||||
|     get_vkd3d() { |     get_vkd3d() { | ||||||
|         local VKD3D_URL="$1" |         local VKD3D_URL="$1" | ||||||
|         local VKD3D_VAR_VER="$2" |         local VKD3D_VAR_VER="$2" | ||||||
|         local VKD3D_PACKAGE="${WH_VULKAN_LIBDIR}/${VKD3D_VAR_VER}.tar.$(echo "${VKD3D_URL#*.tar.}")" |         local VKD3D_PACKAGE="${WH_VULKAN_LIBDIR}/${VKD3D_VAR_VER}.tar.$(echo "${VKD3D_URL#*.tar.}")" | ||||||
|         if try_download "$VKD3D_URL" "$VKD3D_PACKAGE" check256sum \ |         if try_download cloud "$VKD3D_URL" "$VKD3D_PACKAGE" check256sum \ | ||||||
|         && unpack "$VKD3D_PACKAGE" "$WH_VULKAN_LIBDIR" |         && unpack "$VKD3D_PACKAGE" "$WH_VULKAN_LIBDIR" | ||||||
|         then |         then | ||||||
|             try_remove_file "$VKD3D_PACKAGE" |             try_remove_file "$VKD3D_PACKAGE" | ||||||
| @@ -831,16 +836,14 @@ init_vkd3d () { | |||||||
|         return 1 |         return 1 | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     for VKD3D_VAR_VER in "$USE_VKD3D_VER" $@ ; do |     if [[ ! -d "${WH_VULKAN_LIBDIR}/${VKD3D_VER}" ]] ; then | ||||||
|         if [[ ! -d "${WH_VULKAN_LIBDIR}/${VKD3D_VAR_VER}" ]] ; then |         get_vkd3d "$CLOUD_URL/${VKD3D_VER}.tar.xz" "$VKD3D_VER" | ||||||
|             get_vkd3d "$CLOUD_URL/${VKD3D_VAR_VER}.tar.xz" "$VKD3D_VAR_VER" |  | ||||||
|     fi |     fi | ||||||
|     done |  | ||||||
|  |  | ||||||
|     VKD3D_FILES="d3d12 d3d12core libvkd3d-shader-1 libvkd3d-1" # libvkd3d-proton-utils-3 |     VKD3D_FILES="d3d12 d3d12core libvkd3d-shader-1 libvkd3d-1" # libvkd3d-proton-utils-3 | ||||||
|     for vkd3dfiles in $VKD3D_FILES ; do |     for vkd3dfiles in $VKD3D_FILES ; do | ||||||
|         try_copy_other_dll_to_pfx_64 "${WH_VULKAN_LIBDIR}/${USE_VKD3D_VER}/x64/$vkd3dfiles.dll" |         try_copy_other_dll_to_pfx_64 "${WH_VULKAN_LIBDIR}/${VKD3D_VER}/x64/$vkd3dfiles.dll" | ||||||
|         if try_copy_other_dll_to_pfx_32 "${WH_VULKAN_LIBDIR}/${USE_VKD3D_VER}/x86/$vkd3dfiles.dll" |         if try_copy_other_dll_to_pfx_32 "${WH_VULKAN_LIBDIR}/${VKD3D_VER}/x86/$vkd3dfiles.dll" | ||||||
|         then var_winedlloverride_update "$vkd3dfiles=n" |         then var_winedlloverride_update "$vkd3dfiles=n" | ||||||
|         fi |         fi | ||||||
|     done |     done | ||||||
| @@ -855,7 +858,7 @@ init_wine_ver () { | |||||||
|             download_url="$CLOUD_URL/$WH_WINE_USE.tar.xz" |             download_url="$CLOUD_URL/$WH_WINE_USE.tar.xz" | ||||||
|             wine_package="$WH_TMP_DIR/$WH_WINE_USE.tar.xz" |             wine_package="$WH_TMP_DIR/$WH_WINE_USE.tar.xz" | ||||||
|  |  | ||||||
|             try_download "$download_url" "$wine_package" "check256sum" |             try_download cloud "$download_url" "$wine_package" "check256sum" | ||||||
|             unpack "$wine_package" "$WH_DIST_DIR/" |             unpack "$wine_package" "$WH_DIST_DIR/" | ||||||
|             try_remove_file "$wine_package" |             try_remove_file "$wine_package" | ||||||
|  |  | ||||||
| @@ -908,7 +911,7 @@ init_wine_ver () { | |||||||
|             CPCSP_PROXY_NAME="wine-cpcsp_proxy-$CPCSP_PROXY_VER" |             CPCSP_PROXY_NAME="wine-cpcsp_proxy-$CPCSP_PROXY_VER" | ||||||
|             CPCSP_PROXY_URL="$CLOUD_URL/$CPCSP_PROXY_NAME.tar.xz" |             CPCSP_PROXY_URL="$CLOUD_URL/$CPCSP_PROXY_NAME.tar.xz" | ||||||
|  |  | ||||||
|             try_download "$CPCSP_PROXY_URL" "$WH_TMP_DIR/$CPCSP_PROXY_NAME.tar.xz" check256sum |             try_download cloud "$CPCSP_PROXY_URL" "$WH_TMP_DIR/$CPCSP_PROXY_NAME.tar.xz" check256sum | ||||||
|             unpack "$WH_TMP_DIR/$CPCSP_PROXY_NAME.tar.xz" "$WH_TMP_DIR" |             unpack "$WH_TMP_DIR/$CPCSP_PROXY_NAME.tar.xz" "$WH_TMP_DIR" | ||||||
|  |  | ||||||
|             cp -fr "$WH_TMP_DIR/$CPCSP_PROXY_NAME/"i386-* "$WINEDIR/lib/wine/" |             cp -fr "$WH_TMP_DIR/$CPCSP_PROXY_NAME/"i386-* "$WINEDIR/lib/wine/" | ||||||
| @@ -1111,6 +1114,11 @@ init_wineprefix () { | |||||||
|     export DRIVE_C="$WINEPREFIX/drive_c" |     export DRIVE_C="$WINEPREFIX/drive_c" | ||||||
|     export XUSER_PATH="$DRIVE_C/users/xuser" |     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 [[ ! -f "$WINEPREFIX/.firstboot" ]] ; then | ||||||
|         create_new_dir "$WINEPREFIX" |         create_new_dir "$WINEPREFIX" | ||||||
|         if [[ "$CLEAR_PREFIX" == "1" ]] |         if [[ "$CLEAR_PREFIX" == "1" ]] | ||||||
| @@ -1179,6 +1187,7 @@ init_wineprefix () { | |||||||
|     # добавление ассоциаций файлов для запуска нативного приложения из wine |     # добавление ассоциаций файлов для запуска нативного приложения из wine | ||||||
|     # пример переменной: WH_XDG_OPEN="txt doc pdf" |     # пример переменной: WH_XDG_OPEN="txt doc pdf" | ||||||
|     check_variables WH_XDG_OPEN "0" |     check_variables WH_XDG_OPEN "0" | ||||||
|  |  | ||||||
|     local WRAPPER="${WH_TMP_DIR}/wh-xdg-open.sh" |     local WRAPPER="${WH_TMP_DIR}/wh-xdg-open.sh" | ||||||
|     local XDG_OPEN_REG="Software\Classes\xdg-open\shell\open\command" |     local XDG_OPEN_REG="Software\Classes\xdg-open\shell\open\command" | ||||||
|     if [[ $WH_XDG_OPEN != "0" ]] ; then |     if [[ $WH_XDG_OPEN != "0" ]] ; then | ||||||
| @@ -1201,13 +1210,19 @@ init_wineprefix () { | |||||||
|         # добавляем новую команду xdg-open в реестр |         # добавляем новую команду xdg-open в реестр | ||||||
|         get_and_set_reg_file --add "$XDG_OPEN_REG" '@=' 'REG_SZ' "$WRAPPER %1" "system" |         get_and_set_reg_file --add "$XDG_OPEN_REG" '@=' 'REG_SZ' "$WRAPPER %1" "system" | ||||||
|  |  | ||||||
|  |         # удаляем старые ассоциации, которых нет в новом списке | ||||||
|  |         sed -i '/@="xdg-open"/d' "$WINEPREFIX/system.reg" | ||||||
|  |  | ||||||
|         # добавляем ассоциации файлов для запуска с помощью xdg-open |         # добавляем ассоциации файлов для запуска с помощью xdg-open | ||||||
|         for ext in $WH_XDG_OPEN ; do |         for ext in $WH_XDG_OPEN ; do | ||||||
|             get_and_set_reg_file --add "Software\Classes\.$ext" '@=' 'REG_SZ' "xdg-open" "system" |             get_and_set_reg_file --add "Software\Classes\.$ext" '@=' 'REG_SZ' "xdg-open" "system" | ||||||
|         done |         done | ||||||
|         print_info "Используются ассоциации с нативными приложениями для файлов: \"$WH_XDG_OPEN\"" |         print_info "Используются ассоциации с нативными приложениями для файлов: \"$WH_XDG_OPEN\"" | ||||||
|     else |     else | ||||||
|         # удаление команды xdg-open из реестра |         # удаление всех ассоциаций | ||||||
|  |         for old_ext in $old_xdg_open; do | ||||||
|  |             get_and_set_reg_file --delete "Software\Classes\.$old_ext" '@=' | ||||||
|  |         done | ||||||
|         get_and_set_reg_file --delete "$XDG_OPEN_REG" '@=' |         get_and_set_reg_file --delete "$XDG_OPEN_REG" '@=' | ||||||
|         # удаяем скрипт-обёртку |         # удаяем скрипт-обёртку | ||||||
|         try_remove_file "$WRAPPER" |         try_remove_file "$WRAPPER" | ||||||
| @@ -1269,7 +1284,7 @@ init_wineprefix () { | |||||||
|     echo "# переменные последнего использования префикса:" > "$WINEPREFIX/last.conf" |     echo "# переменные последнего использования префикса:" > "$WINEPREFIX/last.conf" | ||||||
|     for var in WH_WINE_USE BASE_PFX WINEARCH WH_WINDOWS_VER WINEESYNC WINEFSYNC \ |     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 \ |     STAGING_SHARED_MEMORY WINE_LARGE_ADDRESS_AWARE WH_USE_SHADER_CACHE WH_USE_WINE_DXGI \ | ||||||
|     WINE_CPU_TOPOLOGY USE_RENDERER DXVK_VER VKD3D_VER WH_XDG_OPEN WH_USE_MESA_GL_OVERRIDE |     WINE_CPU_TOPOLOGY DXVK_VER VKD3D_VER WH_XDG_OPEN WH_USE_MESA_GL_OVERRIDE | ||||||
|     do |     do | ||||||
|         echo "export $var=\"${!var}\"" >> "$WINEPREFIX/last.conf" |         echo "export $var=\"${!var}\"" >> "$WINEPREFIX/last.conf" | ||||||
|     done |     done | ||||||
| @@ -1319,7 +1334,8 @@ use_winetricks () { | |||||||
| } | } | ||||||
|  |  | ||||||
| kill_wine () { | kill_wine () { | ||||||
|     wine_pids=$(ls -l /proc/*/exe 2>/dev/null | grep -E 'wine(64)?-preloader|wineserver' | awk -F/ '{print $3}') |     wine_pids=$(ls -l /proc/*/exe 2>/dev/null | grep -E 'wine(64)?-preloader|wineserver' \ | ||||||
|  |     | grep "$USER_WORK_PATH" | awk -F/ '{print $3}') | ||||||
|  |  | ||||||
|     for pw_kill_pids in ${wine_pids}; do |     for pw_kill_pids in ${wine_pids}; do | ||||||
|         if ps cax | grep "${pw_kill_pids}" ; then |         if ps cax | grep "${pw_kill_pids}" ; then | ||||||
| @@ -1346,12 +1362,12 @@ init_database () { | |||||||
|     if [[ "$WHDB_FILE" != "0" ]] ; then |     if [[ "$WHDB_FILE" != "0" ]] ; then | ||||||
|         print_info "Используется файл настроек: $WHDB_FILE" |         print_info "Используется файл настроек: $WHDB_FILE" | ||||||
|         . "$WHDB_FILE" |         . "$WHDB_FILE" | ||||||
|     elif check_prefix_var && [[ -f "$WINEPREFIX/last.conf" ]] ; then |     fi | ||||||
|  |  | ||||||
|  |     if check_prefix_var && [[ -f "$WINEPREFIX/last.conf" ]] ; then | ||||||
|         print_info "Найдены настройки из предыдущего использования префикса: $WINEPREFIX" |         print_info "Найдены настройки из предыдущего использования префикса: $WINEPREFIX" | ||||||
|         cat "$WINEPREFIX/last.conf" |         cat "$WINEPREFIX/last.conf" | ||||||
|         . "$WINEPREFIX/last.conf" |         . "$WINEPREFIX/last.conf" | ||||||
|     else |  | ||||||
|         print_warning "Файл настроек не найден. Пропускаем." |  | ||||||
|     fi |     fi | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -1360,16 +1376,13 @@ prepair_wine () { | |||||||
|     then print_info "Используются настройки из скрипта установки: $INSTALL_SCRIPT_NAME" |     then print_info "Используются настройки из скрипта установки: $INSTALL_SCRIPT_NAME" | ||||||
|     else init_database |     else init_database | ||||||
|     fi |     fi | ||||||
|  |  | ||||||
|     init_wine_ver |     init_wine_ver | ||||||
|     init_wineprefix |     init_wineprefix | ||||||
|     use_winetricks |     use_winetricks | ||||||
|  |  | ||||||
|     if init_wined3d ; then |  | ||||||
|         : |  | ||||||
|     else |  | ||||||
|     init_dxvk "$DXVK_VER" |     init_dxvk "$DXVK_VER" | ||||||
|     init_vkd3d "$VKD3D_VER" |     init_vkd3d "$VKD3D_VER" | ||||||
|     fi |  | ||||||
|     [[ "$MANGOHUD" == 1 ]] && MANGOHUD_RUN="mangohud" |     [[ "$MANGOHUD" == 1 ]] && MANGOHUD_RUN="mangohud" | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -1465,6 +1478,11 @@ run_autoinstall () { | |||||||
|         echo |         echo | ||||||
|         list_install_scripts "$WH_MANUALINSTALL_DIR" "Список программ с возможностью установки из существующего дистрибутива:" |         list_install_scripts "$WH_MANUALINSTALL_DIR" "Список программ с возможностью установки из существующего дистрибутива:" | ||||||
|     elif [[ "$INSTALL_SCRIPT" != "0" ]] ; then |     elif [[ "$INSTALL_SCRIPT" != "0" ]] ; then | ||||||
|  |         if [[ $WH_USE_GUI == "1" ]] \ | ||||||
|  |         && [[ $(ps -o command= -p "$PPID" | awk '{print $2}') =~ "$DATA_PATH/winehelper_gui.py" ]] | ||||||
|  |         then print_ok "Соглашения приняты из графического интерфейса." | ||||||
|  |         else print_license_agreement | ||||||
|  |         fi | ||||||
|         source "$INSTALL_SCRIPT" "$@" |         source "$INSTALL_SCRIPT" "$@" | ||||||
|         print_info "Завершена установка $INSTALL_SCRIPT_NAME" |         print_info "Завершена установка $INSTALL_SCRIPT_NAME" | ||||||
|     else |     else | ||||||
| @@ -1813,9 +1831,9 @@ create_base_pfx () { | |||||||
|     && [[ ! -L "$users_dir/$USER" ]] |     && [[ ! -L "$users_dir/$USER" ]] | ||||||
|     then |     then | ||||||
|         if [[ -L "$users_dir/xuser" ]] |         if [[ -L "$users_dir/xuser" ]] | ||||||
|         then try_remove_dir "$users_dir/xuser/" |         then try_remove_dir "$users_dir/xuser" | ||||||
|         fi |         fi | ||||||
|         create_new_dir "$users_dir/xuser/" |         create_new_dir "$users_dir/xuser" | ||||||
|         cp -fr "$users_dir/$USER"/* "$users_dir/xuser/" |         cp -fr "$users_dir/$USER"/* "$users_dir/xuser/" | ||||||
|     fi |     fi | ||||||
|  |  | ||||||
| @@ -2150,16 +2168,14 @@ run_install_dxvk() { | |||||||
|     fi |     fi | ||||||
|     check_prefix_var |     check_prefix_var | ||||||
|     init_database |     init_database | ||||||
|  |     export DXVK_VER="$version" | ||||||
|     init_wine_ver |     init_wine_ver | ||||||
|     init_wineprefix |     init_wineprefix | ||||||
|     if [[ "$version" == "none" ]] ; then |     if [[ "$DXVK_VER" == "none" ]] | ||||||
|         print_info "Удаление DXVK..." |     then print_info "Удаление DXVK..." | ||||||
|         init_wined3d |     else print_info "Установка DXVK: $DXVK_VER" | ||||||
|         update_last_conf_var "DXVK_VER" "" |  | ||||||
|     else |  | ||||||
|         init_dxvk "$version" |  | ||||||
|         update_last_conf_var "DXVK_VER" "$USE_DXVK_VER" |  | ||||||
|     fi |     fi | ||||||
|  |     init_dxvk "$DXVK_VER" | ||||||
|     wait_wineserver |     wait_wineserver | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -2174,16 +2190,14 @@ run_install_vkd3d() { | |||||||
|     fi |     fi | ||||||
|     check_prefix_var |     check_prefix_var | ||||||
|     init_database |     init_database | ||||||
|  |     export VKD3D_VER="$version" | ||||||
|     init_wine_ver |     init_wine_ver | ||||||
|     init_wineprefix |     init_wineprefix | ||||||
|     if [[ "$version" == "none" ]] ; then |     if [[ "$VKD3D_VER" == "none" ]] | ||||||
|         print_info "Удаление VKD3D..." |     then print_info "Удаление VKD3D..." | ||||||
|         init_wined3d |     else print_info "Установка VKD3D: $VKD3D_VER" | ||||||
|         update_last_conf_var "VKD3D_VER" "" |  | ||||||
|     else |  | ||||||
|         init_vkd3d "$version" |  | ||||||
|         update_last_conf_var "VKD3D_VER" "$USE_VKD3D_VER" |  | ||||||
|     fi |     fi | ||||||
|  |     init_vkd3d "$VKD3D_VER" | ||||||
|     wait_wineserver |     wait_wineserver | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -12,9 +12,9 @@ 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, QInputDialog) |                              QListWidget, QListWidgetItem, QGridLayout, QFrame, QDialog, QTextBrowser, QInputDialog, QDialogButtonBox, QSystemTrayIcon, QMenu) | ||||||
| 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, QCursor | ||||||
| from PyQt5.QtNetwork import QLocalServer, QLocalSocket | from PyQt5.QtNetwork import QLocalServer, QLocalSocket | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -474,10 +474,9 @@ class WinetricksManagerDialog(QDialog): | |||||||
|         self.log_output.setText(self.INFO_TEXT) |         self.log_output.setText(self.INFO_TEXT) | ||||||
|         main_layout.addWidget(self.log_output) |         main_layout.addWidget(self.log_output) | ||||||
|  |  | ||||||
|         # Кнопки управления |         # Кнопки управления, выровненные по правому краю | ||||||
|         button_layout = QHBoxLayout() |         button_layout = QHBoxLayout() | ||||||
|         self.status_label = QLabel("Загрузка компонентов...") |         button_layout.addStretch(1) | ||||||
|         button_layout.addWidget(self.status_label, 1) |  | ||||||
|  |  | ||||||
|         self.apply_button = QPushButton("Применить") |         self.apply_button = QPushButton("Применить") | ||||||
|         self.apply_button.setEnabled(False) |         self.apply_button.setEnabled(False) | ||||||
| @@ -548,7 +547,6 @@ class WinetricksManagerDialog(QDialog): | |||||||
|     def load_all_categories(self): |     def load_all_categories(self): | ||||||
|         """Запускает загрузку всех категорий.""" |         """Запускает загрузку всех категорий.""" | ||||||
|         self.loading_count = len(self.categories) |         self.loading_count = len(self.categories) | ||||||
|         self.category_statuses = {name: "загрузка..." for name in self.categories.keys()} |  | ||||||
|         for internal_name in self.categories.values(): |         for internal_name in self.categories.values(): | ||||||
|             self._start_load_process(internal_name) |             self._start_load_process(internal_name) | ||||||
|  |  | ||||||
| @@ -602,13 +600,6 @@ class WinetricksManagerDialog(QDialog): | |||||||
|         process.finished.connect(partial(self._on_load_finished, category)) |         process.finished.connect(partial(self._on_load_finished, category)) | ||||||
|         process.start(self.winetricks_path, [category, "list"]) |         process.start(self.winetricks_path, [category, "list"]) | ||||||
|  |  | ||||||
|     def _update_status_label(self): |  | ||||||
|         """Обновляет текстовую метку состояния загрузки.""" |  | ||||||
|         status_parts = [] |  | ||||||
|         for name, status in self.category_statuses.items(): |  | ||||||
|             status_parts.append(f"{name}: {status}") |  | ||||||
|         self.status_label.setText(" | ".join(status_parts)) |  | ||||||
|  |  | ||||||
|     def _parse_winetricks_log(self): |     def _parse_winetricks_log(self): | ||||||
|         """Читает winetricks.log и возвращает множество установленных компонентов.""" |         """Читает winetricks.log и возвращает множество установленных компонентов.""" | ||||||
|         installed_verbs = set() |         installed_verbs = set() | ||||||
| @@ -681,22 +672,15 @@ class WinetricksManagerDialog(QDialog): | |||||||
|  |  | ||||||
|         if exit_code != 0 or exit_status != QProcess.NormalExit: |         if exit_code != 0 or exit_status != QProcess.NormalExit: | ||||||
|             error_string = process.errorString() if process else "N/A" |             error_string = process.errorString() if process else "N/A" | ||||||
|             self._log(f"--- Ошибка загрузки категории '{category}' (код: {exit_code}) ---", "red") |             self._log(f"--- Ошибка загрузки категории '{category_display_name}' (код: {exit_code}) ---", "red") | ||||||
|             self.category_statuses[category_display_name] = "ошибка" |  | ||||||
|             self._update_status_label() # Показываем ошибку в статусе |  | ||||||
|             if exit_status == QProcess.CrashExit: |             if exit_status == QProcess.CrashExit: | ||||||
|                 self._log("--- Процесс winetricks завершился аварийно. ---", "red") |                 self._log("--- Процесс winetricks завершился аварийно. ---", "red") | ||||||
|             # По умолчанию используется "Неизвестная ошибка", которая не очень полезна. |  | ||||||
|             if error_string != "Неизвестная ошибка": |             if error_string != "Неизвестная ошибка": | ||||||
|                 self._log(f"--- Системная ошибка: {error_string} ---", "red") |                 self._log(f"--- Системная ошибка: {error_string} ---", "red") | ||||||
|             self._log(output if output.strip() else "Winetricks не вернул вывод. Проверьте, что он работает корректно.") |             self._log(output if output.strip() else "Winetricks не вернул вывод. Проверьте, что он работает корректно.") | ||||||
|             self._log("--------------------------------------------------", "red") |             self._log("--------------------------------------------------", "red") | ||||||
|         else: |         else: | ||||||
|             self.category_statuses[category_display_name] = "готово" |  | ||||||
|             installed_verbs = self._parse_winetricks_log() |             installed_verbs = self._parse_winetricks_log() | ||||||
|             # Обновляем статус только если это была сетевая загрузка |  | ||||||
|             if from_cache is None: |  | ||||||
|                 self._update_status_label() |  | ||||||
|             found_items = self._parse_winetricks_list_output(output, installed_verbs, list_widget) |             found_items = self._parse_winetricks_list_output(output, installed_verbs, list_widget) | ||||||
|  |  | ||||||
|             if from_cache is None:  # Только если мы не читали из кэша |             if from_cache is None:  # Только если мы не читали из кэша | ||||||
| @@ -721,7 +705,6 @@ class WinetricksManagerDialog(QDialog): | |||||||
|  |  | ||||||
|         self.loading_count -= 1 |         self.loading_count -= 1 | ||||||
|         if self.loading_count == 0: |         if self.loading_count == 0: | ||||||
|             self.status_label.setText("Готово.") |  | ||||||
|             self._update_ui_state() |             self._update_ui_state() | ||||||
|  |  | ||||||
|     def _on_item_changed(self, item): |     def _on_item_changed(self, item): | ||||||
| @@ -862,11 +845,6 @@ class WinetricksManagerDialog(QDialog): | |||||||
|  |  | ||||||
|         # 3. Обрабатываем успех |         # 3. Обрабатываем успех | ||||||
|         self._log("\n=== Все операции успешно завершены ===") |         self._log("\n=== Все операции успешно завершены ===") | ||||||
|         self._show_message_box("Успех", |  | ||||||
|                                "Операции с компонентами были успешно выполнены.", |  | ||||||
|                                QMessageBox.Information, |  | ||||||
|                                {"buttons": {"Да": QMessageBox.AcceptRole}}) |  | ||||||
|  |  | ||||||
|         self.apply_button.setEnabled(True) |         self.apply_button.setEnabled(True) | ||||||
|         self.reinstall_button.setEnabled(False) # Сбрасываем в неактивное состояние |         self.reinstall_button.setEnabled(False) # Сбрасываем в неактивное состояние | ||||||
|         self.close_button.setEnabled(True) |         self.close_button.setEnabled(True) | ||||||
| @@ -876,7 +854,6 @@ class WinetricksManagerDialog(QDialog): | |||||||
|             search_edit.clear() |             search_edit.clear() | ||||||
|  |  | ||||||
|         # Перезагружаем данные, чтобы обновить состояние |         # Перезагружаем данные, чтобы обновить состояние | ||||||
|         self.status_label.setText("Обновление данных...") |  | ||||||
|         self.initial_states.clear() |         self.initial_states.clear() | ||||||
|         self.load_all_categories() |         self.load_all_categories() | ||||||
|         self.installation_finished = True |         self.installation_finished = True | ||||||
| @@ -1233,9 +1210,9 @@ class CreatePrefixDialog(QDialog): | |||||||
|  |  | ||||||
|     def __init__(self, parent=None): |     def __init__(self, parent=None): | ||||||
|         super().__init__(parent) |         super().__init__(parent) | ||||||
|         self.parent_gui = parent  # Store reference to main window |         self.parent_gui = parent  # Сохранить ссылку на главное окно | ||||||
|         self.setWindowTitle("Создание нового префикса") |         self.setWindowTitle("Создание нового префикса") | ||||||
|         self.setMinimumSize(500, 250) |         self.setMinimumSize(680, 250) | ||||||
|         self.setModal(True) |         self.setModal(True) | ||||||
|  |  | ||||||
|         # Attributes to store results |         # Attributes to store results | ||||||
| @@ -1249,9 +1226,22 @@ class CreatePrefixDialog(QDialog): | |||||||
|         form_layout = QFormLayout() |         form_layout = QFormLayout() | ||||||
|         form_layout.setSpacing(10) |         form_layout.setSpacing(10) | ||||||
|  |  | ||||||
|  |         # Создаем виджет для поля ввода и предупреждения | ||||||
|  |         name_input_widget = QWidget() | ||||||
|  |         name_input_layout = QVBoxLayout(name_input_widget) | ||||||
|  |         name_input_layout.setContentsMargins(0, 0, 0, 0) | ||||||
|  |         name_input_layout.setSpacing(2) | ||||||
|  |  | ||||||
|         self.prefix_name_edit = QLineEdit() |         self.prefix_name_edit = QLineEdit() | ||||||
|         self.prefix_name_edit.setPlaceholderText("Например: my_prefix") |         self.prefix_name_edit.setPlaceholderText("Например: my_prefix") | ||||||
|         form_layout.addRow("<b>Имя нового префикса:</b>", self.prefix_name_edit) |         name_input_layout.addWidget(self.prefix_name_edit) | ||||||
|  |  | ||||||
|  |         self.name_warning_label = QLabel("Имя может содержать только латинские буквы, цифры, тире и знаки подчеркивания.") | ||||||
|  |         self.name_warning_label.setStyleSheet("color: red;") | ||||||
|  |         self.name_warning_label.setVisible(False) | ||||||
|  |         name_input_layout.addWidget(self.name_warning_label) | ||||||
|  |  | ||||||
|  |         form_layout.addRow("<b>Имя нового префикса:</b>", name_input_widget) | ||||||
|  |  | ||||||
|         arch_widget = QWidget() |         arch_widget = QWidget() | ||||||
|         arch_layout = QHBoxLayout(arch_widget) |         arch_layout = QHBoxLayout(arch_widget) | ||||||
| @@ -1308,7 +1298,7 @@ class CreatePrefixDialog(QDialog): | |||||||
|  |  | ||||||
|         # Connect signals |         # Connect signals | ||||||
|         self.arch_win32_radio.toggled.connect(self.clear_wine_version_selection) |         self.arch_win32_radio.toggled.connect(self.clear_wine_version_selection) | ||||||
|         self.prefix_name_edit.textChanged.connect(self.update_create_button_state) |         self.prefix_name_edit.textChanged.connect(self.validate_prefix_name) | ||||||
|         self.wine_version_edit.textChanged.connect(self.update_create_button_state) |         self.wine_version_edit.textChanged.connect(self.update_create_button_state) | ||||||
|  |  | ||||||
|     def open_wine_version_dialog(self): |     def open_wine_version_dialog(self): | ||||||
| @@ -1324,11 +1314,28 @@ class CreatePrefixDialog(QDialog): | |||||||
|         self.wine_version_edit.clear() |         self.wine_version_edit.clear() | ||||||
|         self.selected_wine_version_value = None |         self.selected_wine_version_value = None | ||||||
|  |  | ||||||
|  |     def validate_prefix_name(self, text): | ||||||
|  |         """Проверяет имя префикса в реальном времени и показывает/скрывает предупреждение.""" | ||||||
|  |         valid_pattern = r'^[a-zA-Z0-9_-]*$' | ||||||
|  |         if re.match(valid_pattern, text): | ||||||
|  |             self.name_warning_label.setVisible(False) | ||||||
|  |         else: | ||||||
|  |             # Удаляем недопустимые символы | ||||||
|  |             cleaned_text = re.sub(r'[^a-zA-Z0-9_-]', '', text) | ||||||
|  |             # Блокируем сигналы, чтобы избежать рекурсии при изменении текста | ||||||
|  |             self.prefix_name_edit.blockSignals(True) | ||||||
|  |             self.prefix_name_edit.setText(cleaned_text) | ||||||
|  |             self.prefix_name_edit.blockSignals(False) | ||||||
|  |             self.name_warning_label.setVisible(True) | ||||||
|  |  | ||||||
|  |         self.update_create_button_state() | ||||||
|  |  | ||||||
|     def update_create_button_state(self): |     def update_create_button_state(self): | ||||||
|         """Включает или выключает кнопку 'Создать'.""" |         """Включает или выключает кнопку 'Создать'.""" | ||||||
|         name_ok = bool(self.prefix_name_edit.text().strip()) |         name_ok = bool(self.prefix_name_edit.text().strip()) | ||||||
|         version_ok = bool(self.wine_version_edit.text().strip()) |         version_ok = bool(self.wine_version_edit.text().strip()) | ||||||
|         self.create_button.setEnabled(name_ok and version_ok) |         # Кнопка активна, только если имя валидно и версия выбрана | ||||||
|  |         self.create_button.setEnabled(name_ok and version_ok and not self.name_warning_label.isVisible()) | ||||||
|  |  | ||||||
|     def accept_creation(self): |     def accept_creation(self): | ||||||
|         """Валидирует данные, сохраняет их и закрывает диалог с успехом.""" |         """Валидирует данные, сохраняет их и закрывает диалог с успехом.""" | ||||||
| @@ -1338,8 +1345,8 @@ class CreatePrefixDialog(QDialog): | |||||||
|             QMessageBox.warning(self, "Ошибка", "Имя префикса не может быть пустым.") |             QMessageBox.warning(self, "Ошибка", "Имя префикса не может быть пустым.") | ||||||
|             return |             return | ||||||
|  |  | ||||||
|         if not re.match(r'^[a-zA-Z0-9_.-]+$', prefix_name): |         if not re.match(r'^[a-zA-Z0-9_-]+$', prefix_name): | ||||||
|             QMessageBox.warning(self, "Ошибка", "Имя префикса может содержать только латинские буквы, цифры, точки, дефисы и подчеркивания.") |             QMessageBox.warning(self, "Ошибка", "Имя префикса может содержать только латинские буквы, цифры, дефисы и знаки подчеркивания.") | ||||||
|             return |             return | ||||||
|  |  | ||||||
|         prefix_path = os.path.join(Var.USER_WORK_PATH, "prefixes", prefix_name) |         prefix_path = os.path.join(Var.USER_WORK_PATH, "prefixes", prefix_name) | ||||||
| @@ -1355,6 +1362,75 @@ class CreatePrefixDialog(QDialog): | |||||||
|  |  | ||||||
|         self.accept() |         self.accept() | ||||||
|  |  | ||||||
|  | class FileAssociationsDialog(QDialog): | ||||||
|  |     """Диалог для управления ассоциациями файлов (WH_XDG_OPEN).""" | ||||||
|  |  | ||||||
|  |     def __init__(self, current_associations, parent=None): | ||||||
|  |         super().__init__(parent) | ||||||
|  |         self.setWindowTitle("Настройка ассоциаций файлов") | ||||||
|  |         self.setMinimumWidth(450) | ||||||
|  |         self.setModal(True) | ||||||
|  |  | ||||||
|  |         self.new_associations = current_associations | ||||||
|  |  | ||||||
|  |         layout = QVBoxLayout(self) | ||||||
|  |         layout.setSpacing(10)  # Добавляем вертикальный отступ между виджетами | ||||||
|  |  | ||||||
|  |         info_label = QLabel( | ||||||
|  |             "Укажите расширения файлов, которые должны открываться нативными<br>" | ||||||
|  |             "приложениями Linux. Чтобы удалить все ассоциации, очистите поле.<br><br>" | ||||||
|  |             "<b>Пример:</b> <code>pdf docx txt</code>" | ||||||
|  |         ) | ||||||
|  |         info_label.setWordWrap(True) | ||||||
|  |         info_label.setTextFormat(Qt.RichText) | ||||||
|  |         layout.addWidget(info_label) | ||||||
|  |  | ||||||
|  |         self.associations_edit = QLineEdit() | ||||||
|  |         # Если ассоциации не заданы (значение "0"), поле будет пустым, чтобы показать подсказку | ||||||
|  |         if current_associations != "0": | ||||||
|  |             self.associations_edit.setText(current_associations) | ||||||
|  |  | ||||||
|  |         self.associations_edit.setPlaceholderText("Введите расширения через пробел...") | ||||||
|  |         layout.addWidget(self.associations_edit) | ||||||
|  |  | ||||||
|  |         # Запрещенные расширения | ||||||
|  |         forbidden_label = QLabel( | ||||||
|  |             "<small><b>Запрещено использовать:</b> cpl, dll, exe, lnk, msi</small>" | ||||||
|  |         ) | ||||||
|  |         forbidden_label.setTextFormat(Qt.RichText)  # Включаем обработку HTML | ||||||
|  |         layout.addWidget(forbidden_label) | ||||||
|  |  | ||||||
|  |         button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) | ||||||
|  |         button_box.accepted.connect(self.validate_and_accept) | ||||||
|  |         button_box.rejected.connect(self.reject) | ||||||
|  |         layout.addWidget(button_box) | ||||||
|  |  | ||||||
|  |     def validate_and_accept(self): | ||||||
|  |         """Проверяет введенные данные перед закрытием.""" | ||||||
|  |         forbidden_extensions = {"cpl", "dll", "exe", "lnk", "msi"} | ||||||
|  |  | ||||||
|  |         # Получаем введенные расширения, очищаем от лишних пробелов | ||||||
|  |         input_text = self.associations_edit.text().lower().strip() | ||||||
|  |         entered_extensions = {ext.strip() for ext in input_text.split() if ext.strip()} | ||||||
|  |  | ||||||
|  |         found_forbidden = entered_extensions.intersection(forbidden_extensions) | ||||||
|  |  | ||||||
|  |         if found_forbidden: | ||||||
|  |             msg_box = QMessageBox(self) | ||||||
|  |             msg_box.setIcon(QMessageBox.Warning) | ||||||
|  |             msg_box.setWindowTitle("Недопустимые расширения") | ||||||
|  |             msg_box.setTextFormat(Qt.RichText) | ||||||
|  |             msg_box.setText( | ||||||
|  |                 "Следующие расширения запрещены и не могут быть использованы:<br><br>" | ||||||
|  |                 f"<b>{', '.join(sorted(list(found_forbidden)))}</b>" | ||||||
|  |             ) | ||||||
|  |             msg_box.exec_() | ||||||
|  |             return | ||||||
|  |  | ||||||
|  |         # Сохраняем результат в виде отсортированной строки | ||||||
|  |         self.new_associations = " ".join(sorted(list(entered_extensions))) | ||||||
|  |         self.accept() | ||||||
|  |  | ||||||
| class ComponentVersionSelectionDialog(QDialog): | class ComponentVersionSelectionDialog(QDialog): | ||||||
|     """Диалог для выбора версии компонента (DXVK, VKD3D).""" |     """Диалог для выбора версии компонента (DXVK, VKD3D).""" | ||||||
|  |  | ||||||
| @@ -1535,6 +1611,7 @@ class WineHelperGUI(QMainWindow): | |||||||
|         self.current_managed_prefix_name = None  # Имя префикса, выбранного в выпадающем списке |         self.current_managed_prefix_name = None  # Имя префикса, выбранного в выпадающем списке | ||||||
|         self.prefixes_before_install = set() |         self.prefixes_before_install = set() | ||||||
|  |  | ||||||
|  |         self.is_quitting = False # Флаг для корректного выхода из приложения | ||||||
|         self.command_output_buffer = "" |         self.command_output_buffer = "" | ||||||
|         self.command_last_line_was_progress = False |         self.command_last_line_was_progress = False | ||||||
|         # Создаем главный виджет и layout |         # Создаем главный виджет и layout | ||||||
| @@ -1601,6 +1678,50 @@ class WineHelperGUI(QMainWindow): | |||||||
|         self.raise_() |         self.raise_() | ||||||
|         self.activateWindow() |         self.activateWindow() | ||||||
|  |  | ||||||
|  |     def create_tray_icon(self): | ||||||
|  |         """Создает и настраивает иконку в системном трее.""" | ||||||
|  |         if not QSystemTrayIcon.isSystemTrayAvailable(): | ||||||
|  |             print("Системный трей не доступен.") | ||||||
|  |             return | ||||||
|  |  | ||||||
|  |         self.tray_icon = QSystemTrayIcon(self) | ||||||
|  |  | ||||||
|  |         icon_path = Var.WH_ICON_PATH | ||||||
|  |         if icon_path and os.path.exists(icon_path): | ||||||
|  |             pixmap = QPixmap(icon_path) | ||||||
|  |             if not pixmap.isNull(): | ||||||
|  |                 self.tray_icon.setIcon(QIcon(pixmap)) | ||||||
|  |  | ||||||
|  |         # Создаем и сохраняем меню как атрибут класса, чтобы оно не удалялось | ||||||
|  |         self.tray_menu = QMenu(self) | ||||||
|  |  | ||||||
|  |         toggle_visibility_action = self.tray_menu.addAction("Показать/Скрыть") | ||||||
|  |         toggle_visibility_action.triggered.connect(self.toggle_visibility) | ||||||
|  |         self.tray_menu.addSeparator() | ||||||
|  |  | ||||||
|  |         quit_action = self.tray_menu.addAction("Выход") | ||||||
|  |         quit_action.triggered.connect(self.quit_application) | ||||||
|  |  | ||||||
|  |         self.tray_icon.activated.connect(self.on_tray_icon_activated) | ||||||
|  |         self.tray_icon.show() | ||||||
|  |  | ||||||
|  |     def on_tray_icon_activated(self, reason): | ||||||
|  |         """Обрабатывает клики по иконке в трее.""" | ||||||
|  |         # Показываем меню при левом клике | ||||||
|  |         if reason == QSystemTrayIcon.Trigger: | ||||||
|  |             # Получаем позицию курсора и показываем меню | ||||||
|  |             self.tray_menu.popup(QCursor.pos()) | ||||||
|  |  | ||||||
|  |     def toggle_visibility(self): | ||||||
|  |         """Переключает видимость главного окна.""" | ||||||
|  |         if self.isVisible() and self.isActiveWindow(): | ||||||
|  |             self.hide() | ||||||
|  |         else: | ||||||
|  |             # Сначала скрываем, чтобы "сбросить" состояние, затем активируем. | ||||||
|  |             # Это помогает обойти проблемы с фокусом и переключением рабочих столов. | ||||||
|  |             self.hide() | ||||||
|  |             self.activate() | ||||||
|  |  | ||||||
|     def add_tab(self, widget, title): |     def add_tab(self, widget, title): | ||||||
|         """Добавляет вкладку в кастомный TabBar и страницу в StackedWidget.""" |         """Добавляет вкладку в кастомный TabBar и страницу в StackedWidget.""" | ||||||
|         self.tab_bar.addTab(title) |         self.tab_bar.addTab(title) | ||||||
| @@ -2042,7 +2163,7 @@ class WineHelperGUI(QMainWindow): | |||||||
|  |  | ||||||
|         # --- Контейнер для выбора и управления созданными префиксами --- |         # --- Контейнер для выбора и управления созданными префиксами --- | ||||||
|         self.management_container_groupbox = QGroupBox() |         self.management_container_groupbox = QGroupBox() | ||||||
|         self.management_container_groupbox.setVisible(False)  # Скрыт, пока нет префиксов |         self.management_container_groupbox.setVisible(True)  # Всегда виден | ||||||
|         container_layout = QVBoxLayout(self.management_container_groupbox) |         container_layout = QVBoxLayout(self.management_container_groupbox) | ||||||
|  |  | ||||||
|         selector_layout = QHBoxLayout() |         selector_layout = QHBoxLayout() | ||||||
| @@ -2051,6 +2172,13 @@ class WineHelperGUI(QMainWindow): | |||||||
|         self.created_prefix_selector.currentIndexChanged.connect(self.on_created_prefix_selected) |         self.created_prefix_selector.currentIndexChanged.connect(self.on_created_prefix_selected) | ||||||
|         selector_layout.addWidget(self.created_prefix_selector, 1) |         selector_layout.addWidget(self.created_prefix_selector, 1) | ||||||
|  |  | ||||||
|  |         self.create_base_pfx_button = QPushButton() | ||||||
|  |         self.create_base_pfx_button.setIcon(QIcon.fromTheme("document-export")) | ||||||
|  |         self.create_base_pfx_button.setToolTip("Создать шаблон из выбранного префикса (для опытных пользователей)") | ||||||
|  |         self.create_base_pfx_button.setEnabled(False) | ||||||
|  |         self.create_base_pfx_button.clicked.connect(self.create_base_prefix_from_selected) | ||||||
|  |         selector_layout.addWidget(self.create_base_pfx_button) | ||||||
|  |  | ||||||
|         self.delete_prefix_button = QPushButton() |         self.delete_prefix_button = QPushButton() | ||||||
|         self.delete_prefix_button.setIcon(QIcon.fromTheme("user-trash")) |         self.delete_prefix_button.setIcon(QIcon.fromTheme("user-trash")) | ||||||
|         self.delete_prefix_button.setToolTip("Удалить выбранный префикс") |         self.delete_prefix_button.setToolTip("Удалить выбранный префикс") | ||||||
| @@ -2142,6 +2270,13 @@ class WineHelperGUI(QMainWindow): | |||||||
|         self.vkd3d_manage_button.setToolTip("Установка или удаление определенной версии vkd3d-proton в префиксе.") |         self.vkd3d_manage_button.setToolTip("Установка или удаление определенной версии vkd3d-proton в префиксе.") | ||||||
|         management_layout.addWidget(self.vkd3d_manage_button, 5, 1) |         management_layout.addWidget(self.vkd3d_manage_button, 5, 1) | ||||||
|  |  | ||||||
|  |         self.file_associations_button = QPushButton("Ассоциации файлов") | ||||||
|  |         self.file_associations_button.setMinimumHeight(32) | ||||||
|  |         self.file_associations_button.clicked.connect(self.open_file_associations_manager) | ||||||
|  |         self.file_associations_button.setToolTip( | ||||||
|  |             "Настройка открытия определенных типов файлов с помощью нативных приложений Linux.") | ||||||
|  |         management_layout.addWidget(self.file_associations_button, 6, 0, 1, 2) | ||||||
|  |  | ||||||
|         # --- Правая сторона: Информационный блок и кнопки установки --- |         # --- Правая сторона: Информационный блок и кнопки установки --- | ||||||
|         right_column_widget = QWidget() |         right_column_widget = QWidget() | ||||||
|         right_column_layout = QVBoxLayout(right_column_widget) |         right_column_layout = QVBoxLayout(right_column_widget) | ||||||
| @@ -2174,7 +2309,7 @@ class WineHelperGUI(QMainWindow): | |||||||
|         right_column_layout.setStretch(0, 1)  # Информационное окно растягивается |         right_column_layout.setStretch(0, 1)  # Информационное окно растягивается | ||||||
|         right_column_layout.setStretch(1, 0)  # Группа кнопок не растягивается |         right_column_layout.setStretch(1, 0)  # Группа кнопок не растягивается | ||||||
|  |  | ||||||
|         management_layout.addWidget(right_column_widget, 0, 2, 6, 1) |         management_layout.addWidget(right_column_widget, 0, 2, 7, 1) | ||||||
|  |  | ||||||
|         management_layout.setColumnStretch(0, 1) |         management_layout.setColumnStretch(0, 1) | ||||||
|         management_layout.setColumnStretch(1, 1) |         management_layout.setColumnStretch(1, 1) | ||||||
| @@ -2208,8 +2343,8 @@ class WineHelperGUI(QMainWindow): | |||||||
|     def _load_created_prefixes(self): |     def _load_created_prefixes(self): | ||||||
|         """Загружает и обновляет список созданных префиксов в выпадающем списке.""" |         """Загружает и обновляет список созданных префиксов в выпадающем списке.""" | ||||||
|         prefixes_root_path = os.path.join(Var.USER_WORK_PATH, "prefixes") |         prefixes_root_path = os.path.join(Var.USER_WORK_PATH, "prefixes") | ||||||
|         if not os.path.isdir(prefixes_root_path): |         has_prefixes_dir = os.path.isdir(prefixes_root_path) | ||||||
|             self.management_container_groupbox.setVisible(False) |         if not has_prefixes_dir: | ||||||
|             return |             return | ||||||
|  |  | ||||||
|         try: |         try: | ||||||
| @@ -2228,18 +2363,16 @@ class WineHelperGUI(QMainWindow): | |||||||
|         self.created_prefix_selector.blockSignals(False) |         self.created_prefix_selector.blockSignals(False) | ||||||
|  |  | ||||||
|         if not prefix_names: |         if not prefix_names: | ||||||
|             self.management_container_groupbox.setVisible(False) |  | ||||||
|             self.on_created_prefix_selected(-1)  # Убедимся, что панель управления сброшена |             self.on_created_prefix_selected(-1)  # Убедимся, что панель управления сброшена | ||||||
|             return |             return | ||||||
|  |  | ||||||
|         self.management_container_groupbox.setVisible(True) |  | ||||||
|  |  | ||||||
|     def on_created_prefix_selected(self, index): |     def on_created_prefix_selected(self, index): | ||||||
|         """Обрабатывает выбор префикса из выпадающего списка.""" |         """Обрабатывает выбор префикса из выпадающего списка.""" | ||||||
|         if index == -1: |         if index == -1: | ||||||
|             self.current_managed_prefix_name = None |             self.current_managed_prefix_name = None | ||||||
|             self._setup_prefix_management_panel(None) |             self._setup_prefix_management_panel(None) | ||||||
|             self.delete_prefix_button.setEnabled(False) |             self.delete_prefix_button.setEnabled(False) | ||||||
|  |             self.create_base_pfx_button.setEnabled(False) | ||||||
|         else: |         else: | ||||||
|             # Прокручиваем к выбранному элементу, чтобы он был виден в списке |             # Прокручиваем к выбранному элементу, чтобы он был виден в списке | ||||||
|             self.created_prefix_selector.view().scrollTo( |             self.created_prefix_selector.view().scrollTo( | ||||||
| @@ -2249,6 +2382,7 @@ class WineHelperGUI(QMainWindow): | |||||||
|             self.current_managed_prefix_name = prefix_name |             self.current_managed_prefix_name = prefix_name | ||||||
|             self._setup_prefix_management_panel(prefix_name) |             self._setup_prefix_management_panel(prefix_name) | ||||||
|             self.delete_prefix_button.setEnabled(True) |             self.delete_prefix_button.setEnabled(True) | ||||||
|  |             self.create_base_pfx_button.setEnabled(True) | ||||||
|  |  | ||||||
|     def delete_selected_prefix(self): |     def delete_selected_prefix(self): | ||||||
|         """Удаляет префикс, выбранный в выпадающем списке на вкладке 'Менеджер префиксов'.""" |         """Удаляет префикс, выбранный в выпадающем списке на вкладке 'Менеджер префиксов'.""" | ||||||
| @@ -2313,6 +2447,50 @@ class WineHelperGUI(QMainWindow): | |||||||
|         else: |         else: | ||||||
|             QMessageBox.critical(self, "Ошибка удаления", f"Не удалось удалить префикс '{prefix_name}'.\nПодробности смотрите в логе.") |             QMessageBox.critical(self, "Ошибка удаления", f"Не удалось удалить префикс '{prefix_name}'.\nПодробности смотрите в логе.") | ||||||
|  |  | ||||||
|  |     def create_base_prefix_from_selected(self): | ||||||
|  |         """Создает шаблон префикса из выбранного в выпадающем списке.""" | ||||||
|  |         prefix_name = self.current_managed_prefix_name | ||||||
|  |         if not prefix_name: | ||||||
|  |             return | ||||||
|  |  | ||||||
|  |         msg_box = QMessageBox(self) | ||||||
|  |         msg_box.setIcon(QMessageBox.Question) | ||||||
|  |         msg_box.setWindowTitle("Создание шаблона префикса") | ||||||
|  |         msg_box.setText( | ||||||
|  |             f"Будет создан 'шаблон' из префикса '{prefix_name}'.\n" | ||||||
|  |             "Это продвинутая функция для создания базовых архивов префиксов.\n\n" | ||||||
|  |             "Продолжить?" | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  |         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 | ||||||
|  |  | ||||||
|  |         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) | ||||||
|  |  | ||||||
|  |         layout = QVBoxLayout() | ||||||
|  |         self.command_log_output = QTextEdit() | ||||||
|  |         self.command_log_output.setReadOnly(True) | ||||||
|  |         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._run_simple_command("create-base-pfx", [prefix_name]) | ||||||
|  |         self.command_dialog.exec_() | ||||||
|  |  | ||||||
|     def _setup_prefix_management_panel(self, prefix_name): |     def _setup_prefix_management_panel(self, prefix_name): | ||||||
|         """Настраивает панель управления префиксом на основе текущего состояния.""" |         """Настраивает панель управления префиксом на основе текущего состояния.""" | ||||||
|         is_prefix_selected = bool(prefix_name) |         is_prefix_selected = bool(prefix_name) | ||||||
| @@ -2381,8 +2559,9 @@ class WineHelperGUI(QMainWindow): | |||||||
|             "VKD3D_VER": ("Версия VKD3D", lambda v: v if v else "Не установлено"), |             "VKD3D_VER": ("Версия VKD3D", lambda v: v if v else "Не установлено"), | ||||||
|             "WINEESYNC": ("ESync", lambda v: "Включен" if v == "1" else "Выключен"), |             "WINEESYNC": ("ESync", lambda v: "Включен" if v == "1" else "Выключен"), | ||||||
|             "WINEFSYNC": ("FSync", lambda v: "Включен" if v == "1" else "Выключен"), |             "WINEFSYNC": ("FSync", lambda v: "Включен" if v == "1" else "Выключен"), | ||||||
|  |             "WH_XDG_OPEN": ("Ассоциации файлов", lambda v: v if v and v != "0" else "Не заданы"), | ||||||
|         } |         } | ||||||
|         display_order = ["WINEPREFIX", "WINEARCH", "WH_WINE_USE", "BASE_PFX", "DXVK_VER", "VKD3D_VER", "WINEESYNC", "WINEFSYNC"] |         display_order = ["WINEPREFIX", "WINEARCH", "WH_WINE_USE", "BASE_PFX", "DXVK_VER", "VKD3D_VER", "WINEESYNC", "WINEFSYNC", "WH_XDG_OPEN"] | ||||||
|  |  | ||||||
|         html_content = f'<p style="line-height: 1.3; font-size: 9pt;">' |         html_content = f'<p style="line-height: 1.3; font-size: 9pt;">' | ||||||
|         html_content += f"<b>Имя:</b> {html.escape(prefix_name)}<br>" |         html_content += f"<b>Имя:</b> {html.escape(prefix_name)}<br>" | ||||||
| @@ -2531,11 +2710,12 @@ class WineHelperGUI(QMainWindow): | |||||||
|                 # Для удаления лицензия не нужна, запускаем сразу. |                 # Для удаления лицензия не нужна, запускаем сразу. | ||||||
|                 self.run_component_install_command(prefix_name, command, version) |                 self.run_component_install_command(prefix_name, command, version) | ||||||
|             else: |             else: | ||||||
|                 # Установка: сначала показываем лицензионное соглашение. |                 # Установка: для DXVK и VKD3D лицензию не показываем. | ||||||
|  |                 if component not in ['dxvk', 'vkd3d-proton']: | ||||||
|                     if not self._show_license_agreement_dialog(): |                     if not self._show_license_agreement_dialog(): | ||||||
|                         return  # Пользователь отклонил лицензию |                         return  # Пользователь отклонил лицензию | ||||||
|  |  | ||||||
|                 # Если лицензия принята, запускаем установку. |                 # Запускаем установку. | ||||||
|                 self.run_component_install_command(prefix_name, command, version) |                 self.run_component_install_command(prefix_name, command, version) | ||||||
|  |  | ||||||
|     def open_wine_version_manager(self): |     def open_wine_version_manager(self): | ||||||
| @@ -2566,9 +2746,6 @@ class WineHelperGUI(QMainWindow): | |||||||
|             new_version = dialog.selected_version |             new_version = dialog.selected_version | ||||||
|             new_version_display = dialog.selected_display_text |             new_version_display = dialog.selected_display_text | ||||||
|  |  | ||||||
|             if not self._show_license_agreement_dialog(): |  | ||||||
|                 return  # Пользователь отклонил лицензию |  | ||||||
|  |  | ||||||
|             self.run_change_wine_version_command(prefix_name, new_version, new_version_display) |             self.run_change_wine_version_command(prefix_name, new_version, new_version_display) | ||||||
|  |  | ||||||
|     def run_change_wine_version_command(self, prefix_name, new_version, new_version_display): |     def run_change_wine_version_command(self, prefix_name, new_version, new_version_display): | ||||||
| @@ -2682,6 +2859,88 @@ class WineHelperGUI(QMainWindow): | |||||||
|         if exit_code == 0: |         if exit_code == 0: | ||||||
|             self.update_prefix_info_display(prefix_name) |             self.update_prefix_info_display(prefix_name) | ||||||
|  |  | ||||||
|  |     def open_file_associations_manager(self): | ||||||
|  |         """Открывает диалог для управления ассоциациями файлов.""" | ||||||
|  |         prefix_name = self.current_managed_prefix_name | ||||||
|  |         if not prefix_name: | ||||||
|  |             QMessageBox.warning(self, "Ошибка", "Сначала выберите префикс.") | ||||||
|  |             return | ||||||
|  |  | ||||||
|  |         current_associations = self._get_prefix_component_version(prefix_name, "WH_XDG_OPEN") or "0" | ||||||
|  |  | ||||||
|  |         dialog = FileAssociationsDialog(current_associations if current_associations != "0" else "", self) | ||||||
|  |         if dialog.exec_() == QDialog.Accepted: | ||||||
|  |             new_associations = dialog.new_associations | ||||||
|  |  | ||||||
|  |             # Запускаем обновление, только если значение изменилось | ||||||
|  |             if new_associations != (current_associations if current_associations != "0" else "0"): | ||||||
|  |                 self.run_update_associations_command(prefix_name, new_associations) | ||||||
|  |  | ||||||
|  |     def run_update_associations_command(self, prefix_name, new_associations): | ||||||
|  |         """Выполняет команду обновления ассоциаций файлов.""" | ||||||
|  |         # --- Прямое редактирование last.conf, чтобы обойти перезапись переменных в winehelper --- | ||||||
|  |         last_conf_path = os.path.join(Var.USER_WORK_PATH, "prefixes", prefix_name, "last.conf") | ||||||
|  |         if not os.path.exists(last_conf_path): | ||||||
|  |             QMessageBox.critical(self, "Ошибка", f"Файл конфигурации last.conf не найден для префикса '{prefix_name}'.") | ||||||
|  |             return | ||||||
|  |  | ||||||
|  |         try: | ||||||
|  |             with open(last_conf_path, 'r', encoding='utf-8') as f: | ||||||
|  |                 lines = f.readlines() | ||||||
|  |  | ||||||
|  |             updated = False | ||||||
|  |             for i, line in enumerate(lines): | ||||||
|  |                 if line.strip().startswith("export WH_XDG_OPEN="): | ||||||
|  |                     lines[i] = f'export WH_XDG_OPEN="{new_associations}"\n' | ||||||
|  |                     updated = True | ||||||
|  |                     break | ||||||
|  |             if not updated: | ||||||
|  |                 lines.append(f'export WH_XDG_OPEN="{new_associations}"\n') | ||||||
|  |  | ||||||
|  |             with open(last_conf_path, 'w', encoding='utf-8') as f: | ||||||
|  |                 f.writelines(lines) | ||||||
|  |         except IOError as e: | ||||||
|  |             QMessageBox.critical(self, "Ошибка записи", f"Не удалось обновить файл last.conf: {e}") | ||||||
|  |             return | ||||||
|  |  | ||||||
|  |         prefix_path = os.path.join(Var.USER_WORK_PATH, "prefixes", prefix_name) | ||||||
|  |  | ||||||
|  |         self.command_dialog = QDialog(self) | ||||||
|  |         self.command_dialog.setWindowTitle("Обновление ассоциаций файлов") | ||||||
|  |         self.command_dialog.setMinimumSize(750, 400) | ||||||
|  |         self.command_dialog.setModal(True) | ||||||
|  |         self.command_dialog.setWindowFlags(self.command_dialog.windowFlags() & ~Qt.WindowCloseButtonHint) | ||||||
|  |  | ||||||
|  |         layout = QVBoxLayout() | ||||||
|  |         self.command_log_output = QTextEdit() | ||||||
|  |         self.command_log_output.setReadOnly(True) | ||||||
|  |         self.command_log_output.setFont(QFont('DejaVu Sans Mono', 10)) | ||||||
|  |         layout.addWidget(self.command_log_output) | ||||||
|  |  | ||||||
|  |         self.command_close_button = QPushButton("Закрыть") | ||||||
|  |         self.command_close_button.setEnabled(False) | ||||||
|  |         self.command_close_button.clicked.connect(self.command_dialog.close) | ||||||
|  |         layout.addWidget(self.command_close_button) | ||||||
|  |         self.command_dialog.setLayout(layout) | ||||||
|  |  | ||||||
|  |         self.command_process = QProcess(self.command_dialog) | ||||||
|  |         self.command_process.setProcessChannelMode(QProcess.MergedChannels) | ||||||
|  |         self.command_process.readyReadStandardOutput.connect(self._handle_command_output) | ||||||
|  |         self.command_process.finished.connect( | ||||||
|  |             lambda exit_code, exit_status: self._handle_component_install_finished( | ||||||
|  |                 prefix_name, exit_code, exit_status)) | ||||||
|  |  | ||||||
|  |         env = QProcessEnvironment.systemEnvironment() | ||||||
|  |         env.insert("WINEPREFIX", prefix_path) | ||||||
|  |         # Переменная WH_XDG_OPEN теперь читается из измененного last.conf | ||||||
|  |         self.command_process.setProcessEnvironment(env) | ||||||
|  |  | ||||||
|  |         # Вызываем init-prefix, который теперь прочитает правильное значение из last.conf | ||||||
|  |         args = ["init-prefix"] | ||||||
|  |         self.command_log_output.append(f"Выполнение: {shlex.quote(self.winehelper_path)} {' '.join(shlex.quote(a) for a in args)}") | ||||||
|  |         self.command_process.start(self.winehelper_path, args) | ||||||
|  |         self.command_dialog.exec_() | ||||||
|  |  | ||||||
|     def create_launcher_for_prefix(self): |     def create_launcher_for_prefix(self): | ||||||
|         """ |         """ | ||||||
|         Открывает диалог для создания ярлыка для приложения внутри выбранного префикса. |         Открывает диалог для создания ярлыка для приложения внутри выбранного префикса. | ||||||
| @@ -2782,14 +3041,15 @@ class WineHelperGUI(QMainWindow): | |||||||
|         authors_text = QTextEdit() |         authors_text = QTextEdit() | ||||||
|         authors_text.setReadOnly(True) |         authors_text.setReadOnly(True) | ||||||
|         authors_text.setHtml(""" |         authors_text.setHtml(""" | ||||||
|             <div style="text-align: center;"> |             <div style="text-align: center; font-size: 10pt;"> | ||||||
|                 <h2>Разработчики</h2> |                 <p><span style="font-size: 11pt;"><b>Разработчики</b></span><br> | ||||||
|                 Михаил Тергоев (fidel)<br> |                 Михаил Тергоев (fidel)<br> | ||||||
|                 Сергей Пальчех (minergenon)</p> |                 Сергей Пальчех (minergenon)</p> | ||||||
|                 <p><b>Помощники</b><br> |                 <p><span style="font-size: 11pt;"><b>Помощники</b></span><br> | ||||||
|                 Иван Мажукин (vanomj)</p> |                 Иван Мажукин (vanomj)</p> | ||||||
|                 <p><b>Идея и поддержка:</b><br> |                 <p><span style="font-size: 11pt;"><b>Идея и поддержка</b></span><br> | ||||||
|                 сообщество ALT Linux</p> |                 ООО "Базальт СПО"<br> | ||||||
|  |                 ALT Linux Team</p> | ||||||
|                 <br> |                 <br> | ||||||
|                 <p>Отдельная благодарность всем, кто вносит свой вклад в развитие проекта,<br> |                 <p>Отдельная благодарность всем, кто вносит свой вклад в развитие проекта,<br> | ||||||
|                 тестирует и сообщает об ошибках!</p> |                 тестирует и сообщает об ошибках!</p> | ||||||
| @@ -2967,9 +3227,6 @@ class WineHelperGUI(QMainWindow): | |||||||
|  |  | ||||||
|             self.created_prefix_selector.setCurrentText(prefix_name) |             self.created_prefix_selector.setCurrentText(prefix_name) | ||||||
|  |  | ||||||
|             if not self.management_container_groupbox.isVisible(): |  | ||||||
|                 self.management_container_groupbox.setVisible(True) |  | ||||||
|  |  | ||||||
|     def update_installed_apps(self): |     def update_installed_apps(self): | ||||||
|         """Обновляет список установленных приложений в виде кнопок""" |         """Обновляет список установленных приложений в виде кнопок""" | ||||||
|         # Если активная кнопка находится в списке удаляемых, сбрасываем ее |         # Если активная кнопка находится в списке удаляемых, сбрасываем ее | ||||||
| @@ -3058,7 +3315,9 @@ class WineHelperGUI(QMainWindow): | |||||||
|     def show_installed_app_info(self, desktop_path, button_widget): |     def show_installed_app_info(self, desktop_path, button_widget): | ||||||
|         """Показывает информацию об установленном приложении в правой панели.""" |         """Показывает информацию об установленном приложении в правой панели.""" | ||||||
|         self._set_active_button(button_widget) |         self._set_active_button(button_widget) | ||||||
|         # Очищаем поле поиска и принудительно обновляем список, чтобы показать все приложения |         # Если в поиске был текст, очищаем его и перерисовываем список. | ||||||
|  |         # Это предотвращает "прыжок", если список не был отфильтрован. | ||||||
|  |         if self.installed_search_edit.text(): | ||||||
|             self.installed_search_edit.blockSignals(True) |             self.installed_search_edit.blockSignals(True) | ||||||
|             self.installed_search_edit.clear() |             self.installed_search_edit.clear() | ||||||
|             self.installed_search_edit.blockSignals(False) |             self.installed_search_edit.blockSignals(False) | ||||||
| @@ -3512,7 +3771,7 @@ class WineHelperGUI(QMainWindow): | |||||||
|                     QMessageBox.critical(self, "Ошибка", f"Не удалось модифицировать команду для отладки: {e}") |                     QMessageBox.critical(self, "Ошибка", f"Не удалось модифицировать команду для отладки: {e}") | ||||||
|                     return |                     return | ||||||
|  |  | ||||||
|             process = QProcess(self) |             process = QProcess() | ||||||
|             env = QProcessEnvironment.systemEnvironment() |             env = QProcessEnvironment.systemEnvironment() | ||||||
|  |  | ||||||
|             cmd_start_index = 0 |             cmd_start_index = 0 | ||||||
| @@ -3530,7 +3789,10 @@ class WineHelperGUI(QMainWindow): | |||||||
|             arguments = clean_command[cmd_start_index + 1:] |             arguments = clean_command[cmd_start_index + 1:] | ||||||
|  |  | ||||||
|             process.setProcessEnvironment(env) |             process.setProcessEnvironment(env) | ||||||
|             process.finished.connect(lambda: self._on_app_process_finished(desktop_path)) |             # Используем functools.partial для надежной передачи аргументов | ||||||
|  |             # и избегания проблем с замыканием в lambda. | ||||||
|  |             process.finished.connect(partial(self._on_app_process_finished, desktop_path)) | ||||||
|  |  | ||||||
|  |  | ||||||
|             try: |             try: | ||||||
|                 process.start(program, arguments) |                 process.start(program, arguments) | ||||||
| @@ -3549,6 +3811,51 @@ class WineHelperGUI(QMainWindow): | |||||||
|             QMessageBox.critical(self, "Ошибка", |             QMessageBox.critical(self, "Ошибка", | ||||||
|                                  f"Не удалось обработать команду запуска:\n{command_str}\n\nОшибка: {str(e)}") |                                  f"Не удалось обработать команду запуска:\n{command_str}\n\nОшибка: {str(e)}") | ||||||
|  |  | ||||||
|  |     def quit_application(self): | ||||||
|  |         """Инициирует процесс выхода из приложения.""" | ||||||
|  |         self.is_quitting = True | ||||||
|  |         self.close()  # Инициируем событие закрытия, которое будет обработано в closeEvent | ||||||
|  |  | ||||||
|  |     def closeEvent(self, event): | ||||||
|  |         """Обрабатывает событие закрытия главного окна.""" | ||||||
|  |         # Теперь любое закрытие окна (крестик или выход из меню) инициирует выход | ||||||
|  |         if self.running_apps: | ||||||
|  |             msg_box = QMessageBox(self) | ||||||
|  |             msg_box.setWindowTitle('Подтверждение выхода') | ||||||
|  |             msg_box.setTextFormat(Qt.RichText) | ||||||
|  |             msg_box.setText('<font color="red">Все запущенные приложения будут закрыты вместе с WineHelper.</font><br><br>' | ||||||
|  |                             "Вы уверены, что хотите выйти?") | ||||||
|  |             msg_box.setIcon(QMessageBox.Question) | ||||||
|  |  | ||||||
|  |             yes_button = msg_box.addButton("Да", QMessageBox.YesRole) | ||||||
|  |             no_button = msg_box.addButton("Нет", QMessageBox.NoRole) | ||||||
|  |             msg_box.setDefaultButton(no_button) | ||||||
|  |  | ||||||
|  |             msg_box.exec_() | ||||||
|  |  | ||||||
|  |             if msg_box.clickedButton() == yes_button: | ||||||
|  |                 # Отключаем обработчики сигналов от всех запущенных процессов, | ||||||
|  |                 # так как мы собираемся их принудительно завершить и выйти. | ||||||
|  |                 # Это предотвращает ошибку RuntimeError при закрытии. | ||||||
|  |                 for process in self.running_apps.values(): | ||||||
|  |                     process.finished.disconnect() | ||||||
|  |  | ||||||
|  |                 # Используем встроенную команду killall для надежного завершения всех процессов wine | ||||||
|  |                 print("Завершение всех запущенных приложений через 'winehelper killall'...") | ||||||
|  |                 # Используем subprocess.run, который дождется завершения команды | ||||||
|  |                 subprocess.run([self.winehelper_path, "killall"], check=False, capture_output=True) | ||||||
|  |  | ||||||
|  |                 # Принудительно дожидаемся завершения всех дочерних процессов | ||||||
|  |                 for process in self.running_apps.values(): | ||||||
|  |                     process.waitForFinished(5000) # Ждем до 5 секунд | ||||||
|  |  | ||||||
|  |                 QApplication.instance().quit() | ||||||
|  |                 event.accept() | ||||||
|  |             else: | ||||||
|  |                 event.ignore() | ||||||
|  |         else: | ||||||
|  |             QApplication.instance().quit()  # Если нет запущенных приложений, просто выходим | ||||||
|  |  | ||||||
|     def uninstall_app(self): |     def uninstall_app(self): | ||||||
|         """Удаляет выбранное установленное приложение и его префикс""" |         """Удаляет выбранное установленное приложение и его префикс""" | ||||||
|         if not self.current_selected_app or 'desktop_path' not in self.current_selected_app: |         if not self.current_selected_app or 'desktop_path' not in self.current_selected_app: | ||||||
| @@ -3732,11 +4039,14 @@ class WineHelperGUI(QMainWindow): | |||||||
|         search_edit = tab_data['search_edit'] |         search_edit = tab_data['search_edit'] | ||||||
|         scroll_area = tab_data['scroll_area'] |         scroll_area = tab_data['scroll_area'] | ||||||
|  |  | ||||||
|         # Общая логика: очищаем поиск, обновляем список и прокручиваем к элементу |         # Если в поиске был текст, очищаем его и перерисовываем список. | ||||||
|  |         # Это предотвращает "прыжок", если список не был отфильтрован. | ||||||
|  |         if search_edit.text(): | ||||||
|             search_edit.blockSignals(True) |             search_edit.blockSignals(True) | ||||||
|             search_edit.clear() |             search_edit.clear() | ||||||
|             search_edit.blockSignals(False) |             search_edit.blockSignals(False) | ||||||
|             self.filter_buttons(tab_type) |             self.filter_buttons(tab_type) | ||||||
|  |  | ||||||
|         frame = button_widget.parent() |         frame = button_widget.parent() | ||||||
|         if isinstance(frame, QFrame): |         if isinstance(frame, QFrame): | ||||||
|             QTimer.singleShot(0, lambda: scroll_area.ensureWidgetVisible(frame)) |             QTimer.singleShot(0, lambda: scroll_area.ensureWidgetVisible(frame)) | ||||||
| @@ -4175,13 +4485,22 @@ class WineHelperGUI(QMainWindow): | |||||||
|                 self.install_process.terminate() |                 self.install_process.terminate() | ||||||
|  |  | ||||||
|     def _handle_command_output(self): |     def _handle_command_output(self): | ||||||
|         """Обрабатывает вывод для диалога команды""" |         """Обрабатывает вывод для общих команд в модальном диалоге.""" | ||||||
|         if hasattr(self, 'command_process') and self.command_process: |         if hasattr(self, 'command_process') and self.command_process: | ||||||
|             output = self.command_process.readAllStandardOutput().data().decode('utf-8', errors='ignore').strip() |             # Используем readAll, чтобы получить и stdout, и stderr | ||||||
|  |             output_bytes = self.command_process.readAll() | ||||||
|  |             output = output_bytes.data().decode('utf-8', errors='ignore').strip() | ||||||
|             if output and hasattr(self, 'command_log_output'): |             if output and hasattr(self, 'command_log_output'): | ||||||
|                 self.command_log_output.append(output) |                 self.command_log_output.append(output) | ||||||
|                 QApplication.processEvents() |                 QApplication.processEvents() | ||||||
|  |  | ||||||
|  |     def _run_simple_command(self, command, args=None): | ||||||
|  |         """Запускает простую команду winehelper и выводит лог.""" | ||||||
|  |         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_command_finished) | ||||||
|  |         self.command_process.start(self.winehelper_path, [command] + (args or [])) | ||||||
|     def _handle_command_finished(self, exit_code, exit_status): |     def _handle_command_finished(self, exit_code, exit_status): | ||||||
|         """Обрабатывает завершение для диалога команды""" |         """Обрабатывает завершение для диалога команды""" | ||||||
|         if exit_code == 0: |         if exit_code == 0: | ||||||
| @@ -4282,6 +4601,8 @@ def main(): | |||||||
|         # Сохраняем ссылку на сервер, чтобы он не был удален сборщиком мусора |         # Сохраняем ссылку на сервер, чтобы он не был удален сборщиком мусора | ||||||
|         window.server = server |         window.server = server | ||||||
|         window.show() |         window.show() | ||||||
|  |         # Создаем иконку в системном трее после создания окна | ||||||
|  |         window.create_tray_icon() | ||||||
|         return app.exec_() |         return app.exec_() | ||||||
|  |  | ||||||
|     return 1 |     return 1 | ||||||
|   | |||||||