1 /*
2 * Copyright (c) 2015-2016 Hanspeter Portner (dev@open-music-kontrollers.ch)
3 *
4 * This is free software: you can redistribute it and/or modify
5 * it under the terms of the Artistic License 2.0 as published by
6 * The Perl Foundation.
7 *
8 * This source is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * Artistic License 2.0 for more details.
12 *
13 * You should have received a copy of the Artistic License 2.0
14 * along the source as a COPYING file. If not, obtain it from
15 * http://www.perlfoundation.org/artistic_license_2_0.
16 */
17
18 #include <stdbool.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <unistd.h>
22
23 #include <sandbox_slave.h>
24 #include <lv2/lv2plug.in/ns/extensions/ui/ui.h>
25
26 #include <gtk/gtk.h>
27 #include <glib-unix.h>
28
29 typedef struct _wrap_t wrap_t;
30 typedef struct _app_t app_t;
31
32 struct _wrap_t {
33 sandbox_slave_t *sb;
34 app_t *app;
35 };
36
37 struct _app_t {
38 sandbox_slave_t *sb;
39
40 GtkWidget *win;
41 GtkWidget *widget;
42 guint timeout;
43 guint signal;
44 };
45
46 static gboolean
_anim(void * data)47 _anim(void *data)
48 {
49 wrap_t *wrap = data;
50
51 if(sandbox_slave_recv(wrap->sb))
52 {
53 gtk_main_quit();
54 wrap->app->win = NULL;
55 }
56
57 return true;
58 }
59
60 static void
_destroy(GtkWidget * widget,void * data)61 _destroy(GtkWidget *widget, void *data)
62 {
63 app_t *app = data;
64
65 gtk_main_quit();
66 app->win = NULL;
67 }
68
69 static gboolean
_sig(void * data)70 _sig(void *data)
71 {
72 app_t *app = data;
73
74 gtk_main_quit();
75 app->win = NULL;
76
77 return true;
78 }
79
80 static inline int
_init(sandbox_slave_t * sb,void * data)81 _init(sandbox_slave_t *sb, void *data)
82 {
83 app_t *app= data;
84
85 app->win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
86 if(!app->win)
87 {
88 fprintf(stderr, "gtk_window_new failed\n");
89 goto fail;
90 }
91 g_signal_connect(G_OBJECT(app->win), "destroy",
92 G_CALLBACK(_destroy), app);
93
94 const char *title = sandbox_slave_title_get(sb);
95 if(title)
96 gtk_window_set_title(GTK_WINDOW(app->win), title);
97
98 const LV2_Feature parent_feature = {
99 .URI = LV2_UI__parent,
100 .data = app->win
101 };
102
103 if(!sandbox_slave_instantiate(sb, &parent_feature, &app->widget))
104 goto fail;
105 if(!app->widget)
106 goto fail;
107
108 gtk_widget_set_can_focus(app->widget, true);
109 gtk_widget_grab_focus(app->widget);
110
111 gtk_container_add(GTK_CONTAINER(app->win), app->widget);
112 gtk_widget_show_all(app->win);
113
114 app->signal = g_unix_signal_add(SIGINT, _sig, app);
115 if(!app->signal)
116 {
117 fprintf(stderr, "g_unix_signal_add failed\n");
118 goto fail;
119 }
120
121 return 0; //success
122
123 fail:
124 return -1;
125 }
126
127 static inline void
_run(sandbox_slave_t * sb,float update_rate,void * data)128 _run(sandbox_slave_t *sb, float update_rate, void *data)
129 {
130 app_t *app = data;
131
132 wrap_t wrap = {
133 .app = app,
134 .sb = sb
135 };
136
137 app->timeout = g_timeout_add(1000 / update_rate, _anim, &wrap); //FIXME check
138 gtk_main();
139 }
140
141 static inline void
_deinit(void * data)142 _deinit(void *data)
143 {
144 app_t *app = data;
145
146 if(app->timeout)
147 g_source_remove(app->timeout);
148
149 if(app->signal)
150 g_source_remove(app->signal);
151
152 if(app->win)
153 {
154 gtk_widget_hide(app->win);
155 gtk_widget_destroy(app->win);
156 }
157 }
158
159 static const sandbox_slave_driver_t driver = {
160 .init_cb = _init,
161 .run_cb = _run,
162 .deinit_cb = _deinit,
163 .resize_cb = NULL
164 };
165
166 int
main(int argc,char ** argv)167 main(int argc, char **argv)
168 {
169 static app_t app;
170 int res;
171
172 gtk_init(&argc, &argv);
173
174 app.sb = sandbox_slave_new(argc, argv, &driver, &app, &res);
175 if(app.sb)
176 {
177 sandbox_slave_run(app.sb);
178 sandbox_slave_free(app.sb);
179 return res;
180 }
181
182 return res;
183 }
184