1 //
2 // This file is part of libyacurs.
3 // Copyright (C) 2013 Rafael Ostertag
4 //
5 // This program is free software: you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License as
7 // published by the Free Software Foundation, either version 3 of the
8 // License, or (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful, but
11 // WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program. If not, see
17 // <http://www.gnu.org/licenses/>.
18 //
19 //
20 // $Id$
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include <cassert>
27 #include <cerrno>
28 #include <cstdlib>
29
30 #include "curs.h"
31 #include "eventqueue.h"
32 #include "windowbase.h"
33 #include "yacursconst.h"
34 #include "yacursex.h"
35
36 using namespace YACURS;
37
38 //
39 // Private
40 //
41
42 //
43 // Protected
44 //
curses_window() const45 YACURS::INTERNAL::CursWin* WindowBase::curses_window() const {
46 return _curses_window;
47 }
48
area() const49 const Area& WindowBase::area() const { return _area; }
50
widget_area() const51 Area WindowBase::widget_area() const {
52 Area widget_area;
53
54 if (_frame) {
55 // we have to take the frame into account, thus
56 // minus Margin(1,1,1,1)
57 widget_area = (_area - _margin) - Margin(1, 1, 1, 1);
58 } else {
59 widget_area = _area - _margin;
60 }
61
62 return widget_area;
63 }
64
unrealize()65 void WindowBase::unrealize() {
66 UNREALIZE_ENTER;
67
68 assert(_curses_window != 0);
69
70 delete _curses_window;
71 _curses_window = 0;
72
73 UNREALIZE_LEAVE;
74 }
75
on_close()76 bool WindowBase::on_close() { return true; }
77
78 //
79 // Public
80 //
81
WindowBase(const Margin & m)82 WindowBase::WindowBase(const Margin& m)
83 : _area(Coordinates(), Curses::inquiry_screensize()),
84 _margin(m),
85 _curses_window(0),
86 _frame(false),
87 _shown(false),
88 _color(DEFAULT) {
89 // We always want to receive this event. Therefore it was moved
90 // from show() to ctor.
91 EventQueue::connect_event(EventConnectorMethod1<WindowBase>(
92 EVT_SIGWINCH, this, &WindowBase::resize_handler));
93 }
94
~WindowBase()95 WindowBase::~WindowBase() {
96 EventQueue::disconnect_event(EventConnectorMethod1<WindowBase>(
97 EVT_REDRAW, this, &WindowBase::redraw_handler));
98
99 EventQueue::disconnect_event(EventConnectorMethod1<WindowBase>(
100 EVT_FORCEREFRESH, this, &WindowBase::force_refresh_handler));
101 EventQueue::disconnect_event(EventConnectorMethod1<WindowBase>(
102 EVT_REFRESH, this, &WindowBase ::refresh_handler));
103 EventQueue::disconnect_event(EventConnectorMethod1<WindowBase>(
104 EVT_SIGWINCH, this, &WindowBase::resize_handler));
105
106 if (realization() == REALIZED) {
107 assert(_curses_window != 0);
108 delete _curses_window;
109 }
110 }
111
margin(const Margin & m)112 void WindowBase::margin(const Margin& m) {
113 if (realization() == REALIZED) throw EXCEPTIONS::AlreadyRealized();
114 _margin = m;
115 }
116
margin() const117 const Margin& WindowBase::margin() const { return _margin; }
118
frame() const119 bool WindowBase::frame() const { return _frame; }
120
frame(bool b)121 void WindowBase::frame(bool b) { _frame = b; }
122
color(COLOROBJ c)123 void WindowBase::color(COLOROBJ c) { _color = c; }
124
125 COLOROBJ
color() const126 WindowBase::color() const { return _color; }
127
show()128 void WindowBase::show() {
129 if (realization() != UNREALIZED) return;
130
131 EventQueue::connect_event(EventConnectorMethod1<WindowBase>(
132 EVT_REDRAW, this, &WindowBase::redraw_handler));
133
134 EventQueue::connect_event(EventConnectorMethod1<WindowBase>(
135 EVT_FORCEREFRESH, this, &WindowBase::force_refresh_handler));
136 EventQueue::connect_event(EventConnectorMethod1<WindowBase>(
137 EVT_REFRESH, this, &WindowBase::refresh_handler));
138
139 realize();
140 refresh(true);
141 EventQueue::submit(EventEx<WindowBase*>(EVT_WINDOW_SHOW, this));
142
143 _shown = true;
144 }
145
close()146 void WindowBase::close() {
147 if (realization() != REALIZED) return;
148
149 if (!on_close()) return;
150
151 unrealize();
152
153 EventQueue::disconnect_event(EventConnectorMethod1<WindowBase>(
154 EVT_REDRAW, this, &WindowBase::redraw_handler));
155
156 EventQueue::disconnect_event(EventConnectorMethod1<WindowBase>(
157 EVT_FORCEREFRESH, this, &WindowBase::force_refresh_handler));
158 EventQueue::disconnect_event(EventConnectorMethod1<WindowBase>(
159 EVT_REFRESH, this, &WindowBase ::refresh_handler));
160
161 // We might have obstructed another window, so make sure it
162 // receives a refresh.
163 //
164 // See also Window::refresh().
165 EventQueue::submit(EVT_FORCEREFRESH);
166 EventQueue::submit(EVT_REFRESH);
167 EventQueue::submit(EVT_DOUPDATE);
168
169 // Change: earlier, it was submitted before
170 // EVT_REFRESH/EVT_DOUPDATE
171 //
172 // This caused problems with the focus manager, if a Label was
173 // updated in the EVT_WINDOW_CLOSE handler.
174 EventQueue::submit(EventEx<WindowBase*>(EVT_WINDOW_CLOSE, this));
175
176 _shown = false;
177 }
178
shown() const179 bool WindowBase::shown() const { return _shown; }
180
redraw_handler(Event & e)181 void WindowBase::redraw_handler(Event& e) {
182 if (realization() != REALIZED) return;
183
184 assert(e == EVT_REDRAW);
185 assert(_curses_window != 0);
186
187 _curses_window->clear();
188 }
189
force_refresh_handler(Event & e)190 void WindowBase::force_refresh_handler(Event& e) {
191 if (realization() != REALIZED) return;
192
193 assert(e == EVT_FORCEREFRESH);
194 assert(_curses_window != 0);
195
196 _curses_window->touch();
197 }
198
refresh_handler(Event & e)199 void WindowBase::refresh_handler(Event& e) {
200 assert(e == EVT_REFRESH);
201 refresh(false);
202 }
203
resize_handler(Event & e)204 void WindowBase::resize_handler(Event& e) {
205 assert(e == EVT_SIGWINCH);
206 EventEx<Size>& winch = dynamic_cast<EventEx<Size>&>(e);
207 resize(Area(Coordinates(0, 0), winch.data()));
208 }
209
refresh(bool immediate)210 void WindowBase::refresh(bool immediate) {
211 if (realization() != REALIZED && realization() != REALIZING) return;
212
213 assert(_curses_window != 0);
214
215 _curses_window->refresh(immediate);
216 }
217
resize(const Area & a)218 void WindowBase::resize(const Area& a) {
219 //
220 // Keep in mind: a resize does not refresh!
221 //
222
223 if (realization() != REALIZED) {
224 // Even if we're not realized, we keep track of the area at
225 // our disposition.
226 //
227 // This was mainly introduced for the screen unlock dialog.
228 _area = a;
229 return;
230 }
231
232 assert(a.x() > -1);
233 assert(a.y() > -1);
234 assert(a.rows() > 0);
235 assert(a.cols() > 0);
236
237 unrealize();
238
239 _area = a;
240
241 realize();
242 }
243
realize()244 void WindowBase::realize() {
245 REALIZE_ENTER;
246
247 assert(_area.x() >= 0);
248 assert(_area.y() >= 0);
249 assert(_area.rows() > 0);
250 assert(_area.cols() > 0);
251
252 Area _tmp = _area - _margin;
253
254 if (_tmp.x() < 0 || _tmp.y() < 0 || _tmp.rows() < MIN_WINDOW_ROWS ||
255 _tmp.cols() < MIN_WINDOW_COLS) {
256 realization(UNREALIZED);
257 return;
258 }
259
260 assert(_curses_window == 0);
261 try {
262 _curses_window = new YACURS::INTERNAL::CursWin(_tmp, _color);
263 _curses_window->scrollok(false);
264 _curses_window->leaveok(true);
265
266 if (_frame) {
267 _curses_window->box();
268 }
269 } catch (EXCEPTIONS::CursesException&) {
270 if (_curses_window != 0) {
271 delete _curses_window;
272 _curses_window = 0;
273 }
274 realization(UNREALIZED);
275 throw;
276 }
277
278 REALIZE_LEAVE;
279 }
280