1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /***************************************************************************
3  *            nativewindow_pugl.cc
4  *
5  *  Fri Dec 28 18:45:57 CET 2012
6  *  Copyright 2012 Bent Bisballe Nyeng
7  *  deva@aasimon.org
8  ****************************************************************************/
9 
10 /*
11  *  This file is part of DrumGizmo.
12  *
13  *  DrumGizmo is free software; you can redistribute it and/or modify
14  *  it under the terms of the GNU Lesser General Public License as published by
15  *  the Free Software Foundation; either version 3 of the License, or
16  *  (at your option) any later version.
17  *
18  *  DrumGizmo is distributed in the hope that it will be useful,
19  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
20  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  *  GNU Lesser General Public License for more details.
22  *
23  *  You should have received a copy of the GNU Lesser General Public License
24  *  along with DrumGizmo; if not, write to the Free Software
25  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
26  */
27 #include "nativewindow_pugl.h"
28 
29 #include <stdlib.h>
30 #include <list>
31 
32 #ifdef __APPLE__
33 #include <OpenGL/glu.h>
34 #else
35 #include <GL/glu.h>
36 #include <GL/glext.h>
37 #include <GL/gl.h>
38 #endif
39 
40 #include "window.h"
41 #include "guievent.h"
42 
43 #include <hugin.hpp>
44 
45 namespace GUI
46 {
47 
NativeWindowPugl(void * native_window,Window & window)48 NativeWindowPugl::NativeWindowPugl(void* native_window, Window& window)
49 	: window(window)
50 {
51 	INFO(nativewindow, "Running with PuGL native window\n");
52 	view = puglInit(nullptr, nullptr);
53 	puglInitContextType(view, PUGL_GL);
54 	if(native_window)
55 	{
56 		puglInitWindowParent(view, (PuglNativeWindow)native_window);
57 	}
58 	puglInitWindowClass(view, "DrumgGizmo");
59 	puglInitWindowSize(view, 750, 466);
60 	puglInitResizable(view, true);
61 	puglCreateWindow(view, "DrumGizmo");
62 
63 	puglSetHandle(view, (PuglHandle)this);
64 	puglSetEventFunc(view, onEvent);
65 }
66 
~NativeWindowPugl()67 NativeWindowPugl::~NativeWindowPugl()
68 {
69 	puglDestroy(view);
70 }
71 
setFixedSize(std::size_t width,std::size_t height)72 void NativeWindowPugl::setFixedSize(std::size_t width, std::size_t height)
73 {
74 //	redraw();
75 }
76 
resize(std::size_t width,std::size_t height)77 void NativeWindowPugl::resize(std::size_t width, std::size_t height)
78 {
79 //	DEBUG(nativewindow_pugl, "Resizing to %dx%d\n", width, height);
80 //	init();
81 //	redraw();
82 }
83 
getSize() const84 std::pair<std::size_t, std::size_t> NativeWindowPugl::getSize() const
85 {
86 	int width, height;
87 	puglGetSize(view, &width, &height);
88 	return {width, height};
89 }
90 
move(int x,int y)91 void NativeWindowPugl::move(int x, int y)
92 {
93 //	redraw();
94 }
95 
show()96 void NativeWindowPugl::show()
97 {
98 	puglShowWindow(view);
99 }
100 
hide()101 void NativeWindowPugl::hide()
102 {
103 	puglHideWindow(view);
104 }
105 
visible() const106 bool NativeWindowPugl::visible() const
107 {
108 	return puglGetVisible(view);
109 }
110 
redraw(const Rect & dirty_rect)111 void NativeWindowPugl::redraw(const Rect& dirty_rect)
112 {
113 	//puglPostRedisplay(view);//	handleBuffer();
114 	onDisplay(view);
115 }
116 
setCaption(const std::string & caption)117 void NativeWindowPugl::setCaption(const std::string &caption)
118 {
119 //	redraw();
120 }
121 
grabMouse(bool grab)122 void NativeWindowPugl::grabMouse(bool grab)
123 {
124 	puglGrabFocus(view);
125 }
126 
getEvents()127 EventQueue NativeWindowPugl::getEvents()
128 {
129 	puglProcessEvents(view);
130 	EventQueue events;
131 	std::swap(events, event_queue);
132 	return events;
133 }
134 
getNativeWindowHandle() const135 void* NativeWindowPugl::getNativeWindowHandle() const
136 {
137 	return (void*)puglGetNativeWindow(view);
138 }
139 
onEvent(PuglView * view,const PuglEvent * event)140 void NativeWindowPugl::onEvent(PuglView* view, const PuglEvent* event)
141 {
142 	NativeWindowPugl* native = (NativeWindowPugl*)puglGetHandle(view);
143 
144 	switch(event->type)
145 	{
146 	case PUGL_NOTHING:
147 		break;
148 	case PUGL_CONFIGURE:
149 		onReshape(view, event->configure.width, event->configure.height);
150 		{
151 			auto resize_event = std::make_shared<ResizeEvent>();
152 			resize_event->width = event->configure.width;
153 			resize_event->height = event->configure.height;
154 			native->event_queue.push_back(resize_event);
155 		}
156 		break;
157 	case PUGL_EXPOSE:
158 		onDisplay(view);
159 		break;
160 	case PUGL_CLOSE:
161 		//quit = 1;
162 		break;
163 	case PUGL_KEY_PRESS:
164 		fprintf(stderr, "Key %u (char %u) press (%s)%s\n",
165 		        event->key.keycode, event->key.character, event->key.utf8,
166 		        event->key.filter ? " (filtered)" : "");
167 		if (event->key.character == 'q' ||
168 		    event->key.character == 'Q' ||
169 		    event->key.character == PUGL_CHAR_ESCAPE) {
170 			//quit = 1;
171 		}
172 		break;
173 	case PUGL_KEY_RELEASE:
174 		fprintf(stderr, "Key %u (char %u) release (%s)%s\n",
175 		        event->key.keycode, event->key.character, event->key.utf8,
176 		        event->key.filter ? " (filtered)" : "");
177 		break;
178 	case PUGL_MOTION_NOTIFY:
179 		{
180 			auto mouseMoveEvent = std::make_shared<MouseMoveEvent>();
181 			mouseMoveEvent->x = event->motion.x;
182 			mouseMoveEvent->y = event->motion.y;
183 			native->event_queue.push_back(mouseMoveEvent);
184 		}
185 		break;
186 	case PUGL_BUTTON_PRESS:
187 	case PUGL_BUTTON_RELEASE:
188 		{
189 			auto buttonEvent = std::make_shared<ButtonEvent>();
190 			buttonEvent->x = event->button.x;
191 			buttonEvent->y = event->button.y;
192 			switch(event->button.button) {
193 			case 1:
194 				buttonEvent->button = MouseButton::left;
195 				break;
196 			case 2:
197 				buttonEvent->button = MouseButton::middle;
198 				break;
199 			case 3:
200 				buttonEvent->button = MouseButton::right;
201 				break;
202 			default:
203 				WARN(X11, "Unknown button %d, setting to MouseButton::left\n",
204 				     event->button.button);
205 				buttonEvent->button = MouseButton::left;
206 				break;
207 			}
208 
209 			buttonEvent->direction =
210 				(event->type == PUGL_BUTTON_PRESS) ?
211 				Direction::down : Direction::up;
212 
213 			buttonEvent->doubleClick =
214 				(event->type == PUGL_BUTTON_PRESS) &&
215 				((event->button.time - native->last_click) < 200);
216 
217 			if(event->type == PUGL_BUTTON_PRESS)
218 			{
219 				native->last_click = event->button.time;
220 			}
221 			native->event_queue.push_back(buttonEvent);
222 		}
223 		fprintf(stderr, "Mouse %d %s at %f,%f ",
224 		        event->button.button,
225 		        (event->type == PUGL_BUTTON_PRESS) ? "down" : "up",
226 		        event->button.x,
227 		        event->button.y);
228 		///printModifiers(view, event->scroll.state);
229 		break;
230 	case PUGL_SCROLL:
231 		{
232 			auto scrollEvent = std::make_shared<ScrollEvent>();
233 			scrollEvent->x = event->scroll.x;
234 			scrollEvent->y = event->scroll.y;
235 			scrollEvent->delta = event->scroll.dy * -1;//scroll * ((xevent.xbutton.button == 4) ? -1 : 1);
236 			native->event_queue.push_back(scrollEvent);
237 		}
238 		fprintf(stderr, "Scroll %f %f %f %f ",
239 		        event->scroll.x, event->scroll.y, event->scroll.dx, event->scroll.dy);
240 		//printModifiers(view, event->scroll.state);
241 		//dist += event->scroll.dy;
242 		//if (dist < 10.0f) {
243 		//	dist = 10.0f;
244 		//}
245 		puglPostRedisplay(view);
246 		break;
247 	case PUGL_ENTER_NOTIFY:
248 		fprintf(stderr, "Entered\n");
249 		break;
250 	case PUGL_LEAVE_NOTIFY:
251 		fprintf(stderr, "Exited\n");
252 		break;
253 	case PUGL_FOCUS_IN:
254 		fprintf(stderr, "Focus in\n");
255 		break;
256 	case PUGL_FOCUS_OUT:
257 		fprintf(stderr, "Focus out\n");
258 		break;
259 	}
260 }
261 
onReshape(PuglView * view,int width,int height)262 void NativeWindowPugl::onReshape(PuglView* view, int width, int height)
263 {
264 	glMatrixMode(GL_PROJECTION);
265 	glLoadIdentity();
266 	glViewport(0, 0, width, height);
267 }
268 
onDisplay(PuglView * view)269 void NativeWindowPugl::onDisplay(PuglView* view)
270 {
271 	NativeWindowPugl* native = (NativeWindowPugl*)puglGetHandle(view);
272 	Window& window = native->window;
273 	//window.redraw();
274 
275 	if((window.wpixbuf.width < 16) || (window.wpixbuf.height < 16))
276 	{
277 		return;
278 	}
279 
280 	puglEnterContext(view);
281 
282 	glDisable(GL_DEPTH_TEST);
283 	glClear(GL_COLOR_BUFFER_BIT);
284 
285 	glMatrixMode(GL_MODELVIEW);
286 	glLoadIdentity();
287 	glTranslatef(0.0f, 0.0f, 0.0f);
288 
289 	GLuint image;
290 
291 	glGenTextures(1, &image);
292 
293 	//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
294 	//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
295 
296 	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
297 	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
298 	glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE, GL_REPLACE);
299 
300 	glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
301 	glTexImage2D(GL_TEXTURE_2D,
302 	             0, GL_RGBA,
303 	             window.wpixbuf.width,
304 	             window.wpixbuf.height,
305 	             0, GL_RGB, GL_UNSIGNED_BYTE,
306 	             window.wpixbuf.buf);
307 
308 	glEnable(GL_TEXTURE_2D);
309 
310 	glBegin(GL_QUADS);
311 	glTexCoord2d(0.0f,  0.0f); glVertex2f(-1.0f, -1.0f);
312 	glTexCoord2d(0.0f, -1.0f); glVertex2f(-1.0f,  1.0f);
313 	glTexCoord2d(1.0f, -1.0f); glVertex2f( 1.0f,  1.0f);
314 	glTexCoord2d(1.0f,  0.0f); glVertex2f( 1.0f, -1.0f);
315 	glEnd();
316 
317 	glDeleteTextures(1, &image);
318 	glDisable(GL_TEXTURE_2D);
319 	glFlush();
320 
321 	puglLeaveContext(view, true);
322 }
323 
onMouse(PuglView * view,int button,bool press,int x,int y)324 void NativeWindowPugl::onMouse(PuglView* view, int button, bool press, int x, int y)
325 {
326 	NativeWindowPugl* native = (NativeWindowPugl*)puglGetHandle(view);
327 
328 	DEBUG(nativewindow_pugl, "Mouse %d %s at (%d,%d)\n", button,
329 	      press? "down":"up", x, y);
330 
331 	ButtonEvent* e = new ButtonEvent();
332 	e->x = x;
333 	e->y = y;
334 
335 	switch(button) {
336 	case 1:
337 		e->button = MouseButton::left;
338 		break;
339 	case 2:
340 		e->button = MouseButton::middle;
341 		break;
342 	case 3:
343 	default:
344 		e->button = MouseButton::right;
345 		break;
346 	}
347 
348 	e->direction = press ? Direction::down : Direction::up;
349 	e->doubleClick = false;
350 
351 	native->eventq.push_back(e);
352 }
353 
onKeyboard(PuglView * view,bool press,uint32_t key)354 void NativeWindowPugl::onKeyboard(PuglView* view, bool press, uint32_t key)
355 {
356 	NativeWindowPugl* native = (NativeWindowPugl*)puglGetHandle(view);
357 
358 	KeyEvent* e = new KeyEvent();
359 	e->direction = press ? Direction::down : Direction::up;
360 
361 	switch(key)
362 	{
363 	case PUGL_KEY_LEFT: e->keycode = Key::left; break;
364 	case PUGL_KEY_RIGHT: e->keycode = Key::right; break;
365 	case PUGL_KEY_UP: e->keycode = Key::up; break;
366 	case PUGL_KEY_DOWN: e->keycode = Key::down; break;
367 	case PUGL_KEY_PAGE_UP: e->keycode = Key::pageDown; break;
368 	case PUGL_KEY_PAGE_DOWN: e->keycode = Key::pageUp; break;
369 	default: e->keycode = Key::unknown; break;
370 	}
371 
372 	// TODO: perform character type check
373 	if(e->keycode == Key::unknown)
374 	{
375 		e->keycode = Key::character;
376 		e->text.assign(1, (char)key);
377 	}
378 
379 	native->eventq.push_back(e);
380 }
381 
382 } // GUI::
383