// Ewmh.cc for FbPager
// Copyright (c) 2004 Henrik Kinnunen (fluxgen at users.sourceforge.net)
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#include "Ewmh.hh"
#include "Pager.hh"
#include "WindowHint.hh"
#include "FbTk/App.hh"
#include "FbTk/FbWindow.hh"
#include "FbRootWindow.hh"
#include <X11/Xatom.h>
#include <iostream>
#include <vector>
#include <sys/types.h>
#include <unistd.h>
#include <memory>
using namespace std;
namespace FbPager {
class Ewmh_priv {
public:
Ewmh_priv() {
Display *disp = FbTk::App::instance()->display();
state_skip_pager = XInternAtom(disp, "_NET_WM_STATE_SKIP_PAGER", False);
state_skip_taskbar = XInternAtom(disp, "_NET_WM_STATE_SKIP_TASKBAR", False);
state_sticky = XInternAtom(disp, "_NET_WM_STATE_STICKY", False);
state_hidden = XInternAtom(disp, "_NET_WM_STATE_HIDDEN", False);
state_shaded = XInternAtom(disp, "_NET_WM_STATE_SHADED", False);
wm_desktop = XInternAtom(disp, "_NET_WM_DESKTOP", False);
wm_state = XInternAtom(disp, "_NET_WM_STATE", False);
wm_pid = XInternAtom(disp, "_NET_WM_PID", False);
wm_type = XInternAtom(disp, "_NET_WM_WINDOW_TYPE", False);
type_dock = XInternAtom(disp, "_NET_WM_WINDOW_TYPE_DOCK", False);
number_of_desktops = XInternAtom(disp, "_NET_NUMBER_OF_DESKTOPS", False);
current_desktop = XInternAtom(disp, "_NET_CURRENT_DESKTOP", False);
clientlist = XInternAtom(disp, "_NET_CLIENT_LIST", False);
moveresize_window = XInternAtom(disp, "_NET_MOVERESIZE_WINDOW", False);
active_window = XInternAtom(disp, "_NET_ACTIVE_WINDOW", False);
close_window = XInternAtom(disp, "_NET_CLOSE_WINDOW", False);
}
Atom state_skip_pager, state_skip_taskbar, state_sticky, state_hidden, state_shaded;
Atom wm_desktop, wm_state, wm_pid, wm_type;
Atom type_dock;
Atom number_of_desktops, current_desktop;
Atom clientlist;
Atom moveresize_window;
Atom active_window;
Atom close_window;
};
Ewmh::Ewmh():
m_support(true),
m_data(new Ewmh_priv()) {
//!! TODO
// check for ewmh support
}
Ewmh::~Ewmh() {
}
void Ewmh::setFocus(FbTk::FbWindow &win) {
}
void Ewmh::moveResize(FbTk::FbWindow &win) {
// We can't do this yet, there is a bug in fluxbox 0.9.8
// and this makes it crash (it's fixed in cvs though)
/*
Display *disp = FbTk::App::instance()->display();
XEvent event;
event.xclient.display = disp;
event.xclient.type = ClientMessage;
event.xclient.window = RootWindow(disp, win.screenNumber());
event.xclient.message_type = m_data->moveresize_window;
event.xclient.format = 32;
event.xclient.data.l[0] = 0;
event.xclient.data.l[1] = win.x();
event.xclient.data.l[2] = win.y();
event.xclient.data.l[3] = win.width();
event.xclient.data.l[4] = win.height();
XSendEvent(disp, event.xclient.window, False, SubstructureNotifyMask, &event);
*/
}
void Ewmh::sendToWorkspace(FbTk::FbWindow &win, int workspace) {
}
void Ewmh::closeWindow(FbTk::FbWindow &win) {
Display *disp = FbTk::App::instance()->display();
XEvent event;
event.xclient.display = disp;
event.xclient.type = ClientMessage;
event.xclient.window = win.window();
event.xclient.message_type = m_data->close_window;
event.xclient.format = 32;
event.xclient.data.l[0] = 0;
XSendEvent(disp, RootWindow(disp, DefaultScreen(disp)), False, SubstructureNotifyMask, &event);
}
bool Ewmh::clientMessage(Pager &pager, XClientMessageEvent &event) {
if (!m_support)
return false;
if (event.message_type == m_data->current_desktop) {
pager.setCurrentWorkspace(event.data.l[0]);
return true;
} else if (event.message_type == m_data->number_of_desktops) {
pager.updateWorkspaceCount(event.data.l[0]);
return true;
} else if (event.message_type == m_data->wm_desktop) {
pager.moveToWorkspace(event.window, event.data.l[0]);
return true;
} else if (event.message_type == m_data->clientlist) {
return true;
} else if (event.message_type == m_data->active_window) {
pager.setFocusedWindow(event.window);
return true;
}
return false;
}
void Ewmh::changeWorkspace(int screen_num, int workspace) {
Display *disp = FbTk::App::instance()->display();
XEvent event;
event.xclient.display = disp;
event.xclient.type = ClientMessage;
event.xclient.window = RootWindow(disp, screen_num);
event.xclient.message_type = m_data->current_desktop;
event.xclient.format = 32;
event.xclient.data.l[0] = workspace;
XSendEvent(disp, event.xclient.window, False, SubstructureNotifyMask, &event);
}
void Ewmh::setHints(FbTk::FbWindow &win, WindowHint &hint) {
int data = getpid();
win.changeProperty(m_data->wm_pid,
XA_CARDINAL,
32,
PropModeReplace,
(unsigned char *)&data, 1);
if (hint.flags() & WindowHint::WHINT_STICKY) {
data = 0xFFFFFFFF;
win.changeProperty(m_data->wm_desktop,
XA_CARDINAL,
32,
PropModeReplace,
(unsigned char *)&data, 1);
}
if (hint.flags() & WindowHint::WHINT_TYPE_DOCK) {
Atom data = m_data->type_dock;
win.changeProperty(m_data->wm_type,
XA_ATOM,
32,
PropModeReplace,
(unsigned char *)&data, 1);
}
std::vector<Atom> states;
if (hint.flags() & WindowHint::WHINT_SKIP_TASKBAR)
states.push_back(m_data->state_skip_taskbar);
if (hint.flags() & WindowHint::WHINT_SKIP_PAGER)
states.push_back(m_data->state_skip_pager);
if (hint.flags() & WindowHint::WHINT_STICKY)
states.push_back(m_data->state_sticky);
if (hint.flags() & WindowHint::WHINT_HIDDEN)
states.push_back(m_data->state_hidden);
Atom *state_atoms = new Atom[states.size()];
for (size_t i=0; i < states.size(); ++i)
state_atoms[i] = states[i];
win.changeProperty(m_data->wm_state,
XA_ATOM,
32,
PropModeReplace,
(unsigned char *)state_atoms, states.size());
delete [] state_atoms;
}
struct PropT {
PropT(unsigned char *data, unsigned int num):data(data), num(num) { }
~PropT() {
if (data != 0)
XFree(data);
}
unsigned char *data;
unsigned int num;
};
typedef std::auto_ptr<PropT> PropTPtr;
PropT *property(const FbTk::FbWindow &win, Atom atom,
Atom type, unsigned int num) {
Atom ret_type;
int fmt;
unsigned long nitems, bytes_after;
unsigned char *data = 0;
win.property(atom,
0, num,
False,
type,
&ret_type, &fmt,
&nitems,
&bytes_after,
&data);
return new PropT(data, nitems);
}
void Ewmh::getHints(const FbTk::FbWindow &win, WindowHint &hint) const {
PropTPtr p(property(win,
m_data->wm_state,
XA_ATOM, 0x7FFFFFFF));
if (p.get() != 0 && p->data != 0) {
Atom *states = (Atom *)(p->data);
for (int i=0; i<p->num; ++i) {
if (states[i] == m_data->state_skip_pager)
hint.add(WindowHint::WHINT_SKIP_PAGER);
else if (states[i] == m_data->state_skip_taskbar)
hint.add(WindowHint::WHINT_SKIP_TASKBAR);
else if (states[i] == m_data->state_sticky)
hint.add(WindowHint::WHINT_STICKY);
else if (states[i] == m_data->state_shaded)
hint.add(WindowHint::WHINT_SHADED);
}
}
p.reset(property(win, m_data->wm_type,
XA_ATOM, 0x7FFFFFFF));
if (p.get() != 0 && p->data != 0) {
// we only care about the first type.
Atom *atoms = (Atom *)p->data;
if (atoms[0] == m_data->type_dock)
hint.add(WindowHint::WHINT_TYPE_DOCK);
}
p.reset(property(win, m_data->wm_desktop,
XA_CARDINAL, 1));
if (p.get() != 0 && p->data != 0) {
int workspace = static_cast<int>(*(p->data));
hint.setWorkspace(workspace);
}
}
int Ewmh::numberOfWorkspaces(int screen_num) const {
PropTPtr p(property(FbRootWindow(screen_num),
m_data->number_of_desktops,
XA_CARDINAL, 1));
if (p.get() == 0 || p->data == 0)
return 0;
else {
int num = static_cast<int>(*(p->data));
return num;
}
}
} // end namespace FbPager
syntax highlighted by Code2HTML, v. 0.9.1