]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - mac/macctrls.c
0ee332c746df91f770343179e827363ca74fafda
[PuTTY.git] / mac / macctrls.c
1 /* $Id: macctrls.c,v 1.26 2003/04/05 15:08:17 ben Exp $ */
2 /*
3  * Copyright (c) 2003 Ben Harris
4  * All rights reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person
7  * obtaining a copy of this software and associated documentation
8  * files (the "Software"), to deal in the Software without
9  * restriction, including without limitation the rights to use,
10  * copy, modify, merge, publish, distribute, sublicense, and/or
11  * sell copies of the Software, and to permit persons to whom the
12  * Software is furnished to do so, subject to the following
13  * conditions:
14  * 
15  * The above copyright notice and this permission notice shall be
16  * included in all copies or substantial portions of the Software.
17  * 
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21  * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
22  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
23  * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25  * SOFTWARE.
26  */
27
28 #include <MacTypes.h>
29 #include <Appearance.h>
30 #include <Controls.h>
31 #include <ControlDefinitions.h>
32 #include <Menus.h>
33 #include <Resources.h>
34 #include <Script.h>
35 #include <Sound.h>
36 #include <TextEdit.h>
37 #include <TextUtils.h>
38 #include <ToolUtils.h>
39 #include <Windows.h>
40
41 #include <assert.h>
42 #include <string.h>
43
44 #include "putty.h"
45 #include "mac.h"
46 #include "macresid.h"
47 #include "dialog.h"
48 #include "tree234.h"
49
50 /* Range of menu IDs for popup menus */
51 #define MENU_MIN        1024
52 #define MENU_MAX        2048
53
54
55 union macctrl {
56     struct macctrl_generic {
57         enum {
58             MACCTRL_TEXT,
59             MACCTRL_EDITBOX,
60             MACCTRL_RADIO,
61             MACCTRL_CHECKBOX,
62             MACCTRL_BUTTON,
63             MACCTRL_POPUP
64         } type;
65         /* Template from which this was generated */
66         union control *ctrl;
67         /* Next control in this panel */
68         union macctrl *next;
69         void *privdata;
70         int freeprivdata;
71     } generic;
72     struct {
73         struct macctrl_generic generic;
74         ControlRef tbctrl;
75     } text;
76     struct {
77         struct macctrl_generic generic;
78         ControlRef tbctrl;
79         ControlRef tblabel;
80     } editbox;
81     struct {
82         struct macctrl_generic generic;
83         ControlRef *tbctrls;
84         ControlRef tblabel;
85     } radio;
86     struct {
87         struct macctrl_generic generic;
88         ControlRef tbctrl;
89     } checkbox;
90     struct {
91         struct macctrl_generic generic;
92         ControlRef tbctrl;
93     } button;
94     struct {
95         struct macctrl_generic generic;
96         ControlRef tbctrl;
97         MenuRef menu;
98         int menuid;
99         unsigned int nids;
100         int *ids;
101     } popup;
102 };
103
104 struct mac_layoutstate {
105     Point pos;
106     unsigned int width;
107     unsigned int panelnum;
108 };
109
110 #define ctrlevent(mcs, mc, event) do {                                  \
111     if ((mc)->generic.ctrl->generic.handler != NULL)                    \
112         (*(mc)->generic.ctrl->generic.handler)((mc)->generic.ctrl, (mcs),\
113                                                (mcs)->data, (event));   \
114 } while (0)
115
116 #define findbyctrl(mcs, ctrl)                                           \
117     find234((mcs)->byctrl, (ctrl), macctrl_cmp_byctrl_find)
118
119 static void macctrl_layoutset(struct mac_layoutstate *, struct controlset *, 
120                               WindowPtr, struct macctrls *);
121 static void macctrl_switchtopanel(struct macctrls *, unsigned int);
122 static void macctrl_setfocus(struct macctrls *, union macctrl *);
123 static void macctrl_text(struct macctrls *, WindowPtr,
124                          struct mac_layoutstate *, union control *);
125 static void macctrl_editbox(struct macctrls *, WindowPtr,
126                             struct mac_layoutstate *, union control *);
127 static void macctrl_radio(struct macctrls *, WindowPtr,
128                           struct mac_layoutstate *, union control *);
129 static void macctrl_checkbox(struct macctrls *, WindowPtr,
130                              struct mac_layoutstate *, union control *);
131 static void macctrl_button(struct macctrls *, WindowPtr,
132                            struct mac_layoutstate *, union control *);
133 static void macctrl_popup(struct macctrls *, WindowPtr,
134                           struct mac_layoutstate *, union control *);
135 #if !TARGET_API_MAC_CARBON
136 static pascal SInt32 macctrl_sys7_editbox_cdef(SInt16, ControlRef,
137                                                ControlDefProcMessage, SInt32);
138 static pascal SInt32 macctrl_sys7_default_cdef(SInt16, ControlRef,
139                                                ControlDefProcMessage, SInt32);
140 #endif
141
142 #if !TARGET_API_MAC_CARBON
143 /*
144  * This trick enables us to keep all the CDEF code in the main
145  * application, which makes life easier.  For details, see
146  * <http://developer.apple.com/technotes/tn/tn2003.html#custom_code_base>.
147  */
148
149 #pragma options align=mac68k
150 typedef struct {
151     short               jmpabs; /* 4EF9 */
152     ControlDefUPP       theUPP;
153 } **PatchCDEF;
154 #pragma options align=reset
155 #endif
156
157 static void macctrl_init()
158 {
159 #if !TARGET_API_MAC_CARBON
160     static int inited = 0;
161     PatchCDEF cdef;
162
163     if (inited) return;
164     cdef = (PatchCDEF)GetResource(kControlDefProcResourceType, CDEF_EditBox);
165     (*cdef)->theUPP = NewControlDefProc(macctrl_sys7_editbox_cdef);
166     cdef = (PatchCDEF)GetResource(kControlDefProcResourceType, CDEF_Default);
167     (*cdef)->theUPP = NewControlDefProc(macctrl_sys7_default_cdef);
168     inited = 1;
169 #endif
170 }
171
172
173 static int macctrl_cmp_byctrl(void *av, void *bv)
174 {
175     union macctrl *a = (union macctrl *)av;
176     union macctrl *b = (union macctrl *)bv;
177
178     if (a->generic.ctrl < b->generic.ctrl)
179         return -1;
180     else if (a->generic.ctrl > b->generic.ctrl)
181         return +1;
182     else
183         return 0;
184 }
185
186 static int macctrl_cmp_byctrl_find(void *av, void *bv)
187 {
188     union control *a = (union control *)av;
189     union macctrl *b = (union macctrl *)bv;
190
191     if (a < b->generic.ctrl)
192         return -1;
193     else if (a > b->generic.ctrl)
194         return +1;
195     else
196         return 0;
197 }
198
199 void macctrl_layoutbox(struct controlbox *cb, WindowPtr window,
200                        struct macctrls *mcs)
201 {
202     int i;
203     struct mac_layoutstate curstate;
204     ControlRef root;
205     Rect rect;
206
207     macctrl_init();
208 #if TARGET_API_MAC_CARBON
209     GetPortBounds(GetWindowPort(window), &rect);
210 #else
211     rect = window->portRect;
212 #endif
213     curstate.pos.h = rect.left + 13;
214     curstate.pos.v = rect.bottom - 33;
215     curstate.width = rect.right - rect.left - (13 * 2);
216     if (mac_gestalts.apprvers >= 0x100)
217         CreateRootControl(window, &root);
218     mcs->window = window;
219     mcs->byctrl = newtree234(macctrl_cmp_byctrl);
220     mcs->focus = NULL;
221     /* Count the number of panels */
222     mcs->npanels = 1;
223     for (i = 1; i < cb->nctrlsets; i++)
224         if (strcmp(cb->ctrlsets[i]->pathname, cb->ctrlsets[i-1]->pathname))
225             mcs->npanels++;
226     mcs->panels = snewn(mcs->npanels, union macctrl *);
227     memset(mcs->panels, 0, sizeof(*mcs->panels) * mcs->npanels);
228     curstate.panelnum = 0;
229     for (i = 0; i < cb->nctrlsets; i++) {
230         if (i > 0 && strcmp(cb->ctrlsets[i]->pathname,
231                             cb->ctrlsets[i-1]->pathname)) {
232             curstate.pos.v = rect.top + 13;
233             curstate.panelnum++;
234             assert(curstate.panelnum < mcs->npanels);
235         }
236         macctrl_layoutset(&curstate, cb->ctrlsets[i], window, mcs);
237     }
238     macctrl_switchtopanel(mcs, 1);
239     /* 14 = proxies, 20 = SSH bugs */
240 }
241
242 #define MAXCOLS 16
243
244 static void macctrl_layoutset(struct mac_layoutstate *curstate,
245                               struct controlset *s,
246                               WindowPtr window, struct macctrls *mcs)
247 {
248     unsigned int i, j, ncols, colstart;
249     struct mac_layoutstate cols[MAXCOLS];
250
251     fprintf(stderr, "--- begin set ---\n");
252     fprintf(stderr, "pathname = %s\n", s->pathname);
253     if (s->boxname && *s->boxname)
254         fprintf(stderr, "boxname = %s\n", s->boxname);
255     if (s->boxtitle)
256         fprintf(stderr, "boxtitle = %s\n", s->boxtitle);
257
258     cols[0] = *curstate;
259     ncols = 1;
260
261     for (i = 0; i < s->ncontrols; i++) {
262         union control *ctrl = s->ctrls[i];
263         char const *s;
264
265         colstart = COLUMN_START(ctrl->generic.column);
266         switch (ctrl->generic.type) {
267           case CTRL_TEXT: s = "text"; break;
268           case CTRL_EDITBOX: s = "editbox"; break;
269           case CTRL_RADIO: s = "radio"; break;
270           case CTRL_CHECKBOX: s = "checkbox"; break;
271           case CTRL_BUTTON: s = "button"; break;
272           case CTRL_LISTBOX: s = "listbox"; break;
273           case CTRL_COLUMNS: s = "columns"; break;
274           case CTRL_FILESELECT: s = "fileselect"; break;
275           case CTRL_FONTSELECT: s = "fontselect"; break;
276           case CTRL_TABDELAY: s = "tabdelay"; break;
277           default: s = "unknown"; break;
278         }
279         fprintf(stderr, "  control: %s\n", s);
280         switch (ctrl->generic.type) {
281           case CTRL_COLUMNS:
282             if (ctrl->columns.ncols != 1) {
283                 ncols = ctrl->columns.ncols;
284                 fprintf(stderr, "  split to %d\n", ncols);
285                 assert(ncols <= MAXCOLS);
286                 for (j = 0; j < ncols; j++) {
287                     cols[j] = cols[0];
288                     if (j > 0)
289                         cols[j].pos.h = cols[j-1].pos.h + cols[j-1].width + 6;
290                     if (j == ncols - 1)
291                         cols[j].width = curstate->width -
292                             (cols[j].pos.h - curstate->pos.h);
293                     else
294                         cols[j].width = (curstate->width + 6) * 
295                             ctrl->columns.percentages[j] / 100 - 6;
296                 }
297             } else {
298                 fprintf(stderr, "  join\n");
299                 for (j = 0; j < ncols; j++)
300                     if (cols[j].pos.v > cols[0].pos.v)
301                         cols[0].pos.v = cols[j].pos.v;
302                 cols[0].width = curstate->width;
303                 ncols = 1;
304             }
305             break;
306           case CTRL_TEXT:
307             macctrl_text(mcs, window, &cols[colstart], ctrl);
308             break;
309           case CTRL_EDITBOX:
310             macctrl_editbox(mcs, window, &cols[colstart], ctrl);
311             break;
312           case CTRL_RADIO:
313             macctrl_radio(mcs, window, &cols[colstart], ctrl);
314             break;
315           case CTRL_CHECKBOX:
316             macctrl_checkbox(mcs, window, &cols[colstart], ctrl);
317             break;
318           case CTRL_BUTTON:
319             macctrl_button(mcs, window, &cols[colstart], ctrl);
320             break;
321           case CTRL_LISTBOX:
322             if (ctrl->listbox.height == 0)
323                 macctrl_popup(mcs, window, &cols[colstart], ctrl);
324             break;
325         }
326     }
327     for (j = 0; j < ncols; j++)
328         if (cols[j].pos.v > curstate->pos.v)
329             curstate->pos.v = cols[j].pos.v;
330 }
331
332 static void macctrl_switchtopanel(struct macctrls *mcs, unsigned int which)
333 {
334     unsigned int i, j;
335     union macctrl *mc;
336
337 #define hideshow(c) do {                                                \
338     if (i == which) ShowControl(c); else HideControl(c);                \
339 } while (0)
340
341     mcs->curpanel = which;
342     /* Panel 0 is special and always visible. */
343     for (i = 1; i < mcs->npanels; i++)
344         for (mc = mcs->panels[i]; mc != NULL; mc = mc->generic.next) {
345 #if !TARGET_API_MAC_CARBON
346             if (mcs->focus == mc)
347                 macctrl_setfocus(mcs, NULL);
348 #endif
349             switch (mc->generic.type) {
350               case MACCTRL_TEXT:
351                 hideshow(mc->text.tbctrl);
352                 break;
353               case MACCTRL_EDITBOX:
354                 hideshow(mc->editbox.tbctrl);
355                 hideshow(mc->editbox.tblabel);
356                 break;
357               case MACCTRL_RADIO:
358                 for (j = 0; j < mc->generic.ctrl->radio.nbuttons; j++)
359                     hideshow(mc->radio.tbctrls[j]);
360                 hideshow(mc->radio.tblabel);
361                 break;
362               case MACCTRL_CHECKBOX:
363                 hideshow(mc->checkbox.tbctrl);
364                 break;
365               case MACCTRL_BUTTON:
366                 hideshow(mc->button.tbctrl);
367                 break;
368               case MACCTRL_POPUP:
369                 hideshow(mc->popup.tbctrl);
370                 break;
371             }
372         }
373 }
374
375 #if !TARGET_API_MAC_CARBON
376 /*
377  * System 7 focus manipulation
378  */
379 static void macctrl_defocus(union macctrl *mc)
380 {
381
382     assert(mac_gestalts.apprvers < 0x100);
383     switch (mc->generic.type) {
384       case MACCTRL_EDITBOX:
385         TEDeactivate((TEHandle)(*mc->editbox.tbctrl)->contrlData);
386         break;
387     }
388 }
389
390 static void macctrl_enfocus(union macctrl *mc)
391 {
392
393     assert(mac_gestalts.apprvers < 0x100);
394     switch (mc->generic.type) {
395       case MACCTRL_EDITBOX:
396         TEActivate((TEHandle)(*mc->editbox.tbctrl)->contrlData);
397         break;
398     }
399 }
400
401 static void macctrl_setfocus(struct macctrls *mcs, union macctrl *mc)
402 {
403
404     if (mcs->focus != NULL)
405         macctrl_defocus(mcs->focus);
406     mcs->focus = mc;
407     if (mc != NULL)
408         macctrl_enfocus(mc);
409 }
410 #endif
411
412 static void macctrl_text(struct macctrls *mcs, WindowPtr window,
413                          struct mac_layoutstate *curstate,
414                          union control *ctrl)
415 {
416     union macctrl *mc = snew(union macctrl);
417     Rect bounds;
418     SInt16 height;
419
420     fprintf(stderr, "    label = %s\n", ctrl->text.label);
421     mc->generic.type = MACCTRL_TEXT;
422     mc->generic.ctrl = ctrl;
423     mc->generic.privdata = NULL;
424     bounds.left = curstate->pos.h;
425     bounds.right = bounds.left + curstate->width;
426     bounds.top = curstate->pos.v;
427     bounds.bottom = bounds.top + 16;
428     if (mac_gestalts.apprvers >= 0x100) {
429         Size olen;
430
431         mc->text.tbctrl = NewControl(window, &bounds, NULL, TRUE, 0, 0, 0,
432                                      kControlStaticTextProc, (long)mc);
433         SetControlData(mc->text.tbctrl, kControlEntireControl,
434                        kControlStaticTextTextTag,
435                        strlen(ctrl->text.label), ctrl->text.label);
436         GetControlData(mc->text.tbctrl, kControlEntireControl,
437                        kControlStaticTextTextHeightTag,
438                        sizeof(height), &height, &olen);
439     }
440 #if !TARGET_API_MAC_CARBON
441     else {
442         TEHandle te;
443
444         mc->text.tbctrl = NewControl(window, &bounds, NULL, TRUE, 0, 0, 0,
445                                      SYS7_TEXT_PROC, (long)mc);
446         te = (TEHandle)(*mc->text.tbctrl)->contrlData;
447         TESetText(ctrl->text.label, strlen(ctrl->text.label), te);
448         height = TEGetHeight(1, (*te)->nLines, te);
449     }
450 #endif
451     fprintf(stderr, "    height = %d\n", height);
452     SizeControl(mc->text.tbctrl, curstate->width, height);
453     curstate->pos.v += height + 6;
454     add234(mcs->byctrl, mc);
455     mc->generic.next = mcs->panels[curstate->panelnum];
456     mcs->panels[curstate->panelnum] = mc;
457 }
458
459 static void macctrl_editbox(struct macctrls *mcs, WindowPtr window,
460                             struct mac_layoutstate *curstate,
461                             union control *ctrl)
462 {
463     union macctrl *mc = snew(union macctrl);
464     Rect lbounds, bounds;
465
466     fprintf(stderr, "    label = %s\n", ctrl->editbox.label);
467     fprintf(stderr, "    percentwidth = %d\n", ctrl->editbox.percentwidth);
468     if (ctrl->editbox.password) fprintf(stderr, "    password\n");
469     if (ctrl->editbox.has_list) fprintf(stderr, "    has list\n");
470     mc->generic.type = MACCTRL_EDITBOX;
471     mc->generic.ctrl = ctrl;
472     mc->generic.privdata = NULL;
473     lbounds.left = curstate->pos.h;
474     lbounds.top = curstate->pos.v;
475     if (ctrl->editbox.percentwidth == 100) {
476         lbounds.right = lbounds.left + curstate->width;
477         lbounds.bottom = lbounds.top + 16;
478         bounds.left = curstate->pos.h;
479         bounds.right = bounds.left + curstate->width;
480         curstate->pos.v += 18;
481     } else {
482         lbounds.right = lbounds.left +
483             curstate->width * (100 - ctrl->editbox.percentwidth) / 100;
484         lbounds.bottom = lbounds.top + 22;
485         bounds.left = lbounds.right;
486         bounds.right = lbounds.left + curstate->width;
487     }
488     bounds.top = curstate->pos.v;
489     bounds.bottom = bounds.top + 22;
490     if (mac_gestalts.apprvers >= 0x100) {
491         mc->editbox.tblabel = NewControl(window, &lbounds, NULL, TRUE, 0, 0, 0,
492                                          kControlStaticTextProc, (long)mc);
493         SetControlData(mc->editbox.tblabel, kControlEntireControl,
494                        kControlStaticTextTextTag,
495                        strlen(ctrl->editbox.label), ctrl->editbox.label);
496         InsetRect(&bounds, 3, 3);
497         mc->editbox.tbctrl = NewControl(window, &bounds, NULL, TRUE, 0, 0, 0,
498                                         ctrl->editbox.password ?
499                                         kControlEditTextPasswordProc :
500                                         kControlEditTextProc, (long)mc);
501     }
502 #if !TARGET_API_MAC_CARBON
503     else {
504         mc->editbox.tblabel = NewControl(window, &lbounds, NULL, TRUE,
505                                          0, 0, 0, SYS7_TEXT_PROC, (long)mc);
506         TESetText(ctrl->editbox.label, strlen(ctrl->editbox.label),
507                   (TEHandle)(*mc->editbox.tblabel)->contrlData);
508         mc->editbox.tbctrl = NewControl(window, &bounds, NULL, TRUE, 0, 0, 0,
509                                         SYS7_EDITBOX_PROC, (long)mc);
510     }
511 #endif
512     curstate->pos.v += 28;
513     add234(mcs->byctrl, mc);
514     mc->generic.next = mcs->panels[curstate->panelnum];
515     mcs->panels[curstate->panelnum] = mc;
516     ctrlevent(mcs, mc, EVENT_REFRESH);
517 }
518
519 #if !TARGET_API_MAC_CARBON
520 static pascal SInt32 macctrl_sys7_editbox_cdef(SInt16 variant,
521                                                ControlRef control,
522                                                ControlDefProcMessage msg,
523                                                SInt32 param)
524 {
525     RgnHandle rgn;
526     Rect rect;
527     TEHandle te;
528     long ssfs;
529     Point mouse;
530
531     switch (msg) {
532       case initCntl:
533         rect = (*control)->contrlRect;
534         if (variant == SYS7_EDITBOX_VARIANT)
535             InsetRect(&rect, 3, 3); /* 2 if it's 20 pixels high */
536         te = TENew(&rect, &rect);
537         ssfs = GetScriptVariable(smSystemScript, smScriptSysFondSize);
538         (*te)->txSize = LoWord(ssfs);
539         (*te)->txFont = HiWord(ssfs);
540         (*control)->contrlData = (Handle)te;
541         return noErr;
542       case dispCntl:
543         TEDispose((TEHandle)(*control)->contrlData);
544         return 0;
545       case drawCntl:
546         if ((*control)->contrlVis) {
547             rect = (*control)->contrlRect;
548             if (variant == SYS7_EDITBOX_VARIANT) {
549                 PenNormal();
550                 FrameRect(&rect);
551                 InsetRect(&rect, 3, 3);
552             }
553             (*(TEHandle)(*control)->contrlData)->viewRect = rect;
554             TEUpdate(&rect, (TEHandle)(*control)->contrlData);
555         }
556         return 0;
557       case testCntl:
558         if (variant == SYS7_TEXT_VARIANT)
559             return kControlNoPart;
560         mouse.h = LoWord(param);
561         mouse.v = HiWord(param);
562         rect = (*control)->contrlRect;
563         InsetRect(&rect, 3, 3);
564         return PtInRect(mouse, &rect) ? kControlEditTextPart : kControlNoPart;
565       case calcCRgns:
566         if (param & (1 << 31)) {
567             param &= ~(1 << 31);
568             goto calcthumbrgn;
569         }
570         /* FALLTHROUGH */
571       case calcCntlRgn:
572         rgn = (RgnHandle)param;
573         RectRgn(rgn, &(*control)->contrlRect);
574         return 0;
575       case calcThumbRgn:
576       calcthumbrgn:
577         rgn = (RgnHandle)param;
578         SetEmptyRgn(rgn);
579         return 0;
580     }
581
582     return 0;
583 }
584 #endif
585
586 static void macctrl_radio(struct macctrls *mcs, WindowPtr window,
587                           struct mac_layoutstate *curstate,
588                           union control *ctrl)
589 {
590     union macctrl *mc = snew(union macctrl);
591     Rect bounds;
592     Str255 title;
593     unsigned int i, colwidth;
594
595     fprintf(stderr, "    label = %s\n", ctrl->radio.label);
596     mc->generic.type = MACCTRL_RADIO;
597     mc->generic.ctrl = ctrl;
598     mc->generic.privdata = NULL;
599     mc->radio.tbctrls = snewn(ctrl->radio.nbuttons, ControlRef);
600     colwidth = (curstate->width + 13) / ctrl->radio.ncolumns;
601     bounds.top = curstate->pos.v;
602     bounds.bottom = bounds.top + 16;
603     bounds.left = curstate->pos.h;
604     bounds.right = bounds.left + curstate->width;
605     if (mac_gestalts.apprvers >= 0x100) {
606         mc->radio.tblabel = NewControl(window, &bounds, NULL, TRUE, 0, 0, 0,
607                                        kControlStaticTextProc, (long)mc);
608         SetControlData(mc->radio.tblabel, kControlEntireControl,
609                        kControlStaticTextTextTag,
610                        strlen(ctrl->radio.label), ctrl->radio.label);
611     }
612  #if !TARGET_API_MAC_CARBON
613     else {
614         mc->radio.tblabel = NewControl(window, &bounds, NULL, TRUE,
615                                          0, 0, 0, SYS7_TEXT_PROC, (long)mc);
616         TESetText(ctrl->radio.label, strlen(ctrl->radio.label),
617                   (TEHandle)(*mc->radio.tblabel)->contrlData);
618     }
619 #endif
620     curstate->pos.v += 18;
621     for (i = 0; i < ctrl->radio.nbuttons; i++) {
622         fprintf(stderr, "    button = %s\n", ctrl->radio.buttons[i]);
623         bounds.top = curstate->pos.v - 2;
624         bounds.bottom = bounds.top + 18;
625         bounds.left = curstate->pos.h + colwidth * (i % ctrl->radio.ncolumns);
626         if (i == ctrl->radio.nbuttons - 1 ||
627             i % ctrl->radio.ncolumns == ctrl->radio.ncolumns - 1) {
628             bounds.right = curstate->pos.h + curstate->width;
629             curstate->pos.v += 18;
630         } else
631             bounds.right = bounds.left + colwidth - 13;
632         c2pstrcpy(title, ctrl->radio.buttons[i]);
633         mc->radio.tbctrls[i] = NewControl(window, &bounds, title, TRUE,
634                                           0, 0, 1, radioButProc, (long)mc);
635     }
636     curstate->pos.v += 4;
637     add234(mcs->byctrl, mc);
638     mc->generic.next = mcs->panels[curstate->panelnum];
639     mcs->panels[curstate->panelnum] = mc;
640     ctrlevent(mcs, mc, EVENT_REFRESH);
641 }
642
643 static void macctrl_checkbox(struct macctrls *mcs, WindowPtr window,
644                              struct mac_layoutstate *curstate,
645                              union control *ctrl)
646 {
647     union macctrl *mc = snew(union macctrl);
648     Rect bounds;
649     Str255 title;
650
651     fprintf(stderr, "    label = %s\n", ctrl->checkbox.label);
652     mc->generic.type = MACCTRL_CHECKBOX;
653     mc->generic.ctrl = ctrl;
654     mc->generic.privdata = NULL;
655     bounds.left = curstate->pos.h;
656     bounds.right = bounds.left + curstate->width;
657     bounds.top = curstate->pos.v;
658     bounds.bottom = bounds.top + 16;
659     c2pstrcpy(title, ctrl->checkbox.label);
660     mc->checkbox.tbctrl = NewControl(window, &bounds, title, TRUE, 0, 0, 1,
661                                      checkBoxProc, (long)mc);
662     add234(mcs->byctrl, mc);
663     curstate->pos.v += 22;
664     mc->generic.next = mcs->panels[curstate->panelnum];
665     mcs->panels[curstate->panelnum] = mc;
666     ctrlevent(mcs, mc, EVENT_REFRESH);
667 }
668
669 static void macctrl_button(struct macctrls *mcs, WindowPtr window,
670                            struct mac_layoutstate *curstate,
671                            union control *ctrl)
672 {
673     union macctrl *mc = snew(union macctrl);
674     Rect bounds;
675     Str255 title;
676
677     fprintf(stderr, "    label = %s\n", ctrl->button.label);
678     if (ctrl->button.isdefault)
679         fprintf(stderr, "    is default\n");
680     mc->generic.type = MACCTRL_BUTTON;
681     mc->generic.ctrl = ctrl;
682     mc->generic.privdata = NULL;
683     bounds.left = curstate->pos.h;
684     bounds.right = bounds.left + curstate->width;
685     bounds.top = curstate->pos.v;
686     bounds.bottom = bounds.top + 20;
687     c2pstrcpy(title, ctrl->button.label);
688     mc->button.tbctrl = NewControl(window, &bounds, title, TRUE, 0, 0, 1,
689                                    pushButProc, (long)mc);
690     if (mac_gestalts.apprvers >= 0x100) {
691         Boolean isdefault = ctrl->button.isdefault;
692
693         SetControlData(mc->button.tbctrl, kControlEntireControl,
694                        kControlPushButtonDefaultTag,
695                        sizeof(isdefault), &isdefault);
696     } else if (ctrl->button.isdefault) {
697         InsetRect(&bounds, -4, -4);
698         NewControl(window, &bounds, title, TRUE, 0, 0, 1,
699                    SYS7_DEFAULT_PROC, (long)mc);
700     }
701     if (mac_gestalts.apprvers >= 0x110) {
702         Boolean iscancel = ctrl->button.iscancel;
703
704         SetControlData(mc->button.tbctrl, kControlEntireControl,
705                        kControlPushButtonCancelTag,
706                        sizeof(iscancel), &iscancel);
707     }
708     add234(mcs->byctrl, mc);
709     mc->generic.next = mcs->panels[curstate->panelnum];
710     mcs->panels[curstate->panelnum] = mc;
711     curstate->pos.v += 26;
712 }
713
714 #if !TARGET_API_MAC_CARBON
715 static pascal SInt32 macctrl_sys7_default_cdef(SInt16 variant,
716                                                ControlRef control,
717                                                ControlDefProcMessage msg,
718                                                SInt32 param)
719 {
720     RgnHandle rgn;
721     Rect rect;
722     int oval;
723
724     switch (msg) {
725       case drawCntl:
726         if ((*control)->contrlVis) {
727             rect = (*control)->contrlRect;
728             PenNormal();
729             PenSize(3, 3);
730             oval = (rect.bottom - rect.top) / 2 + 2;
731             FrameRoundRect(&rect, oval, oval);
732         }
733         return 0;
734       case calcCRgns:
735         if (param & (1 << 31)) {
736             param &= ~(1 << 31);
737             goto calcthumbrgn;
738         }
739         /* FALLTHROUGH */
740       case calcCntlRgn:
741         rgn = (RgnHandle)param;
742         RectRgn(rgn, &(*control)->contrlRect);
743         return 0;
744       case calcThumbRgn:
745       calcthumbrgn:
746         rgn = (RgnHandle)param;
747         SetEmptyRgn(rgn);
748         return 0;
749     }
750
751     return 0;
752 }
753 #endif
754
755 static void macctrl_popup(struct macctrls *mcs, WindowPtr window,
756                           struct mac_layoutstate *curstate,
757                           union control *ctrl)
758 {
759     union macctrl *mc = snew(union macctrl);
760     Rect bounds;
761     Str255 title;
762     unsigned int labelwidth;
763     static int nextmenuid = MENU_MIN;
764     int menuid;
765     MenuRef menu;
766
767     /* 
768      * <http://developer.apple.com/qa/tb/tb42.html> explains how to
769      * create a popup menu with dynamic content.
770      */
771     assert(ctrl->listbox.height == 0);
772     assert(!ctrl->listbox.draglist);
773     assert(!ctrl->listbox.multisel);
774
775     fprintf(stderr, "    label = %s\n", ctrl->listbox.label);
776     fprintf(stderr, "    percentwidth = %d\n", ctrl->listbox.percentwidth);
777
778     mc->generic.type = MACCTRL_POPUP;
779     mc->generic.ctrl = ctrl;
780     mc->generic.privdata = NULL;
781     c2pstrcpy(title, ctrl->button.label);
782
783     /* Find a spare menu ID and create the menu */
784     while (GetMenuHandle(nextmenuid) != NULL)
785         if (++nextmenuid >= MENU_MAX) nextmenuid = MENU_MIN;
786     menuid = nextmenuid++;
787     menu = NewMenu(menuid, "\pdummy");
788     if (menu == NULL) return;
789     mc->popup.menu = menu;
790     mc->popup.menuid = menuid;
791     InsertMenu(menu, kInsertHierarchicalMenu);
792
793     /* The menu starts off empty */
794     mc->popup.nids = 0;
795     mc->popup.ids = NULL;
796
797     bounds.left = curstate->pos.h;
798     bounds.right = bounds.left + curstate->width;
799     bounds.top = curstate->pos.v;
800     bounds.bottom = bounds.top + 20;
801     /* XXX handle percentwidth == 100 */
802     labelwidth = curstate->width * (100 - ctrl->listbox.percentwidth) / 100;
803     mc->popup.tbctrl = NewControl(window, &bounds, title, TRUE,
804                                   popupTitleLeftJust, menuid, labelwidth,
805                                   popupMenuProc + popupFixedWidth, (long)mc);
806     add234(mcs->byctrl, mc);
807     curstate->pos.v += 26;
808     mc->generic.next = mcs->panels[curstate->panelnum];
809     mcs->panels[curstate->panelnum] = mc;
810     ctrlevent(mcs, mc, EVENT_REFRESH);
811 }
812
813
814 void macctrl_activate(WindowPtr window, EventRecord *event)
815 {
816     struct macctrls *mcs = mac_winctrls(window);
817     Boolean active = (event->modifiers & activeFlag) != 0;
818     GrafPtr saveport;
819     int i, j;
820     ControlPartCode state;
821     union macctrl *mc;
822
823     GetPort(&saveport);
824     SetPort((GrafPtr)GetWindowPort(window));
825     if (mac_gestalts.apprvers >= 0x100)
826         SetThemeWindowBackground(window, active ?
827                                  kThemeBrushModelessDialogBackgroundActive :
828                                  kThemeBrushModelessDialogBackgroundInactive,
829                                  TRUE);
830     state = active ? kControlNoPart : kControlInactivePart;
831     for (i = 0; i <= mcs->curpanel; i += mcs->curpanel)
832         for (mc = mcs->panels[i]; mc != NULL; mc = mc->generic.next) {
833             switch (mc->generic.type) {
834               case MACCTRL_TEXT:
835                 HiliteControl(mc->text.tbctrl, state);
836                 break;
837               case MACCTRL_EDITBOX:
838                 HiliteControl(mc->editbox.tbctrl, state);
839                 HiliteControl(mc->editbox.tblabel, state);
840                 break;
841               case MACCTRL_RADIO:
842                 for (j = 0; j < mc->generic.ctrl->radio.nbuttons; j++)
843                     HiliteControl(mc->radio.tbctrls[j], state);
844                 HiliteControl(mc->radio.tblabel, state);
845                 break;
846               case MACCTRL_CHECKBOX:
847                 HiliteControl(mc->checkbox.tbctrl, state);
848                 break;
849               case MACCTRL_BUTTON:
850                 HiliteControl(mc->button.tbctrl, state);
851                 break;
852               case MACCTRL_POPUP:
853                 HiliteControl(mc->popup.tbctrl, state);
854                 break;
855             }
856 #if !TARGET_API_MAC_CARBON
857             if (mcs->focus == mc) {
858                 if (active)
859                     macctrl_enfocus(mc);
860                 else
861                     macctrl_defocus(mc);
862             }
863 #endif
864         }
865     SetPort(saveport);
866 }
867
868 void macctrl_click(WindowPtr window, EventRecord *event)
869 {
870     Point mouse;
871     ControlHandle control;
872     int part, trackresult;
873     GrafPtr saveport;
874     union macctrl *mc;
875     struct macctrls *mcs = mac_winctrls(window);
876     int i;
877     UInt32 features;
878
879     GetPort(&saveport);
880     SetPort((GrafPtr)GetWindowPort(window));
881     mouse = event->where;
882     GlobalToLocal(&mouse);
883     part = FindControl(mouse, window, &control);
884     if (control != NULL) {
885         mc = (union macctrl *)GetControlReference(control);
886         if (mac_gestalts.apprvers >= 0x100) {
887             if (GetControlFeatures(control, &features) == noErr &&
888                 (features & kControlSupportsFocus) &&
889                 (features & kControlGetsFocusOnClick))
890                 SetKeyboardFocus(window, control, part);
891             trackresult = HandleControlClick(control, mouse, event->modifiers,
892                                              (ControlActionUPP)-1);
893         } else {
894 #if !TARGET_API_MAC_CARBON
895             if (mc->generic.type == MACCTRL_EDITBOX &&
896                 control == mc->editbox.tbctrl) {
897                 TEHandle te = (TEHandle)(*control)->contrlData;
898
899                 macctrl_setfocus(mcs, mc);
900                 TEClick(mouse, !!(event->modifiers & shiftKey), te);
901                 goto done;
902             }
903 #endif
904             trackresult = TrackControl(control, mouse, (ControlActionUPP)-1);
905         }
906         switch (mc->generic.type) {
907           case MACCTRL_RADIO:
908             if (trackresult != 0) {
909                 for (i = 0; i < mc->generic.ctrl->radio.nbuttons; i++)
910                     if (mc->radio.tbctrls[i] == control)
911                         SetControlValue(mc->radio.tbctrls[i],
912                                         kControlRadioButtonCheckedValue);
913                     else
914                         SetControlValue(mc->radio.tbctrls[i],
915                                         kControlRadioButtonUncheckedValue);
916                 ctrlevent(mcs, mc, EVENT_VALCHANGE);
917             }
918             break;
919           case MACCTRL_CHECKBOX:
920             if (trackresult != 0) {
921                 SetControlValue(control, !GetControlValue(control));
922                 ctrlevent(mcs, mc, EVENT_VALCHANGE);
923             }
924             break;
925           case MACCTRL_BUTTON:
926             if (trackresult != 0)
927                 ctrlevent(mcs, mc, EVENT_ACTION);
928             break;
929           case MACCTRL_POPUP:
930             ctrlevent(mcs, mc, EVENT_SELCHANGE);
931             break;
932         }
933     }
934   done:
935     SetPort(saveport);
936 }
937
938 void macctrl_key(WindowPtr window, EventRecord *event)
939 {
940     ControlRef control;
941     struct macctrls *mcs = mac_winctrls(window);
942     union macctrl *mc;
943
944     if (mac_gestalts.apprvers >= 0x100) {
945         if (GetKeyboardFocus(window, &control) == noErr && control != NULL) {
946             HandleControlKey(control, (event->message & keyCodeMask) >> 8,
947                              event->message & charCodeMask, event->modifiers);
948             mc = (union macctrl *)GetControlReference(control);
949             ctrlevent(mcs, mc, EVENT_VALCHANGE);
950         }
951     }
952 #if !TARGET_API_MAC_CARBON
953     else {
954         TEHandle te;
955
956         if (mcs->focus != NULL) {
957             mc = mcs->focus;
958             switch (mc->generic.type) {
959               case MACCTRL_EDITBOX:
960                 te = (TEHandle)(*mc->editbox.tbctrl)->contrlData;
961                 TEKey(event->message & charCodeMask, te);
962                 ctrlevent(mcs, mc, EVENT_VALCHANGE);
963                 break;
964             }
965         }
966     }
967 #endif
968 }
969
970 void macctrl_update(WindowPtr window)
971 {
972 #if TARGET_API_MAC_CARBON
973     RgnHandle visrgn;
974 #endif
975     Rect rect;
976     GrafPtr saveport;
977
978     BeginUpdate(window);
979     GetPort(&saveport);
980     SetPort((GrafPtr)GetWindowPort(window));
981     if (mac_gestalts.apprvers >= 0x101) {
982 #if TARGET_API_MAC_CARBON
983         GetPortBounds(GetWindowPort(window), &rect);
984 #else
985         rect = window->portRect;
986 #endif
987         InsetRect(&rect, -1, -1);
988         DrawThemeModelessDialogFrame(&rect, mac_frontwindow() == window ?
989                                      kThemeStateActive : kThemeStateInactive);
990     }
991 #if TARGET_API_MAC_CARBON
992     visrgn = NewRgn();
993     GetPortVisibleRegion(GetWindowPort(window), visrgn);
994     UpdateControls(window, visrgn);
995     DisposeRgn(visrgn);
996 #else
997     UpdateControls(window, window->visRgn);
998 #endif
999     SetPort(saveport);
1000     EndUpdate(window);
1001 }
1002
1003 #if TARGET_API_MAC_CARBON
1004 #define EnableItem EnableMenuItem
1005 #define DisableItem DisableMenuItem
1006 #endif
1007 void macctrl_adjustmenus(WindowPtr window)
1008 {
1009     MenuHandle menu;
1010
1011     menu = GetMenuHandle(mFile);
1012     DisableItem(menu, iSave); /* XXX enable if modified */
1013     EnableItem(menu, iSaveAs);
1014     EnableItem(menu, iDuplicate);
1015
1016     menu = GetMenuHandle(mEdit);
1017     DisableItem(menu, 0);
1018 }
1019
1020 void macctrl_close(WindowPtr window)
1021 {
1022     struct macctrls *mcs = mac_winctrls(window);
1023     union macctrl *mc;
1024
1025     /*
1026      * Mostly, we don't bother disposing of the Toolbox controls,
1027      * since that will happen automatically when the window is
1028      * disposed of.  Popup menus are an exception, because we have to
1029      * dispose of the menu ourselves, and doing that while the control
1030      * still holds a reference to it seems rude.
1031      */
1032     while ((mc = index234(mcs->byctrl, 0)) != NULL) {
1033         if (mc->generic.privdata != NULL && mc->generic.freeprivdata)
1034             sfree(mc->generic.privdata);
1035         switch (mc->generic.type) {
1036           case MACCTRL_POPUP:
1037             DisposeControl(mc->popup.tbctrl);
1038             DeleteMenu(mc->popup.menuid);
1039             DisposeMenu(mc->popup.menu);
1040             break;
1041         }
1042         del234(mcs->byctrl, mc);
1043         sfree(mc);
1044     }
1045
1046     freetree234(mcs->byctrl);
1047     mcs->byctrl = NULL;
1048     sfree(mcs->panels);
1049     mcs->panels = NULL;
1050 }
1051
1052 void dlg_update_start(union control *ctrl, void *dlg)
1053 {
1054
1055     /* No-op for now */
1056 }
1057
1058 void dlg_update_done(union control *ctrl, void *dlg)
1059 {
1060
1061     /* No-op for now */
1062 }
1063
1064 void dlg_set_focus(union control *ctrl, void *dlg)
1065 {
1066
1067     if (mac_gestalts.apprvers >= 0x100) {
1068         /* Use SetKeyboardFocus() */
1069     } else {
1070         /* Do our own mucking around */
1071     }
1072 }
1073
1074 union control *dlg_last_focused(union control *ctrl, void *dlg)
1075 {
1076
1077     return NULL;
1078 }
1079
1080 void dlg_beep(void *dlg)
1081 {
1082
1083     SysBeep(30);
1084 }
1085
1086 void dlg_error_msg(void *dlg, char *msg)
1087 {
1088     Str255 pmsg;
1089
1090     c2pstrcpy(pmsg, msg);
1091     ParamText(pmsg, NULL, NULL, NULL);
1092     StopAlert(128, NULL);
1093 }
1094
1095 void dlg_end(void *dlg, int value)
1096 {
1097     struct macctrls *mcs = dlg;
1098
1099     if (mcs->end != NULL)
1100         (*mcs->end)(mcs->window, value);
1101 };
1102
1103 void dlg_refresh(union control *ctrl, void *dlg)
1104 {
1105     struct macctrls *mcs = dlg;
1106     union macctrl *mc;
1107
1108     if (ctrl == NULL)
1109         return; /* FIXME */
1110     mc = findbyctrl(mcs, ctrl);
1111     assert(mc != NULL);
1112     ctrlevent(mcs, mc, EVENT_REFRESH);
1113 };
1114
1115 void *dlg_get_privdata(union control *ctrl, void *dlg)
1116 {
1117     struct macctrls *mcs = dlg;
1118     union macctrl *mc = findbyctrl(mcs, ctrl);
1119
1120     assert(mc != NULL);
1121     return mc->generic.privdata;
1122 }
1123
1124 void dlg_set_privdata(union control *ctrl, void *dlg, void *ptr)
1125 {
1126     struct macctrls *mcs = dlg;
1127     union macctrl *mc = findbyctrl(mcs, ctrl);
1128
1129     assert(mc != NULL);
1130     mc->generic.privdata = ptr;
1131     mc->generic.freeprivdata = FALSE;
1132 }
1133
1134 void *dlg_alloc_privdata(union control *ctrl, void *dlg, size_t size)
1135 {
1136     struct macctrls *mcs = dlg;
1137     union macctrl *mc = findbyctrl(mcs, ctrl);
1138
1139     assert(mc != NULL);
1140     mc->generic.privdata = smalloc(size);
1141     mc->generic.freeprivdata = TRUE;
1142     return mc->generic.privdata;
1143 }
1144
1145
1146 /*
1147  * Radio Button control
1148  */
1149
1150 void dlg_radiobutton_set(union control *ctrl, void *dlg, int whichbutton)
1151 {
1152     struct macctrls *mcs = dlg;
1153     union macctrl *mc = findbyctrl(mcs, ctrl);
1154     int i;
1155
1156     assert(mc != NULL);
1157     for (i = 0; i < ctrl->radio.nbuttons; i++) {
1158         if (i == whichbutton)
1159             SetControlValue(mc->radio.tbctrls[i],
1160                             kControlRadioButtonCheckedValue);
1161         else
1162             SetControlValue(mc->radio.tbctrls[i],
1163                             kControlRadioButtonUncheckedValue);
1164     }
1165
1166 };
1167
1168 int dlg_radiobutton_get(union control *ctrl, void *dlg)
1169 {
1170     struct macctrls *mcs = dlg;
1171     union macctrl *mc = findbyctrl(mcs, ctrl);
1172     int i;
1173
1174     assert(mc != NULL);
1175     for (i = 0; i < ctrl->radio.nbuttons; i++) {
1176         if (GetControlValue(mc->radio.tbctrls[i])  ==
1177             kControlRadioButtonCheckedValue)
1178             return i;
1179     }
1180     return -1;
1181 };
1182
1183
1184 /*
1185  * Check Box control
1186  */
1187
1188 void dlg_checkbox_set(union control *ctrl, void *dlg, int checked)
1189 {
1190     struct macctrls *mcs = dlg;
1191     union macctrl *mc = findbyctrl(mcs, ctrl);
1192
1193     assert(mc != NULL);
1194     SetControlValue(mc->checkbox.tbctrl,
1195                     checked ? kControlCheckBoxCheckedValue :
1196                               kControlCheckBoxUncheckedValue);
1197 }
1198
1199 int dlg_checkbox_get(union control *ctrl, void *dlg)
1200 {
1201     struct macctrls *mcs = dlg;
1202     union macctrl *mc = findbyctrl(mcs, ctrl);
1203
1204     assert(mc != NULL);
1205     return GetControlValue(mc->checkbox.tbctrl);
1206 }
1207
1208
1209 /*
1210  * Edit Box control
1211  */
1212
1213 void dlg_editbox_set(union control *ctrl, void *dlg, char const *text)
1214 {
1215     struct macctrls *mcs = dlg;
1216     union macctrl *mc = findbyctrl(mcs, ctrl);
1217     GrafPtr saveport;
1218
1219     assert(mc != NULL);
1220     assert(mc->generic.type == MACCTRL_EDITBOX);
1221     GetPort(&saveport);
1222     SetPort((GrafPtr)(GetWindowPort(mcs->window)));
1223     if (mac_gestalts.apprvers >= 0x100)
1224         SetControlData(mc->editbox.tbctrl, kControlEntireControl,
1225                        ctrl->editbox.password ?
1226                        kControlEditTextPasswordTag :
1227                        kControlEditTextTextTag,
1228                        strlen(text), text);
1229 #if !TARGET_API_MAC_CARBON
1230     else
1231         TESetText(text, strlen(text),
1232                   (TEHandle)(*mc->editbox.tbctrl)->contrlData);
1233 #endif
1234     DrawOneControl(mc->editbox.tbctrl);
1235     SetPort(saveport);
1236 }
1237
1238 void dlg_editbox_get(union control *ctrl, void *dlg, char *buffer, int length)
1239 {
1240     struct macctrls *mcs = dlg;
1241     union macctrl *mc = findbyctrl(mcs, ctrl);
1242     Size olen;
1243
1244     assert(mc != NULL);
1245     assert(mc->generic.type == MACCTRL_EDITBOX);
1246     if (mac_gestalts.apprvers >= 0x100) {
1247         if (GetControlData(mc->editbox.tbctrl, kControlEntireControl,
1248                            ctrl->editbox.password ?
1249                            kControlEditTextPasswordTag :
1250                            kControlEditTextTextTag,
1251                            length - 1, buffer, &olen) != noErr)
1252             olen = 0;
1253         if (olen > length - 1)
1254             olen = length - 1;
1255     }
1256 #if !TARGET_API_MAC_CARBON
1257     else {
1258         TEHandle te = (TEHandle)(*mc->editbox.tbctrl)->contrlData;
1259
1260         olen = (*te)->teLength;
1261         if (olen > length - 1)
1262             olen = length - 1;
1263         memcpy(buffer, *(*te)->hText, olen);
1264     }
1265 #endif
1266     buffer[olen] = '\0';
1267     fprintf(stderr, "dlg_editbox_get: %s\n", buffer);
1268 }
1269
1270
1271 /*
1272  * List Box control
1273  */
1274
1275 static void dlg_macpopup_clear(union control *ctrl, void *dlg)
1276 {
1277     struct macctrls *mcs = dlg;
1278     union macctrl *mc = findbyctrl(mcs, ctrl);
1279     MenuRef menu = mc->popup.menu;
1280     unsigned int i, n;
1281
1282     fprintf(stderr, "      popup_clear\n");
1283     n = CountMenuItems(menu);
1284     for (i = 0; i < n; i++)
1285         DeleteMenuItem(menu, n - i);
1286     mc->popup.nids = 0;
1287     sfree(mc->popup.ids);
1288     mc->popup.ids = NULL;
1289     SetControlMaximum(mc->popup.tbctrl, CountMenuItems(menu));
1290 }
1291
1292 void dlg_listbox_clear(union control *ctrl, void *dlg)
1293 {
1294
1295     if (ctrl->listbox.height == 0)
1296         dlg_macpopup_clear(ctrl, dlg);
1297 }
1298
1299 static void dlg_macpopup_del(union control *ctrl, void *dlg, int index)
1300 {
1301     struct macctrls *mcs = dlg;
1302     union macctrl *mc = findbyctrl(mcs, ctrl);
1303     MenuRef menu = mc->popup.menu;
1304
1305     fprintf(stderr, "      popup_del %d\n", index);
1306     DeleteMenuItem(menu, index + 1);
1307     if (mc->popup.ids != NULL)
1308         memcpy(mc->popup.ids + index, mc->popup.ids + index + 1,
1309                (mc->popup.nids - index - 1) * sizeof(*mc->popup.ids));
1310     SetControlMaximum(mc->popup.tbctrl, CountMenuItems(menu));
1311 }
1312
1313 void dlg_listbox_del(union control *ctrl, void *dlg, int index)
1314 {
1315
1316     if (ctrl->listbox.height == 0)
1317         dlg_macpopup_del(ctrl, dlg, index);
1318 }
1319
1320 static void dlg_macpopup_add(union control *ctrl, void *dlg, char const *text)
1321 {
1322     struct macctrls *mcs = dlg;
1323     union macctrl *mc = findbyctrl(mcs, ctrl);
1324     MenuRef menu = mc->popup.menu;
1325     Str255 itemstring;
1326
1327     fprintf(stderr, "      popup_add %s\n", text);
1328     assert(text[0] != '\0');
1329     c2pstrcpy(itemstring, text);
1330     AppendMenu(menu, "\pdummy");
1331     SetMenuItemText(menu, CountMenuItems(menu), itemstring);
1332     SetControlMaximum(mc->popup.tbctrl, CountMenuItems(menu));
1333 }
1334
1335 void dlg_listbox_add(union control *ctrl, void *dlg, char const *text)
1336 {
1337
1338     if (ctrl->listbox.height == 0)
1339         dlg_macpopup_add(ctrl, dlg, text);
1340 }
1341
1342 static void dlg_macpopup_addwithid(union control *ctrl, void *dlg,
1343                                    char const *text, int id)
1344 {
1345     struct macctrls *mcs = dlg;
1346     union macctrl *mc = findbyctrl(mcs, ctrl);
1347     MenuRef menu = mc->popup.menu;
1348     unsigned int index;
1349
1350     fprintf(stderr, "      popup_addwthindex %s, %d\n", text, id);
1351     dlg_macpopup_add(ctrl, dlg, text);
1352     index = CountMenuItems(menu) - 1;
1353     if (mc->popup.nids <= index) {
1354         mc->popup.nids = index + 1;
1355         mc->popup.ids = sresize(mc->popup.ids, mc->popup.nids, int);
1356     }
1357     mc->popup.ids[index] = id;
1358 }
1359
1360 void dlg_listbox_addwithid(union control *ctrl, void *dlg,
1361                            char const *text, int id)
1362 {
1363
1364     if (ctrl->listbox.height == 0)
1365         dlg_macpopup_addwithid(ctrl, dlg, text, id);
1366 }
1367
1368 int dlg_listbox_getid(union control *ctrl, void *dlg, int index)
1369 {
1370     struct macctrls *mcs = dlg;
1371     union macctrl *mc = findbyctrl(mcs, ctrl);
1372
1373     if (ctrl->listbox.height == 0) {
1374         assert(mc->popup.ids != NULL && mc->popup.nids > index);
1375         return mc->popup.ids[index];
1376     }
1377     return 0;
1378 }
1379
1380 int dlg_listbox_index(union control *ctrl, void *dlg)
1381 {
1382     struct macctrls *mcs = dlg;
1383     union macctrl *mc = findbyctrl(mcs, ctrl);
1384
1385     if (ctrl->listbox.height == 0)
1386         return GetControlValue(mc->popup.tbctrl) - 1;
1387     return 0;
1388 };
1389
1390 int dlg_listbox_issel(union control *ctrl, void *dlg, int index)
1391 {
1392     struct macctrls *mcs = dlg;
1393     union macctrl *mc = findbyctrl(mcs, ctrl);
1394
1395     if (ctrl->listbox.height == 0)
1396         return GetControlValue(mc->popup.tbctrl) - 1 == index;
1397     return 0;
1398 };
1399
1400 void dlg_listbox_select(union control *ctrl, void *dlg, int index)
1401 {
1402     struct macctrls *mcs = dlg;
1403     union macctrl *mc = findbyctrl(mcs, ctrl);
1404
1405     if (ctrl->listbox.height == 0)
1406         SetControlValue(mc->popup.tbctrl, index + 1);
1407 };
1408
1409
1410 /*
1411  * Text control
1412  */
1413
1414 void dlg_text_set(union control *ctrl, void *dlg, char const *text)
1415 {
1416     struct macctrls *mcs = dlg;
1417     union macctrl *mc = findbyctrl(mcs, ctrl);
1418
1419     assert(mc != NULL);
1420     if (mac_gestalts.apprvers >= 0x100)
1421         SetControlData(mc->text.tbctrl, kControlEntireControl,
1422                        kControlStaticTextTextTag, strlen(text), text);
1423 #if !TARGET_API_MAC_CARBON
1424     else
1425         TESetText(text, strlen(text),
1426                   (TEHandle)(*mc->text.tbctrl)->contrlData);
1427 #endif
1428 }
1429
1430
1431 /*
1432  * File Selector control
1433  */
1434
1435 void dlg_filesel_set(union control *ctrl, void *dlg, Filename fn)
1436 {
1437
1438 }
1439
1440 void dlg_filesel_get(union control *ctrl, void *dlg, Filename *fn)
1441 {
1442
1443 }
1444
1445
1446 /*
1447  * Font Selector control
1448  */
1449
1450 void dlg_fontsel_set(union control *ctrl, void *dlg, FontSpec fn)
1451 {
1452
1453 }
1454
1455 void dlg_fontsel_get(union control *ctrl, void *dlg, FontSpec *fn)
1456 {
1457
1458 }
1459
1460
1461 /*
1462  * Printer enumeration
1463  */
1464
1465 printer_enum *printer_start_enum(int *nprinters)
1466 {
1467
1468     *nprinters = 0;
1469     return NULL;
1470 }
1471
1472 char *printer_get_name(printer_enum *pe, int thing)
1473 {
1474
1475     return "<none>";
1476 }
1477
1478 void printer_finish_enum(printer_enum *pe)
1479 {
1480
1481 }
1482
1483
1484 /*
1485  * Colour selection stuff
1486  */
1487
1488 void dlg_coloursel_start(union control *ctrl, void *dlg,
1489                          int r, int g, int b)
1490 {
1491
1492 }
1493
1494 int dlg_coloursel_results(union control *ctrl, void *dlg,
1495                           int *r, int *g, int *b)
1496 {
1497
1498     return 0;
1499 }
1500
1501 /*
1502  * Local Variables:
1503  * c-file-style: "simon"
1504  * End:
1505  */