mirror of
https://github.com/ankitects/anki.git
synced 2025-09-24 08:46:37 -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("-p", "--profile", help="profile name to load")
|
||||
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:])
|
||||
|
||||
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():
|
||||
try:
|
||||
_run()
|
||||
|
@ -256,17 +284,12 @@ def _run(argv=None, exec=True):
|
|||
opts.base = opts.base or ""
|
||||
opts.profile = opts.profile or ""
|
||||
|
||||
if not isMac and not opts.hwaccel:
|
||||
print("Hardware acceleration disabled.")
|
||||
if isWin:
|
||||
os.environ["QT_OPENGL"] = "software"
|
||||
else:
|
||||
os.environ["QT_XCB_FORCE_SOFTWARE_OPENGL"] = "1"
|
||||
# profile manager
|
||||
from aqt.profiles import ProfileManager
|
||||
pm = ProfileManager(opts.base)
|
||||
|
||||
# work around pyqt loading wrong GL library
|
||||
if isLin:
|
||||
import ctypes
|
||||
ctypes.CDLL('libGL.so.1', ctypes.RTLD_GLOBAL)
|
||||
# gl workarounds
|
||||
setupGL(pm)
|
||||
|
||||
# opt in to full hidpi support?
|
||||
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.""")
|
||||
return
|
||||
|
||||
# profile manager
|
||||
from aqt.profiles import ProfileManager
|
||||
pm = ProfileManager(opts.base, opts.profile)
|
||||
pm.setupMeta()
|
||||
|
||||
if opts.profile:
|
||||
pm.openProfile(opts.profile)
|
||||
|
||||
# i18n
|
||||
setupLang(pm, app, opts.lang)
|
||||
|
|
|
@ -61,14 +61,18 @@ profileConf = dict(
|
|||
|
||||
class ProfileManager:
|
||||
|
||||
def __init__(self, base=None, profile=None):
|
||||
def __init__(self, base=None):
|
||||
self.name = None
|
||||
self.db = None
|
||||
# instantiate base folder
|
||||
self._setBaseFolder(base)
|
||||
|
||||
def setupMeta(self):
|
||||
# load metadata
|
||||
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 not in self.profiles():
|
||||
QMessageBox.critical(None, "Error", "Requested profile does not exist.")
|
||||
|
@ -101,27 +105,18 @@ a flash drive.""" % self.base)
|
|||
if isMac:
|
||||
return os.path.expanduser("~/Documents/Anki")
|
||||
elif isWin:
|
||||
loc = QStandardPaths.writableLocation(QStandardPaths.DocumentsLocation)
|
||||
return os.path.join(loc, "Anki")
|
||||
from aqt.winpaths import get_personal
|
||||
return os.path.join(get_personal(), "Anki")
|
||||
else:
|
||||
p = os.path.expanduser("~/Anki")
|
||||
if os.path.isdir(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")
|
||||
else:
|
||||
return os.path.join(loc, "Anki")
|
||||
return os.path.expanduser("~/Documents/Anki")
|
||||
|
||||
def maybeMigrateFolder(self):
|
||||
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)
|
||||
|
||||
# Profile load/save
|
||||
|
@ -271,12 +266,8 @@ and no other programs are accessing your profile folders, then try again."""))
|
|||
|
||||
def _defaultBase(self):
|
||||
if isWin:
|
||||
loc = QStandardPaths.writableLocation(QStandardPaths.AppDataLocation)
|
||||
# the returned value seem to automatically include the app name, but we use Anki2 rather
|
||||
# than Anki
|
||||
assert loc.endswith("/Anki")
|
||||
loc += "2"
|
||||
return loc
|
||||
from aqt.winpaths import get_appdata
|
||||
return os.path.join(get_appdata(), "Anki2")
|
||||
elif isMac:
|
||||
return os.path.expanduser("~/Library/Application Support/Anki2")
|
||||
else:
|
||||
|
@ -407,3 +398,39 @@ please see:
|
|||
self.db.execute(sql, self._pickle(self.meta), "_global")
|
||||
self.db.commit()
|
||||
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