summaryrefslogtreecommitdiff
path: root/src/buffer.c
blob: 48dbdca343104446575dd92a8b60771d22de1066 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
/**
 * @file
 * @section AUTHORS
 *
 *  Authors:
 *       Eamon Walsh <ewalsh@tycho.nsa.gov>
 *
 * @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 <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#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);
        }
}