(Most of this work was cracyc's effort, but I started tweaking it before I thought to perform a commit. --ryan.)
491 lines
15 KiB
C
491 lines
15 KiB
C
/**
|
|
* 2ine; an OS/2 emulator for Linux.
|
|
*
|
|
* Please see the file LICENSE.txt in the source's root directory.
|
|
*
|
|
* This file written by Ryan C. Gordon.
|
|
*/
|
|
|
|
#include "os2native16.h"
|
|
#include "viocalls.h"
|
|
|
|
// os2types.h defines these, but so does curses.
|
|
#undef TRUE
|
|
#undef FALSE
|
|
|
|
#include <unistd.h>
|
|
#include <ctype.h>
|
|
|
|
// CMake searches for a whole bunch of different possible curses includes
|
|
#if defined(HAVE_NCURSESW_NCURSES_H)
|
|
#include <ncursesw/ncurses.h>
|
|
#elif defined(HAVE_NCURSESW_CURSES_H)
|
|
#include <ncursesw/curses.h>
|
|
#elif defined(HAVE_NCURSESW_H)
|
|
#include <ncursesw.h>
|
|
#elif defined(HAVE_CURSES_H)
|
|
#include <curses.h>
|
|
#else
|
|
#error ncurses gui enabled, but no known header file found
|
|
#endif
|
|
|
|
#include <locale.h>
|
|
|
|
#include "viocalls-lx.h"
|
|
|
|
enum
|
|
{
|
|
VIOATTR_BACK_BLACK = 0x00,
|
|
VIOATTR_BACK_BLUE = 0x10,
|
|
VIOATTR_BACK_GREEN = 0x20,
|
|
VIOATTR_BACK_CYAN = 0x30,
|
|
VIOATTR_BACK_RED = 0x40,
|
|
VIOATTR_BACK_MAGENTA = 0x50,
|
|
VIOATTR_BACK_YELLOW = 0x60,
|
|
VIOATTR_BACK_BROWN = 0x60,
|
|
VIOATTR_BACK_WHITE = 0x70,
|
|
|
|
VIOATTR_FORE_BLACK = 0x00,
|
|
VIOATTR_FORE_BLUE = 0x01,
|
|
VIOATTR_FORE_GREEN = 0x02,
|
|
VIOATTR_FORE_CYAN = 0x03,
|
|
VIOATTR_FORE_RED = 0x04,
|
|
VIOATTR_FORE_MAGENTA = 0x05,
|
|
VIOATTR_FORE_YELLOW = 0x06,
|
|
VIOATTR_FORE_BROWN = 0x06,
|
|
VIOATTR_FORE_WHITE = 0x07,
|
|
|
|
VIOATTR_INTENSITY = 0x08,
|
|
VIOATTR_BLINK = 0x80
|
|
};
|
|
|
|
|
|
static uint16 *vio_buffer = NULL;
|
|
static uint16 vio_scrw, vio_scrh;
|
|
static uint16 vio_curx, vio_cury;
|
|
static VIOCURSORINFO vio_cursorinfo;
|
|
|
|
static int initNcurses(void)
|
|
{
|
|
if (vio_buffer != NULL)
|
|
return 1;
|
|
|
|
setlocale(LC_CTYPE, ""); // !!! FIXME: we assume you have a UTF-8 terminal.
|
|
if (initscr() == NULL) {
|
|
fprintf(stderr, "ncurses: initscr() failed\n");
|
|
return 0;
|
|
} // if
|
|
|
|
cbreak();
|
|
keypad(stdscr, TRUE);
|
|
noecho();
|
|
start_color();
|
|
use_default_colors();
|
|
|
|
// map to VIO attributes...
|
|
static const short curses_colormap[] = {
|
|
COLOR_BLACK, COLOR_BLUE, COLOR_GREEN, COLOR_CYAN,
|
|
COLOR_RED, COLOR_MAGENTA, COLOR_YELLOW, COLOR_WHITE
|
|
};
|
|
|
|
if (COLORS >= 64) { // foreground and background
|
|
for (uint32 i = 0; i < 8; i++) {
|
|
for (uint32 j = 0; j < 8; j++) {
|
|
const int pair = (int) (i | (j << 3));
|
|
init_pair(pair, curses_colormap[i], (j == 0) ? -1 : curses_colormap[j]);
|
|
} // for
|
|
} // for
|
|
} else if (COLORS >= 8) { // just foregrounds
|
|
for (int i = 0; i < 8; i++)
|
|
init_pair(i, curses_colormap[i], COLOR_BLACK);
|
|
} // else if
|
|
|
|
// (otherwise, we won't set colors at all.)
|
|
|
|
int scrh, scrw;
|
|
getmaxyx(stdscr, scrh, scrw);
|
|
|
|
const size_t buflen = scrw * scrh * sizeof (uint16);
|
|
vio_buffer = malloc(buflen);
|
|
if (!vio_buffer) {
|
|
endwin();
|
|
delwin(stdscr); // not sure if this is safe, but valgrind said it leaks.
|
|
stdscr = NULL;
|
|
return 0;
|
|
} // if
|
|
|
|
memset(vio_buffer, '\0', buflen);
|
|
vio_scrw = (uint16) scrw;
|
|
vio_scrh = (uint16) scrh;
|
|
vio_curx = vio_cury = 0;
|
|
|
|
FIXME("these are just the default values OS/2 4.52 returns");
|
|
vio_cursorinfo.yStart = 15;
|
|
vio_cursorinfo.cEnd = 15;
|
|
vio_cursorinfo.cx = 1;
|
|
vio_cursorinfo.attr = 0;
|
|
|
|
return 1;
|
|
} // initNcurses
|
|
|
|
static void deinitNcurses(void)
|
|
{
|
|
if (!vio_buffer)
|
|
return;
|
|
|
|
// !!! FIXME: this is wrong
|
|
//endwin();
|
|
reset_shell_mode();
|
|
|
|
printf("\n"); fflush(stdout);
|
|
|
|
delwin(stdscr); // not sure if this is safe, but valgrind said it leaks.
|
|
stdscr = NULL;
|
|
free(vio_buffer);
|
|
vio_buffer = NULL;
|
|
vio_curx = vio_cury = vio_scrw = vio_scrh = 0;
|
|
} // deinitNcurses
|
|
|
|
static inline void commitToNcurses(void)
|
|
{
|
|
refresh();
|
|
} // commitToNcurses
|
|
|
|
static void pushToNcurses(const int y, const int x, int numcells, const int commit)
|
|
{
|
|
const uint8 *src = (const uint8 *) (vio_buffer + ((y * vio_scrw) + x));
|
|
const uint32 avail = (((vio_scrh - y) * vio_scrw) - x);
|
|
if (numcells > avail)
|
|
numcells = avail;
|
|
|
|
move(y, x);
|
|
|
|
for (int i = 0; i < numcells; i++) {
|
|
const uint8 viochar = *(src++);
|
|
const uint8 vioattr = *(src++);
|
|
|
|
chtype ch;
|
|
switch (viochar) {
|
|
case 0xC4: ch = ACS_HLINE; break;
|
|
case 0xB3: ch = ACS_VLINE; break;
|
|
case 0xDA: ch = ACS_ULCORNER; break;
|
|
case 0xBF: ch = ACS_URCORNER; break;
|
|
case 0xC0: ch = ACS_LLCORNER; break;
|
|
case 0xD9: ch = ACS_LRCORNER; break;
|
|
default: ch = (chtype) viochar; break;
|
|
} // switch
|
|
|
|
chtype attr = 0;
|
|
|
|
if (COLORS >= 64) { // foreground and background
|
|
const int color = ((vioattr & 0x70) >> 1) | (vioattr & 0x7);
|
|
attr |= COLOR_PAIR(color);
|
|
} else if (COLORS >= 8) { // just foregrounds
|
|
const int color = (vioattr & 0x7);
|
|
attr |= COLOR_PAIR(color);
|
|
} // else if
|
|
|
|
if (vioattr & VIOATTR_INTENSITY)
|
|
attr |= A_BOLD;
|
|
if (vioattr & VIOATTR_BLINK)
|
|
attr |= A_BLINK;
|
|
|
|
addch(ch | attr);
|
|
} // for
|
|
|
|
move(vio_cury, vio_curx);
|
|
|
|
if (commit)
|
|
commitToNcurses();
|
|
} // pushToNcurses
|
|
|
|
APIRET16 VioGetMode(PVIOMODEINFO pvioModeInfo, HVIO hvio)
|
|
{
|
|
TRACE_NATIVE("VioGetMode(%p, %u)", pvioModeInfo, (uint) hvio);
|
|
|
|
if (hvio != 0)
|
|
return ERROR_VIO_INVALID_HANDLE; // !!! FIXME: can be non-zero when VioCreatePS() is implemented.
|
|
else if (pvioModeInfo == NULL)
|
|
return ERROR_VIO_INVALID_PARMS;
|
|
else if (pvioModeInfo->cb != sizeof (*pvioModeInfo))
|
|
return ERROR_VIO_INVALID_LENGTH;
|
|
else if (!initNcurses())
|
|
return ERROR_VIO_INVALID_HANDLE;
|
|
|
|
memset(pvioModeInfo, '\0', sizeof (*pvioModeInfo));
|
|
pvioModeInfo->cb = sizeof (*pvioModeInfo);
|
|
pvioModeInfo->fbType = VGMT_OTHER;
|
|
pvioModeInfo->color = 4;
|
|
pvioModeInfo->col = vio_scrw;
|
|
pvioModeInfo->row = vio_scrh;
|
|
pvioModeInfo->hres = 640;
|
|
pvioModeInfo->vres = 400;
|
|
pvioModeInfo->fmt_ID = 0;
|
|
pvioModeInfo->attrib = 1;
|
|
FIXME("fill in the rest of these");
|
|
//ULONG buf_addr;
|
|
//ULONG buf_length;
|
|
//ULONG full_length;
|
|
//ULONG partial_length;
|
|
//PCHAR ext_data_addr;
|
|
|
|
return NO_ERROR;
|
|
} // VioGetMode
|
|
|
|
APIRET16 VioGetCurPos(PUSHORT pusRow, PUSHORT pusColumn, HVIO hvio)
|
|
{
|
|
TRACE_NATIVE("VioGetCurPos(%p, %p, %u)", pusRow, pusColumn, (uint) hvio);
|
|
|
|
if (hvio != 0)
|
|
return ERROR_VIO_INVALID_HANDLE; // !!! FIXME: can be non-zero when VioCreatePS() is implemented.
|
|
else if (!initNcurses())
|
|
return ERROR_VIO_INVALID_HANDLE;
|
|
|
|
if (pusRow)
|
|
*pusRow = vio_cury;
|
|
|
|
if (pusColumn)
|
|
*pusColumn = vio_curx;
|
|
|
|
return NO_ERROR;
|
|
} // VioGetCurPos
|
|
|
|
APIRET16 VioGetBuf(PULONG pLVB, PUSHORT pcbLVB, HVIO hvio)
|
|
{
|
|
TRACE_NATIVE("VioGetBuf(%p, %p, %u)", pLVB, pcbLVB, (uint) hvio);
|
|
|
|
if (hvio != 0)
|
|
return ERROR_VIO_INVALID_HANDLE; // !!! FIXME: can be non-zero when VioCreatePS() is implemented.
|
|
else if (!initNcurses())
|
|
return ERROR_VIO_INVALID_HANDLE;
|
|
if (pLVB)
|
|
*pLVB = (ULONG) vio_buffer;
|
|
if (pcbLVB)
|
|
*pcbLVB = vio_scrw * vio_scrh * sizeof (ULONG);
|
|
return NO_ERROR;
|
|
} // VioGetBuf
|
|
|
|
APIRET16 VioGetCurType(PVIOCURSORINFO pvioCursorInfo, HVIO hvio)
|
|
{
|
|
TRACE_NATIVE("VioGetCurType(%p, %u)", pvioCursorInfo, (uint) hvio);
|
|
return NO_ERROR;
|
|
|
|
if (hvio != 0)
|
|
return ERROR_VIO_INVALID_HANDLE; // !!! FIXME: can be non-zero when VioCreatePS() is implemented.
|
|
else if (pvioCursorInfo == NULL)
|
|
return ERROR_VIO_INVALID_PARMS;
|
|
else if (!initNcurses())
|
|
return ERROR_VIO_INVALID_HANDLE;
|
|
|
|
memcpy(pvioCursorInfo, &vio_cursorinfo, sizeof (*pvioCursorInfo));
|
|
return NO_ERROR;
|
|
} // VioGetCurType
|
|
|
|
APIRET16 VioScrollUp(USHORT usTopRow, USHORT usLeftCol, USHORT usBotRow, USHORT usRightCol, USHORT cbLines, PBYTE pCell, HVIO hvio)
|
|
{
|
|
TRACE_NATIVE("VioScrollUp(%u, %u, %u, %u, %u, %p, %u)", (uint) usTopRow, (uint) usLeftCol, (uint) usBotRow, (uint) usRightCol, (uint) cbLines, pCell, (uint) hvio);
|
|
FIXME("buggy");
|
|
return NO_ERROR; // !!! FIXME: buggy
|
|
if (hvio != 0)
|
|
return ERROR_VIO_INVALID_HANDLE; // !!! FIXME: can be non-zero when VioCreatePS() is implemented.
|
|
else if (pCell == NULL)
|
|
return ERROR_VIO_INVALID_PARMS;
|
|
else if (!initNcurses())
|
|
return ERROR_VIO_INVALID_HANDLE;
|
|
|
|
if (usLeftCol >= vio_scrw)
|
|
usLeftCol = vio_scrw - 1;
|
|
if (usRightCol >= vio_scrw)
|
|
usRightCol = vio_scrw - 1;
|
|
if (usTopRow >= vio_scrh)
|
|
usTopRow = vio_scrh - 1;
|
|
if (usBotRow >= vio_scrh)
|
|
usBotRow = vio_scrh - 1;
|
|
|
|
if (usLeftCol >= usRightCol)
|
|
return NO_ERROR; // already done.
|
|
else if (usTopRow >= usBotRow)
|
|
return NO_ERROR; // already done.
|
|
else if (cbLines == 0)
|
|
return NO_ERROR; // already done.
|
|
|
|
const uint32 rowlen = (usRightCol - usLeftCol) + 1;
|
|
const uint32 overlines = (cbLines > usTopRow) ? (cbLines - usTopRow) : 0;
|
|
const uint32 collen = ((usBotRow - usTopRow) + 1) - overlines;
|
|
const uint32 adjust = overlines * vio_scrw;
|
|
|
|
uint16 *src = vio_buffer + ((usTopRow * vio_scrw) + usLeftCol) + adjust;
|
|
uint16 *dst = (src - (cbLines * vio_scrw)) + adjust;
|
|
const size_t rowcpylen = rowlen * sizeof (uint16);
|
|
for (uint32 i = 0; i < collen; i++) {
|
|
memcpy(dst, src, rowcpylen);
|
|
src += vio_scrw;
|
|
dst += vio_scrw;
|
|
} // for
|
|
|
|
const uint16 clear_cell = *((uint16 *) pCell);
|
|
for (uint32 i = 0; i < cbLines; i++) {
|
|
if (dst >= (vio_buffer + (vio_scrw * vio_scrh)))
|
|
break; // !!! FIXME: just calculate this outside the loop and adjust cbLines.
|
|
uint16 *origdst = dst;
|
|
for (uint32 j = 0; j < rowlen; j++) {
|
|
*(dst++) = clear_cell;
|
|
}
|
|
dst = origdst + vio_scrw;
|
|
} // for
|
|
|
|
int starty = usTopRow - cbLines;
|
|
if (starty < 0)
|
|
starty = 0;
|
|
int endy = starty + collen + cbLines;
|
|
if (endy >= vio_scrh)
|
|
endy = vio_scrh;
|
|
|
|
for (int y = starty; y < endy; y++)
|
|
pushToNcurses(y, usLeftCol, rowlen, 0);
|
|
commitToNcurses();
|
|
|
|
return NO_ERROR;
|
|
} // VioScrollUp
|
|
|
|
APIRET16 VioSetCurPos(USHORT usRow, USHORT usColumn, HVIO hvio)
|
|
{
|
|
TRACE_NATIVE("VioSetCurPos(%u, %u, %u)", (uint) usRow, (uint) usColumn, (uint) hvio);
|
|
if (hvio != 0)
|
|
return ERROR_VIO_INVALID_HANDLE; // !!! FIXME: can be non-zero when VioCreatePS() is implemented.
|
|
else if (!initNcurses())
|
|
return ERROR_VIO_INVALID_HANDLE;
|
|
else if (usRow >= vio_scrh)
|
|
return ERROR_VIO_ROW;
|
|
else if (usColumn >= vio_scrw)
|
|
return ERROR_VIO_COL;
|
|
|
|
vio_cury = usRow;
|
|
vio_curx = usColumn;
|
|
|
|
move(vio_cury, vio_curx);
|
|
refresh();
|
|
|
|
return NO_ERROR;
|
|
} // VioSetCurPos
|
|
|
|
APIRET16 VioSetCurType(PVIOCURSORINFO pvioCursorInfo, HVIO hvio)
|
|
{
|
|
TRACE_NATIVE("VioSetCurType(%p, %u)", pvioCursorInfo, (uint) hvio);
|
|
FIXME("write me");
|
|
return NO_ERROR;
|
|
} // VioSetCurType
|
|
|
|
APIRET16 VioReadCellStr(PCH pchCellStr, PUSHORT pcb, USHORT usRow, USHORT usColumn, HVIO hvio)
|
|
{
|
|
TRACE_NATIVE("VioReadCellStr(%p, %p, %u, %u, %u)", pchCellStr, pcb, (uint) usRow, (uint) usColumn, (uint) hvio);
|
|
|
|
if (hvio != 0)
|
|
return ERROR_VIO_INVALID_HANDLE; // !!! FIXME: can be non-zero when VioCreatePS() is implemented.
|
|
else if (!initNcurses())
|
|
return ERROR_VIO_INVALID_HANDLE;
|
|
else if (usRow >= vio_scrh)
|
|
return ERROR_VIO_ROW;
|
|
else if (usColumn >= vio_scrw)
|
|
return ERROR_VIO_COL;
|
|
|
|
const uint32 maxidx = ((uint32)vio_scrh) * ((uint32)vio_scrw);
|
|
const uint32 idx = (((uint32)usRow) * ((uint32)vio_scrw)) + ((uint32)usColumn);
|
|
const uint32 avail = (maxidx - idx) * sizeof (uint16);
|
|
if (((uint32) *pcb) > avail)
|
|
*pcb = (USHORT) avail;
|
|
memcpy(pchCellStr, vio_buffer + idx, (size_t) *pcb);
|
|
return NO_ERROR;
|
|
} // VioReadCellStr
|
|
|
|
APIRET16 VioWrtCellStr(PCH pchCellStr, USHORT cb, USHORT usRow, USHORT usColumn, HVIO hvio)
|
|
{
|
|
TRACE_NATIVE("VioWrtCellStr(%p, %u, %u, %u, %u)", pchCellStr, (uint) cb, (uint) usRow, (uint) usColumn, (uint) hvio);
|
|
|
|
if (hvio != 0)
|
|
return ERROR_VIO_INVALID_HANDLE; // !!! FIXME: can be non-zero when VioCreatePS() is implemented.
|
|
else if (!initNcurses())
|
|
return ERROR_VIO_INVALID_HANDLE;
|
|
else if (usRow >= vio_scrh)
|
|
return ERROR_VIO_ROW;
|
|
else if (usColumn >= vio_scrw)
|
|
return ERROR_VIO_COL;
|
|
|
|
const uint16 *src = (uint16 *) pchCellStr;
|
|
uint16 *dst = vio_buffer + ((usRow * vio_scrw) + usColumn);
|
|
const uint32 avail = (((vio_scrh - usRow) * vio_scrw) - usColumn) * sizeof (uint16);
|
|
if (((uint32) cb) > avail)
|
|
cb = (USHORT) avail;
|
|
|
|
memcpy(dst, src, cb); // !!! FIXME: what happens if cb extends into half a cell?
|
|
|
|
pushToNcurses(usRow, usColumn, cb / sizeof (uint16), 1);
|
|
|
|
return NO_ERROR;
|
|
} // VioWrtCellStr
|
|
|
|
APIRET16 VioWrtCharStrAtt(PCH pch, USHORT cb, USHORT usRow, USHORT usColumn, PBYTE pAttr, HVIO hvio)
|
|
{
|
|
TRACE_NATIVE("VioWrtCharStrAtt(%p, %u, %u, %u, %p, %u)", pch, (uint) cb, (uint) usRow, (uint) usColumn, pAttr, (uint) hvio);
|
|
|
|
if (hvio != 0)
|
|
return ERROR_VIO_INVALID_HANDLE; // !!! FIXME: can be non-zero when VioCreatePS() is implemented.
|
|
else if (!initNcurses())
|
|
return ERROR_VIO_INVALID_HANDLE;
|
|
else if (usRow >= vio_scrh)
|
|
return ERROR_VIO_ROW;
|
|
else if (usColumn >= vio_scrw)
|
|
return ERROR_VIO_COL;
|
|
|
|
const uint8 attr = *pAttr;
|
|
const uint8 *src = (uint8 *) pch;
|
|
uint8 *dst = (uint8 *) (vio_buffer + ((usRow * vio_scrw) + usColumn));
|
|
const uint32 avail = (((vio_scrh - usRow) * vio_scrw) - usColumn);
|
|
if (((uint32) cb) > avail)
|
|
cb = (USHORT) avail;
|
|
|
|
for (uint32 i = 0; i < cb; i++, src++) {
|
|
*(dst++) = *src;
|
|
*(dst++) = attr;
|
|
} // for
|
|
|
|
pushToNcurses(usRow, usColumn, cb, 1);
|
|
|
|
return NO_ERROR;
|
|
} // VioWrtCharStrAtt
|
|
|
|
APIRET16 VioWrtNCell(PBYTE pCell, USHORT cb, USHORT usRow, USHORT usColumn, HVIO hvio)
|
|
{
|
|
TRACE_NATIVE("VioWrtNCell(%p, %u, %u, %u, %u)", pCell, (uint) cb, (uint) usRow, (uint) usColumn, (uint) hvio);
|
|
|
|
if (hvio != 0)
|
|
return ERROR_VIO_INVALID_HANDLE; // !!! FIXME: can be non-zero when VioCreatePS() is implemented.
|
|
else if (!initNcurses())
|
|
return ERROR_VIO_INVALID_HANDLE;
|
|
else if (usRow >= vio_scrh)
|
|
return ERROR_VIO_ROW;
|
|
else if (usColumn >= vio_scrw)
|
|
return ERROR_VIO_COL;
|
|
|
|
const uint16 cell = *((uint16 *) pCell);
|
|
uint16 *dst = vio_buffer + ((usRow * vio_scrw) + usColumn);
|
|
const uint32 avail = (((vio_scrh - usRow) * vio_scrw) - usColumn);
|
|
if (((uint32) cb) > avail)
|
|
cb = (USHORT) avail;
|
|
|
|
for (uint32 i = 0; i < cb; i++)
|
|
*(dst++) = cell;
|
|
|
|
pushToNcurses(usRow, usColumn, cb, 1);
|
|
|
|
return NO_ERROR;
|
|
} // VioWrtNCell
|
|
|
|
LX_NATIVE_DESTRUCTOR(viocalls)
|
|
{
|
|
deinitNcurses();
|
|
}
|
|
|
|
// end of viocalls.c ...
|
|
|