1 /*--------------------------------*-C-*---------------------------------*
2  * File:    pixmap.c
3  *----------------------------------------------------------------------*
4  *
5  * All portions of code are copyright by their respective author/s.
6  * Copyright (c) 1997        Carsten Haitzler <raster@zip.com.au>
7  * Copyright (c) 1997,1998   Oezguer Kesim <kesim@math.fu-berlin.de>
8  * Copyright (c) 1998-2001   Geoff Wing <gcw@pobox.com>
9  * Copyright (c) 2004        Jingmin Zhou <jimmyzhou@users.sourceforge.net>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24  *----------------------------------------------------------------------*/
25 
26 #include "../config.h"
27 #include "rxvt.h"
28 
29 
30 #ifdef BACKGROUND_IMAGE
31 
32 /*--------------------------------------------------------------------*
33  *         BEGIN `INTERNAL' ROUTINE PROTOTYPES                        *
34  *--------------------------------------------------------------------*/
35 void rxvt_pixmap_incr (unsigned int*, unsigned int*, float*, float*, unsigned int, unsigned int);
36 /*--------------------------------------------------------------------*
37  *         END   `INTERNAL' ROUTINE PROTOTYPES                        *
38  *--------------------------------------------------------------------*/
39 
40 
41 
42 /*
43  * These GEOM strings indicate absolute size/position:
44  * @ `WxH+X+Y'
45  * @ `WxH+X'	-> Y = X
46  * @ `WxH'    -> Y = X = 50
47  * @ `W+X+Y'	-> H = W
48  * @ `W+X'    -> H = W, Y = X
49  * @ `W'	-> H = W, X = Y = 50
50  * @ `0xH'    -> H *= H/100, X = Y = 50 (W unchanged)
51  * @ `Wx0'    -> W *= W/100, X = Y = 50 (H unchanged)
52  * @ `=+X+Y'	-> (H, W unchanged)
53  * @ `=+X'    -> Y = X (H, W unchanged)
54  *
55  * These GEOM strings adjust position relative to current position:
56  * @ `+X+Y'
57  * @ `+X'      -> Y = X
58  *
59  * And this GEOM string is for querying current scale/position:
60  * @ `?'
61  */
62 /* EXTPROTO */
63 int
rxvt_scale_pixmap(rxvt_t * r,int page,const char * geom)64 rxvt_scale_pixmap(rxvt_t *r, int page, const char *geom)
65 {
66     int		 flags, changed = 0;
67     int		 x = 0, y = 0;
68     unsigned int    w = 0, h = 0;
69     unsigned int    n;
70     char	   *p, *str;
71     bgPixmap_t	 *bgpixmap = &(PVTS(r, page)->bg);
72 
73 #define MAXLEN_GEOM	sizeof("[1000x1000+1000+1000]")
74 
75     if (geom == NULL)
76 	return 0;
77     str = rxvt_malloc(MAXLEN_GEOM + 1);
78     if (!STRCMP(geom, "?")) {
79 	sprintf(str, "[%dx%d+%d+%d]",	/* can't presume snprintf() ! */
80 	    min(bgpixmap->w, 9999), min(bgpixmap->h, 9999),
81 	    min(bgpixmap->x, 9999), min(bgpixmap->y, 9999));
82 	rxvt_xterm_seq(r, page, XTerm_title, str, CHAR_ST);
83 	rxvt_free(str);
84 	return 0;
85     }
86 
87     if ((p = STRCHR(geom, ';')) == NULL)
88     p = STRCHR(geom, '\0');
89     n = (p - geom);
90     if (n <= MAXLEN_GEOM) {
91     STRNCPY(str, geom, n);
92     str[n] = '\0';
93 
94     flags = XParseGeometry(str, &x, &y, &w, &h);
95     if (!flags) {
96 	flags |= WidthValue;
97 	w = 0;
98     }		/* default is tile */
99     if (flags & WidthValue) {
100 	if (!(flags & XValue))
101 	x = 50;
102 	if (!(flags & HeightValue))
103 	h = w;
104 	if (w && !h) {
105 	w = (bgpixmap->w * w) / 100;
106 	h = bgpixmap->h;
107 	} else if (h && !w) {
108 	w = bgpixmap->w;
109 	h = (bgpixmap->h * h) / 100;
110 	}
111 	if (w > 1000)
112 	w = 1000;
113 	if (h > 1000)
114 	h = 1000;
115 	if (bgpixmap->w != (short)w) {
116 	bgpixmap->w = (short)w;
117 	changed++;
118 	}
119 	if (bgpixmap->h != (short)h) {
120 	bgpixmap->h = (short)h;
121 	changed++;
122 	}
123     }
124     if (!(flags & YValue)) {
125 	if (flags & XNegative)
126 	flags |= YNegative;
127 	y = x;
128     }
129 
130     if (!(flags & WidthValue) && geom[0] != '=') {
131 	x += bgpixmap->x;
132 	y += bgpixmap->y;
133     } else {
134 	if (flags & XNegative)
135 	x += 100;
136 	if (flags & YNegative)
137 	y += 100;
138     }
139     MIN_IT(x, 100);
140     MIN_IT(y, 100);
141     MAX_IT(x, 0);
142     MAX_IT(y, 0);
143     if (bgpixmap->x != x) {
144 	bgpixmap->x = x;
145 	changed++;
146     }
147     if (bgpixmap->y != y) {
148 	bgpixmap->y = y;
149 	changed++;
150     }
151     }
152     rxvt_free(str);
153     return changed;
154 }
155 
156 
157 /* EXTPROTO */
158 void
rxvt_resize_pixmap(rxvt_t * r,int page)159 rxvt_resize_pixmap(rxvt_t *r, int page)
160 {
161     XGCValues	    gcvalue;
162     GC		    gc;
163     unsigned int    width = VT_WIDTH(r);
164     unsigned int    height = VT_HEIGHT(r);
165 
166     if (IS_PIXMAP(PVTS(r, page)->pixmap))
167 	XFreePixmap(r->Xdisplay, PVTS(r, page)->pixmap);
168 
169     if (NOT_PIXMAP(PVTS(r, page)->bg.pixmap))
170 	/* So be it: I'm not using pixmaps */
171 	return;
172 
173     gcvalue.foreground = r->pixColorsFocus[Color_bg];
174     gc = XCreateGC(r->Xdisplay, PVTS(r, page)->vt, GCForeground, &gcvalue);
175 
176     if (IS_GC(gc) && IS_PIXMAP(PVTS(r, page)->bg.pixmap)) {
177 	/* we have a specified pixmap */
178 	unsigned int	w = PVTS(r, page)->bg.w;
179 	unsigned int	h = PVTS(r, page)->bg.h;
180 	unsigned int	x = PVTS(r, page)->bg.x;
181 	unsigned int	y = PVTS(r, page)->bg.y;
182 	unsigned int	xpmh = PVTS(r, page)->xpm_attr.height;
183 	unsigned int	xpmw = PVTS(r, page)->xpm_attr.width;
184 	unsigned int	pixmapw, pixmaph;
185 
186 	/*
187 	 * don't zoom pixmap too much nor expand really small pixmaps
188 	 */
189 	if (w > 1000 || h > 1000)
190 	    w = 1;
191 	else if (width > (10 * xpmw)
192 	     || height > (10 * xpmh))
193 	    w = 0;	/* tile */
194 
195 	if (w == 0) {
196 	    /* basic X tiling - let the X server do it */
197 	    PVTS(r, page)->pixmap = XCreatePixmap(r->Xdisplay,
198 		PVTS(r, page)->vt, xpmw, xpmh, (unsigned int)XDEPTH);
199 	    XCopyArea(r->Xdisplay, PVTS(r, page)->bg.pixmap,
200 		PVTS(r, page)->pixmap, gc, 0, 0, xpmw, xpmh, 0, 0);
201 
202 	    pixmapw = xpmw;
203 	    pixmaph = xpmh;
204 	}
205 	else {
206 	    float	  incr, p;
207 	    Pixmap	  tmp;
208 
209 	    PVTS(r, page)->pixmap = XCreatePixmap(r->Xdisplay,
210 		PVTS(r, page)->vt, width, height, (unsigned int)XDEPTH);
211 
212 	    /* horizontal scaling */
213 	    rxvt_pixmap_incr(&w, &x, &incr, &p, width, xpmw);
214 
215 	    tmp = XCreatePixmap(r->Xdisplay, PVTS(r, page)->vt,
216 		    width, xpmh, (unsigned int)XDEPTH);
217 	    XFillRectangle(r->Xdisplay, tmp, gc, 0, 0, width,
218 		   xpmh);
219 
220 	    for ( /*nil */ ; x < w; x++, p += incr) {
221 		if (p >= xpmw)
222 		    p = 0;
223 		/* copy one column from the original pixmap to the
224 		** tmp pixmap */
225 		XCopyArea(r->Xdisplay, PVTS(r, page)->bg.pixmap, tmp,
226 		    gc, (int)p, 0, 1, xpmh, (int)x, 0);
227 	    }
228 
229 	    /* vertical scaling */
230 	    rxvt_pixmap_incr(&h, &y, &incr, &p, height, xpmh);
231 
232 	    if (y > 0)
233 		XFillRectangle(r->Xdisplay, PVTS(r, page)->pixmap, gc,
234 		    0, 0, width, y);
235 	    if (h < height)
236 		XFillRectangle(r->Xdisplay, PVTS(r, page)->pixmap, gc,
237 		    0, (int)h, width, height - h + 1);
238 	    for ( /*nil */ ; y < h; y++, p += incr) {
239 		if (p >= xpmh)
240 		    p = 0;
241 		/* copy one row from the tmp pixmap to the main
242 		** pixmap */
243 		XCopyArea(r->Xdisplay, tmp, PVTS(r, page)->pixmap, gc,
244 		    0, (int)p, width, 1, 0, (int)y);
245 	    }
246 	    XFreePixmap(r->Xdisplay, tmp);
247 
248 	    pixmapw = width;
249 	    pixmaph = height;
250 	}
251 
252 #ifdef TINTING_SUPPORT
253 # ifdef HAVE_LIBXRENDER
254 	xrenderShadeParentPixmap( r, PVTS(r, page)->pixmap,
255 		0, 0, pixmapw, pixmaph, False);
256 # else
257 	rxvt_shade_pixmap( r, PVTS(r, page)->pixmap,
258 		0, 0, pixmapw, pixmaph);
259 # endif
260 #endif	/* TINTING_SUPPORT */
261 
262 	/* Free gc */
263 	XFreeGC(r->Xdisplay, gc);
264     }
265 
266     XSetWindowBackgroundPixmap(r->Xdisplay, PVTS(r, page)->vt,
267 	PVTS(r, page)->pixmap);
268 # ifdef TRANSPARENT
269     r->h->am_transparent = 0;
270     r->h->am_pixmap_trans = 0;
271 # endif
272 
273     XClearWindow(r->Xdisplay, PVTS(r, page)->vt);
274 
275     XSync(r->Xdisplay, False);
276 }
277 
278 /*
279  * Calculate tiling sizes and increments
280  * At start, p == 0, incr == xpmwidthheight
281  */
282 /* INTPROTO */
283 void
rxvt_pixmap_incr(unsigned int * wh,unsigned int * xy,float * incr,float * p,unsigned int widthheight,unsigned int xpmwidthheight)284 rxvt_pixmap_incr(unsigned int *wh, unsigned int *xy, float *incr, float *p, unsigned int widthheight, unsigned int xpmwidthheight)
285 {
286     unsigned int    cwh, cxy;
287     float	   cincr, cp;
288 
289     cp = 0;
290     cincr = (float)xpmwidthheight;
291     cxy = *xy;
292     cwh = *wh;
293     if (cwh == 1) { /* display one image, no horizontal/vertical scaling */
294     cincr = (float)widthheight;
295     if (xpmwidthheight <= widthheight) {
296 	cwh = xpmwidthheight;
297 	cxy = (cxy * (widthheight - cwh)) / 100;    /* beware! order */
298 	cwh += cxy;
299     } else {
300 	cxy = 0;
301 	cwh = widthheight;
302     }
303     } else if (cwh < 10) {  /* fit WH images across/down screen */
304     cincr *= cwh;
305     cxy = 0;
306     cwh = widthheight;
307     } else {
308     cincr *= 100.0 / cwh;
309     if (cwh < 100) {	/* contract */
310 	float	       pos;
311 
312 	cwh = (cwh * widthheight) / 100;
313 	pos = (float)cxy / 100 * widthheight - (cwh / 2);
314 
315 	cxy = (widthheight - cwh);
316 	if (pos <= 0)
317 	cxy = 0;
318 	else if (pos < cxy)
319 	cxy = pos;
320 	cwh += cxy;
321     } else {	/* expand */
322 	if (cxy > 0) {	/* position */
323 	float	       pos;
324 
325 	pos = (float)cxy / 100 * xpmwidthheight - (cincr / 2);
326 	cp = xpmwidthheight - cincr;
327 	if (pos <= 0)
328 	    cp = 0;
329 	else if (pos < cp)
330 	    cp = pos;
331 	}
332 	cxy = 0;
333 	cwh = widthheight;
334     }
335     }
336     cincr /= widthheight;
337     *wh = cwh;
338     *xy = cxy;
339     *incr = cincr;
340     *p = cp;
341 }
342 
343 
344 /* EXTPROTO */
345 Pixmap
rxvt_load_bg_pixmap(rxvt_t * r,int page,const char * file)346 rxvt_load_bg_pixmap(rxvt_t *r, int page, const char *file)
347 {
348     Pixmap	pixmap;
349     long	w = 0, h = 0;
350 
351     assert(file != NULL);
352 
353     pixmap = rxvt_load_pixmap (r, file, &w, &h);
354     if (IS_PIXMAP(PVTS(r, page)->bg.pixmap))
355 	XFreePixmap (r->Xdisplay, PVTS(r, page)->bg.pixmap);
356     PVTS(r, page)->bg.pixmap = pixmap;
357 
358     if( NOT_PIXMAP(pixmap) )
359     {
360 	if( page == ATAB(r) )
361 	{
362 	    /* Force resetting the background color */
363 	    r->fgbg_tabnum = -1;
364 	    rxvt_set_vt_colors( r, page );
365 	}
366 
367 	return None;
368     }
369 
370     PVTS(r, page)->xpm_attr.closeness = 30000;
371     PVTS(r, page)->xpm_attr.colormap = XCMAP;
372     PVTS(r, page)->xpm_attr.visual = XVISUAL;
373     PVTS(r, page)->xpm_attr.depth = XDEPTH;
374     PVTS(r, page)->xpm_attr.valuemask = (XpmCloseness | XpmColormap |
375 	    XpmVisual | XpmDepth | XpmSize | XpmReturnPixels);
376     PVTS(r, page)->xpm_attr.width = w;
377     PVTS(r, page)->xpm_attr.height = h;
378     rxvt_resize_pixmap(r, page);
379     return (pixmap);
380 }
381 
382 
383 /* EXTPROTO */
384 Pixmap
rxvt_load_pixmap(rxvt_t * r,const char * file,long * pwidth,long * pheight)385 rxvt_load_pixmap(rxvt_t *r, const char *file, long* pwidth, long* pheight)
386 {
387     char*	    f;
388     int		    flen;
389 #if defined(USE_JPEG) || defined(USE_PNG)
390     long	    w = 0, h = 0;
391 #endif
392     XpmAttributes   xpm_attr;
393     Pixmap	    pixmap;
394 
395     UNSET_PIXMAP(pixmap);
396 
397     assert(file != NULL);
398     if ((char) 0 == *file) { /* No file to load */
399 	return None;
400     }
401 
402     xpm_attr.closeness = 30000;
403     xpm_attr.colormap = XCMAP;
404     xpm_attr.visual = XVISUAL;
405     xpm_attr.depth = XDEPTH;
406     xpm_attr.valuemask = (XpmCloseness | XpmColormap |
407 	    XpmVisual | XpmDepth | XpmSize | XpmReturnPixels);
408 
409 
410     /* search environment variables here too */
411     if (NULL == (f = (char*) rxvt_File_find (file, ".xpm", r->h->rs[Rs_path]))
412 #ifdef USE_JPEG
413 	&& NULL == (f = (char*) rxvt_File_find (file, ".jpg", r->h->rs[Rs_path]))
414 	&& NULL == (f = (char*) rxvt_File_find (file, ".jpeg", r->h->rs[Rs_path]))
415 #endif
416 #ifdef USE_PNG
417 	&& NULL == (f = (char*) rxvt_File_find (file, ".png", r->h->rs[Rs_path]))
418 #endif
419 	)   {
420 	char	       *p;
421 	/* semi-colon delimited */
422 	if (NULL == (p = STRCHR(file, ';')))
423 	    p = STRCHR(file, '\0');
424 	rxvt_msg (DBG_ERROR, DBG_PIXMAP, "couldn't load image file \"%.*s\"", (p - file), file);
425 	return None;
426     }
427 
428     flen = STRLEN (f);
429 #ifdef USE_JPEG
430     if ((flen >= 4 && !STRNCASECMP (f+flen-4, ".jpg", 4)) ||
431 	(flen >= 5 && !STRNCASECMP (f+flen-5, ".jpeg",5)))  {
432 	GC	gc = DefaultGC (r->Xdisplay, XSCREEN);
433 	if (!JpegReadFileToPixmap (r->Xdisplay, XROOT, gc, f,
434 	    &pixmap, &w, &h))	{
435 	    *pwidth = w;
436 	    *pheight = h;
437 	}
438     }
439     else
440 #endif
441 #ifdef USE_PNG
442     if (flen >= 4 && !STRNCASECMP (f+flen-4, ".png", 4))    {
443 	GC	gc = DefaultGC (r->Xdisplay, XSCREEN);
444 	if (!PngReadFileToPixmap (r->Xdisplay, XROOT, gc, f,
445 	    &pixmap, &w, &h))	{
446 	    *pwidth = w;
447 	    *pheight = h;
448 	}
449     }
450     else
451 #endif
452 #ifdef HAVE_LIBXPM
453     if (!XpmReadFileToPixmap(r->Xdisplay, XROOT, f,
454 	&pixmap, NULL, &xpm_attr))  {
455 	*pwidth = xpm_attr.width;
456 	*pheight = xpm_attr.height;
457     }
458 #endif
459     {
460 	/* empty to suppress compile error */
461     }
462 
463     rxvt_free(f);
464     if (NOT_PIXMAP(pixmap)) {
465 	char	       *p;
466 	/* semi-colon delimited */
467 	if ((p = STRCHR(file, ';')) == NULL)
468 	p = STRCHR(file, '\0');
469 	rxvt_msg (DBG_ERROR, DBG_PIXMAP, "couldn't load image file \"%.*s\"", (p - file), file);
470     }
471 
472     return  (pixmap);
473 }
474 
475 #endif	/* BACKGROUND_IMAGE */
476 
477 /*----------------------- end-of-file (C source) -----------------------*/
478