1// Aseprite UI Library
2// Copyright (C) 2019-2022 Igara Studio S.A.
3//
4// This file is released under the terms of the MIT license.
5// Read LICENSE.txt for more information.
6
7#ifdef HAVE_CONFIG_H
8#include "config.h"
9#endif
10
11#include "ui/display.h"
12
13#include "base/debug.h"
14#include "ui/system.h"
15#include "ui/widget.h"
16#include "ui/window.h"
17
18#include <algorithm>
19
20namespace ui {
21
22Display::Display(Display* parentDisplay,
23 const os::WindowRef& nativeWindow,
24 Widget* containedWidget)
25 : m_parentDisplay(parentDisplay)
26 , m_nativeWindow(nativeWindow)
27 , m_containedWidget(containedWidget)
28{
29#if 0 // When compiling tests all these values can be nullptr
30 ASSERT(m_nativeWindow);
31 ASSERT(m_containedWidget);
32 ASSERT(m_containedWidget->type() == kManagerWidget ||
33 m_containedWidget->type() == kWindowWidget);
34#endif
35 m_dirtyRegion = bounds();
36}
37
38os::Surface* Display::surface() const
39{
40 return m_nativeWindow->surface();
41}
42
43gfx::Size Display::size() const
44{
45 // When running tests this can be nullptr
46 if (!m_nativeWindow)
47 return gfx::Size(1, 1);
48
49 const int scale = m_nativeWindow->scale();
50 ASSERT(scale > 0);
51 return gfx::Size(m_nativeWindow->width() / scale,
52 m_nativeWindow->height() / scale);
53}
54
55void Display::dirtyRect(const gfx::Rect& bounds)
56{
57 m_dirtyRegion |= gfx::Region(bounds);
58}
59
60void Display::flipDisplay()
61{
62 if (!m_dirtyRegion.isEmpty()) {
63 // Limit the region to the bounds of the window
64 m_dirtyRegion &= gfx::Region(bounds());
65
66 if (!m_dirtyRegion.isEmpty()) {
67 // Invalidate the dirty region in the os::Window
68 if (m_nativeWindow->isVisible())
69 m_nativeWindow->invalidateRegion(m_dirtyRegion);
70 else
71 m_nativeWindow->setVisible(true);
72
73 m_nativeWindow->swapBuffers();
74
75 m_dirtyRegion.clear();
76 }
77 }
78}
79
80void Display::invalidateRect(const gfx::Rect& rect)
81{
82 m_containedWidget->invalidateRect(rect);
83}
84
85void Display::invalidateRegion(const gfx::Region& region)
86{
87 m_containedWidget->invalidateRegion(region);
88}
89
90void Display::addWindow(Window* window)
91{
92 m_windows.insert(m_windows.begin(), window);
93}
94
95void Display::removeWindow(Window* window)
96{
97 auto it = std::find(m_windows.begin(), m_windows.end(), window);
98 ASSERT(it != m_windows.end())
99 if (it == m_windows.end())
100 return;
101
102 m_windows.erase(it);
103}
104
105// TODO code similar to Manager::handleWindowZOrder()
106void Display::handleWindowZOrder(Window* window)
107{
108 removeWindow(window);
109
110 if (window->isOnTop())
111 m_windows.insert(m_windows.begin(), window);
112 else {
113 int pos = (int)m_windows.size();
114
115 for (auto it=m_windows.rbegin(),
116 end=m_windows.rend();
117 it != end; ++it) {
118 if (static_cast<Window*>(*it)->isOnTop())
119 break;
120
121 --pos;
122 }
123
124 m_windows.insert(m_windows.begin()+pos, window);
125 }
126}
127
128gfx::Size Display::workareaSizeUIScale()
129{
130 if (get_multiple_displays()) {
131 return
132 nativeWindow()->screen()->workarea().size() /
133 nativeWindow()->scale();
134 }
135 else {
136 return size();
137 }
138}
139
140} // namespace ui
141