1 /*
2 * IceWM
3 *
4 * Copyright (C) 1997-2003 Marko Macek
5 */
6
7 #include "config.h"
8 #include "wmframe.h"
9 #include "wmmgr.h"
10 #include "yprefs.h"
11 #include "prefs.h"
12 #include "atasks.h"
13 #include "atray.h"
14 #include "wmcontainer.h"
15 #include "wmtitle.h"
16 #include "wmbutton.h"
17 #include "wmminiicon.h"
18 #include "wmtaskbar.h"
19 #include "wmwinlist.h"
20 #include "wmapp.h"
21 #include "yrect.h"
22 #include "wpixmaps.h"
23 #include "workspaces.h"
24 #include "yxcontext.h"
25
26 #include "intl.h"
27
28 YColorName activeBorderBg(&clrActiveBorder);
29 static YColorName inactiveBorderBg(&clrInactiveBorder);
30
31 lazy<YTimer> YFrameWindow::fAutoRaiseTimer;
32 lazy<YTimer> YFrameWindow::fDelayFocusTimer;
33 YArray<YFrameWindow::GroupModal> YFrameWindow::groupModals;
34
YFrameWindow(YActionListener * wmActionListener,unsigned dep,Visual * vis,Colormap col)35 YFrameWindow::YFrameWindow(
36 YActionListener *wmActionListener, unsigned dep, Visual* vis, Colormap col)
37 : YWindow(nullptr, None, dep ? dep : xapp->depth(),
38 vis ? vis : xapp->visual(), col ? col : xapp->colormap()),
39 fManaged(false),
40 fFocused(false),
41 fFrameFunctions(0),
42 fFrameDecors(0),
43 fFrameOptions(0),
44 normalX(0),
45 normalY(0),
46 normalW(1),
47 normalH(1),
48 posX(0),
49 posY(0),
50 posW(1),
51 posH(1),
52 fClient(nullptr),
53 fContainer(nullptr),
54 fTitleBar(nullptr),
55 fPopupActive(nullptr),
56 movingWindow(false),
57 sizingWindow(false),
58 topSide(None),
59 leftSide(None),
60 rightSide(None),
61 bottomSide(None),
62 topLeft(None),
63 topRight(None),
64 bottomLeft(None),
65 bottomRight(None),
66 fTaskBarApp(nullptr),
67 fTrayApp(nullptr),
68 fMiniIcon(nullptr),
69 fWinListItem(nullptr),
70 fFrameIcon(null),
71 fKillMsgBox(nullptr),
72 fOwner(nullptr),
73 fTransient(nullptr),
74 fNextTransient(nullptr),
75 wmActionListener(wmActionListener),
76 fWinWorkspace(manager->activeWorkspace()),
77 fWinRequestedLayer(WinLayerNormal),
78 fWinActiveLayer(WinLayerNormal),
79 fWinTrayOption(WinTrayIgnore),
80 fWinState(0),
81 fWinOptionMask(~0),
82 fTrayOrder(0),
83 fFullscreenMonitorsTop(-1),
84 fFullscreenMonitorsBottom(-1),
85 fFullscreenMonitorsLeft(-1),
86 fFullscreenMonitorsRight(-1),
87 fStrutLeft(0),
88 fStrutRight(0),
89 fStrutTop(0),
90 fStrutBottom(0),
91 fUserTimeWindow(None),
92 fStartManaged(xapp->getEventTime("frame")),
93 fShapeWidth(-1),
94 fShapeHeight(-1),
95 fShapeTitleY(-1),
96 fShapeBorderX(-1),
97 fShapeBorderY(-1),
98 fShapeDecors(0),
99 fHaveStruts(false),
100 indicatorsCreated(false),
101 fWindowType(wtNormal)
102 {
103 setStyle(wsOverrideRedirect);
104 setBitGravity(NorthWestGravity);
105 setPointer(YWMApp::leftPointer);
106 setTitle("Frame");
107 setBackground(inactiveBorderBg);
108 }
109
~YFrameWindow()110 YFrameWindow::~YFrameWindow() {
111 fManaged = false;
112 if (fKillMsgBox) {
113 fKillMsgBox->unmanage();
114 fKillMsgBox = nullptr;
115 }
116 if (fWindowType == wtDialog)
117 wmapp->signalGuiEvent(geDialogClosed);
118 else
119 wmapp->signalGuiEvent(geWindowClosed);
120 if (fDelayFocusTimer)
121 fDelayFocusTimer->disableTimerListener(this);
122 if (fAutoRaiseTimer)
123 fAutoRaiseTimer->disableTimerListener(this);
124 if (movingWindow || sizingWindow)
125 endMoveSize();
126 if (fPopupActive)
127 fPopupActive->cancelPopup();
128 removeAppStatus();
129 removeFromWindowList();
130 if (fMiniIcon) {
131 delete fMiniIcon;
132 fMiniIcon = nullptr;
133 }
134 fFrameIcon = null;
135 #if 1
136 fWinState &= ~WinStateFullscreen;
137 updateLayer(false);
138 #endif
139 // perhaps should be done another way
140 removeTransients();
141 removeAsTransient();
142 if (fContainer) {
143 manager->lockWorkArea();
144 manager->removeFocusFrame(this);
145 manager->removeCreatedFrame(this);
146 removeFrame();
147 manager->removeClientFrame(this);
148 if (client()) {
149 if (!client()->destroyed() && client()->adopted())
150 XRemoveFromSaveSet(xapp->display(), client()->handle());
151 frameContext.remove(client()->handle());
152 }
153 if (fUserTimeWindow != None) {
154 windowContext.remove(fUserTimeWindow);
155 }
156
157 delete fClient; fClient = nullptr;
158 delete fContainer; fContainer = nullptr;
159 delete fTitleBar; fTitleBar = nullptr;
160
161 manager->unlockWorkArea();
162 manager->updateClientList();
163 }
164
165 if (taskBar) {
166 taskBar->workspacesRepaint();
167 }
168 }
169
addToWindowList()170 void YFrameWindow::addToWindowList() {
171 if (fWinListItem == nullptr && client()->adopted() &&
172 windowList && notbit(frameOptions(), foIgnoreWinList))
173 {
174 fWinListItem = windowList->addWindowListApp(this);
175 }
176 }
177
removeFromWindowList()178 void YFrameWindow::removeFromWindowList() {
179 if (fWinListItem) {
180 if (windowList)
181 windowList->removeWindowListApp(fWinListItem);
182 delete fWinListItem; fWinListItem = nullptr;
183 }
184 }
185
setAbove(YFrameWindow * aboveFrame)186 inline bool YFrameWindow::setAbove(YFrameWindow *aboveFrame) {
187 return manager->setAbove(this, aboveFrame);
188 }
189
setBelow(YFrameWindow * belowFrame)190 inline bool YFrameWindow::setBelow(YFrameWindow *belowFrame) {
191 return manager->setBelow(this, belowFrame);
192 }
193
titlebar()194 YFrameTitleBar* YFrameWindow::titlebar() {
195 if (fTitleBar == nullptr && titleY() > 0) {
196 fTitleBar = new YFrameTitleBar(this, this);
197 }
198 return fTitleBar;
199 }
200
doManage(YFrameClient * clientw,bool & doActivate,bool & requestFocus)201 void YFrameWindow::doManage(YFrameClient *clientw, bool &doActivate, bool &requestFocus) {
202 PRECONDITION(clientw != 0 && !fContainer && !fClient);
203
204 if (clientw->handle() == None || clientw->destroyed()) {
205 return;
206 }
207
208 unsigned depth = Elvis(clientw->depth(), xapp->depth());
209 bool sameDepth = (depth == xapp->depth());
210 Visual* visual = (sameDepth ? xapp->visual() : clientw->visual());
211 Colormap clmap = (sameDepth ? xapp->colormap() : clientw->colormap());
212 fContainer = new YClientContainer(this, this, depth, visual, clmap);
213
214 fClient = clientw;
215 if (hintOptions && hintOptions->nonempty()) {
216 getWindowOptions(hintOptions, getHintOption(), true);
217 }
218
219 {
220 int x = client()->x();
221 int y = client()->y();
222 int w = client()->width();
223 int h = client()->height();
224
225 XSizeHints *sh = client()->sizeHints();
226 normalX = x;
227 normalY = y;
228 normalW = sh ? (w - sh->base_width) / max(1, sh->width_inc) : w;
229 normalH = sh ? (h - sh->base_height) / max(1, sh->height_inc) : h;
230
231 if (client()->winGravity() == StaticGravity) {
232 normalX += borderXN();
233 normalY += borderYN() + titleYN();
234 } else {
235 int gx, gy;
236 client()->gravityOffsets(gx, gy);
237
238 if (gx > 0)
239 normalX += 2 * borderXN() - 1 - client()->getBorder();
240 if (gy > 0)
241 normalY += 2 * borderYN() + titleYN() - 1 - client()->getBorder();
242
243 }
244
245 getNormalGeometryInner(&posX, &posY, &posW, &posH);
246 }
247
248 updateIcon();
249 manage();
250 manager->appendCreatedFrame(this);
251 bool isRunning = manager->wmState() == YWindowManager::wmRUNNING;
252 insertFrame(!isRunning);
253 manager->insertFocusFrame(this, !isRunning);
254
255 if (client()->getNetWMWindowType(&fWindowType)) {
256 if (fWindowType == wtDesktop || fWindowType == wtDock) {
257 setAllWorkspaces();
258 }
259 } else if (client()->ownerWindow()) {
260 fWindowType = wtDialog;
261 }
262 int layer = fWinRequestedLayer;
263 if (client()->getLayerHint(&layer) &&
264 layer != fWinRequestedLayer &&
265 inrange<int>(layer, WinLayerDesktop, WinLayerAboveAll))
266 {
267 setRequestedLayer(layer);
268 } else {
269 updateLayer(true);
270 }
271 getFrameHints();
272
273 getDefaultOptions(requestFocus);
274 updateNetWMStrut(); /// ? here
275 updateNetWMStrutPartial();
276 updateNetStartupId();
277 updateNetWMUserTime();
278 updateNetWMUserTimeWindow();
279
280 int workspace = getWorkspace(), mask(0), state(0);
281
282 MSG(("Map - Frame: %d", visible()));
283 MSG(("Map - Client: %d", client()->visible()));
284
285 if (client()->getNetWMStateHint(&mask, &state)) {
286 if ((getState() & mask) != state) {
287 setState(mask, state);
288 }
289 }
290 if (client()->ownerWindow() == xapp->root() ||
291 (client()->mwmHints() && client()->mwmHints()->inputModal())) {
292 fWinState |= WinStateModal;
293 }
294
295 {
296 FrameState st = client()->getFrameState();
297
298 if (st == WithdrawnState) {
299 if (client()->wmHint(StateHint))
300 st = client()->hints()->initial_state;
301 else
302 st = NormalState;
303 }
304 MSG(("FRAME state = %d", st));
305 if (st == IconicState) {
306 fFrameOptions |= foMinimized;
307 if (manager->isRunning())
308 if (notState(WinStateMinimized))
309 setState(WinStateUnmapped, WinStateMinimized);
310 }
311 }
312
313 if (client()->getNetWMDesktopHint(&workspace))
314 setWorkspace(workspace);
315
316 int tray;
317 if (client()->getWinTrayHint(&tray))
318 setTrayOption(tray);
319 addAsTransient();
320 if (owner())
321 setWorkspace(mainOwner()->getWorkspace());
322
323 if (isHidden() || isMinimized() || client() == taskBar) {
324 doActivate = false;
325 requestFocus = false;
326 }
327
328 updateFocusOnMap(doActivate);
329 addTransients();
330 manager->restackWindows();
331
332 afterManage();
333 }
334
afterManage()335 void YFrameWindow::afterManage() {
336 if (affectsWorkArea())
337 manager->updateWorkArea();
338 manager->updateClientList();
339 setShape();
340 if ( !frameOption(foFullKeys))
341 grabKeys();
342 container()->grabButtons();
343 addToWindowList();
344 if (fWindowType == wtDialog)
345 wmapp->signalGuiEvent(geDialogOpened);
346 else
347 wmapp->signalGuiEvent(geWindowOpened);
348 }
349
350 // create a window to show a resize pointer on the frame border
createPointerWindow(Cursor cursor,int gravity)351 Window YFrameWindow::createPointerWindow(Cursor cursor, int gravity) {
352 unsigned long valuemask = CWEventMask | CWCursor | CWWinGravity;
353 XSetWindowAttributes attributes;
354 attributes.win_gravity = gravity;
355 attributes.event_mask = 0;
356 attributes.cursor = cursor;
357 Window window = XCreateWindow(xapp->display(), handle(), 0, 0, 1, 1,
358 0, 0, InputOnly, CopyFromParent,
359 valuemask, &attributes);
360 XMapWindow(xapp->display(), window);
361 return window;
362 }
363
364 // create 8 resize pointer indicator windows
createPointerWindows()365 void YFrameWindow::createPointerWindows() {
366
367 topSide =
368 createPointerWindow(YWMApp::sizeTopPointer, NorthGravity);
369 leftSide =
370 createPointerWindow(YWMApp::sizeLeftPointer, WestGravity);
371 rightSide =
372 createPointerWindow(YWMApp::sizeRightPointer, EastGravity);
373 bottomSide =
374 createPointerWindow(YWMApp::sizeBottomPointer, SouthGravity);
375
376 topLeft =
377 createPointerWindow(YWMApp::sizeTopLeftPointer, NorthWestGravity);
378 topRight =
379 createPointerWindow(YWMApp::sizeTopRightPointer, NorthEastGravity);
380 bottomLeft =
381 createPointerWindow(YWMApp::sizeBottomLeftPointer, SouthWestGravity);
382 bottomRight =
383 createPointerWindow(YWMApp::sizeBottomRightPointer, SouthEastGravity);
384
385 indicatorsCreated = true;
386
387 if (fTitleBar) {
388 fTitleBar->raise();
389 }
390 XStoreName(xapp->display(), topSide, "topSide");
391 container()->raise();
392 }
393
grabKeys()394 void YFrameWindow::grabKeys() {
395 XUngrabKey(xapp->display(), AnyKey, AnyModifier, handle());
396
397 GRAB_WMKEY(gKeyWinRaise);
398 GRAB_WMKEY(gKeyWinOccupyAll);
399 GRAB_WMKEY(gKeyWinLower);
400 GRAB_WMKEY(gKeyWinClose);
401 GRAB_WMKEY(gKeyWinRestore);
402 GRAB_WMKEY(gKeyWinNext);
403 GRAB_WMKEY(gKeyWinPrev);
404 GRAB_WMKEY(gKeyWinMove);
405 GRAB_WMKEY(gKeyWinSize);
406 GRAB_WMKEY(gKeyWinMinimize);
407 GRAB_WMKEY(gKeyWinMaximize);
408 GRAB_WMKEY(gKeyWinMaximizeVert);
409 GRAB_WMKEY(gKeyWinMaximizeHoriz);
410 GRAB_WMKEY(gKeyWinHide);
411 GRAB_WMKEY(gKeyWinRollup);
412 GRAB_WMKEY(gKeyWinFullscreen);
413 GRAB_WMKEY(gKeyWinMenu);
414 GRAB_WMKEY(gKeyWinArrangeN);
415 GRAB_WMKEY(gKeyWinArrangeNE);
416 GRAB_WMKEY(gKeyWinArrangeE);
417 GRAB_WMKEY(gKeyWinArrangeSE);
418 GRAB_WMKEY(gKeyWinArrangeS);
419 GRAB_WMKEY(gKeyWinArrangeSW);
420 GRAB_WMKEY(gKeyWinArrangeW);
421 GRAB_WMKEY(gKeyWinArrangeNW);
422 GRAB_WMKEY(gKeyWinArrangeC);
423 GRAB_WMKEY(gKeyWinSmartPlace);
424
425 container()->regrabMouse();
426 }
427
manage()428 void YFrameWindow::manage() {
429 PRECONDITION(client());
430
431 if (client()->getBorder()) {
432 client()->setBorderWidth(0U);
433 }
434 if (client()->adopted())
435 XAddToSaveSet(xapp->display(), client()->handle());
436 else
437 client()->getPropertiesList();
438
439 client()->reparent(container(), 0, 0);
440 client()->setFrame(this);
441 }
442
unmanage(bool reparent)443 void YFrameWindow::unmanage(bool reparent) {
444 PRECONDITION(client());
445
446 if (fMiniIcon) {
447 delete fMiniIcon;
448 fMiniIcon = nullptr;
449 }
450
451 if (!client()->destroyed()) {
452 int gx, gy;
453 client()->gravityOffsets(gx, gy);
454
455 client()->setBorderWidth(client()->getBorder());
456
457 int posX, posY, posWidth, posHeight;
458
459 getNormalGeometryInner(&posX, &posY, &posWidth, &posHeight);
460 if (gx < 0)
461 posX -= borderXN();
462 else if (gx > 0)
463 posX += borderXN() - 2 * client()->getBorder();
464 if (gy < 0)
465 posY -= borderYN();
466 else if (gy > 0)
467 posY += borderYN() + titleYN() - 2 * client()->getBorder();
468
469 if (gx == 0 && gy == 0) {
470 if (client()->winGravity() == StaticGravity) {
471 posY += titleYN();
472 }
473 }
474
475 if (reparent)
476 client()->reparent(desktop, posX, posY);
477
478 client()->setSize(posWidth, posHeight);
479
480 if (manager->wmState() != YWindowManager::wmSHUTDOWN) {
481 client()->setFrameState(WithdrawnState);
482 }
483
484 if (!client()->destroyed() && client()->adopted())
485 XRemoveFromSaveSet(xapp->display(), client()->handle());
486 }
487 else
488 client()->unmanageWindow();
489
490 client()->setFrame(nullptr);
491 fClient = nullptr;
492
493 hide();
494 }
495
getNewPos(const XConfigureRequestEvent & cr,int & cx,int & cy,int & cw,int & ch)496 void YFrameWindow::getNewPos(const XConfigureRequestEvent& cr,
497 int& cx, int& cy, int& cw, int& ch)
498 {
499 const int mask = int(cr.value_mask);
500 cw = (mask & CWWidth) ? cr.width : client()->width();
501 ch = (mask & CWHeight) ? cr.height : client()->height();
502
503 int grav = client()->winGravity();
504 int cur_x = x() + container()->x();
505 int cur_y = y() + container()->y();
506
507 //msg("%d %d %d %d", cr.x, cr.y, cr.width, cr.height);
508
509 if (mask & CWX) {
510 if (grav == StaticGravity)
511 cx = cr.x;
512 else {
513 cx = cr.x + container()->x();
514 }
515 } else {
516 if (grav == NorthGravity ||
517 grav == CenterGravity ||
518 grav == SouthGravity)
519 {
520 cx = cur_x + (client()->width() - cw) / 2;
521 } else if (grav == NorthEastGravity ||
522 grav == EastGravity ||
523 grav == SouthEastGravity)
524 {
525 cx = cur_x + (client()->width() - cw);
526 } else {
527 cx = cur_x;
528 }
529 }
530
531 if (mask & CWY) {
532 if (grav == StaticGravity)
533 cy = cr.y;
534 else {
535 cy = cr.y + container()->y();
536 }
537 } else {
538 if (grav == WestGravity ||
539 grav == CenterGravity ||
540 grav == EastGravity)
541 {
542 cy = cur_y + (client()->height() - ch) / 2;
543 } else if (grav == SouthEastGravity ||
544 grav == SouthGravity ||
545 grav == SouthWestGravity)
546 {
547 cy = cur_y + (client()->height() - ch);
548 } else {
549 cy = cur_y;
550 }
551 }
552
553 if (affectsWorkArea() == false) {
554 int screen = desktop->getScreenForRect(cx, cy, cw, ch);
555 int left, top, right, bottom;
556 if (taskBar && taskBar->getFrame() &&
557 screen == taskBar->getFrame()->getScreen())
558 {
559 manager->getWorkArea(this, &left, &top, &right, &bottom, screen);
560 }
561 else {
562 left = desktop->x();
563 right = left + desktop->width();
564 top = desktop->y();
565 bottom = top + desktop->height();
566 }
567 if (cx + cw > right && cx > left && (mask & CWWidth)) {
568 cx -= min(cx + cw - right, cx - left);
569 }
570 if (cy + ch > bottom && cy > top && (mask & CWHeight)) {
571 cy -= min(cy + ch - bottom, cy - top);
572 }
573 if (limitPosition && (mask & CWX) && notbit(mask, CWWidth)) {
574 cx = clamp(cx, left, right - cw);
575 }
576 if (limitPosition && (mask & CWY) && notbit(mask, CWHeight)) {
577 cy = clamp(cy, top, bottom - ch);
578 }
579 }
580
581 // update pager when windows move/resize themselves (like xmms, gmplayer, ...),
582 // because this does not call YFrameWindow::endMoveSize()
583 if (taskBar) {
584 taskBar->workspacesRepaint();
585 }
586 }
587
configureClient(const XConfigureRequestEvent & configureRequest)588 void YFrameWindow::configureClient(const XConfigureRequestEvent &configureRequest) {
589 unsigned long mask = configureRequest.value_mask;
590 if (hasbit(mask, CWBorderWidth))
591 client()->setBorder(configureRequest.border_width);
592
593 if (hasbit(mask, CWX | CWY | CWWidth | CWHeight)) {
594 int cx, cy, cw, ch;
595 getNewPos(configureRequest, cx, cy, cw, ch);
596 configureClient(cx, cy, cw, ch);
597 }
598
599 if (hasbit(mask, CWStackMode)) {
600 Window window = hasbit(mask, CWSibling) ? configureRequest.above : None;
601 if (inrange(configureRequest.detail, Above, Opposite)) {
602 netRestackWindow(window, configureRequest.detail);
603 }
604 }
605 sendConfigure();
606 }
607
netRestackWindow(Window window,int detail)608 void YFrameWindow::netRestackWindow(Window window, int detail) {
609 YFrameWindow* sibling = window ? manager->findFrame(window) : nullptr;
610 if (sibling) {
611 switch (detail) {
612 case Above:
613 if (setAbove(sibling)) {
614 raiseTo(sibling);
615 }
616 break;
617 case Below:
618 if (setBelow(sibling)) {
619 beneath(sibling);
620 }
621 break;
622 case TopIf:
623 if (getActiveLayer() == sibling->getActiveLayer()) {
624 for (YFrameWindow* f = prev(); f; f = f->prev()) {
625 if (f == sibling) {
626 if (overlap(sibling) && setAbove(sibling)) {
627 raiseTo(sibling);
628 }
629 break;
630 }
631 }
632 }
633 break;
634 case BottomIf:
635 if (getActiveLayer() == sibling->getActiveLayer()) {
636 YFrameWindow* f;
637 for (f = next(); f && f != owner(); f = f->next()) {
638 if (f == sibling) {
639 if (overlap(sibling) && setBelow(sibling)) {
640 beneath(sibling);
641 }
642 break;
643 }
644 }
645 }
646 break;
647 case Opposite:
648 if (getActiveLayer() == sibling->getActiveLayer()) {
649 bool search = true;
650 for (YFrameWindow* f = prev(); f; f = f->prev()) {
651 if (f == sibling) {
652 if (overlap(sibling) && setAbove(sibling)) {
653 raiseTo(sibling);
654 }
655 search = false;
656 break;
657 }
658 }
659 if (search) {
660 YFrameWindow* f;
661 for (f = next(); f && f != owner(); f = f->next()) {
662 if (f == sibling) {
663 if (overlap(sibling) && setBelow(sibling)) {
664 beneath(sibling);
665 }
666 break;
667 }
668 }
669 }
670 }
671 break;
672 }
673 }
674 else {
675 switch (detail) {
676 case Above:
677 if (canRaise() && !isPassive()) {
678 wmRaise();
679 if (focusOnAppRaise) {
680 if ( !frameOption(foNoFocusOnAppRaise) &&
681 (clickFocus || !strongPointerFocus))
682 {
683 if (focusChangesWorkspace ||
684 focusCurrentWorkspace ||
685 visibleNow())
686 {
687 activate();
688 } else {
689 setWmUrgency(true);
690 }
691 }
692 }
693 else if (requestFocusOnAppRaise) {
694 setWmUrgency(true);
695 }
696 }
697 break;
698 case Below:
699 if (owner() && getActiveLayer() == owner()->getActiveLayer()) {
700 if (setAbove(owner())) {
701 raiseTo(owner());
702 }
703 }
704 else if (focused() || hasState(WinStateModal)) {
705 wmLower();
706 }
707 else {
708 doLower();
709 }
710 break;
711 case TopIf:
712 for (YFrameWindow* f = prev(); f; f = f->prev()) {
713 if (overlap(f)) {
714 while (f->prev()) {
715 f = f->prev();
716 }
717 if (setAbove(f)) {
718 raiseTo(f);
719 }
720 break;
721 }
722 }
723 break;
724 case BottomIf:
725 for (YFrameWindow* f = next(); f && f != owner(); f = f->next()) {
726 if (overlap(f)) {
727 while (f->next() && f->next() != owner()) {
728 f = f->next();
729 }
730 if (setBelow(f)) {
731 beneath(f);
732 }
733 break;
734 }
735 }
736 break;
737 case Opposite:
738 for (YFrameWindow* f = prev(); ; f = f->prev()) {
739 if (f == nullptr) {
740 for (f = next(); f && f != owner(); f = f->next()) {
741 if (overlap(f)) {
742 while (f->next() && f->next() != owner()) {
743 f = f->next();
744 }
745 if (setBelow(f)) {
746 beneath(f);
747 }
748 break;
749 }
750 }
751 break;
752 }
753 else if (overlap(f)) {
754 while (f->prev()) {
755 f = f->prev();
756 }
757 if (setAbove(f)) {
758 raiseTo(f);
759 }
760 break;
761 }
762 }
763 break;
764 }
765 }
766 manager->updateClientList();
767 }
768
configureClient(int cx,int cy,int cwidth,int cheight)769 void YFrameWindow::configureClient(int cx, int cy, int cwidth, int cheight) {
770 MSG(("setting geometry (%d:%d %dx%d)", cx, cy, cwidth, cheight));
771 cy -= titleYN();
772 if (isFullscreen()) {
773 XSizeHints *sh = client()->sizeHints();
774 if (sh) {
775 normalX = cx;
776 normalY = cy;
777 normalW = sh
778 ? (cwidth - sh->base_width) / max(1, sh->width_inc)
779 : cwidth;
780 normalH = sh
781 ? (cheight - sh->base_height) / max(1, sh->height_inc)
782 : cheight;
783 }
784 }
785 else {
786 int posX, posY, posW, posH;
787 getNormalGeometryInner(&posX, &posY, &posW, &posH);
788
789 if (isMaximizedVert() || isRollup()) {
790 cy = posY;
791 cheight = posH;
792 }
793 if (isMaximizedHoriz()) {
794 cx = posX;
795 cwidth = posW;
796 }
797
798 setNormalGeometryInner(cx, cy, cwidth, cheight);
799 }
800 }
801
handleClick(const XButtonEvent & up,int)802 void YFrameWindow::handleClick(const XButtonEvent &up, int /*count*/) {
803 if (up.button == 3) {
804 popupSystemMenu(this, up.x_root, up.y_root,
805 YPopupWindow::pfCanFlipVertical |
806 YPopupWindow::pfCanFlipHorizontal |
807 YPopupWindow::pfPopupMenu);
808 }
809 }
810
handleCrossing(const XCrossingEvent & crossing)811 void YFrameWindow::handleCrossing(const XCrossingEvent &crossing) {
812 if (crossing.type == EnterNotify &&
813 (crossing.mode == NotifyNormal ||
814 (strongPointerFocus && crossing.mode == NotifyUngrab)) &&
815 crossing.window == handle() &&
816 (strongPointerFocus ||
817 (crossing.serial != YWindow::getLastEnterNotifySerial() &&
818 crossing.serial != YWindow::getLastEnterNotifySerial() + 1))
819 #if false
820 &&
821 (strongPointerFocus ||
822 fMouseFocusX != crossing.x_root ||
823 fMouseFocusY != crossing.y_root)
824 #endif
825 )
826 {
827 //msg("xf: %d %d", fMouseFocusX, crossing.x_root, fMouseFocusY, crossing.y_root);
828
829 // fMouseFocusX = crossing.x_root;
830 // fMouseFocusY = crossing.y_root;
831
832 if (!clickFocus && visible() && canFocusByMouse()) {
833 if (!delayPointerFocus)
834 focus(false);
835 else {
836 fDelayFocusTimer->setTimer(pointerFocusDelay, this, true);
837 }
838 } else {
839 if (fDelayFocusTimer) {
840 fDelayFocusTimer->stopTimer();
841 }
842 }
843 if (autoRaise) {
844 fAutoRaiseTimer->setTimer(autoRaiseDelay, this, true);
845 }
846 } else if (crossing.type == LeaveNotify &&
847 fFocused &&
848 focusRootWindow &&
849 crossing.window == handle())
850 {
851 // fMouseFocusX = crossing.x_root;
852 // fMouseFocusY = crossing.y_root;
853
854 if (crossing.detail != NotifyInferior &&
855 crossing.mode == NotifyNormal)
856 {
857 if (fDelayFocusTimer)
858 fDelayFocusTimer->disableTimerListener(this);
859 if (autoRaise && fAutoRaiseTimer) {
860 fAutoRaiseTimer->disableTimerListener(this);
861 }
862 }
863 }
864 }
865
handleFocus(const XFocusChangeEvent & focus)866 void YFrameWindow::handleFocus(const XFocusChangeEvent &focus) {
867 if (manager->switchWindowVisible() || client()->adopted() == false) {
868 return ;
869 }
870 if (focus.type == FocusIn &&
871 focus.mode != NotifyGrab &&
872 focus.window == handle() &&
873 focus.detail != NotifyInferior &&
874 focus.detail != NotifyPointer &&
875 focus.detail != NotifyPointerRoot)
876 {
877 fFocusEventTimer->setTimer(None, this, true);
878 }
879 layoutShape();
880 }
881
handleTimer(YTimer * t)882 bool YFrameWindow::handleTimer(YTimer *t) {
883 if (isMapped() && !client()->destroyed()) {
884 if (t == fAutoRaiseTimer) {
885 actionPerformed(actionRaise);
886 }
887 else if (t == fDelayFocusTimer) {
888 focus(false);
889 }
890 else if (t == fFocusEventTimer) {
891 if (manager->getFocus() != this && client()->visible()) {
892 Window win = 0; int rev = 0;
893 XGetInputFocus(xapp->display(), &win, &rev);
894 while (win != client()->handle()) {
895 YWindow* found = windowContext.find(win);
896 if (found) {
897 break;
898 } else {
899 Window par = xapp->parent(win);
900 if (par == None || par == xapp->root()) {
901 break;
902 } else {
903 win = par;
904 }
905 }
906 }
907 if (win == client()->handle()) {
908 manager->switchFocusTo(this);
909 }
910 }
911 }
912 }
913 return false;
914 }
915
raise()916 void YFrameWindow::raise() {
917 if (this != manager->top(getActiveLayer())) {
918 setAbove(manager->top(getActiveLayer()));
919 raiseTo(prevLayer());
920 }
921 }
922
lower()923 void YFrameWindow::lower() {
924 if (this != manager->bottom(getActiveLayer())) {
925 setAbove(nullptr);
926 beneath(nextLayer());
927 }
928 }
929
removeFrame()930 void YFrameWindow::removeFrame() {
931 #ifdef DEBUG
932 if (debug_z) dumpZorder("before removing", this);
933 #endif
934 manager->removeLayeredFrame(this);
935 #ifdef DEBUG
936 if (debug_z) dumpZorder("after removing", this);
937 #endif
938 }
939
insertFrame(bool top)940 void YFrameWindow::insertFrame(bool top) {
941 #ifdef DEBUG
942 if (debug_z) dumpZorder("before inserting", this);
943 #endif
944 if (top) {
945 manager->setTop(getActiveLayer(), this);
946 } else {
947 manager->setBottom(getActiveLayer(), this);
948 }
949 #ifdef DEBUG
950 if (debug_z) dumpZorder("after inserting", this);
951 #endif
952 }
953
findWindow(int flags)954 YFrameWindow *YFrameWindow::findWindow(int flags) {
955 YFrameWindow *p = this;
956
957 if (flags & fwfNext)
958 goto next;
959
960 do {
961 if ((flags & fwfMinimized) && !p->isMinimized())
962 goto next;
963 if ((flags & fwfUnminimized) && p->isMinimized())
964 goto next;
965 if ((flags & fwfVisible) && !p->visible())
966 goto next;
967 if ((flags & fwfHidden) && !p->isHidden())
968 goto next;
969 if ((flags & fwfNotHidden) && p->isHidden())
970 goto next;
971 if ((flags & fwfFocusable) && !p->canFocus())
972 goto next;
973 if ((flags & fwfWorkspace) && !p->visibleNow())
974 goto next;
975 if (!p->client()->adopted() || p->client()->destroyed())
976 goto next;
977
978 return p;
979
980 next:
981 if (flags & fwfBackward)
982 p = (flags & fwfLayers) ? p->prevLayer() : p->prev();
983 else
984 p = (flags & fwfLayers) ? p->nextLayer() : p->next();
985 if (p == nullptr) {
986 if (!(flags & fwfCycle))
987 return nullptr;
988 else if (flags & fwfBackward)
989 p = (flags & fwfLayers) ? manager->bottomLayer() : manager->bottom(getActiveLayer());
990 else
991 p = (flags & fwfLayers) ? manager->topLayer() : manager->top(getActiveLayer());
992 }
993 } while (p != this);
994
995 if (!(flags & fwfSame))
996 return nullptr;
997 if ((flags & fwfVisible) && !p->visible())
998 return nullptr;
999 if ((flags & fwfWorkspace) && !p->visibleNow())
1000 return nullptr;
1001 if (!p->client()->adopted() || p->client()->destroyed())
1002 return nullptr;
1003
1004 return this;
1005 }
1006
handleConfigure(const XConfigureEvent &)1007 void YFrameWindow::handleConfigure(const XConfigureEvent &/*configure*/) {
1008 }
1009
sendConfigure()1010 void YFrameWindow::sendConfigure() {
1011 XConfigureEvent notify = {
1012 .type = ConfigureNotify,
1013 .serial = CurrentTime,
1014 .send_event = True,
1015 .display = nullptr,
1016 .event = client()->handle(),
1017 .window = client()->handle(),
1018 .x = x() + borderX(),
1019 .y = y() + borderY() + titleY(),
1020 .width = int(client()->width()),
1021 .height = int(client()->height()),
1022 .border_width = client()->getBorder(),
1023 .above = None,
1024 .override_redirect = False,
1025 };
1026
1027 XSendEvent(xapp->display(),
1028 client()->handle(),
1029 False,
1030 StructureNotifyMask,
1031 (XEvent *) ¬ify);
1032 }
1033
actionPerformed(YAction action,unsigned int modifiers)1034 void YFrameWindow::actionPerformed(YAction action, unsigned int modifiers) {
1035 switch (action.ident()) {
1036 case actionRestore:
1037 if (canRestore())
1038 wmRestore();
1039 break;
1040 case actionMinimize:
1041 if (canMinimize())
1042 wmMinimize();
1043 break;
1044 case actionMaximize:
1045 if (canMaximize())
1046 wmMaximize();
1047 break;
1048 case actionMaximizeVert:
1049 if (canMaximize())
1050 wmMaximizeVert();
1051 break;
1052 case actionMaximizeHoriz:
1053 if (canMaximize())
1054 wmMaximizeHorz();
1055 break;
1056 case actionLower:
1057 if (canLower())
1058 wmLower();
1059 break;
1060 case actionRaise:
1061 if (canRaise())
1062 wmRaise();
1063 break;
1064 case actionDepth:
1065 if (overlaps(bool(Below)) && canRaise()){
1066 wmRaise();
1067 manager->setFocus(this, true);
1068 } else if (overlaps(bool(Above)) && canLower())
1069 wmLower();
1070 break;
1071 case actionRollup:
1072 if (canRollup())
1073 wmRollup();
1074 break;
1075 case actionClose:
1076 if (canClose())
1077 wmClose();
1078 break;
1079 case actionKill:
1080 if (client()->adopted())
1081 wmConfirmKill();
1082 else
1083 wmClose();
1084 break;
1085 case actionHide:
1086 if (canHide())
1087 wmHide();
1088 break;
1089 case actionShow:
1090 if (canShow())
1091 wmShow();
1092 break;
1093 case actionMove:
1094 if (canMove())
1095 wmMove();
1096 break;
1097 case actionSize:
1098 if (canSize())
1099 wmSize();
1100 break;
1101 case actionOccupyAllOrCurrent:
1102 wmOccupyAllOrCurrent();
1103 break;
1104 #if DO_NOT_COVER_OLD
1105 case actionDoNotCover:
1106 wmToggleDoNotCover();
1107 break;
1108 #endif
1109 case actionFullscreen:
1110 if (canFullscreen())
1111 wmToggleFullscreen();
1112 break;
1113 case actionToggleTray:
1114 wmToggleTray();
1115 break;
1116 case actionTileLeft:
1117 case actionTileRight:
1118 case actionTileTop:
1119 case actionTileBottom:
1120 case actionTileTopLeft:
1121 case actionTileTopRight:
1122 case actionTileBottomLeft:
1123 case actionTileBottomRight:
1124 case actionTileCenter:
1125 wmTile(action);
1126 break;
1127 case actionLayerDesktop:
1128 case actionLayerOne:
1129 case actionLayerBelow:
1130 case actionLayerThree:
1131 case actionLayerNormal:
1132 case actionLayerFive:
1133 case actionLayerOnTop:
1134 case actionLayerSeven:
1135 case actionLayerDock:
1136 case actionLayerNine:
1137 case actionLayerAboveDock:
1138 case actionLayerEleven:
1139 case actionLayerMenu:
1140 case actionLayerThirteen:
1141 case actionLayerFullscreen:
1142 case actionLayerAboveAll:
1143 {
1144 int layer = (action.ident() - actionLayerDesktop) / 2;
1145 bool isFull = isFullscreen() && manager->fullscreenEnabled();
1146 if (isFull)
1147 manager->setFullscreenEnabled(false);
1148 wmSetLayer(layer);
1149 if (isFull)
1150 manager->setFullscreenEnabled(true);
1151 }
1152 break;
1153 default:
1154 for (int w(0); w < workspaceCount; w++) {
1155 if (action == workspaceActionMoveTo[w]) {
1156 wmOccupyWorkspace(w);
1157 return ;
1158 }
1159 }
1160 wmActionListener->actionPerformed(action, modifiers);
1161 }
1162 }
1163
wmTile(YAction action)1164 void YFrameWindow::wmTile(YAction action) {
1165 if (canMove() == false || visibleNow() == false) {
1166 return;
1167 }
1168 if (hasState(WinStateMaximizedBoth | WinStateRollup)) {
1169 if (notState(WinStateUnmapped | WinStateFullscreen)) {
1170 setState(WinStateMaximizedBoth | WinStateRollup, None);
1171 }
1172 }
1173 if (notState(WinStateUnmapped | WinStateFullscreen)) {
1174 bool size = canSize();
1175 int mx, my, Mx, My;
1176 manager->getWorkArea(this, &mx, &my, &Mx, &My);
1177 int x = this->x(), y = this->y();
1178 int w = int(this->width()), h = int(this->height());
1179 switch (action.ident()) {
1180 case actionTileLeft:
1181 if (size)
1182 w = (Mx - mx) / 2, h = (My - my);
1183 x = mx, y = my;
1184 break;
1185 case actionTileRight:
1186 if (size)
1187 w = (Mx - mx) / 2, h = (My - my);
1188 x = (Mx - mx) / 2, y = my;
1189 break;
1190 case actionTileTop:
1191 if (size)
1192 w = (Mx - mx), h = (My - my) / 2;
1193 x = mx, y = my;
1194 break;
1195 case actionTileBottom:
1196 if (size)
1197 w = (Mx - mx), h = (My - my) / 2;
1198 x = mx, y = (My - my) / 2;
1199 break;
1200 case actionTileTopLeft:
1201 if (size)
1202 w = (Mx - mx) / 2, h = (My - my) / 2;
1203 x = mx, y = my;
1204 break;
1205 case actionTileTopRight:
1206 if (size)
1207 w = (Mx - mx) / 2, h = (My - my) / 2;
1208 x = (Mx - mx) / 2, y = my;
1209 break;
1210 case actionTileBottomLeft:
1211 if (size)
1212 w = (Mx - mx) / 2, h = (My - my) / 2;
1213 x = mx, y = (My - my) / 2;
1214 break;
1215 case actionTileBottomRight:
1216 if (size)
1217 w = (Mx - mx) / 2, h = (My - my) / 2;
1218 x = (Mx - mx) / 2, y = (My - my) / 2;
1219 break;
1220 case actionTileCenter:
1221 if (size)
1222 w = (Mx - mx) / 2, h = (My - my) / 2;
1223 x = (mx + Mx - w) / 2, y = (my + My - h) / 2;
1224 break;
1225 default: return;
1226 }
1227 if (size) {
1228 setNormalGeometryOuter(x, y, w, h);
1229 } else {
1230 setNormalPositionOuter(x, y);
1231 }
1232 }
1233 }
1234
wmSetLayer(int layer)1235 void YFrameWindow::wmSetLayer(int layer) {
1236 int previous = fWinState;
1237 setRequestedLayer(layer);
1238 if (hasbit(previous ^ fWinState, WinStateAbove | WinStateBelow)) {
1239 client()->setStateHint();
1240 }
1241 }
1242
wmSetTrayOption(int option)1243 void YFrameWindow::wmSetTrayOption(int option) {
1244 setTrayOption(option);
1245 }
1246
1247 #if DO_NOT_COVER_OLD
wmToggleDoNotCover()1248 void YFrameWindow::wmToggleDoNotCover() {
1249 setDoNotCover(!doNotCover());
1250 }
1251 #endif
1252
wmToggleFullscreen()1253 void YFrameWindow::wmToggleFullscreen() {
1254 if (isFullscreen()) {
1255 setState(WinStateFullscreen, None);
1256 }
1257 else if (canFullscreen()) {
1258 if (isUnmapped()) {
1259 makeMapped();
1260 xapp->sync();
1261 }
1262 setState(WinStateFullscreen, WinStateFullscreen);
1263 }
1264 }
1265
wmToggleTray()1266 void YFrameWindow::wmToggleTray() {
1267 if (getTrayOption() == WinTrayIgnore) {
1268 setTrayOption(WinTrayExclusive);
1269 } else {
1270 setTrayOption(WinTrayIgnore);
1271 }
1272 }
1273
wmMove()1274 void YFrameWindow::wmMove() {
1275 Window root, child;
1276 int rx, ry, wx, wy;
1277 unsigned int mask;
1278 XQueryPointer(xapp->display(), desktop->handle(),
1279 &root, &child, &rx, &ry, &wx, &wy, &mask);
1280 if (wx > int(x() + width()))
1281 wx = x() + width();
1282 if (wy > int(y() + height()))
1283 wy = y() + height();
1284 if (wx < x())
1285 wx = x();
1286 if (wy < y())
1287 wy = y();
1288 startMoveSize(true, false,
1289 0, 0,
1290 wx - x(), wy - y());
1291 }
1292
wmSize()1293 void YFrameWindow::wmSize() {
1294 startMoveSize(false, false,
1295 0, 0,
1296 0, 0);
1297 }
1298
canRestore() const1299 bool YFrameWindow::canRestore() const {
1300 return hasState(WinStateUnmapped | WinStateMaximizedBoth);
1301 }
1302
wmRestore()1303 void YFrameWindow::wmRestore() {
1304 if (canRestore()) {
1305 wmapp->signalGuiEvent(geWindowRestore);
1306 setState(WinStateUnmapped | WinStateMaximizedBoth, 0);
1307 }
1308 }
1309
wmMinimize()1310 void YFrameWindow::wmMinimize() {
1311 #ifdef DEBUG_S
1312 MSG(("wmMinimize - Frame: %d", visible()));
1313 MSG(("wmMinimize - Client: %d", client()->visible()));
1314 #endif
1315 manager->lockFocus();
1316 if (isMinimized()) {
1317 wmapp->signalGuiEvent(geWindowRestore);
1318 makeMapped();
1319 } else {
1320 wmapp->signalGuiEvent(geWindowMin);
1321 setState(WinStateUnmapped, WinStateMinimized);
1322 wmLower();
1323 }
1324 manager->unlockFocus();
1325 manager->focusLastWindow();
1326 }
1327
minimizeTransients()1328 void YFrameWindow::minimizeTransients() {
1329 for (YFrameWindow *w = transient(); w; w = w->nextTransient()) {
1330 // Since a) YFrameWindow::setState is too heavy but b) we want to save memory
1331 MSG(("> isMinimized: %d\n", w->isMinimized()));
1332 if (w->isMinimized()) {
1333 w->fWinState |= WinStateWasMinimized;
1334 } else {
1335 w->fWinState &= ~WinStateWasMinimized;
1336 w->wmMinimize();
1337 }
1338 }
1339 }
1340
restoreMinimizedTransients()1341 void YFrameWindow::restoreMinimizedTransients() {
1342 for (YFrameWindow *w = transient(); w; w = w->nextTransient())
1343 if (w->isMinimized() && !w->wasMinimized())
1344 w->setState(WinStateMinimized, 0);
1345 }
1346
hideTransients()1347 void YFrameWindow::hideTransients() {
1348 for (YFrameWindow *w = transient(); w; w = w->nextTransient()) {
1349 // See YFrameWindow::minimizeTransients() for reason
1350 MSG(("> isHidden: %d\n", w->isHidden()));
1351 if (w->isHidden()) {
1352 w->fWinState |= WinStateWasHidden;
1353 } else {
1354 w->fWinState&= ~WinStateWasHidden;
1355 w->wmHide();
1356 }
1357 }
1358 }
1359
restoreHiddenTransients()1360 void YFrameWindow::restoreHiddenTransients() {
1361 for (YFrameWindow *w = transient(); w; w = w->nextTransient())
1362 if (w->isHidden() && !w->wasHidden())
1363 w->setState(WinStateHidden, 0);
1364 }
1365
doMaximize(int flags)1366 void YFrameWindow::doMaximize(int flags) {
1367 if (isUnmapped()) {
1368 makeMapped();
1369 xapp->sync();
1370 }
1371 if (flags == (getState() & WinStateMaximizedBoth)) {
1372 wmapp->signalGuiEvent(geWindowRestore);
1373 setState(flags, None);
1374 } else {
1375 wmapp->signalGuiEvent(geWindowMax);
1376 setState(WinStateMaximizedBoth, flags);
1377 }
1378 }
1379
wmMaximize()1380 void YFrameWindow::wmMaximize() {
1381 doMaximize(WinStateMaximizedBoth);
1382 }
1383
wmMaximizeVert()1384 void YFrameWindow::wmMaximizeVert() {
1385 doMaximize(WinStateMaximizedVert);
1386 }
1387
wmMaximizeHorz()1388 void YFrameWindow::wmMaximizeHorz() {
1389 doMaximize(WinStateMaximizedHoriz);
1390 }
1391
wmRollup()1392 void YFrameWindow::wmRollup() {
1393 if (isRollup()) {
1394 wmapp->signalGuiEvent(geWindowRestore);
1395 makeMapped();
1396 } else {
1397 //if (!canRollup())
1398 // return ;
1399 wmapp->signalGuiEvent(geWindowRollup);
1400 setState(WinStateUnmapped, WinStateRollup);
1401 }
1402 }
1403
wmHide()1404 void YFrameWindow::wmHide() {
1405 if (isHidden()) {
1406 wmapp->signalGuiEvent(geWindowRestore);
1407 makeMapped();
1408 } else {
1409 wmapp->signalGuiEvent(geWindowHide);
1410 setState(WinStateUnmapped, WinStateHidden);
1411 }
1412 }
1413
wmLower()1414 void YFrameWindow::wmLower() {
1415 if (canLower()) {
1416 if (isMapped())
1417 wmapp->signalGuiEvent(geWindowLower);
1418 if (owner()) {
1419 for (YFrameWindow* w = this; w; w = w->owner()) {
1420 w->doLower();
1421 }
1422 }
1423 else if (hasState(WinStateModal) && client()->clientLeader()) {
1424 const Window leader = client()->clientLeader();
1425 YArray<YFrameWindow*> lower;
1426 lower += this;
1427 for (YFrameWindow* w = next(); w; w = w->next()) {
1428 if (leader == w->client()->clientLeader() && isGroupModalFor(w))
1429 lower += w;
1430 }
1431 for (YFrameWindow* f : lower) {
1432 f->doLower();
1433 }
1434 }
1435 else {
1436 doLower();
1437 }
1438 manager->focusTopWindow();
1439 }
1440 }
1441
doLower()1442 void YFrameWindow::doLower() {
1443 if (next()) {
1444 if (manager->setAbove(this, nullptr)) {
1445 beneath(prev());
1446 }
1447 }
1448 }
1449
wmRaise()1450 void YFrameWindow::wmRaise() {
1451 if (canRaise()) {
1452 doRaise();
1453 manager->restackWindows();
1454 }
1455 }
1456
doRaise()1457 void YFrameWindow::doRaise() {
1458 #ifdef DEBUG
1459 if (debug_z) dumpZorder("wmRaise: ", this);
1460 #endif
1461 if (prev()) {
1462 YArray<YFrameWindow*> family;
1463 family += this;
1464 const int layer = getActiveLayer();
1465 const Window leader = client()->clientLeader();
1466 if (leader && owner() == nullptr && notState(WinStateModal)) {
1467 for (auto& modal : groupModals) {
1468 if (modal == leader &&
1469 find(family, modal.frame) < 0 &&
1470 layer == modal->getActiveLayer()) {
1471 family += modal;
1472 }
1473 }
1474 }
1475 for (int i = 0; i < family.getCount(); ++i) {
1476 YFrameWindow* frame = family[i];
1477 int k = i;
1478 for (YFrameWindow* trans = frame->transient();
1479 trans != nullptr; trans = trans->nextTransient()) {
1480 if (find(family, trans) < 0 &&
1481 layer == trans->getActiveLayer()) {
1482 family.insert(++k, trans);
1483 }
1484 }
1485 }
1486
1487 YFrameWindow* topmost = manager->top(layer);
1488 while (topmost && topmost != this && 0 <= find(family, topmost)) {
1489 topmost = topmost->next();
1490 }
1491
1492 YArray<YFrameWindow*> raise, other;
1493 for (YFrameWindow* frame = topmost; frame; frame = frame->next()) {
1494 if (find(family, frame) < 0)
1495 other += frame;
1496 else
1497 raise += frame;
1498 if (frame == this)
1499 break;
1500 }
1501
1502 if (other.getCount() < raise.getCount()) {
1503 for (int i = other.getCount() - 1; 0 <= i; --i) {
1504 manager->setAbove(other[i], next());
1505 }
1506 }
1507 else {
1508 for (int i = 0; i < raise.getCount(); ++i) {
1509 manager->setAbove(raise[i], topmost);
1510 }
1511 }
1512
1513 #ifdef DEBUG
1514 if (debug_z) dumpZorder("wmRaise after raise: ", this);
1515 #endif
1516 }
1517 }
1518
wmClose()1519 void YFrameWindow::wmClose() {
1520 if (!canClose())
1521 return ;
1522
1523 manager->grabServer();
1524 client()->getProtocols(true);
1525
1526 client()->sendPing();
1527 if (client()->protocol(YFrameClient::wpDeleteWindow)) {
1528 client()->sendDelete();
1529 } else {
1530 if (frameOption(foForcedClose)) {
1531 wmKill();
1532 } else {
1533 wmConfirmKill();
1534 }
1535 }
1536 manager->ungrabServer();
1537 }
1538
wmConfirmKill(const char * message)1539 void YFrameWindow::wmConfirmKill(const char* message) {
1540 if (message == nullptr) {
1541 message = _("WARNING! All unsaved changes will be lost when\n"
1542 "this client is killed. Do you wish to proceed?");
1543 }
1544 if (fKillMsgBox) {
1545 fKillMsgBox->unmanage();
1546 }
1547 fKillMsgBox = new YMsgBox(YMsgBox::mbBoth,
1548 _("Kill Client: ") + getTitle(),
1549 message,
1550 this, "bomb");
1551 }
1552
wmKill()1553 void YFrameWindow::wmKill() {
1554 if (!canClose())
1555 return ;
1556 #ifdef DEBUG
1557 if (debug)
1558 msg("No WM_DELETE_WINDOW protocol");
1559 #endif
1560 XKillClient(xapp->display(), client()->handle());
1561 }
1562
wmPrevWindow()1563 void YFrameWindow::wmPrevWindow() {
1564 int flags = fwfNext | fwfVisible | fwfCycle |
1565 fwfFocusable | fwfWorkspace | fwfSame;
1566 YFrameWindow *f = findWindow(flags | fwfBackward);
1567 if (f && f != this) {
1568 f->wmRaise();
1569 manager->setFocus(f, true);
1570 }
1571 }
1572
wmNextWindow()1573 void YFrameWindow::wmNextWindow() {
1574 int flags = fwfNext | fwfVisible | fwfCycle |
1575 fwfFocusable | fwfWorkspace | fwfSame;
1576 YFrameWindow *f = findWindow(flags);
1577 if (f && f != this) {
1578 wmLower();
1579 f->wmRaise();
1580 manager->setFocus(f, true);
1581 }
1582 }
1583
loseWinFocus()1584 void YFrameWindow::loseWinFocus() {
1585 if (fFocused && fManaged) {
1586 fFocused = false;
1587
1588 if (hasState(WinStateFocused)) {
1589 setState(WinStateFocused | WinStateUrgent, 0);
1590 }
1591 if (true || !clientMouseActions)
1592 if (focusOnClickClient || raiseOnClickClient)
1593 if (container())
1594 container()->grabButtons();
1595 if (isIconic())
1596 fMiniIcon->repaint();
1597 else {
1598 setBackground(inactiveBorderBg);
1599 repaint();
1600 if (fTitleBar)
1601 fTitleBar->deactivate();
1602 }
1603 updateTaskBar();
1604 }
1605 }
1606
setWinFocus()1607 void YFrameWindow::setWinFocus() {
1608 if (!fFocused) {
1609 fFocused = true;
1610
1611 setState(WinStateFocused | WinStateUrgent, WinStateFocused);
1612 if (isIconic())
1613 fMiniIcon->repaint();
1614 else {
1615 if (fTitleBar)
1616 fTitleBar->activate();
1617 setBackground(activeBorderBg);
1618 repaint();
1619 }
1620 updateTaskBar();
1621
1622 if (true || !clientMouseActions) {
1623 if (!raiseOnClickClient || !canRaise() || !overlaps(bool(Below)))
1624 container()->releaseButtons();
1625 }
1626 }
1627 }
1628
updateFocusOnMap(bool & doActivate)1629 void YFrameWindow::updateFocusOnMap(bool& doActivate) {
1630 bool onCurrentWorkspace = visibleNow();
1631
1632 if (fDelayFocusTimer) {
1633 fDelayFocusTimer->stopTimer();
1634 }
1635 if (fAutoRaiseTimer) {
1636 fAutoRaiseTimer->stopTimer();
1637 }
1638
1639 if (avoidFocus())
1640 doActivate = false;
1641
1642 if (frameOption(foNoFocusOnMap))
1643 doActivate = false;
1644
1645 if (!onCurrentWorkspace && !focusChangesWorkspace && !focusCurrentWorkspace)
1646 doActivate = false;
1647
1648 if (owner() != nullptr) {
1649 if (owner()->focused() ||
1650 (nextTransient() && nextTransient()->focused()))
1651 {
1652 if (!focusOnMapTransientActive)
1653 doActivate = false;
1654 } else {
1655 if (!focusOnMapTransient)
1656 doActivate = false;
1657 }
1658 } else {
1659 bool mapUrgentGroupMember = false;
1660 if (isUrgent() && client()->clientLeader()) {
1661 YFrameWindow* f = manager->getFocus();
1662 if (f && f->client()->clientLeader() == client()->clientLeader()) {
1663 tlog("focus urgent group member %s", boolstr(doActivate));
1664 mapUrgentGroupMember = true;
1665 }
1666 }
1667 else if (manager->getFocus() && isGroupModalFor(manager->getFocus())) {
1668 if (getActiveLayer() >= manager->getFocus()->getActiveLayer()) {
1669 mapUrgentGroupMember = true;
1670 }
1671 }
1672 if (!focusOnMap && !mapUrgentGroupMember) {
1673 doActivate = false;
1674 }
1675 }
1676
1677 manager->updateUserTime(fUserTime);
1678 if (doActivate && fUserTime.good())
1679 doActivate = (fUserTime.time() && fUserTime == manager->lastUserTime());
1680 }
1681
canShow() const1682 bool YFrameWindow::canShow() const {
1683 if (isUnmapped()) {
1684 return true;
1685 }
1686
1687 int ax, ay, ar, ab;
1688
1689 manager->getWorkArea(this, &ax, &ay, &ar, &ab);
1690
1691 if ( !inrange(x(), ax - borderX(), ar - int(width()) + borderX()) ||
1692 !inrange(y(), ay - borderY() - titleY(), ab - int(height()) + borderY()))
1693 {
1694 return true;
1695 }
1696
1697 return false;
1698 }
1699
limitOuterPosition()1700 void YFrameWindow::limitOuterPosition() {
1701 int ax, ay, ar, ab;
1702 if (affectsWorkArea() || client() == taskBar) {
1703 ax = 0; ay = 0; ar = desktop->width(); ab = desktop->height();
1704 } else {
1705 manager->getWorkArea(this, &ax, &ay, &ar, &ab);
1706 }
1707 ay -= min(borderY(), int(topSideVerticalOffset));
1708 if ( !inrange(x(), ax - borderX(), ar - int(width()) + borderX()) ||
1709 !inrange(y(), ay - borderY() - titleY(),
1710 ab - int(height()) + borderY() + titleY()))
1711 {
1712 int newX = x();
1713 int newY = y();
1714
1715 if (newX > ar - int(width()) + borderX())
1716 newX = ar - int(width());
1717 if (newX < ax)
1718 newX = ax;
1719 if (newY > ab - int(height()) + borderY() + titleY())
1720 newY = ab - int(height());
1721 if (newY < ay)
1722 newY = ay;
1723
1724 setCurrentPositionOuter(newX, newY);
1725 }
1726 }
1727
wmShow()1728 void YFrameWindow::wmShow() {
1729 limitOuterPosition();
1730 if (isUnmapped()) {
1731 makeMapped();
1732 }
1733 }
1734
focus(bool canWarp)1735 void YFrameWindow::focus(bool canWarp) {
1736 if (limitPosition &&
1737 (x() >= int(desktop->width()) - borderX() ||
1738 y() >= int(desktop->height()) - borderY() - titleY() ||
1739 x() <= - int(width()) + borderX() ||
1740 y() <= - int(height()) + borderY() + titleY()))
1741 {
1742 int newX = x();
1743 int newY = y();
1744 if (newX >= int(desktop->width()) - borderX())
1745 newX = int(desktop->width()) - int(width());
1746 if (newY >= int(desktop->height()) - borderY() - titleY())
1747 newY = int(desktop->height()) - int(height());
1748 if (newX < int(- borderX()))
1749 newX = int(- borderX());
1750 if (newY < int(- borderY()))
1751 newY = int(- borderY());
1752 setCurrentPositionOuter(newX, newY);
1753 }
1754
1755 manager->setFocus(this, canWarp);
1756 if (raiseOnFocus && manager->wmState() == YWindowManager::wmRUNNING) {
1757 wmRaise();
1758 }
1759 }
1760
activate(bool canWarp,bool curWork)1761 void YFrameWindow::activate(bool canWarp, bool curWork) {
1762 manager->lockFocus();
1763 if ( ! visibleNow()) {
1764 if (focusCurrentWorkspace && curWork)
1765 setWorkspace(manager->activeWorkspace());
1766 else {
1767 workspaces[getWorkspace()].focused = this;
1768 manager->activateWorkspace(getWorkspace());
1769 xapp->sync();
1770 XEvent ignored;
1771 while (XCheckWindowEvent(xapp->display(), xapp->root(),
1772 FocusChangeMask, &ignored)) { }
1773 }
1774 }
1775 if (isUnmapped()) {
1776 makeMapped();
1777 }
1778 manager->unlockFocus();
1779 focus(canWarp);
1780 }
1781
activateWindow(bool raise,bool curWork)1782 void YFrameWindow::activateWindow(bool raise, bool curWork) {
1783 if (raise)
1784 wmRaise();
1785 activate(true, curWork);
1786 }
1787
getMiniIcon()1788 MiniIcon *YFrameWindow::getMiniIcon() {
1789 if (minimizeToDesktop && fMiniIcon == nullptr) {
1790 fMiniIcon = new MiniIcon(this);
1791 }
1792 return fMiniIcon;
1793 }
1794
refresh()1795 void YFrameWindow::refresh() {
1796 repaint();
1797 if (fTitleBar) {
1798 fTitleBar->refresh();
1799 }
1800 }
1801
repaint()1802 void YFrameWindow::repaint() {
1803 if (hasBorders()) {
1804 paint(getGraphics(), geometry());
1805 }
1806 }
1807
checkExpose(Display * display,XEvent * event,XPointer arg)1808 static Bool checkExpose(Display* display, XEvent* event, XPointer arg) {
1809 if (event->type == Expose && event->xexpose.window == *(Window*)arg) {
1810 *(Window*)arg = None;
1811 }
1812 return False;
1813 }
1814
handleExpose(const XExposeEvent & expose)1815 void YFrameWindow::handleExpose(const XExposeEvent &expose) {
1816 if (expose.count == 0) {
1817 XEvent check;
1818 Window where = expose.window;
1819 XCheckIfEvent(xapp->display(), &check, checkExpose, (XPointer) &where);
1820 if (where == expose.window) {
1821 repaint();
1822 }
1823 }
1824 }
1825
paint(Graphics & g,const YRect & r)1826 void YFrameWindow::paint(Graphics &g, const YRect& r) {
1827 if (!(frameDecors() & (fdResize | fdBorder)))
1828 return ;
1829
1830 YColor bg = focused() ? activeBorderBg : inactiveBorderBg;
1831 g.setColor(bg);
1832
1833 switch (wmLook) {
1834 case lookWin95:
1835 case lookWarp4:
1836 case lookNice:
1837 g.fillRect(1, 1, width() - 3, height() - 3);
1838 g.drawBorderW(0, 0, width() - 1, height() - 1, true);
1839 break;
1840 case lookMotif:
1841 case lookWarp3:
1842 g.draw3DRect(0, 0, width() - 1, height() - 1, true);
1843 g.draw3DRect(borderX() - 1, borderY() - 1,
1844 width() - 2 * borderX() + 1, height() - 2 * borderY() + 1,
1845 false);
1846
1847 g.fillRect(1, 1, width() - 2, borderY() - 2);
1848 g.fillRect(1, 1, borderX() - 2, height() - 2);
1849 g.fillRect(1, (height() - 1) - (borderY() - 2), width() - 2, borderX() - 2);
1850 g.fillRect((width() - 1) - (borderX() - 2), 1, borderX() - 2, height() - 2);
1851
1852 if (wmLook == lookMotif && canSize()) {
1853 g.setColor(bg.darker());
1854 g.drawLine(wsCornerX - 1, 0, wsCornerX - 1, height() - 1);
1855 g.drawLine(width() - wsCornerX - 1, 0, width() - wsCornerX - 1, height() - 1);
1856 g.drawLine(0, wsCornerY - 1, width(),wsCornerY - 1);
1857 g.drawLine(0, height() - wsCornerY - 1, width(), height() - wsCornerY - 1);
1858 g.setColor(bg.brighter());
1859 g.drawLine(wsCornerX, 0, wsCornerX, height() - 1);
1860 g.drawLine(width() - wsCornerX, 0, width() - wsCornerX, height() - 1);
1861 g.drawLine(0, wsCornerY, width(), wsCornerY);
1862 g.drawLine(0, height() - wsCornerY, width(), height() - wsCornerY);
1863 }
1864 break;
1865 case lookPixmap:
1866 case lookMetal:
1867 case lookFlat:
1868 case lookGtk:
1869 {
1870 int n = focused();
1871 int t = (frameDecors() & fdResize) ? 0 : 1;
1872
1873 if ((frameT[t][n] != null || rgbFrameT[t][n] != null) &&
1874 (frameL[t][n] != null || rgbFrameL[t][n] != null) &&
1875 (frameR[t][n] != null || rgbFrameR[t][n] != null) &&
1876 (frameB[t][n] != null || rgbFrameB[t][n] != null) &&
1877 frameTL[t][n] != null && frameTR[t][n] != null &&
1878 frameBL[t][n] != null && frameBR[t][n] != null) {
1879 int const xtl(frameTL[t][n]->width());
1880 int const ytl(frameTL[t][n]->height());
1881 int const xtr(frameTR[t][n]->width());
1882 int const ytr(frameTR[t][n]->height());
1883 int const xbl(frameBL[t][n]->width());
1884 int const ybl(frameBL[t][n]->height());
1885 int const xbr(frameBR[t][n]->width());
1886 int const ybr(frameBR[t][n]->height());
1887
1888 int const cx(width()/2);
1889 int const cy(height()/2);
1890
1891 int mxtl = min(xtl, cx);
1892 int mytl = min(ytl, max(titleY() + borderY(), cy));
1893 int mxtr = min(xtr, cx);
1894 int mytr = min(ytr, max(titleY() + borderY(), cy));
1895 int mxbl = min(xbl, cx);
1896 int mybl = min(ybl, cy);
1897 int mxbr = min(xbr, cx);
1898 int mybr = min(ybr, cy);
1899
1900 g.copyPixmap(frameTL[t][n], 0, 0,
1901 mxtl, mytl, 0, 0);
1902 g.copyPixmap(frameTR[t][n], max(0, (int)xtr - (int)cx), 0,
1903 mxtr, mytr,
1904 width() - mxtr, 0);
1905 g.copyPixmap(frameBL[t][n], 0, max(0, (int)ybl - (int)cy),
1906 mxbl, mybl,
1907 0, height() - mybl);
1908 g.copyPixmap(frameBR[t][n],
1909 max(0, (int)xbr - (int)cx), max(0, (int)ybr - (int)cy),
1910 mxbr, mybr,
1911 width() - mxbr, height() - mybr);
1912
1913 if ((int) width() > (mxtl + mxtr)) {
1914 if (frameT[t][n] != null)
1915 g.repHorz(frameT[t][n],
1916 mxtl, 0, width() - mxtl - mxtr);
1917 else g.drawGradient(rgbFrameT[t][n],
1918 mxtl, 0, width() - mxtl - mxtr, borderY());
1919 }
1920
1921 if ((int) height() > (mytl + mybl)) {
1922 if (frameL[t][n] != null) g.repVert(frameL[t][n],
1923 0, mytl, height() - mytl - mybl);
1924 else g.drawGradient(rgbFrameL[t][n],
1925 0, mytl, borderX(), height() - mytl - mybl);
1926 }
1927
1928 if ((int) height() > (mytr + mybr)) {
1929 if (frameR[t][n] != null) g.repVert(frameR[t][n],
1930 width() - borderX(), mytr, height() - mytr - mybr);
1931 else g.drawGradient(rgbFrameR[t][n],
1932 width() - borderX(), mytr,
1933 borderX(), height() - mytr - mybr);
1934 }
1935
1936 if ((int) width() > (mxbl + mxbr)) {
1937 if (frameB[t][n] != null) g.repHorz(frameB[t][n],
1938 mxbl, height() - borderY(), width() - mxbl - mxbr);
1939 else g.drawGradient(rgbFrameB[t][n],
1940 mxbl, height() - borderY(),
1941 width() - mxbl - mxbr, borderY());
1942 }
1943
1944 } else {
1945 g.fillRect(1, 1, width() - 3, height() - 3);
1946 g.drawBorderW(0, 0, width() - 1, height() - 1, true);
1947 }
1948 }
1949 break;
1950 }
1951 }
1952
handlePopDown(YPopupWindow * popup)1953 void YFrameWindow::handlePopDown(YPopupWindow *popup) {
1954 MSG(("popdown %p up %p", popup, fPopupActive));
1955 if (fPopupActive == popup)
1956 fPopupActive = nullptr;
1957 }
1958
popupSystemMenu(YWindow * owner)1959 void YFrameWindow::popupSystemMenu(YWindow *owner) {
1960 if (fPopupActive == nullptr) {
1961 if (fTitleBar &&
1962 fTitleBar->visible() &&
1963 fTitleBar->menuButton() &&
1964 fTitleBar->menuButton()->visible())
1965 {
1966 fTitleBar->menuButton()->popupMenu();
1967 }
1968 else {
1969 int ax = x() + container()->x();
1970 int ay = y() + container()->y();
1971 if (isIconic()) {
1972 ax = fMiniIcon->x();
1973 ay = fMiniIcon->y();
1974 }
1975 popupSystemMenu(owner, ax, ay,
1976 YPopupWindow::pfCanFlipVertical);
1977 }
1978 }
1979 }
1980
popupSystemMenu(YWindow * owner,int x,int y,unsigned int flags,YWindow * forWindow)1981 void YFrameWindow::popupSystemMenu(YWindow *owner, int x, int y,
1982 unsigned int flags,
1983 YWindow *forWindow)
1984 {
1985 if (fPopupActive == nullptr) {
1986 updateMenu();
1987 if (windowMenu()->itemCount() == 0)
1988 return;
1989 if (windowMenu()->popup(owner, forWindow, this,
1990 x, y, flags))
1991 fPopupActive = windowMenu();
1992 }
1993 }
1994
updateTitle()1995 void YFrameWindow::updateTitle() {
1996 layoutShape();
1997 if (fTitleBar)
1998 fTitleBar->repaint();
1999 if (fWinListItem && windowList)
2000 windowList->repaintItem(fWinListItem);
2001 if (fTaskBarApp) {
2002 fTaskBarApp->setToolTip(getTitle());
2003 fTaskBarApp->repaint();
2004 }
2005 if (fTrayApp)
2006 fTrayApp->setToolTip(getTitle());
2007 }
2008
updateIconTitle()2009 void YFrameWindow::updateIconTitle() {
2010 if (fTaskBarApp)
2011 fTaskBarApp->repaint();
2012 if (isIconic())
2013 fMiniIcon->repaint();
2014 }
2015
wmOccupyAllOrCurrent()2016 void YFrameWindow::wmOccupyAllOrCurrent() {
2017 if (isAllWorkspaces()) {
2018 wmOccupyWorkspace(manager->activeWorkspace());
2019 } else {
2020 setAllWorkspaces();
2021 }
2022 }
2023
wmOccupyAll()2024 void YFrameWindow::wmOccupyAll() {
2025 if (!isAllWorkspaces())
2026 setAllWorkspaces();
2027 }
2028
wmOccupyWorkspace(int workspace)2029 void YFrameWindow::wmOccupyWorkspace(int workspace) {
2030 PRECONDITION(workspace < workspaceCount);
2031 mainOwner()->setWorkspace(workspace);
2032 }
2033
updateAllowed()2034 void YFrameWindow::updateAllowed() {
2035 Atom atoms[12];
2036 int i = 0;
2037 if ((fFrameFunctions & ffMove) || (fFrameDecors & fdTitleBar))
2038 atoms[i++] = _XA_NET_WM_ACTION_MOVE;
2039 if ((fFrameFunctions & ffResize) || (fFrameDecors & fdResize))
2040 atoms[i++] = _XA_NET_WM_ACTION_RESIZE;
2041 if ((fFrameFunctions & ffClose) || (fFrameDecors & fdClose))
2042 atoms[i++] = _XA_NET_WM_ACTION_CLOSE;
2043 if ((fFrameFunctions & ffMinimize) || (fFrameDecors & fdMinimize))
2044 atoms[i++] = _XA_NET_WM_ACTION_MINIMIZE;
2045 if ((fFrameFunctions & ffMaximize) || (fFrameDecors & fdMaximize)) {
2046 atoms[i++] = _XA_NET_WM_ACTION_MAXIMIZE_HORZ;
2047 atoms[i++] = _XA_NET_WM_ACTION_MAXIMIZE_VERT;
2048 }
2049 if ((fFrameFunctions & ffRollup) || (fFrameDecors & fdRollup))
2050 atoms[i++] = _XA_NET_WM_ACTION_SHADE;
2051 if (canFullscreen())
2052 atoms[i++] = _XA_NET_WM_ACTION_FULLSCREEN;
2053 if (true || (fFrameDecors & fdDepth)) {
2054 atoms[i++] = _XA_NET_WM_ACTION_ABOVE;
2055 atoms[i++] = _XA_NET_WM_ACTION_BELOW;
2056 }
2057 atoms[i++] = _XA_NET_WM_ACTION_STICK;
2058 atoms[i++] = _XA_NET_WM_ACTION_CHANGE_DESKTOP;
2059 client()->setNetWMAllowedActions(atoms,i);
2060 }
2061
getFrameHints()2062 void YFrameWindow::getFrameHints() {
2063 long decors = client()->mwmDecors();
2064 long functions = client()->mwmFunctions();
2065 long win_hints = client()->winHints();
2066 MwmHints *mwm_hints = client()->mwmHints();
2067 int functions_only = (mwm_hints && mwm_hints->onlyFuncs());
2068
2069 unsigned long old_functions = fFrameFunctions;
2070 unsigned long old_decors = fFrameDecors;
2071
2072 fFrameFunctions = 0;
2073 fFrameDecors = 0;
2074 fFrameOptions = 0;
2075
2076 if (decors & MWM_DECOR_BORDER) fFrameDecors |= fdBorder;
2077 if (decors & MWM_DECOR_RESIZEH) fFrameDecors |= fdResize;
2078 if (decors & MWM_DECOR_TITLE) fFrameDecors |= fdTitleBar | fdDepth;
2079 if (decors & MWM_DECOR_MENU) fFrameDecors |= fdSysMenu;
2080 if (decors & MWM_DECOR_MAXIMIZE) fFrameDecors |= fdMaximize;
2081 if (decors & MWM_DECOR_MINIMIZE) fFrameDecors |= fdMinimize | fdHide | fdRollup;
2082
2083 if (functions & MWM_FUNC_MOVE) {
2084 fFrameFunctions |= ffMove;
2085 if (functions_only)
2086 fFrameDecors |= fdBorder;
2087 }
2088 if (functions & MWM_FUNC_RESIZE) {
2089 fFrameFunctions |= ffResize;
2090 if (functions_only)
2091 fFrameDecors |= fdResize | fdBorder;
2092 }
2093 if (functions & MWM_FUNC_MAXIMIZE) {
2094 fFrameFunctions |= ffMaximize;
2095 if (functions_only)
2096 fFrameDecors |= fdMaximize;
2097 }
2098 if (functions & MWM_FUNC_MINIMIZE) {
2099 fFrameFunctions |= ffMinimize | ffHide | ffRollup;
2100 if (functions_only)
2101 fFrameDecors |= fdMinimize | fdHide | fdRollup;
2102 }
2103 if (functions & MWM_FUNC_CLOSE) {
2104 fFrameFunctions |= ffClose;
2105 fFrameDecors |= fdClose;
2106 }
2107
2108 /// !!! fFrameOptions needs refactoring
2109 if (win_hints & WinHintsSkipFocus)
2110 fFrameOptions |= foIgnoreQSwitch;
2111 if (win_hints & WinHintsSkipWindowMenu)
2112 fFrameOptions |= foIgnoreWinList;
2113 if (win_hints & WinHintsSkipTaskBar)
2114 fFrameOptions |= foIgnoreTaskBar;
2115 if (win_hints & WinHintsDoNotCover)
2116 fFrameOptions |= foDoNotCover;
2117
2118 /// TODO #warning "need initial window mapping cleanup"
2119 switch (fWindowType) {
2120 case wtCombo:
2121 fFrameFunctions = 0;
2122 fFrameDecors = 0;
2123 fFrameOptions |= foIgnoreTaskBar | foIgnoreWinList | foIgnoreQSwitch;
2124 break;
2125 case wtDesktop:
2126 fFrameFunctions = 0;
2127 fFrameDecors = 0;
2128 fFrameOptions |= foIgnoreTaskBar | foIgnoreWinList | foIgnoreQSwitch |
2129 foNoFocusOnMap;
2130 break;
2131 case wtDialog:
2132 break;
2133 case wtDND:
2134 fFrameFunctions = ffMove;
2135 fFrameDecors = 0;
2136 fFrameOptions |= foIgnoreTaskBar | foIgnoreWinList | foIgnoreQSwitch |
2137 foNoFocusOnMap | foDoNotFocus;
2138 break;
2139 case wtDock:
2140 fFrameFunctions = 0;
2141 fFrameDecors = 0;
2142 fFrameOptions |= foIgnoreTaskBar | foIgnoreWinList | foIgnoreQSwitch |
2143 foNoFocusOnMap;
2144 break;
2145 case wtDropdownMenu:
2146 fFrameFunctions = 0;
2147 fFrameDecors = 0;
2148 fFrameOptions |= foIgnoreTaskBar | foIgnoreWinList | foIgnoreQSwitch;
2149 break;
2150 case wtMenu:
2151 fFrameFunctions &= ~(ffResize | ffMinimize | ffMaximize);
2152 fFrameDecors = fdTitleBar | fdSysMenu | fdClose | fdRollup;
2153 fFrameOptions |= foIgnoreTaskBar | foIgnoreWinList | foIgnoreQSwitch;
2154 break;
2155 case wtNormal:
2156 break;
2157 case wtNotification:
2158 fFrameFunctions = 0;
2159 fFrameDecors = 0;
2160 fFrameOptions |= foIgnoreTaskBar | foIgnoreWinList | foIgnoreQSwitch |
2161 foNoFocusOnMap;
2162 break;
2163 case wtPopupMenu:
2164 fFrameFunctions = 0;
2165 fFrameDecors = 0;
2166 fFrameOptions |= foIgnoreTaskBar | foIgnoreWinList | foIgnoreQSwitch;
2167 break;
2168 case wtSplash:
2169 fFrameFunctions = 0;
2170 fFrameDecors = 0;
2171 fFrameOptions |= foIgnoreTaskBar | foIgnoreWinList | foIgnoreQSwitch |
2172 foNoFocusOnMap;
2173 break;
2174 case wtToolbar:
2175 break;
2176 case wtTooltip:
2177 fFrameFunctions = 0;
2178 fFrameDecors = 0;
2179 fFrameOptions |= foIgnoreTaskBar | foIgnoreWinList | foIgnoreQSwitch |
2180 foNoFocusOnMap | foDoNotFocus;
2181 break;
2182 case wtUtility:
2183 break;
2184 }
2185
2186 if (client()->shaped())
2187 fFrameDecors &= ~(fdTitleBar | fdBorder);
2188
2189 WindowOption wo(getWindowOption());
2190
2191 /*msg("decor: %lX %lX %lX %lX %lX %lX",
2192 wo.function_mask, wo.functions,
2193 wo.decor_mask, wo.decors,
2194 wo.option_mask, wo.options);*/
2195
2196 fFrameFunctions &= ~wo.function_mask;
2197 fFrameFunctions |= wo.functions;
2198 fFrameDecors &= ~wo.decor_mask;
2199 fFrameDecors |= wo.decors;
2200 fFrameOptions &= ~(wo.option_mask & fWinOptionMask);
2201 fFrameOptions |= (wo.options & fWinOptionMask);
2202
2203 if (hasbit((fFrameFunctions | fFrameDecors) ^ (old_functions | old_decors), 63))
2204 {
2205 updateAllowed();
2206 }
2207 }
2208
getWindowOption()2209 WindowOption YFrameWindow::getWindowOption() {
2210 WindowOption wo;
2211 if (haveHintOption()) {
2212 wo = getHintOption();
2213 }
2214 if (defOptions) {
2215 getWindowOptions(defOptions, wo, false);
2216 }
2217 return wo;
2218 }
2219
getWindowOptions(WindowOptions * list,WindowOption & opt,bool remove)2220 void YFrameWindow::getWindowOptions(WindowOptions *list, WindowOption &opt,
2221 bool remove)
2222 {
2223 const ClassHint* h = client()->classHint();
2224 mstring klass(h->res_class);
2225 mstring name(h->res_name);
2226 mstring role(client()->windowRole());
2227
2228 if (klass != null) {
2229 if (name != null) {
2230 mstring klass_instance(h->res_class, ".", h->res_name);
2231 list->mergeWindowOption(opt, klass_instance, remove);
2232
2233 mstring name_klass(h->res_name, ".", h->res_class);
2234 list->mergeWindowOption(opt, name_klass, remove);
2235 }
2236 list->mergeWindowOption(opt, klass, remove);
2237 }
2238 if (name != null) {
2239 if (role != null) {
2240 mstring name_role = name.append(".").append(role);
2241 list->mergeWindowOption(opt, name_role, remove);
2242 }
2243 list->mergeWindowOption(opt, name, remove);
2244 }
2245 if (role != null)
2246 list->mergeWindowOption(opt, role, remove);
2247 list->mergeWindowOption(opt, null, remove);
2248 }
2249
getDefaultOptions(bool & requestFocus)2250 void YFrameWindow::getDefaultOptions(bool &requestFocus) {
2251 WindowOption wo(getWindowOption());
2252
2253 if (wo.icon.nonempty()) {
2254 ref<YIcon> icon = YIcon::getIcon(wo.icon);
2255 if (icon != null)
2256 fFrameIcon = icon;
2257 }
2258 if (inrange(wo.workspace, 0, workspaceCount - 1)) {
2259 setWorkspace(wo.workspace);
2260 if (wo.workspace != manager->activeWorkspace())
2261 requestFocus = false;
2262 }
2263 if (inrange(wo.layer, 0, WinLayerCount - 1))
2264 setRequestedLayer(wo.layer);
2265 if (inrange(wo.tray, 0, WinTrayOptionCount - 1))
2266 setTrayOption(wo.tray);
2267 fTrayOrder = wo.order;
2268 }
2269
newClientIcon(int count,int reclen,long * elem)2270 ref<YIcon> newClientIcon(int count, int reclen, long * elem) {
2271 ref<YImage> small;
2272 ref<YImage> large;
2273 ref<YImage> huge;
2274
2275 if (reclen < 2)
2276 return null;
2277 for (int i = 0; i < count; i++, elem += reclen) {
2278 Pixmap pixmap(elem[0]), mask(elem[1]);
2279 if (pixmap == None) {
2280 warn("pixmap == None for subicon #%d", i);
2281 continue;
2282 }
2283
2284 unsigned w = 0, h = 0, depth = 0;
2285
2286 if (reclen >= 6) {
2287 w = elem[2];
2288 h = elem[3];
2289 depth = elem[4];
2290 } else {
2291 Window root;
2292 int x, y;
2293 unsigned w1, h1, border;
2294 if (XGetGeometry(xapp->display(), pixmap,
2295 &root, &x, &y, &w1, &h1,
2296 &border, &depth) != True) {
2297 warn("BadDrawable for subicon #%d", i);
2298 continue;
2299 }
2300 w = w1;
2301 h = h1;
2302 }
2303
2304 MSG(("client icon: %ld %ux%u %d", pixmap, w, h, depth));
2305 if (inrange(w, 1U, 256U) + inrange(h, 1U, 256U) != 2) {
2306 MSG(("Invalid pixmap size for subicon #%d: %ux%u", i, w, h));
2307 continue;
2308 }
2309
2310 if (depth == 1) {
2311 ref<YPixmap> img = YPixmap::create(w, h, xapp->depth());
2312 Graphics g(img);
2313
2314 g.setColorPixel(0xffffffff);
2315 g.fillRect(0, 0, w, h);
2316 g.setColorPixel(0xff000000);
2317 g.setClipMask(pixmap);
2318 g.fillRect(0, 0, w, h);
2319
2320 ref<YImage> img2 =
2321 YImage::createFromPixmapAndMask(img->pixmap(), mask, w, h);
2322
2323 if (w <= YIcon::smallSize() || h <= YIcon::smallSize())
2324 small = img2;
2325 else if (small == null)
2326 small = img2->scale(YIcon::smallSize(), YIcon::smallSize());
2327 if (YIcon::smallSize() == YIcon::largeSize())
2328 large = small;
2329 else if (YIcon::smallSize() < w && w <= YIcon::largeSize()) {
2330 if (large == null || w > large->width()) {
2331 large = img2;
2332 }
2333 }
2334 else if (YIcon::largeSize() < w && large == null)
2335 large = img2->scale(YIcon::largeSize(), YIcon::largeSize());
2336 if (YIcon::largeSize() == YIcon::hugeSize())
2337 huge = large;
2338 else if (YIcon::largeSize() < w && w <= YIcon::hugeSize()) {
2339 if (huge == null || w > huge->width()) {
2340 huge = img2;
2341 }
2342 }
2343 else if (huge == null)
2344 huge = img2->scale(YIcon::hugeSize(), YIcon::hugeSize());
2345 img = null;
2346 }
2347
2348 if (depth == xapp->depth() || depth == 24U) {
2349 if (w <= YIcon::smallSize()) {
2350 small = YImage::createFromPixmapAndMaskScaled(
2351 pixmap, mask, w, h, YIcon::smallSize(), YIcon::smallSize());
2352 }
2353 else if (w <= YIcon::largeSize()) {
2354 large = YImage::createFromPixmapAndMaskScaled(
2355 pixmap, mask, w, h, YIcon::largeSize(), YIcon::largeSize());
2356 }
2357 else if (huge == null) {
2358 huge = YImage::createFromPixmapAndMaskScaled(
2359 pixmap, mask, w, h, YIcon::hugeSize(), YIcon::hugeSize());
2360 }
2361 }
2362 }
2363
2364 if (huge != null) {
2365 if (small == null)
2366 small = huge->scale(YIcon::smallSize(), YIcon::smallSize());
2367 if (large == null)
2368 large = huge->scale(YIcon::largeSize(), YIcon::largeSize());
2369 }
2370
2371 ref<YIcon> icon;
2372 if (small != null || large != null || huge != null)
2373 icon.init(new YIcon(small, large, huge));
2374 return icon;
2375 }
2376
updateIcon()2377 void YFrameWindow::updateIcon() {
2378 long count;
2379 long* elem;
2380 Pixmap* pixmap;
2381 Atom type;
2382
2383 /// TODO #warning "think about winoptions specified icon here"
2384
2385 ref<YIcon> oldFrameIcon = fFrameIcon;
2386
2387 if (client()->getNetWMIcon(&count, &elem)) {
2388 ref<YImage> icons[3], largestIcon;
2389 const long sizes[3] = {
2390 long(YIcon::smallSize()),
2391 long(YIcon::largeSize()),
2392 long(YIcon::hugeSize())
2393 };
2394 long* largestOffset = nullptr;
2395 long largestSize = 0;
2396
2397 // Find icons that match Small-/Large-/HugeIconSize and search
2398 // for the largest icon from NET_WM_ICON set.
2399 for (long *e = elem;
2400 e + 2 < elem + count && e[0] > 0 && e[1] > 0;
2401 e += 2 + e[0] * e[1]) {
2402 long w = e[0], h = e[1], *d = e + 2;
2403 if (w == h && d + w*h <= elem + count) {
2404 // Maybe huge=large=small, so examine all sizes[].
2405 for (int i = 0; i < 3; i++) {
2406 if (w == sizes[i] && icons[i] == null) {
2407 if (i >= 1 && sizes[i - 1] == sizes[i]) {
2408 icons[i] = icons[i - 1];
2409 } else {
2410 icons[i] = YImage::createFromIconProperty(d, w, h);
2411 if (w > largestSize) {
2412 largestOffset = d;
2413 largestSize = w;
2414 largestIcon = icons[i];
2415 }
2416 }
2417 }
2418 }
2419 if ((w > largestSize && largestSize < sizes[2]) ||
2420 (w > sizes[2] && w < largestSize))
2421 {
2422 largestOffset = d;
2423 largestSize = w;
2424 }
2425 }
2426 }
2427
2428 // Create missing icons by scaling the largest icon.
2429 for (int i = 0; i < 3; i++) {
2430 if (icons[i] == null) {
2431 // create the largest icon
2432 if (largestIcon == null && largestOffset && largestSize) {
2433 largestIcon =
2434 YImage::createFromIconProperty(largestOffset,
2435 largestSize,
2436 largestSize);
2437 }
2438 if (largestIcon != null) {
2439 icons[i] = largestIcon->scale(sizes[i], sizes[i]);
2440 }
2441 }
2442 }
2443 fFrameIcon.init(new YIcon(icons[0], icons[1], icons[2]));
2444 XFree(elem);
2445 }
2446 else if (client()->getWinIcons(&type, &count, &elem)) {
2447 if (type == _XA_WIN_ICONS)
2448 fFrameIcon = newClientIcon(elem[0], elem[1], elem + 2);
2449 else // compatibility
2450 fFrameIcon = newClientIcon(count/2, 2, elem);
2451 XFree(elem);
2452 }
2453 else if (client()->getKwmIcon(&count, &pixmap) && count == 2) {
2454 long pix[4] = {
2455 long(pixmap[0]),
2456 long(pixmap[1]),
2457 long(client()->iconPixmapHint()),
2458 long(client()->iconMaskHint()),
2459 };
2460 XFree(pixmap);
2461 fFrameIcon = newClientIcon(1 + (pix[2] != None), 2, pix);
2462 }
2463 else if (client()->iconPixmapHint()) {
2464 long pix[2] = {
2465 long(client()->iconPixmapHint()),
2466 long(client()->iconMaskHint()),
2467 };
2468 fFrameIcon = newClientIcon(1, 2, pix);
2469 }
2470
2471 if (fFrameIcon == null) {
2472 const char* name = client()->classHint()->res_name;
2473 if (nonempty(name)) {
2474 fFrameIcon = YIcon::getIcon(name);
2475 }
2476 }
2477 if (fFrameIcon == null && client()->adopted() == false) {
2478 fFrameIcon = YIcon::getIcon("icewm");
2479 }
2480
2481 if (fFrameIcon != null) {
2482 if (fFrameIcon->small() == null && fFrameIcon->large() == null) {
2483 fFrameIcon = null;
2484 }
2485 }
2486
2487 if (fFrameIcon == null) {
2488 fFrameIcon = oldFrameIcon;
2489 }
2490
2491 if (fTitleBar && fTitleBar->menuButton())
2492 fTitleBar->menuButton()->repaint();
2493 if (fMiniIcon)
2494 fMiniIcon->updateIcon();
2495 if (fTrayApp)
2496 fTrayApp->repaint();
2497 if (fTaskBarApp)
2498 fTaskBarApp->repaint();
2499 if (windowList && fWinListItem && windowList->visible())
2500 windowList->repaintItem(fWinListItem);
2501 }
2502
nextLayer()2503 YFrameWindow *YFrameWindow::nextLayer() {
2504 if (next()) return next();
2505
2506 for (long l(getActiveLayer() - 1); l > -1; --l)
2507 if (manager->top(l)) return manager->top(l);
2508
2509 return nullptr;
2510 }
2511
prevLayer()2512 YFrameWindow *YFrameWindow::prevLayer() {
2513 if (prev()) return prev();
2514
2515 for (long l(getActiveLayer() + 1); l < WinLayerCount; ++l)
2516 if (manager->bottom(l)) return manager->bottom(l);
2517
2518 return nullptr;
2519 }
2520
windowMenu()2521 YMenu *YFrameWindow::windowMenu() {
2522 //if (frameOption(foFullKeys))
2523 // return windowMenuNoKeys;
2524 //else
2525 return wmapp->getWindowMenu();
2526 }
2527
addAsTransient()2528 bool YFrameWindow::addAsTransient() {
2529 Window ownerWindow(client()->ownerWindow());
2530 if (ownerWindow) {
2531 fOwner = manager->findFrame(ownerWindow);
2532 if (fOwner) {
2533 YArray<YFrameWindow*> owners;
2534 for (YFrameWindow* o = fOwner;
2535 o && find(owners, o) < 0;
2536 o = o->owner())
2537 {
2538 owners += o;
2539 }
2540 if (0 <= find(owners, this)) {
2541 fOwner = nullptr;
2542 return false;
2543 }
2544
2545 MSG(("transient for 0x%lX: 0x%p", ownerWindow, fOwner));
2546 PRECONDITION(fOwner->transient() != this);
2547
2548 fNextTransient = fOwner->transient();
2549 fOwner->setTransient(this);
2550
2551 if (getActiveLayer() < fOwner->getActiveLayer()) {
2552 setRequestedLayer(fOwner->getActiveLayer());
2553 }
2554 if (fNextTransient &&
2555 fNextTransient->getActiveLayer() == getActiveLayer())
2556 {
2557 setAbove(fNextTransient);
2558 }
2559 else if (fOwner->getActiveLayer() == getActiveLayer()) {
2560 setAbove(owner());
2561 }
2562 setWorkspace(owner()->getWorkspace());
2563 return true;
2564 }
2565 }
2566 if (ownerWindow == xapp->root() ||
2567 (ownerWindow == None && hasState(WinStateModal)))
2568 {
2569 Window leader = client()->clientLeader();
2570 if (leader && leader != client()->handle() && leader != xapp->root()) {
2571 groupModals += GroupModal(leader, this);
2572 if (notState(WinStateModal)) {
2573 fWinState |= WinStateModal;
2574 }
2575 }
2576 }
2577 return false;
2578 }
2579
removeAsTransient()2580 void YFrameWindow::removeAsTransient() {
2581 if (fOwner) {
2582 MSG(("removeAsTransient"));
2583
2584 for (YFrameWindow *curr = fOwner->transient(), *prev = nullptr;
2585 curr; prev = curr, curr = curr->nextTransient()) {
2586 if (curr == this) {
2587 if (prev)
2588 prev->setNextTransient(nextTransient());
2589 else
2590 fOwner->setTransient(nextTransient());
2591 break;
2592 }
2593 }
2594
2595 fOwner = nullptr;
2596 fNextTransient = nullptr;
2597 }
2598 if (groupModals.nonempty() && hasState(WinStateModal)) {
2599 for (int i = groupModals.getCount() - 1; 0 <= i; --i) {
2600 if (groupModals[i] == this) {
2601 groupModals.remove(i);
2602 }
2603 }
2604 }
2605 }
2606
addTransients()2607 void YFrameWindow::addTransients() {
2608 YArray<YFrameWindow*> owners;
2609 for (YFrameWindow* w(manager->bottomLayer()); w; w = w->prevLayer()) {
2610 if (w->owner() == nullptr) {
2611 Window cow = w->client()->ownerWindow();
2612 if (cow && cow == client()->handle()) {
2613 if (owner()) {
2614 if (owners.isEmpty()) {
2615 for (YFrameWindow* o = owner();
2616 o && find(owners, o) < 0;
2617 o = o->owner())
2618 {
2619 owners += o;
2620 }
2621 }
2622 if (0 <= find(owners, w)) {
2623 continue;
2624 }
2625 }
2626 w->addAsTransient();
2627 }
2628 }
2629 }
2630 }
2631
removeTransients()2632 void YFrameWindow::removeTransients() {
2633 if (transient()) {
2634 MSG(("removeTransients"));
2635 for (YFrameWindow* tran = transient(), *next; tran; tran = next) {
2636 next = tran->nextTransient();
2637 tran->setNextTransient(nullptr);
2638 tran->setOwner(nullptr);
2639 }
2640 fTransient = nullptr;
2641 }
2642 }
2643
isModal()2644 bool YFrameWindow::isModal() {
2645 if (hasState(WinStateModal))
2646 return true;
2647
2648 MwmHints *mwmHints = client()->mwmHints();
2649 if (mwmHints && (mwmHints->flags & MWM_HINTS_INPUT_MODE))
2650 if (mwmHints->input_mode != MWM_INPUT_MODELESS)
2651 return true;
2652
2653 if (hasModal())
2654 return true;
2655
2656 return false;
2657 }
2658
hasModal()2659 bool YFrameWindow::hasModal() {
2660 for (YFrameWindow *w = transient(); w; w = w->nextTransient()) {
2661 if (w->isModal())
2662 return true;
2663 }
2664
2665 /* search for app modal dialogs */
2666 if (groupModals.nonempty()) {
2667 bool self = false, that = false;
2668 for (const auto& modal : groupModals) {
2669 if (modal == client()->clientLeader())
2670 that = true;
2671 if (modal == this)
2672 self = true;
2673 }
2674 if (that && !self)
2675 return true;
2676 }
2677
2678 return false;
2679 }
2680
canFocus()2681 bool YFrameWindow::canFocus() {
2682 if (hasModal())
2683 return false;
2684
2685 return true;
2686 }
2687
canFocusByMouse()2688 bool YFrameWindow::canFocusByMouse() {
2689 return canFocus() && !avoidFocus();
2690 }
2691
avoidFocus()2692 bool YFrameWindow::avoidFocus() {
2693 if (frameOption(foDoNotFocus))
2694 return true;
2695
2696 if (getInputFocusHint())
2697 return false;
2698
2699 if (frameOption(foIgnoreNoFocusHint))
2700 return false;
2701
2702 if (client()->protocol(YFrameClient::wpTakeFocus) ||
2703 frameOption(foAppTakesFocus))
2704 return false;
2705
2706 return true;
2707 }
2708
getInputFocusHint()2709 bool YFrameWindow::getInputFocusHint() {
2710 bool input = true;
2711
2712 if ( !frameOption(foIgnoreNoFocusHint) && client()->wmHint(InputHint)) {
2713 input = bool(client()->hints()->input & True);
2714 }
2715 if (frameOption(foDoNotFocus)) {
2716 input = false;
2717 }
2718 return input;
2719 }
2720
2721
setWorkspace(int workspace)2722 void YFrameWindow::setWorkspace(int workspace) {
2723 if ( ! inrange(workspace + 1, 0, int(workspaceCount)))
2724 return ;
2725 if (workspace != fWinWorkspace) {
2726 int activeWS = int(manager->activeWorkspace());
2727 bool otherWS = (workspace != AllWorkspaces && workspace != activeWS);
2728 bool refocus = (this == manager->getFocus() && otherWS);
2729 if (otherWS) {
2730 int ws = (fWinWorkspace >= 0 ? fWinWorkspace : activeWS);
2731 if (workspaces[ws].focused == this) {
2732 workspaces[ws].focused = nullptr;
2733 }
2734 }
2735 fWinWorkspace = workspace;
2736 if (isAllWorkspaces())
2737 fWinState |= WinStateSticky;
2738 else
2739 fWinState &= ~WinStateSticky;
2740 client()->setWorkspaceHint(fWinWorkspace);
2741 updateState();
2742 if (refocus)
2743 manager->focusLastWindow();
2744 updateTaskBar();
2745 if (windowList && fWinListItem)
2746 windowList->updateWindowListApp(fWinListItem);
2747 for (YFrameWindow *t = transient(); t; t = t->nextTransient()) {
2748 t->setWorkspace(getWorkspace());
2749 }
2750 if (taskBar)
2751 taskBar->workspacesRepaint();
2752 }
2753 }
2754
mainOwner()2755 YFrameWindow *YFrameWindow::mainOwner() {
2756 YFrameWindow *f = this;
2757 while (f->owner()) {
2758 f = f->owner();
2759 }
2760 return f;
2761 }
2762
2763
setRequestedLayer(int layer)2764 void YFrameWindow::setRequestedLayer(int layer) {
2765 if (inrange<int>(layer, WinLayerDesktop, WinLayerAboveAll)) {
2766 if (fWinRequestedLayer != layer ||
2767 (hasState(WinStateAbove) && layer != WinLayerOnTop) ||
2768 (hasState(WinStateBelow) && layer != WinLayerBelow))
2769 {
2770 fWinRequestedLayer = layer;
2771
2772 int state = (fWinState & ~(WinStateAbove | WinStateBelow));
2773 if (layer == WinLayerOnTop) {
2774 state |= WinStateAbove;
2775 }
2776 if (layer == WinLayerBelow) {
2777 state |= WinStateBelow;
2778 }
2779 if (fWinState != state) {
2780 fWinState = state;
2781 }
2782
2783 updateLayer();
2784 }
2785 }
2786 }
2787
windowTypeLayer() const2788 int YFrameWindow::windowTypeLayer() const {
2789 int newLayer = fWinRequestedLayer;
2790
2791 switch (fWindowType) {
2792 case wtCombo:
2793 newLayer = WinLayerMenu;
2794 break;
2795 case wtDesktop:
2796 newLayer = WinLayerDesktop;
2797 break;
2798 case wtDialog:
2799 break;
2800 case wtDND:
2801 newLayer = WinLayerAboveAll;
2802 break;
2803 case wtDock:
2804 newLayer = WinLayerDock;
2805 break;
2806 case wtDropdownMenu:
2807 newLayer = WinLayerMenu;
2808 break;
2809 case wtMenu:
2810 newLayer = WinLayerMenu;
2811 break;
2812 case wtNormal:
2813 break;
2814 case wtNotification:
2815 newLayer = WinLayerAboveDock;
2816 break;
2817 case wtPopupMenu:
2818 newLayer = WinLayerMenu;
2819 break;
2820 case wtSplash:
2821 break;
2822 case wtToolbar:
2823 break;
2824 case wtTooltip:
2825 newLayer = WinLayerAboveAll;
2826 break;
2827 case wtUtility:
2828 break;
2829 }
2830 return newLayer;
2831 }
2832
updateLayer(bool restack)2833 void YFrameWindow::updateLayer(bool restack) {
2834 long oldLayer = fWinActiveLayer;
2835 long newLayer = windowTypeLayer();
2836
2837 if (hasState(WinStateBelow))
2838 newLayer = WinLayerBelow;
2839 if (hasState(WinStateAbove))
2840 newLayer = WinLayerOnTop;
2841 if (fOwner) {
2842 if (newLayer < fOwner->getActiveLayer())
2843 newLayer = fOwner->getActiveLayer();
2844 }
2845 if (isFullscreen() && manager->fullscreenEnabled()) {
2846 for (YFrameWindow *f = manager->getFocus(); f; f = f->owner()) {
2847 if (f == this) {
2848 newLayer = WinLayerFullscreen;
2849 break;
2850 }
2851 }
2852 }
2853
2854 if (newLayer != fWinActiveLayer) {
2855 removeFrame();
2856 fWinActiveLayer = newLayer;
2857 insertFrame(oldLayer != WinLayerFullscreen
2858 || !manager->switchWindowVisible());
2859
2860 if (client() && !client()->destroyed())
2861 client()->setLayerHint(fWinActiveLayer);
2862
2863 if (limitByDockLayer &&
2864 (newLayer == WinLayerDock || oldLayer == WinLayerDock) &&
2865 client() != taskBar)
2866 manager->requestWorkAreaUpdate();
2867
2868 for (YFrameWindow *w = transient(); w; w = w->nextTransient()) {
2869 w->updateLayer(false);
2870 }
2871
2872 if (restack)
2873 manager->restackWindows();
2874 if (taskBar)
2875 taskBar->workspacesRepaint();
2876 }
2877 }
2878
setTrayOption(int option)2879 void YFrameWindow::setTrayOption(int option) {
2880 if (option >= WinTrayOptionCount || option < 0)
2881 return ;
2882 if (option != fWinTrayOption) {
2883 fWinTrayOption = option;
2884 updateTaskBar();
2885 }
2886 }
2887
updateState()2888 void YFrameWindow::updateState() {
2889 if (!isManaged() || client()->destroyed())
2890 return ;
2891
2892 client()->setStateHint();
2893
2894 // some code is probably against the ICCCM.
2895 // some applications misbehave either way.
2896 // (some hide windows on iconize, this is bad when switching workspaces
2897 // or rolling up the window).
2898
2899 bool iconic = isHidden() || isMinimized();
2900 bool hidden = iconic || isRollup() || !visibleNow();
2901
2902 MSG(("updateState: winState=0x%X, client=%d", fWinState, !hidden));
2903
2904 client()->setFrameState(iconic ? IconicState : NormalState);
2905
2906 if (hidden) {
2907 setVisible(isRollup() && visibleNow());
2908 container()->hide();
2909 client()->hide();
2910
2911 if (fDelayFocusTimer)
2912 fDelayFocusTimer->disableTimerListener(this);
2913 if (fAutoRaiseTimer)
2914 fAutoRaiseTimer->disableTimerListener(this);
2915 }
2916 else {
2917 client()->show();
2918 container()->show();
2919 show();
2920 }
2921 }
2922
affectsWorkArea() const2923 bool YFrameWindow::affectsWorkArea() const {
2924 bool affects = ((fHaveStruts || doNotCover() ||
2925 getActiveLayer() == WinLayerDock) &&
2926 client() != taskBar);
2927 return affects;
2928 }
2929
inWorkArea() const2930 bool YFrameWindow::inWorkArea() const {
2931 if (doNotCover())
2932 return false;
2933 if (isFullscreen())
2934 return false;
2935 if (getActiveLayer() >= WinLayerDock) {
2936 if (getActiveLayer() != WinLayerFullscreen)
2937 return false;
2938 }
2939 return !fHaveStruts;
2940 }
2941
getNormalGeometryInner(int * x,int * y,int * w,int * h) const2942 void YFrameWindow::getNormalGeometryInner(int *x, int *y, int *w, int *h) const {
2943 XSizeHints *sh = client()->sizeHints();
2944 *x = normalX;
2945 *y = normalY;
2946 *w = sh ? normalW * max(1, sh->width_inc) + sh->base_width : normalW;
2947 *h = sh ? normalH * max(1, sh->height_inc) + sh->base_height : normalH;
2948 }
2949
setNormalGeometryOuter(int ox,int oy,int ow,int oh)2950 void YFrameWindow::setNormalGeometryOuter(int ox, int oy, int ow, int oh) {
2951 int ix = ox + borderXN();
2952 int iy = oy + borderYN();
2953 int iw = ow - (2 * borderXN());
2954 int ih = oh - (2 * borderYN() + titleYN());
2955 setNormalGeometryInner(ix, iy, iw, ih);
2956 }
2957
setNormalPositionOuter(int x,int y)2958 void YFrameWindow::setNormalPositionOuter(int x, int y) {
2959 XSizeHints *sh = client()->sizeHints();
2960 x += borderXN();
2961 y += borderYN();
2962 int w = sh ? normalW * max(1, sh->width_inc) + sh->base_width : normalW;
2963 int h = sh ? normalH * max(1, sh->height_inc) + sh->base_height : normalH;
2964 setNormalGeometryInner(x, y, w, h);
2965 }
2966
setNormalGeometryInner(int x,int y,int w,int h)2967 void YFrameWindow::setNormalGeometryInner(int x, int y, int w, int h) {
2968 XSizeHints *sh = client()->sizeHints();
2969 normalX = x;
2970 normalY = y;
2971 normalW = sh ? (w - sh->base_width) / max(1, sh->width_inc) : w;
2972 normalH = sh ? (h - sh->base_height) / max(1, sh->height_inc) : h ;
2973
2974 updateDerivedSize(getState() & WinStateMaximizedBoth);
2975 updateLayout();
2976 }
2977
updateDerivedSize(int flagmask)2978 void YFrameWindow::updateDerivedSize(int flagmask) {
2979 XSizeHints *sh = client()->sizeHints();
2980
2981 int nx = normalX;
2982 int ny = normalY;
2983 int nw = sh ? normalW * max(1, sh->width_inc) + sh->base_width : normalW;
2984 int nh = sh ? normalH * max(1, sh->height_inc) + sh->base_height : normalH;
2985
2986 int xiscreen = desktop->getScreenForRect(nx, ny, nw, nh);
2987 int mx, my, Mx, My;
2988 manager->getWorkArea(this, &mx, &my, &Mx, &My, xiscreen);
2989 int Mw = Mx - mx;
2990 int Mh = My - my;
2991
2992 Mh -= titleYN();
2993
2994 if (true) { // aspect of maximization
2995 int aMw, aMh;
2996 aMw = Mw;
2997 aMh = Mh;
2998
2999 client()->constrainSize(aMw, aMh, YFrameClient::csKeepX);
3000 if (aMh < Mh) {
3001 Mh = aMh;
3002 } else {
3003 client()->constrainSize(aMw, aMh, YFrameClient::csKeepY);
3004 if (aMw < Mw) {
3005 Mw = aMw;
3006 }
3007 }
3008 }
3009
3010 bool horiz = false;
3011 bool vert = false;
3012
3013 if (isMaximizedHoriz()) {
3014 nw = Mw;
3015 if (considerHorizBorder) {
3016 nw -= 2 * borderXN();
3017 }
3018 horiz = true;
3019 }
3020
3021 if (isMaximizedVert()) {
3022 nh = Mh;
3023 if (considerVertBorder) {
3024 nh -= 2 * borderYN();
3025 }
3026 vert = true;
3027 }
3028
3029 if (horiz || vert) {
3030 client()->constrainSize(nw, nh, ///getLayer(),
3031 (nw >= Mw) ? YFrameClient::csKeepY
3032 : YFrameClient::csKeepX);
3033 }
3034 nw += 2 * borderXN();
3035 nh += 2 * borderYN();
3036
3037 if (isFullscreen() || (flagmask & WinStateMinimized))
3038 horiz = vert = false;
3039
3040 if (horiz) {
3041 int cx = mx;
3042
3043 if (centerMaximizedWindows && !(sh && (sh->flags & PMaxSize)))
3044 cx = mx + (Mw - nw) / 2;
3045 else if (!considerHorizBorder)
3046 cx -= borderXN();
3047 if (flagmask & WinStateMaximizedHoriz || isMaximizedHoriz())
3048 nx = cx;
3049 else
3050 nx = x();
3051 } else {
3052 nx -= borderXN();
3053 }
3054 if (vert) {
3055 int cy = my;
3056
3057 if (centerMaximizedWindows && !(sh && (sh->flags & PMaxSize)))
3058 cy = my + (Mh - nh) / 2;
3059 else if (!considerVertBorder)
3060 cy -= borderYN();
3061
3062 if (flagmask & WinStateMaximizedVert || isMaximizedVert())
3063 ny = cy;
3064 else
3065 ny = y();
3066 } else {
3067 ny -= borderYN();
3068 }
3069
3070 bool cx = true;
3071 bool cy = true;
3072 bool cw = true;
3073 bool ch = true;
3074
3075 if (isFullscreen()) {
3076 cy = ch = false;
3077 cx = cw = false;
3078 }
3079
3080 if (isMaximizedVert() && !vert)
3081 cy = ch = false;
3082 if (isMaximizedHoriz() && !horiz)
3083 cx = cw = false;
3084
3085 if (cx)
3086 posX = nx;
3087 if (cy)
3088 posY = ny;
3089 if (cw)
3090 posW = nw;
3091 if (ch)
3092 posH = nh + titleYN();
3093 }
3094
updateNormalSize()3095 void YFrameWindow::updateNormalSize() {
3096 MSG(("updateNormalSize: %d %d %d %d", normalX, normalY, normalW, normalH));
3097 XSizeHints *sh = client()->sizeHints();
3098
3099 bool cx = true;
3100 bool cy = true;
3101 bool cw = true;
3102 bool ch = true;
3103
3104 if (isFullscreen())
3105 cy = ch = cx = cw = false;
3106 if (isMaximizedHoriz())
3107 cx = cw = false;
3108 if (isMaximizedVert())
3109 cy = ch = false;
3110 if (isRollup())
3111 ch = false;
3112
3113 if (cx)
3114 normalX = posX + borderXN();
3115 if (cy)
3116 normalY = posY + borderYN();
3117 if (cw) {
3118 normalW = posW - 2 * borderXN();
3119 if (sh) {
3120 normalW = (normalW - sh->base_width) / max(1, sh->width_inc);
3121 }
3122 }
3123 if (ch) {
3124 normalH = posH - (2 * borderYN() + titleYN());
3125 if (sh) {
3126 normalH = (normalH - sh->base_height) / max(1, sh->height_inc);
3127 }
3128 }
3129 MSG(("updateNormalSize> %d %d %d %d", normalX, normalY, normalW, normalH));
3130 }
3131
setCurrentGeometryOuter(YRect newSize)3132 void YFrameWindow::setCurrentGeometryOuter(YRect newSize) {
3133 if (newSize == geometry())
3134 return;
3135
3136 MSG(("setCurrentGeometryOuter: %d %d %d %d",
3137 newSize.x(), newSize.y(), newSize.width(), newSize.height()));
3138 setWindowGeometry(newSize);
3139
3140 if ( ! isFullscreen()) {
3141 posX = x();
3142 posY = y();
3143 posW = width();
3144 }
3145 if ( ! hasState(WinStateFullscreen | WinStateRollup)) {
3146 posH = height();
3147 }
3148
3149 updateNormalSize();
3150 MSG(("setCurrentGeometryOuter> %d %d %d %d",
3151 posX, posY, posW, posH));
3152 }
3153
setCurrentPositionOuter(int px,int py)3154 void YFrameWindow::setCurrentPositionOuter(int px, int py) {
3155 if (px != x() || py != y()) {
3156 YWindow::setPosition(px, py);
3157 if ( ! isFullscreen()) {
3158 posX = px;
3159 posY = py;
3160 if ( !isIconic() && !isMaximizedHoriz())
3161 normalX = posX + borderXN();
3162 if ( !isIconic() && !isMaximizedVert())
3163 normalY = posY + borderYN();
3164 }
3165 sendConfigure();
3166 }
3167 }
3168
updateIconPosition()3169 void YFrameWindow::updateIconPosition() {
3170 if (fMiniIcon) {
3171 if (minimizeToDesktop && isMinimized()) {
3172 fMiniIcon->hide();
3173 fMiniIcon->setPosition(-1, -1);
3174 fMiniIcon->show();
3175 }
3176 else {
3177 delete fMiniIcon;
3178 fMiniIcon = nullptr;
3179 }
3180 }
3181 }
3182
updateLayout()3183 void YFrameWindow::updateLayout() {
3184 if (isIconic()) {
3185 fMiniIcon->show();
3186 }
3187 else if (isRollup()) {
3188 setWindowGeometry(YRect(posX, posY, posW, 2 * borderY() + titleY()));
3189 }
3190 else if (isFullscreen()) {
3191 // for _NET_WM_FULLSCREEN_MONITORS
3192 const int limit = desktop->getScreenCount() - 1;
3193 if (inrange(fFullscreenMonitorsTop, 0, limit) &&
3194 inrange(fFullscreenMonitorsBottom, 0, limit) &&
3195 inrange(fFullscreenMonitorsLeft, 0, limit) &&
3196 inrange(fFullscreenMonitorsRight, 0, limit))
3197 {
3198 YRect t(desktop->getScreenGeometry(fFullscreenMonitorsTop));
3199 YRect b(desktop->getScreenGeometry(fFullscreenMonitorsBottom));
3200 YRect l(desktop->getScreenGeometry(fFullscreenMonitorsLeft));
3201 YRect r(desktop->getScreenGeometry(fFullscreenMonitorsRight));
3202 int x = l.xx;
3203 int y = t.yy;
3204 int w = r.xx + int(r.ww) > x ? r.xx + int(r.ww) - x : int(l.ww);
3205 int h = b.yy + int(b.hh) > y ? b.yy + int(b.hh) - y : int(t.hh);
3206 setWindowGeometry(YRect(x, y, w, h));
3207 }
3208 else if (fullscreenUseAllMonitors) {
3209 YRect geo(desktop->getScreenGeometry(0));
3210 for (int screen = 1; screen <= limit; ++screen) {
3211 geo += desktop->getScreenGeometry(screen);
3212 }
3213 setWindowGeometry(geo);
3214 }
3215 else {
3216 setWindowGeometry(desktop->getScreenGeometry(getScreen()));
3217 }
3218 }
3219 else {
3220 MSG(("updateLayout %d %d %d %d", posX, posY, posW, posH));
3221 setWindowGeometry(YRect(posX, posY, posW, posH));
3222 }
3223 if (affectsWorkArea())
3224 manager->updateWorkArea();
3225 }
3226
setState(int mask,int state)3227 void YFrameWindow::setState(int mask, int state) {
3228 int fOldState = fWinState;
3229 int fNewState = (fWinState & ~mask) | (state & mask);
3230 int deltaState = fOldState ^ fNewState;
3231 fWinState = fNewState;
3232
3233 MSG(("setState: oldState: 0x%X, newState: 0x%X, mask: 0x%X, state: 0x%X",
3234 fOldState, fNewState, mask, state));
3235 //msg("normal1: (%d:%d %dx%d)", normalX, normalY, normalWidth, normalHeight);
3236 if (deltaState & WinStateMinimized) {
3237 MSG(("WinStateMinimized: %d", isMinimized()));
3238 if (fNewState & WinStateMinimized)
3239 minimizeTransients();
3240 else if (owner() && owner()->isMinimized())
3241 owner()->setState(WinStateMinimized, 0);
3242 }
3243 if (deltaState & WinStateHidden) {
3244 MSG(("WinStateHidden: %d", isHidden()));
3245 if (fNewState & WinStateHidden)
3246 hideTransients();
3247 else if (owner() && owner()->isHidden())
3248 owner()->setState(WinStateHidden, 0);
3249 }
3250
3251 manager->lockWorkArea();
3252 updateDerivedSize(deltaState);
3253 updateLayout();
3254 updateState();
3255 updateLayer();
3256 if (hasbit(fOldState | fNewState, WinStateFullscreen) ||
3257 manager->top(WinLayerFullscreen))
3258 {
3259 manager->updateFullscreenLayer();
3260 }
3261 manager->unlockWorkArea();
3262
3263 if (hasbit(deltaState, WinStateRollup | WinStateMinimized)) {
3264 setShape();
3265 }
3266 if (deltaState & fOldState & WinStateMinimized) {
3267 restoreMinimizedTransients();
3268 }
3269 if (deltaState & fOldState & WinStateHidden) {
3270 restoreHiddenTransients();
3271 }
3272 if ((deltaState & WinStateRollup) &&
3273 (clickFocus || !strongPointerFocus) &&
3274 this == manager->getFocus()) {
3275 manager->setFocus(this);
3276 }
3277 if (deltaState & fNewState & WinStateFullscreen) {
3278 if (notbit(deltaState & fNewState, WinStateUnmapped)) {
3279 activate();
3280 }
3281 }
3282 if (deltaState & fNewState & WinStateFocused) {
3283 if (this != manager->getFocus())
3284 manager->setFocus(this);
3285 }
3286
3287 if (deltaState & WinStateUrgent) {
3288 if (notbit(fNewState, WinStateUrgent) && client()->urgencyHint()) {
3289 client()->hints()->flags &= ~XUrgencyHint;
3290 }
3291 updateTaskBar();
3292 }
3293 if (deltaState & WinStateModal) {
3294 if (notbit(fNewState, WinStateModal)) {
3295 for (int i = groupModals.getCount() - 1; 0 <= i; --i) {
3296 if (groupModals[i] == this) {
3297 groupModals.remove(i);
3298 }
3299 }
3300 }
3301 }
3302 if (hasbit(deltaState, WinStateMinimized) && minimizeToDesktop) {
3303 if (isMinimized()) {
3304 if (getMiniIcon()) {
3305 fMiniIcon->show();
3306 }
3307 }
3308 else if (fMiniIcon) {
3309 fMiniIcon->hide();
3310 }
3311 }
3312 if (hasbit(deltaState, WinStateMaximizedBoth) && fTitleBar) {
3313 YFrameButton* maxi = fTitleBar->maximizeButton();
3314 if (maxi) {
3315 maxi->setKind(YFrameTitleBar::Maxi);
3316 maxi->repaint();
3317 }
3318 }
3319 if (hasbit(deltaState, WinStateRollup) && fTitleBar) {
3320 YFrameButton* rollup = fTitleBar->rollupButton();
3321 if (rollup) {
3322 rollup->setKind(YFrameTitleBar::Roll);
3323 rollup->repaint();
3324 }
3325 }
3326 if (hasbit(deltaState,
3327 WinStateMinimized | WinStateHidden | WinStateSkipTaskBar))
3328 {
3329 updateTaskBar();
3330 }
3331 if (hasbit(deltaState, WinStateUnmapped)) {
3332 layoutResizeIndicators();
3333 if (taskBar)
3334 taskBar->workspacesRepaint();
3335 }
3336 }
3337
setAllWorkspaces()3338 void YFrameWindow::setAllWorkspaces() {
3339 if ( ! isAllWorkspaces()) {
3340 setWorkspace(AllWorkspaces);
3341
3342 if (affectsWorkArea())
3343 manager->updateWorkArea();
3344 if (taskBar)
3345 taskBar->relayoutTasks();
3346 if (taskBar)
3347 taskBar->relayoutTray();
3348 }
3349 }
3350
visibleNow() const3351 bool YFrameWindow::visibleNow() const {
3352 return visibleOn(manager->activeWorkspace());
3353 }
3354
3355 #if DO_NOT_COVER_OLD
setDoNotCover(bool doNotCover)3356 void YFrameWindow::setDoNotCover(bool doNotCover) {
3357 fWinOptionMask &= ~foDoNotCover;
3358
3359 if (doNotCover) {
3360 fFrameOptions |= foDoNotCover;
3361 } else {
3362 fFrameOptions &= ~foDoNotCover;
3363 }
3364 manager->updateWorkArea();
3365 }
3366 #endif
3367
updateMwmHints(XSizeHints * sh)3368 void YFrameWindow::updateMwmHints(XSizeHints* sh) {
3369 YDimension old(dimension());
3370 getFrameHints();
3371 int nwidth = sh ? normalW * max(1, sh->width_inc) + sh->base_width
3372 : client()->width();
3373 int height = sh ? normalH * max(1, sh->height_inc) + sh->base_height
3374 : client()->height();
3375 setNormalGeometryInner(normalX, normalY, nwidth, height);
3376 if (old == dimension()) {
3377 performLayout();
3378 }
3379 }
3380
clientIcon() const3381 ref<YIcon> YFrameWindow::clientIcon() const {
3382 for (YFrameWindow const *f(this); f != nullptr; f = f->owner())
3383 if (f->getClientIcon() != null)
3384 return f->getClientIcon();
3385
3386 return wmapp->getDefaultAppIcon();
3387 }
3388
updateProperties()3389 void YFrameWindow::updateProperties() {
3390 client()->setWorkspaceHint(fWinWorkspace);
3391 client()->setLayerHint(fWinActiveLayer);
3392 client()->setStateHint();
3393 }
3394
updateTaskBar()3395 void YFrameWindow::updateTaskBar() {
3396 if (taskBar && fManaged) {
3397 taskBar->updateFrame(this);
3398 }
3399 }
3400
updateAppStatus()3401 void YFrameWindow::updateAppStatus() {
3402 if (taskBar && fManaged) {
3403 bool needTrayApp(false);
3404
3405 if (!isHidden() &&
3406 (notbit(frameOptions(), foIgnoreTaskBar) || isMinimized()) &&
3407 (getTrayOption() != WinTrayIgnore))
3408 if (trayShowAllWindows || visibleNow())
3409 needTrayApp = true;
3410
3411 if (needTrayApp && fTrayApp == nullptr)
3412 fTrayApp = taskBar->addTrayApp(this);
3413
3414 if (fTrayApp) {
3415 fTrayApp->setShown(needTrayApp);
3416 if (fTrayApp->getShown()) ///!!! optimize
3417 fTrayApp->repaint();
3418 }
3419 taskBar->relayoutTray();
3420
3421 bool needTaskBarApp = true;
3422 bool grouping = false;
3423
3424 if (isSkipTaskBar())
3425 needTaskBarApp = false;
3426 if (isHidden())
3427 needTaskBarApp = false;
3428 if (getTrayOption() == WinTrayExclusive)
3429 needTaskBarApp = false;
3430 if (getTrayOption() == WinTrayMinimized && isMinimized())
3431 needTaskBarApp = false;
3432 if (owner() != nullptr && !taskBarShowTransientWindows)
3433 needTaskBarApp = false;
3434 if (!visibleNow() && !taskBarShowAllWindows) {
3435 grouping = bool(taskBarTaskGrouping);
3436 needTaskBarApp = false;
3437 }
3438 if (isUrgent())
3439 needTaskBarApp = true;
3440
3441 if (frameOption(foIgnoreTaskBar))
3442 needTaskBarApp = grouping = false;
3443 if (frameOption(foNoIgnoreTaskBar))
3444 needTaskBarApp = true;
3445
3446 if ((needTaskBarApp || grouping) && fTaskBarApp == nullptr)
3447 fTaskBarApp = taskBar->addTasksApp(this);
3448
3449 if (fTaskBarApp) {
3450 fTaskBarApp->setFlash(isUrgent());
3451 fTaskBarApp->setShown(needTaskBarApp);
3452 if (fTaskBarApp->getShown()) ///!!! optimize
3453 fTaskBarApp->repaint();
3454 }
3455 taskBar->relayoutTasks();
3456 }
3457 }
3458
removeAppStatus()3459 void YFrameWindow::removeAppStatus() {
3460 if (taskBar) {
3461 taskBar->delistFrame(this, fTaskBarApp, fTrayApp);
3462 fTaskBarApp = nullptr;
3463 fTrayApp = nullptr;
3464 }
3465 }
3466
handleMsgBox(YMsgBox * msgbox,int operation)3467 void YFrameWindow::handleMsgBox(YMsgBox *msgbox, int operation) {
3468 //msg("msgbox operation %d", operation);
3469 if (msgbox == fKillMsgBox) {
3470 msgbox->unmanage();
3471 fKillMsgBox = nullptr;
3472 if (operation == YMsgBox::mbOK && !client()->destroyed()) {
3473 if ( !client()->timedOut() || !client()->killPid()) {
3474 wmKill();
3475 }
3476 }
3477 }
3478 }
3479
updateNetWMStrut()3480 void YFrameWindow::updateNetWMStrut() {
3481 int l = fStrutLeft;
3482 int r = fStrutRight;
3483 int t = fStrutTop;
3484 int b = fStrutBottom;
3485 client()->getNetWMStrut(&l, &r, &t, &b);
3486 if (l != fStrutLeft ||
3487 r != fStrutRight ||
3488 t != fStrutTop ||
3489 b != fStrutBottom)
3490 {
3491 fStrutLeft = l;
3492 fStrutRight = r;
3493 fStrutTop = t;
3494 fStrutBottom = b;
3495 fHaveStruts = l | r | t | b;
3496 MSG(("strut: %d %d %d %d", l, r, t, b));
3497 manager->updateWorkArea();
3498 }
3499 }
3500
updateNetWMStrutPartial()3501 void YFrameWindow::updateNetWMStrutPartial() {
3502 int l = fStrutLeft;
3503 int r = fStrutRight;
3504 int t = fStrutTop;
3505 int b = fStrutBottom;
3506 client()->getNetWMStrutPartial(&l, &r, &t, &b);
3507 if (l != fStrutLeft ||
3508 r != fStrutRight ||
3509 t != fStrutTop ||
3510 b != fStrutBottom)
3511 {
3512 fStrutLeft = l;
3513 fStrutRight = r;
3514 fStrutTop = t;
3515 fStrutBottom = b;
3516 fHaveStruts = l | r | t | b;
3517 MSG(("strut: %d %d %d %d", l, r, t, b));
3518 manager->updateWorkArea();
3519 }
3520 }
3521
updateNetStartupId()3522 void YFrameWindow::updateNetStartupId() {
3523 unsigned long time = (unsigned long) -1;
3524 if (client()->getNetStartupId(time)) {
3525 if (fUserTime.update(time))
3526 manager->updateUserTime(fUserTime);
3527 }
3528 }
3529
updateNetWMUserTime()3530 void YFrameWindow::updateNetWMUserTime() {
3531 unsigned long time = (unsigned long) -1;
3532 Window window = fUserTimeWindow ? fUserTimeWindow : client()->handle();
3533 if (client()->getNetWMUserTime(window, time)) {
3534 if (fUserTime.update(time))
3535 manager->updateUserTime(fUserTime);
3536 }
3537 }
3538
updateNetWMUserTimeWindow()3539 void YFrameWindow::updateNetWMUserTimeWindow() {
3540 Window window = fUserTimeWindow;
3541 if (client()->getNetWMUserTimeWindow(window) && window != fUserTimeWindow) {
3542 if (fUserTimeWindow != None) {
3543 windowContext.remove(fUserTimeWindow);
3544 }
3545 fUserTimeWindow = window;
3546 if (window != None) {
3547 windowContext.save(window, client());
3548 XWindowAttributes wa;
3549 if (XGetWindowAttributes(xapp->display(), window, &wa))
3550 XSelectInput(xapp->display(), window,
3551 wa.your_event_mask | PropertyChangeMask);
3552 }
3553 updateNetWMUserTime();
3554 }
3555 }
3556
updateNetWMWindowOpacity()3557 void YFrameWindow::updateNetWMWindowOpacity() {
3558 long data[1] = { 0, };
3559 if (client()->getNetWMWindowOpacity(data[0]))
3560 XChangeProperty(xapp->display(), handle(),
3561 _XA_NET_WM_WINDOW_OPACITY, XA_CARDINAL,
3562 32, PropModeReplace,
3563 (unsigned char *) data, 1);
3564 else
3565 XDeleteProperty(xapp->display(), handle(), _XA_NET_WM_WINDOW_OPACITY);
3566 }
3567
updateNetWMFullscreenMonitors(int t,int b,int l,int r)3568 void YFrameWindow::updateNetWMFullscreenMonitors(int t, int b, int l, int r) {
3569 if (t != fFullscreenMonitorsTop ||
3570 b != fFullscreenMonitorsBottom ||
3571 l != fFullscreenMonitorsLeft ||
3572 r != fFullscreenMonitorsRight)
3573 {
3574 MSG(("fullscreen monitors: %d %d %d %d", t, b, l, r));
3575 fFullscreenMonitorsTop = t;
3576 fFullscreenMonitorsBottom = b;
3577 fFullscreenMonitorsLeft = l;
3578 fFullscreenMonitorsRight = r;
3579 if (isFullscreen())
3580 updateLayout();
3581 }
3582 }
3583
setWmUrgency(bool wmUrgency)3584 void YFrameWindow::setWmUrgency(bool wmUrgency) {
3585 if ( !frameOption(foIgnoreUrgent)) {
3586 if (wmUrgency != hasState(WinStateUrgent)) {
3587 fWinState ^= WinStateUrgent;
3588 client()->setStateHint();
3589 updateTaskBar();
3590 }
3591 }
3592 }
3593
isUrgent() const3594 bool YFrameWindow::isUrgent() const {
3595 return hasState(WinStateUrgent) || client()->urgencyHint();
3596 }
3597
isPassive() const3598 bool YFrameWindow::isPassive() const {
3599 return isMinimized() && startMinimized() && ignoreActivation();
3600 }
3601
getScreen() const3602 int YFrameWindow::getScreen() const {
3603 int nx, ny, nw, nh;
3604 getNormalGeometryInner(&nx, &ny, &nw, &nh);
3605 return desktop->getScreenForRect(nx, ny, nw, nh);
3606 }
3607
wmArrange(int tcb,int lcr)3608 void YFrameWindow::wmArrange(int tcb, int lcr) {
3609 int mx, my, Mx, My, newX = 0, newY = 0;
3610
3611 int xiscreen = desktop->getScreenForRect(x(), y(), width(), height());
3612
3613 manager->getWorkArea(this, &mx, &my, &Mx, &My, xiscreen);
3614
3615 switch (tcb) {
3616 case waTop:
3617 newY = my - (considerVertBorder ? 0 : borderY());
3618 break;
3619 case waCenter:
3620 newY = my + ((My - my) >> 1) - (height() >> 1) - (considerVertBorder ? 0 : borderY());
3621 break;
3622 case waBottom:
3623 newY = My - height() + (considerVertBorder ? 0 : borderY());
3624 break;
3625 }
3626
3627 switch (lcr) {
3628 case waLeft:
3629 newX = mx - (considerHorizBorder ? 0 : borderX());
3630 break;
3631 case waCenter:
3632 newX = mx + ((Mx - mx) >> 1) - ((width()) >> 1) - (considerHorizBorder ? 0 : borderX());
3633 break;
3634 case waRight:
3635 newX = Mx - width() + (considerHorizBorder ? 0 : borderX());
3636 break;
3637 }
3638
3639 MSG(("wmArrange: setPosition(x = %d, y = %d)", newX, newY));
3640
3641 setCurrentPositionOuter(newX, newY);
3642 }
3643
wmSnapMove(int tcb,int lcr)3644 void YFrameWindow::wmSnapMove(int tcb, int lcr) {
3645 int mx, my, Mx, My, newX = 0, newY = 0;
3646
3647 int xiscreen = desktop->getScreenForRect(x(), y(), width(), height());
3648
3649 YArrange arrange = manager->getWindowsToArrange();
3650 YFrameWindow** w = arrange.begin();
3651 int count = arrange.size();
3652
3653 manager->getWorkArea(this, &mx, &my, &Mx, &My, xiscreen);
3654
3655 MSG(("WorkArea: mx = %d, my = %d, Mx = %d, My = %d", mx, my, Mx, My));
3656 MSG(("thisFrame: x = %d, y = %d, w = %d, h = %d, bx = %d, by = %d, ty = %d",
3657 x(), y(), width(), height(), borderX(), borderY(), titleY()));
3658 MSG(("thisClient: w = %d, h = %d", client()->width(), client()->height()));
3659
3660 switch (tcb) {
3661 case waTop:
3662 newY = getTopCoord(my, w, count);
3663 if (!considerVertBorder && newY == my)
3664 newY -= borderY();
3665 break;
3666 case waCenter:
3667 newY = y();
3668 break;
3669 case waBottom:
3670 newY = getBottomCoord(My, w, count) - height();
3671 if (!considerVertBorder && (newY + (int) height()) == My)
3672 newY += borderY();
3673 break;
3674 }
3675
3676 switch (lcr) {
3677 case waLeft:
3678 newX = getLeftCoord(mx, w, count);
3679 if (!considerHorizBorder && newX == mx)
3680 newX -= borderX();
3681 break;
3682 case waCenter:
3683 newX = x();
3684 break;
3685 case waRight:
3686 newX = getRightCoord(Mx, w, count) - width();
3687 if (!considerHorizBorder && (newX + (int) width()) == Mx)
3688 newX += borderX();
3689 break;
3690 }
3691
3692 MSG(("NewPosition: x = %d, y = %d", newX, newY));
3693
3694 setCurrentPositionOuter(newX, newY);
3695
3696 arrange.discard();
3697 }
3698
getTopCoord(int my,YFrameWindow ** w,int count)3699 int YFrameWindow::getTopCoord(int my, YFrameWindow **w, int count)
3700 {
3701 int i, n;
3702
3703 if (y() < my)
3704 return y();
3705
3706 for (i = y() - 2; i > my; i--) {
3707 for (n = 0; n < count; n++) {
3708 if ( (this != w[n])
3709 && (i == (w[n]->y() + (int) w[n]->height()))
3710 && ( x() < (w[n]->x() + (int) w[n]->width()))
3711 && ((x() + (int) width()) > (w[n]->x())) ) {
3712 return i;
3713 }
3714 }
3715 }
3716
3717 return my;
3718 }
3719
getBottomCoord(int My,YFrameWindow ** w,int count)3720 int YFrameWindow::getBottomCoord(int My, YFrameWindow **w, int count)
3721 {
3722 int i, n;
3723
3724 if ((y() + (int) height()) > My)
3725 return y() + height();
3726
3727 for (i = y() + height() + 2; i < My; i++) {
3728 for (n = 0; n < count; n++) {
3729 if ( (this != w[n])
3730 && (i == w[n]->y())
3731 && ( x() < (w[n]->x() + (int) w[n]->width()))
3732 && ((x() + (int) width()) > (w[n]->x())) ) {
3733 return i;
3734 }
3735 }
3736 }
3737
3738 return My;
3739 }
3740
getLeftCoord(int mx,YFrameWindow ** w,int count)3741 int YFrameWindow::getLeftCoord(int mx, YFrameWindow **w, int count)
3742 {
3743 int i, n;
3744
3745 if (x() < mx)
3746 return x();
3747
3748 for (i = x() - 2; i > mx; i--) {
3749 for (n = 0; n < count; n++) {
3750 if ( (this != w[n])
3751 && (i == (w[n]->x() + (int) w[n]->width()))
3752 && ( y() < (w[n]->y() + (int) w[n]->height()))
3753 && ((y() + (int) height()) > (w[n]->y())) ) {
3754 return i;
3755 }
3756 }
3757 }
3758
3759 return mx;
3760 }
3761
getRightCoord(int Mx,YFrameWindow ** w,int count)3762 int YFrameWindow::getRightCoord(int Mx, YFrameWindow **w, int count)
3763 {
3764 int i, n;
3765
3766 if ((x() + (int) width()) > Mx)
3767 return x() + width();
3768
3769 for (i = x() + width() + 2; i < Mx; i++) {
3770 for (n = 0; n < count; n++) {
3771 if ( (this != w[n])
3772 && (i == w[n]->x())
3773 && ( y() < (w[n]->y() + (int) w[n]->height()))
3774 && ((y() + (int) height()) > (w[n]->y())) ) {
3775 return i;
3776 }
3777 }
3778 }
3779
3780 return Mx;
3781 }
3782
3783 // vim: set sw=4 ts=4 et:
3784