1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216
|
Source Code Overview
====================
This page describes application processes and source code.
Applications, Frameworks and Libraries
--------------------------------------
The application is written in C++17 and uses Qt framework.
Source code can be build either with CMake.
Most icons in the application are taken from theme by default (which
currently works only on Linux) with fallback to built-in icons provided
by `FontAwesome <http://fontawesome.io/>`__.
The application logo and icons were created in `Inkscape
<https://inkscape.org/>`__ (icon source is in `src/images/icon.svg
<https://github.com/hluk/CopyQ/blob/master/src/images/icon.svg>`__).
Application Processes
---------------------
There are these system processes related to CopyQ:
- Main GUI application
- Clipboard monitor - executes automatic clipboard commands
- Menu command filter - enables/hides custom menu items based on "Filter" field
in menu commands
- Display command - executes display commands as needed
- Clipboard and X11 selection owner and synchronization - provides clipboard
data; launched as needed
- Multiple clients - anything run by user from Action dialog or triggered as
menu, automatic or global-shortcut command
Main GUI Application
~~~~~~~~~~~~~~~~~~~~
The main GUI application (or server) can be executed by running
``copyq`` binary without attributes (session name can be optionally
specified on command line).
It creates local server allowing communication with clipboard monitor
process and other client processes.
Each user can run multiple main application processes each with unique
session name (default name is empty).
Clipboard Monitor
~~~~~~~~~~~~~~~~~
Clipboard monitoring happens in separate process because otherwise it
would block GUI (in Qt clipboard needs to be accessed in main GUI
thread). The process is allowed to crash or loop indefinitely due to
bugs on some platforms.
Setting and retrieving clipboard can still happen in GUI thread (copying
and pasting in various GUI widgets) but it's preferred to send and
receive clipboard data using monitor process.
The monitor process is launched as soon as GUI application starts and is
restarted whenever it doesn't respond to keep-alive requests.
Clients and Scripting
~~~~~~~~~~~~~~~~~~~~~
Scripting language is `Qt
Script <https://doc.qt.io/qt-6/qtqml-javascript-functionlist.html>`__ (mostly
same syntax and functions as JavaScript).
API is described in :ref:`scripting-api`.
A script can be started by passing arguments to ``copyq``.
For example: ``copyq "1+1"``
After script finishes, the server sends back output of last command and
exit code (non-zero if script crashes).
.. code-block:: bash
copyq eval 'read(0,1,2)' # prints first three items in list
copyq eval 'fail()' # exit code will be non-zero
While script is running, it can send print requests to client.
.. code-block:: bash
copyq eval 'print("Hello, "); print("World!\n")'
Scripts can ask for stdin from client.
.. code-block:: bash
copyq eval 'var client_stdin = input()'
The script run in current directory of client process.
.. code-block:: bash
copyq eval 'Dir().absolutePath()'
copyq eval 'execute("ls", "-l").stdout'
Single function call where all arguments are numbers or strings can be
executed by passing function name and function arguments on command
line. Following commands are equal.
.. code-block:: bash
copyq eval 'copy("Hello, World!")'
copyq copy "Hello, World!"
Getting application version or help mustn't require the server to be
running.
.. code-block:: bash
copyq help
copyq version
Scripts run in separate thread and communicate with main thread by
calling methods on an object of ``ScriptableProxy`` class. If called
from non-main thread, these methods invoke a slot on an ``QObject`` in
main thread and pass it a function object which simply calls the method
again.
.. code-block:: cpp
bool ScriptableProxy::loadTab(const QString &tabName)
{
// This section is wrapped in an macro so to remove duplicate code.
if (!m_inMainThread) {
// Callable object just wraps the lambda so it's possible to send it to a slot.
auto callable = createCallable([&]{ return loadTab(tabName); });
m_inMainThread = true;
QMetaObject::invokeMethod(m_wnd, "invoke", Qt::BlockingQueuedConnection, Q_ARG(Callable*, &callable));
m_inMainThread = false;
return callable.result();
}
// Now it's possible to call method on an object in main thread.
return m_wnd->loadTab(tabName);
}
Platform-dependent Code
-----------------------
Code for various platforms is stored in
`src/platform <https://github.com/hluk/CopyQ/tree/master/src/platform>`__.
This leverages amount of ``#if``\ s and similar preprocessor directives
in common code.
Each supported platform implements
`PlatformNativeInterface <https://github.com/hluk/CopyQ/blob/master/src/platform/platformnativeinterface.h>`__
and ``platformNativeInterface()``.
The implementations can contain:
- Creating Qt application objects
- Clipboard handling (for clipboard monitor)
- Focusing window and getting window titles
- Getting system paths
- Setting "autostart" option
- Handling global shortcuts (**note:** this part is in
`qxt/ <https://github.com/hluk/CopyQ/tree/master/qxt>`__)
For unsupported platforms there is `simple
implementation <https://github.com/hluk/CopyQ/tree/master/src/platform/dummy>`__
to get started.
Plugins
-------
Plugins are built as dynamic libraries which are loaded from runtime
plugin directory (platform-dependent) after application start.
Code is stored in
`plugins <https://github.com/hluk/CopyQ/tree/master/plugins>`__.
Plugins implement interfaces from
`src/item/itemwidget.h <https://github.com/hluk/CopyQ/tree/master/src/item/itemwidget.h>`__.
To create new plugin just duplicate and rewrite an existing plugin. You
can build the plugin with ``make {PLUGIN_NAME}``.
Continuous Integration (CI)
---------------------------
The application binaries and packages are built and tested on multiple
CI servers.
- `GitHub Actions <https://github.com/hluk/CopyQ/actions>`__
- Builds packages for OS X.
- Builds and runs tests for Linux binaries.
- `GitLab CI <https://gitlab.com/CopyQ/CopyQ/builds>`__
- Builds and runs tests for Ubuntu 22.04 binaries.
- Screenshots are taken while GUI tests are running. These are
available if a test fails.
- `AppVeyor <https://ci.appveyor.com/project/hluk/copyq>`__
- Builds installers and portable packages for Windows.
- Provides downloads for recent commits.
- Release build are based on gcc-compiled binaries (Visual Studio
builds are also available).
- `OBS Linux Packages <https://build.opensuse.org/project/show/home:lukho:copyq>`__
- Builds release packages for various Linux distributions.
- `Beta OBS Linux Packages <https://build.opensuse.org/project/show/home:lukho:copyq-beta>`__
- Builds beta and unstable packages for various Linux distributions.
- `Codecov <https://app.codecov.io/gh/hluk/CopyQ>`__
- Contains coverage report from tests run with GitHub Actions.
|