1 /* robwidget - gtk2 & GL wrapper
2  *
3  * Copyright (C) 2013 Robin Gareus <robin@gareus.org>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2, or (at your option)
8  * any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  */
19 #ifndef _ROBTK_H_
20 #define _ROBTK_H_
21 
22 #ifndef VERSION
23 #define VERSION "0.invalid"
24 #endif
25 
26 #include <assert.h>
27 #include <pthread.h>
28 #include <string.h>
29 
30 #include <cairo/cairo.h>
31 #include <pango/pango.h>
32 #include <pango/pangocairo.h>
33 
34 #include "lv2/lv2plug.in/ns/extensions/ui/ui.h"
35 #include "lv2/lv2plug.in/ns/ext/options/options.h"
36 #include "lv2/lv2plug.in/ns/ext/urid/urid.h"
37 #include "lv2/lv2plug.in/ns/ext/atom/atom.h"
38 
39 #ifdef __APPLE__
40 #include <mach/clock.h>
41 #include <mach/mach.h>
42 #endif
43 
44 #ifdef _WIN32
getFILETIMEoffset()45 static LARGE_INTEGER getFILETIMEoffset() {
46 	SYSTEMTIME s;
47 	FILETIME f;
48 	LARGE_INTEGER t;
49 
50 	s.wYear = 1970;
51 	s.wMonth = 1;
52 	s.wDay = 1;
53 	s.wHour = 0;
54 	s.wMinute = 0;
55 	s.wSecond = 0;
56 	s.wMilliseconds = 0;
57 	SystemTimeToFileTime(&s, &f);
58 	t.QuadPart = f.dwHighDateTime;
59 	t.QuadPart <<= 32;
60 	t.QuadPart |= f.dwLowDateTime;
61 	return (t);
62 }
63 #endif
64 
65 // monotonic time
rtk_clock_gettime(struct timespec * ts)66 static void rtk_clock_gettime(struct timespec *ts) {
67 #ifdef __APPLE__
68 	clock_serv_t cclock;
69 	mach_timespec_t mts;
70 	host_get_clock_service(mach_host_self(), SYSTEM_CLOCK /*CALENDAR_CLOCK*/, &cclock);
71 	clock_get_time(cclock, &mts);
72 	mach_port_deallocate(mach_task_self(), cclock);
73 	ts->tv_sec = mts.tv_sec;
74 	ts->tv_nsec = mts.tv_nsec;
75 #elif defined _WIN32
76 	LARGE_INTEGER  t;
77 	FILETIME       f;
78 	double                  microseconds;
79 	static LARGE_INTEGER    offset;
80 	static double           frequencyToMicroseconds;
81 	static int              initialized = 0;
82 	static BOOL             usePerformanceCounter = 0;
83 
84 	if (!initialized) {
85 		LARGE_INTEGER performanceFrequency;
86 		initialized = 1;
87 		usePerformanceCounter = QueryPerformanceFrequency(&performanceFrequency);
88 		if (usePerformanceCounter) {
89 			QueryPerformanceCounter(&offset);
90 			frequencyToMicroseconds = (double)performanceFrequency.QuadPart / 1000000.;
91 		} else {
92 			offset = getFILETIMEoffset();
93 			frequencyToMicroseconds = 10.;
94 		}
95 	}
96 	if (usePerformanceCounter) QueryPerformanceCounter(&t);
97 	else {
98 		GetSystemTimeAsFileTime(&f);
99 		t.QuadPart = f.dwHighDateTime;
100 		t.QuadPart <<= 32;
101 		t.QuadPart |= f.dwLowDateTime;
102 	}
103 
104 	t.QuadPart -= offset.QuadPart;
105 	microseconds = (double)t.QuadPart / frequencyToMicroseconds;
106 	t.QuadPart = microseconds;
107 	ts->tv_sec = t.QuadPart / 1000000;
108 	ts->tv_nsec = 1000 * (t.QuadPart % 1000000);
109 #else
110 	clock_gettime(CLOCK_MONOTONIC, ts);
111 #endif
112 }
113 
114 // realtime time -- only used for  pthread_cond_timedwait()
rtk_clock_systime(struct timespec * ts)115 static void rtk_clock_systime(struct timespec *ts) {
116 #ifdef __APPLE__
117 	rtk_clock_gettime(ts);
118 #elif defined _WIN32
119 	struct __timeb64 currSysTime;
120 	_ftime64(&currSysTime);
121 	ts->tv_sec = currSysTime.time;
122 	ts->tv_nsec = 1000 * currSysTime.millitm;
123 #else
124 	clock_gettime(CLOCK_REALTIME, ts);
125 #endif
126 
127 }
128 /*****************************************************************************/
129 
130 typedef struct {
131 	int x; int y;
132 	int state;
133 	int direction; // scroll
134 	int button;
135 } RobTkBtnEvent;
136 
137 #ifndef ROBTK_MOD_SHIFT
138 #error backend implementation misses ROBTK_MOD_SHIFT
139 #endif
140 
141 #ifndef ROBTK_MOD_CTRL
142 #error backend implementation misses ROBTK_MOD_CTRL
143 #endif
144 
145 enum {
146 	ROBTK_SCROLL_ZERO,
147 	ROBTK_SCROLL_UP,
148 	ROBTK_SCROLL_DOWN,
149 	ROBTK_SCROLL_LEFT,
150 	ROBTK_SCROLL_RIGHT
151 };
152 
153 enum LVGLResize {
154 	LVGL_ZOOM_TO_ASPECT,
155 	LVGL_LAYOUT_TO_FIT,
156 	LVGL_CENTER,
157 	LVGL_TOP_LEFT,
158 };
159 
160 typedef struct _robwidget {
161 	void *self; // user-handle for the actual (wrapped) widget
162 
163 	/* required */
164 	bool (*expose_event) (struct _robwidget* handle, cairo_t* cr, cairo_rectangle_t *ev);
165 	void (*size_request) (struct _robwidget* handle, int *w, int *h);
166 
167 	/* optional */
168 	void (*position_set) (struct _robwidget* handle, int pw, int ph);
169 	void (*size_allocate) (struct _robwidget* handle, int pw, int ph);
170 	/* optional -- hybrid GL+cairo scaling */
171 	void (*size_limit) (struct _robwidget* handle, int *pw, int *ph);
172 	void (*size_default) (struct _robwidget* handle, int *pw, int *ph);
173 
174 	/* optional */
175 	struct _robwidget* (*mousedown)    (struct _robwidget*, RobTkBtnEvent *event);
176 	struct _robwidget* (*mouseup)      (struct _robwidget*, RobTkBtnEvent *event);
177 	struct _robwidget* (*mousemove)    (struct _robwidget*, RobTkBtnEvent *event);
178 	struct _robwidget* (*mousescroll)  (struct _robwidget*, RobTkBtnEvent *event);
179 	void               (*enter_notify) (struct _robwidget*);
180 	void               (*leave_notify) (struct _robwidget*);
181 
182 	/* internal - GL */
183 #ifndef GTK_BACKEND
184 	void* top;
185 	struct _robwidget* parent;
186 	struct _robwidget **children;
187 	unsigned int childcount;
188 	float widget_scale;
189 
190 	bool redraw_pending; // queue_draw_*() failed (during init or top-levelresize)
191 	bool resized; // full-redraw --containers after resize
192 	bool hidden; // don't display, skip in layout and events
193 	int  packing_opts;
194 	bool block_events;
195 #endif
196 	float xalign, yalign; // unused in GTK
197 	cairo_rectangle_t area; // allocated pos + size
198 	cairo_rectangle_t trel; // cached pos + size relative to top widget
199 	bool cached_position;
200 
201 	/* internal - GTK */
202 #ifdef GTK_BACKEND
203 	GtkWidget *m0;
204 	GtkWidget *c;
205 #endif
206 
207 	char name[12]; // debug with ROBWIDGET_NAME()
208 } RobWidget;
209 
210 
211 /*****************************************************************************/
212 /* provided by host */
213 
214 static void resize_self(RobWidget *rw); // dangerous :) -- never call from expose_event
215 static void resize_toplevel(RobWidget *rw, int w, int h); // ditto
216 static void relayout_toplevel(RobWidget *rw);
217 static void queue_draw(RobWidget *);
218 static void queue_draw_area(RobWidget *, int, int, int, int);
219 static void queue_tiny_area(RobWidget *rw, float x, float y, float w, float h);
220 
221 static void robwidget_toplevel_enable_scaling (RobWidget* rw);
222 static void robtk_queue_scale_change (RobWidget *rw, const float ws);
223 
224 static RobWidget * robwidget_new(void *);
225 static void robwidget_destroy(RobWidget *rw);
226 
227 static const char * robtk_info(void *);
228 
229 /*****************************************************************************/
230 /* static plugin singletons */
231 
232 static LV2UI_Handle
233 instantiate(
234 		void *const               ui_toplevel,
235 		const LV2UI_Descriptor*   descriptor,
236 		const char*               plugin_uri,
237 		const char*               bundle_path,
238 		LV2UI_Write_Function      write_function,
239 		LV2UI_Controller          controller,
240 		RobWidget**               widget,
241 		const LV2_Feature* const* features);
242 
243 static void
244 cleanup(LV2UI_Handle handle);
245 
246 static enum LVGLResize
247 plugin_scale_mode(LV2UI_Handle handle);
248 
249 static void
250 port_event(LV2UI_Handle handle,
251            uint32_t     port_index,
252            uint32_t     buffer_size,
253            uint32_t     format,
254            const void*  buffer);
255 
256 static const void *
257 extension_data(const char* uri);
258 
259 #define ROBWIDGET_NAME(RW) ( ((RobWidget*)(RW))->name[0] ? (const char*) (((RobWidget*)(RW))->name) : (const char*) "???")
260 #define ROBWIDGET_SETNAME(RW, TXT) strcpy(((RobWidget*)(RW))->name, TXT); // max 11 chars
261 
262 /******************************************************************************/
263 // utils //
rect_intersection(cairo_rectangle_t * r,const cairo_rectangle_t * r1,const cairo_rectangle_t * r2)264 static void rect_intersection(cairo_rectangle_t *r, const cairo_rectangle_t *r1, const cairo_rectangle_t *r2){
265 	cairo_rectangle_t is;
266 	is.x      = MAX(r1->x, r2->x);
267 	is.y      = MAX(r1->y, r2->y);
268 	is.width  = MAX(0, MIN(r1->x + r1->width,  r2->x + r2->width)  - MAX(r1->x, r2->x));
269 	is.height = MAX(0, MIN(r1->y + r1->height, r2->y + r2->height) - MAX(r1->y, r2->y));
270 	memcpy(r, &is, sizeof(cairo_rectangle_t));
271 }
272 
rect_intersect(const cairo_rectangle_t * r1,const cairo_rectangle_t * r2)273 static bool rect_intersect(const cairo_rectangle_t *r1, const cairo_rectangle_t *r2){
274 	float dest_x, dest_y;
275 	float dest_x2, dest_y2;
276 
277 	dest_x  = MAX (r1->x, r2->x);
278 	dest_y  = MAX (r1->y, r2->y);
279 	dest_x2 = MIN (r1->x + r1->width, r2->x + r2->width);
280 	dest_y2 = MIN (r1->y + r1->height, r2->y + r2->height);
281 
282 	return (dest_x2 > dest_x && dest_y2 > dest_y);
283 }
284 
rect_intersect_a(const cairo_rectangle_t * r1,const float x,const float y,const float w,const float h)285 static bool rect_intersect_a(const cairo_rectangle_t *r1, const float x, const float y, const float w, const float h) {
286 	cairo_rectangle_t r2 = { x, y, w, h};
287 	return rect_intersect(r1, &r2);
288 }
289 
rect_combine(const cairo_rectangle_t * r1,const cairo_rectangle_t * r2,cairo_rectangle_t * dest)290 static void rect_combine(const cairo_rectangle_t *r1, const cairo_rectangle_t *r2, cairo_rectangle_t *dest) {
291 	double dest_x, dest_y;
292 	dest_x = MIN (r1->x, r2->x);
293 	dest_y = MIN (r1->y, r2->y);
294 	dest->width  = MAX (r1->x + r1->width,  r2->x + r2->width)  - dest_x;
295 	dest->height = MAX (r1->y + r1->height, r2->y + r2->height) - dest_y;
296 	dest->x = dest_x;
297 	dest->y = dest_y;
298 }
299 
300 static void get_color_from_theme (int which, float *col);
301 
302 #include "rtk/common.h"
303 #include "rtk/style.h"
304 
305 #ifdef GTK_BACKEND
306 
307 #include "gtk2/common_cgtk.h"
308 #include "gtk2/robwidget_gtk.h"
309 
310 #else
311 
312 #include "gl/common_cgl.h"
313 #include "gl/robwidget_gl.h"
314 #include "gl/layout.h"
315 
316 #endif
317 
318 #define C_RAD 5
319 
320 #include "widgets/robtk_checkbutton.h"
321 #include "widgets/robtk_checkimgbutton.h"
322 #include "widgets/robtk_multibutton.h"
323 #include "widgets/robtk_dial.h"
324 #include "widgets/robtk_label.h"
325 #include "widgets/robtk_pushbutton.h"
326 #include "widgets/robtk_radiobutton.h"
327 #include "widgets/robtk_scale.h"
328 #include "widgets/robtk_separator.h"
329 #include "widgets/robtk_spinner.h"
330 #include "widgets/robtk_xyplot.h"
331 #include "widgets/robtk_selector.h"
332 #include "widgets/robtk_image.h"
333 #include "widgets/robtk_drawingarea.h"
334 
335 #endif
336