diff --git a/.github/workflows/deploy-dev-docs.yml b/.github/workflows/deploy-dev-docs.yml
new file mode 100644
index 00000000..57a3635a
--- /dev/null
+++ b/.github/workflows/deploy-dev-docs.yml
@@ -0,0 +1,75 @@
+name: Deploy developer docs
+
+on:
+ push:
+ branches: [ master, docs ]
+ paths:
+ - 'src/**'
+ - 'docs/dev/**'
+ - '.github/workflows/deploy-dev-docs.yml'
+
+jobs:
+ build-and-deploy:
+ runs-on: ubuntu-22.04
+ steps:
+ - name: Install dependencies
+ run: |
+ sudo apt-get --yes --quiet update
+ sudo apt-get --yes --no-install-recommends install doxygen
+ pip install \
+ mkdocs \
+ mkdocs-material \
+ git+https://github.com/veracioux/mkdoxy@v1.0.0
+
+ - name: Checkout flameshot source
+ uses: actions/checkout@v3
+ with:
+ path: 'flameshot'
+
+ - name: Build docs
+ working-directory: ${{github.workspace}}/flameshot/docs/dev
+ run: |
+ make build
+
+ - name: Checkout flameshot website
+ uses: actions/checkout@v3
+ with:
+ repository: 'flameshot-org/flameshot-org.github.io'
+ ref: 'gh-pages'
+ path: 'website'
+
+ - name: Configure git credentials for website repo
+ working-directory: ${{github.workspace}}/website
+ run: |
+ git config user.name "GitHub Actions"
+ git config user.email "github-actions-bot@users.noreply.github.com"
+ git config http.https://github.com/.extraheader 'AUTHORIZATION basic ${{secrets.TOKEN_PUSH_TO_WEBSITE_REPO}}'
+ git remote add destination "https://x-access-token:${{secrets.TOKEN_PUSH_TO_WEBSITE_REPO}}@github.com/flameshot-org/flameshot-org.github.io"
+
+ - name: Add developer docs to website deployment
+ working-directory: ${{github.workspace}}/website
+ run: |
+ # Create empty dev-docs-staging branch
+ git checkout --orphan dev-docs-staging
+ git rm -r --cached .
+ rm -rf docs/dev
+ # Copy generated docs over
+ mkdir -p docs
+ mv "${{github.workspace}}/flameshot/docs/dev/output" \
+ "./docs/dev"
+ # Commit docs/dev to the dev-docs-staging branch
+ git add docs/dev
+ HASH="$(git --git-dir="${{github.workspace}}/flameshot/.git" rev-parse HEAD)"
+ git commit --message "Add developer docs from flameshot@$HASH"
+ # Apply changes to gh-pages
+ git checkout --force gh-pages
+ git checkout dev-docs-staging -- docs/dev
+ # Commit (we use `|| true` because the commit could be empty and thus fail)
+ git commit --message "Add developer docs from flameshot@$HASH" || true
+
+ - name: Push to website repo
+ working-directory: ${{github.workspace}}/website
+ run: |
+ git push --force destination dev-docs-staging
+ git push destination gh-pages
+
diff --git a/.gitignore b/.gitignore
index 8fbdd26a..389bcb5c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -72,3 +72,6 @@ data/flatpak/.flatpak-builder
#MacOS Crap
.DS_Store
+
+# Miscellaneous
+!docs/dev/Makefile
diff --git a/docs/dev/.gitignore b/docs/dev/.gitignore
new file mode 100644
index 00000000..90551e8b
--- /dev/null
+++ b/docs/dev/.gitignore
@@ -0,0 +1,2 @@
+output
+mkdoxy-generated
diff --git a/docs/dev/Makefile b/docs/dev/Makefile
new file mode 100644
index 00000000..f44e4321
--- /dev/null
+++ b/docs/dev/Makefile
@@ -0,0 +1,9 @@
+serve:
+ mkdocs serve --dev-addr localhost:8080 --watch ../../src
+build:
+ mkdocs build
+ @echo "Post-processing..."
+ @bash post-process.sh
+ @echo "DONE."
+clean:
+ rm -rf mkdoxy-generated output
diff --git a/docs/dev/mkdocs.yml b/docs/dev/mkdocs.yml
new file mode 100644
index 00000000..ad981543
--- /dev/null
+++ b/docs/dev/mkdocs.yml
@@ -0,0 +1,47 @@
+site_name: Flameshot Developer Docs
+site_url: https://flameshot.org/docs/dev/
+repo_url: https://github.com/flameshot-org/flameshot/
+edit_uri: tree/master/docs/dev/src
+docs_dir: src
+site_dir: output
+markdown_extensions:
+ - admonition
+ - attr_list
+ - toc:
+ permalink: "#"
+ - pymdownx.emoji:
+ emoji_index: !!python/name:materialx.emoji.twemoji
+ emoji_generator: !!python/name:materialx.emoji.to_svg
+
+plugins:
+ - search
+ - mkdoxy:
+ projects:
+ flameshot:
+ src-dirs: ../../src/
+ full-doc: True
+ doxy-cfg:
+ FILE_PATTERNS: "*.cpp *.h"
+ # #TODO for some reason this causes an exception
+ EXCLUDE_PATTERNS: "*/capturetool.h"
+ FULL_PATH_NAMES: "NO"
+ SHOW_USED_FILES: "NO"
+ RECURSIVE: True
+
+ save-api: mkdoxy-generated
+ debug: True
+ ignore-errors: False
+
+theme:
+ name: material
+ logo: https://flameshot.org/flameshot-icon.svg
+
+nav:
+ - Overview: index.md
+ - Debugging: debugging.md
+ - FAQ: faq.md
+ - 'Maintaining the documentation': docs.md
+ - API:
+ - Classes: flameshot/classes.md
+ - 'Class Hierarchy': flameshot/hierarchy.md
+ - Files: flameshot/files.md
diff --git a/docs/dev/post-process.sh b/docs/dev/post-process.sh
new file mode 100644
index 00000000..b9c5edbd
--- /dev/null
+++ b/docs/dev/post-process.sh
@@ -0,0 +1,19 @@
+# Only run this script from the Makefile
+
+shopt -s globstar
+cd output
+
+# Classes backlink to the ClassList in their breadcrumbs. We use the ClassIndex
+# instead.
+rm -rf flameshot/annotated
+ln -sf classes flameshot/annotated
+
+# Hide 'Edit this page button' from the auto-generated docs pages
+# It would be better to change the button to link to the file on github, but
+# it seems like too much work right now.
+sed -i 's|title="Edit this page"|& style="display: none !important"|' flameshot/*/*.html
+
+# MkDoxy adds Qt classes into the class hierarchy. We don't want that.
+sed -i 's|
class Q[^<]* ||' flameshot/*/*.html
+
+# vim: filetype=bash
diff --git a/docs/dev/src/debugging.md b/docs/dev/src/debugging.md
new file mode 100644
index 00000000..25566977
--- /dev/null
+++ b/docs/dev/src/debugging.md
@@ -0,0 +1,16 @@
+# Debugging
+
+## `FLAMESHOT_DEBUG_CAPTURE`
+
+With this cmake variable set to `ON`, the flameshot capture GUI window won't bypass the
+window manager. This allows you to manipulate the capture GUI window like any
+other window while debugging.
+
+This can be useful if a debugging breakpoint is triggered while flameshot is in
+full screen mode. Without this variable, you might have trouble inspecting the
+code due to a frozen full-screen window.
+
+Usage:
+```shell
+cmake -DFLAMESHOT_DEBUG_CAPTURE=ON ...
+```
diff --git a/docs/dev/src/docs.md b/docs/dev/src/docs.md
new file mode 100644
index 00000000..c8d4c410
--- /dev/null
+++ b/docs/dev/src/docs.md
@@ -0,0 +1,141 @@
+# Maintaining the documentation
+
+The narrative documentation is written in markdown and built into HTML using
+[MkDocs][mkdocs], particularly the [MkDocs material theme][mkdocs-material]. The
+source code documentation is generated using Doxygen and adapted for MkDocs
+using [MkDoxy][mkdoxy] (a tweaked custom fork of the original). The source code
+of this documentation can be found [here][doc-source].
+
+!!! tip
+
+ In order to edit a page from the documentation, click the :material-pencil:
+ button in the top right corner of the page. Please note that this button
+ won't work within the API section of the documentation - the button is
+ removed from there during [post-processing][], but it will still be visible
+ when [serving the website locally][serving-locally].
+
+## Serving locally
+To serve the documentation locally, run the `make serve` target in the
+`docs/dev` directory. The server is available at the port designated in the
+output of the command.
+
+## Notes and conventions
+- When you add new files or rename existing files or section names, be sure to
+ edit the `nav` property of [mkdocs.yml][mkdocs.yml].
+- Always insert links as [reference style
+ links][markdown:reference-style-links]. This will make the docs source code
+ more readable and make broken links more easily detectable and replaceable.
+
+### Post-processing
+There are some tweaks we make to the generated HTML documentation. We do that in
+the `make build` target, by running the [post-process.sh][post-process.sh]
+script. To see what post-processing we do, see that file.
+
+For this reason, the version of the documentation served locally using `make
+serve` will not match the generated HTML documentation 100%. But those
+inconsistencies are few and minor.
+
+## Dependencies
+```shell
+pip install \
+ mkdocs \
+ mkdocs-material \
+ git+https://github.com/veracioux/mkdoxy@v1.0.0
+```
+
+!!! note
+
+ We use a forked version of [mkdoxy][mkdoxy-original] that can be found
+ [here][mkdoxy], that fixes some annoying things from the original.
+
+## Deployment
+
+The developer documentation is served from the official Flameshot website
+[flameshot.org][website]. Here's how.
+
+The official website itself is served from this [repo][website-repo]. That repo
+contains the user documentation. It's deployed using GitHub pages -- the served
+files can be found on the [gh-pages][] branch of that repo. This branch is
+automatically created by the [build][website-build] workflow on master.
+
+To make the developer docs available on the official site, we use a custom
+GitHub action called [deploy-dev-docs][] in the [flameshot][] repo. This action
+will build and deploy this documentation into the `docs/dev` subdirectory of the
+[gh-pages][] branch.
+
+### The deploy-dev-docs GitHub workflow
+
+This workflow checks out the flameshot website [repo][website-repo] and does the following:
+
+- Creates a clean [dev-docs-staging][] branch (we'll explain why, below).
+- Generates the developer docs under `docs/dev` there and makes a commit
+- Checks out the [gh-pages][] branch and makes the same commit there
+- Force-pushes the dev-docs-staging branch to the website repo
+- Pushes the gh-pages branch to the website repo
+
+Since the [gh-pages][] branch is re-created from scratch by the [website
+deployment workflow][website-build], the commit that added the developer
+documentation will be lost. That's why we have to re-apply the commit during the
+[website deployment workflow][website-build] as well. **That is the reason why
+we created the** [**dev-docs-staging**][dev-docs-staging] **branch in the first
+place.**
+
+!!! note
+
+ The deploy-dev-docs workflow is set to run on the `docs` branch as well as `master`.
+ This branch is used for debugging the developer docs and its associated
+ workflows, without polluting the `master` branch with unnecessary commits.
+
+#### Access tokens
+In order to make changes to the [website repo][website-repo] from within a
+workflow in the [flameshot repo][flameshot], the workflow needs to use an access
+token, which it obtains from the `TOKEN_PUSH_TO_WEBSITE_REPO` secret.
+
+The following process was used to set it up:
+
+1. A flameshot organization member with write access must create a personal
+ access token (PAT) [here][PAT] with write access to the [website repo][website-repo].
+2. A secret named `TOKEN_PUSH_TO_WEBSITE_REPO` must be added to the
+ [flameshot][] repo and its value must be set to the PAT. This can be done
+ [here][action-secrets].
+
+For best security practice, the token should be set to expire after some time
+(currently ~6 months). The token can be regenerated without the need to recreate
+it. After regeneration you will need to update the `TOKEN_PUSH_TO_WEBSITE_REPO`
+secret, which can be done [here][edit-secret].
+
+!!! tip
+
+ The currently active PAT is owned by [veracioux][] and is set to expire on July
+ 31 2024. If you notice the token has expired, ask him to re-generate it.
+
+
+[post-processing]: #post-processing
+[serving-locally]: #serving-locally
+
+
+[flameshot]: https://github.com/flameshot-org/flameshot
+[website]: https://flameshot.org
+[doc-source]: https://github.com/flameshot-org/flameshot/tree/master/docs/dev
+[website-repo]: https://github.com/flameshot-org/flameshot-org.github.io
+[gh-pages]: https://github.com/flameshot-org/flameshot-org.github.io/tree/gh-pages
+[dev-docs-staging]: https://github.com/flameshot-org/flameshot-org.github.io/tree/dev-docs-staging
+[action-secrets]: https://github.com/flameshot-org/flameshot/settings/secrets/actions
+[edit-secret]: https://github.com/flameshot-org/flameshot/settings/secrets/actions/TOKEN_PUSH_TO_WEBSITE_REPO
+
+
+[mkdocs.yml]: https://github.com/flameshot-org/flameshot/blob/master/docs/dev/mkdocs.yml
+[post-process.sh]: https://github.com/flameshot-org/flameshot/blob/master/docs/dev/post-process.sh
+[deploy-dev-docs]: https://github.com/flameshot-org/flameshot/blob/master/.github/workflows/deploy-dev-docs.yml
+
+
+[website-build]: https://github.com/flameshot-org/flameshot-org.github.io/blob/master/.github/workflows/build.yml
+
+
+[markdown:reference-style-links]: https://www.markdownguide.org/basic-syntax/#reference-style-links
+[mkdocs]: https://www.mkdocs.org/
+[mkdocs-material]: https://squidfunk.github.io/mkdocs-material
+[mkdoxy-original]: https://github.com/JakubAndrysek/mkdoxy
+[mkdoxy]: https://github.com/veracioux/mkdoxy
+[PAT]: https://github.com/settings/tokens?type=beta
+[veracioux]: https://github.com/veracioux
diff --git a/docs/dev/src/faq.md b/docs/dev/src/faq.md
new file mode 100644
index 00000000..07f4c591
--- /dev/null
+++ b/docs/dev/src/faq.md
@@ -0,0 +1,47 @@
+
+# FAQ
+
+!!! todo
+
+ Incomplete page.
+
+### How do I create a new subcommand?
+
+### How do I add a new tool?
+
+### How do I add a new config setting?
+
+There are currently two groups of settings: `General` and `Shortcuts`.
+The necessary steps are usually the following:
+
+- Determine a name for the setting - for a general setting, it must be a valid
+ C++ identifier, for a shortcut it must be the name of a tool type from TODO.
+- Add a getter and a setter for the setting in [`ConfigHandler`][ConfigHandler].
+ For most settings you should use the
+ [`CONFIG_GETTER_SETTER`][CONFIG_GETTER_SETTER] macro. If your setting is
+ unusual enough you may need to use [`CONFIG_GETTER`][CONFIG_GETTER] or
+ [`CONFIG_SETTER`][CONFIG_SETTER] individually, or even need to create the
+ methods manually.
+- If you need custom validation or conversion for the value, you must create a
+ subclass of [`ValueHandler`][ValueHandler]. Otherwise you can use one of the
+ existing ones in [valuehandler.h][].
+- If you want to make your setting available in the configuration GUI (usually
+ you do), you should add the appropriate widgets into one of the tabs of
+ [`ConfigWindow`][ConfigWindow]. If your setting doesn't fit into any of the
+ existing tabs, you can add a new one, but please discuss it with us first.
+
+To get a deeper understanding of how the configuration works, please see
+[Configuration][config].
+
+### How do I add a new export action? (@borgmanJeremy @mehrad This is my preferred terminology over final action, need consensus)
+
+[config]: index.md#configuration
+[confighandler.h]: flameshot/confighandler_8h
+[confighandler.cpp]: flameshot/confighandler_8cpp
+[valuehandler.h]: flameshot/valuehandler_8h
+[ValueHandler]: flameshot/classValueHandler
+[ConfigHandler]: flameshot/classConfigHandler
+[ConfigWindow]: flameshot/classConfigWindow
+[CONFIG_GETTER_SETTER]: flameshot/confighandler_8h/#define-config_getter_setter
+[CONFIG_GETTER]: flameshot/confighandler_8h/#define-config_getter
+[CONFIG_SETTER]: flameshot/confighandler_8h/#define-config_setter
diff --git a/docs/dev/src/index.md b/docs/dev/src/index.md
new file mode 100644
index 00000000..0a3aa03f
--- /dev/null
+++ b/docs/dev/src/index.md
@@ -0,0 +1,127 @@
+# Flameshot developer docs
+
+Thank you for your interest in developing flameshot. This developer
+documentation (hopefully) has an intuitive structure. It tries to describe what
+code is run when a user performs an action in Flameshot.
+
+!!! important
+
+ **Please read this entire page. It will make your life a whole lot easier when
+ contributing to Flameshot. If you know exactly what you want to work on, you
+ should look at [FAQ](./faq) **
+
+## Project structure
+
+Flameshot is built on C++/Qt5 with CMake as its build system. The source code is
+located under `src/`. The entrypoint is `src/main.cpp`.
+
+### `main.cpp`
+
+Flameshot provides both a GUI and a CLI (the latter currently works only on
+Linux and macOS).
+
+### Build system
+
+The main cmake file is `CMakeLists.txt` in the project root. It `include`s some
+files from the `cmake/` directory as well. These files together control some
+more general aspects of the build process, like project information, packaging,
+caching etc.
+
+There is also the file `src/CMakeLists.txt`. It mostly defines how the source
+files are compiled into targets and how the external libraries are linked. It
+does some other stuff too. Currently, there isn't a clear separation of concerns
+between `CMakeLists.txt` and `src/CMakeLists.txt`. In the future we should
+refactor these files to make it more clear why each of them exists.
+
+## What happens when I launch flameshot?
+There are two ways to launch flameshot: daemon mode and single-action mode. In
+both modes, an instance of [`Flameshot`][Flameshot] is created via
+[`Flameshot::start()`][Flameshot::start]. [`Flameshot`][Flameshot] provides the
+high level API for interacting with flameshot; and its methods mimic the CLI
+subcommands a great deal. This object is a singleton, so it can only be created
+once. It is accessed as [`Flameshot::instance()`][Flameshot::instance].
+
+!!! note
+
+ On Windows, only daemon mode is currently supported.
+
+### Single-action mode (via command line interface)
+Single-action mode (also called one-off mode) is triggered when flameshot is
+launched with a command line argument - for example as `flameshot gui`. As its
+name implies, it performs a single action, such as "take a screenshot
+interactively by opening a GUI" or "take a screenshot of the entire screen",
+etc. Afterwards, Flameshot quits.
+
+### Daemon mode
+This mode is triggered when the `flameshot` command is launched. In this mode, a
+flameshot process is started in the background. A system tray is displayed if
+the user hasn't disabled it in the config. In addition to [`Flameshot::start()`][Flameshot::start],
+if the current process is the daemon, it also calls [`FlameshotDaemon::start()`][FlameshotDaemon::start]
+during initialization.
+
+The daemon has the following purposes:
+
+- Run in the background, wait for the user to press a hotkey, and perform
+ corresponding action.
+
+ This is true for **Windows** and **macOS**, but not for **Linux**. On Linux, hotkeys
+ are meant to be handled by the desktop environment or equivalent.
+
+- Provide a system tray that the user can click to initiate actions via context
+ menu
+
+- Periodically check for updates and notify the user
+
+- Act as a host for persistent phenomena. Example: On X11 (linux), when a program
+ inserts content into the clipboard, it must keep running so the content
+ persists in the clipboard.
+
+!!! note
+
+ All of the above are user-configurable.
+
+#### `FlameshotDaemon`
+The class [`FlameshotDaemon`][FlameshotDaemon] handles all communication with
+the daemon. The class provides public static methods that are designed so that
+the caller does not need to know if the current process is a flameshot daemon or
+a single-action invocation of Flameshot. If the current process is the daemon,
+then the static methods of [`FlameshotDaemon`][FlameshotDaemon] will call the
+corresponding instance methods of the singleton. If not, the current process
+will communicate with the daemon process via D-Bus. Then, within the daemon
+process, those D-Bus calls will be translated into
+[`FlameshotDaemon`][FlameshotDaemon] instance method calls.
+
+## Configuration
+The configuration is handled by [`ConfigHandler`][ConfigHandler]. It is
+decoupled from any user interface, so it serves the configuration for both the
+GUI and CLI. All configuration settings recognized by the config files are
+defined as getters in this class. There are also setters for each setting, named
+as per the usual convention. For example, the setting `savePath` has a getter
+named `savePath` and a setter named `setSavePath`. Before working on a new
+config setting for flameshot, please read [this FAQ
+entry][faq:add-config-setting].
+
+### Interesting notes
+
+- [`ConfigHandler`][ConfigHandler] is based on `QSettings`
+- The configuration uses the `ini` format
+- The configuration is automatically reloaded when the config file changes
+
+## Conventions
+
+- Always use `&Class::signal` and `&Class::slot` instead of `SIGNAL(signal())`
+ and `SLOT(slot())`. This usually provides better code introspection and makes
+ refactoring easier and less error-prone.
+
+[Flameshot]: flameshot/classFlameshot
+[Flameshot::instance]: flameshot/classFlameshot#function-instance
+[Flameshot::start]: flameshot/classFlameshot#function-start
+[ConfigHandler]: flameshot/classConfigHandler
+[FlameshotDaemon]: flameshot/classFlameshotDaemon
+[FlameshotDaemon::start]: flameshot/classFlameshotDaemon#function-start
+[confighandler.h]: flameshot/confighandler_8h
+[confighandler.cpp]: flameshot/confighandler_8cpp
+
+[faq:add-config-setting]: faq/#how-do-i-add-a-new-config-setting
+
+[matrix-room]: https://matrix.to/#/#flameshot-org:matrix.org