Merge branch 'master' of git://github.com/thepowersgang/acess2
[tpg/acess2.git] / Usermode / Applications / axwin4_src / Server / compositor.cpp
1 /*
2  * Acess2 GUI v4
3  * - By John Hodge (thePowersGang)
4  *
5  * compositor.cpp
6  * - Window compositor
7  */
8 #include <video.hpp>
9 #include <CCompositor.hpp>
10 #include <CClient.hpp>
11 #include <ipc.hpp>
12 #include <cassert>
13
14 namespace AxWin {
15
16 CCompositor::CCompositor(CVideo& video):
17         // TODO: Support multiple screens
18         m_video(video),
19         m_focussed_window(nullptr),
20         m_windowIDBuffer(video.width(), video.height())
21 {
22         // 
23 }
24
25 void CCompositor::ShowWindow(CWindow* window)
26 {
27         DamageArea(window->m_surface.m_rect);
28         // TODO: Append to separate sub-lists (or to separate lists all together)
29         //   if flags AXWIN4_WNDFLAG_KEEPBELOW or AXWIN4_WNDFLAG_KEEPABOVE are set
30         m_windows.push_back(window);
31 }
32 void CCompositor::HideWindow(CWindow* window)
33 {
34         DamageArea(window->m_surface.m_rect);
35         m_windows.remove(window);
36 }
37
38 bool CCompositor::GetScreenDims(unsigned int ScreenID, unsigned int* W, unsigned int* H)
39 {
40         assert(W && H);
41         if( ScreenID != 0 )
42         {
43                 *W = 0;
44                 *H = 0;
45                 return false;
46         }
47         else
48         {
49                 m_video.GetDims(*W, *H);
50                 return true;
51         }
52 }
53
54 void CCompositor::Redraw()
55 {
56         // Redraw the screen and clear damage rects
57         if( m_damageRects.empty() ) {
58                 //_SysDebug("- No damaged regions");
59                 return ;
60         }
61         
62         // Build up foreground grid (Rects and windows)
63         // - This should already be built (mutated on window move/resize/reorder)
64         
65         // For all windows, check for intersection with damage rects
66         for( auto rect : m_damageRects )
67         {
68                 // window list should be sorted by draw order (lowest first)
69                 for( auto window : m_windows )
70                 {
71                         if( window->m_is_shown && rect.HasIntersection( window->m_surface.m_rect ) )
72                         {
73                                 // TODO: just reblit
74                                 CRect   rel_rect = window->m_surface.m_rect.RelativeIntersection(rect);
75                                 _SysDebug("Reblit (%i,%i) %ix%i", rel_rect.m_x, rel_rect.m_y, rel_rect.m_w, rel_rect.m_h);
76                                 BlitFromSurface( window->m_surface, rel_rect );
77                                 //window->Repaint( rel_rect );
78                                 m_windowIDBuffer.set(rel_rect.m_x, rel_rect.m_y, rel_rect.m_w, rel_rect.m_h, window);
79                         }
80                 }
81                 
82                 // TODO: Blit from windows to a local surface, then blit from there to screen here
83         }
84
85         m_damageRects.clear();
86         m_video.Flush();
87 }
88
89 void CCompositor::DamageArea(const CRect& area)
90 {
91         m_damageRects.push_back( area );
92         // 1. Locate intersection with any existing damaged areas
93         // 2. Append after removing intersections
94 }
95
96 void CCompositor::BlitFromSurface(const CSurface& dest, const CRect& src_rect)
97 {
98         for( unsigned int i = 0; i < src_rect.m_h; i ++ )
99         {
100                 m_video.BlitLine(
101                         dest.GetScanline(src_rect.m_y+i, src_rect.m_x),
102                         dest.m_rect.m_y + src_rect.m_y + i,
103                         dest.m_rect.m_x + src_rect.m_x,
104                         src_rect.m_w
105                         );
106         }
107 }
108
109 void CCompositor::MouseMove(unsigned int Cursor, unsigned int X, unsigned int Y, int dX, int dY)
110 {
111         //_SysDebug("MouseButton(%i, %i,%i, %+i,%+i)", Cursor, X, Y, dX, dY);
112         m_video.SetCursorPos(X+dX, Y+dY);
113         CWindow *dstwin = getWindowForCoord(X, Y);
114         if( dstwin )
115         {
116                 // Pass event on to window
117                 dstwin->MouseMove(X, Y);
118         }
119 }
120
121 void CCompositor::MouseButton(unsigned int Cursor, unsigned int X, unsigned int Y, eMouseButton Button, bool Press)
122 {
123         _SysDebug("MouseButton(%i, %i,%i, %i=%i)", Cursor, X, Y, Button, Press);
124         CWindow *dstwin = getWindowForCoord(X, Y);
125         _SysDebug("- dstwin = %p", dstwin);
126         if( dstwin )
127         {
128                 // 1. Give focus and bring to front
129                 // 2. Send event
130                 dstwin->MouseButton(Button, X, Y, Press);
131         }
132 }
133
134 void CCompositor::KeyState(unsigned int KeyboardID, uint32_t KeySym, bool Press, uint32_t Codepoint)
135 {
136         _SysDebug("KeyState(%i, 0x%x, %b, 0x%x)", KeyboardID, KeySym, Press, Codepoint);
137         // TODO: Global hotkeys
138         if( m_focussed_window )
139         {
140                 m_focussed_window->KeyEvent(KeySym, "", Press);
141         }
142 }
143
144 CWindow* CCompositor::getWindowForCoord(unsigned int X, unsigned int Y)
145 {
146         return m_windowIDBuffer.get(X, Y);
147 }
148
149 // --------------------------------------------------------------------
150 CWindowIDBuffer::CWindowIDBuffer(unsigned int W, unsigned int H):
151         m_w(W),
152         m_buf(W*H)
153 {
154 }
155 void CWindowIDBuffer::set(unsigned int X, unsigned int Y, unsigned int W, unsigned int H, CWindow* win)
156 {
157         TWindowID       ent = {
158                 .Client = win->client().id(),
159                 .Window = win->id(),
160                 };
161         for( unsigned int row = 0; row < H; row ++ )
162         {
163                 TWindowID* dst = &m_buf[ (Y+row) * m_w ];
164                 for( unsigned int col = 0; col < W; col ++ )
165                         dst[col] = ent;
166         }
167 }
168 CWindow* CWindowIDBuffer::get(unsigned int X, unsigned int Y)
169 {
170         if( X >= m_w )
171                 return nullptr;
172         unsigned int pos = Y*m_w + X;
173         if( pos >= m_buf.size() )
174                 return nullptr;
175         auto id = m_buf[pos];
176         //_SysDebug("CWindowIDBuffer::get id = {%i,%i}", id.Client, id.Window);
177         auto client = ::AxWin::IPC::GetClientByID(id.Client);
178         if( client == nullptr ) {
179                 //_SysDebug("CWindowIDBuffer::get client=%p", client);
180                 return nullptr;
181         }
182         return client->GetWindow(id.Window);
183 }
184
185 }       // namespace AxWin
186

UCC git Repository :: git.ucc.asn.au