1 /*
2 scrnman.cc Screen Manager
3 Copyright (c) 1997-8,2000,2004 Kriang Lerdsuwanakij
4 email: lerdsuwa@users.sourceforge.net
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "scrnman.h"
22
23 /*************************************************************************
24 Screen manager base class
25 *************************************************************************/
26
RequestAddWindow(NCWindowBase * win)27 void NCScreenManager::RequestAddWindow(NCWindowBase *win)
28 {
29 winList.push_back(win);
30 }
31
RequestDeleteWindow(NCWindowBase * win)32 void NCScreenManager::RequestDeleteWindow(NCWindowBase *win)
33 {
34 for (sptr_list<NCWindowBase>::iterator iter = winList.begin();
35 iter != winList.end(); ++iter) {
36 if ((*iter)() == win) {
37 (*iter).release(); // Since this is called from
38 // the destructor, release
39 // the ref count to avoid
40 // calling the same destructor
41 // again.
42 winList.erase(iter);
43 break;
44 }
45 }
46 }
47
RequestResize()48 void NCScreenManager::RequestResize()
49 {
50 for (sptr_list<NCWindowBase>::iterator iter = winList.begin();
51 iter != winList.end(); ++iter) {
52 (*iter)->DoResize();
53 }
54 RequestRefresh();
55 }
56
RequestRefresh()57 void NCScreenManager::RequestRefresh()
58 {
59 for (sptr_list<NCWindowBase>::iterator iter = winList.begin();
60 iter != winList.end(); ++iter) {
61 (*iter)->DoTouch();
62 }
63 clearok(curscr, TRUE);
64 wrefresh(stdscr);
65 RequestUpdateAndRestCursor(); // Redraw all windows
66 }
67
RequestUpdate()68 void NCScreenManager::RequestUpdate()
69 {
70 for (sptr_list<NCWindowBase>::iterator iter = winList.begin();
71 iter != winList.end(); ++iter) {
72 (*iter)->DoUpdate();
73 }
74 doupdate(); // Transfer to terminal
75 }
76
RequestRestCursor()77 void NCScreenManager::RequestRestCursor()
78 {
79 if (cursorWin)
80 cursorWin->DoRestCursor();
81 else
82 DoRestCursor();
83 doupdate(); // Change cursor position
84 }
85
RequestUpdateAndRestCursor()86 void NCScreenManager::RequestUpdateAndRestCursor()
87 {
88 for (sptr_list<NCWindowBase>::iterator iter = winList.begin();
89 iter != winList.end(); ++iter) {
90 (*iter)->DoUpdate();
91 }
92 RequestRestCursor();
93 }
94
RequestChangeMode(int mode)95 void NCScreenManager::RequestChangeMode(int mode)
96 {
97 // Changing sizes for all window is very
98 // costly, make sure we really need it
99
100 if (mode != geoMan.GetMode()) { // Change required
101 geoMan.SetMode(mode);
102 RequestResize(); // Notify all window
103 }
104 }
105
SetFocus(NCWindowBase * win)106 void NCScreenManager::SetFocus(NCWindowBase *win)
107 {
108 if (win) {
109 focusStack.push_back(focusWin);
110 focusWin = win;
111 }
112 else {
113 if (focusStack.size()) {
114 // Release ref count
115 focusWin = focusStack.back().release();
116 focusStack.pop_back();
117 }
118 else
119 focusWin = 0;
120 }
121 }
122
SetCursor(NCWindowBase * win)123 void NCScreenManager::SetCursor(NCWindowBase *win)
124 {
125 if (win) {
126 cursorStack.push_back(cursorWin);
127 cursorWin = win;
128 }
129 else {
130 if (cursorStack.size()) {
131 // Release ref count
132 cursorWin = cursorStack.back().release();
133 cursorStack.pop_back();
134 }
135 else
136 cursorWin = 0;
137 }
138 }
139
NCScreenManager(NCGeometryManagerBase & geoMan_)140 NCScreenManager::NCScreenManager(NCGeometryManagerBase &geoMan_) :
141 geoMan(geoMan_),
142 focusWin(NULL), cursorWin(NULL),
143 permWin(NULL), ctrlWin(NULL),
144 winList(), focusStack(),
145 cursorStack()
146 {
147 SizeChangeNotify::InstallObject(this);
148 NCurses::SetNotify(SizeChangeNotify::Callback);
149 }
150
151 unsigned NCScreenManager::mouseScrollRate = 2;
152
~NCScreenManager()153 NCScreenManager::~NCScreenManager()
154 {
155 }
156
ReadKeyboard()157 int NCScreenManager::ReadKeyboard()
158 {
159 int c;
160 if (permWin)
161 c = wgetch(permWin->win);
162 else
163 c = wgetch(focusWin->win);
164
165 #ifdef NCURSES_MOUSE_VERSION
166 if (c == KEY_MOUSE)
167 getmouse(&mouseEvent);
168 #endif
169 return c;
170 }
171
KeyboardLoop()172 void NCScreenManager::KeyboardLoop()
173 {
174 NCWindowBase *prevMousePressedWin = 0;
175 MEVENT prevMouseEvent;
176 #ifdef NCURSES_MOUSE_VERSION
177 if (mouseScrollRate > 0)
178 halfdelay(mouseScrollRate);
179 #endif
180 for ( ; ; ) {
181 if (focusWin) {
182 int c = ReadKeyboard();
183 #ifdef NCURSES_MOUSE_VERSION
184 if (c == KEY_MOUSE) {
185 // FIXME: Locate top window in case of overlapping windows
186 for (sptr_list<NCWindowBase>::iterator iter = winList.begin();
187 iter != winList.end(); ++iter) {
188 (*iter)->DoTouch();
189 if ((*iter)->IsInWin(mouseEvent.x, mouseEvent.y)) {
190 if (mouseEvent.bstate
191 & (BUTTON1_PRESSED | BUTTON2_PRESSED
192 | BUTTON3_PRESSED | BUTTON4_PRESSED)) {
193 if (prevMousePressedWin) {
194 // Replace BUTTON?_PRESSED with
195 // BUTTON?_RELEASED
196 if (prevMouseEvent.bstate & BUTTON1_PRESSED) {
197 prevMouseEvent.bstate &= ~BUTTON1_PRESSED;
198 prevMouseEvent.bstate |= BUTTON1_RELEASED;
199 }
200 if (prevMouseEvent.bstate & BUTTON2_PRESSED) {
201 prevMouseEvent.bstate &= ~BUTTON2_PRESSED;
202 prevMouseEvent.bstate |= BUTTON2_RELEASED;
203 }
204 if (prevMouseEvent.bstate & BUTTON3_PRESSED) {
205 prevMouseEvent.bstate &= ~BUTTON3_PRESSED;
206 prevMouseEvent.bstate |= BUTTON3_RELEASED;
207 }
208 if (prevMouseEvent.bstate & BUTTON4_PRESSED) {
209 prevMouseEvent.bstate &= ~BUTTON4_PRESSED;
210 prevMouseEvent.bstate |= BUTTON4_RELEASED;
211 }
212 prevMousePressedWin->ProcessMouse(prevMouseEvent);
213 }
214 prevMousePressedWin = (*iter)();
215 prevMouseEvent = mouseEvent;
216 }
217
218 (*iter)->ProcessMouse(mouseEvent);
219
220 if (mouseEvent.bstate
221 & (BUTTON1_RELEASED | BUTTON2_RELEASED
222 | BUTTON3_RELEASED | BUTTON4_RELEASED))
223 prevMousePressedWin = 0;
224 break;
225 }
226 }
227 }
228 else if (c == ERR) {
229 if (prevMousePressedWin)
230 prevMousePressedWin->ProcessMouse(prevMouseEvent);
231 }
232 else {
233 #endif
234 prevMousePressedWin = 0;
235 focusWin->ProcessKey(c);
236 #ifdef NCURSES_MOUSE_VERSION
237 }
238 #endif
239 }
240 else
241 break; // Exit loop if focusWin is NULL
242 }
243 }
244
DoRestCursor()245 void NCScreenManager::DoRestCursor()
246 {
247 }
248
249 NCScreenManager *NCScreenManager::SizeChangeNotify::notifyObject = NULL;
250
Callback()251 void NCScreenManager::SizeChangeNotify::Callback()
252 {
253 if (notifyObject)
254 notifyObject->RequestResize();
255 }
256
InstallObject(NCScreenManager * obj)257 void NCScreenManager::SizeChangeNotify::InstallObject(NCScreenManager *obj)
258 {
259 notifyObject = obj;
260 }
261
262 /*************************************************************************
263 Window base class
264 *************************************************************************/
265
DoTouch()266 void NCWindowBase::DoTouch()
267 {
268 if (win)
269 touchwin(win);
270 }
271
DoRestCursor()272 void NCWindowBase::DoRestCursor()
273 {
274 }
275
ProcessCtrl(char,bool)276 void NCWindowBase::ProcessCtrl(char /*c*/, bool /*set*/)
277 {
278 }
279
ProcessKey(int)280 void NCWindowBase::ProcessKey(int /*ch*/)
281 {
282 }
283
284 #ifdef NCURSES_MOUSE_VERSION
ProcessMouse(MEVENT &)285 void NCWindowBase::ProcessMouse(MEVENT & /*event*/)
286 {
287 }
288 #endif
289
IsInWin(int x,int y)290 bool NCWindowBase::IsInWin(int x, int y)
291 {
292 return (x >= GetX1() && x <= GetX2() && y >= GetY1() && y <= GetY2());
293 }
294
InitGeometry()295 void NCWindowBase::InitGeometry()
296 {
297 scrnMan.RequestWinRect(id, rect);
298 }
299
Init()300 void NCWindowBase::Init()
301 {
302 InitGeometry();
303 if (!registered) {
304 scrnMan.RequestAddWindow(this);
305 registered = true;
306 }
307 }
308
NCWindowBase(NCScreenManager & scrnMan_,int id_)309 NCWindowBase::NCWindowBase(NCScreenManager &scrnMan_, int id_) : id(id_),
310 win(NULL), rect(),
311 scrnMan(scrnMan_),
312 registered(false)
313 {
314 }
315
~NCWindowBase()316 NCWindowBase::~NCWindowBase()
317 {
318 if (registered)
319 scrnMan.RequestDeleteWindow(this);
320 if (win)
321 delwin(win);
322 }
323
KeyboardLoop()324 void NCWindowBase::KeyboardLoop()
325 {
326 scrnMan.KeyboardLoop();
327 }
328