Skip to content

Commit 51cacbe

Browse files
[3.14] gh-152502: Detect the curses mouse interface portably (GH-152705) (GH-152734)
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. (cherry picked from commit 7bbea4f) Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 08e1772 commit 51cacbe

7 files changed

Lines changed: 94 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
@@ -1502,7 +1502,7 @@ _curses_window_echochar_impl(PyCursesWindowObject *self, PyObject *ch,
15021502
"echochar");
15031503
}
15041504

1505-
#ifdef NCURSES_MOUSE_VERSION
1505+
#if defined(HAVE_CURSES_GETMOUSE) || defined(PDCURSES)
15061506
/*[clinic input]
15071507
_curses.window.enclose
15081508
@@ -3244,7 +3244,7 @@ _curses_getsyx_impl(PyObject *module)
32443244
}
32453245
#endif
32463246

3247-
#ifdef NCURSES_MOUSE_VERSION
3247+
#if defined(HAVE_CURSES_GETMOUSE) || defined(PDCURSES)
32483248
/*[clinic input]
32493249
_curses.getmouse
32503250
@@ -3961,7 +3961,7 @@ _curses_meta_impl(PyObject *module, int yes)
39613961
return PyCursesCheckERR(module, meta(stdscr, yes), "meta");
39623962
}
39633963

3964-
#ifdef NCURSES_MOUSE_VERSION
3964+
#if defined(HAVE_CURSES_GETMOUSE) || defined(PDCURSES)
39653965
/*[clinic input]
39663966
_curses.mouseinterval
39673967
@@ -5385,7 +5385,7 @@ cursesmodule_exec(PyObject *module)
53855385
SetDictInt("COLOR_CYAN", COLOR_CYAN);
53865386
SetDictInt("COLOR_WHITE", COLOR_WHITE);
53875387

5388-
#ifdef NCURSES_MOUSE_VERSION
5388+
#if defined(HAVE_CURSES_GETMOUSE) || defined(PDCURSES)
53895389
/* Mouse-related constants */
53905390
SetDictInt("BUTTON1_PRESSED", BUTTON1_PRESSED);
53915391
SetDictInt("BUTTON1_RELEASED", BUTTON1_RELEASED);
@@ -5411,7 +5411,7 @@ cursesmodule_exec(PyObject *module)
54115411
SetDictInt("BUTTON4_DOUBLE_CLICKED", BUTTON4_DOUBLE_CLICKED);
54125412
SetDictInt("BUTTON4_TRIPLE_CLICKED", BUTTON4_TRIPLE_CLICKED);
54135413

5414-
#if NCURSES_MOUSE_VERSION > 1
5414+
#ifdef BUTTON5_PRESSED
54155415
SetDictInt("BUTTON5_PRESSED", BUTTON5_PRESSED);
54165416
SetDictInt("BUTTON5_RELEASED", BUTTON5_RELEASED);
54175417
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: 51 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
@@ -7086,6 +7086,18 @@ PY_CHECK_CURSES_FUNC([set_escdelay])
70867086
PY_CHECK_CURSES_FUNC([set_tabsize])
70877087
PY_CHECK_CURSES_VAR([ESCDELAY])
70887088
PY_CHECK_CURSES_VAR([TABSIZE])
7089+
7090+
dnl Probe for the X/Open getmouse(MEVENT *) signature specifically: PDCurses
7091+
dnl declares an incompatible getmouse(void) unless built for the ncurses mouse API.
7092+
AC_CACHE_CHECK([for ncurses-style curses function getmouse],
7093+
[ac_cv_lib_curses_getmouse],
7094+
[AC_COMPILE_IFELSE(
7095+
[AC_LANG_PROGRAM(_CURSES_INCLUDES, [MEVENT event; (void)getmouse(&event);])],
7096+
[ac_cv_lib_curses_getmouse=yes],
7097+
[ac_cv_lib_curses_getmouse=no])])
7098+
AS_VAR_IF([ac_cv_lib_curses_getmouse], [yes],
7099+
[AC_DEFINE([HAVE_CURSES_GETMOUSE], [1],
7100+
[Define if you have the 'getmouse' function with the X/Open signature.])])
70897101
CPPFLAGS=$ac_save_cppflags
70907102
])dnl have_curses != no
70917103
])dnl save env

pyconfig.h.in

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

195+
/* Define if you have the 'getmouse' function with the X/Open signature. */
196+
#undef HAVE_CURSES_GETMOUSE
197+
195198
/* Define to 1 if you have the <curses.h> header file. */
196199
#undef HAVE_CURSES_H
197200

0 commit comments

Comments
 (0)