From c00955ce03d10597d31b089f4abc0a2bf9acb8d2 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 28 Sep 2019 22:31:38 +0200 Subject: [PATCH 1/8] key-file: Add support for non ini style config files In some cases me way want to parse key=value style config files from outside of plymouth which lack ini style groups. This commit adds a new ply_key_file_load_groupless_file function which supports loading such files. When a file is loaded this way, NULL must be passed as group_name for subsequent ply_key_file_get_* calls. Signed-off-by: Hans de Goede --- src/libply/ply-key-file.c | 20 ++++++++++++++++++++ src/libply/ply-key-file.h | 5 +++++ 2 files changed, 25 insertions(+) diff --git a/src/libply/ply-key-file.c b/src/libply/ply-key-file.c index 7c0dc44d..de9eb252 100644 --- a/src/libply/ply-key-file.c +++ b/src/libply/ply-key-file.c @@ -60,6 +60,7 @@ struct _ply_key_file FILE *fp; ply_hashtable_t *groups; + ply_key_file_group_t *groupless_group; }; typedef struct @@ -152,6 +153,8 @@ ply_key_file_free (ply_key_file_t *key_file) ply_key_file_free_group, NULL); + if (key_file->groupless_group) + ply_key_file_free_group (NULL, key_file->groupless_group, NULL); ply_hashtable_free (key_file->groups); free (key_file->filename); @@ -303,6 +306,9 @@ static ply_key_file_group_t * ply_key_file_find_group (ply_key_file_t *key_file, const char *group_name) { + if (!group_name) + return key_file->groupless_group; + return ply_hashtable_lookup (key_file->groups, (void *) group_name); } @@ -463,4 +469,18 @@ ply_key_file_foreach_entry (ply_key_file_t *key_file, &func_data); } +bool +ply_key_file_load_groupless_file (ply_key_file_t *key_file) +{ + if (!ply_key_file_open_file (key_file)) + return false; + + key_file->groupless_group = + ply_key_file_load_group (key_file, "NONE"); + + ply_key_file_close_file (key_file); + + return key_file->groupless_group != NULL; +} + /* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */ diff --git a/src/libply/ply-key-file.h b/src/libply/ply-key-file.h index 31f3fd1f..668b8db9 100644 --- a/src/libply/ply-key-file.h +++ b/src/libply/ply-key-file.h @@ -36,6 +36,11 @@ typedef void (ply_key_file_foreach_func_t) (const char *group_name, ply_key_file_t *ply_key_file_new (const char *filename); void ply_key_file_free (ply_key_file_t *key_file); bool ply_key_file_load (ply_key_file_t *key_file); +/* For loading key=value pair files, which do not have ini style groups. + * When a file is loaded this way, NULL must be passed as group_name + * for subsequent ply_key_file_get_* calls. + */ +bool ply_key_file_load_groupless_file (ply_key_file_t *key_file); bool ply_key_file_has_key (ply_key_file_t *key_file, const char *group_name, const char *key); From f91e78f446701b729d359cde61171d0dc340fb80 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 30 Sep 2019 11:01:34 +0200 Subject: [PATCH 2/8] terminal: add ply_terminal_get_keymap function Add a helper function to get the keymap from the terminal. Signed-off-by: Hans de Goede --- src/libply-splash-core/ply-terminal.c | 41 +++++++++++++++++++++++++++ src/libply-splash-core/ply-terminal.h | 1 + 2 files changed, 42 insertions(+) diff --git a/src/libply-splash-core/ply-terminal.c b/src/libply-splash-core/ply-terminal.c index 2a19579d..2b566863 100644 --- a/src/libply-splash-core/ply-terminal.c +++ b/src/libply-splash-core/ply-terminal.c @@ -43,6 +43,7 @@ #include "ply-buffer.h" #include "ply-event-loop.h" +#include "ply-key-file.h" #include "ply-list.h" #include "ply-logger.h" #include "ply-utils.h" @@ -79,6 +80,7 @@ struct _ply_terminal struct termios original_locked_term_attributes; char *name; + char *keymap; int fd; int vt_number; int initial_vt_number; @@ -115,6 +117,35 @@ typedef enum static ply_terminal_open_result_t ply_terminal_open_device (ply_terminal_t *terminal); +static char * +ply_terminal_parse_keymap_conf (ply_terminal_t *terminal) +{ + ply_key_file_t *vconsole_conf; + char *keymap, *old_keymap; + + keymap = ply_kernel_command_line_get_key_value ("rd.vconsole.keymap="); + if (keymap) + return keymap; + + keymap = ply_kernel_command_line_get_key_value ("vconsole.keymap="); + if (keymap) + return keymap; + + vconsole_conf = ply_key_file_new ("/etc/vconsole.conf"); + if (ply_key_file_load_groupless_file (vconsole_conf)) + keymap = ply_key_file_get_value (vconsole_conf, NULL, "KEYMAP"); + ply_key_file_free (vconsole_conf); + + /* The keymap name in vconsole.conf might be quoted, strip these */ + if (keymap && keymap[0] == '"' && keymap[strlen (keymap) - 1] == '"') { + old_keymap = keymap; + keymap = strndup(keymap + 1, strlen (keymap) - 2); + free (old_keymap); + } + + return keymap; +} + ply_terminal_t * ply_terminal_new (const char *device_name) { @@ -136,6 +167,9 @@ ply_terminal_new (const char *device_name) terminal->fd = -1; terminal->vt_number = -1; terminal->initial_vt_number = -1; + terminal->keymap = ply_terminal_parse_keymap_conf (terminal); + if (terminal->keymap) + ply_trace ("terminal %s keymap: %s", terminal->name, terminal->keymap); return terminal; } @@ -845,6 +879,7 @@ ply_terminal_free (ply_terminal_t *terminal) free_vt_change_closures (terminal); free_input_closures (terminal); + free (terminal->keymap); free (terminal->name); free (terminal); } @@ -855,6 +890,12 @@ ply_terminal_get_name (ply_terminal_t *terminal) return terminal->name; } +const char * +ply_terminal_get_keymap (ply_terminal_t *terminal) +{ + return terminal->keymap; +} + bool ply_terminal_get_capslock_state (ply_terminal_t *terminal) { diff --git a/src/libply-splash-core/ply-terminal.h b/src/libply-splash-core/ply-terminal.h index 3ca1dc0c..4ca4c81c 100644 --- a/src/libply-splash-core/ply-terminal.h +++ b/src/libply-splash-core/ply-terminal.h @@ -93,6 +93,7 @@ void ply_terminal_ignore_mode_changes (ply_terminal_t *terminal, bool should_ignore); const char *ply_terminal_get_name (ply_terminal_t *terminal); +const char *ply_terminal_get_keymap (ply_terminal_t *terminal); bool ply_terminal_get_capslock_state (ply_terminal_t *terminal); int ply_terminal_get_vt_number (ply_terminal_t *terminal); bool ply_terminal_activate_vt (ply_terminal_t *terminal); From 9306edbc17ac4144ff9289679c7888cf47f0e6a4 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 30 Sep 2019 14:06:51 +0200 Subject: [PATCH 3/8] renderer: Add ply_renderer_get_keymap function Add a function to get the keymap from a renderer and implement this for the drm and frame-buffer renderers. Signed-off-by: Hans de Goede --- src/libply-splash-core/ply-renderer-plugin.h | 1 + src/libply-splash-core/ply-renderer.c | 9 +++++++++ src/libply-splash-core/ply-renderer.h | 1 + src/plugins/renderers/drm/plugin.c | 10 ++++++++++ src/plugins/renderers/frame-buffer/plugin.c | 10 ++++++++++ 5 files changed, 31 insertions(+) diff --git a/src/libply-splash-core/ply-renderer-plugin.h b/src/libply-splash-core/ply-renderer-plugin.h index b0c3e7d1..367d922f 100644 --- a/src/libply-splash-core/ply-renderer-plugin.h +++ b/src/libply-splash-core/ply-renderer-plugin.h @@ -75,6 +75,7 @@ typedef struct ply_pixel_buffer_rotation_t *rotation, int *scale); bool (*get_capslock_state)(ply_renderer_backend_t *backend); + const char * (*get_keymap)(ply_renderer_backend_t *backend); } ply_renderer_plugin_interface_t; #endif /* PLY_RENDERER_PLUGIN_H */ diff --git a/src/libply-splash-core/ply-renderer.c b/src/libply-splash-core/ply-renderer.c index c2210912..3462bfe2 100644 --- a/src/libply-splash-core/ply-renderer.c +++ b/src/libply-splash-core/ply-renderer.c @@ -443,4 +443,13 @@ ply_renderer_get_capslock_state (ply_renderer_t *renderer) return renderer->plugin_interface->get_capslock_state (renderer->backend); } +const char * +ply_renderer_get_keymap (ply_renderer_t *renderer) +{ + if (!renderer->plugin_interface->get_keymap) + return NULL; + + return renderer->plugin_interface->get_keymap (renderer->backend); +} + /* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */ diff --git a/src/libply-splash-core/ply-renderer.h b/src/libply-splash-core/ply-renderer.h index e4dbdb1c..ed2db34c 100644 --- a/src/libply-splash-core/ply-renderer.h +++ b/src/libply-splash-core/ply-renderer.h @@ -86,6 +86,7 @@ bool ply_renderer_get_panel_properties (ply_renderer_t *renderer, int *scale); bool ply_renderer_get_capslock_state (ply_renderer_t *renderer); +const char *ply_renderer_get_keymap (ply_renderer_t *renderer); #endif #endif /* PLY_RENDERER_H */ diff --git a/src/plugins/renderers/drm/plugin.c b/src/plugins/renderers/drm/plugin.c index dc1e72c8..090be788 100644 --- a/src/plugins/renderers/drm/plugin.c +++ b/src/plugins/renderers/drm/plugin.c @@ -1805,6 +1805,15 @@ get_capslock_state (ply_renderer_backend_t *backend) return ply_terminal_get_capslock_state (backend->terminal); } +static const char * +get_keymap (ply_renderer_backend_t *backend) +{ + if (!backend->terminal) + return NULL; + + return ply_terminal_get_keymap (backend->terminal); +} + ply_renderer_plugin_interface_t * ply_renderer_backend_get_interface (void) { @@ -1830,6 +1839,7 @@ ply_renderer_backend_get_interface (void) .get_device_name = get_device_name, .get_panel_properties = get_panel_properties, .get_capslock_state = get_capslock_state, + .get_keymap = get_keymap, }; return &plugin_interface; diff --git a/src/plugins/renderers/frame-buffer/plugin.c b/src/plugins/renderers/frame-buffer/plugin.c index 68c858e8..87e486a7 100644 --- a/src/plugins/renderers/frame-buffer/plugin.c +++ b/src/plugins/renderers/frame-buffer/plugin.c @@ -727,6 +727,15 @@ get_capslock_state (ply_renderer_backend_t *backend) return ply_terminal_get_capslock_state (backend->terminal); } +static const char * +get_keymap (ply_renderer_backend_t *backend) +{ + if (!backend->terminal) + return NULL; + + return ply_terminal_get_keymap (backend->terminal); +} + ply_renderer_plugin_interface_t * ply_renderer_backend_get_interface (void) { @@ -750,6 +759,7 @@ ply_renderer_backend_get_interface (void) .close_input_source = close_input_source, .get_device_name = get_device_name, .get_capslock_state = get_capslock_state, + .get_keymap = get_keymap, }; return &plugin_interface; From b26a956a11610d45c133f068f67be6d4e23b05bc Mon Sep 17 00:00:00 2001 From: Alberto Ruiz Date: Mon, 30 Sep 2019 16:58:55 +0200 Subject: [PATCH 4/8] scripts: Add keymap-render.py script Add a script for generating a png with the short-name (ignoring variants) of all keymaps listed by "localectl list-keymaps" pre-generated. This scripts also generates a ply-keymap-metadata.h file with info on which pre-generated keymap name is where in the png. This will be used in a follow-up commit to add support for a new keyboard-keymap-icon control to libply-splash-graphics. Note that this commit does not add the generated keymap-render.png file, this file will be added to each themes image-dir separately as the color of the pre-generated text may differ per theme. Changes by Hans de Goede: - Change generated metadata into a C header file - Drop drawing of curved corners, we just want the text - Add special handling for dvorak Signed-off-by: Hans de Goede --- scripts/keymap-render.py | 99 +++++++++++++ .../ply-keymap-metadata.h | 138 ++++++++++++++++++ 2 files changed, 237 insertions(+) create mode 100755 scripts/keymap-render.py create mode 100644 src/libply-splash-graphics/ply-keymap-metadata.h diff --git a/scripts/keymap-render.py b/scripts/keymap-render.py new file mode 100755 index 00000000..495a993b --- /dev/null +++ b/scripts/keymap-render.py @@ -0,0 +1,99 @@ +#!/usr/bin/python3 +# coding: utf-8 +import cairo +import subprocess +import math + + +FONT_SIZE = 30 +MARGIN = int(FONT_SIZE / 3) + +def get_keymaps(): + keymaps = subprocess.check_output(["localectl", "list-keymaps"]).decode("utf-8").strip().split() + + # Note when changing this you MUST keep ply_keymap_normalize_keymap() + # from src/libply-splash-graphics/ply-keymap-icon.c in sync + def normalize_keymaps(keymap): + parts = keymap.replace("_", "-").replace(".", "-").split("-") + + # Special case for dvorak, E.g. when mixing "us" and "us-dvorak" + # on machines returning "us" for both is not useful. + # Presumably users using dvorak now which variant they use + # so we just describe all dvorak layouts as "dvorak". + if "dvorak" in keymap: + return "dvorak" + + # mac / sun keymaps are prefixes with mac / sun / sun[4-6]t + for prefix in ["mac", "sun" ]: + if keymap.startswith(prefix) and len(parts) > 1: + return parts[1] + + return parts[0] + + keymaps = list(map(normalize_keymaps ,keymaps)) + + #Remove duplicates + ret = [] + for k in keymaps: + if k not in ret: + ret.append(k) + return ret + + +# Calculate size +sf = cairo.ImageSurface(cairo.FORMAT_ARGB32, 1, 1) +ct = cairo.Context(sf) +ct.select_font_face("Cantarell", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_BOLD) +ct.set_font_size(FONT_SIZE) + +max_height = 0.0 +total_width = 0.0 +for i in get_keymaps(): + extents = ct.text_extents(i) + h = extents.height + if h > max_height: + max_height = h + total_width += extents.width + total_width += MARGIN * 2 +ascent, descent, _h, _max_x, max_y = ct.font_extents() + +# Create image +sf = cairo.ImageSurface(cairo.FORMAT_ARGB32, int(total_width), int(max_height + MARGIN * 2)) +ct = cairo.Context(sf) +ct.save() +ct.set_source_rgba(0, 0, 0, 0) +ct.set_operator (cairo.OPERATOR_SOURCE) +ct.paint() +ct.restore() +ct.select_font_face("Cantarell", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_BOLD) +ct.set_font_size(FONT_SIZE) +ct.set_source_rgba(0.9, 0.9, 0.9, 1.0) + +ct.move_to(MARGIN, MARGIN + max_height - descent) +current_x, current_y = (MARGIN, MARGIN + max_height - descent) +metadata = [] +for km in get_keymaps(): + extents = ct.text_extents(km) + ct.show_text(km) + metadata.append((km, current_x, extents.width + MARGIN * 2)) + current_x += extents.width + (MARGIN * 2) + ct.move_to(current_x, current_y) + +sf.write_to_png("keymap-render.png") + +print("/* This file is autogenerated by running:") +print(" * scripts/keymap-render.py > src/libply-splash-graphics/ply-keymap-metadata.h") +print(" */") +print("struct ply_keymap_metadata {") +print(" const char *name;") +print(" int offset;") +print(" int width;") +print("};") +print("") +print("static struct ply_keymap_metadata ply_keymap_metadata[] = {") + +for i in metadata: + print((" { \"%s\", %d, %d }," % (i[0],i[1],i[2]))) + +print(" { NULL, } /* End of array marker */ ") +print("};") diff --git a/src/libply-splash-graphics/ply-keymap-metadata.h b/src/libply-splash-graphics/ply-keymap-metadata.h new file mode 100644 index 00000000..854c39d1 --- /dev/null +++ b/src/libply-splash-graphics/ply-keymap-metadata.h @@ -0,0 +1,138 @@ +/* This file is autogenerated by running: + * scripts/keymap-render.py > src/libply-splash-graphics/ply-keymap-metadata.h + */ +struct ply_keymap_metadata { + const char *name; + int offset; + int width; +}; + +static struct ply_keymap_metadata ply_keymap_metadata[] = { + { "dvorak", 10, 113 }, + { "al", 123, 44 }, + { "amiga", 167, 101 }, + { "applkey", 268, 126 }, + { "at", 394, 46 }, + { "atari", 440, 81 }, + { "az", 521, 49 }, + { "azerty", 570, 104 }, + { "ba", 674, 49 }, + { "backspace", 723, 157 }, + { "bashkir", 880, 119 }, + { "be", 999, 50 }, + { "bg", 1049, 51 }, + { "br", 1100, 48 }, + { "by", 1148, 51 }, + { "bywin", 1199, 98 }, + { "ca", 1297, 47 }, + { "carpalx", 1344, 118 }, + { "cf", 1462, 45 }, + { "ch", 1507, 49 }, + { "cm", 1556, 59 }, + { "cn", 1615, 49 }, + { "croat", 1664, 89 }, + { "ctrl", 1753, 65 }, + { "cz", 1818, 47 }, + { "de", 1865, 51 }, + { "defkeymap", 1916, 170 }, + { "dk", 2086, 53 }, + { "dz", 2139, 50 }, + { "ee", 2189, 50 }, + { "emacs", 2239, 106 }, + { "emacs2", 2345, 122 }, + { "en", 2467, 51 }, + { "epo", 2518, 68 }, + { "es", 2586, 49 }, + { "et", 2635, 46 }, + { "euro", 2681, 80 }, + { "euro1", 2761, 95 }, + { "euro2", 2856, 97 }, + { "fi", 2953, 38 }, + { "fo", 2991, 47 }, + { "fr", 3038, 44 }, + { "gb", 3082, 53 }, + { "ge", 3135, 51 }, + { "gh", 3186, 52 }, + { "gr", 3238, 49 }, + { "hr", 3287, 48 }, + { "hu", 3335, 50 }, + { "hu101", 3385, 99 }, + { "ie", 3484, 42 }, + { "il", 3526, 36 }, + { "in", 3562, 43 }, + { "iq", 3605, 43 }, + { "ir", 3648, 40 }, + { "is", 3688, 41 }, + { "it", 3729, 38 }, + { "it2", 3767, 54 }, + { "jp", 3821, 46 }, + { "jp106", 3867, 96 }, + { "kazakh", 3963, 112 }, + { "ke", 4075, 49 }, + { "keypad", 4124, 114 }, + { "kr", 4238, 47 }, + { "ky", 4285, 50 }, + { "kyrgyz", 4335, 107 }, + { "kz", 4442, 48 }, + { "la", 4490, 42 }, + { "latam", 4532, 97 }, + { "lk", 4629, 45 }, + { "lt", 4674, 39 }, + { "lv", 4713, 44 }, + { "ma", 4757, 59 }, + { "pl", 4816, 44 }, + { "pt", 4860, 46 }, + { "se", 4906, 48 }, + { "template", 4954, 142 }, + { "uk", 5096, 53 }, + { "us", 5149, 50 }, + { "md", 5199, 61 }, + { "me", 5260, 60 }, + { "mk", 5320, 62 }, + { "mk0", 5382, 79 }, + { "ml", 5461, 54 }, + { "mm", 5515, 71 }, + { "mt", 5586, 56 }, + { "ng", 5642, 51 }, + { "nl", 5693, 44 }, + { "nl2", 5737, 60 }, + { "no", 5797, 51 }, + { "pc110", 5848, 95 }, + { "ph", 5943, 51 }, + { "pl1", 5994, 58 }, + { "pl2", 6052, 60 }, + { "pl3", 6112, 60 }, + { "pl4", 6172, 62 }, + { "ro", 6234, 46 }, + { "rs", 6280, 44 }, + { "ru", 6324, 45 }, + { "ru1", 6369, 61 }, + { "ru2", 6430, 63 }, + { "ru3", 6493, 63 }, + { "ru4", 6556, 65 }, + { "ruwin", 6621, 95 }, + { "sg", 6716, 49 }, + { "si", 6765, 40 }, + { "sk", 6805, 50 }, + { "slovene", 6855, 122 }, + { "sr", 6977, 46 }, + { "sunkeymap", 7023, 174 }, + { "sv", 7197, 49 }, + { "sy", 7246, 49 }, + { "tj", 7295, 38 }, + { "tm", 7333, 57 }, + { "tr", 7390, 44 }, + { "tralt", 7434, 79 }, + { "trf", 7513, 55 }, + { "trq", 7568, 59 }, + { "ttwin", 7627, 90 }, + { "tw", 7717, 56 }, + { "ua", 7773, 50 }, + { "unicode", 7823, 124 }, + { "uz", 7947, 50 }, + { "vn", 7997, 51 }, + { "wangbe", 8048, 126 }, + { "wangbe2", 8174, 143 }, + { "windowkeys", 8317, 188 }, + { NULL, } /* End of array marker */ +}; From 665c2852aff716d4da8921339c5e458c699a33bc Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 30 Sep 2019 21:02:04 +0200 Subject: [PATCH 5/8] libply-splash-graphics: Add new keymap-icon control Add a new control which draws a keyboard-icon + a pre-rendered text describing the current layout/keymap (as reported by the renderer). Signed-off-by: Hans de Goede --- src/libply-splash-graphics/Makefile.am | 3 + src/libply-splash-graphics/ply-keymap-icon.c | 280 +++++++++++++++++++ src/libply-splash-graphics/ply-keymap-icon.h | 57 ++++ 3 files changed, 340 insertions(+) create mode 100644 src/libply-splash-graphics/ply-keymap-icon.c create mode 100644 src/libply-splash-graphics/ply-keymap-icon.h diff --git a/src/libply-splash-graphics/Makefile.am b/src/libply-splash-graphics/Makefile.am index 20edce67..2a5eec87 100644 --- a/src/libply-splash-graphics/Makefile.am +++ b/src/libply-splash-graphics/Makefile.am @@ -12,6 +12,8 @@ libply_splash_graphics_HEADERS = \ ply-capslock-icon.h \ ply-entry.h \ ply-image.h \ + ply-keymap-icon.h \ + ply-keymap-metadata.h \ ply-label.h \ ply-label-plugin.h \ ply-progress-animation.h \ @@ -34,6 +36,7 @@ libply_splash_graphics_la_SOURCES = \ ply-capslock-icon.c \ ply-entry.c \ ply-image.c \ + ply-keymap-icon.c \ ply-label.c \ ply-progress-animation.c \ ply-progress-bar.c \ diff --git a/src/libply-splash-graphics/ply-keymap-icon.c b/src/libply-splash-graphics/ply-keymap-icon.c new file mode 100644 index 00000000..f9ec614f --- /dev/null +++ b/src/libply-splash-graphics/ply-keymap-icon.c @@ -0,0 +1,280 @@ +/* keymap-icon - Shows a keyboard-icon + the current keymap as text, e.g. "us" + * + * Copyright (C) 2019 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written by: Hans de Goede + */ +#include "config.h" + +#include +#include +#include + +#include "ply-keymap-icon.h" +#include "ply-keymap-metadata.h" +#include "ply-pixel-buffer.h" +#include "ply-pixel-display.h" +#include "ply-logger.h" +#include "ply-image.h" +#include "ply-utils.h" + +#define SPACING 10 + +struct _ply_keymap_icon +{ + ply_pixel_display_t *display; + char *image_dir; + ply_pixel_buffer_t *icon_buffer; + ply_pixel_buffer_t *keymap_buffer; + int keymap_offset; + int keymap_width; + long x, y; + unsigned long width, height; + bool is_hidden; +}; + +/* The keymap name we got from the renderer may contain a variant, e.g. it may + * be "us-intl" while our pre-generated text only contains "us", the code below + * does the same keymap name simplification as the keymap-render.py script. + */ +static char * +ply_keymap_normalize_keymap (const char *keymap_with_variant) +{ + const char *prefix[] = { "sun", "mac", NULL }; + int i, length; + + /* Special case for dvorak layouts */ + if (strstr (keymap_with_variant, "dvorak")) + return strdup ("dvorak"); + + /* Check for and skip sun / mac prefixes */ + for (i = 0; prefix[i]; i++) { + if (strncmp (keymap_with_variant, prefix[i], strlen (prefix[i])) == 0) { + length = strcspn (keymap_with_variant, "_-."); + if (keymap_with_variant[length] != '\0') + keymap_with_variant += length + 1; + break; + } + } + + /* Remove the keymap-variant info after the base keymap name */ + length = strcspn (keymap_with_variant, "_-."); + return strndup (keymap_with_variant, length); +} + +static void +ply_keymap_icon_fill_keymap_info (ply_keymap_icon_t *keymap_icon) +{ + const char *keymap_with_variant; + ply_renderer_t *renderer; + char *keymap; + int i; + + keymap_icon->keymap_offset = -1; + + renderer = ply_pixel_display_get_renderer (keymap_icon->display); + keymap_with_variant = ply_renderer_get_keymap (renderer); + if (!keymap_with_variant) + return; + + keymap = ply_keymap_normalize_keymap (keymap_with_variant); + + for (i = 0; ply_keymap_metadata[i].name; i++) { + if (strcmp (ply_keymap_metadata[i].name, keymap) == 0) { + keymap_icon->keymap_offset = ply_keymap_metadata[i].offset; + keymap_icon->keymap_width = ply_keymap_metadata[i].width; + break; + } + } + + if (keymap_icon->keymap_offset == -1) + ply_trace("Error no pre-rendered text for '%s' keymap", keymap); + + free (keymap); +} + +ply_keymap_icon_t * +ply_keymap_icon_new (ply_pixel_display_t *display, + const char *image_dir) +{ + ply_keymap_icon_t *keymap_icon; + + keymap_icon = calloc (1, sizeof(ply_keymap_icon_t)); + keymap_icon->display = display; + keymap_icon->image_dir = strdup (image_dir); + keymap_icon->is_hidden = true; + + ply_keymap_icon_fill_keymap_info (keymap_icon); + + return keymap_icon; +} + +void +ply_keymap_icon_free (ply_keymap_icon_t *keymap_icon) +{ + if (keymap_icon == NULL) + return; + + if (!keymap_icon->is_hidden) + ply_keymap_icon_hide (keymap_icon); + + ply_pixel_buffer_free (keymap_icon->icon_buffer); + ply_pixel_buffer_free (keymap_icon->keymap_buffer); + + free (keymap_icon->image_dir); + free (keymap_icon); +} + +bool +ply_keymap_icon_load (ply_keymap_icon_t *keymap_icon) +{ + ply_image_t *keymap_image = NULL; + ply_image_t *icon_image; + char *filename; + bool success; + + /* Bail if we did not find the keymap metadata */ + if (keymap_icon->keymap_offset == -1) + return false; + + if (keymap_icon->icon_buffer) + return true; + + asprintf (&filename, "%s/keyboard.png", keymap_icon->image_dir); + icon_image = ply_image_new (filename); + success = ply_image_load (icon_image); + ply_trace("loading '%s': %s", filename, success ? "success" : "failed"); + free (filename); + + if (success) { + asprintf (&filename, "%s/keymap-render.png", keymap_icon->image_dir); + keymap_image = ply_image_new (filename); + success = ply_image_load (keymap_image); + ply_trace("loading '%s': %s", filename, success ? "success" : "failed"); + free (filename); + } + + if (!success) { + ply_image_free (keymap_image); + ply_image_free (icon_image); + return false; + } + + keymap_icon->icon_buffer = ply_image_convert_to_pixel_buffer (icon_image); + keymap_icon->keymap_buffer = ply_image_convert_to_pixel_buffer (keymap_image); + + keymap_icon->width = + ply_pixel_buffer_get_width (keymap_icon->icon_buffer) + + SPACING + keymap_icon->keymap_width; + keymap_icon->height = MAX( + ply_pixel_buffer_get_height (keymap_icon->icon_buffer), + ply_pixel_buffer_get_height (keymap_icon->keymap_buffer)); + + return true; +} + +bool +ply_keymap_icon_show (ply_keymap_icon_t *keymap_icon, + long x, + long y) +{ + if (!keymap_icon->icon_buffer) { + ply_trace ("keymap_icon not loaded, can not start"); + return false; + } + + keymap_icon->x = x; + keymap_icon->y = y; + keymap_icon->is_hidden = false; + + ply_pixel_display_draw_area (keymap_icon->display, + keymap_icon->x, keymap_icon->y, + keymap_icon->width, + keymap_icon->height); + return true; +} + +void +ply_keymap_icon_hide (ply_keymap_icon_t *keymap_icon) +{ + if (keymap_icon->is_hidden) + return; + + keymap_icon->is_hidden = true; + + ply_pixel_display_draw_area (keymap_icon->display, + keymap_icon->x, keymap_icon->y, + keymap_icon->width, + keymap_icon->height); +} + +void +ply_keymap_icon_draw_area (ply_keymap_icon_t *keymap_icon, + ply_pixel_buffer_t *buffer, + long x, + long y, + unsigned long width, + unsigned long height) +{ + ply_rectangle_t icon_area, keymap_area; + + if (keymap_icon->is_hidden) + return; + + /* Draw keyboard icon */ + ply_pixel_buffer_get_size (keymap_icon->icon_buffer, &icon_area); + icon_area.x = keymap_icon->x; + icon_area.y = keymap_icon->y + + (keymap_icon->height - icon_area.height) / 2; + + ply_pixel_buffer_fill_with_buffer (buffer, keymap_icon->icon_buffer, + icon_area.x, icon_area.y); + + /* Draw pre-rendered keyboard layout text */ + keymap_area.width = keymap_icon->keymap_width; + keymap_area.height = + ply_pixel_buffer_get_height (keymap_icon->keymap_buffer); + keymap_area.x = keymap_icon->x + icon_area.width + SPACING; + keymap_area.y = keymap_icon->y + + (keymap_icon->height - keymap_area.height) / 2; + + /* Draw keyboard layout text, shift the pre-rendered image to the left + * so that the text we want lines out at the place we want it and set + * the area we want to draw to as clip-area to only draw what we want. + */ + ply_pixel_buffer_fill_with_buffer_with_clip ( + buffer, + keymap_icon->keymap_buffer, + keymap_area.x - keymap_icon->keymap_offset, + keymap_area.y, + &keymap_area); +} + +unsigned long +ply_keymap_icon_get_width (ply_keymap_icon_t *keymap_icon) +{ + return keymap_icon->width; +} + +unsigned long +ply_keymap_icon_get_height (ply_keymap_icon_t *keymap_icon) +{ + return keymap_icon->height; +} + +/* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */ diff --git a/src/libply-splash-graphics/ply-keymap-icon.h b/src/libply-splash-graphics/ply-keymap-icon.h new file mode 100644 index 00000000..d46a5ded --- /dev/null +++ b/src/libply-splash-graphics/ply-keymap-icon.h @@ -0,0 +1,57 @@ +/* keymap-icon - Shows a keyboard-icon + the current keymap as text, e.g. "us" + * + * Copyright (C) 2019 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written by: Hans de Goede + */ +#ifndef KEYMAP_ICON_H +#define KEYMAP_ICON_H + +#include + +#include "ply-event-loop.h" +#include "ply-pixel-buffer.h" +#include "ply-pixel-display.h" +#include "ply-trigger.h" + +typedef struct _ply_keymap_icon ply_keymap_icon_t; + +#ifndef PLY_HIDE_FUNCTION_DECLARATIONS +ply_keymap_icon_t *ply_keymap_icon_new (ply_pixel_display_t *display, + const char *image_dir); +void ply_keymap_icon_free (ply_keymap_icon_t *keymap_icon); + +bool ply_keymap_icon_load (ply_keymap_icon_t *keymap_icon); +bool ply_keymap_icon_show (ply_keymap_icon_t *keymap_icon, + long x, + long y); +void ply_keymap_icon_hide (ply_keymap_icon_t *keymap_icon); + +void ply_keymap_icon_draw_area (ply_keymap_icon_t *keymap_icon, + ply_pixel_buffer_t *buffer, + long x, + long y, + unsigned long width, + unsigned long height); + +unsigned long ply_keymap_icon_get_width (ply_keymap_icon_t *keymap_icon); +unsigned long ply_keymap_icon_get_height (ply_keymap_icon_t *keymap_icon); +#endif + +#endif /* KEYMAP_ICON_H */ +/* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */ From 28cb15c61c0a4aa5726a88c2a797ffe1d1fea266 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 30 Sep 2019 21:20:33 +0200 Subject: [PATCH 6/8] capslock-icon: Draw the icon on show Mark the display area where the icon is as damaged on show to force it being drawn on show, in case capslock is on at show time. Signed-off-by: Hans de Goede --- .../ply-capslock-icon.c | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/libply-splash-graphics/ply-capslock-icon.c b/src/libply-splash-graphics/ply-capslock-icon.c index aa35c60f..7d19a187 100644 --- a/src/libply-splash-graphics/ply-capslock-icon.c +++ b/src/libply-splash-graphics/ply-capslock-icon.c @@ -95,6 +95,15 @@ ply_capslock_icon_update_state (ply_capslock_icon_t *capslock_icon) capslock_icon->is_on = ply_renderer_get_capslock_state (renderer); } +static void +ply_capslock_icon_draw (ply_capslock_icon_t *capslock_icon) +{ + ply_pixel_display_draw_area (capslock_icon->display, + capslock_icon->x, capslock_icon->y, + capslock_icon->width, + capslock_icon->height); +} + static void on_timeout (void *user_data, ply_event_loop_t *loop) @@ -104,12 +113,8 @@ on_timeout (void *user_data, ply_capslock_icon_update_state (capslock_icon); - if (capslock_icon->is_on != old_is_on) { - ply_pixel_display_draw_area (capslock_icon->display, - capslock_icon->x, capslock_icon->y, - capslock_icon->width, - capslock_icon->height); - } + if (capslock_icon->is_on != old_is_on) + ply_capslock_icon_draw (capslock_icon); ply_event_loop_watch_for_timeout (capslock_icon->loop, 1.0 / FRAMES_PER_SECOND, @@ -160,6 +165,8 @@ ply_capslock_icon_show (ply_capslock_icon_t *capslock_icon, capslock_icon->x = x; capslock_icon->y = y; + ply_capslock_icon_draw (capslock_icon); + ply_event_loop_watch_for_timeout (capslock_icon->loop, 1.0 / FRAMES_PER_SECOND, on_timeout, capslock_icon); @@ -175,10 +182,7 @@ ply_capslock_icon_hide (ply_capslock_icon_t *capslock_icon) capslock_icon->is_hidden = true; - ply_pixel_display_draw_area (capslock_icon->display, - capslock_icon->x, capslock_icon->y, - capslock_icon->width, - capslock_icon->height); + ply_capslock_icon_draw (capslock_icon); ply_event_loop_stop_watching_for_timeout (capslock_icon->loop, (ply_event_loop_timeout_handler_t) From 05f32bc2fff091bfb2a9d6fbe273e6bd58ee7138 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 30 Sep 2019 23:30:53 +0200 Subject: [PATCH 7/8] two-step: Add Keyboard layout indicator support Use the new keymap-icon control to show a keyboard layout indicator, when showing a dialog. Signed-off-by: Hans de Goede --- src/plugins/splash/two-step/plugin.c | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/src/plugins/splash/two-step/plugin.c b/src/plugins/splash/two-step/plugin.c index 74cfbc31..9e648d24 100644 --- a/src/plugins/splash/two-step/plugin.c +++ b/src/plugins/splash/two-step/plugin.c @@ -50,6 +50,7 @@ #include "ply-logger.h" #include "ply-image.h" #include "ply-key-file.h" +#include "ply-keymap-icon.h" #include "ply-trigger.h" #include "ply-pixel-buffer.h" #include "ply-pixel-display.h" @@ -98,6 +99,7 @@ typedef struct ply_boot_splash_plugin_t *plugin; ply_pixel_display_t *display; ply_entry_t *entry; + ply_keymap_icon_t *keymap_icon; ply_capslock_icon_t *capslock_icon; ply_animation_t *end_animation; ply_progress_animation_t *progress_animation; @@ -207,6 +209,7 @@ view_new (ply_boot_splash_plugin_t *plugin, view->display = display; view->entry = ply_entry_new (plugin->animation_dir); + view->keymap_icon = ply_keymap_icon_new (display, plugin->animation_dir); view->capslock_icon = ply_capslock_icon_new (plugin->animation_dir); view->progress_animation = ply_progress_animation_new (plugin->animation_dir, "progress-"); @@ -241,6 +244,7 @@ static void view_free (view_t *view) { ply_entry_free (view->entry); + ply_keymap_icon_free (view->keymap_icon); ply_capslock_icon_free (view->capslock_icon); ply_animation_free (view->end_animation); ply_progress_animation_free (view->progress_animation); @@ -604,6 +608,7 @@ view_load (view_t *view) if (!ply_entry_load (view->entry)) return false; + ply_keymap_icon_load (view->keymap_icon); ply_capslock_icon_load (view->capslock_icon); view_load_end_animation (view); @@ -877,7 +882,7 @@ view_show_prompt (view_t *view, { ply_boot_splash_plugin_t *plugin; unsigned long screen_width, screen_height, entry_width, entry_height; - unsigned long capslock_width, capslock_height; + unsigned long keyboard_indicator_width, keyboard_indicator_height; int x, y; assert (view != NULL); @@ -921,12 +926,20 @@ view_show_prompt (view_t *view, ply_entry_show (view->entry, plugin->loop, view->display, x, y); - capslock_width = ply_capslock_icon_get_width (view->capslock_icon); - capslock_height = ply_capslock_icon_get_height (view->capslock_icon); + keyboard_indicator_width = + ply_keymap_icon_get_width (view->keymap_icon); + keyboard_indicator_height = MAX( + ply_capslock_icon_get_height (view->capslock_icon), + ply_keymap_icon_get_height (view->keymap_icon)); - x = (screen_width - capslock_width) * plugin->keyboard_indicator_horizontal_alignment; - y = (screen_height - capslock_height) * plugin->keyboard_indicator_vertical_alignment; + x = (screen_width - keyboard_indicator_width) * plugin->keyboard_indicator_horizontal_alignment; + y = (screen_height - keyboard_indicator_height) * plugin->keyboard_indicator_vertical_alignment + + (keyboard_indicator_height - ply_keymap_icon_get_height (view->keymap_icon)) / 2.0; + ply_keymap_icon_show (view->keymap_icon, x, y); + x += ply_keymap_icon_get_width (view->keymap_icon); + y = (screen_height - keyboard_indicator_height) * plugin->keyboard_indicator_vertical_alignment + + (keyboard_indicator_height - ply_capslock_icon_get_height (view->capslock_icon)) / 2.0; ply_capslock_icon_show (view->capslock_icon, plugin->loop, view->display, x, y); } @@ -958,6 +971,7 @@ view_hide_prompt (view_t *view) ply_entry_hide (view->entry); ply_capslock_icon_hide (view->capslock_icon); + ply_keymap_icon_hide (view->keymap_icon); ply_label_hide (view->label); } @@ -1452,6 +1466,9 @@ on_draw (view_t *view, ply_entry_draw_area (view->entry, pixel_buffer, x, y, width, height); + ply_keymap_icon_draw_area (view->keymap_icon, + pixel_buffer, + x, y, width, height); ply_capslock_icon_draw_area (view->capslock_icon, pixel_buffer, x, y, width, height); From c87a2c07b7c67b8840c91c64d5e2ed87706bd4d6 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 1 Oct 2019 00:19:48 +0200 Subject: [PATCH 8/8] themes: Add images for keyboard indicator support to spinner and spinfinity Add capslock.png, keyboard.png and keymap-render.png files to the spinner and spinfinity themes, this enables keyboard indicator (keymap and capslock state) support for these themes. capslock.png was made by me drawing the icon in xfig, then export as svg, at some blank rows at the bottom and save as png. I've added the capslock.fig file to the spinner theme dir. keyboard.png comes from google's material-design-icons (original is apache licensed): https://github.com/google/material-design-icons/ I've also added a copy of the 2 svg source files to the spinner theme dir. keymap-render.png is generated by scripts/keymap-render.py. Fixes: #85 Signed-off-by: Hans de Goede --- themes/spinfinity/Makefile.am | 3 +++ themes/spinfinity/capslock.png | Bin 0 -> 958 bytes themes/spinfinity/keyboard.png | Bin 0 -> 5717 bytes themes/spinfinity/keymap-render.png | Bin 0 -> 26108 bytes themes/spinner/Makefile.am | 3 +++ themes/spinner/capslock.fig | 16 ++++++++++++++++ themes/spinner/capslock.png | Bin 0 -> 958 bytes themes/spinner/keyboard.png | Bin 0 -> 5717 bytes themes/spinner/keyboard_24px.svg | 4 ++++ themes/spinner/keyboard_48px.svg | 4 ++++ themes/spinner/keymap-render.png | Bin 0 -> 26108 bytes 11 files changed, 30 insertions(+) create mode 100644 themes/spinfinity/capslock.png create mode 100644 themes/spinfinity/keyboard.png create mode 100644 themes/spinfinity/keymap-render.png create mode 100644 themes/spinner/capslock.fig create mode 100644 themes/spinner/capslock.png create mode 100644 themes/spinner/keyboard.png create mode 100644 themes/spinner/keyboard_24px.svg create mode 100644 themes/spinner/keyboard_48px.svg create mode 100644 themes/spinner/keymap-render.png diff --git a/themes/spinfinity/Makefile.am b/themes/spinfinity/Makefile.am index 98fcfb87..b4bc31d2 100644 --- a/themes/spinfinity/Makefile.am +++ b/themes/spinfinity/Makefile.am @@ -5,6 +5,9 @@ dist_theme_DATA = \ bullet.png \ entry.png \ lock.png \ + capslock.png \ + keyboard.png \ + keymap-render.png \ animation-0001.png \ throbber-00.png \ throbber-01.png \ diff --git a/themes/spinfinity/capslock.png b/themes/spinfinity/capslock.png new file mode 100644 index 0000000000000000000000000000000000000000..e18a0acb0e3ae04d6ed063134a10119e9bdc88d1 GIT binary patch literal 958 zcmV;v13~EX>4Tx04R}tkv&MmKpe$iQ>7{u2P=q(1guUL#ELj-6^c+H)C#RSm|VYvCJjl7 zi=*ILaPVWX>fqw6tAnc`2!4RLxH>7iNQwVT3N2zhIPS;0dyl(!fKV$j)odFFRLwGy z@tBy-tcZbEbYcj7h+^*QA!4!6!b%IXqM;H`5{I*@M)^Y8 zvoPgai=^D%d~?79zB2q?kz3e$2x^;P@qSDdgG! zBgZ_-P$4^h@IUz7t(lKbxJkhn(EeiEA0t3u7pPZl`}^3o>nDK!8MxA#{&EeN{v^HH z)WSzV&o*#z-PDvl;Bp7(f6`?`b|gPdA)g1{&*+;nK<_Qkwd(fP*vIJukfN>>z zndKxd^K3-Id5N=^11<6?hxg|Detek$YGAEhvDU8C$zf=qG3GMK4zHO~tRaFKHSZkjG zco6C^5xJM=`IDd}JLev%>hn;C?QI;uqb$pw?JHo6xg#R40i3{m`~Yx2%d$6r2pD6o zl6+6Hg+rjKI{07*qoM6N<$f?1!wHvj+t literal 0 HcmV?d00001 diff --git a/themes/spinfinity/keyboard.png b/themes/spinfinity/keyboard.png new file mode 100644 index 0000000000000000000000000000000000000000..347954cf802f47251d5ad089820242652871e5c9 GIT binary patch literal 5717 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 Hu0mjfl91$H literal 0 HcmV?d00001 diff --git a/themes/spinfinity/keymap-render.png b/themes/spinfinity/keymap-render.png new file mode 100644 index 0000000000000000000000000000000000000000..4f8c459dae4d06bea19bbc844260d559d21d3df7 GIT binary patch literal 26108 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 literal 0 HcmV?d00001 diff --git a/themes/spinner/Makefile.am b/themes/spinner/Makefile.am index e6e1bb67..ea283363 100644 --- a/themes/spinner/Makefile.am +++ b/themes/spinner/Makefile.am @@ -5,6 +5,9 @@ dist_theme_DATA = \ bullet.png \ entry.png \ lock.png \ + capslock.png \ + keyboard.png \ + keymap-render.png \ animation-0001.png \ animation-0002.png \ animation-0003.png \ diff --git a/themes/spinner/capslock.fig b/themes/spinner/capslock.fig new file mode 100644 index 00000000..22a14a92 --- /dev/null +++ b/themes/spinner/capslock.fig @@ -0,0 +1,16 @@ +#FIG 3.2 Produced by xfig version 3.2.7a +Landscape +Center +Metric +A4 +100.00 +Single +-2 +1200 2 +0 32 #e8e8e8 +2 3 0 1 32 32 50 -1 20 0.000 0 0 0 0 0 4 + 1440 225 193 1620 2687 1620 1440 225 +2 2 0 1 32 32 50 -1 20 0.000 0 0 -1 0 0 5 + 810 1620 2070 1620 2070 2250 810 2250 810 1620 +2 2 0 1 32 32 50 -1 20 0.000 0 0 -1 0 0 5 + 810 2430 2070 2430 2070 2790 810 2790 810 2430 diff --git a/themes/spinner/capslock.png b/themes/spinner/capslock.png new file mode 100644 index 0000000000000000000000000000000000000000..e18a0acb0e3ae04d6ed063134a10119e9bdc88d1 GIT binary patch literal 958 zcmV;v13~EX>4Tx04R}tkv&MmKpe$iQ>7{u2P=q(1guUL#ELj-6^c+H)C#RSm|VYvCJjl7 zi=*ILaPVWX>fqw6tAnc`2!4RLxH>7iNQwVT3N2zhIPS;0dyl(!fKV$j)odFFRLwGy z@tBy-tcZbEbYcj7h+^*QA!4!6!b%IXqM;H`5{I*@M)^Y8 zvoPgai=^D%d~?79zB2q?kz3e$2x^;P@qSDdgG! zBgZ_-P$4^h@IUz7t(lKbxJkhn(EeiEA0t3u7pPZl`}^3o>nDK!8MxA#{&EeN{v^HH z)WSzV&o*#z-PDvl;Bp7(f6`?`b|gPdA)g1{&*+;nK<_Qkwd(fP*vIJukfN>>z zndKxd^K3-Id5N=^11<6?hxg|Detek$YGAEhvDU8C$zf=qG3GMK4zHO~tRaFKHSZkjG zco6C^5xJM=`IDd}JLev%>hn;C?QI;uqb$pw?JHo6xg#R40i3{m`~Yx2%d$6r2pD6o zl6+6Hg+rjKI{07*qoM6N<$f?1!wHvj+t literal 0 HcmV?d00001 diff --git a/themes/spinner/keyboard.png b/themes/spinner/keyboard.png new file mode 100644 index 0000000000000000000000000000000000000000..347954cf802f47251d5ad089820242652871e5c9 GIT binary patch literal 5717 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 Hu0mjfl91$H literal 0 HcmV?d00001 diff --git a/themes/spinner/keyboard_24px.svg b/themes/spinner/keyboard_24px.svg new file mode 100644 index 00000000..6961f3df --- /dev/null +++ b/themes/spinner/keyboard_24px.svg @@ -0,0 +1,4 @@ + + + + diff --git a/themes/spinner/keyboard_48px.svg b/themes/spinner/keyboard_48px.svg new file mode 100644 index 00000000..8fbb16bc --- /dev/null +++ b/themes/spinner/keyboard_48px.svg @@ -0,0 +1,4 @@ + + + + diff --git a/themes/spinner/keymap-render.png b/themes/spinner/keymap-render.png new file mode 100644 index 0000000000000000000000000000000000000000..4f8c459dae4d06bea19bbc844260d559d21d3df7 GIT binary patch literal 26108 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 literal 0 HcmV?d00001