aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas White <taw@physics.org>2020-02-14 17:03:29 +0100
committerThomas White <taw@physics.org>2020-07-29 18:39:50 +0200
commit63eadd0582724e2626dddf0729ec991c1979b8cc (patch)
treed3623ff93591b9b0f066a79846820a5b697a7c6e
parentfc2d7dbbd535c2e2b2cb4b58b70f98ba5aa69a1e (diff)
Skeleton GUI and CrystFELImageView
-rw-r--r--CMakeLists.txt15
-rw-r--r--src/crystfel_gui.c280
-rw-r--r--src/crystfelimageview.c298
-rw-r--r--src/crystfelimageview.h84
4 files changed, 677 insertions, 0 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 985b3596..d8e9dd06 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -367,6 +367,21 @@ target_link_libraries(cell_tool ${COMMON_LIBRARIES})
list(APPEND CRYSTFEL_EXECUTABLES cell_tool)
# ----------------------------------------------------------------------
+# crystfel (main graphical user interface)
+
+if (GTK_FOUND)
+
+ set(CRYSTFEL_GUI_SOURCES src/crystfel_gui.c src/crystfelimageview.c)
+
+ add_executable(crystfel ${CRYSTFEL_GUI_SOURCES})
+ target_include_directories(crystfel PRIVATE ${COMMON_INCLUDES} ${GTK_INCLUDE_DIRS})
+ target_link_libraries(crystfel ${COMMON_LIBRARIES} ${GTK_LIBRARIES})
+
+ list(APPEND CRYSTFEL_EXECUTABLES crystfel)
+
+endif (GTK_FOUND)
+
+# ----------------------------------------------------------------------
# Install targets
set_target_properties(${CRYSTFEL_EXECUTABLES}
diff --git a/src/crystfel_gui.c b/src/crystfel_gui.c
new file mode 100644
index 00000000..fbb8d0e2
--- /dev/null
+++ b/src/crystfel_gui.c
@@ -0,0 +1,280 @@
+/*
+ * crystfel_gui.c
+ *
+ * CrystFEL's main graphical user interface
+ *
+ * Copyright © 2020 Deutsches Elektronen-Synchrotron DESY,
+ * a research centre of the Helmholtz Association.
+ *
+ * Authors:
+ * 2020 Thomas White <taw@physics.org>
+ *
+ * This file is part of CrystFEL.
+ *
+ * CrystFEL is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * CrystFEL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with CrystFEL. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <getopt.h>
+#include <string.h>
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms-compat.h>
+#include <assert.h>
+
+#include "crystfelimageview.h"
+
+
+static void show_help(const char *s)
+{
+ printf("Syntax: %s\n\n", s);
+ printf(
+"CrystFEL graphical user interface.\n"
+"\n"
+" -h, --help Display this help message.\n"
+" --version Print CrystFEL version number and exit.\n"
+
+);
+}
+
+
+struct crystfelproject {
+
+ GtkWidget *window;
+ GtkUIManager *ui;
+ GtkActionGroup *action_group;
+
+ GtkWidget *imageview;
+ GtkWidget *icons; /* Drawing area for task icons */
+ GtkWidget *report; /* Text view at the bottom for messages */
+
+};
+
+
+static void error_box(struct crystfelproject *proj, const char *message)
+{
+ GtkWidget *window;
+
+ window = gtk_message_dialog_new(GTK_WINDOW(proj->window),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_WARNING,
+ GTK_BUTTONS_CLOSE, "%s", message);
+ gtk_window_set_title(GTK_WINDOW(window), "Error");
+
+ g_signal_connect_swapped(window, "response",
+ G_CALLBACK(gtk_widget_destroy), window);
+ gtk_widget_show(window);
+}
+
+
+static gboolean destroy_sig(GtkWidget *da, struct crystfelproject *proj)
+{
+ gtk_main_quit();
+ return FALSE;
+}
+
+
+static void add_ui_sig(GtkUIManager *ui, GtkWidget *widget,
+ GtkContainer *container)
+{
+ gtk_box_pack_start(GTK_BOX(container), widget, FALSE, FALSE, 0);
+ if ( GTK_IS_TOOLBAR(widget) ) {
+ gtk_toolbar_set_show_arrow(GTK_TOOLBAR(widget), TRUE);
+ }
+}
+
+
+static gint quit_sig(GtkWidget *widget, struct crystfelproject *proj)
+{
+ gtk_main_quit();
+ return FALSE;
+}
+
+
+static gint about_sig(GtkWidget *widget, struct crystfelproject *proj)
+{
+ GtkWidget *window;
+
+ const gchar *authors[] = {
+ "Thomas White <taw@physics.org>",
+ NULL
+ };
+
+ window = gtk_about_dialog_new();
+ gtk_window_set_transient_for(GTK_WINDOW(window), GTK_WINDOW(proj->window));
+
+ gtk_about_dialog_set_program_name(GTK_ABOUT_DIALOG(window),
+ "CrystFEL graphical user interface");
+ gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(window), CRYSTFEL_VERSIONSTRING);
+ gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(window),
+ "© 2020 Deutsches Elektronen-Synchrotron DESY, "
+ "a research centre of the Helmholtz Association.");
+ gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(window),
+ "https://www.desy.de/~twhite/crystfel");
+ gtk_about_dialog_set_authors(GTK_ABOUT_DIALOG(window), authors);
+
+ g_signal_connect(window, "response", G_CALLBACK(gtk_widget_destroy),
+ NULL);
+
+ gtk_widget_show_all(window);
+
+ return 0;
+}
+
+
+static void add_menu_bar(struct crystfelproject *proj, GtkWidget *vbox)
+{
+ GError *error = NULL;
+
+ const char *ui = "<ui> <menubar name=\"cellwindow\">"
+ "<menu name=\"file\" action=\"FileAction\">"
+ " <menuitem name=\"quit\" action=\"QuitAction\" />"
+ "</menu>"
+ "<menu name=\"tools\" action=\"ToolsAction\" >"
+ "</menu>"
+ "<menu name=\"help\" action=\"HelpAction\">"
+ " <menuitem name=\"about\" action=\"AboutAction\" />"
+ "</menu>"
+ "</menubar></ui>";
+
+ GtkActionEntry entries[] = {
+
+ { "FileAction", NULL, "_File", NULL, NULL, NULL },
+ { "QuitAction", GTK_STOCK_QUIT, "_Quit", NULL, NULL,
+ G_CALLBACK(quit_sig) },
+
+ { "ToolsAction", NULL, "_Tools", NULL, NULL, NULL },
+
+ { "HelpAction", NULL, "_Help", NULL, NULL, NULL },
+ { "AboutAction", GTK_STOCK_ABOUT, "_About", NULL, NULL,
+ G_CALLBACK(about_sig) },
+
+ };
+ guint n_entries = G_N_ELEMENTS(entries);
+
+ proj->action_group = gtk_action_group_new("cellwindow");
+ gtk_action_group_add_actions(proj->action_group, entries, n_entries, proj);
+
+ proj->ui = gtk_ui_manager_new();
+ gtk_ui_manager_insert_action_group(proj->ui, proj->action_group, 0);
+ g_signal_connect(proj->ui, "add_widget", G_CALLBACK(add_ui_sig), vbox);
+ if ( gtk_ui_manager_add_ui_from_string(proj->ui, ui, -1, &error) == 0 )
+ {
+ fprintf(stderr, "Error loading message window menu bar: %s\n",
+ error->message);
+ return;
+ }
+
+ gtk_window_add_accel_group(GTK_WINDOW(proj->window),
+ gtk_ui_manager_get_accel_group(proj->ui));
+ gtk_ui_manager_ensure_update(proj->ui);
+}
+
+
+int main(int argc, char *argv[])
+{
+ int c;
+ struct crystfelproject proj;
+ GtkWidget *vbox;
+ GtkWidget *vpaned;
+ GtkWidget *hpaned;
+ GtkWidget *scroll;
+ GtkWidget *frame;
+
+ /* Long options */
+ const struct option longopts[] = {
+ {"help", 0, NULL, 'h'},
+ {"version", 0, NULL, 1 },
+ {0, 0, NULL, 0}
+ };
+
+ /* Short options */
+ while ((c = getopt_long(argc, argv, "h",
+ longopts, NULL)) != -1) {
+
+ switch (c) {
+
+ case 'h' :
+ show_help(argv[0]);
+ return 0;
+
+ case 1 :
+ printf("CrystFEL: " CRYSTFEL_VERSIONSTRING "\n");
+ printf(CRYSTFEL_BOILERPLATE"\n");
+ return 0;
+
+ default :
+ return 1;
+
+ }
+
+ }
+
+ /* This isn't great, but necessary to make the command-line UI and file
+ * formats consistent with the other programs, which all use the C
+ * locale. Better would be to have all the programs call
+ * setlocale(LC_ALL, "") and use the C locale temporarily when reading
+ * or writing a stream, reflection file, geometry file etc. */
+ gtk_disable_setlocale();
+
+ gtk_init(&argc, &argv);
+
+ proj.window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_title(GTK_WINDOW(proj.window), "CrystFEL");
+ g_signal_connect(G_OBJECT(proj.window), "destroy", G_CALLBACK(destroy_sig),
+ &proj);
+
+ vbox = gtk_vbox_new(FALSE, 0.0);
+ gtk_container_add(GTK_CONTAINER(proj.window), vbox);
+ add_menu_bar(&proj, vbox);
+
+ vpaned = gtk_paned_new(GTK_ORIENTATION_VERTICAL);
+ gtk_box_pack_end(GTK_BOX(vbox), vpaned, TRUE, TRUE, 0.0);
+
+ hpaned = gtk_paned_new(GTK_ORIENTATION_HORIZONTAL);
+ gtk_paned_pack1(GTK_PANED(vpaned), hpaned, TRUE, TRUE);
+
+ proj.imageview = crystfel_image_view_new();
+ frame = gtk_frame_new(NULL);
+ gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN);
+ scroll = gtk_scrolled_window_new(NULL, NULL);
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll),
+ GTK_POLICY_ALWAYS, GTK_POLICY_ALWAYS);
+ gtk_container_add(GTK_CONTAINER(scroll), GTK_WIDGET(proj.imageview));
+ gtk_container_add(GTK_CONTAINER(frame), GTK_WIDGET(scroll));
+ gtk_paned_pack2(GTK_PANED(hpaned), GTK_WIDGET(frame), TRUE, TRUE);
+
+ proj.icons = gtk_drawing_area_new();
+ frame = gtk_frame_new(NULL);
+ gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN);
+ gtk_container_add(GTK_CONTAINER(frame), GTK_WIDGET(proj.icons));
+ gtk_paned_pack1(GTK_PANED(hpaned), GTK_WIDGET(frame), FALSE, FALSE);
+
+ proj.report = gtk_text_view_new();
+ frame = gtk_frame_new(NULL);
+ gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN);
+ gtk_container_add(GTK_CONTAINER(frame), GTK_WIDGET(proj.report));
+ gtk_paned_pack2(GTK_PANED(vpaned), GTK_WIDGET(frame), FALSE, FALSE);
+
+ gtk_widget_show_all(proj.window);
+ gtk_main();
+
+ return 0;
+}
diff --git a/src/crystfelimageview.c b/src/crystfelimageview.c
new file mode 100644
index 00000000..9d3589d0
--- /dev/null
+++ b/src/crystfelimageview.c
@@ -0,0 +1,298 @@
+/*
+ * crystfelimageview.c
+ *
+ * CrystFEL's image viewer widget
+ *
+ * Copyright © 2020 Deutsches Elektronen-Synchrotron DESY,
+ * a research centre of the Helmholtz Association.
+ *
+ * Authors:
+ * 2020 Thomas White <taw@physics.org>
+ *
+ * This file is part of CrystFEL.
+ *
+ * CrystFEL is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * CrystFEL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with CrystFEL. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <gtk/gtk.h>
+#include <glib-object.h>
+
+#include "crystfelimageview.h"
+
+
+static void scroll_interface_init(GtkScrollable *iface)
+{
+}
+
+
+enum
+{
+ CRYSTFELIMAGEVIEW_0,
+ CRYSTFELIMAGEVIEW_VADJ,
+ CRYSTFELIMAGEVIEW_HADJ,
+ CRYSTFELIMAGEVIEW_VPOL,
+ CRYSTFELIMAGEVIEW_HPOL,
+};
+
+
+G_DEFINE_TYPE_WITH_CODE(CrystFELImageView, crystfel_image_view,
+ GTK_TYPE_DRAWING_AREA,
+ G_IMPLEMENT_INTERFACE(GTK_TYPE_SCROLLABLE,
+ scroll_interface_init))
+
+
+static gint destroy_sig(GtkWidget *window, CrystFELImageView *iv)
+{
+ return FALSE;
+}
+
+
+static gint realise_sig(GtkWidget *window, CrystFELImageView *iv)
+{
+ return FALSE;
+}
+
+
+static gint button_press_sig(GtkWidget *window, GdkEventButton *event,
+ CrystFELImageView *iv)
+{
+ return FALSE;
+}
+
+
+static gint motion_sig(GtkWidget *window, GdkEventMotion *event,
+ CrystFELImageView *iv)
+{
+ return FALSE;
+}
+
+
+
+static gint resize_sig(GtkWidget *window, GdkEventConfigure *event,
+ CrystFELImageView *iv)
+{
+ return FALSE;
+}
+
+
+static gint draw_sig(GtkWidget *window, cairo_t *cr, CrystFELImageView *iv)
+{
+ cairo_set_source_rgb(cr, 1.0, 0.0, 0.0);
+ cairo_paint(cr);
+ return FALSE;
+}
+
+
+static void redraw(CrystFELImageView *iv)
+{
+}
+
+
+static void horizontal_adjust(GtkAdjustment *adj, CrystFELImageView *iv)
+{
+ iv->x_scroll_pos = gtk_adjustment_get_value(adj);
+ redraw(iv);
+}
+
+
+static void set_horizontal_params(CrystFELImageView *iv)
+{
+ if ( iv->hadj == NULL ) return;
+ gtk_adjustment_configure(iv->hadj, iv->x_scroll_pos, 0, iv->w, 100,
+ iv->visible_width, iv->visible_width);
+}
+
+
+static void vertical_adjust(GtkAdjustment *adj, CrystFELImageView *iv)
+{
+ iv->y_scroll_pos = gtk_adjustment_get_value(adj);
+ redraw(iv);
+}
+
+
+static void set_vertical_params(CrystFELImageView *iv)
+{
+ if ( iv->vadj == NULL ) return;
+ gtk_adjustment_configure(iv->vadj, iv->y_scroll_pos, 0, iv->w, 100,
+ iv->visible_width, iv->visible_width);
+}
+
+
+static void crystfel_image_view_set_property(GObject *obj, guint id, const GValue *val,
+ GParamSpec *spec)
+{
+ CrystFELImageView *iv = CRYSTFEL_IMAGE_VIEW(obj);
+
+ switch ( id ) {
+
+ case CRYSTFELIMAGEVIEW_VPOL :
+ iv->vpol = g_value_get_enum(val);
+ break;
+
+ case CRYSTFELIMAGEVIEW_HPOL :
+ iv->hpol = g_value_get_enum(val);
+ break;
+
+ case CRYSTFELIMAGEVIEW_VADJ :
+ iv->vadj = g_value_get_object(val);
+ set_vertical_params(iv);
+ if ( iv->vadj != NULL ) {
+ g_signal_connect(G_OBJECT(iv->vadj), "value-changed",
+ G_CALLBACK(vertical_adjust), iv);
+ }
+ break;
+
+ case CRYSTFELIMAGEVIEW_HADJ :
+ iv->hadj = g_value_get_object(val);
+ set_horizontal_params(iv);
+ if ( iv->hadj != NULL ) {
+ g_signal_connect(G_OBJECT(iv->hadj), "value-changed",
+ G_CALLBACK(horizontal_adjust), iv);
+ }
+ break;
+
+ default :
+ printf("setting %i\n", id);
+ break;
+
+ }
+}
+
+
+static void crystfel_image_view_get_property(GObject *obj, guint id, GValue *val,
+ GParamSpec *spec)
+{
+ CrystFELImageView *iv = CRYSTFEL_IMAGE_VIEW(obj);
+
+ switch ( id ) {
+
+ case CRYSTFELIMAGEVIEW_VADJ :
+ g_value_set_object(val, iv->vadj);
+ break;
+
+ case CRYSTFELIMAGEVIEW_HADJ :
+ g_value_set_object(val, iv->hadj);
+ break;
+
+ case CRYSTFELIMAGEVIEW_VPOL :
+ g_value_set_enum(val, iv->vpol);
+ break;
+
+ case CRYSTFELIMAGEVIEW_HPOL :
+ g_value_set_enum(val, iv->hpol);
+ break;
+
+ default :
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, id, spec);
+ break;
+
+ }
+}
+
+
+static GtkSizeRequestMode get_request_mode(GtkWidget *widget)
+{
+ return GTK_SIZE_REQUEST_CONSTANT_SIZE;
+}
+
+
+static void get_preferred_width(GtkWidget *widget, gint *min, gint *natural)
+{
+ *min = 0;
+ *natural = 640;
+}
+
+
+static void get_preferred_height(GtkWidget *widget, gint *min, gint *natural)
+{
+ *min = 0;
+ *natural = 640;
+}
+
+
+static void crystfel_image_view_class_init(CrystFELImageViewClass *klass)
+{
+ GObjectClass *goc = G_OBJECT_CLASS(klass);
+ goc->set_property = crystfel_image_view_set_property;
+ goc->get_property = crystfel_image_view_get_property;
+ g_object_class_override_property(goc, CRYSTFELIMAGEVIEW_VADJ, "vadjustment");
+ g_object_class_override_property(goc, CRYSTFELIMAGEVIEW_HADJ, "hadjustment");
+ g_object_class_override_property(goc, CRYSTFELIMAGEVIEW_VPOL, "vscroll-policy");
+ g_object_class_override_property(goc, CRYSTFELIMAGEVIEW_HPOL, "hscroll-policy");
+
+ GTK_WIDGET_CLASS(klass)->get_request_mode = get_request_mode;
+ GTK_WIDGET_CLASS(klass)->get_preferred_width = get_preferred_width;
+ GTK_WIDGET_CLASS(klass)->get_preferred_height = get_preferred_height;
+ GTK_WIDGET_CLASS(klass)->get_preferred_height_for_width = NULL;
+}
+
+
+static void crystfel_image_view_init(CrystFELImageView *iv)
+{
+ iv->vpol = GTK_SCROLL_NATURAL;
+ iv->hpol = GTK_SCROLL_NATURAL;
+ iv->vadj = NULL;
+ iv->hadj = NULL;
+}
+
+
+GtkWidget *crystfel_image_view_new()
+{
+ CrystFELImageView *iv;
+
+ iv = g_object_new(CRYSTFEL_TYPE_IMAGE_VIEW, NULL);
+
+ iv->w = 100;
+ iv->h = 100;
+ iv->x_scroll_pos = 0;
+ iv->y_scroll_pos = 0;
+
+ gtk_widget_set_size_request(GTK_WIDGET(iv), iv->w, iv->h);
+
+ g_signal_connect(G_OBJECT(iv), "destroy",
+ G_CALLBACK(destroy_sig), iv);
+ g_signal_connect(G_OBJECT(iv), "realize",
+ G_CALLBACK(realise_sig), iv);
+ g_signal_connect(G_OBJECT(iv), "button-press-event",
+ G_CALLBACK(button_press_sig), iv);
+ g_signal_connect(G_OBJECT(iv), "motion-notify-event",
+ G_CALLBACK(motion_sig), iv);
+ g_signal_connect(G_OBJECT(iv), "configure-event",
+ G_CALLBACK(resize_sig), iv);
+ g_signal_connect(G_OBJECT(iv), "draw",
+ G_CALLBACK(draw_sig), iv);
+
+ gtk_widget_set_can_focus(GTK_WIDGET(iv), TRUE);
+ gtk_widget_add_events(GTK_WIDGET(iv),
+ GDK_POINTER_MOTION_HINT_MASK
+ | GDK_BUTTON1_MOTION_MASK
+ | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+ | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK
+ | GDK_SCROLL_MASK);
+
+ gtk_widget_grab_focus(GTK_WIDGET(iv));
+
+ gtk_widget_show(GTK_WIDGET(iv));
+
+ return GTK_WIDGET(iv);
+}
diff --git a/src/crystfelimageview.h b/src/crystfelimageview.h
new file mode 100644
index 00000000..9dd69d0d
--- /dev/null
+++ b/src/crystfelimageview.h
@@ -0,0 +1,84 @@
+/*
+ * crystfelimageview.h
+ *
+ * CrystFEL's image viewer widget
+ *
+ * Copyright © 2020 Deutsches Elektronen-Synchrotron DESY,
+ * a research centre of the Helmholtz Association.
+ *
+ * Authors:
+ * 2020 Thomas White <taw@physics.org>
+ *
+ * This file is part of CrystFEL.
+ *
+ * CrystFEL is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * CrystFEL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with CrystFEL. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef CRYSTFELIMAGEVIEW_H
+#define CRYSTFELIMAGEVIEW_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define CRYSTFEL_TYPE_IMAGE_VIEW (crystfel_image_view_get_type())
+
+#define CRYSTFEL_IMAGE_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
+ CRYSTFEL_TYPE_IMAGE_VIEW, CrystFELImageView))
+
+#define CRYSTFEL_IS_IMAGE_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), \
+ CRYSTFEL_TYPE_IMAGE_VIEW))
+
+#define CRYSTFEL_IMAGE_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((obj), \
+ CRYSTFEL_TYPE_IMAGE_VIEW, CrystFELImageView))
+
+#define CRYSTFEL_IS_IMAGE_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((obj), \
+ CRYSTFEL_TYPE_IMAGE_VIEW))
+
+#define CRYSTFEL_IMAGE_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), \
+ CRYSTFEL_TYPE_IMAGE_VIEW, CrystFELImageView))
+
+struct _crystfelimageview
+{
+ GtkDrawingArea parent_instance;
+
+ /*< private >*/
+ GtkIMContext *im_context;
+
+ int w; /* Surface size in pixels */
+ int h;
+
+ /* Redraw/scroll stuff */
+ GtkScrollablePolicy hpol;
+ GtkScrollablePolicy vpol;
+ GtkAdjustment *hadj;
+ GtkAdjustment *vadj;
+ double x_scroll_pos;
+ double y_scroll_pos;
+};
+
+struct _crystfelimageviewclass
+{
+ GtkDrawingAreaClass parent_class;
+};
+
+typedef struct _crystfelimageview CrystFELImageView;
+typedef struct _crystfelimageviewclass CrystFELImageViewClass;
+
+extern GType crystfel_image_view_get_type(void);
+extern GtkWidget *crystfel_image_view_new(void);
+
+
+#endif /* CRYSTFELIMAGEVIEW_H */