diff options
author | Ray Strode <rstrode@redhat.com> | 2007-07-22 09:09:00 -0400 |
---|---|---|
committer | Ray Strode <rstrode@redhat.com> | 2007-07-22 09:09:00 -0400 |
commit | f7a9b5cf6962e59120bcb3ff0d3a953022f6aea0 (patch) | |
tree | 7eacb5675407c49898e5570d03131562132c33f9 |
initial import
-rw-r--r-- | Makefile | 5 | ||||
-rw-r--r-- | test-screensaver-extension.c | 589 |
2 files changed, 594 insertions, 0 deletions
diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..b1925f7 --- /dev/null +++ b/Makefile @@ -0,0 +1,5 @@ +all: test-screensaver-extension + + +test-screensaver-extension: test-screensaver-extension.c + gcc `pkg-config --cflags --libs gdk-x11-2.0 xscrnsaver` ${CFLAGS} $< -o $@ diff --git a/test-screensaver-extension.c b/test-screensaver-extension.c new file mode 100644 index 0000000..808b14a --- /dev/null +++ b/test-screensaver-extension.c @@ -0,0 +1,589 @@ +#include <stdlib.h> + +#include <glib.h> + +#include <X11/Xlib.h> +#include <X11/extensions/scrnsaver.h> + +#include <gdk/gdkx.h> +#include <gdk/gdk.h> + +#include <cairo.h> + +typedef struct _TestScreensaverEngine +{ + GdkWindow *window; + + void (* draw) (struct _TestScreensaverEngine *, cairo_t *cairo_context); +} TestScreensaverEngine; + +typedef struct _TestScreensaverHead +{ + int number; + GdkRectangle area; + TestScreensaverEngine *engine; +} TestScreensaverHead; + +typedef enum _TestScreensaverState +{ + TEST_SCREENSAVER_STATE_UNKNOWN = 0, + TEST_SCREENSAVER_STATE_ACTIVE, + TEST_SCREENSAVER_STATE_INACTIVE, + TEST_SCREENSAVER_STATE_DISABLED +} TestScreensaverState; + +typedef struct _TestScreensaver +{ + GMainContext *context; + GdkScreen *screen; + GdkDrawable *drawable; + GdkWindow *toplevel_window; + gint notify_event_number; + + TestScreensaverState state; + GList *heads; + GdkRegion *head_region; + + guint timeout_id; +} TestScreensaver; + +static GdkWindow * +create_engine_window (GdkWindow *toplevel_window, + GdkRectangle *area) +{ + GdkWindow *window; + GdkWindowAttr attributes; + static gint attributes_mask = GDK_WA_COLORMAP + | GDK_WA_VISUAL + | GDK_WA_X + | GDK_WA_Y; + static GdkEventMask event_mask = GDK_EXPOSURE_MASK + | GDK_KEY_PRESS_MASK + | GDK_ENTER_NOTIFY_MASK + | GDK_LEAVE_NOTIFY_MASK + | GDK_FOCUS_CHANGE_MASK + | GDK_STRUCTURE_MASK + | GDK_BUTTON_MOTION_MASK + | GDK_POINTER_MOTION_HINT_MASK + | GDK_BUTTON_PRESS_MASK + | GDK_BUTTON_RELEASE_MASK; + + attributes.window_type = GDK_WINDOW_TOPLEVEL; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.colormap = + gdk_drawable_get_colormap (GDK_DRAWABLE (toplevel_window)); + attributes.visual = + gdk_drawable_get_visual (GDK_DRAWABLE (toplevel_window)); + attributes.x = area->x; + attributes.y = area->y; + attributes.width = area->width; + attributes.height = area->height; + attributes.event_mask = event_mask; + + window = gdk_window_new (toplevel_window, &attributes, attributes_mask); + + return window; +} + +static void +test_screensaver_engine_do_draw (TestScreensaverEngine *engine, + cairo_t *cairo_context) +{ + + cairo_set_source_rgba (cairo_context, g_random_double (), + g_random_double (), g_random_double (), + g_random_double ()); + cairo_paint (cairo_context); +} + +TestScreensaverEngine * +test_screensaver_engine_new (GdkWindow *toplevel_window, + GdkRectangle *area) +{ + TestScreensaverEngine *engine; + + engine = g_slice_new (TestScreensaverEngine); + + engine->window = create_engine_window (toplevel_window, area); + engine->draw = test_screensaver_engine_do_draw; + + return engine; +} + +void +test_screensaver_engine_free (TestScreensaverEngine *engine) +{ + gdk_window_destroy (engine->window); + free (engine); +} + +TestScreensaverHead * +test_screensaver_head_new (int monitor_number, + GdkRectangle *area) +{ + TestScreensaverHead *head; + + head = g_slice_new (TestScreensaverHead); + head->number = monitor_number; + head->area = *area; + head->engine = NULL; + + return head; +} + +void +test_screensaver_head_free (TestScreensaverHead *head) +{ + test_screensaver_engine_free (head->engine); + g_slice_free (TestScreensaverHead, head); +} + +TestScreensaver * +test_screensaver_new (GMainContext *context, + GdkScreen *screen) +{ + TestScreensaver *screensaver; + GdkWindow *root_window; + + if (context == NULL) + context = g_main_context_default (); + + root_window = gdk_screen_get_root_window (screen); + + screensaver = g_slice_new (TestScreensaver); + screensaver->context = g_main_context_ref (context); + screensaver->screen = screen; + screensaver->drawable = GDK_DRAWABLE (root_window); + screensaver->state = TEST_SCREENSAVER_STATE_UNKNOWN; + screensaver->heads = NULL; + screensaver->head_region = gdk_region_new (); + + return screensaver; +} + +void +test_screensaver_free (TestScreensaver *screensaver) +{ + g_main_context_unref (screensaver->context); + gdk_region_destroy (screensaver->head_region); + g_slice_free (TestScreensaver, screensaver); +} + +static gboolean +test_screensaver_query_for_notify_event_number (TestScreensaver *screensaver) +{ + int event_base, error_base; + + event_base = 0; + if (!XScreenSaverQueryExtension (GDK_SCREEN_XDISPLAY (screensaver->screen), + &event_base, &error_base)) + return FALSE; + + screensaver->notify_event_number = event_base + ScreenSaverNotify; + g_debug ("notify event number is %d", screensaver->notify_event_number); + + return TRUE; +} + +gboolean +test_screensaver_unset_window_background (TestScreensaver *screensaver) +{ + XSetWindowAttributes attributes = { 0 }; + GdkVisual *visual; + int x, y, width, height, border_width, depth; + guint class; + gulong mask; + + x = 0; + y = 0; + border_width = 0; + width = gdk_screen_get_width (screensaver->screen); + height = gdk_screen_get_height (screensaver->screen); + + depth = gdk_drawable_get_depth (screensaver->drawable); + visual = gdk_drawable_get_visual (screensaver->drawable); + class = InputOutput; + + mask = CWBackPixmap; + attributes.background_pixmap = None; + + gdk_error_trap_push (); + XScreenSaverSetAttributes (GDK_SCREEN_XDISPLAY (screensaver->screen), + GDK_DRAWABLE_XID (screensaver->drawable), + x, y, width, height, border_width, + depth, class, GDK_VISUAL_XVISUAL (visual), + mask, &attributes); + gdk_flush (); + if (gdk_error_trap_pop () != Success) + return FALSE; + + return TRUE; +} + +static void +update_screensaver_state_from_info (TestScreensaver *screensaver, + XScreenSaverInfo *info) +{ + switch (info->state) + { + case ScreenSaverOn: + g_debug ("server says screensaver is active"); + screensaver->state = TEST_SCREENSAVER_STATE_ACTIVE; + break; + + case ScreenSaverOff: + g_debug ("server says screensaver is inactive"); + screensaver->state = TEST_SCREENSAVER_STATE_INACTIVE; + break; + + case ScreenSaverDisabled: + g_debug ("server says screensaver is disabled"); + screensaver->state = TEST_SCREENSAVER_STATE_DISABLED; + break; + + default: + g_assert_not_reached (); + break; + } +} + +static void +update_screensaver_toplevel_window_from_info (TestScreensaver *screensaver, + XScreenSaverInfo *info) +{ + if ((screensaver->toplevel_window == NULL) || + (info->window != GDK_WINDOW_XWINDOW (screensaver->toplevel_window))) + { + GdkDisplay *display; + GdkWindow *toplevel_window; + + display = gdk_screen_get_display (screensaver->screen); + toplevel_window = gdk_window_foreign_new_for_display (display, info->window); + + if (toplevel_window != NULL) + { + g_debug ("updating screensaver window to %lx", + (gulong) GDK_WINDOW_XWINDOW (toplevel_window)); + screensaver->toplevel_window = toplevel_window; + } + else + g_error ("could not set up screensaver toplevel "); + } + else + g_debug ("screensaver toplevel is already set up"); +} + +static void +clip_area_against_head_region (TestScreensaver *screensaver, + GdkRectangle *area) +{ + GdkRegion *new_region; + + new_region = gdk_region_rectangle (area); + + gdk_region_subtract (new_region, screensaver->head_region); + gdk_region_get_clipbox (new_region, area); +} + +static void +add_area_to_head_region (TestScreensaver *screensaver, + GdkRectangle *area) +{ + gdk_region_union_with_rect (screensaver->head_region, area); +} + +static void +setup_head_geometry (TestScreensaver *screensaver) +{ + int number_of_monitors, i; + + g_assert (screensaver->heads == NULL); + + number_of_monitors = gdk_screen_get_n_monitors (screensaver->screen); + + for (i = 0; i < number_of_monitors; i++) + { + TestScreensaverHead *head; + GdkRectangle area; + + gdk_screen_get_monitor_geometry (screensaver->screen, + i, &area); + + clip_area_against_head_region (screensaver, &area); + + head = test_screensaver_head_new (i, &area); + g_debug ("head %d has geometry %dx%d+%d+%d", + head->number, head->area.x, head->area.y, + head->area.width, head->area.height); + screensaver->heads = g_list_prepend (screensaver->heads, + head); + + add_area_to_head_region (screensaver, &head->area); + } +} + +#ifdef SUPPORT_DYNAMIC_HEAD_SETUPS +static void +clear_head_geometry (TestScreensaver *screensaver) +{ + g_list_foreach (screensaver->heads, (GFunc) test_screensaver_head_free, + NULL); + g_list_free (screensaver->heads); + screensaver->heads = NULL; +} + +static void +update_head_geometry (TestScreensaver *screensaver) +{ + clear_head_geometry (screensaver); + setup_head_geometry (screensaver); +} +#endif + +static void +free_engine_from_head (TestScreensaverHead *head, + GdkWindow *toplevel_window) +{ + g_assert (head->engine->window != toplevel_window); + + test_screensaver_engine_free (head->engine); + head->engine = NULL; +} + +static void +create_engine_for_head (TestScreensaverHead *head, + GdkWindow *toplevel_window) +{ + g_assert (head->engine == NULL); + + head->engine = test_screensaver_engine_new (toplevel_window, + &head->area); +} + +static void +show_engine_for_head (TestScreensaverHead *head) +{ + TestScreensaverEngine *engine; + + engine = head->engine; + gdk_window_show (engine->window); +} + +static void +test_screensaver_fade_to_black (TestScreensaver *screensaver) +{ + cairo_t *cairo_context; + int i; + + gdk_error_trap_push (); + cairo_context = gdk_cairo_create (screensaver->toplevel_window); + cairo_set_source_rgba (cairo_context, 0.0, 0.0, 0.0, 0.5); + for (i = 0; i < 10; i++) + { + cairo_paint (cairo_context); + gdk_flush (); + } + cairo_destroy (cairo_context); + + gdk_flush (); + gdk_error_trap_push (); +} + +static void +draw_engine_for_head (TestScreensaverHead *head) +{ + cairo_t *cairo_context; + TestScreensaverEngine *engine; + + engine = head->engine; + + g_debug ("drawing engine for head %d", head->number); + cairo_context = gdk_cairo_create (engine->window); + engine->draw (engine, cairo_context); + cairo_destroy (cairo_context); + gdk_flush (); +} + +static gboolean +draw_heads (TestScreensaver *screensaver) +{ + g_debug ("drawing heads"); + g_list_foreach (screensaver->heads, (GFunc) draw_engine_for_head, NULL); + return TRUE; +} + +static void +test_screensaver_activate (TestScreensaver *screensaver) +{ + test_screensaver_fade_to_black (screensaver); + + g_list_foreach (screensaver->heads, (GFunc) create_engine_for_head, + screensaver->toplevel_window); + g_list_foreach (screensaver->heads, (GFunc) show_engine_for_head, + screensaver->toplevel_window); + + screensaver->timeout_id = g_timeout_add (1000, (GSourceFunc) draw_heads, + screensaver); +} + +static void +test_screensaver_deactivate (TestScreensaver *screensaver) +{ + g_source_remove (screensaver->timeout_id); + screensaver->timeout_id = 0; + + g_list_foreach (screensaver->heads, (GFunc) free_engine_from_head, + screensaver->toplevel_window); +} + +static void +test_screensaver_toggle (TestScreensaver *screensaver) +{ + switch (screensaver->state) + { + case TEST_SCREENSAVER_STATE_ACTIVE: + test_screensaver_activate (screensaver); + break; + + case TEST_SCREENSAVER_STATE_INACTIVE: + case TEST_SCREENSAVER_STATE_DISABLED: + test_screensaver_deactivate (screensaver); + break; + + default: + break; + } +} + +static gboolean +handle_screensaver_event (TestScreensaver *screensaver) +{ + XScreenSaverInfo *info; + GdkWindow *old_toplevel_window; + + info = XScreenSaverAllocInfo (); + + g_debug ("querying for updated server screensaver state information"); + if (!XScreenSaverQueryInfo (GDK_SCREEN_XDISPLAY (screensaver->screen), + GDK_DRAWABLE_XID (screensaver->drawable), + info)) + { + g_debug ("could not query for updated server screensaver " + "state information"); + XFree (info); + return FALSE; + } + + old_toplevel_window = screensaver->toplevel_window; + + g_debug ("updating internal state from server screensaver state " + "information"); + update_screensaver_state_from_info (screensaver, info); + + g_debug ("updating toplevel window from server screensaver state " + "information"); + update_screensaver_toplevel_window_from_info (screensaver, info); + + test_screensaver_toggle (screensaver); + + XFree (info); + return TRUE; +} + +static GdkFilterReturn +on_event (XEvent *xevent, + GdkEvent *event, + TestScreensaver *screensaver) +{ + if (xevent->type != screensaver->notify_event_number) + return GDK_FILTER_CONTINUE; + + g_debug ("received screensaver event"); + handle_screensaver_event (screensaver); + + return GDK_FILTER_CONTINUE; +} + +void +test_screensaver_listen_for_events (TestScreensaver *screensaver) +{ + gulong mask; + + mask = ScreenSaverCycleMask | ScreenSaverNotifyMask; + XScreenSaverSelectInput (GDK_SCREEN_XDISPLAY (screensaver->screen), + GDK_DRAWABLE_XID (screensaver->drawable), + mask); + + gdk_window_add_filter (NULL, (GdkFilterFunc) on_event, screensaver); +} + +gboolean +test_screensaver_register (TestScreensaver *screensaver) +{ + g_debug ("checking for screensaver extension"); + if (!test_screensaver_query_for_notify_event_number (screensaver)) + { + g_debug ("could not find screensaver extension on display"); + return FALSE; + } + + g_debug ("setting screensaver background to be clear"); + if (!test_screensaver_unset_window_background (screensaver)) + { + g_debug ("could not set screensaver background"); + return FALSE; + } + + g_debug ("listening for screensaver events"); + test_screensaver_listen_for_events (screensaver); + + g_debug ("setting up head geometry"); + setup_head_geometry (screensaver); + + return TRUE; +} + +int +main (int argc, + char **argv) +{ + GMainLoop *loop; + GMainContext *context; + GdkScreen *screen; + TestScreensaver *screensaver; + + g_debug ("opening display '%s'", g_getenv ("DISPLAY")); + gdk_init (&argc, &argv); + + context = NULL; + loop = g_main_loop_new (context, FALSE); + + screen = gdk_screen_get_default (); + + g_debug ("creating test screensaver on screen %d", + gdk_screen_get_number (screen)); + screensaver = test_screensaver_new (context, screen); + + g_debug ("registering test screensaver on screen %d", + gdk_screen_get_number (screen)); + + if (!test_screensaver_register (screensaver)) + { + g_printerr ("could not register screensaver on screen %d", + gdk_screen_get_number (screen)); + return 1; + } + + g_debug ("simulating idle"); + g_spawn_command_line_async ("xset s activate", NULL); + + g_debug ("running event loop"); + g_main_loop_run (loop); + + test_screensaver_free (screensaver); + g_main_loop_unref (loop); + + return 0; +} + +/* vim: set sw=4 ts=4 expandtab */ |