0.9.0claws35
authorChristoph Hohmann <reboot@gmx.ch>
Fri, 13 Jun 2003 17:38:30 +0000 (17:38 +0000)
committerChristoph Hohmann <reboot@gmx.ch>
Fri, 13 Jun 2003 17:38:30 +0000 (17:38 +0000)
* configure.ac
* src/plugins/trayicon/Makefile.am
* src/plugins/trayicon/eggtrayicon.[ch]                         ** REMOVE **
* src/plugins/trayicon/trayicon.c
* src/plugins/trayicon/libeggtrayicon/.cvsignore                ** NEW **
* src/plugins/trayicon/libeggtrayicon/Makefile.am               ** NEW **
* src/plugins/trayicon/libeggtrayicon/eggtrayicon.[ch]          ** NEW **
* src/plugins/trayicon/libeggtrayicon/gtk2-funcs.[ch]           ** NEW **
* src/plugins/trayicon/libeggtrayicon/gtkplugxembed.[ch]        ** NEW **
* src/plugins/trayicon/libeggtrayicon/xembed.h                  ** NEW **
        replace my own EggTrayIcon backport with the backport
        used by (l|x)mule and gabber.

13 files changed:
ChangeLog.claws
configure.ac
src/plugins/trayicon/Makefile.am
src/plugins/trayicon/libeggtrayicon/.cvsignore [new file with mode: 0644]
src/plugins/trayicon/libeggtrayicon/Makefile.am [new file with mode: 0644]
src/plugins/trayicon/libeggtrayicon/eggtrayicon.c [moved from src/plugins/trayicon/eggtrayicon.c with 76% similarity]
src/plugins/trayicon/libeggtrayicon/eggtrayicon.h [moved from src/plugins/trayicon/eggtrayicon.h with 79% similarity]
src/plugins/trayicon/libeggtrayicon/gtk2-funcs.c [new file with mode: 0644]
src/plugins/trayicon/libeggtrayicon/gtk2-funcs.h [new file with mode: 0644]
src/plugins/trayicon/libeggtrayicon/gtkplugxembed.c [new file with mode: 0644]
src/plugins/trayicon/libeggtrayicon/gtkplugxembed.h [new file with mode: 0644]
src/plugins/trayicon/libeggtrayicon/xembed.h [new file with mode: 0644]
src/plugins/trayicon/trayicon.c

index 8693d16534048b8bfbc80a006918a26ec4bd4bf6..00bb8362ccf8dba376bd00d6426b14ba51e86604 100644 (file)
@@ -1,3 +1,18 @@
+2003-06-13 [christoph] 0.9.0claws35
+
+       * configure.ac
+       * src/plugins/trayicon/Makefile.am
+       * src/plugins/trayicon/eggtrayicon.[ch]                         ** REMOVE **
+       * src/plugins/trayicon/trayicon.c
+       * src/plugins/trayicon/libeggtrayicon/.cvsignore                ** NEW **
+       * src/plugins/trayicon/libeggtrayicon/Makefile.am               ** NEW **
+       * src/plugins/trayicon/libeggtrayicon/eggtrayicon.[ch]          ** NEW **
+       * src/plugins/trayicon/libeggtrayicon/gtk2-funcs.[ch]           ** NEW **
+       * src/plugins/trayicon/libeggtrayicon/gtkplugxembed.[ch]        ** NEW **
+       * src/plugins/trayicon/libeggtrayicon/xembed.h                  ** NEW **
+               replace my own EggTrayIcon backport with the backport
+               used by (l|x)mule and gabber.
+
 2003-06-13 [alfons]    0.9.0claws34
 
        * AUTHORS
index c417f477ff665a073404a208bbd8f5d9519d22db..9a5b3dc0007c81ecf1ef3f59eec5db2e47a8539e 100644 (file)
@@ -11,7 +11,7 @@ MINOR_VERSION=9
 MICRO_VERSION=0
 INTERFACE_AGE=0
 BINARY_AGE=0
-EXTRA_VERSION=claws34
+EXTRA_VERSION=claws35
 VERSION=$MAJOR_VERSION.$MINOR_VERSION.$MICRO_VERSION$EXTRA_VERSION
 
 dnl set $target
@@ -485,6 +485,7 @@ src/plugins/mathml_viewer/Makefile
 src/plugins/dillo_viewer/Makefile
 src/plugins/image_viewer/Makefile
 src/plugins/trayicon/Makefile
+src/plugins/trayicon/libeggtrayicon/Makefile
 src/plugins/clamav/Makefile
 faq/Makefile
 faq/de/Makefile
index 7d6f276ebbfc2175b256dad63a88415ffe97745e..2c2212d2eeb8d1213390d687d5040c7ceb3ce254 100644 (file)
@@ -1,19 +1,24 @@
+SUBDIRS = libeggtrayicon
+
 plugindir = $(pkglibdir)/plugins
 
 plugin_LTLIBRARIES = trayicon.la
 
 trayicon_la_SOURCES = \
-       trayicon.c \
-       eggtrayicon.c eggtrayicon.h
+       trayicon.c
 
 trayicon_la_LDFLAGS = \
-       -avoid-version -module \
-       $(GTK_LIBS)
+       -avoid-version -module
+
+trayicon_la_LIBADD = \
+       $(GTK_LIBS) \
+       libeggtrayicon/libeggtrayicon.la
 
 INCLUDES = \
        -I../../ \
        -I../../common \
-       -I../../gtk
+       -I../../gtk \
+       -Ilibeggtrayicon
 
 CPPFLAGS = \
        $(GLIB_CFLAGS) \
diff --git a/src/plugins/trayicon/libeggtrayicon/.cvsignore b/src/plugins/trayicon/libeggtrayicon/.cvsignore
new file mode 100644 (file)
index 0000000..6607302
--- /dev/null
@@ -0,0 +1,6 @@
+.libs
+.deps
+Makefile
+Makefile.in
+*.lo
+*.la
diff --git a/src/plugins/trayicon/libeggtrayicon/Makefile.am b/src/plugins/trayicon/libeggtrayicon/Makefile.am
new file mode 100644 (file)
index 0000000..a3d7a1a
--- /dev/null
@@ -0,0 +1,14 @@
+noinst_LTLIBRARIES = libeggtrayicon.la
+
+libeggtrayicon_la_SOURCES = \
+       eggtrayicon.c eggtrayicon.h \
+       gtk2-funcs.c gtk2-funcs.h \
+       gtkplugxembed.c gtkplugxembed.h \
+       xembed.h
+
+CPPFLAGS = \
+       $(GTK_CFLAGS)
+
+libeggtrayicon_la_LIBADD = \
+       $(GTK_LIBS)
+
similarity index 76%
rename from src/plugins/trayicon/eggtrayicon.c
rename to src/plugins/trayicon/libeggtrayicon/eggtrayicon.c
index 6a0d8c264f37663b31d581f3503b64678b8b4fc9..4217fd8be8a59f09194daf60023ec64161358fcd 100644 (file)
 #define SYSTEM_TRAY_BEGIN_MESSAGE   1
 #define SYSTEM_TRAY_CANCEL_MESSAGE  2
          
-static GtkPlugClass *parent_class = NULL;
+static GtkPlugXEmbedClass *parent_class = NULL;
 
 static void egg_tray_icon_init (EggTrayIcon *icon);
 static void egg_tray_icon_class_init (EggTrayIconClass *klass);
 
-static void egg_tray_icon_unrealize (GtkWidget *widget);
-
 static void egg_tray_icon_update_manager_window (EggTrayIcon *icon);
 
-Window gtk_plug_get_id(GtkPlug *widget)
-{
-    return (guint32) GDK_WINDOW_XWINDOW(GTK_WIDGET(widget)->window);
-}
-
 GtkType
 egg_tray_icon_get_type (void)
 {
@@ -47,19 +40,17 @@ egg_tray_icon_get_type (void)
 
   if (our_type == 0)
     {
-      GtkTypeInfo our_info =
+      static const GtkTypeInfo our_info =
       {
        "EggTrayIcon",
        sizeof (EggTrayIcon),
        sizeof (EggTrayIconClass),
        (GtkClassInitFunc) egg_tray_icon_class_init,
        (GtkObjectInitFunc) egg_tray_icon_init,
-       NULL, /* class_finalize */
-       NULL, /* class_data */
-       0,    /* n_preallocs */
+       NULL, NULL, NULL
       };
 
-      our_type = gtk_type_unique (gtk_plug_get_type(), &our_info);
+      our_type = gtk_type_unique (GTK_TYPE_PLUG_XEMBED, &our_info);
     }
 
   return our_type;
@@ -76,11 +67,8 @@ egg_tray_icon_init (EggTrayIcon *icon)
 static void
 egg_tray_icon_class_init (EggTrayIconClass *klass)
 {
-  GtkWidgetClass *widget_class = (GtkWidgetClass *)klass;
-
-  parent_class = gtk_type_class(gtk_plug_get_type());
-
-  widget_class->unrealize = egg_tray_icon_unrealize;
+       //parent_class = g_type_class_peek_parent (klass);
+       parent_class = gtk_type_class(gtk_plug_xembed_get_type());
 }
 
 static GdkFilterReturn
@@ -106,38 +94,6 @@ egg_tray_icon_manager_filter (GdkXEvent *xevent, GdkEvent *event, gpointer user_
   return GDK_FILTER_CONTINUE;
 }
 
-static void
-egg_tray_icon_unrealize (GtkWidget *widget)
-{
-  EggTrayIcon *icon = EGG_TRAY_ICON (widget);
-  GdkWindow *root_window;
-
-  if (icon->manager_window != None)
-    {
-      GdkWindow *gdkwin;
-
-#if HAVE_GTK_MULTIHEAD
-      gdkwin = gdk_window_lookup_for_display (gtk_widget_get_display (widget),
-                                              icon->manager_window);
-#else
-      gdkwin = gdk_window_lookup (icon->manager_window);
-#endif
-
-      gdk_window_remove_filter (gdkwin, egg_tray_icon_manager_filter, icon);
-    }
-
-#if HAVE_GTK_MULTIHEAD
-  root_window = gdk_screen_get_root_window (gtk_widget_get_screen (widget));
-#else
-  root_window = gdk_window_lookup (GDK_ROOT_WINDOW());
-#endif
-
-  gdk_window_remove_filter (root_window, egg_tray_icon_manager_filter, icon);
-
-  if (GTK_WIDGET_CLASS (parent_class)->unrealize)
-    (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
-}
-
 static void
 egg_tray_icon_send_manager_message (EggTrayIcon *icon,
                                    long         message,
@@ -148,12 +104,17 @@ egg_tray_icon_send_manager_message (EggTrayIcon *icon,
 {
   XClientMessageEvent ev;
   Display *display;
+  
+#ifdef DEBUG
+  g_print("Sending message %lx to %ld. data=(%ld, %ld, %ld)\n", message, window,
+         data1, data2, data3);
+#endif
 
   ev.type = ClientMessage;
   ev.window = window;
   ev.message_type = icon->system_tray_opcode_atom;
   ev.format = 32;
-  ev.data.l[0] = gdk_time_get(); /* gdk_x11_get_server_time (GTK_WIDGET (icon)->window); */
+  ev.data.l[0] = GDK_CURRENT_TIME; //gdk_x11_get_server_time (GTK_WIDGET (icon)->window);
   ev.data.l[1] = message;
   ev.data.l[2] = data1;
   ev.data.l[3] = data2;
@@ -178,7 +139,7 @@ egg_tray_icon_send_dock_request (EggTrayIcon *icon)
   egg_tray_icon_send_manager_message (icon,
                                      SYSTEM_TRAY_REQUEST_DOCK,
                                      icon->manager_window,
-                                     gtk_plug_get_id (GTK_PLUG (icon)),
+                                     gtk_plug_xembed_get_id (GTK_PLUG_XEMBED (icon)),
                                      0, 0);
 }
 
@@ -198,7 +159,7 @@ egg_tray_icon_update_manager_window (EggTrayIcon *icon)
       GdkWindow *gdkwin;
 
 #if HAVE_GTK_MULTIHEAD
-      gdkwin = gdk_window_lookup_for_display (gtk_widget_get_display (GTK_WIDGET (icon)),
+      gdkwin = gdk_window_lookup_for_display (display,
                                              icon->manager_window);
 #else
       gdkwin = gdk_window_lookup (icon->manager_window);
@@ -246,21 +207,16 @@ egg_tray_icon_new_for_xscreen (Screen *xscreen, const char *name)
 
   g_return_val_if_fail (xscreen != NULL, NULL);
   
-  icon = gtk_type_new (EGG_TYPE_TRAY_ICON);
+  icon = (EggTrayIcon*)gtk_object_new (EGG_TYPE_TRAY_ICON, NULL);
   gtk_window_set_title (GTK_WINDOW (icon), name);
 
 #if HAVE_GTK_MULTIHEAD
-  /* FIXME: this code does not compile, screen is undefined. Now try
-   * getting the GdkScreen from xscreen (:. Dunno how to solve this
-   * (there is prolly some easy way I cant think of right now)
-   */
-  gtk_plug_construct_for_display (GTK_PLUG (icon),
+  gtk_plug_construct_for_display (GTK_PLUG_XEMBED (icon),
                                  gdk_screen_get_display (screen), 0);
 #else
-  gtk_plug_construct (GTK_PLUG (icon), 0);
+  gtk_plug_xembed_construct (GTK_PLUG_XEMBED (icon), 0);
 #endif
   
-  gtk_widget_set_events(GTK_WIDGET(icon), GDK_ALL_EVENTS_MASK);
   gtk_widget_realize (GTK_WIDGET (icon));
 
   /* Now see if there's a manager window around */
@@ -280,9 +236,9 @@ egg_tray_icon_new_for_xscreen (Screen *xscreen, const char *name)
   egg_tray_icon_update_manager_window (icon);
 
 #if HAVE_GTK_MULTIHEAD
-  root_window = gdk_screen_get_root_window (gtk_widget_get_screen (screen));
+  root_window = gdk_screen_get_root_window (screen);
 #else
-  root_window = gdk_window_lookup (GDK_ROOT_WINDOW ());
+  root_window = GDK_ROOT_PARENT(); //gdk_window_lookup (gdk_x11_get_default_root_xwindow ());
 #endif
   
   /* Add a root window filter so that we get changes on MANAGER */
@@ -333,7 +289,7 @@ egg_tray_icon_send_message (EggTrayIcon *icon,
   
   /* Get ready to send the message */
   egg_tray_icon_send_manager_message (icon, SYSTEM_TRAY_BEGIN_MESSAGE,
-                                     (Window)gtk_plug_get_id (GTK_PLUG (icon)),
+                                     (Window)gtk_plug_xembed_get_id (GTK_PLUG_XEMBED (icon)),
                                      timeout, len, stamp);
 
   /* Now to send the actual message */
@@ -350,7 +306,7 @@ egg_tray_icon_send_message (EggTrayIcon *icon,
 #endif
       
       ev.type = ClientMessage;
-      ev.window = (Window)gtk_plug_get_id (GTK_PLUG (icon));
+      ev.window = (Window)gtk_plug_xembed_get_id (GTK_PLUG_XEMBED (icon));
       ev.format = 8;
       ev.message_type = XInternAtom (xdisplay,
                                     "_NET_SYSTEM_TRAY_MESSAGE_DATA", False);
@@ -383,6 +339,6 @@ egg_tray_icon_cancel_message (EggTrayIcon *icon,
   g_return_if_fail (id > 0);
   
   egg_tray_icon_send_manager_message (icon, SYSTEM_TRAY_CANCEL_MESSAGE,
-                                     (Window)gtk_plug_get_id (GTK_PLUG (icon)),
+                                     (Window)gtk_plug_xembed_get_id (GTK_PLUG_XEMBED (icon)),
                                      id, 0, 0);
 }
similarity index 79%
rename from src/plugins/trayicon/eggtrayicon.h
rename to src/plugins/trayicon/libeggtrayicon/eggtrayicon.h
index c4396c512c781e758dddfbd2180035b0d8f610a7..7d0c6e2d64faaae63ef864f2c2a040ec5717f22c 100644 (file)
 #ifndef __EGG_TRAY_ICON_H__
 #define __EGG_TRAY_ICON_H__
 
-#include <gtk/gtk.h>
-#include <gtk/gtkplug.h>
+#include "gtkplugxembed.h"
 #include <gdk/gdkx.h>
 
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
 #define EGG_TYPE_TRAY_ICON             (egg_tray_icon_get_type ())
 #define EGG_TRAY_ICON(obj)             (GTK_CHECK_CAST ((obj), EGG_TYPE_TRAY_ICON, EggTrayIcon))
 #define EGG_TRAY_ICON_CLASS(klass)     (GTK_CHECK_CLASS_CAST ((klass), EGG_TYPE_TRAY_ICON, EggTrayIconClass))
 #define EGG_IS_TRAY_ICON(obj)          (GTK_CHECK_TYPE ((obj), EGG_TYPE_TRAY_ICON))
-#define EGG_IS_TRAY_ICON_CLASS(klass)  (GTK_CHECK_CLASS_TYPE ((klass), EGG_TYPE_TRAY_ICON))
-/*
-#define EGG_TRAY_ICON_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), EGG_TYPE_TRAY_ICON, EggTrayIconClass))
-*/
+//#define EGG_IS_TRAY_ICON_CLASS(klass)        (GTK_TYPE_CHECK_CLASS_TYPE ((klass), EGG_TYPE_TRAY_ICON))
+//#define EGG_TRAY_ICON_GET_CLASS(obj) (GTK_TYPE_INSTANCE_GET_CLASS ((obj), EGG_TYPE_TRAY_ICON, EggTrayIconClass))
        
 typedef struct _EggTrayIcon      EggTrayIcon;
 typedef struct _EggTrayIconClass  EggTrayIconClass;
 
 struct _EggTrayIcon
 {
-  GtkPlug parent_instance;
+  GtkPlugXEmbed parent_instance;
 
   guint stamp;
   
@@ -51,11 +52,13 @@ struct _EggTrayIcon
 
 struct _EggTrayIconClass
 {
-  GtkPlugClass parent_class;
+  GtkPlugXEmbedClass parent_class;
 };
 
-GtkType        egg_tray_icon_get_type       (void);
+GtkType      egg_tray_icon_get_type       (void);
 
+EggTrayIcon *
+egg_tray_icon_new_for_xscreen (Screen *xscreen, const char *name);
 #if EGG_TRAY_ENABLE_MULTIHEAD
 EggTrayIcon *egg_tray_icon_new_for_screen (GdkScreen   *screen,
                                           const gchar *name);
@@ -72,4 +75,8 @@ void         egg_tray_icon_cancel_message (EggTrayIcon *icon,
 
 
                                            
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
 #endif /* __EGG_TRAY_ICON_H__ */
diff --git a/src/plugins/trayicon/libeggtrayicon/gtk2-funcs.c b/src/plugins/trayicon/libeggtrayicon/gtk2-funcs.c
new file mode 100644 (file)
index 0000000..c947994
--- /dev/null
@@ -0,0 +1,25 @@
+#include <gtk/gtk.h>
+#include <gtk/gtkprivate.h>
+
+#include <gdk/gdkkeysyms.h>
+#include <gdk/gdkx.h>
+
+#include "gtk2-funcs.h"
+
+extern guint32 gtk2_get_current_event_time (void);
+
+guint32
+gtk2_get_current_event_time (void)
+{
+       GdkEvent *ev = gtk_get_current_event();
+       if ( ev ) {
+               guint32 result;
+               result = gdk_event_get_time(ev);
+               gdk_event_free(ev);
+               return result;
+       } else {
+               return GDK_CURRENT_TIME;
+       }
+
+}
+
diff --git a/src/plugins/trayicon/libeggtrayicon/gtk2-funcs.h b/src/plugins/trayicon/libeggtrayicon/gtk2-funcs.h
new file mode 100644 (file)
index 0000000..52ad24c
--- /dev/null
@@ -0,0 +1,42 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#ifndef __GTK2_FUNCS_H__
+#define __GTK2_FUNCS_H__
+
+#include <glib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+extern guint32 gtk2_get_current_event_time (void);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GTK2_FUNCS_H__ */
diff --git a/src/plugins/trayicon/libeggtrayicon/gtkplugxembed.c b/src/plugins/trayicon/libeggtrayicon/gtkplugxembed.c
new file mode 100644 (file)
index 0000000..7160142
--- /dev/null
@@ -0,0 +1,1180 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* By Owen Taylor <otaylor@gtk.org>              98/4/4 */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include <gtk/gtk.h>
+#include "gtkplugxembed.h"
+#include <gtk/gtkprivate.h>
+
+#include <gdk/gdkkeysyms.h>
+#include <gdk/gdkx.h>
+
+#include "xembed.h"
+#include "gtk2-funcs.h"
+
+static void            gtk_plug_xembed_class_init            (GtkPlugXEmbedClass *klass);
+static void            gtk_plug_xembed_init                  (GtkPlugXEmbed      *plug);
+static void            gtk_plug_xembed_finalize              (GtkObject          *object);
+static void            gtk_plug_xembed_realize               (GtkWidget          *widget);
+static void            gtk_plug_xembed_unrealize             (GtkWidget          *widget);
+static void            gtk_plug_xembed_show                  (GtkWidget          *widget);
+static void            gtk_plug_xembed_hide                  (GtkWidget          *widget);
+static void            gtk_plug_xembed_map                   (GtkWidget          *widget);
+static void            gtk_plug_xembed_unmap                 (GtkWidget          *widget);
+static void            gtk_plug_xembed_size_allocate         (GtkWidget          *widget,
+                                                             GtkAllocation      *allocation);
+static void            gtk_plug_xembed_size_request          (GtkWidget          *widget,
+                                                             GtkRequisition     *requisition);
+static gboolean        gtk_plug_xembed_key_press_event       (GtkWidget          *widget,
+                                                             GdkEventKey        *event);
+static gboolean        gtk_plug_xembed_focus_event           (GtkWidget          *widget,
+                                                             GdkEventFocus      *event);
+static void            gtk_plug_xembed_set_focus             (GtkWindow          *window,
+                                                             GtkWidget          *focus);
+#ifdef PORT_COMPLETE
+static gboolean        gtk_plug_xembed_focus                 (GtkWidget          *widget,
+                                                             GtkDirectionType    direction);
+#endif
+static void            gtk_plug_xembed_check_resize          (GtkContainer       *container);
+#ifdef PORT_COMPLETE
+static void            gtk_plug_xembed_keys_changed          (GtkWindow          *window);
+#endif
+static GdkFilterReturn gtk_plug_xembed_filter_func           (GdkXEvent          *gdk_xevent,
+                                                             GdkEvent           *event,
+                                                             gpointer            data);
+
+static void handle_modality_off        (GtkPlugXEmbed       *plug);
+static void send_xembed_message        (GtkPlugXEmbed       *plug,
+                                       glong                message,
+                                       glong                detail,
+                                       glong                data1,
+                                       glong                data2,
+                                       guint32              time);
+static void xembed_set_info            (GdkWindow           *window,
+                                       unsigned long        flags);
+
+
+/* From Tk */
+#define EMBEDDED_APP_WANTS_FOCUS NotifyNormal+20
+  
+static GtkWindowClass *parent_class = NULL;
+static GtkBinClass *bin_class = NULL;
+
+enum {
+  EMBEDDED,
+  LAST_SIGNAL
+}; 
+
+static guint plug_signals[LAST_SIGNAL] = { 0 };
+
+GtkType
+gtk_plug_xembed_get_type ()
+{
+  static GtkType plug_type = 0;
+
+  if (!plug_type)
+    {
+      static const GtkTypeInfo plug_info =
+      {
+             "GtkPlugXEmbed",
+             sizeof (GtkPlugXEmbed),
+             sizeof (GtkPlugXEmbedClass),
+             (GtkClassInitFunc) gtk_plug_xembed_class_init,
+             (GtkObjectInitFunc) gtk_plug_xembed_init,
+             NULL,
+             NULL,
+             NULL
+      };
+
+      plug_type = gtk_type_unique (GTK_TYPE_WINDOW, &plug_info);
+    }
+
+  return plug_type;
+}
+
+static void
+gtk_plug_xembed_class_init (GtkPlugXEmbedClass *class)
+{
+  GtkObjectClass *gtk_object_class = (GtkObjectClass *)class;
+  GtkWidgetClass *widget_class = (GtkWidgetClass *)class;
+  GtkWindowClass *window_class = (GtkWindowClass *)class;
+  GtkContainerClass *container_class = (GtkContainerClass *)class;
+
+  parent_class = gtk_type_class (GTK_TYPE_WINDOW);
+  bin_class = gtk_type_class (GTK_TYPE_BIN);
+
+  gtk_object_class->finalize = gtk_plug_xembed_finalize;
+  
+  widget_class->realize = gtk_plug_xembed_realize;
+  widget_class->unrealize = gtk_plug_xembed_unrealize;
+  widget_class->key_press_event = gtk_plug_xembed_key_press_event;
+  widget_class->focus_in_event = gtk_plug_xembed_focus_event;
+  widget_class->focus_out_event = gtk_plug_xembed_focus_event;
+
+  widget_class->show = gtk_plug_xembed_show;
+  widget_class->hide = gtk_plug_xembed_hide;
+  widget_class->map = gtk_plug_xembed_map;
+  widget_class->unmap = gtk_plug_xembed_unmap;
+  widget_class->size_allocate = gtk_plug_xembed_size_allocate;
+  widget_class->size_request = gtk_plug_xembed_size_request;
+
+#ifdef PORT_COMPLETE
+  widget_class->focus = gtk_plug_xembed_focus;
+#endif
+
+  container_class->check_resize = gtk_plug_xembed_check_resize;
+
+  window_class->set_focus = gtk_plug_xembed_set_focus;
+#ifdef PORT_COMPLETE
+  window_class->keys_changed = gtk_plug_xembed_keys_changed;
+#endif
+
+  plug_signals[EMBEDDED] =
+         gtk_signal_new ("embedded",
+                         GTK_RUN_LAST,
+                         GTK_OBJECT_CLASS (class)->type,
+                         GTK_STRUCT_OFFSET (GtkPlugXEmbedClass, embedded),
+                         gtk_marshal_NONE__NONE,
+                         GTK_TYPE_NONE, 0);
+}
+
+static void
+gtk_plug_xembed_init (GtkPlugXEmbed *plug)
+{
+  GtkWindow *window;
+
+  window = GTK_WINDOW (plug);
+
+  window->type = GTK_WINDOW_TOPLEVEL;
+}
+
+#ifdef PORT_COMPLETE
+static void
+gtk_plug_xembed_set_is_child (GtkPlugXEmbed  *plug,
+                      gboolean  is_child)
+{
+  g_assert (!GTK_WIDGET (plug)->parent);
+      
+  if (is_child)
+    {
+#if PORT_COMPLETE
+      if (plug->modality_window)
+       handle_modality_off (plug);
+
+      if (plug->modality_group)
+       {
+         gtk_window_group_remove_window (plug->modality_group, GTK_WINDOW (plug));
+         gtk_object_unref (plug->modality_group);
+         plug->modality_group = NULL;
+       }
+#endif
+
+      /* As a toplevel, the MAPPED flag doesn't correspond
+       * to whether the widget->window is mapped; we unmap
+       * here, but don't bother remapping -- we will get mapped
+       * by gtk_widget_set_parent ().
+       */
+      if (GTK_WIDGET_MAPPED (plug))
+       gtk_widget_unmap (GTK_WIDGET (plug));
+      
+      GTK_WIDGET_UNSET_FLAGS (plug, GTK_TOPLEVEL);
+      gtk_container_set_resize_mode (GTK_CONTAINER (plug), GTK_RESIZE_PARENT);
+
+#ifdef PORT_COMPLETE
+      _gtk_widget_propagate_hierarchy_changed (GTK_WIDGET (plug), GTK_WIDGET (plug));
+#endif
+    }
+  else
+    {
+      if (GTK_WINDOW (plug)->focus_widget)
+       gtk_window_set_focus (GTK_WINDOW (plug), NULL);
+      if (GTK_WINDOW (plug)->default_widget)
+       gtk_window_set_default (GTK_WINDOW (plug), NULL);
+         
+#ifdef PORT_COMPLETE
+      plug->modality_group = gtk_window_group_new ();
+      gtk_window_group_add_window (plug->modality_group, GTK_WINDOW (plug));
+#endif
+
+      GTK_WIDGET_SET_FLAGS (plug, GTK_TOPLEVEL);
+      gtk_container_set_resize_mode (GTK_CONTAINER (plug), GTK_RESIZE_QUEUE);
+
+#ifdef PORT_COMPLETE
+      _gtk_widget_propagate_hierarchy_changed (GTK_WIDGET (plug), NULL);
+#endif
+    }
+}
+#endif
+
+/**
+ * _gtk_plug_xembed_add_to_socket:
+ * @plug: a #GtkPlugXEmbed
+ * @socket: a #GtkSocket
+ * 
+ * Adds a plug to a socket within the same application.
+ **/
+void
+_gtk_plug_xembed_add_to_socket (GtkPlugXEmbed   *plug,
+                               GtkSocket *socket)
+{
+#ifdef PORT_COMPLETE /* Only foreign sockets for now */
+  GtkWidget *widget;
+  gint w, h;
+  
+  g_return_if_fail (GTK_IS_PLUG_XEMBED (plug));
+  g_return_if_fail (GTK_IS_SOCKET (socket));
+  g_return_if_fail (GTK_WIDGET_REALIZED (socket));
+
+  widget = GTK_WIDGET (plug);
+
+  gtk_plug_xembed_set_is_child (plug, TRUE);
+  plug->same_app = TRUE;
+  socket->same_app = TRUE;
+  socket->plug_widget = widget;
+
+  plug->socket_window = GTK_WIDGET (socket)->window;
+
+  if (GTK_WIDGET_REALIZED (widget))
+    {
+      gdk_drawable_get_size (GDK_DRAWABLE (widget->window), &w, &h);
+      gdk_window_reparent (widget->window, plug->socket_window, -w, -h);
+    }
+
+  gtk_widget_set_parent (widget, GTK_WIDGET (socket));
+
+  g_signal_emit_by_name (G_OBJECT (socket), "plug_added", 0);
+#endif
+}
+
+/**
+ * _gtk_plug_xembed_remove_from_socket:
+ * @plug: a #GtkPlugXEmbed
+ * @socket: a #GtkSocket
+ * 
+ * Removes a plug from a socket within the same application.
+ **/
+void
+_gtk_plug_xembed_remove_from_socket (GtkPlugXEmbed   *plug,
+                                    GtkSocket *socket)
+{
+#ifdef PORT_COMPLETE /* Only foreign sockets for now */
+  GtkWidget *widget;
+  GdkEvent event;
+  gboolean result;
+  gboolean widget_was_visible;
+
+  g_return_if_fail (GTK_IS_PLUG_XEMBED (plug));
+  g_return_if_fail (GTK_IS_SOCKET (socket));
+  g_return_if_fail (GTK_WIDGET_REALIZED (plug));
+
+  widget = GTK_WIDGET (plug);
+
+  gtk_object_ref (plug);
+  gtk_object_ref (socket);
+
+  widget_was_visible = GTK_WIDGET_VISIBLE (plug);
+  
+  gdk_window_hide (widget->window);
+  gdk_window_reparent (widget->window, GDK_ROOT_PARENT (), 0, 0);
+
+  GTK_PRIVATE_SET_FLAG (plug, GTK_IN_REPARENT);
+  gtk_widget_unparent (GTK_WIDGET (plug));
+  GTK_PRIVATE_UNSET_FLAG (plug, GTK_IN_REPARENT);
+  
+  socket->plug_widget = NULL;
+  gdk_window_unref (socket->plug_window);
+  socket->plug_window = NULL;
+  
+  socket->same_app = FALSE;
+
+  plug->same_app = FALSE;
+  plug->socket_window = NULL;
+
+  gtk_plug_xembed_set_is_child (plug, FALSE);
+                   
+  g_signal_emit_by_name (G_OBJECT (socket), "plug_removed", &result);
+  if (!result)
+    gtk_widget_destroy (GTK_WIDGET (socket));
+
+  event.any.type = GDK_DELETE;
+  event.any.window = gdk_window_ref (widget->window);
+  event.any.send_event = FALSE;
+  
+  if (!gtk_widget_event (widget, &event))
+    gtk_widget_destroy (widget);
+  
+  gdk_window_unref (event.any.window);
+  gtk_object_unref (plug);
+
+  if (widget_was_visible && GTK_WIDGET_VISIBLE (socket))
+    gtk_widget_queue_resize (GTK_WIDGET (socket));
+
+  gtk_object_unref (socket);
+#endif
+}
+
+void
+gtk_plug_xembed_construct (GtkPlugXEmbed         *plug,
+                          GtkPlugXEmbedNativeWindow  socket_id)
+{
+  if (socket_id)
+    {
+#ifdef PORT_COMPLETE /* Only foreign windows for now */
+      gpointer user_data = NULL;
+
+      plug->socket_window = gdk_window_lookup (socket_id);
+
+      if (plug->socket_window)
+       gdk_window_get_user_data (plug->socket_window, &user_data);
+      else
+       plug->socket_window = gdk_window_foreign_new (socket_id);
+
+      if (user_data)
+       {
+         if (GTK_IS_SOCKET (user_data))
+           _gtk_plug_xembed_add_to_socket (plug, user_data);
+         else
+           {
+                   g_warning (/*G_STRLOC*/ "Can't create GtkPlugXEmbed as child of non-GtkSocket");
+             plug->socket_window = NULL;
+           }
+       }
+
+      if (plug->socket_window)
+       g_signal_emit (G_OBJECT (plug), plug_signals[EMBEDDED], 0);
+#else
+      plug->socket_window = gdk_window_foreign_new (socket_id);
+#endif
+      
+    }
+}
+
+GtkWidget*
+gtk_plug_xembed_new (GtkPlugXEmbedNativeWindow socket_id)
+{
+  GtkPlugXEmbed *plug;
+
+  plug = GTK_PLUG_XEMBED (gtk_type_new (GTK_TYPE_PLUG_XEMBED));
+  gtk_plug_xembed_construct (plug, socket_id);
+  return GTK_WIDGET (plug);
+}
+
+/**
+ * gtk_plug_xembed_get_id:
+ * @plug: a #GtkPlugXEmbed.
+ * 
+ * Gets the window ID of a #GtkPlugXEmbed widget, which can then
+ * be used to embed this window inside another window, for
+ * instance with gtk_socket_add_id().
+ * 
+ * Return value: the window ID for the plug
+ **/
+GtkPlugXEmbedNativeWindow
+gtk_plug_xembed_get_id (GtkPlugXEmbed *plug)
+{
+  g_return_val_if_fail (GTK_IS_PLUG_XEMBED (plug), 0);
+
+  if (!GTK_WIDGET_REALIZED (plug))
+    gtk_widget_realize (GTK_WIDGET (plug));
+
+  return GDK_WINDOW_XWINDOW (GTK_WIDGET (plug)->window);
+}
+
+static void
+gtk_plug_xembed_finalize (GtkObject *object)
+{
+  GtkPlugXEmbed *plug = GTK_PLUG_XEMBED (object);
+
+  if (plug->grabbed_keys)
+    {
+      g_hash_table_destroy (plug->grabbed_keys);
+      plug->grabbed_keys = NULL;
+    }
+  
+  GTK_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gtk_plug_xembed_unrealize (GtkWidget *widget)
+{
+  GtkPlugXEmbed *plug;
+
+  g_return_if_fail (GTK_IS_PLUG_XEMBED (widget));
+
+  plug = GTK_PLUG_XEMBED (widget);
+
+  if (plug->socket_window != NULL)
+    {
+      gdk_window_set_user_data (plug->socket_window, NULL);
+      gdk_window_unref (plug->socket_window);
+      plug->socket_window = NULL;
+    }
+
+#ifdef PORT_COMPLETE
+  if (!plug->same_app)
+    {
+      if (plug->modality_window)
+       handle_modality_off (plug);
+
+      gtk_window_group_remove_window (plug->modality_group, GTK_WINDOW (plug));
+      gtk_object_unref (plug->modality_group);
+    }
+#endif
+  
+  if (GTK_WIDGET_CLASS (parent_class)->unrealize)
+    (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
+}
+
+static void
+gtk_plug_xembed_realize (GtkWidget *widget)
+{
+  GtkWindow *window;
+  GtkPlugXEmbed *plug;
+  GdkWindowAttr attributes;
+  gint attributes_mask;
+
+  g_return_if_fail (GTK_IS_PLUG_XEMBED (widget));
+
+  GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
+  window = GTK_WINDOW (widget);
+  plug = GTK_PLUG_XEMBED (widget);
+
+  attributes.window_type = GDK_WINDOW_CHILD;   /* XXX GDK_WINDOW_PLUG ? */
+  attributes.title = window->title;
+  attributes.wmclass_name = window->wmclass_name;
+  attributes.wmclass_class = window->wmclass_class;
+  attributes.width = widget->allocation.width;
+  attributes.height = widget->allocation.height;
+  attributes.wclass = GDK_INPUT_OUTPUT;
+
+  /* this isn't right - we should match our parent's visual/colormap.
+   * though that will require handling "foreign" colormaps */
+  attributes.visual = gtk_widget_get_visual (widget);
+  attributes.colormap = gtk_widget_get_colormap (widget);
+  attributes.event_mask = gtk_widget_get_events (widget);
+  attributes.event_mask |= (GDK_EXPOSURE_MASK |
+                           GDK_KEY_PRESS_MASK |
+                           GDK_KEY_RELEASE_MASK |
+                           GDK_ENTER_NOTIFY_MASK |
+                           GDK_LEAVE_NOTIFY_MASK |
+                           GDK_FOCUS_CHANGE_MASK |
+                           GDK_STRUCTURE_MASK);
+
+  attributes_mask = GDK_WA_VISUAL | GDK_WA_COLORMAP;
+  attributes_mask |= (window->title ? GDK_WA_TITLE : 0);
+  attributes_mask |= (window->wmclass_name ? GDK_WA_WMCLASS : 0);
+
+  if (GTK_WIDGET_TOPLEVEL (widget))
+    {
+      attributes.window_type = GDK_WINDOW_TOPLEVEL;
+
+      gdk_error_trap_push ();
+      widget->window = gdk_window_new (plug->socket_window, 
+                                      &attributes, attributes_mask);
+      gdk_flush ();
+      if (gdk_error_trap_pop ()) /* Uh-oh */
+       {
+         gdk_error_trap_push ();
+         gdk_window_destroy (widget->window);
+         gdk_flush ();
+         gdk_error_trap_pop ();
+         widget->window = gdk_window_new (NULL, &attributes, attributes_mask);
+       }
+      
+      gdk_window_add_filter (widget->window, gtk_plug_xembed_filter_func, widget);
+
+#ifdef PORT_COMPLETE
+      plug->modality_group = gtk_window_group_new ();
+      gtk_window_group_add_window (plug->modality_group, window);
+#endif
+      
+      xembed_set_info (widget->window, 0);
+    }
+  else
+    widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);      
+  
+  gdk_window_set_user_data (widget->window, window);
+
+  widget->style = gtk_style_attach (widget->style, widget->window);
+  gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
+}
+
+static void
+gtk_plug_xembed_show (GtkWidget *widget)
+{
+  if (GTK_WIDGET_TOPLEVEL (widget))
+    GTK_WIDGET_CLASS (parent_class)->show (widget);
+  else
+    GTK_WIDGET_CLASS (bin_class)->show (widget);
+}
+
+static void
+gtk_plug_xembed_hide (GtkWidget *widget)
+{
+  if (GTK_WIDGET_TOPLEVEL (widget))
+    GTK_WIDGET_CLASS (parent_class)->hide (widget);
+  else
+    GTK_WIDGET_CLASS (bin_class)->hide (widget);
+}
+
+static void
+gtk_plug_xembed_map (GtkWidget *widget)
+{
+  if (GTK_WIDGET_TOPLEVEL (widget)) {
+         GtkBin *bin = GTK_BIN (widget);
+         
+         GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
+         
+         if (bin->child &&
+             GTK_WIDGET_VISIBLE (bin->child) &&
+             !GTK_WIDGET_MAPPED (bin->child))
+                 gtk_widget_map (bin->child);
+         xembed_set_info (widget->window, XEMBED_MAPPED);
+         if (!GTK_WIDGET_NO_WINDOW (widget))
+                 gdk_window_show (widget->window);
+
+#ifdef PORT_COMPLETE
+         gdk_synthesize_window_state (widget->window,
+                                      GDK_WINDOW_STATE_WITHDRAWN,
+                                      0);
+#endif
+  } else {
+         GTK_WIDGET_CLASS (bin_class)->map (widget);
+  }
+}
+
+static void
+gtk_plug_xembed_unmap (GtkWidget *widget)
+{
+  if (GTK_WIDGET_TOPLEVEL (widget))
+    {
+      GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
+
+      gdk_window_hide (widget->window);
+      xembed_set_info (widget->window, 0);
+
+#ifdef PORT_COMPLETE      
+      gdk_synthesize_window_state (widget->window,
+                                  0,
+                                  GDK_WINDOW_STATE_WITHDRAWN);
+#endif
+    }
+  else
+    GTK_WIDGET_CLASS (bin_class)->unmap (widget);
+}
+
+static void
+gtk_plug_xembed_size_request (GtkWidget     *widget,
+                             GtkRequisition *requisition)
+{
+  requisition->width = 22;
+  requisition->height = 22;
+}
+
+static void
+gtk_plug_xembed_size_allocate (GtkWidget     *widget,
+                              GtkAllocation *allocation)
+{
+  if (GTK_WIDGET_TOPLEVEL (widget))
+    GTK_WIDGET_CLASS (parent_class)->size_allocate (widget, allocation);
+  else
+    {
+      GtkBin *bin = GTK_BIN (widget);
+
+      widget->allocation = *allocation;
+
+      if (GTK_WIDGET_REALIZED (widget))
+       gdk_window_move_resize (widget->window,
+                               allocation->x, allocation->y,
+                               allocation->width, allocation->height);
+
+      if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
+       {
+         GtkAllocation child_allocation;
+         
+         child_allocation.x = child_allocation.y = GTK_CONTAINER (widget)->border_width;
+         child_allocation.width =
+           MAX (1, (gint)allocation->width - child_allocation.x * 2);
+         child_allocation.height =
+           MAX (1, (gint)allocation->height - child_allocation.y * 2);
+         
+         gtk_widget_size_allocate (bin->child, &child_allocation);
+       }
+      
+    }
+}
+
+static gboolean
+gtk_plug_xembed_key_press_event (GtkWidget   *widget,
+                         GdkEventKey *event)
+{
+  if (GTK_WIDGET_TOPLEVEL (widget))
+    return GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event);
+  else
+    return FALSE;
+}
+
+static gboolean
+gtk_plug_xembed_focus_event (GtkWidget      *widget,
+                     GdkEventFocus  *event)
+{
+  /* We eat focus-in events and focus-out events, since they
+   * can be generated by something like a keyboard grab on
+   * a child of the plug.
+   */
+  return FALSE;
+}
+
+static void
+gtk_plug_xembed_set_focus (GtkWindow *window,
+                          GtkWidget *focus)
+{
+  GtkPlugXEmbed *plug = GTK_PLUG_XEMBED (window);
+
+  GTK_WINDOW_CLASS (parent_class)->set_focus (window, focus);
+  
+  /* Ask for focus from embedder
+   */
+
+  if (focus && !window->window_has_focus)
+    {
+      send_xembed_message (plug, XEMBED_REQUEST_FOCUS, 0, 0, 0,
+                          gtk2_get_current_event_time ());
+    }
+}
+
+#ifdef PORT_COMPLETE
+typedef struct
+{
+  guint                         accelerator_key;
+  GdkModifierType       accelerator_mods;
+} GrabbedKey;
+
+static guint
+grabbed_key_hash (gconstpointer a)
+{
+  const GrabbedKey *key = a;
+  guint h;
+  
+  h = key->accelerator_key << 16;
+  h ^= key->accelerator_key >> 16;
+  h ^= key->accelerator_mods;
+
+  return h;
+}
+
+static gboolean
+grabbed_key_equal (gconstpointer a, gconstpointer b)
+{
+  const GrabbedKey *keya = a;
+  const GrabbedKey *keyb = b;
+
+  return (keya->accelerator_key == keyb->accelerator_key &&
+         keya->accelerator_mods == keyb->accelerator_mods);
+}
+
+static void
+add_grabbed_key (gpointer key, gpointer val, gpointer data)
+{
+  GrabbedKey *grabbed_key = key;
+  GtkPlugXEmbed *plug = data;
+
+  if (!plug->grabbed_keys ||
+      !g_hash_table_lookup (plug->grabbed_keys, grabbed_key))
+    {
+      send_xembed_message (plug, XEMBED_GTK_GRAB_KEY, 0, 
+                          grabbed_key->accelerator_key, grabbed_key->accelerator_mods,
+                          gtk_get_current_event_time ());
+    }
+}
+
+static void
+add_grabbed_key_always (gpointer key, gpointer val, gpointer data)
+{
+  GrabbedKey *grabbed_key = key;
+  GtkPlugXEmbed *plug = data;
+
+  send_xembed_message (plug, XEMBED_GTK_GRAB_KEY, 0, 
+                      grabbed_key->accelerator_key, grabbed_key->accelerator_mods,
+                      gtk_get_current_event_time ());
+}
+
+static void
+remove_grabbed_key (gpointer key, gpointer val, gpointer data)
+{
+  GrabbedKey *grabbed_key = key;
+  GtkPlugXEmbed *plug = data;
+
+  if (!plug->grabbed_keys ||
+      !g_hash_table_lookup (plug->grabbed_keys, grabbed_key))
+    {
+      send_xembed_message (plug, XEMBED_GTK_UNGRAB_KEY, 0, 
+                          grabbed_key->accelerator_key, grabbed_key->accelerator_mods,
+                          gtk_get_current_event_time ());
+    }
+}
+
+static void
+keys_foreach (GtkWindow      *window,
+             guint           keyval,
+             GdkModifierType modifiers,
+             gboolean        is_mnemonic,
+             gpointer        data)
+{
+  GHashTable *new_grabbed_keys = data;
+  GrabbedKey *key = g_new (GrabbedKey, 1);
+
+  key->accelerator_key = keyval;
+  key->accelerator_mods = modifiers;
+  
+  g_hash_table_replace (new_grabbed_keys, key, key);
+}
+
+#ifdef PORT_COMPLETE
+static void
+gtk_plug_xembed_keys_changed (GtkWindow *window)
+{
+  GHashTable *new_grabbed_keys, *old_grabbed_keys;
+  GtkPlugXEmbed *plug = GTK_PLUG_XEMBED (window);
+
+  new_grabbed_keys = g_hash_table_new_full (grabbed_key_hash, grabbed_key_equal, (GDestroyNotify)g_free, NULL);
+  _gtk_window_keys_foreach (window, keys_foreach, new_grabbed_keys);
+
+  if (plug->socket_window)
+    g_hash_table_foreach (new_grabbed_keys, add_grabbed_key, plug);
+
+  old_grabbed_keys = plug->grabbed_keys;
+  plug->grabbed_keys = new_grabbed_keys;
+
+  if (old_grabbed_keys)
+    {
+      if (plug->socket_window)
+       g_hash_table_foreach (old_grabbed_keys, remove_grabbed_key, plug);
+      g_hash_table_destroy (old_grabbed_keys);
+    }
+}
+#endif
+#endif
+
+#ifdef PORT_COMPLETE
+static gboolean
+gtk_plug_xembed_focus (GtkWidget        *widget,
+                      GtkDirectionType  direction)
+{
+  GtkBin *bin = GTK_BIN (widget);
+  GtkPlugXEmbed *plug = GTK_PLUG_XEMBED (widget);
+  GtkWindow *window = GTK_WINDOW (widget);
+  GtkContainer *container = GTK_CONTAINER (widget);
+  GtkWidget *old_focus_child = container->focus_child;
+  GtkWidget *parent;
+
+  /* We override GtkWindow's behavior, since we don't want wrapping here.
+   */
+  if (old_focus_child)
+    {
+      if (gtk_widget_child_focus (old_focus_child, direction))
+       return TRUE;
+
+      if (window->focus_widget)
+       {
+         /* Wrapped off the end, clear the focus setting for the toplevel */
+         parent = window->focus_widget->parent;
+         while (parent)
+           {
+             gtk_container_set_focus_child (GTK_CONTAINER (parent), NULL);
+             parent = GTK_WIDGET (parent)->parent;
+           }
+         
+         gtk_window_set_focus (GTK_WINDOW (container), NULL);
+
+         if (!GTK_CONTAINER (window)->focus_child)
+           {
+             gint message = -1;
+
+             switch (direction)
+               {
+               case GTK_DIR_UP:
+               case GTK_DIR_LEFT:
+               case GTK_DIR_TAB_BACKWARD:
+                 message = XEMBED_FOCUS_PREV;
+                 break;
+               case GTK_DIR_DOWN:
+               case GTK_DIR_RIGHT:
+               case GTK_DIR_TAB_FORWARD:
+                 message = XEMBED_FOCUS_NEXT;
+                 break;
+               }
+             
+             send_xembed_message (plug, message, 0, 0, 0,
+                                  gtk_get_current_event_time ());
+           }
+       }
+
+      return FALSE;
+    }
+  else
+    {
+      /* Try to focus the first widget in the window */
+      
+      if (bin->child && gtk_widget_child_focus (bin->child, direction))
+        return TRUE;
+    }
+
+  return FALSE;
+}
+#endif
+
+static void
+gtk_plug_xembed_check_resize (GtkContainer *container)
+{
+  if (GTK_WIDGET_TOPLEVEL (container))
+    GTK_CONTAINER_CLASS (parent_class)->check_resize (container);
+  else
+    GTK_CONTAINER_CLASS (bin_class)->check_resize (container);
+}
+
+static void
+send_xembed_message (GtkPlugXEmbed *plug,
+                    glong      message,
+                    glong      detail,
+                    glong      data1,
+                    glong      data2,
+                    guint32    time)
+{
+  if (plug->socket_window)
+    {
+      XEvent xevent;
+
+      GTK_NOTE(PLUGSOCKET,
+              g_message ("GtkPlugXEmbed: Sending XEMBED message of type %ld", message));
+
+      xevent.xclient.window = GDK_WINDOW_XWINDOW (plug->socket_window);
+      xevent.xclient.type = ClientMessage;
+      xevent.xclient.message_type = (Atom)gdk_atom_intern ("_XEMBED", FALSE);
+      xevent.xclient.format = 32;
+      xevent.xclient.data.l[0] = 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_DISPLAY (),
+                 GDK_WINDOW_XWINDOW (plug->socket_window),
+                 False, NoEventMask, &xevent);
+      gdk_flush ();
+      gdk_error_trap_pop ();
+    }
+}
+
+static void
+focus_first_last (GtkPlugXEmbed          *plug,
+                 GtkDirectionType  direction)
+{
+  GtkWindow *window = GTK_WINDOW (plug);
+  GtkWidget *parent;
+  
+  if (window->focus_widget)
+    {
+      parent = window->focus_widget->parent;
+      while (parent)
+       {
+         gtk_container_set_focus_child (GTK_CONTAINER (parent), NULL);
+         parent = GTK_WIDGET (parent)->parent;
+       }
+      
+      gtk_window_set_focus (GTK_WINDOW (plug), NULL);
+    }
+
+#ifdef PORT_COMPLETE
+  gtk_widget_child_focus (GTK_WIDGET (plug), direction);
+#endif
+}
+
+static void
+handle_modality_on (GtkPlugXEmbed *plug)
+{
+#ifdef PORT_COMPLETE
+  if (!plug->modality_window)
+    {
+      plug->modality_window = gtk_window_new (GTK_WINDOW_POPUP);
+      gtk_widget_realize (plug->modality_window);
+      gtk_window_group_add_window (plug->modality_group, GTK_WINDOW (plug->modality_window));
+      gtk_grab_add (plug->modality_window);
+    }
+#else
+  // g_print("Modality On for plug %p\n", plug);
+#endif
+}
+
+static void
+handle_modality_off (GtkPlugXEmbed *plug)
+{
+#ifdef PORT_COMPLETE
+  if (plug->modality_window)
+    {
+      gtk_widget_destroy (plug->modality_window);
+      plug->modality_window = NULL;
+    }
+#else
+  // g_print("Modality Off for plug %p\n", plug);
+#endif
+}
+
+static void
+xembed_set_info (GdkWindow     *gdk_window,
+                unsigned long  flags)
+{
+  Display *display = GDK_WINDOW_XDISPLAY (gdk_window);
+  Window window = GDK_WINDOW_XWINDOW (gdk_window);
+  unsigned long buffer[2];
+  
+  Atom xembed_info_atom = (Atom)gdk_atom_intern ("_XEMBED_INFO", FALSE);
+                          
+  buffer[1] = 0;               /* Protocol version */
+  buffer[1] = flags;
+
+  XChangeProperty (display, window,
+                  xembed_info_atom, xembed_info_atom, 32,
+                  PropModeReplace,
+                  (unsigned char *)buffer, 2);
+}
+
+static void
+handle_xembed_message (GtkPlugXEmbed   *plug,
+                      glong      message,
+                      glong      detail,
+                      glong      data1,
+                      glong      data2,
+                      guint32    time)
+{
+  GTK_NOTE (PLUGSOCKET,
+           g_message ("GtkPlugXEmbed: Message of type %ld received\n", message));
+  
+  switch (message)
+    {
+    case XEMBED_EMBEDDED_NOTIFY:
+      break;
+    case XEMBED_WINDOW_ACTIVATE:
+      GTK_NOTE(PLUGSOCKET,
+              g_message ("GtkPlugXEmbed: ACTIVATE received"));
+      break;
+    case XEMBED_WINDOW_DEACTIVATE:
+      GTK_NOTE(PLUGSOCKET,
+              g_message ("GtkPlugXEmbed: DEACTIVATE received"));
+      break;
+      
+    case XEMBED_MODALITY_ON:
+      handle_modality_on (plug);
+      break;
+    case XEMBED_MODALITY_OFF:
+      handle_modality_off (plug);
+      break;
+
+    case XEMBED_FOCUS_IN:
+      switch (detail)
+       {
+       case XEMBED_FOCUS_FIRST:
+         focus_first_last (plug, GTK_DIR_TAB_FORWARD);
+         break;
+       case XEMBED_FOCUS_LAST:
+         focus_first_last (plug, GTK_DIR_TAB_BACKWARD);
+         break;
+       case XEMBED_FOCUS_CURRENT:
+         /* fall through */;
+       }
+      
+    case XEMBED_FOCUS_OUT:
+      {
+       GtkWidget *widget = GTK_WIDGET (plug);
+       GdkEvent event;
+
+       event.focus_change.type = GDK_FOCUS_CHANGE;
+       event.focus_change.window = widget->window;
+       event.focus_change.send_event = TRUE;
+
+       if (message == XEMBED_FOCUS_IN)
+         {
+           event.focus_change.in = TRUE;
+           GTK_WIDGET_CLASS (parent_class)->focus_in_event (widget, (GdkEventFocus *)&event);
+         }
+       else
+         {
+           event.focus_change.in = FALSE;
+           GTK_WIDGET_CLASS (parent_class)->focus_out_event (widget, (GdkEventFocus *)&event);
+         }
+       
+       break;
+      }
+      
+    case XEMBED_GRAB_KEY:
+    case XEMBED_UNGRAB_KEY:
+    case XEMBED_GTK_GRAB_KEY:
+    case XEMBED_GTK_UNGRAB_KEY:
+    case XEMBED_REQUEST_FOCUS:
+    case XEMBED_FOCUS_NEXT:
+    case XEMBED_FOCUS_PREV:
+      g_warning ("GtkPlugXEmbed: Invalid _XEMBED message of type %ld received", message);
+      break;
+      
+    default:
+      GTK_NOTE(PLUGSOCKET,
+              g_message ("GtkPlugXEmbed: Ignoring unknown _XEMBED message of type %ld", message));
+      break;
+    }
+}
+
+static GdkFilterReturn
+gtk_plug_xembed_filter_func (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data)
+{
+  GtkPlugXEmbed *plug = GTK_PLUG_XEMBED (data);
+  XEvent *xevent = (XEvent *)gdk_xevent;
+
+  GdkFilterReturn return_val;
+  
+  return_val = GDK_FILTER_CONTINUE;
+
+  switch (xevent->type)
+    {
+    case ClientMessage:
+      if (xevent->xclient.message_type == (Atom)gdk_atom_intern ("_XEMBED", FALSE))
+       {
+         handle_xembed_message (plug,
+                                xevent->xclient.data.l[1],
+                                xevent->xclient.data.l[2],
+                                xevent->xclient.data.l[3],
+                                xevent->xclient.data.l[4],
+                                xevent->xclient.data.l[0]);
+                                
+
+         return GDK_FILTER_REMOVE;
+       }
+      else if (xevent->xclient.message_type == (Atom)gdk_atom_intern ("WM_DELETE_WINDOW", FALSE))
+       {
+         /* We filter these out because we take being reparented back to the
+          * root window as the reliable end of the embedding protocol
+          */
+
+         return GDK_FILTER_REMOVE;
+       }
+      break;
+    case ReparentNotify:
+    {
+       XReparentEvent *xre = &xevent->xreparent;
+       gboolean was_embedded = plug->socket_window != NULL;
+
+       return_val = GDK_FILTER_REMOVE;
+       
+       gtk_object_ref (GTK_OBJECT(plug));
+       
+       if (was_embedded)
+         {
+           /* End of embedding protocol for previous socket */
+           
+           /* FIXME: race if we remove from another socket and
+            * then add to a local window before we get notification
+            * Probably need check in _gtk_plug_xembed_add_to_socket
+            */
+           
+           if (xre->parent != GDK_WINDOW_XWINDOW (plug->socket_window))
+             {
+               GtkWidget *widget = GTK_WIDGET (plug);
+
+               gdk_window_set_user_data (plug->socket_window, NULL);
+               gdk_window_unref (plug->socket_window);
+               plug->socket_window = NULL;
+
+               /* Emit a delete window, as if the user attempted
+                * to close the toplevel. Simple as to how we
+                * handle WM_DELETE_WINDOW, if it isn't handled
+                * we destroy the widget. BUt only do this if
+                * we are being reparented to the root window.
+                * Moving from one embedder to another should
+                * be invisible to the app.
+                */
+
+               if (xre->parent == GDK_ROOT_WINDOW())
+                 {
+                   GdkEvent event;
+                   
+                   event.any.type = GDK_DELETE;
+                   event.any.window = gdk_window_ref (widget->window);
+                   event.any.send_event = FALSE;
+                   
+                   if (!gtk_widget_event (widget, &event))
+                     gtk_widget_destroy (widget);
+                   
+                   gdk_window_unref (event.any.window);
+                 }
+             }
+           else
+             goto done;
+         }
+
+       if (xre->parent != GDK_ROOT_WINDOW ())
+         {
+           /* Start of embedding protocol */
+
+           plug->socket_window = gdk_window_lookup (xre->parent);
+           if (plug->socket_window)
+             {
+               gpointer user_data = NULL;
+               gdk_window_get_user_data (plug->socket_window, &user_data);
+
+               if (user_data)
+                 {
+                   g_warning (/*G_STRLOC*/ "Plug reparented unexpectedly into window in the same process");
+                   plug->socket_window = NULL;
+                   break;
+                 }
+               
+               gdk_window_ref (plug->socket_window);
+             }
+           else
+             {
+               plug->socket_window = gdk_window_foreign_new (xre->parent);
+               if (!plug->socket_window) /* Already gone */
+                 break;
+             }
+
+#ifdef PORT_COMPLETE
+           if (plug->grabbed_keys)
+             g_hash_table_foreach (plug->grabbed_keys, add_grabbed_key_always, plug);
+#endif
+
+           if (!was_embedded)
+             gtk_signal_emit (GTK_OBJECT (plug), plug_signals[EMBEDDED], 0);
+         }
+
+      done:
+       gtk_object_unref (GTK_OBJECT(plug));
+       
+       break;
+      }
+    }
+
+  return GDK_FILTER_CONTINUE;
+}
diff --git a/src/plugins/trayicon/libeggtrayicon/gtkplugxembed.h b/src/plugins/trayicon/libeggtrayicon/gtkplugxembed.h
new file mode 100644 (file)
index 0000000..f339a96
--- /dev/null
@@ -0,0 +1,97 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#ifndef __GTK_PLUG_XEMBED_H__
+#define __GTK_PLUG_XEMBED_H__
+
+
+#include <gdk/gdk.h>
+#include <gtk/gtksocket.h>
+#include <gtk/gtkwindow.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+#define GTK_TYPE_PLUG_XEMBED            (gtk_plug_xembed_get_type ())
+#define GTK_PLUG_XEMBED(obj)            (GTK_CHECK_CAST ((obj), GTK_TYPE_PLUG_XEMBED, GtkPlugXEmbed))
+#define GTK_PLUG_XEMBED_CLASS(klass)    (GTK_CHECK_CLASS_CAST ((klass), GTK_TYPE_PLUG_XEMBED, GtkPlugXEmbedClass))
+#define GTK_IS_PLUG_XEMBED(obj)         (GTK_CHECK_TYPE ((obj), GTK_TYPE_PLUG_XEMBED))
+#define GTK_IS_PLUG_XEMBED_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GTK_TYPE_PLUG_XEMBED))
+#define GTK_PLUG_XEMBED_GET_CLASS(obj)  (GTK_CHECK_GET_CLASS ((obj), GTK_TYPE_PLUG_XEMBED, GtkPlugXEmbedClass))
+
+
+typedef struct _GtkPlugXEmbed        GtkPlugXEmbed;
+typedef struct _GtkPlugXEmbedClass   GtkPlugXEmbedClass;
+
+typedef guint32 GtkPlugXEmbedNativeWindow;
+
+struct _GtkPlugXEmbed
+{
+  GtkWindow window;
+
+  GdkWindow *socket_window;
+#ifdef PORT_COMPLETE
+  GtkWidget *modality_window;
+  GtkWindowGroup *modality_group;
+#endif
+  GHashTable *grabbed_keys;
+
+  guint same_app : 1;
+};
+
+struct _GtkPlugXEmbedClass
+{
+  GtkWindowClass parent_class;
+
+  void (*embedded) (GtkPlugXEmbed *plug);
+
+  /* Padding for future expansion */
+  void (*_gtk_reserved1) (void);
+  void (*_gtk_reserved2) (void);
+  void (*_gtk_reserved3) (void);
+  void (*_gtk_reserved4) (void);
+};
+
+
+GtkType    gtk_plug_xembed_get_type  (void) G_GNUC_CONST;
+void       gtk_plug_xembed_construct (GtkPlugXEmbed *plug, GtkPlugXEmbedNativeWindow socket_id);
+
+GtkWidget*      gtk_plug_xembed_new    (GtkPlugXEmbedNativeWindow  socket_id);
+GtkPlugXEmbedNativeWindow gtk_plug_xembed_get_id (GtkPlugXEmbed         *plug);
+
+void _gtk_plug_xembed_add_to_socket      (GtkPlugXEmbed   *plug,
+                                         GtkSocket *socket);
+void _gtk_plug_xembed_remove_from_socket (GtkPlugXEmbed   *plug,
+                                         GtkSocket *socket);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GTK_PLUG_XEMBED_H__ */
diff --git a/src/plugins/trayicon/libeggtrayicon/xembed.h b/src/plugins/trayicon/libeggtrayicon/xembed.h
new file mode 100644 (file)
index 0000000..14d55e6
--- /dev/null
@@ -0,0 +1,26 @@
+/* XEMBED messages */
+#define XEMBED_EMBEDDED_NOTIFY          0
+#define XEMBED_WINDOW_ACTIVATE          1
+#define XEMBED_WINDOW_DEACTIVATE        2
+#define XEMBED_REQUEST_FOCUS            3
+#define XEMBED_FOCUS_IN                 4
+#define XEMBED_FOCUS_OUT                5
+#define XEMBED_FOCUS_NEXT               6
+#define XEMBED_FOCUS_PREV               7
+#define XEMBED_GRAB_KEY                 8
+#define XEMBED_UNGRAB_KEY               9
+#define XEMBED_MODALITY_ON              10
+#define XEMBED_MODALITY_OFF             11
+
+/* Non standard messages*/
+#define XEMBED_GTK_GRAB_KEY             108 
+#define XEMBED_GTK_UNGRAB_KEY           109
+
+/* Details for  XEMBED_FOCUS_IN: */
+#define XEMBED_FOCUS_CURRENT            0
+#define XEMBED_FOCUS_FIRST              1
+#define XEMBED_FOCUS_LAST               2
+
+
+/* Flags for _XEMBED_INFO */
+#define XEMBED_MAPPED                   (1 << 0)
index 0494e1dab20a60d5ad3a3403378100d1d6e01da8..f788ce074615cc32f157a3a0a515c1b8a40c0e20 100644 (file)
@@ -23,6 +23,7 @@
 #include <gtk/gtk.h>
 
 #include "plugin.h"
+#include "utils.h"
 #include "hooks.h"
 #include "folder.h"
 #include "mainwindow.h"
@@ -107,9 +108,9 @@ static gboolean folder_item_update_hook(gpointer source, gpointer data)
 static gboolean click_cb(GtkWidget * widget,
                         GdkEventButton * event, gpointer user_data)
 {
+/*
        MainWindow *mainwin;
 
-/*
        mainwin = mainwindow_get_mainwindow();
        if (GTK_WIDGET_VISIBLE(GTK_WIDGET(mainwin->window))) {
                gtk_widget_hide_all(mainwin->window);
@@ -125,18 +126,22 @@ static void resize_cb(GtkWidget *widget, GtkAllocation *allocation)
        update();
 }
 
-int plugin_init(gchar **error)
+static void create_trayicon(void);
+
+static void destroy_cb(GtkWidget *widget, gpointer *data)
 {
-       GtkPacker *packer;
+       debug_print("Widget destroyed\n");
 
-       hook_id = hooks_register_hook (FOLDER_ITEM_UPDATE_HOOKLIST, folder_item_update_hook, NULL);
-       if (hook_id == -1) {
-               *error = g_strdup("Failed to register folder item update hook");
-               return -1;
-       }
+       create_trayicon();
+}
+
+static void create_trayicon()
+{
+       GtkPacker *packer;
 
         trayicon = egg_tray_icon_new("Sylpheed-Claws");
-/*        trayicon = gtk_window_new(GTK_WINDOW_TOPLEVEL); */
+//        trayicon = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+       gtk_widget_realize(GTK_WIDGET(trayicon));
        gtk_window_set_default_size(GTK_WINDOW(trayicon), 16, 16);
         gtk_container_set_border_width(GTK_CONTAINER(trayicon), 0);
 
@@ -155,8 +160,12 @@ int plugin_init(gchar **error)
         image = gtk_pixmap_new(nomail_pixmap, nomail_bitmap);
         gtk_packer_add_defaults(GTK_PACKER(packer), GTK_WIDGET(image), GTK_SIDE_TOP, GTK_ANCHOR_CENTER, GTK_PACK_EXPAND);
 
-       gtk_signal_connect(GTK_OBJECT(trayicon), "size_allocate", GTK_SIGNAL_FUNC(resize_cb), NULL);
-        gtk_signal_connect(GTK_OBJECT(eventbox), "button-press-event", GTK_SIGNAL_FUNC(click_cb), NULL);
+       gtk_signal_connect(GTK_OBJECT(trayicon), "destroy",
+                     GTK_SIGNAL_FUNC(destroy_cb), NULL);
+       gtk_signal_connect(GTK_OBJECT(trayicon), "size_allocate",
+                   GTK_SIGNAL_FUNC(resize_cb), NULL);
+       gtk_signal_connect(GTK_OBJECT(eventbox), "button-press-event",
+                   GTK_SIGNAL_FUNC(click_cb), NULL);
 
         tooltips = gtk_tooltips_new();
         gtk_tooltips_set_delay(tooltips, 1000);
@@ -165,6 +174,17 @@ int plugin_init(gchar **error)
         gtk_widget_show_all(GTK_WIDGET(trayicon));
 
        update();
+}
+
+int plugin_init(gchar **error)
+{
+       hook_id = hooks_register_hook (FOLDER_ITEM_UPDATE_HOOKLIST, folder_item_update_hook, NULL);
+       if (hook_id == -1) {
+               *error = g_strdup("Failed to register folder item update hook");
+               return -1;
+       }
+
+       create_trayicon();
 
         return 0;
 }