]> www.fi.muni.cz Git - evince.git/blob - shell/ev-utils.c
Make printing support optional. Patch from Eduardo de Barros Lima
[evince.git] / shell / ev-utils.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; c-indent-level: 8 -*- */
2 /*
3  *  Copyright (C) 2004 Anders Carlsson <andersca@gnome.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, or (at your option)
8  *  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 #include <config.h>
22
23 #include "ev-utils.h"
24 #include "ev-file-helpers.h"
25 #include <math.h>
26
27 #define PRINT_CONFIG_FILENAME   "ev-print-config.xml"
28
29 typedef struct
30 {
31   int size;
32   double *data;
33 } ConvFilter;
34
35 static double
36 gaussian (double x, double y, double r)
37 {
38     return ((1 / (2 * M_PI * r)) *
39             exp ((- (x * x + y * y)) / (2 * r * r)));
40 }
41
42 static ConvFilter *
43 create_blur_filter (int radius)
44 {
45   ConvFilter *filter;
46   int x, y;
47   double sum;
48   
49   filter = g_new0 (ConvFilter, 1);
50   filter->size = radius * 2 + 1;
51   filter->data = g_new (double, filter->size * filter->size);
52
53   sum = 0.0;
54   
55   for (y = 0 ; y < filter->size; y++)
56     {
57       for (x = 0 ; x < filter->size; x++)
58         {
59           sum += filter->data[y * filter->size + x] = gaussian (x - (filter->size >> 1),
60                                                                 y - (filter->size >> 1),
61                                                                 radius);
62         }
63     }
64
65   for (y = 0; y < filter->size; y++)
66     {
67       for (x = 0; x < filter->size; x++)
68         {
69           filter->data[y * filter->size + x] /= sum;
70         }
71     }
72
73   return filter;
74   
75 }
76
77 static GdkPixbuf *
78 create_shadow (GdkPixbuf *src, int blur_radius,
79                int x_offset, int y_offset, double opacity)
80 {
81   int x, y, i, j;
82   int width, height;
83   GdkPixbuf *dest;
84   static ConvFilter *filter = NULL;
85   int src_rowstride, dest_rowstride;
86   int src_bpp, dest_bpp;
87   
88   guchar *src_pixels, *dest_pixels;
89
90   if (!filter)
91     filter = create_blur_filter (blur_radius);
92
93   if (x_offset < 0)
94           x_offset = (blur_radius * 4) / 5;
95   
96   if (y_offset < 0)
97           y_offset = (blur_radius * 4) / 5;
98
99   
100   width = gdk_pixbuf_get_width (src) + blur_radius * 2 + x_offset;
101   height = gdk_pixbuf_get_height (src) + blur_radius * 2 + y_offset;
102
103   dest = gdk_pixbuf_new (gdk_pixbuf_get_colorspace (src), TRUE,
104                          gdk_pixbuf_get_bits_per_sample (src),
105                          width, height);
106   gdk_pixbuf_fill (dest, 0);  
107   src_pixels = gdk_pixbuf_get_pixels (src);
108   src_rowstride = gdk_pixbuf_get_rowstride (src);
109   src_bpp = gdk_pixbuf_get_has_alpha (src) ? 4 : 3;
110   
111   dest_pixels = gdk_pixbuf_get_pixels (dest);
112   dest_rowstride = gdk_pixbuf_get_rowstride (dest);
113   dest_bpp = gdk_pixbuf_get_has_alpha (dest) ? 4 : 3;
114   
115   for (y = 0; y < height; y++)
116     {
117       for (x = 0; x < width; x++)
118         {
119           int sumr = 0, sumg = 0, sumb = 0, suma = 0;
120
121           for (i = 0; i < filter->size; i++)
122             {
123               for (j = 0; j < filter->size; j++)
124                 {
125                   int src_x, src_y;
126
127                   src_y = -(blur_radius + x_offset) + y - (filter->size >> 1) + i;
128                   src_x = -(blur_radius + y_offset) + x - (filter->size >> 1) + j;
129
130                   if (src_y < 0 || src_y > gdk_pixbuf_get_height (src) ||
131                       src_x < 0 || src_x > gdk_pixbuf_get_width (src))
132                     continue;
133
134                   sumr += src_pixels [src_y * src_rowstride +
135                                       src_x * src_bpp + 0] *
136                     filter->data [i * filter->size + j];
137                   sumg += src_pixels [src_y * src_rowstride +
138                                       src_x * src_bpp + 1] * 
139                     filter->data [i * filter->size + j];
140
141                   sumb += src_pixels [src_y * src_rowstride +
142                                       src_x * src_bpp + 2] * 
143                     filter->data [i * filter->size + j];
144                   
145                   if (src_bpp == 4)
146                     suma += src_pixels [src_y * src_rowstride +
147                                         src_x * src_bpp + 3] *
148                     filter->data [i * filter->size + j];
149                   else
150                           suma += 0xff;
151                     
152                 }
153             }
154
155           if (dest_bpp == 4)
156             dest_pixels [y * dest_rowstride +
157                          x * dest_bpp + 3] = (suma * opacity) / (filter->size * filter->size);
158
159         }
160     }
161   
162   return dest;
163 }
164
165 GdkPixbuf *
166 ev_pixbuf_add_shadow (GdkPixbuf *src, int size,
167                       int x_offset, int y_offset, double opacity)
168 {
169   GdkPixbuf *dest;
170   
171   dest = create_shadow (src, size, x_offset, y_offset, opacity);
172
173   gdk_pixbuf_composite (src, dest,
174                         size, size,
175                         gdk_pixbuf_get_width (src),
176                         gdk_pixbuf_get_height (src),
177                         size, size,
178                         1.0, 1.0,
179                         GDK_INTERP_NEAREST, 255);
180
181   return dest;
182 }
183
184
185 /* Simple function to output the contents of a region.  Used solely for testing
186  * the region code.
187  */
188 void
189 ev_print_region_contents (GdkRegion *region)
190 {
191         GdkRectangle *rectangles = NULL;
192         gint n_rectangles, i;
193
194         if (region == NULL) {
195                 g_print ("<empty region>\n");
196                 return;
197         }
198
199         g_print ("<region %p>\n", region);
200         gdk_region_get_rectangles (region, &rectangles, &n_rectangles);
201         for (i = 0; i < n_rectangles; i++) {
202                 g_print ("\t(%d %d, %d %d) [%dx%d]\n",
203                          rectangles[i].x,
204                          rectangles[i].y,
205                          rectangles[i].x + rectangles[i].width,
206                          rectangles[i].y + rectangles[i].height,
207                          rectangles[i].width,
208                          rectangles[i].height);
209         }
210         g_free (rectangles);
211 }
212
213
214 #ifndef HAVE_G_FILE_SET_CONTENTS
215
216 #include <errno.h>
217 #include <unistd.h>
218 #include <sys/types.h>
219 #include <sys/wait.h>
220 #include <string.h>
221 #include <glib/gstdio.h>
222
223 static gboolean
224 rename_file (const char *old_name,
225              const char *new_name,
226              GError **err)
227 {
228   errno = 0;
229   if (g_rename (old_name, new_name) == -1)
230     {
231       return FALSE;
232     }
233   
234   return TRUE;
235 }
236
237 static gboolean
238 set_umask_permissions (int           fd,
239                        GError      **err)
240 {
241   /* All of this function is just to work around the fact that
242    * there is no way to get the umask without changing it.
243    *
244    * We can't just change-and-reset the umask because that would
245    * lead to a race condition if another thread tried to change
246    * the umask in between the getting and the setting of the umask.
247    * So we have to do the whole thing in a child process.
248    */
249   pid_t pid;
250
251   pid = fork ();
252   
253   if (pid == -1)
254     {
255       return FALSE;
256     }
257   else if (pid == 0)
258     {
259       /* child */
260       mode_t mask = umask (0666);
261
262       errno = 0;
263       if (fchmod (fd, 0666 & ~mask) == -1)
264         _exit (errno);
265       else
266         _exit (0);
267
268       return TRUE; /* To quiet gcc */
269     }
270   else
271     { 
272       /* parent */
273       int status;
274
275       errno = 0;
276       if (waitpid (pid, &status, 0) == -1)
277         {
278           return FALSE;
279         }
280
281       if (WIFEXITED (status))
282         {
283           if (WEXITSTATUS (status) == 0)
284             {
285               return TRUE;
286             }
287           else
288             {
289               return FALSE;
290             }
291         }
292       else if (WIFSIGNALED (status))
293         {
294           return FALSE;
295         }
296       else
297         {
298           return FALSE;
299         }
300     }
301 }
302
303 static gchar *
304 write_to_temp_file (const gchar *contents,
305                     gssize length,
306                     const gchar *template,
307                     GError **err)
308 {
309   gchar *tmp_name;
310   gchar *display_name;
311   gchar *retval;
312   FILE *file;
313   gint fd;
314
315   retval = NULL;
316   
317   tmp_name = g_strdup_printf ("%s.XXXXXX", template);
318
319   errno = 0;
320   fd = g_mkstemp (tmp_name);
321   display_name = g_filename_display_name (tmp_name);
322       
323   if (fd == -1)
324     {
325       goto out;
326     }
327
328   if (!set_umask_permissions (fd, err))
329     {
330       close (fd);
331       g_unlink (tmp_name);
332
333       goto out;
334     }
335   
336   errno = 0;
337   file = fdopen (fd, "wb");
338   if (!file)
339     {
340       close (fd);
341       g_unlink (tmp_name);
342       
343       goto out;
344     }
345
346   if (length > 0)
347     {
348       size_t n_written;
349       
350       errno = 0;
351
352       n_written = fwrite (contents, 1, length, file);
353
354       if (n_written < length)
355         {
356           fclose (file);
357           g_unlink (tmp_name);
358           
359           goto out;
360         }
361     }
362    
363   errno = 0;
364   if (fclose (file) == EOF)
365     { 
366       g_unlink (tmp_name);
367       
368       goto out;
369     }
370
371   retval = g_strdup (tmp_name);
372   
373  out:
374   g_free (tmp_name);
375   g_free (display_name);
376   
377   return retval;
378 }
379
380 static gboolean
381 ev_file_set_contents (const gchar *filename,
382                       const gchar *contents,
383                       gssize         length,
384                       GError       **error)
385 {
386   gchar *tmp_filename;
387   gboolean retval;
388   GError *rename_error = NULL;
389   
390   g_return_val_if_fail (filename != NULL, FALSE);
391   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
392   g_return_val_if_fail (contents != NULL || length == 0, FALSE);
393   g_return_val_if_fail (length >= -1, FALSE);
394   
395   if (length == -1)
396     length = strlen (contents);
397
398   tmp_filename = write_to_temp_file (contents, length, filename, error);
399   
400   if (!tmp_filename)
401     {
402       retval = FALSE;
403       goto out;
404     }
405
406   if (!rename_file (tmp_filename, filename, &rename_error))
407     {
408       g_unlink (tmp_filename);
409       g_propagate_error (error, rename_error);
410       retval = FALSE;
411       goto out;
412     }
413
414   retval = TRUE;
415   
416  out:
417   g_free (tmp_filename);
418   return retval;
419 }
420
421 #endif /* HAVE_G_FILE_SET_CONTENTS */
422
423 #ifdef WITH_GNOME_PRINT
424 gboolean
425 using_pdf_printer (GnomePrintConfig *config)
426 {
427         const guchar *driver;
428
429         driver = gnome_print_config_get (
430                 config, (const guchar *)"Settings.Engine.Backend.Driver");
431
432         if (driver) {
433                 if (!strcmp ((const gchar *)driver, "gnome-print-pdf"))
434                         return TRUE;
435                 else
436                         return FALSE;
437         }
438
439         return FALSE;
440 }
441
442 gboolean
443 using_postscript_printer (GnomePrintConfig *config)
444 {
445         const guchar *driver;
446         const guchar *transport;
447
448         driver = gnome_print_config_get (
449                 config, (const guchar *)"Settings.Engine.Backend.Driver");
450
451         transport = gnome_print_config_get (
452                 config, (const guchar *)"Settings.Transport.Backend");
453
454         if (driver) {
455                 if (!strcmp ((const gchar *)driver, "gnome-print-ps"))
456                         return TRUE;
457                 else
458                         return FALSE;
459         } else  if (transport) { /* these transports default to PostScript */
460                 if (!strcmp ((const gchar *)transport, "CUPS"))
461                         return TRUE;
462                 else if (!strcmp ((const gchar *)transport, "LPD"))
463                         return TRUE;
464         }
465
466         return FALSE;
467 }
468
469 GnomePrintConfig *
470 load_print_config_from_file (void)
471 {
472         GnomePrintConfig *print_config = NULL;
473         char *file_name, *contents = NULL;
474
475         file_name = g_build_filename (ev_dot_dir (), PRINT_CONFIG_FILENAME,
476                                       NULL);
477
478         if (g_file_get_contents (file_name, &contents, NULL, NULL)) {
479                 print_config = gnome_print_config_from_string (contents, 0);
480                 g_free (contents);
481         }
482
483         if (print_config == NULL) {
484                 print_config = gnome_print_config_default ();
485         }
486
487         g_free (file_name);
488
489         return print_config;
490 }
491
492 void
493 save_print_config_to_file (GnomePrintConfig *config)
494 {
495         char *file_name, *str;
496
497         g_return_if_fail (config != NULL);
498
499         str = gnome_print_config_to_string (config, 0);
500         if (str == NULL) return;
501
502         file_name = g_build_filename (ev_dot_dir (),
503                                       PRINT_CONFIG_FILENAME,
504                                       NULL);
505
506 #ifdef HAVE_G_FILE_SET_CONTENTS
507         g_file_set_contents (file_name, str, -1, NULL);
508 #else
509         ev_file_set_contents (file_name, str, -1, NULL);
510 #endif
511
512         g_free (file_name);
513         g_free (str);
514 }
515 #endif /* WITH_GNOME_PRINT */
516
517