#!/usr/bin/env python3
# 使用系统默认的 python3 运行
#################################################################################################################
# 作者:gfdgd xi
# 版本:3.0.0
# 更新时间:2022年12月10日
# 感谢:感谢 wine、deepin-wine 以及星火团队,提供了 wine、deepin-wine、spark-wine-devel 给大家使用,让我能做这个程序
# 基于 Python3 的 PyQt5 构建
#################################################################################################################
#################
# 引入所需的库
#################
import os
import sys
import time
import json
import random
import base64
import shutil
import hashlib
import platform
import pyperclip
import threading
import traceback
import webbrowser
import updatekiller
import subprocess
import req as requests
import urllib.parse as parse
try:
import PyQt5.QtGui as QtGui
except:
os.system("python3 -m pip install --upgrade pyqt5 --trusted-host https://repo.huaweicloud.com -i https://repo.huaweicloud.com/repository/pypi/simple")
os.system("python3 -m pip install --upgrade pyqt5 --trusted-host https://repo.huaweicloud.com -i https://repo.huaweicloud.com/repository/pypi/simple --break-system-packages")
import PyQt5.QtGui as QtGui
import PyQt5.QtCore as QtCore
import PyQt5.QtWidgets as QtWidgets
try:
import PyQt5.QtWebEngineWidgets as QtWebEngineWidgets
bad = False
except:
threading.Thread(target=os.system, args=["python3 -m pip install --upgrade PyQtWebEngine --trusted-host https://repo.huaweicloud.com -i https://repo.huaweicloud.com/repository/pypi/simple"]).start()
threading.Thread(target=os.system, args=["python3 -m pip install --upgrade PyQtWebEngine --trusted-host https://repo.huaweicloud.com -i https://repo.huaweicloud.com/repository/pypi/simple --break-system-packages"]).start()
bad = True
from trans import *
from Model import *
from DefaultSetting import *
def PythonLower():
app = QtWidgets.QApplication(sys.argv)
QtWidgets.QMessageBox.critical(None, "错误", "Python 至少需要 3.6 及以上版本,目前版本:" + platform.python_version() + "")
sys.exit(1)
# Python 版本检测,因为 f-string 格式化要至少 Python 3.6 及以上的版本,所以需要检测
# 判断主版本号
if sys.version_info[0] < 3:
PythonLower()
if sys.version_info[1] < 6:
PythonLower()
###################
# 程序所需事件
###################
def MiniMode(mode):
for i in [sparkWineSetting, qemuMenu, installLib, log, safeWebsize,
checkValue, virtualMachine, killProgram, killBottonProgram,
fontAppStore, wineConfig, trasButton, button5,
saveDesktopFileOnLauncher, label_r_2, combobox1,
leftDown]:
i.setVisible(not mode)
# 打开程序官网
def OpenProgramURL():
webbrowser.open_new_tab(programUrl)
# 读取文本文档
def readtxt(path):
f = open(path, "r") # 设置文件对象
str = f.read() # 获取内容
f.close() # 关闭文本对象
return str # 返回结果
# 写入文本文档
def write_txt(path, things):
file = open(path, 'w', encoding='UTF-8') # 设置文件对象
file.write(things) # 写入文本
file.close() # 关闭文本对象
# 获取用户桌面目录
def get_desktop_path():
for line in open(get_home() + "/.config/user-dirs.dirs"): # 以行来读取配置文件
desktop_index = line.find("XDG_DESKTOP_DIR=\"") # 寻找是否有对应项,有返回 0,没有返回 -1
if desktop_index != -1: # 如果有对应项
break # 结束循环
if desktop_index == -1: # 如果是提前结束,值一定≠-1,如果是没有提前结束,值一定=-1
return -1
else:
get = line[17:-2] # 截取桌面目录路径
get_index = get.find("$HOME") # 寻找是否有对应的项,需要替换内容
if get != -1: # 如果有
get = get.replace("$HOME", get_home()) # 则把其替换为用户目录(~)
return get # 返回目录
# 获取用户主目录
def get_home():
return os.path.expanduser('~')
# 第一个浏览按钮事件
def liulanbutton():
path = QtWidgets.QFileDialog.getExistingDirectory(widget, "选择 wine 容器", json.loads(readtxt(get_home() + "/.config/deepin-wine-runner/WineBotton.json"))["path"])
if path != "" and path != "()":
e1.setEditText(path)
write_txt(get_home() + "/.config/deepin-wine-runner/WineBotton.json", json.dumps({"path": path})) # 写入配置文件
# 第二个浏览按钮事件
def liulanexebutton():
path = QtWidgets.QFileDialog.getOpenFileName(widget, "选择 exe 可执行文件", json.loads(readtxt(get_home() + "/.config/deepin-wine-runner/FindExe.json"))["path"], "exe 可执行文件(*.exe);;MSI 文件(*.msi);;所有文件(*.*)")
if path != "" and path != "()":
e2.setEditText(path[0]) # 显示路径
write_txt(get_home() + "/.config/deepin-wine-runner/FindExe.json", json.dumps({"path": os.path.dirname(path[0])})) # 写入配置文件
run = None
# 使用多线程运行可执行文件
def runexebutton(self):
global run
DisableButton(True)
if not CheckProgramIsInstall(wine[o1.currentText()]) and not o1.currentText() in untipsWine:
if QtWidgets.QMessageBox.question(widget, "提示", "检查到您未安装这个 wine,是否继续使用这个 wine 运行?") == QtWidgets.QMessageBox.No:
DisableButton(False)
return
if e2.currentText() == "": # 判断文本框是否有内容
QtWidgets.QMessageBox.information(widget, "提示", "没有填写需要使用的 exe 应用")
DisableButton(False)
return
returnText.setText("")
run = Runexebutton_threading()
run.signal.connect(QT.ShowWineReturn)
run.showHistory.connect(QT.ShowHistory)
run.start()
class QT:
message = None
def ShowWineReturn(things):
returnText.insertPlainText(things)
def ShowHistory(temp):
e1.clear()
e2.clear()
e2.addItems(wineBottonHistory)
e2.setEditText(wineBottonHistory[-1])
e1.addItems(findExeHistory)
e1.setEditText(findExeHistory[-1])
repairList = []
# Flag: 日志推断解决方案功能
class LogChecking():
def ShowWindow():
global logThread
global logWindow
global questionList
global repairButton
logWindow = QtWidgets.QWidget()
logWindowLayout = QtWidgets.QGridLayout()
questionList = QtWidgets.QListView()
repairButton = QtWidgets.QPushButton("一键修复")
repairButton.setDisabled(True)
repairButton.clicked.connect(LogChecking.RepairButton)
nmodel = QtGui.QStandardItemModel(window)
item = QtGui.QStandardItem("正在分析中……")
questionList.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
nmodel.appendRow(item)
questionList.setModel(nmodel)
logWindowLayout.addWidget(questionList, 0, 0, 3, 1)
logWindowLayout.addWidget(repairButton, 0, 2, 1, 1)
logWindow.setWindowTitle("分析日志")
logWindow.setLayout(logWindowLayout)
logThread = LogThreading()
logThread.done.connect(LogChecking.Show)
logThread.start()
logWindow.setWindowIcon(QtGui.QIcon(f"{programPath}/deepin-wine-runner.svg"))
logWindow.resize(int(logWindow.frameGeometry().width() * 1.2), int(logWindow.frameGeometry().height() * 1.2))
logWindow.show()
def RepairButton():
index = questionList.currentIndex().row()
lists = questionMap[index]
print(f"{programPath}/CheckDLL/bash/{lists[1].lower()}.sh")
if lists[0] == 1 and os.path.exists(f"{programPath}/CheckDLL/bash/{lists[1].lower()}.sh"):
OpenTerminal(f"'{programPath}/AutoShell/main.py' '{programPath}/CheckDLL/bash/{lists[1].lower()}.sh'")
return
if lists[0] == 2:
QtWidgets.QMessageBox.information(logWindow, "修复方法", "切换其它 Wine")
return
if lists[0] == 4:
QtWidgets.QMessageBox.information(logWindow, "修复方法", "如是 Deepin Wine 可以尝试切换 WineHQ,\n并且取消勾选运行器主页面菜单栏“程序”=>“设置Wine”,取消勾选“屏蔽 Wine 默认 Mono 和 Gecko 安装器”\n然后尝试在菜单栏的“Wine”=>“在指定 Wine、容器安装组件”=>“在指定 Wine、容器安装 Gecko”来安装 Gecko")
return
if lists[0] == 5:
InstallMonoGecko("mono")
return
QtWidgets.QMessageBox.critical(logWindow, "错误", "无法修复该问题")
def Show(lists):
global questionMap
nmodel = QtGui.QStandardItemModel(window)
disbledButton = False
print(lists)
if not len(lists):
nmodel.appendRow(QtGui.QStandardItem(f"√ 无法分析到错误"))
disbledButton = True
for i in lists:
if i[0] == 0:
nmodel.appendRow(QtGui.QStandardItem(f"√ 无法分析到错误"))
disbledButton = True
break
if i[0] == 1:
nmodel.appendRow(QtGui.QStandardItem(f"× 无法调用 Dll:{i[1]}"))
if i[0] == 2:
nmodel.appendRow(QtGui.QStandardItem(f"× 尝试用 Mono 运行非 .net 应用 {i[1]}?"))
if i[0] == 3:
nmodel.appendRow(QtGui.QStandardItem(f"! 无法加载 Gecko,是被禁用或未安装?"))
if i[0] == 4:
nmodel.appendRow(QtGui.QStandardItem(f"× 无法更新 Wine 容器版本,是否还有 Wine 程序运行?"))
if i[0] == 5:
nmodel.appendRow(QtGui.QStandardItem(f"× Mono 禁用/未安装"))
questionMap = lists[:]
repairButton.setDisabled(disbledButton)
questionList.setModel(nmodel)
class LogThreading(QtCore.QThread):
done = QtCore.pyqtSignal(list)
def __init__(self):
super().__init__()
def run(self):
global logText
repairList = []
logText = returnText.toPlainText()
print(logText.splitlines())
for i in logText.splitlines():
print(i)
checkingText = i.lower()
if "err:module:import_dll Library".lower() in checkingText:
# Lose Dll
repairList.append([1, i[i.index("Library") + 8: i.index("(")].strip()])
continue
if "err:module:fixup_imports_ilonly".lower() in checkingText:
# Lose Dll
repairList.append([1, i[i.index("_ilonly") + 8: i.index("not")].strip()])
continue
if "Cannot open assembly".lower() in checkingText and ": File does not contain a valid CIL image.".lower() in checkingText:
# Mono
repairList.append([2, i.replace(": File does not contain a valid CIL image.", "").replace("Cannot open assembly", "").strip()[1: -1]])
if "Could not load wine-gecko. HTML rendering will be disabled.".lower() in checkingText and "Could not find Wine Gecko. HTML rendering will be disabled.".lower() in checkingText:
# Disbled Gecko
repairList.append([3, ""])
if "Your wineserver binary was not upgraded correctly".lower() in checkingText:
repairList.append([4, ""])
if "Wine Mono is not installed".lower() in checkingText:
repairList.append([5, ""])
self.done.emit(repairList)
def DisableButton(things):
button_r_6.setDisabled(things)
button1.setDisabled(things)
button2.setDisabled(things)
button3.setDisabled(things)
wineConfig.setDisabled(things)
e1.setDisabled(things)
e2.setDisabled(things)
o1.setDisabled(things)
miniAppStore.setDisabled(things)
#winetricksOpen.configure(state=a[things])
getProgramIcon.setDisabled(things)
uninstallProgram.setDisabled(things)
trasButton.setDisabled(things)
def CheckProgramIsInstall(program):
return not bool(os.system(f"which '{program}'"))
class Runexebutton_threading(QtCore.QThread):
signal = QtCore.pyqtSignal(str)
showHistory = QtCore.pyqtSignal(str)
def __init__(self):
super().__init__()
def run(self):
global lastRunCommand
if e1.currentText() == "":
wineBottonPath = setting["DefultBotton"]
else:
wineBottonPath = e1.currentText()
option = ""
if setting["Architecture"] != "Auto":
option += f"WINEARCH={setting['Architecture']} "
if setting["MonoGeckoInstaller"]:
option += f"WINEDLLOVERRIDES=\"mscoree,mshtml=\" "
if not setting["Debug"]:
option += "WINEDEBUG=-all "
else:
option += "WINEDEBUG=FIXME,ERR,WARN,TRACE,Message "
wineUsingOption = ""
exePath = e2.currentText()
if True:
fileName = [".exe"]
changePath = False
for i in fileName:
if i in exePath:
print(i)
print(exePath)
l = exePath.index(i)
exePath = f"{exePath[:l+4]}' {exePath[l+4:]} '"
print(l)
print(exePath)
changePath = True
break
#if not changePath and not os.path.exists(changePath):
if not changePath and not os.path.exists(exePath):
# 删除前后无用空格以防止出现问题
print(exePath)
exePath = exePath.strip()
# 有空格再说
if " " in exePath:
l = exePath.index(" ")
exePath = f"{exePath[:l]}' {exePath[l:]} '"
print(l)
#print(i)
print(exePath)
if o1.currentText() == "基于 UOS exagear 的 deepin-wine6-stable" or o1.currentText() == "基于 UOS box86 的 deepin-wine6-stable":
wineUsingOption = ""
if o1.currentText() == "基于 UOS box86 的 deepin-wine6-stable" or o1.currentText() == "基于 UOS exagear 的 deepin-wine6-stable":
if not os.path.exists(f"{programPath}/dlls-arm"):
if os.system(f"7z x -y \"{programPath}/dlls-arm.7z\" -o\"{programPath}\""):
QtWidgets.QMessageBox.critical(widget, "错误", "无法解压资源")
return
os.remove(f"{programPath}/dlls-arm.7z")
if setting["TerminalOpen"]:
res = ""
if e2.currentText()[-4:] == ".msi" and os.path.exists(e2.currentText()):
runCommand = "env WINEPREFIX='" + wineBottonPath + "' " + option + wine[o1.currentText()] + " msiexec /i '" + e2.currentText() + "' " + setting["WineOption"]
OpenTerminal(runCommand)
elif e2.currentText()[-4:] == ".bat" and os.path.exists(e2.currentText()):
runCommand = "env WINEPREFIX='" + wineBottonPath + "' " + option + wine[o1.currentText()] + " wineconsole '" + e2.currentText() + "' " + setting["WineOption"]
OpenTerminal(runCommand)
else:
runCommand = "env WINEPREFIX='" + wineBottonPath + "' " + option + wine[o1.currentText()] + " '" + exePath + "' " + setting["WineOption"]
OpenTerminal(runCommand)
#res = subprocess.Popen([f"'{programPath}/launch.sh' deepin-terminal -C \"WINEPREFIX='" + wineBottonPath + "' " + option + wine[o1.currentText()] + " '" + e2.currentText() + "' " + setting["WineOption"] + "\" --keep-open" + wineUsingOption], shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
else:
if e2.currentText()[-4:] == ".msi" and os.path.exists(e2.currentText()):
runCommand = "WINEPREFIX='" + wineBottonPath + "' " + option + wine[o1.currentText()] + " msiexec /i '" + e2.currentText() + "' " + setting["WineOption"]
res = subprocess.Popen([runCommand], shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
elif e2.currentText()[-4:] == ".bat" and os.path.exists(e2.currentText()):
runCommand = "WINEPREFIX='" + wineBottonPath + "' " + option + wine[o1.currentText()] + " wineconsole '" + e2.currentText() + "' " + setting["WineOption"]
res = subprocess.Popen([runCommand], shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
else:
runCommand = "WINEPREFIX='" + wineBottonPath + "' " + option + wine[o1.currentText()] + " '" + exePath + "' " + setting["WineOption"]
print(["WINEPREFIX='" + wineBottonPath + "' " + option + wine[o1.currentText()] + " '" + exePath + "' " + setting["WineOption"]])
res = subprocess.Popen([runCommand], shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
# 实时读取程序返回
#
print(runCommand)
lastRunCommand = runCommand
if not setting["TerminalOpen"]:
while res.poll() is None:
try:
text = res.stdout.readline().decode("utf8")
except:
text = ""
self.signal.emit(text)
print(text, end="")
if len(findExeHistory) == 0 or findExeHistory[-1] != wineBottonPath:
findExeHistory.append(wineBottonPath) # 将记录写进数组
write_txt(get_home() + "/.config/deepin-wine-runner/FindExeHistory.json", str(json.dumps(ListToDictionary(findExeHistory)))) # 将历史记录的数组转换为字典并写入
if len(wineBottonHistory) == 0 or wineBottonHistory[-1] != e2.currentText():
wineBottonHistory.append(e2.currentText()) # 将记录写进数组
write_txt(get_home() + "/.config/deepin-wine-runner/WineBottonHistory.json", str(json.dumps(ListToDictionary(wineBottonHistory)))) # 将历史记录的数组转换为字典并写入
self.showHistory.emit("")
# 针对 QQ、TIM 安装后不会生成 lnk 的问题,由程序读取以及自动创建
# 判断是否安装了 QQ/TIM
for i in iconListUnBuild:
if os.path.exists(i[1].replace("wineBottonPath", wineBottonPath)):
if not os.path.exists(f"{get_home()}/.local/share/applications/wine/{i[0]}-{os.path.basename(wineBottonPath)}.desktop"):
print("图标不存在,创建图标")
# 图标不存在
# 写入 .desktop 文件
try:
os.system(f"mkdir -p '{get_home()}/.local/share/applications/wine'")
name = i[0]
if setting["BuildByBottleName"]:
name = f"{i[0]}——{os.path.basename(wineBottonPath)}"
write_txt(f"{get_home()}/.local/share/applications/wine/{i[0]}-{os.path.basename(wineBottonPath)}.desktop", f'''[Desktop Entry]
Name={name}
Exec=env WINEPREFIX='{wineBottonPath}' {option} {wine[o1.currentText()]} '{i[1].replace("wineBottonPath", wineBottonPath)}' {setting["WineOption"]} {wineUsingOption}
Icon={programPath}/Icon/{i[0]}.svg
Type=Application
StartupNotify=true''')
except:
# 写入不进去就别写入了,当什么事情都没发生就行
traceback.print_exc()
DisableButton(False)
class Temp:
webWindow = None
#QtCore.QUrl().url()
# 显示“关于这个程序”窗口
def about_this_program()->"显示“关于这个程序”窗口":
global about
global title
global iconPath
global clickIconTime
clickIconTime = 0
QT.message = QtWidgets.QMainWindow()
QT.message.setWindowIcon(QtGui.QIcon(iconPath))
messageWidget = QtWidgets.QWidget()
messageWidget.setObjectName("messageWidget")
messageWidget.setStyleSheet(f"QWidget#messageWidget {{background: url({programPath}/Icon/Program/about-background.png) no-repeat;background-position: left bottom;}}")
QT.message.setWindowTitle(f"关于 {title}")
messageLayout = QtWidgets.QGridLayout()
iconShow = QtWidgets.QLabel(f"")
def ChangeIcon():
global clickIconTime
if clickIconTime >= 0:
clickIconTime = clickIconTime + 1
if clickIconTime > 0:
clickIconTime = -1
for k in ["", "Function", "Program"]:
try:
for i in os.listdir(f"{programPath}/Icon/{k}"):
if i[-4:] == ".svg" or i[-4:] == ".png":
iconPathList.append(f"{programPath}/Icon/{k}/{i}")
except:
traceback.print_exec()
randomNumber = random.randint(0, len(iconPathList) - 1)
iconShow.setText(f"
{randomNumber + 1}/{len(iconPathList)}
") iconShow.linkActivated.connect(ChangeIcon) messageLayout.addWidget(iconShow, 0, 0, 1, 1, QtCore.Qt.AlignTop) aboutInfo = QtWidgets.QTextBrowser(messageWidget) aboutInfo.setFocusPolicy(QtCore.Qt.NoFocus) #aboutInfo.copyAvailable.connect(lambda: print("b")) aboutInfo.anchorClicked.connect(OpenUrl) aboutInfo.setOpenLinks(False) aboutInfo.setHtml(about) aboutInfo.setOpenExternalLinks(False) messageLayout.addWidget(aboutInfo, 0, 1, 1, 1) ok = QtWidgets.QPushButton(QtCore.QCoreApplication.translate("U", "确定")) ok.clicked.connect(QT.message.close) messageLayout.addWidget(ok, 1, 1, 1, 1, QtCore.Qt.AlignBottom | QtCore.Qt.AlignRight) messageWidget.setLayout(messageLayout) QT.message.setCentralWidget(messageWidget) QT.message.resize(int(messageWidget.frameGeometry().width() * 1.5), int(messageWidget.frameGeometry().height() * 1.5)) QT.message.show() # 显示“提示”窗口 def helps(): global tips QtWidgets.QMessageBox.information(widget, "提示", tips) # 显示更新内容窗口 def UpdateThings(): QtWidgets.QMessageBox.information(widget, "更新内容", updateThings) # 生成 desktop 文件在启动器 def make_desktop_on_launcher(): try: if combobox1.currentText() == "" or e2.currentText() == "": # 判断文本框是否有内容 QtWidgets.QMessageBox.information(widget, "提示", "没有填写需要使用 exe 应用或保存的文件名") return if not CheckProgramIsInstall(wine[o1.currentText()]) and not o1.currentText() in untipsWine: if QtWidgets.QMessageBox.question(widget, "提示", "检查到您未安装这个 wine,是否继续使用这个 wine 写入?") == QtWidgets.QMessageBox.No: DisableButton(False) return else: # 如果都有 if os.path.exists(get_home() + "/.local/share/applications/" + combobox1.currentText() + ".desktop"): # 判断目录是否有该文件,如果有 choose = QtWidgets.QMessageBox.question(widget, "提示", "文件已经存在,是否覆盖?") == QtWidgets.QMessageBox.Yes if choose: # 如要覆盖 os.remove(get_home() + "/.local/share/applications/" + combobox1.currentText() + ".desktop") # 删除该文件 else: # 如不覆盖 return # 结束 if e1.currentText() == "": wineBottonPath = setting["DefultBotton"] else: wineBottonPath = e1.currentText() option = "" if setting["Architecture"] != "Auto": option += f"WINEARCH={setting['Architecture']} " if not setting["Debug"]: option += "WINEDEBUG=-all " else: option += "WINEDEBUG=FIXME,ERR,WARN,TRACE,Message " wineUsingOption = "" if o1.currentText() == "基于 UOS box86 的 deepin-wine6-stable" or o1.currentText() == "基于 UOS exagear 的 deepin-wine6-stable": if not os.path.exists(f"{programPath}/dlls-arm"): if os.system(f"7z x -y \"{programPath}/dlls-arm.7z\" -o\"{programPath}\""): QtWidgets.QMessageBox.critical(widget, "错误", "无法解压资源") return os.remove(f"{programPath}/dlls-arm.7z") if o1.currentText() == "基于 UOS exagear 的 deepin-wine6-stable" or o1.currentText() == "基于 UOS box86 的 deepin-wine6-stable": wineUsingOption = "" value = "" if e2.currentText()[:2].upper() == "C:": value = f"{wineBottonPath}/drive_c/{e2.currentText()[2:]}".replace("\\", "/").replace("//", "/") print(value) iconPaths = iconPath for i in iconList: listValue = i[1].replace("wineBottonPath", wineBottonPath) if listValue == e2.currentText() or listValue == value: # 如果路径相同,即可以用程序对应的图标 iconPaths = f"{programPath}/Icon/{i[0]}.svg" # 读到了就不需要再读取了 break os.system(f"mkdir -p '{get_home()}/.local/share/applications/wine'") write_txt(get_home() + "/.local/share/applications/wine/" + combobox1.currentText() + ".desktop", f'''[Desktop Entry] Name={combobox1.currentText()} Exec=env WINEPREFIX='{wineBottonPath}' {option} {wine[o1.currentText()]} '{e2.currentText()}' {setting["WineOption"]} {wineUsingOption} Icon={iconPaths} Type=Application StartupNotify=true''') # 写入文本文档 if len(shellHistory) == 0 or shellHistory[-1] != combobox1.currentText(): shellHistory.append(combobox1.currentText()) # 将记录写进数组 write_txt(get_home() + "/.config/deepin-wine-runner/ShellHistory.json", str(json.dumps(ListToDictionary(shellHistory)))) # 将历史记录的数组转换为字典并写入 combobox1.clear() combobox1.addItems(shellHistory) QtWidgets.QMessageBox.information(widget, "提示", "生成完成!") # 显示完成对话框 except: traceback.print_exc() QtWidgets.QMessageBox.critical(widget, "错误", f"快捷方式创建失败,错误如下:\n{traceback.format_exc()}") def ConfigQemu(): lists = [] for i in qemuBottleList: lists.append(f"{i[0]}/{i[1]}") choose = QtWidgets.QInputDialog.getItem(window, "提示", "选择需要 Chroot 到里面的容器", lists, 0, False) if not choose[1]: return threading.Thread(target=OpenTerminal, args=[f"python3 '{programPath}/QemuRun.py' '{choose[0]}' '{int(setting['QemuUnMountHome'])}' "]).start() print(choose) # 生成 desktop 文件在桌面 # (第四个按钮的事件) def make_desktop_on_desktop(): try: if combobox1.currentText() == "" or e2.currentText() == "": # 判断文本框是否有内容 QtWidgets.QMessageBox.information(widget, "提示", "没有填写需要使用 exe 应用或保存的文件名") return if not CheckProgramIsInstall(wine[o1.currentText()]) and not o1.currentText() in untipsWine: if QtWidgets.QMessageBox.question(widget, "提示", "检查到您未安装这个 wine,是否继续使用这个 wine 写入?") == QtWidgets.QMessageBox.No: DisableButton(False) return else: # 如果都有 if os.path.exists(get_desktop_path() + "/" + combobox1.currentText() + ".desktop"): # 判断目录是否有该文件,如果有 choose = QtWidgets.QMessageBox.question(widget, "提示", "文件已经存在,是否覆盖?") == QtWidgets.QMessageBox.Yes if choose: # 如要覆盖 os.remove(get_desktop_path() + "/" + combobox1.currentText() + ".desktop") # 删除该文件 else: # 如不覆盖 return # 结束 if e1.currentText() == "": wineBottonPath = setting["DefultBotton"] else: wineBottonPath = e1.currentText() wineUsingOption = "" if o1.currentText() == "基于 UOS exagear 的 deepin-wine6-stable" or o1.currentText() == "基于 UOS box86 的 deepin-wine6-stable": wineUsingOption = "" if o1.currentText() == "基于 UOS box86 的 deepin-wine6-stable" or o1.currentText() == "基于 UOS exagear 的 deepin-wine6-stable": if not os.path.exists(f"{programPath}/dlls-arm"): if os.system(f"7z x -y \"{programPath}/dlls-arm.7z\" -o\"{programPath}\""): QtWidgets.QMessageBox.critical(widget, "错误", "无法解压资源") return os.remove(f"{programPath}/dlls-arm.7z") if not os.path.exists(get_desktop_path()): os.makedirs(get_home()) os.mknod(get_desktop_path() + "/" + combobox1.currentText() + ".desktop") option = "" if setting["Architecture"] != "Auto": option += f"WINEARCH={setting['Architecture']} " if not setting["Debug"]: option += "WINEDEBUG=-all " value = "" if e2.currentText()[:2].upper() == "C:": value = f"{wineBottonPath}/drive_c/{e2.currentText()[2:]}".replace("\\", "/").replace("//", "/") print(value) iconPaths = iconPath for i in iconList: listValue = i[1].replace("wineBottonPath", wineBottonPath) if listValue == e2.currentText() or listValue == value: # 如果路径相同,即可以用程序对应的图标 iconPaths = f"{programPath}/Icon/{i[0]}.svg" # 读到了就不需要再读取了 break os.system(f"mkdir -p '{get_home()}/.local/share/applications/wine'") write_txt(get_desktop_path() + "/" + combobox1.currentText() + ".desktop", f'''[Desktop Entry] Name={combobox1.currentText()} Exec=env WINEPREFIX='{wineBottonPath}' {option} {wine[o1.currentText()]} '{e2.currentText()}' {setting["WineOption"]} {wineUsingOption} Icon={iconPaths} Type=Application StartupNotify=true''') # 写入文本文档 if len(shellHistory) == 0 or shellHistory[-1] != combobox1.currentText(): shellHistory.append(combobox1.currentText()) # 将记录写进数组 write_txt(get_home() + "/.config/deepin-wine-runner/ShellHistory.json", str(json.dumps(ListToDictionary(shellHistory)))) # 将历史记录的数组转换为字典并写入 combobox1.clear() combobox1.addItems(shellHistory) QtWidgets.QMessageBox.information(widget, "提示", "生成完成!") # 显示完成对话框 except: traceback.print_exc() QtWidgets.QMessageBox.critical(widget, "错误", f"快捷方式创建失败,错误如下:\n{traceback.format_exc()}") # 数组转字典 def ListToDictionary(list): dictionary = {} for i in range(len(list)): dictionary[i] = list[i] return dictionary def CleanProgramHistory(): if QtWidgets.QMessageBox.question(widget, "警告", "删除后将无法恢复,你确定吗?\n删除后软件将会自动重启。") == QtWidgets.QMessageBox.Yes: try: shutil.rmtree(get_home() + "/.config/deepin-wine-runner") except: traceback.print_exc() QtWidgets.QMessageBox.critical(widget, "错误", traceback.format_exc()) ReStartProgram() def CleanProgramCache(): try: shutil.rmtree(get_home() + "/.cache/deepin-wine-runner") QtWidgets.QMessageBox.information(widget, "提示", "缓存清理完毕!") except: traceback.print_exc() QtWidgets.QMessageBox.critical(widget, "错误", traceback.format_exc()) def SetFont(size): font = QtGui.QFont(defaultFont) if size == 1: app.setFont(defaultFont) return font.setPixelSize(int(defaultFont.pixelSize() / size)) font.setPointSize(int(defaultFont.pointSize() / size)) app.setFont(font) # 重启本应用程序 def ReStartProgram(): python = sys.executable os.execl(python, python, * sys.argv) def KillAllProgram(): pass def KillProgram(): os.system(f"killall {wine[o1.currentText()]} -9") os.system("killall winedbg -9") exeName = os.path.basename(e2.currentText()) os.system(f"killall {exeName} -9") def InstallWine(): threading.Thread(target=OpenTerminal, args=[f"'{programPath}/AllInstall.py'"]).start() def InstallWineOnDeepin23(): threading.Thread(target=OpenTerminal, args=[f"'{programPath}/InstallWineOnDeepin23.py'"]).start() class DllWindow(): def ShowWindow(): global dllMessage global dllInfoMap global textInfo global dllName dllMessage = QtWidgets.QWidget() dllLayout = QtWidgets.QGridLayout() try: dllInfoMap["check"] except: try: with open(f"{programPath}/CheckDLL/lists.json", "r") as file: dllInfoMap = json.loads(file.read()) except: traceback.print_exc() QtWidgets.QMessageBox.critical(dllMessage, "错误", traceback.format_exc()) # UI dllName = QtWidgets.QLineEdit() dllButton = QtWidgets.QPushButton("查询") textInfo = QtWidgets.QTextBrowser() dllButton.clicked.connect(DllWindow.Find) dllLayout.addWidget(QtWidgets.QLabel("Dll 名称:"), 0, 0) dllLayout.addWidget(dllName, 0, 1) dllLayout.addWidget(dllButton, 0, 2) dllLayout.addWidget(textInfo, 1, 0, 1, 3) dllMessage.setWindowTitle(f"{title}——查询 Dll") dllMessage.setLayout(dllLayout) dllMessage.resize(int(dllMessage.frameGeometry().width() * 1.2), int(dllMessage.frameGeometry().height() * 1.1)) dllMessage.setWindowIcon(QtGui.QIcon(f"{programPath}/deepin-wine-runner.svg")) dllMessage.show() def Find(): dllNameText = dllName.text().strip().lower() if dllNameText[-4:] != ".dll": dllNameText += ".dll" try: textInfo.setText(dllInfoMap[dllNameText]) except: textInfo.setText(f"未查询到有关 Dll '{dllNameText}' 有关的内容") def InstallWineOnDeepin23Alpha(): threading.Thread(target=OpenTerminal, args=[f"'{programPath}/InstallWineOnDeepin23Alpha.py'"]).start() def InstallWineHQ(): threading.Thread(target=OpenTerminal, args=[f"{programPath}/InstallNewWineHQ.sh"]).start() def OpenWineBotton(): if e1.currentText() == "": wineBottonPath = setting["DefultBotton"] else: wineBottonPath = e1.currentText() os.system("xdg-open \"" + wineBottonPath.replace("\'", "\\\'") + "\"") def OpenWineFontPath(): if e1.currentText() == "": wineBottonPath = setting["DefultBotton"] else: wineBottonPath = e1.currentText() QtWidgets.QMessageBox.information(widget, "提示", QtCore.QCoreApplication.translate("U", "如果安装字体?只需要把字体文件复制到此字体目录\n按下“OK”按钮可以打开字体目录")) os.system("xdg-open \"" + wineBottonPath.replace("\'", "\\\'") + "/drive_c/windows/Fonts\"") def GetLoseDll(): if e1.currentText() == "": wineBottonPath = setting["DefultBotton"] else: wineBottonPath = e1.currentText() option = "" if setting["MonoGeckoInstaller"]: option += f"WINEDLLOVERRIDES=\"mscoree,mshtml=\" " if setting["Architecture"] != "Auto": option += f"WINEARCH={setting['Architecture']} " if not setting["Debug"]: option += "WINEDEBUG=-all " wineUsingOption = "" if o1.currentText() == "基于 UOS exagear 的 deepin-wine6-stable": os.system(f"'{programPath}/deepin-wine-runner-create-botton.py' '{wineBottonPath}'") if o1.currentText() == "基于 UOS exagear 的 deepin-wine6-stable" or o1.currentText() == "基于 UOS box86 的 deepin-wine6-stable": wineUsingOption = "" if o1.currentText() == "基于 UOS box86 的 deepin-wine6-stable" or o1.currentText() == "基于 UOS exagear 的 deepin-wine6-stable": if not os.path.exists(f"{programPath}/dlls-arm"): if os.system(f"7z x -y \"{programPath}/dlls-arm.7z\" -o\"{programPath}\""): QtWidgets.QMessageBox.critical(widget, "错误", "无法解压资源") return os.remove(f"{programPath}/dlls-arm.7z") threading.Thread(target=os.system, args=[f"python3 '{programPath}/CheckDLL/main.py' '{e2.currentText()}' '{wineBottonPath}' '{wine[o1.currentText()]}'" + setting["WineOption"]]).start() class RunWineProgramThread(QtCore.QThread): signal = QtCore.pyqtSignal(str) showHistory = QtCore.pyqtSignal(str) def __init__(self, wineProgram, history = False, Disbled = True): super().__init__() self.wineProgram = wineProgram self.history = history self.Disbled = Disbled def run(self): global lastRunCommand if e1.currentText() == "": wineBottonPath = setting["DefultBotton"] else: wineBottonPath = e1.currentText() option = "" if setting["MonoGeckoInstaller"]: option += f"WINEDLLOVERRIDES=\"mscoree,mshtml=\" " if setting["Architecture"] != "Auto": option += f"WINEARCH={setting['Architecture']} " if not setting["Debug"]: option += "WINEDEBUG=-all " wineUsingOption = "" if o1.currentText() == "基于 UOS exagear 的 deepin-wine6-stable": os.system(f"'{programPath}/deepin-wine-runner-create-botton.py' '{wineBottonPath}'") if o1.currentText() == "基于 UOS exagear 的 deepin-wine6-stable" or o1.currentText() == "基于 UOS box86 的 deepin-wine6-stable": wineUsingOption = "" if o1.currentText() == "基于 UOS box86 的 deepin-wine6-stable" or o1.currentText() == "基于 UOS exagear 的 deepin-wine6-stable": if not os.path.exists(f"{programPath}/dlls-arm"): if os.system(f"7z x -y \"{programPath}/dlls-arm.7z\" -o\"{programPath}\""): QtWidgets.QMessageBox.critical(widget, "错误", "无法解压资源") return os.remove(f"{programPath}/dlls-arm.7z") if setting["TerminalOpen"]: res = "" runCommand = f"env WINEPREFIX='" + wineBottonPath + "' " + option + wine[o1.currentText()] + " '" + self.wineProgram + "' " + setting["WineOption"] + " " + wineUsingOption OpenTerminal(runCommand) #res = subprocess.Popen([f"'{programPath}/launch.sh' deepin-terminal -C \"WINEPREFIX='" + wineBottonPath + "' " + option + wine[o1.currentText()] + " '" + self.wineProgram + "' " + setting["WineOption"] + " " + wineUsingOption + "\" --keep-open"], shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) else: runCommand = "WINEPREFIX='" + wineBottonPath + "' " + option + wine[o1.currentText()] + " '" + self.wineProgram + "' " + setting["WineOption"] res = subprocess.Popen([runCommand], shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) print(runCommand) lastRunCommand = runCommand # 实时读取程序返回 if not setting["TerminalOpen"]: while res.poll() is None: try: text = res.stdout.readline().decode("utf8") except: text = "" self.signal.emit(text) print(text, end="") if self.history: if len(findExeHistory) == 0 or findExeHistory[-1] != wineBottonPath: findExeHistory.append(wineBottonPath) # 将记录写进数组 write_txt(get_home() + "/.config/deepin-wine-runner/FindExeHistory.json", str(json.dumps(ListToDictionary(findExeHistory)))) # 将历史记录的数组转换为字典并写入 if len(wineBottonHistory) == 0 or wineBottonHistory[-1] != e2.currentText(): wineBottonHistory.append(e2.currentText()) # 将记录写进数组 write_txt(get_home() + "/.config/deepin-wine-runner/WineBottonHistory.json", str(json.dumps(ListToDictionary(wineBottonHistory)))) # 将历史记录的数组转换为字典并写入 self.showHistory.emit("") if self.Disbled: DisableButton(False) runProgram = None def RunWineProgram(wineProgram, history = False, Disbled = True): global runProgram DisableButton(True) if not CheckProgramIsInstall(wine[o1.currentText()]) and o1.currentText() != "基于 linglong 的 deepin-wine6-stable(不推荐)" and o1.currentText() != "基于 UOS exagear 的 deepin-wine6-stable" and o1.currentText() != "基于 UOS box86 的 deepin-wine6-stable": if not CheckProgramIsInstall(wine[o1.currentText()]) and not o1.currentText() in untipsWine: if QtWidgets.QMessageBox.question(widget, "提示", "检查到您未安装这个 wine,是否继续使用这个 wine 运行?") == QtWidgets.QMessageBox.No: DisableButton(False) return returnText.setText("") runProgram = RunWineProgramThread(wineProgram, history, Disbled) runProgram.signal.connect(QT.ShowWineReturn) runProgram.showHistory.connect(QT.ShowHistory) runProgram.start() class RunWinetricksThread(QtCore.QThread): signal = QtCore.pyqtSignal(str) bwrap = QtCore.pyqtSignal(str) def __init__(self, bwrap): self.bwrap = bwrap super().__init__() def run(self): wineBottonPath = setting["DefultBotton"] if not e1.currentText() == "": wineBottonPath = e1.currentText() option = "" if setting["Architecture"] != "Auto": option += f"WINEARCH={setting['Architecture']} " if not setting["Debug"]: option += "WINEDEBUG=-all " wineUsingOption = "" if o1.currentText() == "基于 UOS exagear 的 deepin-wine6-stable" or o1.currentText() == "基于 UOS box86 的 deepin-wine6-stable": wineUsingOption = "" if o1.currentText() == "基于 UOS box86 的 deepin-wine6-stable" or o1.currentText() == "基于 UOS exagear 的 deepin-wine6-stable": if not os.path.exists(f"{programPath}/dlls-arm"): if os.system(f"7z x -y \"{programPath}/dlls-arm.7z\" -o\"{programPath}\""): QtWidgets.QMessageBox.critical(widget, "错误", "无法解压资源") return os.remove(f"{programPath}/dlls-arm.7z") ## 获取 WineServer 路径 wineServer = None winePath = wine[o1.currentText()] winePath = winePath.replace(f"bash '{programPath}/WineLib/run.sh'", "").strip() # 判断类似 xxx-server 的 WineServer if not os.system(f"{winePath}-server") >> 8: wineServer = f"{winePath}-server" # 判断类似 deepin-wine6-stable 的 WineServer elif os.path.exists(f"/opt/{winePath}/bin/wineserver"): wineServer = f"/opt/{winePath}/bin/wineserver" elif os.path.exists(winePath): wineServer = os.path.normpath(f"{winePath}/../wineserver") runtime = "" if self.bwrap: runtime = f"'{programPath}/WineLib/run.sh'" winetricksPath = "winetricks" if os.system("which winetricks") >> 8: winetricksPath = f"'{programPath}/winetricks'" print(wineServer) wineProgramP = wine[o1.currentText()].replace(f"bash '{programPath}/WineLib/run.sh'", "").strip() wineProgramP = subprocess.getoutput(f"which {wineProgramP}").strip() if setting["TerminalOpen"]: res = "" # 用终端开应该不用返回输出内容了 if wineServer == None: OpenTerminal(f"WINEPREFIX='{wineBottonPath}' {option} WINE='{wineProgramP}' {runtime} {winetricksPath} --gui {wineUsingOption}") else: OpenTerminal(f"WINEPREFIX='{wineBottonPath}' {option} WINESERVER='{wineServer}' WINE='{wineProgramP}' {runtime} {winetricksPath} --gui {wineUsingOption}") #res = subprocess.Popen([f"'{programPath}/launch.sh' deepin-terminal -C \"WINEPREFIX='{wineBottonPath}' {option} WINE=" + subprocess.getoutput(f"which {wine[o1.currentText()]}").replace(" ", "").replace("\n", "") + f" winetricks --gui {wineUsingOption}\" --keep-open"], shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) else: if wineServer == None: res = subprocess.Popen([f"WINEPREFIX='{wineBottonPath}' {option} WINE='{wineProgramP}' {runtime} {winetricksPath} --gui"], shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) else: res = subprocess.Popen([f"WINEPREFIX='{wineBottonPath}' {option} WINESERVER='{wineServer}' WINE='{wineProgramP}' {runtime} {winetricksPath} --gui"], shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) # 实时读取程序返回 while res.poll() is None: try: text = res.stdout.readline().decode("utf8") except: text = "" self.signal.emit(text) print(text, end="") DisableButton(False) runWinetricks = None def RunWinetricksWithWineLib(): global runWinetricks DisableButton(True) if not CheckProgramIsInstall(wine[o1.currentText()]) and o1.currentText() != "基于 linglong 的 deepin-wine6-stable(不推荐)" and o1.currentText() != "基于 UOS exagear 的 deepin-wine6-stable" and o1.currentText() != "基于 UOS box86 的 deepin-wine6-stable": if not CheckProgramIsInstall(wine[o1.currentText()]) and not o1.currentText() in untipsWine: DisableButton(False) return if o1.currentText() == "基于 UOS box86 的 deepin-wine6-stable" or o1.currentText() == "基于 UOS exagear 的 deepin-wine6-stable": if not os.path.exists(f"{programPath}/dlls-arm"): if os.system(f"7z x -y \"{programPath}/dlls-arm.7z\" -o\"{programPath}\""): QtWidgets.QMessageBox.critical(widget, "错误", "无法解压资源") return os.remove(f"{programPath}/dlls-arm.7z") returnText.setText("") runWinetricks = RunWinetricksThread(False) runWinetricks.signal.connect(QT.ShowWineReturn) runWinetricks.start() def RunWinetricks(): global runWinetricks DisableButton(True) if not CheckProgramIsInstall(wine[o1.currentText()]) and o1.currentText() != "基于 linglong 的 deepin-wine6-stable(不推荐)" and o1.currentText() != "基于 UOS exagear 的 deepin-wine6-stable" and o1.currentText() != "基于 UOS box86 的 deepin-wine6-stable": if not CheckProgramIsInstall(wine[o1.currentText()]) and not o1.currentText() in untipsWine: DisableButton(False) return if o1.currentText() == "基于 UOS box86 的 deepin-wine6-stable" or o1.currentText() == "基于 UOS exagear 的 deepin-wine6-stable": if not os.path.exists(f"{programPath}/dlls-arm"): if os.system(f"7z x -y \"{programPath}/dlls-arm.7z\" -o\"{programPath}\""): QtWidgets.QMessageBox.critical(widget, "错误", "无法解压资源") return os.remove(f"{programPath}/dlls-arm.7z") returnText.setText("") runWinetricks = RunWinetricksThread(False) runWinetricks.signal.connect(QT.ShowWineReturn) runWinetricks.start() def CleanWineBottonByUOS(): if e1.currentText() == "": wineBottonPath = setting["DefultBotton"] else: wineBottonPath = e1.currentText() OpenTerminal(f"env WINE='{wine[o1.currentText()]}' '{programPath}/cleanbottle.sh' '{wineBottonPath}'") def FontAppStore(): if e1.currentText() == "": wineBottonPath = setting["DefultBotton"] else: wineBottonPath = e1.currentText() OpenTerminal(f"env WINE='{programPath}/launch.sh' '{programPath}/InstallFont.py' '{wineBottonPath}' {int(setting['RuntimeCache'])}") def GetDllFromInternet(): if e1.currentText() == "": wineBottonPath = setting["DefultBotton"] else: wineBottonPath = e1.currentText() OpenTerminal(f"env WINE='{programPath}/launch.sh' '{programPath}/InstallDll.py' '{wineBottonPath}' '{wine[o1.currentText()]}' {int(setting['RuntimeCache'])}") def WineBottonAutoConfig(): if e1.currentText() == "": wineBottonPath = setting["DefultBotton"] else: wineBottonPath = e1.currentText() option = "" if setting["Architecture"] != "Auto": option += f"WINEARCH={setting['Architecture']} " if setting["MonoGeckoInstaller"]: option += f"WINEDLLOVERRIDES=\"mscoree,mshtml=\" " if not setting["Debug"]: option += "WINEDEBUG=-all " else: option += "WINEDEBUG=FIXME,ERR,WARN,TRACE,Message " os.system(f"env WINEPREFIX='{wineBottonPath}' {option} WINE='{wine[o1.currentText()]}' '{programPath}/AutoConfig.py' '{wine[o1.currentText()]}' '{wineBottonPath}'") def InstallMonoGecko(program): if e1.currentText() == "": wineBottonPath = setting["DefultBotton"] else: wineBottonPath = e1.currentText() OpenTerminal(f"'{programPath}/InstallMono.py' '{wineBottonPath}' '{wine[o1.currentText()]}' {program} {int(setting['RuntimeCache'])}") def InstallNetFramework(): if e1.currentText() == "": wineBottonPath = setting["DefultBotton"] else: wineBottonPath = e1.currentText() OpenTerminal(f"'{programPath}/InstallNetFramework.py' '{wineBottonPath}' '{wine[o1.currentText()]}' {int(setting['RuntimeCache'])}") def InstallVB(): if e1.currentText() == "": wineBottonPath = setting["DefultBotton"] else: wineBottonPath = e1.currentText() OpenTerminal(f"'{programPath}/InstallVisualBasicRuntime.py' '{wineBottonPath}' '{wine[o1.currentText()]}' {int(setting['RuntimeCache'])}") def InstallFoxPro(): if e1.currentText() == "": wineBottonPath = setting["DefultBotton"] else: wineBottonPath = e1.currentText() OpenTerminal(f"'{programPath}/InstallFoxpro.py' '{wineBottonPath}' '{wine[o1.currentText()]}' {int(setting['RuntimeCache'])}") def InstallVisualStudioCPlusPlus(): if e1.currentText() == "": wineBottonPath = setting["DefultBotton"] else: wineBottonPath = e1.currentText() OpenTerminal(f"'{programPath}/InstallVisualCPlusPlus.py' '{wineBottonPath}' '{wine[o1.currentText()]}' {int(setting['RuntimeCache'])}") def InstallMSXML(): if e1.currentText() == "": wineBottonPath = setting["DefultBotton"] else: wineBottonPath = e1.currentText() OpenTerminal(f"'{programPath}/InstallMsxml.py' '{wineBottonPath}' '{wine[o1.currentText()]}' {int(setting['RuntimeCache'])}") def InstallDXVK(): if not os.path.exists(f"{programPath}/dxvk"): if os.system(f"7z x -y \"{programPath}/dxvk.7z\" -o\"{programPath}\""): QtWidgets.QMessageBox.critical(widget, "错误", "无法解压资源") return os.remove(f"{programPath}/dxvk.7z") if e1.currentText() == "": wineBottonPath = setting["DefultBotton"] else: wineBottonPath = e1.currentText() OpenTerminal(f"env WINE='{wine[o1.currentText()]}' WINE64='{wine[o1.currentText()]}' WINEPREFIX='{wineBottonPath}' '{programPath}/dxvk/setup_dxvk.sh' uninstall") def InstallVkd3d(): if not os.path.exists(f"{programPath}/vkd3d-proton"): if os.system(f"7z x -y \"{programPath}/vkd3d-proton.7z\" -o\"{programPath}\""): QtWidgets.QMessageBox.critical(widget, "错误", "无法解压资源") return os.remove(f"{programPath}/vkd3d-proton.7z") if e1.currentText() == "": wineBottonPath = setting["DefultBotton"] else: wineBottonPath = e1.currentText() OpenTerminal(f"env WINE='{wine[o1.currentText()]}' WINE64='{wine[o1.currentText()]}' WINEPREFIX='{wineBottonPath}' '{programPath}/vkd3d-proton/setup_vkd3d_proton.sh' install") def UninstallVkd3d(): if not os.path.exists(f"{programPath}/vkd3d-proton"): if os.system(f"7z x -y \"{programPath}/vkd3d-proton.7z\" -o\"{programPath}\""): QtWidgets.QMessageBox.critical(widget, "错误", "无法解压资源") return os.remove(f"{programPath}/vkd3d-proton.7z") if e1.currentText() == "": wineBottonPath = setting["DefultBotton"] else: wineBottonPath = e1.currentText() OpenTerminal(f"env WINE='{wine[o1.currentText()]}' WINE64='{wine[o1.currentText()]}' WINEPREFIX='{wineBottonPath}' '{programPath}/vkd3d-proton/setup_vkd3d_proton.sh' uninstall") #process = QtCore.QProcess() #process.startDetached(f"{programPath}/launch.sh", ["deepin-terminal", "-e", #"env", f"WINE={wine[o1.currentText()]}", f"WINE64={wine[o1.currentText()]}", f"WINEPREFIX={wineBottonPath}", "bash", #f"{programPath}/dxvk/setup_dxvk.sh", "install"]) def UninstallDXVK(): if not os.path.exists(f"{programPath}/dxvk"): if os.system(f"7z x -y \"{programPath}/dxvk.7z\" -o\"{programPath}\""): QtWidgets.QMessageBox.critical(widget, "错误", "无法解压资源") return os.remove(f"{programPath}/dxvk.7z") if e1.currentText() == "": wineBottonPath = setting["DefultBotton"] else: wineBottonPath = e1.currentText() OpenTerminal(f"env WINE='{wine[o1.currentText()]}' WINE64='{wine[o1.currentText()]}' WINEPREFIX='{wineBottonPath}' '{programPath}/dxvk/setup_dxvk.sh' uninstall") #process = QtCore.QProcess() #process.startDetached(f"{programPath}/launch.sh", ["deepin-terminal", "-e", #"env", f"WINE={wine[o1.currentText()]}", f"WINE64={wine[o1.currentText()]}", f"WINEPREFIX={wineBottonPath}", #f"{programPath}/dxvk/setup_dxvk.sh", "uninstall"]) def MiniAppStore(): if e1.currentText()== "": wineBottonPath = setting["DefultBotton"] else: wineBottonPath = e1.currentText() OpenTerminal(f"'{programPath}/AppStore.py' '{wineBottonPath}' '{wine[o1.currentText()]}'") def InstallOther(): if e1.currentText()== "": wineBottonPath = setting["DefultBotton"] else: wineBottonPath = e1.currentText() OpenTerminal(f"'{programPath}/InstallOther.py' '{wineBottonPath}' '{wine[o1.currentText()]}' {int(setting['RuntimeCache'])}") def BuildExeDeb(): if e1.currentText() == "": wineBottonPath = setting["DefultBotton"] else: wineBottonPath = e1.currentText() threading.Thread(target=os.system, args=[f"python3 '{programPath}/deepin-wine-packager.py' '{wineBottonPath}' '{wine[o1.currentText()]}'"]).start() def SetDeepinFileDialogDeepin(): code = os.system(f"pkexec \"{programPath}/deepin-wine-venturi-setter.py\" deepin") if code != 0: if code == 1: QtWidgets.QMessageBox.critical(widget, "错误", "无法更新配置:配置不准重复配置") return QtWidgets.QMessageBox.critical(widget, "错误", "配置失败") return QtWidgets.QMessageBox.information(widget, "提示", "设置完成!") def AddReg(): path = QtWidgets.QFileDialog.getOpenFileName(window, "保存路径", get_home(), "reg文件(*.reg);;所有文件(*.*)") if path[0] == "" and not path[1]: return RunWineProgram(f"regedit' /S '{path[0]}' 'HKEY_CURRENT_USER\Software\Wine\DllOverrides") def SaveDllList(): path = QtWidgets.QFileDialog.getSaveFileName(window, "保存路径", get_home(), "reg文件(*.reg);;所有文件(*.*)") if path[0] == "" and not path[1]: return RunWineProgram(f"regedit' /E '{path[0]}' 'HKEY_CURRENT_USER\Software\Wine\DllOverrides") def SetDeepinFileDialogDefult(): code = os.system(f"pkexec \"{programPath}/deepin-wine-venturi-setter.py\" defult") if code != 0: if code == 1: QtWidgets.QMessageBox.critical(widget, "错误", "无法更新配置:配置不准重复配置") return QtWidgets.QMessageBox.critical(widget, "错误", "配置失败") return QtWidgets.QMessageBox.information(widget, "提示", "设置完成!") def SetDeepinFileDialogRecovery(): threading.Thread(target=OpenTerminal, args=[f"pkexec '{programPath}/deepin-wine-venturi-setter.py' recovery"]).start() def DeleteDesktopIcon(): if os.path.exists(f"{get_home()}/.local/share/applications/wine"): try: shutil.rmtree(f"{get_home()}/.local/share/applications/wine") except: traceback.print_exc() QtWidgets.QMessageBox.critical(widget, "错误", traceback.format_exc()) return QtWidgets.QMessageBox.information(widget, "提示", "删除完成") def DeleteWineBotton(): if QtWidgets.QMessageBox.question(widget, "提示", "你确定要删除容器吗?删除后将无法恢复!\n如果没有选择 wine 容器,将会自动删除默认的容器!") == QtWidgets.QMessageBox.No: return if e1.currentText() == "": wineBottonPath = setting["DefultBotton"] else: wineBottonPath = e1.currentText() try: shutil.rmtree(wineBottonPath) QtWidgets.QMessageBox.information(widget, "提示", "删除完毕!") except: traceback.print_exc() QtWidgets.QMessageBox.critical(widget, "错误", traceback.format_exc()) def ThankWindow(): # 直接显示关于窗口,关于窗口已经添加 about_this_program() def InstallWineFont(): # 筛选 apt if not os.system("which aptss"): threading.Thread(target=OpenTerminal, args=[f"sudo aptss install ms-core-fonts -y"]).start() elif not os.system("which ss-apt-fast"): threading.Thread(target=OpenTerminal, args=[f"sudo ss-apt-fast install ms-core-fonts -y"]).start() elif not os.system("which apt-fast"): threading.Thread(target=OpenTerminal, args=[f"sudo apt-fast install ms-core-fonts -y"]).start() else: threading.Thread(target=OpenTerminal, args=[f"sudo apt install ms-core-fonts -y"]).start() def WineRunnerBugUpload(): threading.Thread(target=os.system, args=[f"'{programPath}/deepin-wine-runner-update-bug'"]).start() def SetHttpProxy(): QtWidgets.QMessageBox.information(window, "提示", "请在下面的对话框正确输入内容以便设置代理") proxyServerAddress = QtWidgets.QInputDialog.getText(window, "提示", "请输入代理服务器地址")[0] port = QtWidgets.QInputDialog.getText(window, "提示", "请输入代理服务器端口")[0] if proxyServerAddress == "" or port == "": return RunWineProgram("reg' add 'HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings' /v ProxyEnable /t REG_DWORD /d 00000001 '/f") RunWineProgram(f"reg' add 'HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings' /v ProxyServer /d '{proxyServerAddress}:{port}' '/f") def DisbledHttpProxy(): RunWineProgram("reg' add 'HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings' /v ProxyEnable /t REG_DWORD /d 00000000 '/f") def GetScreenSize(): screenInformation = [] # 使用 xrandr 进行筛选 for i in subprocess.getoutput("xrandr").split('\n'): if not " connected " in i: # 检测连接的显示器 continue # 获取分辨率基本信息,如 # DisplayPort-0 connected 1600x900+1280+0 (normal left inverted right x axis y axis) 434mm x 236mm # 先判断是否为主屏幕 main = False if "primary" in i: main = True # 进行进一步筛选 i = i[i.index("connected"):].replace("connected", "").replace("primary", "") # 进行初步筛选,如 # 1600x900+1280+0 (normal left inverted right x axis y axis) 434mm x 236mm i = i[:i.index("(")].replace(" ", "") # 筛选为 1600x900+0+0 进行最后数值的提取 screenInformation.append([ int(i[:i.index("x")]), # 获取宽度 int(i[i.index("x") + 1 :i.index("+")]), # 获取高度 int(i[i.index("+") + 1:].split('+')[0]), # 获取显示屏 X 坐标 int(i[i.index("+") + 1:].split('+')[1]), # 获取显示屏 Y 坐标 main # 是否为主屏幕 ]) return screenInformation # 返回结果 def UOSPackageScript(): threading.Thread(target=os.system, args=[f"python3 '{programPath}/deepin-wine-packager-with-script.py'"]).start() def RunVM(): threading.Thread(target=os.system, args=[f"bash '{programPath}/RunVM.sh'"]).start() def CleanProgram(): OpenTerminal(f"{programPath}/clean-unuse-program.py") class UpdateWindow(): data = {} update = None def ShowWindow(): UpdateWindow.update = QtWidgets.QMainWindow() updateWidget = QtWidgets.QWidget() updateWidgetLayout = QtWidgets.QGridLayout() versionLabel = QtWidgets.QLabel(f"当前版本:{version}\n最新版本:未知\n更新内容:") updateText = QtWidgets.QTextBrowser() updateText.anchorClicked.connect(OpenUrl) updateText.setOpenLinks(False) updateText.setOpenExternalLinks(False) ok = QtWidgets.QPushButton(QtCore.QCoreApplication.translate("U", "更新(更新时会自动关闭 Wine 运行器)")) ok.clicked.connect(UpdateWindow.Update) cancel = QtWidgets.QPushButton("取消") cancel.clicked.connect(UpdateWindow.update.close) url = "http://update.gfdgdxi.top/update.json" try: UpdateWindow.data = json.loads(requests.get(url).text) versionLabel = QtWidgets.QLabel(f"当前版本:{version}\n最新版本:{UpdateWindow.data['Version']}\n更新内容:") if UpdateWindow.data["Version"] == version: updateText.setText("此为最新版本,无需更新") ok.setDisabled(True) else: # 版本号读取(防止出现高版本号提示要“升级”到低版本号的问题) localVersionList = version.split(".") webVersionList = UpdateWindow.data['Version'].split(".") for i in range(len(localVersionList)): local = int(localVersionList[i]) web = int(webVersionList[i]) if web < local: updateText.setHtml(f"""此为最新版本,无需更新,但似乎您当前使用的程序版本比云端版本还要高。
出现这个问题可能会有如下几种情况:
1、使用编译或者内测版本
2、自己修改了程序版本
3、作者忘记更新云端上的更新信息了
如果是第三种情况,请反馈到此:https://gitee.com/gfdgd-xi/deep-wine-runner/issues/I6T3FG
无法连接到服务器
你可以尝试:
1. 判断是否能正常连接网络
2. 作者的服务出问题了?(到这反馈:https://gitee.com/gfdgd-xi/deep-wine-runner/issues)
3. 玩个游戏解闷下
""" global webInformation if bad: webInformation = QtWidgets.QTextBrowser() webInformation.anchorClicked.connect(OpenUrl) webInformation.setOpenLinks(False) webInformation.setOpenExternalLinks(False) else: webInformation = QtWebEngineWidgets.QWebEngineView() webInformation.setHtml(text) webInformation.setWindowTitle("获取程序公告") webInformation.setWindowIcon(QtGui.QIcon(iconPath)) webInformation.resize(int(webInformation.frameGeometry().width() * 1.3), int(webInformation.frameGeometry().height() * 1.1)) webInformation.setWindowFlags(webInformation.windowFlags() | QtCore.Qt.Dialog) webInformation.setWindowModality(QtCore.Qt.ApplicationModal) webInformation.show() def getFileFolderSize(fileOrFolderPath): """get size for file or folder""" totalSize = 0 try: if not os.path.exists(fileOrFolderPath): return totalSize if os.path.isfile(fileOrFolderPath): totalSize = os.path.getsize(fileOrFolderPath) # 5041481 return totalSize if os.path.islink(fileOrFolderPath): return 0 if os.path.isdir(fileOrFolderPath): with os.scandir(fileOrFolderPath) as dirEntryList: for curSubEntry in dirEntryList: curSubEntryFullPath = os.path.join(fileOrFolderPath, curSubEntry.name) if curSubEntry.is_dir(): curSubFolderSize = getFileFolderSize(curSubEntryFullPath) # 5800007 totalSize += curSubFolderSize elif curSubEntry.is_file(): curSubFileSize = os.path.getsize(curSubEntryFullPath) # 1891 totalSize += curSubFileSize return totalSize except: return totalSize # 获取当前语言 def get_now_lang()->"获取当前语言": return os.getenv('LANG') # 又需要修复多线程导致的控件问题 def AddDockerMenu(): global dockers global openFileManager global openTerminal dockers = menu.addMenu("该 Docker 基础管理") openFileManager = QtWidgets.QAction("打开默认文件管理器") openTerminal = QtWidgets.QAction("打开默认终端") openFileManager.triggered.connect(lambda: threading.Thread(target=os.system, args=[f"xdg-open '{get_home()}'"]).start()) openTerminal.triggered.connect(lambda: threading.Thread(target=os.system, args=[f"x-terminal-emulator"]).start()) dockers.addAction(openFileManager) dockers.addAction(openTerminal) newPackage = False class GetVersionThread(QtCore.QThread): signal = QtCore.pyqtSignal(str) def __init__(self) -> None: super().__init__() def run(self): global about global window global newPackage global programVersionType # 目前分为几个版本(在 control 文件区分): # 星火版本:~spark # 商店版本:~uos # 编译版本:无版本号 # Gitee/Github……:正常版本 # Docker 版本 programVersionTypeLnk = { "spark": "普通版本", "uos": "普通版本" } # 直接判断是不是 Docker 版本 if os.path.exists(f"{programPath}/docker.txt") or os.path.exists("/.dockerenv"): programVersionType = "普通版本" self.signal.emit("") else: programVersionType = "从源码运行的版本" try: if not os.path.exists("/var/lib/dpkg/status"): print("无 dpkg,结束") file = open("/var/lib/dpkg/status", "r") fileName = file.read().splitlines() package = False for i in range(0, len(fileName)): if fileName[i] == "Package: spark-deepin-wine-runner-docker": programVersionType = "普通版本" #AddDockerMenu() self.signal.emit("") break if fileName[i] == "Package: spark-deepin-wine-runner-52": programVersionType = "普通版本" newPackage = False break if fileName[i] == "Package: spark-deepin-wine-runner": package = True newPackage = True continue if fileName[i] == "Package: wine-runner-linux": package = True continue if not package: continue if fileName[i].replace(" ", "").replace("\n", "") == "": # 空行,不再考虑 break # 搜索版本号 try: if fileName[i][:fileName[i].index(":")] == "Version": version = fileName[i][fileName[i].index(":") + 1:].strip() print(f"版本号为:{version}") if not "-" in version: programVersionType = "普通版本" break programVersionType = version[version.index("-") + 1:] print(programVersionType) if "-" in programVersionType: # 考虑到如 2.1.0-2-spark 的情况 programVersionType = programVersionType[programVersionType.index("-") + 1:] try: programVersionType = programVersionTypeLnk[programVersionType] except: programVersionType = "普通版本" break except: traceback.print_exc() continue except: print("无法读取,当没有处理") print(programVersionType) about = about.replace("@VersionForType@", programVersionType) # 获取程序体积 about = about.replace("@programSize@", str(int(getFileFolderSize(programPath) / 1024 / 1024))) def GetVersion(): global runVersion runVersion = GetVersionThread() runVersion.signal.connect(AddDockerMenu) runVersion.start() def UnPackage(): QtWidgets.QMessageBox.information(window, "提示", "请在下面两个对话框中选择 deb 包所在路径和容器解压到的路径") debPath = QtWidgets.QFileDialog.getOpenFileName(window, get_home(), "deb 文件(*.deb);;所有文件(*.*)") if not debPath[1]: return path = QtWidgets.QFileDialog.getExistingDirectory(window, get_home()) print(path) if not path: return tempDebDir = f"/tmp/wine-runner-unpack-deb-{random.randint(0, 1000)}" if os.system(f"dpkg -x '{debPath[0]}' '{tempDebDir}'"): QtWidgets.QMessageBox.critical(window, "错误", "解压失败!") return zippath = FindFile(tempDebDir, "files.7z") if zippath == None: QtWidgets.QMessageBox.critical(window, "错误", "解压失败!") return print(path) # 解压文件 os.system(f"mkdir -p '{path}'") os.system(f"7z x -y '{zippath}' -o'{path}'") os.system(f"rm -rfv '{tempDebDir}'") QtWidgets.QMessageBox.information(window, "提示", "解压完成!") def FindFile(file, name): for i in os.listdir(file): path = f"{file}/{i}" if os.path.isdir(path): returnPath = FindFile(path, name) if returnPath != None: return returnPath.replace("//", "/") if os.path.isfile(path): if i == name: return path return None def TransLog(): oldText = returnText.toPlainText() lineNumber = 0 transText = "" chooseText = "" for i in oldText.splitlines(): lineNumber += 1 chooseText += f"{i}\n" if lineNumber >= 50: lineNumber = 0 try: data = { 'doctype': 'json', 'type': 'auto','i': chooseText.replace("\n\n", "\n")} jsonReturn = requests.post("http://fanyi.youdao.com/translate", data=data).json()["translateResult"] for i in jsonReturn: print(i) transText += f'{i[0]["tgt"]}\n' chooseText = "" except: transText += f"{chooseText}\n" chooseText = "" if lineNumber != 0: lineNumber = 0 try: data = { 'doctype': 'json', 'type': 'auto','i': chooseText.replace("\n\n", "\n")} jsonReturn = requests.post("http://fanyi.youdao.com/translate", data=data).json()["translateResult"] for i in jsonReturn: print(i[0]) transText += f'{i[0]["tgt"]}\n' chooseText = "" except: transText += f"{chooseText}\n" chooseText = "" #return transText returnText.setText(transText.replace("\n\n", "\n")) ########################### # 加载配置 ########################### if not os.path.exists(get_home() + "/.config/"): # 如果没有配置文件夹 os.mkdir(get_home() + "/.config/") # 创建配置文件夹 if not os.path.exists(get_home() + "/.config/deepin-wine-runner"): # 如果没有配置文件夹 os.mkdir(get_home() + "/.config/deepin-wine-runner") # 创建配置文件夹 if not os.path.exists(f"{get_home()}/.config/deepin-wine-runner/information"): # 如果没有配置文件夹 os.mkdir(f"{get_home()}/.config/deepin-wine-runner/information") # 创建配置文件夹 if not os.path.exists(get_home() + "/.config/deepin-wine-runner/ShellHistory.json"): # 如果没有配置文件 write_txt(get_home() + "/.config/deepin-wine-runner/ShellHistory.json", json.dumps({})) # 创建配置文件 if not os.path.exists(get_home() + "/.config/deepin-wine-runner/FindExeHistory.json"): # 如果没有配置文件 write_txt(get_home() + "/.config/deepin-wine-runner/FindExeHistory.json", json.dumps({})) # 创建配置文件 if not os.path.exists(get_home() + "/.config/deepin-wine-runner/WineBottonHistory.json"): # 如果没有配置文件 write_txt(get_home() + "/.config/deepin-wine-runner/WineBottonHistory.json", json.dumps({})) # 创建配置文件 if not os.path.exists(get_home() + "/.config/deepin-wine-runner/ISOPath.json"): # 如果没有配置文件 write_txt(get_home() + "/.config/deepin-wine-runner/ISOPath.json", json.dumps({})) # 写入(创建)一个配置文件 if not os.path.exists(get_home() + "/.config/deepin-wine-runner/ISOPathFound.json"): # 如果没有配置文件 write_txt(get_home() + "/.config/deepin-wine-runner/ISOPathFound.json", json.dumps({})) # 写入(创建)一个配置文件 if not os.path.exists(get_home() + "/.config/deepin-wine-runner/FindExe.json"): # 如果没有配置文件 write_txt(get_home() + "/.config/deepin-wine-runner/FindExe.json", json.dumps({"path": "~"})) # 写入(创建)一个配置文件 if not os.path.exists(get_home() + "/.config/deepin-wine-runner/FindISO.json"): # 如果没有配置文件 write_txt(get_home() + "/.config/deepin-wine-runner/FindISO.json", json.dumps({"path": "~"})) # 写入(创建)一个配置文件 if not os.path.exists(get_home() + "/.config/deepin-wine-runner/WineBotton.json"): # 如果没有配置文件 write_txt(get_home() + "/.config/deepin-wine-runner/WineBotton.json", json.dumps({"path": "~/.deepinwine"})) # 写入(创建)一个配置文件 if not os.path.exists(get_home() + "/.config/deepin-wine-runner/WineSetting.json"): # 如果没有配置文件 write_txt(get_home() + "/.config/deepin-wine-runner/WineSetting.json", json.dumps(defultProgramList)) # 写入(创建)一个配置文件 ########################### # 设置变量 ########################### programPath = os.path.split(os.path.realpath(__file__))[0] # 返回 string # 如果要添加其他 wine,请使用安装更多 Wine 功能 ############# # 检测 Wine ############# def CheckWine(): global wine global untipsWine global canUseWine try: wine7zUse = ["wine", "wine64", "wine-i386", "wine-aarch64", "wine-x86_64"] wine = { "基于 UOS box86 的 deepin-wine6-stable": f"WINEPREDLL='{programPath}/dlls-arm' WINEDLLPATH=/opt/deepin-wine6-stable/lib BOX86_NOSIGSEGV=1 /opt/deepin-box86/box86 /opt/deepin-wine6-stable/bin/wine ", "基于 UOS exagear 的 deepin-wine6-stable": f"WINEPREDLL='{programPath}/dlls-arm' WINEDLLPATH=/opt/deepin-wine6-stable/lib /opt/exagear/bin/ubt_x64a64_al --path-prefix {get_home()}/.deepinwine/debian-buster --utmp-paths-list {get_home()}/.deepinwine/debian-buster/.exagear/utmp-list --vpaths-list {get_home()}/.deepinwine/debian-buster/.exagear/vpaths-list --opaths-list {get_home()}/.deepinwine/debian-buster/.exagear/opaths-list --smo-mode fbase --smo-severity smart --fd-limit 8192 --foreign-ubt-binary /opt/exagear/bin/ubt_x32a64_al -- /opt/deepin-wine6-stable/bin/wine ", "使用 Flatpak 安装的 Wine": "flatpak run org.winehq.Wine", "deepin-wine8-stable": "deepin-wine8-stable", "deepin-wine6 stable": "deepin-wine6-stable", "deepin-wine6-vannila": "deepin-wine6-vannila", "deepin-wine5 stable": "deepin-wine5-stable", "spark-wine": "spark-wine", "spark-wine7-devel": "spark-wine7-devel", "spark-wine8": "spark-wine8", "spark-wine8-wow": "spark-wine8-wow", "spark-wine9": "spark-wine9", "spark-wine9-wow": "spark-wine9-wow", "deepin-wine": "deepin-wine", "deepin-wine5": "deepin-wine5", "wine": "wine", "wine64": "wine64", "ukylin-wine": "ukylin-wine", "okylin-wine": "okylin-wine", "mono(这不是 wine,但可以实现初步调用运行 .net 应用)": "mono", "基于 linglong 的 deepin-wine6-stable(不推荐)": f"ll-cli run '' --exec '/bin/deepin-wine6-stable'" } untipsWine = ["使用 Flatpak 安装的 Wine", "基于 exagear 的 deepin-wine6-stable", "基于 UOS box86 的 deepin-wine6-stable", "基于 UOS exagear 的 deepin-wine6-stable", "基于 linglong 的 deepin-wine6-stable(不推荐)"] canUseWine = [] if os.path.exists("/opt/deepin-box86/box86") and os.path.exists("/opt/deepin-wine6-stable/bin/wine"): canUseWine.append("基于 UOS box86 的 deepin-wine6-stable") if os.path.exists("/opt/exagear/bin/ubt_x64a64_al") and os.path.exists("/opt/deepin-wine6-stable/bin/wine"): canUseWine.append("基于 UOS exagear 的 deepin-wine6-stable") #if not os.system("which exagear") and os.path.exists("/opt/deepin-wine6-stable/bin/wine"): #canUseWine.append("基于 exagear 的 deepin-wine6-stable") for i in wine.keys(): if not os.system(f"which '{wine[i]}'"): canUseWine.append(i) if not os.system("which flatpak") and os.path.exists("/var/lib/flatpak/app/org.winehq.Wine"): canUseWine.append("使用 Flatpak 安装的 Wine") if os.path.exists("/persistent/linglong/layers/"): # 判断是否使用 linglong for i in os.listdir("/persistent/linglong/layers/"): try: dire = os.listdir(f"/persistent/linglong/layers/{i}")[-1] arch = os.listdir(f"/persistent/linglong/layers/{i}/{dire}")[-1] if os.path.exists(f"/persistent/linglong/layers/{i}/{dire}/{arch}/runtime/bin/deepin-wine6-stable"): wine["基于 linglong 的 deepin-wine6-stable(不推荐)"] = f"ll-cli run {i} --exec '/bin/deepin-wine6-stable'" canUseWine.append("基于 linglong 的 deepin-wine6-stable(不推荐)") break except: pass # 读取自定义安装的 Wine(需要解包的才能使用) global qemuBottleList global qemuPath qemuBottleList = [] qemuPath = f"{get_home()}/.deepin-wine-runner-ubuntu-images" if not os.system("which qemu-i386-static"): if os.path.exists(qemuPath): for g in os.listdir(qemuPath): archPath = f"{qemuPath}/{g}" arch = g if os.path.isdir(archPath): for d in os.listdir(archPath): bottlePath = f"{archPath}/{d}" if os.path.isdir(bottlePath): qemuBottleList.append([ arch, d, bottlePath ]) global shellHistory global findExeHistory global wineBottonHistory global isoPath global isoPathFound global setting shellHistory = list(json.loads(readtxt(get_home() + "/.config/deepin-wine-runner/ShellHistory.json")).values()) findExeHistory = list(json.loads(readtxt(get_home() + "/.config/deepin-wine-runner/FindExeHistory.json")).values()) wineBottonHistory = list(json.loads(readtxt(get_home() + "/.config/deepin-wine-runner/WineBottonHistory.json")).values()) isoPath = list(json.loads(readtxt(get_home() + "/.config/deepin-wine-runner/ISOPath.json")).values()) isoPathFound = list(json.loads(readtxt(get_home() + "/.config/deepin-wine-runner/ISOPathFound.json")).values()) setting = json.loads(readtxt(get_home() + "/.config/deepin-wine-runner/WineSetting.json")) change = False if not os.path.exists(get_home() + "/.config/deepin-wine-runner/mono-lock"): os.mknod(f"{get_home()}/.config/deepin-wine-runner/mono-lock") setting["MonoGeckoInstaller"] = False change = True for i in defultProgramList.keys(): if not i in setting: change = True setting[i] = defultProgramList[i] if change: write_txt(get_home() + "/.config/deepin-wine-runner/WineSetting.json", json.dumps(setting)) try: # Read /opt Wine try: for i in os.listdir(f"/opt"): for j in wine7zUse: if os.path.exists(f"/opt/{i}/bin/{j}"): wine[f"/opt/{i}/bin/{j}"] = f"/opt/{i}/bin/{j}" canUseWine.append(f"/opt/{i}/bin/{j}") except: traceback.print_exc() # 不再从列表读取,直接读目录 for i in os.listdir(f"{programPath}/wine/"): #for i in json.loads(readtxt(f"{programPath}/wine/winelist.json")): if os.path.exists(f"{programPath}/wine/{i}") and os.path.isdir(f"{programPath}/wine/{i}"): name = "" qemuInstall = False nameValue = [["", ""]] try: if os.path.exists("/opt/deepin-box86/box86"): nameValue.append( [ "基于 UOS box86 的 ", f"WINEPREDLL='{programPath}/dlls-arm' WINEDLLPATH=/opt/deepin-wine6-stable/lib BOX86_NOSIGSEGV=1 /opt/deepin-box86/box86 " ] ) if os.system("which box86") == 0: nameValue.append( [ "基于 box86 的 ", f"box86 " ] ) if os.system("which box64") == 0: nameValue.append( [ "基于 box64 的 ", f"box64 " ] ) if os.system("which qemu-i386") == 0 and subprocess.getoutput("arch") != "x86_64" and subprocess.getoutput("arch") != "i386" and subprocess.getoutput("arch") != "i686": nameValue.append( [ "基于 qemu-i386 的 ", f"qemu-i386 " ] ) if os.system("which qemu-x86_64") == 0 and subprocess.getoutput("arch") != "x86_64" and subprocess.getoutput("arch") != "i386" and subprocess.getoutput("arch") != "i686": nameValue.append( [ "基于 qemu-x86_64 的 ", f"qemu-x86_64 " ] ) if os.path.exists("/opt/exagear/bin/ubt_x64a64_al") and os.path.exists(f"{get_home()}/.deepinwine/debian-buster"): nameValue.append( [ "基于 UOS exagear 的 ", f"WINEPREDLL='{programPath}/dlls-arm' WINEDLLPATH=/opt/deepin-wine6-stable/lib /opt/exagear/bin/ubt_x64a64_al --path-prefix {get_home()}/.deepinwine/debian-buster --utmp-paths-list {get_home()}/.deepinwine/debian-buster/.exagear/utmp-list --vpaths-list {get_home()}/.deepinwine/debian-buster/.exagear/vpaths-list --opaths-list {get_home()}/.deepinwine/debian-buster/.exagear/opaths-list --smo-mode fbase --smo-severity smart --fd-limit 8192 --foreign-ubt-binary /opt/exagear/bin/ubt_x32a64_al -- " ] ) if os.system("which exagear") == 0: nameValue.append( [ "运行 exagear 容器内的 ", f"exagear -- " ] ) if os.path.exists("/opt/exagear/bin/ubt_x64a64_al"): nameValue.append( [ "使用 ubt_x64a64_al 运行", "/opt/exagear/bin/ubt_x64a64_al -- " ] ) if os.path.exists("/opt/exagear/bin/ubt_x32a64_al"): nameValue.append( [ "使用 ubt_x32a64_al 运行", "/opt/exagear/bin/ubt_x32a64_al -- " ] ) for g in qemuBottleList: nameValue.append([ f"使用qemu-{g[0]}-static 调用容器{g[1]}运行 ", f"python3 '{programPath}/QemuRun.py' '{g[0]}/{g[1]}' {int(setting['QemuUnMountHome'])} " ]) except: traceback.print_exc() for k in nameValue: print(k) if "qemu" in k[0]: chrootProgramPath = "/opt/apps/deepin-wine-runner" else: chrootProgramPath = programPath for j in wine7zUse: if os.path.exists(f"{programPath}/wine/{i}/bin/{j}"): wine[f"{k[0]}{chrootProgramPath}/wine/{i}/bin/{j}"] = f"{k[1]}{chrootProgramPath}/wine/{i}/bin/{j}" canUseWine.append(f"{k[0]}{chrootProgramPath}/wine/{i}/bin/{j}") untipsWine.append(f"{k[0]}{chrootProgramPath}/wine/{i}/bin/{j}") except: traceback.print_exc() try: for i in os.listdir(f"{get_home()}/.deepinwine/"): for j in wine7zUse: if os.path.exists(f"{get_home()}/.deepinwine/{i}/bin/{j}"): wine[f"{get_home()}/.deepinwine/{i}/bin/{j}"] = f"{get_home()}/.deepinwine/{i}/bin/{j}" canUseWine.append(f"{get_home()}/.deepinwine/{i}/bin/{j}") except: traceback.print_exc() try: canUseWineOld = canUseWine[:] for i in canUseWineOld: if os.path.exists(f"{programPath}/WineLib/usr"): wine[f"使用运行器的运行库运行 {i}"] = f"bash '{programPath}/WineLib/run.sh' {wine[i]}" canUseWine.append(f"使用运行器的运行库运行 {i}") untipsWine.append(f"使用运行器的运行库运行 {i}") if os.path.exists("/opt/exagear/images"): for k in os.listdir("/opt/exagear/images"): if not os.path.isdir(f"/opt/exagear/images/{k}"): continue for i in canUseWineOld: wine[f"使用Exagear容器运行库运行 {i}"] = f"bash '{programPath}/WineLib/run-more.sh' '/opt/exagear/images/{k}' {wine[i]}" canUseWine.append(f"使用Exagear容器运行库运行 {i}") untipsWine.append(f"使用Exagear容器运行库运行 {i}") #if os.path.exists(f"{get_home()}/.deepinwine/debian-buster"): #for i in canUseWineOld: #wine[f"使用UOS Exagear容器运行库运行 {i}"] = f"bash '{programPath}/WineLib/run-more.sh' '{get_home()}/.deepinwine/debian-buster' {wine[i]}" #canUseWine.append(f"使用UOS Exagear容器运行库运行 {i}") #untipsWine.append(f"使用UOS Exagear容器运行库运行 {i}") except: traceback.print_exc() except: traceback.print_exc() app = QtWidgets.QApplication(sys.argv) QtWidgets.QMessageBox.critical(None, "错误", f"无法读取配置,无法继续\n{traceback.format_exc()}") sys.exit(1) CheckWine() # transla.transe programVersionType = "" print(wine) ########################### # 程序信息 ########################### app = QtWidgets.QApplication(sys.argv) trans = QtCore.QTranslator() transeObject = QtCore.QObject() transla = QtCore.QCoreApplication.translate #transeObject.tr("") # 语言载入 if not "zh_CN".lower() in get_now_lang().lower(): trans.load(f"{programPath}/LANG/deepin-wine-runner-en_US.qm") else: pass app.installTranslator(trans) iconPath = "{}/deepin-wine-runner.svg".format(programPath) iconPathList = [ "{}/deepin-wine-runner.svg".format(programPath), ] #iconPath = "{}/Icon/Program/wine运行器.png".format(programPath) programUrl = "https://gitee.com/gfdgd-xi/deep-wine-runner\nhttps://github.com/gfdgd-xi/deep-wine-runner\nhttps://gfdgd-xi.github.io" information = json.loads(readtxt(f"{programPath}/information.json")) version = information["Version"] goodRunSystem = QtCore.QCoreApplication.translate("U", "常见 Linux 发行版") thankText = "" lastRunCommand = "暂未运行命令" tips = QtCore.QCoreApplication.translate("U", '''Wine运行器是一个能让Linux用户更加方便地运行Windows应用的程序。原版的 Wine 只能使用命令操作,且安装过程较为繁琐,对小白不友好。于是该运行器为了解决该痛点,内置了对Wine图形化的支持、Wine 安装器、微型应用商店、各种Wine工具、自制的Wine程序打包器、运行库安装工具等。
它同时还内置了基于Qemu/VirtualBox制作的、专供小白使用的Windows虚拟机安装工具,可以做到只需下载系统镜像并点击安装即可,无需考虑虚拟机的安装、创建、分区等操作,也能在非 X86 架构安装 X86 架构的 Windows 操作系统(但是效率较低,可以运行些老系统)。
而且对于部分 Wine 应用适配者来说,提供了图形化的打包工具,以及提供了一些常用工具以及运行库的安装方式,以及能安装多种不同的 Wine 以测试效果,能极大提升适配效率。
且对于 Deepin23 用户做了特别优化,以便能在缺少 i386 运行库的情况下运行 Wine32。同时也为非 X86 架构用户提供了 Box86/64、Qemu User 的安装方式
""") about = f'''关于
{aboutProgram} 版本:{version} 适用平台:{goodRunSystem}(@VersionForType@) 安装包构建时间:{information['Time']} Qt 版本:{QtCore.qVersion()} 程序官网:{programUrl} Wine 运行器 QQ 交流群:762985460 Wine运行器 QQ 频道:https://pd.qq.com/s/edqkgeydx 当前程序占用体积:@programSize@MB
本程序依照 GPLV3 协议开源
{thankText}
{updateThingsString} 更新时间:{updateTime}
{tips}
星火应用商店:https://spark-app.store/ Deepin 官网:https://www.deepin.org Deepin 论坛:https://bbs.deepin.org gfdgd xi:https://gfdgd-xi.github.io") mainLayout.setRowStretch(0, 2) mainLayout.setRowStretch(1, 1) mainLayout.setColumnStretch(0, 2) mainLayout.setColumnStretch(1, 1) mainLayout.addWidget(returnText, 0, 1, 2, 1) # 版权 if offLineInformation.replace("\n", "").replace(" ", "") == "": copy = QtWidgets.QLabel(f"""程序版本:{version},提示:Wine 无法保证可以运行所有的 Windows 程序,如果想要运行更多 Windows 程序,可以考虑虚拟机和双系统
©2020~{time.strftime("%Y")} By gfdgd xi
''' defaultCommandText = "" + QtCore.QCoreApplication.translate("MainWindow", "在此可以看到wine安装应用时的终端输出内容") + """ ============================================================= 如果解决了你的问题,请不要吝啬你的star哟! 也可以请作者喝一杯茶 程序地址: https://gitee.com/gfdgd-xi/deep-wine-runner https://github.com/gfdgd-xi/deep-wine-runner https://sourceforge.net/projects/deep-wine-runner""" # 创建线程用于获取是否有更新 class GetUpdateToShow(QtCore.QThread): signal = QtCore.pyqtSignal(str) def __init__(self): super().__init__() def run(self): global defaultCommandText # 获取更新 url = "http://update.gfdgdxi.top/update.json" try: data = json.loads(requests.get(url).text) if data["Version"] != version: # 版本号读取(防止出现高版本号提示要“升级”到低版本号的问题) localVersionList = version.split(".") webVersionList = data['Version'].split(".") for i in range(len(localVersionList)): local = int(localVersionList[i]) web = int(webVersionList[i]) if web < local: break if web > local: defaultCommandText += f"""\n============================================================= Wine运行器 {data['Version']} 发布了!点此立即更新""" except: traceback.print_exc() # 获取应用公告 try: informationID = requests.get("http://update.gfdgdxi.top/wine-runner/info/id.json").json()["Number"] if not os.path.exists(f"{get_home()}/.config/deepin-wine-runner/information/{informationID}"): defaultCommandText += f"""\n============================================================= 程序有新的公告,点此立即查看""" except: traceback.print_exc() if lastRunCommand == "暂未运行命令": self.signal.emit(defaultCommandText + "") offLineInformation = "" if os.path.exists(f"{programPath}/off-line.lock"): title = "Wine 运行器 {}(离线模式)".format(version) try: offLineInformation = readtxt(f"{programPath}/off-line.lock") except: traceback.print_exc() else: title = "Wine 运行器 {}".format(version) #©2020~{time.strftime("%Y")} By gfdgd xi
''' updateThings = "{} 更新内容:\n{}\n更新时间:{}".format(version, updateThingsString, updateTime, time.strftime("%Y")) try: threading.Thread(target=requests.get, args=[parse.unquote(base64.b64decode("aHR0cDovLzEyMC4yNS4xNTMuMTQ0L3NwYXJrLWRlZXBpbi13aW5lLXJ1bm5lci9vcGVuL0luc3RhbGwucGhw").decode("utf-8")) + "?Version=" + version]).start() except: pass iconListUnBuild = json.loads(readtxt(f"{programPath}/IconList.json"))[0] iconList = json.loads(readtxt(f"{programPath}/IconList.json"))[1] for i in iconListUnBuild: iconList.append(i) print(iconList) # Qemu Lock try: if os.path.exists("/tmp/deepin-wine-runner-lock.txt"): print("lock") with open(f"/tmp/deepin-wine-runner-lock.txt", "r") as file: setting["QemuUnMountHome"] = bool(int(file.read())) else: print("unlock") with open(f"/tmp/deepin-wine-runner-lock.txt", "w") as file: # = bool(int(file.read())) file.write(str(int(setting["QemuUnMountHome"]))) except: traceback.print_exc() ########################### # 窗口创建 ########################### # 读取主题 # Qt 窗口 window = QtWidgets.QMainWindow() defaultFont = app.font() window.setWindowTitle(title) widget = QtWidgets.QWidget() window.setCentralWidget(widget) mainLayout = QtWidgets.QGridLayout() # 权重 size = QtWidgets.QSizePolicy() size.setHorizontalPolicy(0) widgetSize = QtWidgets.QSizePolicy() #size.setHorizontalPolicy(0) widgetSize.setVerticalPolicy(0) # leftUp = QtWidgets.QWidget() mainLayout.addWidget(leftUp, 0, 0, 1, 1) leftUpLayout = QtWidgets.QGridLayout() leftUp.setLayout(leftUpLayout) fastLabel = QtWidgets.QLabel(QtCore.QCoreApplication.translate("U", "快速启动")) fastLabel.setStyleSheet("font: 30px;") leftUpLayout.addWidget(fastLabel, 0, 0, 1, 2) leftUpLayout.addWidget(QtWidgets.QLabel("
"), 1, 0, 1, 2) leftUpLayout.addWidget(QtWidgets.QLabel(QtCore.QCoreApplication.translate("U", "请选择容器路径:")), 2, 0, 1, 1) e1 = QtWidgets.QComboBox() e1.setEditable(True) leftUpLayout.addWidget(e1, 3, 0, 1, 1) button1 = QtWidgets.QPushButton("浏览") button1.clicked.connect(liulanbutton) leftUpLayout.addWidget(button1, 3, 1, 1, 1) leftUpLayout.addWidget(QtWidgets.QLabel(QtCore.QCoreApplication.translate("U", "请选择要执行的程序(EXE、MSI或者命令):")), 4, 0, 1, 1) e2 = QtWidgets.QComboBox() if setting["AutoPath"]: e2.editTextChanged.connect(ChangePath) e2.setEditable(True) leftUpLayout.addWidget(e2, 5, 0, 1, 1) button2 = QtWidgets.QPushButton(QtCore.QCoreApplication.translate("U", "浏览")) button2.clicked.connect(liulanexebutton) leftUpLayout.addWidget(button2, 5, 1, 1, 1) leftUpLayout.addWidget(QtWidgets.QLabel(QtCore.QCoreApplication.translate("U", "请选择WINE版本:")), 6, 0, 1, 1) o1 = QtWidgets.QComboBox() leftUpLayout.addWidget(o1, 7, 0, 1, 1) # 设置空间权重 button1.setSizePolicy(size) button2.setSizePolicy(size) leftDown = QtWidgets.QWidget() mainLayout.addWidget(leftDown, 1, 0, 1, 1) leftDownLayout = QtWidgets.QVBoxLayout() leftDown.setLayout(leftDownLayout) highLabel = QtWidgets.QLabel(QtCore.QCoreApplication.translate("U", "高级功能")) highLabel.setStyleSheet("font: 30px;") leftDownLayout.addWidget(highLabel) leftDownLayout.addWidget(QtWidgets.QLabel("
")) leftDownLayout.addWidget(QtWidgets.QLabel(QtCore.QCoreApplication.translate("U", "创建快捷方式(Desktop文件):"))) createDesktopLink = QtWidgets.QHBoxLayout() label_r_2 = QtWidgets.QLabel(QtCore.QCoreApplication.translate("U", "名称:")) createDesktopLink.addWidget(label_r_2) combobox1 = QtWidgets.QComboBox() combobox1.setEditable(True) createDesktopLink.addWidget(combobox1) button5 = QtWidgets.QPushButton(QtCore.QCoreApplication.translate("U", "创建到桌面")) button5.clicked.connect(make_desktop_on_desktop) createDesktopLink.addWidget(button5) saveDesktopFileOnLauncher = QtWidgets.QPushButton(QtCore.QCoreApplication.translate("U", "创建到开始菜单")) saveDesktopFileOnLauncher.clicked.connect(make_desktop_on_launcher) createDesktopLink.addWidget(saveDesktopFileOnLauncher) leftDownLayout.addLayout(createDesktopLink) programManager = QtWidgets.QGridLayout() leftDownLayout.addLayout(programManager) programManager.addWidget(QtWidgets.QLabel(QtCore.QCoreApplication.translate("U", "程序管理:")), 0, 0, 1, 1) getProgramIcon = QtWidgets.QPushButton(QtCore.QCoreApplication.translate("U", "提取图标")) getProgramIcon.clicked.connect(lambda: RunWineProgram(f"{programPath}/BeCyIconGrabber.exe' '{e2.currentText()}" if e2.currentText()[:2].upper() == "C:" else f"{programPath}/BeCyIconGrabber.exe' 'z:/{e2.currentText()}")) programManager.addWidget(getProgramIcon, 1, 0, 1, 1) programManager.addWidget(QtWidgets.QLabel(" "*5), 1, 1, 1, 1) trasButton = QtWidgets.QPushButton(QtCore.QCoreApplication.translate("U", "窗口透明工具")) trasButton.clicked.connect(lambda: RunWineProgram(f"{programPath}/窗体透明度设置工具.exe")) programManager.addWidget(trasButton, 1, 2, 1, 1) uninstallProgram = QtWidgets.QPushButton(QtCore.QCoreApplication.translate("U", "卸载程序")) uninstallProgram.clicked.connect(lambda: RunWineProgram(f"{programPath}/geek.exe")) programManager.addWidget(QtWidgets.QLabel(" "*5), 1, 3, 1, 1) programManager.addWidget(uninstallProgram, 1, 4, 1, 1) miniAppStore = QtWidgets.QPushButton(QtCore.QCoreApplication.translate("U", "微型应用商店")) miniAppStore.clicked.connect(lambda: threading.Thread(target=MiniAppStore).start()) programManager.addWidget(QtWidgets.QLabel(" "*5), 1, 5, 1, 1) programManager.addWidget(miniAppStore, 1, 6, 1, 1) programManager.addWidget(QtWidgets.QLabel(" "*5), 1, 7, 1, 1) getProgramStatus = QtWidgets.QPushButton(QtCore.QCoreApplication.translate("U", "获取该程序运行情况")) getProgramStatus.clicked.connect(ProgramRunStatusShow.ShowWindow) programManager.addWidget(getProgramStatus, 1, 8, 1, 1) getLoseDll = QtWidgets.QPushButton(QtCore.QCoreApplication.translate("U", "检测静态下程序缺少DLL")) getLoseDll.clicked.connect(GetLoseDll) programManager.addWidget(QtWidgets.QLabel(" "*5), 1, 9, 1, 1) programManager.addWidget(getLoseDll, 1, 10, 1, 1) programManager.addItem(QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum), 1, 11, 1, 1) programManager.addWidget(QtWidgets.QLabel(QtCore.QCoreApplication.translate("U", "WINE配置:")), 2, 0, 1, 1) wineConfig = QtWidgets.QPushButton(QtCore.QCoreApplication.translate("U", "配置容器")) wineConfig.clicked.connect(lambda: RunWineProgram("winecfg")) programManager.addWidget(wineConfig, 3, 0, 1, 1) fontAppStore = QtWidgets.QPushButton(QtCore.QCoreApplication.translate("U", "字体商店")) fontAppStore.clicked.connect(FontAppStore) programManager.addWidget(fontAppStore, 3, 2, 1, 1) button_r_6 = QtWidgets.QPushButton(QtCore.QCoreApplication.translate("U", "RegShot")) button_r_6.clicked.connect(lambda: RunWineProgram(f"{programPath}/RegShot/regshot.exe")) programManager.addWidget(button_r_6, 3, 4, 1, 1) sparkWineSetting = QtWidgets.QPushButton(QtCore.QCoreApplication.translate("U", "星火wine配置")) sparkWineSetting.clicked.connect(lambda: threading.Thread(target=os.system, args=["bash /opt/durapps/spark-dwine-helper/spark-dwine-helper-settings/settings.sh"]).start()) programManager.addWidget(sparkWineSetting, 3, 6, 1, 1) wineAutoConfig = QtWidgets.QPushButton(QtCore.QCoreApplication.translate("U", "自动/手动配置 Wine 容器")) wineAutoConfig.clicked.connect(WineBottonAutoConfig) programManager.addWidget(wineAutoConfig, 3, 8, 1, 1) wineBottleReboot = QtWidgets.QPushButton(QtCore.QCoreApplication.translate("U", "重启指定Wine容器")) wineBottleReboot.clicked.connect(lambda: RunWineProgram(f"wineboot' '-k")) programManager.addWidget(wineBottleReboot, 3, 10, 1, 1) # 权重 button5.setSizePolicy(size) saveDesktopFileOnLauncher.setSizePolicy(size) label_r_2.setSizePolicy(size) getProgramIcon.setSizePolicy(size) #trasButton.setSizePolicy(size) button_r_6.setSizePolicy(size) wineConfig.setSizePolicy(size) returnText = QtWidgets.QTextBrowser() getUpdate = GetUpdateToShow() getUpdate.signal.connect(returnText.setHtml) getUpdate.start() def ReturnTextOpenUrl(url): print(url) if url.url() == "http://update.gfdgdxi.top/update-wine-runner": UpdateWindow.ShowWindow() elif url.url() == "http://update.gfdgdxi.top/information-wine-runner": GetNewInformation() elif url.url() == "http://update.gfdgdxi.top/Appreciate": Appreciate() else: webbrowser.open_new_tab(url.url()) returnText.anchorClicked.connect(ReturnTextOpenUrl) returnText.setOpenExternalLinks(False) returnText.setOpenLinks(False) returnText.setStyleSheet(""" background-color: black; color: white; """) returnText.setHtml(QtCore.QCoreApplication.translate("U", defaultCommandText) + "