3 Minimum Profit - Programmer Text Editor
7 Copyright (C) 1991-2009 Angel Ortega <angel@triptico.com>
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License
11 as published by the Free Software Foundation; either version 2
12 of the License, or (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 http://www.triptico.com
39 #include <sys/ioctl.h>
41 #include <ncursesw/ncurses.h>
50 /* the curses attributes */
51 int * nc_attrs
= NULL
;
53 /* code for the 'normal' attribute */
54 static int normal_attr
= 0;
57 static WINDOW
* cw
= NULL
;
59 /* stack of windows */
60 static int n_stack
= 0;
61 static WINDOW
** w_stack
= NULL
;
64 static int last_attr
= 0;
67 static int timer_msecs
= 0;
68 static mpdm_t timer_func
= NULL
;
72 static void set_attr(void)
73 /* set the current and fill attributes */
75 wattrset(cw
, nc_attrs
[last_attr
]);
76 wbkgdset(cw
, ' ' | nc_attrs
[last_attr
]);
80 static void nc_sigwinch(int s
)
81 /* SIGWINCH signal handler */
85 #ifdef NCURSES_VERSION
86 /* Make sure that window size changes... */
89 int fd
= open("/dev/tty", O_RDWR
);
92 return; /* This should never have to happen! */
94 if (ioctl(fd
, TIOCGWINSZ
, &ws
) == 0)
95 resizeterm(ws
.ws_row
, ws
.ws_col
);
103 /* invalidate main window */
107 /* re-set dimensions */
108 v
= mpdm_hget_s(mp
, L
"window");
109 mpdm_hset_s(v
, L
"tx", MPDM_I(COLS
));
110 mpdm_hset_s(v
, L
"ty", MPDM_I(LINES
));
113 signal(SIGWINCH
, nc_sigwinch
);
117 #ifdef CONFOPT_WGET_WCH
118 int wget_wch(WINDOW
* w
, wint_t *ch
);
121 static wchar_t * nc_getwch(void)
122 /* gets a key as a wchar_t */
126 #ifdef CONFOPT_WGET_WCH
128 /* set timer period */
130 timeout(timer_msecs
);
132 if (wget_wch(stdscr
, (wint_t *)c
) == -1)
136 char tmp
[MB_CUR_MAX
+ 1];
146 /* set to non-blocking */
149 /* read all possible following characters */
151 while (n
< sizeof(tmp
) - 1 && (cc
= getch()) != ERR
)
154 /* sets input as blocking */
166 #define ctrl(k) ((k) & 31)
168 static mpdm_t
nc_getkey(mpdm_t args
)
169 /* reads a key and converts to an action */
171 static int shift
= 0;
175 /* any pending key? return it */
176 if ((k
= mp_pending_key()) != NULL
)
182 mpdm_exec(timer_func
, NULL
);
188 case L
'0': f
= L
"f10"; break;
189 case L
'1': f
= L
"f1"; break;
190 case L
'2': f
= L
"f2"; break;
191 case L
'3': f
= L
"f3"; break;
192 case L
'4': f
= L
"f4"; break;
193 case L
'5': f
= L
"f5"; break;
194 case L
'6': f
= L
"f6"; break;
195 case L
'7': f
= L
"f7"; break;
196 case L
'8': f
= L
"f8"; break;
197 case L
'9': f
= L
"f9"; break;
198 case KEY_LEFT
: f
= L
"ctrl-cursor-left"; break;
199 case KEY_RIGHT
: f
= L
"ctrl-cursor-right"; break;
200 case KEY_DOWN
: f
= L
"ctrl-cursor-down"; break;
201 case KEY_UP
: f
= L
"ctrl-cursor-up"; break;
202 case KEY_END
: f
= L
"ctrl-end"; break;
203 case KEY_HOME
: f
= L
"ctrl-home"; break;
204 case L
'\r': f
= L
"ctrl-enter"; break;
205 case L
'\e': f
= L
"escape"; break;
206 case KEY_ENTER
: f
= L
"ctrl-enter"; break;
207 case L
' ': f
= L
"ctrl-space"; break;
208 case L
'a': f
= L
"ctrl-a"; break;
209 case L
'b': f
= L
"ctrl-b"; break;
210 case L
'c': f
= L
"ctrl-c"; break;
211 case L
'd': f
= L
"ctrl-d"; break;
212 case L
'e': f
= L
"ctrl-e"; break;
213 case L
'f': f
= L
"ctrl-f"; break;
214 case L
'g': f
= L
"ctrl-g"; break;
215 case L
'h': f
= L
"ctrl-h"; break;
216 case L
'i': f
= L
"ctrl-i"; break;
217 case L
'j': f
= L
"ctrl-j"; break;
218 case L
'k': f
= L
"ctrl-k"; break;
219 case L
'l': f
= L
"ctrl-l"; break;
220 case L
'm': f
= L
"ctrl-m"; break;
221 case L
'n': f
= L
"ctrl-n"; break;
222 case L
'o': f
= L
"ctrl-o"; break;
223 case L
'p': f
= L
"ctrl-p"; break;
224 case L
'q': f
= L
"ctrl-q"; break;
225 case L
'r': f
= L
"ctrl-r"; break;
226 case L
's': f
= L
"ctrl-s"; break;
227 case L
't': f
= L
"ctrl-t"; break;
228 case L
'u': f
= L
"ctrl-u"; break;
229 case L
'v': f
= L
"ctrl-v"; break;
230 case L
'w': f
= L
"ctrl-w"; break;
231 case L
'x': f
= L
"ctrl-x"; break;
232 case L
'y': f
= L
"ctrl-y"; break;
233 case L
'z': f
= L
"ctrl-z"; break;
240 case KEY_LEFT
: f
= L
"cursor-left"; break;
241 case KEY_RIGHT
: f
= L
"cursor-right"; break;
242 case KEY_UP
: f
= L
"cursor-up"; break;
243 case KEY_DOWN
: f
= L
"cursor-down"; break;
244 case KEY_PPAGE
: f
= L
"page-up"; break;
245 case KEY_NPAGE
: f
= L
"page-down"; break;
246 case KEY_HOME
: f
= L
"home"; break;
247 case KEY_END
: f
= L
"end"; break;
248 case KEY_LL
: f
= L
"end"; break;
249 case KEY_IC
: f
= L
"insert"; break;
250 case KEY_DC
: f
= L
"delete"; break;
253 case L
'\b': f
= L
"backspace"; break;
255 case KEY_ENTER
: f
= L
"enter"; break;
256 case L
'\t': f
= L
"tab"; break;
257 case KEY_BTAB
: f
= L
"shift-tab"; break;
258 case L
' ': f
= L
"space"; break;
259 case KEY_F(1): f
= L
"f1"; break;
260 case KEY_F(2): f
= L
"f2"; break;
261 case KEY_F(3): f
= L
"f3"; break;
262 case KEY_F(4): f
= L
"f4"; break;
263 case KEY_F(5): f
= L
"f5"; break;
264 case KEY_F(6): f
= L
"f6"; break;
265 case KEY_F(7): f
= L
"f7"; break;
266 case KEY_F(8): f
= L
"f8"; break;
267 case KEY_F(9): f
= L
"f9"; break;
268 case KEY_F(10): f
= L
"f10"; break;
269 case ctrl(' '): f
= L
"ctrl-space"; break;
270 case ctrl('a'): f
= L
"ctrl-a"; break;
271 case ctrl('b'): f
= L
"ctrl-b"; break;
272 case ctrl('c'): f
= L
"ctrl-c"; break;
273 case ctrl('d'): f
= L
"ctrl-d"; break;
274 case ctrl('e'): f
= L
"ctrl-e"; break;
275 case ctrl('f'): f
= L
"ctrl-f"; break;
276 case ctrl('g'): f
= L
"ctrl-g"; break;
277 case ctrl('j'): f
= L
"ctrl-j"; break;
278 case ctrl('k'): f
= L
"ctrl-k"; break;
279 case ctrl('l'): f
= L
"ctrl-l"; break;
280 case ctrl('n'): f
= L
"ctrl-n"; break;
281 case ctrl('o'): f
= L
"ctrl-o"; break;
282 case ctrl('p'): f
= L
"ctrl-p"; break;
283 case ctrl('q'): f
= L
"ctrl-q"; break;
284 case ctrl('r'): f
= L
"ctrl-r"; break;
285 case ctrl('s'): f
= L
"ctrl-s"; break;
286 case ctrl('t'): f
= L
"ctrl-t"; break;
287 case ctrl('u'): f
= L
"ctrl-u"; break;
288 case ctrl('v'): f
= L
"ctrl-v"; break;
289 case ctrl('w'): f
= L
"ctrl-w"; break;
290 case ctrl('x'): f
= L
"ctrl-x"; break;
291 case ctrl('y'): f
= L
"ctrl-y"; break;
292 case ctrl('z'): f
= L
"ctrl-z"; break;
293 case L
'\e': shift
= 1; f
= NULL
; break;
297 /* no known key? do nothing */
301 return mp_process_keyseq(MPDM_S(f
));
305 static mpdm_t
nc_addwstr(mpdm_t str
)
308 wchar_t * wptr
= mpdm_string(str
);
310 #ifndef CONFOPT_ADDWSTR
313 cptr
= mpdm_wcstombs(wptr
, NULL
);
319 #endif /* CONFOPT_ADDWSTR */
325 static void draw_status(void)
326 /* draws the status bar */
330 t
= mp_build_status_line();
332 /* move to the last line, clear it and draw there */
333 wmove(cw
, LINES
- 1, 0);
334 wattrset(cw
, nc_attrs
[normal_attr
]);
338 /* draw the menu key hint, right-aligned */
339 if ((t
= mpdm_hget_s(mp
, L
"menu_key_hint")) == NULL
) {
340 t
= MPDM_LS(L
"ctrl-a: ");
341 t
= mpdm_strcat(t
, mpdm_gettext(MPDM_LS(L
"Menu")));
342 mpdm_hset_s(mp
, L
"menu_key_hint", t
);
345 wmove(cw
, LINES
- 1, COLS
- mpdm_size(t
));
350 static void nc_draw(mpdm_t doc
)
351 /* driver drawing function for cursesw */
360 for (n
= 0; n
< mpdm_size(d
); n
++) {
361 mpdm_t l
= mpdm_aget(d
, n
);
365 for (m
= 0; m
< mpdm_size(l
); m
++) {
369 /* get the attribute and the string */
370 attr
= mpdm_ival(mpdm_aget(l
, m
++));
373 wattrset(cw
, nc_attrs
[attr
]);
384 static void build_colors(void)
385 /* builds the colors */
393 #ifdef CONFOPT_TRANSPARENCY
394 use_default_colors();
396 #define DEFAULT_INK -1
397 #define DEFAULT_PAPER -1
399 #else /* CONFOPT_TRANSPARENCY */
401 #define DEFAULT_INK COLOR_BLACK
402 #define DEFAULT_PAPER COLOR_WHITE
406 /* gets the color definitions and attribute names */
407 colors
= mpdm_hget_s(mp
, L
"colors");
408 color_names
= mpdm_hget_s(mp
, L
"color_names");
409 l
= mpdm_keys(colors
);
412 /* redim the structures */
413 nc_attrs
= realloc(nc_attrs
, sizeof(int) * s
);
415 /* loop the colors */
416 for (n
= 0; n
< s
&& (c
= mpdm_aget(l
, n
)) != NULL
; n
++) {
417 mpdm_t d
= mpdm_hget(colors
, c
);
418 mpdm_t v
= mpdm_hget_s(d
, L
"text");
421 /* store the 'normal' attribute */
422 if (wcscmp(mpdm_string(c
), L
"normal") == 0)
426 mpdm_hset_s(d
, L
"attr", MPDM_I(n
));
428 /* get color indexes */
429 if ((c0
= mpdm_seek(color_names
, mpdm_aget(v
, 0), 1)) == -1 ||
430 (c1
= mpdm_seek(color_names
, mpdm_aget(v
, 1), 1)) == -1)
433 init_pair(n
+ 1, c0
- 1, c1
- 1);
434 cp
= COLOR_PAIR(n
+ 1);
437 v
= mpdm_hget_s(d
, L
"flags");
438 if (mpdm_seek_s(v
, L
"reverse", 1) != -1)
440 if (mpdm_seek_s(v
, L
"bright", 1) != -1)
442 if (mpdm_seek_s(v
, L
"underline", 1) != -1)
448 /* set the background filler */
449 wbkgdset(cw
, ' ' | nc_attrs
[normal_attr
]);
453 /** driver functions **/
455 static mpdm_t
ncursesw_drv_timer(mpdm_t a
)
457 mpdm_t func
= mpdm_aget(a
, 1);
460 timer_msecs
= mpdm_ival(mpdm_aget(a
, 0));
462 r
= mpdm_unref(timer_func
);
463 timer_func
= mpdm_ref(func
);
469 static mpdm_t
ncursesw_drv_main_loop(mpdm_t a
)
470 /* curses driver main loop */
472 while (! mp_exit_requested
) {
473 /* get current document and draw it */
474 nc_draw(mp_active());
476 /* get key and process it */
477 mp_process_event(nc_getkey(NULL
));
484 static mpdm_t
ncursesw_drv_shutdown(mpdm_t a
)
490 if ((v
= mpdm_hget_s(mp
, L
"exit_message")) != NULL
) {
491 mpdm_write_wcs(stdout
, mpdm_string(v
));
501 static mpdm_t
tui_addstr(mpdm_t a
)
502 /* TUI: add a string */
504 return nc_addwstr(mpdm_aget(a
, 0));
508 static mpdm_t
tui_move(mpdm_t a
)
509 /* TUI: move to a screen position */
511 /* curses' move() use y, x */
512 wmove(cw
, mpdm_ival(mpdm_aget(a
, 1)), mpdm_ival(mpdm_aget(a
, 0)));
514 /* if third argument is not NULL, clear line */
515 if (mpdm_aget(a
, 2) != NULL
)
522 static mpdm_t
tui_attr(mpdm_t a
)
523 /* TUI: set attribute for next string */
525 last_attr
= mpdm_ival(mpdm_aget(a
, 0));
533 static mpdm_t
tui_refresh(mpdm_t a
)
534 /* TUI: refresh the screen */
541 static mpdm_t
tui_getxy(mpdm_t a
)
542 /* TUI: returns the x and y cursor position */
550 mpdm_aset(v
, MPDM_I(x
), 0);
551 mpdm_aset(v
, MPDM_I(y
), 1);
557 static mpdm_t
tui_openpanel(mpdm_t a
)
558 /* opens a panel (creates new window) */
561 w_stack
= realloc(w_stack
, n_stack
* sizeof(WINDOW
*));
562 cw
= w_stack
[n_stack
- 1] = newwin(mpdm_ival(mpdm_aget(a
, 3)),
563 mpdm_ival(mpdm_aget(a
, 2)),
564 mpdm_ival(mpdm_aget(a
, 1)),
565 mpdm_ival(mpdm_aget(a
, 0)));
575 static mpdm_t
tui_closepanel(mpdm_t a
)
576 /* closes a panel (deletes last window) */
579 delwin(w_stack
[n_stack
]);
581 w_stack
= realloc(w_stack
, n_stack
* sizeof(WINDOW
*));
582 cw
= n_stack
== 0 ? stdscr
: w_stack
[n_stack
- 1];
591 static void register_functions(void)
596 drv
= mpdm_hget_s(mp
, L
"drv");
597 mpdm_hset_s(drv
, L
"timer", MPDM_X(ncursesw_drv_timer
));
598 mpdm_hset_s(drv
, L
"main_loop", MPDM_X(ncursesw_drv_main_loop
));
599 mpdm_hset_s(drv
, L
"shutdown", MPDM_X(ncursesw_drv_shutdown
));
601 tui
= mpsl_eval(MPDM_LS(L
"load('mp_tui.mpsl');"), NULL
);
603 /* FIXME: if tui failed, a fatal error must be shown */
605 /* if((e = mpdm_hget_s(mpdm_root(), L"ERROR")) != NULL)
607 mpdm_write_wcs(stdout, mpdm_string(e));
614 mpdm_hset_s(tui
, L
"getkey", MPDM_X(nc_getkey
));
615 mpdm_hset_s(tui
, L
"addstr", MPDM_X(tui_addstr
));
616 mpdm_hset_s(tui
, L
"move", MPDM_X(tui_move
));
617 mpdm_hset_s(tui
, L
"attr", MPDM_X(tui_attr
));
618 mpdm_hset_s(tui
, L
"refresh", MPDM_X(tui_refresh
));
619 mpdm_hset_s(tui
, L
"getxy", MPDM_X(tui_getxy
));
620 mpdm_hset_s(tui
, L
"openpanel", MPDM_X(tui_openpanel
));
621 mpdm_hset_s(tui
, L
"closepanel", MPDM_X(tui_closepanel
));
625 static mpdm_t
ncursesw_drv_startup(mpdm_t a
)
629 register_functions();
633 keypad(stdscr
, TRUE
);
640 v
= mpdm_hget_s(mp
, L
"window");
641 mpdm_hset_s(v
, L
"tx", MPDM_I(COLS
));
642 mpdm_hset_s(v
, L
"ty", MPDM_I(LINES
));
644 signal(SIGWINCH
, nc_sigwinch
);
652 int ncursesw_drv_detect(int * argc
, char *** argv
)
656 drv
= mpdm_hget_s(mp
, L
"drv");
657 mpdm_hset_s(drv
, L
"id", MPDM_LS(L
"curses"));
658 mpdm_hset_s(drv
, L
"startup", MPDM_X(ncursesw_drv_startup
));
663 #endif /* CONFOPT_CURSES */