1 /* Window.cpp
2  * Copyright (C) 2018, 2019 by Sven Jähnichen
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 3, or (at your option)
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17  */
18 
19 #ifdef PKG_HAVE_FONTCONFIG
20 #include <fontconfig/fontconfig.h>
21 #endif /*PKG_HAVE_FONTCONFIG*/
22 
23 #include "Window.hpp"
24 #include "Focusable.hpp"
25 
26 namespace BWidgets
27 {
28 
Window()29 Window::Window () : Window (BWIDGETS_DEFAULT_WIDTH, BWIDGETS_DEFAULT_HEIGHT, "window", 0) {}
30 
Window(const double width,const double height,const std::string & title,PuglNativeView nativeWindow,bool resizable,PuglWorldType worldType,int worldFlag)31 Window::Window (const double width, const double height, const std::string& title, PuglNativeView nativeWindow, bool resizable,
32 		PuglWorldType worldType, int worldFlag) :
33 		Widget (0.0, 0.0, width, height, title),
34 		keyGrabStack_ (), buttonGrabStack_ (),
35 		title_ (title), world_ (NULL), view_ (NULL), nativeWindow_ (nativeWindow),
36 		quit_ (false), focused_ (false), pointer_ (),
37 		eventQueue_ ()
38 {
39 	main_ = this;
40 
41 	world_ = puglNewWorld (worldType, worldFlag);
42 	puglSetClassName (world_, "BWidgets");
43 
44 	view_ = puglNewView (world_);
45 	if (nativeWindow_ != 0) puglSetParentWindow(view_, nativeWindow_);
46 	puglSetWindowTitle(view_, title.c_str());
47 	puglSetDefaultSize (view_, getWidth (), getHeight ());
48 	puglSetViewHint(view_, PUGL_RESIZABLE, resizable ? PUGL_TRUE : PUGL_FALSE);
49 	puglSetViewHint(view_, PUGL_IGNORE_KEY_REPEAT, PUGL_TRUE);
50 	puglSetWorldHandle(world_, this);
51 	puglSetHandle (view_, this);
52 	puglSetBackend(view_, puglCairoBackend());
53 	puglSetEventFunc (view_, Window::translatePuglEvent);
54 	puglRealize (view_);
55 	puglShow (view_);
56 
57 	background_ = (BWIDGETS_DEFAULT_WINDOW_BACKGROUND);
58 	postRedisplay();
59 }
60 
~Window()61 Window::~Window ()
62 {
63 	hide();
64 	while (!children_.empty ())
65 	{
66 		Widget* w = children_.front ();
67 		if (w) release (w);
68 	}
69 	purgeEventQueue ();
70 	keyGrabStack_.clear ();
71 	buttonGrabStack_.clear ();
72 	puglFreeView (view_);
73 	puglFreeWorld (world_);
74 	main_ = nullptr;	// Important switch for the super destructor. It took
75 				// days of debugging ...
76 
77 	// Cleanup debug information for memory checkers
78 	//cairo_debug_reset_static_data();
79 #ifdef PKG_HAVE_FONTCONFIG
80 	//FcFini();
81 #endif /*PKG_HAVE_FONTCONFIG*/
82 }
83 
getPuglView()84 PuglView* Window::getPuglView () {return view_;}
85 
getPuglContext()86 cairo_t* Window::getPuglContext ()
87 {
88 	if (view_) return (cairo_t*) puglGetContext (view_);
89 	else return NULL;
90 }
91 
run()92 void Window::run ()
93 {
94 	while (!quit_) handleEvents();
95 }
96 
onConfigureRequest(BEvents::ExposeEvent * event)97 void Window::onConfigureRequest (BEvents::ExposeEvent* event)
98 {
99 	if (getExtends () != event->getArea().getExtends ()) Widget::resize (event->getArea().getExtends ());
100 }
101 
onCloseRequest(BEvents::WidgetEvent * event)102 void Window::onCloseRequest (BEvents::WidgetEvent* event)
103 {
104 	if ((event) && (event->getRequestWidget () == this)) quit_ = true;
105 	else Widget::onCloseRequest (event);
106 }
107 
onExposeRequest(BEvents::ExposeEvent * event)108 void Window::onExposeRequest (BEvents::ExposeEvent* event)
109 {
110 	if (event)
111 	{
112 		BEvents::ExposeEvent* ee = (BEvents::ExposeEvent*)event;
113 		puglPostRedisplayRect (view_, {ee->getArea().getX(), ee->getArea().getY(), ee->getArea().getWidth(), ee->getArea().getHeight()});
114 	}
115 }
116 
addEventToQueue(BEvents::Event * event)117 void Window::addEventToQueue (BEvents::Event* event)
118 {
119 	// Try to merge with precursor event
120 	if
121 	(
122 		(event) &&
123 		(event->getWidget()) &&
124 		(!eventQueue_.empty ()) &&
125 		(eventQueue_.back())
126 	)
127 	{
128 		BEvents::EventType eventType = event->getEventType();
129 
130 		if
131 		(
132 			(event->getWidget ()->isMergeable(eventType)) &&
133 			(
134 				(eventType == BEvents::CONFIGURE_REQUEST_EVENT) ||
135 				(eventType == BEvents::EXPOSE_REQUEST_EVENT) ||
136 				(eventType == BEvents::POINTER_MOTION_EVENT) ||
137 				(eventType == BEvents::POINTER_DRAG_EVENT) ||
138 				(eventType == BEvents::WHEEL_SCROLL_EVENT) ||
139 				(eventType == BEvents::VALUE_CHANGED_EVENT)
140 			)
141 		)
142 		{
143 			// Check for mergeable precursor events
144 			for (std::deque<BEvents::Event*>::reverse_iterator rit = eventQueue_.rbegin(); rit != eventQueue_.rend(); ++rit)
145 			{
146 				BEvents::Event* precursor = *rit;
147 
148 				if ((precursor->getEventType() == eventType) && (event->getWidget () == precursor->getWidget ()))
149 				{
150 					// CONFIGURE_EVENT
151 					if (eventType == BEvents::CONFIGURE_REQUEST_EVENT)
152 					{
153 						BEvents::ExposeEvent* firstEvent = (BEvents::ExposeEvent*) precursor;
154 						BEvents::ExposeEvent* nextEvent = (BEvents::ExposeEvent*) event;
155 
156 						BUtilities::RectArea area = nextEvent->getArea ();
157 						firstEvent->setArea (area);
158 
159 						delete event;
160 						return;
161 					}
162 
163 					// EXPOSE_EVENT
164 					if (eventType == BEvents::EXPOSE_REQUEST_EVENT)
165 					{
166 						BEvents::ExposeEvent* firstEvent = (BEvents::ExposeEvent*) precursor;
167 						BEvents::ExposeEvent* nextEvent = (BEvents::ExposeEvent*) event;
168 
169 						BUtilities::RectArea area = firstEvent->getArea ();
170 						area.extend (nextEvent->getArea ());
171 						firstEvent->setArea (area);
172 
173 						delete event;
174 						return;
175 					}
176 
177 
178 					// POINTER_MOTION_EVENT
179 					else if (eventType == BEvents::POINTER_MOTION_EVENT)
180 					{
181 						BEvents::PointerEvent* firstEvent = (BEvents::PointerEvent*) precursor;
182 						BEvents::PointerEvent* nextEvent = (BEvents::PointerEvent*) event;
183 
184 						firstEvent->setPosition (nextEvent->getPosition ());
185 						firstEvent->setDelta (firstEvent->getDelta () + nextEvent->getDelta ());
186 
187 						delete event;
188 						return;
189 					}
190 
191 					// POINTER_DRAG_EVENT
192 					else if (eventType == BEvents::POINTER_DRAG_EVENT)
193 					{
194 						BEvents::PointerEvent* firstEvent = (BEvents::PointerEvent*) precursor;
195 						BEvents::PointerEvent* nextEvent = (BEvents::PointerEvent*) event;
196 
197 						if
198 						(
199 							(nextEvent->getButton() == firstEvent->getButton()) &&
200 							(nextEvent->getOrigin() == firstEvent->getOrigin())
201 						)
202 						{
203 							firstEvent->setPosition (nextEvent->getPosition ());
204 							firstEvent->setDelta (firstEvent->getDelta () + nextEvent->getDelta ());
205 
206 							delete event;
207 							return;
208 						}
209 					}
210 
211 
212 					// WHEEL_SCROLL_EVENT
213 					else if (eventType == BEvents::WHEEL_SCROLL_EVENT)
214 					{
215 						BEvents::WheelEvent* firstEvent = (BEvents::WheelEvent*) precursor;
216 						BEvents::WheelEvent* nextEvent = (BEvents::WheelEvent*) event;
217 
218 						if (nextEvent->getPosition() == firstEvent->getPosition())
219 						{
220 							firstEvent->setDelta (firstEvent->getDelta () + nextEvent->getDelta ());
221 
222 							delete event;
223 							return;
224 						}
225 					}
226 
227 					// VALUE_CHANGED_EVENT
228 					else if (eventType == BEvents::VALUE_CHANGED_EVENT)
229 					{
230 						BEvents::ValueChangedEvent* firstEvent = (BEvents::ValueChangedEvent*) precursor;
231 						BEvents::ValueChangedEvent* nextEvent = (BEvents::ValueChangedEvent*) event;
232 
233 						firstEvent->setValue (nextEvent->getValue());
234 						delete event;
235 						return;
236 					}
237 				}
238 			}
239 		}
240 	}
241 
242 	eventQueue_.push_back (event);
243 }
244 
getKeyGrabStack()245 BDevices::DeviceGrabStack<uint32_t>* Window::getKeyGrabStack () {return &keyGrabStack_;}
246 
getButtonGrabStack()247 BDevices::DeviceGrabStack<BDevices::MouseDevice>* Window::getButtonGrabStack () {return &buttonGrabStack_;}
248 
handleEvents()249 void Window::handleEvents ()
250 {
251 	puglUpdate (world_, 0);
252 	translateTimeEvent ();
253 
254 	while (!eventQueue_.empty ())
255 	{
256 		BEvents::Event* event = eventQueue_.front ();
257 		eventQueue_.pop_front ();
258 
259 		if (event)
260 		{
261 			Widget* widget = event->getWidget ();
262 			if (widget)
263 			{
264 				BEvents::EventType eventType = event->getEventType ();
265 
266 				switch (eventType)
267 				{
268 				case BEvents::CONFIGURE_REQUEST_EVENT:
269 					widget->onConfigureRequest ((BEvents::ExposeEvent*) event);
270 					break;
271 
272 				// Expose events: Forward to pugl!
273 				case BEvents::EXPOSE_REQUEST_EVENT:
274 					widget->onExposeRequest ((BEvents::ExposeEvent*) event);
275 					break;
276 
277 				case BEvents::CLOSE_REQUEST_EVENT:
278 					widget->onCloseRequest ((BEvents::WidgetEvent*) event);
279 					break;
280 
281 				case BEvents::KEY_PRESS_EVENT:
282 					buttonGrabStack_.remove (BDevices::MouseDevice (BDevices::NO_BUTTON));
283 					widget->onKeyPressed ((BEvents::KeyEvent*) event);
284 					break;
285 
286 				case BEvents::KEY_RELEASE_EVENT:
287 					buttonGrabStack_.remove (BDevices::MouseDevice (BDevices::NO_BUTTON));
288 					widget->onKeyReleased ((BEvents::KeyEvent*) event);
289 					break;
290 
291 				case BEvents::BUTTON_PRESS_EVENT:
292 					{
293 						BEvents::PointerEvent* be = (BEvents::PointerEvent*) event;
294 						unfocus();
295 						buttonGrabStack_.remove (BDevices::MouseDevice (BDevices::NO_BUTTON));
296 						buttonGrabStack_.add
297 						(
298 							BDevices::DeviceGrab<BDevices::MouseDevice>
299 							(
300 								widget,
301 								BDevices::MouseDevice(be->getButton (), be->getPosition())
302 							)
303 						);
304 						widget->onButtonPressed (be);
305 					}
306 					break;
307 
308 				case BEvents::BUTTON_RELEASE_EVENT:
309 					{
310 						BEvents::PointerEvent* be = (BEvents::PointerEvent*) event;
311 						unfocus ();
312 						buttonGrabStack_.remove (BDevices::MouseDevice (BDevices::NO_BUTTON));
313 						buttonGrabStack_.remove
314 						(
315 							BDevices::DeviceGrab<BDevices::MouseDevice>
316 							(
317 								widget,
318 								BDevices::MouseDevice(be->getButton (), be->getPosition())
319 							)
320 						);
321 						widget->onButtonReleased (be);
322 					}
323 					break;
324 
325 				case BEvents::BUTTON_CLICK_EVENT:
326 					{
327 						BEvents::PointerEvent* be = (BEvents::PointerEvent*) event;
328 						unfocus ();
329 						buttonGrabStack_.remove (BDevices::MouseDevice (BDevices::NO_BUTTON));
330 						buttonGrabStack_.remove
331 						(
332 							BDevices::DeviceGrab<BDevices::MouseDevice>
333 							(
334 								widget,
335 								BDevices::MouseDevice(be->getButton (), be->getPosition())
336 							)
337 						);
338 						widget->onButtonClicked (be);
339 					}
340 					break;
341 
342 				case BEvents::POINTER_MOTION_EVENT:
343 					{
344 						BEvents::PointerEvent* be = (BEvents::PointerEvent*) event;
345 						unfocus ();
346 						buttonGrabStack_.remove (BDevices::MouseDevice (BDevices::NO_BUTTON));
347 						BUtilities::Point p = widget->getAbsolutePosition() + be->getPosition();
348 						Widget* w = getWidgetAt (p, [] (Widget* f) {return f->isVisible() && f->isFocusable();});
349 						if (w)
350 						{
351 							buttonGrabStack_.add
352 							(
353 								BDevices::DeviceGrab<BDevices::MouseDevice>
354 								(
355 									w,
356 									BDevices::MouseDevice(BDevices::NO_BUTTON, p - w->getAbsolutePosition())
357 								)
358 							);
359 						}
360 						widget->onPointerMotion (be);
361 					}
362 					break;
363 
364 				case BEvents::POINTER_DRAG_EVENT:
365 					unfocus ();
366 					buttonGrabStack_.remove (BDevices::MouseDevice (BDevices::NO_BUTTON));
367 					widget->onPointerDragged((BEvents::PointerEvent*) event);
368 					break;
369 
370 				case BEvents::WHEEL_SCROLL_EVENT:
371 					unfocus ();
372 					buttonGrabStack_.remove (BDevices::MouseDevice (BDevices::NO_BUTTON));
373 					widget->onWheelScrolled((BEvents::WheelEvent*) event);
374 					break;
375 
376 				case BEvents::VALUE_CHANGED_EVENT:
377 					widget->onValueChanged((BEvents::ValueChangedEvent*) event);
378 					break;
379 
380 				case BEvents::FOCUS_IN_EVENT:
381 					widget->onFocusIn((BEvents::FocusEvent*) event);
382 					break;
383 
384 				case BEvents::FOCUS_OUT_EVENT:
385 					widget->onFocusOut((BEvents::FocusEvent*) event);
386 					break;
387 
388 				case BEvents::MESSAGE_EVENT:
389 					widget->onMessage ((BEvents::MessageEvent*) event);
390 					break;
391 
392 				default:
393 					break;
394 				}
395 
396 			}
397 			delete event;
398 		}
399 	}
400 }
401 
translatePuglEvent(PuglView * view,const PuglEvent * puglEvent)402 PuglStatus Window::translatePuglEvent (PuglView* view, const PuglEvent* puglEvent)
403 {
404 	Window* w = (Window*) puglGetHandle (view);
405 	if (!w) return PUGL_BAD_PARAMETER;
406 
407 	switch (puglEvent->type) {
408 
409 	case PUGL_KEY_PRESS:
410 		{
411 			if ((puglEvent->key.key >= PUGL_KEY_F1) && (puglEvent->key.key <= PUGL_KEY_PAUSE))
412 			{
413 				uint32_t key = puglEvent->key.key;
414 				BDevices::DeviceGrab<uint32_t>* grab = w->getKeyGrabStack()->getGrab(key);
415 				Widget* widget = (grab ? grab->getWidget() : nullptr);
416 				w->addEventToQueue
417 				(
418 					new BEvents::KeyEvent
419 					(
420 						widget,
421 						BEvents::KEY_PRESS_EVENT,
422 						puglEvent->key.x,
423 						puglEvent->key.y,
424 						key
425 					)
426 				);
427 			}
428 		}
429 		break;
430 
431 	case PUGL_KEY_RELEASE:
432 		{
433 			if ((puglEvent->key.key >= PUGL_KEY_F1) && (puglEvent->key.key <= PUGL_KEY_PAUSE))
434 			{
435 				uint32_t key = puglEvent->key.key;
436 				BDevices::DeviceGrab<uint32_t>* grab = w->getKeyGrabStack()->getGrab(key);
437 				Widget* widget = (grab ? grab->getWidget() : nullptr);
438 				w->addEventToQueue
439 				(
440 					new BEvents::KeyEvent
441 					(
442 						widget,
443 						BEvents::KEY_RELEASE_EVENT,
444 						puglEvent->key.x,
445 						puglEvent->key.y,
446 						key
447 					)
448 				);
449 			}
450 		}
451 		break;
452 
453 		case PUGL_TEXT:
454 			{
455 				uint32_t key = puglEvent->text.character;
456 				BDevices::DeviceGrab<uint32_t>* grab = w->getKeyGrabStack()->getGrab(key);
457 				Widget* widget = (grab ? grab->getWidget() : nullptr);
458 				w->addEventToQueue
459 				(
460 					new BEvents::KeyEvent
461 					(
462 						widget,
463 						BEvents::KEY_PRESS_EVENT,
464 						puglEvent->text.x,
465 						puglEvent->text.y,
466 						key
467 					)
468 				);
469 			}
470 			break;
471 
472 		case PUGL_BUTTON_PRESS:
473 		{
474 			BUtilities::Point position = BUtilities::Point (puglEvent->button.x, puglEvent->button.y);
475 			Widget* widget = w->getWidgetAt (position, [] (Widget* w) {return w->isVisible () && w->isClickable ();});
476 			if (widget)
477 			{
478 				w->addEventToQueue
479 				(
480 					new BEvents::PointerEvent
481 					(
482 						widget,
483 						BEvents::BUTTON_PRESS_EVENT,
484 						position - widget->getAbsolutePosition (),
485 						position - widget->getAbsolutePosition (),
486 						BUtilities::Point (),
487 						(BDevices::ButtonCode) puglEvent->button.button
488 					)
489 				);
490 			}
491 			w->pointer_ = position;
492 		}
493 		break;
494 
495 	case PUGL_BUTTON_RELEASE:
496 		{
497 			BUtilities::Point position = BUtilities::Point (puglEvent->button.x, puglEvent->button.y);
498 			BDevices::ButtonCode button = (BDevices::ButtonCode) puglEvent->button.button;
499 			BDevices::MouseDevice mouse = BDevices::MouseDevice (button);
500 			BDevices::DeviceGrab<BDevices::MouseDevice>* grab = w->getButtonGrabStack()->getGrab(mouse);
501 			if (grab)
502 			{
503 				Widget* widget = grab->getWidget();
504 				if (widget)
505 				{
506 					std::set<BDevices::MouseDevice> buttonDevices = grab->getDevices();
507 					std::set<BDevices::MouseDevice>::iterator it = buttonDevices.find(mouse);
508 					BUtilities::Point origin = (it != buttonDevices.end() ? it->position : BUtilities::Point ());
509 
510 					w->addEventToQueue
511 					(
512 						new BEvents::PointerEvent
513 						(
514 							widget,
515 							BEvents::BUTTON_RELEASE_EVENT,
516 							position - widget->getAbsolutePosition (),
517 							origin,
518 							BUtilities::Point (),
519 							button
520 						)
521 					);
522 
523 
524 					// Also emit BUTTON_CLICK_EVENT ?
525 					Widget* widget2 = w->getWidgetAt (position, [] (Widget* w) {return w->isVisible () && w->isClickable ();});
526 					if (widget == widget2)
527 					{
528 						w->addEventToQueue
529 						(
530 							new BEvents::PointerEvent
531 							(
532 								widget,
533 								BEvents::BUTTON_CLICK_EVENT,
534 								position - widget->getAbsolutePosition (),
535 								origin,
536 								BUtilities::Point (),
537 								button
538 							)
539 						);
540 					}
541 				}
542 			}
543 			w->pointer_ = position;
544 		}
545 		break;
546 
547 	case PUGL_MOTION:
548 		{
549 			BUtilities::Point position = BUtilities::Point (puglEvent->motion.x, puglEvent->motion.y);
550 			BDevices::ButtonCode button = BDevices::NO_BUTTON;
551 
552 			// Scan for pressed buttons associated with a widget
553 			for (int i = BDevices::NO_BUTTON + 1; i < BDevices::NR_OF_BUTTONS; ++i)
554 			{
555 				BDevices::ButtonCode b = BDevices::ButtonCode (i);
556 				BDevices::MouseDevice mouse = BDevices::MouseDevice (b);
557 				BDevices::DeviceGrab<BDevices::MouseDevice>* grab = w->getButtonGrabStack()->getGrab(mouse);
558 
559 				if (grab)
560 				{
561 					button = b;
562 					Widget* widget = grab->getWidget();
563 
564 					if (widget && widget->isDraggable())
565 					{
566 						std::set<BDevices::MouseDevice> buttonDevices = grab->getDevices();
567 						std::set<BDevices::MouseDevice>::iterator it = buttonDevices.find(mouse);
568 						BUtilities::Point origin = (it != buttonDevices.end() ? it->position : BUtilities::Point ());
569 
570 						// new
571 						w->addEventToQueue
572 						(
573 							new BEvents::PointerEvent
574 							(
575 								widget,
576 								BEvents::POINTER_DRAG_EVENT,
577 								position - widget->getAbsolutePosition (),
578 								origin,
579 								position - w->pointer_,
580 								button
581 							)
582 						);
583 					}
584 				}
585 			}
586 			// No button associated with a widget? Only POINTER_MOTION_EVENT
587 			if (button == BDevices::NO_BUTTON)
588 			{
589 				Widget* widget = w->getWidgetAt (position, BWidgets::isVisible);
590 				if (widget)
591 				{
592 					w->addEventToQueue
593 					(
594 						new BEvents::PointerEvent
595 						(
596 							widget,
597 							BEvents::POINTER_MOTION_EVENT,
598 							position - widget->getAbsolutePosition (),
599 							BUtilities::Point (),
600 							position - w->pointer_,
601 							button));
602 				}
603 			}
604 			w->pointer_ = position;
605 		}
606 		break;
607 
608 	case PUGL_SCROLL:
609 		{
610 			BUtilities::Point position = BUtilities::Point (puglEvent->scroll.x, puglEvent->scroll.y);
611 			BUtilities::Point scroll = BUtilities::Point (puglEvent->scroll.dx, puglEvent->scroll.dy);
612 			Widget* widget = w->getWidgetAt (position, [] (Widget* wid) {return wid->isVisible() && wid->isScrollable();});
613 			if (widget)
614 			{
615 				w->addEventToQueue
616 				(
617 					new BEvents::WheelEvent
618 					(
619 						widget,
620 						BEvents::WHEEL_SCROLL_EVENT,
621 						position - widget->getAbsolutePosition (),
622 						scroll
623 					)
624 				);
625 			}
626 			w->pointer_ = position;
627 		}
628 		break;
629 
630 	case PUGL_CONFIGURE:
631 		w->addEventToQueue
632 		(
633 			new BEvents::ExposeEvent
634 			(
635 				w, w,
636 				BEvents::CONFIGURE_REQUEST_EVENT,
637 				puglEvent->configure.x,
638 				puglEvent->configure.y,
639 				puglEvent->configure.width,
640 				puglEvent->configure.height
641 			)
642 		);
643 		break;
644 
645 	// Expose events handled HERE
646 	case PUGL_EXPOSE:
647 		{
648 			BUtilities::RectArea area = BUtilities::RectArea (puglEvent->expose.x, puglEvent->expose.y, puglEvent->expose.width, puglEvent->expose.height);
649 
650 			// Create a temporal storage surface and store all children surfaces on this
651 			cairo_surface_t* storageSurface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, w->getWidth(), w->getHeight());
652 			if (cairo_surface_status (storageSurface) == CAIRO_STATUS_SUCCESS)
653 			{
654 				w->redisplay (storageSurface, area);
655 
656 				// Copy storage surface onto pugl provided surface
657 				cairo_t* cr = w->getPuglContext ();
658 				if (cairo_status (cr) == CAIRO_STATUS_SUCCESS)
659 				{
660 					cairo_save (cr);
661 					cairo_set_source_surface (cr, storageSurface, 0, 0);
662 					cairo_paint (cr);
663 					cairo_restore (cr);
664 				}
665 			}
666 			cairo_surface_destroy (storageSurface);
667 		}
668 		break;
669 
670 	case PUGL_CLOSE:
671 		w->addEventToQueue (new BEvents::WidgetEvent (w, w, BEvents::CLOSE_REQUEST_EVENT));
672 		break;
673 
674 	default:
675 		break;
676 	}
677 
678 	return PUGL_SUCCESS;
679 }
680 
translateTimeEvent()681 void Window::translateTimeEvent ()
682 {
683 	BDevices::MouseDevice mouse = BDevices::MouseDevice (BDevices::NO_BUTTON);
684 	BDevices::DeviceGrab<BDevices::MouseDevice>* grab = buttonGrabStack_.getGrab(mouse);
685 	if (grab)
686 	{
687 		Widget* widget = grab->getWidget();
688 		if (widget)
689 		{
690 			Focusable* focus = dynamic_cast<Focusable*> (widget);
691 			if (focus)
692 			{
693 				std::set<BDevices::MouseDevice> buttonDevices = grab->getDevices();
694 				std::set<BDevices::MouseDevice>::iterator it = buttonDevices.find(mouse);
695 				BUtilities::Point position = (it != buttonDevices.end() ? it->position : BUtilities::Point ());
696 				std::chrono::steady_clock::time_point nowTime = std::chrono::steady_clock::now();
697 				std::chrono::steady_clock::time_point pointerTime = (it != buttonDevices.end() ? it->getTime() : nowTime);
698 				std::chrono::milliseconds diffMs = std::chrono::duration_cast<std::chrono::milliseconds> (nowTime - pointerTime);
699 
700 				if ((!focused_) && focus->isFocusActive (diffMs))
701 				{
702 					addEventToQueue (new BEvents::FocusEvent (widget, BEvents::FOCUS_IN_EVENT, position));
703 					focused_ = true;
704 				}
705 
706 				else if (focused_ && (!focus->isFocusActive (diffMs)))
707 				{
708 					addEventToQueue (new BEvents::FocusEvent (widget, BEvents::FOCUS_OUT_EVENT, position));
709 					focused_ = false;
710 				}
711 			}
712 			else focused_ = false;
713 		}
714 		else focused_ = false;
715 	}
716 	else focused_ = false;
717 }
718 
unfocus()719 void Window::unfocus ()
720 {
721 	if (focused_)
722 	{
723 		BDevices::MouseDevice mouse = BDevices::MouseDevice (BDevices::NO_BUTTON);
724 		BDevices::DeviceGrab<BDevices::MouseDevice>* grab = buttonGrabStack_.getGrab (mouse);
725 		if (grab)
726 		{
727 			Widget* widget = grab->getWidget();
728 			if (widget)
729 			{
730 				Focusable* focus = dynamic_cast<Focusable*> (widget);
731 				if (focus)
732 				{
733 					std::set<BDevices::MouseDevice> buttonDevices = grab->getDevices();
734 					std::set<BDevices::MouseDevice>::iterator it = buttonDevices.find(mouse);
735 					BUtilities::Point position = (it != buttonDevices.end() ? it->position : BUtilities::Point ());
736 					addEventToQueue (new BEvents::FocusEvent (widget, BEvents::FOCUS_OUT_EVENT, position));
737 				}
738 			}
739 		}
740 		focused_ = false;
741 	}
742 }
743 
purgeEventQueue(Widget * widget)744 void Window::purgeEventQueue (Widget* widget)
745 {
746 	for (std::deque<BEvents::Event*>::iterator it = eventQueue_.begin (); it != eventQueue_.end (); )
747 	{
748 		BEvents::Event* event = *it;
749 		if
750 		(
751 			(event) &&
752 			(
753 				// Nullptr = joker
754 				(widget == nullptr) ||
755 				// Hit
756 				(widget == event->getWidget ()) ||
757 				(
758 					// Hit in request widgets
759 					(
760 						(event->getEventType () == BEvents::CONFIGURE_REQUEST_EVENT) ||
761 						(event->getEventType () == BEvents::EXPOSE_REQUEST_EVENT) ||
762 						(event->getEventType () == BEvents::CLOSE_REQUEST_EVENT)
763 					) &&
764 					(widget == ((BEvents::WidgetEvent*)event)->getRequestWidget ())
765 				)
766 			)
767 		)
768 		{
769 			it = eventQueue_.erase (it);
770 			delete event;
771 		}
772 		else ++it;
773 	}
774 }
775 
776 }
777