Fix inconsistent #include style
[profile/ivi/weston.git] / clients / image.c
1 /*
2  * Copyright © 2008 Kristian Høgsberg
3  * Copyright © 2009 Chris Wilson
4  *
5  * Permission to use, copy, modify, distribute, and sell this software and its
6  * documentation for any purpose is hereby granted without fee, provided that
7  * the above copyright notice appear in all copies and that both that copyright
8  * notice and this permission notice appear in supporting documentation, and
9  * that the name of the copyright holders not be used in advertising or
10  * publicity pertaining to distribution of the software without specific,
11  * written prior permission.  The copyright holders make no representations
12  * about the suitability of this software for any purpose.  It is provided "as
13  * is" without express or implied warranty.
14  *
15  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
17  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
19  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
20  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
21  * OF THIS SOFTWARE.
22  */
23
24 #include <stdint.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <fcntl.h>
29 #include <unistd.h>
30 #include <math.h>
31 #include <time.h>
32 #include <cairo.h>
33 #include <glib.h>
34 #include <gdk-pixbuf/gdk-pixbuf.h>
35
36 #include <wayland-client.h>
37
38 #include "window.h"
39
40 struct image {
41         struct window *window;
42         struct display *display;
43         uint32_t key;
44         gchar *filename;
45 };
46
47 static void
48 set_source_pixbuf(cairo_t         *cr,
49                   const GdkPixbuf *pixbuf,
50                   double           src_x,
51                   double           src_y,
52                   double           src_width,
53                   double           src_height)
54 {
55         gint width = gdk_pixbuf_get_width (pixbuf);
56         gint height = gdk_pixbuf_get_height (pixbuf);
57         guchar *gdk_pixels = gdk_pixbuf_get_pixels (pixbuf);
58         int gdk_rowstride = gdk_pixbuf_get_rowstride (pixbuf);
59         int n_channels = gdk_pixbuf_get_n_channels (pixbuf);
60         int cairo_stride;
61         guchar *cairo_pixels;
62         cairo_format_t format;
63         cairo_surface_t *surface;
64         int j;
65
66         if (n_channels == 3)
67                 format = CAIRO_FORMAT_RGB24;
68         else
69                 format = CAIRO_FORMAT_ARGB32;
70
71         surface = cairo_image_surface_create(format, width, height);
72         if (cairo_surface_status(surface)) {
73                 cairo_set_source_surface(cr, surface, 0, 0);
74                 return;
75         }
76
77         cairo_stride = cairo_image_surface_get_stride(surface);
78         cairo_pixels = cairo_image_surface_get_data(surface);
79
80         for (j = height; j; j--) {
81                 guchar *p = gdk_pixels;
82                 guchar *q = cairo_pixels;
83
84                 if (n_channels == 3) {
85                         guchar *end = p + 3 * width;
86
87                         while (p < end) {
88 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
89                                 q[0] = p[2];
90                                 q[1] = p[1];
91                                 q[2] = p[0];
92 #else
93                                 q[1] = p[0];
94                                 q[2] = p[1];
95                                 q[3] = p[2];
96 #endif
97                                 p += 3;
98                                 q += 4;
99                         }
100                 } else {
101                         guchar *end = p + 4 * width;
102                         guint t1,t2,t3;
103
104 #define MULT(d,c,a,t) G_STMT_START { t = c * a + 0x7f; d = ((t >> 8) + t) >> 8; } G_STMT_END
105
106                         while (p < end) {
107 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
108                                 MULT(q[0], p[2], p[3], t1);
109                                 MULT(q[1], p[1], p[3], t2);
110                                 MULT(q[2], p[0], p[3], t3);
111                                 q[3] = p[3];
112 #else
113                                 q[0] = p[3];
114                                 MULT(q[1], p[0], p[3], t1);
115                                 MULT(q[2], p[1], p[3], t2);
116                                 MULT(q[3], p[2], p[3], t3);
117 #endif
118
119                                 p += 4;
120                                 q += 4;
121                         }
122 #undef MULT
123                 }
124
125                 gdk_pixels += gdk_rowstride;
126                 cairo_pixels += cairo_stride;
127         }
128         cairo_surface_mark_dirty(surface);
129
130         cairo_set_source_surface(cr, surface,
131                                  src_x + .5 * (src_width - width),
132                                  src_y + .5 * (src_height - height));
133         cairo_surface_destroy(surface);
134 }
135
136 static void
137 image_draw(struct image *image)
138 {
139         struct rectangle allocation;
140         GdkPixbuf *pb;
141         cairo_t *cr;
142         cairo_surface_t *surface;
143
144         window_draw(image->window);
145
146         window_get_child_allocation(image->window, &allocation);
147
148         pb = gdk_pixbuf_new_from_file_at_size(image->filename,
149                                               allocation.width,
150                                               allocation.height,
151                                               NULL);
152         if (pb == NULL)
153                 return;
154
155         surface = window_get_surface(image->window);
156         cr = cairo_create(surface);
157         window_get_child_allocation(image->window, &allocation);
158         cairo_rectangle(cr, allocation.x, allocation.y,
159                         allocation.width, allocation.height);
160         cairo_clip(cr);
161         cairo_push_group(cr);
162         cairo_translate(cr, allocation.x, allocation.y);
163
164         cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
165         cairo_set_source_rgba(cr, 0, 0, 0, 1);
166         cairo_paint(cr);
167         set_source_pixbuf(cr, pb,
168                           0, 0,
169                           allocation.width, allocation.height);
170         cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
171         cairo_paint(cr);
172
173         g_object_unref(pb);
174
175         cairo_pop_group_to_source(cr);
176         cairo_paint(cr);
177         cairo_destroy(cr);
178
179         window_flush(image->window);
180         cairo_surface_destroy(surface);
181 }
182
183 static void
184 redraw_handler(struct window *window, void *data)
185 {
186         struct image *image = data;
187
188         image_draw(image);
189 }
190
191 static void
192 keyboard_focus_handler(struct window *window,
193                        struct input *device, void *data)
194 {
195         struct image *image = data;
196
197         window_schedule_redraw(image->window);
198 }
199
200 static struct image *
201 image_create(struct display *display, uint32_t key, const char *filename)
202 {
203         struct image *image;
204         gchar *basename;
205         gchar *title;
206
207         image = malloc(sizeof *image);
208         if (image == NULL)
209                 return image;
210         memset(image, 0, sizeof *image);
211
212         basename = g_path_get_basename(filename);
213         title = g_strdup_printf("Wayland Image - %s", basename);
214         g_free(basename);
215
216         image->filename = g_strdup(filename);
217
218         image->window = window_create(display, 500, 400);
219         window_set_title(image->window, title);
220         image->display = display;
221
222         /* FIXME: Window uses key 1 for moves, need some kind of
223          * allocation scheme here.  Or maybe just a real toolkit. */
224         image->key = key + 100;
225
226         window_set_user_data(image->window, image);
227         window_set_redraw_handler(image->window, redraw_handler);
228         window_set_keyboard_focus_handler(image->window,
229                                           keyboard_focus_handler);
230
231         image_draw(image);
232
233         return image;
234 }
235
236 static const GOptionEntry option_entries[] = {
237         { NULL }
238 };
239
240 int
241 main(int argc, char *argv[])
242 {
243         struct display *d;
244         int i;
245
246         d = display_create(&argc, &argv, option_entries);
247         if (d == NULL) {
248                 fprintf(stderr, "failed to create display: %m\n");
249                 return -1;
250         }
251
252         for (i = 1; i < argc; i++)
253                 image_create (d, i, argv[i]);
254
255         display_run(d);
256
257         return 0;
258 }