def writecfg(which="user", worker=None): """ Write configuration file. which: 'user' or 'system' worker: worker instance if which == 'system' """ if which == "user": # user config - stores everything and overrides system-wide config cfgfilename = os.path.join(confighome, appname + ".ini") try: io = StringIO() cfg.write(io) io.seek(0) lines = io.read().strip("\n").split("\n") # Sorting works as long as config has only one section lines = [lines[0]] + sorted(lines[1:]) cfgfile = open(cfgfilename, "wb") cfgfile.write("\n".join(lines)) cfgfile.close() except Exception, exception: from debughelpers import handle_error handle_error(u"Warning - could not write user configuration file " "'%s': %s" % (cfgfilename, safe_unicode(exception))) return False
def init(set_wx_locale=False): """ Populate translation dict with found language strings and set locale. If set_wx_locale is True, set locale also for wxPython. """ langdirs = [] for dir_ in data_dirs: langdirs.append(os.path.join(dir_, "lang")) for langdir in langdirs: if os.path.exists(langdir) and os.path.isdir(langdir): try: langfiles = os.listdir(langdir) except Exception as exception: safe_print("Warning - directory '%s' listing failed: %s" % tuple(safe_unicode(s) for s in (langdir, exception))) else: for filename in langfiles: name, ext = os.path.splitext(filename) if ext.lower() == ".yaml" and name.lower() not in ldict: path = os.path.join(langdir, filename) ldict[name.lower()] = LazyDict_YAML_UltraLite(path) if len(ldict) == 0: handle_error(UserWarning("Warning: No language files found. The " "following places have been searched:\n%s" % "\n".join(langdirs)))
def makecfgdir(which="user", worker=None): if which == "user": if not os.path.exists(confighome): try: os.makedirs(confighome) except Exception, exception: from debughelpers import handle_error handle_error(u"Warning - could not create configuration directory " "'%s': %s" % (confighome, safe_unicode(exception))) return False
def main(module=None): mp.freeze_support() if mp.current_process().name != "MainProcess": return if module: name = "%s-%s" % (appbasename, module) else: name = appbasename applockfilename = os.path.join(confighome, "%s.lock" % name) try: _main(module, name, applockfilename) except Exception as exception: if isinstance(exception, ResourceError): error = exception else: error = Error("Fatal error: " + safe_unicode(exception)) handle_error(error) _exit(applockfilename, getattr(sys, "_appsocket_port", ""))
def load(self, path=None, encoding=None, errors=None, raise_exceptions=False): if not self._isloaded and (path or self.path): self._isloaded = True if not path: path = self.path if path and not os.path.isabs(path): path = get_data_path(path) if path and os.path.isfile(path): self.path = path if encoding: self.encoding = encoding if errors: self.errors = errors else: handle_error(UserWarning("Warning - file not found:\n\n%s" % safe_unicode(path)), tb=False) return try: with codecs.open(path, "rU", self.encoding, self.errors) as f: self.parse(f) except EnvironmentError as exception: if raise_exceptions: raise handle_error(exception) except Exception as exception: if raise_exceptions: raise handle_error(UserWarning("Error parsing file:\n\n%s\n\n%s" % tuple(safe_unicode(s) for s in (path, exception))), tb=False)
try: if sys.platform == "win32": os.makedirs(config_sys) else: result = worker.exec_cmd("mkdir", ["-p", config_sys], capture_output=True, low_contrast=False, skip_scripts=True, silent=True, asroot=True) if isinstance(result, Exception): raise result except Exception, exception: from debughelpers import handle_error handle_error(u"Warning - could not create configuration directory " "'%s': %s" % (config_sys, safe_unicode(exception))) return False return True def initcfg(): """ Initialize the configuration. Read in settings if the configuration file exists, else create the settings directory if nonexistent. """ # read pre-v0.2.2b configuration if present if sys.platform == "darwin": oldcfg = os.path.join(expanduseru("~"), "Library", "Preferences",
def get_default_size(): """ Get and return the default size for the window in pixels. The default size is always equivalent to 100 x 100 mm according to the display's size as returned by the RealDisplaySizeMM function, which uses the same code as Argyll to determine that size. This function is used internally. """ display_sizes = [] display_sizes_mm = [] for display_no in range(len(getcfg("displays"))): display_no = get_display_number(display_no) display_size = wx.Display(display_no).Geometry[2:] display_size_mm = [] if RDSMM: try: display_size_mm = RDSMM.RealDisplaySizeMM(display_no) except Exception as exception: handle_error("Error - RealDisplaySizeMM() failed: " + safe_unicode(exception), silent=True) else: display_size_mm = floatlist(display_size_mm) if debug: safe_print("[D] display_size_mm:", display_size_mm) if not len(display_size_mm) or 0 in display_size_mm: ppi_def = get_default_dpi() method = 1 if method == 0: # use configurable screen diagonal inch = 20.0 mm = inch * 25.4 f = mm / math.sqrt(math.pow(display_size[0], 2) + \ math.pow(display_size[1], 2)) w_mm = math.sqrt(math.pow(mm, 2) - \ math.pow(display_size[1] * f, 2)) h_mm = math.sqrt(math.pow(mm, 2) - \ math.pow(display_size[0] * f, 2)) display_size_mm = w_mm, h_mm elif method == 1: # use the first display display_size_1st = wx.DisplaySize() display_size_mm = floatlist(wx.DisplaySizeMM()) if 0 in display_size_mm: # bogus display_size_mm = [ display_size_1st[0] / ppi_def * 25.4, display_size_1st[1] / ppi_def * 25.4 ] if display_no > 0: display_size_mm[0] = display_size[0] / ( display_size_1st[0] / display_size_mm[0]) display_size_mm[1] = display_size[1] / ( display_size_1st[1] / display_size_mm[1]) else: # use assumed ppi display_size_mm = (display_size[0] / ppi_def * 25.4, display_size[1] / ppi_def * 25.4) display_sizes.append(display_size) display_sizes_mm.append(display_size_mm) if sum(mm[0] for mm in display_sizes_mm) / \ len(display_sizes_mm) == display_sizes_mm[0][0] and \ sum(mm[1] for mm in display_sizes_mm) / \ len(display_sizes_mm) == display_sizes_mm[0][1]: # display_size_mm is the same for all screens, use the 1st one display_size = display_sizes[0] display_size_mm = display_sizes_mm[0] else: if getcfg("display_lut.link"): display_no = getcfg("display.number") - 1 else: display_no = getcfg("display_lut.number") - 1 display_size = display_sizes[display_no] display_size_mm = display_sizes_mm[display_no] px_per_mm = (display_size[0] / display_size_mm[0], display_size[1] / display_size_mm[1]) if debug: safe_print("[D] H px_per_mm:", px_per_mm[0]) safe_print("[D] V px_per_mm:", px_per_mm[1]) return round(100.0 * max(px_per_mm))
def _main(module, name, applockfilename, probe_ports=True): # Allow multiple instances only for curve viewer, profile info, # scripting client, synthetic profile creator and testchart editor multi_instance = ("curve-viewer", "profile-info", "scripting-client", "synthprofile", "testchart-editor") lock = AppLock(applockfilename, "a+", True, module in multi_instance) if not lock: # If a race condition occurs, do not start another instance safe_print("Not starting another instance.") return log("=" * 80) if verbose >= 1: version = VERSION_STRING if VERSION > VERSION_BASE: version += " Beta" safe_print(pyname + runtype, version, build) if sys.platform == "darwin": # Python's platform.platform output is useless under Mac OS X # (e.g. 'Darwin-15.0.0-x86_64-i386-64bit' for Mac OS X 10.11 El Capitan) safe_print("Mac OS X %s %s" % (mac_ver()[0], mac_ver()[-1])) elif sys.platform == "win32": machine = platform.machine() safe_print(*[v for v in win_ver() if v] + ({ "AMD64": "x86_64" }.get(machine, machine), )) else: # Linux safe_print(' '.join(platform.dist()), platform.machine()) safe_print("Python " + sys.version) cafile = os.getenv("SSL_CERT_FILE") if cafile: safe_print("CA file", cafile) # Enable faulthandler try: import faulthandler except Exception as exception: safe_print(exception) else: try: faulthandler.enable( open(os.path.join(logdir, pyname + "-fault.log"), "w")) except Exception as exception: safe_print(exception) else: safe_print("Faulthandler", getattr(faulthandler, "__version__", "")) from wxaddons import wx if "phoenix" in wx.PlatformInfo: # py2exe helper so wx.xml gets picked up from wx import xml safe_print("wxPython " + wx.version()) safe_print("Encoding: " + enc) safe_print("File system encoding: " + fs_enc) if sys.platform == "win32" and sys.getwindowsversion() >= (6, 2): # HighDPI support try: shcore = ctypes.windll.shcore except Exception as exception: safe_print("Warning - could not load shcore:", exception) else: if hasattr(shcore, "SetProcessDpiAwareness"): try: # 1 = System DPI aware (wxWpython currently does not # support per-monitor DPI) shcore.SetProcessDpiAwareness(1) except Exception as exception: safe_print("Warning - SetProcessDpiAwareness() failed:", exception) else: safe_print( "Warning - SetProcessDpiAwareness not found in shcore") initcfg(module) host = "127.0.0.1" defaultport = getcfg("app.port") lock2pids_ports = {} opid = os.getpid() if probe_ports: # Check for currently used ports lockfilenames = glob.glob(os.path.join(confighome, "*.lock")) for lockfilename in lockfilenames: safe_print("Lockfile", lockfilename) try: if lock and lockfilename == applockfilename: lockfile = lock lock.seek(0) else: lockfile = AppLock(lockfilename, "r", True, True) if lockfile: if not lockfilename in lock2pids_ports: lock2pids_ports[lockfilename] = [] for ln, line in enumerate(lockfile.read().splitlines(), 1): if ":" in line: # DisplayCAL >= 3.8.8.2 with localhost blocked pid, port = line.split(":", 1) if pid: try: pid = int(pid) except ValueError as exception: # This shouldn't happen safe_print("Warning - couldn't parse PID " "as int: %r (%s line %i)" % (pid, lockfilename, ln)) pid = None else: safe_print("Existing client using PID", pid) else: # DisplayCAL <= 3.8.8.1 or localhost ok pid = None port = line if port: try: port = int(port) except ValueError as exception: # This shouldn't happen safe_print( "Warning - couldn't parse port as int: %r " "(%s line %i)" % (port, lockfilename, ln)) port = None else: safe_print("Existing client using port", port) if pid or port: lock2pids_ports[lockfilename].append((pid, port)) if not lock or lockfilename != applockfilename: lockfile.unlock() except EnvironmentError as exception: # This shouldn't happen safe_print( "Warning - could not read lockfile %s:" % lockfilename, exception) if module not in multi_instance: # Check lockfile(s) and probe port(s) for lockfilename in [applockfilename]: incoming = None pids_ports = lock2pids_ports.get(lockfilename) if pids_ports: pid, port = pids_ports[0] appsocket = AppSocket() if appsocket and port: safe_print("Connecting to %s..." % port) if appsocket.connect(host, port): safe_print("Connected to", port) # Other instance already running? # Get appname to check if expected app is actually # running under that port safe_print("Getting instance name") if appsocket.send("getappname"): safe_print( "Sent scripting request, awaiting response..." ) incoming = appsocket.read().rstrip("\4") safe_print("Got response: %r" % incoming) if incoming: if incoming != pyname: incoming = None else: incoming = False while incoming: # Send args as UTF-8 if module == "apply-profiles": # Always try to close currently running instance safe_print("Closing existing instance") cmd = "exit" if incoming == pyname else "close" data = [cmd] lock.unlock() else: # Send module/appname to notify running app safe_print("Notifying existing instance") data = [module or appname] if module != "3DLUT-maker": for arg in sys.argv[1:]: data.append( safe_str(safe_unicode(arg), "UTF-8")) data = sp.list2cmdline(data) if appsocket.send(data): safe_print( "Sent scripting request, awaiting response..." ) incoming = appsocket.read().rstrip("\4") safe_print("Got response: %r" % incoming) if module == "apply-profiles": if incoming == "": # Successfully sent our close request. incoming = "ok" elif incoming == "invalid" and cmd == "exit": # < 3.8.8.1 didn't have exit command continue break appsocket.close() else: pid = None if not incoming: if sys.platform == "win32": import pywintypes import win32ts try: osid = win32ts.ProcessIdToSessionId(opid) except pywintypes.error as exception: safe_print("Enumerating processes failed:", exception) osid = None try: processes = win32ts.WTSEnumerateProcesses() except pywintypes.error as exception: safe_print("Enumerating processes failed:", exception) else: appname_lower = appname.lower() exename_lower = exename.lower() if module: pyexe_lower = appname_lower + "-" + module + exe_ext else: pyexe_lower = appname_lower + exe_ext incoming = None for (sid, pid2, basename, usid) in processes: basename_lower = basename.lower() if ((pid and pid2 == pid and basename_lower == exename_lower) or ((osid is None or sid == osid) and basename_lower == pyexe_lower)) and pid2 != opid: # Other instance running incoming = False if module == "apply-profiles": if not os.path.isfile(lockfilename): # Create dummy lockfile try: with open(lockfilename, "w"): pass except EnvironmentError as exception: safe_print( "Warning - could " "not create dummy " "lockfile %s: %r" % (lockfilename, exception)) else: safe_print( "Warning - had to " "create dummy " "lockfile", lockfilename) safe_print( "Closing existing instance " "with PID", pid2) startupinfo = sp.STARTUPINFO() startupinfo.dwFlags |= sp.STARTF_USESHOWWINDOW startupinfo.wShowWindow = sp.SW_HIDE lock.unlock() try: p = sp.Popen( [ "taskkill", "/PID", "%s" % pid2 ], stdin=sp.PIPE, stdout=sp.PIPE, stderr=sp.STDOUT, startupinfo=startupinfo) stdout, stderr = p.communicate() except Exception as exception: safe_print(exception) else: safe_print(stdout) if not p.returncode: # Successfully sent our close # request. incoming = "ok" if incoming == "ok": # Successfully sent our request if module == "apply-profiles": # Wait for lockfile to be removed, in which case # we know the running instance has successfully # closed. safe_print( "Waiting for existing instance to exit and " "delete lockfile", lockfilename) while os.path.isfile(lockfilename): sleep(.05) lock.lock() safe_print("Existing instance exited.") incoming = None if lockfilename in lock2pids_ports: del lock2pids_ports[lockfilename] break if incoming is not None: # Other instance running? import localization as lang lang.init() if incoming == "ok": # Successfully sent our request safe_print(lang.getstr("app.otherinstance.notified")) elif module == "apply-profiles": safe_print("Not starting another instance.") else: # Other instance busy? handle_error(lang.getstr("app.otherinstance", name)) # Exit return # Use exclusive lock during app startup with lock: # Create listening socket appsocket = AppSocket() if appsocket: if sys.platform != "win32": # https://docs.microsoft.com/de-de/windows/win32/winsock/using-so-reuseaddr-and-so-exclusiveaddruse#using-so_reuseaddr # From the above link: "The SO_REUSEADDR socket option allows # a socket to forcibly bind to a port in use by another socket". # Note that this is different from the behavior under Linux/BSD, # where a socket can only be (re-)bound if no active listening # socket is already bound to the address. # Consequently, we don't use SO_REUSEADDR under Windows. appsocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sys._appsocket = appsocket.socket if getcfg("app.allow_network_clients"): host = "" used_ports = [ pid_port[1] for pids_ports in list(lock2pids_ports.values()) for pid_port in pids_ports ] candidate_ports = [0] if not defaultport in used_ports: candidate_ports.insert(0, defaultport) for port in candidate_ports: try: sys._appsocket.bind((host, port)) except socket.error as exception: if port == 0: safe_print( "Warning - could not bind to %s:%s:" % (host, port), exception) del sys._appsocket break else: try: sys._appsocket.settimeout(.2) except socket.error as exception: safe_print( "Warning - could not set socket " "timeout:", exception) del sys._appsocket break try: sys._appsocket.listen(1) except socket.error as exception: safe_print("Warning - could not listen on " "socket:", exception) del sys._appsocket break try: port = sys._appsocket.getsockname()[1] except socket.error as exception: safe_print( "Warning - could not get socket " "address:", exception) del sys._appsocket break sys._appsocket_port = port break if not hasattr(sys, "_appsocket_port"): port = "" lock.seek(0) if module not in multi_instance: lock.truncate(0) if not port: lock.write("%s:%s" % (opid, port)) else: lock.write(port) atexit.register(lambda: safe_print("Ran application exit handlers")) from wxwindows import BaseApp BaseApp.register_exitfunc(_exit, applockfilename, port) # Check for required resource files mod2res = { "3DLUT-maker": ["xrc/3dlut.xrc"], "curve-viewer": [], "profile-info": [], "scripting-client": [], "synthprofile": ["xrc/synthicc.xrc"], "testchart-editor": [], "VRML-to-X3D-converter": [] } for filename in mod2res.get(module, resfiles): path = get_data_path(os.path.sep.join(filename.split("/"))) if not path or not os.path.isfile(path): import localization as lang lang.init() raise ResourceError( lang.getstr("resources.notfound.error") + "\n" + filename) # Create main data dir if it does not exist if not os.path.exists(datahome): try: os.makedirs(datahome) except Exception as exception: handle_error( UserWarning("Warning - could not create " "directory '%s'" % datahome)) elif sys.platform == "darwin": # Check & fix permissions if necessary import getpass user = getpass.getuser().decode(fs_enc) script = [] for directory in (confighome, datahome, logdir): if (os.path.isdir(directory) and not os.access(directory, os.W_OK)): script.append("chown -R '%s' '%s'" % (user, directory)) if script: sp.call([ 'osascript', '-e', 'do shell script "%s" with administrator privileges' % ";".join(script).encode(fs_enc) ]) # Initialize & run if module == "3DLUT-maker": from wxLUT3DFrame import main elif module == "curve-viewer": from wxLUTViewer import main elif module == "profile-info": from wxProfileInfo import main elif module == "scripting-client": from wxScriptingClient import main elif module == "synthprofile": from wxSynthICCFrame import main elif module == "testchart-editor": from wxTestchartEditor import main elif module == "VRML-to-X3D-converter": from wxVRML2X3D import main elif module == "apply-profiles": from profile_loader import main else: from DisplayCAL import main # Run main after releasing lock main()
def _excepthook(etype, value, tb): handle_error((etype, value, tb))