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