From 42f037bfb986ca6c33dc53753c11aec295374491 Mon Sep 17 00:00:00 2001 From: kazer_ Date: Fri, 26 Oct 2007 21:46:50 +0000 Subject: [PATCH] Added wcontrol for nghost switching git-svn-id: https://navit.svn.sourceforge.net/svnroot/navit/trunk@479 ffa7fe5e-494d-0410-b361-a75ebd5db220 --- navit/src/gui/sdl/wmcontrol.c | 1293 +++++++++++++++++++++++++++++++++++++++++ navit/src/gui/sdl/wmcontrol.h | 7 + 2 files changed, 1300 insertions(+) create mode 100644 navit/src/gui/sdl/wmcontrol.c create mode 100644 navit/src/gui/sdl/wmcontrol.h diff --git a/navit/src/gui/sdl/wmcontrol.c b/navit/src/gui/sdl/wmcontrol.c new file mode 100644 index 0000000..4d0fbd9 --- /dev/null +++ b/navit/src/gui/sdl/wmcontrol.c @@ -0,0 +1,1293 @@ + +// This is loosely based upon wmctrl 1.07. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "wmcontrol.h" + +#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 */ + +#define MAX_PROPERTY_VALUE_LEN 4096 +#define SELECT_WINDOW_MAGIC ":SELECT:" +#define ACTIVE_WINDOW_MAGIC ":ACTIVE:" + +#define p_verbose(...) if (options.verbose) { \ + fprintf(stderr, __VA_ARGS__); \ +} + +/* declarations of static functions *//*{{{*/ +static gboolean wm_supports (Display *disp, const gchar *prop); +static Window *get_client_list (Display *disp, unsigned long *size); +static int client_msg(Display *disp, Window win, char *msg, + unsigned long data0, unsigned long data1, + unsigned long data2, unsigned long data3, + unsigned long data4); +static int list_windows (Display *disp); +static int list_desktops (Display *disp); +static int showing_desktop (Display *disp); +static int change_viewport (Display *disp); +static int change_geometry (Display *disp); +static int change_number_of_desktops (Display *disp); +static int switch_desktop (Display *disp); +static int wm_info (Display *disp); +static gchar *get_output_str (gchar *str, gboolean is_utf8); +static int action_window (Display *disp, Window win, char mode); +static int action_window_pid (Display *disp, char mode); +static int action_window_str (Display *disp, char mode); +static int activate_window (Display *disp, Window win, + gboolean switch_desktop); +static int close_window (Display *disp, Window win); +static int longest_str (gchar **strv); +static int window_to_desktop (Display *disp, Window win, int desktop); +static void window_set_title (Display *disp, Window win, char *str, char mode); +static gchar *get_window_title (Display *disp, Window win); +static gchar *get_window_class (Display *disp, Window win); +static gchar *get_property (Display *disp, Window win, + Atom xa_prop_type, gchar *prop_name, unsigned long *size); +static void init_charset(void); +static int window_move_resize (Display *disp, Window win, char *arg); +static int window_state (Display *disp, Window win, char *arg); +static Window Select_Window(Display *dpy); +static Window get_active_window(Display *dpy); + +/*}}}*/ + +static struct { + int verbose; + int force_utf8; + int show_class; + int show_pid; + int show_geometry; + int match_by_id; + int match_by_cls; + int full_window_title_match; + int wa_desktop_titles_invalid_utf8; + char *param_window; + char *param; +} options; + +static gboolean envir_utf8; + +int window_switch() { /* {{{ */ + int opt; + int action = 0; + int ret = EXIT_SUCCESS; + int missing_option = 1; + Display *disp; + + memset(&options, 0, sizeof(options)); /* just for sure */ + + /* necessary to make g_get_charset() and g_locale_*() work */ + setlocale(LC_ALL, ""); + + /* make "--help" and "--version" work. I don't want to use + * getopt_long for portability reasons */ + + options.param_window = "Amarok"; + action = 'a'; + + + init_charset(); + + if (! (disp = XOpenDisplay(NULL))) { + fputs("Cannot open display.\n", stderr); + return EXIT_FAILURE; + } + + switch (action) { + case 'l': + ret = list_windows(disp); + break; + case 'd': + ret = list_desktops(disp); + break; + case 's': + ret = switch_desktop(disp); + break; + case 'm': + ret = wm_info(disp); + break; + case 'a': case 'c': case 'R': + case 't': case 'e': case 'b': case 'N': case 'I': case 'T': + if (! options.param_window) { + fputs("No window was specified.\n", stderr); + return EXIT_FAILURE; + } + if (options.match_by_id) { + ret = action_window_pid(disp, action); + } + else { + ret = action_window_str(disp, action); + } + break; + case 'k': + ret = showing_desktop(disp); + break; + case 'o': + ret = change_viewport(disp); + break; + case 'n': + ret = change_number_of_desktops(disp); + break; + case 'g': + ret = change_geometry(disp); + break; + } + + XCloseDisplay(disp); + return ret; +} +/* }}} */ + +static void init_charset (void) {/*{{{*/ + const gchar *charset; /* unused */ + gchar *lang = getenv("LANG") ? g_ascii_strup(getenv("LANG"), -1) : NULL; + gchar *lc_ctype = getenv("LC_CTYPE") ? g_ascii_strup(getenv("LC_CTYPE"), -1) : NULL; + + /* this glib function doesn't work on my system ... */ + envir_utf8 = g_get_charset(&charset); + + /* ... therefore we will examine the environment variables */ + if (lc_ctype && (strstr(lc_ctype, "UTF8") || strstr(lc_ctype, "UTF-8"))) { + envir_utf8 = TRUE; + } + else if (lang && (strstr(lang, "UTF8") || strstr(lang, "UTF-8"))) { + envir_utf8 = TRUE; + } + + g_free(lang); + g_free(lc_ctype); + + if (options.force_utf8) { + envir_utf8 = TRUE; + } + p_verbose("envir_utf8: %d\n", envir_utf8); +}/*}}}*/ + +static int client_msg(Display *disp, Window win, char *msg, /* {{{ */ + unsigned long data0, unsigned long data1, + unsigned long data2, unsigned long data3, + unsigned long data4) { + XEvent event; + long mask = SubstructureRedirectMask | SubstructureNotifyMask; + + event.xclient.type = ClientMessage; + event.xclient.serial = 0; + event.xclient.send_event = True; + event.xclient.message_type = XInternAtom(disp, msg, False); + event.xclient.window = win; + event.xclient.format = 32; + event.xclient.data.l[0] = data0; + event.xclient.data.l[1] = data1; + event.xclient.data.l[2] = data2; + event.xclient.data.l[3] = data3; + event.xclient.data.l[4] = data4; + + if (XSendEvent(disp, DefaultRootWindow(disp), False, mask, &event)) { + return EXIT_SUCCESS; + } + else { + fprintf(stderr, "Cannot send %s event.\n", msg); + return EXIT_FAILURE; + } +}/*}}}*/ + +static gchar *get_output_str (gchar *str, gboolean is_utf8) {/*{{{*/ + gchar *out; + + if (str == NULL) { + return NULL; + } + + if (envir_utf8) { + if (is_utf8) { + out = g_strdup(str); + } + else { + if (! (out = g_locale_to_utf8(str, -1, NULL, NULL, NULL))) { + p_verbose("Cannot convert string from locale charset to UTF-8.\n"); + out = g_strdup(str); + } + } + } + else { + if (is_utf8) { + if (! (out = g_locale_from_utf8(str, -1, NULL, NULL, NULL))) { + p_verbose("Cannot convert string from UTF-8 to locale charset.\n"); + out = g_strdup(str); + } + } + else { + out = g_strdup(str); + } + } + + return out; +}/*}}}*/ + +static int wm_info (Display *disp) {/*{{{*/ + Window *sup_window = NULL; + gchar *wm_name = NULL; + gchar *wm_class = NULL; + unsigned long *wm_pid = NULL; + unsigned long *showing_desktop = NULL; + gboolean name_is_utf8 = TRUE; + gchar *name_out; + gchar *class_out; + + if (! (sup_window = (Window *)get_property(disp, DefaultRootWindow(disp), + XA_WINDOW, "_NET_SUPPORTING_WM_CHECK", NULL))) { + if (! (sup_window = (Window *)get_property(disp, DefaultRootWindow(disp), + XA_CARDINAL, "_WIN_SUPPORTING_WM_CHECK", NULL))) { + fputs("Cannot get window manager info properties.\n" + "(_NET_SUPPORTING_WM_CHECK or _WIN_SUPPORTING_WM_CHECK)\n", stderr); + return EXIT_FAILURE; + } + } + + /* WM_NAME */ + if (! (wm_name = get_property(disp, *sup_window, + XInternAtom(disp, "UTF8_STRING", False), "_NET_WM_NAME", NULL))) { + name_is_utf8 = FALSE; + if (! (wm_name = get_property(disp, *sup_window, + XA_STRING, "_NET_WM_NAME", NULL))) { + p_verbose("Cannot get name of the window manager (_NET_WM_NAME).\n"); + } + } + name_out = get_output_str(wm_name, name_is_utf8); + + /* WM_CLASS */ + if (! (wm_class = get_property(disp, *sup_window, + XInternAtom(disp, "UTF8_STRING", False), "WM_CLASS", NULL))) { + name_is_utf8 = FALSE; + if (! (wm_class = get_property(disp, *sup_window, + XA_STRING, "WM_CLASS", NULL))) { + p_verbose("Cannot get class of the window manager (WM_CLASS).\n"); + } + } + class_out = get_output_str(wm_class, name_is_utf8); + + + /* WM_PID */ + if (! (wm_pid = (unsigned long *)get_property(disp, *sup_window, + XA_CARDINAL, "_NET_WM_PID", NULL))) { + p_verbose("Cannot get pid of the window manager (_NET_WM_PID).\n"); + } + + /* _NET_SHOWING_DESKTOP */ + if (! (showing_desktop = (unsigned long *)get_property(disp, DefaultRootWindow(disp), + XA_CARDINAL, "_NET_SHOWING_DESKTOP", NULL))) { + p_verbose("Cannot get the _NET_SHOWING_DESKTOP property.\n"); + } + + /* print out the info */ + printf("Name: %s\n", name_out ? name_out : "N/A"); + printf("Class: %s\n", class_out ? class_out : "N/A"); + + if (wm_pid) { + printf("PID: %lu\n", *wm_pid); + } + else { + printf("PID: N/A\n"); + } + + if (showing_desktop) { + printf("Window manager's \"showing the desktop\" mode: %s\n", + *showing_desktop == 1 ? "ON" : "OFF"); + } + else { + printf("Window manager's \"showing the desktop\" mode: N/A\n"); + } + + g_free(name_out); + g_free(sup_window); + g_free(wm_name); + g_free(wm_class); + g_free(wm_pid); + g_free(showing_desktop); + + return EXIT_SUCCESS; +}/*}}}*/ + +static int showing_desktop (Display *disp) {/*{{{*/ + unsigned long state; + + if (strcmp(options.param, "on") == 0) { + state = 1; + } + else if (strcmp(options.param, "off") == 0) { + state = 0; + } + else { + fputs("The argument to the -k option must be either \"on\" or \"off\"\n", stderr); + return EXIT_FAILURE; + } + + return client_msg(disp, DefaultRootWindow(disp), "_NET_SHOWING_DESKTOP", + state, 0, 0, 0, 0); +}/*}}}*/ + +static int change_viewport (Display *disp) {/*{{{*/ + unsigned long x, y; + const char *argerr = "The -o option expects two integers separated with a comma.\n"; + + if (sscanf(options.param, "%lu,%lu", &x, &y) == 2) { + return client_msg(disp, DefaultRootWindow(disp), "_NET_DESKTOP_VIEWPORT", + x, y, 0, 0, 0); + } + else { + fputs(argerr, stderr); + return EXIT_FAILURE; + } +}/*}}}*/ + +static int change_geometry (Display *disp) {/*{{{*/ + unsigned long x, y; + const char *argerr = "The -g option expects two integers separated with a comma.\n"; + + if (sscanf(options.param, "%lu,%lu", &x, &y) == 2) { + return client_msg(disp, DefaultRootWindow(disp), "_NET_DESKTOP_GEOMETRY", + x, y, 0, 0, 0); + } + else { + fputs(argerr, stderr); + return EXIT_FAILURE; + } +}/*}}}*/ + +static int change_number_of_desktops (Display *disp) {/*{{{*/ + unsigned long n; + + if (sscanf(options.param, "%lu", &n) != 1) { + fputs("The -n option expects an integer.\n", stderr); + return EXIT_FAILURE; + } + + return client_msg(disp, DefaultRootWindow(disp), "_NET_NUMBER_OF_DESKTOPS", + n, 0, 0, 0, 0); +}/*}}}*/ + +static int switch_desktop (Display *disp) {/*{{{*/ + int target = -1; + + target = atoi(options.param); + if (target == -1) { + fputs("Invalid desktop ID.\n", stderr); + return EXIT_FAILURE; + } + + return client_msg(disp, DefaultRootWindow(disp), "_NET_CURRENT_DESKTOP", + (unsigned long)target, 0, 0, 0, 0); +}/*}}}*/ + +static void window_set_title (Display *disp, Window win, /* {{{ */ + char *title, char mode) { + gchar *title_utf8; + gchar *title_local; + + if (envir_utf8) { + title_utf8 = g_strdup(title); + title_local = NULL; + } + else { + if (! (title_utf8 = g_locale_to_utf8(title, -1, NULL, NULL, NULL))) { + title_utf8 = g_strdup(title); + } + title_local = g_strdup(title); + } + + if (mode == 'T' || mode == 'N') { + /* set name */ + if (title_local) { + XChangeProperty(disp, win, XA_WM_NAME, XA_STRING, 8, PropModeReplace, + title_local, strlen(title_local)); + } + else { + XDeleteProperty(disp, win, XA_WM_NAME); + } + XChangeProperty(disp, win, XInternAtom(disp, "_NET_WM_NAME", False), + XInternAtom(disp, "UTF8_STRING", False), 8, PropModeReplace, + title_utf8, strlen(title_utf8)); + } + + if (mode == 'T' || mode == 'I') { + /* set icon name */ + if (title_local) { + XChangeProperty(disp, win, XA_WM_ICON_NAME, XA_STRING, 8, PropModeReplace, + title_local, strlen(title_local)); + } + else { + XDeleteProperty(disp, win, XA_WM_ICON_NAME); + } + XChangeProperty(disp, win, XInternAtom(disp, "_NET_WM_ICON_NAME", False), + XInternAtom(disp, "UTF8_STRING", False), 8, PropModeReplace, + title_utf8, strlen(title_utf8)); + } + + g_free(title_utf8); + g_free(title_local); + +}/*}}}*/ + +static int window_to_desktop (Display *disp, Window win, int desktop) {/*{{{*/ + unsigned long *cur_desktop = NULL; + Window root = DefaultRootWindow(disp); + + if (desktop == -1) { + if (! (cur_desktop = (unsigned long *)get_property(disp, root, + XA_CARDINAL, "_NET_CURRENT_DESKTOP", NULL))) { + if (! (cur_desktop = (unsigned long *)get_property(disp, root, + XA_CARDINAL, "_WIN_WORKSPACE", NULL))) { + fputs("Cannot get current desktop properties. " + "(_NET_CURRENT_DESKTOP or _WIN_WORKSPACE property)" + "\n", stderr); + return EXIT_FAILURE; + } + } + desktop = *cur_desktop; + } + g_free(cur_desktop); + + return client_msg(disp, win, "_NET_WM_DESKTOP", (unsigned long)desktop, + 0, 0, 0, 0); +}/*}}}*/ + +static int activate_window (Display *disp, Window win, /* {{{ */ + gboolean switch_desktop) { + unsigned long *desktop; + + + printf("sounds good\n"); + /* desktop ID */ + if ((desktop = (unsigned long *)get_property(disp, win, + XA_CARDINAL, "_NET_WM_DESKTOP", NULL)) == NULL) { + if ((desktop = (unsigned long *)get_property(disp, win, + XA_CARDINAL, "_WIN_WORKSPACE", NULL)) == NULL) { + p_verbose("Cannot find desktop ID of the window.\n"); + } + } + + if (switch_desktop && desktop) { + if (client_msg(disp, DefaultRootWindow(disp), + "_NET_CURRENT_DESKTOP", + *desktop, 0, 0, 0, 0) != EXIT_SUCCESS) { + p_verbose("Cannot switch desktop.\n"); + } + g_free(desktop); + } + + client_msg(disp, win, "_NET_ACTIVE_WINDOW", + 0, 0, 0, 0, 0); + XMapRaised(disp, win); + + return EXIT_SUCCESS; +}/*}}}*/ + +static int close_window (Display *disp, Window win) {/*{{{*/ + return client_msg(disp, win, "_NET_CLOSE_WINDOW", + 0, 0, 0, 0, 0); +}/*}}}*/ + +static int window_state (Display *disp, Window win, char *arg) {/*{{{*/ + unsigned long action; + Atom prop1 = 0; + Atom prop2 = 0; + char *p1, *p2; + const char *argerr = "The -b option expects a list of comma separated parameters: \"(remove|add|toggle),[,]\"\n"; + + if (!arg || strlen(arg) == 0) { + fputs(argerr, stderr); + return EXIT_FAILURE; + } + + if ((p1 = strchr(arg, ','))) { + gchar *tmp_prop1, *tmp1; + + *p1 = '\0'; + + /* action */ + if (strcmp(arg, "remove") == 0) { + action = _NET_WM_STATE_REMOVE; + } + else if (strcmp(arg, "add") == 0) { + action = _NET_WM_STATE_ADD; + } + else if (strcmp(arg, "toggle") == 0) { + action = _NET_WM_STATE_TOGGLE; + } + else { + fputs("Invalid action. Use either remove, add or toggle.\n", stderr); + return EXIT_FAILURE; + } + p1++; + + /* the second property */ + if ((p2 = strchr(p1, ','))) { + gchar *tmp_prop2, *tmp2; + *p2 = '\0'; + p2++; + if (strlen(p2) == 0) { + fputs("Invalid zero length property.\n", stderr); + return EXIT_FAILURE; + } + tmp_prop2 = g_strdup_printf("_NET_WM_STATE_%s", tmp2 = g_ascii_strup(p2, -1)); + p_verbose("State 2: %s\n", tmp_prop2); + prop2 = XInternAtom(disp, tmp_prop2, False); + g_free(tmp2); + g_free(tmp_prop2); + } + + /* the first property */ + if (strlen(p1) == 0) { + fputs("Invalid zero length property.\n", stderr); + return EXIT_FAILURE; + } + tmp_prop1 = g_strdup_printf("_NET_WM_STATE_%s", tmp1 = g_ascii_strup(p1, -1)); + p_verbose("State 1: %s\n", tmp_prop1); + prop1 = XInternAtom(disp, tmp_prop1, False); + g_free(tmp1); + g_free(tmp_prop1); + + + return client_msg(disp, win, "_NET_WM_STATE", + action, (unsigned long)prop1, (unsigned long)prop2, 0, 0); + } + else { + fputs(argerr, stderr); + return EXIT_FAILURE; + } +}/*}}}*/ + +static gboolean wm_supports (Display *disp, const gchar *prop) {/*{{{*/ + Atom xa_prop = XInternAtom(disp, prop, False); + Atom *list; + unsigned long size; + int i; + + if (! (list = (Atom *)get_property(disp, DefaultRootWindow(disp), + XA_ATOM, "_NET_SUPPORTED", &size))) { + p_verbose("Cannot get _NET_SUPPORTED property.\n"); + return FALSE; + } + + for (i = 0; i < size / sizeof(Atom); i++) { + if (list[i] == xa_prop) { + g_free(list); + return TRUE; + } + } + + g_free(list); + return FALSE; +}/*}}}*/ + +static int window_move_resize (Display *disp, Window win, char *arg) {/*{{{*/ + signed long grav, x, y, w, h; + unsigned long grflags; + const char *argerr = "The -e option expects a list of comma separated integers: \"gravity,X,Y,width,height\"\n"; + + if (!arg || strlen(arg) == 0) { + fputs(argerr, stderr); + return EXIT_FAILURE; + } + + if (sscanf(arg, "%ld,%ld,%ld,%ld,%ld", &grav, &x, &y, &w, &h) != 5) { + fputs(argerr, stderr); + return EXIT_FAILURE; + } + + if (grav < 0) { + fputs("Value of gravity mustn't be negative. Use zero to use the default gravity of the window.\n", stderr); + return EXIT_FAILURE; + } + + grflags = grav; + if (x != -1) grflags |= (1 << 8); + if (y != -1) grflags |= (1 << 9); + if (w != -1) grflags |= (1 << 10); + if (h != -1) grflags |= (1 << 11); + + p_verbose("grflags: %lu\n", grflags); + + if (wm_supports(disp, "_NET_MOVERESIZE_WINDOW")){ + return client_msg(disp, win, "_NET_MOVERESIZE_WINDOW", + grflags, (unsigned long)x, (unsigned long)y, (unsigned long)w, (unsigned long)h); + } + else { + p_verbose("WM doesn't support _NET_MOVERESIZE_WINDOW. Gravity will be ignored.\n"); + if ((w < 1 || h < 1) && (x >= 0 && y >= 0)) { + XMoveWindow(disp, win, x, y); + } + else if ((x < 0 || y < 0) && (w >= 1 && h >= -1)) { + XResizeWindow(disp, win, w, h); + } + else if (x >= 0 && y >= 0 && w >= 1 && h >= 1) { + XMoveResizeWindow(disp, win, x, y, w, h); + } + return EXIT_SUCCESS; + } +}/*}}}*/ + +static int action_window (Display *disp, Window win, char mode) {/*{{{*/ + p_verbose("Using window: 0x%.8lx\n", win); + switch (mode) { + case 'a': + return activate_window(disp, win, TRUE); + + case 'c': + return close_window(disp, win); + + case 'e': + /* resize/move the window around the desktop => -r -e */ + return window_move_resize(disp, win, options.param); + + case 'b': + /* change state of a window => -r -b */ + return window_state(disp, win, options.param); + + case 't': + /* move the window to the specified desktop => -r -t */ + return window_to_desktop(disp, win, atoi(options.param)); + + case 'R': + /* move the window to the current desktop and activate it => -r */ + if (window_to_desktop(disp, win, -1) == EXIT_SUCCESS) { + usleep(100000); /* 100 ms - make sure the WM has enough + time to move the window, before we activate it */ + return activate_window(disp, win, FALSE); + } + else { + return EXIT_FAILURE; + } + + case 'N': case 'I': case 'T': + window_set_title(disp, win, options.param, mode); + return EXIT_SUCCESS; + + default: + fprintf(stderr, "Unknown action: '%c'\n", mode); + return EXIT_FAILURE; + } +}/*}}}*/ + +static int action_window_pid (Display *disp, char mode) {/*{{{*/ + unsigned long wid; + + if (sscanf(options.param_window, "0x%lx", &wid) != 1 && + sscanf(options.param_window, "0X%lx", &wid) != 1 && + sscanf(options.param_window, "%lu", &wid) != 1) { + fputs("Cannot convert argument to number.\n", stderr); + return EXIT_FAILURE; + } + + return action_window(disp, (Window)wid, mode); +}/*}}}*/ + +static int action_window_str (Display *disp, char mode) {/*{{{*/ + Window activate = 0; + Window *client_list; + unsigned long client_list_size; + int i; + + if (strcmp(SELECT_WINDOW_MAGIC, options.param_window) == 0) { + activate = Select_Window(disp); + if (activate) { + return action_window(disp, activate, mode); + } + else { + return EXIT_FAILURE; + } + } + if (strcmp(ACTIVE_WINDOW_MAGIC, options.param_window) == 0) { + activate = get_active_window(disp); + if (activate) + { + return action_window(disp, activate, mode); + } + else + { + return EXIT_FAILURE; + } + } + else { + if ((client_list = get_client_list(disp, &client_list_size)) == NULL) { + return EXIT_FAILURE; + } + + for (i = 0; i < client_list_size / sizeof(Window); i++) { + gchar *match_utf8; + if (options.show_class) { + match_utf8 = get_window_class(disp, client_list[i]); /* UTF8 */ + } + else { + match_utf8 = get_window_title(disp, client_list[i]); /* UTF8 */ + } + if (match_utf8) { + gchar *match; + gchar *match_cf; + gchar *match_utf8_cf = NULL; + if (envir_utf8) { + match = g_strdup(options.param_window); + match_cf = g_utf8_casefold(options.param_window, -1); + } + else { + if (! (match = g_locale_to_utf8(options.param_window, -1, NULL, NULL, NULL))) { + match = g_strdup(options.param_window); + } + match_cf = g_utf8_casefold(match, -1); + } + + if (!match || !match_cf) { + continue; + } + + match_utf8_cf = g_utf8_casefold(match_utf8, -1); + + if ((options.full_window_title_match && strcmp(match_utf8, match) == 0) || + (!options.full_window_title_match && strstr(match_utf8_cf, match_cf))) { + activate = client_list[i]; + g_free(match); + g_free(match_cf); + g_free(match_utf8); + g_free(match_utf8_cf); + break; + } + g_free(match); + g_free(match_cf); + g_free(match_utf8); + g_free(match_utf8_cf); + } + } + g_free(client_list); + + if (activate) { + return action_window(disp, activate, mode); + } + else { + return EXIT_FAILURE; + } + } +}/*}}}*/ + +static int list_desktops (Display *disp) {/*{{{*/ + unsigned long *num_desktops = NULL; + unsigned long *cur_desktop = NULL; + unsigned long desktop_list_size = 0; + unsigned long *desktop_geometry = NULL; + unsigned long desktop_geometry_size = 0; + gchar **desktop_geometry_str = NULL; + unsigned long *desktop_viewport = NULL; + unsigned long desktop_viewport_size = 0; + gchar **desktop_viewport_str = NULL; + unsigned long *desktop_workarea = NULL; + unsigned long desktop_workarea_size = 0; + gchar **desktop_workarea_str = NULL; + gchar *list = NULL; + int i; + int id; + Window root = DefaultRootWindow(disp); + int ret = EXIT_FAILURE; + gchar **names = NULL; + gboolean names_are_utf8 = TRUE; + + if (! (num_desktops = (unsigned long *)get_property(disp, root, + XA_CARDINAL, "_NET_NUMBER_OF_DESKTOPS", NULL))) { + if (! (num_desktops = (unsigned long *)get_property(disp, root, + XA_CARDINAL, "_WIN_WORKSPACE_COUNT", NULL))) { + fputs("Cannot get number of desktops properties. " + "(_NET_NUMBER_OF_DESKTOPS or _WIN_WORKSPACE_COUNT)" + "\n", stderr); + goto cleanup; + } + } + + if (! (cur_desktop = (unsigned long *)get_property(disp, root, + XA_CARDINAL, "_NET_CURRENT_DESKTOP", NULL))) { + if (! (cur_desktop = (unsigned long *)get_property(disp, root, + XA_CARDINAL, "_WIN_WORKSPACE", NULL))) { + fputs("Cannot get current desktop properties. " + "(_NET_CURRENT_DESKTOP or _WIN_WORKSPACE property)" + "\n", stderr); + goto cleanup; + } + } + + if (options.wa_desktop_titles_invalid_utf8 || + (list = get_property(disp, root, + XInternAtom(disp, "UTF8_STRING", False), + "_NET_DESKTOP_NAMES", &desktop_list_size)) == NULL) { + names_are_utf8 = FALSE; + if ((list = get_property(disp, root, + XA_STRING, + "_WIN_WORKSPACE_NAMES", &desktop_list_size)) == NULL) { + p_verbose("Cannot get desktop names properties. " + "(_NET_DESKTOP_NAMES or _WIN_WORKSPACE_NAMES)" + "\n"); + /* ignore the error - list the desktops without names */ + } + } + + /* common size of all desktops */ + if (! (desktop_geometry = (unsigned long *)get_property(disp, DefaultRootWindow(disp), + XA_CARDINAL, "_NET_DESKTOP_GEOMETRY", &desktop_geometry_size))) { + p_verbose("Cannot get common size of all desktops (_NET_DESKTOP_GEOMETRY).\n"); + } + + /* desktop viewport */ + if (! (desktop_viewport = (unsigned long *)get_property(disp, DefaultRootWindow(disp), + XA_CARDINAL, "_NET_DESKTOP_VIEWPORT", &desktop_viewport_size))) { + p_verbose("Cannot get common size of all desktops (_NET_DESKTOP_VIEWPORT).\n"); + } + + /* desktop workarea */ + if (! (desktop_workarea = (unsigned long *)get_property(disp, DefaultRootWindow(disp), + XA_CARDINAL, "_NET_WORKAREA", &desktop_workarea_size))) { + if (! (desktop_workarea = (unsigned long *)get_property(disp, DefaultRootWindow(disp), + XA_CARDINAL, "_WIN_WORKAREA", &desktop_workarea_size))) { + p_verbose("Cannot get _NET_WORKAREA property.\n"); + } + } + + /* prepare the array of desktop names */ + names = g_malloc0(*num_desktops * sizeof(char *)); + if (list) { + id = 0; + names[id++] = list; + for (i = 0; i < desktop_list_size; i++) { + if (list[i] == '\0') { + if (id >= *num_desktops) { + break; + } + names[id++] = list + i + 1; + } + } + } + + /* prepare desktop geometry strings */ + desktop_geometry_str = g_malloc0((*num_desktops + 1) * sizeof(char *)); + if (desktop_geometry && desktop_geometry_size > 0) { + if (desktop_geometry_size == 2 * sizeof(*desktop_geometry)) { + /* only one value - use it for all desktops */ + p_verbose("WM provides _NET_DESKTOP_GEOMETRY value common for all desktops.\n"); + for (i = 0; i < *num_desktops; i++) { + desktop_geometry_str[i] = g_strdup_printf("%lux%lu", + desktop_geometry[0], desktop_geometry[1]); + } + } + else { + /* seperate values for desktops of different size */ + p_verbose("WM provides separate _NET_DESKTOP_GEOMETRY value for each desktop.\n"); + for (i = 0; i < *num_desktops; i++) { + if (i < desktop_geometry_size / sizeof(*desktop_geometry) / 2) { + desktop_geometry_str[i] = g_strdup_printf("%lux%lu", + desktop_geometry[i*2], desktop_geometry[i*2+1]); + } + else { + desktop_geometry_str[i] = g_strdup("N/A"); + } + } + } + } + else { + for (i = 0; i < *num_desktops; i++) { + desktop_geometry_str[i] = g_strdup("N/A"); + } + } + + /* prepare desktop viewport strings */ + desktop_viewport_str = g_malloc0((*num_desktops + 1) * sizeof(char *)); + if (desktop_viewport && desktop_viewport_size > 0) { + if (desktop_viewport_size == 2 * sizeof(*desktop_viewport)) { + /* only one value - use it for current desktop */ + p_verbose("WM provides _NET_DESKTOP_VIEWPORT value only for the current desktop.\n"); + for (i = 0; i < *num_desktops; i++) { + if (i == *cur_desktop) { + desktop_viewport_str[i] = g_strdup_printf("%lu,%lu", + desktop_viewport[0], desktop_viewport[1]); + } + else { + desktop_viewport_str[i] = g_strdup("N/A"); + } + } + } + else { + /* seperate values for each of desktops */ + for (i = 0; i < *num_desktops; i++) { + if (i < desktop_viewport_size / sizeof(*desktop_viewport) / 2) { + desktop_viewport_str[i] = g_strdup_printf("%lu,%lu", + desktop_viewport[i*2], desktop_viewport[i*2+1]); + } + else { + desktop_viewport_str[i] = g_strdup("N/A"); + } + } + } + } + else { + for (i = 0; i < *num_desktops; i++) { + desktop_viewport_str[i] = g_strdup("N/A"); + } + } + + /* prepare desktop workarea strings */ + desktop_workarea_str = g_malloc0((*num_desktops + 1) * sizeof(char *)); + if (desktop_workarea && desktop_workarea_size > 0) { + if (desktop_workarea_size == 4 * sizeof(*desktop_workarea)) { + /* only one value - use it for current desktop */ + p_verbose("WM provides _NET_WORKAREA value only for the current desktop.\n"); + for (i = 0; i < *num_desktops; i++) { + if (i == *cur_desktop) { + desktop_workarea_str[i] = g_strdup_printf("%lu,%lu %lux%lu", + desktop_workarea[0], desktop_workarea[1], + desktop_workarea[2], desktop_workarea[3]); + } + else { + desktop_workarea_str[i] = g_strdup("N/A"); + } + } + } + else { + /* seperate values for each of desktops */ + for (i = 0; i < *num_desktops; i++) { + if (i < desktop_workarea_size / sizeof(*desktop_workarea) / 4) { + desktop_workarea_str[i] = g_strdup_printf("%lu,%lu %lux%lu", + desktop_workarea[i*4], desktop_workarea[i*4+1], + desktop_workarea[i*4+2], desktop_workarea[i*4+3]); + } + else { + desktop_workarea_str[i] = g_strdup("N/A"); + } + } + } + } + else { + for (i = 0; i < *num_desktops; i++) { + desktop_workarea_str[i] = g_strdup("N/A"); + } + } + + /* print the list */ + for (i = 0; i < *num_desktops; i++) { + gchar *out = get_output_str(names[i], names_are_utf8); + printf("%-2d %c DG: %-*s VP: %-*s WA: %-*s %s\n", i, i == *cur_desktop ? '*' : '-', + longest_str(desktop_geometry_str), desktop_geometry_str[i], + longest_str(desktop_viewport_str), desktop_viewport_str[i], + longest_str(desktop_workarea_str), desktop_workarea_str[i], + out ? out : "N/A"); + g_free(out); + } + + p_verbose("Total number of desktops: %lu\n", *num_desktops); + p_verbose("Current desktop ID (counted from zero): %lu\n", *cur_desktop); + + ret = EXIT_SUCCESS; + goto cleanup; + +cleanup: + g_free(names); + g_free(num_desktops); + g_free(cur_desktop); + g_free(desktop_geometry); + g_strfreev(desktop_geometry_str); + g_free(desktop_viewport); + g_strfreev(desktop_viewport_str); + g_free(desktop_workarea); + g_strfreev(desktop_workarea_str); + g_free(list); + + return ret; +}/*}}}*/ + +static int longest_str (gchar **strv) {/*{{{*/ + int max = 0; + int i = 0; + + while (strv && strv[i]) { + if (strlen(strv[i]) > max) { + max = strlen(strv[i]); + } + i++; + } + + return max; +}/*}}}*/ + +static Window *get_client_list (Display *disp, unsigned long *size) {/*{{{*/ + Window *client_list; + + if ((client_list = (Window *)get_property(disp, DefaultRootWindow(disp), + XA_WINDOW, "_NET_CLIENT_LIST", size)) == NULL) { + if ((client_list = (Window *)get_property(disp, DefaultRootWindow(disp), + XA_CARDINAL, "_WIN_CLIENT_LIST", size)) == NULL) { + fputs("Cannot get client list properties. \n" + "(_NET_CLIENT_LIST or _WIN_CLIENT_LIST)" + "\n", stderr); + return NULL; + } + } + + return client_list; +}/*}}}*/ + +static int list_windows (Display *disp) {/*{{{*/ + Window *client_list; + unsigned long client_list_size; + int i; + int max_client_machine_len = 0; + + if ((client_list = get_client_list(disp, &client_list_size)) == NULL) { + return EXIT_FAILURE; + } + + /* find the longest client_machine name */ + for (i = 0; i < client_list_size / sizeof(Window); i++) { + gchar *client_machine; + if ((client_machine = get_property(disp, client_list[i], + XA_STRING, "WM_CLIENT_MACHINE", NULL))) { + max_client_machine_len = strlen(client_machine); + } + g_free(client_machine); + } + + /* print the list */ + for (i = 0; i < client_list_size / sizeof(Window); i++) { + gchar *title_utf8 = get_window_title(disp, client_list[i]); /* UTF8 */ + gchar *title_out = get_output_str(title_utf8, TRUE); + gchar *client_machine; + gchar *class_out = get_window_class(disp, client_list[i]); /* UTF8 */ + unsigned long *pid; + unsigned long *desktop; + int x, y, junkx, junky; + unsigned int wwidth, wheight, bw, depth; + Window junkroot; + + /* desktop ID */ + if ((desktop = (unsigned long *)get_property(disp, client_list[i], + XA_CARDINAL, "_NET_WM_DESKTOP", NULL)) == NULL) { + desktop = (unsigned long *)get_property(disp, client_list[i], + XA_CARDINAL, "_WIN_WORKSPACE", NULL); + } + + /* client machine */ + client_machine = get_property(disp, client_list[i], + XA_STRING, "WM_CLIENT_MACHINE", NULL); + + /* pid */ + pid = (unsigned long *)get_property(disp, client_list[i], + XA_CARDINAL, "_NET_WM_PID", NULL); + + /* geometry */ + XGetGeometry (disp, client_list[i], &junkroot, &junkx, &junky, + &wwidth, &wheight, &bw, &depth); + XTranslateCoordinates (disp, client_list[i], junkroot, junkx, junky, + &x, &y, &junkroot); + + /* special desktop ID -1 means "all desktops", so we + have to convert the desktop value to signed long */ + printf("0x%.8lx %2ld", client_list[i], + desktop ? (signed long)*desktop : 0); + if (options.show_pid) { + printf(" %-6lu", pid ? *pid : 0); + } + if (options.show_geometry) { + printf(" %-4d %-4d %-4d %-4d", x, y, wwidth, wheight); + } + if (options.show_class) { + printf(" %-20s ", class_out ? class_out : "N/A"); + } + + printf(" %*s %s\n", + max_client_machine_len, + client_machine ? client_machine : "N/A", + title_out ? title_out : "N/A" + ); + g_free(title_utf8); + g_free(title_out); + g_free(desktop); + g_free(client_machine); + g_free(class_out); + g_free(pid); + } + g_free(client_list); + + return EXIT_SUCCESS; +}/*}}}*/ + +static gchar *get_window_class (Display *disp, Window win) {/*{{{*/ + gchar *class_utf8; + gchar *wm_class; + unsigned long size; + + wm_class = get_property(disp, win, XA_STRING, "WM_CLASS", &size); + if (wm_class) { + gchar *p_0 = strchr(wm_class, '\0'); + if (wm_class + size - 1 > p_0) { + *(p_0) = '.'; + } + class_utf8 = g_locale_to_utf8(wm_class, -1, NULL, NULL, NULL); + } + else { + class_utf8 = NULL; + } + + g_free(wm_class); + + return class_utf8; +}/*}}}*/ + +static gchar *get_window_title (Display *disp, Window win) {/*{{{*/ + gchar *title_utf8; + gchar *wm_name; + gchar *net_wm_name; + + wm_name = get_property(disp, win, XA_STRING, "WM_NAME", NULL); + net_wm_name = get_property(disp, win, + XInternAtom(disp, "UTF8_STRING", False), "_NET_WM_NAME", NULL); + + if (net_wm_name) { + title_utf8 = g_strdup(net_wm_name); + } + else { + if (wm_name) { + title_utf8 = g_locale_to_utf8(wm_name, -1, NULL, NULL, NULL); + } + else { + title_utf8 = NULL; + } + } + + g_free(wm_name); + g_free(net_wm_name); + + return title_utf8; +}/*}}}*/ + +static gchar *get_property (Display *disp, Window win, /*{{{*/ + Atom xa_prop_type, gchar *prop_name, unsigned long *size) { + Atom xa_prop_name; + Atom xa_ret_type; + int ret_format; + unsigned long ret_nitems; + unsigned long ret_bytes_after; + unsigned long tmp_size; + unsigned char *ret_prop; + gchar *ret; + + xa_prop_name = XInternAtom(disp, prop_name, False); + + /* MAX_PROPERTY_VALUE_LEN / 4 explanation (XGetWindowProperty manpage): + * + * long_length = Specifies the length in 32-bit multiples of the + * data to be retrieved. + */ + if (XGetWindowProperty(disp, win, xa_prop_name, 0, MAX_PROPERTY_VALUE_LEN / 4, False, + xa_prop_type, &xa_ret_type, &ret_format, + &ret_nitems, &ret_bytes_after, &ret_prop) != Success) { + p_verbose("Cannot get %s property.\n", prop_name); + return NULL; + } + + if (xa_ret_type != xa_prop_type) { + p_verbose("Invalid type of %s property.\n", prop_name); + XFree(ret_prop); + return NULL; + } + + /* null terminate the result to make string handling easier */ + tmp_size = (ret_format / 8) * ret_nitems; + ret = g_malloc(tmp_size + 1); + memcpy(ret, ret_prop, tmp_size); + ret[tmp_size] = '\0'; + + if (size) { + *size = tmp_size; + } + + XFree(ret_prop); + return ret; +}/*}}}*/ + +static Window Select_Window(Display *dpy) {/*{{{*/ + /* + * Routine to let user select a window using the mouse + * Taken from xfree86. + */ + + int status; + Cursor cursor; + XEvent event; + Window target_win = None, root = DefaultRootWindow(dpy); + int buttons = 0; + int dummyi; + unsigned int dummy; + + /* Make the target cursor */ + cursor = XCreateFontCursor(dpy, XC_crosshair); + + /* Grab the pointer using target cursor, letting it room all over */ + status = XGrabPointer(dpy, root, False, + ButtonPressMask|ButtonReleaseMask, GrabModeSync, + GrabModeAsync, root, cursor, CurrentTime); + if (status != GrabSuccess) { + fputs("ERROR: Cannot grab mouse.\n", stderr); + return 0; + } + + /* Let the user select a window... */ + while ((target_win == None) || (buttons != 0)) { + /* allow one more event */ + XAllowEvents(dpy, SyncPointer, CurrentTime); + XWindowEvent(dpy, root, ButtonPressMask|ButtonReleaseMask, &event); + switch (event.type) { + case ButtonPress: + if (target_win == None) { + target_win = event.xbutton.subwindow; /* window selected */ + if (target_win == None) target_win = root; + } + buttons++; + break; + case ButtonRelease: + if (buttons > 0) /* there may have been some down before we started */ + buttons--; + break; + } + } + + XUngrabPointer(dpy, CurrentTime); /* Done with pointer */ + + if (XGetGeometry (dpy, target_win, &root, &dummyi, &dummyi, + &dummy, &dummy, &dummy, &dummy) && target_win != root) { + target_win = XmuClientWindow (dpy, target_win); + } + + return(target_win); +}/*}}}*/ + +static Window get_active_window(Display *disp) {/*{{{*/ + char *prop; + unsigned long size; + Window ret = (Window)0; + + prop = get_property(disp, DefaultRootWindow(disp), XA_WINDOW, + "_NET_ACTIVE_WINDOW", &size); + if (prop) { + ret = *((Window*)prop); + g_free(prop); + } + + return(ret); +}/*}}}*/ + + diff --git a/navit/src/gui/sdl/wmcontrol.h b/navit/src/gui/sdl/wmcontrol.h new file mode 100644 index 0000000..0934a87 --- /dev/null +++ b/navit/src/gui/sdl/wmcontrol.h @@ -0,0 +1,7 @@ +#ifdef __cplusplus +extern "C" { +#endif +int window_switch(); +#ifdef __cplusplus +} +#endif \ No newline at end of file -- 2.7.4