blob: 8f621eb7bfdac5168567fbbb31dc8577906a3e33 [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
Pekka Paalanen50719bc2011-11-22 14:18:50 +020036#include <wayland-client.h>
Chris Wilson0de19eb2009-02-21 15:22:06 -050037
38#include "window.h"
39
Chris Wilson0de19eb2009-02-21 15:22:06 -050040struct image {
41 struct window *window;
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -050042 struct widget *widget;
Chris Wilson0de19eb2009-02-21 15:22:06 -050043 struct display *display;
Chris Wilson0de19eb2009-02-21 15:22:06 -050044 gchar *filename;
45};
46
47static void
48set_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
136static void
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -0500137redraw_handler(struct widget *widget, void *data)
Chris Wilson0de19eb2009-02-21 15:22:06 -0500138{
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -0500139 struct image *image = data;
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øgsberge164e4e2011-01-21 11:35:05 -0500143 cairo_surface_t *surface;
Chris Wilson0de19eb2009-02-21 15:22:06 -0500144
Kristian Høgsbergbb977002012-01-10 19:11:42 -0500145 widget_get_allocation(image->widget, &allocation);
Chris Wilson0de19eb2009-02-21 15:22:06 -0500146
147 pb = gdk_pixbuf_new_from_file_at_size(image->filename,
Kristian Høgsbergda846ca2011-01-11 10:00:52 -0500148 allocation.width,
149 allocation.height,
Chris Wilson0de19eb2009-02-21 15:22:06 -0500150 NULL);
151 if (pb == NULL)
152 return;
153
Kristian Høgsberge164e4e2011-01-21 11:35:05 -0500154 surface = window_get_surface(image->window);
Kristian Høgsberg09531622010-06-14 23:22:15 -0400155 cr = cairo_create(surface);
Kristian Høgsbergbb977002012-01-10 19:11:42 -0500156 widget_get_allocation(image->widget, &allocation);
Kristian Høgsberge164e4e2011-01-21 11:35:05 -0500157 cairo_rectangle(cr, allocation.x, allocation.y,
158 allocation.width, allocation.height);
159 cairo_clip(cr);
160 cairo_push_group(cr);
161 cairo_translate(cr, allocation.x, allocation.y);
162
Chris Wilson0de19eb2009-02-21 15:22:06 -0500163 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
164 cairo_set_source_rgba(cr, 0, 0, 0, 1);
165 cairo_paint(cr);
166 set_source_pixbuf(cr, pb,
167 0, 0,
Kristian Høgsbergda846ca2011-01-11 10:00:52 -0500168 allocation.width, allocation.height);
Chris Wilson0de19eb2009-02-21 15:22:06 -0500169 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
170 cairo_paint(cr);
Chris Wilson0de19eb2009-02-21 15:22:06 -0500171
172 g_object_unref(pb);
173
Kristian Høgsberge164e4e2011-01-21 11:35:05 -0500174 cairo_pop_group_to_source(cr);
175 cairo_paint(cr);
176 cairo_destroy(cr);
177
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
Kristian Høgsberga341fa02010-01-24 18:10:15 -0500182keyboard_focus_handler(struct window *window,
Kristian Høgsberg43788b12010-07-28 23:50:12 -0400183 struct input *device, void *data)
Kristian Høgsberga341fa02010-01-24 18:10:15 -0500184{
185 struct image *image = data;
186
Kristian Høgsberg80d746f2010-06-14 23:52:50 -0400187 window_schedule_redraw(image->window);
Kristian Høgsberga341fa02010-01-24 18:10:15 -0500188}
189
Chris Wilson0de19eb2009-02-21 15:22:06 -0500190static struct image *
Kristian Høgsbergcadd0f52012-01-09 18:56:37 -0500191image_create(struct display *display, const char *filename)
Chris Wilson0de19eb2009-02-21 15:22:06 -0500192{
193 struct image *image;
194 gchar *basename;
195 gchar *title;
196
197 image = malloc(sizeof *image);
198 if (image == NULL)
199 return image;
200 memset(image, 0, sizeof *image);
201
202 basename = g_path_get_basename(filename);
203 title = g_strdup_printf("Wayland Image - %s", basename);
204 g_free(basename);
205
206 image->filename = g_strdup(filename);
207
Kristian Høgsberg009ac0a2012-01-31 15:24:48 -0500208 image->window = window_create(display);
Kristian Høgsberg29af3eb2012-01-10 22:41:05 -0500209 image->widget = frame_create(image->window, image);
Kristian Høgsberg248c1b62011-01-21 18:03:15 -0500210 window_set_title(image->window, title);
Chris Wilson0de19eb2009-02-21 15:22:06 -0500211 image->display = display;
212
Kristian Høgsbergc8c37342010-06-25 11:19:22 -0400213 window_set_user_data(image->window, image);
Kristian Høgsbergb67e94b2012-01-10 12:23:19 -0500214 widget_set_redraw_handler(image->widget, redraw_handler);
Kristian Høgsberg43788b12010-07-28 23:50:12 -0400215 window_set_keyboard_focus_handler(image->window,
216 keyboard_focus_handler);
Chris Wilson0de19eb2009-02-21 15:22:06 -0500217
Kristian Høgsbergbb977002012-01-10 19:11:42 -0500218 widget_schedule_resize(image->widget, 500, 400);
Chris Wilson0de19eb2009-02-21 15:22:06 -0500219
220 return image;
221}
222
223static const GOptionEntry option_entries[] = {
224 { NULL }
225};
226
227int
228main(int argc, char *argv[])
229{
Chris Wilson0de19eb2009-02-21 15:22:06 -0500230 struct display *d;
Chris Wilson0de19eb2009-02-21 15:22:06 -0500231 int i;
232
Kristian Høgsberg9de79a92011-08-24 11:09:53 -0400233 d = display_create(&argc, &argv, option_entries);
Yuval Fledele9f5e362010-11-22 21:34:19 +0200234 if (d == NULL) {
235 fprintf(stderr, "failed to create display: %m\n");
236 return -1;
237 }
Chris Wilson0de19eb2009-02-21 15:22:06 -0500238
Kristian Høgsberg00439612011-01-25 15:16:01 -0500239 for (i = 1; i < argc; i++)
Kristian Høgsbergcadd0f52012-01-09 18:56:37 -0500240 image_create (d, argv[i]);
Chris Wilson0de19eb2009-02-21 15:22:06 -0500241
Kristian Høgsberg7824d812010-06-08 14:59:44 -0400242 display_run(d);
Chris Wilson0de19eb2009-02-21 15:22:06 -0500243
244 return 0;
245}