Blame libxklavier/xklavier_util.c

Packit Service 93d855
/*
Packit Service 93d855
 * Copyright (C) 2002-2006 Sergey V. Udaltsov <svu@gnome.org>
Packit Service 93d855
 *
Packit Service 93d855
 * This library is free software; you can redistribute it and/or
Packit Service 93d855
 * modify it under the terms of the GNU Lesser General Public
Packit Service 93d855
 * License as published by the Free Software Foundation; either
Packit Service 93d855
 * version 2 of the License, or (at your option) any later version.
Packit Service 93d855
 *
Packit Service 93d855
 * This library is distributed in the hope that it will be useful,
Packit Service 93d855
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 93d855
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 93d855
 * Lesser General Public License for more details.
Packit Service 93d855
 *
Packit Service 93d855
 * You should have received a copy of the GNU Lesser General Public
Packit Service 93d855
 * License along with this library; if not, write to the
Packit Service 93d855
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Packit Service 93d855
 * Boston, MA 02111-1307, USA.
Packit Service 93d855
 */
Packit Service 93d855
Packit Service 93d855
#include <time.h>
Packit Service 93d855
#include <string.h>
Packit Service 93d855
Packit Service 93d855
#include <X11/Xatom.h>
Packit Service 93d855
#include <X11/Xlib.h>
Packit Service 93d855
#include <X11/Xutil.h>
Packit Service 93d855
Packit Service 93d855
#include "xklavier_private.h"
Packit Service 93d855
Packit Service 93d855
XklState *
Packit Service 93d855
_xkl_state_copy(XklState * state)
Packit Service 93d855
{
Packit Service 93d855
	XklState * copy;
Packit Service 93d855
Packit Service 93d855
	copy = g_new(XklState, 1);
Packit Service 93d855
	copy->group = state->group;
Packit Service 93d855
	copy->indicators = state->indicators;
Packit Service 93d855
Packit Service 93d855
	return copy;
Packit Service 93d855
}
Packit Service 93d855
Packit Service 93d855
G_DEFINE_BOXED_TYPE (XklState, xkl_state, _xkl_state_copy, g_free);
Packit Service 93d855
Packit Service 93d855
XklState *
Packit Service 93d855
xkl_engine_get_current_state(XklEngine * engine)
Packit Service 93d855
{
Packit Service 93d855
	return &xkl_engine_priv(engine, curr_state);
Packit Service 93d855
}
Packit Service 93d855
Packit Service 93d855
const gchar *
Packit Service 93d855
xkl_get_last_error()
Packit Service 93d855
{
Packit Service 93d855
	return xkl_last_error_message;
Packit Service 93d855
}
Packit Service 93d855
Packit Service 93d855
gchar *
Packit Service 93d855
xkl_engine_get_window_title(XklEngine * engine, Window w)
Packit Service 93d855
{
Packit Service 93d855
	Atom type_ret;
Packit Service 93d855
	int format_ret;
Packit Service 93d855
	unsigned long nitems, rest;
Packit Service 93d855
	unsigned char *prop;
Packit Service 93d855
Packit Service 93d855
	if ((w == xkl_engine_priv(engine, root_window))
Packit Service 93d855
	    || (w == PointerRoot))
Packit Service 93d855
		return g_strdup("ROOT");
Packit Service 93d855
Packit Service 93d855
	if (Success ==
Packit Service 93d855
	    XGetWindowProperty(xkl_engine_get_display(engine), w,
Packit Service 93d855
			       xkl_engine_priv(engine, atoms)[WM_NAME], 0L,
Packit Service 93d855
			       -1L, False, XA_STRING, &type_ret,
Packit Service 93d855
			       &format_ret, &nitems, &rest, &prop))
Packit Service 93d855
		return (gchar *) prop;
Packit Service 93d855
	else
Packit Service 93d855
		return NULL;
Packit Service 93d855
}
Packit Service 93d855
Packit Service 93d855
gboolean
Packit Service 93d855
xkl_engine_is_window_from_same_toplevel_window(XklEngine * engine,
Packit Service 93d855
					       Window win1, Window win2)
Packit Service 93d855
{
Packit Service 93d855
	Window app1, app2;
Packit Service 93d855
	return xkl_engine_find_toplevel_window(engine, win1, &app1) &&
Packit Service 93d855
	    xkl_engine_find_toplevel_window(engine, win2, &app2)
Packit Service 93d855
	    && app1 == app2;
Packit Service 93d855
}
Packit Service 93d855
Packit Service 93d855
gboolean
Packit Service 93d855
xkl_engine_get_state(XklEngine * engine, Window win, XklState * state_out)
Packit Service 93d855
{
Packit Service 93d855
	Window app_win;
Packit Service 93d855
Packit Service 93d855
	if (!xkl_engine_find_toplevel_window(engine, win, &app_win)) {
Packit Service 93d855
		if (state_out != NULL)
Packit Service 93d855
			state_out->group = -1;
Packit Service 93d855
		return FALSE;
Packit Service 93d855
	}
Packit Service 93d855
Packit Service 93d855
	return xkl_engine_get_toplevel_window_state(engine, app_win,
Packit Service 93d855
						    state_out);
Packit Service 93d855
}
Packit Service 93d855
Packit Service 93d855
void
Packit Service 93d855
xkl_engine_delete_state(XklEngine * engine, Window win)
Packit Service 93d855
{
Packit Service 93d855
	Window app_win;
Packit Service 93d855
Packit Service 93d855
	if (xkl_engine_find_toplevel_window(engine, win, &app_win))
Packit Service 93d855
		xkl_engine_remove_toplevel_window_state(engine, app_win);
Packit Service 93d855
}
Packit Service 93d855
Packit Service 93d855
void
Packit Service 93d855
xkl_engine_save_state(XklEngine * engine, Window win, XklState * state)
Packit Service 93d855
{
Packit Service 93d855
	Window app_win;
Packit Service 93d855
Packit Service 93d855
	if (!
Packit Service 93d855
	    (xkl_engine_is_listening_for
Packit Service 93d855
	     (engine, XKLL_MANAGE_WINDOW_STATES)))
Packit Service 93d855
		return;
Packit Service 93d855
Packit Service 93d855
	if (xkl_engine_find_toplevel_window(engine, win, &app_win))
Packit Service 93d855
		xkl_engine_save_toplevel_window_state(engine, app_win,
Packit Service 93d855
						      state);
Packit Service 93d855
}
Packit Service 93d855
Packit Service 93d855
/*
Packit Service 93d855
 *  Prepares the name of window suitable for debugging (32characters long).
Packit Service 93d855
 */
Packit Service 93d855
gchar *
Packit Service 93d855
xkl_get_debug_window_title(XklEngine * engine, Window win)
Packit Service 93d855
{
Packit Service 93d855
	static gchar sname[33];
Packit Service 93d855
	gchar *name;
Packit Service 93d855
	strcpy(sname, "NULL");
Packit Service 93d855
	if (win != (Window) NULL) {
Packit Service 93d855
		name = xkl_engine_get_window_title(engine, win);
Packit Service 93d855
		if (name != NULL) {
Packit Service 93d855
			g_snprintf(sname, sizeof(sname), "%.32s", name);
Packit Service 93d855
			g_free(name);
Packit Service 93d855
		}
Packit Service 93d855
	}
Packit Service 93d855
	return sname;
Packit Service 93d855
}
Packit Service 93d855
Packit Service 93d855
Window
Packit Service 93d855
xkl_engine_get_current_window(XklEngine * engine)
Packit Service 93d855
{
Packit Service 93d855
	return xkl_engine_priv(engine, curr_toplvl_win);
Packit Service 93d855
}
Packit Service 93d855
Packit Service 93d855
/*
Packit Service 93d855
 * Loads subtree. 
Packit Service 93d855
 * All the windows with WM_STATE are added.
Packit Service 93d855
 * All the windows within level 0 are listened for focus and property
Packit Service 93d855
 */
Packit Service 93d855
gboolean
Packit Service 93d855
xkl_engine_load_subtree(XklEngine * engine, Window window, gint level,
Packit Service 93d855
			XklState * init_state)
Packit Service 93d855
{
Packit Service 93d855
	Window rwin = (Window) NULL,
Packit Service 93d855
	    parent = (Window) NULL, *children = NULL, *child;
Packit Service 93d855
	guint num = 0;
Packit Service 93d855
	gboolean retval = True;
Packit Service 93d855
Packit Service 93d855
	xkl_engine_priv(engine, last_error_code) =
Packit Service 93d855
	    xkl_engine_query_tree(engine, window, &rwin, &parent,
Packit Service 93d855
				  &children, &num);
Packit Service 93d855
Packit Service 93d855
	if (xkl_engine_priv(engine, last_error_code) != Success) {
Packit Service 93d855
		return FALSE;
Packit Service 93d855
	}
Packit Service 93d855
Packit Service 93d855
	child = children;
Packit Service 93d855
	while (num) {
Packit Service 93d855
		if (xkl_engine_if_window_has_wm_state(engine, *child)) {
Packit Service 93d855
			xkl_debug(160,
Packit Service 93d855
				  "Window " WINID_FORMAT
Packit Service 93d855
				  " '%s' has WM_STATE so we'll add it\n",
Packit Service 93d855
				  *child,
Packit Service 93d855
				  xkl_get_debug_window_title(engine,
Packit Service 93d855
							     *child));
Packit Service 93d855
			xkl_engine_add_toplevel_window(engine, *child,
Packit Service 93d855
						       window, TRUE,
Packit Service 93d855
						       init_state);
Packit Service 93d855
		} else {
Packit Service 93d855
			xkl_debug(200,
Packit Service 93d855
				  "Window " WINID_FORMAT
Packit Service 93d855
				  " '%s' does not have have WM_STATE so we'll not add it\n",
Packit Service 93d855
				  *child,
Packit Service 93d855
				  xkl_get_debug_window_title(engine,
Packit Service 93d855
							     *child));
Packit Service 93d855
Packit Service 93d855
			if (level == 0) {
Packit Service 93d855
				xkl_debug(200,
Packit Service 93d855
					  "But we are at level 0 so we'll spy on it\n");
Packit Service 93d855
				xkl_engine_select_input_merging(engine,
Packit Service 93d855
								*child,
Packit Service 93d855
								FocusChangeMask
Packit Service 93d855
								|
Packit Service 93d855
								PropertyChangeMask);
Packit Service 93d855
			} else
Packit Service 93d855
				xkl_debug(200,
Packit Service 93d855
					  "And we are at level %d so we'll not spy on it\n",
Packit Service 93d855
					  level);
Packit Service 93d855
Packit Service 93d855
			retval =
Packit Service 93d855
			    xkl_engine_load_subtree(engine, *child,
Packit Service 93d855
						    level + 1, init_state);
Packit Service 93d855
		}
Packit Service 93d855
Packit Service 93d855
		child++;
Packit Service 93d855
		num--;
Packit Service 93d855
	}
Packit Service 93d855
Packit Service 93d855
	if (children != NULL)
Packit Service 93d855
		XFree(children);
Packit Service 93d855
Packit Service 93d855
	return retval;
Packit Service 93d855
}
Packit Service 93d855
Packit Service 93d855
/*
Packit Service 93d855
 * Checks whether given window has WM_STATE property (i.e. "App window").
Packit Service 93d855
 */
Packit Service 93d855
gboolean
Packit Service 93d855
xkl_engine_if_window_has_wm_state(XklEngine * engine, Window win)
Packit Service 93d855
{				/* ICCCM 4.1.3.1 */
Packit Service 93d855
	Atom type = None;
Packit Service 93d855
	int format;
Packit Service 93d855
	unsigned long nitems;
Packit Service 93d855
	unsigned long after;
Packit Service 93d855
	unsigned char *data = NULL;	/* Helps in the case of BadWindow error */
Packit Service 93d855
Packit Service 93d855
	XGetWindowProperty(xkl_engine_get_display(engine), win,
Packit Service 93d855
			   xkl_engine_priv(engine, atoms)[WM_STATE], 0, 0,
Packit Service 93d855
			   False, xkl_engine_priv(engine, atoms)[WM_STATE],
Packit Service 93d855
			   &type, &format, &nitems, &after, &data);
Packit Service 93d855
	if (data != NULL)
Packit Service 93d855
		XFree(data);	/* To avoid an one-byte memory leak because after successfull return
Packit Service 93d855
				 * data array always contains at least one nul byte (NULL-equivalent) */
Packit Service 93d855
	return type != None;
Packit Service 93d855
}
Packit Service 93d855
Packit Service 93d855
/*
Packit Service 93d855
 * Finds out the official parent window (accortind to XQueryTree)
Packit Service 93d855
 */
Packit Service 93d855
Window
Packit Service 93d855
xkl_engine_get_registered_parent(XklEngine * engine, Window win)
Packit Service 93d855
{
Packit Service 93d855
	Window parent = (Window) NULL, rw = (Window) NULL, *children =
Packit Service 93d855
	    NULL;
Packit Service 93d855
	guint nchildren = 0;
Packit Service 93d855
Packit Service 93d855
	xkl_engine_priv(engine, last_error_code) =
Packit Service 93d855
	    xkl_engine_query_tree(engine, win, &rw, &parent, &children,
Packit Service 93d855
				  &nchildren);
Packit Service 93d855
Packit Service 93d855
	if (children != NULL)
Packit Service 93d855
		XFree(children);
Packit Service 93d855
Packit Service 93d855
	return xkl_engine_priv(engine, last_error_code) ==
Packit Service 93d855
	    Success ? parent : (Window) NULL;
Packit Service 93d855
}
Packit Service 93d855
Packit Service 93d855
/*
Packit Service 93d855
 * Make sure about the result. Origial XQueryTree is pretty stupid beast:)
Packit Service 93d855
 */
Packit Service 93d855
Status
Packit Service 93d855
xkl_engine_query_tree(XklEngine * engine, Window w,
Packit Service 93d855
		      Window * root_out,
Packit Service 93d855
		      Window * parent_out,
Packit Service 93d855
		      Window ** children_out, guint * nchildren_out)
Packit Service 93d855
{
Packit Service 93d855
	gboolean result;
Packit Service 93d855
	unsigned int nc;
Packit Service 93d855
Packit Service 93d855
	result = (gboolean) XQueryTree(xkl_engine_get_display(engine),
Packit Service 93d855
				       w,
Packit Service 93d855
				       root_out,
Packit Service 93d855
				       parent_out, children_out, &nc);
Packit Service 93d855
	*nchildren_out = nc;
Packit Service 93d855
Packit Service 93d855
	if (!result) {
Packit Service 93d855
		xkl_debug(160,
Packit Service 93d855
			  "Could not get tree info for window "
Packit Service 93d855
			  WINID_FORMAT ": %d\n", w, result);
Packit Service 93d855
		xkl_last_error_message = "Could not get the tree info";
Packit Service 93d855
	}
Packit Service 93d855
Packit Service 93d855
	return result ? Success : FirstExtensionError;
Packit Service 93d855
}
Packit Service 93d855
Packit Service 93d855
const gchar *
Packit Service 93d855
xkl_event_get_name(gint type)
Packit Service 93d855
{
Packit Service 93d855
	/* Not really good to use the fact of consecutivity
Packit Service 93d855
	   but X protocol is already standartized so... */
Packit Service 93d855
	static const gchar *evt_names[] = {
Packit Service 93d855
		"KeyPress",
Packit Service 93d855
		"KeyRelease",
Packit Service 93d855
		"ButtonPress",
Packit Service 93d855
		"ButtonRelease",
Packit Service 93d855
		"MotionNotify",
Packit Service 93d855
		"EnterNotify",
Packit Service 93d855
		"LeaveNotify",
Packit Service 93d855
		"FocusIn",
Packit Service 93d855
		"FocusOut",
Packit Service 93d855
		"KeymapNotify",
Packit Service 93d855
		"Expose",
Packit Service 93d855
		"GraphicsExpose",
Packit Service 93d855
		"NoExpose",
Packit Service 93d855
		"VisibilityNotify",
Packit Service 93d855
		"CreateNotify",
Packit Service 93d855
		"DestroyNotify",
Packit Service 93d855
		"UnmapNotify",
Packit Service 93d855
		"MapNotify",
Packit Service 93d855
		"MapRequest",
Packit Service 93d855
		"ReparentNotify",
Packit Service 93d855
		"ConfigureNotify",
Packit Service 93d855
		"ConfigureRequest",
Packit Service 93d855
		"GravityNotify",
Packit Service 93d855
		"ResizeRequest",
Packit Service 93d855
		"CirculateNotify",
Packit Service 93d855
		"CirculateRequest",
Packit Service 93d855
		"PropertyNotify",
Packit Service 93d855
		"SelectionClear",
Packit Service 93d855
		"SelectionRequest",
Packit Service 93d855
		"SelectionNotify",
Packit Service 93d855
		"ColormapNotify", "ClientMessage", "MappingNotify",
Packit Service 93d855
		"LASTEvent"
Packit Service 93d855
	};
Packit Service 93d855
	type -= KeyPress;
Packit Service 93d855
	if (type < 0 || type >= (sizeof(evt_names) / sizeof(evt_names[0])))
Packit Service 93d855
		return "UNKNOWN";
Packit Service 93d855
	return evt_names[type];
Packit Service 93d855
}
Packit Service 93d855
Packit Service 93d855
void
Packit Service 93d855
xkl_engine_update_current_state(XklEngine * engine, int group,
Packit Service 93d855
				unsigned indicators, const char reason[])
Packit Service 93d855
{
Packit Service 93d855
	xkl_debug(150,
Packit Service 93d855
		  "Updating the current state with [g:%d/i:%u], reason: %s\n",
Packit Service 93d855
		  group, indicators, reason);
Packit Service 93d855
	xkl_engine_priv(engine, curr_state).group = group;
Packit Service 93d855
	xkl_engine_priv(engine, curr_state).indicators = indicators;
Packit Service 93d855
}