Blame libxklavier/xklavier_toplevel.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/Xmd.h>
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
Window xkl_toplevel_window_prev;
Packit Service 93d855
Packit Service 93d855
void
Packit Service 93d855
xkl_engine_set_toplevel_window_transparent(XklEngine * engine,
Packit Service 93d855
					   Window toplevel_win,
Packit Service 93d855
					   gboolean transparent)
Packit Service 93d855
{
Packit Service 93d855
	gboolean oldval;
Packit Service 93d855
Packit Service 93d855
	oldval =
Packit Service 93d855
	    xkl_engine_is_toplevel_window_transparent(engine,
Packit Service 93d855
						      toplevel_win);
Packit Service 93d855
	xkl_debug(150, "toplevel_win " WINID_FORMAT " was %stransparent\n",
Packit Service 93d855
		  toplevel_win, oldval ? "" : "not ");
Packit Service 93d855
	if (transparent && !oldval) {
Packit Service 93d855
		CARD32 prop = 1;
Packit Service 93d855
		XChangeProperty(xkl_engine_get_display(engine),
Packit Service 93d855
				toplevel_win,
Packit Service 93d855
				xkl_engine_priv(engine, atoms)
Packit Service 93d855
				[XKLAVIER_TRANSPARENT], XA_INTEGER, 32,
Packit Service 93d855
				PropModeReplace,
Packit Service 93d855
				(const unsigned char *) &prop, 1);
Packit Service 93d855
	} else if (!transparent && oldval) {
Packit Service 93d855
		XDeleteProperty(xkl_engine_get_display(engine),
Packit Service 93d855
				toplevel_win,
Packit Service 93d855
				xkl_engine_priv(engine, atoms)
Packit Service 93d855
				[XKLAVIER_TRANSPARENT]);
Packit Service 93d855
	}
Packit Service 93d855
}
Packit Service 93d855
Packit Service 93d855
/*
Packit Service 93d855
 * "Adds" app window to the set of managed windows.
Packit Service 93d855
 * Actually, no data structures involved. The only thing we do is save app state
Packit Service 93d855
 * and register ourselves us listeners.
Packit Service 93d855
 * Note: User's callback is called
Packit Service 93d855
 */
Packit Service 93d855
void
Packit Service 93d855
xkl_engine_add_toplevel_window(XklEngine * engine, Window toplevel_win,
Packit Service 93d855
			       Window parent,
Packit Service 93d855
			       gboolean ignore_existing_state,
Packit Service 93d855
			       XklState * init_state)
Packit Service 93d855
{
Packit Service 93d855
	XklState state = *init_state;
Packit Service 93d855
	gint default_group_to_use = -1;
Packit Service 93d855
	GValue params[3];
Packit Service 93d855
	GValue rv;
Packit Service 93d855
	guint signal_id;
Packit Service 93d855
Packit Service 93d855
	if (toplevel_win == xkl_engine_priv(engine, root_window))
Packit Service 93d855
		xkl_debug(150, "??? root app win ???\n");
Packit Service 93d855
Packit Service 93d855
	xkl_debug(150,
Packit Service 93d855
		  "Trying to add window " WINID_FORMAT
Packit Service 93d855
		  "/%s with group %d\n", toplevel_win,
Packit Service 93d855
		  xkl_get_debug_window_title(engine, toplevel_win),
Packit Service 93d855
		  init_state->group);
Packit Service 93d855
Packit Service 93d855
	if (!ignore_existing_state) {
Packit Service 93d855
		gboolean have_state =
Packit Service 93d855
		    xkl_engine_get_toplevel_window_state(engine,
Packit Service 93d855
							 toplevel_win,
Packit Service 93d855
							 &state);
Packit Service 93d855
Packit Service 93d855
		if (have_state) {
Packit Service 93d855
			xkl_debug(150,
Packit Service 93d855
				  "The window " WINID_FORMAT
Packit Service 93d855
				  " does not require to be added, it already has the xklavier state \n",
Packit Service 93d855
				  toplevel_win);
Packit Service 93d855
			return;
Packit Service 93d855
		}
Packit Service 93d855
	}
Packit Service 93d855
	memset(params, 0, sizeof(params));
Packit Service 93d855
	g_value_init(params, XKL_TYPE_ENGINE);
Packit Service 93d855
	g_value_set_object(params, engine);
Packit Service 93d855
	g_value_init(params + 1, G_TYPE_LONG);
Packit Service 93d855
	g_value_set_long(params + 1, toplevel_win);
Packit Service 93d855
	g_value_init(params + 2, G_TYPE_LONG);
Packit Service 93d855
	g_value_set_long(params + 2, parent);
Packit Service 93d855
Packit Service 93d855
	memset(&rv, 0, sizeof(rv));
Packit Service 93d855
	g_value_init(&rv, G_TYPE_INT);
Packit Service 93d855
	g_value_set_int(&rv, default_group_to_use);
Packit Service 93d855
Packit Service 93d855
	signal_id =
Packit Service 93d855
	    g_signal_lookup("new-toplevel-window", xkl_engine_get_type());
Packit Service 93d855
	g_signal_emitv(params, signal_id, 0, &rv;;
Packit Service 93d855
	default_group_to_use = g_value_get_int(&rv;;
Packit Service 93d855
        
Packit Service 93d855
	if (default_group_to_use == -1) {
Packit Service 93d855
		Window transient_for = 0;
Packit Service 93d855
		if (XGetTransientForHint(xkl_engine_get_display(engine), toplevel_win, &transient_for)) {
Packit Service 93d855
			if (transient_for) {
Packit Service 93d855
				XklState trans_state;
Packit Service 93d855
				gboolean have_state =
Packit Service 93d855
					xkl_engine_get_toplevel_window_state(engine,
Packit Service 93d855
							 transient_for,
Packit Service 93d855
							 &trans_state);
Packit Service 93d855
				if (have_state) {
Packit Service 93d855
					default_group_to_use = trans_state.group;
Packit Service 93d855
				}
Packit Service 93d855
			}
Packit Service 93d855
		}
Packit Service 93d855
	}
Packit Service 93d855
Packit Service 93d855
	if (default_group_to_use == -1)
Packit Service 93d855
		default_group_to_use =
Packit Service 93d855
		    xkl_engine_priv(engine, default_group);
Packit Service 93d855
Packit Service 93d855
	if (default_group_to_use != -1)
Packit Service 93d855
		state.group = default_group_to_use;
Packit Service 93d855
Packit Service 93d855
	xkl_engine_save_toplevel_window_state(engine, toplevel_win,
Packit Service 93d855
					      &state);
Packit Service 93d855
	xkl_engine_select_input_merging(engine, toplevel_win,
Packit Service 93d855
					FocusChangeMask |
Packit Service 93d855
					PropertyChangeMask);
Packit Service 93d855
Packit Service 93d855
	if (default_group_to_use != -1) {
Packit Service 93d855
		if (xkl_engine_priv(engine, curr_toplvl_win) ==
Packit Service 93d855
		    toplevel_win) {
Packit Service 93d855
			if ((xkl_engine_priv(engine, secondary_groups_mask)
Packit Service 93d855
			     & (1 << default_group_to_use)) != 0)
Packit Service 93d855
				xkl_engine_allow_one_switch_to_secondary_group
Packit Service 93d855
				    (engine);
Packit Service 93d855
			xkl_engine_lock_group(engine,
Packit Service 93d855
					      default_group_to_use);
Packit Service 93d855
		}
Packit Service 93d855
	}
Packit Service 93d855
Packit Service 93d855
	if (parent == (Window) NULL)
Packit Service 93d855
		parent =
Packit Service 93d855
		    xkl_engine_get_registered_parent(engine, toplevel_win);
Packit Service 93d855
Packit Service 93d855
	xkl_debug(150, "done\n");
Packit Service 93d855
}
Packit Service 93d855
Packit Service 93d855
/*
Packit Service 93d855
 * Checks the window and goes up
Packit Service 93d855
 */
Packit Service 93d855
gboolean
Packit Service 93d855
xkl_engine_find_toplevel_window_bottom_to_top(XklEngine * engine,
Packit Service 93d855
					      Window win,
Packit Service 93d855
					      Window * toplevel_win_out)
Packit Service 93d855
{
Packit Service 93d855
	Window parent = (Window) NULL, rwin = (Window) NULL, *children =
Packit Service 93d855
	    NULL;
Packit Service 93d855
	guint num = 0;
Packit Service 93d855
Packit Service 93d855
	if (win == (Window) NULL
Packit Service 93d855
	    || win == xkl_engine_priv(engine, root_window)) {
Packit Service 93d855
		*toplevel_win_out = win;
Packit Service 93d855
		xkl_last_error_message = "The window is either 0 or root";
Packit Service 93d855
		return FALSE;
Packit Service 93d855
	}
Packit Service 93d855
Packit Service 93d855
	if (xkl_engine_if_window_has_wm_state(engine, win)) {
Packit Service 93d855
		*toplevel_win_out = win;
Packit Service 93d855
		return TRUE;
Packit Service 93d855
	}
Packit Service 93d855
Packit Service 93d855
	xkl_engine_priv(engine, last_error_code) =
Packit Service 93d855
	    xkl_engine_query_tree(engine, win, &rwin, &parent, &children,
Packit Service 93d855
				  &num);
Packit Service 93d855
Packit Service 93d855
	if (xkl_engine_priv(engine, last_error_code) != Success) {
Packit Service 93d855
		*toplevel_win_out = (Window) NULL;
Packit Service 93d855
		return FALSE;
Packit Service 93d855
	}
Packit Service 93d855
Packit Service 93d855
	if (children != NULL)
Packit Service 93d855
		XFree(children);
Packit Service 93d855
Packit Service 93d855
	return xkl_engine_find_toplevel_window_bottom_to_top(engine,
Packit Service 93d855
							     parent,
Packit Service 93d855
							     toplevel_win_out);
Packit Service 93d855
}
Packit Service 93d855
Packit Service 93d855
/*
Packit Service 93d855
 * Recursively finds "App window" (window with WM_STATE) for given window.
Packit Service 93d855
 * First, checks the window itself
Packit Service 93d855
 * Then, for first level of recursion, checks childen,
Packit Service 93d855
 * Then, goes to parent.
Packit Service 93d855
 * NOTE: root window cannot be "App window" under normal circumstances
Packit Service 93d855
 */
Packit Service 93d855
gboolean
Packit Service 93d855
xkl_engine_find_toplevel_window(XklEngine * engine, Window win,
Packit Service 93d855
				Window * toplevel_win_out)
Packit Service 93d855
{
Packit Service 93d855
	Window parent = (Window) NULL,
Packit Service 93d855
	    rwin = (Window) NULL, *children = NULL, *child;
Packit Service 93d855
	guint num = 0;
Packit Service 93d855
	gboolean rv;
Packit Service 93d855
Packit Service 93d855
	if (win == (Window) NULL
Packit Service 93d855
	    || win == PointerRoot
Packit Service 93d855
	    || win == xkl_engine_priv(engine, root_window)) {
Packit Service 93d855
		*toplevel_win_out = (Window) NULL;
Packit Service 93d855
		xkl_last_error_message = "The window is either 0 or root";
Packit Service 93d855
		xkl_debug(150,
Packit Service 93d855
			  "Window " WINID_FORMAT
Packit Service 93d855
			  " is either 0 or root so could not get the app window for it\n",
Packit Service 93d855
			  win);
Packit Service 93d855
		return FALSE;
Packit Service 93d855
	}
Packit Service 93d855
Packit Service 93d855
	if (xkl_engine_if_window_has_wm_state(engine, win)) {
Packit Service 93d855
		*toplevel_win_out = win;
Packit Service 93d855
		return TRUE;
Packit Service 93d855
	}
Packit Service 93d855
Packit Service 93d855
	xkl_engine_priv(engine, last_error_code) =
Packit Service 93d855
	    xkl_engine_query_tree(engine, win, &rwin, &parent, &children,
Packit Service 93d855
				  &num);
Packit Service 93d855
Packit Service 93d855
	if (xkl_engine_priv(engine, last_error_code) != Success) {
Packit Service 93d855
		*toplevel_win_out = (Window) NULL;
Packit Service 93d855
		xkl_debug(150,
Packit Service 93d855
			  "Could not get tree for window " WINID_FORMAT
Packit Service 93d855
			  " so could not get the app window for it\n",
Packit Service 93d855
			  win);
Packit Service 93d855
		return FALSE;
Packit Service 93d855
	}
Packit Service 93d855
Packit Service 93d855
	/*
Packit Service 93d855
	 * Here we first check the children (in case win is just above some "App Window")
Packit Service 93d855
	 * and then go upstairs
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
			*toplevel_win_out = *child;
Packit Service 93d855
			if (children != NULL)
Packit Service 93d855
				XFree(children);
Packit Service 93d855
			return TRUE;
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
	rv = xkl_engine_find_toplevel_window_bottom_to_top(engine, parent,
Packit Service 93d855
							   toplevel_win_out);
Packit Service 93d855
Packit Service 93d855
	if (!rv)
Packit Service 93d855
		xkl_debug(200,
Packit Service 93d855
			  "Could not get the app window for " WINID_FORMAT
Packit Service 93d855
			  "/%s\n", win, xkl_get_debug_window_title(engine,
Packit Service 93d855
								   win));
Packit Service 93d855
Packit Service 93d855
	return rv;
Packit Service 93d855
}
Packit Service 93d855
Packit Service 93d855
/*
Packit Service 93d855
 * Gets the state from the window property
Packit Service 93d855
 */
Packit Service 93d855
gboolean
Packit Service 93d855
xkl_engine_get_toplevel_window_state(XklEngine * engine,
Packit Service 93d855
				     Window toplevel_win,
Packit Service 93d855
				     XklState * state_out)
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
	CARD32 *prop = NULL;
Packit Service 93d855
	gboolean ret = FALSE;
Packit Service 93d855
Packit Service 93d855
	gint grp = -1;
Packit Service 93d855
	guint inds = 0;
Packit Service 93d855
Packit Service 93d855
	if ((XGetWindowProperty
Packit Service 93d855
	     (xkl_engine_get_display(engine), toplevel_win,
Packit Service 93d855
	      xkl_engine_priv(engine, atoms)[XKLAVIER_STATE], 0L,
Packit Service 93d855
	      XKLAVIER_STATE_PROP_LENGTH, False, XA_INTEGER, &type_ret,
Packit Service 93d855
	      &format_ret, &nitems, &rest,
Packit Service 93d855
	      (unsigned char **) (void *) &prop) == Success)
Packit Service 93d855
	    && (type_ret == XA_INTEGER) && (format_ret == 32)) {
Packit Service 93d855
		grp = prop[0];
Packit Service 93d855
		if (grp >= xkl_engine_get_num_groups(engine) || grp < 0)
Packit Service 93d855
			grp = 0;
Packit Service 93d855
Packit Service 93d855
		inds = prop[1];
Packit Service 93d855
Packit Service 93d855
		if (state_out != NULL) {
Packit Service 93d855
			state_out->group = grp;
Packit Service 93d855
			state_out->indicators = inds;
Packit Service 93d855
		}
Packit Service 93d855
		if (prop != NULL)
Packit Service 93d855
			XFree(prop);
Packit Service 93d855
Packit Service 93d855
		ret = TRUE;
Packit Service 93d855
	}
Packit Service 93d855
Packit Service 93d855
	if (ret)
Packit Service 93d855
		xkl_debug(150,
Packit Service 93d855
			  "Appwin " WINID_FORMAT
Packit Service 93d855
			  ", '%s' has the group %d, indicators %X\n",
Packit Service 93d855
			  toplevel_win,
Packit Service 93d855
			  xkl_get_debug_window_title(engine, toplevel_win),
Packit Service 93d855
			  grp, inds);
Packit Service 93d855
	else
Packit Service 93d855
		xkl_debug(150,
Packit Service 93d855
			  "Appwin " WINID_FORMAT
Packit Service 93d855
			  ", '%s' does not have state\n", toplevel_win,
Packit Service 93d855
			  xkl_get_debug_window_title(engine,
Packit Service 93d855
						     toplevel_win));
Packit Service 93d855
Packit Service 93d855
	return ret;
Packit Service 93d855
}
Packit Service 93d855
Packit Service 93d855
/*
Packit Service 93d855
 * Deletes the state from the window properties
Packit Service 93d855
 */
Packit Service 93d855
void
Packit Service 93d855
xkl_engine_remove_toplevel_window_state(XklEngine * engine,
Packit Service 93d855
					Window toplevel_win)
Packit Service 93d855
{
Packit Service 93d855
	XDeleteProperty(xkl_engine_get_display(engine), toplevel_win,
Packit Service 93d855
			xkl_engine_priv(engine, atoms)[XKLAVIER_STATE]);
Packit Service 93d855
}
Packit Service 93d855
Packit Service 93d855
/*
Packit Service 93d855
 * Saves the state into the window properties
Packit Service 93d855
 */
Packit Service 93d855
void
Packit Service 93d855
xkl_engine_save_toplevel_window_state(XklEngine * engine,
Packit Service 93d855
				      Window toplevel_win,
Packit Service 93d855
				      XklState * state)
Packit Service 93d855
{
Packit Service 93d855
	CARD32 prop[XKLAVIER_STATE_PROP_LENGTH];
Packit Service 93d855
Packit Service 93d855
	prop[0] = state->group;
Packit Service 93d855
	prop[1] = state->indicators;
Packit Service 93d855
Packit Service 93d855
	XChangeProperty(xkl_engine_get_display(engine), toplevel_win,
Packit Service 93d855
			xkl_engine_priv(engine, atoms)[XKLAVIER_STATE],
Packit Service 93d855
			XA_INTEGER, 32, PropModeReplace,
Packit Service 93d855
			(const unsigned char *) prop,
Packit Service 93d855
			XKLAVIER_STATE_PROP_LENGTH);
Packit Service 93d855
Packit Service 93d855
	xkl_debug(160,
Packit Service 93d855
		  "Saved the group %d, indicators %X for appwin "
Packit Service 93d855
		  WINID_FORMAT "\n", state->group, state->indicators,
Packit Service 93d855
		  toplevel_win);
Packit Service 93d855
}
Packit Service 93d855
Packit Service 93d855
gboolean
Packit Service 93d855
xkl_engine_is_toplevel_window_transparent(XklEngine * engine,
Packit Service 93d855
					  Window toplevel_win)
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
	CARD32 *prop = NULL;
Packit Service 93d855
	if ((XGetWindowProperty
Packit Service 93d855
	     (xkl_engine_get_display(engine), toplevel_win,
Packit Service 93d855
	      xkl_engine_priv(engine, atoms)[XKLAVIER_TRANSPARENT], 0L, 1,
Packit Service 93d855
	      False, XA_INTEGER, &type_ret, &format_ret, &nitems, &rest,
Packit Service 93d855
	      (unsigned char **) (void *) &prop) == Success)
Packit Service 93d855
	    && (type_ret == XA_INTEGER) && (format_ret == 32)) {
Packit Service 93d855
		if (prop != NULL)
Packit Service 93d855
			XFree(prop);
Packit Service 93d855
		return TRUE;
Packit Service 93d855
	}
Packit Service 93d855
	return FALSE;
Packit Service 93d855
}