michael-lazar / rtv

Browse Reddit from your terminal
MIT License
4.65k stars 275 forks source link

python derwin() behavior with pdcurses library #32

Closed michael-lazar closed 9 years ago

michael-lazar commented 9 years ago

I'm starting an issue to investigate the observed broken behavior of python's curses.derwin() with pdcurses. There appears to be an issue with the two argument form of derwin (See https://github.com/michael-lazar/rtv/pull/31 for details from @peterpans01). This is not really an RTV issue, but I'm curious none the less.

michael-lazar commented 9 years ago

From cpython/Modules/_cursesmodule.c, line 1075

static PyObject *
PyCursesWindow_DerWin(PyCursesWindowObject *self, PyObject *args)
{
    WINDOW *win;
    int nlines, ncols, begin_y, begin_x;

    nlines = 0;
    ncols  = 0;
    switch (PyTuple_Size(args)) {
    case 2:
        if (!PyArg_ParseTuple(args,"ii;begin_y,begin_x",&begin_y,&begin_x))
            return NULL;
        break;
    case 4:
        if (!PyArg_ParseTuple(args, "iiii;nlines,ncols,begin_y,begin_x",
                              &nlines,&ncols,&begin_y,&begin_x))
            return NULL;
        break;
    default:
        PyErr_SetString(PyExc_TypeError, "derwin requires 2 or 4 arguments");
        return NULL;
    }

    win = derwin(self->win,nlines,ncols,begin_y,begin_x);

    if (win == NULL) {
        PyErr_SetString(PyCursesError, catchall_NULL);
        return NULL;
    }

    return (PyObject *)PyCursesWindow_New(win, NULL);
}

So the two argument form in Python sends derwin(0, 0, begin_y, begin_x) to the curses library.

From ncurses-5.9/ncurses/base, line 186

derwin(WINDOW *orig, int num_lines, int num_columns, int begy, int begx)
{
    WINDOW *win;
    int i;
    int flags = _SUBWIN;
#if NCURSES_SP_FUNCS
    SCREEN *sp = _nc_screen_of(orig);
#endif

    T((T_CALLED("derwin(%p,%d,%d,%d,%d)"), (void *) orig, num_lines, num_columns,
       begy, begx));

    /*
     * make sure window fits inside the original one
     */
    if (begy < 0 || begx < 0 || orig == 0 || num_lines < 0 || num_columns < 0)
        returnWin(0);
    if (begy + num_lines > orig->_maxy + 1
        || begx + num_columns > orig->_maxx + 1)
        returnWin(0);

    if (num_lines == 0)
        num_lines = orig->_maxy + 1 - begy;

    if (num_columns == 0)
        num_columns = orig->_maxx + 1 - begx;

    if (orig->_flags & _ISPAD)
        flags |= _ISPAD;

    win = NCURSES_SP_NAME(_nc_makenew) (NCURSES_SP_ARGx num_lines, num_columns,
                                        orig->_begy + begy,
                                        orig->_begx + begx, flags);
    if (win == 0)
        returnWin(0);

    win->_pary = begy;
    win->_parx = begx;
    WINDOW_ATTRS(win) = WINDOW_ATTRS(orig);
    win->_nc_bkgd = orig->_nc_bkgd;

    for (i = 0; i < num_lines; i++)
        win->_line[i].text = &orig->_line[begy++].text[begx];

    win->_parent = orig;

    returnWin(win);
}

and from PDCurses-3.4/pdcurses/window.c

line 341

WINDOW *derwin(WINDOW *orig, int nlines, int ncols, int begy, int begx)
{
    return subwin(orig, nlines, ncols, begy + orig->_begy, begx + orig->_begx);
}

line 294

WINDOW *subwin(WINDOW *orig, int nlines, int ncols, int begy, int begx)
{
    WINDOW *win;
    int i;
    int j = begy - orig->_begy;
    int k = begx - orig->_begx;

    PDC_LOG(("subwin() - called: lines %d cols %d begy %d begx %d\n",
             nlines, ncols, begy, begx));

    /* make sure window fits inside the original one */

    if (!orig || (begy < orig->_begy) || (begx < orig->_begx) ||
        (begy + nlines) > (orig->_begy + orig->_maxy) ||
        (begx + ncols) > (orig->_begx + orig->_maxx))
        return (WINDOW *)NULL;

    if (!nlines)
        nlines = orig->_maxy - 1 - j;
    if (!ncols)
        ncols  = orig->_maxx - 1 - k;

    if ( !(win = PDC_makenew(nlines, ncols, begy, begx)) )
        return (WINDOW *)NULL;
michael-lazar commented 9 years ago

Dropped all attempts at maintaining windows compatability a long time ago.

Brobin commented 9 years ago

:D #linuxmasterrace