static void
wnck_action_menu_dispose (GObject *object)
{
  WnckActionMenu *menu;

  menu = WNCK_ACTION_MENU (object);

  if (menu->priv->idle_handler)
    {
      g_source_remove (menu->priv->idle_handler);
      menu->priv->idle_handler = 0;
    }

  if (WNCK_IS_WINDOW (menu->priv->window))
    {
      g_object_weak_unref (G_OBJECT (menu->priv->window), window_weak_notify, menu);
      g_signal_handlers_disconnect_by_data (menu->priv->window, menu);

      WnckScreen *screen = wnck_window_get_screen (menu->priv->window);
      g_signal_handlers_disconnect_by_data (screen, menu);

      menu->priv->window = NULL;
    }

  G_OBJECT_CLASS (wnck_action_menu_parent_class)->dispose (object);
}
static void
wnck_action_menu_set_property (GObject      *object,
                               guint         prop_id,
                               const GValue *value,
                               GParamSpec   *pspec)
{
  WnckActionMenu *menu;

  g_return_if_fail (WNCK_IS_ACTION_MENU (object));

  menu = WNCK_ACTION_MENU (object);

  switch (prop_id)
    {
      case PROP_WINDOW:
        g_return_if_fail (WNCK_IS_WINDOW (g_value_get_pointer (value)));

        menu->priv->window = g_value_get_pointer (value);
        g_object_notify (G_OBJECT (menu), "window");
        break;
      default:
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
        break;
    }
}
static void
screen_workspace_callback (WnckWindow    *window,
                           WnckWorkspace *space,
                           gpointer       data)
{
  queue_update (WNCK_ACTION_MENU (data));
}
static void
window_weak_notify (gpointer data,
                    GObject *window)
{
  WNCK_ACTION_MENU(data)->priv->window = NULL;
  gtk_widget_destroy (GTK_WIDGET (data));
}
static void
actions_changed_callback (WnckWindow       *window,
                          WnckWindowActions changed_mask,
                          WnckWindowActions new_actions,
                          gpointer          data)
{
  queue_update (WNCK_ACTION_MENU (data));
}
static void
state_changed_callback (WnckWindow     *window,
                        WnckWindowState changed_mask,
                        WnckWindowState new_state,
                        gpointer        data)
{
  queue_update (WNCK_ACTION_MENU (data));
}
static void
wnck_action_menu_finalize (GObject *object)
{
  WnckActionMenu *menu;

  menu = WNCK_ACTION_MENU (object);

  if (menu->priv->idle_handler)
    g_source_remove (menu->priv->idle_handler);
  menu->priv->idle_handler = 0;

  G_OBJECT_CLASS (wnck_action_menu_parent_class)->finalize (object);
}
static WnckActionMenu*
get_action_menu (GtkWidget *widget)
{
  while (widget) {
    if (GTK_IS_MENU_ITEM (widget))
      widget = widget->parent;

    if (WNCK_IS_ACTION_MENU (widget))
      return WNCK_ACTION_MENU (widget);

    widget = gtk_menu_get_attach_widget (GTK_MENU (widget));
    if (widget == NULL)
      break;
  }

  return NULL;
}
static void
viewports_changed_callback (WnckWindow *window,
                            gpointer    data)
{
  queue_update (WNCK_ACTION_MENU (data));
}
static void
workspace_changed_callback (WnckWindow *window,
                            gpointer    data)
{
  queue_update (WNCK_ACTION_MENU (data));
}
static GObject *
wnck_action_menu_constructor (GType                  type,
                              guint                  n_construct_properties,
                              GObjectConstructParam *construct_properties)
{
  GObject               *obj;
  WnckActionMenu        *menu;
  WnckActionMenuPrivate *priv;
  GtkWidget             *submenu;
  GtkWidget             *separator;
  GSList                *pin_group;
  WnckScreen            *screen;


  obj = G_OBJECT_CLASS (wnck_action_menu_parent_class)->constructor (type,
                                                                     n_construct_properties,
                                                                     construct_properties);

  menu = WNCK_ACTION_MENU (obj);
  priv = menu->priv;

  if (priv->window == NULL)
    {
      g_warning ("No window specified during creation of the action menu");
      return obj;
    }

  g_object_weak_ref (G_OBJECT (priv->window), window_weak_notify, menu);
  g_object_weak_ref (G_OBJECT (menu), object_weak_notify, priv->window);

  priv->minimize_item = make_menu_item (MINIMIZE);

  gtk_menu_shell_append (GTK_MENU_SHELL (menu),
                         priv->minimize_item);

  priv->maximize_item = make_menu_item (MAXIMIZE);

  gtk_menu_shell_append (GTK_MENU_SHELL (menu),
                         priv->maximize_item);

  priv->move_item = make_menu_item (MOVE);
  gtk_menu_shell_append (GTK_MENU_SHELL (menu),
                         priv->move_item);

  set_item_text (priv->move_item, _("_Move"));
  set_item_stock (priv->move_item, NULL);

  priv->resize_item = make_menu_item (RESIZE);
  gtk_menu_shell_append (GTK_MENU_SHELL (menu),
                         priv->resize_item);

  set_item_text (priv->resize_item, _("_Resize"));
  set_item_stock (priv->move_item, NULL);

  priv->workspace_separator = separator = gtk_separator_menu_item_new ();
  gtk_widget_show (separator);
  gtk_menu_shell_append (GTK_MENU_SHELL (menu),
                         separator);

  priv->above_item = make_check_menu_item (ABOVE,
                                          _("Always On _Top"));

  gtk_menu_shell_append (GTK_MENU_SHELL (menu),
                         priv->above_item);

  pin_group = NULL;

  priv->pin_item = make_radio_menu_item (PIN, &pin_group,
                                        _("_Always on Visible Workspace"));
  gtk_menu_shell_append (GTK_MENU_SHELL (menu),
                         priv->pin_item);

  priv->unpin_item = make_radio_menu_item (UNPIN, &pin_group,
                                          _("_Only on This Workspace"));
  gtk_menu_shell_append (GTK_MENU_SHELL (menu),
                         priv->unpin_item);

  priv->left_item = make_menu_item (LEFT);
  gtk_menu_shell_append (GTK_MENU_SHELL (menu),
                         priv->left_item);
  set_item_text (priv->left_item, _("Move to Workspace _Left"));
  set_item_stock (priv->left_item, NULL);

  priv->right_item = make_menu_item (RIGHT);
  gtk_menu_shell_append (GTK_MENU_SHELL (menu),
                         priv->right_item);
  set_item_text (priv->right_item, _("Move to Workspace R_ight"));
  set_item_stock (priv->right_item, NULL);

  priv->up_item = make_menu_item (UP);
  gtk_menu_shell_append (GTK_MENU_SHELL (menu),
                         priv->up_item);
  set_item_text (priv->up_item, _("Move to Workspace _Up"));
  set_item_stock (priv->up_item, NULL);

  priv->down_item = make_menu_item (DOWN);
  gtk_menu_shell_append (GTK_MENU_SHELL (menu),
                         priv->down_item);
  set_item_text (priv->down_item, _("Move to Workspace _Down"));
  set_item_stock (priv->down_item, NULL);

  priv->workspace_item = gtk_menu_item_new_with_mnemonic (_("Move to Another _Workspace"));
  gtk_widget_show (priv->workspace_item);

  submenu = gtk_menu_new ();
  gtk_menu_item_set_submenu (GTK_MENU_ITEM (priv->workspace_item),
                             submenu);

  gtk_menu_shell_append (GTK_MENU_SHELL (menu),
                         priv->workspace_item);

  separator = gtk_separator_menu_item_new ();
  gtk_widget_show (separator);
  gtk_menu_shell_append (GTK_MENU_SHELL (menu),
                         separator);

  priv->close_item = make_menu_item (CLOSE);

  gtk_menu_shell_append (GTK_MENU_SHELL (menu),
                         priv->close_item);

  set_item_text (priv->close_item, _("_Close"));
  set_item_stock (priv->close_item, WNCK_STOCK_DELETE);

  g_signal_connect_object (G_OBJECT (priv->window),
                           "state_changed",
                           G_CALLBACK (state_changed_callback),
                           G_OBJECT (menu),
                           0);

  g_signal_connect_object (G_OBJECT (priv->window),
                           "actions_changed",
                           G_CALLBACK (actions_changed_callback),
                           G_OBJECT (menu),
                           0);

  g_signal_connect_object (G_OBJECT (priv->window),
                           "workspace_changed",
                           G_CALLBACK (workspace_changed_callback),
                           G_OBJECT (menu),
                           0);

  screen = wnck_window_get_screen (priv->window);

  g_signal_connect_object (G_OBJECT (screen),
                           "workspace_created",
                           G_CALLBACK (screen_workspace_callback),
                           G_OBJECT (menu),
                           0);

  g_signal_connect_object (G_OBJECT (screen),
                           "workspace_destroyed",
                           G_CALLBACK (screen_workspace_callback),
                           G_OBJECT (menu),
                           0);

  g_signal_connect_object (G_OBJECT (screen),
                           "viewports_changed",
                           G_CALLBACK (viewports_changed_callback),
                           G_OBJECT (menu),
                           0);

  update_menu_state (menu);

  return obj;
}