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