/* * Copyright (c) 2003 by the gtk2-perl team (see the file AUTHORS) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2.1 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA. * * $Id$ */ #include "gtk2perl.h" /* ------------------------------------------------------------------------- */ /* * a custom marshaler for the item factory callbacks */ static void gtk2perl_item_factory_item_activate (gpointer data, guint callback_action, GtkWidget * widget) { SV * callback_sv; SV * callback_data; dSP; /* the callback out of the widget */ callback_sv = (SV *) g_object_get_data ( G_OBJECT (widget), "_gtk2perl_item_factory_callback_sv"); callback_data = (SV *) data; ENTER; SAVETMPS; PUSHMARK (SP); /* put the parameters on the stack (we're always type 1) */ EXTEND (SP, 3); PUSHs (sv_2mortal (newSVsv (callback_data ? callback_data : &PL_sv_undef))); PUSHs (sv_2mortal (newSViv (callback_action))); PUSHs (sv_2mortal (newSVGtkWidget (widget))); PUTBACK; /* call the code in sv */ call_sv (callback_sv, G_DISCARD); FREETMPS; LEAVE; } /* ------------------------------------------------------------------------- */ GPerlCallback * gtk2perl_translate_func_create (SV * func, SV * data) { GType param_types[1]; param_types[0] = G_TYPE_STRING; return gperl_callback_new (func, data, G_N_ELEMENTS (param_types), param_types, G_TYPE_STRING); } gchar * gtk2perl_translate_func (const gchar *path, gpointer data) { GPerlCallback * callback = (GPerlCallback*)data; GValue value = {0,}; SV * tempsv = NULL; gchar * retval; g_value_init (&value, callback->return_type); gperl_callback_invoke (callback, &value, path); retval = (gchar *) g_value_get_string (&value); /* g_value_unset() will free the string to which retval points. * we will need to keep a copy; let's use a mortal scalar to keep * it around long enough to be useful to the C callers. */ if (retval) tempsv = sv_2mortal (newSVGChar (retval)); g_value_unset (&value); /* using SvPV rather than SvGChar because we used newSVGChar to create * it above, so we're assured that it's been upgraded to utf8 already. * this avoids uncertainty about whether SvGChar may vivify the mortal * value. (i'm paranoid.) */ return tempsv ? SvPV_nolen (tempsv) : NULL; } /* ------------------------------------------------------------------------- */ #define HV_FETCH_AND_CHECK(_member, _sv) \ if (hv_exists (hv, #_member, strlen (#_member))) { \ value = hv_fetch (hv, #_member, strlen (#_member), FALSE); \ if (value && gperl_sv_is_defined (*value)) \ entry->_member = _sv; \ } #define AV_FETCH_AND_CHECK(_index, _member, _sv) \ value = av_fetch (av, _index, 0); \ if (value && gperl_sv_is_defined (*value)) \ entry->_member = _sv; GtkItemFactoryEntry * SvGtkItemFactoryEntry (SV *data, SV **callback) { GtkItemFactoryEntry *entry = gperl_alloc_temp (sizeof (GtkItemFactoryEntry)); memset (entry, 0, sizeof (GtkItemFactoryEntry)); if (!gperl_sv_is_defined (data)) return entry; /* fail silently if undef */ if (gperl_sv_is_hash_ref (data)) { HV *hv = (HV *) SvRV (data); SV **value; HV_FETCH_AND_CHECK (path, SvGChar (*value)); HV_FETCH_AND_CHECK (accelerator, SvGChar (*value)); if (hv_exists (hv, "callback", 8)) { value = hv_fetch (hv, "callback", 8, FALSE); if (callback && value && gperl_sv_is_defined (*value)) { *callback = *value; entry->callback = gtk2perl_item_factory_item_activate; } } HV_FETCH_AND_CHECK (callback_action, SvIV (*value)); HV_FETCH_AND_CHECK (item_type, SvGChar (*value)); HV_FETCH_AND_CHECK (extra_data, SvPOK (*value) ? SvGChar (*value) : NULL); } else if (gperl_sv_is_array_ref (data)) { AV *av = (AV *) SvRV (data); SV **value; AV_FETCH_AND_CHECK (0, path, SvGChar (*value)); AV_FETCH_AND_CHECK (1, accelerator, SvGChar (*value)); value = av_fetch (av, 2, 0); if (callback && value && gperl_sv_is_defined (*value)) { *callback = *value; entry->callback = gtk2perl_item_factory_item_activate; } AV_FETCH_AND_CHECK (3, callback_action, SvIV (*value)); AV_FETCH_AND_CHECK (4, item_type, SvGChar (*value)); AV_FETCH_AND_CHECK (5, extra_data, SvPOK (*value) ? SvGChar (*value) : NULL); } else { croak ("badly formed GtkItemFactoryEntry; use either list or hash form:\n" " list form:\n" " [ path, accel, callback, action, type ]\n" " hash form:\n" " {\n" " path => $path,\n" " accelerator => $accel, # optional\n" " callback => $callback,\n" " callback_action => $action,\n" " item_type => $type, # optional\n" " extra_data => $extra, # optional\n" " }\n" " "); } return entry; } static void gtk2perl_item_factory_create_item_helper (GtkItemFactory *ifactory, SV *entry_ref, SV *callback_data) { GtkItemFactoryEntry *entry; gchar *clean_path; GtkWidget *widget = NULL; SV *callback_sv = NULL, *tmp_defsv; SV * real_data = callback_data ? gperl_sv_copy (callback_data) : NULL; entry = SvGtkItemFactoryEntry (entry_ref, &callback_sv); /* remove all those underscores that gtk+ turns into accelerators to * get a clean path that can later be used for item retrieval */ tmp_defsv = newSVsv (DEFSV); sv_setsv (DEFSV, sv_2mortal (newSVGChar (entry->path))); eval_pv ("s/_(?!_+)//g; s/_+/_/g;", 1); clean_path = SvGChar (sv_2mortal (newSVsv (DEFSV))); sv_setsv (DEFSV, tmp_defsv); /* create the item in the normal manner now */ gtk_item_factory_create_item (ifactory, entry, real_data, 1); /* get the widget that was created by create_item (this is why * we needed clean_path) */ widget = gtk_item_factory_get_item (ifactory, clean_path); if (widget) { /* put the sv we need to call into the widget */ g_object_set_data_full (G_OBJECT (widget), "_gtk2perl_item_factory_callback_sv", gperl_sv_copy (callback_sv), (GtkDestroyNotify) gperl_sv_free); if (real_data) g_object_set_data_full (G_OBJECT (widget), "_gtk2perl_item_factory_callback_data", real_data, (GtkDestroyNotify) gperl_sv_free); } else { if (real_data) gperl_sv_free (real_data); croak("ItemFactory couldn't retrieve widget it just created"); } } /* ------------------------------------------------------------------------- */ MODULE = Gtk2::ItemFactory PACKAGE = Gtk2::ItemFactory PREFIX = gtk_item_factory_ =for deprecated_by Gtk2::UIManager =cut ## GtkItemFactory* gtk_item_factory_new (GType container_type, const gchar *path, GtkAccelGroup *accel_group) GtkItemFactory* gtk_item_factory_new (class, container_type_package, path, accel_group=NULL) char * container_type_package const gchar *path GtkAccelGroup_ornull *accel_group PREINIT: GType container_type; CODE: container_type = gperl_type_from_package (container_type_package); RETVAL = gtk_item_factory_new (container_type, path, accel_group); OUTPUT: RETVAL ### deprecated ## void gtk_item_factory_add_foreign (GtkWidget *accel_widget, const gchar *full_path, GtkAccelGroup *accel_group, guint keyval, GdkModifierType modifiers) GtkItemFactory_ornull* gtk_item_factory_from_widget (class, widget) GtkWidget *widget C_ARGS: widget const gchar* gtk_item_factory_path_from_widget (class, widget) GtkWidget *widget C_ARGS: widget GtkWidget_ornull* gtk_item_factory_get_item (ifactory, path) GtkItemFactory *ifactory const gchar *path GtkWidget_ornull* gtk_item_factory_get_widget (ifactory, path) GtkItemFactory *ifactory const gchar *path GtkWidget_ornull* gtk_item_factory_get_widget_by_action (ifactory, action) GtkItemFactory *ifactory guint action GtkWidget_ornull* gtk_item_factory_get_item_by_action (ifactory, action) GtkItemFactory *ifactory guint action =for apidoc =for arg entry_ref GtkItemFactoryEntry =cut void gtk_item_factory_create_item (ifactory, entry_ref, callback_data=NULL) GtkItemFactory *ifactory SV *entry_ref SV *callback_data CODE: gtk2perl_item_factory_create_item_helper (ifactory, entry_ref, callback_data); =for apidoc =for arg ... GtkItemFactoryEntry's =cut void gtk_item_factory_create_items (ifactory, callback_data, ...) GtkItemFactory *ifactory SV *callback_data PREINIT: int i; CODE: for (i = 2; i < items; i++) gtk2perl_item_factory_create_item_helper (ifactory, ST (i), callback_data); void gtk_item_factory_delete_item (ifactory, path) GtkItemFactory *ifactory const gchar *path =for apidoc =for arg entry_ref GtkItemFactoryEntry =cut void gtk_item_factory_delete_entry (ifactory, entry_ref) GtkItemFactory *ifactory SV *entry_ref PREINIT: GtkItemFactoryEntry *entry; CODE: entry = SvGtkItemFactoryEntry (entry_ref, NULL); gtk_item_factory_delete_entry (ifactory, entry); =for apidoc =for arg ... GtkItemFactoryEntry's =cut void gtk_item_factory_delete_entries (ifactory, ...) GtkItemFactory *ifactory PREINIT: int i; GtkItemFactoryEntry *entry; CODE: for (i = 1; i < items; i++) { entry = SvGtkItemFactoryEntry (ST (i), NULL); gtk_item_factory_delete_entry (ifactory, entry); } ## void gtk_item_factory_popup (GtkItemFactory *ifactory, guint x, guint y, guint mouse_button, guint32 time_) ## void gtk_item_factory_popup_with_data(GtkItemFactory *ifactory, gpointer popup_data, GtkDestroyNotify destroy, guint x, guint y, guint mouse_button, guint32 time_) ### combination of gtk_item_factory_popup and gtk_item_factory_popup_with_data void gtk_item_factory_popup (ifactory, x, y, mouse_button, time_, popup_data=NULL) GtkItemFactory *ifactory guint x guint y guint mouse_button guint32 time_ SV * popup_data PREINIT: SV * real_popup_data = NULL; CODE: if (gperl_sv_is_defined (popup_data)) real_popup_data = gperl_sv_copy (popup_data); gtk_item_factory_popup_with_data (ifactory, real_popup_data, real_popup_data ? (GDestroyNotify)gperl_sv_free : NULL, x, y, mouse_button, time_); SV * gtk_item_factory_popup_data (ifactory) GtkItemFactory *ifactory CODE: RETVAL = (SV *) gtk_item_factory_popup_data (ifactory); if (RETVAL) { RETVAL = gperl_sv_copy (RETVAL); } else { RETVAL = &PL_sv_undef; } OUTPUT: RETVAL SV * gtk_item_factory_popup_data_from_widget (class, widget) GtkWidget *widget CODE: RETVAL = (SV *) gtk_item_factory_popup_data_from_widget (widget); if (RETVAL) { RETVAL = gperl_sv_copy (RETVAL); } else { RETVAL = &PL_sv_undef; } OUTPUT: RETVAL void gtk_item_factory_set_translate_func (ifactory, func, data=NULL) GtkItemFactory *ifactory SV *func SV *data PREINIT: GPerlCallback *callback; CODE: callback = gtk2perl_translate_func_create (func, data); gtk_item_factory_set_translate_func (ifactory, gtk2perl_translate_func, callback, (GtkDestroyNotify) gperl_callback_destroy); ## ## deprecated ## ## void gtk_item_factory_create_items_ac (GtkItemFactory *ifactory, guint n_entries, GtkItemFactoryEntry *entries, gpointer callback_data, guint callback_type) ## GtkItemFactory* gtk_item_factory_from_path (const gchar *path) ## void gtk_item_factory_create_menu_entries (guint n_entries, GtkMenuEntry *entries) ## void gtk_item_factories_path_delete (const gchar *ifactory_path, const gchar *path)