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