Index: src/Window.cc =================================================================== RCS file: /cvsroot/fluxbox/fluxbox/src/Window.cc,v retrieving revision 1.292 diff -a -b -B -p -u -r1.292 Window.cc --- src/Window.cc 29 Jun 2004 12:41:23 -0000 1.292 +++ src/Window.cc 1 Jul 2004 11:25:40 -0000 @@ -67,6 +67,7 @@ #include #include #include +#include using namespace std; @@ -245,6 +246,361 @@ private: WinClient &m_client; }; + + + + +class SkipWindowFunctor { + public: + virtual bool operator()(const FluxboxWindow* win) const = 0; +}; + +struct Rect { + int x; + int y; + unsigned int width; + unsigned int height; + bool free; + + Rect(int _x = 0, int _y = 0, + unsigned int _w = 0, unsigned int _h = 0, + bool _free = true) : + x(_x), y(_y), width(_w), height(_h), free(_free) { }; + + bool overlap(const Rect& rect) const { + return (!(x >= rect.x + rect.width || + x + width <= rect.x || + y >= rect.y + rect.height || + y + height <= rect.y)); + } + + const float area() const { return width * height; } + const float aspect() const { return static_cast(width) / static_cast(height); } +}; + +class SpaceSelect { + public: + SpaceSelect() : m_window(0, 0, 0, 0) { }; + Rect result() const { return m_window; } + + virtual void operator()(const Rect& win) { }; + protected: + Rect m_window; +}; + +class SpaceSelectCarrier { + public: + SpaceSelectCarrier(SpaceSelect& spaceselect) : m_spaceselect(spaceselect) { } + void operator()(const Rect& win) { + m_spaceselect(win); + } + private: + SpaceSelect& m_spaceselect; +}; + +class SpaceGrid { + public: + typedef std::vector > Cells; + typedef Cells::iterator CellsIt; + + typedef std::vector FreeCells; + typedef FreeCells::iterator FreeCellsIt; + typedef FreeCells::const_iterator ConstFreeCellsIt; + + SpaceGrid() { }; + + void draw(const BScreen& screen); + void update(const BScreen& screen, + const Workspace::Windows& wins, + const SkipWindowFunctor& skip); + + + const Cells& cells() const { return m_cells; } + const FreeCells& freecells() const { return m_freecells; } + + Rect query(SpaceSelect& spaceselect) const { + std::for_each(m_freecells.begin(), + m_freecells.end(), + SpaceSelectCarrier(spaceselect)); + + return spaceselect.result(); + }; + + private: + Cells m_cells; + FreeCells m_freecells; +}; + +void SpaceGrid::update(const BScreen& screen, + const Workspace::Windows& wins, const SkipWindowFunctor& skip ) { + + std::set horizontal; + std::set vertical; + + const int head = screen.getCurrHead(); + + vertical.insert(static_cast(screen.getHeadX(head))); + vertical.insert(static_cast(screen.getHeadWidth(head))); + horizontal.insert(static_cast(screen.getHeadY(head))); + horizontal.insert(static_cast(screen.getHeadHeight(head))); + + Workspace::Windows::const_iterator it; + for(it= wins.begin(); it != wins.end(); it++) { + if (!skip(*it) ) { + vertical.insert(static_cast((*it)->x())); + vertical.insert(static_cast((*it)->x() + (*it)->width())); + horizontal.insert(static_cast((*it)->y())); + horizontal.insert(static_cast((*it)->y() + (*it)->height())); + } + } + + m_cells.resize(vertical.size() - 1); + std::for_each(m_cells.begin(), + m_cells.end(), + std::bind2nd(std::mem_fun_ref(&std::vector::resize), + horizontal.size() - 1)); + +/* + { // draw grid, just for debugging + int x = screen.getHeadX(head); + int y = screen.getHeadY(head); + int w = screen.getHeadWidth(head); + int h = screen.getHeadHeight(head); + + GC gc = XCreateGC(Fluxbox::instance()->display(), + screen.rootWindow().window(), + 0, 0); + + XSetForeground(Fluxbox::instance()->display(), + gc, + FbTk::Color("red", screen.screenNumber()).pixel()); + + std::set::iterator i; + for ( i = horizontal.begin(); + i != horizontal.end(); i++ ) { + XDrawLine(Fluxbox::instance()->display(), + screen.rootWindow().window(), + gc, + x, (*i), x + w, (*i)); + } + for ( i = vertical.begin(); + i != vertical.end(); i++ ) { + XDrawLine(Fluxbox::instance()->display(), + screen.rootWindow().window(), + gc, + (*i), y, (*i), y + w); + } + + XFreeGC(Fluxbox::instance()->display(), gc); + } +*/ + + { // create the grid + int y = *horizontal.begin(); + std::set::iterator next_y = horizontal.begin(); + unsigned int j = 0; + for(next_y++; next_y != horizontal.end(); y = *next_y, next_y++) { + + int x = *vertical.begin(); + std::set::iterator next_x = vertical.begin(); + unsigned int i = 0; + for(next_x++; next_x != vertical.end(); x = *next_x, next_x++) { + Rect& rect = m_cells[i][j]; + rect.free = true; + rect.x = x; + rect.y = y; + rect.width = *next_x - x; + rect.height= *next_y - y; + + for(it= wins.begin(); it != wins.end(); it++) { + if (!skip(*it)) { + + Rect tmprect((*it)->x(), (*it)->y(), + (*it)->width(), (*it)->height()); + if(rect.overlap(tmprect)) { + rect.free = false; + break; + } + } + } + i++; + } + j++; + } + } + + + { // store all possible "free" cells + unsigned int w= m_cells.size(); + unsigned int h= m_cells[0].size(); + unsigned int x; + unsigned int y; + unsigned int s; + unsigned int t; + + unsigned int counter= 0; + bool invalid= false; + Rect current(0, 0, 0, 0); + + m_freecells.clear(); + + for(y= 0; y < h; y++) { + for(x= 0; x < w; x++) { + + if (!m_cells[x][y].free) + continue; + + for(t= y; t < h; t++) { + for(s= x; s < w; s++) { + + counter++; + invalid= false; + + current.x= m_cells[x][y].x; + current.y= m_cells[x][y].y; + current.width= m_cells[s][t].x + m_cells[s][t].width - current.x; + current.height= m_cells[s][t].y + m_cells[s][t].height - current.y; + + for(Workspace::Windows::const_iterator it = wins.begin(); + !invalid && it != wins.end(); + it++) { + if(!skip(*it)) { + Rect tmprect((*it)->x(), (*it)->y(), + (*it)->width(), (*it)->height()); + invalid|= current.overlap(tmprect); + } + } + + if(!invalid) + m_freecells.push_back(current); + } + } + } + } + } +} + +void SpaceGrid::draw(const BScreen& screen) { + + int head = screen.getCurrHead(); + + int x = screen.getHeadX(head); + int y = screen.getHeadY(head); + int w = screen.getHeadWidth(head); + int h = screen.getHeadHeight(head); + + FbTk::Color red("red", screen.screenNumber()); + FbTk::Color green("green", screen.screenNumber()); + FbTk::Color white("white", screen.screenNumber()); + FbTk::GContext gc(screen.rootWindow()); + gc.setFunction(GXxor); + gc.setSubwindowMode(IncludeInferiors); + gc.setLineAttributes(10); + gc.setForeground(white); + + /* + std::vector::iterator i; + for ( i = m_freecells.begin(); + i != m_freecells.end(); i++ ) { + if ( (*i).free ) + XSetForeground(Fluxbox::instance()->display(), + gc, green); + else + XSetForeground(Fluxbox::instance()->display(), + gc, red); + + XDrawRectangle(Fluxbox::instance()->display(), + screen.rootWindow().window(), + gc, + (*i).x, + (*i).y, + (*i).x + (*i).width, + (*i).y + (*i).height); + } + */ + + unsigned int i; + unsigned int j; + + for ( j = 0; j < m_cells.size(); j++ ) { + for ( i = 0; i < m_cells[0].size(); i++ ) { + Rect& rect = m_cells[i][j]; + + if ( ! rect.free ) + gc.setLineAttributes(10, FbTk::GContext::LINESOLID); + else + gc.setLineAttributes(10, FbTk::GContext::LINEDOUBLEDASH); + + screen.rootWindow().drawLine(gc.gc(), + rect.x, + rect.y, + rect.x + rect.width, + rect.y + rect.height); + + screen.rootWindow().drawLine(gc.gc(), + rect.x, + rect.y + rect.height, + rect.x + rect.width, + rect.y); + } + } +} + + +SpaceGrid spacegrid; + +class MaxSpace : public SpaceSelect { + public: + MaxSpace() : m_area(0) { }; + virtual void operator()(const Rect& win) { + if (win.area() > m_window.area()) { + m_window= win; + } + } + + float m_area; +}; + +class MaxHorizontalSpace : public MaxSpace{ + public: + MaxHorizontalSpace() { }; + void operator()(const Rect& win) { + if(win.aspect() >= 1.0f) + MaxSpace::operator()(win); + } +}; + +class MaxVerticalSpace : public MaxSpace { + public: + MaxVerticalSpace() { }; + virtual void operator()(const Rect& win) { + if(win.aspect() <= 1.0f) + MaxSpace::operator()(win); + } +}; + +class MaxVerticalLimitSpace : public MaxVerticalSpace { + public: + MaxVerticalLimitSpace(Rect& rect) : m_rect(rect) { }; + void operator()(const Rect& win) { + if(win.x == m_rect.x && win.width == m_rect.width) + MaxSpace::operator()(win); + } + private: + Rect& m_rect; +}; + +class MaxHorizontalLimitSpace : public MaxHorizontalSpace { + public: + MaxHorizontalLimitSpace(Rect& rect) : m_rect(rect) { }; + void operator()(const Rect& win) { + if(win.y == m_rect.y && win.height == m_rect.height) + MaxSpace::operator()(win); + } + private: + Rect& m_rect; +}; + }; @@ -1479,6 +1835,95 @@ void FluxboxWindow::maximizeFull() { } +void FluxboxWindow::place(FluxboxWindow::PlaceMethod method, + bool allow_smaller) { + + class MaxspaceSkipper : public SkipWindowFunctor { + public: + MaxspaceSkipper(const FluxboxWindow* win) : + m_win(win) { }; + + bool operator() (const FluxboxWindow* win) const { + + return !win + || win == m_win + /* || win->layerNum() != m_win->layerNum() */ + || win->isIconic(); + } + private: + const FluxboxWindow* m_win; + }; + + MaxspaceSkipper skipper(this); + + spacegrid.update(screen(), + screen().currentWorkspace()->windowList(), + skipper); + + /*spacegrid.draw(screen());*/ + + + Rect current(x(), y(), width(), height()); + Rect result; + + switch (method) { + case DRAW_GRID: + spacegrid.draw(screen()); + return; + break; + case MAX_SPACE: { + MaxSpace sel; + result = spacegrid.query(sel); + } + break; + case MAX_HORIZONTAL_SPACE: { + MaxHorizontalSpace sel; + result = spacegrid.query(sel); + } + break; + case MAX_VERTICAL_SPACE: { + MaxVerticalSpace sel; + result = spacegrid.query(sel); + } + break; + case EXPAND_HORIZONTAL_SPACE: { + MaxHorizontalLimitSpace sel(current); + result = spacegrid.query(sel); + } + break; + case EXPAND_VERTICAL_SPACE: { + MaxVerticalLimitSpace sel(current); + result = spacegrid.query(sel); + } + break; + default: + return; + break; + } + + if ( result.x <= 0 || result.y <= 0 || result.width <= 0 || result.height <= 0 ) { + std::cerr << "hu, this shouldnt happen .. but hey, its alpha alpha.\n"; + return; + } + + std::cerr << result.area() << " " << allow_smaller << "\n"; + + + if ( ( allow_smaller && result.area() > 0 ) || result.area() > current.area() ) { + std::cerr << "new size: " + << result.x << " " << result.y << " " + << result.width << " " << result.height + << "\n"; + + moveResize(result.x, result.y, result.width, result.height); + } + + return; +} + + + + void FluxboxWindow::setWorkspace(int n) { unsigned int old_wkspc = m_workspace_number; Index: src/Window.hh =================================================================== RCS file: /cvsroot/fluxbox/fluxbox/src/Window.hh,v retrieving revision 1.116 diff -a -b -B -p -u -r1.116 Window.hh --- src/Window.hh 20 Jun 2004 04:49:33 -0000 1.116 +++ src/Window.hh 1 Jul 2004 11:25:40 -0000 @@ -200,6 +200,19 @@ public: void maximizeVertical(); /// maximizes the window fully void maximizeFull(); + + /// different placement methods + typedef enum { + DRAW_GRID, // for debugging, draws the grid + MAX_SPACE, + MAX_HORIZONTAL_SPACE, + MAX_VERTICAL_SPACE, + EXPAND_HORIZONTAL_SPACE, // keeps the height constant + EXPAND_VERTICAL_SPACE // keeps width constant + } PlaceMethod; + /// tries to place a window in a nice way + void place(PlaceMethod pmetho = MAX_SPACE, bool allow_smaller = false); + /// toggles shade void shade(); /// toggles sticky Index: src/FbCommandFactory.cc =================================================================== RCS file: /cvsroot/fluxbox/fluxbox/src/FbCommandFactory.cc,v retrieving revision 1.32 diff -a -b -B -p -u -r1.32 FbCommandFactory.cc --- src/FbCommandFactory.cc 7 Jun 2004 11:46:04 -0000 1.32 +++ src/FbCommandFactory.cc 1 Jul 2004 11:25:41 -0000 @@ -97,6 +97,7 @@ FbCommandFactory::FbCommandFactory() { "nexttab", "nextwindow", "nextworkspace", + "place", "prevgroup", "prevtab", "prevwindow", @@ -194,6 +195,8 @@ FbTk::Command *FbCommandFactory::stringT return new CurrentWindowCmd(&FluxboxWindow::maximizeVertical); else if (command == "maximizehorizontal") return new CurrentWindowCmd(&FluxboxWindow::maximizeHorizontal); + else if (command == "place") + return new PlaceCmd(FbTk::StringUtil::toLower(arguments.c_str()).c_str()); else if (command == "resize") { FB_istringstream is(arguments.c_str()); int dx = 0, dy = 0; Index: src/CurrentWindowCmd.cc =================================================================== RCS file: /cvsroot/fluxbox/fluxbox/src/CurrentWindowCmd.cc,v retrieving revision 1.9 diff -a -b -B -p -u -r1.9 CurrentWindowCmd.cc --- src/CurrentWindowCmd.cc 20 Feb 2004 19:40:31 -0000 1.9 +++ src/CurrentWindowCmd.cc 1 Jul 2004 11:25:41 -0000 @@ -29,6 +29,9 @@ #include "Screen.hh" #include "WinClient.hh" +#include "FbTk/StringUtil.hh" +#include + CurrentWindowCmd::CurrentWindowCmd(Action act):m_action(act) { } void CurrentWindowCmd::execute() { @@ -109,3 +112,37 @@ ResizeToCmd::ResizeToCmd(const int step_ void ResizeToCmd::real_execute() { fbwindow().resize(m_step_size_x, m_step_size_y); } + +PlaceCmd::PlaceCmd(const char* arguments) : + m_method(FluxboxWindow::MAX_SPACE), m_allow_smaller(false) { + + if (arguments) { + typedef std::vector ArgList; + ArgList args; + FbTk::StringUtil::stringtok< ArgList >(args, std::string(arguments)); + + for(ArgList::const_iterator it = args.begin(); it != args.end(); it++) { + if ( (*it) == "max_space" ) + m_method = FluxboxWindow::MAX_SPACE; + else if ( (*it) == "max_vertical_space" ) + m_method = FluxboxWindow::MAX_VERTICAL_SPACE; + else if ( (*it) == "max_horizontal_space" ) + m_method = FluxboxWindow::MAX_HORIZONTAL_SPACE; + else if ( (*it) == "expand_vertical" ) + m_method = FluxboxWindow::EXPAND_VERTICAL_SPACE; + else if ( (*it) == "expand_horizontal" ) + m_method = FluxboxWindow::EXPAND_HORIZONTAL_SPACE; + else if ( (*it) == "allow_smaller" ) + m_allow_smaller = true; + else if ( (*it) == "not_smaller" ) + m_allow_smaller = false; + else if ( (*it) == "draw_grid" ) + m_method = FluxboxWindow::DRAW_GRID; + } + } +} + +void PlaceCmd::real_execute() { + fbwindow().place(static_cast(m_method), + m_allow_smaller); +} Index: src/CurrentWindowCmd.hh =================================================================== RCS file: /cvsroot/fluxbox/fluxbox/src/CurrentWindowCmd.hh,v retrieving revision 1.7 diff -a -b -B -p -u -r1.7 CurrentWindowCmd.hh --- src/CurrentWindowCmd.hh 20 Feb 2004 19:40:31 -0000 1.7 +++ src/CurrentWindowCmd.hh 1 Jul 2004 11:25:41 -0000 @@ -135,4 +135,15 @@ private: const int m_step_size_x; const int m_step_size_y; }; + +// place cmd +class PlaceCmd : public WindowHelperCmd{ +public: + explicit PlaceCmd(const char* arguments); +protected: + void real_execute(); +private: + mutable unsigned int m_method; // look Window.hh + mutable bool m_allow_smaller; +}; #endif // CURRENTWINDOWCMD_HH Index: src/FbTk/FbDrawable.hh =================================================================== RCS file: /cvsroot/fluxbox/fluxbox/src/FbTk/FbDrawable.hh,v retrieving revision 1.4 diff -a -b -B -p -u -r1.4 FbDrawable.hh --- src/FbTk/FbDrawable.hh 16 Dec 2003 17:06:49 -0000 1.4 +++ src/FbTk/FbDrawable.hh 1 Jul 2004 11:25:41 -0000 @@ -37,17 +37,17 @@ public: unsigned int width, unsigned int height); virtual void fillRectangle(GC gc, int x, int y, - unsigned int width, unsigned int height); + unsigned int width, unsigned int height) const; virtual void drawRectangle(GC gc, int x, int y, - unsigned int width, unsigned int height); + unsigned int width, unsigned int height) const; virtual void drawLine(GC gc, int start_x, int start_y, - int end_x, int end_y); + int end_x, int end_y) const; virtual void fillPolygon(GC gc, XPoint *points, int npoints, - int shape, int mode); + int shape, int mode) const ; - virtual void drawPoint(GC gc, int x, int y); + virtual void drawPoint(GC gc, int x, int y) const; virtual XImage *image(int x, int y, unsigned int width, unsigned int height) const; Index: src/FbTk/GContext.hh =================================================================== RCS file: /cvsroot/fluxbox/fluxbox/src/FbTk/GContext.hh,v retrieving revision 1.9 diff -a -b -B -p -u -r1.9 GContext.hh --- src/FbTk/GContext.hh 22 Mar 2004 20:56:15 -0000 1.9 +++ src/FbTk/GContext.hh 1 Jul 2004 11:25:41 -0000 @@ -101,9 +101,10 @@ public: } inline void setLineAttributes(unsigned int width, - int line_style, - int cap_style, - int join_style) { + int line_style = LINESOLID, + int cap_style = CAPNOTLAST, + int join_style = JOINMITER) { + XSetLineAttributes(m_display, m_gc, width, line_style, cap_style, join_style); }