ffe6f6acfd2534fa7b4b91ff4d86f92fe8117abc
[winnie] / src / wm.cc
1 #include <algorithm>
2 #include <stdexcept>
3 #include <stdio.h>      // TODO
4
5 #include "gfx.h"
6 #include "wm.h"
7 #include "window.h"
8 #include "mouse.h"
9 #include "mouse_cursor.h"
10
11 WindowManager *wm;
12 static WindowManager wminst;
13
14 static void display(Window *win);
15 static void mouse(Window *win, int bn, bool pressed, int x, int y);
16 static void motion(Window *win, int x, int y);
17
18 void WindowManager::create_frame(Window *win)
19 {
20         Window *frame = new Window;
21         Window *parent = win->get_parent();
22
23         frame->set_display_callback(display);
24         frame->set_mouse_button_callback(mouse);
25         frame->set_mouse_motion_callback(motion);
26         frame->set_focusable(false);
27         frame->add_child(win);
28
29         windows.push_back(frame);
30
31         Rect win_rect = win->get_rect();
32         frame->move(win_rect.x - frame_thickness,
33                         win_rect.y - frame_thickness - titlebar_thickness);
34         frame->resize(win_rect.width + frame_thickness * 2,
35                         win_rect.height + frame_thickness * 2 + titlebar_thickness);
36
37         win->move(frame_thickness, frame_thickness + titlebar_thickness);
38         parent->add_child(frame);
39 }
40
41 void WindowManager::destroy_frame(Window *win)
42 {
43         Window *frame = win->parent;
44         if(!frame) {
45                 return;
46         }
47
48         std::list<Window*>::iterator it;
49         it = std::find(windows.begin(), windows.end(), frame);
50         if(it != windows.end()) {
51                 root_win->add_child(win);
52                 windows.erase(it);
53                 delete frame;
54         }
55 }
56
57 WindowManager::WindowManager()
58 {
59         if(!wm) {
60                 wm = this;
61         } else {
62                 throw std::runtime_error("Trying to create a second instance of WindowManager!\n");
63         }
64
65         root_win = new Window;
66         root_win->resize(get_screen_size().width, get_screen_size().height);
67         root_win->move(0, 0);
68         root_win->set_managed(false);
69
70         focused_win = 0;
71
72         bg_color[0] = 210;
73         bg_color[1] = 106;
74         bg_color[2] = 106;
75
76         frame_thickness = 8;
77         titlebar_thickness = 16;
78
79         frame_fcolor[0] = frame_fcolor[1] = frame_fcolor[2] = 142;
80         frame_ucolor[0] = frame_ucolor[1] = frame_ucolor[2] = 210;
81
82         mouse_cursor.set_image(mouse_cursor_width, mouse_cursor_height);
83         unsigned char *pixels = mouse_cursor.get_image();
84
85         for(int i=0; i<mouse_cursor_height; i++) {
86                 for(int j=0; j<mouse_cursor_width; j++) {
87                         int val = mouse_cursor_bw[i * mouse_cursor_width + j];
88                         *pixels++ = val;
89                         *pixels++ = val;
90                         *pixels++ = val;
91                         *pixels++ = 255;
92                 }
93         }
94 }
95
96 WindowManager::~WindowManager()
97 {
98         delete root_win;
99 }
100
101 void WindowManager::invalidate_region(const Rect &rect)
102 {
103         dirty_rects.push_back(rect);
104 }
105
106 void WindowManager::process_windows()
107 {
108         if(dirty_rects.empty()) {
109                 return;
110         }
111
112         std::list<Rect>::iterator drit = dirty_rects.begin();
113         Rect uni = *drit++;
114         while(drit != dirty_rects.end()) {
115                 uni = rect_union(uni, *drit++);
116         }
117         dirty_rects.clear();
118
119         wait_vsync();
120
121         fill_rect(uni, bg_color[0], bg_color[1], bg_color[2]);
122
123         root_win->draw_children(uni);
124
125         // draw mouse cursor
126         int mouse_x, mouse_y;
127         get_pointer_pos(&mouse_x, &mouse_y);
128
129         blit_key(mouse_cursor.get_image(), mouse_cursor.get_rect(),
130                         get_framebuffer(), get_screen_size(), mouse_x, mouse_y,
131                         0, 0, 0);
132
133         Rect mouse_rect = {mouse_x, mouse_y, mouse_cursor.get_width(), mouse_cursor.get_height()};
134         invalidate_region(mouse_rect);
135
136         gfx_update();
137 }
138
139 void WindowManager::add_window(Window *win)
140 {
141         if(!win || win == root_win) {
142                 return;
143         }
144
145         root_win->add_child(win);
146
147         if(windows.empty()) {
148                 focused_win = win;
149         }
150
151         if(win->get_managed()) {
152                 create_frame(win);
153         }
154
155         windows.push_back(win);
156 }
157
158 void WindowManager::remove_window(Window *win)
159 {
160         std::list<Window*>::iterator it;
161         it = std::find(windows.begin(), windows.end(), win);
162
163         if(it != windows.end()) {
164                 windows.erase(it);
165         }
166 }
167
168 void WindowManager::set_focused_window(Window *win)
169 {
170         if(win == focused_win) {
171                 return;
172         }
173
174         if(focused_win) {
175                 // invalidate the frame (if any)
176                 Window *parent = focused_win->get_parent();
177                 if(parent && parent != root_win) {
178                         parent->invalidate();
179                 }
180         }
181
182         if(!win) {
183                 focused_win = 0;
184                 return;
185         }
186
187         if(win->get_focusable()) {
188                 focused_win = win;
189                 return;
190         }
191
192         Window **children = win->get_children();
193         for(int i=0; i<win->get_children_count(); i++) {
194                 if(children[0]->get_focusable()) {
195                         set_focused_window(children[0]);
196                         return;
197                 }
198         }
199
200         focused_win = 0;
201 }
202
203 const Window *WindowManager::get_focused_window() const
204 {
205         return focused_win;
206 }
207
208 Window *WindowManager::get_focused_window()
209 {
210         return focused_win;
211 }
212
213 Window *WindowManager::get_window_at_pos(int pointer_x, int pointer_y)
214 {
215         std::list<Window*>::reverse_iterator rit = windows.rbegin();
216         while(rit != windows.rend()) {
217                 Window *w = *rit++;
218                 Window *parent = w->get_parent();
219
220                 if(parent == root_win && w->contains_point(pointer_x, pointer_y)) {
221                         return w;
222                 }
223         }
224
225         return 0;
226 }
227
228 static void display(Window *win)
229 {
230         fill_rect(win->get_absolute_rect(), 255, 211, 5);
231 }
232
233 static int prev_x, prev_y;
234
235 static void mouse(Window *win, int bn, bool pressed, int x, int y)
236 {
237         if(bn == 0) {
238                 if(pressed) {
239                         prev_x = x;
240                         prev_y = y;
241                 }
242         }
243 }
244
245 static void motion(Window *win, int x, int y)
246 {
247         int left_bn = get_button(0);
248         if(left_bn) {
249                 int dx = x - prev_x;
250                 int dy = y - prev_y;
251                 prev_x = x - dx;
252                 prev_y = y - dy;
253
254                 Rect rect = win->get_rect();
255                 win->move(rect.x + dx, rect.y + dy);
256         }
257 }