Missing assert.
[sgt/putty] / windows / winctrls.c
index 0fb4b9f..72d462e 100644 (file)
@@ -148,44 +148,29 @@ void endbox(struct ctlpos *cp)
 }
 
 /*
- * Some edit boxes. Each one has a static above it. The percentages
- * of the horizontal space are provided.
+ * A static line, followed by a full-width edit box.
  */
-void multiedit(struct ctlpos *cp, int password, ...)
+void editboxfw(struct ctlpos *cp, int password, char *text,
+              int staticid, int editid)
 {
     RECT r;
-    va_list ap;
-    int percent, xpos;
-
-    percent = xpos = 0;
-    va_start(ap, password);
-    while (1) {
-       char *text;
-       int staticid, editid, pcwidth;
-       text = va_arg(ap, char *);
-       if (!text)
-           break;
-       staticid = va_arg(ap, int);
-       editid = va_arg(ap, int);
-       pcwidth = va_arg(ap, int);
 
-       r.left = xpos + GAPBETWEEN;
-       percent += pcwidth;
-       xpos = (cp->width + GAPBETWEEN) * percent / 100;
-       r.right = xpos - r.left;
+    r.left = GAPBETWEEN;
+    r.right = cp->width;
 
+    if (text) {
        r.top = cp->ypos;
        r.bottom = STATICHEIGHT;
        doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, text, staticid);
-       r.top = cp->ypos + 8 + GAPWITHIN;
-       r.bottom = EDITHEIGHT;
-       doctl(cp, r, "EDIT",
-             WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL |
-             (password ? ES_PASSWORD : 0),
-             WS_EX_CLIENTEDGE, "", editid);
+       cp->ypos += STATICHEIGHT + GAPWITHIN;
     }
-    va_end(ap);
-    cp->ypos += STATICHEIGHT + GAPWITHIN + EDITHEIGHT + GAPBETWEEN;
+    r.top = cp->ypos;
+    r.bottom = EDITHEIGHT;
+    doctl(cp, r, "EDIT",
+         WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL |
+         (password ? ES_PASSWORD : 0),
+         WS_EX_CLIENTEDGE, "", editid);
+    cp->ypos += EDITHEIGHT + GAPBETWEEN;
 }
 
 /*
@@ -198,16 +183,18 @@ void combobox(struct ctlpos *cp, char *text, int staticid, int listid)
     r.left = GAPBETWEEN;
     r.right = cp->width;
 
+    if (text) {
+       r.top = cp->ypos;
+       r.bottom = STATICHEIGHT;
+       doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, text, staticid);
+       cp->ypos += STATICHEIGHT + GAPWITHIN;
+    }
     r.top = cp->ypos;
-    r.bottom = STATICHEIGHT;
-    doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, text, staticid);
-    r.top = cp->ypos + 8 + GAPWITHIN;
     r.bottom = COMBOHEIGHT * 10;
     doctl(cp, r, "COMBOBOX",
          WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL |
          CBS_DROPDOWN | CBS_HASSTRINGS, WS_EX_CLIENTEDGE, "", listid);
-
-    cp->ypos += STATICHEIGHT + GAPWITHIN + COMBOHEIGHT + GAPBETWEEN;
+    cp->ypos += COMBOHEIGHT + GAPBETWEEN;
 }
 
 struct radio { char *text; int id; };
@@ -461,6 +448,8 @@ char *staticwrap(struct ctlpos *cp, HWND hwnd, char *text, int *lines)
 
     if (lines) *lines = nlines;
 
+    sfree(pwidths);
+
     return ret;
 }
 
@@ -670,7 +659,7 @@ void staticddl(struct ctlpos *cp, char *stext,
     r.right = rwid;
     r.bottom = COMBOHEIGHT*4;
     doctl(cp, r, "COMBOBOX",
-         WS_CHILD | WS_VISIBLE | WS_TABSTOP |
+         WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL |
          CBS_DROPDOWNLIST | CBS_HASSTRINGS, WS_EX_CLIENTEDGE, "", lid);
 
     cp->ypos += height + GAPBETWEEN;
@@ -717,19 +706,21 @@ void staticddlbig(struct ctlpos *cp, char *stext,
 {
     RECT r;
 
-    r.left = GAPBETWEEN;
-    r.top = cp->ypos;
-    r.right = cp->width;
-    r.bottom = STATICHEIGHT;
-    doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
-    cp->ypos += STATICHEIGHT;
+    if (stext) {
+       r.left = GAPBETWEEN;
+       r.top = cp->ypos;
+       r.right = cp->width;
+       r.bottom = STATICHEIGHT;
+       doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
+       cp->ypos += STATICHEIGHT;
+    }
 
     r.left = GAPBETWEEN;
     r.top = cp->ypos;
     r.right = cp->width;
     r.bottom = COMBOHEIGHT*4;
     doctl(cp, r, "COMBOBOX",
-         WS_CHILD | WS_VISIBLE | WS_TABSTOP |
+         WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL |
          CBS_DROPDOWNLIST | CBS_HASSTRINGS, WS_EX_CLIENTEDGE, "", lid);
     cp->ypos += COMBOHEIGHT + GAPBETWEEN;
 }
@@ -742,12 +733,14 @@ void bigeditctrl(struct ctlpos *cp, char *stext,
 {
     RECT r;
 
-    r.left = GAPBETWEEN;
-    r.top = cp->ypos;
-    r.right = cp->width;
-    r.bottom = STATICHEIGHT;
-    cp->ypos += r.bottom + GAPWITHIN;
-    doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
+    if (stext) {
+       r.left = GAPBETWEEN;
+       r.top = cp->ypos;
+       r.right = cp->width;
+       r.bottom = STATICHEIGHT;
+       cp->ypos += r.bottom + GAPWITHIN;
+       doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
+    }
 
     r.left = GAPBETWEEN;
     r.top = cp->ypos;
@@ -1048,6 +1041,10 @@ int handle_prefslist(struct prefslist *hdl,
             int dest = 0;             /* initialise to placate gcc */
             switch (dlm->uNotification) {
               case DL_BEGINDRAG:
+               /* Add a dummy item to make pl_itemfrompt() work
+                * better.
+                * FIXME: this causes scrollbar glitches if the count of
+                *        listbox contains >= its height. */
                hdl->dummyitem =
                    SendDlgItemMessage(hwnd, hdl->listid,
                                       LB_ADDSTRING, 0, (LPARAM) "");
@@ -1055,7 +1052,7 @@ int handle_prefslist(struct prefslist *hdl,
                 hdl->srcitem = LBItemFromPt(dlm->hWnd, dlm->ptCursor, TRUE);
                hdl->dragging = 0;
                /* XXX hack Q183115 */
-               SetWindowLong(hwnd, DWL_MSGRESULT, TRUE);
+               SetWindowLongPtr(hwnd, DWLP_MSGRESULT, TRUE);
                 ret |= 1; break;
               case DL_CANCELDRAG:
                DrawInsert(hwnd, dlm->hWnd, -1);     /* Clear arrow */
@@ -1069,9 +1066,9 @@ int handle_prefslist(struct prefslist *hdl,
                if (dest > hdl->dummyitem) dest = hdl->dummyitem;
                DrawInsert (hwnd, dlm->hWnd, dest);
                if (dest >= 0)
-                   SetWindowLong(hwnd, DWL_MSGRESULT, DL_MOVECURSOR);
+                   SetWindowLongPtr(hwnd, DWLP_MSGRESULT, DL_MOVECURSOR);
                else
-                   SetWindowLong(hwnd, DWL_MSGRESULT, DL_STOPCURSOR);
+                   SetWindowLongPtr(hwnd, DWLP_MSGRESULT, DL_STOPCURSOR);
                 ret |= 1; break;
               case DL_DROPPED:
                if (hdl->dragging) {
@@ -1166,10 +1163,11 @@ void progressbar(struct ctlpos *cp, int id)
  * Return value is a malloc'ed copy of the processed version of the
  * string.
  */
-static char *shortcut_escape(char *text, char shortcut)
+static char *shortcut_escape(const char *text, char shortcut)
 {
     char *ret;
-    char *p, *q;
+    char const *p;
+    char *q;
 
     if (!text)
        return NULL;                   /* sfree won't choke on this */
@@ -1295,6 +1293,7 @@ void winctrl_remove(struct winctrls *wc, struct winctrl *c)
 {
     struct winctrl *ret;
     ret = del234(wc->byctrl, c);
+    assert(ret == c);
     ret = del234(wc->byid, c);
     assert(ret == c);
 }
@@ -1508,8 +1507,8 @@ void winctrl_layout(struct dlgparam *dp, struct winctrls *wc,
                    combobox(&pos, escaped,
                             base_id, base_id+1);
                else
-                   multiedit(&pos, ctrl->editbox.password, escaped,
-                             base_id, base_id+1, 100, NULL);
+                   editboxfw(&pos, ctrl->editbox.password, escaped,
+                             base_id, base_id+1);
            } else {
                if (ctrl->editbox.has_list) {
                    staticcombo(&pos, escaped, base_id, base_id+1,
@@ -1643,8 +1642,8 @@ void winctrl_layout(struct dlgparam *dp, struct winctrls *wc,
            shortcuts[nshortcuts++] = ctrl->fontselect.shortcut;
            statictext(&pos, escaped, 1, base_id);
            staticbtn(&pos, "", base_id+1, "Change...", base_id+2);
+            data = fontspec_new("", 0, 0, 0);
            sfree(escaped);
-           data = snew(FontSpec);
            break;
          default:
            assert(!"Can't happen");
@@ -1669,7 +1668,9 @@ void winctrl_layout(struct dlgparam *dp, struct winctrls *wc,
            winctrl_add_shortcuts(dp, c);
            if (actual_base_id == base_id)
                base_id += num_ids;
-       }
+       } else {
+            sfree(data);
+        }
 
        if (colstart >= 0) {
            /*
@@ -1905,14 +1906,8 @@ int winctrl_handle_command(struct dlgparam *dp, UINT msg,
              HIWORD(wParam) == BN_DOUBLECLICKED))) {
            OPENFILENAME of;
            char filename[FILENAME_MAX];
-           int ret;
 
            memset(&of, 0, sizeof(of));
-#ifdef OPENFILENAME_SIZE_VERSION_400
-           of.lStructSize = OPENFILENAME_SIZE_VERSION_400;
-#else
-           of.lStructSize = sizeof(of);
-#endif
            of.hwndOwner = dp->hwnd;
            if (ctrl->fileselect.filter)
                of.lpstrFilter = ctrl->fileselect.filter;
@@ -1925,14 +1920,9 @@ int winctrl_handle_command(struct dlgparam *dp, UINT msg,
            filename[lenof(filename)-1] = '\0';
            of.nMaxFile = lenof(filename);
            of.lpstrFileTitle = NULL;
-           of.lpstrInitialDir = NULL;
            of.lpstrTitle = ctrl->fileselect.title;
            of.Flags = 0;
-           if (ctrl->fileselect.for_writing)
-               ret = GetSaveFileName(&of);
-           else
-               ret = GetOpenFileName(&of);
-           if (ret) {
+           if (request_file(NULL, &of, FALSE, ctrl->fileselect.for_writing)) {
                SetDlgItemText(dp->hwnd, c->base_id + 1, filename);
                ctrl->generic.handler(ctrl, dp, dp->data, EVENT_VALCHANGE);
            }
@@ -1949,38 +1939,36 @@ int winctrl_handle_command(struct dlgparam *dp, UINT msg,
            CHOOSEFONT cf;
            LOGFONT lf;
            HDC hdc;
-           FontSpec fs = *(FontSpec *)c->data;
-           
+           FontSpec *fs = (FontSpec *)c->data;
+
            hdc = GetDC(0);
-           lf.lfHeight = -MulDiv(fs.height,
+           lf.lfHeight = -MulDiv(fs->height,
                                  GetDeviceCaps(hdc, LOGPIXELSY), 72);
            ReleaseDC(0, hdc);
            lf.lfWidth = lf.lfEscapement = lf.lfOrientation = 0;
            lf.lfItalic = lf.lfUnderline = lf.lfStrikeOut = 0;
-           lf.lfWeight = (fs.isbold ? FW_BOLD : 0);
-           lf.lfCharSet = fs.charset;
+           lf.lfWeight = (fs->isbold ? FW_BOLD : 0);
+           lf.lfCharSet = fs->charset;
            lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
            lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
            lf.lfQuality = DEFAULT_QUALITY;
            lf.lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE;
-           strncpy(lf.lfFaceName, fs.name,
+           strncpy(lf.lfFaceName, fs->name,
                    sizeof(lf.lfFaceName) - 1);
            lf.lfFaceName[sizeof(lf.lfFaceName) - 1] = '\0';
 
            cf.lStructSize = sizeof(cf);
            cf.hwndOwner = dp->hwnd;
            cf.lpLogFont = &lf;
-           cf.Flags = CF_FIXEDPITCHONLY | CF_FORCEFONTEXIST |
-               CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS;
+           cf.Flags = (dp->fixed_pitch_fonts ? CF_FIXEDPITCHONLY : 0) |
+                CF_FORCEFONTEXIST | CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS;
 
            if (ChooseFont(&cf)) {
-               strncpy(fs.name, lf.lfFaceName,
-                       sizeof(fs.name) - 1);
-               fs.name[sizeof(fs.name) - 1] = '\0';
-               fs.isbold = (lf.lfWeight == FW_BOLD);
-               fs.charset = lf.lfCharSet;
-               fs.height = cf.iPointSize / 10;
+                fs = fontspec_new(lf.lfFaceName, (lf.lfWeight == FW_BOLD),
+                                  cf.iPointSize / 10, lf.lfCharSet);
                dlg_fontsel_set(ctrl, dp, fs);
+                fontspec_free(fs);
+
                ctrl->generic.handler(ctrl, dp, dp->data, EVENT_VALCHANGE);
            }
        }
@@ -2020,13 +2008,12 @@ int winctrl_handle_command(struct dlgparam *dp, UINT msg,
 
 /*
  * This function can be called to produce context help on a
- * control. Returns TRUE if it has actually launched WinHelp.
+ * control. Returns TRUE if it has actually launched some help.
  */
 int winctrl_context_help(struct dlgparam *dp, HWND hwnd, int id)
 {
     int i;
     struct winctrl *c;
-    char *cmd;
 
     /*
      * Look up the control ID in our data.
@@ -2047,9 +2034,7 @@ int winctrl_context_help(struct dlgparam *dp, HWND hwnd, int id)
     if (!c->ctrl || !c->ctrl->generic.helpctx.p)
        return 0;                      /* no help available for this ctrl */
 
-    cmd = dupprintf("JI(`',`%s')", c->ctrl->generic.helpctx.p);
-    WinHelp(hwnd, help_path, HELP_COMMAND, (DWORD)cmd);
-    sfree(cmd);
+    launch_help(hwnd, c->ctrl->generic.helpctx.p);
     return 1;
 }
 
@@ -2118,13 +2103,12 @@ void dlg_editbox_set(union control *ctrl, void *dlg, char const *text)
     SetDlgItemText(dp->hwnd, c->base_id+1, text);
 }
 
-void dlg_editbox_get(union control *ctrl, void *dlg, char *buffer, int length)
+char *dlg_editbox_get(union control *ctrl, void *dlg)
 {
     struct dlgparam *dp = (struct dlgparam *)dlg;
     struct winctrl *c = dlg_findbyctrl(dp, ctrl);
     assert(c && c->ctrl->generic.type == CTRL_EDITBOX);
-    GetDlgItemText(dp->hwnd, c->base_id+1, buffer, length);
-    buffer[length-1] = '\0';
+    return GetDlgItemText_alloc(dp->hwnd, c->base_id+1);
 }
 
 /* The `listbox' functions can also apply to combo boxes. */
@@ -2212,8 +2196,13 @@ int dlg_listbox_index(union control *ctrl, void *dlg)
     struct dlgparam *dp = (struct dlgparam *)dlg;
     struct winctrl *c = dlg_findbyctrl(dp, ctrl);
     int msg, ret;
-    assert(c && c->ctrl->generic.type == CTRL_LISTBOX &&
-          !c->ctrl->listbox.multisel);
+    assert(c && c->ctrl->generic.type == CTRL_LISTBOX);
+    if (c->ctrl->listbox.multisel) {
+       assert(c->ctrl->listbox.height != 0); /* not combo box */
+       ret = SendDlgItemMessage(dp->hwnd, c->base_id+1, LB_GETSELCOUNT, 0, 0);
+       if (ret == LB_ERR || ret > 1)
+           return -1;
+    }
     msg = (c->ctrl->listbox.height != 0 ? LB_GETCURSEL : CB_GETCURSEL);
     ret = SendDlgItemMessage(dp->hwnd, c->base_id+1, msg, 0, 0);
     if (ret == LB_ERR)
@@ -2252,49 +2241,103 @@ void dlg_text_set(union control *ctrl, void *dlg, char const *text)
     SetDlgItemText(dp->hwnd, c->base_id, text);
 }
 
-void dlg_filesel_set(union control *ctrl, void *dlg, Filename fn)
+void dlg_label_change(union control *ctrl, void *dlg, char const *text)
+{
+    struct dlgparam *dp = (struct dlgparam *)dlg;
+    struct winctrl *c = dlg_findbyctrl(dp, ctrl);
+    char *escaped = NULL;
+    int id = -1;
+
+    assert(c);
+    switch (c->ctrl->generic.type) {
+      case CTRL_EDITBOX:
+       escaped = shortcut_escape(text, c->ctrl->editbox.shortcut);
+       id = c->base_id;
+       break;
+      case CTRL_RADIO:
+       escaped = shortcut_escape(text, c->ctrl->radio.shortcut);
+       id = c->base_id;
+       break;
+      case CTRL_CHECKBOX:
+       escaped = shortcut_escape(text, ctrl->checkbox.shortcut);
+       id = c->base_id;
+       break;
+      case CTRL_BUTTON:
+       escaped = shortcut_escape(text, ctrl->button.shortcut);
+       id = c->base_id;
+       break;
+      case CTRL_LISTBOX:
+       escaped = shortcut_escape(text, ctrl->listbox.shortcut);
+       id = c->base_id;
+       break;
+      case CTRL_FILESELECT:
+       escaped = shortcut_escape(text, ctrl->fileselect.shortcut);
+       id = c->base_id;
+       break;
+      case CTRL_FONTSELECT:
+       escaped = shortcut_escape(text, ctrl->fontselect.shortcut);
+       id = c->base_id;
+       break;
+      default:
+       assert(!"Can't happen");
+       break;
+    }
+    if (escaped) {
+       SetDlgItemText(dp->hwnd, id, escaped);
+       sfree(escaped);
+    }
+}
+
+void dlg_filesel_set(union control *ctrl, void *dlg, Filename *fn)
 {
     struct dlgparam *dp = (struct dlgparam *)dlg;
     struct winctrl *c = dlg_findbyctrl(dp, ctrl);
     assert(c && c->ctrl->generic.type == CTRL_FILESELECT);
-    SetDlgItemText(dp->hwnd, c->base_id+1, fn.path);
+    SetDlgItemText(dp->hwnd, c->base_id+1, fn->path);
 }
 
-void dlg_filesel_get(union control *ctrl, void *dlg, Filename *fn)
+Filename *dlg_filesel_get(union control *ctrl, void *dlg)
 {
     struct dlgparam *dp = (struct dlgparam *)dlg;
     struct winctrl *c = dlg_findbyctrl(dp, ctrl);
+    char *tmp;
+    Filename *ret;
     assert(c && c->ctrl->generic.type == CTRL_FILESELECT);
-    GetDlgItemText(dp->hwnd, c->base_id+1, fn->path, lenof(fn->path));
-    fn->path[lenof(fn->path)-1] = '\0';
+    tmp = GetDlgItemText_alloc(dp->hwnd, c->base_id+1);
+    ret = filename_from_str(tmp);
+    sfree(tmp);
+    return ret;
 }
 
-void dlg_fontsel_set(union control *ctrl, void *dlg, FontSpec fs)
+void dlg_fontsel_set(union control *ctrl, void *dlg, FontSpec *fs)
 {
     char *buf, *boldstr;
     struct dlgparam *dp = (struct dlgparam *)dlg;
     struct winctrl *c = dlg_findbyctrl(dp, ctrl);
     assert(c && c->ctrl->generic.type == CTRL_FONTSELECT);
 
-    *(FontSpec *)c->data = fs;        /* structure copy */
+    fontspec_free((FontSpec *)c->data);
+    c->data = fontspec_copy(fs);
 
-    boldstr = (fs.isbold ? "bold, " : "");
-    if (fs.height == 0)
-       buf = dupprintf("Font: %s, %sdefault height", fs.name, boldstr);
+    boldstr = (fs->isbold ? "bold, " : "");
+    if (fs->height == 0)
+       buf = dupprintf("Font: %s, %sdefault height", fs->name, boldstr);
     else
-       buf = dupprintf("Font: %s, %s%d-%s", fs.name, boldstr,
-                       (fs.height < 0 ? -fs.height : fs.height),
-                       (fs.height < 0 ? "pixel" : "point"));
+       buf = dupprintf("Font: %s, %s%d-%s", fs->name, boldstr,
+                       (fs->height < 0 ? -fs->height : fs->height),
+                       (fs->height < 0 ? "pixel" : "point"));
     SetDlgItemText(dp->hwnd, c->base_id+1, buf);
     sfree(buf);
+
+    dlg_auto_set_fixed_pitch_flag(dp);
 }
 
-void dlg_fontsel_get(union control *ctrl, void *dlg, FontSpec *fs)
+FontSpec *dlg_fontsel_get(union control *ctrl, void *dlg)
 {
     struct dlgparam *dp = (struct dlgparam *)dlg;
     struct winctrl *c = dlg_findbyctrl(dp, ctrl);
     assert(c && c->ctrl->generic.type == CTRL_FONTSELECT);
-    *fs = *(FontSpec *)c->data;               /* structure copy */
+    return fontspec_copy((FontSpec *)c->data);
 }
 
 /*
@@ -2328,6 +2371,8 @@ void dlg_set_focus(union control *ctrl, void *dlg)
     struct winctrl *c = dlg_findbyctrl(dp, ctrl);
     int id;
     HWND ctl;
+    if (!c)
+        return;
     switch (ctrl->generic.type) {
       case CTRL_EDITBOX: id = c->base_id + 1; break;
       case CTRL_RADIO:
@@ -2432,6 +2477,62 @@ int dlg_coloursel_results(union control *ctrl, void *dlg,
        return 0;
 }
 
+void dlg_auto_set_fixed_pitch_flag(void *dlg)
+{
+    struct dlgparam *dp = (struct dlgparam *)dlg;
+    Conf *conf = (Conf *)dp->data;
+    FontSpec *fs;
+    int quality;
+    HFONT hfont;
+    HDC hdc;
+    TEXTMETRIC tm;
+    int is_var;
+
+    /*
+     * Attempt to load the current font, and see if it's
+     * variable-pitch. If so, start off the fixed-pitch flag for the
+     * dialog box as false.
+     *
+     * We assume here that any client of the dlg_* mechanism which is
+     * using font selectors at all is also using a normal 'Conf *'
+     * as dp->data.
+     */
+
+    quality = conf_get_int(conf, CONF_font_quality);
+    fs = conf_get_fontspec(conf, CONF_font);
+
+    hfont = CreateFont(0, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE,
+                       DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
+                       CLIP_DEFAULT_PRECIS, FONT_QUALITY(quality),
+                       FIXED_PITCH | FF_DONTCARE, fs->name);
+    hdc = GetDC(NULL);
+    if (hdc && SelectObject(hdc, hfont) && GetTextMetrics(hdc, &tm)) {
+        /* Note that the TMPF_FIXED_PITCH bit is defined upside down :-( */
+        is_var = (tm.tmPitchAndFamily & TMPF_FIXED_PITCH);
+    } else {
+        is_var = FALSE;                /* assume it's basically normal */
+    }
+    if (hdc)
+        ReleaseDC(NULL, hdc);
+    if (hfont)
+        DeleteObject(hfont);
+
+    if (is_var)
+        dp->fixed_pitch_fonts = FALSE;
+}
+
+int dlg_get_fixed_pitch_flag(void *dlg)
+{
+    struct dlgparam *dp = (struct dlgparam *)dlg;
+    return dp->fixed_pitch_fonts;
+}
+
+void dlg_set_fixed_pitch_flag(void *dlg, int flag)
+{
+    struct dlgparam *dp = (struct dlgparam *)dlg;
+    dp->fixed_pitch_fonts = flag;
+}
+
 struct perctrl_privdata {
     union control *ctrl;
     void *data;
@@ -2459,6 +2560,7 @@ void dp_init(struct dlgparam *dp)
     dp->hwnd = NULL;
     dp->wintitle = dp->errtitle = NULL;
     dp->privdata = newtree234(perctrl_privdata_cmp);
+    dp->fixed_pitch_fonts = TRUE;
 }
 
 void dp_add_tree(struct dlgparam *dp, struct winctrls *wc)