gtkxembed.c 6.28 KB
Newer Older
Cody Russell's avatar
Cody Russell committed
1
/* GTK - The GIMP Toolkit
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
 * 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.
 */

21
#include "config.h"
22
#include <string.h>
23 24 25
#include "gtkmain.h"
#include "gtkprivate.h"
#include "gtkxembed.h"
26

27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50

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)
{
51
  GtkXEmbedMessage *message = g_slice_new (GtkXEmbedMessage);
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
  
  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);
72
  g_slice_free (GtkXEmbedMessage, message);
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
}

/**
 * _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:
126
 * @recipient: (allow-none): window to which to send the window, or %NULL
127
 *             in which case nothing will be sent
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
 * @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;
143
  XClientMessageEvent xclient;
144 145 146 147 148 149 150 151

  if (!recipient)
    return;
	  
  g_return_if_fail (GDK_IS_WINDOW (recipient));

  display = gdk_drawable_get_display (recipient);
  GTK_NOTE (PLUGSOCKET,
152
	    g_message ("Sending %s", _gtk_xembed_message_name (message)));
153

154 155 156 157 158 159 160 161 162 163
  memset (&xclient, 0, sizeof (xclient));
  xclient.window = GDK_WINDOW_XWINDOW (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;
164 165 166 167

  gdk_error_trap_push ();
  XSendEvent (GDK_WINDOW_XDISPLAY(recipient),
	      GDK_WINDOW_XWINDOW (recipient),
168
	      False, NoEventMask, (XEvent *)&xclient);
169 170 171 172 173 174
  gdk_display_sync (display);
  gdk_error_trap_pop ();
}

/**
 * _gtk_xembed_send_focus_message:
175
 * @recipient: (allow-none): window to which to send the window, or %NULL
176
 *             in which case nothing will be sent
177 178 179 180 181 182 183 184 185 186 187 188 189
 * @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;
190 191 192

  if (!recipient)
    return;
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216
  
  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);
}

217 218 219
const char *
_gtk_xembed_message_name (XEmbedMessageType message)
{
220
  static char unk[24];
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
  
  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:
241
      snprintf (unk, 24, "UNKNOWN(%d)", message);
242 243 244
      return unk;
    }
}