diff --git a/.gitignore b/.gitignore index b74acb2..1f48108 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +# Pycharm +.idea + # Compiled files from Qt *.qmlc *.xcf diff --git a/LICENSE b/LICENSE.txt similarity index 100% rename from LICENSE rename to LICENSE.txt diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..92046bf --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,5 @@ +# Include the README +include *.md + +# Include the license file +include LICENSE.txt diff --git a/README.md b/README.md index 52fb3d4..ab15e86 100644 --- a/README.md +++ b/README.md @@ -7,29 +7,36 @@ VirtScreen is an easy-to-use Linux GUI app that creates a virtual secondary scre VirtScreen is based on [PyQt5](https://www.riverbankcomputing.com/software/pyqt/intro) and [Twisted](https://twistedmatrix.com) in Python side and uses [x11vnc](https://github.com/LibVNC/x11vnc) and XRandR. -## Dependency +## Installation & running -1. You need [`x11vnc`](https://github.com/LibVNC/x11vnc) and `xrandr`. To install (example on Ubuntu): +### Installing dependancies + +You need [`x11vnc`](https://github.com/LibVNC/x11vnc) and `xrandr`. To install (example on Ubuntu): ```bash -sudo apt-get install x11vnc xrandr +$ sudo apt-get install x11vnc ``` -2. Install Python dependencies: +### Installing package -``` -pip install -r requirements.txt -``` - -## How to run - -Simply run this in the project root: +#### From the Git repository ```bash -./virtscreen.py +$ python setup.py install # add --user option if you have permission problem +``` -or -python virtscreen.py +### How to run + +Simply run `virtscreen` after installation: + +```bash +$ virtscreen +``` + +If you want to run it directly from the Git repository: + +```bash +$ ./launch.sh ``` Note that any files related to VirtScreen, including password and log, will be stored in `~/.virtscreen` directory. diff --git a/launch.sh b/launch.sh new file mode 100755 index 0000000..912ddcd --- /dev/null +++ b/launch.sh @@ -0,0 +1,4 @@ +#!/bin/sh +# Script to run virtscreen locally +# This is not intended to be included in the distributed package +python virtscreen/virtscreen.py diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 674dc4f..0000000 --- a/requirements.txt +++ /dev/null @@ -1,4 +0,0 @@ -PyQt5==5.10.1 -Twisted==17.9.0 -qt5reactor==0.5 -netifaces==0.10.6 diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..3e58a57 --- /dev/null +++ b/setup.py @@ -0,0 +1,213 @@ +"""A setuptools based setup module. + +See: +https://packaging.python.org/en/latest/distributing.html +https://github.com/pypa/sampleproject +""" + +# Always prefer setuptools over distutils +from setuptools import setup, find_packages +# To use a consistent encoding +from codecs import open +from os import path + +here = path.abspath(path.dirname(__file__)) + +# Get the long description from the README file +with open(path.join(here, 'README.md'), encoding='utf-8') as f: + long_description = f.read() + +# Arguments marked as "Required" below must be included for upload to PyPI. +# Fields marked as "Optional" may be commented out. + +setup( + # This is the name of your project. The first time you publish this + # package, this name will be registered for you. It will determine how + # users can install this project, e.g.: + # + # $ pip install sampleproject + # + # And where it will live on PyPI: https://pypi.org/project/sampleproject/ + # + # There are some restrictions on what makes a valid project name + # specification here: + # https://packaging.python.org/specifications/core-metadata/#name + name='virtscreen', # Required + + # Versions should comply with PEP 440: + # https://www.python.org/dev/peps/pep-0440/ + # + # For a discussion on single-sourcing the version across setup.py and the + # project code, see + # https://packaging.python.org/en/latest/single_source_version.html + version='0.1.0', # Required + + # This is a one-line description or tagline of what your project does. This + # corresponds to the "Summary" metadata field: + # https://packaging.python.org/specifications/core-metadata/#summary + description='Make your iPad/tablet/computer as a secondary monitor on Linux.', # Required + + # This is an optional longer description of your project that represents + # the body of text which users will see when they visit PyPI. + # + # Often, this is the same as your README, so you can just read it in from + # that file directly (as we have already done above) + # + # This field corresponds to the "Description" metadata field: + # https://packaging.python.org/specifications/core-metadata/#description-optional + long_description=long_description, # Optional + + # Denotes that our long_description is in Markdown; valid values are + # text/plain, text/x-rst, and text/markdown + # + # Optional if long_description is written in reStructuredText (rst) but + # required for plain-text or Markdown; if unspecified, "applications should + # attempt to render [the long_description] as text/x-rst; charset=UTF-8 and + # fall back to text/plain if it is not valid rst" (see link below) + # + # This field corresponds to the "Description-Content-Type" metadata field: + # https://packaging.python.org/specifications/core-metadata/#description-content-type-optional + long_description_content_type='text/markdown', # Optional (see note above) + + # This should be a valid link to your project's main homepage. + # + # This field corresponds to the "Home-Page" metadata field: + # https://packaging.python.org/specifications/core-metadata/#home-page-optional + url='https://github.com/kbumsik/VirtScreen', # Optional + + # This should be your name or the name of the organization which owns the + # project. + author='Bumsik Kim', # Optional + + # This should be a valid email address corresponding to the author listed + # above. + author_email='k.bumsik@gmail.com', # Optional + + # Classifiers help users find your project by categorizing it. + # + # For a list of valid classifiers, see https://pypi.org/classifiers/ + classifiers=[ # Optional + # How mature is this project? Common values are + # 3 - Alpha + # 4 - Beta + # 5 - Production/Stable + 'Development Status :: 4 - Beta', + + # Indicate who your project is intended for + 'Intended Audience :: Developers', + 'Intended Audience :: End Users/Desktop', + 'Topic :: Desktop Environment', + 'Topic :: Office/Business', + 'Topic :: System', + 'Topic :: Utilities', + + # Pick your license as you wish + 'License :: OSI Approved :: GNU General Public License v3 (GPLv3)', + + # Specify the Python versions you support here. In particular, ensure + # that you indicate whether you support Python 2, Python 3 or both. + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', + + # Environment + 'Environment :: X11 Applications', + 'Environment :: X11 Applications :: Qt', + 'Operating System :: POSIX :: Linux', + + # Framework used + 'Framework :: Twisted', + # 'Framework :: AsyncIO', + ], + + # This field adds keywords for your project which will appear on the + # project page. What does your project relate to? + # + # Note that this is a string of words separated by whitespace, not a list. + + # keywords='sample setuptools development', # Optional + + # You can just specify package directories manually here if your project is + # simple. Or you can use find_packages(). + # + # Alternatively, if you just want to distribute a single Python file, use + # the `py_modules` argument instead as follows, which will expect a file + # called `my_module.py` to exist: + # + # py_modules=["my_module"], + # + packages=['virtscreen'], # Required + + # This field lists other packages that your project depends on to run. + # Any package you put here will be installed by pip when your project is + # installed, so they must be valid existing projects. + # + # For an analysis of "install_requires" vs pip's requirements files see: + # https://packaging.python.org/en/latest/requirements.html + install_requires=['PyQt5>=5.10.1', + 'Twisted>=17.9.0', + 'qt5reactor>=0.5', + 'netifaces>=0.10.6'], # Optional + + # List additional groups of dependencies here (e.g. development + # dependencies). Users will be able to install these using the "extras" + # syntax, for example: + # + # $ pip install sampleproject[dev] + # + # Similar to `install_requires` above, these must be valid existing + # projects. + + # extras_require={ # Optional + # 'dev': ['check-manifest'], + # 'test': ['coverage'], + # }, + + # If there are data files included in your packages that need to be + # installed, specify them here. + # + # If using Python 2.6 or earlier, then these have to be included in + # MANIFEST.in as well. + package_data={ + 'virtscreen': ['icon/*.png', 'qml/*.qml', 'data/config.default.json'], + }, + + # Although 'package_data' is the preferred approach, in some case you may + # need to place data files outside of your packages. See: + # http://docs.python.org/3.4/distutils/setupscript.html#installing-additional-files + # + # In this case, 'data_file' will be installed into '/my_data' + + # data_files=[('my_data', ['data/data_file'])], # Optional + + # To provide executable scripts, use entry points in preference to the + # "scripts" keyword. Entry points provide cross-platform support and allow + # `pip` to create the appropriate form of executable for the target + # platform. + # + # For example, the following would provide a command called `sample` which + # executes the function `main` from this package when invoked: + entry_points={ # Optional + 'console_scripts': [ + 'virtscreen = virtscreen.virtscreen:main', + ], + }, + + # List additional URLs that are relevant to your project as a dict. + # + # This field corresponds to the "Project-URL" metadata fields: + # https://packaging.python.org/specifications/core-metadata/#project-url-multiple-use + # + # Examples listed include a pattern for specifying where the package tracks + # issues, where the source is hosted, where to say thanks to the package + # maintainers, and where to support the project financially. The key is + # what's used to render the link text on PyPI. + project_urls={ # Optional + 'Bug Reports': 'https://github.com/kbumsik/VirtScreen/issues', + # 'Funding': 'https://donate.pypi.org', + # 'Say Thanks!': 'http://saythanks.io/to/example', + 'Source': 'https://github.com/kbumsik/VirtScreen', + 'Author Homepage': 'https://kbumsik.io', + }, + python_requires='>=3.6', +) diff --git a/virtscreen/__init__.py b/virtscreen/__init__.py new file mode 100644 index 0000000..8be907d --- /dev/null +++ b/virtscreen/__init__.py @@ -0,0 +1 @@ +__all__ = ['virtscreen'] \ No newline at end of file diff --git a/config.default.json b/virtscreen/data/config.default.json similarity index 100% rename from config.default.json rename to virtscreen/data/config.default.json diff --git a/icon/gif_example.gif b/virtscreen/icon/gif_example.gif similarity index 100% rename from icon/gif_example.gif rename to virtscreen/icon/gif_example.gif diff --git a/icon/icon.png b/virtscreen/icon/icon.png similarity index 100% rename from icon/icon.png rename to virtscreen/icon/icon.png diff --git a/icon/icon_tablet_off.png b/virtscreen/icon/icon_tablet_off.png similarity index 100% rename from icon/icon_tablet_off.png rename to virtscreen/icon/icon_tablet_off.png diff --git a/icon/icon_tablet_on.png b/virtscreen/icon/icon_tablet_on.png similarity index 100% rename from icon/icon_tablet_on.png rename to virtscreen/icon/icon_tablet_on.png diff --git a/qml/AppWindow.qml b/virtscreen/qml/AppWindow.qml similarity index 100% rename from qml/AppWindow.qml rename to virtscreen/qml/AppWindow.qml diff --git a/qml/DisplayPage.qml b/virtscreen/qml/DisplayPage.qml similarity index 100% rename from qml/DisplayPage.qml rename to virtscreen/qml/DisplayPage.qml diff --git a/qml/VncPage.qml b/virtscreen/qml/VncPage.qml similarity index 100% rename from qml/VncPage.qml rename to virtscreen/qml/VncPage.qml diff --git a/main.qml b/virtscreen/qml/main.qml similarity index 96% rename from main.qml rename to virtscreen/qml/main.qml index fdf2925..99a4dbe 100644 --- a/main.qml +++ b/virtscreen/qml/main.qml @@ -62,7 +62,7 @@ Item { Loader { id: mainLoader active: false - source: "qml/AppWindow.qml" + source: "AppWindow.qml" onStatusChanged: { console.log("Loader Status Changed.", status); @@ -106,9 +106,9 @@ Item { // Sytray Icon SystemTrayIcon { id: sysTrayIcon - iconSource: backend.vncState == Backend.CONNECTED ? "icon/icon_tablet_on.png" : - backend.virtScreenCreated ? "icon/icon_tablet_off.png" : - "icon/icon.png" + iconSource: backend.vncState == Backend.CONNECTED ? "../icon/icon_tablet_on.png" : + backend.virtScreenCreated ? "../icon/icon_tablet_off.png" : + "../icon/icon.png" visible: true property bool clicked: false onMessageClicked: console.log("Message clicked") diff --git a/qml/preferenceDialog.qml b/virtscreen/qml/preferenceDialog.qml similarity index 100% rename from qml/preferenceDialog.qml rename to virtscreen/qml/preferenceDialog.qml diff --git a/virtscreen.py b/virtscreen/virtscreen.py similarity index 98% rename from virtscreen.py rename to virtscreen/virtscreen.py index f6e39bd..198f50d 100755 --- a/virtscreen.py +++ b/virtscreen/virtscreen.py @@ -22,19 +22,20 @@ del os.environ['HOME'] # Delete $HOME env for security reason. This will make # Path.home() to look up in the password directory (pwd module) os.environ['PATH'] = os.confstr("CS_PATH") # Sanitize $PATH +# Setting home path and base path HOME_PATH = str(Path.home()) if HOME_PATH is not None: HOME_PATH = HOME_PATH + "/.virtscreen" +BASE_PATH = os.path.dirname(__file__) +# Path in ~/.virtscreen X11VNC_LOG_PATH = HOME_PATH + "/x11vnc_log.txt" X11VNC_PASSWORD_PATH = HOME_PATH + "/x11vnc_passwd" CONFIG_PATH = HOME_PATH + "/config.json" -DEFAULT_CONFIG_PATH = "./config.default.json" - -PROGRAM_PATH = "." -ICON_PATH = PROGRAM_PATH + "/icon/icon.png" -ICON_TABLET_OFF_PATH = PROGRAM_PATH + "/icon/icon_tablet_off.png" -ICON_TABLET_ON_PATH = PROGRAM_PATH + "/icon/icon_tablet_on.png" - +# Path in the program path +DEFAULT_CONFIG_PATH = BASE_PATH + "/data/config.default.json" +ICON_PATH = BASE_PATH + "/icon/icon.png" +QML_PATH = BASE_PATH + "/qml" +MAIN_QML_PATH = QML_PATH + "/main.qml" # ------------------------------------------------------------------------------- # Subprocess wrapper @@ -623,7 +624,7 @@ class Backend(QObject): # ------------------------------------------------------------------------------- # Main Code # ------------------------------------------------------------------------------- -if __name__ == '__main__': +def main(): QApplication.setAttribute(Qt.AA_EnableHighDpiScaling) app = QApplication(sys.argv) @@ -666,9 +667,12 @@ if __name__ == '__main__': # Create a component factory and load the QML script. engine = QQmlApplicationEngine() - engine.load(QUrl('main.qml')) + engine.load(QUrl(MAIN_QML_PATH)) if not engine.rootObjects(): QMessageBox.critical(None, "VirtScreen", "Failed to load QML") sys.exit(1) sys.exit(app.exec_()) reactor.run() + +if __name__ == '__main__': + main()