summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRay Strode <rstrode@redhat.com>2007-07-22 09:09:00 -0400
committerRay Strode <rstrode@redhat.com>2007-07-22 09:09:00 -0400
commitf7a9b5cf6962e59120bcb3ff0d3a953022f6aea0 (patch)
tree7eacb5675407c49898e5570d03131562132c33f9
initial import
-rw-r--r--Makefile5
-rw-r--r--test-screensaver-extension.c589
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 */