//
// Atoms.cc for pekwm
// Copyright (C) 2003-2004 Claes Nasten <pekdon{@}pekdon{.}net>
//
// This program is licensed under the GNU GPL.
// See the LICENSE file for more information.
//

#include "../config.h"

#include "Atoms.hh"
#include "PScreen.hh"

#ifdef DEBUG
#include <iostream>
using std::cerr;
using std::endl;
#endif // DEBUG
using std::string;
using std::map;

PekwmAtoms* PekwmAtoms::_instance = NULL;
IcccmAtoms* IcccmAtoms::_instance = NULL;
EwmhAtoms* EwmhAtoms::_instance = NULL;

//! @brief PekwmAtoms constructor
PekwmAtoms::PekwmAtoms(void)
{
	if (_instance != NULL)
		throw string("PekwmAtoms, trying to create multiple instances");
	_instance = this;

	// pekwm atoms
	char *names[] = {
		"_PEKWM_FRAME_ID",
		"_PEKWM_FRAME_DECOR",
		"_PEKWM_FRAME_SKIP",
		"_PEKWM_FRAME_VPOS"
	};
	const uint num = sizeof(names) / sizeof(char*);
	Atom atoms[num];

	XInternAtoms(PScreen::instance()->getDpy(), names, num, 0, atoms);

	// Insert all atoms into the _atoms map
	for (uint i = 0; i < num; ++i) {
		_atoms[PekwmAtomName(i)] = atoms[i];
	}
}

//! @brief PekwmAtoms destructor
PekwmAtoms::~PekwmAtoms(void)
{
	_instance = NULL;
}

//! @brief IcccmAtoms constructor
IcccmAtoms::IcccmAtoms(void)
{
	if (_instance != NULL)
		throw string("IcccmAtoms, trying to create multiple instances");
	_instance = this;

	// ICCCM atoms
	char *names[] = {
		"WM_STATE",
		"WM_CHANGE_STATE",
		"WM_PROTOCOLS",
		"WM_DELETE_WINDOW",
		"WM_COLORMAP_WINDOWS",
		"WM_TAKE_FOCUS",
		"WM_WINDOW_ROLE"
	};
	const uint num = sizeof(names) / sizeof(char*);
	Atom atoms[num];

	XInternAtoms(PScreen::instance()->getDpy(), names, num, 0, atoms);

	// Insert all atoms into the _atoms map
	for (uint i = 0; i < num; ++i) {
		_atoms[IcccmAtomName(i)] = atoms[i];
	}
}

//! @brief IcccmAtoms destructor
IcccmAtoms::~IcccmAtoms(void)
{
	_instance = NULL;
}

//! @brief EwmhAtoms constructor
EwmhAtoms::EwmhAtoms(void)
{
	if (_instance != NULL)
		throw string("EwmhAtoms, trying to create multiple instances");
	_instance = this;

	char *names[] = {
		"_NET_SUPPORTED",
		"_NET_CLIENT_LIST", "_NET_CLIENT_LIST_STACKING",
		"_NET_NUMBER_OF_DESKTOPS",
		"_NET_DESKTOP_GEOMETRY", "_NET_DESKTOP_VIEWPORT",
		"_NET_CURRENT_DESKTOP", "_NET_ACTIVE_WINDOW",
		"_NET_WORKAREA", "_NET_DESKTOP_LAYOUT",
		"_NET_SUPPORTING_WM_CHECK",
		"_NET_CLOSE_WINDOW",
		"_NET_WM_NAME", "_NET_WM_DESKTOP",
		"_NET_WM_STRUT",

		"_NET_WM_WINDOW_TYPE",
		"_NET_WM_WINDOW_TYPE_DESKTOP", "_NET_WM_WINDOW_TYPE_DOCK",
		"_NET_WM_WINDOW_TYPE_TOOLBAR", "_NET_WM_WINDOW_TYPE_MENU",
		"_NET_WM_WINDOW_TYPE_UTILITY", "_NET_WM_WINDOW_TYPE_SPLASH",
		"_NET_WM_WINDOW_TYPE_DIALOG", "_NET_WM_WINDOW_TYPE_NORMAL",

		"_NET_WM_STATE",
		"_NET_WM_STATE_MODAL", "_NET_WM_STATE_STICKY",
		"_NET_WM_STATE_MAXIMIZED_VERT", "_NET_WM_STATE_MAXIMIZED_HORZ",
		"_NET_WM_STATE_SHADED",
		"_NET_WM_STATE_SKIP_TOOLBAR", "_NET_WM_STATE_PAGER",
		"_NET_WM_STATE_HIDDEN", "_NET_WM_STATE_FULLSCREEN",
		"_NET_WM_STATE_ABOVE", "_NET_WM_STATE_BELOW",

		"_NET_WM_ALLOWED_ACTIONS",
		"_NET_WM_ACTION_MOVE", "_NET_WM_ACTION_RESIZE",
		"_NET_WM_ACTION_MINIMIZE", "_NET_WM_ACTION_SHADE",
		"_NET_WM_ACTION_STICK",
		"_NET_WM_ACTION_MAXIMIZE_VERT", "_NET_WM_ACTION_MAXIMIZE_HORZ",
		"_NET_WM_ACTION_FULLSCREEN", "_NET_WM_ACTION_CHANGE_DESKTOP",
		"_NET_WM_ACTION_CLOSE"
	};
	const uint num = sizeof(names) / sizeof(char*);
	Atom atoms[num];

	XInternAtoms(PScreen::instance()->getDpy(), names, num, 0, atoms);

	// Insert all items into the _atoms map
	for (uint i = 0; i < num; ++i) {
		_atoms[EwmhAtomName(i)] = atoms[i];
	}
}

//! @brief EwmhAtoms destructor
EwmhAtoms::~EwmhAtoms(void)
{
	_instance = NULL;
}

//! @brief Builds a array of all atoms in the map.
Atom*
EwmhAtoms::getAtomArray(void) const
{
	Atom *atoms = new Atom[_atoms.size()];

	map<EwmhAtomName, Atom>::const_iterator it = _atoms.begin();
	for (uint i = 0; it != _atoms.end(); ++i, ++it)
		atoms[i] = it->second;

	return atoms;
}

namespace AtomUtil {

//! @brief Get unknown property
ulong
getProperty(Window win, Atom atom, Atom type, ulong expected, uchar** data)
{
	Atom r_type;
	int r_format, status;
	ulong read, left;

	status =
		XGetWindowProperty(PScreen::instance()->getDpy(), win, atom,
											 0L, expected, False, type,
											 &r_type, &r_format, &read, &left, data);

	if ((status != Success) || (read == 0)) {
		if (*data != NULL) {
			XFree(*data);
			*data = NULL;
		}
	}

	return (*data != NULL);
}

//! @brief Set XA_ATOM, one value
void
setAtom(Window win, Atom atom, Atom value)
{
	XChangeProperty(PScreen::instance()->getDpy(), win, atom, XA_ATOM, 32,
									PropModeReplace, (uchar *) &value, 1);
}

//! @brief Set XA_ATOM, multiple values
void
setAtoms(Window win, Atom atom, Atom *values, int size)
{
	XChangeProperty(PScreen::instance()->getDpy(), win, atom, XA_ATOM, 32,
									PropModeReplace, (uchar *) values, size);
}

//! @brief Set XA_WINDOW, one value
void
setWindow(Window win, Atom atom, Window value)
{
	XChangeProperty(PScreen::instance()->getDpy(), win, atom, XA_WINDOW, 32,
									PropModeReplace, (uchar *) &value, 1);
}

//! @brief Set XA_WINDOW, multiple values
void
setWindows(Window win, Atom atom, Window *values, int size)
{
	XChangeProperty(PScreen::instance()->getDpy(), win, atom, XA_WINDOW, 32,
									PropModeReplace, (uchar *) values, size);
}

//! @brief Get XA_CARDINAL
bool
getLong(Window win, Atom atom, long &value)
{
	long *data = NULL;

	if (getProperty(win, atom, XA_CARDINAL, 1L, (uchar**) &data) == true) {
		value = *data;
		XFree(data);

		return true;
	}

	return false;
}

//! @brief Set XA_CARDINAL
void
setLong(Window win, Atom atom, long value)
{
	XChangeProperty(PScreen::instance()->getDpy(), win, atom, XA_CARDINAL, 32,
									PropModeReplace, (uchar *) &value, 1);
}

//! @brief Get XA_STRING property
bool
getString(Window win, Atom atom, string &value)
{
	uchar *data = NULL;

	if (getProperty(win, atom, XA_STRING, 64L, &data) == true) {
		value = string((const char*) data);
		XFree(data);

		return true;
	}

	return false;
}

//! @brief Set XA_STRING property
void
setString(Window win, Atom atom, const string &value)
{
	XChangeProperty(PScreen::instance()->getDpy(), win, atom, XA_STRING, 8,
									PropModeReplace, (uchar*) value.c_str(), value.size());
}

//! @brief Used to get two CARD32(int) values, used for _PEKWM_VPOS
bool
getPosition(Window win, Atom atom, int &x, int &y)
{
	CARD32 *data = NULL;

	getProperty(win, atom, XA_CARDINAL, 2L, (uchar**) &data);

	if (data != NULL) {
		x = data[0];
		y = data[1];
		XFree(data);

		return true;
	}

	return false;
}

//! @brief Used to set two CARD32(int) values, used for _PEKWM_VPOS
void
setPosition(Window win, Atom atom, int x, int y)
{
	CARD32 data[2];

	data[0] = x;
	data[1] = y;

	XChangeProperty(PScreen::instance()->getDpy(), win, atom, XA_CARDINAL, 32,
									PropModeReplace, (uchar *) data, 2);
}

//! @brief
void*
getEwmhPropData(Window win, Atom prop, Atom type, int &num)
{
	Atom type_ret;
	int format_ret;
	ulong items_ret, after_ret;
	uchar *prop_data = NULL;

	XGetWindowProperty(PScreen::instance()->getDpy(), win, prop, 0, 0x7fffffff,
										 False, type, &type_ret, &format_ret, &items_ret,
										 &after_ret, &prop_data);

	num = items_ret;

	return prop_data;
}

//! @brief
void
unsetProperty(Window win, Atom prop)
{
	XDeleteProperty(PScreen::instance()->getDpy(), win, prop);
}

} // end namespace AtomUtil


syntax highlighted by Code2HTML, v. 0.9.1