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