1 /* Tabs Widget for SXEmacs.
2 Copyright (C) 1999 Edward A. Falk
4 This file is part of SXEmacs.
6 SXEmacs is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 SXEmacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19 /* Synched up with: Gcs.c 1.7 */
21 /* #### This code is duplicated many times within lwlib and XEmacs. It
22 should be modularised. */
25 * Gcs.c - Utility functions to allocate GCs.
27 * Author: Edward A. Falk
28 * falk@falconer.vip.best.com
35 * GC AllocFgGC(w, fg, font)
36 * Return a GC with foreground set as specified.
37 * If font is None, then the returned GC is allocated with font specified
38 * as a "don't care" value.
41 * AllocBackgroundGC(w, font)
42 * Return a GC with the foreground set to the widget's background color.
45 * AllocGreyGC(w, fg, font, contrast, be_nice_to_cmap)
50 * int be_nice_to_cmap ;
52 * Return a GC suitable for rendering a widget in its "inactive" color.
53 * Normally returns a GC with a color somewhere between the widget's
54 * background color and the specified foreground. If font is None, then
55 * the returned GC is allocated with font specified as "don't care".
56 * If be_nice_to_cmap is True, the returned GC is created using a 50%
57 * dither instead of a new color.
61 * AllocShadeGC(w, fg, bg, font, contrast, be_nice_to_cmap)
66 * int be_nice_to_cmap ;
68 * Return a GC suitable for rendering in a shade somewhere between
69 * bg and fg, as determined by contrast (0 = bg, 100 = fg)
70 * If font is None, then the returned GC is allocated with
71 * font specified as "don't care". If be_nice_to_cmap
72 * is True, the returned GC is created using a 50% dither
73 * instead of a new color.
77 * AllocTopShadowGC(w, contrast, be_nice_to_cmap)
78 * Return a GC suitable for rendering the "top shadow" decorations of
79 * a widget. Returns a GC with foreground computed from widget's
80 * background color and contrast. If be_nice_to_cmap is True, the
81 * returned GC will use a foreground color of white. If widget depth
82 * is 1, this function will use a foreground color of black.
85 * AllocBotShadowGC(w, contrast, be_nice_to_cmap)
86 * Return a GC suitable for rendering the "bottom shadow" decorations
87 * of a widget. Returns a GC with foreground computed from widget's
88 * background color and contrast. If be_nice_to_cmap is True, the
89 * returned GC will use a foreground color of black.
92 * AllocArmGC(w, contrast, be_nice_to_cmap)
93 * Return a GC suitable for rendering the "armed" decorations of a
94 * widget. This GC would typically be used to fill in the widget's
95 * background. Returns a GC with foreground computed from widget's
96 * background color and contrast. If be_nice_to_cmap is True, the
97 * returned GC will use a foreground color of black and a 50% dither.
101 * Draw3dBox(w, x,y,wid,hgt,s, topgc, botgc)
102 * Utility function. Draws a raised shadow box with outside dimensions
103 * as specified by x,y,wid,hgt and shadow width specified by s.
104 * A lowered shadow box may be generated by swapping topgc and botgc.
111 #include <X11/Xlib.h>
112 #include <X11/IntrinsicP.h>
113 #include <X11/StringDefs.h>
114 #include "ui/X11/xmu.h"
117 /* Color & GC allocation.
119 * Frame widgets use the following graphics contexts:
121 * Foreground tab label text drawn this way
122 * Insensitive Fg foreground color greyed out.
123 * Background frame background color
124 * Top shadow upper-left highlight around widget
125 * Bottom shadow lower-right highlight around widget
126 * Arm shadow button pressed and ready to be released
129 * GC's are defined as follows, depending on attributes and
133 * Foreground = foreground color attribute or BlackPixel()
134 * Grey = Foreground color + 50% dither
135 * Background = background color attribute or WhitePixel()
136 * top shadow = foreground
137 * bottom shadow = foreground
138 * arm shadow = (what?)
140 * Color, beNiceToColormap=true:
141 * Foreground = foreground color attribute or BlackPixel()
142 * Grey = Foreground color + 50% dither
143 * Background = background color attribute or WhitePixel()
145 * bottom shadow = black
146 * arm shadow = (what?)
148 * Color, beNiceToColormap=false:
149 * Foreground = foreground color attribute or BlackPixel()
150 * Grey = (foreground color + background color)/2
151 * Background = background color attribute or WhitePixel()
152 * top shadow = background * 1.2
153 * bottom shadow = background * .6
154 * arm shadow = background * .8
157 * If background is white, ??
158 * if background is black, ??
161 * If the widget's background is solid white or solid black,
162 * this code just picks some numbers. (The choice is designed
163 * to be compatible with ThreeD interface.)
166 #if XtSpecificationRelease < 5
168 static GC XtAllocateGC(Widget, int, unsigned long, XGCValues *,
169 unsigned long, unsigned long);
173 #if NeedFunctionPrototypes
174 static Pixmap getDitherPixmap(Widget, int contrast);
176 static Pixmap getDitherPixmap();
179 /* return a GC with the specified foreground and optional font */
181 GC AllocFgGC(Widget w, Pixel fg, Font font)
184 unsigned long vmask, dcmask;
186 values.foreground = fg;
190 vmask = GCForeground | GCFont;
191 dcmask = GCSubwindowMode | GCDashOffset |
192 GCDashList | GCArcMode | GCBackground | GCGraphicsExposures;
194 vmask = GCForeground;
195 dcmask = GCFont | GCSubwindowMode | GCDashOffset |
196 GCDashList | GCArcMode | GCBackground | GCGraphicsExposures;
199 return XtAllocateGC(w, w->core.depth, vmask, &values, 0L, dcmask);
202 /* return gc with widget background color as the foreground */
204 GC AllocBackgroundGC(Widget w, Font font)
206 return AllocFgGC(w, w->core.background_pixel, font);
209 /* Allocate an "inactive" GC. Color is grey (possibly via
214 AllocGreyGC(Widget w, Pixel fg, Font font, int contrast, Bool be_nice_to_cmap)
216 return AllocShadeGC(w, fg, w->core.background_pixel,
217 font, contrast, be_nice_to_cmap);
220 /* Allocate a GC somewhere between two colors. */
223 AllocShadeGC(Widget w, Pixel fg, Pixel bg, Font font,
224 int contrast, Bool be_nice_to_cmap)
227 unsigned long vmask, dcmask;
229 values.foreground = fg;
230 values.background = bg;
234 vmask = GCForeground | GCFont;
235 dcmask = GCSubwindowMode | GCDashOffset |
236 GCDashList | GCArcMode | GCGraphicsExposures;
238 vmask = GCForeground;
239 dcmask = GCFont | GCSubwindowMode | GCDashOffset |
240 GCDashList | GCArcMode | GCGraphicsExposures;
243 if (be_nice_to_cmap || w->core.depth == 1) {
245 values.foreground = bg;
246 else if (contrast >= 95)
247 values.foreground = fg;
249 vmask |= GCBackground | GCStipple | GCFillStyle;
250 values.fill_style = FillOpaqueStippled;
251 values.stipple = getDitherPixmap(w, contrast);
254 return XtAllocateGC(w, w->core.depth, vmask, &values, 0L,
259 dcmask |= GCBackground;
260 values.foreground = AllocGreyPixel(w, fg, bg, contrast);
261 return XtAllocateGC(w, w->core.depth, vmask, &values, 0L,
266 /* return top-shadow gc. */
268 GC AllocTopShadowGC(Widget w, int contrast, Bool be_nice_to_cmap)
270 Screen *scr = XtScreen(w);
273 if (w->core.depth == 1)
274 values.foreground = BlackPixelOfScreen(scr);
275 else if (be_nice_to_cmap)
276 values.foreground = WhitePixelOfScreen(scr);
278 values.foreground = AllocShadowPixel(w, 100 + contrast);
280 return XtAllocateGC(w, w->core.depth,
281 GCForeground, &values,
283 GCBackground | GCFont | GCSubwindowMode |
284 GCGraphicsExposures | GCDashOffset | GCDashList |
288 /* return bottom-shadow gc. */
290 GC AllocBotShadowGC(Widget w, int contrast, Bool be_nice_to_cmap)
292 Screen *scr = XtScreen(w);
295 if (w->core.depth == 1 || be_nice_to_cmap)
296 values.foreground = BlackPixelOfScreen(scr);
298 values.foreground = AllocShadowPixel(w, 100 - contrast);
300 return XtAllocateGC(w, w->core.depth,
301 GCForeground, &values,
303 GCBackground | GCFont | GCSubwindowMode |
304 GCGraphicsExposures | GCDashOffset | GCDashList |
308 /* return arm-shadow gc. */
310 GC AllocArmGC(Widget w, int contrast, Bool be_nice_to_cmap)
312 Screen *scr = XtScreen(w);
315 /* Not clear exactly what we should do here. Take a look at
316 * Xaw3d to see what they do.
319 if (w->core.depth == 1 || be_nice_to_cmap) {
320 values.background = w->core.background_pixel;
321 if (values.background == BlackPixelOfScreen(scr))
322 values.foreground = WhitePixelOfScreen(scr);
324 values.foreground = BlackPixelOfScreen(scr);
325 values.fill_style = FillStippled;
327 XmuCreateStippledPixmap(XtScreen(w), 1L, 0L, 1);
329 return XtAllocateGC(w, w->core.depth,
330 GCForeground | GCBackground | GCStipple |
331 GCFillStyle, &values, 0L,
332 GCFont | GCSubwindowMode |
333 GCGraphicsExposures | GCDashOffset |
334 GCDashList | GCArcMode);
338 values.foreground = AllocShadowPixel(w, 100 - contrast);
339 return XtAllocateGC(w, w->core.depth,
340 GCForeground, &values,
342 GCBackground | GCFont | GCSubwindowMode |
343 GCGraphicsExposures | GCDashOffset |
344 GCDashList | GCArcMode);
348 Pixel AllocShadowPixel(Widget w, int scale)
351 Display *dpy = XtDisplay(w);
352 Screen *scr = XtScreen(w);
356 cmap = w->core.colormap;
358 get_c.pixel = w->core.background_pixel;
359 if (get_c.pixel == WhitePixelOfScreen(scr) ||
360 get_c.pixel == BlackPixelOfScreen(scr)) {
361 /* what we *ought* to do is choose gray75 as the base color,
362 * or perhaps gray83. Instead, we choose colors that are
363 * the same as ThreeD would choose.
367 set_c.red = set_c.green = set_c.blue = 65535 * scale / 100;
369 XQueryColor(dpy, cmap, &get_c);
370 /* adjust scale so that brightest component does not
371 * exceed 65535; otherwise hue would change.
374 maxColor = Max(get_c.red, Max(get_c.green, get_c.blue));
375 if (scale * maxColor > 65535 * 100)
376 scale = 65535 * 100 / maxColor;
378 set_c.red = scale * get_c.red / 100;
379 set_c.green = scale * get_c.green / 100;
380 set_c.blue = scale * get_c.blue / 100;
382 set_c.flags = DoRed | DoGreen | DoBlue;
383 if (XAllocColor(dpy, cmap, &set_c))
385 else if (scale > 100)
386 return WhitePixelOfScreen(scr);
388 return BlackPixelOfScreen(scr);
391 /* Allocate a pixel partway between foreground and background */
393 Pixel AllocGreyPixel(Widget w, Pixel fg, Pixel bg, int scale)
395 XColor get_cf, get_cb;
396 Display *dpy = XtDisplay(w);
399 cmap = w->core.colormap;
404 XQueryColor(dpy, cmap, &get_cf);
405 XQueryColor(dpy, cmap, &get_cb);
407 return AllocGreyPixelC(w, &get_cf, &get_cb, scale);
410 /* Allocate a pixel partway between foreground and background */
412 Pixel AllocGreyPixelC(Widget w, XColor * fg, XColor * bg, int scale)
415 Display *dpy = XtDisplay(w);
417 Colormap cmap = w->core.colormap;
419 r = (fg->red * scale + bg->red * (100 - scale)) / 100;
420 g = (fg->green * scale + bg->green * (100 - scale)) / 100;
421 b = (fg->blue * scale + bg->blue * (100 - scale)) / 100;
423 if (scale > 100 || scale < 0) { /* look out for overflow */
425 maxc = Max(r, Max(g, b));
426 minc = Min(r, Min(g, b));
429 r = r * (65535 / 16) / maxc;
430 g = g * (65535 / 16) / maxc;
431 b = b * (65535 / 16) / maxc;
443 set_c.flags = DoRed | DoGreen | DoBlue;
444 (void)XAllocColor(dpy, cmap, &set_c);
451 Draw3dBox(Widget w, int x, int y, int wid, int hgt, int s, GC topgc, GC botgc)
453 Display *dpy = XtDisplay(w);
454 Window win = XtWindow(w);
460 XDrawLine(dpy, win, botgc, x, y + hgt - 1, x + wid - 1,
462 XDrawLine(dpy, win, botgc, x + wid - 1, y, x + wid - 1,
464 XDrawLine(dpy, win, topgc, x, y, x, y + hgt - 1);
465 XDrawLine(dpy, win, topgc, x, y, x + wid - 1, y);
469 /* bottom-right shadow */
474 pts[2].x = wid - 2 * s;
477 pts[3].y = -(hgt - 2 * s);
482 XFillPolygon(dpy, win, botgc, pts, 6, Nonconvex,
485 /* top-left shadow */
492 pts[3].x = -wid + 2 * s;
495 pts[4].y = hgt - 2 * s;
498 XFillPolygon(dpy, win, topgc, pts, 6, Nonconvex,
503 #if XtSpecificationRelease < 5
506 XtAllocateGC(Widget w, int depth, unsigned long mask, XGCValues * values,
507 unsigned long dynamic, unsigned long dontcare)
509 return XtGetGC(w, mask, values);
515 static unsigned char screen0[2] = { 0, 0 };
516 static unsigned char screen25[2] = { 0, 0xaa };
517 static unsigned char screen75[2] = { 0xaa, 0xff };
518 static unsigned char screen100[2] = { 0xff, 0xff };
520 static Pixmap getDitherPixmap(Widget w, int contrast)
522 Display *dpy = XtDisplay(w);
523 Window win = XtWindow(w);
526 return XCreateBitmapFromData(dpy, win, (char *)screen0, 2, 2);
527 else if (contrast <= 37)
528 return XCreateBitmapFromData(dpy, win, (char *)screen25, 2, 2);
529 else if (contrast <= 62)
530 return XmuCreateStippledPixmap(XtScreen(w), 1L, 0L, 1);
531 else if (contrast <= 95)
532 return XCreateBitmapFromData(dpy, win, (char *)screen75, 2, 2);
534 return XCreateBitmapFromData(dpy, win, (char *)screen100, 2, 2);
537 #endif /* HAVE_XMU */