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