1 /**
2  * Minimal GTK bindings by Steve Teale
3  *
4  * License: Boost License 1.0
5  *
6  * Warning:
7  * The GTK here is as simple as possible, but not useable for real world code.
8  * At least the following features are missing:
9  * * Drawing should be done to a Pixmap, then clipped onto the GTKWindow
10  * * We always draw everything! Real code should determine the area that needs to be redrawn!
11  * * Resizing support
12  */
13 module cairo.examples.gtk;
14 
15 version(GTK):
16 
17 import cairo, cairo.c;
18 import core.stdc.config;
19 import cairo.example;
20 
21 struct GtkWidget;
22 struct GtkWindow;
23 struct GtkContainer;
24 struct GdkWindow;
25 enum GTK_WINDOW_TOPLEVEL = 0;
26 enum GTK_WIN_POS_CENTER = 1;
27 
28 extern(C) GtkWidget* gtk_window_new (int type);
29 extern(C) GtkWidget* gtk_drawing_area_new();
30 extern(C) void gtk_container_add(GtkContainer *container, GtkWidget *widget);
31 extern(C) c_ulong g_signal_connect_data (void* instance,
32                        const char *detailed_signal,
33                        void* c_handler,
34                        void* data,
35                        void* destroy_data,
36                        int connect_flags);
37 extern(C) void gtk_window_set_position (GtkWindow *window, int position);
38 extern(C) void gtk_window_set_default_size (GtkWindow *window, int width, int height);
39 extern(C) void gtk_window_set_title (GtkWindow *window, const char *title);
40 extern(C) void gtk_widget_show_all (GtkWidget *widget);
41 extern(C) void gtk_main();
42 extern(C) void gtk_init(int*, char***);
43 extern(C) void gtk_main_quit();
44 extern(C) cairo_t* gdk_cairo_create (GdkWindow *window);
45 extern(C) GdkWindow * gtk_widget_get_window (GtkWidget *widget);
46 
47 version(GTK3)
48 {
49     extern(C) nothrow bool on_draw_event(GtkWidget *widget, cairo_t *cr, void* user_data)
50     {
51         import std.stdio;
52 
53         try
54         {
55             cairo_reference(cr);
56             auto ctx = Context(cr);
57             (cast(DrawFunction)user_data)(ctx);
58         }
59         catch(Throwable t)
60         {
61             import std.stdio;
62             try{writefln("Unhandled exception: %s", t);}catch(Throwable){}
63         }
64         return false;
65     }
66 }
67 else
68 {
69     extern(C) nothrow bool on_draw_event(GtkWidget *widget, void * event, void* user_data)
70     {
71         import std.stdio;
72 
73         try
74         {
75             auto cr = gdk_cairo_create(gtk_widget_get_window (widget));
76             //cairo_reference(cr);
77             auto ctx = Context(cr);
78             (cast(DrawFunction)user_data)(ctx);
79         }
80         catch(Throwable t)
81         {
82             import std.stdio;
83             try{writefln("Unhandled exception: %s", t);}catch(Throwable){}
84         }
85         return false;
86     }
87 }
88 
89 void gtkRunExample(DrawFunction draw)
90 {
91     import std.stdio;
92     version(GTK3)
93         writeln("Using GTK3");
94     else
95         writeln("Using GTK2");
96     import core.runtime;
97     int argc = Runtime.cArgs.argc;
98     char** argv = Runtime.cArgs.argv;
99     
100     gtk_init(&argc, &argv);
101 
102     auto window = cast(GtkWindow*)gtk_window_new(GTK_WINDOW_TOPLEVEL);
103 
104     auto darea = gtk_drawing_area_new();
105     gtk_container_add(cast(GtkContainer*)window, darea);
106 
107     version(GTK3)
108     {
109         g_signal_connect_data(darea, "draw".ptr, 
110             &on_draw_event, draw, null, 1);
111     }
112     else
113     {
114         g_signal_connect_data(darea, "expose_event".ptr, 
115             &on_draw_event, draw, null, 1);
116     }
117     g_signal_connect_data(window, "destroy".ptr,
118         &gtk_main_quit, null, null, 1);
119 
120     gtk_window_set_position(window, GTK_WIN_POS_CENTER);
121     gtk_window_set_default_size(window, 400, 400); 
122     gtk_window_set_title(window, "GTK window");
123 
124     gtk_widget_show_all(cast(GtkWidget*)window);
125 
126     gtk_main();
127 }