summaryrefslogtreecommitdiff
path: root/gtk/gtkxembed.c
diff options
context:
space:
mode:
authorOwen Taylor <otaylor@redhat.com>2003-08-25 21:46:57 +0000
committerOwen Taylor <otaylor@src.gnome.org>2003-08-25 21:46:57 +0000
commiteb41026147d0966a366420bb93f7e0fcefb73536 (patch)
tree18b29a08a3e5fe61d3e5e3f0c767ee2aecc79839 /gtk/gtkxembed.c
parent9eb2d7c261dbbfaa3f7248efb88970eb02aa210a (diff)
downloadgtk+-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.c210
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);
+}
+