diff options
author | Owen Taylor <otaylor@redhat.com> | 2003-08-25 21:46:57 +0000 |
---|---|---|
committer | Owen Taylor <otaylor@src.gnome.org> | 2003-08-25 21:46:57 +0000 |
commit | eb41026147d0966a366420bb93f7e0fcefb73536 (patch) | |
tree | 18b29a08a3e5fe61d3e5e3f0c767ee2aecc79839 /gtk/gtkxembed.c | |
parent | 9eb2d7c261dbbfaa3f7248efb88970eb02aa210a (diff) | |
download | gtk+-eb41026147d0966a366420bb93f7e0fcefb73536.tar.gz |
Send the focus on to the parent when there was no focus widget before and
Wed Aug 20 21:26:49 2003 Owen Taylor <otaylor@redhat.com>
* gtk/gtkplug.c (gtk_plug_focus): Send the focus on
to the parent when there was no focus widget before
and no focus widget after - that is, when there are
no focusable widgets. (#108678, help tracking it
down from Padraig O'Briain, Federico Mena Quintero, )
* gtk/gtkxembed.[ch]: Move various shared utilities
for the XEMBED protocol eused by GtkPlug and GtkSocket
here.
* gtk/gtkxembed.[ch] gtkplug.c gtksocket.c: Implement
a flag bit that is sent with focus mesages to indicate
that the focus has wrapped around on the toplevel;
use this bit to catch infinite loops when there is no
focusable widget at ll in the entire toplevel.
* tests/testsocket.c (child_read_watch): Remove an
extraneous unref.
* gtk/gtkplug.c gtk/gtksocket.c gtk/gtkxembed.h:
Up XEMBED protocol version to 1, add logic for
sending the right version in XEMBED_EMBEDDED_NOTIFY.
* gtk/gtksocket.c (gtk_socket_add_window): Send
the embedder window in the XEMBED_EMBEDDED_NOTIFY
as the spec requires.
Diffstat (limited to 'gtk/gtkxembed.c')
-rw-r--r-- | gtk/gtkxembed.c | 210 |
1 files changed, 210 insertions, 0 deletions
diff --git a/gtk/gtkxembed.c b/gtk/gtkxembed.c new file mode 100644 index 0000000000..bc1f5dfa2b --- /dev/null +++ b/gtk/gtkxembed.c @@ -0,0 +1,210 @@ +/* GTK - The GIMP Toolkit + * gtkxembed.c: Utilities for the XEMBED protocol + * Copyright (C) 2001, 2003, Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "gtkmain.h" +#include "gtkprivate.h" +#include "gtkxembed.h" + +typedef struct _GtkXEmbedMessage GtkXEmbedMessage; + +struct _GtkXEmbedMessage +{ + glong message; + glong detail; + glong data1; + glong data2; + guint32 time; +}; + +static GSList *current_messages; + + +/** + * _gtk_xembed_push_message: + * @xevent: a XEvent + * + * Adds a client message to the stack of current XEMBED events. + **/ +void +_gtk_xembed_push_message (XEvent *xevent) +{ + GtkXEmbedMessage *message = g_new (GtkXEmbedMessage, 1); + + message->time = xevent->xclient.data.l[0]; + message->message = xevent->xclient.data.l[1]; + message->detail = xevent->xclient.data.l[2]; + message->data1 = xevent->xclient.data.l[3]; + message->data2 = xevent->xclient.data.l[4]; + + current_messages = g_slist_prepend (current_messages, message); +} + +/** + * _gtk_xembed_pop_message: + * + * Removes an event added with _gtk_xembed_push_message() + **/ +void +_gtk_xembed_pop_message (void) +{ + GtkXEmbedMessage *message = current_messages->data; + current_messages = g_slist_delete_link (current_messages, current_messages); + + g_free (message); +} + +/** + * _gtk_xembed_set_focus_wrapped: + * + * Sets a flag indicating that the current focus sequence wrapped + * around to the beginning of the ultimate toplevel. + **/ +void +_gtk_xembed_set_focus_wrapped (void) +{ + GtkXEmbedMessage *message; + + g_return_if_fail (current_messages != NULL); + message = current_messages->data; + g_return_if_fail (message->message == XEMBED_FOCUS_PREV || message->message == XEMBED_FOCUS_NEXT); + + message->data1 |= XEMBED_FOCUS_WRAPAROUND; +} + +/** + * _gtk_xembed_get_focus_wrapped: + * + * Gets whether the current focus sequence has wrapped around + * to the beginning of the ultimate toplevel. + * + * Return value: %TRUE if the focus sequence has wrapped around. + **/ +gboolean +_gtk_xembed_get_focus_wrapped (void) +{ + GtkXEmbedMessage *message; + + g_return_val_if_fail (current_messages != NULL, FALSE); + message = current_messages->data; + + return (message->data1 & XEMBED_FOCUS_WRAPAROUND) != 0; +} + +static guint32 +gtk_xembed_get_time (void) +{ + if (current_messages) + { + GtkXEmbedMessage *message = current_messages->data; + return message->time; + } + else + return gtk_get_current_event_time (); +} + +/** + * _gtk_xembed_send_message: + * @recipient: window to which to send the window, or %NULL + * in which case nothing wil be sent + * @message: type of message + * @detail: detail field of message + * @data1: data1 field of message + * @data2: data2 field of message + * + * Sends a generic XEMBED message to a particular window. + **/ +void +_gtk_xembed_send_message (GdkWindow *recipient, + XEmbedMessageType message, + glong detail, + glong data1, + glong data2) +{ + GdkDisplay *display; + XEvent xevent; + + if (!recipient) + return; + + g_return_if_fail (GDK_IS_WINDOW (recipient)); + + display = gdk_drawable_get_display (recipient); + GTK_NOTE (PLUGSOCKET, + g_message ("Sending XEMBED message of type %d", message)); + + xevent.xclient.window = GDK_WINDOW_XWINDOW (recipient); + xevent.xclient.type = ClientMessage; + xevent.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "_XEMBED"); + xevent.xclient.format = 32; + xevent.xclient.data.l[0] = gtk_xembed_get_time (); + xevent.xclient.data.l[1] = message; + xevent.xclient.data.l[2] = detail; + xevent.xclient.data.l[3] = data1; + xevent.xclient.data.l[4] = data2; + + gdk_error_trap_push (); + XSendEvent (GDK_WINDOW_XDISPLAY(recipient), + GDK_WINDOW_XWINDOW (recipient), + False, NoEventMask, &xevent); + gdk_display_sync (display); + gdk_error_trap_pop (); +} + +/** + * _gtk_xembed_send_focus_message: + * @recipient: window to which to send the window, or %NULL + * in which case nothing wil be sent + * @message: type of message + * @detail: detail field of message + * + * Sends a XEMBED message for moving the focus along the focus + * chain to a window. The flags field that these messages share + * will be correctly filled in. + **/ +void +_gtk_xembed_send_focus_message (GdkWindow *recipient, + XEmbedMessageType message, + glong detail) +{ + gulong flags = 0; + + g_return_if_fail (GDK_IS_WINDOW (recipient)); + g_return_if_fail (message == XEMBED_FOCUS_IN || + message == XEMBED_FOCUS_NEXT || + message == XEMBED_FOCUS_PREV); + + if (current_messages) + { + GtkXEmbedMessage *message = current_messages->data; + switch (message->message) + { + case XEMBED_FOCUS_IN: + case XEMBED_FOCUS_NEXT: + case XEMBED_FOCUS_PREV: + flags = message->data1 & XEMBED_FOCUS_WRAPAROUND; + break; + default: + break; + } + } + + _gtk_xembed_send_message (recipient, message, detail, flags, 0); +} + |