pdcurses/pdcscrn.c

changeset 97
2d43f05b284c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pdcurses/pdcscrn.c	Thu Jul 23 18:07:39 2015 +0300
@@ -0,0 +1,620 @@
+/* Public Domain Curses */
+
+#include "pdcwin.h"
+
+RCSID("$Id: pdcscrn.c,v 1.92 2008/07/20 20:12:04 wmcbrine Exp $")
+
+#ifdef CHTYPE_LONG
+# define PDC_OFFSET 32
+#else
+# define PDC_OFFSET  8
+#endif
+
+/* COLOR_PAIR to attribute encoding table. */
+
+unsigned char *pdc_atrtab = (unsigned char *)NULL;
+
+HANDLE pdc_con_out = INVALID_HANDLE_VALUE;
+HANDLE pdc_con_in = INVALID_HANDLE_VALUE;
+
+DWORD pdc_quick_edit;
+
+static short curstoreal[16], realtocurs[16] =
+{
+    COLOR_BLACK, COLOR_BLUE, COLOR_GREEN, COLOR_CYAN, COLOR_RED,
+    COLOR_MAGENTA, COLOR_YELLOW, COLOR_WHITE, COLOR_BLACK + 8,
+    COLOR_BLUE + 8, COLOR_GREEN + 8, COLOR_CYAN + 8, COLOR_RED + 8,
+    COLOR_MAGENTA + 8, COLOR_YELLOW + 8, COLOR_WHITE + 8
+};
+
+enum { PDC_RESTORE_NONE, PDC_RESTORE_BUFFER, PDC_RESTORE_WINDOW };
+
+/* Struct for storing console registry keys, and for use with the 
+   undocumented WM_SETCONSOLEINFO message. Originally by James Brown, 
+   www.catch22.net. */
+
+static struct
+{
+    ULONG    Length;
+    COORD    ScreenBufferSize;
+    COORD    WindowSize;
+    ULONG    WindowPosX;
+    ULONG    WindowPosY;
+
+    COORD    FontSize;
+    ULONG    FontFamily;
+    ULONG    FontWeight;
+    WCHAR    FaceName[32];
+
+    ULONG    CursorSize;
+    ULONG    FullScreen;
+    ULONG    QuickEdit;
+    ULONG    AutoPosition;
+    ULONG    InsertMode;
+    
+    USHORT   ScreenColors;
+    USHORT   PopupColors;
+    ULONG    HistoryNoDup;
+    ULONG    HistoryBufferSize;
+    ULONG    NumberOfHistoryBuffers;
+    
+    COLORREF ColorTable[16];
+
+    ULONG    CodePage;
+    HWND     Hwnd;
+
+    WCHAR    ConsoleTitle[0x100];
+} console_info;
+
+static CONSOLE_SCREEN_BUFFER_INFO orig_scr;
+
+static CHAR_INFO *ci_save = NULL;
+static DWORD old_console_mode = 0;
+
+static bool is_nt;
+
+static HWND _find_console_handle(void)
+{
+    TCHAR orgtitle[1024], temptitle[1024];
+    HWND wnd;
+
+    GetConsoleTitle(orgtitle, 1024);
+
+    wsprintf(temptitle, TEXT("%d/%d"), GetTickCount(), GetCurrentProcessId());
+    SetConsoleTitle(temptitle);
+
+    Sleep(40);
+
+    wnd = FindWindow(NULL, temptitle);
+
+    SetConsoleTitle(orgtitle);
+
+    return wnd;
+}
+
+/* Undocumented console message */
+
+#define WM_SETCONSOLEINFO (WM_USER + 201)
+
+/* Wrapper around WM_SETCONSOLEINFO. We need to create the necessary 
+   section (file-mapping) object in the context of the process which 
+   owns the console, before posting the message. Originally by JB. */
+
+static void _set_console_info(void)
+{
+    CONSOLE_SCREEN_BUFFER_INFO csbi;
+    CONSOLE_CURSOR_INFO cci;
+    DWORD dwConsoleOwnerPid;
+    HANDLE hProcess;
+    HANDLE hSection, hDupSection;
+    PVOID ptrView;
+
+    /* Each-time initialization for console_info */
+
+    GetConsoleCursorInfo(pdc_con_out, &cci);
+    console_info.CursorSize = cci.dwSize;
+
+    GetConsoleScreenBufferInfo(pdc_con_out, &csbi);
+    console_info.ScreenBufferSize = csbi.dwSize;
+
+    console_info.WindowSize.X = csbi.srWindow.Right - csbi.srWindow.Left + 1;
+    console_info.WindowSize.Y = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
+
+    console_info.WindowPosX = csbi.srWindow.Left;
+    console_info.WindowPosY = csbi.srWindow.Top;
+
+    /* Open the process which "owns" the console */
+
+    GetWindowThreadProcessId(console_info.Hwnd, &dwConsoleOwnerPid);
+    
+    hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwConsoleOwnerPid);
+
+    /* Create a SECTION object backed by page-file, then map a view of
+       this section into the owner process so we can write the contents
+       of the CONSOLE_INFO buffer into it */
+
+    hSection = CreateFileMapping(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE,
+                                 0, sizeof(console_info), 0);
+
+    /* Copy our console structure into the section-object */
+
+    ptrView = MapViewOfFile(hSection, FILE_MAP_WRITE|FILE_MAP_READ,
+                            0, 0, sizeof(console_info));
+
+    memcpy(ptrView, &console_info, sizeof(console_info));
+
+    UnmapViewOfFile(ptrView);
+
+    /* Map the memory into owner process */
+
+    DuplicateHandle(GetCurrentProcess(), hSection, hProcess, &hDupSection,
+                    0, FALSE, DUPLICATE_SAME_ACCESS);
+
+    /* Send console window the "update" message */
+
+    SendMessage(console_info.Hwnd, WM_SETCONSOLEINFO, (WPARAM)hDupSection, 0);
+
+    CloseHandle(hSection);
+    CloseHandle(hProcess);
+}
+
+/* One-time initialization for console_info -- color table and font info
+   from the registry; other values from functions. */
+
+static void _init_console_info(void)
+{
+    DWORD scrnmode, len;
+    HKEY reghnd;
+    int i;
+
+    console_info.Hwnd = _find_console_handle();
+    console_info.Length = sizeof(console_info);
+
+    GetConsoleMode(pdc_con_in, &scrnmode);
+    console_info.QuickEdit = !!(scrnmode & 0x0040);
+    console_info.InsertMode = !!(scrnmode & 0x0020);
+
+    console_info.FullScreen = FALSE;
+    console_info.AutoPosition = 0x10000;
+    console_info.ScreenColors = SP->orig_back << 4 | SP->orig_fore;
+    console_info.PopupColors = 0xf5;
+    
+    console_info.HistoryNoDup = FALSE;
+    console_info.HistoryBufferSize = 50;
+    console_info.NumberOfHistoryBuffers = 4;
+
+    console_info.CodePage = GetConsoleOutputCP();
+
+    RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("Console"), 0,
+                 KEY_QUERY_VALUE, &reghnd);
+
+    len = sizeof(DWORD);
+
+    /* Default color table */
+
+    for (i = 0; i < 16; i++)
+    {
+        char tname[13];
+
+        sprintf(tname, "ColorTable%02d", i);
+        RegQueryValueExA(reghnd, tname, NULL, NULL,
+                         (LPBYTE)(&(console_info.ColorTable[i])), &len);
+    }
+
+    /* Font info */
+
+    RegQueryValueEx(reghnd, TEXT("FontSize"), NULL, NULL,
+                    (LPBYTE)(&console_info.FontSize), &len);
+    RegQueryValueEx(reghnd, TEXT("FontFamily"), NULL, NULL,
+                    (LPBYTE)(&console_info.FontFamily), &len);
+    RegQueryValueEx(reghnd, TEXT("FontWeight"), NULL, NULL,
+                    (LPBYTE)(&console_info.FontWeight), &len);
+
+    len = sizeof(WCHAR) * 32;
+    RegQueryValueExW(reghnd, L"FaceName", NULL, NULL,
+                     (LPBYTE)(console_info.FaceName), &len);
+
+    RegCloseKey(reghnd);
+}
+
+/* close the physical screen -- may restore the screen to its state
+   before PDC_scr_open(); miscellaneous cleanup */
+
+void PDC_scr_close(void)
+{
+    COORD origin;
+    SMALL_RECT rect;
+
+    PDC_LOG(("PDC_scr_close() - called\n"));
+
+    PDC_reset_shell_mode();
+
+    if (SP->_restore != PDC_RESTORE_NONE)
+    {
+        if (SP->_restore == PDC_RESTORE_WINDOW)
+        {
+            rect.Top = orig_scr.srWindow.Top;
+            rect.Left = orig_scr.srWindow.Left;
+            rect.Bottom = orig_scr.srWindow.Bottom;
+            rect.Right = orig_scr.srWindow.Right;
+        }
+        else    /* PDC_RESTORE_BUFFER */
+        {
+            rect.Top = rect.Left = 0;
+            rect.Bottom = orig_scr.dwSize.Y - 1;
+            rect.Right = orig_scr.dwSize.X - 1;
+        }
+
+        origin.X = origin.Y = 0;
+
+        if (!WriteConsoleOutput(pdc_con_out, ci_save, orig_scr.dwSize, 
+                                origin, &rect))
+            return;
+    }
+
+    if (SP->visibility != 1)
+        curs_set(1);
+
+    /* Position cursor to the bottom left of the screen. */
+
+    PDC_gotoyx(PDC_get_buffer_rows() - 2, 0);
+}
+
+void PDC_scr_free(void)
+{
+    if (SP)
+        free(SP);
+    if (pdc_atrtab)
+        free(pdc_atrtab);
+
+    pdc_atrtab = (unsigned char *)NULL;
+}
+
+/* open the physical screen -- allocate SP, miscellaneous intialization,
+   and may save the existing screen for later restoration */
+
+int PDC_scr_open(int argc, char **argv)
+{
+    COORD bufsize, origin;
+    SMALL_RECT rect;
+    const char *str;
+    CONSOLE_SCREEN_BUFFER_INFO csbi;
+    int i;
+
+    PDC_LOG(("PDC_scr_open() - called\n"));
+
+    SP = calloc(1, sizeof(SCREEN));
+    pdc_atrtab = calloc(PDC_COLOR_PAIRS * PDC_OFFSET, 1);
+
+    if (!SP || !pdc_atrtab)
+        return ERR;
+
+    for (i = 0; i < 16; i++)
+        curstoreal[realtocurs[i]] = i;
+
+    pdc_con_out = GetStdHandle(STD_OUTPUT_HANDLE);
+    pdc_con_in = GetStdHandle(STD_INPUT_HANDLE);
+
+    if (GetFileType(pdc_con_in) != FILE_TYPE_CHAR)
+    {
+        fprintf(stderr, "\nRedirection is not supported.\n");
+        exit(1);
+    }
+
+    is_nt = !(GetVersion() & 0x80000000);
+
+    GetConsoleScreenBufferInfo(pdc_con_out, &csbi);
+    GetConsoleScreenBufferInfo(pdc_con_out, &orig_scr);
+    GetConsoleMode(pdc_con_in, &old_console_mode);
+
+    /* preserve QuickEdit Mode setting for use in PDC_mouse_set() when
+       the mouse is not enabled -- other console input settings are
+       cleared */
+
+    pdc_quick_edit = old_console_mode & 0x0040;
+
+    SP->lines = (str = getenv("LINES")) ? atoi(str) : PDC_get_rows();
+    SP->cols = (str = getenv("COLS")) ? atoi(str) : PDC_get_columns();
+
+    SP->mouse_wait = PDC_CLICK_PERIOD;
+    SP->audible = TRUE;
+
+    if (SP->lines < 2 || SP->lines > csbi.dwMaximumWindowSize.Y)
+    {
+        fprintf(stderr, "LINES value must be >= 2 and <= %d: got %d\n",
+                csbi.dwMaximumWindowSize.Y, SP->lines);
+
+        return ERR;
+    }
+
+    if (SP->cols < 2 || SP->cols > csbi.dwMaximumWindowSize.X)
+    {
+        fprintf(stderr, "COLS value must be >= 2 and <= %d: got %d\n",
+                csbi.dwMaximumWindowSize.X, SP->cols);
+
+        return ERR;
+    }
+
+    SP->orig_fore = csbi.wAttributes & 0x0f;
+    SP->orig_back = (csbi.wAttributes & 0xf0) >> 4;
+
+    SP->orig_attr = TRUE;
+
+    SP->_restore = PDC_RESTORE_NONE;
+
+    if (getenv("PDC_RESTORE_SCREEN"))
+    {
+        /* Attempt to save the complete console buffer */
+
+        ci_save = malloc(orig_scr.dwSize.X * orig_scr.dwSize.Y *
+                         sizeof(CHAR_INFO));
+
+        if (!ci_save)
+        {
+            PDC_LOG(("PDC_scr_open() - malloc failure (1)\n"));
+
+            return ERR;
+        }
+
+        bufsize.X = orig_scr.dwSize.X;
+        bufsize.Y = orig_scr.dwSize.Y;
+
+        origin.X = origin.Y = 0;
+
+        rect.Top = rect.Left = 0;
+        rect.Bottom = orig_scr.dwSize.Y  - 1;
+        rect.Right = orig_scr.dwSize.X - 1;
+
+        if (!ReadConsoleOutput(pdc_con_out, ci_save, bufsize, origin, &rect))
+        {
+            /* We can't save the complete buffer, so try and save just 
+               the displayed window */
+
+            free(ci_save);
+            ci_save = NULL;
+
+            bufsize.X = orig_scr.srWindow.Right - orig_scr.srWindow.Left + 1;
+            bufsize.Y = orig_scr.srWindow.Bottom - orig_scr.srWindow.Top + 1;
+
+            ci_save = malloc(bufsize.X * bufsize.Y * sizeof(CHAR_INFO));
+
+            if (!ci_save)
+            {
+                PDC_LOG(("PDC_scr_open() - malloc failure (2)\n"));
+
+                return ERR;
+            }
+
+            origin.X = origin.Y = 0;
+
+            rect.Top = orig_scr.srWindow.Top;
+            rect.Left = orig_scr.srWindow.Left;
+            rect.Bottom = orig_scr.srWindow.Bottom;
+            rect.Right = orig_scr.srWindow.Right;
+
+            if (!ReadConsoleOutput(pdc_con_out, ci_save, bufsize, 
+                                   origin, &rect))
+            {
+#ifdef PDCDEBUG
+                CHAR LastError[256];
+
+                FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, 
+                              GetLastError(), MAKELANGID(LANG_NEUTRAL, 
+                              SUBLANG_DEFAULT), LastError, 256, NULL);
+
+                PDC_LOG(("PDC_scr_open() - %s\n", LastError));
+#endif
+                free(ci_save);
+                ci_save = NULL;
+
+                return ERR;
+            }
+
+            SP->_restore = PDC_RESTORE_WINDOW;
+        }
+        else
+            SP->_restore = PDC_RESTORE_BUFFER;
+    }
+
+    SP->_preserve = (getenv("PDC_PRESERVE_SCREEN") != NULL);
+
+    PDC_reset_prog_mode();
+
+    SP->mono = FALSE;
+
+    return OK;
+}
+
+ /* Calls SetConsoleWindowInfo with the given parameters, but fits them 
+    if a scoll bar shrinks the maximum possible value. The rectangle 
+    must at least fit in a half-sized window. */
+
+static BOOL _fit_console_window(HANDLE con_out, CONST SMALL_RECT *rect)
+{
+    SMALL_RECT run;
+    SHORT mx, my;
+
+    if (SetConsoleWindowInfo(con_out, TRUE, rect))
+        return TRUE;
+
+    run = *rect;
+    run.Right /= 2;
+    run.Bottom /= 2;
+
+    mx = run.Right;
+    my = run.Bottom;
+
+    if (!SetConsoleWindowInfo(con_out, TRUE, &run))
+        return FALSE;
+
+    for (run.Right = rect->Right; run.Right >= mx; run.Right--)
+        if (SetConsoleWindowInfo(con_out, TRUE, &run))
+            break;
+
+    if (run.Right < mx)
+        return FALSE;
+
+    for (run.Bottom = rect->Bottom; run.Bottom >= my; run.Bottom--)
+        if (SetConsoleWindowInfo(con_out, TRUE, &run))
+            return TRUE;
+
+    return FALSE;
+}
+
+/* the core of resize_term() */
+
+int PDC_resize_screen(int nlines, int ncols)
+{
+    SMALL_RECT rect;
+    COORD size, max;
+
+    if (nlines < 2 || ncols < 2)
+        return ERR;
+
+    max = GetLargestConsoleWindowSize(pdc_con_out);
+
+    rect.Left = rect.Top = 0;
+    rect.Right = ncols - 1;
+
+    if (rect.Right > max.X)
+        rect.Right = max.X;
+
+    rect.Bottom = nlines - 1;
+
+    if (rect.Bottom > max.Y)
+        rect.Bottom = max.Y;
+
+    size.X = rect.Right + 1;
+    size.Y = rect.Bottom + 1;
+
+    _fit_console_window(pdc_con_out, &rect);
+    SetConsoleScreenBufferSize(pdc_con_out, size);
+    _fit_console_window(pdc_con_out, &rect);
+    SetConsoleScreenBufferSize(pdc_con_out, size);
+    SetConsoleActiveScreenBuffer(pdc_con_out);
+
+    return OK;
+}
+
+void PDC_reset_prog_mode(void)
+{
+    PDC_LOG(("PDC_reset_prog_mode() - called.\n"));
+
+    if (is_nt)
+    {
+        COORD bufsize;
+        SMALL_RECT rect;
+
+        bufsize.X = orig_scr.srWindow.Right - orig_scr.srWindow.Left + 1;
+        bufsize.Y = orig_scr.srWindow.Bottom - orig_scr.srWindow.Top + 1;
+
+        rect.Top = rect.Left = 0;
+        rect.Bottom = bufsize.Y - 1;
+        rect.Right = bufsize.X - 1;
+
+        SetConsoleScreenBufferSize(pdc_con_out, bufsize);
+        SetConsoleWindowInfo(pdc_con_out, TRUE, &rect);
+        SetConsoleScreenBufferSize(pdc_con_out, bufsize);
+        SetConsoleActiveScreenBuffer(pdc_con_out);
+    }
+
+    PDC_mouse_set();
+}
+
+void PDC_reset_shell_mode(void)
+{
+    PDC_LOG(("PDC_reset_shell_mode() - called.\n"));
+
+    if (is_nt)
+    {
+        SetConsoleScreenBufferSize(pdc_con_out, orig_scr.dwSize);
+        SetConsoleWindowInfo(pdc_con_out, TRUE, &orig_scr.srWindow);
+        SetConsoleScreenBufferSize(pdc_con_out, orig_scr.dwSize);
+        SetConsoleWindowInfo(pdc_con_out, TRUE, &orig_scr.srWindow);
+        SetConsoleActiveScreenBuffer(pdc_con_out);
+    }
+
+    SetConsoleMode(pdc_con_in, old_console_mode);
+}
+
+void PDC_restore_screen_mode(int i)
+{
+}
+
+void PDC_save_screen_mode(int i)
+{
+}
+
+void PDC_init_pair(short pair, short fg, short bg)
+{
+    unsigned char att, temp_bg;
+    chtype i;
+
+    fg = curstoreal[fg];
+    bg = curstoreal[bg];
+
+    for (i = 0; i < PDC_OFFSET; i++)
+    {
+        att = fg | (bg << 4);
+
+        if (i & (A_REVERSE >> PDC_ATTR_SHIFT))
+            att = bg | (fg << 4);
+        if (i & (A_UNDERLINE >> PDC_ATTR_SHIFT))
+            att = 1;
+        if (i & (A_INVIS >> PDC_ATTR_SHIFT))
+        {
+            temp_bg = att >> 4;
+            att = temp_bg << 4 | temp_bg;
+        }
+        if (i & (A_BOLD >> PDC_ATTR_SHIFT))
+            att |= 8;
+        if (i & (A_BLINK >> PDC_ATTR_SHIFT))
+            att |= 128;
+
+        pdc_atrtab[pair * PDC_OFFSET + i] = att;
+    }
+}
+
+int PDC_pair_content(short pair, short *fg, short *bg)
+{
+    *fg = realtocurs[pdc_atrtab[pair * PDC_OFFSET] & 0x0F];
+    *bg = realtocurs[(pdc_atrtab[pair * PDC_OFFSET] & 0xF0) >> 4];
+
+    return OK;
+}
+
+bool PDC_can_change_color(void)
+{
+    return is_nt;
+}
+
+int PDC_color_content(short color, short *red, short *green, short *blue)
+{
+    DWORD col;
+
+    if (!console_info.Hwnd)
+        _init_console_info();
+
+    col = console_info.ColorTable[curstoreal[color]];
+
+    *red = DIVROUND(GetRValue(col) * 1000, 255);
+    *green = DIVROUND(GetGValue(col) * 1000, 255);
+    *blue = DIVROUND(GetBValue(col) * 1000, 255);
+
+    return OK;
+}
+
+int PDC_init_color(short color, short red, short green, short blue)
+{
+    if (!console_info.Hwnd)
+        _init_console_info();
+
+    console_info.ColorTable[curstoreal[color]] =
+        RGB(DIVROUND(red * 255, 1000),
+            DIVROUND(green * 255, 1000),
+            DIVROUND(blue * 255, 1000));
+
+    _set_console_info();
+
+    return OK;
+}

mercurial