1/* -*- C -*-
2 * $Id: curses.c 40388 2013-04-19 17:39:44Z nagachika $
3 *
4 * ext/curses/curses.c
5 *
6 * by MAEDA Shugo (ender@pic-internet.or.jp)
7 * modified by Yukihiro Matsumoto (matz@netlab.co.jp),
8 *         Toki Yoshinori,
9 *         Hitoshi Takahashi,
10 *         and Takaaki Tateishi (ttate@kt.jaist.ac.jp)
11 *
12 * maintainers:
13 * - Takaaki Tateishi (ttate@kt.jaist.ac.jp)
14 *
15 * doumentation:
16 * - Vincent Batts (vbatts@hashbangbash.com)
17 */
18
19#include "ruby.h"
20#include "ruby/io.h"
21#include "ruby/thread.h"
22
23#if defined(HAVE_NCURSES_H)
24# include <ncurses.h>
25#elif defined(HAVE_NCURSES_CURSES_H)
26# include <ncurses/curses.h>
27#elif defined(HAVE_CURSES_COLR_CURSES_H)
28# ifdef HAVE_STDARG_PROTOTYPES
29#  include <stdarg.h>
30# else
31#  include <varargs.h>
32# endif
33# include <curses_colr/curses.h>
34#else
35# include <curses.h>
36# if defined(__bsdi__) || defined(__NetBSD__) || defined(__APPLE__)
37#  if !defined(_maxx)
38#  define _maxx maxx
39#  endif
40#  if !defined(_maxy)
41#  define _maxy maxy
42#  endif
43#  if !defined(_begx)
44#  define _begx begx
45#  endif
46#  if !defined(_begy)
47#  define _begy begy
48#  endif
49# endif
50#endif
51
52#ifdef HAVE_INIT_COLOR
53# define USE_COLOR 1
54#endif
55
56/* supports only ncurses mouse routines */
57#ifdef NCURSES_MOUSE_VERSION
58# define USE_MOUSE 1
59#endif
60
61#define NUM2CH NUM2CHR
62#define CH2FIX CHR2FIX
63
64static VALUE mCurses;
65static VALUE mKey;
66static VALUE cWindow;
67static VALUE cPad;
68#ifdef USE_MOUSE
69static VALUE cMouseEvent;
70#endif
71
72static VALUE rb_stdscr;
73
74struct windata {
75    WINDOW *window;
76};
77
78static VALUE window_attroff(VALUE obj, VALUE attrs);
79static VALUE window_attron(VALUE obj, VALUE attrs);
80static VALUE window_attrset(VALUE obj, VALUE attrs);
81
82static void
83no_window(void)
84{
85    rb_raise(rb_eRuntimeError, "already closed window");
86}
87
88#define GetWINDOW(obj, winp) do {\
89    if (!OBJ_TAINTED(obj) && rb_safe_level() >= 4)\
90	rb_raise(rb_eSecurityError, "Insecure: operation on untainted window");\
91    TypedData_Get_Struct((obj), struct windata, &windata_type, (winp));\
92    if ((winp)->window == 0) no_window();\
93} while (0)
94
95static void
96window_free(void *p)
97{
98    struct windata *winp = p;
99    if (winp->window && winp->window != stdscr) delwin(winp->window);
100    winp->window = 0;
101    xfree(winp);
102}
103
104static size_t
105window_memsize(const void *p)
106{
107    const struct windata *winp = p;
108    size_t size = sizeof(*winp);
109    if (!winp) return 0;
110    if (winp->window && winp->window != stdscr) size += sizeof(winp->window);
111    return size;
112}
113
114static const rb_data_type_t windata_type = {
115    "windata",
116    {0, window_free, window_memsize,}
117};
118
119static VALUE
120prep_window(VALUE class, WINDOW *window)
121{
122    VALUE obj;
123    struct windata *winp;
124
125    if (window == NULL) {
126	rb_raise(rb_eRuntimeError, "failed to create window");
127    }
128
129    obj = rb_obj_alloc(class);
130    TypedData_Get_Struct(obj, struct windata, &windata_type, winp);
131    winp->window = window;
132
133    return obj;
134}
135
136/*-------------------------- module Curses --------------------------*/
137
138/*
139 * Document-method: Curses.init_screen
140 *
141 * Initialize a standard screen
142 *
143 * see also Curses.stdscr
144 */
145static VALUE
146curses_init_screen(void)
147{
148    rb_secure(4);
149    if (rb_stdscr) return rb_stdscr;
150    initscr();
151    if (stdscr == 0) {
152	rb_raise(rb_eRuntimeError, "can't initialize curses");
153    }
154    clear();
155    rb_stdscr = prep_window(cWindow, stdscr);
156    return rb_stdscr;
157}
158
159/*
160 * Document-method: Curses.stdscr
161 *
162 * The Standard Screen.
163 *
164 * Upon initializing curses, a default window called stdscr,
165 * which is the size of the terminal screen, is created.
166 *
167 * Many curses functions use this window.
168 */
169#define curses_stdscr curses_init_screen
170
171/*
172 * Document-method: Curses.close_screen
173 *
174 * A program should always call Curses.close_screen before exiting or
175 * escaping from curses mode temporarily. This routine
176 * restores tty modes, moves the cursor to the lower
177 * left-hand corner of the screen and resets the terminal
178 * into the proper non-visual mode.
179 *
180 * Calling Curses.refresh or Curses.doupdate after a temporary
181 * escape causes the program to resume visual mode.
182 *
183 */
184static VALUE
185curses_close_screen(void)
186{
187    curses_stdscr();
188#ifdef HAVE_ISENDWIN
189    if (!isendwin())
190#endif
191	endwin();
192    rb_stdscr = 0;
193    return Qnil;
194}
195
196/*
197 * This is no runtime method,
198 * but a function called before the proc ends
199 *
200 * Similar to Curses.close_screen, except that it also
201 * garbage collects/unregisters the Curses.stdscr
202 */
203static void
204curses_finalize(VALUE dummy)
205{
206    if (stdscr
207#ifdef HAVE_ISENDWIN
208	&& !isendwin()
209#endif
210	)
211	endwin();
212    rb_stdscr = 0;
213    rb_gc_unregister_address(&rb_stdscr);
214}
215
216#ifdef HAVE_ISENDWIN
217/*
218 * Document-method: Curses.closed?
219 *
220 * Returns +true+ if the window/screen has been closed,
221 * without any subsequent Curses.refresh calls,
222 * returns +false+ otherwise.
223 */
224static VALUE
225curses_closed(void)
226{
227    curses_stdscr();
228    if (isendwin()) {
229	return Qtrue;
230    }
231    return Qfalse;
232}
233#else
234#define curses_closed rb_f_notimplement
235#endif
236
237/*
238 * Document-method: Curses.clear
239 *
240 * Clears every position on the screen completely,
241 * so that a subsequent call by Curses.refresh for the screen/window
242 * will be repainted from scratch.
243 */
244static VALUE
245curses_clear(VALUE obj)
246{
247    curses_stdscr();
248    wclear(stdscr);
249    return Qnil;
250}
251
252/*
253 * Document-method: Curses.clrtoeol
254 *
255 * Clears to the end of line, that the cursor is currently on.
256 */
257static VALUE
258curses_clrtoeol(void)
259{
260    curses_stdscr();
261    clrtoeol();
262    return Qnil;
263}
264
265/*
266 * Document-method: Curses.refresh
267 *
268 * Refreshes the windows and lines.
269 *
270 */
271static VALUE
272curses_refresh(VALUE obj)
273{
274    curses_stdscr();
275    refresh();
276    return Qnil;
277}
278
279/*
280 * Document-method: Curses.doupdate
281 *
282 * Refreshes the windows and lines.
283 *
284 * Curses.doupdate allows multiple updates with
285 * more efficiency than Curses.refresh alone.
286 */
287static VALUE
288curses_doupdate(VALUE obj)
289{
290    curses_stdscr();
291#ifdef HAVE_DOUPDATE
292    doupdate();
293#else
294    refresh();
295#endif
296    return Qnil;
297}
298
299/*
300 * Document-method: Curses.echo
301 *
302 * Enables characters typed by the user
303 * to be echoed by Curses.getch as they are typed.
304 */
305static VALUE
306curses_echo(VALUE obj)
307{
308    curses_stdscr();
309    echo();
310    return Qnil;
311}
312
313/*
314 * Document-method: Curses.noecho
315 *
316 * Disables characters typed by the user
317 * to be echoed by Curses.getch as they are typed.
318 */
319static VALUE
320curses_noecho(VALUE obj)
321{
322    curses_stdscr();
323    noecho();
324    return Qnil;
325}
326
327/*
328 * Document-method: Curses.raw
329 *
330 * Put the terminal into raw mode.
331 *
332 * Raw mode is similar to Curses.cbreak mode, in that characters typed
333 * are immediately passed through to the user program.
334 *
335 * The differences are that in raw mode, the interrupt, quit,
336 * suspend, and flow control characters are all passed through
337 * uninterpreted, instead of generating a signal. The behavior
338 * of the BREAK key depends on other bits in the tty driver
339 * that are not set by curses.
340 */
341static VALUE
342curses_raw(VALUE obj)
343{
344    curses_stdscr();
345    raw();
346    return Qnil;
347}
348
349/*
350 * Document-method: Curses.noraw
351 *
352 * Put the terminal out of raw mode.
353 *
354 * see Curses.raw for more detail
355 */
356static VALUE
357curses_noraw(VALUE obj)
358{
359    curses_stdscr();
360    noraw();
361    return Qnil;
362}
363
364/*
365 * Document-method: Curses.cbreak
366 *
367 * Put the terminal into cbreak mode.
368 *
369 * Normally, the tty driver buffers typed characters until
370 * a newline or carriage return is typed. The Curses.cbreak
371 * routine disables line buffering and erase/kill
372 * character-processing (interrupt and flow control characters
373 * are unaffected), making characters typed by the user
374 * immediately available to the program.
375 *
376 * The Curses.nocbreak routine returns the terminal to normal (cooked) mode.
377 *
378 * Initially the terminal may or may not be in cbreak mode,
379 * as the mode is inherited; therefore, a program should
380 * call Curses.cbreak or Curses.nocbreak explicitly.
381 * Most interactive programs using curses set the cbreak mode.
382 * Note that Curses.cbreak overrides Curses.raw.
383 *
384 * see also Curses.raw
385 */
386static VALUE
387curses_cbreak(VALUE obj)
388{
389    curses_stdscr();
390    cbreak();
391    return Qnil;
392}
393
394/*
395 * Document-method: Curses.nocbreak
396 *
397 * Put the terminal into normal mode (out of cbreak mode).
398 *
399 * See Curses.cbreak for more detail.
400 */
401static VALUE
402curses_nocbreak(VALUE obj)
403{
404    curses_stdscr();
405    nocbreak();
406    return Qnil;
407}
408
409/*
410 * Document-method: Curses.nl
411 *
412 * Enable the underlying display device to translate
413 * the return key into newline on input, and whether it
414 * translates newline into return and line-feed on output
415 * (in either case, the call Curses.addch('\n') does the
416 * equivalent of return and line feed on the virtual screen).
417 *
418 * Initially, these translations do occur. If you disable
419 * them using Curses.nonl, curses will be able to make better use
420 * of the line-feed capability, resulting in faster cursor
421 * motion. Also, curses will then be able to detect the return key.
422 */
423static VALUE
424curses_nl(VALUE obj)
425{
426    curses_stdscr();
427    nl();
428    return Qnil;
429}
430
431/*
432 * Document-method: Curses.nl
433 *
434 * Disable the underlying display device to translate
435 * the return key into newline on input
436 *
437 * See Curses.nl for more detail
438 */
439static VALUE
440curses_nonl(VALUE obj)
441{
442    curses_stdscr();
443    nonl();
444    return Qnil;
445}
446
447/*
448 * Document-method: Curses.beep
449 *
450 * Sounds an audible alarm on the terminal, if possible;
451 * otherwise it flashes the screen (visual bell).
452 *
453 * see also Curses.flash
454 */
455static VALUE
456curses_beep(VALUE obj)
457{
458#ifdef HAVE_BEEP
459    curses_stdscr();
460    beep();
461#endif
462    return Qnil;
463}
464
465/*
466 * Document-method: Curses.flash
467 *
468 * Flashs the screen, for visual alarm on the terminal, if possible;
469 * otherwise it sounds the alert.
470 *
471 * see also Curses.beep
472 */
473static VALUE
474curses_flash(VALUE obj)
475{
476#ifdef HAVE_FLASH
477    curses_stdscr();
478    flash();
479#endif
480    return Qnil;
481}
482
483static int
484curses_char(VALUE c)
485{
486    if (FIXNUM_P(c)) {
487	return NUM2INT(c);
488    }
489    else {
490	int cc;
491
492	StringValue(c);
493	if (RSTRING_LEN(c) == 0 || RSTRING_LEN(c) > 1) {
494	    rb_raise(rb_eArgError, "string not corresponding a character");
495	}
496	cc = RSTRING_PTR(c)[0];
497	if (cc > 0x7f) {
498	    rb_raise(rb_eArgError, "no multibyte string supported (yet)");
499	}
500	return cc;
501    }
502}
503
504#ifdef HAVE_UNGETCH
505/*
506 * Document-method: Curses.ungetch
507 * call-seq: ungetch(ch)
508 *
509 * Places +ch+ back onto the input queue to be returned by
510 * the next call to Curses.getch.
511 *
512 * There is just one input queue for all windows.
513 */
514static VALUE
515curses_ungetch(VALUE obj, VALUE ch)
516{
517    int c = curses_char(ch);
518    curses_stdscr();
519    ungetch(c);
520    return Qnil;
521}
522#else
523#define curses_ungetch rb_f_notimplement
524#endif
525
526/*
527 * Document-method: Curses.setpos
528 * call-seq: setpos(y, x)
529 *
530 * A setter for the position of the cursor,
531 * using coordinates +x+ and +y+
532 *
533 */
534static VALUE
535curses_setpos(VALUE obj, VALUE y, VALUE x)
536{
537    curses_stdscr();
538    move(NUM2INT(y), NUM2INT(x));
539    return Qnil;
540}
541
542/*
543 * Document-method: Curses.standout
544 *
545 * Enables the best highlighting mode of the terminal.
546 *
547 * This is equivalent to Curses:Window.attron(A_STANDOUT)
548 *
549 * see also Curses::Window.attrset additional information
550 */
551static VALUE
552curses_standout(VALUE obj)
553{
554    curses_stdscr();
555    standout();
556    return Qnil;
557}
558
559/*
560 * Document-method: Curses.standend
561 *
562 * Enables the Normal display (no highlight)
563 *
564 * This is equivalent to Curses.attron(A_NORMAL)
565 *
566 * see also Curses::Window.attrset for additional information.
567 */
568static VALUE
569curses_standend(VALUE obj)
570{
571    curses_stdscr();
572    standend();
573    return Qnil;
574}
575
576/*
577 * Document-method: Curses.inch
578 *
579 * Returns the character at the current position.
580 */
581static VALUE
582curses_inch(VALUE obj)
583{
584    curses_stdscr();
585    return CH2FIX(inch());
586}
587
588/*
589 * Document-method: Curses.addch
590 * call-seq: addch(ch)
591 *
592 * Add a character +ch+, with attributes, then advance the cursor.
593 *
594 * see also the system manual for curs_addch(3)
595 */
596static VALUE
597curses_addch(VALUE obj, VALUE ch)
598{
599    curses_stdscr();
600    addch(NUM2CH(ch));
601    return Qnil;
602}
603
604/*
605 * Document-method: Curses.insch
606 * call-seq: insch(ch)
607 *
608 * Insert a character +ch+, before the cursor.
609 *
610 */
611static VALUE
612curses_insch(VALUE obj, VALUE ch)
613{
614    curses_stdscr();
615    insch(NUM2CH(ch));
616    return Qnil;
617}
618
619/*
620 * Document-method: Curses.addstr
621 * call-seq: addstr(str)
622 *
623 * add a string of characters +str+, to the window and advance cursor
624 *
625 */
626static VALUE
627curses_addstr(VALUE obj, VALUE str)
628{
629    StringValue(str);
630    str = rb_str_export_locale(str);
631    curses_stdscr();
632    if (!NIL_P(str)) {
633	addstr(StringValueCStr(str));
634    }
635    return Qnil;
636}
637
638static void *
639getch_func(void *arg)
640{
641    int *ip = (int *)arg;
642    *ip = getch();
643    return 0;
644}
645
646/*
647 * Document-method: Curses.getch
648 *
649 * Read and returns a character from the window.
650 *
651 * See Curses::Key to all the function KEY_* available
652 *
653 */
654static VALUE
655curses_getch(VALUE obj)
656{
657    int c;
658
659    curses_stdscr();
660    rb_thread_call_without_gvl(getch_func, &c, RUBY_UBF_IO, 0);
661    if (c == EOF) return Qnil;
662    if (rb_isprint(c)) {
663	char ch = (char)c;
664
665	return rb_locale_str_new(&ch, 1);
666    }
667    return UINT2NUM(c);
668}
669
670/* This should be big enough.. I hope */
671#define GETSTR_BUF_SIZE 1024
672
673static void *
674getstr_func(void *arg)
675{
676    char *rtn = (char *)arg;
677#if defined(HAVE_GETNSTR)
678    getnstr(rtn,GETSTR_BUF_SIZE-1);
679#else
680    getstr(rtn);
681#endif
682    return 0;
683}
684
685/*
686 * Document-method: Curses.getstr
687 *
688 * This is equivalent to a series f Curses::Window.getch calls
689 *
690 */
691static VALUE
692curses_getstr(VALUE obj)
693{
694    char rtn[GETSTR_BUF_SIZE];
695
696    curses_stdscr();
697    rb_thread_call_without_gvl(getstr_func, rtn, RUBY_UBF_IO, 0);
698    return rb_locale_str_new_cstr(rtn);
699}
700
701/*
702 * Document-method: Curses.delch
703 *
704 * Delete the character under the cursor
705 *
706 */
707static VALUE
708curses_delch(VALUE obj)
709{
710    curses_stdscr();
711    delch();
712    return Qnil;
713}
714
715/*
716 * Document-method: Curses.deleteln
717 *
718 * Delete the line under the cursor.
719 *
720 */
721static VALUE
722curses_deleteln(VALUE obj)
723{
724    curses_stdscr();
725#if defined(HAVE_DELETELN) || defined(deleteln)
726    deleteln();
727#endif
728    return Qnil;
729}
730
731/*
732 * Document-method: Curses.insertln
733 *
734 * Inserts a line above the cursor, and the bottom line is lost
735 *
736 */
737static VALUE
738curses_insertln(VALUE obj)
739{
740    curses_stdscr();
741#if defined(HAVE_INSERTLN) || defined(insertln)
742    insertln();
743#endif
744    return Qnil;
745}
746
747/*
748 * Document-method: Curses.keyname
749 * call-seq: keyname(c)
750 *
751 * Returns the character string corresponding to key +c+
752 */
753static VALUE
754curses_keyname(VALUE obj, VALUE c)
755{
756#ifdef HAVE_KEYNAME
757    int cc = curses_char(c);
758    const char *name;
759
760    curses_stdscr();
761    name = keyname(cc);
762    if (name) {
763	return rb_str_new_cstr(name);
764    }
765    else {
766	return Qnil;
767    }
768#else
769    return Qnil;
770#endif
771}
772
773/*
774 * Document-method: Curses.lines
775 *
776 * Returns the number of lines on the screen
777 */
778static VALUE
779curses_lines(void)
780{
781    return INT2FIX(LINES);
782}
783
784/*
785 * Document-method: Curses.cols
786 *
787 * Returns the number of columns on the screen
788 */
789static VALUE
790curses_cols(void)
791{
792    return INT2FIX(COLS);
793}
794
795/*
796 * Document-method: Curses.curs_set
797 * call-seq: curs_set(visibility)
798 *
799 * Sets Cursor Visibility.
800 * 0: invisible
801 * 1: visible
802 * 2: very visible
803 */
804static VALUE
805curses_curs_set(VALUE obj, VALUE visibility)
806{
807#ifdef HAVE_CURS_SET
808    int n;
809    curses_stdscr();
810    return (n = curs_set(NUM2INT(visibility)) != ERR) ? INT2FIX(n) : Qnil;
811#else
812    return Qnil;
813#endif
814}
815
816/*
817 * Document-method: Curses.scrl
818 * call-seq: scrl(num)
819 *
820 * Scrolls the current window Fixnum +num+ lines.
821 * The current cursor position is not changed.
822 *
823 * For positive +num+, it scrolls up.
824 *
825 * For negative +num+, it scrolls down.
826 *
827 */
828static VALUE
829curses_scrl(VALUE obj, VALUE n)
830{
831    /* may have to raise exception on ERR */
832#ifdef HAVE_SCRL
833    curses_stdscr();
834    return (scrl(NUM2INT(n)) == OK) ? Qtrue : Qfalse;
835#else
836    return Qfalse;
837#endif
838}
839
840/*
841 * Document-method: Curses.setscrreg
842 *
843 * call-seq:
844 *   setscrreg(top, bottom)
845 *
846 * Set a software scrolling region in a window.
847 * +top+ and +bottom+ are lines numbers of the margin.
848 *
849 * If this option and Curses.scrollok are enabled, an attempt to move off
850 * the bottom margin line causes all lines in the scrolling region
851 * to scroll one line in the direction of the first line.
852 * Only the text of the window is scrolled.
853 *
854 */
855static VALUE
856curses_setscrreg(VALUE obj, VALUE top, VALUE bottom)
857{
858    /* may have to raise exception on ERR */
859#ifdef HAVE_SETSCRREG
860    curses_stdscr();
861    return (setscrreg(NUM2INT(top), NUM2INT(bottom)) == OK) ? Qtrue : Qfalse;
862#else
863    return Qfalse;
864#endif
865}
866
867/*
868 * Document-method: Curses.attroff
869 * call-seq: attroff(attrs)
870 *
871 * Turns on the named attributes +attrs+ without affecting any others.
872 *
873 * See also Curses::Window.attrset for additional information.
874 */
875static VALUE
876curses_attroff(VALUE obj, VALUE attrs)
877{
878    curses_stdscr();
879    return window_attroff(rb_stdscr,attrs);
880    /* return INT2FIX(attroff(NUM2INT(attrs))); */
881}
882
883/*
884 * Document-method: Curses.attron
885 * call-seq: attron(attrs)
886 *
887 * Turns off the named attributes +attrs+
888 * without turning any other attributes on or off.
889 *
890 * See also Curses::Window.attrset for additional information.
891 */
892static VALUE
893curses_attron(VALUE obj, VALUE attrs)
894{
895    curses_stdscr();
896    return window_attron(rb_stdscr,attrs);
897    /* return INT2FIX(attroff(NUM2INT(attrs))); */
898}
899
900/*
901 * Document-method: Curses.attrset
902 * call-seq: attrset(attrs)
903 *
904 * Sets the current attributes of the given window to +attrs+.
905 *
906 * see also Curses::Window.attrset
907 *
908 */
909static VALUE
910curses_attrset(VALUE obj, VALUE attrs)
911{
912    curses_stdscr();
913    return window_attrset(rb_stdscr,attrs);
914    /* return INT2FIX(attroff(NUM2INT(attrs))); */
915}
916
917/*
918 * Document-method: Curses.bkgdset
919 * call-seq: bkgdset(ch)
920 *
921 * Manipulate the background of the named window
922 * with character Integer +ch+
923 *
924 * The background becomes a property of the character
925 * and moves with the character through any scrolling
926 * and insert/delete line/character operations.
927 *
928 * see also the system manual for curs_bkgd(3)
929 */
930static VALUE
931curses_bkgdset(VALUE obj, VALUE ch)
932{
933#ifdef HAVE_BKGDSET
934    curses_stdscr();
935    bkgdset(NUM2CH(ch));
936#endif
937    return Qnil;
938}
939
940/*
941 * call-seq: bkgd(ch)
942 *
943 * Window background manipulation routines.
944 *
945 * Set the background property of the current
946 * and then apply the character Integer +ch+ setting
947 * to every character position in that window.
948 *
949 * see also the system manual for curs_bkgd(3)
950 */
951static VALUE
952curses_bkgd(VALUE obj, VALUE ch)
953{
954#ifdef HAVE_BKGD
955    curses_stdscr();
956    return (bkgd(NUM2CH(ch)) == OK) ? Qtrue : Qfalse;
957#else
958    return Qfalse;
959#endif
960}
961
962#if defined(HAVE_USE_DEFAULT_COLORS)
963/*
964 * tells the curses library to use terminal's default colors.
965 *
966 * see also the system manual for default_colors(3)
967 */
968static VALUE
969curses_use_default_colors(VALUE obj)
970{
971    curses_stdscr();
972    use_default_colors();
973    return Qnil;
974}
975#else
976#define curses_use_default_colors rb_f_notimplement
977#endif
978
979#if defined(HAVE_TABSIZE)
980/*
981 * Document-method: Curses.TABSIZE=
982 * call-seq: TABSIZE=(value)
983 *
984 * Sets the TABSIZE to Integer +value+
985 */
986static VALUE
987curses_tabsize_set(VALUE obj, VALUE val)
988{
989    TABSIZE = NUM2INT(val);
990    return INT2NUM(TABSIZE);
991}
992#else
993#define curses_tabsize_set rb_f_notimplement
994#endif
995
996#if defined(HAVE_TABSIZE)
997/*
998 * Returns the number of positions in a tab.
999 */
1000static VALUE
1001curses_tabsize_get(VALUE ojb)
1002{
1003    return INT2NUM(TABSIZE);
1004}
1005#else
1006#define curses_tabsize_get rb_f_notimplement
1007#endif
1008
1009#if defined(HAVE_ESCDELAY)
1010/*
1011 * call-seq: Curses.ESCDELAY=(value)
1012 *
1013 * Sets the ESCDELAY to Integer +value+
1014 */
1015static VALUE
1016curses_escdelay_set(VALUE obj, VALUE val)
1017{
1018    ESCDELAY = NUM2INT(val);
1019    return INT2NUM(ESCDELAY);
1020}
1021#else
1022#define curses_escdelay_set rb_f_notimplement
1023#endif
1024
1025#if defined(HAVE_ESCDELAY)
1026/*
1027 * Returns the total time, in milliseconds, for which
1028 * curses will await a character sequence, e.g., a function key
1029 */
1030static VALUE
1031curses_escdelay_get(VALUE obj)
1032{
1033    return INT2NUM(ESCDELAY);
1034}
1035#else
1036#define curses_escdelay_get rb_f_notimplement
1037#endif
1038
1039/*
1040 * Document-method: Curses.resize
1041 * call-seq: resize(lines, cols)
1042 *
1043 * alias for Curses.resizeterm
1044 *
1045 */
1046
1047/*
1048 * Document-method: Curses.resizeterm
1049 * call-seq: resizeterm(lines, cols)
1050 *
1051 * Resize the current term to Fixnum +lines+ and Fixnum +cols+
1052 *
1053 */
1054static VALUE
1055curses_resizeterm(VALUE obj, VALUE lin, VALUE col)
1056{
1057#if defined(HAVE_RESIZETERM)
1058    curses_stdscr();
1059    return (resizeterm(NUM2INT(lin),NUM2INT(col)) == OK) ? Qtrue : Qfalse;
1060#else
1061    return Qnil;
1062#endif
1063}
1064
1065#ifdef USE_COLOR
1066/*
1067 * Document-method: Curses.start_color
1068 *
1069 * Initializes the color attributes, for terminals that support it.
1070 *
1071 * This must be called, in order to use color attributes.
1072 * It is good practice to call it just after Curses.init_screen
1073 */
1074static VALUE
1075curses_start_color(VALUE obj)
1076{
1077    /* may have to raise exception on ERR */
1078    curses_stdscr();
1079    return (start_color() == OK) ? Qtrue : Qfalse;
1080}
1081
1082/*
1083 * Document-method: Curses.init_pair
1084 * call-seq: init_pair(pair, f, b)
1085 *
1086 * Changes the definition of a color-pair.
1087 *
1088 * It takes three arguments: the number of the color-pair to be changed +pair+,
1089 * the foreground color number +f+, and the background color number +b+.
1090 *
1091 * If the color-pair was previously initialized, the screen is
1092 * refreshed and all occurrences of that color-pair are changed
1093 * to the new definition.
1094 *
1095 */
1096static VALUE
1097curses_init_pair(VALUE obj, VALUE pair, VALUE f, VALUE b)
1098{
1099    /* may have to raise exception on ERR */
1100    curses_stdscr();
1101    return (init_pair(NUM2INT(pair),NUM2INT(f),NUM2INT(b)) == OK) ? Qtrue : Qfalse;
1102}
1103
1104/*
1105 * Document-method: Curses.init_color
1106 * call-seq: init_color(color, r, g, b)
1107 *
1108 * Changes the definition of a color. It takes four arguments:
1109 * * the number of the color to be changed, +color+
1110 * * the amount of red, +r+
1111 * * the amount of green, +g+
1112 * * the amount of blue, +b+
1113 *
1114 * The value of the first argument must be between 0 and  COLORS.
1115 * (See the section Colors for the default color index.)  Each
1116 * of the last three arguments must be a value between 0 and 1000.
1117 * When Curses.init_color is used, all occurrences of that color
1118 * on the screen immediately change to the new definition.
1119 */
1120static VALUE
1121curses_init_color(VALUE obj, VALUE color, VALUE r, VALUE g, VALUE b)
1122{
1123    /* may have to raise exception on ERR */
1124    curses_stdscr();
1125    return (init_color(NUM2INT(color),NUM2INT(r),
1126		       NUM2INT(g),NUM2INT(b)) == OK) ? Qtrue : Qfalse;
1127}
1128
1129/*
1130 * Document-method: Curses.has_colors?
1131 *
1132 * Returns +true+ or +false+ depending on whether the terminal has color capbilities.
1133 */
1134static VALUE
1135curses_has_colors(VALUE obj)
1136{
1137    curses_stdscr();
1138    return has_colors() ? Qtrue : Qfalse;
1139}
1140
1141/*
1142 * Document-method: Curses.can_change_color?
1143 *
1144 * Returns +true+ or +false+ depending on whether the terminal can change color attributes
1145 */
1146static VALUE
1147curses_can_change_color(VALUE obj)
1148{
1149    curses_stdscr();
1150    return can_change_color() ? Qtrue : Qfalse;
1151}
1152
1153#if defined(HAVE_COLORS)
1154/*
1155 * Document-method: Curses.color
1156 *
1157 * returns COLORS
1158 */
1159static VALUE
1160curses_colors(VALUE obj)
1161{
1162    return INT2FIX(COLORS);
1163}
1164#else
1165#define curses_colors rb_f_notimplement
1166#endif
1167
1168/*
1169 * Document-method: Curses.color_content
1170 * call-seq: color_content(color)
1171 *
1172 * Returns an 3 item Array of the RGB values in +color+
1173 */
1174static VALUE
1175curses_color_content(VALUE obj, VALUE color)
1176{
1177    short r,g,b;
1178
1179    curses_stdscr();
1180    color_content(NUM2INT(color),&r,&g,&b);
1181    return rb_ary_new3(3,INT2FIX(r),INT2FIX(g),INT2FIX(b));
1182}
1183
1184
1185#if defined(HAVE_COLOR_PAIRS)
1186/*
1187 * Document-method: Curses.color_pairs
1188 *
1189 * Returns the COLOR_PAIRS available, if the curses library supports it.
1190 */
1191static VALUE
1192curses_color_pairs(VALUE obj)
1193{
1194    return INT2FIX(COLOR_PAIRS);
1195}
1196#else
1197#define curses_color_pairs rb_f_notimplement
1198#endif
1199
1200/*
1201 * Document-method: Curses.pair_content
1202 * call-seq: pair_content(pair)
1203 *
1204 * Returns a 2 item Array, with the foreground and
1205 * background color, in +pair+
1206 */
1207static VALUE
1208curses_pair_content(VALUE obj, VALUE pair)
1209{
1210    short f,b;
1211
1212    curses_stdscr();
1213    pair_content(NUM2INT(pair),&f,&b);
1214    return rb_ary_new3(2,INT2FIX(f),INT2FIX(b));
1215}
1216
1217/*
1218 * Document-method: Curses.color_pair
1219 * call-seq: color_pair(attrs)
1220 *
1221 * Sets the color pair attributes to +attrs+.
1222 *
1223 * This should be equivalent to Curses.attrset(COLOR_PAIR(+attrs+))
1224 *
1225 * TODO: validate that equivalency
1226 */
1227static VALUE
1228curses_color_pair(VALUE obj, VALUE attrs)
1229{
1230    return INT2FIX(COLOR_PAIR(NUM2INT(attrs)));
1231}
1232
1233/*
1234 * Document-method: Curses.pair_number
1235 * call-seq: pair_number(attrs)
1236 *
1237 * Returns the Fixnum color pair number of attributes +attrs+.
1238 */
1239static VALUE
1240curses_pair_number(VALUE obj, VALUE attrs)
1241{
1242    curses_stdscr();
1243    return INT2FIX(PAIR_NUMBER(NUM2LONG(attrs)));
1244}
1245#endif /* USE_COLOR */
1246
1247#ifdef USE_MOUSE
1248struct mousedata {
1249    MEVENT *mevent;
1250};
1251
1252static void
1253no_mevent(void)
1254{
1255    rb_raise(rb_eRuntimeError, "no such mouse event");
1256}
1257
1258#define GetMOUSE(obj, data) do {\
1259    if (!OBJ_TAINTED(obj) && rb_safe_level() >= 4)\
1260	rb_raise(rb_eSecurityError, "Insecure: operation on untainted mouse");\
1261    TypedData_Get_Struct((obj), struct mousedata, &mousedata_type, (data));\
1262    if ((data)->mevent == 0) no_mevent();\
1263} while (0)
1264
1265static void
1266curses_mousedata_free(void *p)
1267{
1268    struct mousedata *mdata = p;
1269    if (mdata->mevent)
1270	xfree(mdata->mevent);
1271}
1272
1273static size_t
1274curses_mousedata_memsize(const void *p)
1275{
1276    const struct mousedata *mdata = p;
1277    size_t size = sizeof(*mdata);
1278    if (!mdata) return 0;
1279    if (mdata->mevent) size += sizeof(mdata->mevent);
1280    return size;
1281}
1282
1283static const rb_data_type_t mousedata_type = {
1284    "mousedata",
1285    {0, curses_mousedata_free, curses_mousedata_memsize,}
1286};
1287
1288/*
1289 * Document-method: Curses.getmouse
1290 *
1291 * Returns coordinates of the mouse.
1292 *
1293 * This will read and pop the mouse event data off the queue
1294 *
1295 * See the BUTTON*, ALL_MOUSE_EVENTS and REPORT_MOUSE_POSITION constants, to examine the mask of the event
1296 */
1297static VALUE
1298curses_getmouse(VALUE obj)
1299{
1300    struct mousedata *mdata;
1301    VALUE val;
1302
1303    curses_stdscr();
1304    val = TypedData_Make_Struct(cMouseEvent,struct mousedata,
1305				&mousedata_type,mdata);
1306    mdata->mevent = (MEVENT*)xmalloc(sizeof(MEVENT));
1307    return (getmouse(mdata->mevent) == OK) ? val : Qnil;
1308}
1309
1310/*
1311 * Document-method: Curses.ungetmouse
1312 *
1313 * It pushes a KEY_MOUSE event onto the input queue, and associates with that
1314 * event the given state data and screen-relative character-cell coordinates.
1315 *
1316 * The Curses.ungetmouse function behaves analogously to Curses.ungetch.
1317 */
1318static VALUE
1319curses_ungetmouse(VALUE obj, VALUE mevent)
1320{
1321    struct mousedata *mdata;
1322
1323    curses_stdscr();
1324    GetMOUSE(mevent,mdata);
1325    return (ungetmouse(mdata->mevent) == OK) ? Qtrue : Qfalse;
1326}
1327
1328/*
1329 * Document-method: Curses.mouseinterval
1330 * call-seq: mouseinterval(interval)
1331 *
1332 * The Curses.mouseinterval function sets the maximum time
1333 * (in thousands of a second) that can elapse between press
1334 * and release events for them to be recognized as a click.
1335 *
1336 * Use Curses.mouseinterval(0) to disable click resolution.
1337 * This function returns the previous interval value.
1338 *
1339 * Use Curses.mouseinterval(-1) to obtain the interval without
1340 * altering it.
1341 *
1342 * The default is one sixth of a second.
1343 */
1344static VALUE
1345curses_mouseinterval(VALUE obj, VALUE interval)
1346{
1347    curses_stdscr();
1348    return mouseinterval(NUM2INT(interval)) ? Qtrue : Qfalse;
1349}
1350
1351/*
1352 * Document-method: Curses.mousemask
1353 * call-seq: mousemask(mask)
1354 *
1355 * Returns the +mask+ of the reportable events
1356 */
1357static VALUE
1358curses_mousemask(VALUE obj, VALUE mask)
1359{
1360    curses_stdscr();
1361    return INT2NUM(mousemask(NUM2UINT(mask),NULL));
1362}
1363
1364#define DEFINE_MOUSE_GET_MEMBER(func_name,mem) \
1365static VALUE func_name (VALUE mouse) \
1366{ \
1367    struct mousedata *mdata; \
1368    GetMOUSE(mouse, mdata); \
1369    return (UINT2NUM(mdata->mevent -> mem)); \
1370}
1371
1372/*
1373 * Document-method: Curses::MouseEvent.eid
1374 *
1375 * Returns the current mouse id
1376 */
1377DEFINE_MOUSE_GET_MEMBER(curs_mouse_id, id)
1378/*
1379 * Document-method: Curses::MouseEvent.x
1380 *
1381 * Returns the current mouse's X coordinate
1382 */
1383DEFINE_MOUSE_GET_MEMBER(curs_mouse_x, x)
1384/*
1385 * Document-method: Curses::MouseEvent.y
1386 *
1387 * Returns the current mouse's Y coordinate
1388 */
1389DEFINE_MOUSE_GET_MEMBER(curs_mouse_y, y)
1390/*
1391 * Document-method: Curses::MouseEvent.z
1392 *
1393 * Returns the current mouse's Z coordinate
1394 */
1395DEFINE_MOUSE_GET_MEMBER(curs_mouse_z, z)
1396/*
1397 * Document-method: Curses::MouseEvent.bstate
1398 *
1399 * Returns the current mouse's button state.  Use this with the button state
1400 * constants to determine which buttons were pressed.
1401 */
1402DEFINE_MOUSE_GET_MEMBER(curs_mouse_bstate, bstate)
1403#undef define_curs_mouse_member
1404#endif /* USE_MOUSE */
1405
1406#ifdef HAVE_TIMEOUT
1407/*
1408 * Document-method: Curses.timeout=
1409 * call-seq: timeout=(delay)
1410 *
1411 * Sets block and non-blocking reads for the window.
1412 * - If delay is negative, blocking read is used (i.e., waits indefinitely for input).
1413 * - If delay is zero, then non-blocking read is used (i.e., read returns ERR if no input is waiting).
1414 * - If delay is positive, then read blocks for delay milliseconds, and returns ERR if there is still no input.
1415 *
1416 */
1417static VALUE
1418curses_timeout(VALUE obj, VALUE delay)
1419{
1420    curses_stdscr();
1421    timeout(NUM2INT(delay));
1422    return Qnil;
1423}
1424#else
1425#define curses_timeout rb_f_notimplement
1426#endif
1427
1428#ifdef HAVE_DEF_PROG_MODE
1429/*
1430 * Document-method: Curses.def_prog_mode
1431 *
1432 * Save the current terminal modes as the "program"
1433 * state for use by the Curses.reset_prog_mode
1434 *
1435 * This is done automatically by Curses.init_screen
1436 */
1437static VALUE
1438curses_def_prog_mode(VALUE obj)
1439{
1440    curses_stdscr();
1441    return def_prog_mode() == OK ? Qtrue : Qfalse;
1442}
1443#else
1444#define curses_def_prog_mode rb_f_notimplement
1445#endif
1446
1447#ifdef HAVE_RESET_PROG_MODE
1448/*
1449 * Document-method: Curses.reset_prog_mode
1450 *
1451 * Reset the current terminal modes to the saved state
1452 * by the Curses.def_prog_mode
1453 *
1454 * This is done automatically by Curses.close_screen
1455 */
1456static VALUE
1457curses_reset_prog_mode(VALUE obj)
1458{
1459    curses_stdscr();
1460    return reset_prog_mode() == OK ? Qtrue : Qfalse;
1461}
1462#else
1463#define curses_reset_prog_mode rb_f_notimplement
1464#endif
1465
1466/*-------------------------- class Window --------------------------*/
1467
1468/* returns a Curses::Window object */
1469static VALUE
1470window_s_allocate(VALUE class)
1471{
1472    struct windata *winp;
1473
1474    return TypedData_Make_Struct(class, struct windata, &windata_type, winp);
1475}
1476
1477/*
1478 * Document-method: Curses::Window.new
1479 * call-seq: new(height, width, top, left)
1480 *
1481 * Contruct a new Curses::Window with constraints of
1482 * +height+ lines, +width+ columns, begin at +top+ line, and begin +left+ most column.
1483 *
1484 * A new window using full screen is called as
1485 * 	Curses::Window.new(0,0,0,0)
1486 *
1487 */
1488static VALUE
1489window_initialize(VALUE obj, VALUE h, VALUE w, VALUE top, VALUE left)
1490{
1491    struct windata *winp;
1492    WINDOW *window;
1493
1494    rb_secure(4);
1495    curses_init_screen();
1496    TypedData_Get_Struct(obj, struct windata, &windata_type, winp);
1497    if (winp->window) delwin(winp->window);
1498    window = newwin(NUM2INT(h), NUM2INT(w), NUM2INT(top), NUM2INT(left));
1499    wclear(window);
1500    winp->window = window;
1501
1502    return obj;
1503}
1504
1505/*
1506 * Document-method: Curses::Window.subwin
1507 * call-seq: subwin(height, width, top, left)
1508 *
1509 * Contruct a new subwindow with constraints of
1510 * +height+ lines, +width+ columns, begin at +top+ line, and begin +left+ most column.
1511 *
1512 */
1513static VALUE
1514window_subwin(VALUE obj, VALUE height, VALUE width, VALUE top, VALUE left)
1515{
1516    struct windata *winp;
1517    WINDOW *window;
1518    VALUE win;
1519    int h, w, t, l;
1520
1521    h = NUM2INT(height);
1522    w = NUM2INT(width);
1523    t = NUM2INT(top);
1524    l = NUM2INT(left);
1525    GetWINDOW(obj, winp);
1526    window = subwin(winp->window, h, w, t, l);
1527    win = prep_window(rb_obj_class(obj), window);
1528
1529    return win;
1530}
1531
1532/*
1533 * Document-method: Curses::Window.close
1534 *
1535 * Deletes the window, and frees the memory
1536 */
1537static VALUE
1538window_close(VALUE obj)
1539{
1540    struct windata *winp;
1541
1542    GetWINDOW(obj, winp);
1543    delwin(winp->window);
1544    winp->window = 0;
1545
1546    return Qnil;
1547}
1548
1549/*
1550 * Document-method: Curses::Window.clear
1551 *
1552 * Clear the window.
1553 */
1554static VALUE
1555window_clear(VALUE obj)
1556{
1557    struct windata *winp;
1558
1559    GetWINDOW(obj, winp);
1560    wclear(winp->window);
1561
1562    return Qnil;
1563}
1564
1565/*
1566 * Document-method: Curses::Window.clrtoeol
1567 *
1568 * Clear the window to the end of line, that the cursor is currently on.
1569 */
1570static VALUE
1571window_clrtoeol(VALUE obj)
1572{
1573    struct windata *winp;
1574
1575    GetWINDOW(obj, winp);
1576    wclrtoeol(winp->window);
1577
1578    return Qnil;
1579}
1580
1581/*
1582 * Document-method: Curses::Window.refresh
1583 *
1584 * Refreshes the windows and lines.
1585 *
1586 */
1587static VALUE
1588window_refresh(VALUE obj)
1589{
1590    struct windata *winp;
1591
1592    GetWINDOW(obj, winp);
1593    wrefresh(winp->window);
1594
1595    return Qnil;
1596}
1597
1598/*
1599 * Document-method: Curses::Window.noutrefresh
1600 *
1601 * Refreshes the windows and lines.
1602 *
1603 * Curses::Window.noutrefresh allows multiple updates with
1604 * more efficiency than Curses::Window.refresh alone.
1605 */
1606static VALUE
1607window_noutrefresh(VALUE obj)
1608{
1609    struct windata *winp;
1610
1611    GetWINDOW(obj, winp);
1612#ifdef HAVE_DOUPDATE
1613    wnoutrefresh(winp->window);
1614#else
1615    wrefresh(winp->window);
1616#endif
1617
1618    return Qnil;
1619}
1620
1621/*
1622 * Document-method: Curses::Window.move
1623 * call-seq: move(y,x)
1624 *
1625 * Moves the window so that the upper left-hand corner is at position (+y+, +x+)
1626 */
1627static VALUE
1628window_move(VALUE obj, VALUE y, VALUE x)
1629{
1630    struct windata *winp;
1631
1632    GetWINDOW(obj, winp);
1633    mvwin(winp->window, NUM2INT(y), NUM2INT(x));
1634
1635    return Qnil;
1636}
1637
1638/*
1639 * Document-method: Curses::Window.setpos
1640 * call-seq: setpos(y, x)
1641 *
1642 * A setter for the position of the cursor
1643 * in the current window,
1644 * using coordinates +x+ and +y+
1645 *
1646 */
1647static VALUE
1648window_setpos(VALUE obj, VALUE y, VALUE x)
1649{
1650    struct windata *winp;
1651
1652    GetWINDOW(obj, winp);
1653    wmove(winp->window, NUM2INT(y), NUM2INT(x));
1654    return Qnil;
1655}
1656
1657/*
1658 * Document-method: Curses::Window.cury
1659 *
1660 * A getter for the current line (Y coord) of the window
1661 */
1662static VALUE
1663window_cury(VALUE obj)
1664{
1665    struct windata *winp;
1666    int RB_UNUSED_VAR(x), y;
1667
1668    GetWINDOW(obj, winp);
1669    getyx(winp->window, y, x);
1670    return INT2FIX(y);
1671}
1672
1673/*
1674 * Document-method: Curses::Window.curx
1675 *
1676 * A getter for the current column (X coord) of the window
1677 */
1678static VALUE
1679window_curx(VALUE obj)
1680{
1681    struct windata *winp;
1682    int x, RB_UNUSED_VAR(y);
1683
1684    GetWINDOW(obj, winp);
1685    getyx(winp->window, y, x);
1686    return INT2FIX(x);
1687}
1688
1689/*
1690 * Document-method: Curses::Window.maxy
1691 *
1692 * A getter for the maximum lines for the window
1693 */
1694static VALUE
1695window_maxy(VALUE obj)
1696{
1697    struct windata *winp;
1698
1699    GetWINDOW(obj, winp);
1700#if defined(getmaxy)
1701    return INT2FIX(getmaxy(winp->window));
1702#elif defined(getmaxyx)
1703    {
1704	int x, y;
1705	getmaxyx(winp->window, y, x);
1706	return INT2FIX(y);
1707    }
1708#else
1709    return INT2FIX(winp->window->_maxy+1);
1710#endif
1711}
1712
1713/*
1714 * Document-method: Curses::Window.maxx
1715 *
1716 * A getter for the maximum columns for the window
1717 */
1718static VALUE
1719window_maxx(VALUE obj)
1720{
1721    struct windata *winp;
1722
1723    GetWINDOW(obj, winp);
1724#if defined(getmaxx)
1725    return INT2FIX(getmaxx(winp->window));
1726#elif defined(getmaxyx)
1727    {
1728	int x, y;
1729	getmaxyx(winp->window, y, x);
1730	return INT2FIX(x);
1731    }
1732#else
1733    return INT2FIX(winp->window->_maxx+1);
1734#endif
1735}
1736
1737/*
1738 * Document-method: Curses::Window.begy
1739 *
1740 * A getter for the beginning line (Y coord) of the window
1741 */
1742static VALUE
1743window_begy(VALUE obj)
1744{
1745    struct windata *winp;
1746    int RB_UNUSED_VAR(x), y;
1747
1748    GetWINDOW(obj, winp);
1749#ifdef getbegyx
1750    getbegyx(winp->window, y, x);
1751#else
1752    y = winp->window->_begy;
1753#endif
1754    return INT2FIX(y);
1755}
1756
1757/*
1758 * Document-method: Curses::Window.begx
1759 *
1760 * A getter for the beginning column (X coord) of the window
1761 */
1762static VALUE
1763window_begx(VALUE obj)
1764{
1765    struct windata *winp;
1766    int x, RB_UNUSED_VAR(y);
1767
1768    GetWINDOW(obj, winp);
1769#ifdef getbegyx
1770    getbegyx(winp->window, y, x);
1771#else
1772    x = winp->window->_begx;
1773#endif
1774    return INT2FIX(x);
1775}
1776
1777/*
1778 * Document-method: Curses::Window.box
1779 * call-seq: box(vert, hor)
1780 *
1781 * set the characters to frame the window in.
1782 * The vertical +vert+ and horizontal +hor+ character.
1783 *
1784 * 	win = Curses::Window.new(5,5,5,5)
1785 * 	win.box(?|, ?-)
1786 *
1787 */
1788static VALUE
1789window_box(int argc, VALUE *argv, VALUE self)
1790{
1791    struct windata *winp;
1792    VALUE vert, hor, corn;
1793
1794    rb_scan_args(argc, argv, "21", &vert, &hor, &corn);
1795
1796    GetWINDOW(self, winp);
1797    box(winp->window, NUM2CH(vert), NUM2CH(hor));
1798
1799    if (!NIL_P(corn)) {
1800	int cur_x, cur_y, x, y;
1801	chtype c;
1802
1803	c = NUM2CH(corn);
1804	getyx(winp->window, cur_y, cur_x);
1805	x = NUM2INT(window_maxx(self)) - 1;
1806	y = NUM2INT(window_maxy(self)) - 1;
1807	wmove(winp->window, 0, 0);
1808	waddch(winp->window, c);
1809	wmove(winp->window, y, 0);
1810	waddch(winp->window, c);
1811	wmove(winp->window, y, x);
1812	waddch(winp->window, c);
1813	wmove(winp->window, 0, x);
1814	waddch(winp->window, c);
1815	wmove(winp->window, cur_y, cur_x);
1816    }
1817
1818    return Qnil;
1819}
1820
1821/*
1822 * Document-method: Curses::Window.standout
1823 *
1824 * Enables the best highlighting mode of the terminal.
1825 *
1826 * This is equivalent to Curses::Window.attron(A_STANDOUT)
1827 *
1828 * see also Curses::Window.attrset
1829 */
1830static VALUE
1831window_standout(VALUE obj)
1832{
1833    struct windata *winp;
1834
1835    GetWINDOW(obj, winp);
1836    wstandout(winp->window);
1837    return Qnil;
1838}
1839
1840/*
1841 * Document-method: Curses::Window.standend
1842 *
1843 * Enables the Normal display (no highlight)
1844 *
1845 * This is equivalent to Curses::Window.attron(A_NORMAL)
1846 *
1847 * see also Curses::Window.attrset
1848 */
1849static VALUE
1850window_standend(VALUE obj)
1851{
1852    struct windata *winp;
1853
1854    GetWINDOW(obj, winp);
1855    wstandend(winp->window);
1856    return Qnil;
1857}
1858
1859/*
1860 * Document-method: Curses::Window.inch
1861 *
1862 * Returns the character at the current position of the window.
1863 */
1864static VALUE
1865window_inch(VALUE obj)
1866{
1867    struct windata *winp;
1868
1869    GetWINDOW(obj, winp);
1870    return CH2FIX(winch(winp->window));
1871}
1872
1873/*
1874 * Document-method: Curses::Window.addch
1875 * call-seq: addch(ch)
1876 *
1877 * Add a character +ch+, with attributes, to the window, then advance the cursor.
1878 *
1879 * see also the system manual for curs_addch(3)
1880 */
1881static VALUE
1882window_addch(VALUE obj, VALUE ch)
1883{
1884    struct windata *winp;
1885
1886    GetWINDOW(obj, winp);
1887    waddch(winp->window, NUM2CH(ch));
1888
1889    return Qnil;
1890}
1891
1892/*
1893 * Document-method: Curses::Window.insch
1894 * call-seq: insch(ch)
1895 *
1896 * Insert a character +ch+, before the cursor, in the current window
1897 *
1898 */
1899static VALUE
1900window_insch(VALUE obj, VALUE ch)
1901{
1902    struct windata *winp;
1903
1904    GetWINDOW(obj, winp);
1905    winsch(winp->window, NUM2CH(ch));
1906
1907    return Qnil;
1908}
1909
1910/*
1911 * Document-method: Curses::Window.addstr
1912 * call-seq: addstr(str)
1913 *
1914 * add a string of characters +str+, to the window and advance cursor
1915 *
1916 */
1917static VALUE
1918window_addstr(VALUE obj, VALUE str)
1919{
1920    if (!NIL_P(str)) {
1921	struct windata *winp;
1922
1923	StringValue(str);
1924	str = rb_str_export_locale(str);
1925	GetWINDOW(obj, winp);
1926	waddstr(winp->window, StringValueCStr(str));
1927    }
1928    return Qnil;
1929}
1930
1931/*
1932 * Document-method: Curses::Window.<<
1933 *
1934 * call-seq:
1935 *   <<(str)
1936 *
1937 * Add String +str+ to the current string.
1938 *
1939 * See also Curses::Window.addstr
1940 */
1941static VALUE
1942window_addstr2(VALUE obj, VALUE str)
1943{
1944    window_addstr(obj, str);
1945    return obj;
1946}
1947
1948struct wgetch_arg {
1949    WINDOW *win;
1950    int c;
1951};
1952
1953static void *
1954wgetch_func(void *_arg)
1955{
1956    struct wgetch_arg *arg = (struct wgetch_arg *)_arg;
1957    arg->c = wgetch(arg->win);
1958    return 0;
1959}
1960
1961/*
1962 * Document-method: Curses::Window.getch
1963 *
1964 * Read and returns a character from the window.
1965 *
1966 * See Curses::Key to all the function KEY_* available
1967 *
1968 */
1969static VALUE
1970window_getch(VALUE obj)
1971{
1972    struct windata *winp;
1973    struct wgetch_arg arg;
1974    int c;
1975
1976    GetWINDOW(obj, winp);
1977    arg.win = winp->window;
1978    rb_thread_call_without_gvl(wgetch_func, (void *)&arg, RUBY_UBF_IO, 0);
1979    c = arg.c;
1980    if (c == EOF) return Qnil;
1981    if (rb_isprint(c)) {
1982	char ch = (char)c;
1983
1984	return rb_locale_str_new(&ch, 1);
1985    }
1986    return UINT2NUM(c);
1987}
1988
1989struct wgetstr_arg {
1990    WINDOW *win;
1991    char rtn[GETSTR_BUF_SIZE];
1992};
1993
1994static void *
1995wgetstr_func(void *_arg)
1996{
1997    struct wgetstr_arg *arg = (struct wgetstr_arg *)_arg;
1998#if defined(HAVE_WGETNSTR)
1999    wgetnstr(arg->win, arg->rtn, GETSTR_BUF_SIZE-1);
2000#else
2001    wgetstr(arg->win, arg->rtn);
2002#endif
2003    return 0;
2004}
2005
2006/*
2007 * Document-method: Curses::Window.getstr
2008 *
2009 * This is equivalent to a series f Curses::Window.getch calls
2010 *
2011 */
2012static VALUE
2013window_getstr(VALUE obj)
2014{
2015    struct windata *winp;
2016    struct wgetstr_arg arg;
2017
2018    GetWINDOW(obj, winp);
2019    arg.win = winp->window;
2020    rb_thread_call_without_gvl(wgetstr_func, (void *)&arg, RUBY_UBF_IO, 0);
2021    return rb_locale_str_new_cstr(arg.rtn);
2022}
2023
2024/*
2025 * Document-method: Curses::Window.delch
2026 *
2027 * Delete the character under the cursor
2028 *
2029 */
2030static VALUE
2031window_delch(VALUE obj)
2032{
2033    struct windata *winp;
2034
2035    GetWINDOW(obj, winp);
2036    wdelch(winp->window);
2037    return Qnil;
2038}
2039
2040/*
2041 * Document-method: Curses::Window.deleteln
2042 *
2043 * Delete the line under the cursor.
2044 *
2045 */
2046static VALUE
2047window_deleteln(VALUE obj)
2048{
2049#if defined(HAVE_WDELETELN) || defined(wdeleteln)
2050    struct windata *winp;
2051
2052    GetWINDOW(obj, winp);
2053    wdeleteln(winp->window);
2054#endif
2055    return Qnil;
2056}
2057
2058/*
2059 * Document-method: Curses::Window.insertln
2060 *
2061 * Inserts a line above the cursor, and the bottom line is lost
2062 *
2063 */
2064static VALUE
2065window_insertln(VALUE obj)
2066{
2067#if defined(HAVE_WINSERTLN) || defined(winsertln)
2068    struct windata *winp;
2069
2070    GetWINDOW(obj, winp);
2071    winsertln(winp->window);
2072#endif
2073    return Qnil;
2074}
2075
2076/*
2077 * Document-method: Curses::Window.scrollok
2078 * call-seq: scrollok(bool)
2079 *
2080 * Controls what happens when the cursor of a window
2081 * is moved off the edge of the window or scrolling region,
2082 * either as a result of a newline action on the bottom line,
2083 * or typing the last character of the last line.
2084 *
2085 * If disabled, (+bool+ is false), the cursor is left on the bottom line.
2086 *
2087 * If enabled, (+bool+ is true), the window is scrolled up one line
2088 * (Note that to get the physical scrolling effect on the terminal,
2089 * it is also necessary to call Curses::Window.idlok)
2090 */
2091static VALUE
2092window_scrollok(VALUE obj, VALUE bf)
2093{
2094    struct windata *winp;
2095
2096    GetWINDOW(obj, winp);
2097    scrollok(winp->window, RTEST(bf) ? TRUE : FALSE);
2098    return Qnil;
2099}
2100
2101/*
2102 * Document-method: Curses::Window.idlok
2103 * call-seq: idlok(bool)
2104 *
2105 * If +bool+ is +true+ curses considers using the hardware insert/delete
2106 * line feature of terminals so equipped.
2107 *
2108 * If +bool+ is +false+, disables use of line insertion and deletion.
2109 * This option should be enabled only if the application needs insert/delete
2110 * line, for example, for a screen editor.
2111 *
2112 * It is disabled by default because insert/delete line tends to be visually
2113 * annoying when used in applications where it is not really needed.
2114 * If insert/delete line cannot be used, curses redraws the changed portions of all lines.
2115 *
2116 */
2117static VALUE
2118window_idlok(VALUE obj, VALUE bf)
2119{
2120    struct windata *winp;
2121
2122    GetWINDOW(obj, winp);
2123    idlok(winp->window, RTEST(bf) ? TRUE : FALSE);
2124    return Qnil;
2125}
2126
2127/*
2128 * Document-method: Curses::Window.setscrreg
2129 * call-seq:
2130 *   setscrreg(top, bottom)
2131 *
2132 * Set a software scrolling region in a window.
2133 * +top+ and +bottom+ are lines numbers of the margin.
2134 *
2135 * If this option and Curses::Window.scrollok are enabled, an attempt to move
2136 * off the bottom margin line causes all lines in the scrolling region to
2137 * scroll one line in the direction of the first line.  Only the text of the
2138 * window is scrolled.
2139 *
2140 */
2141static VALUE
2142window_setscrreg(VALUE obj, VALUE top, VALUE bottom)
2143{
2144#ifdef HAVE_WSETSCRREG
2145    struct windata *winp;
2146    int res;
2147
2148    GetWINDOW(obj, winp);
2149    res = wsetscrreg(winp->window, NUM2INT(top), NUM2INT(bottom));
2150    /* may have to raise exception on ERR */
2151    return (res == OK) ? Qtrue : Qfalse;
2152#else
2153    return Qfalse;
2154#endif
2155}
2156
2157#if defined(USE_COLOR) && defined(HAVE_WCOLOR_SET)
2158/*
2159 * Document-method: Curses::Window.color_set
2160 * call-seq: color_set(col)
2161 *
2162 * Sets the current color of the given window to the
2163 * foreground/background combination described by the Fixnum +col+.
2164 */
2165static VALUE
2166window_color_set(VALUE obj, VALUE col)
2167{
2168    struct windata *winp;
2169    int res;
2170
2171    GetWINDOW(obj, winp);
2172    res = wcolor_set(winp->window, NUM2INT(col), NULL);
2173    return (res == OK) ? Qtrue : Qfalse;
2174}
2175#endif /* defined(USE_COLOR) && defined(HAVE_WCOLOR_SET) */
2176
2177/*
2178 * Document-method: Curses::Window.scroll
2179 *
2180 * Scrolls the current window up one line.
2181 */
2182static VALUE
2183window_scroll(VALUE obj)
2184{
2185    struct windata *winp;
2186
2187    GetWINDOW(obj, winp);
2188    /* may have to raise exception on ERR */
2189    return (scroll(winp->window) == OK) ? Qtrue : Qfalse;
2190}
2191
2192/*
2193 * Document-method: Curses::Window.scrl
2194 * call-seq: scrl(num)
2195 *
2196 * Scrolls the current window Fixnum +num+ lines.
2197 * The current cursor position is not changed.
2198 *
2199 * For positive +num+, it scrolls up.
2200 *
2201 * For negative +num+, it scrolls down.
2202 *
2203 */
2204static VALUE
2205window_scrl(VALUE obj, VALUE n)
2206{
2207#ifdef HAVE_WSCRL
2208    struct windata *winp;
2209
2210    GetWINDOW(obj, winp);
2211    /* may have to raise exception on ERR */
2212    return (wscrl(winp->window,NUM2INT(n)) == OK) ? Qtrue : Qfalse;
2213#else
2214    return Qfalse;
2215#endif
2216}
2217
2218/*
2219 * Document-method: Curses::Window.attroff
2220 * call-seq: attroff(attrs)
2221 *
2222 * Turns on the named attributes +attrs+ without affecting any others.
2223 *
2224 * See also Curses::Window.attrset
2225 */
2226static VALUE
2227window_attroff(VALUE obj, VALUE attrs)
2228{
2229#ifdef HAVE_WATTROFF
2230    struct windata *winp;
2231
2232    GetWINDOW(obj,winp);
2233    return INT2FIX(wattroff(winp->window,NUM2INT(attrs)));
2234#else
2235    return Qtrue;
2236#endif
2237}
2238
2239/*
2240 * Document-method: Curses::Window.attron
2241 * call-seq: attron(attrs)
2242 *
2243 * Turns off the named attributes +attrs+
2244 * without turning any other attributes on or off.
2245 *
2246 * See also Curses::Window.attrset
2247 */
2248static VALUE
2249window_attron(VALUE obj, VALUE attrs)
2250{
2251#ifdef HAVE_WATTRON
2252    struct windata *winp;
2253    VALUE val;
2254
2255    GetWINDOW(obj,winp);
2256    val = INT2FIX(wattron(winp->window,NUM2INT(attrs)));
2257    if (rb_block_given_p()) {
2258	rb_yield(val);
2259	wattroff(winp->window,NUM2INT(attrs));
2260	return val;
2261    }
2262    else{
2263	return val;
2264    }
2265#else
2266    return Qtrue;
2267#endif
2268}
2269
2270/*
2271 * Document-method: Curses::Window.attrset
2272 * call-seq: attrset(attrs)
2273 *
2274 * Sets the current attributes of the given window to +attrs+.
2275 *
2276 * The following video attributes, defined in <curses.h>, can
2277 * be passed to the routines Curses::Window.attron, Curses::Window.attroff,
2278 * and Curses::Window.attrset, or OR'd with the characters passed to addch.
2279 *   A_NORMAL        Normal display (no highlight)
2280 *   A_STANDOUT      Best highlighting mode of the terminal.
2281 *   A_UNDERLINE     Underlining
2282 *   A_REVERSE       Reverse video
2283 *   A_BLINK         Blinking
2284 *   A_DIM           Half bright
2285 *   A_BOLD          Extra bright or bold
2286 *   A_PROTECT       Protected mode
2287 *   A_INVIS         Invisible or blank mode
2288 *   A_ALTCHARSET    Alternate character set
2289 *   A_CHARTEXT      Bit-mask to extract a character
2290 *   COLOR_PAIR(n)   Color-pair number n
2291 *
2292 * TODO: provide some examples here.
2293 *
2294 * see also system manual curs_attr(3)
2295 */
2296static VALUE
2297window_attrset(VALUE obj, VALUE attrs)
2298{
2299#ifdef HAVE_WATTRSET
2300    struct windata *winp;
2301
2302    GetWINDOW(obj,winp);
2303    return INT2FIX(wattrset(winp->window,NUM2INT(attrs)));
2304#else
2305    return Qtrue;
2306#endif
2307}
2308
2309/*
2310 * Document-method: Curses::Window.bkgdset
2311 * call-seq: bkgdset(ch)
2312 *
2313 * Manipulate the background of the current window
2314 * with character Integer +ch+
2315 *
2316 * see also Curses.bkgdset
2317 */
2318static VALUE
2319window_bkgdset(VALUE obj, VALUE ch)
2320{
2321#ifdef HAVE_WBKGDSET
2322    struct windata *winp;
2323
2324    GetWINDOW(obj,winp);
2325    wbkgdset(winp->window, NUM2CH(ch));
2326#endif
2327    return Qnil;
2328}
2329
2330/*
2331 * Document-method: Curses::Window.bkgd
2332 * call-seq: bkgd(ch)
2333 *
2334 * Set the background of the current window
2335 * and apply character Integer +ch+ to every character.
2336 *
2337 * see also Curses.bkgd
2338 */
2339static VALUE
2340window_bkgd(VALUE obj, VALUE ch)
2341{
2342#ifdef HAVE_WBKGD
2343    struct windata *winp;
2344
2345    GetWINDOW(obj,winp);
2346    return (wbkgd(winp->window, NUM2CH(ch)) == OK) ? Qtrue : Qfalse;
2347#else
2348    return Qfalse;
2349#endif
2350}
2351
2352/*
2353 * Document-method: Curses::Window.getbkgd
2354 *
2355 * Returns an Interer (+ch+) for the character property in the current window.
2356 */
2357static VALUE
2358window_getbkgd(VALUE obj)
2359{
2360#ifdef HAVE_WGETBKGD
2361    chtype c;
2362    struct windata *winp;
2363
2364    GetWINDOW(obj,winp);
2365    return (c = getbkgd(winp->window) != ERR) ? CH2FIX(c) : Qnil;
2366#else
2367    return Qnil;
2368#endif
2369}
2370
2371/*
2372 * Document-method: Curses::Window.resize
2373 * call-seq: resize(lines, cols)
2374 *
2375 * Resize the current window to Fixnum +lines+ and Fixnum +cols+
2376 *
2377 */
2378static VALUE
2379window_resize(VALUE obj, VALUE lin, VALUE col)
2380{
2381#if defined(HAVE_WRESIZE)
2382    struct windata *winp;
2383
2384    GetWINDOW(obj,winp);
2385    return wresize(winp->window, NUM2INT(lin), NUM2INT(col)) == OK ? Qtrue : Qfalse;
2386#else
2387    return Qnil;
2388#endif
2389}
2390
2391
2392#ifdef HAVE_KEYPAD
2393/*
2394 * Document-method: Curses::Window.keypad=
2395 * call-seq:
2396 *   keypad=(bool)
2397 *
2398 * See Curses::Window.keypad
2399 */
2400
2401/*
2402 * Document-method: Curses::Window.keypad
2403 * call-seq:
2404 *   keypad(bool)
2405 *
2406 * Enables the keypad of the user's terminal.
2407 *
2408 * If enabled (+bool+ is +true+), the user can press a function key
2409 * (such as an arrow key) and wgetch returns a single value representing
2410 * the function key, as in KEY_LEFT.  If disabled (+bool+ is +false+),
2411 * curses does not treat function keys specially and the program has to
2412 * interpret the escape sequences itself.  If the keypad in the terminal
2413 * can be turned on (made to transmit) and off (made to work locally),
2414 * turning on this option causes the terminal keypad to be turned on when
2415 * Curses::Window.getch is called.
2416 *
2417 * The default value for keypad is false.
2418 *
2419 */
2420static VALUE
2421window_keypad(VALUE obj, VALUE val)
2422{
2423    struct windata *winp;
2424
2425    GetWINDOW(obj,winp);
2426    /* keypad() of NetBSD's libcurses returns no value */
2427#if defined(__NetBSD__) && !defined(NCURSES_VERSION)
2428    keypad(winp->window,(RTEST(val) ? TRUE : FALSE));
2429    return Qnil;
2430#else
2431    /* may have to raise exception on ERR */
2432    return (keypad(winp->window,RTEST(val) ? TRUE : FALSE)) == OK ?
2433	Qtrue : Qfalse;
2434#endif
2435}
2436#else
2437#define window_keypad rb_f_notimplement
2438#endif
2439
2440#ifdef HAVE_NODELAY
2441/*
2442 * Document-method: Curses::Window.nodelay
2443 * call-seq:
2444 *   window.nodelay = bool
2445 *
2446 * When in no-delay mode Curses::Window#getch is a non-blocking call.  If no
2447 * input is ready #getch returns ERR.
2448 *
2449 * When in delay mode (+bool+ is +false+ which is the default),
2450 * Curses::Window#getch blocks until a key is pressed.
2451 *
2452 */
2453static VALUE
2454window_nodelay(VALUE obj, VALUE val)
2455{
2456    struct windata *winp;
2457    GetWINDOW(obj,winp);
2458
2459    /* nodelay() of NetBSD's libcurses returns no value */
2460#if defined(__NetBSD__) && !defined(NCURSES_VERSION)
2461    nodelay(winp->window, RTEST(val) ? TRUE : FALSE);
2462    return Qnil;
2463#else
2464    return nodelay(winp->window,RTEST(val) ? TRUE : FALSE) == OK ? Qtrue : Qfalse;
2465#endif
2466}
2467#else
2468#define window_nodelay rb_f_notimplement
2469#endif
2470
2471#ifdef HAVE_WTIMEOUT
2472/*
2473 * Document-method: Curses::Window.timeout=
2474 * call-seq: timeout=(delay)
2475 *
2476 * Sets block and non-blocking reads for the window.
2477 * - If delay is negative, blocking read is used (i.e., waits indefinitely for input).
2478 * - If delay is zero, then non-blocking read is used (i.e., read returns ERR if no input is waiting).
2479 * - If delay is positive, then read blocks for delay milliseconds, and returns ERR if there is still no input.
2480 *
2481 */
2482static VALUE
2483window_timeout(VALUE obj, VALUE delay)
2484{
2485    struct windata *winp;
2486    GetWINDOW(obj,winp);
2487
2488    wtimeout(winp->window,NUM2INT(delay));
2489    return Qnil;
2490}
2491#else
2492#define window_timeout rb_f_notimplement
2493#endif
2494
2495/*--------------------------- class Pad ----------------------------*/
2496
2497#ifdef HAVE_NEWPAD
2498/*
2499 * Document-method: Curses::Pad.new
2500 *
2501 * call-seq:
2502 *   new(height, width)
2503 *
2504 * Contruct a new Curses::Pad with constraints of +height+ lines, +width+
2505 * columns
2506 *
2507 */
2508static VALUE
2509pad_initialize(VALUE obj, VALUE h, VALUE w)
2510{
2511    struct windata *padp;
2512    WINDOW *window;
2513
2514    rb_secure(4);
2515    curses_init_screen();
2516    TypedData_Get_Struct(obj, struct windata, &windata_type, padp);
2517    if (padp->window) delwin(padp->window);
2518    window = newpad(NUM2INT(h), NUM2INT(w));
2519    wclear(window);
2520    padp->window = window;
2521
2522    return obj;
2523}
2524
2525#if 1
2526#define pad_subpad window_subwin
2527#else
2528/*
2529 * Document-method: Curses::Pad.subpad
2530 * call-seq:
2531 *   subpad(height, width, begin_x, begin_y)
2532 *
2533 * Contruct a new subpad with constraints of +height+ lines, +width+ columns,
2534 * begin at +begin_x+ line, and +begin_y+ columns on the pad.
2535 *
2536 */
2537static VALUE
2538pad_subpad(VALUE obj, VALUE height, VALUE width, VALUE begin_x, VALUE begin_y)
2539{
2540    struct windata *padp;
2541    WINDOW *subpad;
2542    VALUE pad;
2543    int h, w, x, y;
2544
2545    h = NUM2INT(height);
2546    w = NUM2INT(width);
2547    x = NUM2INT(begin_x);
2548    y = NUM2INT(begin_y);
2549    GetWINDOW(obj, padp);
2550    subpad = subwin(padp->window, h, w, x, y);
2551    pad = prep_window(rb_obj_class(obj), subpad);
2552
2553    return pad;
2554}
2555#endif
2556
2557/*
2558 * Document-method: Curses::Pad.refresh
2559 *
2560 * call-seq:
2561 *   pad.refresh(pad_minrow, pad_mincol, screen_minrow, screen_mincol, screen_maxrow, screen_maxcol)
2562 *
2563 * Refreshes the pad.  +pad_minrow+ and pad_mincol+ define the upper-left
2564 * corner of the rectangle to be displayed.  +screen_minrow+, +screen_mincol+,
2565 * +screen_maxrow+, +screen_maxcol+ define the edges of the rectangle to be
2566 * displayed on the screen.
2567 *
2568 */
2569static VALUE
2570pad_refresh(VALUE obj, VALUE pminrow, VALUE pmincol, VALUE sminrow,
2571	    VALUE smincol, VALUE smaxrow, VALUE smaxcol)
2572{
2573    struct windata *padp;
2574    int pmr, pmc, smr, smc, sxr, sxc;
2575
2576    pmr = NUM2INT(pminrow);
2577    pmc = NUM2INT(pmincol);
2578    smr = NUM2INT(sminrow);
2579    smc = NUM2INT(smincol);
2580    sxr = NUM2INT(smaxrow);
2581    sxc = NUM2INT(smaxcol);
2582
2583    GetWINDOW(obj, padp);
2584    prefresh(padp->window, pmr, pmc, smr, smc, sxr, sxc);
2585
2586    return Qnil;
2587}
2588
2589/*
2590 * Document-method: Curses::Pad.noutrefresh
2591 *
2592 * call-seq:
2593 *   pad.noutrefresh(pad_minrow, pad_mincol, screen_minrow, screen_mincol, screen_maxrow, screen_maxcol)
2594 *
2595 * Refreshes the pad.  +pad_minrow+ and pad_mincol+ define the upper-left
2596 * corner of the rectangle to be displayed.  +screen_minrow+, +screen_mincol+,
2597 * +screen_maxrow+, +screen_maxcol+ define the edges of the rectangle to be
2598 * displayed on the screen.
2599 *
2600 */
2601static VALUE
2602pad_noutrefresh(VALUE obj, VALUE pminrow, VALUE pmincol, VALUE sminrow,
2603		VALUE smincol, VALUE smaxrow, VALUE smaxcol)
2604{
2605    struct windata *padp;
2606    int pmr, pmc, smr, smc, sxr, sxc;
2607
2608    pmr = NUM2INT(pminrow);
2609    pmc = NUM2INT(pmincol);
2610    smr = NUM2INT(sminrow);
2611    smc = NUM2INT(smincol);
2612    sxr = NUM2INT(smaxrow);
2613    sxc = NUM2INT(smaxcol);
2614
2615    GetWINDOW(obj, padp);
2616#ifdef HAVE_DOUPDATE
2617    pnoutrefresh(padp->window, pmr, pmc, smr, smc, sxr, sxc);
2618#else
2619    prefresh(padp->window, pmr, pmc, smr, smc, sxr, sxc);
2620#endif
2621
2622    return Qnil;
2623}
2624#endif /* HAVE_NEWPAD */
2625
2626/*------------------------- Initialization -------------------------*/
2627
2628/*
2629 * Document-module: Curses
2630 *
2631 * == Description
2632 * An implementation of the CRT screen handling and optimization library.
2633 *
2634 * == Structures and such
2635 *
2636 * === Classes
2637 *
2638 * * Curses::Window - class with the means to draw a window or box
2639 * * Curses::MouseEvent - class for collecting mouse events
2640 *
2641 * === Modules
2642 *
2643 * Curses:: The curses implementation
2644 * Curses::Key:: Collection of constants for keypress events
2645 *
2646 * == Examples
2647 *
2648 * * hello.rb
2649 *     :include: hello.rb
2650 *
2651 *
2652 * * rain.rb
2653 *     :include: rain.rb
2654 *
2655 *
2656 */
2657void
2658Init_curses(void)
2659{
2660    mCurses    = rb_define_module("Curses");
2661
2662    /*
2663     * Document-module: Curses::Key
2664     *
2665     *
2666     * a container for the KEY_* values.
2667     *
2668     * See also system manual for getch(3)
2669     *
2670     */
2671    mKey       = rb_define_module_under(mCurses, "Key");
2672
2673    rb_gc_register_address(&rb_stdscr);
2674
2675#ifdef USE_MOUSE
2676    /*
2677     * Document-class: Curses::MouseEvent
2678     *
2679     * == Description
2680     *
2681     * Curses::MouseEvent
2682     *
2683     * == Example
2684     *
2685     * * mouse.rb
2686     *     :include: mouse.rb
2687     *
2688     */
2689    cMouseEvent = rb_define_class_under(mCurses,"MouseEvent",rb_cObject);
2690    rb_undef_method(CLASS_OF(cMouseEvent),"new");
2691    rb_define_method(cMouseEvent, "eid", curs_mouse_id, 0);
2692    rb_define_method(cMouseEvent, "x", curs_mouse_x, 0);
2693    rb_define_method(cMouseEvent, "y", curs_mouse_y, 0);
2694    rb_define_method(cMouseEvent, "z", curs_mouse_z, 0);
2695    rb_define_method(cMouseEvent, "bstate", curs_mouse_bstate, 0);
2696#endif /* USE_MOUSE */
2697
2698    rb_define_module_function(mCurses, "ESCDELAY=", curses_escdelay_set, 1);
2699    rb_define_module_function(mCurses, "ESCDELAY", curses_escdelay_get, 0);
2700    rb_define_module_function(mCurses, "TABSIZE", curses_tabsize_get, 0);
2701    rb_define_module_function(mCurses, "TABSIZE=", curses_tabsize_set, 1);
2702
2703    rb_define_module_function(mCurses, "use_default_colors", curses_use_default_colors, 0);
2704    rb_define_module_function(mCurses, "init_screen", curses_init_screen, 0);
2705    rb_define_module_function(mCurses, "close_screen", curses_close_screen, 0);
2706    rb_define_module_function(mCurses, "closed?", curses_closed, 0);
2707    rb_define_module_function(mCurses, "stdscr", curses_stdscr, 0);
2708    rb_define_module_function(mCurses, "refresh", curses_refresh, 0);
2709    rb_define_module_function(mCurses, "doupdate", curses_doupdate, 0);
2710    rb_define_module_function(mCurses, "clear", curses_clear, 0);
2711    rb_define_module_function(mCurses, "clrtoeol", curses_clrtoeol, 0);
2712    rb_define_module_function(mCurses, "echo", curses_echo, 0);
2713    rb_define_module_function(mCurses, "noecho", curses_noecho, 0);
2714    rb_define_module_function(mCurses, "raw", curses_raw, 0);
2715    rb_define_module_function(mCurses, "noraw", curses_noraw, 0);
2716    rb_define_module_function(mCurses, "cbreak", curses_cbreak, 0);
2717    rb_define_module_function(mCurses, "nocbreak", curses_nocbreak, 0);
2718    rb_define_module_function(mCurses, "crmode", curses_cbreak, 0);
2719    rb_define_module_function(mCurses, "nocrmode", curses_nocbreak, 0);
2720    rb_define_module_function(mCurses, "nl", curses_nl, 0);
2721    rb_define_module_function(mCurses, "nonl", curses_nonl, 0);
2722    rb_define_module_function(mCurses, "beep", curses_beep, 0);
2723    rb_define_module_function(mCurses, "flash", curses_flash, 0);
2724    rb_define_module_function(mCurses, "ungetch", curses_ungetch, 1);
2725    rb_define_module_function(mCurses, "setpos", curses_setpos, 2);
2726    rb_define_module_function(mCurses, "standout", curses_standout, 0);
2727    rb_define_module_function(mCurses, "standend", curses_standend, 0);
2728    rb_define_module_function(mCurses, "inch", curses_inch, 0);
2729    rb_define_module_function(mCurses, "addch", curses_addch, 1);
2730    rb_define_module_function(mCurses, "insch", curses_insch, 1);
2731    rb_define_module_function(mCurses, "addstr", curses_addstr, 1);
2732    rb_define_module_function(mCurses, "getch", curses_getch, 0);
2733    rb_define_module_function(mCurses, "getstr", curses_getstr, 0);
2734    rb_define_module_function(mCurses, "delch", curses_delch, 0);
2735    rb_define_module_function(mCurses, "deleteln", curses_deleteln, 0);
2736    rb_define_module_function(mCurses, "insertln", curses_insertln, 0);
2737    rb_define_module_function(mCurses, "keyname", curses_keyname, 1);
2738    rb_define_module_function(mCurses, "lines", curses_lines, 0);
2739    rb_define_module_function(mCurses, "cols", curses_cols, 0);
2740    rb_define_module_function(mCurses, "curs_set", curses_curs_set, 1);
2741    rb_define_module_function(mCurses, "scrl", curses_scrl, 1);
2742    rb_define_module_function(mCurses, "setscrreg", curses_setscrreg, 2);
2743    rb_define_module_function(mCurses, "attroff", curses_attroff, 1);
2744    rb_define_module_function(mCurses, "attron", curses_attron, 1);
2745    rb_define_module_function(mCurses, "attrset", curses_attrset, 1);
2746    rb_define_module_function(mCurses, "bkgdset", curses_bkgdset, 1);
2747    rb_define_module_function(mCurses, "bkgd", curses_bkgd, 1);
2748    rb_define_module_function(mCurses, "resizeterm", curses_resizeterm, 2);
2749    rb_define_module_function(mCurses, "resize", curses_resizeterm, 2);
2750#ifdef USE_COLOR
2751    rb_define_module_function(mCurses, "start_color", curses_start_color, 0);
2752    rb_define_module_function(mCurses, "init_pair", curses_init_pair, 3);
2753    rb_define_module_function(mCurses, "init_color", curses_init_color, 4);
2754    rb_define_module_function(mCurses, "has_colors?", curses_has_colors, 0);
2755    rb_define_module_function(mCurses, "can_change_color?",
2756			      curses_can_change_color, 0);
2757    rb_define_module_function(mCurses, "colors", curses_colors, 0);
2758    rb_define_module_function(mCurses, "color_content", curses_color_content, 1);
2759    rb_define_module_function(mCurses, "color_pairs", curses_color_pairs, 0);
2760    rb_define_module_function(mCurses, "pair_content", curses_pair_content, 1);
2761    rb_define_module_function(mCurses, "color_pair", curses_color_pair, 1);
2762    rb_define_module_function(mCurses, "pair_number", curses_pair_number, 1);
2763#endif /* USE_COLOR */
2764#ifdef USE_MOUSE
2765    rb_define_module_function(mCurses, "getmouse", curses_getmouse, 0);
2766    rb_define_module_function(mCurses, "ungetmouse", curses_ungetmouse, 1);
2767    rb_define_module_function(mCurses, "mouseinterval", curses_mouseinterval, 1);
2768    rb_define_module_function(mCurses, "mousemask", curses_mousemask, 1);
2769#endif /* USE_MOUSE */
2770
2771    rb_define_module_function(mCurses, "timeout=", curses_timeout, 1);
2772    rb_define_module_function(mCurses, "def_prog_mode", curses_def_prog_mode, 0);
2773    rb_define_module_function(mCurses, "reset_prog_mode", curses_reset_prog_mode, 0);
2774
2775    {
2776        VALUE version;
2777#if defined(HAVE_FUNC_CURSES_VERSION)
2778        /* ncurses and PDcurses */
2779        version = rb_str_new2(curses_version());
2780#elif defined(HAVE_VAR_CURSES_VERSION)
2781        /* SVR4 curses has an undocumented and undeclared variable, curses_version.
2782         * It contains a string, "SVR4".  */
2783        RUBY_EXTERN char *curses_version;
2784        version = rb_sprintf("curses (%s)", curses_version);
2785#else
2786        /* BSD curses, perhaps.  NetBSD 5 still use it. */
2787        version = rb_str_new2("curses (unknown)");
2788#endif
2789        /*
2790         * Identifies curses library version.
2791         *
2792         * - "ncurses 5.9.20110404"
2793         * - "PDCurses 3.4 - Public Domain 2008"
2794         * - "curses (SVR4)" (System V curses)
2795         * - "curses (unknown)" (The original BSD curses?  NetBSD maybe.)
2796         *
2797         */
2798        rb_define_const(mCurses, "VERSION", version);
2799    }
2800
2801    /*
2802     * Document-class: Curses::Window
2803     *
2804     * == Description
2805     *
2806     * The means by which to create and manage frames or windows.
2807     * While there may be more than one window at a time, only one window
2808     * will receive input.
2809     *
2810     * == Usage
2811     *
2812     *   require 'curses'
2813     *
2814     *   Curses.init_screen()
2815     *
2816     *   my_str = "LOOK! PONIES!"
2817     *   win = Curses::Window.new( 8, (my_str.length + 10),
2818     *                             (Curses.lines - 8) / 2,
2819     *                             (Curses.cols - (my_str.length + 10)) / 2 )
2820     *   win.box("|", "-")
2821     *   win.setpos(2,3)
2822     *   win.addstr(my_str)
2823     *   # or even
2824     *   win << "\nORLY"
2825     *   win << "\nYES!! " + my_str
2826     *   win.refresh
2827     *   win.getch
2828     *   win.close
2829     *
2830     */
2831    cWindow = rb_define_class_under(mCurses, "Window", rb_cData);
2832    rb_define_alloc_func(cWindow, window_s_allocate);
2833    rb_define_method(cWindow, "initialize", window_initialize, 4);
2834    rb_define_method(cWindow, "subwin", window_subwin, 4);
2835    rb_define_method(cWindow, "close", window_close, 0);
2836    rb_define_method(cWindow, "clear", window_clear, 0);
2837    rb_define_method(cWindow, "clrtoeol", window_clrtoeol, 0);
2838    rb_define_method(cWindow, "refresh", window_refresh, 0);
2839    rb_define_method(cWindow, "noutrefresh", window_noutrefresh, 0);
2840    rb_define_method(cWindow, "box", window_box, -1);
2841    rb_define_method(cWindow, "move", window_move, 2);
2842    rb_define_method(cWindow, "setpos", window_setpos, 2);
2843#if defined(USE_COLOR) && defined(HAVE_WCOLOR_SET)
2844    rb_define_method(cWindow, "color_set", window_color_set, 1);
2845#endif /* USE_COLOR && HAVE_WCOLOR_SET */
2846    rb_define_method(cWindow, "cury", window_cury, 0);
2847    rb_define_method(cWindow, "curx", window_curx, 0);
2848    rb_define_method(cWindow, "maxy", window_maxy, 0);
2849    rb_define_method(cWindow, "maxx", window_maxx, 0);
2850    rb_define_method(cWindow, "begy", window_begy, 0);
2851    rb_define_method(cWindow, "begx", window_begx, 0);
2852    rb_define_method(cWindow, "standout", window_standout, 0);
2853    rb_define_method(cWindow, "standend", window_standend, 0);
2854    rb_define_method(cWindow, "inch", window_inch, 0);
2855    rb_define_method(cWindow, "addch", window_addch, 1);
2856    rb_define_method(cWindow, "insch", window_insch, 1);
2857    rb_define_method(cWindow, "addstr", window_addstr, 1);
2858    rb_define_method(cWindow, "<<", window_addstr2, 1);
2859    rb_define_method(cWindow, "getch", window_getch, 0);
2860    rb_define_method(cWindow, "getstr", window_getstr, 0);
2861    rb_define_method(cWindow, "delch", window_delch, 0);
2862    rb_define_method(cWindow, "deleteln", window_deleteln, 0);
2863    rb_define_method(cWindow, "insertln", window_insertln, 0);
2864    rb_define_method(cWindow, "scroll", window_scroll, 0);
2865    rb_define_method(cWindow, "scrollok", window_scrollok, 1);
2866    rb_define_method(cWindow, "idlok", window_idlok, 1);
2867    rb_define_method(cWindow, "setscrreg", window_setscrreg, 2);
2868    rb_define_method(cWindow, "scrl", window_scrl, 1);
2869    rb_define_method(cWindow, "resize", window_resize, 2);
2870    rb_define_method(cWindow, "keypad", window_keypad, 1);
2871    rb_define_method(cWindow, "keypad=", window_keypad, 1);
2872
2873    rb_define_method(cWindow, "attroff", window_attroff, 1);
2874    rb_define_method(cWindow, "attron", window_attron, 1);
2875    rb_define_method(cWindow, "attrset", window_attrset, 1);
2876    rb_define_method(cWindow, "bkgdset", window_bkgdset, 1);
2877    rb_define_method(cWindow, "bkgd", window_bkgd, 1);
2878    rb_define_method(cWindow, "getbkgd", window_getbkgd, 0);
2879
2880    rb_define_method(cWindow, "nodelay=", window_nodelay, 1);
2881    rb_define_method(cWindow, "timeout=", window_timeout, 1);
2882
2883#ifdef HAVE_NEWPAD
2884    /*
2885     * Document-class: Curses::Pad
2886     *
2887     * == Description
2888     *
2889     * A Pad is like a Window but allows for scrolling of contents that cannot
2890     * fit on the screen.  Pads do not refresh automatically, use Pad#refresh
2891     * or Pad#noutrefresh instead.
2892     *
2893     */
2894    cPad = rb_define_class_under(mCurses, "Pad", cWindow);
2895    /* inherits alloc_func from cWindow */
2896    rb_define_method(cPad, "initialize", pad_initialize, 2);
2897    rb_define_method(cPad, "subpad", pad_subpad, 4);
2898    rb_define_method(cPad, "refresh", pad_refresh, 6);
2899    rb_define_method(cPad, "noutrefresh", pad_noutrefresh, 6);
2900    rb_undef_method(cPad, "subwin");
2901#endif
2902
2903#define rb_curses_define_const(c) rb_define_const(mCurses,#c,UINT2NUM(c))
2904
2905#ifdef USE_COLOR
2906    /* Document-const: A_ATTRIBUTES
2907     *
2908     * Character attribute mask:
2909     * Bit-mask to extract attributes
2910     *
2911     * See Curses.inch or Curses::Window.inch
2912     */
2913    rb_curses_define_const(A_ATTRIBUTES);
2914#ifdef A_NORMAL
2915    /* Document-const: A_NORMAL
2916     *
2917     * Attribute mask:
2918     * Normal display (no highlight)
2919     *
2920     * See Curses.attrset
2921     */
2922    rb_curses_define_const(A_NORMAL);
2923#endif
2924    /* Document-const: A_STANDOUT
2925     *
2926     * Attribute mask:
2927     * Best highlighting mode of the terminal.
2928     *
2929     * See Curses.attrset
2930     */
2931    rb_curses_define_const(A_STANDOUT);
2932    /* Document-const: A_UNDERLINE
2933     *
2934     * Attribute mask:
2935     * Underlining
2936     *
2937     * See Curses.attrset
2938     */
2939    rb_curses_define_const(A_UNDERLINE);
2940    /* Document-const: A_REVERSE
2941     *
2942     * Attribute mask:
2943     * Reverse video
2944     *
2945     * See Curses.attrset
2946     */
2947    rb_curses_define_const(A_REVERSE);
2948    /* Document-const: A_BLINK
2949     *
2950     * Attribute mask:
2951     * Blinking
2952     *
2953     * See Curses.attrset
2954     */
2955    rb_curses_define_const(A_BLINK);
2956    /* Document-const: A_DIM
2957     *
2958     * Attribute mask:
2959     * Half bright
2960     *
2961     * See Curses.attrset
2962     */
2963    rb_curses_define_const(A_DIM);
2964    /* Document-const: A_BOLD
2965     *
2966     * Attribute mask:
2967     * Extra bright or bold
2968     *
2969     * See Curses.attrset
2970     */
2971    rb_curses_define_const(A_BOLD);
2972    /* Document-const: A_PROTECT
2973     *
2974     * Attribute mask:
2975     * Protected mode
2976     *
2977     * See Curses.attrset
2978     */
2979    rb_curses_define_const(A_PROTECT);
2980#ifdef A_INVIS /* for NetBSD */
2981    /* Document-const: A_INVIS
2982     *
2983     * Attribute mask:
2984     * Invisible or blank mode
2985     *
2986     * See Curses.attrset
2987     */
2988    rb_curses_define_const(A_INVIS);
2989#endif
2990    /* Document-const: A_ALTCHARSET
2991     *
2992     * Attribute mask:
2993     * Alternate character set
2994     *
2995     * See Curses.attrset
2996     */
2997    rb_curses_define_const(A_ALTCHARSET);
2998    /* Document-const: A_CHARTEXT
2999     *
3000     * Attribute mask:
3001     * Bit-mask to extract a character
3002     *
3003     * See Curses.attrset
3004     */
3005    rb_curses_define_const(A_CHARTEXT);
3006#ifdef A_HORIZONTAL
3007    /* Document-const: A_HORIZONTAL
3008     *
3009     * Attribute mask:
3010     * horizontal highlight
3011     *
3012     * Check system curs_attr(3x) for support
3013     */
3014    rb_curses_define_const(A_HORIZONTAL);
3015#endif
3016#ifdef A_LEFT
3017    /* Document-const: A_LEFT
3018     *
3019     * Attribute mask:
3020     * left highlight
3021     *
3022     * Check system curs_attr(3x) for support
3023     */
3024    rb_curses_define_const(A_LEFT);
3025#endif
3026#ifdef A_LOW
3027    /* Document-const: A_LOW
3028     *
3029     * Attribute mask:
3030     * low highlight
3031     *
3032     * Check system curs_attr(3x) for support
3033     */
3034    rb_curses_define_const(A_LOW);
3035#endif
3036#ifdef A_RIGHT
3037    /* Document-const: A_RIGHT
3038     *
3039     * Attribute mask:
3040     * right highlight
3041     *
3042     * Check system curs_attr(3x) for support
3043     */
3044    rb_curses_define_const(A_RIGHT);
3045#endif
3046#ifdef A_TOP
3047    /* Document-const: A_TOP
3048     *
3049     * Attribute mask:
3050     * top highlight
3051     *
3052     * Check system curs_attr(3x) for support
3053     */
3054    rb_curses_define_const(A_TOP);
3055#endif
3056#ifdef A_VERTICAL
3057    /* Document-const: A_VERTICAL
3058     *
3059     * Attribute mask:
3060     * vertical highlight
3061     *
3062     * Check system curs_attr(3x) for support
3063     */
3064    rb_curses_define_const(A_VERTICAL);
3065#endif
3066    /* Document-const: A_COLOR
3067     *
3068     * Character attribute mask:
3069     * Bit-mask to extract color-pair field information
3070     *
3071     * See Curses.inch or Curses::Window.inch
3072     */
3073    rb_curses_define_const(A_COLOR);
3074
3075#ifdef COLORS
3076    /*
3077     * Document-const: Curses::COLORS
3078     *
3079     * Number of the colors available
3080     */
3081    rb_curses_define_const(COLORS);
3082#endif
3083    /*
3084     * Document-const: Curses::COLOR_BLACK
3085     *
3086     * Value of the color black
3087     */
3088    rb_curses_define_const(COLOR_BLACK);
3089    /*
3090     * Document-const: COLOR_RED
3091     *
3092     * Value of the color red
3093     */
3094    rb_curses_define_const(COLOR_RED);
3095    /*
3096     * Document-const: COLOR_GREEN
3097     *
3098     * Value of the color green
3099     */
3100    rb_curses_define_const(COLOR_GREEN);
3101    /*
3102     * Document-const: COLOR_YELLOW
3103     *
3104     * Value of the color yellow
3105     */
3106    rb_curses_define_const(COLOR_YELLOW);
3107    /*
3108     * Document-const: COLOR_BLUE
3109     *
3110     * Value of the color blue
3111     */
3112    rb_curses_define_const(COLOR_BLUE);
3113    /*
3114     * Document-const: COLOR_MAGENTA
3115     *
3116     * Value of the color magenta
3117     */
3118    rb_curses_define_const(COLOR_MAGENTA);
3119    /*
3120     * Document-const: COLOR_CYAN
3121     *
3122     * Value of the color cyan
3123     */
3124    rb_curses_define_const(COLOR_CYAN);
3125    /*
3126     * Document-const: COLOR_WHITE
3127     *
3128     * Value of the color white
3129     */
3130    rb_curses_define_const(COLOR_WHITE);
3131#endif /* USE_COLOR */
3132#ifdef USE_MOUSE
3133#ifdef BUTTON1_PRESSED
3134    /* Document-const: BUTTON1_PRESSED
3135     *
3136     * Mouse event mask:
3137     * mouse button 1 down
3138     *
3139     * See Curses.getmouse
3140     */
3141    rb_curses_define_const(BUTTON1_PRESSED);
3142#endif
3143#ifdef BUTTON1_RELEASED
3144    /* Document-const: BUTTON1_RELEASED
3145     *
3146     * Mouse event mask:
3147     * mouse button 1 up
3148     *
3149     * See Curses.getmouse
3150     */
3151    rb_curses_define_const(BUTTON1_RELEASED);
3152#endif
3153#ifdef BUTTON1_CLICKED
3154    /* Document-const: BUTTON1_CLICKED
3155     *
3156     * Mouse event mask:
3157     * mouse button 1 clicked
3158     *
3159     * See Curses.getmouse
3160     */
3161    rb_curses_define_const(BUTTON1_CLICKED);
3162#endif
3163#ifdef BUTTON1_DOUBLE_CLICKED
3164    /* Document-const: BUTTON1_DOUBLE_CLICKED
3165     *
3166     * Mouse event mask:
3167     * mouse button 1 double clicked
3168     *
3169     * See Curses.getmouse
3170     */
3171    rb_curses_define_const(BUTTON1_DOUBLE_CLICKED);
3172#endif
3173#ifdef BUTTON1_TRIPLE_CLICKED
3174    /* Document-const: BUTTON1_TRIPLE_CLICKED
3175     *
3176     * Mouse event mask:
3177     * mouse button 1 triple clicked
3178     *
3179     * See Curses.getmouse
3180     */
3181    rb_curses_define_const(BUTTON1_TRIPLE_CLICKED);
3182#endif
3183#ifdef BUTTON2_PRESSED
3184    /* Document-const: BUTTON2_PRESSED
3185     *
3186     * Mouse event mask:
3187     * mouse button 2 down
3188     *
3189     * See Curses.getmouse
3190     */
3191    rb_curses_define_const(BUTTON2_PRESSED);
3192#endif
3193#ifdef BUTTON2_RELEASED
3194    /* Document-const: BUTTON2_RELEASED
3195     *
3196     * Mouse event mask:
3197     * mouse button 2 up
3198     *
3199     * See Curses.getmouse
3200     */
3201    rb_curses_define_const(BUTTON2_RELEASED);
3202#endif
3203#ifdef BUTTON2_CLICKED
3204    /* Document-const: BUTTON2_CLICKED
3205     *
3206     * Mouse event mask:
3207     * mouse button 2 clicked
3208     *
3209     * See Curses.getmouse
3210     */
3211    rb_curses_define_const(BUTTON2_CLICKED);
3212#endif
3213#ifdef BUTTON2_DOUBLE_CLICKED
3214    /* Document-const: BUTTON2_DOUBLE_CLICKED
3215     *
3216     * Mouse event mask:
3217     * mouse button 2 double clicked
3218     *
3219     * See Curses.getmouse
3220     */
3221    rb_curses_define_const(BUTTON2_DOUBLE_CLICKED);
3222#endif
3223#ifdef BUTTON2_TRIPLE_CLICKED
3224    /* Document-const: BUTTON2_TRIPLE_CLICKED
3225     *
3226     * Mouse event mask:
3227     * mouse button 2 triple clicked
3228     *
3229     * See Curses.getmouse
3230     */
3231    rb_curses_define_const(BUTTON2_TRIPLE_CLICKED);
3232#endif
3233#ifdef BUTTON3_PRESSED
3234    /* Document-const: BUTTON3_PRESSED
3235     *
3236     * Mouse event mask:
3237     * mouse button 3 down
3238     *
3239     * See Curses.getmouse
3240     */
3241    rb_curses_define_const(BUTTON3_PRESSED);
3242#endif
3243#ifdef BUTTON3_RELEASED
3244    /* Document-const: BUTTON3_RELEASED
3245     *
3246     * Mouse event mask:
3247     * mouse button 3 up
3248     *
3249     * See Curses.getmouse
3250     */
3251    rb_curses_define_const(BUTTON3_RELEASED);
3252#endif
3253#ifdef BUTTON3_CLICKED
3254    /* Document-const: BUTTON3_CLICKED
3255     *
3256     * Mouse event mask:
3257     * mouse button 3 clicked
3258     *
3259     * See Curses.getmouse
3260     */
3261    rb_curses_define_const(BUTTON3_CLICKED);
3262#endif
3263#ifdef BUTTON3_DOUBLE_CLICKED
3264    /* Document-const: BUTTON3_DOUBLE_CLICKED
3265     *
3266     * Mouse event mask:
3267     * mouse button 3 double clicked
3268     *
3269     * See Curses.getmouse
3270     */
3271    rb_curses_define_const(BUTTON3_DOUBLE_CLICKED);
3272#endif
3273#ifdef BUTTON3_TRIPLE_CLICKED
3274    /* Document-const: BUTTON3_TRIPLE_CLICKED
3275     *
3276     * Mouse event mask:
3277     * mouse button 3 triple clicked
3278     *
3279     * See Curses.getmouse
3280     */
3281    rb_curses_define_const(BUTTON3_TRIPLE_CLICKED);
3282#endif
3283#ifdef BUTTON4_PRESSED
3284    /* Document-const: BUTTON4_PRESSED
3285     *
3286     * Mouse event mask:
3287     * mouse button 4 down
3288     *
3289     * See Curses.getmouse
3290     */
3291    rb_curses_define_const(BUTTON4_PRESSED);
3292#endif
3293#ifdef BUTTON4_RELEASED
3294    /* Document-const: BUTTON4_RELEASED
3295     *
3296     * Mouse event mask:
3297     * mouse button 4 up
3298     *
3299     * See Curses.getmouse
3300     */
3301    rb_curses_define_const(BUTTON4_RELEASED);
3302#endif
3303#ifdef BUTTON4_CLICKED
3304    /* Document-const: BUTTON4_CLICKED
3305     *
3306     * Mouse event mask:
3307     * mouse button 4 clicked
3308     *
3309     * See Curses.getmouse
3310     */
3311    rb_curses_define_const(BUTTON4_CLICKED);
3312#endif
3313#ifdef BUTTON4_DOUBLE_CLICKED
3314    /* Document-const: BUTTON4_DOUBLE_CLICKED
3315     *
3316     * Mouse event mask:
3317     * mouse button 4 double clicked
3318     *
3319     * See Curses.getmouse
3320     */
3321    rb_curses_define_const(BUTTON4_DOUBLE_CLICKED);
3322#endif
3323#ifdef BUTTON4_TRIPLE_CLICKED
3324    /* Document-const: BUTTON4_TRIPLE_CLICKED
3325     *
3326     * Mouse event mask:
3327     * mouse button 4 triple clicked
3328     *
3329     * See Curses.getmouse
3330     */
3331    rb_curses_define_const(BUTTON4_TRIPLE_CLICKED);
3332#endif
3333#ifdef BUTTON_SHIFT
3334    /* Document-const: BUTTON_SHIFT
3335     *
3336     * Mouse event mask:
3337     * shift was down during button state change
3338     *
3339     * See Curses.getmouse
3340     */
3341    rb_curses_define_const(BUTTON_SHIFT);
3342#endif
3343#ifdef BUTTON_CTRL
3344    /* Document-const: BUTTON_CTRL
3345     *
3346     * Mouse event mask:
3347     * control was down during button state change
3348     *
3349     * See Curses.getmouse
3350     */
3351    rb_curses_define_const(BUTTON_CTRL);
3352#endif
3353#ifdef BUTTON_ALT
3354    /* Document-const: BUTTON_ALT
3355     *
3356     * Mouse event mask:
3357     * alt was down during button state change
3358     *
3359     * See Curses.getmouse
3360     */
3361    rb_curses_define_const(BUTTON_ALT);
3362#endif
3363#ifdef ALL_MOUSE_EVENTS
3364    /* Document-const: ALL_MOUSE_EVENTS
3365     *
3366     * Mouse event mask:
3367     * report all button state changes
3368     *
3369     * See Curses.getmouse
3370     */
3371    rb_curses_define_const(ALL_MOUSE_EVENTS);
3372#endif
3373#ifdef REPORT_MOUSE_POSITION
3374    /* Document-const: REPORT_MOUSE_POSITION
3375     *
3376     * Mouse event mask:
3377     * report mouse movement
3378     *
3379     * See Curses.getmouse
3380     */
3381    rb_curses_define_const(REPORT_MOUSE_POSITION);
3382#endif
3383#endif /* USE_MOUSE */
3384
3385#if defined(KEY_MOUSE) && defined(USE_MOUSE)
3386    /* Document-const: KEY_MOUSE
3387     * Mouse event read
3388     */
3389    /* Document-const: MOUSE
3390     * Mouse event read
3391     */
3392    rb_curses_define_const(KEY_MOUSE);
3393    rb_define_const(mKey, "MOUSE", INT2NUM(KEY_MOUSE));
3394#endif
3395#ifdef KEY_MIN
3396    /* Document-const: KEY_MIN
3397     * The minimum allowed curses key value.
3398     */
3399    /* Document-const: MIN
3400     * The minimum allowed curses key value.
3401     */
3402    rb_curses_define_const(KEY_MIN);
3403    rb_define_const(mKey, "MIN", INT2NUM(KEY_MIN));
3404#endif
3405#ifdef KEY_BREAK
3406    /* Document-const: KEY_BREAK
3407     * Break key
3408     */
3409    /* Document-const: BREAK
3410     * Break key
3411     */
3412    rb_curses_define_const(KEY_BREAK);
3413    rb_define_const(mKey, "BREAK", INT2NUM(KEY_BREAK));
3414#endif
3415#ifdef KEY_DOWN
3416    /* Document-const: KEY_DOWN
3417     * the down arrow key
3418     */
3419    /* Document-const: DOWN
3420     * the down arrow key
3421     */
3422    rb_curses_define_const(KEY_DOWN);
3423    rb_define_const(mKey, "DOWN", INT2NUM(KEY_DOWN));
3424#endif
3425#ifdef KEY_UP
3426    /* Document-const: KEY_UP
3427     * the up arrow key
3428     */
3429    /* Document-const: UP
3430     * the up arrow key
3431     */
3432    rb_curses_define_const(KEY_UP);
3433    rb_define_const(mKey, "UP", INT2NUM(KEY_UP));
3434#endif
3435#ifdef KEY_LEFT
3436    /* Document-const: KEY_LEFT
3437     * the left arrow key
3438     */
3439    /* Document-const: LEFT
3440     * the left arrow key
3441     */
3442    rb_curses_define_const(KEY_LEFT);
3443    rb_define_const(mKey, "LEFT", INT2NUM(KEY_LEFT));
3444#endif
3445#ifdef KEY_RIGHT
3446    /* Document-const: KEY_RIGHT
3447     * the right arrow key
3448     */
3449    /* Document-const: RIGHT
3450     * the right arrow key
3451     */
3452    rb_curses_define_const(KEY_RIGHT);
3453    rb_define_const(mKey, "RIGHT", INT2NUM(KEY_RIGHT));
3454#endif
3455#ifdef KEY_HOME
3456    /* Document-const: KEY_HOME
3457     * Home key (upward+left arrow)
3458     */
3459    /* Document-const: HOME
3460     * Home key (upward+left arrow)
3461     */
3462    rb_curses_define_const(KEY_HOME);
3463    rb_define_const(mKey, "HOME", INT2NUM(KEY_HOME));
3464#endif
3465#ifdef KEY_BACKSPACE
3466    /* Document-const: KEY_BACKSPACE
3467     * Backspace
3468     */
3469    /* Document-const: BACKSPACE
3470     * Backspace
3471     */
3472    rb_curses_define_const(KEY_BACKSPACE);
3473    rb_define_const(mKey, "BACKSPACE", INT2NUM(KEY_BACKSPACE));
3474#endif
3475#ifdef KEY_F
3476    /* KEY_F(n) : 0 <= n <= 63 */
3477    {
3478	int i;
3479	char c[8];
3480	for (i=0; i<64; i++) {
3481	    sprintf(c, "KEY_F%d", i);
3482	    rb_define_const(mCurses, c, INT2NUM(KEY_F(i)));
3483	    sprintf(c, "F%d", i);
3484	    rb_define_const(mKey, c, INT2NUM(KEY_F(i)));
3485	}
3486    }
3487#endif
3488#ifdef KEY_DL
3489    /* Document-const: KEY_DL
3490     * Delete line
3491     */
3492    /* Document-const: DL
3493     * Delete line
3494     */
3495    rb_curses_define_const(KEY_DL);
3496    rb_define_const(mKey, "DL", INT2NUM(KEY_DL));
3497#endif
3498#ifdef KEY_IL
3499    /* Document-const: KEY_IL
3500     * Insert line
3501     */
3502    /* Document-const: IL
3503     * Insert line
3504     */
3505    rb_curses_define_const(KEY_IL);
3506    rb_define_const(mKey, "IL", INT2NUM(KEY_IL));
3507#endif
3508#ifdef KEY_DC
3509    /* Document-const: KEY_DC
3510     * Delete character
3511     */
3512    /* Document-const: DC
3513     * Delete character
3514     */
3515    rb_curses_define_const(KEY_DC);
3516    rb_define_const(mKey, "DC", INT2NUM(KEY_DC));
3517#endif
3518#ifdef KEY_IC
3519    /* Document-const: KEY_IC
3520     * Insert char or enter insert mode
3521     */
3522    /* Document-const: IC
3523     * Insert char or enter insert mode
3524     */
3525    rb_curses_define_const(KEY_IC);
3526    rb_define_const(mKey, "IC", INT2NUM(KEY_IC));
3527#endif
3528#ifdef KEY_EIC
3529    /* Document-const: KEY_EIC
3530     * Enter insert char mode
3531     */
3532    /* Document-const: EIC
3533     * Enter insert char mode
3534     */
3535    rb_curses_define_const(KEY_EIC);
3536    rb_define_const(mKey, "EIC", INT2NUM(KEY_EIC));
3537#endif
3538#ifdef KEY_CLEAR
3539    /* Document-const: KEY_CLEAR
3540     * Clear Screen
3541     */
3542    /* Document-const: CLEAR
3543     * Clear Screen
3544     */
3545    rb_curses_define_const(KEY_CLEAR);
3546    rb_define_const(mKey, "CLEAR", INT2NUM(KEY_CLEAR));
3547#endif
3548#ifdef KEY_EOS
3549    /* Document-const: KEY_EOS
3550     * Clear to end of screen
3551     */
3552    /* Document-const: EOS
3553     * Clear to end of screen
3554     */
3555    rb_curses_define_const(KEY_EOS);
3556    rb_define_const(mKey, "EOS", INT2NUM(KEY_EOS));
3557#endif
3558#ifdef KEY_EOL
3559    /* Document-const: KEY_EOL
3560     * Clear to end of line
3561     */
3562    /* Document-const: EOL
3563     * Clear to end of line
3564     */
3565    rb_curses_define_const(KEY_EOL);
3566    rb_define_const(mKey, "EOL", INT2NUM(KEY_EOL));
3567#endif
3568#ifdef KEY_SF
3569    /* Document-const: KEY_SF
3570     * Scroll 1 line forward
3571     */
3572    /* Document-const: SF
3573     * Scroll 1 line forward
3574     */
3575    rb_curses_define_const(KEY_SF);
3576    rb_define_const(mKey, "SF", INT2NUM(KEY_SF));
3577#endif
3578#ifdef KEY_SR
3579    /* Document-const: KEY_SR
3580     * Scroll 1 line backware (reverse)
3581     */
3582    /* Document-const: SR
3583     * Scroll 1 line backware (reverse)
3584     */
3585    rb_curses_define_const(KEY_SR);
3586    rb_define_const(mKey, "SR", INT2NUM(KEY_SR));
3587#endif
3588#ifdef KEY_NPAGE
3589    /* Document-const: KEY_NPAGE
3590     * Next page
3591     */
3592    /* Document-const: NPAGE
3593     * Next page
3594     */
3595    rb_curses_define_const(KEY_NPAGE);
3596    rb_define_const(mKey, "NPAGE", INT2NUM(KEY_NPAGE));
3597#endif
3598#ifdef KEY_PPAGE
3599    /* Document-const: KEY_PPAGE
3600     * Previous page
3601     */
3602    /* Document-const: PPAGE
3603     * Previous page
3604     */
3605    rb_curses_define_const(KEY_PPAGE);
3606    rb_define_const(mKey, "PPAGE", INT2NUM(KEY_PPAGE));
3607#endif
3608#ifdef KEY_STAB
3609    /* Document-const: KEY_STAB
3610     * Set tab
3611     */
3612    /* Document-const: STAB
3613     * Set tab
3614     */
3615    rb_curses_define_const(KEY_STAB);
3616    rb_define_const(mKey, "STAB", INT2NUM(KEY_STAB));
3617#endif
3618#ifdef KEY_CTAB
3619    /* Document-const: KEY_CTAB
3620     * Clear tab
3621     */
3622    /* Document-const: CTAB
3623     * Clear tab
3624     */
3625    rb_curses_define_const(KEY_CTAB);
3626    rb_define_const(mKey, "CTAB", INT2NUM(KEY_CTAB));
3627#endif
3628#ifdef KEY_CATAB
3629    /* Document-const: KEY_CATAB
3630     * Clear all tabs
3631     */
3632    /* Document-const: CATAB
3633     * Clear all tabs
3634     */
3635    rb_curses_define_const(KEY_CATAB);
3636    rb_define_const(mKey, "CATAB", INT2NUM(KEY_CATAB));
3637#endif
3638#ifdef KEY_ENTER
3639    /* Document-const: KEY_ENTER
3640     * Enter or send
3641     */
3642    /* Document-const: ENTER
3643     * Enter or send
3644     */
3645    rb_curses_define_const(KEY_ENTER);
3646    rb_define_const(mKey, "ENTER", INT2NUM(KEY_ENTER));
3647#endif
3648#ifdef KEY_SRESET
3649    /* Document-const: KEY_SRESET
3650     * Soft (partial) reset
3651     */
3652    /* Document-const: SRESET
3653     * Soft (partial) reset
3654     */
3655    rb_curses_define_const(KEY_SRESET);
3656    rb_define_const(mKey, "SRESET", INT2NUM(KEY_SRESET));
3657#endif
3658#ifdef KEY_RESET
3659    /* Document-const: KEY_RESET
3660     * Reset or hard reset
3661     */
3662    /* Document-const: RESET
3663     * Reset or hard reset
3664     */
3665    rb_curses_define_const(KEY_RESET);
3666    rb_define_const(mKey, "RESET", INT2NUM(KEY_RESET));
3667#endif
3668#ifdef KEY_PRINT
3669    /* Document-const: KEY_PRINT
3670     * Print or copy
3671     */
3672    /* Document-const: PRINT
3673     * Print or copy
3674     */
3675    rb_curses_define_const(KEY_PRINT);
3676    rb_define_const(mKey, "PRINT", INT2NUM(KEY_PRINT));
3677#endif
3678#ifdef KEY_LL
3679    /* Document-const: KEY_LL
3680     * Home down or bottom (lower left)
3681     */
3682    /* Document-const: LL
3683     * Home down or bottom (lower left)
3684     */
3685    rb_curses_define_const(KEY_LL);
3686    rb_define_const(mKey, "LL", INT2NUM(KEY_LL));
3687#endif
3688#ifdef KEY_A1
3689    /* Document-const: KEY_A1
3690     * Upper left of keypad
3691     */
3692    /* Document-const: A1
3693     * Upper left of keypad
3694     */
3695    rb_curses_define_const(KEY_A1);
3696    rb_define_const(mKey, "A1", INT2NUM(KEY_A1));
3697#endif
3698#ifdef KEY_A3
3699    /* Document-const: KEY_A3
3700     * Upper right of keypad
3701     */
3702    /* Document-const: A3
3703     * Upper right of keypad
3704     */
3705    rb_curses_define_const(KEY_A3);
3706    rb_define_const(mKey, "A3", INT2NUM(KEY_A3));
3707#endif
3708#ifdef KEY_B2
3709    /* Document-const: KEY_B2
3710     * Center of keypad
3711     */
3712    /* Document-const: B2
3713     * Center of keypad
3714     */
3715    rb_curses_define_const(KEY_B2);
3716    rb_define_const(mKey, "B2", INT2NUM(KEY_B2));
3717#endif
3718#ifdef KEY_C1
3719    /* Document-const: KEY_C1
3720     * Lower left of keypad
3721     */
3722    /* Document-const: C1
3723     * Lower left of keypad
3724     */
3725    rb_curses_define_const(KEY_C1);
3726    rb_define_const(mKey, "C1", INT2NUM(KEY_C1));
3727#endif
3728#ifdef KEY_C3
3729    /* Document-const: KEY_C3
3730     * Lower right of keypad
3731     */
3732    /* Document-const: C3
3733     * Lower right of keypad
3734     */
3735    rb_curses_define_const(KEY_C3);
3736    rb_define_const(mKey, "C3", INT2NUM(KEY_C3));
3737#endif
3738#ifdef KEY_BTAB
3739    /* Document-const: BTAB
3740     * Back tab key
3741     */
3742    /* Document-const: KEY_BTAB
3743     * Back tab key
3744     */
3745    rb_curses_define_const(KEY_BTAB);
3746    rb_define_const(mKey, "BTAB", INT2NUM(KEY_BTAB));
3747#endif
3748#ifdef KEY_BEG
3749    /* Document-const: KEY_BEG
3750     * Beginning key
3751     */
3752    /* Document-const: BEG
3753     * Beginning key
3754     */
3755    rb_curses_define_const(KEY_BEG);
3756    rb_define_const(mKey, "BEG", INT2NUM(KEY_BEG));
3757#endif
3758#ifdef KEY_CANCEL
3759    /* Document-const: KEY_CANCEL
3760     * Cancel key
3761     */
3762    /* Document-const: CANCEL
3763     * Cancel key
3764     */
3765    rb_curses_define_const(KEY_CANCEL);
3766    rb_define_const(mKey, "CANCEL", INT2NUM(KEY_CANCEL));
3767#endif
3768#ifdef KEY_CLOSE
3769    /* Document-const: KEY_CLOSE
3770     * Close key
3771     */
3772    /* Document-const: CLOSE
3773     * Close key
3774     */
3775    rb_curses_define_const(KEY_CLOSE);
3776    rb_define_const(mKey, "CLOSE", INT2NUM(KEY_CLOSE));
3777#endif
3778#ifdef KEY_COMMAND
3779    /* Document-const: KEY_COMMAND
3780     * Cmd (command) key
3781     */
3782    /* Document-const: COMMAND
3783     * Cmd (command) key
3784     */
3785    rb_curses_define_const(KEY_COMMAND);
3786    rb_define_const(mKey, "COMMAND", INT2NUM(KEY_COMMAND));
3787#endif
3788#ifdef KEY_COPY
3789    /* Document-const: KEY_COPY
3790     * Copy key
3791     */
3792    /* Document-const: COPY
3793     * Copy key
3794     */
3795    rb_curses_define_const(KEY_COPY);
3796    rb_define_const(mKey, "COPY", INT2NUM(KEY_COPY));
3797#endif
3798#ifdef KEY_CREATE
3799    /* Document-const: KEY_CREATE
3800     * Create key
3801     */
3802    /* Document-const: CREATE
3803     * Create key
3804     */
3805    rb_curses_define_const(KEY_CREATE);
3806    rb_define_const(mKey, "CREATE", INT2NUM(KEY_CREATE));
3807#endif
3808#ifdef KEY_END
3809    /* Document-const: KEY_END
3810     * End key
3811     */
3812    /* Document-const: END
3813     * End key
3814     */
3815    rb_curses_define_const(KEY_END);
3816    rb_define_const(mKey, "END", INT2NUM(KEY_END));
3817#endif
3818#ifdef KEY_EXIT
3819    /* Document-const: KEY_EXIT
3820     * Exit key
3821     */
3822    /* Document-const: EXIT
3823     * Exit key
3824     */
3825    rb_curses_define_const(KEY_EXIT);
3826    rb_define_const(mKey, "EXIT", INT2NUM(KEY_EXIT));
3827#endif
3828#ifdef KEY_FIND
3829    /* Document-const: KEY_FIND
3830     * Find key
3831     */
3832    /* Document-const: FIND
3833     * Find key
3834     */
3835    rb_curses_define_const(KEY_FIND);
3836    rb_define_const(mKey, "FIND", INT2NUM(KEY_FIND));
3837#endif
3838#ifdef KEY_HELP
3839    /* Document-const: KEY_HELP
3840     * Help key
3841     */
3842    /* Document-const: HELP
3843     * Help key
3844     */
3845    rb_curses_define_const(KEY_HELP);
3846    rb_define_const(mKey, "HELP", INT2NUM(KEY_HELP));
3847#endif
3848#ifdef KEY_MARK
3849    /* Document-const: KEY_MARK
3850     * Mark key
3851     */
3852    /* Document-const: MARK
3853     * Mark key
3854     */
3855    rb_curses_define_const(KEY_MARK);
3856    rb_define_const(mKey, "MARK", INT2NUM(KEY_MARK));
3857#endif
3858#ifdef KEY_MESSAGE
3859    /* Document-const: KEY_MESSAGE
3860     * Message key
3861     */
3862    /* Document-const: MESSAGE
3863     * Message key
3864     */
3865    rb_curses_define_const(KEY_MESSAGE);
3866    rb_define_const(mKey, "MESSAGE", INT2NUM(KEY_MESSAGE));
3867#endif
3868#ifdef KEY_MOVE
3869    /* Document-const: KEY_MOVE
3870     * Move key
3871     */
3872    /* Document-const: MOVE
3873     * Move key
3874     */
3875    rb_curses_define_const(KEY_MOVE);
3876    rb_define_const(mKey, "MOVE", INT2NUM(KEY_MOVE));
3877#endif
3878#ifdef KEY_NEXT
3879    /* Document-const: KEY_NEXT
3880     * Next object key
3881     */
3882    /* Document-const: NEXT
3883     * Next object key
3884     */
3885    rb_curses_define_const(KEY_NEXT);
3886    rb_define_const(mKey, "NEXT", INT2NUM(KEY_NEXT));
3887#endif
3888#ifdef KEY_OPEN
3889    /* Document-const: KEY_OPEN
3890     * Open key
3891     */
3892    /* Document-const: OPEN
3893     * Open key
3894     */
3895    rb_curses_define_const(KEY_OPEN);
3896    rb_define_const(mKey, "OPEN", INT2NUM(KEY_OPEN));
3897#endif
3898#ifdef KEY_OPTIONS
3899    /* Document-const: KEY_OPTIONS
3900     * Options key
3901     */
3902    /* Document-const: OPTIONS
3903     * Options key
3904     */
3905    rb_curses_define_const(KEY_OPTIONS);
3906    rb_define_const(mKey, "OPTIONS", INT2NUM(KEY_OPTIONS));
3907#endif
3908#ifdef KEY_PREVIOUS
3909    /* Document-const: KEY_PREVIOUS
3910     * Previous object key
3911     */
3912    /* Document-const: PREVIOUS
3913     * Previous object key
3914     */
3915    rb_curses_define_const(KEY_PREVIOUS);
3916    rb_define_const(mKey, "PREVIOUS", INT2NUM(KEY_PREVIOUS));
3917#endif
3918#ifdef KEY_REDO
3919    /* Document-const: KEY_REDO
3920     * Redo key
3921     */
3922    /* Document-const: REDO
3923     * Redo key
3924     */
3925    rb_curses_define_const(KEY_REDO);
3926    rb_define_const(mKey, "REDO", INT2NUM(KEY_REDO));
3927#endif
3928#ifdef KEY_REFERENCE
3929    /* Document-const: KEY_REFERENCE
3930     * Reference key
3931     */
3932    /* Document-const: REFERENCE
3933     * Reference key
3934     */
3935    rb_curses_define_const(KEY_REFERENCE);
3936    rb_define_const(mKey, "REFERENCE", INT2NUM(KEY_REFERENCE));
3937#endif
3938#ifdef KEY_REFRESH
3939    /* Document-const: KEY_REFRESH
3940     * Refresh key
3941     */
3942    /* Document-const: REFRESH
3943     * Refresh key
3944     */
3945    rb_curses_define_const(KEY_REFRESH);
3946    rb_define_const(mKey, "REFRESH", INT2NUM(KEY_REFRESH));
3947#endif
3948#ifdef KEY_REPLACE
3949    /* Document-const: KEY_REPLACE
3950     * Replace key
3951     */
3952    /* Document-const: REPLACE
3953     * Replace key
3954     */
3955    rb_curses_define_const(KEY_REPLACE);
3956    rb_define_const(mKey, "REPLACE", INT2NUM(KEY_REPLACE));
3957#endif
3958#ifdef KEY_RESTART
3959    /* Document-const: KEY_RESTART
3960     * Restart key
3961     */
3962    /* Document-const: RESTART
3963     * Restart key
3964     */
3965    rb_curses_define_const(KEY_RESTART);
3966    rb_define_const(mKey, "RESTART", INT2NUM(KEY_RESTART));
3967#endif
3968#ifdef KEY_RESUME
3969    /* Document-const: KEY_RESUME
3970     * Resume key
3971     */
3972    /* Document-const: RESUME
3973     * Resume key
3974     */
3975    rb_curses_define_const(KEY_RESUME);
3976    rb_define_const(mKey, "RESUME", INT2NUM(KEY_RESUME));
3977#endif
3978#ifdef KEY_SAVE
3979    /* Document-const: KEY_SAVE
3980     * Save key
3981     */
3982    /* Document-const: SAVE
3983     * Save key
3984     */
3985    rb_curses_define_const(KEY_SAVE);
3986    rb_define_const(mKey, "SAVE", INT2NUM(KEY_SAVE));
3987#endif
3988#ifdef KEY_SBEG
3989    /* Document-const: KEY_SBEG
3990     * Shifted beginning key
3991     */
3992    /* Document-const: SBEG
3993     * Shifted beginning key
3994     */
3995    rb_curses_define_const(KEY_SBEG);
3996    rb_define_const(mKey, "SBEG", INT2NUM(KEY_SBEG));
3997#endif
3998#ifdef KEY_SCANCEL
3999    /* Document-const: KEY_SCANCEL
4000     * Shifted cancel key
4001     */
4002    /* Document-const: SCANCEL
4003     * Shifted cancel key
4004     */
4005    rb_curses_define_const(KEY_SCANCEL);
4006    rb_define_const(mKey, "SCANCEL", INT2NUM(KEY_SCANCEL));
4007#endif
4008#ifdef KEY_SCOMMAND
4009    /* Document-const: KEY_SCOMMAND
4010     * Shifted command key
4011     */
4012    /* Document-const: SCOMMAND
4013     * Shifted command key
4014     */
4015    rb_curses_define_const(KEY_SCOMMAND);
4016    rb_define_const(mKey, "SCOMMAND", INT2NUM(KEY_SCOMMAND));
4017#endif
4018#ifdef KEY_SCOPY
4019    /* Document-const: KEY_SCOPY
4020     * Shifted copy key
4021     */
4022    /* Document-const: SCOPY
4023     * Shifted copy key
4024     */
4025    rb_curses_define_const(KEY_SCOPY);
4026    rb_define_const(mKey, "SCOPY", INT2NUM(KEY_SCOPY));
4027#endif
4028#ifdef KEY_SCREATE
4029    /* Document-const: KEY_SCREATE
4030     * Shifted create key
4031     */
4032    /* Document-const: SCREATE
4033     * Shifted create key
4034     */
4035    rb_curses_define_const(KEY_SCREATE);
4036    rb_define_const(mKey, "SCREATE", INT2NUM(KEY_SCREATE));
4037#endif
4038#ifdef KEY_SDC
4039    /* Document-const: KEY_SDC
4040     * Shifted delete char key
4041     */
4042    /* Document-const: SDC
4043     * Shifted delete char key
4044     */
4045    rb_curses_define_const(KEY_SDC);
4046    rb_define_const(mKey, "SDC", INT2NUM(KEY_SDC));
4047#endif
4048#ifdef KEY_SDL
4049    /* Document-const: KEY_SDL
4050     * Shifted delete line key
4051     */
4052    /* Document-const: SDL
4053     * Shifted delete line key
4054     */
4055    rb_curses_define_const(KEY_SDL);
4056    rb_define_const(mKey, "SDL", INT2NUM(KEY_SDL));
4057#endif
4058#ifdef KEY_SELECT
4059    /* Document-const: KEY_SELECT
4060     * Select key
4061     */
4062    /* Document-const: SELECT
4063     * Select key
4064     */
4065    rb_curses_define_const(KEY_SELECT);
4066    rb_define_const(mKey, "SELECT", INT2NUM(KEY_SELECT));
4067#endif
4068#ifdef KEY_SEND
4069    /* Document-const: KEY_SEND
4070     * Shifted end key
4071     */
4072    /* Document-const: SEND
4073     * Shifted end key
4074     */
4075    rb_curses_define_const(KEY_SEND);
4076    rb_define_const(mKey, "SEND", INT2NUM(KEY_SEND));
4077#endif
4078#ifdef KEY_SEOL
4079    /* Document-const: KEY_SEOL
4080     * Shifted clear line key
4081     */
4082    /* Document-const: SEOL
4083     * Shifted clear line key
4084     */
4085    rb_curses_define_const(KEY_SEOL);
4086    rb_define_const(mKey, "SEOL", INT2NUM(KEY_SEOL));
4087#endif
4088#ifdef KEY_SEXIT
4089    /* Document-const: KEY_SEXIT
4090     * Shifted exit key
4091     */
4092    /* Document-const: SEXIT
4093     * Shifted exit key
4094     */
4095    rb_curses_define_const(KEY_SEXIT);
4096    rb_define_const(mKey, "SEXIT", INT2NUM(KEY_SEXIT));
4097#endif
4098#ifdef KEY_SFIND
4099    /* Document-const: KEY_SFIND
4100     * Shifted find key
4101     */
4102    /* Document-const: SFIND
4103     * Shifted find key
4104     */
4105    rb_curses_define_const(KEY_SFIND);
4106    rb_define_const(mKey, "SFIND", INT2NUM(KEY_SFIND));
4107#endif
4108#ifdef KEY_SHELP
4109    /* Document-const: KEY_SHELP
4110     * Shifted help key
4111     */
4112    /* Document-const: SHELP
4113     * Shifted help key
4114     */
4115    rb_curses_define_const(KEY_SHELP);
4116    rb_define_const(mKey, "SHELP", INT2NUM(KEY_SHELP));
4117#endif
4118#ifdef KEY_SHOME
4119    /* Document-const: KEY_SHOME
4120     * Shifted home key
4121     */
4122    /* Document-const: SHOME
4123     * Shifted home key
4124     */
4125    rb_curses_define_const(KEY_SHOME);
4126    rb_define_const(mKey, "SHOME", INT2NUM(KEY_SHOME));
4127#endif
4128#ifdef KEY_SIC
4129    /* Document-const: KEY_SIC
4130     * Shifted input key
4131     */
4132    /* Document-const: SIC
4133     * Shifted input key
4134     */
4135    rb_curses_define_const(KEY_SIC);
4136    rb_define_const(mKey, "SIC", INT2NUM(KEY_SIC));
4137#endif
4138#ifdef KEY_SLEFT
4139    /* Document-const: KEY_SLEFT
4140     * Shifted left arrow key
4141     */
4142    /* Document-const: SLEFT
4143     * Shifted left arrow key
4144     */
4145    rb_curses_define_const(KEY_SLEFT);
4146    rb_define_const(mKey, "SLEFT", INT2NUM(KEY_SLEFT));
4147#endif
4148#ifdef KEY_SMESSAGE
4149    /* Document-const: KEY_SMESSAGE
4150     * Shifted message key
4151     */
4152    /* Document-const: SMESSAGE
4153     * Shifted message key
4154     */
4155    rb_curses_define_const(KEY_SMESSAGE);
4156    rb_define_const(mKey, "SMESSAGE", INT2NUM(KEY_SMESSAGE));
4157#endif
4158#ifdef KEY_SMOVE
4159    /* Document-const: KEY_SMOVE
4160     * Shifted move key
4161     */
4162    /* Document-const: SMOVE
4163     * Shifted move key
4164     */
4165    rb_curses_define_const(KEY_SMOVE);
4166    rb_define_const(mKey, "SMOVE", INT2NUM(KEY_SMOVE));
4167#endif
4168#ifdef KEY_SNEXT
4169    /* Document-const: KEY_SNEXT
4170     * Shifted next key
4171     */
4172    /* Document-const: SNEXT
4173     * Shifted next key
4174     */
4175    rb_curses_define_const(KEY_SNEXT);
4176    rb_define_const(mKey, "SNEXT", INT2NUM(KEY_SNEXT));
4177#endif
4178#ifdef KEY_SOPTIONS
4179    /* Document-const: KEY_SOPTIONS
4180     * Shifted options key
4181     */
4182    /* Document-const: SOPTIONS
4183     * Shifted options key
4184     */
4185    rb_curses_define_const(KEY_SOPTIONS);
4186    rb_define_const(mKey, "SOPTIONS", INT2NUM(KEY_SOPTIONS));
4187#endif
4188#ifdef KEY_SPREVIOUS
4189    /* Document-const: KEY_SPREVIOUS
4190     * Shifted previous key
4191     */
4192    /* Document-const: SPREVIOUS
4193     * Shifted previous key
4194     */
4195    rb_curses_define_const(KEY_SPREVIOUS);
4196    rb_define_const(mKey, "SPREVIOUS", INT2NUM(KEY_SPREVIOUS));
4197#endif
4198#ifdef KEY_SPRINT
4199    /* Document-const: KEY_SPRINT
4200     * Shifted print key
4201     */
4202    /* Document-const: SPRINT
4203     * Shifted print key
4204     */
4205    rb_curses_define_const(KEY_SPRINT);
4206    rb_define_const(mKey, "SPRINT", INT2NUM(KEY_SPRINT));
4207#endif
4208#ifdef KEY_SREDO
4209    /* Document-const: KEY_SREDO
4210     * Shifted redo key
4211     */
4212    /* Document-const: SREDO
4213     * Shifted redo key
4214     */
4215    rb_curses_define_const(KEY_SREDO);
4216    rb_define_const(mKey, "SREDO", INT2NUM(KEY_SREDO));
4217#endif
4218#ifdef KEY_SREPLACE
4219    /* Document-const: KEY_SREPLACE
4220     * Shifted replace key
4221     */
4222    /* Document-const: SREPLACE
4223     * Shifted replace key
4224     */
4225    rb_curses_define_const(KEY_SREPLACE);
4226    rb_define_const(mKey, "SREPLACE", INT2NUM(KEY_SREPLACE));
4227#endif
4228#ifdef KEY_SRIGHT
4229    /* Document-const: KEY_SRIGHT
4230     * Shifted right arrow key
4231     */
4232    /* Document-const: SRIGHT
4233     * Shifted right arrow key
4234     */
4235    rb_curses_define_const(KEY_SRIGHT);
4236    rb_define_const(mKey, "SRIGHT", INT2NUM(KEY_SRIGHT));
4237#endif
4238#ifdef KEY_SRSUME
4239    /* Document-const: KEY_SRSUME
4240     * Shifted resume key
4241     */
4242    /* Document-const: SRSUME
4243     * Shifted resume key
4244     */
4245    rb_curses_define_const(KEY_SRSUME);
4246    rb_define_const(mKey, "SRSUME", INT2NUM(KEY_SRSUME));
4247#endif
4248#ifdef KEY_SSAVE
4249    /* Document-const: KEY_SSAVE
4250     * Shifted save key
4251     */
4252    /* Document-const: SSAVE
4253     * Shifted save key
4254     */
4255    rb_curses_define_const(KEY_SSAVE);
4256    rb_define_const(mKey, "SSAVE", INT2NUM(KEY_SSAVE));
4257#endif
4258#ifdef KEY_SSUSPEND
4259    /* Document-const: KEY_SSUSPEND
4260     * Shifted suspend key
4261     */
4262    /* Document-const: SSUSPEND
4263     * Shifted suspend key
4264     */
4265    rb_curses_define_const(KEY_SSUSPEND);
4266    rb_define_const(mKey, "SSUSPEND", INT2NUM(KEY_SSUSPEND));
4267#endif
4268#ifdef KEY_SUNDO
4269    /* Document-const: KEY_SUNDO
4270     * Shifted undo key
4271     */
4272    /* Document-const: SUNDO
4273     * Shifted undo key
4274     */
4275    rb_curses_define_const(KEY_SUNDO);
4276    rb_define_const(mKey, "SUNDO", INT2NUM(KEY_SUNDO));
4277#endif
4278#ifdef KEY_SUSPEND
4279    /* Document-const: KEY_SUSPEND
4280     * Suspend key
4281     */
4282    /* Document-const: SUSPEND
4283     * Suspend key
4284     */
4285    rb_curses_define_const(KEY_SUSPEND);
4286    rb_define_const(mKey, "SUSPEND", INT2NUM(KEY_SUSPEND));
4287#endif
4288#ifdef KEY_UNDO
4289    /* Document-const: KEY_UNDO
4290     * Undo key
4291     */
4292    /* Document-const: UNDO
4293     * Undo key
4294     */
4295    rb_curses_define_const(KEY_UNDO);
4296    rb_define_const(mKey, "UNDO", INT2NUM(KEY_UNDO));
4297#endif
4298#ifdef KEY_RESIZE
4299    /* Document-const: KEY_RESIZE
4300     * Screen Resized
4301     */
4302    /* Document-const: RESIZE
4303     * Screen Resized
4304     */
4305    rb_curses_define_const(KEY_RESIZE);
4306    rb_define_const(mKey, "RESIZE", INT2NUM(KEY_RESIZE));
4307#endif
4308#ifdef KEY_MAX
4309    /* Document-const: KEY_MAX
4310     * The maximum allowed curses key value.
4311     */
4312    /* Document-const: MAX
4313     * The maximum allowed curses key value.
4314     */
4315    rb_curses_define_const(KEY_MAX);
4316    rb_define_const(mKey, "MAX", INT2NUM(KEY_MAX));
4317#endif
4318    {
4319	int c;
4320	char name[] = "KEY_CTRL_x";
4321	for (c = 'A'; c <= 'Z'; c++) {
4322	    name[sizeof(name) - 2] = c;
4323	    rb_define_const(mCurses, name, INT2FIX(c - 'A' + 1));
4324	}
4325    }
4326#undef rb_curses_define_const
4327
4328    rb_set_end_proc(curses_finalize, 0);
4329}
4330