all repos — fluxbox @ a59428d67a95a9df16554962f0a6257d6378328a

custom fork of the fluxbox windowmanager

merged changes from pre-devel
markt markt
commit

a59428d67a95a9df16554962f0a6257d6378328a

parent

41b5c6dadb1f474675660cef18b812d4c2338ed2

93 files changed, 3083 insertions(+), 3177 deletions(-)

jump to
M ChangeLogChangeLog

@@ -1,9 +1,136 @@

(Format: Year/Month/Day) -Changes for 1.0.0: +Changes for 1.0.1: *07/10/13: + * Merged pre-devel branch; see all Changes since 1.0.0 (Mark) * Updated ru_RU (Thanks Konstantin Shashkin) - * Deiconify windows via :Deiconify in reverse order (Mathias) + * deiconify windows via :Deiconify in reverse order (Mathias) FbCommands.cc +*07/05/23: + * Added key command :Attach <pattern> which groups all windows matching the + given pattern (Mark) + FbCommandFactory.cc WorkspaceCmd.cc/hh +*07/05/20: + * Added resources session.screen<N>.maxDisable{Move,Resize}: <boolean>, which + prevent maximized windows from being moved/resized (Mark) + Window.cc Screen.cc/hh nls/fluxbox-nls.hh +*07/05/19: + * Changed behavior of resource session.screen<N>.followModel (Mark) + - now only options are Ignore and Follow, the latter using the setting in + session.screen<N>.userFollowModel + Window.cc/hh Ewmh.cc Screen.cc/hh +*07/05/16: + * Added new resource session.screen<N>.noFocusWhileTypingDelay: <int> (Mark) + - specifies a time in milliseconds that new windows should not gain focus + while the user is typing in the focused window + Window.cc/hh Screen.cc/hh +*07/05/13: + * Added new placement policies {Row,Col}MinOverlapPlacement. They behave the + same as {Row,Col}SmartPlacement when the window fits but fall back on + minimizing overlap with other windows instead of CascadePlacement (Mark) + MinOverlapPlacement.cc/hh ScreenPlacement.cc/hh +*07/04/23: + * Set IconicState on all unmapped clients and unmap clients with frames, as + per ICCCM 4.1.4 (Mark) + Screen.cc Window.cc FocusControl.cc + * Added ClientMenu key command, which pops up a menu of open windows, based + on a pattern match + - e.g. :ClientMenu (workspace=[current]) (minimized=no) + ClientMenu.cc FbCommands.cc/hh FbCommandFactory.cc +*07/04/11: + * Added resource session.screen<N>.maxIgnoreIncrement: <boolean>, to + disable size checking when maximizing a window (e.g. terminals) (Mark) + - Also added a new configuration submenu for maximize options, to be filled + at a later date + Screen.cc/hh Window.cc +*07/04/08: + * Added OnToolbar modifier to keys file (Mark) + Keys.cc/hh Toolbar.cc/hh Screen.cc/hh IconbarTool.cc fluxbox.cc +*07/04/06: + * More changes to theme handling (Mark) + - introduced window.label.(un)focused.{justify,border{Color,Width}}, + which fallback to window.label.{justify,border{Color,Width}} before + window.{justify,border{Color,Width}} + - this has the backwards-incompatible effect that + toolbar.iconbar.(un)focused.* fallback first to toolbar.iconbar.* and + then to window.label.* + FbWinFrame.cc/hh IconbarTool.cc/hh IconButton.cc/hh IconbarTheme.cc + FbWinFrameTheme.cc/hh +*07/04/03: + * Added window.label.(un)focused.font to styles (Mark) + FbWinFrame.cc +*07/03/31: + * [group] tag in apps file may now have a pattern appended to it, and a new + window will only be automatically attached to the group if the group + matches that pattern -- e.g. [group] (workspace) (shaded=no) will only + automatically group with windows on the current workspace that are not + shaded (Mark) + Remember.cc/hh + * Lots of window commands now take a client pattern as an additional + argument, and the command will then be applied to all matching windows + (Mark) + - For example: `SendToWorkspace 2 (xterm)' will send all xterm windows to + workspace 2 + - Here is the full list of affected commands (which is not to imply they + all necessarily make sense to do): Fullscreen, Minimize, Maximize, + MaximizeVertical, MaximizeHorizontal, SetAlpha, Resize, ResizeTo, + ResizeHorizontal, ResizeVertical, MoveTo, Move, MoveRight, MoveLeft, + MoveUp, MoveDown, Raise, RaiseLayer, Lower, LowerLayer, Close, Kill, + Shade, Stick, ToggleDecor, SetHead, Tab, SendToNextWorkspace, + SendToPrevWorkspace, TakeToNextWorkspace, TakeToPrevWorkspace, + SendToWorkspace, TakeToWorkspace, NextTab, PrevTab, MoveTabLeft, + MoveTabRight, DetachClient + WorkspaceCmd.cc/hh CurrentWindowCmd.cc/hh FbCommandFactory.cc +*07/03/30: + * Changed syntax for window cycling (Mark) + - Instead of a bitmask, the window cycling functions NextWindow, + PrevWindow, TypeAheadFocus, and GoToWindow now take a list of options + enclosed in {} followed by a pattern similar to those used in the apps + file. + - Examples: + * NextWindow {static groups} (shaded=yes) (name=xterm) + - cycles through all shaded xterms in creation order, only focusing + the active tab in the group + * GoToWindow 3 (title=[current]) + - focuses the third client in last-focused order with the same title + as the currently focused window + - The options are: name, class, title, role, maximized, minimized, shaded, + stuck, focushidden (can't be disabled), iconhidden, workspace (matches + workspace names, not numbers), head (numbers), and layer (names) + - Parsing is a pain, so you'll have to update your keys file yourself for + now. +*07/03/29: + * Removed groups file; entries will be added to the apps file automatically + (Mark) + * Fixed a problem with programs starting in IconicState (Mark) +*07/03/27: + * Added new resource session.screen<N>.clientMenu.usePixmap that puts the + window's icon in the workspace and icons menus: default true. (Mark) + - For some reason, it doesn't work with un-shaped icons yet, but I've spent + way too many hours already trying to figure out why + * Use IconTitle in iconbar for minimized windows (Mark) +*07/03/25: + * Added new resource session.screen<N>.tabs.usePixmap that puts the window's + icon in the tab, if available. This is on by default. (Mark) + Window.cc FbWinFrame.cc/hh WinClient.cc Screen.cc/hh +*07/03/24: + * Added new key command GoToWindow (Mark) + - Syntax is GoToWindow <int> [<bitmask>], where the int gives the position + of the desired window with respect to a list of windows, and the bitmask + is the same as for NextWindow. A negative number for <int> will count + back from the end of the list. + - Particularly useful examples are GoToWindow <int> 9 and + GoToWindow <int> 25, which will focus the window at position <int> in the + iconbar modes Workspace and WorkspaceNoIcons, respectively. + * Fixed creation order window cycling with tabbed windows (Mark) +*07/03/21: + * Added new command TypeAheadFocus (Mark) + - syntax is the same as for NextWindow; when you run the command, you can + start typing the title of the window, and it will gain focus; pressing + tab will cycle through all matching entries using the options specified; + when you've found the window you want, just press return or escape + WinClient.hh Screen.cc/hh FbCommandFactory.cc WorkspaceCmd.cc/hh +-------------------------------- +Changes for 1.0.0: *07/10/08: * Changed default style to bloe *07/10/07:
M nls/fluxbox-nls.hhnls/fluxbox-nls.hh

@@ -77,6 +77,10 @@ ConfigmenuTabsInTitlebar = 22,

ConfigmenuExternalTabWidth = 23, ConfigmenuMouseTabFocus = 24, ConfigmenuClickTabFocus = 25, + ConfigmenuMaxMenu = 26, + ConfigmenuMaxIgnoreInc = 27, + ConfigmenuMaxDisableMove = 28, + ConfigmenuMaxDisableResize = 29, EwmhSet = 5, EwmhOutOfMemoryClientList = 1,
M nls/ru_RU/generated-KOI8-R.mnls/ru_RU/generated-KOI8-R.m

@@ -62,7 +62,6 @@ 9

10 11 12 -13 14 15 16 -

@@ -82,15 +81,49 @@ 1 : EWMH

$set 6 #FbTkError +1 ! > 3200, = 3200 +2 ! > 3200, = 3200 +3 : +4 . +5 pixmap +6 XImage +7 +8 : alpha. +9 : alpha picture. +10 : alpha pixmap. +11 (%d) +12 +13 . +14 . +15 . +16 +17 visual +18 $set 7 #Fluxbox +1 +2 +3 +4 +5 ! ! +6 %s +7 .\n, WM. +8 +9 ! fluxbox . +10 X .\n, X Fluxbox. +11 : X +12 : $set 8 #Gnome +1 : GNOME $set 9 #Keys +1 Keys: +2 Keys: +3 Keys: / $set 10 #Menu

@@ -103,6 +136,7 @@ 6 ...

7 8 9 +10 : [encoding] $set 11 #Remember

@@ -121,6 +155,11 @@ 13

$set 12 #Screen +1 BScreen::BScreen: X .\n +2 W: %4d x H: %4d +3 BScreen::BScreen: %d visual 0x%lx, depth %d\n +4 W: %04d x H: %04d + $set 13 #Slit 1 2

@@ -165,6 +204,7 @@ 7 ...

8 9 10 +11 $set 17 #Workspace

@@ -176,6 +216,7 @@

$set 18 #fbsetroot 1 : : -solid, -mod, -gradient\n +2 pixmap, ! 3 -display <string> \n\ -mod <x> <y> \n\ -foreground, -fg <color> \n\

@@ -196,8 +237,8 @@ 5

6 7 8 : '-log' -9 -10 +9 +10 11 : '-rc' 12 : '-screen' 13 Fluxbox %s: (c) %s Henrik Kinnunen\n\
M nls/ru_RU/generated-UTF-8.mnls/ru_RU/generated-UTF-8.m

@@ -62,7 +62,6 @@ 9 Перемещать фокус на новые окна

10 Полная максимизация 11 Сглаживать изображение 12 Перемещение заполненных окон -13 Размытый фокус 14 Фокус по перемещению 15 Перемещение окон между рабочими столами 16 Использовать псевдо-прозрачность

@@ -82,15 +81,49 @@ 1 Фатальная ошибка: не удалось выделить память для списка клиентов EWMH

$set 6 #FbTkError +1 Внимание! Высота > 3200, установлена Высота = 3200 +2 Внимание! Ширина > 3200, установлена Ширина = 3200 +3 Внимание: не удалось загрузить резервный шрифт +4 Ошибка выделения памяти. +5 Ошибка при создании pixmap +6 Невозможно создать XImage +7 Ошибка чтения +8 Внимание: Неверное значение alpha. +9 Внимание: Не удалось создать alpha picture. +10 Внимание: Не удалось создать alpha pixmap. +11 Не удалось найти формат экрана(%d) +12 Нехватка памяти +13 Нехватка памяти при выделении буфера синего. +14 Нехватка памяти при выделении буфера зеленого. +15 Нехватка памяти при выделении буфера красного. +16 Ошибка чтения элемента стиля +17 Неподдерживаемый visual +18 Установлено значение по умолчанию $set 7 #Fluxbox +1 Неправильное имя файла ресурсов +2 Невозможно загрузить файл групп +3 Невозможно загрузить базу +4 Повторная попытка с +5 Внимание! Не найден экран для отображения окна! +6 Невозможно создать директорию %s +7 Не удалось найти экран.\nУбедитесь, что не запущен другой WM. +8 Ошибка при разборе регулярного выражения +9 Фатальная ошибка! Экземпляр класса fluxbox может быть только один. +10 Невозможно соединиться с X сервером.\nУбедитесь, что X сервер запущен перед запуском Fluxbox. +11 Внимание: X сервер не поддерживает локаль +12 Внимание: невозможно установить модификаторы локали $set 8 #Gnome +1 Фатальная ошибка: не удалось выделить память для списка клиентов GNOME $set 9 #Keys +1 Keys: Ошибка в строке +2 Keys: Не удалось создать дерево ключей +3 Keys: Неверная клавиша/модификатор в строке $set 10 #Menu

@@ -103,6 +136,7 @@ 6 В заголовок...

7 Расположение 8 Перечитать настройки 9 Перезапуск +10 Внимание: не закрыты тэги [encoding] $set 11 #Remember

@@ -121,6 +155,11 @@ 13 Прозрачность

$set 12 #Screen +1 BScreen::BScreen: произошла ошибка во время опроса X сервера.\n запущен другой менеджер окон +2 W: %4d x H: %4d +3 BScreen::BScreen: управляем экраном %d используя visual 0x%lx, depth %d\n +4 W: %04d x H: %04d + $set 13 #Slit 1 Клиенты 2 Обычный порядок

@@ -165,6 +204,7 @@ 7 Отправить окно на ...

8 Свернуть в заголовок 9 Приклеить 10 Убить +11 Использовать установки по умолчанию $set 17 #Workspace

@@ -176,6 +216,7 @@

$set 18 #fbsetroot 1 Ошибка: необходимо задать один из следующих ключей: -solid, -mod, -gradient\n +2 Не удалось создать атомы pixmap, бросаем это гиблое дело! 3 -display <string> соединение с дисплеем\n\ -mod <x> <y> макет клетки\n\ -foreground, -fg <color> цвет переднего плана клетки\n\

@@ -196,8 +237,8 @@ 5 Ошибка во время выполнения

6 Стандартное исключение 7 Неизвестная ошибка 8 ошибка: '-log' требует наличие аргумента -9 Записывается в -10 Имя журнала +9 Имя файла журнала +10 Записывается в 11 ошибка: '-rc' требует наличие аргумента 12 ошибка: '-screen' требует наличие аргумента 13 Fluxbox %s: (c) %s Henrik Kinnunen\n\
M src/AttentionNoticeHandler.ccsrc/AttentionNoticeHandler.cc

@@ -23,7 +23,7 @@ // $Id$

#include "AttentionNoticeHandler.hh" -#include "WinClient.hh" +#include "Window.hh" #include "Screen.hh" #include "STLUtil.hh"

@@ -34,16 +34,15 @@

namespace { class ToggleFrameFocusCmd: public FbTk::Command { public: - ToggleFrameFocusCmd(WinClient &client): + ToggleFrameFocusCmd(Focusable &client): m_client(client), m_state(false) {} void execute() { m_state ^= true; - m_client.fbwindow()->setLabelButtonFocus(m_client, m_state); - m_client.fbwindow()->setAttentionState(m_state); + m_client.setAttentionState(m_state); } private: - WinClient& m_client; + Focusable &m_client; bool m_state; };

@@ -54,9 +53,9 @@ AttentionNoticeHandler::~AttentionNoticeHandler() {

STLUtil::destroyAndClearSecond(m_attentions); } -void AttentionNoticeHandler::addAttention(WinClient &client) { +void AttentionNoticeHandler::addAttention(Focusable &client) { // no need to add already active client - if (client.fbwindow()->isFocused() && &client.fbwindow()->winClient() == &client) + if (client.isFocused()) return; // Already have a notice for it?

@@ -104,22 +103,24 @@

void AttentionNoticeHandler::update(FbTk::Subject *subj) { // we need to be able to get the window - if (typeid(*subj) != typeid(WinClient::WinClientSubj)) + if (!subj || typeid(*subj) != typeid(Focusable::FocusSubject)) return; // all signals results in destruction of the notice - WinClient::WinClientSubj *winsubj = - static_cast<WinClient::WinClientSubj *>(subj); - delete m_attentions[&winsubj->winClient()]; - m_attentions.erase(&winsubj->winClient()); + Focusable::FocusSubject *winsubj = + static_cast<Focusable::FocusSubject *>(subj); + delete m_attentions[&winsubj->win()]; + m_attentions.erase(&winsubj->win()); + winsubj->win().setAttentionState(false); // update _NET_WM_STATE atom - FluxboxWindow *fbwin = winsubj->winClient().fbwindow(); - if (fbwin && winsubj != &winsubj->winClient().dieSig()) + FluxboxWindow *fbwin = winsubj->win().fbwindow(); + if (fbwin && winsubj != &winsubj->win().dieSig()) fbwin->stateSig().notify(); + } -bool AttentionNoticeHandler::isDemandingAttention(WinClient &client) { +bool AttentionNoticeHandler::isDemandingAttention(Focusable &client) { return m_attentions.find(&client) != m_attentions.end(); }
M src/AttentionNoticeHandler.hhsrc/AttentionNoticeHandler.hh

@@ -27,7 +27,7 @@ #include "FbTk/Observer.hh"

#include <map> -class WinClient; +class Focusable; namespace FbTk { class Timer;

@@ -41,14 +41,14 @@ class AttentionNoticeHandler: public FbTk::Observer {

public: ~AttentionNoticeHandler(); - typedef std::map<WinClient*, FbTk::Timer*> NoticeMap; + typedef std::map<Focusable*, FbTk::Timer*> NoticeMap; /// Adds a client that requires attention, /// will fail if the client is already active - void addAttention(WinClient &client); + void addAttention(Focusable &client); /// removes the client from the attention map void update(FbTk::Subject *subj); - bool isDemandingAttention(WinClient &client); + bool isDemandingAttention(Focusable &client); private: NoticeMap m_attentions;
M src/CascadePlacement.ccsrc/CascadePlacement.cc

@@ -42,7 +42,7 @@ delete [] m_cascade_x;

delete [] m_cascade_y; } -bool CascadePlacement::placeWindow(const std::vector<FluxboxWindow *> &windowlist, +bool CascadePlacement::placeWindow(const std::list<FluxboxWindow *> &windowlist, const FluxboxWindow &win, int &place_x, int &place_y) {
M src/CascadePlacement.hhsrc/CascadePlacement.hh

@@ -34,7 +34,7 @@ private FbTk::NotCopyable {

public: explicit CascadePlacement(const BScreen &screen); ~CascadePlacement(); - bool placeWindow(const std::vector<FluxboxWindow *> &windowlist, + bool placeWindow(const std::list<FluxboxWindow *> &windowlist, const FluxboxWindow &window, int &place_x, int &place_y); private:
A src/ClientMenu.cc

@@ -0,0 +1,146 @@

+// ClientMenu.hh +// Copyright (c) 2007 Fluxbox Team (fluxgen at fluxbox dot org) +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +// $Id$ + +#include "ClientMenu.hh" + +#include "Layer.hh" +#include "Screen.hh" +#include "Window.hh" +#include "WindowCmd.hh" + +#include "FbTk/MenuItem.hh" + +namespace { // anonymous + +class ClientMenuItem: public FbTk::MenuItem { +public: + ClientMenuItem(Focusable &client, ClientMenu &menu): + FbTk::MenuItem(client.title().c_str(), menu), + m_client(client) { + client.titleSig().attach(&menu); + client.dieSig().attach(&menu); + } + ~ClientMenuItem() { m_client.titleSig().detach(menu()); } + + void click(int button, int time) { + FluxboxWindow *fbwin = m_client.fbwindow(); + if (fbwin == 0) + return; + + // this MenuItem object can get destroyed as a result of focus(), so we + // must get a local copy of the parent menu + FbTk::Menu *parent = menu(); + + m_client.focus(); + fbwin->raise(); + parent->hide(); + } + + const std::string &label() const { return m_client.title(); } + const FbTk::PixmapWithMask *icon() const { + return m_client.screen().clientMenuUsePixmap() ? &m_client.icon() : 0; + } + + bool isSelected() const { + if (m_client.fbwindow() == 0) + return false; + if (m_client.fbwindow()->isFocused() == false) + return false; + return (&(m_client.fbwindow()->winClient()) == &m_client); + } + + // for updating menu when receiving a signal from client + Focusable *client() { return &m_client; } + +private: + Focusable &m_client; +}; + +}; // end anonymous namespace + +ClientMenu::ClientMenu(BScreen &screen, Focusables &clients, + FbTk::Subject *refresh): + FbMenu(screen.menuTheme(), screen.imageControl(), + *screen.layerManager().getLayer(Layer::MENU)), + m_list(clients), + m_refresh_sig(refresh) { + + if (refresh) + refresh->attach(this); + refreshMenu(); + +} + +void ClientMenu::refreshMenu() { + // remove all items and then add them again + removeAll(); + + // for each fluxboxwindow add every client in them to our clientlist + Focusables::iterator win_it = m_list.begin(); + Focusables::iterator win_it_end = m_list.end(); + for (; win_it != win_it_end; ++win_it) { + // add every client in this fluxboxwindow to menu + if (typeid(*win_it) == typeid(FluxboxWindow *)) { + FluxboxWindow *win = static_cast<FluxboxWindow *>(*win_it); + FluxboxWindow::ClientList::iterator client_it = + win->clientList().begin(); + FluxboxWindow::ClientList::iterator client_it_end = + win->clientList().end(); + for (; client_it != client_it_end; ++client_it) + insert(new ClientMenuItem(**client_it, *this)); + } else + insert(new ClientMenuItem(**win_it, *this)); + } + + updateMenu(); +} + +void ClientMenu::update(FbTk::Subject *subj) { + if (subj == m_refresh_sig) + refreshMenu(); + else if (subj && typeid(*subj) == typeid(Focusable::FocusSubject)) { + + Focusable::FocusSubject *fsubj = static_cast<Focusable::FocusSubject *>(subj); + Focusable &win = fsubj->win(); + + // find the corresponding menuitem + ClientMenuItem *cl_item = 0; + for (size_t i = 0; i < numberOfItems(); i++) { + FbTk::MenuItem *item = find(i); + if (item && typeid(*item) == typeid(ClientMenuItem)) { + cl_item = static_cast<ClientMenuItem *>(item); + if (cl_item->client() == &win) + break; + } + } + + // update accordingly + if (cl_item && fsubj == &win.dieSig()) + remove(cl_item->getIndex()); + else if (cl_item && fsubj == &win.titleSig()) + // this could change the size of the menu, so do a full update + FbTk::Menu::update(subj); + + } else + FbTk::Menu::update(subj); +}
A src/ClientMenu.hh

@@ -0,0 +1,60 @@

+// ClientMenu.hh +// Copyright (c) 2007 Fluxbox Team (fluxgen at fluxbox dot org) +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +// $Id$ + +#ifndef CLIENTMENU_HH +#define CLIENTMENU_HH + +#include <list> + +#include "FbMenu.hh" + +class BScreen; +class FluxboxWindow; +/** + * A menu holding a set of client menus. + * @see WorkspaceMenu + */ +class ClientMenu: public FbMenu { +public: + + typedef std::list<FluxboxWindow *> Focusables; + + /** + * @param screen the screen to show this menu on + * @param client a list of clients to show in this menu + * @param refresh the refresh subject to listen to + */ + ClientMenu(BScreen &screen, + Focusables &clients, FbTk::Subject *refresh); + +private: + /// refresh the entire menu + void refreshMenu(); + /// called when receiving a subject signal + void update(FbTk::Subject *subj); + + Focusables &m_list; ///< clients in the menu + FbTk::Subject *m_refresh_sig; ///< signal to listen to +}; + +#endif // CLIENTMENU_HH
M src/ClientPattern.ccsrc/ClientPattern.cc

@@ -24,7 +24,12 @@ // $Id$

#include "ClientPattern.hh" #include "RegExp.hh" + +#include "FocusControl.hh" +#include "Layer.hh" +#include "Screen.hh" #include "WinClient.hh" +#include "Workspace.hh" #include "FbTk/StringUtil.hh" #include "FbTk/App.hh"

@@ -73,54 +78,67 @@ property name is given, then CLASSNAME is assumed.

If no limit is specified, no limit is applied (i.e. limit = infinity) */ - int had_error = 0; + bool had_error = false; int pos = 0; string match; int err = 1; // for starting first loop - while (had_error == 0 && err > 0) { + while (!had_error && err > 0) { err = FbTk::StringUtil::getStringBetween(match, str + pos, '(', ')', " \t\n", true); if (err > 0) { - size_t eq = match.find_first_of('='); + // need to determine the property used + string memstr, expr; + WinProperty prop; + string::size_type eq = match.find_first_of('='); if (eq == match.npos) { - if (!addTerm(match, NAME)) { - had_error = pos + match.find_first_of('(') + 1; - break; - } + memstr = match; + expr = "[current]"; } else { - // need to determine the property used - string memstr, expr; - WinProperty prop; memstr.assign(match, 0, eq); // memstr = our identifier expr.assign(match, eq+1, match.length()); - if (strcasecmp(memstr.c_str(), "name") == 0) { - prop = NAME; - } else if (strcasecmp(memstr.c_str(), "class") == 0) { - prop = CLASS; - } else if (strcasecmp(memstr.c_str(), "title") == 0) { - prop = TITLE; - } else if (strcasecmp(memstr.c_str(), "role") == 0) { - prop = ROLE; - } else { - had_error = pos + match.find_first_of('(') + 1; - break; - } - if (!addTerm(expr, prop)) { - had_error = pos + ((str+pos) - index(str+pos, '=')) + 1; - break; - } } + if (strcasecmp(memstr.c_str(), "name") == 0) { + prop = NAME; + } else if (strcasecmp(memstr.c_str(), "class") == 0) { + prop = CLASS; + } else if (strcasecmp(memstr.c_str(), "title") == 0) { + prop = TITLE; + } else if (strcasecmp(memstr.c_str(), "role") == 0) { + prop = ROLE; + } else if (strcasecmp(memstr.c_str(), "maximized") == 0) { + prop = MAXIMIZED; + } else if (strcasecmp(memstr.c_str(), "minimized") == 0) { + prop = MINIMIZED; + } else if (strcasecmp(memstr.c_str(), "shaded") == 0) { + prop = SHADED; + } else if (strcasecmp(memstr.c_str(), "stuck") == 0) { + prop = STUCK; + } else if (strcasecmp(memstr.c_str(), "focushidden") == 0) { + prop = FOCUSHIDDEN; + } else if (strcasecmp(memstr.c_str(), "iconhidden") == 0) { + prop = ICONHIDDEN; + } else if (strcasecmp(memstr.c_str(), "workspace") == 0) { + prop = WORKSPACE; + } else if (strcasecmp(memstr.c_str(), "head") == 0) { + prop = HEAD; + } else if (strcasecmp(memstr.c_str(), "layer") == 0) { + prop = LAYER; + } else { + prop = NAME; + expr = match; + } + had_error = !addTerm(expr, prop); pos += err; } } - if (pos == 0 && had_error == 0) { + if (pos == 0 && !had_error) { // no match terms given, this is not allowed - had_error = 1; + had_error = true; } - if (had_error == 0) { + if (!had_error) { // otherwise, we check for a number string number; err = FbTk::StringUtil::getStringBetween(number,

@@ -139,12 +157,11 @@ size_t uerr;// need a special type here

uerr = match.find_first_not_of(" \t\n", pos); if (uerr != match.npos) { // found something, not good - had_error++; + had_error = true; } } - if (had_error > 0) { - m_matchlimit = had_error; + if (had_error) { // delete all the terms while (!m_terms.empty()) { Term * term = m_terms.back();

@@ -183,6 +200,34 @@ pat.append("title=");

break; case ROLE: pat.append("role="); + break; + case MAXIMIZED: + pat.append("maximized="); + break; + case MINIMIZED: + pat.append("minimized="); + break; + case SHADED: + pat.append("shaded="); + break; + case STUCK: + pat.append("stuck="); + break; + case FOCUSHIDDEN: + pat.append("focushidden="); + break; + case ICONHIDDEN: + pat.append("iconhidden="); + break; + case WORKSPACE: + pat.append("workspace="); + break; + case HEAD: + pat.append("head="); + break; + case LAYER: + pat.append("layer="); + break; } pat.append((*it)->orig);

@@ -198,9 +243,8 @@ return pat;

} // does this client match this pattern? -bool ClientPattern::match(const WinClient &win) const { - if (m_matchlimit != 0 && m_nummatches >= m_matchlimit || - m_terms.empty()) +bool ClientPattern::match(const Focusable &win) const { + if (m_matchlimit != 0 && m_nummatches >= m_matchlimit) return false; // already matched out // regmatch everything

@@ -209,7 +253,20 @@ // changing to OR would require minor modifications in this function only

Terms::const_iterator it = m_terms.begin(); Terms::const_iterator it_end = m_terms.end(); for (; it != it_end; ++it) { - if (!(*it)->regexp.match(getProperty((*it)->prop, win))) + if ((*it)->orig == "[current]") { + // workspaces don't necessarily have unique names, so we want to + // compare numbers instead of strings + if ((*it)->prop == WORKSPACE && (!win.fbwindow() || + win.fbwindow()->workspaceNumber() != + win.screen().currentWorkspaceID())) + return false; + else { + WinClient *focused = FocusControl::focusedWindow(); + if (!focused || getProperty((*it)->prop, win) != + getProperty((*it)->prop, *focused)) + return false; + } + } else if (!(*it)->regexp.match(getProperty((*it)->prop, win))) return false; } return true;

@@ -232,7 +289,11 @@ m_terms.push_back(term);

return true; } -string ClientPattern::getProperty(WinProperty prop, const WinClient &client) const { +string ClientPattern::getProperty(WinProperty prop, + const Focusable &client) const { + // we need this for some of the window properties + const FluxboxWindow *fbwin = client.fbwindow(); + switch (prop) { case TITLE: return client.title();

@@ -244,8 +305,44 @@ case NAME:

return client.getWMClassName(); break; case ROLE: - Atom wm_role = XInternAtom(FbTk::App::instance()->display(), "WM_WINDOW_ROLE", False); - return client.textProperty(wm_role); + return client.getWMRole(); + break; + case MAXIMIZED: + return (fbwin && fbwin->isMaximized()) ? "yes" : "no"; + break; + case MINIMIZED: + return (fbwin && fbwin->isIconic()) ? "yes" : "no"; + break; + case SHADED: + return (fbwin && fbwin->isShaded()) ? "yes" : "no"; + break; + case STUCK: + return (fbwin && fbwin->isStuck()) ? "yes" : "no"; + break; + case FOCUSHIDDEN: + return (fbwin && fbwin->isFocusHidden()) ? "yes" : "no"; + break; + case ICONHIDDEN: + return (fbwin && fbwin->isIconHidden()) ? "yes" : "no"; + break; + case WORKSPACE: { + if (!fbwin) + return ""; + const Workspace *w = client.screen().getWorkspace(fbwin->workspaceNumber()); + return w ? w->name() : ""; + break; + } + case HEAD: { + if (!fbwin) + return ""; + int head = client.screen().getHead(fbwin->fbWindow()); + char tmpstr[128]; + sprintf(tmpstr, "%d", head); + return std::string(tmpstr); + break; + } + case LAYER: + return fbwin ? ::Layer::getString(fbwin->layerNum()) : ""; break; } return client.getWMClassName();
M src/ClientPattern.hhsrc/ClientPattern.hh

@@ -32,7 +32,7 @@

#include <string> #include <list> -class WinClient; +class Focusable; /** * This class represents a "pattern" that we can match against a

@@ -53,10 +53,14 @@

/// @return a string representation of this pattern std::string toString() const; - enum WinProperty { TITLE, CLASS, NAME, ROLE }; + enum WinProperty { + TITLE, CLASS, NAME, ROLE, + MAXIMIZED, MINIMIZED, SHADED, STUCK, FOCUSHIDDEN, ICONHIDDEN, + WORKSPACE, HEAD, LAYER + }; /// Does this client match this pattern? - bool match(const WinClient &win) const; + bool match(const Focusable &win) const; /** * Add an expression to match against

@@ -68,7 +72,7 @@ bool addTerm(const std::string &str, WinProperty prop);

inline void addMatch() { ++m_nummatches; } - inline bool operator == (const WinClient &win) const { + inline bool operator == (const Focusable &win) const { return match(win); }

@@ -79,9 +83,9 @@ /**

* If there are no terms, then there is assumed to be an error * the column of the error is stored in m_matchlimit */ - inline int error() const { return m_terms.empty() ? m_matchlimit : 0; } + inline int error() const { return m_terms.empty() ? 1 : 0; } - std::string getProperty(WinProperty prop, const WinClient &winclient) const; + std::string getProperty(WinProperty prop, const Focusable &winclient) const; private: /**
M src/ClockTool.ccsrc/ClockTool.cc

@@ -220,12 +220,12 @@ void ClockTool::update(FbTk::Subject *subj) {

updateTime(); // + 2 to make the entire text fit inside - // we only replace numbers with zeros because everything else should be + // we only replace numbers with zeros because everything else should be // relatively static. If we replace all text with zeros then widths of // proportional fonts with some strftime formats will be considerably off. std::string text(m_button.text()); - int textlen = text.size(); + int textlen = text.size(); for (int i=0; i < textlen; ++i) { if (isdigit(text[i])) // don't bother replacing zeros text[i] = '0';
M src/ColSmartPlacement.ccsrc/ColSmartPlacement.cc

@@ -27,7 +27,7 @@ #include "Screen.hh"

#include "ScreenPlacement.hh" #include "Window.hh" -bool ColSmartPlacement::placeWindow(const std::vector<FluxboxWindow *> &windowlist, +bool ColSmartPlacement::placeWindow(const std::list<FluxboxWindow *> &windowlist, const FluxboxWindow &win, int &place_x, int &place_y) {

@@ -85,9 +85,9 @@ placed = true;

next_y = test_y + change_y; - std::vector<FluxboxWindow *>::const_iterator it = + std::list<FluxboxWindow *>::const_iterator it = windowlist.begin(); - std::vector<FluxboxWindow *>::const_iterator it_end = + std::list<FluxboxWindow *>::const_iterator it_end = windowlist.end(); for (; it != it_end && placed; ++it) { int curr_x = (*it)->x() - (*it)->xOffset();
M src/ColSmartPlacement.hhsrc/ColSmartPlacement.hh

@@ -28,7 +28,7 @@ #include "PlacementStrategy.hh"

class ColSmartPlacement: public PlacementStrategy { public: - bool placeWindow(const std::vector<FluxboxWindow *> &windowlist, + bool placeWindow(const std::list<FluxboxWindow *> &windowlist, const FluxboxWindow &win, int &place_x, int &place_y); };
M src/CommandDialog.ccsrc/CommandDialog.cc

@@ -98,7 +98,7 @@ Fluxbox::instance()->setShowingDialog(false);

// return focus to fluxbox window if (FocusControl::focusedFbWindow()) - FocusControl::focusedFbWindow()->setInputFocus(); + FocusControl::focusedFbWindow()->focus(); }

@@ -193,12 +193,12 @@ }

void CommandDialog::render() { Pixmap tmp = m_pixmap; - if (!m_screen.winFrameTheme().labelFocusTexture().usePixmap()) { - m_label.setBackgroundColor(m_screen.winFrameTheme().labelFocusTexture().color()); + if (!m_screen.winFrameTheme().iconbarTheme().focusedTexture().usePixmap()) { + m_label.setBackgroundColor(m_screen.winFrameTheme().iconbarTheme().focusedTexture().color()); m_pixmap = 0; } else { m_pixmap = m_screen.imageControl().renderImage(m_label.width(), m_label.height(), - m_screen.winFrameTheme().labelFocusTexture()); + m_screen.winFrameTheme().iconbarTheme().focusedTexture()); m_label.setBackgroundPixmap(m_pixmap); }

@@ -213,7 +213,7 @@

// setup label // we listen to motion notify too m_label.setEventMask(m_label.eventMask() | ButtonPressMask | ButtonMotionMask); - m_label.setGC(m_screen.winFrameTheme().labelTextFocusGC()); + m_label.setGC(m_screen.winFrameTheme().iconbarTheme().focusedText().textGC()); m_label.show(); // setup text box
M src/CommandDialog.hhsrc/CommandDialog.hh

@@ -34,14 +34,25 @@ #include "FbTk/RefCount.hh"

class BScreen; +/** + * Displays a fluxbox command dialog which executes fluxbox + * action commands. + */ class CommandDialog: public FbTk::FbWindow, public FbTk::EventHandler { public: CommandDialog(BScreen &screen, const std::string &title, const std::string pre_command = ""); virtual ~CommandDialog(); - + + /// Sets the entry text. void setText(const std::string &text); - void setPostCommand(FbTk::RefCount<FbTk::Command> &postcommand) { m_postcommand = postcommand; } + /** + * Sets the command to be execute after the command is done. + * @param postcommand the command. + */ + void setPostCommand(FbTk::RefCount<FbTk::Command> &postcommand) { + m_postcommand = postcommand; + } void show(); void hide();

@@ -52,6 +63,7 @@ void handleEvent(XEvent &event);

void keyPressEvent(XKeyEvent &event); protected: + /// expand the current word, using the history as a references virtual void tabComplete(); private:

@@ -59,8 +71,8 @@ void init();

void render(); void updateSizes(); - FbTk::TextBox m_textbox; - FbTk::TextButton m_label; + FbTk::TextBox m_textbox; //< entry field + FbTk::TextButton m_label; //< text in the titlebar FbTk::GContext m_gc; FbTk::RefCount<FbTk::Command> m_postcommand; ///< command to do after the first command was issued (like reconfigure) BScreen &m_screen;
M src/Container.ccsrc/Container.cc

@@ -36,7 +36,6 @@ m_orientation(FbTk::ROT0),

m_align(RELATIVE), m_max_size_per_client(60), m_max_total_size(0), - m_selected(0), m_update_lock(false) { FbTk::EventManager::instance()->add(*this, *this); }

@@ -215,9 +214,6 @@ ItemList::iterator it = m_item_list.begin();

for (; index != 0; ++it, --index) continue; - if (*it == selected()) - m_selected = 0; - m_item_list.erase(it); repositionItems();

@@ -225,7 +221,6 @@ return true;

} void Container::removeAll() { - m_selected = 0; m_item_list.clear(); if (!m_update_lock) { clear();

@@ -246,19 +241,6 @@ if (it == it_end)

return -1; return index; -} - -void Container::setSelected(int pos) { - if (pos < 0 || pos >= size()) - m_selected = 0; - else { - ItemList::iterator it = m_item_list.begin(); - for (; pos != 0; --pos, ++it) - continue; - m_selected = *it; - // caller does any graphics stuff if appropriate - } - } void Container::setMaxSizePerClient(unsigned int size) {
M src/Container.hhsrc/Container.hh

@@ -65,7 +65,6 @@ void removeAll();

void moveItem(Item item, int movement); // wraps around bool moveItemTo(Item item, int x, int y); int find(ConstItem item); - void setSelected(int index); void setMaxSizePerClient(unsigned int size); void setMaxTotalSize(unsigned int size); void setAlignment(Alignment a);

@@ -93,8 +92,6 @@ inline Alignment alignment() const { return m_align; }

inline FbTk::Orientation orientation() const { return m_orientation; } inline int size() const { return m_item_list.size(); } inline bool empty() const { return m_item_list.empty(); } - inline const Item& selected() const { return m_selected; } - inline Item selected() { return m_selected; } unsigned int maxWidthPerClient() const; inline bool updateLock() const { return m_update_lock; }

@@ -115,7 +112,6 @@ Alignment m_align;

unsigned int m_max_size_per_client; unsigned int m_max_total_size; ItemList m_item_list; - Item m_selected; bool m_update_lock; };
M src/CurrentWindowCmd.ccsrc/CurrentWindowCmd.cc

@@ -31,17 +31,24 @@ #include "WinClient.hh"

#include "FocusControl.hh" -CurrentWindowCmd::CurrentWindowCmd(Action act):m_action(act) { } +void WindowHelperCmd::execute() { + m_win = 0; + if (FocusControl::focusedFbWindow()) // guarantee that fbwindow() exists too + real_execute(); +} -void CurrentWindowCmd::execute() { - FluxboxWindow *win = FocusControl::focusedFbWindow(); - if (win) - (win->*m_action)(); +void WindowHelperCmd::execute(FluxboxWindow &win) { + m_win = &win; + real_execute(); } +FluxboxWindow &WindowHelperCmd::fbwindow() { + // will exist from execute above + return (m_win ? *m_win : *FocusControl::focusedFbWindow()); +} -void KillWindowCmd::real_execute() { - winclient().sendClose(true); +void CurrentWindowCmd::real_execute() { + (fbwindow().*m_action)(); } void SetHeadCmd::real_execute() {

@@ -54,13 +61,14 @@ }

void SendToNextWorkspaceCmd::real_execute() { const int ws_nr = - ( fbwindow().screen().currentWorkspaceID() + m_workspace_num ) % + ( fbwindow().workspaceNumber() + m_workspace_num ) % fbwindow().screen().numberOfWorkspaces(); fbwindow().screen().sendToWorkspace(ws_nr, &fbwindow(), false); } void SendToPrevWorkspaceCmd::real_execute() { - int ws_nr = fbwindow().screen().currentWorkspaceID() - m_workspace_num; + int ws_nr = (fbwindow().workspaceNumber() - m_workspace_num) % + fbwindow().screen().numberOfWorkspaces(); if ( ws_nr < 0 ) ws_nr += fbwindow().screen().numberOfWorkspaces(); fbwindow().screen().sendToWorkspace(ws_nr, &fbwindow(), false);

@@ -72,13 +80,14 @@ }

void TakeToNextWorkspaceCmd::real_execute() { unsigned int workspace_num= - ( fbwindow().screen().currentWorkspaceID() + m_workspace_num ) % + ( fbwindow().workspaceNumber() + m_workspace_num ) % fbwindow().screen().numberOfWorkspaces(); fbwindow().screen().sendToWorkspace(workspace_num, &fbwindow()); } void TakeToPrevWorkspaceCmd::real_execute() { - int workspace_num= fbwindow().screen().currentWorkspaceID() - m_workspace_num; + int workspace_num = (fbwindow().workspaceNumber() - m_workspace_num) % + fbwindow().screen().numberOfWorkspaces(); if ( workspace_num < 0 ) workspace_num += fbwindow().screen().numberOfWorkspaces(); fbwindow().screen().sendToWorkspace(workspace_num, &fbwindow());

@@ -95,21 +104,6 @@

while (--num > 0) ++it; (*it)->focus(); -} - -void WindowHelperCmd::execute() { - if (FocusControl::focusedFbWindow()) // guarantee that fbwindow() exists too - real_execute(); -} - -WinClient &WindowHelperCmd::winclient() { - // will exist from execute above - return *FocusControl::focusedWindow(); -} - -FluxboxWindow &WindowHelperCmd::fbwindow() { - // will exist from execute above - return *FocusControl::focusedFbWindow(); } MoveCmd::MoveCmd(const int step_size_x, const int step_size_y) :
M src/CurrentWindowCmd.hhsrc/CurrentWindowCmd.hh

@@ -28,36 +28,33 @@

#include "Command.hh" class FluxboxWindow; -class WinClient; - -/// command that calls FluxboxWindow::<the function> on execute() -/// similar to FbTk::SimpleCommand<T> -class CurrentWindowCmd: public FbTk::Command { -public: - typedef void (FluxboxWindow::* Action)(); - explicit CurrentWindowCmd(Action action); - void execute(); -private: - Action m_action; -}; /// helper class for window commands /// calls real_execute if there's a focused window or a window in button press/release window class WindowHelperCmd: public FbTk::Command { public: + explicit WindowHelperCmd(FluxboxWindow *win = 0): m_win(win) { } + void execute(); + void execute(FluxboxWindow &fbwin); protected: - - WinClient &winclient(); FluxboxWindow &fbwindow(); virtual void real_execute() = 0; +private: + FluxboxWindow *m_win; }; -class KillWindowCmd: public WindowHelperCmd { -protected: +/// command that calls FluxboxWindow::<the function> on execute() +/// similar to FbTk::SimpleCommand<T> +class CurrentWindowCmd: public WindowHelperCmd { +public: + typedef void (FluxboxWindow::* Action)(); + explicit CurrentWindowCmd(Action action): m_action(action) { } void real_execute(); +private: + Action m_action; }; class SetHeadCmd : public WindowHelperCmd {
M src/Ewmh.ccsrc/Ewmh.cc

@@ -28,7 +28,6 @@ #include "Window.hh"

#include "WinClient.hh" #include "Workspace.hh" #include "Layer.hh" -#include "WinClientUtil.hh" #include "fluxbox.hh" #include "FbWinFrameTheme.hh" #include "FocusControl.hh"

@@ -79,13 +78,6 @@ Ewmh::Ewmh() {

createAtoms(); } -Ewmh::~Ewmh() { - while (!m_windows.empty()) { - XDestroyWindow(FbTk::App::instance()->display(), m_windows.back()); - m_windows.pop_back(); - } -} - void Ewmh::initForScreen(BScreen &screen) { Display *disp = FbTk::App::instance()->display();

@@ -108,14 +100,9 @@ * or not properly set, clients SHOULD assume that no conforming

* Window Manager is present. */ - Window wincheck = XCreateSimpleWindow(disp, - screen.rootWindow().window(), - -10, -10, 5, 5, 0, 0, 0); + Window wincheck = screen.dummyWindow().window(); if (wincheck != None) { - // store the window so we can delete it later - m_windows.push_back(wincheck); - screen.rootWindow().changeProperty(m_net_supporting_wm_check, XA_WINDOW, 32, PropModeReplace, (unsigned char *) &wincheck, 1); XChangeProperty(disp, wincheck, m_net_supporting_wm_check, XA_WINDOW, 32,

@@ -278,7 +265,7 @@ if (atoms[l] == m_net_wm_window_type_dock) {

// we also assume it shouldn't be visible in any toolbar win.setFocusHidden(true); win.setIconHidden(true); - win.setDecoration(FluxboxWindow::DECOR_NONE); + win.setDecorationMask(FluxboxWindow::DECOR_NONE); win.moveToLayer(Layer::DOCK); } else if (atoms[l] == m_net_wm_window_type_desktop) { /*

@@ -291,7 +278,7 @@

win.setFocusHidden(true); win.setIconHidden(true); win.moveToLayer(Layer::DESKTOP); - win.setDecorationMask(0); + win.setDecorationMask(FluxboxWindow::DECOR_NONE); win.setTabable(false); win.setMovable(false); win.setResizable(false);

@@ -303,7 +290,7 @@ * _NET_WM_WINDOW_TYPE_SPLASH indicates that the

* window is a splash screen displayed as an application * is starting up. */ - win.setDecoration(FluxboxWindow::DECOR_NONE); + win.setDecorationMask(FluxboxWindow::DECOR_NONE); win.setFocusHidden(true); win.setIconHidden(true); win.setMovable(false);

@@ -320,11 +307,11 @@ * (i.e. toolbars and menus "torn off" from the main

* application). Windows of this type may set the * WM_TRANSIENT_FOR hint indicating the main application window. */ - win.setDecoration(FluxboxWindow::DECOR_TOOL); + win.setDecorationMask(FluxboxWindow::DECOR_TOOL); win.setIconHidden(true); win.moveToLayer(Layer::ABOVE_DOCK); } else if (atoms[l] == m_net_wm_window_type_toolbar) { - win.setDecoration(FluxboxWindow::DECOR_NONE); + win.setDecorationMask(FluxboxWindow::DECOR_NONE); win.setIconHidden(true); win.moveToLayer(Layer::ABOVE_DOCK); }

@@ -402,7 +389,10 @@ }

void Ewmh::updateClientList(BScreen &screen) { - list<WinClient *> creation_order_list = screen.focusControl().creationOrderList(); + if (screen.isShuttingdown()) + return; + + list<Focusable *> creation_order_list = screen.focusControl().creationOrderList(); size_t num = creation_order_list.size(); Window *wl = FB_new_nothrow Window[num];

@@ -414,10 +404,13 @@ return;

} int win=0; - list<WinClient *>::iterator client_it = creation_order_list.begin(); - list<WinClient *>::iterator client_it_end = creation_order_list.end(); - for (; client_it != client_it_end; ++client_it) - wl[win++] = (*client_it)->window(); + list<Focusable *>::iterator client_it = creation_order_list.begin(); + list<Focusable *>::iterator client_it_end = creation_order_list.end(); + for (; client_it != client_it_end; ++client_it) { + WinClient *client = dynamic_cast<WinClient *>(*client_it); + if (client) + wl[win++] = client->window(); + } /* From Extended Window Manager Hints, draft 1.3: *

@@ -800,32 +793,12 @@ if (winclient == 0)

return true; // ce.window = window to focus - if (winclient->fbwindow()) { - - FluxboxWindow* fbwin = winclient->fbwindow(); - - // if the raised window is on a different workspace - // we do what the user wish: - // either ignore|go to that workspace|get the window - if (fbwin->screen().currentWorkspaceID() != fbwin->workspaceNumber() - && !fbwin->isStuck()) { - BScreen::FollowModel model = (ce.data.l[0] == 2) ? - fbwin->screen().getUserFollowModel() : - fbwin->screen().getFollowModel(); - if (model == BScreen::FOLLOW_ACTIVE_WINDOW) { - fbwin->screen().changeWorkspaceID(fbwin->workspaceNumber()); - } else if (model == BScreen::FETCH_ACTIVE_WINDOW) { - fbwin->screen().sendToWorkspace(fbwin->screen().currentWorkspaceID(), fbwin); - } else if (model == BScreen::SEMIFOLLOW_ACTIVE_WINDOW) { - if (fbwin->isIconic()) - fbwin->screen().sendToWorkspace(fbwin->screen().currentWorkspaceID(), fbwin); - else - fbwin->screen().changeWorkspaceID(fbwin->workspaceNumber()); - } // else we ignore it. my favourite mode :) - } - fbwin->raise(); + // ce.data.l[0] == 2 means the request came from a pager + if (winclient->fbwindow() && (ce.data.l[0] == 2 || + winclient->fbwindow()->allowsFocusFromClient())) { + winclient->focus(); + winclient->fbwindow()->raise(); } - winclient->focus(); return true; } else if (ce.message_type == m_net_close_window) { if (winclient == 0)

@@ -1203,7 +1176,7 @@ if (win.isIconifiable())

actions.push_back(m_net_wm_action_minimize); unsigned int max_width, max_height; - WinClientUtil::maxSize(win.clientList(), max_width, max_height); + win.maxSize(max_width, max_height); // if unlimited max width we can maximize horizontal if (max_width == 0) {
M src/Ewmh.hhsrc/Ewmh.hh

@@ -34,7 +34,6 @@ class Ewmh:public AtomHandler {

public: Ewmh(); - ~Ewmh(); void initForScreen(BScreen &screen); void setupFrame(FluxboxWindow &win); void setupClient(WinClient &winclient);

@@ -144,8 +143,6 @@ // application protocols

Atom m_net_wm_ping; Atom utf8_string; - - std::vector<Window> m_windows; FbTk::FbString getUTF8Property(Atom property); };
M src/FbAtoms.ccsrc/FbAtoms.cc

@@ -60,35 +60,6 @@ xa_wm_delete_window = XInternAtom(display, "WM_DELETE_WINDOW", False);

xa_wm_take_focus = XInternAtom(display, "WM_TAKE_FOCUS", False); motif_wm_hints = XInternAtom(display, "_MOTIF_WM_HINTS", False); - blackbox_hints = XInternAtom(display, "_BLACKBOX_HINTS", False); blackbox_attributes = XInternAtom(display, "_BLACKBOX_ATTRIBUTES", False); - blackbox_change_attributes = - XInternAtom(display, "_BLACKBOX_CHANGE_ATTRIBUTES", False); - - blackbox_structure_messages = - XInternAtom(display, "_BLACKBOX_STRUCTURE_MESSAGES", False); - blackbox_notify_startup = - XInternAtom(display, "_BLACKBOX_NOTIFY_STARTUP", False); - blackbox_notify_window_add = - XInternAtom(display, "_BLACKBOX_NOTIFY_WINDOW_ADD", False); - blackbox_notify_window_del = - XInternAtom(display, "_BLACKBOX_NOTIFY_WINDOW_DEL", False); - blackbox_notify_current_workspace = - XInternAtom(display, "_BLACKBOX_NOTIFY_CURRENT_WORKSPACE", False); - blackbox_notify_workspace_count = - XInternAtom(display, "_BLACKBOX_NOTIFY_WORKSPACE_COUNT", False); - blackbox_notify_window_focus = - XInternAtom(display, "_BLACKBOX_NOTIFY_WINDOW_FOCUS", False); - blackbox_notify_window_raise = - XInternAtom(display, "_BLACKBOX_NOTIFY_WINDOW_RAISE", False); - blackbox_notify_window_lower = - XInternAtom(display, "_BLACKBOX_NOTIFY_WINDOW_LOWER", False); - - blackbox_change_workspace = - XInternAtom(display, "_BLACKBOX_CHANGE_WORKSPACE", False); - blackbox_change_window_focus = - XInternAtom(display, "_BLACKBOX_CHANGE_WINDOW_FOCUS", False); - blackbox_cycle_window_focus = - XInternAtom(display, "_BLACKBOX_CYCLE_WINDOW_FOCUS", False); }
M src/FbAtoms.hhsrc/FbAtoms.hh

@@ -40,56 +40,17 @@ inline Atom getWMDeleteAtom() const { return xa_wm_delete_window; }

inline Atom getWMProtocolsAtom() const { return xa_wm_protocols; } inline Atom getWMTakeFocusAtom() const { return xa_wm_take_focus; } - // this atom is for normal app->WM hints about decorations, stacking, - // starting workspace etc... - inline Atom getFluxboxHintsAtom() const { return blackbox_hints;} inline Atom getMWMHintsAtom() const { return motif_wm_hints; } // these atoms are for normal app->WM interaction beyond the scope of the // ICCCM... inline Atom getFluxboxAttributesAtom() const { return blackbox_attributes; } - inline Atom getFluxboxChangeAttributesAtom() const { return blackbox_change_attributes; } - - // these atoms are for window->WM interaction, with more control and - // information on window "structure"... common examples are - // notifying apps when windows are raised/lowered... when the user changes - // workspaces... i.e. "pager talk" - inline Atom getFluxboxStructureMessagesAtom() const{ return blackbox_structure_messages; } - - // *Notify* portions of the NETStructureMessages protocol - inline Atom getFluxboxNotifyStartupAtom() const { return blackbox_notify_startup; } - inline Atom getFluxboxNotifyWindowAddAtom() const { return blackbox_notify_window_add; } - inline Atom getFluxboxNotifyWindowDelAtom() const { return blackbox_notify_window_del; } - inline Atom getFluxboxNotifyWindowFocusAtom() const { return blackbox_notify_window_focus; } - inline Atom getFluxboxNotifyCurrentWorkspaceAtom() const { return blackbox_notify_current_workspace; } - inline Atom getFluxboxNotifyWorkspaceCountAtom() const { return blackbox_notify_workspace_count; } - inline Atom getFluxboxNotifyWindowRaiseAtom() const { return blackbox_notify_window_raise; } - inline Atom getFluxboxNotifyWindowLowerAtom() const { return blackbox_notify_window_lower; } - - // atoms to change that request changes to the desktop environment during - // runtime... these messages can be sent by any client... as the sending - // client window id is not included in the ClientMessage event... - inline Atom getFluxboxChangeWorkspaceAtom() const { return blackbox_change_workspace; } - inline Atom getFluxboxChangeWindowFocusAtom() const { return blackbox_change_window_focus; } - inline Atom getFluxboxCycleWindowFocusAtom() const { return blackbox_cycle_window_focus; } private: void initAtoms(); // NETAttributes - Atom blackbox_attributes, blackbox_change_attributes, blackbox_hints; - + Atom blackbox_attributes; Atom motif_wm_hints; - - // NETStructureMessages - Atom blackbox_structure_messages, blackbox_notify_startup, - blackbox_notify_window_add, blackbox_notify_window_del, - blackbox_notify_window_focus, blackbox_notify_current_workspace, - blackbox_notify_workspace_count, blackbox_notify_window_raise, - blackbox_notify_window_lower; - - // message_types for client -> wm messages - Atom blackbox_change_workspace, blackbox_change_window_focus, - blackbox_cycle_window_focus; Atom xa_wm_protocols, xa_wm_state, xa_wm_delete_window, xa_wm_take_focus, xa_wm_change_state;
M src/FbCommandFactory.ccsrc/FbCommandFactory.cc

@@ -52,17 +52,43 @@

// autoregister this module to command parser FbCommandFactory FbCommandFactory::s_autoreg; +namespace { + static int getint(const char *str, int defaultvalue) { sscanf(str, "%d", &defaultvalue); return defaultvalue; } +void parseNextWindowArgs(const string &in, int &opts, string &pat) { + string options; + int err = FbTk::StringUtil::getStringBetween(options, in.c_str(), '{', '}'); + + // the rest of the string is a ClientPattern + pat = in.c_str() + err; + + // now parse the options + vector<string> args; + FbTk::StringUtil::stringtok(args, options); + vector<string>::iterator it = args.begin(), it_end = args.end(); + opts = 0; + for (; it != it_end; ++it) { + if (strcasecmp((*it).c_str(), "static") == 0) + opts |= FocusControl::CYCLELINEAR; + else if (strcasecmp((*it).c_str(), "groups") == 0) + opts |= FocusControl::CYCLEGROUPS; + } +} + +}; // end anonymous namespace + FbCommandFactory::FbCommandFactory() { // setup commands that we can handle const char* commands[] = { - "addworkspace", + "addworkspace", "arrangewindows", + "attach", "bindkey", + "clientmenu", "close", "closeallwindows", "commanddialog",

@@ -79,6 +105,7 @@ "focusdown",

"focusleft", "focusright", "fullscreen", + "gotowindow", "hidemenus", "iconify", "keymode",

@@ -116,7 +143,7 @@ "raiselayer",

"reconfig", "reconfigure", "reloadstyle", - "removelastworkspace", + "removelastworkspace", "resizeto", "resize", "resizehorizontal",

@@ -148,6 +175,7 @@ "taketonextworkspace",

"taketoprevworkspace", "togglecmd", "toggledecor", + "typeaheadfocus", "windowmenu", "workspace", /* NOTE: The following are DEPRECATED and subject to removal */

@@ -243,21 +271,15 @@ //

// Current focused window commands // else if (command == "fullscreen") - return new FullscreenCmd(); - else if (command == "minimizewindow" || command == "minimize" || command == "iconify") { - string cmd; - if (FbTk::StringUtil::getStringBetween(cmd, arguments.c_str() + - 0, '(', ')', " \t\n", true) - && cmd == "layer") - return new MinimizeLayerCmd(); - else - return new CurrentWindowCmd(&FluxboxWindow::iconify); - } else if (command == "maximizewindow" || command == "maximize") - return new CurrentWindowCmd(&FluxboxWindow::maximizeFull); + return new WindowListCmd(FbTk::RefCount<WindowHelperCmd>(new FullscreenCmd()), arguments); + else if (command == "minimizewindow" || command == "minimize" || command == "iconify") + return new WindowListCmd(FbTk::RefCount<WindowHelperCmd>(new CurrentWindowCmd(&FluxboxWindow::iconify)), arguments); + else if (command == "maximizewindow" || command == "maximize") + return new WindowListCmd(FbTk::RefCount<WindowHelperCmd>(new CurrentWindowCmd(&FluxboxWindow::maximizeFull)), arguments); else if (command == "maximizevertical") - return new CurrentWindowCmd(&FluxboxWindow::maximizeVertical); + return new WindowListCmd(FbTk::RefCount<WindowHelperCmd>(new CurrentWindowCmd(&FluxboxWindow::maximizeVertical)), arguments); else if (command == "maximizehorizontal") - return new CurrentWindowCmd(&FluxboxWindow::maximizeHorizontal); + return new WindowListCmd(FbTk::RefCount<WindowHelperCmd>(new CurrentWindowCmd(&FluxboxWindow::maximizeHorizontal)), arguments); else if (command == "setalpha") { typedef vector<string> StringTokens; StringTokens tokens;

@@ -279,24 +301,37 @@ un_rel = (tokens[1][0] == '+' || tokens[1][0] == '-');

unfocused = atoi(tokens[1].c_str()); } - return new SetAlphaCmd(focused, relative, unfocused, un_rel); - } else if (command == "resize") { + string pat; + string::size_type pos = arguments.find('('); + if (pos != string::npos && pos != arguments.size()) + pat = arguments.c_str() + pos; + + return new WindowListCmd(FbTk::RefCount<WindowHelperCmd>(new SetAlphaCmd(focused, relative, unfocused, un_rel)), pat); + } else if (command == "resize" || command == "resizeto" || + command == "resizehorizontal" || command == "resizevertical") { FbTk_istringstream is(arguments.c_str()); int dx = 0, dy = 0; is >> dx >> dy; - return new ResizeCmd(dx, dy); - } - else if (command == "resizeto") { - FbTk_istringstream is(arguments.c_str()); - int dx = 0, dy = 0; - is >> dx >> dy; - return new ResizeToCmd(dx, dy); - } - else if (command == "resizehorizontal") - return new ResizeCmd(atoi(arguments.c_str()),0); - else if (command == "resizevertical") - return new ResizeCmd(0,atoi(arguments.c_str())); - else if (command == "moveto") { + if (command == "resizehorizontal") + dy = 0; + else if (command == "resizevertical") { + dy = dx; + dx = 0; + } + + string pat; + string::size_type pos = arguments.find('('); + if (pos != string::npos && pos != arguments.size()) + pat = arguments.c_str() + pos; + + FbTk::RefCount<WindowHelperCmd> cmd; + if (command == "resizeto") + cmd = new ResizeToCmd(dx, dy); + else + cmd = new ResizeCmd(dx, dy); + + return new WindowListCmd(cmd, pat); + } else if (command == "moveto") { typedef vector<string> StringTokens; StringTokens tokens; FbTk::StringUtil::stringtok<StringTokens>(tokens, arguments);

@@ -339,70 +374,107 @@ refc &= ~MoveToCmd::UPPER;

} } - return new MoveToCmd(dx, dy, refc); - } - else if (command == "move") { + string pat; + string::size_type pos = arguments.find('('); + if (pos != string::npos && pos != arguments.size()) + pat = arguments.c_str() + pos; + + return new WindowListCmd(FbTk::RefCount<WindowHelperCmd>(new MoveToCmd(dx, dy, refc)), pat); + } else if (command == "move" || command == "moveright" || + command == "moveleft" || command == "moveup" || + command == "movedown") { FbTk_istringstream is(arguments.c_str()); int dx = 0, dy = 0; is >> dx >> dy; - return new MoveCmd(dx, dy); - } - else if (command == "moveright") - return new MoveCmd(atoi(arguments.c_str()),0); - else if (command == "moveleft") - return new MoveCmd(-atoi(arguments.c_str()),0); - else if (command == "moveup") - return new MoveCmd(0,-atoi(arguments.c_str())); - else if (command == "movedown") - return new MoveCmd(0,atoi(arguments.c_str())); - else if (command == "raise") - return new CurrentWindowCmd(&FluxboxWindow::raise); + + if (command == "moveright") + dy = 0; + else if (command == "moveleft") { + dy = 0; + dx = -dx; + } else if (command == "movedown") { + dy = dx; + dx = 0; + } else if (command == "moveup") { + dy = -dx; + dx = 0; + } + + string pat; + string::size_type pos = arguments.find('('); + if (pos != string::npos && pos != arguments.size()) + pat = arguments.c_str() + pos; + + return new WindowListCmd(FbTk::RefCount<WindowHelperCmd>(new MoveCmd(dx, dy)), pat); + } else if (command == "raise") + return new WindowListCmd(FbTk::RefCount<WindowHelperCmd>(new CurrentWindowCmd(&FluxboxWindow::raise)), arguments); else if (command == "raiselayer") - return new CurrentWindowCmd(&FluxboxWindow::raiseLayer); + return new WindowListCmd(FbTk::RefCount<WindowHelperCmd>(new CurrentWindowCmd(&FluxboxWindow::raiseLayer)), arguments); else if (command == "lower") - return new CurrentWindowCmd(&FluxboxWindow::lower); + return new WindowListCmd(FbTk::RefCount<WindowHelperCmd>(new CurrentWindowCmd(&FluxboxWindow::lower)), arguments); else if (command == "lowerlayer") - return new CurrentWindowCmd(&FluxboxWindow::lowerLayer); + return new WindowListCmd(FbTk::RefCount<WindowHelperCmd>(new CurrentWindowCmd(&FluxboxWindow::lowerLayer)), arguments); else if (command == "close") - return new CurrentWindowCmd(&FluxboxWindow::close); + return new WindowListCmd(FbTk::RefCount<WindowHelperCmd>(new CurrentWindowCmd(&FluxboxWindow::close)), arguments); else if (command == "closeallwindows") return new CloseAllWindowsCmd(); + else if (command == "killwindow" || command == "kill") + return new WindowListCmd(FbTk::RefCount<WindowHelperCmd>(new CurrentWindowCmd(&FluxboxWindow::kill)), arguments); else if (command == "shade" || command == "shadewindow") - return new CurrentWindowCmd(&FluxboxWindow::shade); + return new WindowListCmd(FbTk::RefCount<WindowHelperCmd>(new CurrentWindowCmd(&FluxboxWindow::shade)), arguments); else if (command == "stick" || command == "stickwindow") - return new CurrentWindowCmd(&FluxboxWindow::stick); + return new WindowListCmd(FbTk::RefCount<WindowHelperCmd>(new CurrentWindowCmd(&FluxboxWindow::stick)), arguments); else if (command == "toggledecor") - return new CurrentWindowCmd(&FluxboxWindow::toggleDecoration); - else if (command == "sethead") - return new SetHeadCmd(atoi(arguments.c_str())); - else if (command == "sendtoworkspace") + return new WindowListCmd(FbTk::RefCount<WindowHelperCmd>(new CurrentWindowCmd(&FluxboxWindow::toggleDecoration)), arguments); + else if (command == "sethead") { + int num = 0; + string pat; + FbTk_istringstream iss(arguments.c_str()); + iss >> num; + string::size_type pos = arguments.find('('); + if (pos != string::npos && pos != arguments.size()) + pat = arguments.c_str() + pos; + return new WindowListCmd(FbTk::RefCount<WindowHelperCmd>(new SetHeadCmd(num)), pat); + } else if (command == "tab" || command == "sendtonextworkspace" || + command == "sendtoprevworkspace" || + command == "taketonextworkspace" || + command == "taketoprevworkspace" || + command == "sendtoworkspace" || command == "taketoworkspace") { // workspaces appear 1-indexed to the user, hence the minus 1 - return new SendToWorkspaceCmd(getint(arguments.c_str(), 1) - 1); - else if (command == "sendtonextworkspace") - return new SendToNextWorkspaceCmd(getint(arguments.c_str(), 1)); - else if (command == "sendtoprevworkspace") - return new SendToPrevWorkspaceCmd(getint(arguments.c_str(), 1)); - else if (command == "taketoworkspace") - // workspaces appear 1-indexed to the user, hence the minus 1 - return new TakeToWorkspaceCmd(getint(arguments.c_str(), 1) - 1); - else if (command == "taketonextworkspace") - return new TakeToNextWorkspaceCmd(getint(arguments.c_str(), 1)); - else if (command == "taketoprevworkspace") - return new TakeToPrevWorkspaceCmd(getint(arguments.c_str(), 1)); - else if (command == "killwindow" || command == "kill") - return new KillWindowCmd(); - else if (command == "tab") - return new GoToTabCmd(getint(arguments.c_str(), 1)); - else if (command == "nexttab") - return new CurrentWindowCmd(&FluxboxWindow::nextClient); + int num = 1; + string pat; + FbTk_istringstream iss(arguments.c_str()); + iss >> num; + string::size_type pos = arguments.find('('); + if (pos != string::npos && pos != arguments.size()) + pat = arguments.c_str() + pos; + FbTk::RefCount<WindowHelperCmd> cmd; + + if (command == "tab") + cmd = new GoToTabCmd(num); + else if (command == "sendtonextworkspace") + cmd = new SendToNextWorkspaceCmd(num); + else if (command == "sendtoprevworkspace") + cmd = new SendToPrevWorkspaceCmd(num); + else if (command == "taketonextworkspace") + cmd = new TakeToNextWorkspaceCmd(num); + else if (command == "taketoprevworkspace") + cmd = new TakeToPrevWorkspaceCmd(num); + else if (command == "sendtoworkspace") + cmd = new SendToWorkspaceCmd(num-1); + else + cmd = new TakeToWorkspaceCmd(num-1); + return new WindowListCmd(cmd, pat); + } else if (command == "nexttab") + return new WindowListCmd(FbTk::RefCount<WindowHelperCmd>(new CurrentWindowCmd(&FluxboxWindow::nextClient)), arguments); else if (command == "prevtab") - return new CurrentWindowCmd(&FluxboxWindow::prevClient); + return new WindowListCmd(FbTk::RefCount<WindowHelperCmd>(new CurrentWindowCmd(&FluxboxWindow::prevClient)), arguments); else if (command == "movetableft") - return new CurrentWindowCmd(&FluxboxWindow::moveClientLeft); + return new WindowListCmd(FbTk::RefCount<WindowHelperCmd>(new CurrentWindowCmd(&FluxboxWindow::moveClientLeft)), arguments); else if (command == "movetabright") - return new CurrentWindowCmd(&FluxboxWindow::moveClientRight); + return new WindowListCmd(FbTk::RefCount<WindowHelperCmd>(new CurrentWindowCmd(&FluxboxWindow::moveClientRight)), arguments); else if (command == "detachclient") - return new CurrentWindowCmd(&FluxboxWindow::detachCurrentClient); + return new WindowListCmd(FbTk::RefCount<WindowHelperCmd>(new CurrentWindowCmd(&FluxboxWindow::detachCurrentClient)), arguments); else if (command == "windowmenu") return new CurrentWindowCmd(&FluxboxWindow::popupMenu); //

@@ -423,11 +495,54 @@ else if (command.substr(0, 9) == "workspace" && command[9] >= '0' && command[9] <= '9') {

cerr<<"*** WARNING: 'Workspace<n>' actions are deprecated! Use 'Workspace <n>' instead"<<endl; return new JumpToWorkspaceCmd(getint(command.substr(9).c_str(), 1) - 1); - } else if (command == "nextwindow") - return new NextWindowCmd(atoi(arguments.c_str())); - else if (command == "prevwindow") - return new PrevWindowCmd(atoi(arguments.c_str())); - else if (command == "focusup") + } else if (command == "attach") { + int opts; // not used + string pat; + parseNextWindowArgs(arguments, opts, pat); + return new AttachCmd(pat); + } else if (command == "nextwindow") { + int opts; + string pat; + parseNextWindowArgs(arguments, opts, pat); + return new NextWindowCmd(opts, pat); + } else if (command == "nextgroup") { + int opts; + string pat; + parseNextWindowArgs(arguments, opts, pat); + opts |= FocusControl::CYCLEGROUPS; + return new NextWindowCmd(opts, pat); + } else if (command == "prevwindow") { + int opts; + string pat; + parseNextWindowArgs(arguments, opts, pat); + return new PrevWindowCmd(opts, pat); + } else if (command == "prevgroup") { + int opts; + string pat; + parseNextWindowArgs(arguments, opts, pat); + opts |= FocusControl::CYCLEGROUPS; + return new PrevWindowCmd(opts, pat); + } else if (command == "typeaheadfocus") { + int opts; + string pat; + parseNextWindowArgs(arguments, opts, pat); + return new TypeAheadFocusCmd(opts, pat); + } else if (command == "gotowindow") { + int num, opts; + string args, pat; + FbTk_istringstream iss(arguments.c_str()); + iss >> num; + string::size_type pos = arguments.find_first_of("({"); + if (pos != string::npos && pos != arguments.size()) + args = arguments.c_str() + pos; + parseNextWindowArgs(args, opts, pat); + return new GoToWindowCmd(num, opts, pat); + } else if (command == "clientmenu") { + int opts; + string pat; + parseNextWindowArgs(arguments, opts, pat); + return new ShowClientMenuCmd(opts, pat); + } else if (command == "focusup") return new DirFocusCmd(FocusControl::FOCUSUP); else if (command == "focusdown") return new DirFocusCmd(FocusControl::FOCUSDOWN);

@@ -435,10 +550,6 @@ else if (command == "focusleft")

return new DirFocusCmd(FocusControl::FOCUSLEFT); else if (command == "focusright") return new DirFocusCmd(FocusControl::FOCUSRIGHT); - else if (command == "nextgroup") - return new NextWindowCmd(atoi(arguments.c_str()) ^ FocusControl::CYCLEGROUPS); - else if (command == "prevgroup") - return new PrevWindowCmd(atoi(arguments.c_str()) ^ FocusControl::CYCLEGROUPS); else if (command == "arrangewindows") return new ArrangeWindowsCmd(); else if (command == "showdesktop")
M src/FbCommands.ccsrc/FbCommands.cc

@@ -25,6 +25,7 @@ #include "FbCommands.hh"

#include "fluxbox.hh" #include "Screen.hh" #include "CommandDialog.hh" +#include "FocusControl.hh" #include "Workspace.hh" #include "Window.hh" #include "Keys.hh"

@@ -277,6 +278,35 @@ if (screen->workspaceMenu().isVisible())

screen->workspaceMenu().hide(); if (FbTk::Menu::shownMenu()) FbTk::Menu::shownMenu()->hide(); +} + +void ShowClientMenuCmd::execute() { + BScreen *screen = Fluxbox::instance()->mouseScreen(); + if (screen == 0) + return; + + // TODO: ClientMenu only accepts lists of FluxboxWindows for now + FocusControl::Focusables *win_list = 0; +// if (m_option & FocusControl::CYCLEGROUPS) { + win_list = (m_option & FocusControl::CYCLELINEAR) ? + &screen->focusControl().creationOrderWinList() : + &screen->focusControl().focusedOrderWinList(); +/* } else { + win_list = (m_option & FocusControl::CYCLELINEAR) ? + &screen->focusControl().creationOrderList() : + &screen->focusControl().focusedOrderList(); + } */ + + m_list.clear(); + FocusControl::Focusables::iterator it = win_list->begin(), + it_end = win_list->end(); + for (; it != it_end; ++it) { + if (typeid(**it) == typeid(FluxboxWindow) && m_pat.match(**it)) + m_list.push_back(static_cast<FluxboxWindow *>(*it)); + } + + m_menu = new ClientMenu(*screen, m_list, 0); + ::showMenu(*screen, **m_menu); } ShowCustomMenuCmd::ShowCustomMenuCmd(const string &arguments) : custom_menu_file(arguments) {}
M src/FbCommands.hhsrc/FbCommands.hh

@@ -29,8 +29,10 @@

#include "Command.hh" #include "FbTk/RefCount.hh" -#include "FbTk/Menu.hh" +#include "ClientMenu.hh" +#include "ClientPattern.hh" +#include <list> #include <string> namespace FbCommands {

@@ -119,6 +121,18 @@

class HideMenuCmd: public FbTk::Command { public: void execute(); +}; + +class ShowClientMenuCmd: public FbTk::Command { +public: + ShowClientMenuCmd(int option, std::string &pat): + m_option(option), m_pat(pat.c_str()) { } + void execute(); +private: + const int m_option; + const ClientPattern m_pat; + std::list<FluxboxWindow *> m_list; + FbTk::RefCount<ClientMenu> m_menu; }; class ShowCustomMenuCmd: public FbTk::Command {
M src/FbTk/ITypeAheadable.hhsrc/FbTk/ITypeAheadable.hh

@@ -19,6 +19,8 @@ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING

// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. +// $Id$ + #ifndef FBTK_ITYPEAHEADABLE_HH #define FBTK_ITYPEAHEADABLE_HH
M src/FbTk/Makefile.amsrc/FbTk/Makefile.am

@@ -49,7 +49,6 @@ TextBox.hh TextBox.cc \

GContext.hh GContext.cc \ KeyUtil.hh KeyUtil.cc \ MenuSeparator.hh MenuSeparator.cc \ - MenuIcon.hh MenuIcon.cc \ stringstream.hh \ TypeAhead.hh SearchResult.hh SearchResult.cc ITypeAheadable.hh \ Select2nd.hh \
M src/FbTk/Menu.ccsrc/FbTk/Menu.cc

@@ -357,10 +357,6 @@ submenu->m_active_index = -1; // so we land on 0 after nextItem()

submenu->cycleItems(false); } -void Menu::enterParent() { - internal_hide(); -} - void Menu::disableTitle() { setTitleVisibility(false); }

@@ -1033,7 +1029,7 @@ cycleItems(false);

break; case XK_Left: // enter parent if we have one resetTypeAhead(); - enterParent(); + internal_hide(); break; case XK_Right: // enter submenu if we have one resetTypeAhead();

@@ -1046,7 +1042,7 @@ hide();

break; case XK_BackSpace: if (m_type_ahead.stringSize() == 0) { - enterParent(); + internal_hide(); break; }
M src/FbTk/Menu.hhsrc/FbTk/Menu.hh

@@ -49,7 +49,8 @@ class MenuItem;

class ImageControl; /// Base class for menus -class Menu: public FbTk::EventHandler, FbTk::FbWindowRenderer, protected FbTk::Observer { +class Menu: public FbTk::EventHandler, FbTk::FbWindowRenderer, + public FbTk::Observer { public: enum Alignment{ ALIGNDONTCARE = 1, ALIGNTOP, ALIGNBOTTOM }; enum { RIGHT = 1, LEFT };

@@ -91,7 +92,6 @@ virtual void lower();

/// cycle through menuitems void cycleItems(bool reverse); void enterSubmenu(); - void enterParent(); void disableTitle(); void enableTitle();

@@ -193,7 +193,7 @@ virtual void redrawFrame(FbDrawable &pm);

virtual void internal_hide(bool first = true); - void update(FbTk::Subject *); + virtual void update(FbTk::Subject *); private:
D src/FbTk/MenuIcon.cc

@@ -1,96 +0,0 @@

-// MenuIcon.cc for FbTk - Fluxbox ToolKit -// Copyright (c) 2004 - 2006 Henrik Kinnunen (fluxgen at fluxbox dot org) -// and Simon Bowden (rathnor at users.sourceforge.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -// $Id$ - -#include "MenuIcon.hh" - -#include "MenuTheme.hh" -#include "Image.hh" -#include "App.hh" - -namespace FbTk { - -MenuIcon::MenuIcon(const std::string &filename, FbString &label, int screen_num): - MenuItem(label), - m_filename(filename) { - FbTk::PixmapWithMask *pm = Image::load(filename.c_str(), screen_num); - if (pm != 0) { - m_pixmap = pm->pixmap().release(); - m_mask = pm->mask().release(); - delete pm; - } - -} - -void MenuIcon::updateTheme(const MenuTheme &theme) { - FbTk::PixmapWithMask *pm = Image::load(m_filename.c_str(), theme.screenNum()); - if (pm != 0) { - m_pixmap = pm->pixmap().release(); - m_mask = pm->mask().release(); - delete pm; - } -} - -void MenuIcon::draw(FbDrawable &drawable, - const MenuTheme &theme, - bool highlight, bool draw_foreground, bool draw_background, - int x, int y, - unsigned int width, unsigned int height) const { - - // all background - if (draw_background) { - Display *disp = FbTk::App::instance()->display(); - if (height - 2*theme.bevelWidth() != m_pixmap.height() && - !m_filename.empty()) { - unsigned int scale_size = height - 2*theme.bevelWidth(); - m_pixmap.scale(scale_size, scale_size); - m_mask.scale(scale_size, scale_size); - } - - if (m_pixmap.drawable() != 0) { - GC gc = theme.frameTextGC().gc(); - - // enable clip mask - XSetClipMask(disp, gc, m_mask.drawable()); - XSetClipOrigin(disp, gc, x + theme.bevelWidth(), y + theme.bevelWidth()); - - drawable.copyArea(m_pixmap.drawable(), - gc, - 0, 0, - x + theme.bevelWidth(), y + theme.bevelWidth(), - m_pixmap.width(), m_pixmap.height()); - - // restore clip mask - XSetClipMask(disp, gc, None); - } - } - FbTk::MenuItem::draw(drawable, theme, highlight, - draw_background, draw_foreground, x, y, width, height); -} - -unsigned int MenuIcon::width(const MenuTheme &theme) const { - return MenuItem::width(theme) + 2 * (theme.bevelWidth() + height(theme)); -} - -} // end namespace FbTk -
D src/FbTk/MenuIcon.hh

@@ -1,54 +0,0 @@

-// MenuIcon.hh for FbTk - Fluxbox ToolKit -// Copyright (c) 2004 Henrik Kinnunen (fluxgen at fluxbox dot org) -// and Simon Bowden (rathnor at users.sourceforge.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -// $Id$ - -#ifndef MENUICON_HH -#define MENUICON_HH - -#include "MenuItem.hh" -#include "FbPixmap.hh" - -#include <string> - -namespace FbTk { - -class MenuIcon: public MenuItem { -public: - MenuIcon(const std::string &filename, FbString &label, int screen_num); - void draw(FbDrawable &drawable, - const MenuTheme &theme, - bool highlight, - bool draw_foreground, bool draw_background, - int x, int y, - unsigned int width, unsigned int height) const; - unsigned int width(const MenuTheme &item) const; - void updateTheme(const MenuTheme &theme); -private: - mutable FbPixmap m_pixmap, m_mask; - const std::string m_filename; -}; - -} // end namespace FbTk - -#endif // MENUICON_HH -
M src/FbTk/MenuItem.ccsrc/FbTk/MenuItem.cc

@@ -93,27 +93,32 @@ //

// Icon // if (draw_background) { - if (m_icon.get() != 0 && m_icon->pixmap.get() != 0) { + if (icon() != 0) { + // copy pixmap, so we don't resize the original + FbPixmap tmp_pixmap, tmp_mask; + tmp_pixmap.copy(icon()->pixmap()); + tmp_mask.copy(icon()->mask()); + // scale pixmap to right size - if (height - 2*theme.bevelWidth() != m_icon->pixmap->height() && - !m_icon->filename.empty()) { + if (height - 2*theme.bevelWidth() != tmp_pixmap.height()) { unsigned int scale_size = height - 2*theme.bevelWidth(); - m_icon->pixmap->scale(scale_size, scale_size); + tmp_pixmap.scale(scale_size, scale_size); + tmp_mask.scale(scale_size, scale_size); } - if (m_icon->pixmap->pixmap().drawable() != 0) { + if (tmp_pixmap.drawable() != 0) { GC gc = theme.frameTextGC().gc(); int icon_x = x + theme.bevelWidth(); int icon_y = y + theme.bevelWidth(); // enable clip mask - XSetClipMask(disp, gc, m_icon->pixmap->mask().drawable()); + XSetClipMask(disp, gc, tmp_mask.drawable()); XSetClipOrigin(disp, gc, icon_x, icon_y); - draw.copyArea(m_icon->pixmap->pixmap().drawable(), + draw.copyArea(tmp_pixmap.drawable(), gc, 0, 0, icon_x, icon_y, - m_icon->pixmap->width(), m_icon->pixmap->height()); + tmp_pixmap.width(), tmp_pixmap.height()); // restore clip mask XSetClipMask(disp, gc, None);
M src/FbTk/MenuItem.hhsrc/FbTk/MenuItem.hh

@@ -101,6 +101,9 @@ @name accessors

*/ //@{ virtual const std::string &label() const { return m_label; } + virtual const PixmapWithMask *icon() const { + return m_icon.get() ? m_icon->pixmap.get() : 0; + } virtual const Menu *submenu() const { return m_submenu; } virtual bool isEnabled() const { return m_enabled; } virtual bool isSelected() const { return m_selected; }
M src/FbTk/TypeAhead.hhsrc/FbTk/TypeAhead.hh

@@ -103,6 +103,8 @@ Items last_matched;

if (!m_search_results.empty()) fillValues(m_search_results.back().result(), last_matched); + else + return *m_ref; return last_matched; }
M src/FbWinFrame.ccsrc/FbWinFrame.cc

@@ -33,6 +33,7 @@ #include "CompareWindow.hh"

#include "FbWinFrameTheme.hh" #include "Screen.hh" +#include "IconButton.hh" #include "Container.hh" #ifdef SHAPE

@@ -52,7 +53,8 @@ unsigned int width, unsigned int height):

m_screen(screen), m_theme(theme), m_imagectrl(imgctrl), - m_window(theme.screenNum(), x, y, width, height, ButtonPressMask | ButtonReleaseMask | + m_window(theme.screenNum(), x, y, width, height, + ButtonPressMask | ButtonReleaseMask | ButtonMotionMask | EnterWindowMask, true), m_layeritem(window(), layer), m_titlebar(m_window, 0, 0, 100, 16,

@@ -512,13 +514,6 @@ m_window.setOpaque(255);

} } - if (currentLabel()) { - if (newvalue) // focused - applyFocusLabel(*m_current_label); - else // unfocused - applyUnfocusLabel(*m_current_label); - } - applyAll(); clearAll(); }

@@ -610,11 +605,9 @@ m_buttons_right.pop_back();

} } -FbWinFrame::ButtonId FbWinFrame::createTab(const string &title, FbTk::Command *command, - int tabs_padding) { - FbTk::TextButton *button = new FbTk::TextButton(m_tab_container, - theme().font(), - title); +IconButton *FbWinFrame::createTab(Focusable &client) { + IconButton *button = new IconButton(m_tab_container, theme().iconbarTheme(), + client); button->show(); button->setEventMask(ExposureMask | ButtonPressMask |

@@ -622,29 +615,14 @@ ButtonReleaseMask | ButtonMotionMask |

EnterWindowMask); FbTk::EventManager::instance()->add(*button, button->window()); - FbTk::RefCount<FbTk::Command> refcmd(command); - button->setOnClick(refcmd); - - button->setTextPadding(tabs_padding); - button->setJustify(theme().justify()); - button->setBorderColor(theme().border().color()); - button->setBorderWidth(m_window.borderWidth()); - m_tab_container.insertItem(button); - - if (currentLabel() == 0) - setLabelButtonFocus(*button); return button; } -void FbWinFrame::removeTab(ButtonId btn) { - if (btn == m_current_label) - m_current_label = 0; - +void FbWinFrame::removeTab(IconButton *btn) { if (m_tab_container.removeItem(btn)) delete btn; - }

@@ -688,33 +666,10 @@

m_tab_container.moveItem(&btn, movement); } -void FbWinFrame::setLabelButtonFocus(FbTk::TextButton &btn) { - if (&btn == currentLabel() || btn.parent() != &m_tab_container) +void FbWinFrame::setLabelButtonFocus(IconButton &btn) { + if (btn.parent() != &m_tab_container) return; - - // render label buttons - if (currentLabel() != 0) - applyUnfocusLabel(*m_current_label); - - m_current_label = &btn; // current focused button m_label.setText(btn.text()); - - if (m_focused) - applyFocusLabel(*m_current_label); - else - applyUnfocusLabel(*m_current_label); -} - -void FbWinFrame::setLabelButtonFocus(FbTk::TextButton &btn, bool value) { - if (btn.parent() != &m_tab_container) - return; - - if (value) - applyFocusLabel(btn); - else - applyUnfocusLabel(btn); - - btn.clear(); } void FbWinFrame::setClientWindow(FbTk::FbWindow &win) {

@@ -745,7 +700,8 @@

XChangeWindowAttributes(win.display(), win.window(), CWEventMask|CWDontPropagate, &attrib_set); m_clientarea.raise(); - win.show(); + if (isVisible()) + win.show(); win.raise(); m_window.showSubwindows();

@@ -900,10 +856,6 @@ evm.remove(m_clientarea);

} void FbWinFrame::buttonPressEvent(XButtonEvent &event) { - // we can ignore which window the event was generated for - if (event.window == m_label.window() && m_current_label) - event.window = m_current_label->window(); - m_tab_container.tryButtonPressEvent(event); if (event.window == m_grip_right.window() || event.window == m_grip_left.window() ||

@@ -919,10 +871,6 @@ m_commands[event.button - 1].click_pressed->execute();

} void FbWinFrame::buttonReleaseEvent(XButtonEvent &event) { - // we can ignore which window the event was generated for - if (event.window == m_label.window() && m_current_label) - event.window = m_current_label->window(); - // we continue even if a button got the event m_tab_container.tryButtonReleaseEvent(event);

@@ -1274,11 +1222,11 @@ m_titlebar.width(), m_titlebar.height());

//!! TODO: don't render label if internal tabs - render(m_theme.labelFocusTexture(), m_label_focused_color, + render(m_theme.iconbarTheme().focusedTexture(), m_label_focused_color, m_label_focused_pm, m_label.width(), m_label.height()); - render(m_theme.labelUnfocusTexture(), m_label_unfocused_color, + render(m_theme.iconbarTheme().unfocusedTexture(), m_label_unfocused_color, m_label_unfocused_pm, m_label.width(), m_label.height());

@@ -1290,8 +1238,8 @@ m_need_render = true;

return; } - const FbTk::Texture *tc_focused = &m_theme.labelFocusTexture(); - const FbTk::Texture *tc_unfocused = &m_theme.labelUnfocusTexture(); + const FbTk::Texture *tc_focused = &m_theme.iconbarTheme().focusedTexture(); + const FbTk::Texture *tc_unfocused = &m_theme.iconbarTheme().unfocusedTexture(); if (m_tabmode == EXTERNAL && tc_focused->type() & FbTk::Texture::PARENTRELATIVE) tc_focused = &m_theme.titleFocusTexture();

@@ -1306,14 +1254,6 @@ render(*tc_unfocused, m_tabcontainer_unfocused_color,

m_tabcontainer_unfocused_pm, m_tab_container.width(), m_tab_container.height(), m_tab_container.orientation()); - render(m_theme.labelFocusTexture(), m_labelbutton_focused_color, - m_labelbutton_focused_pm, - m_tab_container.width(), m_tab_container.height(), m_tab_container.orientation()); - - render(m_theme.labelUnfocusTexture(), m_labelbutton_unfocused_color, - m_labelbutton_unfocused_pm, - m_tab_container.width(), m_tab_container.height(), m_tab_container.orientation()); - renderButtons(); }

@@ -1333,8 +1273,12 @@ m_titlebar.setAlpha(alpha);

m_label.setAlpha(alpha); if (m_tabmode != INTERNAL) { - m_label.setGC(m_focused?theme().labelTextFocusGC():theme().labelTextUnfocusGC()); - m_label.setJustify(theme().justify()); + m_label.setGC(m_focused ? + theme().iconbarTheme().focusedText().textGC() : + theme().iconbarTheme().unfocusedText().textGC()); + m_label.setJustify(m_focused ? + theme().iconbarTheme().focusedText().justify() : + theme().iconbarTheme().unfocusedText().justify()); if (label_pm != 0) m_label.setBackgroundPixmap(label_pm);

@@ -1454,8 +1398,6 @@ if (theme().handleWidth() == 0)

m_use_handle = false; m_disable_themeshape = false; - - m_current_label = 0; // no focused button at first m_handle.showSubwindows();

@@ -1463,7 +1405,6 @@ // clear pixmaps

m_title_focused_pm = m_title_unfocused_pm = 0; m_label_focused_pm = m_label_unfocused_pm = 0; m_tabcontainer_focused_pm = m_tabcontainer_unfocused_pm = 0; - m_labelbutton_focused_pm = m_labelbutton_unfocused_pm = 0; m_handle_focused_pm = m_handle_unfocused_pm = 0; m_button_pm = m_button_unfocused_pm = m_button_pressed_pm = 0; m_grip_unfocused_pm = m_grip_focused_pm = 0;

@@ -1586,11 +1527,8 @@ // and the labelbuttons in it

Container::ItemList::iterator btn_it = m_tab_container.begin(); Container::ItemList::iterator btn_it_end = m_tab_container.end(); for (; btn_it != btn_it_end; ++btn_it) { - FbTk::TextButton *btn = static_cast<FbTk::TextButton *>(*btn_it); - if (btn == m_current_label && m_focused) - applyFocusLabel(*btn); - else - applyUnfocusLabel(*btn); + IconButton *btn = static_cast<IconButton *>(*btn_it); + btn->reconfigTheme(); } }

@@ -1626,15 +1564,6 @@

gripRight().setBorderWidth(border_width); gripRight().setBorderColor(theme().border().color()); - // and the labelbuttons - Container::ItemList::iterator btn_it = m_tab_container.begin(); - Container::ItemList::iterator btn_it_end = m_tab_container.end(); - for (; btn_it != btn_it_end; ++btn_it) { - (*btn_it)->setBorderWidth(border_width); - (*btn_it)->setBorderColor(theme().border().color()); - } - m_tab_container.update(); - if (bw_changes != 0) resize(width(), height() + bw_changes);

@@ -1645,32 +1574,6 @@ gravityTranslate(grav_x, grav_y, m_active_gravity, m_active_orig_client_bw, false);

// if the location changes, shift it if (grav_x != 0 || grav_y != 0) move(grav_x + x(), grav_y + y()); - -} - -void FbWinFrame::applyFocusLabel(FbTk::TextButton &button) { - - button.setGC(theme().labelTextFocusGC()); - button.setJustify(theme().justify()); - button.setAlpha(getAlpha(m_focused)); - - if (m_labelbutton_focused_pm != 0) { - button.setBackgroundPixmap(m_labelbutton_focused_pm); - } else - button.setBackgroundColor(m_labelbutton_focused_color); - -} - -void FbWinFrame::applyUnfocusLabel(FbTk::TextButton &button) { - - button.setGC(theme().labelTextUnfocusGC()); - button.setJustify(theme().justify()); - button.setAlpha(getAlpha(m_focused)); - - if (m_labelbutton_unfocused_pm != 0) { - button.setBackgroundPixmap(m_labelbutton_unfocused_pm); - } else - button.setBackgroundColor(m_labelbutton_unfocused_color); }
M src/FbWinFrame.hhsrc/FbWinFrame.hh

@@ -43,6 +43,8 @@

class Shape; class FbWinFrameTheme; class BScreen; +class IconButton; +class Focusable; namespace FbTk { class TextButton;

@@ -70,8 +72,6 @@ LEFTBOTTOM, LEFTTOP,

RIGHTBOTTOM, RIGHTTOP }; - - typedef FbTk::TextButton *ButtonId; ///< defines a button id /// create a top level window FbWinFrame(BScreen &screen, FbWinFrameTheme &theme, FbTk::ImageControl &imgctrl,

@@ -142,10 +142,9 @@ void addRightButton(FbTk::Button *btn);

/// remove all buttons from titlebar void removeAllButtons(); /// adds a button to label window with specified title and command - ButtonId createTab(const std::string &title, FbTk::Command *cmd, int tab_padding); - // void addLabelButton(FbTk::TextButton &btn); + IconButton *createTab(Focusable &client); /// removes a specific button from label window - void removeTab(ButtonId id); + void removeTab(IconButton *id); /// move label button to the left void moveLabelButtonLeft(FbTk::TextButton &btn); /// move label button to the right

@@ -157,9 +156,7 @@ void moveLabelButtonLeftOf(FbTk::TextButton &btn, const FbTk::TextButton &dest);

//move the first label button to the right of the second void moveLabelButtonRightOf(FbTk::TextButton &btn, const FbTk::TextButton &dest); /// which button is to be rendered focused - void setLabelButtonFocus(FbTk::TextButton &btn); - /// specify focus state of button - void setLabelButtonFocus(FbTk::TextButton &btn, bool value); + void setLabelButtonFocus(IconButton &btn); /// attach a client window for client area void setClientWindow(FbTk::FbWindow &win); /// remove attached client window

@@ -238,7 +235,7 @@ inline const FbTk::FbWindow &gripLeft() const { return m_grip_left; }

inline FbTk::FbWindow &gripLeft() { return m_grip_left; } inline const FbTk::FbWindow &gripRight() const { return m_grip_right; } inline FbTk::FbWindow &gripRight() { return m_grip_right; } - inline const FbTk::TextButton *currentLabel() const { return m_current_label; } + inline const IconButton *currentLabel() const { return m_current_label; } inline bool focused() const { return m_focused; } inline bool isShaded() const { return m_shaded; } inline FbWinFrameTheme &theme() const { return m_theme; }

@@ -284,8 +281,6 @@ void applyAll();

void applyTitlebar(); void applyHandles(); void applyTabContainer(); // and label buttons - void applyFocusLabel(FbTk::TextButton &button); - void applyUnfocusLabel(FbTk::TextButton &button); void applyButtons(); // only called within applyTitlebar void getCurrentFocusPixmap(Pixmap &label_pm, Pixmap &title_pm,

@@ -324,8 +319,7 @@ typedef std::vector<FbTk::Button *> ButtonList;

ButtonList m_buttons_left, ///< buttons to the left m_buttons_right; ///< buttons to the right typedef std::list<FbTk::TextButton *> LabelList; - FbTk::TextButton *m_current_label; ///< which client button is focused at the moment - std::string m_titletext; ///< text to be displayed int m_label + IconButton *m_current_label; ///< which client button is focused at the moment int m_bevel; ///< bevel between titlebar items and titlebar bool m_use_titlebar; ///< if we should use titlebar bool m_use_tabs; ///< if we should use tabs (turns them off in external mode only)

@@ -354,11 +348,6 @@ FbTk::Color m_tabcontainer_focused_color; ///< color for focused tab container

Pixmap m_tabcontainer_unfocused_pm; ///< pixmap for unfocused tab container FbTk::Color m_tabcontainer_unfocused_color; ///< color for unfocused tab container - Pixmap m_labelbutton_focused_pm; ///< pixmap for focused label - FbTk::Color m_labelbutton_focused_color; ///< color for focused label - Pixmap m_labelbutton_unfocused_pm; ///< pixmap for unfocused label - FbTk::Color m_labelbutton_unfocused_color; ///< color for unfocused label - FbTk::Color m_handle_focused_color, m_handle_unfocused_color; Pixmap m_handle_focused_pm, m_handle_unfocused_pm;
M src/FbWinFrameTheme.ccsrc/FbWinFrameTheme.cc

@@ -24,13 +24,12 @@

#include "FbWinFrameTheme.hh" #include "App.hh" +#include "IconbarTheme.hh" + #include <X11/cursorfont.h> FbWinFrameTheme::FbWinFrameTheme(int screen_num): FbTk::Theme(screen_num), - m_label_focus(*this, "window.label.focus", "Window.Label.Focus"), - m_label_unfocus(*this, "window.label.unfocus", "Window.Label.Unfocus"), - m_title_focus(*this, "window.title.focus", "Window.Title.Focus"), m_title_unfocus(*this, "window.title.unfocus", "Window.Title.Unfocus"),

@@ -44,25 +43,20 @@

m_grip_focus(*this, "window.grip.focus", "Window.Grip.Focus"), m_grip_unfocus(*this, "window.grip.unfocus", "Window.Grip.Unfocus"), - m_label_focus_color(*this, "window.label.focus.textColor", "Window.Label.Focus.TextColor"), - m_label_unfocus_color(*this, "window.label.unfocus.textColor", "Window.Label.Unfocus.TextColor"), - m_button_focus_color(*this, "window.button.focus.picColor", "Window.Button.Focus.PicColor"), m_button_unfocus_color(*this, "window.button.unfocus.picColor", "Window.Button.Unfocus.PicColor"), m_font(*this, "window.font", "Window.Font"), - m_textjustify(*this, "window.justify", "Window.Justify"), m_shape_place(*this, "window.roundCorners", "Window.RoundCorners"), m_title_height(*this, "window.title.height", "Window.Title.Height"), m_bevel_width(*this, "window.bevelWidth", "Window.BevelWidth"), m_handle_width(*this, "window.handleWidth", "Window.handleWidth"), m_border(*this, "window", "Window"), // for window.border* - m_label_text_focus_gc(RootWindow(FbTk::App::instance()->display(), screen_num)), - m_label_text_unfocus_gc(RootWindow(FbTk::App::instance()->display(), screen_num)), m_button_pic_focus_gc(RootWindow(FbTk::App::instance()->display(), screen_num)), m_button_pic_unfocus_gc(RootWindow(FbTk::App::instance()->display(), screen_num)), m_focused_alpha(255), - m_unfocused_alpha(255) { + m_unfocused_alpha(255), + m_iconbar_theme(screen_num, "window.label", "Window.Label") { *m_title_height = 0; // set defaults

@@ -107,9 +101,9 @@ *m_handle_width = 200;

else if (*m_handle_width < 0) *m_handle_width = 1; - m_label_text_focus_gc.setForeground(*m_label_focus_color); - m_label_text_unfocus_gc.setForeground(*m_label_unfocus_color); m_button_pic_focus_gc.setForeground(*m_button_focus_color); m_button_pic_unfocus_gc.setForeground(*m_button_unfocus_color); + + m_iconbar_theme.reconfigTheme(); }
M src/FbWinFrameTheme.hhsrc/FbWinFrameTheme.hh

@@ -33,6 +33,7 @@ #include "FbTk/Subject.hh"

#include "FbTk/GContext.hh" #include "BorderTheme.hh" +#include "IconbarTheme.hh" #include "Shape.hh" class FbWinFrameTheme: public FbTk::Theme {

@@ -43,9 +44,6 @@ /**

@name textures */ //@{ - const FbTk::Texture &labelFocusTexture() const { return *m_label_focus; } - const FbTk::Texture &labelUnfocusTexture() const { return *m_label_unfocus; } - const FbTk::ThemeItem<FbTk::Texture> &label() const { return m_label_unfocus; } const FbTk::Texture &titleFocusTexture() const { return *m_title_focus; } const FbTk::Texture &titleUnfocusTexture() const { return *m_title_unfocus; }

@@ -64,18 +62,11 @@ /**

@name colors */ //@{ - const FbTk::Color &labelFocusColor() const { return *m_label_focus_color; } - const FbTk::Color &labelUnfocusColor() const { return *m_label_unfocus_color; } - const FbTk::Color &buttonFocuscolor() const { return *m_button_focus_color; } const FbTk::Color &buttonUnfocuscolor() const { return *m_button_unfocus_color; } //@} FbTk::Font &font() { return *m_font; } - FbTk::Justify justify() const { return *m_textjustify; } - - GC labelTextFocusGC() const { return m_label_text_focus_gc.gc(); } - GC labelTextUnfocusGC() const { return m_label_text_unfocus_gc.gc(); } GC buttonPicFocusGC() const { return m_button_pic_focus_gc.gc(); } GC buttonPicUnfocusGC() const { return m_button_pic_unfocus_gc.gc(); }

@@ -100,24 +91,22 @@ unsigned char unfocusedAlpha() const { return m_unfocused_alpha; }

void setFocusedAlpha(unsigned char alpha) { m_focused_alpha = alpha; } void setUnfocusedAlpha(unsigned char alpha) { m_unfocused_alpha = alpha; } + IconbarTheme &iconbarTheme() { return m_iconbar_theme; } + private: - FbTk::ThemeItem<FbTk::Texture> m_label_focus, m_label_unfocus; FbTk::ThemeItem<FbTk::Texture> m_title_focus, m_title_unfocus; FbTk::ThemeItem<FbTk::Texture> m_handle_focus, m_handle_unfocus; FbTk::ThemeItem<FbTk::Texture> m_button_focus, m_button_unfocus, m_button_pressed; FbTk::ThemeItem<FbTk::Texture> m_grip_focus, m_grip_unfocus; - FbTk::ThemeItem<FbTk::Color> m_label_focus_color, m_label_unfocus_color; FbTk::ThemeItem<FbTk::Color> m_button_focus_color, m_button_unfocus_color; FbTk::ThemeItem<FbTk::Font> m_font; - FbTk::ThemeItem<FbTk::Justify> m_textjustify; FbTk::ThemeItem<Shape::ShapePlace> m_shape_place; FbTk::ThemeItem<int> m_title_height, m_bevel_width, m_handle_width; BorderTheme m_border; - FbTk::GContext m_label_text_focus_gc, m_label_text_unfocus_gc; FbTk::GContext m_button_pic_focus_gc, m_button_pic_unfocus_gc; Cursor m_cursor_move;

@@ -127,6 +116,8 @@ Cursor m_cursor_upper_left_angle;

Cursor m_cursor_upper_right_angle; unsigned char m_focused_alpha; unsigned char m_unfocused_alpha; + + IconbarTheme m_iconbar_theme; }; #endif // FBWINFRAMETHEME_HH
M src/FocusControl.ccsrc/FocusControl.cc

@@ -23,6 +23,7 @@ // $Id$

#include "FocusControl.hh" +#include "ClientPattern.hh" #include "Screen.hh" #include "Window.hh" #include "WinClient.hh"

@@ -48,6 +49,22 @@ WinClient *FocusControl::s_focused_window = 0;

FluxboxWindow *FocusControl::s_focused_fbwindow = 0; bool FocusControl::s_reverting = false; +namespace { + +bool doSkipWindow(const Focusable &win, const ClientPattern *pat) { + const FluxboxWindow *fbwin = win.fbwindow(); + if (!fbwin || fbwin->isFocusHidden()) + return true; // skip if no fbwindow or if focushidden + if (pat && !pat->match(win)) + return true; // skip if it doesn't match the pattern + if (fbwin->workspaceNumber() != win.screen().currentWorkspaceID() && + !fbwin->isStuck()) + return true; // for now, we only cycle through the current workspace + return false; // else don't skip +} + +}; // end anonymous namespace + FocusControl::FocusControl(BScreen &screen): m_screen(screen), m_focus_model(screen.resourceManager(),

@@ -65,28 +82,12 @@ m_cycling_list(0),

m_was_iconic(false), m_cycling_last(0) { - m_cycling_window = m_focused_list.end(); + m_cycling_window = m_focused_win_list.end(); } -// true if the windows should be skiped else false -bool doSkipWindow(const WinClient &winclient, int opts) { - const FluxboxWindow *win = winclient.fbwindow(); - return (!win || - // skip if stuck - (opts & FocusControl::CYCLESKIPSTUCK) != 0 && win->isStuck() || - // skip if not active client (i.e. only visit each fbwin once) - (opts & FocusControl::CYCLEGROUPS) != 0 && win->winClient().window() != winclient.window() || - // skip if shaded - (opts & FocusControl::CYCLESKIPSHADED) != 0 && win->isShaded() || - // skip if iconic - (opts & FocusControl::CYCLESKIPICONIC) != 0 && win->isIconic() || - // skip if hidden - win->isFocusHidden() - ); -} - -void FocusControl::cycleFocus(FocusedWindows &window_list, int opts, bool cycle_reverse) { +void FocusControl::cycleFocus(Focusables &window_list, const ClientPattern *pat, + bool cycle_reverse) { if (!m_cycling_list) { if (&m_screen == FbTk::EventManager::instance()->grabbingKeyboard())

@@ -97,13 +98,15 @@ m_cycling_last = 0;

} else if (m_cycling_list != &window_list) m_cycling_list = &window_list; - FocusedWindows::iterator it_begin = window_list.begin(); - FocusedWindows::iterator it_end = window_list.end(); + Focusables::iterator it_begin = window_list.begin(); + Focusables::iterator it_end = window_list.end(); // too many things can go wrong with remembering this m_cycling_window = find(it_begin, it_end, s_focused_window); + if (m_cycling_window == it_end) + m_cycling_window = find(it_begin, it_end, s_focused_fbwindow); - FocusedWindows::iterator it = m_cycling_window; + Focusables::iterator it = m_cycling_window; FluxboxWindow *fbwin = 0; WinClient *last_client = 0; WinClient *was_iconic = 0;

@@ -123,11 +126,7 @@ if (it == it_end)

continue; fbwin = (*it)->fbwindow(); - // make sure the window is on the same workspace, - // unless its sticky, which is ok - if (!fbwin || - ( fbwin->workspaceNumber() != m_screen.currentWorkspaceID() && - ! fbwin->isStuck())) + if (!fbwin) continue; // keep track of the originally selected window in a group

@@ -135,7 +134,7 @@ last_client = &fbwin->winClient();

was_iconic = (fbwin->isIconic() ? last_client : 0); // now we actually try to focus the window - if (!doSkipWindow(**it, opts) && (*it)->focus()) + if (!doSkipWindow(**it, pat) && (*it)->focus()) break; }

@@ -168,6 +167,33 @@ m_was_iconic = was_iconic;

} +void FocusControl::goToWindowNumber(Focusables &winlist, int num, + const ClientPattern *pat) { + Focusable *last_matched = 0; + if (num > 0) { + Focusables::iterator it = winlist.begin(); + Focusables::iterator it_end = winlist.end(); + for (; it != it_end; ++it) { + if (!doSkipWindow(**it, pat) && (*it)->acceptsFocus()) { + --num; + last_matched = *it; + if (!num) break; + } + } + } else if (num < 0) { + Focusables::reverse_iterator it = winlist.rbegin(); + Focusables::reverse_iterator it_end = winlist.rend(); + for (; it != it_end; ++it) { + if (!doSkipWindow(**it, pat) && (*it)->acceptsFocus()) { + ++num; + last_matched = *it; + if (!num) break; + } + } + } + if (last_matched) last_matched->focus(); +} + void FocusControl::addFocusBack(WinClient &client) { m_focused_list.push_back(&client); m_creation_order_list.push_back(&client);

@@ -178,6 +204,16 @@ m_focused_list.push_front(&client);

m_creation_order_list.push_back(&client); } +void FocusControl::addFocusWinBack(Focusable &win) { + m_focused_win_list.push_back(&win); + m_creation_order_win_list.push_back(&win); +} + +void FocusControl::addFocusWinFront(Focusable &win) { + m_focused_win_list.push_front(&win); + m_creation_order_win_list.push_back(&win); +} + // move all clients in given window to back of focused list void FocusControl::setFocusBack(FluxboxWindow *fbwin) { // do nothing if there are no windows open

@@ -185,9 +221,19 @@ // don't change focus order while cycling

if (m_focused_list.empty() || s_reverting) return; - FocusedWindows::iterator it = m_focused_list.begin(); + // if the window isn't already in this list, we could accidentally add it + Focusables::iterator win_begin = m_focused_win_list.begin(), + win_end = m_focused_win_list.end(); + Focusables::iterator win_it = find(win_begin, win_end, fbwin); + if (win_it == win_end) + return; + + m_focused_win_list.erase(win_it); + m_focused_win_list.push_back(fbwin); + + Focusables::iterator it = m_focused_list.begin(); // use back to avoid an infinite loop - FocusedWindows::iterator it_back = --m_focused_list.end(); + Focusables::iterator it_back = --m_focused_list.end(); while (it != it_back) { if ((*it)->fbwindow() == fbwin) {

@@ -201,6 +247,7 @@ if ((*it)->fbwindow() == fbwin) {

m_focused_list.push_back(*it); m_focused_list.erase(it); } + } void FocusControl::stopCyclingFocus() {

@@ -208,7 +255,7 @@ // nothing to do

if (m_cycling_list == 0) return; - FocusedWindows::iterator it_end = m_cycling_list->end(); + Focusables::iterator it_end = m_cycling_list->end(); m_cycling_last = 0; m_cycling_list = 0;

@@ -217,10 +264,9 @@ // the iterator may be invalid if the window died

// in which case we'll do a proper revert focus if (m_cycling_window != it_end && (*m_cycling_window)->fbwindow() && (*m_cycling_window)->fbwindow()->isVisible()) { - WinClient *client = *m_cycling_window; - m_focused_list.remove(client); - m_focused_list.push_front(client); - client->fbwindow()->raise(); + (*m_cycling_window)->fbwindow()->raise(); + if (s_focused_window) + setScreenFocusedWindow(*s_focused_window); } else revertFocus(m_screen); }

@@ -230,13 +276,13 @@ * Used to find out which window was last focused on the given workspace

* If workspace is outside the ID range, then the absolute last focused window * is given. */ -WinClient *FocusControl::lastFocusedWindow(int workspace) { - if (m_focused_list.empty()) return 0; +Focusable *FocusControl::lastFocusedWindow(int workspace) { + if (m_focused_list.empty() || m_screen.isShuttingdown()) return 0; if (workspace < 0 || workspace >= (int) m_screen.numberOfWorkspaces()) return m_focused_list.front(); - FocusedWindows::iterator it = m_focused_list.begin(); - FocusedWindows::iterator it_end = m_focused_list.end(); + Focusables::iterator it = m_focused_list.begin(); + Focusables::iterator it_end = m_focused_list.end(); for (; it != it_end; ++it) { if ((*it)->fbwindow() && ((((int)(*it)->fbwindow()->workspaceNumber()) == workspace ||

@@ -253,14 +299,15 @@ * If ignore_client is given, it excludes that client.

* Stuck, iconic etc don't matter within a group */ WinClient *FocusControl::lastFocusedWindow(FluxboxWindow &group, WinClient *ignore_client) { - if (m_focused_list.empty()) return 0; + if (m_focused_list.empty() || m_screen.isShuttingdown()) + return 0; - FocusedWindows::iterator it = m_focused_list.begin(); - FocusedWindows::iterator it_end = m_focused_list.end(); + Focusables::iterator it = m_focused_list.begin(); + Focusables::iterator it_end = m_focused_list.end(); for (; it != it_end; ++it) { if (((*it)->fbwindow() == &group) && (*it) != ignore_client) - return *it; + return dynamic_cast<WinClient *>(*it); } return 0; }

@@ -269,11 +316,28 @@ void FocusControl::setScreenFocusedWindow(WinClient &win_client) {

// raise newly focused window to the top of the focused list // don't change the order if we're cycling or shutting down - // don't change on startup, as it may add windows that aren't listed yet - if (!isCycling() && !m_screen.isShuttingdown() && !s_reverting && - !Fluxbox::instance()->isStartup()) { - m_focused_list.remove(&win_client); + if (!isCycling() && !m_screen.isShuttingdown() && !s_reverting) { + + // make sure client is in our list, or else we could end up adding it + Focusables::iterator it_begin = m_focused_list.begin(), + it_end = m_focused_list.end(); + Focusables::iterator it = find(it_begin, it_end, &win_client); + if (it == it_end) + return; + + m_focused_list.erase(it); m_focused_list.push_front(&win_client); + + // also check the fbwindow + it_begin = m_focused_win_list.begin(); + it_end = m_focused_win_list.end(); + it = find(it_begin, it_end, win_client.fbwindow()); + + if (it != it_end) { + m_focused_win_list.erase(it); + m_focused_win_list.push_front(win_client.fbwindow()); + } + } }

@@ -380,7 +444,7 @@ } // else not improvement

} if (foundwin) - foundwin->setInputFocus(); + foundwin->focus(); }

@@ -388,7 +452,7 @@ void FocusControl::removeClient(WinClient &client) {

if (client.screen().isShuttingdown()) return; - WinClient *cyc = 0; + Focusable *cyc = 0; if (m_cycling_list && m_cycling_window != m_cycling_list->end()) cyc = *m_cycling_window;

@@ -401,27 +465,30 @@ stopCyclingFocus();

} } +void FocusControl::removeWindow(Focusable &win) { + m_focused_win_list.remove(&win); + m_creation_order_win_list.remove(&win); +} + void FocusControl::shutdown() { // restore windows backwards so they get put back correctly on restart - FocusedWindows::reverse_iterator it = m_focused_list.rbegin(); + Focusables::reverse_iterator it = m_focused_list.rbegin(); for (; it != m_focused_list.rend(); ++it) { - if (*it && (*it)->fbwindow()) - (*it)->fbwindow()->restore(*it, true); + WinClient *client = dynamic_cast<WinClient *>(*it); + if (client && client->fbwindow()) + client->fbwindow()->restore(client, true); } } /** * This function is called whenever we aren't quite sure what * focus is meant to be, it'll make things right ;-) - * last_focused is set to something if we want to make use of the - * previously focused window (it must NOT be set focused now, it - * is probably dying). */ void FocusControl::revertFocus(BScreen &screen) { - if (s_reverting) + if (s_reverting || screen.isShuttingdown()) return; - WinClient *next_focus = + Focusable *next_focus = screen.focusControl().lastFocusedWindow(screen.currentWorkspaceID()); if (next_focus && next_focus->fbwindow() &&

@@ -430,6 +497,7 @@ FocusControl::s_reverting = true;

// if setting focus fails, or isn't possible, fallback correctly if (!(next_focus && next_focus->focus())) { + setFocusedWindow(0); // so we don't get dangling m_focused_window pointer // if there's a menu open, focus it if (FbTk::Menu::shownMenu())

@@ -458,9 +526,8 @@ * local to the client.

* If unfocus_frame is true, we won't focus anything in the same frame * as the client. * - * So, we first prefer to choose a transient parent, then the last - * client in this window, and if no luck (or unfocus_frame), then - * we just use the normal revertFocus on the screen. + * So, we first prefer to choose the last client in this window, and if no luck + * (or unfocus_frame), then we just use the normal revertFocus on the screen. * * assumption: client has focus */
M src/FocusControl.hhsrc/FocusControl.hh

@@ -28,8 +28,10 @@ #include <list>

#include "FbTk/Resource.hh" +class ClientPattern; class WinClient; class FluxboxWindow; +class Focusable; class BScreen; /**

@@ -38,13 +40,12 @@ * It also holds the static "global" focused window

*/ class FocusControl { public: - typedef std::list<WinClient *> FocusedWindows; + typedef std::list<Focusable *> Focusables; /// main focus model enum FocusModel { MOUSEFOCUS = 0, ///< focus follows mouse CLICKFOCUS ///< focus on click }; - /// focus model for tabs enum TabFocusModel { MOUSETABFOCUS = 0, ///< tab focus follows mouse

@@ -60,18 +61,12 @@ FOCUSRIGHT ///< window is right

}; /// prevFocus/nextFocus option bits - enum FocusOption { - CYCLEGROUPS = 0x01, ///< cycle groups - CYCLESKIPSTUCK = 0x02, ///< skip stuck windows - CYCLESKIPSHADED = 0x04, ///< skip shaded windows - CYCLELINEAR = 0x08, ///< linear cycle - CYCLESKIPICONIC = 0x10, ///< skip iconified windows - CYCLEDEFAULT = 0x00 ///< default + enum { + CYCLEGROUPS = 0x01, //< cycle through groups + CYCLELINEAR = 0x08, ///< linear cycle }; - /// @param screen the screen to control focus for explicit FocusControl(BScreen &screen); - /// cycle previous focuable void prevFocus() { cycleFocus(m_focused_list, 0, true); } /// cycle next focusable

@@ -79,17 +74,20 @@ void nextFocus() { cycleFocus(m_focused_list, 0, false); }

/** * Cycle focus for a set of windows. * @param winlist the windowlist to cycle through - * @param options cycle options @see FocusOption + * @param pat pattern for matching focusables * @param reverse reverse the cycle order */ - void cycleFocus(FocusedWindows &winlist, int options, bool reverse = false); + void cycleFocus(Focusables &winlist, const ClientPattern *pat = 0, + bool reverse = false); + + void goToWindowNumber(Focusables &winlist, int num, + const ClientPattern *pat = 0); /// sets the focused window on a screen void setScreenFocusedWindow(WinClient &win_client); /// sets the main focus model void setFocusModel(FocusModel model); /// sets tab focus model - void setTabFocusModel(TabFocusModel model); - + void setTabFocusModel(TabFocusModel model); /// stop cycling mode void stopCyclingFocus(); /**

@@ -104,10 +102,12 @@ /// @return true if tab focus mode is mouse tab focus

bool isMouseTabFocus() const { return tabFocusModel() == MOUSETABFOCUS; } /// @return true if cycling is in progress bool isCycling() const { return m_cycling_list != 0; } - /// Appends a client to the back of the focus list + /// Appends a client to the front of the focus list void addFocusBack(WinClient &client); /// Appends a client to the front of the focus list void addFocusFront(WinClient &client); + void addFocusWinBack(Focusable &win); + void addFocusWinFront(Focusable &win); void setFocusBack(FluxboxWindow *fbwin); /// @return main focus model FocusModel focusModel() const { return *m_focus_model; }

@@ -115,19 +115,26 @@ /// @return tab focus model

TabFocusModel tabFocusModel() const { return *m_tab_focus_model; } /// @return true if newly created windows are focused bool focusNew() const { return *m_focus_new; } + /// @return last focused client in a specific workspace, or NULL. - WinClient *lastFocusedWindow(int workspace); - - WinClient *lastFocusedWindow(FluxboxWindow &group, WinClient *ignore_client); + Focusable *lastFocusedWindow(int workspace); + + WinClient *lastFocusedWindow(FluxboxWindow &group, WinClient *ignore_client = 0); /// @return focus list in creation order - FocusedWindows &creationOrderList() { return m_creation_order_list; } - /// @return the focus list - FocusedWindows &focusedOrderList() { return m_focused_list; } - /// removes a client from the focus list + Focusables &creationOrderList() { return m_creation_order_list; } + /// @return the focus list in focused order + Focusables &focusedOrderList() { return m_focused_list; } + Focusables &creationOrderWinList() { return m_creation_order_win_list; } + Focusables &focusedOrderWinList() { return m_focused_win_list; } + + /// remove client from focus list void removeClient(WinClient &client); + /// remove window from focus list + void removeWindow(Focusable &win); /// starts terminating this control void shutdown(); + /// do fallback focus for screen if normal focus control failed. static void revertFocus(BScreen &screen); // like revertFocus, but specifically related to this window (transients etc)

@@ -146,12 +153,14 @@ FbTk::Resource<bool> m_focus_new;

// This list keeps the order of window focusing for this screen // Screen global so it works for sticky windows too. - FocusedWindows m_focused_list; - FocusedWindows m_creation_order_list; + Focusables m_focused_list; + Focusables m_creation_order_list; + Focusables m_focused_win_list; + Focusables m_creation_order_win_list; - FocusedWindows::iterator m_cycling_window; - FocusedWindows *m_cycling_list; - WinClient *m_was_iconic; + Focusables::iterator m_cycling_window; + Focusables *m_cycling_list; + Focusable *m_was_iconic; WinClient *m_cycling_last; static WinClient *s_focused_window;
A src/Focusable.hh

@@ -0,0 +1,140 @@

+// Focusable.hh +// Copyright (c) 2007 Fluxbox Team (fluxgen at fluxbox dot org) +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +// $Id$ + +#ifndef FOCUSABLE_HH +#define FOCUSABLE_HH + +#include "FbTk/PixmapWithMask.hh" +#include "FbTk/ITypeAheadable.hh" +#include "FbTk/Subject.hh" + +#include <string> + +class BScreen; +class FluxboxWindow; + +/** + * A Base class for any object that might be "focused". + * Such as FluxboxWindow, Menu etc + */ +class Focusable: public FbTk::ITypeAheadable { +public: + Focusable(BScreen &scr, FluxboxWindow *fbwin = 0): + m_screen(scr), m_fbwin(fbwin), + m_instance_name("fluxbox"), m_class_name("fluxbox"), + m_focused(false), m_attention_state(false), + m_titlesig(*this), m_focussig(*this), m_diesig(*this), + m_attentionsig(*this) { } + virtual ~Focusable() { } + /** + * Take focus. + * @return true if the focuable took focus + */ + virtual bool focus() { return false; } + + /// @return true if the focusable has input focus + virtual bool isFocused() const { return m_focused; } + /// @return return true if it can be focused + virtual bool acceptsFocus() const { return true; } + + /// @return true if icon button should appear focused + inline bool getAttentionState() const { return m_attention_state; } + /// @set the attention state + virtual void setAttentionState(bool value) { + m_attention_state = value; attentionSig().notify(); + } + + /// @return the screen in which this object resides + inline BScreen &screen() { return m_screen; } + /// @return the screen in which this object resides + inline const BScreen &screen() const { return m_screen; } + + /** + * For accessing window properties, like shaded, minimized, etc. + * @return window context + */ + inline const FluxboxWindow *fbwindow() const { return m_fbwin; } + /** + * For accessing window properties, like shaded, minimized, etc. + * @return window context + */ + inline FluxboxWindow *fbwindow() { return m_fbwin; } + + /// @return WM_CLASS class string (for pattern matching) + virtual const std::string &getWMClassClass() const { return m_class_name; } + /// @return WM_CLASS name string (for pattern matching) + virtual const std::string &getWMClassName() const { return m_instance_name; } + /// @return wm role string ( for pattern matching) + virtual std::string getWMRole() const { return "Focusable"; } + + // so we can make nice buttons, menu entries, etc. + /// @return icon pixmap of the focusable + virtual const FbTk::PixmapWithMask &icon() const { return m_icon; } + /// @return title string + virtual const std::string &title() const { return m_title; } + /// @return type ahead string + const std::string &iTypeString() const { return title(); } + /** + * Signaling object to attatch observers to. + */ + class FocusSubject: public FbTk::Subject { + public: + explicit FocusSubject(Focusable &w):m_win(w) { } + /// @return context focusable for this signal + Focusable &win() { return m_win; } + /// @return context focusable for this signal + const Focusable &win() const { return m_win; } + private: + Focusable &m_win; //< the context + }; + + /** + @name signals + @{ + */ + // Used for both title and icon changes. + FbTk::Subject &titleSig() { return m_titlesig; } + // Used for both title and icon changes. + const FbTk::Subject &titleSig() const { return m_titlesig; } + FbTk::Subject &focusSig() { return m_focussig; } + const FbTk::Subject &focusSig() const { return m_focussig; } + FbTk::Subject &dieSig() { return m_diesig; } + const FbTk::Subject &dieSig() const { return m_diesig; } + FbTk::Subject &attentionSig() { return m_attentionsig; } + const FbTk::Subject &attentionSig() const { return m_attentionsig; } + /** @} */ // end group signals + +protected: + BScreen &m_screen; //< the screen in which it works + FluxboxWindow *m_fbwin; //< the working fluxbox window + + std::string m_title, m_instance_name, m_class_name; + bool m_focused; //< whether or not it has focus + bool m_attention_state; //< state of icon button while demanding attention + FbTk::PixmapWithMask m_icon; //< icon pixmap with mask + + // state and hint signals + FocusSubject m_titlesig, m_focussig, m_diesig, m_attentionsig; +}; + +#endif // FOCUSABLE_HH
M src/IconButton.ccsrc/IconButton.cc

@@ -24,21 +24,19 @@ // $Id$

#include "IconButton.hh" #include "IconbarTool.hh" +#include "IconbarTheme.hh" -#include "fluxbox.hh" #include "Screen.hh" -#include "Window.hh" -#include "WinClient.hh" -#include "CommandParser.hh" -#include "WindowCmd.hh" +#include "Focusable.hh" #include "FbTk/App.hh" -#include "FbTk/SimpleCommand.hh" +#include "FbTk/Command.hh" #include "FbTk/EventManager.hh" +#include "FbTk/ImageControl.hh" #include "FbTk/MacroCommand.hh" -#include "FbTk/Command.hh" +#include "FbTk/Menu.hh" #include "FbTk/RefCount.hh" -#include "FbTk/Menu.hh" +#include "FbTk/SimpleCommand.hh" #ifdef HAVE_CONFIG_H #include "config.h"

@@ -49,127 +47,25 @@ #ifdef SHAPE

#include <X11/extensions/shape.h> #endif // SHAPE -typedef FbTk::RefCount<FbTk::Command> RefCmd; -namespace { - -class ShowMenu: public FbTk::Command { -public: - explicit ShowMenu(FluxboxWindow &win):m_win(win) { } - void execute() { - // hide the menu if it's already showing for this FluxboxWindow - if (m_win.menu().isVisible() && WindowCmd<void>::window() == &m_win) { - m_win.screen().hideMenus(); - return; - } - m_win.screen().hideMenus(); - // get last button pos - const XEvent &event = Fluxbox::instance()->lastEvent(); - int x = event.xbutton.x_root - (m_win.menu().width() / 2); - int y = event.xbutton.y_root - (m_win.menu().height() / 2); - m_win.showMenu(x, y); - } -private: - FluxboxWindow &m_win; -}; - -class FocusCommand: public FbTk::Command { -public: - explicit FocusCommand(const IconbarTool& tool, FluxboxWindow &win) : - m_win(win), m_tool(tool) { } - void execute() { - // this needs to be a local variable, as this object could be destroyed - // if the workspace is changed. - FluxboxWindow &win = m_win; - if(win.isIconic() || !win.isFocused()) { - switch(win.screen().getUserFollowModel()) { - case BScreen::SEMIFOLLOW_ACTIVE_WINDOW: - if (win.isIconic()) { - win.screen().sendToWorkspace(win.screen().currentWorkspaceID(), &win); - } else { - win.screen().changeWorkspaceID(win.workspaceNumber()); - } - break; - case BScreen::FETCH_ACTIVE_WINDOW: - win.screen().sendToWorkspace(win.screen().currentWorkspaceID(), &win); - break; - case BScreen::FOLLOW_ACTIVE_WINDOW: - if (!win.isStuck()) - win.screen().changeWorkspaceID(win.workspaceNumber()); - default: - break; - }; - win.raiseAndFocus(); - } else - win.iconify(); - } - -private: - FluxboxWindow &m_win; - const IconbarTool& m_tool; -}; - -// simple forwarding of wheeling, but only -// if desktopwheeling is enabled -class WheelWorkspaceCmd : public FbTk::Command { -public: - explicit WheelWorkspaceCmd(const IconbarTool& tool, FluxboxWindow &win, const char* cmd) : - m_win(win), m_cmd(CommandParser::instance().parseLine(cmd)), m_tool(tool) { } - void execute() { - - switch(m_tool.wheelMode()) { - case IconbarTool::ON: - m_cmd->execute(); - break; - case IconbarTool::SCREEN: - if(m_win.screen().isDesktopWheeling()) - m_cmd->execute(); - break; - case IconbarTool::OFF: - default: - break; - }; - } - -private: - FluxboxWindow &m_win; - RefCmd m_cmd; - const IconbarTool& m_tool; -}; - -} // end anonymous namespace - - - -IconButton::IconButton(const IconbarTool& tool, const FbTk::FbWindow &parent, - FbTk::Font &font, FluxboxWindow &win): - FbTk::TextButton(parent, font, win.winClient().title()), +IconButton::IconButton(const FbTk::FbWindow &parent, IconbarTheme &theme, + Focusable &win): + FbTk::TextButton(parent, theme.focusedText().font(), win.title()), m_win(win), m_icon_window(*this, 1, 1, 1, 1, ExposureMask | ButtonPressMask | ButtonReleaseMask), - m_use_pixmap(true) { + m_use_pixmap(true), + m_theme(theme), + m_focused_pm(win.screen().imageControl()), + m_unfocused_pm(win.screen().imageControl()) { - - RefCmd next_workspace(new ::WheelWorkspaceCmd(tool, m_win, "nextworkspace")); - RefCmd prev_workspace(new ::WheelWorkspaceCmd(tool, m_win, "prevworkspace")); - - RefCmd focus_cmd(new ::FocusCommand(tool, m_win)); - RefCmd menu_cmd(new ::ShowMenu(m_win)); - setOnClick(focus_cmd, 1); - setOnClick(menu_cmd, 3); - if(win.screen().isReverseWheeling()) { - setOnClick(next_workspace, 5); - setOnClick(prev_workspace, 4); - } else { - setOnClick(next_workspace, 4); - setOnClick(prev_workspace, 5); - } - - m_win.hintSig().attach(this); m_win.titleSig().attach(this); + m_win.focusSig().attach(this); + m_win.attentionSig().attach(this); FbTk::EventManager::instance()->add(*this, m_icon_window); + reconfigTheme(); update(0); }

@@ -222,20 +118,68 @@ update(0);

} } +void IconButton::reconfigTheme() { + + if (m_theme.focusedTexture().usePixmap()) + m_focused_pm.reset(m_win.screen().imageControl().renderImage( + width(), height(), m_theme.focusedTexture(), + orientation())); + else + m_focused_pm.reset(0); + + if (m_theme.unfocusedTexture().usePixmap()) + m_unfocused_pm.reset(m_win.screen().imageControl().renderImage( + width(), height(), m_theme.unfocusedTexture(), + orientation())); + else + m_unfocused_pm.reset(0); + + setAlpha(parent()->alpha()); + + if (m_win.isFocused() || m_win.getAttentionState()) { + if (m_focused_pm != 0) + setBackgroundPixmap(m_focused_pm); + else + setBackgroundColor(m_theme.focusedTexture().color()); + + setGC(m_theme.focusedText().textGC()); + setFont(m_theme.focusedText().font()); + setJustify(m_theme.focusedText().justify()); + setBorderWidth(m_theme.focusedBorder().width()); + setBorderColor(m_theme.focusedBorder().color()); + + } else { + if (m_unfocused_pm != 0) + setBackgroundPixmap(m_unfocused_pm); + else + setBackgroundColor(m_theme.unfocusedTexture().color()); + + setGC(m_theme.unfocusedText().textGC()); + setFont(m_theme.unfocusedText().font()); + setJustify(m_theme.unfocusedText().justify()); + setBorderWidth(m_theme.unfocusedBorder().width()); + setBorderColor(m_theme.unfocusedBorder().color()); + + } + +} + void IconButton::update(FbTk::Subject *subj) { + // if the window's focus state changed, we need to update the background + if (subj == &m_win.focusSig() || subj == &m_win.attentionSig()) { + reconfigTheme(); + clear(); + return; + } + // we got signal that either title or // icon pixmap was updated, // so we refresh everything - // we need to check our client first - if (m_win.clientList().empty()) - return; - Display *display = FbTk::App::instance()->display(); - int screen = m_win.screen().screenNumber(); - if (m_use_pixmap && m_win.usePixmap()) { + if (m_use_pixmap && m_win.icon().pixmap().drawable() != None) { // setup icon window m_icon_window.show(); unsigned int w = width();

@@ -254,7 +198,8 @@ FbTk::translatePosition(orientation(), iconx, icony, neww, newh, 0);

m_icon_window.moveResize(iconx, icony, neww, newh); - m_icon_pixmap.copy(m_win.iconPixmap().drawable(), DefaultDepth(display, screen), screen); + m_icon_pixmap.copy(m_win.icon().pixmap().drawable(), + DefaultDepth(display, screen), screen); m_icon_pixmap.scale(m_icon_window.width(), m_icon_window.height()); // rotate the icon or not?? lets go not for now, and see what they say...

@@ -269,8 +214,8 @@ m_icon_window.hide();

m_icon_pixmap = 0; } - if(m_use_pixmap && m_win.useMask()) { - m_icon_mask.copy(m_win.iconMask().drawable(), 0, 0); + if(m_icon_pixmap.drawable() && m_win.icon().mask().drawable() != None) { + m_icon_mask.copy(m_win.icon().mask().drawable(), 0, 0); m_icon_mask.scale(m_icon_pixmap.width(), m_icon_pixmap.height()); m_icon_mask.rotate(orientation()); } else

@@ -287,9 +232,6 @@ ShapeSet);

#endif // SHAPE - if (subj == &(m_win.titleSig())) - setText(m_win.title()); - if (subj != 0) { setupWindow(); } else {

@@ -298,13 +240,8 @@ }

} void IconButton::setupWindow() { - m_icon_window.clear(); - - if (!m_win.clientList().empty()) { - setText(m_win.winClient().title()); - // draw with x offset and y offset - } + setText(m_win.title()); FbTk::TextButton::clear(); }
M src/IconButton.hhsrc/IconButton.hh

@@ -25,17 +25,18 @@

#ifndef ICONBUTTON_HH #define ICONBUTTON_HH +#include "FbTk/CachedPixmap.hh" #include "FbTk/FbPixmap.hh" #include "FbTk/Observer.hh" #include "FbTk/TextButton.hh" -class FluxboxWindow; -class IconbarTool; +class Focusable; +class IconbarTheme; class IconButton: public FbTk::TextButton, public FbTk::Observer { public: - IconButton(const IconbarTool& tool, const FbTk::FbWindow &parent, - FbTk::Font &font, FluxboxWindow &window); + IconButton(const FbTk::FbWindow &parent, IconbarTheme &theme, + Focusable &window); virtual ~IconButton(); void exposeEvent(XExposeEvent &event);

@@ -46,12 +47,14 @@ bool exposure = false);

void moveResize(int x, int y, unsigned int width, unsigned int height); void resize(unsigned int width, unsigned int height); + + void reconfigTheme(); void update(FbTk::Subject *subj); void setPixmap(bool use); - FluxboxWindow &win() { return m_win; } - const FluxboxWindow &win() const { return m_win; } + Focusable &win() { return m_win; } + const Focusable &win() const { return m_win; } bool setOrientation(FbTk::Orientation orient);

@@ -60,11 +63,15 @@ void drawText(int x, int y, FbTk::FbDrawable *drawable_override);

private: void setupWindow(); - FluxboxWindow &m_win; + Focusable &m_win; FbTk::FbWindow m_icon_window; FbTk::FbPixmap m_icon_pixmap; FbTk::FbPixmap m_icon_mask; bool m_use_pixmap; + + IconbarTheme &m_theme; + // cached pixmaps + FbTk::CachedPixmap m_focused_pm, m_unfocused_pm; }; #endif // ICONBUTTON_HH
D src/IconMenu.cc

@@ -1,66 +0,0 @@

-// IconMenu.cc for Fluxbox -// Copyright (c) 2004 Henrik Kinnunen (fluxgen at fluxbox dot org) -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -// $Id$ - -#include "IconMenu.hh" - -#include "Screen.hh" -#include "IconMenuItem.hh" -#include "Layer.hh" -#include "FbTk/I18n.hh" - -#include <typeinfo> - -static void updateItems(FbTk::Menu &menu, BScreen &screen) { - menu.removeAll(); - BScreen::Icons::iterator it = screen.iconList().begin(); - BScreen::Icons::iterator it_end = screen.iconList().end(); - for (; it != it_end; ++it) { - FluxboxWindow::ClientList::iterator client_it = (*it)->clientList().begin(); - FluxboxWindow::ClientList::iterator client_it_end = (*it)->clientList().end(); - for (; client_it != client_it_end; ++client_it) - menu.insert(new IconMenuItem(**client_it)); - } - menu.updateMenu(); -} - -IconMenu::IconMenu(BScreen &screen): - FbMenu(screen.menuTheme(), - screen.imageControl(), - *screen.layerManager(). - getLayer(Layer::MENU)) { - - _FB_USES_NLS; - setLabel(_FB_XTEXT(Menu, Icons, "Icons", "Iconic windows menu title")); - screen.iconListSig().attach(this); - updateItems(*this, screen); -} - -void IconMenu::update(FbTk::Subject *subj) { - if (subj == 0) - FbTk::Menu::update(subj); - else if (typeid(*subj) == typeid(BScreen::ScreenSubject)) { - BScreen &screen = static_cast<BScreen::ScreenSubject *>(subj)->screen(); - updateItems(*this, screen); - } else - FbTk::Menu::update(subj); -}
D src/IconMenu.hh

@@ -1,38 +0,0 @@

-// IconMenu.hh for Fluxbox -// Copyright (c) 2004 Henrik Kinnunen (fluxgen at fluxbox dot org) -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -// $Id$ - -#ifndef ICONMENU_HH -#define ICONMENU_HH - -#include "FbMenu.hh" - -class BScreen; - -class IconMenu: public FbMenu { -public: - explicit IconMenu(BScreen &screen); - virtual ~IconMenu() { } - void update(FbTk::Subject *subj); -}; - -#endif // ICONMENU_HH
D src/IconMenuItem.hh

@@ -1,44 +0,0 @@

-// IconMenuItem.hh for Fluxbox Window Manager -// Copyright (c) 2003 Henrik Kinnunen (fluxgen at fluxbox dot org) -// and Simon Bowden (rathnor at users.sourceforge.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -// $Id$ - -#ifndef ICONMENUITEM_HH -#define ICONMENUITEM_HH - -#include "FbTk/MenuItem.hh" -#include "WinClient.hh" -#include "Window.hh" - -class IconMenuItem: public FbTk::MenuItem { -public: - explicit IconMenuItem(WinClient &client):FbTk::MenuItem(client.iconTitle().c_str()), m_client(client) { } - const std::string &label() const { return m_client.iconTitle(); } - void click(int button, int time) { - if (m_client.fbwindow() != 0) - m_client.fbwindow()->deiconify(); - } -private: - WinClient &m_client; -}; - -#endif // ICONMENUITEM_HH
M src/IconbarTheme.ccsrc/IconbarTheme.cc

@@ -37,8 +37,7 @@ m_unfocused_border(*this, name + ".unfocused", altname + ".Unfocused"),

m_border(*this, name, altname), m_focused_text(*this, name + ".focused", altname + ".Focused"), m_unfocused_text(*this, name + ".unfocused", altname + ".Unfocused"), - m_name(name), - m_alpha(*this, name+".alpha", altname+".Alpha") { + m_name(name), m_altname(altname) { FbTk::ThemeManager::instance().loadTheme(*this);

@@ -58,27 +57,36 @@ bool IconbarTheme::fallback(FbTk::ThemeItem_base &item) {

using namespace FbTk; ThemeManager &tm = ThemeManager::instance(); + // TODO: fix fallbacks for "focused" vs. "focus" if (&m_focused_texture == &item) { return (tm.loadItem(item, "window.label.focus", "Window.Label.Focus") || tm.loadItem(item, "toolbar.windowLabel", "toolbar.windowLabel")); } else if (&m_unfocused_texture == &item) { - return (tm.loadItem(item, "window.label.unfocus", "Window.Label.Unfocus") || - tm.loadItem(item, "toolbar.windowLabel", "toolbar.windowLabel")); + return (tm.loadItem(item, "window.label.unfocus", + "Window.Label.Unfocus") || + tm.loadItem(item, "toolbar.windowLabel", + "toolbar.windowLabel")); } else if (&m_empty_texture == &item) { - return (tm.loadItem(item, m_focused_texture.name(), m_focused_texture.altName()) || - tm.loadItem(item, "toolbar.windowLabel", "toolbar.windowLabel") || - tm.loadItem(item, "toolbar", "toolbar") - ); + return (tm.loadItem(item, m_focused_texture.name(), + m_focused_texture.altName()) || + tm.loadItem(item, "toolbar.windowLabel", "toolbar.windowLabel") + || tm.loadItem(item, "toolbar", "toolbar")); } else if (item.name() == m_name + ".focused.borderWidth" || item.name() == m_name + ".unfocused.borderWidth") // don't fallback for base border, for theme backwards compatibility - return tm.loadItem(item, "borderWidth", "BorderWidth"); + return (tm.loadItem(item, m_name + ".borderWidth", + m_altname + ".BorderWidth") || + tm.loadItem(item, "window.borderWidth", "Window.BorderWidth") || + tm.loadItem(item, "borderWidth", "BorderWidth")); else if (item.name() == m_name + ".focused.borderColor" || item.name() == m_name + ".unfocused.borderColor") - return tm.loadItem(item, "borderColor", "BorderColor"); + return (tm.loadItem(item, m_name + ".borderColor", + m_altname + ".BorderColor") || + tm.loadItem(item, "window.borderColor", "Window.BorderColor") || + tm.loadItem(item, "borderColor", "BorderColor")); else if (item.name() == m_name + ".focused.font" || item.name() == m_name + ".unfocused.font")

@@ -91,11 +99,10 @@ return tm.loadItem(item, "window.label.focus.textColor", "Window.Label.Focus.TextColor");

} else if (item.name() == m_name + ".unfocused.textColor") { return tm.loadItem(item, "window.label.unfocus.textColor", "Window.Label.Unfocus.TextColor"); - } else if (item.name() == m_name + ".alpha") { - if (!tm.loadItem(item, "toolbar.alpha", "Toolbar.Alpha")) { - *m_alpha = 255; - } - return true; + } else if (item.name() == m_name + ".focused.justify" || + item.name() == m_name + ".unfocused.justify") { + return (tm.loadItem(item, m_name + ".justify", m_altname + ".Justify") + || tm.loadItem(item, "window.justify", "Window.Justify")); } return false;
M src/IconbarTheme.hhsrc/IconbarTheme.hh

@@ -49,14 +49,12 @@

const FbTk::Texture &focusedTexture() const { return *m_focused_texture; } const FbTk::Texture &unfocusedTexture() const { return *m_unfocused_texture; } const FbTk::Texture &emptyTexture() const { return *m_empty_texture; } - inline unsigned char alpha() const { return *m_alpha; } private: FbTk::ThemeItem<FbTk::Texture> m_focused_texture, m_unfocused_texture, m_empty_texture; BorderTheme m_focused_border, m_unfocused_border, m_border; TextTheme m_focused_text, m_unfocused_text; - std::string m_name; - FbTk::ThemeItem<int> m_alpha; + std::string m_name, m_altname; }; #endif // ICONBARTHEME_HH
M src/IconbarTool.ccsrc/IconbarTool.cc

@@ -24,6 +24,8 @@ // $Id$

#include "IconbarTool.hh" +#include "fluxbox.hh" +#include "WindowCmd.hh" #include "Screen.hh" #include "IconbarTheme.hh" #include "Window.hh"

@@ -83,40 +85,6 @@ else if (strcasecmp(strval, "AllWindows") == 0)

m_value = IconbarTool::ALLWINDOWS; else setDefaultValue(); -} - -template<> -void FbTk::Resource<IconbarTool::WheelMode>::setDefaultValue() { - m_value = IconbarTool::SCREEN; -} - - -template<> -void FbTk::Resource<IconbarTool::WheelMode>::setFromString(const char* strval) { - if (strncasecmp(strval, "off", strlen("off")) == 0) - m_value = IconbarTool::OFF; - else if (strncasecmp(strval, "on", strlen("on")) == 0) - m_value = IconbarTool::ON; - else if (strncasecmp(strval, "screen", strlen("screen")) == 0) - m_value = IconbarTool::SCREEN; - else - setDefaultValue(); -} - - -template<> -string FbTk::Resource<IconbarTool::WheelMode>::getString() const { - switch(m_value) { - case IconbarTool::ON: - return string("On"); - break; - case IconbarTool::SCREEN: - return string("Screen"); - break; - case IconbarTool::OFF: - default: - return string("Off"); - }; } template<>

@@ -290,52 +258,67 @@ menu.updateMenu();

} inline bool checkAddWindow(IconbarTool::Mode mode, const FluxboxWindow &win) { - bool ret_val = false; - // just add the icons that are on the this workspace - switch (mode) { - case IconbarTool::NONE: - break; - case IconbarTool::ICONS: - if (win.isIconic()) - ret_val = true; - break; - case IconbarTool::NOICONS: - if (!win.isIconic()) - ret_val = true; - break; - case IconbarTool::WORKSPACEICONS: - if(win.workspaceNumber() == win.screen().currentWorkspaceID() && - win.isIconic()) - ret_val = true; - break; - case IconbarTool::WORKSPACENOICONS: - if (win.isIconic()) - break; - case IconbarTool::WORKSPACE: - if (win.workspaceNumber() == win.screen().currentWorkspaceID()) - ret_val = true; - break; - case IconbarTool::ALLWINDOWS: - ret_val = true; - break; - } + if (win.isIconHidden() || mode == IconbarTool::NONE) + return false; + + if ((mode == IconbarTool::ICONS || mode == IconbarTool::WORKSPACEICONS) && + !win.isIconic()) + return false; + + if ((mode == IconbarTool::NOICONS || mode == IconbarTool::WORKSPACENOICONS) + && win.isIconic()) + return false; - if (win.isIconHidden()) - ret_val = false; + if ((mode == IconbarTool::WORKSPACE || mode == IconbarTool::WORKSPACEICONS + || mode == IconbarTool::WORKSPACENOICONS) && + win.workspaceNumber() != win.screen().currentWorkspaceID()) + return false; - return ret_val; + return true; } -void removeDuplicate(const IconbarTool::IconList &iconlist, list<FluxboxWindow *> &windowlist) { - IconbarTool::IconList::const_iterator icon_it = iconlist.begin(); - IconbarTool::IconList::const_iterator icon_it_end = iconlist.end(); - list<FluxboxWindow *>::iterator remove_it = windowlist.end(); - for (; icon_it != icon_it_end; ++icon_it) - remove_it = remove(windowlist.begin(), remove_it, &(*icon_it)->win()); +typedef FbTk::RefCount<FbTk::Command> RefCmd; + +class ShowMenu: public FbTk::Command { +public: + explicit ShowMenu(FluxboxWindow &win):m_win(win) { } + void execute() { + // hide the menu if it's already showing for this FluxboxWindow + if (m_win.menu().isVisible() && WindowCmd<void>::window() == &m_win) { + m_win.screen().hideMenus(); + return; + } + m_win.screen().hideMenus(); + // get last button pos + const XEvent &event = Fluxbox::instance()->lastEvent(); + int x = event.xbutton.x_root - (m_win.menu().width() / 2); + int y = event.xbutton.y_root - (m_win.menu().height() / 2); + m_win.showMenu(x, y); + } +private: + FluxboxWindow &m_win; +}; + +class FocusCommand: public FbTk::Command { +public: + explicit FocusCommand(Focusable &win): m_win(win) { } + void execute() { + // this needs to be a local variable, as this object could be destroyed + // if the workspace is changed. + FluxboxWindow *fbwin = m_win.fbwindow(); + if (!fbwin) + return; + if (m_win.isFocused()) + fbwin->iconify(); + else { + m_win.focus(); + fbwin->raise(); + } + } - // remove already existing windows - windowlist.erase(remove_it, windowlist.end()); -} +private: + Focusable &m_win; +}; }; // end anonymous namespace

@@ -345,16 +328,9 @@ ToolbarItem(ToolbarItem::RELATIVE),

m_screen(screen), m_icon_container(parent), m_theme(theme), - m_focused_pm( screen.imageControl() ), - m_unfocused_pm( screen.imageControl() ), - m_focused_err_pm( screen.imageControl() ), - m_unfocused_err_pm( screen.imageControl() ), m_empty_pm( screen.imageControl() ), m_rc_mode(screen.resourceManager(), WORKSPACE, screen.name() + ".iconbar.mode", screen.altName() + ".Iconbar.Mode"), - m_wheel_mode(screen.resourceManager(), OFF, - screen.name() + ".iconbar.wheelMode", - screen.name() + ".iconbar.WheelMode"), m_rc_alignment(screen.resourceManager(), Container::LEFT, screen.name() + ".iconbar.alignment", screen.altName() + ".Iconbar.Alignment"), m_rc_client_width(screen.resourceManager(), 70,

@@ -392,15 +368,6 @@ theme.reconfigSig().attach(this);

screen.clientListSig().attach(this); screen.iconListSig().attach(this); screen.currentWorkspaceSig().attach(this); - // setup focus timer - - FbTk::RefCount<FbTk::Command> timer_cmd(new FbTk::SimpleCommand<IconbarTool>(*this, &IconbarTool::timedRender)); - timeval to; - to.tv_sec = 0; - to.tv_usec = 1; // so it updates next event round - m_focus_timer.setCommand(timer_cmd); - m_focus_timer.setTimeout(to); - m_focus_timer.fireOnce(true); }

@@ -506,18 +473,10 @@ // handle window signal

if (subj != 0 && typeid(*subj) == typeid(FluxboxWindow::WinSubject)) { // we handle everything except die signal here FluxboxWindow::WinSubject *winsubj = static_cast<FluxboxWindow::WinSubject *>(subj); - if (subj == &(winsubj->win().focusSig())) { - // start focus timer, so we can update without flicker - m_focus_timer.start(); - - return; - } else if (subj == &(winsubj->win().workspaceSig())) { + if (subj == &(winsubj->win().workspaceSig())) { // we can ignore this signal if we're in ALLWINDOWS mode - // unless the window was focused and has nothing to revert to - if (mode() == ALLWINDOWS || mode() == ICONS || mode() == NOICONS) { - m_focus_timer.start(); + if (mode() == ALLWINDOWS || mode() == ICONS || mode() == NOICONS) return; - } // workspace changed for this window, and if it's not on current workspace we remove it if (m_screen.currentWorkspaceID() != winsubj->win().workspaceNumber()) {

@@ -525,29 +484,23 @@ removeWindow(winsubj->win());

renderTheme(); } return; - } else if (subj == &(winsubj->win().dieSig())) { // die sig - removeWindow(winsubj->win()); - renderTheme(); - return; // we don't need to update the entire list } else if (subj == &(winsubj->win().stateSig())) { if (!checkAddWindow(mode(), winsubj->win())) { removeWindow(winsubj->win()); renderTheme(); } - return; - } else if (subj == &(winsubj->win().attentionSig())) { - // render with titlebar focus, on attention - IconButton *button = findButton(winsubj->win()); - if (button) { - renderButton(*button, true, - winsubj->win().getAttentionState()); - } - return; } else { // signal not handled return; + } + } else if (subj != 0 && typeid(*subj) == typeid(Focusable::FocusSubject)) { + Focusable::FocusSubject *winsubj = static_cast<Focusable::FocusSubject *>(subj); + if (subj == &(winsubj->win().dieSig())) { // die sig + removeWindow(winsubj->win()); + renderTheme(); + return; // we don't need to update the entire list } }

@@ -587,7 +540,7 @@ // so text can end up behind program icons

renderTheme(); } -IconButton *IconbarTool::findButton(FluxboxWindow &win) { +IconButton *IconbarTool::findButton(Focusable &win) { IconList::iterator icon_it = m_icon_list.begin(); IconList::iterator icon_it_end = m_icon_list.end();

@@ -598,25 +551,14 @@ }

return 0; } -/* -void IconbarTool::renderWindow(FluxboxWindow &win) { - IconButton *button = findButton(win); - if (button == 0) - return; - renderButton(*button); -} -*/ + void IconbarTool::updateSizing() { m_icon_container.setBorderWidth(m_theme.border().width()); IconList::iterator icon_it = m_icon_list.begin(); const IconList::iterator icon_it_end = m_icon_list.end(); - for (; icon_it != icon_it_end; ++icon_it) { - if ((*icon_it)->win().isFocused()) - (*icon_it)->setBorderWidth(m_theme.focusedBorder().width()); - else // unfocused - (*icon_it)->setBorderWidth(m_theme.unfocusedBorder().width()); - } + for (; icon_it != icon_it_end; ++icon_it) + (*icon_it)->reconfigTheme(); }

@@ -631,127 +573,33 @@

// update button sizes before we get max width per client! updateSizing(); - unsigned int icon_width = 0, icon_height = 0; - unsigned int icon_width_off=0, icon_height_off=0; - - if (orientation() == FbTk::ROT0 || orientation() == FbTk::ROT180) { - icon_width = m_icon_container.maxWidthPerClient(); - icon_height = m_icon_container.height(); - icon_width_off = 1; - } else { - icon_width = m_icon_container.width(); - icon_height = m_icon_container.maxWidthPerClient(); - icon_height_off = 1; - } - - if (!m_theme.focusedTexture().usePixmap()) { - m_focused_pm.reset( 0 ); - m_focused_err_pm.reset( 0 ); - } else { - m_focused_pm.reset( m_screen.imageControl(). - renderImage(icon_width, icon_height, - m_theme.focusedTexture(), orientation()) ); - m_focused_err_pm.reset( m_screen.imageControl(). - renderImage(icon_width + icon_width_off, - icon_height + icon_height_off, - m_theme.focusedTexture(), orientation()) ); - } - - if (!m_theme.unfocusedTexture().usePixmap()) { - m_unfocused_pm.reset( 0 ); - m_unfocused_err_pm.reset( 0 ); - } else { - m_unfocused_pm.reset( m_screen.imageControl(). - renderImage(icon_width, icon_height, - m_theme.unfocusedTexture(), orientation()) ); - m_unfocused_err_pm.reset( m_screen.imageControl(). - renderImage(icon_width+icon_width_off, - icon_height+icon_height_off, - m_theme.unfocusedTexture(), orientation()) ); - } - // if we dont have any icons then we should render empty texture if (!m_theme.emptyTexture().usePixmap()) { m_empty_pm.reset( 0 ); m_icon_container.setBackgroundColor(m_theme.emptyTexture().color()); } else { - m_empty_pm.reset( m_screen.imageControl(). - renderImage(m_icon_container.width(), m_icon_container.height(), - m_theme.emptyTexture(), orientation()) ); + m_empty_pm.reset(m_screen.imageControl(). + renderImage(m_icon_container.width(), + m_icon_container.height(), + m_theme.emptyTexture(), orientation())); m_icon_container.setBackgroundPixmap(m_empty_pm); } - // set to zero so its consistent and not ugly - m_icon_container.setBorderWidth(m_theme.border().width()); - m_icon_container.setBorderColor(m_theme.border().color()); m_icon_container.setAlpha(m_alpha); // update buttons IconList::iterator icon_it = m_icon_list.begin(); const IconList::iterator icon_it_end = m_icon_list.end(); - for (; icon_it != icon_it_end; ++icon_it) { + for (; icon_it != icon_it_end; ++icon_it) renderButton(*(*icon_it)); - } + } -void IconbarTool::renderButton(IconButton &button, bool clear, - int focusOption) { +void IconbarTool::renderButton(IconButton &button, bool clear) { button.setPixmap(*m_rc_use_pixmap); - button.setAlpha(m_alpha); button.setTextPadding(*m_rc_client_padding); - - // The last button is always the regular width - bool wider_button = false; - if (!m_icon_container.empty()) { - if (button.orientation() == FbTk::ROT0 || button.orientation() == FbTk::ROT180) - wider_button = button.width() != m_icon_container.back()->width(); - else - wider_button = button.height() != m_icon_container.back()->height(); -// wider_button = (button.width() != m_icon_container.maxWidthPerClient() || // height to cover both orients - -// button.height() != m_icon_container.back()->height()); - } - - if (focusOption == 1 || - (focusOption == -1 && - button.win().isFocused())) { - - // focused texture - if (button.win().isFocused()) - m_icon_container.setSelected(m_icon_container.find(&button)); - - button.setGC(m_theme.focusedText().textGC()); - button.setFont(m_theme.focusedText().font()); - button.setJustify(m_theme.focusedText().justify()); - button.setBorderWidth(m_theme.focusedBorder().width()); - button.setBorderColor(m_theme.focusedBorder().color()); - - if (!wider_button && m_focused_pm != 0) - button.setBackgroundPixmap(m_focused_pm); - else if (wider_button && m_focused_err_pm != 0) - button.setBackgroundPixmap(m_focused_err_pm); - else - button.setBackgroundColor(m_theme.focusedTexture().color()); - - } else { // unfocused - if (m_icon_container.selected() == &button) - m_icon_container.setSelected(-1); - - button.setGC(m_theme.unfocusedText().textGC()); - button.setFont(m_theme.unfocusedText().font()); - button.setJustify(m_theme.unfocusedText().justify()); - button.setBorderWidth(m_theme.unfocusedBorder().width()); - button.setBorderColor(m_theme.unfocusedBorder().color()); - - if (!wider_button && m_unfocused_pm != 0) - button.setBackgroundPixmap(m_unfocused_pm); - else if (wider_button && m_unfocused_err_pm != 0) - button.setBackgroundPixmap(m_unfocused_err_pm); - else - button.setBackgroundColor(m_theme.unfocusedTexture().color()); - } - + button.reconfigTheme(); if (clear) button.clear(); // the clear also updates transparent }

@@ -764,7 +612,7 @@ m_icon_list.pop_back();

} } -void IconbarTool::removeWindow(FluxboxWindow &win) { +void IconbarTool::removeWindow(Focusable &win) { // got window die signal, lets find and remove the window IconList::iterator it = m_icon_list.begin(); IconList::iterator it_end = m_icon_list.end();

@@ -780,12 +628,11 @@ #ifdef DEBUG

cerr<<"IconbarTool::"<<__FUNCTION__<<"( 0x"<<&win<<" title = "<<win.title()<<") found!"<<endl; #endif // DEBUG // detach from all signals - win.focusSig().detach(this); win.dieSig().detach(this); - win.workspaceSig().detach(this); - win.stateSig().detach(this); - win.titleSig().detach(this); - + if (win.fbwindow()) { + win.fbwindow()->workspaceSig().detach(this); + win.fbwindow()->stateSig().detach(this); + } // remove from list and render theme again IconButton *button = *it;

@@ -797,46 +644,46 @@ delete button;

} -void IconbarTool::addWindow(FluxboxWindow &win) { - // we just want windows that has clients - if (win.clientList().empty() || win.isIconHidden() ) +void IconbarTool::addWindow(Focusable &win) { + // we just want windows that have clients + FluxboxWindow *fbwin = win.fbwindow(); + if (!fbwin || fbwin->clientList().empty() || fbwin->isIconHidden()) return; #ifdef DEBUG cerr<<"IconbarTool::addWindow(0x"<<&win<<" title = "<<win.title()<<")"<<endl; #endif // DEBUG - IconButton *button = new IconButton(*this, - m_icon_container, - m_theme.focusedText().font(), - win); + IconButton *button = new IconButton(m_icon_container, m_theme, win); + RefCmd focus_cmd(new ::FocusCommand(win)); + RefCmd menu_cmd(new ::ShowMenu(*fbwin)); + button->setOnClick(focus_cmd, 1); + button->setOnClick(menu_cmd, 3); renderButton(*button, false); // update the attributes, but don't clear it m_icon_container.insertItem(button); m_icon_list.push_back(button); // dont forget to detach signal in removeWindow - win.focusSig().attach(this); win.dieSig().attach(this); - win.workspaceSig().attach(this); - win.stateSig().attach(this); - win.attentionSig().attach(this); + fbwin->workspaceSig().attach(this); + fbwin->stateSig().attach(this); } void IconbarTool::updateList() { - list<WinClient *> ordered_list = - m_screen.focusControl().creationOrderList(); - list<WinClient *>::iterator it = ordered_list.begin(); - list<WinClient *>::iterator it_end = ordered_list.end(); + list<Focusable *> ordered_list = + m_screen.focusControl().creationOrderWinList(); + list<Focusable *>::iterator it = ordered_list.begin(); + list<Focusable *>::iterator it_end = ordered_list.end(); for (; it != it_end; ++it) { if ((*it)->fbwindow() && checkAddWindow(mode(), *(*it)->fbwindow()) && - !checkDuplicate(*(*it)->fbwindow())) - addWindow(*(*it)->fbwindow()); + !checkDuplicate(**it)) + addWindow(**it); } renderTheme(); } -bool IconbarTool::checkDuplicate(FluxboxWindow &win) { +bool IconbarTool::checkDuplicate(Focusable &win) { IconList::iterator it = m_icon_list.begin(); IconList::iterator it_end = m_icon_list.end(); for (; it != it_end; ++it) {

@@ -844,27 +691,6 @@ if (&win == &(*it)->win())

return true; } return false; -} - -void IconbarTool::timedRender() { - WinClient *client = FocusControl::focusedWindow(); - IconButton *current_button = static_cast<IconButton *>(m_icon_container.selected()); - - if (client == 0 || client->fbwindow() == 0) { - if (current_button != 0) - renderButton(*current_button); - return; - } - - IconButton *button = findButton(*client->fbwindow()); - // if old window is the same as the new focused window then ignore this render - // else render old client and new client - if (button == current_button) - return; - if (button != 0) - renderButton(*button); - if (current_button != 0) - renderButton(*current_button); } void IconbarTool::setOrientation(FbTk::Orientation orient) {
M src/IconbarTool.hhsrc/IconbarTool.hh

@@ -41,7 +41,7 @@

class IconbarTheme; class BScreen; class IconButton; -class FluxboxWindow; +class Focusable; class IconbarTool: public ToolbarItem, public FbTk::Observer { public:

@@ -55,13 +55,6 @@ WORKSPACEICONS, ///< icons on current workspace

WORKSPACENOICONS, ///< non iconified workspaces on current workspaces WORKSPACE, ///< all windows and all icons on current workspace ALLWINDOWS ///< all windows and all icons from all workspaces - }; - - /// wheeling on iconbutton - enum WheelMode { - OFF, ///< no wheeling, default mode - ON, ///< enabled wheeling - SCREEN ///< in perfect harmony with desktopwheeling-value }; IconbarTool(const FbTk::FbWindow &parent, IconbarTheme &theme,

@@ -85,60 +78,48 @@ unsigned int height() const;

unsigned int borderWidth() const; Mode mode() const { return *m_rc_mode; } - WheelMode wheelMode() const { return *m_wheel_mode; } void setOrientation(FbTk::Orientation orient); Container::Alignment alignment() const { return m_icon_container.alignment(); } + const BScreen &screen() const { return m_screen; } private: /// @return button associated with window - IconButton *findButton(FluxboxWindow &win); + IconButton *findButton(Focusable &win); void updateSizing(); - /// render single button that holds win - // void renderWindow(FluxboxWindow &win); /// render single button, and probably apply changes (clear) /// @param button the button to render /// @param clear if the window should be cleared first - /// @param focusOption -1 = use window focus, 0 = render no focus, 1 = render focus - void renderButton(IconButton &button, bool clear = true, - int focusOption = -1); + void renderButton(IconButton &button, bool clear = true); /// render all buttons void renderTheme(); void renderTheme(unsigned char alpha); /// destroy all icons void deleteIcons(); /// remove a single window - void removeWindow(FluxboxWindow &win); + void removeWindow(Focusable &win); /// add a single window - void addWindow(FluxboxWindow &win); + void addWindow(Focusable &win); /// add icons to the list void updateList(); /// check if window is already in the list - bool checkDuplicate(FluxboxWindow &win); - /// so we can update current window without flicker - void timedRender(); + bool checkDuplicate(Focusable &win); BScreen &m_screen; Container m_icon_container; IconbarTheme &m_theme; - // cached pixmaps - FbTk::CachedPixmap m_focused_pm, m_unfocused_pm; - // some are a fraction bigger due to rounding - FbTk::CachedPixmap m_focused_err_pm, m_unfocused_err_pm; FbTk::CachedPixmap m_empty_pm; ///< pixmap for empty container IconList m_icon_list; FbTk::Resource<Mode> m_rc_mode; - FbTk::Resource<WheelMode> m_wheel_mode; FbTk::Resource<Container::Alignment> m_rc_alignment; ///< alignment of buttons FbTk::Resource<int> m_rc_client_width; ///< size of client button in LEFT/RIGHT mode FbTk::Resource<unsigned int> m_rc_client_padding; ///< padding of the text FbTk::Resource<bool> m_rc_use_pixmap; ///< if iconbar should use win pixmap or not - FbTk::Timer m_focus_timer; ///< so we can update current window without flicker while changing attached clients FbMenu m_menu; unsigned char m_alpha; };
M src/Keys.ccsrc/Keys.cc

@@ -101,18 +101,7 @@ using std::vector;

using std::ifstream; using std::pair; -Keys::Keys(): - m_display(FbTk::App::instance()->display()) -{ - typedef std::list<BScreen *> ScreenList; - ScreenList screen_list = Fluxbox::instance()->screenList(); - ScreenList::iterator it = screen_list.begin(); - ScreenList::iterator it_end = screen_list.end(); - - for (; it != it_end; ++it) - m_window_list.push_back(RootWindow(m_display,(*it)->screenNumber())); - -} +Keys::Keys(): m_display(FbTk::App::instance()->display()) { } Keys::~Keys() { ungrabKeys();

@@ -127,37 +116,69 @@ delete map_it->second;

m_map.clear(); } +// keys are only grabbed in global context void Keys::grabKey(unsigned int key, unsigned int mod) { - std::list<Window>::iterator it = m_window_list.begin(); - std::list<Window>::iterator it_end = m_window_list.end(); + WindowMap::iterator it = m_window_map.begin(); + WindowMap::iterator it_end = m_window_map.end(); - for (; it != it_end; ++it) - FbTk::KeyUtil::grabKey(key, mod, *it); + for (; it != it_end; ++it) { + if ((it->second & Keys::GLOBAL) > 0) + FbTk::KeyUtil::grabKey(key, mod, it->first); + } } +// keys are only grabbed in global context void Keys::ungrabKeys() { - std::list<Window>::iterator it = m_window_list.begin(); - std::list<Window>::iterator it_end = m_window_list.end(); + WindowMap::iterator it = m_window_map.begin(); + WindowMap::iterator it_end = m_window_map.end(); - for (; it != it_end; ++it) - FbTk::KeyUtil::ungrabKeys(*it); + for (; it != it_end; ++it) { + if ((it->second & Keys::GLOBAL) > 0) + FbTk::KeyUtil::ungrabKeys(it->first); + } } -void Keys::grabButton(unsigned int button, unsigned int mod) { - std::list<Window>::iterator it = m_window_list.begin(); - std::list<Window>::iterator it_end = m_window_list.end(); +// ON_DESKTOP context doesn't need to be grabbed +void Keys::grabButton(unsigned int button, unsigned int mod, int context) { + WindowMap::iterator it = m_window_map.begin(); + WindowMap::iterator it_end = m_window_map.end(); - for (; it != it_end; ++it) - FbTk::KeyUtil::grabButton(button, mod, *it, - ButtonPressMask|ButtonReleaseMask); + for (; it != it_end; ++it) { + if ((context & it->second & ~Keys::ON_DESKTOP) > 0) + FbTk::KeyUtil::grabButton(button, mod, it->first, + ButtonPressMask|ButtonReleaseMask); + } } void Keys::ungrabButtons() { - std::list<Window>::iterator it = m_window_list.begin(); - std::list<Window>::iterator it_end = m_window_list.end(); + WindowMap::iterator it = m_window_map.begin(); + WindowMap::iterator it_end = m_window_map.end(); for (; it != it_end; ++it) - FbTk::KeyUtil::ungrabButtons(*it); + FbTk::KeyUtil::ungrabButtons(it->first); +} + +void Keys::grabWindow(Window win) { + if (!m_keylist) + return; + + // make sure the window is in our list + WindowMap::iterator win_it = m_window_map.find(win); + if (win_it == m_window_map.end()) + return; + + keylist_t::iterator it = m_keylist->keylist.begin(); + keylist_t::iterator it_end = m_keylist->keylist.end(); + for (; it != it_end; ++it) { + // keys are only grabbed in global context + if ((win_it->second & Keys::GLOBAL) > 0 && (*it)->type == KeyPress) + FbTk::KeyUtil::grabKey((*it)->key, (*it)->mod, win); + // ON_DESKTOP buttons don't need to be grabbed + else if ((win_it->second & (*it)->context & ~Keys::ON_DESKTOP) > 0 && + (*it)->type == ButtonPress) + FbTk::KeyUtil::grabButton((*it)->key, (*it)->mod, win, + ButtonPressMask|ButtonReleaseMask); + } } /**

@@ -278,6 +299,8 @@ if(tmpmod)

mod |= tmpmod; //If it's a modifier else if (strcasecmp("ondesktop", val[argc].c_str()) == 0) context |= ON_DESKTOP; + else if (strcasecmp("ontoolbar", val[argc].c_str()) == 0) + context |= ON_TOOLBAR; else if (strcasecmp("NONE",val[argc].c_str())) { // check if it's a mouse button if (!strcasecmp(val[argc].substr(0,5).c_str(), "mouse") &&

@@ -349,16 +372,15 @@ return false;

} // return true if bound to a command, else false -bool Keys::doAction(int type, unsigned int mods, unsigned int key) { +bool Keys::doAction(int type, unsigned int mods, unsigned int key, + int context) { static t_key* next_key = m_keylist; if (!next_key) next_key = m_keylist; mods = FbTk::KeyUtil::instance().cleanMods(mods); - // at the moment, any key/button that gets here is on root window - // context will need to be added as an argument to doAction, though - t_key *temp_key = next_key->find(type, mods, key, ON_DESKTOP|GLOBAL); + t_key *temp_key = next_key->find(type, mods, key, context); // need to save this for emacs-style keybindings static t_key *saved_keymode = 0;

@@ -396,6 +418,19 @@ next_key = 0;

return true; } +/// adds the window to m_window_map, so we know to grab buttons on it +void Keys::registerWindow(Window win, int context) { + m_window_map[win] = context; + grabWindow(win); +} + +/// remove the window from the window map, probably being deleted +void Keys::unregisterWindow(Window win) { + FbTk::KeyUtil::ungrabKeys(win); + FbTk::KeyUtil::ungrabButtons(win); + m_window_map.erase(win); +} + /** deletes the tree and load configuration returns true on success else false

@@ -419,14 +454,13 @@ keylist_t::iterator it = keyMode->keylist.begin();

keylist_t::iterator it_end = keyMode->keylist.end(); for (; it != it_end; ++it) { if ((*it)->type == KeyPress) - grabKey((*it)->key,(*it)->mod); - else if ((*it)->context == GLOBAL) - grabButton((*it)->key,(*it)->mod); - // we must use root window's event mask to get ON_DESKTOP events + grabKey((*it)->key, (*it)->mod); + else + grabButton((*it)->key, (*it)->mod, (*it)->context); } m_keylist = keyMode; } - + Keys::t_key::t_key(int type_, unsigned int mod_, unsigned int key_, int context_, FbTk::RefCount<FbTk::Command> command) { key = key_;
M src/Keys.hhsrc/Keys.hh

@@ -25,7 +25,6 @@ #ifndef KEYS_HH

#define KEYS_HH #include <string> -#include <vector> #include <list> #include <map> #include <X11/Xlib.h>

@@ -53,11 +52,7 @@ ON_SLIT = 0x80

// and so on... }; - /** - Constructor - @param display display connection - @param filename file to load, default none - */ + /// constructor explicit Keys(); /// destructor ~Keys();

@@ -80,7 +75,12 @@

/** do action from XKeyEvent; return false if not bound to anything */ - bool doAction(int type, unsigned int mods, unsigned int key); + bool doAction(int type, unsigned int mods, unsigned int key, int context); + + /// register a window so that proper keys/buttons get grabbed on it + void registerWindow(Window win, int context); + /// unregister window + void unregisterWindow(Window win); /** Reload configuration from filename

@@ -94,8 +94,9 @@ void deleteTree();

void grabKey(unsigned int key, unsigned int mod); void ungrabKeys(); - void grabButton(unsigned int button, unsigned int mod); + void grabButton(unsigned int button, unsigned int mod, int context); void ungrabButtons(); + void grabWindow(Window win); // Load default keybindings for when there are errors loading the initial one void loadDefaults();

@@ -103,7 +104,7 @@

std::string m_filename; class t_key; - typedef std::vector<t_key*> keylist_t; + typedef std::list<t_key*> keylist_t; class t_key { public:

@@ -116,11 +117,12 @@ t_key *find(int type_, unsigned int mod_, unsigned int key_,

int context_) { // t_key ctor sets context_ of 0 to GLOBAL, so we must here too context_ = context_ ? context_ : GLOBAL; - for (size_t i = 0; i < keylist.size(); i++) { - if (keylist[i]->type == type_ && keylist[i]->key == key_ && - (keylist[i]->context & context_) > 0 && keylist[i]->mod == + keylist_t::iterator it = keylist.begin(), it_end = keylist.end(); + for (; it != it_end; it++) { + if ((*it)->type == type_ && (*it)->key == key_ && + ((*it)->context & context_) > 0 && (*it)->mod == FbTk::KeyUtil::instance().isolateModifierMask(mod_)) - return keylist[i]; + return *it; } return 0; }

@@ -141,7 +143,9 @@ t_key *m_keylist;

keyspace_t m_map; Display *m_display; ///< display connection - std::list<Window> m_window_list; + + typedef std::map<Window, int> WindowMap; + WindowMap m_window_map; }; #endif // KEYS_HH
M src/Layer.hhsrc/Layer.hh

@@ -22,6 +22,9 @@

#ifndef LAYER_HH #define LAYER_HH +#include <string> +using std::string; + /** * (This is not the layer->raise/lower handling stuff, @see FbTk::Layer) * Class to store layer numbers (special Resource type)

@@ -42,7 +45,53 @@ NUM_LAYERS = 13

}; explicit Layer(int i) : m_num(i) {}; + + static int getNumFromString(string &str) { + int tempnum = 0; + if (sscanf(str.c_str(), "%d", &tempnum) == 1) + return tempnum; + if (strcasecmp(str.c_str(), "Menu") == 0) + return ::Layer::MENU; + if (strcasecmp(str.c_str(), "AboveDock") == 0) + return ::Layer::ABOVE_DOCK; + if (strcasecmp(str.c_str(), "Dock") == 0) + return ::Layer::DOCK; + if (strcasecmp(str.c_str(), "Top") == 0) + return ::Layer::TOP; + if (strcasecmp(str.c_str(), "Normal") == 0) + return ::Layer::NORMAL; + if (strcasecmp(str.c_str(), "Bottom") == 0) + return ::Layer::BOTTOM; + if (strcasecmp(str.c_str(), "Desktop") == 0) + return ::Layer::DESKTOP; + return -1; + } + + static string getString(int num) { + switch (num) { + case ::Layer::MENU: + return string("Menu"); + case ::Layer::ABOVE_DOCK: + return string("AboveDock"); + case ::Layer::DOCK: + return string("Dock"); + case ::Layer::TOP: + return string("Top"); + case ::Layer::NORMAL: + return string("Normal"); + case ::Layer::BOTTOM: + return string("Bottom"); + case ::Layer::DESKTOP: + return string("Desktop"); + default: + char tmpstr[128]; + sprintf(tmpstr, "%d", num); + return string(tmpstr); + } + } + int getNum() const { return m_num; } + string getString() const { return getString(m_num); } Layer &operator=(int num) { m_num = num; return *this; }
M src/Makefile.amsrc/Makefile.am

@@ -87,9 +87,8 @@ TOOLBAR_SOURCE = Toolbar.hh Toolbar.cc \

ToolbarTheme.hh ToolbarTheme.cc ToolbarItem.hh ToolbarItem.cc \ ClockTool.hh ClockTool.cc \ WorkspaceNameTool.hh WorkspaceNameTool.cc WorkspaceNameTheme.hh \ - IconbarTool.hh IconbarTool.cc IconbarTheme.hh IconbarTheme.cc \ + IconbarTool.hh IconbarTool.cc \ ToolTheme.hh ToolTheme.cc \ - IconButton.hh IconButton.cc \ SystemTray.hh SystemTray.cc \ GenericTool.hh GenericTool.cc \ ButtonTool.hh ButtonTool.cc ButtonTheme.hh ButtonTheme.cc \

@@ -102,7 +101,6 @@ FbAtoms.hh FbAtoms.cc FbWinFrame.hh FbWinFrame.cc \

FbWinFrameTheme.hh FbWinFrameTheme.cc \ fluxbox.cc fluxbox.hh \ Keys.cc Keys.hh main.cc \ - Netizen.cc Netizen.hh \ RootTheme.hh RootTheme.cc \ FbRootWindow.hh FbRootWindow.cc \ Screen.cc Screen.hh ScreenResources.cc \

@@ -117,7 +115,6 @@ IntResMenuItem.hh FbMenu.hh FbMenu.cc \

WinClient.hh WinClient.cc \ Strut.hh \ Xinerama.hh \ - IconMenuItem.hh \ Xutil.hh Xutil.cc \ CurrentWindowCmd.hh CurrentWindowCmd.cc \ WorkspaceCmd.hh WorkspaceCmd.cc \

@@ -135,7 +132,7 @@ Parser.hh Parser.cc FbMenuParser.hh FbMenuParser.cc \

StyleMenuItem.hh StyleMenuItem.cc \ RootCmdMenuItem.hh RootCmdMenuItem.cc\ MenuCreator.hh MenuCreator.cc \ - IconMenu.hh IconMenu.cc \ + ClientMenu.hh ClientMenu.cc \ WorkspaceMenu.hh WorkspaceMenu.cc \ FocusModelMenuItem.hh \ ToggleMenu.hh \

@@ -146,11 +143,13 @@ FocusControl.hh FocusControl.cc \

PlacementStrategy.hh \ CascadePlacement.hh CascadePlacement.cc \ ColSmartPlacement.hh ColSmartPlacement.cc \ + MinOverlapPlacement.hh MinOverlapPlacement.cc \ RowSmartPlacement.hh RowSmartPlacement.cc \ ScreenPlacement.hh ScreenPlacement.cc \ UnderMousePlacement.hh UnderMousePlacement.cc \ - WinClientUtil.hh WinClientUtil.cc \ AttentionNoticeHandler.hh AttentionNoticeHandler.cc \ + IconButton.hh IconButton.cc \ + IconbarTheme.hh IconbarTheme.cc \ STLUtil.hh \ ${newwmspec_SOURCE} ${gnome_SOURCE} \ ${REMEMBER_SOURCE} ${TOOLBAR_SOURCE}
M src/MenuCreator.ccsrc/MenuCreator.cc

@@ -31,8 +31,7 @@ #include "fluxbox.hh"

#include "Window.hh" #include "WindowCmd.hh" -#include "FbMenu.hh" -#include "IconMenu.hh" +#include "ClientMenu.hh" #include "WorkspaceMenu.hh" #include "LayerMenu.hh" #include "SendToMenu.hh"

@@ -52,7 +51,6 @@ #include "FbTk/SimpleCommand.hh"

#include "FbTk/StringUtil.hh" #include "FbTk/FileUtil.hh" #include "FbTk/MenuSeparator.hh" -#include "FbTk/MenuIcon.hh" #include "FbTk/Transparent.hh" #include <iostream>

@@ -470,8 +468,8 @@

bool MenuCreator::createFromFile(const string &filename, FbTk::Menu &inject_into, bool require_begin) { - string real_filename = FbTk::StringUtil::expandFilename(filename); + FbMenuParser parser(real_filename); if (!parser.isLoaded()) return false;

@@ -521,7 +519,8 @@ BScreen *screen = Fluxbox::instance()->findScreen(screen_num);

if (screen == 0) return 0; if (type == "iconmenu") { - return new IconMenu(*screen); + return new ClientMenu(*screen, screen->iconList(), + &screen->iconListSig()); } else if (type == "workspacemenu") { return new WorkspaceMenu(*screen); } else if (type == "windowmenu") {
A src/MinOverlapPlacement.cc

@@ -0,0 +1,186 @@

+// MinOverlapPlacement.cc +// Copyright (c) 2007 Fluxbox Team (fluxgen at fluxbox dot org) +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR (*it) +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR (*it)WISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR (*it) +// DEALINGS IN THE SOFTWARE. + +// $Id$ + +#include "MinOverlapPlacement.hh" + +#include "Window.hh" +#include "Screen.hh" + +ScreenPlacement::PlacementPolicy MinOverlapPlacement::s_policy = ScreenPlacement::ROWMINOVERLAPPLACEMENT; +ScreenPlacement::RowDirection MinOverlapPlacement::s_row_dir = ScreenPlacement::LEFTRIGHT; +ScreenPlacement::ColumnDirection MinOverlapPlacement::s_col_dir = ScreenPlacement::TOPBOTTOM; + +MinOverlapPlacement::MinOverlapPlacement(ScreenPlacement::PlacementPolicy policy) { + s_policy = policy; +} + +bool MinOverlapPlacement::placeWindow( + const std::list<FluxboxWindow *> &windowlist, + const FluxboxWindow &win, int &place_x, int &place_y) { + + // view (screen + head) constraints + int head = (signed) win.screen().getCurrHead(); + int head_left = (signed) win.screen().maxLeft(head); + int head_right = (signed) win.screen().maxRight(head); + int head_top = (signed) win.screen().maxTop(head); + int head_bot = (signed) win.screen().maxBottom(head); + + const ScreenPlacement &screen_placement = + dynamic_cast<const ScreenPlacement &>(win.screen().placementStrategy()); + s_row_dir = screen_placement.rowDirection(); + s_col_dir = screen_placement.colDirection(); + + int win_w = win.width() + win.fbWindow().borderWidth()*2 + win.widthOffset(); + int win_h = win.height() + win.fbWindow().borderWidth()*2 + win.heightOffset(); + + // we keep a set of open spaces on the desktop, sorted by size/location + std::set<Region> region_set; + + // initialize the set of regions to contain the entire head + region_set.insert(Region(Region::TOPLEFT, head_left, head_top)); + region_set.insert(Region(Region::TOPRIGHT, head_right - win_w, head_top)); + region_set.insert(Region(Region::BOTTOMLEFT, head_left, head_bot - win_h)); + region_set.insert(Region(Region::BOTTOMRIGHT, head_right - win_w, + head_bot - win_h)); + + // go through the list of windows, creating other reasonable placements + // at the end, we'll find the one with minimum overlap + // the size of this set is at most 2(n+2)(n+1) (n = number of windows) + // finding overlaps is therefore O(n^3), but it can probably be improved + std::list<FluxboxWindow *>::const_reverse_iterator it = windowlist.rbegin(), + it_end = windowlist.rend(); + for (; it != it_end; ++it) { + + // get the dimensions of the window + int left = (*it)->x() - (*it)->xOffset(); + int top = (*it)->y() - (*it)->yOffset(); + int right = left + (*it)->width() + + 2*(*it)->frame().window().borderWidth() + + (*it)->widthOffset(); + int bottom = top + (*it)->height() + + 2*(*it)->frame().window().borderWidth() + + (*it)->heightOffset(); + + // go through the list of regions + // if this window overlaps that region and the new window still fits, + // it will create new regions to test + std::set<Region>::iterator reg_it = region_set.begin(); + for (; reg_it != region_set.end(); ++reg_it) { + + switch (reg_it->corner) { + case Region::TOPLEFT: + if (right > reg_it->x && bottom > reg_it->y) { + if (bottom + win_h <= head_bot) + region_set.insert(Region(Region::TOPLEFT, + reg_it->x, bottom)); + if (right + win_w <= head_right) + region_set.insert(Region(Region::TOPLEFT, + right, reg_it->y)); + } + break; + case Region::TOPRIGHT: + if (left < reg_it->x + win_w && bottom > reg_it->y) { + if (bottom + win_h <= head_bot) + region_set.insert(Region(Region::TOPRIGHT, + reg_it->x, bottom)); + if (left - win_w >= head_left) + region_set.insert(Region(Region::TOPRIGHT, + left - win_w, reg_it->y)); + } + break; + case Region::BOTTOMRIGHT: + if (left < reg_it->x + win_w && top < reg_it->y + win_h) { + if (top - win_h >= head_top) + region_set.insert(Region(Region::BOTTOMRIGHT, + reg_it->x, top - win_h)); + if (left - win_w >= head_left) + region_set.insert(Region(Region::BOTTOMRIGHT, + left - win_w, reg_it->y)); + } + break; + case Region::BOTTOMLEFT: + if (right > reg_it->x && top < reg_it->y + win_h) { + if (top - win_h >= head_top) + region_set.insert(Region(Region::BOTTOMLEFT, + reg_it->x, top - win_h)); + if (right + win_w <= head_right) + region_set.insert(Region(Region::BOTTOMLEFT, + right, reg_it->y)); + } + break; + } + + } + } + + // choose the region with minimum overlap + int min_so_far = win_w * win_h * windowlist.size() + 1; + std::set<Region>::iterator min_reg = region_set.end(); + + std::set<Region>::iterator reg_it = region_set.begin(); + for (; reg_it != region_set.end(); ++reg_it) { + + int overlap = 0; + it = windowlist.rbegin(); + for (; it != windowlist.rend(); ++it) { + + // get the dimensions of the window + int left = (*it)->x() - (*it)->xOffset(); + int top = (*it)->y() - (*it)->yOffset(); + int right = left + (*it)->width() + + 2*(*it)->frame().window().borderWidth() + + (*it)->widthOffset(); + int bottom = top + (*it)->height() + + 2*(*it)->frame().window().borderWidth() + + (*it)->heightOffset(); + + // get the coordinates of the overlap region + int min_right = (right > reg_it->x + win_w) ? + reg_it->x + win_w : right; + int min_bottom = (bottom > reg_it->y + win_h) ? + reg_it->y + win_h : bottom; + int max_left = (left > reg_it->x) ? left : reg_it->x; + int max_top = (top > reg_it->y) ? top : reg_it->y; + + // now compute the overlap and add to running total + if (min_right > max_left && min_bottom > max_top) + overlap += (min_right - max_left) * (min_bottom - max_top); + + } + + // if this placement is better, use it + if (overlap < min_so_far) { + min_reg = reg_it; + min_so_far = overlap; + if (overlap == 0) // can't do better than this + break; + } + + } + + // place window + place_x = min_reg->x + win.xOffset(); + place_y = min_reg->y + win.yOffset(); + + return true; +}
A src/MinOverlapPlacement.hh

@@ -0,0 +1,83 @@

+// MinOverlapPlacement.hh +// Copyright (c) 2007 Fluxbox Team (fluxgen at fluxbox dot org) +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +// $Id$ + +#ifndef MINOVERLAPPLACEMENT_HH +#define MINOVERLAPPLACEMENT_HH + +#include "ScreenPlacement.hh" + +class MinOverlapPlacement: public PlacementStrategy { +public: + MinOverlapPlacement(ScreenPlacement::PlacementPolicy policy); + + bool placeWindow(const std::list<FluxboxWindow *> &windowlist, + const FluxboxWindow &win, + int &place_x, int &place_y); + +private: + class Region { + public: + + enum Corner { + TOPLEFT, + TOPRIGHT, + BOTTOMLEFT, + BOTTOMRIGHT + } corner; // indicates the corner of the window that will be placed + + Region(Corner _corner, int _x, int _y): + corner(_corner), x(_x), y(_y) { }; + + // do all STL set implementations use this for sorting? + bool operator <(const Region &o) const { + // for now, I'm assuming RowSmartPlacement, so y is more important + switch (MinOverlapPlacement::s_policy) { + case ScreenPlacement::ROWMINOVERLAPPLACEMENT: + // if we're making rows, y-value is most important + if (y != o.y) + return ((y < o.y) ^ (s_col_dir == ScreenPlacement::BOTTOMTOP)); + if (x != o.x) + return ((x < o.x) ^ (s_row_dir == ScreenPlacement::RIGHTLEFT)); + return (corner < o.corner); + case ScreenPlacement::COLMINOVERLAPPLACEMENT: + // if we're making columns, x-value is most important + if (x != o.x) + return ((x < o.x) ^ (s_row_dir == ScreenPlacement::RIGHTLEFT)); + if (y != o.y) + return ((y < o.y) ^ (s_col_dir == ScreenPlacement::BOTTOMTOP)); + return (corner < o.corner); + default: + return false; + } + } + + // position where the top left corner of the window will be placed + int x, y; + }; + + static ScreenPlacement::PlacementPolicy s_policy; + static ScreenPlacement::RowDirection s_row_dir; + static ScreenPlacement::ColumnDirection s_col_dir; +}; + +#endif // MINOVERLAPPLACEMENT_HH
D src/Netizen.cc

@@ -1,112 +0,0 @@

-// Netizen.cc for Fluxbox -// Copyright (c) 2001 - 2003 Henrik Kinnunen (fluxgen at fluxbox dot org) -// -// Netizen.cc for Blackbox - An X11 Window Manager -// Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -#include "Netizen.hh" - -#include "Screen.hh" -#include "FbAtoms.hh" - -#include "FbTk/App.hh" - -Netizen::Netizen(const BScreen &scr, Window win): - m_screen(scr), - m_display(FbTk::App::instance()->display()), - m_window(win) { - - event.type = ClientMessage; - event.xclient.message_type = FbAtoms::instance()->getFluxboxStructureMessagesAtom(); - event.xclient.display = m_display; - event.xclient.window = window(); - event.xclient.format = 32; - event.xclient.data.l[0] = FbAtoms::instance()->getFluxboxNotifyStartupAtom(); - event.xclient.data.l[1] = event.xclient.data.l[2] = - event.xclient.data.l[3] = event.xclient.data.l[4] = 0l; - - XSendEvent(m_display, window(), False, NoEventMask, &event); -} - - -void Netizen::sendWorkspaceCount() { - - event.xclient.data.l[0] = FbAtoms::instance()->getFluxboxNotifyWorkspaceCountAtom(); - event.xclient.data.l[1] = m_screen.numberOfWorkspaces(); - - XSendEvent(m_display, window(), False, NoEventMask, &event); -} - - -void Netizen::sendCurrentWorkspace() { - - event.xclient.data.l[0] = FbAtoms::instance()->getFluxboxNotifyCurrentWorkspaceAtom(); - event.xclient.data.l[1] = m_screen.currentWorkspaceID(); - - XSendEvent(m_display, window(), False, NoEventMask, &event); -} - - -void Netizen::sendWindowFocus(Window w) { - event.xclient.data.l[0] = FbAtoms::instance()->getFluxboxNotifyWindowFocusAtom(); - event.xclient.data.l[1] = w; - - XSendEvent(m_display, window(), False, NoEventMask, &event); -} - - -void Netizen::sendWindowAdd(Window w, unsigned long wkspc) { - event.xclient.data.l[0] = FbAtoms::instance()->getFluxboxNotifyWindowAddAtom(); - event.xclient.data.l[1] = w; - event.xclient.data.l[2] = wkspc; - - XSendEvent(m_display, window(), False, NoEventMask, &event); - - event.xclient.data.l[2] = 0l; -} - - -void Netizen::sendWindowDel(Window w) { - event.xclient.data.l[0] = FbAtoms::instance()->getFluxboxNotifyWindowDelAtom(); - event.xclient.data.l[1] = w; - - XSendEvent(m_display, window(), False, NoEventMask, &event); -} - - -void Netizen::sendWindowRaise(Window w) { - event.xclient.data.l[0] = FbAtoms::instance()->getFluxboxNotifyWindowRaiseAtom(); - event.xclient.data.l[1] = w; - - XSendEvent(m_display, window(), False, NoEventMask, &event); -} - - -void Netizen::sendWindowLower(Window w) { - event.xclient.data.l[0] = FbAtoms::instance()->getFluxboxNotifyWindowLowerAtom(); - event.xclient.data.l[1] = w; - - XSendEvent(m_display, window(), False, NoEventMask, &event); -} - -void Netizen::sendConfigNotify(XEvent &ev) { - XSendEvent(m_display, window(), False, StructureNotifyMask, &ev); -}
D src/Netizen.hh

@@ -1,58 +0,0 @@

-// Netizen.hh for Fluxbox -// Copyright (c) 2002-2003 Henrik Kinnunen (fluxgen at fluxbox dot org) -// -// Netizen.hh for Blackbox - An X11 Window Manager -// Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -#ifndef NETIZEN_HH -#define NETIZEN_HH - -#include <X11/Xlib.h> - -class BScreen; - -class Netizen { -public: - Netizen(const BScreen &scr, Window w); - - inline Window window() const { return m_window; } - - void sendWorkspaceCount(); - void sendCurrentWorkspace(); - - void sendWindowFocus(Window w); - void sendWindowAdd(Window w, unsigned long wkspc); - void sendWindowDel(Window w); - void sendWindowRaise(Window w); - void sendWindowLower(Window w); - - void sendConfigNotify(XEvent &xe); -private: - const BScreen &m_screen; - Display *m_display; ///< display connection - Window m_window; - XEvent event; - -}; - - -#endif // _NETIZEN_HH_ -
M src/PlacementStrategy.hhsrc/PlacementStrategy.hh

@@ -24,7 +24,7 @@

#ifndef PLACEMENTSTRATEGY_HH #define PLACEMENTSTRATEGY_HH -#include <vector> +#include <list> class FluxboxWindow;

@@ -37,7 +37,7 @@ * @param place_x x placement of specific strategy

* @param place_y y placement of specific strategy * @return true if the strategy found a placement for the window */ - virtual bool placeWindow(const std::vector<FluxboxWindow *> &windowlist, + virtual bool placeWindow(const std::list<FluxboxWindow *> &windowlist, const FluxboxWindow &win, int &place_x, int &place_y) = 0; virtual ~PlacementStrategy() { }
M src/Remember.ccsrc/Remember.cc

@@ -247,8 +247,8 @@

}; // end anonymous namespace -Application::Application(int grouped) - : is_grouped(grouped) +Application::Application(bool grouped, ClientPattern *pat) + : is_grouped(grouped), group_pattern(pat) { decostate_remember = dimensions_remember =

@@ -328,7 +328,7 @@ }

Application * Remember::add(WinClient &winclient) { ClientPattern *p = new ClientPattern(); - Application *app = new Application(0); + Application *app = new Application(false); // by default, we match against the WMClass of a window (instance and class strings) string win_name = ::escapeRememberChars(p->getProperty(ClientPattern::NAME, winclient));

@@ -520,11 +520,13 @@ We REMOVE and delete any matching patterns from the old list, as they're

effectively moved into the new */ -Application *Remember::findMatchingPatterns(ClientPattern *pat, Patterns *patlist, int is_group) { +Application *Remember::findMatchingPatterns(ClientPattern *pat, Patterns *patlist, bool is_group, ClientPattern *match_pat) { Patterns::iterator it = patlist->begin(); Patterns::iterator it_end = patlist->end(); for (; it != it_end; ++it) { - if (it->first->equals(*pat) && is_group == it->second->is_grouped) { + if (it->first->equals(*pat) && is_group == it->second->is_grouped && + ((match_pat == 0 && *it->second->group_pattern == 0) || + (match_pat && match_pat->equals(**it->second->group_pattern)))) { Application *ret = it->second; // find any previous or subsequent matching ones and delete

@@ -576,7 +578,8 @@ m_last_timestamp = timestamp;

if (!apps_file.eof()) { string line; int row = 0; - int in_group = 0; + bool in_group = false; + ClientPattern *pat = 0; list<ClientPattern *> grouped_pats; while (getline(apps_file, line) && ! apps_file.eof()) { row++;

@@ -592,11 +595,11 @@ '[', ']');

if (pos > 0 && strcasecmp(key.c_str(), "app") == 0) { ClientPattern *pat = new ClientPattern(line.c_str() + pos); - if (in_group == 0) { + if (!in_group) { if ((err = pat->error()) == 0) { - Application *app = findMatchingPatterns(pat, old_pats, 0); + Application *app = findMatchingPatterns(pat, old_pats, false); if (!app) - app = new Application(0); + app = new Application(false); m_pats->push_back(make_pair(pat, app)); row += parseApp(apps_file, *app);

@@ -615,12 +618,9 @@ }

// save the item even if it was bad (aren't we nice) m_startups.push_back(line.substr(pos)); } else if (pos > 0 && strcasecmp(key.c_str(), "group") == 0) { - in_group = Application::IS_GROUPED; - pos = FbTk::StringUtil::getStringBetween(key, - line.c_str() + pos, - '(', ')'); - if (pos > 0 && strcasecmp(key.c_str(), "workspace") == 0) - in_group |= Application::MATCH_WORKSPACE; + in_group = true; + if (line.find('(') != string::npos) + pat = new ClientPattern(line.c_str() + pos); } else if (in_group) { // otherwise assume that it is the start of the attributes Application *app = 0;

@@ -628,12 +628,12 @@ // search for a matching app

list<ClientPattern *>::iterator it = grouped_pats.begin(); list<ClientPattern *>::iterator it_end = grouped_pats.end(); while (!app && it != it_end) { - app = findMatchingPatterns(*it, old_pats, in_group); + app = findMatchingPatterns(*it, old_pats, in_group, pat); ++it; } if (!app) - app = new Application(in_group); + app = new Application(in_group, pat); while (!grouped_pats.empty()) { // associate all the patterns with this app

@@ -647,7 +647,7 @@ // otherwise parse the app

if (!(pos>0 && strcasecmp(key.c_str(), "end") == 0)) { row += parseApp(apps_file, *app, &line); } - in_group = 0; + in_group = false; } else cerr<<"Error in apps file on line "<<row<<"."<<endl;

@@ -725,8 +725,8 @@ continue;

grouped_apps.insert(&a); // otherwise output this whole group apps_file << "[group]"; - if (a.is_grouped & Application::MATCH_WORKSPACE) - apps_file << " (workspace)"; + if (*a.group_pattern) + apps_file << " " << a.group_pattern->toString(); apps_file << endl; Patterns::iterator git = m_pats->begin();

@@ -1151,10 +1151,7 @@ Clients::iterator it_end = m_clients.end();

for (; it != it_end; ++it) { if (it->second == app && it->first->fbwindow() && &screen == &it->first->screen() && - (!(app->is_grouped & Application::MATCH_WORKSPACE) || - it->first->fbwindow()->workspaceNumber() == - screen.currentWorkspaceID())) - + (!*app->group_pattern || app->group_pattern->match(*it->first))) return it->first->fbwindow(); }
M src/Remember.hhsrc/Remember.hh

@@ -29,6 +29,9 @@ #ifndef REMEMBER_HH

#define REMEMBER_HH #include "AtomHandler.hh" +#include "ClientPattern.hh" + +#include "FbTk/RefCount.hh" #include <fstream> #include <map>

@@ -40,11 +43,10 @@

class FluxboxWindow; class BScreen; class WinClient; -class ClientPattern; class Application { public: - Application(int grouped); + Application(bool grouped, ClientPattern *pat = 0); inline void forgetWorkspace() { workspace_remember = false; } inline void forgetHead() { head_remember = false; } inline void forgetDimensions() { dimensions_remember = false; }

@@ -137,14 +139,8 @@

bool save_on_close_remember; bool save_on_close; - enum { - IS_GROUPED = 0x01, - MATCH_WORKSPACE = 0x02 - // MATCH_HEAD, STUCK, ICONIFIED, etc.? - // this will probably evolve into a ClientPattern as soon as they - // match things like currentworkspace - }; - int is_grouped; + bool is_grouped; + FbTk::RefCount<ClientPattern> group_pattern; };

@@ -254,7 +250,8 @@ // returns number of lines read

// optionally can give a line to read before the first (lookahead line) int parseApp(std::ifstream &file, Application &app, std::string *first_line = 0); - Application *findMatchingPatterns(ClientPattern *pat, Patterns *patlist, int is_group); + Application *findMatchingPatterns(ClientPattern *pat, Patterns *patlist, + bool is_group, ClientPattern *match_pat = 0); std::auto_ptr<Patterns> m_pats; Clients m_clients;
M src/Resources.ccsrc/Resources.cc

@@ -202,23 +202,10 @@

template<> void FbTk::Resource<Layer>:: setFromString(const char *strval) { - int tempnum = 0; - if (sscanf(strval, "%d", &tempnum) == 1) + string str(strval); + int tempnum = ::Layer::getNumFromString(str); + if (tempnum >= 0 && tempnum < ::Layer::NUM_LAYERS) m_value = tempnum; - else if (strcasecmp(strval, "Menu") == 0) - m_value = ::Layer::MENU; - else if (strcasecmp(strval, "AboveDock") == 0) - m_value = ::Layer::ABOVE_DOCK; - else if (strcasecmp(strval, "Dock") == 0) - m_value = ::Layer::DOCK; - else if (strcasecmp(strval, "Top") == 0) - m_value = ::Layer::TOP; - else if (strcasecmp(strval, "Normal") == 0) - m_value = ::Layer::NORMAL; - else if (strcasecmp(strval, "Bottom") == 0) - m_value = ::Layer::BOTTOM; - else if (strcasecmp(strval, "Desktop") == 0) - m_value = ::Layer::DESKTOP; else setDefaultValue(); }

@@ -227,26 +214,7 @@

template<> string FbTk::Resource<Layer>:: getString() const { - switch (m_value.getNum()) { - case Layer::MENU: - return string("Menu"); - case Layer::ABOVE_DOCK: - return string("AboveDock"); - case Layer::DOCK: - return string("Dock"); - case Layer::TOP: - return string("Top"); - case Layer::NORMAL: - return string("Normal"); - case Layer::BOTTOM: - return string("Bottom"); - case Layer::DESKTOP: - return string("Desktop"); - default: - char tmpstr[128]; - sprintf(tmpstr, "%d", m_value.getNum()); - return string(tmpstr); - } + return ::Layer::getString(m_value.getNum()); } template<>
M src/RowSmartPlacement.ccsrc/RowSmartPlacement.cc

@@ -27,7 +27,7 @@ #include "Window.hh"

#include "Screen.hh" #include "ScreenPlacement.hh" -bool RowSmartPlacement::placeWindow(const std::vector<FluxboxWindow *> &windowlist, +bool RowSmartPlacement::placeWindow(const std::list<FluxboxWindow *> &windowlist, const FluxboxWindow &win, int &place_x, int &place_y) {

@@ -95,9 +95,9 @@ placed = true;

next_x = test_x + change_x; - std::vector<FluxboxWindow *>::const_iterator win_it = + std::list<FluxboxWindow *>::const_iterator win_it = windowlist.begin(); - std::vector<FluxboxWindow *>::const_iterator win_it_end = + std::list<FluxboxWindow *>::const_iterator win_it_end = windowlist.end(); for (; win_it != win_it_end && placed; ++win_it) {
M src/RowSmartPlacement.hhsrc/RowSmartPlacement.hh

@@ -28,7 +28,7 @@ #include "PlacementStrategy.hh"

class RowSmartPlacement: public PlacementStrategy { public: - bool placeWindow(const std::vector<FluxboxWindow *> &windowlist, + bool placeWindow(const std::list<FluxboxWindow *> &windowlist, const FluxboxWindow &win, int &place_x, int &place_y); };
M src/Screen.ccsrc/Screen.cc

@@ -31,7 +31,6 @@ #include "fluxbox.hh"

#include "Keys.hh" #include "Window.hh" #include "Workspace.hh" -#include "Netizen.hh" #include "Layer.hh" #include "FocusControl.hh"

@@ -287,9 +286,10 @@ const string &altscrname):

image_dither(rm, false, scrname+".imageDither", altscrname+".ImageDither"), opaque_move(rm, false, scrname + ".opaqueMove", altscrname+".OpaqueMove"), full_max(rm, false, scrname+".fullMaximization", altscrname+".FullMaximization"), + max_ignore_inc(rm, true, scrname+".maxIgnoreIncrement", altscrname+".MaxIgnoreIncrement"), + max_disable_move(rm, false, scrname+".maxDisableMove", altscrname+".MaxDisableMove"), + max_disable_resize(rm, false, scrname+".maxDisableResize", altscrname+".MaxDisableResize"), workspace_warping(rm, true, scrname+".workspacewarping", altscrname+".WorkspaceWarping"), - desktop_wheeling(rm, true, scrname+".desktopwheeling", altscrname+".DesktopWheeling"), - reverse_wheeling(rm, false, scrname+".reversewheeling", altscrname+".ReverseWheeling"), show_window_pos(rm, true, scrname+".showwindowposition", altscrname+".ShowWindowPosition"), auto_raise(rm, true, scrname+".autoRaise", altscrname+".AutoRaise"), click_raises(rm, true, scrname+".clickRaises", altscrname+".ClickRaises"),

@@ -299,6 +299,7 @@ rootcommand(rm, "", scrname+".rootCommand", altscrname+".RootCommand"),

resize_model(rm, BOTTOMRESIZE, scrname+".resizeMode", altscrname+".ResizeMode"), tab_placement(rm, FbWinFrame::TOPLEFT, scrname+".tab.placement", altscrname+".Tab.Placement"), windowmenufile(rm, "", scrname+".windowMenu", altscrname+".WindowMenu"), + typing_delay(rm, 0, scrname+".noFocusWhileTypingDelay", altscrname+".NoFocusWhileTypingDelay"), follow_model(rm, IGNORE_OTHER_WORKSPACES, scrname+".followModel", altscrname+".followModel"), user_follow_model(rm, FOLLOW_ACTIVE_WINDOW, scrname+".userFollowModel", altscrname+".UserFollowModel"), workspaces(rm, 1, scrname+".workspaces", altscrname+".Workspaces"),

@@ -327,6 +328,8 @@ altscrname+".overlay.CapStyle"),

scroll_action(rm, "", scrname+".windowScrollAction", altscrname+".WindowScrollAction"), scroll_reverse(rm, false, scrname+".windowScrollReverse", altscrname+".WindowScrollReverse"), allow_remote_actions(rm, false, scrname+".allowRemoteActions", altscrname+".AllowRemoteActions"), + clientmenu_use_pixmap(rm, true, scrname+".clientMenu.usePixmap", altscrname+".ClientMenu.UsePixmap"), + tabs_use_pixmap(rm, true, scrname+".tabs.usePixmap", altscrname+".Tabs.UsePixmap"), max_over_tabs(rm, false, scrname+".tabs.maxOver", altscrname+".Tabs.MaxOver"), default_internal_tabs(rm, true /* TODO: autoconf option? */ , scrname+".tabs.intitlebar", altscrname+".Tabs.InTitlebar") {

@@ -362,13 +365,15 @@ m_pos_window(m_root_window,

0, 0, 10, 10, false, // override redirect true), // save under + m_dummy_window(scrn, -1, -1, 1, 1, 0, true, false, CopyFromParent, + InputOnly), resource(rm, screenname, altscreenname), m_resource_manager(rm), m_name(screenname), m_altname(altscreenname), m_focus_control(new FocusControl(*this)), m_placement_strategy(new ScreenPlacement(*this)), - m_cycling(false), + m_cycling(false), m_typing_ahead(false), m_cycle_opts(0), m_xinerama_headinfo(0), m_restart(false), m_shutdown(false) {

@@ -423,6 +428,10 @@ rootWindow().depth());

FbTk::EventManager *evm = FbTk::EventManager::instance(); evm->add(*this, rootWindow()); + Keys *keys = Fluxbox::instance()->keys(); + if (keys) + keys->registerWindow(rootWindow().window(), + Keys::GLOBAL|Keys::ON_DESKTOP); rootWindow().setCursor(XCreateFontCursor(disp, XC_left_ptr)); // load this screens resources

@@ -510,7 +519,6 @@ }

} changeWorkspaceID(first_desktop); - updateNetizenWorkspaceCount(); // we need to load win frame theme before we create any fluxbox window // and after we've load the resources

@@ -547,6 +555,9 @@ return;

FbTk::EventManager *evm = FbTk::EventManager::instance(); evm->remove(rootWindow()); + Keys *keys = Fluxbox::instance()->keys(); + if (keys) + keys->unregisterWindow(rootWindow().window()); if (m_rootmenu.get() != 0) m_rootmenu->removeAll();

@@ -582,7 +593,6 @@

removeWorkspaceNames(); using namespace STLUtil; destroyAndClear(m_workspaces_list); - destroyAndClear(m_netizen_list); destroyAndClear(m_managed_resources); //why not destroyAndClear(m_icon_list); ?

@@ -816,7 +826,44 @@ m_bg_change_sig.notify();

} void BScreen::keyPressEvent(XKeyEvent &ke) { - Fluxbox::instance()->keys()->doAction(ke.type, ke.state, ke.keycode); + if (!m_typing_ahead) { + Fluxbox::instance()->keys()->doAction(ke.type, ke.state, ke.keycode, + Keys::GLOBAL|Keys::ON_DESKTOP); + return; + } + + KeySym ks; + char keychar[1]; + XLookupString(&ke, keychar, 1, &ks, 0); + // a modifier key by itself doesn't do anything + if (IsModifierKey(ks)) + return; + + switch (ks) { + case XK_Escape: + case XK_KP_Enter: + case XK_Return: + m_type_ahead.reset(); + FbTk::EventManager::instance()->ungrabKeyboard(); + break; + case XK_BackSpace: + m_type_ahead.putBackSpace(); + m_matches = m_type_ahead.matched(); + break; + case XK_Tab: + case XK_ISO_Left_Tab: + m_type_ahead.seek(); + focusControl().cycleFocus(m_matches, m_cycle_opts, (bool)(ke.state & ShiftMask)); + break; + default: + m_matches = m_type_ahead.putCharacter(keychar[0]); + // if focused win doesn't match new search string, find the next one + if (!m_matches.empty() && + std::find(m_matches.begin(), m_matches.end(), + FocusControl::focusedWindow()) == m_matches.end()) + focusControl().cycleFocus(m_matches, m_cycle_opts); + break; + } } void BScreen::keyReleaseEvent(XKeyEvent &ke) {

@@ -835,15 +882,28 @@ if (be.button == 1 && !isRootColormapInstalled())

imageControl().installRootColormap(); Keys *keys = Fluxbox::instance()->keys(); - keys->doAction(be.type, be.state, be.button); + keys->doAction(be.type, be.state, be.button, Keys::GLOBAL|Keys::ON_DESKTOP); } void BScreen::notifyUngrabKeyboard() { m_cycling = false; + m_typing_ahead = false; + m_type_ahead.reset(); focusControl().stopCyclingFocus(); } -void BScreen::cycleFocus(int options, bool reverse) { +void BScreen::startTypeAheadFocus(std::list<Focusable *> &winlist, + const ClientPattern *pat) { + m_type_ahead.init(winlist); + m_matches = winlist; + FbTk::EventManager *evm = FbTk::EventManager::instance(); + if (!m_typing_ahead && !m_cycling) + evm->grabKeyboard(*this, rootWindow().window()); + m_cycle_opts = pat; + m_typing_ahead = true; +} + +void BScreen::cycleFocus(int options, const ClientPattern *pat, bool reverse) { // get modifiers from event that causes this for focus order cycling XEvent ev = Fluxbox::instance()->lastEvent(); unsigned int mods = 0;

@@ -852,7 +912,7 @@ mods = FbTk::KeyUtil::instance().cleanMods(ev.xkey.state);

else if (ev.type == ButtonPress) mods = FbTk::KeyUtil::instance().cleanMods(ev.xbutton.state); - if (!m_cycling && mods) { + if (!m_cycling && !m_typing_ahead && mods) { m_cycling = true; FbTk::EventManager::instance()->grabKeyboard(*this, rootWindow().window()); }

@@ -860,12 +920,19 @@

if (mods == 0) // can't stacked cycle unless there is a mod to grab options |= FocusControl::CYCLELINEAR; - FocusControl::FocusedWindows *win_list = - (options & FocusControl::CYCLELINEAR) ? + FocusControl::Focusables *win_list = 0; + if (options & FocusControl::CYCLEGROUPS) { + win_list = (options & FocusControl::CYCLELINEAR) ? + &focusControl().creationOrderWinList() : + &focusControl().focusedOrderWinList(); + } else { + win_list = (options & FocusControl::CYCLELINEAR) ? &focusControl().creationOrderList() : &focusControl().focusedOrderList(); + } - focusControl().cycleFocus(*win_list, options, reverse); + focusControl().cycleFocus(*win_list, pat, reverse); + } FbTk::Menu *BScreen::createMenu(const string &label) {

@@ -1101,8 +1168,8 @@ void BScreen::removeClient(WinClient &client) {

focusControl().removeClient(client); - for_each(getWorkspacesList().begin(), getWorkspacesList().end(), - mem_fun(&Workspace::updateClientmenu)); + if (client.fbwindow() && client.fbwindow()->isIconic()) + iconListSig().notify(); using namespace FbTk;

@@ -1124,7 +1191,7 @@

int BScreen::addWorkspace() { bool save_name = getNameOfWorkspace(m_workspaces_list.size()) != "" ? false : true; - Workspace *wkspc = new Workspace(*this, m_layermanager, + Workspace *wkspc = new Workspace(*this, getNameOfWorkspace(m_workspaces_list.size()), m_workspaces_list.size()); m_workspaces_list.push_back(wkspc);

@@ -1133,8 +1200,6 @@ if (save_name)

addWorkspaceName(wkspc->name().c_str()); //update names saveWorkspaces(m_workspaces_list.size()); - - updateNetizenWorkspaceCount(); return m_workspaces_list.size();

@@ -1163,7 +1228,6 @@

//remove last workspace m_workspaces_list.pop_back(); - updateNetizenWorkspaceCount(); saveWorkspaces(m_workspaces_list.size()); // must be deleted after we send notify!! // so we dont get bad pointers somewhere

@@ -1225,13 +1289,14 @@

currentWorkspace()->showAll(); if (focused && focused->isMoving()) { - focused->setInputFocus(); + focused->focus(); focused->resumeMoving(); } else FocusControl::revertFocus(*this); - updateNetizenCurrentWorkspace(); FbTk::App::instance()->sync(false); + + m_currentworkspace_sig.notify(); }

@@ -1243,31 +1308,24 @@

if (!win) win = FocusControl::focusedFbWindow(); - FbTk::App::instance()->sync(false); - - if (!win || &win->screen() != this || win->isStuck()) + if (!win || &win->screen() != this) return; - // if iconified, deiconify it before we send it somewhere - if (win->isIconic()) - win->deiconify(); - - // if the window isn't on current workspace, hide it - if (id != currentWorkspace()->workspaceID()) - win->withdraw(true); + FbTk::App::instance()->sync(false); windowMenu().hide(); - reassociateWindow(win, id, true); - // if the window is on current workspace, show it. - if (id == currentWorkspace()->workspaceID()) - win->deiconify(false, false); - // change workspace ? - if (changeWS && id != currentWorkspace()->workspaceID()) { + if (changeWS) changeWorkspaceID(id); - win->setInputFocus(); + + // if the window is on current workspace, show it; else hide it. + if (id == currentWorkspace()->workspaceID() && !win->isIconic()) + win->deiconify(false, false); + else { + win->hide(true); + FocusControl::revertFocus(*this); } // send all the transients too

@@ -1285,113 +1343,6 @@

} -void BScreen::addNetizen(Window win) { - Netizen *net = new Netizen(*this, win); - m_netizen_list.push_back(net); - - net->sendWorkspaceCount(); - net->sendCurrentWorkspace(); - - // send all windows to netizen - Workspaces::iterator it = m_workspaces_list.begin(); - Workspaces::iterator it_end = m_workspaces_list.end(); - for (; it != it_end; ++it) { - Workspace::Windows::iterator win_it = (*it)->windowList().begin(); - Workspace::Windows::iterator win_it_end = (*it)->windowList().end(); - for (; win_it != win_it_end; ++win_it) { - net->sendWindowAdd((*win_it)->clientWindow(), - (*it)->workspaceID()); - } - } - - Window f = ((FocusControl::focusedWindow()) ? - FocusControl::focusedWindow()->window() : None); - net->sendWindowFocus(f); -} - -void BScreen::removeNetizen(Window w) { - Netizens::iterator it = m_netizen_list.begin(); - Netizens::iterator it_end = m_netizen_list.end(); - for (; it != it_end; ++it) { - if ((*it)->window() == w) { - Netizen *n = *it; - delete n; - m_netizen_list.erase(it); - break; - } - } -} - - -void BScreen::updateNetizenCurrentWorkspace() { - m_currentworkspace_sig.notify(); - for_each(m_netizen_list.begin(), - m_netizen_list.end(), - mem_fun(&Netizen::sendCurrentWorkspace)); -} - - -void BScreen::updateNetizenWorkspaceCount() { - for_each(m_netizen_list.begin(), - m_netizen_list.end(), - mem_fun(&Netizen::sendWorkspaceCount)); - m_workspacecount_sig.notify(); -} - - -void BScreen::updateNetizenWindowFocus() { - Window f = ((FocusControl::focusedWindow()) ? - FocusControl::focusedWindow()->window() : None); - for_each(m_netizen_list.begin(), - m_netizen_list.end(), - bind2nd(mem_fun(&Netizen::sendWindowFocus), f)); -} - - -void BScreen::updateNetizenWindowAdd(Window w, unsigned long p) { - - // update the list of clients - m_clientlist_sig.notify(); - - // and then send the signal to listeners - Netizens::iterator it = m_netizen_list.begin(); - Netizens::iterator it_end = m_netizen_list.end(); - for (; it != it_end; ++it) { - (*it)->sendWindowAdd(w, p); - } - -} - - -void BScreen::updateNetizenWindowDel(Window w) { - for_each(m_netizen_list.begin(), - m_netizen_list.end(), - bind2nd(mem_fun(&Netizen::sendWindowDel), w)); - - m_clientlist_sig.notify(); -} - - -void BScreen::updateNetizenWindowRaise(Window w) { - for_each(m_netizen_list.begin(), - m_netizen_list.end(), - bind2nd(mem_fun(&Netizen::sendWindowRaise), w)); -} - - -void BScreen::updateNetizenWindowLower(Window w) { - for_each(m_netizen_list.begin(), - m_netizen_list.end(), - bind2nd(mem_fun(&Netizen::sendWindowLower), w)); -} - -void BScreen::updateNetizenConfigNotify(XEvent &e) { - Netizens::iterator it = m_netizen_list.begin(); - Netizens::iterator it_end = m_netizen_list.end(); - for (; it != it_end; ++it) - (*it)->sendConfigNotify(e); -} - bool BScreen::isKdeDockapp(Window client) const { //Check and see if client is KDE dock applet. bool iskdedockapp = false;

@@ -1505,10 +1456,6 @@ if (!win->isManaged()) {

delete win; return 0; } - - Workspace *workspace = getWorkspace(win->workspaceNumber()); - if (workspace && !Fluxbox::instance()->isStartup()) - workspace->checkGrouping(*win); } }

@@ -1559,7 +1506,7 @@ win->show();

// don't ask me why, but client doesn't seem to keep focus in new window // and we don't seem to get a FocusIn event from setInputFocus if ((focusControl().focusNew() || FocusControl::focusedWindow() == &client) - && win->setInputFocus()) + && win->focus()) FocusControl::setFocusedWindow(&client); m_clientlist_sig.notify();

@@ -1640,20 +1587,12 @@

if (w->isIconic()) { removeIcon(w); getWorkspace(wkspc_id)->addWindow(*w); - // client list need to notify now even though - // we didn't remove/add any window, - // so listeners that uses the client list to - // show whats on current/other workspace - // gets updated - m_clientlist_sig.notify(); } else if (ignore_sticky || ! w->isStuck()) { // fresh windows have workspaceNumber == -1, which leads to // an invalid workspace (unsigned int) if (getWorkspace(w->workspaceNumber())) getWorkspace(w->workspaceNumber())->removeWindow(w, true); getWorkspace(wkspc_id)->addWindow(*w); - // see comment above - m_clientlist_sig.notify(); } }

@@ -1774,6 +1713,15 @@ focusControl(), FocusControl::CLICKTABFOCUS, save_and_reconfigure));

focus_menu->insert(new TabFocusModelMenuItem(_FB_XTEXT(Configmenu, MouseTabFocus, "MouseTabFocus", "Hover over tab to focus windows"), focusControl(), FocusControl::MOUSETABFOCUS, save_and_reconfigure)); + + try { + focus_menu->insert(new BoolMenuItem(_FB_XTEXT(Configmenu, FocusNew, + "Focus New Windows", "Focus newly created windows"), + *m_resource_manager.getResource<bool>(name() + ".focusNewWindows"), + saverc_cmd)); + } catch (FbTk::ResourceException e) { + cerr<<e.what()<<endl; + } focus_menu->insert(new BoolMenuItem(_FB_XTEXT(Configmenu, AutoRaise,

@@ -1788,6 +1736,31 @@ menu.insert(focusmenu_label, focus_menu);

// END focus menu + // BEGIN maximize menu + + FbTk::FbString maxmenu_label = _FB_XTEXT(Configmenu, MaxMenu, + "Maximize Options", "heading for maximization options"); + FbTk::Menu *maxmenu = createMenu(maxmenu_label); + + _BOOLITEM(*maxmenu, Configmenu, FullMax, + "Full Maximization", "Maximise over slit, toolbar, etc", + *resource.full_max, saverc_cmd); + _BOOLITEM(*maxmenu, Configmenu, MaxIgnoreInc, + "Ignore Resize Increment", + "Maximizing Ignores Resize Increment (e.g. xterm)", + *resource.max_ignore_inc, saverc_cmd); + _BOOLITEM(*maxmenu, Configmenu, MaxDisableMove, + "Disable Moving", "Don't Allow Moving While Maximized", + *resource.max_disable_move, saverc_cmd); + _BOOLITEM(*maxmenu, Configmenu, MaxDisableResize, + "Disable Resizing", "Don't Allow Resizing While Maximized", + *resource.max_disable_resize, saverc_cmd); + + maxmenu->updateMenu(); + menu.insert(maxmenu_label, maxmenu); + + // END maximize menu + // BEGIN tab menu FbTk::FbString tabmenu_label = _FB_XTEXT(Configmenu, TabMenu,

@@ -1805,6 +1778,9 @@ *resource.default_internal_tabs, save_and_reconftabs);

tab_menu->insert(new BoolMenuItem(_FB_XTEXT(Common, MaximizeOver, "Maximize Over", "Maximize over this thing when maximizing"), *resource.max_over_tabs, save_and_reconfigure)); + tab_menu->insert(new BoolMenuItem(_FB_XTEXT(Toolbar, ShowIcons, + "Show Pictures", "chooses if little icons are shown next to title in the iconbar"), + *resource.tabs_use_pixmap, save_and_reconfigure)); FbTk::MenuItem *tab_width_item = new IntResMenuItem< FbTk::Resource<int> >(_FB_XTEXT(Configmenu, ExternalTabWidth,

@@ -1908,18 +1884,6 @@ _BOOLITEM(menu, Configmenu, OpaqueMove,

"Opaque Window Moving", "Window Moving with whole window visible (as opposed to outline moving)", *resource.opaque_move, saverc_cmd); - _BOOLITEM(menu, Configmenu, FullMax, - "Full Maximization", "Maximise over slit, toolbar, etc", - *resource.full_max, saverc_cmd); - try { - _BOOLITEM(menu, Configmenu, FocusNew, - "Focus New Windows", "Focus newly created windows", - *m_resource_manager.getResource<bool>(name() + ".focusNewWindows"), - saverc_cmd); - } catch (FbTk::ResourceException e) { - cerr<<e.what()<<endl; - } - _BOOLITEM(menu, Configmenu, WorkspaceWarping, "Workspace Warping", "Workspace Warping - dragging windows to the edge and onto the next workspace",

@@ -1978,7 +1942,7 @@ m_pos_window.clear();

winFrameTheme().font().drawText(m_pos_window, screenNumber(), - winFrameTheme().labelTextFocusGC(), + winFrameTheme().iconbarTheme().focusedText().textGC(), label, strlen(label), winFrameTheme().bevelWidth(), winFrameTheme().bevelWidth() +

@@ -2030,7 +1994,7 @@

//!! TODO: geom window again?! repeated winFrameTheme().font().drawText(m_geom_window, screenNumber(), - winFrameTheme().labelTextFocusGC(), + winFrameTheme().iconbarTheme().focusedText().textGC(), label, strlen(label), winFrameTheme().bevelWidth(), winFrameTheme().bevelWidth() +

@@ -2101,7 +2065,7 @@

Pixmap tmp = geom_pixmap; - if (winFrameTheme().labelFocusTexture().type() & FbTk::Texture::PARENTRELATIVE) { + if (winFrameTheme().iconbarTheme().focusedTexture().type() & FbTk::Texture::PARENTRELATIVE) { if (!winFrameTheme().titleFocusTexture().usePixmap()) { geom_pixmap = None; m_geom_window.setBackgroundColor(winFrameTheme().titleFocusTexture().color());

@@ -2111,12 +2075,12 @@ winFrameTheme().titleFocusTexture());

m_geom_window.setBackgroundPixmap(geom_pixmap); } } else { - if (!winFrameTheme().labelFocusTexture().usePixmap()) { + if (!winFrameTheme().iconbarTheme().focusedTexture().usePixmap()) { geom_pixmap = None; - m_geom_window.setBackgroundColor(winFrameTheme().labelFocusTexture().color()); + m_geom_window.setBackgroundColor(winFrameTheme().iconbarTheme().focusedTexture().color()); } else { geom_pixmap = imageControl().renderImage(m_geom_window.width(), m_geom_window.height(), - winFrameTheme().labelFocusTexture()); + winFrameTheme().iconbarTheme().focusedTexture()); m_geom_window.setBackgroundPixmap(geom_pixmap); } }

@@ -2139,7 +2103,7 @@

Pixmap tmp = pos_pixmap; - if (winFrameTheme().labelFocusTexture().type() & FbTk::Texture::PARENTRELATIVE) { + if (winFrameTheme().iconbarTheme().focusedTexture().type() & FbTk::Texture::PARENTRELATIVE) { if (!winFrameTheme().titleFocusTexture().usePixmap()) { pos_pixmap = None; m_pos_window.setBackgroundColor(winFrameTheme().titleFocusTexture().color());

@@ -2149,12 +2113,12 @@ winFrameTheme().titleFocusTexture());

m_pos_window.setBackgroundPixmap(pos_pixmap); } } else { - if (!winFrameTheme().labelFocusTexture().usePixmap()) { + if (!winFrameTheme().iconbarTheme().focusedTexture().usePixmap()) { pos_pixmap = None; - m_pos_window.setBackgroundColor(winFrameTheme().labelFocusTexture().color()); + m_pos_window.setBackgroundColor(winFrameTheme().iconbarTheme().focusedTexture().color()); } else { pos_pixmap = imageControl().renderImage(m_pos_window.width(), m_pos_window.height(), - winFrameTheme().labelFocusTexture()); + winFrameTheme().iconbarTheme().focusedTexture()); m_pos_window.setBackgroundPixmap(pos_pixmap); } }
M src/Screen.hhsrc/Screen.hh

@@ -58,7 +58,6 @@

class ClientPattern; class Focusable; class FluxboxWindow; -class Netizen; class FbWinFrameTheme; class RootTheme; class WinButtonTheme;

@@ -88,17 +87,17 @@ public:

/// a window becomes active / focussed on a different workspace enum FollowModel { IGNORE_OTHER_WORKSPACES = 0, ///< who cares? - FOLLOW_ACTIVE_WINDOW, ///< go to that workspace + FOLLOW_ACTIVE_WINDOW, ///< go to that workspace SEMIFOLLOW_ACTIVE_WINDOW, ///< fetch iconified windows, else follow - FETCH_ACTIVE_WINDOW ///< put that window to the current workspace + FETCH_ACTIVE_WINDOW ///< put that window to the current workspace }; /// Different resize modes when resizing a window enum ResizeModel { - BOTTOMRESIZE = 0, //< resizes from the bottom right corner - QUADRANTRESIZE, //< resizes from one quadrant - CENTERRESIZE, //< resizes from center - DEFAULTRESIZE = BOTTOMRESIZE //< default resize mode is bottom + BOTTOMRESIZE = 0, ///< resizes from the bottom right corner + QUADRANTRESIZE, ///< resizes from one quadrant + CENTERRESIZE, ///< resizes from center + DEFAULTRESIZE = BOTTOMRESIZE ///< default resize mode is bottom };

@@ -119,12 +118,13 @@

bool isRootColormapInstalled() const { return root_colormap_installed; } bool isScreenManaged() const { return managed; } bool isWorkspaceWarping() const { return *resource.workspace_warping; } - bool isDesktopWheeling() const { return *resource.desktop_wheeling; } - bool isReverseWheeling() const { return *resource.reverse_wheeling; } bool doAutoRaise() const { return *resource.auto_raise; } bool clickRaises() const { return *resource.click_raises; } bool doOpaqueMove() const { return *resource.opaque_move; } bool doFullMax() const { return *resource.full_max; } + bool getMaxIgnoreIncrement() const { return *resource.max_ignore_inc; } + bool getMaxDisableMove() const { return *resource.max_disable_move; } + bool getMaxDisableResize() const { return *resource.max_disable_resize; } bool doShowWindowPos() const { return *resource.show_window_pos; } bool decorateTransient() const { return *resource.decorate_transient; } const std::string &defaultDeco() const { return *resource.default_deco; }

@@ -144,13 +144,16 @@ FbWinFrame::TabPlacement getTabPlacement() const { return *resource.tab_placement; }

ResizeModel getResizeModel() const { return *resource.resize_model; } + inline unsigned int noFocusWhileTypingDelay() const { return *resource.typing_delay; } inline FollowModel getFollowModel() const { return *resource.follow_model; } inline FollowModel getUserFollowModel() const { return *resource.user_follow_model; } inline const std::string &getScrollAction() const { return *resource.scroll_action; } inline const bool getScrollReverse() const { return *resource.scroll_reverse; } inline const bool allowRemoteActions() const { return *resource.allow_remote_actions; } + inline const bool clientMenuUsePixmap() const { return *resource.clientmenu_use_pixmap; } inline const bool getDefaultInternalTabs() const { return *resource.default_internal_tabs; } + inline const bool getTabsUsePixmap() const { return *resource.tabs_use_pixmap; } inline const bool getMaxOverTabs() const { return *resource.max_over_tabs; } inline unsigned int getTabWidth() const { return *resource.tab_width; }

@@ -256,9 +259,10 @@ const ClientPattern *pat = 0);

/** * Cycles focus of windows * @param opts focus options + * @param pat specific pattern to match windows with * @param reverse the order of cycling */ - void cycleFocus(int opts = 0, bool reverse = false); + void cycleFocus(int opts = 0, const ClientPattern *pat = 0, bool reverse = false); /** * Creates an empty menu with specified label

@@ -306,6 +310,9 @@ const WinButtonTheme &winButtonTheme() const { return *m_winbutton_theme.get(); }

FbRootWindow &rootWindow() { return m_root_window; } const FbRootWindow &rootWindow() const { return m_root_window; } + + FbTk::FbWindow &dummyWindow() { return m_dummy_window; } + const FbTk::FbWindow &dummyWindow() const { return m_dummy_window; } FbTk::MultLayers &layerManager() { return m_layermanager; } const FbTk::MultLayers &layerManager() const { return m_layermanager; }

@@ -355,10 +362,6 @@ /// update the workspace name atom

void updateWorkspaceNamesAtom(); /// add a workspace name to the end of the workspace name list void addWorkspaceName(const char *name); - /// add a Netizen window - void addNetizen(Window win); - /// remove a netizen - void removeNetizen(Window win); /// add a window to the icon list void addIcon(FluxboxWindow *win); /// remove a window from the icon list

@@ -456,16 +459,6 @@ // group to the left, or to the right (they'll be different if

// they exist). WinClient *findGroupLeft(WinClient &winclient); WinClient *findGroupRight(WinClient &winclient); - - // notify netizens - void updateNetizenCurrentWorkspace(); - void updateNetizenWorkspaceCount(); - void updateNetizenWindowFocus(); - void updateNetizenWindowAdd(Window, unsigned long); - void updateNetizenWindowDel(Window); - void updateNetizenConfigNotify(XEvent &ev); - void updateNetizenWindowRaise(Window); - void updateNetizenWindowLower(Window); /// create window frame for client window and attach it FluxboxWindow *createWindow(Window clientwin);

@@ -536,12 +529,10 @@

ExtraMenus m_extramenus; typedef std::list<FbTk::Menu *> Rootmenus; - typedef std::list<Netizen *> Netizens; typedef std::list<std::pair<FbTk::FbString, FbTk::Menu *> > Configmenus; Rootmenus m_rootmenu_list; - Netizens m_netizen_list; Configmenus m_configmenu_list; Icons m_icon_list;

@@ -558,21 +549,22 @@ std::auto_ptr<MenuTheme> m_menutheme;

std::auto_ptr<RootTheme> m_root_theme; FbRootWindow m_root_window; - FbTk::FbWindow m_geom_window, m_pos_window; + FbTk::FbWindow m_geom_window, m_pos_window, m_dummy_window; struct ScreenResource { ScreenResource(FbTk::ResourceManager &rm, const std::string &scrname, const std::string &altscrname); FbTk::Resource<bool> image_dither, opaque_move, full_max, - workspace_warping, - desktop_wheeling, reverse_wheeling, show_window_pos, - auto_raise, click_raises, decorate_transient; + max_ignore_inc, max_disable_move, max_disable_resize, + workspace_warping, show_window_pos, auto_raise, click_raises, + decorate_transient; FbTk::Resource<std::string> default_deco; FbTk::Resource<std::string> rootcommand; FbTk::Resource<ResizeModel> resize_model; FbTk::Resource<FbWinFrame::TabPlacement> tab_placement; FbTk::Resource<std::string> windowmenufile; + FbTk::Resource<unsigned int> typing_delay; FbTk::Resource<FollowModel> follow_model, user_follow_model; bool ordered_dither; FbTk::Resource<int> workspaces, edge_snap_threshold, focused_alpha,

@@ -586,6 +578,8 @@ FbTk::Resource<FbTk::GContext::CapStyle> gc_cap_style;

FbTk::Resource<std::string> scroll_action; FbTk::Resource<bool> scroll_reverse; FbTk::Resource<bool> allow_remote_actions; + FbTk::Resource<bool> clientmenu_use_pixmap; + FbTk::Resource<bool> tabs_use_pixmap; FbTk::Resource<bool> max_over_tabs; FbTk::Resource<bool> default_internal_tabs;
M src/ScreenPlacement.ccsrc/ScreenPlacement.cc

@@ -25,6 +25,7 @@ #include "ScreenPlacement.hh"

#include "RowSmartPlacement.hh" +#include "MinOverlapPlacement.hh" #include "UnderMousePlacement.hh" #include "ColSmartPlacement.hh" #include "CascadePlacement.hh"

@@ -57,7 +58,7 @@ m_strategy(0)

{ } -bool ScreenPlacement::placeWindow(const std::vector<FluxboxWindow *> &windowlist, +bool ScreenPlacement::placeWindow(const std::list<FluxboxWindow *> &windowlist, const FluxboxWindow &win, int &place_x, int &place_y) {

@@ -72,6 +73,10 @@ m_strategy.reset(new RowSmartPlacement());

break; case COLSMARTPLACEMENT: m_strategy.reset(new ColSmartPlacement()); + break; + case ROWMINOVERLAPPLACEMENT: + case COLMINOVERLAPPLACEMENT: + m_strategy.reset(new MinOverlapPlacement(*m_placement_policy)); break; case CASCADEPLACEMENT: m_strategy.reset(new CascadePlacement(win.screen()));

@@ -143,6 +148,10 @@ if (strcasecmp("RowSmartPlacement", str) == 0)

*(*this) = ScreenPlacement::ROWSMARTPLACEMENT; else if (strcasecmp("ColSmartPlacement", str) == 0) *(*this) = ScreenPlacement::COLSMARTPLACEMENT; + else if (strcasecmp("RowMinOverlapPlacement", str) == 0) + *(*this) = ScreenPlacement::ROWMINOVERLAPPLACEMENT; + else if (strcasecmp("ColMinOverlapPlacement", str) == 0) + *(*this) = ScreenPlacement::COLMINOVERLAPPLACEMENT; else if (strcasecmp("UnderMousePlacement", str) == 0) *(*this) = ScreenPlacement::UNDERMOUSEPLACEMENT; else if (strcasecmp("CascadePlacement", str) == 0)

@@ -158,6 +167,10 @@ case ScreenPlacement::ROWSMARTPLACEMENT:

return "RowSmartPlacement"; case ScreenPlacement::COLSMARTPLACEMENT: return "ColSmartPlacement"; + case ScreenPlacement::ROWMINOVERLAPPLACEMENT: + return "RowMinOverlapPlacement"; + case ScreenPlacement::COLMINOVERLAPPLACEMENT: + return "ColMinOverlapPlacement"; case ScreenPlacement::UNDERMOUSEPLACEMENT: return "UnderMousePlacement"; case ScreenPlacement::CASCADEPLACEMENT:
M src/ScreenPlacement.hhsrc/ScreenPlacement.hh

@@ -43,8 +43,10 @@ class ScreenPlacement: public PlacementStrategy {

public: enum PlacementPolicy { ROWSMARTPLACEMENT, - COLSMARTPLACEMENT, - CASCADEPLACEMENT, + COLSMARTPLACEMENT, + COLMINOVERLAPPLACEMENT, + ROWMINOVERLAPPLACEMENT, + CASCADEPLACEMENT, UNDERMOUSEPLACEMENT };

@@ -62,7 +64,7 @@

virtual ~ScreenPlacement() {} /// placeWindow is guaranteed to succeed, ignore return value /// @return true - bool placeWindow(const std::vector<FluxboxWindow *> &windowlist, + bool placeWindow(const std::list<FluxboxWindow *> &windowlist, const FluxboxWindow &window, int &place_x, int &place_y);
M src/Slit.ccsrc/Slit.cc

@@ -59,7 +59,6 @@

#include "SlitTheme.hh" #include "SlitClient.hh" #include "Xutil.hh" -#include "FbAtoms.hh" #include "FbTk/App.hh" #include "FbTk/MenuSeparator.hh" #include "FbTk/StringUtil.hh"

@@ -497,14 +496,8 @@ }

Atom *proto = 0; int num_return = 0; - FbAtoms *fbatoms = FbAtoms::instance(); if (XGetWMProtocols(disp, w, &proto, &num_return)) { - - for (int i = 0; i < num_return; ++i) { - if (proto[i] == fbatoms->getFluxboxStructureMessagesAtom()) - screen().addNetizen(w); - } XFree((void *) proto); #ifdef DEBUG

@@ -587,8 +580,6 @@ if (destroy)

m_client_list.remove(client); else // Clear the window info, but keep around to help future sorting? client->initialize(); - - screen().removeNetizen(client->window()); if (remap && client->window() != 0) { Display *disp = FbTk::App::instance()->display();
M src/Toolbar.ccsrc/Toolbar.cc

@@ -33,6 +33,7 @@ // themes

#include "ToolbarTheme.hh" #include "fluxbox.hh" +#include "Keys.hh" #include "Screen.hh" #include "IntResMenuItem.hh" #include "BoolMenuItem.hh"

@@ -279,6 +280,8 @@

scrn.resourceManager().unlock(); // setup to listen to child events FbTk::EventManager::instance()->addParent(*this, window()); + Fluxbox::instance()->keys()->registerWindow(window().window(), + Keys::ON_TOOLBAR); // get everything together reconfigure(); // this gets done by the screen later as it loads

@@ -286,6 +289,7 @@

} Toolbar::~Toolbar() { + Fluxbox::instance()->keys()->unregisterWindow(window().window()); FbTk::EventManager::instance()->remove(window()); // remove menu items before we delete tools so we dont end up // with dangling pointers to old submenu items (internal menus)

@@ -520,6 +524,11 @@

void Toolbar::buttonPressEvent(XButtonEvent &be) { + if (Fluxbox::instance()->keys()->doAction(be.type, be.state, be.button, + Keys::ON_TOOLBAR)) + return; + if (be.button == 1) + raise(); if (be.button != 3) return;

@@ -545,25 +554,6 @@ menu().grabInputFocus();

} else menu().hide(); -} - - -void Toolbar::buttonReleaseEvent(XButtonEvent &re) { - if (re.button == 1) { - raise(); - } else if (re.button == 4) { //mousewheel scroll up - if(screen().isReverseWheeling()) { - screen().prevWorkspace(1); - } else { - screen().nextWorkspace(1); - } - } else if (re.button == 5) { //mousewheel scroll down - if(screen().isReverseWheeling()) { - screen().nextWorkspace(1); - } else { - screen().prevWorkspace(1); - } - } } void Toolbar::enterNotifyEvent(XCrossingEvent &not_used) {
M src/Toolbar.hhsrc/Toolbar.hh

@@ -88,7 +88,6 @@ @name eventhandlers

*/ //@{ void buttonPressEvent(XButtonEvent &be); - void buttonReleaseEvent(XButtonEvent &be); void enterNotifyEvent(XCrossingEvent &ce); void leaveNotifyEvent(XCrossingEvent &ce); void exposeEvent(XExposeEvent &ee);
M src/UnderMousePlacement.ccsrc/UnderMousePlacement.cc

@@ -27,7 +27,7 @@ #include "FbTk/App.hh"

#include "Screen.hh" #include "Window.hh" -bool UnderMousePlacement::placeWindow(const std::vector<FluxboxWindow *> &list, +bool UnderMousePlacement::placeWindow(const std::list<FluxboxWindow *> &list, const FluxboxWindow &win, int &place_x, int &place_y) {
M src/UnderMousePlacement.hhsrc/UnderMousePlacement.hh

@@ -28,7 +28,7 @@ #include "PlacementStrategy.hh"

class UnderMousePlacement: public PlacementStrategy { public: - bool placeWindow(const std::vector<FluxboxWindow *> &windowlist, + bool placeWindow(const std::list<FluxboxWindow *> &windowlist, const FluxboxWindow &win, int &place_x, int &place_y); };
M src/WinButton.ccsrc/WinButton.cc

@@ -321,15 +321,15 @@ if (m_type == MENUICON && !m_listen_to.empty()) {

Display* display = m_listen_to.fbWindow().display(); int screen = m_listen_to.screen().screenNumber(); - if (m_listen_to.usePixmap()) { - m_icon_pixmap.copy(m_listen_to.iconPixmap().drawable(), + if (m_listen_to.icon().pixmap().drawable() != None) { + m_icon_pixmap.copy(m_listen_to.icon().pixmap().drawable(), DefaultDepth(display, screen), screen); m_icon_pixmap.scale(width() - 4, height() - 4); } else m_icon_pixmap.release(); - if (m_listen_to.useMask()) { - m_icon_mask.copy(m_listen_to.iconMask().drawable(), 0, 0); + if (m_listen_to.icon().mask().drawable() != None) { + m_icon_mask.copy(m_listen_to.icon().mask().drawable(), 0, 0); m_icon_mask.scale(width() - 4, height() - 4); } else m_icon_mask.release();
M src/WinClient.ccsrc/WinClient.cc

@@ -25,6 +25,7 @@ #include "WinClient.hh"

#include "Window.hh" #include "fluxbox.hh" +#include "FocusControl.hh" #include "Screen.hh" #include "FbAtoms.hh"

@@ -62,7 +63,8 @@ #endif // DEBUG

WinClient::TransientWaitMap WinClient::s_transient_wait; -WinClient::WinClient(Window win, BScreen &screen, FluxboxWindow *fbwin):FbTk::FbWindow(win), +WinClient::WinClient(Window win, BScreen &screen, FluxboxWindow *fbwin): + Focusable(screen, fbwin), FbTk::FbWindow(win), transient_for(0), window_group(0), x(0), y(0), old_bw(0),

@@ -75,24 +77,17 @@ base_width(1), base_height(1),

initial_state(0), normal_hint_flags(0), wm_hint_flags(0), - m_win(fbwin), m_modal_count(0), m_modal(false), send_focus_message(false), send_close_message(false), m_win_gravity(0), - m_title(""), m_icon_title(""), - m_class_name(""), m_instance_name(""), m_title_override(false), m_icon_title_override(false), - m_blackbox_hint(0), m_mwm_hint(0), m_focus_mode(F_PASSIVE), - m_diesig(*this), m_focussig(*this), - m_screen(screen), m_strut(0) { updateWMProtocols(); - updateBlackboxHints(); updateMWMHints(); updateWMHints(); updateWMNormalHints();

@@ -145,8 +140,8 @@ transients.back()->transient_for = 0;

transients.pop_back(); } - if (m_win != 0) - m_win->removeClient(*this); + if (fbwindow() != 0) + fbwindow()->removeClient(*this); // this takes care of any focus issues m_diesig.notify();

@@ -159,8 +154,6 @@ removeTransientFromWaitingList();

s_transient_wait.erase(window()); - screen().removeNetizen(window()); - if (window_group != 0) { fluxbox->removeGroupSearch(window_group); window_group = 0;

@@ -169,13 +162,8 @@

if (m_mwm_hint != 0) XFree(m_mwm_hint); - if (m_blackbox_hint != 0) - XFree(m_blackbox_hint); - if (window()) fluxbox->removeWindowSearch(window()); - - m_win = 0; } bool WinClient::acceptsFocus() const {

@@ -243,12 +231,16 @@ bool WinClient::getWMIconName(XTextProperty &textprop) const {

return XGetWMIconName(display(), window(), &textprop); } -const string &WinClient::getWMClassName() const { - return m_instance_name; +string WinClient::getWMRole() const { + Atom wm_role = XInternAtom(FbTk::App::instance()->display(), + "WM_WINDOW_ROLE", False); + return textProperty(wm_role); } -const string &WinClient::getWMClassClass() const { - return m_class_name; +const string &WinClient::title() const { + if (!fbwindow() || !fbwindow()->isIconic() || m_icon_title.empty()) + return m_title; + return m_icon_title; } void WinClient::updateWMClassHint() {

@@ -257,6 +249,7 @@ if (XGetClassHint(display(), window(), &ch) == 0) {

#ifdef DEBUG cerr<<"WinClient: Failed to read class hint!"<<endl; #endif //DEBUG + m_instance_name = m_class_name = ""; } else { if (ch.res_name != 0) {

@@ -364,18 +357,24 @@ if (m_title_override)

return; m_title = string(Xutil::getWMName(window()), 0, 512); + titleSig().notify(); + if (fbwindow()) + fbwindow()->updateTitleFromClient(*this); } void WinClient::setTitle(FbTk::FbString &title) { m_title = title; m_title_override = true; - if (m_win) - m_win->updateTitleFromClient(*this); + titleSig().notify(); + if (fbwindow()) + fbwindow()->updateTitleFromClient(*this); } void WinClient::setIconTitle(FbTk::FbString &icon_title) { m_icon_title = icon_title; m_icon_title_override = true; + if (fbwindow() && fbwindow()->isIconic()) + fbwindow()->updateTitleFromClient(*this); } void WinClient::updateIconTitle() {

@@ -390,24 +389,27 @@ if (getWMIconName(text_prop)) {

if (text_prop.value && text_prop.nitems > 0) { if (text_prop.encoding != XA_STRING) { text_prop.nitems = strlen((char *) text_prop.value); + XmbTextPropertyToTextList(display(), &text_prop, &list, &num); - if (XmbTextPropertyToTextList(display(), &text_prop, - &list, &num) == Success && - num > 0 && *list) { + if (num > 0 && list) m_icon_title = (char *)*list; + else + m_icon_title = text_prop.value ? (char *)text_prop.value : ""; + if (list) XFreeStringList(list); - } else - m_icon_title = text_prop.value ? (char *)text_prop.value : ""; + } else m_icon_title = text_prop.value ? (char *)text_prop.value : ""; if (text_prop.value) XFree((char *) text_prop.value); } else - m_icon_title = title(); + m_icon_title = ""; } else - m_icon_title = title(); + m_icon_title = ""; + if (fbwindow() && fbwindow()->isIconic()) + fbwindow()->updateTitleFromClient(*this); } void WinClient::saveBlackboxAttribs(FluxboxWindow::BlackboxAttributes &blackbox_attribs) {

@@ -419,32 +421,7 @@ );

} void WinClient::setFluxboxWindow(FluxboxWindow *win) { - m_win = win; -} - -void WinClient::updateBlackboxHints() { - int format; - Atom atom_return; - unsigned long num, len; - FbAtoms *atoms = FbAtoms::instance(); - - if (m_blackbox_hint) { - XFree(m_blackbox_hint); - m_blackbox_hint = 0; - } - - if (property(atoms->getFluxboxHintsAtom(), 0, - PropBlackboxHintsElements, False, - atoms->getFluxboxHintsAtom(), &atom_return, - &format, &num, &len, - (unsigned char **) &m_blackbox_hint) && - m_blackbox_hint) { - - if (num != (unsigned)PropBlackboxHintsElements) { - XFree(m_blackbox_hint); - m_blackbox_hint = 0; - } - } + m_fbwin = win; } void WinClient::updateMWMHints() {

@@ -521,16 +498,16 @@ } else

window_group = None; if ((bool)(wmhint->flags & IconPixmapHint) && wmhint->icon_pixmap != 0) - m_icon_pixmap.copy(wmhint->icon_pixmap, 0, 0); + m_icon.pixmap().copy(wmhint->icon_pixmap, 0, 0); else - m_icon_pixmap = 0; + m_icon.pixmap().release(); if ((bool)(wmhint->flags & IconMaskHint) && wmhint->icon_mask != 0) - m_icon_mask.copy(wmhint->icon_mask, 0, 0); + m_icon.mask().copy(wmhint->icon_mask, 0, 0); else - m_icon_mask = 0; + m_icon.mask().release(); - if (m_win) { + if (fbwindow()) { if (wmhint->flags & XUrgencyHint) { Fluxbox::instance()->attentionHandler().addAttention(*this); } else {

@@ -715,10 +692,22 @@ }

} bool WinClient::focus() { - if (m_win == 0) + if (fbwindow() == 0) return false; else - return m_win->setCurrentClient(*this, true); + return fbwindow()->setCurrentClient(*this, true); +} + +bool WinClient::isFocused() const { + return (fbwindow() ? + fbwindow()->isFocused() && &fbwindow()->winClient() == this : + false); +} + +void WinClient::setAttentionState(bool value) { + Focusable::setAttentionState(value); + if (fbwindow() && !fbwindow()->isFocused()) + fbwindow()->setAttentionState(value); } void WinClient::updateWMProtocols() {

@@ -731,19 +720,16 @@

// defaults send_focus_message = false; send_close_message = false; - // could be added to netizens twice... for (int i = 0; i < num_return; ++i) { if (proto[i] == fbatoms->getWMDeleteAtom()) send_close_message = true; else if (proto[i] == fbatoms->getWMTakeFocusAtom()) send_focus_message = true; - else if (proto[i] == fbatoms->getFluxboxStructureMessagesAtom()) - screen().addNetizen(window()); } XFree(proto); - if (m_win) - m_win->updateFunctions(); + if (fbwindow()) + fbwindow()->updateFunctions(); #ifdef DEBUG } else { cerr<<"Warning: Failed to read WM Protocols. "<<endl;
M src/WinClient.hhsrc/WinClient.hh

@@ -24,6 +24,7 @@

#ifndef WINCLIENT_HH #define WINCLIENT_HH +#include "Focusable.hh" #include "Window.hh" #include "Subject.hh" #include "FbWindow.hh"

@@ -35,7 +36,7 @@ class BScreen;

class Strut; /// Holds client window info -class WinClient:public FbTk::FbWindow { +class WinClient: public Focusable, public FbTk::FbWindow { public: typedef std::list<WinClient *> TransientList; // this structure only contains 3 elements... the Motif 2.0 structure contains

@@ -69,7 +70,6 @@ void updateIconTitle();

/// updates transient window information void updateTransientInfo(); - void updateBlackboxHints(); void updateMWMHints(); void updateWMHints(); void updateWMNormalHints();

@@ -78,6 +78,9 @@ void setStrut(Strut *strut);

void clearStrut(); bool focus(); // calls Window->setCurrentClient to give focus to this client + bool isFocused() const; + void setAttentionState(bool value); + const std::string &title() const; /** * Changes width and height to the nearest (lower) value

@@ -106,17 +109,7 @@

bool getAttrib(XWindowAttributes &attr) const; bool getWMName(XTextProperty &textprop) const; bool getWMIconName(XTextProperty &textprop) const; - /// @return name member of class structure - const std::string &getWMClassName() const; - /// @return class member of class structure - const std::string &getWMClassClass() const; - - BScreen &screen() { return m_screen; } - const BScreen &screen() const { return m_screen; } - /// notifies when this client dies - FbTk::Subject &dieSig() { return m_diesig; } - /// notifies when this client becomes focused - FbTk::Subject &focusSig() { return m_focussig; } + std::string getWMRole() const; inline WinClient *transientFor() { return transient_for; } inline const WinClient *transientFor() const { return transient_for; }

@@ -128,15 +121,6 @@ inline bool isModal() const { return m_modal_count > 0; }

inline bool isStateModal() const { return m_modal; } void setStateModal(bool state); - const FbTk::FbPixmap &iconPixmap() const { return m_icon_pixmap; } - const FbTk::FbPixmap &iconMask() const { return m_icon_mask; } - const bool usePixmap() const { return m_icon_pixmap.drawable() != None; } - const bool useMask() const { return m_icon_mask.drawable() != None; } - - inline const std::string &title() const { return m_title; } - inline const std::string &iconTitle() const { return m_icon_title; } - inline const FluxboxWindow *fbwindow() const { return m_win; } - inline FluxboxWindow *fbwindow() { return m_win; } inline int gravity() const { return m_win_gravity; } bool hasGroupLeftWindow() const;

@@ -144,14 +128,11 @@ // grouping is tracked by remembering the window to the left in the group

Window getGroupLeftWindow() const; inline int getFocusMode() const { return m_focus_mode; } - inline const FluxboxWindow::BlackboxHints *getBlackboxHint() const { return m_blackbox_hint; } inline const MwmHints *getMwmHint() const { return m_mwm_hint; } inline unsigned int maxWidth() const { return max_width; } inline unsigned int maxHeight() const { return max_height; } - - static const int PropBlackboxHintsElements = 5; static const int PropMwmHintsElements = 3; /**

@@ -171,15 +152,6 @@ min_aspect_x, min_aspect_y, max_aspect_x, max_aspect_y,

base_width, base_height; unsigned long initial_state, normal_hint_flags, wm_hint_flags; - - - class WinClientSubj: public FbTk::Subject { - public: - explicit WinClientSubj(WinClient &client):m_winclient(client) { } - WinClient &winClient() { return m_winclient; } - private: - WinClient &m_winclient; - }; enum FocusMode { F_NOINPUT = 0, F_PASSIVE, F_LOCALLYACTIVE, F_GLOBALLYACTIVE };

@@ -192,8 +164,6 @@ void addModal() { ++m_modal_count; }

// some transient (or us) is no longer modal void removeModal() { --m_modal_count; } - FluxboxWindow *m_win; - // number of transients which we are modal for int m_modal_count; bool m_modal;

@@ -201,21 +171,12 @@ bool send_focus_message, send_close_message;

int m_win_gravity; - std::string m_title, m_icon_title; - std::string m_class_name, m_instance_name; + std::string m_icon_title; bool m_title_override, m_icon_title_override; - FbTk::FbPixmap m_icon_pixmap; - FbTk::FbPixmap m_icon_mask; - - FluxboxWindow::BlackboxHints *m_blackbox_hint; MwmHints *m_mwm_hint; int m_focus_mode; - - WinClientSubj m_diesig; - WinClientSubj m_focussig; - BScreen &m_screen; Strut *m_strut; // map transient_for X window to winclient transient
D src/WinClientUtil.cc

@@ -1,32 +0,0 @@

-#include "WinClientUtil.hh" -#include "WinClient.hh" - -#include <algorithm> - -namespace WinClientUtil { - -void maxSize(const FluxboxWindow::ClientList &clients, - unsigned int &max_width, unsigned int &max_height) { - FluxboxWindow::ClientList::const_iterator it = clients.begin(); - FluxboxWindow::ClientList::const_iterator it_end = clients.end(); - max_width = (unsigned int) ~0; // unlimited - max_height = (unsigned int) ~0; // unlimited - for (; it != it_end; ++it) { - // special case for max height/width == 0 - // 0 indicates unlimited size, so we skip them - // and set max size to 0 if max size == ~0 after the loop - if ((*it)->maxHeight() != 0) - max_height = std::min( (*it)->maxHeight(), max_height ); - if ((*it)->maxWidth() != 0) - max_width = std::min( (*it)->maxWidth(), max_width ); - } - - if (max_width == (unsigned int) ~0) - max_width = 0; - if (max_height == (unsigned int) ~0) - max_height = 0; -} - -} - -
D src/WinClientUtil.hh

@@ -1,19 +0,0 @@

-#ifndef WINCLIENTUTIL_H -#define WINCLIENTUTIL_H - -#include "Window.hh" - -/// window client utilities -namespace WinClientUtil { - -/** - * Calculates the min of all maximum width/heights of all clients - * @param clients the client list - * @param width the return value of minimum of all max width of all clients - * @param height the return value of mimimum of all max heights of all clients - */ -void maxSize(const FluxboxWindow::ClientList &clients, - unsigned int &width, unsigned int &height); -} - -#endif // WINCLIENTUTIL_H
M src/Window.ccsrc/Window.cc

@@ -42,8 +42,8 @@ #include "MenuCreator.hh"

#include "StringUtil.hh" #include "FocusControl.hh" #include "Layer.hh" +#include "IconButton.hh" -#include "FbTk/TextButton.hh" #include "FbTk/Compose.hh" #include "FbTk/EventManager.hh" #include "FbTk/KeyUtil.hh"

@@ -148,7 +148,6 @@ // won't do anything nasty

if (!win.winClient().transientList().empty()) win.screen().layerManager().lock(); - win.screen().updateNetizenWindowRaise(win.clientWindow()); win.layerItem().raise(); // for each transient do raise

@@ -193,7 +192,6 @@ // TODO: should we also check if it is the active client?

lowerFluxboxWindow(*(*it)->fbwindow()); } - win.screen().updateNetizenWindowLower(win.clientWindow()); win.layerItem().lower(); win.oplock = false;

@@ -208,7 +206,6 @@ if (win.oplock) return;

win.oplock = true; if (!win.isIconic()) { - // don't update netizen, as it is only temporary win.layerItem().tempRaise(); }

@@ -242,23 +239,18 @@ int FluxboxWindow::s_num_grabs = 0;

FluxboxWindow::FluxboxWindow(WinClient &client, FbWinFrameTheme &tm, FbTk::XLayer &layer): + Focusable(client.screen(), this), oplock(false), m_hintsig(*this), m_statesig(*this), m_layersig(*this), m_workspacesig(*this), - m_diesig(*this), - m_focussig(*this), - m_titlesig(*this), - m_attentionsig(*this), m_themelistener(*this), m_creation_time(0), - moving(false), resizing(false), shaded(false), - iconic(false), focused(false), + moving(false), resizing(false), shaded(false), iconic(false), stuck(false), m_initialized(false), fullscreen(false), maximized(MAX_NONE), m_attaching_tab(0), - m_screen(client.screen()), display(FbTk::App::instance()->display()), m_button_grab_x(0), m_button_grab_y(0), m_last_move_x(0), m_last_move_y(0),

@@ -282,6 +274,17 @@

tm.reconfigSig().attach(&m_themelistener); init(); + + if (!isManaged()) + return; + + // add the window to the focus list + // always add to front on startup to keep the focus order the same + if (screen().focusControl().focusNew() || Fluxbox::instance()->isStartup()) + screen().focusControl().addFocusWinFront(*this); + else + screen().focusControl().addFocusWinBack(*this); + }

@@ -331,7 +334,9 @@ detachClient(*m_clientlist.back());

} } - // deal with extra menus + if (!screen().isShuttingdown()) + screen().focusControl().removeWindow(*this); + #ifdef DEBUG cerr<<__FILE__<<"("<<__LINE__<<"): ~FluxboxWindow("<<this<<")"<<endl; #endif // DEBUG

@@ -389,10 +394,7 @@

functions.resize = functions.move = functions.iconify = functions.maximize = functions.close = functions.tabable = true; - if (m_client->getBlackboxHint() != 0) - updateBlackboxHintsFromClient(*m_client); - else - updateMWMHintsFromClient(*m_client); + updateMWMHintsFromClient(*m_client); //!! // fetch client size and placement

@@ -516,10 +518,11 @@ maximized = MAX_NONE; // it is not maximized now

maximize(req_maximized); } + setFocusFlag(false); // update graphics before mapping + if (stuck) { stuck = false; stick(); - deiconify(); //we're omnipresent and visible } if (shaded) { // start shaded

@@ -530,16 +533,19 @@

if (iconic) { iconic = false; iconify(); - } else + } else if (m_workspace_number == screen().currentWorkspaceID()) { + iconic = true; deiconify(false); + // check if we should prevent this window from gaining focus + if (!allowsFocusFromClient() || Fluxbox::instance()->isStartup()) + m_focused = false; + } struct timeval now; gettimeofday(&now, NULL); m_creation_time = now.tv_sec; sendConfigureNotify(); - // no focus default - setFocusFlag(false); setupWindow();

@@ -570,18 +576,8 @@

if (client.fbwindow() != 0) { FluxboxWindow *old_win = client.fbwindow(); // store old window - // figure out which client to raise at the end - if (FocusControl::focusedFbWindow() == old_win) { + if (FocusControl::focusedFbWindow() == old_win) was_focused = true; - } else if (FocusControl::focusedFbWindow() != this) { - FocusControl::FocusedWindows focus_list = - screen().focusControl().focusedOrderList(); - FocusControl::FocusedWindows::iterator it = focus_list.begin(); - for (; it != focus_list.end() && !focused_win; ++it) { - if ((*it)->fbwindow() == this || (*it)->fbwindow() == old_win) - focused_win = *it; - } - } ClientList::iterator client_insert_pos = getClientInsertPosition(x, y); FbTk::TextButton *button_insert_pos = NULL;

@@ -630,9 +626,13 @@ frame().clientArea().width(),

frame().clientArea().height()); // right now, this block only happens with new windows or on restart - if (screen().focusControl().focusNew() || - Fluxbox::instance()->isStartup()) - focused_win = &client; + bool focus_new = screen().focusControl().focusNew(); + bool is_startup = Fluxbox::instance()->isStartup(); + + // we use m_focused as a signal to focus the window when mapped + if (focus_new && !is_startup) + m_focused = true; + focused_win = (focus_new || is_startup) ? &client : m_client; client.saveBlackboxAttribs(m_blackbox_attrib); m_clientlist.push_back(&client);

@@ -648,17 +648,17 @@

if (was_focused) { // don't ask me why, but client doesn't seem to keep focus in new window // and we don't seem to get a FocusIn event from setInputFocus - setCurrentClient(client); + client.focus(); FocusControl::setFocusedWindow(&client); - } else if (focused_win) { - setCurrentClient(*focused_win, false); - if (isIconic() && screen().focusControl().focusNew() && !Fluxbox::instance()->isStartup()) - deiconify(); - } else - // reparenting puts the new client on top, but the old client is keeping - // the focus, so we raise it - m_client->raise(); - + } else { + if (!focused_win) + focused_win = screen().focusControl().lastFocusedWindow(*this); + if (focused_win) { + setCurrentClient(*focused_win, false); + if (isIconic() && m_focused) + deiconify(); + } + } frame().reconfigure(); }

@@ -725,7 +725,7 @@

FbTk::EventManager &evm = *FbTk::EventManager::instance(); evm.remove(client.window()); - FbTk::TextButton *label_btn = m_labelbuttons[&client]; + IconButton *label_btn = m_labelbuttons[&client]; if (label_btn != 0) { frame().removeTab(label_btn); label_btn = 0;

@@ -756,14 +756,32 @@ void FluxboxWindow::nextClient() {

if (numClients() <= 1) return; - screen().focusControl().cycleFocus(m_clientlist, 0); + ClientList::iterator it = find(m_clientlist.begin(), m_clientlist.end(), + m_client); + if (it == m_clientlist.end()) + return; + + ++it; + if (it == m_clientlist.end()) + it = m_clientlist.begin(); + + setCurrentClient(**it, isFocused()); } void FluxboxWindow::prevClient() { if (numClients() <= 1) return; - screen().focusControl().cycleFocus(m_clientlist, 0, true); + ClientList::iterator it = find(m_clientlist.begin(), m_clientlist.end(), + m_client); + if (it == m_clientlist.end()) + return; + + if (it == m_clientlist.begin()) + it = m_clientlist.end(); + --it; + + setCurrentClient(**it, isFocused()); }

@@ -959,15 +977,11 @@ // make sure it's in our list

if (client.fbwindow() != this) return false; - FbTk::TextButton *button = m_labelbuttons[&client]; + IconButton *button = m_labelbuttons[&client]; // in case the window is being destroyed, but this should never happen if (!button) return false; - if (&client != m_client) { - m_screen.focusControl().setScreenFocusedWindow(client); - frame().setShapingClient(&client, false); - } m_client = &client; m_client->raise(); m_client->focusSig().notify();

@@ -979,25 +993,9 @@ button<<endl;

#endif // DEBUG // frame focused doesn't necessarily mean input focused frame().setLabelButtonFocus(*button); - - if (setinput && setInputFocus()) { - return true; - } - - return false; -} - -void FluxboxWindow::setLabelButtonFocus(WinClient &client, bool value) { - // make sure it's in our list - if (client.fbwindow() != this) - return; - - frame().setLabelButtonFocus(*m_labelbuttons[&client], value); -} + frame().setShapingClient(&client, false); -void FluxboxWindow::setAttentionState(bool value) { - m_attention_state = value; - m_attentionsig.notify(); + return setinput && focus(); } bool FluxboxWindow::isGroupable() const {

@@ -1010,8 +1008,8 @@ void FluxboxWindow::associateClientWindow(bool use_attrs,

int x, int y, unsigned int width, unsigned int height, int gravity, unsigned int client_bw) { - updateTitleFromClient(*m_client); - updateIconNameFromClient(*m_client); + m_client->updateTitle(); + m_client->updateIconTitle(); frame().setShapingClient(m_client, false);

@@ -1056,7 +1054,7 @@ void FluxboxWindow::reconfigure() {

applyDecorations(); - setFocusFlag(focused); + setFocusFlag(m_focused); moveResize(frame().x(), frame().y(), frame().width(), frame().height());

@@ -1092,25 +1090,21 @@ frame().setOnClickTitlebar(null_cmd, 4);

frame().setOnClickTitlebar(null_cmd, 5); } + Client2ButtonMap::iterator it = m_labelbuttons.begin(), + it_end = m_labelbuttons.end(); + for (; it != it_end; ++it) + it->second->setPixmap(screen().getTabsUsePixmap()); + } /// update current client title and title in our frame void FluxboxWindow::updateTitleFromClient(WinClient &client) { - client.updateTitle(); - // compare old title with new and see if we need to update - // graphics - if (m_labelbuttons[&client]->text() != client.title()) { - m_labelbuttons[&client]->setText(client.title()); - if (&client == m_client) - frame().setFocusTitle(client.title()); + if (&client == m_client) { + frame().setFocusTitle(client.title()); + titleSig().notify(); } } -/// update icon title from client -void FluxboxWindow::updateIconNameFromClient(WinClient &client) { - client.updateIconTitle(); -} - void FluxboxWindow::updateMWMHintsFromClient(WinClient &client) { const WinClient::MwmHints *hint = client.getMwmHint();

@@ -1191,42 +1185,6 @@ if (changed)

setupWindow(); } -void FluxboxWindow::updateBlackboxHintsFromClient(const WinClient &client) { - const FluxboxWindow::BlackboxHints *hint = client.getBlackboxHint(); - if (!hint) return; - - if (hint->flags & ATTRIB_SHADED) - shaded = (hint->attrib & ATTRIB_SHADED); - - if (hint->flags & ATTRIB_HIDDEN) - iconic = (hint->attrib & ATTRIB_HIDDEN); - - if ((hint->flags & ATTRIB_MAXHORIZ) && - (hint->flags & ATTRIB_MAXVERT)) - maximized = ((hint->attrib & - (ATTRIB_MAXHORIZ | - ATTRIB_MAXVERT)) ? MAX_FULL : MAX_NONE); - else if (hint->flags & ATTRIB_MAXVERT) - maximized = ((hint->attrib & - ATTRIB_MAXVERT) ? MAX_VERT : MAX_NONE); - else if (hint->flags & ATTRIB_MAXHORIZ) - maximized = ((hint->attrib & - ATTRIB_MAXHORIZ) ? MAX_HORZ : MAX_NONE); - - if (hint->flags & ATTRIB_OMNIPRESENT) - stuck = (hint->attrib & ATTRIB_OMNIPRESENT); - - if (hint->flags & ATTRIB_WORKSPACE) - m_workspace_number = hint->workspace; - - if (hint->flags & ATTRIB_STACK) - m_workspace_number = hint->stack; - - if (hint->flags & ATTRIB_DECORATION) { - setDecoration(static_cast<Decoration>(hint->decoration), false); - } -} - void FluxboxWindow::move(int x, int y) { moveResize(x, y, frame().width(), frame().height()); }

@@ -1262,7 +1220,7 @@ if ((((signed) frame().height()) + new_y) < 0)

new_y = 0; frame().moveResize(new_x, new_y, new_width, new_height); - setFocusFlag(focused); + setFocusFlag(m_focused); send_event = true; } else if (send_event)

@@ -1287,7 +1245,7 @@ // magic to detect if moved during initialisation

if (!m_initialized) m_old_pos_x = 1; frame().moveResizeForClient(new_x, new_y, new_width, new_height, gravity, client_bw); - setFocusFlag(focused); + setFocusFlag(m_focused); shaded = false; sendConfigureNotify();

@@ -1298,15 +1256,33 @@ }

} +void FluxboxWindow::maxSize(unsigned int &max_width, unsigned int &max_height) { + ClientList::const_iterator it = clientList().begin(); + ClientList::const_iterator it_end = clientList().end(); + max_width = (unsigned int) ~0; // unlimited + max_height = (unsigned int) ~0; // unlimited + for (; it != it_end; ++it) { + // special case for max height/width == 0 + // 0 indicates unlimited size, so we skip them + // and set max size to 0 if max size == ~0 after the loop + if ((*it)->maxHeight() != 0) + max_height = std::min( (*it)->maxHeight(), max_height ); + if ((*it)->maxWidth() != 0) + max_width = std::min( (*it)->maxWidth(), max_width ); + } - + if (max_width == (unsigned int) ~0) + max_width = 0; + if (max_height == (unsigned int) ~0) + max_height = 0; +} // returns whether the focus was "set" to this window // it doesn't guarantee that it has focus, but says that we have -// tried. A FocusqIn event should eventually arrive for that -// window if it actually got the focus, then setFocusedFlag is called, +// tried. A FocusIn event should eventually arrive for that +// window if it actually got the focus, then setFocusFlag is called, // which updates all the graphics etc -bool FluxboxWindow::setInputFocus() { +bool FluxboxWindow::focus() { if (((signed) (frame().x() + frame().width())) < 0) { if (((signed) (frame().y() + frame().height())) < 0) {

@@ -1337,6 +1313,33 @@

if (! m_client->validateClient()) return false; + if (screen().currentWorkspaceID() != workspaceNumber() && !isStuck()) { + + BScreen::FollowModel model = screen().getUserFollowModel(); + if (model == BScreen::IGNORE_OTHER_WORKSPACES) + return false; + + // fetch the window to the current workspace + if (model == BScreen::FETCH_ACTIVE_WINDOW || + (isIconic() && model == BScreen::SEMIFOLLOW_ACTIVE_WINDOW)) + screen().sendToWorkspace(screen().currentWorkspaceID(), this, false); + // warp to the workspace of the window + else + screen().changeWorkspaceID(workspaceNumber()); + } + + FluxboxWindow *cur = FocusControl::focusedFbWindow(); + WinClient *client = FocusControl::focusedWindow(); + if (cur && client && cur != this && cur->isFullscreen() && + getRootTransientFor(m_client) != getRootTransientFor(client)) + return false; + + if (isIconic()) { + deiconify(); + m_focused = true; // signal to mapNotifyEvent to set focus when mapped + return true; // the window probably will get focused, just not yet + } + // this needs to be here rather than setFocusFlag because // FocusControl::revertFocus will return before FocusIn events arrive m_screen.focusControl().setScreenFocusedWindow(*m_client);

@@ -1405,12 +1408,18 @@ if (m_attaching_tab)

attachTo(0, 0, true); } + setState(IconicState, false); + menu().hide(); frame().hide(); + + if (FocusControl::focusedFbWindow() == this) + FocusControl::setFocusedWindow(0); } void FluxboxWindow::show() { frame().show(); + setState(NormalState, false); } void FluxboxWindow::toggleIconic() {

@@ -1426,14 +1435,9 @@ */

void FluxboxWindow::iconify() { if (isIconic()) // no need to iconify if we're already return; - - m_blackbox_attrib.flags |= ATTRIB_HIDDEN; - m_blackbox_attrib.attrib |= ATTRIB_HIDDEN; iconic = true; - setState(IconicState, false); - hide(true); screen().focusControl().setFocusBack(this);

@@ -1442,9 +1446,6 @@ ClientList::iterator client_it = m_clientlist.begin();

const ClientList::iterator client_it_end = m_clientlist.end(); for (; client_it != client_it_end; ++client_it) { WinClient &client = *(*client_it); - client.setEventMask(NoEventMask); - client.hide(); - client.setEventMask(PropertyChangeMask | StructureNotifyMask | FocusChangeMask); if (client.transientFor() && client.transientFor()->fbwindow()) { if (!client.transientFor()->fbwindow()->isIconic()) {

@@ -1480,22 +1481,12 @@ }

bool was_iconic = iconic; - m_blackbox_attrib.flags &= ~ATTRIB_HIDDEN; iconic = false; - setState(NormalState, false); - - ClientList::iterator client_it = clientList().begin(); - ClientList::iterator client_it_end = clientList().end(); - for (; client_it != client_it_end; ++client_it) { - (*client_it)->setEventMask(NoEventMask); - (*client_it)->show(); - (*client_it)->setEventMask(PropertyChangeMask | StructureNotifyMask | FocusChangeMask); - } - - if (reassoc) { + if (reassoc && !m_client->transients.empty()) { // deiconify all transients - client_it = clientList().begin(); + ClientList::iterator client_it = clientList().begin(); + ClientList::iterator client_it_end = clientList().end(); for (; client_it != client_it_end; ++client_it) { //TODO: Can this get stuck in a loop? WinClient::TransientList::iterator trans_it =

@@ -1512,26 +1503,16 @@

show(); // focus new, OR if it's the only window on the workspace - if (was_iconic && (screen().focusControl().focusNew() || screen().currentWorkspace()->numberOfWindows() == 1)) - setInputFocus(); - + // but not on startup: focus will be handled after creating everything + // we use m_focused as a signal to focus the window when mapped + if (was_iconic && (screen().currentWorkspace()->numberOfWindows() == 1 || + screen().focusControl().focusNew() || m_client->isTransient())) + m_focused = true; oplock = false; if (do_raise) raise(); -} - -/** - Set window in withdrawn state -*/ -void FluxboxWindow::withdraw(bool interrupt_moving) { -#ifdef DEBUG - cerr<<"FluxboxWindow::"<<__FUNCTION__<<": this = "<<this<<endl; -#endif // DEBUG - iconic = false; - - hide(interrupt_moving); } /** setFullscreen mode:

@@ -1590,9 +1571,9 @@

frame().setUseShape(true); if (m_toggled_decos) { if (m_old_decoration_mask & DECORM_TITLEBAR) - setDecoration(DECOR_NONE); + setDecorationMask(DECOR_NONE); else - setDecoration(DECOR_NORMAL); + setDecorationMask(DECOR_NORMAL); } else setDecorationMask(m_old_decoration_mask);

@@ -1698,10 +1679,15 @@ m_last_resize_y = new_y;

m_last_resize_w = new_w; m_last_resize_h = new_h; - ResizeDirection old_resize_corner = m_resize_corner; - m_resize_corner = NOCORNER; - fixsize(0, 0, true); - m_resize_corner = old_resize_corner; + // frankly, that xterm bug was pretty obscure, and it's really annoying not + // being able to maximize my terminals, so we make an option + // but we do fix size hints when restoring the window to normal size + if (!screen().getMaxIgnoreIncrement() || !maximized) { + ResizeDirection old_resize_corner = m_resize_corner; + m_resize_corner = NOCORNER; + fixsize(0, 0, (maximized ? true : false)); + m_resize_corner = old_resize_corner; + } moveResize(m_last_resize_x, m_last_resize_y, m_last_resize_w, m_last_resize_h);

@@ -1736,9 +1722,6 @@ unsigned int old_wkspc = m_workspace_number;

m_workspace_number = n; - m_blackbox_attrib.flags |= ATTRIB_WORKSPACE; - m_blackbox_attrib.workspace = m_workspace_number; - // notify workspace change if (m_initialized && !stuck && old_wkspc != m_workspace_number) { #ifdef DEBUG

@@ -1774,22 +1757,9 @@ // we're toggling, so if they're equal now, we need to change it

if (m_initialized && m_frame.isShaded() == shaded) frame().shade(); - if (shaded) { - shaded = false; - m_blackbox_attrib.flags ^= ATTRIB_SHADED; - m_blackbox_attrib.attrib ^= ATTRIB_SHADED; + shaded = !shaded; - if (m_initialized) - setState(NormalState, false); - } else { - shaded = true; - m_blackbox_attrib.flags |= ATTRIB_SHADED; - m_blackbox_attrib.attrib |= ATTRIB_SHADED; - // shading is the same as iconic - if (m_initialized) - setState(IconicState, false); - } - + // TODO: this should set IconicState, but then we can't focus the window } void FluxboxWindow::shadeOn() {

@@ -1808,22 +1778,10 @@ }

void FluxboxWindow::stick() { - if (stuck) { - m_blackbox_attrib.flags ^= ATTRIB_OMNIPRESENT; - m_blackbox_attrib.attrib ^= ATTRIB_OMNIPRESENT; - - stuck = false; - - } else { - stuck = true; - - m_blackbox_attrib.flags |= ATTRIB_OMNIPRESENT; - m_blackbox_attrib.attrib |= ATTRIB_OMNIPRESENT; - - } + stuck = !stuck; if (m_initialized) { - setState(m_current_state, false); + stateSig().notify(); // notify since some things consider "stuck" to be a pseudo-workspace m_workspacesig.notify(); }

@@ -1853,9 +1811,6 @@ #endif // DEBUG

// get root window WinClient *client = getRootTransientFor(m_client); - // if we don't have any root window use this as root - if (client == 0) - client = m_client; // if we have transient_for then we should put ourself last in // transients list so we get raised last and thus gets above the other transients if (m_client->transientFor() && m_client != m_client->transientFor()->transientList().back()) {

@@ -1884,15 +1839,14 @@ #endif // DEBUG

// get root window WinClient *client = getRootTransientFor(m_client); - // if we don't have any root window use this as root - if (client == 0) - client = m_client; - if (client->fbwindow()) lowerFluxboxWindow(*client->fbwindow()); } void FluxboxWindow::tempRaise() { + // Note: currently, this causes a problem with cycling through minimized + // clients if this window has more than one tab, since the window will not + // match isIconic() when the rest of the tabs get checked if (isIconic()) deiconify();

@@ -1931,19 +1885,9 @@

// get root window WinClient *client = getRootTransientFor(m_client); - // if we don't have any root window use this as root - if (client == 0) - client = m_client; - FluxboxWindow *win = client->fbwindow(); if (!win) return; - if (!win->isIconic()) { - if (layernum > m_layernum) - screen().updateNetizenWindowLower(client->window()); - else - screen().updateNetizenWindowRaise(client->window()); - } win->layerItem().moveToLayer(layernum); // remember number just in case a transient happens to revisit this window layernum = win->layerItem().getLayerNum();

@@ -1959,7 +1903,6 @@ WinClient::TransientList::const_iterator it_end = (*client_it)->transientList().end();

for (; it != it_end; ++it) { FluxboxWindow *fbwin = (*it)->fbwindow(); if (fbwin && !fbwin->isIconic()) { - screen().updateNetizenWindowRaise((*it)->window()); fbwin->layerItem().moveToLayer(layernum); fbwin->setLayerNum(layernum); }

@@ -1986,7 +1929,7 @@ // window has actually RECEIVED focus (got a FocusIn event)

// so now we make it a focused frame etc void FluxboxWindow::setFocusFlag(bool focus) { bool was_focused = isFocused(); - focused = focus; + m_focused = focus; #ifdef DEBUG cerr<<"FluxboxWindow("<<title()<<")::setFocusFlag("<<focus<<")"<<endl; #endif // DEBUG

@@ -1997,7 +1940,7 @@ if (focus != frame().focused())

frame().setFocus(focus); if (screen().doAutoRaise() && !screen().focusControl().isCycling()) { - if (focused) + if (m_focused) m_timer.start(); else m_timer.stop();

@@ -2005,6 +1948,7 @@ }

// did focus change? notify listeners if (was_focused != focus) { + m_attention_state = false; m_focussig.notify(); if (m_client) m_client->focusSig().notify();

@@ -2071,24 +2015,34 @@ Use setting_up for setting startup state - it may not be committed yet

That'll happen when its mapped */ void FluxboxWindow::setState(unsigned long new_state, bool setting_up) { - if (numClients() == 0) + m_current_state = new_state; + if (numClients() == 0 || setting_up) return; - m_current_state = new_state; - if (!setting_up) { - unsigned long state[2]; - state[0] = (unsigned long) m_current_state; - state[1] = (unsigned long) None; + unsigned long state[2]; + state[0] = (unsigned long) m_current_state; + state[1] = (unsigned long) None; - for_each(m_clientlist.begin(), m_clientlist.end(), - FbTk::ChangeProperty(display, FbAtoms::instance()->getWMStateAtom(), - PropModeReplace, - (unsigned char *)state, 2)); + for_each(m_clientlist.begin(), m_clientlist.end(), + FbTk::ChangeProperty(display, + FbAtoms::instance()->getWMStateAtom(), + PropModeReplace, + (unsigned char *)state, 2)); - saveBlackboxAttribs(); - //notify state changed - m_statesig.notify(); + ClientList::iterator it = clientList().begin(); + ClientList::iterator it_end = clientList().end(); + for (; it != it_end; ++it) { + (*it)->setEventMask(NoEventMask); + if (new_state == IconicState) + (*it)->hide(); + else if (new_state == NormalState) + (*it)->show(); + (*it)->setEventMask(PropertyChangeMask | StructureNotifyMask | FocusChangeMask | KeyPressMask); } + + saveBlackboxAttribs(); + //notify state changed + m_statesig.notify(); } bool FluxboxWindow::getState() {

@@ -2153,23 +2107,6 @@ XFree(static_cast<void *>(net));

} else return; - if (m_blackbox_attrib.flags & ATTRIB_SHADED && - m_blackbox_attrib.attrib & ATTRIB_SHADED) - shaded = true; - - if (m_blackbox_attrib.flags & ATTRIB_HIDDEN && - m_blackbox_attrib.attrib & ATTRIB_HIDDEN) { - iconic = true; - } - - if (( m_blackbox_attrib.workspace != screen().currentWorkspaceID()) && - ( m_blackbox_attrib.workspace < screen().numberOfWorkspaces())) - m_workspace_number = m_blackbox_attrib.workspace; - - if (m_blackbox_attrib.flags & ATTRIB_OMNIPRESENT && - m_blackbox_attrib.attrib & ATTRIB_OMNIPRESENT) - stuck = true; - if (m_blackbox_attrib.flags & ATTRIB_STACK) { //!! TODO check value? m_layernum = m_blackbox_attrib.stack;

@@ -2177,21 +2114,10 @@ }

if ((m_blackbox_attrib.flags & ATTRIB_MAXHORIZ) || (m_blackbox_attrib.flags & ATTRIB_MAXVERT)) { - int x = m_blackbox_attrib.premax_x, y = m_blackbox_attrib.premax_y; - unsigned int w = m_blackbox_attrib.premax_w, h = m_blackbox_attrib.premax_h; - maximized = MAX_NONE; - if ((m_blackbox_attrib.flags & ATTRIB_MAXHORIZ) && - (m_blackbox_attrib.flags & ATTRIB_MAXVERT)) - maximized = MAX_FULL; - else if (m_blackbox_attrib.flags & ATTRIB_MAXVERT) - maximized = MAX_VERT; - else if (m_blackbox_attrib.flags & ATTRIB_MAXHORIZ) - maximized = MAX_HORZ; - - m_blackbox_attrib.premax_x = x; - m_blackbox_attrib.premax_y = y; - m_blackbox_attrib.premax_w = w; - m_blackbox_attrib.premax_h = h; + m_blackbox_attrib.premax_x = m_blackbox_attrib.premax_x; + m_blackbox_attrib.premax_y = m_blackbox_attrib.premax_y; + m_blackbox_attrib.premax_w = m_blackbox_attrib.premax_w; + m_blackbox_attrib.premax_h = m_blackbox_attrib.premax_h; } }

@@ -2199,7 +2125,7 @@

/** Show the window menu at pos mx, my */ -void FluxboxWindow::showMenu(int menu_x, int menu_y, WinClient *client) { +void FluxboxWindow::showMenu(int menu_x, int menu_y) { // move menu directly under titlebar int head = screen().getHead(menu_x, menu_y);

@@ -2215,11 +2141,7 @@ menu_x = screen().maxLeft(head);

else if (menu_x + static_cast<signed>(menu().width()) >= static_cast<signed>(screen().maxRight(head))) menu_x = screen().maxRight(head) - menu().width() - 1; - if (client && (client->fbwindow() == this)) - WindowCmd<void>::setClient(client); - else - WindowCmd<void>::setWindow(this); - + WindowCmd<void>::setWindow(this); menu().move(menu_x, menu_y); menu().show(); menu().raise();

@@ -2238,34 +2160,13 @@ menu().hide();

return; } - /* Check if we're on a tab, we should make the menu for that tab */ - WinClient *client = 0; - Window labelbutton = 0; - int dest_x = 0, dest_y = 0; - if (XTranslateCoordinates(FbTk::App::instance()->display(), - parent().window(), frame().tabcontainer().window(), - m_last_button_x, m_last_button_y, &dest_x, &dest_y, - &labelbutton)) { - - Client2ButtonMap::iterator it = - find_if(m_labelbuttons.begin(), - m_labelbuttons.end(), - Compose(bind2nd(equal_to<Window>(), labelbutton), - Compose(mem_fun(&TextButton::window), - Select2nd<Client2ButtonMap::value_type>()))); - - // label button not found - if (it != m_labelbuttons.end()) - client = it->first; - } - menu().disableTitle(); int menu_y = frame().titlebar().height() + frame().titlebar().borderWidth(); if (!decorations.titlebar) // if we don't have any titlebar menu_y = 0; if (m_last_button_x < x() || m_last_button_x > x() + static_cast<signed>(width())) m_last_button_x = x(); - showMenu(m_last_button_x, menu_y + frame().y(), client); + showMenu(m_last_button_x, menu_y + frame().y()); }

@@ -2339,53 +2240,56 @@ }

// Note: this function never gets called from WithdrawnState // initial state is handled in restoreAttributes() and init() + + // if the user doesn't want the window, then ignore request + if (!allowsFocusFromClient()) + return; + setCurrentClient(*client, false); // focus handled on MapNotify deiconify(false); } +bool FluxboxWindow::allowsFocusFromClient() { + + // check what to do if window is on another workspace + if (screen().currentWorkspaceID() != workspaceNumber() && !isStuck()) { + BScreen::FollowModel model = screen().getFollowModel(); + if (model == BScreen::IGNORE_OTHER_WORKSPACES) + return false; + } + + FluxboxWindow *cur = FocusControl::focusedFbWindow(); + WinClient *client = FocusControl::focusedWindow(); + if (cur && client && cur->isTyping() && + getRootTransientFor(m_client) != getRootTransientFor(client)) + return false; + + return true; + +} void FluxboxWindow::mapNotifyEvent(XMapEvent &ne) { WinClient *client = findClient(ne.window); - if (client == 0 || client != m_client) + if (!client || client != m_client) + return; + + if (ne.override_redirect || !isVisible() || !client->validateClient()) return; -#ifdef DEBUG - cerr<<"FluxboxWindow::mapNotifyEvent: " - <<"ne.override_redirect = "<<ne.override_redirect - <<" isVisible() = "<<isVisible()<<endl; -#endif // DEBUG - if (!ne.override_redirect && isVisible()) { -#ifdef DEBUG - cerr<<"FluxboxWindow::mapNotify: not override redirect ans visible!"<<endl; -#endif // DEBUG - Fluxbox *fluxbox = Fluxbox::instance(); - fluxbox->grab(); - if (! client->validateClient()) - return; + iconic = false; + // setting state will cause all tabs to be mapped, but we only want the + // original tab to be focused + if (m_current_state != NormalState) setState(NormalState, false); - FluxboxWindow *cur = FocusControl::focusedFbWindow(); - if (client->isTransient() || - m_screen.currentWorkspace()->numberOfWindows() == 1 || - m_screen.focusControl().focusNew() && !(cur && cur->isFullscreen())) - setCurrentClient(*client, true); - else if (m_screen.focusControl().focusNew()) - Fluxbox::instance()->attentionHandler().addAttention(*client); - - - iconic = false; - - // Auto-group from tab? - if (!client->isTransient()) { -#ifdef DEBUG - cerr<<__FILE__<<"("<<__FUNCTION__<<") TODO check grouping here"<<endl; -#endif // DEBUG - } + // we use m_focused as a signal that this should be focused when mapped + if (m_focused) { + m_focused = false; + focus(); + } - fluxbox->ungrab(); - } } /**

@@ -2442,15 +2346,16 @@ } break;

case XA_WM_HINTS: client.updateWMHints(); - hintSig().notify(); // notify listeners + titleSig().notify(); + // nothing uses this yet + // hintSig().notify(); // notify listeners break; case XA_WM_ICON_NAME: // update icon title and then do normal XA_WM_NAME stuff client.updateIconTitle(); case XA_WM_NAME: - updateTitleFromClient(client); - titleSig().notify(); + client.updateTitle(); break; case XA_WM_NORMAL_HINTS: {

@@ -2495,8 +2400,10 @@ changed = true;

functions.resize = true; } - if (changed) + if (changed) { setupWindow(); + applyDecorations(); + } } moveResize(frame().x(), frame().y(),

@@ -2514,14 +2421,6 @@ client.updateMWMHints();

updateMWMHintsFromClient(client); updateRememberStateFromClient(client); applyDecorations(); // update decorations (if they changed) - } else if (atom == fbatoms->getFluxboxHintsAtom()) { - client.updateBlackboxHints(); - updateBlackboxHintsFromClient(client); - if (client.getBlackboxHint() != 0 && - (client.getBlackboxHint()->flags & ATTRIB_DECORATION)) { - updateRememberStateFromClient(client); - applyDecorations(); // update decoration - } } break; }

@@ -2607,7 +2506,6 @@

if (cr.value_mask & CWHeight) ch = cr.height; - // whether we should send ConfigureNotify to netizens // the request is for client window so we resize the frame to it first if (old_w != cw || old_h != ch) { if (old_x != cx || old_y != cy)

@@ -2623,7 +2521,7 @@ switch (cr.detail) {

case Above: case TopIf: default: - setCurrentClient(*client, focused); + setCurrentClient(*client, m_focused); raise(); break;

@@ -2638,6 +2536,41 @@ sendConfigureNotify();

} +// keep track of last keypress in window, so we can decide not to focusNew +void FluxboxWindow::keyPressEvent(XKeyEvent &ke) { + // if there's a modifier key down, the user probably expects the new window + if (FbTk::KeyUtil::instance().cleanMods(ke.state)) + return; + + // we need to ignore modifier keys themselves, too + KeySym ks; + char keychar[1]; + XLookupString(&ke, keychar, 1, &ks, 0); + if (IsModifierKey(ks)) + return; + + // if the key was return/enter, the user probably expects the window + // e.g., typed the command in a terminal + if (ks == XK_KP_Enter || ks == XK_Return) { + // we'll actually reset the time for this one + m_last_keypress_time.tv_sec = 0; + return; + } + + // otherwise, make a note that the user is typing + gettimeofday(&m_last_keypress_time, 0); +} + +bool FluxboxWindow::isTyping() { + timeval now; + if (gettimeofday(&now, NULL) == -1) + return false; + + unsigned int diff = 1000*(now.tv_sec - m_last_keypress_time.tv_sec); + diff += (now.tv_usec - m_last_keypress_time.tv_usec)/1000; + + return (diff < screen().noFocusWhileTypingDelay()); +} void FluxboxWindow::buttonPressEvent(XButtonEvent &be) { m_last_button_x = be.x_root;

@@ -2648,9 +2581,8 @@ frame().buttonPressEvent(be);

if (be.button == 1 || (be.button == 3 && be.state == Fluxbox::instance()->getModKey())) { - if ( (! focused) ) { //check focus - setInputFocus(); - } + if (!m_focused) //check focus + focus(); if (frame().window().window() == be.window || frame().tabcontainer().window() == be.window) { if (screen().clickRaises())

@@ -2673,7 +2605,7 @@ }

void FluxboxWindow::buttonReleaseEvent(XButtonEvent &re) { - if ((re.button == 1) && (re.state & Fluxbox::instance()->getModKey()) + if ((re.button == 1) && (re.state & Fluxbox::instance()->getModKey()) && !screen().clickRaises()) { if (!isMoving())

@@ -2801,7 +2733,7 @@ // move the pointer to (m_last_resize_x,m_last_resize_y)

XWarpPointer(display, None, me.root, 0, 0, 0, 0, m_last_resize_x, m_last_resize_y); - screen().changeWorkspaceID(new_id); + screen().sendToWorkspace(new_id, this, true); } }

@@ -3043,7 +2975,7 @@ sa.enter = sa.leave = False;

XCheckIfEvent(display, &dummy, queueScanner, (char *) &sa); if ((!sa.leave || sa.inferior) && !screen().focusControl().isCycling() ) { - setInputFocus(); + focus(); } } }

@@ -3060,61 +2992,6 @@ //if (ev.window == frame().window())

//installColormap(false); } -// TODO: functions should not be affected by decoration -void FluxboxWindow::setDecoration(Decoration decoration, bool apply) { - switch (decoration) { - case DECOR_NONE: - decorations.titlebar = decorations.border = decorations.handle = - decorations.iconify = decorations.maximize = - decorations.tab = false; //tab is also a decor - decorations.menu = true; // menu is present - // functions.iconify = functions.maximize = true; - // functions.move = true; // We need to move even without decor - // functions.resize = true; // We need to resize even without decor - break; - - default: - case DECOR_NORMAL: - decorations.titlebar = decorations.border = decorations.handle = - decorations.iconify = decorations.maximize = - decorations.menu = decorations.tab = true; - functions.resize = functions.move = functions.iconify = - functions.maximize = true; - break; - - case DECOR_TAB: - decorations.border = decorations.iconify = decorations.maximize = - decorations.menu = decorations.tab = true; - decorations.titlebar = decorations.handle = false; - functions.resize = functions.move = functions.iconify = - functions.maximize = true; - break; - - case DECOR_TINY: - decorations.titlebar = decorations.iconify = decorations.menu = - functions.move = functions.iconify = decorations.tab = true; - decorations.border = decorations.handle = decorations.maximize = - functions.resize = functions.maximize = false; - break; - - case DECOR_TOOL: - decorations.titlebar = decorations.tab = decorations.menu = functions.move = true; - decorations.iconify = decorations.border = decorations.handle = - decorations.maximize = functions.resize = functions.maximize = - functions.iconify = false; - break; - } - - // we might want to wait with apply decorations - if (apply) - applyDecorations(); - - //!! TODO: make sure this is correct - // is this reconfigure necessary??? - // reconfigure(); - -} - // commit current decoration values to actual displayed things void FluxboxWindow::applyDecorations(bool initial) { frame().clientArea().setBorderWidth(0); // client area bordered by other things

@@ -3191,10 +3068,10 @@

if (m_toggled_decos) { m_old_decoration_mask = decorationMask(); if (decorations.titlebar) - setDecoration(DECOR_NONE); + setDecorationMask(DECOR_NONE); else - setDecoration(DECOR_NORMAL); - } else + setDecorationMask(DECOR_NORMAL); + } else //revert back to old decoration setDecorationMask(m_old_decoration_mask); }

@@ -3247,6 +3124,9 @@ void FluxboxWindow::startMoving(int x, int y) {

if (s_num_grabs > 0) return; + if (isMaximized() && screen().getMaxDisableMove()) + return; + // save first event point m_last_resize_x = x; m_last_resize_y = y;

@@ -3296,7 +3176,7 @@ moveResize(m_last_move_x, m_last_move_y, frame().width(), frame().height());

if (m_workspace_number != screen().currentWorkspaceID()) { screen().reassociateWindow(this, screen().currentWorkspaceID(), true); frame().show(); - setInputFocus(); + focus(); } } fluxbox->ungrab();

@@ -3332,7 +3212,7 @@ }

if (m_workspace_number == screen().currentWorkspaceID()) { frame().show(); - setInputFocus(); + focus(); } FbTk::App::instance()->sync(false);

@@ -3397,7 +3277,7 @@

// we only care about the left/top etc that includes borders int borderW = 0; - if (decorationMask() & (DECORM_ENABLED|DECORM_BORDER|DECORM_HANDLE)) + if (decorationMask() & (DECORM_BORDER|DECORM_HANDLE)) borderW = frame().window().borderWidth(); int top = orig_top; // orig include the borders

@@ -3469,7 +3349,7 @@ for (; it != it_end; it++) {

if ((*it) == this) continue; // skip myself - bw = (*it)->decorationMask() & (DECORM_ENABLED|DECORM_BORDER|DECORM_HANDLE) ? + bw = (*it)->decorationMask() & (DECORM_BORDER|DECORM_HANDLE) ? (*it)->frame().window().borderWidth() : 0; snapToWindow(dx, dy, left, right, top, bottom,

@@ -3517,6 +3397,9 @@

if (s_num_grabs > 0 || isShaded() || isIconic() ) return; + if (isMaximized() && screen().getMaxDisableResize()) + return; + m_resize_corner = dir; resizing = true;

@@ -3714,14 +3597,13 @@ FbTk::Menu &FluxboxWindow::menu() {

return screen().windowMenu(); } -const FbTk::FbPixmap &FluxboxWindow::iconPixmap() const { return m_client->iconPixmap(); } -const FbTk::FbPixmap &FluxboxWindow::iconMask() const { return m_client->iconMask(); } +bool FluxboxWindow::acceptsFocus() const { + return (m_client ? m_client->acceptsFocus() : false); +} -const bool FluxboxWindow::usePixmap() const { - return m_client ? m_client->usePixmap() : false; +const FbTk::PixmapWithMask &FluxboxWindow::icon() const { + return (m_client ? m_client->icon() : m_icon); } - -const bool FluxboxWindow::useMask() const { return m_client->useMask(); } const FbTk::Menu &FluxboxWindow::menu() const { return screen().windowMenu();

@@ -3739,17 +3621,19 @@ }

const string &FluxboxWindow::title() const { - static string empty_string; - if (m_client == 0) - return empty_string; - return m_client->title(); + return (m_client ? m_client->title() : m_title); +} + +const std::string &FluxboxWindow::getWMClassName() const { + return (m_client ? m_client->getWMClassName() : m_instance_name); +} + +const std::string &FluxboxWindow::getWMClassClass() const { + return (m_client ? m_client->getWMClassClass() : m_class_name); } -const string &FluxboxWindow::iconTitle() const { - static string empty_string; - if (m_client == 0) - return empty_string; - return m_client->iconTitle(); +std::string FluxboxWindow::getWMRole() const { + return (m_client ? m_client->getWMRole() : "FluxboxWindow"); } int FluxboxWindow::normalX() const {

@@ -3780,74 +3664,6 @@ }

int FluxboxWindow::initialState() const { return m_client->initial_state; } -void FluxboxWindow::changeBlackboxHints(const BlackboxHints &net) { - if ((net.flags & ATTRIB_SHADED) && - ((m_blackbox_attrib.attrib & ATTRIB_SHADED) != - (net.attrib & ATTRIB_SHADED))) - shade(); - - if ((net.flags & ATTRIB_HIDDEN) && - ((m_blackbox_attrib.attrib & ATTRIB_HIDDEN) != - (net.attrib & ATTRIB_HIDDEN))) { - bool want_iconic = net.attrib & ATTRIB_HIDDEN; - if (!iconic && want_iconic) - iconify(); - else if (iconic && !want_iconic) - deiconify(); - } - - if (net.flags & (ATTRIB_MAXVERT | ATTRIB_MAXHORIZ)) { - // make maximise look like the net maximise flags - int want_max = MAX_NONE; - - if (net.flags & ATTRIB_MAXVERT) - want_max |= MAX_VERT; - if (net.flags & ATTRIB_MAXHORIZ) - want_max |= MAX_HORZ; - - if (want_max == MAX_NONE && maximized != MAX_NONE) { - maximize(maximized); - } else if (want_max == MAX_FULL && maximized != MAX_FULL) { - maximize(MAX_FULL); - } else { - // either we want vert and aren't - // or we want horizontal and aren't - if (want_max == MAX_VERT ^ (bool)(maximized & MAX_VERT)) - maximize(MAX_VERT); - if (want_max == MAX_HORZ ^ (bool)(maximized & MAX_HORZ)) - maximize(MAX_HORZ); - } - } - - if ((net.flags & ATTRIB_OMNIPRESENT) && - ((m_blackbox_attrib.attrib & ATTRIB_OMNIPRESENT) != - (net.attrib & ATTRIB_OMNIPRESENT))) - stick(); - - if ((net.flags & ATTRIB_WORKSPACE) && - (m_workspace_number != net.workspace)) { - - screen().reassociateWindow(this, net.workspace, true); - - if (screen().currentWorkspaceID() != net.workspace) - withdraw(true); - else - deiconify(); - } - - if (net.flags & ATTRIB_STACK) { - if ((unsigned int) m_layernum != net.stack) { - moveToLayer(net.stack); - } - } - - if (net.flags & ATTRIB_DECORATION) { - setDecoration(static_cast<Decoration>(net.decoration)); - } - -} - - void FluxboxWindow::fixsize(int *user_w, int *user_h, bool maximizing) { int titlebar_height = (decorations.titlebar ? frame().titlebar().height() +

@@ -3892,7 +3708,7 @@ frame().clientArea().width(),

frame().clientArea().height()); } -void FluxboxWindow::sendConfigureNotify(bool send_to_netizens) { +void FluxboxWindow::sendConfigureNotify() { ClientList::iterator client_it = m_clientlist.begin(); ClientList::iterator client_it_end = m_clientlist.end(); for (; client_it != client_it_end; ++client_it) {

@@ -3910,23 +3726,6 @@ frame().clientArea().y(),

frame().clientArea().width(), frame().clientArea().height()); - if (send_to_netizens) { - XEvent event; - event.type = ConfigureNotify; - - event.xconfigure.display = display; - event.xconfigure.event = client.window(); - event.xconfigure.window = client.window(); - event.xconfigure.x = frame().x() + frame().clientArea().x(); - event.xconfigure.y = frame().y() + frame().clientArea().y(); - event.xconfigure.width = client.width(); - event.xconfigure.height = client.height(); - event.xconfigure.border_width = client.old_bw; - event.xconfigure.above = frame().window().window(); - event.xconfigure.override_redirect = false; - - screen().updateNetizenConfigNotify(event); - } } // end for }

@@ -4156,7 +3955,6 @@ winbtn = new WinButton(*this, winbutton_theme,

dir[i], frame().titlebar(), 0, 0, 10, 10); - hintSig().attach(winbtn); titleSig().attach(winbtn); winbtn->setOnClick(show_menu_cmd); break;

@@ -4242,13 +4040,14 @@ }

void FluxboxWindow::associateClient(WinClient &client) { - FbWinFrame::ButtonId btn = frame().createTab(client.title(), - new SetClientCmd(client), - Fluxbox::instance()->getTabsPadding()); + IconButton *btn = frame().createTab(client); + + FbTk::RefCount<FbTk::Command> setcmd(new SetClientCmd(client)); + btn->setOnClick(setcmd, 1); + btn->setTextPadding(Fluxbox::instance()->getTabsPadding()); + btn->setPixmap(screen().getTabsUsePixmap()); m_labelbuttons[&client] = btn; - - FbTk::EventManager &evm = *FbTk::EventManager::instance();

@@ -4259,24 +4058,17 @@ }

int FluxboxWindow::getDecoMaskFromString(const string &str_label) { if (strcasecmp(str_label.c_str(), "NONE") == 0) - return 0; + return DECOR_NONE; if (strcasecmp(str_label.c_str(), "NORMAL") == 0) - return FluxboxWindow::DECORM_LAST - 1; + return DECOR_NORMAL; if (strcasecmp(str_label.c_str(), "TINY") == 0) - return FluxboxWindow::DECORM_TITLEBAR - | FluxboxWindow::DECORM_ICONIFY - | FluxboxWindow::DECORM_MENU - | FluxboxWindow::DECORM_TAB; + return DECOR_TINY; if (strcasecmp(str_label.c_str(), "TOOL") == 0) - return FluxboxWindow::DECORM_TITLEBAR - | FluxboxWindow::DECORM_MENU; + return DECOR_TOOL; if (strcasecmp(str_label.c_str(), "BORDER") == 0) - return FluxboxWindow::DECORM_BORDER - | FluxboxWindow::DECORM_MENU; + return DECOR_BORDER; if (strcasecmp(str_label.c_str(), "TAB") == 0) - return FluxboxWindow::DECORM_BORDER - | FluxboxWindow::DECORM_MENU - | FluxboxWindow::DECORM_TAB; + return DECOR_TAB; unsigned int mask = atoi(str_label.c_str()); if (mask) return mask;
M src/Window.hhsrc/Window.hh

@@ -32,11 +32,13 @@ #include "FbTk/Subject.hh"

#include "FbTk/EventHandler.hh" #include "FbTk/XLayerItem.hh" #include "FbWinFrame.hh" +#include "Focusable.hh" #include "WinButton.hh" #include <X11/Xlib.h> #include <X11/Xutil.h> +#include <sys/time.h> #include <vector> #include <string> #include <memory>

@@ -56,17 +58,8 @@ class Menu;

} /// Creates the window frame and handles any window event for it -class FluxboxWindow: public FbTk::EventHandler { +class FluxboxWindow: public Focusable, public FbTk::EventHandler { public: - /// Represents certain "preset" sets of decorations. - enum Decoration { - DECOR_NONE=0, ///< no decor at all - DECOR_NORMAL, ///< normal normal - DECOR_TINY, ///< tiny decoration - DECOR_TOOL, ///< decor tool - DECOR_TAB ///< decor tab (border + tab) - }; - /// Motif wm Hints enum { MwmHintsFunctions = (1l << 0), ///< use motif wm functions

@@ -96,14 +89,14 @@ };

/// attributes for BlackboxHints enum Attrib { - ATTRIB_SHADED = 0x01, - ATTRIB_MAXHORIZ = 0x02, - ATTRIB_MAXVERT = 0x04, - ATTRIB_OMNIPRESENT = 0x08, - ATTRIB_WORKSPACE = 0x10, - ATTRIB_STACK = 0x20, - ATTRIB_DECORATION = 0x40, - ATTRIB_HIDDEN = 0x80, + ATTRIB_SHADED = 0x01, ///< shaded + ATTRIB_MAXHORIZ = 0x02, ///< maximized horizontal + ATTRIB_MAXVERT = 0x04, ///< maximized vertical + ATTRIB_OMNIPRESENT = 0x08, ///< omnipresent (sticky) + ATTRIB_WORKSPACE = 0x10, ///< workspace + ATTRIB_STACK = 0x20, ///< stack + ATTRIB_DECORATION = 0x40, ///< decorations + ATTRIB_HIDDEN = 0x80, ///< hidden }; /**

@@ -135,7 +128,18 @@ DECORM_ENABLED = (1<<10),

DECORM_LAST = (1<<11) // useful for getting "All" }; + enum Decoration { + DECOR_NONE = 0, + DECOR_NORMAL = DECORM_LAST - 1, + DECOR_TINY = DECORM_TITLEBAR|DECORM_ICONIFY|DECORM_MENU|DECORM_TAB, + DECOR_TOOL = DECORM_TITLEBAR|DECORM_MENU, + DECOR_BORDER = DECORM_BORDER|DECORM_MENU, + DECOR_TAB = DECORM_BORDER|DECORM_MENU|DECORM_TAB + }; + /** + * Resize direction while resizing + */ enum ResizeDirection { NOCORNER = -1, LEFTTOP = 0,

@@ -149,11 +153,7 @@ LEFT = 7,

ALLCORNERS = 8 }; - typedef struct _blackbox_hints { - unsigned long flags, attrib, workspace, stack; - long decoration; - } BlackboxHints; - + /// holds old blackbox attributes typedef struct _blackbox_attributes { unsigned long flags, attrib, workspace, stack; long premax_x, premax_y;

@@ -179,33 +179,76 @@ /// remove client from client list

bool removeClient(WinClient &client); /// set new current client and raise it bool setCurrentClient(WinClient &client, bool setinput = true); - void setLabelButtonFocus(WinClient &client, bool value = true); - void setAttentionState(bool value); - bool getAttentionState() { return m_attention_state; } + /** + * Searches for a client + * @param win the client X window + * @return pointer to client matching the window or NULL + */ WinClient *findClient(Window win); + /// select next client void nextClient(); + /// select previous client void prevClient(); + /// move the current client to the left void moveClientLeft(); + /// move the current client to the right void moveClientRight(); + /** + * Move a client to the right of dest. + * @param win the client to move + * @param dest the left-of-client + */ void moveClientRightOf(WinClient &win, WinClient &dest); + /** + * Move a client to the right of dest. + * @param win the client to move + * @param dest the left-of-client + */ void moveClientLeftOf(WinClient &win, WinClient &dest); + /** + * Move client to place specified by pixel position + * @param win the client to move + * @param x position + * @param y position + */ void moveClientTo(WinClient &win, int x, int y); + /** + * Calculates insertition position in the list by + * using pixel position x and y. + * @param x position + * @param y position + * @return iterator position for insertion + */ ClientList::iterator getClientInsertPosition(int x, int y); + /** + * Take focus. + * @see Focusable + * @return true if it took focus. + */ + bool focus(); + bool allowsFocusFromClient(); - bool setInputFocus(); - void raiseAndFocus() { raise(); setInputFocus(); } + /// Raises the window and takes focus (if possible). + void raiseAndFocus() { raise(); focus(); } + /// sets the internal focus flag void setFocusFlag(bool flag); - // map this window + /// make this window visible void show(); - // unmap this window + /// hide window void hide(bool interrupt_moving = true); + /// iconify window void iconify(); + /** + * Deiconify window + * @param reassoc reassociate the window to the current workspace + * @param do_raise raise the window when its been deiconfied + */ void deiconify(bool reassoc = true, bool do_raise = true); // ------------------ // Per window transparency addons - unsigned char getFocusedAlpha() const { return frame().getAlpha(true); } - unsigned char getUnfocusedAlpha() const { return frame().getAlpha(false); } + unsigned char getFocusedAlpha() const { return frame().getAlpha(true); } + unsigned char getUnfocusedAlpha() const { return frame().getAlpha(false); } void setFocusedAlpha(unsigned char alpha) { frame().setAlpha(true, alpha); } void setUnfocusedAlpha(unsigned char alpha) { frame().setAlpha(false, alpha); } void updateAlpha(bool focused, unsigned char alpha) { frame().setAlpha(focused, alpha); }

@@ -218,8 +261,6 @@ /// close current client

void close(); /// kill current client void kill(); - /// set the window in withdrawn state - void withdraw(bool interrupt_moving); /// set fullscreen void setFullscreen(bool flag); /// toggle maximize

@@ -245,8 +286,11 @@ void lower();

void tempRaise(); void raiseLayer(); void lowerLayer(); + /// moves the window to a new layer void moveToLayer(int layernum, bool force = false); + /// sets the window focus hidden state void setFocusHidden(bool value); + /// sets the window icon hidden state void setIconHidden(bool value); void reconfigure();

@@ -262,11 +306,21 @@ /// move and resize frame to pox x,y and size width, height

void moveResize(int x, int y, unsigned int width, unsigned int height, bool send_event = false); /// move to pos x,y and resize client window to size width, height void moveResizeForClient(int x, int y, unsigned int width, unsigned int height, int gravity = ForgetGravity, unsigned int client_bw = 0); + /** + * Determines maximum size using all clients that this window can have. + * @param width will be filled in with maximum width + * @param height will be filled in with maximum height + */ + void maxSize(unsigned int &width, unsigned int &height); void setWorkspace(int n); - void changeBlackboxHints(const BlackboxHints &bh); void updateFunctions(); void restoreAttributes(); - void showMenu(int mx, int my, WinClient *client = 0); + /** + * Show window meny at at given position + * @param mx position + * @param my position + */ + void showMenu(int mx, int my); // popup menu on last button press position void popupMenu();

@@ -277,6 +331,7 @@ @name event handlers

*/ //@{ void handleEvent(XEvent &event); + void keyPressEvent(XKeyEvent &ke); void buttonPressEvent(XButtonEvent &be); void buttonReleaseEvent(XButtonEvent &be); void motionNotifyEvent(XMotionEvent &me);

@@ -291,7 +346,6 @@ void enterNotifyEvent(XCrossingEvent &ev);

void leaveNotifyEvent(XCrossingEvent &ev); //@} - void setDecoration(Decoration decoration, bool apply = true); void applyDecorations(bool initial = false); void toggleDecoration();

@@ -333,7 +387,6 @@

inline bool isFocusHidden() const { return m_focus_hidden; } inline bool isIconHidden() const { return m_icon_hidden; } inline bool isManaged() const { return m_initialized; } - inline bool isFocused() const { return focused; } bool isVisible() const; inline bool isIconic() { return iconic; } inline bool isIconic() const { return iconic; }

@@ -360,8 +413,7 @@ inline const ClientList &clientList() const { return m_clientlist; }

inline WinClient &winClient() { return *m_client; } inline const WinClient &winClient() const { return *m_client; } - inline const BScreen &screen() const { return m_screen; } - inline BScreen &screen() { return m_screen; } + bool isTyping(); inline const FbTk::XLayerItem &layerItem() const { return m_frame.layerItem(); } inline FbTk::XLayerItem &layerItem() { return m_frame.layerItem(); }

@@ -377,13 +429,13 @@

const FbTk::FbWindow &parent() const { return m_parent; } FbTk::FbWindow &parent() { return m_parent; } - const FbTk::FbPixmap &iconPixmap() const; - const FbTk::FbPixmap &iconMask() const; - const bool usePixmap() const; - const bool useMask() const; + bool acceptsFocus() const; + const FbTk::PixmapWithMask &icon() const; + const std::string &title() const; + const std::string &getWMClassName() const; + const std::string &getWMClassClass() const; + std::string getWMRole() const; - const std::string &title() const; - const std::string &iconTitle() const; inline int x() const { return frame().x(); } inline int y() const { return frame().y(); } inline unsigned int width() const { return frame().width(); }

@@ -425,11 +477,6 @@ FbTk::Subject &hintSig() { return m_hintsig; }

const FbTk::Subject &hintSig() const { return m_hintsig; } FbTk::Subject &workspaceSig() { return m_workspacesig; } const FbTk::Subject &workspaceSig() const { return m_workspacesig; } - FbTk::Subject &dieSig() { return m_diesig; } - const FbTk::Subject &dieSig() const { return m_diesig; } - FbTk::Subject &focusSig() { return m_focussig; } - FbTk::Subject &titleSig() { return m_titlesig; } - FbTk::Subject &attentionSig() { return m_attentionsig; } /** @} */ // end group signals void reconfigTheme();

@@ -464,9 +511,7 @@ bool getState();

/// gets title string from client window and updates frame's title void updateTitleFromClient(WinClient &client); /// gets icon name from client window - void updateIconNameFromClient(WinClient &client); void updateMWMHintsFromClient(WinClient &client); - void updateBlackboxHintsFromClient(const WinClient &client); void updateRememberStateFromClient(WinClient &client); void saveBlackboxAttribs(); void associateClientWindow(bool use_attrs = false, int x = 0, int y = 0, unsigned int width = 1, unsigned int height = 1, int gravity = ForgetGravity, unsigned int client_bw = 0);

@@ -479,7 +524,7 @@ // user_w/h return the values that should be shown to the user

void fixsize(int *user_w = 0, int *user_h = 0, bool maximizing = false); void moveResizeClient(WinClient &client, int x, int y, unsigned int width, unsigned int height); /// sends configurenotify to all clients - void sendConfigureNotify(bool send_to_netizens = true); + void sendConfigureNotify(); static void grabPointer(Window grab_window, Bool owner_events,

@@ -496,10 +541,7 @@ // state and hint signals

WinSubject m_hintsig, m_statesig, m_layersig, - m_workspacesig, - m_diesig, m_focussig, - m_titlesig, - m_attentionsig; + m_workspacesig; class ThemeListener: public FbTk::Observer { public:

@@ -516,14 +558,12 @@ time_t m_creation_time;

// Window states bool moving, resizing, shaded, iconic, - focused, stuck, m_initialized, fullscreen; + stuck, m_initialized, fullscreen; int maximized; WinClient *m_attaching_tab; - bool m_attention_state; - BScreen &m_screen; /// screen on which this window exist FbTk::Timer m_timer; Display *display; /// display connection BlackboxAttributes m_blackbox_attrib;

@@ -533,6 +573,8 @@ int m_last_resize_x, m_last_resize_y; // handles last button press event for resize

int m_last_move_x, m_last_move_y; // handles last pos for non opaque moving unsigned int m_last_resize_h, m_last_resize_w; // handles height/width for resize "window" + timeval m_last_keypress_time; + unsigned int m_workspace_number; unsigned long m_current_state; // NormalState | IconicState | Withdrawn

@@ -540,7 +582,7 @@ unsigned int m_old_decoration_mask;

ClientList m_clientlist; WinClient *m_client; ///< current client - typedef std::map<WinClient *, FbTk::TextButton *> Client2ButtonMap; + typedef std::map<WinClient *, IconButton *> Client2ButtonMap; Client2ButtonMap m_labelbuttons; // just temporary solution

@@ -564,14 +606,14 @@ int m_old_pos_x, m_old_pos_y; ///< old position so we can restore from maximized

unsigned int m_old_width, m_old_height; ///< old size so we can restore from maximized state int m_last_button_x, ///< last known x position of the mouse button m_last_button_y; ///< last known y position of the mouse button - FbWinFrame m_frame; + FbWinFrame m_frame; ///< the actuall window frame int m_layernum; int m_old_layernum; FbTk::FbWindow &m_parent; ///< window on which we draw move/resize rectangle (the "root window") - ResizeDirection m_resize_corner; + ResizeDirection m_resize_corner; //< the current resize corner used while resizing static int s_num_grabs; ///< number of XGrabPointer's };
M src/Workspace.ccsrc/Workspace.cc

@@ -30,13 +30,10 @@ #include "Screen.hh"

#include "Window.hh" #include "WinClient.hh" #include "FbWinFrame.hh" -#include "WindowCmd.hh" #include "FocusControl.hh" #include "PlacementStrategy.hh" -#include "Layer.hh" #include "FbTk/I18n.hh" -#include "FbTk/MenuItem.hh" #include "FbTk/StringUtil.hh" #include "FbTk/FbString.hh"

@@ -64,95 +61,18 @@ #include <string.h>

#endif #include <algorithm> -#include <iostream> -#include <iterator> using std::string; -using std::vector; -using std::ifstream; #ifdef DEBUG +#include <iostream> using std::cerr; using std::endl; #endif // DEBUG -namespace { // anonymous - -int countTransients(const WinClient &client) { - if (client.transientList().empty()) - return 0; - // now go throu the entire tree and count transients - size_t ret = client.transientList().size(); - WinClient::TransientList::const_iterator it = client.transientList().begin(); - WinClient::TransientList::const_iterator it_end = client.transientList().end(); - for (; it != it_end; ++it) - ret += countTransients(*(*it)); - - return ret; -} - -class ClientMenuItem:public FbTk::MenuItem { -public: - ClientMenuItem(WinClient &client): - FbTk::MenuItem(client.title().c_str(), &client.screen().windowMenu()), - m_client(client) { - - } - FbTk::Menu *submenu() { return &m_client.screen().windowMenu(); } - const FbTk::Menu *submenu() const { return &m_client.screen().windowMenu(); } - - void showSubmenu() { - WindowCmd<void>::setClient(&m_client); - FbTk::MenuItem::showSubmenu(); - } - - void click(int button, int time) { - if (m_client.fbwindow() == 0) - return; - FluxboxWindow &win = *m_client.fbwindow(); - - if (win.screen().currentWorkspaceID() != win.workspaceNumber() && - !win.isStuck()) { - win.menu().hide(); - BScreen::FollowModel model = win.screen().getUserFollowModel(); - if (model == BScreen::IGNORE_OTHER_WORKSPACES) - return; - // fetch the window to the current workspace - else if ((button == 3) ^ (model == BScreen::FETCH_ACTIVE_WINDOW || - win.isIconic() && model == BScreen::SEMIFOLLOW_ACTIVE_WINDOW)) { - win.screen().sendToWorkspace(win.screen().currentWorkspaceID(), &win, true); - return; - } - // warp to the workspace of the window - win.screen().changeWorkspaceID(win.workspaceNumber()); - } - win.setCurrentClient(m_client); - win.raiseAndFocus(); - } - - const string &label() const { return m_client.title(); } - bool isSelected() const { - if (m_client.fbwindow() == 0) - return false; - if (m_client.fbwindow()->isFocused() == false) - return false; - return (&(m_client.fbwindow()->winClient()) == &m_client); - - } -private: - WinClient &m_client; -}; - -}; - -Workspace::GroupList Workspace::m_groups; - -Workspace::Workspace(BScreen &scrn, FbTk::MultLayers &layermanager, - const string &name, unsigned int id): +Workspace::Workspace(BScreen &scrn, const string &name, unsigned int id): m_screen(scrn), - m_clientmenu(scrn.menuTheme(), scrn.imageControl(), - *scrn.layerManager().getLayer(Layer::MENU)), - m_layermanager(layermanager), + m_clientmenu(scrn, m_windowlist, &m_clientlist_sig), m_name(name), m_id(id) {

@@ -171,23 +91,12 @@ if (find(m_windowlist.begin(), m_windowlist.end(), &w) != m_windowlist.end())

return; w.setWorkspace(m_id); - // attach signals - w.titleSig().attach(this); if (place) placeWindow(w); m_windowlist.push_back(&w); - updateClientmenu(); - - if (!w.isStuck()) { - FluxboxWindow::ClientList::iterator client_it = - w.clientList().begin(); - FluxboxWindow::ClientList::iterator client_it_end = - w.clientList().end(); - for (; client_it != client_it_end; ++client_it) - screen().updateNetizenWindowAdd((*client_it)->window(), m_id); - } + m_clientlist_sig.notify(); }

@@ -200,28 +109,11 @@

if (w == 0) return -1; - // detach from signals - w->titleSig().detach(this); - if (w->isFocused() && still_alive) FocusControl::unfocusWindow(w->winClient(), true, true); - // we don't remove it from the layermanager, as it may be being moved - Windows::iterator erase_it = remove(m_windowlist.begin(), - m_windowlist.end(), w); - if (erase_it != m_windowlist.end()) - m_windowlist.erase(erase_it); - - updateClientmenu(); - - if (!w->isStuck()) { - FluxboxWindow::ClientList::iterator client_it = - w->clientList().begin(); - FluxboxWindow::ClientList::iterator client_it_end = - w->clientList().end(); - for (; client_it != client_it_end; ++client_it) - screen().updateNetizenWindowDel((*client_it)->window()); - } + m_windowlist.remove(w); + m_clientlist_sig.notify(); return m_windowlist.size(); }

@@ -239,7 +131,7 @@ Windows::reverse_iterator it = m_windowlist.rbegin();

Windows::reverse_iterator it_end = m_windowlist.rend(); for (; it != it_end; ++it) { if (! (*it)->isStuck()) - (*it)->withdraw(interrupt_moving); + (*it)->hide(interrupt_moving); } }

@@ -268,107 +160,6 @@ size_t Workspace::numberOfWindows() const {

return m_windowlist.size(); } -namespace { -// helper class for checkGrouping -class FindInGroup { -public: - FindInGroup(const FluxboxWindow &w):m_w(w) { } - bool operator ()(const string &name) const { - return (name == m_w.winClient().getWMClassName()); - } -private: - const FluxboxWindow &m_w; -}; - -}; - -//Note: this function doesn't check if the window is groupable -bool Workspace::checkGrouping(FluxboxWindow &win) { - if (win.numClients() == 0) - return false; -#ifdef DEBUG - cerr<<__FILE__<<"("<<__LINE__<<"): Checking grouping. ("<<win.title()<<")"<<endl; -#endif // DEBUG - if (!win.isGroupable()) { // make sure this window can hold a tab -#ifdef DEBUG - cerr<<__FILE__<<"("<<__LINE__<<"): window can't use a tab"<<endl; -#endif // DEBUG - return false; - } - - string instance_name = win.winClient().getWMClassName(); - - // go through every group and search for matching win instancename - GroupList::iterator g(m_groups.begin()); - GroupList::iterator g_end(m_groups.end()); - for (; g != g_end; ++g) { - Group::iterator name((*g).begin()); - Group::iterator name_end((*g).end()); - for (; name != name_end; ++name) { - - if ((*name) != instance_name) - continue; - - // find a window with the specific name - Windows::iterator wit(m_windowlist.begin()); - Windows::iterator wit_end(m_windowlist.end()); - for (; wit != wit_end; ++wit) { -#ifdef DEBUG - cerr<<__FILE__<<" check group with : "<<(*wit)->winClient().getWMClassName()<<endl; -#endif // DEBUG - if (find_if((*g).begin(), - (*g).end(), - FindInGroup(*(*wit))) != (*g).end()) { - // make sure the window is groupable - // and don't group with ourself - if ( !(*wit)->isGroupable() || (*wit)->winClient().fbwindow() == &win) - break; // try next name -#ifdef DEBUG - cerr<<__FILE__<<"("<<__FUNCTION__<<"): window ("<<*wit<<") attaching window ("<<&win<<")"<<endl; -#endif // DEBUG - WinClient &client = win.winClient(); - (*wit)->attachClient(client); - if (client.screen().focusControl().focusNew()) - (*wit)->setCurrentClient(client); - return true; // grouping done - - } - - } - - } - - } - - return false; -} - -bool Workspace::loadGroups(const string &filename) { - string real_filename = FbTk::StringUtil::expandFilename(filename); - FbTk::StringUtil::removeTrailingWhitespace(real_filename); - ifstream infile(real_filename.c_str()); - if (!infile) - return false; - - m_groups.clear(); // erase old groups - - // load new groups - while (!infile.eof()) { - string line; - vector<string> names; - getline(infile, line); - FbTk::StringUtil::stringtok(names, line); - m_groups.push_back(names); - } - - return true; -} - -void Workspace::update(FbTk::Subject *subj) { - updateClientmenu(); -} - - void Workspace::setName(const string &name) { if (!name.empty() && name != "") { if (name == m_name)

@@ -404,22 +195,7 @@ }

} void Workspace::updateClientmenu() { - // remove all items and then add them again - menu().removeAll(); - // for each fluxboxwindow add every client in them to our clientlist - Windows::iterator win_it = m_windowlist.begin(); - Windows::iterator win_it_end = m_windowlist.end(); - for (; win_it != win_it_end; ++win_it) { - // add every client in this fluxboxwindow to menu - FluxboxWindow::ClientList::iterator client_it = - (*win_it)->clientList().begin(); - FluxboxWindow::ClientList::iterator client_it_end = - (*win_it)->clientList().end(); - for (; client_it != client_it_end; ++client_it) - menu().insert(new ClientMenuItem(*(*client_it))); - } - - menu().updateMenu(); + m_clientlist_sig.notify(); } void Workspace::placeWindow(FluxboxWindow &win) {
M src/Workspace.hhsrc/Workspace.hh

@@ -25,30 +25,24 @@

#ifndef WORKSPACE_HH #define WORKSPACE_HH - - -#include "FbMenu.hh" +#include "ClientMenu.hh" -#include "FbTk/MultLayers.hh" -#include "FbTk/Observer.hh" #include "FbTk/NotCopyable.hh" #include <string> -#include <vector> #include <list> class BScreen; class FluxboxWindow; -class WinClient; /** * Handles a single workspace */ -class Workspace:private FbTk::NotCopyable, private FbTk::Observer { +class Workspace: private FbTk::NotCopyable { public: - typedef std::vector<FluxboxWindow *> Windows; + typedef std::list<FluxboxWindow *> Windows; - Workspace(BScreen &screen, FbTk::MultLayers &layermanager, const std::string &name, + Workspace(BScreen &screen, const std::string &name, unsigned int workspaceid = 0); ~Workspace();

@@ -83,24 +77,15 @@ const Windows &windowList() const { return m_windowlist; }

Windows &windowList() { return m_windowlist; } size_t numberOfWindows() const; - bool checkGrouping(FluxboxWindow &win); - - static bool loadGroups(const std::string &filename); private: - void update(FbTk::Subject *subj); void placeWindow(FluxboxWindow &win); BScreen &m_screen; - FbMenu m_clientmenu; - typedef std::vector<std::string> Group; - typedef std::vector<Group> GroupList; - - static GroupList m_groups; ///< handle auto groupings - - FbTk::MultLayers &m_layermanager; Windows m_windowlist; + FbTk::Subject m_clientlist_sig; + ClientMenu m_clientmenu; std::string m_name; ///< name of this workspace unsigned int m_id; ///< id, obsolete, this should be in BScreen
M src/WorkspaceCmd.ccsrc/WorkspaceCmd.cc

@@ -41,16 +41,90 @@ #endif

#include <algorithm> #include <functional> +void WindowListCmd::execute() { + if (m_pat.error()) { + m_cmd->execute(); + return; + } + + BScreen *screen = Fluxbox::instance()->keyScreen(); + if (screen != 0) { + FocusControl::Focusables win_list(screen->focusControl().creationOrderWinList()); + + FocusControl::Focusables::iterator it = win_list.begin(), + it_end = win_list.end(); + for (; it != it_end; ++it) { + if (m_pat.match(**it) && (*it)->fbwindow()) + m_cmd->execute(*(*it)->fbwindow()); + } + } +} + +void AttachCmd::execute() { + BScreen *screen = Fluxbox::instance()->keyScreen(); + if (screen != 0) { + FocusControl::Focusables win_list(screen->focusControl().focusedOrderWinList()); + + FocusControl::Focusables::iterator it = win_list.begin(), + it_end = win_list.end(); + FluxboxWindow *first = 0; + for (; it != it_end; ++it) { + if (m_pat.match(**it) && (*it)->fbwindow()) { + if (first == 0) + first = (*it)->fbwindow(); + else + first->attachClient((*it)->fbwindow()->winClient()); + } + } + + } +} + void NextWindowCmd::execute() { BScreen *screen = Fluxbox::instance()->keyScreen(); if (screen != 0) - screen->cycleFocus(m_option, false); + screen->cycleFocus(m_option, &m_pat, false); } void PrevWindowCmd::execute() { BScreen *screen = Fluxbox::instance()->keyScreen(); if (screen != 0) - screen->cycleFocus(m_option, true); + screen->cycleFocus(m_option, &m_pat, true); +} + +void TypeAheadFocusCmd::execute() { + BScreen *screen = Fluxbox::instance()->keyScreen(); + if (screen != 0) { + FocusControl::Focusables *win_list = 0; + if (m_option & FocusControl::CYCLEGROUPS) { + win_list = (m_option & FocusControl::CYCLELINEAR) ? + &screen->focusControl().creationOrderWinList() : + &screen->focusControl().focusedOrderWinList(); + } else { + win_list = (m_option & FocusControl::CYCLELINEAR) ? + &screen->focusControl().creationOrderList() : + &screen->focusControl().focusedOrderList(); + } + + screen->startTypeAheadFocus(*win_list, &m_pat); + } +} + +void GoToWindowCmd::execute() { + BScreen *screen = Fluxbox::instance()->keyScreen(); + if (screen != 0) { + FocusControl::Focusables *win_list = 0; + if (m_option & FocusControl::CYCLEGROUPS) { + win_list = (m_option & FocusControl::CYCLELINEAR) ? + &screen->focusControl().creationOrderWinList() : + &screen->focusControl().focusedOrderWinList(); + } else { + win_list = (m_option & FocusControl::CYCLELINEAR) ? + &screen->focusControl().creationOrderList() : + &screen->focusControl().focusedOrderList(); + } + screen->focusControl().goToWindowNumber(*win_list, m_num, &m_pat); + } } void DirFocusCmd::execute() {

@@ -248,19 +322,6 @@ Workspace::Windows windows(screen->currentWorkspace()->windowList());

std::for_each(windows.begin(), windows.end(), std::mem_fun(&FluxboxWindow::iconify)); -} - -void MinimizeLayerCmd::execute() { - FluxboxWindow *win = FocusControl::focusedFbWindow(); - if (!win) - return; - - Workspace::Windows windows(win->screen().currentWorkspace()->windowList()); - Workspace::Windows::iterator it = windows.begin(), it_end = windows.end(); - for (; it != it_end; ++it) { - if (win->layerNum() == (*it)->layerNum()) - (*it)->iconify(); - } } void CloseAllWindowsCmd::execute() {
M src/WorkspaceCmd.hhsrc/WorkspaceCmd.hh

@@ -26,23 +26,73 @@ #ifndef WORKSPACECMD_HH

#define WORKSPACECMD_HH #include "Command.hh" +#include "ClientPattern.hh" +#include "CurrentWindowCmd.hh" #include "FocusControl.hh" +#include "FbTk/RefCount.hh" + +class WindowHelperCmd; + +class WindowListCmd: public FbTk::Command { +public: + WindowListCmd(FbTk::RefCount<WindowHelperCmd> cmd, const std::string &pat): + m_cmd(cmd), m_pat(pat.c_str()) { } + + void execute(); + +private: + FbTk::RefCount<WindowHelperCmd> m_cmd; + ClientPattern m_pat; +}; + +class AttachCmd: public FbTk::Command { +public: + explicit AttachCmd(const std::string &pat): m_pat(pat.c_str()) { } + void execute(); +private: + const ClientPattern m_pat; +}; class NextWindowCmd: public FbTk::Command { public: - explicit NextWindowCmd(int option):m_option(option) { } + explicit NextWindowCmd(int option, std::string &pat): + m_option(option), m_pat(pat.c_str()) { } void execute(); private: const int m_option; + const ClientPattern m_pat; }; class PrevWindowCmd: public FbTk::Command { public: - explicit PrevWindowCmd(int option):m_option(option) { } + explicit PrevWindowCmd(int option, std::string &pat): + m_option(option), m_pat(pat.c_str()) { } + void execute(); +private: + const int m_option; + const ClientPattern m_pat; +}; + +class TypeAheadFocusCmd: public FbTk::Command { +public: + explicit TypeAheadFocusCmd(int option, std::string &pat): + m_option(option), m_pat(pat.c_str()) { } + void execute(); +private: + const int m_option; + const ClientPattern m_pat; +}; + +class GoToWindowCmd: public FbTk::Command { +public: + GoToWindowCmd(int num, int option, std::string &pat): + m_num(num), m_option(option), m_pat(pat.c_str()) { } void execute(); private: + const int m_num; const int m_option; + const ClientPattern m_pat; }; class DirFocusCmd: public FbTk::Command {

@@ -110,11 +160,6 @@ void execute();

}; class ShowDesktopCmd: public FbTk::Command { -public: - void execute(); -}; - -class MinimizeLayerCmd: public FbTk::Command { public: void execute(); };
M src/WorkspaceMenu.hhsrc/WorkspaceMenu.hh

@@ -28,12 +28,21 @@ #include "FbMenu.hh"

class BScreen; +/** + * A menu specific for workspace. + * Contains some simple workspace commands + * such as new/delete workspace and edit + * workspace name. + * It also contains client menus for all clients. + */ class WorkspaceMenu: public FbMenu { public: explicit WorkspaceMenu(BScreen &screen); virtual ~WorkspaceMenu() { } + /// called when a subject is sending a signal void update(FbTk::Subject *subj); private: + /// initialize menu for the screen void init(BScreen &screen); };
M src/Xutil.ccsrc/Xutil.cc

@@ -56,8 +56,8 @@ Display *display = FbTk::App::instance()->display();

XTextProperty text_prop; text_prop.value = 0; - char **list; - int num; + char **list = 0; + int num = 0; _FB_USES_NLS; string name;

@@ -66,14 +66,15 @@ if (text_prop.value && text_prop.nitems > 0) {

if (text_prop.encoding != XA_STRING) { text_prop.nitems = strlen((char *) text_prop.value); + XmbTextPropertyToTextList(display, &text_prop, &list, &num); - if ((XmbTextPropertyToTextList(display, &text_prop, - &list, &num) == Success) && - (num > 0) && *list) { + if (num > 0 && list != 0) name = FbTk::FbStringUtil::LocaleStrToFb(static_cast<char *>(*list)); + else + name = text_prop.value ? FbTk::FbStringUtil::XStrToFb((char *)text_prop.value) : ""; + + if (list) XFreeStringList(list); - } else - name = text_prop.value ? FbTk::FbStringUtil::XStrToFb((char *)text_prop.value) : ""; } else name = text_prop.value ? FbTk::FbStringUtil::XStrToFb((char *)text_prop.value) : "";
M src/fluxbox.ccsrc/fluxbox.cc

@@ -206,7 +206,6 @@ m_rc_styleoverlayfile(m_resourcemanager, "~/." + realProgramName("fluxbox") + "/overlay", "session.styleOverlay", "Session.StyleOverlay"),

m_rc_menufile(m_resourcemanager, DEFAULTMENU, "session.menuFile", "Session.MenuFile"), m_rc_keyfile(m_resourcemanager, DEFAULTKEYSFILE, "session.keyFile", "Session.KeyFile"), m_rc_slitlistfile(m_resourcemanager, "~/." + realProgramName("fluxbox") + "/slitlist", "session.slitlistFile", "Session.SlitlistFile"), - m_rc_groupfile(m_resourcemanager, "~/." + realProgramName("fluxbox") + "/groups", "session.groupFile", "Session.GroupFile"), m_rc_appsfile(m_resourcemanager, "~/." + realProgramName("fluxbox") + "/apps", "session.appsFile", "Session.AppsFile"), m_rc_tabs_attach_area(m_resourcemanager, ATTACH_AREA_WINDOW, "session.tabsAttachArea", "Session.TabsAttachArea"), m_rc_cache_life(m_resourcemanager, 5, "session.cacheLife", "Session.CacheLife"),

@@ -320,6 +319,11 @@ m_fluxbox_pid = XInternAtom(disp, "_BLACKBOX_PID", False);

#endif // HAVE_GETPID + // Create keybindings handler and load keys file + // Note: this needs to be done before creating screens + m_key.reset(new Keys); + m_key->load(StringUtil::expandFilename(*m_rc_keyfile).c_str()); + vector<int> screens; int i;

@@ -415,10 +419,6 @@ sync(false);

m_reconfigure_wait = m_reread_menu_wait = false; - // Create keybindings handler and load keys file - m_key.reset(new Keys); - m_key->load(StringUtil::expandFilename(*m_rc_keyfile).c_str()); - m_resourcemanager.unlock(); ungrab();

@@ -545,8 +545,11 @@ XNextEvent(disp, &e);

if (last_bad_window != None && e.xany.window == last_bad_window && e.type != DestroyNotify) { // we must let the actual destroys through + if (e.type == FocusOut) + m_revert_timer.start(); #ifdef DEBUG - cerr<<"Fluxbox::eventLoop(): removing bad window from event queue"<<endl; + else + cerr<<"Fluxbox::eventLoop(): removing bad window from event queue"<<endl; #endif // DEBUG } else { last_bad_window = None;

@@ -640,7 +643,7 @@ // copy init file

if (create_init) FbTk::FileUtil::copyFile(DEFAULT_INITFILE, init_file.c_str()); -#define CONFIG_VERSION 1 +#define CONFIG_VERSION 3 FbTk::Resource<int> config_version(m_resourcemanager, 0, "session.configVersion", "Session.ConfigVersion"); if (*config_version < CONFIG_VERSION) {

@@ -1019,41 +1022,6 @@ if (ce.data.l[0] == IconicState)

winclient->fbwindow()->iconify(); if (ce.data.l[0] == NormalState) winclient->fbwindow()->deiconify(); - } else if (ce.message_type == m_fbatoms->getFluxboxChangeWorkspaceAtom()) { - BScreen *screen = searchScreen(ce.window); - - if (screen && ce.data.l[0] >= 0 && - ce.data.l[0] < (signed)screen->numberOfWorkspaces()) - screen->changeWorkspaceID(ce.data.l[0]); - - } else if (ce.message_type == m_fbatoms->getFluxboxChangeWindowFocusAtom()) { - WinClient *winclient = searchWindow(ce.window); - if (winclient) { - FluxboxWindow *win = winclient->fbwindow(); - if (win && win->isVisible()) - win->setCurrentClient(*winclient, true); - } - } else if (ce.message_type == m_fbatoms->getFluxboxCycleWindowFocusAtom()) { - BScreen *screen = searchScreen(ce.window); - - if (screen) { - if (! ce.data.l[0]) - screen->focusControl().prevFocus(); - else - screen->focusControl().nextFocus(); - } - } else if (ce.message_type == m_fbatoms->getFluxboxChangeAttributesAtom()) { - WinClient *winclient = searchWindow(ce.window); - FluxboxWindow *win = 0; - if (winclient && (win = winclient->fbwindow()) && winclient->validateClient()) { - FluxboxWindow::BlackboxHints net; - net.flags = ce.data.l[0]; - net.attrib = ce.data.l[1]; - net.workspace = ce.data.l[2]; - net.stack = ce.data.l[3]; - net.decoration = static_cast<int>(ce.data.l[4]); - win->changeBlackboxHints(net); - } } else { WinClient *winclient = searchWindow(ce.window); BScreen *screen = searchScreen(ce.window);

@@ -1117,73 +1085,92 @@

void Fluxbox::update(FbTk::Subject *changedsub) { //TODO: fix signaling, this does not look good + FluxboxWindow *fbwin = 0; + WinClient *client = 0; + if (typeid(*changedsub) == typeid(FluxboxWindow::WinSubject)) { FluxboxWindow::WinSubject *winsub = dynamic_cast<FluxboxWindow::WinSubject *>(changedsub); - FluxboxWindow &win = winsub->win(); - if ((&(win.hintSig())) == changedsub) { // hint signal - for (AtomHandlerContainerIt it= m_atomhandler.begin(); - it != m_atomhandler.end(); ++it) { - if ( (*it).first->update()) - (*it).first->updateHints(win); - } - } else if ((&(win.stateSig())) == changedsub) { // state signal - for (AtomHandlerContainerIt it= m_atomhandler.begin(); - it != m_atomhandler.end(); ++it) { - if ((*it).first->update()) - (*it).first->updateState(win); - } - // if window changed to iconic state - // add to icon list - if (win.isIconic()) { - win.screen().addIcon(&win); - Workspace *space = win.screen().getWorkspace(win.workspaceNumber()); - if (space != 0) - space->removeWindow(&win, true); - } + fbwin = &winsub->win(); + } else if (typeid(*changedsub) == typeid(Focusable::FocusSubject)) { + Focusable::FocusSubject *winsub = dynamic_cast<Focusable::FocusSubject *>(changedsub); + fbwin = winsub->win().fbwindow(); + if (typeid(winsub->win()) == typeid(WinClient)) + client = dynamic_cast<WinClient *>(&winsub->win()); + } - if (win.isStuck()) { - // if we're sticky then reassociate window - // to all workspaces - BScreen &scr = win.screen(); - if (scr.currentWorkspaceID() != win.workspaceNumber()) { - scr.reassociateWindow(&win, - scr.currentWorkspaceID(), - true); - } - } - } else if ((&(win.layerSig())) == changedsub) { // layer signal + if (fbwin && &fbwin->stateSig() == changedsub) { // state signal + for (AtomHandlerContainerIt it= m_atomhandler.begin(); + it != m_atomhandler.end(); ++it) { + if ((*it).first->update()) + (*it).first->updateState(*fbwin); + } + // if window changed to iconic state + // add to icon list + if (fbwin->isIconic()) { + fbwin->screen().addIcon(fbwin); + Workspace *space = fbwin->screen().getWorkspace(fbwin->workspaceNumber()); + if (space != 0) + space->removeWindow(fbwin, true); + } - for (AtomHandlerContainerIt it= m_atomhandler.begin(); - it != m_atomhandler.end(); ++it) { - if ((*it).first->update()) - (*it).first->updateLayer(win); + if (fbwin->isStuck()) { + // if we're sticky then reassociate window + // to all workspaces + BScreen &scr = fbwin->screen(); + if (scr.currentWorkspaceID() != fbwin->workspaceNumber()) { + scr.reassociateWindow(fbwin, + scr.currentWorkspaceID(), + true); } - } else if ((&(win.dieSig())) == changedsub) { // window death signal + } + } else if (fbwin && &fbwin->layerSig() == changedsub) { // layer signal + AtomHandlerContainerIt it= m_atomhandler.begin(); + for (; it != m_atomhandler.end(); ++it) { + if ((*it).first->update()) + (*it).first->updateLayer(*fbwin); + } + } else if (fbwin && &fbwin->dieSig() == changedsub) { // window death signal + AtomHandlerContainerIt it= m_atomhandler.begin(); + for (; it != m_atomhandler.end(); ++it) { + if ((*it).first->update()) + (*it).first->updateFrameClose(*fbwin); + } - for (AtomHandlerContainerIt it= m_atomhandler.begin(); - it != m_atomhandler.end(); ++it) { - if ((*it).first->update()) - (*it).first->updateFrameClose(win); - } + // make sure each workspace get this + BScreen &scr = fbwin->screen(); + scr.removeWindow(fbwin); + if (FocusControl::focusedFbWindow() == fbwin) + FocusControl::setFocusedFbWindow(0); + } else if (fbwin && &fbwin->workspaceSig() == changedsub) { // workspace signal + for (AtomHandlerContainerIt it= m_atomhandler.begin(); + it != m_atomhandler.end(); ++it) { + if ((*it).first->update()) + (*it).first->updateWorkspace(*fbwin); + } + } else if (client && &client->dieSig() == changedsub) { // client death + for (AtomHandlerContainerIt it= m_atomhandler.begin(); + it != m_atomhandler.end(); ++it) { + if ((*it).first->update()) + (*it).first->updateClientClose(*client); + } - // make sure each workspace get this - BScreen &scr = win.screen(); - scr.removeWindow(&win); - if (FocusControl::focusedFbWindow() == &win) - FocusControl::setFocusedFbWindow(0); + BScreen &screen = client->screen(); - } else if ((&(win.workspaceSig())) == changedsub) { // workspace signal - for (AtomHandlerContainerIt it= m_atomhandler.begin(); - it != m_atomhandler.end(); ++it) { - if ((*it).first->update()) - (*it).first->updateWorkspace(win); - } - } else { -#ifdef DEBUG - cerr<<__FILE__<<"("<<__LINE__<<"): WINDOW uncought signal from "<<&win<<endl; -#endif // DEBUG - } + screen.removeClient(*client); + // At this point, we trust that this client is no longer in the + // client list of its frame (but it still has reference to the frame) + // We also assume that any remaining active one is the last focused one + + // This is where we revert focus on window close + // NOWHERE ELSE!!! + if (FocusControl::focusedWindow() == client) { + FocusControl::unfocusWindow(*client); + // make sure nothing else uses this window before focus reverts + FocusControl::setFocusedWindow(0); + m_revert_screen = &screen; + m_revert_timer.start(); + } } else if (typeid(*changedsub) == typeid(BScreen::ScreenSubject)) { BScreen::ScreenSubject *subj = dynamic_cast<BScreen::ScreenSubject *>(changedsub); BScreen &screen = subj->screen();

@@ -1218,37 +1205,6 @@ if ((*it).first->update())

(*it).first->updateClientList(screen); } } - } else if (typeid(*changedsub) == typeid(WinClient::WinClientSubj)) { - - WinClient::WinClientSubj *subj = dynamic_cast<WinClient::WinClientSubj *>(changedsub); - WinClient &client = subj->winClient(); - - // TODO: don't assume it is diesig (need to fix as soon as another signal appears) - for (AtomHandlerContainerIt it= m_atomhandler.begin(); - it != m_atomhandler.end(); ++it) { - if ((*it).first->update()) - (*it).first->updateClientClose(client); - } - - BScreen &screen = client.screen(); - - screen.removeClient(client); - // finaly send notify signal - screen.updateNetizenWindowDel(client.window()); - - // At this point, we trust that this client is no longer in the - // client list of its frame (but it still has reference to the frame) - // We also assume that any remaining active one is the last focused one - - // This is where we revert focus on window close - // NOWHERE ELSE!!! - if (FocusControl::focusedWindow() == &client) { - FocusControl::unfocusWindow(client); - // make sure nothing else uses this window before focus reverts - FocusControl::setFocusedWindow(0); - m_revert_screen = &screen; - m_revert_timer.start(); - } } }

@@ -1450,7 +1406,7 @@ return m_rc_file;

} /// Provides default filename of data file -void Fluxbox::getDefaultDataFilename(const char *name, string &filename) { +void Fluxbox::getDefaultDataFilename(const char *name, string &filename) const { filename = string(getenv("HOME") + string("/.") + m_RC_PATH + string("/") + name); }

@@ -1492,12 +1448,6 @@ *m_rc_colors_per_channel = 6;

if (m_rc_stylefile->empty()) *m_rc_stylefile = DEFAULTSTYLE; - - if (!Workspace::loadGroups(*m_rc_groupfile)) { -#ifdef DEBUG - cerr<<_FB_CONSOLETEXT(Fluxbox, CantLoadGroupFile, "Failed to load groupfile", "Couldn't load the groupfile")<<": "<<*m_rc_groupfile<<endl; -#endif // DEBUG - } } void Fluxbox::load_rc(BScreen &screen) {

@@ -1735,7 +1685,6 @@ }

void Fluxbox::updateFocusedWindow(BScreen *screen, BScreen *old_screen) { if (screen != 0) { - screen->updateNetizenWindowFocus(); for (AtomHandlerContainerIt it= m_atomhandler.begin(); it != m_atomhandler.end(); it++) { (*it).first->updateFocusedWindow(*screen, (FocusControl::focusedWindow() ?

@@ -1745,7 +1694,6 @@ }

} if (old_screen && old_screen != screen) { - old_screen->updateNetizenWindowFocus(); for (AtomHandlerContainerIt it= m_atomhandler.begin(); it != m_atomhandler.end(); it++) (*it).first->updateFocusedWindow(*old_screen, 0);
M src/fluxbox.hhsrc/fluxbox.hh

@@ -196,7 +196,7 @@ /// @return whether the timestamps on the menu changed

bool menuTimestampsChanged() const; bool haveShape() const { return m_have_shape; } int shapeEventbase() const { return m_shape_eventbase; } - void getDefaultDataFilename(const char *name, std::string &); + void getDefaultDataFilename(const char *name, std::string &) const; // screen mouse was in at last key event BScreen *mouseScreen() { return m_mousescreen; } // screen of window that last key event (i.e. focused window) went to

@@ -240,7 +240,7 @@ m_rc_tabs_padding;

FbTk::Resource<std::string> m_rc_stylefile, m_rc_styleoverlayfile, m_rc_menufile, m_rc_keyfile, m_rc_slitlistfile, - m_rc_groupfile, m_rc_appsfile; + m_rc_appsfile; FbTk::Resource<TabsAttachArea> m_rc_tabs_attach_area;
M util/fluxbox-update_configs.ccutil/fluxbox-update_configs.cc

@@ -38,23 +38,17 @@ #ifndef _GNU_SOURCE

#define _GNU_SOURCE #endif // _GNU_SOURCE -#ifdef HAVE_CSTDIO - #include <cstdio> -#else - #include <stdio.h> -#endif -#ifdef HAVE_CSTDLIB - #include <cstdlib> -#else - #include <stdlib.h> -#endif #ifdef HAVE_CSTRING #include <cstring> #else #include <string.h> #endif + #include <iostream> #include <fstream> +#include <set> +#include <map> +#include <list> using std::cout; using std::cerr;

@@ -62,39 +56,34 @@ using std::endl;

using std::string; using std::ifstream; using std::ofstream; +using std::set; +using std::map; +using std::list; -#define VERSION 1 +string read_file(string filename); +void write_file(string filename, string &contents); +void save_all_files(); int run_updates(int old_version, FbTk::ResourceManager rm) { int new_version = old_version; - if (old_version < 1) { // add mouse events to keys file - FbTk::Resource<string> rc_keyfile(rm, DEFAULTKEYSFILE, - "session.keyFile", "Session.KeyFile"); - string keyfilename = FbTk::StringUtil::expandFilename(*rc_keyfile); + FbTk::Resource<string> rc_keyfile(rm, "~/.fluxbox/keys", + "session.keyFile", "Session.KeyFile"); + FbTk::Resource<string> rc_appsfile(rm, "~/.fluxbox/apps", + "session.appsFile", "Session.AppsFile"); - // ok, I don't know anything about file handling in c++ - // what's it to you?!?! - // I assume there should be some error handling in here, but I sure - // don't know how, and I don't have documentation + string appsfilename = FbTk::StringUtil::expandFilename(*rc_appsfile); + string keyfilename = FbTk::StringUtil::expandFilename(*rc_keyfile); - ifstream in_keyfile(keyfilename.c_str()); - string whole_keyfile = ""; + if (old_version < 1) { // add mouse events to keys file - while (!in_keyfile.eof()) { - string linebuffer; - - getline(in_keyfile, linebuffer); - whole_keyfile += linebuffer + "\n"; - } - in_keyfile.close(); - - ofstream out_keyfile(keyfilename.c_str()); + string whole_keyfile = read_file(keyfilename); + string new_keyfile = ""; // let's put our new keybindings first, so they're easy to find - out_keyfile << "!mouse actions added by fluxbox-update_configs" << endl - << "OnDesktop Mouse1 :hideMenus" << endl - << "OnDesktop Mouse2 :workspaceMenu" << endl - << "OnDesktop Mouse3 :rootMenu" << endl; + new_keyfile += "!mouse actions added by fluxbox-update_configs\n"; + new_keyfile += "OnDesktop Mouse1 :hideMenus\n"; + new_keyfile += "OnDesktop Mouse2 :workspaceMenu\n"; + new_keyfile += "OnDesktop Mouse3 :rootMenu\n"; // scrolling on desktop needs to match user's desktop wheeling settings // hmmm, what are the odds that somebody wants this to be different on

@@ -108,25 +97,97 @@ "session.screen0.reversewheeling",

"Session.Screen0.ReverseWheeling"); if (*rc_wheeling) { if (*rc_reverse) { // if you ask me, this should have been default - out_keyfile << "OnDesktop Mouse4 :prevWorkspace" << endl - << "OnDesktop Mouse5 :nextWorkspace" << endl; + new_keyfile += "OnDesktop Mouse4 :prevWorkspace\n"; + new_keyfile += "OnDesktop Mouse5 :nextWorkspace\n"; } else { - out_keyfile << "OnDesktop Mouse4 :nextWorkspace" << endl - << "OnDesktop Mouse5 :prevWorkspace" << endl; + new_keyfile += "OnDesktop Mouse4 :nextWorkspace\n"; + new_keyfile += "OnDesktop Mouse5 :prevWorkspace\n"; } } - out_keyfile << endl; // just for good looks + new_keyfile += "\n"; // just for good looks + new_keyfile += whole_keyfile; // don't forget user's old keybindings - // now, restore user's old keybindings - out_keyfile << whole_keyfile; + write_file(keyfilename, new_keyfile); new_version = 1; } + if (old_version < 2) { // move groups entries to apps file + FbTk::Resource<string> rc_groupfile(rm, "~/.fluxbox/groups", + "session.groupFile", "Session.GroupFile"); + string groupfilename = FbTk::StringUtil::expandFilename(*rc_groupfile); + string whole_groupfile = read_file(groupfilename); + string whole_appsfile = read_file(appsfilename); + string new_appsfile = ""; + + list<string> lines; + FbTk::StringUtil::stringtok(lines, whole_groupfile, "\n"); + + list<string>::iterator line_it = lines.begin(); + list<string>::iterator line_it_end = lines.end(); + for (; line_it != line_it_end; ++line_it) { + new_appsfile += "[group] (workspace=[current])\n"; + + list<string> apps; + FbTk::StringUtil::stringtok(apps, *line_it); + + list<string>::iterator it = apps.begin(); + list<string>::iterator it_end = apps.end(); + for (; it != it_end; ++it) { + new_appsfile += " [app] (name="; + new_appsfile += *it; + new_appsfile += ")\n"; + } + + new_appsfile += "[end]\n"; + } + + new_appsfile += whole_appsfile; + write_file(appsfilename, new_appsfile); + new_version = 2; + } + + if (old_version < 3) { // move toolbar wheeling to keys file + string whole_keyfile = read_file(keyfilename); + string new_keyfile = ""; + // let's put our new keybindings first, so they're easy to find + new_keyfile += "!mouse actions added by fluxbox-update_configs\n"; + bool keep_changes = false; + + // scrolling on toolbar needs to match user's toolbar wheeling settings + FbTk::Resource<string> rc_wheeling(rm, "Off", + "session.screen0.iconbar.wheelMode", + "Session.Screen0.Iconbar.WheelMode"); + FbTk::Resource<bool> rc_screen(rm, true, + "session.screen0.desktopwheeling", + "Session.Screen0.DesktopWheeling"); + FbTk::Resource<bool> rc_reverse(rm, false, + "session.screen0.reversewheeling", + "Session.Screen0.ReverseWheeling"); + if (strcasecmp((*rc_wheeling).c_str(), "On") == 0 || + (strcasecmp((*rc_wheeling).c_str(), "Screen") && *rc_screen)) { + keep_changes = true; + if (*rc_reverse) { // if you ask me, this should have been default + new_keyfile += "OnToolbar Mouse4 :prevWorkspace\n"; + new_keyfile += "OnToolbar Mouse5 :nextWorkspace\n"; + } else { + new_keyfile += "OnToolbar Mouse4 :nextWorkspace\n"; + new_keyfile += "OnToolbar Mouse5 :prevWorkspace\n"; + } + } + new_keyfile += "\n"; // just for good looks + new_keyfile += whole_keyfile; // don't forget user's old keybindings + + if (keep_changes) + write_file(keyfilename, new_keyfile); + new_version = 3; + } + return new_version; } int main(int argc, char **argv) { string rc_filename; + set<string> style_filenames; int i = 1; pid_t fb_pid = 0;

@@ -184,8 +245,10 @@ "session.configVersion", "Session.ConfigVersion");

int old_version = *config_version; int new_version = run_updates(old_version, resource_manager); if (new_version > old_version) { + // configs were updated -- let's save our changes config_version = new_version; resource_manager.save(rc_filename.c_str(), rc_filename.c_str()); + save_all_files(); #ifdef HAVE_SIGNAL_H // if we were given a fluxbox pid, send it a reconfigure signal

@@ -197,3 +260,75 @@ }

return 0; } + +static set<string> modified_files; +// we may want to put a size limit on this cache, so it doesn't grow too big +static map<string,string> file_cache; + +// returns the contents of the file given, either from the cache or by reading +// the file from disk +string read_file(string filename) { + // check if we already have the file in memory + map<string,string>::iterator it = file_cache.find(filename); + if (it != file_cache.end()) + return it->second; + + // nope, we'll have to read the file + ifstream infile(filename.c_str()); + string whole_file = ""; + + if (!infile) // failed to open file + return whole_file; + + while (!infile.eof()) { + string linebuffer; + + getline(infile, linebuffer); + whole_file += linebuffer + "\n"; + } + infile.close(); + + file_cache[filename] = whole_file; + return whole_file; +} + +#ifdef NOT_USED +// remove the file from the cache, writing to disk if it's been changed +void forget_file(string filename) { + map<string,string>::iterator cache_it = file_cache.find(filename); + // check if we knew about the file to begin with + if (cache_it == file_cache.end()) + return; + + // check if we've actually modified it + set<string>::iterator mod_it = modified_files.find(filename); + if (mod_it == modified_files.end()) { + file_cache.erase(cache_it); + return; + } + + // flush our changes to disk and remove all traces + ofstream outfile(filename.c_str()); + outfile << cache_it->second; + file_cache.erase(cache_it); + modified_files.erase(mod_it); +} +#endif // NOT_USED + +// updates the file contents in the cache and marks the file as modified so it +// gets saved later +void write_file(string filename, string &contents) { + modified_files.insert(filename); + file_cache[filename] = contents; +} + +// actually save all the files we've modified +void save_all_files() { + set<string>::iterator it = modified_files.begin(); + set<string>::iterator it_end = modified_files.end(); + for (; it != it_end; ++it) { + ofstream outfile(it->c_str()); + outfile << file_cache[it->c_str()]; + } + modified_files.clear(); +}