blob: 61d8b25f3f8eceefa1e9eff9b94cab13e46a3835 [file] [log] [blame]
Chris Wilson0de19eb2009-02-21 15:22:06 -05001/*
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>
Chris Wilson0de19eb2009-02-21 15:22:06 -050033#include <glib.h>
34#include <gdk-pixbuf/gdk-pixbuf.h>
35
36#include "wayland-client.h"
37#include "wayland-glib.h"
38
39#include "window.h"
40
Chris Wilson0de19eb2009-02-21 15:22:06 -050041struct image {
42 struct window *window;
43 struct display *display;
Chris Wilson0de19eb2009-02-21 15:22:06 -050044 uint32_t key;
Chris Wilson0de19eb2009-02-21 15:22:06 -050045 gchar *filename;
46};
47
48static void
49set_source_pixbuf(cairo_t *cr,
50 const GdkPixbuf *pixbuf,
51 double src_x,
52 double src_y,
53 double src_width,
54 double src_height)
55{
56 gint width = gdk_pixbuf_get_width (pixbuf);
57 gint height = gdk_pixbuf_get_height (pixbuf);
58 guchar *gdk_pixels = gdk_pixbuf_get_pixels (pixbuf);
59 int gdk_rowstride = gdk_pixbuf_get_rowstride (pixbuf);
60 int n_channels = gdk_pixbuf_get_n_channels (pixbuf);
61 int cairo_stride;
62 guchar *cairo_pixels;
63 cairo_format_t format;
64 cairo_surface_t *surface;
65 int j;
66
67 if (n_channels == 3)
68 format = CAIRO_FORMAT_RGB24;
69 else
70 format = CAIRO_FORMAT_ARGB32;
71
72 surface = cairo_image_surface_create(format, width, height);
73 if (cairo_surface_status(surface)) {
74 cairo_set_source_surface(cr, surface, 0, 0);
75 return;
76 }
77
78 cairo_stride = cairo_image_surface_get_stride(surface);
79 cairo_pixels = cairo_image_surface_get_data(surface);
80
81 for (j = height; j; j--) {
82 guchar *p = gdk_pixels;
83 guchar *q = cairo_pixels;
84
85 if (n_channels == 3) {
86 guchar *end = p + 3 * width;
87
88 while (p < end) {
89#if G_BYTE_ORDER == G_LITTLE_ENDIAN
90 q[0] = p[2];
91 q[1] = p[1];
92 q[2] = p[0];
93#else
94 q[1] = p[0];
95 q[2] = p[1];
96 q[3] = p[2];
97#endif
98 p += 3;
99 q += 4;
100 }
101 } else {
102 guchar *end = p + 4 * width;
103 guint t1,t2,t3;
104
105#define MULT(d,c,a,t) G_STMT_START { t = c * a + 0x7f; d = ((t >> 8) + t) >> 8; } G_STMT_END
106
107 while (p < end) {
108#if G_BYTE_ORDER == G_LITTLE_ENDIAN
109 MULT(q[0], p[2], p[3], t1);
110 MULT(q[1], p[1], p[3], t2);
111 MULT(q[2], p[0], p[3], t3);
112 q[3] = p[3];
113#else
114 q[0] = p[3];
115 MULT(q[1], p[0], p[3], t1);
116 MULT(q[2], p[1], p[3], t2);
117 MULT(q[3], p[2], p[3], t3);
118#endif
119
120 p += 4;
121 q += 4;
122 }
123#undef MULT
124 }
125
126 gdk_pixels += gdk_rowstride;
127 cairo_pixels += cairo_stride;
128 }
129 cairo_surface_mark_dirty(surface);
130
131 cairo_set_source_surface(cr, surface,
132 src_x + .5 * (src_width - width),
133 src_y + .5 * (src_height - height));
134 cairo_surface_destroy(surface);
135}
136
137static void
138image_draw(struct image *image)
139{
Kristian Høgsbergda846ca2011-01-11 10:00:52 -0500140 struct rectangle allocation;
Chris Wilson0de19eb2009-02-21 15:22:06 -0500141 GdkPixbuf *pb;
142 cairo_t *cr;
Kristian Høgsberg09531622010-06-14 23:22:15 -0400143 cairo_surface_t *wsurface, *surface;
Chris Wilson0de19eb2009-02-21 15:22:06 -0500144
Chris Wilson0de19eb2009-02-21 15:22:06 -0500145 window_draw(image->window);
146
Kristian Høgsbergda846ca2011-01-11 10:00:52 -0500147 window_get_child_allocation(image->window, &allocation);
Chris Wilson0de19eb2009-02-21 15:22:06 -0500148
149 pb = gdk_pixbuf_new_from_file_at_size(image->filename,
Kristian Høgsbergda846ca2011-01-11 10:00:52 -0500150 allocation.width,
151 allocation.height,
Chris Wilson0de19eb2009-02-21 15:22:06 -0500152 NULL);
153 if (pb == NULL)
154 return;
155
Kristian Høgsberg09531622010-06-14 23:22:15 -0400156 wsurface = window_get_surface(image->window);
157 surface = cairo_surface_create_similar(wsurface,
158 CAIRO_CONTENT_COLOR_ALPHA,
Kristian Høgsbergda846ca2011-01-11 10:00:52 -0500159 allocation.width,
160 allocation.height);
Chris Wilson0de19eb2009-02-21 15:22:06 -0500161
Johan Bilien990854d2010-11-07 09:52:11 -0500162 cairo_surface_destroy(wsurface);
Kristian Høgsberg09531622010-06-14 23:22:15 -0400163 cr = cairo_create(surface);
Chris Wilson0de19eb2009-02-21 15:22:06 -0500164 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,
Kristian Høgsbergda846ca2011-01-11 10:00:52 -0500169 allocation.width, allocation.height);
Chris Wilson0de19eb2009-02-21 15:22:06 -0500170 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
171 cairo_paint(cr);
172 cairo_destroy(cr);
173
174 g_object_unref(pb);
175
Kristian Høgsbergda846ca2011-01-11 10:00:52 -0500176 window_copy_surface(image->window, &allocation, surface);
Kristian Høgsberg9d69f8e2010-09-03 14:46:38 -0400177 window_flush(image->window);
Kristian Høgsberg09531622010-06-14 23:22:15 -0400178 cairo_surface_destroy(surface);
Chris Wilson0de19eb2009-02-21 15:22:06 -0500179}
180
Kristian Høgsberg80d746f2010-06-14 23:52:50 -0400181static void
182redraw_handler(struct window *window, void *data)
Chris Wilson0de19eb2009-02-21 15:22:06 -0500183{
184 struct image *image = data;
185
186 image_draw(image);
Chris Wilson0de19eb2009-02-21 15:22:06 -0500187}
188
189static void
Kristian Høgsberga341fa02010-01-24 18:10:15 -0500190keyboard_focus_handler(struct window *window,
Kristian Høgsberg43788b12010-07-28 23:50:12 -0400191 struct input *device, void *data)
Kristian Høgsberga341fa02010-01-24 18:10:15 -0500192{
193 struct image *image = data;
194
Kristian Høgsberg80d746f2010-06-14 23:52:50 -0400195 window_schedule_redraw(image->window);
Kristian Høgsberga341fa02010-01-24 18:10:15 -0500196}
197
Chris Wilson0de19eb2009-02-21 15:22:06 -0500198static struct image *
199image_create(struct display *display, uint32_t key, const char *filename)
200{
201 struct image *image;
202 gchar *basename;
203 gchar *title;
204
205 image = malloc(sizeof *image);
206 if (image == NULL)
207 return image;
208 memset(image, 0, sizeof *image);
209
210 basename = g_path_get_basename(filename);
211 title = g_strdup_printf("Wayland Image - %s", basename);
212 g_free(basename);
213
214 image->filename = g_strdup(filename);
215
Kristian Høgsberg82da52b2010-12-17 09:53:12 -0500216 image->window = window_create(display, title, 500, 400);
Chris Wilson0de19eb2009-02-21 15:22:06 -0500217 image->display = display;
218
219 /* FIXME: Window uses key 1 for moves, need some kind of
220 * allocation scheme here. Or maybe just a real toolkit. */
221 image->key = key + 100;
Chris Wilson0de19eb2009-02-21 15:22:06 -0500222
Kristian Høgsbergc8c37342010-06-25 11:19:22 -0400223 window_set_user_data(image->window, image);
224 window_set_redraw_handler(image->window, redraw_handler);
Kristian Høgsberg43788b12010-07-28 23:50:12 -0400225 window_set_keyboard_focus_handler(image->window,
226 keyboard_focus_handler);
Chris Wilson0de19eb2009-02-21 15:22:06 -0500227
228 image_draw(image);
229
230 return image;
231}
232
233static const GOptionEntry option_entries[] = {
234 { NULL }
235};
236
237int
238main(int argc, char *argv[])
239{
Chris Wilson0de19eb2009-02-21 15:22:06 -0500240 struct display *d;
Chris Wilson0de19eb2009-02-21 15:22:06 -0500241 int i;
242
Kristian Høgsberg7824d812010-06-08 14:59:44 -0400243 d = display_create(&argc, &argv, option_entries);
Yuval Fledele9f5e362010-11-22 21:34:19 +0200244 if (d == NULL) {
245 fprintf(stderr, "failed to create display: %m\n");
246 return -1;
247 }
Chris Wilson0de19eb2009-02-21 15:22:06 -0500248
249 for (i = 1; i < argc; i++) {
250 struct image *image;
251
252 image = image_create (d, i, argv[i]);
253 }
254
Kristian Høgsberg7824d812010-06-08 14:59:44 -0400255 display_run(d);
Chris Wilson0de19eb2009-02-21 15:22:06 -0500256
257 return 0;
258}