home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 5 Edit
/
05-Edit.zip
/
vile-src.zip
/
vile-8.1
/
ntwinio.c
< prev
next >
Wrap
C/C++ Source or Header
|
1998-09-27
|
62KB
|
2,748 lines
/*
* Uses the Win32 screen API.
*
* $Header: /usr/build/vile/vile/RCS/ntwinio.c,v 1.34 1998/09/28 01:05:51 cmorgan Exp $
* Written by T.E.Dickey for vile (october 1997).
* -- improvements by Clark Morgan (see w32cbrd.c, w32pipe.c).
*/
#include <windows.h>
#include <windowsx.h>
#include <commdlg.h>
#include <stdlib.h>
#include <math.h>
#define termdef 1 /* don't define "term" external */
#include "estruct.h"
#include "edef.h"
#include "pscreen.h"
#undef RECT /* FIXME: symbol conflict */
#define MIN_ROWS MINWLNS
#define MIN_COLS 15
#define FIXME_POSCHANGING 1 /* this doesn't seem to help */
#define FIXME_RECUR_SB 0 /* I'm not sure this is needed */
#if OPT_TRACE
#define IGN_PROC(tag,name) \
case name: \
TRACE((tag #name " (ignored)\n")) \
break;
#define DEF_PROC(tag,name) \
case name: \
TRACE((tag #name " (%s)\n", which_window(hWnd))) \
return (DefWindowProc(hWnd, message, wParam, lParam))
#else
#define IGN_PROC(tag,name) case name: break;
#define DEF_PROC(tag,name) /*nothing*/
#endif
#define MAIN_CLASS "VileMain"
#define TEXT_CLASS "VileText"
#define SCRL_CLASS "SCROLLBAR"
#define GRIP_CLASS "VileResize"
#define MY_APPLE "Vile Application"
#define MY_FONT SYSTEM_FIXED_FONT /* or ANSI_FIXED_FONT */
#define GetMyFont() vile_font
#define MM_FILE 1
#define MM_FONT 2
#define NROW 128 /* Max Screen size. */
#define NCOL 256 /* Edit if you want to. */
#define MARGIN 8 /* size of minimum margin and */
#define SCRSIZ 64 /* scroll size for extended lines */
#define NPAUSE 200 /* # times thru update to pause */
#define NOKYMAP (-1)
#define SetCols(value) term.t_ncol = cur_win->cols = value
#define SetRows(value) term.t_nrow = cur_win->rows = value
#define AttrColor(b,f) ((WORD)(((ctrans[b] & 15) << 4) | (ctrans[f] & 15)))
#define RowToPixel(n) ((n) * nLineHeight)
#define ColToPixel(n) ((n) * nCharWidth)
#define PixelToRow(n) ((n) / nLineHeight)
#define PixelToCol(n) ((n) / nCharWidth)
#define RectToCols(rect) (PixelToCol(rect.right - rect.left - SbWidth))
#define RectToRows(rect) (PixelToRow(rect.bottom - rect.top))
#if OPT_SCROLLBARS
#define SbWidth nLineHeight
#else
#define SbWidth 0
#endif
static int ntgetch (void);
static void ntmove (int, int);
static void nteeol (void);
static void nteeop (void);
static void ntbeep (void);
static void ntopen (void);
static void ntrev (UINT);
static int ntcres (const char *);
static void ntclose (void);
static void ntputc (int);
static int nttypahead (void);
static void ntkopen (void);
static void ntkclose (void);
#if OPT_COLOR
static void ntfcol (int);
static void ntbcol (int);
#endif
static void ntflush (void);
static void ntscroll (int, int, int);
#if OPT_ICURSOR
static void nticursor (int);
#endif
#if OPT_TITLE
static void nttitle (char *);
#endif
static HANDLE vile_hinstance;
static HMENU vile_menu;
static HFONT vile_font;
static LOGFONT vile_logfont;
static HANDLE hAccTable; /* handle to accelerator table */
static HCURSOR hglass_cursor;
static HCURSOR arrow_cursor;
static int nLineHeight = 10;
static int nCharWidth = 8;
static int caret_disabled = FALSE;
static int caret_visible = 0;
static int caret_exists = 0;
static int vile_in_getfkey = 0;
static int vile_resizing = FALSE; /* rely on repaint_window if true */
static int dont_update_sb = FALSE;
static DWORD default_fcolor;
static DWORD default_bcolor;
#ifdef VILE_OLE
static OLEAUTO_OPTIONS oa_opts;
#endif
static int nfcolor = -1; /* normal foreground color */
static int nbcolor = -1; /* normal background color */
static int ninvert = FALSE; /* normal colors inverted? */
static int crow = -1; /* current row */
static int ccol = -1; /* current col */
/* ansi to ibm color translation table */
static const char *initpalettestr = "0 4 2 6 1 5 3 7 8 12 10 14 9 13 11 15";
/* black, red, green, yellow, blue, magenta, cyan, white */
static int cur_pos = 0;
static VIDEO_ATTR cur_atr = 0;
typedef struct {
HWND w;
RECT r;
int shown;
} SBDATA;
struct gui_info {
HWND main_hwnd; /* the top-level window */
HWND text_hwnd; /* the enclosed text area */
int closed;
int cols;
int rows;
RECT xy_limit;
int x_border;
int y_border;
int y_titles; /* height of caption/titles */
int nscrollbars;
int maxscrollbars;
SBDATA *scrollbars;
SBDATA size_box;
SBDATA size_grip;
} only_window, *cur_win = &only_window;
#if OPT_SCROLLBARS
static int check_scrollbar_allocs(void);
static void update_scrollbar_sizes(void);
#endif
/*
* Standard terminal interface dispatch table. None of the fields point into
* "termio" code.
*/
TERM term = {
NROW,
NROW,
NCOL,
NCOL,
MARGIN,
SCRSIZ,
NPAUSE,
ntopen,
ntclose,
ntkopen,
ntkclose,
ntgetch,
ntputc,
nttypahead,
ntflush,
ntmove,
nteeol,
nteeop,
ntbeep,
ntrev,
ntcres,
#if OPT_COLOR
ntfcol,
ntbcol,
set_ctrans,
#else
null_t_setfor,
null_t_setback,
null_t_setpal,
#endif
ntscroll,
null_t_pflush,
#if OPT_ICURSOR
nticursor,
#else
null_t_icursor,
#endif
#if OPT_TITLE
nttitle,
#else
null_t_title,
#endif
null_t_watchfd,
null_t_unwatchfd,
};
#if OPT_TRACE
static char *
which_window(HWND hwnd)
{
if (hwnd == 0) {
return "NULL";
} if (hwnd == cur_win->main_hwnd) {
return "main";
} else if (hwnd == cur_win->text_hwnd) {
return "text";
} else {
int n;
static char temp[20];
sprintf(temp, "%#lx", hwnd);
for (n = 0; n < cur_win->nscrollbars; n++) {
if (hwnd == cur_win->scrollbars[n].w) {
sprintf(temp, "sb%d", n);
break;
}
}
return temp;
}
}
static char *
message2s(unsigned code)
{
static struct {
WORD code;
char *name;
} table[] = {
{ WM_ACTIVATE, "WM_ACTIVATE" },
{ WM_ACTIVATEAPP, "WM_ACTIVATEAPP" },
{ WM_CANCELMODE, "WM_CANCELMODE" },
{ WM_CAPTURECHANGED, "WM_CAPTURECHANGED" },
{ WM_CLOSE, "WM_CLOSE" },
{ WM_CREATE, "WM_CREATE" },
{ WM_CTLCOLORSCROLLBAR, "WM_CTLCOLORSCROLLBAR" },
{ WM_ENABLE, "WM_ENABLE" },
{ WM_ENTERIDLE, "WM_ENTERIDLE" },
{ WM_ENTERMENULOOP, "WM_ENTERMENULOOP" },
{ WM_ENTERSIZEMOVE, "WM_ENTERSIZEMOVE" },
{ WM_ERASEBKGND, "WM_ERASEBKGND" },
{ WM_EXITMENULOOP, "WM_EXITMENULOOP" },
{ WM_EXITSIZEMOVE, "WM_EXITSIZEMOVE" },
{ WM_GETMINMAXINFO, "WM_GETMINMAXINFO" },
{ WM_GETTEXT, "WM_GETTEXT" },
{ WM_KILLFOCUS, "WM_KILLFOCUS" },
{ WM_INITMENU, "WM_INITMENU" },
{ WM_INITMENUPOPUP, "WM_INITMENUPOPUP" },
{ WM_KEYDOWN, "WM_KEYDOWN" },
{ WM_KEYUP, "WM_KEYUP" },
{ WM_MENUSELECT, "WM_MENUSELECT" },
{ WM_MOUSEACTIVATE, "WM_MOUSEACTIVATE" },
{ WM_MOVE, "WM_MOVE" },
{ WM_MOVING, "WM_MOVING" },
{ WM_NCACTIVATE, "WM_NCACTIVATE" },
{ WM_NCCALCSIZE, "WM_NCCALCSIZE" },
{ WM_NCCREATE, "WM_NCCREATE" },
{ WM_NCHITTEST, "WM_NCHITTEST" },
{ WM_NCLBUTTONDOWN, "WM_NCLBUTTONDOWN" },
{ WM_NCMOUSEMOVE, "WM_NCMOUSEMOVE" },
{ WM_NCPAINT, "WM_NCPAINT" },
{ WM_PAINT, "WM_PAINT" },
{ WM_PARENTNOTIFY, "WM_PARENTNOTIFY" },
{ WM_QUERYNEWPALETTE, "WM_QUERYNEWPALETTE" },
{ WM_SETCURSOR, "WM_SETCURSOR" },
{ WM_SETFOCUS, "WM_SETFOCUS" },
{ WM_SETTEXT, "WM_SETTEXT" },
{ WM_SHOWWINDOW, "WM_SHOWWINDOW" },
{ WM_SIZE, "WM_SIZE" },
{ WM_SIZING, "WM_SIZING" },
{ WM_SYSCOMMAND, "WM_SYSCOMMAND" },
{ WM_WINDOWPOSCHANGED, "WM_WINDOWPOSCHANGED" },
{ WM_WINDOWPOSCHANGING, "WM_WINDOWPOSCHANGING" },
};
size_t n;
static char temp[20];
for (n = 0; n < TABLESIZE(table); n++) {
if (table[n].code == code) {
return table[n].name;
}
}
sprintf(temp, "%#x", code);
return temp;
}
static char *
syscommand2s(unsigned code)
{
static struct {
WORD code;
char *name;
} table[] = {
{ SC_SIZE, "SC_SIZE" },
{ SC_MOVE, "SC_MOVE" },
{ SC_MINIMIZE, "SC_MINIMIZE" },
{ SC_MAXIMIZE, "SC_MAXIMIZE" },
{ SC_NEXTWINDOW, "SC_NEXTWINDOW" },
{ SC_PREVWINDOW, "SC_PREVWINDOW" },
{ SC_CLOSE, "SC_CLOSE" },
{ SC_VSCROLL, "SC_VSCROLL" },
{ SC_HSCROLL, "SC_HSCROLL" },
{ SC_MOUSEMENU, "SC_MOUSEMENU" },
{ SC_KEYMENU, "SC_KEYMENU" },
{ SC_ARRANGE, "SC_ARRANGE" },
{ SC_RESTORE, "SC_RESTORE" },
{ SC_TASKLIST, "SC_TASKLIST" },
{ SC_SCREENSAVE, "SC_SCREENSAVE" },
{ SC_HOTKEY, "SC_HOTKEY" },
};
size_t n;
static char temp[80];
unsigned remainder = code & 0xf;
for (n = 0; n < TABLESIZE(table); n++) {
if (table[n].code == (code - remainder)) {
sprintf(temp, "%s+%X", table[n].name, remainder);
return temp;
}
}
sprintf(temp, "%#x", code);
return temp;
}
static void
TraceWindowRect(HWND hwnd)
{
RECT wrect;
int rows;
int cols;
GetWindowRect(hwnd, &wrect);
cols = RectToCols(wrect);
rows = RectToRows(wrect);
TRACE(("... (%3d,%3d) (%3d,%3d), window is %dx%d cells (%dx%d pixels)%s\n",
wrect.top, wrect.left,
wrect.bottom, wrect.right,
rows,
cols,
RowToPixel(rows),
ColToPixel(cols),
IsZoomed(hwnd) ? " zoomed" : ""
))
}
static void
TraceClientRect(HWND hwnd)
{
RECT crect;
int rows;
int cols;
GetClientRect(hwnd, &crect);
cols = RectToCols(crect);
rows = RectToRows(crect);
TRACE(("... (%3d,%3d) (%3d,%3d), client is %dx%d cells (%dx%d pixels)\n",
crect.top, crect.left,
crect.bottom, crect.right,
rows,
cols,
RowToPixel(rows),
ColToPixel(cols)
))
}
#else
#define TraceWindowRect(hwnd) /* nothing */
#define TraceClientRect(hwnd) /* nothing */
#endif
static HBRUSH
Background(HDC hdc)
{
TRACE(("Background %#06x\n", GetBkColor(hdc)))
return CreateSolidBrush(GetBkColor(hdc));
}
void
gui_resize(int cols, int rows)
{
static int level;
RECT crect;
RECT wrect;
int main_wide;
int main_high;
int text_wide;
int text_high;
level++;
TRACE(("gui_resize(%d x %d) begin %d\n", rows, cols, level))
TraceWindowRect(cur_win->main_hwnd);
TraceClientRect(cur_win->main_hwnd);
GetClientRect(cur_win->main_hwnd, &crect);
GetWindowRect(cur_win->main_hwnd, &wrect);
text_wide = ColToPixel(cols);
text_high = RowToPixel(rows);
wrect.right += text_wide - crect.right;
wrect.bottom += text_high - crect.bottom;
#if FIXME_POSCHANGING
main_wide = text_wide + (2 * cur_win->x_border) + SbWidth;
main_high = text_high + (2 * cur_win->y_border) + cur_win->y_titles;
#else
main_wide = wrect.right - wrect.left + SbWidth;
main_high = wrect.bottom - wrect.top;
#endif
TRACE(("... gui_resize -> (%d,%d) (%d,%d) main %dx%d, text %dx%d\n",
wrect.top,
wrect.left,
wrect.bottom,
wrect.right,
main_high,
main_wide,
text_high,
text_wide))
MoveWindow(cur_win->main_hwnd,
wrect.left,
wrect.top,
main_wide,
main_high,
TRUE);
MoveWindow(cur_win->text_hwnd,
0,
0,
text_wide,
text_high,
TRUE);
TraceWindowRect(cur_win->main_hwnd);
TraceClientRect(cur_win->main_hwnd);
#if OPT_SCROLLBARS
update_scrollbar_sizes();
#endif
TRACE(("... gui_resize finish %d\n", level))
level--;
}
static int
AdjustedHeight(int high)
{
int extra = cur_win->y_titles + (2 * cur_win->y_border);
int rows;
if (high > cur_win->xy_limit.bottom)
high = cur_win->xy_limit.bottom;
rows = (high - extra) / nLineHeight;
if (rows < MIN_ROWS)
rows = MIN_ROWS;
return (rows * nLineHeight) + extra;
}
static int
AdjustedWidth(int wide)
{
int extra = SbWidth + (2 * cur_win->x_border);
int cols;
if (wide > cur_win->xy_limit.right)
wide = cur_win->xy_limit.right;
cols = (wide - extra) / nCharWidth;
if (cols < MIN_COLS)
cols = MIN_COLS;
return (cols * nCharWidth) + extra;
}
#if FIXME_POSCHANGING
static int
AdjustPosChanging(HWND hwnd, WINDOWPOS *pos)
{
if (!(pos->flags & SWP_NOSIZE)) {
int wide = AdjustedWidth(pos->cx);
int high = AdjustedHeight(pos->cy);
TRACE(("...%s position %d,%d, resize from %d,%d to %d,%d\n",
IsZoomed(hwnd) ? " zoomed" : "",
pos->y, pos->x,
pos->cy, pos->cx, high, wide))
pos->cx = wide;
pos->cy = high;
}
return 0;
}
#endif
/*
* Handle WM_SIZING, forcing the screen size to stay in multiples of a
* character cell.
*/
static int
AdjustResizing(HWND hwnd, WPARAM fwSide, RECT *rect)
{
int wide = rect->right - rect->left;
int high = rect->bottom - rect->top;
int adjX = wide - AdjustedWidth(wide);
int adjY = high - AdjustedHeight(high);
TRACE(("AdjustResizing now (%d,%d) (%d,%d) (%dx%d pixels)\n",
rect->top, rect->left, rect->bottom, rect->right,
rect->bottom - rect->top,
rect->right - rect->left))
TraceWindowRect(hwnd);
TraceClientRect(hwnd);
if (fwSide == WMSZ_LEFT
|| fwSide == WMSZ_TOPLEFT
|| fwSide == WMSZ_BOTTOMLEFT)
rect->left += adjX;
else
if (fwSide == WMSZ_RIGHT
|| fwSide == WMSZ_TOPRIGHT
|| fwSide == WMSZ_BOTTOMRIGHT)
rect->right -= adjX;
if (fwSide == WMSZ_TOP
|| fwSide == WMSZ_TOPLEFT
|| fwSide == WMSZ_TOPRIGHT)
rect->top += adjY;
else
if (fwSide == WMSZ_BOTTOM
|| fwSide == WMSZ_BOTTOMLEFT
|| fwSide == WMSZ_BOTTOMRIGHT)
rect->bottom -= adjY;
TRACE(("... AdjustResizing (%d,%d) (%d,%d) adjY:%d, adjX:%d\n",
rect->top, rect->left, rect->bottom, rect->right,
adjY, adjX))
return TRUE;
}
static void
ResizeClient()
{
static int level;
int h, w;
RECT crect;
if (cur_win->closed) {
TRACE(("ResizeClient ignored (closed)\n"))
return;
}
level++;
TRACE(("ResizeClient begin %d, currently %dx%d\n", level, term.t_nrow, term.t_ncol))
TraceWindowRect(cur_win->main_hwnd);
TraceClientRect(cur_win->main_hwnd);
GetClientRect(cur_win->main_hwnd, &crect);
h = RectToRows(crect);
w = RectToCols(crect);
/*
* The WM_WINDOWPOSCHANGING message is supposed to allow modification
* to keep a window in bounds. But it doesn't work. This does (by
* forcing the calls on MoveWindow to have a "good" value).
*/
if (h < MIN_ROWS)
h = MIN_ROWS;
if (w < MIN_COLS)
w = MIN_COLS;
if ((h > 1 && h != term.t_nrow) || (w > 1 && w != term.t_ncol)) {
TRACE(("...ResizeClient %dx%d\n", h, w))
vile_resizing = TRUE;
newscreensize(h, w);
SetRows(h);
SetCols(w);
#if OPT_SCROLLBARS
if (check_scrollbar_allocs() == TRUE) /* no allocation failure */
update_scrollbar_sizes();
#endif
vile_resizing = FALSE;
TRACE(("...ResizeClient %dx%d\n", h, w))
} else {
TRACE(("ResizeClient ignored (h=%d, w=%d, vs %d x %d)\n",
h, w, term.t_nrow, term.t_ncol));
}
gui_resize(w, h);
TRACE(("...ResizeClient finish %d\n", level))
level--;
}
#define LTGRAY_COLOR 140
#define NORMAL_COLOR 180
#define BRIGHT_COLOR 255
static COLORREF
color_of (int code)
{
int red = 0, green = 0, blue = 0;
COLORREF result = 0;
if (code & 1)
red = NORMAL_COLOR;
if (code & 2)
green = NORMAL_COLOR;
if (code & 4)
blue = NORMAL_COLOR;
if (code & 8) {
if (red) red = BRIGHT_COLOR;
if (green) green = BRIGHT_COLOR;
if (blue) blue = BRIGHT_COLOR;
if (code == 8) {
red = LTGRAY_COLOR;
green = LTGRAY_COLOR;
blue = LTGRAY_COLOR;
}
}
return PALETTERGB(red, green, blue);
}
static void
attr_to_colors(VIDEO_ATTR attr, int *fcolor, int *bcolor)
{
*fcolor = nfcolor;
*bcolor = nbcolor;
ninvert = FALSE;
if (attr) {
if (attr & VASPCOL)
*fcolor = (attr & (NCOLORS - 1));
else if (attr == VABOLD)
*fcolor |= FOREGROUND_INTENSITY;
else if (attr == VAITAL)
*bcolor |= BACKGROUND_INTENSITY;
else if (attr & VACOLOR)
*fcolor = ((VCOLORNUM(attr)) & (NCOLORS - 1));
if (attr & (VASEL|VAREV)) { /* reverse video? */
int temp = *bcolor;
*bcolor = *fcolor;
*fcolor = temp;
ninvert = TRUE;
}
}
}
static void
set_colors (HDC hdc, VIDEO_ATTR attr)
{
int fcolor;
int bcolor;
attr_to_colors(attr, &fcolor, &bcolor);
if (fcolor < 0)
fcolor = ninvert
? default_bcolor
: default_fcolor;
else
fcolor = color_of(fcolor);
if (bcolor < 0)
bcolor = ninvert
? default_fcolor
: default_bcolor;
else
bcolor = color_of(bcolor);
SetTextColor(hdc, fcolor);
SetBkColor(hdc, bcolor);
}
#if OPT_ICURSOR
static void nticursor(int cmode)
{
}
#endif
static int fhide_cursor(void)
{
TRACE(("fhide_cursor pos %#lx,%#lx (visible:%d, exists:%d)\n", ttrow, ttcol, caret_visible, caret_exists))
if(caret_visible) {
HideCaret(cur_win->text_hwnd);
caret_visible = 0;
}
if(caret_exists) {
DestroyCaret();
caret_exists = 0;
}
return 0;
}
static void fshow_cursor(void)
{
int x, y;
POINT z;
if (caret_disabled /* reject display during font-dialog */
|| ttrow > term.t_nrow /* reject bogus position in init */
|| ttcol > term.t_ncol)
return;
TRACE(("fshow_cursor pos %#lx,%#lx (visible:%d, exists:%d)\n", ttrow, ttcol, caret_visible, caret_exists))
x = ColToPixel(ttcol) + 1;
y = RowToPixel(ttrow) + 1;
if (caret_exists) {
GetCaretPos(&z);
if (x != z.x
|| y != z.y)
fhide_cursor();
}
if (!caret_exists) {
TRACE(("...CreateCaret(%d,%d)\n", ttrow, ttcol))
CreateCaret(cur_win->text_hwnd, (HBITMAP) 0, nCharWidth, nLineHeight);
caret_exists = 1;
SetCaretPos(x, y);
ShowCaret(cur_win->text_hwnd);
caret_visible = 1;
}
}
static void
get_borders(void)
{
SystemParametersInfo(SPI_GETWORKAREA, 0, &cur_win->xy_limit, 0);
TRACE(("WORKAREA: %d,%d %d,%d\n",
cur_win->xy_limit.top,
cur_win->xy_limit.left,
cur_win->xy_limit.right,
cur_win->xy_limit.bottom))
cur_win->x_border = GetSystemMetrics(SM_CXSIZEFRAME);
cur_win->y_border = GetSystemMetrics(SM_CYSIZEFRAME);
cur_win->y_titles = GetSystemMetrics(SM_CYCAPTION);
TRACE(("X border: %d, Y border: %d\n", cur_win->x_border, cur_win->y_border))
TRACE(("CYFRAME: %d\n", GetSystemMetrics(SM_CYFRAME)))
TRACE(("CYCAPTION: %d\n", cur_win->y_titles))
}
/* Notes: lpntm is a pointer to a TEXTMETRIC struct if FontType does not
* have TRUETYPE_FONTTYPE set, but we only need the tmPitchAndFamily member,
* which has the same alignment as in NEWTEXTMETRIC.
*/
static int CALLBACK
enumerate_fonts(
ENUMLOGFONT *lpelf,
NEWTEXTMETRIC *lpntm,
DWORD FontType,
LPARAM lParam)
{
int code = 2;
LOGFONT *src = &(lpelf->elfLogFont);
LOGFONT *dst = ((LOGFONT *)lParam);
if ((src->lfPitchAndFamily & 3) != FIXED_PITCH) {
code = 1;
} else {
*dst = *src;
if (src->lfCharSet == ANSI_CHARSET) {
code = 0;
TRACE(("Found good font:%s\n", lpelf->elfFullName))
}
TRACE(("Found ok font:%s\n", lpelf->elfFullName))
TRACE(("Pitch/Family: %#x\n", dst->lfPitchAndFamily))
}
return code;
}
static int is_fixed_pitch(HFONT font)
{
BOOL ok;
HDC hDC;
TEXTMETRIC metrics;
hDC = GetDC(cur_win->text_hwnd);
SelectObject(hDC, font);
ok = GetTextMetrics(hDC, &metrics);
ReleaseDC(cur_win->text_hwnd, hDC);
if (ok)
ok = ((metrics.tmPitchAndFamily & TMPF_FIXED_PITCH) == 0);
TRACE(("is_fixed_pitch: %d\n", ok))
TRACE(("Ave Text width: %d\n", metrics.tmAveCharWidth))
TRACE(("Max Text width: %d\n", metrics.tmMaxCharWidth))
TRACE(("Pitch/Family: %#x\n", metrics.tmPitchAndFamily))
return (ok);
}
static int new_font(LOGFONT *lf)
{
HFONT font = CreateFontIndirect(lf);
if (font != 0) {
if (is_fixed_pitch(font)) {
DeleteObject(vile_font);
vile_font = font;
TRACE(("created new font\n"))
return TRUE;
}
else
DeleteObject(font);
}
return FALSE;
}
static void get_font(LOGFONT *lf)
{
HDC hDC;
vile_font = GetStockObject(MY_FONT);
hDC = GetDC(cur_win->text_hwnd);
if (EnumFontFamilies(hDC, NULL, enumerate_fonts, (LPARAM) lf) <= 0)
{
TRACE(("Creating Pitch/Family: %#x\n", lf->lfPitchAndFamily))
new_font(lf);
}
ReleaseDC(cur_win->text_hwnd, hDC);
}
static void use_font(HFONT my_font, BOOL resizable)
{
HDC hDC;
TEXTMETRIC textmetric;
RECT crect;
hDC = GetDC(cur_win->text_hwnd);
SelectObject(hDC, my_font);
GetTextMetrics(hDC, &textmetric);
ReleaseDC(cur_win->text_hwnd, hDC);
TRACE(("Text height: %d\n", textmetric.tmHeight))
TRACE(("Ave Text width: %d\n", textmetric.tmAveCharWidth))
TRACE(("Max Text width: %d\n", textmetric.tmMaxCharWidth))
TRACE(("Pitch/Family: %#x\n", textmetric.tmPitchAndFamily))
/*
* We'll use the average text-width, since some fonts (e.g., Courier
* New) have a bogus max text-width.
*/
nLineHeight = textmetric.tmExternalLeading + textmetric.tmHeight;
nCharWidth = textmetric.tmAveCharWidth;
get_borders();
if (resizable) {
GetClientRect(cur_win->main_hwnd, &crect);
SetCols(RectToCols(crect));
SetRows(RectToRows(crect));
}
gui_resize(term.t_ncol, term.t_nrow);
}
static void set_font(void)
{
HDC hDC;
CHOOSEFONT choose;
TRACE(("set_font\n"))
fhide_cursor();
caret_disabled = TRUE;
memset(&choose, 0, sizeof(choose));
choose.lStructSize = sizeof(choose);
choose.hwndOwner = cur_win->text_hwnd;
choose.Flags = CF_SCREENFONTS
| CF_FIXEDPITCHONLY
| CF_FORCEFONTEXIST
| CF_NOSCRIPTSEL
| CF_INITTOLOGFONTSTRUCT;
choose.lpLogFont = &vile_logfont;
hDC = GetDC(cur_win->text_hwnd);
SelectObject(hDC, GetMyFont());
GetTextFace(hDC, sizeof(vile_logfont.lfFaceName), vile_logfont.lfFaceName);
ReleaseDC(cur_win->text_hwnd, hDC);
vile_logfont.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
vile_logfont.lfCharSet = ANSI_CHARSET;
TRACE(("LOGFONT Facename:%s\n", vile_logfont.lfFaceName))
if (ChooseFont(&choose)) {
TRACE(("ChooseFont '%s'\n", vile_logfont.lfFaceName))
if (new_font(&vile_logfont)) {
int saverow = ttrow;
int savecol = ttcol;
mlwrite("[Set font to %s]", vile_logfont.lfFaceName);
movecursor(saverow, savecol);
use_font(vile_font, FALSE);
vile_refresh(FALSE,0);
} else {
mlforce("[Cannot create font]");
}
} else {
mlforce("[No font selected]");
}
caret_disabled = FALSE;
fshow_cursor();
TRACE(("...set_font, LOGFONT Facename:%s\n", vile_logfont.lfFaceName))
}
static int
last_w32_error(int use_msg_box)
{
if (use_msg_box)
disp_win32_error(W32_SYS_ERROR, winvile_hwnd());
else
{
char *msg = NULL;
fmt_win32_error(W32_SYS_ERROR, &msg, 0);
mlforce(msg);
LocalFree(msg);
}
return (FALSE);
}
/*
* Set font from string specification. See the function parse_font_str()
* in file w32misc.c for acceptable font string syntax.
*
* Prerequistes before calling this function:
*
* winvile's windows and default font (vile_font) created.
*
* Returns: T -> all is well, F -> failure.
*/
int
ntwinio_font_frm_str(
const char *fontstr,
int use_mb /* Boolean, T -> errors reported via MessageBox.
* F -> errors reported via message line.
*/
)
{
int face_specified;
HDC hdc;
HFONT hfont;
HWND hwnd;
LOGFONT logfont;
char *msg, font_mapper_face[LF_FACESIZE + 1];
TEXTMETRIC metrics;
FONTSTR_OPTIONS str_rslts;
if (! parse_font_str(fontstr, &str_rslts))
{
msg = "Font syntax invalid";
if (use_mb)
MessageBox(winvile_hwnd(), msg, prognam, MB_ICONSTOP|MB_OK);
else
mlforce(msg);
return (FALSE);
}
hwnd = cur_win->text_hwnd;
face_specified = (str_rslts.face[0] != '\0');
if (! ((hdc = GetDC(hwnd)) && SelectObject(hdc, vile_font)))
{
if (hdc)
ReleaseDC(hwnd, hdc);
return (last_w32_error(use_mb));
}
if (! face_specified)
{
/* user didn't specify a face name, get current name. */
if ((GetTextFace(hdc, sizeof(str_rslts.face), str_rslts.face)) == 0)
{
ReleaseDC(hwnd, hdc);
return (last_w32_error(use_mb));
}
}
/* Build up LOGFONT data structure. */
memset(&logfont, 0, sizeof(logfont));
logfont.lfWeight = (str_rslts.bold) ? FW_BOLD : FW_NORMAL;
logfont.lfHeight = -MulDiv(str_rslts.size,
GetDeviceCaps(hdc, LOGPIXELSY),
72);
if (str_rslts.italic)
logfont.lfItalic = TRUE;
logfont.lfCharSet = DEFAULT_CHARSET;
logfont.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
strncpy(logfont.lfFaceName, str_rslts.face, LF_FACESIZE - 1);
logfont.lfFaceName[LF_FACESIZE - 1] = '\0';
if (! ((hfont = CreateFontIndirect(&logfont)) && SelectObject(hdc, hfont)))
{
if (hfont)
DeleteObject(hfont);
ReleaseDC(hwnd, hdc);
return (last_w32_error(use_mb));
}
/*
* The font mapper will substitute some other font for a font request
* that cannot exactly be met. Ck first to see if the face name
* matches the user chosen face (if applicatble).
*/
if (face_specified)
{
if ((GetTextFace(hdc, sizeof(font_mapper_face), font_mapper_face)) == 0)
{
ReleaseDC(hwnd, hdc);
DeleteObject(hfont);
return (last_w32_error(use_mb));
}
if (stricmp(font_mapper_face, str_rslts.face) != 0)
{
ReleaseDC(hwnd, hdc);
DeleteObject(hfont);
msg = "Font face unknown or size/style unsupported";
if (use_mb)
MessageBox(winvile_hwnd(), msg, prognam, MB_ICONSTOP|MB_OK);
else
mlforce(msg);
return (FALSE);
}
}
/* Next, font must be fixed pitch. */
if (! GetTextMetrics(hdc, &metrics))
{
ReleaseDC(hwnd, hdc);
DeleteObject(hfont);
return (last_w32_error(use_mb));
}
if ((metrics.tmPitchAndFamily & TMPF_FIXED_PITCH) != 0)
{
/* Misnamed constant! */
ReleaseDC(hwnd, hdc);
DeleteObject(hfont);
msg = "Font not fixed pitch";
if (use_mb)
MessageBox(winvile_hwnd(), msg, prognam, MB_ICONSTOP|MB_OK);
else
mlforce(msg);
return (FALSE);
}
DeleteObject(vile_font); /* Nuke original font */
ReleaseDC(hwnd, hdc); /* finally done with this */
vile_font = hfont;
memcpy(&vile_logfont, &logfont, sizeof(vile_logfont));
use_font(vile_font, FALSE);
vile_refresh(FALSE, 0);
return (TRUE);
}
char *
ntwinio_current_font(void)
{
static char *buf;
HDC hdc;
HWND hwnd;
LONG size;
char *style;
if (! buf)
{
buf = castalloc(char,
sizeof("bold-italic") +
LF_FACESIZE +
16); /* space for delimiters and point size */
if (! buf)
return ("out of memory");
}
hwnd = cur_win->text_hwnd;
if (! ((hdc = GetDC(hwnd)) && SelectObject(hdc, vile_font)))
{
char *msg = NULL;
if (hdc)
ReleaseDC(hwnd, hdc);
fmt_win32_error(W32_SYS_ERROR, &msg, 0);
return (msg);
/* "msg" leaks here, but this code path should never be taken. */
}
if (vile_logfont.lfWeight == FW_BOLD && vile_logfont.lfItalic)
style = "bold-italic";
else if (vile_logfont.lfWeight == FW_BOLD)
style = "bold";
else if (vile_logfont.lfItalic)
style = "italic";
else
style = NULL;
size = MulDiv(labs(vile_logfont.lfHeight),
72,
GetDeviceCaps(hdc, LOGPIXELSY));
sprintf(buf,
"%s,%ld%s%s",
vile_logfont.lfFaceName,
size,
(style) ? "," : "",
(style) ? style : "");
ReleaseDC(hwnd, hdc);
return (buf);
}
#if OPT_TITLE
static void
nttitle(char *title) /* set the current window title */
{
SetWindowText(winvile_hwnd(), title);
}
#endif
static void
scflush(void)
{
if (cur_pos && !vile_resizing) {
HDC hdc;
TRACE(("PUTC:flush %2d (%2d,%2d) (%.*s)\n", cur_pos, crow,ccol, cur_pos, &CELL_TEXT(crow,ccol)))
hdc = GetDC(cur_win->text_hwnd);
SelectObject(hdc, GetMyFont());
set_colors(hdc, cur_atr);
TextOut(hdc,
ColToPixel(ccol),
RowToPixel(crow),
&CELL_TEXT(crow,ccol), cur_pos);
ReleaseDC(cur_win->text_hwnd, hdc);
}
ccol = ccol + cur_pos;
cur_pos = 0;
}
#if OPT_COLOR
static void
ntfcol(int color) /* set the current output color */
{
scflush();
nfcolor = color;
}
static void
ntbcol(int color) /* set the current background color */
{
scflush();
nbcolor = color;
}
#endif
static void
ntflush(void)
{
scflush();
SetCaretPos(ColToPixel(ccol), RowToPixel(crow));
}
static void
ntmove(int row, int col)
{
scflush();
crow = (short) row;
ccol = (short) col;
}
/* erase to the end of the line */
static void
nteeol(void)
{
HDC hDC;
HBRUSH brush;
RECT rect;
int x;
scflush();
TRACE(("NTEEOL %d,%d, atr %#x\n", crow, ccol, cur_atr))
for (x = ccol; x < term.t_ncol; x++) {
CELL_TEXT(crow,x) = ' ';
CELL_ATTR(crow,x) = cur_atr;
}
GetClientRect(cur_win->text_hwnd, &rect);
rect.left = ColToPixel(ccol);
rect.top = RowToPixel(crow);
rect.right = ColToPixel(term.t_ncol);
rect.bottom = RowToPixel(crow+1);
hDC = GetDC(cur_win->text_hwnd);
set_colors(hDC, cur_atr);
brush = Background(hDC);
FillRect(hDC, &rect, brush);
DeleteObject(brush);
ReleaseDC(cur_win->text_hwnd, hDC);
}
/*
* vile very rarely generates any of the ASCII printing control characters
* except for a few hand coded routines but we have to support them anyway.
*/
/* put a character at the current position in the current colors */
static void
ntputc(int ch)
{
/* This is an optimization for the most common case. */
if (ch >= ' ') {
CELL_TEXT(crow,ccol+cur_pos) = (char) ch;
CELL_ATTR(crow,ccol+cur_pos) = cur_atr;
cur_pos++;
} else {
switch (ch) {
case '\b':
scflush();
if (ccol)
ccol--;
break;
case '\a':
ntbeep();
break;
case '\t':
scflush();
do {
CELL_TEXT(crow,ccol+cur_pos) = ' ';
CELL_ATTR(crow,ccol+cur_pos) = cur_atr;
cur_pos++;
} while ((ccol + cur_pos) % 8 != 0);
break;
case '\r':
scflush();
ccol = 0;
break;
case '\n':
scflush();
if (crow < term.t_nrow - 1)
crow++;
else
ntscroll(1, 0, term.t_nrow - 1);
break;
default:
CELL_TEXT(crow,ccol+cur_pos) = (char) ch;
CELL_ATTR(crow,ccol+cur_pos) = cur_atr;
cur_pos++;
break;
}
}
}
static void
nteeop(void)
{
HDC hDC;
HBRUSH brush;
RECT rect;
int y, x, x0;
scflush();
x0 = ccol;
TRACE(("NTEEOP %d,%d, atr %#x\n", crow, ccol, cur_atr))
for (y = crow; y < term.t_nrow; y++) {
for (x = 0; x < term.t_ncol; x++) {
CELL_TEXT(y,x) = ' ';
CELL_ATTR(y,x) = cur_atr;
}
x0 = 0;
}
rect.left = ColToPixel(ccol);
rect.top = RowToPixel(crow);
rect.right = ColToPixel(term.t_ncol);
rect.bottom = RowToPixel(term.t_nrow);
if (!vile_resizing) {
hDC = GetDC(cur_win->text_hwnd);
set_colors(hDC, cur_atr);
brush = Background(hDC);
FillRect(hDC, &rect, brush);
DeleteObject(brush);
ReleaseDC(cur_win->text_hwnd, hDC);
}
}
static void
ntrev(UINT reverse) /* change reverse video state */
{
scflush();
cur_atr = (VIDEO_ATTR) reverse;
}
static int
ntcres(const char *res) /* change screen resolution */
{
scflush();
return 0;
}
#if OPT_FLASH
static void
flash_display()
{
RECT rect;
HDC hDC;
GetClientRect(cur_win->text_hwnd, &rect);
hDC = GetDC(cur_win->text_hwnd);
InvertRect(hDC, &rect);
Sleep(100);
InvertRect(hDC, &rect);
ReleaseDC(cur_win->text_hwnd, hDC);
}
#endif
static void
ntbeep(void)
{
#if OPT_FLASH
if (global_g_val(GMDFLASH)) {
flash_display();
return;
}
#endif
MessageBeep(0xffffffff);
}
static void
ntopen(void)
{
TRACE(("ntopen\n"))
set_palette(initpalettestr);
}
static int old_title_set = 0;
static char old_title[256];
static int orig_title_set = 0;
static char orig_title[256];
static void
ntclose(void)
{
TRACE(("ntclose\n"))
scflush();
ntmove(term.t_nrow - 1, 0);
nteeol();
ntflush();
}
static void
ntkopen(void) /* open the keyboard */
{
}
static void
ntkclose(void) /* close the keyboard */
{
}
static struct {
int windows;
int vile;
} keyxlate[] = {
{ VK_NEXT, KEY_Next },
{ VK_PRIOR, KEY_Prior },
{ VK_END, KEY_End },
{ VK_HOME, KEY_Home },
{ VK_LEFT, KEY_Left },
{ VK_RIGHT, KEY_Right },
{ VK_UP, KEY_Up },
{ VK_DOWN, KEY_Down },
{ VK_INSERT, KEY_Insert },
{ VK_DELETE, KEY_Delete },
{ VK_HELP, KEY_Help },
{ VK_SELECT, KEY_Select },
#if 0
/* Merely pressing the Alt key generates a VK_MENU key event. */
{ VK_MENU, KEY_Menu },
#endif
{ VK_F1, KEY_F1 },
{ VK_F2, KEY_F2 },
{ VK_F3, KEY_F3 },
{ VK_F4, KEY_F4 },
{ VK_F5, KEY_F5 },
{ VK_F6, KEY_F6 },
{ VK_F7, KEY_F7 },
{ VK_F8, KEY_F8 },
{ VK_F9, KEY_F9 },
{ VK_F10, KEY_F10 },
{ VK_F11, KEY_F11 },
{ VK_F12, KEY_F12 },
{ VK_F13, KEY_F13 },
{ VK_F14, KEY_F14 },
{ VK_F15, KEY_F15 },
{ VK_F16, KEY_F16 },
{ VK_F17, KEY_F17 },
{ VK_F18, KEY_F18 },
{ VK_F19, KEY_F19 },
{ VK_F20, KEY_F20 },
/* Allow ^-6 to invoke the alternate-buffer command, a la Unix. */
{ '6', '6' },
};
static int savedChar;
static int saveCount = 0;
static int
decode_key_event(KEY_EVENT_RECORD *irp)
{
int key;
int i;
if ((key = (unsigned char) irp->uChar.AsciiChar) != 0)
return key;
for (i = 0; i < TABLESIZE(keyxlate); i++)
{
if (keyxlate[i].windows == irp->wVirtualKeyCode)
{
DWORD state = irp->dwControlKeyState;
/*
* This is a combination from the window menu which is caught when
* we've grabbed focus. Just ignore it here, and it will be
* processed properly.
*/
if (keyxlate[i].windows == VK_F4
&& (state & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)))
break;
/*
* If this key is modified in some way, we'll prefer to use the
* Win32 definition. But only for the modifiers that we
* recognize. Specifically, we don't care about ENHANCED_KEY,
* since we already have portable pageup/pagedown and arrow key
* bindings that would be lost if we used the Win32-only
* definition.
*/
if (state &
(LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED
| LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED
| SHIFT_PRESSED))
{
key = W32_KEY | keyxlate[i].windows;
if (state & (LEFT_CTRL_PRESSED|RIGHT_CTRL_PRESSED))
key |= W32_CTRL;
if (state & (LEFT_ALT_PRESSED|RIGHT_ALT_PRESSED))
key |= W32_ALT;
if (state & SHIFT_PRESSED)
key |= W32_SHIFT;
}
else
key = keyxlate[i].vile;
TRACE(("... %#x -> %#x\n", irp->wVirtualKeyCode, key))
break;
}
}
if (key == 0)
return (NOKYMAP);
return key;
}
static int
get_keyboard_state(void)
{
int result = 0;
if (GetKeyState(VK_CONTROL) < 0)
result |= (LEFT_CTRL_PRESSED|RIGHT_CTRL_PRESSED);
if (GetKeyState(VK_MENU) < 0)
result |= (LEFT_ALT_PRESSED|RIGHT_ALT_PRESSED);
if (GetKeyState(VK_SHIFT) < 0)
result |= SHIFT_PRESSED;
return result;
}
static int
ntgetch(void)
{
int buttondown = FALSE;
MSG msg;
POINTS points;
POINT first;
int have_focus = 0;
int result = 0;
DWORD dword;
KEY_EVENT_RECORD ker;
if (saveCount > 0) {
saveCount--;
return savedChar;
}
vile_in_getfkey = 1;
while(! result) {
if(GetFocus() == cur_win->main_hwnd) {
if(! have_focus) {
have_focus = 1;
fshow_cursor();
}
} else {
if(have_focus) {
have_focus = 0;
fhide_cursor();
}
}
if(GetMessage(&msg, (HWND)0, 0, 0) != TRUE) {
PostQuitMessage(1);
TRACE(("GETC:no message\n"))
quit(TRUE,1);
}
if (TranslateAccelerator(cur_win->main_hwnd, hAccTable, &msg)) {
TRACE(("GETC:no accelerator\n"))
continue;
}
TranslateMessage(&msg);
switch(msg.message) {
case WM_DESTROY:
TRACE(("GETC:DESTROY\n"))
PostQuitMessage(0);
continue;
case WM_CHAR:
TRACE(("GETC:CHAR:%#x\n", msg.wParam))
result = msg.wParam;
if (result == ESC) {
sel_release();
(void)update(TRUE);
}
break;
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
ker.uChar.AsciiChar = 0;
ker.wVirtualKeyCode = (SHORT) msg.wParam;
ker.dwControlKeyState = get_keyboard_state();
result = decode_key_event(&ker);
TRACE(("GETC:%sKEYDOWN:%#x ->%#x\n",
(msg.message == WM_SYSKEYDOWN) ? "SYS" : "",
msg.wParam, result))
if (result == NOKYMAP) {
DispatchMessage(&msg);
result = 0;
} else if (result == (int) msg.wParam) {
result = 0; /* we'll get a WM_CHAR next */
}
break;
case WM_LBUTTONDOWN:
TRACE(("GETC:LBUTTONDOWN %s\n", which_window(msg.hwnd)))
if (msg.hwnd == cur_win->text_hwnd) {
dword = GetMessagePos();
points = MAKEPOINTS(dword);
POINTSTOPOINT(first, points);
ScreenToClient(cur_win->main_hwnd, &first);
first.x /= nCharWidth;
first.y /= nLineHeight;
TRACE(("GETC:setcursor(%d, %d)\n", first.y, first.x))
if (setcursor(first.y, first.x)) {
fhide_cursor();
(void)sel_begin();
(void)update(TRUE);
buttondown = TRUE;
}
} else {
DispatchMessage(&msg);
}
break;
case WM_RBUTTONDOWN:
TRACE(("GETC:RBUTTONDOWN %s\n", which_window(msg.hwnd)))
if (msg.hwnd == cur_win->text_hwnd) {
if (buttondown) {
(void)sel_release();
(void)update(TRUE);
}
} else {
DispatchMessage(&msg);
}
break;
case WM_MOUSEMOVE:
if (buttondown) {
int x = PixelToCol(LOWORD(msg.lParam));
int y = PixelToRow(HIWORD(msg.lParam));
TRACE(("GETC:MOUSEMOVE (%d,%d)%s\n",
x, y, buttondown ? " selecting" : ""));
fhide_cursor();
if (!setcursor(y, x))
break;
if (get_keyboard_state()
& (LEFT_CTRL_PRESSED|RIGHT_CTRL_PRESSED))
(void)sel_setshape(RECTANGLE);
if (!sel_extend(TRUE, TRUE))
break;
(void)update(TRUE);
}
break;
case WM_LBUTTONUP:
TRACE(("GETC:LBUTTONUP %s\n", which_window(msg.hwnd)))
if (msg.hwnd == cur_win->text_hwnd) {
fhide_cursor();
if (buttondown) {
sel_yank(0);
buttondown = FALSE;
}
(void)update(TRUE);
fshow_cursor();
} else {
DispatchMessage(&msg);
}
break;
default:
TRACE(("GETC:default(%s)\n", message2s(msg.message)))
case WM_COMMAND:
case WM_KEYUP:
case WM_NCHITTEST:
case WM_NCMOUSEMOVE:
case WM_NCLBUTTONDOWN:
case WM_PAINT:
case WM_NCACTIVATE:
case WM_SETCURSOR:
case 0x118:
DispatchMessage(&msg);
break;
}
}
fhide_cursor();
vile_in_getfkey = 0;
TRACE(("...ntgetch %#x\n", result))
return result;
}
/*
* The function `kbhit' returns true if there are *any* input records
* available. We need to define our own type ahead routine because
* otherwise events which we will discard (like pressing or releasing
* the Shift key) can block screen updates because `ntgetch' won't
* return until a ordinary key event occurs.
*/
static int
nttypahead()
{
#if FIXME
#endif
return 0;
}
/*
* Move 'n' lines starting at 'from' to 'to'
*
* OPT_PRETTIER_SCROLL is prettier but slower -- it scrolls a line at a time
* instead of all at once.
*/
/* move howmany lines starting at from to to */
static void
ntscroll(int from, int to, int n)
{
HDC hDC;
HBRUSH brush;
RECT region;
RECT tofill;
scflush();
if (to == from)
return;
#if OPT_PRETTIER_SCROLL
if (absol(from-to) > 1) {
ntscroll(from, (from<to) ? to-1:to+1, n);
if (from < to)
from = to-1;
else
from = to+1;
}
#endif
region.left = 0;
region.right = (SHORT) ColToPixel(term.t_ncol);
if (from > to) {
region.top = (SHORT) RowToPixel(to);
region.bottom = (SHORT) RowToPixel(from + n);
} else {
region.top = (SHORT) RowToPixel(from);
region.bottom = (SHORT) RowToPixel(to + n);
}
TRACE(("ScrollWindowEx from=%d, to=%d, n=%d (%d,%d)/(%d,%d)\n",
from, to, n,
region.left, region.top,
region.right, region.bottom));
ScrollWindowEx(
cur_win->text_hwnd, /* handle of window to scroll */
0, /* amount of horizontal scrolling */
RowToPixel(to-from), /* amount of vertical scrolling */
®ion, /* address of structure with scroll rectangle */
®ion, /* address of structure with clip rectangle */
(HRGN)0, /* handle of update region */
&tofill, /* address of structure for update rectangle */
SW_ERASE /* scrolling flags */
);
TRACE(("fill: (%d,%d)/(%d,%d)\n",
tofill.left, tofill.top,
tofill.right, tofill.bottom));
hDC = GetDC(cur_win->text_hwnd);
set_colors(hDC, cur_atr);
brush = Background(hDC);
FillRect(hDC, &tofill, brush);
DeleteObject(brush);
ReleaseDC(cur_win->text_hwnd, hDC);
}
#if OPT_SCROLLBARS
static
int check_scrollbar_allocs(void)
{
int newmax = cur_win->rows/2;
int oldmax = cur_win->maxscrollbars;
TRACE(("check_scrollbar_allocs %d > %d ?\n", oldmax, newmax))
if (newmax > oldmax) {
GROW(cur_win->scrollbars, SBDATA, oldmax, newmax);
cur_win->maxscrollbars = newmax;
TRACE(("GROW scrollbars=%p, oldmax=%d, newmax=%d\n",
cur_win->scrollbars, oldmax, newmax))
}
return TRUE;
}
static SBDATA
new_scrollbar(void)
{
SBDATA result;
result.shown = FALSE;
result.r.top = -1;
result.r.left = -1;
result.r.bottom = -1;
result.r.right = -1;
result.w = CreateWindow(
SCRL_CLASS,
"scrollbar",
WS_CHILD | SBS_VERT | WS_CLIPSIBLINGS,
0, /* x */
0, /* y */
SbWidth, /* width */
1, /* height */
cur_win->main_hwnd,
(HMENU)0,
vile_hinstance,
(LPVOID)0
);
return result;
}
static int
show_scrollbar(int n, int flag)
{
if (cur_win->scrollbars[n].shown != flag) {
ShowScrollBar(cur_win->scrollbars[n].w, SB_CTL, flag);
cur_win->scrollbars[n].shown = flag;
return TRUE;
}
return FALSE;
}
static void
set_scrollbar_range(int n, WINDOW *wp)
{
SCROLLINFO info;
int lnum, lcnt;
lnum = line_no(wp->w_bufp, wp->w_dot.l);
lnum = max(lnum, 1);
lcnt = line_count(wp->w_bufp);
lcnt = max(lcnt, 1) + wp->w_ntrows - 1;
TRACE(("set_scrollbar_range(%d, %s) %d:%d\n",
n, wp->w_bufp->b_bname, lnum, lcnt))
info.cbSize = sizeof(info);
info.fMask = SIF_POS | SIF_RANGE | SIF_PAGE;
info.nPos = lnum - 1;
info.nMin = 0;
info.nMax = lcnt - 1;
info.nPage = wp->w_ntrows;
SetScrollInfo(cur_win->scrollbars[n].w, SB_CTL, &info, TRUE);
}
/*
* All we want to do here is to paint the gap between the real resize-grip and
* the borders of the dummy window we're surrounding it with. That's because
* the resize-grip itself isn't resizable.
*/
LONG FAR PASCAL GripWndProc(
HWND hWnd,
UINT message,
WPARAM wParam,
LONG lParam)
{
PAINTSTRUCT ps;
HBRUSH brush;
TRACE(("GRIP:%s\n", message2s(message)))
switch (message) {
case WM_PAINT:
BeginPaint(hWnd, &ps);
TRACE(("...painting (%d,%d) (%d,%d)\n",
ps.rcPaint.top,
ps.rcPaint.left,
ps.rcPaint.bottom,
ps.rcPaint.right))
brush = CreateSolidBrush(GetSysColor(COLOR_SCROLLBAR));
SelectObject(ps.hdc, brush);
Rectangle(ps.hdc,
ps.rcPaint.left,
ps.rcPaint.top,
ps.rcPaint.right,
ps.rcPaint.bottom);
DeleteObject(brush);
EndPaint(hWnd, &ps);
break;
}
return (DefWindowProc(hWnd, message, wParam, lParam));
}
static void
update_scrollbar_sizes(void)
{
RECT crect;
register WINDOW *wp;
int i, top, left;
int newsbcnt;
int oldsbcnt = cur_win->nscrollbars;
TRACE(("update_scrollbar_sizes\n"))
i = 0;
for_each_visible_window(wp)
i++;
newsbcnt = i;
for (i = cur_win->nscrollbars+1; i <= newsbcnt; i++) {
if (cur_win->scrollbars[i].w == NULL) {
cur_win->scrollbars[i] = new_scrollbar();
TRACE(("... created sb%d=%#x\n", i, cur_win->scrollbars[i].w))
}
}
cur_win->nscrollbars = newsbcnt;
/* Set sizes and positions on scrollbars and sliders */
i = 0;
GetClientRect(cur_win->main_hwnd, &crect);
top = crect.top;
left = crect.right - SbWidth;
for_each_visible_window(wp) {
int high = RowToPixel(wp->w_ntrows + 1);
int wide = SbWidth;
if (show_scrollbar(i, TRUE)
|| cur_win->scrollbars[i].r.top != top
|| cur_win->scrollbars[i].r.left != left
|| cur_win->scrollbars[i].r.bottom != high
|| cur_win->scrollbars[i].r.right != wide) {
MoveWindow(cur_win->scrollbars[i].w,
cur_win->scrollbars[i].r.left = left,
cur_win->scrollbars[i].r.top = top,
cur_win->scrollbars[i].r.right = wide,
cur_win->scrollbars[i].r.bottom = high,
TRUE);
TRACE(("... adjusted %s to (%d,%d) (%d,%d)\n",
which_window(cur_win->scrollbars[i].w),
left,
top,
SbWidth,
high));
}
if (cur_win->nscrollbars == i+1)
set_scrollbar_range(i, wp);
i++;
top += high;
}
while (i < oldsbcnt) {
(void) show_scrollbar(i, FALSE);
i++;
}
#if FIXME_RECUR_SB
for_each_visible_window(wp) {
wp->w_flag &= ~WFSBAR;
gui_update_scrollbar(wp);
}
#endif
if (cur_win->size_box.w == 0) {
cur_win->size_box.w = CreateWindow(
GRIP_CLASS,
"sizebox",
WS_CHILD
| WS_VISIBLE
| WS_CLIPSIBLINGS,
cur_win->size_box.r.left = left,
cur_win->size_box.r.top = top,
cur_win->size_box.r.right = SbWidth + 1,
cur_win->size_box.r.bottom = nLineHeight,
cur_win->main_hwnd,
(HMENU)0,
vile_hinstance,
(LPVOID)0
);
cur_win->size_grip.w = CreateWindow(
"SCROLLBAR",
"sizebox",
WS_CHILD
| WS_VISIBLE
| SB_CTL
| SBS_SIZEGRIP
| WS_CLIPSIBLINGS
| SBS_SIZEBOXBOTTOMRIGHTALIGN,
cur_win->size_box.r.left = 0,
cur_win->size_box.r.top = 0,
cur_win->size_box.r.right = SbWidth,
cur_win->size_box.r.bottom = nLineHeight,
cur_win->size_box.w,
(HMENU)0,
vile_hinstance,
(LPVOID)0
);
TRACE(("... made SIZEGRIP %x at %d,%d\n", cur_win->size_box.w, left, top))
} else {
int ok;
if (cur_win->size_box.r.left != left
|| cur_win->size_box.r.top != top
|| cur_win->size_box.r.right != SbWidth
|| cur_win->size_box.r.bottom != nLineHeight) {
ok = MoveWindow(cur_win->size_box.w,
cur_win->size_box.r.left = left,
cur_win->size_box.r.top = top,
cur_win->size_box.r.right = SbWidth,
cur_win->size_box.r.bottom = nLineHeight,
TRUE);
TRACE(("... move SIZE_BOX %d:%x to %d,%d\n",
ok, cur_win->size_box.w, left, top))
}
left = 0;
top = 0;
if (cur_win->size_grip.r.left != left
|| cur_win->size_grip.r.top != top
|| cur_win->size_grip.r.right != SbWidth
|| cur_win->size_grip.r.bottom != nLineHeight) {
ok = MoveWindow(cur_win->size_grip.w,
cur_win->size_grip.r.left = left,
cur_win->size_grip.r.top = top,
cur_win->size_grip.r.right = SbWidth,
cur_win->size_grip.r.bottom = nLineHeight,
TRUE);
TRACE(("... move SIZEGRIP %d:%x to %d,%d\n",
ok, cur_win->size_grip.w, left, top))
}
}
}
void
gui_update_scrollbar(WINDOW *uwp)
{
WINDOW *wp;
int i;
TRACE(("gui_update_scrollbar uwp=%p %s\n", uwp, uwp->w_bufp->b_bname))
if (dont_update_sb)
return;
i = 0;
for_each_visible_window(wp) {
TRACE(("wp=%p name='%s'\n", wp, wp->w_bufp->b_bname))
if (wp == uwp)
break;
i++;
}
TRACE(("i=%d, nscrollbars=%d\n", i, cur_win->nscrollbars))
if (i >= cur_win->nscrollbars || (wp->w_flag & WFSBAR)) {
/*
* update_scrollbar_sizes will recursively invoke gui_update_scrollbar,
* but with WFSBAR disabled.
*/
update_scrollbar_sizes();
return;
}
set_scrollbar_range(i, wp);
}
static int find_scrollbar (HWND hWnd)
{
WINDOW *wp;
int i = 0;
for_each_visible_window(wp) {
if (cur_win->scrollbars[i].w == hWnd) {
set_curwp (wp);
if (wp->w_bufp != curbp) {
swbuffer(wp->w_bufp);
}
return i;
}
i++;
}
return -1;
}
static void handle_scrollbar (HWND hWnd, int msg, int nPos)
{
int snum = find_scrollbar(hWnd);
TRACE(("handle_scrollbar msg=%d, nPos=%d\n", msg, nPos))
if (snum < 0) {
TRACE(("...could not find window for %s\n", which_window(hWnd)))
return;
}
fhide_cursor();
switch (msg)
{
case SB_BOTTOM:
TRACE(("-> SB_BOTTOM\n"))
gotoline(FALSE, 1);
break;
case SB_ENDSCROLL:
TRACE(("-> SB_ENDSCROLL\n"))
break;
case SB_LINEDOWN:
TRACE(("-> SB_LINEDOWN\n"))
mvdnwind(FALSE,1);
break;
case SB_LINEUP:
TRACE(("-> SB_LINEUP\n"))
mvupwind(FALSE,1);
break;
case SB_PAGEDOWN:
TRACE(("-> SB_PAGEDOWN\n"))
forwpage(FALSE,1);
break;
case SB_PAGEUP:
TRACE(("-> SB_PAGEUP\n"))
backpage(FALSE,1);
break;
case SB_THUMBPOSITION:
TRACE(("-> SB_THUMBPOSITION: %d\n", nPos))
gotoline(TRUE, nPos + 1);
break;
case SB_THUMBTRACK:
TRACE(("-> SB_THUMBTRACK: %d\n", nPos))
mvupwind(TRUE, line_no(curwp->w_bufp, curwp->w_line.l) - nPos);
break;
case SB_TOP:
TRACE(("-> SB_TOP\n"))
gotoline(TRUE, 1);
break;
}
(void)update(TRUE);
set_scrollbar_range(snum, curwp);
fshow_cursor();
}
#endif /* OPT_SCROLLBARS */
static void repaint_window(HWND hWnd)
{
PAINTSTRUCT ps;
HBRUSH brush;
int x0, y0, x1, y1;
int row, col;
BeginPaint(hWnd, &ps);
TRACE(("repaint_window (erase:%d)\n", ps.fErase))
SelectObject(ps.hdc, GetMyFont());
set_colors(ps.hdc, cur_atr);
brush = Background(ps.hdc);
TRACE(("...painting (%d,%d) (%d,%d)\n",
ps.rcPaint.top,
ps.rcPaint.left,
ps.rcPaint.bottom,
ps.rcPaint.right))
y0 = (ps.rcPaint.top) / nLineHeight;
x0 = (ps.rcPaint.left) / nCharWidth;
y1 = (ps.rcPaint.bottom + nLineHeight) / nLineHeight;
x1 = (ps.rcPaint.right + nCharWidth) / nCharWidth;
if (y0 < 0)
y0 = 0;
if (x0 < 0)
x0 = 0;
TRACE(("...erase %d\n", ps.fErase))
TRACE(("...cells (%d,%d) - (%d,%d)\n", y0,x0, y1,x1))
TRACE(("...top: %d\n", RowToPixel(y0) - ps.rcPaint.top))
TRACE(("...left: %d\n", ColToPixel(x0) - ps.rcPaint.left))
TRACE(("...bottom: %d\n", RowToPixel(y1) - ps.rcPaint.bottom))
TRACE(("...right: %d\n", ColToPixel(x1) - ps.rcPaint.right))
for (row = y0; row < y1; row++) {
if (pscreen != 0
&& pscreen[row]->v_text != 0
&& pscreen[row]->v_attrs != 0) {
for (col = x0; col < x1; col++) {
set_colors(ps.hdc, CELL_ATTR(row,col));
TextOut(ps.hdc,
ColToPixel(col),
RowToPixel(row),
&CELL_TEXT(row,col), 1);
}
}
}
DeleteObject(brush);
TRACE(("...repaint_window\n"))
EndPaint(hWnd, &ps);
}
static int khit = 0;
int kbhit(void)
{
MSG msg;
int hit;
if(PeekMessage(&msg, (HWND)0, (UINT)0, (UINT)0, PM_REMOVE)){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
hit = khit;
khit = 0;
return hit;
}
static void HandleClose(HWND hWnd)
{
quit(FALSE,1);
}
LONG FAR PASCAL TextWndProc(
HWND hWnd,
UINT message,
WPARAM wParam,
LONG lParam)
{
TRACE(("TEXT:%s, %s\n", message2s(message), which_window(hWnd)))
switch (message) {
case WM_PAINT:
if (GetUpdateRect(hWnd, (LPRECT)0, FALSE)) {
repaint_window(hWnd);
} else {
TRACE(("FIXME:WM_PAINT\n"))
return (DefWindowProc(hWnd, message, wParam, lParam));
}
break;
case WM_KEYDOWN:
case WM_LBUTTONDOWN:
case WM_RBUTTONDOWN:
case WM_SYSKEYDOWN:
khit = 1;
/* FALLTHRU */
default:
return (DefWindowProc(hWnd, message, wParam, lParam));
IGN_PROC("TEXT:", WM_ERASEBKGND);
}
return (0);
}
LONG FAR PASCAL MainWndProc(
HWND hWnd,
UINT message,
WPARAM wParam,
LONG lParam)
{
#if FIXME
FARPROC lpProcAbout;
#endif
TRACE(("MAIN:%s, %s\n", message2s(message), which_window(hWnd)))
switch (message) {
HANDLE_MSG(hWnd, WM_CLOSE, HandleClose);
case WM_COMMAND:
#if FIXME
switch (wParam) {
case IDC_button:
khit = 1;
wParam = IDC_button_x;
PostMessage(hWnd, message, wParam, lParam);
break;
case IDM_ABOUT:
lpProcAbout = MakeProcInstance(About, vile_hinstance);
DialogBox(vile_hinstance, "AboutBox", hWnd, lpProcAbout);
FreeProcInstance(lpProcAbout);
break;
/* file menu commands */
case IDM_PRINT:
MessageBox (
GetFocus(),
"Command not implemented",
MY_APPLE,
MB_ICONASTERISK | MB_OK);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
}
#endif
break;
/*
case WM_SIZE:
MoveWindow(cur_win->main_hwnd, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);
break;
*/
case WM_SETFOCUS:
fshow_cursor();
break;
case WM_KILLFOCUS:
fhide_cursor();
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_WINDOWPOSCHANGED:
ResizeClient();
return (DefWindowProc(hWnd, message, wParam, lParam));
case WM_WINDOWPOSCHANGING:
#if FIXME_POSCHANGING
if (wheadp != 0)
return AdjustPosChanging(hWnd, (LPWINDOWPOS)lParam);
#endif
return (DefWindowProc(hWnd, message, wParam, lParam));
case WM_SIZING:
return AdjustResizing(hWnd, wParam, (LPRECT)lParam);
case WM_EXITSIZEMOVE:
ResizeClient();
return (DefWindowProc(hWnd, message, wParam, lParam));
case WM_SYSCOMMAND:
TRACE(("MAIN:WM_SYSCOMMAND %s at %d,%d\n",
syscommand2s(LOWORD(wParam)),
HIWORD(lParam),
LOWORD(lParam)))
switch(LOWORD(wParam))
{
case MM_FONT:
set_font();
break;
}
return (DefWindowProc(hWnd, message, wParam, lParam));
#if OPT_SCROLLBARS
case WM_VSCROLL:
handle_scrollbar((HWND)lParam, LOWORD(wParam), HIWORD(wParam));
return (DefWindowProc(hWnd, message, wParam, lParam));
#endif
case WM_KEYDOWN:
case WM_LBUTTONDOWN:
case WM_RBUTTONDOWN:
case WM_SYSKEYDOWN:
khit = 1;
/* FALLTHRU */
default:
return (TextWndProc(hWnd, message, wParam, lParam));
IGN_PROC("MAIN:", WM_ERASEBKGND);
}
return (1);
}
static BOOL
InitInstance(HINSTANCE hInstance, int nCmdShow)
{
WNDCLASS wc;
hglass_cursor = LoadCursor((HINSTANCE)0, IDC_WAIT);
arrow_cursor = LoadCursor((HINSTANCE)0, IDC_ARROW);
default_bcolor = GetSysColor(COLOR_WINDOWTEXT+1);
default_fcolor = GetSysColor(COLOR_WINDOW+1);
ZeroMemory(&wc, sizeof(&wc));
wc.style = CS_VREDRAW | CS_HREDRAW;
wc.lpfnWndProc = (WNDPROC) MainWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(hInstance, "VilewIcon");
wc.hCursor = arrow_cursor;
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszMenuName = "VileMenu";
wc.lpszClassName = MAIN_CLASS;
if(! RegisterClass(&wc))
return FALSE;
TRACE(("Registered(%s)\n", MAIN_CLASS))
vile_hinstance = hInstance;
hAccTable = LoadAccelerators(vile_hinstance, "VileAcc");
cur_win->main_hwnd = CreateWindow(
MAIN_CLASS,
MY_APPLE,
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
CW_USEDEFAULT,
CW_USEDEFAULT,
1,
1,
(HWND)0,
(HMENU)0,
hInstance,
(LPVOID)0
);
TRACE(("CreateWindow(main) -> %#lx\n", cur_win->main_hwnd))
if (!cur_win->main_hwnd)
return (FALSE);
ZeroMemory(&wc, sizeof(&wc));
wc.style = CS_VREDRAW | CS_HREDRAW;
wc.lpfnWndProc = (WNDPROC) TextWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = 0;
wc.hCursor = arrow_cursor;
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszMenuName = 0;
wc.lpszClassName = TEXT_CLASS;
if(! RegisterClass(&wc))
return FALSE;
TRACE(("Registered(%s)\n", TEXT_CLASS))
cur_win->text_hwnd = CreateWindow(
TEXT_CLASS,
"text",
WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS,
CW_USEDEFAULT,
CW_USEDEFAULT,
1,
1,
cur_win->main_hwnd,
(HMENU)0,
hInstance,
(LPVOID)0
);
TRACE(("CreateWindow(text) -> %#lx\n", cur_win->text_hwnd))
if (!cur_win->text_hwnd)
return (FALSE);
/*
* Register the GRIP_CLASS now also, otherwise it won't succeed when
* we create the first scrollbars, until we resize the window.
*/
#if OPT_SCROLLBARS
ZeroMemory(&wc, sizeof(&wc));
wc.style = CS_VREDRAW | CS_HREDRAW;
wc.lpfnWndProc = (WNDPROC) GripWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = vile_hinstance;
wc.hCursor = arrow_cursor;
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszMenuName = 0;
wc.lpszClassName = GRIP_CLASS;
if(! RegisterClass(&wc)) {
TRACE(("could not register class %s:%#x\n", GRIP_CLASS, GetLastError()))
return (FALSE);
}
TRACE(("Registered(%s)\n", GRIP_CLASS))
#endif
cur_win->nscrollbars = -1;
/*
* Insert "File" and "Font" before "Close" in the system menu.
*/
vile_menu = GetSystemMenu(cur_win->main_hwnd, FALSE);
AppendMenu(vile_menu, MF_SEPARATOR, 0, NULL);
#if 0 /* FIXME: later */
AppendMenu(vile_menu, MF_STRING, MM_FILE, "File");
#endif
AppendMenu(vile_menu, MF_STRING, MM_FONT, "&Font");
#if OPT_SCROLLBARS
if (check_scrollbar_allocs() != TRUE)
return (FALSE);
#endif
get_font(&vile_logfont);
use_font(vile_font, FALSE);
ShowWindow(cur_win->main_hwnd, nCmdShow);
UpdateWindow(cur_win->main_hwnd);
return (TRUE);
}
int WINAPI
WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
#define MAXARGS 12
int argc = 0;
int n;
char *argv[MAXARGS];
char *ptr, *fontstr;
#ifdef VILE_OLE
int oa_invoke, oa_reg;
memset(&oa_opts, 0, sizeof(oa_opts));
oa_invoke = oa_reg = FALSE;
#endif
TRACE(("Starting ntvile, CmdLine:%s\n", lpCmdLine))
argv[argc++] = "VILE";
for(ptr = lpCmdLine; *ptr != '\0';) {
char delim = ' ';
while (*ptr == ' ')
ptr++;
if (*ptr == '\''
|| *ptr == '"'
|| *ptr == ' ') {
delim = *ptr++;
}
TRACE(("argv%d:%s\n", argc, ptr))
argv[argc++] = ptr;
if (argc+1 >= MAXARGS) {
break;
}
while (*ptr != delim && *ptr != '\0')
ptr++;
if (*ptr == delim)
*ptr++ = '\0';
}
fontstr = argv[argc] = 0;
SetCols(80);
SetRows(24);
/*
* Get screen size and OLE options, if any. Parsing logic is
* messy, but must remain that way to handle the various command
* line options available with and without OLE automation.
*/
for (n = 1; n < argc; n++) {
int m = n, eat = 0;
if (n + 1 < argc) {
if (strcmp(argv[n], "-geometry") == 0) {
char *src = argv[n+1];
char *dst = 0;
int value = strtol(src, &dst, 0);
if (dst != src) {
if (value > 2)
SetCols(value);
if (*dst++ == 'x') {
src = dst;
value = strtol(src, &dst, 0);
if (value > 2) {
SetRows(value);
#ifdef VILE_OLE
oa_opts.cols = term.t_ncol;
oa_opts.rows = term.t_nrow;
#endif
}
}
eat = 2;
}
}
else if (strcmp(argv[n], "-font") == 0 ||
strcmp(argv[n], "-fn") == 0)
{
fontstr = argv[n + 1];
eat = 2;
}
}
#ifdef VILE_OLE
if (eat == 0)
{
/* No valid options seen yet. */
if (argv[n][0] == '-' && argv[n][1] == 'O')
{
int which = argv[n][2];
if (which == 'r')
{
/*
* Flag OLE registration request,
* but don't eat argument. Instead,
* registration will be carried out
* in main.c, so that the regular
* cmdline parser has an opportunity
* to flag misspelled OLE options.
*
* Ex: winvile -Or -mutiple
*/
oa_reg = TRUE;
}
else if (which == 'u')
ExitProgram(oleauto_unregister());
else if (which == 'a')
{
oa_invoke = TRUE;
eat = 1;
}
}
else if (strcmp(argv[n], "-invisible") == 0)
{
oa_opts.invisible = TRUE;
eat = 1;
}
else if (strcmp(argv[n], "-multiple") == 0)
{
oa_opts.multiple = TRUE;
eat = 1;
}
}
#endif
if (eat) {
while (m+eat <= argc) {
argv[m] = argv[m+eat];
m++;
}
n--;
argc -= eat;
}
}
#ifdef VILE_OLE
if (oa_reg && oa_invoke)
{
/* tsk tsk */
MessageBox(cur_win->main_hwnd,
"-Oa and -Or are mutually exclusive",
prognam,
MB_OK|MB_ICONSTOP);
ExitProgram(1);
}
if (oa_reg)
{
/*
* The main program's cmd line parser will eventually cause
* OLE autoamation registration to occur, at which point
* winvile exits. So don't show a window.
*/
nCmdShow = SW_HIDE;
}
if (oa_opts.invisible)
nCmdShow = SW_HIDE;
#endif
if (!InitInstance(hInstance, nCmdShow))
return (FALSE);
/*
* Vile window created and default font set. It's now kosher to set
* the font from a cmdline switch.
*/
if (fontstr)
{
int success = ntwinio_font_frm_str(fontstr, TRUE);
#ifdef VILE_OLE
if (oa_reg)
{
if (! success)
{
/*
* That's it, game over -- crummy font spec detected during
* OLE registration.
*/
ExitProgram(1);
}
else
oa_opts.fontstr = fontstr;
}
#endif
/* Regardless of success or failure, continue with new/default font. */
}
#ifdef VILE_OLE
if (oa_invoke)
{
/* Intialize OLE Automation */
if (! oleauto_init(&oa_opts))
ExitProgram(1);
}
#endif
return MainProgram(argc, argv);
}
void *
winvile_hwnd(void)
{
return (cur_win->main_hwnd);
}
#ifdef VILE_OLE
void
ntwinio_oleauto_reg(void)
{
/* Pound a bunch of OLE registration data into the registry & exit. */
ExitProgram(oleauto_register(&oa_opts));
}
#endif
/*
* Split the version-message to allow us to format with tabs, so the
* proportional font doesn't look ugly.
*/
static size_t
option_size(const char *option)
{
if (*option == '-') {
const char *next = skip_ctext(option);
if (next[0] == ' '
&& next[1] != ' '
&& next[1] != 0) {
next = skip_ctext(next + 1);
return next - option;
}
return 14; /* use embedded blanks to fix the tabs ... */
}
return 0;
}
void
gui_version(char *program)
{
ShowWindow(cur_win->main_hwnd, SW_HIDE);
MessageBox(cur_win->main_hwnd, getversion(), prognam, MB_OK|MB_ICONSTOP);
}
void
gui_usage(char *program, const char *const *options, size_t length)
{
char *buf, *s;
size_t need, n;
const char *fmt1 = "%s\n\nOptions:\n";
const char *fmt2 = " %s\t%s\n";
const char *fmt3 = "%s\n";
/*
* Hide the (partly-constructed) main window. It'll flash (FIXME).
*/
ShowWindow(cur_win->main_hwnd, SW_HIDE);
need = strlen(fmt1) + strlen(prognam);
for (n = 0; n < length; n++) {
if (option_size(options[n]))
need += strlen(fmt2) + strlen(options[n]);
else
need += strlen(fmt3) + strlen(options[n]);
}
buf = malloc(need);
s = lsprintf(buf, fmt1, prognam);
for (n = 0; n < length; n++) {
char temp[80];
if ((need = option_size(options[n])) != 0) {
strncpy(temp, options[n], need);
temp[need] = EOS;
s = lsprintf(s, fmt2, temp, skip_cblanks(options[n] + need));
} else {
s = lsprintf(s, fmt3, options[n]);
}
}
MessageBox(cur_win->main_hwnd, buf, prognam, MB_OK|MB_ICONSTOP);
}