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