Set window user data using separate function
[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 <cairo-drm.h>
34 #include <glib.h>
35 #include <gdk-pixbuf/gdk-pixbuf.h>
36
37 #include "wayland-client.h"
38 #include "wayland-glib.h"
39
40 #include "window.h"
41
42 static const char gem_device[] = "/dev/dri/card0";
43 static const char socket_name[] = "\0wayland";
44
45 struct image {
46         struct window *window;
47         struct display *display;
48         uint32_t key;
49         gchar *filename;
50 };
51
52 static void
53 set_source_pixbuf(cairo_t         *cr,
54                   const GdkPixbuf *pixbuf,
55                   double           src_x,
56                   double           src_y,
57                   double           src_width,
58                   double           src_height)
59 {
60         gint width = gdk_pixbuf_get_width (pixbuf);
61         gint height = gdk_pixbuf_get_height (pixbuf);
62         guchar *gdk_pixels = gdk_pixbuf_get_pixels (pixbuf);
63         int gdk_rowstride = gdk_pixbuf_get_rowstride (pixbuf);
64         int n_channels = gdk_pixbuf_get_n_channels (pixbuf);
65         int cairo_stride;
66         guchar *cairo_pixels;
67         cairo_format_t format;
68         cairo_surface_t *surface;
69         int j;
70
71         if (n_channels == 3)
72                 format = CAIRO_FORMAT_RGB24;
73         else
74                 format = CAIRO_FORMAT_ARGB32;
75
76         surface = cairo_image_surface_create(format, width, height);
77         if (cairo_surface_status(surface)) {
78                 cairo_set_source_surface(cr, surface, 0, 0);
79                 return;
80         }
81
82         cairo_stride = cairo_image_surface_get_stride(surface);
83         cairo_pixels = cairo_image_surface_get_data(surface);
84
85         for (j = height; j; j--) {
86                 guchar *p = gdk_pixels;
87                 guchar *q = cairo_pixels;
88
89                 if (n_channels == 3) {
90                         guchar *end = p + 3 * width;
91
92                         while (p < end) {
93 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
94                                 q[0] = p[2];
95                                 q[1] = p[1];
96                                 q[2] = p[0];
97 #else
98                                 q[1] = p[0];
99                                 q[2] = p[1];
100                                 q[3] = p[2];
101 #endif
102                                 p += 3;
103                                 q += 4;
104                         }
105                 } else {
106                         guchar *end = p + 4 * width;
107                         guint t1,t2,t3;
108
109 #define MULT(d,c,a,t) G_STMT_START { t = c * a + 0x7f; d = ((t >> 8) + t) >> 8; } G_STMT_END
110
111                         while (p < end) {
112 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
113                                 MULT(q[0], p[2], p[3], t1);
114                                 MULT(q[1], p[1], p[3], t2);
115                                 MULT(q[2], p[0], p[3], t3);
116                                 q[3] = p[3];
117 #else
118                                 q[0] = p[3];
119                                 MULT(q[1], p[0], p[3], t1);
120                                 MULT(q[2], p[1], p[3], t2);
121                                 MULT(q[3], p[2], p[3], t3);
122 #endif
123
124                                 p += 4;
125                                 q += 4;
126                         }
127 #undef MULT
128                 }
129
130                 gdk_pixels += gdk_rowstride;
131                 cairo_pixels += cairo_stride;
132         }
133         cairo_surface_mark_dirty(surface);
134
135         cairo_set_source_surface(cr, surface,
136                                  src_x + .5 * (src_width - width),
137                                  src_y + .5 * (src_height - height));
138         cairo_surface_destroy(surface);
139 }
140
141 static void
142 image_draw(struct image *image)
143 {
144         struct rectangle rectangle;
145         GdkPixbuf *pb;
146         cairo_t *cr;
147         cairo_surface_t *wsurface, *surface;
148
149         window_draw(image->window);
150
151         window_get_child_rectangle(image->window, &rectangle);
152
153         pb = gdk_pixbuf_new_from_file_at_size(image->filename,
154                                               rectangle.width,
155                                               rectangle.height,
156                                               NULL);
157         if (pb == NULL)
158                 return;
159
160         wsurface = window_get_surface(image->window);
161         surface = cairo_surface_create_similar(wsurface,
162                                                CAIRO_CONTENT_COLOR_ALPHA,
163                                                rectangle.width,
164                                                rectangle.height);
165
166         cr = cairo_create(surface);
167         cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
168         cairo_set_source_rgba(cr, 0, 0, 0, 1);
169         cairo_paint(cr);
170         set_source_pixbuf(cr, pb,
171                           0, 0,
172                           rectangle.width, rectangle.height);
173         cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
174         cairo_paint(cr);
175         cairo_destroy(cr);
176
177         g_object_unref(pb);
178
179         window_copy_surface(image->window, &rectangle, surface);
180         window_commit(image->window, image->key);
181         cairo_surface_destroy(surface);
182 }
183
184 static void
185 redraw_handler(struct window *window, void *data)
186 {
187         struct image *image = data;
188
189         image_draw(image);
190 }
191
192 static void
193 keyboard_focus_handler(struct window *window,
194                        struct wl_input_device *device, void *data)
195 {
196         struct image *image = data;
197
198         window_schedule_redraw(image->window);
199 }
200
201 static struct image *
202 image_create(struct display *display, uint32_t key, const char *filename)
203 {
204         struct image *image;
205         gchar *basename;
206         gchar *title;
207
208         image = malloc(sizeof *image);
209         if (image == NULL)
210                 return image;
211         memset(image, 0, sizeof *image);
212
213         basename = g_path_get_basename(filename);
214         title = g_strdup_printf("Wayland Image - %s", basename);
215         g_free(basename);
216
217         image->filename = g_strdup(filename);
218
219         image->window = window_create(display, title, 100 * key, 100 * key, 500, 400);
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, keyboard_focus_handler);
229
230         image_draw(image);
231
232         return image;
233 }
234
235 static const GOptionEntry option_entries[] = {
236         { NULL }
237 };
238
239 int
240 main(int argc, char *argv[])
241 {
242         struct display *d;
243         int i;
244
245         d = display_create(&argc, &argv, option_entries);
246
247         for (i = 1; i < argc; i++) {
248                 struct image *image;
249
250                 image = image_create (d, i, argv[i]);
251         }
252
253         display_run(d);
254
255         return 0;
256 }