/** * @file * @section AUTHORS * * Authors: * Eamon Walsh * * @section LICENSE * * This file is in the public domain. * * @section DESCRIPTION * * This is the implementation of buffer objects, which represent regions of * memory, provided by clients, that contain graphical content. * * There are also two "special" types of buffer that are provided by the * server itself; these are the background images for the server screen and * the combined desktop, respectively. All other buffers come from clients * and, in Linpicker, are associated with framebuffers that are shared out by * the frontend devices in the guest and which are mapped into Linpicker's * memory for use. * * The implementation here includes the functions to create and manipulate * buffer objects. The integration of these into the desktop presentation is * done by the display subsystem, which has various hooks in this code which * are used to respond to buffer creation and changes; these calls are * prefixed with display_buffer_. */ #include #include #include #include #include "view.h" #include "client.h" #include "display.h" static int buffer_position_background(struct buffer *b) { DFBRectangle bpos, spos; int guest_width, guest_height; guest_width = display_get_width(); guest_height = display_get_height(); bpos.x = 0; bpos.y = 0; bpos.w = b->desc.width; bpos.h = b->desc.height; b->xoff = (bpos.w >= guest_width) ? 0 : (guest_width - bpos.w) / 2; b->yoff = (bpos.h >= guest_height) ? 0 : (guest_height - bpos.h) / 2; spos.x = b->xoff; spos.y = b->yoff; spos.w = bpos.w; spos.h = bpos.h; return view_set_viewport(b->bg_view, &bpos, &spos, 1); } static void buffer_free(struct buffer *b) { /* remove buffer from its client list */ LIST_REMOVE(b, client_next); /* free resources */ b->bsurface->Release(b->bsurface); free(b); } struct buffer * lookup_buffer(int domid, int buf_id) { struct client *c = client_lookup(domid); struct buffer *b; LIST_FOREACH(b, &c->buffers, client_next) if (b->id == buf_id) return b; return NULL; } struct buffer * buffer_new(struct client *c, const DFBSurfaceDescription *desc, unsigned int flags) { struct buffer *b; IDirectFBSurface *surf; struct view *v; if (c->num_buffers >= c->max_buffers) return NULL; /* create DirectFB surface */ if (dfb->CreateSurface(dfb, desc, &surf) != DFB_OK) return NULL; /* get memory for the buffer header */ b = calloc(1, sizeof(struct buffer)); if (!b) return NULL; TAILQ_INIT(&b->views); b->id = c->num_buffers; b->client = c; b->flags = flags; memcpy(&b->desc, desc, sizeof(DFBSurfaceDescription)); b->bsurface = surf; /* bump client view count */ c->num_buffers++; /* add buffer to the client's buffer list */ LIST_INSERT_HEAD(&c->buffers, b, client_next); /* create background view for this buffer */ v = view_new(b->client, b, 0, VIEW_FLAGS_BACKGROUND); if (!v) { buffer_free(b); return NULL; } b->bg_view = v; buffer_position_background(b); /* notify display subsystem */ if (display_buffer_new(b) < 0) { view_remove(v); buffer_free(b); return NULL; } return b; } int buffer_resize(struct buffer *b, const DFBSurfaceDescription *desc) { struct view *v; IDirectFBSurface *oldsurf, *newsurf; /* create new DirectFB surface */ if (dfb->CreateSurface(dfb, desc, &newsurf) != DFB_OK) return -1; memcpy(&b->desc, desc, sizeof(DFBSurfaceDescription)); oldsurf = b->bsurface; b->bsurface = newsurf; /* go through all the views and change over to the new surface */ TAILQ_FOREACH(v, &b->views, buffer_next) view_update_surface(v); /* re-center the background view on the screen */ buffer_position_background(b); /* free old surface */ oldsurf->Release(oldsurf); return 0; } void buffer_remove(struct buffer *b) { /* close all views */ while (!TAILQ_EMPTY(&b->views)) view_remove(TAILQ_FIRST(&b->views)); /* call display hook */ display_buffer_remove(b); /* release resources */ buffer_free(b); } void buffer_refresh(struct buffer *b, int x, int y, int w, int h) { int x1, y1, x2, y2; struct view *v; /* for all views at this buffer */ TAILQ_FOREACH(v, &b->views, buffer_next) { /* calculate intersection of refresh area and view area */ x1 = MAX(x, v->bpos.x); y1 = MAX(y, v->bpos.y); x2 = MIN(x + w, v->bpos.x + v->bpos.w); y2 = MIN(y + h, v->bpos.y + v->bpos.h); /* redraw intersection */ if ((x1 <= x2) && (y1 <= y2)) view_refresh(v); } }