mirror of
https://github.com/ankitects/anki.git
synced 2025-09-25 17:26:36 -04:00
support specifying gfx driver in profile folder
We need to set the OpenGL mode prior to Qt initialisation, but want to fetch the current driver from the profile manager - and the profile manager required Qt to already be set up. Work around this by moving away from QStandardPaths in favour of a pure Python module. The profile manager now does early setup using winpaths, and we defer most of the setup until Qt has been initialised. Also we install a message handler to catch OpenGL initialisation errors, and automatically switch to the next driver so users don't need to manually change the driver. The --hwaccel option has been removed, as it is no longer necessary.
This commit is contained in:
parent
91983ce21f
commit
f2b5c8a862
2 changed files with 87 additions and 36 deletions
|
@ -224,10 +224,38 @@ def parseArgs(argv):
|
||||||
parser.add_option("-b", "--base", help="path to base folder")
|
parser.add_option("-b", "--base", help="path to base folder")
|
||||||
parser.add_option("-p", "--profile", help="profile name to load")
|
parser.add_option("-p", "--profile", help="profile name to load")
|
||||||
parser.add_option("-l", "--lang", help="interface language (en, de, etc)")
|
parser.add_option("-l", "--lang", help="interface language (en, de, etc)")
|
||||||
if not isMac:
|
|
||||||
parser.add_option("--hwaccel", action="store_true", help="enable hardware acceleration")
|
|
||||||
return parser.parse_args(argv[1:])
|
return parser.parse_args(argv[1:])
|
||||||
|
|
||||||
|
def setupGL(pm):
|
||||||
|
if isMac:
|
||||||
|
return
|
||||||
|
|
||||||
|
mode = pm.glMode()
|
||||||
|
|
||||||
|
# work around pyqt loading wrong GL library
|
||||||
|
if isLin:
|
||||||
|
import ctypes
|
||||||
|
ctypes.CDLL('libGL.so.1', ctypes.RTLD_GLOBAL)
|
||||||
|
|
||||||
|
# catch opengl errors
|
||||||
|
def msgHandler(type, ctx, msg):
|
||||||
|
if "Failed to create OpenGL context" in msg:
|
||||||
|
QMessageBox.critical(None, "Error", "Error loading '%s' graphics driver. Please start Anki again to try next driver." % mode)
|
||||||
|
pm.nextGlMode()
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
print("qt:", msg)
|
||||||
|
qInstallMessageHandler(msgHandler)
|
||||||
|
|
||||||
|
print("Hardware acceleration set to", mode)
|
||||||
|
|
||||||
|
if mode == "auto":
|
||||||
|
return
|
||||||
|
elif isLin:
|
||||||
|
os.environ["QT_XCB_FORCE_SOFTWARE_OPENGL"] = "1"
|
||||||
|
else:
|
||||||
|
os.environ["QT_OPENGL"] = mode
|
||||||
|
|
||||||
def run():
|
def run():
|
||||||
try:
|
try:
|
||||||
_run()
|
_run()
|
||||||
|
@ -256,17 +284,12 @@ def _run(argv=None, exec=True):
|
||||||
opts.base = opts.base or ""
|
opts.base = opts.base or ""
|
||||||
opts.profile = opts.profile or ""
|
opts.profile = opts.profile or ""
|
||||||
|
|
||||||
if not isMac and not opts.hwaccel:
|
# profile manager
|
||||||
print("Hardware acceleration disabled.")
|
from aqt.profiles import ProfileManager
|
||||||
if isWin:
|
pm = ProfileManager(opts.base)
|
||||||
os.environ["QT_OPENGL"] = "software"
|
|
||||||
else:
|
|
||||||
os.environ["QT_XCB_FORCE_SOFTWARE_OPENGL"] = "1"
|
|
||||||
|
|
||||||
# work around pyqt loading wrong GL library
|
# gl workarounds
|
||||||
if isLin:
|
setupGL(pm)
|
||||||
import ctypes
|
|
||||||
ctypes.CDLL('libGL.so.1', ctypes.RTLD_GLOBAL)
|
|
||||||
|
|
||||||
# opt in to full hidpi support?
|
# opt in to full hidpi support?
|
||||||
if not os.environ.get("ANKI_NOHIGHDPI"):
|
if not os.environ.get("ANKI_NOHIGHDPI"):
|
||||||
|
@ -293,9 +316,10 @@ No usable temporary folder found. Make sure C:\\temp exists or TEMP in your \
|
||||||
environment points to a valid, writable folder.""")
|
environment points to a valid, writable folder.""")
|
||||||
return
|
return
|
||||||
|
|
||||||
# profile manager
|
pm.setupMeta()
|
||||||
from aqt.profiles import ProfileManager
|
|
||||||
pm = ProfileManager(opts.base, opts.profile)
|
if opts.profile:
|
||||||
|
pm.openProfile(opts.profile)
|
||||||
|
|
||||||
# i18n
|
# i18n
|
||||||
setupLang(pm, app, opts.lang)
|
setupLang(pm, app, opts.lang)
|
||||||
|
|
|
@ -61,14 +61,18 @@ profileConf = dict(
|
||||||
|
|
||||||
class ProfileManager:
|
class ProfileManager:
|
||||||
|
|
||||||
def __init__(self, base=None, profile=None):
|
def __init__(self, base=None):
|
||||||
self.name = None
|
self.name = None
|
||||||
self.db = None
|
self.db = None
|
||||||
# instantiate base folder
|
# instantiate base folder
|
||||||
self._setBaseFolder(base)
|
self._setBaseFolder(base)
|
||||||
|
|
||||||
|
def setupMeta(self):
|
||||||
# load metadata
|
# load metadata
|
||||||
self.firstRun = self._loadMeta()
|
self.firstRun = self._loadMeta()
|
||||||
# did the user request a profile to start up with?
|
|
||||||
|
# profile load on startup
|
||||||
|
def openProfile(self, profile):
|
||||||
if profile:
|
if profile:
|
||||||
if profile not in self.profiles():
|
if profile not in self.profiles():
|
||||||
QMessageBox.critical(None, "Error", "Requested profile does not exist.")
|
QMessageBox.critical(None, "Error", "Requested profile does not exist.")
|
||||||
|
@ -101,27 +105,18 @@ a flash drive.""" % self.base)
|
||||||
if isMac:
|
if isMac:
|
||||||
return os.path.expanduser("~/Documents/Anki")
|
return os.path.expanduser("~/Documents/Anki")
|
||||||
elif isWin:
|
elif isWin:
|
||||||
loc = QStandardPaths.writableLocation(QStandardPaths.DocumentsLocation)
|
from aqt.winpaths import get_personal
|
||||||
return os.path.join(loc, "Anki")
|
return os.path.join(get_personal(), "Anki")
|
||||||
else:
|
else:
|
||||||
p = os.path.expanduser("~/Anki")
|
p = os.path.expanduser("~/Anki")
|
||||||
if os.path.isdir(p):
|
if os.path.isdir(p):
|
||||||
return p
|
return p
|
||||||
else:
|
|
||||||
loc = QStandardPaths.writableLocation(QStandardPaths.DocumentsLocation)
|
|
||||||
if loc[:-1] == QStandardPaths.writableLocation(
|
|
||||||
QStandardPaths.HomeLocation):
|
|
||||||
# occasionally "documentsLocation" will return the home
|
|
||||||
# folder because the Documents folder isn't configured
|
|
||||||
# properly; fall back to an English path
|
|
||||||
return os.path.expanduser("~/Documents/Anki")
|
return os.path.expanduser("~/Documents/Anki")
|
||||||
else:
|
|
||||||
return os.path.join(loc, "Anki")
|
|
||||||
|
|
||||||
def maybeMigrateFolder(self):
|
def maybeMigrateFolder(self):
|
||||||
oldBase = self._oldFolderLocation()
|
oldBase = self._oldFolderLocation()
|
||||||
|
|
||||||
if not os.path.exists(self.base) and os.path.isdir(oldBase):
|
if oldBase and not os.path.exists(self.base) and os.path.isdir(oldBase):
|
||||||
shutil.move(oldBase, self.base)
|
shutil.move(oldBase, self.base)
|
||||||
|
|
||||||
# Profile load/save
|
# Profile load/save
|
||||||
|
@ -271,12 +266,8 @@ and no other programs are accessing your profile folders, then try again."""))
|
||||||
|
|
||||||
def _defaultBase(self):
|
def _defaultBase(self):
|
||||||
if isWin:
|
if isWin:
|
||||||
loc = QStandardPaths.writableLocation(QStandardPaths.AppDataLocation)
|
from aqt.winpaths import get_appdata
|
||||||
# the returned value seem to automatically include the app name, but we use Anki2 rather
|
return os.path.join(get_appdata(), "Anki2")
|
||||||
# than Anki
|
|
||||||
assert loc.endswith("/Anki")
|
|
||||||
loc += "2"
|
|
||||||
return loc
|
|
||||||
elif isMac:
|
elif isMac:
|
||||||
return os.path.expanduser("~/Library/Application Support/Anki2")
|
return os.path.expanduser("~/Library/Application Support/Anki2")
|
||||||
else:
|
else:
|
||||||
|
@ -407,3 +398,39 @@ please see:
|
||||||
self.db.execute(sql, self._pickle(self.meta), "_global")
|
self.db.execute(sql, self._pickle(self.meta), "_global")
|
||||||
self.db.commit()
|
self.db.commit()
|
||||||
anki.lang.setLang(code, local=False)
|
anki.lang.setLang(code, local=False)
|
||||||
|
|
||||||
|
# OpenGL
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
def _glPath(self):
|
||||||
|
return os.path.join(self.base, "gldriver")
|
||||||
|
|
||||||
|
def glMode(self):
|
||||||
|
assert not isMac
|
||||||
|
|
||||||
|
path = self._glPath()
|
||||||
|
if not os.path.exists(path):
|
||||||
|
return "software"
|
||||||
|
|
||||||
|
mode = open(path, "r").read().strip()
|
||||||
|
|
||||||
|
if mode == "angle" and isWin:
|
||||||
|
return mode
|
||||||
|
elif mode == "software":
|
||||||
|
return mode
|
||||||
|
return "auto"
|
||||||
|
|
||||||
|
def setGlMode(self, mode):
|
||||||
|
open(self._glPath(), "w").write(mode)
|
||||||
|
|
||||||
|
def nextGlMode(self):
|
||||||
|
mode = self.glMode()
|
||||||
|
if mode == "software":
|
||||||
|
self.setGlMode("auto")
|
||||||
|
elif mode == "auto":
|
||||||
|
if isWin:
|
||||||
|
self.setGlMode("angle")
|
||||||
|
else:
|
||||||
|
self.setGlMode("software")
|
||||||
|
elif mode == "angle":
|
||||||
|
self.setGlMode("software")
|
||||||
|
|
Loading…
Reference in a new issue