This renderer is useful for testing plymouth splash plugins without leaving X. It simulates a multi-head display by creating two X windows each representing one monitor.calculate-0.9.5
parent
a8676e2c08
commit
654c14e680
@ -1,2 +1,2 @@
|
||||
SUBDIRS = frame-buffer drm
|
||||
SUBDIRS = frame-buffer drm x11
|
||||
MAINTAINERCLEANFILES = Makefile.in
|
||||
|
@ -0,0 +1,20 @@
|
||||
INCLUDES = -I$(top_srcdir) \
|
||||
-I$(srcdir)/../../../libply \
|
||||
-I$(srcdir)/../../../libplybootsplash \
|
||||
-I$(srcdir)/../../.. \
|
||||
-I$(srcdir)/../.. \
|
||||
-I$(srcdir)/.. \
|
||||
-I$(srcdir)
|
||||
|
||||
plugindir = $(libdir)/plymouth/renderers
|
||||
plugin_LTLIBRARIES = x11.la
|
||||
|
||||
x11_la_CFLAGS = $(GTK_CFLAGS) $(PLYMOUTH_CFLAGS)
|
||||
x11_la_LDFLAGS = -module -avoid-version -export-dynamic
|
||||
x11_la_LIBADD = $(PLYMOUTH_LIBS) \
|
||||
$(GTK_LIBS) \
|
||||
../../../libply/libply.la \
|
||||
../../../libplybootsplash/libplybootsplash.la
|
||||
x11_la_SOURCES = $(srcdir)/plugin.c
|
||||
|
||||
MAINTAINERCLEANFILES = Makefile.in
|
@ -0,0 +1,485 @@
|
||||
/* plugin.c - frame-backend renderer plugin
|
||||
*
|
||||
* Copyright (C) 2006-2009 Red Hat, Inc.
|
||||
* 2009 Charlie Brej <cbrej@cs.man.ac.uk>
|
||||
*
|
||||
* 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: Charlie Brej <cbrej@cs.man.ac.uk>
|
||||
* Kristian Høgsberg <krh@redhat.com>
|
||||
* Peter Jones <pjones@redhat.com>
|
||||
* Ray Strode <rstrode@redhat.com>
|
||||
*/
|
||||
#include "config.h"
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/shm.h>
|
||||
|
||||
#include <values.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <linux/fb.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <gdk/gdkkeysyms.h>
|
||||
|
||||
#include "ply-buffer.h"
|
||||
#include "ply-event-loop.h"
|
||||
#include "ply-list.h"
|
||||
#include "ply-logger.h"
|
||||
#include "ply-rectangle.h"
|
||||
#include "ply-region.h"
|
||||
#include "ply-terminal.h"
|
||||
|
||||
#include "ply-renderer.h"
|
||||
#include "ply-renderer-plugin.h"
|
||||
|
||||
struct _ply_renderer_head
|
||||
{
|
||||
ply_renderer_backend_t *backend;
|
||||
ply_pixel_buffer_t *pixel_buffer;
|
||||
ply_rectangle_t area;
|
||||
GtkWidget *window;
|
||||
cairo_surface_t *image;
|
||||
};
|
||||
|
||||
struct _ply_renderer_input_source
|
||||
{
|
||||
ply_buffer_t *key_buffer;
|
||||
ply_renderer_input_source_handler_t handler;
|
||||
void *user_data;
|
||||
};
|
||||
|
||||
struct _ply_renderer_backend
|
||||
{
|
||||
ply_event_loop_t *loop;
|
||||
ply_renderer_input_source_t input_source;
|
||||
ply_list_t *heads;
|
||||
};
|
||||
|
||||
ply_renderer_plugin_interface_t *ply_renderer_backend_get_interface (void);
|
||||
static void ply_renderer_head_redraw (ply_renderer_backend_t *backend,
|
||||
ply_renderer_head_t *head);
|
||||
static gboolean on_key_event (GtkWidget *widget,
|
||||
GdkEventKey *event,
|
||||
gpointer user_data);
|
||||
|
||||
static ply_renderer_backend_t *
|
||||
create_backend (const char *device_name,
|
||||
ply_terminal_t *terminal,
|
||||
ply_console_t *console)
|
||||
{
|
||||
ply_renderer_backend_t *backend;
|
||||
|
||||
backend = calloc (1, sizeof (ply_renderer_backend_t));
|
||||
|
||||
backend->loop = ply_event_loop_get_default ();
|
||||
backend->heads = ply_list_new ();
|
||||
backend->input_source.key_buffer = ply_buffer_new ();
|
||||
|
||||
return backend;
|
||||
}
|
||||
|
||||
static void
|
||||
destroy_backend (ply_renderer_backend_t *backend)
|
||||
{
|
||||
ply_list_node_t *node;
|
||||
node = ply_list_get_first_node (backend->heads);
|
||||
while (node != NULL)
|
||||
{
|
||||
ply_list_node_t *next_node;
|
||||
ply_renderer_head_t *head;
|
||||
|
||||
head = (ply_renderer_head_t *) ply_list_node_get_data (node);
|
||||
next_node = ply_list_get_next_node (backend->heads, node);
|
||||
|
||||
free (head);
|
||||
node = next_node;
|
||||
}
|
||||
|
||||
ply_list_free (backend->heads);
|
||||
ply_buffer_free (backend->input_source.key_buffer);
|
||||
free (backend);
|
||||
}
|
||||
|
||||
static bool
|
||||
open_device (ply_renderer_backend_t *backend)
|
||||
{
|
||||
return gtk_init_check (0, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
close_device (ply_renderer_backend_t *backend)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static bool
|
||||
query_device (ply_renderer_backend_t *backend)
|
||||
{
|
||||
ply_renderer_head_t *head;
|
||||
assert (backend != NULL);
|
||||
|
||||
if (ply_list_get_first_node (backend->heads) == NULL)
|
||||
{
|
||||
head = calloc (1, sizeof (ply_renderer_head_t));
|
||||
|
||||
head->backend = backend;
|
||||
head->area.x = 0;
|
||||
head->area.y = 0;
|
||||
head->area.width = 800; /* FIXME hardcoded */
|
||||
head->area.height = 600;
|
||||
|
||||
ply_list_append_data (backend->heads, head);
|
||||
|
||||
head = calloc (1, sizeof (ply_renderer_head_t));
|
||||
|
||||
head->backend = backend;
|
||||
head->area.x = 0;
|
||||
head->area.y = 0;
|
||||
head->area.width = 640; /* FIXME hardcoded */
|
||||
head->area.height = 480;
|
||||
|
||||
ply_list_append_data (backend->heads, head);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
screen_refresh (GtkWidget *widget,
|
||||
cairo_surface_t *image,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
cairo_t *cr;
|
||||
cr = gdk_cairo_create (gtk_widget_get_window (widget));
|
||||
cairo_rectangle (cr, x, y, width, height);
|
||||
cairo_clip (cr);
|
||||
|
||||
cairo_set_source_surface (cr, image, 0, 0);
|
||||
cairo_paint (cr);
|
||||
|
||||
cairo_destroy (cr);
|
||||
return;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
on_expose_event (GtkWidget *widget,
|
||||
GdkEventExpose *event,
|
||||
gpointer user_data)
|
||||
{
|
||||
cairo_surface_t *image = user_data;
|
||||
screen_refresh (widget,
|
||||
image,
|
||||
event->area.x,
|
||||
event->area.y,
|
||||
event->area.width,
|
||||
event->area.height);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
on_window_destroy (GtkWidget *widget,
|
||||
GdkEvent *event,
|
||||
gpointer user_data)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
on_timeout (ply_renderer_backend_t *backend)
|
||||
{
|
||||
while (gtk_events_pending ())
|
||||
gtk_main_iteration ();
|
||||
ply_event_loop_watch_for_timeout (backend->loop,
|
||||
0.01,
|
||||
(ply_event_loop_timeout_handler_t)
|
||||
on_timeout, backend);
|
||||
}
|
||||
|
||||
static bool
|
||||
map_to_device (ply_renderer_backend_t *backend)
|
||||
{
|
||||
ply_list_node_t *node;
|
||||
assert (backend != NULL);
|
||||
|
||||
node = ply_list_get_first_node (backend->heads);
|
||||
while (node != NULL)
|
||||
{
|
||||
ply_list_node_t *next_node;
|
||||
ply_renderer_head_t *head;
|
||||
uint32_t *shadow_buffer;
|
||||
|
||||
head = (ply_renderer_head_t *) ply_list_node_get_data (node);
|
||||
next_node = ply_list_get_next_node (backend->heads, node);
|
||||
|
||||
head->pixel_buffer = ply_pixel_buffer_new (head->area.width, head->area.height);
|
||||
head->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
||||
gtk_window_set_default_size (GTK_WINDOW (head->window),
|
||||
head->area.width,
|
||||
head->area.height);
|
||||
shadow_buffer = ply_pixel_buffer_get_argb32_data (head->pixel_buffer);
|
||||
head->image = cairo_image_surface_create_for_data ((unsigned char *) shadow_buffer,
|
||||
CAIRO_FORMAT_ARGB32,
|
||||
head->area.width, head->area.height,
|
||||
head->area.width * 4);
|
||||
gtk_widget_set_app_paintable (head->window, TRUE);
|
||||
gtk_widget_show_all (head->window);
|
||||
|
||||
g_signal_connect (head->window, "expose-event",
|
||||
G_CALLBACK (on_expose_event),
|
||||
head->image);
|
||||
g_signal_connect (head->window, "key-press-event",
|
||||
G_CALLBACK (on_key_event),
|
||||
&backend->input_source);
|
||||
g_signal_connect (head->window, "delete-event",
|
||||
G_CALLBACK (on_window_destroy),
|
||||
NULL);
|
||||
|
||||
ply_renderer_head_redraw (backend, head);
|
||||
node = next_node;
|
||||
}
|
||||
on_timeout (backend);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
unmap_from_device (ply_renderer_backend_t *backend)
|
||||
{
|
||||
ply_list_node_t *node;
|
||||
assert (backend != NULL);
|
||||
|
||||
node = ply_list_get_first_node (backend->heads);
|
||||
while (node != NULL)
|
||||
{
|
||||
ply_list_node_t *next_node;
|
||||
ply_renderer_head_t *head;
|
||||
|
||||
head = (ply_renderer_head_t *) ply_list_node_get_data (node);
|
||||
next_node = ply_list_get_next_node (backend->heads, node);
|
||||
|
||||
gtk_widget_destroy (head->window);
|
||||
head->window = NULL;
|
||||
ply_pixel_buffer_free (head->pixel_buffer);
|
||||
head->pixel_buffer = NULL;
|
||||
cairo_surface_destroy (head->image);
|
||||
head->image = NULL;
|
||||
|
||||
node = next_node;
|
||||
}
|
||||
ply_event_loop_stop_watching_for_timeout (backend->loop,
|
||||
(ply_event_loop_timeout_handler_t)
|
||||
on_timeout, backend);
|
||||
}
|
||||
|
||||
static void
|
||||
flush_area_to_device (ply_renderer_backend_t *backend,
|
||||
ply_renderer_head_t *head,
|
||||
ply_rectangle_t *area_to_flush)
|
||||
{
|
||||
screen_refresh (head->window,
|
||||
head->image,
|
||||
area_to_flush->x,
|
||||
area_to_flush->y,
|
||||
area_to_flush->width,
|
||||
area_to_flush->height);
|
||||
}
|
||||
|
||||
static void
|
||||
flush_head (ply_renderer_backend_t *backend,
|
||||
ply_renderer_head_t *head)
|
||||
{
|
||||
ply_region_t *updated_region;
|
||||
ply_list_t *areas_to_flush;
|
||||
ply_list_node_t *node;
|
||||
ply_pixel_buffer_t *pixel_buffer;
|
||||
|
||||
assert (backend != NULL);
|
||||
|
||||
pixel_buffer = head->pixel_buffer;
|
||||
updated_region = ply_pixel_buffer_get_updated_areas (pixel_buffer);
|
||||
areas_to_flush = ply_region_get_rectangle_list (updated_region);
|
||||
|
||||
node = ply_list_get_first_node (areas_to_flush);
|
||||
while (node != NULL)
|
||||
{
|
||||
ply_list_node_t *next_node;
|
||||
ply_rectangle_t *area_to_flush;
|
||||
|
||||
area_to_flush = (ply_rectangle_t *) ply_list_node_get_data (node);
|
||||
|
||||
next_node = ply_list_get_next_node (areas_to_flush, node);
|
||||
|
||||
flush_area_to_device (backend, head, area_to_flush);
|
||||
|
||||
node = next_node;
|
||||
}
|
||||
ply_region_clear (updated_region);
|
||||
}
|
||||
|
||||
static void
|
||||
ply_renderer_head_redraw (ply_renderer_backend_t *backend,
|
||||
ply_renderer_head_t *head)
|
||||
{
|
||||
ply_region_t *region;
|
||||
|
||||
region = ply_pixel_buffer_get_updated_areas (head->pixel_buffer);
|
||||
|
||||
ply_region_add_rectangle (region, &head->area);
|
||||
|
||||
flush_head (backend, head);
|
||||
}
|
||||
|
||||
static ply_list_t *
|
||||
get_heads (ply_renderer_backend_t *backend)
|
||||
{
|
||||
return backend->heads;
|
||||
}
|
||||
|
||||
static ply_pixel_buffer_t *
|
||||
get_buffer_for_head (ply_renderer_backend_t *backend,
|
||||
ply_renderer_head_t *head)
|
||||
{
|
||||
if (head->backend != backend)
|
||||
return NULL;
|
||||
|
||||
return head->pixel_buffer;
|
||||
}
|
||||
|
||||
static bool
|
||||
has_input_source (ply_renderer_backend_t *backend,
|
||||
ply_renderer_input_source_t *input_source)
|
||||
{
|
||||
return input_source == &backend->input_source;
|
||||
}
|
||||
|
||||
static ply_renderer_input_source_t *
|
||||
get_input_source (ply_renderer_backend_t *backend)
|
||||
{
|
||||
return &backend->input_source;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
on_key_event (GtkWidget *widget,
|
||||
GdkEventKey *event,
|
||||
gpointer user_data)
|
||||
{
|
||||
ply_renderer_input_source_t *input_source = user_data;
|
||||
|
||||
if (event->keyval == GDK_Return) /* Enter */
|
||||
{
|
||||
ply_buffer_append_bytes (input_source->key_buffer, "\r", 1);
|
||||
}
|
||||
else if (event->keyval == GDK_Escape) /* Esc */
|
||||
{
|
||||
ply_buffer_append_bytes (input_source->key_buffer, "\033", 1);
|
||||
}
|
||||
else if (event->keyval == GDK_BackSpace) /* Backspace */
|
||||
{
|
||||
ply_buffer_append_bytes (input_source->key_buffer, "\177", 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
gchar bytes[7];
|
||||
int byte_count;
|
||||
guint32 unichar;
|
||||
unichar = gdk_keyval_to_unicode (event->keyval);
|
||||
byte_count = g_unichar_to_utf8 (unichar, bytes);
|
||||
if (bytes[0] != 0)
|
||||
ply_buffer_append_bytes (input_source->key_buffer, bytes, byte_count);
|
||||
else
|
||||
ply_trace ("unknown GDK key: 0x%X \"%s\"",
|
||||
event->keyval,
|
||||
gdk_keyval_name (event->keyval));
|
||||
}
|
||||
|
||||
if (input_source->handler != NULL)
|
||||
input_source->handler (input_source->user_data, input_source->key_buffer, input_source);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static bool
|
||||
open_input_source (ply_renderer_backend_t *backend,
|
||||
ply_renderer_input_source_t *input_source)
|
||||
{
|
||||
|
||||
assert (backend != NULL);
|
||||
assert (has_input_source (backend, input_source));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
set_handler_for_input_source (ply_renderer_backend_t *backend,
|
||||
ply_renderer_input_source_t *input_source,
|
||||
ply_renderer_input_source_handler_t handler,
|
||||
void *user_data)
|
||||
{
|
||||
assert (backend != NULL);
|
||||
assert (has_input_source (backend, input_source));
|
||||
|
||||
input_source->handler = handler;
|
||||
input_source->user_data = user_data;
|
||||
}
|
||||
|
||||
static void
|
||||
close_input_source (ply_renderer_backend_t *backend,
|
||||
ply_renderer_input_source_t *input_source)
|
||||
{
|
||||
assert (backend != NULL);
|
||||
assert (has_input_source (backend, input_source));
|
||||
}
|
||||
|
||||
ply_renderer_plugin_interface_t *
|
||||
ply_renderer_backend_get_interface (void)
|
||||
{
|
||||
static ply_renderer_plugin_interface_t plugin_interface =
|
||||
{
|
||||
.create_backend = create_backend,
|
||||
.destroy_backend = destroy_backend,
|
||||
.open_device = open_device,
|
||||
.close_device = close_device,
|
||||
.query_device = query_device,
|
||||
.map_to_device = map_to_device,
|
||||
.unmap_from_device = unmap_from_device,
|
||||
.flush_head = flush_head,
|
||||
.get_heads = get_heads,
|
||||
.get_buffer_for_head = get_buffer_for_head,
|
||||
.get_input_source = get_input_source,
|
||||
.open_input_source = open_input_source,
|
||||
.set_handler_for_input_source = set_handler_for_input_source,
|
||||
.close_input_source = close_input_source
|
||||
};
|
||||
return &plugin_interface;
|
||||
}
|
||||
|
||||
/* vim: set ts=4 sw=4 et ai ci cino={.5s,^-2,+.5s,t0,g0,e-2,n-2,p2s,(0,=.5s,:.5s */
|
Loading…
Reference in new issue