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