[Date Prev][Date Next] [Thread Prev][Thread Next]
[Thread Index]
[Date Index]
[Author Index]
XEMBED: Preventing focus loops
- From: Owen Taylor <otaylor redhat com>
- To: xdg-list freedesktop org
- Subject: XEMBED: Preventing focus loops
- Date: Thu, 21 Aug 2003 09:07:32 -0400
Currently, it's possible to get into loops with focus messages and
XEMBED. The problem occurs when you have a client that doesn't have
any internal focus locations, embedded into a toplevel without
any focus sites.
If we try to focus the first widget in the toplevel (say, when
the toplevel is mapped), we get the following sequence:
- Embedder sends XEMBED_FOCUS_IN/XEMBED_FOCUS_FIRST to the client
- Client finds no focus sites, sends XEMBED_FOCUS_NEXT to
the embedder
- Embedder takes this as the user hitting Tab again, wraps
around to the beginning, and sends another XEMBED_FOCUS_IN
If you have nested embedding, then this can occur over two
levels.
My proposed solution to this is to define the currently unused data1
of the XEMBED_FOCUS_IN, XEMBED_FOCUS_PREV and XEMBED_FOCUS next
messages as a flags field, with currently one flag defined:
#define XEMBED_FOCUS_WRAPAROUND (1 << 0)
When sending one of these messages, the flag is set as follows:
- If the message is not generated as the result as one of
these three XEMBED messages, set the bit to zero
- When generating an XEMBED_FOCUS_IN in response to a
XEMBED_FOCUS_PREV or XEMBED_FOCUS_NEXT message and the
focus moved from the bottom of the window to the top
for a XEMBED_FOCUS_NEXT message or from the top of the
window to the bottom for a XEMBED_FOCUS_PREV message:
- If the bit was not set in the generating message, set
the bit in the new message
- If the bit was set in the generating message, a loop
has be detected. DO NOT SEND THE NEW MESSAGE.
- Otherwise, set the bit to the value found in the
generating message.
All other bits in the field are unused and must be set to zero.
Notes about the proposal:
* The only difficult thing about implementing this proposal
is detecting when XEMBED_FOCUS_NEXT causes a wrap-around
at the toplevel. It required some hackiness to implement
in GTK+. I think most toolkits will be similar - a bit
hacky to do but possible.
* The two other approach that I considered were:
* assign a unique ID to the focus sequence so that an
individual embedder could check if it was repeating
a focus sequence.
Assigning a sufficiently unique ID is hard and requires
using all the remaining free space in the messages
instead of just one bit.You have to keep a history since
it is possible to have multiple interleaved infinite
focus loops.
* Some sort of response message to XEMBED_FOCUS_IN,
to allow tracking focus sequences without needing
a globally unique ID for the sequence.
This has the same problem with multiple interleaved focus
sequences as the prior solution and would also require
a lot of complicated bookkeeping to implement.
* I didn't up the protocol version because it is a highly
compatible addition - there is nothing you would do
differently if you knew that the other side didn't
understand XEMBED_FOCUS_WRAPAROUND.
Thanks for any feedback; if I don't hear anything in the next
few days I'll go ahead and make the changes to the spec.
Regards,
Owen
Index: xembed-spec.xml
===================================================================
RCS file: /home/freedesktop/xembed/spec/xembed-spec.xml,v
retrieving revision 1.2
diff -u -p -r1.2 xembed-spec.xml
--- xembed-spec.xml 21 Apr 2002 19:12:33 -0000 1.2
+++ xembed-spec.xml 21 Aug 2003 12:54:38 -0000
@@ -5,8 +5,8 @@
<article id="index">
<articleinfo>
<title>XEmbed Protocol Specification</title>
- <releaseinfo>Version 0.5</releaseinfo>
- <date>15 April 2002</date>
+ <releaseinfo>Version 0.6</releaseinfo>
+ <date>20 April 2003</date>
<authorgroup>
<author>
<firstname>Mathias</firstname>
@@ -339,6 +339,57 @@
Backward tabbing is done exactly in the same manner, using the
XEMBED_FOCUS_PREV message.
</para>
+ <para>
+ If there are no focusable widgets at all in a toplevel window,
+ then is possible for an infinite loop of focusing to be
+ generated. To prevent this, the XEMBED_FOCUS_WRAPAROUND flag
+ can be used in the flags field XEMBED_FOCUS_IN, XEMBED_FOCUS_NEXT,
+ and XEMBED_FOCUS_PREV. it is set as follows:
+ </para>
+ <itemizedlist id="focus-wraparound">
+ <listitem>
+ <para>
+ If the message is not generated as the result as one of
+ these three focus chain messages, set the bit to zero.
+ (As examples of such generation, a XEMBED_FOCUS_NEXT message
+ from a client to the embedder might cause XEMBED_FOCUS_IN
+ to be sent to another client in the same toplevel, or a
+ XEMBED_FOCUS_IN event sent to a client might cause another
+ XEMBED_FOCUS_IN event to be sent to a client nested in
+ another level of embedding.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ When generating an XEMBED_FOCUS_IN in response to a
+ XEMBED_FOCUS_PREV or XEMBED_FOCUS_NEXT message and the
+ focus moved from the bottom of the window to the top
+ for a XEMBED_FOCUS_NEXT message or from the top of the
+ window to the bottom for a XEMBED_FOCUS_PREV message;
+ then:
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ If the bit was not set in the generating message, set
+ the bit in the new message
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ If the bit was set in the generating message, a loop
+ has been detected. <emphasis>Do not send the new message.</emphasis>
+ </para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+ <listitem>
+ <para>
+ Otherwise, set the bit to the value found in the
+ generating message.
+ </para>
+ </listitem>
+ </itemizedlist>
</sect2>
<sect2>
<title>Keyboard short cuts / accelerators</title>
@@ -596,6 +647,18 @@
#define XEMBED_FOCUS_FIRST 1
#define XEMBED_FOCUS_LAST 2<!--
--></programlisting>
+ <para>
+ The XEMBED_FOCUS_IN, XEMBED_FOCUS_NEXT, and XEMBED_FOCUS_PREV
+ messages store flags in the data1 field. The valid flags
+ currently defined are:
+ </para>
+ <programlisting><!--
+-->/* Flags for XEMBED_FOCUS_IN, XEMBED_FOCUS_NEXT, XEMBED_FOCUS_PREV */
+#define XEMBED_FOCUS_WRAPAROUND (1 << 0)<!--
+ --></programlisting>
+ <para>
+ All other bits must be zero.
+ </para>
<sect2>
<title>XEMBED_EMBEDDED_NOTIFY</title>
<para>
@@ -639,13 +702,6 @@
within a toplevel can be moved programmatically when the
toplevel doesn't have input focus.
</para>
- <remark>
- [ GTK+ is currently in violation of the preceding note,
- and sends FOCUS_IN and FOCUS_OUT only when the toplevel
- is active. See
- <ulink
- url="http://bugzilla.gnome.org/show_bug.cgi?id=67943">GNOME bug #67943</ulink> ]
- </remark>
<para>
Widgets within the client should typically be displayed with
the focus only when the client both has focus and is active.
@@ -705,6 +761,23 @@
</listitem>
</varlistentry>
</variablelist>
+ <para>
+ The flags field can contain the
+ <link linkend="focus-wraparound">XEMBED_FOCUS_WRAPAROUND</link> bit.
+ </para>
+ <table>
+ <title>XEMBED_FOCUS_IN</title>
+ <tgroup cols="2">
+ <tbody>
+ <row>
+ <entry>detail</entry><entry>enumeration indicating</entry>
+ </row>
+ <row>
+ <entry>data1</entry><entry>flags field.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
</sect2>
<sect2>
<title>XEMBED_FOCUS_OUT</title>
@@ -719,8 +792,20 @@
its logical tab chain after the user tabbed forward. If the
embedder has siblings that accept tab focus, it will do a virtual
tab forward. As a result, it will loose focus itself and
- consequently send an XEMBED_FOCUS_OUT message to the client
+ consequently send an XEMBED_FOCUS_OUT message to the client.
+ The flags field can contain the
+ <link linkend="focus-wraparound">XEMBED_FOCUS_WRAPAROUND</link> bit.
</para>
+ <table>
+ <title>XEMBED_FOCUS_NEXT</title>
+ <tgroup cols="2">
+ <tbody>
+ <row>
+ <entry>data1</entry><entry>flags field.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
</sect2>
<sect2>
<title>XEMBED_FOCUS_PREV</title>
@@ -730,8 +815,19 @@
backward. If the embedder has siblings that accept tab focus, it
will do a virtual tab backward. As a result, it will loose focus
itself and consequently send an XEMBED_FOCUS_OUT message to the
- client
+ client. The flags field can contain the
+ <link linkend="focus-wraparound">XEMBED_FOCUS_WRAPAROUND</link> bit.
</para>
+ <table>
+ <title>XEMBED_FOCUS_PREV</title>
+ <tgroup cols="2">
+ <tbody>
+ <row>
+ <entry>data1</entry><entry>flags field.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
</sect2>
<sect2>
<title>XEMBED_REGISTER_ACCELERATOR / XEMBED_UNREGISTER_ACCELERATOR</title>
@@ -1128,59 +1224,6 @@ void send_xembed_message(
</para>
</sect2>
<sect2>
- <title>Infinite loops in focusing</title>
- <para>
- There is the potential for infinite loops of focusing -
- Consider the case:
- </para>
- <programlisting><!--
---> Toplevel Window
- Embedder
- Client<!--
- --></programlisting>
- <para>
- Where there are no focusable sites in the client or in the
- toplevel window. Then if <keysym>Tab</keysym> is pressed, the embedder
- will send: FOCUS_IN/FOCUS_FIRST to the client, the client will
- send FOCUS_NEXT to the embedder, the toplevel window will
- wrap the focus around and send FOCUS_IN/FOCUS_FIRST to the
- client...
- </para>
- <para>
- The minimum mechanism that seems necessary to prevent this
- loop is a serial number in the FOCUS_IN/FOCUS_FIRST message
- that is repeated in a resulting FOCUS_NEXT message.
- </para>
- <para>
- A possibly better way of handling this could be to make FOCUS_IN have
- an explicit response; that, is, add a XEMBED_FOCUS_IN_RESPONSE
- that the client must send to the embedder after receipt
- of a FOCUS_IN message.
- </para>
-
- <table>
- <title>XEMBED_FOCUS_IN_RESPONSE</title>
- <tgroup cols="2">
- <tbody>
- <row>
- <entry>detail</entry><entry>1 if the client accepted the focus, 0 otherwise</entry>
- </row>
- <row>
- <entry>data1</entry><entry>serial number from XEMBED_FOCUS_IN</entry>
- </row>
- </tbody>
- </tgroup>
- </table>
- <para>
- The main problem with requiring a response here is that caller
- needs to wait for the return event, and to handle cases like
- parent (client 1) => child (client 2) => grandchild (client 1),
- it probably needs to process all sorts of incoming events at
- this point. If the user hits <keysym>Tab</keysym><keysym>Tab</keysym>
- in quick succession things could get very complicated.
- </para>
- </sect2>
- <sect2>
<title>Robustness</title>
<para>
The protocol, as currently constituted, is not robust against
@@ -1398,6 +1441,18 @@ void send_xembed_message(
<listitem>
<para>
Converted to docbook format.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ </formalpara>
+ <formalpara>
+ <title>Version 0.6, 20 August 2003, Owen Taylor</title>
+ <para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ Added the XEMBED_FOCUS_WRAPAROUND flag.
</para>
</listitem>
</itemizedlist>
[Date Prev][Date Next] [Thread Prev][Thread Next]
[Thread Index]
[Date Index]
[Author Index]