/* * wmfs2 by Martin Duquesnoy { 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_state_sticky(struct client *c) { Atom *atom, rf; int f; unsigned long n, il, i; unsigned char *data = NULL; 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) { /* manage _NET_WM_STATE_STICKY */ if(atom[i] == W->net_atom[net_wm_state_sticky]) { c->flags |= CLIENT_STICKY; c->flags |= CLIENT_FREE; client_place_at_mouse(c); break; } } XFree(data); } } 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; }