]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - mac/macctrls.c
4ce523e6a1fc2f1b2024ed7181e798dc07ee432a
[PuTTY.git] / mac / macctrls.c
1 /* $Id$ */
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 <ColorPicker.h>
31 #include <Controls.h>
32 #include <ControlDefinitions.h>
33 #include <Events.h>
34 #include <Lists.h>
35 #include <Menus.h>
36 #include <Resources.h>
37 #include <Script.h>
38 #include <Sound.h>
39 #include <TextEdit.h>
40 #include <TextUtils.h>
41 #include <ToolUtils.h>
42 #include <Windows.h>
43
44 #include <assert.h>
45 #include <string.h>
46
47 #include "putty.h"
48 #include "mac.h"
49 #include "macresid.h"
50 #include "dialog.h"
51 #include "tree234.h"
52
53 /* Range of menu IDs for popup menus */
54 #define MENU_MIN        1024
55 #define MENU_MAX        2048
56
57
58 union macctrl {
59     struct macctrl_generic {
60         enum {
61             MACCTRL_TEXT,
62             MACCTRL_EDITBOX,
63             MACCTRL_RADIO,
64             MACCTRL_CHECKBOX,
65             MACCTRL_BUTTON,
66             MACCTRL_LISTBOX,
67             MACCTRL_POPUP,
68             MACCTRL_GROUPBOX
69         } type;
70         /* Template from which this was generated */
71         union control *ctrl;
72         /* Next control in this panel */
73         union macctrl *next;
74         void *privdata;
75         int freeprivdata;
76     } generic;
77     struct {
78         struct macctrl_generic generic;
79         ControlRef tbctrl;
80     } text;
81     struct {
82         struct macctrl_generic generic;
83         ControlRef tbctrl;
84         ControlRef tblabel;
85     } editbox;
86     struct {
87         struct macctrl_generic generic;
88         ControlRef *tbctrls;
89         ControlRef tblabel;
90     } radio;
91     struct {
92         struct macctrl_generic generic;
93         ControlRef tbctrl;
94     } checkbox;
95     struct {
96         struct macctrl_generic generic;
97         ControlRef tbctrl;
98         ControlRef tbring;
99     } button;
100     struct {
101         struct macctrl_generic generic;
102         ControlRef tbctrl;
103         ListHandle list;
104         unsigned int nids;
105         int *ids;
106     } listbox;
107     struct {
108         struct macctrl_generic generic;
109         ControlRef tbctrl;
110         MenuRef menu;
111         int menuid;
112         unsigned int nids;
113         int *ids;
114     } popup;
115     struct {
116         struct macctrl_generic generic;
117         ControlRef tbctrl;
118     } groupbox;
119 };
120
121 struct mac_layoutstate {
122     Point pos;
123     Point boxpos;
124     char *boxname;
125     unsigned int width;
126     unsigned int panelnum;
127 };
128
129 #define ctrlevent(mcs, mc, event) do {                                  \
130     if ((mc)->generic.ctrl->generic.handler != NULL)                    \
131         (*(mc)->generic.ctrl->generic.handler)((mc)->generic.ctrl, (mcs),\
132                                                (mcs)->data, (event));   \
133 } while (0)
134
135 #define findbyctrl(mcs, ctrl)                                           \
136     find234((mcs)->byctrl, (ctrl), macctrl_cmp_byctrl_find)
137
138 static void macctrl_layoutset(struct mac_layoutstate *, struct controlset *, 
139                               WindowPtr, struct macctrls *);
140 static void macctrl_hideshowpanel(struct macctrls *, unsigned int, int);
141 static void macctrl_switchtopanel(struct macctrls *, unsigned int);
142 static void macctrl_setfocus(struct macctrls *, union macctrl *);
143 static void macctrl_text(struct macctrls *, WindowPtr,
144                          struct mac_layoutstate *, union control *);
145 static void macctrl_editbox(struct macctrls *, WindowPtr,
146                             struct mac_layoutstate *, union control *);
147 static void macctrl_radio(struct macctrls *, WindowPtr,
148                           struct mac_layoutstate *, union control *);
149 static void macctrl_checkbox(struct macctrls *, WindowPtr,
150                              struct mac_layoutstate *, union control *);
151 static void macctrl_button(struct macctrls *, WindowPtr,
152                            struct mac_layoutstate *, union control *);
153 static void macctrl_listbox(struct macctrls *, WindowPtr,
154                             struct mac_layoutstate *, union control *);
155 static void macctrl_popup(struct macctrls *, WindowPtr,
156                           struct mac_layoutstate *, union control *);
157 static void macctrl_groupbox(struct macctrls *, WindowPtr,
158                              struct mac_layoutstate *, union control *);
159 #if !TARGET_API_MAC_CARBON
160 static pascal SInt32 macctrl_sys7_editbox_cdef(SInt16, ControlRef,
161                                                ControlDefProcMessage, SInt32);
162 static pascal SInt32 macctrl_sys7_default_cdef(SInt16, ControlRef,
163                                                ControlDefProcMessage, SInt32);
164 static pascal SInt32 macctrl_sys7_listbox_cdef(SInt16, ControlRef,
165                                                ControlDefProcMessage, SInt32);
166 static pascal SInt32 macctrl_sys7_groupbox_cdef(SInt16, ControlRef,
167                                                 ControlDefProcMessage, SInt32);
168 #endif
169
170 #if !TARGET_API_MAC_CARBON
171 /*
172  * This trick enables us to keep all the CDEF code in the main
173  * application, which makes life easier.  For details, see
174  * <http://developer.apple.com/technotes/tn/tn2003.html#custom_code_base>.
175  */
176
177 #pragma options align=mac68k
178 typedef struct {
179     short               jmpabs; /* 4EF9 */
180     ControlDefUPP       theUPP;
181 } **PatchCDEF;
182 #pragma options align=reset
183 #endif
184
185 static void macctrl_init()
186 {
187 #if !TARGET_API_MAC_CARBON
188     static int inited = 0;
189     PatchCDEF cdef;
190
191     if (inited) return;
192     cdef = (PatchCDEF)GetResource(kControlDefProcResourceType, CDEF_EditBox);
193     (*cdef)->theUPP = NewControlDefProc(macctrl_sys7_editbox_cdef);
194     cdef = (PatchCDEF)GetResource(kControlDefProcResourceType, CDEF_Default);
195     (*cdef)->theUPP = NewControlDefProc(macctrl_sys7_default_cdef);
196     cdef = (PatchCDEF)GetResource(kControlDefProcResourceType, CDEF_ListBox);
197     (*cdef)->theUPP = NewControlDefProc(macctrl_sys7_listbox_cdef);
198     cdef = (PatchCDEF)GetResource(kControlDefProcResourceType, CDEF_GroupBox);
199     (*cdef)->theUPP = NewControlDefProc(macctrl_sys7_groupbox_cdef);
200     inited = 1;
201 #endif
202 }
203
204
205 static int macctrl_cmp_byctrl(void *av, void *bv)
206 {
207     union macctrl *a = (union macctrl *)av;
208     union macctrl *b = (union macctrl *)bv;
209
210     if (a->generic.ctrl < b->generic.ctrl)
211         return -1;
212     else if (a->generic.ctrl > b->generic.ctrl)
213         return +1;
214     else
215         return 0;
216 }
217
218 static int macctrl_cmp_byctrl_find(void *av, void *bv)
219 {
220     union control *a = (union control *)av;
221     union macctrl *b = (union macctrl *)bv;
222
223     if (a < b->generic.ctrl)
224         return -1;
225     else if (a > b->generic.ctrl)
226         return +1;
227     else
228         return 0;
229 }
230
231 static union control panellist;
232
233 static void panellist_handler(union control *ctrl, void *dlg, void *data,
234                               int event)
235 {
236     struct macctrls *mcs = dlg;
237
238     /* XXX what if there's no selection? */
239     if (event == EVENT_SELCHANGE)
240         macctrl_switchtopanel(mcs, dlg_listbox_index(ctrl, dlg) + 1);
241 }
242
243 void macctrl_layoutbox(struct controlbox *cb, WindowPtr window,
244                        struct macctrls *mcs)
245 {
246     int i;
247     struct mac_layoutstate curstate;
248     ControlRef root;
249     Rect rect;
250
251     macctrl_init();
252     if (mac_gestalts.apprvers >= 0x100)
253         CreateRootControl(window, &root);
254 #if TARGET_API_MAC_CARBON
255     GetPortBounds(GetWindowPort(window), &rect);
256 #else
257     rect = window->portRect;
258 #endif
259     mcs->window = window;
260     mcs->byctrl = newtree234(macctrl_cmp_byctrl);
261     mcs->focus = NULL;
262     mcs->defbutton = NULL;
263     mcs->canbutton = NULL;
264     mcs->curpanel = 1;
265     /* Count the number of panels */
266     mcs->npanels = 1;
267     for (i = 1; i < cb->nctrlsets; i++)
268         if (strcmp(cb->ctrlsets[i]->pathname, cb->ctrlsets[i-1]->pathname))
269             mcs->npanels++;
270     mcs->panels = snewn(mcs->npanels, union macctrl *);
271     memset(mcs->panels, 0, sizeof(*mcs->panels) * mcs->npanels);
272     curstate.panelnum = 0;
273
274     curstate.pos.h = rect.left + 13;
275     curstate.pos.v = rect.top + 13;
276     curstate.width = 160;
277     panellist.listbox.type = CTRL_LISTBOX;
278     panellist.listbox.handler = &panellist_handler;
279     panellist.listbox.height = 20;
280     panellist.listbox.percentwidth = 100;
281     macctrl_listbox(mcs, window, &curstate, &panellist);
282     /* XXX Start with panel 1 active */
283
284     curstate.pos.h = rect.left + 13 + 160 + 13;
285     curstate.pos.v = rect.bottom - 33;
286     curstate.width = rect.right - (rect.left + 13 + 160) - (13 * 2);
287     for (i = 0; i < cb->nctrlsets; i++) {
288         if (i > 0 && strcmp(cb->ctrlsets[i]->pathname,
289                             cb->ctrlsets[i-1]->pathname)) {
290             curstate.pos.v = rect.top + 13;
291             curstate.panelnum++;
292             assert(curstate.panelnum < mcs->npanels);
293             dlg_listbox_add(&panellist, mcs, cb->ctrlsets[i]->pathname);
294         }
295         macctrl_layoutset(&curstate, cb->ctrlsets[i], window, mcs);
296     }
297     macctrl_switchtopanel(mcs, 1);
298     macctrl_hideshowpanel(mcs, 0, TRUE);
299     /* 14 = proxies, 19 = portfwd, 20 = SSH bugs */
300 }
301
302
303
304 #define MAXCOLS 16
305
306 static void macctrl_layoutset(struct mac_layoutstate *curstate,
307                               struct controlset *s,
308                               WindowPtr window, struct macctrls *mcs)
309 {
310     unsigned int i, j, ncols, colstart, colspan;
311     struct mac_layoutstate cols[MAXCOLS], pos;
312
313     /* Start a containing box, if we have a boxname. */
314     if (s->boxname && *s->boxname) {
315         curstate->boxpos = curstate->pos;
316         if (s->boxtitle) {
317             curstate->boxname = s->boxtitle;
318             curstate->pos.v += 10; /* XXX determine font height */
319         } else {
320             curstate->boxname = NULL;
321         }
322         curstate->pos.v += 6;
323         curstate->pos.h += 12;
324         curstate->width -= 24;
325     }
326
327     /* Draw a title, if we have one. */
328     if (!s->boxname && s->boxtitle) {
329         union control *ctrl = snew(union control);
330         ctrl->generic.handler = NULL;
331         ctrl->text.label = dupstr(s->boxtitle);
332         macctrl_text(mcs, window, curstate, ctrl);
333         /* FIXME: should be highlighted, centred or boxed */
334     }
335
336     cols[0] = *curstate;
337     ncols = 1;
338
339     for (i = 0; i < s->ncontrols; i++) {
340         union control *ctrl = s->ctrls[i];
341
342         colstart = COLUMN_START(ctrl->generic.column);
343         colspan = COLUMN_SPAN(ctrl->generic.column);
344         if (ctrl->generic.type == CTRL_COLUMNS) {
345             if (ctrl->columns.ncols != 1) {
346                 ncols = ctrl->columns.ncols;
347                 assert(ncols <= MAXCOLS);
348                 for (j = 0; j < ncols; j++) {
349                     cols[j] = cols[0];
350                     if (j > 0)
351                         cols[j].pos.h = cols[j-1].pos.h + cols[j-1].width + 6;
352                     if (j == ncols - 1)
353                         cols[j].width = curstate->width -
354                             (cols[j].pos.h - curstate->pos.h);
355                     else
356                         cols[j].width = (curstate->width + 6) * 
357                             ctrl->columns.percentages[j] / 100 - 6;
358                 }
359             } else {
360                 for (j = 0; j < ncols; j++)
361                     if (cols[j].pos.v > cols[0].pos.v)
362                         cols[0].pos.v = cols[j].pos.v;
363                 cols[0].width = curstate->width;
364                 ncols = 1;
365             }
366         } else {
367             pos = cols[colstart];
368             pos.width = cols[colstart + colspan - 1].width +
369                 (cols[colstart + colspan - 1].pos.h - cols[colstart].pos.h);
370
371             for (j = colstart; j < colstart + colspan; j++)
372                 if (pos.pos.v < cols[j].pos.v)
373                     pos.pos.v = cols[j].pos.v;
374
375             switch (ctrl->generic.type) {
376               case CTRL_TEXT:
377                 macctrl_text(mcs, window, &pos, ctrl);
378                 break;
379               case CTRL_EDITBOX:
380                 macctrl_editbox(mcs, window, &pos, ctrl);
381                 break;
382               case CTRL_RADIO:
383                 macctrl_radio(mcs, window, &pos, ctrl);
384                 break;
385               case CTRL_CHECKBOX:
386                 macctrl_checkbox(mcs, window, &pos, ctrl);
387                 break;
388               case CTRL_BUTTON:
389                 macctrl_button(mcs, window, &pos, ctrl);
390                 break;
391               case CTRL_LISTBOX:
392                 if (ctrl->listbox.height == 0)
393                     macctrl_popup(mcs, window, &pos, ctrl);
394                 else
395                     macctrl_listbox(mcs, window, &pos, ctrl);
396                 break;
397             }
398             for (j = colstart; j < colstart + colspan; j++)
399                 cols[j].pos.v = pos.pos.v;
400         }
401     }
402     for (j = 0; j < ncols; j++)
403         if (cols[j].pos.v > curstate->pos.v)
404             curstate->pos.v = cols[j].pos.v;
405
406     if (s->boxname && *s->boxname) {
407         union control *ctrl = snew(union control);
408         /* We're coming out of a box, so set the width back */
409         curstate->pos.h -= 12;
410         curstate->width += 24;
411         /* And draw the box to the original width */
412         macctrl_groupbox(mcs, window, curstate, ctrl);
413     }
414 }
415
416 static void macctrl_hideshowpanel(struct macctrls *mcs, unsigned int panel,
417                                   int showit)
418 {
419     union macctrl *mc;
420     int j;
421
422 #define hideshow(c) do {                                                \
423     if (showit) ShowControl(c); else HideControl(c);                    \
424 } while (0)
425
426     for (mc = mcs->panels[panel]; mc != NULL; mc = mc->generic.next) {
427 #if !TARGET_API_MAC_CARBON
428         if (mcs->focus == mc)
429             macctrl_setfocus(mcs, NULL);
430 #endif
431         switch (mc->generic.type) {
432           case MACCTRL_TEXT:
433             hideshow(mc->text.tbctrl);
434             break;
435           case MACCTRL_EDITBOX:
436             hideshow(mc->editbox.tbctrl);
437             if (mc->editbox.tblabel != NULL)
438                 hideshow(mc->editbox.tblabel);
439             break;
440           case MACCTRL_RADIO:
441             for (j = 0; j < mc->generic.ctrl->radio.nbuttons; j++)
442                 hideshow(mc->radio.tbctrls[j]);
443             if (mc->radio.tblabel != NULL)
444                 hideshow(mc->radio.tblabel);
445             break;
446           case MACCTRL_CHECKBOX:
447             hideshow(mc->checkbox.tbctrl);
448             break;
449           case MACCTRL_BUTTON:
450             hideshow(mc->button.tbctrl);
451             if (mc->button.tbring != NULL)
452                 hideshow(mc->button.tbring);
453             break;
454           case MACCTRL_LISTBOX:
455             hideshow(mc->listbox.tbctrl);
456             /*
457              * At least under Mac OS 8.1, hiding a list box
458              * doesn't hide its scroll bars.
459              */
460 #if TARGET_API_MAC_CARBON
461             hideshow(GetListVerticalScrollBar(mc->listbox.list));
462 #else
463             hideshow((*mc->listbox.list)->vScroll);
464 #endif
465             break;
466           case MACCTRL_POPUP:
467             hideshow(mc->popup.tbctrl);
468             break;
469           case MACCTRL_GROUPBOX:
470             hideshow(mc->groupbox.tbctrl);
471             break;
472         }
473     }
474 }
475
476 static void macctrl_switchtopanel(struct macctrls *mcs, unsigned int which)
477 {
478
479     macctrl_hideshowpanel(mcs, mcs->curpanel, FALSE);
480     macctrl_hideshowpanel(mcs, which, TRUE);
481     mcs->curpanel = which;
482 }
483
484 #if !TARGET_API_MAC_CARBON
485 /*
486  * System 7 focus manipulation
487  */
488 static void macctrl_defocus(union macctrl *mc)
489 {
490
491     assert(mac_gestalts.apprvers < 0x100);
492     switch (mc->generic.type) {
493       case MACCTRL_EDITBOX:
494         TEDeactivate((TEHandle)(*mc->editbox.tbctrl)->contrlData);
495         break;
496     }
497 }
498
499 static void macctrl_enfocus(union macctrl *mc)
500 {
501
502     assert(mac_gestalts.apprvers < 0x100);
503     switch (mc->generic.type) {
504       case MACCTRL_EDITBOX:
505         TEActivate((TEHandle)(*mc->editbox.tbctrl)->contrlData);
506         break;
507     }
508 }
509
510 static void macctrl_setfocus(struct macctrls *mcs, union macctrl *mc)
511 {
512
513     if (mcs->focus == mc)
514         return;
515     if (mcs->focus != NULL)
516         macctrl_defocus(mcs->focus);
517     mcs->focus = mc;
518     if (mc != NULL)
519         macctrl_enfocus(mc);
520 }
521 #endif
522
523 static void macctrl_text(struct macctrls *mcs, WindowPtr window,
524                          struct mac_layoutstate *curstate,
525                          union control *ctrl)
526 {
527     union macctrl *mc = snew(union macctrl);
528     Rect bounds;
529     SInt16 height;
530
531     assert(ctrl->text.label != NULL);
532     mc->generic.type = MACCTRL_TEXT;
533     mc->generic.ctrl = ctrl;
534     mc->generic.privdata = NULL;
535     bounds.left = curstate->pos.h;
536     bounds.right = bounds.left + curstate->width;
537     bounds.top = curstate->pos.v;
538     bounds.bottom = bounds.top + 16;
539     if (mac_gestalts.apprvers >= 0x100) {
540         Size olen;
541
542         mc->text.tbctrl = NewControl(window, &bounds, NULL, FALSE, 0, 0, 0,
543                                      kControlStaticTextProc, (long)mc);
544         SetControlData(mc->text.tbctrl, kControlEntireControl,
545                        kControlStaticTextTextTag,
546                        strlen(ctrl->text.label), ctrl->text.label);
547         GetControlData(mc->text.tbctrl, kControlEntireControl,
548                        kControlStaticTextTextHeightTag,
549                        sizeof(height), &height, &olen);
550     }
551 #if !TARGET_API_MAC_CARBON
552     else {
553         TEHandle te;
554
555         mc->text.tbctrl = NewControl(window, &bounds, NULL, FALSE, 0, 0, 0,
556                                      SYS7_TEXT_PROC, (long)mc);
557         te = (TEHandle)(*mc->text.tbctrl)->contrlData;
558         TESetText(ctrl->text.label, strlen(ctrl->text.label), te);
559         height = TEGetHeight(1, (*te)->nLines, te);
560     }
561 #endif
562     SizeControl(mc->text.tbctrl, curstate->width, height);
563     curstate->pos.v += height + 6;
564     add234(mcs->byctrl, mc);
565     mc->generic.next = mcs->panels[curstate->panelnum];
566     mcs->panels[curstate->panelnum] = mc;
567 }
568
569 static void macctrl_editbox(struct macctrls *mcs, WindowPtr window,
570                             struct mac_layoutstate *curstate,
571                             union control *ctrl)
572 {
573     union macctrl *mc = snew(union macctrl);
574     Rect lbounds, bounds;
575
576     mc->generic.type = MACCTRL_EDITBOX;
577     mc->generic.ctrl = ctrl;
578     mc->generic.privdata = NULL;
579     lbounds.left = curstate->pos.h;
580     lbounds.top = curstate->pos.v;
581     if (ctrl->editbox.percentwidth == 100) {
582         if (ctrl->editbox.label != NULL) {
583             lbounds.right = lbounds.left + curstate->width;
584             lbounds.bottom = lbounds.top + 16;
585             curstate->pos.v += 18;
586         }
587         bounds.left = curstate->pos.h;
588         bounds.right = bounds.left + curstate->width;
589     } else {
590         lbounds.right = lbounds.left +
591             curstate->width * (100 - ctrl->editbox.percentwidth) / 100;
592         lbounds.bottom = lbounds.top + 22;
593         bounds.left = lbounds.right;
594         bounds.right = lbounds.left + curstate->width;
595     }
596     bounds.top = curstate->pos.v;
597     bounds.bottom = bounds.top + 22;
598     if (mac_gestalts.apprvers >= 0x100) {
599         if (ctrl->editbox.label == NULL)
600             mc->editbox.tblabel = NULL;
601         else {
602             mc->editbox.tblabel = NewControl(window, &lbounds, NULL, FALSE,
603                                              0, 0, 0, kControlStaticTextProc,
604                                              (long)mc);
605             SetControlData(mc->editbox.tblabel, kControlEntireControl,
606                            kControlStaticTextTextTag,
607                            strlen(ctrl->editbox.label), ctrl->editbox.label);
608         }
609         InsetRect(&bounds, 3, 3);
610         mc->editbox.tbctrl = NewControl(window, &bounds, NULL, FALSE, 0, 0, 0,
611                                         ctrl->editbox.password ?
612                                         kControlEditTextPasswordProc :
613                                         kControlEditTextProc, (long)mc);
614     }
615 #if !TARGET_API_MAC_CARBON
616     else {
617         if (ctrl->editbox.label == NULL)
618             mc->editbox.tblabel = NULL;
619         else {
620             mc->editbox.tblabel = NewControl(window, &lbounds, NULL, FALSE,
621                                              0, 0, 0, SYS7_TEXT_PROC,
622                                              (long)mc);
623             TESetText(ctrl->editbox.label, strlen(ctrl->editbox.label),
624                       (TEHandle)(*mc->editbox.tblabel)->contrlData);
625         }
626         mc->editbox.tbctrl = NewControl(window, &bounds, NULL, FALSE, 0, 0, 0,
627                                         SYS7_EDITBOX_PROC, (long)mc);
628     }
629 #endif
630     curstate->pos.v += 28;
631     add234(mcs->byctrl, mc);
632     mc->generic.next = mcs->panels[curstate->panelnum];
633     mcs->panels[curstate->panelnum] = mc;
634     ctrlevent(mcs, mc, EVENT_REFRESH);
635 }
636
637 #if !TARGET_API_MAC_CARBON
638 static pascal SInt32 macctrl_sys7_editbox_cdef(SInt16 variant,
639                                                ControlRef control,
640                                                ControlDefProcMessage msg,
641                                                SInt32 param)
642 {
643     RgnHandle rgn;
644     Rect rect;
645     TEHandle te;
646     long ssfs;
647     Point mouse;
648
649     switch (msg) {
650       case initCntl:
651         rect = (*control)->contrlRect;
652         if (variant == SYS7_EDITBOX_VARIANT)
653             InsetRect(&rect, 3, 3); /* 2 if it's 20 pixels high */
654         te = TENew(&rect, &rect);
655         ssfs = GetScriptVariable(smSystemScript, smScriptSysFondSize);
656         (*te)->txSize = LoWord(ssfs);
657         (*te)->txFont = HiWord(ssfs);
658         (*control)->contrlData = (Handle)te;
659         return noErr;
660       case dispCntl:
661         TEDispose((TEHandle)(*control)->contrlData);
662         return 0;
663       case drawCntl:
664         if ((*control)->contrlVis) {
665             rect = (*control)->contrlRect;
666             if (variant == SYS7_EDITBOX_VARIANT) {
667                 PenNormal();
668                 FrameRect(&rect);
669                 InsetRect(&rect, 3, 3);
670             }
671             EraseRect(&rect);
672             (*(TEHandle)(*control)->contrlData)->viewRect = rect;
673             TEUpdate(&rect, (TEHandle)(*control)->contrlData);
674         }
675         return 0;
676       case testCntl:
677         if (variant == SYS7_TEXT_VARIANT)
678             return kControlNoPart;
679         mouse.h = LoWord(param);
680         mouse.v = HiWord(param);
681         rect = (*control)->contrlRect;
682         InsetRect(&rect, 3, 3);
683         return PtInRect(mouse, &rect) ? kControlEditTextPart : kControlNoPart;
684       case calcCRgns:
685         if (param & (1 << 31)) {
686             param &= ~(1 << 31);
687             goto calcthumbrgn;
688         }
689         /* FALLTHROUGH */
690       case calcCntlRgn:
691         rgn = (RgnHandle)param;
692         RectRgn(rgn, &(*control)->contrlRect);
693         return 0;
694       case calcThumbRgn:
695       calcthumbrgn:
696         rgn = (RgnHandle)param;
697         SetEmptyRgn(rgn);
698         return 0;
699     }
700
701     return 0;
702 }
703 #endif
704
705 static void macctrl_radio(struct macctrls *mcs, WindowPtr window,
706                           struct mac_layoutstate *curstate,
707                           union control *ctrl)
708 {
709     union macctrl *mc = snew(union macctrl);
710     Rect bounds;
711     Str255 title;
712     unsigned int i, colwidth;
713
714     mc->generic.type = MACCTRL_RADIO;
715     mc->generic.ctrl = ctrl;
716     mc->generic.privdata = NULL;
717     mc->radio.tbctrls = snewn(ctrl->radio.nbuttons, ControlRef);
718     colwidth = (curstate->width + 13) / ctrl->radio.ncolumns;
719     bounds.top = curstate->pos.v;
720     bounds.bottom = bounds.top + 16;
721     bounds.left = curstate->pos.h;
722     bounds.right = bounds.left + curstate->width;
723     if (ctrl->radio.label == NULL)
724         mc->radio.tblabel = NULL;
725     else {
726         if (mac_gestalts.apprvers >= 0x100) {
727             mc->radio.tblabel = NewControl(window, &bounds, NULL, FALSE,
728                                            0, 0, 0, kControlStaticTextProc,
729                                            (long)mc);
730             SetControlData(mc->radio.tblabel, kControlEntireControl,
731                            kControlStaticTextTextTag,
732                            strlen(ctrl->radio.label), ctrl->radio.label);
733         }
734 #if !TARGET_API_MAC_CARBON
735         else {
736             mc->radio.tblabel = NewControl(window, &bounds, NULL, FALSE,
737                                            0, 0, 0, SYS7_TEXT_PROC, (long)mc);
738             TESetText(ctrl->radio.label, strlen(ctrl->radio.label),
739                       (TEHandle)(*mc->radio.tblabel)->contrlData);
740         }
741 #endif
742         curstate->pos.v += 18;
743     }
744     for (i = 0; i < ctrl->radio.nbuttons; i++) {
745         bounds.top = curstate->pos.v - 2;
746         bounds.bottom = bounds.top + 18;
747         bounds.left = curstate->pos.h + colwidth * (i % ctrl->radio.ncolumns);
748         if (i == ctrl->radio.nbuttons - 1 ||
749             i % ctrl->radio.ncolumns == ctrl->radio.ncolumns - 1) {
750             bounds.right = curstate->pos.h + curstate->width;
751             curstate->pos.v += 18;
752         } else
753             bounds.right = bounds.left + colwidth - 13;
754         c2pstrcpy(title, ctrl->radio.buttons[i]);
755         mc->radio.tbctrls[i] = NewControl(window, &bounds, title, FALSE,
756                                           0, 0, 1, radioButProc, (long)mc);
757     }
758     curstate->pos.v += 4;
759     add234(mcs->byctrl, mc);
760     mc->generic.next = mcs->panels[curstate->panelnum];
761     mcs->panels[curstate->panelnum] = mc;
762     ctrlevent(mcs, mc, EVENT_REFRESH);
763 }
764
765 static void macctrl_checkbox(struct macctrls *mcs, WindowPtr window,
766                              struct mac_layoutstate *curstate,
767                              union control *ctrl)
768 {
769     union macctrl *mc = snew(union macctrl);
770     Rect bounds;
771     Str255 title;
772
773     assert(ctrl->checkbox.label != NULL);
774     mc->generic.type = MACCTRL_CHECKBOX;
775     mc->generic.ctrl = ctrl;
776     mc->generic.privdata = NULL;
777     bounds.left = curstate->pos.h;
778     bounds.right = bounds.left + curstate->width;
779     bounds.top = curstate->pos.v;
780     bounds.bottom = bounds.top + 16;
781     c2pstrcpy(title, ctrl->checkbox.label);
782     mc->checkbox.tbctrl = NewControl(window, &bounds, title, FALSE, 0, 0, 1,
783                                      checkBoxProc, (long)mc);
784     add234(mcs->byctrl, mc);
785     curstate->pos.v += 22;
786     mc->generic.next = mcs->panels[curstate->panelnum];
787     mcs->panels[curstate->panelnum] = mc;
788     ctrlevent(mcs, mc, EVENT_REFRESH);
789 }
790
791 static void macctrl_button(struct macctrls *mcs, WindowPtr window,
792                            struct mac_layoutstate *curstate,
793                            union control *ctrl)
794 {
795     union macctrl *mc = snew(union macctrl);
796     Rect bounds;
797     Str255 title;
798
799     assert(ctrl->button.label != NULL);
800     mc->generic.type = MACCTRL_BUTTON;
801     mc->generic.ctrl = ctrl;
802     mc->generic.privdata = NULL;
803     bounds.left = curstate->pos.h;
804     bounds.right = bounds.left + curstate->width;
805     bounds.top = curstate->pos.v;
806     bounds.bottom = bounds.top + 20;
807     c2pstrcpy(title, ctrl->button.label);
808     mc->button.tbctrl = NewControl(window, &bounds, title, FALSE, 0, 0, 1,
809                                    pushButProc, (long)mc);
810     mc->button.tbring = NULL;
811     if (mac_gestalts.apprvers >= 0x100) {
812         Boolean isdefault = ctrl->button.isdefault;
813
814         SetControlData(mc->button.tbctrl, kControlEntireControl,
815                        kControlPushButtonDefaultTag,
816                        sizeof(isdefault), &isdefault);
817     } else if (ctrl->button.isdefault) {
818         InsetRect(&bounds, -4, -4);
819         mc->button.tbring = NewControl(window, &bounds, title, FALSE, 0, 0, 1,
820                                        SYS7_DEFAULT_PROC, (long)mc);
821     }
822     if (mac_gestalts.apprvers >= 0x110) {
823         Boolean iscancel = ctrl->button.iscancel;
824
825         SetControlData(mc->button.tbctrl, kControlEntireControl,
826                        kControlPushButtonCancelTag,
827                        sizeof(iscancel), &iscancel);
828     }
829     if (ctrl->button.isdefault)
830         mcs->defbutton = mc;
831     if (ctrl->button.iscancel)
832         mcs->canbutton = mc;
833     add234(mcs->byctrl, mc);
834     mc->generic.next = mcs->panels[curstate->panelnum];
835     mcs->panels[curstate->panelnum] = mc;
836     curstate->pos.v += 26;
837 }
838
839 #if !TARGET_API_MAC_CARBON
840 static pascal SInt32 macctrl_sys7_default_cdef(SInt16 variant,
841                                                ControlRef control,
842                                                ControlDefProcMessage msg,
843                                                SInt32 param)
844 {
845     RgnHandle rgn;
846     Rect rect;
847     int oval;
848     PenState savestate;
849
850     switch (msg) {
851       case drawCntl:
852         if ((*control)->contrlVis) {
853             rect = (*control)->contrlRect;
854             GetPenState(&savestate);
855             PenNormal();
856             PenSize(3, 3);
857             if ((*control)->contrlHilite == kControlInactivePart)
858                 PenPat(&qd.gray);
859             oval = (rect.bottom - rect.top) / 2 + 2;
860             FrameRoundRect(&rect, oval, oval);
861             SetPenState(&savestate);
862         }
863         return 0;
864       case calcCRgns:
865         if (param & (1 << 31)) {
866             param &= ~(1 << 31);
867             goto calcthumbrgn;
868         }
869         /* FALLTHROUGH */
870       case calcCntlRgn:
871         rgn = (RgnHandle)param;
872         RectRgn(rgn, &(*control)->contrlRect);
873         return 0;
874       case calcThumbRgn:
875       calcthumbrgn:
876         rgn = (RgnHandle)param;
877         SetEmptyRgn(rgn);
878         return 0;
879     }
880
881     return 0;
882 }
883 #endif
884
885 static void macctrl_listbox(struct macctrls *mcs, WindowPtr window,
886                             struct mac_layoutstate *curstate,
887                             union control *ctrl)
888 {
889     union macctrl *mc = snew(union macctrl);
890     Rect bounds;
891     Size olen;
892
893     /* XXX Use label */
894     assert(ctrl->listbox.percentwidth == 100);
895     mc->generic.type = MACCTRL_LISTBOX;
896     mc->generic.ctrl = ctrl;
897     mc->generic.privdata = NULL;
898     /* The list starts off empty */
899     mc->listbox.nids = 0;
900     mc->listbox.ids = NULL;
901     bounds.left = curstate->pos.h;
902     bounds.right = bounds.left + curstate->width;
903     bounds.top = curstate->pos.v;
904     bounds.bottom = bounds.top + 16 * ctrl->listbox.height + 2;
905
906     if (mac_gestalts.apprvers >= 0x100) {
907         InsetRect(&bounds, 3, 3);
908         mc->listbox.tbctrl = NewControl(window, &bounds, NULL, FALSE,
909                                         ldes_Default, 0, 0,
910                                         kControlListBoxProc, (long)mc);
911         if (GetControlData(mc->listbox.tbctrl, kControlEntireControl,
912                            kControlListBoxListHandleTag,
913                            sizeof(mc->listbox.list), &mc->listbox.list,
914                            &olen) != noErr) {
915             DisposeControl(mc->listbox.tbctrl);
916             sfree(mc);
917             return;
918         }
919     }
920 #if !TARGET_API_MAC_CARBON
921     else {
922         InsetRect(&bounds, -3, -3);
923         mc->listbox.tbctrl = NewControl(window, &bounds, NULL, FALSE,
924                                         0, 0, 0,
925                                         SYS7_LISTBOX_PROC, (long)mc);
926         mc->listbox.list = (ListHandle)(*mc->listbox.tbctrl)->contrlData;
927         (*mc->listbox.list)->refCon = (long)mc;
928     }
929 #endif
930     if (!ctrl->listbox.multisel) {
931 #if TARGET_API_MAC_CARBON
932         SetListSelectionFlags(mc->listbox.list, lOnlyOne);
933 #else
934         (*mc->listbox.list)->selFlags = lOnlyOne;
935 #endif
936     }
937     add234(mcs->byctrl, mc);
938     curstate->pos.v += 6 + 16 * ctrl->listbox.height + 2;
939     mc->generic.next = mcs->panels[curstate->panelnum];
940     mcs->panels[curstate->panelnum] = mc;
941     ctrlevent(mcs, mc, EVENT_REFRESH);
942 #if TARGET_API_MAC_CARBON
943     HideControl(GetListVerticalScrollBar(mc->listbox.list));
944 #else
945     HideControl((*mc->listbox.list)->vScroll);
946 #endif
947 }
948
949 #if !TARGET_API_MAC_CARBON
950 static pascal SInt32 macctrl_sys7_listbox_cdef(SInt16 variant,
951                                                ControlRef control,
952                                                ControlDefProcMessage msg,
953                                                SInt32 param)
954 {
955     RgnHandle rgn;
956     Rect rect;
957     ListHandle list;
958     long ssfs;
959     Point mouse;
960     ListBounds bounds;
961     Point csize;
962     short savefont;
963     short savesize;
964     GrafPtr curport;
965
966     switch (msg) {
967       case initCntl:
968         rect = (*control)->contrlRect;
969         InsetRect(&rect, 4, 4);
970         rect.right -= 15; /* scroll bar */
971         bounds.top = bounds.bottom = bounds.left = 0;
972         bounds.right = 1;
973         csize.h = csize.v = 0;
974         GetPort(&curport);
975         savefont = curport->txFont;
976         savesize = curport->txSize;
977         ssfs = GetScriptVariable(smSystemScript, smScriptSysFondSize);
978         TextFont(HiWord(ssfs));
979         TextSize(LoWord(ssfs));
980         list = LNew(&rect, &bounds, csize, 0, (*control)->contrlOwner,
981                     TRUE, FALSE, FALSE, TRUE);
982         SetControlReference((*list)->vScroll, (long)list);
983         (*control)->contrlData = (Handle)list;
984         TextFont(savefont);
985         TextSize(savesize);
986         return noErr;
987       case dispCntl:
988         /*
989          * If the dialogue box is being destroyed, the scroll bar
990          * might have gone already.  In our situation, this is the
991          * only time we destroy a control, so NULL out the scroll bar
992          * handle to prevent LDispose trying to free it.
993          */
994         list = (ListHandle)(*control)->contrlData;
995         (*list)->vScroll = NULL;
996         LDispose(list);
997         return 0;
998       case drawCntl:
999         if ((*control)->contrlVis) {
1000             rect = (*control)->contrlRect;
1001             /* XXX input focus highlighting? */
1002             InsetRect(&rect, 3, 3);
1003             PenNormal();
1004             FrameRect(&rect);
1005             list = (ListHandle)(*control)->contrlData;
1006             LActivate((*control)->contrlHilite != kControlInactivePart, list);
1007             GetPort(&curport);
1008             LUpdate(curport->visRgn, list);
1009         }
1010         return 0;
1011       case testCntl:
1012         mouse.h = LoWord(param);
1013         mouse.v = HiWord(param);
1014         rect = (*control)->contrlRect;
1015         InsetRect(&rect, 4, 4);
1016         /*
1017          * We deliberately exclude the scrollbar so that LClick() can see it.
1018          */
1019         rect.right -= 15;
1020         return PtInRect(mouse, &rect) ? kControlListBoxPart : kControlNoPart;
1021       case calcCRgns:
1022         if (param & (1 << 31)) {
1023             param &= ~(1 << 31);
1024             goto calcthumbrgn;
1025         }
1026         /* FALLTHROUGH */
1027       case calcCntlRgn:
1028         rgn = (RgnHandle)param;
1029         RectRgn(rgn, &(*control)->contrlRect);
1030         return 0;
1031       case calcThumbRgn:
1032       calcthumbrgn:
1033         rgn = (RgnHandle)param;
1034         SetEmptyRgn(rgn);
1035         return 0;
1036     }
1037
1038     return 0;
1039 }
1040 #endif
1041
1042 #if !TARGET_API_MAC_CARBON
1043 static pascal SInt32 macctrl_sys7_groupbox_cdef(SInt16 variant,
1044                                                 ControlRef control,
1045                                                 ControlDefProcMessage msg,
1046                                                 SInt32 param)
1047 {
1048     RgnHandle rgn;
1049     Rect rect;
1050     PenState savestate;
1051
1052     switch (msg) {
1053       case drawCntl:
1054         if ((*control)->contrlVis) {
1055             rect = (*control)->contrlRect;
1056             GetPenState(&savestate);
1057             PenNormal();
1058             PenSize(3, 3);
1059             PenPat(&qd.gray);
1060             FrameRect(&rect);
1061             SetPenState(&savestate);
1062         }
1063         return 0;
1064       case calcCRgns:
1065         if (param & (1 << 31)) {
1066             param &= ~(1 << 31);
1067             goto calcthumbrgn;
1068         }
1069         /* FALLTHROUGH */
1070       case calcCntlRgn:
1071         rgn = (RgnHandle)param;
1072         RectRgn(rgn, &(*control)->contrlRect);
1073         return 0;
1074       case calcThumbRgn:
1075       calcthumbrgn:
1076         rgn = (RgnHandle)param;
1077         SetEmptyRgn(rgn);
1078         return 0;
1079     }
1080     return 0;
1081 }
1082 #endif
1083
1084 static void macctrl_popup(struct macctrls *mcs, WindowPtr window,
1085                           struct mac_layoutstate *curstate,
1086                           union control *ctrl)
1087 {
1088     union macctrl *mc = snew(union macctrl);
1089     Rect bounds;
1090     Str255 title;
1091     unsigned int labelwidth;
1092     static int nextmenuid = MENU_MIN;
1093     int menuid;
1094     MenuRef menu;
1095
1096     /* 
1097      * <http://developer.apple.com/qa/tb/tb42.html> explains how to
1098      * create a popup menu with dynamic content.
1099      */
1100     assert(ctrl->listbox.height == 0);
1101     assert(!ctrl->listbox.draglist);
1102     assert(!ctrl->listbox.multisel);
1103
1104     mc->generic.type = MACCTRL_POPUP;
1105     mc->generic.ctrl = ctrl;
1106     mc->generic.privdata = NULL;
1107     c2pstrcpy(title, ctrl->button.label == NULL ? "" : ctrl->button.label);
1108
1109     /* Find a spare menu ID and create the menu */
1110     while (GetMenuHandle(nextmenuid) != NULL)
1111         if (++nextmenuid >= MENU_MAX) nextmenuid = MENU_MIN;
1112     menuid = nextmenuid++;
1113     menu = NewMenu(menuid, "\pdummy");
1114     if (menu == NULL) return;
1115     mc->popup.menu = menu;
1116     mc->popup.menuid = menuid;
1117     InsertMenu(menu, kInsertHierarchicalMenu);
1118
1119     /* The menu starts off empty */
1120     mc->popup.nids = 0;
1121     mc->popup.ids = NULL;
1122
1123     bounds.left = curstate->pos.h;
1124     bounds.right = bounds.left + curstate->width;
1125     bounds.top = curstate->pos.v;
1126     bounds.bottom = bounds.top + 20;
1127     /* XXX handle percentwidth == 100 */
1128     labelwidth = curstate->width * (100 - ctrl->listbox.percentwidth) / 100;
1129     mc->popup.tbctrl = NewControl(window, &bounds, title, FALSE,
1130                                   popupTitleLeftJust, menuid, labelwidth,
1131                                   popupMenuProc + popupFixedWidth, (long)mc);
1132     add234(mcs->byctrl, mc);
1133     curstate->pos.v += 26;
1134     mc->generic.next = mcs->panels[curstate->panelnum];
1135     mcs->panels[curstate->panelnum] = mc;
1136     ctrlevent(mcs, mc, EVENT_REFRESH);
1137 }
1138
1139 static void macctrl_groupbox(struct macctrls *mcs, WindowPtr window,
1140                              struct mac_layoutstate *curstate,
1141                              union control *ctrl)
1142 {
1143     union macctrl *mc = snew (union macctrl);
1144     Str255 ptitle;
1145     Rect r;
1146
1147     r.top = curstate->boxpos.v;
1148     r.left = curstate->boxpos.h;
1149     r.bottom = curstate->pos.v;
1150     r.right = curstate->boxpos.h + curstate->width;
1151
1152     mc->generic.type = MACCTRL_GROUPBOX;
1153     mc->generic.privdata = NULL;
1154     mc->generic.ctrl = ctrl;
1155     mc->generic.ctrl->generic.handler = NULL;
1156
1157     if (curstate->boxname)
1158         c2pstrcpy(ptitle, curstate->boxname);
1159     else
1160         c2pstrcpy(ptitle, "");
1161     if (mac_gestalts.apprvers >= 0x100) { /* Appearance Manager */
1162         mc->groupbox.tbctrl = NewControl(window, &r, ptitle, FALSE, 0, 0, 1,
1163                                          kControlGroupBoxTextTitleProc, (long)mc);
1164     } else {
1165         mc->groupbox.tbctrl = NewControl(window, &r, ptitle, FALSE, 0, 0, 1,
1166                                          SYS7_GROUPBOX_PROC, (long)mc);
1167     }
1168     add234(mcs->byctrl, mc);
1169     mc->generic.next = mcs->panels[curstate->panelnum];
1170     mcs->panels[curstate->panelnum] = mc;
1171 }
1172
1173 void macctrl_activate(WindowPtr window, EventRecord *event)
1174 {
1175     struct macctrls *mcs = mac_winctrls(window);
1176     Boolean active = (event->modifiers & activeFlag) != 0;
1177     GrafPtr saveport;
1178     int i, j;
1179     ControlPartCode state;
1180     union macctrl *mc;
1181
1182     GetPort(&saveport);
1183     SetPort((GrafPtr)GetWindowPort(window));
1184     if (mac_gestalts.apprvers >= 0x100)
1185         SetThemeWindowBackground(window, active ?
1186                                  kThemeBrushModelessDialogBackgroundActive :
1187                                  kThemeBrushModelessDialogBackgroundInactive,
1188                                  TRUE);
1189     state = active ? kControlNoPart : kControlInactivePart;
1190     for (i = 0; i <= mcs->curpanel; i += mcs->curpanel)
1191         for (mc = mcs->panels[i]; mc != NULL; mc = mc->generic.next) {
1192             switch (mc->generic.type) {
1193               case MACCTRL_TEXT:
1194                 HiliteControl(mc->text.tbctrl, state);
1195                 break;
1196               case MACCTRL_EDITBOX:
1197                 HiliteControl(mc->editbox.tbctrl, state);
1198                 if (mc->editbox.tblabel != NULL)
1199                     HiliteControl(mc->editbox.tblabel, state);
1200                 break;
1201               case MACCTRL_RADIO:
1202                 for (j = 0; j < mc->generic.ctrl->radio.nbuttons; j++)
1203                     HiliteControl(mc->radio.tbctrls[j], state);
1204                 if (mc->radio.tblabel != NULL)
1205                     HiliteControl(mc->radio.tblabel, state);
1206                 break;
1207               case MACCTRL_CHECKBOX:
1208                 HiliteControl(mc->checkbox.tbctrl, state);
1209                 break;
1210               case MACCTRL_BUTTON:
1211                 HiliteControl(mc->button.tbctrl, state);
1212                 if (mc->button.tbring != NULL)
1213                     HiliteControl(mc->button.tbring, state);                
1214                 break;
1215               case MACCTRL_LISTBOX:
1216                 HiliteControl(mc->listbox.tbctrl, state);
1217                 break;
1218               case MACCTRL_POPUP:
1219                 HiliteControl(mc->popup.tbctrl, state);
1220                 break;
1221             }
1222 #if !TARGET_API_MAC_CARBON
1223             if (mcs->focus == mc) {
1224                 if (active)
1225                     macctrl_enfocus(mc);
1226                 else
1227                     macctrl_defocus(mc);
1228             }
1229 #endif
1230         }
1231     SetPort(saveport);
1232 }
1233
1234 void macctrl_click(WindowPtr window, EventRecord *event)
1235 {
1236     Point mouse;
1237     ControlHandle control, oldfocus;
1238     int part, trackresult;
1239     GrafPtr saveport;
1240     union macctrl *mc;
1241     struct macctrls *mcs = mac_winctrls(window);
1242     int i;
1243     UInt32 features;
1244
1245     GetPort(&saveport);
1246     SetPort((GrafPtr)GetWindowPort(window));
1247     mouse = event->where;
1248     GlobalToLocal(&mouse);
1249     part = FindControl(mouse, window, &control);
1250     if (control != NULL) {
1251 #if !TARGET_API_MAC_CARBON
1252         /*
1253          * Special magic for scroll bars in list boxes, whose refcon
1254          * is the list.
1255          */
1256         if (part == kControlUpButtonPart || part == kControlDownButtonPart ||
1257             part == kControlPageUpPart || part == kControlPageDownPart ||
1258             part == kControlIndicatorPart)
1259             mc = (union macctrl *)
1260                 (*(ListHandle)GetControlReference(control))->refCon;
1261        else
1262 #endif
1263             mc = (union macctrl *)GetControlReference(control);
1264         if (mac_gestalts.apprvers >= 0x100) {
1265             if (GetControlFeatures(control, &features) == noErr &&
1266                 (features & kControlSupportsFocus) &&
1267                 (features & kControlGetsFocusOnClick) &&
1268                 GetKeyboardFocus(window, &oldfocus) == noErr &&
1269                 control != oldfocus)
1270                 SetKeyboardFocus(window, control, part);
1271             trackresult = HandleControlClick(control, mouse, event->modifiers,
1272                                              (ControlActionUPP)-1);
1273         } else {
1274 #if !TARGET_API_MAC_CARBON
1275             if (mc->generic.type == MACCTRL_EDITBOX &&
1276                 control == mc->editbox.tbctrl) {
1277                 TEHandle te = (TEHandle)(*control)->contrlData;
1278
1279                 macctrl_setfocus(mcs, mc);
1280                 TEClick(mouse, !!(event->modifiers & shiftKey), te);
1281                 goto done;
1282             }
1283             if (mc->generic.type == MACCTRL_LISTBOX &&
1284                 (control == mc->listbox.tbctrl ||
1285                  control == (*mc->listbox.list)->vScroll)) {
1286
1287                 macctrl_setfocus(mcs, mc);
1288                 if (LClick(mouse, event->modifiers, mc->listbox.list))
1289                     /* double-click */
1290                     ctrlevent(mcs, mc, EVENT_ACTION);
1291                 else
1292                     ctrlevent(mcs, mc, EVENT_SELCHANGE);
1293                 goto done;
1294             }
1295 #endif
1296             trackresult = TrackControl(control, mouse, (ControlActionUPP)-1);
1297         }
1298         switch (mc->generic.type) {
1299           case MACCTRL_RADIO:
1300             if (trackresult != 0) {
1301                 for (i = 0; i < mc->generic.ctrl->radio.nbuttons; i++)
1302                     if (mc->radio.tbctrls[i] == control)
1303                         SetControlValue(mc->radio.tbctrls[i],
1304                                         kControlRadioButtonCheckedValue);
1305                     else
1306                         SetControlValue(mc->radio.tbctrls[i],
1307                                         kControlRadioButtonUncheckedValue);
1308                 ctrlevent(mcs, mc, EVENT_VALCHANGE);
1309             }
1310             break;
1311           case MACCTRL_CHECKBOX:
1312             if (trackresult != 0) {
1313                 SetControlValue(control, !GetControlValue(control));
1314                 ctrlevent(mcs, mc, EVENT_VALCHANGE);
1315             }
1316             break;
1317           case MACCTRL_BUTTON:
1318             if (trackresult != 0)
1319                 ctrlevent(mcs, mc, EVENT_ACTION);
1320             break;
1321           case MACCTRL_LISTBOX:
1322             /* FIXME spot double-click */
1323             ctrlevent(mcs, mc, EVENT_SELCHANGE);
1324             break;
1325           case MACCTRL_POPUP:
1326             ctrlevent(mcs, mc, EVENT_SELCHANGE);
1327             break;
1328         }
1329     }
1330   done:
1331     SetPort(saveport);
1332 }
1333
1334 void macctrl_key(WindowPtr window, EventRecord *event)
1335 {
1336     ControlRef control;
1337     struct macctrls *mcs = mac_winctrls(window);
1338     union macctrl *mc;
1339     unsigned long dummy;
1340
1341     switch (event->message & charCodeMask) {
1342       case kEnterCharCode:
1343       case kReturnCharCode:
1344         if (mcs->defbutton != NULL) {
1345             assert(mcs->defbutton->generic.type == MACCTRL_BUTTON);
1346             HiliteControl(mcs->defbutton->button.tbctrl, kControlButtonPart);
1347             /*
1348              * I'd like to delay unhilighting the button until after
1349              * the event has been processed, but by them the entire
1350              * dialgue box might have been destroyed.
1351              */
1352             Delay(6, &dummy);
1353             HiliteControl(mcs->defbutton->button.tbctrl, kControlNoPart);
1354             ctrlevent(mcs, mcs->defbutton, EVENT_ACTION);
1355         }
1356         return;
1357       case kEscapeCharCode:
1358         if (mcs->canbutton != NULL) {
1359             assert(mcs->canbutton->generic.type == MACCTRL_BUTTON);
1360             HiliteControl(mcs->canbutton->button.tbctrl, kControlButtonPart);
1361             Delay(6, &dummy);
1362             HiliteControl(mcs->defbutton->button.tbctrl, kControlNoPart);
1363             ctrlevent(mcs, mcs->canbutton, EVENT_ACTION);
1364         }
1365         return;
1366     }
1367     if (mac_gestalts.apprvers >= 0x100) {
1368         if (GetKeyboardFocus(window, &control) == noErr && control != NULL) {
1369             HandleControlKey(control, (event->message & keyCodeMask) >> 8,
1370                              event->message & charCodeMask, event->modifiers);
1371             mc = (union macctrl *)GetControlReference(control);
1372             switch (mc->generic.type) {
1373               case MACCTRL_LISTBOX:
1374                 ctrlevent(mcs, mc, EVENT_SELCHANGE);
1375                 break;
1376               default:
1377                 ctrlevent(mcs, mc, EVENT_VALCHANGE);
1378                 break;
1379             }
1380         }
1381     }
1382 #if !TARGET_API_MAC_CARBON
1383     else {
1384         TEHandle te;
1385
1386         if (mcs->focus != NULL) {
1387             mc = mcs->focus;
1388             switch (mc->generic.type) {
1389               case MACCTRL_EDITBOX:
1390                 te = (TEHandle)(*mc->editbox.tbctrl)->contrlData;
1391                 TEKey(event->message & charCodeMask, te);
1392                 ctrlevent(mcs, mc, EVENT_VALCHANGE);
1393                 break;
1394             }
1395         }
1396     }
1397 #endif
1398 }
1399
1400 void macctrl_update(WindowPtr window)
1401 {
1402 #if TARGET_API_MAC_CARBON
1403     RgnHandle visrgn;
1404 #endif
1405     Rect rect;
1406     GrafPtr saveport;
1407
1408     BeginUpdate(window);
1409     GetPort(&saveport);
1410     SetPort((GrafPtr)GetWindowPort(window));
1411     if (mac_gestalts.apprvers >= 0x101) {
1412 #if TARGET_API_MAC_CARBON
1413         GetPortBounds(GetWindowPort(window), &rect);
1414 #else
1415         rect = window->portRect;
1416 #endif
1417         InsetRect(&rect, -1, -1);
1418         DrawThemeModelessDialogFrame(&rect, mac_frontwindow() == window ?
1419                                      kThemeStateActive : kThemeStateInactive);
1420     }
1421 #if TARGET_API_MAC_CARBON
1422     visrgn = NewRgn();
1423     GetPortVisibleRegion(GetWindowPort(window), visrgn);
1424     UpdateControls(window, visrgn);
1425     DisposeRgn(visrgn);
1426 #else
1427     UpdateControls(window, window->visRgn);
1428 #endif
1429     SetPort(saveport);
1430     EndUpdate(window);
1431 }
1432
1433 #if TARGET_API_MAC_CARBON
1434 #define EnableItem EnableMenuItem
1435 #define DisableItem DisableMenuItem
1436 #endif
1437 void macctrl_adjustmenus(WindowPtr window)
1438 {
1439     MenuHandle menu;
1440
1441     menu = GetMenuHandle(mFile);
1442     DisableItem(menu, iSave); /* XXX enable if modified */
1443     EnableItem(menu, iSaveAs);
1444     EnableItem(menu, iDuplicate);
1445
1446     menu = GetMenuHandle(mEdit);
1447     DisableItem(menu, 0);
1448 }
1449
1450 void macctrl_close(WindowPtr window)
1451 {
1452     struct macctrls *mcs = mac_winctrls(window);
1453     union macctrl *mc;
1454
1455     /*
1456      * Mostly, we don't bother disposing of the Toolbox controls,
1457      * since that will happen automatically when the window is
1458      * disposed of.  Popup menus are an exception, because we have to
1459      * dispose of the menu ourselves, and doing that while the control
1460      * still holds a reference to it seems rude.
1461      */
1462     while ((mc = index234(mcs->byctrl, 0)) != NULL) {
1463         if (mc->generic.privdata != NULL && mc->generic.freeprivdata)
1464             sfree(mc->generic.privdata);
1465         switch (mc->generic.type) {
1466           case MACCTRL_POPUP:
1467             DisposeControl(mc->popup.tbctrl);
1468             DeleteMenu(mc->popup.menuid);
1469             DisposeMenu(mc->popup.menu);
1470             break;
1471         }
1472         del234(mcs->byctrl, mc);
1473         sfree(mc);
1474     }
1475
1476     freetree234(mcs->byctrl);
1477     mcs->byctrl = NULL;
1478     sfree(mcs->panels);
1479     mcs->panels = NULL;
1480 }
1481
1482 void dlg_update_start(union control *ctrl, void *dlg)
1483 {
1484
1485     /* No-op for now */
1486 }
1487
1488 void dlg_update_done(union control *ctrl, void *dlg)
1489 {
1490
1491     /* No-op for now */
1492 }
1493
1494 void dlg_set_focus(union control *ctrl, void *dlg)
1495 {
1496
1497     if (mac_gestalts.apprvers >= 0x100) {
1498         /* Use SetKeyboardFocus() */
1499     } else {
1500         /* Do our own mucking around */
1501     }
1502 }
1503
1504 union control *dlg_last_focused(union control *ctrl, void *dlg)
1505 {
1506
1507     return NULL;
1508 }
1509
1510 void dlg_beep(void *dlg)
1511 {
1512
1513     SysBeep(30);
1514 }
1515
1516 void dlg_error_msg(void *dlg, char *msg)
1517 {
1518     Str255 pmsg;
1519
1520     c2pstrcpy(pmsg, msg);
1521     ParamText(pmsg, NULL, NULL, NULL);
1522     StopAlert(128, NULL);
1523 }
1524
1525 void dlg_end(void *dlg, int value)
1526 {
1527     struct macctrls *mcs = dlg;
1528
1529     if (mcs->end != NULL)
1530         (*mcs->end)(mcs->window, value);
1531 };
1532
1533 void dlg_refresh(union control *ctrl, void *dlg)
1534 {
1535     struct macctrls *mcs = dlg;
1536     union macctrl *mc;
1537     int i;
1538
1539     if (ctrl == NULL) {
1540         /* NULL means refresh every control */
1541         for (i = 0 ; i < mcs->npanels; i++) {
1542             for (mc = mcs->panels[i]; mc != NULL; mc = mc->generic.next) {
1543                 ctrlevent(mcs, mc, EVENT_REFRESH);
1544             }
1545         }
1546         return;
1547     }
1548     /* Just refresh a specific control */
1549     mc = findbyctrl(mcs, ctrl);
1550     assert(mc != NULL);
1551     ctrlevent(mcs, mc, EVENT_REFRESH);
1552 };
1553
1554 void *dlg_get_privdata(union control *ctrl, void *dlg)
1555 {
1556     struct macctrls *mcs = dlg;
1557     union macctrl *mc = findbyctrl(mcs, ctrl);
1558
1559     assert(mc != NULL);
1560     return mc->generic.privdata;
1561 }
1562
1563 void dlg_set_privdata(union control *ctrl, void *dlg, void *ptr)
1564 {
1565     struct macctrls *mcs = dlg;
1566     union macctrl *mc = findbyctrl(mcs, ctrl);
1567
1568     assert(mc != NULL);
1569     mc->generic.privdata = ptr;
1570     mc->generic.freeprivdata = FALSE;
1571 }
1572
1573 void *dlg_alloc_privdata(union control *ctrl, void *dlg, size_t size)
1574 {
1575     struct macctrls *mcs = dlg;
1576     union macctrl *mc = findbyctrl(mcs, ctrl);
1577
1578     assert(mc != NULL);
1579     mc->generic.privdata = smalloc(size);
1580     mc->generic.freeprivdata = TRUE;
1581     return mc->generic.privdata;
1582 }
1583
1584
1585 /*
1586  * Radio Button control
1587  */
1588
1589 void dlg_radiobutton_set(union control *ctrl, void *dlg, int whichbutton)
1590 {
1591     struct macctrls *mcs = dlg;
1592     union macctrl *mc = findbyctrl(mcs, ctrl);
1593     int i;
1594
1595     if (mc == NULL) return;
1596     for (i = 0; i < ctrl->radio.nbuttons; i++) {
1597         if (i == whichbutton)
1598             SetControlValue(mc->radio.tbctrls[i],
1599                             kControlRadioButtonCheckedValue);
1600         else
1601             SetControlValue(mc->radio.tbctrls[i],
1602                             kControlRadioButtonUncheckedValue);
1603     }
1604
1605 };
1606
1607 int dlg_radiobutton_get(union control *ctrl, void *dlg)
1608 {
1609     struct macctrls *mcs = dlg;
1610     union macctrl *mc = findbyctrl(mcs, ctrl);
1611     int i;
1612
1613     assert(mc != NULL);
1614     for (i = 0; i < ctrl->radio.nbuttons; i++) {
1615         if (GetControlValue(mc->radio.tbctrls[i])  ==
1616             kControlRadioButtonCheckedValue)
1617             return i;
1618     }
1619     return -1;
1620 };
1621
1622
1623 /*
1624  * Check Box control
1625  */
1626
1627 void dlg_checkbox_set(union control *ctrl, void *dlg, int checked)
1628 {
1629     struct macctrls *mcs = dlg;
1630     union macctrl *mc = findbyctrl(mcs, ctrl);
1631
1632     if (mc == NULL) return;
1633     SetControlValue(mc->checkbox.tbctrl,
1634                     checked ? kControlCheckBoxCheckedValue :
1635                               kControlCheckBoxUncheckedValue);
1636 }
1637
1638 int dlg_checkbox_get(union control *ctrl, void *dlg)
1639 {
1640     struct macctrls *mcs = dlg;
1641     union macctrl *mc = findbyctrl(mcs, ctrl);
1642
1643     assert(mc != NULL);
1644     return GetControlValue(mc->checkbox.tbctrl);
1645 }
1646
1647
1648 /*
1649  * Edit Box control
1650  */
1651
1652 void dlg_editbox_set(union control *ctrl, void *dlg, char const *text)
1653 {
1654     struct macctrls *mcs = dlg;
1655     union macctrl *mc = findbyctrl(mcs, ctrl);
1656     GrafPtr saveport;
1657
1658     if (mc == NULL) return;
1659     assert(mc->generic.type == MACCTRL_EDITBOX);
1660     GetPort(&saveport);
1661     SetPort((GrafPtr)(GetWindowPort(mcs->window)));
1662     if (mac_gestalts.apprvers >= 0x100)
1663         SetControlData(mc->editbox.tbctrl, kControlEntireControl,
1664                        ctrl->editbox.password ?
1665                        kControlEditTextPasswordTag :
1666                        kControlEditTextTextTag,
1667                        strlen(text), text);
1668 #if !TARGET_API_MAC_CARBON
1669     else
1670         TESetText(text, strlen(text),
1671                   (TEHandle)(*mc->editbox.tbctrl)->contrlData);
1672 #endif
1673     DrawOneControl(mc->editbox.tbctrl);
1674     SetPort(saveport);
1675 }
1676
1677 void dlg_editbox_get(union control *ctrl, void *dlg, char *buffer, int length)
1678 {
1679     struct macctrls *mcs = dlg;
1680     union macctrl *mc = findbyctrl(mcs, ctrl);
1681     Size olen;
1682
1683     assert(mc != NULL);
1684     assert(mc->generic.type == MACCTRL_EDITBOX);
1685     if (mac_gestalts.apprvers >= 0x100) {
1686         if (GetControlData(mc->editbox.tbctrl, kControlEntireControl,
1687                            ctrl->editbox.password ?
1688                            kControlEditTextPasswordTag :
1689                            kControlEditTextTextTag,
1690                            length - 1, buffer, &olen) != noErr)
1691             olen = 0;
1692         if (olen > length - 1)
1693             olen = length - 1;
1694     }
1695 #if !TARGET_API_MAC_CARBON
1696     else {
1697         TEHandle te = (TEHandle)(*mc->editbox.tbctrl)->contrlData;
1698
1699         olen = (*te)->teLength;
1700         if (olen > length - 1)
1701             olen = length - 1;
1702         memcpy(buffer, *(*te)->hText, olen);
1703     }
1704 #endif
1705     buffer[olen] = '\0';
1706 }
1707
1708
1709 /*
1710  * List Box control
1711  */
1712
1713 static void dlg_macpopup_clear(union control *ctrl, void *dlg)
1714 {
1715     struct macctrls *mcs = dlg;
1716     union macctrl *mc = findbyctrl(mcs, ctrl);
1717     MenuRef menu = mc->popup.menu;
1718     unsigned int i, n;
1719
1720     if (mc == NULL) return;
1721     n = CountMenuItems(menu);
1722     for (i = 0; i < n; i++)
1723         DeleteMenuItem(menu, n - i);
1724     mc->popup.nids = 0;
1725     sfree(mc->popup.ids);
1726     mc->popup.ids = NULL;
1727     SetControlMaximum(mc->popup.tbctrl, CountMenuItems(menu));
1728 }
1729
1730 static void dlg_maclist_clear(union control *ctrl, void *dlg)
1731 {
1732     struct macctrls *mcs = dlg;
1733     union macctrl *mc = findbyctrl(mcs, ctrl);
1734
1735     if (mc == NULL) return;
1736     LDelRow(0, 0, mc->listbox.list);
1737     mc->listbox.nids = 0;
1738     sfree(mc->listbox.ids);
1739     mc->listbox.ids = NULL;
1740     DrawOneControl(mc->listbox.tbctrl);
1741 }
1742
1743 void dlg_listbox_clear(union control *ctrl, void *dlg)
1744 {
1745
1746     switch (ctrl->generic.type) {
1747       case CTRL_LISTBOX:
1748         if (ctrl->listbox.height == 0)
1749             dlg_macpopup_clear(ctrl, dlg);
1750         else
1751             dlg_maclist_clear(ctrl, dlg);
1752         break;
1753     }
1754 }
1755
1756 static void dlg_macpopup_del(union control *ctrl, void *dlg, int index)
1757 {
1758     struct macctrls *mcs = dlg;
1759     union macctrl *mc = findbyctrl(mcs, ctrl);
1760     MenuRef menu = mc->popup.menu;
1761
1762     if (mc == NULL) return;
1763     DeleteMenuItem(menu, index + 1);
1764     if (mc->popup.ids != NULL)
1765         memcpy(mc->popup.ids + index, mc->popup.ids + index + 1,
1766                (mc->popup.nids - index - 1) * sizeof(*mc->popup.ids));
1767     SetControlMaximum(mc->popup.tbctrl, CountMenuItems(menu));
1768 }
1769
1770 static void dlg_maclist_del(union control *ctrl, void *dlg, int index)
1771 {
1772     struct macctrls *mcs = dlg;
1773     union macctrl *mc = findbyctrl(mcs, ctrl);
1774
1775     if (mc == NULL) return;
1776     LDelRow(1, index, mc->listbox.list);
1777     if (mc->listbox.ids != NULL)
1778         memcpy(mc->listbox.ids + index, mc->listbox.ids + index + 1,
1779                (mc->listbox.nids - index - 1) * sizeof(*mc->listbox.ids));
1780     DrawOneControl(mc->listbox.tbctrl);
1781 }
1782
1783 void dlg_listbox_del(union control *ctrl, void *dlg, int index)
1784 {
1785
1786     switch (ctrl->generic.type) {
1787       case CTRL_LISTBOX:
1788         if (ctrl->listbox.height == 0)
1789             dlg_macpopup_del(ctrl, dlg, index);
1790         else
1791             dlg_maclist_del(ctrl, dlg, index);
1792         break;
1793     }
1794 }
1795
1796 static void dlg_macpopup_add(union control *ctrl, void *dlg, char const *text)
1797 {
1798     struct macctrls *mcs = dlg;
1799     union macctrl *mc = findbyctrl(mcs, ctrl);
1800     MenuRef menu = mc->popup.menu;
1801     Str255 itemstring;
1802
1803     if (mc == NULL) return;
1804     assert(text[0] != '\0');
1805     c2pstrcpy(itemstring, text);
1806     AppendMenu(menu, "\pdummy");
1807     SetMenuItemText(menu, CountMenuItems(menu), itemstring);
1808     SetControlMaximum(mc->popup.tbctrl, CountMenuItems(menu));
1809 }
1810
1811
1812 static void dlg_maclist_add(union control *ctrl, void *dlg, char const *text)
1813 {
1814     struct macctrls *mcs = dlg;
1815     union macctrl *mc = findbyctrl(mcs, ctrl);
1816     ListBounds bounds;
1817     Cell cell = { 0, 0 };
1818
1819     if (mc == NULL) return;
1820 #if TARGET_API_MAC_CARBON
1821     GetListDataBounds(mc->listbox.list, &bounds);
1822 #else
1823     bounds = (*mc->listbox.list)->dataBounds;
1824 #endif
1825     cell.v = bounds.bottom;
1826     LAddRow(1, cell.v, mc->listbox.list);
1827     LSetCell(text, strlen(text), cell, mc->listbox.list);
1828     DrawOneControl(mc->listbox.tbctrl);
1829 }
1830
1831 void dlg_listbox_add(union control *ctrl, void *dlg, char const *text)
1832 {
1833
1834     switch (ctrl->generic.type) {
1835       case CTRL_LISTBOX:
1836         if (ctrl->listbox.height == 0)
1837             dlg_macpopup_add(ctrl, dlg, text);
1838         else
1839             dlg_maclist_add(ctrl, dlg, text);
1840         break;
1841     }
1842 }
1843
1844 static void dlg_macpopup_addwithid(union control *ctrl, void *dlg,
1845                                    char const *text, int id)
1846 {
1847     struct macctrls *mcs = dlg;
1848     union macctrl *mc = findbyctrl(mcs, ctrl);
1849     MenuRef menu = mc->popup.menu;
1850     unsigned int index;
1851
1852     if (mc == NULL) return;
1853     dlg_macpopup_add(ctrl, dlg, text);
1854     index = CountMenuItems(menu) - 1;
1855     if (mc->popup.nids <= index) {
1856         mc->popup.nids = index + 1;
1857         mc->popup.ids = sresize(mc->popup.ids, mc->popup.nids, int);
1858     }
1859     mc->popup.ids[index] = id;
1860 }
1861
1862 static void dlg_maclist_addwithid(union control *ctrl, void *dlg,
1863                                   char const *text, int id)
1864 {
1865     struct macctrls *mcs = dlg;
1866     union macctrl *mc = findbyctrl(mcs, ctrl);
1867     ListBounds bounds;
1868     int index;
1869
1870     if (mc == NULL) return;
1871     dlg_maclist_add(ctrl, dlg, text);
1872 #if TARGET_API_MAC_CARBON
1873     GetListDataBounds(mc->listbox.list, &bounds);
1874 #else
1875     bounds = (*mc->listbox.list)->dataBounds;
1876 #endif
1877     index = bounds.bottom;
1878     if (mc->listbox.nids <= index) {
1879         mc->listbox.nids = index + 1;
1880         mc->listbox.ids = sresize(mc->listbox.ids, mc->listbox.nids, int);
1881     }
1882     mc->listbox.ids[index] = id;
1883 }
1884
1885 void dlg_listbox_addwithid(union control *ctrl, void *dlg,
1886                            char const *text, int id)
1887 {
1888
1889     switch (ctrl->generic.type) {
1890       case CTRL_LISTBOX:
1891         if (ctrl->listbox.height == 0)
1892             dlg_macpopup_addwithid(ctrl, dlg, text, id);
1893         else
1894             dlg_maclist_addwithid(ctrl, dlg, text, id);
1895         break;
1896     }
1897 }
1898
1899 int dlg_listbox_getid(union control *ctrl, void *dlg, int index)
1900 {
1901     struct macctrls *mcs = dlg;
1902     union macctrl *mc = findbyctrl(mcs, ctrl);
1903
1904     assert(mc != NULL);
1905     switch (ctrl->generic.type) {
1906       case CTRL_LISTBOX:
1907         if (ctrl->listbox.height == 0) {
1908             assert(mc->popup.ids != NULL && mc->popup.nids > index);
1909             return mc->popup.ids[index];
1910         } else {
1911             assert(mc->listbox.ids != NULL && mc->listbox.nids > index);
1912             return mc->listbox.ids[index];
1913         }
1914     }
1915     return -1;
1916 }
1917
1918 int dlg_listbox_index(union control *ctrl, void *dlg)
1919 {
1920     struct macctrls *mcs = dlg;
1921     union macctrl *mc = findbyctrl(mcs, ctrl);
1922     Cell cell = { 0, 0 };
1923
1924     assert(mc != NULL);
1925     switch (ctrl->generic.type) {
1926       case CTRL_LISTBOX:
1927         if (ctrl->listbox.height == 0)
1928             return GetControlValue(mc->popup.tbctrl) - 1;
1929         else {
1930             if (LGetSelect(TRUE, &cell, mc->listbox.list))
1931                 return cell.v;
1932             else
1933                 return -1;
1934         }
1935     }
1936     return -1;
1937 }
1938
1939 int dlg_listbox_issel(union control *ctrl, void *dlg, int index)
1940 {
1941     struct macctrls *mcs = dlg;
1942     union macctrl *mc = findbyctrl(mcs, ctrl);
1943     Cell cell = { 0, 0 };
1944
1945     assert(mc != NULL);
1946     switch (ctrl->generic.type) {
1947       case CTRL_LISTBOX:
1948         if (ctrl->listbox.height == 0)
1949             return GetControlValue(mc->popup.tbctrl) - 1 == index;
1950         else {
1951             cell.v = index;
1952             return LGetSelect(FALSE, &cell, mc->listbox.list);
1953         }
1954     }
1955     return FALSE;
1956 }
1957
1958 void dlg_listbox_select(union control *ctrl, void *dlg, int index)
1959 {
1960     struct macctrls *mcs = dlg;
1961     union macctrl *mc = findbyctrl(mcs, ctrl);
1962
1963     if (mc == NULL) return;
1964     switch (ctrl->generic.type) {
1965       case CTRL_LISTBOX:
1966         if (ctrl->listbox.height == 0)
1967             SetControlValue(mc->popup.tbctrl, index + 1);
1968         break;
1969     }
1970 }
1971
1972
1973 /*
1974  * Text control
1975  */
1976
1977 void dlg_text_set(union control *ctrl, void *dlg, char const *text)
1978 {
1979     struct macctrls *mcs = dlg;
1980     union macctrl *mc = findbyctrl(mcs, ctrl);
1981
1982     if (mc == NULL) return;
1983     if (mac_gestalts.apprvers >= 0x100)
1984         SetControlData(mc->text.tbctrl, kControlEntireControl,
1985                        kControlStaticTextTextTag, strlen(text), text);
1986 #if !TARGET_API_MAC_CARBON
1987     else
1988         TESetText(text, strlen(text),
1989                   (TEHandle)(*mc->text.tbctrl)->contrlData);
1990 #endif
1991 }
1992
1993
1994 /*
1995  * File Selector control
1996  */
1997
1998 void dlg_filesel_set(union control *ctrl, void *dlg, Filename fn)
1999 {
2000
2001 }
2002
2003 void dlg_filesel_get(union control *ctrl, void *dlg, Filename *fn)
2004 {
2005
2006 }
2007
2008
2009 /*
2010  * Font Selector control
2011  */
2012
2013 void dlg_fontsel_set(union control *ctrl, void *dlg, FontSpec fn)
2014 {
2015
2016 }
2017
2018 void dlg_fontsel_get(union control *ctrl, void *dlg, FontSpec *fn)
2019 {
2020
2021 }
2022
2023
2024 /*
2025  * Printer enumeration
2026  */
2027
2028 printer_enum *printer_start_enum(int *nprinters)
2029 {
2030
2031     *nprinters = 0;
2032     return NULL;
2033 }
2034
2035 char *printer_get_name(printer_enum *pe, int thing)
2036 {
2037
2038     return "<none>";
2039 }
2040
2041 void printer_finish_enum(printer_enum *pe)
2042 {
2043
2044 }
2045
2046
2047 /*
2048  * Colour selection stuff
2049  */
2050
2051 void dlg_coloursel_start(union control *ctrl, void *dlg,
2052                          int r, int g, int b)
2053 {
2054     struct macctrls *mcs = dlg;
2055     union macctrl *mc = findbyctrl(mcs, ctrl);
2056     Point where = {-1, -1}; /* Screen with greatest colour depth */
2057     RGBColor incolour;
2058
2059     if (HAVE_COLOR_QD()) {
2060         incolour.red = r * 0x0101;
2061         incolour.green = g * 0x0101;
2062         incolour.blue = b * 0x0101;
2063         mcs->gotcolour = GetColor(where, "\pModify Colour:", &incolour,
2064                                   &mcs->thecolour);
2065         ctrlevent(mcs, mc, EVENT_CALLBACK);
2066     } else
2067         dlg_beep(dlg);
2068 }
2069
2070 int dlg_coloursel_results(union control *ctrl, void *dlg,
2071                           int *r, int *g, int *b)
2072 {
2073     struct macctrls *mcs = dlg;
2074
2075     if (mcs->gotcolour) {
2076         *r = mcs->thecolour.red >> 8;
2077         *g = mcs->thecolour.green >> 8;
2078         *b = mcs->thecolour.blue >> 8;
2079         return 1;
2080     } else
2081         return 0;
2082 }
2083
2084 /*
2085  * Local Variables:
2086  * c-file-style: "simon"
2087  * End:
2088  */