Logo Search packages:      
Sourcecode: ladish version File versions  Download package

dynmenu.c

/* -*- Mode: C ; c-basic-offset: 2 -*- */
/*
 * LADI Session Handler (ladish)
 *
 * Copyright (C) 2010 Nedko Arnaudov <nedko@arnaudov.name>
 *
 **************************************************************************
 * This file contains dynamic menu related code
 **************************************************************************
 *
 * LADI Session Handler is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * LADI Session Handler 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with LADI Session Handler. If not, see <http://www.gnu.org/licenses/>
 * or write to the Free Software Foundation, Inc.,
 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include "dynmenu.h"
#include "gtk_builder.h"
#include "../common/catdup.h"

00031 struct ladish_dynmenu
{
  int count;
  GtkWidget * menu_item;
  GtkWidget * menu;
  bool
  (* fill_callback)(
    void
    (* callback)(
      void * context,
      const char * name,
      void * data,
      ladish_dynmenu_item_activate_callback item_activate_callback,
      void (* data_free)()),
    void * context);
  ladish_dynmenu_item_activate_callback item_activate_callback;
  bool add_sensitive;
  gulong activate_signal_id;
  char * description;
};

00052 struct ladish_dynmenu_item_data
{
  GtkWidget * item;
  void * data;
  void (* data_free)();
  ladish_dynmenu_item_activate_callback item_activate_callback;
};

void on_activate_item(GtkMenuItem * item, struct ladish_dynmenu_item_data * data_ptr)
{
  //log_info("on_activate_item('%s')", gtk_label_get_text(GTK_LABEL(gtk_bin_get_child(GTK_BIN(data_ptr->item)))));

  data_ptr->item_activate_callback(
    gtk_label_get_text(GTK_LABEL(gtk_bin_get_child(GTK_BIN(data_ptr->item)))),
    data_ptr->data);
}

#define data_ptr ((struct ladish_dynmenu_item_data *)data)

void free_item_data(gpointer data, GClosure * closure)
{
  //log_info("data_ptr %p deallocate", data_ptr);

  if (data_ptr->data != NULL)
  {
    if (data_ptr->data_free != NULL)
    {
      data_ptr->data_free(data_ptr->data);
    }
    else
    {
      free(data_ptr->data);
    }
  }

  free(data_ptr);
}

#undef data_ptr
#define dynmenu_ptr ((struct ladish_dynmenu *)context)

static
void
ladish_dynmenu_add_entry(
  void * context,
  const char * name,
  void * data,
  ladish_dynmenu_item_activate_callback item_activate_callback,
  void (* data_free)())
{
  struct ladish_dynmenu_item_data * data_ptr;

  data_ptr = malloc(sizeof(struct ladish_dynmenu_item_data));
  //log_info("data_ptr %p allocated", data_ptr);
  data_ptr->data = data;
  data_ptr->data_free = data_free;
  data_ptr->item_activate_callback = item_activate_callback != NULL ? item_activate_callback : dynmenu_ptr->item_activate_callback;

  if (name == NULL)
  {
    data_ptr->item = gtk_separator_menu_item_new(); /* separator */
    gtk_widget_show(data_ptr->item);
    gtk_menu_shell_append(GTK_MENU_SHELL(dynmenu_ptr->menu), data_ptr->item);
  }
  else
  {
    data_ptr->item = gtk_menu_item_new_with_label(name);
    //log_info("refcount == %d", (unsigned int)G_OBJECT(item)->ref_count); // refcount == 2 because of the label
    gtk_widget_set_sensitive(data_ptr->item, dynmenu_ptr->add_sensitive);
    gtk_widget_show(data_ptr->item);
    gtk_menu_shell_append(GTK_MENU_SHELL(dynmenu_ptr->menu), data_ptr->item);
    g_signal_connect_data(
      G_OBJECT(data_ptr->item),
      "activate",
      G_CALLBACK(on_activate_item),
      data_ptr,
      free_item_data,
      (GConnectFlags)0);
  }

  dynmenu_ptr->count++;
}

static void remove_dynmenu_menu_entry(GtkWidget * item, gpointer context)
{
  GtkWidget * label;

  label = gtk_bin_get_child(GTK_BIN(item));

  //log_debug("removing dynmenu item \"%s\"", gtk_menu_item_get_label(GTK_MENU_ITEM(item));
  // gtk_menu_item_get_label() requries gtk 2.16
  log_debug("removing dynmenu item \"%s\"", gtk_label_get_text(GTK_LABEL(label)));

  gtk_container_remove(GTK_CONTAINER(item), label); /* destroy the label and drop the item refcount by one */
  //log_info("refcount == %d", (unsigned int)G_OBJECT(item)->ref_count);
  gtk_container_remove(GTK_CONTAINER(dynmenu_ptr->menu), item); /* drop the refcount of item by one and thus destroy it */
  dynmenu_ptr->count--;
}

#undef dynmenu_ptr

static void menu_dynmenu_clear(struct ladish_dynmenu * dynmenu_ptr)
{
  gtk_container_foreach(GTK_CONTAINER(dynmenu_ptr->menu), remove_dynmenu_menu_entry, dynmenu_ptr);
  ASSERT(dynmenu_ptr->count == 0);
  dynmenu_ptr->count = 0;
}

static void populate_dynmenu_menu(GtkMenuItem * menu_item, struct ladish_dynmenu * dynmenu_ptr)
{
  const char * prefix;
  char * text;

  menu_dynmenu_clear(dynmenu_ptr);
  dynmenu_ptr->add_sensitive = true;
  if (!dynmenu_ptr->fill_callback(ladish_dynmenu_add_entry, dynmenu_ptr))
  {
    menu_dynmenu_clear(dynmenu_ptr);
    prefix = _("Error filling ");
  }
  else if (dynmenu_ptr->count == 0)
  {
    prefix = _("Empty ");
  }
  else
  {
    return;
  }

  text = catdup(prefix, dynmenu_ptr->description);

  dynmenu_ptr->add_sensitive = false;
  ladish_dynmenu_add_entry(dynmenu_ptr, text != NULL ? text : prefix, NULL, NULL, NULL);

  free(text);                   /* free(NULL) is safe */
}

bool
ladish_dynmenu_create(
  const char * menu_item,
  const char * menu,
  bool
  (* fill_callback)(
    void
    (* callback)(
      void * context,
      const char * name,
      void * data,
      ladish_dynmenu_item_activate_callback item_activate_callback,
      void (* data_free)()),
    void * context),
  const char * description,
  ladish_dynmenu_item_activate_callback item_activate_callback,
  ladish_dynmenu_handle * dynmenu_handle_ptr)
{
  struct ladish_dynmenu * dynmenu_ptr;

  dynmenu_ptr = malloc(sizeof(struct ladish_dynmenu));
  if (dynmenu_ptr == NULL)
  {
    log_error("Allocation of ladish_dynmenu struct failed");
    return false;
  }

  dynmenu_ptr->description = strdup(description);
  if (dynmenu_ptr->description == NULL)
  {
    log_error("strdup('%s') failed for dynmenu description string", description);
    free(dynmenu_ptr);
    return false;
  }

  dynmenu_ptr->count = 0;
  dynmenu_ptr->menu_item = get_gtk_builder_widget(menu_item);
  dynmenu_ptr->menu = get_gtk_builder_widget(menu);
  dynmenu_ptr->fill_callback = fill_callback;
  dynmenu_ptr->item_activate_callback = item_activate_callback;
  gtk_menu_item_set_submenu(GTK_MENU_ITEM(dynmenu_ptr->menu_item), dynmenu_ptr->menu);
  dynmenu_ptr->activate_signal_id = g_signal_connect(G_OBJECT(dynmenu_ptr->menu_item), "activate", G_CALLBACK(populate_dynmenu_menu), dynmenu_ptr);

  *dynmenu_handle_ptr = (ladish_dynmenu_handle)dynmenu_ptr;
  return true;
}

#define dynmenu_ptr ((struct ladish_dynmenu *)dynmenu_handle)

void
ladish_dynmenu_fill_external(
  ladish_dynmenu_handle dynmenu_handle,
  GtkMenu * menu)
{
  GtkWidget * menu_backup;
  int count_backup;

  menu_backup = dynmenu_ptr->menu;
  count_backup = dynmenu_ptr->count;

  dynmenu_ptr->menu = GTK_WIDGET(menu);
  dynmenu_ptr->add_sensitive = true;

  dynmenu_ptr->fill_callback(ladish_dynmenu_add_entry, dynmenu_ptr);

  dynmenu_ptr->menu = menu_backup;
  dynmenu_ptr->count = count_backup;
}

void
ladish_dynmenu_destroy(
  ladish_dynmenu_handle dynmenu_handle)
{
  if (g_signal_handler_is_connected(G_OBJECT(dynmenu_ptr->menu_item), dynmenu_ptr->activate_signal_id))
  {
    g_signal_handler_disconnect(G_OBJECT(dynmenu_ptr->menu_item), dynmenu_ptr->activate_signal_id);
  }

  free(dynmenu_ptr);
}

#undef dynmenu_ptr

Generated by  Doxygen 1.6.0   Back to index