From 095ed342bd5c0c2b25858e50e8786e4a212e59b0 Mon Sep 17 00:00:00 2001 From: fluxgen Date: Wed, 29 May 2002 06:21:59 +0000 Subject: slit order --- src/Slit.cc | 210 ++++++++++++++++++++++++++++++++++++++++++++++++++++++------ src/Slit.hh | 19 +++++- 2 files changed, 207 insertions(+), 22 deletions(-) diff --git a/src/Slit.cc b/src/Slit.cc index 48345c9..79e3d31 100644 --- a/src/Slit.cc +++ b/src/Slit.cc @@ -19,7 +19,7 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -// $Id: Slit.cc,v 1.13 2002/05/08 14:12:28 fluxgen Exp $ +// $Id: Slit.cc,v 1.14 2002/05/29 06:21:59 fluxgen Exp $ //use GNU extensions #ifndef _GNU_SOURCE @@ -42,9 +42,60 @@ #include "Toolbar.hh" #include +#include +#include +#ifdef HAVE_SYS_STAT_H +# include +# include +#endif // HAVE_SYS_STAT_H + + +// Utility method for extracting name from window +namespace { + void getWMName(BScreen *screen, Window window, std::string& name) { + assert(screen); + name = ""; + + if (screen != 0 && window != None) { + Display *display = screen->getBaseDisplay()->getXDisplay(); + + XTextProperty text_prop; + char **list; + int num; + I18n *i18n = I18n::instance(); + + if (XGetWMName(display, window, &text_prop)) { + if (text_prop.value && text_prop.nitems > 0) { + if (text_prop.encoding != XA_STRING) { + + text_prop.nitems = strlen((char *) text_prop.value); + + if ((XmbTextPropertyToTextList(display, &text_prop, + &list, &num) == Success) && + (num > 0) && *list) { + name = static_cast(*list); + XFreeStringList(list); + } else + name = (char *)text_prop.value; + + } else + name = (char *)text_prop.value; + } else + name = i18n->getMessage( + FBNLS::WindowSet, FBNLS::WindowUnnamed, + "Unnamed"); + } else { + name = i18n->getMessage( + FBNLS::WindowSet, FBNLS::WindowUnnamed, + "Unnamed"); + } + } + } +}; // End anonymous namespace Slit::Slit(BScreen *scr):screen(scr), timer(this), slitmenu(*this) { + assert(scr); fluxbox = Fluxbox::instance(); on_top = screen->isSlitOnTop(); @@ -66,7 +117,7 @@ Slit::Slit(BScreen *scr):screen(scr), timer(this), slitmenu(*this) { attrib.colormap = screen->getColormap(); attrib.override_redirect = True; attrib.event_mask = SubstructureRedirectMask | ButtonPressMask | - EnterWindowMask | LeaveWindowMask; + EnterWindowMask | LeaveWindowMask; frame.x = frame.y = 0; frame.width = frame.height = 1; @@ -78,6 +129,9 @@ Slit::Slit(BScreen *scr):screen(scr), timer(this), slitmenu(*this) { create_mask, &attrib); fluxbox->saveSlitSearch(frame.window, this); + // Get client list for sorting purposes + loadClientList(); + reconfigure(); } @@ -102,8 +156,37 @@ void Slit::addClient(Window w) { fluxbox->grab(); if (fluxbox->validateWindow(w)) { - SlitClient *client = new SlitClient; - client->client_window = w; + // Look for slot in client list by name + SlitClient *client = 0; + std::string match_name; + ::getWMName(screen, w, match_name); + SlitClients::iterator it = clientList.begin(); + SlitClients::iterator it_end = clientList.end(); + bool found_match = false; + for (; it != it_end; ++it) { + // If the name matches... + if ((*it)->match_name == match_name) { + // Use the slot if no window is assigned + if ((*it)->window == None) { + client = (*it); + client->initialize(screen, w); + break; + } + // Otherwise keep looking for an unused match or a non-match + found_match = true; // Possibly redundant + + } else if (found_match) { + // Insert before first non-match after a previously found match? + client = new SlitClient(screen, w); + clientList.insert(it, client); + break; + } + } + // Append to client list? + if (client == 0) { + client = new SlitClient(screen, w); + clientList.push_back(client); + } XWMHints *wmhints = XGetWMHints(display, w); @@ -184,22 +267,26 @@ void Slit::addClient(Window w) { SubstructureNotifyMask | EnterWindowMask); XFlush(display); - clientList.push_back(client); - fluxbox->saveSlitSearch(client->client_window, this); fluxbox->saveSlitSearch(client->icon_window, this); reconfigure(); + + saveClientList(); } fluxbox->ungrab(); } -void Slit::removeClient(SlitClient *client, bool remap) { +void Slit::removeClient(SlitClient *client, bool remap, bool destroy) { fluxbox->removeSlitSearch(client->client_window); fluxbox->removeSlitSearch(client->icon_window); - clientList.remove(client); + // Destructive removal? + if (destroy) + clientList.remove(client); + else // Clear the window info, but keep around to help future sorting? + client->initialize(); screen->removeNetizen(client->window); @@ -214,7 +301,9 @@ void Slit::removeClient(SlitClient *client, bool remap) { XFlush(display); } - delete client; + // Destructive removal? + if (destroy) + delete client; } @@ -227,7 +316,7 @@ void Slit::removeClient(Window w, bool remap) { SlitClients::iterator it_end = clientList.end(); for (; it != it_end; ++it) { if ((*it)->window == w) { - removeClient((*it), remap); + removeClient((*it), remap, false); reconf = true; break; @@ -243,16 +332,25 @@ void Slit::reconfigure(void) { frame.width = 0; frame.height = 0; + // Need to count windows because not all client list entries + // actually correspond to mapped windows. + int num_windows = 0; + switch (screen->getSlitDirection()) { case VERTICAL: { SlitClients::iterator it = clientList.begin(); SlitClients::iterator it_end = clientList.end(); for (; it != it_end; ++it) { - frame.height += (*it)->height + screen->getBevelWidth(); - - if (frame.width < (*it)->width) - frame.width = (*it)->width; + //client created window? + if ((*it)->window != None) { + num_windows++; + frame.height += (*it)->height + screen->getBevelWidth(); + + //frame width < client window? + if (frame.width < (*it)->width) + frame.width = (*it)->width; + } } } @@ -273,10 +371,14 @@ void Slit::reconfigure(void) { SlitClients::iterator it = clientList.begin(); SlitClients::iterator it_end = clientList.end(); for (; it != it_end; ++it) { - frame.width += (*it)->width + screen->getBevelWidth(); - - if (frame.height < (*it)->height) - frame.height = (*it)->height; + //client created window? + if ((*it)->window != None) { + num_windows++; + frame.width += (*it)->width + screen->getBevelWidth(); + //frame height < client height? + if (frame.height < (*it)->height) + frame.height = (*it)->height; + } } } @@ -299,7 +401,8 @@ void Slit::reconfigure(void) { XSetWindowBorder(display, frame.window, screen->getBorderColor()->getPixel()); - if (clientList.size()==0) + //did we actually use slit slots + if (num_windows == 0) XUnmapWindow(display, frame.window); else XMapWindow(display, frame.window); @@ -316,7 +419,9 @@ void Slit::reconfigure(void) { texture); XSetWindowBackgroundPixmap(display, frame.window, frame.pixmap); } - if (tmp) image_ctrl->removeImage(tmp); + + if (tmp) + image_ctrl->removeImage(tmp); XClearWindow(display, frame.window); int x, y; @@ -330,6 +435,10 @@ void Slit::reconfigure(void) { SlitClients::iterator it = clientList.begin(); SlitClients::iterator it_end = clientList.end(); for (; it != it_end; ++it) { + //client created window? + if ((*it)->window == None) + continue; + x = (frame.width - (*it)->width) / 2; XMoveResizeWindow(display, (*it)->window, x, y, @@ -371,6 +480,10 @@ void Slit::reconfigure(void) { SlitClients::iterator it = clientList.begin(); SlitClients::iterator it_end = clientList.end(); for (; it != it_end; ++it) { + //client created window? + if ((*it)->window == None) + continue; + y = (frame.height - (*it)->height) / 2; XMoveResizeWindow(display, (*it)->window, x, y, @@ -556,8 +669,9 @@ void Slit::reposition(void) { void Slit::shutdown(void) { + saveClientList(); while (clientList.size() != 0) - removeClient(clientList.front()); + removeClient(clientList.front(), true, true); } @@ -663,6 +777,39 @@ void Slit::timeout(void) { XMoveWindow(display, frame.window, frame.x, frame.y); } +void Slit::loadClientList(void) { + const std::string &filename = fluxbox->getSlitlistFilename(); + struct stat buf; + if (!stat(filename.c_str(), &buf)) + { + std::ifstream file(fluxbox->getSlitlistFilename().c_str()); + std::string name; + while (! file.eof()) { + name = ""; + file >> name; + if (name.size() > 0) { + SlitClient *client = new SlitClient(name.c_str()); + clientList.push_back(client); + } + } + } +} + +void Slit::saveClientList(void) { + const std::string &filename = fluxbox->getSlitlistFilename(); + std::ofstream file(filename.c_str()); + SlitClients::iterator it = clientList.begin(); + SlitClients::iterator it_end = clientList.end(); + std::string prevName; + std::string name; + for (; it != it_end; ++it) { + name = (*it)->match_name; + if (name != prevName) + file << name.c_str() << std::endl; + prevName = name; + } +} + Slitmenu::Slitmenu(Slit &sl) : Basemenu(sl.screen), slit(sl) { @@ -929,4 +1076,25 @@ void Slitmenu::Headmenu::itemSelected(int button, unsigned int index) { #endif // XINERAMA +Slit::SlitClient::SlitClient(const char *name) +{ + initialize(); + match_name = name; +} + +Slit::SlitClient::SlitClient(BScreen *screen, Window w) +{ + initialize(screen, w); +} + +void Slit::SlitClient::initialize(BScreen *screen, Window w) { + assert(screen); + client_window = w; + window = icon_window = None; + x = y = 0; + width = height = 0; + if (match_name.size() == 0) + getWMName(screen, client_window, match_name); +} + #endif // SLIT diff --git a/src/Slit.hh b/src/Slit.hh index 75111d0..61a7d33 100644 --- a/src/Slit.hh +++ b/src/Slit.hh @@ -35,6 +35,7 @@ class Slitmenu; #include "Basemenu.hh" #include +#include class Slitmenu : public Basemenu { public: @@ -130,6 +131,7 @@ public: void reconfigure(void); void reposition(void); void shutdown(void); + void saveClientList(void); void buttonPressEvent(XButtonEvent *); void enterNotifyEvent(XCrossingEvent *); @@ -145,13 +147,27 @@ public: private: class SlitClient { public: + SlitClient(BScreen *, Window); // For adding an actual window + SlitClient(const char *); // For adding a placeholder + + // Now we pre-initialize a list of slit clients with names for + // comparison with incoming client windows. This allows the slit + // to maintain a sorted order based on a saved window name list. + // Incoming windows not found in the list are appended. Matching + // duplicates are inserted after the last found instance of the + // matching name. + std::string match_name; + Window window, client_window, icon_window; int x, y; unsigned int width, height; + + void initialize(BScreen * = NULL, Window = None); }; - void removeClient(SlitClient *, bool = true); + void removeClient(SlitClient *, bool, bool); + void loadClientList(void); Bool on_top, hidden, do_auto_hide; Display *display; @@ -164,6 +180,7 @@ private: SlitClients clientList; Slitmenu slitmenu; + std::string clientListPath; struct frame { Pixmap pixmap; -- cgit v0.11.2