add most recently used window cycling (Simon)

It is now the default cycling action
This commit is contained in:
rathnor 2003-04-15 00:50:25 +00:00
parent 1aa5ede1b7
commit 58e19dc91e
9 changed files with 289 additions and 80 deletions

View file

@ -1,5 +1,8 @@
(Format: Year/Month/Day)
Changes for 0.9.1:
*03/04/15:
* Add most recently used/stacked window cycling, set as default (Simon)
Window.cc Screen.hh/cc fluxbox.hh/cc Keys.hh/cc
*03/04/14:
* Don't create menuconfig during install and style cleanups (Han)
fluxbox_generate_menu

View file

@ -82,7 +82,7 @@ Major Features:
* Toolbar modes (Simon)
= Tabs embedded in titlebar (Henrik)
= Tabgroup rewrite (Henrik)
= Most recently used window cycling (Simon)
* Most recently used window cycling (Simon)
Minor Features:
- per workspace backgrounds (Simon)
- more keybinding actions (Both)

View file

@ -19,7 +19,7 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//$Id: Keys.cc,v 1.24 2003/04/14 12:10:16 fluxgen Exp $
//$Id: Keys.cc,v 1.25 2003/04/15 00:50:24 rathnor Exp $
#include "Keys.hh"
@ -140,14 +140,18 @@ Keys::Keys(const char *filename):
m_numlock_mod(0),
m_scrolllock_mod(0),
m_abortkey(0),
m_display(FbTk::App::instance()->display())
m_display(FbTk::App::instance()->display()),
m_modmap(0)
{
determineModmap();
loadModmap();
if (filename != 0)
load(filename);
}
Keys::~Keys() {
if (m_modmap) {
XFreeModifiermap(m_modmap);
}
ungrabKeys();
deleteTree();
}
@ -458,7 +462,7 @@ unsigned int Keys::getKey(const char *keystr) {
Keys::KeyAction Keys::getAction(XKeyEvent *ke) {
static t_key *next_key = 0;
//remove numlock, capslock and scrolllock
ke->state &= ~Mod2Mask & ~Mod5Mask & ~LockMask;
ke->state = cleanMods(ke->state);
if (m_abortkey && *m_abortkey==ke) { //abort current keychain
next_key = 0;
@ -636,9 +640,14 @@ Keys::t_key::~t_key() {
}
/**
determines modifier mapping for caps, num and scroll lock
*/
void Keys::determineModmap() {
* load state relating to the modifier map
*/
void Keys::loadModmap() {
if (m_modmap) {
XFreeModifiermap(m_modmap);
}
m_modmap = XGetModifierMapping(m_display);
// mask to use for modifier
int mods[] = {
ShiftMask,
@ -652,15 +661,14 @@ void Keys::determineModmap() {
0
};
XModifierKeymap *map = XGetModifierMapping(m_display);
// find modifiers and set them
for (int i=0, realkey=0; i<8; ++i) {
for (int key=0; key<map->max_keypermod; ++key, ++realkey) {
for (int key=0; key<m_modmap->max_keypermod; ++key, ++realkey) {
if (map->modifiermap[realkey] == 0)
if (m_modmap->modifiermap[realkey] == 0)
continue;
KeySym ks = XKeycodeToKeysym(m_display, map->modifiermap[realkey], 0);
KeySym ks = XKeycodeToKeysym(m_display, m_modmap->modifiermap[realkey], 0);
switch (ks) {
case XK_Caps_Lock:
@ -675,5 +683,21 @@ void Keys::determineModmap() {
}
}
}
XFreeModifiermap(map);
}
unsigned int Keys::keycodeToModmask(unsigned int keycode) {
if (!m_modmap) return 0;
// search through modmap for this keycode
for (int mod=0; mod < 8; mod++) {
for (int key=0; key < m_modmap->max_keypermod; ++key) {
// modifiermap is an array with 8 sets of keycodes
// each max_keypermod long, but in a linear array.
if (m_modmap->modifiermap[m_modmap->max_keypermod*mod + key] == keycode) {
return (1<<mod);
}
}
}
// no luck
return 0;
}

View file

@ -19,7 +19,7 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
// $Id: Keys.hh,v 1.21 2003/04/14 12:10:14 fluxgen Exp $
// $Id: Keys.hh,v 1.22 2003/04/15 00:50:24 rathnor Exp $
#ifndef KEYS_HH
#define KEYS_HH
@ -74,6 +74,18 @@ public:
explicit Keys(const char *filename=0);
/// destructor
~Keys();
/**
Strip out modifiers we want to ignore
@return the cleaned state number
*/
static unsigned int cleanMods(unsigned int mods)
//remove numlock, capslock and scrolllock
{ return mods & (~Mod2Mask & ~Mod5Mask & ~LockMask);}
unsigned int keycodeToModmask(unsigned int keycode);
void loadModmap();
/**
Load configuration from file
@return true on success, else false
@ -170,8 +182,6 @@ private:
/// debug function
void showKeyTree(t_key *key, unsigned int w=0);
#endif //DEBUG
/// determine key modifier maps for caps-, num- and scrolllock
void determineModmap();
struct t_actionstr{
const char *string;
@ -187,6 +197,7 @@ private:
std::string m_execcmdstring; ///< copy of the execcommandstring
int m_param; ///< copy of the param argument
Display *m_display; ///< display connection
XModifierKeymap *m_modmap; // Modifier->keycode mapping
};
#endif // _KEYS_HH_

View file

@ -22,7 +22,7 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
// $Id: Screen.cc,v 1.119 2003/04/14 14:49:47 fluxgen Exp $
// $Id: Screen.cc,v 1.120 2003/04/15 00:50:24 rathnor Exp $
#include "Screen.hh"
@ -407,6 +407,7 @@ BScreen::BScreen(ResourceManager &rm,
m_workspacenames_sig(*this), // workspace names signal
m_currentworkspace_sig(*this), // current workspace signal
m_layermanager(num_layers),
cycling_focus(false),
theme(0), m_windowtheme(scrn),
m_menutheme(new FbTk::MenuTheme(scrn)),
resource(rm, screenname, altscreenname),
@ -449,6 +450,7 @@ BScreen::BScreen(ResourceManager &rm,
(unsigned char *) &bpid, 1);
#endif // HAVE_GETPID
cycling_window = focused_list.end();
XDefineCursor(disp, getRootWindow(), fluxbox->getSessionCursor());
@ -841,6 +843,15 @@ void BScreen::removeWindow(FluxboxWindow *win) {
(*it)->removeWindow(win);
}
void BScreen::removeClient(WinClient &client) {
WinClient *cyc = *cycling_window;
focused_list.remove(&client);
if (cyc == &client) {
cycling_window = focused_list.end();
}
}
FluxboxWindow *BScreen::getIcon(unsigned int index) {
if (index < iconList.size())
return iconList[index];
@ -1130,12 +1141,17 @@ FluxboxWindow *BScreen::createWindow(Window client) {
delete win;
return 0;
} else {
// always put on end of focused list, if it gets focused it'll get pushed up
// there is only the one win client at this stage
focused_list.push_back(&win->winClient());
//TODO: is next line needed?
Fluxbox::instance()->saveWindowSearch(client, win);
Fluxbox::instance()->attachSignals(*win);
setupWindowActions(*win);
}
if (win->getWorkspaceNumber() == getCurrentWorkspaceID() || win->isStuck()) {
win->show();
win->show();
}
XSync(FbTk::App::instance()->display(), False);
return win;
@ -1153,6 +1169,9 @@ FluxboxWindow *BScreen::createWindow(WinClient &client) {
delete win;
return 0;
}
// don't add to focused_list, as it should already be in there (since the
// WinClient already exists).
Fluxbox::instance()->saveWindowSearch(client.window(), win);
Fluxbox::instance()->attachSignals(*win);
setupWindowActions(*win);
@ -1343,27 +1362,58 @@ void BScreen::nextFocus(int opts) {
}
if (num_windows >= 1) {
Workspace *wksp = getCurrentWorkspace();
Workspace::Windows &wins = wksp->getWindowList();
Workspace::Windows::iterator it = wins.begin();
if (!(opts & CYCLELINEAR)) {
if (!cycling_focus) {
cycling_focus = True;
cycling_window = focused_list.begin();
}
// if it is stacked, we want the highest window in the focused list
// that is on the same workspace
FocusedWindows::iterator it = cycling_window;
FocusedWindows::iterator it_end = focused_list.end();
if (!have_focused) {
focused = (*it);
} else {
for (; (*it) != focused; ++it) //get focused window iterator
continue;
while (true) {
++it;
if (it == it_end) {
it = focused_list.begin();
}
// give up [do nothing] if we reach the current focused again
if ((*it) == (*cycling_window)) {
break;
}
FluxboxWindow *fbwin = (*it)->m_win;
if (fbwin && !fbwin->isIconic() &&
(fbwin->isStuck()
|| fbwin->getWorkspaceNumber() == getCurrentWorkspaceID())) {
// either on this workspace, or stuck
if (! (doSkipWindow(fbwin, opts) || !fbwin->setInputFocus()) )
break;
}
}
cycling_window = it;
} else { // not stacked cycling
Workspace *wksp = getCurrentWorkspace();
Workspace::Windows &wins = wksp->getWindowList();
Workspace::Windows::iterator it = wins.begin();
if (!have_focused) {
focused = (*it);
} else {
for (; (*it) != focused; ++it) //get focused window iterator
continue;
}
do {
++it;
if (it == wins.end())
it = wins.begin();
// see if the window should be skipped
if (! (doSkipWindow((*it), opts) || !(*it)->setInputFocus()) )
break;
} while ((*it) != focused);
if ((*it) != focused && it != wins.end())
(*it)->raise();
}
do {
++it;
if (it == wins.end())
it = wins.begin();
// see if the window should be skipped
if (! (doSkipWindow((*it), opts) || !(*it)->setInputFocus()) )
break;
} while ((*it) != focused);
if ((*it) != focused && it != wins.end())
(*it)->raise();
}
@ -1385,29 +1435,62 @@ void BScreen::prevFocus(int opts) {
}
if (num_windows >= 1) {
Workspace *wksp = getCurrentWorkspace();
Workspace::Windows &wins = wksp->getWindowList();
Workspace::Windows::iterator it = wins.begin();
if (!(opts & CYCLELINEAR)) {
if (!cycling_focus) {
cycling_focus = True;
cycling_window = focused_list.end();
}
// if it is stacked, we want the highest window in the focused list
// that is on the same workspace
FocusedWindows::iterator it = cycling_window;
FocusedWindows::iterator it_end = focused_list.end();
if (!have_focused) {
focused = (*it);
} else {
for (; (*it) != focused; ++it) //get focused window iterator
continue;
while (true) {
--it;
if (it == it_end) {
it = focused_list.end();
--it;
}
// give up [do nothing] if we reach the current focused again
if ((*it) == (*cycling_window)) {
break;
}
FluxboxWindow *fbwin = (*it)->m_win;
if (fbwin && !fbwin->isIconic() &&
(fbwin->isStuck()
|| fbwin->getWorkspaceNumber() == getCurrentWorkspaceID())) {
// either on this workspace, or stuck
if (! (doSkipWindow(fbwin, opts) || !fbwin->setInputFocus()) )
break;
}
}
cycling_window = it;
} else { // not stacked cycling
Workspace *wksp = getCurrentWorkspace();
Workspace::Windows &wins = wksp->getWindowList();
Workspace::Windows::iterator it = wins.begin();
if (!have_focused) {
focused = (*it);
} else {
for (; (*it) != focused; ++it) //get focused window iterator
continue;
}
do {
if (it == wins.begin())
it = wins.end();
--it;
// see if the window should be skipped
if (! (doSkipWindow((*it), opts) || !(*it)->setInputFocus()) )
break;
} while ((*it) != focused);
if ((*it) != focused && it != wins.end())
(*it)->raise();
}
do {
if (it == wins.begin())
it = wins.end();
--it;
// see if the window should be skipped
if (! (doSkipWindow((*it), opts) || !(*it)->setInputFocus()) )
break;
} while ((*it) != focused);
if ((*it) != focused && it != wins.end())
(*it)->raise();
}
}
@ -1428,6 +1511,15 @@ void BScreen::raiseFocus() {
fb->getFocusedWindow()->raise();
}
void BScreen::setFocusedWindow(WinClient &winclient) {
// raise newly focused window to the top of the focused list
if (!cycling_focus) { // don't change the order if we're cycling
focused_list.remove(&winclient);
focused_list.push_front(&winclient);
cycling_window = focused_list.begin();
}
}
void BScreen::initMenu() {
I18n *i18n = I18n::instance();
@ -2059,6 +2151,19 @@ bool BScreen::doSkipWindow(const FluxboxWindow *w, int opts) {
(opts & CYCLESKIPSHADED) != 0 && w->isShaded()); // skip if shaded
}
/**
Called when a set of watched modifiers has been released
*/
void BScreen::notifyReleasedKeys(XKeyEvent &ke) {
if (cycling_focus) {
cycling_focus = false;
// put currently focused window to top
WinClient *client = *cycling_window;
focused_list.erase(cycling_window);
focused_list.push_front(client);
}
}
/**
Access and clear the auto-group window
*/

View file

@ -22,7 +22,7 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
// $Id: Screen.hh,v 1.74 2003/04/14 12:13:36 fluxgen Exp $
// $Id: Screen.hh,v 1.75 2003/04/15 00:50:24 rathnor Exp $
#ifndef SCREEN_HH
#define SCREEN_HH
@ -151,6 +151,7 @@ public:
unsigned int getMaxBottom() const;
typedef std::vector<FluxboxWindow *> Icons;
typedef std::list<WinClient *> FocusedWindows;
/// @return number of workspaces
inline unsigned int getCount() const { return workspacesList.size(); }
@ -158,6 +159,8 @@ public:
inline unsigned int getIconCount() const { return iconList.size(); }
inline const Icons &getIconList() const { return iconList; }
inline Icons &getIconList() { return iconList; }
inline const FocusedWindows &getFocusedList() const { return focused_list; }
inline FocusedWindows &getFocusedList() { return focused_list; }
const Workspaces &getWorkspacesList() const { return workspacesList; }
const WorkspaceNames &getWorkspaceNames() const { return workspaceNames; }
/**
@ -258,6 +261,7 @@ public:
void removeIcon(FluxboxWindow *win);
// remove window
void removeWindow(FluxboxWindow *win);
void removeClient(WinClient &client);
std::string getNameOfWorkspace(unsigned int workspace) const;
void changeWorkspaceID(unsigned int);
@ -269,6 +273,8 @@ public:
void prevFocus(int options);
void nextFocus(int options);
void raiseFocus();
void setFocusedWindow(WinClient &winclient);
void reconfigure();
void rereadMenu();
void shutdown();
@ -276,6 +282,8 @@ public:
void showGeometry(unsigned int, unsigned int);
void hideGeometry();
void notifyReleasedKeys(XKeyEvent &ke);
void setLayer(FbTk::XLayerItem &item, int layernum);
// remove? no, items are never removed from their layer until they die
@ -306,7 +314,7 @@ public:
WINDOWLOWER, WINDOWSTICK, WINDOWKILL, SETSTYLE, WINDOWTAB};
// prevFocus/nextFocus option bits
enum { CYCLESKIPLOWERTABS = 0x01, CYCLESKIPSTUCK = 0x02, CYCLESKIPSHADED = 0x04,
CYCLEDEFAULT = 0x00 };
CYCLELINEAR = 0x08, CYCLEDEFAULT = 0x00 };
class ScreenSubject:public FbTk::Subject {
public:
@ -334,10 +342,8 @@ private:
m_currentworkspace_sig; ///< current workspace signal
FbTk::MultLayers m_layermanager;
//!!
Theme *theme; ///< obsolete
Bool root_colormap_installed, managed, geom_visible;
Bool root_colormap_installed, managed, geom_visible, cycling_focus;
GC opGC;
Pixmap geom_pixmap;
FbTk::FbWindow geom_window;
@ -353,6 +359,12 @@ private:
Rootmenus rootmenuList;
Netizens netizenList;
Icons iconList;
// This list keeps the order of window focusing for this screen
// Screen global so it works for sticky windows too.
FocusedWindows focused_list;
FocusedWindows::iterator cycling_window;
#ifdef SLIT
std::auto_ptr<Slit> m_slit;
#endif // SLIT
@ -368,6 +380,9 @@ private:
Window auto_group_window;
//!!
Theme *theme; ///< obsolete
FbWinFrameTheme m_windowtheme;
std::auto_ptr<FbTk::MenuTheme> m_menutheme;

View file

@ -22,7 +22,7 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
// $Id: Window.cc,v 1.131 2003/04/14 14:58:12 fluxgen Exp $
// $Id: Window.cc,v 1.132 2003/04/15 00:50:25 rathnor Exp $
#include "Window.hh"
@ -1143,7 +1143,8 @@ bool FluxboxWindow::setInputFocus() {
}
m_frame.setFocus(true);
screen.setFocusedWindow(*m_client);
Fluxbox::instance()->setFocusedWindow(this);
if (send_focus_message)

View file

@ -22,7 +22,7 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
// $Id: fluxbox.cc,v 1.106 2003/04/14 15:28:52 fluxgen Exp $
// $Id: fluxbox.cc,v 1.107 2003/04/15 00:50:25 rathnor Exp $
#include "fluxbox.hh"
@ -373,6 +373,7 @@ Fluxbox::Fluxbox(int m_argc, char **m_argv, const char *dpy_name, const char *rc
m_rc_cache_max(m_resourcemanager, 200, "session.cacheMax", "Session.CacheMax"),
focused_window(0), masked_window(0),
timer(this),
watching_screen(0), watch_keyrelease(0),
no_focus(false),
rc_file(rc ? rc : ""),
argv(m_argv), argc(m_argc),
@ -699,6 +700,15 @@ void Fluxbox::handleEvent(XEvent * const e) {
case UnmapNotify:
handleUnmapNotify(e->xunmap);
break;
case MappingNotify:
// Update stored modifier mapping
#ifdef DEBUG
cerr<<__FILE__<<"("<<__FUNCTION__<<"): MappingNotify"<<endl;
#endif // DEBUG
if (key.get()) {
key->loadModmap();
}
break;
case CreateNotify:
break;
case DestroyNotify: {
@ -767,6 +777,7 @@ void Fluxbox::handleEvent(XEvent * const e) {
}
break;
case KeyRelease:
case KeyPress:
handleKeyEvent(e->xkey);
break;
@ -1136,9 +1147,19 @@ void Fluxbox::handleKeyEvent(XKeyEvent &ke) {
}
break;
case Keys::NEXTWINDOW: //activate next window
if (!watching_screen && !(key->getParam() & BScreen::CYCLELINEAR)) {
// if stacked cycling, then set a watch for
// the release of exactly these modifiers
watchKeyRelease(screen, Keys::cleanMods(ke.state));
}
screen->nextFocus(key->getParam());
break;
case Keys::PREVWINDOW: //activate prev window
if (!watching_screen && !(key->getParam() & BScreen::CYCLELINEAR)) {
// if stacked cycling, then set a watch for
// the release of exactly these modifiers
watchKeyRelease(screen, Keys::cleanMods(ke.state));
}
screen->prevFocus(key->getParam());
break;
case Keys::NEXTTAB:
@ -1242,7 +1263,30 @@ void Fluxbox::handleKeyEvent(XKeyEvent &ke) {
break;
}
case KeyRelease:
{
// we ignore most key releases unless we need to use
// a release to stop something (e.g. window cycling).
// we notify if _all_ of the watched modifiers are released
if (watching_screen && watch_keyrelease) {
// mask the mod of the released key out
// won't mask anything if it isn't a mod
ke.state &= ~key->keycodeToModmask(ke.keycode);
if ((watch_keyrelease & ke.state) == 0) {
watching_screen->notifyReleasedKeys(ke);
XUngrabKeyboard(getXDisplay(), CurrentTime);
// once they are released, we drop the watch
watching_screen = 0;
watch_keyrelease = 0;
}
}
break;
}
default:
break;
}
@ -1470,10 +1514,7 @@ void Fluxbox::update(FbTk::Subject *changedsub) {
}
// make sure each workspace get this
BScreen &scr = win.getScreen();
for (int workspace = 0; workspace < scr.getNumberOfWorkspaces();
++workspace) {
scr.getWorkspace(workspace)->removeWindow(&win);
}
scr.removeWindow(&win);
} else if ((&(win.workspaceSig())) == changedsub) { // workspace signal
for (size_t i=0; i<m_atomhandler.size(); ++i) {
@ -1513,13 +1554,12 @@ void Fluxbox::update(FbTk::Subject *changedsub) {
} else if (typeid(*changedsub) == typeid(WinClient::WinClientSubj)) {
WinClient::WinClientSubj *subj = dynamic_cast<WinClient::WinClientSubj *>(changedsub);
WinClient &client = subj->winClient();
//!! TODO we shouldn't call update netizen on every screen
// just the screen it was located on
ScreenList::iterator screen_it = screenList.begin();
const ScreenList::iterator screen_it_end = screenList.end();
for (; screen_it != screen_it_end; ++screen_it)
(*screen_it)->updateNetizenWindowDel(client.window());
if (client.fbwindow()) {
BScreen &screen = client.fbwindow()->getScreen();
screen.updateNetizenWindowDel(client.window());
screen.removeClient(client);
}
removeWindowSearch(client.window());
//!! TODO
@ -2232,13 +2272,12 @@ void Fluxbox::setFocusedWindow(FluxboxWindow *win) {
if (focused_window != 0) {
old_win = focused_window;
old_screen = &old_win->getScreen();
old_tbar = old_screen->getToolbar();
old_wkspc = old_screen->getWorkspace(old_win->getWorkspaceNumber());
old_win->setFocusFlag(False);
old_wkspc->menu().setItemSelected(old_win->getWindowNumber(), false);
}
if (win && ! win->isIconic()) {
@ -2272,3 +2311,10 @@ void Fluxbox::setFocusedWindow(FluxboxWindow *win) {
old_screen->updateNetizenWindowFocus();
}
void Fluxbox::watchKeyRelease(BScreen *screen, unsigned int mods) {
watching_screen = screen;
watch_keyrelease = mods;
XGrabKeyboard(getXDisplay(),screen->getRootWindow(), True,
GrabModeAsync, GrabModeAsync, CurrentTime);
}

View file

@ -22,7 +22,7 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
// $Id: fluxbox.hh,v 1.47 2003/04/14 15:25:14 fluxgen Exp $
// $Id: fluxbox.hh,v 1.48 2003/04/15 00:50:25 rathnor Exp $
#ifndef FLUXBOX_HH
#define FLUXBOX_HH
@ -141,6 +141,8 @@ public:
{ masked = w; masked_window = bw; }
inline void setNoFocus(Bool f) { no_focus = f; }
void watchKeyRelease(BScreen *screen, unsigned int mods);
void setFocusedWindow(FluxboxWindow *w);
void shutdown();
void load_rc(BScreen *);
@ -236,6 +238,8 @@ private:
FluxboxWindow *focused_window, *masked_window;
FbTk::Timer timer;
BScreen *watching_screen;
unsigned int watch_keyrelease;
#ifdef HAVE_GETPID
Atom fluxbox_pid;