@@ -5,9 +5,6 @@ import signal
 
		
	
		
			
				import  subprocess  
		
	
		
			
				import  sys  
		
	
		
			
				import  psutil  
		
	
		
			
				import  tarfile  
		
	
		
			
				import  glob  
		
	
		
			
				import  re  
		
	
		
			
				 
		
	
		
			
				from  portprotonqt . logger  import  get_logger  
		
	
		
			
				from  portprotonqt . dialogs  import  AddGameDialog ,  FileExplorer  
		
	
	
		
			
				
					
					
						
					 
				
			
			@@ -41,7 +38,7 @@ from portprotonqt.game_library_manager import GameLibraryManager
 
		
	
		
			
				 
		
	
		
			
				 
		
	
		
			
				from  PySide6 . QtWidgets  import  ( QLineEdit ,  QMainWindow ,  QStatusBar ,  QWidget ,  QVBoxLayout ,  QLabel ,  QHBoxLayout ,  QStackedWidget ,  QComboBox ,  
		
	
		
			
				                               QDialog ,  QFormLayout ,  QFrame ,  QGraphicsDropShadowEffect ,  QMessageBox ,  QApplication ,  QPushButton ,  QProgressBar ,  QCheckBox ,  QSizePolicy ) 
 
		
	
		
			
				                               QDialog ,  QFormLayout ,  QFrame ,  QGraphicsDropShadowEffect ,  QMessageBox ,  QApplication ,  QPushButton ,  QProgressBar ,  QCheckBox ,  QSizePolicy ,  QGridLayout 
 
		
	
		
			
				from  PySide6 . QtCore  import  Qt ,  QAbstractAnimation ,  QUrl ,  Signal ,  QTimer ,  Slot  
		
	
		
			
				from  PySide6 . QtGui  import  QIcon ,  QPixmap ,  QColor ,  QDesktopServices  
		
	
		
			
				from  typing  import  cast  
		
	
	
		
			
				
					
					
						
					 
				
			
			@@ -772,6 +769,7 @@ class MainWindow(QMainWindow):
 
		
	
		
			
				    def  createInstalledTab ( self ) : 
 
		
	
		
			
				        self . gamesLibraryWidget  =  self . game_library_manager . create_games_library_widget ( ) 
 
		
	
		
			
				        self . stackedWidget . addWidget ( self . gamesLibraryWidget ) 
 
		
	
		
			
				        self . gamesListWidget  =  self . game_library_manager . gamesListWidget 
 
		
	
		
			
				        self . game_library_manager . update_game_grid ( ) 
 
		
	
		
			
				 
		
	
		
			
				    def  resizeEvent ( self ,  event ) : 
 
		
	
	
		
			
				
					
					
						
					 
				
			
			@@ -1010,24 +1008,12 @@ class MainWindow(QMainWindow):
 
		
	
		
			
				 
		
	
		
			
				        # Путь к дистрибутивам Wine/Proton 
 
		
	
		
			
				        if  self . portproton_location  is  None : 
 
		
	
		
			
				            content  =  QLabel ( _ ( " PortProton location not set " ) ) 
 
		
	
		
			
				            content . setStyleSheet ( self . theme . CONTENT_STYLE ) 
 
		
	
		
			
				            content . setObjectName ( " tabContent " ) 
 
		
	
		
			
				            layout . addWidget ( content ) 
 
		
	
		
			
				            layout . addStretch ( 1 ) 
 
		
	
		
			
				            self . stackedWidget . addWidget ( self . wineWidget ) 
 
		
	
		
			
				            return 
 
		
	
		
			
				 
		
	
		
			
				        dist_path  =  os . path . join ( self . portproton_location ,  " data " ,  " dist " ) 
 
		
	
		
			
				        prefixes_path  =  os . path . join ( self . portproton_location ,  " data " ,  " prefixes " ) 
 
		
	
		
			
				 
		
	
		
			
				        if  not  os . path . exists ( dist_path ) : 
 
		
	
		
			
				            content  =  QLabel ( _ ( " PortProton data/dist not found " ) ) 
 
		
	
		
			
				            content . setStyleSheet ( self . theme . CONTENT_STYLE ) 
 
		
	
		
			
				            content . setObjectName ( " tabContent " ) 
 
		
	
		
			
				            layout . addWidget ( content ) 
 
		
	
		
			
				            layout . addStretch ( 1 ) 
 
		
	
		
			
				            self . stackedWidget . addWidget ( self . wineWidget ) 
 
		
	
		
			
				            return 
 
		
	
		
			
				 
		
	
		
			
				        # Форма с  
 
		
	
	
		
			
				
					
					
						
					 
				
			
			@@ -1066,9 +1052,10 @@ class MainWindow(QMainWindow):
 
		
	
		
			
				 
		
	
		
			
				        layout . addLayout ( formLayout ) 
 
		
	
		
			
				 
		
	
		
			
				        # Кнопки для стандартных инструментов Wine 
 
		
	
		
			
				        toolsLayout   =  QHBox Layout ( ) 
 
		
	
		
			
				        toolsLayout  . setSpacing ( 10 ) 
 
		
	
		
			
				        # Кнопки для стандартных инструментов Wine в сетке 2x3  
 
		
	
		
			
				        tools_grid   =  QGrid Layout ( ) 
 
		
	
		
			
				        tools_grid  . setSpacing ( 10 ) 
 
		
	
		
			
				        tools_grid . setContentsMargins ( 0 ,  0 ,  0 ,  0 ) 
 
		
	
		
			
				 
		
	
		
			
				        tools  =  [ 
 
		
	
		
			
				            ( " winecfg " ,  _ ( " Wine Configuration " ) ) , 
 
		
	
	
		
			
				
					
					
						
					 
				
			
			@@ -1079,264 +1066,59 @@ class MainWindow(QMainWindow):
 
		
	
		
			
				            ( " cmd " ,  _ ( " Command Prompt " ) ) , 
 
		
	
		
			
				        ] 
 
		
	
		
			
				 
		
	
		
			
				        for  tool_cmd ,  tool_name  in  tools : 
 
		
	
		
			
				            btn =  AutoSizeButton ( tool_name ) 
 
		
	
		
			
				        for  i ,  ( _ tool_cmd,  tool_name ) in  enumerate ( tools ) 
 
		
	
		
			
				            row =  i  / /  3 
 
		
	
		
			
				            col  =  i  %  3 
 
		
	
		
			
				            btn  =  AutoSizeButton ( tool_name ,  update_size = False )   # Отключаем авторазмер для избежания проблем 
 
		
	
		
			
				            btn . setStyleSheet ( self . theme . ACTION_BUTTON_STYLE ) 
 
		
	
		
			
				            btn . setFocusPolicy ( Qt . FocusPolicy . StrongFocus ) 
 
		
	
		
			
				            btn . clicked . connect ( lambda  checked ,  t = tool_cmd : self . run_wine_tool ( t ) ) 
 
		
	
		
			
				            toolsLayout . addWidget ( btn ) 
 
		
	
		
			
				            tools_grid . addWidget ( btn ,  row , col ) 
 
		
	
		
			
				 
		
	
		
			
				        # Растягиваем столбцы равномерно 
 
		
	
		
			
				        for  col  in  range ( 3 ) : 
 
		
	
		
			
				            tools_grid . setColumnStretch ( col ,  1 ) 
 
		
	
		
			
				 
		
	
		
			
				        layout . addLayout ( tools_grid ) 
 
		
	
		
			
				 
		
	
		
			
				        # Дополнительные инструменты в сетке 1x4 или 2x2 если нужно 
 
		
	
		
			
				        additional_grid  =  QGridLayout ( ) 
 
		
	
		
			
				        additional_grid . setSpacing ( 10 ) 
 
		
	
		
			
				        additional_grid . setContentsMargins ( 0 ,  0 ,  0 ,  0 ) 
 
		
	
		
			
				 
		
	
		
			
				        # Wine Uninstaller 
 
		
	
		
			
				        uninstaller_btn  =  AutoSizeButton ( _ ( " Uninstaller " ) ,  update_size = False ) 
 
		
	
		
			
				        uninstaller_btn . setStyleSheet ( self . theme . ACTION_BUTTON_STYLE ) 
 
		
	
		
			
				        uninstaller_btn . setFocusPolicy ( Qt . FocusPolicy . StrongFocus ) 
 
		
	
		
			
				        additional_grid . addWidget ( uninstaller_btn ,  0 ,  0 ) 
 
		
	
		
			
				 
		
	
		
			
				        # Winetricks 
 
		
	
		
			
				        winetricks_btn  =  AutoSizeButton ( _ ( " Winetricks " ) ,  update_size = False ) 
 
		
	
		
			
				        winetricks_btn . setStyleSheet ( self . theme . ACTION_BUTTON_STYLE ) 
 
		
	
		
			
				        winetricks_btn . setFocusPolicy ( Qt . FocusPolicy . StrongFocus ) 
 
		
	
		
			
				        additional_grid . addWidget ( winetricks_btn ,  0 ,  1 ) 
 
		
	
		
			
				 
		
	
		
			
				        # Create Backup 
 
		
	
		
			
				        create_backup_btn  =  AutoSizeButton ( _ ( " Create Prefix Backup " ) ,  update_size = False ) 
 
		
	
		
			
				        create_backup_btn . setStyleSheet ( self . theme . ACTION_BUTTON_STYLE ) 
 
		
	
		
			
				        create_backup_btn . setFocusPolicy ( Qt . FocusPolicy . StrongFocus ) 
 
		
	
		
			
				        additional_grid . addWidget ( create_backup_btn ,  0 ,  2 ) 
 
		
	
		
			
				 
		
	
		
			
				        # Load Backup 
 
		
	
		
			
				        load_backup_btn  =  AutoSizeButton ( _ ( " Load Prefix Backup " ) ,  update_size = False ) 
 
		
	
		
			
				        load_backup_btn . setStyleSheet ( self . theme . ACTION_BUTTON_STYLE ) 
 
		
	
		
			
				        load_backup_btn . setFocusPolicy ( Qt . FocusPolicy . StrongFocus ) 
 
		
	
		
			
				        additional_grid . addWidget ( load_backup_btn ,  0 ,  3 ) 
 
		
	
		
			
				 
		
	
		
			
				        # Растягиваем столбцы равномерно 
 
		
	
		
			
				        for  col  in  range ( 4 ) : 
 
		
	
		
			
				            additional_grid . setColumnStretch ( col ,  1 ) 
 
		
	
		
			
				 
		
	
		
			
				        layout . addLayout ( additional_grid ) 
 
		
	
		
			
				 
		
	
		
			
				        layout . addLayout ( toolsLayout ) 
 
		
	
		
			
				        layout . addStretch ( 1 ) 
 
		
	
		
			
				 
		
	
		
			
				        self . stackedWidget . addWidget ( self . wineWidget ) 
 
		
	
		
			
				 
		
	
		
			
				    def  prepare_wine ( self ,  version ) : 
 
		
	
		
			
				        """ Подготавливает окружение Wine/Proton для выбранной версии. """ 
 
		
	
		
			
				        if  not  version : 
 
		
	
		
			
				            return 
 
		
	
		
			
				 
		
	
		
			
				        if  self . portproton_location  is  None : 
 
		
	
		
			
				            logger . warning ( " PortProton location not set " ) 
 
		
	
		
			
				            return 
 
		
	
		
			
				 
		
	
		
			
				        dist_path  =  os . path . join ( self . portproton_location ,  " data " ,  " dist " ) 
 
		
	
		
			
				        winendir  =  os . path . join ( dist_path ,  version ) 
 
		
	
		
			
				        if  not  os . path . exists ( winendir ) : 
 
		
	
		
			
				            logger . warning ( f " Wine directory not found:  { winendir } " ) 
 
		
	
		
			
				            return 
 
		
	
		
			
				 
		
	
		
			
				        files_dir  =  os . path . join ( winendir ,  " files " ) 
 
		
	
		
			
				        dist_dir  =  os . path . join ( winendir ,  " dist " ) 
 
		
	
		
			
				        proton_tar  =  os . path . join ( winendir ,  " proton_dist.tar " ) 
 
		
	
		
			
				 
		
	
		
			
				        if  os . path . isdir ( files_dir )  and  not  os . path . isdir ( dist_dir ) : 
 
		
	
		
			
				            for  item  in  os . listdir ( winendir ) : 
 
		
	
		
			
				                if  item  not  in  [ " files " ,  " version " ] : 
 
		
	
		
			
				                    item_path  =  os . path . join ( winendir ,  item ) 
 
		
	
		
			
				                    if  os . path . isdir ( item_path ) : 
 
		
	
		
			
				                        shutil . rmtree ( item_path ) 
 
		
	
		
			
				                    else : 
 
		
	
		
			
				                        os . remove ( item_path ) 
 
		
	
		
			
				            if  os . path . exists ( files_dir ) : 
 
		
	
		
			
				                for  item  in  os . listdir ( files_dir ) : 
 
		
	
		
			
				                    shutil . move ( os . path . join ( files_dir ,  item ) ,  winendir ) 
 
		
	
		
			
				                os . rmdir ( files_dir ) 
 
		
	
		
			
				        elif  not  os . path . isdir ( files_dir )  and  os . path . isdir ( dist_dir ) : 
 
		
	
		
			
				            for  item  in  os . listdir ( winendir ) : 
 
		
	
		
			
				                if  item  not  in  [ " dist " ,  " version " ] : 
 
		
	
		
			
				                    item_path  =  os . path . join ( winendir ,  item ) 
 
		
	
		
			
				                    if  os . path . isdir ( item_path ) : 
 
		
	
		
			
				                        shutil . rmtree ( item_path ) 
 
		
	
		
			
				                    else : 
 
		
	
		
			
				                        os . remove ( item_path ) 
 
		
	
		
			
				            if  os . path . exists ( dist_dir ) : 
 
		
	
		
			
				                for  item  in  os . listdir ( dist_dir ) : 
 
		
	
		
			
				                    shutil . move ( os . path . join ( dist_dir ,  item ) ,  winendir ) 
 
		
	
		
			
				                os . rmdir ( dist_dir ) 
 
		
	
		
			
				        elif  os . path . isfile ( proton_tar ) : 
 
		
	
		
			
				            with  tarfile . open ( proton_tar )  as  tar : 
 
		
	
		
			
				                tar . extractall ( winendir ) 
 
		
	
		
			
				            os . remove ( proton_tar ) 
 
		
	
		
			
				            for  item  in  os . listdir ( winendir ) : 
 
		
	
		
			
				                if  item  not  in  [ " bin " ,  " lib " ,  " lib64 " ,  " share " ,  " version " ] : 
 
		
	
		
			
				                    item_path  =  os . path . join ( winendir ,  item ) 
 
		
	
		
			
				                    if  os . path . isdir ( item_path ) : 
 
		
	
		
			
				                        shutil . rmtree ( item_path ) 
 
		
	
		
			
				                    else : 
 
		
	
		
			
				                        os . remove ( item_path ) 
 
		
	
		
			
				 
		
	
		
			
				        if  os . path . exists ( winendir ) : 
 
		
	
		
			
				            # Создать файл version 
 
		
	
		
			
				            version_file  =  os . path . join ( winendir ,  " version " ) 
 
		
	
		
			
				            if  not  os . path . exists ( version_file ) : 
 
		
	
		
			
				                with  open ( version_file ,  " w " )  as  f : 
 
		
	
		
			
				                    f . write ( version ) 
 
		
	
		
			
				 
		
	
		
			
				            # Симлинк lib64/wine 
 
		
	
		
			
				            lib_wine  =  os . path . join ( winendir ,  " lib " ,  " wine " ,  " x86_64-unix " ) 
 
		
	
		
			
				            lib64_wine  =  os . path . join ( winendir ,  " lib64 " ,  " wine " ) 
 
		
	
		
			
				            if  not  os . path . lexists ( lib64_wine )  and  os . path . exists ( lib_wine ) : 
 
		
	
		
			
				                os . makedirs ( os . path . join ( winendir ,  " lib64 " ) ,  exist_ok = True ) 
 
		
	
		
			
				                self . safe_symlink ( os . path . join ( winendir ,  " lib " ,  " wine " ) ,  lib64_wine ) 
 
		
	
		
			
				 
		
	
		
			
				            # Обработка mono и gecko 
 
		
	
		
			
				            tmp_path  =  os . path . join ( self . portproton_location ,  " tmp " ) 
 
		
	
		
			
				            os . makedirs ( tmp_path ,  exist_ok = True ) 
 
		
	
		
			
				            for  component  in  [ " mono " ,  " gecko " ] : 
 
		
	
		
			
				                share_wine_comp  =  os . path . join ( winendir ,  " share " ,  " wine " ,  component ) 
 
		
	
		
			
				                tmp_comp  =  os . path . join ( tmp_path ,  component ) 
 
		
	
		
			
				                if  os . path . lexists ( share_wine_comp )  and  os . path . islink ( share_wine_comp ) : 
 
		
	
		
			
				                    logger . info ( f " { share_wine_comp }  is symlink. OK. " ) 
 
		
	
		
			
				                elif  os . path . isdir ( share_wine_comp ) : 
 
		
	
		
			
				                    self . safe_copytree ( share_wine_comp ,  tmp_comp ) 
 
		
	
		
			
				                    self . safe_rmtree ( share_wine_comp ) 
 
		
	
		
			
				                    self . safe_symlink ( tmp_comp ,  share_wine_comp ) 
 
		
	
		
			
				                    logger . info ( f " Copied  { component }  to tmp and created symlink. OK. " ) 
 
		
	
		
			
				                else : 
 
		
	
		
			
				                    self . safe_rmtree ( share_wine_comp ) 
 
		
	
		
			
				                    if  os . path . exists ( tmp_comp ) : 
 
		
	
		
			
				                        self . safe_symlink ( tmp_comp ,  share_wine_comp ) 
 
		
	
		
			
				                    logger . warning ( f " { share_wine_comp }  is broken symlink. Repaired. " ) 
 
		
	
		
			
				 
		
	
		
			
				            # Модификация wine.inf 
 
		
	
		
			
				            wine_inf  =  os . path . join ( winendir ,  " share " ,  " wine " ,  " wine.inf " ) 
 
		
	
		
			
				            if  os . path . exists ( wine_inf ) : 
 
		
	
		
			
				                with  open ( wine_inf )  as  f : 
 
		
	
		
			
				                    lines  =  f . readlines ( ) 
 
		
	
		
			
				 
		
	
		
			
				                nvidia_uuid  =  ' Global, " { 41FCC608-8496-4DEF-B43E-7D9BD675A6FF} " ,0x10001,0x00000001 ' 
 
		
	
		
			
				                has_nvidia  =  any ( nvidia_uuid  in  line  for  line  in  lines ) 
 
		
	
		
			
				                if  not  has_nvidia : 
 
		
	
		
			
				                    lines . append ( ' HKLM,Software \\ NVIDIA Corporation \\ Global, " { 41FCC608-8496-4DEF-B43E-7D9BD675A6FF} " ,0x10001,0x00000001 \n ' ) 
 
		
	
		
			
				                    lines . append ( ' HKLM,System \\ ControlSet001 \\ Services \\ nvlddmkm, " { 41FCC608-8496-4DEF-B43E-7D9BD675A6FF} " ,0x10001,0x00000001 \n ' ) 
 
		
	
		
			
				 
		
	
		
			
				                new_lines  =  [ ] 
 
		
	
		
			
				                for  line  in  lines : 
 
		
	
		
			
				                    if  ' Steam.exe '  in  line  or  r ' \\ Valve \\ Steam '  in  line  or  ' winemenubuilder '  in  line : 
 
		
	
		
			
				                        continue 
 
		
	
		
			
				                    new_lines . append ( line ) 
 
		
	
		
			
				                lines  =  new_lines 
 
		
	
		
			
				 
		
	
		
			
				                with  open ( wine_inf ,  " w " )  as  f : 
 
		
	
		
			
				                    f . writelines ( lines ) 
 
		
	
		
			
				 
		
	
		
			
				            # Удаление steam и winemenubuilder файлов 
 
		
	
		
			
				            for  libdir  in  [ " lib " ,  " lib64 " ] : 
 
		
	
		
			
				                lib_path  =  os . path . join ( winendir ,  libdir ) 
 
		
	
		
			
				                if  os . path . exists ( lib_path ) : 
 
		
	
		
			
				                    # *steam* 
 
		
	
		
			
				                    for  pattern  in  [ 
 
		
	
		
			
				                        os . path . join ( lib_path ,  " *steam* " ) , 
 
		
	
		
			
				                        os . path . join ( lib_path ,  " wine " ,  " * " ,  " *steam* " ) , 
 
		
	
		
			
				                        os . path . join ( lib_path ,  " wine " ,  " *-windows " ,  " winemenubuilder.exe " ) 
 
		
	
		
			
				                    ] : 
 
		
	
		
			
				                        for  file_path  in  glob . glob ( pattern ,  recursive = True ) : 
 
		
	
		
			
				                            try : 
 
		
	
		
			
				                                os . remove ( file_path ) 
 
		
	
		
			
				                            except  Exception : 
 
		
	
		
			
				                                pass 
 
		
	
		
			
				 
		
	
		
			
				    def  safe_symlink ( self ,  src ,  dst ) : 
 
		
	
		
			
				        """ Создает симлинк, удаляя dst если существует. """ 
 
		
	
		
			
				        if  os . path . exists ( dst ) : 
 
		
	
		
			
				            if  os . path . islink ( dst ) : 
 
		
	
		
			
				                os . remove ( dst ) 
 
		
	
		
			
				            else : 
 
		
	
		
			
				                shutil . rmtree ( dst ) 
 
		
	
		
			
				        os . symlink ( src ,  dst ) 
 
		
	
		
			
				 
		
	
		
			
				    def  safe_copytree ( self ,  src ,  dst ) : 
 
		
	
		
			
				        """ Копирует директорию, удаляя dst если существует. """ 
 
		
	
		
			
				        if  os . path . exists ( dst ) : 
 
		
	
		
			
				            shutil . rmtree ( dst ) 
 
		
	
		
			
				        shutil . copytree ( src ,  dst ) 
 
		
	
		
			
				 
		
	
		
			
				    def  safe_rmtree ( self ,  path ) : 
 
		
	
		
			
				        """ Удаляет директорию если существует. """ 
 
		
	
		
			
				        if  os . path . exists ( path ) : 
 
		
	
		
			
				            shutil . rmtree ( path ) 
 
		
	
		
			
				 
		
	
		
			
				    def  clean_wine_dist_dirs ( self ) : 
 
		
	
		
			
				        """ Normalizes Wine dist directory names to uppercase with underscores. """ 
 
		
	
		
			
				        if  self . portproton_location  is  None : 
 
		
	
		
			
				            return 
 
		
	
		
			
				 
		
	
		
			
				        dist_path  =  os . path . join ( self . portproton_location ,  " data " ,  " dist " ) 
 
		
	
		
			
				        if  not  os . path . exists ( dist_path ) : 
 
		
	
		
			
				            return 
 
		
	
		
			
				        for  entry  in  os . scandir ( dist_path ) : 
 
		
	
		
			
				            if  entry . is_dir ( ) : 
 
		
	
		
			
				                dist_dir  =  entry . name 
 
		
	
		
			
				                dist_dir_stripped  =  re . sub ( r ' \ s+ ' ,  '   ' ,  dist_dir . strip ( ) ) 
 
		
	
		
			
				                dist_dir_new  =  dist_dir_stripped . replace ( '   ' ,  ' _ ' ) . upper ( ) 
 
		
	
		
			
				                if  dist_dir_new  !=  dist_dir : 
 
		
	
		
			
				                    new_path  =  os . path . join ( dist_path ,  dist_dir_new ) 
 
		
	
		
			
				                    if  not  os . path . exists ( new_path ) : 
 
		
	
		
			
				                        try : 
 
		
	
		
			
				                            os . rename ( entry . path ,  new_path ) 
 
		
	
		
			
				                            logger . info ( f " Renamed  { dist_dir }  to  { dist_dir_new } " ) 
 
		
	
		
			
				                        except  Exception  as  e : 
 
		
	
		
			
				                            logger . error ( f " Failed to rename  { dist_dir }  to  { dist_dir_new } :  { e } " ) 
 
		
	
		
			
				 
		
	
		
			
				    def  run_wine_tool ( self ,  tool_cmd :  str ) : 
 
		
	
		
			
				        """ Запускает инструмент Wine с  """ 
 
		
	
		
			
				        version  =  self . wineCombo . currentText ( ) 
 
		
	
		
			
				        prefix  =  self . prefixCombo . currentText ( ) 
 
		
	
		
			
				 
		
	
		
			
				        if  not  version : 
 
		
	
		
			
				            QMessageBox . warning ( self ,  _ ( " Error " ) ,  _ ( " Please select a Wine/Proton version " ) ) 
 
		
	
		
			
				            return 
 
		
	
		
			
				 
		
	
		
			
				        if  not  prefix : 
 
		
	
		
			
				            QMessageBox . warning ( self ,  _ ( " Error " ) ,  _ ( " Please select a prefix " ) ) 
 
		
	
		
			
				            return 
 
		
	
		
			
				 
		
	
		
			
				        if  self . portproton_location  is  None : 
 
		
	
		
			
				            QMessageBox . warning ( self ,  _ ( " Error " ) ,  _ ( " PortProton location not set " ) ) 
 
		
	
		
			
				            return 
 
		
	
		
			
				 
		
	
		
			
				        # Clean and normalize dist directories 
 
		
	
		
			
				        self . clean_wine_dist_dirs ( ) 
 
		
	
		
			
				 
		
	
		
			
				        # Repopulate wineCombo with normalized names 
 
		
	
		
			
				        dist_path  =  os . path . join ( self . portproton_location ,  " data " ,  " dist " ) 
 
		
	
		
			
				        self . wine_versions  =  sorted ( [ d  for  d  in  os . listdir ( dist_path )  if  os . path . isdir ( os . path . join ( dist_path ,  d ) ) ] ) 
 
		
	
		
			
				        self . wineCombo . clear ( ) 
 
		
	
		
			
				        self . wineCombo . addItems ( self . wine_versions ) 
 
		
	
		
			
				 
		
	
		
			
				        # Try to select the normalized original version 
 
		
	
		
			
				        version_normalized  =  version . strip ( ) . replace ( '   ' ,  ' _ ' ) . upper ( ) 
 
		
	
		
			
				        index  =  self . wineCombo . findText ( version_normalized ) 
 
		
	
		
			
				        if  index  !=  - 1 : 
 
		
	
		
			
				            self . wineCombo . setCurrentIndex ( index ) 
 
		
	
		
			
				            version  =  version_normalized 
 
		
	
		
			
				        elif  self . wine_versions : 
 
		
	
		
			
				            self . wineCombo . setCurrentIndex ( 0 ) 
 
		
	
		
			
				            version  =  self . wine_versions [ 0 ] 
 
		
	
		
			
				        else : 
 
		
	
		
			
				            QMessageBox . warning ( self ,  _ ( " Error " ) ,  _ ( " No Wine versions found after cleaning " ) ) 
 
		
	
		
			
				            return 
 
		
	
		
			
				 
		
	
		
			
				        # Prepare Wine for the (possibly updated) version 
 
		
	
		
			
				        self . prepare_wine ( version ) 
 
		
	
		
			
				 
		
	
		
			
				        prefixes_path  =  os . path . join ( self . portproton_location ,  " data " ,  " prefixes " ) 
 
		
	
		
			
				        winendir  =  os . path . join ( dist_path ,  version ) 
 
		
	
		
			
				        wine_bin  =  os . path . join ( winendir ,  " bin " ,  " wine " ) 
 
		
	
		
			
				        wineserver_bin  =  os . path . join ( winendir ,  " bin " ,  " wineserver " ) 
 
		
	
		
			
				 
		
	
		
			
				        if  not  os . path . exists ( wine_bin ) : 
 
		
	
		
			
				            QMessageBox . warning ( self ,  _ ( " Error " ) ,  _ ( " Wine binary not found:  {} " ) . format ( wine_bin ) ) 
 
		
	
		
			
				            return 
 
		
	
		
			
				 
		
	
		
			
				        prefix_dir  =  os . path . join ( prefixes_path ,  prefix ) 
 
		
	
		
			
				        if  not  os . path . exists ( prefix_dir ) : 
 
		
	
		
			
				            QMessageBox . warning ( self ,  _ ( " Error " ) ,  _ ( " Prefix not found:  {} " ) . format ( prefix_dir ) ) 
 
		
	
		
			
				            return 
 
		
	
		
			
				 
		
	
		
			
				        env  =  os . environ . copy ( ) 
 
		
	
		
			
				        env [ ' WINEPREFIX ' ]  =  prefix_dir 
 
		
	
		
			
				        env [ ' WINEDIR ' ]  =  winendir 
 
		
	
		
			
				        env [ ' WINE ' ]  =  wine_bin 
 
		
	
		
			
				        env [ ' WINELOADER ' ]  =  wine_bin 
 
		
	
		
			
				        env [ ' WINESERVER ' ]  =  wineserver_bin 
 
		
	
		
			
				        env [ ' WINEDEBUG ' ]  =  ' -all ' 
 
		
	
		
			
				        env [ ' WINEDLLOVERRIDES ' ]  =  " steam_api,steam_api64,steamclient,steamclient64=n;dotnetfx35.exe,dotnetfx35setup.exe=b;winemenubuilder.exe=;mscoree= " 
 
		
	
		
			
				 
		
	
		
			
				        try : 
 
		
	
		
			
				            if  tool_cmd  ==  " cmd " : 
 
		
	
		
			
				                # Open Command Prompt in a separate terminal 
 
		
	
		
			
				                term_cmd  =  [ " x-terminal-emulator " ,  " -e " ,  wine_bin ,  tool_cmd ] 
 
		
	
		
			
				                subprocess . Popen ( term_cmd ,  env = env ,  start_new_session = True ) 
 
		
	
		
			
				            else : 
 
		
	
		
			
				                cmd  =  [ wine_bin ,  tool_cmd ] 
 
		
	
		
			
				                subprocess . Popen ( cmd ,  env = env ,  start_new_session = True ) 
 
		
	
		
			
				            self . statusBar ( ) . showMessage ( _ ( " Launched  {}  for prefix  {} " ) . format ( tool_cmd ,  prefix ) ,  3000 ) 
 
		
	
		
			
				        except  Exception  as  e : 
 
		
	
		
			
				            logger . error ( f " Failed to launch  { tool_cmd } :  { e } " ) 
 
		
	
		
			
				            QMessageBox . warning ( self ,  _ ( " Error " ) ,  _ ( " Failed to launch  {} :  {} " ) . format ( tool_cmd ,  str ( e ) ) ) 
 
		
	
		
			
				 
		
	
		
			
				    def  createPortProtonTab ( self ) : 
 
		
	
		
			
				        """ Вкладка  ' PortProton Settings ' . """ 
 
		
	
		
			
				        self . portProtonWidget  =  QWidget ( )