1 /*
2 Module : main.c
3 Purpose : GDK/Imlib Quick Image Viewer (qiv)
4 More : see qiv README
5 Homepage : http://qiv.spiegl.de/
6 Original : http://www.klografx.net/qiv/
7 Policy : GNU GPL
8 */
9
10 #include <gdk/gdkx.h>
11 #include <stdio.h>
12 #include <signal.h>
13 #include <sys/time.h>
14 #include <ctype.h>
15 #include <string.h>
16
17 #ifdef HAVE_MAGIC
18 #include <magic.h>
19 #endif
20
21 #include "qiv.h"
22 #include "main.h"
23
24 qiv_image main_img;
25 qiv_mgl magnify_img; /* [lc] */
26
27 static int check_extension(const char *);
28 static void qiv_signal_usr1();
29 static void qiv_signal_usr2();
30 static gboolean qiv_handle_timer(gpointer);
31 static void qiv_timer_restart(gpointer);
32
33 #ifdef HAVE_MAGIC
34 static int check_magic(magic_t cookie, const char *name);
35 #endif
36
main(int argc,char ** argv)37 int main(int argc, char **argv)
38 {
39 struct timeval tv;
40 int i;
41
42 // [as] workaround for problem with X composite extension
43 // is this still needed with imlib2 ??
44 putenv("XLIB_SKIP_ARGB_VISUALS=1");
45
46 /*
47 // [as] thinks that this is not portable enough
48 // [lc]
49 // I use a virtual screen of 1600x1200, and the resolution is 1024x768,
50 // so I changed how screen_[x,y] is obtained; it seems that gtk 1.2
51 // cannot give the geometry of viewport, so I borrowed from the source of
52 // xvidtune the code for calling XF86VidModeGetModeLine, this requires
53 // the linking option -lXxf86vm.
54 XF86VidModeModeLine modeline;
55 int dot_clock;
56 */
57
58 /* Randomize seed for 'true' random */
59 gettimeofday(&tv,NULL);
60 srand(tv.tv_usec*1000000+tv.tv_sec);
61
62 /* Initialize GDK */
63
64 gdk_init(&argc,&argv);
65
66 /* Set up our options, image list, etc */
67 strncpy(select_dir, SELECT_DIR, sizeof select_dir);
68 reset_mod(&main_img);
69
70 options_read(argc, argv, &main_img);
71
72 #ifdef SUPPORT_LCMS
73 /* read profiles if provided */
74 if (cms_transform)
75 {
76 if (source_profile) {
77 h_source_profile = cmsOpenProfileFromFile(source_profile, "r");
78 } else {
79 h_source_profile = cmsCreate_sRGBProfile();
80 }
81
82 if (h_source_profile == NULL)
83 {
84 g_print("qiv: cannot create source color profile.\n");
85 usage(argv[0],1);
86 }
87
88 if (display_profile) {
89 h_display_profile = cmsOpenProfileFromFile(display_profile, "r");
90 } else {
91 h_display_profile = cmsCreate_sRGBProfile();
92 }
93 if (h_display_profile == NULL)
94 {
95 g_print("qiv: cannot create display color profile.\n");
96 usage(argv[0],1);
97 }
98
99 }
100 /* TYPE_BGRA_8 or TYPE_ARGB_8 depending on endianess */
101 h_cms_transform = cmsCreateTransform(h_source_profile,
102 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
103 TYPE_BGRA_8,
104 h_display_profile,
105 TYPE_BGRA_8,
106 #else
107 TYPE_ARGB_8,
108 h_display_profile,
109 TYPE_ARGB_8,
110 #endif
111 INTENT_PERCEPTUAL, 0);
112 #endif
113
114 /* Load things from GDK/Imlib */
115
116 qiv_main_loop = g_main_new(TRUE);
117 cmap = gdk_colormap_get_system();
118 screen_x = gdk_screen_width();
119 screen_y = gdk_screen_height();
120
121 screen = gdk_screen_get_default();
122 num_monitors = gdk_screen_get_n_monitors(screen);
123 monitor = malloc( num_monitors * sizeof(GdkRectangle));
124 for(i=0; i< num_monitors ; i++)
125 {
126 gdk_screen_get_monitor_geometry(screen, i, &monitor[i]);
127 }
128
129 if(user_screen < num_monitors)
130 {
131 main_img.mon_id = user_screen;
132 }
133
134 /* statusbar with pango */
135 layout = pango_layout_new(gdk_pango_context_get());
136 fontdesc = pango_font_description_from_string (STATUSBAR_FONT);
137
138 /* set fontsize to 8 if no fontsize is given */
139 if(!pango_font_description_get_size(fontdesc))
140 {
141 pango_font_description_set_size(fontdesc, PANGO_SCALE * STATUSBAR_FS);
142 }
143 metrics = pango_context_get_metrics (gdk_pango_context_get(), fontdesc, NULL);
144 pango_layout_set_font_description (layout, fontdesc);
145
146 /* jpeg comment with pango */
147 layoutComment = pango_layout_new(gdk_pango_context_get());
148 fontdescComment = pango_font_description_from_string (COMMENT_FONT);
149
150 /* set fontsize to 8 if no fontsize is given */
151 if(!pango_font_description_get_size(fontdescComment))
152 {
153 pango_font_description_set_size(fontdescComment, PANGO_SCALE * COMMENT_FS);
154 }
155 metricsComment = pango_context_get_metrics (gdk_pango_context_get(), fontdescComment, NULL);
156 pango_layout_set_font_description (layoutComment, fontdescComment);
157
158 max_rand_num = images;
159
160 if (!images) { /* No images to display */
161 g_print("qiv: cannot load any images.\n");
162 usage(argv[0],1);
163 }
164
165 /* get colors */
166
167 color_alloc(STATUSBAR_BG, &text_bg);
168 color_alloc(ERROR_BG, &error_bg);
169 color_alloc(COMMENT_BG, &comment_bg);
170 color_alloc(image_bg_spec, &image_bg);
171
172 /* Display first image first, except in random mode */
173
174 if (random_order)
175 next_image(0);
176
177 //disabled because 'params' is never used, see above
178 //if (to_root || to_root_t || to_root_s) {
179 // params.flags |= PARAMS_VISUALID;
180 // (GdkVisual*)params.visualid = gdk_window_get_visual(GDK_ROOT_PARENT());
181 //}
182
183 /* Setup callbacks */
184
185 gdk_event_handler_set(qiv_handle_event, &main_img, NULL);
186 qiv_timer_restart(NULL);
187
188 /* And signal catchers */
189
190 signal(SIGTERM, finish);
191 signal(SIGINT, finish);
192 signal(SIGUSR1, qiv_signal_usr1);
193 signal(SIGUSR2, qiv_signal_usr2);
194
195 /* check for DPMS capability and disable it if slideshow
196 was started from command options */
197 dpms_check();
198 if(slide){
199 dpms_disable();
200 }
201
202
203 /* Load & display the first image */
204
205 qiv_load_image(&main_img);
206
207 if(watch_file){
208 g_timeout_add_full(G_PRIORITY_DEFAULT_IDLE, 100, qiv_watch_file, &main_img, NULL);
209 }
210
211 g_main_run(qiv_main_loop); /* will never return */
212 return 0;
213 }
214
215
qiv_exit(int code)216 void qiv_exit(int code)
217 {
218 if (cmap) gdk_colormap_unref(cmap);
219 destroy_image(&main_img);
220 dpms_enable();
221
222 pango_font_description_free (fontdesc);
223 g_object_unref (layout);
224 pango_font_metrics_unref(metrics);
225
226 g_main_destroy(qiv_main_loop);
227 finish(SIGTERM); /* deprecated, subject to change */
228 }
229
230
231 /*
232 * functions for handling signals
233 */
234
qiv_signal_usr1()235 static void qiv_signal_usr1()
236 {
237 next_image(1);
238 qiv_load_image(&main_img);
239 }
240
qiv_signal_usr2()241 static void qiv_signal_usr2()
242 {
243 next_image(-1);
244 qiv_load_image(&main_img);
245 }
246
247
248 /*
249 * Slideshow timer function
250 *
251 * If this function returns false, the timer is destroyed
252 * and qiv_timer_restart() is automatically called, which
253 * then starts the timer again. Thus images which takes some
254 * time to load will still be displayed for "delay" seconds.
255 */
256
qiv_handle_timer(gpointer data)257 static gboolean qiv_handle_timer(gpointer data)
258 {
259 if (*(int *)data || slide) {
260 next_image(0);
261 /* disable screensaver during slideshow */
262 XResetScreenSaver(GDK_DISPLAY());
263 qiv_load_image(&main_img);
264 }
265 return FALSE;
266 }
267
268
269 /*
270 * Slideshow timer (re)start function
271 */
272
qiv_timer_restart(gpointer dummy)273 static void qiv_timer_restart(gpointer dummy)
274 {
275 g_timeout_add_full(G_PRIORITY_DEFAULT_IDLE, delay,
276 qiv_handle_timer, &slide,
277 qiv_timer_restart);
278 }
279
280 /* Filter images by extension */
281
filter_images(int * images,char ** image_names)282 void filter_images(int *images, char **image_names)
283 {
284 int i = 0;
285 #ifdef HAVE_MAGIC
286 magic_t cookie;
287
288 cookie = magic_open(MAGIC_SYMLINK);
289 magic_load(cookie,NULL);
290 #endif
291
292 while(i < *images) {
293 if (check_extension(image_names[i])
294 #ifdef HAVE_MAGIC
295 || check_magic(cookie, image_names[i])
296 #endif
297 ) {
298 i++;
299 } else {
300 int j = i;
301 if (j < *images-1)
302 image_idx--;
303 while(j < *images-1) {
304 image_names[j] = image_names[j+1];
305 ++j;
306 }
307 --(*images);
308 }
309 }
310 #ifdef HAVE_MAGIC
311 magic_close(cookie);
312 #endif
313 if (image_idx < 0)
314 image_idx = 0;
315 }
316
check_extension(const char * name)317 static int check_extension(const char *name)
318 {
319 char *extn = strrchr(name, '.');
320 int i;
321
322 if (extn)
323 for (i=0; image_extensions[i]; i++)
324 if (strcasecmp(extn, image_extensions[i]) == 0)
325 return 1;
326
327 return 0;
328 }
329
330 #ifdef HAVE_MAGIC
check_magic(magic_t cookie,const char * name)331 static int check_magic(magic_t cookie, const char *name)
332 {
333 const char *description=NULL;
334 int i;
335 int ret=0;
336
337 description = magic_file(cookie, name);
338 if(description)
339 {
340 for(i=0; image_magic[i]; i++ )
341 if (strncasecmp(description, image_magic[i], strlen(image_magic[i])) == 0)
342 {
343 ret = 1;
344 break;
345 }
346 }
347 return ret;
348 }
349 #endif
350