Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions Doc/library/curses.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1192,6 +1192,17 @@ Window objects
object for the derived window.


.. method:: window.dupwin()

Return a new window that is an exact duplicate of the window: it has the same
size, position, contents and attributes. Unlike a window created by
:meth:`subwin` or :meth:`derwin`, the duplicate is independent of the
original -- it has its own cell buffer, so later changes to one do not affect
the other.

.. versionadded:: next


.. method:: window.echochar(ch[, attr])

Add character *ch* with attribute *attr*, and immediately call :meth:`refresh`
Expand Down
4 changes: 4 additions & 0 deletions Doc/whatsnew/3.16.rst
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,10 @@ curses
accept a :class:`~curses.complexstr`.
(Contributed by Serhiy Storchaka in :gh:`152233`.)

* Add the :mod:`curses` window method :meth:`~curses.window.dupwin`, which
returns a new window that is an independent duplicate of an existing one.
(Contributed by Serhiy Storchaka in :gh:`152258`.)

gzip
----

Expand Down
29 changes: 29 additions & 0 deletions Lib/test/test_curses.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,35 @@ def test_subwindows_references(self):
del win2
gc_collect()

def test_dupwin(self):
win = curses.newwin(5, 10, 2, 3)
win.addstr(0, 0, 'ABCDE')
win.addstr(1, 0, 'fghij')
dup = win.dupwin()
# Same geometry and contents as the original.
self.assertEqual(dup.getbegyx(), win.getbegyx())
self.assertEqual(dup.getmaxyx(), win.getmaxyx())
self.assertEqual(dup.instr(0, 0, 5), b'ABCDE')
self.assertEqual(dup.instr(1, 0, 5), b'fghij')
# The duplicate is independent, not a subwindow.
if hasattr(dup, 'is_subwin'):
self.assertIs(dup.is_subwin(), False)
self.assertIsNone(dup.getparent())
# Changes to one do not affect the other.
dup.addstr(0, 0, 'xxxxx')
win.addstr(1, 0, 'YYYYY')
self.assertEqual(win.instr(0, 0, 5), b'ABCDE')
self.assertEqual(dup.instr(0, 0, 5), b'xxxxx')
self.assertEqual(dup.instr(1, 0, 5), b'fghij')
self.assertEqual(win.instr(1, 0, 5), b'YYYYY')
# A subwindow can also be duplicated; the duplicate is independent.
sub = win.subwin(3, 5, 2, 3)
subdup = sub.dupwin()
self.assertEqual(subdup.getmaxyx(), sub.getmaxyx())
if hasattr(subdup, 'is_subwin'):
self.assertIs(subdup.is_subwin(), False)
self.assertIsNone(subdup.getparent())

def test_move_cursor(self):
stdscr = self.stdscr
win = stdscr.subwin(10, 15, 2, 5)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Add the :mod:`curses` window method :meth:`~curses.window.dupwin`, which
returns a new window that is an independent duplicate of an existing one.
30 changes: 29 additions & 1 deletion Modules/_cursesmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
Here's a list of currently unsupported functions:

addchnstr addchstr color_set define_key
del_curterm dupwin inchnstr inchstr innstr keyok
del_curterm inchnstr inchstr innstr keyok
mcprint mvaddchnstr mvaddchstr mvcur mvinchnstr
mvinchstr mvinnstr mmvwaddchnstr mvwaddchstr
mvwinchnstr mvwinchstr mvwinnstr
Expand Down Expand Up @@ -2722,6 +2722,33 @@ _curses_window_derwin_impl(PyCursesWindowObject *self, int group_left_1,
return PyCursesWindow_New(state, win, NULL, self, self->screen);
}

/*[clinic input]
_curses.window.dupwin

Create an exact duplicate of the window.

The new window is independent of the original: it has the same size,
position, contents and attributes, but its own cell buffer, so later
changes to one do not affect the other.
[clinic start generated code]*/

static PyObject *
_curses_window_dupwin_impl(PyCursesWindowObject *self)
/*[clinic end generated code: output=37d91aa8f88f13d1 input=787301b3799b618e]*/
{
WINDOW *win = dupwin(self->win);
if (win == NULL) {
curses_window_set_null_error(self, "dupwin", NULL);
return NULL;
}

/* The duplicate owns an independent cell buffer (unlike a subwindow), so
it has no parent: pass NULL as orig. Inherit the source encoding and
screen so it matches the original. */
cursesmodule_state *state = get_cursesmodule_state_by_win(self);
return PyCursesWindow_New(state, win, self->encoding, NULL, self->screen);
}

/*[clinic input]
_curses.window.echochar

Expand Down Expand Up @@ -4520,6 +4547,7 @@ static PyMethodDef PyCursesWindow_methods[] = {
"deleteln($self, /)\n--\n\n"
"Delete the line under the cursor; move following lines up by one."},
_CURSES_WINDOW_DERWIN_METHODDEF
_CURSES_WINDOW_DUPWIN_METHODDEF
_CURSES_WINDOW_ECHOCHAR_METHODDEF
_CURSES_WINDOW_ENCLOSE_METHODDEF
{"erase", PyCursesWindow_werase, METH_NOARGS,
Expand Down
24 changes: 23 additions & 1 deletion Modules/clinic/_cursesmodule.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading