2 * Copyright Geoff Levand <geoff@infradead.org>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 2 of the License.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include <linux/input.h>
25 #include "list/list.h"
27 #include "talloc/talloc.h"
28 #include "waiter/waiter.h"
29 #include "ui/common/ui-system.h"
32 void _pbt_dump_event(const char *text, twin_window_t *twindow,
33 const twin_event_t *tevent, const char *func, int line)
35 switch(tevent->kind) {
36 case TwinEventButtonDown:
37 DBG("%s:%d: %s@%p: TwinEventButtonDown %x\n", func, line, text,
38 twindow, tevent->kind);
40 case TwinEventButtonUp:
41 DBG("%s:%d: %s@%p: TwinEventButtonUp %x\n", func, line, text,
42 twindow, tevent->kind);
45 //DBG("%s:%d:%s@%p: TwinEventMotion %x\n", func, line, text,
46 // twindow, tevent->kind);
49 DBG("%s:%d: %s@%p: TwinEventEnter %x\n", func, line, text,
50 twindow, tevent->kind);
53 DBG("%s:%d: %s@%p: TwinEventLeave %x\n", func, line, text,
54 twindow, tevent->kind);
56 case TwinEventKeyDown:
59 const char *kind = (tevent->kind == TwinEventKeyDown)
60 ? "TwinEventKeyDown" : "TwinEventKeyUp ";
62 switch(tevent->u.key.key) {
63 case (twin_keysym_t)XK_Up:
64 case (twin_keysym_t)KEY_UP:
65 DBG("%s:%d: %s@%p: %s = 'KEY_UP'\n", func, line, text,
68 case (twin_keysym_t)XK_Down:
69 case (twin_keysym_t)KEY_DOWN:
70 DBG("%s:%d: %s@%p: %s = 'KEY_DOWN'\n", func, line, text,
73 case (twin_keysym_t)XK_Right:
74 case (twin_keysym_t)KEY_RIGHT:
75 DBG("%s:%d: %s@%p: %s = 'KEY_RIGHT'\n", func, line, text,
78 case (twin_keysym_t)XK_Left:
79 case (twin_keysym_t)KEY_LEFT:
80 DBG("%s:%d: %s@%p: %s = 'KEY_LEFT'\n", func, line, text,
83 case (twin_keysym_t)XK_Escape:
84 case (twin_keysym_t)KEY_ESC:
85 DBG("%s:%d: %s@%p: %s = 'KEY_ESC'\n", func, line, text,
88 case (twin_keysym_t)XK_Return:
89 case (twin_keysym_t)KEY_ENTER:
90 DBG("%s:%d: %s@%p: %s = 'KEY_ENTER'\n", func, line, text,
93 case (twin_keysym_t)XK_Delete:
94 case (twin_keysym_t)KEY_DELETE:
95 DBG("%s:%d: %s@%p: %s = 'KEY_DELETE'\n", func, line, text,
98 case (twin_keysym_t)XK_BackSpace:
99 case (twin_keysym_t)KEY_BACKSPACE:
100 DBG("%s:%d: %s@%p: %s = 'KEY_BACKSPACE'\n", func, line, text,
104 DBG("%s:%d: %s@%p: %s = %d (%xh) = '%c'\n", func, line, text, twindow,
106 tevent->u.key.key, tevent->u.key.key,
107 (char)tevent->u.key.key);
112 DBG("%s:%d: %s@%p: %x\n", func, line, text, twindow, tevent->kind);
118 * pbt_background_load - Load the background pixmap from storage.
119 * @filename: File name of a jpg background.
121 * Returns the default background if @filename is NULL. Returns a default
122 * pattern if the load of @filename fails.
125 twin_pixmap_t *pbt_background_load(twin_screen_t *tscreen,
126 const char *filename)
128 static const char *default_background_file =
129 PB_ARTWORK_PATH "/background.jpg";
130 twin_pixmap_t *raw_background;
131 twin_pixmap_t *scaled_background;
134 filename = default_background_file;
136 raw_background = twin_jpeg_to_pixmap(filename, TWIN_ARGB32);
138 if (!raw_background) {
139 pb_log("%s: loading image '%s' failed\n", __func__, filename);
141 /* Fallback to a default pattern */
143 return twin_make_pattern();
146 if (tscreen->height == raw_background->height &&
147 tscreen->width == raw_background->width)
148 return raw_background;
150 /* Scale as needed. */
153 twin_operand_t srcop;
155 scaled_background = twin_pixmap_create(TWIN_ARGB32,
158 if (!scaled_background) {
159 pb_log("%s: scale '%s' failed\n", __func__, filename);
160 twin_pixmap_destroy(raw_background);
161 return twin_make_pattern();
163 sx = twin_fixed_div(twin_int_to_fixed(raw_background->width),
164 twin_int_to_fixed(tscreen->width));
165 sy = twin_fixed_div(twin_int_to_fixed(raw_background->height),
166 twin_int_to_fixed(tscreen->height));
168 twin_matrix_scale(&raw_background->transform, sx, sy);
169 srcop.source_kind = TWIN_PIXMAP;
170 srcop.u.pixmap = raw_background;
171 twin_composite(scaled_background, 0, 0, &srcop, 0, 0,
172 NULL, 0, 0, TWIN_SOURCE,
173 tscreen->width, tscreen->height);
175 twin_pixmap_destroy(raw_background);
177 return scaled_background;
180 const char *pbt_icon_chooser(const char *hint)
182 if (strstr(hint, "net"))
183 return PB_ARTWORK_PATH "/network-wired.png";
189 * pbt_icon_load - Load an icon pixmap from storage.
190 * @filename: File name of a png icon.
192 * Returns the default icon if @filename is NULL, or if the load
193 * of @filename fails.
194 * Caches pixmaps based on a hash of the @filename string.
197 twin_pixmap_t *pbt_icon_load(const char *filename)
199 static const char *default_icon_file = PB_ARTWORK_PATH "/tux.png";
201 struct list_item list;
205 STATIC_LIST(icon_cache);
206 struct cache_entry new;
207 struct cache_entry *i;
210 filename = default_icon_file;
213 new.hash = pb_elf_hash(filename);
215 list_for_each_entry(&icon_cache, i, list) {
216 if (i->hash == new.hash) {
217 DBGS("found %p\n", i->icon);
222 new.icon = twin_png_to_pixmap(filename, TWIN_ARGB32);
225 pb_log("%s: loading image '%s' failed\n", __func__, filename);
227 if (filename == default_icon_file)
230 filename = default_icon_file;
234 DBGS("new %p\n", new.icon);
236 i = talloc(NULL, struct cache_entry);
238 list_add(&icon_cache, &i->list);
240 pbt_dump_pixmap(new.icon);
246 * pbt_border_draw - Draw a border on a pixmap.
247 * @pixmap: The image to operate on.
248 * @border: The border to draw.
251 void pbt_border_draw(twin_pixmap_t *pixmap, const struct pbt_border *border)
253 twin_path_t *path = twin_path_create();
254 twin_argb32_t fill = border->fill_color ? border->fill_color
255 : 0xff000000; /* default to black */
259 //pbt_dump_pixmap(pixmap);
262 twin_path_rectangle(path, 0, 0,
263 twin_int_to_fixed(border->left),
264 twin_int_to_fixed(pixmap->height));
268 twin_path_rectangle(path,
269 twin_int_to_fixed(pixmap->width - border->right),
271 twin_int_to_fixed(pixmap->width),
272 twin_int_to_fixed(pixmap->height));
276 twin_path_rectangle(path, 0, 0,
277 twin_int_to_fixed(pixmap->width),
278 twin_int_to_fixed(border->top));
281 if (border->bottom) {
282 twin_path_rectangle(path, 0,
283 twin_int_to_fixed(pixmap->height - border->bottom),
284 twin_int_to_fixed(pixmap->width),
285 twin_int_to_fixed(border->bottom));
288 twin_paint_path(pixmap, fill, path);
289 twin_path_empty(path);
292 int pbt_window_contains(const twin_window_t *window, const twin_event_t *event)
294 pbt_dump_pixmap(window->pixmap);
296 if (event->u.pointer.x < window->pixmap->x) {
297 DBGS("%p: {%d,%d} left miss\n", window, event->u.pointer.x, event->u.pointer.y);
300 if (event->u.pointer.x >= window->pixmap->x + window->pixmap->width) {
301 DBGS("%p: {%d,%d} right miss\n", window, event->u.pointer.x, event->u.pointer.y);
304 if (event->u.pointer.y < window->pixmap->y) {
305 DBGS("%p: {%d,%d} high miss\n", window, event->u.pointer.x, event->u.pointer.y);
308 if (event->u.pointer.y >= window->pixmap->y + window->pixmap->height){
309 DBGS("%p: {%d,%d} low miss\n", window, event->u.pointer.x, event->u.pointer.y);
313 DBGS("%p: {%d,%d} hit\n", window, event->u.pointer.x, event->u.pointer.y);
318 static __attribute__((unused)) void pbt_image_copy(twin_pixmap_t *dest, twin_pixmap_t *src)
322 assert(dest->height >= src->height);
324 op.source_kind = TWIN_PIXMAP;
327 twin_composite(dest, 0, 0, &op, 0, 0, NULL,
328 0, 0, TWIN_SOURCE, src->width, src->height);
331 void pbt_image_draw(twin_pixmap_t *dest, twin_pixmap_t *image)
336 assert(dest->height >= image->height);
338 src.source_kind = TWIN_PIXMAP;
339 src.u.pixmap = image;
341 /* Center the image in the window. */
343 offset = (dest->height - image->height) / 2;
345 twin_composite(dest, offset, offset, &src, 0, 0, NULL,
346 0, 0, TWIN_SOURCE, image->width, image->height);
349 static int pbt_twin_waiter_cb(struct pbt_twin_ctx *twin_ctx)
351 #if defined(HAVE_LIBTWIN_TWIN_X11_H)
352 if (twin_ctx->backend == pbt_twin_x11)
353 twin_x11_process_events(twin_ctx->x11);
355 #if defined(HAVE_LIBTWIN_TWIN_FBDEV_H)
356 if (twin_ctx->backend == pbt_twin_fbdev)
357 twin_fbdev_process_events(twin_ctx->fbdev);
362 static void pbt_scr_destructor(struct pbt_scr *scr)
364 pb_log("%s\n", __func__);
366 twin_x11_destroy(scr->twin_ctx.x11);
367 // FIXME: need cursor cleanup???
368 memset(scr, 0, sizeof(*scr));
371 struct pbt_scr *pbt_scr_init(void *talloc_ctx,
372 struct waitset *waitset,
373 enum pbt_twin_backend backend,
374 unsigned int width, unsigned int height,
375 const char *filename_background,
376 twin_bool_t (*scr_event_cb)(twin_screen_t *tscreen,
377 twin_event_t *event))
379 struct pbt_scr *scr = talloc_zero(talloc_ctx, struct pbt_scr);
382 assert(backend && backend < 3);
385 pb_log("%s: alloc pbt_scr failed.\n", __func__);
389 talloc_set_destructor(scr, (void *)pbt_scr_destructor);
391 twin_feature_init(); // FIXME: need it???
393 scr->twin_ctx.backend = backend;
395 if (backend == pbt_twin_x11) {
396 pb_log("%s: using twin x11 backend.\n", __func__);
398 assert(height > 100);
400 #if !defined(HAVE_LIBTWIN_TWIN_X11_H)
403 scr->twin_ctx.x11 = twin_x11_create_ext(XOpenDisplay(0), width,
406 if (!scr->twin_ctx.x11) {
407 pb_log("%s: twin_x11_create_ext failed.\n", __func__);
408 perror("failed to create twin x11 context\n");
409 goto fail_ctx_create;
412 pb_log("%s: x11: %p\n", __func__, scr->twin_ctx.x11);
414 assert(scr->twin_ctx.x11->screen);
415 scr->tscreen = scr->twin_ctx.x11->screen;
416 waiter_fd = ConnectionNumber(scr->twin_ctx.x11->dpy);
418 } else if (backend == pbt_twin_fbdev) {
419 pb_log("%s: using twin fbdev backend.\n", __func__);
420 #if !defined(HAVE_LIBTWIN_TWIN_FBDEV_H)
423 scr->twin_ctx.fbdev = twin_fbdev_create_ext(-1, SIGUSR1, 0);
425 if (!scr->twin_ctx.fbdev) {
426 pb_log("%s: twin_fbdev_create_ext failed.\n", __func__);
427 perror("failed to create twin fbdev context\n");
428 goto fail_ctx_create;
431 assert(scr->twin_ctx.fbdev->screen);
432 scr->tscreen = scr->twin_ctx.fbdev->screen;
433 waiter_fd = scr->twin_ctx.fbdev->vt_fd;
435 twin_fbdev_activate(scr->twin_ctx.fbdev);
439 scr->tscreen->event_filter = scr_event_cb;
441 twin_screen_set_background(scr->tscreen,
442 pbt_background_load(scr->tscreen, filename_background));
444 assert(waiter_fd != -1);
446 waiter_register_io(waitset, waiter_fd, WAIT_IN,
447 (void *)pbt_twin_waiter_cb, &scr->twin_ctx);
456 void pbt_window_redraw(twin_window_t *twindow)
458 twin_window_damage(twindow, 0, 0, twindow->pixmap->width,
459 twindow->pixmap->height);
460 //twin_window_queue_paint(twindow);
461 twin_window_draw(twindow);