X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/fe8abbf463f798f37ee4f43b3b85583a80fbddf4..7440fd4419acfc9c784f142fb9dee3e64c9a18c2:/winctrls.c diff --git a/winctrls.c b/winctrls.c index 4d055f46..4a35cb6b 100644 --- a/winctrls.c +++ b/winctrls.c @@ -13,16 +13,14 @@ * button. */ -#include -#include #include +#include -#include "winstuff.h" +#include "putty.h" #include "misc.h" #include "dialog.h" -#include "puttymem.h" -#include "putty.h" +#include #define GAPBETWEEN 3 #define GAPWITHIN 1 @@ -94,7 +92,8 @@ HWND doctl(struct ctlpos *cp, RECT r, SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOZORDER); } - } + } else + ctl = NULL; return ctl; } @@ -285,9 +284,10 @@ void radioline(struct ctlpos *cp, char *text, int id, int nacross, ...) if (!btext) break; bid = va_arg(ap, int); + nbuttons++; } va_end(ap); - buttons = smalloc(nbuttons * sizeof(struct radio)); + buttons = snewn(nbuttons, struct radio); va_start(ap, nacross); for (i = 0; i < nbuttons; i++) { buttons[i].text = va_arg(ap, char *); @@ -318,7 +318,7 @@ void bareradioline(struct ctlpos *cp, int nacross, ...) bid = va_arg(ap, int); } va_end(ap); - buttons = smalloc(nbuttons * sizeof(struct radio)); + buttons = snewn(nbuttons, struct radio); va_start(ap, nacross); for (i = 0; i < nbuttons; i++) { buttons[i].text = va_arg(ap, char *); @@ -349,7 +349,7 @@ void radiobig(struct ctlpos *cp, char *text, int id, ...) bid = va_arg(ap, int); } va_end(ap); - buttons = smalloc(nbuttons * sizeof(struct radio)); + buttons = snewn(nbuttons, struct radio); va_start(ap, id); for (i = 0; i < nbuttons; i++) { buttons[i].text = va_arg(ap, char *); @@ -384,7 +384,6 @@ void checkbox(struct ctlpos *cp, char *text, int id) */ char *staticwrap(struct ctlpos *cp, HWND hwnd, char *text, int *lines) { - HFONT font = (HFONT) cp->font; HDC hdc = GetDC(hwnd); int lpx = GetDeviceCaps(hdc, LOGPIXELSX); int width, nlines, j; @@ -392,28 +391,33 @@ char *staticwrap(struct ctlpos *cp, HWND hwnd, char *text, int *lines) SIZE size; char *ret, *p, *q; RECT r; + HFONT oldfont, newfont; - ret = smalloc(1+strlen(text)); + ret = snewn(1+strlen(text), char); p = text; q = ret; - pwidths = smalloc(sizeof(INT)*(1+strlen(text))); + pwidths = snewn(1+strlen(text), INT); /* * Work out the width the text will need to fit in, by doing * the same adjustment that the `statictext' function itself * will perform. - * - * We must first convert from dialog-box units into pixels, and - * then from pixels into the `logical units' that Windows uses - * within GDI. You can't make this stuff up. */ + SetMapMode(hdc, MM_TEXT); /* ensure logical units == pixels */ r.left = r.top = r.bottom = 0; r.right = cp->width; MapDialogRect(hwnd, &r); - width = MulDiv(r.right, lpx, 72); + width = r.right; nlines = 1; + /* + * We must select the correct font into the HDC before calling + * GetTextExtent*, or silly things will happen. + */ + newfont = (HFONT)SendMessage(hwnd, WM_GETFONT, 0, 0); + oldfont = SelectObject(hdc, newfont); + while (*p) { if (!GetTextExtentExPoint(hdc, p, strlen(p), width, &nfit, pwidths, &size) || @@ -452,6 +456,7 @@ char *staticwrap(struct ctlpos *cp, HWND hwnd, char *text, int *lines) nlines++; } + SelectObject(hdc, oldfont); ReleaseDC(cp->hwnd, hdc); if (lines) *lines = nlines; @@ -966,7 +971,7 @@ static void pl_moveitem(HWND hwnd, int listid, int src, int dst) char *txt; /* Get the item's data. */ tlen = SendDlgItemMessage (hwnd, listid, LB_GETTEXTLEN, src, 0); - txt = smalloc(tlen+1); + txt = snewn(tlen+1, char); SendDlgItemMessage (hwnd, listid, LB_GETTEXT, src, (LPARAM) txt); val = SendDlgItemMessage (hwnd, listid, LB_GETITEMDATA, src, 0); /* Deselect old location. */ @@ -1040,7 +1045,7 @@ int handle_prefslist(struct prefslist *hdl, if ((int)wParam == hdl->listid) { DRAGLISTINFO *dlm = (DRAGLISTINFO *)lParam; - int dest; + int dest = 0; /* initialise to placate gcc */ switch (dlm->uNotification) { case DL_BEGINDRAG: hdl->dummyitem = @@ -1169,7 +1174,7 @@ static char *shortcut_escape(char *text, char shortcut) if (!text) return NULL; /* sfree won't choke on this */ - ret = smalloc(2*strlen(text)+1); /* size potentially doubles! */ + ret = snewn(2*strlen(text)+1, char); /* size potentially doubles! */ shortcut = tolower((unsigned char)shortcut); p = text; @@ -1321,16 +1326,17 @@ void winctrl_layout(struct dlgparam *dp, struct winctrls *wc, struct ctlpos pos; - char shortcuts[MAX_SHORTCUTS_PER_CTRL], nshortcuts; + char shortcuts[MAX_SHORTCUTS_PER_CTRL]; + int nshortcuts; char *escaped; - int i, base_id, num_ids, orig_tabdelay; + int i, actual_base_id, base_id, num_ids; void *data; base_id = *id; /* Start a containing box, if we have a boxname. */ if (s->boxname && *s->boxname) { - struct winctrl *c = smalloc(sizeof(struct winctrl)); + struct winctrl *c = snew(struct winctrl); c->ctrl = NULL; c->base_id = base_id; c->num_ids = 1; @@ -1343,7 +1349,7 @@ void winctrl_layout(struct dlgparam *dp, struct winctrls *wc, /* Draw a title, if we have one. */ if (!s->boxname && s->boxtitle) { - struct winctrl *c = smalloc(sizeof(struct winctrl)); + struct winctrl *c = snew(struct winctrl); c->ctrl = NULL; c->base_id = base_id; c->num_ids = 1; @@ -1365,8 +1371,6 @@ void winctrl_layout(struct dlgparam *dp, struct winctrls *wc, for (i = 0; i < s->ncontrols; i++) { union control *ctrl = s->ctrls[i]; - orig_tabdelay = FALSE; - /* * Generic processing that pertains to all control types. * At the end of this if statement, we'll have produced @@ -1423,7 +1427,6 @@ void winctrl_layout(struct dlgparam *dp, struct winctrls *wc, assert(!ctrl->generic.tabdelay); ctrl = ctrl->tabdelay.ctrl; - orig_tabdelay = TRUE; for (i = 0; i < ntabdelays; i++) if (tabdelayed[i] == ctrl) @@ -1432,6 +1435,8 @@ void winctrl_layout(struct dlgparam *dp, struct winctrls *wc, pos = tabdelays[i]; /* structure copy */ + colstart = colspan = -1; /* indicate this was tab-delayed */ + } else { /* * If it wasn't one of those, it's a genuine control; @@ -1472,6 +1477,9 @@ void winctrl_layout(struct dlgparam *dp, struct winctrls *wc, memset(shortcuts, NO_SHORTCUT, lenof(shortcuts)); nshortcuts = 0; + /* Almost all controls start at base_id. */ + actual_base_id = base_id; + /* * Now we're ready to actually create the control, by * switching on its type. @@ -1524,7 +1532,7 @@ void winctrl_layout(struct dlgparam *dp, struct winctrls *wc, ctrl->radio.shortcut); shortcuts[nshortcuts++] = ctrl->radio.shortcut; - buttons = smalloc(ctrl->radio.nbuttons * sizeof(struct radio)); + buttons = snewn(ctrl->radio.nbuttons, struct radio); for (i = 0; i < ctrl->radio.nbuttons; i++) { buttons[i].text = @@ -1562,8 +1570,10 @@ void winctrl_layout(struct dlgparam *dp, struct winctrls *wc, escaped = shortcut_escape(ctrl->button.label, ctrl->button.shortcut); shortcuts[nshortcuts++] = ctrl->button.shortcut; + if (ctrl->button.iscancel) + actual_base_id = IDCANCEL; num_ids = 1; - button(&pos, escaped, base_id, ctrl->button.isdefault); + button(&pos, escaped, actual_base_id, ctrl->button.isdefault); sfree(escaped); break; case CTRL_LISTBOX: @@ -1572,7 +1582,7 @@ void winctrl_layout(struct dlgparam *dp, struct winctrls *wc, ctrl->listbox.shortcut); shortcuts[nshortcuts++] = ctrl->listbox.shortcut; if (ctrl->listbox.draglist) { - data = smalloc(sizeof(struct prefslist)); + data = snew(struct prefslist); num_ids = 4; prefslist(data, &pos, ctrl->listbox.height, escaped, base_id, base_id+1, base_id+2, base_id+3); @@ -1604,7 +1614,7 @@ void winctrl_layout(struct dlgparam *dp, struct winctrls *wc, int *tabarray; int i, percent; - tabarray = smalloc((ctrl->listbox.ncols-1) * sizeof(int)); + tabarray = snewn(ctrl->listbox.ncols-1, int); percent = 0; for (i = 0; i < ctrl->listbox.ncols-1; i++) { percent += ctrl->listbox.percentages[i]; @@ -1634,10 +1644,11 @@ void winctrl_layout(struct dlgparam *dp, struct winctrls *wc, statictext(&pos, escaped, 1, base_id); staticbtn(&pos, "", base_id+1, "Change...", base_id+2); sfree(escaped); - data = smalloc(sizeof(FontSpec)); + data = snew(FontSpec); break; default: assert(!"Can't happen"); + num_ids = 0; /* placate gcc */ break; } @@ -1647,19 +1658,20 @@ void winctrl_layout(struct dlgparam *dp, struct winctrls *wc, * (and isn't tabdelayed). */ if (pos.hwnd) { - struct winctrl *c = smalloc(sizeof(struct winctrl)); + struct winctrl *c = snew(struct winctrl); c->ctrl = ctrl; - c->base_id = base_id; + c->base_id = actual_base_id; c->num_ids = num_ids; c->data = data; memcpy(c->shortcuts, shortcuts, sizeof(shortcuts)); winctrl_add(wc, c); winctrl_add_shortcuts(dp, c); - base_id += num_ids; + if (actual_base_id == base_id) + base_id += num_ids; } - if (!orig_tabdelay) { + if (colstart >= 0) { /* * Update the ypos in all columns crossed by this * control. @@ -1697,10 +1709,10 @@ static void winctrl_set_focus(union control *ctrl, struct dlgparam *dp, } } -union control *dlg_last_focused(void *dlg) +union control *dlg_last_focused(union control *ctrl, void *dlg) { struct dlgparam *dp = (struct dlgparam *)dlg; - return dp->lastfocused; + return dp->focused == ctrl ? dp->lastfocused : dp->focused; } /* @@ -1728,6 +1740,7 @@ int winctrl_handle_command(struct dlgparam *dp, UINT msg, /* * Look up the control ID in our data. */ + c = NULL; for (i = 0; i < dp->nctrltrees; i++) { c = winctrl_findbyid(dp->controltrees[i], LOWORD(wParam)); if (c) @@ -1745,6 +1758,8 @@ int winctrl_handle_command(struct dlgparam *dp, UINT msg, RECT r = di->rcItem; SIZE s; + SetMapMode(hdc, MM_TEXT); /* ensure logical units == pixels */ + GetTextExtentPoint32(hdc, (char *)c->data, strlen((char *)c->data), &s); DrawEdge(hdc, &r, EDGE_ETCHED, BF_ADJUST | BF_RECT); @@ -1797,7 +1812,7 @@ int winctrl_handle_command(struct dlgparam *dp, UINT msg, CB_GETCURSEL, 0, 0); len = SendDlgItemMessage(dp->hwnd, c->base_id+1, CB_GETLBTEXTLEN, index, 0); - text = smalloc(len+1); + text = snewn(len+1, char); SendDlgItemMessage(dp->hwnd, c->base_id+1, CB_GETLBTEXT, index, (LPARAM)text); SetDlgItemText(dp->hwnd, c->base_id+1, text); @@ -1823,8 +1838,8 @@ int winctrl_handle_command(struct dlgparam *dp, UINT msg, * checked before generating an event. */ if (msg == WM_COMMAND && - HIWORD(wParam) == BN_CLICKED || - HIWORD(wParam) == BN_DOUBLECLICKED && + (HIWORD(wParam) == BN_CLICKED || + HIWORD(wParam) == BN_DOUBLECLICKED) && IsDlgButtonChecked(dp->hwnd, LOWORD(wParam))) { ctrl->generic.handler(ctrl, dp, dp->data, EVENT_VALCHANGE); } @@ -1882,6 +1897,8 @@ int winctrl_handle_command(struct dlgparam *dp, UINT msg, if (msg == WM_COMMAND && id == 2 && (HIWORD(wParam) == BN_SETFOCUS || HIWORD(wParam) == BN_KILLFOCUS)) winctrl_set_focus(ctrl, dp, HIWORD(wParam) == BN_SETFOCUS); + if (msg == WM_COMMAND && id == 1 && HIWORD(wParam) == EN_CHANGE) + ctrl->generic.handler(ctrl, dp, dp->data, EVENT_VALCHANGE); if (id == 2 && (msg == WM_COMMAND && (HIWORD(wParam) == BN_CLICKED || @@ -2014,6 +2031,7 @@ int winctrl_context_help(struct dlgparam *dp, HWND hwnd, int id) /* * Look up the control ID in our data. */ + c = NULL; for (i = 0; i < dp->nctrltrees; i++) { c = winctrl_findbyid(dp->controltrees[i], id); if (c) @@ -2117,8 +2135,8 @@ void dlg_listbox_clear(union control *ctrl, void *dlg) int msg; assert(c && (c->ctrl->generic.type == CTRL_LISTBOX || - c->ctrl->generic.type == CTRL_EDITBOX && - c->ctrl->editbox.has_list)); + (c->ctrl->generic.type == CTRL_EDITBOX && + c->ctrl->editbox.has_list))); msg = (c->ctrl->generic.type==CTRL_LISTBOX && c->ctrl->listbox.height!=0 ? LB_RESETCONTENT : CB_RESETCONTENT); SendDlgItemMessage(dp->hwnd, c->base_id+1, msg, 0, 0); @@ -2131,8 +2149,8 @@ void dlg_listbox_del(union control *ctrl, void *dlg, int index) int msg; assert(c && (c->ctrl->generic.type == CTRL_LISTBOX || - c->ctrl->generic.type == CTRL_EDITBOX && - c->ctrl->editbox.has_list)); + (c->ctrl->generic.type == CTRL_EDITBOX && + c->ctrl->editbox.has_list))); msg = (c->ctrl->generic.type==CTRL_LISTBOX && c->ctrl->listbox.height!=0 ? LB_DELETESTRING : CB_DELETESTRING); SendDlgItemMessage(dp->hwnd, c->base_id+1, msg, index, 0); @@ -2145,8 +2163,8 @@ void dlg_listbox_add(union control *ctrl, void *dlg, char const *text) int msg; assert(c && (c->ctrl->generic.type == CTRL_LISTBOX || - c->ctrl->generic.type == CTRL_EDITBOX && - c->ctrl->editbox.has_list)); + (c->ctrl->generic.type == CTRL_EDITBOX && + c->ctrl->editbox.has_list))); msg = (c->ctrl->generic.type==CTRL_LISTBOX && c->ctrl->listbox.height!=0 ? LB_ADDSTRING : CB_ADDSTRING); SendDlgItemMessage(dp->hwnd, c->base_id+1, msg, 0, (LPARAM)text); @@ -2159,16 +2177,16 @@ void dlg_listbox_add(union control *ctrl, void *dlg, char const *text) * strings in any listbox then you MUST not assign them different * IDs and expect to get meaningful results back. */ -void dlg_listbox_addwithindex(union control *ctrl, void *dlg, - char const *text, int id) +void dlg_listbox_addwithid(union control *ctrl, void *dlg, + char const *text, int id) { struct dlgparam *dp = (struct dlgparam *)dlg; struct winctrl *c = dlg_findbyctrl(dp, ctrl); int msg, msg2, index; assert(c && (c->ctrl->generic.type == CTRL_LISTBOX || - c->ctrl->generic.type == CTRL_EDITBOX && - c->ctrl->editbox.has_list)); + (c->ctrl->generic.type == CTRL_EDITBOX && + c->ctrl->editbox.has_list))); msg = (c->ctrl->generic.type==CTRL_LISTBOX && c->ctrl->listbox.height!=0 ? LB_ADDSTRING : CB_ADDSTRING); msg2 = (c->ctrl->generic.type==CTRL_LISTBOX && c->ctrl->listbox.height!=0 ? @@ -2412,3 +2430,105 @@ int dlg_coloursel_results(union control *ctrl, void *dlg, } else return 0; } + +struct perctrl_privdata { + union control *ctrl; + void *data; + int needs_free; +}; + +static int perctrl_privdata_cmp(void *av, void *bv) +{ + struct perctrl_privdata *a = (struct perctrl_privdata *)av; + struct perctrl_privdata *b = (struct perctrl_privdata *)bv; + if (a->ctrl < b->ctrl) + return -1; + else if (a->ctrl > b->ctrl) + return +1; + return 0; +} + +void dp_init(struct dlgparam *dp) +{ + dp->nctrltrees = 0; + dp->data = NULL; + dp->ended = FALSE; + dp->focused = dp->lastfocused = NULL; + memset(dp->shortcuts, 0, sizeof(dp->shortcuts)); + dp->hwnd = NULL; + dp->wintitle = dp->errtitle = NULL; + dp->privdata = newtree234(perctrl_privdata_cmp); +} + +void dp_add_tree(struct dlgparam *dp, struct winctrls *wc) +{ + assert(dp->nctrltrees < lenof(dp->controltrees)); + dp->controltrees[dp->nctrltrees++] = wc; +} + +void dp_cleanup(struct dlgparam *dp) +{ + struct perctrl_privdata *p; + + if (dp->privdata) { + while ( (p = index234(dp->privdata, 0)) != NULL ) { + del234(dp->privdata, p); + if (p->needs_free) + sfree(p->data); + sfree(p); + } + freetree234(dp->privdata); + dp->privdata = NULL; + } + sfree(dp->wintitle); + sfree(dp->errtitle); +} + +void *dlg_get_privdata(union control *ctrl, void *dlg) +{ + struct dlgparam *dp = (struct dlgparam *)dlg; + struct perctrl_privdata tmp, *p; + tmp.ctrl = ctrl; + p = find234(dp->privdata, &tmp, NULL); + if (p) + return p->data; + else + return NULL; +} + +void dlg_set_privdata(union control *ctrl, void *dlg, void *ptr) +{ + struct dlgparam *dp = (struct dlgparam *)dlg; + struct perctrl_privdata tmp, *p; + tmp.ctrl = ctrl; + p = find234(dp->privdata, &tmp, NULL); + if (!p) { + p = snew(struct perctrl_privdata); + p->ctrl = ctrl; + p->needs_free = FALSE; + add234(dp->privdata, p); + } + p->data = ptr; +} + +void *dlg_alloc_privdata(union control *ctrl, void *dlg, size_t size) +{ + struct dlgparam *dp = (struct dlgparam *)dlg; + struct perctrl_privdata tmp, *p; + tmp.ctrl = ctrl; + p = find234(dp->privdata, &tmp, NULL); + if (!p) { + p = snew(struct perctrl_privdata); + p->ctrl = ctrl; + p->needs_free = FALSE; + add234(dp->privdata, p); + } + assert(!p->needs_free); + p->needs_free = TRUE; + /* + * This is an internal allocation routine, so it's allowed to + * use smalloc directly. + */ + p->data = smalloc(size); + return p->data; +}