1/*
2
3Copyright 1988, 1994, 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
12in all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
18OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20OTHER DEALINGS IN THE SOFTWARE.
21
22Except as contained in this notice, the name of The Open Group shall
23not be used in advertising or otherwise to promote the sale, use or
24other dealings in this Software without prior written authorization
25from The Open Group.
26
27*/
28
29#ifdef HAVE_CONFIG_H
30#include <config.h>
31#endif
32#include <X11/StringDefs.h>
33#include <X11/IntrinsicP.h>
34#include <X11/Xmu/Drawing.h>
35#include "LogoP.h"
36#include <X11/extensions/shape.h>
37#include <X11/Xfuncproto.h>
38#include <X11/Xos.h>
39
40#ifdef XRENDER
41#include "RenderLogo.h"
42#endif
43
44static XtResource resources[] = {
45    {XtNshapeWindow, XtCShapeWindow, XtRBoolean, sizeof (Boolean),
46       XtOffsetOf(LogoRec,logo.shape_window), XtRImmediate,
47       (XtPointer) FALSE},
48#ifdef XRENDER
49    {XtNrender, XtCBoolean, XtRBoolean, sizeof(Boolean),
50       XtOffsetOf(LogoRec,logo.render), XtRImmediate,
51       (XtPointer) FALSE },
52    {XtNsharp, XtCBoolean, XtRBoolean, sizeof(Boolean),
53       XtOffsetOf(LogoRec,logo.sharp), XtRImmediate,
54       (XtPointer) FALSE },
55    {XtNforeground, XtCForeground, XtRXftColor, sizeof(XftColor),
56       XtOffsetOf(LogoRec, logo.fg), XtRString,
57       (XtPointer) XtDefaultForeground},
58    {XtNbackground, XtCForeground, XtRXftColor, sizeof(XftColor),
59       XtOffsetOf(LogoRec, logo.bg), XtRString,
60       (XtPointer) XtDefaultBackground},
61#else
62    {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
63        XtOffsetOf(LogoRec,logo.fgpixel), XtRString,
64       (XtPointer) XtDefaultForeground},
65#endif
66};
67
68static void ClassInitialize ( void );
69static void Initialize ( Widget request, Widget new, ArgList args,
70			 Cardinal *num_args );
71static void Destroy ( Widget gw );
72static void Realize ( Widget gw, XtValueMask *valuemaskp,
73		      XSetWindowAttributes *attr );
74static void Resize ( Widget gw );
75static void Redisplay ( Widget gw, XEvent *event, Region region );
76static Boolean SetValues ( Widget gcurrent, Widget grequest, Widget gnew,
77			   ArgList args, Cardinal *num_args );
78
79LogoClassRec logoClassRec = {
80    { /* core fields */
81    /* superclass		*/	(WidgetClass) &simpleClassRec,
82    /* class_name		*/	"Logo",
83    /* widget_size		*/	sizeof(LogoRec),
84    /* class_initialize		*/	ClassInitialize,
85    /* class_part_initialize	*/	NULL,
86    /* class_inited		*/	FALSE,
87    /* initialize		*/	Initialize,
88    /* initialize_hook		*/	NULL,
89    /* realize			*/	Realize,
90    /* actions			*/	NULL,
91    /* num_actions		*/	0,
92    /* resources		*/	resources,
93    /* resource_count		*/	XtNumber(resources),
94    /* xrm_class		*/	NULLQUARK,
95    /* compress_motion		*/	TRUE,
96    /* compress_exposure	*/	TRUE,
97    /* compress_enterleave	*/	TRUE,
98    /* visible_interest		*/	FALSE,
99    /* destroy			*/	Destroy,
100    /* resize			*/	Resize,
101    /* expose			*/	Redisplay,
102    /* set_values		*/	SetValues,
103    /* set_values_hook		*/	NULL,
104    /* set_values_almost	*/	XtInheritSetValuesAlmost,
105    /* get_values_hook		*/	NULL,
106    /* accept_focus		*/	NULL,
107    /* version			*/	XtVersion,
108    /* callback_private		*/	NULL,
109    /* tm_table			*/	NULL,
110    /* query_geometry		*/	XtInheritQueryGeometry,
111    /* display_accelerator	*/	XtInheritDisplayAccelerator,
112    /* extension		*/	NULL
113    },
114    { /* simple fields */
115    /* change_sensitive         */      XtInheritChangeSensitive,
116    /* extension                */      NULL
117    },
118    { /* logo fields */
119    /* ignore                   */      0
120    }
121};
122
123WidgetClass logoWidgetClass = (WidgetClass) &logoClassRec;
124
125
126/*****************************************************************************
127 *									     *
128 *			   private utility routines			     *
129 *									     *
130 *****************************************************************************/
131
132static void
133create_gcs(LogoWidget w)
134{
135    XGCValues v = { 0 };
136
137#ifdef XRENDER
138    w->logo.fgpixel = w->logo.fg.pixel;
139#endif
140
141    v.foreground = w->logo.fgpixel;
142    w->logo.foreGC = XtGetGC ((Widget) w, GCForeground, &v);
143    v.foreground = w->core.background_pixel;
144    w->logo.backGC = XtGetGC ((Widget) w, GCForeground, &v);
145}
146
147static void
148check_shape(LogoWidget w)
149{
150    if (w->logo.shape_window) {
151	int event_base, error_base;
152
153	if (!XShapeQueryExtension (XtDisplay (w), &event_base, &error_base))
154	  w->logo.shape_window = FALSE;
155    }
156}
157
158/* ARGSUSED */
159static void
160unset_shape(LogoWidget w)
161{
162    XSetWindowAttributes attr = { 0 };
163    unsigned long mask;
164    Display *dpy = XtDisplay ((Widget) w);
165    Window win = XtWindow ((Widget) w);
166
167    if (w->core.background_pixmap != None &&
168	w->core.background_pixmap != XtUnspecifiedPixmap) {
169	attr.background_pixmap = w->core.background_pixmap;
170	mask = CWBackPixmap;
171    } else {
172	attr.background_pixel = w->core.background_pixel;
173	mask = CWBackPixel;
174    }
175    XChangeWindowAttributes (dpy, win, mask, &attr);
176    XShapeCombineMask (dpy, win, ShapeBounding, 0, 0, None, ShapeSet);
177    if (!w->logo.foreGC) create_gcs (w);
178    w->logo.need_shaping = w->logo.shape_window;
179}
180
181static void
182set_shape(LogoWidget w)
183{
184    GC ones, zeros;
185    Display *dpy = XtDisplay ((Widget) w);
186    Window win = XtWindow ((Widget) w);
187    unsigned int width = (unsigned int) w->core.width;
188    unsigned int height = (unsigned int) w->core.height;
189    Pixmap pm = XCreatePixmap (dpy, win, width, height, (unsigned int) 1);
190    XGCValues v = { 0 };
191
192    v.foreground = (Pixel) 1;
193    v.background = (Pixel) 0;
194    ones = XCreateGC (dpy, pm, (GCForeground | GCBackground), &v);
195    v.foreground = (Pixel) 0;
196    v.background = (Pixel) 1;
197    zeros = XCreateGC (dpy, pm, (GCForeground | GCBackground), &v);
198
199    if (pm && ones && zeros) {
200	int x = 0, y = 0;
201	Widget parent;
202
203	XmuDrawLogo (dpy, pm, ones, zeros, 0, 0, width, height);
204	for (parent = (Widget) w; XtParent(parent);
205	     parent = XtParent(parent)) {
206	    x += parent->core.x + parent->core.border_width;
207	    y += parent->core.y + parent->core.border_width;
208	}
209	XShapeCombineMask (dpy, XtWindow (parent), ShapeBounding,
210			   x, y, pm, ShapeSet);
211	w->logo.need_shaping = FALSE;
212    } else {
213	unset_shape (w);
214    }
215    if (ones) XFreeGC (dpy, ones);
216    if (zeros) XFreeGC (dpy, zeros);
217    if (pm) XFreePixmap (dpy, pm);
218}
219
220
221/*****************************************************************************
222 *									     *
223 *				 class methods				     *
224 *									     *
225 *****************************************************************************/
226
227#ifdef XRENDER
228
229static void
230RenderPrepare (LogoWidget w)
231{
232    if (!w->logo.draw)
233    {
234	w->logo.draw = XftDrawCreate (XtDisplay (w), XtWindow (w),
235				       DefaultVisual (XtDisplay (w),
236						      DefaultScreen(XtDisplay (w))),
237				       w->core.colormap);
238    }
239}
240
241static XtConvertArgRec xftColorConvertArgs[] = {
242    {XtWidgetBaseOffset, (XtPointer)XtOffsetOf(WidgetRec, core.screen),
243     sizeof(Screen *)},
244    {XtWidgetBaseOffset, (XtPointer)XtOffsetOf(WidgetRec, core.colormap),
245     sizeof(Colormap)}
246};
247
248#define	donestr(type, value, tstr) \
249	do {							\
250	    if (toVal->addr != NULL) {				\
251		if (toVal->size < sizeof(type)) {		\
252		    toVal->size = sizeof(type);			\
253		    XtDisplayStringConversionWarning(dpy, 	\
254			(char*) fromVal->addr, tstr);		\
255		    return False;				\
256		}						\
257		*(type*)(toVal->addr) = (value);		\
258	    }							\
259	    else {						\
260		static type static_val;				\
261		static_val = (value);				\
262		toVal->addr = (XPointer)&static_val;		\
263	    }							\
264	    toVal->size = sizeof(type);				\
265	    return True;					\
266	} while (0)
267
268static void
269XmuFreeXftColor (XtAppContext app, XrmValuePtr toVal,
270                 _X_UNUSED XtPointer closure,
271		 XrmValuePtr args, Cardinal *num_args)
272{
273    Screen	*screen;
274    Colormap	colormap;
275    XftColor	*color;
276
277    if (*num_args != 2)
278    {
279	XtAppErrorMsg (app,
280		       "freeXftColor", "wrongParameters",
281		       "XtToolkitError",
282		       "Freeing an XftColor requires screen and colormap arguments",
283		       (String *) NULL, (Cardinal *)NULL);
284	return;
285    }
286
287    screen = *((Screen **) args[0].addr);
288    colormap = *((Colormap *) args[1].addr);
289    color = (XftColor *) toVal->addr;
290    XftColorFree (DisplayOfScreen (screen),
291		  DefaultVisual (DisplayOfScreen (screen),
292				 XScreenNumberOfScreen (screen)),
293		  colormap, color);
294}
295
296static Boolean
297XmuCvtStringToXftColor(Display *dpy,
298		       XrmValue *args, Cardinal *num_args,
299		       XrmValue *fromVal, XrmValue *toVal,
300		       _X_UNUSED XtPointer *converter_data)
301{
302    char	    *spec;
303    XRenderColor    renderColor;
304    XftColor	    xftColor;
305    Screen	    *screen;
306    Colormap	    colormap;
307
308    if (*num_args != 2)
309    {
310	XtAppErrorMsg (XtDisplayToApplicationContext (dpy),
311		       "cvtStringToXftColor", "wrongParameters",
312		       "XtToolkitError",
313		       "String to render color conversion needs screen and colormap arguments",
314		       (String *) NULL, (Cardinal *)NULL);
315	return False;
316    }
317
318    screen = *((Screen **) args[0].addr);
319    colormap = *((Colormap *) args[1].addr);
320
321    spec = (char *) fromVal->addr;
322    if (strcasecmp (spec, XtDefaultForeground) == 0)
323    {
324	renderColor = (XRenderColor) {
325	    .red = 0,
326	    .green = 0,
327	    .blue = 0,
328	    .alpha = 0xffff
329	};
330    }
331    else if (strcasecmp (spec, XtDefaultBackground) == 0)
332    {
333	renderColor = (XRenderColor) {
334	    .red = 0xffff,
335	    .green = 0xffff,
336	    .blue = 0xffff,
337	    .alpha = 0xffff
338	};
339    }
340    else if (!XRenderParseColor (dpy, spec, &renderColor))
341	return False;
342    if (!XftColorAllocValue (dpy,
343			     DefaultVisual (dpy,
344					    XScreenNumberOfScreen (screen)),
345			     colormap,
346			     &renderColor,
347			     &xftColor))
348	return False;
349
350    donestr (XftColor, xftColor, XtRXftColor);
351}
352
353
354#endif
355
356static void
357ClassInitialize(void)
358{
359#ifdef XRENDER
360    XtSetTypeConverter (XtRString, XtRXftColor,
361			XmuCvtStringToXftColor,
362			xftColorConvertArgs, XtNumber(xftColorConvertArgs),
363			XtCacheByDisplay, XmuFreeXftColor);
364#endif
365}
366
367/* ARGSUSED */
368static void
369Initialize(_X_UNUSED Widget request, Widget new,
370           _X_UNUSED ArgList args, _X_UNUSED Cardinal *num_args)
371{
372    LogoWidget w = (LogoWidget)new;
373
374#ifdef XRENDER
375    w->logo.draw = NULL;
376    w->logo.fgpixel = w->logo.fg.pixel;
377#endif
378    if (w->core.width < 1) w->core.width = 100;
379    if (w->core.height < 1) w->core.height = 100;
380
381    w->logo.foreGC = (GC) NULL;
382    w->logo.backGC = (GC) NULL;
383    check_shape (w);
384    w->logo.need_shaping = w->logo.shape_window;
385}
386
387static void
388Destroy(Widget gw)
389{
390    LogoWidget w = (LogoWidget) gw;
391    if (w->logo.foreGC) {
392	XtReleaseGC (gw, w->logo.foreGC);
393	w->logo.foreGC = (GC) NULL;
394    }
395    if (w->logo.backGC) {
396	XtReleaseGC (gw, w->logo.backGC);
397	w->logo.backGC = (GC) NULL;
398    }
399}
400
401static void
402Realize(Widget gw, XtValueMask *valuemaskp, XSetWindowAttributes *attr)
403{
404    LogoWidget w = (LogoWidget) gw;
405
406    if (w->logo.shape_window) {
407	attr->background_pixel = w->logo.fgpixel;  /* going to shape */
408	*valuemaskp |= CWBackPixel;
409    } else
410      create_gcs (w);
411    (*logoWidgetClass->core_class.superclass->core_class.realize)
412	(gw, valuemaskp, attr);
413}
414
415static void
416Resize(Widget gw)
417{
418    LogoWidget w = (LogoWidget) gw;
419
420    if (w->logo.shape_window && XtIsRealized(gw)) set_shape (w);
421}
422
423/* ARGSUSED */
424static void
425Redisplay(Widget gw, _X_UNUSED XEvent *event, _X_UNUSED Region region)
426{
427    LogoWidget w = (LogoWidget) gw;
428
429    if (w->logo.shape_window) {
430	if (w->logo.need_shaping) set_shape (w);  /* may change shape flag */
431    }
432    if (!w->logo.shape_window) {
433#ifdef XRENDER
434	if (w->logo.render)
435	{
436	    RenderPrepare (w);
437
438	    XClearWindow (XtDisplay(w), XtWindow(w));
439	    RenderLogo (XtDisplay(w), PictOpOver,
440			XftDrawSrcPicture (w->logo.draw, &w->logo.fg),
441			XftDrawPicture (w->logo.draw),
442			XRenderFindStandardFormat (XtDisplay (w),
443						   w->logo.sharp ?
444						   PictStandardA1:
445						   PictStandardA8),
446			0, 0, (unsigned int) w->core.width,
447			(unsigned int) w->core.height);
448	}
449	else
450#endif
451	{
452	    XmuDrawLogo (XtDisplay(w), XtWindow(w), w->logo.foreGC, w->logo.backGC,
453			 0, 0, (unsigned int) w->core.width,
454			 (unsigned int) w->core.height);
455	}
456    }
457}
458
459/* ARGSUSED */
460static Boolean
461SetValues (Widget gcurrent, _X_UNUSED Widget grequest, Widget gnew,
462	   _X_UNUSED ArgList args, _X_UNUSED Cardinal *num_args)
463{
464    LogoWidget current = (LogoWidget) gcurrent;
465    LogoWidget new = (LogoWidget) gnew;
466    Boolean redisplay = FALSE;
467
468    if (new->logo.shape_window &&
469	new->logo.shape_window != current->logo.shape_window)
470	check_shape (new);			/* validate shape_window */
471
472    if ((new->logo.fgpixel != current->logo.fgpixel) ||
473	(new->core.background_pixel != current->core.background_pixel)) {
474	Destroy (gnew);
475	if (!new->logo.shape_window) create_gcs (new);
476	redisplay = TRUE;
477    }
478
479   if (new->logo.shape_window != current->logo.shape_window) {
480       if (new->logo.shape_window) {
481	   Destroy (gnew);
482	   if (XtIsRealized(gnew))
483	       set_shape (new);
484	   else
485	       new->logo.need_shaping = True;
486	   redisplay = FALSE;
487       } else {
488	   if (XtIsRealized(gnew))
489	       unset_shape (new);		/* creates new GCs */
490	   redisplay = TRUE;
491       }
492   }
493
494   return (redisplay);
495}
496