Subscribe: Planet Maemo
http://maemo.org/news/planet-maemo/rss091.xml
Added By: Feedage Forager Feedage Grade B rated
Language: English
Tags:
abstractcommand  bool  commands  decl override  include  new  parent  public  qobject parent  qobject  qsharedpointer  void  work 
Rate this Feed
Rate this feedRate this feedRate this feedRate this feedRate this feed
Rate this feed 1 starRate this feed 2 starRate this feed 3 starRate this feed 4 starRate this feed 5 star

Comments (0)

Feed Details and Statistics Feed Statistics
Preview: Planet Maemo

Planet Maemo



Blog entries from Maemo community



Last Build Date: Thu, 18 Jan 2018 06:45:29 +0000

 






Semrush, MJ12 and DotBot just slow down your server

Fri, 17 Nov 2017 20:02:07 +0000

I recently migrated a server to a new VHost that was supposed to improve the performance – however after the upgrade the performance actually was worse.

Looking at the system load I discovered that the load average was at about 3.5 – with only 2 cores available this corresponds to server overload by almost 2x.

Further looking at the logs revealed that this unfortunately was not due to the users taking interest in the site, but due to various bots hammering on the server. Actual users would be probably drawn away by the awful page load times at this point.

Asking the bots to leave

To improve page loading times, I configured my robots.txt as following

User-agent: *
Disallow: /

This effectively tells all bots to skip my site. You should not do this as you will not be discoverable at e.g. Google.

But here I just wanted to allow my existing users to use the site. Unfortunately the situation only slightly improve; the system load was still over 2.

From the logs I could tell that all bots were actually gone, except for

  • SemrushBot by semrush.com
  • MJ12Bot by majestic.com
  • DotBot by Moz.com

But those were enough to keep the site (PHP+MySQL) overloaded.

The above bots crawl the web for their respective SEO analytics company which sell this information to webmasters. This means that unless you are already a customer of these companies, you do not benefit from having your site crawled.

In fact, if you are interested in SEO analytics for your website, you should probably look elsewhere. In the next paragraph we will block these bots and I am by far not the first one recommending this.

Making the bots leave

As the bots do not respect the robots.txt, you will have to forcefully block them. Instead of the actual webpages, we will give them a 410/ 403 which prevents them touching any PHP/ MySQL resources.

On nginx, add this to your server section:

if ($http_user_agent ~* (SemrushBot|MJ12Bot|DotBot)) {
     return 410;
}

For Apache2.4+ do:

BrowserMatchNoCase SemrushBot bad_bot
BrowserMatchNoCase MJ12Bot bad_bot
BrowserMatchNoCase DotBot bad_bot
Order Deny,Allow
Deny from env=bad_bot

For additional fun you could also given them a 307 (redirect) to their own websites here.

0 (image) 0 (image)



Q1 2018 Community Council Election Announcement

Tue, 07 Nov 2017 21:04:14 +0000

Dear Maemoans and fellow humans. The time has come again to elect a new Community Council for Q1/2018. The schedule for the voting process is as follows, according to the election rules: The nomination period of at least 2 weeks starts tomorrow, on the 8th of November 2017 and will continue until the 3rd of December 2017. The one week election starts on Friday, the 8th of December 2017 and will continue until the 14th of December 2017. In order for us to keep the community strong, it would be great to have new people with fresh ideas to carry on the torch. Please consider volunteering for the position of Maemo Council. On behalf of the outgoing Community Council, mosen0 (image) 0 (image)



C++ matrix maths – library performance

Sun, 05 Nov 2017 01:47:26 +0000

Recently I have been look on the Ogre Matrix class which has a fairly un-optimized, but straightforward implementation, that you can see here.
I was wondering how it compares.

Of course somebody had a similar question in mind before. Martin Foot that is. While the discussion still applies today, I felt like the results could have changed since 2012 as libraries and compilers have moved on.

So I forked his code to update the libs to the latest versions and came up with the following results:

Library add (x86_64, SSSE3) mult (x86_64, SSSE3) add (armeabi-v7a, NEON) mult (armeabi-v7a, NEON)
Eigen3 17 ms 53 ms 173 ms 399 ms
GLM 50 ms 186 ms 232 ms 399 ms
Ogre 50 ms 184 ms 232 ms 399 ms
CML1 116 ms 348 ms 178 ms 489 ms

The used compiler was gcc with optimization level -O2.

As we can see Eigen3 just downgrades the rest on x86_64 – probably due its explicit vectorization. Notably, CLM1 is having some issues and even falls behind the naive implementations.
On ARM the results are more tight. With Eigen3 and CLM1 being about 25% faster at addition. However CML1 again has some issues with the mult test.

We end up with Eigen3 being the overall winner and GLM being second (Ogre does not count as it is not a Math library).

Also you should migrate away from CLM1 as the development focus shifted to CLM2 and the issues found above are probably not going to be resolved.

0 (image) 0 (image)



Switching Apache2 to php-fpm for performance

Fri, 27 Oct 2017 14:43:19 +0000

there are many articles on the internet telling you to switch from Apache & mod_php to nginx to get better performance. However the main reason for performance improvement is not nginx itself but rather the way it integrates PHP. Different ways to integrate PHP Apache traditionally used mod_php to embed the PHP interpreter inside Apache HTTP request handler. This way it can directly interpret PHP scripts whereas with CGI it would have to start a new PHP interpreter process first – per request. The drawback however is that the PHP interpreter is embedded in all request handlers – even those that just serve static files. This obviously blows up memory consumption which in turn can lower performance. Nginx on the other hand uses the FCGI approach where a pool of PHP processes is started along the webserver using the FCGI process manager, FPM. The webserver then delegates individual requests using the FCGI protocol as needed. This avoids the PHP interpreter startup costs as well as starting it without a need and is the reason nginx is faster then mod_php. However since Apache 2.4 one can also use FCGI to integrate PHP and get virtually the same characteristics like nginx. Sticking with Apache saves you migrating all the .htaccess rules and means an easier setup for many webapps. Furthermore since Apache 2.4.10 one can use mod_proxy_fcgi for a reverse-proxy configuration which further reduces the occupied PHP workers in the FPM pool for better performance. Configuration on Ubuntu 16.04 Switching to FCGI on Ubuntu 16.04 is quite easy. The needed module are installed by default and just need to be enabled: a2enmod proxy_fcgi && a2dismod php7.0 Then inside your-site.conf add # PHP-FPM SetHandler "proxy:unix:/var/run/php/php7.0-fpm.sock|fcgi://localhost/" this connects Apache in reverse proxy mode to the PHP-FPM pool using unix domain sockets for optimal performance. See the Apache Wiki for details. Note that php-fpm by default only creates 5 PHP worker processes, which in turn limits the maximal simultaneous connections. You might want to raise this by adapting pm.max_children in /etc/php/7.0/fpm/pool.d/www.conf. Typically you set this to RAM size / avg. process size. You can find out the latter via: ps -ylC php-fpm7.0 --sort:rss Performance Measurements To measure the results I did a force reload of my single user Nextcloud instance and measured the Load time via Chrome developer tools: Page mod_php mod_proxy_fcgi Files 701 ms 605 ms 0.86 News 1.77 s 1.67 s 0.94 as one can see depending on the amount of static/ dynamic files and internal/ external requests we can bring down the page load time by up to 15%. 0 0 [...]



Asynchronous commands

Mon, 23 Oct 2017 19:31:18 +0000

With asynchronous commands we have typical commands from the Model View ViewModel world that return asynchronously. Whenever that happens we want result reporting and progress reporting. We basically want something like this in QML: Item { id: container property ViewModel viewModel: ViewModel {} Connections { target: viewModel.asyncHelloCommand onExecuteProgressed: { progressBar.value = value progressBar.maximumValue = maximum } } ProgressBar { id: progressBar } Button { enabled: viewModel.asyncHelloCommand.canExecute onClicked: viewModel.asyncHelloCommand.execute() } } How do we do this? First we start with defining a AbstractAsyncCommand (impl. of protected APIs here): class AbstractAsyncCommand : public AbstractCommand { Q_OBJECT public: AbstractAsyncCommand(QObject *parent=0); Q_INVOKABLE virtual QFuture executeAsync() = 0; virtual void execute() Q_DECL_OVERRIDE; signals: void executeFinished(void* result); void executeProgressed(int value, int maximum); protected: QSharedPointer> start(); void progress(QSharedPointer> fut, int value, int total); void finish(QSharedPointer> fut, void* result); private: QVector>> m_futures; }; After that we provide an implementation: #include #include #include class AsyncHelloCommand: public AbstractAsyncCommand { Q_OBJECT public: AsyncHelloCommand(QObject *parent=0); bool canExecute() const Q_DECL_OVERRIDE { return true; } QFuture executeAsync() Q_DECL_OVERRIDE; private: void* executeAsyncTaskFunc(); QSharedPointer> current; QMutex mutex; }; #include "asynchellocommand.h" #include AsyncHelloCommand::AsyncHelloCommand(QObject* parent) : AbstractAsyncCommand(parent) { } void* AsyncHelloCommand::executeAsyncTaskFunc() { for (int i=0; i<10; i++) { QThread::sleep(1); qDebug() << "Hello Async!"; mutex.lock(); progress(current, i, 10); mutex.unlock(); } return nullptr; } QFuture AsyncHelloCommand::executeAsync() { mutex.lock(); current = start(); QFutureWatcher* watcher = new QFutureWatcher(this); connect(watcher, &QFutureWatcher::progressValueChanged, this, [=]{ mutex.lock(); progress(current, watcher->progressValue(), watcher->progressMaximum()); mutex.unlock(); }); connect(watcher, &QFutureWatcher::finished, this, [=]{ void* result=watcher->result(); mutex.lock(); finish(current, result); mutex.unlock(); watcher->deleteLater(); }); watcher->setFuture(QtConcurrent::run(this, &AsyncHelloCommand::executeAsyncTaskFunc)); QFuture future = current->future(); mutex.unlock(); return future; } You can find the complete working example here. 0 0 [...]



Attending the GStreamer Conference 2017

Tue, 17 Oct 2017 10:48:45 +0000

This weekend I’ll be in Node5 (Prague) presenting our Media Source Extensions platform implementation work in WebKit using GStreamer.

The Media Source Extensions HTML5 specification allows JavaScript to generate media streams for playback and lets the web page have more control on complex use cases such as adaptive streaming.

My plan for the talk is to start with a brief introduction about the motivation and basic usage of MSE. Next I’ll show a design overview of the WebKit implementation of the spec. Then we’ll go through the iterative evolution of the GStreamer platform-specific parts, as well as its implementation quirks and challenges faced during the development. The talk continues with a demo, some clues about the future work and a final round of questions.

Our recent MSE work has been on desktop WebKitGTK+ (the WebKit version powering the Epiphany, aka: GNOME Web), but we also have MSE working on WPE and optimized for a Raspberry Pi 2. We will be showing it in the Igalia booth, in case you want to see it working live.

I’ll be also attending the GStreamer Hackfest the days before. There I plan to work on webm support in MSE, focusing on any issue in the Matroska demuxer or the vp9/opus/vorbis decoders breaking our use cases.

See you there!

UPDATE 2017-10-22:

The talk slides are available at https://eocanha.org/talks/gstconf2017/gstconf-2017-mse.pdf and the video is available at https://gstconf.ubicast.tv/videos/media-source-extension-on-webkit (the rest of the talks here).

0 (image) 0 (image)



The RelayCommand in Qt

Thu, 24 Aug 2017 18:57:12 +0000

A few days ago I explained how we can do MVVM techniques like ICommand in Qt. Today I’ll explain how to make and use a simple version of the, in the XAML MVVM world quite famous, RelayCommand. In the Microsoft Prism4 & 5 world this is DelegateCommand. Both are equivalent. I will only show a non-templated RelayCommand, so no RelayCommand for now. Perhaps I’ll add a templated one to that mvvm project some other day. What people call a delegate in C# is what C++ people call a Functor. Obviously we will use functors, then. Note that for people actually reading all those links: in C# the Action and Func are basically also C# delegates (or, functors, if you fancy C++’s names for this more). Here is the RelayCommand.h: #include #include #include class RelayCommand : public AbstractCommand { Q_OBJECT public: RelayCommand(std::function executeDelegatep, std::function canExecuteDelegatep, QObject *parent = 0) : AbstractCommand(parent) , executeDelegate(executeDelegatep) , canExecuteDelegate(canExecuteDelegatep) {} void execute() Q_DECL_OVERRIDE; bool canExecute() const Q_DECL_OVERRIDE; public slots: void evaluateCanExecute(); private: std::function executeDelegate; std::function canExecuteDelegate; }; The implementation is too simple to be true: #include "RelayCommand.h" bool RelayCommand::canExecute() const { return canExecuteDelegate(); } void RelayCommand::evaluateCanExecute() { emit canExecuteChanged( canExecute() ); } void RelayCommand::execute() { executeDelegate(); } Okay, so how do we use this? First we make a ViewModel. Because in this case we will define the command in C++. That probably means you want a ViewModel. I added a CompositeCommand in the mix. For a Q_PROPERTY isn’t a CommandProxy really needed, as ownership stays in C++ (when for example you pass this as parent). For a Q_INVOKABLE you would need it to wrap the QSharedPointer. Note. I already hear you think: wait a minute, you are not passing this to the QObject’s constructor, it’s not a QScopedPointer and you have a new but no delete. That’s because CommandProxy converts the ownership rules to QQmlEngine::setObjectOwnership (this, QQmlEngine::JavaScriptOwnership) for itself. I don’t necessarily recommend its usage here (for it’s not immediately clear), but at the same time this is just a demo. You can try printing a warning in the destructor and you’ll see that the QML garbage collector takes care of it. #include #include #include #include #include #include class ViewModel: public QObject { Q_OBJECT Q_PROPERTY(CommandProxy* helloCommand READ helloCommand CONSTANT) public: ViewModel(QObject *parent=0):QObject(parent), helloCmd(new CompositeCommand()){ QSharedPointer cCmd = helloCmd.dynamicCast(); cCmd->add( new RelayCommand ([=] { qWarning() << "Hello1 from C++ RelayCommand"; }, [=]{ return true; })); cCmd->add( new RelayCommand ([=] { qWarning() << "Hello2 from C++ RelayCommand"; }, [=]{ return true; })); proxyCmd = new CommandProxy (helloCmd); } CommandProxy* helloCommand() { return proxyCmd; } private: QSharedPointer helloCmd; CommandProxy *proxyC[...]



AbstractCommand Model View ViewModel techniques

Fri, 18 Aug 2017 20:06:12 +0000

In the .NET XAML world, you have the ICommand, the CompositeCommand and the DelegateCommand. You use these commands to in a declarative way bind them as properties to XAML components like menu items and buttons. You can find an excellent book on this titled Prism 5.0 for WPF. The ICommand defines two things: a canExecute property and an execute() method. The CompositeCommand allows you to combine multiple commands together, the DelegateCommand makes it possible to pass two delegates (functors or lambda’s); one for the canExecute evaluation and one for the execute() method. The idea here is that you want to make it possible to put said commands in a ViewModel and then data bind them to your View (so in QML that’s with Q_INVOKABLE and Q_PROPERTY). Meaning that the action of the component in the view results in execute() being called, and the component in the view being enabled or not is bound to the canExecute bool property. In QML that of course corresponds to a ViewModel.cpp for a View.qml. Meanwhile you also want to make it possible to in a declarative way use certain commands in the View.qml without involving the ViewModel.cpp. So I tried making exactly that. I’ve placed it on github in a project I plan to use more often to collect MVVM techniques I come up with. And in this article I’ll explain how and what. I’ll stick to the header files and the QML file. We start with defining a AbstractCommand interface. This is very much like .NET’s ICommand, of course: #include class AbstractCommand : public QObject { Q_OBJECT Q_PROPERTY(bool canExecute READ canExecute NOTIFY canExecuteChanged) public: AbstractCommand(QObject *parent = 0):QObject(parent){} Q_INVOKABLE virtual void execute() = 0; virtual bool canExecute() const = 0; signals: void canExecuteChanged(bool canExecute); }; We will also make a command that is very easy to use in QML, the EmitCommand: #include class EmitCommand : public AbstractCommand { Q_OBJECT Q_PROPERTY(bool canExecute READ canExecute WRITE setCanExecute NOTIFY privateCanExecuteChanged) public: EmitCommand(QObject *parent=0):AbstractCommand(parent){} void execute() Q_DECL_OVERRIDE; bool canExecute() const Q_DECL_OVERRIDE; public slots: void setCanExecute(bool canExecute); signals: void executes(); void privateCanExecuteChanged(); private: bool canExe = false; }; We make a command that allows us to combine multiple commands together as one. This is the equivalent of .NET’s CompositeCommand, here you have our own: #include #include #include #include class CompositeCommand : public AbstractCommand { Q_OBJECT Q_PROPERTY(QQmlListProperty commands READ commands NOTIFY commandsChanged ) Q_CLASSINFO("DefaultProperty", "commands") public: CompositeCommand(QObject *parent = 0):AbstractCommand (parent) {} CompositeCommand(QList > cmds, QObject *parent=0); ~CompositeCommand(); void execute() Q_DECL_OVERRIDE; bool canExecute() const Q_DECL_OVERRIDE; void remove(const QSharedPointer &cmd); void add(const QSharedPointer &cmd); void add(AbstractCommand *cmd); void clearCommands(); QQmlListProperty commands(); signals: void commandsChanged(); private slots: void onCanExecuteChanged(bool canExecute); private: QList > cmds; static void appendCommand(QQmlListProperty *lst, AbstractCom[...]



Do not use Meson

Tue, 25 Jul 2017 14:05:00 +0000

Recently the Meson Build System gained some momentum. It is time to stop that. Not that Meson is a bad piece of software – on the contrary, it is quite well designed. Still it makes building C/C++ applications worse, by (quoting xkcd) basically creating  this: It sets out to create a cross-platform, more readable and faster alternative to autotools. But there is already CMake that solves this. You might say that CMake is ugly, but note that the CMake 2.x you might have tried is not the same CMake 3.x that is available today. Many patterns have improved and are now both more logical and more readable. Nowadays the difference between Meson and CMake is just a matter of syntactic preference. The Meson authors seem to agree here. The actual criterion for selecting a build system however should be tooling support and community spread. CMake easily wins here: After the introduction of the server mode it got native support by QtCreator, CLion, Android Studio (NDK) and even Microsofts Visual Studio. Native means that you do not have to generate any intermediate project files, but the CMakeLists.txt is used directly by the IDE. On the community spread side we got e.g. KDE, OpenCV, zlib, libpng, freetype and as of recently Boost. These projects using CMake not only guarantees that you can easily use them, but that you can also include them in your build via add_subdirectory such that the become part of your project. This is especially useful if you are cross-compiling – for instance to a Raspberry Pi. On the other hand, reinventing a wheel that is tailored to the needs of a specific community (Gnome), means that it will fall behind and eventually die. This is what is currently happening to the Vala language that had a similar birth to Meson. The meson devs might object that Meson generates build files that run faster on a Raspberry Pi. However if your cross compiling is working you do not need that. And honestly, that particular improvement could have been also achieved by providing a patch to the CMake Ninja generator.. Addendum 4-1-2018 Some comments (rightfully) note that Meson has generally a better documentation and avoids some of its pitfalls. However this is mostly due to Meson not being around long enough such that the way you do things in Meson changed. Neither did it see such a widespread use like CMake yet. (think of corner-cases) But even if you argue that this is precisely the point why you should use Meson, I would argue that improving the existing documentation in CMake and adding more educational warnings is easier then writing something from scratch.   0 0 [...]



Meet the new Q2 2017 Maemo Community Council

Tue, 11 Jul 2017 20:17:23 +0000

Dear Maemo community, I have the great honor of introducing the new Community Council for the upcoming Q2/2017 period.

**The members of the new council are (in alphabetical order):**

  • Juiceme (Jussi Ohenoja)
  • Mosen (Timo Könnecke)
  • Sicelo (Sicelo Mhlongo)

The voting results can be seen on the [voting page]

I want to thank warmly all the members of the community who participated in this most important action of choosing a new council for us!

The new council shall meet on the #maemo-meeting IRC channel next tuesday 18.06 at 20:00 UTC for the formal handover with the passing council.

Jussi Ohenoja, On behalf of the outgoing Maemo Community Council

0 (image) 0 (image)



Colleague tells me I write blogs in chats while I explain how to write a producer-consumer

Thu, 06 Jul 2017 19:49:17 +0000

I’m at home now. I don’t do non-public unpaid work. So let’s blog the example I’m making for him. workplace.h #ifndef Workplace_H #define Workplace_H #include #include #include #include #include #include #include #include class Workplace; typedef enum { WT_INSERTS, WT_QUERY } WorkplaceWorkType; typedef struct { WorkplaceWorkType type; QList values; QString query; QFutureInterface insertIface; QFutureInterface > queryIface; } WorkplaceWork; class WorkplaceWorker: public QThread { Q_OBJECT public: WorkplaceWorker(QObject *parent = NULL) : QThread(parent), m_running(false) { } void run() Q_DECL_OVERRIDE; void pushWork(WorkplaceWork *a_work); private: QStack m_ongoing; QMutex m_mutex; QWaitCondition m_waitCondition; bool m_running; }; class Workplace: public QObject { Q_OBJECT public: explicit Workplace(QObject *a_parent=0) : QObject (a_parent) {} bool insert(QList a_values); QList query(const QString &a_param); QFuture insertAsync(QList a_values); QFuture > queryAsync(const QString &a_param); private: WorkplaceWorker m_worker; }; class App: public QObject { Q_OBJECT public slots: void perform(); void onFinished(); private: Workplace m_workplace; }; #endif// Workplace_H workplace.cpp #include "workplace.h" void App::onFinished() { QFutureWatcher *watcher = static_cast* > ( sender() ); delete watcher; } void App::perform() { for (int i=0; i<10; i++) { QList vals; vals.append(1); vals.append(2); QFutureWatcher *watcher = new QFutureWatcher; connect (watcher, &QFutureWatcher::finished, this, &App::onFinished); watcher->setFuture( m_workplace.insertAsync( vals ) ); } for (int i=0; i<10; i++) { QList vals; vals.append(1); vals.append(2); qWarning() << m_workplace.insert( vals ); qWarning() << m_workplace.query("test"); } } void WorkplaceWorker::pushWork(WorkplaceWork *a_work) { if (!m_running) { start(); } m_mutex.lock(); switch (a_work->type) { case WT_QUERY: m_ongoing.push_front( a_work ); break;     default: m_ongoing.push_back( a_work ); } m_waitCondition.wakeAll(); m_mutex.unlock(); } void WorkplaceWorker::run() { m_mutex.lock(); m_running = true; while ( m_running ) { m_mutex.unlock(); m_mutex.lock(); if ( m_ongoing.isEmpty() ) { m_waitCondition.wait(&m_mutex); } WorkplaceWork *work = m_ongoing.pop(); m_mutex.unlock(); // Do work here and report progress sleep(1); switch (work->type) { case WT_QUERY: { // Report result here QList result; QStringList row; row.append("abc"); row.append("def"); result.append(row); work->queryIface.reportFinished( &result ); } break; case WT_INSERTS:         default: { // Report result here bool result = true; work->insertIface.reportFinished[...]



How do they do it? Asynchronous undo and redo editors

Thu, 11 May 2017 20:09:25 +0000

Imagine we want an editor that has undo and redo capability. But the operations on the editor are all asynchronous. This implies that also undo and redo are asynchronous operations. We want all this to be available in QML, we want to use QFuture for the asynchronous stuff and we want to use QUndoCommand for the undo and redo capability. But how do they do it? First of all we will make a status object, to put the status of the asynchronous operations in (asyncundoable.h). class AbstractAsyncStatus: public QObject { Q_OBJECT Q_PROPERTY(bool success READ success CONSTANT) Q_PROPERTY(int extra READ extra CONSTANT) public: AbstractAsyncStatus(QObject *parent):QObject (parent) {} virtual bool success() = 0; virtual int extra() = 0; }; We will be passing it around as a QSharedPointer, so that lifetime management becomes easy. But typing that out is going to give us long APIs. So let’s make a typedef for that (asyncundoable.h). typedef QSharedPointer AsyncStatusPointer; Now let’s make ourselves an undo command that allows us to wait for asynchronous undo and asynchronous redo. We’re combining QUndoCommand and QFutureInterface here (asyncundoable.h). class AbstractAsyncUndoable: public QUndoCommand { public: AbstractAsyncUndoable( QUndoCommand *parent = nullptr ) : QUndoCommand ( parent ) , m_undoFuture ( new QFutureInterface() ) , m_redoFuture ( new QFutureInterface() ) {} QFuture undoFuture() { return m_undoFuture->future(); } QFuture redoFuture() { return m_redoFuture->future(); } protected: QScopedPointer > m_undoFuture; QScopedPointer > m_redoFuture; }; Okay, let’s implement these with an example operation. First the concrete status object (asyncexample1command.h). class AsyncExample1Status: public AbstractAsyncStatus { Q_OBJECT Q_PROPERTY(bool example1 READ example1 CONSTANT) public: AsyncExample1Status ( bool success, int extra, bool example1, QObject *parent = nullptr ) : AbstractAsyncStatus(parent) , m_example1 ( example1 ) , m_success ( success ) , m_extra ( extra ) {} bool example1() { return m_example1; } bool success() Q_DECL_OVERRIDE { return m_success; } int extra() Q_DECL_OVERRIDE { return m_extra; } private: bool m_example1 = false; bool m_success = false; int m_extra = -1; }; Let’s make a QUndoCommand that uses a timer to simulate asynchronous behavior. We could also use QtConcurrent’s run function to use a QThreadPool and QRunnable instances that also implement QFutureInterface, of course. Seasoned Qt developers know what I mean. For the sake of example, I wanted to illustrate that QFuture can also be used for asynchronous things that aren’t threads. We’ll use the lambda because QUndoCommand isn’t a QObject, so no easy slots. That’s the only reason (asyncexample1command.h). class AsyncExample1Command: public AbstractAsyncUndoable { public: AsyncExample1Command(bool example1, QUndoCommand *parent = nullptr) : AbstractAsyncUndoable ( parent ), m_example1(example1) {} void undo() Q_DECL_OVERRIDE { m_undoFuture->reportStarted(); QTimer *timer = new QTimer(); timer->setSingleShot(true); QObject::connect(timer, &QTimer::timeout, [=]() { QSharedPointer result; result.reset(new AsyncExample1Status ( tr[...]



Q2 2017 Community Council Election Announcement

Sun, 30 Apr 2017 10:16:50 +0000

Dear friends and Maemoans. It is again the time for us to elect the new Community Council.

The schedule for the voting process is as follows:

  • The nomination period starts next Monday, on the 1st of May 2017 and will continue until the 23rd of May 2017.
  • The election starts on Thursday, on the 1st of June 2017 and will continue until the 7th of June 2017. In order for us to keep the community strong, we need to have new people with fresh ideas to carry on the torch. So, please consider volunteering for the position of Maemo Council.

    On behalf of the outgoing Community Council,

    eekkelund

0 (image) 0 (image)



Atreus: Building a custom ergonomic keyboard

Thu, 20 Apr 2017 00:00:00 +0000

As mentioned in my Working on Android post, I’ve been using a mechanical keyboard for a couple of years now. Now that I work on Flowhub from home, it was a good time to re-evaluate the whole work setup. As far as regular keyboards go, the MiniLa was nice, but I wanted something more compact and ergonomic. The Atreus keyboard Atreus is a 40% ergonomic mechanical keyboard designed by Phil Hagelberg. It is an open hardware design, but he also sells kits for easier construction. From the kit introduction: The Atreus is a small mechanical keyboard that is based around the shape of the human hand. It combines the comfort of a split ergonomic keyboard with the crisp key action of mechanical switches, all while fitting into a tiny profile. My use case was also quite travel-oriented. I wanted a small keyboard that would enable me to work with it also on the road. There are many other small-ish DIY keyboard designs like Planck and Gherkin available, but Atreus had the advantage of better ergonomics. I really liked the design of the Ergodox keyboard, and Atreus essentially is that made mobile: I found the split halves and relatively large size (which are fantastic for stationary use at a desk) make me reluctant to use it on the lap, at a coffee shop, or on the couch, so that’s the primary use case I’ve targeted with the Atreus. It still has most of the other characteristics that make the Ergodox stand out, like mechanical Cherry switches, staggered columns instead of rows, heavy usage of the thumbs, and a hackable microcontroller with flexible firmware, but it’s dramatically smaller and lighter I had the opportunity to try a kit-built Atreus in the Berlin Mechanical Keyboard meetup, and it felt nice. It was time to start the project. Sourcing the parts When building an Atreus the first decision is whether to go with the kit or hand-wire it yourself. Building from a kit is certainly easier, but since I’m a member of a hackerspace, doing a hand-wired build seemed like the way to go. To build a custom keyboard, you need: Switches: in my case 37 Cherry MX blues and 5 Cherry MX blacks Diodes: one 1N4148 per switch Microcontroller: a Arduino Pro Micro on my keyboard Keycaps: started with recycled ones and later upgraded to DSA blanks Case: got a set of laset-cut steel plates Even though Cherry — the maker of the most common mechanical key switches — is a German company, it is quite difficult to get switches in retail here. Luckily a fellow hackerspace member had just dismantled some old mechanical keyboards, and so I was able to get the switches I needed via barter. The Cherry MX blues are tactile clicky switches that feel super-nice to type on, but are quite loud. For modifiers I went with Cherry MX blacks that are linear. This way there is quite a clear difference in feel between keys you typically hold down compared to the ones you just press. The diodes and the microcontroller I ordered from Amazon for about 20€ total. At first I used a set of old keycaps that I got with the switches, but once the keyboard was up and running I upgraded to a very nice set of blank DSA-profile keycaps that I ordered from AliExpress for 30€. That set came with enough keycaps that I’ll have myself covered if I ever build a second Atreus. All put together, I think the parts ended up costing me around 100€ total. Preparations When I received all the parts, there were some preparation steps to be made. Since the key switches were 2nd hand, I had to start by dismantling them and removing old diodes that had been left inside some of them. The keycaps I had gotten with the switches were super grimy, and so I ended up[...]



Asynchronous undoable and redoable APIs

Thu, 13 Apr 2017 21:32:22 +0000

Combining QFuture with QUndoCommand made a lot of sense for us. The undo and the redo methods of the QUndoCommand can also be asynchronous, of course. We wanted to use QFuture without involving threads, because our asynchronosity is done through a process and IPC, and not a thread. It’s the design mistake of QtConcurrent‘s run method, in my opinion. That meant using QFutureInterface instead (which is undocumented, but luckily public – so it’ll remain with us until at least Qt’s 6.y.z releases).

So how do we make a QUndoCommand that has a undo, and that has a redo method that returns a asynchronous QFuture?

We just did that, today. I’m very satisfied with the resulting API and design. It might have helped if QUndoStack would be a QUndoStack and QUndoCommand would have been a QUndoCommand with undo and redo’s return type being T. Just an idea for the Qt 6.y.z developers.

0 (image) 0 (image)



Looking for new adventures

Mon, 10 Apr 2017 19:07:00 +0000

Yes, I'm looking for a job. :-) These six years I've spent at Canonical have literally been flying. I enjoyed my work from the very first day, when I was assigned to the Unity 2D team, developing a lightweight desktop environment for Ubuntu, though I stayed in that team just for a few weeks. The next task, which I've been carrying on till today, has been implementing the Online Accounts feature in Ubuntu; this project has been especially dear to me, given that I got to reuse and improve much of the work we developed for the Nokia N9 phone. Seeing it being adopted also by Sailfish OS and KDE has been a major satisfaction, and a proof that we were on the right track. And indeed, porting the UI to Qt/QML for running in Unity 8, plus extending and simplifying the APIs and helping with the development of client applications has been a fantastic ride. In the times where calm was reigning in the project, I reached out to other teams and offered help, mainly for improving the geolocation service and the webapps project. Unfortunately, with the decision to terminate the development of Unity8 and to set aside the convergence goals, all of the above is no longer relevant for Canonical's future and I, along many other developers, have left the company. So, here's my CV. Given that reading is boring, here's a few pictures (and even a video!) of programs I've done, not as part of my daily work but in my spare time; though, to be honest, I do enjoy middleware and logic development (and even kernel, though I got little chances to work on that so far) more than UI development: Imaginario on the Ubuntu phone Imaginario for your desktop (under development) allowfullscreen="" frameborder="0" height="360" src="https://www.youtube.com/embed/b1J84dISuNk?rel=0" width="640"> Mappero Geotagger If you wish to see my code, please have a look at my gitlab, github and launchpad accounts. 0 0 [...]



Making something that is ‘undoable editable’ with Qt

Fri, 24 Mar 2017 09:42:36 +0000

Among the problems we’ll face is that we want asynchronous APIs that are undoable and that we want to switch to read only, undoable editing, non-undoable editing and that QML doesn’t really work well with QFuture. At least not yet. We want an interface that is easy to talk with from QML. Yet we want to switch between complicated behaviors. We will also want synchronous mode and asynchronous mode. Because I just invented that requirement out of thin air. Ok, first the “design”. We see a lot of behaviors, for something that can do something. The behaviors will perform for that something, the actions it can do. That is the strategy design pattern, then. It’s the one about ducks and wing fly behavior and rocket propelled fly behavior and the ostrich that has a can’t fly behavior. For undo and redo, we have the command pattern. We have this neat thing in Qt for that. We’ll use it. We don’t reinvent the wheel. Reinventing the wheel is stupid. Let’s create the duck. I mean, the thing-editor as I will use “Thing” for the thing that is being edited. We want copy (sync is sufficient), paste (must be aysnc), and edit (must be async). We could also have insert and delete, but those APIs would be just like edit. Paste is usually similar to insert, of course. Except that it can be a combined delete and insert when overwriting content. The command pattern allows you to make such combinations. Not the purpose of this example, though. Enough explanation. Let’s start! The ThingEditor, is like the flying Duck in strategy. This is going to be more or less the API that we will present to the QML world. It could be your ViewModel, for example (ie. you could let your ThingViewModel subclass ThingEditor). class ThingEditor : public QObject { Q_OBJECT Q_PROPERTY ( ThingEditingBehavior* editingBehavior READ editingBehavior                  WRITE setEditingBehavior NOTIFY editingBehaviorChanged ) Q_PROPERTY ( Thing* thing READ thing WRITE setThing NOTIFY thingChanged ) public: explicit ThingEditor( QSharedPointer &a_thing, ThingEditingBehavior *a_editBehavior, QObject *a_parent = nullptr ); explicit ThingEditor( QObject *a_parent = nullptr ); Thing* thing() const { return m_thing.data(); } virtual void setThing( QSharedPointer &a_thing ); virtual void setThing( Thing *a_thing ); ThingEditingBehavior* editingBehavior() const { return m_editingBehavior.data(); } virtual void setEditingBehavior ( ThingEditingBehavior *a_editingBehavior ); Q_INVOKABLE virtual void copyCurrentToClipboard ( ); Q_INVOKABLE virtual void editCurrentAsync( const QString &a_value ); Q_INVOKABLE virtual void pasteCurrentFromClipboardAsync( ); signals: void editingBehaviorChanged (); void thingChanged(); void editCurrentFinished( EditCurrentCommand *a_command ); void pasteCurrentFromClipboardFinished( EditCurrentCommand *a_command ); private slots: void onEditCurrentFinished(); void onPasteCurrentFromClipboardFinished(); private: QScopedPointer m_editingBehavior; QSharedPointer m_thing; QList *> m_editCurrentFutureWatchers; QList *> m_pasteCurrentFromClipboardFutureWatchers; }; For the implementation of this class, I’ll only provide the non-obvious pieces. I’m sure you can do that setTh[...]



Perfection

Thu, 23 Mar 2017 00:17:15 +0000

Perfection has been reached not when there is nothing left to add, but when there is nothing left to take away.

0 (image) 0 (image)



Media Source Extensions upstreaming, from WPE to WebKitGTK+

Mon, 20 Mar 2017 11:55:33 +0000

A lot of good things have happened to the Media Source Extensions support since my last post, almost a year ago. The most important piece of news is that the code upstreaming has kept going forward at a slow, but steady pace. The amount of code Igalia had to port was pretty big. Calvaris (my favourite reviewer) and I considered that the regular review tools in WebKit bugzilla were not going to be enough for a good exhaustive review. Instead, we did a pre-review in GitHub using a pull request on my own repository. It was an interesting experience, because the change set was so large that it had to be (artificially) divided in smaller commits just to avoid reaching GitHub diff display limits. 394 GitHub comments later, the patches were mature enough to be submitted to bugzilla as child bugs of Bug 157314 – [GStreamer][MSE] Complete backend rework. After some comments more in bugzilla, they were finally committed during Web Engines Hackfest 2016: Some unforeseen regressions in the layout tests appeared, but after a couple of commits more, all the mediasource WebKit tests were passing. There are also some other tests imported from W3C, but I kept them still skipped because webm support was needed for many of them. I’ll focus again on that set of tests at its due time. Igalia is proud of having brought the MSE support up to date to WebKitGTK+. Eventually, this will improve the browser video experience for a lot of users using Epiphany and other web browsers based on that library. Here’s how it enables the usage of YouTube TV at 1080p@30fps on desktop Linux: src="https://www.youtube.com/embed/qofLTJrrVKg" width="560" height="315" frameborder="0" allowfullscreen="allowfullscreen"> Our future roadmap includes bugfixing and webm/vp9+opus support. This support is important for users from countries enforcing patents on H.264. The current implementation can’t be included in distros such as Fedora for that reason. As mentioned before, part of this upstreaming work happened during Web Engines Hackfest 2016. I’d like to thank our sponsors for having made this hackfest possible, as well as Metrological for giving upstreaming the importance it deserves. Thank you for reading.   0 0 [...]