blob: 45cfafeee4782fd2f1bef79fed5cf8444c73c976 [file] [log] [blame]
Kristian Høgsberg8f2f7732009-09-21 13:46:45 -04001/*
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 <linux/input.h>
36
37#include <glib/poppler-document.h>
38#include <glib/poppler-page.h>
39
40#include "wayland-util.h"
41#include "wayland-client.h"
42#include "wayland-glib.h"
43
44#include "window.h"
45
46static const char gem_device[] = "/dev/dri/card0";
47static const char socket_name[] = "\0wayland";
48
49struct view {
50 struct window *window;
51 struct display *display;
52 struct wl_compositor *compositor;
53 uint32_t key;
54
55 gboolean redraw_scheduled;
56 gboolean redraw_pending;
57
58 cairo_surface_t *surface;
59 gchar *filename;
60 PopplerDocument *document;
61 int page;
62 int fullscreen;
63 int focused;
64};
65
66static void
67view_draw(struct view *view)
68{
69 struct rectangle rectangle;
70 cairo_t *cr;
71 PopplerPage *page;
72 double width, height, doc_aspect, window_aspect, scale;
73
74 view->redraw_pending = 0;
75
76 window_draw(view->window);
77
78 window_get_child_rectangle(view->window, &rectangle);
79
80 page = poppler_document_get_page(view->document, view->page);
81
82 view->surface =
83 window_create_surface(view->window, &rectangle);
84
85 cr = cairo_create(view->surface);
86 cairo_set_source_rgba(cr, 0, 0, 0, 0.8);
87 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
88 cairo_paint(cr);
89 poppler_page_get_size(page, &width, &height);
90 doc_aspect = width / height;
91 window_aspect = (double) rectangle.width / rectangle.height;
92 if (doc_aspect < window_aspect)
93 scale = rectangle.height / height;
94 else
95 scale = rectangle.width / width;
96 cairo_scale(cr, scale, scale);
97 cairo_translate(cr,
98 (rectangle.width - width * scale) / 2 / scale,
99 (rectangle.height - height * scale) / 2 / scale);
100 cairo_rectangle(cr, 0, 0, width, height);
101 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
102 cairo_set_source_rgb(cr, 1, 1, 1);
103 cairo_fill(cr);
104 poppler_page_render(page, cr);
105 cairo_destroy(cr);
106 g_object_unref(G_OBJECT(page));
107
108 window_copy_surface(view->window,
109 &rectangle,
110 view->surface);
111
112 wl_compositor_commit(view->compositor, view->key);
113}
114
115static gboolean
116view_idle_redraw(void *data)
117{
118 struct view *view = data;
119
120 view_draw(view);
121
122 return FALSE;
123}
124
125static void
126view_schedule_redraw(struct view *view)
127{
128 if (!view->redraw_scheduled) {
129 view->redraw_scheduled = 1;
130 g_idle_add(view_idle_redraw, view);
131 } else {
132 view->redraw_pending = 1;
133 }
134}
135
136static void
137key_handler(struct window *window, uint32_t key, uint32_t unicode,
138 uint32_t state, uint32_t modifiers, void *data)
139{
140 struct view *view = data;
141
142 switch (key) {
143 case KEY_F11:
144 if (!state)
145 break;
146 view->fullscreen ^= 1;
147 window_set_fullscreen(window, view->fullscreen);
148 view_schedule_redraw(view);
149 break;
150 case KEY_SPACE:
151 case KEY_PAGEDOWN:
152 if (!state)
153 break;
154 view->page++;
155 view_schedule_redraw(view);
156 break;
157 case KEY_BACKSPACE:
158 case KEY_PAGEUP:
159 if (!state)
160 break;
161 view->page--;
162 view_schedule_redraw(view);
163 break;
164 default:
165 break;
166 }
167}
168
169static void
170resize_handler(struct window *window, void *data)
171{
172 struct view *view = data;
173
174 view_schedule_redraw(view);
175}
176
177static void
178handle_acknowledge(void *data,
179 struct wl_compositor *compositor,
180 uint32_t key, uint32_t frame)
181{
182 struct view *view = data;
183
184 if (view->key != key)
185 return;
186
187 cairo_surface_destroy(view->surface);
188 view->redraw_scheduled = 0;
189 if (view->redraw_pending) {
190 view->redraw_pending = 0;
191 view_schedule_redraw(view);
192 }
193}
194
195static void
196keyboard_focus_handler(struct window *window,
197 struct wl_input_device *device, void *data)
198{
199 struct view *view = data;
200
201 view->focused = (device != NULL);
202 view_schedule_redraw(view);
203}
204
205static void
206handle_frame(void *data,
207 struct wl_compositor *compositor,
208 uint32_t frame, uint32_t timestamp)
209{
210}
211
212static const struct wl_compositor_listener compositor_listener = {
213 handle_acknowledge,
214 handle_frame,
215};
216
217static struct view *
218view_create(struct display *display, uint32_t key, const char *filename)
219{
220 struct view *view;
221 gchar *basename;
222 gchar *title;
223 GError *error = NULL;
224
225 view = malloc(sizeof *view);
226 if (view == NULL)
227 return view;
228 memset(view, 0, sizeof *view);
229
230 basename = g_path_get_basename(filename);
231 title = g_strdup_printf("Wayland View - %s", basename);
232 g_free(basename);
233
234 view->filename = g_strdup(filename);
235
236 view->window = window_create(display, title,
237 100 * key, 100 * key, 500, 400);
238 view->display = display;
239
240 /* FIXME: Window uses key 1 for moves, need some kind of
241 * allocation scheme here. Or maybe just a real toolkit. */
242 view->key = key + 100;
243 view->redraw_scheduled = 1;
244
245 view->compositor = display_get_compositor(display);
246 window_set_resize_handler(view->window, resize_handler, view);
247 window_set_key_handler(view->window, key_handler, view);
248 window_set_keyboard_focus_handler(view->window,
249 keyboard_focus_handler, view);
250
251 wl_compositor_add_listener(view->compositor,
252 &compositor_listener, view);
253
254 view->document = poppler_document_new_from_file(view->filename,
255 NULL, &error);
256 view->page = 0;
257 view_draw(view);
258
259 return view;
260}
261
262static const GOptionEntry option_entries[] = {
263 { NULL }
264};
265
266int
267main(int argc, char *argv[])
268{
269 struct wl_display *display;
270 int fd;
271 GMainLoop *loop;
272 GSource *source;
273 struct display *d;
274 GOptionContext *context;
275 GError *error = NULL;
276 int i;
277
278 context = g_option_context_new(NULL);
279 g_option_context_add_main_entries(context, option_entries, "Wayland View");
280 if (!g_option_context_parse(context, &argc, &argv, &error)) {
281 fprintf(stderr, "option parsing failed: %s\n", error->message);
282 exit(EXIT_FAILURE);
283 }
284
285 fd = open(gem_device, O_RDWR);
286 if (fd < 0) {
287 fprintf(stderr, "drm open failed: %m\n");
288 return -1;
289 }
290
291 display = wl_display_create(socket_name, sizeof socket_name);
292 if (display == NULL) {
293 fprintf(stderr, "failed to create display: %m\n");
294 return -1;
295 }
296
297 d = display_create(display, fd);
298 loop = g_main_loop_new(NULL, FALSE);
299 source = wl_glib_source_new(display);
300 g_source_attach(source, NULL);
301
302 g_type_init ();
303
304 for (i = 1; i < argc; i++) {
305 struct view *view;
306
307 view = view_create (d, i, argv[i]);
308 }
309
310 g_main_loop_run(loop);
311
312 return 0;
313}