Merge branch 'scaling' into 'master'
Stop scaling See merge request Librem5/squeekboard!339
This commit is contained in:
		@ -44,11 +44,11 @@
 | 
			
		||||
 | 
			
		||||
typedef struct _EekGtkKeyboardPrivate
 | 
			
		||||
{
 | 
			
		||||
    EekRenderer *renderer;
 | 
			
		||||
    EekRenderer *renderer; // owned, nullable
 | 
			
		||||
    EekboardContextService *eekboard_context; // unowned reference
 | 
			
		||||
    struct submission *submission; // unowned reference
 | 
			
		||||
 | 
			
		||||
    struct squeek_layout_state *layout;
 | 
			
		||||
    struct squeek_layout_state *layout; // unowned
 | 
			
		||||
    LevelKeyboard *keyboard; // unowned reference; it's kept in server-context
 | 
			
		||||
 | 
			
		||||
    GdkEventSequence *sequence; // unowned reference
 | 
			
		||||
@ -92,18 +92,21 @@ eek_gtk_keyboard_real_draw (GtkWidget *self,
 | 
			
		||||
                    pcontext);
 | 
			
		||||
 | 
			
		||||
        eek_renderer_set_allocation_size (priv->renderer,
 | 
			
		||||
                                          priv->keyboard->layout,
 | 
			
		||||
                                          allocation.width,
 | 
			
		||||
                                          allocation.height);
 | 
			
		||||
        eek_renderer_set_scale_factor (priv->renderer,
 | 
			
		||||
                                       gtk_widget_get_scale_factor (self));
 | 
			
		||||
    }
 | 
			
		||||
    eek_renderer_render_keyboard (priv->renderer, priv->submission, cr);
 | 
			
		||||
 | 
			
		||||
    eek_renderer_render_keyboard (priv->renderer, priv->submission, cr, priv->keyboard);
 | 
			
		||||
    return FALSE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Units of pixel size
 | 
			
		||||
static enum squeek_arrangement_kind get_type(uint32_t width, uint32_t height) {
 | 
			
		||||
    (void)height;
 | 
			
		||||
    if (width < 540) {
 | 
			
		||||
    if (width < 1080) {
 | 
			
		||||
        return ARRANGEMENT_KIND_BASE;
 | 
			
		||||
    }
 | 
			
		||||
    return ARRANGEMENT_KIND_WIDE;
 | 
			
		||||
@ -115,11 +118,11 @@ eek_gtk_keyboard_real_size_allocate (GtkWidget     *self,
 | 
			
		||||
{
 | 
			
		||||
    EekGtkKeyboardPrivate *priv =
 | 
			
		||||
        eek_gtk_keyboard_get_instance_private (EEK_GTK_KEYBOARD (self));
 | 
			
		||||
 | 
			
		||||
    uint32_t scale = (uint32_t)gtk_widget_get_scale_factor(self);
 | 
			
		||||
    // check if the change would switch types
 | 
			
		||||
    enum squeek_arrangement_kind new_type = get_type(
 | 
			
		||||
                (uint32_t)(allocation->width - allocation->x),
 | 
			
		||||
                (uint32_t)(allocation->height - allocation->y));
 | 
			
		||||
                (uint32_t)(allocation->width - allocation->x) * scale,
 | 
			
		||||
                (uint32_t)(allocation->height - allocation->y) * scale);
 | 
			
		||||
    if (priv->layout->arrangement != new_type) {
 | 
			
		||||
        priv->layout->arrangement = new_type;
 | 
			
		||||
 | 
			
		||||
@ -128,6 +131,7 @@ eek_gtk_keyboard_real_size_allocate (GtkWidget     *self,
 | 
			
		||||
 | 
			
		||||
    if (priv->renderer)
 | 
			
		||||
        eek_renderer_set_allocation_size (priv->renderer,
 | 
			
		||||
                                          priv->keyboard->layout,
 | 
			
		||||
                                          allocation->width,
 | 
			
		||||
                                          allocation->height);
 | 
			
		||||
 | 
			
		||||
@ -286,7 +290,7 @@ eek_gtk_keyboard_dispose (GObject *object)
 | 
			
		||||
    EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self);
 | 
			
		||||
 | 
			
		||||
    if (priv->renderer) {
 | 
			
		||||
        g_object_unref (priv->renderer);
 | 
			
		||||
        eek_renderer_free(priv->renderer);
 | 
			
		||||
        priv->renderer = NULL;
 | 
			
		||||
        priv->renderer = NULL;
 | 
			
		||||
    }
 | 
			
		||||
@ -341,7 +345,7 @@ on_notify_keyboard (GObject              *object,
 | 
			
		||||
    EekGtkKeyboardPrivate *priv = (EekGtkKeyboardPrivate*)eek_gtk_keyboard_get_instance_private (self);
 | 
			
		||||
    priv->keyboard = eekboard_context_service_get_keyboard(EEKBOARD_CONTEXT_SERVICE(object));
 | 
			
		||||
    if (priv->renderer) {
 | 
			
		||||
        g_object_unref(priv->renderer);
 | 
			
		||||
        eek_renderer_free(priv->renderer);
 | 
			
		||||
    }
 | 
			
		||||
    priv->renderer = NULL;
 | 
			
		||||
    gtk_widget_queue_draw(GTK_WIDGET(self));
 | 
			
		||||
 | 
			
		||||
@ -32,7 +32,6 @@
 | 
			
		||||
 | 
			
		||||
struct submission;
 | 
			
		||||
struct squeek_layout_state;
 | 
			
		||||
typedef struct _LevelKeyboard LevelKeyboard; // including causes weird bugs
 | 
			
		||||
 | 
			
		||||
G_BEGIN_DECLS
 | 
			
		||||
#define EEK_TYPE_GTK_KEYBOARD (eek_gtk_keyboard_get_type())
 | 
			
		||||
 | 
			
		||||
@ -38,10 +38,8 @@ void level_keyboard_free(LevelKeyboard *self) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
LevelKeyboard*
 | 
			
		||||
level_keyboard_new (const gchar            *keyboard_type,
 | 
			
		||||
                    enum squeek_arrangement_kind t)
 | 
			
		||||
level_keyboard_new (struct squeek_layout *layout)
 | 
			
		||||
{
 | 
			
		||||
    struct squeek_layout *layout = squeek_load_layout(keyboard_type, t);
 | 
			
		||||
    LevelKeyboard *keyboard = g_new0(LevelKeyboard, 1);
 | 
			
		||||
 | 
			
		||||
    if (!keyboard) {
 | 
			
		||||
 | 
			
		||||
@ -47,8 +47,7 @@ gchar *             eek_keyboard_get_keymap
 | 
			
		||||
                                     (LevelKeyboard *keyboard);
 | 
			
		||||
 | 
			
		||||
LevelKeyboard*
 | 
			
		||||
level_keyboard_new (const gchar            *keyboard_type,
 | 
			
		||||
                    enum squeek_arrangement_kind t);
 | 
			
		||||
level_keyboard_new (struct squeek_layout *layout);
 | 
			
		||||
void level_keyboard_free(LevelKeyboard *self);
 | 
			
		||||
 | 
			
		||||
G_END_DECLS
 | 
			
		||||
 | 
			
		||||
@ -28,27 +28,6 @@
 | 
			
		||||
#include "eek-renderer.h"
 | 
			
		||||
#include "src/style.h"
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
    PROP_0,
 | 
			
		||||
    PROP_PCONTEXT,
 | 
			
		||||
    PROP_LAST
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef struct _EekRendererPrivate
 | 
			
		||||
{
 | 
			
		||||
    LevelKeyboard *keyboard; // unowned
 | 
			
		||||
    PangoContext *pcontext; // owned
 | 
			
		||||
    GtkCssProvider *css_provider; // owned
 | 
			
		||||
    GtkStyleContext *view_context; // owned
 | 
			
		||||
    GtkStyleContext *button_context; // TODO: maybe move a copy to each button
 | 
			
		||||
 | 
			
		||||
    gdouble allocation_width;
 | 
			
		||||
    gdouble allocation_height;
 | 
			
		||||
    gint scale_factor; /* the outputs scale factor */
 | 
			
		||||
    struct transformation widget_to_layout;
 | 
			
		||||
} EekRendererPrivate;
 | 
			
		||||
 | 
			
		||||
G_DEFINE_TYPE_WITH_PRIVATE (EekRenderer, eek_renderer, G_TYPE_OBJECT)
 | 
			
		||||
 | 
			
		||||
/* eek-keyboard-drawing.c */
 | 
			
		||||
static void render_button_label (cairo_t *cr, GtkStyleContext *ctx,
 | 
			
		||||
@ -138,9 +117,7 @@ eek_render_button (EekRenderer *self,
 | 
			
		||||
               gboolean     pressed,
 | 
			
		||||
               gboolean     locked)
 | 
			
		||||
{
 | 
			
		||||
    EekRendererPrivate *priv = eek_renderer_get_instance_private (self);
 | 
			
		||||
 | 
			
		||||
    GtkStyleContext *ctx = priv->button_context;
 | 
			
		||||
    GtkStyleContext *ctx = self->button_context;
 | 
			
		||||
    /* Set the name of the button on the widget path, using the name obtained
 | 
			
		||||
       from the button's symbol. */
 | 
			
		||||
    g_autoptr (GtkWidgetPath) path = NULL;
 | 
			
		||||
@ -160,7 +137,7 @@ eek_render_button (EekRenderer *self,
 | 
			
		||||
    }
 | 
			
		||||
    gtk_style_context_add_class(ctx, outline_name);
 | 
			
		||||
 | 
			
		||||
    render_button_in_context(priv->scale_factor, cr, ctx, button);
 | 
			
		||||
    render_button_in_context(self->scale_factor, cr, ctx, button);
 | 
			
		||||
 | 
			
		||||
    // Save and restore functions don't work if gtk_render_* was used in between
 | 
			
		||||
    gtk_style_context_set_state(ctx, GTK_STATE_FLAG_NORMAL);
 | 
			
		||||
@ -218,116 +195,42 @@ render_button_label (cairo_t     *cr,
 | 
			
		||||
void
 | 
			
		||||
eek_renderer_render_keyboard (EekRenderer *self,
 | 
			
		||||
                              struct submission *submission,
 | 
			
		||||
                                   cairo_t     *cr)
 | 
			
		||||
                                   cairo_t     *cr,
 | 
			
		||||
                              LevelKeyboard *keyboard)
 | 
			
		||||
{
 | 
			
		||||
    EekRendererPrivate *priv = eek_renderer_get_instance_private (self);
 | 
			
		||||
 | 
			
		||||
    g_return_if_fail (priv->keyboard);
 | 
			
		||||
    g_return_if_fail (priv->allocation_width > 0.0);
 | 
			
		||||
    g_return_if_fail (priv->allocation_height > 0.0);
 | 
			
		||||
    g_return_if_fail (self->allocation_width > 0.0);
 | 
			
		||||
    g_return_if_fail (self->allocation_height > 0.0);
 | 
			
		||||
 | 
			
		||||
    /* Paint the background covering the entire widget area */
 | 
			
		||||
    gtk_render_background (priv->view_context,
 | 
			
		||||
    gtk_render_background (self->view_context,
 | 
			
		||||
                           cr,
 | 
			
		||||
                           0, 0,
 | 
			
		||||
                           priv->allocation_width, priv->allocation_height);
 | 
			
		||||
                           self->allocation_width, self->allocation_height);
 | 
			
		||||
 | 
			
		||||
    cairo_save(cr);
 | 
			
		||||
    cairo_translate (cr, priv->widget_to_layout.origin_x, priv->widget_to_layout.origin_y);
 | 
			
		||||
    cairo_scale (cr, priv->widget_to_layout.scale, priv->widget_to_layout.scale);
 | 
			
		||||
    cairo_translate (cr, self->widget_to_layout.origin_x, self->widget_to_layout.origin_y);
 | 
			
		||||
    cairo_scale (cr, self->widget_to_layout.scale, self->widget_to_layout.scale);
 | 
			
		||||
 | 
			
		||||
    squeek_draw_layout_base_view(priv->keyboard->layout, self, cr);
 | 
			
		||||
    squeek_layout_draw_all_changed(priv->keyboard->layout, self, cr, submission);
 | 
			
		||||
    squeek_draw_layout_base_view(keyboard->layout, self, cr);
 | 
			
		||||
    squeek_layout_draw_all_changed(keyboard->layout, self, cr, submission);
 | 
			
		||||
    cairo_restore (cr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
eek_renderer_set_property (GObject      *object,
 | 
			
		||||
                           guint         prop_id,
 | 
			
		||||
                           const GValue *value,
 | 
			
		||||
                           GParamSpec   *pspec)
 | 
			
		||||
void
 | 
			
		||||
eek_renderer_free (EekRenderer        *self)
 | 
			
		||||
{
 | 
			
		||||
    EekRendererPrivate *priv = eek_renderer_get_instance_private (
 | 
			
		||||
            EEK_RENDERER(object));
 | 
			
		||||
 | 
			
		||||
    switch (prop_id) {
 | 
			
		||||
    case PROP_PCONTEXT:
 | 
			
		||||
        priv->pcontext = g_value_get_object (value);
 | 
			
		||||
        g_object_ref (priv->pcontext);
 | 
			
		||||
        break;
 | 
			
		||||
    default:
 | 
			
		||||
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 | 
			
		||||
        break;
 | 
			
		||||
    if (self->pcontext) {
 | 
			
		||||
        g_object_unref (self->pcontext);
 | 
			
		||||
        self->pcontext = NULL;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
eek_renderer_get_property (GObject    *object,
 | 
			
		||||
                           guint       prop_id,
 | 
			
		||||
                           GValue     *value,
 | 
			
		||||
                           GParamSpec *pspec)
 | 
			
		||||
{
 | 
			
		||||
    (void)value;
 | 
			
		||||
    switch (prop_id) {
 | 
			
		||||
    default:
 | 
			
		||||
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
eek_renderer_dispose (GObject *object)
 | 
			
		||||
{
 | 
			
		||||
    EekRenderer        *self = EEK_RENDERER (object);
 | 
			
		||||
    EekRendererPrivate *priv = eek_renderer_get_instance_private (self);
 | 
			
		||||
 | 
			
		||||
    if (priv->keyboard) {
 | 
			
		||||
        priv->keyboard = NULL;
 | 
			
		||||
    }
 | 
			
		||||
    if (priv->pcontext) {
 | 
			
		||||
        g_object_unref (priv->pcontext);
 | 
			
		||||
        priv->pcontext = NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    g_object_unref(self->css_provider);
 | 
			
		||||
    g_object_unref(self->view_context);
 | 
			
		||||
    g_object_unref(self->button_context);
 | 
			
		||||
    // this is where renderer-specific surfaces would be released
 | 
			
		||||
 | 
			
		||||
    G_OBJECT_CLASS (eek_renderer_parent_class)->dispose (object);
 | 
			
		||||
    free(self);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
eek_renderer_finalize (GObject *object)
 | 
			
		||||
{
 | 
			
		||||
    EekRenderer        *self = EEK_RENDERER(object);
 | 
			
		||||
    EekRendererPrivate *priv = eek_renderer_get_instance_private (self);
 | 
			
		||||
 | 
			
		||||
    g_object_unref(priv->css_provider);
 | 
			
		||||
    g_object_unref(priv->view_context);
 | 
			
		||||
    g_object_unref(priv->button_context);
 | 
			
		||||
    G_OBJECT_CLASS (eek_renderer_parent_class)->finalize (object);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
eek_renderer_class_init (EekRendererClass *klass)
 | 
			
		||||
{
 | 
			
		||||
    GObjectClass      *gobject_class = G_OBJECT_CLASS (klass);
 | 
			
		||||
    GParamSpec        *pspec;
 | 
			
		||||
 | 
			
		||||
    gobject_class->set_property = eek_renderer_set_property;
 | 
			
		||||
    gobject_class->get_property = eek_renderer_get_property;
 | 
			
		||||
    gobject_class->dispose = eek_renderer_dispose;
 | 
			
		||||
    gobject_class->finalize = eek_renderer_finalize;
 | 
			
		||||
 | 
			
		||||
    pspec = g_param_spec_object ("pango-context",
 | 
			
		||||
                                 "Pango Context",
 | 
			
		||||
                                 "Pango Context",
 | 
			
		||||
                                 PANGO_TYPE_CONTEXT,
 | 
			
		||||
                                 G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE);
 | 
			
		||||
    g_object_class_install_property (gobject_class,
 | 
			
		||||
                                     PROP_PCONTEXT,
 | 
			
		||||
                                     pspec);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static GType new_type(char *name) {
 | 
			
		||||
    GTypeInfo info = {0};
 | 
			
		||||
    info.class_size = sizeof(GtkWidgetClass);
 | 
			
		||||
@ -355,81 +258,75 @@ static GType button_type() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
eek_renderer_init (EekRenderer *self)
 | 
			
		||||
renderer_init (EekRenderer *self)
 | 
			
		||||
{
 | 
			
		||||
    EekRendererPrivate *priv = eek_renderer_get_instance_private (self);
 | 
			
		||||
 | 
			
		||||
    priv->keyboard = NULL;
 | 
			
		||||
    priv->pcontext = NULL;
 | 
			
		||||
    priv->allocation_width = 0.0;
 | 
			
		||||
    priv->allocation_height = 0.0;
 | 
			
		||||
    priv->scale_factor = 1;
 | 
			
		||||
    self->pcontext = NULL;
 | 
			
		||||
    self->allocation_width = 0.0;
 | 
			
		||||
    self->allocation_height = 0.0;
 | 
			
		||||
    self->scale_factor = 1;
 | 
			
		||||
 | 
			
		||||
    GtkIconTheme *theme = gtk_icon_theme_get_default ();
 | 
			
		||||
 | 
			
		||||
    gtk_icon_theme_add_resource_path (theme, "/sm/puri/squeekboard/icons");
 | 
			
		||||
 | 
			
		||||
    priv->css_provider = squeek_load_style();
 | 
			
		||||
    self->css_provider = squeek_load_style();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
EekRenderer *
 | 
			
		||||
eek_renderer_new (LevelKeyboard  *keyboard,
 | 
			
		||||
                  PangoContext *pcontext)
 | 
			
		||||
{
 | 
			
		||||
    EekRenderer *renderer = g_object_new (EEK_TYPE_RENDERER,
 | 
			
		||||
                         "pango-context", pcontext,
 | 
			
		||||
                         NULL);
 | 
			
		||||
    EekRendererPrivate *priv = eek_renderer_get_instance_private (renderer);
 | 
			
		||||
    priv->keyboard = keyboard;
 | 
			
		||||
    EekRenderer *renderer = calloc(1, sizeof(EekRenderer));
 | 
			
		||||
    renderer_init(renderer);
 | 
			
		||||
    renderer->pcontext = pcontext;
 | 
			
		||||
    g_object_ref (renderer->pcontext);
 | 
			
		||||
 | 
			
		||||
    /* Create a style context for the layout */
 | 
			
		||||
    GtkWidgetPath *path = gtk_widget_path_new();
 | 
			
		||||
    gtk_widget_path_append_type(path, view_type());
 | 
			
		||||
 | 
			
		||||
    priv->view_context = gtk_style_context_new();
 | 
			
		||||
    gtk_style_context_set_path(priv->view_context, path);
 | 
			
		||||
    renderer->view_context = gtk_style_context_new();
 | 
			
		||||
    gtk_style_context_set_path(renderer->view_context, path);
 | 
			
		||||
    gtk_widget_path_unref(path);
 | 
			
		||||
    if (squeek_layout_get_kind(priv->keyboard->layout) == ARRANGEMENT_KIND_WIDE) {
 | 
			
		||||
        gtk_style_context_add_class(priv->view_context, "wide");
 | 
			
		||||
    if (squeek_layout_get_kind(keyboard->layout) == ARRANGEMENT_KIND_WIDE) {
 | 
			
		||||
        gtk_style_context_add_class(renderer->view_context, "wide");
 | 
			
		||||
    }
 | 
			
		||||
    gtk_style_context_add_provider (priv->view_context,
 | 
			
		||||
        GTK_STYLE_PROVIDER(priv->css_provider),
 | 
			
		||||
    gtk_style_context_add_provider (renderer->view_context,
 | 
			
		||||
        GTK_STYLE_PROVIDER(renderer->css_provider),
 | 
			
		||||
        GTK_STYLE_PROVIDER_PRIORITY_USER);
 | 
			
		||||
 | 
			
		||||
    /* Create a style context for the buttons */
 | 
			
		||||
    path = gtk_widget_path_new();
 | 
			
		||||
    gtk_widget_path_append_type(path, view_type());
 | 
			
		||||
    if (squeek_layout_get_kind(priv->keyboard->layout) == ARRANGEMENT_KIND_WIDE) {
 | 
			
		||||
    if (squeek_layout_get_kind(keyboard->layout) == ARRANGEMENT_KIND_WIDE) {
 | 
			
		||||
        gtk_widget_path_iter_add_class(path, -1, "wide");
 | 
			
		||||
    }
 | 
			
		||||
    gtk_widget_path_append_type(path, button_type());
 | 
			
		||||
    priv->button_context = gtk_style_context_new ();
 | 
			
		||||
    gtk_style_context_set_path(priv->button_context, path);
 | 
			
		||||
    renderer->button_context = gtk_style_context_new ();
 | 
			
		||||
    gtk_style_context_set_path(renderer->button_context, path);
 | 
			
		||||
    gtk_widget_path_unref(path);
 | 
			
		||||
    gtk_style_context_set_parent(priv->button_context, priv->view_context);
 | 
			
		||||
    gtk_style_context_set_state (priv->button_context, GTK_STATE_FLAG_NORMAL);
 | 
			
		||||
    gtk_style_context_add_provider (priv->button_context,
 | 
			
		||||
        GTK_STYLE_PROVIDER(priv->css_provider),
 | 
			
		||||
    gtk_style_context_set_parent(renderer->button_context, renderer->view_context);
 | 
			
		||||
    gtk_style_context_set_state (renderer->button_context, GTK_STATE_FLAG_NORMAL);
 | 
			
		||||
    gtk_style_context_add_provider (renderer->button_context,
 | 
			
		||||
        GTK_STYLE_PROVIDER(renderer->css_provider),
 | 
			
		||||
        GTK_STYLE_PROVIDER_PRIORITY_USER);
 | 
			
		||||
    return renderer;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
eek_renderer_set_allocation_size (EekRenderer *renderer,
 | 
			
		||||
                                  struct squeek_layout *layout,
 | 
			
		||||
                                  gdouble      width,
 | 
			
		||||
                                  gdouble      height)
 | 
			
		||||
{
 | 
			
		||||
    g_return_if_fail (EEK_IS_RENDERER(renderer));
 | 
			
		||||
    g_return_if_fail (width > 0.0 && height > 0.0);
 | 
			
		||||
 | 
			
		||||
    EekRendererPrivate *priv = eek_renderer_get_instance_private (renderer);
 | 
			
		||||
    renderer->allocation_width = width;
 | 
			
		||||
    renderer->allocation_height = height;
 | 
			
		||||
 | 
			
		||||
    priv->allocation_width = width;
 | 
			
		||||
    priv->allocation_height = height;
 | 
			
		||||
 | 
			
		||||
    priv->widget_to_layout = squeek_layout_calculate_transformation(
 | 
			
		||||
                priv->keyboard->layout,
 | 
			
		||||
                priv->allocation_width, priv->allocation_height);
 | 
			
		||||
    renderer->widget_to_layout = squeek_layout_calculate_transformation(
 | 
			
		||||
                layout,
 | 
			
		||||
                renderer->allocation_width, renderer->allocation_height);
 | 
			
		||||
 | 
			
		||||
    // This is where size-dependent surfaces would be released
 | 
			
		||||
}
 | 
			
		||||
@ -437,10 +334,7 @@ eek_renderer_set_allocation_size (EekRenderer *renderer,
 | 
			
		||||
void
 | 
			
		||||
eek_renderer_set_scale_factor (EekRenderer *renderer, gint scale)
 | 
			
		||||
{
 | 
			
		||||
    g_return_if_fail (EEK_IS_RENDERER(renderer));
 | 
			
		||||
 | 
			
		||||
    EekRendererPrivate *priv = eek_renderer_get_instance_private (renderer);
 | 
			
		||||
    priv->scale_factor = scale;
 | 
			
		||||
    renderer->scale_factor = scale;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
cairo_surface_t *
 | 
			
		||||
@ -469,9 +363,5 @@ eek_renderer_get_icon_surface (const gchar *icon_name,
 | 
			
		||||
 | 
			
		||||
struct transformation
 | 
			
		||||
eek_renderer_get_transformation (EekRenderer *renderer) {
 | 
			
		||||
    struct transformation failed = {0};
 | 
			
		||||
    g_return_val_if_fail (EEK_IS_RENDERER(renderer), failed);
 | 
			
		||||
 | 
			
		||||
    EekRendererPrivate *priv = eek_renderer_get_instance_private (renderer);
 | 
			
		||||
    return priv->widget_to_layout;
 | 
			
		||||
    return renderer->widget_to_layout;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -27,30 +27,34 @@
 | 
			
		||||
#include "eek-types.h"
 | 
			
		||||
#include "src/submission.h"
 | 
			
		||||
 | 
			
		||||
G_BEGIN_DECLS
 | 
			
		||||
struct squeek_layout;
 | 
			
		||||
 | 
			
		||||
#define EEK_TYPE_RENDERER (eek_renderer_get_type())
 | 
			
		||||
G_DECLARE_DERIVABLE_TYPE (EekRenderer, eek_renderer, EEK, RENDERER, GObject)
 | 
			
		||||
 | 
			
		||||
struct _EekRendererClass
 | 
			
		||||
/// Renders LevelKayboards
 | 
			
		||||
/// It cannot adjust styles at runtime.
 | 
			
		||||
typedef struct EekRenderer
 | 
			
		||||
{
 | 
			
		||||
    GObjectClass parent_class;
 | 
			
		||||
    PangoContext *pcontext; // owned
 | 
			
		||||
    GtkCssProvider *css_provider; // owned
 | 
			
		||||
    GtkStyleContext *view_context; // owned
 | 
			
		||||
    GtkStyleContext *button_context; // TODO: maybe move a copy to each button
 | 
			
		||||
    /// Style class for rendering the view and button CSS.
 | 
			
		||||
    gchar *extra_style; // owned
 | 
			
		||||
 | 
			
		||||
    cairo_surface_t *(* get_icon_surface)   (EekRenderer *self,
 | 
			
		||||
                                             const gchar *icon_name,
 | 
			
		||||
                                             gint         size,
 | 
			
		||||
                                             gint         scale);
 | 
			
		||||
    // Mutable state
 | 
			
		||||
    /// Background extents
 | 
			
		||||
    gdouble allocation_width;
 | 
			
		||||
    gdouble allocation_height;
 | 
			
		||||
    gint scale_factor; /* the outputs scale factor */
 | 
			
		||||
    /// Coords transformation
 | 
			
		||||
    struct transformation widget_to_layout;
 | 
			
		||||
} EekRenderer;
 | 
			
		||||
 | 
			
		||||
    /*< private >*/
 | 
			
		||||
    /* padding */
 | 
			
		||||
    gpointer pdummy[23];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
GType            eek_renderer_get_type         (void) G_GNUC_CONST;
 | 
			
		||||
EekRenderer     *eek_renderer_new              (LevelKeyboard     *keyboard,
 | 
			
		||||
                                                PangoContext    *pcontext);
 | 
			
		||||
void             eek_renderer_set_allocation_size
 | 
			
		||||
                                               (EekRenderer     *renderer,
 | 
			
		||||
                                               (EekRenderer     *renderer, struct squeek_layout *layout,
 | 
			
		||||
                                                gdouble          width,
 | 
			
		||||
                                                gdouble          height);
 | 
			
		||||
void             eek_renderer_set_scale_factor (EekRenderer     *renderer,
 | 
			
		||||
@ -61,7 +65,9 @@ cairo_surface_t *eek_renderer_get_icon_surface(const gchar     *icon_name,
 | 
			
		||||
                                                gint             scale);
 | 
			
		||||
 | 
			
		||||
void             eek_renderer_render_keyboard  (EekRenderer     *renderer, struct submission *submission,
 | 
			
		||||
                                                cairo_t         *cr);
 | 
			
		||||
                                                cairo_t         *cr, LevelKeyboard *keyboard);
 | 
			
		||||
void
 | 
			
		||||
eek_renderer_free (EekRenderer        *self);
 | 
			
		||||
 | 
			
		||||
struct transformation
 | 
			
		||||
eek_renderer_get_transformation (EekRenderer *renderer);
 | 
			
		||||
 | 
			
		||||
@ -47,7 +47,6 @@ static guint signals[LAST_SIGNAL] = { 0, };
 | 
			
		||||
 | 
			
		||||
struct _EekboardContextServicePrivate {
 | 
			
		||||
    LevelKeyboard *keyboard; // currently used keyboard
 | 
			
		||||
    GHashTable *keyboard_hash; // a table of available keyboards, per layout
 | 
			
		||||
    GSettings *settings; // Owned reference
 | 
			
		||||
 | 
			
		||||
    // Maybe TODO: it's used only for fetching layout type.
 | 
			
		||||
@ -94,13 +93,6 @@ eekboard_context_service_get_property (GObject    *object,
 | 
			
		||||
static void
 | 
			
		||||
eekboard_context_service_dispose (GObject *object)
 | 
			
		||||
{
 | 
			
		||||
    EekboardContextService *context = EEKBOARD_CONTEXT_SERVICE(object);
 | 
			
		||||
 | 
			
		||||
    if (context->priv->keyboard_hash) {
 | 
			
		||||
        g_hash_table_destroy (context->priv->keyboard_hash);
 | 
			
		||||
        context->priv->keyboard_hash = NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    G_OBJECT_CLASS (eekboard_context_service_parent_class)->
 | 
			
		||||
        dispose (object);
 | 
			
		||||
}
 | 
			
		||||
@ -148,7 +140,8 @@ eekboard_context_service_use_layout(EekboardContextService *context, struct sque
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // generic part follows
 | 
			
		||||
    LevelKeyboard *keyboard = level_keyboard_new(layout_name, state->arrangement);
 | 
			
		||||
    struct squeek_layout *layout = squeek_load_layout(layout_name, state->arrangement);
 | 
			
		||||
    LevelKeyboard *keyboard = level_keyboard_new(layout);
 | 
			
		||||
    // set as current
 | 
			
		||||
    LevelKeyboard *previous_keyboard = context->priv->keyboard;
 | 
			
		||||
    context->priv->keyboard = keyboard;
 | 
			
		||||
@ -248,12 +241,6 @@ static void
 | 
			
		||||
eekboard_context_service_init (EekboardContextService *self)
 | 
			
		||||
{
 | 
			
		||||
    self->priv = EEKBOARD_CONTEXT_SERVICE_GET_PRIVATE(self);
 | 
			
		||||
 | 
			
		||||
    self->priv->keyboard_hash =
 | 
			
		||||
        g_hash_table_new_full (g_direct_hash,
 | 
			
		||||
                               g_direct_equal,
 | 
			
		||||
                               NULL,
 | 
			
		||||
                               (GDestroyNotify)g_object_unref);
 | 
			
		||||
    const char *schema_name = "org.gnome.desktop.input-sources";
 | 
			
		||||
    GSettingsSchemaSource *ssrc = g_settings_schema_source_get_default();
 | 
			
		||||
    if (ssrc) {
 | 
			
		||||
 | 
			
		||||
@ -72,9 +72,6 @@ struct _EekboardContextServiceClass {
 | 
			
		||||
    GObjectClass parent_class;
 | 
			
		||||
 | 
			
		||||
    /*< public >*/
 | 
			
		||||
    struct squeek_view *(*create_keyboard)    (EekboardContextService *self,
 | 
			
		||||
                                        const gchar            *keyboard_type);
 | 
			
		||||
 | 
			
		||||
    /* signals */
 | 
			
		||||
    void         (*destroyed)          (EekboardContextService *self);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -35,5 +35,6 @@ mod style;
 | 
			
		||||
mod submission;
 | 
			
		||||
pub mod tests;
 | 
			
		||||
pub mod util;
 | 
			
		||||
mod ui_manager;
 | 
			
		||||
mod vkeyboard;
 | 
			
		||||
mod xdg;
 | 
			
		||||
 | 
			
		||||
@ -4,10 +4,14 @@
 | 
			
		||||
#include "wayland-client-protocol.h"
 | 
			
		||||
 | 
			
		||||
struct squeek_outputs;
 | 
			
		||||
struct squeek_output_handle {
 | 
			
		||||
    struct wl_output *output;
 | 
			
		||||
    struct squeek_outputs *outputs;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct squeek_outputs *squeek_outputs_new();
 | 
			
		||||
void squeek_outputs_free(struct squeek_outputs*);
 | 
			
		||||
void squeek_outputs_register(struct squeek_outputs*, struct wl_output *output);
 | 
			
		||||
struct wl_output *squeek_outputs_get_current(struct squeek_outputs*);
 | 
			
		||||
struct squeek_output_handle squeek_outputs_get_current(struct squeek_outputs*);
 | 
			
		||||
int32_t squeek_outputs_get_perceptual_width(struct squeek_outputs*, struct wl_output *output);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										103
									
								
								src/outputs.rs
									
									
									
									
									
								
							
							
						
						
									
										103
									
								
								src/outputs.rs
									
									
									
									
									
								
							@ -17,7 +17,7 @@ pub mod c {
 | 
			
		||||
    // Defined in C
 | 
			
		||||
 | 
			
		||||
    #[repr(transparent)]
 | 
			
		||||
    #[derive(Clone, PartialEq)]
 | 
			
		||||
    #[derive(Clone, PartialEq, Copy)]
 | 
			
		||||
    pub struct WlOutput(*const c_void);
 | 
			
		||||
 | 
			
		||||
    #[repr(C)]
 | 
			
		||||
@ -105,6 +105,24 @@ pub mod c {
 | 
			
		||||
 | 
			
		||||
    type COutputs = ::util::c::Wrapped<Outputs>;
 | 
			
		||||
 | 
			
		||||
    /// A stable reference to an output.
 | 
			
		||||
    #[derive(Clone)]
 | 
			
		||||
    #[repr(C)]
 | 
			
		||||
    pub struct OutputHandle {
 | 
			
		||||
        wl_output: WlOutput,
 | 
			
		||||
        outputs: COutputs,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl OutputHandle {
 | 
			
		||||
        // Cannot return an Output reference
 | 
			
		||||
        // because COutputs is too deeply wrapped
 | 
			
		||||
        pub fn get_state(&self) -> Option<OutputState> {
 | 
			
		||||
            let outputs = self.outputs.clone_ref();
 | 
			
		||||
            let outputs = outputs.borrow();
 | 
			
		||||
            find_output(&outputs, self.wl_output.clone()).map(|o| o.current.clone())
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Defined in Rust
 | 
			
		||||
 | 
			
		||||
    extern fn outputs_handle_geometry(
 | 
			
		||||
@ -240,46 +258,15 @@ pub mod c {
 | 
			
		||||
    
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_outputs_get_current(raw_collection: COutputs) -> WlOutput {
 | 
			
		||||
    fn squeek_outputs_get_current(raw_collection: COutputs) -> OutputHandle {
 | 
			
		||||
        let collection = raw_collection.clone_ref();
 | 
			
		||||
        let collection = collection.borrow();
 | 
			
		||||
        collection.outputs[0].output.clone()
 | 
			
		||||
        OutputHandle {
 | 
			
		||||
            wl_output: collection.outputs[0].output.clone(),
 | 
			
		||||
            outputs: raw_collection.clone(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_outputs_get_perceptual_width(
 | 
			
		||||
        raw_collection: COutputs,
 | 
			
		||||
        wl_output: WlOutput,
 | 
			
		||||
    ) -> i32 {
 | 
			
		||||
        let collection = raw_collection.clone_ref();
 | 
			
		||||
        let collection = collection.borrow();
 | 
			
		||||
 | 
			
		||||
        let output_state = find_output(&collection, wl_output)
 | 
			
		||||
            .map(|o| &o.current);
 | 
			
		||||
        match output_state {
 | 
			
		||||
            Some(OutputState {
 | 
			
		||||
                current_mode: Some(super::Mode { width, height } ),
 | 
			
		||||
                transform: Some(transform),
 | 
			
		||||
                scale,
 | 
			
		||||
            }) => {
 | 
			
		||||
                match transform {
 | 
			
		||||
                    Transform::Normal
 | 
			
		||||
                    | Transform::Rotated180
 | 
			
		||||
                    | Transform::Flipped
 | 
			
		||||
                    | Transform::FlippedRotated180 => width / scale,
 | 
			
		||||
                    _ => height / scale,
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            _ => {
 | 
			
		||||
                log_print!(
 | 
			
		||||
                    logging::Level::Surprise,
 | 
			
		||||
                    "Not enough info received on output",
 | 
			
		||||
                );
 | 
			
		||||
                0
 | 
			
		||||
            },
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    // TODO: handle unregistration
 | 
			
		||||
    
 | 
			
		||||
    fn find_output(
 | 
			
		||||
@ -305,6 +292,14 @@ pub mod c {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Generic size
 | 
			
		||||
#[derive(Clone)]
 | 
			
		||||
pub struct Size {
 | 
			
		||||
    pub width: u32,
 | 
			
		||||
    pub height: u32,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// wl_output mode
 | 
			
		||||
#[derive(Clone)]
 | 
			
		||||
struct Mode {
 | 
			
		||||
    width: i32,
 | 
			
		||||
@ -315,10 +310,16 @@ struct Mode {
 | 
			
		||||
pub struct OutputState {
 | 
			
		||||
    current_mode: Option<Mode>,
 | 
			
		||||
    transform: Option<c::Transform>,
 | 
			
		||||
    scale: i32,
 | 
			
		||||
    pub scale: i32,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl OutputState {
 | 
			
		||||
    // More properly, this would have been a builder kind of struct,
 | 
			
		||||
    // with wl_output gradually adding properties to it
 | 
			
		||||
    // before it reached a fully initialized state,
 | 
			
		||||
    // when it would transform into a struct without all (some?) of the Options.
 | 
			
		||||
    // However, it's not clear which state is fully initialized,
 | 
			
		||||
    // and whether it would make things easier at all anyway.
 | 
			
		||||
    fn uninitialized() -> OutputState {
 | 
			
		||||
        OutputState {
 | 
			
		||||
            current_mode: None,
 | 
			
		||||
@ -326,6 +327,32 @@ impl OutputState {
 | 
			
		||||
            scale: 1,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn get_pixel_size(&self) -> Option<Size> {
 | 
			
		||||
        use self::c::Transform;
 | 
			
		||||
        match self {
 | 
			
		||||
            OutputState {
 | 
			
		||||
                current_mode: Some(Mode { width, height } ),
 | 
			
		||||
                transform: Some(transform),
 | 
			
		||||
                scale: _,
 | 
			
		||||
            } => Some(
 | 
			
		||||
                match transform {
 | 
			
		||||
                    Transform::Normal
 | 
			
		||||
                    | Transform::Rotated180
 | 
			
		||||
                    | Transform::Flipped
 | 
			
		||||
                    | Transform::FlippedRotated180 => Size {
 | 
			
		||||
                        width: *width as u32,
 | 
			
		||||
                        height: *height as u32,
 | 
			
		||||
                    },
 | 
			
		||||
                    _ => Size {
 | 
			
		||||
                        width: *height as u32,
 | 
			
		||||
                        height: *width as u32,
 | 
			
		||||
                    },
 | 
			
		||||
                }
 | 
			
		||||
            ),
 | 
			
		||||
            _ => None,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct Output {
 | 
			
		||||
 | 
			
		||||
@ -43,6 +43,7 @@ struct _ServerContextService {
 | 
			
		||||
    /// Needed for instantiating the widget
 | 
			
		||||
    struct submission *submission; // unowned
 | 
			
		||||
    struct squeek_layout_state *layout;
 | 
			
		||||
    struct ui_manager *manager; // unowned
 | 
			
		||||
 | 
			
		||||
    gboolean visible;
 | 
			
		||||
    PhoshLayerSurface *window;
 | 
			
		||||
@ -86,18 +87,6 @@ on_notify_unmap (GObject    *object,
 | 
			
		||||
    g_object_set (context, "visible", FALSE, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static uint32_t
 | 
			
		||||
calculate_height(int32_t width)
 | 
			
		||||
{
 | 
			
		||||
    uint32_t height = 180;
 | 
			
		||||
    if (width < 360 && width > 0) {
 | 
			
		||||
        height = ((unsigned)width * 7 / 12); // to match 360×210
 | 
			
		||||
    } else if (width < 540) {
 | 
			
		||||
        height = 180 + (540 - (unsigned)width) * 30 / 180; // smooth transition
 | 
			
		||||
    }
 | 
			
		||||
    return height;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
on_surface_configure(PhoshLayerSurface *surface, ServerContextService *context)
 | 
			
		||||
{
 | 
			
		||||
@ -108,7 +97,7 @@ on_surface_configure(PhoshLayerSurface *surface, ServerContextService *context)
 | 
			
		||||
                 "configured-height", &height,
 | 
			
		||||
                 NULL);
 | 
			
		||||
 | 
			
		||||
    guint desired_height = calculate_height(width);
 | 
			
		||||
    guint desired_height = squeek_uiman_get_perceptual_height(context->manager);
 | 
			
		||||
    guint configured_height = (guint)height;
 | 
			
		||||
    // if height was already requested once but a different one was given
 | 
			
		||||
    // (for the same set of surrounding properties),
 | 
			
		||||
@ -131,14 +120,14 @@ make_window (ServerContextService *context)
 | 
			
		||||
    if (context->window)
 | 
			
		||||
        g_error("Window already present");
 | 
			
		||||
 | 
			
		||||
    struct wl_output *output = squeek_outputs_get_current(squeek_wayland->outputs);
 | 
			
		||||
    int32_t width = squeek_outputs_get_perceptual_width(squeek_wayland->outputs, output);
 | 
			
		||||
    uint32_t height = calculate_height(width);
 | 
			
		||||
    struct squeek_output_handle output = squeek_outputs_get_current(squeek_wayland->outputs);
 | 
			
		||||
    squeek_uiman_set_output(context->manager, output);
 | 
			
		||||
    uint32_t height = squeek_uiman_get_perceptual_height(context->manager);
 | 
			
		||||
 | 
			
		||||
    context->window = g_object_new (
 | 
			
		||||
        PHOSH_TYPE_LAYER_SURFACE,
 | 
			
		||||
        "layer-shell", squeek_wayland->layer_shell,
 | 
			
		||||
        "wl-output", output,
 | 
			
		||||
        "wl-output", output.output,
 | 
			
		||||
        "height", height,
 | 
			
		||||
        "anchor", ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM
 | 
			
		||||
                  | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT
 | 
			
		||||
@ -322,11 +311,12 @@ server_context_service_init (ServerContextService *state) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ServerContextService *
 | 
			
		||||
server_context_service_new (EekboardContextService *state, struct submission *submission, struct squeek_layout_state *layout)
 | 
			
		||||
server_context_service_new (EekboardContextService *state, struct submission *submission, struct squeek_layout_state *layout, struct ui_manager *uiman)
 | 
			
		||||
{
 | 
			
		||||
    ServerContextService *ui = g_object_new (SERVER_TYPE_CONTEXT_SERVICE, NULL);
 | 
			
		||||
    ui->submission = submission;
 | 
			
		||||
    ui->state = state;
 | 
			
		||||
    ui->layout = layout;
 | 
			
		||||
    ui->manager = uiman;
 | 
			
		||||
    return ui;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -20,6 +20,7 @@
 | 
			
		||||
 | 
			
		||||
#include "src/layout.h"
 | 
			
		||||
#include "src/submission.h"
 | 
			
		||||
#include "ui_manager.h"
 | 
			
		||||
 | 
			
		||||
G_BEGIN_DECLS
 | 
			
		||||
 | 
			
		||||
@ -36,7 +37,7 @@ typedef struct _ServerContextService ServerContextService;
 | 
			
		||||
GType         server_context_service_get_type
 | 
			
		||||
                                              (void) G_GNUC_CONST;
 | 
			
		||||
 | 
			
		||||
ServerContextService *server_context_service_new(EekboardContextService *state, struct submission *submission, struct squeek_layout_state *layout);
 | 
			
		||||
ServerContextService *server_context_service_new(EekboardContextService *state, struct submission *submission, struct squeek_layout_state *layout, struct ui_manager *uiman);
 | 
			
		||||
enum squeek_arrangement_kind server_context_service_get_layout_type(ServerContextService *);
 | 
			
		||||
void server_context_service_show_keyboard (ServerContextService *context);
 | 
			
		||||
void server_context_service_hide_keyboard (ServerContextService *context);
 | 
			
		||||
 | 
			
		||||
@ -32,6 +32,7 @@
 | 
			
		||||
#include "outputs.h"
 | 
			
		||||
#include "submission.h"
 | 
			
		||||
#include "server-context-service.h"
 | 
			
		||||
#include "ui_manager.h"
 | 
			
		||||
#include "wayland.h"
 | 
			
		||||
 | 
			
		||||
#include <gdk/gdkwayland.h>
 | 
			
		||||
@ -45,6 +46,7 @@ struct squeekboard {
 | 
			
		||||
    ServerContextService *ui_context; // mess, includes the entire UI
 | 
			
		||||
    struct submission *submission; // Wayland text input handling.
 | 
			
		||||
    struct squeek_layout_state layout_choice; // Currently wanted layout.
 | 
			
		||||
    struct ui_manager *ui_manager; // UI shape tracker/chooser. TODO: merge with layuot choice
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -201,6 +203,8 @@ main (int argc, char **argv)
 | 
			
		||||
        g_warning("Wayland input method interface not available");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    instance.ui_manager = squeek_uiman_new();
 | 
			
		||||
 | 
			
		||||
    instance.settings_context = eekboard_context_service_new(&instance.layout_choice);
 | 
			
		||||
 | 
			
		||||
    // set up dbus
 | 
			
		||||
@ -282,7 +286,8 @@ main (int argc, char **argv)
 | 
			
		||||
    ServerContextService *ui_context = server_context_service_new(
 | 
			
		||||
                instance.settings_context,
 | 
			
		||||
                instance.submission,
 | 
			
		||||
                &instance.layout_choice);
 | 
			
		||||
                &instance.layout_choice,
 | 
			
		||||
                instance.ui_manager);
 | 
			
		||||
    if (!ui_context) {
 | 
			
		||||
        g_error("Could not initialize GUI");
 | 
			
		||||
        exit(1);
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										14
									
								
								src/ui_manager.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/ui_manager.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,14 @@
 | 
			
		||||
#ifndef UI_MANAGER__
 | 
			
		||||
#define UI_MANAGER__
 | 
			
		||||
 | 
			
		||||
#include <inttypes.h>
 | 
			
		||||
 | 
			
		||||
#include "outputs.h"
 | 
			
		||||
 | 
			
		||||
struct ui_manager;
 | 
			
		||||
 | 
			
		||||
struct ui_manager *squeek_uiman_new();
 | 
			
		||||
void squeek_uiman_set_output(struct ui_manager *uiman, struct squeek_output_handle output);
 | 
			
		||||
uint32_t squeek_uiman_get_perceptual_height(struct ui_manager *uiman);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										81
									
								
								src/ui_manager.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								src/ui_manager.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,81 @@
 | 
			
		||||
/* Copyright (C) 2020 Purism SPC
 | 
			
		||||
 * SPDX-License-Identifier: GPL-3.0+
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*! Centrally manages the shape of the UI widgets, and the choice of layout.
 | 
			
		||||
 * 
 | 
			
		||||
 * Coordinates this based on information collated from all possible sources.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
use std::cmp::min;
 | 
			
		||||
use ::outputs::c::OutputHandle;
 | 
			
		||||
 | 
			
		||||
mod c {
 | 
			
		||||
    use super::*;
 | 
			
		||||
    use ::util::c::Wrapped;
 | 
			
		||||
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_uiman_new() -> Wrapped<Manager> {
 | 
			
		||||
        Wrapped::new(Manager { output: None })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Used to size the layer surface containing all the OSK widgets.
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_uiman_get_perceptual_height(
 | 
			
		||||
        uiman: Wrapped<Manager>,
 | 
			
		||||
    ) -> u32 {
 | 
			
		||||
        let uiman = uiman.clone_ref();
 | 
			
		||||
        let uiman = uiman.borrow();
 | 
			
		||||
        // TODO: what to do when there's no output?
 | 
			
		||||
        uiman.get_perceptual_height().unwrap_or(0)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_uiman_set_output(
 | 
			
		||||
        uiman: Wrapped<Manager>,
 | 
			
		||||
        output: OutputHandle,
 | 
			
		||||
    ) {
 | 
			
		||||
        let uiman = uiman.clone_ref();
 | 
			
		||||
        let mut uiman = uiman.borrow_mut();
 | 
			
		||||
        uiman.output = Some(output);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Stores current state of all things influencing what the UI should look like.
 | 
			
		||||
pub struct Manager {
 | 
			
		||||
    /// Shared output handle, current state updated whenever it's needed.
 | 
			
		||||
    // TODO: Stop assuming that the output never changes.
 | 
			
		||||
    // (There's no way for the output manager to update the ui manager.)
 | 
			
		||||
    // FIXME: Turn into an OutputState and apply relevant connections elsewhere.
 | 
			
		||||
    // Otherwise testability and predictablity is low.
 | 
			
		||||
    output: Option<OutputHandle>,
 | 
			
		||||
    //// Pixel size of the surface. Needs explicit updating.
 | 
			
		||||
    //surface_size: Option<Size>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Manager {
 | 
			
		||||
    fn get_perceptual_height(&self) -> Option<u32> {
 | 
			
		||||
        let output_info = (&self.output).as_ref()
 | 
			
		||||
            .and_then(|o| o.get_state())
 | 
			
		||||
            .map(|os| (os.scale as u32, os.get_pixel_size()));
 | 
			
		||||
        match output_info {
 | 
			
		||||
            Some((scale, Some(px_size))) => Some({
 | 
			
		||||
                let height = if (px_size.width < 720) & (px_size.width > 0) {
 | 
			
		||||
                    px_size.width * 7 / 12 // to match 360×210
 | 
			
		||||
                } else if px_size.width < 1080 {
 | 
			
		||||
                    360 + (1080 - px_size.width) * 60 / 360 // smooth transition
 | 
			
		||||
                } else {
 | 
			
		||||
                    360
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                // Don't exceed half the display size
 | 
			
		||||
                min(height, px_size.height / 2) / scale
 | 
			
		||||
            }),
 | 
			
		||||
            Some((scale, None)) => Some(360 / scale),
 | 
			
		||||
            None => None,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -98,7 +98,8 @@ pub mod c {
 | 
			
		||||
            Rc::from_raw(self.0)
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        /// Creates a new Rc reference to the same data
 | 
			
		||||
        /// Creates a new Rc reference to the same data.
 | 
			
		||||
        /// Use for accessing the underlying data as a reference.
 | 
			
		||||
        pub fn clone_ref(&self) -> Rc<RefCell<T>> {
 | 
			
		||||
            // A bit dangerous: the Rc may be in use elsewhere
 | 
			
		||||
            let used_rc = unsafe { Rc::from_raw(self.0) };
 | 
			
		||||
@ -130,6 +131,7 @@ pub mod c {
 | 
			
		||||
    impl<T> COpaquePtr for Wrapped<T> {}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Clones the underlying data structure, like ToOwned.
 | 
			
		||||
pub trait CloneOwned {
 | 
			
		||||
    type Owned;
 | 
			
		||||
    fn clone_owned(&self) -> Self::Owned;
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user