1 /*
2 * IceWM
3 *
4 * Copyright (C) 1997-2002 Marko Macek
5 */
6 #include "config.h"
7 #include "wmframe.h"
8 #include "wmmgr.h"
9 #include "wmtitle.h"
10 #include "wmapp.h"
11 #include "wmcontainer.h"
12 #include "wmtaskbar.h"
13 #include "workspaces.h"
14 #include "wpixmaps.h"
15 #include "ymenuitem.h"
16 #include "yrect.h"
17 #include "prefs.h"
18
updateMenu()19 void YFrameWindow::updateMenu() {
20 YMenu *windowMenu = this->windowMenu();
21 // enable all commands
22 windowMenu->setActionListener(this);
23 windowMenu->enableCommand(actionNull);
24
25 if (!canMaximize()) {
26 windowMenu->disableCommand(actionMaximize);
27 windowMenu->disableCommand(actionMaximizeVert);
28 windowMenu->disableCommand(actionMaximizeHoriz);
29 }
30 if (!canMinimize())
31 windowMenu->disableCommand(actionMinimize);
32 if (!canRestore())
33 windowMenu->disableCommand(actionRestore);
34 if (isMinimized() || isHidden() || !canSize() || !visibleNow())
35 windowMenu->disableCommand(actionSize);
36 if (isMinimized() || isHidden() || !canMove() || !visibleNow())
37 windowMenu->disableCommand(actionMove);
38 if (!canLower())
39 windowMenu->disableCommand(actionLower);
40 if (!canRaise())
41 windowMenu->disableCommand(actionRaise);
42 if (!canHide())
43 windowMenu->disableCommand(actionHide);
44 if (!canRollup())
45 windowMenu->disableCommand(actionRollup);
46 if (!canClose())
47 windowMenu->disableCommand(actionClose);
48
49 bool full = isFullscreen();
50 bool vert = !full && isMaximizedVert();
51 bool hori = !full && isMaximizedHoriz();
52 windowMenu->checkCommand(actionMinimize, isMinimized());
53 windowMenu->checkCommand(actionMaximize, vert && hori);
54 windowMenu->checkCommand(actionMaximizeVert, vert && !hori);
55 windowMenu->checkCommand(actionMaximizeHoriz, hori && !vert);
56 windowMenu->checkCommand(actionFullscreen, full);
57 windowMenu->checkCommand(actionHide, isHidden());
58 windowMenu->checkCommand(actionRollup, isRollup());
59 windowMenu->checkCommand(actionOccupyAllOrCurrent, isAllWorkspaces());
60 #if DO_NOT_COVER_OLD
61 windowMenu->checkCommand(actionDoNotCover, doNotCover());
62 #endif
63 updateSubmenus();
64 }
65
updateSubmenus()66 void YFrameWindow::updateSubmenus() {
67 if (moveMenu) {
68 YMenuItem *item = windowMenu()->findSubmenu(moveMenu);
69 if (item) {
70 bool enable = !isAllWorkspaces() && 1 < workspaceCount;
71 item->setEnabled(enable);
72 if (enable) {
73 moveMenu->updatePopup();
74 moveMenu->setActionListener(this);
75
76 for (int i(0); i < moveMenu->itemCount(); i++) {
77 item = moveMenu->getItem(i);
78 if (item && item->getAction() == workspaceActionMoveTo[i]) {
79 bool const e(i == getWorkspace());
80 item->setEnabled(!e);
81 item->setChecked(e);
82 }
83 }
84 }
85 }
86 }
87
88 if (layerMenu) {
89 YMenuItem *item = windowMenu()->findSubmenu(layerMenu);
90 if (item) {
91 layerMenu->updatePopup();
92 layerMenu->setActionListener(this);
93
94 int layer = WinLayerCount - 1;
95 for (int j(0); j < layerMenu->itemCount(); j++) {
96 YMenuItem* item = layerMenu->getItem(j);
97 YAction action = item->getAction();
98 while (action < layerActionSet[layer] && 0 < layer) {
99 --layer;
100 }
101 if (action == layerActionSet[layer]) {
102 bool const e(layer == getActiveLayer());
103 item->setEnabled(!e);
104 item->setChecked(e);
105 }
106 }
107 }
108 }
109
110 if (tileMenu) {
111 YMenuItem *item = windowMenu()->findSubmenu(tileMenu);
112 if (item) {
113 bool enable = canMove();
114 item->setEnabled(enable);
115 if (enable) {
116 tileMenu->updatePopup();
117 tileMenu->setActionListener(this);
118 }
119 }
120 }
121
122 YMenuItem* item = windowMenu()->findAction(actionToggleTray);
123 if (item) {
124 bool checked = (getTrayOption() != WinTrayIgnore);
125 bool enabled = notbit(frameOptions(), foIgnoreTaskBar);
126 item->setChecked(checked);
127 item->setEnabled(enabled || checked);
128 }
129
130 #if 0
131 if (trayMenu) for (int k(0); k < trayMenu->itemCount(); k++) {
132 item = trayMenu->getItem(k);
133 for (int opt(0); opt < WinTrayOptionCount; opt++)
134 if (item && item->getAction() == trayOptionActionSet[opt]) {
135 bool const e(opt == getTrayOption());
136 item->setEnabled(!e);
137 item->setChecked(e);
138 }
139 }
140 #endif
141 }
142
setShape()143 void YFrameWindow::setShape() {
144 #ifdef CONFIG_SHAPE
145 if (!shapes.supported)
146 return ;
147
148 if (client()->shaped()) {
149 MSG(("setting shape w=%d, h=%d", width(), height()));
150 if (isRollup() || isIconic()) {
151 XRectangle full;
152 full.x = 0;
153 full.y = 0;
154 full.width = width();
155 full.height = height();
156 XShapeCombineRectangles(xapp->display(), handle(),
157 ShapeBounding,
158 0, 0, &full, 1,
159 ShapeSet, Unsorted);
160 } else {
161 XRectangle rect[6];
162 int nrect = 0;
163
164 if ((frameDecors() & (fdResize | fdBorder)) == fdResize + fdBorder) {
165 rect[0].x = 0;
166 rect[0].y = 0;
167 rect[0].width = width();
168 rect[0].height = borderY();
169
170 rect[1] = rect[0];
171 rect[1].y = height() - borderY();
172
173 rect[2].x = 0;
174 rect[2].y = borderY();
175 rect[2].width = borderX();
176 rect[2].height = height() - 2 * borderY();
177
178 rect[3] = rect[2];
179 rect[3].x = width() - borderX();
180
181 nrect = 4;
182 }
183
184 if (titleY() > 0) {
185 rect[nrect].x = borderX();
186 rect[nrect].y = borderY();
187 rect[nrect].width = width() - 2 * borderX();
188 rect[nrect].height = titleY();
189 nrect++;
190 }
191
192 if (nrect != 0)
193 XShapeCombineRectangles(xapp->display(), handle(),
194 ShapeBounding,
195 0, 0, rect, nrect,
196 ShapeSet, Unsorted);
197 XShapeCombineShape(xapp->display(), handle(),
198 ShapeBounding,
199 borderX(),
200 borderY() + titleY(),
201 client()->handle(),
202 ShapeBounding, nrect ? ShapeUnion : ShapeSet);
203 }
204 }
205 #endif
206 }
207
layoutShape()208 void YFrameWindow::layoutShape() {
209 #ifdef CONFIG_SHAPE
210 if (fShapeWidth != width() ||
211 fShapeHeight != height() ||
212 fShapeTitleY != titleY() ||
213 fShapeBorderX != borderX() ||
214 fShapeBorderY != borderY() ||
215 fShapeDecors != frameDecors() ||
216 fShapeTitle != getTitle())
217 {
218 fShapeWidth = width();
219 fShapeHeight = height();
220 fShapeTitleY = titleY();
221 fShapeBorderX = borderX();
222 fShapeBorderY = borderY();
223 fShapeDecors = frameDecors();
224 fShapeTitle = getTitle();
225
226 if (shapes.supported &&
227 (frameDecors() & fdBorder) &&
228 !isIconic() &&
229 !isFullscreen())
230 {
231 int const a(focused());
232 int const t((frameDecors() & fdResize) ? 0 : 1);
233
234 Pixmap shape = XCreatePixmap(xapp->display(), desktop->handle(),
235 width(), height(), 1);
236 Graphics g(shape, width(), height(), 1);
237
238 g.setColorPixel(1);
239 g.fillRect(0, 0, width(), height());
240
241 const int
242 xTL(frameTL[t][a] != null ? frameTL[t][a]->width() : 0),
243 xTR(width() - (frameTR[t][a] != null ? frameTR[t][a]->width() : 0)),
244 xBL(frameBL[t][a] != null ? frameBL[t][a]->width() : 0),
245 xBR(width() - (frameBR[t][a] != null ? frameBR[t][a]->width() : 0));
246 const int
247 yTL(frameTL[t][a] != null ? frameTL[t][a]->height() : 0),
248 yBL(height() - (frameBL[t][a] != null ? frameBL[t][a]->height() : 0)),
249 yTR(frameTR[t][a] != null ? frameTR[t][a]->height() : 0),
250 yBR(height() - (frameBR[t][a] != null ? frameBR[t][a]->height() : 0));
251
252 if (frameTL[t][a] != null) {
253 g.copyDrawable(frameTL[t][a]->mask(), 0, 0,
254 frameTL[t][a]->width(), frameTL[t][a]->height(),
255 0, 0);
256 if (protectClientWindow)
257 g.fillRect(borderX(), borderY(),
258 frameTL[t][a]->width() - borderX(),
259 frameTL[t][a]->height() - borderY());
260 }
261 if (frameTR[t][a] != null) {
262 g.copyDrawable(frameTR[t][a]->mask(), 0, 0,
263 frameTR[t][a]->width(), frameTR[t][a]->height(),
264 xTR, 0);
265 if (protectClientWindow)
266 g.fillRect(xTR, borderY(),
267 frameTR[t][a]->width() - borderX(),
268 frameTR[t][a]->height() - borderY());
269 }
270 if (frameBL[t][a] != null) {
271 g.copyDrawable(frameBL[t][a]->mask(), 0, 0,
272 frameBL[t][a]->width(), frameBL[t][a]->height(),
273 0, yBL);
274 if (protectClientWindow)
275 g.fillRect(borderX(), yBL,
276 frameBL[t][a]->width() - borderX(),
277 frameBL[t][a]->height() - borderY());
278 }
279 if (frameBR[t][a] != null) {
280 g.copyDrawable(frameBR[t][a]->mask(), 0, 0,
281 frameBR[t][a]->width(), frameBL[t][a]->height(),
282 xBR, yBR);
283 if (protectClientWindow)
284 g.fillRect(xBR, yBR,
285 frameBR[t][a]->width() - borderX(),
286 frameBR[t][a]->width() - borderY());
287 }
288
289 if (frameT[t][a] != null)
290 g.repHorz(frameT[t][a]->mask(),
291 frameT[t][a]->width(), frameT[t][a]->height(),
292 xTL, 0, xTR - xTL);
293 if (frameB[t][a] != null)
294 g.repHorz(frameB[t][a]->mask(),
295 frameB[t][a]->width(), frameB[t][a]->height(),
296 xBL, height() - frameB[t][a]->height(), xBR - xBL);
297 if (frameL[t][a] != null)
298 g.repVert(frameL[t][a]->mask(),
299 frameL[t][a]->width(), frameL[t][a]->height(),
300 0, yTL, yBL - yTL);
301 if (frameR[t][a] != null)
302 g.repVert(frameR[t][a]->mask(),
303 frameR[t][a]->width(), frameR[t][a]->height(),
304 width() - frameR[t][a]->width(), yTR, yBR - yTR);
305
306 if (titleY() && titlebar())
307 titlebar()->renderShape(g);
308 XShapeCombineMask(xapp->display(), handle(),
309 ShapeBounding, 0, 0, shape, ShapeSet);
310 XFreePixmap(xapp->display(), shape);
311 } else {
312 XShapeCombineMask(xapp->display(), handle(),
313 ShapeBounding, 0, 0, None, ShapeSet);
314 }
315 setShape();
316 }
317 #endif
318 }
319
configure(const YRect2 & r)320 void YFrameWindow::configure(const YRect2& r) {
321 MSG(("%s %d %d %d %d", __func__, r.x(), r.y(), r.width(), r.height()));
322
323 if (r.resized()) {
324 performLayout();
325 if (taskBar)
326 taskBar->workspacesRepaint();
327 }
328 if (affectsWorkArea()) {
329 manager->updateWorkArea();
330 }
331 }
332
performLayout()333 void YFrameWindow::performLayout()
334 {
335 layoutTitleBar();
336 layoutClient();
337 layoutShape();
338 if (fTitleBar)
339 fTitleBar->activate();
340 layoutResizeIndicators();
341 }
342
layoutTitleBar()343 void YFrameWindow::layoutTitleBar() {
344 if (titleY()) {
345 if (fTitleBar) {
346 fTitleBar->relayout();
347 } else {
348 fTitleBar = new YFrameTitleBar(this, this);
349 }
350 }
351 else if (fTitleBar) {
352 delete fTitleBar;
353 fTitleBar = nullptr;
354 }
355 }
356
layoutResizeIndicators()357 void YFrameWindow::layoutResizeIndicators() {
358 if (isUnmapped() || !hasBorders() || !isResizable()) {
359 if (indicatorsCreated) {
360 Window* indicators[] = {
361 &topSide, &leftSide, &rightSide, &bottomSide,
362 &topLeft, &topRight, &bottomLeft, &bottomRight
363 };
364 for (Window* window : indicators) {
365 XDestroyWindow(xapp->display(), *window);
366 *window = None;
367 }
368 indicatorsCreated = false;
369 }
370 return;
371 }
372 if (indicatorsCreated == false)
373 createPointerWindows();
374
375 int vo = int(min(height(), topSideVerticalOffset));
376 int ww(max(3, (int) width()));
377 int hh(max(3, (int) height() - vo));
378 int bx(max(1, (int) borderX()));
379 int bt(max(2, (int) borderY() - vo));
380 int bb(max(1, (int) borderY()));
381 int cx(max(1, (int) wsCornerX));
382 int cy(max(1, (int) wsCornerY));
383 int xx(min(cx, ww / 2));
384 int yy(min(cy, hh / 2));
385
386 XMoveResizeWindow(xapp->display(), topSide,
387 xx, vo, max(1, ww - 2 * xx), bt);
388 XMoveResizeWindow(xapp->display(), leftSide,
389 0, yy + vo, bx, max(1, hh - 2 * yy));
390 XMoveResizeWindow(xapp->display(), rightSide,
391 ww - bx, yy + vo, bx, max(1, hh - 2 * yy));
392 XMoveResizeWindow(xapp->display(), bottomSide,
393 xx, hh - bb + vo, max(1, ww - 2 * xx), bb);
394
395 XMoveResizeWindow(xapp->display(), topLeft,
396 0, vo, xx, yy);
397 XMoveResizeWindow(xapp->display(), topRight,
398 ww - xx, vo, xx, yy);
399 XMoveResizeWindow(xapp->display(), bottomLeft,
400 0, hh - yy + vo, xx, yy);
401 XMoveResizeWindow(xapp->display(), bottomRight,
402 ww - xx, hh - yy + vo, xx, yy);
403
404 XRaiseWindow(xapp->display(), topSide);
405 }
406
layoutClient()407 void YFrameWindow::layoutClient() {
408 if (!isRollup()) {
409 int x = borderX();
410 int y = borderY();
411 int title = titleY();
412 int w = max(1, int(width()) - 2 * x);
413 int h = max(1, int(height()) - 2 * y - title);
414 bool moved = (x != container()->x() || !fManaged ||
415 y != container()->y() - title);
416
417 container()->setGeometry(YRect(x, y + title, w, h));
418 client()->setGeometry(YRect(0, 0, w, h));
419
420 if (moved) {
421 sendConfigure();
422 client()->setNetFrameExtents(x, x, y + title, y);
423 }
424 }
425 }
426
isGroupModalFor(const YFrameWindow * other) const427 bool YFrameWindow::isGroupModalFor(const YFrameWindow* other) const {
428 bool have = false;
429 if (hasState(WinStateModal) && owner() == nullptr) {
430 Window leader = client()->clientLeader();
431 if (leader && leader == other->client()->clientLeader()) {
432 bool self = false, that = false;
433 for (auto& modal : groupModals) {
434 if (modal == this) {
435 self = true;
436 }
437 if (modal == other) {
438 that = true;
439 }
440 }
441 have = self && !that;
442 }
443 }
444 return have;
445 }
446
isTransientFor(const YFrameWindow * other) const447 bool YFrameWindow::isTransientFor(const YFrameWindow* other) const {
448 YFrameWindow* o = owner();
449 while (o && o != other) {
450 o = o->owner();
451 }
452 return o == other;
453 }
454
canLower() const455 bool YFrameWindow::canLower() const {
456 for (YFrameWindow* w = next(); w; w = w->next()) {
457 if (isTransientFor(w) == false && isGroupModalFor(w) == false) {
458 return true;
459 }
460 }
461 return false;
462 }
463
canRaise() const464 bool YFrameWindow::canRaise() const {
465 for (YFrameWindow *w = prev(); w; w = w->prev()) {
466 if (w->visibleNow() || w->visibleOn(getWorkspace())) {
467 if (w->isTransientFor(this) == false &&
468 w->isGroupModalFor(this) == false)
469 return true;
470 }
471 }
472 return false;
473 }
474
overlap(YFrameWindow * f)475 unsigned YFrameWindow::overlap(YFrameWindow* f) {
476 if (false == f->isHidden() &&
477 false == f->isMinimized() &&
478 f->visibleNow())
479 {
480 return geometry().intersect(f->geometry()).pixels();
481 }
482 return 0;
483 }
484
overlaps(bool isAbove)485 bool YFrameWindow::overlaps(bool isAbove) {
486 YFrameWindow* f = isAbove ? prev() : next();
487 for (; f; f = isAbove ? f->prev() : f->next())
488 if (overlap(f))
489 return true;
490 return false;
491 }
492
hasBorders() const493 bool YFrameWindow::hasBorders() const {
494 return hasbit(frameDecors(), fdBorder) && !isFullscreen() &&
495 !(hideBordersMaximized && isMaximizedFully()) &&
496 (hasbit(frameDecors(), fdResize) ?
497 (wsBorderX | wsBorderY) != 0 :
498 (wsDlgBorderX | wsDlgBorderY) != 0);
499 }
500
501 /// TODO #warning "should precalculate these"
borderX() const502 int YFrameWindow::borderX() const {
503 return
504 isFullscreen() ? 0 : borderXN();
505 }
506
borderXN() const507 int YFrameWindow::borderXN() const {
508 return
509 ((frameDecors() & fdBorder) && !(hideBordersMaximized && isMaximizedFully()))
510 ? ((frameDecors() & fdResize) ? wsBorderX : wsDlgBorderX)
511 : 0;
512 }
513
borderY() const514 int YFrameWindow::borderY() const {
515 return
516 isFullscreen() ? 0 : borderYN();
517 }
518
borderYN() const519 int YFrameWindow::borderYN() const {
520 return
521 ((frameDecors() & fdBorder) && !(hideBordersMaximized && isMaximizedFully()))
522 ? ((frameDecors() & fdResize) ? wsBorderY : wsDlgBorderY)
523 : 0;
524 }
525
titleY() const526 int YFrameWindow::titleY() const {
527 return isFullscreen() ? 0 : titleYN();
528 }
529
titleYN() const530 int YFrameWindow::titleYN() const {
531 if (hideTitleBarWhenMaximized && isMaximizedVert())
532 return 0;
533 return (frameDecors() & fdTitleBar) ? wsTitleBar : 0;
534 }
535
536 // vim: set sw=4 ts=4 et:
537