~ubuntu-branches/ubuntu/dapper/tk8.0/dapper-updates

« back to all changes in this revision

Viewing changes to mac/tkMacButton.c

  • Committer: Bazaar Package Importer
  • Author(s): Mike Markley
  • Date: 2001-07-24 21:57:40 UTC
  • Revision ID: james.westby@ubuntu.com-20010724215740-r70t25rtmbqjil2h
Tags: upstream-8.0.5
ImportĀ upstreamĀ versionĀ 8.0.5

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* 
 
2
 * tkMacButton.c --
 
3
 *
 
4
 *      This file implements the Macintosh specific portion of the
 
5
 *      button widgets.
 
6
 *
 
7
 * Copyright (c) 1996-1997 by Sun Microsystems, Inc.
 
8
 *
 
9
 * See the file "license.terms" for information on usage and redistribution
 
10
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 
11
 *
 
12
 * RCS: @(#) $Id: tkMacButton.c,v 1.3 1998/09/14 18:23:34 stanton Exp $
 
13
 */
 
14
 
 
15
#include "tkButton.h"
 
16
#include "tkMacInt.h"
 
17
#include <Controls.h>
 
18
#include <LowMem.h>
 
19
#include <Appearance.h>
 
20
 
 
21
 
 
22
#include <ToolUtils.h>
 
23
 
 
24
/*
 
25
 * Some defines used to control what type of control is drawn.
 
26
 */
 
27
 
 
28
#define DRAW_LABEL      0               /* Labels are treated genericly. */
 
29
#define DRAW_CONTROL    1               /* Draw using the Native control. */
 
30
#define DRAW_CUSTOM     2               /* Make our own button drawing. */
 
31
#define DRAW_BEVEL      3
 
32
 
 
33
/*
 
34
 * The following structures are used to draw our controls.  Rather than
 
35
 * having many Mac controls we just use one control of each type and
 
36
 * reuse them for all Tk widgets.  When the windowRef variable is NULL
 
37
 * it means none of the data structures have been allocated.
 
38
 */
 
39
 
 
40
static WindowRef windowRef = NULL;
 
41
static CWindowRecord windowRecord;
 
42
static ControlRef buttonHandle;
 
43
static ControlRef checkHandle;
 
44
static ControlRef radioHandle;
 
45
static ControlRef smallBevelHandle;
 
46
static ControlRef smallStickyBevelHandle;
 
47
static ControlRef medBevelHandle;
 
48
static ControlRef medStickyBevelHandle;
 
49
static ControlRef largeBevelHandle;
 
50
static ControlRef largeStickyBevelHandle;
 
51
 
 
52
/*
 
53
 * These are used to store the image content for
 
54
 * beveled buttons - i.e. buttons with images.
 
55
 */
 
56
 
 
57
static ControlButtonContentInfo bevelButtonContent;
 
58
static OpenCPicParams picParams;
 
59
 
 
60
static CCTabHandle buttonTabHandle;
 
61
static CCTabHandle checkTabHandle;
 
62
static CCTabHandle radioTabHandle;
 
63
static PixMapHandle oldPixPtr;
 
64
 
 
65
/*
 
66
 * These functions are used when Appearance is present.
 
67
 * By embedding all our controls in a userPane control,
 
68
 * we can color the background of the text in radiobuttons
 
69
 * and checkbuttons.  Thanks to Peter Gontier of Apple DTS
 
70
 * for help on this one.
 
71
 */
 
72
 
 
73
static ControlRef userPaneHandle;
 
74
static RGBColor gUserPaneBackground = { ~0, ~0, ~0};
 
75
static pascal OSErr SetUserPaneDrawProc(ControlRef control,
 
76
        ControlUserPaneDrawProcPtr upp);
 
77
static pascal OSErr SetUserPaneSetUpSpecialBackgroundProc(ControlRef control,
 
78
        ControlUserPaneBackgroundProcPtr upp);
 
79
static pascal void UserPaneDraw(ControlRef control, ControlPartCode cpc);
 
80
static pascal void UserPaneBackgroundProc(ControlHandle,
 
81
        ControlBackgroundPtr info);
 
82
 
 
83
/*
 
84
 * Forward declarations for procedures defined later in this file:
 
85
 */
 
86
 
 
87
static int      UpdateControlColors _ANSI_ARGS_((TkButton *butPtr,
 
88
                            ControlRef controlHandle, CCTabHandle ccTabHandle,
 
89
                            RGBColor *saveColorPtr));
 
90
static void     DrawBufferedControl _ANSI_ARGS_((TkButton *butPtr,
 
91
                    GWorldPtr destPort, GC gc, Pixmap pixmap));
 
92
static void     InitSampleControls();
 
93
static void     SetupBevelButton _ANSI_ARGS_((TkButton *butPtr,
 
94
                    ControlRef controlHandle, 
 
95
                    GWorldPtr destPort, GC gc, Pixmap pixmap));
 
96
static void     ChangeBackgroundWindowColor _ANSI_ARGS_((
 
97
                            WindowRef macintoshWindow, RGBColor rgbColor,
 
98
                            RGBColor *oldColor));
 
99
static void     ButtonExitProc _ANSI_ARGS_((ClientData clientData));
 
100
 
 
101
/*
 
102
 * The class procedure table for the button widgets.
 
103
 */
 
104
 
 
105
TkClassProcs tkpButtonProcs = { 
 
106
    NULL,                       /* createProc. */
 
107
    TkButtonWorldChanged,       /* geometryProc. */
 
108
    NULL                        /* modalProc. */
 
109
};
 
110
 
 
111
/*
 
112
 *----------------------------------------------------------------------
 
113
 *
 
114
 * TkpCreateButton --
 
115
 *
 
116
 *      Allocate a new TkButton structure.
 
117
 *
 
118
 * Results:
 
119
 *      Returns a newly allocated TkButton structure.
 
120
 *
 
121
 * Side effects:
 
122
 *      Registers an event handler for the widget.
 
123
 *
 
124
 *----------------------------------------------------------------------
 
125
 */
 
126
 
 
127
TkButton *
 
128
TkpCreateButton(
 
129
    Tk_Window tkwin)
 
130
{
 
131
    return (TkButton *) ckalloc(sizeof(TkButton));
 
132
}
 
133
 
 
134
/*
 
135
 *----------------------------------------------------------------------
 
136
 *
 
137
 * TkpDisplayButton --
 
138
 *
 
139
 *      This procedure is invoked to display a button widget.  It is
 
140
 *      normally invoked as an idle handler.
 
141
 *
 
142
 * Results:
 
143
 *      None.
 
144
 *
 
145
 * Side effects:
 
146
 *      Commands are output to X to display the button in its
 
147
 *      current mode.  The REDRAW_PENDING flag is cleared.
 
148
 *
 
149
 *----------------------------------------------------------------------
 
150
 */
 
151
 
 
152
void
 
153
TkpDisplayButton(
 
154
    ClientData clientData)      /* Information about widget. */
 
155
{
 
156
    TkButton *butPtr = (TkButton *) clientData;
 
157
    Pixmap pixmap;
 
158
    GC gc;
 
159
    Tk_3DBorder border;
 
160
    int x = 0;                  /* Initialization only needed to stop
 
161
                                 * compiler warning. */
 
162
    int y, relief;
 
163
    register Tk_Window tkwin = butPtr->tkwin;
 
164
    int width, height;
 
165
    int offset;                 /* 0 means this is a normal widget.  1 means
 
166
                                 * it is an image button, so we offset the
 
167
                                 * image to make the button appear to move
 
168
                                 * up and down as the relief changes. */
 
169
    int hasImageOrBitmap;
 
170
    CGrafPtr saveWorld;
 
171
    GDHandle saveDevice;
 
172
    GWorldPtr destPort;
 
173
    int drawType, borderWidth;
 
174
    
 
175
    GetGWorld(&saveWorld, &saveDevice);
 
176
 
 
177
    butPtr->flags &= ~REDRAW_PENDING;
 
178
    if ((butPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) {
 
179
        return;
 
180
    }
 
181
 
 
182
    /*
 
183
     * In order to avoid screen flashes, this procedure redraws
 
184
     * the button in a pixmap, then copies the pixmap to the
 
185
     * screen in a single operation.  This means that there's no
 
186
     * point in time where the on-sreen image has been cleared.
 
187
     */
 
188
 
 
189
    pixmap = Tk_GetPixmap(butPtr->display, Tk_WindowId(tkwin),
 
190
            Tk_Width(tkwin), Tk_Height(tkwin), Tk_Depth(tkwin));
 
191
 
 
192
    hasImageOrBitmap = ((butPtr->image != NULL) || (butPtr->bitmap != None));
 
193
    offset = (butPtr->type == TYPE_BUTTON) && hasImageOrBitmap;
 
194
 
 
195
    border = butPtr->normalBorder;
 
196
    if ((butPtr->state == tkDisabledUid) && (butPtr->disabledFg != NULL)) {
 
197
        gc = butPtr->disabledGC;
 
198
    } else if ((butPtr->type == TYPE_BUTTON)
 
199
            && (butPtr->state == tkActiveUid)) {
 
200
        gc = butPtr->activeTextGC;
 
201
        border = butPtr->activeBorder;
 
202
    } else {
 
203
        gc = butPtr->normalTextGC;
 
204
    }
 
205
    
 
206
    if ((butPtr->flags & SELECTED) && (butPtr->state != tkActiveUid)
 
207
            && (butPtr->selectBorder != NULL) && !butPtr->indicatorOn) {
 
208
        border = butPtr->selectBorder;
 
209
    }
 
210
 
 
211
    /*
 
212
     * Override the relief specified for the button if this is a
 
213
     * checkbutton or radiobutton and there's no indicator.
 
214
     * However, don't do this in the presence of Appearance, since
 
215
     * then the bevel button will take care of the relief.
 
216
     */
 
217
 
 
218
    relief = butPtr->relief;
 
219
 
 
220
    if ((butPtr->type >= TYPE_CHECK_BUTTON) && !butPtr->indicatorOn) { 
 
221
        if (!TkMacHaveAppearance() || !hasImageOrBitmap) {
 
222
            relief = (butPtr->flags & SELECTED) ? TK_RELIEF_SUNKEN
 
223
                    : TK_RELIEF_RAISED;
 
224
        }
 
225
    }
 
226
 
 
227
    /*
 
228
     * See the comment in UpdateControlColors as to why we use the 
 
229
     * highlightbackground for the border of Macintosh buttons.
 
230
     */
 
231
     
 
232
    if (butPtr->type == TYPE_BUTTON) {
 
233
        Tk_Fill3DRectangle(tkwin, pixmap, butPtr->highlightBorder, 0, 0,
 
234
                Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT);
 
235
    } else {
 
236
    Tk_Fill3DRectangle(tkwin, pixmap, butPtr->normalBorder, 0, 0,
 
237
            Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT);
 
238
    }
 
239
   
 
240
    if (butPtr->type == TYPE_LABEL) {
 
241
        drawType = DRAW_LABEL;
 
242
    } else if (butPtr->type == TYPE_BUTTON) {
 
243
        if (!hasImageOrBitmap) {
 
244
            drawType = DRAW_CONTROL;
 
245
        } else if (butPtr->image != None) {
 
246
            drawType = DRAW_BEVEL;
 
247
        } else {
 
248
            /*
 
249
             * TO DO - The current way the we draw bitmaps (XCopyPlane)
 
250
             * uses CopyDeepMask in this one case.  The Picture recording 
 
251
             * does not record this call, and so we can't use the
 
252
             * Appearance bevel button here.  The only case that would
 
253
             * exercise this is if you use a bitmap, with
 
254
             * -data & -mask specified.  We should probably draw the 
 
255
             * appearance button and overprint the image in this case.
 
256
             * This just punts and draws the old-style, ugly, button.
 
257
             */
 
258
             
 
259
            if (gc->clip_mask == 0) {
 
260
                drawType = DRAW_BEVEL;
 
261
            } else {
 
262
                TkpClipMask *clipPtr = (TkpClipMask*) gc->clip_mask;
 
263
                if ((clipPtr->type == TKP_CLIP_PIXMAP) &&
 
264
                    (clipPtr->value.pixmap != butPtr->bitmap)) {
 
265
                    drawType = DRAW_CUSTOM;
 
266
                } else {
 
267
                    drawType = DRAW_BEVEL;
 
268
                }
 
269
            }
 
270
        }
 
271
    } else {
 
272
        if (butPtr->indicatorOn) {
 
273
            drawType = DRAW_CONTROL;
 
274
        } else if (hasImageOrBitmap) {
 
275
            if (gc->clip_mask == 0) {
 
276
                drawType = DRAW_BEVEL;
 
277
            } else {
 
278
                TkpClipMask *clipPtr = (TkpClipMask*) gc->clip_mask;
 
279
                if ((clipPtr->type == TKP_CLIP_PIXMAP) &&
 
280
                    (clipPtr->value.pixmap != butPtr->bitmap)) {
 
281
                    drawType = DRAW_CUSTOM;
 
282
                } else {
 
283
                    drawType = DRAW_BEVEL;
 
284
                }
 
285
            }
 
286
        } else {
 
287
            drawType = DRAW_CUSTOM;
 
288
        }
 
289
    }
 
290
 
 
291
    /*
 
292
     * Draw the native portion of the buttons.  Start by creating the control
 
293
     * if it doesn't already exist.  Then configure the Macintosh control from
 
294
     * the Tk info.  Finally, we call Draw1Control to draw to the screen.
 
295
     */
 
296
 
 
297
    if ((drawType == DRAW_CONTROL) || 
 
298
            ((drawType == DRAW_BEVEL) && TkMacHaveAppearance())) {
 
299
        borderWidth = 0;
 
300
        
 
301
        /*
 
302
         * This part uses Macintosh rather than Tk calls to draw
 
303
         * to the screen.  Make sure the ports etc. are set correctly.
 
304
         */
 
305
        
 
306
        destPort = TkMacGetDrawablePort(pixmap);
 
307
        SetGWorld(destPort, NULL);
 
308
        DrawBufferedControl(butPtr, destPort, gc, pixmap);
 
309
    }
 
310
 
 
311
    if ((drawType == DRAW_CUSTOM) || (drawType == DRAW_LABEL)) {
 
312
        borderWidth = butPtr->borderWidth;
 
313
    }
 
314
 
 
315
    /*
 
316
     * Display image or bitmap or text for button.  This has
 
317
     * already been done under Appearance with the Bevel
 
318
     * button types.
 
319
     */
 
320
 
 
321
    if ((drawType == DRAW_BEVEL) && TkMacHaveAppearance()) {
 
322
        /* Empty Body */
 
323
    } else if (butPtr->image != None) {
 
324
        Tk_SizeOfImage(butPtr->image, &width, &height);
 
325
 
 
326
        imageOrBitmap:
 
327
        TkComputeAnchor(butPtr->anchor, tkwin, 0, 0,
 
328
                butPtr->indicatorSpace + width, height, &x, &y);
 
329
        x += butPtr->indicatorSpace;
 
330
 
 
331
        x += offset;
 
332
        y += offset;
 
333
        if (relief == TK_RELIEF_RAISED) {
 
334
            x -= offset;
 
335
            y -= offset;
 
336
        } else if (relief == TK_RELIEF_SUNKEN) {
 
337
            x += offset;
 
338
            y += offset;
 
339
        }
 
340
        if (butPtr->image != NULL) {
 
341
            if ((butPtr->selectImage != NULL) && (butPtr->flags & SELECTED)) {
 
342
                Tk_RedrawImage(butPtr->selectImage, 0, 0, width, height,
 
343
                        pixmap, x, y);
 
344
            } else {
 
345
                Tk_RedrawImage(butPtr->image, 0, 0, width, height, pixmap,
 
346
                        x, y);
 
347
            }
 
348
        } else {
 
349
            XSetClipOrigin(butPtr->display, gc, x, y);
 
350
            XCopyPlane(butPtr->display, butPtr->bitmap, pixmap, gc, 0, 0,
 
351
                    (unsigned int) width, (unsigned int) height, x, y, 1);
 
352
            XSetClipOrigin(butPtr->display, gc, 0, 0);
 
353
        }
 
354
        y += height/2;
 
355
    } else if (butPtr->bitmap != None) {
 
356
        Tk_SizeOfBitmap(butPtr->display, butPtr->bitmap, &width, &height);
 
357
        goto imageOrBitmap;
 
358
    } else {
 
359
        TkComputeAnchor(butPtr->anchor, tkwin, butPtr->padX, butPtr->padY,
 
360
                butPtr->indicatorSpace + butPtr->textWidth, butPtr->textHeight,
 
361
                &x, &y);
 
362
 
 
363
        x += butPtr->indicatorSpace;
 
364
 
 
365
        Tk_DrawTextLayout(butPtr->display, pixmap, gc, butPtr->textLayout,
 
366
                x, y, 0, -1);
 
367
        y += butPtr->textHeight/2;
 
368
    }
 
369
 
 
370
    /*
 
371
     * If the button is disabled with a stipple rather than a special
 
372
     * foreground color, generate the stippled effect.  If the widget
 
373
     * is selected and we use a different background color when selected,
 
374
     * must temporarily modify the GC.
 
375
     */
 
376
 
 
377
    if ((butPtr->state == tkDisabledUid)
 
378
            && ((butPtr->disabledFg == NULL) || (butPtr->image != NULL))) {
 
379
        if ((butPtr->flags & SELECTED) && !butPtr->indicatorOn
 
380
                && (butPtr->selectBorder != NULL)) {
 
381
            XSetForeground(butPtr->display, butPtr->disabledGC,
 
382
                    Tk_3DBorderColor(butPtr->selectBorder)->pixel);
 
383
        }
 
384
        XFillRectangle(butPtr->display, pixmap, butPtr->disabledGC,
 
385
                butPtr->inset, butPtr->inset,
 
386
                (unsigned) (Tk_Width(tkwin) - 2*butPtr->inset),
 
387
                (unsigned) (Tk_Height(tkwin) - 2*butPtr->inset));
 
388
        if ((butPtr->flags & SELECTED) && !butPtr->indicatorOn
 
389
                && (butPtr->selectBorder != NULL)) {
 
390
            XSetForeground(butPtr->display, butPtr->disabledGC,
 
391
                    Tk_3DBorderColor(butPtr->normalBorder)->pixel);
 
392
        }
 
393
    }
 
394
 
 
395
    /*
 
396
     * Draw the border and traversal highlight last.  This way, if the
 
397
     * button's contents overflow they'll be covered up by the border.
 
398
     */
 
399
 
 
400
    if (relief != TK_RELIEF_FLAT) {
 
401
        int inset = butPtr->highlightWidth;
 
402
        Tk_Draw3DRectangle(tkwin, pixmap, border, inset, inset,
 
403
                Tk_Width(tkwin) - 2*inset, Tk_Height(tkwin) - 2*inset,
 
404
                butPtr->borderWidth, relief);
 
405
    }
 
406
 
 
407
    /*
 
408
     * Copy the information from the off-screen pixmap onto the screen,
 
409
     * then delete the pixmap.
 
410
     */
 
411
 
 
412
    XCopyArea(butPtr->display, pixmap, Tk_WindowId(tkwin),
 
413
            butPtr->copyGC, 0, 0, (unsigned) Tk_Width(tkwin),
 
414
            (unsigned) Tk_Height(tkwin), 0, 0);
 
415
    Tk_FreePixmap(butPtr->display, pixmap);
 
416
 
 
417
    SetGWorld(saveWorld, saveDevice);
 
418
}
 
419
 
 
420
/*
 
421
 *----------------------------------------------------------------------
 
422
 *
 
423
 * TkpComputeButtonGeometry --
 
424
 *
 
425
 *      After changes in a button's text or bitmap, this procedure
 
426
 *      recomputes the button's geometry and passes this information
 
427
 *      along to the geometry manager for the window.
 
428
 *
 
429
 * Results:
 
430
 *      None.
 
431
 *
 
432
 * Side effects:
 
433
 *      The button's window may change size.
 
434
 *
 
435
 *----------------------------------------------------------------------
 
436
 */
 
437
 
 
438
void
 
439
TkpComputeButtonGeometry(
 
440
    TkButton *butPtr)   /* Button whose geometry may have changed. */
 
441
{
 
442
    int width, height, avgWidth;
 
443
    Tk_FontMetrics fm;
 
444
 
 
445
 
 
446
    /*
 
447
     * First figure out the size of the contents of the button.
 
448
     */
 
449
     
 
450
    butPtr->indicatorSpace = 0;
 
451
    if (butPtr->image != NULL) {
 
452
        Tk_SizeOfImage(butPtr->image, &width, &height);
 
453
        imageOrBitmap:
 
454
        if (butPtr->width > 0) {
 
455
            width = butPtr->width;
 
456
        }
 
457
        if (butPtr->height > 0) {
 
458
            height = butPtr->height;
 
459
        }
 
460
        if ((butPtr->type >= TYPE_CHECK_BUTTON) && butPtr->indicatorOn) {
 
461
            butPtr->indicatorSpace = height;
 
462
            if (butPtr->type == TYPE_CHECK_BUTTON) {
 
463
                butPtr->indicatorDiameter = (65*height)/100;
 
464
            } else {
 
465
                butPtr->indicatorDiameter = (75*height)/100;
 
466
            }
 
467
        }
 
468
    } else if (butPtr->bitmap != None) {
 
469
        Tk_SizeOfBitmap(butPtr->display, butPtr->bitmap, &width, &height);
 
470
        goto imageOrBitmap;
 
471
    } else {
 
472
        Tk_FreeTextLayout(butPtr->textLayout);
 
473
        butPtr->textLayout = Tk_ComputeTextLayout(butPtr->tkfont,
 
474
                butPtr->text, -1, butPtr->wrapLength,
 
475
                butPtr->justify, 0, &butPtr->textWidth, &butPtr->textHeight);
 
476
 
 
477
        width = butPtr->textWidth;
 
478
        height = butPtr->textHeight;
 
479
        avgWidth = Tk_TextWidth(butPtr->tkfont, "0", 1);
 
480
        Tk_GetFontMetrics(butPtr->tkfont, &fm);
 
481
 
 
482
        if (butPtr->width > 0) {
 
483
            width = butPtr->width * avgWidth;
 
484
        }
 
485
        if (butPtr->height > 0) {
 
486
            height = butPtr->height * fm.linespace;
 
487
        }
 
488
        if ((butPtr->type >= TYPE_CHECK_BUTTON) && butPtr->indicatorOn) {
 
489
            butPtr->indicatorDiameter = fm.linespace;
 
490
            if (butPtr->type == TYPE_CHECK_BUTTON) {
 
491
                butPtr->indicatorDiameter = (80*butPtr->indicatorDiameter)/100;
 
492
            }
 
493
            butPtr->indicatorSpace = butPtr->indicatorDiameter + avgWidth;
 
494
        }
 
495
    }
 
496
 
 
497
    /*
 
498
     * Now figure out the size of the border decorations for the button.
 
499
     */
 
500
     
 
501
    if (butPtr->highlightWidth < 0) {
 
502
        butPtr->highlightWidth = 0;
 
503
    }
 
504
    
 
505
    /*
 
506
     * The width and height calculation for Appearance buttons with images & 
 
507
     * non-Appearance buttons with images is different.  In the latter case, 
 
508
     * we add the borderwidth to the inset, since we are going to stamp a
 
509
     * 3-D border over the image.  In the former, we add it to the height,
 
510
     * directly, since Appearance will draw the border as part of our control.
 
511
     *
 
512
     * When issuing the geometry request, add extra space for the indicator,
 
513
     * if any, and for the border and padding, plus if this is an image two 
 
514
     * extra pixels so the display can be offset by 1 pixel in either
 
515
     * direction for the raised or lowered effect.
 
516
     *
 
517
     * The highlight width corresponds to the default ring on the Macintosh.
 
518
     * As such, the highlight width is only added if the button is the default
 
519
     * button.  The actual width of the default ring is one less than the
 
520
     * highlight width as there is also one pixel of spacing.
 
521
     * Appearance buttons with images do not have a highlight ring, because the 
 
522
     * Bevel button type does not support one.
 
523
     */
 
524
 
 
525
    if ((butPtr->image == None) && (butPtr->bitmap == None)) {
 
526
        width += 2*butPtr->padX;
 
527
        height += 2*butPtr->padY;
 
528
    }
 
529
    
 
530
    if ((butPtr->type == TYPE_BUTTON)) {
 
531
        if ((butPtr->image == None) && (butPtr->bitmap == None)) {
 
532
            butPtr->inset = 0;
 
533
            if (butPtr->defaultState != tkDisabledUid) {
 
534
                butPtr->inset += butPtr->highlightWidth;
 
535
            }
 
536
        } else if (TkMacHaveAppearance()) {
 
537
                butPtr->inset = 0;
 
538
                width += (2 * butPtr->borderWidth + 4);
 
539
                height += (2 * butPtr->borderWidth + 4);
 
540
        } else {
 
541
            butPtr->inset = butPtr->borderWidth;
 
542
        width += 2;
 
543
        height += 2;
 
544
            if (butPtr->defaultState != tkDisabledUid) {
 
545
                butPtr->inset += butPtr->highlightWidth;
 
546
            }
 
547
        }
 
548
    } else if ((butPtr->type != TYPE_LABEL)) {
 
549
        if (butPtr->indicatorOn) {
 
550
            butPtr->inset = 0;
 
551
        } else {
 
552
        /*
 
553
         * Under Appearance, the Checkbutton or radiobutton with an image
 
554
         * is represented by a BevelButton with the Sticky defProc...  
 
555
         * So we must set its height in the same way as the Button 
 
556
         * with an image or bitmap.
 
557
         */
 
558
            if (((butPtr->image != None) || (butPtr->bitmap != None))
 
559
                    && TkMacHaveAppearance()) {
 
560
                int border;
 
561
                butPtr->inset = 0;
 
562
                if ( butPtr->borderWidth <= 2 ) {
 
563
                    border = 6;
 
564
                }  else {
 
565
                    border = 2 * butPtr->borderWidth + 2;
 
566
                }              
 
567
                width += border;
 
568
                height += border;
 
569
            } else {
 
570
                butPtr->inset = butPtr->borderWidth;
 
571
            }   
 
572
        }       
 
573
    } else {
 
574
        butPtr->inset = butPtr->borderWidth;
 
575
    }
 
576
 
 
577
 
 
578
 
 
579
    Tk_GeometryRequest(butPtr->tkwin, (int) (width + butPtr->indicatorSpace
 
580
            + 2*butPtr->inset), (int) (height + 2*butPtr->inset));
 
581
    Tk_SetInternalBorder(butPtr->tkwin, butPtr->inset);
 
582
}
 
583
 
 
584
/*
 
585
 *----------------------------------------------------------------------
 
586
 *
 
587
 * TkpDestroyButton --
 
588
 *
 
589
 *      Free data structures associated with the button control.
 
590
 *
 
591
 * Results:
 
592
 *      None.
 
593
 *
 
594
 * Side effects:
 
595
 *      Restores the default control state.
 
596
 *
 
597
 *----------------------------------------------------------------------
 
598
 */
 
599
 
 
600
void
 
601
TkpDestroyButton(
 
602
    TkButton *butPtr)
 
603
{
 
604
    /* Do nothing. */
 
605
}
 
606
 
 
607
/*
 
608
 *--------------------------------------------------------------
 
609
 *
 
610
 * DrawBufferedControl --
 
611
 *
 
612
 *      This function uses a dummy Macintosh window to allow
 
613
 *      drawing Mac controls to any GWorld (including off-screen
 
614
 *      bitmaps).  In addition, this code may apply custom
 
615
 *      colors passed in the TkButton.
 
616
 *
 
617
 * Results:
 
618
 *      None.
 
619
 *
 
620
 * Side effects:
 
621
 *      Control is to the GWorld.  Static state created on
 
622
 *      first invocation of this routine.
 
623
 *
 
624
 *--------------------------------------------------------------
 
625
 */
 
626
 
 
627
static void
 
628
DrawBufferedControl(
 
629
    TkButton *butPtr,           /* Tk button. */
 
630
    GWorldPtr destPort,         /* Off screen GWorld. */
 
631
    GC gc,                      /* The GC we are drawing into - needed for
 
632
                                 * the bevel button */
 
633
    Pixmap pixmap               /* The pixmap we are drawing into - needed
 
634
                                   for the bevel button */
 
635
    )           
 
636
{
 
637
    ControlRef controlHandle;
 
638
    CCTabHandle ccTabHandle;
 
639
    int windowColorChanged = false;
 
640
    RGBColor saveBackColor;
 
641
    int isBevel = 0;
 
642
    
 
643
    if (windowRef == NULL) {
 
644
        InitSampleControls();
 
645
    }
 
646
    
 
647
    /*
 
648
     * Now swap in the passed in GWorld for the portBits of our fake
 
649
     * window.  We also adjust various fields in the WindowRecord to make
 
650
     * the system think this is a normal window.
 
651
     * Note, we can use DrawControlInCurrentPort under Appearance, so we don't
 
652
     * need to swap pixmaps.
 
653
     */
 
654
    
 
655
    if (!TkMacHaveAppearance()) {
 
656
        ((CWindowPeek) windowRef)->port.portPixMap = destPort->portPixMap;
 
657
    }
 
658
    
 
659
    ((CWindowPeek) windowRef)->port.portRect = destPort->portRect;
 
660
    RectRgn(((CWindowPeek) windowRef)->port.visRgn, &destPort->portRect);
 
661
    RectRgn(((CWindowPeek) windowRef)->strucRgn, &destPort->portRect);
 
662
    RectRgn(((CWindowPeek) windowRef)->updateRgn, &destPort->portRect);
 
663
    RectRgn(((CWindowPeek) windowRef)->contRgn, &destPort->portRect);
 
664
    PortChanged(windowRef);
 
665
    
 
666
    /*
 
667
     * Set up control in hidden window to match what we need
 
668
     * to draw in the buffered window.  
 
669
     */
 
670
     
 
671
    isBevel = 0;   
 
672
    switch (butPtr->type) {
 
673
        case TYPE_BUTTON:
 
674
            if (TkMacHaveAppearance()) {
 
675
                if ((butPtr->image == None) && (butPtr->bitmap == None)) {
 
676
                    controlHandle = buttonHandle;
 
677
                    ccTabHandle = buttonTabHandle;
 
678
                } else {
 
679
                    if (butPtr->borderWidth <= 2) {
 
680
                        controlHandle = smallBevelHandle;
 
681
                    } else if (butPtr->borderWidth == 3) {
 
682
                        controlHandle = medBevelHandle;
 
683
                    } else {
 
684
                        controlHandle = largeBevelHandle;
 
685
                    }
 
686
                    ccTabHandle = buttonTabHandle;
 
687
                    SetupBevelButton(butPtr, controlHandle, destPort, 
 
688
                            gc, pixmap);
 
689
                    isBevel = 1;                
 
690
                }
 
691
            } else {
 
692
                controlHandle = buttonHandle;
 
693
                ccTabHandle = buttonTabHandle;
 
694
            }
 
695
            break;
 
696
        case TYPE_RADIO_BUTTON:
 
697
            if (TkMacHaveAppearance()) {
 
698
                if (((butPtr->image == None) && (butPtr->bitmap == None))
 
699
                        || (butPtr->indicatorOn)) {
 
700
                    controlHandle = radioHandle;
 
701
                    ccTabHandle = radioTabHandle;
 
702
                } else {
 
703
                    if (butPtr->borderWidth <= 2) {
 
704
                        controlHandle = smallStickyBevelHandle;
 
705
                    } else if (butPtr->borderWidth == 3) {
 
706
                        controlHandle = medStickyBevelHandle;
 
707
                    } else {
 
708
                        controlHandle = largeStickyBevelHandle;
 
709
                    }
 
710
                    ccTabHandle = radioTabHandle;
 
711
                    SetupBevelButton(butPtr, controlHandle, destPort, 
 
712
                            gc, pixmap);
 
713
                    isBevel = 1;                
 
714
                }
 
715
            } else {
 
716
                controlHandle = radioHandle;
 
717
                ccTabHandle = radioTabHandle;
 
718
            }          
 
719
            break;
 
720
        case TYPE_CHECK_BUTTON:
 
721
            if (TkMacHaveAppearance()) {
 
722
                if (((butPtr->image == None) && (butPtr->bitmap == None))
 
723
                        || (butPtr->indicatorOn)) {
 
724
                    controlHandle = checkHandle;
 
725
                    ccTabHandle = checkTabHandle;
 
726
                } else {
 
727
                    if (butPtr->borderWidth <= 2) {
 
728
                        controlHandle = smallStickyBevelHandle;
 
729
                    } else if (butPtr->borderWidth == 3) {
 
730
                        controlHandle = medStickyBevelHandle;
 
731
                    } else {
 
732
                        controlHandle = largeStickyBevelHandle;
 
733
                    }
 
734
                    ccTabHandle = checkTabHandle;
 
735
                    SetupBevelButton(butPtr, controlHandle, destPort, 
 
736
                            gc, pixmap);
 
737
                    isBevel = 1;                
 
738
                }
 
739
            } else {
 
740
                controlHandle = checkHandle;
 
741
                ccTabHandle = checkTabHandle;
 
742
            }          
 
743
            break;
 
744
    }
 
745
    
 
746
    (**controlHandle).contrlRect.left = butPtr->inset;
 
747
    (**controlHandle).contrlRect.top = butPtr->inset;
 
748
    (**controlHandle).contrlRect.right = Tk_Width(butPtr->tkwin) 
 
749
            - butPtr->inset;
 
750
    (**controlHandle).contrlRect.bottom = Tk_Height(butPtr->tkwin) 
 
751
            - butPtr->inset;
 
752
            
 
753
    /*
 
754
     * Setting the control visibility by hand does not 
 
755
     * seem to work under Appearance. 
 
756
     */
 
757
     
 
758
    if (TkMacHaveAppearance()) {
 
759
        SetControlVisibility(controlHandle, true, false);      
 
760
        (**userPaneHandle).contrlRect.left = 0;
 
761
        (**userPaneHandle).contrlRect.top = 0;
 
762
        (**userPaneHandle).contrlRect.right = Tk_Width(butPtr->tkwin);
 
763
        (**userPaneHandle).contrlRect.bottom = Tk_Height(butPtr->tkwin);
 
764
    } else {      
 
765
        (**controlHandle).contrlVis = 255;
 
766
    }     
 
767
    
 
768
                
 
769
    
 
770
    if (butPtr->flags & SELECTED) {
 
771
        (**controlHandle).contrlValue = 1;
 
772
    } else {
 
773
        (**controlHandle).contrlValue = 0;
 
774
    }
 
775
    
 
776
    if (butPtr->state == tkActiveUid) {
 
777
        if (isBevel) {
 
778
            (**controlHandle).contrlHilite = kControlButtonPart;
 
779
        } else {
 
780
            switch (butPtr->type) {
 
781
                case TYPE_BUTTON:
 
782
                    (**controlHandle).contrlHilite = kControlButtonPart;
 
783
                    break;
 
784
                case TYPE_RADIO_BUTTON:
 
785
                    (**controlHandle).contrlHilite = kControlRadioButtonPart;
 
786
                    break;
 
787
                case TYPE_CHECK_BUTTON:
 
788
                    (**controlHandle).contrlHilite = kControlCheckBoxPart;
 
789
                    break;
 
790
            }
 
791
        }
 
792
    } else if (butPtr->state == tkDisabledUid) {
 
793
        (**controlHandle).contrlHilite = kControlInactivePart;
 
794
    } else {
 
795
        (**controlHandle).contrlHilite = kControlNoPart;
 
796
    }
 
797
 
 
798
    /*
 
799
     * Before we draw the control we must add the hidden window back to the
 
800
     * main window list.  Otherwise, radiobuttons and checkbuttons will draw
 
801
     * incorrectly.  I don't really know why - but clearly the control draw
 
802
     * proc needs to have the controls window in the window list.
 
803
     */
 
804
 
 
805
    ((CWindowPeek) windowRef)->nextWindow = (CWindowPeek) LMGetWindowList();
 
806
    LMSetWindowList(windowRef);
 
807
 
 
808
    /*
 
809
     * Now we can set the port to our doctered up window.  We next need
 
810
     * to muck with the colors for the port & window to draw the control
 
811
     * with the proper Tk colors.  If we need to we also draw a default
 
812
     * ring for buttons.
 
813
     * Under Appearance, we draw the control directly into destPort, and
 
814
     * just set the default control data.
 
815
     */
 
816
 
 
817
    if (TkMacHaveAppearance()) {
 
818
        SetPort((GrafPort *) destPort);
 
819
    } else {
 
820
        SetPort(windowRef);
 
821
    }
 
822
    
 
823
    windowColorChanged = UpdateControlColors(butPtr, controlHandle, 
 
824
        ccTabHandle, &saveBackColor);
 
825
        
 
826
    if ((butPtr->type == TYPE_BUTTON) && TkMacHaveAppearance()) {
 
827
        Boolean isDefault;
 
828
        
 
829
        if (butPtr->defaultState == tkActiveUid) {
 
830
            isDefault = true;
 
831
        } else {
 
832
            isDefault = false;
 
833
        }
 
834
        SetControlData(controlHandle, kControlNoPart, 
 
835
                kControlPushButtonDefaultTag,
 
836
                sizeof(isDefault), (Ptr) &isDefault);                   
 
837
    }
 
838
 
 
839
    if (TkMacHaveAppearance()) {
 
840
        DrawControlInCurrentPort(userPaneHandle);
 
841
    } else {
 
842
        Draw1Control(controlHandle);
 
843
    }
 
844
 
 
845
    if (!TkMacHaveAppearance() &&
 
846
            (butPtr->type == TYPE_BUTTON) && 
 
847
            (butPtr->defaultState == tkActiveUid)) {
 
848
        Rect box = (**controlHandle).contrlRect;
 
849
        RGBColor rgbColor;
 
850
 
 
851
        TkSetMacColor(butPtr->highlightColorPtr->pixel, &rgbColor);
 
852
        RGBForeColor(&rgbColor);
 
853
        PenSize(butPtr->highlightWidth - 1, butPtr->highlightWidth - 1);
 
854
        InsetRect(&box, -butPtr->highlightWidth, -butPtr->highlightWidth);
 
855
        FrameRoundRect(&box, 16, 16);
 
856
    }
 
857
    
 
858
    if (windowColorChanged) {
 
859
        RGBColor dummyColor;
 
860
        ChangeBackgroundWindowColor(windowRef, saveBackColor, &dummyColor);
 
861
    }
 
862
    
 
863
    /*
 
864
     * Clean up: remove the hidden window from the main window list, and
 
865
     * hide the control we drew.  
 
866
     */
 
867
 
 
868
    if (TkMacHaveAppearance()) {
 
869
        SetControlVisibility(controlHandle, false, false);
 
870
        if (isBevel) {
 
871
            KillPicture(bevelButtonContent.u.picture);
 
872
        }     
 
873
    } else {      
 
874
        (**controlHandle).contrlVis = 0;
 
875
    }     
 
876
    LMSetWindowList((WindowRef) ((CWindowPeek) windowRef)->nextWindow);
 
877
}
 
878
 
 
879
/*
 
880
 *--------------------------------------------------------------
 
881
 *
 
882
 * InitSampleControls --
 
883
 *
 
884
 *      This function initializes a dummy Macintosh window and
 
885
 *      sample controls to allow drawing Mac controls to any GWorld 
 
886
 *      (including off-screen bitmaps).  
 
887
 *
 
888
 * Results:
 
889
 *      None.
 
890
 *
 
891
 * Side effects:
 
892
 *      Controls & a window are created.
 
893
 *
 
894
 *--------------------------------------------------------------
 
895
 */
 
896
 
 
897
static void
 
898
InitSampleControls()
 
899
{
 
900
        Rect geometry = {0, 0, 10, 10};
 
901
        CWindowPeek windowList;
 
902
 
 
903
        /*
 
904
         * Create a dummy window that we can draw to.  We will
 
905
         * actually replace this window's bitmap with the one
 
906
         * we want to draw to at a later time.  This window and
 
907
         * the data structures attached to it are only deallocated
 
908
         * on exit of the application.
 
909
         */
 
910
        
 
911
        windowRef = NewCWindow(NULL, &geometry, "\pempty", false, 
 
912
            zoomDocProc, (WindowRef) -1, true, 0);
 
913
        if (windowRef == NULL) {
 
914
            panic("Can't allocate buffer window.");
 
915
        }
 
916
        
 
917
        /*
 
918
         * Now add the three standard controls to hidden window.  We
 
919
         * only create one of each and reuse them for every widget in
 
920
         * Tk.
 
921
         * Under Appearance, we have to embed the controls in a UserPane
 
922
         * control, so that we can color the background text in 
 
923
         * radiobuttons and checkbuttons.
 
924
         */
 
925
        
 
926
        SetPort(windowRef);
 
927
        
 
928
        if (TkMacHaveAppearance()) {
 
929
            
 
930
            OSErr err;
 
931
            ControlRef dontCare;
 
932
            
 
933
            /* Adding UserPaneBackgroundProcs to the root control does
 
934
             * not seem to work, so we have to add another UserPane to 
 
935
             * the root control.
 
936
             */
 
937
             
 
938
            err = CreateRootControl(windowRef, &dontCare);
 
939
            if (err != noErr) {
 
940
                panic("Can't create root control in DrawBufferedControl");
 
941
            }
 
942
            
 
943
            userPaneHandle = NewControl(windowRef, &geometry, "\p",
 
944
                true, kControlSupportsEmbedding|kControlHasSpecialBackground, 
 
945
                0, 1, kControlUserPaneProc, (SInt32) 0);
 
946
            SetUserPaneSetUpSpecialBackgroundProc(userPaneHandle,
 
947
                    UserPaneBackgroundProc);
 
948
            SetUserPaneDrawProc(userPaneHandle, UserPaneDraw);
 
949
 
 
950
            buttonHandle = NewControl(windowRef, &geometry, "\p",
 
951
                false, 1, 0, 1, kControlPushButtonProc, (SInt32) 0);
 
952
            EmbedControl(buttonHandle, userPaneHandle);
 
953
            checkHandle = NewControl(windowRef, &geometry, "\p",
 
954
            false, 1, 0, 1, kControlCheckBoxProc, (SInt32) 0);
 
955
            EmbedControl(checkHandle, userPaneHandle);
 
956
            radioHandle = NewControl(windowRef, &geometry, "\p",
 
957
                false, 1, 0, 1, kControlRadioButtonProc, (SInt32) 0);
 
958
            EmbedControl(radioHandle, userPaneHandle);
 
959
        smallBevelHandle = NewControl(windowRef, &geometry, "\p",
 
960
                false, 0, 0, 
 
961
                kControlBehaviorOffsetContents << 16 | kControlContentPictHandle, 
 
962
                kControlBevelButtonSmallBevelProc, (SInt32) 0);
 
963
        EmbedControl(smallBevelHandle, userPaneHandle);
 
964
        medBevelHandle = NewControl(windowRef, &geometry, "\p",
 
965
                false, 0, 0, 
 
966
                kControlBehaviorOffsetContents << 16 | kControlContentPictHandle, 
 
967
                kControlBevelButtonNormalBevelProc, (SInt32) 0);
 
968
        EmbedControl(medBevelHandle, userPaneHandle);
 
969
        largeBevelHandle = NewControl(windowRef, &geometry, "\p",
 
970
                false, 0, 0, 
 
971
                kControlBehaviorOffsetContents << 16 | kControlContentPictHandle, 
 
972
                kControlBevelButtonLargeBevelProc, (SInt32) 0);
 
973
        EmbedControl(largeBevelHandle, userPaneHandle);
 
974
        bevelButtonContent.contentType = kControlContentPictHandle;
 
975
        smallStickyBevelHandle = NewControl(windowRef, &geometry, "\p",
 
976
                false, 0, 0, 
 
977
                (kControlBehaviorOffsetContents | kControlBehaviorSticky) << 16 
 
978
                | kControlContentPictHandle, 
 
979
                kControlBevelButtonSmallBevelProc, (SInt32) 0);
 
980
        EmbedControl(smallStickyBevelHandle, userPaneHandle);
 
981
        medStickyBevelHandle = NewControl(windowRef, &geometry, "\p",
 
982
                false, 0, 0, 
 
983
                (kControlBehaviorOffsetContents | kControlBehaviorSticky) << 16 
 
984
                | kControlContentPictHandle, 
 
985
                kControlBevelButtonNormalBevelProc, (SInt32) 0);
 
986
        EmbedControl(medStickyBevelHandle, userPaneHandle);
 
987
        largeStickyBevelHandle = NewControl(windowRef, &geometry, "\p",
 
988
                false, 0, 0, 
 
989
                (kControlBehaviorOffsetContents | kControlBehaviorSticky) << 16 
 
990
                | kControlContentPictHandle, 
 
991
                kControlBevelButtonLargeBevelProc, (SInt32) 0);
 
992
        EmbedControl(largeStickyBevelHandle, userPaneHandle);
 
993
    
 
994
        picParams.version = -2;
 
995
        picParams.hRes = 0x00480000;
 
996
        picParams.vRes = 0x00480000;
 
997
        picParams.srcRect.top = 0;
 
998
        picParams.srcRect.left = 0;
 
999
    
 
1000
            ((CWindowPeek) windowRef)->visible = true;
 
1001
        } else {
 
1002
        buttonHandle = NewControl(windowRef, &geometry, "\p",
 
1003
                false, 1, 0, 1, pushButProc, (SInt32) 0);
 
1004
        checkHandle = NewControl(windowRef, &geometry, "\p",
 
1005
                false, 1, 0, 1, checkBoxProc, (SInt32) 0);
 
1006
        radioHandle = NewControl(windowRef, &geometry, "\p",
 
1007
                false, 1, 0, 1, radioButProc, (SInt32) 0);
 
1008
        ((CWindowPeek) windowRef)->visible = true;
 
1009
 
 
1010
        buttonTabHandle = (CCTabHandle) NewHandle(sizeof(CtlCTab));
 
1011
        checkTabHandle = (CCTabHandle) NewHandle(sizeof(CtlCTab));
 
1012
        radioTabHandle = (CCTabHandle) NewHandle(sizeof(CtlCTab));
 
1013
        }
 
1014
 
 
1015
        /*
 
1016
         * Remove our window from the window list.  This way our
 
1017
         * applications and others will not be confused that this
 
1018
         * window exists - but no one knows about it.
 
1019
         */
 
1020
 
 
1021
        windowList = (CWindowPeek) LMGetWindowList();
 
1022
        if (windowList == (CWindowPeek) windowRef) {
 
1023
            LMSetWindowList((WindowRef) windowList->nextWindow);
 
1024
        } else {
 
1025
            while ((windowList != NULL) 
 
1026
                    && (windowList->nextWindow != (CWindowPeek) windowRef)) {
 
1027
                windowList = windowList->nextWindow;
 
1028
            }
 
1029
            if (windowList != NULL) {
 
1030
                windowList->nextWindow = windowList->nextWindow->nextWindow;
 
1031
            }
 
1032
        }
 
1033
        ((CWindowPeek) windowRef)->nextWindow = NULL;
 
1034
 
 
1035
        /* 
 
1036
         * Create an exit handler to clean up this mess if we our
 
1037
         * unloaded etc.  We need to remember the windows portPixMap
 
1038
         * so it isn't leaked.
 
1039
         *
 
1040
         * TODO: The ButtonExitProc doesn't currently work and the
 
1041
         * code it includes will crash the Mac on exit from Tk.
 
1042
         
 
1043
         oldPixPtr = ((CWindowPeek) windowRef)->port.portPixMap;
 
1044
         Tcl_CreateExitHandler(ButtonExitProc, (ClientData) NULL);
 
1045
         */
 
1046
 
 
1047
}
 
1048
 
 
1049
/*
 
1050
 *--------------------------------------------------------------
 
1051
 *
 
1052
 * SetupBevelButton --
 
1053
 *
 
1054
 *      Sets up the Bevel Button with image by copying the
 
1055
 *      source image onto the PicHandle for the button.
 
1056
 *
 
1057
 * Results:
 
1058
 *      None
 
1059
 *
 
1060
 * Side effects:
 
1061
 *      The image or bitmap for the button is copied over to a picture.
 
1062
 *
 
1063
 *--------------------------------------------------------------
 
1064
 */
 
1065
void
 
1066
SetupBevelButton(
 
1067
    TkButton *butPtr,           /* Tk button. */
 
1068
    ControlRef controlHandle,    /* The control to set this picture to */
 
1069
    GWorldPtr destPort,         /* Off screen GWorld. */
 
1070
    GC gc,                      /* The GC we are drawing into - needed for
 
1071
                                 * the bevel button */
 
1072
    Pixmap pixmap               /* The pixmap we are drawing into - needed
 
1073
                                   for the bevel button */
 
1074
    )
 
1075
{
 
1076
    int height, width;
 
1077
    ControlButtonGraphicAlignment theAlignment;
 
1078
    
 
1079
    SetPort((GrafPtr) destPort);
 
1080
 
 
1081
    if (butPtr->image != None) {
 
1082
        Tk_SizeOfImage(butPtr->image, 
 
1083
                &width, &height);
 
1084
    } else {
 
1085
        Tk_SizeOfBitmap(butPtr->display, butPtr->bitmap, 
 
1086
                &width, &height);
 
1087
    }
 
1088
            
 
1089
    if ((butPtr->width > 0) && (butPtr->width < width)) {
 
1090
        width = butPtr->width;
 
1091
    }
 
1092
    if ((butPtr->height > 0) && (butPtr->height < height)) {
 
1093
        height = butPtr->height;
 
1094
    }
 
1095
    
 
1096
    picParams.srcRect.right = width;
 
1097
    picParams.srcRect.bottom = height;
 
1098
    
 
1099
    bevelButtonContent.u.picture = OpenCPicture(&picParams);
 
1100
    
 
1101
    /*
 
1102
     * TO DO - There is one case where XCopyPlane calls CopyDeepMask,
 
1103
     * which does not get recorded in the picture.  So the bitmap code
 
1104
     * will fail in that case.
 
1105
     */
 
1106
     
 
1107
    if ((butPtr->selectImage != NULL) && (butPtr->flags & SELECTED)) {
 
1108
        Tk_RedrawImage(butPtr->selectImage, 0, 0, width, height,
 
1109
                pixmap, 0, 0);
 
1110
    } else if (butPtr->image != NULL) {
 
1111
        Tk_RedrawImage(butPtr->image, 0, 0, width, 
 
1112
            height, pixmap, 0, 0);
 
1113
    } else {                    
 
1114
        XSetClipOrigin(butPtr->display, gc, 0, 0);
 
1115
        XCopyPlane(butPtr->display, butPtr->bitmap, pixmap, gc, 0, 0,
 
1116
                (unsigned int) width, (unsigned int) height, 0, 0, 1);
 
1117
    }
 
1118
    
 
1119
    ClosePicture();
 
1120
    
 
1121
    SetControlData(controlHandle, kControlButtonPart,
 
1122
            kControlBevelButtonContentTag,
 
1123
            sizeof(ControlButtonContentInfo),
 
1124
            (char *) &bevelButtonContent);
 
1125
            
 
1126
    if (butPtr->anchor == TK_ANCHOR_N) {
 
1127
            theAlignment = kControlBevelButtonAlignTop;
 
1128
     } else if (butPtr->anchor == TK_ANCHOR_NE) { 
 
1129
            theAlignment = kControlBevelButtonAlignTopRight;
 
1130
     } else if (butPtr->anchor == TK_ANCHOR_E) { 
 
1131
            theAlignment = kControlBevelButtonAlignRight;
 
1132
     } else if (butPtr->anchor == TK_ANCHOR_SE) {
 
1133
            theAlignment = kControlBevelButtonAlignBottomRight;
 
1134
     } else if (butPtr->anchor == TK_ANCHOR_S) {
 
1135
            theAlignment = kControlBevelButtonAlignBottom;
 
1136
     } else if (butPtr->anchor == TK_ANCHOR_SW) {
 
1137
            theAlignment = kControlBevelButtonAlignBottomLeft;
 
1138
     } else if (butPtr->anchor == TK_ANCHOR_W) {
 
1139
            theAlignment = kControlBevelButtonAlignLeft;
 
1140
     } else if (butPtr->anchor == TK_ANCHOR_NW) {
 
1141
            theAlignment = kControlBevelButtonAlignTopLeft;
 
1142
     } else if (butPtr->anchor == TK_ANCHOR_CENTER) {
 
1143
            theAlignment = kControlBevelButtonAlignCenter;
 
1144
    }
 
1145
 
 
1146
    SetControlData(controlHandle, kControlButtonPart,
 
1147
            kControlBevelButtonGraphicAlignTag,
 
1148
            sizeof(ControlButtonGraphicAlignment),
 
1149
            (char *) &theAlignment);
 
1150
 
 
1151
}
 
1152
 
 
1153
/*
 
1154
 *--------------------------------------------------------------
 
1155
 *
 
1156
 * SetUserPaneDrawProc --
 
1157
 *
 
1158
 *      Utility function to add a UserPaneDrawProc
 
1159
 *      to a userPane control.  From MoreControls code
 
1160
 *      from Apple DTS.
 
1161
 *
 
1162
 * Results:
 
1163
 *      MacOS system error.
 
1164
 *
 
1165
 * Side effects:
 
1166
 *      The user pane gets a new UserPaneDrawProc.
 
1167
 *
 
1168
 *--------------------------------------------------------------
 
1169
 */
 
1170
pascal OSErr SetUserPaneDrawProc (
 
1171
        ControlRef control,
 
1172
        ControlUserPaneDrawProcPtr upp)
 
1173
{
 
1174
    ControlUserPaneDrawUPP myControlUserPaneDrawUPP;
 
1175
    myControlUserPaneDrawUPP = NewControlUserPaneDrawProc(upp); 
 
1176
    return SetControlData (control, 
 
1177
                kControlNoPart, kControlUserPaneDrawProcTag, 
 
1178
                sizeof(myControlUserPaneDrawUPP), 
 
1179
                (Ptr) &myControlUserPaneDrawUPP);
 
1180
}
 
1181
 
 
1182
/*
 
1183
 *--------------------------------------------------------------
 
1184
 *
 
1185
 * SetUserPaneSetUpSpecialBackgroundProc --
 
1186
 *
 
1187
 *      Utility function to add a UserPaneBackgroundProc
 
1188
 *      to a userPane control
 
1189
 *
 
1190
 * Results:
 
1191
 *      MacOS system error.
 
1192
 *
 
1193
 * Side effects:
 
1194
 *      The user pane gets a new UserPaneBackgroundProc.
 
1195
 *
 
1196
 *--------------------------------------------------------------
 
1197
 */
 
1198
pascal OSErr
 
1199
SetUserPaneSetUpSpecialBackgroundProc(
 
1200
    ControlRef control, 
 
1201
    ControlUserPaneBackgroundProcPtr upp)
 
1202
{
 
1203
    ControlUserPaneBackgroundUPP myControlUserPaneBackgroundUPP;
 
1204
    myControlUserPaneBackgroundUPP = NewControlUserPaneBackgroundProc(upp);
 
1205
    return SetControlData (control, kControlNoPart, 
 
1206
                kControlUserPaneBackgroundProcTag, 
 
1207
                sizeof(myControlUserPaneBackgroundUPP), 
 
1208
                (Ptr) &myControlUserPaneBackgroundUPP);
 
1209
}
 
1210
 
 
1211
/*
 
1212
 *--------------------------------------------------------------
 
1213
 *
 
1214
 * UserPaneDraw --
 
1215
 *
 
1216
 *      This function draws the background of the user pane that will 
 
1217
 *      lie under checkboxes and radiobuttons.
 
1218
 *
 
1219
 * Results:
 
1220
 *      None.
 
1221
 *
 
1222
 * Side effects:
 
1223
 *      The user pane gets updated to the current color.
 
1224
 *
 
1225
 *--------------------------------------------------------------
 
1226
 */
 
1227
pascal void
 
1228
UserPaneDraw(
 
1229
    ControlRef control,
 
1230
    ControlPartCode cpc)
 
1231
{
 
1232
        Rect contrlRect = (**control).contrlRect;
 
1233
        RGBBackColor (&gUserPaneBackground);
 
1234
        EraseRect (&contrlRect);
 
1235
}
 
1236
 
 
1237
/*
 
1238
 *--------------------------------------------------------------
 
1239
 *
 
1240
 * UserPaneBackgroundProc --
 
1241
 *
 
1242
 *      This function sets up the background of the user pane that will 
 
1243
 *      lie under checkboxes and radiobuttons.
 
1244
 *
 
1245
 * Results:
 
1246
 *      None.
 
1247
 *
 
1248
 * Side effects:
 
1249
 *      The user pane background gets set to the current color.
 
1250
 *
 
1251
 *--------------------------------------------------------------
 
1252
 */
 
1253
 
 
1254
pascal void
 
1255
UserPaneBackgroundProc(
 
1256
    ControlHandle,
 
1257
    ControlBackgroundPtr info)
 
1258
{
 
1259
    if (info->colorDevice) {
 
1260
        RGBBackColor (&gUserPaneBackground);
 
1261
    }
 
1262
}
 
1263
 
 
1264
/*
 
1265
 *--------------------------------------------------------------
 
1266
 *
 
1267
 * UpdateControlColors --
 
1268
 *
 
1269
 *      This function will review the colors used to display
 
1270
 *      a Macintosh button.  If any non-standard colors are
 
1271
 *      used we create a custom palette for the button, populate
 
1272
 *      with the colors for the button and install the palette.
 
1273
 *
 
1274
 *      Under Appearance, we just set the pointer that will be
 
1275
 *      used by the UserPaneDrawProc.
 
1276
 *
 
1277
 * Results:
 
1278
 *      None.
 
1279
 *
 
1280
 * Side effects:
 
1281
 *      The Macintosh control may get a custom palette installed.
 
1282
 *
 
1283
 *--------------------------------------------------------------
 
1284
 */
 
1285
 
 
1286
static int
 
1287
UpdateControlColors(
 
1288
    TkButton *butPtr,
 
1289
    ControlRef controlHandle,
 
1290
    CCTabHandle ccTabHandle,
 
1291
    RGBColor *saveColorPtr)
 
1292
{
 
1293
    XColor *xcolor;
 
1294
    
 
1295
    /*
 
1296
     * Under Appearance we cannot change the background of the
 
1297
     * button itself.  However, the color we are setting is the color
 
1298
     *  of the containing userPane.  This will be the color that peeks 
 
1299
     * around the rounded corners of the button.  
 
1300
     * We make this the highlightbackground rather than the background,
 
1301
     * because if you color the background of a frame containing a
 
1302
     * button, you usually also color the highlightbackground as well,
 
1303
     * or you will get a thin grey ring around the button.
 
1304
     */
 
1305
      
 
1306
    if (TkMacHaveAppearance() && (butPtr->type == TYPE_BUTTON)) {
 
1307
        xcolor = Tk_3DBorderColor(butPtr->highlightBorder);
 
1308
    } else {
 
1309
    xcolor = Tk_3DBorderColor(butPtr->normalBorder);
 
1310
    }
 
1311
    if (TkMacHaveAppearance()) {
 
1312
         TkSetMacColor(xcolor->pixel, &gUserPaneBackground);
 
1313
     } else {
 
1314
    (**ccTabHandle).ccSeed = 0;
 
1315
    (**ccTabHandle).ccRider = 0;
 
1316
    (**ccTabHandle).ctSize = 3;
 
1317
    (**ccTabHandle).ctTable[0].value = cBodyColor;
 
1318
    TkSetMacColor(xcolor->pixel,
 
1319
        &(**ccTabHandle).ctTable[0].rgb);
 
1320
    (**ccTabHandle).ctTable[1].value = cTextColor;
 
1321
    TkSetMacColor(butPtr->normalFg->pixel,
 
1322
        &(**ccTabHandle).ctTable[1].rgb);
 
1323
    (**ccTabHandle).ctTable[2].value = cFrameColor;
 
1324
    TkSetMacColor(butPtr->highlightColorPtr->pixel,
 
1325
        &(**ccTabHandle).ctTable[2].rgb);
 
1326
    SetControlColor(controlHandle, ccTabHandle);
 
1327
        
 
1328
    if (((xcolor->pixel >> 24) != CONTROL_BODY_PIXEL) && 
 
1329
            ((butPtr->type == TYPE_CHECK_BUTTON) ||
 
1330
                    (butPtr->type == TYPE_RADIO_BUTTON))) {
 
1331
        RGBColor newColor;
 
1332
        
 
1333
        TkSetMacColor(xcolor->pixel, &newColor);
 
1334
        ChangeBackgroundWindowColor((**controlHandle).contrlOwner,
 
1335
                newColor, saveColorPtr);
 
1336
        return true;
 
1337
    }
 
1338
    }
 
1339
    
 
1340
    return false;
 
1341
}
 
1342
 
 
1343
/*
 
1344
 *--------------------------------------------------------------
 
1345
 *
 
1346
 * ChangeBackgroundWindowColor --
 
1347
 *
 
1348
 *      This procedure will change the background color entry
 
1349
 *      in the Window's colortable.  The system isn't notified
 
1350
 *      of the change.  This call should only be used to fool
 
1351
 *      the drawing routines for checkboxes and radiobuttons.
 
1352
 *      Any change should be temporary and be reverted after
 
1353
 *      the widget is drawn.
 
1354
 *
 
1355
 * Results:
 
1356
 *      None.
 
1357
 *
 
1358
 * Side effects:
 
1359
 *      The Window's color table will be adjusted.
 
1360
 *
 
1361
 *--------------------------------------------------------------
 
1362
 */
 
1363
 
 
1364
static void
 
1365
ChangeBackgroundWindowColor(
 
1366
    WindowRef macintoshWindow,  /* A Mac window whose color to change. */
 
1367
    RGBColor rgbColor,          /* The new RGB Color for the background. */
 
1368
    RGBColor *oldColor)         /* The old color of the background. */
 
1369
{
 
1370
    AuxWinHandle auxWinHandle;
 
1371
    WCTabHandle winCTabHandle;
 
1372
    short ctIndex;
 
1373
    ColorSpecPtr rgbScan;
 
1374
        
 
1375
    GetAuxWin(macintoshWindow, &auxWinHandle);
 
1376
    winCTabHandle = (WCTabHandle) ((**auxWinHandle).awCTable);
 
1377
 
 
1378
    /*
 
1379
     * Scan through the color table until we find the content
 
1380
     * (background) color for the window.  Don't tell the system
 
1381
     * about the change - it will generate damage and we will get
 
1382
     * into an infinite loop.
 
1383
     */
 
1384
 
 
1385
    ctIndex = (**winCTabHandle).ctSize;
 
1386
    while (ctIndex > -1) {
 
1387
        rgbScan = ctIndex + (**winCTabHandle).ctTable;
 
1388
 
 
1389
        if (rgbScan->value == wContentColor) {
 
1390
            *oldColor = rgbScan->rgb;
 
1391
            rgbScan->rgb = rgbColor;
 
1392
            break;
 
1393
        }
 
1394
        ctIndex--;
 
1395
    }
 
1396
}
 
1397
 
 
1398
/*
 
1399
 *----------------------------------------------------------------------
 
1400
 *
 
1401
 * ButtonExitProc --
 
1402
 *
 
1403
 *      This procedure is invoked just before the application exits.
 
1404
 *      It frees all of the control handles, our dummy window, etc.
 
1405
 *
 
1406
 * Results:
 
1407
 *      None.
 
1408
 *
 
1409
 * Side effects:
 
1410
 *      Memory is freed.
 
1411
 *
 
1412
 *----------------------------------------------------------------------
 
1413
 */
 
1414
 
 
1415
static void
 
1416
ButtonExitProc(clientData)
 
1417
    ClientData clientData;              /* Not used. */
 
1418
{
 
1419
    Rect pixRect = {0, 0, 10, 10};
 
1420
    Rect rgnRect = {0, 0, 0, 0};
 
1421
 
 
1422
    /*
 
1423
     * Restore our dummy window to it's origional state by putting it
 
1424
     * back in the window list and restoring it's bits.  The destroy
 
1425
     * the controls and window.
 
1426
     */
 
1427
 
 
1428
    ((CWindowPeek) windowRef)->nextWindow = (CWindowPeek) LMGetWindowList();
 
1429
    LMSetWindowList(windowRef);
 
1430
    ((CWindowPeek) windowRef)->port.portPixMap = oldPixPtr;
 
1431
    ((CWindowPeek) windowRef)->port.portRect = pixRect;
 
1432
    RectRgn(((CWindowPeek) windowRef)->port.visRgn, &rgnRect);
 
1433
    RectRgn(((CWindowPeek) windowRef)->strucRgn, &rgnRect);
 
1434
    RectRgn(((CWindowPeek) windowRef)->updateRgn, &rgnRect);
 
1435
    RectRgn(((CWindowPeek) windowRef)->contRgn, &rgnRect);
 
1436
    PortChanged(windowRef);
 
1437
 
 
1438
    DisposeControl(buttonHandle);
 
1439
    DisposeControl(checkHandle);
 
1440
    DisposeControl(radioHandle);
 
1441
    DisposeWindow(windowRef);
 
1442
    windowRef = NULL;
 
1443
}