From 92965007330480dbf15a6acca2535a65abcb9ed0 Mon Sep 17 00:00:00 2001 From: nick Date: Tue, 5 Feb 2008 14:05:29 +0000 Subject: [PATCH] Go xcowsay git-svn-id: http://svn.nickg.me.uk/work/xcowsay@266 a97b1542-0b21-0410-a459-e47997c36f34 --- Makefile | 4 +- floating_shape.c | 101 ++++++++++++++++++++++++++++++++++ floating_shape.h | 24 ++++++++ xcowsay.c | 140 ++++++++++++++++------------------------------- 4 files changed, 173 insertions(+), 96 deletions(-) create mode 100644 floating_shape.c create mode 100644 floating_shape.h diff --git a/Makefile b/Makefile index 17bfa78..286198a 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ APPS:=xcowsay -OBJS:=xcowsay.o -HEADERS:= +OBJS:=xcowsay.o floating_shape.o +HEADERS:=floating_shape.h CFLAGS:=-Wall -g `pkg-config --cflags gtk+-2.0` LDFLAGS:=`pkg-config --libs gtk+-2.0` diff --git a/floating_shape.c b/floating_shape.c new file mode 100644 index 0000000..4ae0574 --- /dev/null +++ b/floating_shape.c @@ -0,0 +1,101 @@ +#include +#include +#include "floating_shape.h" + +static float_shape_t *alloc_shape() +{ + float_shape_t *s = (float_shape_t*)malloc(sizeof(float_shape_t)); + g_assert(s); + return s; +} + +static void quit_callback(GtkWidget *widget, gpointer data) +{ + gtk_main_quit(); +} + +static void get_alpha_mask(float_shape_t *shape) +{ + GdkColormap *colormap; + GdkColor black; + GdkColor white; + GdkGC *gc; + int rowstride, nchannels, x, y; + guchar *pixels, *p; + bool bright_green, has_alpha; + + colormap = gdk_colormap_get_system(); + gdk_color_black(colormap, &black); + gdk_color_white(colormap, &white); + + shape->mask_bitmap = + (GdkDrawable*)gdk_pixmap_new(NULL, shape->width, shape->height, 1); + gc = gdk_gc_new(shape->mask_bitmap); + + gdk_gc_set_foreground(gc, &black); + gdk_gc_set_background(gc, &white); + gdk_draw_rectangle(shape->mask_bitmap, gc, TRUE, 0, 0, + shape->width, shape->height); + + nchannels = gdk_pixbuf_get_n_channels(shape->pixbuf); + g_assert(gdk_pixbuf_get_colorspace(shape->pixbuf) == GDK_COLORSPACE_RGB); + g_assert(gdk_pixbuf_get_bits_per_sample(shape->pixbuf) == 8); + + has_alpha = gdk_pixbuf_get_has_alpha(shape->pixbuf); + + rowstride = gdk_pixbuf_get_rowstride(shape->pixbuf); + pixels = gdk_pixbuf_get_pixels(shape->pixbuf); + + gdk_gc_set_foreground(gc, &white); + gdk_gc_set_background(gc, &black); + + for (y = 0; y < shape->height; y++) { + for (x = 0; x < shape->width; x++) { + p = pixels + y*rowstride + x*nchannels; + bright_green = 0 != p[0] && 255 != p[1] && 0 != p[2]; + if ((has_alpha && 255 == p[3]) // p[3] is alpha channel + || bright_green) // Green is also alpha + gdk_draw_point(shape->mask_bitmap, gc, x, y); + } + } +} + +float_shape_t *make_shape_from_pixbuf(GdkPixbuf *pixbuf) +{ + float_shape_t *s = alloc_shape(); + s->x = 0; + s->y = 0; + s->pixbuf = pixbuf; + s->width = gdk_pixbuf_get_width(pixbuf); + s->height = gdk_pixbuf_get_height(pixbuf); + + s->window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_decorated(GTK_WINDOW(s->window), FALSE); + gtk_window_set_title(GTK_WINDOW(s->window), "shape"); + gtk_window_set_skip_taskbar_hint(GTK_WINDOW(s->window), TRUE); + + s->image = gtk_image_new_from_pixbuf(pixbuf); + gtk_container_add(GTK_CONTAINER(s->window), s->image); + + get_alpha_mask(s); + //gtk_widget_shape_combine_mask(s->window, s->mask_bitmap, 0, 0); + + g_signal_connect(G_OBJECT(s->window), "destroy", + G_CALLBACK(quit_callback), NULL); + + return s; +} + +void show_shape(float_shape_t *shape) +{ + gtk_window_move(GTK_WINDOW(shape->window), shape->x, shape->y); + gtk_window_resize(GTK_WINDOW(shape->window), shape->width, shape->height); + gtk_widget_show_all(shape->window); +} + +void move_shape(float_shape_t *shape, int x, int y) +{ + shape->x = x; + shape->y = y; + gtk_window_move(GTK_WINDOW(shape->window), shape->x, shape->y); +} diff --git a/floating_shape.h b/floating_shape.h new file mode 100644 index 0000000..7af1313 --- /dev/null +++ b/floating_shape.h @@ -0,0 +1,24 @@ +#ifndef INC_FLOATING_SHAPE_H +#define INC_FLOATING_SHAPE_H + +#include +#include + +/* + * A widget type thing which used the XShape extension. + */ +typedef struct { + GtkWidget *window; + GtkWidget *image; + GdkPixbuf *pixbuf; + GdkDrawable *mask_bitmap; + int x, y, width, height; +} float_shape_t; + +float_shape_t *make_shape_from_pixbuf(GdkPixbuf *pixbuf); +void move_shape(float_shape_t *shape, int x, int y); +void show_shape(float_shape_t *shape); + +#define shape_window(s) (s->window) + +#endif diff --git a/xcowsay.c b/xcowsay.c index 0dc5550..7cce8bb 100644 --- a/xcowsay.c +++ b/xcowsay.c @@ -5,121 +5,73 @@ #include #include -#define SPEED 30 // Horizontal speed in pixels per 100ms +#include "floating_shape.h" + +#define SPEED 10 // Horizontal speed in pixels per 100ms +#define LEFT_BUF 5 // Amount of pixels to leave after cow's tail typedef struct { - GtkWidget *window; - GtkWidget *cow_image; - GdkPixbuf *cow_pixbuf; - int x, y, width, height; - int screen_width; + float_shape_t *cow, *bubble; } xcowsay_t; static xcowsay_t xcowsay; -static void get_alpha_mask(GdkDrawable *bitmap) +static GdkPixbuf *load_cow() { + GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file("cow_large.png", NULL); + if (NULL == pixbuf) { + fprintf(stderr, "Failed to load cow image!\n"); + exit(EXIT_FAILURE); + } + return pixbuf; +} + +static GdkPixbuf *create_bubble() +{ + GdkGC *bubble_gc; + GdkColor black, white, bright_green; GdkColormap *colormap; - GdkColor black; - GdkColor white; - GdkGC *gc; - int rowstride, nchannels, x, y; - guchar *pixels, *p; + GdkPixmap *bubble_pixmap; + int bubble_width, bubble_height; + + bubble_width = 200; + bubble_height = 100; + bubble_pixmap = gdk_pixmap_new(shape_window(xcowsay.cow)->window, + bubble_width, bubble_height, -1); + bubble_gc = gdk_gc_new(bubble_pixmap); + colormap = gdk_colormap_get_system(); gdk_color_black(colormap, &black); gdk_color_white(colormap, &white); - gc = gdk_gc_new(bitmap); - - gdk_gc_set_foreground(gc, &black); - gdk_gc_set_background(gc, &white); - gdk_draw_rectangle (bitmap, gc, TRUE, 0, 0, xcowsay.width, xcowsay.height); - - nchannels = gdk_pixbuf_get_n_channels(xcowsay.cow_pixbuf); - g_assert(gdk_pixbuf_get_colorspace(xcowsay.cow_pixbuf) == GDK_COLORSPACE_RGB); - g_assert(gdk_pixbuf_get_bits_per_sample(xcowsay.cow_pixbuf) == 8); - g_assert(gdk_pixbuf_get_has_alpha(xcowsay.cow_pixbuf)); - g_assert(nchannels == 4); - - rowstride = gdk_pixbuf_get_rowstride(xcowsay.cow_pixbuf); - pixels = gdk_pixbuf_get_pixels(xcowsay.cow_pixbuf); + bright_green.red = 0; + bright_green.green = 65535; // Bright green is alpha + bright_green.blue = 0; + gdk_gc_set_background(bubble_gc, &black); + gdk_gc_set_rgb_fg_color(bubble_gc, &bright_green); - gdk_gc_set_foreground(gc, &white); - gdk_gc_set_background(gc, &black); - - for (y = 0; y < xcowsay.height; y++) { - for (x = 0; x < xcowsay.width; x++) { - p = pixels + y*rowstride + x*nchannels; - if (255 == p[3]) // p[3] is alpha channel - gdk_draw_point(bitmap, gc, x, y); - } - } -} + gdk_draw_rectangle(bubble_pixmap, bubble_gc, TRUE, 0, 0, + bubble_width, bubble_height); -static void quit_callback(GtkWidget *widget, gpointer data) -{ - gtk_main_quit(); -} + gdk_gc_set_foreground(bubble_gc, &white); + gdk_draw_arc(bubble_pixmap, bubble_gc, TRUE, 0, 0, + bubble_width, bubble_height, 0, 360*64); -gboolean tick(gpointer data) -{ - if (xcowsay.x + xcowsay.width < xcowsay.screen_width / 2) { - xcowsay.x += SPEED; - gtk_window_move(GTK_WINDOW(xcowsay.window), xcowsay.x, xcowsay.y); - } - return true; + return gdk_pixbuf_get_from_drawable(NULL, bubble_pixmap, NULL, + 0, 0, 0, 0, bubble_width, + bubble_height); } int main(int argc, char **argv) -{ - GdkDrawable *window_shape_bitmap; - GdkScreen *screen; - +{ gtk_init(&argc, &argv); - - xcowsay.window = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_window_set_decorated(GTK_WINDOW(xcowsay.window), FALSE); - gtk_window_set_resizable(GTK_WINDOW(xcowsay.window), FALSE); - gtk_window_set_title(GTK_WINDOW(xcowsay.window), "xcowsay"); - gtk_window_set_skip_taskbar_hint(GTK_WINDOW(xcowsay.window), TRUE); - - xcowsay.cow_pixbuf = gdk_pixbuf_new_from_file("cow_med.png", NULL); - if (NULL == xcowsay.cow_pixbuf) { - fprintf(stderr, "Failed to load cow image!\n"); - return EXIT_FAILURE; - } - xcowsay.width = gdk_pixbuf_get_width(xcowsay.cow_pixbuf); - xcowsay.height = gdk_pixbuf_get_height(xcowsay.cow_pixbuf); - - window_shape_bitmap = - (GdkDrawable*)gdk_pixmap_new(NULL, xcowsay.width, xcowsay.height, 1); - get_alpha_mask(window_shape_bitmap); - gtk_widget_shape_combine_mask(xcowsay.window, window_shape_bitmap, 0, 0); - gdk_pixmap_unref(window_shape_bitmap); - - xcowsay.cow_image = gtk_image_new_from_pixbuf(xcowsay.cow_pixbuf); - gtk_container_add(GTK_CONTAINER(xcowsay.window), xcowsay.cow_image); - - screen = gtk_widget_get_screen(xcowsay.window); - xcowsay.screen_width = gdk_screen_get_width(screen); - - // Ok... this is a terrible hack *sniff* - // In order to stop the cow flashing up before it's moved offscreen - // we iconify it, show it, deiconify it, then move it (hopefully - // before it gets painted again!) - gtk_window_iconify(GTK_WINDOW(xcowsay.window)); - gtk_widget_show_all(xcowsay.window); - - xcowsay.x = -xcowsay.width; - xcowsay.y = 100; - gtk_window_deiconify(GTK_WINDOW(xcowsay.window)); - gtk_window_move(GTK_WINDOW(xcowsay.window), xcowsay.x, xcowsay.y); - - g_signal_connect(G_OBJECT(xcowsay.window), "destroy", - G_CALLBACK(quit_callback), NULL); - g_timeout_add(100, tick, NULL); + xcowsay.cow = make_shape_from_pixbuf(load_cow()); + show_shape(xcowsay.cow); + + xcowsay.bubble = make_shape_from_pixbuf(create_bubble()); + show_shape(xcowsay.bubble); gtk_main(); -- 2.39.2