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
18 #if defined(HAVE_CONFIG_H)
25 #include <linux/input.h>
27 #include "list/list.h"
29 #include "talloc/talloc.h"
30 #include "waiter/waiter.h"
31 #include "ui/common/ui-system.h"
34 void _pbt_dump_event(const char *text, twin_window_t *twindow,
35 const twin_event_t *tevent, const char *func, int line)
37 switch(tevent->kind) {
38 case TwinEventButtonDown:
39 DBG("%s:%d: %s@%p: TwinEventButtonDown %x\n", func, line, text,
40 twindow, tevent->kind);
42 case TwinEventButtonUp:
43 DBG("%s:%d: %s@%p: TwinEventButtonUp %x\n", func, line, text,
44 twindow, tevent->kind);
47 //DBG("%s:%d:%s@%p: TwinEventMotion %x\n", func, line, text,
48 // twindow, tevent->kind);
51 DBG("%s:%d: %s@%p: TwinEventEnter %x\n", func, line, text,
52 twindow, tevent->kind);
55 DBG("%s:%d: %s@%p: TwinEventLeave %x\n", func, line, text,
56 twindow, tevent->kind);
58 case TwinEventKeyDown:
61 const char *kind = (tevent->kind == TwinEventKeyDown)
62 ? "TwinEventKeyDown" : "TwinEventKeyUp ";
64 switch(tevent->u.key.key) {
65 case (twin_keysym_t)XK_Up:
66 case (twin_keysym_t)KEY_UP:
67 DBG("%s:%d: %s@%p: %s = 'KEY_UP'\n", func, line, text,
70 case (twin_keysym_t)XK_Down:
71 case (twin_keysym_t)KEY_DOWN:
72 DBG("%s:%d: %s@%p: %s = 'KEY_DOWN'\n", func, line, text,
75 case (twin_keysym_t)XK_Right:
76 case (twin_keysym_t)KEY_RIGHT:
77 DBG("%s:%d: %s@%p: %s = 'KEY_RIGHT'\n", func, line, text,
80 case (twin_keysym_t)XK_Left:
81 case (twin_keysym_t)KEY_LEFT:
82 DBG("%s:%d: %s@%p: %s = 'KEY_LEFT'\n", func, line, text,
85 case (twin_keysym_t)XK_Escape:
86 case (twin_keysym_t)KEY_ESC:
87 DBG("%s:%d: %s@%p: %s = 'KEY_ESC'\n", func, line, text,
90 case (twin_keysym_t)XK_Return:
91 case (twin_keysym_t)KEY_ENTER:
92 DBG("%s:%d: %s@%p: %s = 'KEY_ENTER'\n", func, line, text,
95 case (twin_keysym_t)XK_Delete:
96 case (twin_keysym_t)KEY_DELETE:
97 DBG("%s:%d: %s@%p: %s = 'KEY_DELETE'\n", func, line, text,
100 case (twin_keysym_t)XK_BackSpace:
101 case (twin_keysym_t)KEY_BACKSPACE:
102 DBG("%s:%d: %s@%p: %s = 'KEY_BACKSPACE'\n", func, line, text,
106 DBG("%s:%d: %s@%p: %s = %d (%xh) = '%c'\n", func, line, text, twindow,
108 tevent->u.key.key, tevent->u.key.key,
109 (char)tevent->u.key.key);
114 DBG("%s:%d: %s@%p: %x\n", func, line, text, twindow, tevent->kind);
120 * pbt_background_load - Load the background pixmap from storage.
121 * @filename: File name of a jpg background.
123 * Returns the default background if @filename is NULL. Returns a default
124 * pattern if the load of @filename fails.
127 twin_pixmap_t *pbt_background_load(twin_screen_t *tscreen,
128 const char *filename)
130 static const char *default_background_file =
131 PB_ARTWORK_PATH "/background.jpg";
132 twin_pixmap_t *raw_background;
133 twin_pixmap_t *scaled_background;
136 filename = default_background_file;
138 raw_background = twin_jpeg_to_pixmap(filename, TWIN_ARGB32);
140 if (!raw_background) {
141 pb_log_fn("loading image '%s' failed\n", filename);
143 /* Fallback to a default pattern */
145 return twin_make_pattern();
148 if (tscreen->height == raw_background->height &&
149 tscreen->width == raw_background->width)
150 return raw_background;
152 /* Scale as needed. */
155 twin_operand_t srcop;
157 scaled_background = twin_pixmap_create(TWIN_ARGB32,
160 if (!scaled_background) {
161 pb_log_fn("scale '%s' failed\n", filename);
162 twin_pixmap_destroy(raw_background);
163 return twin_make_pattern();
165 sx = twin_fixed_div(twin_int_to_fixed(raw_background->width),
166 twin_int_to_fixed(tscreen->width));
167 sy = twin_fixed_div(twin_int_to_fixed(raw_background->height),
168 twin_int_to_fixed(tscreen->height));
170 twin_matrix_scale(&raw_background->transform, sx, sy);
171 srcop.source_kind = TWIN_PIXMAP;
172 srcop.u.pixmap = raw_background;
173 twin_composite(scaled_background, 0, 0, &srcop, 0, 0,
174 NULL, 0, 0, TWIN_SOURCE,
175 tscreen->width, tscreen->height);
177 twin_pixmap_destroy(raw_background);
179 return scaled_background;
182 const char *pbt_icon_chooser(const char *hint)
184 if (strstr(hint, "net"))
185 return PB_ARTWORK_PATH "/network-wired.png";
191 * pbt_icon_load - Load an icon pixmap from storage.
192 * @filename: File name of a png icon.
194 * Returns the default icon if @filename is NULL, or if the load
195 * of @filename fails.
196 * Caches pixmaps based on a hash of the @filename string.
199 twin_pixmap_t *pbt_icon_load(const char *filename)
201 static const char *default_icon_file = PB_ARTWORK_PATH "/tux.png";
203 struct list_item list;
207 STATIC_LIST(icon_cache);
208 struct cache_entry new;
209 struct cache_entry *i;
212 filename = default_icon_file;
215 new.hash = pb_elf_hash(filename);
217 list_for_each_entry(&icon_cache, i, list) {
218 if (i->hash == new.hash) {
219 DBGS("found %p\n", i->icon);
224 new.icon = twin_png_to_pixmap(filename, TWIN_ARGB32);
227 pb_log_fn("loading image '%s' failed\n", filename);
229 if (filename == default_icon_file)
232 filename = default_icon_file;
236 DBGS("new %p\n", new.icon);
238 i = talloc(NULL, struct cache_entry);
240 list_add(&icon_cache, &i->list);
242 pbt_dump_pixmap(new.icon);
248 * pbt_border_draw - Draw a border on a pixmap.
249 * @pixmap: The image to operate on.
250 * @border: The border to draw.
253 void pbt_border_draw(twin_pixmap_t *pixmap, const struct pbt_border *border)
255 twin_path_t *path = twin_path_create();
256 twin_argb32_t fill = border->fill_color ? border->fill_color
257 : 0xff000000; /* default to black */
261 //pbt_dump_pixmap(pixmap);
264 twin_path_rectangle(path, 0, 0,
265 twin_int_to_fixed(border->left),
266 twin_int_to_fixed(pixmap->height));
270 twin_path_rectangle(path,
271 twin_int_to_fixed(pixmap->width - border->right),
273 twin_int_to_fixed(pixmap->width),
274 twin_int_to_fixed(pixmap->height));
278 twin_path_rectangle(path, 0, 0,
279 twin_int_to_fixed(pixmap->width),
280 twin_int_to_fixed(border->top));
283 if (border->bottom) {
284 twin_path_rectangle(path, 0,
285 twin_int_to_fixed(pixmap->height - border->bottom),
286 twin_int_to_fixed(pixmap->width),
287 twin_int_to_fixed(border->bottom));
290 twin_paint_path(pixmap, fill, path);
291 twin_path_empty(path);
294 int pbt_window_contains(const twin_window_t *window, const twin_event_t *event)
296 pbt_dump_pixmap(window->pixmap);
298 if (event->u.pointer.x < window->pixmap->x) {
299 DBGS("%p: {%d,%d} left miss\n", window, event->u.pointer.x, event->u.pointer.y);
302 if (event->u.pointer.x >= window->pixmap->x + window->pixmap->width) {
303 DBGS("%p: {%d,%d} right miss\n", window, event->u.pointer.x, event->u.pointer.y);
306 if (event->u.pointer.y < window->pixmap->y) {
307 DBGS("%p: {%d,%d} high miss\n", window, event->u.pointer.x, event->u.pointer.y);
310 if (event->u.pointer.y >= window->pixmap->y + window->pixmap->height){
311 DBGS("%p: {%d,%d} low miss\n", window, event->u.pointer.x, event->u.pointer.y);
315 DBGS("%p: {%d,%d} hit\n", window, event->u.pointer.x, event->u.pointer.y);
320 static __attribute__((unused)) void pbt_image_copy(twin_pixmap_t *dest, twin_pixmap_t *src)
324 assert(dest->height >= src->height);
326 op.source_kind = TWIN_PIXMAP;
329 twin_composite(dest, 0, 0, &op, 0, 0, NULL,
330 0, 0, TWIN_SOURCE, src->width, src->height);
333 void pbt_image_draw(twin_pixmap_t *dest, twin_pixmap_t *image)
338 assert(dest->height >= image->height);
340 src.source_kind = TWIN_PIXMAP;
341 src.u.pixmap = image;
343 /* Center the image in the window. */
345 offset = (dest->height - image->height) / 2;
347 twin_composite(dest, offset, offset, &src, 0, 0, NULL,
348 0, 0, TWIN_SOURCE, image->width, image->height);
351 static int pbt_twin_waiter_cb(struct pbt_twin_ctx *twin_ctx)
353 #if defined(HAVE_LIBTWIN_TWIN_X11_H)
354 if (twin_ctx->backend == pbt_twin_x11)
355 twin_x11_process_events(twin_ctx->x11);
357 #if defined(HAVE_LIBTWIN_TWIN_FBDEV_H)
358 if (twin_ctx->backend == pbt_twin_fbdev)
359 twin_fbdev_process_events(twin_ctx->fbdev);
364 static void pbt_scr_destructor(struct pbt_scr *scr)
366 pb_debug("%s\n", __func__);
368 twin_x11_destroy(scr->twin_ctx.x11);
369 // FIXME: need cursor cleanup???
370 memset(scr, 0, sizeof(*scr));
373 struct pbt_scr *pbt_scr_init(void *talloc_ctx,
374 struct waitset *waitset,
375 enum pbt_twin_backend backend,
376 unsigned int width, unsigned int height,
377 const char *filename_background,
378 twin_bool_t (*scr_event_cb)(twin_screen_t *tscreen,
379 twin_event_t *event))
381 struct pbt_scr *scr = talloc_zero(talloc_ctx, struct pbt_scr);
384 assert(backend && backend < 3);
387 pb_log_fn("alloc pbt_scr failed.\n");
391 talloc_set_destructor(scr, (void *)pbt_scr_destructor);
393 twin_feature_init(); // FIXME: need it???
395 scr->twin_ctx.backend = backend;
397 if (backend == pbt_twin_x11) {
398 pb_log_fn("using twin x11 backend.\n");
400 assert(height > 100);
402 #if !defined(HAVE_LIBTWIN_TWIN_X11_H)
405 scr->twin_ctx.x11 = twin_x11_create_ext(XOpenDisplay(NULL),
408 if (!scr->twin_ctx.x11) {
409 pb_log_fn("twin_x11_create_ext failed.\n");
410 perror("failed to create twin x11 context\n");
411 goto fail_ctx_create;
414 pb_debug("%s: x11: %p\n", __func__, scr->twin_ctx.x11);
416 assert(scr->twin_ctx.x11->screen);
417 scr->tscreen = scr->twin_ctx.x11->screen;
418 waiter_fd = ConnectionNumber(scr->twin_ctx.x11->dpy);
420 } else if (backend == pbt_twin_fbdev) {
421 pb_log_fn("using twin fbdev backend.\n");
422 #if !defined(HAVE_LIBTWIN_TWIN_FBDEV_H)
425 scr->twin_ctx.fbdev = twin_fbdev_create_ext(-1, SIGUSR1, 0);
427 if (!scr->twin_ctx.fbdev) {
428 pb_log_fn("twin_fbdev_create_ext failed.\n");
429 perror("failed to create twin fbdev context\n");
430 goto fail_ctx_create;
433 assert(scr->twin_ctx.fbdev->screen);
434 scr->tscreen = scr->twin_ctx.fbdev->screen;
435 waiter_fd = scr->twin_ctx.fbdev->vt_fd;
437 twin_fbdev_activate(scr->twin_ctx.fbdev);
441 scr->tscreen->event_filter = scr_event_cb;
443 twin_screen_set_background(scr->tscreen,
444 pbt_background_load(scr->tscreen, filename_background));
446 assert(waiter_fd != -1);
448 waiter_register_io(waitset, waiter_fd, WAIT_IN,
449 (void *)pbt_twin_waiter_cb, &scr->twin_ctx);
458 void pbt_window_redraw(twin_window_t *twindow)
460 twin_window_damage(twindow, 0, 0, twindow->pixmap->width,
461 twindow->pixmap->height);
462 //twin_window_queue_paint(twindow);
463 twin_window_draw(twindow);