mirror of
https://gitee.com/gfdgd-xi/deep-wine-runner
synced 2025-05-14 12:09:54 +08:00
1514 lines
80 KiB
Python
Executable File
1514 lines
80 KiB
Python
Executable File
#!/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 threading
|
||
import traceback
|
||
import webbrowser
|
||
import subprocess
|
||
import req as requests
|
||
import urllib.parse as parse
|
||
import PyQt5.QtGui as QtGui
|
||
import PyQt5.QtCore as QtCore
|
||
import PyQt5.QtWidgets as QtWidgets
|
||
from trans import *
|
||
from Model 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 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 = []
|
||
|
||
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)
|
||
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):
|
||
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()
|
||
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()):
|
||
OpenTerminal("env WINEPREFIX='" + wineBottonPath + "' " + option + wine[o1.currentText()] + " msiexec /i '" + e2.currentText() + "' " + setting["WineOption"])
|
||
elif e2.currentText()[-4:] == ".bat" and os.path.exists(e2.currentText()):
|
||
OpenTerminal("env WINEPREFIX='" + wineBottonPath + "' " + option + wine[o1.currentText()] + " wineconsole '" + e2.currentText() + "' " + setting["WineOption"])
|
||
else:
|
||
OpenTerminal("env WINEPREFIX='" + wineBottonPath + "' " + option + wine[o1.currentText()] + " '" + exePath + "' " + setting["WineOption"])
|
||
#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()):
|
||
res = subprocess.Popen(["WINEPREFIX='" + wineBottonPath + "' " + option + wine[o1.currentText()] + " msiexec /i '" + e2.currentText() + "' " + setting["WineOption"]], shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||
elif e2.currentText()[-4:] == ".bat" and os.path.exists(e2.currentText()):
|
||
res = subprocess.Popen(["WINEPREFIX='" + wineBottonPath + "' " + option + wine[o1.currentText()] + " wineconsole '" + e2.currentText() + "' " + setting["WineOption"]], shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||
else:
|
||
print(["WINEPREFIX='" + wineBottonPath + "' " + option + wine[o1.currentText()] + " '" + exePath + "' " + setting["WineOption"]])
|
||
res = subprocess.Popen(["WINEPREFIX='" + wineBottonPath + "' " + option + wine[o1.currentText()] + " '" + exePath + "' " + setting["WineOption"]], shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||
# 实时读取程序返回
|
||
#
|
||
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
|
||
|
||
def OpenUrl(url):
|
||
print(url.url())
|
||
# 判断是否可以使用小窗打开
|
||
if not bad:
|
||
Temp.webWindow = QtWidgets.QMainWindow()
|
||
web = QtWebEngineWidgets.QWebEngineView()
|
||
web.setUrl(url)
|
||
Temp.webWindow.setWindowTitle("浏览页面")
|
||
Temp.webWindow.setCentralWidget(web)
|
||
Temp.webWindow.setWindowIcon(QtGui.QIcon(iconPath))
|
||
Temp.webWindow.show()
|
||
return
|
||
webbrowser.open_new_tab(url.url())
|
||
|
||
#QtCore.QUrl().url()
|
||
|
||
# 显示“关于这个程序”窗口
|
||
def about_this_program()->"显示“关于这个程序”窗口":
|
||
global about
|
||
global title
|
||
global iconPath
|
||
QT.message = QtWidgets.QMainWindow()
|
||
QT.message.setWindowIcon(QtGui.QIcon(iconPath))
|
||
messageWidget = QtWidgets.QWidget()
|
||
QT.message.setWindowTitle(f"关于 {title}")
|
||
messageLayout = QtWidgets.QGridLayout()
|
||
messageLayout.addWidget(QtWidgets.QLabel(f"<img width=256 src='{iconPath}'>"), 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(transla.transe("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()
|
||
|
||
# 生成 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 ReStartProgram():
|
||
python = sys.executable
|
||
os.execl(python, python, * sys.argv)
|
||
|
||
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 OpenWineBotton():
|
||
if e1.currentText() == "":
|
||
wineBottonPath = setting["DefultBotton"]
|
||
else:
|
||
wineBottonPath = e1.currentText()
|
||
os.system("xdg-open \"" + wineBottonPath.replace("\'", "\\\'") + "\"")
|
||
|
||
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):
|
||
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 = ""
|
||
OpenTerminal(f"env WINEPREFIX='" + wineBottonPath + "' " + option + wine[o1.currentText()] + " '" + self.wineProgram + "' " + setting["WineOption"] + " " + wineUsingOption)
|
||
#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:
|
||
res = subprocess.Popen(["WINEPREFIX='" + wineBottonPath + "' " + option + wine[o1.currentText()] + " '" + self.wineProgram + "' " + setting["WineOption"]], shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||
# 实时读取程序返回
|
||
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:
|
||
DisableButton(False)
|
||
return
|
||
returnText.setText("")
|
||
runProgram = RunWineProgramThread(wineProgram, history, Disbled)
|
||
runProgram.signal.connect(QT.ShowWineReturn)
|
||
runProgram.showHistory.connect(QT.ShowHistory)
|
||
runProgram.start()
|
||
|
||
|
||
def ThankWindow():
|
||
# 直接显示关于窗口,关于窗口已经添加
|
||
about_this_program()
|
||
|
||
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 # 返回结果
|
||
|
||
choose = None
|
||
|
||
class ProgramSetting():
|
||
wineBottonA = None
|
||
wineDebug = None
|
||
defultWine = None
|
||
defultBotton = None
|
||
terminalOpen = None
|
||
wineOption = None
|
||
#wineBottonDifferent = None
|
||
centerWindow = None
|
||
message = None
|
||
theme = None
|
||
monogeckoInstaller = None
|
||
autoWine = None
|
||
runtimeCache = None
|
||
buildByBottleName = None
|
||
autoPath = None
|
||
qemuUnmountHome = None
|
||
def ShowWindow():
|
||
ProgramSetting.message = QtWidgets.QMainWindow()
|
||
widget = QtWidgets.QWidget()
|
||
widgetLayout = QtWidgets.QGridLayout()
|
||
widgetLayout.addWidget(QtWidgets.QLabel(transla.transe("U", "选择 Wine 容器版本:")), 0, 0, 1, 1)
|
||
widgetLayout.addWidget(QtWidgets.QLabel(transla.transe("U", "wine DEBUG 信息输出:")), 1, 0, 1, 1)
|
||
widgetLayout.addWidget(QtWidgets.QLabel(transla.transe("U", "默认 Wine:")), 2, 0, 1, 1)
|
||
widgetLayout.addWidget(QtWidgets.QLabel(transla.transe("U", "默认 Wine 容器:")), 3, 0, 1, 1)
|
||
widgetLayout.addWidget(QtWidgets.QLabel(transla.transe("U", "使用终端打开:")), 4, 0, 1, 1)
|
||
widgetLayout.addWidget(QtWidgets.QLabel(transla.transe("U", "自定义 wine 参数:")), 5, 0, 1, 1)
|
||
widgetLayout.addWidget(QtWidgets.QLabel(transla.transe("U", "程序主题:")), 6, 0, 1, 1)
|
||
widgetLayout.addWidget(QtWidgets.QLabel(transla.transe("U", "Wine 默认 Mono 和 Gecko 安装器:")), 7, 0, 1, 1)
|
||
widgetLayout.addWidget(QtWidgets.QLabel(transla.transe("U", "忽略未安装的 Wine:")), 8, 0, 1, 1)
|
||
widgetLayout.addWidget(QtWidgets.QLabel(transla.transe("U", "下载缓存:")), 9, 0, 1, 1)
|
||
widgetLayout.addWidget(QtWidgets.QLabel(transla.transe("U", "图标生成:")), 10, 0, 1, 1)
|
||
widgetLayout.addWidget(QtWidgets.QLabel(transla.transe("U", "自动根据EXE名称生成路径:")), 11, 0, 1, 1)
|
||
widgetLayout.addWidget(QtWidgets.QLabel(transla.transe("U", "Qemu + Chroot 挂载用户目录:")), 12, 0, 1, 1)
|
||
ProgramSetting.wineBottonA = QtWidgets.QComboBox()
|
||
ProgramSetting.wineDebug = QtWidgets.QCheckBox(transla.transe("U", "开启 DEBUG 输出"))
|
||
ProgramSetting.defultWine = QtWidgets.QComboBox()
|
||
ProgramSetting.defultBotton = QtWidgets.QLineEdit()
|
||
ProgramSetting.theme = QtWidgets.QComboBox()
|
||
ProgramSetting.theme.addItems(QtWidgets.QStyleFactory.keys())
|
||
ProgramSetting.theme.setCurrentText(setting["Theme"])
|
||
save = QtWidgets.QPushButton(transla.transe("U", "保存"))
|
||
save.clicked.connect(ProgramSetting.Save)
|
||
defultBottonButton = QtWidgets.QPushButton(transla.transe("U", "浏览"))
|
||
defultBottonButton.clicked.connect(ProgramSetting.Browser)
|
||
themeTry = QtWidgets.QPushButton(transla.transe("U", "测试(重启后变回设置的主题)"))
|
||
themeTry.clicked.connect(ProgramSetting.Try)
|
||
ProgramSetting.terminalOpen = QtWidgets.QCheckBox(transla.transe("U", "使用终端打开(deepin 终端)"))
|
||
ProgramSetting.wineOption = QtWidgets.QLineEdit()
|
||
ProgramSetting.monogeckoInstaller = QtWidgets.QCheckBox(transla.transe("U", "屏蔽 Wine 默认 Mono 和 Gecko 安装器"))
|
||
ProgramSetting.autoWine = QtWidgets.QCheckBox(transla.transe("U", "不显示未检测到的 Wine"))
|
||
ProgramSetting.runtimeCache = QtWidgets.QCheckBox(transla.transe("U", "开启下载缓存"))
|
||
ProgramSetting.buildByBottleName = QtWidgets.QCheckBox(transla.transe("U", "本软件构建的图标后面添加容器名"))
|
||
ProgramSetting.autoPath = QtWidgets.QCheckBox(transla.transe("U", "自动根据文件名生成容器路径(开启后必须通过修改默认wine容器路径才可指定其它路径,重启程序后生效)"))
|
||
ProgramSetting.qemuUnmountHome = QtWidgets.QCheckBox(transla.transe("U", "使用 Qemu + Chroot 时不挂载用户目录并与系统隔离(修改后重启操作系统生效)"))
|
||
ProgramSetting.wineBottonA.addItems(["Auto", "win32", "win64"])
|
||
ProgramSetting.wineBottonA.setCurrentText(setting["Architecture"])
|
||
ProgramSetting.wineDebug.setChecked(setting["Debug"])
|
||
ProgramSetting.defultWine.addItems(wine.keys())
|
||
ProgramSetting.defultWine.setCurrentText(setting["DefultWine"])
|
||
ProgramSetting.defultBotton.setText(setting["DefultBotton"])
|
||
ProgramSetting.terminalOpen.setChecked(setting["TerminalOpen"])
|
||
ProgramSetting.wineOption.setText(setting["WineOption"])
|
||
ProgramSetting.monogeckoInstaller.setChecked(setting["MonoGeckoInstaller"])
|
||
ProgramSetting.autoWine.setChecked(setting["AutoWine"])
|
||
ProgramSetting.runtimeCache.setChecked(setting["RuntimeCache"])
|
||
ProgramSetting.buildByBottleName.setChecked(setting["BuildByBottleName"])
|
||
ProgramSetting.autoPath.setChecked(setting["AutoPath"])
|
||
ProgramSetting.qemuUnmountHome.setChecked(setting["QemuUnMountHome"])
|
||
# QemuUnMountHome
|
||
widgetLayout.addWidget(ProgramSetting.wineBottonA, 0, 1, 1, 1)
|
||
widgetLayout.addWidget(ProgramSetting.wineDebug, 1, 1, 1, 1)
|
||
widgetLayout.addWidget(ProgramSetting.defultWine, 2, 1, 1, 1)
|
||
widgetLayout.addWidget(ProgramSetting.defultBotton, 3, 1, 1, 1)
|
||
widgetLayout.addWidget(defultBottonButton, 3, 2, 1, 1)
|
||
widgetLayout.addWidget(ProgramSetting.terminalOpen, 4, 1, 1, 1)
|
||
widgetLayout.addWidget(ProgramSetting.wineOption, 5, 1, 1, 1)
|
||
widgetLayout.addWidget(ProgramSetting.theme, 6, 1, 1, 1)
|
||
widgetLayout.addWidget(themeTry, 6, 2, 1, 1)
|
||
widgetLayout.addWidget(ProgramSetting.monogeckoInstaller, 7, 1, 1, 1)
|
||
widgetLayout.addWidget(ProgramSetting.autoWine, 8, 1, 1, 1)
|
||
widgetLayout.addWidget(ProgramSetting.runtimeCache, 9, 1, 1, 1)
|
||
widgetLayout.addWidget(ProgramSetting.buildByBottleName, 10, 1, 1, 1)
|
||
widgetLayout.addWidget(ProgramSetting.autoPath, 11, 1, 1, 2)
|
||
widgetLayout.addWidget(ProgramSetting.qemuUnmountHome, 12, 1, 1, 2)
|
||
widgetLayout.addWidget(save, 13, 2, 1, 1)
|
||
widget.setLayout(widgetLayout)
|
||
ProgramSetting.message.setCentralWidget(widget)
|
||
ProgramSetting.message.setWindowIcon(QtGui.QIcon(iconPath))
|
||
ProgramSetting.message.setWindowTitle(f"设置 wine 运行器 {version}")
|
||
ProgramSetting.message.show()
|
||
|
||
def Browser():
|
||
path = QtWidgets.QFileDialog.getExistingDirectory(ProgramSetting.message, transla.transe("U", "选择 Wine 容器"), json.loads(readtxt(get_home() + "/.config/deepin-wine-runner/WineBotton.json"))["path"])
|
||
if path == "" or path == None or path == "()" or path == ():
|
||
return
|
||
ProgramSetting.defultBotton.setText(path)
|
||
|
||
def Try():
|
||
app.setStyle(QtWidgets.QStyleFactory.create(ProgramSetting.theme.currentText()))
|
||
|
||
def Save():
|
||
# 写入容器位数设置
|
||
setting["Architecture"] = ProgramSetting.wineBottonA.currentText()
|
||
setting["Debug"] = ProgramSetting.wineDebug.isChecked()
|
||
setting["DefultWine"] = ProgramSetting.defultWine.currentText()
|
||
setting["DefultBotton"] = ProgramSetting.defultBotton.text()
|
||
setting["TerminalOpen"] = ProgramSetting.terminalOpen.isChecked()
|
||
setting["WineOption"] = ProgramSetting.wineOption.text()
|
||
setting["Theme"] = ProgramSetting.theme.currentText()
|
||
setting["MonoGeckoInstaller"] = ProgramSetting.monogeckoInstaller.isChecked()
|
||
setting["AutoWine"] = ProgramSetting.autoWine.isChecked()
|
||
setting["RuntimeCache"] = ProgramSetting.runtimeCache.isChecked()
|
||
setting["BuildByBottleName"] = ProgramSetting.buildByBottleName.isChecked()
|
||
setting["AutoPath"] = ProgramSetting.autoPath.isChecked()
|
||
setting["QemuUnMountHome"] = ProgramSetting.qemuUnmountHome.isChecked()
|
||
try:
|
||
write_txt(get_home() + "/.config/deepin-wine-runner/WineSetting.json", json.dumps(setting))
|
||
except:
|
||
traceback.print_exc()
|
||
QtWidgets.QMessageBox.critical(ProgramSetting.message, "错误", traceback.format_exc())
|
||
return
|
||
QtWidgets.QMessageBox.information(ProgramSetting.message, "提示", "保存完毕!")
|
||
|
||
def ChangePath():
|
||
e1.setCurrentText(f'{setting["DefultBotton"]}/{os.path.splitext(os.path.basename(e2.currentText()))[0]}')
|
||
|
||
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.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": "deepin/UOS 应用商店版本<带签名>"
|
||
}
|
||
# 直接判断是不是 Docker 版本
|
||
if os.path.exists(f"{programPath}/docker.txt") or os.path.exists("/.dockerenv"):
|
||
programVersionType = "Docker/Chroot 内置版本"
|
||
window.setWindowTitle(f"{title} (Docker/Chroot 内置版本)")
|
||
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 = "Docker 内置版本"
|
||
window.setWindowTitle(f"{title} (Docker 内置版本)")
|
||
#AddDockerMenu()
|
||
self.signal.emit("")
|
||
break
|
||
if fileName[i] == "Package: spark-deepin-wine-runner-52":
|
||
programVersionType = "吾爱专版"
|
||
window.setWindowTitle(f"{title}(吾爱专版)")
|
||
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 = "从Gitee/Github/Gitlink等平台获取的版本"
|
||
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 = "从Gitee/Github/Gitlink等平台获取的版本"
|
||
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 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
|
||
|
||
###########################
|
||
# 加载配置
|
||
###########################
|
||
defultProgramList = {
|
||
"Architecture": "Auto",
|
||
"Debug": True,
|
||
"DefultWine": "deepin-wine6 stable",
|
||
"DefultBotton" : get_home() + "/.wine",
|
||
"TerminalOpen": False,
|
||
"WineOption": "",
|
||
"WineBottonDifferent": False,
|
||
"CenterWindow": False,
|
||
"Theme": "",
|
||
"MonoGeckoInstaller": False,
|
||
"AutoWine": True,
|
||
"RuntimeCache": True,
|
||
"MustRead": False,
|
||
"BuildByBottleName": False,
|
||
"AutoPath": False,
|
||
"QemuUnMountHome": False
|
||
}
|
||
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(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
|
||
#############
|
||
try:
|
||
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 ",
|
||
"deepin-wine6 stable": "deepin-wine6-stable",
|
||
"deepin-wine5 stable": "deepin-wine5-stable",
|
||
"spark-wine7-devel": "spark-wine7-devel",
|
||
"deepin-wine": "deepin-wine",
|
||
"deepin-wine5": "deepin-wine5",
|
||
"wine": "wine",
|
||
"wine64": "wine64",
|
||
"ukylin-wine": "ukylin-wine",
|
||
"mono(这不是 wine,但可以实现初步调用运行 .net 应用)": "mono",
|
||
"基于 linglong 的 deepin-wine6-stable(不推荐)": f"ll-cli run '' --exec '/bin/deepin-wine6-stable'"
|
||
}
|
||
untipsWine = ["基于 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 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(需要解包的才能使用)
|
||
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
|
||
])
|
||
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:
|
||
# 不再从列表读取,直接读目录
|
||
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 exagear") == 0:
|
||
nameValue.append(
|
||
[
|
||
"基于 exagear 的 ",
|
||
f"exagear "
|
||
]
|
||
)
|
||
if os.path.exists("/opt/exagear/bin/ubt_x64a64_al"):
|
||
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 -- "
|
||
]
|
||
)
|
||
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
|
||
if os.path.exists(f"{programPath}/wine/{i}/bin/wine"):
|
||
wine[f"{k[0]}{chrootProgramPath}/wine/{i}/bin/wine"] = f"{k[1]}{chrootProgramPath}/wine/{i}/bin/wine"
|
||
canUseWine.append(f"{k[0]}{chrootProgramPath}/wine/{i}/bin/wine")
|
||
untipsWine.append(f"{k[0]}{chrootProgramPath}/wine/{i}/bin/wine")
|
||
if os.path.exists(f"{programPath}/wine/{i}/bin/wine64"):
|
||
wine[f"{k[0]}{chrootProgramPath}/wine/{i}/bin/wine64"] = f"{k[1]}{chrootProgramPath}/wine/{i}/bin/wine64"
|
||
canUseWine.append(f"{k[0]}{chrootProgramPath}/wine/{i}/bin/wine64")
|
||
untipsWine.append(f"{k[0]}{chrootProgramPath}/wine/{i}/bin/wine64")
|
||
except:
|
||
pass
|
||
try:
|
||
for i in os.listdir(f"{get_home()}/.deepinwine/"):
|
||
if os.path.exists(f"{get_home()}/.deepinwine/{i}/bin/wine"):
|
||
wine[f"{get_home()}/.deepinwine/{i}/bin/wine"] = f"{get_home()}/.deepinwine/{i}/bin/wine"
|
||
canUseWine.append(f"{get_home()}/.deepinwine/{i}/bin/wine")
|
||
if os.path.exists(f"{get_home()}/.deepinwine/{i}/bin/wine64"):
|
||
wine[f"{get_home()}/.deepinwine/{i}/bin/wine64"] = f"{get_home()}/.deepinwine/{i}/bin/wine64"
|
||
canUseWine.append(f"{get_home()}/.deepinwine/{i}/bin/wine64")
|
||
except:
|
||
pass
|
||
except:
|
||
traceback.print_exc()
|
||
app = QtWidgets.QApplication(sys.argv)
|
||
QtWidgets.QMessageBox.critical(None, "错误", f"无法读取配置,无法继续\n{traceback.format_exc()}")
|
||
sys.exit(1)
|
||
|
||
# transla.transe
|
||
|
||
programVersionType = ""
|
||
print(wine)
|
||
###########################
|
||
# 程序信息
|
||
###########################
|
||
# 语言载入
|
||
if not "zh_CN".lower() in get_now_lang().lower():
|
||
transla = Trans("en_US", f"{programPath}/trans/deepin-wine-runner.json")
|
||
else:
|
||
transla = Trans("zh_CN")
|
||
iconPath = "{}/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://www.gitlink.org.cn/gfdgd_xi/deep-wine-runner\nhttps://gfdgd-xi.github.io"
|
||
information = json.loads(readtxt(f"{programPath}/information.json"))
|
||
version = information["Version"]
|
||
goodRunSystem = transla.transe("U", "常见 Linux 发行版")
|
||
thankText = ""
|
||
tips = transla.transe("U", '''<h4>提示:</h4>
|
||
1、使用终端运行该程序,可以看到 wine 以及程序本身的提示和报错;
|
||
2、wine 32 位和 64 位的容器互不兼容;
|
||
3、所有的 wine 和 winetricks 均需要自行安装(可以从 菜单栏=>程序 里面进行安装);
|
||
4、本程序支持带参数运行 wine 程序(之前版本也可以),只需要按以下格式即可:
|
||
exe路径\' 参数 \'
|
||
即可(单引号需要输入);
|
||
5、wine 容器如果没有指定,则会默认为 ~/.wine;
|
||
6、如果可执行文件比较大的话,会出现点击“获取该程序运行情况”出现假死的情况,因为正在后台读取 SHA1,只需要等一下即可(读取速度依照您电脑处理速度、读写速度、可执行文件大小等有关);
|
||
7、对于非 X86 的用户来说,请不要使用本程序自带的 Wine 安装程序和 Windows 虚拟机安装功能(检测到为非 X86 架构会自动禁用);
|
||
8、如果非 X86 的用户的 UOS 专业版用户想要使用的话,只需要在应用商店安装一个 Wine 版本微信即可在本程序选择正确的 Wine 运行程序;
|
||
9、在使用 linglong 包的 Wine 应用时,必须安装至少一个 linglong 的使用 Wine 软件包才会出现该选项,
|
||
而程序识别到的 Wine 是按 linglong 的使用 Wine 软件包名的字母排序第一个的 Wine,且生成的容器不在用户目录下,而是在容器的用户目录下(~/.deepinwine、/tmp、桌面、下载、文档等被映射的目录除外),
|
||
同理需要运行的 EXE 也必须在被映射的目录内;
|
||
10、如果是使用 Deepin 23 的 Wine 安装脚本,请切记——安装过程会临时添加 Deepin 20 的 apt 源,不要中断安装以及
|
||
<b>千万不要中断后不删除源的情况下 apt upgrade !!!</b>中断后只需重新打开脚本输入 repair 或者随意安装一个 Wine(会自动执行恢复操作)即可
|
||
以及此脚本安装的 Wine 无法保证 100% 能使用,以及副作用是会提示;
|
||
<code>N: 鉴于仓库 'https://community-packages.deepin.com/beige beige InRelease' 不支持 'i386' 体系结构,跳过配置文件 'main/binary-i386/Packages' 的获取。</code>''')
|
||
updateThingsString = transla.transe("U", '''※1、不基于生态适配脚本打包器支持禁用 Mono/Gecko 打包器;
|
||
※2、自动容器配置脚本新增命令 decompressionbottle、programforum、installmsi 以及上述命令的帮助;
|
||
※3、自动容器配置脚本新增评论功能;
|
||
※4、自动容器配置脚本新增许多应用安装脚本;
|
||
※5、安装 Windows 虚拟机功能更换应答镜像图标并添加常用 Windows 组件安装功能;
|
||
※6、安装 Windows 虚拟机功能提供镜像下载的网盘链接;
|
||
※7、简易打包器支持自动添加宋体;
|
||
8、修复 installfont 命令下载的字体目录错误问题;
|
||
9、修复提交日志功能在提交成功时依旧提示提交失败问题;
|
||
10、支持强制启用所有被禁用的组件(不推荐)。
|
||
''')
|
||
for i in information["Thank"]:
|
||
thankText += f"{i}\n"
|
||
updateTime = "2023年01月06日"
|
||
aboutProgram = transla.transe("U", """<p>Wine运行器是一个能让Linux用户更加方便地运行Windows应用的程序,内置了对Wine图形化的支持、各种Wine工具、自制的Wine程序打包器和运行库安装工具等。</p>
|
||
<p>它同时还内置了基于VirtualBox制作的、专供小白使用的Windows虚拟机安装工具,可以做到只需下载系统镜像并点击安装即可,无需考虑虚拟机的安装、创建、分区等操作。</p>
|
||
<pre>
|
||
|
||
一个图形化了如下命令的程序(最简单格式)
|
||
<code>env WINEPREFIX=容器路径 wine(wine的路径) 可执行文件路径</code>
|
||
让你可以简易方便的使用 wine""")
|
||
about = f'''<style>
|
||
a:link, a:active {{
|
||
text-decoration: none;
|
||
}}
|
||
</style>
|
||
<h1>关于</h1>
|
||
{aboutProgram}
|
||
|
||
版本:{version}
|
||
适用平台:{goodRunSystem}(@VersionForType@)
|
||
Qt 版本:{QtCore.qVersion()}
|
||
程序官网:{programUrl}
|
||
当前程序占用体积:@programSize@MB</pre>
|
||
<p>本程序依照 GPLV3 协议开源</p>
|
||
<hr>
|
||
<h1>鸣谢名单</h1>
|
||
<pre>{thankText}</pre>
|
||
<hr>
|
||
<h1>更新内容</h1>
|
||
<pre>{updateThingsString}
|
||
<b>更新时间:{updateTime}</b></pre>
|
||
<hr>
|
||
<h1>提示</h1>
|
||
<pre>{tips}
|
||
</pre>
|
||
<hr>
|
||
<h1>关于 RacoonGX 项目组</h1>
|
||
<p>是由 @gfdgd xi 带头的团队,gfdgd xi开发了UEngine运行器等好用的开源软件。</p>
|
||
<hr>
|
||
<h1>友谊链接</h1>
|
||
<pre>星火应用商店:https://spark-app.store/
|
||
Deepin 官网:https://www.deepin.org
|
||
Deepin 论坛:https://bbs.deepin.org
|
||
论坛:https://gfdgdxi.flarum.cloud/</pre>
|
||
<hr>
|
||
<h1>©2020~{time.strftime("%Y")} By gfdgd xi、为什么您不喜欢熊出没和阿布呢,RacoonGX 团队作品</h1>'''
|
||
title = "Wine 运行器 {}".format(version)
|
||
#<h1>©2020~{time.strftime("%Y")} <a href="https://gitee.com/gfdgd-xi">RacoonGX 团队,By gfdgd xi、为什么您不喜欢熊出没和阿布呢</h1>'''
|
||
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 窗口
|
||
app = QtWidgets.QApplication(sys.argv)
|
||
window = QtWidgets.QMainWindow()
|
||
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(transla.transe("U", "快速启动"))
|
||
fastLabel.setStyleSheet("font: 30px;")
|
||
leftUpLayout.addWidget(fastLabel, 0, 0, 1, 2)
|
||
leftUpLayout.addWidget(QtWidgets.QLabel("<hr>"), 1, 0, 1, 2)
|
||
leftUpLayout.addWidget(QtWidgets.QLabel(transla.transe("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(transla.transe("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(transla.transe("U", "浏览"))
|
||
button2.clicked.connect(liulanexebutton)
|
||
leftUpLayout.addWidget(button2, 5, 1, 1, 1)
|
||
leftUpLayout.addWidget(QtWidgets.QLabel(transla.transe("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(transla.transe("U", "高级功能"))
|
||
highLabel.setStyleSheet("font: 30px;")
|
||
leftDownLayout.addWidget(highLabel)
|
||
leftDownLayout.addWidget(QtWidgets.QLabel("<hr>"))
|
||
leftDownLayout.addWidget(QtWidgets.QLabel(transla.transe("U", "创建快捷方式(Desktop文件):")))
|
||
createDesktopLink = QtWidgets.QHBoxLayout()
|
||
label_r_2 = QtWidgets.QLabel(transla.transe("U", "名称:"))
|
||
createDesktopLink.addWidget(label_r_2)
|
||
combobox1 = QtWidgets.QComboBox()
|
||
combobox1.setEditable(True)
|
||
createDesktopLink.addWidget(combobox1)
|
||
button5 = QtWidgets.QPushButton(transla.transe("U", "创建到桌面"))
|
||
button5.clicked.connect(make_desktop_on_desktop)
|
||
createDesktopLink.addWidget(button5)
|
||
saveDesktopFileOnLauncher = QtWidgets.QPushButton(transla.transe("U", "创建到开始菜单"))
|
||
saveDesktopFileOnLauncher.clicked.connect(make_desktop_on_launcher)
|
||
createDesktopLink.addWidget(saveDesktopFileOnLauncher)
|
||
leftDownLayout.addLayout(createDesktopLink)
|
||
programManager = QtWidgets.QGridLayout()
|
||
leftDownLayout.addLayout(programManager)
|
||
programManager.addWidget(QtWidgets.QLabel(transla.transe("U", "程序管理:")), 0, 0, 1, 1)
|
||
programManager.addWidget(QtWidgets.QLabel(" "*5), 1, 5, 1, 1)
|
||
programManager.addItem(QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum), 1, 11, 1, 1)
|
||
programManager.addWidget(QtWidgets.QLabel(transla.transe("U", "WINE配置:")), 2, 0, 1, 1)
|
||
wineConfig = QtWidgets.QPushButton(transla.transe("U", "配置容器"))
|
||
wineConfig.clicked.connect(lambda: RunWineProgram("winecfg"))
|
||
programManager.addWidget(wineConfig, 3, 0, 1, 1)
|
||
# 权重
|
||
button5.setSizePolicy(size)
|
||
saveDesktopFileOnLauncher.setSizePolicy(size)
|
||
label_r_2.setSizePolicy(size)
|
||
#trasButton.setSizePolicy(size)
|
||
wineConfig.setSizePolicy(size)
|
||
|
||
returnText = QtWidgets.QTextBrowser()
|
||
returnText.setStyleSheet("""
|
||
background-color: black;
|
||
color: white;
|
||
""")
|
||
returnText.setText(transla.transe("U", "在此可以看到wine安装应用时的终端输出内容"))
|
||
mainLayout.setRowStretch(0, 2)
|
||
mainLayout.setRowStretch(1, 1)
|
||
mainLayout.setColumnStretch(0, 2)
|
||
mainLayout.setColumnStretch(1, 1)
|
||
mainLayout.addWidget(returnText, 0, 1, 2, 1)
|
||
|
||
# 版权
|
||
copy = QtWidgets.QLabel(f"""\n程序版本:{version},<b>提示:Wine 无法运行保证可以运行所有的 Windows 程序,如果想要运行更多可执行程序,可以考虑虚拟机和双系统</b><br>
|
||
©2020~{time.strftime("%Y")} gfdgd xi、为什么您不喜欢熊出没和阿布呢,RacoonGX 团队作品""")
|
||
mainLayout.addWidget(copy, 2, 0, 1, 1)
|
||
|
||
# 程序运行
|
||
programRun = QtWidgets.QWidget()
|
||
programRunLayout = QtWidgets.QHBoxLayout()
|
||
programRun.setLayout(programRunLayout)
|
||
programRunLayout.addItem(QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum))
|
||
button3 = QtWidgets.QPushButton(transla.transe("U", "运行程序"))
|
||
button3.clicked.connect(runexebutton)
|
||
programRunLayout.addWidget(button3)
|
||
killProgram = QtWidgets.QPushButton(transla.transe("U", "终止程序"))
|
||
killProgram.clicked.connect(KillProgram)
|
||
programRunLayout.addWidget(killProgram)
|
||
killBottonProgram = QtWidgets.QPushButton(transla.transe("U", "终止指定容器的程序"))
|
||
killBottonProgram.clicked.connect(lambda: threading.Thread(target=os.system, args=[f"'{programPath}/kill.sh' '{os.path.basename(e1.currentText())}'"]).start())
|
||
programRunLayout.addWidget(killBottonProgram)
|
||
mainLayout.addWidget(programRun, 2, 1, 1, 1)
|
||
|
||
# 菜单栏
|
||
menu = window.menuBar()
|
||
programmenu = menu.addMenu(transla.transe("U", "程序(&P)"))
|
||
installMoreWine = QtWidgets.QAction(QtGui.QIcon(f"{programPath}/Icon/Function/more-wine.png"), transla.transe("U", "安装更多 Wine"))
|
||
downloadChrootBottle = QtWidgets.QAction(QtGui.QIcon(f"{programPath}/Icon/Function/CHROOT.png"), transla.transe("U", "下载 Chroot 容器"))
|
||
p2 = QtWidgets.QAction(transla.transe("U", "设置程序(&S)"))
|
||
enabledAll = QtWidgets.QAction(transla.transe("U", "强制启用所有被禁用的组件(不推荐)"))
|
||
p3 = QtWidgets.QAction(QtWidgets.QApplication.style().standardIcon(47), transla.transe("U", "清空软件历史记录(&C)"))
|
||
cleanCache = QtWidgets.QAction(QtWidgets.QApplication.style().standardIcon(47), transla.transe("U", "清空软件缓存"))
|
||
p4 = QtWidgets.QAction(transla.transe("U", "退出程序(&E)"))
|
||
programmenu.addAction(installMoreWine)
|
||
programmenu.addAction(downloadChrootBottle)
|
||
programmenu.addSeparator()
|
||
programmenu.addAction(p2)
|
||
programmenu.addAction(enabledAll)
|
||
programmenu.addSeparator()
|
||
programmenu.addAction(p3)
|
||
programmenu.addAction(cleanCache)
|
||
programmenu.addSeparator()
|
||
programmenu.addAction(p4)
|
||
installMoreWine.triggered.connect(lambda: threading.Thread(target=os.system, args=[f"'{programPath}/wine/installwine'"]).start())
|
||
downloadChrootBottle.triggered.connect(lambda: threading.Thread(target=os.system, args=[f"'{programPath}/QemuDownload.py'"]).start())
|
||
p2.triggered.connect(ProgramSetting.ShowWindow)
|
||
enabledAll.triggered.connect(lambda: DisableButton(False))
|
||
p3.triggered.connect(CleanProgramHistory)
|
||
cleanCache.triggered.connect(CleanProgramCache)
|
||
p4.triggered.connect(window.close)
|
||
|
||
wineOption = menu.addMenu(transla.transe("U", "Wine(&W)"))
|
||
w1 = QtWidgets.QAction(transla.transe("U", "打开 Wine 容器目录"))
|
||
updateGeek = QtWidgets.QAction(transla.transe("U", "从 Geek Uninstaller 官网升级程序"))
|
||
deletePartIcon = QtWidgets.QAction(transla.transe("U", "快捷方式管理工具"))
|
||
deleteDesktopIcon = QtWidgets.QAction(transla.transe("U", "删除所有 Wine 程序在启动器的快捷方式"))
|
||
wineOption.addAction(w1)
|
||
wineOption.addSeparator()
|
||
wineOption.addAction(deletePartIcon)
|
||
wineOption.addSeparator()
|
||
wineOption.addSeparator()
|
||
wineOption.addAction(updateGeek)
|
||
wineOption.addSeparator()
|
||
wm2 = wineOption.addMenu(transla.transe("U", "在指定 Wine、容器运行基础应用"))
|
||
wm2_1 = QtWidgets.QAction(QtGui.QIcon.fromTheme("control-center2"), transla.transe("U", "打开指定wine、指定容器的控制面板"))
|
||
wm2_2 = QtWidgets.QAction(QtGui.QIcon.fromTheme("web-browser"), transla.transe("U", "打开指定wine、指定容器的浏览器"))
|
||
wm2_3 = QtWidgets.QAction(QtGui.QIcon.fromTheme("regedit"), transla.transe("U", "打开指定wine、指定容器的注册表"))
|
||
wm2_4 = QtWidgets.QAction(transla.transe("U", "打开指定wine、指定容器的任务管理器"))
|
||
wm2_5 = QtWidgets.QAction(transla.transe("U", "打开指定wine、指定容器的资源管理器"))
|
||
wm2_6 = QtWidgets.QAction(transla.transe("U", "打开指定wine、指定容器的关于 wine"))
|
||
wm2.addAction(wm2_1)
|
||
wm2.addAction(wm2_2)
|
||
wm2.addAction(wm2_3)
|
||
wm2.addAction(wm2_4)
|
||
wm2.addAction(wm2_5)
|
||
wm2.addAction(wm2_6)
|
||
wineOption.addSeparator()
|
||
w1.triggered.connect(OpenWineBotton)
|
||
updateGeek.triggered.connect(lambda: os.system(f"'{programPath}/launch.sh' deepin-terminal -C '\"{programPath}/UpdateGeek.sh\"' --keep-open"))
|
||
wm2_1.triggered.connect(lambda: RunWineProgram("control"))
|
||
wm2_2.triggered.connect(lambda: RunWineProgram("iexplore' 'https://gfdgd-xi.github.io"))
|
||
wm2_3.triggered.connect(lambda: RunWineProgram("regedit"))
|
||
wm2_4.triggered.connect(lambda: RunWineProgram("taskmgr"))
|
||
wm2_5.triggered.connect(lambda: RunWineProgram("explorer"))
|
||
wm2_6.triggered.connect(lambda: RunWineProgram("winver"))
|
||
deletePartIcon.triggered.connect(lambda: threading.Thread(target=os.system, args=[f"python3 '{programPath}/BuildDesktop.py'"]).start())
|
||
|
||
help = menu.addMenu(transla.transe("U", "帮助(&H)"))
|
||
runStatusWebSize = QtWidgets.QAction(QtWidgets.QApplication.style().standardIcon(20), transla.transe("U", "查询程序在 Wine 的运行情况"))
|
||
h1 = help.addMenu(QtWidgets.QApplication.style().standardIcon(20), transla.transe("U", "程序官网"))
|
||
wineRunnerHelp = QtWidgets.QAction(QtWidgets.QApplication.style().standardIcon(20), transla.transe("U", "Wine运行器和Wine打包器傻瓜式使用教程(小白专用) By 鹤舞白沙"))
|
||
h4 = QtWidgets.QAction(transla.transe("U", "鸣谢名单"))
|
||
fenUpload = QtWidgets.QAction(transla.transe("U", "程序评分"))
|
||
h7 = QtWidgets.QAction(QtWidgets.QApplication.style().standardIcon(9), transla.transe("U", "关于这个程序"))
|
||
h8 = QtWidgets.QAction(QtWidgets.QApplication.style().standardIcon(9), transla.transe("U", "关于 Qt"))
|
||
gfdgdxiio = QtWidgets.QAction(QtWidgets.QApplication.style().standardIcon(20), transla.transe("U", "作者个人站"))
|
||
forumWebsize = QtWidgets.QAction(QtWidgets.QApplication.style().standardIcon(20), transla.transe("U", "程序论坛"))
|
||
gitee = QtWidgets.QAction(QtWidgets.QApplication.style().standardIcon(20), transla.transe("U", "Gitee"))
|
||
github = QtWidgets.QAction(QtWidgets.QApplication.style().standardIcon(20), transla.transe("U", "Github"))
|
||
gitlink = QtWidgets.QAction(QtWidgets.QApplication.style().standardIcon(20), transla.transe("U", "Gitlink"))
|
||
gitlab = QtWidgets.QAction(QtWidgets.QApplication.style().standardIcon(20), transla.transe("U", "Gitlab"))
|
||
jihu = QtWidgets.QAction(QtWidgets.QApplication.style().standardIcon(20), transla.transe("U", "极狐"))
|
||
h1.addAction(gfdgdxiio)
|
||
h1.addAction(gitee)
|
||
h1.addAction(github)
|
||
h1.addAction(gitlink)
|
||
h1.addAction(gitlab)
|
||
h1.addAction(jihu)
|
||
help.addSeparator()
|
||
help.addAction(forumWebsize)
|
||
help.addAction(wineRunnerHelp)
|
||
help.addAction(runStatusWebSize)
|
||
help.addSeparator()
|
||
help.addAction(h4)
|
||
help.addSeparator()
|
||
wikiHelp = QtWidgets.QAction(QtWidgets.QApplication.style().standardIcon(20), transla.transe("U", "程序 Wiki"))
|
||
help.addAction(wikiHelp)
|
||
videoHelp = help.addMenu(QtWidgets.QApplication.style().standardIcon(20), transla.transe("U", "视频教程"))
|
||
easyHelp = QtWidgets.QAction(QtWidgets.QApplication.style().standardIcon(20), transla.transe("U", "简易使用教程"))
|
||
buildHelp = QtWidgets.QAction(QtWidgets.QApplication.style().standardIcon(20), transla.transe("U", "打包教程"))
|
||
videoHelp.addAction(easyHelp)
|
||
videoHelp.addAction(buildHelp)
|
||
help.addSeparator()
|
||
help.addAction(fenUpload)
|
||
help.addAction(h7)
|
||
help.addAction(h8)
|
||
help.addSeparator()
|
||
hm1 = help.addMenu(transla.transe("U", "更多生态适配应用"))
|
||
hm1_1 = QtWidgets.QAction(transla.transe("U", "运行 Android 应用:UEngine 运行器"))
|
||
hm1.addAction(hm1_1)
|
||
gfdgdxiio.triggered.connect(lambda: webbrowser.open_new_tab("https://gfdgd-xi.github.io"))
|
||
gitee.triggered.connect(lambda: webbrowser.open_new_tab("https://gitee.com/gfdgd-xi/deep-wine-runner"))
|
||
github.triggered.connect(lambda: webbrowser.open_new_tab("https://github.com/gfdgd-xi/deep-wine-runner"))
|
||
gitlink.triggered.connect(lambda: webbrowser.open_new_tab("https://gitlink.org.cn/gfdgd_xi/deep-wine-runner"))
|
||
gitlab.triggered.connect(lambda: webbrowser.open_new_tab("https://gitlab.com/gfdgd-xi/deep-wine-runner"))
|
||
jihu.triggered.connect(lambda: webbrowser.open_new_tab("https://jihulab.com//gfdgd-xi/deep-wine-runner"))
|
||
runStatusWebSize.triggered.connect(lambda: webbrowser.open_new_tab("https://gfdgd-xi.github.io/wine-runner-info"))
|
||
forumWebsize.triggered.connect(lambda: webbrowser.open_new_tab("https://gfdgdxi.flarum.cloud/"))
|
||
wineRunnerHelp.triggered.connect(lambda: webbrowser.open_new_tab("https://bbs.deepin.org/post/246837"))
|
||
h4.triggered.connect(ThankWindow)
|
||
wikiHelp.triggered.connect(lambda: webbrowser.open_new_tab("https://gfdgd-xi.github.io/wine-runner-wiki"))
|
||
easyHelp.triggered.connect(lambda: webbrowser.open_new_tab("https://www.bilibili.com/video/BV1ma411972Y"))
|
||
buildHelp.triggered.connect(lambda: webbrowser.open_new_tab("https://www.bilibili.com/video/BV1EU4y1k7zr"))
|
||
fenUpload.triggered.connect(lambda: threading.Thread(target=os.system, args=[f"python3 '{programPath}/ProgramFen.py'"]).start())
|
||
h7.triggered.connect(about_this_program)
|
||
h8.triggered.connect(lambda: QtWidgets.QMessageBox.aboutQt(widget))
|
||
hm1_1.triggered.connect(lambda: webbrowser.open_new_tab("https://gitee.com/gfdgd-xi/uengine-runner"))
|
||
# 异同步获取信息
|
||
#threading.Thread(target=GetVersion).start()
|
||
GetVersion()
|
||
# 窗口设置
|
||
window.resize(widget.frameGeometry().width() * 2, widget.frameGeometry().height())
|
||
widget.setLayout(mainLayout)
|
||
window.setWindowIcon(QtGui.QIcon(f"{programPath}/deepin-wine-runner.svg"))
|
||
widget.show()
|
||
window.show()
|
||
|
||
# 控件设置
|
||
app.setStyle(QtWidgets.QStyleFactory.create(setting["Theme"]))
|
||
e1.addItems(findExeHistory)
|
||
e2.addItems(wineBottonHistory)
|
||
combobox1.addItems(shellHistory)
|
||
if setting["AutoWine"]:
|
||
o1.addItems(canUseWine)
|
||
else:
|
||
o1.addItems(wine.keys())
|
||
# 有些功能是非 X86 不适用的,需要屏蔽
|
||
if subprocess.getoutput("arch").lower() != "x86_64":
|
||
installMoreWine.setEnabled(True)
|
||
virtualMachine.setDisabled(True)
|
||
v1.setDisabled(True)
|
||
pass
|
||
o1.setCurrentText(setting["DefultWine"])
|
||
e1.setEditText(setting["DefultBotton"])
|
||
e2.setEditText("")
|
||
combobox1.setEditText("")
|
||
if len(sys.argv) > 1 and sys.argv[1]:
|
||
e2.setEditText(sys.argv[1])
|
||
if o1.currentText() == "":
|
||
# 一个 Wine 都没有却用 Wine 的功能
|
||
# 还是要处理的,至少不会闪退
|
||
wine["没有识别到任何Wine,请在菜单栏“程序”安装Wine或安装任意Wine应用"] = "没有识别到任何Wine,请在菜单栏“程序”安装Wine或安装任意Wine应用"
|
||
canUseWine.append("没有识别到任何Wine,请在菜单栏“程序”安装Wine或安装任意Wine应用")
|
||
o1.addItem("没有识别到任何Wine,请在菜单栏“程序”安装Wine或安装任意Wine应用")
|
||
|
||
|
||
sys.exit(app.exec_())
|