1 // IconButton.cc
2 // Copyright (c) 2003 - 2006 Henrik Kinnunen (fluxgen at fluxbox dot org)
3 //                and Simon Bowden    (rathnor at users.sourceforge.net)
4 //
5 // Permission is hereby granted, free of charge, to any person obtaining a
6 // copy of this software and associated documentation files (the "Software"),
7 // to deal in the Software without restriction, including without limitation
8 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 // and/or sell copies of the Software, and to permit persons to whom the
10 // Software is furnished to do so, subject to the following conditions:
11 //
12 // The above copyright notice and this permission notice shall be included in
13 // all copies or substantial portions of the Software.
14 //
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 // DEALINGS IN THE SOFTWARE.
22 
23 #include "IconButton.hh"
24 #include "IconbarTool.hh"
25 #include "IconbarTheme.hh"
26 
27 #include "Screen.hh"
28 
29 #include "FbTk/App.hh"
30 #include "FbTk/Command.hh"
31 #include "FbTk/EventManager.hh"
32 #include "FbTk/ImageControl.hh"
33 #include "FbTk/TextUtils.hh"
34 
35 #include <X11/Xutil.h>
36 #ifdef SHAPE
37 #include <X11/extensions/shape.h>
38 #endif // SHAPE
39 
40 
IconButton(const FbTk::FbWindow & parent,FbTk::ThemeProxy<IconbarTheme> & focused_theme,FbTk::ThemeProxy<IconbarTheme> & unfocused_theme,Focusable & win)41 IconButton::IconButton(const FbTk::FbWindow &parent,
42         FbTk::ThemeProxy<IconbarTheme> &focused_theme,
43         FbTk::ThemeProxy<IconbarTheme> &unfocused_theme, Focusable &win):
44     FbTk::TextButton(parent, focused_theme->text().font(), win.title()),
45     m_win(win),
46     m_icon_window(*this, 1, 1, 1, 1,
47                   ExposureMask |EnterWindowMask | LeaveWindowMask |
48                   ButtonPressMask | ButtonReleaseMask),
49     m_use_pixmap(true),
50     m_has_tooltip(false),
51     m_theme(win, focused_theme, unfocused_theme),
52     m_pm(win.screen().imageControl()) {
53 
54     m_signals.join(m_win.titleSig(),
55                    MemFunIgnoreArgs(*this, &IconButton::clientTitleChanged));
56 
57     m_signals.join(m_win.focusSig(),
58                    MemFunIgnoreArgs(*this, &IconButton::reconfigAndClear));
59 
60     m_signals.join(m_win.attentionSig(),
61                    MemFunIgnoreArgs(*this, &IconButton::reconfigAndClear));
62 
63     FbTk::EventManager::instance()->add(*this, m_icon_window);
64 
65     reconfigTheme();
66     refreshEverything(false);
67 }
68 
~IconButton()69 IconButton::~IconButton() {
70     // ~FbWindow cleans event manager
71     if (m_has_tooltip)
72         m_win.screen().hideTooltip();
73 }
74 
75 
exposeEvent(XExposeEvent & event)76 void IconButton::exposeEvent(XExposeEvent &event) {
77     if (m_icon_window == event.window)
78         m_icon_window.clear();
79     else
80         FbTk::TextButton::exposeEvent(event);
81 }
82 
enterNotifyEvent(XCrossingEvent & ev)83 void IconButton::enterNotifyEvent(XCrossingEvent &ev) {
84     m_has_tooltip = true;
85     showTooltip();
86 }
87 
leaveNotifyEvent(XCrossingEvent & ev)88 void IconButton::leaveNotifyEvent(XCrossingEvent &ev) {
89     m_has_tooltip = false;
90     m_win.screen().hideTooltip();
91 }
92 
moveResize(int x,int y,unsigned int width,unsigned int height)93 void IconButton::moveResize(int x, int y,
94                             unsigned int width, unsigned int height) {
95 
96     FbTk::TextButton::moveResize(x, y, width, height);
97 
98     if (m_icon_window.width() != FbTk::Button::width() ||
99         m_icon_window.height() != FbTk::Button::height()) {
100         reconfigTheme();
101         refreshEverything(false); // update icon window
102     }
103 }
104 
resize(unsigned int width,unsigned int height)105 void IconButton::resize(unsigned int width, unsigned int height) {
106     FbTk::TextButton::resize(width, height);
107     if (m_icon_window.width() != FbTk::Button::width() ||
108         m_icon_window.height() != FbTk::Button::height()) {
109         reconfigTheme();
110         refreshEverything(false); // update icon window
111     }
112 }
113 
showTooltip()114 void IconButton::showTooltip() {
115    int xoffset = 1;
116    if (m_icon_pixmap.drawable() != 0)
117        xoffset = m_icon_window.x() + m_icon_window.width() + 1;
118 
119     if (FbTk::TextButton::textExceeds(xoffset))
120         m_win.screen().showTooltip(m_win.title());
121     else
122         m_win.screen().hideTooltip();
123 }
124 
clear()125 void IconButton::clear() {
126     setupWindow();
127 }
128 
clearArea(int x,int y,unsigned int width,unsigned int height,bool exposure)129 void IconButton::clearArea(int x, int y,
130                            unsigned int width, unsigned int height,
131                            bool exposure) {
132     FbTk::TextButton::clearArea(x, y,
133                                 width, height, exposure);
134 }
135 
setPixmap(bool use)136 void IconButton::setPixmap(bool use) {
137     if (m_use_pixmap != use) {
138         m_use_pixmap = use;
139         refreshEverything(false);
140     }
141 }
142 
reconfigTheme()143 void IconButton::reconfigTheme() {
144 
145     setFont(m_theme->text().font());
146     setGC(m_theme->text().textGC());
147     setBorderWidth(m_theme->border().width());
148     setBorderColor(m_theme->border().color());
149     setJustify(m_theme->text().justify());
150     setAlpha(parent()->alpha());
151 
152     if (m_theme->texture().usePixmap()) {
153         m_pm.reset(m_win.screen().imageControl().renderImage(
154                            width(), height(), m_theme->texture(),
155                            orientation()));
156         setBackgroundPixmap(m_pm);
157     } else{
158         m_pm.reset(0);
159         setBackgroundColor(m_theme->texture().color());
160     }
161 
162     updateBackground(false);
163 }
164 
reconfigAndClear()165 void IconButton::reconfigAndClear() {
166     reconfigTheme();
167     clear();
168 }
169 
refreshEverything(bool setup)170 void IconButton::refreshEverything(bool setup) {
171 
172     Display *display = FbTk::App::instance()->display();
173     int screen = m_win.screen().screenNumber();
174 
175     if (m_use_pixmap && m_win.icon().pixmap().drawable() != None) {
176         // setup icon window
177         m_icon_window.show();
178         unsigned int w = width();
179         unsigned int h = height();
180         FbTk::translateSize(orientation(), w, h);
181         int iconx = 1;
182         int icony = 1;
183         unsigned int neww;
184         unsigned int newh = h;
185         if (newh > 2*static_cast<unsigned>(icony))
186             newh -= 2*icony;
187         else
188             newh = 1;
189         neww = newh;
190 
191         FbTk::translateCoords(orientation(), iconx, icony, w, h);
192         FbTk::translatePosition(orientation(), iconx, icony, neww, newh, 0);
193 
194         m_icon_window.moveResize(iconx, icony, neww, newh);
195 
196         m_icon_pixmap.copy(m_win.icon().pixmap().drawable(),
197                            DefaultDepth(display, screen), screen);
198         m_icon_pixmap.scale(m_icon_window.width(), m_icon_window.height());
199 
200         // rotate the icon or not?? lets go not for now, and see what they say...
201         // need to rotate mask too if we do do this
202         m_icon_pixmap.rotate(orientation());
203 
204         m_icon_window.setBackgroundPixmap(m_icon_pixmap.drawable());
205     } else {
206         // no icon pixmap
207         m_icon_window.move(0, 0);
208         m_icon_window.hide();
209         m_icon_pixmap = 0;
210     }
211 
212     if(m_icon_pixmap.drawable() && m_win.icon().mask().drawable() != None) {
213         m_icon_mask.copy(m_win.icon().mask().drawable(), 0, 0);
214         m_icon_mask.scale(m_icon_pixmap.width(), m_icon_pixmap.height());
215         m_icon_mask.rotate(orientation());
216     } else
217         m_icon_mask = 0;
218 
219 #ifdef SHAPE
220 
221     XShapeCombineMask(display,
222                       m_icon_window.drawable(),
223                       ShapeBounding,
224                       0, 0,
225                       m_icon_mask.drawable(),
226                       ShapeSet);
227 
228 #endif // SHAPE
229 
230     if (setup) {
231         setupWindow();
232     } else {
233         m_icon_window.clear();
234     }
235 
236 
237 }
238 
clientTitleChanged()239 void IconButton::clientTitleChanged() {
240     refreshEverything(true);
241 
242     if (m_has_tooltip)
243         showTooltip();
244 }
245 
setupWindow()246 void IconButton::setupWindow() {
247     m_icon_window.clear();
248     setText(m_win.title());
249     FbTk::TextButton::clear();
250 }
251 
drawText(int x,int y,FbTk::FbDrawable * drawable)252 void IconButton::drawText(int x, int y, FbTk::FbDrawable *drawable) {
253 
254     // offset text
255     if (m_icon_pixmap.drawable() != 0)
256         FbTk::TextButton::drawText(m_icon_window.x() + m_icon_window.width() + 1, y, drawable);
257     else
258         FbTk::TextButton::drawText(1, y, drawable);
259 }
260 
setOrientation(FbTk::Orientation orient)261 bool IconButton::setOrientation(FbTk::Orientation orient) {
262     if (orientation() == orient)
263         return true;
264 
265     if (FbTk::TextButton::setOrientation(orient)) {
266         int iconx = 1, icony = 1;
267         unsigned int tmpw = width(), tmph = height();
268         FbTk::translateSize(orient, tmpw, tmph);
269         FbTk::translateCoords(orient, iconx, icony, tmpw, tmph);
270         FbTk::translatePosition(orient, iconx, icony, m_icon_window.width(), m_icon_window.height(), 0);
271         m_icon_window.move(iconx, icony);
272         return true;
273     }
274     return false;
275 }
276 
277