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