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 *) &notify);
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