ioctl doesn't work for my intel
[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
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         wait_vsync();
121
122         fill_rect(uni, bg_color[0], bg_color[1], bg_color[2]);
123
124         root_win->draw_children(uni);
125
126         // draw mouse cursor
127         int mouse_x, mouse_y;
128         get_pointer_pos(&mouse_x, &mouse_y);
129
130         blit_key(mouse_cursor.get_image(), mouse_cursor.get_rect(),
131                         get_framebuffer(), get_screen_size(), mouse_x, mouse_y,
132                         0, 0, 0);
133
134         Rect mouse_rect = {mouse_x, mouse_y, mouse_cursor.get_width(), mouse_cursor.get_height()};
135         invalidate_region(mouse_rect);
136
137         gfx_update();
138 }
139
140 void WindowManager::add_window(Window *win)
141 {
142         if(!win || win == root_win) {
143                 return;
144         }
145
146         root_win->add_child(win);
147
148         if(windows.empty()) {
149                 focused_win = win;
150         }
151
152         if(win->get_managed()) {
153                 create_frame(win);
154         }
155
156         windows.push_back(win);
157 }
158
159 void WindowManager::remove_window(Window *win)
160 {
161         std::list<Window*>::iterator it;
162         it = std::find(windows.begin(), windows.end(), win);
163
164         if(it != windows.end()) {
165                 windows.erase(it);
166         }
167 }
168
169 void WindowManager::set_focused_window(Window *win)
170 {
171         if(win == focused_win) {
172                 return;
173         }
174
175         if(focused_win) {
176                 // invalidate the frame (if any)
177                 Window *parent = focused_win->get_parent();
178                 if(parent && parent != root_win) {
179                         parent->invalidate();
180                 }
181         }
182
183         if(!win) {
184                 focused_win = 0;
185                 return;
186         }
187
188         if(win->get_focusable()) {
189                 focused_win = win;
190                 return;
191         }
192
193         Window **children = win->get_children();
194         for(int i=0; i<win->get_children_count(); i++) {
195                 if(children[0]->get_focusable()) {
196                         set_focused_window(children[0]);
197                         return;
198                 }
199         }
200
201         focused_win = 0;
202 }
203
204 const Window *WindowManager::get_focused_window() const
205 {
206         return focused_win;
207 }
208
209 Window *WindowManager::get_focused_window()
210 {
211         return focused_win;
212 }
213
214 Window *WindowManager::get_window_at_pos(int pointer_x, int pointer_y)
215 {
216         std::list<Window*>::reverse_iterator rit = windows.rbegin();
217         while(rit != windows.rend()) {
218                 Window *w = *rit++;
219                 Window *parent = w->get_parent();
220
221                 if(parent == root_win && w->contains_point(pointer_x, pointer_y)) {
222                         return w;
223                 }
224         }
225
226         return 0;
227 }
228
229 static void display(Window *win)
230 {
231         fill_rect(win->get_absolute_rect(), 255, 211, 5);
232 }
233
234 static int prev_x, prev_y;
235
236 static void mouse(Window *win, int bn, bool pressed, int x, int y)
237 {
238         if(bn == 0) {
239                 if(pressed) {
240                         prev_x = x;
241                         prev_y = y;
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                 Rect rect = win->get_rect();
256                 win->move(rect.x + dx, rect.y + dy);
257         }
258 }