win_decorations_init.c revision 0bbfda8a
1/*
2 * Window decoration routines -- initializtion time
3 *
4 * These are funcs that are called during ctwm initialization to setup
5 * bits based on general X stuff and/or config file bits.
6 */
7
8
9#include "ctwm.h"
10
11#include <stdio.h>
12#include <stdlib.h>
13
14#include "add_window.h"
15#include "functions_defs.h"
16#include "image.h"
17#include "screen.h"
18
19#include "win_decorations_init.h"
20
21
22/*
23 * Global marker used in config file loading to track "which one we're
24 * currently messing with"
25 */
26static TitleButton *cur_tb = NULL;
27
28
29/* Internal func[s] */
30static void ComputeCommonTitleOffsets(void);
31
32
33
34/*
35 * InitTitlebarButtons - Do all the necessary stuff to load in a titlebar
36 * button.  If we can't find the button, then put in a question; if we can't
37 * find the question mark, something is wrong and we are probably going to be
38 * in trouble later on.
39 */
40void
41InitTitlebarButtons(void)
42{
43	TitleButton *tb;
44	int h;
45
46	/*
47	 * initialize dimensions
48	 */
49	Scr->TBInfo.width = (Scr->TitleHeight -
50	                     2 * (Scr->FramePadding + Scr->ButtonIndent));
51	if(Scr->use3Dtitles)
52		Scr->TBInfo.pad = ((Scr->TitlePadding > 1)
53		                   ? ((Scr->TitlePadding + 1) / 2) : 0);
54	else
55		Scr->TBInfo.pad = ((Scr->TitlePadding > 1)
56		                   ? ((Scr->TitlePadding + 1) / 2) : 1);
57	h = Scr->TBInfo.width - 2 * Scr->TBInfo.border;
58
59	/*
60	 * add in some useful buttons and bindings so that novices can still
61	 * use the system.
62	 */
63	if(!Scr->NoDefaults) {
64		/* insert extra buttons */
65#define MKBTN(bmap, func, isrt) \
66                        CreateTitleButton(TBPM_##bmap, F_##func, "", NULL, \
67                                          isrt, isrt)
68
69		/* Iconify on the left, resize on the right */
70		if(Scr->use3Dtitles) {
71			MKBTN(3DDOT, ICONIFY, false);
72			MKBTN(3DRESIZE, RESIZE, true);
73		}
74		else {
75			MKBTN(ICONIFY, ICONIFY, false);
76			MKBTN(RESIZE, RESIZE, true);
77		}
78
79#undef MKBTN
80
81		/* Default mouse bindings in titlebar/icon/iconmgr as fallback */
82		AddDefaultFuncButtons();
83	}
84
85	/* Init screen-wide dimensions for common titlebar bits */
86	ComputeCommonTitleOffsets();
87
88
89	/*
90	 * load in images and do appropriate centering
91	 */
92	for(tb = Scr->TBInfo.head; tb; tb = tb->next) {
93		tb->image = GetImage(tb->name, Scr->TitleC);
94		if(!tb->image) {
95			/* Couldn't find it, make a question mark */
96			tb->image = GetImage(TBPM_QUESTION, Scr->TitleC);
97			if(!tb->image) {
98				/*
99				 * (sorta) Can't Happen.  Calls a static function that
100				 * builds from static data, so could only possibly fail
101				 * if XCreateBitmapFromData() failed (which should be
102				 * vanishingly rare; memory allocation failures etc).
103				 */
104				fprintf(stderr, "%s:  unable to add titlebar button \"%s\"\n",
105				        ProgramName, tb->name);
106				continue;
107			}
108		}
109		tb->width  = tb->image->width;
110		tb->height = tb->image->height;
111
112		/* Figure centering.  Horizontally... */
113		tb->dstx = (h - tb->width + 1) / 2;
114		if(tb->dstx < 0) {              /* clip to minimize copying */
115			tb->srcx = -(tb->dstx);
116			tb->width = h;
117			tb->dstx = 0;
118		}
119		else {
120			tb->srcx = 0;
121		}
122
123		/* ... and vertically */
124		tb->dsty = (h - tb->height + 1) / 2;
125		if(tb->dsty < 0) {
126			tb->srcy = -(tb->dsty);
127			tb->height = h;
128			tb->dsty = 0;
129		}
130		else {
131			tb->srcy = 0;
132		}
133	}
134}
135
136
137/*
138 * Figure general sizing/locations for titlebar bits.
139 *
140 * For the session; called during ctwm startup.  main() ->
141 * InitTitleBarButtons() -> ComputeCommonTitleOffsets()
142 */
143static void
144ComputeCommonTitleOffsets(void)
145{
146	int buttonwidth = (Scr->TBInfo.width + Scr->TBInfo.pad);
147
148	/* Start "+left" and "-right" with our padding */
149	Scr->TBInfo.leftx = Scr->TBInfo.rightoff = Scr->FramePadding;
150
151	/*
152	 * If there are buttons on the left, add a space to clear the right
153	 * edge of the last one.
154	 */
155	if(Scr->TBInfo.nleft > 0) {
156		Scr->TBInfo.leftx += Scr->ButtonIndent;
157	}
158
159	/*
160	 * Similar on the right, except we need to know how many there are
161	 * and account for all of that to leave enough space open for them.
162	 * We didn't need to do that above because leftx is already relative
163	 * to the end of the window holding them (and so means something like
164	 * "move over this much further"), whereas rightoff is relative to
165	 * the right side of the titlebar (and so means something like "we
166	 * have to leave this much space")?
167	 */
168	if(Scr->TBInfo.nright > 0) {
169		Scr->TBInfo.rightoff += (Scr->ButtonIndent
170		                         + (Scr->TBInfo.nright * buttonwidth)
171		                         - Scr->TBInfo.pad);
172	}
173
174	/*
175	 * titlex does however go from the far-left of the titlebar, so it
176	 * needs to account for the space the left-side buttons use.
177	 */
178	Scr->TBInfo.titlex = (Scr->TBInfo.leftx
179	                      + (Scr->TBInfo.nleft * buttonwidth)
180	                      - Scr->TBInfo.pad
181	                      + Scr->TitlePadding);
182}
183
184
185
186/*
187 * Sets the action for a given {mouse button,set of modifier keys} on the
188 * "current" button.  This happens during initialization, in a few
189 * different ways.
190 *
191 * CreateTitleButton() winds up creating a new button, and setting the
192 * cur_tb global we rely on.  It calls us then to initialize our action
193 * to what it was told (hardcoded for the !NoDefaults case in
194 * InitTitlebarButtons() for fallback config, from the config file when
195 * it's called via GotTitleButton() for the one-line string form of
196 * *TitleButton spec).
197 *
198 * It's also called directly from the config parsing for the block-form
199 * *TitleButton specs, when the cur_tb was previously set by
200 * CreateTitleButton() at the opening of the block.
201 */
202void
203SetCurrentTBAction(int button, int nmods, int func, char *action,
204                   MenuRoot *menuroot)
205{
206	TitleButtonFunc *tbf;
207
208	if(!cur_tb) {
209		fprintf(stderr, "%s: can't find titlebutton\n", ProgramName);
210		return;
211	}
212	for(tbf = cur_tb->funs; tbf; tbf = tbf->next) {
213		if(tbf->num == button && tbf->mods == nmods) {
214			break;
215		}
216	}
217	if(!tbf) {
218		tbf = malloc(sizeof(TitleButtonFunc));
219		if(!tbf) {
220			fprintf(stderr, "%s: out of memory\n", ProgramName);
221			return;
222		}
223		tbf->next = cur_tb->funs;
224		cur_tb->funs = tbf;
225	}
226	tbf->num = button;
227	tbf->mods = nmods;
228	tbf->func = func;
229	tbf->action = action;
230	tbf->menuroot = menuroot;
231}
232
233
234
235/*
236 * XXX This return value is a little pointless.  The only failure it
237 * acknowledges is from malloc(), and that Never Fails On Real
238 * Systems(tm).  And if it does, we're pretty screwed anyway.
239 */
240bool
241CreateTitleButton(char *name, int func, char *action, MenuRoot *menuroot,
242                  bool rightside, bool append)
243{
244	int button;
245	cur_tb = calloc(1, sizeof(TitleButton));
246
247	if(!cur_tb) {
248		fprintf(stderr,
249		        "%s:  unable to allocate %lu bytes for title button\n",
250		        ProgramName, (unsigned long) sizeof(TitleButton));
251		return false;
252	}
253
254	cur_tb->name = name;           /* note that we are not copying */
255	cur_tb->rightside = rightside;
256	if(rightside) {
257		Scr->TBInfo.nright++;
258	}
259	else {
260		Scr->TBInfo.nleft++;
261	}
262
263	for(button = 0; button < MAX_BUTTONS; button++) {
264		SetCurrentTBAction(button + 1, 0, func, action, menuroot);
265	}
266
267	/*
268	 * Cases for list:
269	 *
270	 *     1.  empty list, prepend left       put at head of list
271	 *     2.  append left, prepend right     put in between left and right
272	 *     3.  append right                   put at tail of list
273	 *
274	 * Do not refer to widths and heights yet since buttons not created
275	 * (since fonts not loaded and heights not known).
276	 */
277	if((!Scr->TBInfo.head) || ((!append) && (!rightside))) {    /* 1 */
278		cur_tb->next = Scr->TBInfo.head;
279		Scr->TBInfo.head = cur_tb;
280	}
281	else if(append && rightside) {      /* 3 */
282		TitleButton *t;
283		for(t = Scr->TBInfo.head; t->next; t = t->next) {
284			/* just walking to tail */;
285		}
286		t->next = cur_tb;
287		cur_tb->next = NULL;
288	}
289	else {                              /* 2 */
290		TitleButton *t, *prev = NULL;
291		for(t = Scr->TBInfo.head; t && !t->rightside; t = t->next) {
292			prev = t;
293		}
294		if(prev) {
295			cur_tb->next = prev->next;
296			prev->next = cur_tb;
297		}
298		else {
299			cur_tb->next = Scr->TBInfo.head;
300			Scr->TBInfo.head = cur_tb;
301		}
302	}
303
304	return true;
305}
306