mirror of
https://github.com/edeproject/ede.git
synced 2023-08-10 21:13:03 +03:00
1883 lines
66 KiB
C++
1883 lines
66 KiB
C++
|
//
|
||
|
// Config.cc for pekwm
|
||
|
// Copyright © 2002-2009 Claes Nästén <me@pekdon.net>
|
||
|
//
|
||
|
// This program is licensed under the GNU GPL.
|
||
|
// See the LICENSE file for more information.
|
||
|
//
|
||
|
|
||
|
#ifdef HAVE_CONFIG_H
|
||
|
#include "config.h"
|
||
|
#endif // HAVE_CONFIG_H
|
||
|
|
||
|
#include "Config.hh"
|
||
|
|
||
|
#include "Compat.hh"
|
||
|
#include "Util.hh"
|
||
|
#include "PScreen.hh" // for DPY in keyconfig code
|
||
|
|
||
|
#include <iostream>
|
||
|
#include <fstream>
|
||
|
|
||
|
#include <cstdlib>
|
||
|
|
||
|
extern "C" {
|
||
|
#include <unistd.h>
|
||
|
#include <sys/types.h>
|
||
|
#include <sys/stat.h>
|
||
|
}
|
||
|
|
||
|
using std::cerr;
|
||
|
using std::endl;
|
||
|
using std::string;
|
||
|
using std::wstring;
|
||
|
using std::list;
|
||
|
using std::map;
|
||
|
using std::vector;
|
||
|
using std::pair;
|
||
|
using std::ifstream;
|
||
|
using std::ofstream;
|
||
|
using std::strtol;
|
||
|
using std::getenv;
|
||
|
|
||
|
Config* Config::_instance = 0;
|
||
|
|
||
|
const int FRAME_MASK =
|
||
|
FRAME_OK|FRAME_BORDER_OK|CLIENT_OK|WINDOWMENU_OK|
|
||
|
KEYGRABBER_OK|BUTTONCLICK_OK;
|
||
|
const int ANY_MASK =
|
||
|
KEYGRABBER_OK|FRAME_OK|FRAME_BORDER_OK|CLIENT_OK|ROOTCLICK_OK|
|
||
|
BUTTONCLICK_OK|WINDOWMENU_OK|ROOTMENU_OK|SCREEN_EDGE_OK;
|
||
|
|
||
|
/**
|
||
|
* Parse width and height limits.
|
||
|
*/
|
||
|
bool
|
||
|
SizeLimits::parse(const std::string &minimum, const std::string &maximum)
|
||
|
{
|
||
|
return (parseLimit(minimum, _limits[WIDTH_MIN], _limits[HEIGHT_MIN])
|
||
|
&& parseLimit(maximum, _limits[WIDTH_MAX], _limits[HEIGHT_MAX]));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Parse single limit.
|
||
|
*/
|
||
|
bool
|
||
|
SizeLimits::parseLimit(const std::string &limit, unsigned int &min, unsigned int &max)
|
||
|
{
|
||
|
bool status = false;
|
||
|
vector<string> tokens;
|
||
|
if ((Util::splitString(limit, tokens, "x", 2, true)) == 2) {
|
||
|
min = strtol(tokens[0].c_str(), 0, 10);
|
||
|
max = strtol(tokens[1].c_str(), 0, 10);
|
||
|
status = true;
|
||
|
} else {
|
||
|
min = 0;
|
||
|
max = 0;
|
||
|
}
|
||
|
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
//! @brief Constructor for Config class
|
||
|
Config::Config(void) :
|
||
|
_moveresize_edgeattract(0), _moveresize_edgeresist(0),
|
||
|
_moveresize_woattract(0), _moveresize_woresist(0),
|
||
|
_moveresize_opaquemove(0), _moveresize_opaqueresize(0),
|
||
|
_screen_workspaces(4), _screen_pixmap_cache_size(20),
|
||
|
_screen_workspaces_per_row(0), _screen_workspace_name_default(L"Workspace"),
|
||
|
_screen_edge_indent(false),
|
||
|
_screen_doubleclicktime(250), _screen_fullscreen_above(true),
|
||
|
_screen_fullscreen_detect(true),
|
||
|
_screen_showframelist(true),
|
||
|
_screen_show_status_window(true), _screen_show_status_window_on_root(false),
|
||
|
_screen_show_client_id(false),
|
||
|
_screen_show_workspace_indicator(500), _screen_workspace_indicator_scale(16),
|
||
|
#ifdef OPACITY
|
||
|
_screen_workspace_indicator_opacity(EWMH_OPAQUE_WINDOW),
|
||
|
#endif // OPACITY
|
||
|
_screen_place_new(true), _screen_focus_new(false),
|
||
|
_screen_focus_new_child(true), _screen_honour_randr(true),
|
||
|
_screen_honour_aspectratio(true),
|
||
|
_screen_placement_row(false),
|
||
|
_screen_placement_ltr(true), _screen_placement_ttb(true),
|
||
|
_screen_placement_offset_x(0), _screen_placement_offset_y(0),
|
||
|
_screen_client_unique_name(true),
|
||
|
_screen_client_unique_name_pre(" #"), _screen_client_unique_name_post(""),
|
||
|
_screen_report_all_clients(false),
|
||
|
_menu_select_mask(0), _menu_enter_mask(0), _menu_exec_mask(0),
|
||
|
_menu_display_icons(true),
|
||
|
#ifdef OPACITY
|
||
|
_menu_focus_opacity(EWMH_OPAQUE_WINDOW),
|
||
|
_menu_unfocus_opacity(EWMH_OPAQUE_WINDOW),
|
||
|
#endif // OPACITY
|
||
|
_cmd_dialog_history_unique(true), _cmd_dialog_history_size(1024),
|
||
|
_cmd_dialog_history_file("~/.pekwm/history"), _cmd_dialog_history_save_interval(16),
|
||
|
_harbour_da_min_s(0), _harbour_da_max_s(0),
|
||
|
_harbour_ontop(true), _harbour_maximize_over(false),
|
||
|
_harbour_placement(TOP), _harbour_orientation(TOP_TO_BOTTOM), _harbour_head_nr(0)
|
||
|
#ifdef OPACITY
|
||
|
,_harbour_opacity(EWMH_OPAQUE_WINDOW)
|
||
|
#endif // OPACITY
|
||
|
{
|
||
|
if (_instance) {
|
||
|
throw string("Config, trying to create multiple instances");
|
||
|
}
|
||
|
_instance = this;
|
||
|
|
||
|
for (uint i = 0; i <= SCREEN_EDGE_NO; ++i) {
|
||
|
_screen_edge_sizes.push_back(0);
|
||
|
}
|
||
|
|
||
|
// fill parsing maps
|
||
|
_action_map[""] = pair<ActionType, uint>(ACTION_NO, 0);
|
||
|
_action_map["Focus"] = pair<ActionType, uint>(ACTION_FOCUS, ANY_MASK);
|
||
|
_action_map["UnFocus"] = pair<ActionType, uint>(ACTION_UNFOCUS, ANY_MASK);
|
||
|
|
||
|
_action_map["Set"] = pair<ActionType, uint>(ACTION_SET, ANY_MASK);
|
||
|
_action_map["Unset"] = pair<ActionType, uint>(ACTION_UNSET, ANY_MASK);
|
||
|
_action_map["Toggle"] = pair<ActionType, uint>(ACTION_TOGGLE, ANY_MASK);
|
||
|
|
||
|
_action_map["MaxFill"] = pair<ActionType, uint>(ACTION_MAXFILL, FRAME_MASK);
|
||
|
_action_map["GrowDirection"] = pair<ActionType, uint>(ACTION_GROW_DIRECTION, FRAME_MASK);
|
||
|
_action_map["Close"] = pair<ActionType, uint>(ACTION_CLOSE, FRAME_MASK);
|
||
|
_action_map["CloseFrame"] = pair<ActionType, uint>(ACTION_CLOSE_FRAME, FRAME_MASK);
|
||
|
_action_map["Kill"] = pair<ActionType, uint>(ACTION_KILL, FRAME_MASK);
|
||
|
_action_map["Raise"] = pair<ActionType, uint>(ACTION_RAISE, FRAME_MASK);
|
||
|
_action_map["Lower"] = pair<ActionType, uint>(ACTION_LOWER, FRAME_MASK);
|
||
|
_action_map["ActivateOrRaise"] = pair<ActionType, uint>(ACTION_ACTIVATE_OR_RAISE, FRAME_MASK);
|
||
|
_action_map["ActivateClientRel"] = pair<ActionType, uint>(ACTION_ACTIVATE_CLIENT_REL, FRAME_MASK);
|
||
|
_action_map["MoveClientRel"] = pair<ActionType, uint>(ACTION_MOVE_CLIENT_REL, FRAME_MASK);
|
||
|
_action_map["ActivateClient"] = pair<ActionType, uint>(ACTION_ACTIVATE_CLIENT, FRAME_MASK);
|
||
|
_action_map["ActivateClientNum"] = pair<ActionType, uint>(ACTION_ACTIVATE_CLIENT_NUM, KEYGRABBER_OK);
|
||
|
_action_map["Resize"] = pair<ActionType, uint>(ACTION_RESIZE, BUTTONCLICK_OK|CLIENT_OK|FRAME_OK|FRAME_BORDER_OK);
|
||
|
_action_map["Move"] = pair<ActionType, uint>(ACTION_MOVE, FRAME_OK|FRAME_BORDER_OK|CLIENT_OK);
|
||
|
_action_map["MoveResize"] = pair<ActionType, uint>(ACTION_MOVE_RESIZE, KEYGRABBER_OK);
|
||
|
_action_map["GroupingDrag"] = pair<ActionType, uint>(ACTION_GROUPING_DRAG, FRAME_OK|CLIENT_OK);
|
||
|
_action_map["WarpToWorkspace"] = pair<ActionType, uint>(ACTION_WARP_TO_WORKSPACE, SCREEN_EDGE_OK);
|
||
|
_action_map["MoveToEdge"] = pair<ActionType, uint>(ACTION_MOVE_TO_EDGE, KEYGRABBER_OK);
|
||
|
_action_map["NextFrame"] = pair<ActionType, uint>(ACTION_NEXT_FRAME, KEYGRABBER_OK|ROOTCLICK_OK|SCREEN_EDGE_OK);
|
||
|
_action_map["PrevFrame"] = pair<ActionType, uint>(ACTION_PREV_FRAME, KEYGRABBER_OK|ROOTCLICK_OK|SCREEN_EDGE_OK);
|
||
|
_action_map["NextFrameMRU"] = pair<ActionType, uint>(ACTION_NEXT_FRAME_MRU, KEYGRABBER_OK|ROOTCLICK_OK|SCREEN_EDGE_OK);
|
||
|
_action_map["PrevFrameMRU"] = pair<ActionType, uint>(ACTION_PREV_FRAME_MRU, KEYGRABBER_OK|ROOTCLICK_OK|SCREEN_EDGE_OK);
|
||
|
_action_map["FocusDirectional"] = pair<ActionType, uint>(ACTION_FOCUS_DIRECTIONAL, FRAME_MASK);
|
||
|
_action_map["AttachMarked"] = pair<ActionType, uint>(ACTION_ATTACH_MARKED, FRAME_MASK);
|
||
|
_action_map["AttachClientInNextFrame"] = pair<ActionType, uint>(ACTION_ATTACH_CLIENT_IN_NEXT_FRAME, FRAME_MASK);
|
||
|
_action_map["AttachClientInPrevFrame"] = pair<ActionType, uint>(ACTION_ATTACH_CLIENT_IN_PREV_FRAME, FRAME_MASK);
|
||
|
_action_map["FindClient"] = pair<ActionType, uint>(ACTION_FIND_CLIENT, ANY_MASK);
|
||
|
_action_map["GotoClientID"] = pair<ActionType, uint>(ACTION_GOTO_CLIENT_ID, ANY_MASK);
|
||
|
_action_map["Detach"] = pair<ActionType, uint>(ACTION_DETACH, FRAME_MASK);
|
||
|
_action_map["SendToWorkspace"] = pair<ActionType, uint>(ACTION_SEND_TO_WORKSPACE, ANY_MASK);
|
||
|
_action_map["GoToWorkspace"] = pair<ActionType, uint>(ACTION_GOTO_WORKSPACE, ANY_MASK );
|
||
|
_action_map["Exec"] = pair<ActionType, uint>(ACTION_EXEC, FRAME_MASK|ROOTMENU_OK|ROOTCLICK_OK|SCREEN_EDGE_OK);
|
||
|
_action_map["Reload"] = pair<ActionType, uint>(ACTION_RELOAD, KEYGRABBER_OK|ROOTMENU_OK);
|
||
|
_action_map["Restart"] = pair<ActionType, uint>(ACTION_RESTART, KEYGRABBER_OK|ROOTMENU_OK);
|
||
|
_action_map["RestartOther"] = pair<ActionType, uint>(ACTION_RESTART_OTHER, KEYGRABBER_OK|ROOTMENU_OK);
|
||
|
_action_map["Exit"] = pair<ActionType, uint>(ACTION_EXIT, KEYGRABBER_OK|ROOTMENU_OK);
|
||
|
_action_map["ShowCmdDialog"] = pair<ActionType, uint>(ACTION_SHOW_CMD_DIALOG, KEYGRABBER_OK|ROOTCLICK_OK|SCREEN_EDGE_OK|ROOTMENU_OK|WINDOWMENU_OK);
|
||
|
_action_map["ShowSearchDialog"] = pair<ActionType, uint>(ACTION_SHOW_SEARCH_DIALOG, KEYGRABBER_OK|ROOTCLICK_OK|SCREEN_EDGE_OK|ROOTMENU_OK|WINDOWMENU_OK);
|
||
|
_action_map["ShowMenu"] = pair<ActionType, uint>(ACTION_SHOW_MENU, FRAME_MASK|ROOTCLICK_OK|SCREEN_EDGE_OK|ROOTMENU_OK|WINDOWMENU_OK);
|
||
|
_action_map["HideAllMenus"] = pair<ActionType, uint>(ACTION_HIDE_ALL_MENUS, FRAME_MASK|ROOTCLICK_OK|SCREEN_EDGE_OK);
|
||
|
_action_map["SubMenu"] = pair<ActionType, uint>(ACTION_MENU_SUB, ROOTMENU_OK|WINDOWMENU_OK);
|
||
|
_action_map["Dynamic"] = pair<ActionType, uint>(ACTION_MENU_DYN, ROOTMENU_OK|WINDOWMENU_OK);
|
||
|
_action_map["SendKey"] = pair<ActionType, uint>(ACTION_SEND_KEY, ANY_MASK);
|
||
|
#ifdef OPACITY
|
||
|
_action_map["SetOpacity"] = pair<ActionType, uint>(ACTION_SET_OPACITY, FRAME_MASK);
|
||
|
#endif // OPACITY
|
||
|
|
||
|
_action_access_mask_map[""] = ACTION_ACCESS_NO;
|
||
|
_action_access_mask_map["MOVE"] = ACTION_ACCESS_MOVE;
|
||
|
_action_access_mask_map["RESIZE"] = ACTION_ACCESS_RESIZE;
|
||
|
_action_access_mask_map["ICONIFY"] = ACTION_ACCESS_MINIMIZE;
|
||
|
_action_access_mask_map["SHADE"] = ACTION_ACCESS_SHADE;
|
||
|
_action_access_mask_map["STICK"] = ACTION_ACCESS_STICK;
|
||
|
_action_access_mask_map["MAXIMIZEHORIZONTAL"] = ACTION_ACCESS_MAXIMIZE_HORZ;
|
||
|
_action_access_mask_map["MAXIMIZEVERTICAL"] = ACTION_ACCESS_MAXIMIZE_VERT;
|
||
|
_action_access_mask_map["FULLSCREEN"] = ACTION_ACCESS_FULLSCREEN;
|
||
|
_action_access_mask_map["SETWORKSPACE"] = ACTION_ACCESS_CHANGE_DESKTOP;
|
||
|
_action_access_mask_map["CLOSE"] = ACTION_ACCESS_CLOSE;
|
||
|
|
||
|
_placement_map[""] = PLACE_NO;
|
||
|
_placement_map["SMART"] = PLACE_SMART;
|
||
|
_placement_map["MOUSENOTUNDER"] = PLACE_MOUSE_NOT_UNDER;
|
||
|
_placement_map["MOUSECENTERED"] = PLACE_MOUSE_CENTERED;
|
||
|
_placement_map["MOUSETOPLEFT"] = PLACE_MOUSE_TOP_LEFT;
|
||
|
_placement_map["CENTEREDONPARENT"] = PLACE_CENTERED_ON_PARENT;
|
||
|
|
||
|
_edge_map[""] = NO_EDGE;
|
||
|
_edge_map["TOPLEFT"] = TOP_LEFT;
|
||
|
_edge_map["TOPEDGE"] = TOP_EDGE;
|
||
|
_edge_map["TOPCENTEREDGE"] = TOP_CENTER_EDGE;
|
||
|
_edge_map["TOPRIGHT"] = TOP_RIGHT;
|
||
|
_edge_map["BOTTOMRIGHT"] = BOTTOM_RIGHT;
|
||
|
_edge_map["BOTTOMEDGE"] = BOTTOM_EDGE;
|
||
|
_edge_map["BOTTOMCENTEREDGE"] = BOTTOM_CENTER_EDGE;
|
||
|
_edge_map["BOTTOMLEFT"] = BOTTOM_LEFT;
|
||
|
_edge_map["LEFTEDGE"] = LEFT_EDGE;
|
||
|
_edge_map["LEFTCENTEREDGE"] = LEFT_CENTER_EDGE;
|
||
|
_edge_map["RIGHTEDGE"] = RIGHT_EDGE;
|
||
|
_edge_map["RIGHTCENTEREDGE"] = RIGHT_CENTER_EDGE;
|
||
|
_edge_map["CENTER"] = CENTER;
|
||
|
|
||
|
_raise_map[""] = NO_RAISE;
|
||
|
_raise_map["ALWAYSRAISE"] = ALWAYS_RAISE;
|
||
|
_raise_map["ENDRAISE"] = END_RAISE;
|
||
|
_raise_map["NEVERRAISE"] = NEVER_RAISE;
|
||
|
|
||
|
_skip_map[""] = SKIP_NONE;
|
||
|
_skip_map["MENUS"] = SKIP_MENUS;
|
||
|
_skip_map["FOCUSTOGGLE"] = SKIP_FOCUS_TOGGLE;
|
||
|
_skip_map["SNAP"] = SKIP_SNAP;
|
||
|
_skip_map["PAGER"] = SKIP_PAGER;
|
||
|
_skip_map["TASKBAR"] = SKIP_TASKBAR;
|
||
|
|
||
|
_layer_map[""] = LAYER_NONE;
|
||
|
_layer_map["DESKTOP"] = LAYER_DESKTOP;
|
||
|
_layer_map["BELOW"] = LAYER_BELOW;
|
||
|
_layer_map["NORMAL"] = LAYER_NORMAL;
|
||
|
_layer_map["ONTOP"] = LAYER_ONTOP;
|
||
|
_layer_map["HARBOUR"] = LAYER_DOCK;
|
||
|
_layer_map["ABOVEHARBOUR"] = LAYER_ABOVE_DOCK;
|
||
|
_layer_map["MENU"] = LAYER_MENU;
|
||
|
|
||
|
_moveresize_map[""] = NO_MOVERESIZE_ACTION;
|
||
|
_moveresize_map["MOVEHORIZONTAL"] = MOVE_HORIZONTAL;
|
||
|
_moveresize_map["MOVEVERTICAL"] = MOVE_VERTICAL;
|
||
|
_moveresize_map["RESIZEHORIZONTAL"] = RESIZE_HORIZONTAL;
|
||
|
_moveresize_map["RESIZEVERTICAL"] = RESIZE_VERTICAL;
|
||
|
_moveresize_map["MOVESNAP"] = MOVE_SNAP;
|
||
|
_moveresize_map["CANCEL"] = MOVE_CANCEL;
|
||
|
_moveresize_map["END"] = MOVE_END;
|
||
|
|
||
|
_inputdialog_map[""] = INPUT_NO_ACTION;
|
||
|
_inputdialog_map["INSERT"] = INPUT_INSERT;
|
||
|
_inputdialog_map["ERASE"] = INPUT_REMOVE;
|
||
|
_inputdialog_map["CLEAR"] = INPUT_CLEAR;
|
||
|
_inputdialog_map["CLEARFROMCURSOR"] = INPUT_CLEARFROMCURSOR;
|
||
|
_inputdialog_map["EXEC"] = INPUT_EXEC;
|
||
|
_inputdialog_map["CLOSE"] = INPUT_CLOSE;
|
||
|
_inputdialog_map["COMPLETE"] = INPUT_COMPLETE;
|
||
|
_inputdialog_map["COMPLETEABORT"] = INPUT_COMPLETE_ABORT;
|
||
|
_inputdialog_map["CURSNEXT"] = INPUT_CURS_NEXT;
|
||
|
_inputdialog_map["CURSPREV"] = INPUT_CURS_PREV;
|
||
|
_inputdialog_map["CURSEND"] = INPUT_CURS_END;
|
||
|
_inputdialog_map["CURSBEGIN"] = INPUT_CURS_BEGIN;
|
||
|
_inputdialog_map["HISTNEXT"] = INPUT_HIST_NEXT;
|
||
|
_inputdialog_map["HISTPREV"] = INPUT_HIST_PREV;
|
||
|
|
||
|
_direction_map[""] = DIRECTION_NO;
|
||
|
_direction_map["UP"] = DIRECTION_UP;
|
||
|
_direction_map["DOWN"] = DIRECTION_DOWN;
|
||
|
_direction_map["LEFT"] = DIRECTION_LEFT;
|
||
|
_direction_map["RIGHT"] = DIRECTION_RIGHT;
|
||
|
|
||
|
_workspace_change_map[""] = WORKSPACE_NO;
|
||
|
_workspace_change_map["LEFT"] = WORKSPACE_LEFT;
|
||
|
_workspace_change_map["PREV"] = WORKSPACE_PREV;
|
||
|
_workspace_change_map["RIGHT"] = WORKSPACE_RIGHT;
|
||
|
_workspace_change_map["NEXT"] = WORKSPACE_NEXT;
|
||
|
_workspace_change_map["PREVV"] = WORKSPACE_PREV_V;
|
||
|
_workspace_change_map["UP"] = WORKSPACE_UP;
|
||
|
_workspace_change_map["NEXTV"] = WORKSPACE_NEXT_V;
|
||
|
_workspace_change_map["DOWN"] = WORKSPACE_DOWN;
|
||
|
_workspace_change_map["LAST"] = WORKSPACE_LAST;
|
||
|
|
||
|
_borderpos_map[""] = BORDER_NO_POS;
|
||
|
_borderpos_map["TOPLEFT"] = BORDER_TOP_LEFT;
|
||
|
_borderpos_map["TOP"] = BORDER_TOP;
|
||
|
_borderpos_map["TOPRIGHT"] = BORDER_TOP_RIGHT;
|
||
|
_borderpos_map["LEFT"] = BORDER_LEFT;
|
||
|
_borderpos_map["RIGHT"] = BORDER_RIGHT;
|
||
|
_borderpos_map["BOTTOMLEFT"] = BORDER_BOTTOM_LEFT;
|
||
|
_borderpos_map["BOTTOM"] = BORDER_BOTTOM;
|
||
|
_borderpos_map["BOTTOMRIGHT"] = BORDER_BOTTOM_RIGHT;
|
||
|
|
||
|
_mouse_event_map[""] = MOUSE_EVENT_NO;
|
||
|
_mouse_event_map["BUTTONPRESS"] = MOUSE_EVENT_PRESS;
|
||
|
_mouse_event_map["BUTTONRELEASE"] = MOUSE_EVENT_RELEASE;
|
||
|
_mouse_event_map["DOUBLECLICK"] = MOUSE_EVENT_DOUBLE;
|
||
|
_mouse_event_map["MOTION"] = MOUSE_EVENT_MOTION;
|
||
|
_mouse_event_map["ENTER"] = MOUSE_EVENT_ENTER;
|
||
|
_mouse_event_map["LEAVE"] = MOUSE_EVENT_LEAVE;
|
||
|
_mouse_event_map["ENTERMOVING"] = MOUSE_EVENT_ENTER_MOVING;
|
||
|
_mouse_event_map["MOTIONPRESSED"] = MOUSE_EVENT_MOTION_PRESSED;
|
||
|
|
||
|
_mod_map[""] = 0;
|
||
|
_mod_map["NONE"] = 0;
|
||
|
_mod_map["SHIFT"] = ShiftMask;
|
||
|
_mod_map["CTRL"] = ControlMask;
|
||
|
_mod_map["MOD1"] = Mod1Mask;
|
||
|
_mod_map["MOD2"] = Mod2Mask;
|
||
|
_mod_map["MOD3"] = Mod3Mask;
|
||
|
_mod_map["MOD4"] = Mod4Mask;
|
||
|
_mod_map["MOD5"] = Mod5Mask;
|
||
|
_mod_map["ANY"] = MOD_ANY;
|
||
|
|
||
|
_action_state_map[""] = ACTION_STATE_NO;
|
||
|
_action_state_map["Maximized"] = ACTION_STATE_MAXIMIZED;
|
||
|
_action_state_map["Fullscreen"] = ACTION_STATE_FULLSCREEN;
|
||
|
_action_state_map["Shaded"] = ACTION_STATE_SHADED;
|
||
|
_action_state_map["Sticky"] = ACTION_STATE_STICKY;
|
||
|
_action_state_map["AlwaysOnTop"] = ACTION_STATE_ALWAYS_ONTOP;
|
||
|
_action_state_map["AlwaysBelow"] = ACTION_STATE_ALWAYS_BELOW;
|
||
|
_action_state_map["DecorBorder"] = ACTION_STATE_DECOR_BORDER;
|
||
|
_action_state_map["DecorTitlebar"] = ACTION_STATE_DECOR_TITLEBAR;
|
||
|
_action_state_map["Iconified"] = ACTION_STATE_ICONIFIED;
|
||
|
_action_state_map["Tagged"] = ACTION_STATE_TAGGED;
|
||
|
_action_state_map["Marked"] = ACTION_STATE_MARKED;
|
||
|
_action_state_map["Skip"] = ACTION_STATE_SKIP;
|
||
|
_action_state_map["CfgDeny"] = ACTION_STATE_CFG_DENY;
|
||
|
#ifdef OPACITY
|
||
|
_action_state_map["Opaque"] = ACTION_STATE_OPAQUE;
|
||
|
#endif // OPACITY
|
||
|
_action_state_map["Title"] = ACTION_STATE_TITLE;
|
||
|
_action_state_map["HarbourHidden"] = ACTION_STATE_HARBOUR_HIDDEN;
|
||
|
_action_state_map["GlobalGrouping"] = ACTION_STATE_GLOBAL_GROUPING;
|
||
|
|
||
|
|
||
|
_cfg_deny_map["POSITION"] = CFG_DENY_POSITION;
|
||
|
_cfg_deny_map["SIZE"] = CFG_DENY_SIZE;
|
||
|
_cfg_deny_map["STACKING"] = CFG_DENY_STACKING;
|
||
|
_cfg_deny_map["ACTIVEWINDOW"] = CFG_DENY_ACTIVE_WINDOW;
|
||
|
_cfg_deny_map["MAXIMIZEDVERT"] = CFG_DENY_STATE_MAXIMIZED_VERT;
|
||
|
_cfg_deny_map["MAXIMIZEDHORZ"] = CFG_DENY_STATE_MAXIMIZED_HORZ;
|
||
|
_cfg_deny_map["HIDDEN"] = CFG_DENY_STATE_HIDDEN;
|
||
|
_cfg_deny_map["FULLSCREEN"] = CFG_DENY_STATE_FULLSCREEN;
|
||
|
_cfg_deny_map["ABOVE"] = CFG_DENY_STATE_ABOVE;
|
||
|
_cfg_deny_map["BELOW"] = CFG_DENY_STATE_BELOW;
|
||
|
|
||
|
_menu_action_map[""] = ACTION_MENU_NEXT;
|
||
|
_menu_action_map["NEXTITEM"] = ACTION_MENU_NEXT;
|
||
|
_menu_action_map["PREVITEM"] = ACTION_MENU_PREV;
|
||
|
_menu_action_map["SELECT"] = ACTION_MENU_SELECT;
|
||
|
_menu_action_map["ENTERSUBMENU"] = ACTION_MENU_ENTER_SUBMENU;
|
||
|
_menu_action_map["LEAVESUBMENU"] = ACTION_MENU_LEAVE_SUBMENU;
|
||
|
_menu_action_map["CLOSE"] = ACTION_CLOSE;
|
||
|
|
||
|
_harbour_placement_map[""] = NO_HARBOUR_PLACEMENT;
|
||
|
_harbour_placement_map["TOP"] = TOP;
|
||
|
_harbour_placement_map["LEFT"] = LEFT;
|
||
|
_harbour_placement_map["RIGHT"] = RIGHT;
|
||
|
_harbour_placement_map["BOTTOM"] = BOTTOM;
|
||
|
|
||
|
_harbour_orientation_map[""] = NO_ORIENTATION;
|
||
|
_harbour_orientation_map["TOPTOBOTTOM"] = TOP_TO_BOTTOM;
|
||
|
_harbour_orientation_map["LEFTTORIGHT"] = TOP_TO_BOTTOM;
|
||
|
_harbour_orientation_map["BOTTOMTOTOP"] = BOTTOM_TO_TOP;
|
||
|
_harbour_orientation_map["RIGHTTOLEFT"] = BOTTOM_TO_TOP;
|
||
|
|
||
|
// fill the mouse action map
|
||
|
_mouse_action_map[MOUSE_ACTION_LIST_TITLE_FRAME] = new list<ActionEvent>;
|
||
|
_mouse_action_map[MOUSE_ACTION_LIST_TITLE_OTHER] = new list<ActionEvent>;
|
||
|
_mouse_action_map[MOUSE_ACTION_LIST_CHILD_FRAME] = new list<ActionEvent>;
|
||
|
_mouse_action_map[MOUSE_ACTION_LIST_CHILD_OTHER] = new list<ActionEvent>;
|
||
|
_mouse_action_map[MOUSE_ACTION_LIST_ROOT] = new list<ActionEvent>;
|
||
|
_mouse_action_map[MOUSE_ACTION_LIST_MENU] = new list<ActionEvent>;
|
||
|
_mouse_action_map[MOUSE_ACTION_LIST_OTHER] = new list<ActionEvent>;
|
||
|
|
||
|
_mouse_action_map[MOUSE_ACTION_LIST_EDGE_T] = new list<ActionEvent>;
|
||
|
_mouse_action_map[MOUSE_ACTION_LIST_EDGE_B] = new list<ActionEvent>;
|
||
|
_mouse_action_map[MOUSE_ACTION_LIST_EDGE_L] = new list<ActionEvent>;
|
||
|
_mouse_action_map[MOUSE_ACTION_LIST_EDGE_R] = new list<ActionEvent>;
|
||
|
|
||
|
_mouse_action_map[MOUSE_ACTION_LIST_BORDER_TL] = new list<ActionEvent>;
|
||
|
_mouse_action_map[MOUSE_ACTION_LIST_BORDER_T] = new list<ActionEvent>;
|
||
|
_mouse_action_map[MOUSE_ACTION_LIST_BORDER_TR] = new list<ActionEvent>;
|
||
|
_mouse_action_map[MOUSE_ACTION_LIST_BORDER_L] = new list<ActionEvent>;
|
||
|
_mouse_action_map[MOUSE_ACTION_LIST_BORDER_R] = new list<ActionEvent>;
|
||
|
_mouse_action_map[MOUSE_ACTION_LIST_BORDER_BL] = new list<ActionEvent>;
|
||
|
_mouse_action_map[MOUSE_ACTION_LIST_BORDER_B] = new list<ActionEvent>;
|
||
|
_mouse_action_map[MOUSE_ACTION_LIST_BORDER_BR] = new list<ActionEvent>;
|
||
|
}
|
||
|
|
||
|
//! @brief Destructor for Config class
|
||
|
Config::~Config(void)
|
||
|
{
|
||
|
_instance = 0;
|
||
|
|
||
|
map<MouseActionListName, list<ActionEvent>* >::iterator it;
|
||
|
for (it = _mouse_action_map.begin(); it != _mouse_action_map.end(); ++it) {
|
||
|
delete it->second;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns an array of NULL-terminated desktop names in UTF-8.
|
||
|
*
|
||
|
* @param names *names will be set to an array of desktop names or 0. The caller has to delete [] *names
|
||
|
* @param length *length will be set to the complete length of array *names points to or 0.
|
||
|
*/
|
||
|
void
|
||
|
Config::getDesktopNamesUTF8(uchar **names, uint *length) const
|
||
|
{
|
||
|
if (! _screen_workspace_names.size()) {
|
||
|
*names = 0;
|
||
|
*length = 0;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Convert strings to UTF-8 and calculate total length
|
||
|
string utf8_names;
|
||
|
vector<wstring>::const_iterator it(_screen_workspace_names.begin());
|
||
|
for (; it != _screen_workspace_names.end(); ++it) {
|
||
|
string utf8_name(Util::to_utf8_str(*it));
|
||
|
utf8_names.append(utf8_name.c_str(), utf8_name.size() + 1);
|
||
|
}
|
||
|
|
||
|
*names = new uchar[utf8_names.size()];
|
||
|
::memcpy(*names, utf8_names.c_str(), utf8_names.size());
|
||
|
*length = utf8_names.size();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets the desktop names.
|
||
|
*
|
||
|
* @param names names is expected to point to an array of NULL-terminated utf8-strings.
|
||
|
* @param length The length of the array "names".
|
||
|
*/
|
||
|
void
|
||
|
Config::setDesktopNamesUTF8(char *names, ulong length)
|
||
|
{
|
||
|
_screen_workspace_names.clear();
|
||
|
|
||
|
if (! names || ! length) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
for (ulong i = 0; i < length;) {
|
||
|
_screen_workspace_names.push_back(Util::from_utf8_str(names));
|
||
|
i += strlen(names) + 1;
|
||
|
names += strlen(names) + 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//! @brief Tries to load config_file, ~/.pekwm/config, SYSCONFDIR/config
|
||
|
bool
|
||
|
Config::load(const std::string &config_file)
|
||
|
{
|
||
|
if (! Util::requireReload(_cfg_state, config_file)) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
CfgParser cfg;
|
||
|
|
||
|
_config_file = config_file;
|
||
|
bool success = tryHardLoadConfig(cfg, _config_file);
|
||
|
|
||
|
// Make sure config is reloaded next time as content is dynamically
|
||
|
// generated from the configuration file.
|
||
|
if (! success || cfg.is_dynamic_content()) {
|
||
|
_cfg_state.clear();
|
||
|
} else {
|
||
|
_cfg_state = cfg.get_file_list();
|
||
|
}
|
||
|
|
||
|
if (! success) {
|
||
|
cerr << " *** WARNING: unable to load configuration files!" << endl;
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// Update PEKWM_CONFIG_FILE environment if needed (to reflect active file)
|
||
|
char *cfg_env = getenv("PEKWM_CONFIG_FILE");
|
||
|
if (! cfg_env || (strcmp(cfg_env, _config_file.c_str()) != 0)) {
|
||
|
setenv("PEKWM_CONFIG_FILE", _config_file.c_str(), 1);
|
||
|
}
|
||
|
|
||
|
string o_file_mouse; // temporary filepath for mouseconfig
|
||
|
|
||
|
CfgParser::Entry *section;
|
||
|
|
||
|
// Get other config files dests.
|
||
|
section = cfg.get_entry_root()->find_section("FILES");
|
||
|
if (section) {
|
||
|
loadFiles(section);
|
||
|
}
|
||
|
|
||
|
// Parse moving / resizing options.
|
||
|
section = cfg.get_entry_root()->find_section("MOVERESIZE");
|
||
|
if (section) {
|
||
|
loadMoveResize(section);
|
||
|
}
|
||
|
|
||
|
// Screen, important stuff such as number of workspaces
|
||
|
section = cfg.get_entry_root()->find_section("SCREEN");
|
||
|
if (section) {
|
||
|
loadScreen(section);
|
||
|
}
|
||
|
|
||
|
section = cfg.get_entry_root()->find_section("MENU");
|
||
|
if (section) {
|
||
|
loadMenu(section);
|
||
|
}
|
||
|
|
||
|
section = cfg.get_entry_root()->find_section("CMDDIALOG");
|
||
|
if (section) {
|
||
|
loadCmdDialog(section);
|
||
|
}
|
||
|
|
||
|
section = cfg.get_entry_root()->find_section("HARBOUR");
|
||
|
if (section) {
|
||
|
loadHarbour(section);
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
//! @brief Loads file section of configuration
|
||
|
//! @param section Pointer to FILES section.
|
||
|
void
|
||
|
Config::loadFiles(CfgParser::Entry *section)
|
||
|
{
|
||
|
if (! section) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
list<CfgParserKey*> key_list;
|
||
|
key_list.push_back(new CfgParserKeyPath("KEYS", _files_keys, SYSCONFDIR "/keys"));
|
||
|
key_list.push_back(new CfgParserKeyPath("MOUSE", _files_mouse, SYSCONFDIR "/mouse"));
|
||
|
key_list.push_back(new CfgParserKeyPath("MENU", _files_menu, SYSCONFDIR "/menu"));
|
||
|
key_list.push_back(new CfgParserKeyPath("START", _files_start, SYSCONFDIR "/start"));
|
||
|
key_list.push_back(new CfgParserKeyPath("AUTOPROPS", _files_autoprops, SYSCONFDIR "/autoproperties"));
|
||
|
key_list.push_back(new CfgParserKeyPath("THEME", _files_theme, DATADIR "/pekwm/themes/default/theme"));
|
||
|
key_list.push_back(new CfgParserKeyPath("ICONS", _files_icon_path, DATADIR "/pekwm/icons"));
|
||
|
|
||
|
// Parse
|
||
|
section->parse_key_values(key_list.begin(), key_list.end());
|
||
|
|
||
|
// Free up resources
|
||
|
for_each(key_list.begin(), key_list.end(), Util::Free<CfgParserKey*>());
|
||
|
}
|
||
|
|
||
|
//! @brief Loads MOVERESIZE section of main configuration
|
||
|
//! @param section Pointer to MOVERESIZE section.
|
||
|
void
|
||
|
Config::loadMoveResize(CfgParser::Entry *section)
|
||
|
{
|
||
|
if (! section) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
list<CfgParserKey*> key_list;
|
||
|
key_list.push_back(new CfgParserKeyNumeric<int>("EDGEATTRACT", _moveresize_edgeattract, 0, 0));
|
||
|
key_list.push_back(new CfgParserKeyNumeric<int>("EDGERESIST", _moveresize_edgeresist, 0, 0));
|
||
|
key_list.push_back(new CfgParserKeyNumeric<int>("WINDOWATTRACT",_moveresize_woattract, 0, 0));
|
||
|
key_list.push_back(new CfgParserKeyNumeric<int>("WINDOWRESIST", _moveresize_woresist, 0, 0));
|
||
|
key_list.push_back(new CfgParserKeyBool("OPAQUEMOVE", _moveresize_opaquemove));
|
||
|
key_list.push_back(new CfgParserKeyBool("OPAQUERESIZE", _moveresize_opaqueresize));
|
||
|
|
||
|
// Parse data
|
||
|
section->parse_key_values(key_list.begin(), key_list.end());
|
||
|
|
||
|
// Free up resources
|
||
|
for_each(key_list.begin(), key_list.end(), Util::Free<CfgParserKey*>());
|
||
|
}
|
||
|
|
||
|
//! @brief Loads SCREEN section of main configuration
|
||
|
//! @param section Pointer to SCREEN section.
|
||
|
void
|
||
|
Config::loadScreen(CfgParser::Entry *section)
|
||
|
{
|
||
|
if (! section) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Parse data
|
||
|
string edge_size, workspace_names, trim_title;
|
||
|
CfgParser::Entry *value;
|
||
|
|
||
|
list<CfgParserKey*> key_list;
|
||
|
key_list.push_back(new CfgParserKeyNumeric<int>("WORKSPACES", _screen_workspaces, 4, 1));
|
||
|
key_list.push_back(new CfgParserKeyNumeric<int>("PIXMAPCACHESIZE", _screen_pixmap_cache_size));
|
||
|
key_list.push_back(new CfgParserKeyNumeric<int>("WORKSPACESPERROW", _screen_workspaces_per_row, 0, 0));
|
||
|
key_list.push_back(new CfgParserKeyString("WORKSPACENAMES", workspace_names));
|
||
|
key_list.push_back(new CfgParserKeyString("EDGESIZE", edge_size));
|
||
|
key_list.push_back(new CfgParserKeyBool("EDGEINDENT", _screen_edge_indent));
|
||
|
key_list.push_back(new CfgParserKeyNumeric<int>("DOUBLECLICKTIME", _screen_doubleclicktime, 250, 0));
|
||
|
key_list.push_back(new CfgParserKeyString("TRIMTITLE", trim_title));
|
||
|
key_list.push_back(new CfgParserKeyBool("FULLSCREENABOVE", _screen_fullscreen_above, true));
|
||
|
key_list.push_back(new CfgParserKeyBool("FULLSCREENDETECT", _screen_fullscreen_detect, true));
|
||
|
key_list.push_back(new CfgParserKeyBool("SHOWFRAMELIST", _screen_showframelist));
|
||
|
key_list.push_back(new CfgParserKeyBool("SHOWSTATUSWINDOW", _screen_show_status_window));
|
||
|
key_list.push_back(new CfgParserKeyBool("SHOWSTATUSWINDOWCENTEREDONROOT", _screen_show_status_window_on_root, false));
|
||
|
key_list.push_back(new CfgParserKeyBool("SHOWCLIENTID", _screen_show_client_id));
|
||
|
key_list.push_back(new CfgParserKeyNumeric<int>("SHOWWORKSPACEINDICATOR",
|
||
|
_screen_show_workspace_indicator, 500, 0));
|
||
|
key_list.push_back(new CfgParserKeyNumeric<int>("WORKSPACEINDICATORSCALE",
|
||
|
_screen_workspace_indicator_scale, 16, 2));
|
||
|
#ifdef OPACITY
|
||
|
key_list.push_back(new CfgParserKeyNumeric<uint>("WORKSPACEINDICATOROPACITY",
|
||
|
_screen_workspace_indicator_opacity, 100, 0, 100));
|
||
|
#endif // OPACITY
|
||
|
key_list.push_back(new CfgParserKeyBool("PLACENEW", _screen_place_new));
|
||
|
key_list.push_back(new CfgParserKeyBool("FOCUSNEW", _screen_focus_new));
|
||
|
key_list.push_back(new CfgParserKeyBool("FOCUSNEWCHILD", _screen_focus_new_child, true));
|
||
|
key_list.push_back(new CfgParserKeyBool("HONOURRANDR", _screen_honour_randr, true));
|
||
|
key_list.push_back(new CfgParserKeyBool("HONOURASPECTRATIO", _screen_honour_aspectratio, true));
|
||
|
key_list.push_back(new CfgParserKeyBool("REPORTALLCLIENTS", _screen_report_all_clients, false));
|
||
|
|
||
|
// Parse data
|
||
|
section->parse_key_values(key_list.begin(), key_list.end());
|
||
|
|
||
|
// Free up resources
|
||
|
for_each(key_list.begin(), key_list.end(), Util::Free<CfgParserKey*>());
|
||
|
key_list.clear();
|
||
|
|
||
|
// Convert input data
|
||
|
_screen_trim_title = Util::to_wide_str(trim_title);
|
||
|
|
||
|
// Convert opacity from percent to absolute value
|
||
|
CONV_OPACITY(_screen_workspace_indicator_opacity);
|
||
|
|
||
|
int edge_size_all = 0;
|
||
|
_screen_edge_sizes.clear();
|
||
|
if (edge_size.size()) {
|
||
|
vector<string> sizes;
|
||
|
if (Util::splitString(edge_size, sizes, " \t", 4) == 4) {
|
||
|
for (vector<string>::iterator it(sizes.begin()); it != sizes.end(); ++it) {
|
||
|
_screen_edge_sizes.push_back(strtol(it->c_str(), 0, 10));
|
||
|
}
|
||
|
} else {
|
||
|
edge_size_all = strtol(edge_size.c_str(), 0, 10);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for (uint i = 0; i < SCREEN_EDGE_NO; ++i) {
|
||
|
_screen_edge_sizes.push_back(edge_size_all);
|
||
|
}
|
||
|
// Add SCREEN_EDGE_NO to the list for safety
|
||
|
_screen_edge_sizes.push_back(0);
|
||
|
|
||
|
// Workspace names
|
||
|
_screen_workspace_names.clear();
|
||
|
|
||
|
vector<string> vs;
|
||
|
if (Util::splitString(workspace_names, vs, ";", 0, true)) {
|
||
|
vector<string>::iterator vs_it(vs.begin());
|
||
|
for (; vs_it != vs.end(); ++vs_it) {
|
||
|
_screen_workspace_names.push_back(Util::to_wide_str(*vs_it));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
CfgParser::Entry *sub = section->find_section("PLACEMENT");
|
||
|
if (sub) {
|
||
|
value = sub->find_entry("MODEL");
|
||
|
if (value) {
|
||
|
_screen_placementmodels.clear();
|
||
|
|
||
|
vector<string> models;
|
||
|
if (Util::splitString(value->get_value(), models, " \t")) {
|
||
|
vector<string>::iterator it(models.begin());
|
||
|
for (; it != models.end(); ++it)
|
||
|
_screen_placementmodels.push_back(ParseUtil::getValue<PlacementModel>(*it, _placement_map));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
CfgParser::Entry *sub_2 = sub->find_section("SMART");
|
||
|
if (sub_2) {
|
||
|
key_list.push_back(new CfgParserKeyBool("ROW", _screen_placement_row));
|
||
|
key_list.push_back(new CfgParserKeyBool("LEFTTORIGHT", _screen_placement_ltr));
|
||
|
key_list.push_back(new CfgParserKeyBool("TOPTOBOTTOM", _screen_placement_ttb));
|
||
|
key_list.push_back(new CfgParserKeyNumeric<int>("OFFSETX", _screen_placement_offset_x, 0, 0));
|
||
|
key_list.push_back(new CfgParserKeyNumeric<int>("OFFSETY", _screen_placement_offset_y, 0, 0));
|
||
|
|
||
|
// Do the parsing
|
||
|
sub_2->parse_key_values(key_list.begin(), key_list.end());
|
||
|
|
||
|
// Freeup resources
|
||
|
for_each(key_list.begin(), key_list.end(), Util::Free<CfgParserKey*>());
|
||
|
key_list.clear();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Fallback value
|
||
|
if (! _screen_placementmodels.size()) {
|
||
|
_screen_placementmodels.push_back(PLACE_MOUSE_CENTERED);
|
||
|
}
|
||
|
|
||
|
sub = section->find_section("UNIQUENAMES");
|
||
|
if (sub) {
|
||
|
key_list.push_back(new CfgParserKeyBool("SETUNIQUE", _screen_client_unique_name));
|
||
|
key_list.push_back(new CfgParserKeyString("PRE", _screen_client_unique_name_pre));
|
||
|
key_list.push_back(new CfgParserKeyString("POST", _screen_client_unique_name_post));
|
||
|
|
||
|
// Parse data
|
||
|
sub->parse_key_values(key_list.begin(), key_list.end());
|
||
|
|
||
|
// Free up resources
|
||
|
for_each(key_list.begin(), key_list.end(), Util::Free<CfgParserKey*>());
|
||
|
key_list.clear();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//! @brief Loads the MENU section of the main configuration
|
||
|
//! @param section Pointer to MENU section
|
||
|
void
|
||
|
Config::loadMenu(CfgParser::Entry *section)
|
||
|
{
|
||
|
if (! section) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
list<CfgParserKey*> key_list;
|
||
|
string value_select, value_enter, value_exec;
|
||
|
|
||
|
key_list.push_back(new CfgParserKeyString("SELECT", value_select, "MOTION", 0));
|
||
|
key_list.push_back(new CfgParserKeyString("ENTER", value_enter, "BUTTONPRESS", 0));
|
||
|
key_list.push_back(new CfgParserKeyString("EXEC", value_exec, "BUTTONRELEASE", 0));
|
||
|
key_list.push_back(new CfgParserKeyBool("DISPLAYICONS", _menu_display_icons, true));
|
||
|
#ifdef OPACITY
|
||
|
key_list.push_back(new CfgParserKeyNumeric<uint>("FOCUSOPACITY", _menu_focus_opacity, 100, 0, 100));
|
||
|
key_list.push_back(new CfgParserKeyNumeric<uint>("UNFOCUSOPACITY", _menu_unfocus_opacity, 100, 0, 100));
|
||
|
#endif // OPACITY
|
||
|
|
||
|
// Parse data
|
||
|
section->parse_key_values(key_list.begin(), key_list.end());
|
||
|
|
||
|
_menu_select_mask = getMenuMask(value_select);
|
||
|
_menu_enter_mask = getMenuMask(value_enter);
|
||
|
_menu_exec_mask = getMenuMask(value_exec);
|
||
|
|
||
|
// Free up resources
|
||
|
for_each(key_list.begin(), key_list.end(), Util::Free<CfgParserKey*>());
|
||
|
key_list.clear();
|
||
|
|
||
|
// Parse icon size limits
|
||
|
CfgParser::iterator it(section->begin());
|
||
|
for (; it != section->end(); ++it) {
|
||
|
if (*(*it) == "ICONS") {
|
||
|
loadMenuIcons((*it)->get_section());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Convert opacity from percent to absolute value
|
||
|
CONV_OPACITY(_menu_focus_opacity);
|
||
|
CONV_OPACITY(_menu_unfocus_opacity);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Load Icon size limits for menu.
|
||
|
*/
|
||
|
void
|
||
|
Config::loadMenuIcons(CfgParser::Entry *section)
|
||
|
{
|
||
|
if (! section || ! section->get_value().size()) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
list<CfgParserKey*> key_list;
|
||
|
string minimum, maximum;
|
||
|
|
||
|
key_list.push_back(new CfgParserKeyString("MINIMUM", minimum, "16x16", 3));
|
||
|
key_list.push_back(new CfgParserKeyString("MAXIMUM", maximum, "16x16", 3));
|
||
|
|
||
|
// Parse data
|
||
|
section->parse_key_values(key_list.begin(), key_list.end());
|
||
|
|
||
|
for_each(key_list.begin(), key_list.end(), Util::Free<CfgParserKey*>());
|
||
|
|
||
|
SizeLimits limits;
|
||
|
if (limits.parse(minimum, maximum)) {
|
||
|
_menu_icon_limits[section->get_value()] = limits;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Load configuration from CmdDialog section.
|
||
|
*/
|
||
|
void
|
||
|
Config::loadCmdDialog(CfgParser::Entry *section)
|
||
|
{
|
||
|
if (! section) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
list<CfgParserKey*> key_list;
|
||
|
|
||
|
key_list.push_back(new CfgParserKeyBool("HISTORYUNIQUE", _cmd_dialog_history_unique));
|
||
|
key_list.push_back(new CfgParserKeyNumeric<int>("HISTORYSIZE", _cmd_dialog_history_size, 1024, 1));
|
||
|
key_list.push_back(new CfgParserKeyPath("HISTORYFILE", _cmd_dialog_history_file, "~/.pekwm/history"));
|
||
|
key_list.push_back(new CfgParserKeyNumeric<int>("HISTORYSAVEINTERVAL", _cmd_dialog_history_save_interval, 16, 0));
|
||
|
|
||
|
section->parse_key_values(key_list.begin(), key_list.end());
|
||
|
|
||
|
for_each(key_list.begin(), key_list.end(), Util::Free<CfgParserKey*>());
|
||
|
}
|
||
|
|
||
|
//! @brief Loads the HARBOUR section of the main configuration
|
||
|
void
|
||
|
Config::loadHarbour(CfgParser::Entry *section)
|
||
|
{
|
||
|
if (! section) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
list<CfgParserKey*> key_list;
|
||
|
string value_placement, value_orientation;
|
||
|
|
||
|
key_list.push_back(new CfgParserKeyBool("ONTOP", _harbour_ontop, true));
|
||
|
key_list.push_back(new CfgParserKeyBool("MAXIMIZEOVER", _harbour_maximize_over, false));
|
||
|
key_list.push_back(new CfgParserKeyNumeric<int>("HEAD", _harbour_head_nr, 0, 0));
|
||
|
key_list.push_back(new CfgParserKeyString("PLACEMENT", value_placement, "RIGHT", 0));
|
||
|
key_list.push_back(new CfgParserKeyString("ORIENTATION", value_orientation, "TOPTOBOTTOM", 0));
|
||
|
#ifdef OPACITY
|
||
|
key_list.push_back(new CfgParserKeyNumeric<uint>("OPACITY", _harbour_opacity, 100, 0, 100));
|
||
|
#endif // OPACITY
|
||
|
|
||
|
// Parse data
|
||
|
section->parse_key_values(key_list.begin(), key_list.end());
|
||
|
|
||
|
// Free up resources
|
||
|
for_each(key_list.begin(), key_list.end(), Util::Free<CfgParserKey*>());
|
||
|
key_list.clear();
|
||
|
|
||
|
// Convert opacity from percent to absolute value
|
||
|
CONV_OPACITY(_harbour_opacity);
|
||
|
|
||
|
_harbour_placement = ParseUtil::getValue<HarbourPlacement>(value_placement, _harbour_placement_map);
|
||
|
_harbour_orientation = ParseUtil::getValue<Orientation>(value_orientation, _harbour_orientation_map);
|
||
|
if (_harbour_placement == NO_HARBOUR_PLACEMENT) {
|
||
|
_harbour_placement = RIGHT;
|
||
|
}
|
||
|
if (_harbour_orientation == NO_ORIENTATION) {
|
||
|
_harbour_orientation = TOP_TO_BOTTOM;
|
||
|
}
|
||
|
|
||
|
CfgParser::Entry *sub = section->find_section("DOCKAPP");
|
||
|
if (sub) {
|
||
|
key_list.push_back(new CfgParserKeyNumeric<int>("SIDEMIN", _harbour_da_min_s, 64, 0));
|
||
|
key_list.push_back(new CfgParserKeyNumeric<int>("SIDEMAX", _harbour_da_max_s, 64, 0));
|
||
|
|
||
|
// Parse data
|
||
|
sub->parse_key_values(key_list.begin(), key_list.end());
|
||
|
|
||
|
// Free up resources
|
||
|
for_each(key_list.begin(), key_list.end(), Util::Free<CfgParserKey*>());
|
||
|
key_list.clear();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//! @brief
|
||
|
ActionType
|
||
|
Config::getAction(const std::string &name, uint mask)
|
||
|
{
|
||
|
pair<ActionType, uint> val(ParseUtil::getValue<pair<ActionType, uint> >(name, _action_map));
|
||
|
|
||
|
if ((val.first != ACTION_NO) && (val.second&mask)) {
|
||
|
return val.first;
|
||
|
}
|
||
|
return ACTION_NO;
|
||
|
}
|
||
|
|
||
|
ActionAccessMask
|
||
|
Config::getActionAccessMask(const std::string &name)
|
||
|
{
|
||
|
ActionAccessMask mask = ParseUtil::getValue<ActionAccessMask>(name, _action_access_mask_map);
|
||
|
return mask;
|
||
|
}
|
||
|
|
||
|
//! @brief
|
||
|
bool
|
||
|
Config::parseKey(const std::string &key_string, uint &mod, uint &key)
|
||
|
{
|
||
|
// used for parsing
|
||
|
vector<string> tok;
|
||
|
vector<string>::iterator it;
|
||
|
|
||
|
uint num;
|
||
|
|
||
|
// chop the string up separating mods and the end key/button
|
||
|
if (Util::splitString(key_string, tok, " \t")) {
|
||
|
num = tok.size() - 1;
|
||
|
if ((tok[num].size() > 1) && (tok[num][0] == '#')) {
|
||
|
key = strtol(tok[num].c_str() + 1, 0, 10);
|
||
|
} else if (strcasecmp(tok[num].c_str(), "ANY") == 0) {
|
||
|
// Do no matching, anything goes.
|
||
|
key = 0;
|
||
|
} else {
|
||
|
KeySym keysym = XStringToKeysym(tok[num].c_str());
|
||
|
|
||
|
// XStringToKeysym() may fail. Perhaps we have luck after some
|
||
|
// simple transformations. First we convert the string to lowercase
|
||
|
// and try again. Then we try with only the first character in
|
||
|
// uppercase and at last we try a complete uppercase string. If all
|
||
|
// fails, we print a warning and return false.
|
||
|
if (keysym == NoSymbol) {
|
||
|
string str = tok[num];
|
||
|
Util::to_lower(str);
|
||
|
keysym = XStringToKeysym(str.c_str());
|
||
|
if (keysym == NoSymbol) {
|
||
|
str[0] = ::toupper(str[0]);
|
||
|
keysym = XStringToKeysym(str.c_str());
|
||
|
if (keysym == NoSymbol) {
|
||
|
Util::to_upper(str);
|
||
|
keysym = XStringToKeysym(str.c_str());
|
||
|
if (keysym == NoSymbol) {
|
||
|
cerr << " *** WARNING: Couldn't find keysym for " << tok[num] << endl;
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
key = XKeysymToKeycode(PScreen::instance()->getDpy(), keysym);
|
||
|
}
|
||
|
|
||
|
// if the last token isn't an key/button, the action isn't valid
|
||
|
if ((key != 0) || (strcasecmp(tok[num].c_str(), "ANY") == 0)) {
|
||
|
tok.pop_back(); // remove the key/button
|
||
|
|
||
|
// add the modifier
|
||
|
mod = 0;
|
||
|
for (it = tok.begin(); it != tok.end(); ++it) {
|
||
|
mod |= getMod(*it);
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool
|
||
|
Config::parseButton(const std::string &button_string, uint &mod, uint &button)
|
||
|
{
|
||
|
// used for parsing
|
||
|
vector<string> tok;
|
||
|
vector<string>::iterator it;
|
||
|
|
||
|
// chop the string up separating mods and the end key/button
|
||
|
if (Util::splitString(button_string, tok, " \t")) {
|
||
|
// if the last token isn't an key/button, the action isn't valid
|
||
|
button = getMouseButton(tok[tok.size() - 1]);
|
||
|
if (button != BUTTON_NO) {
|
||
|
tok.pop_back(); // remove the key/button
|
||
|
|
||
|
// add the modifier
|
||
|
mod = 0;
|
||
|
uint tmp_mod;
|
||
|
|
||
|
for (it = tok.begin(); it != tok.end(); ++it) {
|
||
|
tmp_mod = getMod(*it);
|
||
|
if (tmp_mod == MOD_ANY) {
|
||
|
mod = MOD_ANY;
|
||
|
break;
|
||
|
} else {
|
||
|
mod |= tmp_mod;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
//! @brief Parse a single action and fills action.
|
||
|
//! @param action_string String representation of action.
|
||
|
//! @param action Action structure to fill in.
|
||
|
//! @param mask Mask action is valid for.
|
||
|
//! @return true on success, else false
|
||
|
bool
|
||
|
Config::parseAction(const std::string &action_string, Action &action, uint mask)
|
||
|
{
|
||
|
vector<string> tok;
|
||
|
|
||
|
// chop the string up separating the action and parameters
|
||
|
if (Util::splitString(action_string, tok, " \t", 2)) {
|
||
|
action.setAction(getAction(tok[0], mask));
|
||
|
if (action.getAction() != ACTION_NO) {
|
||
|
if (tok.size() == 2) { // we got enough tok for a parameter
|
||
|
switch (action.getAction()) {
|
||
|
case ACTION_EXEC:
|
||
|
case ACTION_RESTART_OTHER:
|
||
|
case ACTION_FIND_CLIENT:
|
||
|
case ACTION_SHOW_CMD_DIALOG:
|
||
|
case ACTION_SHOW_SEARCH_DIALOG:
|
||
|
case ACTION_SEND_KEY:
|
||
|
case ACTION_MENU_DYN:
|
||
|
action.setParamS(tok[1]);
|
||
|
break;
|
||
|
case ACTION_ACTIVATE_CLIENT_REL:
|
||
|
case ACTION_MOVE_CLIENT_REL:
|
||
|
case ACTION_GOTO_CLIENT_ID:
|
||
|
action.setParamI(0, strtol(tok[1].c_str(), 0, 10));
|
||
|
break;
|
||
|
case ACTION_SET:
|
||
|
case ACTION_UNSET:
|
||
|
case ACTION_TOGGLE:
|
||
|
parseActionState(action, tok[1]);
|
||
|
break;
|
||
|
case ACTION_MAXFILL:
|
||
|
if ((Util::splitString(tok[1], tok, " \t", 2)) == 2) {
|
||
|
action.setParamI(0, Util::isTrue(tok[tok.size() - 2]));
|
||
|
action.setParamI(1, Util::isTrue(tok[tok.size() - 1]));
|
||
|
} else {
|
||
|
cerr << "*** WARNING: Missing argument to MaxFill." << endl;
|
||
|
}
|
||
|
break;
|
||
|
case ACTION_GROW_DIRECTION:
|
||
|
action.setParamI(0, ParseUtil::getValue<DirectionType>(tok[1], _direction_map));
|
||
|
break;
|
||
|
case ACTION_ACTIVATE_CLIENT_NUM:
|
||
|
action.setParamI(0, strtol(tok[1].c_str(), 0, 10) - 1);
|
||
|
if (action.getParamI(0) < 0) {
|
||
|
cerr << "*** WARNING: Negative number to ActivateClientNum." << endl;
|
||
|
action.setParamI(0, 0);
|
||
|
}
|
||
|
break;
|
||
|
case ACTION_WARP_TO_WORKSPACE:
|
||
|
case ACTION_SEND_TO_WORKSPACE:
|
||
|
case ACTION_GOTO_WORKSPACE:
|
||
|
action.setParamI(0, parseWorkspaceNumber(tok[1]));
|
||
|
break;
|
||
|
case ACTION_GROUPING_DRAG:
|
||
|
action.setParamI(0, Util::isTrue(tok[1]));
|
||
|
break;
|
||
|
case ACTION_MOVE_TO_EDGE:
|
||
|
action.setParamI(0, ParseUtil::getValue<OrientationType>(tok[1], _edge_map));
|
||
|
break;
|
||
|
case ACTION_NEXT_FRAME:
|
||
|
case ACTION_NEXT_FRAME_MRU:
|
||
|
case ACTION_PREV_FRAME:
|
||
|
case ACTION_PREV_FRAME_MRU:
|
||
|
if ((Util::splitString(tok[1], tok, " \t", 2)) == 2) {
|
||
|
action.setParamI(0, ParseUtil::getValue<Raise>(tok[tok.size() - 2],
|
||
|
_raise_map));
|
||
|
action.setParamI(1, Util::isTrue(tok[tok.size() - 1]));
|
||
|
} else {
|
||
|
action.setParamI(0, ParseUtil::getValue<Raise>(tok[1],
|
||
|
_raise_map));
|
||
|
action.setParamI(1, false);
|
||
|
}
|
||
|
break;
|
||
|
case ACTION_FOCUS_DIRECTIONAL:
|
||
|
if ((Util::splitString(tok[1], tok, " \t", 2)) == 2) {
|
||
|
action.setParamI(0, ParseUtil::getValue<DirectionType>(tok[tok.size() - 2], _direction_map));
|
||
|
action.setParamI(1, Util::isTrue(tok[tok.size() - 1])); // raise?
|
||
|
} else {
|
||
|
action.setParamI(0, ParseUtil::getValue<DirectionType>(tok[1], _direction_map));
|
||
|
action.setParamI(1, true); // default to raise
|
||
|
}
|
||
|
break;
|
||
|
case ACTION_RESIZE:
|
||
|
action.setParamI(0, 1 + ParseUtil::getValue<BorderPosition>(tok[1], _borderpos_map));
|
||
|
break;
|
||
|
case ACTION_RAISE:
|
||
|
case ACTION_LOWER:
|
||
|
if ((Util::splitString(tok[1], tok, " \t", 1)) == 1) {
|
||
|
action.setParamI(0, Util::isTrue(tok[tok.size() - 1]));
|
||
|
} else {
|
||
|
action.setParamI(0, false);
|
||
|
}
|
||
|
break;
|
||
|
case ACTION_SHOW_MENU:
|
||
|
if ((Util::splitString(tok[1], tok, " \t", 2)) == 2) {
|
||
|
Util::to_upper(tok[tok.size() - 2]);
|
||
|
action.setParamS(tok[tok.size() - 2]);
|
||
|
action.setParamI(0, Util::isTrue(tok[tok.size() - 1]));
|
||
|
} else {
|
||
|
Util::to_upper(tok[1]);
|
||
|
action.setParamS(tok[1]);
|
||
|
action.setParamI(0, false); // Default to non-sticky
|
||
|
}
|
||
|
break;
|
||
|
#ifdef OPACITY
|
||
|
case ACTION_SET_OPACITY:
|
||
|
if ((Util::splitString(tok[1], tok, " \t", 2)) == 2) {
|
||
|
action.setParamI(0, std::atoi(tok[tok.size() - 2].c_str()));
|
||
|
action.setParamI(1, std::atoi(tok[tok.size() - 1].c_str()));
|
||
|
} else {
|
||
|
action.setParamI(0, std::atoi(tok[1].c_str()));
|
||
|
action.setParamI(1, std::atoi(tok[1].c_str()));
|
||
|
}
|
||
|
break;
|
||
|
#endif // OPACITY
|
||
|
default:
|
||
|
// do nothing
|
||
|
break;
|
||
|
}
|
||
|
} else {
|
||
|
switch (action.getAction()) {
|
||
|
case ACTION_MAXFILL:
|
||
|
action.setParamI(0, 1);
|
||
|
action.setParamI(1, 1);
|
||
|
break;
|
||
|
default:
|
||
|
// do nothing
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool
|
||
|
Config::parseActionAccessMask(const std::string &action_mask, uint &mask)
|
||
|
{
|
||
|
mask = ACTION_ACCESS_NO;
|
||
|
|
||
|
vector<string> tok;
|
||
|
if (Util::splitString(action_mask, tok, " \t")) {
|
||
|
vector<string>::iterator it(tok.begin());
|
||
|
for (; it != tok.end(); ++it) {
|
||
|
mask |= getActionAccessMask(*it);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
//! @brief
|
||
|
bool
|
||
|
Config::parseActionState(Action &action, const std::string &as_action)
|
||
|
{
|
||
|
vector<string> tok;
|
||
|
|
||
|
// chop the string up separating the action and parameters
|
||
|
if (Util::splitString(as_action, tok, " \t", 2)) {
|
||
|
action.setParamI(0, ParseUtil::getValue<ActionStateType>(tok[0], _action_state_map));
|
||
|
if (action.getParamI(0) != ACTION_STATE_NO) {
|
||
|
if (tok.size() == 2) { // we got enough tok for a parameter
|
||
|
string directions;
|
||
|
|
||
|
switch (action.getParamI(0)) {
|
||
|
case ACTION_STATE_MAXIMIZED:
|
||
|
// Using copy of token here to silence valgrind checks.
|
||
|
directions = tok[1];
|
||
|
|
||
|
Util::splitString(directions, tok, " \t", 2);
|
||
|
if (tok.size() == 4) {
|
||
|
action.setParamI(1, Util::isTrue(tok[2]));
|
||
|
action.setParamI(2, Util::isTrue(tok[3]));
|
||
|
} else {
|
||
|
cerr << "*** WARNING: Missing argument to Maximized." << endl;
|
||
|
}
|
||
|
break;
|
||
|
case ACTION_STATE_TAGGED:
|
||
|
action.setParamI(1, Util::isTrue(tok[1]));
|
||
|
break;
|
||
|
case ACTION_STATE_SKIP:
|
||
|
action.setParamI(1, getSkip(tok[1]));
|
||
|
break;
|
||
|
case ACTION_STATE_CFG_DENY:
|
||
|
action.setParamI(1, getCfgDeny(tok[1]));
|
||
|
break;
|
||
|
case ACTION_STATE_DECOR:
|
||
|
case ACTION_STATE_TITLE:
|
||
|
action.setParamS(tok[1]);
|
||
|
break;
|
||
|
};
|
||
|
} else {
|
||
|
switch (action.getParamI(0)) {
|
||
|
case ACTION_STATE_MAXIMIZED:
|
||
|
action.setParamI(1, 1);
|
||
|
action.setParamI(2, 1);
|
||
|
break;
|
||
|
default:
|
||
|
// do nothing
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
//! @brief
|
||
|
bool
|
||
|
Config::parseActions(const std::string &action_string, ActionEvent &ae, uint mask)
|
||
|
{
|
||
|
vector<string> tok;
|
||
|
vector<string>::iterator it;
|
||
|
Action action;
|
||
|
|
||
|
// reset the action event
|
||
|
ae.action_list.clear();
|
||
|
|
||
|
// chop the string up separating the actions
|
||
|
if (Util::splitString(action_string, tok, ";")) {
|
||
|
for (it = tok.begin(); it != tok.end(); ++it) {
|
||
|
if (parseAction(*it, action, mask)) {
|
||
|
ae.action_list.push_back(action);
|
||
|
action.clear();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
//! @brief
|
||
|
bool
|
||
|
Config::parseActionEvent(CfgParser::Entry *section, ActionEvent &ae, uint mask, bool button)
|
||
|
{
|
||
|
CfgParser::Entry *value = section->find_entry("ACTIONS");
|
||
|
if (! value && section->get_section()) {
|
||
|
value = section->get_section()->find_entry("ACTIONS");
|
||
|
}
|
||
|
|
||
|
if (! value) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
string str_button = section->get_value();
|
||
|
if (! str_button.size()) {
|
||
|
if ((ae.type == MOUSE_EVENT_ENTER) || (ae.type == MOUSE_EVENT_LEAVE)) {
|
||
|
str_button = "1";
|
||
|
} else {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool ok;
|
||
|
if (button) {
|
||
|
ok = parseButton(str_button, ae.mod, ae.sym);
|
||
|
} else {
|
||
|
ok = parseKey(str_button, ae.mod, ae.sym);
|
||
|
}
|
||
|
|
||
|
if (ok) {
|
||
|
return parseActions(value->get_value(), ae, mask);
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
//! @brief
|
||
|
bool
|
||
|
Config::parseMoveResizeAction(const std::string &action_string, Action &action)
|
||
|
{
|
||
|
vector<string> tok;
|
||
|
|
||
|
// Chop the string up separating the actions.
|
||
|
if (Util::splitString(action_string, tok, " \t", 2)) {
|
||
|
action.setAction(ParseUtil::getValue<MoveResizeActionType>(tok[0],
|
||
|
_moveresize_map));
|
||
|
if (action.getAction() != NO_MOVERESIZE_ACTION) {
|
||
|
if (tok.size() == 2) { // we got enough tok for a paremeter
|
||
|
switch (action.getAction()) {
|
||
|
case MOVE_HORIZONTAL:
|
||
|
case MOVE_VERTICAL:
|
||
|
case RESIZE_HORIZONTAL:
|
||
|
case RESIZE_VERTICAL:
|
||
|
case MOVE_SNAP:
|
||
|
action.setParamI(0, strtol(tok[1].c_str(), 0, 10));
|
||
|
break;
|
||
|
default:
|
||
|
// Do nothing.
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
//! @brief
|
||
|
bool
|
||
|
Config::parseMoveResizeActions(const std::string &action_string, ActionEvent& ae)
|
||
|
{
|
||
|
vector<string> tok;
|
||
|
vector<string>::iterator it;
|
||
|
Action action;
|
||
|
|
||
|
// reset the action event
|
||
|
ae.action_list.clear();
|
||
|
|
||
|
// chop the string up separating the actions
|
||
|
if (Util::splitString(action_string, tok, ";")) {
|
||
|
for (it = tok.begin(); it != tok.end(); ++it) {
|
||
|
if (parseMoveResizeAction(*it, action)) {
|
||
|
ae.action_list.push_back(action);
|
||
|
action.clear();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
//! @brief Parses MoveResize Event.
|
||
|
bool
|
||
|
Config::parseMoveResizeEvent(CfgParser::Entry *section, ActionEvent& ae)
|
||
|
{
|
||
|
CfgParser::Entry *value;
|
||
|
|
||
|
if (! section->get_value().size ()) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if (parseKey(section->get_value(), ae.mod, ae.sym)) {
|
||
|
value = section->get_section()->find_entry("ACTIONS");
|
||
|
if (value) {
|
||
|
return parseMoveResizeActions(value->get_value(), ae);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
//! @brief
|
||
|
bool
|
||
|
Config::parseInputDialogAction(const std::string &val, Action &action)
|
||
|
{
|
||
|
action.setAction(ParseUtil::getValue<InputDialogAction>(val, _inputdialog_map));
|
||
|
return (action.getAction() != INPUT_NO_ACTION);
|
||
|
}
|
||
|
|
||
|
//! @brief
|
||
|
bool
|
||
|
Config::parseInputDialogActions(const std::string &actions, ActionEvent &ae)
|
||
|
{
|
||
|
vector<string> tok;
|
||
|
vector<string>::iterator it;
|
||
|
Action action;
|
||
|
|
||
|
// reset the action event
|
||
|
ae.action_list.clear();
|
||
|
|
||
|
// chop the string up separating the actions
|
||
|
if (Util::splitString(actions, tok, ";")) {
|
||
|
for (it = tok.begin(); it != tok.end(); ++it) {
|
||
|
if (parseInputDialogAction(*it, action)) {
|
||
|
ae.action_list.push_back(action);
|
||
|
action.clear();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
|
||
|
}
|
||
|
|
||
|
//! @brief Parses InputDialog Event.
|
||
|
bool
|
||
|
Config::parseInputDialogEvent(CfgParser::Entry *section, ActionEvent &ae)
|
||
|
{
|
||
|
CfgParser::Entry *value;
|
||
|
|
||
|
if (! section->get_value().size()) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if (parseKey(section->get_value(), ae.mod, ae.sym)) {
|
||
|
value = section->get_section()->find_entry("ACTIONS");
|
||
|
if (value) {
|
||
|
return parseInputDialogActions(value->get_value(), ae);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get mask for handling menu events.
|
||
|
*/
|
||
|
uint
|
||
|
Config::getMenuMask(const std::string &mask)
|
||
|
{
|
||
|
uint mask_return = 0, val;
|
||
|
|
||
|
vector<string> tok;
|
||
|
Util::splitString(mask, tok, " \t");
|
||
|
|
||
|
vector<string>::iterator it(tok.begin());
|
||
|
for (; it != tok.end(); ++it) {
|
||
|
val = ParseUtil::getValue<MouseEventType>(*it, _mouse_event_map);
|
||
|
if (val != MOUSE_EVENT_NO) {
|
||
|
mask_return |= val;
|
||
|
}
|
||
|
}
|
||
|
return mask_return;
|
||
|
}
|
||
|
|
||
|
//! @brief
|
||
|
bool
|
||
|
Config::parseMenuAction(const std::string &action_string, Action &action)
|
||
|
{
|
||
|
vector<string> tok;
|
||
|
|
||
|
// chop the string up separating the actions
|
||
|
if (Util::splitString(action_string, tok, " \t", 2)) {
|
||
|
action.setAction(ParseUtil::getValue<ActionType>(tok[0], _menu_action_map));
|
||
|
if (action.getAction() != ACTION_NO) {
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
//! @brief
|
||
|
bool
|
||
|
Config::parseMenuActions(const std::string &actions, ActionEvent &ae)
|
||
|
{
|
||
|
vector<string> tok;
|
||
|
vector<string>::iterator it;
|
||
|
Action action;
|
||
|
|
||
|
// reset the action event
|
||
|
ae.action_list.clear();
|
||
|
|
||
|
// chop the string up separating the actions
|
||
|
if (Util::splitString(actions, tok, ";")) {
|
||
|
for (it = tok.begin(); it != tok.end(); ++it) {
|
||
|
if (parseMenuAction(*it, action)) {
|
||
|
ae.action_list.push_back(action);
|
||
|
action.clear();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
//! @brief Parses MenuEvent.
|
||
|
bool
|
||
|
Config::parseMenuEvent(CfgParser::Entry *section, ActionEvent& ae)
|
||
|
{
|
||
|
CfgParser::Entry *value;
|
||
|
|
||
|
if (! section->get_value().size()) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if (parseKey(section->get_value(), ae.mod, ae.sym)) {
|
||
|
value = section->get_section()->find_entry("ACTIONS");
|
||
|
if (value) {
|
||
|
return parseMenuActions(value->get_value(), ae);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
//! @brief
|
||
|
uint
|
||
|
Config::getMouseButton(const std::string &button)
|
||
|
{
|
||
|
uint btn;
|
||
|
|
||
|
if (button.size() == 1) { // it's a button
|
||
|
btn = unsigned(strtol(button.c_str(), 0, 10));
|
||
|
} else if (strcasecmp(button.c_str(), "ANY") == 0) { // any button
|
||
|
btn = BUTTON_ANY;
|
||
|
} else {
|
||
|
btn = BUTTON_NO;
|
||
|
}
|
||
|
|
||
|
if (btn > BUTTON_NO) {
|
||
|
btn = BUTTON_NO;
|
||
|
}
|
||
|
|
||
|
return btn;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Load main configuration file, priority as follows:
|
||
|
*
|
||
|
* 1. Load command line specified file.
|
||
|
* 2. Load ~/.pekwm/config
|
||
|
* 3. Copy configuration and load ~/.pekwm/config
|
||
|
* 4. Load system configuration
|
||
|
*/
|
||
|
bool
|
||
|
Config::tryHardLoadConfig(CfgParser &cfg, std::string &file)
|
||
|
{
|
||
|
bool success = false;
|
||
|
|
||
|
// Try loading command line specified file.
|
||
|
if (file.size()) {
|
||
|
success = cfg.parse(file, CfgParserSource::SOURCE_FILE, true);
|
||
|
}
|
||
|
|
||
|
// Try loading ~/.pekwm/config
|
||
|
if (! success) {
|
||
|
file = string(getenv("HOME")) + string("/.pekwm/config");
|
||
|
success = cfg.parse(file, CfgParserSource::SOURCE_FILE, true);
|
||
|
|
||
|
// Copy cfg files to ~/.pekwm and try loading ~/.pekwm/config again.
|
||
|
if (! success) {
|
||
|
copyConfigFiles();
|
||
|
success = cfg.parse(file, CfgParserSource::SOURCE_FILE, true);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Try loading system configuration files.
|
||
|
if (! success) {
|
||
|
file = string(SYSCONFDIR "/config");
|
||
|
success = cfg.parse(file, CfgParserSource::SOURCE_FILE, true);
|
||
|
}
|
||
|
|
||
|
return success;
|
||
|
}
|
||
|
|
||
|
//! @brief Populates the ~/.pekwm/ dir with config files
|
||
|
void
|
||
|
Config::copyConfigFiles(void)
|
||
|
{
|
||
|
string cfg_dir = getenv("HOME") + string("/.pekwm");
|
||
|
|
||
|
string cfg_file = cfg_dir + string("/config");
|
||
|
string keys_file = cfg_dir + string("/keys");
|
||
|
string mouse_file = cfg_dir + string("/mouse");
|
||
|
string menu_file = cfg_dir + string("/menu");
|
||
|
string autoprops_file = cfg_dir + string("/autoproperties");
|
||
|
string start_file = cfg_dir + string("/start");
|
||
|
string vars_file = cfg_dir + string("/vars");
|
||
|
string themes_dir = cfg_dir + string("/themes");
|
||
|
|
||
|
bool cp_config, cp_keys, cp_mouse, cp_menu;
|
||
|
bool cp_autoprops, cp_start, cp_vars;
|
||
|
bool make_themes = false;
|
||
|
cp_config = cp_keys = cp_mouse = cp_menu = false;
|
||
|
cp_autoprops = cp_start = cp_vars = false;
|
||
|
|
||
|
struct stat stat_buf;
|
||
|
// check and see if we already have a ~/.pekwm/ directory
|
||
|
if (stat(cfg_dir.c_str(), &stat_buf) == 0) {
|
||
|
// is it a dir or file?
|
||
|
if (! S_ISDIR(stat_buf.st_mode)) {
|
||
|
cerr << cfg_dir << " already exists and isn't a directory" << endl
|
||
|
<< "Can't copy config files !" << endl;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// we already have a directory, see if it's writeable and executable
|
||
|
bool cfg_dir_ok = false;
|
||
|
|
||
|
if (getuid() == stat_buf.st_uid) {
|
||
|
if ((stat_buf.st_mode&S_IWUSR) && (stat_buf.st_mode&(S_IXUSR))) {
|
||
|
cfg_dir_ok = true;
|
||
|
}
|
||
|
}
|
||
|
if (! cfg_dir_ok) {
|
||
|
if (getgid() == stat_buf.st_gid) {
|
||
|
if ((stat_buf.st_mode&S_IWGRP) && (stat_buf.st_mode&(S_IXGRP))) {
|
||
|
cfg_dir_ok = true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (! cfg_dir_ok) {
|
||
|
if (! (stat_buf.st_mode&S_IWOTH) || ! (stat_buf.st_mode&(S_IXOTH))) {
|
||
|
cerr << "You don't have the rights to add files to the: " << cfg_dir
|
||
|
<< " directory! Therefor I can't copy the config files!" << endl;
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// we apparently could write and exec that dir, now see if we have any
|
||
|
// files in it
|
||
|
if (stat(cfg_file.c_str(), &stat_buf))
|
||
|
cp_config = true;
|
||
|
if (stat(keys_file.c_str(), &stat_buf))
|
||
|
cp_keys = true;
|
||
|
if (stat(mouse_file.c_str(), &stat_buf))
|
||
|
cp_mouse = true;
|
||
|
if (stat(menu_file.c_str(), &stat_buf))
|
||
|
cp_menu = true;
|
||
|
if (stat(autoprops_file.c_str(), &stat_buf))
|
||
|
cp_autoprops = true;
|
||
|
if (stat(start_file.c_str(), &stat_buf))
|
||
|
cp_start = true;
|
||
|
if (stat(vars_file.c_str(), &stat_buf))
|
||
|
cp_vars = true;
|
||
|
if (stat(themes_dir.c_str(), &stat_buf)) {
|
||
|
make_themes = true;
|
||
|
}
|
||
|
} else { // we didn't have a ~/.pekwm directory already, lets create one
|
||
|
if (mkdir(cfg_dir.c_str(), 0700)) {
|
||
|
cerr << "Can't create " << cfg_dir << " directory!" << endl;
|
||
|
cerr << "Can't copy config files !" << endl;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
cp_config = cp_keys = cp_mouse = cp_menu = true;
|
||
|
cp_autoprops = cp_start = cp_vars = true;
|
||
|
make_themes = true;
|
||
|
}
|
||
|
|
||
|
if (cp_config) {
|
||
|
Util::copyTextFile(SYSCONFDIR "/config", cfg_file);
|
||
|
}
|
||
|
if (cp_keys) {
|
||
|
Util::copyTextFile(SYSCONFDIR "/keys", keys_file);
|
||
|
}
|
||
|
if (cp_mouse) {
|
||
|
Util::copyTextFile(SYSCONFDIR "/mouse", mouse_file);
|
||
|
}
|
||
|
if (cp_menu) {
|
||
|
Util::copyTextFile(SYSCONFDIR "/menu", menu_file);
|
||
|
}
|
||
|
if (cp_autoprops) {
|
||
|
Util::copyTextFile(SYSCONFDIR "/autoproperties", autoprops_file);
|
||
|
}
|
||
|
if (cp_start) {
|
||
|
Util::copyTextFile(SYSCONFDIR "/start", start_file);
|
||
|
}
|
||
|
if (cp_vars) {
|
||
|
Util::copyTextFile(SYSCONFDIR "/vars", vars_file);
|
||
|
}
|
||
|
if (make_themes) {
|
||
|
mkdir(themes_dir.c_str(), 0700);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Parses mouse configuration file.
|
||
|
*/
|
||
|
bool
|
||
|
Config::loadMouseConfig(const std::string &mouse_file)
|
||
|
{
|
||
|
if (! Util::requireReload(_mouse_state, mouse_file)) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
CfgParser mouse_cfg;
|
||
|
if (! mouse_cfg.parse(mouse_file, CfgParserSource::SOURCE_FILE, true)
|
||
|
&& ! mouse_cfg.parse(SYSCONFDIR "/mouse", CfgParserSource::SOURCE_FILE, true)) {
|
||
|
_mouse_state.clear();
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// Clear state if load failed or dynamic content.
|
||
|
if (mouse_cfg.is_dynamic_content()) {
|
||
|
_mouse_state.clear();
|
||
|
} else {
|
||
|
_mouse_state = mouse_cfg.get_file_list();
|
||
|
}
|
||
|
|
||
|
// Make sure old actions get unloaded.
|
||
|
map<MouseActionListName, list<ActionEvent>* >::iterator it;
|
||
|
for (it = _mouse_action_map.begin(); it != _mouse_action_map.end(); ++it) {
|
||
|
it->second->clear();
|
||
|
}
|
||
|
|
||
|
CfgParser::Entry *section;
|
||
|
|
||
|
section = mouse_cfg.get_entry_root()->find_section("FRAMETITLE");
|
||
|
if (section) {
|
||
|
parseButtons(section, _mouse_action_map[MOUSE_ACTION_LIST_TITLE_FRAME], FRAME_OK);
|
||
|
}
|
||
|
|
||
|
section = mouse_cfg.get_entry_root()->find_section("OTHERTITLE");
|
||
|
if (section) {
|
||
|
parseButtons(section, _mouse_action_map[MOUSE_ACTION_LIST_TITLE_OTHER], FRAME_OK);
|
||
|
}
|
||
|
|
||
|
section = mouse_cfg.get_entry_root()->find_section("CLIENT");
|
||
|
if (section) {
|
||
|
parseButtons(section, _mouse_action_map[MOUSE_ACTION_LIST_CHILD_FRAME], CLIENT_OK);
|
||
|
}
|
||
|
|
||
|
section = mouse_cfg.get_entry_root()->find_section("ROOT");
|
||
|
if (section) {
|
||
|
parseButtons(section, _mouse_action_map[MOUSE_ACTION_LIST_ROOT], ROOTCLICK_OK);
|
||
|
}
|
||
|
|
||
|
section = mouse_cfg.get_entry_root()->find_section("MENU");
|
||
|
if (section) {
|
||
|
parseButtons(section, _mouse_action_map[MOUSE_ACTION_LIST_MENU], FRAME_OK);
|
||
|
}
|
||
|
|
||
|
section = mouse_cfg.get_entry_root()->find_section("OTHER");
|
||
|
if (section) {
|
||
|
parseButtons(section, _mouse_action_map[MOUSE_ACTION_LIST_OTHER], FRAME_OK);
|
||
|
}
|
||
|
|
||
|
section = mouse_cfg.get_entry_root()->find_section("SCREENEDGE");
|
||
|
if (section) {
|
||
|
CfgParser::iterator edge_it(section->begin());
|
||
|
for (; edge_it != section->end(); ++edge_it) {
|
||
|
uint pos = ParseUtil::getValue<DirectionType>((*edge_it)->get_name(), _direction_map);
|
||
|
|
||
|
if (pos != SCREEN_EDGE_NO) {
|
||
|
parseButtons((*edge_it)->get_section(), getEdgeListFromPosition(pos), SCREEN_EDGE_OK);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
section = mouse_cfg.get_entry_root()->find_section("BORDER");
|
||
|
if (section) {
|
||
|
CfgParser::iterator border_it(section->begin());
|
||
|
for (; border_it != section->end(); ++border_it) {
|
||
|
uint pos = ParseUtil::getValue<BorderPosition>((*border_it)->get_name(), _borderpos_map);
|
||
|
if (pos != BORDER_NO_POS) {
|
||
|
parseButtons((*border_it)->get_section(), getBorderListFromPosition(pos), FRAME_BORDER_OK);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
//! @brief Parses mouse config section, like FRAME
|
||
|
void
|
||
|
Config::parseButtons(CfgParser::Entry *section, std::list<ActionEvent>* mouse_list, ActionOk action_ok)
|
||
|
{
|
||
|
if (! section || ! mouse_list) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
ActionEvent ae;
|
||
|
CfgParser::Entry *value;
|
||
|
|
||
|
CfgParser::iterator it(section->begin());
|
||
|
for (; it != section->end(); ++it) {
|
||
|
if (! (*it)->get_section()) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
ae.type = ParseUtil::getValue<MouseEventType>((*it)->get_name(), _mouse_event_map);
|
||
|
|
||
|
if (ae.type == MOUSE_EVENT_NO) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (ae.type == MOUSE_EVENT_MOTION) {
|
||
|
value = (*it)->get_section()->find_entry("THRESHOLD");
|
||
|
if (value) {
|
||
|
ae.threshold = strtol(value->get_value().c_str(), 0, 10);
|
||
|
} else {
|
||
|
ae.threshold = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (parseActionEvent((*it), ae, action_ok, true)) {
|
||
|
mouse_list->push_back(ae);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// frame border configuration
|
||
|
|
||
|
list<ActionEvent>*
|
||
|
Config::getBorderListFromPosition(uint pos)
|
||
|
{
|
||
|
list<ActionEvent> *ret = 0;
|
||
|
|
||
|
switch (pos) {
|
||
|
case BORDER_TOP_LEFT:
|
||
|
ret = _mouse_action_map[MOUSE_ACTION_LIST_BORDER_TL];
|
||
|
break;
|
||
|
case BORDER_TOP:
|
||
|
ret = _mouse_action_map[MOUSE_ACTION_LIST_BORDER_T];
|
||
|
break;
|
||
|
case BORDER_TOP_RIGHT:
|
||
|
ret = _mouse_action_map[MOUSE_ACTION_LIST_BORDER_TR];
|
||
|
break;
|
||
|
case BORDER_LEFT:
|
||
|
ret = _mouse_action_map[MOUSE_ACTION_LIST_BORDER_L];
|
||
|
break;
|
||
|
case BORDER_RIGHT:
|
||
|
ret = _mouse_action_map[MOUSE_ACTION_LIST_BORDER_R];
|
||
|
break;
|
||
|
case BORDER_BOTTOM_LEFT:
|
||
|
ret = _mouse_action_map[MOUSE_ACTION_LIST_BORDER_BL];
|
||
|
break;
|
||
|
case BORDER_BOTTOM:
|
||
|
ret = _mouse_action_map[MOUSE_ACTION_LIST_BORDER_B];
|
||
|
break;
|
||
|
case BORDER_BOTTOM_RIGHT:
|
||
|
ret = _mouse_action_map[MOUSE_ACTION_LIST_BORDER_BR];
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
list<ActionEvent>*
|
||
|
Config::getEdgeListFromPosition(uint pos)
|
||
|
{
|
||
|
list<ActionEvent> *ret = 0;
|
||
|
|
||
|
switch (pos) {
|
||
|
case SCREEN_EDGE_TOP:
|
||
|
ret = _mouse_action_map[MOUSE_ACTION_LIST_EDGE_T];
|
||
|
break;
|
||
|
case SCREEN_EDGE_BOTTOM:
|
||
|
ret = _mouse_action_map[MOUSE_ACTION_LIST_EDGE_B];
|
||
|
break;
|
||
|
case SCREEN_EDGE_LEFT:
|
||
|
ret = _mouse_action_map[MOUSE_ACTION_LIST_EDGE_L];
|
||
|
break;
|
||
|
case SCREEN_EDGE_RIGHT:
|
||
|
ret = _mouse_action_map[MOUSE_ACTION_LIST_EDGE_R];
|
||
|
break;
|
||
|
};
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
|
||
|
//! @brief Parses workspace number
|
||
|
int
|
||
|
Config::parseWorkspaceNumber(const std::string &workspace)
|
||
|
{
|
||
|
// Get workspace looking for relative numbers
|
||
|
uint num = ParseUtil::getValue<WorkspaceChangeType>(workspace, _workspace_change_map);
|
||
|
|
||
|
if (num == WORKSPACE_NO) {
|
||
|
// Workspace isn't relative, check for 2x2 and ordinary specification
|
||
|
vector<string> tok;
|
||
|
if (Util::splitString(workspace, tok, "x", 2, true) == 2) {
|
||
|
uint row = strtol(tok[0].c_str(), 0, 10) - 1;
|
||
|
uint col = strtol(tok[1].c_str(), 0, 10) - 1;
|
||
|
|
||
|
num = _screen_workspaces_per_row * row + col;
|
||
|
|
||
|
} else {
|
||
|
num = strtol(workspace.c_str(), 0, 10) - 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Fallback to 0 if something went wrong
|
||
|
if (num < 0) {
|
||
|
num = 0;
|
||
|
}
|
||
|
|
||
|
return num;
|
||
|
}
|
||
|
|
||
|
#ifdef OPACITY
|
||
|
//! @brief Parses a string which contains two opacity values
|
||
|
bool
|
||
|
Config::parseOpacity(const std::string value, uint &focused, uint &unfocused)
|
||
|
{
|
||
|
std::vector<string> tokens;
|
||
|
switch ((Util::splitString(value, tokens, " ,", 2))) {
|
||
|
case 2:
|
||
|
focused = std::atoi(tokens.at(0).c_str());
|
||
|
unfocused = std::atoi(tokens.at(1).c_str());
|
||
|
break;
|
||
|
case 1:
|
||
|
focused = unfocused = std::atoi(tokens.at(0).c_str());
|
||
|
break;
|
||
|
default:
|
||
|
return false;
|
||
|
}
|
||
|
CONV_OPACITY(focused);
|
||
|
CONV_OPACITY(unfocused);
|
||
|
return true;
|
||
|
}
|
||
|
#endif // OPACITY
|