1 /*
2  * IceWM
3  *
4  * Copyright (C) 1997-2001 Marko Macek
5  */
6 #include "config.h"
7 #include "wmminiicon.h"
8 #include "wmframe.h"
9 #include "wmmgr.h"
10 #include "yxapp.h"
11 #include "prefs.h"
12 
13 MiniIcon::ArrayType MiniIcon::fIcons;
14 
acceptableDimensions(unsigned w,unsigned h) const15 bool MiniIcon::acceptableDimensions(unsigned w, unsigned h) const {
16     unsigned lower = YIcon::hugeSize() / 2;
17     unsigned upper = 3 * YIcon::hugeSize() / 2;
18     return inrange(w, lower, upper) && inrange(h, lower, upper);
19 }
20 
client() const21 inline YFrameClient* MiniIcon::client() const {
22     return fFrame->client();
23 }
24 
iconWindow()25 Window MiniIcon::iconWindow() {
26     return Elvis(fIconWindow, handle());
27 }
28 
MiniIcon(YFrameWindow * frame)29 MiniIcon::MiniIcon(YFrameWindow *frame):
30     YWindow(),
31     fFrame(frame),
32     fIconWindow(client()->iconWindowHint())
33 {
34     setStyle(wsOverrideRedirect | wsBackingMapped);
35     setSize(YIcon::hugeSize(), YIcon::hugeSize());
36     setTitle("MiniIcon");
37     setPosition(-1, -1);
38 
39     if (fIconWindow) {
40         Window root, parent;
41         xsmart<Window> child;
42         unsigned border, depth, count;
43         if (XGetGeometry(xapp->display(), fIconWindow, &root,
44                          &fIconGeometry.xx, &fIconGeometry.yy,
45                          &fIconGeometry.ww, &fIconGeometry.hh,
46                          &border, &depth) == False) {
47             fIconWindow = None;
48         }
49         else if (acceptableDimensions(fIconGeometry.ww, fIconGeometry.hh)) {
50             int x = (int(YIcon::hugeSize()) - int(fIconGeometry.ww)) / 2
51                   - int(border);
52             int y = (int(YIcon::hugeSize()) - int(fIconGeometry.hh)) / 2
53                   - int(border);
54             XAddToSaveSet(xapp->display(), fIconWindow);
55             XReparentWindow(xapp->display(), fIconWindow, handle(), x, y);
56             if (XQueryTree(xapp->display(), handle(), &root, &parent, &child,
57                    &count) == True && count == 1 && child[0] == fIconWindow)
58             {
59                 XMapWindow(xapp->display(), fIconWindow);
60                 XWMHints* hints = XGetWMHints(xapp->display(), fIconWindow);
61                 if (hints) {
62                     if ((hints->flags & StateHint) &&
63                         hints->initial_state != WithdrawnState) {
64                         // Fix initial_state for icewm restart to succeed.
65                         hints->initial_state = WithdrawnState;
66                         XSetWMHints(xapp->display(), fIconWindow, hints);
67                     }
68                     XFree(hints);
69                 }
70             }
71             else {
72                 fIconWindow = None;
73             }
74         }
75         else {
76             fIconWindow = None;
77         }
78     }
79 
80     updateIcon();
81 
82     fIcons += this;
83 }
84 
~MiniIcon()85 MiniIcon::~MiniIcon() {
86     if (fIconWindow && client() && !client()->destroyed()) {
87         XUnmapWindow(xapp->display(), fIconWindow);
88         XReparentWindow(xapp->display(), fIconWindow, xapp->root(),
89                         fIconGeometry.xx, fIconGeometry.hh);
90         XRemoveFromSaveSet(xapp->display(), fIconWindow);
91     }
92     findRemove(fIcons, this);
93 }
94 
handleExpose(const XExposeEvent & expose)95 void MiniIcon::handleExpose(const XExposeEvent& expose) {
96     if (expose.count == 0) {
97         repaint();
98     }
99 }
100 
repaint()101 void MiniIcon::repaint() {
102     if (fIconWindow == None) {
103         Graphics g(*this);
104         paint(g, geometry());
105     }
106 }
107 
paint(Graphics & g,const YRect & r)108 void MiniIcon::paint(Graphics &g, const YRect &r) {
109     if (fIconWindow == None) {
110         ref<YIcon> icon(fFrame->clientIcon());
111         if (icon != null && icon->huge() != null) {
112             int x = (YIcon::hugeSize() - icon->huge()->width()) / 2;
113             int y = (YIcon::hugeSize() - icon->huge()->height()) / 2;
114             if (xapp->alpha()) {
115                icon->draw(g, x, y, YIcon::hugeSize());
116             }
117             // g.drawImage(icon->huge(), x, y);
118             else {
119                 icon->huge()->copy(g, x, y);
120             }
121         }
122     }
123 }
124 
updateIcon()125 void MiniIcon::updateIcon() {
126     if (fIconWindow)
127         return;
128 #ifdef CONFIG_SHAPE
129     ref<YIcon> icon(fFrame->clientIcon());
130     if (icon != null && icon->huge() != null) {
131         ref<YImage> image = icon->huge();
132         ref<YPixmap> pixmap = image->renderToPixmap(depth());
133         if (pixmap != null && pixmap->mask()) {
134             int x = (YIcon::hugeSize() - pixmap->width()) / 2;
135             int y = (YIcon::hugeSize() - pixmap->height()) / 2;
136             XShapeCombineMask(xapp->display(), handle(), ShapeBounding,
137                               x, y, pixmap->mask(), ShapeSet);
138         }
139     }
140 #endif
141 }
142 
updatePosition()143 void MiniIcon::updatePosition() {
144     int xpos = x();
145     int ypos = y();
146     manager->getIconPosition(this, &xpos, &ypos);
147     if (xpos != x() || ypos != y()) {
148         setPosition(xpos, ypos);
149     }
150 }
151 
stack()152 void MiniIcon::stack() {
153     beneath(manager->bottomWindow());
154 }
155 
show()156 void MiniIcon::show() {
157     updatePosition();
158     if (x() != -1 || y() != -1) {
159         stack();
160         YWindow::show();
161     }
162 }
163 
handleButton(const XButtonEvent & button)164 void MiniIcon::handleButton(const XButtonEvent &button) {
165     if (button.type == ButtonPress) {
166         if (!(button.state & ControlMask) &&
167             (buttonRaiseMask & (1 << (button.button - Button1))))
168         {
169             raise();
170         }
171         YWindow::handleButton(button);
172     }
173     else if (button.type == ButtonRelease) {
174         YWindow::handleButton(button);
175     }
176 }
177 
handleClick(const XButtonEvent & up,int)178 void MiniIcon::handleClick(const XButtonEvent &up, int /*count*/) {
179     if (up.button == Button3) {
180         getFrame()->popupSystemMenu(this, up.x_root, up.y_root,
181                                     YPopupWindow::pfCanFlipVertical |
182                                     YPopupWindow::pfCanFlipHorizontal |
183                                     YPopupWindow::pfPopupMenu);
184     }
185     else if (up.button == Button1) {
186         if (up.state & xapp->AltMask) {
187             stack();
188         } else {
189             if (!(up.state & ControlMask))
190                 getFrame()->wmRaise();
191             getFrame()->activate();
192         }
193     }
194 }
195 
handleCrossing(const XCrossingEvent & crossing)196 void MiniIcon::handleCrossing(const XCrossingEvent &crossing) {
197     if (crossing.type == EnterNotify && !dragging()) {
198         mstring title(fFrame->getIconTitle());
199         if (title.isEmpty())
200             title = fFrame->getTitle();
201         setToolTip(title);
202     }
203     YWindow::handleCrossing(crossing);
204 }
205 
handleBeginDrag(const XButtonEvent & d,const XMotionEvent & m)206 bool MiniIcon::handleBeginDrag(const XButtonEvent& d, const XMotionEvent& m) {
207     setToolTip(null);
208     raise();
209     return true;
210 }
211 
handleEndDrag(const XButtonEvent & d,const XButtonEvent & u)212 void MiniIcon::handleEndDrag(const XButtonEvent& d, const XButtonEvent& u) {
213     stack();
214 }
215 
handleDrag(const XButtonEvent & down,const XMotionEvent & motion)216 void MiniIcon::handleDrag(const XButtonEvent &down, const XMotionEvent &motion) {
217     if (down.button) {
218         int mx, my, Mx, My;
219         manager->getWorkArea(fFrame, &mx, &my, &Mx, &My);
220         int x = clamp(motion.x_root - down.x, mx, Mx - int(width()));
221         int y = clamp(motion.y_root - down.y, my, My - int(height()));
222         setPosition(x, y);
223     }
224 }
225 
handleKey(const XKeyEvent & key)226 bool MiniIcon::handleKey(const XKeyEvent& key) {
227     if (key.type == KeyPress) {
228         KeySym k = keyCodeToKeySym(key.keycode);
229         unsigned int m = KEY_MODMASK(key.state);
230         unsigned int vm = VMod(m);
231         if (IS_WMKEY(k, vm, gKeyWinClose)) {
232             fFrame->actionPerformed(actionClose);
233         }
234         else if (IS_WMKEY(k, vm, gKeyWinLower)) {
235             fFrame->actionPerformed(actionLower);
236         }
237         else if (IS_WMKEY(k, vm, gKeyWinRestore)) {
238             fFrame->actionPerformed(actionRestore);
239         }
240         else if (k == XK_Return || k == XK_KP_Enter) {
241             fFrame->activate();
242         }
243         else if (k == XK_Menu || (k == XK_F10 && m == ShiftMask)) {
244             fFrame->popupSystemMenu(fFrame);
245         }
246     }
247     return true;
248 }
249 
250 // vim: set sw=4 ts=4 et:
251