Commits

Michele Bini committed d3d02ff

Convert and connect menu callback data to extra_gc_roots, and consequently remove special GC hook.

  • Participants
  • Parent commits c532008

Comments (0)

Files changed (5)

   GC_PHASE_MARK_TERMINALS,
   GC_PHASE_MARK_KBOARDS,
   GC_PHASE_MARK_TTYS,
-#ifdef USE_GTK
-  GC_PHASE_MARK_GTK,
-#endif
   GC_PHASE_MARK_EXTRAROOTS
 };
 
   mark_kboards ();
   mark_ttys ();
 
-#ifdef USE_GTK
-  {
-    extern void xg_mark_data (void);
-    xg_mark_data ();
-  }
-#endif
-
 #if (GC_MARK_STACK == GC_MAKE_GCPROS_NOOPS \
      || GC_MARK_STACK == GC_MARK_STACK_CHECK_GCPROS)
   mark_stack ();

File src/gtkutil.c

     gdk_window_set_cursor (GDK_WINDOW (children->data), cursor);
 }
 
-/* Insert NODE into linked LIST.  */
-
-static void
-xg_list_insert (xg_list_node *list, xg_list_node *node)
-{
-  xg_list_node *list_start = list->next;
-
-  if (list_start) list_start->prev = node;
-  node->next = list_start;
-  node->prev = 0;
-  list->next = node;
-}
-
-/* Remove NODE from linked LIST.  */
-
-static void
-xg_list_remove (xg_list_node *list, xg_list_node *node)
-{
-  xg_list_node *list_start = list->next;
-  if (node == list_start)
-    {
-      list->next = node->next;
-      if (list->next) list->next->prev = 0;
-    }
-  else
-    {
-      node->prev->next = node->next;
-      if (node->next) node->next->prev = node->prev;
-    }
-}
-
 /* Allocate and return a utf8 version of STR.  If STR is already
    utf8 or NULL, just return a copy of STR.
    A new string is allocated and the caller must free the result
 #define MENU_ITEM_NAME "emacs-menuitem"
 
 
-/* Linked list of all allocated struct xg_menu_cb_data.  Used for marking
-   during GC.  The next member points to the items.  */
-static xg_list_node xg_menu_cb_list;
+/* List of all allocated struct xg_menu_cb_data.  Used for marking
+   during GC.  */
+DECLARE_GC_ROOT(xg_menu_cb_list);
 
-/* Linked list of all allocated struct xg_menu_item_cb_data.  Used for marking
-   during GC.  The next member points to the items.  */
-static xg_list_node xg_menu_item_cb_list;
+/* List of all allocated struct xg_menu_item_cb_data.  Used for marking
+   during GC. */
+DECLARE_GC_ROOT(xg_menu_item_cb_list);
 
 /* Allocate and initialize CL_DATA if NULL, otherwise increase ref_count.
    F is the frame CL_DATA will be initialized for.
    Returns CL_DATA if CL_DATA is not NULL,  or a pointer to a newly
    allocated xg_menu_cb_data if CL_DATA is NULL.  */
 
-static xg_menu_cb_data *
-make_cl_data (xg_menu_cb_data *cl_data, FRAME_PTR f, GCallback highlight_cb)
+Lisp_Object
+make_cl_data (Lisp_Object cl_data_lisp, FRAME_PTR f, GCallback highlight_cb)
 {
-  if (! cl_data)
-    {
-      cl_data = (xg_menu_cb_data*) xmalloc (sizeof (*cl_data));
-      cl_data->f = f;
-      cl_data->menu_bar_vector = f->menu_bar_vector;
-      cl_data->menu_bar_items_used = f->menu_bar_items_used;
-      cl_data->highlight_cb = highlight_cb;
-      cl_data->ref_count = 0;
-
-      xg_list_insert (&xg_menu_cb_list, &cl_data->ptrs);
-    }
-
-  cl_data->ref_count++;
-
-  return cl_data;
+  if (!NILP(cl_data_lisp)) {
+    xg_menu_cb_data *cl_data = XMENUCBDATA(cl_data_lisp);
+    cl_data->ref_count++;
+  } else {
+    xg_menu_cb_data *cl_data = ALLOCATE_MENUCBDATA();
+    cl_data->f = f;
+    cl_data->menu_bar_items_used = f->menu_bar_items_used;
+    cl_data->highlight_cb = highlight_cb;
+    cl_data->ref_count = 1;
+
+    XSETMENUCBDATA(cl_data_lisp, cl_data);
+    XSETMENUBARVECTOR(cl_data_lisp, f->menu_bar_vector);
+    SET_GC_ROOT(xg_menu_cb_list,
+		Fcons(cl_data_lisp,
+		      GET_GC_ROOT(xg_menu_cb_list)));
+  }
+  return cl_data_lisp;
 }
 
 /* Update CL_DATA with values from frame F and with HIGHLIGHT_CB.
    creating the menu bar.  */
 
 static void
-update_cl_data (xg_menu_cb_data *cl_data,
+update_cl_data (Lisp_Object cl_data_lisp,
                 FRAME_PTR f,
                 GCallback highlight_cb)
 {
-  if (cl_data)
+  xg_menu_cb_data *cl_data = XMENUCBDATA(cl_data_lisp);
+  if (cl_data != NULL)
     {
       cl_data->f = f;
-      cl_data->menu_bar_vector = f->menu_bar_vector;
+      XSETMENUBARVECTOR(cl_data_lisp, f->menu_bar_vector);
       cl_data->menu_bar_items_used = f->menu_bar_items_used;
       cl_data->highlight_cb = highlight_cb;
     }
    If reference count is zero, free CL_DATA.  */
 
 static void
-unref_cl_data (xg_menu_cb_data *cl_data)
+unref_cl_data (Lisp_Object cl_data_lisp)
 {
+  xg_menu_cb_data *cl_data = XMENUCBDATA(cl_data_lisp);
+
   if (cl_data && cl_data->ref_count > 0)
     {
       cl_data->ref_count--;
       if (cl_data->ref_count == 0)
         {
-          xg_list_remove (&xg_menu_cb_list, &cl_data->ptrs);
-          xfree (cl_data);
+	  SET_GC_ROOT(xg_menu_cb_list,
+		      Fdelq(cl_data_lisp,
+			    GET_GC_ROOT(xg_menu_cb_list)));
         }
     }
 }
 
-/* Function that marks all lisp data during GC.  */
-
-void
-xg_mark_data (void)
-{
-  xg_list_node *iter;
-
-  for (iter = xg_menu_cb_list.next; iter; iter = iter->next)
-    mark_object (((xg_menu_cb_data *) iter)->menu_bar_vector);
-
-  for (iter = xg_menu_item_cb_list.next; iter; iter = iter->next)
-    {
-      xg_menu_item_cb_data *cb_data = (xg_menu_item_cb_data *) iter;
-
-      if (! NILP (cb_data->help))
-        mark_object (cb_data->help);
-    }
-}
-
-
 /* Callback called when a menu item is destroyed.  Used to free data.
    W is the widget that is being destroyed (not used).
    CLIENT_DATA points to the xg_menu_item_cb_data associated with the W.  */
 static void
 menuitem_destroy_callback (GtkWidget *w, gpointer client_data)
 {
-  if (client_data)
+  Lisp_Object data = (Lisp_Object)(int)client_data;
+  if (!NILP(data))
     {
-      xg_menu_item_cb_data *data = (xg_menu_item_cb_data*) client_data;
-      xg_list_remove (&xg_menu_item_cb_list, &data->ptrs);
-      xfree (data);
+      SET_GC_ROOT(xg_menu_item_cb_list,
+		  Fdelq(data,
+			GET_GC_ROOT(xg_menu_item_cb_list)));
     }
 }
 
 {
   GdkEvent ev;
   GtkWidget *subwidget;
+  Lisp_Object data_lisp;
   xg_menu_item_cb_data *data;
 
   ev.crossing = *event;
   subwidget = gtk_get_event_widget (&ev);
-  data = (xg_menu_item_cb_data *) g_object_get_data (G_OBJECT (subwidget),
-                                                     XG_ITEM_DATA);
+  data_lisp =
+    (Lisp_Object)(int)
+    g_object_get_data (G_OBJECT (subwidget),
+		       XG_ITEM_DATA);
+  data = XMENUITEMCBDATA(data_lisp);
   if (data)
     {
-      if (! NILP (data->help) && data->cl_data->highlight_cb)
+      xg_menu_cb_data *menucbdata;
+      if (! NILP(XMENUITEMHELP(data_lisp)) &&
+	  (menucbdata =
+	   XMENUCBDATA(XMENUITEMMENU(data_lisp)))->highlight_cb)
         {
           gpointer call_data = event->type == GDK_LEAVE_NOTIFY ? 0 : data;
-          GtkCallback func = (GtkCallback) data->cl_data->highlight_cb;
+          GtkCallback func = (GtkCallback) menucbdata->highlight_cb;
           (*func) (subwidget, call_data);
         }
     }
 static void
 menu_destroy_callback (GtkWidget *w, gpointer client_data)
 {
-  unref_cl_data ((xg_menu_cb_data*) client_data);
+  unref_cl_data ((Lisp_Object)(int)client_data);
 }
 
 /* Make a GTK widget that contains both UTF8_LABEL and UTF8_KEY (both
                         FRAME_PTR f,
                         GCallback select_cb,
                         GCallback highlight_cb,
-                        xg_menu_cb_data *cl_data,
+                        Lisp_Object cl_data_lisp,
                         GSList **group)
 {
   char *utf8_label;
   char *utf8_key;
   GtkWidget *w;
+  Lisp_Object cb_data_lisp;
   xg_menu_item_cb_data *cb_data;
 
   utf8_label = get_utf8_string (item->name);
   if (utf8_label) g_free (utf8_label);
   if (utf8_key) g_free (utf8_key);
 
-  cb_data = xmalloc (sizeof (xg_menu_item_cb_data));
-
-  xg_list_insert (&xg_menu_item_cb_list, &cb_data->ptrs);
+  cb_data = ALLOCATE_MENUITEMCBDATA();
 
   cb_data->select_id = 0;
-  cb_data->help = item->help;
-  cb_data->cl_data = cl_data;
+  XSETMENUITEMCBDATA(cb_data_lisp, cb_data);
+  XSETMENUITEMHELP(cb_data_lisp, item->help);
+  XSETMENUITEMMENU(cb_data_lisp, cl_data_lisp);
   cb_data->call_data = item->call_data;
 
+  XSETMENUITEMCBDATA(cb_data_lisp, cb_data);
+
+  SET_GC_ROOT(xg_menu_item_cb_list,
+	      Fcons(cb_data_lisp,
+		    GET_GC_ROOT(xg_menu_item_cb_list)));
+
   g_signal_connect (G_OBJECT (w),
                     "destroy",
                     G_CALLBACK (menuitem_destroy_callback),
-                    cb_data);
+                    (void*)(int)cb_data_lisp);
 
   /* Put cb_data in widget, so we can get at it when modifying menubar  */
-  g_object_set_data (G_OBJECT (w), XG_ITEM_DATA, cb_data);
+  g_object_set_data (G_OBJECT (w), XG_ITEM_DATA, (void*)(int)cb_data_lisp);
 
   /* final item, not a submenu  */
   if (item->call_data && ! item->contents)
     {
       if (select_cb)
         cb_data->select_id
-          = g_signal_connect (G_OBJECT (w), "activate", select_cb, cb_data);
+          = g_signal_connect (G_OBJECT (w), "activate", select_cb,
+			      (void*)(int)cb_data_lisp);
     }
 
   return w;
               int menu_bar_p,
               int add_tearoff_p,
               GtkWidget *topmenu,
-              xg_menu_cb_data *cl_data,
+              Lisp_Object cl_data_lisp,
               const char *name)
 {
   widget_value *item;
         }
 
       /* Put cl_data on the top menu for easier access.  */
-      cl_data = make_cl_data (cl_data, f, highlight_cb);
-      g_object_set_data (G_OBJECT (wmenu), XG_FRAME_DATA, (gpointer)cl_data);
+      cl_data_lisp = make_cl_data (cl_data_lisp, f, highlight_cb);
+      g_object_set_data (G_OBJECT (wmenu), XG_FRAME_DATA, (gpointer)(int)cl_data_lisp);
       g_signal_connect (G_OBJECT (wmenu), "destroy",
-                        G_CALLBACK (menu_destroy_callback), cl_data);
+                        G_CALLBACK (menu_destroy_callback), (gpointer)(int)cl_data_lisp);
 
       if (name)
         gtk_widget_set_name (wmenu, name);
                                       f,
                                       item->contents ? 0 : select_cb,
                                       highlight_cb,
-                                      cl_data,
+                                      cl_data_lisp,
                                       &group);
 
           /* Create a possibly empty submenu for menu bar items, since some
                                                  0,
                                                  add_tearoff_p,
                                                  0,
-                                                 cl_data,
+                                                 cl_data_lisp,
                                                  0);
               gtk_menu_item_set_submenu (GTK_MENU_ITEM (w), submenu);
             }
                         menu_bar_p,
                         menu_bar_p,
                         0,
-                        0,
+                        Qnil,
                         name);
 
       /* Set the cursor to an arrow for popup menus when they are mapped.
 		   GCallback select_cb,
 		   GCallback deactivate_cb,
 		   GCallback highlight_cb,
-		   xg_menu_cb_data *cl_data)
+		   Lisp_Object cl_data_lisp)
 {
   if (! iter && ! val)
     return;
     {
       /* Item(s) added.  Add all new items in one call.  */
       create_menus (val, f, select_cb, deactivate_cb, highlight_cb,
-                    0, 1, 0, menubar, cl_data, 0);
+                    0, 1, 0, menubar, cl_data_lisp, 0);
 
       /* All updated.  */
       val = 0;
                                                  f,
                                                  select_cb,
                                                  highlight_cb,
-                                                 cl_data,
+                                                 cl_data_lisp,
                                                  &group);
 
           /* Create a possibly empty submenu for menu bar items, since some
           GtkWidget *submenu = create_menus (NULL, f,
                                              select_cb, deactivate_cb,
                                              highlight_cb,
-                                             0, 0, 0, 0, cl_data, 0);
+                                             0, 0, 0, 0, cl_data_lisp, 0);
           gtk_widget_set_name (w, MENU_ITEM_NAME);
           gtk_menu_shell_insert (GTK_MENU_SHELL (menubar), w, pos);
           gtk_menu_item_set_submenu (GTK_MENU_ITEM (w), submenu);
 
   /* Update the rest of the menu bar.  */
   xg_update_menubar (menubar, f, list, iter, pos, val,
-                     select_cb, deactivate_cb, highlight_cb, cl_data);
+                     select_cb, deactivate_cb, highlight_cb, cl_data_lisp);
 }
 
 /* Update the menu item W so it corresponds to VAL.
                      GtkWidget *w,
                      GCallback select_cb,
                      GCallback highlight_cb,
-                     xg_menu_cb_data *cl_data)
+                     Lisp_Object cl_data_lisp)
 {
   GtkWidget *wchild;
   GtkLabel *wlbl = 0;
   char *utf8_key;
   const char *old_label = 0;
   const char *old_key = 0;
+  Lisp_Object cb_data_lisp;
   xg_menu_item_cb_data *cb_data;
 
   wchild = XG_BIN_CHILD (w);
   else if (val->enabled && ! gtk_widget_get_sensitive (w))
     gtk_widget_set_sensitive (w, TRUE);
 
-  cb_data = (xg_menu_item_cb_data*) g_object_get_data (G_OBJECT (w),
-                                                       XG_ITEM_DATA);
+  cb_data_lisp =
+    (Lisp_Object)(int)
+    g_object_get_data (G_OBJECT (w),
+		       XG_ITEM_DATA);
+  cb_data = cb_data_lisp ? XMENUITEMCBDATA(cb_data_lisp) : NULL;
   if (cb_data)
     {
       cb_data->call_data = val->call_data;
-      cb_data->help = val->help;
-      cb_data->cl_data = cl_data;
+      XSETMENUITEMHELP(cb_data_lisp, val->help);
+      XSETMENUITEMMENU(cb_data_lisp, cl_data_lisp);
 
       /* We assume the callback functions don't change.  */
       if (val->call_data && ! val->contents)
 		   GCallback select_cb,
 		   GCallback deactivate_cb,
 		   GCallback highlight_cb,
-		   xg_menu_cb_data *cl_data)
+		   Lisp_Object cl_data_lisp)
 {
   GtkWidget *newsub = submenu;
   GList *list = 0;
         if (cur->button_type != BUTTON_TYPE_TOGGLE)
           break;
         xg_update_toggle_item (cur, w);
-        xg_update_menu_item (cur, w, select_cb, highlight_cb, cl_data);
+        xg_update_menu_item (cur, w, select_cb, highlight_cb, cl_data_lisp);
       }
     else if (GTK_IS_RADIO_MENU_ITEM (w))
       {
         if (cur->button_type != BUTTON_TYPE_RADIO)
           break;
         xg_update_radio_item (cur, w);
-        xg_update_menu_item (cur, w, select_cb, highlight_cb, cl_data);
+        xg_update_menu_item (cur, w, select_cb, highlight_cb, cl_data_lisp);
       }
     else if (GTK_IS_MENU_ITEM (w))
       {
             menu_separator_name_p (cur->name))
           break;
 
-        xg_update_menu_item (cur, w, select_cb, highlight_cb, cl_data);
+        xg_update_menu_item (cur, w, select_cb, highlight_cb, cl_data_lisp);
 
         sub = gtk_menu_item_get_submenu (witem);
         if (sub && ! cur->contents)
 
             nsub = xg_update_submenu (sub, f, cur->contents,
                                       select_cb, deactivate_cb,
-                                      highlight_cb, cl_data);
+                                      highlight_cb, cl_data_lisp);
 
             /* If this item just became a submenu, we must set it.  */
             if (nsub != sub)
                              0,
                              ! has_tearoff_p,
                              submenu,
-                             cl_data,
+                             cl_data_lisp,
                              0);
     }
 
                            GCallback select_cb, GCallback deactivate_cb,
 			   GCallback highlight_cb)
 {
-  xg_menu_cb_data *cl_data;
+  Lisp_Object cl_data_lisp;
   GList *list = gtk_container_get_children (GTK_CONTAINER (menubar));
 
   if (! list) return;
 
-  cl_data = (xg_menu_cb_data*) g_object_get_data (G_OBJECT (menubar),
-                                                  XG_FRAME_DATA);
+  cl_data_lisp =
+    (Lisp_Object)(int)
+    g_object_get_data (G_OBJECT (menubar),
+		       XG_FRAME_DATA);
 
   xg_update_menubar (menubar, f, &list, list, 0, val->contents,
-                     select_cb, deactivate_cb, highlight_cb, cl_data);
+                     select_cb, deactivate_cb, highlight_cb, cl_data_lisp);
 
   if (deep_p)
     {
          X Window in the XEvent that activates the menu are those widgets.  */
 
       /* Update cl_data, menu_item things in F may have changed.  */
-      update_cl_data (cl_data, f, highlight_cb);
+      update_cl_data (cl_data_lisp, f, highlight_cb);
 
       for (cur = val->contents; cur; cur = cur->next)
         {
                                       select_cb,
                                       deactivate_cb,
                                       highlight_cb,
-                                      cl_data);
+                                      cl_data_lisp);
           /* sub may still be NULL.  If we just updated non deep and added
              a new menu bar item, it has no sub menu yet.  So we set the
              newly created sub menu under witem.  */
   gdpy_def = NULL;
   xg_ignore_gtk_scrollbar = 0;
   xg_detached_menus = 0;
-  xg_menu_cb_list.prev = xg_menu_cb_list.next =
-    xg_menu_item_cb_list.prev = xg_menu_item_cb_list.next = 0;
+  INSTALL_GC_ROOT(xg_menu_cb_list,       Qnil);
+  INSTALL_GC_ROOT(xg_menu_item_cb_list,  Qnil);
 
   id_to_widget.max_size = id_to_widget.used = 0;
   id_to_widget.widgets = 0;

File src/gtkutil.h

 /* Key for data that menu items hold.  */
 #define XG_ITEM_DATA "emacs_menuitem"
 
-/* This is a list node in a generic list implementation.  */
-typedef struct xg_list_node_
-{
-  struct xg_list_node_ *prev;
-  struct xg_list_node_ *next;
-} xg_list_node;
-
 /* This structure is the callback data that is shared for menu items.
    We need to keep it separate from the frame structure due to
    detachable menus.  The data in the frame structure is only valid while
    the menu is.  */
 typedef struct xg_menu_cb_data_
 {
-  xg_list_node  ptrs;
+  struct vectorlike_header header;
+#define XMENUCBDATA(a) ((xg_menu_cb_data *)XPNTR_OR_NULL(a))
+#define XSETMENUCBDATA(a, b) XSETPSEUDOVECTOR(a, b, PVEC_OTHER)
+
+  Lisp_Object   ___menu_bar_vector;
+#define XMENUBARVECTOR(cbdata) AREF(cbdata, 0)
+#define XSETMENUBARVECTOR(cbdata, x) ASET(cbdata, 0, x)
 
+#define ALLOCATE_MENUCBDATA()				\
+  ALLOCATE_PSEUDOVECTOR(xg_menu_cb_data,		\
+			f, PVEC_OTHER)
   FRAME_PTR     f;
-  Lisp_Object   menu_bar_vector;
   int           menu_bar_items_used;
   GCallback     highlight_cb;
   int           ref_count;
 /* This structure holds callback information for each individual menu item.  */
 typedef struct xg_menu_item_cb_data_
 {
-  xg_list_node  ptrs;
-
+  struct vectorlike_header header;
+#define XMENUITEMCBDATA(a) ((xg_menu_item_cb_data *)XPNTR_OR_NULL(a))
+#define XSETMENUITEMCBDATA(a, b) XSETPSEUDOVECTOR(a, b, PVEC_OTHER)
+
+  Lisp_Object   ___help;
+#define XMENUITEMHELP(cbdata) AREF(cbdata, 0)
+#define XSETMENUITEMHELP(cbdata, x) ASET(cbdata, 0, x)
+  Lisp_Object   ___menu;
+#define XMENUITEMMENU(cbdata) AREF(cbdata, 1)
+#define XSETMENUITEMMENU(cbdata, x) ASET(cbdata, 1, x)
+
+#define ALLOCATE_MENUITEMCBDATA()			\
+  ALLOCATE_PSEUDOVECTOR(xg_menu_item_cb_data,		\
+			select_id, PVEC_OTHER)
   gulong        select_id;
-  Lisp_Object   help;
   gpointer	call_data;
-  xg_menu_cb_data *cl_data;
-
 } xg_menu_item_cb_data;
 
-
 #ifdef HAVE_GTK_FILE_SELECTION_NEW
 extern int use_old_gtk_file_dialog;
 #endif
 
 #endif /* USE_LISP_UNION_TYPE */
 
+#define XPNTR_OR_NULL(a) (xpntr_or_null((a)))
+				  
+
 /* For integers known to be positive, XFASTINT sometimes provides
    faster retrieval and XSETFASTINT provides faster storage.
    If not, fallback on the non-accelerated path.  */
   } while (0)
 
 
+static inline void* xpntr_or_null(Lisp_Object a) {
+  if (NILP(a)) {
+    return NULL;
+  } else {
+    return (void*)XPNTR(a);
+  }
+}
+
 #include "globals.h"
 
 #endif /* EMACS_LISP_H */
 static void
 menu_highlight_callback (GtkWidget *widget, gpointer call_data)
 {
+  Lisp_Object cb_data_lisp;
   xg_menu_item_cb_data *cb_data;
   Lisp_Object help;
 
-  cb_data = (xg_menu_item_cb_data*) g_object_get_data (G_OBJECT (widget),
-                                                       XG_ITEM_DATA);
-  if (! cb_data) return;
+  cb_data_lisp =
+    (Lisp_Object)(int)
+    g_object_get_data (G_OBJECT (widget),
+		       XG_ITEM_DATA);
+  if (! cb_data_lisp) return;
 
-  help = call_data ? cb_data->help : Qnil;
+  help = call_data ? XMENUITEMHELP(cb_data_lisp) : Qnil;
 
   /* If popup_activated_flag is greater than 1 we are in a popup menu.
      Don't pass the frame to show_help_event for those.
      popup_widget_loop, it won't be handled.  Passing NULL shows the tip
      directly without using an Emacs event.  This is what the Lucid code
      does below.  */
-  show_help_event (popup_activated_flag <= 1 ? cb_data->cl_data->f : NULL,
+  cb_data_lisp = XMENUITEMMENU(cb_data_lisp);
+  if (NILP(cb_data_lisp)) return;
+  show_help_event (popup_activated_flag <= 1 ? XMENUCBDATA(cb_data_lisp)->f : 0,
                    widget, help);
 }
 #else
 static void
 menubar_selection_callback (GtkWidget *widget, gpointer client_data)
 {
-  xg_menu_item_cb_data *cb_data = (xg_menu_item_cb_data*) client_data;
+  Lisp_Object cb_data_lisp;
+  xg_menu_item_cb_data *cb_data;
+
+  Lisp_Object menucbdata_lisp;
+  xg_menu_cb_data *menucbdata;
+
+  if (!client_data)
+    return;
 
   if (xg_crazy_callback_abort)
     return;
 
-  if (! cb_data || ! cb_data->cl_data || ! cb_data->cl_data->f)
+  cb_data_lisp = (Lisp_Object)(int)client_data;
+  cb_data = XMENUITEMCBDATA(cb_data_lisp);
+
+  if (! cb_data)
+    return;
+
+  menucbdata_lisp = XMENUITEMMENU(cb_data_lisp);
+  menucbdata = XMENUCBDATA(menucbdata_lisp);
+  if (! menucbdata || ! menucbdata->f)
     return;
 
   /* For a group of radio buttons, GTK calls the selection callback first
     gtk_main_iteration ();
   UNBLOCK_INPUT;
 
-  find_and_call_menu_selection (cb_data->cl_data->f,
-                                cb_data->cl_data->menu_bar_items_used,
-                                cb_data->cl_data->menu_bar_vector,
+  find_and_call_menu_selection (menucbdata->f,
+                                menucbdata->menu_bar_items_used,
+                                XMENUBARVECTOR(menucbdata_lisp),
                                 cb_data->call_data);
 }