1/* 2 3Copyright 1988, 1998 The Open Group 4 5Permission to use, copy, modify, distribute, and sell this software and its 6documentation for any purpose is hereby granted without fee, provided that 7the above copyright notice appear in all copies and that both that 8copyright notice and this permission notice appear in supporting 9documentation. 10 11The above copyright notice and this permission notice shall be included in 12all copies or substantial portions of the Software. 13 14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 21Except as contained in this notice, the name of The Open Group shall not be 22used in advertising or otherwise to promote the sale, use or other dealings 23in this Software without prior written authorization from The Open Group. 24 25*/ 26 27#ifdef HAVE_CONFIG_H 28#include <config.h> 29#endif 30#include <X11/IntrinsicP.h> 31#include <X11/extensions/shape.h> 32#include "Converters.h" 33#include "Drawing.h" 34#include "Misc.h" 35 36/* 37 * Prototypes 38 */ 39static void ShapeEllipseOrRoundedRectangle(Widget, Bool, int, int); 40static void ShapeError(Widget); 41static void ShapeOval(Widget); 42static void ShapeRectangle(Widget); 43 44/* 45 * Implementation 46 */ 47Boolean 48XmuReshapeWidget(Widget w, int shape_style, 49 int corner_width, int corner_height) 50{ 51 switch (shape_style) 52 { 53 case XmuShapeRectangle: 54 ShapeRectangle(w); 55 break; 56 case XmuShapeOval: 57 ShapeOval(w); 58 break; 59 case XmuShapeEllipse: 60 case XmuShapeRoundedRectangle: 61 ShapeEllipseOrRoundedRectangle(w, shape_style == XmuShapeEllipse, 62 corner_width, corner_height); 63 break; 64 default: 65 ShapeError(w); 66 return (False); 67 } 68 return (True); 69} 70 71static void 72ShapeError(Widget w) 73{ 74 String params[1]; 75 Cardinal num_params = 1; 76 77 params[0] = XtName(w); 78 XtAppWarningMsg(XtWidgetToApplicationContext(w), 79 "shapeUnknown", "xmuReshapeWidget", "XmuLibrary", 80 "Unsupported shape style for Command widget \"%s\"", 81 params, &num_params); 82} 83 84static void 85ShapeRectangle(Widget w) 86{ 87 XShapeCombineMask(XtDisplay(w), XtWindow(w), 88 ShapeBounding, 0, 0, None, ShapeSet); 89 XShapeCombineMask(XtDisplay(w), XtWindow(w), 90 ShapeClip, 0, 0, None, ShapeSet); 91} 92 93/* 94 * Function: 95 * ShapeOval 96 * 97 * Parameters: 98 * w - widget to be reshaped 99 * 100 * Description: 101 * Reshapes a widget to a oval format. 102 * 103 * Notes: 104 * X11R6.3 behaviour changed. Now if the height is larger than the 105 * width, this function inverts the sense of the oval, instead of 106 * fallbacking to ellipse. 107 */ 108static void 109ShapeOval(Widget w) 110{ 111 Display *dpy = XtDisplay(w); 112 int width = w->core.width; 113 int height = w->core.height; 114 Pixmap p; 115 XGCValues values; 116 GC gc; 117 int rad; 118 119 if (width < 3 || height < 3) 120 return; 121 width += w->core.border_width << 1; 122 height += w->core.border_width << 1; 123 124 p = XCreatePixmap(dpy, XtWindow(w), width, height, 1); 125 values.foreground = 0; 126 values.background = 1; 127 values.cap_style = CapRound; 128 values.line_width = Min(width, height); 129 gc = XCreateGC(dpy, p, 130 GCForeground | GCBackground | GCLineWidth | GCCapStyle, 131 &values); 132 XFillRectangle(dpy, p, gc, 0, 0, width, height); 133 XSetForeground(dpy, gc, 1); 134 135 if (width < height) 136 { 137 rad = width >> 1; 138 XDrawLine(dpy, p, gc, rad, rad, rad, height - rad - 1); 139 } 140 else 141 { 142 rad = height >> 1; 143 XDrawLine(dpy, p, gc, rad, rad, width - rad - 1, rad); 144 } 145 XShapeCombineMask(dpy, XtWindow(w), ShapeBounding, 146 -(int)w->core.border_width, -(int)w->core.border_width, 147 p, ShapeSet); 148 if (w->core.border_width) 149 { 150 XSetForeground(dpy, gc, 0); 151 XFillRectangle(dpy, p, gc, 0, 0, width, height); 152 values.line_width = Min(w->core.width, w->core.height); 153 values.foreground = 1; 154 XChangeGC(dpy, gc, GCLineWidth | GCForeground, &values); 155 if (w->core.width < w->core.height) 156 { 157 rad = w->core.width >> 1; 158 XDrawLine(dpy, p, gc, rad, rad, rad, w->core.height - rad - 1); 159 } 160 else 161 { 162 rad = w->core.height >> 1; 163 XDrawLine(dpy, p, gc, rad, rad, w->core.width - rad - 1, rad); 164 } 165 XShapeCombineMask(dpy, XtWindow(w), ShapeClip, 0, 0, p, ShapeSet); 166 } 167 else 168 XShapeCombineMask(XtDisplay(w), XtWindow(w), 169 ShapeClip, 0, 0, None, ShapeSet); 170 171 XFreePixmap(dpy, p); 172 XFreeGC(dpy, gc); 173} 174 175/* 176 * Function: 177 * ShapeEllipseOrRoundedRectangle 178 * 179 * Parameters: 180 * w - widget to be reshaped 181 * ellipse - True if shape to ellipse, rounded rectangle otherwise 182 * ew - horizontal radius of rounded rectangle 183 * eh - vertical radius of rounded rectangle 184 * 185 * Description: 186 * Based on the ellipse parameter, gives the widget a elliptical 187 * shape, or rounded rectangle shape. 188 * 189 * Notes: 190 * The GC is created with a line width of 2, what seens to draw the 191 * widget border correctly, if the width - height is not proportional. 192 */ 193static void 194ShapeEllipseOrRoundedRectangle(Widget w, Bool ellipse, int ew, int eh) 195{ 196 Display *dpy = XtDisplay(w); 197 unsigned width = w->core.width; 198 unsigned height = w->core.height; 199 Pixmap p; 200 XGCValues values; 201 GC gc; 202 unsigned long mask; 203 204 if (width < 3 || height < 3) 205 return; 206 width += w->core.border_width << 1; 207 height += w->core.border_width << 1; 208 209 mask = GCForeground | GCLineWidth; 210 p = XCreatePixmap(dpy, XtWindow(w), width, height, 1); 211 212 values.foreground = 0; 213 values.line_width = 2; 214 215 gc = XCreateGC(dpy, p, mask, &values); 216 XFillRectangle(dpy, p, gc, 0, 0, width, height); 217 XSetForeground(dpy, gc, 1); 218 if (!ellipse) 219 XmuFillRoundedRectangle(dpy, p, gc, 1, 1, width - 2, height - 2, ew, eh); 220 else 221 { 222 XDrawArc(dpy, p, gc, 1, 1, width - 2, height - 2, 0, 360 * 64); 223 XFillArc(dpy, p, gc, 2, 2, width - 4, height - 4, 0, 360 * 64); 224 } 225 XShapeCombineMask(dpy, XtWindow(w), ShapeBounding, 226 -(int)w->core.border_width, -(int)w->core.border_width, 227 p, ShapeSet); 228 if (w->core.border_width) 229 { 230 XSetForeground(dpy, gc, 0); 231 XFillRectangle(dpy, p, gc, 0, 0, width, height); 232 XSetForeground(dpy, gc, 1); 233 if (!ellipse) 234 XmuFillRoundedRectangle(dpy, p, gc, 1, 1, 235 w->core.width - 2, w->core.height - 2, 236 ew, eh); 237 else 238 XFillArc(dpy, p, gc, 0, 0, w->core.width, w->core.height, 239 0, 360 * 64); 240 XShapeCombineMask(dpy, XtWindow(w), ShapeClip, 0, 0, p, ShapeSet); 241 } 242 else 243 XShapeCombineMask(XtDisplay(w), XtWindow(w), 244 ShapeClip, 0, 0, None, ShapeSet); 245 246 XFreePixmap(dpy, p); 247 XFreeGC(dpy, gc); 248} 249