322 lines
6.4 KiB
C
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)
|
|
{
|
|
}
|