[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-bindings
Subject:    Re: [Kde-bindings] I need help with SMOKE (trying to write bindings
From:       Ashley Winters <jahqueel () yahoo ! com>
Date:       2005-10-10 1:08:18
Message-ID: 20051010010819.43099.qmail () web50910 ! mail ! yahoo ! com
[Download RAW message or body]

--- Clifford Wolf <clifford@clifford.at> wrote:
> Hi,
> 
> I'm trying to write Qt+KDE bindings for SPL
> (http://www.clifford.at/spl/)
> using SMOKE. My idea was to first write a little C program which only
> implemnts those parst of the iterface required for a little "Hello
> World"
> program, than make it an SPL module and finally add the missing code
> for
> the bindings to be complete.
> 

[...]

> I think with this two informations I should be able to write a small
> app
> which does the following with the SMOKE wrapper library:
> 
> 	#include <qt3/qapplication.h>
> 	#include <qt3/qlabel.h>
> 
> 	int main(int argc, char **argv)
> 	{
> 		QApplication *a = new QApplication(argc, argv);
> 		QWidget *l = new QLabel("Hello World!", NULL);
> 		a->setMainWidget(l);
> 		l->show();
> 		a->exec();
> 		return 0;
> 	}

I attached a working version of that program using Smoke. It's written
so that you don't link directly to -lsmokeqt, but dlopen() it. Ideally,
that would be portable, but the init() function isn't declared as
extern "C". The portable way is to link with -lsmokeqt directly, but I
don't really like that. Oh well. If Richard can patch Smoke with a new
version of the init() function, that'd be nifty:

extern void init_qt_Smoke();
extern "C" init_libsmokeqt() { init_qt_Smoke(); }

Compile with:
g++ -g -o hello hello.c -lqt-mt

and make sure you have libsmokeqt installed where it can be found --
either in your default lib path, or by setting LD_LIBRARY_PATH

Cheers,
Ashley Winters


	
		
__________________________________ 
Yahoo! Mail - PC Magazine Editors' Choice 2005 
http://mail.yahoo.com
["hello.c" (text/x-csrc)]

#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <qt3/qstring.h>
#include "smoke.h"

// don't add any behaviors -- just let everything work
class MySmokeBinding : public SmokeBinding {
public:
    MySmokeBinding(Smoke *s) : SmokeBinding(s) {}
    virtual void deleted(Smoke::Index, void*) {
        // ignore object deletion
    }
    virtual bool callMethod(Smoke::Index, void*, Smoke::Stack, bool) {
        return false;   // decline all offers to override a virtual function
    }
    virtual char *className(Smoke::Index classId) {
        // return a new[] copy of the language-specific name of this Smoke class
        // poorly designed function, but oh well. Sorry.

        const char *className = smoke->className(classId);
        char *buf = new char[strlen(className) + 1];
        strcpy(buf, className);
        return buf;
    }
    virtual ~MySmokeBinding() {}
};

// call init function, and return the master Smoke* object
Smoke *init_smoke() {
    typedef void (*smoke_init_func)();

    void *lib = dlopen("libsmokeqt.so.1", RTLD_NOW);
    if(!lib) {
        fprintf(stderr, "Unable to open Smoke: %s", dlerror());
        exit(-1);
    }

    smoke_init_func init = (smoke_init_func)dlsym(lib, "init_libsmokeqt");   /* \
extern "C" version -- requires latest version */  if(!init) init = \
(smoke_init_func)dlsym(lib, "_Z13init_qt_Smokev");   /* Linux ABI version -- old */  \
if(!init) {  dlclose(lib);
        return 0;
    }

    init();
    void *qt_smoke = dlsym(lib, "qt_Smoke");
    return *(Smoke**)qt_smoke;
}

// given class-name and mangled function-name, return an unambiguous method ID
Smoke::Index getMethod(Smoke *smoke, const char* c, const char* m) {
    Smoke::Index method = smoke->findMethod(c, m);
    Smoke::Index i = smoke->methodMaps[method].method;
    if(i <= 0) {
        // ambiguous method have i < 0; it's possible to resolve them, see the other \
bindings  fprintf(stderr, "%s method %s::%s\n",
            i ? "Ambiguous" : "Unknown", c, m);
        exit(-1);
    }
    return i;
}

// call obj->method(args)
void callMethod(Smoke *smoke, void *obj, Smoke::Index method, Smoke::Stack args) {
    Smoke::Method *m = smoke->methods + method;
    Smoke::ClassFn fn = smoke->classes[m->classId].classFn;
    fn(m->method, obj, args);
}

// cast argument pointer to the correct type for the specified method argument
// args[i].s_class = (void*)(typeof(args[i]))(className*)obj
void smokeCast(Smoke *smoke, Smoke::Index method, Smoke::Stack args, Smoke::Index i, \
void *obj, const char *className) {  // cast obj from className to the desired type \
of args[i]  Smoke::Index arg = smoke->argumentList[
        smoke->methods[method].args + i - 1
    ];
    // cast(obj, from_type, to_type)
    args[i].s_class = smoke->cast(obj, smoke->idClass(className), \
smoke->types[arg].classId); }

// cast obj to the required type of this, which, dur to multiple-inheritance, could \
change the pointer-address // from the one returned by new. Puts the pointer in \
args[0].s_class, even though smoke doesn't do it that way void smokeCastThis(Smoke \
*smoke, Smoke::Index method, Smoke::Stack args, void *obj, const char *className) {  \
args[0].s_class = smoke->cast(obj, smoke->idClass(className), \
smoke->methods[method].classId); }

int main(int argc, char **argv) {
    Smoke *smoke = init_smoke();

    smoke->binding = new MySmokeBinding(smoke);

    void *qapp;
    {
        // new QApplication(argc, argv)
        Smoke::Index method = getMethod(smoke, "QApplication", "QApplication$?");
        Smoke::StackItem args[3];
        args[1].s_voidp = (void*)&argc;
        args[2].s_voidp = (void*)argv;
        callMethod(smoke, 0, method, args);

        qapp = args[0].s_class;
    }

    void *l;
    {
        // new QLabel(QString("Hello World!"), (QWidget*)0)
        Smoke::Index method = getMethod(smoke, "QLabel", "QLabel$#");
        Smoke::StackItem args[3];
        QString s("Hello World!");
        args[1].s_voidp = (void*)&s;
        args[2].s_class = 0;
        callMethod(smoke, 0, method, args);
        l = args[0].s_class;
    }

    {
        // qapp->setMainWidget(l)
        Smoke::Index method = getMethod(smoke, "QApplication", "setMainWidget#");
        Smoke::StackItem args[2];
        smokeCast(smoke, method, args, 1, l, "QLabel");
        smokeCastThis(smoke, method, args, qapp, "QApplication");
        callMethod(smoke, args[0].s_class, method, args);
    }

    {
        // l->show()
        Smoke::Index method = getMethod(smoke, "QLabel", "show");
        Smoke::StackItem args[1];
        smokeCastThis(smoke, method, args, l, "QLabel");
        callMethod(smoke, args[0].s_class, method, args);
    }

    {
        // return qapp->exec()
        Smoke::Index method = getMethod(smoke, "QApplication", "exec");
        Smoke::StackItem args[1];
        smokeCastThis(smoke, method, args, qapp, "QApplication");
        callMethod(smoke, args[0].s_class, method, args);
        return args[0].s_int;
    }
}



_______________________________________________
Kde-bindings mailing list
Kde-bindings@kde.org
https://mail.kde.org/mailman/listinfo/kde-bindings


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic