1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2 // Texture.cc for Blackbox - an X11 Window manager
3 // Copyright (c) 2001 - 2005 Sean 'Shaleh' Perry <shaleh@debian.org>
4 // Copyright (c) 1997 - 2000, 2002 - 2005
5 // Bradley T Hughes <bhughes at trolltech.com>
6 //
7 // Permission is hereby granted, free of charge, to any person obtaining a
8 // copy of this software and associated documentation files (the "Software"),
9 // to deal in the Software without restriction, including without limitation
10 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 // and/or sell copies of the Software, and to permit persons to whom the
12 // Software is furnished to do so, subject to the following conditions:
13 //
14 // The above copyright notice and this permission notice shall be included in
15 // all copies or substantial portions of the Software.
16 //
17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 // DEALINGS IN THE SOFTWARE.
24
25 #include "Texture.hh"
26 #include "Display.hh"
27 #include "Pen.hh"
28 #include "Resource.hh"
29
30 #include <algorithm>
31 #include <cstdlib>
32
33 #include <X11/Xlib.h>
34 #include <ctype.h>
35
36
setColor1(const bt::Color & new_color)37 void bt::Texture::setColor1(const bt::Color &new_color) {
38 c1 = new_color;
39
40 unsigned char r, g, b, rr, gg, bb;
41 r = c1.red();
42 g = c1.green();
43 b = c1.blue();
44
45 // calculate the light color
46 rr = r + (r >> 1);
47 gg = g + (g >> 1);
48 bb = b + (b >> 1);
49 if (rr < r)
50 rr = ~0;
51 if (gg < g)
52 gg = ~0;
53 if (bb < b)
54 bb = ~0;
55 lc.setRGB(rr, gg, bb);
56
57 // calculate the shadow color
58 rr = (r >> 2) + (r >> 1);
59 gg = (g >> 2) + (g >> 1);
60 bb = (b >> 2) + (b >> 1);
61 if (rr > r)
62 rr = 0;
63 if (gg > g)
64 gg = 0;
65 if (bb > b)
66 bb = 0;
67 sc.setRGB(rr, gg, bb);
68 }
69
70
setDescription(const std::string & d)71 void bt::Texture::setDescription(const std::string &d) {
72 descr = tolower(d);
73 if (descr.find("parentrelative") != std::string::npos) {
74 setTexture(bt::Texture::Parent_Relative);
75 } else {
76 setTexture(0);
77
78 if (descr.find("gradient") != std::string::npos) {
79 addTexture(bt::Texture::Gradient);
80 if (descr.find("crossdiagonal") != std::string::npos)
81 addTexture(bt::Texture::CrossDiagonal);
82 else if (descr.find("rectangle") != std::string::npos)
83 addTexture(bt::Texture::Rectangle);
84 else if (descr.find("pyramid") != std::string::npos)
85 addTexture(bt::Texture::Pyramid);
86 else if (descr.find("pipecross") != std::string::npos)
87 addTexture(bt::Texture::PipeCross);
88 else if (descr.find("elliptic") != std::string::npos)
89 addTexture(bt::Texture::Elliptic);
90 else if (descr.find("horizontal") != std::string::npos)
91 addTexture(bt::Texture::Horizontal);
92 else if (descr.find("vertical") != std::string::npos)
93 addTexture(bt::Texture::Vertical);
94 else
95 addTexture(bt::Texture::Diagonal);
96 } else {
97 addTexture(bt::Texture::Solid);
98 }
99
100 if (descr.find("sunken") != std::string::npos)
101 addTexture(bt::Texture::Sunken);
102 else if (descr.find("flat") != std::string::npos)
103 addTexture(bt::Texture::Flat);
104 else
105 addTexture(bt::Texture::Raised);
106
107 if (descr.find("interlaced") != std::string::npos)
108 addTexture(bt::Texture::Interlaced);
109
110 if (descr.find("border") != std::string::npos)
111 addTexture(bt::Texture::Border);
112 }
113 }
114
115
operator =(const bt::Texture & tt)116 bt::Texture& bt::Texture::operator=(const bt::Texture &tt) {
117 descr = tt.descr;
118
119 c1 = tt.c1;
120 c2 = tt.c2;
121 bc = tt.bc;
122 lc = tt.lc;
123 sc = tt.sc;
124 t = tt.t;
125 bw = tt.bw;
126
127 return *this;
128 }
129
130
textureResource(const Display & display,unsigned int screen,const bt::Resource & resource,const std::string & name,const std::string & className,const std::string & defaultColor)131 bt::Texture bt::textureResource(const Display &display,
132 unsigned int screen,
133 const bt::Resource &resource,
134 const std::string &name,
135 const std::string &className,
136 const std::string &defaultColor)
137 {
138 Texture texture;
139
140 std::string description = resource.read(name + ".appearance",
141 className + ".Appearance",
142 resource.read(name,
143 className));
144 if (description.empty()) {
145 // no such texture, use the default color in a flat solid texture
146 texture.setDescription("flat solid");
147 texture.setColor1(Color::namedColor(display, screen, defaultColor));
148 return texture;
149 }
150
151 texture.setDescription(description);
152
153 if ((texture.texture() & bt::Texture::Gradient)
154 || (texture.texture() & bt::Texture::Interlaced)) {
155 std::string color1, color2;
156 color1 = resource.read(name + ".color1",
157 className + ".Color1",
158 resource.read(name + ".color",
159 className + ".Color",
160 defaultColor));
161 color2 = resource.read(name + ".color2",
162 className + ".Color2",
163 resource.read(name + ".colorTo",
164 className + ".ColorTo",
165 defaultColor));
166 texture.setColor1(Color::namedColor(display, screen, color1));
167 texture.setColor2(Color::namedColor(display, screen, color2));
168 } else {
169 std::string color1;
170 color1 = resource.read(name + ".backgroundColor",
171 className + ".BackgroundColor",
172 resource.read(name + ".color",
173 className + ".Color",
174 defaultColor));
175 texture.setColor1(Color::namedColor(display, screen, color1));
176 }
177
178 if (texture.texture() & bt::Texture::Border) {
179 Color borderColor =
180 Color::namedColor(display, screen,
181 resource.read(name + ".borderColor",
182 className + ".BorderColor",
183 "black"));
184 texture.setBorderColor(borderColor);
185
186 const std::string bstr =
187 resource.read(name + ".borderWidth", className + ".BorderWidth", "1");
188 unsigned int bw = static_cast<unsigned int>(std::strtoul(bstr.c_str(), 0, 0));
189 texture.setBorderWidth(bw);
190 }
191
192 return texture;
193 }
194
195
textureResource(const Display & display,unsigned int screen,const Resource & resource,const std::string & name,const std::string & className,const Texture & defaultTexture)196 bt::Texture bt::textureResource(const Display &display,
197 unsigned int screen,
198 const Resource &resource,
199 const std::string &name,
200 const std::string &className,
201 const Texture &defaultTexture)
202 {
203 std::string description = resource.read(name + ".appearance",
204 className + ".Appearance",
205 resource.read(name,
206 className));
207 if (description.empty()) {
208 // no such texture, return the default
209 return defaultTexture;
210 }
211 return textureResource(display, screen, resource, name, className);
212 }
213
214
drawTexture(unsigned int screen,const Texture & texture,Drawable drawable,const Rect & trect,const Rect & urect,Pixmap pixmap)215 void bt::drawTexture(unsigned int screen,
216 const Texture &texture,
217 Drawable drawable,
218 const Rect &trect,
219 const Rect &urect,
220 Pixmap pixmap) {
221 Pen pen(screen, texture.color1());
222
223 if ((texture.texture() & Texture::Gradient) && pixmap) {
224 XCopyArea(pen.XDisplay(), pixmap, drawable, pen.gc(),
225 urect.x() - trect.x(), urect.y() - trect.y(),
226 urect.width(), urect.height(), urect.x(), urect.y());
227 return;
228 } else if (!(texture.texture() & Texture::Solid)) {
229 XClearArea(pen.XDisplay(), drawable,
230 urect.x(), urect.y(), urect.width(), urect.height(), False);
231 return; // might be Parent_Relative or empty
232 }
233
234 XFillRectangle(pen.XDisplay(), drawable, pen.gc(),
235 urect.x(), urect.y(), urect.width(), urect.height());
236
237 int bw = static_cast<int>(texture.borderWidth());
238 if (texture.texture() & bt::Texture::Border &&
239 (trect.left() == urect.left() || trect.right() == urect.right() ||
240 trect.top() == urect.top() || trect.bottom() == urect.bottom())) {
241 Pen penborder(screen, texture.borderColor());
242 penborder.setLineWidth(bw);
243 XDrawRectangle(pen.XDisplay(), drawable, penborder.gc(),
244 trect.x() + bw / 2, trect.y() + bw / 2,
245 trect.width() - bw, trect.height() - bw);
246 }
247
248 if (texture.texture() & bt::Texture::Interlaced) {
249 Pen peninterlace(screen, texture.color2());
250 int begin = trect.top() + bw;
251 while (begin < urect.top()) begin += 2;
252 int end = std::min(trect.bottom() - bw, urect.bottom());
253
254 for (int i = begin; i <= end; i += 2)
255 XDrawLine(pen.XDisplay(), drawable, peninterlace.gc(),
256 std::max(trect.left() + bw, urect.left()), i,
257 std::min(trect.right() - bw, urect.right()), i);
258 }
259
260 if ((trect.left() + bw >= urect.left() ||
261 trect.right() - bw <= urect.right() ||
262 trect.top() + bw >= urect.top() ||
263 trect.bottom() - bw <= urect.bottom())) {
264 // draw bevel
265 Pen penlight(screen, texture.lightColor());
266 Pen penshadow(screen, texture.shadowColor());
267
268 if (texture.texture() & bt::Texture::Raised) {
269 XDrawLine(pen.XDisplay(), drawable, penshadow.gc(),
270 trect.left() + bw, trect.bottom() - bw,
271 trect.right() - bw, trect.bottom() - bw);
272 XDrawLine(pen.XDisplay(), drawable, penshadow.gc(),
273 trect.right() - bw, trect.bottom() - bw,
274 trect.right() - bw, trect.top() + bw);
275
276 XDrawLine(pen.XDisplay(), drawable, penlight.gc(),
277 trect.left() + bw, trect.top() + bw,
278 trect.right() - bw, trect.top() + bw);
279 XDrawLine(pen.XDisplay(), drawable, penlight.gc(),
280 trect.left() + bw, trect.bottom() - bw,
281 trect.left() + bw, trect.top() + bw);
282 } else if (texture.texture() & bt::Texture::Sunken) {
283 XDrawLine(pen.XDisplay(), drawable, penlight.gc(),
284 trect.left() + bw, trect.bottom() - bw,
285 trect.right() - bw, trect.bottom() - bw);
286 XDrawLine(pen.XDisplay(), drawable, penlight.gc(),
287 trect.right() - bw, trect.bottom() - bw,
288 trect.right() - bw, trect.top() + bw);
289
290 XDrawLine(pen.XDisplay(), drawable, penshadow.gc(),
291 trect.left() + bw, trect.top() + bw,
292 trect.right() - bw, trect.top() + bw);
293 XDrawLine(pen.XDisplay(), drawable, penshadow.gc(),
294 trect.left() + bw, trect.bottom() - bw,
295 trect.left() + bw, trect.top() + bw);
296 }
297 }
298 }
299