xref: /inferno-os/libtk/frame.c (revision c094a1409b780cc543c077e8469fdb28b4c90afb)
1 #include <lib9.h>
2 #include <kernel.h>
3 #include "draw.h"
4 #include "tk.h"
5 #include "frame.h"
6 
7 char*
8 tkframe(TkTop *t, char *arg, char **ret)
9 {
10 	Tk *tk;
11 	char *e;
12 	TkOptab tko[2];
13 	TkName *names;
14 
15 	tk = tknewobj(t, TKframe, sizeof(Tk));
16 	if(tk == nil)
17 		return TkNomem;
18 
19 	tko[0].ptr = tk;
20 	tko[0].optab = tkgeneric;
21 	tko[1].ptr = nil;
22 	names = nil;
23 
24 	e = tkparse(t, arg, tko, &names);
25 	if(e != nil) {
26 		tkfreeobj(tk);
27 		return e;
28 	}
29 	tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd));
30 
31 	e = tkaddchild(t, tk, &names);
32 
33 	tkfreename(names);
34 	if(e != nil) {
35 		tkfreeobj(tk);
36 		return e;
37 	}
38 	tk->name->link = nil;
39 
40 	return tkvalue(ret, "%s", tk->name->name);
41 }
42 
43 /*
44  * Also used for windows, menus, separators
45  */
46 void
47 tkfreeframe(Tk *tk)
48 {
49 	TkWin *tkw;
50 
51 	if((tk->flag & Tkwindow) == 0)
52 		return;
53 
54 	if(tk->type == TKmenu) {
55 		tkw = TKobj(TkWin, tk);
56 		free(tkw->postcmd);
57 		free(tkw->cascade);
58 		free(tkw->cbname);
59 	}
60 
61 	tkunmap(tk);		/* XXX do this only if (tk->flag&Tkswept)==0 ?? */
62 }
63 
64 char*
65 tkdrawframe(Tk *tk, Point orig)
66 {
67 	int bw;
68 	Point p;
69 	Image *i;
70 	Tk *f;
71 	Rectangle r, slaver;		/* dribbling, whipping or just square? */
72 
73 	i = tkimageof(tk);
74 	if(i == nil)
75 		return nil;
76 
77 	p.x = orig.x + tk->act.x + tk->borderwidth;
78 	p.y = orig.y + tk->act.y + tk->borderwidth;
79 
80 	draw(i, rectaddpt(tk->dirty, p), tkgc(tk->env, TkCbackgnd), nil, ZP);
81 
82 	/*
83 	 * doesn't matter about drawing TKseparator
84 	 * oblivious of dirty rect, as it never has any children to sully anyway
85 	 */
86 	if(tk->type == TKseparator) {
87 		r = rectaddpt(tkrect(tk, 1), p);
88 		r.min.x += 4;
89 		r.max.x -= 4;
90 		r.min.y += (Dy(r) - 2)/2;
91 		r.max.y = r.min.y+1;
92 		draw(i, r, tkgc(tk->env, TkCbackgnddark), nil, ZP);
93 		r.min.y += 1;
94 		r.max.y += 1;
95 		draw(i, r, tkgc(tk->env, TkCbackgndlght), nil, ZP);
96 		return nil;
97 	}
98 
99 	/*
100 	 * make sure all the slaves inside the area we've just drawn
101 	 * refresh themselves properly.
102 	 */
103 	for(f = tk->slave; f; f = f->next) {
104 		bw = f->borderwidth;
105 		slaver.min.x = f->act.x;
106 		slaver.min.y = f->act.y;
107 		slaver.max.x = slaver.min.x + f->act.width + 2*bw;
108 		slaver.max.y = slaver.min.y + f->act.height + 2*bw;
109 		if (rectclip(&slaver, tk->dirty)) {
110 			f->flag |= Tkrefresh;
111 			slaver = rectsubpt(slaver, Pt(f->act.x + bw, f->act.y + bw));
112 			combinerect(&f->dirty, slaver);
113 		}
114 	}
115 	p.x -= tk->borderwidth;
116 	p.y -= tk->borderwidth;
117 
118 	if (!rectinrect(tk->dirty, tkrect(tk, 0)))
119 		tkdrawrelief(i, tk, p, TkCbackgnd, tk->relief);
120 	return nil;
121 }
122 
123 /* Frame commands */
124 
125 static char*
126 tkframecget(Tk *tk, char *arg, char **val)
127 {
128 	TkOptab tko[3];
129 
130 	tko[0].ptr = tk;
131 	tko[0].optab = tkgeneric;
132 	tko[1].ptr = nil;
133 	if(tk->flag & Tkwindow){
134 		tko[1].ptr = TKobj(TkWin, tk);
135 		tko[1].optab = tktop;
136 		tko[2].ptr = nil;
137 	}
138 
139 	return tkgencget(tko, arg, val, tk->env->top);
140 }
141 
142 static char*
143 tkframeconf(Tk *tk, char *arg, char **val)
144 {
145 	char *e;
146 	TkGeom g;
147 	int bd;
148 	Point oldp;
149 	TkOptab tko[3];
150 	TkWin *tkw;
151 
152 	tko[0].ptr = tk;
153 	tko[0].optab = tkgeneric;
154 	tko[1].ptr = nil;
155 	tkw = nil;
156 	if(tk->flag & Tkwindow) {
157 		tkw = TKobj(TkWin, tk);
158 		tko[1].ptr = tkw;
159 		tko[1].optab = tktop;
160 		tko[2].ptr = nil;
161 		oldp = tkw->act;
162 	}
163 
164 	if(*arg == '\0')
165 		return tkconflist(tko, val);
166 
167 	if(tkw != nil){
168 		/*
169 		 * see whether only -x or -y is being configured,
170 		 * in which case just move the window; don't redraw
171 		 * everything
172 		 */
173 		e = tkparse(tk->env->top, arg, &tko[1], nil);
174 		if(e == nil){
175 			if(!eqpt(oldp, tkw->req))
176 				tkmovewin(tk, tkw->req);
177 			return nil;
178 		}
179 	}
180 
181 	g = tk->req;
182 	bd = tk->borderwidth;
183 	e = tkparse(tk->env->top, arg, tko, nil);
184 	tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd));
185 	tk->req.x = tk->act.x;
186 	tk->req.y = tk->act.y;
187 	tkgeomchg(tk, &g, bd);
188 	if(tkw != nil && !eqpt(oldp, tkw->act))
189 		tkmovewin(tk, tkw->req);
190 
191 	tk->dirty = tkrect(tk, 1);
192 
193 	return e;
194 }
195 
196 static char*
197 tkframesuspend(Tk *tk, char *arg, char **val)
198 {
199 	USED(arg);
200 	USED(val);
201 	if((tk->flag & Tkwindow) == 0)
202 		return TkNotwm;
203 	tk->flag |= Tksuspended;
204 	return nil;
205 }
206 
207 static char*
208 tkframemap(Tk *tk, char *arg, char **val)
209 {
210 	USED(arg);
211 	USED(val);
212 	if(tk->flag & Tkwindow)
213 		return tkmap(tk);
214 	return TkNotwm;
215 }
216 
217 static char*
218 tkframeunmap(Tk *tk, char *arg, char **val)
219 {
220 	USED(arg);
221 	USED(val);
222 	if(tk->flag & Tkwindow) {
223 		tkunmap(tk);
224 		return nil;
225 	}
226 	return TkNotwm;
227 }
228 
229 static void
230 tkframefocusorder(Tk *tk)
231 {
232 	int i, n;
233 	Tk *sub;
234 	TkWinfo *inf;
235 
236 	n = 0;
237 	for (sub = tk->slave; sub != nil; sub = sub->next)
238 		n++;
239 
240 	if (n == 0)
241 		return;
242 
243 	inf = malloc(sizeof(*inf) * n);
244 	if (inf == nil)
245 		return;
246 	i = 0;
247 	for (sub = tk->slave; sub != nil; sub = sub->next) {
248 		inf[i].w = sub;
249 		inf[i].r = rectaddpt(tkrect(sub, 1), Pt(sub->act.x, sub->act.y));
250 		i++;
251 	}
252 	tksortfocusorder(inf, n);
253 	for (i = 0; i < n; i++)
254 		tkappendfocusorder(inf[i].w);
255 	free(inf);
256 }
257 
258 static
259 TkCmdtab tkframecmd[] =
260 {
261 	"cget",			tkframecget,
262 	"configure",		tkframeconf,
263 	"map",			tkframemap,
264 	"unmap",		tkframeunmap,
265 	"suspend",		tkframesuspend,
266 	nil
267 };
268 
269 TkMethod framemethod = {
270 	"frame",
271 	tkframecmd,
272 	tkfreeframe,
273 	tkdrawframe,
274 	nil,
275 	nil,
276 	tkframefocusorder
277 };
278