gnome-control-center/capplets/screensaver/preview.c
Bradford Hovinen (Gdict maintainer) 2830dc67b3 Added new screensaver properties capplet
2000-07-31 20:06:12 +00:00

322 lines
6.4 KiB
C

/* -*- mode: c; style: linux -*- */
/* preview.c
* Copyright (C) 2000 Helix Code, Inc.
*
* Written by Bradford Hovinen <hovinen@helixcode.com>
*
* 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.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <signal.h>
#include <string.h>
#include <sys/wait.h>
#include <gdk/gdk.h>
#include <gdk/gdkx.h>
#include <gnome.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <X11/Xatom.h>
#include "preview.h"
static GtkWidget *preview_window;
static pid_t preview_pid;
static int timeout_id;
#if 0
/* DEBUG FUNCTION */
static void
print_args (char **args)
{
int i;
printf ("Command line:\n");
for (i = 0; args[i]; i++) {
printf ("%s ", args[i]);
}
printf ("\n");
}
#endif
void
set_preview_window (GtkWidget *widget)
{
preview_window = widget;
}
static char **
strip_arg (char **args, char *arg)
{
int i, j, arg_len;
arg_len = strlen (arg);
for (i = 0; args[i]; i++) {
if (!strncmp (args[i], arg, arg_len)) {
for (j = i; args[j]; j++)
args[j] = args[j + 1];
i--;
}
}
return args;
}
static void
setup_path (void)
{
char *path, *newpath;
path = getenv ("PATH");
newpath = g_strconcat (path, ":/usr/X11R6/lib/xscreensaver", NULL);
setenv ("PATH", newpath, TRUE);
}
/* Warning: memory leaks, please do not use except in a separate
* process
*/
static char **
add_window_arg (char **args, GdkWindow *window)
{
int i;
char *x_window_id;
for (i = 0; args[i]; i++);
x_window_id =
g_strdup_printf ("0x%x",
(guint) GDK_WINDOW_XWINDOW (window));
args = g_renew (char *, args, i + 4);
args[i] = "-window";
args[i + 1] = "-window-id";
args[i + 2] = x_window_id;
args[i + 3] = NULL;
return args;
}
/* show_screensaver
*
* Given a GdkWindow in which to render and a particular screensaver,
* fork off a process and start the screensaver.
*/
static void
show_screensaver (GdkWindow *window, Screensaver *saver, pid_t *pid)
{
char **args;
*pid = fork ();
if (*pid == (pid_t) -1) {
perror ("fork");
abort ();
}
else if (*pid == 0) {
nice (20); /* Very low priority */
args = g_strsplit (saver->command_line, " ", -1);
args = strip_arg (args, "-root");
args = add_window_arg (args, window);
setup_path ();
if (execvp (args[0], args) == -1) {
perror ("execv");
abort ();
}
exit (1);
}
}
static gint
show_screensaver_timeout (void)
{
GdkPixbuf *pixbuf;
int ret;
ret = waitpid (preview_pid, NULL, WNOHANG);
if (ret == -1) {
g_error ("waitpid: %s", g_strerror (errno));
}
else if (ret > 0) {
pixbuf = gdk_pixbuf_new_from_file
(GNOME_ICONDIR "/no-hack.png");
gdk_pixbuf_render_to_drawable
(pixbuf, (GdkDrawable *) preview_window->window,
preview_window->style->fg_gc[0], 0, 0, 0, 0,
300, 250, GDK_RGB_DITHER_NONE, 0, 0);
}
timeout_id = 0;
return FALSE;
}
void
show_preview (Screensaver *saver)
{
/* Note: kill this next line for a very interesting effect ... */
close_preview ();
if (!saver->command_line) return;
show_screensaver (preview_window->window, saver, &preview_pid);
timeout_id =
gtk_timeout_add (500, (GtkFunction)
show_screensaver_timeout, NULL);
}
void
close_preview (void)
{
if (timeout_id) {
gtk_timeout_remove (timeout_id);
timeout_id = 0;
}
if (preview_pid) {
kill (preview_pid, SIGTERM);
preview_pid = 0;
}
}
/* Ick... */
static GdkWindow *
gdk_window_new_from_xwindow (Window xwindow)
{
GdkWindow *window;
GdkWindowPrivate *window_priv;
window_priv = g_new0 (GdkWindowPrivate, 1);
window = (GdkWindow *) window_priv;
window_priv->xdisplay = gdk_display;
window_priv->xwindow = xwindow;
window_priv->destroyed = FALSE;
return window;
}
static GdkWindow *
find_xscreensaver_window (Display *dpy)
{
static Atom XA_SCREENSAVER;
GdkAtom actual_type;
gint actual_format;
Window root, parent, *children;
Window root_ret;
GdkWindow *ret;
gint number_children, i;
unsigned long nitems, bytes_after;
gboolean found;
unsigned char *data;
gint x_error;
if (!XA_SCREENSAVER)
XA_SCREENSAVER =
XInternAtom (dpy, "_SCREENSAVER_VERSION", FALSE);
gdk_error_trap_push ();
root = GDK_ROOT_WINDOW ();
XQueryTree (dpy, DefaultRootWindow (dpy),
&root_ret, &parent, &children, &number_children);
if (root_ret != root) abort ();
if (parent) abort ();
if (!children || !number_children) return NULL;
for (i = 0; i < number_children; i++) {
found = XGetWindowProperty (dpy, children[i],
XA_SCREENSAVER,
0, 0, FALSE, XA_STRING,
&actual_type,
&actual_format, &nitems,
&bytes_after, &data);
free (data);
if (actual_type != None) {
ret = gdk_window_new_from_xwindow (children[i]);
free (children);
return ret;
}
}
free (children);
gdk_flush ();
x_error = gdk_error_trap_pop ();
if (x_error && x_error != BadWindow)
g_error ("X error");
return NULL;
}
void
show_demo (Screensaver *saver)
{
static GdkAtom demo_atom, xscreensaver_atom;
GdkWindow *xscreensaver_window;
GdkEventClient *event;
if (!demo_atom)
demo_atom = gdk_atom_intern ("DEMO", FALSE);
if (!xscreensaver_atom)
xscreensaver_atom = gdk_atom_intern ("SCREENSAVER", FALSE);
xscreensaver_window = find_xscreensaver_window (gdk_display);
if (!xscreensaver_window)
g_error ("Could not find XScreensaver window");
event = g_new0 (GdkEventClient, 1);
event->type = GDK_CLIENT_EVENT;
event->window = xscreensaver_window;
event->message_type = xscreensaver_atom;
event->data_format = 32;
event->data.l[0] = demo_atom;
event->data.l[1] = 300; /* XA_DEMO protocol version number */
event->data.l[2] = saver->id + 1;
gdk_event_send_client_message
((GdkEvent *) event, GDK_WINDOW_XWINDOW (xscreensaver_window));
gdk_flush ();
g_free (xscreensaver_window);
g_free (event);
}
void
close_demo (void)
{
}