[Xlib] Force Raise/Map/Focus a given Window

Andrew Troschinetz ast at arlut.utexas.edu
Mon Aug 11 12:25:30 PDT 2008


Hi,

I'm trying to force raise/present/focus a window in Gnome/Metacity  
2.18 (RHEL5) but it seems like a "don't steal focus" feature is  
preventing me from doing so. The following code works in Gnome/ 
Metacity 2.8 (RHEL4), but note quite in RHEL5.

What I mean is: If the window is minimized (unmapped) then the  
following code will map, raise, and focus the window correctly in  
either RHEL4 or RHEL5. But in RHEL5 only, if the window currently  
doesn't have focus, but is mapped and raised (say another window has  
focus and is ontop of the window I want to present), then the  
following code only results in the taskbar item for the window blinking.

So my question is, is there a problem in my code? Is there a known  
workaround for this, some Xlib function I should be calling here? Or  
does anyone happen to know off the top of their head if this is a new  
feature in RHEL5 that can be easily disabled?

void present_window(Display* display, Window window)
{
	// Get current hidden/unhidden state of window
	XWindowAttributes atts;
	XGetWindowAttributes (display, window, &atts);
	bool hidden = (atts.map_state == IsUnmapped);

	// If hidden: map, raise, and focus the window.
	// The window has to be mapped before we can call XSetInputFocus() on  
it,
	// otherwise we will likely get BadMatch errors.
	if (hidden)
	{
		// Save current even mask
		unsigned long old_mask = atts.your_event_mask;
		unsigned long wanted_mask = StructureNotifyMask;

		// Add wanted mask to current mask
		XSelectInput (display, window, old_mask | wanted_mask);

		// Request to raise and map window
		XMapRaised (display, window);

		// Wait for window to be mapped before going on,
		// but only wait timeout seconds before giving up
		const double timeout = 5;
		XEvent e;
		std::vector<XEvent> events;
		boost::timer time;
		do
		{
			if (XCheckWindowEvent (display, window, wanted_mask, &e))
			{
				events.push_back (e);
			}
		} while (e.type != MapNotify && time.elapsed () < timeout);

		// Determine if we unhid the window or not
		hidden = (e.type != MapNotify);

		// Push back the events we stole
		std::vector<XEvent>::iterator i = events.begin ();
		for (; i != events.end (); ++i)
		{
			XPutBackEvent (display, &(*i));
		}

		// Revert the mask to previous state
		XSelectInput (display, window, old_mask);

		if (!hidden)
		{
			XSetInputFocus (display, window, RevertToParent, CurrentTime);
		}
	}
	else
	{
		XRaiseWindow (display, window);
		XSetInputFocus (display, window, RevertToParent, CurrentTime);
	}
}

--
Andrew Troschinetz
Applied Research Laboratories




More information about the xorg mailing list