/* 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, see <http://www.gnu.org/licenses/>. */ #include "config.h" #include <string.h> #include "gtkmain.h" #include "gtkprivate.h" #include "gtkxembed.h" #include "gtkdebug.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_slice_new (GtkXEmbedMessage); 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_slice_free (GtkXEmbedMessage, 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. * * Returns: %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: (allow-none): window to which to send the window, or %NULL * in which case nothing will 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; XClientMessageEvent xclient; if (!recipient) return; g_return_if_fail (GDK_IS_WINDOW (recipient)); display = gdk_window_get_display (recipient); GTK_NOTE (PLUGSOCKET, g_message ("Sending %s", _gtk_xembed_message_name (message))); memset (&xclient, 0, sizeof (xclient)); xclient.window = GDK_WINDOW_XID (recipient); xclient.type = ClientMessage; xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "_XEMBED"); xclient.format = 32; xclient.data.l[0] = gtk_xembed_get_time (); xclient.data.l[1] = message; xclient.data.l[2] = detail; xclient.data.l[3] = data1; xclient.data.l[4] = data2; gdk_x11_display_error_trap_push (display); XSendEvent (GDK_WINDOW_XDISPLAY(recipient), GDK_WINDOW_XID (recipient), False, NoEventMask, (XEvent *)&xclient); gdk_x11_display_error_trap_pop_ignored (display); } /** * _gtk_xembed_send_focus_message: * @recipient: (allow-none): window to which to send the window, or %NULL * in which case nothing will be sent * @message_type: 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_type, glong detail) { gulong flags = 0; if (!recipient) return; g_return_if_fail (GDK_IS_WINDOW (recipient)); g_return_if_fail (message_type == XEMBED_FOCUS_IN || message_type == XEMBED_FOCUS_NEXT || message_type == 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_type, detail, flags, 0); } const char * _gtk_xembed_message_name (XEmbedMessageType message) { static char unk[24]; switch (message) { #define CASE(x) case XEMBED_##x: return "XEMBED_"#x CASE (EMBEDDED_NOTIFY); CASE (WINDOW_ACTIVATE); CASE (WINDOW_DEACTIVATE); CASE (REQUEST_FOCUS); CASE (FOCUS_IN); CASE (FOCUS_OUT); CASE (FOCUS_NEXT); CASE (FOCUS_PREV); CASE (GRAB_KEY); CASE (UNGRAB_KEY); CASE (MODALITY_ON); CASE (MODALITY_OFF); CASE (GTK_GRAB_KEY); CASE (GTK_UNGRAB_KEY); #undef CASE default: snprintf (unk, 24, "UNKNOWN(%d)", message); return unk; } }