Merge branch 'keyboard-indicator' into 'master'
Add keyboard layout indicator support Closes #85 See merge request plymouth/plymouth!71
99
scripts/keymap-render.py
Executable file
|
|
@ -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("};")
|
||||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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: */
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 \
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
280
src/libply-splash-graphics/ply-keymap-icon.c
Normal file
|
|
@ -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 <hdegoede@redhat.com>
|
||||
*/
|
||||
#include "config.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#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: */
|
||||
57
src/libply-splash-graphics/ply-keymap-icon.h
Normal file
|
|
@ -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 <hdegoede@redhat.com>
|
||||
*/
|
||||
#ifndef KEYMAP_ICON_H
|
||||
#define KEYMAP_ICON_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#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: */
|
||||
138
src/libply-splash-graphics/ply-keymap-metadata.h
Normal file
|
|
@ -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 */
|
||||
};
|
||||
|
|
@ -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: */
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 \
|
||||
|
|
|
|||
BIN
themes/spinfinity/capslock.png
Normal file
|
After Width: | Height: | Size: 958 B |
BIN
themes/spinfinity/keyboard.png
Normal file
|
After Width: | Height: | Size: 5.6 KiB |
BIN
themes/spinfinity/keymap-render.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
|
|
@ -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 \
|
||||
|
|
|
|||
16
themes/spinner/capslock.fig
Normal file
|
|
@ -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
|
||||
BIN
themes/spinner/capslock.png
Normal file
|
After Width: | Height: | Size: 958 B |
BIN
themes/spinner/keyboard.png
Normal file
|
After Width: | Height: | Size: 5.6 KiB |
4
themes/spinner/keyboard_24px.svg
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<path d="M20 5H4c-1.1 0-1.99.9-1.99 2L2 17c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm-9 3h2v2h-2V8zm0 3h2v2h-2v-2zM8 8h2v2H8V8zm0 3h2v2H8v-2zm-1 2H5v-2h2v2zm0-3H5V8h2v2zm9 7H8v-2h8v2zm0-4h-2v-2h2v2zm0-3h-2V8h2v2zm3 3h-2v-2h2v2zm0-3h-2V8h2v2z"/>
|
||||
<path d="M0 0h24v24H0zm0 0h24v24H0z" fill="none"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 403 B |
4
themes/spinner/keyboard_48px.svg
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48">
|
||||
<path d="M40 10H8c-2.21 0-3.98 1.79-3.98 4L4 34c0 2.21 1.79 4 4 4h32c2.21 0 4-1.79 4-4V14c0-2.21-1.79-4-4-4zm-18 6h4v4h-4v-4zm0 6h4v4h-4v-4zm-6-6h4v4h-4v-4zm0 6h4v4h-4v-4zm-2 4h-4v-4h4v4zm0-6h-4v-4h4v4zm18 14H16v-4h16v4zm0-8h-4v-4h4v4zm0-6h-4v-4h4v4zm6 6h-4v-4h4v4zm0-6h-4v-4h4v4z"/>
|
||||
<path d="M0 0h48v48H0zm0 0h48v48H0z" fill="none"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 434 B |
BIN
themes/spinner/keymap-render.png
Normal file
|
After Width: | Height: | Size: 26 KiB |