From 7c5ff316594f52faf9774f4238c53aff2e41a807 Mon Sep 17 00:00:00 2001 From: Bert Gijsbers Date: Fri, 28 Jun 2024 18:08:03 +0200 Subject: [PATCH] Add -Await option to icesh to wait for and select new client windows. --- man/icesh.pod | 5 ++++ src/icesh.cc | 74 +++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 71 insertions(+), 8 deletions(-) diff --git a/man/icesh.pod b/man/icesh.pod index 31eeee6b3..44c9568fc 100644 --- a/man/icesh.pod +++ b/man/icesh.pod @@ -147,6 +147,11 @@ the same process identifier as one of the selected windows. Selects the IceWM taskbar. +=item B<-A>, B<-Await> + +Wait for one or more new client windows to appear and make that the new +selection. + =back =head2 FILTER OPTIONS diff --git a/src/icesh.cc b/src/icesh.cc index e46871fcb..8571eedf3 100644 --- a/src/icesh.cc +++ b/src/icesh.cc @@ -478,6 +478,7 @@ class YProperty { if (type) fType = type; if (leng) fLength = leng; if (fWindow && fProp && fLength) { + fRequest = fProp; fStatus = XGetWindowProperty(display, fWindow, fProp, 0L, fLength, False, fType, &type, &fFormat, &fCount, &fAfter, &fData); @@ -559,7 +560,11 @@ class YProperty { int fFormat, fStatus; YProperty& operator=(const YProperty& copy); + +public: + static Atom fRequest; }; +Atom YProperty::fRequest; class YCardinal : public YProperty { public: @@ -999,8 +1004,11 @@ class YWindowTree { } } + static YWindowTree lastClientList; + void getClientList() { getWindowList(ATOM_NET_CLIENT_LIST); + lastClientList = *this; } void getSystrayList() { @@ -1357,6 +1365,7 @@ class YWindowTree { vector fChildren; YTreeLeaf fLeaf; }; +YWindowTree YWindowTree::lastClientList; YTreeIter::operator Window() const { return fTree[fIndex]; } YTreeLeaf* YTreeIter::operator->() { return fTree.leaf(fIndex); } @@ -1470,6 +1479,7 @@ class IceSh { bool desktop(); bool wmcheck(); bool change(); + void await(); bool loop(); bool pick(); bool sync(); @@ -2861,6 +2871,46 @@ bool IceSh::guiEvents() return true; } +void IceSh::await() +{ + windowList.release(); + YWindowTree old = YWindowTree::lastClientList; + if (old == false) + old.getClientList(); + + running = true; + sighandler_t previous = signal(SIGINT, catcher); + XSelectInput(display, root, PropertyChangeMask); + while (running) { + if (XPending(display)) { + XEvent xev = { 0 }; + XNextEvent(display, &xev); + if (xev.type == PropertyNotify && + xev.xproperty.atom == ATOM_NET_CLIENT_LIST && + xev.xproperty.state == PropertyNewValue) + { + YWindowTree now; + now.getClientList(); + for (YTreeIter window(now); window; ++window) { + if (old.have(window) == false) + windowList.append(window); + } + if (windowList) + break; + old = now; + } + } + else { + int fd = ConnectionNumber(display); + fd_set rfds; + FD_ZERO(&rfds); + FD_SET(fd, &rfds); + select(fd + 1, SELECT_TYPE_ARG234 &rfds, nullptr, nullptr, nullptr); + } + } + signal(SIGINT, previous); +} + bool IceSh::icewmAction() { static const Symbol sa[] = { @@ -4361,6 +4411,11 @@ void IceSh::flag(char* arg) selecting = true; return; } + if (isOptArg(arg, "-Await", "")) { + await(); + selecting = true; + return; + } if (isOptArg(arg, "+group", "")) { extendGroup(); return; @@ -4900,19 +4955,22 @@ int IceSh::xerrors(Display* dpy, XErrorEvent* evt) { } void IceSh::xerror(XErrorEvent* evt) { - char message[80], req[80], number[80]; + const int size = 80; + char message[size], req[size], number[size]; if (evt->request_code == X_GetWindowAttributes) return; - - snprintf(number, 80, "%d", evt->request_code); - XGetErrorDatabaseText(display, "XRequest", - number, "", - req, sizeof(req)); + if (evt->request_code == X_GetProperty) + snprintf(req, size, "X_GetProperty(%s)", atomName(YProperty::fRequest)); + else { + snprintf(number, size, "%d", evt->request_code); + XGetErrorDatabaseText(display, "XRequest", number, + "", req, sizeof(req)); + } if (req[0] == 0) - snprintf(req, 80, "[request_code=%d]", evt->request_code); + snprintf(req, size, "[request_code=%d]", evt->request_code); - if (XGetErrorText(display, evt->error_code, message, 80) != Success) + if (XGetErrorText(display, evt->error_code, message, size) != Success) *message = '\0'; tlog("%s(0x%lx): %s", req, evt->resourceid, message);