#include #include #include #include #include #include #include #if GTK_CHECK_VERSION (3, 0, 0) #include #endif #include #ifdef CA_CHECK_VERSION #if CA_CHECK_VERSION(0, 13) #define HAVE_CANBERRA_GTK_MULTIHEAD_SAFE #endif #endif #include "panel-util.h" #include "nothing.h" #if !GTK_CHECK_VERSION (3, 0, 0) static void pixbuf_reverse (GdkPixbuf *gp) { guchar *pixels = gdk_pixbuf_get_pixels (gp); int rs = gdk_pixbuf_get_rowstride (gp); int w = gdk_pixbuf_get_width (gp); int h = gdk_pixbuf_get_height (gp); int x, y; #define DOSWAP(x,y) tmp = x; x = y; y = tmp; for (y = 0; y < h; y++, pixels += rs) { guchar *p = pixels; guchar *p2 = pixels + w*4 - 4; for (x = 0; x < w/2; x++, p+=4, p2-=4) { guchar tmp; DOSWAP (p[0], p2[0]); DOSWAP (p[1], p2[1]); DOSWAP (p[2], p2[2]); DOSWAP (p[3], p2[3]); } } #undef DOSWAP } /* This unsea's the phsh */ /*code snippet, not to be compiled separately*/ static gboolean goat_loaded=FALSE; static int goat_frame=0; static GdkPixmap *goat_pix[2] = {NULL,NULL}; static GdkPixmap *goat_pix_rev[2] = {NULL,NULL}; static GtkWidget *goat_darea = NULL; static int goat_width = 0,goat_height = 0; static int goat_timeout = 0; static int goat_x = -1, goat_y = -1; static int goat_accx = -1, goat_accy = -1; static void destroy_egg(GtkWidget *widget, gpointer data) { int i; goat_loaded = FALSE; if(goat_timeout) { g_source_remove(goat_timeout); goat_timeout = 0; } for (i = 0; i < 2; i++) { if (goat_pix[i] != NULL) g_object_unref (G_OBJECT (goat_pix[i])); goat_pix[i] = NULL; if (goat_pix_rev[i] != NULL) g_object_unref (G_OBJECT (goat_pix_rev[i])); goat_pix_rev[i] = NULL; } goat_x = goat_y = -1; } static int goat_timeout_func(gpointer data) { GtkAllocation allocation; cairo_t *cr; int real_goat_frame; gboolean sound = FALSE; int old_x; int old_y; if(!gtk_widget_get_realized(goat_darea) || !gtk_widget_is_drawable(goat_darea)) return TRUE; if (!goat_pix[0] || !goat_pix[1]) { destroy_egg (NULL, NULL); return FALSE; } gtk_widget_get_allocation (goat_darea, &allocation); cr = gdk_cairo_create (gtk_widget_get_window (goat_darea)); if(goat_x == -1) { cairo_set_source_rgb (cr, 1, 1, 1); cairo_paint (cr); goat_x = 2; goat_y = 2; goat_accx = g_random_int()%4 +3; goat_accy = g_random_int()%4 +3; } old_x = goat_x; old_y = goat_y; goat_x += goat_accx; goat_y += goat_accy; if(goat_x>allocation.width-2-goat_width) { goat_accx = -(g_random_int()%4 +3); goat_x = allocation.width-2-goat_width; sound = TRUE; } else if(goat_x<2) { goat_accx = g_random_int()%4 +3; goat_x = 2; sound = TRUE; } if(goat_y>allocation.height-2-goat_height) { goat_accy = -(g_random_int()%4 +3); goat_y = allocation.height-2-goat_height; sound = TRUE; } else if(goat_y<2) { goat_accy = g_random_int()%4 +3; goat_y = 2; sound = TRUE; } if (sound) { #ifdef HAVE_CANBERRA_GTK_MULTIHEAD_SAFE ca_context_cancel (ca_gtk_context_get_for_screen (gtk_widget_get_screen (goat_darea)), 42); #else ca_context_cancel (ca_gtk_context_get (), 42); #endif ca_gtk_play_for_widget (goat_darea, 42, CA_PROP_EVENT_ID, "bell-window-system", CA_PROP_EVENT_DESCRIPTION, "Ouch! This box is small!", NULL); } real_goat_frame = goat_frame/2; cairo_rectangle (cr, MIN(old_x, goat_x), MIN(old_y, goat_y), goat_width + ABS(goat_x-old_x) + 6, goat_height + ABS(goat_y-old_y) + 6); cairo_set_source_rgb (cr, 1, 1, 1); cairo_paint (cr); gdk_cairo_set_source_pixmap (cr, goat_accx<0?goat_pix[real_goat_frame]: goat_pix_rev[real_goat_frame], goat_x,goat_y); cairo_paint (cr); if(++goat_frame == 4) goat_frame = 0; cairo_destroy (cr); return TRUE; } static int goat_expose(GtkWidget *widget, GdkEventExpose *event) { cairo_t *cr; if(!gtk_widget_is_drawable(widget)) return FALSE; cr = gdk_cairo_create (gtk_widget_get_window (goat_darea)); cairo_set_source_rgb (cr, 1, 1, 1); cairo_paint (cr); cairo_destroy (cr); return FALSE; } static void goat_realize(GtkWidget *widget) { GdkWindow *window; int frame; char *files[] = { "mate-gegl2.png", "mate-gegl2-2.png" }; if(goat_pix[0]) return; window = gtk_widget_get_window (widget); for(frame=0;frame<2;frame++) { GdkPixbuf *pb; char *file; int width; int height; cairo_t *cr; cairo_matrix_t matrix; cairo_pattern_t *pattern; file = g_strdup_printf ("%s/%s", ICONDIR, files[frame]); if(!file) return; pb=gdk_pixbuf_new_from_file (file, NULL); g_free(file); if(!pb) { g_warning("Goat is not available!"); return; } width = gdk_pixbuf_get_width(pb); height = gdk_pixbuf_get_height(pb); goat_pix[frame] = gdk_pixmap_new(window, width, height, -1); cr = gdk_cairo_create (goat_pix[frame]); gdk_cairo_set_source_pixbuf (cr, pb, 0, 0); cairo_paint (cr); cairo_destroy (cr); goat_pix_rev[frame] = gdk_pixmap_new(window, width, height, -1); cr = gdk_cairo_create (goat_pix_rev[frame]); gdk_cairo_set_source_pixbuf (cr, pb, 0, 0); cairo_matrix_init_identity (&matrix); cairo_matrix_translate (&matrix, width, 0); /* scale in -X direction to flip along X */ cairo_matrix_scale (&matrix, -1.0, 1.0); pattern = cairo_get_source (cr); cairo_pattern_set_filter (pattern, CAIRO_FILTER_BEST); cairo_pattern_set_matrix (pattern, &matrix); cairo_rectangle (cr, 0, 0, width, height); cairo_fill (cr); cairo_destroy (cr); goat_width = MAX (width, goat_width); goat_height = MAX (height, goat_height); g_object_unref (pb); } } /*thy evil easter egg*/ int config_event(GtkWidget *widget,GdkEvent *event,GtkNotebook *nbook) { static int clicks=0; GdkEventButton *bevent; if (!nbook) return FALSE; if(event->type != GDK_BUTTON_PRESS) return FALSE; bevent = (GdkEventButton *)event; if(bevent->button != 3) clicks = 0; else clicks++; if(clicks<3) return FALSE; clicks = 0; if(!goat_loaded) { goat_darea = gtk_drawing_area_new(); g_signal_connect (G_OBJECT(goat_darea),"destroy", G_CALLBACK (destroy_egg),NULL); g_signal_connect (GTK_OBJECT(goat_darea),"expose_event", G_CALLBACK (goat_expose),NULL); g_signal_connect_after (G_OBJECT(goat_darea),"realize", G_CALLBACK (goat_realize),NULL); gtk_widget_show(goat_darea); goat_timeout = g_timeout_add(60,goat_timeout_func,NULL); /*the GEGL shall not be translated*/ g_object_set (G_OBJECT (nbook), "show_tabs", TRUE, "show_border", TRUE, NULL); gtk_notebook_append_page (nbook, goat_darea, gtk_label_new ("GEGL")); gtk_notebook_set_current_page(nbook,-1); goat_loaded = TRUE; } else { gtk_notebook_set_current_page(nbook,-1); } return FALSE; } /* phish code */ #define PHSHFRAMES 8 #define PHSHORIGWIDTH 288 #define PHSHORIGHEIGHT 22 #define PHSHWIDTH (PHSHORIGWIDTH/PHSHFRAMES) #define PHSHHEIGHT PHSHORIGHEIGHT #define PHSHCHECKTIMEOUT (g_random_int()%120*1000) #define PHSHTIMEOUT 120 #define PHSHHIDETIMEOUT 80 #define PHSHXS 5 #define PHSHYS ((g_random_int() % 2) + 1) #define PHSHXSHIDEFACTOR 2.5 #define PHSHYSHIDEFACTOR 2.5 #define PHSHPIXELSTOREMOVE(p) (p[3] < 55 || p[2] > 200) /* Some important code copied from PonG */ typedef struct _AppletContainer AppletContainer; struct _AppletContainer { GdkWindow *win; gboolean hide_mode; int state; int x, y, xs, ys; int handler; GdkPixmap *phsh[2*PHSHFRAMES]; GdkBitmap *phsh_mask[2*PHSHFRAMES]; }; static AppletContainer phsh = {NULL}; static void phsh_kill (void) { int i; for (i = 0; i < 2*PHSHFRAMES; i++) { if (phsh.phsh[i] != NULL) g_object_unref (G_OBJECT (phsh.phsh[i])); phsh.phsh[i] = NULL; if (phsh.phsh_mask[i] != NULL) g_object_unref (G_OBJECT (phsh.phsh_mask[i])); phsh.phsh_mask[i] = NULL; } gdk_window_destroy (phsh.win); g_source_remove (phsh.handler); memset (&phsh, 0, sizeof (AppletContainer)); } static gboolean phsh_move (gpointer data) { int orient, state; gboolean change = TRUE; phsh.x += phsh.xs; phsh.y += phsh.ys; if (phsh.x <= -PHSHWIDTH || phsh.x >= gdk_screen_width ()) { phsh_kill (); return FALSE; } if (phsh.y <= 0 || phsh.y >= gdk_screen_height () - PHSHHEIGHT || g_random_int() % (phsh.hide_mode?10:50) == 0) phsh.ys = -phsh.ys; phsh.state ++; if (phsh.hide_mode) { phsh.state ++; if (phsh.state >= 2*PHSHFRAMES) phsh.state = 0; } else if (phsh.state >= PHSHFRAMES) phsh.state = 0; if (!phsh.hide_mode || phsh.state % 2 == 0) change = TRUE; state = phsh.state / (phsh.hide_mode?2:1); orient = phsh.xs >= 0 ? 0 : 1; if (change) { gdk_window_set_back_pixmap (phsh.win, phsh.phsh[orient + 2*state], FALSE); gdk_window_shape_combine_mask (phsh.win, phsh.phsh_mask[orient + 2*state], 0, 0); gdk_window_clear (phsh.win); } gdk_window_move (phsh.win, phsh.x, phsh.y); gdk_window_raise (phsh.win); return TRUE; } static void phsh_unsea(GdkPixbuf *gp) { guchar *pixels = gdk_pixbuf_get_pixels (gp); int rs = gdk_pixbuf_get_rowstride (gp); int w = gdk_pixbuf_get_width (gp); int h = gdk_pixbuf_get_height (gp); int x, y; for (y = 0; y < h; y++, pixels += rs) { guchar *p = pixels; for (x = 0; x < w; x++, p+=4) { if (PHSHPIXELSTOREMOVE(p)) p[3] = 0; } } } static GdkFilterReturn phsh_filter (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data) { XEvent *xevent = (XEvent *)gdk_xevent; if (xevent->type == ButtonPress && ! phsh.hide_mode) { g_source_remove (phsh.handler); phsh.handler = g_timeout_add (PHSHHIDETIMEOUT, phsh_move, NULL); phsh.xs *= PHSHXSHIDEFACTOR; phsh.ys *= PHSHYSHIDEFACTOR; phsh.hide_mode = TRUE; if (phsh.x < (gdk_screen_width () / 2)) phsh.xs *= -1; } return GDK_FILTER_CONTINUE; } static char * get_phsh_file (void) { char *phsh_file; phsh_file = g_strdup_printf ("%s/%cand%c.png", ICONDIR, 'w', 'a'); return phsh_file; } static GdkPixbuf * get_phsh_frame (GdkPixbuf *pb, int frame) { GdkPixbuf *newpb; newpb = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, PHSHWIDTH, PHSHHEIGHT); gdk_pixbuf_copy_area (pb, frame * PHSHWIDTH, 0, PHSHWIDTH, PHSHHEIGHT, newpb, 0, 0); return newpb; } /* this checks the screen */ static void check_screen (void) { GdkWindowAttr attributes; char *phsh_file; GdkPixbuf *gp, *tmp; int i; if (phsh.win != NULL) return; phsh_file = get_phsh_file (); if (phsh_file == NULL) return; tmp = gdk_pixbuf_new_from_file (phsh_file, NULL); if (tmp == NULL) return; g_free (phsh_file); if (gdk_pixbuf_get_width (tmp) != PHSHORIGWIDTH || gdk_pixbuf_get_height (tmp) != PHSHORIGHEIGHT) { g_object_unref (G_OBJECT (tmp)); return; } phsh.state = 0; phsh.hide_mode = FALSE; phsh.x = -PHSHWIDTH; phsh.y = (g_random_int() % (gdk_screen_height() - PHSHHEIGHT - 2)) + 1; phsh.xs = PHSHXS; phsh.ys = PHSHYS; for (i = 0; i < PHSHFRAMES; i++) { gp = get_phsh_frame (tmp, i); phsh_unsea (gp); gdk_pixbuf_render_pixmap_and_mask (gp, &phsh.phsh[2*i+1], &phsh.phsh_mask[2*i+1], 128); pixbuf_reverse (gp); gdk_pixbuf_render_pixmap_and_mask (gp, &phsh.phsh[2*i], &phsh.phsh_mask[2*i], 128); g_object_unref (G_OBJECT (gp)); } g_object_unref (G_OBJECT (tmp)); attributes.window_type = GDK_WINDOW_TEMP; attributes.x = phsh.x; attributes.y = phsh.y; attributes.width = PHSHWIDTH; attributes.height = PHSHHEIGHT; attributes.wclass = GDK_INPUT_OUTPUT; attributes.visual = gdk_rgb_get_visual(); attributes.colormap = gdk_rgb_get_colormap(); attributes.event_mask = GDK_BUTTON_PRESS_MASK; phsh.win = gdk_window_new (NULL, &attributes, GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP); gdk_window_set_back_pixmap (phsh.win, phsh.phsh[0], FALSE); gdk_window_shape_combine_mask (phsh.win, phsh.phsh_mask[0], 0, 0); /* setup the keys filter */ gdk_window_add_filter (phsh.win, phsh_filter, NULL); gdk_window_show (phsh.win); phsh.handler = g_timeout_add (PHSHTIMEOUT, phsh_move, NULL); } static guint screen_check_id = 0; static gboolean check_screen_timeout (gpointer data) { screen_check_id = 0; check_screen (); screen_check_id = g_timeout_add (PHSHCHECKTIMEOUT, check_screen_timeout, NULL); return FALSE; } void start_screen_check (void) { if (screen_check_id > 0) g_source_remove (screen_check_id); check_screen_timeout (NULL); } typedef struct { gboolean live; int x, y; } InvGoat; typedef struct { gboolean good; int y; int x; } InvShot; static GtkWidget *geginv = NULL; static GtkWidget *geginv_canvas = NULL; static GtkWidget *geginv_label = NULL; static GdkPixmap *geginv_pixmap = NULL; static GdkPixmap *inv_goat1 = NULL; static GdkPixmap *inv_goat2 = NULL; static GdkPixmap *inv_phsh1 = NULL; static GdkBitmap *inv_phsh1_mask = NULL; static GdkPixmap *inv_phsh2 = NULL; static GdkBitmap *inv_phsh2_mask = NULL; static int inv_phsh_state = 0; static int inv_goat_state = 0; static int inv_width = 0; static int inv_height = 0; static int inv_goat_width = 0; static int inv_goat_height = 0; static int inv_phsh_width = 0; static int inv_phsh_height = 0; #define INV_ROWS 3 #define INV_COLS 5 static InvGoat invs[INV_COLS][INV_ROWS] = { { { FALSE, 0, 0 } } }; static int inv_num = INV_ROWS * INV_COLS; static double inv_factor = 1.0; static int inv_our_x = 0; static int inv_x = 0; static int inv_y = 0; static int inv_first_col = 0; static int inv_last_col = INV_COLS-1; static int inv_level = 0; static int inv_lives = 0; static gboolean inv_do_pause = FALSE; static gboolean inv_reverse = FALSE; static gboolean inv_game_over = FALSE; static gboolean inv_left_pressed = FALSE; static gboolean inv_right_pressed = FALSE; static gboolean inv_fire_pressed = FALSE; static gboolean inv_left_released = FALSE; static gboolean inv_right_released = FALSE; static gboolean inv_fire_released = FALSE; static gboolean inv_paused = FALSE; static GSList *inv_shots = NULL; static guint inv_draw_idle = 0; static void inv_show_status (void) { gchar *s, *t, *u, *v, *w; if (geginv == NULL) return; if (inv_game_over) { t = g_strdup_printf (_("GAME OVER at level %d!"), inv_level+1); u = g_strdup_printf ("%s", t); /* Translators: the first and third strings are similar to a * title, and the second string is a small information text. * The spaces are there only to separate all the strings, so try to keep them as is. */ s = g_strdup_printf (_("%1$s %2$s %3$s"), u, _("Press 'q' to quit"), u); g_free (t); g_free (u); } else if (inv_paused) { t = g_strdup_printf("%s", _("Paused")); /* Translators: the first string is a title and the second * string is a small information text. */ s = g_strdup_printf (_("%1$s\t%2$s"), t, _("Press 'p' to unpause")); g_free (t); } else { t = g_strdup_printf ("%d", inv_level+1); u = g_strdup_printf ("%d", inv_lives); v = g_strdup_printf (_("Level: %s, Lives: %s"), t, u); w = g_strdup_printf ("%s", v); /* Translators: the first string is a title and the second * string is a small information text. */ s = g_strdup_printf (_("%1$s\t%2$s"), w, _("Left/Right to move, Space to fire, 'p' to pause, 'q' to quit")); g_free (t); g_free (u); g_free (v); g_free (w); } gtk_label_set_markup (GTK_LABEL (geginv_label), s); g_free (s); } static gboolean inv_draw (gpointer data) { GtkStyle *style; GdkPixmap *goat; GSList *li; int i, j; if (data != geginv) { inv_draw_idle = 0; return FALSE; } if ( ! gtk_widget_is_drawable (geginv_canvas) || geginv_pixmap == NULL) return TRUE; style = gtk_widget_get_style (geginv_canvas); gdk_draw_rectangle (geginv_pixmap, style->white_gc, TRUE /* filled */, 0, 0, inv_width, inv_height); if (inv_goat_state == 0) goat = inv_goat1; else goat = inv_goat2; for (i = 0; i < INV_COLS; i++) { for (j = 0; j < INV_ROWS; j++) { int x, y; if ( ! invs[i][j].live) continue; x = invs[i][j].x*inv_factor - inv_goat_width/2, y = invs[i][j].y*inv_factor - inv_goat_height/2, gdk_draw_drawable (geginv_pixmap, style->white_gc, goat, 0, 0, x, y, inv_goat_width, inv_goat_height); } } for (li = inv_shots; li != NULL; li = li->next) { InvShot *shot = li->data; gdk_draw_rectangle (geginv_pixmap, style->black_gc, TRUE /* filled */, (shot->x-1)*inv_factor, (shot->y-4)*inv_factor, 3, 8); } if ( ! inv_game_over) { GdkPixmap *phsh; GdkBitmap *mask; if (inv_phsh_state < 5) { phsh = inv_phsh1; mask = inv_phsh1_mask; } else { phsh = inv_phsh2; mask = inv_phsh2_mask; } gdk_gc_set_clip_origin (style->white_gc, inv_our_x*inv_factor - inv_phsh_width/2, 550*inv_factor - inv_phsh_height/2); gdk_gc_set_clip_mask (style->white_gc, mask); gdk_draw_drawable (geginv_pixmap, style->white_gc, phsh, 0, 0, inv_our_x*inv_factor - inv_phsh_width/2, 550*inv_factor - inv_phsh_height/2, inv_phsh_width, inv_phsh_height); gdk_gc_set_clip_origin (style->white_gc, 0, 0); gdk_gc_set_clip_mask (style->white_gc, NULL); } gdk_draw_drawable (gtk_widget_get_window (geginv_canvas), style->white_gc, geginv_pixmap, 0, 0, 0, 0, inv_width, inv_height); gdk_flush (); if (inv_do_pause) { sleep (1); inv_do_pause = FALSE; } inv_draw_idle = 0; return FALSE; } static void inv_queue_draw (GtkWidget *window) { if (inv_draw_idle == 0) inv_draw_idle = g_idle_add (inv_draw, window); } static void inv_draw_explosion (int x, int y) { GdkWindow *window; GtkStyle *style; int i; GdkColormap *cmap; GdkColor red; GdkGC *gc; if ( ! gtk_widget_is_drawable (geginv_canvas)) return; window = gtk_widget_get_window (geginv_canvas); style = gtk_widget_get_style (geginv_canvas); cmap = gdk_drawable_get_colormap (window); gdk_color_parse ("red", &red); gdk_colormap_alloc_color (cmap, &red, FALSE, TRUE); gc = gdk_gc_new (window); gdk_gc_set_foreground (gc, &red); gdk_gc_set_background (gc, &red); for (i = 5; i < 100; i += 5) { gdk_draw_arc (window, gc, TRUE /* filled */, x-i, y-i, i*2, i*2, 0, 360*64); gdk_flush (); g_usleep (50000); } g_object_unref (G_OBJECT (gc)); for (i = 5; i < 100; i += 5) { gdk_draw_arc (window, style->white_gc, TRUE /* filled */, x-i, y-i, i*2, i*2, 0, 360*64); gdk_flush (); g_usleep (50000); } gdk_colormap_free_colors (cmap, &red, 1); inv_queue_draw (geginv); } static void inv_do_game_over (void) { GSList *li; inv_game_over = TRUE; for (li = inv_shots; li != NULL; li = li->next) { InvShot *shot = li->data; shot->good = FALSE; } inv_queue_draw (geginv); inv_show_status (); } static GdkPixbuf * pb_scale (GdkPixbuf *pb, double scale) { int w, h; if (scale == 1.0) return (GdkPixbuf *)g_object_ref ((GObject *)pb); w = gdk_pixbuf_get_width (pb) * scale; h = gdk_pixbuf_get_height (pb) * scale; return gdk_pixbuf_scale_simple (pb, w, h, GDK_INTERP_BILINEAR); } static void refind_first_and_last (void) { int i, j; for (i = 0; i < INV_COLS; i++) { gboolean all_null = TRUE; for (j = 0; j < INV_ROWS; j++) { if (invs[i][j].live) { all_null = FALSE; break; } } if ( ! all_null) { inv_first_col = i; break; } } for (i = INV_COLS-1; i >= 0; i--) { gboolean all_null = TRUE; for (j = 0; j < INV_ROWS; j++) { if (invs[i][j].live) { all_null = FALSE; break; } } if ( ! all_null) { inv_last_col = i; break; } } } static void whack_gegl (int i, int j) { if ( ! invs[i][j].live) return; invs[i][j].live = FALSE; inv_num --; if (inv_num > 0) { refind_first_and_last (); } else { inv_x = 70; inv_y = 70; inv_first_col = 0; inv_last_col = INV_COLS-1; inv_reverse = FALSE; g_slist_foreach (inv_shots, (GFunc)g_free, NULL); g_slist_free (inv_shots); inv_shots = NULL; for (i = 0; i < INV_COLS; i++) { for (j = 0; j < INV_ROWS; j++) { invs[i][j].live = TRUE; invs[i][j].x = 70 + i * 100; invs[i][j].y = 70 + j * 80; } } inv_num = INV_ROWS * INV_COLS; inv_level ++; inv_show_status (); } inv_queue_draw (geginv); } static gboolean geginv_timeout (gpointer data) { int i, j; int limitx1; int limitx2; int speed; int shots; int max_shots; if (inv_paused) return TRUE; if (geginv != data || inv_num <= 0 || inv_y > 700) return FALSE; limitx1 = 70 - (inv_first_col * 100); limitx2 = 800 - 70 - (inv_last_col * 100); if (inv_game_over) { inv_y += 30; } else { if (inv_num < (INV_COLS*INV_ROWS)/3) speed = 45+2*inv_level; else if (inv_num < (2*INV_COLS*INV_ROWS)/3) speed = 30+2*inv_level; else speed = 15+2*inv_level; if (inv_reverse) { inv_x -= speed; if (inv_x < limitx1) { inv_reverse = FALSE; inv_x = (limitx1 + (limitx1 - inv_x)); inv_y += 30+inv_level; } } else { inv_x += speed; if (inv_x > limitx2) { inv_reverse = TRUE; inv_x = (limitx2 - (inv_x - limitx2)); inv_y += 30+inv_level; } } } for (i = 0; i < INV_COLS; i++) { for (j = 0; j < INV_ROWS; j++) { if (invs[i][j].live) { invs[i][j].x = inv_x + i * 100; invs[i][j].y = inv_y + j * 80; if ( ! inv_game_over && invs[i][j].y >= 570) { inv_do_game_over (); } else if ( ! inv_game_over && invs[i][j].y >= 530 && invs[i][j].x + 40 > inv_our_x - 25 && invs[i][j].x - 40 < inv_our_x + 25) { whack_gegl (i,j); inv_lives --; inv_draw_explosion (inv_our_x, 550); if (inv_lives <= 0) { inv_do_game_over (); } else { g_slist_foreach (inv_shots, (GFunc)g_free, NULL); g_slist_free (inv_shots); inv_shots = NULL; inv_our_x = 400; inv_do_pause = TRUE; inv_show_status (); } } } } } shots = 0; max_shots = (g_random_int () >> 3) % (2+inv_level); while ( ! inv_game_over && shots < MIN (max_shots, inv_num)) { int i = (g_random_int () >> 3) % INV_COLS; for (j = INV_ROWS-1; j >= 0; j--) { if (invs[i][j].live) { InvShot *shot = g_new0 (InvShot, 1); shot->good = FALSE; shot->x = invs[i][j].x + (g_random_int () % 6) - 3; shot->y = invs[i][j].y + inv_goat_height/2 + (g_random_int () % 3); inv_shots = g_slist_prepend (inv_shots, shot); shots++; break; } } } inv_goat_state = (inv_goat_state+1) % 2; inv_queue_draw (geginv); g_timeout_add (((inv_num/4)+1) * 100, geginv_timeout, geginv); return FALSE; } static gboolean find_gegls (int x, int y) { int i, j; /* FIXME: this is stupid, we can do better */ for (i = 0; i < INV_COLS; i++) { for (j = 0; j < INV_ROWS; j++) { int ix = invs[i][j].x; int iy = invs[i][j].y; if ( ! invs[i][j].live) continue; if (y >= iy - 30 && y <= iy + 30 && x >= ix - 40 && x <= ix + 40) { whack_gegl (i, j); return TRUE; } } } return FALSE; } static gboolean geginv_move_timeout (gpointer data) { GSList *li; static int shot_inhibit = 0; if (inv_paused) return TRUE; if (geginv != data || inv_num <= 0 || inv_y > 700) return FALSE; inv_phsh_state = (inv_phsh_state+1)%10; /* we will be drawing something */ if (inv_shots != NULL) inv_queue_draw (geginv); li = inv_shots; while (li != NULL) { InvShot *shot = li->data; if (shot->good) { shot->y -= 30; if (find_gegls (shot->x, shot->y) || shot->y <= 0) { GSList *list = li; /* we were restarted */ if (inv_shots == NULL) return TRUE; li = li->next; g_free (shot); inv_shots = g_slist_delete_link (inv_shots, list); continue; } } else /* bad */ { shot->y += 30; if ( ! inv_game_over && shot->y >= 535 && shot->y <= 565 && shot->x >= inv_our_x - 25 && shot->x <= inv_our_x + 25) { inv_lives --; inv_draw_explosion (inv_our_x, 550); if (inv_lives <= 0) { inv_do_game_over (); } else { g_slist_foreach (inv_shots, (GFunc)g_free, NULL); g_slist_free (inv_shots); inv_shots = NULL; inv_our_x = 400; inv_do_pause = TRUE; inv_show_status (); return TRUE; } } if (shot->y >= 600) { GSList *list = li; li = li->next; g_free (shot); inv_shots = g_slist_delete_link (inv_shots, list); continue; } } li = li->next; } if ( ! inv_game_over) { if (inv_left_pressed && inv_our_x > 100) { inv_our_x -= 20; inv_queue_draw (geginv); } else if (inv_right_pressed && inv_our_x < 700) { inv_our_x += 20; inv_queue_draw (geginv); } } if (shot_inhibit > 0) shot_inhibit--; if ( ! inv_game_over && inv_fire_pressed && shot_inhibit == 0) { InvShot *shot = g_new0 (InvShot, 1); shot->good = TRUE; shot->x = inv_our_x; shot->y = 540; inv_shots = g_slist_prepend (inv_shots, shot); shot_inhibit = 5; inv_queue_draw (geginv); } if (inv_left_released) inv_left_pressed = FALSE; if (inv_right_released) inv_right_pressed = FALSE; if (inv_fire_released) inv_fire_pressed = FALSE; return TRUE; } static gboolean inv_key_press (GtkWidget *widget, GdkEventKey *event, gpointer data) { switch (event->keyval) { case GDK_Left: case GDK_KP_Left: case GDK_Pointer_Left: inv_left_pressed = TRUE; inv_left_released = FALSE; return TRUE; case GDK_Right: case GDK_KP_Right: case GDK_Pointer_Right: inv_right_pressed = TRUE; inv_right_released = FALSE; return TRUE; case GDK_space: case GDK_KP_Space: inv_fire_pressed = TRUE; inv_fire_released = FALSE; return TRUE; default: break; } return FALSE; } static gboolean inv_key_release (GtkWidget *widget, GdkEventKey *event, gpointer data) { switch (event->keyval) { case GDK_Left: case GDK_KP_Left: case GDK_Pointer_Left: inv_left_released = TRUE; return TRUE; case GDK_Right: case GDK_KP_Right: case GDK_Pointer_Right: inv_right_released = TRUE; return TRUE; case GDK_space: case GDK_KP_Space: inv_fire_released = TRUE; return TRUE; case GDK_q: case GDK_Q: gtk_widget_destroy (widget); return TRUE; case GDK_p: case GDK_P: inv_paused = ! inv_paused; inv_show_status (); return TRUE; default: break; } return FALSE; } static gboolean ensure_creatures (void) { GdkPixbuf *pb, *pb1, *phsh1, *phsh2, *goat1, *goat2; char *phsh_file; char *goat_file; if (inv_goat1 != NULL) return TRUE; phsh_file = get_phsh_file (); if (phsh_file == NULL) return FALSE; pb = gdk_pixbuf_new_from_file (phsh_file, NULL); g_free (phsh_file); if (pb == NULL) return FALSE; pb1 = get_phsh_frame (pb, 1); phsh1 = pb_scale (pb1, inv_factor); g_object_unref (G_OBJECT (pb1)); phsh_unsea (phsh1); pb1 = get_phsh_frame (pb, 2); phsh2 = pb_scale (pb1, inv_factor); g_object_unref (G_OBJECT (pb1)); phsh_unsea (phsh2); g_object_unref (G_OBJECT (pb)); goat_file = g_strdup_printf ("%s/mate-gegl2.png", ICONDIR); if (goat_file == NULL) { g_object_unref (G_OBJECT (phsh1)); g_object_unref (G_OBJECT (phsh2)); return FALSE; } pb = gdk_pixbuf_new_from_file (goat_file, NULL); g_free (goat_file); if (pb == NULL) { g_object_unref (G_OBJECT (phsh1)); g_object_unref (G_OBJECT (phsh2)); return FALSE; } goat1 = pb_scale (pb, inv_factor * 0.66); g_object_unref (pb); goat_file = g_strdup_printf ("%s/mate-gegl2-2.png", ICONDIR); if (goat_file == NULL) { g_object_unref (G_OBJECT (goat1)); g_object_unref (G_OBJECT (phsh1)); g_object_unref (G_OBJECT (phsh2)); return FALSE; } pb = gdk_pixbuf_new_from_file (goat_file, NULL); g_free (goat_file); if (pb == NULL) { g_object_unref (G_OBJECT (goat1)); g_object_unref (G_OBJECT (phsh1)); g_object_unref (G_OBJECT (phsh2)); return FALSE; } goat2 = pb_scale (pb, inv_factor * 0.66); g_object_unref (pb); inv_goat_width = gdk_pixbuf_get_width (goat1); inv_goat_height = gdk_pixbuf_get_height (goat1); inv_phsh_width = gdk_pixbuf_get_width (phsh1); inv_phsh_height = gdk_pixbuf_get_height (phsh1); gdk_pixbuf_render_pixmap_and_mask (goat1, &inv_goat1, NULL, 127); g_object_unref (G_OBJECT (goat1)); gdk_pixbuf_render_pixmap_and_mask (goat2, &inv_goat2, NULL, 127); g_object_unref (G_OBJECT (goat2)); gdk_pixbuf_render_pixmap_and_mask (phsh1, &inv_phsh1, &inv_phsh1_mask, 127); g_object_unref (G_OBJECT (phsh1)); gdk_pixbuf_render_pixmap_and_mask (phsh2, &inv_phsh2, &inv_phsh2_mask, 127); g_object_unref (G_OBJECT (phsh2)); return TRUE; } static void geginv_destroyed (GtkWidget *w, gpointer data) { geginv = NULL; if (geginv_pixmap != NULL) g_object_unref (G_OBJECT (geginv_pixmap)); geginv_pixmap = NULL; } static void geginv_realized (GtkWidget *w, gpointer data) { if (geginv_pixmap == NULL) geginv_pixmap = gdk_pixmap_new (gtk_widget_get_window (w), inv_width, inv_height, gdk_visual_get_depth (gtk_widget_get_visual (w))); } static gboolean inv_expose (GtkWidget *widget, GdkEventExpose *event) { if ( ! gtk_widget_is_drawable (widget) || geginv_pixmap == NULL) return FALSE; inv_queue_draw (geginv); /* gdk_draw_drawable (geginv_canvas->window, geginv_canvas->style->white_gc, geginv_pixmap, event->area.x, event->area.x, event->area.x, event->area.x, event->area.width, event->area.height); */ return FALSE; } void start_geginv (void) { GtkWidget *vbox; int i, j; if (geginv != NULL) { gtk_window_present (GTK_WINDOW (geginv)); return; } inv_width = 800; inv_height = 600; if (inv_width > gdk_screen_width () * 0.9) { inv_width = gdk_screen_width () * 0.9; inv_height = inv_width * (600.0/800.0); } if (inv_height > gdk_screen_height () * 0.9) { inv_height = gdk_screen_height () * 0.9; inv_width = inv_height * (800.0/600.0); } inv_factor = (double)inv_width / 800.0; if ( ! ensure_creatures ()) return; geginv = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_set_title (GTK_WINDOW (geginv), _("Killer GEGLs from Outer Space")); g_object_set (G_OBJECT (geginv), "resizable", FALSE, NULL); g_signal_connect (G_OBJECT (geginv), "destroy", G_CALLBACK (geginv_destroyed), NULL); geginv_canvas = gtk_drawing_area_new (); gtk_widget_set_double_buffered (GTK_WIDGET (geginv_canvas), FALSE); gtk_widget_set_size_request (geginv_canvas, inv_width, inv_height); vbox = gtk_vbox_new (FALSE, 0); gtk_container_add (GTK_CONTAINER (geginv), vbox); gtk_box_pack_start (GTK_BOX (vbox), geginv_canvas, TRUE, TRUE, 0); geginv_label = gtk_label_new (""); gtk_box_pack_start (GTK_BOX (vbox), geginv_label, FALSE, FALSE, 0); inv_our_x = 400; inv_x = 70; inv_y = 70; inv_first_col = 0; inv_level = 0; inv_lives = 3; inv_last_col = INV_COLS-1; inv_reverse = FALSE; inv_game_over = FALSE; inv_left_pressed = FALSE; inv_right_pressed = FALSE; inv_fire_pressed = FALSE; inv_left_released = FALSE; inv_right_released = FALSE; inv_fire_released = FALSE; inv_paused = FALSE; gtk_widget_add_events (geginv, GDK_KEY_RELEASE_MASK); g_signal_connect (G_OBJECT (geginv), "key_press_event", G_CALLBACK (inv_key_press), NULL); g_signal_connect (G_OBJECT (geginv), "key_release_event", G_CALLBACK (inv_key_release), NULL); g_signal_connect (G_OBJECT (geginv), "realize", G_CALLBACK (geginv_realized), NULL); g_signal_connect (GTK_OBJECT (geginv_canvas), "expose_event", G_CALLBACK (inv_expose), NULL); g_slist_foreach (inv_shots, (GFunc)g_free, NULL); g_slist_free (inv_shots); inv_shots = NULL; for (i = 0; i < INV_COLS; i++) { for (j = 0; j < INV_ROWS; j++) { invs[i][j].live = TRUE; invs[i][j].x = 70 + i * 100; invs[i][j].y = 70 + j * 80; } } inv_num = INV_ROWS * INV_COLS; g_timeout_add (((inv_num/4)+1) * 100, geginv_timeout, geginv); g_timeout_add (90, geginv_move_timeout, geginv); inv_show_status (); gtk_widget_show_all (geginv); } static gboolean move_window_handler (gpointer data) { int x, y, sx, sy, wx, wy, foox, fooy; GtkWidget *win = data; GtkAllocation allocation; data = g_object_get_data (G_OBJECT (win), "move_speed_x"); sx = GPOINTER_TO_INT (data); data = g_object_get_data (G_OBJECT (win), "move_speed_y"); sy = GPOINTER_TO_INT (data); gtk_widget_get_allocation (win, &allocation); gdk_window_get_pointer (NULL, &x, &y, NULL); wx = allocation.x; wy = allocation.y; foox = wx + (allocation.width / 2); fooy = wy + (allocation.height / 2); if (sqrt ((foox - x)*(foox - x) + (fooy - y)*(fooy - y)) < MAX (allocation.width, allocation.height)) { if (foox < x) sx -= 5; else sx += 5; if (fooy < y) sy -= 5; else sy += 5; } else { sx /= 2; sy /= 2; } if (sx > 50) sx = 50; else if (sx < -50) sx = -50; if (sy > 50) sy = 50; else if (sy < -50) sy = -50; wx += sx; wy += sy; if (wx < 0) wx = 0; if (wy < 0) wy = 0; if (wx + allocation.width > gdk_screen_width ()) wx = gdk_screen_width () - allocation.width; if (wy + allocation.height > gdk_screen_height ()) wy = gdk_screen_height () - allocation.height; gtk_window_move (GTK_WINDOW (win), wx, wy); allocation.x = wx; allocation.y = wy; gtk_widget_set_allocation (win, &allocation); data = GINT_TO_POINTER (sx); g_object_set_data (G_OBJECT (win), "move_speed_x", data); data = GINT_TO_POINTER (sy); g_object_set_data (G_OBJECT (win), "move_speed_y", data); return TRUE; } static void move_window_destroyed (GtkWidget *win) { gpointer data = g_object_get_data (G_OBJECT (win), "move_window_handler"); int handler = GPOINTER_TO_INT (data); if (handler != 0) g_source_remove (handler); g_object_set_data (G_OBJECT (win), "move_window_handler", NULL); } static void doblah (GtkWidget *window) { gpointer data = g_object_get_data (G_OBJECT (window), "move_window_handler"); int handler = GPOINTER_TO_INT (data); if (handler == 0) { handler = g_timeout_add (30, move_window_handler, window); data = GINT_TO_POINTER (handler); g_object_set_data (G_OBJECT (window), "move_window_handler", data); g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (move_window_destroyed), NULL); } } gboolean panel_dialog_window_event (GtkWidget *window, GdkEvent *event) { switch (event->type) { static int foo = 0; case GDK_KEY_PRESS: if((event->key.state & GDK_CONTROL_MASK) && foo < 4) { switch (event->key.keyval) { case GDK_r: case GDK_R: if(foo == 3) { doblah (window); } foo = 0; break; case GDK_a: case GDK_A: if(foo == 2) { foo++; } else { foo = 0; } break; case GDK_e: case GDK_E: if(foo == 1) { foo++; } else { foo = 0; } break; case GDK_f: case GDK_F: if(foo == 0) { foo++; } else { foo = 0; } break; default: foo = 0; } } default: break; } return FALSE; } #endif