-- sale, use or other dealings in this Software without prior written --
-- authorization. --
-------------------------------------------------------------------------------
--- $Id: NEWS,v 1.1213 2008/03/09 00:21:51 tom Exp $
+-- $Id: NEWS,v 1.1216 2008/03/23 00:18:40 tom Exp $
-------------------------------------------------------------------------------
This is a log of changes that ncurses has gone through since Zeyd started
Changes through 1.9.9e did not credit all contributions;
it is not possible to add this information.
+20080322
+ + fill in extended-color pair two more places in wbkgrndset() and
+ waddch_nosync() (prompted by Sedeno's patch).
+ + fill in extended-color pair in _nc_build_wch() to make colors work
+ for wide-characters using extended-colors (patch by Alejandro R
+ Sedeno).
+ + add x/X toggles to ncurses.c C color test to test/demo
+ wide-characters with extended-colors.
+ + add a/A toggles to ncurses.c c/C color tests.
+ + modify test/ditto.c to use use_screen().
+ + finish modifying test/rain.c to demonstrate threads.
+
20080308
+ start modifying test/rain.c for threading demo.
+ modify test/ncurses.c to make 'f' test accept the f/F/b/F/</> toggles
# use or other dealings in this Software without prior written #
# authorization. #
##############################################################################
-# $Id: dist.mk,v 1.633 2008/03/02 15:19:41 tom Exp $
+# $Id: dist.mk,v 1.635 2008/03/22 16:02:24 tom Exp $
# Makefile for creating ncurses distributions.
#
# This only needs to be used directly as a makefile by developers, but
# These define the major/minor/patch versions of ncurses.
NCURSES_MAJOR = 5
NCURSES_MINOR = 6
-NCURSES_PATCH = 20080308
+NCURSES_PATCH = 20080322
# We don't append the patch to the version, since this only applies to releases
VERSION = $(NCURSES_MAJOR).$(NCURSES_MINOR)
#include <curses.priv.h>
#include <ctype.h>
-MODULE_ID("$Id: lib_addch.c,v 1.108 2008/02/03 18:50:27 tom Exp $")
+MODULE_ID("$Id: lib_addch.c,v 1.110 2008/03/22 23:18:28 tom Exp $")
static const NCURSES_CH_T blankchar = NewChar(BLANK_TEXT);
buffer,
WINDOW_EXT(win, addch_used), &state)) > 0) {
attr_t attrs = AttrOf(CHDEREF(ch));
+ int pair = GetPair(CHDEREF(ch));
SetChar(CHDEREF(ch), result, attrs);
+ if_EXT_COLORS(SetPair(CHDEREF(ch), pair));
WINDOW_EXT(win, addch_used) = 0;
} else if (len == -1) {
/*
while (*s) {
NCURSES_CH_T sch;
SetChar(sch, *s++, AttrOf(ch));
+ if_EXT_COLORS(SetPair(sch, GetPair(ch)));
if (waddch_literal(win, sch) == ERR)
return ERR;
}
/****************************************************************************
- * Copyright (c) 1998-2005,2006 Free Software Foundation, Inc. *
+ * Copyright (c) 1998-2006,2008 Free Software Foundation, Inc. *
* *
* Permission is hereby granted, free of charge, to any person obtaining a *
* copy of this software and associated documentation files (the *
#include <curses.priv.h>
-MODULE_ID("$Id: lib_bkgd.c,v 1.35 2006/05/27 19:20:11 tom Exp $")
+MODULE_ID("$Id: lib_bkgd.c,v 1.36 2008/03/23 00:09:14 tom Exp $")
/*
* Set the window's background information.
if (CharOf(CHDEREF(ch)) == L('\0')) {
SetChar(win->_nc_bkgd, BLANK_TEXT, AttrOf(CHDEREF(ch)));
- SetPair(win->_nc_bkgd, GetPair(CHDEREF(ch)));
+ if_EXT_COLORS(SetPair(win->_nc_bkgd, GetPair(CHDEREF(ch))));
} else {
win->_nc_bkgd = CHDEREF(ch);
}
/****************************************************************************
- * Copyright (c) 1998-2006,2007 Free Software Foundation, Inc. *
+ * Copyright (c) 1998-2007,2008 Free Software Foundation, Inc. *
* *
* Permission is hereby granted, free of charge, to any person obtaining a *
* copy of this software and associated documentation files (the *
#include <ctype.h>
-MODULE_ID("$Id: lib_trace.c,v 1.65 2007/09/29 21:47:46 tom Exp $")
+MODULE_ID("$Id: lib_trace.c,v 1.66 2008/03/22 16:56:48 tom Exp $")
NCURSES_EXPORT_VAR(unsigned) _nc_tracing = 0; /* always define this */
if (doit != 0) {
if (TraceFP == 0)
TraceFP = stderr;
+#ifdef USE_PTHREADS
+ /*
+ * TRACE_ICALLS is "really" needed to show normal use with threaded
+ * applications, since anything can be running during a napms(),
+ * making it appear in the hierarchical trace as it other functions
+ * are being called.
+ *
+ * Rather than add the complication of a per-thread stack, just
+ * show the thread-id in each line of the trace.
+ */
+ fprintf(TraceFP, "%#lx:", (long) pthread_self());
+#endif
if (before || after) {
int n;
for (n = 1; n < TraceLevel; n++)
/****************************************************************************
- * Copyright (c) 1998-2005,2007 Free Software Foundation, Inc. *
+ * Copyright (c) 1998-2007,2008 Free Software Foundation, Inc. *
* *
* Permission is hereby granted, free of charge, to any person obtaining a *
* copy of this software and associated documentation files (the *
/*
* Author: Thomas E. Dickey <dickey@clark.net> 1998
*
- * $Id: ditto.c,v 1.8 2007/09/01 21:10:38 tom Exp $
+ * $Id: ditto.c,v 1.11 2008/03/22 20:26:31 tom Exp $
*
* The program illustrates how to set up multiple screens from a single
* program. Invoke the program by specifying another terminal on the same
return fp;
}
+static int
+close_screen(void *arg)
+{
+ (void) arg;
+ return endwin();
+}
+
+static int
+read_screen(void *arg)
+{
+ (void) arg;
+ return getch();
+}
+
+static int
+write_screen(WINDOW *win, void *arg)
+{
+ (void) win;
+ addstr((char *) arg);
+ refresh();
+ return OK;
+}
+
static void
-show_ditto(DITTO * data, int count, int which, int ch)
+show_ditto(DITTO * data, int count, char *msg)
{
int n;
for (n = 0; n < count; n++) {
- set_term(data[n].screen);
- addch(UChar(ch));
- refresh();
+ USING_SCREEN(data[n].screen, write_screen, (void *) msg);
}
- set_term(data[which].screen);
}
int
* of the screens.
*/
for (count = 0;; ++count) {
+ char message[80];
int ch;
int which = (count % argc);
- set_term(data[which].screen);
napms(20);
- ch = getch();
+ ch = USING_SCREEN(data[which].screen, read_screen, 0);
if (ch == ERR) {
/* echochar('.'); */
continue;
}
if (ch == CTRL('D'))
break;
- show_ditto(data, argc, which, ch);
+ sprintf(message, "from[%d:%d] '%c' (%#x)\n", count, which, ch, ch);
+ show_ditto(data, argc, message);
}
/*
* Cleanup and exit
*/
for (j = argc - 1; j >= 0; j--) {
- set_term(data[j].screen);
- endwin();
+ USING_SCREEN(data[j].screen, close_screen, 0);
}
ExitProgram(EXIT_SUCCESS);
}
Author: Eric S. Raymond <esr@snark.thyrsus.com> 1993
Thomas E. Dickey (beginning revision 1.27 in 1996).
-$Id: ncurses.c,v 1.309 2008/03/08 20:57:09 tom Exp $
+$Id: ncurses.c,v 1.312 2008/03/22 23:02:57 tom Exp $
***************************************************************************/
{
return ((c) == QUIT || (c) == ESCAPE);
}
-#define case_QUIT case QUIT: case ESCAPE
+#define case_QUIT QUIT: case ESCAPE
/* Common function to allow ^T to toggle trace-mode in the middle of a test
* so that trace-files can be made smaller.
}
#if USE_WIDEC_SUPPORT
+static wchar_t
+fullwidth_of(int ch)
+{
+ return (ch + 0xff10 - '0');
+}
+
+static void
+make_fullwidth_text(wchar_t *target, const char *source)
+{
+ int ch;
+ while ((ch = *source++) != 0) {
+ *target++ = fullwidth_of(ch);
+ }
+ *target = 0;
+}
+
+static void
+make_narrow_text(wchar_t *target, const char *source)
+{
+ int ch;
+ while ((ch = *source++) != 0) {
+ *target++ = ch;
+ }
+ *target = 0;
+}
+
+static void
+make_fullwidth_digit(cchar_t *target, int digit)
+{
+ wchar_t source[2];
+
+ source[0] = fullwidth_of(digit + '0');
+ source[1] = 0;
+ setcchar(target, source, A_NORMAL, 0, 0);
+}
+
static int
wGet_wchar(WINDOW *win, wint_t *result)
{
case '>':
adjust_attr_string(1);
break;
- case_QUIT:
+ case case_QUIT:
result = FALSE;
break;
default:
case '>':
wide_adjust_attr_string(1);
break;
- case_QUIT:
+ case case_QUIT:
result = FALSE;
break;
default:
}
static void
-color_legend(WINDOW *helpwin)
+color_legend(WINDOW *helpwin, bool wide)
{
int row = 1;
int col = 1;
mvwprintw(helpwin, row++, col,
"longer than one screen. Control/N and Control/P can be used");
mvwprintw(helpwin, row++, col,
- "in place up up/down arrow. Use pageup/pagedown to scroll a");
+ "in place of up/down arrow. Use pageup/pagedown to scroll a");
mvwprintw(helpwin, row++, col,
"full screen; control/B and control/F can be used here.");
++row;
mvwprintw(helpwin, row++, col,
"Toggles:");
+ mvwprintw(helpwin, row++, col,
+ " a/A toggle altcharset off/on");
mvwprintw(helpwin, row++, col,
" b/B toggle bold off/on");
mvwprintw(helpwin, row++, col,
" n/N toggle text/number on/off");
mvwprintw(helpwin, row++, col,
" w/W toggle width between 8/16 colors");
+#if USE_WIDEC_SUPPORT
+ if (wide) {
+ mvwprintw(helpwin, row++, col,
+ "Wide characters:");
+ mvwprintw(helpwin, row++, col,
+ " x/X toggle text between ASCII and wide-character");
+ }
+#else
+ (void) wide;
+#endif
}
#define set_color_test(name, value) if (name != value) { name = value; base_row = 0; }
char numbered[80];
const char *hello;
bool done = FALSE;
+ bool opt_acsc = FALSE;
bool opt_bold = FALSE;
bool opt_wide = FALSE;
bool opt_nums = FALSE;
init_pair(pair, fg, bg);
attron((attr_t) COLOR_PAIR(pair));
+ if (opt_acsc)
+ attron((attr_t) A_ALTCHARSET);
if (opt_bold)
attron((attr_t) A_BOLD);
}
switch (wGetchar(stdscr)) {
+ case 'a':
+ opt_acsc = FALSE;
+ break;
+ case 'A':
+ opt_acsc = TRUE;
+ break;
case 'b':
opt_bold = FALSE;
break;
case 'N':
opt_nums = TRUE;
break;
- case_QUIT:
+ case case_QUIT:
done = TRUE;
continue;
case 'w':
case '?':
if ((helpwin = newwin(LINES - 1, COLS - 2, 0, 0)) != 0) {
box(helpwin, 0, 0);
- color_legend(helpwin);
+ color_legend(helpwin, FALSE);
wGetchar(helpwin);
delwin(helpwin);
}
char numbered[80];
const char *hello;
bool done = FALSE;
+ bool opt_acsc = FALSE;
bool opt_bold = FALSE;
bool opt_wide = FALSE;
bool opt_nums = FALSE;
+ bool opt_xchr = FALSE;
+ wchar_t buffer[10];
WINDOW *helpwin;
while (!done) {
hello = "Hello";
per_row = 8;
}
+ if (opt_xchr) {
+ make_fullwidth_text(buffer, hello);
+ width *= 2;
+ per_row /= 2;
+ } else {
+ make_narrow_text(buffer, hello);
+ }
row_limit = (pairs_max + per_row - 1) / per_row;
if (row >= 0 && move(row, col) != ERR) {
init_pair(pair, i % COLORS, i / COLORS);
color_set(pair, NULL);
+ if (opt_acsc)
+ attr_on((attr_t) A_ALTCHARSET, NULL);
if (opt_bold)
attr_on((attr_t) A_BOLD, NULL);
if (opt_nums) {
sprintf(numbered, "{%02X}", i);
- hello = numbered;
+ if (opt_xchr) {
+ make_fullwidth_text(buffer, numbered);
+ } else {
+ make_narrow_text(buffer, numbered);
+ }
}
- printw("%-*.*s", width, width, hello);
+ addnwstr(buffer, width);
attr_set(A_NORMAL, 0, NULL);
if ((i % per_row) == 0 && (i % COLORS) == 0) {
}
switch (c = wGetchar(stdscr)) {
+ case 'a':
+ opt_acsc = FALSE;
+ break;
+ case 'A':
+ opt_acsc = TRUE;
+ break;
case 'b':
opt_bold = FALSE;
break;
case 'N':
opt_nums = TRUE;
break;
- case_QUIT:
+ case case_QUIT:
done = TRUE;
continue;
case 'w':
case 'W':
set_color_test(opt_wide, TRUE);
break;
+ case 'x':
+ opt_xchr = FALSE;
+ break;
+ case 'X':
+ opt_xchr = TRUE;
+ break;
case CTRL('p'):
case KEY_UP:
if (base_row <= 0) {
case '?':
if ((helpwin = newwin(LINES - 1, COLS - 2, 0, 0)) != 0) {
box(helpwin, 0, 0);
- color_legend(helpwin);
+ color_legend(helpwin, TRUE);
wGetchar(helpwin);
delwin(helpwin);
}
refresh();
break;
- case_QUIT:
+ case case_QUIT:
break;
default:
clrtobot();
break;
- case_QUIT:
+ case case_QUIT:
goto done;
#if HAVE_SLK_COLOR
clrtobot();
break;
- case_QUIT:
+ case case_QUIT:
goto done;
case 'F':
case KEY_RIGHT:
j++;
break;
- case_QUIT:
+ case case_QUIT:
return ((pair *) 0);
#ifdef NCURSES_MOUSE_VERSION
case KEY_MOUSE:
}
#if USE_WIDEC_SUPPORT
-static void
-make_fullwidth_digit(cchar_t *target, int digit)
-{
- wchar_t source[2];
-
- source[0] = digit + 0xff10;
- source[1] = 0;
- setcchar(target, source, A_NORMAL, 0, 0);
-}
-
static void
init_wide_panel(void)
{
c = KEY_DC;
break;
case ERR: /* FALLTHRU */
- case_QUIT:
+ case case_QUIT:
count = 0;
c = KEY_EXIT;
break;
* authorization. *
****************************************************************************/
/*
- * $Id: rain.c,v 1.26 2008/03/09 00:17:09 tom Exp $
+ * $Id: rain.c,v 1.33 2008/03/22 18:12:01 tom Exp $
*/
#include <test.priv.h>
WANT_USE_WINDOW();
-#define MAX_DROP 5
+#define MAX_THREADS 10
+#define MAX_DROP 5
struct DATA;
typedef struct DATA {
int y, x;
#ifdef USE_PTHREADS
- pthread_t thread;
DrawPart func;
int state;
#endif
} DATA;
+#ifdef USE_PTHREADS
+pthread_cond_t cond_next_drop;
+pthread_mutex_t mutex_next_drop;
+static int used_threads;
+
+typedef struct {
+ pthread_t myself;
+ long counter;
+} STATS;
+
+static STATS drop_threads[MAX_THREADS];
+#endif
+
static void
onsig(int n GCC_UNUSED)
{
static void
napsome(void)
{
- refresh();
napms(60);
}
/*
- * This runs inside the mutex.
+ * This runs inside the use_window() mutex.
*/
static int
really_draw(WINDOW *win, void *arg)
(void) win;
next_j(data->state);
data->func(data);
+ refresh();
return OK;
}
napsome();
}
+/*
+ * Tell the threads that one of them can start work on a new raindrop.
+ * They may all be busy if we're sending requests too rapidly.
+ */
+static int
+put_next_drop(void)
+{
+ pthread_cond_signal(&cond_next_drop);
+ pthread_mutex_unlock(&mutex_next_drop);
+
+ return 0;
+}
+
+/*
+ * Wait until we're assigned the task of drawing a new raindrop.
+ */
+static int
+get_next_drop(void)
+{
+ pthread_mutex_lock(&mutex_next_drop);
+ pthread_cond_wait(&cond_next_drop, &mutex_next_drop);
+
+ return TRUE;
+}
+
static void *
draw_drop(void *arg)
{
DATA mydata;
+ int mystats;
+
+ /*
+ * Find myself in the list of threads so we can count the number of loops.
+ */
+ for (mystats = 0; mystats < MAX_THREADS; ++mystats) {
+ if (drop_threads[mystats].myself == pthread_self())
+ break;
+ }
+
+ do {
+ if (mystats < MAX_THREADS)
+ drop_threads[mystats].counter++;
- mydata = *(DATA *) arg; /* make a copy of caller's data */
+ /*
+ * Make a copy of caller's data. We're cheating for the cases after
+ * the first loop since we still have a pointer into the main thread
+ * to the data which it uses for setting up this thread (but it has
+ * been modified to use different coordinates).
+ */
+ mydata = *(DATA *) arg;
- draw_part(part1, 0, &mydata);
- draw_part(part2, 1, &mydata);
- draw_part(part3, 2, &mydata);
- draw_part(part4, 3, &mydata);
- draw_part(part5, 4, &mydata);
- draw_part(part6, 0, &mydata);
+ draw_part(part1, 0, &mydata);
+ draw_part(part2, 1, &mydata);
+ draw_part(part3, 2, &mydata);
+ draw_part(part4, 3, &mydata);
+ draw_part(part5, 4, &mydata);
+ draw_part(part6, 0, &mydata);
+ } while (get_next_drop());
return NULL;
}
+
+/*
+ * The description of pthread_create() is misleading, since it implies that
+ * threads will exit cleanly after their function returns.
+ *
+ * Since they do not (and the number of threads is limited by system
+ * resources), make a limited number of threads, and signal any that are
+ * waiting when we want a thread past that limit.
+ */
+static int
+start_drop(DATA * data)
+{
+ int rc;
+
+ if (!used_threads) {
+ /* mutex and condition for signalling thread */
+ pthread_mutex_init(&mutex_next_drop, NULL);
+ pthread_cond_init(&cond_next_drop, NULL);
+ }
+
+ if (used_threads < MAX_THREADS) {
+ rc = pthread_create(&(drop_threads[used_threads].myself),
+ NULL,
+ draw_drop,
+ data);
+ ++used_threads;
+ } else {
+ rc = put_next_drop();
+ }
+ return rc;
+}
#endif
static int
get_input(void)
{
- int ch;
- ch = USING_WINDOW(stdscr, wgetch);
- return ch;
+ return USING_WINDOW(stdscr, wgetch);
}
int
main(int argc GCC_UNUSED,
char *argv[]GCC_UNUSED)
{
+ bool done = FALSE;
DATA drop;
+#ifndef USE_PTHREADS
DATA last[MAX_DROP];
+#endif
int j = 0;
- bool done = FALSE;
setlocale(LC_ALL, "");
curs_set(0);
timeout(0);
+#ifndef USE_PTHREADS
for (j = MAX_DROP; --j >= 0;) {
last[j].x = random_x();
last[j].y = random_y();
}
+#endif
while (!done) {
drop.x = random_x();
drop.y = random_y();
#ifdef USE_PTHREADS
- if (pthread_create(&(drop.thread), NULL, draw_drop, &drop)) {
+ if (start_drop(&drop) != 0) {
beep();
- done = TRUE;
- continue;
}
#else
/*
}
curs_set(1);
endwin();
+#ifdef USE_PTHREADS
+ printf("Counts per thread:\n");
+ for (j = 0; j < MAX_THREADS; ++j)
+ printf(" %d:%ld\n", j, drop_threads[j].counter);
+#endif
ExitProgram(EXIT_SUCCESS);
}
/****************************************************************************
* Author: Thomas E. Dickey 1996-on *
****************************************************************************/
-/* $Id: test.priv.h,v 1.74 2008/02/23 23:02:41 tom Exp $ */
+/* $Id: test.priv.h,v 1.75 2008/03/22 19:27:11 tom Exp $ */
#ifndef __TEST_PRIV_H
#define __TEST_PRIV_H 1
#define CONST_MENUS /* nothing */
#endif
+#ifndef HAVE_USE_WINDOW
+#if !defined(NCURSES_VERSION_PATCH) || (NCURSES_VERSION_PATCH < 20070915) || !NCURSES_EXT_FUNCS
+#define HAVE_USE_WINDOW 0
+#else
+#define HAVE_USE_WINDOW 1
+#endif
+#endif
+
/*
* Simplify setting up demo of threading with these macros.
*/
-#if !defined(NCURSES_VERSION_PATCH) || (NCURSES_VERSION_PATCH < 20070915) || !NCURSES_EXT_FUNCS
+
+#if !HAVE_USE_WINDOW
typedef int (*NCURSES_CALLBACK)(WINDOW *, void *);
-#define WANT_USE_WINDOW() \
-static int \
-use_window(WINDOW *win, int (*func) (WINDOW *, void *), void *data) \
-{ \
- return func(win, data); \
-} \
- extern void _nc_want_use_window(void)
+#endif
+
+#if HAVE_USE_WINDOW
#define USING_WINDOW(w,func) use_window(w, (NCURSES_CALLBACK) func, w)
+#define WANT_USE_WINDOW() extern void _nc_want_use_window(void)
#else
-#define WANT_USE_WINDOW() /* nothing */ \
- extern void _nc_want_use_window(void)
#define USING_WINDOW(w,func) func(w)
+#define WANT_USE_WINDOW() extern void _nc_want_use_window(void)
+#endif
+
+#if HAVE_USE_WINDOW
+#define USING_SCREEN(s,func,data) use_screen(s, (NCURSES_CALLBACK) func, data)
+#define WANT_USE_SCREEN() extern void _nc_want_use_screen(void)
+#else
+#define USING_SCREEN(s,func,data) func(data)
+#define WANT_USE_SCREEN() extern void _nc_want_use_screen(void)
#endif
#ifdef TRACE