mirror of
https://github.com/edeproject/ede.git
synced 2023-08-10 21:13:03 +03:00
463 lines
16 KiB
C++
463 lines
16 KiB
C++
|
//
|
||
|
// PDecor.hh for pekwm
|
||
|
// Copyright © 2004-2009 Claes Nästén <me@pekdon.net>
|
||
|
//
|
||
|
// This program is licensed under the GNU GPL.
|
||
|
// See the LICENSE file for more information.
|
||
|
//
|
||
|
|
||
|
#ifndef _PDECOR_HH_
|
||
|
#define _PDECOR_HH_
|
||
|
|
||
|
#ifdef HAVE_CONFIG_H
|
||
|
#include "config.h"
|
||
|
#endif // HAVE_CONFIG_H
|
||
|
|
||
|
#include "Config.hh"
|
||
|
#include "Theme.hh" // for Theme::FrameData inlines
|
||
|
#include "PTexture.hh" // for border/image inlines
|
||
|
#include "Util.hh"
|
||
|
|
||
|
#include <list>
|
||
|
|
||
|
class ActionEvent;
|
||
|
class PFont;
|
||
|
class PWinObj;
|
||
|
|
||
|
/**
|
||
|
* Create window attributes.
|
||
|
*/
|
||
|
class CreateWindowParams {
|
||
|
public:
|
||
|
int depth;
|
||
|
long mask;
|
||
|
XSetWindowAttributes attr;
|
||
|
Visual *visual;
|
||
|
};
|
||
|
|
||
|
//! @brief PWinObj container class with fancy decor.
|
||
|
class PDecor : public PWinObj
|
||
|
{
|
||
|
public:
|
||
|
//! @brief Decor title button class.
|
||
|
class Button : public PWinObj {
|
||
|
public:
|
||
|
Button(PWinObj *parent, Theme::PDecorButtonData *data, uint width, uint height);
|
||
|
~Button(void);
|
||
|
|
||
|
ActionEvent *findAction(XButtonEvent *ev);
|
||
|
ButtonState getState(void) const { return _state; }
|
||
|
void setState(ButtonState state);
|
||
|
|
||
|
//! @brief Returns wheter the button is positioned relative the left title edge.
|
||
|
inline bool isLeft(void) const { return _left; }
|
||
|
|
||
|
private:
|
||
|
Theme::PDecorButtonData *_data;
|
||
|
ButtonState _state;
|
||
|
|
||
|
Pixmap _bg;
|
||
|
bool _left;
|
||
|
};
|
||
|
|
||
|
//! @brief Decor title item class.
|
||
|
class TitleItem {
|
||
|
public:
|
||
|
//! Info bitmask enum.
|
||
|
enum Info {
|
||
|
INFO_MARKED = (1 << 1),
|
||
|
INFO_ID = (1 << 2)
|
||
|
};
|
||
|
|
||
|
TitleItem(void) : _count(0), _id(0), _info(0), _width(0) { }
|
||
|
|
||
|
inline const std::wstring &getVisible(void) const { return _visible; }
|
||
|
inline const std::wstring &getReal(void) const { return _real; }
|
||
|
inline const std::wstring &getCustom(void) const { return _custom; }
|
||
|
inline const std::wstring &getUser(void) const { return _user; }
|
||
|
|
||
|
inline uint getCount(void) const { return _count; }
|
||
|
inline uint getId(void) const { return _id; }
|
||
|
inline bool isUserSet(void) const { return (_user.size() > 0); }
|
||
|
inline bool isCustom(void) const { return (_custom.size() > 0); }
|
||
|
inline uint getWidth(void) const { return _width; }
|
||
|
|
||
|
inline void infoAdd(enum Info info) { _info |= info; }
|
||
|
inline void infoRemove(enum Info info) { _info &= ~info; }
|
||
|
inline bool infoIs(enum Info info) { return (_info&info); }
|
||
|
|
||
|
void setReal(const std::wstring &real) {
|
||
|
_real = real;
|
||
|
if (! isUserSet() && ! isCustom()) {
|
||
|
updateVisible();
|
||
|
}
|
||
|
}
|
||
|
void setCustom(const std::wstring &custom) {
|
||
|
_custom = custom;
|
||
|
if (_custom.size() > 0 && ! isUserSet()) {
|
||
|
updateVisible();
|
||
|
}
|
||
|
}
|
||
|
void setUser(const std::wstring &user) {
|
||
|
_user = user;
|
||
|
updateVisible();
|
||
|
}
|
||
|
void setCount(uint count) { _count = count; }
|
||
|
void setId(uint id) { _id = id; }
|
||
|
inline void setWidth(uint width) { _width = width; }
|
||
|
|
||
|
void updateVisible(void);
|
||
|
|
||
|
private:
|
||
|
std::wstring _visible; //!< Visible version of title
|
||
|
|
||
|
std::wstring _real; //!< Title from client
|
||
|
std::wstring _custom; //!< Custom (title rule) set version of title
|
||
|
std::wstring _user; //!< User set version of title
|
||
|
|
||
|
uint _count; //!< Number of title
|
||
|
uint _id; //!< ID of title
|
||
|
uint _info; //!< Info bitmask for extra title info
|
||
|
|
||
|
uint _width;
|
||
|
};
|
||
|
|
||
|
PDecor(Theme *theme,
|
||
|
const std::string decor_name = DEFAULT_DECOR_NAME,
|
||
|
const Window child_window = None);
|
||
|
virtual ~PDecor(void);
|
||
|
|
||
|
// START - PWinObj interface.
|
||
|
virtual void mapWindow(void);
|
||
|
virtual void mapWindowRaised(void);
|
||
|
virtual void unmapWindow(void);
|
||
|
|
||
|
virtual void move(int x, int y);
|
||
|
virtual void resize(uint width, uint height);
|
||
|
virtual void moveResize(int x, int y, uint width, uint height);
|
||
|
virtual void raise(void);
|
||
|
virtual void lower(void);
|
||
|
|
||
|
virtual void setFocused(bool focused);
|
||
|
virtual void setWorkspace(uint workspace);
|
||
|
|
||
|
virtual void giveInputFocus(void);
|
||
|
|
||
|
virtual ActionEvent *handleButtonPress(XButtonEvent *ev);
|
||
|
virtual ActionEvent *handleButtonRelease(XButtonEvent *ev);
|
||
|
virtual ActionEvent *handleMotionEvent(XMotionEvent *ev);
|
||
|
virtual ActionEvent *handleEnterEvent(XCrossingEvent *ev);
|
||
|
virtual ActionEvent *handleLeaveEvent(XCrossingEvent *ev);
|
||
|
|
||
|
virtual bool operator == (const Window &window) {
|
||
|
if ((_window == window) || (_title_wo == window) ||
|
||
|
findButton(window) ||
|
||
|
(getBorderPosition(window) != BORDER_NO_POS) ||
|
||
|
((_child) ? (*_child == window) : false)) {
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
virtual bool operator != (const Window &window) {
|
||
|
return !(*this == window);
|
||
|
}
|
||
|
// END - PWinObj interface.
|
||
|
|
||
|
// START - PDecor interface.
|
||
|
virtual bool allowMove(void) const { return true; }
|
||
|
|
||
|
virtual void addChild(PWinObj *child, std::list<PWinObj*>::iterator *it = 0);
|
||
|
virtual void removeChild(PWinObj *child, bool do_delete = true);
|
||
|
virtual void activateChild(PWinObj *child);
|
||
|
|
||
|
virtual void updatedChildOrder(void) { }
|
||
|
virtual void updatedActiveChild(void) { }
|
||
|
|
||
|
virtual void getDecorInfo(wchar_t *buf, uint size);
|
||
|
|
||
|
virtual void setShaded(StateAction sa);
|
||
|
virtual void setSkip(uint skip);
|
||
|
// END - PDecor interface.
|
||
|
|
||
|
static std::list<PDecor*>::iterator pdecor_begin(void) { return _pdecor_list.begin(); }
|
||
|
static std::list<PDecor*>::iterator pdecor_end(void) { return _pdecor_list.end(); }
|
||
|
|
||
|
inline bool isSkip(uint skip) const { return (_skip&skip); }
|
||
|
|
||
|
void addDecor(PDecor *decor);
|
||
|
|
||
|
bool setDecor(const std::string &name);
|
||
|
void setDecorOverride(StateAction sa, const std::string &name);
|
||
|
void loadDecor(void);
|
||
|
|
||
|
//! @brief Returns title Window.
|
||
|
inline Window getTitleWindow(void) const { return _title_wo.getWindow(); }
|
||
|
PDecor::Button *findButton(Window win);
|
||
|
|
||
|
//! @brief Returns height of PDecor ignoring shaded state.
|
||
|
inline uint getRealHeight(void) const {
|
||
|
return (_shaded ? _real_height : _gm.height);
|
||
|
}
|
||
|
|
||
|
//! @brief Returns last click x root position.
|
||
|
inline int getPointerX(void) const { return _pointer_x; }
|
||
|
//! @brief Returns last click y root position.
|
||
|
inline int getPointerY(void) const { return _pointer_y; }
|
||
|
//! @brief Returns last click x window position.
|
||
|
inline int getClickX(void) const { return _click_x; }
|
||
|
//! @brief Returns last click y window position.
|
||
|
inline int getClickY(void) const { return _click_y; }
|
||
|
|
||
|
//! @brief Returns width of child container.
|
||
|
inline uint getChildWidth(void) const {
|
||
|
if ((borderLeft() + borderRight()) >= _gm.width) {
|
||
|
return 1;
|
||
|
}
|
||
|
return (_gm.width - borderLeft() - borderRight());
|
||
|
}
|
||
|
//! @brief Returns height of child container.
|
||
|
inline uint getChildHeight(void) const {
|
||
|
if ((borderTop() + borderBottom() + getTitleHeight()) >= getRealHeight()) {
|
||
|
return 1;
|
||
|
}
|
||
|
return (getRealHeight() - borderTop() - borderBottom() - getTitleHeight());
|
||
|
}
|
||
|
|
||
|
// child list actions
|
||
|
|
||
|
//! @brief Returns number of children in PDecor.
|
||
|
inline uint size(void) const { return _child_list.size(); }
|
||
|
//! @brief Returns iterator to the first child in PDecor.
|
||
|
inline std::list<PWinObj*>::iterator begin(void) {
|
||
|
return _child_list.begin();
|
||
|
}
|
||
|
//! @brief Returns iterator to the last+1 child in PDecor.
|
||
|
inline std::list<PWinObj*>::iterator end(void) { return _child_list.end(); }
|
||
|
|
||
|
//! @brief Returns pointer to active PWinObj.
|
||
|
inline PWinObj *getActiveChild(void) { return _child; }
|
||
|
PWinObj *getChildFromPos(int x);
|
||
|
|
||
|
void activateChildNum(uint num);
|
||
|
void activateChildRel(int off); // +/- relative from active
|
||
|
void moveChildRel(int off); // +/- relative from active
|
||
|
|
||
|
// title
|
||
|
|
||
|
//! @brief Adds TitleItem to title list.
|
||
|
inline void titleAdd(PDecor::TitleItem *ct) { _title_list.push_back(ct); }
|
||
|
//! @brief Removes all TitleItems from title list.
|
||
|
inline void titleClear(void) { _title_list.clear(); }
|
||
|
//! @brief Sets active TitleItem.
|
||
|
void titleSetActive(uint num) {
|
||
|
_title_active = (num > _title_list.size()) ? 0 : num;
|
||
|
}
|
||
|
|
||
|
// move and resize relative to the child instead of decor
|
||
|
void moveChild(int x, int y);
|
||
|
void resizeChild(uint width, uint height);
|
||
|
|
||
|
// decor state
|
||
|
|
||
|
//! @brief Returns wheter we have a border or not.
|
||
|
inline bool hasBorder(void) const { return _border; }
|
||
|
//! @brief Returns wheter we have a titlebar or not.
|
||
|
inline bool hasTitlebar(void) const { return _titlebar; }
|
||
|
//! @brief Returns wheter we are shaded or not.
|
||
|
inline bool isShaded(void) const { return _shaded; }
|
||
|
void setBorder(StateAction sa);
|
||
|
void setTitlebar(StateAction sa);
|
||
|
|
||
|
// decor element sizes
|
||
|
uint getTitleHeight(void) const;
|
||
|
|
||
|
// common actions like doMove
|
||
|
void doMove(int x_root, int y_root);
|
||
|
void doKeyboardMoveResize(void);
|
||
|
|
||
|
//! @brief Returns border position Window win is at.
|
||
|
inline BorderPosition getBorderPosition(Window win) const {
|
||
|
for (uint i = 0; i < BORDER_NO_POS; ++i) {
|
||
|
if (_border_win[i] == win) {
|
||
|
return BorderPosition(i);
|
||
|
}
|
||
|
}
|
||
|
return BORDER_NO_POS;
|
||
|
|
||
|
}
|
||
|
inline uint borderTop(void) const {
|
||
|
return (_border ? _data->getBorderTexture(getFocusedState(false), BORDER_TOP)->getHeight() : 0);
|
||
|
}
|
||
|
inline uint borderTopLeft(void) const {
|
||
|
return (_border ? _data->getBorderTexture(getFocusedState(false), BORDER_TOP_LEFT)->getWidth() : 0);
|
||
|
}
|
||
|
inline uint borderTopLeftHeight(void) const {
|
||
|
return (_border ? _data->getBorderTexture(getFocusedState(false), BORDER_TOP_LEFT)->getHeight() : 0);
|
||
|
}
|
||
|
inline uint borderTopRight(void) const {
|
||
|
return (_border ? _data->getBorderTexture(getFocusedState(false), BORDER_TOP_RIGHT)->getWidth() : 0);
|
||
|
}
|
||
|
inline uint borderTopRightHeight(void) const {
|
||
|
return (_border ? _data->getBorderTexture(getFocusedState(false), BORDER_TOP_RIGHT)->getHeight() : 0);
|
||
|
}
|
||
|
inline uint borderBottom(void) const {
|
||
|
return (_border ? _data->getBorderTexture(getFocusedState(false), BORDER_BOTTOM)->getHeight() : 0);
|
||
|
}
|
||
|
inline uint borderBottomLeft(void) const {
|
||
|
return (_border ? _data->getBorderTexture(getFocusedState(false), BORDER_BOTTOM_LEFT)->getWidth() : 0);
|
||
|
}
|
||
|
inline uint borderBottomLeftHeight(void) const {
|
||
|
return (_border ? _data->getBorderTexture(getFocusedState(false), BORDER_BOTTOM_LEFT)->getHeight() : 0);
|
||
|
}
|
||
|
inline uint borderBottomRight(void) const {
|
||
|
return (_border ? _data->getBorderTexture(getFocusedState(false), BORDER_BOTTOM_RIGHT)->getWidth() : 0);
|
||
|
}
|
||
|
inline uint borderBottomRightHeight(void) const {
|
||
|
return (_border ? _data->getBorderTexture(getFocusedState(false), BORDER_BOTTOM_RIGHT)->getHeight() : 0);
|
||
|
}
|
||
|
inline uint borderLeft(void) const {
|
||
|
return (_border ? _data->getBorderTexture(getFocusedState(false), BORDER_LEFT)->getWidth() : 0);
|
||
|
}
|
||
|
inline uint borderRight(void) const {
|
||
|
return (_border ? _data->getBorderTexture(getFocusedState(false), BORDER_RIGHT)->getWidth() : 0);
|
||
|
}
|
||
|
|
||
|
void deiconify(void);
|
||
|
protected:
|
||
|
// START - PDecor interface.
|
||
|
virtual void renderTitle(void);
|
||
|
virtual void renderButtons(void);
|
||
|
virtual void renderBorder(void);
|
||
|
virtual void setBorderShape(void); // shapes border corners
|
||
|
virtual void applyBorderShape(void); // applies shape onto window
|
||
|
|
||
|
virtual void loadTheme(void) { } // called after loadDecor, render child
|
||
|
|
||
|
virtual int resizeHorzStep(int diff) const { return diff; }
|
||
|
virtual int resizeVertStep(int diff) const { return diff; }
|
||
|
// END - PDecor interface.
|
||
|
|
||
|
void resizeTitle(void);
|
||
|
|
||
|
//! @brief Returns font used at FocusedState state.
|
||
|
inline PFont *getFont(FocusedState state) const { return _data->getFont(state); }
|
||
|
|
||
|
uint getNearestHead(void);
|
||
|
|
||
|
void checkSnap(void);
|
||
|
void checkWOSnap(void);
|
||
|
void checkEdgeSnap(void);
|
||
|
|
||
|
bool setShape(void);
|
||
|
void alignChild(PWinObj *child);
|
||
|
void drawOutline(const Geometry &gm);
|
||
|
|
||
|
inline FocusedState getFocusedState(bool selected) const {
|
||
|
if (selected) {
|
||
|
return (_focused) ? FOCUSED_STATE_FOCUSED_SELECTED : FOCUSED_STATE_UNFOCUSED_SELECTED;
|
||
|
} else {
|
||
|
return (_focused) ? FOCUSED_STATE_FOCUSED : FOCUSED_STATE_UNFOCUSED;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
void getParentWindowAttributes(CreateWindowParams ¶ms,
|
||
|
Window child_window);
|
||
|
void getChildWindowAttributes(CreateWindowParams ¶ms,
|
||
|
Window child_window);
|
||
|
void createParentWindow(CreateWindowParams ¶ms);
|
||
|
void createTitle(CreateWindowParams ¶ms);
|
||
|
void createBorder(CreateWindowParams ¶ms);
|
||
|
|
||
|
void unloadDecor(void);
|
||
|
|
||
|
ActionEvent *handleButtonPressButton(XButtonEvent *ev, PDecor::Button *button);
|
||
|
ActionEvent *handleButtonPressBorder(XButtonEvent *ev);
|
||
|
ActionEvent *handleButtonReleaseButton(XButtonEvent *ev, PDecor::Button *button);
|
||
|
ActionEvent *handleButtonReleaseBorder(XButtonEvent *ev);
|
||
|
|
||
|
EdgeType doMoveEdgeFind(int x, int y);
|
||
|
void doMoveEdgeAction(XMotionEvent *ev, EdgeType edge);
|
||
|
|
||
|
void placeButtons(void);
|
||
|
void placeBorder(void);
|
||
|
void shapeBorder(void);
|
||
|
void restackBorder(void); // shaded, borderless, no border visible
|
||
|
|
||
|
bool updateDecorName(void);
|
||
|
|
||
|
PWinObj *getChildRel(int off); // +/- relative from active
|
||
|
void getBorderSize(BorderPosition pos, uint &width, uint &height);
|
||
|
|
||
|
uint calcTitleWidth(void);
|
||
|
void calcTabsWidth(void);
|
||
|
void calcTabsGetAvailAndTabWidth(uint &width_avail, uint &tab_width, int &off);
|
||
|
void calcTabsWidthSymetric(void);
|
||
|
void calcTabsWidthAsymetric(void);
|
||
|
void calcTabsWidthAsymetricGrow(uint width_avail, uint tab_width);
|
||
|
void calcTabsWidthAsymetricShrink(uint width_avail, uint tab_width);
|
||
|
|
||
|
protected:
|
||
|
Theme *_theme; //!< Pointer to Theme used by PDecor.
|
||
|
std::string _decor_name; /**< Name of decoration used. */
|
||
|
std::string _decor_name_override; /**< Overridden decoration name. */
|
||
|
|
||
|
PWinObj *_child; //!< Pointer to active child in PDecor.
|
||
|
std::list<PWinObj*> _child_list; //!< List of children in PDecor.
|
||
|
|
||
|
PDecor::Button *_button; /**< Active title button in PDecor. */
|
||
|
Window _button_press_win; /**< Active border window, for button release handling. */
|
||
|
|
||
|
// used for treshold calculation
|
||
|
int _pointer_x; //!< Last click x root position.
|
||
|
int _pointer_y; //!< Last click y root position.
|
||
|
int _click_x; //!< Last click x window position.
|
||
|
int _click_y; //!< Last click y window position.
|
||
|
|
||
|
// how the decor should behave
|
||
|
bool _decor_cfg_keep_empty; //!< Boolean to configure allowing empty PDecors.
|
||
|
bool _decor_cfg_child_move_overloaded; //!< Boolean to set wheter ::move is overloaded.
|
||
|
|
||
|
// button{press,release} handling cfg
|
||
|
bool _decor_cfg_bpr_replay_pointer; //!< Boolean to configure wheter to call XReplayPointer on clicks.
|
||
|
MouseActionListName _decor_cfg_bpr_al_child; //!< What list to search for child actions.
|
||
|
MouseActionListName _decor_cfg_bpr_al_title; //!< What list to search for title actions.
|
||
|
|
||
|
static const std::string DEFAULT_DECOR_NAME; //!< Default decor name in normal state.
|
||
|
static const std::string DEFAULT_DECOR_NAME_BORDERLESS; //!< Default decor name in borderless state.
|
||
|
static const std::string DEFAULT_DECOR_NAME_TITLEBARLESS; //!< Default decor name in titlebarless state.
|
||
|
|
||
|
// state switches, commonly not used by all decors
|
||
|
bool _maximized_vert;
|
||
|
bool _maximized_horz;
|
||
|
bool _fullscreen;
|
||
|
uint _skip;
|
||
|
|
||
|
Window _border_win[BORDER_NO_POS]; /** Array of border windows. */
|
||
|
std::map<BorderPosition, Pixmap> _border_pos_map;
|
||
|
|
||
|
private:
|
||
|
Theme::PDecorData *_data;
|
||
|
|
||
|
// decor state
|
||
|
bool _border, _titlebar, _shaded;
|
||
|
bool _need_shape;
|
||
|
bool _need_client_shape;
|
||
|
bool _dirty_resized; //!< Flag set when decor has been resized.
|
||
|
uint _real_height;
|
||
|
|
||
|
PWinObj _title_wo;
|
||
|
std::list<PDecor::Button*> _button_list;
|
||
|
|
||
|
Pixmap _title_bg;
|
||
|
|
||
|
// variable decor data
|
||
|
uint _title_active;
|
||
|
std::list<PDecor::TitleItem*> _title_list;
|
||
|
uint _titles_left, _titles_right; // area where to put titles
|
||
|
|
||
|
static std::list<PDecor*> _pdecor_list; /**< List of PDecors */
|
||
|
};
|
||
|
|
||
|
#endif // _PDECOR_HH_
|