Logo Search packages:      
Sourcecode: xbill version File versions  Download package

gtk.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>

#include <gtk/gtk.h>

#include "util.h"

#include "gtk.h"

#include "Game.h"
#include "UI.h"

00016 struct MCursor {
      GdkCursor *cursor;
};

00020 struct Picture {
      gint width, height;
      GdkPixmap *pix;
      GdkBitmap *mask;
      GdkGC *gc;
};

static const char *pictdir;

static GtkWidget *toplevel, *base, *menubar, *field;
static GtkWidget *dialogs[DIALOG_MAX + 1];
static GtkWidget *pausebutton;
static guint timer;
static GdkGC *stdgc;
static GdkPixmap *offscreen;
static GdkFont *font;
static GdkColor white, black;
static int screensize;

/*
 * Callback functions
 */

static void
gtk_ui_popup_dialog(int index) {
      GtkWidget *popup;
      int tx, ty, tw, th;
      int px, py, pw, ph;

      popup = dialogs[index];

      gdk_window_get_origin(toplevel->window, &tx, &ty);
      gdk_window_get_size(toplevel->window, &tw, &th);
      gdk_window_get_size(popup->window, &pw, &ph);
      px = tx + (tw - pw) / 2;
      py = ty + (th - ph) / 2;
      gtk_window_set_position(GTK_WINDOW(popup), GTK_WIN_POS_NONE);
      gtk_widget_set_uposition(popup, px, py);
      gtk_widget_show_all(popup);
      gtk_main();
}

static void
popdown(void) {
      gtk_main_quit();
}

static void
new_game(void) {
      Game_start(1);
}

static void
quit_game(void) {
      Game_quit();
}

static void
warp_apply(GtkWidget *text) {
      char *str;
      char *endp;
      int newlevel;

      str = gtk_entry_get_text(GTK_ENTRY(text));
      newlevel = strtol(str, &endp, 10);
      if (*endp != '\0')
            return;
      Game_warp_to_level(newlevel);
}

static void
enter_name(GtkWidget *text) {
      char *str;

      str = gtk_entry_get_text(GTK_ENTRY(text));
      Game_add_high_score(str);
}

/*
 * Event handlers
 */

static gboolean
leave_window(GtkWidget *widget, GdkEvent *event, gpointer user_data) {
      UNUSED(widget);
      UNUSED(event);
      UNUSED(user_data);

      UI_pause_game();
      return FALSE;
}

static gboolean
enter_window(GtkWidget *widget, GdkEvent *event, gpointer user_data) {
      UNUSED(widget);
      UNUSED(event);
      UNUSED(user_data);

      UI_resume_game();
      return FALSE;
}

static gboolean
redraw_window(GtkWidget *widget, GdkEvent *event, gpointer user_data) {
      UNUSED(widget);
      UNUSED(event);
      UNUSED(user_data);

      UI_refresh();
      return FALSE;
}

static gboolean
button_press(GtkWidget *widget, GdkEvent *event, gpointer user_data) {
      GdkEventButton *buttonevent = (GdkEventButton *) event;

      UNUSED(widget);
      UNUSED(user_data);

      Game_button_press((int)buttonevent->x, (int)buttonevent->y);
      return FALSE;
}

static gboolean
button_release(GtkWidget *widget, GdkEvent *event, gpointer user_data) {
      GdkEventButton *buttonevent = (GdkEventButton *) event;

      UNUSED(widget);
      UNUSED(user_data);

      Game_button_release((int)buttonevent->x, (int)buttonevent->y);
      return FALSE;
}

static int
timer_tick(gpointer arg) {
      UNUSED(arg);

      UI_restart_timer();
      Game_update();
      return TRUE;
}

/*
 * Cursor handling
 */

#include "bitmaps/apple.xbm"
#include "bitmaps/bsd.xbm"
#include "bitmaps/hurd.xbm"
#include "bitmaps/linux.xbm"
#include "bitmaps/next.xbm"
#include "bitmaps/os2.xbm"
#include "bitmaps/palm.xbm"
#include "bitmaps/redhat.xbm"
#include "bitmaps/sgi.xbm"
#include "bitmaps/sun.xbm"
#include "bitmaps/bucket.xbm"
#include "bitmaps/hand_down.xbm"
#include "bitmaps/hand_down_mask.xbm"
#include "bitmaps/hand_up.xbm"
#include "bitmaps/hand_up_mask.xbm"

00183 typedef struct cursormap {
      const char *name;
      int width, height;
      const char *data, *maskdata;
} cursormap;

#define CURSOR_ADD(x) \
      {#x, x ## _width, x ## _height, x ## _bits, NULL}

#define CURSOR_ADD_MASKED(x) \
      {#x, x ## _width, x ## _height, x ## _bits, x ## _mask_bits}

static cursormap cursors[] = {
      CURSOR_ADD(apple), CURSOR_ADD(bsd), CURSOR_ADD(hurd),
      CURSOR_ADD(linux), CURSOR_ADD(next), CURSOR_ADD(os2), CURSOR_ADD(palm),
      CURSOR_ADD(redhat), CURSOR_ADD(sgi), CURSOR_ADD(sun),
      CURSOR_ADD(bucket),
      CURSOR_ADD_MASKED(hand_up), CURSOR_ADD_MASKED(hand_down),
      {NULL, 0, 0, NULL, NULL},
};

static void
gtk_ui_set_cursor(MCursor *cursor) {
      gdk_window_set_cursor(field->window, cursor->cursor);
}

static void
gtk_ui_load_cursor(const char *name, int masked, MCursor **cursorp) {
      MCursor *cursor;
      GdkBitmap *bitmap, *mask;
      cursormap *c;

      cursor = xalloc(sizeof *cursor);

      for (c = cursors; c->name != NULL; c++)
            if (strcmp(name, c->name) == 0)
                  break;
      if (c->name == NULL)
            fatal("couldn't load cursor: %s", name);
      bitmap = gdk_bitmap_create_from_data(field->window, c->data,
                                   c->width, c->height);

      if (masked == CURSOR_SEP_MASK)
            mask = gdk_bitmap_create_from_data(field->window, c->maskdata,
                                       c->width, c->height);
      else
            mask = bitmap;
      cursor->cursor = gdk_cursor_new_from_pixmap(bitmap, mask, 
                                        &black, &white,
                                        c->width/2, c->height/2);
      *cursorp = cursor;
}

/*
 * Pixmap handling
 */

static void
gtk_ui_load_picture(const char *name, int trans, Picture **pictp) {
      Picture *pict;
      char file[255];
      GdkBitmap *mask;

      UNUSED(trans);

      pict = xalloc(sizeof *pict);

      sprintf(file, "%s/pixmaps/%s.xpm", pictdir, name);
      pict->pix = gdk_pixmap_create_from_xpm(toplevel->window, &mask,
                                     NULL, file);
      if (pict->pix == NULL)
            fatal("error reading %s", file);
      pict->mask = mask;
      pict->gc = gdk_gc_new(toplevel->window);
      gdk_gc_set_exposures(pict->gc, FALSE);
      gdk_gc_set_clip_mask(pict->gc, mask);
      gdk_window_get_size(pict->pix, &pict->width, &pict->height);

      *pictp = pict;
}

static void
gtk_ui_set_icon(Picture *icon) {
      gdk_window_set_icon(toplevel->window, NULL, icon->pix, icon->mask);
}

static int
gtk_ui_picture_width(Picture *pict) {
      return (pict->width);
}

static int
gtk_ui_picture_height(Picture *pict) {
      return (pict->height);
}

/*
 * Graphics operations
 */

static void
gtk_ui_clear_window(void) {
      gdk_draw_rectangle(offscreen, field->style->white_gc, TRUE, 0, 0,
                     screensize, screensize);
}

static void
gtk_ui_refresh_window(void) {
      gdk_draw_pixmap(field->window, stdgc, offscreen, 0, 0, 0, 0,
                  screensize, screensize);
}

static void
gtk_ui_draw_image(Picture *pict, int x, int y) {
      gdk_gc_set_clip_origin(pict->gc, x, y);
      gdk_draw_pixmap(offscreen, pict->gc, pict->pix, 0, 0, x, y,
                  pict->width, pict->height);
}

static void
gtk_ui_draw_line(int x1, int y1, int x2, int y2) {
      gdk_draw_line(offscreen, stdgc, x1, y1, x2, y2);
}

static void
gtk_ui_draw_string(const char *str, int x, int y) {
      gdk_draw_string(offscreen, font, stdgc, x, y, str);
}

/*
 * Timer operations
 */

static void
gtk_ui_start_timer(int ms) {
      if (timer == 0)
            timer = gtk_timeout_add(ms, timer_tick, NULL);
}

static void
gtk_ui_stop_timer(void) {
      if (timer != 0)
            gtk_timeout_remove(timer);
      timer = 0;
}

static int
gtk_ui_timer_active(void) {
      return (!!timer);
}

/*
 * Main Loop 
 */
static void
gtk_ui_main_loop(void) {
      gtk_main();
}

/*
 * Initialization
 */
static void
gtk_ui_initialize(int *argc, char **argv) {
      struct stat stats;

      gtk_init(argc, &argv);
      toplevel = gtk_window_new(GTK_WINDOW_TOPLEVEL);

      timer = 0;
      gtk_window_set_title(GTK_WINDOW(toplevel), "XBill");

      gtk_signal_connect(GTK_OBJECT(toplevel), "delete_event",
                     GTK_SIGNAL_FUNC(quit_game), NULL);

      if (stat(IMAGES, &stats) == 0)
            pictdir = IMAGES;
      else
            pictdir = ".";
}

static GtkWidget *
new_menu_item(GtkWidget *menu, int dialog) {
      GtkWidget *menu_item;

      menu_item = gtk_menu_item_new_with_label(UI_menu_string(dialog));
      gtk_menu_append(GTK_MENU(menu), menu_item);
      gtk_signal_connect_object(GTK_OBJECT(menu_item), "activate",
                          gtk_ui_popup_dialog, (gpointer) dialog);
      return (menu_item);
}

static GtkWidget *
CreateMenuBar(void) {
      GtkWidget *menubar;
      GtkWidget *game_item, *game_menu;
      GtkWidget *info_item, *info_menu;
      GtkWidget *tearoff;

      menubar = gtk_menu_bar_new();

      game_item = gtk_menu_item_new_with_label("Game");
      game_menu = gtk_menu_new();

      tearoff = gtk_tearoff_menu_item_new();
      gtk_menu_append(GTK_MENU(game_menu), tearoff);

      new_menu_item(game_menu, DIALOG_NEWGAME);
      pausebutton = new_menu_item(game_menu, DIALOG_PAUSEGAME);
      new_menu_item(game_menu, DIALOG_WARPLEVEL);
      new_menu_item(game_menu, DIALOG_HIGHSCORE);
      new_menu_item(game_menu, DIALOG_QUITGAME);

      gtk_menu_bar_append(GTK_MENU_BAR(menubar), game_item);
      gtk_menu_item_set_submenu(GTK_MENU_ITEM(game_item), game_menu);

      info_item = gtk_menu_item_new_with_label("Info");
      info_menu = gtk_menu_new();

      tearoff = gtk_tearoff_menu_item_new();
      gtk_menu_append(GTK_MENU(info_menu), tearoff);

      new_menu_item(info_menu, DIALOG_STORY);
      new_menu_item(info_menu, DIALOG_RULES);
      new_menu_item(info_menu, DIALOG_ABOUT);

      gtk_menu_bar_append(GTK_MENU_BAR(menubar), info_item);
      gtk_menu_item_set_submenu(GTK_MENU_ITEM(info_item), info_menu);

      return menubar;
}

static GtkWidget *
CreateDrawingArea(int width, int height) {
      GtkWidget *w = gtk_drawing_area_new();
      gtk_drawing_area_size(GTK_DRAWING_AREA(w), width, height);
      return w;
}

static void
gtk_ui_make_main_window(int size) {
      GdkWindowHints flags;
      GdkGeometry geom;
      gint winwidth, winheight;

      screensize = size;

      base = gtk_vbox_new(FALSE, 0);
      gtk_container_add(GTK_CONTAINER(toplevel), base);

      menubar = CreateMenuBar();
      gtk_box_pack_start(GTK_BOX(base), menubar, FALSE, FALSE, 0);

      field = CreateDrawingArea(size, size);
      gtk_box_pack_start(GTK_BOX(base), field, FALSE, FALSE, 0);

      gtk_signal_connect(GTK_OBJECT(field), "button-press-event",
                     GTK_SIGNAL_FUNC(button_press), NULL);
      gtk_signal_connect(GTK_OBJECT(field), "button-release-event",
                     GTK_SIGNAL_FUNC(button_release), NULL);
      gtk_signal_connect(GTK_OBJECT(field), "enter-notify-event",
                     GTK_SIGNAL_FUNC(enter_window), NULL);
      gtk_signal_connect(GTK_OBJECT(field), "leave-notify-event",
                     GTK_SIGNAL_FUNC(leave_window), NULL);
      gtk_signal_connect(GTK_OBJECT(field), "expose-event",
                     GTK_SIGNAL_FUNC(redraw_window), NULL);
      gtk_widget_set_events(field, GDK_BUTTON_PRESS_MASK |
                        GDK_BUTTON_RELEASE_MASK |
                        GDK_ENTER_NOTIFY_MASK |
                        GDK_LEAVE_NOTIFY_MASK |
                        GDK_EXPOSURE_MASK);

      gtk_widget_show_all(toplevel);

      gdk_window_get_size(toplevel->window, &winwidth, &winheight);
      geom.min_width = geom.max_width = geom.base_width = winwidth;
      geom.min_height = geom.max_height = geom.base_height = winheight;
      geom.width_inc = geom.height_inc = 0;
      flags = GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE | GDK_HINT_BASE_SIZE |
            GDK_HINT_RESIZE_INC;
      gdk_window_set_geometry_hints(toplevel->window, &geom, flags);

      gdk_color_parse("white", &white);
      gdk_color_parse("black", &black);
}

static void
gtk_ui_graphics_init(void) {
      offscreen = gdk_pixmap_new(field->window, screensize, screensize, -1);
      stdgc = gdk_gc_new(offscreen);
      gdk_gc_set_exposures(stdgc, FALSE);
      gdk_gc_set_line_attributes(stdgc, 2, GDK_LINE_SOLID, GDK_CAP_ROUND,
                           GDK_JOIN_MITER);
      font = gdk_font_load("fixed");
}

static GtkWidget *
new_button(GtkWidget *dialog, const char *text, GtkSignalFunc func,
         GtkObject *obj)
{
      GtkWidget *button = gtk_button_new_with_label(text);
      if (func != NULL)
            gtk_signal_connect_object(GTK_OBJECT(button), "clicked",
                                func, obj);
      gtk_signal_connect_object(GTK_OBJECT(button), "clicked",
                          GTK_SIGNAL_FUNC(gtk_widget_hide),
                          GTK_OBJECT(dialog));
      gtk_signal_connect_object(GTK_OBJECT(button), "clicked",
                          GTK_SIGNAL_FUNC(popdown), NULL);
      gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area),
                    button);
      gtk_widget_show(button);
      return button;
}

static void
CreateDialog(int index, int hascancel, Picture *icon,
           const char *buttonlabel, GtkSignalFunc func)
{
      GtkWidget *dialog, *pixmap, *label, *hbox;

      dialog = gtk_dialog_new();
      gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);

      hbox = gtk_hbox_new(FALSE, 0);

      if (icon != NULL) {
            pixmap = gtk_pixmap_new(icon->pix, icon->mask);
            gtk_container_add(GTK_CONTAINER(hbox), pixmap);
      }

      label = gtk_label_new(UI_dialog_string(index));
      gtk_container_add(GTK_CONTAINER(hbox), label);

      gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), hbox);
      gtk_widget_show_all(hbox);

      if (buttonlabel == NULL)
            buttonlabel = "OK";
      new_button(dialog, buttonlabel, func, NULL);

      if (hascancel)
            new_button(dialog, "Cancel", NULL, NULL);

      gtk_widget_realize(dialog); 
      dialogs[index] = dialog;
}

static void
CreateEnterText(int index, GtkSignalFunc func) {
      GtkWidget *dialog, *label, *entry;

      dialog = gtk_dialog_new();
      gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);

      label = gtk_label_new(UI_dialog_string(index));
      gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), label);
      gtk_widget_show(label);

      entry = gtk_entry_new_with_max_length(20);
      gtk_signal_connect_object(GTK_OBJECT(entry), "activate",
                          func, GTK_OBJECT(entry));
      gtk_signal_connect_object(GTK_OBJECT(entry), "activate",
                          GTK_SIGNAL_FUNC(gtk_widget_hide),
                          GTK_OBJECT(dialog));
      gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), entry);
      gtk_widget_show(entry);

      new_button(dialog, "OK", func, GTK_OBJECT(entry));

      gtk_widget_realize(dialog); 
      dialogs[index] = dialog;
}

static void
CreatePixmapBox(int index, Picture *logo, Picture *pix) {
      GtkWidget *dialog, *pixmap, *label;
      const char *text = UI_dialog_string(index);

      dialog = gtk_dialog_new();
      gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);

      pixmap = gtk_pixmap_new(logo->pix, logo->mask);
      gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), pixmap);
      gtk_widget_show(pixmap);

      if (pix != NULL) {
            pixmap = gtk_pixmap_new(pix->pix, pix->mask);
            gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox),
                          pixmap);
            gtk_widget_show(pixmap);
      }

      if (text != NULL) {
            label = gtk_label_new(text);
            gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox),
                          label);
            gtk_widget_show(label);
      }

      new_button(dialog, "OK", NULL, NULL);

      gtk_widget_realize(dialog); 
      dialogs[index] = dialog;
}

static void
gtk_ui_create_dialogs(Picture *logo, Picture *icon, Picture *about) {
      CreateDialog(DIALOG_NEWGAME, 1, NULL, NULL, new_game);
      CreateDialog(DIALOG_PAUSEGAME, 0, icon, "Continue", NULL);
      CreateEnterText(DIALOG_WARPLEVEL, warp_apply);
      CreateDialog(DIALOG_HIGHSCORE, 0, NULL, NULL, NULL);
      CreateDialog(DIALOG_QUITGAME, 1, NULL, NULL, quit_game);

      CreatePixmapBox(DIALOG_STORY, logo, NULL);
      CreatePixmapBox(DIALOG_RULES, logo, NULL);
      CreatePixmapBox(DIALOG_ABOUT, logo, about);

      CreateDialog(DIALOG_SCORE, 0, NULL, NULL, NULL);
      CreateDialog(DIALOG_ENDGAME, 0, NULL, "Nuts!", NULL);
      CreateEnterText(DIALOG_ENTERNAME, enter_name);
}

static void
set_label(GtkWidget *dialog, const char *str) {
      GList *list;
      GtkWidget *hbox = NULL;

      list = gtk_container_children(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox));
      while (list != NULL) {
            GtkWidget *w = (GtkWidget *) list->data;
            list = g_list_next(list);
            if (GTK_IS_HBOX(w)) {
                  hbox = w;
                  break;
            }
      }
      if (hbox == NULL)
            return;
      list = gtk_container_children(GTK_CONTAINER(hbox));
      while (list != NULL) {
            GtkWidget *w = (GtkWidget *) list->data;
            list = g_list_next(list);
            if (GTK_IS_LABEL(w)) {
                  gtk_label_set_text(GTK_LABEL(w), str);
                  return;
            }
      }
}

static void
gtk_ui_update_dialog(int index, const char *str) {
      set_label(dialogs[index], str);
}

static void
gtk_ui_set_pausebutton(int active) {
      if (pausebutton != NULL)
            gtk_widget_set_sensitive(pausebutton, active);
}

static struct UI_methods gtk_methods = {
      gtk_ui_set_cursor,
      gtk_ui_load_cursor,
      gtk_ui_load_picture,
      gtk_ui_set_icon,
      gtk_ui_picture_width,
      gtk_ui_picture_height,
      gtk_ui_graphics_init,
      gtk_ui_clear_window,
      gtk_ui_refresh_window,
      gtk_ui_draw_image,
      gtk_ui_draw_line,
      gtk_ui_draw_string,
      gtk_ui_start_timer,
      gtk_ui_stop_timer,
      gtk_ui_timer_active,
      gtk_ui_popup_dialog,
      gtk_ui_main_loop,
      gtk_ui_initialize,
      gtk_ui_make_main_window,
      gtk_ui_create_dialogs,
      gtk_ui_set_pausebutton,
      gtk_ui_update_dialog,
};

void
gtk_ui_setmethods(UI_methods **methodsp) {
      *methodsp = &gtk_methods;
}

Generated by  Doxygen 1.6.0   Back to index