gliv-1.0.2
[gliv.git] / gliv.c
blob94013d0d9fcf3b3740c43195cba2589bfa25589a
1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License
4 * as published by the Free Software Foundation; either version 2
5 * of the License, or (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16 * See the COPYING file for license information.
18 * Guillaume Chazarain <booh@altern.org>
21 /***************************************
22 * Main source file. *
23 ***************************************/
25 #include "gliv.h"
27 Display *dpy;
28 GC gc;
29 Window win;
30 gliv_image *im1 = NULL; /* Displayed. */
31 rt_struct rt;
32 char **names;
33 int total = 0;
34 pthread_t thread;
36 static pthread_mutex_t imlib_mutex, ogl_mutex;
38 /***************************************
39 * Locks or unlocks a mutex. *
40 ***************************************/
41 void lock(int value)
43 if (rt.load_requested)
44 return;
46 switch (value) {
47 case LOCK_IMLIB:
48 pthread_mutex_lock(&imlib_mutex);
49 return;
51 case UNLOCK_IMLIB:
52 pthread_mutex_unlock(&imlib_mutex);
53 return;
55 case LOCK_OGL:
56 pthread_mutex_lock(&ogl_mutex);
57 return;
59 case UNLOCK_OGL:
60 pthread_mutex_unlock(&ogl_mutex);
61 return;
65 /***************************************
66 * Changes the imlib_context and *
67 * destroys the given Imlib_Image. *
68 ***************************************/
69 void free_imlib_image(Imlib_Image * im)
71 if (!im)
72 return;
74 lock(LOCK_IMLIB);
75 imlib_context_set_image(im);
76 imlib_free_image();
77 lock(UNLOCK_IMLIB);
80 /***************************************
81 * Frees a gliv_image structure. *
82 ***************************************/
83 void destroy_image(gliv_image * im)
85 if (!im)
86 return;
88 if (rt.verbose)
89 printf("\nUnloading : %s", im->filename);
91 if (im->textures)
92 glDeleteTextures((GLsizei) (im->nb_w * im->nb_h), im->textures);
94 free(im->filename);
95 free(im->textures);
96 free_imlib_image(im->im);
97 free_imlib_image(im->gl_im);
98 free(im);
100 if (rt.verbose)
101 puts(" : done");
104 /***************************************
105 * Shuffles the given array. *
106 ***************************************/
107 static void randomize_array(char **array)
109 char *tmp;
110 int i, r;
112 srandom((unsigned) (time(NULL) + getpid()));
114 for (i = 0; i < total; i++) {
115 tmp = array[i];
116 r = random() % total;
117 array[i] = array[r];
118 array[r] = tmp;
122 /***************************************
123 * Adds a filename to the list. This *
124 *function is only used by ftw when the*
125 * -R flag is given. *
126 ***************************************/
127 static int add_to_list(const char *file, const struct stat *st, int flag)
129 if (flag == FTW_F) {
130 /* It is not a directory, we don't care if it is an image or not. */
131 total++;
132 names = realloc(names, total * sizeof(char *));
133 names[total - 1] = strdup(file);
135 return 0;
138 /***************************************
139 * Recursively adds all files to the *
140 * list by descending directories. The *
141 * image list is the variable 'names'. *
142 ***************************************/
143 static void build_image_list(char **array, unsigned int nb)
145 unsigned int i;
147 for (i = 0; i < nb; i++) {
148 ftw(array[i], add_to_list, 8);
149 free(array[i]);
153 /***************************************
154 * Sets global variables according *
155 * to command-line arguments. *
156 ***************************************/
157 static void getopt_parser(struct gengetopt_args_info *args)
159 if (!args->inputs_num) {
160 cmdline_parser_print_help();
161 exit(1);
164 rt.fullscreen = args->full_screen_flag || args->maximize_flag;
165 rt.verbose = args->verbose_flag;
166 rt.info = args->info_flag;
167 rt.maximize = args->maximize_flag;
169 if (args->recursive_flag) {
170 build_image_list(args->inputs, args->inputs_num);
171 free(args->inputs);
172 } else {
173 total = args->inputs_num;
174 names = args->inputs;
177 if (total < 2)
178 /* Don't use a thread for only one image. */
179 rt.load_requested = 1;
180 else
181 rt.load_requested = args->load_requested_flag;
183 if (args->shuffle_flag)
184 randomize_array(names);
186 if (args->delay_given && args->delay_arg >= 0)
187 rt.delay = args->delay_arg;
188 else
189 rt.delay = 0;
192 /***************************************
193 * "Hides" the cursor by changing it *
194 * to a transparent one. *
195 ***************************************/
196 static void alarm_func(int unused)
198 if (!rt.cursor_hidden)
199 set_transparent_cursor();
202 /***************************************
203 * Frees OpenGL memory and disconnects *
204 * from glX at exit. *
205 ***************************************/
206 static void clean_exit(void)
208 signal(SIGALRM, SIG_IGN);
210 glDeleteTextures((GLsizei) (im1->nb_w * im1->nb_h), im1->textures);
212 if (!rt.load_requested) {
213 pthread_join(thread, (void *) &im1);
214 glDeleteTextures((GLsizei) (im1->nb_w * im1->nb_h), im1->textures);
218 /***************************************
219 * Exits cleanly but acts as if we *
220 * were killed by the received signal. *
221 ***************************************/
222 static void exit_with_signal(int sig)
224 clean_exit();
226 /* Don't intercept the signal once more. */
227 signal(sig, SIG_DFL);
229 /* Sometimes the window stays here, so destroy it. */
230 XDestroyWindow(dpy, win);
231 XFlush(dpy);
233 /* Kill ourselves with the intercepted signal. */
234 raise(sig);
237 /***************************************
238 *Fills run-time fields with predefined*
239 * values or command line arguments. *
240 ***************************************/
241 static void init_rt(int argc, char *argv[])
243 /* Processes command line. */
244 struct gengetopt_args_info *args;
245 args = malloc(sizeof(struct gengetopt_args_info));
246 cmdline_parser(argc, argv, args);
247 getopt_parser(args);
248 free(args);
250 /* Predefined values. */
251 rt.zoom_frame = 0;
252 rt.help = 0;
253 rt.direction = +1;
254 rt.state = STATE_LOADED;
257 /***************************************
258 * Catches signals that would make *
259 * exit badly. *
260 ***************************************/
261 static void install_sig_handlers(void)
263 #ifdef SIGHUP
264 signal(SIGHUP, exit_with_signal);
265 #endif
266 #ifdef SIGINT
267 signal(SIGINT, exit_with_signal);
268 #endif
269 #ifdef SIGQUIT
270 signal(SIGQUIT, exit_with_signal);
271 #endif
272 #ifdef SIGILL
273 signal(SIGILL, exit_with_signal);
274 #endif
275 #ifdef SIGSEGV
276 signal(SIGSEGV, exit_with_signal);
277 #endif
278 #ifdef SIGTERM
279 signal(SIGTERM, exit_with_signal);
280 #endif
281 #ifdef SIGBUS
282 signal(SIGBUS, exit_with_signal);
283 #endif
286 /***************************************
287 * The function. *
288 ***************************************/
289 int main(int argc, char *argv[])
291 XEvent ev;
292 struct timespec time_to_sleep = { tv_sec:0, tv_nsec:1000000 };
294 init_rt(argc, argv);
296 if (rt.verbose)
297 printf("%s %s\n\n", PACKAGE, VERSION);
299 init_glX();
301 atexit(clean_exit);
303 install_sig_handlers();
305 if (rt.delay) {
306 signal(SIGALRM, alarm_func);
307 alarm(rt.delay);
308 rt.cursor_hidden = 0;
311 pthread_mutex_init(&imlib_mutex, NULL);
312 pthread_mutex_init(&ogl_mutex, NULL);
314 imlib_set_cache_size(1024 * 1024);
315 imlib_context_set_color(0, 0, 0, ~0);
317 if (!total || !(im1 = load_next_image(0))) {
318 fputs("Error : no valid images on command line.\n", stderr);
319 exit(1);
322 render();
323 glXWaitGL();
324 XMapWindow(dpy, win);
326 if (!rt.load_requested)
327 threaded_load();
329 for (;;) {
330 if (rt.state == STATE_WAITING)
331 /* Waiting for ClientMessage from the loading thread. */
332 while (!XPending(dpy))
333 nanosleep(&time_to_sleep, NULL);
335 XNextEvent(dpy, &ev);
337 if (process_event(&ev))
338 redraw();
339 else
340 nanosleep(&time_to_sleep, NULL);
343 /* for (;;) never ends but ... */
344 return 0;