diff --git a/meson.build b/meson.build
new file mode 100644
index 0000000..3efced1
--- /dev/null
+++ b/meson.build
@@ -0,0 +1,24 @@
+project(
+ 'wf-simple-osk',
+ 'c',
+ 'cpp',
+ version: '0.1',
+ license: 'MIT',
+ meson_version: '>=0.43.0',
+ default_options: [
+ 'cpp_std=c++14',
+ 'c_std=c11',
+ 'warning_level=2',
+ 'werror=false',
+ ],
+)
+
+gtkmm = dependency('gtkmm-3.0')
+wayland_client = dependency('wayland-client')
+wayland_protos = dependency('wayland-protocols')
+
+add_project_link_arguments(['-rdynamic'], language:'cpp')
+add_project_arguments(['-Wno-unused-parameter'], language: 'cpp')
+
+subdir('proto')
+subdir('src')
diff --git a/proto/meson.build b/proto/meson.build
new file mode 100644
index 0000000..a05e26e
--- /dev/null
+++ b/proto/meson.build
@@ -0,0 +1,37 @@
+wl_protocol_dir = wayland_protos.get_pkgconfig_variable('pkgdatadir')
+
+wayland_scanner = find_program('wayland-scanner')
+
+wayland_scanner_code = generator(
+ wayland_scanner,
+ output: '@BASENAME@-protocol.c',
+ arguments: ['private-code', '@INPUT@', '@OUTPUT@'],
+)
+
+wayland_scanner_client = generator(
+ wayland_scanner,
+ output: '@BASENAME@-client-protocol.h',
+ arguments: ['client-header', '@INPUT@', '@OUTPUT@'],
+)
+
+client_protocols = [
+ 'wayfire-shell.xml',
+ 'virtual-keyboard-unstable-v1.xml'
+]
+
+wl_protos_src = []
+wl_protos_headers = []
+
+foreach p : client_protocols
+ xml = join_paths(p)
+ wl_protos_headers += wayland_scanner_client.process(xml)
+ wl_protos_src += wayland_scanner_code.process(xml)
+endforeach
+
+lib_wl_protos = static_library('wl_protos', wl_protos_src + wl_protos_headers,
+ dependencies: [wayland_client]) # for the include directory
+
+wf_protos = declare_dependency(
+ link_with: lib_wl_protos,
+ sources: wl_protos_headers,
+)
diff --git a/proto/virtual-keyboard-unstable-v1.xml b/proto/virtual-keyboard-unstable-v1.xml
new file mode 100644
index 0000000..5095c91
--- /dev/null
+++ b/proto/virtual-keyboard-unstable-v1.xml
@@ -0,0 +1,113 @@
+
+
+
+ Copyright © 2008-2011 Kristian Høgsberg
+ Copyright © 2010-2013 Intel Corporation
+ Copyright © 2012-2013 Collabora, Ltd.
+ Copyright © 2018 Purism SPC
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice (including the next
+ paragraph) shall be included in all copies or substantial portions of the
+ Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+
+
+
+
+ The virtual keyboard provides an application with requests which emulate
+ the behaviour of a physical keyboard.
+
+ This interface can be used by clients on its own to provide raw input
+ events, or it can accompany the input method protocol.
+
+
+
+
+ Provide a file descriptor to the compositor which can be
+ memory-mapped to provide a keyboard mapping description.
+
+ Format carries a value from the keymap_format enumeration.
+
+
+
+
+
+
+
+
+
+
+
+
+ A key was pressed or released.
+ The time argument is a timestamp with millisecond granularity, with an
+ undefined base. All requests regarding a single object must share the
+ same clock.
+
+ Keymap must be set before issuing this request.
+
+ State carries a value from the key_state enumeration.
+
+
+
+
+
+
+
+
+ Notifies the compositor that the modifier and/or group state has
+ changed, and it should update state.
+
+ The client should use wl_keyboard.modifiers event to synchronize its
+ internal state with seat state.
+
+ Keymap must be set before issuing this request.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ A virtual keyboard manager allows an application to provide keyboard
+ input events as if they came from a physical keyboard.
+
+
+
+
+
+
+
+
+ Creates a new virtual keyboard associated to a seat.
+
+ If the compositor enables a keyboard to perform arbitrary actions, it
+ should present an error when an untrusted client requests a new
+ keyboard.
+
+
+
+
+
+
diff --git a/proto/wayfire-shell.xml b/proto/wayfire-shell.xml
new file mode 100644
index 0000000..d1d4f82
--- /dev/null
+++ b/proto/wayfire-shell.xml
@@ -0,0 +1,168 @@
+
+
+
+ The purpose of this protocol is to enable the creation of different
+ desktop-interface windows like panels, backgrounds, docks,
+ lockscreens, etc. It also aims to allow the creation of full-blown
+ DEs using Wayfire.
+
+ Note that in contrast to some other efforts to create a similar
+ protocol, such as wlr-layer-shell, this isn't a new "shell" for
+ giving a role to wl_surfaces. This protocol can be used with any
+ type of toplevel surface (xdg_toplevel, xdg_toplevel_v6, etc.)
+ to give them to the corresponding WM role.
+
+
+
+
+
+
+
+
+
+
+ Assign the given role to the given surface and add it to the
+ given output. A client can specify a null output, in which case
+ the compositor will assign the surface to the focused output,
+ if any such output.
+
+ The role cannot be changed later, and neither can the surface be
+ moved to a different output, except by the compositor.
+
+
+
+
+
+
+
+
+
+
+
+ Represents a single output.
+ Each output is managed independently from the others.
+
+
+
+ Panels are always rendered on top, even above fullscreen windows.
+ If autohide is 1, the event indicates that the panels should hide
+ itself, by for example unmapping or sliding outside of the output.
+ If autohide is 0, this means that the reason for the last request
+ with autohide == 1 is no longer valid, i.e the panels can show
+ themselves.
+
+ The output_hide_panels can be called multiple times with
+ autohide = 1, and the panel should show itself only when
+ it has received a matching number of events with autohide = 0
+
+
+
+
+
+
+
+ Request the compositor to not render the output, so
+ the output usually is cleared to black color.
+ To enable output rendering again, call inhibit_output_done
+
+
+
+
+
+ Stop inhibiting the output. This must be called as many times
+ as inhibit_output was called to actually uninhibit rendering.
+
+ The inhibit/inhibit_done requests can be called multiple times,
+ even from different apps, so don't assume that a call to
+ inhibit_done would always mean actually starting the rendering process.
+
+
+
+
+
+
+ Represents a surface with a specific WM role.
+ It belongs to the output which it was created for.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Sets the position on the screen where the compositor should
+ position the view. Can be reset by specifying anchor 0. If not
+ set, the compositor will assume manual positioning via the
+ configure request.
+
+ If one anchor edge is provided, the wm surface is "stuck" to
+ that edge.
+ If two anchor edges are provided, the wm surface is considered
+ anchored to the corner of the screen between them.
+
+ Any other anchor edge configuration is considered invalid.
+
+
+
+
+
+
+ Set the offset from the anchored edges to the wm surface. This
+ is an alternative to the configure request. Using both will
+ result in undefined results.
+
+ Margin has effect only for edges the wm surface is anchored to.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Sets how the wm surface will interact with keyboard focus.
+ Setting no_focus means that the surface will never receive
+ keyboard focus, click_to_focus means normal focus semantics (i.e
+ what you expect from "normal" windows), and exclusive focus means
+ that no other window can get keyboard focus.
+
+
+
+
+
+
+ Request the compositor to reserve the given amount of pixels
+ for the wm surface(like STRUTS in X11). This has effect only
+ if the surface is anchored to a single edge. Margin doesn't
+ affect exclusive zone in any way.
+
+
+
+
+
diff --git a/src/keymap.tpp b/src/keymap.tpp
new file mode 100644
index 0000000..d97c6ca
--- /dev/null
+++ b/src/keymap.tpp
@@ -0,0 +1,1462 @@
+static const char keymap[] = "xkb_keymap {\
+xkb_keycodes \"(unnamed)\" {\
+ minimum = 8;\
+ maximum = 255;\
+ = 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;\
+ = 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;\
+ = 217;\
+ = 218;\
+ = 219;\
+ = 220;\
+ = 221;\
+ = 222;\
+ = 223;\
+ = 224;\
+ = 225;\
+ = 226;\
+ = 227;\
+ = 228;\
+ = 229;\
+ = 230;\
+ = 231;\
+ = 232;\
+ = 233;\
+ = 234;\
+ = 235;\
+ = 236;\
+ = 237;\
+ = 238;\
+ = 239;\
+ = 240;\
+ = 241;\
+ = 242;\
+ = 243;\
+ = 244;\
+ = 245;\
+ = 246;\
+ = 247;\
+ = 248;\
+ = 249;\
+ = 250;\
+ = 251;\
+ = 252;\
+ = 253;\
+ = 254;\
+ = 255;\
+ indicator 1 = \"Caps Lock\";\
+ indicator 2 = \"Num Lock\";\
+ indicator 3 = \"Scroll Lock\";\
+ indicator 4 = \"Compose\";\
+ indicator 5 = \"Kana\";\
+ indicator 6 = \"Sleep\";\
+ indicator 7 = \"Suspend\";\
+ indicator 8 = \"Mute\";\
+ indicator 9 = \"Misc\";\
+ indicator 10 = \"Mail\";\
+ indicator 11 = \"Charging\";\
+ indicator 12 = \"Shift Lock\";\
+ indicator 13 = \"Group 2\";\
+ indicator 14 = \"Mouse Keys\";\
+ alias = ;\
+ alias