xref: /plan9-contrib/sys/src/libdraw/alloc.c (revision 7dd7cddf99dd7472612f1413b4da293630e6b1bc)
1 #include <u.h>
2 #include <libc.h>
3 #include <draw.h>
4 
5 extern ulong
6 drawld2chan[] = {
7 	GREY1,
8 	GREY2,
9 	GREY4,
10 	CMAP8,
11 };
12 
13 int log2[] = { -1, 0, 1, -1, 2, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1, 4, -1, -1, -1, -1, -1, -1, -1, 4 /* BUG */, -1, -1, -1, -1, -1, -1, -1, 5 };
14 
15 Image*
16 allocimage(Display *d, Rectangle r, ulong chan, int repl, ulong val)
17 {
18 	return _allocimage(nil, d, r, chan, repl, val, 0, 0);
19 }
20 
21 Image*
22 _allocimage(Image *ai, Display *d, Rectangle r, ulong chan, int repl, ulong val, int screenid, int refresh)
23 {
24 	uchar *a;
25 	char *err;
26 	Image *i;
27 	Rectangle clipr;
28 	int id;
29 	int depth;
30 
31 	err = 0;
32 	i = 0;
33 
34 	if(chan == 0){
35 		werrstr("bad channel descriptor");
36 		return nil;
37 	}
38 
39 	depth = chantodepth(chan);
40 	if(depth == 0){
41 		err = "bad channel descriptor";
42     Error:
43 		if(err)
44 			werrstr("allocimage: %s", err);
45 		else
46 			werrstr("allocimage: %r");
47 		free(i);
48 		return 0;
49 	}
50 
51 	/* flush pending data so we don't get error allocating the image */
52 	flushimage(d, 0);
53 	a = bufimage(d, 1+4+4+1+4+1+4*4+4*4+4);
54 	if(a == 0)
55 		goto Error;
56 	d->imageid++;
57 	id = d->imageid;
58 	a[0] = 'b';
59 	BPLONG(a+1, id);
60 	BPLONG(a+5, screenid);
61 	a[9] = refresh;
62 	BPLONG(a+10, chan);
63 	a[14] = repl;
64 	BPLONG(a+15, r.min.x);
65 	BPLONG(a+19, r.min.y);
66 	BPLONG(a+23, r.max.x);
67 	BPLONG(a+27, r.max.y);
68 	if(repl)
69 		/* huge but not infinite, so various offsets will leave it huge, not overflow */
70 		clipr = Rect(-0x3FFFFFFF, -0x3FFFFFFF, 0x3FFFFFFF, 0x3FFFFFFF);
71 	else
72 		clipr = r;
73 	BPLONG(a+31, clipr.min.x);
74 	BPLONG(a+35, clipr.min.y);
75 	BPLONG(a+39, clipr.max.x);
76 	BPLONG(a+43, clipr.max.y);
77 	BPLONG(a+47, val);
78 	if(flushimage(d, 0) < 0)
79 		goto Error;
80 
81 	if(ai)
82 		i = ai;
83 	else{
84 		i = malloc(sizeof(Image));
85 		if(i == nil){
86 			a = bufimage(d, 1+4);
87 			if(a){
88 				a[0] = 'f';
89 				BPLONG(a+1, id);
90 				flushimage(d, 0);
91 			}
92 			goto Error;
93 		}
94 	}
95 	i->display = d;
96 	i->id = id;
97 	i->depth = depth;
98 	i->chan = chan;
99 	i->r = r;
100 	i->clipr = clipr;
101 	i->repl = repl;
102 	i->screen = 0;
103 	i->next = 0;
104 	return i;
105 }
106 
107 Image*
108 namedimage(Display *d, char *name)
109 {
110 	uchar *a;
111 	char *err, buf[12*12+1];
112 	Image *i;
113 	int id, n;
114 	ulong chan;
115 
116 	err = 0;
117 	i = 0;
118 
119 	n = strlen(name);
120 	if(n >= 256){
121 		err = "name too long";
122     Error:
123 		if(err)
124 			werrstr("namedimage: %s", err);
125 		else
126 			werrstr("namedimage: %r");
127 		if(i)
128 			free(i);
129 		return 0;
130 	}
131 	/* flush pending data so we don't get error allocating the image */
132 	flushimage(d, 0);
133 	a = bufimage(d, 1+4+1+n);
134 	if(a == 0)
135 		goto Error;
136 	d->imageid++;
137 	id = d->imageid;
138 	a[0] = 'n';
139 	BPLONG(a+1, id);
140 	a[5] = n;
141 	memmove(a+6, name, n);
142 	if(flushimage(d, 0) < 0)
143 		goto Error;
144 
145 	if(read(d->ctlfd, buf, sizeof buf) < 12*12)
146 		goto Error;
147 
148 	i = malloc(sizeof(Image));
149 	if(i == nil){
150 	Error1:
151 		a = bufimage(d, 1+4);
152 		if(a){
153 			a[0] = 'f';
154 			BPLONG(a+1, id);
155 			flushimage(d, 0);
156 		}
157 		goto Error;
158 	}
159 	i->display = d;
160 	i->id = id;
161 	if((chan=strtochan(buf+2*12))==0){
162 		werrstr("bad channel from devdraw");
163 		goto Error1;
164 	}
165 	i->chan = chan;
166 	i->depth = chantodepth(chan);
167 	i->repl = atoi(buf+3*12);
168 	i->r.min.x = atoi(buf+4*12);
169 	i->r.min.y = atoi(buf+5*12);
170 	i->r.max.x = atoi(buf+6*12);
171 	i->r.max.y = atoi(buf+7*12);
172 	i->clipr.min.x = atoi(buf+8*12);
173 	i->clipr.min.y = atoi(buf+9*12);
174 	i->clipr.max.x = atoi(buf+10*12);
175 	i->clipr.max.y = atoi(buf+11*12);
176 	i->screen = 0;
177 	i->next = 0;
178 	return i;
179 }
180 
181 int
182 nameimage(Image *i, char *name, int in)
183 {
184 	uchar *a;
185 	int n;
186 
187 	n = strlen(name);
188 	a = bufimage(i->display, 1+4+1+1+n);
189 	if(a == 0)
190 		return 0;
191 	a[0] = 'N';
192 	BPLONG(a+1, i->id);
193 	a[5] = in;
194 	a[6] = n;
195 	memmove(a+7, name, n);
196 	if(flushimage(i->display, 0) < 0)
197 		return 0;
198 	return 1;
199 }
200 
201 int
202 _freeimage1(Image *i)
203 {
204 	uchar *a;
205 	Display *d;
206 	Image *w;
207 
208 	if(i == 0)
209 		return 0;
210 	/* make sure no refresh events occur on this if we block in the write */
211 	d = i->display;
212 	/* flush pending data so we don't get error deleting the image */
213 	flushimage(d, 0);
214 	a = bufimage(d, 1+4);
215 	if(a == 0)
216 		return -1;
217 	a[0] = 'f';
218 	BPLONG(a+1, i->id);
219 	if(i->screen){
220 		w = d->windows;
221 		if(w == i)
222 			d->windows = i->next;
223 		else
224 			while(w){
225 				if(w->next == i){
226 					w->next = i->next;
227 					break;
228 				}
229 				w = w->next;
230 			}
231 	}
232 	if(flushimage(d, i->screen!=0) < 0)
233 		return -1;
234 
235 	return 0;
236 }
237 
238 int
239 freeimage(Image *i)
240 {
241 	int ret;
242 
243 	ret = _freeimage1(i);
244 	free(i);
245 	return ret;
246 }
247