/* * window_gtk.c -- window handling, GTK */ #include "gui.h" signed int gui_window_origin_x, gui_window_origin_y; GtkWidget *gui_redraw_widget; gui_window_id menu_window_id; gboolean gui_window_press(GtkWidget *widget, GdkEventButton *event, gpointer data) { gui_window_id window_id; printf("gui_window_press: widget 0x%x, type %i, win 0x%x, %f %f, %i, data 0x%x\n", (unsigned int) widget, event->type, (unsigned int) event->window, event->x, event->y, event->button, (unsigned int) data); window_id = gui_handle_to_window_id(data); if (window_id != gui_WINDOW_UNKNOWN) { assert(window_id < gui_window_list_items && gui_window_list[window_id].used); if (gui_window_list[window_id].menu && event->button == 2) { gtk_menu_popup(gui_window_list[window_id].menu->menu, NULL, NULL, NULL, NULL, event->button, event->time); menu_window_id = window_id; } else if (gui_window_list[window_id].click_fn) { unsigned int z; z = (event->button == 1 ? gui_CLICK : (event->button == 3 ? gui_CLICK_RIGHT : 0)); gui_window_list[window_id].click_fn(window_id, event->x * 2, event->y * 2, z); } } } gboolean gui_expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer data) { gui_window_id window_id; signed int invalid[4]; window_id = gui_handle_to_window_id(data); gui_window_origin_x = 0; gui_window_origin_y = 0; gui_redraw_widget = widget; invalid[0] = event->area.x * 2; invalid[1] = event->area.y * 2; invalid[2] = (event->area.x + event->area.width) * 2; invalid[3] = (event->area.y + event->area.height) * 2; gdk_window_clear_area(widget->window, event->area.x, event->area.y, event->area.width, event->area.height); gdk_gc_set_clip_rectangle(widget->style->white_gc, &event->area); printf("gui_expose_event: id %i, rect %i %i %i %i\n", window_id, invalid[0], invalid[1], invalid[2], invalid[3]); gui_window_list[window_id].redraw_fn(window_id, invalid); gdk_gc_set_clip_rectangle(widget->style->white_gc, NULL); return TRUE; } void gui_size_allocate(GtkWidget *widget, GtkAllocation *allocation, gpointer data) { gui_window_id window_id; window_id = gui_handle_to_window_id(data); printf("gui_size_allocate: id %i, %i %i %u %u\n", window_id, allocation->x, allocation->y, allocation->width, allocation->height); gui_window_list[window_id].resize_fn(window_id, allocation->width * 2, allocation->height * 2); } /* * gui_create_window -- create and display a window * * => flags -- window details * title -- window title * width -- width of window * height -- height of window * close_fn -- function called when an attempt is made to close the window, * NULL for default of closing and destroying window * redraw_fn -- function called when the window needs redrawing * click_fn -- function called when the mouse is clicked in the window or equivalent, * NULL for default of no action * * <= window id */ gui_window_id gui_create_window(const unsigned int flags, char *title, const unsigned int width, const unsigned int height, void (*close_fn)(gui_window_id window_id), void (*redraw_fn)(gui_window_id window_id, unsigned int invalid[]), void (*click_fn)(gui_window_id window_id, unsigned int x, unsigned int y, unsigned int z), void (*resize_fn)(gui_window_id window_id, unsigned int width, unsigned int height), bool (*key_fn)(gui_window_id window_id, unsigned int key), void (*input_fn)(gui_window_id window_id, wchar_t key), void (*menu_fn)(gui_window_id window_id, unsigned int items[]), struct gui_menu_data *menu, const char *bbar, const char *help) { GtkWidget *window; GtkWidget *scrolled_window; GtkWidget *event_box; GtkWidget *drawing_area; gui_window_id id; #ifdef DEBUG printf("gui_create_window: title = '%s'\n", title); fflush(stdout); #endif assert(redraw_fn != NULL); id = gui_get_free_window_id(); drawing_area = gtk_drawing_area_new(); event_box = gtk_event_box_new(); scrolled_window = gtk_scrolled_window_new(NULL, NULL); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_drawing_area_size(drawing_area, flags & gui_H_SCROLL_BAR ? width / 2 : 0, flags & gui_V_SCROLL_BAR ? height / 2 : 0); gtk_container_set_border_width(GTK_CONTAINER (scrolled_window), 0); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW (scrolled_window), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_window_set_title(GTK_WINDOW (window), title); gtk_container_set_border_width(GTK_CONTAINER (window), 0); gtk_container_add(GTK_CONTAINER (event_box), drawing_area); gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW (scrolled_window), event_box); gtk_container_add(GTK_CONTAINER (window), scrolled_window); gtk_widget_show(drawing_area); gtk_widget_show(event_box); gtk_widget_show(scrolled_window); gtk_widget_show(window); gui_window_list[id].used = 1; gui_window_list[id].handle = window; gui_window_list[id].close_fn = (close_fn == NULL ? gui_remove_window : close_fn); gui_window_list[id].redraw_fn = redraw_fn; gui_window_list[id].click_fn = click_fn; gui_window_list[id].resize_fn = resize_fn; gui_window_list[id].key_fn = key_fn; gui_window_list[id].input_fn = input_fn; gui_window_list[id].menu_fn = menu_fn; gui_window_list[id].width = width; gui_window_list[id].height = height; gui_window_list[id].menu = menu; gui_window_list[id].help = help; gui_window_list[id].drawing_area = drawing_area; gtk_signal_connect(event_box, "button-press-event", gui_window_press, window); gtk_signal_connect(drawing_area, "expose-event", gui_expose_event, window); gtk_signal_connect(drawing_area, "size-allocate", gui_size_allocate, window); #ifdef DEBUG printf("gui_create_window: id = 0x%x, handle = 0x%x\n", id, (unsigned int) window); fflush(stdout); #endif return id; } /* * gui_get_free_window_id -- allocate space and return a window id * * => nothing * * <= window id (gui_window_list index) */ gui_window_id gui_get_free_window_id() { static struct gui_window_data *new_gui_window_list; int i; #ifdef DEBUG printf("gui_get_free_window_id: gui_window_list_items = %i\n", gui_window_list_items); fflush(stdout); #endif for (i = 0; i < gui_window_list_items; i++) { if (!gui_window_list[i].used) { assert(i >= 0 && i < gui_window_list_items); return i; } } new_gui_window_list = realloc(gui_window_list, sizeof(struct gui_window_data) * (gui_window_list_items + WINDOW_LIST_CHUNK)); if (!new_gui_window_list) gui_raise_error("memory"); gui_window_list = new_gui_window_list; for (i = gui_window_list_items; i < gui_window_list_items + WINDOW_LIST_CHUNK; i++) gui_window_list[i].used = 0; i = gui_window_list_items; gui_window_list_items += WINDOW_LIST_CHUNK; #ifdef DEBUG printf("gui_get_free_window_id: increased gui_window_list_items = %i\n", gui_window_list_items); fflush(stdout); #endif assert(i >= 0 && i < gui_window_list_items); return i; } /* * gui_handle_to_window_id -- convert a window handle to a window id * * => handle -- wimp window handle * * <= window id */ gui_window_id gui_handle_to_window_id(GtkWidget *handle) { int i; for (i = 0; i < gui_window_list_items; i++) { if ((gui_window_list[i].used) && (gui_window_list[i].handle == handle)) { #ifdef DEBUG printf("gui_handle_to_window_id: handle = 0x%x, id = 0x%x\n", (unsigned int) handle, i); fflush(stdout); #endif return i; } } return gui_WINDOW_UNKNOWN; } /* * gui_remove_window -- close and destroy a window * * => window_id -- window id from gui_create_window * * <= nothing */ void gui_remove_window(const gui_window_id window_id) { assert(window_id >= 0 && window_id < gui_window_list_items && gui_window_list[window_id].used); #ifdef DEBUG printf("gui_remove_window: window_id = 0x%x\n", window_id); fflush(stdout); #endif /* gui_error = xwimp_delete_window(gui_window_list[window_id].handle); * gui_check_error(); * gui_window_list[window_id].used = 0; */ } /* * gui_refresh_window -- update a window's contents * * => window_id -- window id from gui_create_window * * <= nothing */ void gui_refresh_window(const gui_window_id window_id) { assert(window_id >= 0 && window_id < gui_window_list_items && gui_window_list[window_id].used); #ifdef DEBUG printf("gui_refresh_window: window_id = 0x%x\n", window_id); fflush(stdout); #endif /* gui_refresh_box(window_id, 0, 0, gui_window_list[window_id].width, gui_window_list[window_id].height); */ } /* * gui_refresh_box -- update part of a window's contents * * => window_id -- window id from gui_create_window * x0, y0, x1, y1 -- area to update * * <= nothing */ void gui_refresh_box(const gui_window_id window_id, unsigned int x0, unsigned int y0, unsigned int x1, unsigned int y1) { signed int invalid[4]; bool more; /* wimp_window_state state; * wimp_draw update; */ assert(window_id >= 0 && window_id < gui_window_list_items && gui_window_list[window_id].used); #ifdef DEBUG printf("gui_refresh_box: window_id = 0x%x, box %i %i %i %i\n", window_id, x0, y0, x1, y1); fflush(stdout); #endif /* state.w = gui_window_list[window_id].handle; * * gui_error = xwimp_get_window_state(&state); * gui_check_error(); * * gui_window_origin_x = state.visible.x0 - state.xscroll; * gui_window_origin_y = state.visible.y1 - state.yscroll; * * #ifdef DEBUG * printf("gui_refresh_box: redraw origin %i %i\n", gui_window_origin_x, gui_window_origin_y); * fflush(stdout); * #endif * * update.w = state.w; * update.box.x0 = x0; * update.box.y0 = -y1; * update.box.x1 = x1; * update.box.y1 = -y0; * gui_error = xwimp_update_window(&update, &more); * gui_check_error(); * * while (more) * { * invalid[0] = update.clip.x0 - gui_window_origin_x; * invalid[1] = gui_window_origin_y - update.clip.y1; * invalid[2] = update.clip.x1 - gui_window_origin_x; * invalid[3] = gui_window_origin_y - update.clip.y0; * * #ifdef DEBUG * printf("gui_refresh_box: redraw invalid %i %i %i %i\n", * invalid[0], invalid[1], invalid[2], invalid[3]); * fflush(stdout); * #endif * * gui_window_list[window_id].redraw_fn(window_id, invalid); * * gui_error = xwimp_get_rectangle(&update, &more); * gui_check_error(); * } */ } /* * gui_window_extent -- set window size * * => window_id -- window id from gui_create_window * width, height -- new dimensions of window * * <= nothing */ void gui_window_extent(const gui_window_id window_id, unsigned int width, unsigned int height) { assert(window_id >= 0 && window_id < gui_window_list_items && gui_window_list[window_id].used); #ifdef DEBUG printf("gui_window_extent: window_id = 0x%x, extent = %i x %i\n", window_id, width, height); fflush(stdout); #endif gtk_drawing_area_size(gui_window_list[window_id].drawing_area, width / 2, height / 2); gui_window_list[window_id].width = width; gui_window_list[window_id].height = height; } /* * gui_fill -- fill a rectangular area during window redraw * * => colour -- 0xbbggrr format colour * x0, y0, x1, y1 -- coordinates of rectangle */ void gui_fill(unsigned int colour, unsigned int x0, unsigned int y0, unsigned int x1, unsigned int y1) { GdkColor gdk_colour; printf("gui_fill: box %i %i %i %i\n", x0, y0, x1, y1); BGR_TO_GDK(colour, gdk_colour); gdk_colormap_alloc_color(gdk_window_get_colormap(gui_redraw_widget->window), &gdk_colour, FALSE, TRUE); gdk_gc_set_foreground(gui_redraw_widget->style->fg_gc[gui_redraw_widget->state], &gdk_colour); gdk_draw_rectangle(gui_redraw_widget->window, gui_redraw_widget->style->fg_gc[gui_redraw_widget->state], TRUE, x0 / 2, y0 / 2, (x1-x0) / 2, (y1-y0) / 2); } /* * gui_move_box -- copy a rectangular area within a window * * => window_id -- window id from gui_create_window * x0, y0, x1, y1 -- source area * x2, y2 -- destination */ void gui_move_box(const gui_window_id window_id, unsigned int x0, unsigned int y0, unsigned int x1, unsigned int y1, unsigned int x2, unsigned int y2) { assert(window_id >= 0 && window_id < gui_window_list_items && gui_window_list[window_id].used); #ifdef DEBUG printf("gui_move_box: window_id = 0x%x, box = %i %i %i %i, dest = %i %i\n", window_id, x0, y0, x1, y1, x2, y2); fflush(stdout); #endif /* gui_error = xwimp_block_copy(gui_window_list[window_id].handle, x0, -y1, x1, -y0, x2, -(y1 + (y2 - y0))); * gui_check_error(); */ }