Started project plugin in objective-c

master
Yevgen Muntyan 2007-11-03 12:48:58 -05:00
parent 03802b459d
commit c446f77f97
22 changed files with 1381 additions and 368 deletions

View File

@ -61,6 +61,7 @@ moo/mooedit/gtksourceview/Makefile
moo/mooedit/gtksourceview/upstream/Makefile
moo/mooedit/plugins/Makefile
moo/mooedit/plugins/ctags/Makefile
moo/mooedit/plugins/project/Makefile
moo/mooapp/Makefile
moo/mooapp/smclient/Makefile
moo/moopython/Makefile

View File

@ -14,8 +14,14 @@ AC_DEFUN_ONCE([MOO_AC_OBJC],[
if test "x$MOO_USE_OBJC" != "xno"; then
_MOO_OBJC_CHECK([
MOO_USE_OBJC=yes
MOO_OBJC_LIBS="$MOO_FFI_LIBS $MOO_OBJC_LIBS"
AC_DEFINE(MOO_USE_OBJC, 1, [Use Objective-C.])
AC_MSG_NOTICE([Objective-C flags: $MOO_OBJCFLAGS $MOO_OBJC_LIBS])
AC_LANG_SAVE
AC_LANG_OBJC
AC_CHECK_SIZEOF(BOOL,,[#include <objc/objc.h>])
AC_LANG_RESTORE
],[
MOO_USE_OBJC=no
MOO_OBJCFLAGS=
@ -86,7 +92,7 @@ AC_DEFUN([_MOO_OBJC_CHECK_RUNTIME],[
AC_LANG_SAVE
AC_LANG([Objective C])
save_LIBS=$LIBS
save_LIBS="$LIBS"
LIBS="-lobjc $LIBS"
AC_LINK_IFELSE([AC_LANG_PROGRAM(
@ -117,15 +123,42 @@ AC_DEFUN([_MOO_OBJC_CHECK_RUNTIME],[
AC_LANG_RESTORE
])
AC_DEFUN([_MOO_CHECK_FFI],[
AC_MSG_CHECKING(FFI library)
MOO_FFI_LIBS="-lffi"
save_LIBS="$LIBS"
LIBS="$LIBS $MOO_FFI_LIBS"
AC_LINK_IFELSE([AC_LANG_PROGRAM(
[#include <ffi.h>],
[ffi_call (0, 0, 0, 0);])],
[
AC_MSG_RESULT(yes)
$1
],[
AC_MSG_RESULT(no)
$2
])
LIBS="$save_LIBS"
])
AC_DEFUN([_MOO_OBJC_CHECK],[
MOO_OBJC_LIBS=
MOO_OBJCFLAGS=
_MOO_OBJC_CHECK_RUNTIME([
MOO_OBJC_USE_FOUNDATION=no
dnl _MOO_OBJC_CHECK_FOUNDATION
$1
_MOO_CHECK_FFI([
_MOO_OBJC_CHECK_RUNTIME([
MOO_OBJC_USE_FOUNDATION=no
dnl _MOO_OBJC_CHECK_FOUNDATION
$1
],[
:
$2
])
],[
:
$2
])
])

View File

@ -26,13 +26,13 @@
</ignoreparts>
<projectdirectory>.</projectdirectory>
<absoluteprojectpath>false</absoluteprojectpath>
<description></description>
<description/>
<secondaryLanguages>
<language>C</language>
</secondaryLanguages>
<versioncontrol>kdevsubversion</versioncontrol>
<projectname>moo</projectname>
<defaultencoding></defaultencoding>
<defaultencoding/>
</general>
<kdevautoproject>
<general>
@ -253,10 +253,10 @@
<breakonloadinglibs>true</breakonloadinglibs>
<separatetty>false</separatetty>
<floatingtoolbar>true</floatingtoolbar>
<gdbpath></gdbpath>
<configGdbScript></configGdbScript>
<runShellScript></runShellScript>
<runGdbScript></runGdbScript>
<gdbpath/>
<configGdbScript/>
<runShellScript/>
<runGdbScript/>
</general>
<display>
<staticmembers>true</staticmembers>
@ -318,16 +318,16 @@
</kdevdoctreeview>
<kdevfilecreate>
<filetypes>
<type icon="source" ext="g" create="template" name="GAP source" >
<type icon="source" ext="g" name="GAP source" create="template" >
<descr>A new empty GAP source file</descr>
</type>
<type icon="source_cpp" ext="cpp" create="template" name="C++ Source" >
<type icon="source_cpp" ext="cpp" name="C++ Source" create="template" >
<descr>A new empty C++ file.</descr>
</type>
<type icon="source_h" ext="h" create="template" name="C/C++ Header" >
<type icon="source_h" ext="h" name="C/C++ Header" create="template" >
<descr>A new empty header file for C/C++.</descr>
</type>
<type icon="source_c" ext="c" create="template" name="C Source" >
<type icon="source_c" ext="c" name="C Source" create="template" >
<descr>A new empty C file.</descr>
</type>
</filetypes>
@ -366,10 +366,12 @@
<usePermanentCaching>true</usePermanentCaching>
<alwaysIncludeNamespaces>false</alwaysIncludeNamespaces>
<includePaths>.;</includePaths>
<parseMissingHeadersExperimental>false</parseMissingHeadersExperimental>
<resolveIncludePathsUsingMakeExperimental>false</resolveIncludePathsUsingMakeExperimental>
</codecompletion>
<references/>
<creategettersetter>
<prefixGet></prefixGet>
<prefixGet/>
<prefixSet>set</prefixSet>
<prefixVariable>m_,_</prefixVariable>
<parameterName>theValue</parameterName>
@ -382,7 +384,7 @@
<root>/usr/share/qt3</root>
<includestyle>3</includestyle>
<designerintegration>EmbeddedKDevDesigner</designerintegration>
<qmake>/usr/bin/qmake-qt3</qmake>
<qmake>/usr/bin/qmake</qmake>
<designer>/usr/bin/designer-qt3</designer>
<designerpluginpaths/>
</qt>

View File

@ -1,9 +1,12 @@
DIST_SUBDIRS = ctags
DIST_SUBDIRS = ctags project
SUBDIRS =
if MOO_BUILD_CTAGS
SUBDIRS += ctags
endif
if MOO_USE_OBJC
SUBDIRS += project
endif
noinst_LTLIBRARIES =
EXTRA_DIST =
@ -54,6 +57,9 @@ libmooeditplugins_la_LIBADD = libfileselector.la
if MOO_BUILD_CTAGS
libmooeditplugins_la_LIBADD += ctags/libctags.la
endif
if MOO_USE_OBJC
libmooeditplugins_la_LIBADD += project/libproject.la
endif
libmooeditplugins_la_SOURCES = \
mooeditplugins.h

View File

@ -26,6 +26,7 @@ gboolean _moo_ctags_plugin_init (void);
gboolean _moo_active_strings_plugin_init (void);
gboolean _moo_completion_plugin_init (void);
gboolean _moo_file_selector_plugin_init (void);
gboolean _moo_project_plugin_init (void);
G_END_DECLS

View File

@ -0,0 +1,36 @@
AM_CFLAGS = \
-I../.. \
-I$(top_builddir) \
-I$(top_builddir)/moo \
$(MOO_CFLAGS) \
$(MOO_DEBUG_CFLAGS)
AM_OBJCFLAGS = $(AM_CFLAGS) $(MOO_OBJCFLAGS)
noinst_LTLIBRARIES = libproject.la
# EXTRA_DIST += \
# moofileselector.glade \
# moofileselector-prefs.glade
libproject_la_SOURCES = \
project-plugin.m \
manager.h \
manager.m \
mpconfig.h \
mpconfig.m \
mpfile.h \
mpfile.m \
project.h \
project.m
@MOO_GLADE_RULE@
# nodist_libfileselector_la_SOURCES = \
# moofileselector-glade.h \
# moofileselector-prefs-glade.h
# BUILT_SOURCES += \
# moofileselector-glade.h \
# moofileselector-prefs-glade.h
# CLEANFILES += \
# moofileselector-glade.h \
# moofileselector-prefs-glade.h

View File

@ -0,0 +1,27 @@
#ifndef MOO_PROJECT_MANAGER_H
#define MOO_PROJECT_MANAGER_H
#include <mooutils/moocobject.h>
#include <mooedit/mooeditwindow.h>
@class MPProject;
@interface MPManager : MooCObject
{
@private
MPProject *project;
MooEditWindow *window;
char *filename;
}
- (void) deinit;
- (void) attachWindow: (MooEditWindow*) window;
- (void) detachWindow: (MooEditWindow*) window;
- (void) openProject: (CSTR) file;
- (void) closeProject;
- (void) projectOptions;
@end
#endif // MOO_PROJECT_MANAGER_H
// -*- objc -*-

View File

@ -0,0 +1,146 @@
#include "manager.h"
#include "project.h"
#include "project-plugin.h"
#include "mpfile.h"
#include <mooedit/mooeditor.h>
#include <mooutils/moofiledialog.h>
@interface MPManager(Private)
- (void) doOpenProject: (CSTR) file
error: (GError**) error;
- (void) doCloseProject;
@end
@implementation MPManager
- (void) dealloc
{
g_free (filename);
filename = NULL;
[super dealloc];
}
- (void) deinit
{
if (project)
[self doCloseProject];
}
- (void) attachWindow: (MooEditWindow*) win
{
MooEditor *editor = moo_editor_instance ();
GtkAction *action;
window = win;
moo_editor_set_app_name (editor, project ? [project name] : NULL);
moo_objc_signal_connect (window, "close", self, @selector(onCloseWindow));
if ((action = moo_window_get_action (MOO_WINDOW (window), "CloseProject")))
g_object_set (action, "sensitive", project != NULL, NULL);
if ((action = moo_window_get_action (MOO_WINDOW (window), "ProjectOptions")))
g_object_set (action, "visible", project != NULL, NULL);
if (!project)
{
const char *path = moo_prefs_get_string ("Plugins/Project/last");
if (path && g_file_test (path, G_FILE_TEST_EXISTS))
[self doOpenProject:path error:NULL];
}
}
- (void) detachWindow: (MooEditWindow*) win
{
g_return_if_fail (win == window);
window = NULL;
}
- (void) openProject: (CSTR) file
{
if (!window)
{
g_free (filename);
filename = g_strdup (file);
}
if (!file)
file = moo_file_dialogp (window ? GTK_WIDGET (window) : NULL,
MOO_FILE_DIALOG_OPEN,
NULL, "Open Project",
"Plugins/Project/last_dir", NULL);
if (!file)
return;
if (project)
[self closeProject];
if (project)
return;
[self doOpenProject:file error:NULL];
}
- (void) closeProject
{
}
- (void) projectOptions
{
}
@end
@implementation MPManager(Private)
- (void) initProjectTypes
{
}
- (void) deinitProjectTypes
{
}
- (void) doOpenProject: (CSTR) file
error: (GError**) error
{
g_return_if_fail (project == nil);
g_return_if_fail (file != NULL);
g_return_if_fail (!error || !*error);
MPFile *pf = [MPFile open:file error:error];
if (!pf)
return;
if ((project = [MPProject loadFile:pf error:error]))
{
moo_editor_set_app_name (moo_editor_instance (), [project name]);
moo_history_list_add_filename (moo_history_list_get (MP_RECENT_LIST_ID), file);
moo_prefs_set_filename ("Plugins/Project/last", file);
if (window)
{
GtkAction *close = moo_window_get_action (MOO_WINDOW (window), MP_ACTION_CLOSE_PROJECT);
GtkAction *options = moo_window_get_action (MOO_WINDOW (window), MP_ACTION_PROJECT_OPTIONS);
if (close)
g_object_set (close, "sensitive", TRUE, NULL);
if (options)
g_object_set (options, "visible", TRUE, NULL);
}
}
else
{
moo_history_list_remove (moo_history_list_get (MP_RECENT_LIST_ID), file);
}
[pf release];
}
// - (void) doCloseProject;
@end
// -*- objc -*-

View File

@ -0,0 +1,12 @@
#ifndef MOO_PROJECT_CONFIG_H
#define MOO_PROJECT_CONFIG_H
#include <mooutils/moocobject.h>
@interface MPConfig : MooCObject
@end
#endif // MOO_PROJECT_CONFIG_H
// -*- objc -*-

View File

@ -0,0 +1,3 @@
#include "mpconfig.h"

View File

@ -0,0 +1,29 @@
#ifndef MOO_PROJECT_FILE_H
#define MOO_PROJECT_FILE_H
#import <mooutils/moocobject.h>
#import <mooutils/moomarkup.h>
#define MP_FILE_ERROR (_mp_file_error_quark ())
@interface MPFile : MooCObject
{
@private
char *filename;
char *project_name;
char *project_type;
MooMarkupDoc *xml;
}
+ (id) open: (CSTR) filename
error: (GError**) error;
- (CSTR) type;
- (CSTR) name;
@end
GQuark _mp_file_error_quark (void) G_GNUC_CONST;
#endif /* MOO_PROJECT_FILE_H */
// -*- objc -*-

View File

@ -0,0 +1,112 @@
#import "mpfile.h"
#define MP_FILE_VERSION "2.0"
@implementation MPFile
- (id) init
{
if ((self = [super init]))
{
project_type = NULL;
project_name = NULL;
filename = NULL;
}
return self;
}
- (void) dealloc
{
g_free (filename);
g_free (project_type);
g_free (project_name);
if (xml)
moo_markup_doc_unref (xml);
[super dealloc];
}
- (BOOL) _open: (CSTR) filename_
error: (GError**) error
{
MooMarkupNode *root;
const char *version, *type, *name;
g_return_val_if_fail (filename_ != NULL, NO);
g_return_val_if_fail (filename == NULL, NO);
if (!(xml = moo_markup_parse_file (filename_, error)))
return NO;
if (!(root = moo_markup_get_root_element (xml, "medit-project")))
{
g_set_error (error, MP_FILE_ERROR, 0,
"malformed project file");
return NO;
}
version = moo_markup_get_prop (root, "version");
if (!version || strcmp (version, MP_FILE_VERSION) != 0)
{
g_set_error (error, MP_FILE_ERROR, 0,
"invalid project version %s",
version ? version : "<null>");
return NO;
}
type = moo_markup_get_prop (root, "type");
if (!type || !type[0])
{
g_set_error (error, MP_FILE_ERROR, 0,
"project type missing");
return NO;
}
name = moo_markup_get_prop (root, "name");
if (!name || !name[0])
{
g_set_error (error, MP_FILE_ERROR, 0,
"project name missing");
return NO;
}
filename = g_strdup (filename_);
project_name = g_strdup (name);
project_type = g_strdup (type);
return YES;
}
+ (id) open: (CSTR) filename
error: (GError**) error
{
MPFile *file = [[self alloc] init];
if (file && [file _open:filename error:error])
return file;
if (file)
[file release];
return file;
}
- (CSTR) type
{
return project_type;
}
- (CSTR) name
{
return project_name;
}
@end
GQuark
_mp_file_error_quark (void)
{
return g_quark_from_static_string ("moo-project-file-error");
}
// -*- objc -*-

View File

@ -0,0 +1,24 @@
/*
* project-plugin.h
*
* Copyright (C) 2004-2007 by Yevgen Muntyan <muntyan@math.tamu.edu>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation.
*
* See COPYING file that comes with this distribution.
*/
#ifndef MOO_PROJECT_PLUGIN_H
#define MOO_PROJECT_PLUGIN_H
#define PROJECT_PLUGIN_ID "ProjectMgr"
#define MP_RECENT_LIST_ID "ProjectManager"
#define MP_ACTION_CLOSE_PROJECT "CloseProject"
#define MP_ACTION_OPEN_PROJECT "OpenProject"
#define MP_ACTION_PROJECT_OPTIONS "ProjectOptions"
#endif /* MOO_PROJECT_PLUGIN_H */
/* -*- objc -*- */

View File

@ -0,0 +1,267 @@
/*
* project-plugin.m
*
* Copyright (C) 2004-2007 by Yevgen Muntyan <muntyan@math.tamu.edu>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation.
*
* See COPYING file that comes with this distribution.
*/
#include "config.h"
#include "mooedit/mooplugin-macro.h"
#include "mooedit/plugins/mooeditplugins.h"
#include "mooedit/mooeditwindow.h"
#include "mooutils/moostock.h"
#include "mooutils/moomenuaction.h"
#include "mooutils/moomarshals.h"
#include "manager.h"
#include "project-plugin.h"
#include <gtk/gtk.h>
typedef struct {
MooPlugin parent;
guint ui_merge_id;
MooHistoryList *recent_list;
MPManager *pm;
char *project_to_open;
} ProjectPlugin;
#define PROJECT_PLUGIN(mpl) ((ProjectPlugin*)mpl)
static void
project_plugin_attach_window (MooPlugin *mplugin,
MooEditWindow *window)
{
ProjectPlugin *plugin = PROJECT_PLUGIN (mplugin);
g_return_if_fail (plugin->pm != nil);
moo_objc_push_autorelease_pool ();
[plugin->pm attachWindow: window];
moo_objc_pop_autorelease_pool ();
}
static void
project_plugin_detach_window (MooPlugin *mplugin,
MooEditWindow *window)
{
ProjectPlugin *plugin = PROJECT_PLUGIN (mplugin);
g_return_if_fail (plugin->pm != nil);
moo_objc_push_autorelease_pool ();
[plugin->pm detachWindow: window];
moo_objc_pop_autorelease_pool ();
}
static void
open_project_cb (void)
{
ProjectPlugin *plugin = moo_plugin_lookup (PROJECT_PLUGIN_ID);
g_return_if_fail (plugin && plugin->pm);
moo_objc_push_autorelease_pool ();
[plugin->pm openProject:NULL];
moo_objc_pop_autorelease_pool ();
}
static void
close_project_cb (void)
{
ProjectPlugin *plugin = moo_plugin_lookup (PROJECT_PLUGIN_ID);
g_return_if_fail (plugin && plugin->pm);
moo_objc_push_autorelease_pool ();
[plugin->pm closeProject];
moo_objc_pop_autorelease_pool ();
}
static void
project_options_cb (void)
{
ProjectPlugin *plugin = moo_plugin_lookup (PROJECT_PLUGIN_ID);
g_return_if_fail (plugin && plugin->pm);
moo_objc_push_autorelease_pool ();
[plugin->pm projectOptions];
moo_objc_pop_autorelease_pool ();
}
static GtkAction *
create_recent_list_action (G_GNUC_UNUSED MooWindow *window,
ProjectPlugin *plugin)
{
GtkAction *action;
action = moo_menu_action_new ("OpenRecentProject", "Open Recent Project");
g_object_set (action, "display-name", "Open Recent Project", NULL);
moo_menu_action_set_mgr (MOO_MENU_ACTION (action),
moo_history_list_get_menu_mgr (plugin->recent_list));
moo_bind_bool_property (action, "sensitive", plugin->recent_list, "empty", TRUE);
return action;
}
static void
recent_item_activated (G_GNUC_UNUSED MooHistoryList *list,
MooHistoryItem *item,
G_GNUC_UNUSED gpointer menu_data,
ProjectPlugin *plugin)
{
[plugin->pm openProject:item->data];
}
static void
meth_open_project (ProjectPlugin *plugin,
const char *filename)
{
g_return_if_fail (filename != NULL);
if (plugin->pm)
{
[plugin->pm openProject:filename];
}
else
{
g_free (plugin->project_to_open);
plugin->project_to_open = g_strdup (filename);
}
}
static gboolean
project_plugin_init (ProjectPlugin *plugin)
{
MooEditor *editor;
MooWindowClass *klass;
MooUIXML *xml;
moo_objc_push_autorelease_pool ();
if (!(plugin->pm = [[MPManager alloc] init]))
{
moo_objc_pop_autorelease_pool ();
return FALSE;
}
editor = moo_editor_instance ();
g_object_set (editor, "allow-empty-window", TRUE, "single-window", TRUE, NULL);
klass = g_type_class_peek (MOO_TYPE_EDIT_WINDOW);
moo_window_class_new_action (klass, "OpenProject", NULL,
"display-name", "Open Project",
"label", "Open Project",
"stock-id", MOO_STOCK_OPEN_PROJECT,
"closure-callback", open_project_cb,
NULL);
moo_window_class_new_action (klass, "ProjectOptions", NULL,
"display-name", "Project _Options",
"label", "Project Options",
"stock-id", MOO_STOCK_PROJECT_OPTIONS,
"closure-callback", project_options_cb,
NULL);
moo_window_class_new_action (klass, "CloseProject", NULL,
"display-name", "Close Project",
"label", "Close Project",
"stock-id", MOO_STOCK_CLOSE_PROJECT,
"closure-callback", close_project_cb,
NULL);
plugin->recent_list = moo_history_list_new (MP_RECENT_LIST_ID);
g_signal_connect (plugin->recent_list, "activate-item",
G_CALLBACK (recent_item_activated), plugin);
moo_window_class_new_action_custom (klass, "OpenRecentProject", NULL,
(MooWindowActionFunc) create_recent_list_action,
plugin, NULL);
xml = moo_editor_get_ui_xml (editor);
plugin->ui_merge_id = moo_ui_xml_new_merge_id (xml);
moo_ui_xml_insert_markup_after (xml, plugin->ui_merge_id,
"Editor/Menubar", "View",
"<item name=\"Project\" _label=\"_Project\">"
" <item action=\"OpenProject\"/>"
" <item action=\"OpenRecentProject\"/>"
" <separator/>"
" <item action=\"ProjectOptions\"/>"
" <separator/>"
" <item action=\"CloseProject\"/>"
" <separator/>"
"</item>");
if (plugin->project_to_open)
{
[plugin->pm openProject:plugin->project_to_open];
g_free (plugin->project_to_open);
plugin->project_to_open = NULL;
}
moo_objc_pop_autorelease_pool ();
return TRUE;
}
static void
project_plugin_deinit (ProjectPlugin *plugin)
{
MooWindowClass *klass = g_type_class_peek (MOO_TYPE_EDIT_WINDOW);
moo_window_class_remove_action (klass, "OpenProject");
moo_window_class_remove_action (klass, "CloseProject");
moo_window_class_remove_action (klass, "ProjectOptions");
moo_window_class_remove_action (klass, "OpenRecentProject");
if (plugin->ui_merge_id)
{
MooEditor *editor = moo_editor_instance ();
MooUIXML *xml = moo_editor_get_ui_xml (editor);
moo_ui_xml_remove_ui (xml, plugin->ui_merge_id);
plugin->ui_merge_id = 0;
}
if (plugin->recent_list)
g_object_unref (plugin->recent_list);
plugin->recent_list = NULL;
if (plugin->pm)
{
moo_objc_push_autorelease_pool ();
[plugin->pm deinit];
[plugin->pm release];
plugin->pm = nil;
moo_objc_pop_autorelease_pool ();
}
g_free (plugin->project_to_open);
plugin->project_to_open = NULL;
}
MOO_PLUGIN_DEFINE_INFO (project, "Project", "Project manager",
"Yevgen Muntyan <muntyan@tamu.edu>",
MOO_VERSION, NULL)
MOO_PLUGIN_DEFINE_FULL (Project, project,
project_plugin_attach_window, project_plugin_detach_window,
NULL, NULL, NULL, 0, 0)
gboolean
_moo_project_plugin_init (void)
{
MooPluginParams params = {TRUE, TRUE};
if (!moo_plugin_register (PROJECT_PLUGIN_ID,
project_plugin_get_type (),
&project_plugin_info,
&params))
return FALSE;
moo_plugin_method_new ("open-project", project_plugin_get_type (),
G_CALLBACK (meth_open_project),
_moo_marshal_VOID__STRING,
G_TYPE_NONE, 1, G_TYPE_STRING);
return TRUE;
}

View File

@ -0,0 +1,28 @@
#ifndef MOO_PROJECT_H
#define MOO_PROJECT_H
#include <mooutils/moocobject.h>
#include <mooedit/mooeditwindow.h>
#include "mpfile.h"
@interface MPProject : MooCObject
{
@private
}
+ (id) loadFile: (MPFile*) pf
error: (GError**) error;
- (BOOL) loadFile: (MPFile*) pf
error: (GError**) error;
- (CSTR) name;
+ (void) registerProjectType: (CSTR) name;
@end
#endif // MOO_PROJECT_H
// -*- objc -*-

View File

@ -0,0 +1,67 @@
#include "project.h"
#include <mooutils/mooutils-debug.h>
static GHashTable *registered_types;
static void
init_types (void)
{
if (!registered_types)
registered_types = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
}
@implementation MPProject
+ (void) registerProjectType: (CSTR) name
{
Class old_class;
init_types ();
old_class = g_hash_table_lookup (registered_types, name);
if (old_class != Nil && old_class != self)
_moo_message ("%s: re-registering project type %s", G_STRLOC, name);
g_hash_table_insert (registered_types, g_strdup (name), self);
}
+ (id) loadFile: (MPFile*) pf
error: (GError**) error
{
const char *project_type;
Class project_class;
MPProject *project;
init_types ();
project_type = [pf type];
project_class = g_hash_table_lookup (registered_types, project_type);
if (!project_class)
{
g_set_error (error, MP_FILE_ERROR, 0,
"unknown project type '%s'",
project_type);
return nil;
}
project = [[project_class alloc] init];
if (project && [project loadFile:pf error:error])
return project;
[project release];
return nil;
}
- (BOOL) loadFile: (MPFile*) pf
error: (GError**) error
{
MOO_UNUSED_VAR (pf);
MOO_UNUSED_VAR (error);
g_return_val_if_reached (NO);
}
@end
// -*- objc -*-

View File

@ -132,8 +132,11 @@ mooobjc.lo: mooutils-fli.lo
moopython.lo: mooutils-fli.lo
objc_sources = \
moocobject-private.h \
moocobject.h \
moocobject.m
moocobject.m \
mooobjcmarshal.h \
mooobjcmarshal.m
if MOO_USE_OBJC
mooutils_sources += $(objc_sources)

View File

@ -0,0 +1,45 @@
/*
* moocobject-private.h
*
* Copyright (C) 2007 by Yevgen Muntyan <muntyan@math.tamu.edu>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation.
*
* See COPYING file that comes with this distribution.
*/
#ifndef MOO_COBJECT_PRIVATE_H
#define MOO_COBJECT_PRIVATE_H
#import "moocobject.h"
G_BEGIN_DECLS
#ifndef MOO_OBJC_USE_FOUNDATION
@interface MooAutoreleasePool : MooCObject
{
@private
MooAutoreleasePool *parent;
MooAutoreleasePool *child;
GSList *objects;
}
+ (void) addObject: (id)anObj;
- (void) addObject: (id)anObj;
- (void) emptyPool;
@end
#define NSAutoreleasePool MooAutoreleasePool
#endif
G_END_DECLS
#endif /* MOO_COBJECT_PRIVATE_H */
/* -*- objc -*- */

View File

@ -62,6 +62,12 @@ void moo_objc_push_autorelease_pool (void);
void moo_objc_pop_autorelease_pool (void);
gulong moo_objc_signal_connect (gpointer instance,
const char *signal,
MooCObject *target,
SEL sel);
#ifdef CSTR
#warning "CSTR defined"
#endif

View File

@ -11,37 +11,15 @@
*/
#include <config.h>
#import "moocobject.h"
#import "moocobject-private.h"
#import "mooobjc.h"
#import "mooobjcmarshal.h"
#import <objc/objc-api.h>
static GSList *autorelease_pools;
#ifndef MOO_OBJC_USE_FOUNDATION
@interface MooAutoreleasePool : MooCObject
{
@private
MooAutoreleasePool *parent;
MooAutoreleasePool *child;
GSList *objects;
}
+ (void) addObject: (id)anObj;
- (void) addObject: (id)anObj;
- (void) emptyPool;
@end
#else
typedef NSAutoreleasePool MooAutoreleasePool;
#endif
static void
moo_objc_send_msg (MooObjCObject *m_obj,
const char *name)
@ -115,7 +93,7 @@ moo_init_objc_api (void)
void
moo_objc_push_autorelease_pool (void)
{
MooAutoreleasePool *pool = [[MooAutoreleasePool alloc] init];
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
g_return_if_fail (pool != nil);
autorelease_pools = g_slist_prepend (autorelease_pools, pool);
}
@ -123,7 +101,7 @@ moo_objc_push_autorelease_pool (void)
void
moo_objc_pop_autorelease_pool (void)
{
MooAutoreleasePool *pool;
NSAutoreleasePool *pool;
g_return_if_fail (autorelease_pools != NULL);
@ -273,362 +251,136 @@ static MooAutoreleasePool *currentPool;
#endif // !MOO_OBJC_USE_FOUNDATION
#if 0
#ifdef MOO_OS_DARWIN
#define class_get_class_name(klass) (klass->name)
#define sel_get_name sel_getName
#endif
#define OBJECT_HAS_TOGGLE_REF_FLAG 1
#define OBJECT_HAS_TOGGLE_REF() ((g_datalist_get_flags (&moo_c_object_qdata) & OBJECT_HAS_TOGGLE_REF_FLAG) != 0)
static GQuark quark_toggle_refs = 0;
typedef enum {
CG_SIGNAL_RETAIN_DATA = 1 << 0,
CG_SIGNAL_SWAP_DATA = 1 << 1,
CG_SIGNAL_CONNECT_AFTER = 1 << 2
} CGSignalFlags;
typedef struct {
guint n_toggle_refs;
struct {
MooToggleNotify notify;
gpointer data;
} toggle_refs[1]; /* flexible array */
} ToggleRefStack;
GClosure closure;
MooCObject *obj;
SEL sel;
MooCObject *data;
guint has_data : 1;
guint owns_data : 1;
guint swap : 1;
} CGClosureSel;
static void
toggle_refs_notify (MooCObject *object,
GData **qdata,
gboolean is_last_ref)
cg_closure_sel_marshal (CGClosureSel *closure,
GValue *return_value,
guint n_params,
const GValue *params)
{
ToggleRefStack *tstack = g_datalist_id_get_data (qdata, quark_toggle_refs);
g_assert (tstack->n_toggle_refs == 1);
tstack->toggle_refs[0].notify (tstack->toggle_refs[0].data, object, is_last_ref);
IMP callback;
/* TODO: use NSInvocation to enable forwarding */
callback = get_imp ([closure->obj class], closure->sel);
g_return_if_fail (callback != NULL);
_moo_objc_marshal (G_CALLBACK (callback), closure->obj, closure->sel,
return_value, n_params, params,
closure->data, closure->has_data, closure->swap);
}
@implementation MooCObject : Object
+ initialize
static void
cg_closure_sel_invalidate (G_GNUC_UNUSED gpointer data,
CGClosureSel *cg)
{
quark_toggle_refs = g_quark_from_static_string ("moo-object-toggle-refs");
return self;
if (cg->owns_data)
{
[cg->data release];
cg->data = nil;
}
}
#ifndef MOO_OS_DARWIN
- (retval_t) forward :(SEL)aSel :(arglist_t)argFrame
static GClosure *
_cg_closure_new_sel (MooCObject *target,
SEL sel,
MooCObject *data,
CGSignalFlags sig_flags,
gboolean use_data)
{
MOO_UNUSED_VAR (argFrame);
g_critical ("no method `%s' found in <%s at %p>",
sel_get_name (aSel), [self name], (gpointer) self);
return NULL;
}
GClosure *closure;
CGClosureSel *cg;
g_return_val_if_fail (target != nil, NULL);
g_return_val_if_fail (sel != NULL, NULL);
g_return_val_if_fail (data == nil || use_data, NULL);
g_return_val_if_fail (data != nil || !(sig_flags & CG_SIGNAL_RETAIN_DATA), NULL);
if (![target respondsToSelector:sel])
{
#ifndef MOO_OBJC_USE_FOUNDATION
const char *desc = "<unknown>";
#else
- forward: (SEL)aSel :(marg_list)args
{
MOO_UNUSED_VAR (args);
g_critical ("no method `%s' found in <%s at %p>",
sel_get_name (aSel), [self name], (gpointer) self);
return nil;
}
const char *desc = [[target description] cString];
#endif
- init
{
moo_c_object_ref_count = 1;
moo_c_object_qdata = NULL;
return [super init];
}
- (void) dealloc
{
if (moo_c_object_qdata)
g_datalist_clear (&moo_c_object_qdata);
[self free];
}
- free
{
return [super free];
}
- retain
{
g_assert (moo_c_object_ref_count > 0);
moo_c_object_ref_count++;
if (moo_c_object_ref_count == 2 && OBJECT_HAS_TOGGLE_REF ())
toggle_refs_notify (self, &moo_c_object_qdata, FALSE);
return self;
}
- (void) release
{
gboolean need_dealloc;
g_assert (moo_c_object_ref_count > 0);
moo_c_object_ref_count--;
need_dealloc = !moo_c_object_ref_count;
if (moo_c_object_ref_count == 1 && OBJECT_HAS_TOGGLE_REF ())
toggle_refs_notify (self, &moo_c_object_qdata, TRUE);
if (need_dealloc)
[self dealloc];
}
- autorelease
{
[MooAutoreleasePool addObject: self];
return self;
}
- (guint) retainCount
{
return moo_c_object_ref_count;
}
- (void) setQData :(GQuark)key
:(gpointer)data
{
g_datalist_id_set_data (&moo_c_object_qdata, key, data);
}
- (void) setQData :(GQuark)key :(gpointer)data withDestroy:(GDestroyNotify)destroy
{
g_datalist_id_set_data_full (&moo_c_object_qdata, key, data, destroy);
}
- (gpointer) getQData :(GQuark)key
{
return g_datalist_id_get_data (&moo_c_object_qdata, key);
}
- (void) setData :(CSTR)key :(gpointer)data
{
g_datalist_set_data (&moo_c_object_qdata, key, data);
}
- (void) setData :(CSTR)key :(gpointer)data withDestroy:(GDestroyNotify)destroy
{
g_datalist_set_data_full (&moo_c_object_qdata, key, data, destroy);
}
- (gpointer) getData: (CSTR)key
{
return g_datalist_get_data (&moo_c_object_qdata, key);
}
- (void) addToggleRef :(MooToggleNotify)notify
:(gpointer)data
{
ToggleRefStack *tstack;
guint i;
g_return_if_fail (notify != NULL);
g_return_if_fail (moo_c_object_ref_count >= 1);
[self retain];
tstack = g_datalist_id_remove_no_notify (&moo_c_object_qdata, quark_toggle_refs);
if (tstack)
{
i = tstack->n_toggle_refs++;
/* allocate i = tstate->n_toggle_refs - 1 positions beyond the 1 declared
* in tstate->toggle_refs */
tstack = g_realloc (tstack, sizeof (*tstack) + sizeof (tstack->toggle_refs[0]) * i);
}
else
{
tstack = g_renew (ToggleRefStack, NULL, 1);
tstack->n_toggle_refs = 1;
i = 0;
g_critical ("in %s: object %s does not respond to selector '%s'",
G_STRLOC, desc ? desc : "<NULL>", sel_get_name (sel));
return NULL;
}
/* Set a flag for fast lookup after adding the first toggle reference */
if (tstack->n_toggle_refs == 1)
g_datalist_set_flags (&moo_c_object_qdata, OBJECT_HAS_TOGGLE_REF_FLAG);
closure = g_closure_new_simple (sizeof (CGClosureSel), NULL);
g_closure_add_invalidate_notifier (closure, NULL,
(GClosureNotify) cg_closure_sel_invalidate);
g_closure_set_marshal(closure, (GClosureMarshal) cg_closure_sel_marshal);
tstack->toggle_refs[i].notify = notify;
tstack->toggle_refs[i].data = data;
g_datalist_id_set_data_full (&moo_c_object_qdata, quark_toggle_refs, tstack,
(GDestroyNotify) g_free);
}
cg = (CGClosureSel*) closure;
cg->obj = target;
cg->sel = sel;
cg->data = data;
cg->has_data = use_data ? 1 : 0;
cg->swap = (sig_flags & CG_SIGNAL_SWAP_DATA) ? 1 : 0;
- (void) removeToggleRef :(MooToggleNotify)notify
:(gpointer)data
{
ToggleRefStack *tstack;
gboolean found_one = FALSE;
g_return_if_fail (notify != NULL);
tstack = g_datalist_id_get_data (&moo_c_object_qdata, quark_toggle_refs);
if (tstack)
if (sig_flags & CG_SIGNAL_RETAIN_DATA)
{
guint i;
for (i = 0; i < tstack->n_toggle_refs; i++)
if (tstack->toggle_refs[i].notify == notify &&
tstack->toggle_refs[i].data == data)
{
found_one = TRUE;
tstack->n_toggle_refs -= 1;
if (i != tstack->n_toggle_refs)
tstack->toggle_refs[i] = tstack->toggle_refs[tstack->n_toggle_refs];
if (tstack->n_toggle_refs == 0)
g_datalist_unset_flags (&moo_c_object_qdata, OBJECT_HAS_TOGGLE_REF_FLAG);
[self release];
break;
}
[cg->data retain];
cg->owns_data = TRUE;
}
if (!found_one)
g_warning ("%s: couldn't find toggle ref %p(%p)", G_STRFUNC, notify, data);
return closure;
}
@end
@implementation MooAutoreleasePool : MooCObject
static MooAutoreleasePool *current_pool;
+ (void) addObject: (id)anObj
static gulong
_cg_signal_connect_sel (GObject *obj,
const char *signal,
MooCObject *target,
SEL sel,
CGSignalFlags flags)
{
g_return_if_fail (current_pool != nil);
[current_pool addObject: anObj];
}
gulong cb_id = 0;
GClosure *closure;
+ (id) currentPool
{
return current_pool;
}
closure = _cg_closure_new_sel (target, sel, nil, flags, FALSE);
- (void) addObject: (id)anObj
{
if (G_UNLIKELY (!objects))
objects = g_ptr_array_new ();
g_ptr_array_add (objects, anObj);
}
- (void) emptyPool
{
[self retain];
if (child)
[child emptyPool];
if (objects)
if (closure)
{
id *objs;
guint n_objs, i;
n_objs = objects->len;
objs = (id*) g_ptr_array_free (objects, FALSE);
objects = NULL;
for (i = 0; i < n_objs; ++i)
[objs[i] release];
g_free (objs);
g_closure_sink (g_closure_ref (closure));
cb_id = g_signal_connect_closure (obj, signal, closure,
(flags & CG_SIGNAL_CONNECT_AFTER) ? 1 : 0);
g_closure_unref (closure);
}
[self release];
return cb_id;
}
- (id) autorelease
gulong
moo_objc_signal_connect (gpointer instance,
const char *signal,
MooCObject *target,
SEL sel)
{
g_return_val_if_reached (self);
g_return_val_if_fail (G_IS_OBJECT (instance), 0);
g_return_val_if_fail (signal != NULL, 0);
g_return_val_if_fail (target != nil, 0);
g_return_val_if_fail (sel != 0, 0);
return _cg_signal_connect_sel (instance, signal, target, sel, 0);
}
- init
{
[super init];
if (current_pool)
{
current_pool->child = self;
parent = current_pool;
current_pool = self;
}
current_pool = self;
return self;
}
- (void) free
{
current_pool = parent;
if (current_pool)
current_pool->child = nil;
[self emptyPool];
[super free];
}
@end
static gpointer
moo_object_retain (gpointer obj)
{
g_return_val_if_fail (obj != NULL, NULL);
return [(id)obj retain];
}
static gpointer
moo_object_copy (gpointer obj)
{
g_return_val_if_fail (obj != NULL, NULL);
return [(id)obj copy];
}
static void
moo_object_release (gpointer obj)
{
g_return_if_fail (obj != NULL);
[(id)obj release];
}
GType
moo_cboxed_type_new (Class klass,
gboolean copy)
{
g_return_val_if_fail (klass != Nil, 0);
return g_boxed_type_register_static (class_get_class_name (klass),
copy ? moo_object_copy : moo_object_retain,
moo_object_release);
}
id
moo_cobject_check_type_cast (id obj, Class klass)
{
if (!obj)
g_warning ("invalid cast of (nil) to `%s'",
class_get_class_name (klass));
else if (![obj isKindOf :klass])
g_warning ("invalid cast from `%s' to `%s'",
[obj name], class_get_class_name (klass));
return obj;
}
BOOL
moo_cobject_check_type (id obj, Class klass)
{
return obj != nil && [obj isKindOf :klass];
}
#endif
/* -*- objc -*- */

View File

@ -0,0 +1,36 @@
/*
* mooobjcmarshal.h
*
* Copyright (C) 2007 by Yevgen Muntyan <muntyan@math.tamu.edu>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation.
*
* See COPYING file that comes with this distribution.
*/
#ifndef MOO_OBJC_MARSHAL_H
#define MOO_OBJC_MARSHAL_H
#include <glib-object.h>
#include "moocobject.h"
G_BEGIN_DECLS
void _moo_objc_marshal (GCallback callback,
id add_obj,
SEL add_sel,
GValue *return_value,
guint n_params,
const GValue *params,
id data,
gboolean use_data,
gboolean swap);
G_END_DECLS
#endif /* MOO_OBJC_MARSHAL_H */
/* -*- objc -*- */

View File

@ -0,0 +1,377 @@
/*
* mooobjcmarshal.m
*
* Copyright (C) 2007 by Yevgen Muntyan <muntyan@math.tamu.edu>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation.
*
* See COPYING file that comes with this distribution.
*/
#import <config.h>
#import "mooobjcmarshal.h"
#import "moocobject-private.h"
#import <objc/objc-api.h>
#import <ffi.h>
#define MAX_N_FREELIST 16
#if SIZEOF_BOOL == 1
#define ffi_type_objc_bool ffi_type_uchar
#elif SIZEOF_BOOL == 2
#define ffi_type_objc_bool ffi_type_uint16
#elif SIZEOF_BOOL == 4
#define ffi_type_objc_bool ffi_type_uint32
#else
#error "Something is wrong with the BOOL type"
#endif
static gboolean
get_ffi_type (const GValue *cgvalue,
ffi_type **arg_type,
gpointer *arg_val,
gpointer *freelist,
guint *n_freelist)
{
BOOL *bval;
GValue *gvalue = (GValue*) cgvalue;
switch (g_type_fundamental (G_VALUE_TYPE (gvalue)))
{
case G_TYPE_BOOLEAN:
if (*n_freelist == MAX_N_FREELIST)
{
g_warning ("%s: too many argumnents pushed", G_STRLOC);
return FALSE;
}
bval = g_new (BOOL, 1);
*bval = g_value_get_boolean (gvalue) ? 1 : 0;
freelist[(*n_freelist)++] = bval;
*arg_type = &ffi_type_sint;
*arg_val = bval;
break;
case G_TYPE_STRING:
case G_TYPE_OBJECT:
case G_TYPE_BOXED:
*arg_type = &ffi_type_pointer;
*arg_val = &gvalue->data[0].v_pointer;
break;
case G_TYPE_CHAR:
case G_TYPE_INT:
case G_TYPE_ENUM:
case G_TYPE_FLAGS:
*arg_type = &ffi_type_sint;
*arg_val = &gvalue->data[0].v_int;
break;
case G_TYPE_UCHAR:
case G_TYPE_UINT:
*arg_type = &ffi_type_uint;
*arg_val = &gvalue->data[0].v_uint;
break;
case G_TYPE_LONG:
*arg_type = &ffi_type_slong;
*arg_val = &gvalue->data[0].v_long;
break;
case G_TYPE_ULONG:
*arg_type = &ffi_type_ulong;
*arg_val = &gvalue->data[0].v_ulong;
break;
case G_TYPE_INT64:
*arg_type = &ffi_type_sint64;
*arg_val = &gvalue->data[0].v_int64;
break;
case G_TYPE_UINT64:
*arg_type = &ffi_type_uint64;
*arg_val = &gvalue->data[0].v_uint64;
break;
case G_TYPE_FLOAT:
*arg_type = &ffi_type_float;
*arg_val = &gvalue->data[0].v_float;
break;
case G_TYPE_DOUBLE:
*arg_type = &ffi_type_double;
*arg_val = &gvalue->data[0].v_double;
break;
case G_TYPE_POINTER:
*arg_type = &ffi_type_pointer;
*arg_val = &gvalue->data[0].v_pointer;
break;
case G_TYPE_PARAM:
default:
g_warning ("Unsupported argument type: %s",
g_type_name (G_VALUE_TYPE (gvalue)));
return FALSE;
}
return TRUE;
}
static gboolean
get_ffi_type_for_return (GValue *gvalue,
ffi_type **ret_type,
gpointer *ret_val,
gpointer *freelist,
guint *n_freelist)
{
BOOL *bval;
switch (g_type_fundamental (G_VALUE_TYPE (gvalue)))
{
case G_TYPE_BOOLEAN:
if (*n_freelist == MAX_N_FREELIST)
{
g_warning ("%s: too many argumnents pushed", G_STRLOC);
return FALSE;
}
bval = g_new (BOOL, 1);
*bval = 0;
freelist[(*n_freelist)++] = bval;
*ret_type = &ffi_type_sint;
*ret_val = bval;
break;
case G_TYPE_STRING:
case G_TYPE_OBJECT:
case G_TYPE_BOXED:
*ret_type = &ffi_type_pointer;
*ret_val = &gvalue->data[0].v_pointer;
break;
case G_TYPE_CHAR:
case G_TYPE_INT:
case G_TYPE_ENUM:
case G_TYPE_FLAGS:
*ret_type = &ffi_type_sint;
*ret_val = &gvalue->data[0].v_int;
break;
case G_TYPE_UCHAR:
case G_TYPE_UINT:
*ret_type = &ffi_type_uint;
*ret_val = &gvalue->data[0].v_uint;
break;
case G_TYPE_LONG:
*ret_type = &ffi_type_slong;
*ret_val = &gvalue->data[0].v_long;
break;
case G_TYPE_ULONG:
*ret_type = &ffi_type_ulong;
*ret_val = &gvalue->data[0].v_ulong;
break;
case G_TYPE_INT64:
*ret_type = &ffi_type_sint64;
*ret_val = &gvalue->data[0].v_int64;
break;
case G_TYPE_UINT64:
*ret_type = &ffi_type_uint64;
*ret_val = &gvalue->data[0].v_uint64;
break;
case G_TYPE_FLOAT:
*ret_type = &ffi_type_float;
*ret_val = &gvalue->data[0].v_float;
break;
case G_TYPE_DOUBLE:
*ret_type = &ffi_type_double;
*ret_val = &gvalue->data[0].v_double;
break;
case G_TYPE_POINTER:
*ret_type = &ffi_type_pointer;
*ret_val = &gvalue->data[0].v_pointer;
break;
case G_TYPE_PARAM:
default:
g_warning ("Unsupported argument type: %s",
g_type_name (G_VALUE_TYPE (gvalue)));
return FALSE;
}
return TRUE;
}
static void
convert_return_value (gpointer ptr,
GValue *gvalue)
{
BOOL *bval;
switch (g_type_fundamental (G_VALUE_TYPE (gvalue)))
{
case G_TYPE_BOOLEAN:
bval = ptr;
g_value_set_boolean (gvalue, *bval);
break;
case G_TYPE_STRING:
case G_TYPE_OBJECT:
case G_TYPE_BOXED:
case G_TYPE_POINTER:
break;
case G_TYPE_CHAR:
case G_TYPE_INT:
case G_TYPE_ENUM:
case G_TYPE_FLAGS:
case G_TYPE_UCHAR:
case G_TYPE_UINT:
case G_TYPE_LONG:
case G_TYPE_ULONG:
case G_TYPE_INT64:
case G_TYPE_UINT64:
case G_TYPE_FLOAT:
case G_TYPE_DOUBLE:
break;
case G_TYPE_PARAM:
default:
g_return_if_reached ();
}
}
static void
do_marshal (GCallback callback,
id add_obj,
SEL add_sel,
GValue *return_value,
guint n_params,
const GValue *params,
id data,
gboolean use_data,
gboolean swap)
{
ffi_cif cif;
ffi_type *ret_type, **arg_types;
guint i_arg, i, n_args;
gpointer ret_val, *arg_vals;
gpointer freelist[MAX_N_FREELIST];
guint n_freelist = 0;
/* params: object arg1 ... argN */
n_args = use_data ? n_params + 1 : n_params;
if (add_obj)
n_args += 2;
arg_types = g_new (ffi_type*, n_args);
arg_vals = g_new (gpointer, n_args);
i_arg = 0;
if (data)
[data retain];
if (add_obj)
[add_obj retain];
/*
if (use_data)
if (swap)
callback (data, arg1, ..., argN, object)
else
callback (object, arg1, ..., argN, data)
else
if (swap)
callback (arg1, ..., argN, object)
else
callback (object, arg1, ..., argN)
*/
/* Return value */
if (return_value)
{
if (!get_ffi_type_for_return (return_value, &ret_type, &ret_val,
freelist, &n_freelist))
goto out;
}
else
{
ret_type = &ffi_type_void;
ret_val = NULL;
}
if (add_obj)
{
arg_types[0] = &ffi_type_pointer;
arg_vals[0] = &add_obj;
arg_types[1] = &ffi_type_pointer;
arg_vals[1] = &add_sel;
i_arg = 2;
}
if (use_data && swap)
{
arg_types[i_arg] = &ffi_type_pointer;
arg_vals[i_arg] = &data;
i_arg++;
}
else if (!swap)
{
if (!get_ffi_type (&params[0], &arg_types[i_arg], &arg_vals[i_arg],
freelist, &n_freelist))
goto out;
i_arg++;
}
for (i = 1; i < n_params; ++i, ++i_arg)
{
if (!get_ffi_type (&params[i], &arg_types[i_arg], &arg_vals[i_arg],
freelist, &n_freelist))
goto out;
}
if (use_data && !swap)
{
arg_types[i_arg] = &ffi_type_pointer;
arg_vals[i_arg] = &data;
i_arg++;
}
else if (swap)
{
if (!get_ffi_type (&params[0], &arg_types[i_arg], &arg_vals[i_arg],
freelist, &n_freelist))
goto out;
i_arg++;
}
g_assert (i_arg == n_args);
if (ffi_prep_cif (&cif, FFI_DEFAULT_ABI, n_args, ret_type, arg_types) != FFI_OK)
goto out;
ffi_call (&cif, FFI_FN (callback), ret_val, arg_vals);
if (return_value)
convert_return_value (ret_val, return_value);
out:
if (data)
[data release];
if (add_obj)
[add_obj release];
for (i = 0; i < n_freelist; ++i)
g_free (freelist[i]);
g_free (arg_types);
g_free (arg_vals);
}
void
_moo_objc_marshal (GCallback callback,
id add_obj,
SEL add_sel,
GValue *return_value,
guint n_params,
const GValue *params,
id data,
gboolean use_data,
gboolean swap)
{
do_marshal (callback, add_obj, add_sel,
return_value, n_params, params,
data, use_data, swap);
}
/* -*- objc -*- */