added fonts - works with sdl version
[winnie] / src / wm.cc
1 #include <algorithm>
2 #include <stdexcept>
3 #include <stdio.h>      // TODO
4
5 #include "gfx.h"
6 #include "mouse.h"
7 #include "mouse_cursor.h"
8 #include "text.h"
9 #include "wm.h"
10 #include "window.h"
11
12 WindowManager *wm;
13 static WindowManager wminst;
14
15 static void display(Window *win);
16 static void mouse(Window *win, int bn, bool pressed, int x, int y);
17 static void motion(Window *win, int x, int y);
18
19 void WindowManager::create_frame(Window *win)
20 {
21         Window *frame = new Window;
22         Window *parent = win->get_parent();
23
24         frame->set_display_callback(display);
25         frame->set_mouse_button_callback(mouse);
26         frame->set_mouse_motion_callback(motion);
27         frame->set_focusable(false);
28         frame->add_child(win);
29
30         windows.push_back(frame);
31
32         Rect win_rect = win->get_rect();
33         frame->move(win_rect.x - frame_thickness,
34                         win_rect.y - frame_thickness - titlebar_thickness);
35         frame->resize(win_rect.width + frame_thickness * 2,
36                         win_rect.height + frame_thickness * 2 + titlebar_thickness);
37
38         win->move(frame_thickness, frame_thickness + titlebar_thickness);
39         parent->add_child(frame);
40 }
41
42 void WindowManager::destroy_frame(Window *win)
43 {
44         Window *frame = win->parent;
45         if(!frame) {
46                 return;
47         }
48
49         if(grab_win == win) {
50                 release_mouse();
51         }
52
53         std::list<Window*>::iterator it;
54         it = std::find(windows.begin(), windows.end(), frame);
55         if(it != windows.end()) {
56                 root_win->add_child(win);
57                 windows.erase(it);
58                 delete frame;
59         }
60 }
61
62 WindowManager::WindowManager()
63 {
64         if(!wm) {
65                 wm = this;
66         } else {
67                 throw std::runtime_error("Trying to create a second instance of WindowManager!\n");
68         }
69
70         root_win = new Window;
71         root_win->resize(get_screen_size().width, get_screen_size().height);
72         root_win->move(0, 0);
73         root_win->set_managed(false);
74
75         focused_win = 0;
76
77         bg_color[0] = 210;
78         bg_color[1] = 106;
79         bg_color[2] = 106;
80
81         frame_thickness = 8;
82         titlebar_thickness = 16;
83
84         set_focused_frame_color(36, 59, 98);
85         set_unfocused_frame_color(80, 129, 162);
86
87         mouse_cursor.set_image(mouse_cursor_width, mouse_cursor_height);
88         unsigned char *pixels = mouse_cursor.get_image();
89
90         for(int i=0; i<mouse_cursor_height; i++) {
91                 for(int j=0; j<mouse_cursor_width; j++) {
92                         int val = mouse_cursor_bw[i * mouse_cursor_width + j];
93                         *pixels++ = val;
94                         *pixels++ = val;
95                         *pixels++ = val;
96                         *pixels++ = 255;
97                 }
98         }
99 }
100
101 WindowManager::~WindowManager()
102 {
103         delete root_win;
104 }
105
106 void WindowManager::invalidate_region(const Rect &rect)
107 {
108         dirty_rects.push_back(rect);
109 }
110
111 void WindowManager::process_windows()
112 {
113         if(dirty_rects.empty()) {
114                 return;
115         }
116
117         std::list<Rect>::iterator drit = dirty_rects.begin();
118         Rect uni = *drit++;
119         while(drit != dirty_rects.end()) {
120                 uni = rect_union(uni, *drit++);
121         }
122         dirty_rects.clear();
123
124         wait_vsync();
125
126         fill_rect(uni, bg_color[0], bg_color[1], bg_color[2]);
127
128         root_win->draw_children(uni);
129
130         // draw mouse cursor
131         int mouse_x, mouse_y;
132         get_pointer_pos(&mouse_x, &mouse_y);
133
134         blit_key(mouse_cursor.get_image(), mouse_cursor.get_rect(),
135                         get_framebuffer(), get_screen_size(), mouse_x, mouse_y,
136                         0, 0, 0);
137
138         Rect mouse_rect = {mouse_x, mouse_y, mouse_cursor.get_width(), mouse_cursor.get_height()};
139         invalidate_region(mouse_rect);
140
141         gfx_update();
142 }
143
144 void WindowManager::add_window(Window *win)
145 {
146         if(!win || win == root_win) {
147                 return;
148         }
149
150         root_win->add_child(win);
151
152         if(windows.empty()) {
153                 focused_win = win;
154         }
155
156         if(win->get_managed()) {
157                 create_frame(win);
158         }
159
160         windows.push_back(win);
161 }
162
163 void WindowManager::remove_window(Window *win)
164 {
165         std::list<Window*>::iterator it;
166         it = std::find(windows.begin(), windows.end(), win);
167
168         if(it != windows.end()) {
169                 windows.erase(it);
170         }
171 }
172
173 void WindowManager::set_focused_window(Window *win)
174 {
175         if(win && win == focused_win) {
176                 return;
177         }
178
179         Window *parent;
180         if(focused_win) {
181                 // invalidate the frame (if any)
182                 parent = focused_win->get_parent();
183                 if(parent && parent != root_win) {
184                         parent->invalidate();
185                         fill_rect(parent->get_absolute_rect(), frame_ucolor[0], frame_ucolor[1], frame_ucolor[2]);
186                 }
187         }
188
189         if(!win) {
190                 focused_win = 0;
191                 return;
192         }
193
194         if(win->get_focusable()) {
195                 focused_win = win;
196                 parent = focused_win->get_parent();
197                 fill_rect(parent->get_absolute_rect(), frame_fcolor[0], frame_fcolor[1], frame_fcolor[2]);
198                 return;
199         }
200
201         Window **children = win->get_children();
202         for(int i=0; i<win->get_children_count(); i++) {
203                 if(children[0]->get_focusable()) {
204                         set_focused_window(children[0]);
205                         fill_rect(win->get_absolute_rect(), frame_fcolor[0], frame_fcolor[1], frame_fcolor[2]);
206                         return;
207                 }
208         }
209
210         focused_win = 0;
211 }
212
213 const Window *WindowManager::get_focused_window() const
214 {
215         return focused_win;
216 }
217
218 Window *WindowManager::get_focused_window()
219 {
220         return focused_win;
221 }
222
223 Window *WindowManager::get_window_at_pos(int pointer_x, int pointer_y)
224 {
225         Window *root_win = wm->get_root_window();
226         Window **children = root_win->get_children();
227         for(int i=root_win->get_children_count() - 1; i>=0; i--) {
228                 if(children[i]->contains_point(pointer_x, pointer_y)) {
229                         return children[i];
230                 }
231         }
232
233         return 0;
234 }
235
236 Window *WindowManager::get_root_window() const
237 {
238         return root_win;
239 }
240
241 void WindowManager::set_focused_frame_color(int r, int g, int b)
242 {
243         frame_fcolor[0] = r;
244         frame_fcolor[1] = g;
245         frame_fcolor[2] = b;
246 }
247
248 void WindowManager::get_focused_frame_color(int *r, int *g, int *b) const
249 {
250         *r = frame_fcolor[0];
251         *g = frame_fcolor[1];
252         *b = frame_fcolor[2];
253 }
254
255 void WindowManager::set_unfocused_frame_color(int r, int g, int b)
256 {
257         frame_ucolor[0] = r;
258         frame_ucolor[1] = g;
259         frame_ucolor[2] = b;
260 }
261
262 void WindowManager::get_unfocused_frame_color(int *r, int *g, int *b) const
263 {
264         *r = frame_ucolor[0];
265         *g = frame_ucolor[1];
266         *b = frame_ucolor[2];
267 }
268
269 Window *WindowManager::get_grab_window() const
270 {
271         return grab_win;
272 }
273
274 void WindowManager::grab_mouse(Window *win)
275 {
276         grab_win = win;
277 }
278
279 void WindowManager::release_mouse()
280 {
281         grab_win = 0;
282 }
283
284 void WindowManager::raise_window(Window *win)
285 {
286         if(!win) {
287                 return;
288         }
289
290         Window *parent = win->get_parent();
291         if(parent != root_win) {
292                 if(parent->get_parent() == root_win) {
293                         win = parent;
294                 }
295                 else {
296                         return;
297                 }
298         }
299
300         root_win->remove_child(win);
301         root_win->add_child(win);
302 }
303
304 void WindowManager::sink_window(Window *win)
305 {
306         if(!win) {
307                 return;
308         }
309
310         std::list<Window*>::iterator it;
311         it = std::find(windows.begin(), windows.end(), win);
312         if(it != windows.end()) {
313                 windows.erase(it);
314                 windows.push_front(win);
315         }
316 }
317
318 static void display(Window *win)
319 {
320         //frame display:
321         Window *child = win->get_children()[0];
322         int r, g, b;
323         Rect abs_rect = win->get_absolute_rect();
324
325         //TODO 5 not hardcoded
326         set_text_position(abs_rect.x + 5, abs_rect.y + 15);
327         set_text_color(255, 255, 255);
328
329         if(child == wm->get_focused_window()) {
330                 wm->get_focused_frame_color(&r, &g, &b);
331                 fill_rect(abs_rect, r, g, b);
332         }
333         else {
334                 wm->get_unfocused_frame_color(&r, &g, &b);
335                 fill_rect(win->get_absolute_rect(), r, g, b);
336         }
337
338         draw_text(child->get_title());
339 }
340
341 static int prev_x, prev_y;
342
343 static void mouse(Window *win, int bn, bool pressed, int x, int y)
344 {
345         if(bn == 0) {
346                 if(pressed) {
347                         wm->grab_mouse(win);
348                         wm->raise_window(win);
349                         prev_x = x;
350                         prev_y = y;
351                 }
352                 else {
353                         wm->release_mouse();
354                 }
355         }
356 }
357
358 static void motion(Window *win, int x, int y)
359 {
360         int left_bn = get_button(0);
361         int right_button = get_button(2);
362
363         if(left_bn) {
364                 int dx = x - prev_x;
365                 int dy = y - prev_y;
366                 prev_x = x - dx;
367                 prev_y = y - dy;
368
369                 Rect rect = win->get_rect();
370                 win->move(rect.x + dx, rect.y + dy);
371         }
372 }