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