[libplybootsplash] Add console class

This serves a few purposes:

1) To watch for VT changes
2) To make VT changes
3) To put the console in KD_GRAPHICS mode

The latter is handled by the window class right now, but I want to
drop the window class.
This commit is contained in:
Ray Strode 2009-09-23 02:53:21 -04:00
parent a018e96d5f
commit f183218c73
2 changed files with 476 additions and 0 deletions

View file

@ -0,0 +1,406 @@
/* ply-console.c - console APIs
*
* 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-console.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/major.h>
#include <linux/vt.h>
#include "ply-event-loop.h"
#include "ply-list.h"
#include "ply-logger.h"
#include "ply-utils.h"
#ifndef TEXT_PALETTE_SIZE
#define TEXT_PALETTE_SIZE 48
#endif
typedef struct
{
ply_console_active_vt_changed_handler_t handler;
void *user_data;
} ply_console_active_vt_changed_closure_t;
struct _ply_console
{
ply_event_loop_t *loop;
int fd;
int active_vt;
int next_active_vt;
ply_list_t *vt_change_closures;
ply_fd_watch_t *fd_watch;
uint32_t is_open : 1;
uint32_t is_watching_for_vt_changes : 1;
uint32_t should_force_text_mode : 1;
};
static bool ply_console_open_device (ply_console_t *console);
ply_console_t *
ply_console_new (void)
{
ply_console_t *console;
console = calloc (1, sizeof (ply_console_t));
console->loop = ply_event_loop_get_default ();
console->vt_change_closures = ply_list_new ();
console->fd = -1;
return console;
}
static void
ply_console_look_up_active_vt (ply_console_t *console)
{
struct vt_stat console_state = { 0 };
if (ioctl (console->fd, VT_GETSTATE, &console_state) < 0)
return;
console->active_vt = console_state.v_active;
}
void
ply_console_set_mode (ply_console_t *console,
ply_console_mode_t mode)
{
assert (console != NULL);
assert (mode == PLY_CONSOLE_MODE_TEXT || mode == PLY_CONSOLE_MODE_GRAPHICS);
if (console->should_force_text_mode)
mode = PLY_CONSOLE_MODE_TEXT;
switch (mode)
{
case PLY_CONSOLE_MODE_TEXT:
if (ioctl (console->fd, KDSETMODE, KD_TEXT) < 0)
return;
break;
case PLY_CONSOLE_MODE_GRAPHICS:
if (ioctl (console->fd, KDSETMODE, KD_GRAPHICS) < 0)
return;
break;
}
}
void
ply_console_force_text_mode (ply_console_t *console,
bool should_force)
{
console->should_force_text_mode = should_force;
}
static void
on_tty_disconnected (ply_console_t *console)
{
ply_trace ("console tty disconnected (fd %d)", console->fd);
console->fd_watch = NULL;
console->fd = -1;
ply_trace ("trying to reopen console");
ply_console_open_device (console);
}
static void
do_active_vt_changed (ply_console_t *console)
{
ply_list_node_t *node;
node = ply_list_get_first_node (console->vt_change_closures);
while (node != NULL)
{
ply_console_active_vt_changed_closure_t *closure;
ply_list_node_t *next_node;
closure = ply_list_node_get_data (node);
next_node = ply_list_get_next_node (console->vt_change_closures, node);
if (closure->handler != NULL)
closure->handler (closure->user_data, console);
node = next_node;
}
}
static void
on_leave_vt (ply_console_t *console)
{
ioctl (console->fd, VT_RELDISP, 1);
if (console->next_active_vt > 0)
{
ioctl (console->fd, VT_WAITACTIVE, console->next_active_vt);
console->next_active_vt = 0;
}
ply_console_look_up_active_vt (console);
do_active_vt_changed (console);
}
static void
on_enter_vt (ply_console_t *console)
{
ioctl (console->fd, VT_RELDISP, VT_ACKACQ);
ply_console_look_up_active_vt (console);
do_active_vt_changed (console);
}
static void
ply_console_watch_for_vt_changes (ply_console_t *console)
{
assert (console != NULL);
assert (console->fd >= 0);
struct vt_mode mode = { 0 };
if (console->is_watching_for_vt_changes)
return;
mode.mode = VT_PROCESS;
mode.relsig = SIGUSR1;
mode.acqsig = SIGUSR2;
if (!ioctl (console->fd, VT_SETMODE, &mode) < 0)
return;
ply_event_loop_watch_signal (console->loop,
SIGUSR1,
(ply_event_handler_t)
on_leave_vt, console);
ply_event_loop_watch_signal (console->loop,
SIGUSR2,
(ply_event_handler_t)
on_enter_vt, console);
console->is_watching_for_vt_changes = true;
}
static void
ply_console_stop_watching_for_vt_changes (ply_console_t *console)
{
struct vt_mode mode = { 0 };
if (!console->is_watching_for_vt_changes)
return;
console->is_watching_for_vt_changes = false;
ply_event_loop_stop_watching_signal (console->loop, SIGUSR1);
ply_event_loop_stop_watching_signal (console->loop, SIGUSR2);
mode.mode = VT_AUTO;
ioctl (console->fd, VT_SETMODE, &mode);
}
static bool
ply_console_open_device (ply_console_t *console)
{
assert (console != NULL);
assert (console->fd < 0);
assert (console->fd_watch == NULL);
console->fd = open ("/dev/tty0", O_RDWR | O_NOCTTY);
if (console->fd < 0)
return false;
console->fd_watch = ply_event_loop_watch_fd (console->loop, console->fd,
PLY_EVENT_LOOP_FD_STATUS_NONE,
(ply_event_handler_t) NULL,
(ply_event_handler_t) on_tty_disconnected,
console);
ply_console_look_up_active_vt (console);
return true;
}
bool
ply_console_open (ply_console_t *console)
{
assert (console != NULL);
if (!ply_console_open_device (console))
{
ply_trace ("could not open console: %m");
return false;
}
ply_console_watch_for_vt_changes (console);
console->is_open = true;
return true;
}
int
ply_console_get_fd (ply_console_t *console)
{
return console->fd;
}
bool
ply_console_is_open (ply_console_t *console)
{
return console->is_open;
}
void
ply_console_close (ply_console_t *console)
{
console->is_open = false;
ply_console_stop_watching_for_vt_changes (console);
if (console->fd_watch != NULL)
{
ply_trace ("stop watching tty fd");
ply_event_loop_stop_watching_fd (console->loop, console->fd_watch);
console->fd_watch = NULL;
}
close (console->fd);
console->fd = -1;
}
static void
free_vt_change_closures (ply_console_t *console)
{
ply_list_node_t *node;
node = ply_list_get_first_node (console->vt_change_closures);
while (node != NULL)
{
ply_console_active_vt_changed_closure_t *closure;
ply_list_node_t *next_node;
closure = ply_list_node_get_data (node);
next_node = ply_list_get_next_node (console->vt_change_closures, node);
free (closure);
node = next_node;
}
ply_list_free (console->vt_change_closures);
}
void
ply_console_free (ply_console_t *console)
{
if (console == NULL)
return;
ply_console_close (console);
free_vt_change_closures (console);
free (console);
}
int
ply_console_get_active_vt (ply_console_t *console)
{
return console->active_vt;
}
bool
ply_console_set_active_vt (ply_console_t *console,
int vt_number)
{
assert (console != NULL);
assert (vt_number > 0);
if (vt_number == console->active_vt)
return true;
if (ioctl (console->fd, VT_ACTIVATE, vt_number) < 0)
return false;
console->next_active_vt = vt_number;
return true;
}
void
ply_console_watch_for_active_vt_change (ply_console_t *console,
ply_console_active_vt_changed_handler_t active_vt_changed_handler,
void *user_data)
{
ply_console_active_vt_changed_closure_t *closure;
closure = calloc (1, sizeof (*closure));
closure->handler = active_vt_changed_handler;
closure->user_data = user_data;
ply_list_append_data (console->vt_change_closures, closure);
}
void
ply_console_stop_watching_for_active_vt_change (ply_console_t *console,
ply_console_active_vt_changed_handler_t active_vt_changed_handler,
void *user_data)
{
ply_list_node_t *node;
node = ply_list_get_first_node (console->vt_change_closures);
while (node != NULL)
{
ply_console_active_vt_changed_closure_t *closure;
ply_list_node_t *next_node;
closure = ply_list_node_get_data (node);
next_node = ply_list_get_next_node (console->vt_change_closures, node);
if (closure->handler == active_vt_changed_handler &&
closure->user_data == user_data)
{
free (closure);
ply_list_remove_node (console->vt_change_closures, node);
}
node = next_node;
}
}
/* 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,70 @@
/* ply-console.h - APIs for consoleing text
*
* 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_CONSOLE_H
#define PLY_CONSOLE_H
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <unistd.h>
typedef struct _ply_console ply_console_t;
typedef void (* ply_console_active_vt_changed_handler_t) (void *user_data,
ply_console_t *console);
typedef enum
{
PLY_CONSOLE_MODE_TEXT,
PLY_CONSOLE_MODE_GRAPHICS
} ply_console_mode_t;
#ifndef PLY_HIDE_FUNCTION_DECLARATIONS
ply_console_t *ply_console_new (void);
void ply_console_free (ply_console_t *console);
bool ply_console_open (ply_console_t *console);
bool ply_console_is_open (ply_console_t *console);
void ply_console_close (ply_console_t *console);
void ply_console_set_mode (ply_console_t *console,
ply_console_mode_t mode);
void ply_console_force_text_mode (ply_console_t *console,
bool should_force);
int ply_console_get_fd (ply_console_t *console);
int ply_console_get_active_vt (ply_console_t *console);
bool ply_console_set_active_vt (ply_console_t *console,
int vt_number);
void ply_console_watch_for_active_vt_change (ply_console_t *console,
ply_console_active_vt_changed_handler_t active_vt_changed_handler,
void *user_data);
void ply_console_stop_watching_for_active_vt_change (ply_console_t *console,
ply_console_active_vt_changed_handler_t active_vt_changed_handler,
void *user_data);
#endif
#endif /* PLY_CONSOLE_H */
/* vim: set ts=4 sw=4 et ai ci cino={.5s,^-2,+.5s,t0,g0,e-2,n-2,p2s,(0,=.5s,:.5s */