From 5e2ed052c671c33e4ea4c8085027d3c82afa9eaa Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Wed, 17 May 2017 14:35:21 -0700 Subject: [PATCH] Initial import --- .bzrignore | 2 + README.rst | 15 +++++ setup.cfg | 0 setup.py | 43 +++++++++++++ webappify/__init__.py | 142 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 202 insertions(+) create mode 100644 .bzrignore create mode 100644 README.rst create mode 100644 setup.cfg create mode 100644 setup.py create mode 100644 webappify/__init__.py diff --git a/.bzrignore b/.bzrignore new file mode 100644 index 0000000..8a09f29 --- /dev/null +++ b/.bzrignore @@ -0,0 +1,2 @@ +dist +*.egg-info diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..2b34e50 --- /dev/null +++ b/README.rst @@ -0,0 +1,15 @@ +WebAppify +========= + +WebAppify is a simple module to easily create your own desktop apps of websites. + +To create your own desktop web app, import and set up the WebApp class. + +.. code:: python + + from webappify import WebApp + + app = WebApp('OpenStreetMap', 'https://www.openstreetmap.org', 'osm.png') + app.run() + +This will create a window with the website, using the icon provided. diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..e69de29 diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..07ed206 --- /dev/null +++ b/setup.py @@ -0,0 +1,43 @@ +""" +The webappify package +""" +import os +from codecs import open +from setuptools import setup, find_packages + +HERE = os.path.abspath(os.path.dirname(__file__)) + +with open(os.path.join(HERE, 'README.rst'), encoding='utf8') as f: + LONG_DESCRIPTION = f.read() + + +setup( + name='WebAppify', + version='0.1', + description='Create desktop apps of your favourite websites', + long_description=LONG_DESCRIPTION, + url='https://launchpad.net/webappify', + author='Raoul Snyman', + author_email='raoul@snyman.info', + license='MIT', + classifiers=[ + 'Development Status :: 4 - Beta', + 'Environment :: MacOS X', + 'Environment :: Win32 (MS Windows)', + 'Environment :: X11 Applications', + 'Environment :: X11 Applications :: Qt', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: MIT License', + 'Operating System :: OS Independent', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', + 'Topic :: Desktop Environment', + 'Topic :: Internet :: WWW/HTTP :: Browsers', + 'Topic :: Software Development :: Libraries :: Python Modules' + ], + keywords='Qt website', + packages=find_packages(), + install_requires=['PyQt5'] +) diff --git a/webappify/__init__.py b/webappify/__init__.py new file mode 100644 index 0000000..9ba6787 --- /dev/null +++ b/webappify/__init__.py @@ -0,0 +1,142 @@ +""" +The :mod:`webapp` module contains a WebApp class which can be used to create simple "app windows" +for websites. To use it, do this:: + + from webapp import WebApp + + app = WebApp('GMail', 'https://mail.google.com', 'gmail.png') + app.run() + +.. note: + + If your site needs Flash Player, you'll need the appropriate Flash Player plugin installed + system-wide. For WebKit, this is the NPAPI plugin, and for WebEngine, this is the PPAPI plugin. + +""" +import sys + +from PyQt5 import QtCore, QtGui, QtWidgets + +try: + from PyQt5 import QtWebEngineWidgets + HAS_WEBENGINE = True +except ImportError: + HAS_WEBENGINE = False + +try: + from PyQt5 import QtWebKit, QtWebKitWidgets + HAS_WEBKIT = True +except ImportError: + HAS_WEBKIT = False + +if HAS_WEBENGINE: + SETTINGS = [ + QtWebEngineWidgets.QWebEngineSettings.PluginsEnabled, + QtWebEngineWidgets.QWebEngineSettings.JavascriptCanAccessClipboard, + QtWebEngineWidgets.QWebEngineSettings.LocalContentCanAccessRemoteUrls + ] + WebView = QtWebEngineWidgets.QWebEngineView +elif HAS_WEBKIT: + SETTINGS = [ + QtWebKit.QWebSettings.AutoLoadImages, + QtWebKit.QWebSettings.JavascriptEnabled, + QtWebKit.QWebSettings.JavaEnabled, + QtWebKit.QWebSettings.PluginsEnabled, + QtWebKit.QWebSettings.JavascriptCanOpenWindows, + QtWebKit.QWebSettings.JavascriptCanCloseWindows, + QtWebKit.QWebSettings.JavascriptCanAccessClipboard, + QtWebKit.QWebSettings.DeveloperExtrasEnabled, + QtWebKit.QWebSettings.OfflineStorageDatabaseEnabled, + QtWebKit.QWebSettings.OfflineWebApplicationCacheEnabled, + QtWebKit.QWebSettings.LocalStorageEnabled, + QtWebKit.QWebSettings.LocalContentCanAccessRemoteUrls, + QtWebKit.QWebSettings.LocalContentCanAccessFileUrls, + QtWebKit.QWebSettings.AcceleratedCompositingEnabled + ] + WebView = QtWebKitWidgets.QWebView + class WebPage(QtWebKitWidgets.QWebPage): + """Custom class for overriding the user agent to make WebKit look like Chrome""" + def userAgentForUrl(self, url): + return 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) ' \ + 'Chrome/28.0.1500.52 Safari/537.36' +else: + print('Cannot detect either QtWebEngine or QtWebKit!') + sys.exit(1) + + +class WebWindow(QtWidgets.QWidget): + """ + Window + """ + def __init__(self, title, url, icon, parent=None): + """ + Create the window + """ + super().__init__(parent) + self.setWindowTitle(title) + self.setWindowIcon(QtGui.QIcon(icon)) + self.setContentsMargins(0, 0, 0, 0) + self.layout = QtWidgets.QVBoxLayout(self) + self.layout.setContentsMargins(0, 0, 0, 0) + self.webview = WebView(self) + if HAS_WEBKIT: + self.webview.setPage(WebPage(self.webview)) + for setting in SETTINGS: + self.webview.settings().setAttribute(setting, True) + self.webview.titleChanged.connect(self.onTitleChanged) + self.webview.setUrl(QtCore.QUrl(url)) + self.layout.addWidget(self.webview) + + def onTitleChanged(self, title): + """ + React to title changes + """ + if title: + self.setWindowTitle(title) + + +class WebApp(QtWidgets.QApplication): + """ + A generic application to open a web page in a desktop app + """ + def __init__(self, title, url, icon, hasTray=False, canMinimizeToTray=False): + """ + Create an application which loads a URL into a window + """ + super().__init__(sys.argv) + self.beforeHooks = [] + self.afterHooks = [] + self.window = None + self.title = title + self.url = url + self.icon = icon + self.hasTray = hasTray + self.canMinimizeToTray = canMinimizeToTray + self.setWindowIcon(QtGui.QIcon(self.icon)) + + def setupTrayIcon(self): + """ + Set up the tray icon + """ + if not QtWidgets.QSystemTrayIcon.isSystemTrayAvailable(): + # No reason to continue if the OS doesn't support system tray icons + return + self.trayIcon = QtWidgets.QSystemTrayIcon(QtGui.QIcon(self.icon), self.window) + self.trayIcon.show() + + def addBeforeHook(self, hook): + """ + Add a function to run before setting everything up + """ + if hook: + self.beforeHooks.append(hook) + + def run(self): + """ + Run the app + """ + self.window = WebWindow(self.title, self.url, self.icon) + if self.hasTray: + self.setupTrayIcon() + self.window.showMaximized() + return self.exec()