diff options
-rw-r--r-- | configure.ac | 1 | ||||
-rw-r--r-- | src/libplybootsplash/ply-boot-splash.c | 10 | ||||
-rw-r--r-- | src/libplybootsplash/ply-console.c | 12 | ||||
-rw-r--r-- | src/libplybootsplash/ply-console.h | 4 | ||||
-rw-r--r-- | src/libplybootsplash/ply-renderer.c | 5 | ||||
-rw-r--r-- | src/main.c | 3 | ||||
-rw-r--r-- | src/plugins/renderers/Makefile.am | 2 | ||||
-rw-r--r-- | src/plugins/renderers/drm/plugin.c | 7 | ||||
-rw-r--r-- | src/plugins/renderers/frame-buffer/plugin.c | 7 | ||||
-rw-r--r-- | src/plugins/renderers/x11/Makefile.am | 20 | ||||
-rw-r--r-- | src/plugins/renderers/x11/plugin.c | 523 |
11 files changed, 576 insertions, 18 deletions
diff --git a/configure.ac b/configure.ac index 318c80e2..e257b9d0 100644 --- a/configure.ac +++ b/configure.ac @@ -216,6 +216,7 @@ AC_OUTPUT([Makefile src/plugins/renderers/Makefile src/plugins/renderers/frame-buffer/Makefile src/plugins/renderers/drm/Makefile + src/plugins/renderers/x11/Makefile src/plugins/splash/Makefile src/plugins/splash/throbgress/Makefile src/plugins/splash/fade-throbber/Makefile diff --git a/src/libplybootsplash/ply-boot-splash.c b/src/libplybootsplash/ply-boot-splash.c index 72ee7f02..5ba1bc1d 100644 --- a/src/libplybootsplash/ply-boot-splash.c +++ b/src/libplybootsplash/ply-boot-splash.c @@ -169,8 +169,14 @@ on_keyboard_input (ply_boot_splash_t *splash, case KEY_CTRL_T: ply_trace ("toggle text mode!"); splash->should_force_text_mode = !splash->should_force_text_mode; - ply_console_force_text_mode (splash->console, - splash->should_force_text_mode); + + if (splash->should_force_text_mode) + { + ply_console_set_mode (splash->console, PLY_CONSOLE_MODE_TEXT); + ply_console_ignore_mode_changes (splash->console, true); + } + else + ply_console_ignore_mode_changes (splash->console, false); ply_trace ("text mode toggled!"); return; diff --git a/src/libplybootsplash/ply-console.c b/src/libplybootsplash/ply-console.c index 7fb92980..fb5a86db 100644 --- a/src/libplybootsplash/ply-console.c +++ b/src/libplybootsplash/ply-console.c @@ -68,7 +68,7 @@ struct _ply_console uint32_t is_open : 1; uint32_t is_watching_for_vt_changes : 1; - uint32_t should_force_text_mode : 1; + uint32_t should_ignore_mode_changes : 1; }; static bool ply_console_open_device (ply_console_t *console); @@ -106,8 +106,8 @@ ply_console_set_mode (ply_console_t *console, 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; + if (console->should_ignore_mode_changes) + return; switch (mode) { @@ -124,10 +124,10 @@ ply_console_set_mode (ply_console_t *console, } void -ply_console_force_text_mode (ply_console_t *console, - bool should_force) +ply_console_ignore_mode_changes (ply_console_t *console, + bool should_ignore) { - console->should_force_text_mode = should_force; + console->should_ignore_mode_changes = should_ignore; } static void diff --git a/src/libplybootsplash/ply-console.h b/src/libplybootsplash/ply-console.h index 36263bbc..4b45c86e 100644 --- a/src/libplybootsplash/ply-console.h +++ b/src/libplybootsplash/ply-console.h @@ -49,8 +49,8 @@ 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); +void ply_console_ignore_mode_changes (ply_console_t *console, + bool should_ignore); int ply_console_get_fd (ply_console_t *console); int ply_console_get_active_vt (ply_console_t *console); diff --git a/src/libplybootsplash/ply-renderer.c b/src/libplybootsplash/ply-renderer.c index 5410feb8..08a246ba 100644 --- a/src/libplybootsplash/ply-renderer.c +++ b/src/libplybootsplash/ply-renderer.c @@ -220,6 +220,7 @@ ply_renderer_open (ply_renderer_t *renderer) */ const char *known_plugins[] = { + PLYMOUTH_PLUGIN_PATH "renderers/x11.so", PLYMOUTH_PLUGIN_PATH "renderers/drm.so", PLYMOUTH_PLUGIN_PATH "renderers/frame-buffer.so", NULL @@ -299,10 +300,6 @@ ply_renderer_flush_head (ply_renderer_t *renderer, assert (renderer->plugin_interface != NULL); assert (head != NULL); - if (ply_console_get_active_vt (renderer->console) != - ply_terminal_get_vt_number (renderer->terminal)) - return; - renderer->plugin_interface->flush_head (renderer->backend, head); } @@ -989,9 +989,6 @@ add_default_displays_and_keyboard (state_t *state) return; } - ply_console_set_active_vt (state->console, - ply_terminal_get_vt_number (terminal)); - renderer = ply_renderer_new (NULL, terminal, state->console); if (!ply_renderer_open (renderer)) diff --git a/src/plugins/renderers/Makefile.am b/src/plugins/renderers/Makefile.am index 2fadbf40..5a449a79 100644 --- a/src/plugins/renderers/Makefile.am +++ b/src/plugins/renderers/Makefile.am @@ -1,2 +1,2 @@ -SUBDIRS = frame-buffer drm +SUBDIRS = frame-buffer drm x11 MAINTAINERCLEANFILES = Makefile.in diff --git a/src/plugins/renderers/drm/plugin.c b/src/plugins/renderers/drm/plugin.c index 2c5e1aa9..05e36fa2 100644 --- a/src/plugins/renderers/drm/plugin.c +++ b/src/plugins/renderers/drm/plugin.c @@ -783,6 +783,9 @@ map_to_device (ply_renderer_backend_t *backend) node = next_node; } + ply_console_set_active_vt (backend->console, + ply_terminal_get_vt_number (backend->terminal)); + return head_mapped; } @@ -922,6 +925,10 @@ flush_head (ply_renderer_backend_t *backend, assert (backend != NULL); + if (ply_console_get_active_vt (backend->console) != + ply_terminal_get_vt_number (backend->terminal)) + return; + ply_console_set_mode (backend->console, PLY_CONSOLE_MODE_GRAPHICS); ply_terminal_set_unbuffered_input (backend->terminal); pixel_buffer = head->pixel_buffer; diff --git a/src/plugins/renderers/frame-buffer/plugin.c b/src/plugins/renderers/frame-buffer/plugin.c index 6f45b8f4..0163daa0 100644 --- a/src/plugins/renderers/frame-buffer/plugin.c +++ b/src/plugins/renderers/frame-buffer/plugin.c @@ -491,6 +491,9 @@ map_to_device (ply_renderer_backend_t *backend) initialize_head (backend, head); + ply_console_set_active_vt (backend->console, + ply_terminal_get_vt_number (backend->terminal)); + return true; } @@ -522,6 +525,10 @@ flush_head (ply_renderer_backend_t *backend, assert (backend != NULL); assert (&backend->head == head); + if (ply_console_get_active_vt (backend->console) != + ply_terminal_get_vt_number (backend->terminal)) + return; + ply_console_set_mode (backend->console, PLY_CONSOLE_MODE_GRAPHICS); ply_terminal_set_unbuffered_input (backend->terminal); pixel_buffer = head->pixel_buffer; diff --git a/src/plugins/renderers/x11/Makefile.am b/src/plugins/renderers/x11/Makefile.am new file mode 100644 index 00000000..2bf85d27 --- /dev/null +++ b/src/plugins/renderers/x11/Makefile.am @@ -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 diff --git a/src/plugins/renderers/x11/plugin.c b/src/plugins/renderers/x11/plugin.c new file mode 100644 index 00000000..a2b61c0b --- /dev/null +++ b/src/plugins/renderers/x11/plugin.c @@ -0,0 +1,523 @@ +/* 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 <gdk/gdkx.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; + GdkPixmap *pixmap; + 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_console_t *console; + + ply_fd_watch_t *display_watch; +}; + +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_motion_notify_event (GtkWidget *widget, + GdkEventMotion *event, + gpointer user_data); +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 (); + backend->console = console; + + 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 void +on_display_event (ply_renderer_backend_t *backend) +{ + while (gtk_events_pending ()) + gtk_main_iteration (); +} + +static bool +open_device (ply_renderer_backend_t *backend) +{ + Display *display; + int display_fd; + + if (!gtk_init_check (0, NULL)) + return false; + + display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()); + display_fd = ConnectionNumber (display); + backend->display_watch = ply_event_loop_watch_fd (backend->loop, + display_fd, + PLY_EVENT_LOOP_FD_STATUS_HAS_DATA, + (ply_event_handler_t) on_display_event, + NULL, + backend); + + return true; +} + +static void +close_device (ply_renderer_backend_t *backend) +{ + ply_event_loop_stop_watching_fd (backend->loop, backend->display_watch); + backend->display_watch = NULL; + 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; + head->pixmap = gdk_pixmap_new (NULL, + head->area.width, + head->area.height, + 24); + + ply_list_append_data (backend->heads, head); + + head = calloc (1, sizeof (ply_renderer_head_t)); + + head->backend = backend; + head->area.x = 800; + head->area.y = 0; + head->area.width = 640; /* FIXME hardcoded */ + head->area.height = 480; + head->pixmap = gdk_pixmap_new (NULL, + head->area.width, + head->area.height, + 24); + + ply_list_append_data (backend->heads, head); + } + + return true; +} + +static gboolean +on_window_destroy (GtkWidget *widget, + GdkEvent *event, + gpointer user_data) +{ + return TRUE; +} + +static bool +map_to_device (ply_renderer_backend_t *backend) +{ + ply_list_node_t *node; + assert (backend != NULL); + + /* Prevent other parts of plymouth from trying to use + * the console, since X draws to it. + */ + ply_console_ignore_mode_changes (backend->console, true); + + 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_resizable (GTK_WINDOW (head->window), FALSE); + gtk_widget_set_size_request (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); + gdk_window_set_back_pixmap (head->window->window, head->pixmap, FALSE); + gdk_window_set_decorations (head->window->window, GDK_DECOR_BORDER); + gtk_window_move (GTK_WINDOW (head->window), head->area.x, head->area.y); + + gtk_widget_add_events (head->window, GDK_BUTTON1_MOTION_MASK); + + g_signal_connect (head->window, "motion-notify-event", + G_CALLBACK (on_motion_notify_event), + head); + 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; + } + 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_console_ignore_mode_changes (backend->console, false); +} + +static void +flush_area_to_device (ply_renderer_backend_t *backend, + ply_renderer_head_t *head, + ply_rectangle_t *area_to_flush, + cairo_t *cr) +{ + cairo_save (cr); + cairo_rectangle (cr, + area_to_flush->x, + area_to_flush->y, + area_to_flush->width, + area_to_flush->height); + cairo_clip (cr); + + cairo_set_source_surface (cr, head->image, 0, 0); + cairo_paint (cr); + cairo_restore (cr); +} + +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; + cairo_t *cr; + + 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); + + cr = gdk_cairo_create (head->pixmap); + + 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, cr); + gdk_window_clear_area (head->window->window, + area_to_flush->x, + area_to_flush->y, + area_to_flush->width, + area_to_flush->height); + node = next_node; + } + ply_region_clear (updated_region); + + cairo_destroy (cr); + + /* Force read-back to make sure plymouth isn't saturating the + * X server with requests + */ + g_object_unref (gdk_drawable_get_image (GDK_DRAWABLE (head->pixmap), + 0, 0, 1, 1)); +} + +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_motion_notify_event (GtkWidget *widget, + GdkEventMotion *event, + gpointer user_data) +{ + ply_renderer_head_t *head = user_data; + + gtk_window_begin_move_drag (GTK_WINDOW (head->window), 1, + event->x_root, event->y_root, event->time); + return FALSE; +} + +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 */ |