Commit 0a2b2fad authored by sumpfralle's avatar sumpfralle

handle gtk import in pyinstaller binary properly

git-svn-id: https://pycam.svn.sourceforge.net/svnroot/pycam/trunk@628 bbaffbd6-741e-11dd-a85d-61de82d9cad9
parent 6caf64e4
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" """
$Id$ $Id$
Copyright 2010 Lars Kruse <devel@sumpfralle.de> Copyright 2010 Lars Kruse <devel@sumpfralle.de>
This file is part of PyCAM. This file is part of PyCAM.
PyCAM is free software: you can redistribute it and/or modify PyCAM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
PyCAM is distributed in the hope that it will be useful, PyCAM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with PyCAM. If not, see <http://www.gnu.org/licenses/>. along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
""" """
import pycam.Utils.log import pycam.Utils.log
# Tkinter is used for "EmergencyDialog" below - but we will try to import it # Tkinter is used for "EmergencyDialog" below - but we will try to import it
# carefully. # carefully.
#import Tkinter #import Tkinter
import sys import sys
import os import os
log = pycam.Utils.log.get_logger() log = pycam.Utils.log.get_logger()
DEPENDENCY_DESCRIPTION = { DEPENDENCY_DESCRIPTION = {
"gtk": ("Python bindings for GTK+", "gtk": ("Python bindings for GTK+",
"Install the package 'python-gtk2'", "Install the package 'python-gtk2'",
"see http://www.bonifazi.eu/appunti/pygtk_windows_installer.exe"), "see http://www.bonifazi.eu/appunti/pygtk_windows_installer.exe"),
"opengl": ("Python bindings for OpenGL", "opengl": ("Python bindings for OpenGL",
"Install the package 'python-opengl'", "Install the package 'python-opengl'",
"see http://www.bonifazi.eu/appunti/pygtk_windows_installer.exe"), "see http://www.bonifazi.eu/appunti/pygtk_windows_installer.exe"),
"gtkgl": ("GTK extension for OpenGL", "gtkgl": ("GTK extension for OpenGL",
"Install the package 'python-gtkglext1'", "Install the package 'python-gtkglext1'",
"see http://www.bonifazi.eu/appunti/pygtk_windows_installer.exe"), "see http://www.bonifazi.eu/appunti/pygtk_windows_installer.exe"),
"gl": ("OpenGL support of graphic driver", "gl": ("OpenGL support of graphic driver",
"Your current graphic driver does not support OpenGL. Please consult " \ "Your current graphic driver does not support OpenGL. Please consult " \
+ "'glxgears' to locate this problem."), + "'glxgears' to locate this problem."),
} }
REQUIREMENTS_LINK = "http://sourceforge.net/apps/mediawiki/pycam/index.php?title=Requirements" REQUIREMENTS_LINK = "http://sourceforge.net/apps/mediawiki/pycam/index.php?title=Requirements"
# Usually the windows registry "HKEY_LOCAL_MACHINE/SOFTWARE/Gtk+/Path" contains # Usually the windows registry "HKEY_LOCAL_MACHINE/SOFTWARE/Gtk+/Path" contains
# something like: C:\Programs\Common files\GTK # something like: C:\Programs\Common files\GTK
# Afterwards we need to append "\bin" to get the library subdirectory. # Afterwards we need to append "\bin" to get the library subdirectory.
WINDOWS_GTK_REGISTRY_PATH = r"SOFTWARE\Gtk+" WINDOWS_GTK_REGISTRY_PATH = r"SOFTWARE\Gtk+"
WINDOWS_GTK_REGISTRY_KEY = "Path" WINDOWS_GTK_REGISTRY_KEY = "Path"
WINDOWS_GTK_LIB_SUBDIR = "bin" WINDOWS_GTK_LIB_SUBDIR = "bin"
def import_gtk_carefully(): def import_gtk_carefully():
""" especially for windows: try to locate required libraries manually, if """ especially for windows: try to locate required libraries manually, if
the import of GTK fails the import of GTK fails
""" """
try: try:
import _winreg import _winreg
in_windows = True in_windows = True
except ImportError: except ImportError:
in_windows = False in_windows = False
if not in_windows: if not in_windows:
# We are not in windows - thus we just try to import gtk without # We are not in windows - thus we just try to import gtk without
# the need for any more manual preparations. # the need for any more manual preparations.
import gtk import gtk
else: else:
# We try to retrive the GTK library directory from the registry before # We try to retrive the GTK library directory from the registry before
# trying any import. Otherwise the user will always see a warning # trying any import. Otherwise the user will always see a warning
# dialog regarding the missing libglib-2.0-0.dll file. This Windows # dialog regarding the missing libglib-2.0-0.dll file. This Windows
# warning dialog can't be suppressed - thus we should try to avoid it. # warning dialog can't be suppressed - thus we should try to avoid it.
try: try:
reg_path = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, reg_path = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,
WINDOWS_GTK_REGISTRY_PATH) WINDOWS_GTK_REGISTRY_PATH)
gtk_dll_path = os.path.join(_winreg.QueryValueEx(reg_path, gtk_dll_path = os.path.join(_winreg.QueryValueEx(reg_path,
WINDOWS_GTK_REGISTRY_KEY)[0], WINDOWS_GTK_LIB_SUBDIR) WINDOWS_GTK_REGISTRY_KEY)[0], WINDOWS_GTK_LIB_SUBDIR)
_winreg.CloseKey(reg_path) _winreg.CloseKey(reg_path)
except NameError: except NameError:
# GTK is probably not installed - the next import will fail # GTK is probably not installed - the next import will fail
pass pass
else: except WindowsError:
# add the new path to the PATH environment variable # this happens with pyinstaller binaries - just ignore it
if "PATH" in os.environ: pass
if not gtk_dll_path in os.environ["PATH"].split(os.pathsep): else:
# append the guessed path to the library search path # add the new path to the PATH environment variable
os.environ["PATH"] += "%s%s" % (os.pathsep, gtk_dll_path) if "PATH" in os.environ:
# everything should be prepared - now we try to import it again if not gtk_dll_path in os.environ["PATH"].split(os.pathsep):
import gtk # append the guessed path to the library search path
os.environ["PATH"] += "%s%s" % (os.pathsep, gtk_dll_path)
def requirements_details_gtk(): # everything should be prepared - now we try to import it again
result = {} import gtk
try:
import_gtk_carefully() def requirements_details_gtk():
result["gtk"] = True result = {}
except ImportError: try:
result["gtk"] = False import_gtk_carefully()
return result result["gtk"] = True
except ImportError:
def recommends_details_gtk(): result["gtk"] = False
result = {} return result
try:
import gtk.gtkgl def recommends_details_gtk():
result["gtkgl"] = True result = {}
result["gl"] = True try:
except ImportError: import gtk.gtkgl
result["gtkgl"] = False result["gtkgl"] = True
except RuntimeError: result["gl"] = True
result["gl"] = False except ImportError:
try: result["gtkgl"] = False
import OpenGL except RuntimeError:
result["opengl"] = True result["gl"] = False
except ImportError: try:
result["opengl"] = False import OpenGL
result["opengl"] = True
def check_dependencies(details): except ImportError:
"""you can feed this function with the output of result["opengl"] = False
'(requirements|recommends)_details_*'.
The result is True if all dependencies are met. def check_dependencies(details):
""" """you can feed this function with the output of
failed = [key for (key, state) in details.items() if not state] '(requirements|recommends)_details_*'.
return len(failed) == 0 The result is True if all dependencies are met.
"""
def get_dependency_report(details, prefix=""): failed = [key for (key, state) in details.items() if not state]
result = [] return len(failed) == 0
DESC_COL = 0
if sys.platform.startswith("win"): def get_dependency_report(details, prefix=""):
ADVICE_COL = 2 result = []
else: DESC_COL = 0
ADVICE_COL = 1 if sys.platform.startswith("win"):
for key, state in details.items(): ADVICE_COL = 2
text = "%s%s: " % (prefix, DEPENDENCY_DESCRIPTION[key][DESC_COL]) else:
if state: ADVICE_COL = 1
text += "OK" for key, state in details.items():
else: text = "%s%s: " % (prefix, DEPENDENCY_DESCRIPTION[key][DESC_COL])
text += "MISSING (%s)" % DEPENDENCY_DESCRIPTION[key][ADVICE_COL] if state:
result.append(text) text += "OK"
return os.linesep.join(result) else:
text += "MISSING (%s)" % DEPENDENCY_DESCRIPTION[key][ADVICE_COL]
result.append(text)
class EmergencyDialog: return os.linesep.join(result)
""" This graphical message window requires no external dependencies.
The Tk interface package is part of the main python distribution.
Use this class for displaying dependency errors (especially on Windows). class EmergencyDialog:
""" """ This graphical message window requires no external dependencies.
The Tk interface package is part of the main python distribution.
def __init__(self, title, message): Use this class for displaying dependency errors (especially on Windows).
try: """
import Tkinter
except ImportError: def __init__(self, title, message):
# tk is not installed try:
log.warn("Failed to show error dialog due to a missing Tkinter " \ import Tkinter
+ "Python package.") except ImportError:
return # tk is not installed
try: log.warn("Failed to show error dialog due to a missing Tkinter " \
root = Tkinter.Tk() + "Python package.")
except Tkinter.TclError, err_msg: return
log.info(("Failed to create error dialog window (%s). Probably " \ try:
+ "you are running PyCAM from a terminal.") % err_msg) root = Tkinter.Tk()
return except Tkinter.TclError, err_msg:
root.title(title) log.info(("Failed to create error dialog window (%s). Probably " \
root.bind("<Return>", self.finish) + "you are running PyCAM from a terminal.") % err_msg)
root.bind("<Escape>", self.finish) return
root.minsize(300, 100) root.title(title)
self.root = root root.bind("<Return>", self.finish)
frame = Tkinter.Frame(root) root.bind("<Escape>", self.finish)
frame.pack() root.minsize(300, 100)
# add text output as label self.root = root
message = Tkinter.Message(root, text=message) frame = Tkinter.Frame(root)
# we need some space for the dependency report frame.pack()
message["width"] = 800 # add text output as label
message.pack() message = Tkinter.Message(root, text=message)
# add the "close" button # we need some space for the dependency report
close = Tkinter.Button(root, text="Close") message["width"] = 800
close["command"] = self.finish message.pack()
close.pack(side=Tkinter.BOTTOM) # add the "close" button
root.mainloop() close = Tkinter.Button(root, text="Close")
close["command"] = self.finish
def finish(self, *args): close.pack(side=Tkinter.BOTTOM)
self.root.quit() root.mainloop()
def finish(self, *args):
self.root.quit()
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment