Compare commits
	
		
			20 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 7e57df3434 | |||
| 24cacf988b | |||
| 8e55e9ee56 | |||
| e1a012cf50 | |||
| 50dab14754 | |||
| 733cbe94ee | |||
| 01a8afad0d | |||
| bafd1e6eb3 | |||
| a799178b6a | |||
| 12be3e980f | |||
| ca8a2baefa | |||
| 6b72d09fb8 | |||
| c8dd34c829 | |||
| 4d656ff54d | |||
| e2b89e85f7 | |||
| b6f3d9c1ea | |||
| 9ff11dc511 | |||
| 1cffdda09d | |||
| d9f284b19a | |||
| ed602faeaf | 
@ -40,7 +40,7 @@ Most common testing is done in CI. Occasionally, and for each release, do perfor
 | 
				
			|||||||
Testing with an application:
 | 
					Testing with an application:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
python3 tests/entry.py
 | 
					python3 tools/entry.py
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Testing visibility:
 | 
					Testing visibility:
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										16
									
								
								data/keyboards/emoji.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								data/keyboards/emoji.yaml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,16 @@
 | 
				
			|||||||
 | 
					---
 | 
				
			||||||
 | 
					outlines:
 | 
				
			||||||
 | 
					    default: { width: 52, height: 52 }
 | 
				
			||||||
 | 
					    altline: { width: 52, height: 52 }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					views:
 | 
				
			||||||
 | 
					    base:
 | 
				
			||||||
 | 
					        - "😀 😁 😅 😂 😊 😇 🙃"
 | 
				
			||||||
 | 
					        - "😍 😘 😋 😜 😎 🥳 😔"
 | 
				
			||||||
 | 
					        - "😢 😭 😡 😱 🤔 😬 🙄"
 | 
				
			||||||
 | 
					        - "preferences 🤨 🤓 😴 🤢 🤮 😈"
 | 
				
			||||||
 | 
					buttons:
 | 
				
			||||||
 | 
					    preferences:
 | 
				
			||||||
 | 
					        action: "show_prefs"
 | 
				
			||||||
 | 
					        outline: "altline"
 | 
				
			||||||
 | 
					        icon: "keyboard-mode-symbolic"
 | 
				
			||||||
							
								
								
									
										19
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										19
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							@ -1,3 +1,22 @@
 | 
				
			|||||||
 | 
					squeekboard (1.6.0) UNRELEASED; urgency=medium
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Dorota Czaplejewicz ]
 | 
				
			||||||
 | 
					  * tools: Move entry.py
 | 
				
			||||||
 | 
					  * build: Move building of squeekboard-test-layout to tools
 | 
				
			||||||
 | 
					  * packaging: Install entty.py as squeekboard-entry
 | 
				
			||||||
 | 
					  * Remove unused build dependencies
 | 
				
			||||||
 | 
					  * Remove unused header generator
 | 
				
			||||||
 | 
					  * logging: Move all facilities to one file
 | 
				
			||||||
 | 
					  * logging: Described the design
 | 
				
			||||||
 | 
					  * logging: Add described log levels
 | 
				
			||||||
 | 
					  * popover: Install emoji layout
 | 
				
			||||||
 | 
					  * popover: Show overlays as selected
 | 
				
			||||||
 | 
					  * Fix old Rust woes
 | 
				
			||||||
 | 
					  * emoji: Add a passable layout
 | 
				
			||||||
 | 
					  * Fix g_ and stdlib allocation/free mismatches
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 -- Dorota Czaplejewicz <dorota.czaplejewicz@puri.sm>  Thu, 02 Jan 2020 12:02:50 +0000
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
squeekboard (1.5.0) amber-phone; urgency=medium
 | 
					squeekboard (1.5.0) amber-phone; urgency=medium
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  [ Dorota Czaplejewicz ]
 | 
					  [ Dorota Czaplejewicz ]
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										8
									
								
								debian/control
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								debian/control
									
									
									
									
										vendored
									
									
								
							@ -26,9 +26,6 @@ Build-Depends:
 | 
				
			|||||||
 libwayland-dev (>= 1.16),
 | 
					 libwayland-dev (>= 1.16),
 | 
				
			||||||
 rustc,
 | 
					 rustc,
 | 
				
			||||||
 wayland-protocols (>= 1.14),
 | 
					 wayland-protocols (>= 1.14),
 | 
				
			||||||
# for running the tests
 | 
					 | 
				
			||||||
 xvfb,
 | 
					 | 
				
			||||||
 xauth,
 | 
					 | 
				
			||||||
Standards-Version: 4.1.3
 | 
					Standards-Version: 4.1.3
 | 
				
			||||||
Homepage: https://source.puri.sm/Librem5/squeekboard
 | 
					Homepage: https://source.puri.sm/Librem5/squeekboard
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -45,9 +42,12 @@ Description: On-screen keyboard for Wayland
 | 
				
			|||||||
Package: squeekboard-devel
 | 
					Package: squeekboard-devel
 | 
				
			||||||
Architecture: linux-any
 | 
					Architecture: linux-any
 | 
				
			||||||
Depends:
 | 
					Depends:
 | 
				
			||||||
 | 
					 python3,
 | 
				
			||||||
 | 
					 python3-gi,
 | 
				
			||||||
 ${shlibs:Depends}
 | 
					 ${shlibs:Depends}
 | 
				
			||||||
 ${misc:Depends}
 | 
					 ${misc:Depends}
 | 
				
			||||||
Description: Resources for making Squeekboard layouts
 | 
					Description: Resources for making Squeekboard layouts
 | 
				
			||||||
 Tools for creating Squeekboard layouts:
 | 
					 Tools for creating and testing Squeekboard layouts:
 | 
				
			||||||
 .
 | 
					 .
 | 
				
			||||||
 | 
					  * squeekboard-entry
 | 
				
			||||||
  * squeekboard-test-layout
 | 
					  * squeekboard-test-layout
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										1
									
								
								debian/squeekboard-devel.install
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								debian/squeekboard-devel.install
									
									
									
									
										vendored
									
									
								
							@ -1 +1,2 @@
 | 
				
			|||||||
usr/bin/squeekboard-test-layout /usr/bin
 | 
					usr/bin/squeekboard-test-layout /usr/bin
 | 
				
			||||||
 | 
					usr/bin/squeekboard-entry /usr/bin
 | 
				
			||||||
 | 
				
			|||||||
@ -131,14 +131,17 @@ static void drag(EekGtkKeyboard *self,
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self);
 | 
					    EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self);
 | 
				
			||||||
    squeek_layout_drag(priv->keyboard->layout, priv->keyboard->manager->virtual_keyboard,
 | 
					    squeek_layout_drag(priv->keyboard->layout, priv->keyboard->manager->virtual_keyboard,
 | 
				
			||||||
                       x, y, eek_renderer_get_transformation(priv->renderer), time, self);
 | 
					                       x, y, eek_renderer_get_transformation(priv->renderer), time,
 | 
				
			||||||
 | 
					                       priv->keyboard->manager, self);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void release(EekGtkKeyboard *self, guint32 time)
 | 
					static void release(EekGtkKeyboard *self, guint32 time)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self);
 | 
					    EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    squeek_layout_release(priv->keyboard->layout, priv->keyboard->manager->virtual_keyboard, eek_renderer_get_transformation(priv->renderer), time, self);
 | 
					    squeek_layout_release(priv->keyboard->layout, priv->keyboard->manager->virtual_keyboard,
 | 
				
			||||||
 | 
					                          eek_renderer_get_transformation(priv->renderer), time,
 | 
				
			||||||
 | 
					                          priv->keyboard->manager, self);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static gboolean
 | 
					static gboolean
 | 
				
			||||||
 | 
				
			|||||||
@ -30,7 +30,6 @@
 | 
				
			|||||||
#include "config.h"
 | 
					#include "config.h"
 | 
				
			||||||
#include <glib/gprintf.h>
 | 
					#include <glib/gprintf.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "eek-enumtypes.h"
 | 
					 | 
				
			||||||
#include "eekboard/eekboard-context-service.h"
 | 
					#include "eekboard/eekboard-context-service.h"
 | 
				
			||||||
#include "eekboard/key-emitter.h"
 | 
					#include "eekboard/key-emitter.h"
 | 
				
			||||||
#include "keymap.h"
 | 
					#include "keymap.h"
 | 
				
			||||||
 | 
				
			|||||||
@ -1,8 +0,0 @@
 | 
				
			|||||||
gnome = import('gnome')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
enum_headers = [
 | 
					 | 
				
			||||||
  'eek-types.h',
 | 
					 | 
				
			||||||
]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
enums = gnome.mkenums_simple('eek-enumtypes', sources: enum_headers)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@ -71,6 +71,8 @@ struct _EekboardContextServicePrivate {
 | 
				
			|||||||
    LevelKeyboard *keyboard; // currently used keyboard
 | 
					    LevelKeyboard *keyboard; // currently used keyboard
 | 
				
			||||||
    GHashTable *keyboard_hash; // a table of available keyboards, per layout
 | 
					    GHashTable *keyboard_hash; // a table of available keyboards, per layout
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char *overlay;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    GSettings *settings;
 | 
					    GSettings *settings;
 | 
				
			||||||
    uint32_t hint;
 | 
					    uint32_t hint;
 | 
				
			||||||
    uint32_t purpose;
 | 
					    uint32_t purpose;
 | 
				
			||||||
@ -214,15 +216,17 @@ settings_get_layout(GSettings *settings, char **type, char **layout)
 | 
				
			|||||||
void
 | 
					void
 | 
				
			||||||
eekboard_context_service_update_layout(EekboardContextService *context, enum squeek_arrangement_kind t)
 | 
					eekboard_context_service_update_layout(EekboardContextService *context, enum squeek_arrangement_kind t)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    g_autofree gchar *keyboard_type = NULL;
 | 
					 | 
				
			||||||
    g_autofree gchar *keyboard_layout = NULL;
 | 
					    g_autofree gchar *keyboard_layout = NULL;
 | 
				
			||||||
    settings_get_layout(context->priv->settings, &keyboard_type, &keyboard_layout);
 | 
					    if (context->priv->overlay) {
 | 
				
			||||||
 | 
					        keyboard_layout = g_strdup(context->priv->overlay);
 | 
				
			||||||
    if (!keyboard_type) {
 | 
					    } else {
 | 
				
			||||||
        keyboard_type = g_strdup("us");
 | 
					        g_autofree gchar *keyboard_type = NULL;
 | 
				
			||||||
 | 
					        settings_get_layout(context->priv->settings,
 | 
				
			||||||
 | 
					                            &keyboard_type, &keyboard_layout);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!keyboard_layout) {
 | 
					    if (!keyboard_layout) {
 | 
				
			||||||
        keyboard_layout = g_strdup("undefined");
 | 
					        keyboard_layout = g_strdup("us");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    EekboardContextServicePrivate *priv = EEKBOARD_CONTEXT_SERVICE_GET_PRIVATE(context);
 | 
					    EekboardContextServicePrivate *priv = EEKBOARD_CONTEXT_SERVICE_GET_PRIVATE(context);
 | 
				
			||||||
@ -262,6 +266,8 @@ settings_handle_layout_changed(GSettings *s,
 | 
				
			|||||||
    (void)keys;
 | 
					    (void)keys;
 | 
				
			||||||
    (void)n_keys;
 | 
					    (void)n_keys;
 | 
				
			||||||
    EekboardContextService *context = user_data;
 | 
					    EekboardContextService *context = user_data;
 | 
				
			||||||
 | 
					    g_free(context->priv->overlay);
 | 
				
			||||||
 | 
					    context->priv->overlay = NULL;
 | 
				
			||||||
    update_layout_and_type(context);
 | 
					    update_layout_and_type(context);
 | 
				
			||||||
    return TRUE;
 | 
					    return TRUE;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -391,6 +397,8 @@ eekboard_context_service_init (EekboardContextService *self)
 | 
				
			|||||||
        g_warning ("Could not connect to gsettings updates, layout"
 | 
					        g_warning ("Could not connect to gsettings updates, layout"
 | 
				
			||||||
                   " changing unavailable");
 | 
					                   " changing unavailable");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    self->priv->overlay = NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@ -463,6 +471,7 @@ eekboard_context_service_destroy (EekboardContextService *context)
 | 
				
			|||||||
    if (context->priv->enabled) {
 | 
					    if (context->priv->enabled) {
 | 
				
			||||||
        eekboard_context_service_disable (context);
 | 
					        eekboard_context_service_disable (context);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    g_free(context->priv->overlay);
 | 
				
			||||||
    g_signal_emit (context, signals[DESTROYED], 0);
 | 
					    g_signal_emit (context, signals[DESTROYED], 0);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -498,3 +507,14 @@ void eekboard_context_service_set_hint_purpose(EekboardContextService *context,
 | 
				
			|||||||
        update_layout_and_type(context);
 | 
					        update_layout_and_type(context);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					eekboard_context_service_set_overlay(EekboardContextService *context, const char* name) {
 | 
				
			||||||
 | 
					    context->priv->overlay = g_strdup(name);
 | 
				
			||||||
 | 
					    update_layout_and_type(context);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const char*
 | 
				
			||||||
 | 
					eekboard_context_service_get_overlay(EekboardContextService *context) {
 | 
				
			||||||
 | 
					    return context->priv->overlay;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,7 +1,7 @@
 | 
				
			|||||||
project(
 | 
					project(
 | 
				
			||||||
    'squeekboard',
 | 
					    'squeekboard',
 | 
				
			||||||
    'c', 'rust',
 | 
					    'c', 'rust',
 | 
				
			||||||
    version: '1.5.0',
 | 
					    version: '1.6.0',
 | 
				
			||||||
    license: 'GPLv3',
 | 
					    license: 'GPLv3',
 | 
				
			||||||
    meson_version: '>=0.51.0',
 | 
					    meson_version: '>=0.51.0',
 | 
				
			||||||
    default_options: [
 | 
					    default_options: [
 | 
				
			||||||
@ -40,6 +40,7 @@ else
 | 
				
			|||||||
endif
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
prefix = get_option('prefix')
 | 
					prefix = get_option('prefix')
 | 
				
			||||||
 | 
					bindir = join_paths(prefix, get_option('bindir'))
 | 
				
			||||||
datadir = join_paths(prefix, get_option('datadir'))
 | 
					datadir = join_paths(prefix, get_option('datadir'))
 | 
				
			||||||
pkgdatadir = join_paths(datadir, meson.project_name())
 | 
					pkgdatadir = join_paths(datadir, meson.project_name())
 | 
				
			||||||
if get_option('depdatadir') == ''
 | 
					if get_option('depdatadir') == ''
 | 
				
			||||||
@ -65,6 +66,6 @@ cargo_build = find_program('cargo_build.sh')
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
subdir('data')
 | 
					subdir('data')
 | 
				
			||||||
subdir('protocols')
 | 
					subdir('protocols')
 | 
				
			||||||
subdir('eek')
 | 
					 | 
				
			||||||
subdir('src')
 | 
					subdir('src')
 | 
				
			||||||
 | 
					subdir('tools')
 | 
				
			||||||
subdir('tests')
 | 
					subdir('tests')
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										23
									
								
								src/data.rs
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								src/data.rs
									
									
									
									
									
								
							@ -21,17 +21,17 @@ use ::keyboard::{
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
use ::layout;
 | 
					use ::layout;
 | 
				
			||||||
use ::layout::ArrangementKind;
 | 
					use ::layout::ArrangementKind;
 | 
				
			||||||
 | 
					use ::logging::PrintWarnings;
 | 
				
			||||||
use ::resources;
 | 
					use ::resources;
 | 
				
			||||||
use ::util::c::as_str;
 | 
					use ::util::c::as_str;
 | 
				
			||||||
use ::util::hash_map_map;
 | 
					use ::util::hash_map_map;
 | 
				
			||||||
use ::xdg;
 | 
					use ::xdg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// traits, derives
 | 
					// traits, derives
 | 
				
			||||||
 | 
					use serde::Deserialize;
 | 
				
			||||||
use std::io::BufReader;
 | 
					use std::io::BufReader;
 | 
				
			||||||
use std::iter::FromIterator;
 | 
					use std::iter::FromIterator;
 | 
				
			||||||
use serde::Deserialize;
 | 
					use ::logging::WarningHandler;
 | 
				
			||||||
use util::WarningHandler;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Gathers stuff defined in C or called by C
 | 
					/// Gathers stuff defined in C or called by C
 | 
				
			||||||
pub mod c {
 | 
					pub mod c {
 | 
				
			||||||
@ -154,14 +154,6 @@ fn list_layout_sources(
 | 
				
			|||||||
    ret
 | 
					    ret
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct PrintWarnings;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl WarningHandler for PrintWarnings {
 | 
					 | 
				
			||||||
    fn handle(&mut self, warning: &str) {
 | 
					 | 
				
			||||||
        println!("{}", warning);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
fn load_layout_data(source: DataSource)
 | 
					fn load_layout_data(source: DataSource)
 | 
				
			||||||
    -> Result<::layout::LayoutData, LoadError>
 | 
					    -> Result<::layout::LayoutData, LoadError>
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@ -671,14 +663,7 @@ mod tests {
 | 
				
			|||||||
    use super::*;
 | 
					    use super::*;
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    use std::error::Error as ErrorTrait;
 | 
					    use std::error::Error as ErrorTrait;
 | 
				
			||||||
 | 
					    use ::logging::PanicWarn;
 | 
				
			||||||
    struct PanicWarn;
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    impl WarningHandler for PanicWarn {
 | 
					 | 
				
			||||||
        fn handle(&mut self, warning: &str) {
 | 
					 | 
				
			||||||
            panic!("{}", warning);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
    fn test_parse_path() {
 | 
					    fn test_parse_path() {
 | 
				
			||||||
 | 
				
			|||||||
@ -36,6 +36,7 @@ void squeek_layout_free(struct squeek_layout*);
 | 
				
			|||||||
void squeek_layout_release(struct squeek_layout *layout, struct zwp_virtual_keyboard_v1 *virtual_keyboard,
 | 
					void squeek_layout_release(struct squeek_layout *layout, struct zwp_virtual_keyboard_v1 *virtual_keyboard,
 | 
				
			||||||
                           struct transformation widget_to_layout,
 | 
					                           struct transformation widget_to_layout,
 | 
				
			||||||
                           uint32_t timestamp,
 | 
					                           uint32_t timestamp,
 | 
				
			||||||
 | 
					                           EekboardContextService *manager,
 | 
				
			||||||
                           EekGtkKeyboard *ui_keyboard);
 | 
					                           EekGtkKeyboard *ui_keyboard);
 | 
				
			||||||
void squeek_layout_release_all_only(struct squeek_layout *layout, struct zwp_virtual_keyboard_v1 *virtual_keyboard, uint32_t timestamp);
 | 
					void squeek_layout_release_all_only(struct squeek_layout *layout, struct zwp_virtual_keyboard_v1 *virtual_keyboard, uint32_t timestamp);
 | 
				
			||||||
void squeek_layout_depress(struct squeek_layout *layout, struct zwp_virtual_keyboard_v1 *virtual_keyboard,
 | 
					void squeek_layout_depress(struct squeek_layout *layout, struct zwp_virtual_keyboard_v1 *virtual_keyboard,
 | 
				
			||||||
@ -45,7 +46,8 @@ void squeek_layout_depress(struct squeek_layout *layout, struct zwp_virtual_keyb
 | 
				
			|||||||
void squeek_layout_drag(struct squeek_layout *layout, struct zwp_virtual_keyboard_v1 *virtual_keyboard,
 | 
					void squeek_layout_drag(struct squeek_layout *layout, struct zwp_virtual_keyboard_v1 *virtual_keyboard,
 | 
				
			||||||
                        double x_widget, double y_widget,
 | 
					                        double x_widget, double y_widget,
 | 
				
			||||||
                        struct transformation widget_to_layout,
 | 
					                        struct transformation widget_to_layout,
 | 
				
			||||||
                        uint32_t timestamp, EekGtkKeyboard *ui_keyboard);
 | 
					                        uint32_t timestamp, EekboardContextService *manager,
 | 
				
			||||||
 | 
					                        EekGtkKeyboard *ui_keyboard);
 | 
				
			||||||
void squeek_layout_draw_all_changed(struct squeek_layout *layout, EekRenderer* renderer, cairo_t     *cr);
 | 
					void squeek_layout_draw_all_changed(struct squeek_layout *layout, EekRenderer* renderer, cairo_t     *cr);
 | 
				
			||||||
void squeek_draw_layout_base_view(struct squeek_layout *layout, EekRenderer* renderer, cairo_t     *cr);
 | 
					void squeek_draw_layout_base_view(struct squeek_layout *layout, EekRenderer* renderer, cairo_t     *cr);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
				
			|||||||
@ -26,6 +26,7 @@ use std::vec::Vec;
 | 
				
			|||||||
use ::action::Action;
 | 
					use ::action::Action;
 | 
				
			||||||
use ::drawing;
 | 
					use ::drawing;
 | 
				
			||||||
use ::keyboard::{ KeyState, PressType };
 | 
					use ::keyboard::{ KeyState, PressType };
 | 
				
			||||||
 | 
					use ::manager;
 | 
				
			||||||
use ::submission::{ Timestamp, VirtualKeyboard };
 | 
					use ::submission::{ Timestamp, VirtualKeyboard };
 | 
				
			||||||
use ::util::find_max_double;
 | 
					use ::util::find_max_double;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -258,6 +259,7 @@ pub mod c {
 | 
				
			|||||||
            virtual_keyboard: ZwpVirtualKeyboardV1, // TODO: receive a reference to the backend
 | 
					            virtual_keyboard: ZwpVirtualKeyboardV1, // TODO: receive a reference to the backend
 | 
				
			||||||
            widget_to_layout: Transformation,
 | 
					            widget_to_layout: Transformation,
 | 
				
			||||||
            time: u32,
 | 
					            time: u32,
 | 
				
			||||||
 | 
					            manager: manager::c::Manager,
 | 
				
			||||||
            ui_keyboard: EekGtkKeyboard,
 | 
					            ui_keyboard: EekGtkKeyboard,
 | 
				
			||||||
        ) {
 | 
					        ) {
 | 
				
			||||||
            let time = Timestamp(time);
 | 
					            let time = Timestamp(time);
 | 
				
			||||||
@ -273,6 +275,7 @@ pub mod c {
 | 
				
			|||||||
                    &widget_to_layout,
 | 
					                    &widget_to_layout,
 | 
				
			||||||
                    time,
 | 
					                    time,
 | 
				
			||||||
                    ui_keyboard,
 | 
					                    ui_keyboard,
 | 
				
			||||||
 | 
					                    manager,
 | 
				
			||||||
                    key,
 | 
					                    key,
 | 
				
			||||||
                );
 | 
					                );
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@ -344,6 +347,7 @@ pub mod c {
 | 
				
			|||||||
            x_widget: f64, y_widget: f64,
 | 
					            x_widget: f64, y_widget: f64,
 | 
				
			||||||
            widget_to_layout: Transformation,
 | 
					            widget_to_layout: Transformation,
 | 
				
			||||||
            time: u32,
 | 
					            time: u32,
 | 
				
			||||||
 | 
					            manager: manager::c::Manager,
 | 
				
			||||||
            ui_keyboard: EekGtkKeyboard,
 | 
					            ui_keyboard: EekGtkKeyboard,
 | 
				
			||||||
        ) {
 | 
					        ) {
 | 
				
			||||||
            let time = Timestamp(time);
 | 
					            let time = Timestamp(time);
 | 
				
			||||||
@ -378,6 +382,7 @@ pub mod c {
 | 
				
			|||||||
                            &widget_to_layout,
 | 
					                            &widget_to_layout,
 | 
				
			||||||
                            time,
 | 
					                            time,
 | 
				
			||||||
                            ui_keyboard,
 | 
					                            ui_keyboard,
 | 
				
			||||||
 | 
					                            manager,
 | 
				
			||||||
                            key,
 | 
					                            key,
 | 
				
			||||||
                        );
 | 
					                        );
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
@ -395,6 +400,7 @@ pub mod c {
 | 
				
			|||||||
                        &widget_to_layout,
 | 
					                        &widget_to_layout,
 | 
				
			||||||
                        time,
 | 
					                        time,
 | 
				
			||||||
                        ui_keyboard,
 | 
					                        ui_keyboard,
 | 
				
			||||||
 | 
					                        manager,
 | 
				
			||||||
                        key,
 | 
					                        key,
 | 
				
			||||||
                    );
 | 
					                    );
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
@ -853,6 +859,7 @@ mod seat {
 | 
				
			|||||||
        widget_to_layout: &c::Transformation,
 | 
					        widget_to_layout: &c::Transformation,
 | 
				
			||||||
        time: Timestamp,
 | 
					        time: Timestamp,
 | 
				
			||||||
        ui_keyboard: c::EekGtkKeyboard,
 | 
					        ui_keyboard: c::EekGtkKeyboard,
 | 
				
			||||||
 | 
					        manager: manager::c::Manager,
 | 
				
			||||||
        key: &Rc<RefCell<KeyState>>,
 | 
					        key: &Rc<RefCell<KeyState>>,
 | 
				
			||||||
    ) {
 | 
					    ) {
 | 
				
			||||||
        layout.release_key(virtual_keyboard, &mut key.clone(), time);
 | 
					        layout.release_key(virtual_keyboard, &mut key.clone(), time);
 | 
				
			||||||
@ -874,7 +881,8 @@ mod seat {
 | 
				
			|||||||
                };
 | 
					                };
 | 
				
			||||||
                ::popover::show(
 | 
					                ::popover::show(
 | 
				
			||||||
                    ui_keyboard,
 | 
					                    ui_keyboard,
 | 
				
			||||||
                    widget_to_layout.reverse_bounds(bounds)
 | 
					                    widget_to_layout.reverse_bounds(bounds),
 | 
				
			||||||
 | 
					                    manager,
 | 
				
			||||||
                );
 | 
					                );
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
				
			|||||||
@ -24,6 +24,8 @@ mod keyboard;
 | 
				
			|||||||
mod layout;
 | 
					mod layout;
 | 
				
			||||||
mod locale;
 | 
					mod locale;
 | 
				
			||||||
mod locale_config;
 | 
					mod locale_config;
 | 
				
			||||||
 | 
					mod logging;
 | 
				
			||||||
 | 
					mod manager;
 | 
				
			||||||
mod outputs;
 | 
					mod outputs;
 | 
				
			||||||
mod popover;
 | 
					mod popover;
 | 
				
			||||||
mod resources;
 | 
					mod resources;
 | 
				
			||||||
 | 
				
			|||||||
@ -16,6 +16,9 @@ mod c {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Clone, Debug, PartialEq)]
 | 
				
			||||||
 | 
					pub struct Translation<'a>(pub &'a str);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn cstring_safe(s: &str) -> CString {
 | 
					fn cstring_safe(s: &str) -> CString {
 | 
				
			||||||
    CString::new(s)
 | 
					    CString::new(s)
 | 
				
			||||||
        .unwrap_or(CString::new("").unwrap())
 | 
					        .unwrap_or(CString::new("").unwrap())
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										110
									
								
								src/logging.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								src/logging.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,110 @@
 | 
				
			|||||||
 | 
					/*! Logging library.
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * This is probably the only part of squeekboard
 | 
				
			||||||
 | 
					 * that should be doing any direct printing.
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * There are several approaches to logging,
 | 
				
			||||||
 | 
					 * in the order of increasing flexibility and/or purity:
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * 1. `println!` directly
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 *   It can't be easily replaced by a different solution
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * 2. simple `log!` macro
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 *   Replacing the destination at runtime other than globally would be awkward,
 | 
				
			||||||
 | 
					 *   so no easy way to suppress errors for things that don't matter,
 | 
				
			||||||
 | 
					 *   but formatting is still easy.
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * 3. logging to a mutable destination type
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 *   Can be easily replaced, but logging `Result` types,
 | 
				
			||||||
 | 
					 *   which should be done by calling a method on the result,
 | 
				
			||||||
 | 
					 *   can't be formatted directly.
 | 
				
			||||||
 | 
					 *   Cannot be parallelized.
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * 4. logging to an immutable destination type
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 *   Same as above, except it can be parallelized.
 | 
				
			||||||
 | 
					 *   It seems more difficult to pass the logger around,
 | 
				
			||||||
 | 
					 *   but this may be a solved problem from the area of functional programming.
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * This library generally aims at the approach in 3.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use std::error::Error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Levels are not in order.
 | 
				
			||||||
 | 
					pub enum Level {
 | 
				
			||||||
 | 
					    // Levels for reporting violated constraints
 | 
				
			||||||
 | 
					    /// The program violated a self-imposed constraint,
 | 
				
			||||||
 | 
					    /// ended up in an inconsistent state, and cannot recover.
 | 
				
			||||||
 | 
					    /// Handlers must not actually panic. (should they?)
 | 
				
			||||||
 | 
					    Panic,
 | 
				
			||||||
 | 
					    /// The program violated a self-imposed constraint,
 | 
				
			||||||
 | 
					    /// ended up in an inconsistent state, but some state can be recovered.
 | 
				
			||||||
 | 
					    Bug,
 | 
				
			||||||
 | 
					    /// Invalid data given by an external source,
 | 
				
			||||||
 | 
					    /// some state of the program must be dropped.
 | 
				
			||||||
 | 
					    Error,
 | 
				
			||||||
 | 
					    // Still violated constraints, but harmless
 | 
				
			||||||
 | 
					    /// Invalid data given by an external source, parts of data are ignored.
 | 
				
			||||||
 | 
					    /// No previous program state needs to be dropped.
 | 
				
			||||||
 | 
					    Warning,
 | 
				
			||||||
 | 
					    /// External source not in an expected state,
 | 
				
			||||||
 | 
					    /// but not violating any protocols (including no relevant protocol).
 | 
				
			||||||
 | 
					    Surprise,
 | 
				
			||||||
 | 
					    // Informational
 | 
				
			||||||
 | 
					    /// A change in internal state that results in a change of behaviour
 | 
				
			||||||
 | 
					    /// that a user can observe, and a tinkerer might find useful.
 | 
				
			||||||
 | 
					    /// E.g. selection of external sources, like loading user's UI files,
 | 
				
			||||||
 | 
					    /// language switch, overrides.
 | 
				
			||||||
 | 
					    Info,
 | 
				
			||||||
 | 
					    /// Information useful for application developer only.
 | 
				
			||||||
 | 
					    /// Should be limited to information gotten from external sources,
 | 
				
			||||||
 | 
					    /// and more tricky parts of internal state.
 | 
				
			||||||
 | 
					    Debug,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Sugar for logging errors in results.
 | 
				
			||||||
 | 
					/// Approach 2.
 | 
				
			||||||
 | 
					pub trait Warn {
 | 
				
			||||||
 | 
					    type Value;
 | 
				
			||||||
 | 
					    fn ok_warn(self, msg: &str) -> Option<Self::Value>;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<T, E: Error> Warn for Result<T, E> {
 | 
				
			||||||
 | 
					    type Value = T;
 | 
				
			||||||
 | 
					    fn ok_warn(self, msg: &str) -> Option<T> {
 | 
				
			||||||
 | 
					        self.map_err(|e| {
 | 
				
			||||||
 | 
					            eprintln!("{}: {}", msg, e);
 | 
				
			||||||
 | 
					            e
 | 
				
			||||||
 | 
					        }).ok()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// A mutable handler for text warnings.
 | 
				
			||||||
 | 
					/// Approach 3.
 | 
				
			||||||
 | 
					pub trait WarningHandler {
 | 
				
			||||||
 | 
					    /// Handle a warning
 | 
				
			||||||
 | 
					    fn handle(&mut self, warning: &str);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Prints warnings to stderr
 | 
				
			||||||
 | 
					pub struct PrintWarnings;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl WarningHandler for PrintWarnings {
 | 
				
			||||||
 | 
					    fn handle(&mut self, warning: &str) {
 | 
				
			||||||
 | 
					        eprintln!("{}", warning);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Warning handler that will panic at any warning.
 | 
				
			||||||
 | 
					/// Don't use except in tests
 | 
				
			||||||
 | 
					pub struct PanicWarn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl WarningHandler for PanicWarn {
 | 
				
			||||||
 | 
					    fn handle(&mut self, warning: &str) {
 | 
				
			||||||
 | 
					        panic!("{}", warning);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										34
									
								
								src/manager.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/manager.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,34 @@
 | 
				
			|||||||
 | 
					/*! Procedures relating to the management of the switching of layouts */
 | 
				
			||||||
 | 
					use ::util;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub mod c {
 | 
				
			||||||
 | 
					    use std::os::raw::{c_char, c_void};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// EekboardContextService*
 | 
				
			||||||
 | 
					    #[repr(transparent)]
 | 
				
			||||||
 | 
					    #[derive(Clone, Copy)]
 | 
				
			||||||
 | 
					    pub struct Manager(*const c_void);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    #[no_mangle]
 | 
				
			||||||
 | 
					    extern "C" {
 | 
				
			||||||
 | 
					        pub fn eekboard_context_service_set_overlay(
 | 
				
			||||||
 | 
					            manager: Manager,
 | 
				
			||||||
 | 
					            name: *const c_char,
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        pub fn eekboard_context_service_get_overlay(
 | 
				
			||||||
 | 
					            manager: Manager,
 | 
				
			||||||
 | 
					        ) -> *const c_char;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Returns the overlay name.
 | 
				
			||||||
 | 
					/// The result lifetime is "as long as the C copy lives"
 | 
				
			||||||
 | 
					pub fn get_overlay(manager: c::Manager) -> Option<String> {
 | 
				
			||||||
 | 
					    let raw_str = unsafe {
 | 
				
			||||||
 | 
					        c::eekboard_context_service_get_overlay(manager)
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    // this string is generated from Rust, should never be invalid
 | 
				
			||||||
 | 
					    util::c::as_str(&raw_str).unwrap()
 | 
				
			||||||
 | 
					        .map(String::from)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -25,7 +25,6 @@ sources = [
 | 
				
			|||||||
  '../eek/eek-xml-layout.c',
 | 
					  '../eek/eek-xml-layout.c',
 | 
				
			||||||
  '../eek/layersurface.c',
 | 
					  '../eek/layersurface.c',
 | 
				
			||||||
  dbus_src,
 | 
					  dbus_src,
 | 
				
			||||||
  enums,
 | 
					 | 
				
			||||||
  '../eekboard/key-emitter.c',
 | 
					  '../eekboard/key-emitter.c',
 | 
				
			||||||
  '../eekboard/eekboard-context-service.c',
 | 
					  '../eekboard/eekboard-context-service.c',
 | 
				
			||||||
  '../eekboard/eekboard-service.c',
 | 
					  '../eekboard/eekboard-service.c',
 | 
				
			||||||
@ -112,16 +111,3 @@ squeekboard = executable('squeekboard',
 | 
				
			|||||||
    '-DEEK_COMPILATION=1'],
 | 
					    '-DEEK_COMPILATION=1'],
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bindir = join_paths(prefix, get_option('bindir'))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
test_layout = custom_target('squeekboard-test-layout',
 | 
					 | 
				
			||||||
    build_by_default: true,
 | 
					 | 
				
			||||||
    # meson doesn't track all inputs, cargo does
 | 
					 | 
				
			||||||
    build_always_stale: true,
 | 
					 | 
				
			||||||
    output: ['squeekboard-test-layout'],
 | 
					 | 
				
			||||||
    console: true,
 | 
					 | 
				
			||||||
    command: [cargo_build] + cargo_build_flags
 | 
					 | 
				
			||||||
        + ['--rename', 'test_layout', '@OUTPUT@', '--bin', 'test_layout'],
 | 
					 | 
				
			||||||
    install: true,
 | 
					 | 
				
			||||||
    install_dir: bindir,
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										160
									
								
								src/popover.rs
									
									
									
									
									
								
							
							
						
						
									
										160
									
								
								src/popover.rs
									
									
									
									
									
								
							@ -2,9 +2,11 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
use gio;
 | 
					use gio;
 | 
				
			||||||
use gtk;
 | 
					use gtk;
 | 
				
			||||||
use ::layout::c::EekGtkKeyboard;
 | 
					use std::ffi::CString;
 | 
				
			||||||
use ::locale::compare_current_locale;
 | 
					use ::layout::c::{ Bounds, EekGtkKeyboard };
 | 
				
			||||||
 | 
					use ::locale::{ Translation, compare_current_locale };
 | 
				
			||||||
use ::locale_config::system_locale;
 | 
					use ::locale_config::system_locale;
 | 
				
			||||||
 | 
					use ::manager;
 | 
				
			||||||
use ::resources;
 | 
					use ::resources;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use gio::ActionMapExt;
 | 
					use gio::ActionMapExt;
 | 
				
			||||||
@ -92,7 +94,7 @@ mod variants {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn make_menu_builder(inputs: Vec<(&str, &str)>) -> gtk::Builder {
 | 
					fn make_menu_builder(inputs: Vec<(&str, Translation)>) -> gtk::Builder {
 | 
				
			||||||
    let mut xml: Vec<u8> = Vec::new();
 | 
					    let mut xml: Vec<u8> = Vec::new();
 | 
				
			||||||
    writeln!(
 | 
					    writeln!(
 | 
				
			||||||
        xml,
 | 
					        xml,
 | 
				
			||||||
@ -101,7 +103,7 @@ fn make_menu_builder(inputs: Vec<(&str, &str)>) -> gtk::Builder {
 | 
				
			|||||||
  <menu id=\"app-menu\">
 | 
					  <menu id=\"app-menu\">
 | 
				
			||||||
    <section>"
 | 
					    <section>"
 | 
				
			||||||
    ).unwrap();
 | 
					    ).unwrap();
 | 
				
			||||||
    for (input_name, human_name) in inputs {
 | 
					    for (input_name, translation) in inputs {
 | 
				
			||||||
        writeln!(
 | 
					        writeln!(
 | 
				
			||||||
            xml,
 | 
					            xml,
 | 
				
			||||||
            "
 | 
					            "
 | 
				
			||||||
@ -110,7 +112,7 @@ fn make_menu_builder(inputs: Vec<(&str, &str)>) -> gtk::Builder {
 | 
				
			|||||||
            <attribute name=\"action\">layout</attribute>
 | 
					            <attribute name=\"action\">layout</attribute>
 | 
				
			||||||
            <attribute name=\"target\">{}</attribute>
 | 
					            <attribute name=\"target\">{}</attribute>
 | 
				
			||||||
        </item>",
 | 
					        </item>",
 | 
				
			||||||
            human_name,
 | 
					            translation.0,
 | 
				
			||||||
            input_name,
 | 
					            input_name,
 | 
				
			||||||
        ).unwrap();
 | 
					        ).unwrap();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -141,16 +143,79 @@ fn set_layout(kind: String, name: String) {
 | 
				
			|||||||
    settings.apply();
 | 
					    settings.apply();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn show(window: EekGtkKeyboard, position: ::layout::c::Bounds) {
 | 
					/// A reference to what the user wants to see
 | 
				
			||||||
 | 
					#[derive(PartialEq, Clone, Debug)]
 | 
				
			||||||
 | 
					enum LayoutId {
 | 
				
			||||||
 | 
					    /// Affects the layout in system settings
 | 
				
			||||||
 | 
					    System {
 | 
				
			||||||
 | 
					        kind: String,
 | 
				
			||||||
 | 
					        name: String,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    /// Only affects what this input method presents
 | 
				
			||||||
 | 
					    Local(String),
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl LayoutId {
 | 
				
			||||||
 | 
					    fn get_name(&self) -> &str {
 | 
				
			||||||
 | 
					        match &self {
 | 
				
			||||||
 | 
					            LayoutId::System { kind: _, name } => name.as_str(),
 | 
				
			||||||
 | 
					            LayoutId::Local(name) => name.as_str(),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn set_visible_layout(
 | 
				
			||||||
 | 
					    manager: manager::c::Manager,
 | 
				
			||||||
 | 
					    layout_id: LayoutId,
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
					    match layout_id {
 | 
				
			||||||
 | 
					        LayoutId::System { kind, name } => set_layout(kind, name),
 | 
				
			||||||
 | 
					        LayoutId::Local(name) => {
 | 
				
			||||||
 | 
					            let name = CString::new(name.as_str()).unwrap();
 | 
				
			||||||
 | 
					            let name_ptr = name.as_ptr();
 | 
				
			||||||
 | 
					            unsafe {
 | 
				
			||||||
 | 
					                manager::c::eekboard_context_service_set_overlay(
 | 
				
			||||||
 | 
					                    manager,
 | 
				
			||||||
 | 
					                    name_ptr,
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Takes into account first any overlays, then system layouts from the list
 | 
				
			||||||
 | 
					fn get_current_layout(
 | 
				
			||||||
 | 
					    manager: manager::c::Manager,
 | 
				
			||||||
 | 
					    system_layouts: &Vec<LayoutId>,
 | 
				
			||||||
 | 
					) -> Option<LayoutId> {
 | 
				
			||||||
 | 
					    match manager::get_overlay(manager) {
 | 
				
			||||||
 | 
					        Some(name) => Some(LayoutId::Local(name)),
 | 
				
			||||||
 | 
					        None => system_layouts.get(0).map(LayoutId::clone),
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn show(
 | 
				
			||||||
 | 
					    window: EekGtkKeyboard,
 | 
				
			||||||
 | 
					    position: Bounds,
 | 
				
			||||||
 | 
					    manager: manager::c::Manager,
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
    unsafe { gtk::set_initialized() };
 | 
					    unsafe { gtk::set_initialized() };
 | 
				
			||||||
    let window = unsafe { gtk::Widget::from_glib_none(window.0) };
 | 
					    let window = unsafe { gtk::Widget::from_glib_none(window.0) };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let overlay_layouts = resources::get_overlays().into_iter()
 | 
				
			||||||
 | 
					        .map(|name| LayoutId::Local(name.to_string()));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let settings = gio::Settings::new("org.gnome.desktop.input-sources");
 | 
					    let settings = gio::Settings::new("org.gnome.desktop.input-sources");
 | 
				
			||||||
    let inputs = settings.get_value("sources").unwrap();
 | 
					    let inputs = settings.get_value("sources").unwrap();
 | 
				
			||||||
    let inputs = variants::get_tuples(inputs);
 | 
					    let inputs = variants::get_tuples(inputs);
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    let input_names: Vec<&str> = inputs.iter()
 | 
					    let system_layouts: Vec<LayoutId> = inputs.into_iter()
 | 
				
			||||||
        .map(|(_kind, name)| name.as_str())
 | 
					        .map(|(kind, name)| LayoutId::System { kind, name })
 | 
				
			||||||
 | 
					        .collect();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let all_layouts: Vec<LayoutId> = system_layouts.clone()
 | 
				
			||||||
 | 
					        .into_iter()
 | 
				
			||||||
 | 
					        .chain(overlay_layouts)
 | 
				
			||||||
        .collect();
 | 
					        .collect();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let translations = system_locale()
 | 
					    let translations = system_locale()
 | 
				
			||||||
@ -162,26 +227,56 @@ pub fn show(window: EekGtkKeyboard, position: ::layout::c::Bounds) {
 | 
				
			|||||||
        )
 | 
					        )
 | 
				
			||||||
        .and_then(|lang| resources::get_layout_names(lang.as_str()));
 | 
					        .and_then(|lang| resources::get_layout_names(lang.as_str()));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // sorted collection of human and machine names
 | 
					    let translated_names = all_layouts.iter()
 | 
				
			||||||
    let mut human_names: Vec<(&str, &str)> = match translations {
 | 
					        .map(LayoutId::get_name);
 | 
				
			||||||
 | 
					    let translated_names: Vec<Translation> = match translations {
 | 
				
			||||||
        Some(translations) => {
 | 
					        Some(translations) => {
 | 
				
			||||||
            input_names.iter()
 | 
					            translated_names
 | 
				
			||||||
                .map(|name| (*name, *translations.get(name).unwrap_or(name)))
 | 
					                .map(move |name| {
 | 
				
			||||||
 | 
					                    translations.get(name)
 | 
				
			||||||
 | 
					                        .map(|translation| translation.clone())
 | 
				
			||||||
 | 
					                        .unwrap_or(Translation(name))
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
                .collect()
 | 
					                .collect()
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        // display bare codes
 | 
					 | 
				
			||||||
        None => {
 | 
					        None => {
 | 
				
			||||||
            input_names.iter()
 | 
					            translated_names.map(|name| Translation(name))
 | 
				
			||||||
                .map(|n| (*n, *n)) // turns &&str into &str
 | 
					 | 
				
			||||||
                .collect()
 | 
					                .collect()
 | 
				
			||||||
        }
 | 
					        },
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    human_names.sort_unstable_by(|(_, human_label_a), (_, human_label_b)| {
 | 
					    // sorted collection of human and machine names
 | 
				
			||||||
        compare_current_locale(human_label_a, human_label_b)
 | 
					    let mut human_names: Vec<(Translation, LayoutId)> = translated_names
 | 
				
			||||||
 | 
					        .into_iter()
 | 
				
			||||||
 | 
					        .zip(all_layouts.clone().into_iter())
 | 
				
			||||||
 | 
					        .collect();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    human_names.sort_unstable_by(|(tr_a, _), (tr_b, _)| {
 | 
				
			||||||
 | 
					        compare_current_locale(tr_a.0, tr_b.0)
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let builder = make_menu_builder(human_names);
 | 
					    // GVariant doesn't natively support `enum`s,
 | 
				
			||||||
 | 
					    // so the `choices` vector will serve as a lookup table.
 | 
				
			||||||
 | 
					    let choices_with_translations: Vec<(String, (Translation, LayoutId))>
 | 
				
			||||||
 | 
					        = human_names.into_iter()
 | 
				
			||||||
 | 
					            .enumerate()
 | 
				
			||||||
 | 
					                .map(|(i, human_entry)| {(
 | 
				
			||||||
 | 
					                    format!("{}_{}", i, human_entry.1.get_name()),
 | 
				
			||||||
 | 
					                    human_entry,
 | 
				
			||||||
 | 
					                )}).collect();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let builder = make_menu_builder(
 | 
				
			||||||
 | 
					        choices_with_translations.iter()
 | 
				
			||||||
 | 
					            .map(|(id, (translation, _))| (id.as_str(), translation.clone()))
 | 
				
			||||||
 | 
					            .collect()
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let choices: Vec<(String, LayoutId)>
 | 
				
			||||||
 | 
					        = choices_with_translations.into_iter()
 | 
				
			||||||
 | 
					            .map(|(id, (_tr, layout))| (id, layout))
 | 
				
			||||||
 | 
					            .collect();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Much more debuggable to populate the model & menu
 | 
					    // Much more debuggable to populate the model & menu
 | 
				
			||||||
    // from a string representation
 | 
					    // from a string representation
 | 
				
			||||||
    // than add items imperatively
 | 
					    // than add items imperatively
 | 
				
			||||||
@ -195,16 +290,21 @@ pub fn show(window: EekGtkKeyboard, position: ::layout::c::Bounds) {
 | 
				
			|||||||
        height: position.width.floor() as i32,
 | 
					        height: position.width.floor() as i32,
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if let Some(current_name) = input_names.get(0) {
 | 
					    if let Some(current_layout) = get_current_layout(manager, &system_layouts) {
 | 
				
			||||||
        let current_name = current_name.to_variant();
 | 
					        let current_name_variant = choices.iter()
 | 
				
			||||||
 | 
					            .find(
 | 
				
			||||||
 | 
					                |(_id, layout)| layout == ¤t_layout
 | 
				
			||||||
 | 
					            ).unwrap()
 | 
				
			||||||
 | 
					            .0.to_variant();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let layout_action = gio::SimpleAction::new_stateful(
 | 
					        let layout_action = gio::SimpleAction::new_stateful(
 | 
				
			||||||
            "layout",
 | 
					            "layout",
 | 
				
			||||||
            Some(current_name.type_()),
 | 
					            Some(current_name_variant.type_()),
 | 
				
			||||||
            ¤t_name,
 | 
					            ¤t_name_variant,
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        layout_action.connect_change_state(|_action, state| {
 | 
					        let menu_inner = menu.clone();
 | 
				
			||||||
 | 
					        layout_action.connect_change_state(move |_action, state| {
 | 
				
			||||||
            match state {
 | 
					            match state {
 | 
				
			||||||
                Some(v) => {
 | 
					                Some(v) => {
 | 
				
			||||||
                    v.get::<String>()
 | 
					                    v.get::<String>()
 | 
				
			||||||
@ -212,10 +312,20 @@ pub fn show(window: EekGtkKeyboard, position: ::layout::c::Bounds) {
 | 
				
			|||||||
                            eprintln!("Variant is not string: {:?}", v);
 | 
					                            eprintln!("Variant is not string: {:?}", v);
 | 
				
			||||||
                            None
 | 
					                            None
 | 
				
			||||||
                        })
 | 
					                        })
 | 
				
			||||||
                        .map(|state| set_layout("xkb".into(), state));
 | 
					                        .map(|state| {
 | 
				
			||||||
 | 
					                            let (_id, layout) = choices.iter()
 | 
				
			||||||
 | 
					                                .find(
 | 
				
			||||||
 | 
					                                    |choices| state == choices.0
 | 
				
			||||||
 | 
					                                ).unwrap();
 | 
				
			||||||
 | 
					                            set_visible_layout(
 | 
				
			||||||
 | 
					                                manager,
 | 
				
			||||||
 | 
					                                layout.clone(),
 | 
				
			||||||
 | 
					                            )
 | 
				
			||||||
 | 
					                        });
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
                None => eprintln!("No variant selected"),
 | 
					                None => eprintln!("No variant selected"),
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					            menu_inner.popdown();
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let action_group = gio::SimpleActionGroup::new();
 | 
					        let action_group = gio::SimpleActionGroup::new();
 | 
				
			||||||
 | 
				
			|||||||
@ -3,6 +3,7 @@
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use std::collections::HashMap;
 | 
					use std::collections::HashMap;
 | 
				
			||||||
 | 
					use ::locale::Translation;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use std::iter::FromIterator;
 | 
					use std::iter::FromIterator;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -23,6 +24,8 @@ const KEYBOARDS: &[(*const str, *const str)] = &[
 | 
				
			|||||||
    ("no", include_str!("../data/keyboards/no.yaml")),
 | 
					    ("no", include_str!("../data/keyboards/no.yaml")),
 | 
				
			||||||
    ("number", include_str!("../data/keyboards/number.yaml")),
 | 
					    ("number", include_str!("../data/keyboards/number.yaml")),
 | 
				
			||||||
    ("se", include_str!("../data/keyboards/se.yaml")),
 | 
					    ("se", include_str!("../data/keyboards/se.yaml")),
 | 
				
			||||||
 | 
					    // Overlays
 | 
				
			||||||
 | 
					    ("emoji", include_str!("../data/keyboards/emoji.yaml")),
 | 
				
			||||||
];
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn get_keyboard(needle: &str) -> Option<&'static str> {
 | 
					pub fn get_keyboard(needle: &str) -> Option<&'static str> {
 | 
				
			||||||
@ -39,6 +42,18 @@ pub fn get_keyboard(needle: &str) -> Option<&'static str> {
 | 
				
			|||||||
        })
 | 
					        })
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const OVERLAY_NAMES: &[*const str] = &[
 | 
				
			||||||
 | 
					    "emoji"
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn get_overlays() -> Vec<&'static str> {
 | 
				
			||||||
 | 
					    OVERLAY_NAMES.iter()
 | 
				
			||||||
 | 
					        .map(|name| {
 | 
				
			||||||
 | 
					            let name: *const str = *name;
 | 
				
			||||||
 | 
					            unsafe { &*name }
 | 
				
			||||||
 | 
					        }).collect()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Translations of the layout identifier strings
 | 
					/// Translations of the layout identifier strings
 | 
				
			||||||
const LAYOUT_NAMES: &[(*const str, *const str)] = &[
 | 
					const LAYOUT_NAMES: &[(*const str, *const str)] = &[
 | 
				
			||||||
    ("de-DE", include_str!("../data/langs/de-DE.txt")),
 | 
					    ("de-DE", include_str!("../data/langs/de-DE.txt")),
 | 
				
			||||||
@ -49,7 +64,7 @@ const LAYOUT_NAMES: &[(*const str, *const str)] = &[
 | 
				
			|||||||
];
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn get_layout_names(lang: &str)
 | 
					pub fn get_layout_names(lang: &str)
 | 
				
			||||||
    -> Option<HashMap<&'static str, &'static str>>
 | 
					    -> Option<HashMap<&'static str, Translation<'static>>>
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    let translations = LAYOUT_NAMES.iter()
 | 
					    let translations = LAYOUT_NAMES.iter()
 | 
				
			||||||
        .find(|(name, _data)| {
 | 
					        .find(|(name, _data)| {
 | 
				
			||||||
@ -63,7 +78,7 @@ pub fn get_layout_names(lang: &str)
 | 
				
			|||||||
    translations.map(make_mapping)
 | 
					    translations.map(make_mapping)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn parse_line(line: &str) -> Option<(&str, &str)> {
 | 
					fn parse_line(line: &str) -> Option<(&str, Translation)> {
 | 
				
			||||||
    let comment = line.trim().starts_with("#");
 | 
					    let comment = line.trim().starts_with("#");
 | 
				
			||||||
    if comment {
 | 
					    if comment {
 | 
				
			||||||
        None
 | 
					        None
 | 
				
			||||||
@ -71,11 +86,11 @@ fn parse_line(line: &str) -> Option<(&str, &str)> {
 | 
				
			|||||||
        let mut iter = line.splitn(2, " ");
 | 
					        let mut iter = line.splitn(2, " ");
 | 
				
			||||||
        let name = iter.next().unwrap();
 | 
					        let name = iter.next().unwrap();
 | 
				
			||||||
        // will skip empty and unfinished lines
 | 
					        // will skip empty and unfinished lines
 | 
				
			||||||
        iter.next().map(|tr| (name, tr.trim()))
 | 
					        iter.next().map(|tr| (name, Translation(tr.trim())))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn make_mapping(data: &str) -> HashMap<&str, &str> {
 | 
					fn make_mapping(data: &str) -> HashMap<&str, Translation> {
 | 
				
			||||||
    HashMap::from_iter(
 | 
					    HashMap::from_iter(
 | 
				
			||||||
        data.split("\n")
 | 
					        data.split("\n")
 | 
				
			||||||
            .filter_map(parse_line)
 | 
					            .filter_map(parse_line)
 | 
				
			||||||
@ -86,10 +101,17 @@ fn make_mapping(data: &str) -> HashMap<&str, &str> {
 | 
				
			|||||||
mod test {
 | 
					mod test {
 | 
				
			||||||
    use super::*;
 | 
					    use super::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn check_overlays_present() {
 | 
				
			||||||
 | 
					        for name in get_overlays() {
 | 
				
			||||||
 | 
					            assert!(get_keyboard(name).is_some());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
    fn mapping_line() {
 | 
					    fn mapping_line() {
 | 
				
			||||||
        assert_eq!(
 | 
					        assert_eq!(
 | 
				
			||||||
            Some(("name", "translation")),
 | 
					            Some(("name", Translation("translation"))),
 | 
				
			||||||
            parse_line("name translation")
 | 
					            parse_line("name translation")
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -21,7 +21,7 @@
 | 
				
			|||||||
use std::env;
 | 
					use std::env;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use glib::object::ObjectExt;
 | 
					use glib::object::ObjectExt;
 | 
				
			||||||
use util::Warn;
 | 
					use logging::Warn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Gathers stuff defined in C or called by C
 | 
					/// Gathers stuff defined in C or called by C
 | 
				
			||||||
pub mod c {
 | 
					pub mod c {
 | 
				
			||||||
 | 
				
			|||||||
@ -3,7 +3,7 @@
 | 
				
			|||||||
use ::data::Layout;
 | 
					use ::data::Layout;
 | 
				
			||||||
use xkbcommon::xkb;
 | 
					use xkbcommon::xkb;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use ::util::WarningHandler;
 | 
					use ::logging::WarningHandler;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub struct CountAndPrint(u32);
 | 
					pub struct CountAndPrint(u32);
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										22
									
								
								src/util.rs
									
									
									
									
									
								
							
							
						
						
									
										22
									
								
								src/util.rs
									
									
									
									
									
								
							@ -21,6 +21,7 @@ pub mod c {
 | 
				
			|||||||
    
 | 
					    
 | 
				
			||||||
    use std::borrow::ToOwned;
 | 
					    use std::borrow::ToOwned;
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
 | 
					    // The lifetime on input limits the existence of the result
 | 
				
			||||||
    pub fn as_str(s: &*const c_char) -> Result<Option<&str>, Utf8Error> {
 | 
					    pub fn as_str(s: &*const c_char) -> Result<Option<&str>, Utf8Error> {
 | 
				
			||||||
        if s.is_null() {
 | 
					        if s.is_null() {
 | 
				
			||||||
            Ok(None)
 | 
					            Ok(None)
 | 
				
			||||||
@ -189,27 +190,6 @@ impl<T> Borrow<Rc<T>> for Pointer<T> {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Sugar for logging errors in results
 | 
					 | 
				
			||||||
pub trait Warn {
 | 
					 | 
				
			||||||
    type Value;
 | 
					 | 
				
			||||||
    fn ok_warn(self, msg: &str) -> Option<Self::Value>;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl<T, E: std::error::Error> Warn for Result<T, E> {
 | 
					 | 
				
			||||||
    type Value = T;
 | 
					 | 
				
			||||||
    fn ok_warn(self, msg: &str) -> Option<T> {
 | 
					 | 
				
			||||||
        self.map_err(|e| {
 | 
					 | 
				
			||||||
            eprintln!("{}: {}", msg, e);
 | 
					 | 
				
			||||||
            e
 | 
					 | 
				
			||||||
        }).ok()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub trait WarningHandler {
 | 
					 | 
				
			||||||
    /// Handle a warning
 | 
					 | 
				
			||||||
    fn handle(&mut self, warning: &str);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[cfg(test)]
 | 
					#[cfg(test)]
 | 
				
			||||||
mod tests {
 | 
					mod tests {
 | 
				
			||||||
    use super::*;
 | 
					    use super::*;
 | 
				
			||||||
 | 
				
			|||||||
@ -58,6 +58,8 @@ foreach layout : [
 | 
				
			|||||||
    'no',
 | 
					    'no',
 | 
				
			||||||
    'number',
 | 
					    'number',
 | 
				
			||||||
    'se',
 | 
					    'se',
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    'emoji',
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
    test(
 | 
					    test(
 | 
				
			||||||
        'test_layout_' + layout,
 | 
					        'test_layout_' + layout,
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										19
									
								
								tools/meson.build
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								tools/meson.build
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					entry = configure_file(
 | 
				
			||||||
 | 
					    copy: true,
 | 
				
			||||||
 | 
					    input: 'entry.py',
 | 
				
			||||||
 | 
					    output: 'squeekboard-entry',
 | 
				
			||||||
 | 
					    install: true,
 | 
				
			||||||
 | 
					    install_dir: bindir,
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_layout = custom_target('squeekboard-test-layout',
 | 
				
			||||||
 | 
					    build_by_default: true,
 | 
				
			||||||
 | 
					    # meson doesn't track all inputs, cargo does
 | 
				
			||||||
 | 
					    build_always_stale: true,
 | 
				
			||||||
 | 
					    output: ['squeekboard-test-layout'],
 | 
				
			||||||
 | 
					    console: true,
 | 
				
			||||||
 | 
					    command: [cargo_build] + cargo_build_flags
 | 
				
			||||||
 | 
					        + ['--rename', 'test_layout', '@OUTPUT@', '--bin', 'test_layout'],
 | 
				
			||||||
 | 
					    install: true,
 | 
				
			||||||
 | 
					    install_dir: bindir,
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
		Reference in New Issue
	
	Block a user