Using C, how to pass a string to the Smoke C++ API

248 views Asked by At

Smoke provides an introspective C++ API wrapper to the Qt framework.
https://techbase.kde.org/Development/Languages/Smoke
https://techbase.kde.org/Development/Languages/Smoke/API_Documentation

SmokeC wraps the the Smoke wrapper with C functions to facilitate using the Smoke API from C.
https://github.com/pankajp/pysmoke/blob/master/smokec/smokec.cpp

Working example application in C (functionally identical to the C++ example in the first link above):
https://github.com/pankajp/pysmoke/blob/master/examples/hellowidget.c

I'm trying to modify this example application and add further calls to QWidget object methods, but I can't figure out how to call a method that takes a QString argument, such as setWindowTitle, whose signature is

void setWindowTitle(const QString &);

Here's my best guess:

/* Set the window title... Segfaults */    
methId = Smoke_findMethod(classId.smoke, "QWidget", "setWindowTitle$");
klass = Smoke_classes(classId.smoke)[classId.index];
meth = Smoke_methods(methId.smoke)[Smoke_methodMaps(methId.smoke)[methId.index].method];
stack[1].s_voidp = (void*)"hello universe";
(*klass.classFn)(meth.method, widget, stack);

... but this segfaults. Can anyone advise how I should construct a QString argument using the SmokeC wrapper?

My complete modified example application follows.

/* 
 * File:   hellowidget.c
 * Author: pankaj
 *
 * Created on November 19, 2013, 2:41 PM
 */


#include <stdio.h>
#include <string.h>
#include "smokec.h"
#include "bindings.h"


/*
 * In a bindings runtime, this should return the classname as used
 * in the bindings language, e.g. Qt::Widget in Ruby or
 * Qyoto.QWidget in C# or QtGui.QWidget in python
 */
char *className(CSmokeBinding binding, Index classId) {
    return (char*) Smoke_classes(CSmoke_FromBinding(binding))[classId].className;
}


void deleted(CSmokeBinding binding, Index classId, void *obj) 
{
}

cbool callMethod(CSmokeBinding binding, Index method, void *obj, Stack args, cbool isAbstract)
{
    return 0;
}


int main(int argc, char **argv)
{
    /* Initialize the Qt SMOKE runtime. */
    init_qtcore_CSmoke();
    init_qtgui_CSmoke();

    CSmoke qtcore_smoke = qtcore_CSmoke();
    CSmoke qtgui_smoke = qtgui_CSmoke();

    /* Create a SmokeBinding for the Qt SMOKE runtime. */
    CSmokeBinding qtcoreBinding = SmokeBinding_new(qtcore_smoke, deleted, callMethod, className);
    CSmokeBinding qtguiBinding = SmokeBinding_new(qtgui_smoke, deleted, callMethod, className);

    /* Find the 'QApplication' class. */
    CModuleIndex classId = findClass("QApplication");
    /* find the methodId. we use a munged method signature, where
     * $ is a plain scalar
     * # is an object
     * ? is a non-scalar (reference to array or hash, undef) */
    CModuleIndex methId = Smoke_findMethod(classId.smoke, "QApplication", "QApplication$?");  // find the constructor

    /* Get the Smoke::Class */
    Class klass = Smoke_classes(classId.smoke)[classId.index];

    // findMethod() returns an index into methodMaps, which has
    // information about the classId, methodNameId and methodId. we
    // are interested in the methodId to get a Smoke::Method
    Method meth = Smoke_methods(methId.smoke)[Smoke_methodMaps(methId.smoke)[methId.index].method];

    StackItem stack[3];
    // QApplication expects a reference to argc, so we pass it as a pointer
    stack[1].s_voidp = &argc;
    stack[2].s_voidp = argv;
    // call the constructor, Smoke::Method::method is the methodId
    // specifically for this class.
    (*klass.classFn)(meth.method, 0, stack);

    // the zeroth element contains the return value, in this case the
    // QApplication instance
    void *qapp = stack[0].s_voidp;

    // method index 0 is always "set smoke binding" - needed for
    // virtual method callbacks etc.
    stack[1].s_voidp = qtguiBinding.binding;
    (*klass.classFn)(0, qapp, stack);



    // create a widget
    classId = findClass("QWidget");
    methId = Smoke_findMethod(classId.smoke, "QWidget", "QWidget");

    klass = Smoke_classes(classId.smoke)[classId.index];
    meth = Smoke_methods(methId.smoke)[Smoke_methodMaps(methId.smoke)[methId.index].method];
    (*klass.classFn)(meth.method, 0, stack);

    void *widget = stack[0].s_voidp;
    // set the smoke binding
    stack[1].s_voidp = qtguiBinding.binding;
    (*klass.classFn)(0, widget, stack);

    /* Show the widget maximized.*/
    methId = Smoke_findMethod(classId.smoke, "QWidget", "showMaximized");
    meth = Smoke_methods(methId.smoke)[Smoke_methodMaps(methId.smoke)[methId.index].method];
    (*klass.classFn)(meth.method, widget, 0);

    /* Raise the window to the foreground */
    methId = Smoke_findMethod(classId.smoke, "QWidget", "raise");
    meth = Smoke_methods(methId.smoke)[Smoke_methodMaps(methId.smoke)[methId.index].method];
    (*klass.classFn)(meth.method, widget, 0);

    /* Set the modified indicator. */
    methId = Smoke_findMethod(classId.smoke, "QWidget", "setWindowModified$");
    meth = Smoke_methods(methId.smoke)[Smoke_methodMaps(methId.smoke)[methId.index].method];
    stack[1].s_bool = 1;
    (*klass.classFn)(meth.method, widget, stack);

    /* Set the window title... Segfaults */    
    methId = Smoke_findMethod(classId.smoke, "QWidget", "setWindowTitle$");
    klass = Smoke_classes(classId.smoke)[classId.index];
    meth = Smoke_methods(methId.smoke)[Smoke_methodMaps(methId.smoke)[methId.index].method];
    stack[1].s_voidp = (void*)"hello universe";
    (*klass.classFn)(meth.method, widget, stack);


    // we don't even need findClass() when we use the classId provided
    // by the MethodMap
    methId = Smoke_findMethod(qtgui_smoke, "QApplication", "exec");

    klass = Smoke_classes(methId.smoke)[Smoke_methodMaps(methId.smoke)[methId.index].classId];
    meth = Smoke_methods(methId.smoke)[Smoke_methodMaps(methId.smoke)[methId.index].method];

    // call QApplication::exec()
    (*klass.classFn)(meth.method, 0, stack);

    // store the return value of QApplication::exec()
    int retval = stack[0].s_int;

    // destroy the QApplication instance
    methId = Smoke_findMethod(qtgui_smoke, "QApplication", "~QApplication");

    meth = Smoke_methods(methId.smoke)[Smoke_methodMaps(methId.smoke)[methId.index].method];
    (*klass.classFn)(meth.method, qapp, 0);

    // destroy the smoke instance
    CSmoke_delete(qtgui_smoke);
    CSmoke_delete(qtcore_smoke);

    // return the previously stored value
    return retval;
}
0

There are 0 answers