Skip to content

Commit 2b5208a

Browse files
[3.13] gh-152502: Detect the curses mouse interface portably (GH-152705)
The mouse interface (getmouse(), the BUTTON* constants, ...) was gated on the ncurses-specific NCURSES_MOUSE_VERSION macro, so it was dropped on other curses implementations that provide it, such as NetBSD curses and PDCurses. Gate it instead on a configure capability probe or the PDCURSES macro. Probe for getmouse() with its X/Open getmouse(MEVENT *) signature, since PDCurses declares an incompatible getmouse(void) unless built for the ncurses mouse API, which PDC_NCMOUSE now always selects. The is_*() state-query methods named in the original change do not exist on 3.15, so only the mouse interface is backported. (cherry picked from commit 7bbea4f) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent ce97622 commit 2b5208a

7 files changed

Lines changed: 92 additions & 16 deletions

File tree

Include/py_curses.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,13 @@
3636
#define NCURSES_OPAQUE 0
3737
#endif
3838

39+
/* PDCurses exposes its ncurses-compatible mouse API, the one this module uses,
40+
only when this is defined before the curses header is included below.
41+
Ignored by other curses implementations. */
42+
#ifndef PDC_NCMOUSE
43+
# define PDC_NCMOUSE
44+
#endif
45+
3946
#if defined(HAVE_NCURSESW_NCURSES_H)
4047
# include <ncursesw/ncurses.h>
4148
#elif defined(HAVE_NCURSESW_CURSES_H)
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Detect the :mod:`curses` mouse interface (:func:`~curses.getmouse`, the
2+
``BUTTON*`` constants, and others) with a configure capability probe or library
3+
macros instead of gating it on ncurses-specific macros. It is now also
4+
available with other curses implementations that provide it, such as NetBSD
5+
curses and PDCurses (the latter underpins ``windows-curses``).

Modules/_cursesmodule.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1358,7 +1358,7 @@ _curses_window_echochar_impl(PyCursesWindowObject *self, PyObject *ch,
13581358
"echochar");
13591359
}
13601360

1361-
#ifdef NCURSES_MOUSE_VERSION
1361+
#if defined(HAVE_CURSES_GETMOUSE) || defined(PDCURSES)
13621362
/*[clinic input]
13631363
_curses.window.enclose
13641364
@@ -3003,7 +3003,7 @@ _curses_getsyx_impl(PyObject *module)
30033003
}
30043004
#endif
30053005

3006-
#ifdef NCURSES_MOUSE_VERSION
3006+
#if defined(HAVE_CURSES_GETMOUSE) || defined(PDCURSES)
30073007
/*[clinic input]
30083008
_curses.getmouse
30093009
@@ -3699,7 +3699,7 @@ _curses_meta_impl(PyObject *module, int yes)
36993699
return PyCursesCheckERR(meta(stdscr, yes), "meta");
37003700
}
37013701

3702-
#ifdef NCURSES_MOUSE_VERSION
3702+
#if defined(HAVE_CURSES_GETMOUSE) || defined(PDCURSES)
37033703
/*[clinic input]
37043704
_curses.mouseinterval
37053705
@@ -4946,7 +4946,7 @@ PyInit__curses(void)
49464946
SetDictInt("COLOR_CYAN", COLOR_CYAN);
49474947
SetDictInt("COLOR_WHITE", COLOR_WHITE);
49484948

4949-
#ifdef NCURSES_MOUSE_VERSION
4949+
#if defined(HAVE_CURSES_GETMOUSE) || defined(PDCURSES)
49504950
/* Mouse-related constants */
49514951
SetDictInt("BUTTON1_PRESSED", BUTTON1_PRESSED);
49524952
SetDictInt("BUTTON1_RELEASED", BUTTON1_RELEASED);
@@ -4972,7 +4972,7 @@ PyInit__curses(void)
49724972
SetDictInt("BUTTON4_DOUBLE_CLICKED", BUTTON4_DOUBLE_CLICKED);
49734973
SetDictInt("BUTTON4_TRIPLE_CLICKED", BUTTON4_TRIPLE_CLICKED);
49744974

4975-
#if NCURSES_MOUSE_VERSION > 1
4975+
#ifdef BUTTON5_PRESSED
49764976
SetDictInt("BUTTON5_PRESSED", BUTTON5_PRESSED);
49774977
SetDictInt("BUTTON5_RELEASED", BUTTON5_RELEASED);
49784978
SetDictInt("BUTTON5_CLICKED", BUTTON5_CLICKED);

Modules/clinic/_cursesmodule.c.h

Lines changed: 11 additions & 11 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

configure

Lines changed: 49 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

configure.ac

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6976,6 +6976,18 @@ PY_CHECK_CURSES_FUNC([set_escdelay])
69766976
PY_CHECK_CURSES_FUNC([set_tabsize])
69776977
PY_CHECK_CURSES_VAR([ESCDELAY])
69786978
PY_CHECK_CURSES_VAR([TABSIZE])
6979+
6980+
dnl Probe for the X/Open getmouse(MEVENT *) signature specifically: PDCurses
6981+
dnl declares an incompatible getmouse(void) unless built for the ncurses mouse API.
6982+
AC_CACHE_CHECK([for ncurses-style curses function getmouse],
6983+
[ac_cv_lib_curses_getmouse],
6984+
[AC_COMPILE_IFELSE(
6985+
[AC_LANG_PROGRAM(_CURSES_INCLUDES, [MEVENT event; (void)getmouse(&event);])],
6986+
[ac_cv_lib_curses_getmouse=yes],
6987+
[ac_cv_lib_curses_getmouse=no])])
6988+
AS_VAR_IF([ac_cv_lib_curses_getmouse], [yes],
6989+
[AC_DEFINE([HAVE_CURSES_GETMOUSE], [1],
6990+
[Define if you have the 'getmouse' function with the X/Open signature.])])
69796991
CPPFLAGS=$ac_save_cppflags
69806992
])dnl have_curses != no
69816993
])dnl save env

pyconfig.h.in

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,9 @@
189189
/* Define if you have the 'filter' function. */
190190
#undef HAVE_CURSES_FILTER
191191

192+
/* Define if you have the 'getmouse' function with the X/Open signature. */
193+
#undef HAVE_CURSES_GETMOUSE
194+
192195
/* Define to 1 if you have the <curses.h> header file. */
193196
#undef HAVE_CURSES_H
194197

0 commit comments

Comments
 (0)