Planet maemo: category "feed:70bebeb934a26428d85371654b6c3163"
Wow, something I think I would not see, but GUADEC is happening less than 3km from home in less than a week!
I have collaborated in organizing the Lightning Talks and BoFs/Hackfests and of course, I’ll help wherever I can. Poor Zeenix will be at my place so he will need to wake up early to come with me and my wife Laura to the faculty.
I also want to thank Igalia for sponsoring me with time to help organizing and attending the event and I might be also helping the Advisory Board meeting that will happen at Igalia headquarters on the 25th.
As I already said the other day in Twitter, I became Qt Ambassador because of Aura. The only problem is that is a project-person program, meaning that it is granted to a person because of having worked on a project. Aura was a project developed by three Igalians, who were Miguel, Víctor and me and I consider a bit unfair that it was granted only to me because they deserve it as much as I do.
The procedure I followed was:
- Applying with Aura
- When that was accepted, I submitted Aura project page.
- After the publication I was told that I was going to receive the Qt Ambassador Merchansise
Does anybody know if more people can become ambassadors for the same project and how?
In the context of a personal ad-hoc app (I will come to that later) that I wrote for my Nokia N9, I needed to send an email to a specific person with an attachment. After the first research at Harmattan APIs you come to QMessageService.
The first thing I did was writing Mixed QML/Qt object that I could instantiate from the QML code so that I could do something like:
Message { id: message from: "my@Address" to: [ "destination@Address" ] subject: "This is not Spam for sure!" body: "Trolled! Enlarge...!" attachments: [ "/a/path/to/an/attachment" ] } Button { onClicked: message.compose() // onClicked: message.send() }
There we have an object with two send
and compose
methods, three string properties representing the from, subject and body and two string list properties representing the to and attachments (we leave the CC and BCC as an exercise
As part of my work at Igalia I had to work with video and GStreamer for some years. I always used Gtk+ for that so when I needed to do things with Qt and QML, things were different. In my projects I always used pure GStreamer code instead of the Qt bindings for GStreamer because at the moment those bindings were not ready or reliable.
As part of my work at Igalia I had to work with video and GStreamer for some years. I always used Gtk+ for that so when I needed to do things with Qt and QML, things were different. In my projects I always used pure GStreamer code instead of the Qt bindings for GStreamer because at the moment those bindings were not ready or reliable.
As my colleague Víctor at Igalia has said before in his post, Aura was released to the Nokia Store. Miguel, Víctor and I are quite happy with the result achieved with this app, which intention was to be kind of a port of the Cheese application of the GNOME platform to be used in the N9 or N950 Nokia phones.
The apps allows you to use both cameras (front and principal) to record videos, applying a lot of funny effects (a subset of the GNOME Video Effects) and changing them during the recording. Being Nokia a Finnish company, we decided to name the app after a Finnish Cheese to both honor the GNOME Cheese application and Finland
As part of my work at Igalia I am writing an app to record some videos for the Nokia N9. I wanted to get them shown in the gallery so I tried the DBUS approach, that is something similar to what is explained here. The problem is the same they faced, meaning that I got gallery in foreground when it was not previously running, but not otherwise.
The solution to that was using libcontentaction. In order to get this working, first you need to get the vendor name in the tags of your pictures or videos, otherwise Tracker will not index them correctly and this solution can be useless.
With the following solution Gallery will be brought to foreground and show the desired file. Code would be something like:
using ContentAction::Action; [...] { Action action = Action::defaultActionForFile(uri, "x-maemo-nepomuk/device-captured-video"); if (action.isValid()) { qDebug() < < Q_FUNC_INFO << "chosen action:" << action.name(); action.triggerAndWait(); } else { qWarning() << "could not file action for" << m_file; } }
The mime type is one of the defined in the galleryserviceaction.desktop
that you can find in the device. For images, you can also check the mime types in that file and maybe you do not need to specify it, but I have not tried this and let it to you. Please, comment me your findings.
Some days ago I was writing about how to have mixed QML/C++ objects in a QML application for Igalia, but I faced a problem with the code that I had written. And the problem was that I needed to receive some events and from the QML elements I was loading. Retaking that code:
#define QML_PATH "/path/to/the/qml/files/" MyObject::MyObject(QDeclarativeItem *parent = 0) : QDeclarativeItem(parent) { QDeclarativeEngine engine; QDeclarativeComponent component(&engine, QUrl::fromLocalFile(QML_PATH "MyObject.qml")); QDeclarativeItem *rect = dynamic_cast(component.create()); rect->setParentItem(this); }
and being MyObject.qml something like:
Button { id: "myButton" text: "Do something cool" }
The natural way of connecting that button to some slot you are writing would be something like:
MyObject::MyObject(QDeclarativeItem *parent = 0) : QDeclarativeItem(parent) { QDeclarativeEngine engine; QDeclarativeComponent component(&engine, QUrl::fromLocalFile(QML_PATH "MyObject.qml")); QDeclarativeItem *item = dynamic_cast(component.create()); item->setParentItem(this); connect(item, SIGNAL(clicked()), this, SLOT(doCoolStuff())); }
Even if you do this, you are not getting any event in the QML button you declare. It behaves as it were a label or whatever, but the key is the engine. The engine must live while you need the events of the QML component. And the easiest way of getting that done is adding the engine as a private class attribute:
#ifndef MYOBJECT_H #define MYOBJECT_H #include #include #include class PostCapture : public QDeclarativeItem { Q_OBJECT // ... private slots: void doCoolStuff(); private: QDeclarativeEngine m_engine; }; #endif
and of course removing the engine stack declaration from the constructor:
MyObject::MyObject(QDeclarativeItem *parent = 0) : QDeclarativeItem(parent) { QDeclarativeComponent component(&m_engine, QUrl::fromLocalFile(QML_PATH "MyObject.qml")); QDeclarativeItem *item = dynamic_cast(component.create()); item->setParentItem(this); connect(item, SIGNAL(clicked()), this, SLOT(doCoolStuff())); }
Voilà.
Of course, if you need to connect to any element that is not the root element, you can always forward the signals and properties from the QML root object or just use the QObject::findChild method to access the right component.
One of the good things of QML is that you can have both C++ and QML code and interact between them. For example, from C++, you can access the QML tree and invoke methods, change properties, etc.
The other way around, you can also define C++ objects and interact with them from QML. Here you have two ways of doing it:
- Instantiating from C++ and adding the objects to the QML context, meaning that you can invoke the public slots and access the properties.
- Registering the QML type with
qmlRegisterType
and then instantiating it from QML.
At the Qt documentation you can find examples about how to implement the different approaches so I won’t talk too much about them and I’ll focus in a special case of the last approach.
Let’s see a QML code like this:
Item { id: myObject function doCoolStuff() { // doing really cool stuff here } Rectangle { anchors.fill: parent color: "red" } } Button { text: "Do cool stuff!" onClicked: myObject.doCoolStuff() }
Imagine now that painting that rectangle is something that must be really done by your object, because it is needed and inherent to it, and so is the function. If the code is written only in QML, the answer is obvious, just move the whole Item
code to a .qml file and leave the main code like this:
MyObject { id: myObject } Button { text: "Do cool stuff!" onClicked: myObject.doCoolStuff() }
Let’s suppose that you need some C++ code in that object for whatever reason (you want to use some GNOME library, for instance). In this case you need to write it in C++ to define the public slots in that language. Our first step would be something like this:
#include <QtCore> #include <QtDeclarative> class MyObject : public QDeclarativeItem { Q_OBJECT // Define some Q_PROPERTY here with its methods public slots: void doCoolStuff(void); // We could even define some signals };
For the slot, it does not matter if you declare it as slot or with Q_INVOKABLE
because QML will see it both ways. Of course, don’t forget to write the cpp file with the implementation for the slot
.
I travel sponsored by Igalia.
I was writing some tests for a project at Igalia and I need to mock the convert-frame playbin2 element action. The code to invoke it is something like this:
GstElement *pipeline = /* get pipeline */; GstCaps *caps = /* create caps to adapt the conversion */; GstBuffer *buffer = NULL; g_signal_emit_by_name (pipeline, "convert-frame", caps, &buffer);
When you are writing tests, what you want to do is testing just your code and not to depend on something external, so in this case the idea would be providing a fake implementation for that GStreamer element action.
The way you can do this kind of things is providing the symbol in your code so that the linker when doing its job does not look any further and uses that instead of the one in the external library, so the natural solution coming to your mind would be rewriting g_signal_emit_by_name
. The problem with this is that though you are not using it in your code, it is too general, so it is not a good idea.
I thought I could replace the convert-frame action in the playbin2 class, so I wrote this code:
typedef struct { GstPipelineClass parent_class; void (*about_to_finish) (gpointer playbin); void (*video_changed) (gpointer playbin); void (*audio_changed) (gpointer playbin); void (*text_changed) (gpointer playbin); void (*video_tags_changed) (gpointer playbin, gint stream); void (*audio_tags_changed) (gpointer playbin, gint stream); void (*text_tags_changed) (gpointer playbin, gint stream); GstTagList *(*get_video_tags) (gpointer playbin, gint stream); GstTagList *(*get_audio_tags) (gpointer playbin, gint stream); GstTagList *(*get_text_tags) (gpointer playbin, gint stream); GstBuffer *(*convert_frame) (gpointer playbin, GstCaps * caps); GstPad *(*get_video_pad) (gpointer playbin, gint stream); GstPad *(*get_audio_pad) (gpointer playbin, gint stream); GstPad *(*get_text_pad) (gpointer playbin, gint stream); } GstPlayBinClass; static gpointer gst_play_bin_convert_frame (G_GNUC_UNUSED gpointer playbin, G_GNUC_UNUSED gpointer caps) { GstBuffer *buffer; /* Create my own GstBuffer with the data I need */ return buffer; } void simulator_gst_reset(GstElement *new_pipeline, GstBus *new_bus) { /* ... */ GstPlayBinClass *klass = G_TYPE_INSTANCE_GET_CLASS(new_pipeline, GST_PLAY_BIN_TYPE, GstPlayBinClass); klass->convert_frame = (gpointer) gst_play_bin_convert_frame; /* ... */ }
First I declared the GstPlayBinClass copying it from the GStreamer code. I didn’t change any parameters order, just replaced some pointers with gpointer as we don’t need them. This way you don’t break the ABI. Then you can declare your own element action code and finally you get the Class, assign the method and voilà!.
As I said, the solution is far from being the best, but if you know a better way, drop me a comment.