1 /*
2  * IceWM
3  *
4  * Copyright (C) 1997-2001 Marko Macek
5  */
6 #include "config.h"
7 #include "wmcontainer.h"
8 #include "wmframe.h"
9 #include "wmmgr.h"
10 #include "wmapp.h"
11 #include "prefs.h"
12 
YClientContainer(YWindow * parent,YFrameWindow * frame,int depth,Visual * visual,Colormap cmap)13 YClientContainer::YClientContainer(YWindow *parent, YFrameWindow *frame,
14                                    int depth, Visual *visual, Colormap cmap)
15     : YWindow(parent, None, depth, visual, cmap)
16 {
17     fFrame = frame;
18     fHaveGrab = false;
19     fHaveActionGrab = false;
20 
21     setStyle(wsManager | wsNoExpose);
22     setPointer(YWMApp::leftPointer);
23     setTitle("Container");
24     show();
25 }
26 
~YClientContainer()27 YClientContainer::~YClientContainer() {
28     if (destroyed() == false)
29         releaseButtons();
30 }
31 
handleButton(const XButtonEvent & button)32 void YClientContainer::handleButton(const XButtonEvent &button) {
33     if (clientMouseActions) {
34         unsigned int k = button.button + XK_Pointer_Button1 - 1;
35         unsigned int m = KEY_MODMASK(button.state);
36         unsigned int vm = VMod(m);
37 
38         if (gMouseWinSize.eq(k, vm)) {
39             XAllowEvents(xapp->display(), AsyncPointer, CurrentTime);
40 
41             int px = button.x + x();
42             int py = button.y + y();
43             int gx = (px * 3 / (int)width() - 1);
44             int gy = (py * 3 / (int)height() - 1);
45             if (gx < 0) gx = -1;
46             if (gx > 0) gx = 1;
47             if (gy < 0) gy = -1;
48             if (gy > 0) gy = 1;
49             bool doMove = (gx == 0 && gy == 0) ? true : false;
50             int mx, my;
51             if (doMove) {
52                 mx = px;
53                 my = py;
54             } else {
55                 mx = button.x_root;
56                 my = button.y_root;
57             }
58             if ((doMove && getFrame()->canMove()) ||
59                 (!doMove && getFrame()->canSize()))
60             {
61                 getFrame()->startMoveSize(doMove, true,
62                                           gx, gy,
63                                           mx, my);
64             }
65             return ;
66         }
67         else if (gMouseWinMove.eq(k, vm)) {
68             XAllowEvents(xapp->display(), AsyncPointer, CurrentTime);
69 
70             if (getFrame()->canMove()) {
71                 int px = button.x + x();
72                 int py = button.y + y();
73                 getFrame()->startMoveSize(true, true,
74                                           0, 0,
75                                           px, py);
76             }
77             return ;
78         }
79         else if (gMouseWinRaise.eq(k, vm)
80             && (gMouseWinRaise != gMouseWinLower || getFrame()->canRaise()))
81         {
82             XAllowEvents(xapp->display(), AsyncPointer, CurrentTime);
83             getFrame()->wmRaise();
84             return ;
85         }
86         else if (gMouseWinLower.eq(k, vm)) {
87             XAllowEvents(xapp->display(), AsyncPointer, CurrentTime);
88             getFrame()->wmLower();
89             return ;
90         }
91     }
92 
93     bool doRaise = false;
94     bool doActivate = false;
95     bool firstClick = false;
96 
97     if (!(button.state & ControlMask) &&
98         (buttonRaiseMask & (1 << (button.button - 1))) &&
99         (!useMouseWheel || (button.button != 4 && button.button != 5)))
100     {
101         if (focusOnClickClient) {
102             if (!getFrame()->isTypeDock()) {
103                 doActivate = (getFrame() != manager->getFocus());
104                 if (getFrame()->canFocusByMouse() && !getFrame()->focused())
105                     firstClick = true;
106             }
107         }
108         if (raiseOnClickClient && getFrame()->canRaise()) {
109             doRaise = true;
110             firstClick = true;
111         }
112     }
113 
114     ///!!! it might be nice if this was per-window option (app-request)
115     if (!firstClick || passFirstClickToClient)
116         XAllowEvents(xapp->display(), ReplayPointer, CurrentTime);
117     else
118         XAllowEvents(xapp->display(), AsyncPointer, CurrentTime);
119     xapp->sync();
120 
121     ///!!! do this first?
122     if (doActivate)
123         getFrame()->focus();
124     if (doRaise && (!doActivate || !raiseOnFocus))
125         getFrame()->wmRaise();
126 }
127 
128 // manage button grab on frame window to capture clicks to client window
129 // we want to keep the grab when:
130 //    focusOnClickClient && not focused
131 // || raiseOnClickClient && not can be raised
132 
133 // ('not on top' != 'can be raised')
134 // the difference is when we have transients and explicitFocus
135 // also there is the difference with layers and multiple workspaces
136 
grabButtons()137 void YClientContainer::grabButtons() {
138     grabActions();
139     if (!fHaveGrab && (clickFocus ||
140                        focusOnClickClient ||
141                        raiseOnClickClient))
142     {
143         for (int button = Button1; button <= Button3; ++button) {
144             if (buttonRaiseMask & (1 << (button - Button1))) {
145                 XGrabButton(xapp->display(), button, AnyModifier,
146                             handle(), True, ButtonPressMask,
147                             GrabModeSync, GrabModeAsync, None, None);
148             }
149         }
150         fHaveGrab = true;
151     }
152 }
153 
releaseButtons()154 void YClientContainer::releaseButtons() {
155     if (fHaveGrab) {
156         fHaveGrab = false;
157         for (int button = Button1; button <= Button3; ++button) {
158             if (buttonRaiseMask & (1 << (button - Button1))) {
159                 XUngrabButton(xapp->display(), button, AnyModifier, handle());
160             }
161         }
162         fHaveActionGrab = false;
163     }
164     grabActions();
165 }
166 
regrabMouse()167 void YClientContainer::regrabMouse() {
168     fHaveActionGrab = false;
169     releaseButtons();
170     grabButtons();
171 }
172 
grabActions()173 void YClientContainer::grabActions() {
174     if (clientMouseActions && fHaveActionGrab == false) {
175         WMKey grab[] = { gMouseWinMove, gMouseWinSize,
176                          gMouseWinRaise, gMouseWinLower };
177         const int count = int ACOUNT(grab) - (gMouseWinRaise == gMouseWinLower);
178         for (int i = 0; i < count; ++i) {
179             int button = int(grab[i].key) - XK_Pointer_Button1 + Button1;
180             if (inrange(button, Button1, Button3)) {
181                 grabVButton(button, grab[i].mod);
182             }
183         }
184         fHaveActionGrab = true;
185     }
186 }
187 
handleConfigureRequest(const XConfigureRequestEvent & configureRequest)188 void YClientContainer::handleConfigureRequest(const XConfigureRequestEvent &configureRequest) {
189     MSG(("configure request in frame"));
190 
191     if (getFrame() &&
192         configureRequest.window == getFrame()->client()->handle())
193     {
194         getFrame()->configureClient(configureRequest);
195     }
196 }
197 
handleMapRequest(const XMapRequestEvent & mapRequest)198 void YClientContainer::handleMapRequest(const XMapRequestEvent &mapRequest) {
199     if (mapRequest.window == getFrame()->client()->handle()
200         && getFrame()->isPassive() == false)
201     {
202         if (getFrame()->isUnmapped()) {
203             manager->lockFocus();
204             getFrame()->makeMapped();
205             manager->unlockFocus();
206         }
207         bool doActivate = true;
208         getFrame()->updateFocusOnMap(doActivate);
209         if (doActivate) {
210             getFrame()->activateWindow(true);
211         }
212     }
213 }
214 
handleCrossing(const XCrossingEvent & crossing)215 void YClientContainer::handleCrossing(const XCrossingEvent &crossing) {
216     if (getFrame() && pointerColormap) {
217         if (crossing.type == EnterNotify)
218             manager->setColormapWindow(getFrame());
219         else if (crossing.type == LeaveNotify &&
220                  crossing.detail != NotifyInferior &&
221                  crossing.mode == NotifyNormal &&
222                  manager->colormapWindow() == getFrame())
223         {
224             manager->setColormapWindow(nullptr);
225         }
226     }
227 }
228 
229 
230 // vim: set sw=4 ts=4 et:
231