From a59428d67a95a9df16554962f0a6257d6378328a Mon Sep 17 00:00:00 2001 From: markt Date: Sat, 13 Oct 2007 21:51:37 +0000 Subject: [PATCH] merged changes from pre-devel --- ChangeLog | 131 ++++- nls/fluxbox-nls.hh | 4 + nls/ru_RU/generated-KOI8-R.m | 47 +- nls/ru_RU/generated-UTF-8.m | 47 +- src/AttentionNoticeHandler.cc | 31 +- src/AttentionNoticeHandler.hh | 8 +- src/CascadePlacement.cc | 2 +- src/CascadePlacement.hh | 2 +- src/ClientMenu.cc | 146 +++++ src/{Netizen.hh => ClientMenu.hh} | 58 +- src/ClientPattern.cc | 175 ++++-- src/ClientPattern.hh | 16 +- src/ClockTool.cc | 4 +- src/ColSmartPlacement.cc | 6 +- src/ColSmartPlacement.hh | 2 +- src/CommandDialog.cc | 10 +- src/CommandDialog.hh | 20 +- src/Container.cc | 18 - src/Container.hh | 4 - src/CurrentWindowCmd.cc | 48 +- src/CurrentWindowCmd.hh | 29 +- src/Ewmh.cc | 73 +-- src/Ewmh.hh | 3 - src/FbAtoms.cc | 29 - src/FbAtoms.hh | 41 +- src/FbCommandFactory.cc | 289 ++++++---- src/FbCommands.cc | 30 ++ src/FbCommands.hh | 16 +- src/FbTk/ITypeAheadable.hh | 2 + src/FbTk/Makefile.am | 1 - src/FbTk/Menu.cc | 8 +- src/FbTk/Menu.hh | 6 +- src/FbTk/MenuIcon.cc | 96 ---- src/FbTk/MenuIcon.hh | 54 -- src/FbTk/MenuItem.cc | 21 +- src/FbTk/MenuItem.hh | 3 + src/FbTk/TypeAhead.hh | 2 + src/FbWinFrame.cc | 143 +---- src/FbWinFrame.hh | 25 +- src/FbWinFrameTheme.cc | 18 +- src/FbWinFrameTheme.hh | 19 +- src/FocusControl.cc | 187 ++++--- src/FocusControl.hh | 65 ++- src/Focusable.hh | 140 +++++ src/IconButton.cc | 215 +++----- src/IconButton.hh | 21 +- src/IconMenu.cc | 66 --- src/IconMenu.hh | 38 -- src/IconMenuItem.hh | 44 -- src/IconbarTheme.cc | 37 +- src/IconbarTheme.hh | 4 +- src/IconbarTool.cc | 384 ++++---------- src/IconbarTool.hh | 33 +- src/Keys.cc | 110 ++-- src/Keys.hh | 32 +- src/Layer.hh | 49 ++ src/Makefile.am | 11 +- src/MenuCreator.cc | 9 +- src/MinOverlapPlacement.cc | 186 +++++++ src/MinOverlapPlacement.hh | 83 +++ src/Netizen.cc | 112 ---- src/PlacementStrategy.hh | 4 +- src/Remember.cc | 45 +- src/Remember.hh | 19 +- src/Resources.cc | 40 +- src/RowSmartPlacement.cc | 6 +- src/RowSmartPlacement.hh | 2 +- src/Screen.cc | 324 +++++------- src/Screen.hh | 54 +- src/ScreenPlacement.cc | 15 +- src/ScreenPlacement.hh | 8 +- src/Slit.cc | 9 - src/Toolbar.cc | 28 +- src/Toolbar.hh | 1 - src/UnderMousePlacement.cc | 2 +- src/UnderMousePlacement.hh | 2 +- src/WinButton.cc | 8 +- src/WinClient.cc | 122 ++--- src/WinClient.hh | 53 +- src/WinClientUtil.cc | 32 -- src/WinClientUtil.hh | 19 - src/Window.cc | 850 +++++++++++------------------- src/Window.hh | 170 +++--- src/Workspace.cc | 240 +-------- src/Workspace.hh | 27 +- src/WorkspaceCmd.cc | 91 +++- src/WorkspaceCmd.hh | 59 ++- src/WorkspaceMenu.hh | 9 + src/Xutil.cc | 15 +- src/fluxbox.cc | 236 ++++----- src/fluxbox.hh | 4 +- util/fluxbox-update_configs.cc | 219 ++++++-- 92 files changed, 3066 insertions(+), 3160 deletions(-) create mode 100644 src/ClientMenu.cc rename src/{Netizen.hh => ClientMenu.hh} (55%) delete mode 100644 src/FbTk/MenuIcon.cc delete mode 100644 src/FbTk/MenuIcon.hh create mode 100644 src/Focusable.hh delete mode 100644 src/IconMenu.cc delete mode 100644 src/IconMenu.hh delete mode 100644 src/IconMenuItem.hh create mode 100644 src/MinOverlapPlacement.cc create mode 100644 src/MinOverlapPlacement.hh delete mode 100644 src/Netizen.cc delete mode 100644 src/WinClientUtil.cc delete mode 100644 src/WinClientUtil.hh diff --git a/ChangeLog b/ChangeLog index 125f9397..4187012d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -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 which groups all windows matching the + given pattern (Mark) + FbCommandFactory.cc WorkspaceCmd.cc/hh +*07/05/20: + * Added resources session.screen.maxDisable{Move,Resize}: , 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.followModel (Mark) + - now only options are Ignore and Follow, the latter using the setting in + session.screen.userFollowModel + Window.cc/hh Ewmh.cc Screen.cc/hh +*07/05/16: + * Added new resource session.screen.noFocusWhileTypingDelay: (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.maxIgnoreIncrement: , 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.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.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 [], 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 will count + back from the end of the list. + - Particularly useful examples are GoToWindow 9 and + GoToWindow 25, which will focus the window at position 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: diff --git a/nls/fluxbox-nls.hh b/nls/fluxbox-nls.hh index 53d06aaa..3aa44800 100644 --- a/nls/fluxbox-nls.hh +++ b/nls/fluxbox-nls.hh @@ -77,6 +77,10 @@ enum { ConfigmenuExternalTabWidth = 23, ConfigmenuMouseTabFocus = 24, ConfigmenuClickTabFocus = 25, + ConfigmenuMaxMenu = 26, + ConfigmenuMaxIgnoreInc = 27, + ConfigmenuMaxDisableMove = 28, + ConfigmenuMaxDisableResize = 29, EwmhSet = 5, EwmhOutOfMemoryClientList = 1, diff --git a/nls/ru_RU/generated-KOI8-R.m b/nls/ru_RU/generated-KOI8-R.m index f3a24a8d..e8820bca 100644 --- a/nls/ru_RU/generated-KOI8-R.m +++ b/nls/ru_RU/generated-KOI8-R.m @@ -62,7 +62,6 @@ $set 4 #Configmenu 10 11 12 -13 14 15 16 - @@ -82,15 +81,49 @@ $set 5 #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 @@ $set 10 #Menu 7 8 9 +10 : [encoding] $set 11 #Remember @@ -121,6 +155,11 @@ $set 11 #Remember $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 @@ $set 16 #Windowmenu 8 9 10 +11 $set 17 #Workspace @@ -176,6 +216,7 @@ $set 17 #Workspace $set 18 #fbsetroot 1 : : -solid, -mod, -gradient\n +2 pixmap, ! 3 -display \n\ -mod \n\ -foreground, -fg \n\ @@ -196,8 +237,8 @@ $set 19 #main 6 7 8 : '-log' -9 -10 +9 +10 11 : '-rc' 12 : '-screen' 13 Fluxbox %s: (c) %s Henrik Kinnunen\n\ diff --git a/nls/ru_RU/generated-UTF-8.m b/nls/ru_RU/generated-UTF-8.m index 5467f3a2..36837d67 100644 --- a/nls/ru_RU/generated-UTF-8.m +++ b/nls/ru_RU/generated-UTF-8.m @@ -62,7 +62,6 @@ $set 4 #Configmenu 10 Полная максимизация 11 Сглаживать изображение 12 Перемещение заполненных окон -13 Размытый фокус 14 Фокус по перемещению 15 Перемещение окон между рабочими столами 16 Использовать псевдо-прозрачность @@ -82,15 +81,49 @@ $set 5 #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 @@ $set 10 #Menu 7 Расположение 8 Перечитать настройки 9 Перезапуск +10 Внимание: не закрыты тэги [encoding] $set 11 #Remember @@ -121,6 +155,11 @@ $set 11 #Remember $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 @@ $set 16 #Windowmenu 8 Свернуть в заголовок 9 Приклеить 10 Убить +11 Использовать установки по умолчанию $set 17 #Workspace @@ -176,6 +216,7 @@ $set 17 #Workspace $set 18 #fbsetroot 1 Ошибка: необходимо задать один из следующих ключей: -solid, -mod, -gradient\n +2 Не удалось создать атомы pixmap, бросаем это гиблое дело! 3 -display соединение с дисплеем\n\ -mod макет клетки\n\ -foreground, -fg цвет переднего плана клетки\n\ @@ -196,8 +237,8 @@ $set 19 #main 6 Стандартное исключение 7 Неизвестная ошибка 8 ошибка: '-log' требует наличие аргумента -9 Записывается в -10 Имя журнала +9 Имя файла журнала +10 Записывается в 11 ошибка: '-rc' требует наличие аргумента 12 ошибка: '-screen' требует наличие аргумента 13 Fluxbox %s: (c) %s Henrik Kinnunen\n\ diff --git a/src/AttentionNoticeHandler.cc b/src/AttentionNoticeHandler.cc index 10a087c7..3f286958 100644 --- a/src/AttentionNoticeHandler.cc +++ b/src/AttentionNoticeHandler.cc @@ -23,7 +23,7 @@ #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::addAttention(WinClient &client) { 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(subj); - delete m_attentions[&winsubj->winClient()]; - m_attentions.erase(&winsubj->winClient()); + Focusable::FocusSubject *winsubj = + static_cast(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(); } diff --git a/src/AttentionNoticeHandler.hh b/src/AttentionNoticeHandler.hh index ed38d205..ed2245d3 100644 --- a/src/AttentionNoticeHandler.hh +++ b/src/AttentionNoticeHandler.hh @@ -27,7 +27,7 @@ #include -class WinClient; +class Focusable; namespace FbTk { class Timer; @@ -41,14 +41,14 @@ class AttentionNoticeHandler: public FbTk::Observer { public: ~AttentionNoticeHandler(); - typedef std::map NoticeMap; + typedef std::map 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; diff --git a/src/CascadePlacement.cc b/src/CascadePlacement.cc index e2993d22..3d4eeef9 100644 --- a/src/CascadePlacement.cc +++ b/src/CascadePlacement.cc @@ -42,7 +42,7 @@ CascadePlacement::~CascadePlacement() { delete [] m_cascade_y; } -bool CascadePlacement::placeWindow(const std::vector &windowlist, +bool CascadePlacement::placeWindow(const std::list &windowlist, const FluxboxWindow &win, int &place_x, int &place_y) { diff --git a/src/CascadePlacement.hh b/src/CascadePlacement.hh index 6fde194b..8fa39a00 100644 --- a/src/CascadePlacement.hh +++ b/src/CascadePlacement.hh @@ -34,7 +34,7 @@ class CascadePlacement: public PlacementStrategy, public: explicit CascadePlacement(const BScreen &screen); ~CascadePlacement(); - bool placeWindow(const std::vector &windowlist, + bool placeWindow(const std::list &windowlist, const FluxboxWindow &window, int &place_x, int &place_y); private: diff --git a/src/ClientMenu.cc b/src/ClientMenu.cc new file mode 100644 index 00000000..ae35aabf --- /dev/null +++ b/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(*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(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(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); +} diff --git a/src/Netizen.hh b/src/ClientMenu.hh similarity index 55% rename from src/Netizen.hh rename to src/ClientMenu.hh index 334a0656..b6ea2e56 100644 --- a/src/Netizen.hh +++ b/src/ClientMenu.hh @@ -1,8 +1,5 @@ -// 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) +// 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"), @@ -22,37 +19,42 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -#ifndef NETIZEN_HH -#define NETIZEN_HH +// $Id$ -#include +#ifndef CLIENTMENU_HH +#define CLIENTMENU_HH + +#include + +#include "FbMenu.hh" class BScreen; - -class Netizen { +class FluxboxWindow; +/** + * A menu holding a set of client menus. + * @see WorkspaceMenu + */ +class ClientMenu: public FbMenu { public: - Netizen(const BScreen &scr, Window w); - inline Window window() const { return m_window; } + typedef std::list Focusables; - void sendWorkspaceCount(); - void sendCurrentWorkspace(); + /** + * @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); - 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; + /// 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 // _NETIZEN_HH_ - +#endif // CLIENTMENU_HH diff --git a/src/ClientPattern.cc b/src/ClientPattern.cc index d6447675..9324bee5 100644 --- a/src/ClientPattern.cc +++ b/src/ClientPattern.cc @@ -24,7 +24,12 @@ #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 @@ ClientPattern::ClientPattern(const char *str): 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 @@ ClientPattern::ClientPattern(const char *str): 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 @@ string ClientPattern::toString() const { 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 @@ string ClientPattern::toString() const { } // 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 @@ bool ClientPattern::match(const WinClient &win) const { 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 @@ bool ClientPattern::addTerm(const string &str, WinProperty prop) { 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 @@ string ClientPattern::getProperty(WinProperty prop, const WinClient &client) con 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(); diff --git a/src/ClientPattern.hh b/src/ClientPattern.hh index 7610e77d..4a3cd0bc 100644 --- a/src/ClientPattern.hh +++ b/src/ClientPattern.hh @@ -32,7 +32,7 @@ #include #include -class WinClient; +class Focusable; /** * This class represents a "pattern" that we can match against a @@ -53,10 +53,14 @@ public: /// @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 @@ public: 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 @@ public: * 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: /** diff --git a/src/ClockTool.cc b/src/ClockTool.cc index a2598486..0bfa1362 100644 --- a/src/ClockTool.cc +++ b/src/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'; diff --git a/src/ColSmartPlacement.cc b/src/ColSmartPlacement.cc index cb3fbd93..16c3b815 100644 --- a/src/ColSmartPlacement.cc +++ b/src/ColSmartPlacement.cc @@ -27,7 +27,7 @@ #include "ScreenPlacement.hh" #include "Window.hh" -bool ColSmartPlacement::placeWindow(const std::vector &windowlist, +bool ColSmartPlacement::placeWindow(const std::list &windowlist, const FluxboxWindow &win, int &place_x, int &place_y) { @@ -85,9 +85,9 @@ bool ColSmartPlacement::placeWindow(const std::vector &windowli next_y = test_y + change_y; - std::vector::const_iterator it = + std::list::const_iterator it = windowlist.begin(); - std::vector::const_iterator it_end = + std::list::const_iterator it_end = windowlist.end(); for (; it != it_end && placed; ++it) { int curr_x = (*it)->x() - (*it)->xOffset(); diff --git a/src/ColSmartPlacement.hh b/src/ColSmartPlacement.hh index ad17d3b9..f8c85cf6 100644 --- a/src/ColSmartPlacement.hh +++ b/src/ColSmartPlacement.hh @@ -28,7 +28,7 @@ class ColSmartPlacement: public PlacementStrategy { public: - bool placeWindow(const std::vector &windowlist, + bool placeWindow(const std::list &windowlist, const FluxboxWindow &win, int &place_x, int &place_y); }; diff --git a/src/CommandDialog.cc b/src/CommandDialog.cc index e502bc1a..e19cd538 100644 --- a/src/CommandDialog.cc +++ b/src/CommandDialog.cc @@ -98,7 +98,7 @@ void CommandDialog::hide() { // return focus to fluxbox window if (FocusControl::focusedFbWindow()) - FocusControl::focusedFbWindow()->setInputFocus(); + FocusControl::focusedFbWindow()->focus(); } @@ -193,12 +193,12 @@ void CommandDialog::tabComplete() { 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 @@ void CommandDialog::init() { // 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 diff --git a/src/CommandDialog.hh b/src/CommandDialog.hh index a9e82acc..47d66879 100644 --- a/src/CommandDialog.hh +++ b/src/CommandDialog.hh @@ -34,14 +34,25 @@ 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 &postcommand) { m_postcommand = postcommand; } + /** + * Sets the command to be execute after the command is done. + * @param postcommand the command. + */ + void setPostCommand(FbTk::RefCount &postcommand) { + m_postcommand = postcommand; + } void show(); void hide(); @@ -52,6 +63,7 @@ public: void keyPressEvent(XKeyEvent &event); protected: + /// expand the current word, using the history as a references virtual void tabComplete(); private: @@ -59,8 +71,8 @@ private: 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 m_postcommand; ///< command to do after the first command was issued (like reconfigure) BScreen &m_screen; diff --git a/src/Container.cc b/src/Container.cc index d6ffcf3b..e2d01c75 100644 --- a/src/Container.cc +++ b/src/Container.cc @@ -36,7 +36,6 @@ Container::Container(const FbTk::FbWindow &parent): 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 @@ bool Container::removeItem(int index) { for (; index != 0; ++it, --index) continue; - if (*it == selected()) - m_selected = 0; - m_item_list.erase(it); repositionItems(); @@ -225,7 +221,6 @@ bool Container::removeItem(int index) { } void Container::removeAll() { - m_selected = 0; m_item_list.clear(); if (!m_update_lock) { clear(); @@ -248,19 +243,6 @@ int Container::find(ConstItem item) { 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) { if (size != m_max_size_per_client) { m_max_size_per_client = size; diff --git a/src/Container.hh b/src/Container.hh index cfaf1ea5..69da43d8 100644 --- a/src/Container.hh +++ b/src/Container.hh @@ -65,7 +65,6 @@ public: 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 @@ public: 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 @@ private: unsigned int m_max_size_per_client; unsigned int m_max_total_size; ItemList m_item_list; - Item m_selected; bool m_update_lock; }; diff --git a/src/CurrentWindowCmd.cc b/src/CurrentWindowCmd.cc index b6c3c0e0..4a60e63f 100644 --- a/src/CurrentWindowCmd.cc +++ b/src/CurrentWindowCmd.cc @@ -31,17 +31,24 @@ #include "FocusControl.hh" -CurrentWindowCmd::CurrentWindowCmd(Action act):m_action(act) { } - -void CurrentWindowCmd::execute() { - FluxboxWindow *win = FocusControl::focusedFbWindow(); - if (win) - (win->*m_action)(); +void WindowHelperCmd::execute() { + m_win = 0; + if (FocusControl::focusedFbWindow()) // guarantee that fbwindow() exists too + real_execute(); } +void WindowHelperCmd::execute(FluxboxWindow &win) { + m_win = &win; + real_execute(); +} -void KillWindowCmd::real_execute() { - winclient().sendClose(true); +FluxboxWindow &WindowHelperCmd::fbwindow() { + // will exist from execute above + return (m_win ? *m_win : *FocusControl::focusedFbWindow()); +} + +void CurrentWindowCmd::real_execute() { + (fbwindow().*m_action)(); } void SetHeadCmd::real_execute() { @@ -54,13 +61,14 @@ void SendToWorkspaceCmd::real_execute() { 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 TakeToWorkspaceCmd::real_execute() { 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()); @@ -97,21 +106,6 @@ void GoToTabCmd::real_execute() { (*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_step_size_x(step_size_x), m_step_size_y(step_size_y) { } diff --git a/src/CurrentWindowCmd.hh b/src/CurrentWindowCmd.hh index c1b91407..172f9c01 100644 --- a/src/CurrentWindowCmd.hh +++ b/src/CurrentWindowCmd.hh @@ -28,36 +28,33 @@ #include "Command.hh" class FluxboxWindow; -class WinClient; - -/// command that calls FluxboxWindow:: on execute() -/// similar to FbTk::SimpleCommand -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:: on execute() +/// similar to FbTk::SimpleCommand +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 { diff --git a/src/Ewmh.cc b/src/Ewmh.cc index de4377bf..72664962 100644 --- a/src/Ewmh.cc +++ b/src/Ewmh.cc @@ -28,7 +28,6 @@ #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 @@ void Ewmh::initForScreen(BScreen &screen) { * 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 @@ void Ewmh::setupFrame(FluxboxWindow &win) { // 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 @@ void Ewmh::setupFrame(FluxboxWindow &win) { 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 @@ void Ewmh::setupFrame(FluxboxWindow &win) { * 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 @@ void Ewmh::setupFrame(FluxboxWindow &win) { * 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::updateClientClose(WinClient &winclient){ void Ewmh::updateClientList(BScreen &screen) { - list creation_order_list = screen.focusControl().creationOrderList(); + if (screen.isShuttingdown()) + return; + + list creation_order_list = screen.focusControl().creationOrderList(); size_t num = creation_order_list.size(); Window *wl = FB_new_nothrow Window[num]; @@ -414,10 +404,13 @@ void Ewmh::updateClientList(BScreen &screen) { } int win=0; - list::iterator client_it = creation_order_list.begin(); - list::iterator client_it_end = creation_order_list.end(); - for (; client_it != client_it_end; ++client_it) - wl[win++] = (*client_it)->window(); + list::iterator client_it = creation_order_list.begin(); + list::iterator client_it_end = creation_order_list.end(); + for (; client_it != client_it_end; ++client_it) { + WinClient *client = dynamic_cast(*client_it); + if (client) + wl[win++] = client->window(); + } /* From Extended Window Manager Hints, draft 1.3: * @@ -800,32 +793,12 @@ bool Ewmh::checkClientMessage(const XClientMessageEvent &ce, 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 @@ void Ewmh::updateActions(FluxboxWindow &win) { 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) { diff --git a/src/Ewmh.hh b/src/Ewmh.hh index 00979a16..cc33eff3 100644 --- a/src/Ewmh.hh +++ b/src/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); @@ -145,7 +144,5 @@ private: Atom utf8_string; - std::vector m_windows; - FbTk::FbString getUTF8Property(Atom property); }; diff --git a/src/FbAtoms.cc b/src/FbAtoms.cc index e6b5e514..ccbf41c2 100644 --- a/src/FbAtoms.cc +++ b/src/FbAtoms.cc @@ -60,35 +60,6 @@ void FbAtoms::initAtoms() { 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); } diff --git a/src/FbAtoms.hh b/src/FbAtoms.hh index 5e8e75fd..0f2e1477 100644 --- a/src/FbAtoms.hh +++ b/src/FbAtoms.hh @@ -40,57 +40,18 @@ public: 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; diff --git a/src/FbCommandFactory.cc b/src/FbCommandFactory.cc index 02573748..bf008ad8 100644 --- a/src/FbCommandFactory.cc +++ b/src/FbCommandFactory.cc @@ -52,17 +52,43 @@ using std::endl; // 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 args; + FbTk::StringUtil::stringtok(args, options); + vector::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 @@ FbCommandFactory::FbCommandFactory() { "focusleft", "focusright", "fullscreen", + "gotowindow", "hidemenus", "iconify", "keymode", @@ -116,7 +143,7 @@ FbCommandFactory::FbCommandFactory() { "reconfig", "reconfigure", "reloadstyle", - "removelastworkspace", + "removelastworkspace", "resizeto", "resize", "resizehorizontal", @@ -148,6 +175,7 @@ FbCommandFactory::FbCommandFactory() { "taketoprevworkspace", "togglecmd", "toggledecor", + "typeaheadfocus", "windowmenu", "workspace", /* NOTE: The following are DEPRECATED and subject to removal */ @@ -243,21 +271,15 @@ FbTk::Command *FbCommandFactory::stringToCommand(const std::string &command, // 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(new FullscreenCmd()), arguments); + else if (command == "minimizewindow" || command == "minimize" || command == "iconify") + return new WindowListCmd(FbTk::RefCount(new CurrentWindowCmd(&FluxboxWindow::iconify)), arguments); + else if (command == "maximizewindow" || command == "maximize") + return new WindowListCmd(FbTk::RefCount(new CurrentWindowCmd(&FluxboxWindow::maximizeFull)), arguments); else if (command == "maximizevertical") - return new CurrentWindowCmd(&FluxboxWindow::maximizeVertical); + return new WindowListCmd(FbTk::RefCount(new CurrentWindowCmd(&FluxboxWindow::maximizeVertical)), arguments); else if (command == "maximizehorizontal") - return new CurrentWindowCmd(&FluxboxWindow::maximizeHorizontal); + return new WindowListCmd(FbTk::RefCount(new CurrentWindowCmd(&FluxboxWindow::maximizeHorizontal)), arguments); else if (command == "setalpha") { typedef vector StringTokens; StringTokens tokens; @@ -279,24 +301,37 @@ FbTk::Command *FbCommandFactory::stringToCommand(const std::string &command, 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(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 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 StringTokens; StringTokens tokens; FbTk::StringUtil::stringtok(tokens, arguments); @@ -339,70 +374,107 @@ FbTk::Command *FbCommandFactory::stringToCommand(const std::string &command, } } - 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(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(new MoveCmd(dx, dy)), pat); + } else if (command == "raise") + return new WindowListCmd(FbTk::RefCount(new CurrentWindowCmd(&FluxboxWindow::raise)), arguments); else if (command == "raiselayer") - return new CurrentWindowCmd(&FluxboxWindow::raiseLayer); + return new WindowListCmd(FbTk::RefCount(new CurrentWindowCmd(&FluxboxWindow::raiseLayer)), arguments); else if (command == "lower") - return new CurrentWindowCmd(&FluxboxWindow::lower); + return new WindowListCmd(FbTk::RefCount(new CurrentWindowCmd(&FluxboxWindow::lower)), arguments); else if (command == "lowerlayer") - return new CurrentWindowCmd(&FluxboxWindow::lowerLayer); + return new WindowListCmd(FbTk::RefCount(new CurrentWindowCmd(&FluxboxWindow::lowerLayer)), arguments); else if (command == "close") - return new CurrentWindowCmd(&FluxboxWindow::close); + return new WindowListCmd(FbTk::RefCount(new CurrentWindowCmd(&FluxboxWindow::close)), arguments); else if (command == "closeallwindows") return new CloseAllWindowsCmd(); - else if (command == "shade" || command == "shadewindow") - return new CurrentWindowCmd(&FluxboxWindow::shade); - else if (command == "stick" || command == "stickwindow") - return new CurrentWindowCmd(&FluxboxWindow::stick); - else if (command == "toggledecor") - return new CurrentWindowCmd(&FluxboxWindow::toggleDecoration); - else if (command == "sethead") - return new SetHeadCmd(atoi(arguments.c_str())); - else if (command == "sendtoworkspace") - // 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); + return new WindowListCmd(FbTk::RefCount(new CurrentWindowCmd(&FluxboxWindow::kill)), arguments); + else if (command == "shade" || command == "shadewindow") + return new WindowListCmd(FbTk::RefCount(new CurrentWindowCmd(&FluxboxWindow::shade)), arguments); + else if (command == "stick" || command == "stickwindow") + return new WindowListCmd(FbTk::RefCount(new CurrentWindowCmd(&FluxboxWindow::stick)), arguments); + else if (command == "toggledecor") + return new WindowListCmd(FbTk::RefCount(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(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 + 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 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(new CurrentWindowCmd(&FluxboxWindow::nextClient)), arguments); else if (command == "prevtab") - return new CurrentWindowCmd(&FluxboxWindow::prevClient); + return new WindowListCmd(FbTk::RefCount(new CurrentWindowCmd(&FluxboxWindow::prevClient)), arguments); else if (command == "movetableft") - return new CurrentWindowCmd(&FluxboxWindow::moveClientLeft); + return new WindowListCmd(FbTk::RefCount(new CurrentWindowCmd(&FluxboxWindow::moveClientLeft)), arguments); else if (command == "movetabright") - return new CurrentWindowCmd(&FluxboxWindow::moveClientRight); + return new WindowListCmd(FbTk::RefCount(new CurrentWindowCmd(&FluxboxWindow::moveClientRight)), arguments); else if (command == "detachclient") - return new CurrentWindowCmd(&FluxboxWindow::detachCurrentClient); + return new WindowListCmd(FbTk::RefCount(new CurrentWindowCmd(&FluxboxWindow::detachCurrentClient)), arguments); else if (command == "windowmenu") return new CurrentWindowCmd(&FluxboxWindow::popupMenu); // @@ -423,11 +495,54 @@ FbTk::Command *FbCommandFactory::stringToCommand(const std::string &command, cerr<<"*** WARNING: 'Workspace' actions are deprecated! Use 'Workspace ' instead"<> 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 @@ FbTk::Command *FbCommandFactory::stringToCommand(const std::string &command, 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") diff --git a/src/FbCommands.cc b/src/FbCommands.cc index b7ee9413..f536fd8e 100644 --- a/src/FbCommands.cc +++ b/src/FbCommands.cc @@ -25,6 +25,7 @@ #include "fluxbox.hh" #include "Screen.hh" #include "CommandDialog.hh" +#include "FocusControl.hh" #include "Workspace.hh" #include "Window.hh" #include "Keys.hh" @@ -279,6 +280,35 @@ void HideMenuCmd::execute() { 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(*it)); + } + + m_menu = new ClientMenu(*screen, m_list, 0); + ::showMenu(*screen, **m_menu); +} + ShowCustomMenuCmd::ShowCustomMenuCmd(const string &arguments) : custom_menu_file(arguments) {} void ShowCustomMenuCmd::execute() { diff --git a/src/FbCommands.hh b/src/FbCommands.hh index 314d3398..a049a7ce 100644 --- a/src/FbCommands.hh +++ b/src/FbCommands.hh @@ -29,8 +29,10 @@ #include "Command.hh" #include "FbTk/RefCount.hh" -#include "FbTk/Menu.hh" +#include "ClientMenu.hh" +#include "ClientPattern.hh" +#include #include namespace FbCommands { @@ -121,6 +123,18 @@ 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 m_list; + FbTk::RefCount m_menu; +}; + class ShowCustomMenuCmd: public FbTk::Command { public: explicit ShowCustomMenuCmd(const std::string &arguments); diff --git a/src/FbTk/ITypeAheadable.hh b/src/FbTk/ITypeAheadable.hh index 1b0bd035..c998f980 100644 --- a/src/FbTk/ITypeAheadable.hh +++ b/src/FbTk/ITypeAheadable.hh @@ -19,6 +19,8 @@ // 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 diff --git a/src/FbTk/Makefile.am b/src/FbTk/Makefile.am index fadc998e..d98c8f61 100644 --- a/src/FbTk/Makefile.am +++ b/src/FbTk/Makefile.am @@ -49,7 +49,6 @@ libFbTk_a_SOURCES = App.hh App.cc Color.cc Color.hh Command.hh \ 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 \ diff --git a/src/FbTk/Menu.cc b/src/FbTk/Menu.cc index b0fcb4b1..23efcfec 100644 --- a/src/FbTk/Menu.cc +++ b/src/FbTk/Menu.cc @@ -357,10 +357,6 @@ void Menu::enterSubmenu() { submenu->cycleItems(false); } -void Menu::enterParent() { - internal_hide(); -} - void Menu::disableTitle() { setTitleVisibility(false); } @@ -1033,7 +1029,7 @@ void Menu::keyPressEvent(XKeyEvent &event) { 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 @@ void Menu::keyPressEvent(XKeyEvent &event) { break; case XK_BackSpace: if (m_type_ahead.stringSize() == 0) { - enterParent(); + internal_hide(); break; } diff --git a/src/FbTk/Menu.hh b/src/FbTk/Menu.hh index 34df40a8..06af08d2 100644 --- a/src/FbTk/Menu.hh +++ b/src/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 @@ public: /// cycle through menuitems void cycleItems(bool reverse); void enterSubmenu(); - void enterParent(); void disableTitle(); void enableTitle(); @@ -193,7 +193,7 @@ protected: virtual void internal_hide(bool first = true); - void update(FbTk::Subject *); + virtual void update(FbTk::Subject *); private: diff --git a/src/FbTk/MenuIcon.cc b/src/FbTk/MenuIcon.cc deleted file mode 100644 index d64d876d..00000000 --- a/src/FbTk/MenuIcon.cc +++ /dev/null @@ -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 - diff --git a/src/FbTk/MenuIcon.hh b/src/FbTk/MenuIcon.hh deleted file mode 100644 index 90cf320b..00000000 --- a/src/FbTk/MenuIcon.hh +++ /dev/null @@ -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 - -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 - diff --git a/src/FbTk/MenuItem.cc b/src/FbTk/MenuItem.cc index bc80ca08..2576d2b0 100644 --- a/src/FbTk/MenuItem.cc +++ b/src/FbTk/MenuItem.cc @@ -93,27 +93,32 @@ void MenuItem::draw(FbDrawable &draw, // 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); diff --git a/src/FbTk/MenuItem.hh b/src/FbTk/MenuItem.hh index afb6be9d..7fac8c76 100644 --- a/src/FbTk/MenuItem.hh +++ b/src/FbTk/MenuItem.hh @@ -101,6 +101,9 @@ public: */ //@{ 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; } diff --git a/src/FbTk/TypeAhead.hh b/src/FbTk/TypeAhead.hh index 15246b99..b28c8030 100644 --- a/src/FbTk/TypeAhead.hh +++ b/src/FbTk/TypeAhead.hh @@ -103,6 +103,8 @@ public: if (!m_search_results.empty()) fillValues(m_search_results.back().result(), last_matched); + else + return *m_ref; return last_matched; } diff --git a/src/FbWinFrame.cc b/src/FbWinFrame.cc index fbf11027..cc7d379f 100644 --- a/src/FbWinFrame.cc +++ b/src/FbWinFrame.cc @@ -33,6 +33,7 @@ #include "FbWinFrameTheme.hh" #include "Screen.hh" +#include "IconButton.hh" #include "Container.hh" #ifdef SHAPE @@ -52,7 +53,8 @@ FbWinFrame::FbWinFrame(BScreen &screen, FbWinFrameTheme &theme, FbTk::ImageContr 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 @@ void FbWinFrame::setFocus(bool newvalue) { } } - if (currentLabel()) { - if (newvalue) // focused - applyFocusLabel(*m_current_label); - else // unfocused - applyUnfocusLabel(*m_current_label); - } - applyAll(); clearAll(); } @@ -610,11 +605,9 @@ void FbWinFrame::removeAllButtons() { } } -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 @@ FbWinFrame::ButtonId FbWinFrame::createTab(const string &title, FbTk::Command *c EnterWindowMask); FbTk::EventManager::instance()->add(*button, button->window()); - FbTk::RefCount 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 @@ void FbWinFrame::moveLabelButtonRightOf(FbTk::TextButton &btn, const FbTk::TextB m_tab_container.moveItem(&btn, movement); } -void FbWinFrame::setLabelButtonFocus(FbTk::TextButton &btn) { - if (&btn == currentLabel() || 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) { +void FbWinFrame::setLabelButtonFocus(IconButton &btn) { if (btn.parent() != &m_tab_container) return; - - if (value) - applyFocusLabel(btn); - else - applyUnfocusLabel(btn); - - btn.clear(); + m_label.setText(btn.text()); } void FbWinFrame::setClientWindow(FbTk::FbWindow &win) { @@ -745,7 +700,8 @@ void FbWinFrame::setClientWindow(FbTk::FbWindow &win) { 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 @@ void FbWinFrame::removeEventHandler() { } 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 @@ void FbWinFrame::buttonPressEvent(XButtonEvent &event) { } 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 @@ void FbWinFrame::renderTitlebar() { //!! 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 @@ void FbWinFrame::renderTabContainer() { 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 @@ void FbWinFrame::renderTabContainer() { 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 @@ void FbWinFrame::applyTitlebar() { 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); @@ -1455,15 +1399,12 @@ void FbWinFrame::init() { m_disable_themeshape = false; - m_current_label = 0; // no focused button at first - m_handle.showSubwindows(); // 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 @@ void FbWinFrame::applyTabContainer() { 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(*btn_it); - if (btn == m_current_label && m_focused) - applyFocusLabel(*btn); - else - applyUnfocusLabel(*btn); + IconButton *btn = static_cast(*btn_it); + btn->reconfigTheme(); } } @@ -1626,15 +1564,6 @@ void FbWinFrame::setBorderWidth(unsigned int border_width) { 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); @@ -1648,32 +1577,6 @@ void FbWinFrame::setBorderWidth(unsigned int border_width) { } -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); - -} - // this function translates its arguments according to win_gravity // if win_gravity is negative, it does an inverse translation // This function should be used when a window is mapped/unmapped/pos configured diff --git a/src/FbWinFrame.hh b/src/FbWinFrame.hh index 1eefe424..bdc2adde 100644 --- a/src/FbWinFrame.hh +++ b/src/FbWinFrame.hh @@ -43,6 +43,8 @@ class Shape; class FbWinFrameTheme; class BScreen; +class IconButton; +class Focusable; namespace FbTk { class TextButton; @@ -71,8 +73,6 @@ public: }; - typedef FbTk::TextButton *ButtonId; ///< defines a button id - /// create a top level window FbWinFrame(BScreen &screen, FbWinFrameTheme &theme, FbTk::ImageControl &imgctrl, FbTk::XLayer &layer, @@ -142,10 +142,9 @@ public: /// 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 @@ public: //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 @@ public: 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 @@ private: 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 @@ private: ButtonList m_buttons_left, ///< buttons to the left m_buttons_right; ///< buttons to the right typedef std::list 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 @@ private: 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; diff --git a/src/FbWinFrameTheme.cc b/src/FbWinFrameTheme.cc index e4bc196f..6f7f9efa 100644 --- a/src/FbWinFrameTheme.cc +++ b/src/FbWinFrameTheme.cc @@ -24,13 +24,12 @@ #include "FbWinFrameTheme.hh" #include "App.hh" +#include "IconbarTheme.hh" + #include 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 @@ FbWinFrameTheme::FbWinFrameTheme(int screen_num): 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 @@ void FbWinFrameTheme::reconfigTheme() { 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(); } diff --git a/src/FbWinFrameTheme.hh b/src/FbWinFrameTheme.hh index 319e01bf..04d6ee49 100644 --- a/src/FbWinFrameTheme.hh +++ b/src/FbWinFrameTheme.hh @@ -33,6 +33,7 @@ #include "FbTk/GContext.hh" #include "BorderTheme.hh" +#include "IconbarTheme.hh" #include "Shape.hh" class FbWinFrameTheme: public FbTk::Theme { @@ -43,9 +44,6 @@ public: @name textures */ //@{ - const FbTk::Texture &labelFocusTexture() const { return *m_label_focus; } - const FbTk::Texture &labelUnfocusTexture() const { return *m_label_unfocus; } - const FbTk::ThemeItem &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 @@ public: @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 @@ public: 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 m_label_focus, m_label_unfocus; FbTk::ThemeItem m_title_focus, m_title_unfocus; FbTk::ThemeItem m_handle_focus, m_handle_unfocus; FbTk::ThemeItem m_button_focus, m_button_unfocus, m_button_pressed; FbTk::ThemeItem m_grip_focus, m_grip_unfocus; - FbTk::ThemeItem m_label_focus_color, m_label_unfocus_color; FbTk::ThemeItem m_button_focus_color, m_button_unfocus_color; FbTk::ThemeItem m_font; - FbTk::ThemeItem m_textjustify; FbTk::ThemeItem m_shape_place; FbTk::ThemeItem 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 @@ private: Cursor m_cursor_upper_right_angle; unsigned char m_focused_alpha; unsigned char m_unfocused_alpha; + + IconbarTheme m_iconbar_theme; }; #endif // FBWINFRAMETHEME_HH diff --git a/src/FocusControl.cc b/src/FocusControl.cc index d4cb4104..6ccc9a1f 100644 --- a/src/FocusControl.cc +++ b/src/FocusControl.cc @@ -23,6 +23,7 @@ #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 @@ FocusControl::FocusControl(BScreen &screen): 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 @@ void FocusControl::cycleFocus(FocusedWindows &window_list, int opts, bool cycle_ } 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 @@ void FocusControl::cycleFocus(FocusedWindows &window_list, int opts, bool cycle_ 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 @@ void FocusControl::cycleFocus(FocusedWindows &window_list, int opts, bool cycle_ 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 @@ void FocusControl::cycleFocus(FocusedWindows &window_list, int opts, bool cycle_ } +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 @@ void FocusControl::addFocusFront(WinClient &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 @@ void FocusControl::setFocusBack(FluxboxWindow *fbwin) { 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 @@ void FocusControl::setFocusBack(FluxboxWindow *fbwin) { m_focused_list.push_back(*it); m_focused_list.erase(it); } + } void FocusControl::stopCyclingFocus() { @@ -208,7 +255,7 @@ void FocusControl::stopCyclingFocus() { 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 @@ void FocusControl::stopCyclingFocus() { // 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 @@ void FocusControl::stopCyclingFocus() { * 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 @@ WinClient *FocusControl::lastFocusedWindow(int workspace) { * 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(*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 @@ void FocusControl::dirFocus(FluxboxWindow &win, FocusDir dir) { } 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 @@ void FocusControl::removeClient(WinClient &client) { } } +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(*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 @@ void FocusControl::revertFocus(BScreen &screen) { // 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 @@ void FocusControl::revertFocus(BScreen &screen) { * 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 */ diff --git a/src/FocusControl.hh b/src/FocusControl.hh index 79d16d49..07901101 100644 --- a/src/FocusControl.hh +++ b/src/FocusControl.hh @@ -28,8 +28,10 @@ #include "FbTk/Resource.hh" +class ClientPattern; class WinClient; class FluxboxWindow; +class Focusable; class BScreen; /** @@ -38,13 +40,12 @@ class BScreen; */ class FocusControl { public: - typedef std::list FocusedWindows; + typedef std::list 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 @@ public: }; /// 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 @@ public: /** * 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 @@ public: 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 @@ public: 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 @@ private: // 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; diff --git a/src/Focusable.hh b/src/Focusable.hh new file mode 100644 index 00000000..e02e0d79 --- /dev/null +++ b/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 + +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 diff --git a/src/IconButton.cc b/src/IconButton.cc index 545ee1d7..34fe532c 100644 --- a/src/IconButton.cc +++ b/src/IconButton.cc @@ -24,21 +24,19 @@ #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/EventManager.hh" -#include "FbTk/MacroCommand.hh" #include "FbTk/Command.hh" -#include "FbTk/RefCount.hh" +#include "FbTk/EventManager.hh" +#include "FbTk/ImageControl.hh" +#include "FbTk/MacroCommand.hh" #include "FbTk/Menu.hh" +#include "FbTk/RefCount.hh" +#include "FbTk/SimpleCommand.hh" #ifdef HAVE_CONFIG_H #include "config.h" @@ -49,127 +47,25 @@ #include #endif // SHAPE -typedef FbTk::RefCount 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::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 @@ void IconButton::setPixmap(bool use) { } } +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 @@ void IconButton::update(FbTk::Subject *subj) { 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 @@ void IconButton::update(FbTk::Subject *subj) { 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 @@ void IconButton::update(FbTk::Subject *subj) { #endif // SHAPE - if (subj == &(m_win.titleSig())) - setText(m_win.title()); - if (subj != 0) { setupWindow(); } else { @@ -298,13 +240,8 @@ void IconButton::update(FbTk::Subject *subj) { } 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(); } diff --git a/src/IconButton.hh b/src/IconButton.hh index b8a7ef0c..dc8203b1 100644 --- a/src/IconButton.hh +++ b/src/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); @@ -47,11 +48,13 @@ public: 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 @@ protected: 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 diff --git a/src/IconMenu.cc b/src/IconMenu.cc deleted file mode 100644 index 33ef05ad..00000000 --- a/src/IconMenu.cc +++ /dev/null @@ -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 - -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(subj)->screen(); - updateItems(*this, screen); - } else - FbTk::Menu::update(subj); -} diff --git a/src/IconMenu.hh b/src/IconMenu.hh deleted file mode 100644 index 43351d10..00000000 --- a/src/IconMenu.hh +++ /dev/null @@ -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 diff --git a/src/IconMenuItem.hh b/src/IconMenuItem.hh deleted file mode 100644 index b737833f..00000000 --- a/src/IconMenuItem.hh +++ /dev/null @@ -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 diff --git a/src/IconbarTheme.cc b/src/IconbarTheme.cc index f4e4c55a..2ee8360e 100644 --- a/src/IconbarTheme.cc +++ b/src/IconbarTheme.cc @@ -37,8 +37,7 @@ IconbarTheme::IconbarTheme(int screen_num, 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 @@ bool IconbarTheme::fallback(FbTk::ThemeItem_base &item) { } 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; diff --git a/src/IconbarTheme.hh b/src/IconbarTheme.hh index 62fa2ef0..419ab1a2 100644 --- a/src/IconbarTheme.hh +++ b/src/IconbarTheme.hh @@ -49,14 +49,12 @@ public: 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 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 m_alpha; + std::string m_name, m_altname; }; #endif // ICONBARTHEME_HH diff --git a/src/IconbarTool.cc b/src/IconbarTool.cc index 3509a0c6..bbd867be 100644 --- a/src/IconbarTool.cc +++ b/src/IconbarTool.cc @@ -24,6 +24,8 @@ #include "IconbarTool.hh" +#include "fluxbox.hh" +#include "WindowCmd.hh" #include "Screen.hh" #include "IconbarTheme.hh" #include "Window.hh" @@ -85,40 +87,6 @@ void FbTk::Resource::setFromString(const char *strval) { setDefaultValue(); } -template<> -void FbTk::Resource::setDefaultValue() { - m_value = IconbarTool::SCREEN; -} - - -template<> -void FbTk::Resource::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::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<> void FbTk::Resource::setDefaultValue() { m_value = Container::RELATIVE; @@ -290,52 +258,67 @@ void setupModeMenu(FbTk::Menu &menu, IconbarTool &handler) { } 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 ((mode == IconbarTool::WORKSPACE || mode == IconbarTool::WORKSPACEICONS + || mode == IconbarTool::WORKSPACENOICONS) && + win.workspaceNumber() != win.screen().currentWorkspaceID()) + return false; + + return true; +} + +typedef FbTk::RefCount 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::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(); + } } - if (win.isIconHidden()) - ret_val = false; - - return ret_val; -} - -void removeDuplicate(const IconbarTool::IconList &iconlist, list &windowlist) { - IconbarTool::IconList::const_iterator icon_it = iconlist.begin(); - IconbarTool::IconList::const_iterator icon_it_end = iconlist.end(); - list::iterator remove_it = windowlist.end(); - for (; icon_it != icon_it_end; ++icon_it) - remove_it = remove(windowlist.begin(), remove_it, &(*icon_it)->win()); - - // remove already existing windows - windowlist.erase(remove_it, windowlist.end()); -} +private: + Focusable &m_win; +}; }; // end anonymous namespace @@ -345,16 +328,9 @@ IconbarTool::IconbarTool(const FbTk::FbWindow &parent, IconbarTheme &theme, BScr 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 @@ IconbarTool::IconbarTool(const FbTk::FbWindow &parent, IconbarTheme &theme, BScr screen.clientListSig().attach(this); screen.iconListSig().attach(this); screen.currentWorkspaceSig().attach(this); - // setup focus timer - - FbTk::RefCount timer_cmd(new FbTk::SimpleCommand(*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 @@ void IconbarTool::update(FbTk::Subject *subj) { if (subj != 0 && typeid(*subj) == typeid(FluxboxWindow::WinSubject)) { // we handle everything except die signal here FluxboxWindow::WinSubject *winsubj = static_cast(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,30 +484,24 @@ void IconbarTool::update(FbTk::Subject *subj) { 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(subj); + if (subj == &(winsubj->win().dieSig())) { // die sig + removeWindow(winsubj->win()); + renderTheme(); + return; // we don't need to update the entire list + } } bool remove_all = false; // if we should readd all windows @@ -587,7 +540,7 @@ void IconbarTool::update(FbTk::Subject *subj) { 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 @@ IconButton *IconbarTool::findButton(FluxboxWindow &win) { 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 @@ void IconbarTool::renderTheme() { // 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 @@ void IconbarTool::deleteIcons() { } } -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 @@ void IconbarTool::removeWindow(FluxboxWindow &win) { cerr<<"IconbarTool::"<<__FUNCTION__<<"( 0x"<<&win<<" title = "<workspaceSig().detach(this); + win.fbwindow()->stateSig().detach(this); + } // remove from list and render theme again IconButton *button = *it; @@ -797,46 +644,46 @@ void IconbarTool::removeWindow(FluxboxWindow &win) { } -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 = "<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 ordered_list = - m_screen.focusControl().creationOrderList(); - list::iterator it = ordered_list.begin(); - list::iterator it_end = ordered_list.end(); + list ordered_list = + m_screen.focusControl().creationOrderWinList(); + list::iterator it = ordered_list.begin(); + list::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) { @@ -846,27 +693,6 @@ bool IconbarTool::checkDuplicate(FluxboxWindow &win) { return false; } -void IconbarTool::timedRender() { - WinClient *client = FocusControl::focusedWindow(); - IconButton *current_button = static_cast(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_icon_container.setOrientation(orient); ToolbarItem::setOrientation(orient); diff --git a/src/IconbarTool.hh b/src/IconbarTool.hh index 3512f784..323c714f 100644 --- a/src/IconbarTool.hh +++ b/src/IconbarTool.hh @@ -41,7 +41,7 @@ class IconbarTheme; class BScreen; class IconButton; -class FluxboxWindow; +class Focusable; class IconbarTool: public ToolbarItem, public FbTk::Observer { public: @@ -57,13 +57,6 @@ public: 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, BScreen &screen, FbTk::Menu &menu); ~IconbarTool(); @@ -85,60 +78,48 @@ public: 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 m_rc_mode; - FbTk::Resource m_wheel_mode; FbTk::Resource m_rc_alignment; ///< alignment of buttons FbTk::Resource m_rc_client_width; ///< size of client button in LEFT/RIGHT mode FbTk::Resource m_rc_client_padding; ///< padding of the text FbTk::Resource 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; }; diff --git a/src/Keys.cc b/src/Keys.cc index 72d59cdc..6d13cd42 100644 --- a/src/Keys.cc +++ b/src/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 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 @@ void Keys::deleteTree() { m_map.clear(); } +// keys are only grabbed in global context void Keys::grabKey(unsigned int key, unsigned int mod) { - std::list::iterator it = m_window_list.begin(); - std::list::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::iterator it = m_window_list.begin(); - std::list::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::iterator it = m_window_list.begin(); - std::list::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::iterator it = m_window_list.begin(); - std::list::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 @@ bool Keys::addBinding(const string &linebuffer) { 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 @@ bool Keys::addBinding(const string &linebuffer) { } // 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 @@ bool Keys::doAction(int type, unsigned int mods, unsigned int key) { 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 @@ void Keys::setKeyMode(t_key *keyMode) { 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 command) { key = key_; diff --git a/src/Keys.hh b/src/Keys.hh index a83a0eca..2fca4605 100644 --- a/src/Keys.hh +++ b/src/Keys.hh @@ -25,7 +25,6 @@ #define KEYS_HH #include -#include #include #include #include @@ -53,11 +52,7 @@ public: // and so on... }; - /** - Constructor - @param display display connection - @param filename file to load, default none - */ + /// constructor explicit Keys(); /// destructor ~Keys(); @@ -80,7 +75,12 @@ public: /** 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 @@ private: 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 @@ private: std::string m_filename; class t_key; - typedef std::vector keylist_t; + typedef std::list keylist_t; class t_key { public: @@ -116,11 +117,12 @@ private: 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 @@ private: keyspace_t m_map; Display *m_display; ///< display connection - std::list m_window_list; + + typedef std::map WindowMap; + WindowMap m_window_map; }; #endif // KEYS_HH diff --git a/src/Layer.hh b/src/Layer.hh index 2b155393..e86c0908 100644 --- a/src/Layer.hh +++ b/src/Layer.hh @@ -22,6 +22,9 @@ #ifndef LAYER_HH #define LAYER_HH +#include +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 @@ public: }; 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; } diff --git a/src/Makefile.am b/src/Makefile.am index b6cb0240..f82a206d 100644 --- a/src/Makefile.am +++ b/src/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 @@ fluxbox_SOURCES = AtomHandler.hh ArrowButton.hh ArrowButton.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 @@ fluxbox_SOURCES = AtomHandler.hh ArrowButton.hh ArrowButton.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 @@ fluxbox_SOURCES = AtomHandler.hh ArrowButton.hh ArrowButton.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 @@ fluxbox_SOURCES = AtomHandler.hh ArrowButton.hh ArrowButton.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} diff --git a/src/MenuCreator.cc b/src/MenuCreator.cc index fefb3dcf..a99d7854 100644 --- a/src/MenuCreator.cc +++ b/src/MenuCreator.cc @@ -31,8 +31,7 @@ #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/StringUtil.hh" #include "FbTk/FileUtil.hh" #include "FbTk/MenuSeparator.hh" -#include "FbTk/MenuIcon.hh" #include "FbTk/Transparent.hh" #include @@ -470,8 +468,8 @@ FbTk::Menu *MenuCreator::createFromFile(const string &filename, int screen_numbe 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 @@ FbTk::Menu *MenuCreator::createMenuType(const string &type, int 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") { diff --git a/src/MinOverlapPlacement.cc b/src/MinOverlapPlacement.cc new file mode 100644 index 00000000..e7e80cbb --- /dev/null +++ b/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 &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(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_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::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::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::iterator min_reg = region_set.end(); + + std::set::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; +} diff --git a/src/MinOverlapPlacement.hh b/src/MinOverlapPlacement.hh new file mode 100644 index 00000000..20b5c95a --- /dev/null +++ b/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 &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 diff --git a/src/Netizen.cc b/src/Netizen.cc deleted file mode 100644 index c220a838..00000000 --- a/src/Netizen.cc +++ /dev/null @@ -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); -} diff --git a/src/PlacementStrategy.hh b/src/PlacementStrategy.hh index 001218d2..e8b0e961 100644 --- a/src/PlacementStrategy.hh +++ b/src/PlacementStrategy.hh @@ -24,7 +24,7 @@ #ifndef PLACEMENTSTRATEGY_HH #define PLACEMENTSTRATEGY_HH -#include +#include class FluxboxWindow; @@ -37,7 +37,7 @@ struct PlacementStrategy { * @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 &windowlist, + virtual bool placeWindow(const std::list &windowlist, const FluxboxWindow &win, int &place_x, int &place_y) = 0; virtual ~PlacementStrategy() { } diff --git a/src/Remember.cc b/src/Remember.cc index f5a5ac85..fbb4a2e6 100644 --- a/src/Remember.cc +++ b/src/Remember.cc @@ -247,8 +247,8 @@ bool handleStartupItem(const string &line, int offset) { }; // 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::find(WinClient &winclient) { 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 @@ int Remember::parseApp(ifstream &file, Application &app, string *first_line) { 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 @@ void Remember::reconfigure() { if (!apps_file.eof()) { string line; int row = 0; - int in_group = 0; + bool in_group = false; + ClientPattern *pat = 0; list grouped_pats; while (getline(apps_file, line) && ! apps_file.eof()) { row++; @@ -592,11 +595,11 @@ void Remember::reconfigure() { 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 @@ void Remember::reconfigure() { // 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 @@ void Remember::reconfigure() { list::iterator it = grouped_pats.begin(); list::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 @@ void Remember::reconfigure() { 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 "<toString(); apps_file << endl; Patterns::iterator git = m_pats->begin(); @@ -1151,10 +1151,7 @@ FluxboxWindow *Remember::findGroup(Application *app, BScreen &screen) { 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(); } diff --git a/src/Remember.hh b/src/Remember.hh index 581e525d..7ecf8c2a 100644 --- a/src/Remember.hh +++ b/src/Remember.hh @@ -29,6 +29,9 @@ #define REMEMBER_HH #include "AtomHandler.hh" +#include "ClientPattern.hh" + +#include "FbTk/RefCount.hh" #include #include @@ -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 @@ public: 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 group_pattern; }; @@ -254,7 +250,8 @@ private: // 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 m_pats; Clients m_clients; diff --git a/src/Resources.cc b/src/Resources.cc index fde08d7c..d8660eb0 100644 --- a/src/Resources.cc +++ b/src/Resources.cc @@ -202,23 +202,10 @@ getString() const { template<> void FbTk::Resource:: 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 @@ setFromString(const char *strval) { template<> string FbTk::Resource:: 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<> diff --git a/src/RowSmartPlacement.cc b/src/RowSmartPlacement.cc index 22ab768e..e2a0be42 100644 --- a/src/RowSmartPlacement.cc +++ b/src/RowSmartPlacement.cc @@ -27,7 +27,7 @@ #include "Screen.hh" #include "ScreenPlacement.hh" -bool RowSmartPlacement::placeWindow(const std::vector &windowlist, +bool RowSmartPlacement::placeWindow(const std::list &windowlist, const FluxboxWindow &win, int &place_x, int &place_y) { @@ -95,9 +95,9 @@ bool RowSmartPlacement::placeWindow(const std::vector &windowli next_x = test_x + change_x; - std::vector::const_iterator win_it = + std::list::const_iterator win_it = windowlist.begin(); - std::vector::const_iterator win_it_end = + std::list::const_iterator win_it_end = windowlist.end(); for (; win_it != win_it_end && placed; ++win_it) { diff --git a/src/RowSmartPlacement.hh b/src/RowSmartPlacement.hh index 43dbf55c..7b54fc11 100644 --- a/src/RowSmartPlacement.hh +++ b/src/RowSmartPlacement.hh @@ -28,7 +28,7 @@ class RowSmartPlacement: public PlacementStrategy { public: - bool placeWindow(const std::vector &windowlist, + bool placeWindow(const std::list &windowlist, const FluxboxWindow &win, int &place_x, int &place_y); }; diff --git a/src/Screen.cc b/src/Screen.cc index b0575f3a..d843a531 100644 --- a/src/Screen.cc +++ b/src/Screen.cc @@ -31,7 +31,6 @@ #include "Keys.hh" #include "Window.hh" #include "Workspace.hh" -#include "Netizen.hh" #include "Layer.hh" #include "FocusControl.hh" @@ -287,9 +286,10 @@ BScreen::ScreenResource::ScreenResource(FbTk::ResourceManager &rm, 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 @@ BScreen::ScreenResource::ScreenResource(FbTk::ResourceManager &rm, 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 @@ BScreen::ScreenResource::ScreenResource(FbTk::ResourceManager &rm, 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 @@ BScreen::BScreen(FbTk::ResourceManager &rm, 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 @@ BScreen::BScreen(FbTk::ResourceManager &rm, 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 @@ BScreen::BScreen(FbTk::ResourceManager &rm, } 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 @@ BScreen::~BScreen() { 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 @@ BScreen::~BScreen() { 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 @@ void BScreen::propertyNotify(Atom atom) { } 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 @@ void BScreen::buttonPressEvent(XButtonEvent &be) { 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 &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 @@ void BScreen::cycleFocus(int options, bool reverse) { 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 @@ void BScreen::cycleFocus(int options, bool reverse) { 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, pat, reverse); - focusControl().cycleFocus(*win_list, options, 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 @@ void BScreen::removeClient(WinClient &client) { 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); @@ -1134,8 +1201,6 @@ int BScreen::addWorkspace() { saveWorkspaces(m_workspaces_list.size()); - updateNetizenWorkspaceCount(); - return m_workspaces_list.size(); } @@ -1163,7 +1228,6 @@ int BScreen::removeLastWorkspace() { //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,14 +1289,15 @@ void BScreen::changeWorkspaceID(unsigned int id) { 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 @@ void BScreen::sendToWorkspace(unsigned int id, FluxboxWindow *win, bool changeWS 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::sendToWorkspace(unsigned int id, FluxboxWindow *win, bool changeWS } -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 @@ FluxboxWindow *BScreen::createWindow(Window client) { delete win; return 0; } - - Workspace *workspace = getWorkspace(win->workspaceNumber()); - if (workspace && !Fluxbox::instance()->isStartup()) - workspace->checkGrouping(*win); } } @@ -1559,7 +1506,7 @@ FluxboxWindow *BScreen::createWindow(WinClient &client) { // 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 @@ void BScreen::reassociateWindow(FluxboxWindow *w, unsigned int wkspc_id, 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(); } } @@ -1775,6 +1714,15 @@ void BScreen::setupConfigmenu(FbTk::Menu &menu) { 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(name() + ".focusNewWindows"), + saverc_cmd)); + } catch (FbTk::ResourceException e) { + cerr<insert(new BoolMenuItem(_FB_XTEXT(Configmenu, AutoRaise, "Auto Raise", @@ -1788,6 +1736,31 @@ void BScreen::setupConfigmenu(FbTk::Menu &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 @@ void BScreen::setupConfigmenu(FbTk::Menu &menu) { 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 >(_FB_XTEXT(Configmenu, ExternalTabWidth, @@ -1908,18 +1884,6 @@ void BScreen::setupConfigmenu(FbTk::Menu &menu) { "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(name() + ".focusNewWindows"), - saverc_cmd); - } catch (FbTk::ResourceException e) { - cerr< Rootmenus; - typedef std::list Netizens; typedef std::list > Configmenus; Rootmenus m_rootmenu_list; - Netizens m_netizen_list; Configmenus m_configmenu_list; Icons m_icon_list; @@ -558,21 +549,22 @@ private: std::auto_ptr 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 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 default_deco; FbTk::Resource rootcommand; FbTk::Resource resize_model; FbTk::Resource tab_placement; FbTk::Resource windowmenufile; + FbTk::Resource typing_delay; FbTk::Resource follow_model, user_follow_model; bool ordered_dither; FbTk::Resource workspaces, edge_snap_threshold, focused_alpha, @@ -586,6 +578,8 @@ private: FbTk::Resource scroll_action; FbTk::Resource scroll_reverse; FbTk::Resource allow_remote_actions; + FbTk::Resource clientmenu_use_pixmap; + FbTk::Resource tabs_use_pixmap; FbTk::Resource max_over_tabs; FbTk::Resource default_internal_tabs; diff --git a/src/ScreenPlacement.cc b/src/ScreenPlacement.cc index d9f8df27..d6144888 100644 --- a/src/ScreenPlacement.cc +++ b/src/ScreenPlacement.cc @@ -25,6 +25,7 @@ #include "RowSmartPlacement.hh" +#include "MinOverlapPlacement.hh" #include "UnderMousePlacement.hh" #include "ColSmartPlacement.hh" #include "CascadePlacement.hh" @@ -57,7 +58,7 @@ ScreenPlacement::ScreenPlacement(BScreen &screen): { } -bool ScreenPlacement::placeWindow(const std::vector &windowlist, +bool ScreenPlacement::placeWindow(const std::list &windowlist, const FluxboxWindow &win, int &place_x, int &place_y) { @@ -73,6 +74,10 @@ bool ScreenPlacement::placeWindow(const std::vector &windowlist 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())); break; @@ -143,6 +148,10 @@ void FbTk::Resource::setFromString(const char *(*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 @@ std::string FbTk::Resource::getString() const 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: diff --git a/src/ScreenPlacement.hh b/src/ScreenPlacement.hh index be007ebd..79d6c21c 100644 --- a/src/ScreenPlacement.hh +++ b/src/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 @@ public: virtual ~ScreenPlacement() {} /// placeWindow is guaranteed to succeed, ignore return value /// @return true - bool placeWindow(const std::vector &windowlist, + bool placeWindow(const std::list &windowlist, const FluxboxWindow &window, int &place_x, int &place_y); diff --git a/src/Slit.cc b/src/Slit.cc index a8e95a08..b18dddcb 100644 --- a/src/Slit.cc +++ b/src/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,15 +496,9 @@ void Slit::addClient(Window w) { 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 } else { @@ -588,8 +581,6 @@ void Slit::removeClient(SlitClient *client, bool remap, bool destroy) { 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(); diff --git a/src/Toolbar.cc b/src/Toolbar.cc index b5ad9678..54ee2393 100644 --- a/src/Toolbar.cc +++ b/src/Toolbar.cc @@ -33,6 +33,7 @@ #include "ToolbarTheme.hh" #include "fluxbox.hh" +#include "Keys.hh" #include "Screen.hh" #include "IntResMenuItem.hh" #include "BoolMenuItem.hh" @@ -279,6 +280,8 @@ Toolbar::Toolbar(BScreen &scrn, FbTk::XLayer &layer, size_t width): 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(BScreen &scrn, FbTk::XLayer &layer, size_t width): } 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::reconfigure() { 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; @@ -547,25 +556,6 @@ void Toolbar::buttonPressEvent(XButtonEvent &be) { } - -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 ¬_used) { if (! doAutoHide()) { if (isHidden()) diff --git a/src/Toolbar.hh b/src/Toolbar.hh index 5ac21144..243ce52b 100644 --- a/src/Toolbar.hh +++ b/src/Toolbar.hh @@ -88,7 +88,6 @@ public: */ //@{ void buttonPressEvent(XButtonEvent &be); - void buttonReleaseEvent(XButtonEvent &be); void enterNotifyEvent(XCrossingEvent &ce); void leaveNotifyEvent(XCrossingEvent &ce); void exposeEvent(XExposeEvent &ee); diff --git a/src/UnderMousePlacement.cc b/src/UnderMousePlacement.cc index 3af29753..e601e775 100644 --- a/src/UnderMousePlacement.cc +++ b/src/UnderMousePlacement.cc @@ -27,7 +27,7 @@ #include "Screen.hh" #include "Window.hh" -bool UnderMousePlacement::placeWindow(const std::vector &list, +bool UnderMousePlacement::placeWindow(const std::list &list, const FluxboxWindow &win, int &place_x, int &place_y) { diff --git a/src/UnderMousePlacement.hh b/src/UnderMousePlacement.hh index d89133cd..7f95e0cb 100644 --- a/src/UnderMousePlacement.hh +++ b/src/UnderMousePlacement.hh @@ -28,7 +28,7 @@ class UnderMousePlacement: public PlacementStrategy { public: - bool placeWindow(const std::vector &windowlist, + bool placeWindow(const std::list &windowlist, const FluxboxWindow &win, int &place_x, int &place_y); }; diff --git a/src/WinButton.cc b/src/WinButton.cc index f690f938..cdfb8b5b 100644 --- a/src/WinButton.cc +++ b/src/WinButton.cc @@ -321,15 +321,15 @@ void WinButton::update(FbTk::Subject *subj) { 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(); diff --git a/src/WinClient.cc b/src/WinClient.cc index 989088bf..d75d6eba 100644 --- a/src/WinClient.cc +++ b/src/WinClient.cc @@ -25,6 +25,7 @@ #include "Window.hh" #include "fluxbox.hh" +#include "FocusControl.hh" #include "Screen.hh" #include "FbAtoms.hh" @@ -62,7 +63,8 @@ using std::dec; 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 @@ WinClient::WinClient(Window win, BScreen &screen, FluxboxWindow *fbwin):FbTk::Fb 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 @@ WinClient::~WinClient() { 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 @@ WinClient::~WinClient() { s_transient_wait.erase(window()); - screen().removeNetizen(window()); - if (window_group != 0) { fluxbox->removeGroupSearch(window_group); window_group = 0; @@ -169,13 +162,8 @@ WinClient::~WinClient() { 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 @@ void WinClient::updateWMClassHint() { #ifdef DEBUG cerr<<"WinClient: Failed to read class hint!"<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 @@ void WinClient::updateIconTitle() { 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; - XFreeStringList(list); - } else + 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 : ""; 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::saveBlackboxAttribs(FluxboxWindow::BlackboxAttributes &blackbox_ } 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 @@ void WinClient::updateWMHints() { 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 @@ void WinClient::clearStrut() { } 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 @@ void WinClient::updateWMProtocols() { // 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. "< TransientList; // this structure only contains 3 elements... the Motif 2.0 structure contains @@ -69,7 +70,6 @@ public: /// updates transient window information void updateTransientInfo(); - void updateBlackboxHints(); void updateMWMHints(); void updateWMHints(); void updateWMNormalHints(); @@ -78,6 +78,9 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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; /** @@ -172,15 +153,6 @@ public: 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 }; private: @@ -192,8 +164,6 @@ private: // 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,22 +171,13 @@ private: 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 // (used if transient_for FbWindow was created after transient) diff --git a/src/WinClientUtil.cc b/src/WinClientUtil.cc deleted file mode 100644 index a6460a28..00000000 --- a/src/WinClientUtil.cc +++ /dev/null @@ -1,32 +0,0 @@ -#include "WinClientUtil.hh" -#include "WinClient.hh" - -#include - -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; -} - -} - - diff --git a/src/WinClientUtil.hh b/src/WinClientUtil.hh deleted file mode 100644 index 8ad0a036..00000000 --- a/src/WinClientUtil.hh +++ /dev/null @@ -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 diff --git a/src/Window.cc b/src/Window.cc index 8bf728fd..a5cf6fdf 100644 --- a/src/Window.cc +++ b/src/Window.cc @@ -42,8 +42,8 @@ #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 @@ void raiseFluxboxWindow(FluxboxWindow &win) { 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 @@ void lowerFluxboxWindow(FluxboxWindow &win) { lowerFluxboxWindow(*(*it)->fbwindow()); } - win.screen().updateNetizenWindowLower(win.clientWindow()); win.layerItem().lower(); win.oplock = false; @@ -208,7 +206,6 @@ void tempRaiseFluxboxWindow(FluxboxWindow &win) { 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 @@ FluxboxWindow::FluxboxWindow(WinClient &client, FbWinFrameTheme &tm, 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 @@ FluxboxWindow::~FluxboxWindow() { } } - // deal with extra menus + if (!screen().isShuttingdown()) + screen().focusControl().removeWindow(*this); + #ifdef DEBUG cerr<<__FILE__<<"("<<__LINE__<<"): ~FluxboxWindow("<getBlackboxHint() != 0) - updateBlackboxHintsFromClient(*m_client); - else - updateMWMHintsFromClient(*m_client); + updateMWMHintsFromClient(*m_client); //!! // fetch client size and placement @@ -516,10 +518,11 @@ void FluxboxWindow::init() { 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 @@ void FluxboxWindow::init() { 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 @@ void FluxboxWindow::attachClient(WinClient &client, int x, int y) { 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 @@ void FluxboxWindow::attachClient(WinClient &client, int x, int y) { 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 @@ void FluxboxWindow::attachClient(WinClient &client, int x, int y) { 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 @@ bool FluxboxWindow::removeClient(WinClient &client) { 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 @@ bool FluxboxWindow::setCurrentClient(WinClient &client, bool setinput) { 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 @@ bool FluxboxWindow::setCurrentClient(WinClient &client, bool setinput) { #endif // DEBUG // frame focused doesn't necessarily mean input focused frame().setLabelButtonFocus(*button); + frame().setShapingClient(&client, false); - 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); -} - -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 @@ void FluxboxWindow::reconfigure() { 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 @@ void FluxboxWindow::updateFunctions() { 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(hint->decoration), false); - } -} - void FluxboxWindow::move(int x, int y) { moveResize(x, y, frame().width(), frame().height()); } @@ -1262,7 +1220,7 @@ void FluxboxWindow::moveResize(int new_x, int new_y, 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 @@ void FluxboxWindow::moveResizeForClient(int new_x, int new_y, 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::moveResizeForClient(int new_x, int new_y, } +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 @@ bool FluxboxWindow::setInputFocus() { 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 @@ void FluxboxWindow::hide(bool interrupt_moving) { 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() { @@ -1427,13 +1436,8 @@ 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 @@ void FluxboxWindow::iconify() { 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 @@ void FluxboxWindow::deiconify(bool reassoc, bool do_raise) { 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,9 +1503,11 @@ void FluxboxWindow::deiconify(bool reassoc, bool do_raise) { 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; @@ -1522,18 +1515,6 @@ void FluxboxWindow::deiconify(bool reassoc, bool do_raise) { raise(); } -/** - Set window in withdrawn state -*/ -void FluxboxWindow::withdraw(bool interrupt_moving) { -#ifdef DEBUG - cerr<<"FluxboxWindow::"<<__FUNCTION__<<": this = "<transientFor() && m_client != m_client->transientFor()->transientList().back()) { @@ -1884,15 +1839,14 @@ void FluxboxWindow::lower() { // 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 @@ void FluxboxWindow::moveToLayer(int layernum, bool force) { // 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 @@ void FluxboxWindow::moveToLayer(int layernum, bool force) { 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 @@ void FluxboxWindow::setIconHidden(bool value) { // 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("<focusSig().notify(); @@ -2071,24 +2015,34 @@ void FluxboxWindow::saveBlackboxAttribs() { 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 @@ void FluxboxWindow::restoreAttributes() { } 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 @@ void FluxboxWindow::restoreAttributes() { 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 @@ void FluxboxWindow::restoreAttributes() { /** 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 @@ void FluxboxWindow::showMenu(int menu_x, int menu_y, WinClient *client) { else if (menu_x + static_cast(menu().width()) >= static_cast(screen().maxRight(head))) menu_x = screen().maxRight(head) - menu().width() - 1; - if (client && (client->fbwindow() == this)) - WindowCmd::setClient(client); - else - WindowCmd::setWindow(this); - + WindowCmd::setWindow(this); menu().move(menu_x, menu_y); menu().show(); menu().raise(); @@ -2238,34 +2160,13 @@ void FluxboxWindow::popupMenu() { 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(), labelbutton), - Compose(mem_fun(&TextButton::window), - Select2nd()))); - - // 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(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 @@ void FluxboxWindow::mapRequestEvent(XMapRequestEvent &re) { // 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; -#ifdef DEBUG - cerr<<"FluxboxWindow::mapNotifyEvent: " - <<"ne.override_redirect = "<grab(); - if (! client->validateClient()) - return; + if (ne.override_redirect || !isVisible() || !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"<ungrab(); + // we use m_focused as a signal that this should be focused when mapped + if (m_focused) { + m_focused = false; + focus(); } + } /** @@ -2442,15 +2346,16 @@ void FluxboxWindow::propertyNotifyEvent(WinClient &client, Atom atom) { 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 @@ void FluxboxWindow::propertyNotifyEvent(WinClient &client, Atom atom) { functions.resize = true; } - if (changed) + if (changed) { setupWindow(); + applyDecorations(); + } } moveResize(frame().x(), frame().y(), @@ -2514,14 +2421,6 @@ void FluxboxWindow::propertyNotifyEvent(WinClient &client, Atom atom) { 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 @@ void FluxboxWindow::configureRequestEvent(XConfigureRequestEvent &cr) { 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 @@ void FluxboxWindow::configureRequestEvent(XConfigureRequestEvent &cr) { case Above: case TopIf: default: - setCurrentClient(*client, focused); + setCurrentClient(*client, m_focused); raise(); break; @@ -2638,6 +2536,41 @@ void FluxboxWindow::configureRequestEvent(XConfigureRequestEvent &cr) { } +// 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 @@ void FluxboxWindow::buttonPressEvent(XButtonEvent &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::buttonPressEvent(XButtonEvent &be) { 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 @@ void FluxboxWindow::motionNotifyEvent(XMotionEvent &me) { 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 @@ void FluxboxWindow::enterNotifyEvent(XCrossingEvent &ev) { XCheckIfEvent(display, &dummy, queueScanner, (char *) &sa); if ((!sa.leave || sa.inferior) && !screen().focusControl().isCycling() ) { - setInputFocus(); + focus(); } } } @@ -3060,61 +2992,6 @@ void FluxboxWindow::leaveNotifyEvent(XCrossingEvent &ev) { //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 @@ void FluxboxWindow::toggleDecoration() { 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 @@ void FluxboxWindow::stopMoving(bool interrupted) { if (m_workspace_number != screen().currentWorkspaceID()) { screen().reassociateWindow(this, screen().currentWorkspaceID(), true); frame().show(); - setInputFocus(); + focus(); } } fluxbox->ungrab(); @@ -3332,7 +3212,7 @@ void FluxboxWindow::resumeMoving() { if (m_workspace_number == screen().currentWorkspaceID()) { frame().show(); - setInputFocus(); + focus(); } FbTk::App::instance()->sync(false); @@ -3397,7 +3277,7 @@ void FluxboxWindow::doSnapping(int &orig_left, int &orig_top) { // 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 @@ void FluxboxWindow::doSnapping(int &orig_left, int &orig_top) { 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 @@ void FluxboxWindow::startResizing(int x, int y, ResizeDirection dir) { 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(); } - -const bool FluxboxWindow::usePixmap() const { - return m_client ? m_client->usePixmap() : false; +bool FluxboxWindow::acceptsFocus() const { + return (m_client ? m_client->acceptsFocus() : false); } -const bool FluxboxWindow::useMask() const { return m_client->useMask(); } +const FbTk::PixmapWithMask &FluxboxWindow::icon() const { + return (m_client ? m_client->icon() : m_icon); +} const FbTk::Menu &FluxboxWindow::menu() const { return screen().windowMenu(); @@ -3739,17 +3621,19 @@ Window FluxboxWindow::clientWindow() const { 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 string &FluxboxWindow::iconTitle() const { - static string empty_string; - if (m_client == 0) - return empty_string; - return m_client->iconTitle(); +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); +} + +std::string FluxboxWindow::getWMRole() const { + return (m_client ? m_client->getWMRole() : "FluxboxWindow"); } int FluxboxWindow::normalX() const { @@ -3780,74 +3664,6 @@ unsigned int FluxboxWindow::normalHeight() const { 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(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 @@ void FluxboxWindow::moveResizeClient(WinClient &client, int x, int y, 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 @@ void FluxboxWindow::sendConfigureNotify(bool send_to_netizens) { 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 @@ void FluxboxWindow::updateButtons() { dir[i], frame().titlebar(), 0, 0, 10, 10); - hintSig().attach(winbtn); titleSig().attach(winbtn); winbtn->setOnClick(show_menu_cmd); break; @@ -4242,14 +4040,15 @@ void FluxboxWindow::ungrabPointer(Time time) { 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 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(); evm.add(*this, btn->window()); // we take care of button events for this @@ -4259,24 +4058,17 @@ void FluxboxWindow::associateClient(WinClient &client) { 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; diff --git a/src/Window.hh b/src/Window.hh index 92431abc..d0012844 100644 --- a/src/Window.hh +++ b/src/Window.hh @@ -32,11 +32,13 @@ #include "FbTk/EventHandler.hh" #include "FbTk/XLayerItem.hh" #include "FbWinFrame.hh" +#include "Focusable.hh" #include "WinButton.hh" #include #include +#include #include #include #include @@ -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 @@ public: /// 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: */ //@{ void handleEvent(XEvent &event); + void keyPressEvent(XKeyEvent &ke); void buttonPressEvent(XButtonEvent &be); void buttonReleaseEvent(XButtonEvent &be); void motionNotifyEvent(XMotionEvent &me); @@ -291,7 +346,6 @@ public: void leaveNotifyEvent(XCrossingEvent &ev); //@} - void setDecoration(Decoration decoration, bool apply = true); void applyDecorations(bool initial = false); void toggleDecoration(); @@ -333,7 +387,6 @@ public: 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 @@ public: 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 @@ public: 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 &iconTitle() const; + const std::string &getWMClassName() const; + const std::string &getWMClassClass() const; + std::string getWMRole() 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 @@ public: 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 @@ private: /// 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 @@ private: 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 @@ private: 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 @@ private: // 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 @@ private: 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 @@ private: ClientList m_clientlist; WinClient *m_client; ///< current client - typedef std::map Client2ButtonMap; + typedef std::map Client2ButtonMap; Client2ButtonMap m_labelbuttons; // just temporary solution @@ -564,14 +606,14 @@ private: 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 }; diff --git a/src/Workspace.cc b/src/Workspace.cc index 2f575aff..cce8dfeb 100644 --- a/src/Workspace.cc +++ b/src/Workspace.cc @@ -30,13 +30,10 @@ #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 @@ #endif #include -#include -#include using std::string; -using std::vector; -using std::ifstream; #ifdef DEBUG +#include 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::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 @@ void Workspace::addWindow(FluxboxWindow &w, bool place) { 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 @@ int Workspace::removeWindow(FluxboxWindow *w, bool still_alive) { 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 @@ void Workspace::hideAll(bool interrupt_moving) { 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. ("<winClient().getWMClassName()<isGroupable() || (*wit)->winClient().fbwindow() == &win) - break; // try next name -#ifdef DEBUG - cerr<<__FILE__<<"("<<__FUNCTION__<<"): window ("<<*wit<<") attaching window ("<<&win<<")"<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 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::shutdown() { } 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) { diff --git a/src/Workspace.hh b/src/Workspace.hh index b7c29516..3f865ed0 100644 --- a/src/Workspace.hh +++ b/src/Workspace.hh @@ -25,30 +25,24 @@ #ifndef WORKSPACE_HH #define WORKSPACE_HH +#include "ClientMenu.hh" - -#include "FbMenu.hh" - -#include "FbTk/MultLayers.hh" -#include "FbTk/Observer.hh" #include "FbTk/NotCopyable.hh" #include -#include #include 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 Windows; + typedef std::list 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 @@ public: 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 Group; - typedef std::vector 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 diff --git a/src/WorkspaceCmd.cc b/src/WorkspaceCmd.cc index 9859dd64..e7d92ee9 100644 --- a/src/WorkspaceCmd.cc +++ b/src/WorkspaceCmd.cc @@ -41,16 +41,90 @@ #include #include +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() { @@ -250,19 +324,6 @@ void ShowDesktopCmd::execute() { 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() { BScreen *screen = Fluxbox::instance()->mouseScreen(); if (screen == 0) diff --git a/src/WorkspaceCmd.hh b/src/WorkspaceCmd.hh index 31a6ea45..8053dc90 100644 --- a/src/WorkspaceCmd.hh +++ b/src/WorkspaceCmd.hh @@ -26,23 +26,73 @@ #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 cmd, const std::string &pat): + m_cmd(cmd), m_pat(pat.c_str()) { } + + void execute(); + +private: + FbTk::RefCount 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 { @@ -114,11 +164,6 @@ public: void execute(); }; -class MinimizeLayerCmd: public FbTk::Command { -public: - void execute(); -}; - class CloseAllWindowsCmd: public FbTk::Command { public: void execute(); diff --git a/src/WorkspaceMenu.hh b/src/WorkspaceMenu.hh index 2a425a3c..1b06dc61 100644 --- a/src/WorkspaceMenu.hh +++ b/src/WorkspaceMenu.hh @@ -28,12 +28,21 @@ 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); }; diff --git a/src/Xutil.cc b/src/Xutil.cc index c2fb71fc..6a120714 100644 --- a/src/Xutil.cc +++ b/src/Xutil.cc @@ -56,8 +56,8 @@ FbTk::FbString getWMName(Window window) { XTextProperty text_prop; text_prop.value = 0; - char **list; - int num; + char **list = 0; + int num = 0; _FB_USES_NLS; string name; @@ -66,15 +66,16 @@ FbTk::FbString getWMName(Window window) { 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(*list)); - XFreeStringList(list); - } else + 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) : ""; diff --git a/src/fluxbox.cc b/src/fluxbox.cc index 8b9e39a0..80d055b9 100644 --- a/src/fluxbox.cc +++ b/src/fluxbox.cc @@ -206,7 +206,6 @@ Fluxbox::Fluxbox(int argc, char **argv, const char *dpy_name, const char *rcfile 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 @@ Fluxbox::Fluxbox(int argc, char **argv, const char *dpy_name, const char *rcfile #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 screens; int i; @@ -415,10 +419,6 @@ Fluxbox::Fluxbox(int argc, char **argv, const char *dpy_name, const char *rcfile 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 @@ void Fluxbox::eventLoop() { 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"< config_version(m_resourcemanager, 0, "session.configVersion", "Session.ConfigVersion"); if (*config_version < CONFIG_VERSION) { @@ -1019,41 +1022,6 @@ void Fluxbox::handleClientMessage(XClientMessageEvent &ce) { 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(ce.data.l[4]); - win->changeBlackboxHints(net); - } } else { WinClient *winclient = searchWindow(ce.window); BScreen *screen = searchScreen(ce.window); @@ -1117,73 +1085,92 @@ void Fluxbox::handleSignal(int signum) { 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(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(changedsub); + fbwin = winsub->win().fbwindow(); + if (typeid(winsub->win()) == typeid(WinClient)) + client = dynamic_cast(&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 - - for (AtomHandlerContainerIt it= m_atomhandler.begin(); - it != m_atomhandler.end(); ++it) { - if ((*it).first->update()) - (*it).first->updateLayer(win); - } - } else if ((&(win.dieSig())) == changedsub) { // window death signal - - 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 = win.screen(); - scr.removeWindow(&win); - if (FocusControl::focusedFbWindow() == &win) - FocusControl::setFocusedFbWindow(0); - - } 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<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); } + 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 (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); + } + + // 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); + } + + BScreen &screen = client->screen(); + + 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(changedsub); BScreen &screen = subj->screen(); @@ -1218,37 +1205,6 @@ void Fluxbox::update(FbTk::Subject *changedsub) { (*it).first->updateClientList(screen); } } - } else if (typeid(*changedsub) == typeid(WinClient::WinClientSubj)) { - - WinClient::WinClientSubj *subj = dynamic_cast(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 @@ string Fluxbox::getRcFilename() { } /// 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 @@ void Fluxbox::load_rc() { 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<updateNetizenWindowFocus(); for (AtomHandlerContainerIt it= m_atomhandler.begin(); it != m_atomhandler.end(); it++) { (*it).first->updateFocusedWindow(*screen, (FocusControl::focusedWindow() ? @@ -1745,7 +1694,6 @@ void Fluxbox::updateFocusedWindow(BScreen *screen, BScreen *old_screen) { } 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); diff --git a/src/fluxbox.hh b/src/fluxbox.hh index 04189016..625a9062 100644 --- a/src/fluxbox.hh +++ b/src/fluxbox.hh @@ -196,7 +196,7 @@ public: 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 @@ private: FbTk::Resource 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 m_rc_tabs_attach_area; diff --git a/util/fluxbox-update_configs.cc b/util/fluxbox-update_configs.cc index 8cfe8ef4..2dc5eb69 100644 --- a/util/fluxbox-update_configs.cc +++ b/util/fluxbox-update_configs.cc @@ -38,23 +38,17 @@ #define _GNU_SOURCE #endif // _GNU_SOURCE -#ifdef HAVE_CSTDIO - #include -#else - #include -#endif -#ifdef HAVE_CSTDLIB - #include -#else - #include -#endif #ifdef HAVE_CSTRING #include #else #include #endif + #include #include +#include +#include +#include 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; + FbTk::Resource rc_keyfile(rm, "~/.fluxbox/keys", + "session.keyFile", "Session.KeyFile"); + FbTk::Resource rc_appsfile(rm, "~/.fluxbox/apps", + "session.appsFile", "Session.AppsFile"); + + string appsfilename = FbTk::StringUtil::expandFilename(*rc_appsfile); + string keyfilename = FbTk::StringUtil::expandFilename(*rc_keyfile); + if (old_version < 1) { // add mouse events to keys file - FbTk::Resource rc_keyfile(rm, DEFAULTKEYSFILE, - "session.keyFile", "Session.KeyFile"); - string keyfilename = FbTk::StringUtil::expandFilename(*rc_keyfile); - // 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 - - ifstream in_keyfile(keyfilename.c_str()); - string whole_keyfile = ""; - - 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 @@ int run_updates(int old_version, FbTk::ResourceManager rm) { "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 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 lines; + FbTk::StringUtil::stringtok(lines, whole_groupfile, "\n"); + + list::iterator line_it = lines.begin(); + list::iterator line_it_end = lines.end(); + for (; line_it != line_it_end; ++line_it) { + new_appsfile += "[group] (workspace=[current])\n"; + + list apps; + FbTk::StringUtil::stringtok(apps, *line_it); + + list::iterator it = apps.begin(); + list::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 rc_wheeling(rm, "Off", + "session.screen0.iconbar.wheelMode", + "Session.Screen0.Iconbar.WheelMode"); + FbTk::Resource rc_screen(rm, true, + "session.screen0.desktopwheeling", + "Session.Screen0.DesktopWheeling"); + FbTk::Resource 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 style_filenames; int i = 1; pid_t fb_pid = 0; @@ -184,8 +245,10 @@ int main(int argc, char **argv) { 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 @@ int main(int argc, char **argv) { return 0; } + +static set modified_files; +// we may want to put a size limit on this cache, so it doesn't grow too big +static map 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::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::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::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::iterator it = modified_files.begin(); + set::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(); +}