1 /* Skippy - Seduces Kids Into Perversion
2  *
3  * Copyright (C) 2004 Hyriand <hyriand@thegraveyard.org>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19 
20 /**
21  * @file skippy.h
22  *
23  * @brief Global header.
24  */
25 
26 #ifndef SKIPPY_H
27 #define SKIPPY_H
28 
29 #define BUF_LEN 128
30 
31 #define _GNU_SOURCE
32 
33 #include <stdbool.h>
34 #include <strings.h>
35 #include <assert.h>
36 
37 #include <X11/Xlib.h>
38 #include <X11/Xmd.h>
39 #include <X11/Xatom.h>
40 #include <X11/Xft/Xft.h>
41 
42 #include <X11/extensions/Xrender.h>
43 #include <X11/extensions/Xcomposite.h>
44 #include <X11/extensions/Xdamage.h>
45 #include <X11/extensions/Xfixes.h>
46 #include <X11/extensions/shape.h>
47 
48 #ifdef CFG_XINERAMA
49 # include <X11/extensions/Xinerama.h>
50 #endif
51 
52 #include <sys/types.h>
53 #include <sys/time.h>
54 #include <sys/poll.h>
55 #include <stdio.h>
56 #include <stdlib.h>
57 #include <math.h>
58 #include <unistd.h>
59 #include <time.h>
60 #include <string.h>
61 #include <inttypes.h>
62 #include <ctype.h>
63 
64 #include "dlist.h"
65 
66 #define MAX_MOUSE_BUTTONS 4
67 
68 /**
69  * @brief Dump raw bytes in HEX format.
70  *
71  * @param data pointer to raw data
72  * @param len length of data
73  */
74 static inline void
hexdump(const char * data,int len)75 hexdump(const char *data, int len) {
76   static const int BYTE_PER_LN = 16;
77 
78   if (len <= 0)
79     return;
80 
81   // Print header
82   printf("%10s:", "Offset");
83   for (int i = 0; i < BYTE_PER_LN; ++i)
84     printf(" %2d", i);
85   putchar('\n');
86 
87   // Dump content
88   for (int offset = 0; offset < len; ++offset) {
89     if (!(offset % BYTE_PER_LN))
90       printf("0x%08x:", offset);
91 
92     printf(" %02hhx", data[offset]);
93 
94     if ((BYTE_PER_LN - 1) == offset % BYTE_PER_LN)
95       putchar('\n');
96   }
97   if (len % BYTE_PER_LN)
98     putchar('\n');
99 
100   fflush(stdout);
101 }
102 
103 /// @brief Possible return values.
104 enum {
105 	RET_SUCCESS = 0,
106 	RET_UNKNOWN,
107 	RET_BADARG,
108 	RET_XFAIL,
109 	RET_BADALLOC,
110 };
111 
112 enum progmode {
113 	PROGMODE_NORMAL,
114 	PROGMODE_ACTV_PICKER,
115 	PROGMODE_DEACTV_PICKER,
116 	PROGMODE_TOGGLE_PICKER,
117 	PROGMODE_DM_STOP,
118 };
119 
120 enum cliop {
121 	CLIENTOP_NO,
122 	CLIENTOP_FOCUS,
123 	CLIENTOP_ICONIFY,
124 	CLIENTOP_SHADE_EWMH,
125 	CLIENTOP_CLOSE_ICCCM,
126 	CLIENTOP_CLOSE_EWMH,
127 	CLIENTOP_DESTROY,
128 };
129 
130 enum align {
131 	ALIGN_LEFT,
132 	ALIGN_MID,
133 	ALIGN_RIGHT,
134 };
135 
136 enum buttons {
137 	BUTN_CLOSE,
138 	BUTN_MINIMIZE,
139 	BUTN_SHADE,
140 	NUM_BUTN,
141 };
142 
143 enum pict_posp_mode {
144 	PICTPOSP_ORIG,
145 	PICTPOSP_SCALE,
146 	PICTPOSP_SCALEK,
147 	PICTPOSP_SCALEE,
148 	PICTPOSP_SCALEEK,
149 	PICTPOSP_TILE,
150 };
151 
152 typedef enum {
153 	WMPSN_NONE,
154 	WMPSN_EWMH,
155 	WMPSN_GNOME,
156 } wmpsn_t;
157 
158 typedef struct {
159 	Pixmap pxmap;
160 	Picture pict;
161 	int height;
162 	int width;
163 	int depth;
164 } pictw_t;
165 
166 typedef struct {
167 	char *path;
168 	pictw_t *img;
169 	enum pict_posp_mode mode;
170 	int twidth;
171 	int theight;
172 	enum align alg;
173 	enum align valg;
174 	XRenderColor c;
175 } pictspec_t;
176 
177 #define PICTSPECT_INIT { \
178 	.path = NULL, \
179 }
180 
181 typedef struct {
182 	unsigned int key;
183 	enum {
184 		KEYMOD_CTRL = 1 << 0,
185 		KEYMOD_SHIFT = 1 << 1,
186 		KEYMOD_META = 1 << 2,
187 	} mod;
188 } keydef_t;
189 
190 typedef enum {
191 	CLIDISP_NONE,
192 	CLIDISP_FILLED,
193 	CLIDISP_ICON,
194 	CLIDISP_THUMBNAIL,
195 	CLIDISP_THUMBNAIL_ICON,
196 } client_disp_mode_t;
197 
198 /// @brief Option structure.
199 typedef struct {
200 	char *config_path;
201 	enum progmode mode;
202 	bool runAsDaemon;
203 	bool synchronize;
204 
205 	int distance;
206 	bool useNetWMFullscreen;
207 	bool ignoreSkipTaskbar;
208 	bool acceptOvRedir;
209 	bool acceptWMWin;
210 	double updateFreq;
211 	bool lazyTrans;
212 	bool useNameWindowPixmap;
213 	bool forceNameWindowPixmap;
214 	bool includeFrame;
215 	char *pipePath;
216 	bool movePointerOnStart;
217 	bool movePointerOnSelect;
218 	bool movePointerOnRaise;
219 	bool switchDesktopOnActivate;
220 	bool allowUpscale;
221 	bool includeAllScreens;
222 	bool avoidThumbnailsFromOtherScreens;
223 	bool showAllDesktops;
224 	bool showUnmapped;
225 	int preferredIconSize;
226 	client_disp_mode_t *clientDisplayModes;
227 	pictspec_t iconFillSpec;
228 	pictw_t *iconDefault;
229 	pictspec_t fillSpec;
230 	char *buttonImgs[NUM_BUTN];
231 	pictw_t *background;
232 
233 	bool xinerama_showAll;
234 
235 	char *normal_tint;
236 	int normal_tintOpacity;
237 	int normal_opacity;
238 
239 	char *highlight_tint;
240 	int highlight_tintOpacity;
241 	int highlight_opacity;
242 
243 	bool tooltip_show;
244 	bool tooltip_followsMouse;
245 	int tooltip_offsetX;
246 	int tooltip_offsetY;
247 	enum align tooltip_align;
248 	char *tooltip_border;
249 	char *tooltip_background;
250 	int tooltip_opacity;
251 	char *tooltip_text;
252 	char *tooltip_textShadow;
253 	char *tooltip_font;
254 
255 	enum cliop bindings_miwMouse[MAX_MOUSE_BUTTONS];
256 } options_t;
257 
258 #define OPTIONST_INIT { \
259 	.config_path = NULL, \
260 	.mode = PROGMODE_NORMAL, \
261 	.runAsDaemon = false, \
262 	.synchronize = false, \
263 \
264 	.distance = 50, \
265 	.useNetWMFullscreen = true, \
266 	.ignoreSkipTaskbar = false, \
267 	.acceptOvRedir = false, \
268 	.acceptWMWin = false, \
269 	.updateFreq = 10.0, \
270 	.lazyTrans = false, \
271 	.useNameWindowPixmap = false, \
272 	.forceNameWindowPixmap = false, \
273 	.includeFrame = false, \
274 	.pipePath = NULL, \
275 	.movePointerOnStart = true, \
276 	.movePointerOnSelect = true, \
277 	.movePointerOnRaise = true, \
278 	.switchDesktopOnActivate = false, \
279 	.allowUpscale = true, \
280 	.includeAllScreens = false, \
281 	.avoidThumbnailsFromOtherScreens = true, \
282 	.preferredIconSize = 48, \
283 	.clientDisplayModes = NULL, \
284 	.iconFillSpec = PICTSPECT_INIT, \
285 	.fillSpec = PICTSPECT_INIT, \
286 	.showAllDesktops = false, \
287 	.showUnmapped = true, \
288 	.buttonImgs = { NULL }, \
289 	.background = NULL, \
290 	.xinerama_showAll = true, \
291 	.normal_tint = NULL, \
292 	.normal_tintOpacity = 0, \
293 	.normal_opacity = 200, \
294 	.highlight_tint = NULL, \
295 	.highlight_tintOpacity = 64, \
296 	.highlight_opacity = 255, \
297 	.tooltip_show = true, \
298 	.tooltip_followsMouse = true, \
299 	.tooltip_offsetX = 20, \
300 	.tooltip_offsetY = 20, \
301 	.tooltip_align = ALIGN_LEFT, \
302 	.tooltip_border = NULL, \
303 	.tooltip_background = NULL, \
304 	.tooltip_opacity = 128, \
305 	.tooltip_text = NULL, \
306 	.tooltip_textShadow = NULL, \
307 	.tooltip_font = NULL, \
308 }
309 
310 /// @brief X information structure.
311 typedef struct {
312 	int damage_ev_base;
313 	int damage_err_base;
314 	int composite_ev_base;
315 	int composite_err_base;
316 	int render_ev_base;
317 	int render_err_base;
318 	int fixes_ev_base;
319 	int fixes_err_base;
320 
321 	bool xinerama_exist;
322 	int xinerama_err_base;
323 	int xinerama_ev_base;
324 } xinfo_t;
325 
326 #define XINFOT_INIT { \
327 	.xinerama_exist = false, \
328 }
329 
330 typedef struct _clientwin_t ClientWin;
331 typedef struct _mainwin_t MainWin;
332 
333 /// @brief Session global info structure.
334 typedef struct {
335 	/// @brief Program options.
336 	options_t o;
337 	/// @brief X display.
338 	Display *dpy;
339 	/// @brief Current screen.
340 	int screen;
341 	/// @brief Root window ID.
342 	Window root;
343 	/// @brief Information about X.
344 	xinfo_t xinfo;
345 	/// @brief Time the program was started, in milliseconds.
346 	struct timeval time_start;
347 	/// @brief WM personality.
348 	wmpsn_t wmpsn;
349 	/// @brief Whether we have EWMH fullscreen support.
350 	bool has_ewmh_fullscreen;
351 	/// @brief ARGB visual of the current screen.
352 	Visual *argb_visual;
353 	/// @brief File descriptor of command pipe, in daemon mode.
354 	int fd_pipe;
355 	/// @brief Main window.
356 	MainWin *mainwin;
357 } session_t;
358 
359 #define SESSIONT_INIT { \
360 	.o = OPTIONST_INIT, \
361 	.xinfo = XINFOT_INIT, \
362 	.time_start = { .tv_sec = 0, .tv_usec = 0 }, \
363 	.fd_pipe = -1, \
364 }
365 
366 /// @brief Print out a debug message.
367 #define printfd(format, ...) \
368   (fprintf(stdout, format "\n", ## __VA_ARGS__), fflush(stdout))
369 
370 /// @brief Print out a debug message with function name.
371 #define printfdf(format, ...) \
372   (fprintf(stdout, "%s" format "\n", __func__, ## __VA_ARGS__), fflush(stdout))
373 
374 /// @brief Print out an error message.
375 #define printfe(format, ...) \
376   (fprintf(stderr, format "\n", ## __VA_ARGS__), fflush(stderr))
377 
378 /// @brief Print out an error message with function name.
379 #define printfef(format, ...) \
380   printfe("%s" format, __func__, ## __VA_ARGS__)
381 
382 /// @brief Return a value if it's true.
383 #define retif(x) do { if (x) return (x); } while (0)
384 
385 /// @brief Wrapper for gcc branch prediction builtin, for likely branch.
386 #define likely(x)    __builtin_expect(!!(x), 1)
387 /// @brief Wrapper for gcc branch prediction builtin, for unlikely branch.
388 #define unlikely(x)  __builtin_expect(!!(x), 0)
389 
390 /**
391  * @brief Quit with RETV_BADALLOC if the passed-in pointer is empty.
392  */
393 static inline void *
allocchk_(void * ptr,const char * func_name)394 allocchk_(void *ptr, const char *func_name) {
395   if (unlikely(!ptr)) {
396     printfe("%s(): Failed to allocate memory.", func_name);
397 	exit(RET_BADALLOC);
398   }
399 
400   return ptr;
401 }
402 
403 /// @brief Wrapper of allocchk_().
404 #define allocchk(ptr) allocchk_(ptr, __func__)
405 
406 /// @brief Wrapper of malloc().
407 #define smalloc(nmemb, type) ((type *) allocchk(malloc((nmemb) * sizeof(type))))
408 
409 /// @brief Wrapper of calloc().
410 #define scalloc(nmemb, type) ((type *) allocchk(calloc((nmemb), sizeof(type))))
411 
412 /// @brief Wrapper of ralloc().
413 #define srealloc(ptr, nmemb, type) ((type *) allocchk(realloc((ptr), (nmemb) * sizeof(type))))
414 
415 /// @brief Return the case string.
416 /// Use #s here to prevent macro expansion
417 #define CASESTRRET(s)   case s: return #s
418 
419 /// @brief Return number of elements in a constant array.
420 #define CARR_LEN(a) sizeof(a) / sizeof(a[0])
421 
422 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
423 #define MIN(a,b) (((a) > (b)) ? (b) : (a))
424 
425 #define foreach_dlist_vn(itervar, l) \
426 	for (dlist *(itervar) = dlist_first(l); (itervar); (itervar) = (itervar)->next)
427 #define foreach_dlist(l) foreach_dlist_vn(iter, l)
428 #define REDUCE(statement, l) \
429 	do { \
430 		foreach_dlist(l) \
431 			statement; \
432 	} while (0)
433 
434 /**
435  * @brief Get current time, in milliseconds.
436  */
437 static inline long
time_in_millis(void)438 time_in_millis(void) {
439 	struct timeval tp;
440 
441 	gettimeofday(&tp, NULL);
442 
443 	return (tp.tv_sec * 1000) + (tp.tv_usec / 1000);
444 }
445 
446 /**
447  * @brief Subtracting two struct timeval values.
448  *
449  * Taken from glibc manual.
450  *
451  * Subtract the `struct timeval' values X and Y,
452  * storing the result in RESULT.
453  * Return 1 if the difference is negative, otherwise 0.
454  */
455 static inline int
timeval_subtract(struct timeval * result,struct timeval * x,struct timeval * y)456 timeval_subtract(struct timeval *result,
457 		struct timeval *x, struct timeval *y) {
458 	// Perform the carry for the later subtraction by updating y
459 	if (x->tv_usec < y->tv_usec) {
460 		long nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
461 		y->tv_usec -= 1000000 * nsec;
462 		y->tv_sec += nsec;
463 	}
464 
465 	if (x->tv_usec - y->tv_usec > 1000000) {
466 		long nsec = (x->tv_usec - y->tv_usec) / 1000000;
467 		y->tv_usec += 1000000 * nsec;
468 		y->tv_sec -= nsec;
469 	}
470 
471 	// Compute the time remaining to wait.
472 	// tv_usec is certainly positive.
473 	result->tv_sec = x->tv_sec - y->tv_sec;
474 	result->tv_usec = x->tv_usec - y->tv_usec;
475 
476 	// Return 1 if result is negative.
477 	return x->tv_sec < y->tv_sec;
478 }
479 
480 /**
481  * @brief Print time passed since program starts execution.
482  */
483 static inline void
print_timestamp(session_t * ps)484 print_timestamp(session_t *ps) {
485 	struct timeval tm, diff;
486 
487 	if (gettimeofday(&tm, NULL)) return;
488 
489 	timeval_subtract(&diff, &tm, &ps->time_start);
490 
491 	printf("[ %5ld.%02ld ] ", diff.tv_sec, diff.tv_usec / 10000);
492 }
493 
494 /**
495  * @brief Allocate the space and copy some data.
496  */
497 static inline unsigned char *
mmemcpy(const unsigned char * data,int len)498 mmemcpy(const unsigned char *data, int len) {
499 	unsigned char *d = smalloc(len, unsigned char);
500 	memcpy(d, data, len);
501 	return d;
502 }
503 
504 /**
505  * @brief Allocate the space and join two strings.
506  */
507 static inline char *
mstrjoin(const char * src1,const char * src2)508 mstrjoin(const char *src1, const char *src2) {
509   char *str = allocchk(calloc((strlen(src1) + strlen(src2) + 1), sizeof(char)));
510 
511   strcpy(str, src1);
512   strcat(str, src2);
513 
514   return str;
515 }
516 
517 /**
518  * @brief Allocate the space and join two strings;
519  */
520 static inline char *
mstrjoin3(const char * src1,const char * src2,const char * src3)521 mstrjoin3(const char *src1, const char *src2, const char *src3) {
522   char *str = allocchk(calloc((strlen(src1) + strlen(src2)
523         + strlen(src3) + 1), sizeof(char)));
524 
525   strcpy(str, src1);
526   strcat(str, src2);
527   strcat(str, src3);
528 
529   return str;
530 }
531 
532 /**
533  * @brief Wrapper of strdup().
534  */
535 static inline char *
mstrdup(const char * src)536 mstrdup(const char *src) {
537 	return allocchk(strdup(src));
538 }
539 
540 /**
541  * @brief Copy a number of characters to a newly allocated string.
542  */
543 static inline char *
mstrncpy(const char * src,unsigned len)544 mstrncpy(const char *src, unsigned len) {
545 	char *str = allocchk(malloc(sizeof(char) * (len + 1)));
546 	strncpy(str, src, len);
547 	str[len] = '\0';
548 
549 	return str;
550 }
551 
552 /**
553  * @brief Copy and place a string to somewhere.
554  */
555 static inline void
strplace(char ** dst,const char * src)556 strplace(char **dst, const char *src) {
557 	free(*dst);
558 	*dst = mstrdup(src);
559 }
560 
561 /**
562  * @brief Check if a character symbolizes end of a word.
563  */
564 static inline bool
isspace0(char c)565 isspace0(char c) {
566 	return !c || isspace(c);
567 }
568 
569 /**
570  * @brief Check if a string ends with something, ignore case.
571  */
572 static inline bool
str_endwith(const char * haystick,const char * needle)573 str_endwith(const char *haystick, const char *needle) {
574 	int haystick_len = strlen(haystick);
575 	int needle_len = strlen(needle);
576 	return haystick_len >= needle_len
577 		&& !strcasecmp(haystick + haystick_len - needle_len, needle);
578 }
579 
580 /**
581  * @brief Check if a string starts with some words.
582  */
583 static inline bool
str_startswithword(const char * haystick,const char * needle)584 str_startswithword(const char *haystick, const char *needle) {
585 	const int needle_len = strlen(needle);
586 	return !strncmp(haystick, needle, needle_len)
587 		&& isspace0(haystick[needle_len]);
588 }
589 
590 /**
591  * @brief Check if a string starts with some words, ignore case.
592  */
593 static inline bool
str_startswithwordi(const char * haystick,const char * needle)594 str_startswithwordi(const char *haystick, const char *needle) {
595 	const int needle_len = strlen(needle);
596 	return !strncasecmp(haystick, needle, needle_len)
597 		&& isspace0(haystick[needle_len]);
598 }
599 
600 /**
601  * @brief Get first word.
602  *
603  * @param dest place to store pointer to a copy of the first word
604  * @return start of next word
605  */
606 static inline const char *
str_get_word(const char * s,char ** dest)607 str_get_word(const char *s, char **dest) {
608 	*dest = NULL;
609 	int i = 0;
610 	while (isspace(s[i])) ++i;
611 	int start = i;
612 	while (!isspace0(s[i])) ++i;
613 	if (i - start)
614 		*dest = mstrncpy(s + start, i - start);
615 	while (isspace(s[i])) ++i;
616 	if (!s[i]) return NULL;
617 	return &s[i];
618 }
619 
620 /**
621  * @brief Destroy a <code>Pixmap</code>.
622  */
623 static inline void
free_pixmap(session_t * ps,Pixmap * p)624 free_pixmap(session_t *ps, Pixmap *p) {
625 	if (*p) {
626 		XFreePixmap(ps->dpy, *p);
627 		*p = None;
628 	}
629 }
630 
631 /**
632  * @brief Destroy a <code>Picture</code>.
633  */
634 static inline void
free_picture(session_t * ps,Picture * p)635 free_picture(session_t *ps, Picture *p) {
636 	if (*p) {
637 		XRenderFreePicture(ps->dpy, *p);
638 		*p = None;
639 	}
640 }
641 
642 /**
643  * @brief Destroy a <code>Damage</code>.
644  */
645 static inline void
free_damage(session_t * ps,Damage * p)646 free_damage(session_t *ps, Damage *p) {
647 	if (*p) {
648 		// BadDamage will be thrown if the window is destroyed
649 		XDamageDestroy(ps->dpy, *p);
650 		*p = None;
651 	}
652 }
653 
654 /**
655  * @brief Destroy a <code>XserverRegion</code>.
656  */
657 static inline void
free_region(session_t * ps,XserverRegion * p)658 free_region(session_t *ps, XserverRegion *p) {
659 	if (*p) {
660 		XFixesDestroyRegion(ps->dpy, *p);
661 		*p = None;
662 	}
663 }
664 
665 static inline unsigned short
alphaconv(int alpha)666 alphaconv(int alpha) {
667 	return MIN(alpha * 256, 65535);
668 }
669 
670 /**
671  * @brief Wrapper of XFree() for convenience.
672  *
673  * Because a NULL pointer cannot be passed to XFree(), its man page says.
674  */
675 static inline void
sxfree(void * data)676 sxfree(void *data) {
677   if (data)
678     XFree(data);
679 }
680 
681 /**
682  * @brief Wrapper to sxfree() to turn the pointer NULL as well.
683  */
684 static inline void
spxfree(void * data)685 spxfree(void *data) {
686 	sxfree(*(void **) data);
687 	*(void **) data = NULL;
688 }
689 
690 /**
691  * @brief Checks if a key event matches particular key and modifier
692  * combination.
693  */
694 static inline bool
ev_iskey(XKeyEvent * ev,const keydef_t * k)695 ev_iskey(XKeyEvent *ev, const keydef_t *k) {
696 	unsigned int mask = 0;
697 	if (KEYMOD_CTRL & k->mod) mask |= ControlMask;
698 	if (KEYMOD_SHIFT & k->mod) mask |= ShiftMask;
699 	if (KEYMOD_META & k->mod) mask |= Mod1Mask;
700 	return k->key == ev->keycode
701 		&& (ev->state & (ControlMask | ShiftMask | Mod1Mask)) == mask;
702 }
703 
704 /**
705  * @brief Return a string representation for the keycode in a KeyEvent.
706  */
707 static inline const char *
ev_key_str(XKeyEvent * ev)708 ev_key_str(XKeyEvent *ev) {
709 	return XKeysymToString(XLookupKeysym(ev, 0));
710 }
711 
712 #define report_key_ignored(ev) \
713 	printfef("(): KeyRelease %u (%s) ignored.", (ev)->xkey.keycode, \
714 			ev_key_str(&(ev)->xkey))
715 
716 #define report_key_unbinded(ev) \
717 	printfef("(): KeyRelease %u (%s) not binded to anything.", \
718 			(ev)->xkey.keycode, ev_key_str(&(ev)->xkey))
719 
720 #include "img.h"
721 #include "wm.h"
722 #include "mainwin.h"
723 #include "clientwin.h"
724 #include "layout.h"
725 #include "focus.h"
726 #include "config.h"
727 #include "tooltip.h"
728 #include "img-xlib.h"
729 #ifdef CFG_LIBPNG
730 // FreeType uses setjmp.h and libpng-1.2 feels crazy about this...
731 #define PNG_SKIP_SETJMP_CHECK 1
732 #include "img-png.h"
733 #endif
734 #ifdef CFG_JPEG
735 #include "img-jpeg.h"
736 #endif
737 #ifdef CFG_GIFLIB
738 #include "img-gif.h"
739 #endif
740 
741 extern session_t *ps_g;
742 
743 #endif /* SKIPPY_H */
744