From 9ccf2f552be246f7912e9dc923f8da8ae47fe544 Mon Sep 17 00:00:00 2001 From: Lex Neva Date: Wed, 10 Apr 2019 23:37:16 -0400 Subject: switch print pdf gui to electron --- lib/extensions/print_pdf.py | 141 ++++++-------------------------------------- lib/gui/__init__.py | 1 + lib/gui/electron.py | 16 +++++ 3 files changed, 34 insertions(+), 124 deletions(-) create mode 100644 lib/gui/electron.py (limited to 'lib') diff --git a/lib/extensions/print_pdf.py b/lib/extensions/print_pdf.py index 4913a32a..e736b05b 100644 --- a/lib/extensions/print_pdf.py +++ b/lib/extensions/print_pdf.py @@ -1,27 +1,27 @@ -import sys +from copy import deepcopy +from datetime import date +import errno +import json +import logging import os -from threading import Thread import socket -import errno +import sys +from threading import Thread import time -import logging -from copy import deepcopy -import wx + import appdirs -import json +from flask import Flask, request, Response, send_from_directory, jsonify import inkex from jinja2 import Environment, FileSystemLoader, select_autoescape -from datetime import date -from flask import Flask, request, Response, send_from_directory, jsonify -import webbrowser import requests -from .base import InkstitchExtension +from ..gui import open_url from ..i18n import _, translation as inkstitch_translation +from ..stitch_plan import patches_to_stitch_plan from ..svg import render_stitch_plan from ..svg.tags import INKSCAPE_GROUPMODE -from ..stitch_plan import patches_to_stitch_plan from ..threads import ThreadCatalog +from .base import InkstitchExtension def datetimeformat(value, format='%Y/%m/%d'): @@ -51,42 +51,6 @@ def save_defaults(defaults): json.dump(defaults, defaults_file) -def open_url(url): - # Avoid spurious output from xdg-open. Any output on stdout will crash - # inkscape. - null = open(os.devnull, 'w') - old_stdout = os.dup(sys.stdout.fileno()) - os.dup2(null.fileno(), sys.stdout.fileno()) - - if getattr(sys, 'frozen', False): - - # PyInstaller sets LD_LIBRARY_PATH. We need to temporarily clear it - # to avoid confusing xdg-open, which webbrowser will run. - - # The following code is adapted from PyInstaller's documentation - # http://pyinstaller.readthedocs.io/en/stable/runtime-information.html - - old_environ = dict(os.environ) # make a copy of the environment - lp_key = 'LD_LIBRARY_PATH' # for Linux and *BSD. - lp_orig = os.environ.get(lp_key + '_ORIG') # pyinstaller >= 20160820 has this - if lp_orig is not None: - os.environ[lp_key] = lp_orig # restore the original, unmodified value - else: - os.environ.pop(lp_key, None) # last resort: remove the env var - - webbrowser.open(url) - - # restore the old environ - os.environ.clear() - os.environ.update(old_environ) - else: - webbrowser.open(url) - - # restore file descriptors - os.dup2(old_stdout, sys.stdout.fileno()) - os.close(old_stdout) - - class PrintPreviewServer(Thread): def __init__(self, *args, **kwargs): self.html = kwargs.pop('html') @@ -96,7 +60,6 @@ class PrintPreviewServer(Thread): self.realistic_color_block_svgs = kwargs.pop('realistic_color_block_svgs') Thread.__init__(self, *args, **kwargs) self.daemon = True - self.last_request_time = None self.shutting_down = False self.__setup_app() @@ -111,16 +74,6 @@ class PrintPreviewServer(Thread): self.__set_resources_path() self.app = Flask(__name__) - @self.app.before_request - def request_started(): - self.last_request_time = time.time() - - @self.app.before_first_request - def start_watcher(): - self.watcher_thread = Thread(target=self.watch) - self.watcher_thread.daemon = True - self.watcher_thread.start() - @self.app.route('/') def index(): return self.html @@ -129,17 +82,12 @@ class PrintPreviewServer(Thread): def shutdown(): self.shutting_down = True request.environ.get('werkzeug.server.shutdown')() - return _('Closing...') + '

' + _('It is safe to close this window now.') + return "shutting down" @self.app.route('/resources/', methods=['GET']) def resources(resource): return send_from_directory(self.resources_path, resource, cache_timeout=1) - @self.app.route('/ping') - def ping(): - # Javascript is letting us know it's still there. This resets self.last_request_time. - return "pong" - @self.app.route('/printing/start') def printing_start(): # temporarily turn off the watcher while the print dialog is up, @@ -215,21 +163,6 @@ class PrintPreviewServer(Thread): # the context of a flask request, so we'll just make one requests.post("http://%s:%s/shutdown" % (self.host, self.port)) - def watch(self): - try: - while True: - time.sleep(1) - if self.shutting_down: - break - - if self.last_request_time is not None and \ - (time.time() - self.last_request_time) > 3: - self.stop() - break - except BaseException: - # seems like sometimes this thread blows up during shutdown - pass - def disable_logging(self): logging.getLogger('werkzeug').setLevel(logging.ERROR) @@ -252,42 +185,6 @@ class PrintPreviewServer(Thread): break -class PrintInfoFrame(wx.Frame): - def __init__(self, *args, **kwargs): - self.print_server = kwargs.pop("print_server") - wx.Frame.__init__(self, *args, **kwargs) - - panel = wx.Panel(self) - sizer = wx.BoxSizer(wx.VERTICAL) - - message = _("A print preview has been opened in your web browser. " - "This window will stay open in order to communicate with the JavaScript code running in your browser.\n\n" - "This window will close after you close the print preview in your browser, or you can close it manually if necessary.") - text = wx.StaticText(panel, label=message) - font = wx.Font(14, wx.DEFAULT, wx.NORMAL, wx.NORMAL) - text.SetFont(font) - sizer.Add(text, proportion=1, flag=wx.ALL | wx.EXPAND, border=20) - - stop_button = wx.Button(panel, id=wx.ID_CLOSE) - stop_button.Bind(wx.EVT_BUTTON, self.close_button_clicked) - sizer.Add(stop_button, proportion=0, flag=wx.ALIGN_CENTER | wx.ALL, border=10) - - panel.SetSizer(sizer) - panel.Layout() - - self.timer = wx.PyTimer(self.__watcher) - self.timer.Start(250) - - def close_button_clicked(self, event): - self.print_server.stop() - - def __watcher(self): - if not self.print_server.is_alive(): - self.timer.Stop() - self.timer = None - self.Destroy() - - class Print(InkstitchExtension): def build_environment(self): if getattr(sys, 'frozen', False): @@ -409,11 +306,7 @@ class Print(InkstitchExtension): realistic_color_block_svgs=realistic_color_block_svgs ) print_server.start() - - time.sleep(1) - open_url("http://%s:%s/" % (print_server.host, print_server.port)) - - app = wx.App() - info_frame = PrintInfoFrame(None, title=_("Ink/Stitch Print"), size=(450, 350), print_server=print_server) - info_frame.Show() - app.MainLoop() + browser_window = open_url("http://%s:%s/" % (print_server.host, print_server.port)) + browser_window.wait() + print_server.stop() + print_server.join() diff --git a/lib/gui/__init__.py b/lib/gui/__init__.py index 060c3d93..5e249a55 100644 --- a/lib/gui/__init__.py +++ b/lib/gui/__init__.py @@ -1,3 +1,4 @@ from dialogs import info_dialog, confirm_dialog +from electron import open_url from presets import PresetsPanel from simulator import EmbroiderySimulator, SimulatorPreview, show_simulator diff --git a/lib/gui/electron.py b/lib/gui/electron.py new file mode 100644 index 00000000..cad86a16 --- /dev/null +++ b/lib/gui/electron.py @@ -0,0 +1,16 @@ +import os +import subprocess + +from ..utils import get_bundled_dir + + +app_process = None + + +def open_url(url): + global app + + electron_path = os.path.join(get_bundled_dir("electron"), "out", "inkstitch-linux-x64", "inkstitch-gui") + app_process = subprocess.Popen([electron_path, url]) + + return app_process -- cgit v1.2.3 From d52dc8d5fc80fad645718805ebf6ec297ace8a44 Mon Sep 17 00:00:00 2001 From: Lex Neva Date: Thu, 11 Apr 2019 00:03:23 -0400 Subject: fix electron path --- lib/gui/electron.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/gui/electron.py b/lib/gui/electron.py index cad86a16..d3547c34 100644 --- a/lib/gui/electron.py +++ b/lib/gui/electron.py @@ -1,5 +1,6 @@ import os import subprocess +import sys from ..utils import get_bundled_dir @@ -10,7 +11,19 @@ app_process = None def open_url(url): global app - electron_path = os.path.join(get_bundled_dir("electron"), "out", "inkstitch-linux-x64", "inkstitch-gui") + if getattr(sys, 'frozen', None) is not None: + electron_path = os.path.join(get_bundled_dir("electron"), "inkstitch-gui") + else: + # It's a bit trickier to find the electron app in a development environment. + base_dir = get_bundled_dir("electron") + + try: + package_dir = os.listdir(os.path.join(base_dir, "out"))[0] + except (OSError, IndexError): + raise Exception("Electron app not found. Be sure to run 'npm install; npm run package' in %s." % base_dir) + + electron_path = os.path.join(base_dir, "out", package_dir, "inkstitch-gui") + app_process = subprocess.Popen([electron_path, url]) return app_process -- cgit v1.2.3 From 7e04b879c27fd0ece9193adf48cc2939c66de08b Mon Sep 17 00:00:00 2001 From: Lex Neva Date: Thu, 11 Apr 2019 00:03:33 -0400 Subject: wait for server to (probably) be up --- lib/extensions/print_pdf.py | 1 + 1 file changed, 1 insertion(+) (limited to 'lib') diff --git a/lib/extensions/print_pdf.py b/lib/extensions/print_pdf.py index e736b05b..6eef1f8d 100644 --- a/lib/extensions/print_pdf.py +++ b/lib/extensions/print_pdf.py @@ -306,6 +306,7 @@ class Print(InkstitchExtension): realistic_color_block_svgs=realistic_color_block_svgs ) print_server.start() + time.sleep(0.5) browser_window = open_url("http://%s:%s/" % (print_server.host, print_server.port)) browser_window.wait() print_server.stop() -- cgit v1.2.3 From 28ffc8692c30ce2db98b70b7752927758ed8f772 Mon Sep 17 00:00:00 2001 From: Lex Neva Date: Thu, 11 Apr 2019 01:00:28 -0400 Subject: launch electron properly on macos --- lib/gui/electron.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/gui/electron.py b/lib/gui/electron.py index d3547c34..6a31abe1 100644 --- a/lib/gui/electron.py +++ b/lib/gui/electron.py @@ -24,6 +24,10 @@ def open_url(url): electron_path = os.path.join(base_dir, "out", package_dir, "inkstitch-gui") - app_process = subprocess.Popen([electron_path, url]) + if sys.platform == "darwin": + electron_path += ".app/Contents/MacOS/inkstitch-gui" + app_process = subprocess.Popen(["open", "-a", electron_path, "--args", url]) + else: + app_process = subprocess.Popen([electron_path, url]) return app_process -- cgit v1.2.3 From 0d54c828d0477db8666ff24d451591d9f7fdcf57 Mon Sep 17 00:00:00 2001 From: Lex Neva Date: Fri, 12 Apr 2019 01:41:14 -0400 Subject: use docker for windows --- lib/gui/electron.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/gui/electron.py b/lib/gui/electron.py index 6a31abe1..4ecc37bf 100644 --- a/lib/gui/electron.py +++ b/lib/gui/electron.py @@ -1,3 +1,4 @@ +from glob import glob import os import subprocess import sys @@ -16,13 +17,12 @@ def open_url(url): else: # It's a bit trickier to find the electron app in a development environment. base_dir = get_bundled_dir("electron") + package_dir = glob(os.path.join(base_dir, 'dist', '*-unpacked')) - try: - package_dir = os.listdir(os.path.join(base_dir, "out"))[0] - except (OSError, IndexError): - raise Exception("Electron app not found. Be sure to run 'npm install; npm run package' in %s." % base_dir) + if not package_dir: + raise Exception("Electron app not found. Be sure to run 'yarn; yarn dist' in %s." % base_dir) - electron_path = os.path.join(base_dir, "out", package_dir, "inkstitch-gui") + electron_path = os.path.join(base_dir, package_dir, "inkstitch-gui") if sys.platform == "darwin": electron_path += ".app/Contents/MacOS/inkstitch-gui" -- cgit v1.2.3 From 3a3c9e5406563edd00c2ec08102ca7c69aaa360c Mon Sep 17 00:00:00 2001 From: Lex Neva Date: Fri, 12 Apr 2019 15:32:37 -0400 Subject: fix style --- lib/extensions/print_pdf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/extensions/print_pdf.py b/lib/extensions/print_pdf.py index 6eef1f8d..4d8ffbd4 100644 --- a/lib/extensions/print_pdf.py +++ b/lib/extensions/print_pdf.py @@ -16,7 +16,7 @@ from jinja2 import Environment, FileSystemLoader, select_autoescape import requests from ..gui import open_url -from ..i18n import _, translation as inkstitch_translation +from ..i18n import translation as inkstitch_translation from ..stitch_plan import patches_to_stitch_plan from ..svg import render_stitch_plan from ..svg.tags import INKSCAPE_GROUPMODE -- cgit v1.2.3 From 5b5cde330fd21289fcdce7f43d37c54b7cc73310 Mon Sep 17 00:00:00 2001 From: Lex Neva Date: Fri, 12 Apr 2019 16:48:25 -0400 Subject: fix dev path --- lib/gui/electron.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/gui/electron.py b/lib/gui/electron.py index 4ecc37bf..ced3ad66 100644 --- a/lib/gui/electron.py +++ b/lib/gui/electron.py @@ -17,9 +17,10 @@ def open_url(url): else: # It's a bit trickier to find the electron app in a development environment. base_dir = get_bundled_dir("electron") - package_dir = glob(os.path.join(base_dir, 'dist', '*-unpacked')) - if not package_dir: + try: + package_dir = glob(os.path.join(base_dir, 'dist', '*-unpacked'))[0] + except IndexError: raise Exception("Electron app not found. Be sure to run 'yarn; yarn dist' in %s." % base_dir) electron_path = os.path.join(base_dir, package_dir, "inkstitch-gui") -- cgit v1.2.3 From 9b2a47136b34a4b9cfcc42282a39fdd909e9f8af Mon Sep 17 00:00:00 2001 From: Lex Neva Date: Fri, 12 Apr 2019 17:45:57 -0400 Subject: enable print button --- lib/extensions/print_pdf.py | 12 ------------ lib/gui/electron.py | 22 +++++++--------------- 2 files changed, 7 insertions(+), 27 deletions(-) (limited to 'lib') diff --git a/lib/extensions/print_pdf.py b/lib/extensions/print_pdf.py index 4d8ffbd4..0cbce479 100644 --- a/lib/extensions/print_pdf.py +++ b/lib/extensions/print_pdf.py @@ -88,18 +88,6 @@ class PrintPreviewServer(Thread): def resources(resource): return send_from_directory(self.resources_path, resource, cache_timeout=1) - @self.app.route('/printing/start') - def printing_start(): - # temporarily turn off the watcher while the print dialog is up, - # because javascript will be frozen - self.last_request_time = None - return "OK" - - @self.app.route('/printing/end') - def printing_end(): - # nothing to do here -- request_started() will restart the watcher - return "OK" - @self.app.route('/settings/', methods=['POST']) def set_field(field_name): self.metadata[field_name] = request.json['value'] diff --git a/lib/gui/electron.py b/lib/gui/electron.py index ced3ad66..f1bdeb61 100644 --- a/lib/gui/electron.py +++ b/lib/gui/electron.py @@ -1,4 +1,3 @@ -from glob import glob import os import subprocess import sys @@ -14,21 +13,14 @@ def open_url(url): if getattr(sys, 'frozen', None) is not None: electron_path = os.path.join(get_bundled_dir("electron"), "inkstitch-gui") - else: - # It's a bit trickier to find the electron app in a development environment. - base_dir = get_bundled_dir("electron") - - try: - package_dir = glob(os.path.join(base_dir, 'dist', '*-unpacked'))[0] - except IndexError: - raise Exception("Electron app not found. Be sure to run 'yarn; yarn dist' in %s." % base_dir) - - electron_path = os.path.join(base_dir, package_dir, "inkstitch-gui") - if sys.platform == "darwin": - electron_path += ".app/Contents/MacOS/inkstitch-gui" - app_process = subprocess.Popen(["open", "-a", electron_path, "--args", url]) + if sys.platform == "darwin": + electron_path += ".app/Contents/MacOS/inkstitch-gui" + subprocess.Popen(["open", "-a", electron_path, "--args", url]) + else: + app_process = subprocess.Popen([electron_path, url]) else: - app_process = subprocess.Popen([electron_path, url]) + # if we're not running in a pyinstaller bundle, run electron directly + app_process = subprocess.Popen(["yarn", "dev", url], cwd=get_bundled_dir("electron")) return app_process -- cgit v1.2.3 From 67027f07046aecc9e45785e077ad7ee70b365c0c Mon Sep 17 00:00:00 2001 From: Kate Murphy Date: Wed, 17 Apr 2019 21:48:44 -0400 Subject: Fix crashed caused by Inkscape reading message from stdout --- lib/gui/electron.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/gui/electron.py b/lib/gui/electron.py index f1bdeb61..8bc0bcef 100644 --- a/lib/gui/electron.py +++ b/lib/gui/electron.py @@ -11,16 +11,19 @@ app_process = None def open_url(url): global app + # Any output on stdout will crash inkscape. + null = open(os.devnull, 'w') + if getattr(sys, 'frozen', None) is not None: electron_path = os.path.join(get_bundled_dir("electron"), "inkstitch-gui") if sys.platform == "darwin": electron_path += ".app/Contents/MacOS/inkstitch-gui" - subprocess.Popen(["open", "-a", electron_path, "--args", url]) + subprocess.Popen(["open", "-a", electron_path, "--args", url], stdout=null) else: app_process = subprocess.Popen([electron_path, url]) else: # if we're not running in a pyinstaller bundle, run electron directly - app_process = subprocess.Popen(["yarn", "dev", url], cwd=get_bundled_dir("electron")) + app_process = subprocess.Popen(["yarn", "dev", url], cwd=get_bundled_dir("electron"), stdout=null) return app_process -- cgit v1.2.3 From a3b7d8eb421d6e909c374c92560cfeec230bba69 Mon Sep 17 00:00:00 2001 From: katee Date: Mon, 22 Apr 2019 21:42:17 -0400 Subject: Refactor electron to always pipe stdout to /dev/null --- lib/gui/electron.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/gui/electron.py b/lib/gui/electron.py index 8bc0bcef..6bff15aa 100644 --- a/lib/gui/electron.py +++ b/lib/gui/electron.py @@ -11,19 +11,22 @@ app_process = None def open_url(url): global app - # Any output on stdout will crash inkscape. - null = open(os.devnull, 'w') + command = [] + cwd = None if getattr(sys, 'frozen', None) is not None: electron_path = os.path.join(get_bundled_dir("electron"), "inkstitch-gui") if sys.platform == "darwin": electron_path += ".app/Contents/MacOS/inkstitch-gui" - subprocess.Popen(["open", "-a", electron_path, "--args", url], stdout=null) + command = ["open", "-a", electron_path, "--args", url] else: - app_process = subprocess.Popen([electron_path, url]) + command = [electron_path, url] else: # if we're not running in a pyinstaller bundle, run electron directly - app_process = subprocess.Popen(["yarn", "dev", url], cwd=get_bundled_dir("electron"), stdout=null) + command = ["yarn", "dev", url] + cwd = get_bundled_dir("electron") - return app_process + # Any output on stdout will crash inkscape. + null = open(os.devnull, 'w') + return subprocess.Popen(command, cwd=cwd, stdout=null) -- cgit v1.2.3 From 352aebad5e9f5439f428efdeb1c29a51fa4bad96 Mon Sep 17 00:00:00 2001 From: Lex Neva Date: Tue, 23 Apr 2019 19:57:49 -0400 Subject: comment to explain sleep --- lib/extensions/print_pdf.py | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'lib') diff --git a/lib/extensions/print_pdf.py b/lib/extensions/print_pdf.py index 0cbce479..befb7861 100644 --- a/lib/extensions/print_pdf.py +++ b/lib/extensions/print_pdf.py @@ -294,7 +294,12 @@ class Print(InkstitchExtension): realistic_color_block_svgs=realistic_color_block_svgs ) print_server.start() + + # Wait for print_server.host and print_server.port to be populated. + # Hacky, but Flask doesn't have an option for a callback to be run + # after startup. time.sleep(0.5) + browser_window = open_url("http://%s:%s/" % (print_server.host, print_server.port)) browser_window.wait() print_server.stop() -- cgit v1.2.3