1/*
2 * Various drawing routines.
3 *
4 * These are generalized routines that are used in multiple places in the
5 * codebase.  A number of other functions that are "drawing" related are
6 * left in various places through the codebase; some are only used in one
7 * file, and are left there for internal linkage, while others are
8 * part of a more abstract subdivision (e.g., the window decoration bits
9 * in win_decorations.c) and so belong there.
10 */
11
12#include "ctwm.h"
13
14
15#include "screen.h"
16#include "gram.tab.h"
17#include "occupation.h"
18#include "vscreen.h"
19
20#include "drawing.h"
21
22
23
24/*
25 * "3D border" drawings are used all over the place, not just in the
26 * obvious usage as window borders.
27 */
28#define FBGC(gc, fix_fore, fix_back)\
29    Gcv.foreground = fix_fore;\
30    Gcv.background = fix_back;\
31    XChangeGC(dpy, gc, GCForeground|GCBackground,&Gcv)
32
33void
34Draw3DBorder(Window w, int x, int y, int width, int height, int bw,
35             ColorPair cp, ButtonState state, bool fill, bool forcebw)
36{
37	int           i;
38	XGCValues     gcv;
39	unsigned long gcm;
40
41	if((width < 1) || (height < 1)) {
42		return;
43	}
44	if(Scr->Monochrome != COLOR) {
45		if(fill) {
46			gcm = GCFillStyle;
47			gcv.fill_style = FillOpaqueStippled;
48			XChangeGC(dpy, Scr->BorderGC, gcm, &gcv);
49			XFillRectangle(dpy, w, Scr->BorderGC, x, y, width, height);
50		}
51		gcm  = 0;
52		gcm |= GCLineStyle;
53		gcv.line_style = (state == on) ? LineSolid : LineDoubleDash;
54		gcm |= GCFillStyle;
55		gcv.fill_style = FillSolid;
56		XChangeGC(dpy, Scr->BorderGC, gcm, &gcv);
57		for(i = 0; i < bw; i++) {
58			XDrawLine(dpy, w, Scr->BorderGC, x,                 y + i,
59			          x + width - i - 1, y + i);
60			XDrawLine(dpy, w, Scr->BorderGC, x + i,                  y,
61			          x + i, y + height - i - 1);
62		}
63
64		gcm  = 0;
65		gcm |= GCLineStyle;
66		gcv.line_style = (state == on) ? LineDoubleDash : LineSolid;
67		gcm |= GCFillStyle;
68		gcv.fill_style = FillSolid;
69		XChangeGC(dpy, Scr->BorderGC, gcm, &gcv);
70		for(i = 0; i < bw; i++) {
71			XDrawLine(dpy, w, Scr->BorderGC, x + width - i - 1,          y + i,
72			          x + width - i - 1, y + height - 1);
73			XDrawLine(dpy, w, Scr->BorderGC, x + i,         y + height - i - 1,
74			          x + width - 1, y + height - i - 1);
75		}
76		return;
77	}
78
79	if(fill) {
80		FBGC(Scr->BorderGC, cp.back, cp.fore);
81		XFillRectangle(dpy, w, Scr->BorderGC, x, y, width, height);
82	}
83	if(Scr->BeNiceToColormap) {
84		int dashoffset = 0;
85
86		gcm  = 0;
87		gcm |= GCLineStyle;
88		gcv.line_style = (forcebw) ? LineSolid : LineDoubleDash;
89		gcm |= GCBackground;
90		gcv.background = cp.back;
91		XChangeGC(dpy, Scr->BorderGC, gcm, &gcv);
92
93		if(state == on) {
94			XSetForeground(dpy, Scr->BorderGC, Scr->Black);
95		}
96		else {
97			XSetForeground(dpy, Scr->BorderGC, Scr->White);
98		}
99		for(i = 0; i < bw; i++) {
100			XDrawLine(dpy, w, Scr->BorderGC, x + i,     y + dashoffset,
101			          x + i, y + height - i - 1);
102			XDrawLine(dpy, w, Scr->BorderGC, x + dashoffset,    y + i,
103			          x + width - i - 1, y + i);
104			dashoffset = 1 - dashoffset;
105		}
106		XSetForeground(dpy, Scr->BorderGC, ((state == on) ? Scr->White : Scr->Black));
107		for(i = 0; i < bw; i++) {
108			XDrawLine(dpy, w, Scr->BorderGC, x + i,         y + height - i - 1,
109			          x + width - 1, y + height - i - 1);
110			XDrawLine(dpy, w, Scr->BorderGC, x + width - i - 1,          y + i,
111			          x + width - i - 1, y + height - 1);
112		}
113		return;
114	}
115	if(state == on) {
116		FBGC(Scr->BorderGC, cp.shadd, cp.shadc);
117	}
118	else             {
119		FBGC(Scr->BorderGC, cp.shadc, cp.shadd);
120	}
121	for(i = 0; i < bw; i++) {
122		XDrawLine(dpy, w, Scr->BorderGC, x,                 y + i,
123		          x + width - i - 1, y + i);
124		XDrawLine(dpy, w, Scr->BorderGC, x + i,                  y,
125		          x + i, y + height - i - 1);
126	}
127
128	if(state == on) {
129		FBGC(Scr->BorderGC, cp.shadc, cp.shadd);
130	}
131	else             {
132		FBGC(Scr->BorderGC, cp.shadd, cp.shadc);
133	}
134	for(i = 0; i < bw; i++) {
135		XDrawLine(dpy, w, Scr->BorderGC, x + width - i - 1,          y + i,
136		          x + width - i - 1, y + height - 1);
137		XDrawLine(dpy, w, Scr->BorderGC, x + i,         y + height - i - 1,
138		          x + width - 1, y + height - i - 1);
139	}
140	return;
141}
142
143#undef FBGC
144
145
146
147/*
148 * Paint a button representing a workspace.  This is used in the
149 * workspace manager window when it button mode, as well as in the
150 * f.occupy window.
151 */
152void
153PaintWsButton(PWBType which, VirtualScreen *vs, Window w,
154              char *label, ColorPair cp, ButtonState state)
155{
156	int    bwidth, bheight;
157	MyFont font;
158	int    hspace, vspace;
159
160	if(which == WSPCWINDOW) {
161		bwidth  = vs->wsw->bwidth;
162		bheight = vs->wsw->bheight;
163		font    = Scr->workSpaceMgr.buttonFont;
164	}
165	else if(which == OCCUPYWINDOW) {
166		OccupyWindow *occwin = Scr->workSpaceMgr.occupyWindow;
167		bwidth  = occwin->bwidth;
168		bheight = occwin->bheight;
169		font    = occwin->font;
170	}
171	else if(which == OCCUPYBUTTON) {
172		OccupyWindow *occwin = Scr->workSpaceMgr.occupyWindow;
173		bwidth  = occwin->owidth;
174		bheight = occwin->bheight;
175		font    = occwin->font;
176	}
177	else {
178		return;
179	}
180
181	{
182		int        strWid, strHei;
183		XRectangle inc_rect;
184		XRectangle logical_rect;
185
186		XmbTextExtents(font.font_set, label, strlen(label), &inc_rect,
187		               &logical_rect);
188		strHei = logical_rect.height;
189		vspace = ((bheight + strHei - font.descent) / 2);
190		strWid = logical_rect.width;
191		hspace = (bwidth - strWid) / 2;
192	}
193
194	if(hspace < (Scr->WMgrButtonShadowDepth + 1)) {
195		hspace = Scr->WMgrButtonShadowDepth + 1;
196	}
197	XClearWindow(dpy, w);
198
199	if(Scr->Monochrome == COLOR) {
200		Draw3DBorder(w, 0, 0, bwidth, bheight, Scr->WMgrButtonShadowDepth,
201		             cp, state, true, false);
202
203		switch(Scr->workSpaceMgr.buttonStyle) {
204			case STYLE_NORMAL:
205				break;
206
207			case STYLE_STYLE1:
208				Draw3DBorder(w,
209				             Scr->WMgrButtonShadowDepth - 1,
210				             Scr->WMgrButtonShadowDepth - 1,
211				             bwidth  - 2 * Scr->WMgrButtonShadowDepth + 2,
212				             bheight - 2 * Scr->WMgrButtonShadowDepth + 2,
213				             1, cp, (state == on) ? off : on, true, false);
214				break;
215
216			case STYLE_STYLE2:
217				Draw3DBorder(w,
218				             Scr->WMgrButtonShadowDepth / 2,
219				             Scr->WMgrButtonShadowDepth / 2,
220				             bwidth  - Scr->WMgrButtonShadowDepth,
221				             bheight - Scr->WMgrButtonShadowDepth,
222				             1, cp, (state == on) ? off : on, true, false);
223				break;
224
225			case STYLE_STYLE3:
226				Draw3DBorder(w,
227				             1,
228				             1,
229				             bwidth  - 2,
230				             bheight - 2,
231				             1, cp, (state == on) ? off : on, true, false);
232				break;
233		}
234		FB(cp.fore, cp.back);
235		XmbDrawString(dpy, w, font.font_set, Scr->NormalGC, hspace, vspace,
236		              label, strlen(label));
237	}
238	else {
239		Draw3DBorder(w, 0, 0, bwidth, bheight, Scr->WMgrButtonShadowDepth,
240		             cp, state, true, false);
241		if(state == on) {
242			FB(cp.fore, cp.back);
243			XmbDrawImageString(dpy, w, font.font_set, Scr->NormalGC, hspace, vspace,
244			                   label, strlen(label));
245		}
246		else {
247			FB(cp.back, cp.fore);
248			XmbDrawImageString(dpy, w, font.font_set, Scr->NormalGC, hspace, vspace,
249			                   label, strlen(label));
250		}
251	}
252}
253