2001-04-18 18:09:18 +00:00
|
|
|
/* Pixbufs
|
|
|
|
*
|
|
|
|
* A GdkPixbuf represents an image, normally in RGB or RGBA format.
|
|
|
|
* Pixbufs are normally used to load files from disk and perform
|
|
|
|
* image scaling.
|
|
|
|
*
|
|
|
|
* This demo is not all that educational, but looks cool. It was written
|
|
|
|
* by Extreme Pixbuf Hacker Federico Mena Quintero. It also shows
|
|
|
|
* off how to use GtkDrawingArea to do a simple animation.
|
|
|
|
*
|
|
|
|
* Look at the Image demo for additional pixbuf usage examples.
|
2001-05-18 16:28:30 +00:00
|
|
|
*
|
2001-04-18 18:09:18 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
#include <math.h>
|
|
|
|
|
2001-11-23 21:46:44 +00:00
|
|
|
#include "demo-common.h"
|
|
|
|
|
2001-04-18 18:09:18 +00:00
|
|
|
#define FRAME_DELAY 50
|
|
|
|
|
2001-11-23 21:46:44 +00:00
|
|
|
#define BACKGROUND_NAME "background.jpg"
|
2001-04-18 18:09:18 +00:00
|
|
|
|
2001-11-23 21:46:44 +00:00
|
|
|
static const char *image_names[] = {
|
2001-04-18 18:09:18 +00:00
|
|
|
"apple-red.png",
|
|
|
|
"gnome-applets.png",
|
|
|
|
"gnome-calendar.png",
|
|
|
|
"gnome-foot.png",
|
|
|
|
"gnome-gmush.png",
|
|
|
|
"gnome-gimp.png",
|
|
|
|
"gnome-gsame.png",
|
|
|
|
"gnu-keys.png"
|
|
|
|
};
|
|
|
|
|
2001-11-23 21:46:44 +00:00
|
|
|
#define N_IMAGES G_N_ELEMENTS (image_names)
|
2001-04-18 18:09:18 +00:00
|
|
|
|
|
|
|
/* demo window */
|
2001-05-18 18:30:59 +00:00
|
|
|
static GtkWidget *window = NULL;
|
2001-04-18 18:09:18 +00:00
|
|
|
|
|
|
|
/* Current frame */
|
|
|
|
static GdkPixbuf *frame;
|
|
|
|
|
|
|
|
/* Background image */
|
|
|
|
static GdkPixbuf *background;
|
2001-05-18 16:28:30 +00:00
|
|
|
static gint back_width, back_height;
|
2001-04-18 18:09:18 +00:00
|
|
|
|
|
|
|
/* Images */
|
|
|
|
static GdkPixbuf *images[N_IMAGES];
|
|
|
|
|
|
|
|
/* Widgets */
|
|
|
|
static GtkWidget *da;
|
|
|
|
|
|
|
|
/* Loads the images for the demo and returns whether the operation succeeded */
|
|
|
|
static gboolean
|
|
|
|
load_pixbufs (GError **error)
|
|
|
|
{
|
2001-05-18 16:28:30 +00:00
|
|
|
gint i;
|
2001-11-23 21:46:44 +00:00
|
|
|
char *filename;
|
2001-04-18 18:09:18 +00:00
|
|
|
|
|
|
|
if (background)
|
|
|
|
return TRUE; /* already loaded earlier */
|
2001-05-18 16:28:30 +00:00
|
|
|
|
2006-09-25 14:48:31 +00:00
|
|
|
/* demo_find_file() looks in the current directory first,
|
2001-11-23 21:46:44 +00:00
|
|
|
* so you can run gtk-demo without installing GTK, then looks
|
|
|
|
* in the location where the file is installed.
|
|
|
|
*/
|
|
|
|
filename = demo_find_file (BACKGROUND_NAME, error);
|
|
|
|
if (!filename)
|
|
|
|
return FALSE; /* note that "error" was filled in and returned */
|
2001-04-18 18:09:18 +00:00
|
|
|
|
2001-11-23 21:46:44 +00:00
|
|
|
background = gdk_pixbuf_new_from_file (filename, error);
|
|
|
|
g_free (filename);
|
|
|
|
|
2001-04-18 18:09:18 +00:00
|
|
|
if (!background)
|
2001-11-23 21:46:44 +00:00
|
|
|
return FALSE; /* Note that "error" was filled with a GError */
|
2001-05-18 16:28:30 +00:00
|
|
|
|
2001-04-18 18:09:18 +00:00
|
|
|
back_width = gdk_pixbuf_get_width (background);
|
|
|
|
back_height = gdk_pixbuf_get_height (background);
|
|
|
|
|
|
|
|
for (i = 0; i < N_IMAGES; i++)
|
|
|
|
{
|
2001-11-23 21:46:44 +00:00
|
|
|
filename = demo_find_file (image_names[i], error);
|
|
|
|
if (!filename)
|
|
|
|
return FALSE; /* Note that "error" was filled with a GError */
|
|
|
|
|
|
|
|
images[i] = gdk_pixbuf_new_from_file (filename, error);
|
|
|
|
g_free (filename);
|
|
|
|
|
2001-04-18 18:09:18 +00:00
|
|
|
if (!images[i])
|
2001-05-18 16:28:30 +00:00
|
|
|
return FALSE; /* Note that "error" was filled with a GError */
|
2001-04-18 18:09:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Expose callback for the drawing area */
|
|
|
|
static gint
|
2001-05-18 16:28:30 +00:00
|
|
|
expose_cb (GtkWidget *widget,
|
|
|
|
GdkEventExpose *event,
|
|
|
|
gpointer data)
|
2001-04-18 18:09:18 +00:00
|
|
|
{
|
|
|
|
guchar *pixels;
|
|
|
|
int rowstride;
|
|
|
|
|
|
|
|
rowstride = gdk_pixbuf_get_rowstride (frame);
|
|
|
|
|
|
|
|
pixels = gdk_pixbuf_get_pixels (frame) + rowstride * event->area.y + event->area.x * 3;
|
2001-05-18 16:28:30 +00:00
|
|
|
|
2001-04-18 18:09:18 +00:00
|
|
|
gdk_draw_rgb_image_dithalign (widget->window,
|
2001-05-18 16:28:30 +00:00
|
|
|
widget->style->black_gc,
|
|
|
|
event->area.x, event->area.y,
|
|
|
|
event->area.width, event->area.height,
|
|
|
|
GDK_RGB_DITHER_NORMAL,
|
|
|
|
pixels, rowstride,
|
|
|
|
event->area.x, event->area.y);
|
2001-04-18 18:09:18 +00:00
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define CYCLE_LEN 60
|
|
|
|
|
|
|
|
static int frame_num;
|
|
|
|
|
|
|
|
/* Timeout handler to regenerate the frame */
|
|
|
|
static gint
|
|
|
|
timeout (gpointer data)
|
|
|
|
{
|
|
|
|
double f;
|
|
|
|
int i;
|
|
|
|
double xmid, ymid;
|
|
|
|
double radius;
|
|
|
|
|
|
|
|
gdk_pixbuf_copy_area (background, 0, 0, back_width, back_height,
|
2001-05-18 16:28:30 +00:00
|
|
|
frame, 0, 0);
|
2001-04-18 18:09:18 +00:00
|
|
|
|
|
|
|
f = (double) (frame_num % CYCLE_LEN) / CYCLE_LEN;
|
|
|
|
|
|
|
|
xmid = back_width / 2.0;
|
|
|
|
ymid = back_height / 2.0;
|
|
|
|
|
|
|
|
radius = MIN (xmid, ymid) / 2.0;
|
|
|
|
|
|
|
|
for (i = 0; i < N_IMAGES; i++)
|
|
|
|
{
|
|
|
|
double ang;
|
|
|
|
int xpos, ypos;
|
|
|
|
int iw, ih;
|
|
|
|
double r;
|
|
|
|
GdkRectangle r1, r2, dest;
|
|
|
|
double k;
|
|
|
|
|
2001-11-25 23:36:29 +00:00
|
|
|
ang = 2.0 * G_PI * (double) i / N_IMAGES - f * 2.0 * G_PI;
|
2001-04-18 18:09:18 +00:00
|
|
|
|
|
|
|
iw = gdk_pixbuf_get_width (images[i]);
|
|
|
|
ih = gdk_pixbuf_get_height (images[i]);
|
|
|
|
|
2001-11-25 23:36:29 +00:00
|
|
|
r = radius + (radius / 3.0) * sin (f * 2.0 * G_PI);
|
2001-04-18 18:09:18 +00:00
|
|
|
|
|
|
|
xpos = floor (xmid + r * cos (ang) - iw / 2.0 + 0.5);
|
|
|
|
ypos = floor (ymid + r * sin (ang) - ih / 2.0 + 0.5);
|
|
|
|
|
2001-11-25 23:36:29 +00:00
|
|
|
k = (i & 1) ? sin (f * 2.0 * G_PI) : cos (f * 2.0 * G_PI);
|
2001-04-18 18:09:18 +00:00
|
|
|
k = 2.0 * k * k;
|
|
|
|
k = MAX (0.25, k);
|
|
|
|
|
|
|
|
r1.x = xpos;
|
|
|
|
r1.y = ypos;
|
|
|
|
r1.width = iw * k;
|
|
|
|
r1.height = ih * k;
|
|
|
|
|
|
|
|
r2.x = 0;
|
|
|
|
r2.y = 0;
|
|
|
|
r2.width = back_width;
|
|
|
|
r2.height = back_height;
|
|
|
|
|
|
|
|
if (gdk_rectangle_intersect (&r1, &r2, &dest))
|
2001-05-18 16:28:30 +00:00
|
|
|
gdk_pixbuf_composite (images[i],
|
|
|
|
frame,
|
|
|
|
dest.x, dest.y,
|
|
|
|
dest.width, dest.height,
|
|
|
|
xpos, ypos,
|
|
|
|
k, k,
|
|
|
|
GDK_INTERP_NEAREST,
|
|
|
|
((i & 1)
|
2001-11-25 23:36:29 +00:00
|
|
|
? MAX (127, fabs (255 * sin (f * 2.0 * G_PI)))
|
|
|
|
: MAX (127, fabs (255 * cos (f * 2.0 * G_PI)))));
|
2001-04-18 18:09:18 +00:00
|
|
|
}
|
|
|
|
|
2006-12-22 19:10:43 +00:00
|
|
|
GDK_THREADS_ENTER ();
|
2001-04-18 18:09:18 +00:00
|
|
|
gtk_widget_queue_draw (da);
|
2006-12-22 19:10:43 +00:00
|
|
|
GDK_THREADS_LEAVE ();
|
2001-04-18 18:09:18 +00:00
|
|
|
|
|
|
|
frame_num++;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static guint timeout_id;
|
|
|
|
|
|
|
|
static void
|
|
|
|
cleanup_callback (GtkObject *object,
|
2001-05-18 16:28:30 +00:00
|
|
|
gpointer data)
|
2001-04-18 18:09:18 +00:00
|
|
|
{
|
|
|
|
g_source_remove (timeout_id);
|
|
|
|
timeout_id = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
GtkWidget *
|
2003-11-08 22:08:05 +00:00
|
|
|
do_pixbufs (GtkWidget *do_widget)
|
2001-04-18 18:09:18 +00:00
|
|
|
{
|
|
|
|
if (!window)
|
|
|
|
{
|
|
|
|
GError *error;
|
|
|
|
|
|
|
|
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
2003-11-08 22:08:05 +00:00
|
|
|
gtk_window_set_screen (GTK_WINDOW (window),
|
|
|
|
gtk_widget_get_screen (do_widget));
|
2001-04-18 18:09:18 +00:00
|
|
|
gtk_window_set_title (GTK_WINDOW (window), "Pixbufs");
|
2001-06-25 23:48:51 +00:00
|
|
|
gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
|
2001-05-18 16:28:30 +00:00
|
|
|
|
2001-10-20 23:39:32 +00:00
|
|
|
g_signal_connect (window, "destroy", G_CALLBACK (gtk_widget_destroyed), &window);
|
|
|
|
g_signal_connect (window, "destroy", G_CALLBACK (cleanup_callback), NULL);
|
2001-04-18 18:09:18 +00:00
|
|
|
|
2001-05-18 16:28:30 +00:00
|
|
|
|
2001-04-18 18:09:18 +00:00
|
|
|
error = NULL;
|
|
|
|
if (!load_pixbufs (&error))
|
2001-05-18 16:28:30 +00:00
|
|
|
{
|
|
|
|
GtkWidget *dialog;
|
|
|
|
|
|
|
|
dialog = gtk_message_dialog_new (GTK_WINDOW (window),
|
|
|
|
GTK_DIALOG_DESTROY_WITH_PARENT,
|
|
|
|
GTK_MESSAGE_ERROR,
|
|
|
|
GTK_BUTTONS_CLOSE,
|
|
|
|
"Failed to load an image: %s",
|
|
|
|
error->message);
|
|
|
|
|
|
|
|
g_error_free (error);
|
|
|
|
|
2001-10-20 23:39:32 +00:00
|
|
|
g_signal_connect (dialog, "response",
|
|
|
|
G_CALLBACK (gtk_widget_destroy), NULL);
|
2001-05-18 16:28:30 +00:00
|
|
|
|
|
|
|
gtk_widget_show (dialog);
|
|
|
|
}
|
2001-04-18 18:09:18 +00:00
|
|
|
else
|
2001-05-18 16:28:30 +00:00
|
|
|
{
|
fix a typo.
2001-08-07 Havoc Pennington <hp@pobox.com>
* gtk/gtkfilesel.c (open_ref_dir): fix a typo.
* gtk/gtkplug.c (gtk_plug_init): remove setting of auto_shrink;
some fixage is needed here, but nothing simple. Owen understands
it. ;-)
* gtk/gtkwindow.h, gtk/gtkwindow.c: Rework code and API for window
sizing and positioning. Also, fix bug in compute_geometry_hints
(width/height confusion for setting min size).
(gtk_window_move): new function
(gtk_window_resize): new function
(gtk_window_get_size): new function
(gtk_window_get_position): new function
(gtk_window_parse_geometry): new function
* gtk/gtkwidget.c (gtk_widget_set_size_request): new function
(gtk_widget_get_size_request): new function
(gtk_widget_get_usize): delete, that was a short-lived function
;-)
(gtk_widget_set_usize): deprecate
(gtk_widget_set_uposition): deprecate, make it a trivial
gtk_window_move() wrapper
(gtk_widget_class_init): remove x/y/width/height properties,
add width_request height_request
* demos/*: update to avoid deprecated functions
* gtk/gtklayout.c: add x/y child properties
* gtk/gtkfixed.c: add x/y child properties, and get rid of
uses of "gint16"
* tests/testgtk.c (create_window_sizing): lots of tweaks to window
sizing test
* gdk/x11/gdkevents-x11.c (gdk_event_translate): Ensure that
configure events on toplevel windows are always in root window
coordinates, following ICCCM spec that all synthetic events
are in root window coords already, while real events are
in parent window coords. Previously the code assumed that
coords of 0,0 were parent window coords, which was
really broken.
* gtk/gtkcontainer.c (gtk_container_get_focus_chain): fix
warning
* gdk/gdkwindow.h (GdkWindowHints): add GDK_HINT_USER_POS
and GDK_HINT_USER_SIZE so we can set USSize and USPosition
hints in gtk_window_parse_geometry()
* gdk/x11/gdkwindow-x11.c (gdk_window_set_geometry_hints): support
new USER_POS USER_SIZE hints
2001-08-10 03:46:08 +00:00
|
|
|
gtk_widget_set_size_request (window, back_width, back_height);
|
2001-05-18 16:28:30 +00:00
|
|
|
|
|
|
|
frame = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, back_width, back_height);
|
|
|
|
|
|
|
|
da = gtk_drawing_area_new ();
|
|
|
|
|
2001-10-20 23:39:32 +00:00
|
|
|
g_signal_connect (da, "expose_event",
|
|
|
|
G_CALLBACK (expose_cb), NULL);
|
2001-05-18 16:28:30 +00:00
|
|
|
|
|
|
|
gtk_container_add (GTK_CONTAINER (window), da);
|
|
|
|
|
2003-02-01 01:47:01 +00:00
|
|
|
timeout_id = g_timeout_add (FRAME_DELAY, timeout, NULL);
|
2001-05-18 16:28:30 +00:00
|
|
|
}
|
2001-04-18 18:09:18 +00:00
|
|
|
}
|
2001-05-18 16:28:30 +00:00
|
|
|
|
2001-04-18 18:09:18 +00:00
|
|
|
if (!GTK_WIDGET_VISIBLE (window))
|
|
|
|
{
|
|
|
|
gtk_widget_show_all (window);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gtk_widget_destroy (window);
|
|
|
|
window = NULL;
|
2004-09-22 04:55:19 +00:00
|
|
|
g_object_unref (frame);
|
2001-04-18 18:09:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return window;
|
|
|
|
}
|