304 lines
11 KiB
C
304 lines
11 KiB
C
/*
|
|
* wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
|
|
* For license, see COPYING.
|
|
*/
|
|
|
|
#include "ewmh.h"
|
|
#include "util.h"
|
|
#include "screen.h"
|
|
#include "client.h"
|
|
|
|
/* Taken From standards.freedesktop.org */
|
|
#define _NET_WM_STATE_REMOVE 0 /* remove/unset property */
|
|
#define _NET_WM_STATE_ADD 1 /* add/set property */
|
|
#define _NET_WM_STATE_TOGGLE 2 /* toggle property */
|
|
|
|
void
|
|
ewmh_init(void)
|
|
{
|
|
int b = 1;
|
|
|
|
W->net_atom = xcalloc(net_last, sizeof(Atom));
|
|
|
|
/* EWMH hints */
|
|
W->net_atom[wm_state] = ATOM("WM_STATE");
|
|
W->net_atom[wm_class] = ATOM("WM_CLASS");
|
|
W->net_atom[wm_name] = ATOM("WM_NAME");
|
|
W->net_atom[net_supported] = ATOM("_NET_SUPPORTED");
|
|
W->net_atom[net_client_list] = ATOM("_NET_CLIENT_LIST");
|
|
W->net_atom[net_frame_extents] = ATOM("_NET_FRAME_EXTENTS");
|
|
W->net_atom[net_number_of_desktops] = ATOM("_NET_NUMBER_OF_DESKTOPS");
|
|
W->net_atom[net_current_desktop] = ATOM("_NET_CURRENT_DESKTOP");
|
|
W->net_atom[net_desktop_names] = ATOM("_NET_DESKTOP_NAMES");
|
|
W->net_atom[net_desktop_geometry] = ATOM("_NET_DESKTOP_GEOMETRY");
|
|
W->net_atom[net_active_window] = ATOM("_NET_ACTIVE_WINDOW");
|
|
W->net_atom[net_close_window] = ATOM("_NET_CLOSE_WINDOW");
|
|
W->net_atom[net_wm_name] = ATOM("_NET_WM_NAME");
|
|
W->net_atom[net_wm_pid] = ATOM("_NET_WM_PID");
|
|
W->net_atom[net_wm_desktop] = ATOM("_NET_WM_DESKTOP");
|
|
W->net_atom[net_showing_desktop] = ATOM("_NET_SHOWING_DESKTOP");
|
|
W->net_atom[net_wm_icon_name] = ATOM("_NET_WM_ICON_NAME");
|
|
W->net_atom[net_wm_window_type] = ATOM("_NET_WM_WINDOW_TYPE");
|
|
W->net_atom[net_supporting_wm_check] = ATOM("_NET_SUPPORTING_WM_CHECK");
|
|
W->net_atom[net_wm_window_opacity] = ATOM("_NET_WM_WINDOW_OPACITY");
|
|
W->net_atom[net_wm_window_type_normal] = ATOM("_NET_WM_WINDOW_TYPE_NORMAL");
|
|
W->net_atom[net_wm_window_type_desktop] = ATOM("_NET_WM_WINDOW_TYPE_DESKTOP");
|
|
W->net_atom[net_wm_window_type_dock] = ATOM("_NET_WM_WINDOW_TYPE_DOCK");
|
|
W->net_atom[net_wm_window_type_splash] = ATOM("_NET_WM_WINDOW_TYPE_SPLASH");
|
|
W->net_atom[net_wm_window_type_dialog] = ATOM("_NET_WM_WINDOW_TYPE_DIALOG");
|
|
W->net_atom[net_wm_icon] = ATOM("_NET_WM_ICON");
|
|
W->net_atom[net_wm_state] = ATOM("_NET_WM_STATE");
|
|
W->net_atom[net_wm_state_fullscreen] = ATOM("_NET_WM_STATE_FULLSCREEN");
|
|
W->net_atom[net_wm_state_sticky] = ATOM("_NET_WM_STATE_STICKY");
|
|
W->net_atom[net_wm_state_demands_attention] = ATOM("_NET_WM_STATE_DEMANDS_ATTENTION");
|
|
W->net_atom[net_wm_state_hidden] = ATOM("_NET_WM_STATE_HIDDEN");
|
|
W->net_atom[net_system_tray_s] = ATOM("_NET_SYSTEM_TRAY_S0");
|
|
W->net_atom[net_system_tray_opcode] = ATOM("_NET_SYSTEM_TRAY_OPCODE");
|
|
W->net_atom[net_system_tray_message_data] = ATOM("_NET_SYSTEM_TRAY_MESSAGE_DATA");
|
|
W->net_atom[net_system_tray_visual] = ATOM("_NET_SYSTEM_TRAY_VISUAL");
|
|
W->net_atom[net_system_tray_orientation] = ATOM("_NET_SYSTEM_TRAY_ORIENTATION");
|
|
W->net_atom[xembed] = ATOM("_XEMBED");
|
|
W->net_atom[xembedinfo] = ATOM("_XEMBED_INFO");
|
|
W->net_atom[manager] = ATOM("MANAGER");
|
|
W->net_atom[utf8_string] = ATOM("UTF8_STRING");
|
|
|
|
/* WMFS hints */
|
|
W->net_atom[wmfs_running] = ATOM("_WMFS_RUNNING");
|
|
W->net_atom[wmfs_focus] = ATOM("_WMFS_FOCUS");
|
|
W->net_atom[wmfs_update_hints] = ATOM("_WMFS_UPDATE_HINTS");
|
|
W->net_atom[wmfs_set_screen] = ATOM("_WMFS_SET_SCREEN");
|
|
W->net_atom[wmfs_screen_count] = ATOM("_WMFS_SCREEN_COUNT");
|
|
W->net_atom[wmfs_current_tag] = ATOM("_WMFS_CURRENT_TAG");
|
|
W->net_atom[wmfs_tag_list] = ATOM("_WMFS_TAG_LIST");
|
|
W->net_atom[wmfs_current_screen] = ATOM("_WMFS_CURRENT_SCREEN");
|
|
W->net_atom[wmfs_current_layout] = ATOM("_WMFS_CURRENT_LAYOUT");
|
|
W->net_atom[wmfs_function] = ATOM("_WMFS_FUNCTION");
|
|
W->net_atom[wmfs_cmd] = ATOM("_WMFS_CMD");
|
|
|
|
XChangeProperty(W->dpy, W->root, W->net_atom[net_supported], XA_ATOM, 32,
|
|
PropModeReplace, (unsigned char*)W->net_atom, net_last);
|
|
|
|
XChangeProperty(W->dpy, W->root, W->net_atom[wmfs_running], XA_CARDINAL, 32,
|
|
PropModeReplace, (unsigned char*)&b, 1);
|
|
|
|
/* Set _NET_SUPPORTING_WM_CHECK */
|
|
XChangeProperty(W->dpy, W->root, W->net_atom[net_supporting_wm_check], XA_WINDOW, 32,
|
|
PropModeReplace, (unsigned char*)&W->root, 1);
|
|
|
|
XChangeProperty(W->dpy, W->root, ATOM("WM_CLASS"), XA_STRING, 8,
|
|
PropModeReplace, (unsigned char*)&"wmfs", 4);
|
|
|
|
XChangeProperty(W->dpy, W->root, W->net_atom[net_wm_name], W->net_atom[utf8_string], 8,
|
|
PropModeReplace, (unsigned char*)&"wmfs2", 5);
|
|
|
|
/*
|
|
|
|
* Set _NET_WM_PID
|
|
XChangeProperty(W->dpy, W->root, W->net_atom[net_wm_pid], XA_CARDINAL, 32,
|
|
PropModeReplace, (unsigned char*)&pid, 1);
|
|
|
|
* Set _NET_SHOWING_DESKTOP
|
|
XChangeProperty(W->dpy, W->root, W->net_atom[net_showing_desktop], XA_CARDINAL, 32,
|
|
PropModeReplace, (unsigned char*)&showing_desk, 1);
|
|
*/
|
|
|
|
}
|
|
|
|
void
|
|
ewmh_set_wm_state(Window w, int state)
|
|
{
|
|
unsigned char d[] = { state, None };
|
|
|
|
XChangeProperty(W->dpy, w, W->net_atom[wm_state],
|
|
W->net_atom[wm_state], 32, PropModeReplace, d, 2);
|
|
}
|
|
|
|
/*
|
|
* _NET_CLIENT_LIST
|
|
*/
|
|
void
|
|
ewmh_get_client_list(void)
|
|
{
|
|
Window *list;
|
|
struct client *c;
|
|
int win_n = 0;
|
|
|
|
SLIST_FOREACH(c, &W->h.client, next)
|
|
++win_n;
|
|
|
|
list = xcalloc(win_n, sizeof(Window));
|
|
|
|
win_n = 0;
|
|
SLIST_FOREACH(c, &W->h.client, next)
|
|
list[win_n++] = c->win;
|
|
|
|
XChangeProperty(W->dpy, W->root, W->net_atom[net_client_list], XA_WINDOW, 32,
|
|
PropModeReplace, (unsigned char *)list, win_n);
|
|
|
|
XFree(list);
|
|
}
|
|
|
|
/*
|
|
* Get xembed state
|
|
*/
|
|
long
|
|
ewmh_get_xembed_state(Window win)
|
|
{
|
|
Atom rf;
|
|
int f;
|
|
long ret = 0;
|
|
unsigned long n, il;
|
|
unsigned char *data = NULL;
|
|
|
|
if(XGetWindowProperty(W->dpy, win, W->net_atom[xembedinfo], 0L, 2, False,
|
|
W->net_atom[xembedinfo], &rf, &f, &n, &il, &data) != Success)
|
|
return 0;
|
|
|
|
if(rf == W->net_atom[xembedinfo] && n == 2)
|
|
ret = (long)data[1];
|
|
|
|
if(n && data)
|
|
XFree(data);
|
|
|
|
return ret;
|
|
}
|
|
|
|
void
|
|
ewmh_update_wmfs_props(void)
|
|
{
|
|
struct screen *s;
|
|
int i, ns = 0;
|
|
long *cts = NULL;
|
|
|
|
SLIST_FOREACH(s, &W->h.screen, next)
|
|
++ns;
|
|
|
|
cts = xcalloc(ns, sizeof(long));
|
|
|
|
for(i = 0; i < ns; ++i)
|
|
{
|
|
s = screen_gb_id(i);
|
|
cts[i] = (s->seltag ? s->seltag->id : 0);
|
|
}
|
|
|
|
XChangeProperty(W->dpy, W->root, W->net_atom[wmfs_current_tag], XA_CARDINAL, 32,
|
|
PropModeReplace, (unsigned char*)cts, ns);
|
|
|
|
if(W->client)
|
|
XChangeProperty(W->dpy, W->root, W->net_atom[wmfs_focus], XA_WINDOW, 32,
|
|
PropModeReplace, (unsigned char*)&W->client->win, 1);
|
|
|
|
free(cts);
|
|
}
|
|
|
|
void
|
|
ewmh_manage_state(long data[], struct client *c)
|
|
{
|
|
/* _NET_WM_STATE_FULLSCREEN */
|
|
if(data[1] == (long)W->net_atom[net_wm_state_fullscreen]
|
|
|| data[2] == (long)W->net_atom[net_wm_state_fullscreen])
|
|
{
|
|
if(data[0] == _NET_WM_STATE_ADD
|
|
|| (data[0] == _NET_WM_STATE_TOGGLE && !(c->flags & CLIENT_FULLSCREEN)))
|
|
{
|
|
c->flags |= CLIENT_FULLSCREEN;
|
|
|
|
XChangeProperty(W->dpy, c->win, W->net_atom[net_wm_state], XA_ATOM, 32, PropModeReplace,
|
|
(unsigned char*)&W->net_atom[net_wm_state_fullscreen], 1);
|
|
XReparentWindow(W->dpy, c->win, W->root, c->screen->geo.x, c->screen->geo.y);
|
|
XResizeWindow(W->dpy, c->win, c->screen->geo.w, c->screen->geo.h);
|
|
|
|
if(c->tag)
|
|
client_focus(c);
|
|
|
|
XRaiseWindow(W->dpy, c->win);
|
|
}
|
|
else
|
|
{
|
|
c->flags &= ~CLIENT_FULLSCREEN;
|
|
|
|
XChangeProperty(W->dpy, c->win, W->net_atom[net_wm_state], XA_ATOM, 32, PropModeReplace,
|
|
(unsigned char*)0, 0);
|
|
XReparentWindow(W->dpy, c->win, c->frame, c->wgeo.x, c->wgeo.y);
|
|
|
|
if(c->flags & CLIENT_FREE)
|
|
client_moveresize(c, &c->geo);
|
|
else
|
|
layout_fix_hole(c);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
ewmh_manage_window_type(struct client *c)
|
|
{
|
|
Atom *atom, rf;
|
|
int f;
|
|
unsigned long n, il, i;
|
|
unsigned char *data = NULL;
|
|
long ldata[5] = { _NET_WM_STATE_ADD };
|
|
|
|
if(XGetWindowProperty(W->dpy, c->win, W->net_atom[net_wm_window_type], 0L, 0x7FFFFFFFL,
|
|
False, XA_ATOM, &rf, &f, &n, &il, &data) == Success && n)
|
|
{
|
|
atom = (Atom*)data;
|
|
|
|
for(i = 0; i < n; ++i)
|
|
{
|
|
/* MANAGE _NET_WM_WINDOW_TYPE_DIALOG */
|
|
if(atom[i] == W->net_atom[net_wm_window_type_dialog])
|
|
c->flags |= CLIENT_FREE;
|
|
}
|
|
XFree(data);
|
|
}
|
|
|
|
/* _NET_WM_STATE at window mangement */
|
|
if(XGetWindowProperty(W->dpy, c->win, W->net_atom[net_wm_state], 0L, 0x7FFFFFFFL, false,
|
|
XA_ATOM, &rf, &f, &n, &il, &data) == Success && n)
|
|
{
|
|
atom = (Atom*)data;
|
|
|
|
for(i = 0; i < n; ++i)
|
|
{
|
|
ldata[1] = atom[i];
|
|
ewmh_manage_state(ldata, c);
|
|
}
|
|
|
|
XFree(data);
|
|
}
|
|
}
|
|
|
|
bool
|
|
ewmh_manage_window_type_desktop(Window win)
|
|
{
|
|
Atom *atom, rf;
|
|
int f;
|
|
unsigned long n, il, i;
|
|
unsigned char *data = NULL;
|
|
bool is_desktop = false;
|
|
|
|
if(XGetWindowProperty(W->dpy, win, W->net_atom[net_wm_window_type], 0L, 0x7FFFFFFF,
|
|
False, XA_ATOM, &rf, &f, &n, &il, &data) == Success && n)
|
|
{
|
|
atom = (Atom*)data;
|
|
|
|
for(i = 0; i < n; ++i)
|
|
{
|
|
/* If it is a _NET_WM_WINDOW_TYPE_DESKTOP window */
|
|
if(atom[i] == W->net_atom[net_wm_window_type_desktop])
|
|
{
|
|
/* map it, but don't manage it */
|
|
XMapWindow(W->dpy, win);
|
|
XMapSubwindows(W->dpy, win);
|
|
|
|
is_desktop = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
XFree(data);
|
|
}
|
|
|
|
return is_desktop;
|
|
}
|