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