1 // Aseprite UI Library
2 // Copyright (C) 2001-2018 David Capello
3 //
4 // This file is released under the terms of the MIT license.
5 // Read LICENSE.txt for more information.
6
7 // #define REPORT_EVENTS
8 // #define REPORT_FOCUS_MOVEMENT
9 // #define DEBUG_PAINT_EVENTS
10 // #define LIMIT_DISPATCH_TIME
11 // #define DEBUG_UI_THREADS
12
13 #ifdef HAVE_CONFIG_H
14 #include "config.h"
15 #endif
16
17 #include "ui/manager.h"
18
19 #include "base/concurrent_queue.h"
20 #include "base/scoped_value.h"
21 #include "base/time.h"
22 #include "she/display.h"
23 #include "she/event.h"
24 #include "she/event_queue.h"
25 #include "she/surface.h"
26 #include "she/system.h"
27 #include "ui/intern.h"
28 #include "ui/ui.h"
29
30 #if defined(DEBUG_PAINT_EVENTS) || defined(DEBUG_UI_THREADS)
31 #include "base/thread.h"
32 #endif
33
34 #ifdef REPORT_EVENTS
35 #include <iostream>
36 #endif
37
38 #include <algorithm>
39 #include <limits>
40 #include <list>
41 #include <utility>
42 #include <vector>
43
44 namespace ui {
45
46 #define ACCEPT_FOCUS(widget) \
47 ((((widget)->flags() & (FOCUS_STOP | \
48 DISABLED | \
49 HIDDEN | \
50 DECORATIVE)) == FOCUS_STOP) && \
51 ((widget)->isVisible()))
52
53 static const int NFILTERS = (int)(kFirstRegisteredMessage+1);
54
55 struct Filter {
56 int message;
57 Widget* widget;
58
Filterui::Filter59 Filter(int message, Widget* widget)
60 : message(message)
61 , widget(widget) { }
62 };
63
64 typedef std::list<Message*> Messages;
65 typedef std::list<Filter*> Filters;
66
67 Manager* Manager::m_defaultManager = NULL;
68 gfx::Region Manager::m_dirtyRegion;
69
70 #ifdef DEBUG_UI_THREADS
71 static base::thread::native_handle_type manager_thread = 0;
72 #endif
73
74 static WidgetsList mouse_widgets_list; // List of widgets to send mouse events
75 static Messages msg_queue; // Messages queue
76 static base::concurrent_queue<Message*> concurrent_msg_queue;
77 static Filters msg_filters[NFILTERS]; // Filters for every enqueued message
78 static int filter_locks = 0;
79
80 static Widget* focus_widget; // The widget with the focus
81 static Widget* mouse_widget; // The widget with the mouse
82 static Widget* capture_widget; // The widget that captures the mouse
83
84 static bool first_time = true; // true when we don't enter in poll yet
85
86 // Don't adjust window positions automatically when it's false. Used
87 // when Screen/UI scaling is changed to avoid adjusting windows as
88 // when the she::Display is resized by the user.
89 static bool auto_window_adjustment = true;
90
91 /* keyboard focus movement stuff */
92 static int count_widgets_accept_focus(Widget* widget);
93 static bool child_accept_focus(Widget* widget, bool first);
94 static Widget* next_widget(Widget* widget);
95 static int cmp_left(Widget* widget, int x, int y);
96 static int cmp_right(Widget* widget, int x, int y);
97 static int cmp_up(Widget* widget, int x, int y);
98 static int cmp_down(Widget* widget, int x, int y);
99
100 namespace {
101
102 class LockFilters {
103 public:
LockFilters()104 LockFilters() {
105 ++filter_locks;
106 }
~LockFilters()107 ~LockFilters() {
108 ASSERT(filter_locks > 0);
109 --filter_locks;
110
111 if (filter_locks == 0) {
112 // Clear empty filters
113 for (Filters& msg_filter : msg_filters) {
114 for (auto it = msg_filter.begin(); it != msg_filter.end(); ) {
115 Filter* filter = *it;
116 if (filter->widget == nullptr) {
117 delete filter;
118 it = msg_filter.erase(it);
119 }
120 else {
121 ++it;
122 }
123 }
124 }
125 }
126 }
127 };
128
129 } // anonymous namespace
130
131 // static
widgetAssociatedToManager(Widget * widget)132 bool Manager::widgetAssociatedToManager(Widget* widget)
133 {
134 return (focus_widget == widget ||
135 mouse_widget == widget ||
136 capture_widget == widget ||
137 std::find(mouse_widgets_list.begin(),
138 mouse_widgets_list.end(),
139 widget) != mouse_widgets_list.end());
140 }
141
Manager()142 Manager::Manager()
143 : Widget(kManagerWidget)
144 , m_display(NULL)
145 , m_eventQueue(NULL)
146 , m_lockedWindow(NULL)
147 , m_mouseButtons(kButtonNone)
148 {
149 #ifdef DEBUG_UI_THREADS
150 ASSERT(!manager_thread);
151 manager_thread = base::this_thread::native_handle();
152 #endif
153
154 if (!m_defaultManager) {
155 // Empty lists
156 ASSERT(msg_queue.empty());
157 mouse_widgets_list.clear();
158
159 // Reset variables
160 focus_widget = NULL;
161 mouse_widget = NULL;
162 capture_widget = NULL;
163 }
164
165 setBounds(gfx::Rect(0, 0, ui::display_w(), ui::display_h()));
166 setVisible(true);
167
168 m_dirtyRegion = bounds();
169
170 // Default manager is the first one (and is always visible).
171 if (!m_defaultManager)
172 m_defaultManager = this;
173 }
174
~Manager()175 Manager::~Manager()
176 {
177 #ifdef DEBUG_UI_THREADS
178 ASSERT(manager_thread == base::this_thread::native_handle());
179 #endif
180
181 // There are some messages in queue? Dispatch everything.
182 dispatchMessages();
183 collectGarbage();
184
185 // Finish the main manager.
186 if (m_defaultManager == this) {
187 // No more cursor
188 set_mouse_cursor(kNoCursor);
189
190 // Destroy timers
191 Timer::checkNoTimers();
192
193 // Destroy filters
194 #ifdef _DEBUG
195 for (Filters& msg_filter : msg_filters)
196 ASSERT(msg_filter.empty());
197 #endif
198
199 // No more default manager
200 m_defaultManager = nullptr;
201
202 // Shutdown system
203 ASSERT(msg_queue.empty());
204 mouse_widgets_list.clear();
205 }
206 }
207
setDisplay(she::Display * display)208 void Manager::setDisplay(she::Display* display)
209 {
210 base::ScopedValue<bool> lock(
211 auto_window_adjustment, false,
212 auto_window_adjustment);
213
214 m_display = display;
215 m_eventQueue = she::instance()->eventQueue();
216
217 onNewDisplayConfiguration();
218 }
219
run()220 void Manager::run()
221 {
222 MessageLoop loop(this);
223
224 if (first_time) {
225 first_time = false;
226
227 Manager::getDefault()->invalidate();
228 set_mouse_cursor(kArrowCursor);
229 }
230
231 while (!children().empty())
232 loop.pumpMessages();
233 }
234
flipDisplay()235 void Manager::flipDisplay()
236 {
237 if (!m_display)
238 return;
239
240 OverlayManager* overlays = OverlayManager::instance();
241
242 update_cursor_overlay();
243
244 // Draw overlays.
245 overlays->captureOverlappedAreas();
246 overlays->drawOverlays();
247
248 // Flip dirty region.
249 {
250 m_dirtyRegion.createIntersection(
251 m_dirtyRegion,
252 gfx::Region(gfx::Rect(0, 0, ui::display_w(), ui::display_h())));
253
254 for (auto& rc : m_dirtyRegion)
255 m_display->flip(rc);
256
257 m_dirtyRegion.clear();
258 }
259
260 overlays->restoreOverlappedAreas();
261 }
262
generateMessages()263 bool Manager::generateMessages()
264 {
265 // First check: there are windows to manage?
266 if (children().empty())
267 return false;
268
269 // Generate messages from other threads
270 if (!concurrent_msg_queue.empty()) {
271 Message* msg = nullptr;
272 while (concurrent_msg_queue.try_pop(msg))
273 msg_queue.push_back(msg);
274 }
275
276 // Generate messages from OS input
277 generateMessagesFromSheEvents();
278
279 // Generate messages for timers
280 Timer::pollTimers();
281
282 if (!msg_queue.empty())
283 return true;
284 else
285 return false;
286 }
287
generateSetCursorMessage(const gfx::Point & mousePos,KeyModifiers modifiers,PointerType pointerType)288 void Manager::generateSetCursorMessage(const gfx::Point& mousePos,
289 KeyModifiers modifiers,
290 PointerType pointerType)
291 {
292 if (get_mouse_cursor() == kOutsideDisplay)
293 return;
294
295 Widget* dst = (capture_widget ? capture_widget: mouse_widget);
296 if (dst)
297 enqueueMessage(
298 newMouseMessage(
299 kSetCursorMessage, dst,
300 mousePos,
301 pointerType,
302 _internal_get_mouse_buttons(),
303 modifiers));
304 else
305 set_mouse_cursor(kArrowCursor);
306 }
307
mouse_buttons_from_she_to_ui(const she::Event & sheEvent)308 static MouseButtons mouse_buttons_from_she_to_ui(const she::Event& sheEvent)
309 {
310 switch (sheEvent.button()) {
311 case she::Event::LeftButton: return kButtonLeft; break;
312 case she::Event::RightButton: return kButtonRight; break;
313 case she::Event::MiddleButton: return kButtonMiddle; break;
314 case she::Event::X1Button: return kButtonX1; break;
315 case she::Event::X2Button: return kButtonX2; break;
316 default: return kButtonNone;
317 }
318 }
319
generateMessagesFromSheEvents()320 void Manager::generateMessagesFromSheEvents()
321 {
322 she::Event lastMouseMoveEvent;
323
324 // Events from "she" layer.
325 she::Event sheEvent;
326 for (;;) {
327 // bool canWait = (msg_queue.empty());
328 bool canWait = false;
329
330 m_eventQueue->getEvent(sheEvent, canWait);
331 if (sheEvent.type() == she::Event::None)
332 break;
333
334 switch (sheEvent.type()) {
335
336 case she::Event::CloseDisplay: {
337 Message* msg = new Message(kCloseDisplayMessage);
338 msg->broadcastToChildren(this);
339 enqueueMessage(msg);
340 break;
341 }
342
343 case she::Event::ResizeDisplay: {
344 Message* msg = new Message(kResizeDisplayMessage);
345 msg->broadcastToChildren(this);
346 enqueueMessage(msg);
347 break;
348 }
349
350 case she::Event::DropFiles: {
351 Message* msg = new DropFilesMessage(sheEvent.files());
352 msg->addRecipient(this);
353 enqueueMessage(msg);
354 break;
355 }
356
357 case she::Event::KeyDown:
358 case she::Event::KeyUp: {
359 Message* msg = new KeyMessage(
360 (sheEvent.type() == she::Event::KeyDown ?
361 kKeyDownMessage:
362 kKeyUpMessage),
363 sheEvent.scancode(),
364 sheEvent.modifiers(),
365 sheEvent.unicodeChar(),
366 sheEvent.repeat());
367
368 if (sheEvent.isDeadKey())
369 static_cast<KeyMessage*>(msg)->setDeadKey(true);
370
371 broadcastKeyMsg(msg);
372 enqueueMessage(msg);
373 break;
374 }
375
376 case she::Event::MouseEnter: {
377 _internal_set_mouse_position(sheEvent.position());
378 set_mouse_cursor(kArrowCursor);
379 lastMouseMoveEvent = sheEvent;
380 break;
381 }
382
383 case she::Event::MouseLeave: {
384 set_mouse_cursor(kOutsideDisplay);
385 setMouse(NULL);
386
387 _internal_no_mouse_position();
388
389 // To avoid calling kSetCursorMessage when the mouse leaves
390 // the window.
391 lastMouseMoveEvent = she::Event();
392 break;
393 }
394
395 case she::Event::MouseMove: {
396 _internal_set_mouse_position(sheEvent.position());
397 handleMouseMove(
398 sheEvent.position(),
399 m_mouseButtons,
400 sheEvent.modifiers(),
401 sheEvent.pointerType());
402 lastMouseMoveEvent = sheEvent;
403 break;
404 }
405
406 case she::Event::MouseDown: {
407 MouseButtons pressedButton = mouse_buttons_from_she_to_ui(sheEvent);
408 m_mouseButtons = (MouseButtons)((int)m_mouseButtons | (int)pressedButton);
409 _internal_set_mouse_buttons(m_mouseButtons);
410
411 handleMouseDown(
412 sheEvent.position(),
413 pressedButton,
414 sheEvent.modifiers(),
415 sheEvent.pointerType());
416 break;
417 }
418
419 case she::Event::MouseUp: {
420 MouseButtons releasedButton = mouse_buttons_from_she_to_ui(sheEvent);
421 m_mouseButtons = (MouseButtons)((int)m_mouseButtons & ~(int)releasedButton);
422 _internal_set_mouse_buttons(m_mouseButtons);
423
424 handleMouseUp(
425 sheEvent.position(),
426 releasedButton,
427 sheEvent.modifiers(),
428 sheEvent.pointerType());
429 break;
430 }
431
432 case she::Event::MouseDoubleClick: {
433 MouseButtons clickedButton = mouse_buttons_from_she_to_ui(sheEvent);
434 handleMouseDoubleClick(
435 sheEvent.position(),
436 clickedButton,
437 sheEvent.modifiers(),
438 sheEvent.pointerType());
439 break;
440 }
441
442 case she::Event::MouseWheel: {
443 handleMouseWheel(sheEvent.position(), m_mouseButtons,
444 sheEvent.modifiers(),
445 sheEvent.pointerType(),
446 sheEvent.wheelDelta(),
447 sheEvent.preciseWheel());
448 break;
449 }
450
451 case she::Event::TouchMagnify: {
452 _internal_set_mouse_position(sheEvent.position());
453
454 handleTouchMagnify(sheEvent.position(),
455 sheEvent.modifiers(),
456 sheEvent.magnification());
457 break;
458 }
459
460 }
461 }
462
463 // Generate just one kSetCursorMessage for the last mouse position
464 if (lastMouseMoveEvent.type() != she::Event::None) {
465 sheEvent = lastMouseMoveEvent;
466 generateSetCursorMessage(sheEvent.position(),
467 sheEvent.modifiers(),
468 sheEvent.pointerType());
469 }
470 }
471
handleMouseMove(const gfx::Point & mousePos,MouseButtons mouseButtons,KeyModifiers modifiers,PointerType pointerType)472 void Manager::handleMouseMove(const gfx::Point& mousePos,
473 MouseButtons mouseButtons,
474 KeyModifiers modifiers,
475 PointerType pointerType)
476 {
477 // Get the list of widgets to send mouse messages.
478 mouse_widgets_list.clear();
479 broadcastMouseMessage(mouse_widgets_list);
480
481 // Get the widget under the mouse
482 Widget* widget = nullptr;
483 for (auto mouseWidget : mouse_widgets_list) {
484 widget = mouseWidget->pick(mousePos);
485 if (widget)
486 break;
487 }
488
489 // Fixup "mouse" flag
490 if (widget != mouse_widget) {
491 if (!widget)
492 freeMouse();
493 else
494 setMouse(widget);
495 }
496
497 // Send the mouse movement message
498 Widget* dst = (capture_widget ? capture_widget: mouse_widget);
499 enqueueMessage(
500 newMouseMessage(
501 kMouseMoveMessage, dst,
502 mousePos,
503 pointerType,
504 mouseButtons,
505 modifiers));
506 }
507
handleMouseDown(const gfx::Point & mousePos,MouseButtons mouseButtons,KeyModifiers modifiers,PointerType pointerType)508 void Manager::handleMouseDown(const gfx::Point& mousePos,
509 MouseButtons mouseButtons,
510 KeyModifiers modifiers,
511 PointerType pointerType)
512 {
513 handleWindowZOrder();
514
515 enqueueMessage(
516 newMouseMessage(
517 kMouseDownMessage,
518 (capture_widget ? capture_widget: mouse_widget),
519 mousePos,
520 pointerType,
521 mouseButtons,
522 modifiers));
523 }
524
handleMouseUp(const gfx::Point & mousePos,MouseButtons mouseButtons,KeyModifiers modifiers,PointerType pointerType)525 void Manager::handleMouseUp(const gfx::Point& mousePos,
526 MouseButtons mouseButtons,
527 KeyModifiers modifiers,
528 PointerType pointerType)
529 {
530 enqueueMessage(
531 newMouseMessage(
532 kMouseUpMessage,
533 (capture_widget ? capture_widget: mouse_widget),
534 mousePos,
535 pointerType,
536 mouseButtons,
537 modifiers));
538 }
539
handleMouseDoubleClick(const gfx::Point & mousePos,MouseButtons mouseButtons,KeyModifiers modifiers,PointerType pointerType)540 void Manager::handleMouseDoubleClick(const gfx::Point& mousePos,
541 MouseButtons mouseButtons,
542 KeyModifiers modifiers,
543 PointerType pointerType)
544 {
545 Widget* dst = (capture_widget ? capture_widget: mouse_widget);
546 if (dst) {
547 enqueueMessage(
548 newMouseMessage(
549 kDoubleClickMessage,
550 dst, mousePos, pointerType,
551 mouseButtons, modifiers));
552 }
553 }
554
handleMouseWheel(const gfx::Point & mousePos,MouseButtons mouseButtons,KeyModifiers modifiers,PointerType pointerType,const gfx::Point & wheelDelta,bool preciseWheel)555 void Manager::handleMouseWheel(const gfx::Point& mousePos,
556 MouseButtons mouseButtons,
557 KeyModifiers modifiers,
558 PointerType pointerType,
559 const gfx::Point& wheelDelta,
560 bool preciseWheel)
561 {
562 enqueueMessage(newMouseMessage(
563 kMouseWheelMessage,
564 (capture_widget ? capture_widget: mouse_widget),
565 mousePos, pointerType, mouseButtons, modifiers,
566 wheelDelta, preciseWheel));
567 }
568
handleTouchMagnify(const gfx::Point & mousePos,const KeyModifiers modifiers,const double magnification)569 void Manager::handleTouchMagnify(const gfx::Point& mousePos,
570 const KeyModifiers modifiers,
571 const double magnification)
572 {
573 Widget* widget = (capture_widget ? capture_widget: mouse_widget);
574 if (widget) {
575 Message* msg = new TouchMessage(
576 kTouchMagnifyMessage,
577 modifiers,
578 mousePos,
579 magnification);
580
581 msg->addRecipient(widget);
582
583 enqueueMessage(msg);
584 }
585 }
586
587 // Handles Z order: Send the window to top (only when you click in a
588 // window that aren't the desktop).
handleWindowZOrder()589 void Manager::handleWindowZOrder()
590 {
591 if (capture_widget || !mouse_widget)
592 return;
593
594 // The clicked window
595 Window* window = mouse_widget->window();
596 Manager* win_manager = (window ? window->manager(): NULL);
597
598 if ((window) &&
599 // We cannot change Z-order of desktop windows
600 (!window->isDesktop()) &&
601 // We cannot change Z order of foreground windows because a
602 // foreground window can launch other background windows
603 // which should be kept on top of the foreground one.
604 (!window->isForeground()) &&
605 // If the window is not already the top window of the manager.
606 (window != win_manager->getTopWindow())) {
607 base::ScopedValue<Widget*> scoped(m_lockedWindow, window, NULL);
608
609 // Put it in the top of the list
610 win_manager->removeChild(window);
611
612 if (window->isOnTop())
613 win_manager->insertChild(0, window);
614 else {
615 int pos = (int)win_manager->children().size();
616 UI_FOREACH_WIDGET_BACKWARD(win_manager->children(), it) {
617 if (static_cast<Window*>(*it)->isOnTop())
618 break;
619
620 --pos;
621 }
622 win_manager->insertChild(pos, window);
623 }
624
625 window->invalidate();
626 }
627
628 // Put the focus
629 setFocus(mouse_widget);
630 }
631
dispatchMessages()632 void Manager::dispatchMessages()
633 {
634 // Send messages in the queue (mouse/key/timer/etc. events) This
635 // might change the state of widgets, etc. In case pumpQueue()
636 // returns a number greater than 0, it means that we've processed
637 // some messages, so we've to redraw the screen.
638 if (pumpQueue() > 0) {
639 // Generate and send just kPaintMessages with the latest UI state.
640 flushRedraw();
641 pumpQueue();
642 }
643
644 // Flip the back-buffer to the real display.
645 flipDisplay();
646 }
647
addToGarbage(Widget * widget)648 void Manager::addToGarbage(Widget* widget)
649 {
650 m_garbage.push_back(widget);
651 }
652
enqueueMessage(Message * msg)653 void Manager::enqueueMessage(Message* msg)
654 {
655 ASSERT(msg);
656
657 if (is_ui_thread())
658 msg_queue.push_back(msg);
659 else
660 concurrent_msg_queue.push(msg);
661 }
662
getTopWindow()663 Window* Manager::getTopWindow()
664 {
665 return static_cast<Window*>(UI_FIRST_WIDGET(children()));
666 }
667
getForegroundWindow()668 Window* Manager::getForegroundWindow()
669 {
670 for (auto child : children()) {
671 Window* window = static_cast<Window*>(child);
672 if (window->isForeground() ||
673 window->isDesktop())
674 return window;
675 }
676 return nullptr;
677 }
678
getFocus()679 Widget* Manager::getFocus()
680 {
681 return focus_widget;
682 }
683
getMouse()684 Widget* Manager::getMouse()
685 {
686 return mouse_widget;
687 }
688
getCapture()689 Widget* Manager::getCapture()
690 {
691 return capture_widget;
692 }
693
setFocus(Widget * widget)694 void Manager::setFocus(Widget* widget)
695 {
696 if ((focus_widget != widget)
697 && (!(widget)
698 || (!(widget->hasFlags(DISABLED))
699 && !(widget->hasFlags(HIDDEN))
700 && !(widget->hasFlags(DECORATIVE))
701 && someParentIsFocusStop(widget)))) {
702 WidgetsList widget_parents;
703 Widget* common_parent = NULL;
704
705 if (widget)
706 widget->getParents(false, widget_parents);
707
708 // Fetch the focus
709 if (focus_widget) {
710 WidgetsList focus_parents;
711 focus_widget->getParents(true, focus_parents);
712
713 Message* msg = new Message(kFocusLeaveMessage);
714
715 for (Widget* parent1 : focus_parents) {
716 if (widget) {
717 for (Widget* parent2 : widget_parents) {
718 if (parent1 == parent2) {
719 common_parent = parent1;
720 break;
721 }
722 }
723 if (common_parent)
724 break;
725 }
726
727 if (parent1->hasFocus()) {
728 parent1->disableFlags(HAS_FOCUS);
729 msg->addRecipient(parent1);
730 }
731 }
732
733 enqueueMessage(msg);
734 }
735
736 // Put the focus
737 focus_widget = widget;
738 if (widget) {
739 WidgetsList::iterator it;
740
741 if (common_parent) {
742 it = std::find(widget_parents.begin(),
743 widget_parents.end(),
744 common_parent);
745 ASSERT(it != widget_parents.end());
746 ++it;
747 }
748 else
749 it = widget_parents.begin();
750
751 Message* msg = new Message(kFocusEnterMessage);
752
753 for (; it != widget_parents.end(); ++it) {
754 Widget* w = *it;
755
756 if (w->hasFlags(FOCUS_STOP)) {
757 w->enableFlags(HAS_FOCUS);
758 msg->addRecipient(w);
759 }
760 }
761
762 enqueueMessage(msg);
763 }
764 }
765 }
766
setMouse(Widget * widget)767 void Manager::setMouse(Widget* widget)
768 {
769 #ifdef REPORT_EVENTS
770 std::cout << "Manager::setMouse ";
771 if (widget) {
772 std::cout << typeid(*widget).name();
773 if (!widget->id().empty())
774 std::cout << " (" << widget->id() << ")";
775 }
776 else {
777 std::cout << "null";
778 }
779 std::cout << std::endl;
780 #endif
781
782 if ((mouse_widget != widget) && (!capture_widget)) {
783 WidgetsList widget_parents;
784 Widget* common_parent = NULL;
785
786 if (widget)
787 widget->getParents(false, widget_parents);
788
789 // Fetch the mouse
790 if (mouse_widget) {
791 WidgetsList mouse_parents;
792 mouse_widget->getParents(true, mouse_parents);
793
794 Message* msg = new Message(kMouseLeaveMessage);
795
796 for (Widget* parent1 : mouse_parents) {
797 if (widget) {
798 for (Widget* parent2 : widget_parents) {
799 if (parent1 == parent2) {
800 common_parent = parent1;
801 break;
802 }
803 }
804 if (common_parent)
805 break;
806 }
807
808 if (parent1->hasMouse()) {
809 parent1->disableFlags(HAS_MOUSE);
810 msg->addRecipient(parent1);
811 }
812 }
813
814 enqueueMessage(msg);
815 }
816
817 // Put the mouse
818 mouse_widget = widget;
819 if (widget) {
820 WidgetsList::iterator it;
821
822 if (common_parent) {
823 it = std::find(widget_parents.begin(),
824 widget_parents.end(),
825 common_parent);
826 ASSERT(it != widget_parents.end());
827 ++it;
828 }
829 else
830 it = widget_parents.begin();
831
832 Message* msg = newMouseMessage(
833 kMouseEnterMessage, NULL,
834 get_mouse_position(),
835 PointerType::Unknown,
836 _internal_get_mouse_buttons(),
837 kKeyUninitializedModifier);
838
839 for (; it != widget_parents.end(); ++it) {
840 (*it)->enableFlags(HAS_MOUSE);
841 msg->addRecipient(*it);
842 }
843
844 enqueueMessage(msg);
845 generateSetCursorMessage(get_mouse_position(),
846 kKeyUninitializedModifier,
847 PointerType::Unknown);
848 }
849 }
850 }
851
setCapture(Widget * widget)852 void Manager::setCapture(Widget* widget)
853 {
854 // To set the capture, we set first the mouse_widget (because
855 // mouse_widget shouldn't be != capture_widget)
856 setMouse(widget);
857
858 widget->enableFlags(HAS_CAPTURE);
859 capture_widget = widget;
860
861 m_display->captureMouse();
862 }
863
864 // Sets the focus to the "magnetic" widget inside the window
attractFocus(Widget * widget)865 void Manager::attractFocus(Widget* widget)
866 {
867 // Get the magnetic widget
868 Widget* magnet = findMagneticWidget(widget->window());
869
870 // If magnetic widget exists and it doesn't have the focus
871 if (magnet && !magnet->hasFocus())
872 setFocus(magnet);
873 }
874
focusFirstChild(Widget * widget)875 void Manager::focusFirstChild(Widget* widget)
876 {
877 for (Widget* it=widget->window(); it; it=next_widget(it)) {
878 if (ACCEPT_FOCUS(it) && !(child_accept_focus(it, true))) {
879 setFocus(it);
880 break;
881 }
882 }
883 }
884
freeFocus()885 void Manager::freeFocus()
886 {
887 setFocus(NULL);
888 }
889
freeMouse()890 void Manager::freeMouse()
891 {
892 setMouse(NULL);
893 }
894
freeCapture()895 void Manager::freeCapture()
896 {
897 if (capture_widget) {
898 capture_widget->disableFlags(HAS_CAPTURE);
899 capture_widget = NULL;
900
901 m_display->releaseMouse();
902 }
903 }
904
freeWidget(Widget * widget)905 void Manager::freeWidget(Widget* widget)
906 {
907 #ifdef DEBUG_UI_THREADS
908 ASSERT(manager_thread == base::this_thread::native_handle());
909 #endif
910
911 if (widget->hasFocus() || (widget == focus_widget))
912 freeFocus();
913
914 // We shouldn't free widgets that are locked, it means, widgets that
915 // will be re-added soon (e.g. when the stack of windows is
916 // temporarily modified).
917 if (m_lockedWindow == widget)
918 return;
919
920 // Break any relationship with the GUI manager
921 if (widget->hasCapture() || (widget == capture_widget))
922 freeCapture();
923
924 if (widget->hasMouse() || (widget == mouse_widget))
925 freeMouse();
926
927 auto it = std::find(mouse_widgets_list.begin(),
928 mouse_widgets_list.end(),
929 widget);
930 if (it != mouse_widgets_list.end())
931 mouse_widgets_list.erase(it);
932
933 ASSERT(!Manager::widgetAssociatedToManager(widget));
934 }
935
removeMessage(Message * msg)936 void Manager::removeMessage(Message* msg)
937 {
938 #ifdef DEBUG_UI_THREADS
939 ASSERT(manager_thread == base::this_thread::native_handle());
940 #endif
941
942 auto it = std::find(msg_queue.begin(), msg_queue.end(), msg);
943 ASSERT(it != msg_queue.end());
944 msg_queue.erase(it);
945 }
946
removeMessagesFor(Widget * widget)947 void Manager::removeMessagesFor(Widget* widget)
948 {
949 #ifdef DEBUG_UI_THREADS
950 ASSERT(manager_thread == base::this_thread::native_handle());
951 #endif
952
953 for (Message* msg : msg_queue)
954 removeWidgetFromRecipients(widget, msg);
955 }
956
removeMessagesFor(Widget * widget,MessageType type)957 void Manager::removeMessagesFor(Widget* widget, MessageType type)
958 {
959 #ifdef DEBUG_UI_THREADS
960 ASSERT(manager_thread == base::this_thread::native_handle());
961 #endif
962
963 for (Message* msg : msg_queue)
964 if (msg->type() == type)
965 removeWidgetFromRecipients(widget, msg);
966 }
967
removeMessagesForTimer(Timer * timer)968 void Manager::removeMessagesForTimer(Timer* timer)
969 {
970 #ifdef DEBUG_UI_THREADS
971 ASSERT(manager_thread == base::this_thread::native_handle());
972 #endif
973
974 for (auto it=msg_queue.begin(); it != msg_queue.end(); ) {
975 Message* msg = *it;
976
977 if (!msg->isUsed() &&
978 msg->type() == kTimerMessage &&
979 static_cast<TimerMessage*>(msg)->timer() == timer) {
980 delete msg;
981 it = msg_queue.erase(it);
982 }
983 else
984 ++it;
985 }
986 }
987
addMessageFilter(int message,Widget * widget)988 void Manager::addMessageFilter(int message, Widget* widget)
989 {
990 #ifdef DEBUG_UI_THREADS
991 ASSERT(manager_thread == base::this_thread::native_handle());
992 #endif
993
994 LockFilters lock;
995 int c = message;
996 if (c >= kFirstRegisteredMessage)
997 c = kFirstRegisteredMessage;
998
999 msg_filters[c].push_back(new Filter(message, widget));
1000 }
1001
removeMessageFilter(int message,Widget * widget)1002 void Manager::removeMessageFilter(int message, Widget* widget)
1003 {
1004 #ifdef DEBUG_UI_THREADS
1005 ASSERT(manager_thread == base::this_thread::native_handle());
1006 #endif
1007
1008 LockFilters lock;
1009 int c = message;
1010 if (c >= kFirstRegisteredMessage)
1011 c = kFirstRegisteredMessage;
1012
1013 Filters& msg_filter = msg_filters[c];
1014 for (Filter* filter : msg_filter) {
1015 if (filter->widget == widget)
1016 filter->widget = nullptr;
1017 }
1018 }
1019
removeMessageFilterFor(Widget * widget)1020 void Manager::removeMessageFilterFor(Widget* widget)
1021 {
1022 #ifdef DEBUG_UI_THREADS
1023 ASSERT(manager_thread == base::this_thread::native_handle());
1024 #endif
1025
1026 LockFilters lock;
1027 for (Filters& msg_filter : msg_filters) {
1028 for (Filter* filter : msg_filter) {
1029 if (filter->widget == widget)
1030 filter->widget = nullptr;
1031 }
1032 }
1033 }
1034
isFocusMovementMessage(Message * msg)1035 bool Manager::isFocusMovementMessage(Message* msg)
1036 {
1037 if (msg->type() != kKeyDownMessage &&
1038 msg->type() != kKeyUpMessage)
1039 return false;
1040
1041 switch (static_cast<KeyMessage*>(msg)->scancode()) {
1042 case kKeyTab:
1043 case kKeyLeft:
1044 case kKeyRight:
1045 case kKeyUp:
1046 case kKeyDown:
1047 return true;
1048 }
1049 return false;
1050 }
1051
dirtyRect(const gfx::Rect & bounds)1052 void Manager::dirtyRect(const gfx::Rect& bounds)
1053 {
1054 m_dirtyRegion.createUnion(m_dirtyRegion, gfx::Region(bounds));
1055 }
1056
1057 // Configures the window for begin the loop
_openWindow(Window * window)1058 void Manager::_openWindow(Window* window)
1059 {
1060 // Free all widgets of special states.
1061 if (window->isWantFocus()) {
1062 freeCapture();
1063 freeMouse();
1064 freeFocus();
1065 }
1066
1067 // Add the window to manager.
1068 insertChild(0, window);
1069
1070 // Broadcast the open message.
1071 {
1072 base::UniquePtr<Message> msg(new Message(kOpenMessage));
1073 window->sendMessage(msg);
1074 }
1075
1076 // Relayout
1077 window->layout();
1078
1079 // Dirty the entire window and show it
1080 window->setVisible(true);
1081 window->invalidate();
1082
1083 // Attract the focus to the magnetic widget...
1084 // 1) get the magnetic widget
1085 Widget* magnet = findMagneticWidget(window);
1086 // 2) if magnetic widget exists and it doesn't have the focus
1087 if (magnet && !magnet->hasFocus())
1088 setFocus(magnet);
1089 // 3) if not, put the focus in the first child
1090 else if (window->isWantFocus())
1091 focusFirstChild(window);
1092
1093 // Update mouse widget (as it can be a widget below the
1094 // recently opened window).
1095 Widget* widget = pick(ui::get_mouse_position());
1096 if (widget)
1097 setMouse(widget);
1098 }
1099
_closeWindow(Window * window,bool redraw_background)1100 void Manager::_closeWindow(Window* window, bool redraw_background)
1101 {
1102 if (!hasChild(window))
1103 return;
1104
1105 gfx::Region reg1;
1106 if (redraw_background)
1107 window->getRegion(reg1);
1108
1109 // Close all windows to this desktop
1110 if (window->isDesktop()) {
1111 while (!children().empty()) {
1112 Window* child = static_cast<Window*>(children().front());
1113 if (child == window)
1114 break;
1115 else {
1116 gfx::Region reg2;
1117 window->getRegion(reg2);
1118 reg1.createUnion(reg1, reg2);
1119
1120 _closeWindow(child, false);
1121 }
1122 }
1123 }
1124
1125 // Free all widgets of special states.
1126 if (capture_widget && capture_widget->window() == window)
1127 freeCapture();
1128
1129 if (mouse_widget && mouse_widget->window() == window)
1130 freeMouse();
1131
1132 if (focus_widget && focus_widget->window() == window)
1133 freeFocus();
1134
1135 // Hide window.
1136 window->setVisible(false);
1137
1138 // Close message.
1139 {
1140 base::UniquePtr<Message> msg(new Message(kCloseMessage));
1141 window->sendMessage(msg);
1142 }
1143
1144 // Update manager list stuff.
1145 removeChild(window);
1146
1147 // Redraw background.
1148 invalidateRegion(reg1);
1149
1150 // Update mouse widget (as it can be a widget below the
1151 // recently closed window).
1152 Widget* widget = pick(ui::get_mouse_position());
1153 if (widget)
1154 setMouse(widget);
1155 }
1156
onProcessMessage(Message * msg)1157 bool Manager::onProcessMessage(Message* msg)
1158 {
1159 switch (msg->type()) {
1160
1161 case kPaintMessage:
1162 // Draw nothing (the manager should be invisible). On Windows,
1163 // after closing the main window, the manager will not refresh
1164 // the she::Display content, so we'll avoid a gray background
1165 // (the last main window content is kept until the Display is
1166 // finally closed.)
1167 return true;
1168
1169 case kResizeDisplayMessage:
1170 onNewDisplayConfiguration();
1171 break;
1172
1173 case kKeyDownMessage:
1174 case kKeyUpMessage: {
1175 KeyMessage* keymsg = static_cast<KeyMessage*>(msg);
1176 keymsg->setPropagateToChildren(true);
1177 keymsg->setPropagateToParent(false);
1178
1179 // Continue sending the message to the children of all windows
1180 // (until a desktop or foreground window).
1181 Window* win = nullptr;
1182 for (auto manchild : children()) {
1183 win = static_cast<Window*>(manchild);
1184
1185 // Send to the window.
1186 for (auto winchild : win->children())
1187 if (winchild->sendMessage(msg))
1188 return true;
1189
1190 if (win->isForeground() ||
1191 win->isDesktop())
1192 break;
1193 }
1194
1195 // Check the focus movement for foreground (non-desktop) windows.
1196 if (win && win->isForeground()) {
1197 if (msg->type() == kKeyDownMessage)
1198 processFocusMovementMessage(msg);
1199 return true;
1200 }
1201 else
1202 return false;
1203 }
1204
1205 }
1206
1207 return Widget::onProcessMessage(msg);
1208 }
1209
onResize(ResizeEvent & ev)1210 void Manager::onResize(ResizeEvent& ev)
1211 {
1212 gfx::Rect old_pos = bounds();
1213 gfx::Rect new_pos = ev.bounds();
1214 setBoundsQuietly(new_pos);
1215
1216 // The whole manager area is invalid now.
1217 m_invalidRegion = gfx::Region(new_pos);
1218
1219 const int dx = new_pos.x - old_pos.x;
1220 const int dy = new_pos.y - old_pos.y;
1221 const int dw = new_pos.w - old_pos.w;
1222 const int dh = new_pos.h - old_pos.h;
1223
1224 for (auto child : children()) {
1225 Window* window = static_cast<Window*>(child);
1226 if (window->isDesktop()) {
1227 window->setBounds(new_pos);
1228 break;
1229 }
1230
1231 gfx::Rect bounds = window->bounds();
1232 const int cx = bounds.x+bounds.w/2;
1233 const int cy = bounds.y+bounds.h/2;
1234
1235 if (auto_window_adjustment) {
1236 if (cx > old_pos.x+old_pos.w*3/5) {
1237 bounds.x += dw;
1238 }
1239 else if (cx > old_pos.x+old_pos.w*2/5) {
1240 bounds.x += dw / 2;
1241 }
1242
1243 if (cy > old_pos.y+old_pos.h*3/5) {
1244 bounds.y += dh;
1245 }
1246 else if (cy > old_pos.y+old_pos.h*2/5) {
1247 bounds.y += dh / 2;
1248 }
1249
1250 bounds.offset(dx, dy);
1251 }
1252 else {
1253 if (bounds.x2() > new_pos.x2()) {
1254 bounds.x = new_pos.x2() - bounds.w;
1255 }
1256 if (bounds.y2() > new_pos.y2()) {
1257 bounds.y = new_pos.y2() - bounds.h;
1258 }
1259 }
1260 window->setBounds(bounds);
1261 }
1262 }
1263
onBroadcastMouseMessage(WidgetsList & targets)1264 void Manager::onBroadcastMouseMessage(WidgetsList& targets)
1265 {
1266 // Ask to the first window in the "children" list to know how to
1267 // propagate mouse messages.
1268 Widget* widget = UI_FIRST_WIDGET(children());
1269 if (widget)
1270 widget->broadcastMouseMessage(targets);
1271 }
1272
onInitTheme(InitThemeEvent & ev)1273 void Manager::onInitTheme(InitThemeEvent& ev)
1274 {
1275 Widget::onInitTheme(ev);
1276
1277 // Remap the windows
1278 const int oldUIScale = ui::details::old_guiscale();
1279 const int newUIScale = ui::guiscale();
1280 for (auto widget : children()) {
1281 if (widget->type() == kWindowWidget) {
1282 auto window = static_cast<Window*>(widget);
1283 if (window->isDesktop()) {
1284 window->layout();
1285 }
1286 else {
1287 gfx::Rect bounds = window->bounds();
1288 bounds *= newUIScale;
1289 bounds /= oldUIScale;
1290 bounds.x = MID(0, bounds.x, m_display->width() - bounds.w);
1291 bounds.y = MID(0, bounds.y, m_display->height() - bounds.h);
1292 window->setBounds(bounds);
1293 }
1294 }
1295 }
1296 }
1297
onGetLayoutIO()1298 LayoutIO* Manager::onGetLayoutIO()
1299 {
1300 return NULL;
1301 }
1302
onNewDisplayConfiguration()1303 void Manager::onNewDisplayConfiguration()
1304 {
1305 if (m_display) {
1306 int w = m_display->width() / m_display->scale();
1307 int h = m_display->height() / m_display->scale();
1308 if ((bounds().w != w ||
1309 bounds().h != h)) {
1310 setBounds(gfx::Rect(0, 0, w, h));
1311 }
1312 }
1313
1314 _internal_set_mouse_display(m_display);
1315 invalidate();
1316 flushRedraw();
1317 }
1318
onSizeHint(SizeHintEvent & ev)1319 void Manager::onSizeHint(SizeHintEvent& ev)
1320 {
1321 int w = 0, h = 0;
1322
1323 if (!parent()) { // hasn' parent?
1324 w = bounds().w;
1325 h = bounds().h;
1326 }
1327 else {
1328 gfx::Rect pos = parent()->childrenBounds();
1329
1330 for (auto child : children()) {
1331 gfx::Rect cpos = child->bounds();
1332 pos = pos.createUnion(cpos);
1333 }
1334
1335 w = pos.w;
1336 h = pos.h;
1337 }
1338
1339 ev.setSizeHint(gfx::Size(w, h));
1340 }
1341
pumpQueue()1342 int Manager::pumpQueue()
1343 {
1344 #ifdef LIMIT_DISPATCH_TIME
1345 base::tick_t t = base::current_tick();
1346 #endif
1347
1348 int count = 0; // Number of processed messages
1349 auto it = msg_queue.begin();
1350 while (it != msg_queue.end()) {
1351 #ifdef LIMIT_DISPATCH_TIME
1352 if (base::current_tick()-t > 250)
1353 break;
1354 #endif
1355
1356 // The message to process
1357 Message* msg = *it;
1358
1359 // Go to next message
1360 if (msg->isUsed()) {
1361 ++it;
1362 continue;
1363 }
1364
1365 // This message is in use
1366 msg->markAsUsed();
1367 Message* first_msg = msg;
1368
1369 // Call Timer::tick() if this is a tick message.
1370 if (msg->type() == kTimerMessage) {
1371 ASSERT(static_cast<TimerMessage*>(msg)->timer() != NULL);
1372 static_cast<TimerMessage*>(msg)->timer()->tick();
1373 }
1374
1375 bool done = false;
1376
1377 // Send this message to filters
1378 {
1379 Filters& msg_filter = msg_filters[MIN(msg->type(), kFirstRegisteredMessage)];
1380 if (!msg_filter.empty()) {
1381 LockFilters lock;
1382 for (Filter* filter : msg_filter) {
1383 // The widget can be nullptr in case that the filter was
1384 // "pre-removed" (it'll finally erased from the
1385 // msg_filter list from ~LockFilters()).
1386 if (filter->widget != nullptr &&
1387 msg->type() == filter->message) {
1388 msg->setFromFilter(true);
1389 done = sendMessageToWidget(msg, filter->widget);
1390 msg->setFromFilter(false);
1391
1392 if (done)
1393 break;
1394 }
1395 }
1396 }
1397 }
1398
1399 if (!done) {
1400 // Then send the message to its recipients
1401 for (Widget* widget : msg->recipients()) {
1402 done = sendMessageToWidget(msg, widget);
1403 if (done)
1404 break;
1405 }
1406 }
1407
1408 // Remove the message from the msg_queue
1409 it = msg_queue.erase(it);
1410
1411 // Destroy the message
1412 delete first_msg;
1413 ++count;
1414 }
1415
1416 return count;
1417 }
1418
sendMessageToWidget(Message * msg,Widget * widget)1419 bool Manager::sendMessageToWidget(Message* msg, Widget* widget)
1420 {
1421 #ifdef DEBUG_UI_THREADS
1422 ASSERT(manager_thread == base::this_thread::native_handle());
1423 #endif
1424
1425 if (!widget)
1426 return false;
1427
1428 #ifdef REPORT_EVENTS
1429 {
1430 static const char* msg_name[] = {
1431 "kFunctionMessage",
1432
1433 "kOpenMessage",
1434 "kCloseMessage",
1435 "kCloseDisplayMessage",
1436 "kResizeDisplayMessage",
1437 "kPaintMessage",
1438 "kTimerMessage",
1439 "kDropFilesMessage",
1440 "kWinMoveMessage",
1441
1442 "kKeyDownMessage",
1443 "kKeyUpMessage",
1444 "kFocusEnterMessage",
1445 "kFocusLeaveMessage",
1446
1447 "kMouseDownMessage",
1448 "kMouseUpMessage",
1449 "kDoubleClickMessage",
1450 "kMouseEnterMessage",
1451 "kMouseLeaveMessage",
1452 "kMouseMoveMessage",
1453 "kSetCursorMessage",
1454 "kMouseWheelMessage",
1455 "kTouchMagnifyMessage",
1456 };
1457 static_assert(kFunctionMessage == 0 &&
1458 kTouchMagnifyMessage == sizeof(msg_name)/sizeof(const char*)-1,
1459 "MessageType enum has changed");
1460 const char* string =
1461 (msg->type() >= 0 &&
1462 msg->type() < sizeof(msg_name)/sizeof(const char*)) ?
1463 msg_name[msg->type()]: "Unknown";
1464
1465 std::cout << "Event " << msg->type() << " (" << string << ") "
1466 << "for " << ((void*)widget) << std::flush;
1467 std::cout << " (" << typeid(*widget).name() << ")";
1468 if (!widget->id().empty())
1469 std::cout << " (" << widget->id() << ")";
1470 std::cout << std::endl;
1471 }
1472 #endif
1473
1474 bool used = false;
1475
1476 // We need to configure the clip region for paint messages
1477 // before we call Widget::sendMessage().
1478 if (msg->type() == kPaintMessage) {
1479 if (widget->hasFlags(HIDDEN))
1480 return false;
1481
1482 PaintMessage* paintMsg = static_cast<PaintMessage*>(msg);
1483 she::Surface* surface = m_display->getSurface();
1484 surface->saveClip();
1485
1486 if (surface->clipRect(paintMsg->rect())) {
1487 #ifdef REPORT_EVENTS
1488 std::cout << " - clip("
1489 << paintMsg->rect().x << ", "
1490 << paintMsg->rect().y << ", "
1491 << paintMsg->rect().w << ", "
1492 << paintMsg->rect().h << ")"
1493 << std::endl;
1494 #endif
1495
1496 #ifdef DEBUG_PAINT_EVENTS
1497 {
1498 she::SurfaceLock lock(surface);
1499 surface->fillRect(gfx::rgba(0, 0, 255), paintMsg->rect());
1500 }
1501
1502 if (m_display)
1503 m_display->flip(gfx::Rect(0, 0, display_w(), display_h()));
1504
1505 base::this_thread::sleep_for(0.002);
1506 #endif
1507
1508 if (surface) {
1509 // Call the message handler
1510 used = widget->sendMessage(msg);
1511
1512 // Restore clip region for paint messages.
1513 surface->restoreClip();
1514 }
1515 }
1516
1517 // As this kPaintMessage's rectangle was updated, we can
1518 // remove it from "m_invalidRegion".
1519 m_invalidRegion -= gfx::Region(paintMsg->rect());
1520 }
1521 else {
1522 // Call the message handler
1523 used = widget->sendMessage(msg);
1524 }
1525
1526 return used;
1527 }
1528
invalidateDisplayRegion(const gfx::Region & region)1529 void Manager::invalidateDisplayRegion(const gfx::Region& region)
1530 {
1531 // TODO intersect with getDrawableRegion()???
1532 gfx::Region reg1;
1533 reg1.createIntersection(region, gfx::Region(bounds()));
1534
1535 // Redraw windows from top to background.
1536 bool withDesktop = false;
1537 for (auto child : children()) {
1538 ASSERT(dynamic_cast<Window*>(child));
1539 ASSERT(child->type() == kWindowWidget);
1540 Window* window = static_cast<Window*>(child);
1541
1542 // Invalidate regions of this window
1543 window->invalidateRegion(reg1);
1544
1545 // There is desktop?
1546 if (window->isDesktop()) {
1547 withDesktop = true;
1548 break; // Work done
1549 }
1550
1551 // Clip this window area for the next window.
1552 gfx::Region reg3;
1553 window->getRegion(reg3);
1554 reg1.createSubtraction(reg1, reg3);
1555 }
1556
1557 // Invalidate areas outside windows (only when there are not a
1558 // desktop window).
1559 if (!withDesktop)
1560 Widget::invalidateRegion(reg1);
1561 }
1562
getLayoutIO()1563 LayoutIO* Manager::getLayoutIO()
1564 {
1565 return onGetLayoutIO();
1566 }
1567
collectGarbage()1568 void Manager::collectGarbage()
1569 {
1570 if (m_garbage.empty())
1571 return;
1572
1573 for (WidgetsList::iterator
1574 it = m_garbage.begin(),
1575 end = m_garbage.end(); it != end; ++it) {
1576 delete *it;
1577 }
1578 m_garbage.clear();
1579 }
1580
1581 /**********************************************************************
1582 Internal routines
1583 **********************************************************************/
1584
1585 // static
removeWidgetFromRecipients(Widget * widget,Message * msg)1586 void Manager::removeWidgetFromRecipients(Widget* widget, Message* msg)
1587 {
1588 msg->removeRecipient(widget);
1589 }
1590
1591 // static
someParentIsFocusStop(Widget * widget)1592 bool Manager::someParentIsFocusStop(Widget* widget)
1593 {
1594 if (widget->isFocusStop())
1595 return true;
1596
1597 if (widget->parent())
1598 return someParentIsFocusStop(widget->parent());
1599 else
1600 return false;
1601 }
1602
1603 // static
findMagneticWidget(Widget * widget)1604 Widget* Manager::findMagneticWidget(Widget* widget)
1605 {
1606 Widget* found;
1607
1608 for (auto child : widget->children()) {
1609 found = findMagneticWidget(child);
1610 if (found)
1611 return found;
1612 }
1613
1614 if (widget->isFocusMagnet())
1615 return widget;
1616 else
1617 return NULL;
1618 }
1619
1620 // static
newMouseMessage(MessageType type,Widget * widget,const gfx::Point & mousePos,PointerType pointerType,MouseButtons buttons,KeyModifiers modifiers,const gfx::Point & wheelDelta,bool preciseWheel)1621 Message* Manager::newMouseMessage(
1622 MessageType type,
1623 Widget* widget,
1624 const gfx::Point& mousePos,
1625 PointerType pointerType,
1626 MouseButtons buttons,
1627 KeyModifiers modifiers,
1628 const gfx::Point& wheelDelta,
1629 bool preciseWheel)
1630 {
1631 #ifdef __APPLE__
1632 // Convert Ctrl+left click -> right-click
1633 if (widget &&
1634 widget->isVisible() &&
1635 widget->isEnabled() &&
1636 widget->hasFlags(CTRL_RIGHT_CLICK) &&
1637 (modifiers & kKeyCtrlModifier) &&
1638 (buttons == kButtonLeft)) {
1639 modifiers = KeyModifiers(int(modifiers) & ~int(kKeyCtrlModifier));
1640 buttons = kButtonRight;
1641 }
1642 #endif
1643
1644 Message* msg = new MouseMessage(
1645 type, pointerType, buttons, modifiers, mousePos,
1646 wheelDelta, preciseWheel);
1647
1648 if (widget)
1649 msg->addRecipient(widget);
1650
1651 return msg;
1652 }
1653
1654 // static
broadcastKeyMsg(Message * msg)1655 void Manager::broadcastKeyMsg(Message* msg)
1656 {
1657 // Send the message to the widget with capture
1658 if (capture_widget) {
1659 msg->addRecipient(capture_widget);
1660 }
1661 // Send the msg to the focused widget
1662 else if (focus_widget) {
1663 msg->addRecipient(focus_widget);
1664 }
1665 // Finally, send the message to the manager, it'll know what to do
1666 else {
1667 msg->addRecipient(this);
1668 }
1669 }
1670
1671 /***********************************************************************
1672 Focus Movement
1673 ***********************************************************************/
1674
1675 // TODO rewrite this function, it is based in an old code from the
1676 // Allegro library GUI code
1677
processFocusMovementMessage(Message * msg)1678 bool Manager::processFocusMovementMessage(Message* msg)
1679 {
1680 int (*cmp)(Widget*, int, int) = NULL;
1681 Widget* focus = NULL;
1682 Widget* it;
1683 bool ret = false;
1684 Window* window = NULL;
1685 int c, count;
1686
1687 // Who have the focus
1688 if (focus_widget) {
1689 window = focus_widget->window();
1690 }
1691 else if (!this->children().empty()) {
1692 window = this->getTopWindow();
1693 }
1694
1695 if (!window)
1696 return false;
1697
1698 // How many children want the focus in this window?
1699 count = count_widgets_accept_focus(window);
1700
1701 // One at least
1702 if (count > 0) {
1703 std::vector<Widget*> list(count);
1704
1705 c = 0;
1706
1707 // Create a list of possible candidates to receive the focus
1708 for (it=focus_widget; it; it=next_widget(it)) {
1709 if (ACCEPT_FOCUS(it) && !(child_accept_focus(it, true)))
1710 list[c++] = it;
1711 }
1712 for (it=window; it != focus_widget; it=next_widget(it)) {
1713 if (ACCEPT_FOCUS(it) && !(child_accept_focus(it, true)))
1714 list[c++] = it;
1715 }
1716
1717 // Depending on the pressed key...
1718 switch (static_cast<KeyMessage*>(msg)->scancode()) {
1719
1720 case kKeyTab:
1721 // Reverse tab
1722 if ((msg->modifiers() & (kKeyShiftModifier | kKeyCtrlModifier | kKeyAltModifier)) != 0) {
1723 focus = list[count-1];
1724 }
1725 // Normal tab
1726 else if (count > 1) {
1727 focus = list[1];
1728 }
1729 ret = true;
1730 break;
1731
1732 // Arrow keys
1733 case kKeyLeft: if (!cmp) cmp = cmp_left;
1734 case kKeyRight: if (!cmp) cmp = cmp_right;
1735 case kKeyUp: if (!cmp) cmp = cmp_up;
1736 case kKeyDown: if (!cmp) cmp = cmp_down;
1737
1738 // More than one widget
1739 if (count > 1) {
1740 // Position where the focus come
1741 gfx::Point pt = (focus_widget ? focus_widget->bounds().center():
1742 window->bounds().center());
1743
1744 c = (focus_widget ? 1: 0);
1745
1746 // Rearrange the list
1747 for (int i=c; i<count-1; ++i) {
1748 for (int j=i+1; j<count; ++j) {
1749 // Sort the list in ascending order
1750 if ((*cmp)(list[i], pt.x, pt.y) > (*cmp)(list[j], pt.x, pt.y))
1751 std::swap(list[i], list[j]);
1752 }
1753 }
1754
1755 #ifdef REPORT_FOCUS_MOVEMENT
1756 // Print list of widgets
1757 for (int i=c; i<count-1; ++i) {
1758 TRACE("list[%d] = %d (%s)\n",
1759 i, (*cmp)(list[i], pt.x, pt.y),
1760 typeid(*list[i]).name());
1761 }
1762 #endif
1763
1764 // Check if the new widget to put the focus is not in the wrong way.
1765 if ((*cmp)(list[c], pt.x, pt.y) < std::numeric_limits<int>::max())
1766 focus = list[c];
1767 }
1768 // If only there are one widget, put the focus in this
1769 else
1770 focus = list[0];
1771
1772 ret = true;
1773 break;
1774 }
1775
1776 if ((focus) && (focus != focus_widget))
1777 setFocus(focus);
1778 }
1779
1780 return ret;
1781 }
1782
count_widgets_accept_focus(Widget * widget)1783 static int count_widgets_accept_focus(Widget* widget)
1784 {
1785 int count = 0;
1786
1787 for (auto child : widget->children())
1788 count += count_widgets_accept_focus(child);
1789
1790 if ((count == 0) && (ACCEPT_FOCUS(widget)))
1791 count++;
1792
1793 return count;
1794 }
1795
child_accept_focus(Widget * widget,bool first)1796 static bool child_accept_focus(Widget* widget, bool first)
1797 {
1798 for (auto child : widget->children())
1799 if (child_accept_focus(child, false))
1800 return true;
1801
1802 return (first ? false: ACCEPT_FOCUS(widget));
1803 }
1804
next_widget(Widget * widget)1805 static Widget* next_widget(Widget* widget)
1806 {
1807 if (!widget->children().empty())
1808 return UI_FIRST_WIDGET(widget->children());
1809
1810 while (widget->parent() &&
1811 widget->parent()->type() != kManagerWidget) {
1812 WidgetsList::const_iterator begin = widget->parent()->children().begin();
1813 WidgetsList::const_iterator end = widget->parent()->children().end();
1814 WidgetsList::const_iterator it = std::find(begin, end, widget);
1815
1816 ASSERT(it != end);
1817
1818 if ((it+1) != end)
1819 return *(it+1);
1820 else
1821 widget = widget->parent();
1822 }
1823
1824 return NULL;
1825 }
1826
cmp_left(Widget * widget,int x,int y)1827 static int cmp_left(Widget* widget, int x, int y)
1828 {
1829 int z = x - (widget->bounds().x+widget->bounds().w/2);
1830 if (z <= 0)
1831 return std::numeric_limits<int>::max();
1832 return z + ABS((widget->bounds().y+widget->bounds().h/2) - y) * 8;
1833 }
1834
cmp_right(Widget * widget,int x,int y)1835 static int cmp_right(Widget* widget, int x, int y)
1836 {
1837 int z = (widget->bounds().x+widget->bounds().w/2) - x;
1838 if (z <= 0)
1839 return std::numeric_limits<int>::max();
1840 return z + ABS((widget->bounds().y+widget->bounds().h/2) - y) * 8;
1841 }
1842
cmp_up(Widget * widget,int x,int y)1843 static int cmp_up(Widget* widget, int x, int y)
1844 {
1845 int z = y - (widget->bounds().y+widget->bounds().h/2);
1846 if (z <= 0)
1847 return std::numeric_limits<int>::max();
1848 return z + ABS((widget->bounds().x+widget->bounds().w/2) - x) * 8;
1849 }
1850
cmp_down(Widget * widget,int x,int y)1851 static int cmp_down(Widget* widget, int x, int y)
1852 {
1853 int z = (widget->bounds().y+widget->bounds().h/2) - y;
1854 if (z <= 0)
1855 return std::numeric_limits<int>::max();
1856 return z + ABS((widget->bounds().x+widget->bounds().w/2) - x) * 8;
1857 }
1858
1859 } // namespace ui
1860