[libplybootsplash] Add keyboard class

This is the input portion of the window class.  With this commit
and subsequent commits to split out the output portions, we should
be able to drop the window class.

This will give us the flexibility we need for multi-head rendering.
This commit is contained in:
Ray Strode 2009-08-21 19:21:53 -04:00
parent 33d5702de6
commit a018e96d5f
3 changed files with 663 additions and 0 deletions

View file

@ -12,6 +12,7 @@ libplybootsplash_HEADERS = \
ply-boot-splash-plugin.h \
ply-entry.h \
ply-image.h \
ply-keyboard.h \
ply-label.h \
ply-label-plugin.h \
ply-pixel-buffer.h \
@ -35,6 +36,7 @@ libplybootsplash_la_SOURCES = \
$(libplybootsplash_HEADERS) \
ply-entry.c \
ply-image.c \
ply-keyboard.c \
ply-label.c \
ply-progress-bar.c \
ply-throbber.c \

View file

@ -0,0 +1,583 @@
/* ply-keyboard.h - APIs for putting up a keyboard screen
*
* Copyright (C) 2009 Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Written by: Ray Strode <rstrode@redhat.com>
*/
#include "config.h"
#include "ply-keyboard.h"
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <wchar.h>
#include "ply-buffer.h"
#include "ply-event-loop.h"
#include "ply-list.h"
#include "ply-logger.h"
#include "ply-renderer.h"
#include "ply-terminal.h"
#include "ply-utils.h"
#define KEY_CTRL_U ('\100' ^'U')
#define KEY_CTRL_W ('\100' ^'W')
#define KEY_CTRL_V ('\100' ^'V')
#define KEY_ESCAPE ('\100' ^'[')
#define KEY_RETURN '\r'
#define KEY_BACKSPACE '\177'
typedef void (* ply_keyboard_handler_t) (void *);
typedef struct
{
ply_keyboard_handler_t function;
void *user_data;
} ply_keyboard_closure_t;
typedef enum
{
PLY_KEYBOARD_PROVIDER_TYPE_TERMINAL,
PLY_KEYBOARD_PROVIDER_TYPE_RENDERER
} ply_keyboard_provider_type_t;
typedef struct
{
ply_terminal_t *terminal;
ply_fd_watch_t *input_watch;
ply_buffer_t *key_buffer;
} ply_keyboard_terminal_provider_t;
typedef struct
{
ply_renderer_t *renderer;
ply_renderer_input_source_t *input_source;
} ply_keyboard_renderer_provider_t;
typedef union {
ply_keyboard_renderer_provider_t *if_renderer;
ply_keyboard_terminal_provider_t *if_terminal;
} ply_keyboard_provider_t;
struct _ply_keyboard
{
ply_event_loop_t *loop;
ply_keyboard_provider_type_t provider_type;
ply_keyboard_provider_t provider;
ply_buffer_t *line_buffer;
ply_list_t *keyboard_input_handler_list;
ply_list_t *backspace_handler_list;
ply_list_t *escape_handler_list;
ply_list_t *enter_handler_list;
};
ply_keyboard_t *
ply_keyboard_new_for_terminal (ply_terminal_t *terminal)
{
ply_keyboard_t *keyboard;
keyboard = calloc (1, sizeof (ply_keyboard_t));
keyboard->line_buffer = ply_buffer_new ();
keyboard->keyboard_input_handler_list = ply_list_new ();
keyboard->backspace_handler_list = ply_list_new ();
keyboard->escape_handler_list = ply_list_new ();
keyboard->enter_handler_list = ply_list_new ();
keyboard->provider_type = PLY_KEYBOARD_PROVIDER_TYPE_TERMINAL;
keyboard->provider.if_terminal = calloc (1, sizeof (ply_keyboard_terminal_provider_t));
keyboard->provider.if_terminal->terminal = terminal;
keyboard->provider.if_terminal->key_buffer = ply_buffer_new ();
keyboard->loop = ply_event_loop_get_default ();
return keyboard;
}
ply_keyboard_t *
ply_keyboard_new_for_renderer (ply_renderer_t *renderer)
{
ply_keyboard_t *keyboard;
ply_renderer_input_source_t *input_source;
keyboard = calloc (1, sizeof (ply_keyboard_t));
keyboard->line_buffer = ply_buffer_new ();
keyboard->keyboard_input_handler_list = ply_list_new ();
keyboard->backspace_handler_list = ply_list_new ();
keyboard->escape_handler_list = ply_list_new ();
keyboard->enter_handler_list = ply_list_new ();
keyboard->provider_type = PLY_KEYBOARD_PROVIDER_TYPE_RENDERER;
keyboard->provider.if_renderer = calloc (1, sizeof (ply_keyboard_renderer_provider_t));
keyboard->provider.if_renderer->renderer = renderer;
input_source = ply_renderer_get_input_source (renderer);
keyboard->provider.if_renderer->input_source = input_source;
keyboard->loop = ply_event_loop_get_default ();
return keyboard;
}
static void
process_backspace (ply_keyboard_t *keyboard)
{
size_t bytes_to_remove;
ssize_t previous_character_size;
const char *bytes;
size_t size;
ply_list_node_t *node;
bytes = ply_buffer_get_bytes (keyboard->line_buffer);
size = ply_buffer_get_size (keyboard->line_buffer);
bytes_to_remove = MIN (size, PLY_UTF8_CHARACTER_SIZE_MAX);
while ((previous_character_size = ply_utf8_character_get_size (bytes + size - bytes_to_remove, bytes_to_remove)) < (ssize_t) bytes_to_remove)
{
if (previous_character_size > 0)
bytes_to_remove -= previous_character_size;
else
bytes_to_remove--;
}
if (bytes_to_remove <= size)
ply_buffer_remove_bytes_at_end (keyboard->line_buffer, bytes_to_remove);
for (node = ply_list_get_first_node(keyboard->backspace_handler_list);
node; node = ply_list_get_next_node(keyboard->backspace_handler_list, node))
{
ply_keyboard_closure_t *closure = ply_list_node_get_data (node);
ply_keyboard_backspace_handler_t backspace_handler =
(ply_keyboard_backspace_handler_t) closure->function;
backspace_handler (closure->user_data);
}
}
static void
process_line_erase (ply_keyboard_t *keyboard)
{
size_t size;
while ((size = ply_buffer_get_size (keyboard->line_buffer)) > 0)
process_backspace (keyboard);
}
static void
process_keyboard_input (ply_keyboard_t *keyboard,
const char *keyboard_input,
size_t character_size)
{
wchar_t key;
ply_list_node_t *node;
if ((ssize_t) mbrtowc (&key, keyboard_input, character_size, NULL) > 0)
{
switch (key)
{
case KEY_CTRL_U:
case KEY_CTRL_W:
ply_trace ("erase line!");
process_line_erase (keyboard);
return;
case KEY_CTRL_V:
ply_trace ("toggle verbose mode!");
ply_toggle_tracing ();
ply_trace ("verbose mode toggled!");
return;
case KEY_ESCAPE:
ply_trace ("escape key!");
for (node = ply_list_get_first_node(keyboard->escape_handler_list);
node; node = ply_list_get_next_node(keyboard->escape_handler_list, node))
{
ply_keyboard_closure_t *closure = ply_list_node_get_data (node);
ply_keyboard_escape_handler_t escape_handler = (ply_keyboard_escape_handler_t) closure->function;
escape_handler (closure->user_data);
}
ply_trace ("end escape key handler");
return;
case KEY_BACKSPACE:
ply_trace ("backspace key!");
process_backspace (keyboard);
return;
case KEY_RETURN:
ply_trace ("return key!");
for (node = ply_list_get_first_node(keyboard->enter_handler_list);
node; node = ply_list_get_next_node(keyboard->enter_handler_list, node))
{
ply_keyboard_closure_t *closure = ply_list_node_get_data (node);
ply_keyboard_enter_handler_t enter_handler = (ply_keyboard_enter_handler_t) closure->function;
enter_handler (closure->user_data, ply_buffer_get_bytes (keyboard->line_buffer));
}
ply_buffer_clear (keyboard->line_buffer);
return;
default:
ply_buffer_append_bytes (keyboard->line_buffer,
keyboard_input, character_size);
break;
}
}
for (node = ply_list_get_first_node(keyboard->keyboard_input_handler_list);
node; node = ply_list_get_next_node(keyboard->keyboard_input_handler_list, node))
{
ply_keyboard_closure_t *closure = ply_list_node_get_data (node);
ply_keyboard_input_handler_t keyboard_input_handler =
(ply_keyboard_input_handler_t) closure->function;
keyboard_input_handler (closure->user_data,
keyboard_input, character_size);
}
}
static void
on_key_event (ply_keyboard_t *keyboard,
ply_buffer_t *buffer)
{
const char *bytes;
size_t size, i;
bytes = ply_buffer_get_bytes (buffer);
size = ply_buffer_get_size (buffer);
i = 0;
while (i < size)
{
ssize_t character_size;
char *keyboard_input;
character_size = (ssize_t) ply_utf8_character_get_size (bytes + i, size - i);
if (character_size < 0)
break;
/* If we're at a NUL character walk through it
*/
if (character_size == 0)
{
i++;
continue;
}
keyboard_input = strndup (bytes + i, character_size);
process_keyboard_input (keyboard, keyboard_input, character_size);
i += character_size;
free (keyboard_input);
}
if (i > 0)
ply_buffer_remove_bytes (buffer, i);
}
static bool
ply_keyboard_watch_for_renderer_input (ply_keyboard_t *keyboard)
{
assert (keyboard != NULL);
if (!ply_renderer_open_input_source (keyboard->provider.if_renderer->renderer,
keyboard->provider.if_renderer->input_source))
return false;
ply_renderer_set_handler_for_input_source (keyboard->provider.if_renderer->renderer,
keyboard->provider.if_renderer->input_source,
(ply_renderer_input_source_handler_t)
on_key_event,
keyboard);
return true;
}
static void
ply_keyboard_stop_watching_for_renderer_input (ply_keyboard_t *keyboard)
{
ply_renderer_set_handler_for_input_source (keyboard->provider.if_renderer->renderer,
keyboard->provider.if_renderer->input_source,
(ply_renderer_input_source_handler_t)
NULL, NULL);
ply_renderer_close_input_source (keyboard->provider.if_renderer->renderer,
keyboard->provider.if_renderer->input_source);
}
static void
on_terminal_data (ply_keyboard_t *keyboard)
{
int terminal_fd;
terminal_fd = ply_terminal_get_fd (keyboard->provider.if_terminal->terminal);
ply_buffer_append_from_fd (keyboard->provider.if_terminal->key_buffer,
terminal_fd);
on_key_event (keyboard, keyboard->provider.if_terminal->key_buffer);
}
static bool
ply_keyboard_watch_for_terminal_input (ply_keyboard_t *keyboard)
{
int terminal_fd;
assert (keyboard != NULL);
terminal_fd = ply_terminal_get_fd (keyboard->provider.if_terminal->terminal);
keyboard->provider.if_terminal->input_watch = ply_event_loop_watch_fd (keyboard->loop, terminal_fd, PLY_EVENT_LOOP_FD_STATUS_HAS_DATA,
(ply_event_handler_t) on_terminal_data, NULL, keyboard);
return true;
}
static void
ply_keyboard_stop_watching_for_terminal_input (ply_keyboard_t *keyboard)
{
ply_event_loop_stop_watching_fd (keyboard->loop,
keyboard->provider.if_terminal->input_watch);
keyboard->provider.if_terminal->input_watch = NULL;
}
bool
ply_keyboard_watch_for_input (ply_keyboard_t *keyboard)
{
assert (keyboard != NULL);
switch (keyboard->provider_type)
{
case PLY_KEYBOARD_PROVIDER_TYPE_RENDERER:
return ply_keyboard_watch_for_renderer_input (keyboard);
case PLY_KEYBOARD_PROVIDER_TYPE_TERMINAL:
return ply_keyboard_watch_for_terminal_input (keyboard);
}
return false;
}
void
ply_keyboard_stop_watching_for_input (ply_keyboard_t *keyboard)
{
assert (keyboard != NULL);
switch (keyboard->provider_type)
{
case PLY_KEYBOARD_PROVIDER_TYPE_RENDERER:
ply_keyboard_stop_watching_for_renderer_input (keyboard);
break;
case PLY_KEYBOARD_PROVIDER_TYPE_TERMINAL:
ply_keyboard_stop_watching_for_terminal_input (keyboard);
break;
}
}
void
ply_keyboard_free (ply_keyboard_t *keyboard)
{
if (keyboard == NULL)
return;
ply_keyboard_stop_watching_for_input (keyboard);
ply_buffer_free (keyboard->line_buffer);
if (keyboard->provider_type == PLY_KEYBOARD_PROVIDER_TYPE_RENDERER)
{
free (keyboard->provider.if_renderer);
}
else
{
ply_buffer_free (keyboard->provider.if_terminal->key_buffer);
free (keyboard->provider.if_terminal);
}
free (keyboard);
}
static ply_keyboard_closure_t *
ply_keyboard_closure_new (ply_keyboard_handler_t function,
void *user_data)
{
ply_keyboard_closure_t *closure = calloc (1, sizeof (ply_keyboard_closure_t));
closure->function = function;
closure->user_data = user_data;
return closure;
}
static void
ply_keyboard_closure_free (ply_keyboard_closure_t *closure)
{
free (closure);
}
void
ply_keyboard_add_input_handler (ply_keyboard_t *keyboard,
ply_keyboard_input_handler_t input_handler,
void *user_data)
{
ply_keyboard_closure_t *closure;
assert (keyboard != NULL);
closure = ply_keyboard_closure_new ((ply_keyboard_handler_t) input_handler,
user_data);
ply_list_append_data (keyboard->keyboard_input_handler_list, closure);
}
void
ply_keyboard_remove_input_handler (ply_keyboard_t *keyboard,
ply_keyboard_input_handler_t input_handler)
{
ply_list_node_t *node;
assert (keyboard != NULL);
for (node = ply_list_get_first_node(keyboard->keyboard_input_handler_list);
node; node = ply_list_get_next_node(keyboard->keyboard_input_handler_list, node))
{
ply_keyboard_closure_t *closure = ply_list_node_get_data (node);
if ((ply_keyboard_input_handler_t) closure->function == input_handler)
{
ply_keyboard_closure_free (closure);
ply_list_remove_node (keyboard->keyboard_input_handler_list, node);
return;
}
}
}
void
ply_keyboard_add_backspace_handler (ply_keyboard_t *keyboard,
ply_keyboard_backspace_handler_t backspace_handler,
void *user_data)
{
ply_keyboard_closure_t *closure;
assert (keyboard != NULL);
closure = ply_keyboard_closure_new ((ply_keyboard_handler_t) backspace_handler,
user_data);
ply_list_append_data (keyboard->backspace_handler_list, closure);
}
void
ply_keyboard_remove_backspace_handler (ply_keyboard_t *keyboard,
ply_keyboard_backspace_handler_t backspace_handler)
{
ply_list_node_t *node;
assert (keyboard != NULL);
for (node = ply_list_get_first_node(keyboard->backspace_handler_list);
node; node = ply_list_get_next_node(keyboard->backspace_handler_list, node))
{
ply_keyboard_closure_t *closure = ply_list_node_get_data (node);
if ((ply_keyboard_backspace_handler_t) closure->function == backspace_handler)
{
ply_keyboard_closure_free (closure);
ply_list_remove_node (keyboard->backspace_handler_list, node);
return;
}
}
}
void
ply_keyboard_add_escape_handler (ply_keyboard_t *keyboard,
ply_keyboard_escape_handler_t escape_handler,
void *user_data)
{
ply_keyboard_closure_t *closure;
assert (keyboard != NULL);
closure = ply_keyboard_closure_new ((ply_keyboard_handler_t) escape_handler,
user_data);
ply_list_append_data (keyboard->escape_handler_list, closure);
}
void
ply_keyboard_remove_escape_handler (ply_keyboard_t *keyboard,
ply_keyboard_escape_handler_t escape_handler)
{
ply_list_node_t *node;
assert (keyboard != NULL);
for (node = ply_list_get_first_node(keyboard->escape_handler_list);
node; node = ply_list_get_next_node(keyboard->escape_handler_list, node))
{
ply_keyboard_closure_t *closure = ply_list_node_get_data (node);
if ((ply_keyboard_escape_handler_t) closure->function == escape_handler)
{
ply_keyboard_closure_free (closure);
ply_list_remove_node (keyboard->escape_handler_list, node);
return;
}
}
}
void
ply_keyboard_add_enter_handler (ply_keyboard_t *keyboard,
ply_keyboard_enter_handler_t enter_handler,
void *user_data)
{
ply_keyboard_closure_t *closure;
assert (keyboard != NULL);
closure = ply_keyboard_closure_new ((ply_keyboard_handler_t) enter_handler,
user_data);
ply_list_append_data (keyboard->enter_handler_list, closure);
}
void
ply_keyboard_remove_enter_handler (ply_keyboard_t *keyboard,
ply_keyboard_enter_handler_t enter_handler)
{
ply_list_node_t *node;
assert (keyboard != NULL);
for (node = ply_list_get_first_node(keyboard->enter_handler_list);
node; node = ply_list_get_next_node(keyboard->enter_handler_list, node))
{
ply_keyboard_closure_t *closure = ply_list_node_get_data (node);
if ((ply_keyboard_enter_handler_t) closure->function == enter_handler)
{
ply_keyboard_closure_free (closure);
ply_list_remove_node (keyboard->enter_handler_list, node);
return;
}
}
}
/* vim: set ts=4 sw=4 et ai ci cino={.5s,^-2,+.5s,t0,g0,e-2,n-2,p2s,(0,=.5s,:.5s */

View file

@ -0,0 +1,78 @@
/* ply-keyboard.h - APIs for putting up a splash screen
*
* Copyright (C) 2009 Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Written By: Ray Strode <rstrode@redhat.com>
*/
#ifndef PLY_KEYBOARD_H
#define PLY_KEYBOARD_H
#include <stdbool.h>
#include <stdint.h>
#include <unistd.h>
#include "ply-buffer.h"
#include "ply-event-loop.h"
#include "ply-renderer.h"
typedef struct _ply_keyboard ply_keyboard_t;
typedef void (* ply_keyboard_input_handler_t) (void *user_data,
const char *keyboard_input,
size_t character_size);
typedef void (* ply_keyboard_backspace_handler_t) (void *user_data);
typedef void (* ply_keyboard_escape_handler_t) (void *user_data);
typedef void (* ply_keyboard_enter_handler_t) (void *user_data,
const char *line);
#ifndef PLY_HIDE_FUNCTION_DECLARATIONS
ply_keyboard_t *ply_keyboard_new_for_terminal (ply_terminal_t *terminal);
ply_keyboard_t *ply_keyboard_new_for_renderer (ply_renderer_t *renderer);
void ply_keyboard_free (ply_keyboard_t *keyboard);
void ply_keyboard_add_input_handler (ply_keyboard_t *keyboard,
ply_keyboard_input_handler_t input_handler,
void *user_data);
void ply_keyboard_remove_input_handler (ply_keyboard_t *keyboard,
ply_keyboard_input_handler_t input_handler);
void ply_keyboard_add_backspace_handler (ply_keyboard_t *keyboard,
ply_keyboard_backspace_handler_t backspace_handler,
void *user_data);
void ply_keyboard_remove_backspace_handler (ply_keyboard_t *keyboard,
ply_keyboard_backspace_handler_t backspace_handler);
void ply_keyboard_add_escape_handler (ply_keyboard_t *keyboard,
ply_keyboard_escape_handler_t escape_handler,
void *user_data);
void ply_keyboard_remove_escape_handler (ply_keyboard_t *keyboard,
ply_keyboard_escape_handler_t escape_handler);
void ply_keyboard_add_enter_handler (ply_keyboard_t *keyboard,
ply_keyboard_enter_handler_t enter_handler,
void *user_data);
void ply_keyboard_remove_enter_handler (ply_keyboard_t *keyboard,
ply_keyboard_enter_handler_t enter_handler);
bool ply_keyboard_watch_for_input (ply_keyboard_t *keyboard);
void ply_keyboard_stop_watching_for_input (ply_keyboard_t *keyboard);
#endif
#endif /* PLY_KEYBOARD_H */
/* vim: set ts=4 sw=4 et ai ci cino={.5s,^-2,+.5s,t0,g0,e-2,n-2,p2s,(0,=.5s,:.5s */