summaryrefslogtreecommitdiff
path: root/src/runtime/rmswin.ri
diff options
context:
space:
mode:
Diffstat (limited to 'src/runtime/rmswin.ri')
-rw-r--r--src/runtime/rmswin.ri4204
1 files changed, 4204 insertions, 0 deletions
diff --git a/src/runtime/rmswin.ri b/src/runtime/rmswin.ri
new file mode 100644
index 0000000..3471fd3
--- /dev/null
+++ b/src/runtime/rmswin.ri
@@ -0,0 +1,4204 @@
+/*
+ * rmswin.ri - Microsoft Windows-specific graphics interface code.
+ *
+ * Todo:
+ * geticonpos
+ * seticonimage
+ * free_mutable
+ * freecolor
+ *
+ * Untested:
+ * toggle_fgbg
+ * rebind
+ * geticonic
+ * getimstr
+ * getfntnam
+ * dumpimage
+ * getpointername
+ *
+ * Blown off:
+ * getvisual
+ * getdefault
+ */
+#ifdef Graphics
+
+void wfreersc();
+int alc_rgb(wbp w, SysColor rgb);
+/*
+ * check_and_get_msg retreives the next message in *pMsg;
+ * returns 1 if regular message was retreived, 0 if quit message,
+ * -1 if there was an error.
+ */
+static int check_and_get_msg( MSG *pMsg );
+int numRealized;
+
+#ifndef min
+ #define min(x,y) (((x) < (y))?(x):(y))
+ #define max(x,y) (((x) > (y))?(x):(y))
+#endif /* min */
+#define PALCLR(c) (c | 0x2000000L)
+
+int winInitialized = 0;
+int BORDHEIGHT;
+int BORDWIDTH;
+/*
+ * check for double-byte character set versions of Windows
+ */
+CPINFO cpinfo;
+int MAXBYTESPERCHAR;
+
+wclrp scp;
+HPALETTE palette;
+int numColors = 0;
+
+char szAppName[] = "Icon";
+
+/*
+ * pattern symbols
+ */
+stringint siPatternSyms[] = {
+ {0, 16},
+ { "black", 0},
+ { "checkers", 12},
+ { "darkgray", 2},
+ { "diagonal", 8},
+ { "grains", 13},
+ { "gray", 3},
+ { "grid", 10},
+ { "horizontal",9},
+ { "lightgray", 4},
+ { "scales", 14},
+ { "trellis", 11},
+ { "vertical", 7},
+ { "verydark", 1},
+ { "verylight", 5},
+ { "waves", 15},
+ { "white", 6},
+};
+
+/*
+ * draw ops
+ */
+stringint drawops[] = {
+ { 0, 16},
+ {"and", R2_MASKPEN},
+ {"andInverted", R2_MASKPENNOT},
+ {"andReverse", R2_MASKNOTPEN},
+ {"clear", R2_BLACK},
+ {"copy", R2_COPYPEN},
+ {"copyInverted", R2_NOTCOPYPEN},
+ {"equiv", R2_NOTXORPEN},
+ {"invert", R2_NOT},
+ {"nand", R2_NOTMASKPEN},
+ {"noop", R2_NOP},
+ {"nor", R2_NOTMERGEPEN},
+ {"or", R2_MERGEPEN},
+ {"orInverted", R2_MERGEPENNOT},
+ {"orReverse", R2_MERGENOTPEN},
+ {"set", R2_WHITE},
+ {"xor", R2_XORPEN},
+};
+
+/*
+ * line types
+ */
+stringint siLineTypes[] = {
+ {0, 6},
+ {"dashdotted", PS_DASHDOT},
+ {"dashdotdotted", PS_DASHDOTDOT},
+ {"dashed", PS_DOT},
+ {"longdashed", PS_DASH},
+ {"solid", PS_SOLID},
+ {"striped", PS_DOT}
+};
+
+HINSTANCE mswinInstance;
+int ncmdShow;
+
+int FoundIt, FoundNew;
+HWND NewWin;
+char *lookingfor;
+struct WNDlist {
+ HWND w;
+ struct WNDlist *next;
+ } * wlhead;
+
+struct WNDlist *wlinsert(HWND w)
+{
+ struct WNDlist *x = malloc(sizeof (struct WNDlist));
+ x->w = w;
+ x->next = wlhead;
+ wlhead = x;
+}
+
+int wlsearch(HWND w)
+{
+ struct WNDlist *x;
+ for(x=wlhead;x;x=x->next) if (x->w == w) return 1;
+ return 0;
+}
+
+void wlfree()
+{
+ struct WNDlist *x = wlhead;
+ while (wlhead) {
+ x = wlhead->next;
+ free(wlhead);
+ wlhead = x;
+ }
+}
+
+BOOL_CALLBACK myenumproc(HWND w, LPARAM l)
+{
+ wlinsert(w);
+ return 1;
+}
+
+BOOL_CALLBACK myenumproc2(HWND w, LPARAM l)
+{
+ if (!wlsearch(w)) {
+ FoundNew++;
+ NewWin = w;
+ }
+ return 1;
+}
+
+char * strcasestr(char *haystack, char *needle)
+{
+ int len = strlen(needle);
+ while (*haystack) {
+ if (strncasecmp(haystack, needle, len) == 0) return haystack;
+ haystack++;
+ }
+ return 0;
+}
+
+BOOL_CALLBACK myenumproc3(HWND w, LPARAM l)
+{
+ char s[64], s2[64];
+ GetWindowText(w, s2, 63);
+ /*
+ * Conditions to find a window:
+ * 1) wasn't in the list of windows already present when we launched.
+ * 2) either contains the argv[0] program name, or
+ * was first window to appear after we called WinExec().
+ */
+ if (!wlsearch(w)) {
+ FoundNew++;
+ if ((strcasestr(s2, lookingfor) != NULL) || (NewWin && (NewWin == w))) {
+ FoundIt++;
+ }
+ }
+ return 1;
+}
+
+char *lookcmdname(char *buf, char *s)
+{
+ char *t = buf;
+ while (*s) {
+ *t++ = *s;
+ if (*s == '\\') t = buf;
+ s++;
+ }
+ *t++ = '\0';
+ s = buf;
+ while (*s) {
+ if (*s == '.') *s = '\0';
+ s++;
+ }
+ return buf;
+}
+
+
+/*
+ * wopen
+ */
+FILE *wopen(char *name, struct b_list *lp, dptr attr, int n, int *err_idx)
+ {
+ wbp w;
+ wsp ws;
+ wcp wc;
+ struct imgdata *imd;
+ char answer[256];
+ int i, r;
+ tended struct b_list *tlp;
+ tended struct descrip attrrslt;
+ HDC hdc, hdc2, hdc3;
+ TEXTMETRIC metrics;
+ LOGPALETTE logpal[4]; /* really 1 + space for an extra palette entry */
+ HBRUSH brush;
+ HBITMAP oldpix, oldpix2;
+ HFONT oldfont;
+
+ if (! winInitialized++) {
+ BORDWIDTH = FRAMEWIDTH * 2;
+ BORDHEIGHT = TITLEHEIGHT + FRAMEHEIGHT * 2 - 1;
+ GetCPInfo(CP_ACP, &cpinfo);
+ MAXBYTESPERCHAR = cpinfo.MaxCharSize;
+ }
+
+ tlp = lp;
+
+ /*
+ * allocate a binding, a window state, and a context
+ */
+ Protect(w = alc_wbinding(), return NULL);
+ Protect(w->window = alc_winstate(), { free_binding(w); return NULL; });
+ Protect(w->context = alc_context(w), { free_binding(w); return NULL; });
+ ws = w->window;
+ ws->listp.dword = D_List;
+ BlkLoc(ws->listp) = (union block *)lp;
+ ws->width = ws->height = 0;
+ wc = w->context;
+
+ /*
+ * process the passed in attributes - by calling wattrib
+ */
+ for(i = 0; i < n; i++)
+ switch (wattrib(w, StrLoc(attr[i]), StrLen(attr[i]), &attrrslt,
+ answer)) {
+ case Failed:
+ wclose(w);
+ return NULL;
+ case Error:
+ /* think of something to do here */
+ break;
+ }
+
+ /*
+ * set the title, defaulting to the "filename" supplied to open()
+ */
+ if (ws->windowlabel == NULL) ws->windowlabel = salloc(name);
+ if (ws->iconlabel == NULL) ws->iconlabel = salloc(name);
+
+ if (ws->posx < 0) ws->posx = 0;
+ if (ws->posy < 0) ws->posy = 0;
+
+ /*
+ * create the window
+ */
+ ws->iconwin = CreateWindow( "iconx", ws->windowlabel, WS_OVERLAPPEDWINDOW,
+ ws->posx, ws->posy,
+ ws->width == 0 ? 400 : ws->width + BORDWIDTH,
+ ws->height == 0 ? 400: ws->height + BORDHEIGHT,
+ NULL, NULL, mswinInstance, NULL);
+ hdc = GetDC(ws->iconwin);
+ if ((GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE) && (numColors == 0)){
+ /* This window is on a device that supports palettes */
+ numColors = 2;
+ logpal[0].palNumEntries = 2;
+ logpal[0].palVersion = 0x300;
+ logpal[0].palPalEntry[0].peFlags = 0;
+ logpal[0].palPalEntry[0].peRed = 0;
+ logpal[0].palPalEntry[0].peGreen = 0;
+ logpal[0].palPalEntry[0].peBlue = 0;
+ logpal[0].palPalEntry[1].peFlags = 0;
+ logpal[0].palPalEntry[1].peRed = 255;
+ logpal[0].palPalEntry[1].peGreen = 255;
+ logpal[0].palPalEntry[1].peBlue = 255;
+ palette = CreatePalette(logpal);
+ if ((scp = malloc(2 * sizeof (struct wcolor))) == NULL) return NULL;
+ scp[0].c = RGB(0,0,0);
+ scp[0].type = SHARED;
+ strcpy(scp[0].name, "black");
+ scp[1].c = RGB(255,255,255);
+ scp[1].type = SHARED;
+ strcpy(scp[1].name, "white");
+ }
+ oldfont = SelectObject(hdc, wc->font->font);
+ GetTextMetrics(hdc, &metrics);
+ wc->font->charwidth = dc_maxcharwidth(hdc);
+ SelectObject(hdc, oldfont);
+ ReleaseDC(ws->iconwin, hdc);
+ wc->font->ascent = metrics.tmAscent;
+ wc->font->descent = metrics.tmDescent;
+ /* wc->font->charwidth = metrics.tmMaxCharWidth; buggy */
+ wc->font->height = metrics.tmHeight;
+ wc->leading = metrics.tmHeight;
+ ws->x = 0;
+ ws->y = ASCENT(w);
+ ws->y += w->context->dy;
+ ws->x += w->context->dx;
+ /*
+ * set the generic window's true default sizes
+ */
+ if (!ws->width || !ws->height) {
+ if (!ws->width) ws->width = FWIDTH(w) * 80;
+ if (!ws->height) ws->height = FHEIGHT(w) * 12;
+ SetWindowPos(ws->iconwin, ws->iconwin,
+ ws->posx,
+ ws->posy,
+ ws->width + BORDWIDTH, ws->height + BORDHEIGHT,
+ SWP_NOZORDER);
+ }
+ if (!ws->pix) {
+ hdc = GetDC(ws->iconwin);
+ ws->pix = CreateCompatibleBitmap(hdc, ws->width, ws->height);
+ ReleaseDC(ws->iconwin, hdc);
+ }
+
+ if (alc_rgb(w, wc->fg) == Failed) {
+ return 0;
+ }
+ if (alc_rgb(w, wc->bg) == Failed) {
+ return 0;
+ }
+ ws->pixwidth = ws->width;
+ ws->pixheight = ws->height;
+ if (!ISTOBEHIDDEN(ws)) {
+ ws->win = ws->iconwin;
+ ShowWindow(ws->win, ncmdShow);
+ }
+ else ws->win = 0;
+
+ if (ws->initialPix) {
+ hdc = GetDC(ws->iconwin);
+ hdc2 = CreateCompatibleDC(hdc);
+ oldpix = SelectObject(hdc2, ws->pix);
+ hdc3 = CreateCompatibleDC(hdc);
+ oldpix2 = SelectObject(hdc3, ws->initialPix);
+ BitBlt(hdc2, 0, 0, ws->width, ws->height, hdc3, 0, 0, SRCCOPY);
+ if (ws->win)
+ BitBlt(hdc, 0, 0, ws->width, ws->height, hdc3, 0, 0, SRCCOPY);
+ SelectObject(hdc2, oldpix);
+ SelectObject(hdc3, oldpix2);
+ DeleteDC(hdc2);
+ DeleteDC(hdc3);
+ DeleteObject(ws->initialPix);
+ ws->initialPix = (HBITMAP) NULL;
+ }
+ else {
+ /*
+ * initialize the image with the background color
+ */
+ RECT rec;
+ hdc = GetDC(ws->iconwin);
+ hdc2 = CreateCompatibleDC(hdc);
+ oldpix = SelectObject(hdc2, ws->pix);
+ rec.left = rec.top = 0;
+ rec.right = ws->width;
+ rec.bottom = ws->height;
+ if (palette) {
+ SelectPalette(hdc, palette, FALSE);
+ SelectPalette(hdc2, palette, FALSE);
+ RealizePalette(hdc);
+ RealizePalette(hdc2);
+ }
+ brush = CreateBrushIndirect(&(wc->bgbrush));
+ if (ws->win)
+ FillRect(hdc, &rec, brush);
+ FillRect(hdc2, &rec, brush);
+ DeleteObject(brush);
+ SelectObject(hdc2, oldpix);
+ ReleaseDC(ws->iconwin, hdc);
+ DeleteDC(hdc2);
+
+ imd = &ws->initimage;
+ if (imd->width) {
+ r = strimage(w, 0, 0, imd->width, imd->height, imd->paltbl,
+ imd->data, (word)imd->width * (word)imd->height, 0);
+ free((pointer)imd->paltbl);
+ free((pointer)imd->data);
+ imd->width = 0;
+ if (r < 0) {
+ return 0;
+ }
+ }
+ }
+ if (ws->win)
+ UpdateWindow(ws->win);
+
+ return (FILE *)w;
+ }
+
+int handle_config(wbp w, UINT msg, WPARAM wp, LPARAM lp)
+ {
+ int neww, newh;
+ struct descrip d;
+ wsp ws = w->window;
+
+ if (wp == SIZE_MINIMIZED) {
+ if (ws->win) {
+ SetWindowText(ws->win, ws->iconlabel);
+ ws->win = NULL;
+ }
+ return 1;
+ }
+
+ if (ws->win)
+ SetWindowText(ws->win, ws->windowlabel);
+ ws->win = ws->iconwin;
+
+ /*
+ * make sure text cursor stays on-screen
+ */
+ ws->x = min(ws->x, LOWORD(lp) - FWIDTH(w));
+ ws->y = min(ws->y, HIWORD(lp));
+
+ neww = LOWORD(lp);
+ newh = HIWORD(lp);
+
+ /*
+ * if it was not a resize, drop it
+ */
+ if ((ws->width == neww) && (ws->height == newh)) {
+ return 1;
+ }
+
+ ws->width = neww;
+ ws->height = newh;
+ if (! resizePixmap(w, ws->width, ws->height)) return 0;
+ if (!ISEXPOSED(w)) {
+ SETEXPOSED(w);
+ return 1;
+ }
+ MakeInt(RESIZED, &d);
+ qevent(w->window, &d, ws->width, ws->height, ~(uword)0, 0);
+ return 1;
+ }
+
+/*
+ * handle window controls (child windows), at the moment these are
+ * buttons and scrollbars. wp is which child (base 1).
+ * Buttons come in as undiluted messages.
+ * Scrollbars come in with msg = new value of scrollbar
+ */
+void handle_child(wbp wb, UINT msg, WPARAM wp, LPARAM lp)
+ {
+ DWORD dw;
+ LONG t;
+ WORD x, y;
+ wsp ws = wb->window;
+ char *s;
+ int len;
+ struct descrip d;
+ int flags = 0;
+ if (LOWORD(wp) > ws->nChildren) return;
+ s = ws->child[LOWORD(wp) - 1].id;
+ len = strlen(s);
+ d = nulldesc;
+ StrLoc(d) = alcstr(s, len);
+ StrLen(d) = len;
+ switch (HIWORD(wp)) {
+ case BN_CLICKED: {
+ dw = GetMessagePos();
+ x = LOWORD(dw);
+ y = HIWORD(dw);
+ break;
+ }
+ case EN_SETFOCUS: case EN_KILLFOCUS: case EN_CHANGE: case EN_UPDATE:
+ case EN_ERRSPACE: case EN_MAXTEXT: case EN_HSCROLL: case EN_VSCROLL: {
+ return;
+ }
+ default: { /* scrollbar */
+ x = y = msg;
+ }
+ }
+ t = GetMessageTime();
+ qevent(ws, &d, x, y, t, flags);
+ if (ws->focusChild)
+ SetFocus(ws->focusChild);
+ else if (ws->win)
+ SetFocus(ws->win);
+ else
+ SetFocus(ws->iconwin);
+ }
+
+void handle_menu(wbp wb, UINT msg, WPARAM wp, LPARAM lp)
+ {
+ wsp ws = wb->window;
+ DWORD dw;
+ LONG t;
+ WORD x, y;
+ struct descrip d;
+ char *s = ws->menuMap[wp];
+ int len = strlen(s);
+ int flags = 0;
+
+ d = nulldesc;
+ StrLoc(d) = alcstr(s, len);
+ StrLen(d) = len;
+ dw = GetMessagePos();
+ x = LOWORD(dw);
+ y = HIWORD(dw);
+ t = GetMessageTime();
+ qevent(ws, &d, x, y, t, flags);
+ }
+
+void handle_keypress(wbp wb, UINT msg, WPARAM wp, LPARAM lp, int meta)
+ {
+ wsp ws = wb->window;
+ DWORD dw;
+ LONG t;
+ WORD x, y;
+ struct descrip d;
+ int flags = 0;
+ if (msg == WM_CHAR || msg == WM_SYSCHAR) {
+ StrLen(d) = 1;
+ StrLoc(d) = (char *)&allchars[wp & 0xFF];
+ }
+ else { /* WM_KEYDOWN or WM_SYSKEYDOWN */
+ MakeInt(wp, &d);
+ }
+ dw = GetMessagePos();
+ x = LOWORD(dw);
+ y = HIWORD(dw);
+ t = GetMessageTime();
+ if (GetKeyState(VK_CONTROL) < 0) flags |= ControlMask;
+ if (GetKeyState(VK_SHIFT) < 0) flags |= ShiftMask;
+
+ if (meta) flags |= Mod1Mask;
+ qevent(ws, &d, x, y, t, flags);
+ }
+
+void handle_mouse(wbp wb, UINT msg, WPARAM wp, LPARAM lp)
+ {
+ wsp ws = wb->window;
+ LONG t;
+ WORD x, y;
+ struct descrip d;
+ long flags = 0, eventcode;
+
+ switch(msg) {
+ case WM_MOUSEMOVE: /* only called if one of these three cases is true */
+ if (MK_LBUTTON & wp)
+ eventcode = MOUSELEFTDRAG;
+ else if (MK_RBUTTON & wp)
+ eventcode = MOUSERIGHTDRAG;
+ else if (MK_MBUTTON & wp)
+ eventcode = MOUSEMIDDRAG;
+ else eventcode = 0;
+ break;
+ case WM_LBUTTONDOWN:
+ eventcode = MOUSELEFT;
+ break;
+ case WM_MBUTTONDOWN:
+ eventcode = MOUSEMID;
+ break;
+ case WM_RBUTTONDOWN:
+ eventcode = MOUSERIGHT;
+ break;
+ case WM_LBUTTONUP:
+ eventcode = MOUSELEFTUP;
+ break;
+ case WM_MBUTTONUP:
+ eventcode = MOUSEMIDUP;
+ break;
+ case WM_RBUTTONUP:
+ eventcode = MOUSERIGHTUP;
+ break;
+ default:
+ eventcode = 0;
+ break;
+ }
+
+ MakeInt(eventcode, &d);
+ x = LOWORD(lp);
+ y = HIWORD(lp);
+ t = GetMessageTime(); /* why might someone comment this out? */
+
+ if (MK_CONTROL & wp) flags |= ControlMask;
+ if (MK_SHIFT & wp) flags |= ShiftMask;
+
+ qevent(ws, &d, x, y, t, flags);
+ }
+
+LRESULT_CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
+{
+ HDC hdc, hdc2;
+ PAINTSTRUCT ps;
+ RECT rect;
+ wbp wb = NULL;
+ wsp ws = NULL;
+ int n, i, imin, imax;
+
+ /*
+ * find a binding associated with the given window.
+ */
+ for (wb = wbndngs; wb; wb=wb->next) {
+ ws = wb->window;
+
+ if ((ws->win == hwnd) || (ws->iconwin == hwnd)) break;
+ }
+ if (msg == WM_QUIT) {
+ wfreersc();
+ }
+ else if (!wb) {
+ /*
+ * doesn't look like its for one of our windows, pass it to
+ * DefWindowProc and hope for the best.
+ */
+ }
+ else
+ switch(msg) {
+ case WM_PAINT:
+ hdc = BeginPaint(hwnd, &ps);
+ GetClientRect(hwnd, &rect);
+ if (IsIconic(hwnd)) {
+ HBRUSH hb = CreateBrushIndirect(&(wb->context->brush));
+ FrameRect(hdc, &rect, hb);
+ DeleteObject(hb);
+ DrawText(hdc, "Iconx", 5, &rect, DT_WORDBREAK);
+ }
+ else {
+ HBITMAP oldpix;
+ hdc2 = CreateCompatibleDC(hdc);
+ oldpix = SelectObject(hdc2, ws->pix);
+ BitBlt(hdc, rect.left, rect.top,
+ rect.right - rect.left + 1, rect.bottom - rect.top + 1,
+ hdc2, rect.left, rect.top, SRCCOPY);
+ SelectObject(hdc2, oldpix);
+ DeleteDC(hdc2);
+ }
+ EndPaint(hwnd, &ps);
+ return 0;
+ case WM_MOUSEMOVE:
+ if (ws->curcursor)
+ SetCursor(ws->curcursor);
+ if ((MK_LBUTTON | MK_RBUTTON | MK_MBUTTON) & wp)
+ handle_mouse(wb,msg,wp,lp);
+ return 0;
+ case WM_LBUTTONDOWN: case WM_RBUTTONDOWN: case WM_MBUTTONDOWN:
+ case WM_LBUTTONUP: case WM_RBUTTONUP: case WM_MBUTTONUP:
+ handle_mouse(wb,msg,wp,lp);
+ return 0;
+ case WM_KEYDOWN:
+ switch (wp) { /* VK defn's from <winuser.h> */
+ case VK_F1: case VK_F2: case VK_F3: case VK_F4:
+ case VK_F5: case VK_F6: case VK_F7: case VK_F8:
+ case VK_F9: case VK_F10: case VK_F11: case VK_F12:
+ case VK_HOME: case VK_END: case VK_PRIOR: case VK_NEXT:
+ case VK_LEFT: case VK_RIGHT: case VK_UP: case VK_DOWN:
+ case VK_INSERT: case VK_SELECT: case VK_PRINT:
+ case VK_EXECUTE: case VK_SNAPSHOT: case VK_HELP: case VK_SEPARATOR:
+ case VK_CLEAR: case VK_PAUSE: case VK_SCROLL:
+ handle_keypress(wb, msg, wp, lp, 0);
+ return 0;
+ case VK_DELETE:
+ handle_keypress(wb, WM_CHAR, '\177', lp, 0);
+ return 0;
+ }
+ break;
+ case WM_SYSKEYDOWN:
+ switch (wp) {
+ case VK_F1: case VK_F2: case VK_F3: /* alt-F4 terminates */
+ case VK_F5: case VK_F6: case VK_F7: case VK_F8:
+ case VK_F9: case VK_F10: case VK_F11: case VK_F12:
+ case VK_HOME: case VK_END: case VK_PRIOR: case VK_NEXT:
+ case VK_LEFT: case VK_RIGHT: case VK_UP: case VK_DOWN:
+ case VK_INSERT: case VK_DELETE: case VK_SELECT: case VK_PRINT:
+ case VK_EXECUTE: case VK_SNAPSHOT: case VK_HELP: case VK_SEPARATOR:
+ case VK_CLEAR: case VK_PAUSE:
+ handle_keypress(wb, msg, wp, lp, 1);
+ return 0;
+ }
+ break;
+ case WM_CHAR:
+ handle_keypress(wb, msg, wp, lp, 0);
+ return 0;
+ case WM_SYSCHAR:
+ handle_keypress(wb, msg, wp, lp, 1);
+ /*
+ * Unless there is a menu bar installed,
+ * Alt-A .. Alt-Z, and Alt-0 .. Alt-9 are eaten by Icon;
+ * others are passed on to Windows for things like Alt-Esc.
+ */
+ if (isalnum(wp) && !(ws->menuMap)) return 0;
+ break;
+ case WM_HSCROLL:
+ case WM_VSCROLL:
+ for(n=0; n < ws->nChildren && ws->child[n].win != (HWND)lp; n++){
+ }
+ if (n == ws->nChildren) break;
+ i = GetScrollPos(ws->child[n].win, SB_CTL);
+ GetScrollRange(ws->child[n].win, SB_CTL, &imin, &imax);
+ switch (LOWORD(wp)) {
+ case SB_PAGEDOWN :
+ break;
+ case SB_LINEDOWN :
+ if (i < imax) {
+ SetScrollPos(ws->child[n].win, SB_CTL,
+ GetScrollPos(ws->child[n].win, SB_CTL) + 1, TRUE);
+ }
+ break;
+ case SB_PAGEUP :
+ break;
+ case SB_LINEUP :
+ if (i > imin) {
+ SetScrollPos(ws->child[n].win, SB_CTL,
+ GetScrollPos(ws->child[n].win, SB_CTL) - 1, TRUE);
+ }
+ break;
+ case SB_TOP :
+ SetScrollPos(ws->child[n].win, SB_CTL, imin, TRUE);
+ break;
+ case SB_BOTTOM :
+ SetScrollPos(ws->child[n].win, SB_CTL, imax, TRUE);
+ break;
+ case SB_THUMBPOSITION :
+ SetScrollPos(ws->child[n].win, SB_CTL, HIWORD(wp), TRUE);
+ break;
+ case SB_THUMBTRACK :
+ SetScrollPos(ws->child[n].win, SB_CTL, HIWORD(wp), TRUE);
+ break;
+ case SB_ENDSCROLL: /* noop */
+ break;
+ default : /* potentially a problem here */
+ break;
+ }
+ i = GetScrollPos(ws->child[n].win, SB_CTL);
+ handle_child(wb, i, n+1, -1);
+ break;
+ case WM_COMMAND:
+ if (LOWORD(lp) == 0)
+ handle_menu(wb, msg, wp, lp);
+ else
+ handle_child(wb, msg, wp, lp);
+ break;
+ case WM_SIZE:
+ handle_config(wb, msg, wp, lp);
+ break;
+ case WM_MOVE:
+ ws->posx = LOWORD(lp) - (BORDWIDTH>>1);
+ ws->posy = HIWORD(lp) - (BORDHEIGHT - 4);
+ break;
+ case WM_ACTIVATE:
+ if (wp == WA_INACTIVE) {
+ if (ws->savedcursor) SetCursor(ws->savedcursor);
+ if (ws->hasCaret) {
+ HideCaret(ws->iconwin);
+ DestroyCaret();
+ ws->hasCaret = 0;
+ }
+ }
+ else { /* ... */
+ if (ws->savedcursor == NULL)
+ ws->savedcursor = SetCursor(ws->curcursor);
+ else (void) SetCursor(ws->curcursor);
+ if (ISCURSORON(wb)) {
+ CreateCaret(ws->iconwin, NULL, FWIDTH(wb), FHEIGHT(wb));
+ SetCaretPos(ws->x, ws->y - ASCENT(wb));
+ SetCaretBlinkTime(500);
+ ShowCaret(ws->iconwin);
+ ws->hasCaret = 1;
+ }
+ }
+ break;
+ case WM_GETMINMAXINFO: {
+ MINMAXINFO *mmi = (MINMAXINFO *)lp;
+ if (! ISRESIZABLE(wb)) {
+ mmi->ptMinTrackSize.x = mmi->ptMaxTrackSize.x =
+ ws->width + BORDWIDTH;
+ mmi->ptMinTrackSize.y = mmi->ptMaxTrackSize.y =
+ ws->height + BORDHEIGHT;
+ }
+ return 0;
+ }
+ case WM_KILLFOCUS:
+ if (ws->hasCaret) {
+ HideCaret(ws->iconwin);
+ DestroyCaret();
+ ws->hasCaret = 0;
+ }
+ break;
+ case WM_SETFOCUS:
+ if (ws->focusChild)
+ SetFocus(ws->focusChild);
+ else if (ISCURSORON(wb)) {
+ CreateCaret(ws->iconwin, NULL, FWIDTH(wb), FHEIGHT(wb));
+ SetCaretPos(ws->x, ws->y - ASCENT(wb));
+ SetCaretBlinkTime(500);
+ ShowCaret(ws->iconwin);
+ ws->hasCaret = 1;
+ }
+ break;
+ /* case WM_QUIT is handled prior to the switch*/
+ case WM_DESTROY:
+ if (ws->win == hwnd)
+ ws->win = NULL;
+ if (ws->iconwin == hwnd)
+ ws->iconwin = NULL;
+ if (ws->refcount > 0) {
+ PostQuitMessage(0);
+ return 0;
+ }
+ else if (ws->refcount < 0) {
+ ws->refcount = -ws->refcount;
+ }
+ break;
+ case MM_MCINOTIFY:
+ mciSendCommand(LOWORD(lp), MCI_CLOSE, 0, (DWORD)NULL);
+ break;
+ }
+ return DefWindowProc(hwnd, msg, wp, lp);
+}
+
+/*
+ * wclose - make sure the window goes away - no questions asked
+ */
+int wclose(wbp w)
+ {
+ wsp ws = w->window;
+ if (pollevent() == -1) return -1;
+ if (ws->win && ws->refcount > 1) {
+ /*
+ * Decrement refcount and negate it to tell the window procedure
+ * that we closed the window, not the user, so don't terminate.
+ */
+ ws->refcount--;
+ ws->refcount = -ws->refcount;
+ DestroyWindow(ws->win);
+ while (ws->win)
+ if (pollevent() == -1) return -1;
+ }
+ else {
+ free_binding(w);
+ }
+ return 1;
+ }
+
+int pollevent()
+ {
+ wbp w;
+ MSG m;
+ int result;
+
+ /* some while PeekMessage loops here, maybe one per window ? */
+ while (PeekMessage(&m, NULL, 0, 0, PM_NOREMOVE)) {
+ if ((result = check_and_get_msg(&m)) <= 0) return result;
+ TranslateMessage(&m);
+ DispatchMessage(&m);
+ }
+ return 400;
+ }
+
+/*
+ * write some text to both the window and the pixmap
+ */
+void xdis(w,s,n)
+register wbp w;
+char *s;
+int n;
+ {
+ XPoint pt;
+ HBRUSH hb;
+ XRectangle rect;
+ STDLOCALS(w);
+
+ STDFONT;
+ rect.left = ws->x; rect.right = ws->x + dc_textwidth(pixdc, s, n);
+ rect.top = ws->y - ASCENT(w); rect.bottom = ws->y + DESCENT(w);
+
+ /* skip resource allocation if we are offscreen */
+ if (!(rect.left > ws->width || rect.right < 0 ||
+ rect.top < 0 || rect.bottom > ws->height)) {
+
+ hb = CreateBrushIndirect(&(wc->bgbrush));
+ if (stdwin) {
+ /*
+ * SetBkColor() does not dither consistently with bgbrush;
+ * erase the background beforehand and use transparent drawing
+ */
+ FillRect(stddc, &rect, hb);
+ SetBkMode(stddc, TRANSPARENT);
+ SetTextColor(stddc, PALCLR(wc->fg));
+ TextOut(stddc, ws->x, ws->y - ASCENT(w), s, n);
+ }
+ FillRect(pixdc, &rect, hb);
+ DeleteObject(hb);
+ SetBkMode(pixdc, TRANSPARENT);
+ SetTextColor(pixdc, PALCLR(wc->fg));
+ TextOut(pixdc, ws->x, ws->y - ASCENT(w), s, n);
+ }
+ ws->x += dc_textwidth(pixdc, s, n);
+
+ FREE_STDLOCALS(w);
+ }
+/*
+ * wputc
+ */
+int wputc(int ci, wbp w)
+ {
+ char c = (char)ci;
+ wsp ws = w->window;
+ wcp wc = w->context;
+ int y_plus_descent;
+ HBRUSH hb;
+
+ switch (c) {
+ case '\n':
+ ws->y += LEADING(w);
+ if (ws->y + DESCENT(w) > ws->height) {
+ RECT r;
+ STDLOCALS(w);
+ ws->y -= LEADING(w);
+ y_plus_descent = ws->y + DESCENT(w);
+ BitBlt(pixdc, 0, 0,
+ ws->width, y_plus_descent,
+ pixdc, 0, LEADING(w), SRCCOPY);
+ r.left = 0;
+ r.top = y_plus_descent - FHEIGHT(w);
+ r.right = ws->width;
+ r.bottom = ws->height;
+ hb = CreateBrushIndirect(&(wc->bgbrush));
+ FillRect(pixdc, &r, hb);
+ DeleteObject(hb);
+ if (stdwin)
+ BitBlt(stddc, 0, 0, ws->width, ws->height,
+ pixdc, 0, 0, SRCCOPY);
+ FREE_STDLOCALS(w);
+ }
+ /* intended fall-through */
+ case '\r':
+ /*
+ * set the new x position
+ */
+ ws->x = wc->dx;
+ break;
+ case '\t':
+ xdis(w, " ", 8 - (XTOCOL(w,ws->x) & 7));
+ break;
+ /*
+ * Handle backspaces. This implements cooked mode echo handling.
+ */
+ case '\177':
+ case '\010': {
+ int i = 0, pre_x;
+
+ /*
+ * Start with the last character queued up.
+ */
+ i--;
+ /*
+ * Trot back to the control-H itself.
+ */
+ while ((i>-EQUEUELEN) && (EVQUESUB(w,i) != c)) {
+ i--;
+ }
+ if (i == -EQUEUELEN) break;
+ /*
+ * Go past the control-H.
+ */
+ i--;
+ /*
+ * Go back through any number of control-H's from prior lifetimes.
+ */
+ while((i > -EQUEUELEN) && !isprint(EVQUESUB(w,i))) {
+ i--;
+ }
+ if (i == -EQUEUELEN) break;
+
+ /*
+ * OK, here's the character we're actually rubbing out. Back up.
+ */
+ c = EVQUESUB(w,i);
+ pre_x = ws->x;
+ ws->x -= TEXTWIDTH(w, &c, 1);
+ /*
+ * Physically erase the character from the queue. This results in
+ * two control-H's present in the queue.
+ */
+ *evquesub(w,i) = '\010';
+ /*
+ * Save the backed-up position, and draw spaces through the erased.
+ */
+ i = ws->x;
+ while(ws->x < pre_x) {
+ xdis(w, " ",1);
+ }
+ ws->x = i;
+ break;
+ }
+ /*
+ * bell (control-G)
+ */
+ case '\007':
+ break;
+ default:
+ xdis(w, &c, 1);
+ }
+ /*
+ * turn the cursor back on
+ */
+ UpdateCursorPos(ws,wc);
+ return 0;
+ }
+
+/*
+ * wgetq - get event from pending queue
+ */
+int wgetq(wbp w, dptr res)
+ {
+ MSG m;
+ wsp ws;
+ int first = 0, i = 0, j;
+ int hascaret = 0;
+ FILE *f;
+
+ if (!w || !(ws = w->window) || !(ws->iconwin)) {
+ return -1;
+ }
+ while (1) {
+ /*
+ * grab the built up queue
+ */
+ if (!EVQUEEMPTY(ws)) {
+ EVQUEGET(ws, *res);
+ if (ws->hasCaret) {
+ HideCaret(ws->iconwin);
+ DestroyCaret();
+ ws->hasCaret = 0;
+ }
+ return 1;
+ }
+ if (ISCURSORON(w) && ws->hasCaret == 0) {
+ CreateCaret(ws->iconwin, NULL, FWIDTH(w), FHEIGHT(w));
+ SetCaretPos(ws->x, ws->y - ASCENT(w));
+ SetCaretBlinkTime(500);
+ ShowCaret(ws->iconwin);
+ ws->hasCaret = 1;
+ }
+ i++;
+ if (check_and_get_msg(&m) <= 0) return -1;
+ TranslateMessage(&m);
+ DispatchMessage(&m);
+ }
+ }
+
+/*
+ * determine the new size of the client
+ */
+int setheight(w, height)
+wbp w;
+int height;
+ {
+ wsp ws = w->window;
+ ws->height = height;
+ return Succeeded;
+ }
+
+/*
+ * determine new size of client
+ */
+int setwidth(w, width)
+wbp w;
+SHORT width;
+ {
+ wsp ws = w->window;
+ ws->width = width;
+ return Succeeded;
+ }
+
+int setgeometry(w, geo)
+wbp w;
+char *geo;
+ {
+ wsp ws = w->window;
+ int width = 0, height = 0;
+ int x = 0, y = 0, status;
+ if ((status = parsegeometry(geo, &x, &y, &width, &height)) == 0)
+ return Error;
+ if (status & 1) {
+ ws->width = width;
+ ws->height = height;
+ }
+ if (status & 2) {
+ ws->posx = x;
+ ws->posy = y;
+ }
+ return Succeeded;
+ }
+
+int setcanvas(w,s)
+wbp w;
+char *s;
+ {
+ int cmd;
+ wsp ws = w->window;
+ HWND stdwin = ws->win;
+
+ if (!strcmp(s, "iconic")) {
+ cmd = SW_MINIMIZE;
+ CLRTOBEHIDDEN(ws);
+ }
+ else if (!strcmp(s, "normal")) {
+ cmd = SW_RESTORE;
+ stdwin = ws->win = ws->iconwin;
+ CLRTOBEHIDDEN(ws);
+ }
+ else if (!strcmp(s, "maximal")) {
+ cmd = SW_SHOWMAXIMIZED;
+ stdwin = ws->win = ws->iconwin;
+ CLRTOBEHIDDEN(ws);
+ }
+ else if (!strcmp(s, "hidden")) {
+ cmd = SW_HIDE;
+ SETTOBEHIDDEN(ws);
+ }
+ else {
+ return Error;
+ }
+ if (stdwin)
+ ShowWindow(stdwin, cmd);
+
+ return Succeeded;
+ }
+
+int seticonicstate(w, val)
+wbp w;
+char *val;
+ {
+ int height;
+ return Failed;
+ }
+
+int seticonlabel(w, val)
+wbp w;
+char *val;
+ {
+ wsp ws = w->window;
+ if (ws->iconlabel != NULL) free(ws->iconlabel);
+ ws->iconlabel = salloc(val);
+ if (ws->win && IsIconic(ws->win))
+ SetWindowText(ws->win, ws->iconlabel);
+ return Succeeded;
+ }
+
+int seticonpos(w, val)
+wbp w;
+char *val;
+ {
+ return Failed;
+ }
+
+
+int setwindowlabel(w, val)
+wbp w;
+char *val;
+ {
+ wsp ws = w->window;
+ /*
+ * plug in the new string
+ */
+ if (ws->windowlabel != NULL)
+ free(ws->windowlabel);
+ ws->windowlabel = salloc(val);
+
+ /*
+ * if we have to update, do it
+ */
+ if (ws->win && !IsIconic(ws->win))
+ SetWindowText(ws->win, ws->windowlabel);
+ return Succeeded;
+ }
+
+int setcursor(w, on)
+wbp w;
+int on;
+ {
+ wsp ws = w->window;
+ if (on) {
+ SETCURSORON(w);
+ }
+ else {
+ CLRCURSORON(w);
+ }
+ return Succeeded;
+ }
+
+HFONT findfont(char *family, int size, int flags, int ansi)
+{
+ int weight;
+ char slant, spacing;
+
+ if (size < 0) size = DEFAULTFONTSIZE;
+
+ if (flags & FONTFLAG_MEDIUM)
+ weight = FW_MEDIUM;
+ else if ((flags & FONTFLAG_DEMI) && (flags & FONTFLAG_BOLD))
+ weight = FW_DEMIBOLD;
+ else if (flags & FONTFLAG_BOLD)
+ weight = FW_BOLD;
+ else if (flags & FONTFLAG_DEMI)
+ weight = FW_SEMIBOLD;
+ else if (flags & FONTFLAG_LIGHT)
+ weight = FW_LIGHT;
+ else
+ weight = FW_DONTCARE;
+
+ if (flags & FONTFLAG_ITALIC)
+ slant = 1;
+ else
+ slant = 0;
+
+ if (flags & FONTFLAG_PROPORTIONAL)
+ spacing = VARIABLE_PITCH;
+ else if (flags & FONTFLAG_MONO)
+ spacing = FIXED_PITCH;
+ else spacing = DEFAULT_PITCH;
+
+ return CreateFont(size, 0, 0, 0, weight, slant, 0, 0,
+ (ansi && (MAXBYTESPERCHAR==1)) ? ANSI_CHARSET:DEFAULT_CHARSET,
+ OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
+ spacing, family);
+}
+
+HFONT mkfont(char *s)
+{
+ int flags, size;
+ char family[MAXFONTWORD+1];
+ char *stdfam = NULL;
+ HFONT hf = 0;
+
+ if (parsefont(s, family, &flags, &size)) {
+ /*
+ * This is a legal Icon font spec.
+ * Check first for special "standard" family names.
+ */
+ if (!strcmp(family, "mono") || !strcmp(family, "fixed")) {
+ stdfam = "Lucida Sans";
+ flags |= FONTFLAG_MONO + FONTFLAG_SANS;
+ }
+ else if (!strcmp(family, "typewriter")) {
+ stdfam = "Courier New"; /* was "courier" */
+ flags |= FONTFLAG_MONO + FONTFLAG_SERIF;
+ }
+ else if (!strcmp(family, "sans")) {
+ stdfam = "Arial"; /* was "swiss" */
+ flags |= FONTFLAG_PROPORTIONAL + FONTFLAG_SANS;
+ }
+ else if (!strcmp(family, "serif")) {
+ stdfam = "Times New Roman";
+ flags |= FONTFLAG_PROPORTIONAL + FONTFLAG_SERIF;
+ }
+ else stdfam = NULL;
+
+ if (stdfam) {
+ /*
+ * Standard name: first try preferred family, then generalize.
+ * ICONFONT can be NULL, in which case Windows chooses.
+ */
+ hf = findfont(stdfam, size, flags, 1);
+ if (hf == NULL)
+ hf = findfont(getenv("ICONFONT"), size, flags, 1);
+ }
+ else {
+ /*
+ * Any other name: must match as specified.
+ */
+ hf = findfont(family, size, flags, 0);
+ }
+ }
+ return hf;
+}
+
+/*
+ * Set the window's font by name.
+ */
+int setfont(w, s)
+wbp w;
+char **s;
+ {
+ wsp ws = w->window;
+ wcp wc = w->context;
+ HFONT hf, oldfont;
+ TEXTMETRIC metrics;
+ HDC tmpdc;
+
+ hf = mkfont(*s);
+ if (hf != NULL) {
+ if (wc->font->font)
+ DeleteObject(wc->font->font);
+ wc->font->font = hf;
+ if (wc->font->name)
+ free(wc->font->name);
+ wc->font->name = salloc(*s);
+
+ tmpdc = GetDC(ws->iconwin);
+ oldfont = SelectObject(tmpdc, hf);
+ wc->font->charwidth = dc_maxcharwidth(tmpdc);
+ if (GetTextMetrics(tmpdc, &metrics) == 0) {
+ /* gettextmetrics can fail; what should we do about it? */
+ ;
+ }
+ SelectObject(tmpdc, oldfont);
+ ReleaseDC(ws->iconwin, tmpdc);
+ wc->font->ascent = metrics.tmAscent;
+ wc->font->descent = metrics.tmDescent;
+/* wc->font->charwidth = metrics.tmMaxCharWidth; unreliable due to MS bug */
+ wc->leading = wc->font->height = metrics.tmHeight;
+ return Succeeded;
+ }
+ return Failed;
+ }
+
+/*
+ * rebind() - bind w's context to that of w2.
+ */
+int rebind(w, w2)
+wbp w, w2;
+ {
+ wsp ws = w->window;
+ /* decrement w->context->refcount? increment w2->context->refcount? */
+ w->context = w2->context;
+ return Succeeded;
+ }
+
+void setclip(w)
+wbp w;
+ {
+ wcp wc = w->context;
+ if (wc->cliprgn)
+ DeleteObject(wc->cliprgn);
+ if (wc->clipw >= 0)
+ wc->cliprgn = CreateRectRgn(wc->clipx, wc->clipy,
+ wc->clipx + wc->clipw,
+ wc->clipy + wc->cliph);
+ else
+ wc->cliprgn = NULL;
+ }
+
+void unsetclip(w)
+wbp w;
+ {
+ wcp wc = w->context;
+ if (wc->cliprgn)
+ DeleteObject(wc->cliprgn);
+ wc->cliprgn = NULL;
+ }
+
+ int lowerWindow(wbp w)
+ {
+ wsp ws = w->window;
+ if (ws->win)
+ SetWindowPos(ws->win, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
+ return Succeeded;
+ }
+
+int raiseWindow(wbp w)
+ {
+ wsp ws = w->window;
+ if (ws->win)
+ SetWindowPos(ws->win, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
+ return Succeeded;
+ }
+
+int nativecolor(w, s, r, g, b)
+wbp w;
+char *s;
+long *r, *g, *b;
+ {
+ return 0; /* no new colors beyond those of Icon */
+ }
+/*
+ * convert an Icon linear color into an MS Windows color value
+ */
+SysColor mscolor(wbp w, long r, long g, long b)
+{
+ SysColor x;
+ double invgamma = 1.0 / w->context->gamma;
+ long int red, green, blue;
+
+ red = 65535L * pow(r / 65535.0, invgamma);
+ green = 65535L * pow(g / 65535.0, invgamma);
+ blue = 65535L * pow(b / 65535.0, invgamma);
+ return RGB(red >> 8, green >> 8, blue >> 8);
+}
+
+/*
+ * Set the context's fill style by name.
+ */
+int setfillstyle(w, s)
+wbp w;
+char *s;
+ {
+ wcp wc = w->context;
+
+ if (!strcmp(s, "solid")) {
+ wc->brush.lbStyle = wc->fillstyle = BS_SOLID;
+ wc->brush.lbColor = PALCLR(wc->fg);
+ }
+ else {
+ if (!strcmp(s, "masked")
+ || !strcmp(s, "stippled") || !strcmp(s, "patterned")) {
+ wc->brush.lbStyle = wc->fillstyle = BS_PATTERN;
+ wc->brush.lbColor = PALCLR(wc->fg);
+ wc->brush.lbHatch = (LONG)wc->pattern;
+ wc->bkmode = TRANSPARENT;
+ }
+ else if (!strcmp(s, "textured")
+ || !strcmp(s, "opaquestippled") || !strcmp(s, "opaquepatterned")) {
+ wc->brush.lbStyle = wc->fillstyle = BS_PATTERN;
+ wc->brush.lbColor = PALCLR(wc->fg);
+ wc->brush.lbHatch = (LONG)wc->pattern;
+ wc->bkmode = OPAQUE;
+ }
+ else {
+ return Error;
+ }
+ }
+ return Succeeded;
+ }
+
+/*
+ * Set the context's line style by name.
+ */
+int setlinestyle(w, s)
+wbp w;
+char *s;
+ {
+ wcp wc = w->context;
+ SHORT ltype;
+
+ if ((ltype = si_s2i(siLineTypes, s)) < 0)
+ return Error;
+ wc->pen.lopnStyle = ltype;
+ resetfg(w);
+ if(!strcmp(s, "striped")) wc->bkmode = OPAQUE;
+ else wc->bkmode = TRANSPARENT;
+ return Succeeded;
+ }
+
+/*
+ * Set the context's line width
+ */
+int setlinewidth(wbp w, LONG linewid)
+ {
+ wcp wc = w->context;
+ wc->pen.lopnWidth.x = wc->pen.lopnWidth.y =
+ wc->bgpen.lopnWidth.x = wc->bgpen.lopnWidth.y = linewid;
+ return Succeeded;
+ }
+
+
+/*
+ * Set the foreground to draw in a mutable color
+ */
+int isetfg(wbp w, int i)
+ {
+ char tmp[20];
+ wcp wc = w->context;
+ if (-i > numColors) return Failed;
+ wc->fg = (0x01000000L | -i);
+ sprintf(tmp, "%ld", -i);
+ if (wc->fgname != NULL) free(wc->fgname);
+ wc->fgname = salloc(tmp);
+ wc->pen.lopnColor = wc->fg;
+ wc->brush.lbStyle = BS_SOLID;
+ wc->brush.lbColor = wc->fg;
+ return Succeeded;
+ }
+
+/*
+ * Set the context's background color by color cell.
+ */
+int isetbg(w, i)
+wbp w;
+int i;
+ {
+ char tmp[20];
+ wcp wc = w->context;
+ if (-i > numColors) return Failed;
+ wc->bg = (0x01000000L | -i);
+ sprintf(tmp, "%ld", -i);
+ if (wc->bgname != NULL) free(wc->bgname);
+ wc->bgname = salloc(tmp);
+ wc->bgpen.lopnColor = wc->bg;
+ wc->bgbrush.lbStyle = BS_SOLID;
+ wc->bgbrush.lbColor = wc->bg;
+ return ISXORREVERSE(w) ? resetfg(w) : Succeeded;
+ }
+
+
+int getdepthDC(HDC dc)
+{
+ return GetDeviceCaps(dc, BITSPIXEL) * GetDeviceCaps(dc, PLANES);
+}
+
+int getdepth(wbp w)
+{
+ int i, j;
+ STDLOCALS(w);
+ i = GetDeviceCaps(pixdc, BITSPIXEL);
+ j = GetDeviceCaps(pixdc, PLANES);
+ FREE_STDLOCALS(w);
+ return i * j;
+}
+
+int devicecaps(wbp w, int i)
+{
+ int rv;
+ STDLOCALS(w);
+ rv = GetDeviceCaps(pixdc, i);
+ FREE_STDLOCALS(w);
+ return rv;
+}
+
+/*
+ * Reset the context's foreground color to whatever it is supposed to be.
+ */
+int resetfg(w)
+wbp w;
+ {
+ return setfg(w, w->context->fgname);
+ }
+
+int alc_rgb(wbp w, SysColor rgb)
+{
+ int i;
+ wsp ws = w->window;
+ HDC hdc;
+ PALETTEENTRY pe;
+ LOGPALETTE lp;
+ if (palette) {
+ for (i=0; i < numColors; i++) {
+ if (rgb == scp[i].c && scp[i].type == SHARED) break;
+ }
+ if (i == numColors) {
+ numColors++;
+ if (ResizePalette(palette, numColors) == 0) {
+ numColors--;
+ return Failed;
+ }
+ scp = realloc(scp, numColors * sizeof(struct wcolor));
+ if (scp == NULL) { numColors--; return Failed; }
+ scp[numColors - 1].c = rgb;
+ scp[numColors - 1].type = SHARED;
+ sprintf(scp[numColors - 1].name, "%d,%d,%d",
+ RED(rgb), GREEN(rgb), BLUE(rgb));
+ lp.palNumEntries = 1;
+ lp.palVersion = 0x300;
+ lp.palPalEntry[0].peFlags = 0;
+ lp.palPalEntry[0].peRed = RED(rgb);
+ lp.palPalEntry[0].peGreen = GREEN(rgb);
+ lp.palPalEntry[0].peBlue = BLUE(rgb);
+ SetPaletteEntries(palette, numColors - 1, 1, lp.palPalEntry);
+ hdc = GetDC(ws->iconwin);
+ SelectPalette(hdc, palette, FALSE);
+ RealizePalette(hdc);
+ ReleaseDC(ws->iconwin, hdc);
+ }
+ }
+ return Succeeded;
+}
+
+/*
+ * Retrieve next message, returning 0 if WM_QUIT, -1 if there is an error.
+ */
+int check_and_get_msg( MSG *pMsg )
+{
+ BOOL result;
+ if ((result = GetMessage(pMsg, NULL, 0, 0)) <= 0)
+ {
+ return (result < 0) ? -1 : 0;
+ }
+ return 1;
+}
+
+/*
+ * Set the context's foreground color
+ */
+int setfg(wbp w, char *val)
+ {
+ long r, g, b;
+ wcp wc = w->context;
+ if (parsecolor(w, val, &r, &g, &b) == Succeeded) {
+ wc->fg = mscolor(w, r, g, b);
+ if (alc_rgb(w, wc->fg) == Failed) return Failed;
+ if (!wc->fgname) wc->fgname = salloc(val);
+ else if (strcmp(wc->fgname, val)) {
+ free(wc->fgname);
+ wc->fgname = salloc(val);
+ }
+ wc->brush.lbColor =
+ PALCLR(ISXORREVERSE(w) ? ((wc->fg ^ wc->bg) & 0x00FFFFFF) : wc->fg);
+ wc->pen.lopnColor = wc->brush.lbColor;
+ wc->brush.lbStyle = wc->fillstyle;
+ if (wc->fillstyle == BS_PATTERN)
+ wc->brush.lbHatch = (LONG)wc->pattern;
+ return Succeeded;
+ }
+ return Failed;
+ }
+
+/*
+ * Set the window context's background color
+ */
+int setbg(wbp w, char *val)
+ {
+ long r, g, b;
+ wcp wc = w->context;
+ if (parsecolor(w, val, &r, &g, &b) == Succeeded) {
+ wc->bg = mscolor(w, r, g, b);
+ if (alc_rgb(w, wc->bg) == Failed) return Failed;
+ if (!wc->bgname) wc->bgname = salloc(val);
+ else if (strcmp(wc->bgname, val)) {
+ free(wc->bgname);
+ wc->bgname = salloc(val);
+ }
+ wc->bgpen.lopnColor = PALCLR(wc->bg);
+ wc->bgbrush.lbStyle = BS_SOLID;
+ wc->bgbrush.lbColor = PALCLR(wc->bg);
+ return ISXORREVERSE(w) ? resetfg(w) : Succeeded;
+ }
+ return Failed;
+ }
+
+/*
+ * Set the gamma correction factor.
+ */
+int setgamma(w, gamma)
+wbp w;
+double gamma;
+ {
+ wcp wc = w->context;
+ wc->gamma = gamma;
+ setfg(w, wc->fgname);
+ setbg(w, wc->bgname);
+ return Succeeded;
+ }
+
+/*
+ * setpointer() - define a mouse pointer shape
+ */
+int setpointer(w, val)
+wbp w;
+char *val;
+ {
+ HCURSOR c;
+ char *cval;
+ if (!strcmp(val,"arrow")) cval = IDC_ARROW;
+ else if (!strcmp(val,"cross")) cval = IDC_CROSS;
+ else if (!strcmp(val,"ibeam")) cval = IDC_IBEAM;
+ else if (!strcmp(val,"uparrow")) cval = IDC_UPARROW;
+ else if (!strcmp(val,"wait")) cval = IDC_WAIT;
+ else if (!strcmp(val,"starting")) cval = IDC_APPSTARTING;
+ else if (!strcmp(val,"icon")) cval = IDC_ICON;
+ else if (!strcmp(val,"size")) cval = IDC_SIZE;
+ else if (!strcmp(val,"sizenesw")) cval = IDC_SIZENESW;
+ else if (!strcmp(val,"sizens")) cval = IDC_SIZENS;
+ else if (!strcmp(val,"sizenwse")) cval = IDC_SIZENWSE;
+ else if (!strcmp(val,"sizewe")) cval = IDC_SIZEWE;
+ else if (!strcmp(val,"no")) cval = IDC_NO;
+ else {
+ return Failed;
+ }
+ c = LoadCursor(NULL, cval);
+ if (c == NULL) {
+ return Failed;
+ }
+ w->window->curcursor = c;
+ if (w->window->cursorname) free(w->window->cursorname);
+ w->window->cursorname = salloc(val);
+ if (! w->window->savedcursor)
+ w->window->savedcursor = SetCursor(c);
+ else (void) SetCursor(c);
+ /* should restore savedcursor when pointer moves outside our window */
+ return Succeeded;
+ }
+
+/*
+ * setdrawop() - set the drawing operation
+ */
+int setdrawop(w, val)
+wbp w;
+char *val;
+ {
+ wcp wc = w->context;
+ if (!strcmp(val,"reverse")) {
+ if (!ISXORREVERSE(w)) {
+ SETXORREVERSE(w);
+ wc->drawop = R2_XORPEN;
+ resetfg(w);
+ }
+ }
+ else {
+ if (ISXORREVERSE(w)) {
+ CLRXORREVERSE(w);
+ resetfg(w);
+ }
+ wc->drawop = si_s2i(drawops,val);
+ if (wc->drawop == -1) { wc->drawop = R2_COPYPEN; return Error; }
+ }
+ return Succeeded;
+ }
+
+setdisplay(wbp w, char *val)
+ {
+ if (strcmp(val, "MS Windows"))
+ return Failed;
+ return Succeeded;
+ }
+
+setimage(wbp w, char *val)
+ {
+ wsp ws = w->window;
+ int status;
+ ws->initialPix = loadimage(w, val, &(ws->width), &(ws->height),
+ 0, &status);
+ if (ws->initialPix == (HBITMAP) NULL) return Failed;
+ return Succeeded;
+ }
+
+setleading(w, i)
+wbp w;
+int i;
+ {
+ wcp wc = w->context;
+ wc->leading = i;
+ }
+
+void toggle_fgbg(w)
+wbp w;
+ {
+ SysColor tmp;
+ LOGPEN tpen;
+ LOGBRUSH tbrush;
+ wcp wc = w->context;
+ tmp = wc->fg;
+ wc->fg = wc->bg;
+ wc->bg = tmp;
+ tpen = wc->pen;
+ wc->pen = wc->bgpen;
+ wc->bgpen = tpen;
+ tbrush = wc->brush;
+ wc->brush = wc->bgbrush;
+ wc->bgbrush = tbrush;
+ }
+
+int getvisual(w, answer)
+wbp w;
+char *answer;
+ {
+ return Failed;
+ }
+
+/*
+ * getpos() - update the window state's notion of its current position
+ */
+int getpos(w)
+wbp w;
+ {
+ return Succeeded;
+ }
+
+void getfg(w, answer)
+wbp w;
+char *answer;
+ {
+ strcpy(answer, w->context->fgname);
+ }
+
+void getbg(w, answer)
+wbp w;
+char *answer;
+ {
+ strcpy(answer, w->context->bgname);
+ }
+
+void getlinestyle(w, answer)
+wbp w;
+char *answer;
+ {
+ wcp wc = w->context;
+ char *ptr = si_i2s(siLineTypes, wc->pen.lopnStyle);
+ if (ptr != NULL) {
+ strcpy(answer, ptr);
+ }
+ else strcpy(answer, "unknown");
+ }
+
+void getfntnam(w, answer)
+wbp w;
+char *answer;
+ {
+ strcpy(answer, w->context->font->name);
+ }
+
+void getpointername(w, answer)
+wbp w;
+char *answer;
+ {
+ char *s;
+ wsp ws = w->window;
+ strcpy(answer, w->window->cursorname);
+ }
+
+void getdisplay(wbp w, char *answer)
+ {
+ strcpy(answer, "MS Windows");
+ }
+
+void getdrawop(w, answer)
+wbp w;
+char *answer;
+ {
+ char *s;
+ if (ISXORREVERSE(w)) s = "reverse";
+ else s = si_i2s(drawops, w->context->drawop);
+ if (s) sprintf(answer, "%s", s);
+ else strcpy(answer, "unknown");
+ }
+
+void geticonic(w, answer)
+wbp w;
+char *answer;
+ {
+ getcanvas(w, answer);
+ }
+
+void getcanvas(w, answer)
+wbp w;
+char *answer;
+ {
+ wsp ws = w->window;
+ if (ws->iconwin) {
+ if (!IsWindowVisible(ws->iconwin)) sprintf(answer, "hidden");
+ else if (IsIconic(ws->iconwin)) sprintf(answer, "iconic");
+ else if (IsZoomed(ws->iconwin)) sprintf(answer, "maximal");
+ else sprintf(answer,"normal");
+ }
+ else sprintf(answer,"hidden");
+ }
+
+int geticonpos(w, val)
+wbp w;
+char *val;
+ {
+ return Failed;
+ }
+
+/*
+ * erase an area
+ */
+void eraseArea(w,x,y,width,height)
+wbp w;
+int x, y, width, height;
+ {
+ HBRUSH hb, oldbrush, oldbrush2;
+ XRectangle rect;
+ STDLOCALS(w);
+ hb = CreateBrushIndirect(&(wc->bgbrush));
+ if (stdwin) oldbrush = SelectObject(stddc, hb);
+ oldbrush2 = SelectObject(pixdc, hb);
+ rect.left = x; rect.right = x + width;
+ rect.top = y; rect.bottom = y + height;
+
+ if (stdwin) FillRect(stddc, &rect, hb);
+ FillRect(pixdc, &rect, hb);
+ if (stdwin) SelectObject(stddc, oldbrush);
+ SelectObject(pixdc, oldbrush2);
+ DeleteObject(hb);
+ FREE_STDLOCALS(w);
+ }
+
+/*
+ * copy an area
+ */
+int copyArea(w,w2,x,y,width,height,x2,y2)
+wbp w, w2;
+int x, y, width, height, x2, y2;
+ {
+ int lpad, rpad, tpad, bpad;
+ RECT r;
+ HDC srcdc, srcpixdc;
+ HBRUSH hb;
+ wsp ws1 = w->window;
+ HBITMAP oldpix;
+ STDLOCALS(w2);
+ /*
+ * setup device contexts for area copy
+ */
+ SetROP2(pixdc, R2_COPYPEN);
+ hb = CreateBrushIndirect(&(wc->bgbrush));
+ if (stdwin)
+ SetROP2(stddc, R2_COPYPEN);
+ if (w2->window == w->window) {
+ srcdc = pixdc;
+ srcpixdc = pixdc;
+ }
+ else {
+ srcdc = GetDC(w->window->iconwin);
+ srcpixdc = CreateCompatibleDC(srcdc);
+ SetROP2(srcpixdc, R2_COPYPEN);
+ }
+ oldpix = SelectObject(srcpixdc, w->window->pix);
+
+ /*
+ * copy area, write unavailable areas with bg color
+ */
+ if (x + width < 0 || y + height < 0 || x >= ws1->pixwidth || y >= ws1->pixheight) {
+ /* source is entirely offscreen, just fill with background */
+ r.left = x2; r.top = y2;
+ r.right = x2 + width; r.bottom = y2 + height;
+ if (stdwin)
+ FillRect(stddc, &r, hb);
+ FillRect(pixdc, &r, hb);
+ }
+ else {
+ /*
+ * Check for source partially offscreen, but copy first and
+ * fill later in case the source and destination overlap.
+ */
+ lpad = rpad = tpad = bpad = 0;
+ if (x < 0) { /* source extends past left edge */
+ lpad = -x;
+ width -= lpad;
+ x2 += lpad;
+ x = 0;
+ }
+ if (x + width > ws1->pixwidth) { /* source extends past right edge */
+ rpad = x + width - ws1->pixwidth;
+ width -= rpad;
+ }
+ if (y < 0) { /* source extends above top edge */
+ tpad = -y;
+ height -= tpad;
+ y2 += tpad;
+ y = 0;
+ }
+ if (y + height > ws1->pixheight) { /* source extends below bottom */
+ bpad = y + height - ws1->pixheight;
+ height -= bpad;
+ }
+ if (stdwin)
+ BitBlt(stddc, x2, y2, width, height, srcpixdc, x, y, SRCCOPY);
+ BitBlt(pixdc, x2, y2, width, height, srcpixdc, x, y, SRCCOPY);
+
+ if (lpad > 0) {
+ r.left = x2-lpad;
+ r.top = y2-tpad;
+ r.right = r.left + lpad;
+ r.bottom = r.top + tpad+height+bpad;
+ if (stdwin)
+ FillRect(stddc, &r, hb);
+ FillRect(pixdc, &r, hb);
+ }
+ if (rpad > 0) {
+ r.left = x2+width;
+ r.top = y2-tpad;
+ r.right = r.left + rpad;
+ r.bottom = r.top + tpad+height+bpad;
+ if (stdwin)
+ FillRect(stddc, &r, hb);
+ FillRect(pixdc, &r, hb);
+ }
+ if (tpad > 0) {
+ r.left = x2;
+ r.top = y2-tpad;
+ r.right = r.left + width;
+ r.bottom = r.top + tpad;
+ if (stdwin)
+ FillRect(stddc, &r, hb);
+ FillRect(pixdc, &r, hb);
+ }
+ if (bpad > 0) {
+ r.left = x2;
+ r.top = y2+height;
+ r.right = r.left + width;
+ r.bottom = r.top + bpad;
+ if (stdwin)
+ FillRect(stddc, &r, hb);
+ FillRect(pixdc, &r, hb);
+ }
+ }
+
+ /*
+ * free resources
+ */
+ SelectObject(srcpixdc, oldpix);
+ if (w2->window != w->window) {
+ ReleaseDC(w->window->iconwin, srcdc);
+ DeleteDC(srcpixdc);
+ }
+ DeleteObject(hb);
+ FREE_STDLOCALS(w2);
+ return Succeeded;
+ }
+
+int getdefault(w, prog, opt, answer)
+wbp w;
+char *prog, *opt, *answer;
+ {
+ return Failed;
+ }
+
+/*
+ * Draw a bilevel image.
+ */
+int blimage(w, x, y, width, height, ch, s, len)
+wbp w;
+int x, y, width, height, ch;
+unsigned char *s;
+word len;
+ {
+ unsigned int m, msk1, c, ix, iy;
+ long fg, bg;
+ SysColor palfg, palbg;
+ STDLOCALS(w);
+ palfg = PALCLR(wc->fg);
+ palbg = PALCLR(wc->bg);
+ /*
+ * Read the image string and set the pixel values. Note that
+ * the hex digits in sequence fill the rows *right to left*.
+ */
+ m = width % 4;
+ if (m == 0)
+ msk1 = 8;
+ else
+ msk1 = 1 << (m - 1); /* mask for first byte of row */
+
+ fg = wc->fg;
+ bg = wc->bg;
+ ix = width;
+ iy = 0;
+ m = msk1;
+ while (len--) {
+ if (isxdigit(c = *s++)) { /* if hexadecimal character */
+ if (!isdigit(c)) /* fix bottom 4 bits if necessary */
+ c += 9;
+ while (m > 0) { /* set (usually) 4 pixel values */
+ --ix;
+ if (c & m) {
+ SetPixel(pixdc, ix, iy, palfg);
+ }
+ else if (ch != TCH1) { /* if zeroes aren't transparent */
+ SetPixel(pixdc, ix, iy, palbg);
+ }
+ m >>= 1;
+ }
+ if (ix == 0) { /* if end of row */
+ ix = width;
+ iy++;
+ m = msk1;
+ }
+ else
+ m = 8;
+ }
+ }
+ if (ix > 0) /* pad final row if incomplete */
+ while (ix < width)
+ SetPixel(pixdc, ix++, iy, palbg);
+
+ /*
+ * Put it on the screen.
+ */
+ if (ws->win)
+ BitBlt(stddc, x, y, width, height, pixdc, x, y, SRCCOPY);
+ FREE_STDLOCALS(w);
+ return Succeeded;
+ }
+
+/*
+ * Draw a character-per-pixel image.
+ */
+int strimage(w, x, y, width, height, e, s, len, on_icon)
+wbp w;
+int x, y, width, height;
+struct palentry *e;
+unsigned char *s;
+word len;
+int on_icon;
+ {
+ HDC tempdc;
+ HBITMAP temppix;
+ register int c;
+ register unsigned int ix;
+ int v, anytransparent=0;
+ unsigned int iy, tmpw;
+ SysColor clrlist[256], xc, palbg;
+ char tmp[24];
+ BITMAPINFO *bmi;
+ BITMAPINFOHEADER *bmih = &(bmi->bmiHeader);
+ HBITMAP oldpix = 0;
+ STDLOCALS(w);
+
+ bmi = malloc(sizeof(BITMAPINFO) + 256 * sizeof(SysColor));
+ if (bmi == NULL) {
+ FREE_STDLOCALS(w);
+ return -1;
+ }
+
+ bmih = &(bmi->bmiHeader);
+ palbg = PALCLR(wc->bg);
+ if (on_icon) {
+ free(bmi);
+ FREE_STDLOCALS(w);
+ return -1;
+ }
+
+ bmih->biClrImportant = 0;
+ /*
+ * Build arrays of colors in SysColor and RGBQUAD format for use by
+ * either SetPixel or DIB. Decide which to use based on whether
+ * there are any transparent pixels
+ */
+ for (c = 0; c < 256; c++) {
+ if (e[c].transpt) anytransparent++;
+ if (e[c].used && e[c].valid) {
+ bmih->biClrImportant++;
+ clrlist[c] = mscolor(w, e[c].clr.red, e[c].clr.green, e[c].clr.blue);
+ bmi->bmiColors[c].rgbBlue = BLUE(clrlist[c]);
+ bmi->bmiColors[c].rgbRed = RED(clrlist[c]);
+ bmi->bmiColors[c].rgbGreen = GREEN(clrlist[c]);
+ if (alc_rgb(w, clrlist[c]) == Failed) {
+ free(bmi);
+ FREE_STDLOCALS(w);
+ return -1;
+ }
+ clrlist[c] = PALCLR(clrlist[c]);
+ }
+ else {
+ bmi->bmiColors[c].rgbBlue = BLUE(wc->bg);
+ bmi->bmiColors[c].rgbRed = RED(wc->bg);
+ bmi->bmiColors[c].rgbGreen = GREEN(wc->bg);
+ }
+ }
+
+ /*
+ * if transparent characters are not present, blast out a DIB.
+ */
+ if (anytransparent == 0) {
+ char *buf = malloc(height * (width+4)), *buf2;
+ buf2 = buf;
+ bmih->biSize = sizeof(BITMAPINFOHEADER);
+ bmih->biWidth = width;
+ bmih->biHeight = -height;
+ bmih->biPlanes = 1;
+ bmih->biBitCount = 8;
+ bmih->biCompression = BI_RGB;
+ bmih->biSizeImage = 0;
+ bmih->biXPelsPerMeter = 0;
+ bmih->biYPelsPerMeter = 0;
+ bmih->biClrUsed = 256;
+
+ ix = 0;
+ while (len--) {
+ *buf++ = *s++;
+ if (++ix >= width) {
+ while(ix % 4) {
+ buf++;
+ ix++;
+ }
+ ix = 0;
+ }
+ }
+ temppix=CreateDIBitmap(pixdc, bmih, CBM_INIT, buf2, bmi, DIB_RGB_COLORS);
+ free(buf2);
+ tempdc = CreateCompatibleDC(stddc);
+ oldpix = SelectObject(tempdc, temppix);
+ BitBlt(pixdc, x, y, width, height, tempdc, 0, 0, SRCCOPY);
+ SelectObject(tempdc, oldpix);
+ DeleteDC(tempdc);
+ DeleteObject(temppix);
+ }
+ else {
+ /*
+ * The image contains some transparent pixels.
+ * Read the image string and set the pixel values.
+ * Note that SetPixelV() fails under Win32s; so we don't use it.
+ */
+ ix = x;
+ iy = y;
+ tmpw = x + width;
+ while (len--) {
+ c = *s++;
+ v = e[c].valid;
+ if (v) { /* put char if valid */
+ xc = SetPixel(pixdc, ix, iy, clrlist[c]);
+ }
+ if (v || e[c].transpt) { /* advance if valid or transparent */
+ if (++ix >= tmpw) {
+ ix = x; /* reset for new row */
+ iy++;
+ }
+ }
+ }
+ if (ix > 0) /* pad final row if incomplete */
+ while (ix < width)
+ SetPixel(pixdc, x+ix++, y+iy, palbg);
+ }
+
+ free(bmi);
+ /*
+ * Copy it from the pixmap onto the screen.
+ */
+ if (on_icon) {
+ FREE_STDLOCALS(w);
+ return -1;
+ }
+ else {
+ if (ws->win)
+ BitBlt(stddc, x, y, width, height, pixdc, x, y, SRCCOPY);
+ }
+ FREE_STDLOCALS(w);
+ return 0;
+ }
+
+/*
+ * imqsearch(key,base,nel) - binary search hardwired for images
+ *
+ * A binary search routine with arguments similar to qsort(3).
+ * Returns a pointer to the item matching "key", or NULL if none.
+ * This is called a LOT, so it is hardwired for speed.
+ * Based on Bentley, CACM 28,7 (July, 1985), p. 676.
+ */
+
+SysColor * imqsearch (SysColor key, SysColor *base, int nel)
+{
+ int l, u, m;
+ SysColor * a;
+
+ l = 0;
+ u = nel - 1;
+ while (l <= u) {
+ m = (l + u) / 2;
+ a = base + m;
+ if (*a < key)
+ l = m + 1;
+ else if (*a > key)
+ u = m - 1;
+ else
+ return a;
+ }
+ while (a>base && key < *a) a--;
+ while (a<base+nel && key > *a) a++;
+ return a;
+}
+
+/*
+ * capture -- get an image region.
+ *
+ * Stores the specified subimage in data as 15-bit color.
+ */
+int capture(w, xx, yy, width, height, data)
+wbp w;
+int xx, yy, width, height;
+short *data;
+ {
+ SysColor px;
+ int r, g, b, x, y;
+ int wd = xx + width;
+ int ht = yy + height;
+ STDLOCALS(w);
+
+ for (y = yy; y < ht; y++) {
+ for (x = xx; x < wd; x++) {
+ px = GetPixel(pixdc, x, y);
+ r = RED(px) >> 3;
+ g = GREEN(px) >> 3;
+ b = BLUE(px) >> 3;
+ *data++ = (r << 10) | (g << 5) | b;
+ }
+ }
+ FREE_STDLOCALS(w);
+ return 1;
+ }
+
+int readimage(w, filename, x, y, status)
+wbp w;
+char *filename;
+int x, y, *status;
+ {
+ HBITMAP p, oldpix;
+ unsigned int width, height;
+ HDC srcdc, srcpixdc;
+
+ if (!x && !y)
+ p = loadimage(w, filename, &width, &height, 1, status);
+ else
+ p = loadimage(w, filename, &width, &height, 0, status);
+
+ if (p == (HBITMAP) NULL) {
+ return Failed;
+ }
+
+ {
+ STDLOCALS(w);
+
+ srcdc = GetDC(ws->iconwin);
+ srcpixdc = CreateCompatibleDC(srcdc);
+ oldpix = SelectObject(srcpixdc, p);
+ BitBlt(pixdc, x, y, width, height, srcpixdc, 0, 0, SRCCOPY);
+ if (stdwin)
+ BitBlt(stddc, x, y, width, height, srcpixdc, 0, 0, SRCCOPY);
+ SelectObject(srcpixdc, oldpix);
+ ReleaseDC(ws->iconwin, srcdc);
+ DeleteDC(srcpixdc);
+
+ /*
+ * Make sure previous ops on p are complete, then free it.
+ */
+ DeleteObject(p);
+ FREE_STDLOCALS(w);
+ return Succeeded;
+ }
+ }
+
+
+
+/*
+ * Initialize client for producing pixels from a window, or in this case,
+ * only create a device context once, not once per getpixel.
+ */
+int getpixel_init(w, imem)
+wbp w;
+struct imgmem *imem;
+ {
+ COLORREF *p;
+ wsp ws = w->window;
+ int i, j, x2, y2;
+ HDC stddc = GetDC(ws->iconwin), pixdc = CreateCompatibleDC(stddc);
+ HBITMAP oldpix;
+
+ if (palette) SelectPalette(pixdc, palette, FALSE);
+ oldpix = SelectObject(pixdc, ws->pix);
+
+ /* this looks like a bug for Win16 for images > 100x100 or so... */
+ imem->crp = malloc( imem->width * imem->height * sizeof(COLORREF));
+ if (imem->crp == NULL) return Failed;
+ p = imem->crp;
+ x2 = imem->x + imem->width;
+ y2 = imem->y + imem->height;
+ for(i = imem->y; i < y2; i++)
+ for(j = imem->x; j < x2; j++) {
+ if ((*p++ = GetPixel(pixdc, j, i)) == (COLORREF)-1L) {
+ free(imem->crp);
+ SelectObject(pixdc, oldpix);
+ FREE_STDLOCALS(w);
+ return Failed;
+ }
+ }
+ SelectObject(pixdc, oldpix);
+ FREE_STDLOCALS(w);
+ return Succeeded;
+ }
+
+int getpixel_term(w, imem)
+wbp w;
+struct imgmem *imem;
+{
+ free(imem->crp);
+ return Succeeded;
+}
+
+/*
+ * Return pixel (x,y) from a window
+ */
+int getpixel(wbp w, int x, int y, long *rv, char *s, struct imgmem *imem)
+ {
+ COLORREF cr = imem->crp[(y-imem->y) * imem->width + (x-imem->x)];
+ *rv = 1;
+ sprintf(s, "%ld,%ld,%ld",
+ (long)RED(cr)*257L, (long)GREEN(cr)*257L, (long)BLUE(cr)*257L);
+ return Succeeded;
+ }
+
+int query_pointer(w, pp)
+wbp w;
+XPoint *pp;
+ {
+ wsp ws = w->window;
+ RECT r;
+ if (ws->win) {
+ GetCursorPos(pp);
+ GetWindowRect(ws->win, &r);
+ pp->x -= r.left;
+ pp->y -= r.top;
+ return Succeeded;
+ }
+ return Failed;
+ }
+
+int query_rootpointer(pp)
+XPoint *pp;
+ {
+ GetCursorPos(pp);
+ return Succeeded;
+ }
+
+int seticonimage(w, dp)
+wbp w;
+dptr dp;
+ {
+ wsp ws = w->window;
+ return Succeeded;
+ }
+
+/*
+ * dumpimage -- write an image to a disk file. Return 0 on failure.
+ */
+int dumpimage(wbp w, char *filename, unsigned int x, unsigned int y,
+ unsigned int width, unsigned int height)
+ {
+ int result = 0;
+ HDIB dib;
+ HDC destdc;
+ HBITMAP dumppix, oldpix;
+ STDLOCALS(w);
+
+ if (strcmp(".bmp", filename + strlen(filename) - 4) &&
+ strcmp(".BMP", filename + strlen(filename) - 4)) {
+ FREE_STDLOCALS(w);
+ return NoCvt;
+ }
+
+ /*
+ * extract the desired rectangle from the source bitmap
+ */
+ if (x || y || width != ws->pixwidth || height != ws->pixheight) {
+ dumppix = CreateCompatibleBitmap(stddc, width, height);
+ destdc = CreateCompatibleDC(stddc);
+ oldpix = SelectObject(destdc, dumppix);
+ BitBlt(destdc, 0, 0, width, height, pixdc, x, y, SRCCOPY);
+ }
+ else dumppix = ws->pix;
+ dib = BitmapToDIB(dumppix, palette);
+ if (dumppix != ws->pix) {
+ SelectObject(destdc, oldpix);
+ DeleteDC(destdc);
+ DeleteObject(dumppix);
+ }
+
+ if (dib == NULL) {
+ result = Failed;
+ }
+ else {
+ if (result = SaveDIB(dib, filename)) { /* != 0 implies error */
+ result = Failed;
+ }
+ else {
+ result = Succeeded;
+ }
+ DestroyDIB(dib);
+ }
+
+ FREE_STDLOCALS(w);
+ return result;
+ }
+
+
+/*
+ * loadimage
+ */
+HBITMAP loadimage(wbp w, char *filename, unsigned int *width,
+ unsigned int *height, int atorigin, int *status)
+ {
+ HDC hdc;
+ HDIB dib;
+ HBITMAP bmap;
+ HPALETTE p2;
+ PALETTEENTRY pe;
+ LPBITMAPINFO lpbmi;
+ int j;
+ int ii,jj, kk;
+ int xx[256];
+ unsigned char * pd;
+ char *j2;
+
+ dib = LoadDIB(filename);
+ if (dib != NULL) {
+ LPSTR pdib;
+ p2 = CreateDIBPalette(dib);
+ j2 = GlobalLock(dib);
+ j = DIBNumColors(j2);
+ jj = DIBWidth(j2);
+ kk = DIBHeight(j2);
+ GlobalUnlock(dib);
+
+ if (!palette) {
+ LOGPALETTE logpal[4]; /* (1, + space for an extra palette entry) */
+ hdc = GetDC(w->window->iconwin);
+ if ((GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE) && (numColors ==0)){
+ /* This window is on a device that supports palettes */
+ numColors = 2;
+ logpal[0].palNumEntries = 2;
+ logpal[0].palVersion = 0x300;
+ logpal[0].palPalEntry[0].peFlags = 0;
+ logpal[0].palPalEntry[0].peRed = 0;
+ logpal[0].palPalEntry[0].peGreen = 0;
+ logpal[0].palPalEntry[0].peBlue = 0;
+ logpal[0].palPalEntry[1].peFlags = 0;
+ logpal[0].palPalEntry[1].peRed = 255;
+ logpal[0].palPalEntry[1].peGreen = 255;
+ logpal[0].palPalEntry[1].peBlue = 255;
+ palette = CreatePalette(logpal);
+ if (!palette) {
+ return NULL;
+ }
+ if ((scp = malloc(2 * sizeof (struct wcolor))) == NULL)
+ return NULL;
+ scp[0].c = RGB(0,0,0);
+ scp[0].type = SHARED;
+ strcpy(scp[0].name, "black");
+ scp[1].c = RGB(255,255,255);
+ scp[1].type = SHARED;
+ strcpy(scp[1].name, "white");
+ }
+ else {
+ /* this window is not on a device that supports palettes */
+ }
+ ReleaseDC(w->window->iconwin, hdc);
+ }
+ if (palette) {
+ if (ResizePalette(palette, numColors + j) == 0) {
+ return NULL;
+ }
+ for (ii = 0; ii < j; ii++) {
+ if (GetPaletteEntries(p2, ii, 1, &pe) == 0) {
+ return NULL;
+ }
+ SetPaletteEntries(palette, numColors++, 1, &pe);
+ }
+ }
+ bmap = DIBToBitmap(dib, palette);
+ pdib = GlobalLock(dib);
+ *width = DIBWidth(pdib);
+ *height = DIBHeight(pdib);
+ GlobalUnlock(dib);
+ DestroyDIB(dib);
+ DeleteObject(p2);
+ *status = 0;
+ return bmap;
+ }
+ return NULL;
+ }
+
+
+char *get_mutable_name(wbp w, int mute_index)
+ {
+ char *tmp;
+ PALETTEENTRY pe;
+
+ if (-mute_index > numColors || scp[-mute_index].type != MUTABLE) {
+ return NULL;
+ }
+
+ if (GetPaletteEntries(palette, -mute_index, 1, &pe) == 0) {
+ return NULL;
+ }
+ tmp = scp[-mute_index].name;
+ sprintf(tmp, "%d", mute_index);
+ sprintf(tmp + strlen(tmp) + 1, "%d,%d,%d",
+ (pe.peRed << 8) | 0xff, (pe.peGreen << 8) | 0xff, (pe.peBlue << 8) | 0xff);
+ return tmp + strlen(tmp) + 1;
+ }
+
+int set_mutable(wbp w, int i, char *s)
+ {
+ long r, g, b;
+ UINT rv;
+ PALETTEENTRY pe;
+ if (palette == 0) return Failed;
+
+ {
+ STDLOCALS(w);
+ if (parsecolor(w, s, &r, &g, &b) != Succeeded) {
+ FREE_STDLOCALS(w);
+ return Failed; /* invalid color specification */
+ }
+ pe.peRed = r >> 8;
+ pe.peGreen = g >> 8;
+ pe.peBlue = b >> 8;
+ pe.peFlags = PC_RESERVED;
+ raiseWindow(w); /* mutable won't mutate if window isn't active */
+#if 1
+ AnimatePalette(palette, -i, 1, &pe);
+ rv = SetPaletteEntries(palette, -i, 1, &pe);
+#endif
+ UnrealizeObject(palette);
+ RealizePalette(stddc);
+ AnimatePalette(palette, -i, 1, &pe);
+ FREE_STDLOCALS(w);
+}
+ return Succeeded;
+ }
+
+void free_mutable(wbp w, int mute_index)
+ {
+ }
+
+/*
+ * Allocate a mutable color
+ */
+int mutable_color(wbp w, dptr argv, int argc, int *retval)
+ {
+ long r, g, b;
+ tended char *str;
+ LOGPALETTE lp;
+ {
+ STDLOCALS(w);
+
+ if (!stddc || ((GetDeviceCaps(stddc, RASTERCAPS) & RC_PALETTE) == 0)) {
+ FREE_STDLOCALS(w);
+ return Failed;
+ }
+
+ numColors++;
+ scp = realloc(scp, numColors * sizeof(struct wcolor));
+ if (scp == NULL) {
+ FREE_STDLOCALS(w);
+ return Failed;
+ }
+ scp[numColors-1].c = -(numColors-1);
+ sprintf(scp[numColors-1].name, "%d:", -(numColors-1));
+ scp[numColors-1].type = MUTABLE;
+ if (ResizePalette(palette, numColors) == 0) {
+ FREE_STDLOCALS(w);
+ return Failed;
+ }
+
+ if (argc > 0) { /* set the color */
+ if (argc != 1) {
+ FREE_STDLOCALS(w);
+ return Error;
+ }
+ /*
+ * old-style check for C integer
+ */
+ else if (argv[0].dword == D_Integer) {/* check for color cell */
+ if (IntVal(argv[0]) >= 0) {
+ FREE_STDLOCALS(w);
+ return Failed; /* must be negative */
+ }
+ if (GetPaletteEntries(palette, -IntVal(argv[0]),
+ 1, lp.palPalEntry) == 0) {
+ FREE_STDLOCALS(w);
+ return Error;
+ }
+ /* convert to linear color? */
+ }
+ else {
+ if (!cnv:C_string(argv[0],str)) {
+ FREE_STDLOCALS(w);
+ ReturnErrVal(103,argv[0], Error);
+ }
+ if (parsecolor(w, str, &r, &g, &b) != Succeeded) {
+ /* reduce logical palette size and count */
+ FREE_STDLOCALS(w);
+ numColors--;
+ ResizePalette(palette, numColors);
+ return Failed; /* invalid color specification */
+ }
+ lp.palPalEntry[0].peRed = r >> 8;
+ lp.palPalEntry[0].peGreen = g >> 8;
+ lp.palPalEntry[0].peBlue = b >> 8;
+ }
+ lp.palNumEntries = 1;
+ lp.palVersion = 0x300;
+ lp.palPalEntry[0].peFlags = PC_RESERVED;
+ SetPaletteEntries(palette, numColors - 1, 1, lp.palPalEntry);
+ UnrealizeObject(palette);
+ RealizePalette(stddc);
+ }
+
+ *retval = -(numColors - 1);
+ FREE_STDLOCALS(w);
+ return Succeeded;
+ }
+ }
+
+void freecolor(wbp w, char *s)
+ {
+ }
+
+/*
+ * drawarcs() - assumes x and y are already fixed up for the bitmap
+ */
+void drawarcs(wbp wb, XArc *arcs, int narcs)
+ {
+ register XArc *arc = arcs;
+ int i, halfwidth, halfheight, x1, y1, x2, y2, right, bottom;
+ double a1_a2;
+ HPEN hp, oldpen, oldpen2;
+ STDLOCALS(wb);
+ hp = CreatePenIndirect(&(wc->pen));
+ if (stdwin) oldpen = SelectObject(stddc, hp);
+ oldpen2 = SelectObject(pixdc, hp);
+ for (i = 0; i < narcs; i++, arc++) {
+ halfwidth = arc->width >> 1;
+ halfheight = arc->height >> 1;
+ arc->angle1 = -arc->angle1 - arc->angle2;
+ a1_a2 = arc->angle1 + arc->angle2;
+ x1 = arc->x + halfwidth + (int)(halfwidth * cos(arc->angle1));
+ y1 = arc->y + halfheight - (int)(halfheight * sin(arc->angle1));
+ x2 = arc->x + halfwidth + (int)(halfwidth * cos(a1_a2));
+ y2 = arc->y + halfheight - (int)(halfheight * sin(a1_a2));
+ right = arc->x + arc->width + 1;
+ bottom = arc->y + arc->height + 1;
+ if (ws->win)
+ Arc(stddc, arc->x, arc->y, right, bottom, x1, y1, x2, y2);
+ Arc(pixdc, arc->x, arc->y, right, bottom, x1, y1, x2, y2);
+ }
+ if (stdwin) SelectObject(stddc, oldpen);
+ SelectObject(pixdc, oldpen2);
+ DeleteObject(hp);
+ FREE_STDLOCALS(wb);
+ return;
+ }
+
+
+/*
+ * drawlines - Support routine for DrawLine
+ */
+void drawlines(wbinding *wb, XPoint *points, int npoints)
+ {
+ int i, diff, bheight;
+ HPEN hp, oldpen, oldpen2;
+ XPoint tmp[2];
+ STDLOCALS(wb);
+ hp = CreatePenIndirect(&(wc->pen));
+ if (stdwin) oldpen = SelectObject(stddc, hp);
+ oldpen2 = SelectObject(pixdc, hp);
+ tmp[0] = points[npoints-1];
+ tmp[1] = points[npoints-2];
+ if (ws->win) {
+ SetBkMode(stddc, wc->bkmode);
+ Polyline(stddc, points, npoints);
+ Polyline(stddc, tmp, 2);
+ }
+ SetBkMode(pixdc, wc->bkmode);
+ Polyline(pixdc, points, npoints);
+ Polyline(pixdc, tmp, 2);
+ if (stdwin) SelectObject(stddc, oldpen);
+ SelectObject(pixdc, oldpen2);
+ DeleteObject(hp);
+ FREE_STDLOCALS(wb);
+ return;
+ }
+
+
+/*
+ * drawpoints() -
+ * Parameters - the window binding for output, an array of points (assumed
+ * to be fixed up for bitmap) and the number of points
+ */
+void drawpoints(wbinding *wb, XPoint *points, int npoints)
+ {
+ register XPoint *p, *endp;
+ SysColor palfg;
+ STDLOCALS(wb);
+ endp = points + npoints;
+ palfg = PALCLR(wc->fg);
+ if (stdwin) {
+ for(p = points; p < endp; p++) {
+ SetPixel(stddc, p->x, p->y, palfg);
+ SetPixel(pixdc, p->x, p->y, palfg);
+ }
+ }
+ else {
+ for(p = points; p < endp; p++) {
+ SetPixel(pixdc, p->x, p->y, palfg);
+ }
+ }
+ FREE_STDLOCALS(wb);
+ return;
+ }
+
+
+/*
+ * drawsegments() -
+ */
+void drawsegments(wbinding *wb, XSegment *segs, int nsegs)
+ {
+ int i, bheight;
+ XPoint ps[2];
+ HPEN hp, oldpen, oldpen2;
+ STDLOCALS(wb);
+ hp = CreatePenIndirect(&(wc->pen));
+ if (stdwin) oldpen = SelectObject(stddc, hp);
+ oldpen2 = SelectObject(pixdc, hp);
+ if (stdwin) {
+ SetBkMode(stddc, wc->bkmode);
+ for (i = 0; i < nsegs; i++) {
+ Polyline(stddc, (POINT *)(segs+i), 2);
+ }
+ }
+ SetBkMode(pixdc, wc->bkmode);
+ for (i = 0; i < nsegs; i++) {
+ Polyline(pixdc, (POINT *)(segs+i), 2);
+ }
+ if (stdwin) SelectObject(stddc, oldpen);
+ SelectObject(pixdc, oldpen2);
+ DeleteObject(hp);
+ FREE_STDLOCALS(wb);
+ return;
+ }
+
+
+int allowresize(w, on)
+wbp w;
+int on;
+ {
+ if (on)
+ SETRESIZABLE(w);
+ else
+ CLRRESIZABLE(w);
+ return Succeeded;
+ }
+int getselection(wbp w, char *buf)
+{
+ return Failed;
+ }
+int setselection(wbp w, char *val)
+{
+ return Failed;
+ }
+
+/*
+ * drawstrng()
+ */
+void drawstrng(wbinding *wb, int x, int y, char *s, int slen)
+ {
+ STDLOCALS(wb);
+
+ STDFONT;
+ if (stdwin) {
+ SetBkMode(stddc, TRANSPARENT);
+ if (wc->fg != RGB(0, 0, 0)) SetTextColor(stddc, PALCLR(wc->fg));
+ if (wc->bg != RGB(255, 255, 255)) SetBkColor(stddc, PALCLR(wc->bg));
+ TextOut(stddc, x, y - ASCENT(wb), s, slen);
+ }
+ SetBkMode(pixdc, TRANSPARENT);
+ if (wc->fg != RGB(0, 0, 0)) SetTextColor(pixdc, PALCLR(wc->fg));
+ if (wc->bg != RGB(255, 255, 255)) SetBkColor(pixdc, PALCLR(wc->bg));
+ TextOut(pixdc, x, y - ASCENT(wb), s, slen);
+
+ FREE_STDLOCALS(wb);
+ return;
+ }
+
+
+/*
+ * fillarcs
+ */
+void fillarcs(wbp wb, XArc *arcs, int narcs)
+ {
+ register XArc *arc = arcs;
+ int i, diff, bheight;
+ HBRUSH hb, oldbrush, oldbrush2;
+ POINT pts[3];
+ HPEN hp, oldpen, oldpen2;
+ STDLOCALS(wb);
+ hp = CreatePenIndirect(&(wc->pen));
+ if (stdwin) oldpen = SelectObject(stddc, hp);
+ oldpen2 = SelectObject(pixdc, hp);
+ hb = CreateBrushIndirect(&(wc->brush));
+ if (stdwin) oldbrush = SelectObject(stddc, hb);
+ oldbrush2 = SelectObject(pixdc, hb);
+ SetTextColor(pixdc, PALCLR(wc->fg));
+ if (stdwin) SetTextColor(stddc, PALCLR(wc->fg));
+ SetBkColor(pixdc, PALCLR(wc->bg));
+ if (stdwin) SetBkColor(stddc, PALCLR(wc->bg));
+ if (stdwin) SetBkMode(stddc, wc->bkmode);
+ SetBkMode(pixdc, wc->bkmode);
+ for (i = 0; i < narcs; i++, arc++) {
+ if (arc->angle2 >= 2 * Pi) {
+ /*
+ * from SDK reference: Ellipse() draws up to but not including
+ * the right and bottom coordinates. Add +1 to compensate.
+ */
+ if (stdwin)
+ Ellipse(stddc, arc->x, arc->y,
+ arc->x + arc->width + 1, arc->y + arc->height + 1);
+ Ellipse(pixdc, arc->x, arc->y,
+ arc->x + arc->width + 1, arc->y + arc->height + 1);
+ }
+ else {
+ arc->angle1 = -arc->angle1 - arc->angle2;
+ pts[0].x = arc->x + (arc->width>>1);
+ pts[0].y = arc->y + (arc->height>>1);
+ pts[1].x = arc->x + (arc->width>>1) +
+ (int)(((arc->width + 1)>>1) * cos(arc->angle1));
+ pts[1].y = arc->y + (arc->height>>1) -
+ (int)(((arc->height )>>1) * sin(arc->angle1));
+ pts[2].x = arc->x + (arc->width>> 1) +
+ (int)(((arc->width + 1)>>1) * cos(arc->angle1+arc->angle2));
+ pts[2].y = arc->y + (arc->height>>1) -
+ (int)(((arc->height )>>1) * sin(arc->angle1+arc->angle2));
+ if (stdwin) {
+ Pie(stddc, arc->x, arc->y,
+ arc->x + arc->width + 1, arc->y + arc->height + 1,
+ pts[1].x, pts[1].y, pts[2].x, pts[2].y);
+ }
+ Pie(pixdc, arc->x, arc->y,
+ arc->x + arc->width + 1, arc->y + arc->height + 1,
+ pts[1].x, pts[1].y, pts[2].x, pts[2].y);
+ }
+ }
+ if (stdwin) SelectObject(stddc, oldpen);
+ SelectObject(pixdc, oldpen2);
+ DeleteObject(hp);
+ if (stdwin) SelectObject(stddc, oldbrush);
+ SelectObject(pixdc, oldbrush2);
+ DeleteObject(hb);
+ FREE_STDLOCALS(wb);
+ return;
+ }
+
+/*
+ * fillrectangles
+ */
+void fillrectangles(wbp wb, XRectangle *recs, int nrecs)
+ {
+ int i, diff, bheight;
+ HBRUSH hb, oldbrush, oldbrush2;
+ HPEN hp, oldpen, oldpen2;
+ STDLOCALS(wb);
+ hp = CreatePenIndirect(&(wc->pen));
+ if (stdwin) oldpen = SelectObject(stddc, hp);
+ oldpen2 = SelectObject(pixdc, hp);
+ hb = CreateBrushIndirect(&(wc->brush));
+ if (stdwin) oldbrush = SelectObject(stddc, hb);
+ oldbrush2 = SelectObject(pixdc, hb);
+ SetTextColor(pixdc, PALCLR(wc->fg));
+ if (stdwin) SetTextColor(stddc, PALCLR(wc->fg));
+ SetBkColor(pixdc, PALCLR(wc->bg));
+ if (stdwin) SetBkColor(stddc, PALCLR(wc->bg));
+ if (stdwin) SetBkMode(stddc, wc->bkmode);
+ SetBkMode(pixdc, wc->bkmode);
+ for (i = 0; i < nrecs; i++) {
+ recs[i].right += recs[i].left;
+ recs[i].bottom += recs[i].top;
+ if (stdwin) FillRect(stddc, (recs+i), hb);
+ FillRect(pixdc, (recs+i), hb);
+ }
+ if (stdwin) SelectObject(stddc, oldpen);
+ SelectObject(pixdc, oldpen2);
+ DeleteObject(hp);
+ if (stdwin) SelectObject(stddc, oldbrush);
+ SelectObject(pixdc, oldbrush2);
+ DeleteObject(hb);
+ FREE_STDLOCALS(wb);
+ return;
+ }
+
+
+/*
+ * drawrectangles - draw nrecs # of rectangles in array recs to binding w
+ */
+void drawrectangles(wbp w, XRectangle *recs, int nrecs)
+ {
+ register XRectangle *r;
+ LOGBRUSH lb;
+ HBRUSH hb, oldbrush, oldbrush2;
+ HPEN hp, oldpen, oldpen2;
+ STDLOCALS(w);
+ hp = CreatePenIndirect(&(wc->pen));
+ if (stdwin) oldpen = SelectObject(stddc, hp);
+ oldpen2 = SelectObject(pixdc, hp);
+ lb.lbStyle = BS_NULL;
+ hb = CreateBrushIndirect(&lb);
+ if (stdwin) oldbrush = SelectObject(stddc, hb);
+ oldbrush2 = SelectObject(pixdc, hb);
+ for (r = recs; r < recs + nrecs; r++) {
+ /*
+ * from SDK reference: Rectangle() draws up to but not including
+ * the right and bottom coordinates. Add +1 to compensate.
+ */
+ r->right += r->left + 1;
+ r->bottom += r->top + 1;
+ if (stdwin) Rectangle(stddc, r->left, r->top, r->right, r->bottom);
+ Rectangle(pixdc, r->left, r->top, r->right, r->bottom);
+ }
+ if (stdwin) SelectObject(stddc, oldpen);
+ SelectObject(pixdc, oldpen2);
+ DeleteObject(hp);
+ if (stdwin) SelectObject(stddc, oldbrush);
+ SelectObject(pixdc, oldbrush2);
+ DeleteObject(hb);
+ FREE_STDLOCALS(w);
+ return;
+ }
+
+/*
+ * fillpolygon
+ */
+void fillpolygon(wbp w, XPoint *pts, int npts)
+ {
+ HBRUSH hb, oldbrush;
+ HPEN hp, oldpen, oldpen2;
+ STDLOCALS(w);
+ if (stdwin) SetBkMode(stddc, wc->bkmode);
+ SetBkMode(pixdc, wc->bkmode);
+ hp = CreatePenIndirect(&(wc->pen));
+ if (stdwin) oldpen = SelectObject(stddc, hp);
+ oldpen2 = SelectObject(pixdc, hp);
+ hb = CreateBrushIndirect(&(wc->brush));
+ if (stdwin) {
+ oldbrush = SelectObject(stddc, hb);
+ Polygon(stddc, pts, npts);
+ SelectObject(stddc, oldbrush);
+ }
+ oldbrush = SelectObject(pixdc, hb);
+ Polygon(pixdc, pts, npts);
+ SelectObject(pixdc, oldbrush);
+ DeleteObject(hb);
+ if (stdwin) SelectObject(stddc, oldpen);
+ SelectObject(pixdc, oldpen2);
+ DeleteObject(hp);
+ FREE_STDLOCALS(w);
+ }
+
+LONG NumWindows = 0;
+
+
+/*
+ * allocate a context. Can't be called until w has a display and window.
+ */
+wcp alc_context(w)
+wbp w;
+ {
+ int i;
+ wcp wc;
+
+ GRFX_ALLOC(wc, _wcontext);
+
+ wc->bkmode = OPAQUE; /* at present, only used in line drawing */
+ wc->fg = RGB(0,0,0);
+ wc->bg = RGB(255,255,255);
+ wc->fgname = salloc("black");
+ wc->bgname = salloc("white");
+ wc->pen.lopnStyle = PS_SOLID;
+ wc->pen.lopnWidth.x = wc->pen.lopnWidth.y = 1;
+ wc->pen.lopnColor = PALCLR(wc->fg);
+ wc->bgpen.lopnStyle = PS_SOLID;
+ wc->bgpen.lopnWidth.x = wc->bgpen.lopnWidth.y = 1;
+ wc->bgpen.lopnColor = PALCLR(wc->bg);
+ wc->fillstyle = BS_SOLID;
+ wc->brush.lbStyle = BS_SOLID;
+ wc->brush.lbColor = PALCLR(wc->fg);
+ wc->bgbrush.lbStyle = BS_SOLID;
+ wc->bgbrush.lbColor = PALCLR(wc->bg);
+ wc->gamma = GammaCorrection;
+ wc->drawop = R2_COPYPEN;
+ wc->font = (wfp)alloc(sizeof (struct _wfont));
+ wc->font->name = salloc("fixed");
+ wc->font->font = CreateFont(16,0,0,0,FW_NORMAL,0,0,0,
+ ((MAXBYTESPERCHAR==1)?ANSI_CHARSET:DEFAULT_CHARSET),
+ OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,
+ DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN,
+ getenv("ICONFONT"));
+
+ wc->font->charwidth = 8; /* looks like a bug */
+ wc->leading = 16;
+
+ GRFX_LINK(wc, wcntxts);
+ return wc;
+ }
+
+/*
+ * allocate a context, cloning attributes from an existing context
+ */
+wcp clone_context(w)
+wbp w;
+ {
+ wcp wc, wc2 = w->context;
+ wsp ws = w->window;
+ wbinding tmp;
+ int i;
+
+ GRFX_ALLOC(wc, _wcontext);
+
+ tmp.window = ws;
+ tmp.context = wc;
+ /*
+ * copy over some stuff
+ */
+ wc->clipx = wc2->clipx;
+ wc->clipy = wc2->clipy;
+ wc->clipw = wc2->clipw;
+ wc->cliph = wc2->cliph;
+ if (wc2->cliprgn)
+ wc->cliprgn = CreateRectRgn(wc->clipx,wc->clipy,
+ wc->clipx+wc->clipw,
+ wc->clipy+wc->cliph);
+ wc->dx = wc2->dx;
+ wc->dy = wc2->dy;
+ wc->bits = wc2->bits;
+ /*
+ * clone needs to make a copy of the pattern
+ * if (wc2->pattern) {
+ * wc->pattern = copy+somehow(wc2->pattern);
+ * if (wc2->patternname)
+ * wc->patternname = salloc(wc2->patternname);
+ * }
+ */
+
+ wc->bkmode = wc2->bkmode;
+ wc->fg = wc2->fg;
+ wc->bg = wc2->bg;
+ wc->fgname = salloc(wc2->fgname);
+ wc->bgname = salloc(wc2->bgname);
+ wc->pen = wc2->pen;
+ if (ISXORREVERSEW(wc)) {
+ wc->brush.lbColor = PALCLR((wc->fg ^ wc->bg) & 0x00FFFFFF);
+ }
+ else {
+ wc->brush.lbColor = PALCLR(wc->fg);
+ }
+ wc->bgpen = wc2->bgpen;
+ wc->fillstyle = wc2->fillstyle;
+ wc->brush.lbStyle = wc->fillstyle;
+ wc->bgbrush.lbStyle = wc->fillstyle;
+ wc->bgbrush.lbColor = PALCLR(wc->bg);
+ wc->gamma = wc2->gamma;
+ wc->drawop = wc2->drawop;
+ wc->font = (wfp)alloc(sizeof (struct _wfont));
+ wc->font->name = salloc("fixed");
+ wc->font->font = CreateFont(13,0,0,0,FW_NORMAL,0,0,0,
+ ((MAXBYTESPERCHAR==1)?ANSI_CHARSET:DEFAULT_CHARSET),
+ OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,
+ DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN,
+ getenv("ICONFONT"));
+ wc->leading = wc2->leading;
+ setfont(&tmp, &(wc2->font->name));
+
+ GRFX_LINK(wc, wcntxts);
+ return wc;
+ }
+
+/*
+ * allocate a window state structure
+ */
+wsp alc_winstate()
+ {
+ int i;
+ wsp ws;
+
+ GRFX_ALLOC(ws, _wstate);
+ ws->bits = 1024; /* echo ON; others OFF */
+ ws->filep = nulldesc;
+ ws->listp = nulldesc;
+ ws->cursorname = salloc("arrow");
+ ws->curcursor = LoadCursor(NULL, IDC_ARROW);
+ GRFX_LINK(ws, wstates);
+ return ws;
+ }
+
+/*
+ * free a window state
+ */
+int free_window(ws)
+wsp ws;
+ {
+ int i;
+ ws->refcount--;
+ if(ws->refcount == 0) {
+ if (ws->win) /* && IsWindowVisible(ws->win))*/
+ DestroyWindow(ws->win);
+/* ws->win = 0;*/
+ if (ws->iconwin && ws->iconwin != ws->win) {
+ if (IsWindowVisible(ws->iconwin))
+ DestroyWindow(ws->iconwin);
+ else DestroyWindow(ws->iconwin);
+ }
+/* ws->iconwin = 0;*/
+/* while (ws->win)
+ if (pollevent() == -1) return -1;
+*/
+ if (ws->windowlabel) free(ws->windowlabel);
+ if (ws->iconlabel) free(ws->iconlabel);
+ if (ws->pix)
+ DeleteObject(ws->pix);
+ ws->pix = 0;
+ if (ws->iconpix)
+ DeleteObject(ws->iconpix);
+ ws->iconpix = 0;
+ if (ws->initialPix)
+ DeleteObject(ws->initialPix);
+ ws->initialPix = 0;
+ /* need to enumerate and specifically free each string */
+ if (ws->menuMap) {
+ for(i=0;i<ws->nmMapElems;i++) free(ws->menuMap[i]);
+ free(ws->menuMap);
+ ws->menuMap = 0;
+ }
+ free(ws->cursorname);
+ if (ws->child) {
+ for(i=0;i<ws->nChildren;i++) {
+ free(ws->child[i].id);
+ if (ws->child[i].font) DeleteObject(ws->child[i].font);
+ }
+ free(ws->child);
+ }
+ ws->child = 0;
+ GRFX_UNLINK(ws, wstates);
+ }
+ return 0;
+ }
+
+/*
+ * free a window context
+ */
+void free_context(wc)
+wcp wc;
+ {
+ wc->refcount--;
+ if(wc->refcount == 0) {
+ if (wc->cliprgn)
+ DeleteObject(wc->cliprgn);
+ wc->cliprgn = 0;
+ if (wc->pattern)
+ DeleteObject(wc->pattern);
+ wc->pattern = 0;
+ if (wc->patternname)
+ free(wc->patternname);
+ wc->patternname = 0;
+ if (wc->fgname) free(wc->fgname);
+ wc->fgname = 0;
+ if (wc->bgname) free(wc->bgname);
+ wc->bgname = 0;
+ if (wc->font) {
+ if (wc->font->font)
+ DeleteObject(wc->font->font);
+ wc->font->font = 0;
+ if (wc->font->name)
+ free(wc->font->name);
+ wc->font->name = 0;
+ free(wc->font);
+ }
+ wc->font = 0;
+ GRFX_UNLINK(wc, wcntxts);
+ }
+ }
+
+int walert(wbp w, int volume)
+ {
+ MessageBeep(0);
+ }
+
+int patbits[] = {
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFE,0xFF,0xEF,0xFF,0xFE,0xFF,0xEF,0xFF,
+ 0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,
+ 0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,
+ 0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,
+ 0x01,0x00,0x10,0x00,0x01,0x00,0x10,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+ 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
+ 0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01,
+ 0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,
+ 0x10,0x10,0x10,0xFF,0x10,0x10,0x10,0x10,
+ 0x82,0x44,0x28,0x10,0x28,0x44,0x82,0x01,
+
+ 0x0F,0x0F,0x0F,0x0F,0xF0,0xF0,0xF0,0xF0,
+ 0x1B,0x18,0x81,0xB1,0x36,0x06,0x60,0x63,
+ 0x02,0x02,0x05,0xF8,0x20,0x20,0x50,0x8F,
+ 0x03,0x84,0x48,0x30,0x03,0x84,0x48,0x30,
+};
+
+/*
+ * SetPattern
+ */
+int SetPattern(w, name, len)
+wbp w;
+char *name;
+int len;
+ {
+ int width, nbits;
+ int i, j;
+ int symbol;
+ C_integer v, bits[MAXXOBJS];
+ HBITMAP p;
+ char data[MAXXOBJS];
+ char *buf = data;
+ wcp wc = w->context;
+
+ if (wc->patternname != NULL)
+ free(wc->patternname);
+ wc->patternname = malloc(len+1);
+ strncpy(wc->patternname, name, len);
+ wc->patternname[len] = '\0';
+
+ /*
+ * If the pattern starts with a number it is a width , bits encoding
+ */
+ if ((len > 0) && isdigit(name[0])) {
+ nbits = MAXXOBJS;
+ switch (parsepattern(name, len, &width, &nbits, bits)) {
+ case Failed:
+ return Failed;
+ case Error:
+ ReturnErrNum(145, Error);
+ }
+ if (w->window->iconwin == NULL) return Succeeded;
+ return SetPatternBits(w, width, bits, nbits);
+ }
+
+ /*
+ * Otherwise, it is a named pattern. Find the symbol id.
+ */
+ if ((symbol = si_s2i(siPatternSyms, wc->patternname)) >= 0) {
+ if (w->window->iconwin == NULL) return Succeeded;
+ for(i = 0; i < 8; i++) {
+ v = reversebits(~(patbits[symbol * 8 + i]));
+ *buf++ = v;
+ }
+ p = CreateBitmapFromData(data);
+ if (wc->pattern)
+ DeleteObject(wc->pattern);
+ wc->pattern = p;
+ if (wc->fillstyle == BS_PATTERN) {
+ wc->brush.lbStyle = BS_PATTERN;
+ wc->brush.lbColor = PALCLR(wc->fg);
+ wc->brush.lbHatch = (LONG)p;
+ }
+ return Succeeded;
+ }
+ ReturnErrNum(145, Error);
+ }
+
+/*
+ * Create an 8x8 bitmap from some data
+ */
+HBITMAP CreateBitmapFromData(char *data)
+{
+ WORD *wBits = alloc(8 * sizeof(WORD));
+ HBITMAP rv;
+ int i;
+ static BITMAP bitmap = { 0, 8, 8, 2, 1, 1};
+ for (i = 0; i < 8; i++)
+ wBits[i] = data[i];
+ bitmap.bmBits = (LPSTR) wBits;
+ rv = CreateBitmapIndirect(&bitmap);
+ free(wBits);
+ return rv;
+}
+
+
+int SetPatternBits(w, width, bits, nbits)
+wbp w;
+int width;
+C_integer *bits;
+int nbits;
+ {
+ C_integer v;
+ int i, j, k;
+ HBITMAP p;
+ char data[MAXXOBJS];
+ char *buf = data;
+ wcp wc = w->context;
+
+ if (width != nbits)
+ return Failed;
+
+ if (width == 8) {
+ for(i = 0; i < nbits; i++) {
+ v = bits[i];
+ *buf++ = reversebits(~v);
+ }
+ }
+ else if (width == 4) {
+ for(k=0; k < 2; k++) /* do twice to get 8 rows */
+ for(i = 0; i < nbits; i++) {
+ v = widenbits(bits[i]);
+ *buf++ = reversebits(~v);
+ }
+ }
+ else return Failed;
+
+ p = CreateBitmapFromData(data);
+ if (wc->pattern)
+ DeleteObject(wc->pattern);
+ wc->pattern = p;
+ if (wc->fillstyle == BS_PATTERN) {
+ wc->brush.lbStyle = BS_PATTERN;
+ wc->brush.lbColor = PALCLR(wc->fg);
+ wc->brush.lbHatch = (LONG)p;
+ }
+ return Succeeded;
+ }
+
+int widenbits(int c)
+{
+ int rv = c;
+ if (c & 1) rv |= 16;
+ if (c & 2) rv |= 32;
+ if (c & 4) rv |= 64;
+ if (c & 8) rv |= 128;
+ return rv;
+}
+
+int reversebits(int c)
+{
+ int rv = 0;
+ if (c & 1) rv |= 128;
+ if (c & 2) rv |= 64;
+ if (c & 4) rv |= 32;
+ if (c & 8) rv |= 16;
+ if (c & 16) rv |= 8;
+ if (c & 32) rv |= 4;
+ if (c & 64) rv |= 2;
+ if (c & 128) rv |= 1;
+ return rv;
+}
+
+int pixmap_init(w)
+wbp w;
+ {
+ wsp ws = w->window;
+ resizePixmap(w, ws->width, ws->height);
+ return Succeeded;
+ }
+
+
+int do_config(w, status)
+wbp w;
+int status;
+ {
+ wsp ws = w->window;
+ int wid = ws->width, ht = ws->height;
+ int posx = ws->posx, posy = ws->posy;
+ if (! resizePixmap(w, wid, ht))
+ return Failed;
+ if (ws->win) {
+ pollevent();
+ if (status == 3) {
+ SetWindowPos(ws->win, ws->win,
+ posx,
+ posy,
+ wid, ht, SWP_NOZORDER);
+ }
+ else if (status == 2) {
+ SetWindowPos(ws->win, ws->win, 0, 0,
+ wid, ht, SWP_NOMOVE|SWP_NOZORDER);
+ }
+ else if (status == 1)
+ SetWindowPos(ws->win, ws->win,
+ posx,
+ posy,
+ 0, 0, SWP_NOSIZE|SWP_NOZORDER);
+ }
+ else if (ws->iconwin) {
+ if (status == 3) {
+ SetWindowPos(ws->iconwin, ws->iconwin,
+ posx,
+ posy,
+ wid, ht, SWP_NOZORDER);
+ }
+ else if (status == 2) {
+ SetWindowPos(ws->iconwin, ws->iconwin, 0, 0,
+ wid, ht, SWP_NOMOVE|SWP_NOZORDER);
+ }
+ else if (status == 1)
+ SetWindowPos(ws->iconwin, ws->iconwin,
+ posx,
+ posy,
+ 0, 0, SWP_NOSIZE|SWP_NOZORDER);
+ }
+ return Succeeded;
+ }
+
+DWORD playMIDIfile(HWND hWndNotify, LPSTR s)
+{
+ UINT wDeviceID;
+ DWORD dwReturn;
+ MCI_OPEN_PARMS mciOpenParms;
+ MCI_PLAY_PARMS mciPlayParms;
+ MCI_STATUS_PARMS mciStatusParms;
+ MCI_SEQ_SET_PARMS mciSeqSetParms;
+
+ mciOpenParms.lpstrDeviceType = "sequencer";
+ mciOpenParms.lpstrElementName = s;
+ if (dwReturn = mciSendCommand((UINT)NULL, MCI_OPEN,
+ MCI_OPEN_TYPE | MCI_OPEN_ELEMENT,
+ (DWORD)(LPVOID) &mciOpenParms)) {
+ return dwReturn;
+ }
+ wDeviceID = mciOpenParms.wDeviceID;
+
+ /* attempt to select the MIDI mapper */
+ mciSeqSetParms.dwPort = MIDI_MAPPER;
+ if (dwReturn = mciSendCommand(wDeviceID, MCI_SET, MCI_SEQ_SET_PORT,
+ (DWORD)(LPVOID) &mciSeqSetParms)) {
+ /* could not select the MIDI mapper; play anyway */
+ }
+
+ mciPlayParms.dwCallback = (DWORD) hWndNotify;
+ if (dwReturn = mciSendCommand(wDeviceID, MCI_PLAY, MCI_NOTIFY,
+ (DWORD)(LPVOID) &mciPlayParms)) {
+ mciSendCommand(wDeviceID, MCI_CLOSE, 0, (DWORD)NULL);
+ return dwReturn;
+ }
+
+ return 0L;
+}
+
+
+int playmedia(wbp w, char *s)
+{
+ if (strstr(s, ".wav") || strstr(s, ".WAV")) {
+ sndPlaySound((LPSTR) s, SND_ASYNC);
+ return Succeeded;
+ }
+ else if (strstr(s, ".mid") || strstr(s, ".MID") ||
+ strstr(s, ".rmi") || strstr(s, ".RMI")) {
+ if (playMIDIfile(w->window->win, (LPSTR) s) == 0)
+ return Succeeded;
+ }
+ /*
+ * Interpret as an MCI command string
+ */
+ else {
+ if (mciSendString(s, NULL, 0, 0L)) return Failed;
+ return Succeeded;
+ }
+}
+
+/*
+ * UpdateCursorPos
+ */
+void UpdateCursorPos(wsp ws, wcp wc)
+{
+ if (ISCURSORONW(ws)) {
+ if (ws->hasCaret) {
+ }
+ CreateCaret(ws->iconwin, NULL, FWIDTHC(wc), FHEIGHTC(wc));
+ SetCaretBlinkTime(500);
+ SetCaretPos(ws->x, ws->y - ASCENTC(wc));
+ ShowCaret(ws->iconwin);
+ ws->hasCaret = 1;
+ }
+}
+
+int resizePixmap(wbp w, int width, int height)
+ {
+ HDC hdc, hdc2, hdc3;
+ HBITMAP newpix, oldpix, oldpix2;
+ HBRUSH hb;
+ LOGBRUSH lb;
+ XRectangle rect;
+ wsp ws = w->window;
+ int x = ws->pixwidth, y = ws->pixheight;
+ if (ISEXPOSED(w)) {
+ if (ws->pixwidth >= width && ws->pixheight >= height) {
+ return 1;
+ }
+ ws->pixheight = max(ws->pixheight, height);
+ ws->pixwidth = max(ws->pixwidth, width);
+ }
+ else {
+ ws->pixwidth = width;
+ ws->pixheight = height;
+ }
+ hdc = GetDC(ws->iconwin);
+ newpix = CreateCompatibleBitmap (hdc, ws->pixwidth, ws->pixheight);
+ if (ws->pix) {
+ hdc2 = CreateCompatibleDC(hdc);
+ oldpix = SelectObject(hdc2, ws->pix);
+ }
+ hdc3 = CreateCompatibleDC(hdc);
+ oldpix2 = SelectObject(hdc3, newpix);
+ if (palette) {
+ SelectPalette(hdc, palette, FALSE);
+ if (ws->pix) SelectPalette(hdc2, palette, FALSE);
+ SelectPalette(hdc3, palette, FALSE);
+ RealizePalette(hdc);
+ if (ws->pix) RealizePalette(hdc2);
+ RealizePalette(hdc3);
+ }
+ lb.lbStyle = BS_SOLID;
+ lb.lbColor = PALCLR(w->context->bg);
+ hb = CreateBrushIndirect(&lb);
+ /*
+ * initialize the new pixmap, including areas not in the old pixmap.
+ */
+ rect.left = 0; rect.right = ws->pixwidth;
+ rect.top = 0; rect.bottom = ws->pixheight;
+ FillRect(hdc3, &rect, hb);
+ if (ws->win)
+ FillRect(hdc, &rect, hb);
+
+ if (ws->pix) BitBlt(hdc3, 0, 0, x - 2, y - 1, hdc2, 0, 0, SRCCOPY);
+ if (ws->win)
+ BitBlt(hdc, 0, 0, ws->pixwidth, ws->pixheight, hdc3, 0, 0, SRCCOPY);
+ SelectObject(hdc3, oldpix2);
+ DeleteDC(hdc3);
+ if (ws->pix) {
+ SelectObject(hdc2, oldpix);
+ DeleteDC(hdc2);
+ }
+ ReleaseDC(ws->iconwin, hdc);
+ if (ws->pix) DeleteObject(ws->pix);
+ DeleteObject(hb);
+ ws->pix = newpix;
+ return 1;
+ }
+
+/*
+ * CreateWinDC - create a device context for drawing on the window
+ * In addition, select objects specified by flags.
+ */
+HDC CreateWinDC(wbp w)
+ {
+ wsp ws = w->window;
+ wcp wc = w->context;
+ HDC hdc = GetDC(ws->iconwin);
+ if (numColors > 0) {
+ SelectPalette(hdc, palette, FALSE);
+/* UnrealizeObject(palette); */
+ RealizePalette(hdc);
+ if (numRealized < numColors) {
+ numRealized = numColors;
+ if (RealizePalette(hdc) == 0) /* noop */;
+ }
+ }
+ SetROP2(hdc, wc->drawop);
+ if (wc->clipw >= 0){
+ SelectClipRgn(hdc, wc->cliprgn);
+ }
+ return hdc;
+ }
+
+HDC CreatePixDC(wbp w, HDC hdc)
+ {
+ wsp ws = w->window;
+ wcp wc = w->context;
+ HBITMAP oldpix;
+ HDC hdc2 = CreateCompatibleDC(hdc);
+ if (numColors > 0) {
+ SelectPalette(hdc2, palette, FALSE);
+ RealizePalette(hdc2);
+ }
+/* ws->initialPix = */ ws->theOldPix = SelectObject(hdc2, ws->pix);
+ SetROP2(hdc2, wc->drawop);
+ if (wc->clipw >= 0){
+ SelectClipRgn(hdc2, wc->cliprgn);
+ }
+ return hdc2;
+ }
+
+int dc_maxcharwidth(HDC dc)
+{
+ int i, m = -1, x;
+ char s[2];
+ s[1] = '\0';
+ for (i=0; i<256; i++) {
+ s[0] = i;
+ x = dc_textwidth(dc, s, 1);
+ if (x > m) m = x;
+ }
+ return m;
+}
+
+/*
+ * compute a text width for a current device context (typically pixdc)
+ */
+int dc_textwidth(HDC dc, char *s, int n)
+{
+ SIZE sz;
+ /*
+ * GetTextExtentPoint32(dc, s, n, &sz) gives incorrect behavior
+ * under Win32s
+ */
+ GetTextExtentPoint(dc, s, n, &sz);
+ return (int)sz.cx;
+}
+
+int sysScrollWidth()
+{
+ return GetSystemMetrics(SM_CXVSCROLL);
+}
+
+int sysFontHeight(wbp w)
+{
+ TEXTMETRIC tm;
+ int rv;
+ wsp ws = w->window;
+ HDC dc = GetDC(ws->iconwin);
+ HFONT oldfont = SelectObject(dc, GetStockObject(SYSTEM_FIXED_FONT));
+ GetTextMetrics(dc, &tm);
+ SelectObject(dc, oldfont);
+ ReleaseDC(ws->iconwin, dc);
+ return tm.tmHeight + tm.tmExternalLeading;
+}
+
+int sysTextWidth(wbp w, char *s, int n)
+{
+ int rv;
+ wsp ws = w->window;
+ HDC dc = GetDC(ws->iconwin);
+ HFONT oldfont;
+ oldfont = SelectObject(dc, GetStockObject(SYSTEM_FIXED_FONT));
+ rv = dc_textwidth(dc, s, n);
+ SelectObject(dc, oldfont);
+ ReleaseDC(ws->iconwin, dc);
+ return rv;
+}
+
+int textWidth(wbp w, char *s, int n)
+ {
+ int rv;
+ wsp ws = w->window;
+ HDC stddc = GetDC(ws->iconwin);
+ HFONT oldfont = SelectObject(stddc, w->context->font->font);
+ rv = dc_textwidth(stddc, s, n);
+ SelectObject(stddc, oldfont);
+ ReleaseDC(ws->iconwin, stddc);
+ return rv;
+ }
+
+void warpPointer(w, x, y)
+wbp w;
+int x, y;
+ {
+ wsp ws = w->window;
+ SetCursorPos(ws->posx + x, ws->posy + y);
+ }
+
+/*
+ * free all Windows resources allocated by this instantiation of iconx
+ */
+void wfreersc()
+{
+ wbp w;
+ extern struct palentry *palsetup_palette;
+ while (wbndngs != NULL) {
+ w = wbndngs;
+ wbndngs = wbndngs->next;
+ free(w);
+ }
+ while (wstates != NULL) {
+ wstates->refcount = 1;
+ free_window(wstates);
+ }
+ while (wcntxts != NULL) {
+ wcntxts->refcount = 1;
+ free_context(wcntxts);
+ }
+ if (palette) {
+ DeleteObject(palette);
+ palette = 0;
+ }
+ if (palsetup_palette) {
+ free(palsetup_palette);
+ palsetup_palette = 0;
+ }
+ if (scp) {
+ free(scp);
+ scp = 0;
+ }
+ if (wlhead)
+ wlfree();
+ mciSendCommand(MCI_ALL_DEVICE_ID, MCI_CLOSE, 0, (DWORD)NULL);
+}
+
+
+/*
+ * Native Windows UI facilities
+ */
+void makebutton(wsp ws, childcontrol *cc, char *s)
+{
+ cc->type = CHILD_BUTTON;
+ cc->font = 0;
+ cc->id = salloc(s);
+ cc->win = CreateWindow("button", cc->id,
+ WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
+ 0, 0, 0, 0, ws->iconwin, (HMENU)ws->nChildren, mswinInstance,
+ NULL);
+}
+
+void makescrollbar(wsp ws, childcontrol *cc, char *s, int i1, int i2)
+{
+ cc->type = CHILD_SCROLLBAR;
+ cc->id = salloc(s);
+ cc->font = 0;
+ cc->win = CreateWindow("scrollbar", cc->id,
+ WS_CHILD | WS_VISIBLE | SBS_VERT, 0, 0, 0, 0,
+ ws->iconwin, (HMENU)ws->nChildren, mswinInstance, NULL);
+ SetScrollRange(cc->win, SB_CTL, i1, i2, FALSE);
+}
+
+int nativemenubar(wbp w, int total, int argc, dptr argv, int warg, dptr d)
+{
+ wsp ws;
+ tended struct b_list *hp;
+ HMENU tempMenu, tempMenu2 = NULL;
+ tended char *s, *s2;
+ int r, i;
+ ws = w->window;
+
+ if (ws->nmMapElems)
+ tempMenu2 = ws->menuBar;
+
+ ws->menuBar = CreateMenu();
+ ws->nmMapElems = total;
+ total = 0;
+ while (warg < argc){
+ /*
+ * each argument must be a list of strings
+ */
+ hp = (struct b_list *)BlkLoc(argv[warg]);
+ r = hp->size;
+ /*
+ * Construct a Windows menu corresponding to the Icon list
+ */
+ tempMenu = CreateMenu();
+ for(i=0; i < r; i++) {
+ c_get(hp, d);
+ if (!is:string(*d)) return Error;
+ if (!cnv:C_string(*d, s)) return Error;
+ s = strdup(s);
+ if (i == 0) s2=s;
+ else
+ AppendMenu(tempMenu, MF_STRING, total, s);
+ ws->menuMap[total++] = s;
+ c_put(&(argv[warg]), d);
+ }
+ AppendMenu(ws->menuBar, MF_POPUP, (unsigned int)tempMenu, s2);
+ warg++;
+ }
+ /*
+ * Insert the menu into the window
+ */
+ if (ws->win) SetMenu(ws->win, ws->menuBar);
+ if (tempMenu2) {
+ int i, n = GetMenuItemCount(tempMenu2);
+ for (i=0; i < n; i++) {
+ DestroyMenu(GetSubMenu(tempMenu2, i));
+ }
+ DestroyMenu(tempMenu2);
+ }
+ return Succeeded;
+}
+
+void makeeditregion(wbp w, childcontrol *cc, char *s)
+{
+ wsp ws = w->window;
+ cc->type = CHILD_EDIT;
+ cc->id = salloc(s);
+ cc->win = CreateWindow("edit", NULL,
+ WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL |
+ WS_BORDER | ES_LEFT | ES_MULTILINE |
+ ES_AUTOHSCROLL | ES_AUTOVSCROLL,
+ 0, 0, 0, 0, ws->iconwin,
+ (HMENU) ws->nChildren, mswinInstance, NULL);
+ setchildfont(cc, w->context->font->name);
+}
+
+void cleareditregion(childcontrol *cc)
+{
+ SendMessage(cc->win, WM_CLEAR, 0, 0);
+}
+
+void copyeditregion(childcontrol *cc)
+{
+ SendMessage(cc->win, WM_COPY, 0, 0);
+}
+
+void cuteditregion(childcontrol *cc)
+{
+ SendMessage(cc->win, WM_CUT, 0, 0);
+}
+
+void pasteeditregion(childcontrol *cc)
+{
+ SendMessage(cc->win, WM_PASTE, 0, 0);
+}
+
+int undoeditregion(childcontrol *cc)
+{
+ if (!SendMessage(cc->win, WM_UNDO, 0, 0)) return Failed;
+ return Succeeded;
+}
+
+int modifiededitregion(childcontrol *cc)
+{
+ if (!SendMessage(cc->win, EM_GETMODIFY, 0, 0)) return Failed;
+ return Succeeded;
+}
+
+int setmodifiededitregion(childcontrol *cc, int i)
+{
+ SendMessage(cc->win, EM_SETMODIFY, i, 0);
+ return Succeeded;
+}
+
+void geteditregion(childcontrol *cc, dptr d)
+{
+ int y = GetWindowTextLength(cc->win);
+ char *s2 = alcstr(NULL, y + 1);
+ GetWindowText(cc->win, s2, y+1);
+ StrLoc(*d) = s2;
+ StrLen(*d) = y;
+}
+
+void seteditregion(childcontrol *cc, char *s2)
+{
+ SetWindowText(cc->win, s2);
+}
+
+
+void movechild(childcontrol *cc,
+ C_integer x, C_integer y, C_integer width, C_integer height)
+{
+ MoveWindow(cc->win, x, y, width, height, TRUE);
+}
+
+int setchildfont(childcontrol *cc, char *fontname)
+{
+ HFONT hf;
+ RECT rect;
+ if (hf = mkfont(fontname)) {
+ SendMessage(cc->win, WM_SETFONT, (WPARAM)hf, 0);
+ if (cc->font) DeleteObject(cc->font);
+ cc->font = hf;
+ GetClientRect(cc->win, &rect);
+ InvalidateRect(cc->win, &rect, TRUE);
+ return Succeeded;
+ }
+ return Failed;
+}
+
+void setfocusonchild(wsp ws, childcontrol *cc, int width, int height)
+{
+ if (width || height) {
+ SetFocus(cc->win);
+ ws->focusChild = cc->win;
+ }
+ else ws->focusChild = 0;
+}
+
+void setchildselection(wsp ws, childcontrol *cc, int x, int y)
+{
+ int iLine = SendMessage(cc->win, EM_LINEFROMCHAR, x-1,0);
+ int topLine = SendMessage(cc->win, EM_GETFIRSTVISIBLELINE, 0, 0);
+ if (topLine != iLine) {
+ SendMessage(cc->win, EM_LINESCROLL, 0, iLine-topLine);
+ }
+ SendMessage(cc->win, EM_SETSEL, x - 1, y - 1);
+ SetFocus(cc->win);
+ ws->focusChild = cc->win;
+}
+
+CHOOSEFONT cf;
+LOGFONT lf;
+
+int nativefontdialog(wbp w, char *buf, int flags, int fheight)
+{
+ strcpy(lf.lfFaceName, buf);
+ lf.lfHeight = fheight;
+ lf.lfWidth = 0;
+ lf.lfEscapement = 0;
+ if (!strcmp(lf.lfFaceName, "mono") || !strcmp(lf.lfFaceName, "fixed")){
+ strcpy(lf.lfFaceName, "Lucida Sans Typewriter");
+ flags |= FONTFLAG_MONO + FONTFLAG_SANS;
+ }
+ else if (!strcmp(lf.lfFaceName, "typewriter")) {
+ strcpy(lf.lfFaceName, "courier");
+ flags |= FONTFLAG_MONO + FONTFLAG_SERIF;
+ }
+ else if (!strcmp(lf.lfFaceName, "sans")) {
+ strcpy(lf.lfFaceName, "swiss");
+ flags |= FONTFLAG_PROPORTIONAL + FONTFLAG_SANS;
+ }
+ else if (!strcmp(lf.lfFaceName, "serif")) {
+ strcpy(lf.lfFaceName, "roman");
+ flags |= FONTFLAG_PROPORTIONAL + FONTFLAG_SERIF;
+ }
+
+ if (flags & FONTFLAG_BOLD) lf.lfWeight = FW_BOLD;
+ else
+ lf.lfWeight = FW_DONTCARE;
+ if (flags & FONTFLAG_ITALIC) lf.lfItalic = 1;
+ lf.lfUnderline = lf.lfStrikeOut = 0;
+ lf.lfCharSet =
+ ((MAXBYTESPERCHAR==1)?ANSI_CHARSET:DEFAULT_CHARSET);
+ lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
+ lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
+ lf.lfQuality = DEFAULT_QUALITY;
+ if (FONTFLAG_PROPORTIONAL)
+ lf.lfPitchAndFamily = VARIABLE_PITCH;
+ else if (FONTFLAG_MONO)
+ lf.lfPitchAndFamily = FIXED_PITCH;
+ else
+ lf.lfPitchAndFamily = DEFAULT_PITCH;
+ if (!strcmp(lf.lfFaceName, "swiss")) lf.lfPitchAndFamily |= FF_SWISS;
+ else if (!strcmp(lf.lfFaceName, "roman"))
+ lf.lfPitchAndFamily |= FF_ROMAN;
+ else
+ lf.lfPitchAndFamily |= FF_DONTCARE;
+
+ memset(&cf, 0, sizeof(CHOOSEFONT));
+ cf.lStructSize = sizeof(CHOOSEFONT);
+ cf.hwndOwner = w->window->iconwin;
+ cf.lpLogFont = &lf;
+ cf.Flags = CF_SCREENFONTS | CF_EFFECTS | CF_INITTOLOGFONTSTRUCT;
+ cf.rgbColors = RGB(0,0,0);
+ cf.nFontType = SCREEN_FONTTYPE;
+ if (ChooseFont(&cf) == 0) return Failed;
+ sprintf(buf, "%s,%d%s%s", lf.lfFaceName,
+ ((lf.lfHeight > 0) ? lf.lfHeight : -lf.lfHeight),
+ (lf.lfItalic ? ",italic" : ""),
+ ((lf.lfWeight > 500) ? ",bold" : ""));
+ return Succeeded;
+}
+
+/*
+ * common dialog functions
+ */
+COLORREF aclrCust[16];
+CHOOSECOLOR cc;
+
+char *nativecolordialog(wbp w, long r, long g, long b, char *buf)
+{
+ aclrCust[0] = RGB(255,255,255);
+ aclrCust[1] = RGB(239,239,239);
+ aclrCust[2] = RGB(223,223,223);
+ aclrCust[3] = RGB(207,207,207);
+ aclrCust[4] = RGB(191,191,191);
+ aclrCust[5] = RGB(175,175,175);
+ aclrCust[6] = RGB(159,159,159);
+ aclrCust[7] = RGB(143,143,143);
+ aclrCust[8] = RGB(127,127,127);
+ aclrCust[9] = RGB(111,111,111);
+ aclrCust[10] = RGB(95,95,95);
+ aclrCust[11] = RGB(79,79,79);
+ aclrCust[12] = RGB(63,63,63);
+ aclrCust[13] = RGB(47,47,47);
+ aclrCust[14] = RGB(31,31,31);
+ aclrCust[15] = RGB(15,15,15);
+ memset(&cc, 0, sizeof(CHOOSECOLOR));
+ cc.lStructSize = sizeof(CHOOSECOLOR);
+ cc.hwndOwner = w->window->iconwin;
+ cc.lpCustColors = aclrCust;
+ cc.rgbResult = mscolor(w, r, g, b);
+ cc.Flags = CC_FULLOPEN | CC_RGBINIT;
+ if (ChooseColor(&cc) == 0) {
+ return NULL;
+ }
+ sprintf(buf, "%d,%d,%d", (RED(cc.rgbResult)<<8) | 0xFF,
+ (GREEN(cc.rgbResult) << 8) | 0xFF,
+ (BLUE(cc.rgbResult) << 8) | 0xFF);
+ return buf;
+}
+
+
+
+
+char *nativeselectdialog(wbp w, struct b_list *L, char *s)
+{
+ int i, j, okflag=0, yesnoflag=0, cancelflag=0, retryflag=0, otherflag=0;
+ tended struct b_list *hp = L;
+ tended char *s1 = NULL;
+ tended struct descrip d, d2;
+ char s3[8];
+ wsp ws = w->window;
+ int lsize;
+
+ if (hp == NULL) {
+ okflag = 1;
+ }
+ else {
+ BlkLoc(d2) = (union block *)hp;
+ d2.dword = D_List;
+ lsize = hp->size;
+
+ for(i=0; i < lsize; i++) {
+ c_get(hp, &d);
+ if (!cnv:C_string(d, s1)) return NULL;
+ for(j=0; j<8; j++) {
+ s3[j] = tolower(s1[j]);
+ if (s3[j] == '\0') break;
+ }
+ if (!strcmp(s3, "ok")) okflag = 1;
+ else if (!strcmp(s3, "okay")) okflag = 1;
+ else if (!strcmp(s3, "no")) yesnoflag = MB_YESNO;
+ else if (!strcmp(s3, "yes")) yesnoflag = MB_YESNO;
+ else if (!strcmp(s3, "cancel")) cancelflag++;
+ else if (!strcmp(s3, "retry")) retryflag = MB_RETRYCANCEL;
+ else { otherflag++; return NULL; }
+ c_put(&d2, &d);
+ }
+ }
+ /*
+ * validate flags
+ */
+ if (okflag && yesnoflag) return NULL;
+ if (okflag && retryflag) return NULL;
+ if (yesnoflag && retryflag) return NULL;
+ if (retryflag && !cancelflag) return NULL;
+
+ if (cancelflag) {
+ if (okflag) {
+ okflag = MB_OKCANCEL;
+ }
+ else if (yesnoflag) yesnoflag = MB_YESNOCANCEL;
+ }
+ else if (okflag) okflag = MB_OK;
+
+ j = MessageBox((ws->focusChild ? ws->focusChild :
+ (ws->win ? ws->win : ws->iconwin)),
+ s, " ",
+ okflag | yesnoflag | retryflag
+ | (strchr(s, '!') ? MB_ICONEXCLAMATION :
+ (strchr(s, '?') ? MB_ICONQUESTION : MB_ICONASTERISK)));
+
+ switch (j) {
+ case IDOK: return "Okay";
+ case IDCANCEL: return "Cancel";
+ case IDYES: return "Yes";
+ case IDNO: return "No";
+ case IDRETRY: return "Retry";
+ default: return NULL;
+ }
+}
+
+OPENFILENAME ofn;
+
+char *nativeopendialog(wbp w, char *s1, char *s2, char *s3, int i, int j)
+{
+ char buf[128], buf2[64];
+
+ memset(&ofn, 0, sizeof(OPENFILENAME));
+ ofn.lStructSize = sizeof(OPENFILENAME);
+ ofn.hwndOwner = w->window->iconwin;
+ ofn.lpstrFilter = s3;
+ ofn.nFilterIndex = j;
+ strcpy(buf, s2);
+ ofn.lpstrFile = buf;
+ ofn.nMaxFile = sizeof(buf);
+ ofn.lpstrTitle = s1;
+ ofn.lpstrFileTitle = buf2;
+ ofn.nMaxFileTitle = sizeof(buf2);
+ ofn.lpstrInitialDir = NULL;
+ ofn.Flags = OFN_SHOWHELP | OFN_PATHMUSTEXIST;
+ if (GetOpenFileName(&ofn) == 0) return NULL;
+ return ofn.lpstrFile;
+}
+
+
+char *nativesavedialog(wbp w, char *s1, char *s2, char *s3, int i, int j)
+{
+ char buf[128], buf2[64];
+ /*
+ * Use the standard dialog to obtain a filename.
+ */
+ memset(&ofn, 0, sizeof(OPENFILENAME));
+ ofn.lStructSize = sizeof(OPENFILENAME);
+ ofn.hwndOwner = w->window->iconwin;
+ ofn.lpstrFilter = s3;
+ ofn.nFilterIndex = j;
+ strcpy(buf, s2);
+ ofn.lpstrFile = buf;
+ ofn.nMaxFile = sizeof(buf);
+ ofn.lpstrTitle = s1;
+ ofn.lpstrFileTitle = buf2;
+ ofn.nMaxFileTitle = sizeof(buf2);
+ ofn.lpstrInitialDir = NULL;
+ ofn.Flags = OFN_SHOWHELP | OFN_PATHMUSTEXIST;
+ if (GetSaveFileName(&ofn) == 0) return NULL;
+ return ofn.lpstrFile;
+}
+
+/*
+ * flush a window - noop under Windows
+ */
+void wflush(w)
+wbp w;
+ {
+ }
+
+#endif /* Graphics */