mirror of
https://github.com/edeproject/ede.git
synced 2023-08-10 21:13:03 +03:00
917 lines
29 KiB
C++
917 lines
29 KiB
C++
//
|
|
// AutoProperties.cc for pekwm
|
|
// Copyright © 2003-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 <algorithm>
|
|
#include <vector>
|
|
#include <iostream>
|
|
|
|
#include "AutoProperties.hh"
|
|
#include "Config.hh"
|
|
#include "Util.hh"
|
|
|
|
using std::cerr;
|
|
using std::endl;
|
|
using std::find;
|
|
using std::list;
|
|
using std::map;
|
|
using std::string;
|
|
using std::vector;
|
|
using std::strtol;
|
|
|
|
AutoProperties *AutoProperties::_instance = 0;
|
|
|
|
//! @brief Constructor for AutoProperties class
|
|
AutoProperties::AutoProperties(void)
|
|
: _extended(false), _harbour_sort(false),
|
|
_apply_on_start(true)
|
|
{
|
|
#ifdef DEBUG
|
|
if (_instance) {
|
|
cerr << __FILE__ << "@" << __LINE__ << ": "
|
|
<< "AutoProperties(" << this << ")::AutoProperties()" << endl
|
|
<< " *** _instance already set: " << _instance << endl;
|
|
}
|
|
#endif // DEBUG
|
|
_instance = this;
|
|
|
|
// fill parsing maps
|
|
_apply_on_map[""] = APPLY_ON_NONE;
|
|
_apply_on_map["START"] = APPLY_ON_START;
|
|
_apply_on_map["NEW"] = APPLY_ON_NEW;
|
|
_apply_on_map["RELOAD"] = APPLY_ON_RELOAD;
|
|
_apply_on_map["WORKSPACE"] = APPLY_ON_WORKSPACE;
|
|
_apply_on_map["TRANSIENT"] = APPLY_ON_TRANSIENT;
|
|
_apply_on_map["TRANSIENTONLY"] = APPLY_ON_TRANSIENT_ONLY;
|
|
|
|
// global properties
|
|
_property_map[""] = AP_NO_PROPERTY;
|
|
_property_map["WORKSPACE"] = AP_WORKSPACE;
|
|
_property_map["PROPERTY"] = AP_PROPERTY;
|
|
_property_map["STICKY"] = AP_STICKY;
|
|
_property_map["SHADED"] = AP_SHADED;
|
|
_property_map["MAXIMIZEDVERTICAL"] = AP_MAXIMIZED_VERTICAL;
|
|
_property_map["MAXIMIZEDHORIZONTAL"] = AP_MAXIMIZED_HORIZONTAL;
|
|
_property_map["ICONIFIED"] = AP_ICONIFIED;
|
|
_property_map["BORDER"] = AP_BORDER;
|
|
_property_map["TITLEBAR"] = AP_TITLEBAR;
|
|
_property_map["FRAMEGEOMETRY"] = AP_FRAME_GEOMETRY;
|
|
_property_map["CLIENTGEOMETRY"] = AP_CLIENT_GEOMETRY;
|
|
_property_map["LAYER"] = AP_LAYER;
|
|
_property_map["SKIP"] = AP_SKIP;
|
|
_property_map["FULLSCREEN"] = AP_FULLSCREEN;
|
|
_property_map["PLACENEW"] = AP_PLACE_NEW;
|
|
_property_map["FOCUSNEW"] = AP_FOCUS_NEW;
|
|
_property_map["FOCUSABLE"] = AP_FOCUSABLE;
|
|
_property_map["CFGDENY"] = AP_CFG_DENY;
|
|
_property_map["ALLOWEDACTIONS"] = AP_ALLOWED_ACTIONS;
|
|
_property_map["DISALLOWEDACTIONS"] = AP_DISALLOWED_ACTIONS;
|
|
#ifdef OPACITY
|
|
_property_map["OPACITY"] = AP_OPACITY;
|
|
#endif // OPACITY
|
|
|
|
// group properties
|
|
_group_property_map[""] = AP_NO_PROPERTY;
|
|
_group_property_map["SIZE"] = AP_GROUP_SIZE;
|
|
_group_property_map["BEHIND"] = AP_GROUP_BEHIND;
|
|
_group_property_map["FOCUSEDFIRST"] = AP_GROUP_FOCUSED_FIRST;
|
|
_group_property_map["GLOBAL"] = AP_GROUP_GLOBAL;
|
|
_group_property_map["RAISE"] = AP_GROUP_RAISE;
|
|
|
|
// window type map
|
|
_window_type_map[""] = WINDOW_TYPE;
|
|
_window_type_map["DESKTOP"] = WINDOW_TYPE_DESKTOP;
|
|
_window_type_map["DOCK"] = WINDOW_TYPE_DOCK;
|
|
_window_type_map["TOOLBAR"] = WINDOW_TYPE_TOOLBAR;
|
|
_window_type_map["MENU"] = WINDOW_TYPE_MENU;
|
|
_window_type_map["UTILITY"] = WINDOW_TYPE_UTILITY;
|
|
_window_type_map["SPLASH"] = WINDOW_TYPE_SPLASH;
|
|
_window_type_map["DIALOG"] = WINDOW_TYPE_DIALOG;
|
|
_window_type_map["NORMAL"] = WINDOW_TYPE_NORMAL;
|
|
}
|
|
|
|
//! @brief Destructor for AutoProperties class
|
|
AutoProperties::~AutoProperties(void)
|
|
{
|
|
unload();
|
|
_instance = 0;
|
|
}
|
|
|
|
//! @brief Loads the autoprop config file.
|
|
bool
|
|
AutoProperties::load(void)
|
|
{
|
|
string cfg_file(Config::instance()->getAutoPropsFile());
|
|
if (! Util::requireReload(_cfg_state, cfg_file)) {
|
|
return false;
|
|
}
|
|
|
|
// dealloc memory
|
|
unload();
|
|
|
|
CfgParser a_cfg;
|
|
if (! a_cfg.parse(cfg_file, CfgParserSource::SOURCE_FILE, false)) {
|
|
cfg_file = SYSCONFDIR "/autoproperties";
|
|
if (! a_cfg.parse (cfg_file, CfgParserSource::SOURCE_FILE, false)) {
|
|
setDefaultTypeProperties();
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Setup template parsing if requested
|
|
loadRequire(a_cfg, cfg_file);
|
|
|
|
if (a_cfg.is_dynamic_content()) {
|
|
_cfg_state.clear();
|
|
} else {
|
|
_cfg_state = a_cfg.get_file_list();
|
|
}
|
|
|
|
// reset values
|
|
_apply_on_start = true;
|
|
|
|
vector<string> tokens;
|
|
vector<string>::iterator token_it;
|
|
list<uint> workspaces;
|
|
|
|
CfgParser::iterator it(a_cfg.get_entry_root()->begin());
|
|
for (; it != a_cfg.get_entry_root()->end(); ++it) {
|
|
if (*(*it) == "PROPERTY") {
|
|
parseAutoProperty(*it, 0);
|
|
} else if (*(*it) == "TITLERULES") {
|
|
parseTitleProperty(*it);
|
|
} else if (*(*it) == "DECORRULES") {
|
|
parseDecorProperty(*it);
|
|
} else if (*(*it) == "TYPERULES") {
|
|
parseTypeProperty(*it);
|
|
} else if (*(*it) == "HARBOUR") {
|
|
parseDockAppProperty(*it);
|
|
} else if (*(*it) == "WORKSPACE") { // Workspace section
|
|
CfgParser::Entry *workspace = (*it)->get_section();
|
|
CfgParser::Entry *value = workspace->find_entry("WORKSPACE");
|
|
if (! value) {
|
|
continue; // Need workspace numbers.
|
|
}
|
|
|
|
tokens.clear();
|
|
if (Util::splitString(value->get_value(), tokens, " \t")) {
|
|
workspaces.clear();
|
|
for (token_it = tokens.begin(); token_it != tokens.end(); ++token_it)
|
|
workspaces.push_back(strtol(token_it->c_str(), 0, 10) - 1);
|
|
|
|
// Get all properties on for these workspaces.
|
|
CfgParser::iterator workspace_it(workspace->begin());
|
|
for (; workspace_it != workspace->end(); ++workspace_it) {
|
|
parseAutoProperty(*workspace_it, &workspaces);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Validate date
|
|
setDefaultTypeProperties();
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Load autoproperties quirks.
|
|
*/
|
|
void
|
|
AutoProperties::loadRequire(CfgParser &a_cfg, std::string &file)
|
|
{
|
|
CfgParser::Entry *section;
|
|
|
|
// Look for requires section,
|
|
section = a_cfg.get_entry_root()->find_section("REQUIRE");
|
|
if (section) {
|
|
list<CfgParserKey*> key_list;
|
|
|
|
key_list.push_back(new CfgParserKeyBool("TEMPLATES", _extended, false));
|
|
section->parse_key_values(key_list.begin(), key_list.end());
|
|
for_each(key_list.begin(), key_list.end(), Util::Free<CfgParserKey*>());
|
|
|
|
// Re-load configuration with templates enabled.
|
|
if (_extended) {
|
|
a_cfg.clear(true);
|
|
a_cfg.parse(file, CfgParserSource::SOURCE_FILE, true);
|
|
}
|
|
} else {
|
|
_extended = false;
|
|
}
|
|
}
|
|
|
|
//! @brief Frees allocated memory
|
|
void
|
|
AutoProperties::unload(void)
|
|
{
|
|
list<Property*>::iterator it;
|
|
|
|
// remove auto properties
|
|
for (it = _prop_list.begin(); it != _prop_list.end(); ++it) {
|
|
delete *it;
|
|
}
|
|
_prop_list.clear();
|
|
|
|
// remove title properties
|
|
for (it = _title_prop_list.begin(); it != _title_prop_list.end(); ++it) {
|
|
delete *it;
|
|
}
|
|
_title_prop_list.clear();
|
|
|
|
// remove decor properties
|
|
for (it = _decor_prop_list.begin(); it != _decor_prop_list.end(); ++it) {
|
|
delete *it;
|
|
}
|
|
_decor_prop_list.clear();
|
|
|
|
// remove dock app properties
|
|
for (it = _dock_app_prop_list.begin(); it != _dock_app_prop_list.end(); ++it) {
|
|
delete *it;
|
|
}
|
|
_dock_app_prop_list.clear();
|
|
|
|
// remove type properties
|
|
map<AtomName, AutoProperty*>::iterator m_it(_window_type_prop_map.begin());
|
|
for (; m_it != _window_type_prop_map.end(); ++m_it) {
|
|
delete m_it->second;
|
|
}
|
|
_window_type_prop_map.clear();
|
|
}
|
|
|
|
//! @brief Finds a property from the prop_list
|
|
Property*
|
|
AutoProperties::findProperty(const ClassHint* class_hint,
|
|
std::list<Property*>* prop_list, int ws, uint type)
|
|
{
|
|
// Allready remove apply on start
|
|
if (! _apply_on_start && (type == APPLY_ON_START))
|
|
return 0;
|
|
|
|
list<Property*>::iterator it(prop_list->begin());
|
|
list<uint>::iterator w_it;
|
|
|
|
// start searching for a suitable property
|
|
for (; it != prop_list->end(); ++it) {
|
|
// see if the type matches, if we have one
|
|
if ((type != 0) && ! (*it)->isApplyOn(type))
|
|
continue;
|
|
|
|
if (matchAutoClass(*class_hint, *it)) {
|
|
|
|
// make sure it applies on the correct workspace
|
|
if ((*it)->getWsList().size()) {
|
|
w_it = find((*it)->getWsList().begin(), (*it)->getWsList().end(),
|
|
unsigned(ws));
|
|
if (w_it != (*it)->getWsList().end()) {
|
|
return *it;
|
|
}
|
|
} else {
|
|
return *it;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Parse regex_str and set on regex, outputting warning with name if
|
|
* it fails.
|
|
*/
|
|
bool
|
|
AutoProperties::parseRegexpOrWarning(RegexString ®ex, const std::string regex_str, const std::string &name)
|
|
{
|
|
if (! regex_str.size() || regex.parse_match(Util::to_wide_str(regex_str))) {
|
|
return true;
|
|
} else {
|
|
cerr << " *** WARNING: invalid regexp " << regex_str << " for autoproperty " << name << endl;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
//! @brief Parses a property match rule
|
|
//! @param str String to parse.
|
|
//! @param prop Property to place result in.
|
|
//! @param extended Extended syntax including role and title in the name, defaults to true.
|
|
//! @return true on success, else false.
|
|
bool
|
|
AutoProperties::parsePropertyMatch(const std::string &str, Property *prop, bool extended)
|
|
{
|
|
bool status = false;
|
|
|
|
// Format of property matches are regexp,regexp . Split up in class
|
|
// and role regexps.
|
|
vector<string> tokens;
|
|
Util::splitString(str, tokens, ",", extended ? 5 : 2, true);
|
|
|
|
if (tokens.size() >= 2) {
|
|
// Make sure one of the two regexps compiles
|
|
status = parseRegexpOrWarning(prop->getHintName(), tokens[0], "name");
|
|
status = status && parseRegexpOrWarning(prop->getHintClass(), tokens[1], "class");
|
|
}
|
|
|
|
// Parse extended part of regexp, role, title and apply on
|
|
if (status && extended) {
|
|
if (status && tokens.size() > 2) {
|
|
status = parseRegexpOrWarning(prop->getRole(), tokens[2], "role");
|
|
}
|
|
if (status && tokens.size() > 3) {
|
|
status = parseRegexpOrWarning(prop->getTitle(), tokens[3], "title");
|
|
}
|
|
if (status && tokens.size() > 4) {
|
|
parsePropertyApplyOn(tokens[4], prop);
|
|
}
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
//! @brief Parses a cs and sets up a basic property
|
|
bool
|
|
AutoProperties::parseProperty(CfgParser::Entry *section, Property *prop)
|
|
{
|
|
CfgParser::Entry *value;
|
|
|
|
// Get extra matching info.
|
|
value = section->find_entry ("TITLE");
|
|
if (value) {
|
|
parseRegexpOrWarning(prop->getTitle(), value->get_value(), "title");
|
|
}
|
|
value = section->find_entry ("ROLE");
|
|
if (value) {
|
|
parseRegexpOrWarning(prop->getRole(), value->get_value(), "role");
|
|
}
|
|
|
|
// Parse apply on mask.
|
|
value = section->find_entry ("APPLYON");
|
|
if (value) {
|
|
parsePropertyApplyOn(value->get_value(), prop);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Parse property apply on.
|
|
*/
|
|
void
|
|
AutoProperties::parsePropertyApplyOn(const std::string &apply_on, Property *prop)
|
|
{
|
|
vector<string> tokens;
|
|
if ((Util::splitString(apply_on, tokens, " \t", 5))) {
|
|
vector<string>::iterator it(tokens.begin());
|
|
for (; it != tokens.end(); ++it) {
|
|
prop->applyAdd(static_cast<unsigned int>(ParseUtil::getValue<ApplyOn>(*it, _apply_on_map)));
|
|
}
|
|
}
|
|
}
|
|
|
|
//! @brief Parses AutopProperty
|
|
void
|
|
AutoProperties::parseAutoProperty(CfgParser::Entry *section, std::list<uint>* ws)
|
|
{
|
|
// Get sub section
|
|
section = section->get_section();
|
|
if (! section) {
|
|
return;
|
|
}
|
|
|
|
AutoProperty* property = new AutoProperty();
|
|
parsePropertyMatch(section->get_value(), property, _extended);
|
|
|
|
if (parseProperty(section, property)) {
|
|
parseAutoPropertyValue(section, property, ws);
|
|
_prop_list.push_back(property);
|
|
|
|
} else {
|
|
delete property;
|
|
}
|
|
}
|
|
|
|
//! @brief Parses a Group section of the AutoProps
|
|
void
|
|
AutoProperties::parseAutoGroup(CfgParser::Entry *section, AutoProperty* property)
|
|
{
|
|
if (! section) {
|
|
return;
|
|
}
|
|
|
|
if (section->get_value().size()) {
|
|
property->group_name = Util::to_wide_str(section->get_value());
|
|
}
|
|
|
|
PropertyType property_type;
|
|
|
|
CfgParser::iterator it(section->begin());
|
|
for (; it != section->end(); ++it) {
|
|
property_type = ParseUtil::getValue<PropertyType>((*it)->get_name(), _group_property_map);
|
|
|
|
switch (property_type) {
|
|
case AP_GROUP_SIZE:
|
|
property->group_size = strtol((*it)->get_value().c_str(), 0, 10);
|
|
break;
|
|
case AP_GROUP_BEHIND:
|
|
property->group_behind = Util::isTrue((*it)->get_value());
|
|
break;
|
|
case AP_GROUP_FOCUSED_FIRST:
|
|
property->group_focused_first = Util::isTrue((*it)->get_value());
|
|
break;
|
|
case AP_GROUP_GLOBAL:
|
|
property->group_global = Util::isTrue((*it)->get_value());
|
|
break;
|
|
case AP_GROUP_RAISE:
|
|
property->group_raise = Util::isTrue((*it)->get_value());
|
|
break;
|
|
default:
|
|
// do nothing
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Parses a title property section.
|
|
*/
|
|
void
|
|
AutoProperties::parseTitleProperty(CfgParser::Entry *section)
|
|
{
|
|
section = section->get_section();
|
|
|
|
TitleProperty *title_property;
|
|
CfgParser::Entry *title_section;
|
|
|
|
CfgParser::iterator it(section->begin());
|
|
for (; it != section->end(); ++it) {
|
|
title_section = (*it)->get_section();
|
|
if (! title_section) {
|
|
continue;
|
|
}
|
|
|
|
title_property = new TitleProperty();
|
|
parsePropertyMatch(title_section->get_value(), title_property, _extended);
|
|
if (parseProperty(title_section, title_property)) {
|
|
CfgParser::Entry *value = title_section->find_entry("RULE");
|
|
if (value && title_property->getTitleRule().parse_ed_s(Util::to_wide_str(value->get_value()))) {
|
|
_title_prop_list.push_back(title_property);
|
|
title_property = 0;
|
|
}
|
|
}
|
|
|
|
if (title_property) {
|
|
delete title_property;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Parse decor property sections.
|
|
*/
|
|
void
|
|
AutoProperties::parseDecorProperty(CfgParser::Entry *section)
|
|
{
|
|
section = section->get_section();
|
|
|
|
DecorProperty *decor_property;
|
|
CfgParser::Entry *decor_section;
|
|
|
|
CfgParser::iterator it(section->begin());
|
|
for (; it != section->end(); ++it) {
|
|
decor_section = (*it)->get_section ();
|
|
if (! decor_section) {
|
|
continue;
|
|
}
|
|
|
|
decor_property = new DecorProperty();
|
|
parsePropertyMatch(decor_section->get_value (), decor_property, _extended);
|
|
if (parseProperty(decor_section, decor_property)) {
|
|
CfgParser::Entry *value = decor_section->find_entry("DECOR");
|
|
if (value) {
|
|
decor_property->applyAdd(APPLY_ON_START);
|
|
decor_property->setName(value->get_value());
|
|
_decor_prop_list.push_back(decor_property);
|
|
decor_property = 0;
|
|
}
|
|
}
|
|
|
|
if (decor_property) {
|
|
delete decor_property;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Parse dock app properties.
|
|
*/
|
|
void
|
|
AutoProperties::parseDockAppProperty(CfgParser::Entry *section)
|
|
{
|
|
section = section->get_section();
|
|
|
|
// Reset harbour sort, set to true if POSITION property found.
|
|
_harbour_sort = false;
|
|
|
|
DockAppProperty *dock_property;
|
|
CfgParser::Entry *dock_section;
|
|
|
|
CfgParser::iterator it(section->begin());
|
|
for (; it != section->end(); ++it) {
|
|
dock_section = (*it)->get_section();
|
|
if (! dock_section) {
|
|
continue;
|
|
}
|
|
|
|
dock_property = new DockAppProperty();
|
|
parsePropertyMatch(dock_section->get_value(), dock_property, _extended);
|
|
if (parseProperty(dock_section, dock_property)) {
|
|
CfgParser::Entry *value = dock_section->find_entry("POSITION");
|
|
if (value) {
|
|
_harbour_sort = true;
|
|
|
|
int position = strtol(value->get_value().c_str(), 0, 10);
|
|
dock_property->setPosition(position);
|
|
_decor_prop_list.push_back(dock_property);
|
|
dock_property = 0;
|
|
}
|
|
}
|
|
|
|
if (dock_property) {
|
|
delete dock_property;
|
|
}
|
|
}
|
|
}
|
|
|
|
//! @brief Parse type auto properties.
|
|
//! @param section Section containing properties.
|
|
void
|
|
AutoProperties::parseTypeProperty(CfgParser::Entry *section)
|
|
{
|
|
// Get sub section
|
|
section = section->get_section();
|
|
|
|
AtomName atom;
|
|
AutoProperty *type_property;
|
|
CfgParser::Entry *type_section;
|
|
map<AtomName, AutoProperty*>::iterator atom_it;
|
|
|
|
// Look for all type properties
|
|
CfgParser::iterator it(section->begin());
|
|
for (; it != section->end(); ++it) {
|
|
type_section = (*it)->get_section();
|
|
if (! type_section) {
|
|
continue;
|
|
}
|
|
|
|
// Create new property and try to parse
|
|
type_property = new AutoProperty();
|
|
atom = ParseUtil::getValue<AtomName>(type_section->get_value(), _window_type_map);
|
|
if (atom == WINDOW_TYPE) {
|
|
cerr << " *** WARNING: unknown type " << type_section->get_value() << " for autoproperty." << endl;
|
|
}
|
|
|
|
if (atom != WINDOW_TYPE && parseProperty(type_section, type_property)) {
|
|
// Parse of match ok, parse values
|
|
parseAutoPropertyValue(type_section, type_property, 0);
|
|
|
|
// Add to list, make sure it does not exist already
|
|
atom_it = _window_type_prop_map.find(atom);
|
|
if (atom_it != _window_type_prop_map.end()) {
|
|
cerr << " *** WARNING: multiple type autoproperties for type "
|
|
<< type_section->get_value() << endl;
|
|
delete atom_it->second;
|
|
}
|
|
_window_type_prop_map[atom] = type_property;
|
|
} else {
|
|
delete type_property;
|
|
}
|
|
}
|
|
}
|
|
|
|
//! @brief Set default values for type auto properties not in configuration.
|
|
void
|
|
AutoProperties::setDefaultTypeProperties(void)
|
|
{
|
|
// DESKTOP
|
|
if (! findWindowTypeProperty(WINDOW_TYPE_DESKTOP)) {
|
|
AutoProperty *prop = new AutoProperty();
|
|
prop->maskAdd(AP_CLIENT_GEOMETRY);
|
|
prop->client_gm_mask =
|
|
XParseGeometry("0x0+0+0",
|
|
&prop->client_gm.x, &prop->client_gm.y,
|
|
&prop->client_gm.width, &prop->client_gm.height);
|
|
prop->maskAdd(AP_STICKY);
|
|
prop->sticky = true;
|
|
prop->maskAdd(AP_TITLEBAR);
|
|
prop->titlebar = false;
|
|
prop->maskAdd(AP_BORDER);
|
|
prop->border = false;
|
|
prop->maskAdd(AP_SKIP);
|
|
prop->skip = SKIP_MENUS|SKIP_FOCUS_TOGGLE|SKIP_SNAP|SKIP_PAGER|SKIP_TASKBAR;
|
|
prop->maskAdd(AP_LAYER);
|
|
prop->layer = LAYER_DESKTOP;
|
|
prop->maskAdd(AP_FOCUSABLE);
|
|
prop->focusable = false;
|
|
prop->maskAdd(AP_DISALLOWED_ACTIONS);
|
|
prop->disallowed_actions = ACTION_ACCESS_MOVE|ACTION_ACCESS_RESIZE;
|
|
|
|
_window_type_prop_map[WINDOW_TYPE_DESKTOP] = prop;
|
|
}
|
|
|
|
// DOCK
|
|
if (! findWindowTypeProperty(WINDOW_TYPE_DOCK)) {
|
|
AutoProperty *prop = new AutoProperty();
|
|
prop->maskAdd(AP_STICKY);
|
|
prop->sticky = true;
|
|
prop->maskAdd(AP_TITLEBAR);
|
|
prop->titlebar = false;
|
|
prop->maskAdd(AP_BORDER);
|
|
prop->border = false;
|
|
prop->maskAdd(AP_SKIP);
|
|
prop->skip = SKIP_MENUS|SKIP_FOCUS_TOGGLE|SKIP_PAGER|SKIP_TASKBAR;
|
|
prop->maskAdd(AP_LAYER);
|
|
prop->layer = LAYER_DOCK;
|
|
prop->maskAdd(AP_FOCUSABLE);
|
|
prop->focusable = false;
|
|
prop->maskAdd(AP_DISALLOWED_ACTIONS);
|
|
prop->disallowed_actions = ACTION_ACCESS_MOVE|ACTION_ACCESS_RESIZE;
|
|
|
|
_window_type_prop_map[WINDOW_TYPE_DOCK] = prop;
|
|
}
|
|
|
|
// TOOLBAR
|
|
if (! findWindowTypeProperty(WINDOW_TYPE_TOOLBAR)) {
|
|
AutoProperty *prop = new AutoProperty();
|
|
prop->maskAdd(AP_TITLEBAR);
|
|
prop->titlebar = true;
|
|
prop->maskAdd(AP_BORDER);
|
|
prop->border = true;
|
|
prop->maskAdd(AP_SKIP);
|
|
prop->skip = SKIP_MENUS|SKIP_FOCUS_TOGGLE|SKIP_PAGER|SKIP_TASKBAR;
|
|
|
|
_window_type_prop_map[WINDOW_TYPE_TOOLBAR] = prop;
|
|
}
|
|
|
|
// MENU
|
|
if (! findWindowTypeProperty(WINDOW_TYPE_MENU)) {
|
|
AutoProperty *prop = new AutoProperty();
|
|
prop->maskAdd(AP_TITLEBAR);
|
|
prop->titlebar = false;
|
|
prop->maskAdd(AP_BORDER);
|
|
prop->border = false;
|
|
prop->maskAdd(AP_SKIP);
|
|
prop->skip = SKIP_MENUS|SKIP_FOCUS_TOGGLE|SKIP_SNAP|SKIP_PAGER|SKIP_TASKBAR;
|
|
|
|
_window_type_prop_map[WINDOW_TYPE_MENU] = prop;
|
|
}
|
|
|
|
// UTILITY
|
|
if (! findWindowTypeProperty(WINDOW_TYPE_UTILITY)) {
|
|
AutoProperty *prop = new AutoProperty();
|
|
prop->maskAdd(AP_TITLEBAR);
|
|
prop->titlebar = true;
|
|
prop->maskAdd(AP_BORDER);
|
|
prop->border = true;
|
|
prop->maskAdd(AP_SKIP);
|
|
prop->skip = SKIP_MENUS|SKIP_FOCUS_TOGGLE|SKIP_SNAP;
|
|
|
|
_window_type_prop_map[WINDOW_TYPE_UTILITY] = prop;
|
|
}
|
|
|
|
// SPLASH
|
|
if (! findWindowTypeProperty(WINDOW_TYPE_SPLASH)) {
|
|
AutoProperty *prop = new AutoProperty();
|
|
prop->maskAdd(AP_TITLEBAR);
|
|
prop->titlebar = false;
|
|
prop->maskAdd(AP_BORDER);
|
|
prop->border = false;
|
|
|
|
_window_type_prop_map[WINDOW_TYPE_SPLASH] = prop;
|
|
}
|
|
}
|
|
|
|
//! @brief Parse AutoProperty value attributes.
|
|
//! @param section Config section to parse.
|
|
//! @param prop Property to store result in.
|
|
//! @param ws List of workspaces to apply property on.
|
|
void
|
|
AutoProperties::parseAutoPropertyValue(CfgParser::Entry *section, AutoProperty *prop, std::list<uint> *ws)
|
|
{
|
|
// Copy workspaces, if any
|
|
if (ws) {
|
|
prop->getWsList().assign(ws->begin(), ws->end());
|
|
}
|
|
|
|
// See if we have a group section
|
|
CfgParser::Entry *group_section(section->find_section ("GROUP"));
|
|
if (group_section) {
|
|
parseAutoGroup(group_section, prop);
|
|
}
|
|
|
|
// start parsing of values
|
|
string name, value;
|
|
vector<string> tokens;
|
|
vector<string>::iterator token_it;
|
|
PropertyType property_type;
|
|
|
|
CfgParser::iterator it(section->begin());
|
|
for (; it != section->end(); ++it) {
|
|
property_type = ParseUtil::getValue<PropertyType>((*it)->get_name(), _property_map);
|
|
|
|
switch (property_type) {
|
|
case AP_STICKY:
|
|
prop->maskAdd(AP_STICKY);
|
|
prop->sticky = Util::isTrue((*it)->get_value());
|
|
break;
|
|
case AP_SHADED:
|
|
prop->maskAdd(AP_SHADED);
|
|
prop->shaded = Util::isTrue((*it)->get_value());
|
|
break;
|
|
case AP_MAXIMIZED_VERTICAL:
|
|
prop->maskAdd(AP_MAXIMIZED_VERTICAL);
|
|
prop->maximized_vertical = Util::isTrue((*it)->get_value());
|
|
break;
|
|
case AP_MAXIMIZED_HORIZONTAL:
|
|
prop->maskAdd(AP_MAXIMIZED_HORIZONTAL);
|
|
prop->maximized_horizontal = Util::isTrue((*it)->get_value());
|
|
break;
|
|
case AP_ICONIFIED:
|
|
prop->maskAdd(AP_ICONIFIED);
|
|
prop->iconified = Util::isTrue((*it)->get_value());
|
|
break;
|
|
case AP_BORDER:
|
|
prop->maskAdd(AP_BORDER);
|
|
prop->border = Util::isTrue((*it)->get_value());
|
|
break;
|
|
case AP_TITLEBAR:
|
|
prop->maskAdd(AP_TITLEBAR);
|
|
prop->titlebar = Util::isTrue((*it)->get_value());
|
|
break;
|
|
case AP_FRAME_GEOMETRY:
|
|
prop->maskAdd(AP_FRAME_GEOMETRY);
|
|
prop->frame_gm_mask =
|
|
XParseGeometry((char*) (*it)->get_value().c_str(),
|
|
&prop->frame_gm.x, &prop->frame_gm.y,
|
|
&prop->frame_gm.width, &prop->frame_gm.height);
|
|
break;
|
|
case AP_CLIENT_GEOMETRY:
|
|
prop->maskAdd(AP_CLIENT_GEOMETRY);
|
|
prop->client_gm_mask =
|
|
XParseGeometry((char*) (*it)->get_value().c_str(),
|
|
&prop->client_gm.x, &prop->client_gm.y,
|
|
&prop->client_gm.width, &prop->client_gm.height);
|
|
break;
|
|
case AP_LAYER:
|
|
prop->layer = Config::instance()->getLayer((*it)->get_value());
|
|
if (prop->layer != LAYER_NONE) {
|
|
prop->maskAdd(AP_LAYER);
|
|
}
|
|
break;
|
|
case AP_WORKSPACE:
|
|
prop->maskAdd(AP_WORKSPACE);
|
|
prop->workspace = unsigned(strtol((*it)->get_value().c_str(), 0, 10) - 1);
|
|
break;
|
|
case AP_SKIP:
|
|
prop->maskAdd(AP_SKIP);
|
|
tokens.clear();
|
|
if ((Util::splitString((*it)->get_value(), tokens, " \t"))) {
|
|
for (token_it = tokens.begin(); token_it != tokens.end(); ++token_it) {
|
|
prop->skip |= Config::instance()->getSkip(*token_it);
|
|
}
|
|
}
|
|
break;
|
|
case AP_FULLSCREEN:
|
|
prop->maskAdd(AP_FULLSCREEN);
|
|
prop->fullscreen = Util::isTrue((*it)->get_value());
|
|
break;
|
|
case AP_PLACE_NEW:
|
|
prop->maskAdd(AP_PLACE_NEW);
|
|
prop->place_new = Util::isTrue((*it)->get_value());
|
|
break;
|
|
case AP_FOCUS_NEW:
|
|
prop->maskAdd(AP_FOCUS_NEW);
|
|
prop->focus_new = Util::isTrue((*it)->get_value());
|
|
break;
|
|
case AP_FOCUSABLE:
|
|
prop->maskAdd(AP_FOCUSABLE);
|
|
prop->focusable = Util::isTrue((*it)->get_value());
|
|
break;
|
|
case AP_CFG_DENY:
|
|
prop->maskAdd(AP_CFG_DENY);
|
|
tokens.clear();
|
|
if ((Util::splitString((*it)->get_value(), tokens, " \t"))) {
|
|
for (token_it = tokens.begin(); token_it != tokens.end(); ++token_it) {
|
|
prop->cfg_deny |= Config::instance()->getCfgDeny(*token_it);
|
|
}
|
|
}
|
|
break;
|
|
case AP_ALLOWED_ACTIONS:
|
|
prop->maskAdd(AP_ALLOWED_ACTIONS);
|
|
Config::instance()->parseActionAccessMask((*it)->get_value(), prop->allowed_actions);
|
|
break;
|
|
case AP_DISALLOWED_ACTIONS:
|
|
prop->maskAdd(AP_DISALLOWED_ACTIONS);
|
|
Config::instance()->parseActionAccessMask((*it)->get_value(), prop->disallowed_actions);
|
|
break;
|
|
#ifdef OPACITY
|
|
case AP_OPACITY:
|
|
prop->maskAdd(AP_OPACITY);
|
|
Config::parseOpacity((*it)->get_value(), prop->focus_opacity, prop->unfocus_opacity);
|
|
break;
|
|
#endif // OPACITY
|
|
default:
|
|
// do nothing
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//! @brief Searches the _prop_list for a property
|
|
AutoProperty*
|
|
AutoProperties::findAutoProperty(const ClassHint* class_hint, int ws, uint type)
|
|
{
|
|
return static_cast<AutoProperty*>(findProperty(class_hint, &_prop_list, ws, type));
|
|
}
|
|
|
|
//! @brief Searches the _title_prop_list for a property
|
|
TitleProperty*
|
|
AutoProperties::findTitleProperty(const ClassHint* class_hint)
|
|
{
|
|
return static_cast<TitleProperty*>(findProperty(class_hint, &_title_prop_list, -1, 0));
|
|
}
|
|
|
|
//! @brief
|
|
DecorProperty*
|
|
AutoProperties::findDecorProperty(const ClassHint* class_hint)
|
|
{
|
|
return static_cast<DecorProperty*>(findProperty(class_hint, &_decor_prop_list, -1, 0));
|
|
}
|
|
|
|
DockAppProperty*
|
|
AutoProperties::findDockAppProperty(const ClassHint *class_hint)
|
|
{
|
|
return static_cast<DockAppProperty*>(findProperty(class_hint, &_dock_app_prop_list, -1, 0));
|
|
}
|
|
|
|
//! @brief Get AutoProperty for window of type type
|
|
//! @param atom Atom to get property for.
|
|
//! @return AutoProperty on success, else 0.
|
|
AutoProperty*
|
|
AutoProperties::findWindowTypeProperty(AtomName atom)
|
|
{
|
|
AutoProperty *prop = 0;
|
|
map<AtomName, AutoProperty*>::iterator it(_window_type_prop_map.find(atom));
|
|
if (it != _window_type_prop_map.end()) {
|
|
prop = it->second;
|
|
}
|
|
|
|
return prop;
|
|
}
|
|
|
|
//! @brief Removes all ApplyOnStart actions as they consume memory
|
|
void
|
|
AutoProperties::removeApplyOnStart(void)
|
|
{
|
|
list<Property*>::iterator it(_prop_list.begin());
|
|
for (; it != _prop_list.end(); ++it) {
|
|
if ((*it)->isApplyOn(APPLY_ON_START)) {
|
|
(*it)->applyRemove(APPLY_ON_START);
|
|
if (! (*it)->getApplyOn()) {
|
|
delete *it;
|
|
it = _prop_list.erase(it);
|
|
--it; // compensate for the ++ in the loop
|
|
}
|
|
}
|
|
}
|
|
|
|
_apply_on_start = false;
|
|
}
|
|
|
|
//! @brief Tries to match a class hint against an autoproperty data entry
|
|
bool
|
|
AutoProperties::matchAutoClass(const ClassHint &hint, Property *prop)
|
|
{
|
|
bool ok = false;
|
|
|
|
if ((prop->getHintName() == hint.h_name)
|
|
&& (prop->getHintClass() == hint.h_class))
|
|
{
|
|
ok = true;
|
|
if (prop->getTitle ().is_match_ok ()) {
|
|
ok = (prop->getTitle () == hint.title);
|
|
}
|
|
if (ok && prop->getRole ().is_match_ok ()) {
|
|
ok = (prop->getRole () == hint.h_role);
|
|
}
|
|
}
|
|
|
|
return ok;
|
|
}
|