The WinSock library is now loaded at run-time, which means we can
[u/mdw/putty] / winctrls.c
index dc931c8..4a35cb6 100644 (file)
  *    button.
  */
 
-#include <windows.h>
-#include <commctrl.h>
 #include <assert.h>
 #include <ctype.h>
 
-#include "winstuff.h"
+#include "putty.h"
 #include "misc.h"
 #include "dialog.h"
-#include "puttymem.h"
 
-#include "putty.h"
+#include <commctrl.h>
 
 #define GAPBETWEEN 3
 #define GAPWITHIN 1
@@ -287,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 *);
@@ -320,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 *);
@@ -351,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 *);
@@ -395,10 +393,10 @@ char *staticwrap(struct ctlpos *cp, HWND hwnd, char *text, int *lines)
     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
@@ -973,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. */
@@ -1176,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;
@@ -1331,14 +1329,14 @@ void winctrl_layout(struct dlgparam *dp, struct winctrls *wc,
     char shortcuts[MAX_SHORTCUTS_PER_CTRL];
     int nshortcuts;
     char *escaped;
-    int i, base_id, num_ids;
+    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;
@@ -1351,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;
@@ -1479,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.
@@ -1531,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 =
@@ -1569,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:
@@ -1579,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);
@@ -1611,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];
@@ -1641,7 +1644,7 @@ 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");
@@ -1655,16 +1658,17 @@ 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 (colstart >= 0) {
@@ -1705,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;
 }
 
 /*
@@ -1808,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);
@@ -1893,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 ||
@@ -2171,8 +2177,8 @@ 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);
@@ -2424,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;
+}