gtk2/gtk/gtkxembed.c
Owen Taylor eb41026147 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.
2003-08-25 21:46:57 +00:00

211 lines
5.5 KiB
C

/* 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);
}