You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
872 lines
21 KiB
872 lines
21 KiB
/* ply-window.h - APIs for putting up a window screen
|
|
*
|
|
* Copyright (C) 2007 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-window.h"
|
|
|
|
#include <assert.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
#include <termios.h>
|
|
#include <unistd.h>
|
|
#include <wchar.h>
|
|
|
|
#include <linux/kd.h>
|
|
#include <linux/vt.h>
|
|
|
|
#include "ply-buffer.h"
|
|
#include "ply-event-loop.h"
|
|
#include "ply-frame-buffer.h"
|
|
#include "ply-logger.h"
|
|
#include "ply-utils.h"
|
|
|
|
#define KEY_CTRL_T ('\100' ^'T')
|
|
#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'
|
|
|
|
#ifndef CLEAR_SCREEN_SEQUENCE
|
|
#define CLEAR_SCREEN_SEQUENCE "\033[2J"
|
|
#endif
|
|
|
|
#ifndef MOVE_CURSOR_SEQUENCE
|
|
#define MOVE_CURSOR_SEQUENCE "\033[%d;%df"
|
|
#endif
|
|
|
|
#ifndef HIDE_CURSOR_SEQUENCE
|
|
#define HIDE_CURSOR_SEQUENCE "\033[?25l"
|
|
#endif
|
|
|
|
#ifndef SHOW_CURSOR_SEQUENCE
|
|
#define SHOW_CURSOR_SEQUENCE "\033[?25h"
|
|
#endif
|
|
|
|
#ifndef COLOR_SEQUENCE_FORMAT
|
|
#define COLOR_SEQUENCE_FORMAT "\033[%dm"
|
|
#endif
|
|
|
|
#ifndef FOREGROUND_COLOR_BASE
|
|
#define FOREGROUND_COLOR_BASE 30
|
|
#endif
|
|
|
|
#ifndef BACKGROUND_COLOR_BASE
|
|
#define BACKGROUND_COLOR_BASE 40
|
|
#endif
|
|
|
|
struct _ply_window
|
|
{
|
|
ply_event_loop_t *loop;
|
|
ply_buffer_t *keyboard_input_buffer;
|
|
ply_buffer_t *line_buffer;
|
|
|
|
struct termios original_term_attributes;
|
|
|
|
ply_frame_buffer_t *frame_buffer;
|
|
|
|
char *tty_name;
|
|
int tty_fd;
|
|
int vt_number;
|
|
|
|
ply_fd_watch_t *tty_fd_watch;
|
|
ply_window_mode_t mode;
|
|
ply_window_color_t foreground_color;
|
|
ply_window_color_t background_color;
|
|
|
|
int number_of_text_rows;
|
|
int number_of_text_columns;
|
|
|
|
uint32_t should_force_text_mode : 1;
|
|
uint32_t original_term_attributes_saved : 1;
|
|
|
|
ply_window_keyboard_input_handler_t keyboard_input_handler;
|
|
void *keyboard_input_handler_user_data;
|
|
|
|
ply_window_backspace_handler_t backspace_handler;
|
|
void *backspace_handler_user_data;
|
|
|
|
ply_window_escape_handler_t escape_handler;
|
|
void *escape_handler_user_data;
|
|
|
|
ply_window_enter_handler_t enter_handler;
|
|
void *enter_handler_user_data;
|
|
};
|
|
|
|
ply_window_t *
|
|
ply_window_new (int vt_number)
|
|
{
|
|
ply_window_t *window;
|
|
|
|
window = calloc (1, sizeof (ply_window_t));
|
|
window->keyboard_input_buffer = ply_buffer_new ();
|
|
window->line_buffer = ply_buffer_new ();
|
|
window->frame_buffer = ply_frame_buffer_new (NULL);
|
|
window->loop = NULL;
|
|
asprintf (&window->tty_name, "/dev/tty%d", vt_number);
|
|
window->tty_fd = -1;
|
|
window->vt_number = vt_number;
|
|
|
|
return window;
|
|
}
|
|
|
|
static void
|
|
process_backspace (ply_window_t *window)
|
|
{
|
|
ssize_t bytes_to_remove;
|
|
ssize_t previous_character_size;
|
|
const char *bytes;
|
|
size_t size;
|
|
|
|
bytes = ply_buffer_get_bytes (window->line_buffer);
|
|
size = ply_buffer_get_size (window->line_buffer);
|
|
|
|
bytes_to_remove = MB_CUR_MAX;
|
|
while ((previous_character_size = mbrlen (bytes + size - bytes_to_remove, bytes_to_remove, NULL)) < bytes_to_remove &&
|
|
previous_character_size > 0)
|
|
bytes_to_remove -= previous_character_size;
|
|
|
|
if (bytes_to_remove <= size)
|
|
{
|
|
ply_buffer_remove_bytes_at_end (window->line_buffer, bytes_to_remove);
|
|
|
|
if (window->backspace_handler != NULL)
|
|
window->backspace_handler (window->backspace_handler_user_data);
|
|
}
|
|
}
|
|
|
|
static void
|
|
process_line_erase (ply_window_t *window)
|
|
{
|
|
size_t size;
|
|
|
|
while ((size = ply_buffer_get_size (window->line_buffer)) > 0)
|
|
process_backspace (window);
|
|
}
|
|
|
|
static void
|
|
process_keyboard_input (ply_window_t *window,
|
|
const char *keyboard_input,
|
|
size_t character_size)
|
|
{
|
|
wchar_t key;
|
|
|
|
if (mbrtowc (&key, keyboard_input, 1, NULL) > 0)
|
|
{
|
|
switch (key)
|
|
{
|
|
case KEY_CTRL_T:
|
|
ply_trace ("toggle text mode!");
|
|
window->should_force_text_mode = !window->should_force_text_mode;
|
|
ply_window_set_mode (window, window->mode);
|
|
ply_trace ("text mode toggled!");
|
|
return;
|
|
|
|
case KEY_CTRL_U:
|
|
case KEY_CTRL_W:
|
|
ply_trace ("erase line!");
|
|
process_line_erase (window);
|
|
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!");
|
|
if (window->escape_handler != NULL)
|
|
window->escape_handler (window->escape_handler_user_data);
|
|
ply_trace ("end escape key handler");
|
|
return;
|
|
|
|
case KEY_BACKSPACE:
|
|
ply_trace ("backspace key!");
|
|
process_backspace (window);
|
|
return;
|
|
|
|
case KEY_RETURN:
|
|
ply_trace ("return key!");
|
|
|
|
if (window->enter_handler != NULL)
|
|
window->enter_handler (window->enter_handler_user_data,
|
|
ply_buffer_get_bytes (window->line_buffer));
|
|
|
|
ply_buffer_clear (window->line_buffer);
|
|
return;
|
|
|
|
default:
|
|
ply_buffer_append_bytes (window->line_buffer,
|
|
keyboard_input, character_size);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (window->keyboard_input_handler != NULL)
|
|
window->keyboard_input_handler (window->keyboard_input_handler_user_data,
|
|
keyboard_input, character_size);
|
|
}
|
|
|
|
static void
|
|
check_buffer_for_key_events (ply_window_t *window)
|
|
{
|
|
const char *bytes;
|
|
size_t size, i;
|
|
|
|
bytes = ply_buffer_get_bytes (window->keyboard_input_buffer);
|
|
size = ply_buffer_get_size (window->keyboard_input_buffer);
|
|
|
|
i = 0;
|
|
while (i < size)
|
|
{
|
|
ssize_t character_size;
|
|
char *keyboard_input;
|
|
|
|
character_size = (ssize_t) mbrlen (bytes + i, size - i, NULL);
|
|
|
|
if (character_size < 0)
|
|
break;
|
|
|
|
keyboard_input = strndup (bytes + i, character_size);
|
|
|
|
process_keyboard_input (window, keyboard_input, character_size);
|
|
|
|
free (keyboard_input);
|
|
|
|
i += character_size;
|
|
}
|
|
|
|
if (i > 0)
|
|
ply_buffer_remove_bytes (window->keyboard_input_buffer, i);
|
|
}
|
|
|
|
static void
|
|
on_key_event (ply_window_t *window)
|
|
{
|
|
ply_buffer_append_from_fd (window->keyboard_input_buffer, window->tty_fd);
|
|
|
|
check_buffer_for_key_events (window);
|
|
}
|
|
|
|
static bool
|
|
ply_window_set_unbuffered_input (ply_window_t *window)
|
|
{
|
|
struct termios term_attributes;
|
|
|
|
tcgetattr (window->tty_fd, &term_attributes);
|
|
|
|
if (!window->original_term_attributes_saved)
|
|
{
|
|
window->original_term_attributes = term_attributes;
|
|
window->original_term_attributes_saved = true;
|
|
}
|
|
|
|
cfmakeraw (&term_attributes);
|
|
|
|
/* Make \n return go to the beginning of the next line */
|
|
term_attributes.c_oflag |= ONLCR;
|
|
|
|
if (tcsetattr (window->tty_fd, TCSAFLUSH, &term_attributes) != 0)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool
|
|
ply_window_set_buffered_input (ply_window_t *window)
|
|
{
|
|
if (!window->original_term_attributes_saved)
|
|
return false;
|
|
|
|
if (tcsetattr (window->tty_fd, TCSAFLUSH, &window->original_term_attributes) != 0)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
static int
|
|
get_active_vt (void)
|
|
{
|
|
int console_fd;
|
|
struct vt_stat console_state = { 0 };
|
|
|
|
console_fd = open ("/dev/tty0", O_RDONLY | O_NOCTTY);
|
|
|
|
if (console_fd < 0)
|
|
goto out;
|
|
|
|
if (ioctl (console_fd, VT_GETSTATE, &console_state) < 0)
|
|
goto out;
|
|
|
|
out:
|
|
if (console_fd >= 0)
|
|
close (console_fd);
|
|
|
|
return console_state.v_active;
|
|
}
|
|
|
|
bool
|
|
ply_window_look_up_geometry (ply_window_t *window)
|
|
{
|
|
struct winsize window_size;
|
|
|
|
ply_trace ("looking up window text geometry");
|
|
|
|
if (ioctl (window->tty_fd, TIOCGWINSZ, &window_size) < 0)
|
|
{
|
|
ply_trace ("could not read window text geometry: %m");
|
|
return false;
|
|
}
|
|
|
|
window->number_of_text_rows = window_size.ws_row;
|
|
window->number_of_text_columns = window_size.ws_col;
|
|
|
|
ply_trace ("window is now %dx%d text cells",
|
|
window->number_of_text_columns,
|
|
window->number_of_text_rows);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
ply_window_open (ply_window_t *window)
|
|
{
|
|
assert (window != NULL);
|
|
assert (window->tty_name != NULL);
|
|
assert (window->tty_fd < 0);
|
|
|
|
if (window->vt_number == 0)
|
|
{
|
|
window->vt_number = get_active_vt ();
|
|
free (window->tty_name);
|
|
asprintf (&window->tty_name, "/dev/tty%d", window->vt_number);
|
|
}
|
|
|
|
window->tty_fd = open (window->tty_name, O_RDWR | O_NOCTTY);
|
|
|
|
if (window->tty_fd < 0)
|
|
return false;
|
|
|
|
if (!ply_window_set_unbuffered_input (window))
|
|
return false;
|
|
|
|
if (!ply_window_set_mode (window, PLY_WINDOW_MODE_TEXT))
|
|
return false;
|
|
|
|
if (!ply_window_look_up_geometry (window))
|
|
return false;
|
|
|
|
ply_window_hide_text_cursor (window);
|
|
ply_window_set_text_cursor_position (window, 0, 0);
|
|
|
|
ply_event_loop_watch_signal (window->loop,
|
|
SIGWINCH,
|
|
(ply_event_handler_t)
|
|
ply_window_look_up_geometry,
|
|
window);
|
|
|
|
if (window->loop != NULL)
|
|
window->tty_fd_watch = ply_event_loop_watch_fd (window->loop, window->tty_fd,
|
|
PLY_EVENT_LOOP_FD_STATUS_HAS_DATA,
|
|
(ply_event_handler_t) on_key_event,
|
|
NULL, window);
|
|
|
|
/* We try to open the frame buffer, but it may fail. splash plugins can check
|
|
* to see if it's open and react accordingly
|
|
*/
|
|
ply_frame_buffer_open (window->frame_buffer);
|
|
|
|
return true;
|
|
}
|
|
|
|
void
|
|
ply_window_close (ply_window_t *window)
|
|
{
|
|
ply_window_set_text_cursor_position (window, 0, 0);
|
|
|
|
if (ply_frame_buffer_device_is_open (window->frame_buffer))
|
|
ply_frame_buffer_close (window->frame_buffer);
|
|
|
|
if (window->tty_fd_watch != NULL)
|
|
{
|
|
ply_event_loop_stop_watching_fd (window->loop, window->tty_fd_watch);
|
|
window->tty_fd_watch = NULL;
|
|
}
|
|
|
|
if (window->loop != NULL)
|
|
ply_event_loop_stop_watching_signal (window->loop, SIGWINCH);
|
|
|
|
ply_window_set_buffered_input (window);
|
|
|
|
close (window->tty_fd);
|
|
window->tty_fd = -1;
|
|
}
|
|
|
|
bool
|
|
ply_window_set_mode (ply_window_t *window,
|
|
ply_window_mode_t mode)
|
|
{
|
|
assert (window != NULL);
|
|
assert (mode == PLY_WINDOW_MODE_TEXT || mode == PLY_WINDOW_MODE_GRAPHICS);
|
|
|
|
if (ply_is_tracing ())
|
|
window->should_force_text_mode = true;
|
|
|
|
switch (mode)
|
|
{
|
|
case PLY_WINDOW_MODE_TEXT:
|
|
if (ioctl (window->tty_fd, KDSETMODE, KD_TEXT) < 0)
|
|
return false;
|
|
break;
|
|
|
|
case PLY_WINDOW_MODE_GRAPHICS:
|
|
if (!ply_frame_buffer_device_is_open (window->frame_buffer)
|
|
&& !ply_frame_buffer_open (window->frame_buffer))
|
|
return false;
|
|
|
|
if (ioctl (window->tty_fd, KDSETMODE,
|
|
window->should_force_text_mode? KD_TEXT : KD_GRAPHICS) < 0)
|
|
return false;
|
|
break;
|
|
}
|
|
ply_window_set_unbuffered_input (window);
|
|
|
|
window->mode = mode;
|
|
return true;
|
|
}
|
|
|
|
int
|
|
ply_window_get_number_of_text_rows (ply_window_t *window)
|
|
{
|
|
return window->number_of_text_rows;
|
|
}
|
|
|
|
int
|
|
ply_window_get_number_of_text_columns (ply_window_t *window)
|
|
{
|
|
return window->number_of_text_columns;
|
|
}
|
|
|
|
void
|
|
ply_window_set_text_cursor_position (ply_window_t *window,
|
|
int column,
|
|
int row)
|
|
{
|
|
char *sequence;
|
|
|
|
sequence = NULL;
|
|
asprintf (&sequence, MOVE_CURSOR_SEQUENCE, row, column);
|
|
write (window->tty_fd, sequence, strlen (sequence));
|
|
free (sequence);
|
|
}
|
|
|
|
void
|
|
ply_window_clear_screen (ply_window_t *window)
|
|
{
|
|
write (window->tty_fd, CLEAR_SCREEN_SEQUENCE, strlen (CLEAR_SCREEN_SEQUENCE));
|
|
|
|
ply_window_set_text_cursor_position (window, 0, 0);
|
|
|
|
if (ply_frame_buffer_device_is_open (window->frame_buffer))
|
|
ply_frame_buffer_fill_with_color (window->frame_buffer, NULL, 0.0, 0.0, 0.0, 1.0);
|
|
}
|
|
|
|
void
|
|
ply_window_set_background_color (ply_window_t *window,
|
|
ply_window_color_t color)
|
|
{
|
|
char *sequence;
|
|
|
|
sequence = NULL;
|
|
asprintf (&sequence, COLOR_SEQUENCE_FORMAT,
|
|
BACKGROUND_COLOR_BASE + color);
|
|
write (window->tty_fd, sequence, strlen (sequence));
|
|
free (sequence);
|
|
|
|
window->background_color = color;
|
|
}
|
|
|
|
void
|
|
ply_window_set_foreground_color (ply_window_t *window,
|
|
ply_window_color_t color)
|
|
{
|
|
char *sequence;
|
|
|
|
sequence = NULL;
|
|
asprintf (&sequence, COLOR_SEQUENCE_FORMAT,
|
|
FOREGROUND_COLOR_BASE + color);
|
|
write (window->tty_fd, sequence, strlen (sequence));
|
|
free (sequence);
|
|
|
|
window->foreground_color = color;
|
|
}
|
|
|
|
ply_window_color_t
|
|
ply_window_get_background_color (ply_window_t *window)
|
|
{
|
|
return window->background_color;
|
|
}
|
|
|
|
ply_window_color_t
|
|
ply_window_get_foreground_color (ply_window_t *window)
|
|
{
|
|
return window->foreground_color;
|
|
}
|
|
|
|
static uint8_t *
|
|
ply_window_get_color_palette (ply_window_t *window)
|
|
{
|
|
uint8_t *palette;
|
|
|
|
palette = malloc (48);
|
|
|
|
if (ioctl (window->tty_fd, GIO_CMAP, palette) < 0)
|
|
{
|
|
free (palette);
|
|
return NULL;
|
|
}
|
|
|
|
return palette;
|
|
}
|
|
|
|
static bool
|
|
ply_window_set_color_palette (ply_window_t *window,
|
|
uint8_t *palette)
|
|
{
|
|
if (ioctl (window->tty_fd, PIO_CMAP, palette) < 0)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
uint32_t
|
|
ply_window_get_color_hex_value (ply_window_t *window,
|
|
ply_window_color_t color)
|
|
{
|
|
uint8_t *palette;
|
|
uint8_t red, green, blue;
|
|
uint32_t hex_value;
|
|
|
|
assert (window != NULL);
|
|
assert (color >= 0 && color <= PLY_WINDOW_COLOR_WHITE);
|
|
|
|
palette = ply_window_get_color_palette (window);
|
|
|
|
if (palette == NULL)
|
|
return 0;
|
|
|
|
red = (uint8_t) *(palette + 3 * color);
|
|
green = (uint8_t) *(palette + 3 * color + 1);
|
|
blue = (uint8_t) *(palette + 3 * color + 2);
|
|
free (palette);
|
|
|
|
hex_value = red << 16 | green << 8 | blue;
|
|
|
|
return hex_value;
|
|
}
|
|
|
|
void
|
|
ply_window_set_color_hex_value (ply_window_t *window,
|
|
ply_window_color_t color,
|
|
uint32_t hex_value)
|
|
{
|
|
uint8_t *palette;
|
|
uint8_t red, green, blue;
|
|
|
|
assert (window != NULL);
|
|
assert (color >= 0 && color <= PLY_WINDOW_COLOR_WHITE);
|
|
|
|
palette = ply_window_get_color_palette (window);
|
|
|
|
if (palette == NULL)
|
|
return;
|
|
|
|
red = (uint8_t) ((hex_value >> 16) & 0xff);
|
|
green = (uint8_t) ((hex_value >> 8) & 0xff);
|
|
blue = (uint8_t) (hex_value & 0xff);
|
|
|
|
*(palette + 3 * color) = red;
|
|
*(palette + 3 * color + 1) = green;
|
|
*(palette + 3 * color + 2) = blue;
|
|
|
|
ply_window_set_color_palette (window, palette);
|
|
free (palette);
|
|
}
|
|
|
|
void
|
|
ply_window_hide_text_cursor (ply_window_t *window)
|
|
{
|
|
write (window->tty_fd, HIDE_CURSOR_SEQUENCE, strlen (HIDE_CURSOR_SEQUENCE));
|
|
}
|
|
|
|
void
|
|
ply_window_show_text_cursor (ply_window_t *window)
|
|
{
|
|
write (window->tty_fd, SHOW_CURSOR_SEQUENCE, strlen (SHOW_CURSOR_SEQUENCE));
|
|
}
|
|
|
|
static void
|
|
ply_window_detach_from_event_loop (ply_window_t *window)
|
|
{
|
|
assert (window != NULL);
|
|
window->loop = NULL;
|
|
window->tty_fd_watch = NULL;
|
|
}
|
|
|
|
void
|
|
ply_window_free (ply_window_t *window)
|
|
{
|
|
if (window == NULL)
|
|
return;
|
|
|
|
if (window->loop != NULL)
|
|
ply_event_loop_stop_watching_for_exit (window->loop,
|
|
(ply_event_loop_exit_handler_t)
|
|
ply_window_detach_from_event_loop,
|
|
window);
|
|
|
|
ply_window_close (window);
|
|
|
|
ply_buffer_free (window->keyboard_input_buffer);
|
|
ply_buffer_free (window->line_buffer);
|
|
|
|
ply_frame_buffer_free (window->frame_buffer);
|
|
|
|
free (window);
|
|
}
|
|
|
|
void
|
|
ply_window_set_keyboard_input_handler (ply_window_t *window,
|
|
ply_window_keyboard_input_handler_t input_handler,
|
|
void *user_data)
|
|
{
|
|
assert (window != NULL);
|
|
|
|
window->keyboard_input_handler = input_handler;
|
|
window->keyboard_input_handler_user_data = user_data;
|
|
}
|
|
|
|
void
|
|
ply_window_set_backspace_handler (ply_window_t *window,
|
|
ply_window_backspace_handler_t backspace_handler,
|
|
void *user_data)
|
|
{
|
|
assert (window != NULL);
|
|
|
|
window->backspace_handler = backspace_handler;
|
|
window->backspace_handler_user_data = user_data;
|
|
}
|
|
|
|
void
|
|
ply_window_set_escape_handler (ply_window_t *window,
|
|
ply_window_escape_handler_t escape_handler,
|
|
void *user_data)
|
|
{
|
|
assert (window != NULL);
|
|
|
|
window->escape_handler = escape_handler;
|
|
window->escape_handler_user_data = user_data;
|
|
}
|
|
|
|
void
|
|
ply_window_set_enter_handler (ply_window_t *window,
|
|
ply_window_enter_handler_t enter_handler,
|
|
void *user_data)
|
|
{
|
|
assert (window != NULL);
|
|
|
|
window->enter_handler = enter_handler;
|
|
window->enter_handler_user_data = user_data;
|
|
}
|
|
|
|
void
|
|
ply_window_attach_to_event_loop (ply_window_t *window,
|
|
ply_event_loop_t *loop)
|
|
{
|
|
assert (window != NULL);
|
|
assert (loop != NULL);
|
|
assert (window->loop == NULL);
|
|
|
|
window->loop = loop;
|
|
|
|
if (window->tty_fd >= 0)
|
|
window->tty_fd_watch = ply_event_loop_watch_fd (window->loop, window->tty_fd,
|
|
PLY_EVENT_LOOP_FD_STATUS_HAS_DATA,
|
|
(ply_event_handler_t) on_key_event,
|
|
NULL, window);
|
|
|
|
ply_event_loop_watch_for_exit (loop, (ply_event_loop_exit_handler_t)
|
|
ply_window_detach_from_event_loop,
|
|
window);
|
|
}
|
|
|
|
ply_frame_buffer_t *
|
|
ply_window_get_frame_buffer (ply_window_t *window)
|
|
{
|
|
return window->frame_buffer;
|
|
}
|
|
|
|
static bool
|
|
switch_to_vt (int tty_fd,
|
|
int vt_number)
|
|
{
|
|
if (ioctl (tty_fd, VT_ACTIVATE, vt_number) < 0)
|
|
return false;
|
|
|
|
ioctl (tty_fd, VT_WAITACTIVE, vt_number);
|
|
|
|
return get_active_vt () == vt_number;
|
|
}
|
|
|
|
bool
|
|
ply_window_take_console (ply_window_t *window)
|
|
{
|
|
assert (window != NULL);
|
|
|
|
return switch_to_vt (window->tty_fd, window->vt_number);
|
|
}
|
|
|
|
bool
|
|
ply_window_give_console (ply_window_t *window,
|
|
int vt_number)
|
|
{
|
|
char *tty_name;
|
|
int tty_fd;
|
|
bool vt_switched;
|
|
|
|
assert (window != NULL);
|
|
assert (vt_number > 0);
|
|
assert (vt_number != window->vt_number);
|
|
|
|
tty_name = NULL;
|
|
asprintf (&tty_name, "/dev/tty%d", vt_number);
|
|
tty_fd = open (tty_name, O_RDONLY | O_NOCTTY);
|
|
|
|
if (tty_fd < 0)
|
|
{
|
|
free (tty_name);
|
|
return false;
|
|
}
|
|
free (tty_name);
|
|
|
|
vt_switched = switch_to_vt (tty_fd, vt_number);
|
|
|
|
close (tty_fd);
|
|
|
|
return vt_switched;
|
|
}
|
|
|
|
#ifdef PLY_WINDOW_ENABLE_TEST
|
|
|
|
#include <stdio.h>
|
|
|
|
#include "ply-event-loop.h"
|
|
#include "ply-window.h"
|
|
|
|
static void
|
|
on_timeout (ply_window_t *window,
|
|
ply_event_loop_t *loop)
|
|
{
|
|
ply_event_loop_exit (loop, 0);
|
|
}
|
|
|
|
static void
|
|
on_keypress (ply_window_t *window,
|
|
const char *keyboard_input)
|
|
{
|
|
printf ("key '%c' (0x%x) was pressed\n",
|
|
keyboard_input[0], (unsigned int) keyboard_input[0]);
|
|
}
|
|
|
|
int
|
|
main (int argc,
|
|
char **argv)
|
|
{
|
|
ply_event_loop_t *loop;
|
|
ply_window_t *window;
|
|
int exit_code;
|
|
int vt_number;
|
|
|
|
exit_code = 0;
|
|
|
|
loop = ply_event_loop_new ();
|
|
|
|
vt_number = 0;
|
|
if (argc > 1)
|
|
vt_number = atoi (argv[1]);
|
|
|
|
if (vt_number <= 0)
|
|
vt_number = 1;
|
|
|
|
window = ply_window_new (vt_number);
|
|
ply_window_attach_to_event_loop (window, loop);
|
|
ply_window_set_keyboard_input_handler (window,
|
|
(ply_window_keyboard_input_handler_t)
|
|
on_keypress, window);
|
|
|
|
if (!ply_window_open (window))
|
|
{
|
|
ply_save_errno ();
|
|
perror ("could not open window");
|
|
ply_restore_errno ();
|
|
return errno;
|
|
}
|
|
|
|
if (!ply_window_take_console (window))
|
|
{
|
|
ply_save_errno ();
|
|
ply_error ("could not move console to vt %d: %m", vt_number);
|
|
ply_restore_errno ();
|
|
return errno;
|
|
}
|
|
|
|
if (!ply_window_set_mode (window, PLY_WINDOW_MODE_TEXT))
|
|
{
|
|
ply_save_errno ();
|
|
perror ("could not set window for graphics mode");
|
|
ply_restore_errno ();
|
|
}
|
|
|
|
ply_event_loop_watch_for_timeout (loop,
|
|
15.0,
|
|
(ply_event_loop_timeout_handler_t)
|
|
on_timeout,
|
|
window);
|
|
exit_code = ply_event_loop_run (loop);
|
|
|
|
ply_window_close (window);
|
|
ply_window_free (window);
|
|
|
|
return exit_code;
|
|
}
|
|
|
|
#endif /* PLY_WINDOW_ENABLE_TEST */
|
|
/* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */
|