summaryrefslogtreecommitdiff
path: root/demos/gtk-demo
diff options
context:
space:
mode:
authorHavoc Pennington <hp@redhat.com>2001-04-18 18:09:18 +0000
committerHavoc Pennington <hp@src.gnome.org>2001-04-18 18:09:18 +0000
commit60b6a010e931aaaf97d723c893068381a421f0a0 (patch)
tree14982e448c4281c77bdfb5cd17add1a61fe72fce /demos/gtk-demo
parentebd3958c0641d82b54f26118155e4669725900e2 (diff)
downloadgtk+-60b6a010e931aaaf97d723c893068381a421f0a0.tar.gz
fix to properly queue resizes when the image is set
2001-04-18 Havoc Pennington <hp@redhat.com> * gtk/gtkimage.c: fix to properly queue resizes when the image is set * gtk/gtktextview.c (gtk_text_view_do_popup): desensitize Paste if the insertion point isn't editable * demos/gtk-demo/images.c: Added a GtkImage demo * demos/gtk-demo/drawingarea.c: drawing area demo * demos/gtk-demo/menus.c (create_menu): cleanups 2001-04-18 Havoc Pennington <hp@redhat.com> * gdk-pixbuf.c (gdk_pixbuf_fill): Function to fill pixbuf with a given color.
Diffstat (limited to 'demos/gtk-demo')
-rw-r--r--demos/gtk-demo/Makefile.am22
-rw-r--r--demos/gtk-demo/apple-red.pngbin0 -> 3545 bytes
-rw-r--r--demos/gtk-demo/background.jpgbin0 -> 22219 bytes
-rw-r--r--demos/gtk-demo/button_box.c20
-rw-r--r--demos/gtk-demo/drawingarea.c322
-rw-r--r--demos/gtk-demo/gnome-applets.pngbin0 -> 3090 bytes
-rw-r--r--demos/gtk-demo/gnome-calendar.pngbin0 -> 2755 bytes
-rw-r--r--demos/gtk-demo/gnome-foot.pngbin0 -> 2916 bytes
-rw-r--r--demos/gtk-demo/gnome-gimp.pngbin0 -> 3410 bytes
-rw-r--r--demos/gtk-demo/gnome-gmush.pngbin0 -> 3244 bytes
-rw-r--r--demos/gtk-demo/gnome-gsame.pngbin0 -> 4263 bytes
-rw-r--r--demos/gtk-demo/gnu-keys.pngbin0 -> 3852 bytes
-rw-r--r--demos/gtk-demo/gtk-logo-rgb.gifbin0 -> 6459 bytes
-rw-r--r--demos/gtk-demo/images.c396
-rw-r--r--demos/gtk-demo/main.c31
-rw-r--r--demos/gtk-demo/menus.c34
-rw-r--r--demos/gtk-demo/pixbufs.c277
17 files changed, 1073 insertions, 29 deletions
diff --git a/demos/gtk-demo/Makefile.am b/demos/gtk-demo/Makefile.am
index 6fa87fac72..b581f51e14 100644
--- a/demos/gtk-demo/Makefile.am
+++ b/demos/gtk-demo/Makefile.am
@@ -2,12 +2,17 @@
democodedir=$(datadir)/gtk-2.0/demo
+## These should be in the order you want them to appear in the
+## demo app, which means alphabetized by demo title, not filename
demos = @STRIP_BEGIN@ \
button_box.c \
+ dialog.c \
+ drawingarea.c \
+ images.c \
item_factory.c \
menus.c \
panes.c \
- dialog.c \
+ pixbufs.c \
textview.c \
@STRIP_END@
@@ -63,4 +68,17 @@ gtk_demo_SOURCES = \
gtk_demo_DEPENDENCIES = $(DEPS)
gtk_demo_LDADD = $(LDADDS)
-democode_DATA = $(demos)
+IMAGEFILES= apple-red.png \
+ background.jpg \
+ gnome-applets.png \
+ gnome-calendar.png \
+ gnome-foot.png \
+ gnome-gimp.png \
+ gnome-gmush.png \
+ gnome-gsame.png \
+ gnu-keys.png \
+ gtk-logo-rgb.gif
+
+democode_DATA = $(demos) $(IMAGEFILES)
+
+EXTRA_DIST = $(IMAGEFILES)
diff --git a/demos/gtk-demo/apple-red.png b/demos/gtk-demo/apple-red.png
new file mode 100644
index 0000000000..b0a24e9418
--- /dev/null
+++ b/demos/gtk-demo/apple-red.png
Binary files differ
diff --git a/demos/gtk-demo/background.jpg b/demos/gtk-demo/background.jpg
new file mode 100644
index 0000000000..86c006aa46
--- /dev/null
+++ b/demos/gtk-demo/background.jpg
Binary files differ
diff --git a/demos/gtk-demo/button_box.c b/demos/gtk-demo/button_box.c
index a0fae11226..f8e7bd3838 100644
--- a/demos/gtk-demo/button_box.c
+++ b/demos/gtk-demo/button_box.c
@@ -72,19 +72,19 @@ do_button_box (void)
gtk_container_add (GTK_CONTAINER (frame_horz), vbox);
gtk_box_pack_start (GTK_BOX (vbox),
- create_bbox (TRUE, "Spread", 40, GTK_BUTTONBOX_SPREAD),
+ create_bbox (TRUE, "Spread", 40, GTK_BUTTONBOX_SPREAD),
TRUE, TRUE, 0);
gtk_box_pack_start (GTK_BOX (vbox),
- create_bbox (TRUE, "Edge", 40, GTK_BUTTONBOX_EDGE),
+ create_bbox (TRUE, "Edge", 40, GTK_BUTTONBOX_EDGE),
TRUE, TRUE, 5);
-
+
gtk_box_pack_start (GTK_BOX (vbox),
- create_bbox (TRUE, "Start", 40, GTK_BUTTONBOX_START),
+ create_bbox (TRUE, "Start", 40, GTK_BUTTONBOX_START),
TRUE, TRUE, 5);
-
+
gtk_box_pack_start (GTK_BOX (vbox),
- create_bbox (TRUE, "End", 40, GTK_BUTTONBOX_END),
+ create_bbox (TRUE, "End", 40, GTK_BUTTONBOX_END),
TRUE, TRUE, 5);
frame_vert = gtk_frame_new ("Vertical Button Boxes");
@@ -95,19 +95,19 @@ do_button_box (void)
gtk_container_add (GTK_CONTAINER (frame_vert), hbox);
gtk_box_pack_start (GTK_BOX (hbox),
- create_bbox (FALSE, "Spread", 30, GTK_BUTTONBOX_SPREAD),
+ create_bbox (FALSE, "Spread", 30, GTK_BUTTONBOX_SPREAD),
TRUE, TRUE, 0);
gtk_box_pack_start (GTK_BOX (hbox),
- create_bbox (FALSE, "Edge", 30, GTK_BUTTONBOX_EDGE),
+ create_bbox (FALSE, "Edge", 30, GTK_BUTTONBOX_EDGE),
TRUE, TRUE, 5);
gtk_box_pack_start (GTK_BOX (hbox),
- create_bbox (FALSE, "Start", 30, GTK_BUTTONBOX_START),
+ create_bbox (FALSE, "Start", 30, GTK_BUTTONBOX_START),
TRUE, TRUE, 5);
gtk_box_pack_start (GTK_BOX (hbox),
- create_bbox (FALSE, "End", 30, GTK_BUTTONBOX_END),
+ create_bbox (FALSE, "End", 30, GTK_BUTTONBOX_END),
TRUE, TRUE, 5);
}
diff --git a/demos/gtk-demo/drawingarea.c b/demos/gtk-demo/drawingarea.c
new file mode 100644
index 0000000000..101b159730
--- /dev/null
+++ b/demos/gtk-demo/drawingarea.c
@@ -0,0 +1,322 @@
+/* Drawing Area
+ *
+ * GtkDrawingArea is a blank area where you can draw custom displays
+ * of various kinds.
+ *
+ * This demo has two drawing areas. The checkerboard area shows
+ * how you can just draw something; all you have to do is write
+ * a signal handler for expose_event, as shown here.
+ *
+ * The "scribble" area is a bit more advanced, and shows how to handle
+ * events such as button presses and mouse motion. Click the mouse
+ * and drag in the scribble area to draw squiggles. Resize the window
+ * to clear the area.
+ */
+
+#include <gtk/gtk.h>
+
+static GtkWidget *window = NULL;
+/* Pixmap for scribble area, to store current scribbles */
+static GdkPixmap *pixmap = NULL;
+
+/* Create a new pixmap of the appropriate size to store our scribbles */
+static gboolean
+scribble_configure_event (GtkWidget *widget,
+ GdkEventConfigure *event,
+ gpointer data)
+{
+ if (pixmap)
+ g_object_unref (G_OBJECT (pixmap));
+
+ pixmap = gdk_pixmap_new (widget->window,
+ widget->allocation.width,
+ widget->allocation.height,
+ -1);
+
+ /* Initialize the pixmap to white */
+ gdk_draw_rectangle (pixmap,
+ widget->style->white_gc,
+ TRUE,
+ 0, 0,
+ widget->allocation.width,
+ widget->allocation.height);
+
+ /* We've handled the configure event, no need for further processing. */
+ return TRUE;
+}
+
+/* Redraw the screen from the pixmap */
+static gboolean
+scribble_expose_event (GtkWidget *widget,
+ GdkEventExpose *event,
+ gpointer data)
+{
+ /* We use the "foreground GC" for the widget since it already exists,
+ * but honestly any GC would work. The only thing to worry about
+ * is whether the GC has an inappropriate clip region set.
+ */
+
+ gdk_draw_drawable (widget->window,
+ widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
+ pixmap,
+ /* Only copy the area that was exposed. */
+ event->area.x, event->area.y,
+ event->area.x, event->area.y,
+ event->area.width, event->area.height);
+
+ return FALSE;
+}
+
+/* Draw a rectangle on the screen */
+static void
+draw_brush (GtkWidget *widget,
+ gdouble x,
+ gdouble y)
+{
+ GdkRectangle update_rect;
+
+ update_rect.x = x - 3;
+ update_rect.y = y - 3;
+ update_rect.width = 6;
+ update_rect.height = 6;
+
+ /* Paint to the pixmap, where we store our state */
+ gdk_draw_rectangle (pixmap,
+ widget->style->black_gc,
+ TRUE,
+ update_rect.x, update_rect.y,
+ update_rect.width, update_rect.height);
+
+ /* Now invalidate the affected region of the drawing area. */
+ gdk_window_invalidate_rect (widget->window,
+ &update_rect,
+ FALSE);
+}
+
+static gboolean
+scribble_button_press_event (GtkWidget *widget,
+ GdkEventButton *event,
+ gpointer data)
+{
+ if (pixmap == NULL)
+ return FALSE; /* paranoia check, in case we haven't gotten a configure event */
+
+ if (event->button == 1)
+ draw_brush (widget, event->x, event->y);
+
+ /* We've handled the event, stop processing */
+ return TRUE;
+}
+
+static gboolean
+scribble_motion_notify_event (GtkWidget *widget,
+ GdkEventMotion *event,
+ gpointer data)
+{
+ int x, y;
+ GdkModifierType state;
+
+ if (pixmap == NULL)
+ return FALSE; /* paranoia check, in case we haven't gotten a configure event */
+
+ /* This call is very important; it requests the next motion event.
+ * If you don't call gdk_window_get_pointer() you'll only get
+ * a single motion event. The reason is that we specified
+ * GDK_POINTER_MOTION_HINT_MASK to gtk_widget_set_events().
+ * If we hadn't specified that, we could just use event->x, event->y
+ * as the pointer location. But we'd also get deluged in events.
+ * By requesting the next event as we handle the current one,
+ * we avoid getting a huge number of events faster than we
+ * can cope.
+ */
+
+ gdk_window_get_pointer (event->window, &x, &y, &state);
+
+ if (state & GDK_BUTTON1_MASK)
+ draw_brush (widget, x, y);
+
+ /* We've handled it, stop processing */
+ return TRUE;
+}
+
+
+static gboolean
+checkerboard_expose (GtkWidget *da,
+ GdkEventExpose *event,
+ gpointer data)
+{
+ gint i, j, xcount, ycount;
+ GdkGC *gc1, *gc2;
+ GdkColor color;
+
+#define CHECK_SIZE 10
+#define SPACING 2
+
+ /* At the start of an expose handler, a clip region of event->area
+ * is set on the window, and event->area has been cleared to the
+ * widget's background color. The docs for
+ * gdk_window_begin_paint_region() give more details on how this
+ * works.
+ */
+
+ /* It would be a bit more efficient to keep these
+ * GC's around instead of recreating on each expose, but
+ * this is the lazy/slow way.
+ */
+ gc1 = gdk_gc_new (da->window);
+ color.red = 30000;
+ color.green = 0;
+ color.blue = 30000;
+ gdk_gc_set_rgb_fg_color (gc1, &color);
+
+ gc2 = gdk_gc_new (da->window);
+ color.red = 65535;
+ color.green = 65535;
+ color.blue = 65535;
+ gdk_gc_set_rgb_fg_color (gc2, &color);
+
+ xcount = 0;
+ i = SPACING;
+ while (i < da->allocation.width)
+ {
+ j = SPACING;
+ ycount = xcount % 2; /* start with even/odd depending on row */
+ while (j < da->allocation.height)
+ {
+ GdkGC *gc;
+
+ if (ycount % 2)
+ gc = gc1;
+ else
+ gc = gc2;
+
+ /* If we're outside event->area, this will do nothing.
+ * It might be mildly more efficient if we handled
+ * the clipping ourselves, but again we're feeling lazy.
+ */
+ gdk_draw_rectangle (da->window,
+ gc,
+ TRUE,
+ i, j,
+ CHECK_SIZE,
+ CHECK_SIZE);
+
+ j += CHECK_SIZE + SPACING;
+ ++ycount;
+ }
+
+ i += CHECK_SIZE + SPACING;
+ ++xcount;
+ }
+
+ g_object_unref (G_OBJECT (gc1));
+ g_object_unref (G_OBJECT (gc2));
+
+ /* return TRUE because we've handled this event, so no
+ * further processing is required.
+ */
+ return TRUE;
+}
+
+GtkWidget *
+do_drawingarea (void)
+{
+ GtkWidget *frame;
+ GtkWidget *vbox;
+ GtkWidget *da;
+ GtkWidget *label;
+
+ if (!window)
+ {
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_title (GTK_WINDOW (window), "Drawing Area");
+
+ gtk_signal_connect (GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC (gtk_widget_destroyed), &window);
+
+ gtk_container_set_border_width (GTK_CONTAINER (window), 8);
+
+ vbox = gtk_vbox_new (FALSE, 8);
+ gtk_container_set_border_width (GTK_CONTAINER (vbox), 8);
+ gtk_container_add (GTK_CONTAINER (window), vbox);
+
+ /*
+ * Create the checkerboard area
+ */
+
+ label = gtk_label_new (NULL);
+ gtk_label_set_markup (GTK_LABEL (label),
+ "<u>Checkerboard pattern</u>");
+ gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
+
+ frame = gtk_frame_new (NULL);
+ gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
+ gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0);
+
+ da = gtk_drawing_area_new ();
+ /* set a minimum size */
+ gtk_widget_set_usize (da, 100, 100);
+
+ gtk_container_add (GTK_CONTAINER (frame), da);
+
+ gtk_signal_connect (GTK_OBJECT (da),
+ "expose_event",
+ GTK_SIGNAL_FUNC (checkerboard_expose),
+ NULL);
+
+ /*
+ * Create the scribble area
+ */
+
+ label = gtk_label_new (NULL);
+ gtk_label_set_markup (GTK_LABEL (label),
+ "<u>Scribble area</u>");
+ gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
+
+ frame = gtk_frame_new (NULL);
+ gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
+ gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0);
+
+ da = gtk_drawing_area_new ();
+ /* set a minimum size */
+ gtk_widget_set_usize (da, 100, 100);
+
+ gtk_container_add (GTK_CONTAINER (frame), da);
+
+ /* Signals used to handle backing pixmap */
+
+ gtk_signal_connect (GTK_OBJECT (da), "expose_event",
+ GTK_SIGNAL_FUNC (scribble_expose_event), NULL);
+ gtk_signal_connect (GTK_OBJECT (da),"configure_event",
+ GTK_SIGNAL_FUNC (scribble_configure_event), NULL);
+
+ /* Event signals */
+
+ gtk_signal_connect (GTK_OBJECT (da), "motion_notify_event",
+ GTK_SIGNAL_FUNC (scribble_motion_notify_event), NULL);
+ gtk_signal_connect (GTK_OBJECT (da), "button_press_event",
+ GTK_SIGNAL_FUNC (scribble_button_press_event), NULL);
+
+
+ /* Ask to receive events the drawing area doesn't normally
+ * subscribe to
+ */
+ gtk_widget_set_events (da, gtk_widget_get_events (da)
+ | GDK_LEAVE_NOTIFY_MASK
+ | GDK_BUTTON_PRESS_MASK
+ | GDK_POINTER_MOTION_MASK
+ | GDK_POINTER_MOTION_HINT_MASK);
+
+ }
+
+ if (!GTK_WIDGET_VISIBLE (window))
+ {
+ gtk_widget_show_all (window);
+ }
+ else
+ {
+ gtk_widget_destroy (window);
+ window = NULL;
+ }
+
+ return window;
+}
diff --git a/demos/gtk-demo/gnome-applets.png b/demos/gtk-demo/gnome-applets.png
new file mode 100644
index 0000000000..8d3549e97c
--- /dev/null
+++ b/demos/gtk-demo/gnome-applets.png
Binary files differ
diff --git a/demos/gtk-demo/gnome-calendar.png b/demos/gtk-demo/gnome-calendar.png
new file mode 100644
index 0000000000..889f329ae5
--- /dev/null
+++ b/demos/gtk-demo/gnome-calendar.png
Binary files differ
diff --git a/demos/gtk-demo/gnome-foot.png b/demos/gtk-demo/gnome-foot.png
new file mode 100644
index 0000000000..0476658517
--- /dev/null
+++ b/demos/gtk-demo/gnome-foot.png
Binary files differ
diff --git a/demos/gtk-demo/gnome-gimp.png b/demos/gtk-demo/gnome-gimp.png
new file mode 100644
index 0000000000..f6bbc6d36c
--- /dev/null
+++ b/demos/gtk-demo/gnome-gimp.png
Binary files differ
diff --git a/demos/gtk-demo/gnome-gmush.png b/demos/gtk-demo/gnome-gmush.png
new file mode 100644
index 0000000000..0a4b0d04e6
--- /dev/null
+++ b/demos/gtk-demo/gnome-gmush.png
Binary files differ
diff --git a/demos/gtk-demo/gnome-gsame.png b/demos/gtk-demo/gnome-gsame.png
new file mode 100644
index 0000000000..01c061151f
--- /dev/null
+++ b/demos/gtk-demo/gnome-gsame.png
Binary files differ
diff --git a/demos/gtk-demo/gnu-keys.png b/demos/gtk-demo/gnu-keys.png
new file mode 100644
index 0000000000..58a33770e6
--- /dev/null
+++ b/demos/gtk-demo/gnu-keys.png
Binary files differ
diff --git a/demos/gtk-demo/gtk-logo-rgb.gif b/demos/gtk-demo/gtk-logo-rgb.gif
new file mode 100644
index 0000000000..f6e934d5e6
--- /dev/null
+++ b/demos/gtk-demo/gtk-logo-rgb.gif
Binary files differ
diff --git a/demos/gtk-demo/images.c b/demos/gtk-demo/images.c
new file mode 100644
index 0000000000..756046ecfd
--- /dev/null
+++ b/demos/gtk-demo/images.c
@@ -0,0 +1,396 @@
+/* Images
+ *
+ * GtkImage is used to display an image; the image can be in a number of formats.
+ * Typically, you load an image into a GdkPixbuf, then display the pixbuf.
+ *
+ * This demo code shows some of the more obscure cases, in the simple
+ * case a call to gtk_image_new_from_file() is all you need.
+ *
+ * If you want to put image data in your program as a C variable,
+ * use the make-inline-pixbuf program that comes with GTK+.
+ */
+
+#include <gtk/gtk.h>
+#include <stdio.h>
+#include <errno.h>
+
+static GtkWidget *window = NULL;
+static GdkPixbufLoader *pixbuf_loader = NULL;
+static guint load_timeout = 0;
+static FILE* image_stream = NULL;
+
+static void
+progressive_prepared_callback (GdkPixbufLoader* loader, gpointer data)
+{
+ GdkPixbuf* pixbuf;
+ GtkWidget* image;
+
+ image = GTK_WIDGET (data);
+
+ pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
+
+ /* Avoid displaying random memory contents, since the pixbuf
+ * isn't filled in yet.
+ */
+ gdk_pixbuf_fill (pixbuf, 0xaaaaaaff);
+
+ gtk_image_set_from_pixbuf (GTK_IMAGE (image), pixbuf);
+}
+
+static void
+progressive_updated_callback (GdkPixbufLoader* loader,
+ guint x, guint y, guint width, guint height,
+ gpointer data)
+{
+ GtkWidget* image;
+
+ image = GTK_WIDGET (data);
+
+ /* We know the pixbuf inside the image has changed, but the image
+ * itself doesn't know this; so queue a redraw. If we wanted to be
+ * really efficient, we could use a drawing area or something
+ * instead of a GtkImage, so we could control the exact position of
+ * the pixbuf on the display, then we could queue a draw for only
+ * the updated area of the image.
+ */
+
+ gtk_widget_queue_draw (image);
+}
+
+static gint
+progressive_timeout (gpointer data)
+{
+ GtkWidget *image;
+
+ image = GTK_WIDGET (data);
+
+ /* This shows off fully-paranoid error handling, so looks scary.
+ * You could factor out the error handling code into a nice separate
+ * function to make things nicer.
+ */
+
+ if (image_stream)
+ {
+ size_t bytes_read;
+ guchar buf[256];
+ GError *error = NULL;
+
+ bytes_read = fread (buf, 1, 256, image_stream);
+
+ if (ferror (image_stream))
+ {
+ GtkWidget *dialog;
+
+ dialog = gtk_message_dialog_new (GTK_WINDOW (window),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_CLOSE,
+ "Failure reading image file 'gtk-logo-rgb.gif': %s",
+ g_strerror (errno));
+
+ gtk_signal_connect (GTK_OBJECT (dialog),
+ "response",
+ GTK_SIGNAL_FUNC (gtk_widget_destroy),
+ NULL);
+
+ fclose (image_stream);
+ image_stream = NULL;
+
+ gtk_widget_show (dialog);
+
+ load_timeout = 0;
+
+ return FALSE; /* uninstall the timeout */
+ }
+
+ if (!gdk_pixbuf_loader_write (pixbuf_loader,
+ buf, bytes_read,
+ &error))
+ {
+ GtkWidget *dialog;
+
+ dialog = gtk_message_dialog_new (GTK_WINDOW (window),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_CLOSE,
+ "Failed to load image: %s",
+ error->message);
+
+ g_error_free (error);
+
+ gtk_signal_connect (GTK_OBJECT (dialog),
+ "response",
+ GTK_SIGNAL_FUNC (gtk_widget_destroy),
+ NULL);
+
+ fclose (image_stream);
+ image_stream = NULL;
+
+ gtk_widget_show (dialog);
+
+ load_timeout = 0;
+
+ return FALSE; /* uninstall the timeout */
+ }
+
+ if (feof (image_stream))
+ {
+ fclose (image_stream);
+ image_stream = NULL;
+
+ /* Errors can happen on close, e.g. if the image
+ * file was truncated we'll know on close that
+ * it was incomplete.
+ */
+ error = NULL;
+ if (!gdk_pixbuf_loader_close (pixbuf_loader,
+ &error))
+ {
+ GtkWidget *dialog;
+
+ dialog = gtk_message_dialog_new (GTK_WINDOW (window),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_CLOSE,
+ "Failed to load image: %s",
+ error->message);
+
+ g_error_free (error);
+
+ gtk_signal_connect (GTK_OBJECT (dialog),
+ "response",
+ GTK_SIGNAL_FUNC (gtk_widget_destroy),
+ NULL);
+
+ gtk_widget_show (dialog);
+
+ g_object_unref (G_OBJECT (pixbuf_loader));
+ pixbuf_loader = NULL;
+
+ load_timeout = 0;
+
+ return FALSE; /* uninstall the timeout */
+ }
+
+ g_object_unref (G_OBJECT (pixbuf_loader));
+ pixbuf_loader = NULL;
+ }
+ }
+ else
+ {
+ const gchar *filename;
+
+ if (g_file_test ("./gtk-logo-rgb.gif", G_FILE_TEST_EXISTS))
+ filename = "./gtk-logo-rgb.gif";
+ else
+ filename = DEMOCODEDIR"/gtk-log-rgb.gif";
+
+ image_stream = fopen (filename, "r");
+
+ if (image_stream == NULL)
+ {
+ GtkWidget *dialog;
+
+ dialog = gtk_message_dialog_new (GTK_WINDOW (window),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_CLOSE,
+ "Unable to open image file 'gtk-logo-rgb.gif': %s",
+ g_strerror (errno));
+
+ gtk_signal_connect (GTK_OBJECT (dialog),
+ "response",
+ GTK_SIGNAL_FUNC (gtk_widget_destroy),
+ NULL);
+
+ gtk_widget_show (dialog);
+
+ load_timeout = 0;
+
+ return FALSE; /* uninstall the timeout */
+ }
+
+ if (pixbuf_loader)
+ {
+ gdk_pixbuf_loader_close (pixbuf_loader, NULL);
+ g_object_unref (G_OBJECT (pixbuf_loader));
+ pixbuf_loader = NULL;
+ }
+
+ pixbuf_loader = gdk_pixbuf_loader_new ();
+
+ g_signal_connect_data (G_OBJECT (pixbuf_loader),
+ "area_prepared",
+ G_CALLBACK (progressive_prepared_callback),
+ image,
+ NULL, FALSE, FALSE);
+
+ g_signal_connect_data (G_OBJECT (pixbuf_loader),
+ "area_updated",
+ G_CALLBACK (progressive_updated_callback),
+ image,
+ NULL, FALSE, FALSE);
+ }
+
+ /* leave timeout installed */
+ return TRUE;
+}
+
+static void
+start_progressive_loading (GtkWidget *image)
+{
+ /* This is obviously totally contrived (we slow down loading
+ * on purpose to show how incremental loading works).
+ * The real purpose of incremental loading is the case where
+ * you are reading data from a slow source such as the network.
+ * The timeout simply simulates a slow data source by inserting
+ * pauses in the reading process.
+ */
+ load_timeout = g_timeout_add (300,
+ progressive_timeout,
+ image);
+}
+
+static void
+cleanup_callback (GtkObject *object,
+ gpointer data)
+{
+ if (load_timeout)
+ {
+ g_source_remove (load_timeout);
+ load_timeout = 0;
+ }
+
+ if (pixbuf_loader)
+ {
+ gdk_pixbuf_loader_close (pixbuf_loader, NULL);
+ g_object_unref (G_OBJECT (pixbuf_loader));
+ pixbuf_loader = NULL;
+ }
+
+ if (image_stream)
+ fclose (image_stream);
+ image_stream = NULL;
+}
+
+GtkWidget *
+do_images (void)
+{
+ GtkWidget *frame;
+ GtkWidget *vbox;
+ GtkWidget *image;
+ GtkWidget *label;
+ GtkWidget *align;
+
+ if (!window)
+ {
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_title (GTK_WINDOW (window), "Images");
+
+ gtk_signal_connect (GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC (gtk_widget_destroyed), &window);
+ gtk_signal_connect (GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC (cleanup_callback), NULL);
+
+ gtk_container_set_border_width (GTK_CONTAINER (window), 8);
+
+ vbox = gtk_vbox_new (FALSE, 8);
+ gtk_container_set_border_width (GTK_CONTAINER (vbox), 8);
+ gtk_container_add (GTK_CONTAINER (window), vbox);
+
+ label = gtk_label_new (NULL);
+ gtk_label_set_markup (GTK_LABEL (label),
+ "<u>Image loaded from a file</u>");
+ gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
+
+ frame = gtk_frame_new (NULL);
+ gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
+ /* The alignment keeps the frame from growing when users resize
+ * the window
+ */
+ align = gtk_alignment_new (0.5, 0.5, 0, 0);
+ gtk_container_add (GTK_CONTAINER (align), frame);
+ gtk_box_pack_start (GTK_BOX (vbox), align, FALSE, FALSE, 0);
+
+ /* We look for the image in the current directory first,
+ * so you can run gtk-demo without installing GTK
+ */
+ if (g_file_test ("./gtk-logo-rgb.gif", G_FILE_TEST_EXISTS))
+ {
+ /* This code shows off error handling. You can just use
+ * gtk_image_new_from_file() instead if you don't want to report
+ * errors to the user. If the file doesn't load when using
+ * gtk_image_new_from_file(), a "missing image" icon will
+ * be displayed instead.
+ */
+ GdkPixbuf *pixbuf;
+ GError *error = NULL;
+
+ pixbuf = gdk_pixbuf_new_from_file ("./gtk-logo-rgb.gif",
+ &error);
+ if (error)
+ {
+ GtkWidget *dialog;
+
+ dialog = gtk_message_dialog_new (GTK_WINDOW (window),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_CLOSE,
+ "Unable to open image file 'gtk-logo-rgb.gif': %s",
+ error->message);
+ g_error_free (error);
+
+ gtk_signal_connect (GTK_OBJECT (dialog),
+ "response",
+ GTK_SIGNAL_FUNC (gtk_widget_destroy),
+ NULL);
+
+ gtk_widget_show (dialog);
+ }
+
+ image = gtk_image_new_from_pixbuf (pixbuf);
+ }
+ else
+ {
+ /* This is the simpler code, with no error handling.
+ * Here we're loading the installed gtk-logo-rgb.gif instead
+ * of the one in the current directory.
+ */
+ image = gtk_image_new_from_file (DEMOCODEDIR"/gtk-logo-rgb.gif");
+ }
+
+ gtk_container_add (GTK_CONTAINER (frame), image);
+
+ label = gtk_label_new (NULL);
+ gtk_label_set_markup (GTK_LABEL (label),
+ "<u>Progressive image loading</u>");
+ gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
+
+ frame = gtk_frame_new (NULL);
+ gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
+ /* The alignment keeps the frame from growing when users resize
+ * the window
+ */
+ align = gtk_alignment_new (0.5, 0.5, 0, 0);
+ gtk_container_add (GTK_CONTAINER (align), frame);
+ gtk_box_pack_start (GTK_BOX (vbox), align, FALSE, FALSE, 0);
+
+ /* Create an empty image for now; the progressive loader
+ * will create the pixbuf and fill it in.
+ */
+ image = gtk_image_new_from_pixbuf (NULL);
+ gtk_container_add (GTK_CONTAINER (frame), image);
+
+ start_progressive_loading (image);
+ }
+
+ if (!GTK_WIDGET_VISIBLE (window))
+ {
+ gtk_widget_show_all (window);
+ }
+ else
+ {
+ gtk_widget_destroy (window);
+ window = NULL;
+ }
+
+ return window;
+}
diff --git a/demos/gtk-demo/main.c b/demos/gtk-demo/main.c
index 0dfb4b1e26..fabf898d44 100644
--- a/demos/gtk-demo/main.c
+++ b/demos/gtk-demo/main.c
@@ -299,16 +299,18 @@ button_press_event_cb (GtkTreeView *tree_view,
return FALSE;
}
-gboolean
+void
row_activated_cb (GtkTreeView *tree_view,
- GtkTreePath *path,
- GtkTreeViewColumn *column,
- GtkTreeModel *model)
+ GtkTreePath *path,
+ GtkTreeViewColumn *column)
{
GtkTreeIter iter;
gboolean italic;
GDoDemoFunc func;
GtkWidget *window;
+ GtkTreeModel *model;
+
+ model = gtk_tree_view_get_model (tree_view);
gtk_tree_model_get_iter (model, &iter, path);
gtk_tree_model_get (GTK_TREE_MODEL (model),
@@ -321,6 +323,7 @@ row_activated_cb (GtkTreeView *tree_view,
ITALIC_COLUMN, !italic,
-1);
window = (func) ();
+
if (window != NULL)
{
CallbackData *cbdata;
@@ -334,10 +337,6 @@ row_activated_cb (GtkTreeView *tree_view,
window_closed_cb,
cbdata);
}
- else
- {
- gtk_tree_path_free (path);
- }
}
static void
@@ -385,9 +384,20 @@ create_text (GtkTextBuffer **buffer,
font_desc = pango_font_description_from_string ("Courier 10");
gtk_widget_modify_font (text_view, font_desc);
pango_font_description_free (font_desc);
+
+ gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (text_view),
+ GTK_WRAP_NONE);
+ }
+ else
+ {
+ /* Make it a bit nicer for text. */
+ gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (text_view),
+ GTK_WRAP_WORD);
+ gtk_text_view_set_pixels_above_lines (GTK_TEXT_VIEW (text_view),
+ 2);
+ gtk_text_view_set_pixels_below_lines (GTK_TEXT_VIEW (text_view),
+ 2);
}
-
- gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (text_view), !is_source);
return scrolled_window;
}
@@ -458,6 +468,7 @@ main (int argc, char **argv)
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_title (GTK_WINDOW (window), "GTK+ Code Demos");
gtk_signal_connect (GTK_OBJECT (window), "destroy",
GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
diff --git a/demos/gtk-demo/menus.c b/demos/gtk-demo/menus.c
index ac8a7e2c53..4788edd861 100644
--- a/demos/gtk-demo/menus.c
+++ b/demos/gtk-demo/menus.c
@@ -1,10 +1,31 @@
/* Menus
*
- * GTK+ includes a number of widgets for menus of actions.
- * GtkMenu is a drop-down menu, GtkMenuBar a horizontal menu bar.
- * Each of these widgets can hold various types of menuitem.
- * As well as the base type, GtkMenuItem, there are GtkCheckMenuItem,
- * GtkRadioMenuItem and GtkTearoffMenuItem.
+ * There are several widgets involved in displaying menus. The
+ * GtkMenuBar widget is a horizontal menu bar, which normally appears
+ * at the top of an application. The GtkMenu widget is the actual menu
+ * that pops up. Both GtkMenuBar and GtkMenu are subclasses of
+ * GtkMenuShell; a GtkMenuShell contains menu items
+ * (GtkMenuItem). Each menu item contains text and/or images and can
+ * be selected by the user.
+ *
+ * There are several kinds of menu item, including plain GtkMenuItem,
+ * GtkCheckMenuItem which can be checked/unchecked, GtkRadioMenuItem
+ * which is a check menu item that's in a mutually exclusive group,
+ * GtkSeparatorMenuItem which is a separator bar, GtkTearoffMenuItem
+ * which allows a GtkMenu to be torn off, and GtkImageMenuItem which
+ * can place a GtkImage or other widget next to the menu text.
+ *
+ * A GtkMenuItem can have a submenu, which is simply a GtkMenu to pop
+ * up when the menu item is selected. Typically, all menu items in a menu bar
+ * have submenus.
+ *
+ * The GtkOptionMenu widget is a button that pops up a GtkMenu when clicked.
+ * It's used inside dialogs and such.
+ *
+ * GtkItemFactory provides a higher-level interface for creating menu bars
+ * and menus; while you can construct menus manually, most people don't
+ * do that. There's a separate demo for GtkItemFactory.
+ *
*/
#include <stdio.h>
@@ -39,8 +60,7 @@ create_menu (gint depth, gboolean tearoff)
sprintf (buf, "item %2d - %d", depth, j);
menuitem = gtk_radio_menu_item_new_with_label (group, buf);
group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem));
- if (depth % 2)
- gtk_check_menu_item_set_show_toggle (GTK_CHECK_MENU_ITEM (menuitem), TRUE);
+
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
gtk_widget_show (menuitem);
if (i == 3)
diff --git a/demos/gtk-demo/pixbufs.c b/demos/gtk-demo/pixbufs.c
new file mode 100644
index 0000000000..6c067098ac
--- /dev/null
+++ b/demos/gtk-demo/pixbufs.c
@@ -0,0 +1,277 @@
+/* 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.
+ *
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <gtk/gtk.h>
+#include <math.h>
+
+
+
+#define FRAME_DELAY 50
+
+#define RELATIVE_BACKGROUND_NAME "background.jpg"
+#define INSTALLED_BACKGROUND_NAME DEMOCODEDIR"/background.jpg"
+
+static const char *relative_image_names[] = {
+ "apple-red.png",
+ "gnome-applets.png",
+ "gnome-calendar.png",
+ "gnome-foot.png",
+ "gnome-gmush.png",
+ "gnome-gimp.png",
+ "gnome-gsame.png",
+ "gnu-keys.png"
+};
+
+static const char *installed_image_names[] = {
+ DEMOCODEDIR"/apple-red.png",
+ DEMOCODEDIR"/gnome-applets.png",
+ DEMOCODEDIR"/gnome-calendar.png",
+ DEMOCODEDIR"/gnome-foot.png",
+ DEMOCODEDIR"/gnome-gmush.png",
+ DEMOCODEDIR"/gnome-gimp.png",
+ DEMOCODEDIR"/gnome-gsame.png",
+ DEMOCODEDIR"/gnu-keys.png"
+};
+
+#define N_IMAGES G_N_ELEMENTS (relative_image_names)
+
+/* demo window */
+static GtkWindow *window = NULL;
+
+/* Current frame */
+static GdkPixbuf *frame;
+
+/* Background image */
+static GdkPixbuf *background;
+static int back_width, back_height;
+
+/* 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)
+{
+ int i;
+ const char **image_names;
+
+ if (background)
+ return TRUE; /* already loaded earlier */
+
+ background = gdk_pixbuf_new_from_file (RELATIVE_BACKGROUND_NAME, NULL);
+
+ if (!background)
+ background = gdk_pixbuf_new_from_file (INSTALLED_BACKGROUND_NAME, error);
+
+ if (!background)
+ return FALSE; /* note that "error" was filled in and returned */
+
+ back_width = gdk_pixbuf_get_width (background);
+ back_height = gdk_pixbuf_get_height (background);
+
+ if (g_file_test (relative_image_names[0], G_FILE_TEST_EXISTS))
+ image_names = relative_image_names;
+ else
+ image_names = installed_image_names;
+
+ for (i = 0; i < N_IMAGES; i++)
+ {
+ images[i] = gdk_pixbuf_new_from_file (image_names[i], error);
+ if (!images[i])
+ return FALSE; /* Note that "error" was filled with a GError */
+ }
+
+ return TRUE;
+}
+
+/* Expose callback for the drawing area */
+static gint
+expose_cb (GtkWidget *widget, GdkEventExpose *event, gpointer data)
+{
+ guchar *pixels;
+ int rowstride;
+
+ rowstride = gdk_pixbuf_get_rowstride (frame);
+
+ pixels = gdk_pixbuf_get_pixels (frame) + rowstride * event->area.y + event->area.x * 3;
+
+ gdk_draw_rgb_image_dithalign (widget->window,
+ 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);
+
+ 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,
+ frame, 0, 0);
+
+ 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;
+
+ ang = 2.0 * M_PI * (double) i / N_IMAGES - f * 2.0 * M_PI;
+
+ iw = gdk_pixbuf_get_width (images[i]);
+ ih = gdk_pixbuf_get_height (images[i]);
+
+ r = radius + (radius / 3.0) * sin (f * 2.0 * M_PI);
+
+ xpos = floor (xmid + r * cos (ang) - iw / 2.0 + 0.5);
+ ypos = floor (ymid + r * sin (ang) - ih / 2.0 + 0.5);
+
+ k = (i & 1) ? sin (f * 2.0 * M_PI) : cos (f * 2.0 * M_PI);
+ 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))
+ gdk_pixbuf_composite (images[i],
+ frame,
+ dest.x, dest.y,
+ dest.width, dest.height,
+ xpos, ypos,
+ k, k,
+ GDK_INTERP_NEAREST,
+ ((i & 1)
+ ? MAX (127, fabs (255 * sin (f * 2.0 * M_PI)))
+ : MAX (127, fabs (255 * cos (f * 2.0 * M_PI)))));
+ }
+
+ gtk_widget_queue_draw (da);
+
+ frame_num++;
+ return TRUE;
+}
+
+static guint timeout_id;
+
+static void
+cleanup_callback (GtkObject *object,
+ gpointer data)
+{
+ g_source_remove (timeout_id);
+ timeout_id = 0;
+}
+
+GtkWidget *
+do_pixbufs (void)
+{
+ if (!window)
+ {
+ GError *error;
+
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_title (GTK_WINDOW (window), "Pixbufs");
+ gtk_window_set_resizeable (GTK_WINDOW (window), FALSE);
+
+ gtk_signal_connect (GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC (gtk_widget_destroyed), &window);
+ gtk_signal_connect (GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC (cleanup_callback), NULL);
+
+
+ error = NULL;
+ if (!load_pixbufs (&error))
+ {
+ 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);
+
+ gtk_signal_connect (GTK_OBJECT (dialog),
+ "response",
+ GTK_SIGNAL_FUNC (gtk_widget_destroy),
+ NULL);
+
+ gtk_widget_show (dialog);
+ }
+ else
+ {
+ gtk_widget_set_usize (window, back_width, back_height);
+
+ frame = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, back_width, back_height);
+
+ da = gtk_drawing_area_new ();
+
+ gtk_signal_connect (GTK_OBJECT (da), "expose_event",
+ GTK_SIGNAL_FUNC (expose_cb), NULL);
+
+ gtk_container_add (GTK_CONTAINER (window), da);
+
+ timeout_id = gtk_timeout_add (FRAME_DELAY, timeout, NULL);
+ }
+ }
+
+ if (!GTK_WIDGET_VISIBLE (window))
+ {
+ gtk_widget_show_all (window);
+ }
+ else
+ {
+ gtk_widget_destroy (window);
+ window = NULL;
+ }
+
+ return window;
+}