Eee Note Development: QCop Messaging

Discussion in 'Asus (Android)' started by pbarrette, Aug 18, 2011.

  1. pbarrette

    pbarrette Scribbler - Standard Member

    Messages:
    196
    Likes Received:
    2
    Trophy Points:
    31
    Hi all,

    I just went through some very painful development work trying to get the Qt Messaging Framework (QMF) to work correctly with the EeeNote. Hopefully, with this post, I can save someone else from the same problems and help others better integrate their applications with the Eee Note's basic framework.

    The Eee Note uses Qt's built-in, inter-process communication framework called QCop to send messages and notifications between processes. These messages are handled by the Qt Windowing System (QWS) server process, and are sent to a named "channel".

    On the Eee Note, the qws server process is the [eeeserver]. The purpose of the server is to provide the window management functions and the interfaces to the mouse, keyboard and graphics subsystems and to establish the QCop messaging service.

    The Eee Note's [eeeserver] process is responsible for many functions, including starting all of the other applications, as well as monitoring the power state, controlling the speaker volume and showing all of the "loading" message screens.

    The [eeeserver] process also starts up the [launcher] which provides the main menu screen, and the [virtualkeyboard] which is exactly what the name suggests. Additionally, the [eeeserver] also provides the status bar at the top of the screen.

    Finally, each application is expected to communicate with the [eeeserver] and the [launcher] at least, and should be capable of communicating to the other applications in order to achieve full integration.

    For instance, when a user selects a menu item from the [launcher], it sends a message to the [eeeserver] to start the selected application, then it sends another message to the [eeeserver] to display the "Loading.." screen. Next, the application is expected to send a message to the [launcher] that states the application is running as expected. At this point, the [launcher] sends a message to the [eeeserver], telling it to remove the "Loading.." screen and display the application screen.

    The next post will outline some of the code required to send and receive the QCop messages, and will give examples of the messages that the various process expect to receive, as well as some of the messages that your application is expected to handle.

    pb
     
  2. pbarrette

    pbarrette Scribbler - Standard Member

    Messages:
    196
    Likes Received:
    2
    Trophy Points:
    31
    So here we go with the meaty bits..

    To send a QCop message, you send a QString and, optionally, a QByteArray to a named channel.
    The first thing that needs to be done is to add the QCopChannel include statement to your code:
    PHP:
    #include <QCopChannel>
    At it's most simple form, we just send a simple message that requires no optional data.
    Like starting the WiFi connection:
    PHP:
    QCopChannel::send("statusbar""wifi/on");
    QCopChannel::flush();
    To send additional data to a channel, like changing the text shown in the top status bar:
    PHP:
    QByteArray optiondata;
    QDataStream out(&optiondataQIODevice::WriteOnly);
    out << "My App Title";
    QCopChannel::send("statusbar""title changed"optiondata);
    Before we start sending messages out to other applications, we should probably check to see if the application is listening first:
    PHP:
    if (QCopChannel::isRegistered("dictionary")) {
      
    //The dictionary app is running, so we can send messages to it.
    }
    This isn't required for critical message channels like [eeeserver], [launcher], [statusbar] and a few others, since they MUST be running at all times.

    We can also start listening for data that is sent to our application by constructing a QCopChannel of our own. The channel emits the "received" signal whenever a message is sent to it. We connect that signal to a "SLOT", which is just a section of code that gets called when the signal is triggered and can receive the parameters that the signal carries.

    The first thing we need to do to set up a QCopChannel is to set up our header file with the QCopChannel and slot definitions:
    PHP:
    //----------MyApp.h-------------
    #include <QCopChannel>
    class MyApp : public QMainWindow
    {
        
    Q_OBJECT
    public:
        
    MyApp(QWidget *parent 0);
        ~
    MyApp();
    private:
        
    QCopChannel *my_channel;
    private 
    slots:
        
    void msgHandler(const QString &, const QByteArray &);
    };
    Then we create the channel and handle the incoming messages in the code:
    PHP:
    //----------MyApp.cpp-------------
    #include <QCopChannel>
    #include <iostream>
    #include "MyApp.h"

    MyApp::MyApp(QWidget *parent) : QMainWindow(parent)
    {
        
    QCopChannel *channel;

        
    channel = new QCopChannel("mychannel"this);
        
    connect(channelSIGNAL(received(const QString&, const QByteArray&)),
                
    thisSLOT(msgHander(const QString&, const QByteArray&)));
    }

    MyApp::~MyApp()
    {}


    void MyApp::msgHander(const QString &msg, const QByteArray &data)
    {
            
    QDataStream in(data);
            
    QString sData;
            
    in >> sData;

            
    QString r " MSG: " msg " DATA:" sData;
            
    std::cout << qPrintable(r) << std::endl;
    }
    Of course, any app needs a Main function, and all QCop messages must be handled within a QApplication:
    PHP:
    //-------main.cpp-------
    #include <QApplication>
    #include "MyApp.h"

    int main(int argcchar *argv[])
    {
        
    QApplication a(argcargv);
        
    MyApp w;
        
    w.show();
        return 
    a.exec();
    }
    Your application can also listen to any channel if you know that it exists:
    PHP:
    QCopChannel *channel;
    channel = new QCopChannel("eeeserver"this);
        
    connect(channelSIGNAL(received(const QString&, const QByteArray&)),
            
    thisSLOT(eeeserverMsg(const QString&, const QByteArray&)));
    Of course, you will have to create a function called "eeeserverMsg" to handle the messages, and add the slot definition to your header file.

    Here are some messages you can expect. The format is:
    [channel]
    message - "optional data" (my comments)
    ---------------------------------
    [eeeserver]
    volume/mute
    app/playsound
    app/run - "dictionary" (launches the application. Arguments can be supplied)
    app/startLoading - "Deleting..." (data text is optional)
    app/endLoading
    app/stopLoadingTimer - "Deleting.." (sometimes used to clear loading screen)
    app/clickUP (I'm not sure.. Return to the home screen?)
    app/raiseLauncher - "dictionary"
    app/resumeScreen
    app/updateDB - X (data is not a QString, more research needed)
    app/readyToClose - "app-name" (sent by application after being told to shut down)
    app/closeAll (sent by application to get all applications to exit)

    [qte/etablemsgchannel]
    QWS_PowerModeMessage
    QWS_PowerMessage
    QWS_UsbCapMessage
    QWS_SDStateMessage
    QWS_SenBoardLockMessage (seen when locking and unlocking the keypad)
    power/normal
    wifi/off

    [qte/etablevkbchannel]
    VKB/hide (seen when the keyboard disappears)

    [qte/etablepowerchannel]
    app/shutdown (application should quit NOW)
    app/shutdown - "closeAfterSave" (application has time to save state, then close)

    [statusbar]
    title changed - "AppName" (sent to set the title text on the top bar)
    icon/disable - "1" (sometimes seen with no data. Likely grey's out the top bar)
    icon/enable - "1" (sometimes seen with no data. Likely re-enables the top bar)
    wifi/on (turn on the wifi module)
    wifi/off (turn off the wifi module)
    wifi/autoconnect (really don't know. wifi/on will autoconnect also)

    [bookreader]
    drm/addbook - "path/filename.pdf" (path is relative and based in /eTablet/.dl_tmp/ folder)
    folder/hide (unknown)

    [dictionary]
    popup - "-popup -x 271 -y 303 -w 23 -h 35 Word" (looks up "Word" and shows the pop-up like the bookreader app uses)
    popuphide

    -------------------------

    To make it easier to find and test your own messages, I've created a couple of programs:

    [qcopsend]
    [source]
    This program was created to send arbitrary messages to arbitrary channels and as a way to send proper messages from QtMail. It is now in the QtMail release and installed into /usr/bin. It is used as follows:
    qcopsend statusbar "title changed" "My Text Here"

    [eeesniff]
    [source]
    This program was created to help me determine if the messages I was sending were actually being received correctly.
    To use it, just run it. It will start dumping every message it gets, except one. The launcher app is constantly emitting [app/alive - "launcher"] and I didn't want to see it every 2 seconds.
    You can also redirect the output to a file and run it in the background. It's a lot easier to find hidden messages that way:
    /mnt/extsdcard/eeesniff >/mnt/extsdcard/message.log &

    pb
     
    Last edited by a moderator: May 18, 2015
  3. akiross

    akiross Pen Pal - Newbie

    Messages:
    15
    Likes Received:
    0
    Trophy Points:
    5
    Thanks, I'm just starting developing on the eeenote, this may be useful in a near future :)

    (p.s. where can I find some resources for developing for the eeenote? I built the toolchain and the qt framework successfully, but I'd like to know if other steps were taken, like emulating the device, or tips for handle pointing device, or software under development (or developed) to look as example, ports you did, and so on).
     
  4. nikoperugia

    nikoperugia Pen Pal - Newbie

    Messages:
    35
    Likes Received:
    0
    Trophy Points:
    15
    Hey. My friend finally lent me his Eee note and I started to poke around.
    I'm trying to make an application that stays resident in memory instead of quitting every time, like the asus made ones.
    I got to the point of sending a "launcher" "App/hide" message to hide the window when I'm done with it, and that's ok. the screen then shows the launcher again.
    problem is, if I click on the app icon again, the launcher doesn't know the window is already open and launches the binary all over again.
    I looked at the dictionary source and added a IF clause before creating my window class, checking if there is a listener already setup with my app name. if i find one, i just send it a "app/show" message and the window should come back on top. everything works as expected when running from the shell (with qcopsend). if I run this modified app from within the launcher itself, it gets stuck on the loading window, even if I send it a "app/showed" message. Anyone got any ideas?
    on a sidenote, I noticed the only unofficial app that is able to resume its window after being hidden is qOrganizer. I looked at the source and I couldn't find anything special about it. What's the catch?
     
  5. d.goryachev

    d.goryachev Scribbler - Standard Member

    Messages:
    275
    Likes Received:
    0
    Trophy Points:
    31
    Found few additional messages UNSORTED by channels.

    Moreover, I am not sure that all listed below - really works, although some commands I've checked.

    app/kill
    app/alive
    app/close
    app/restart
    app/rotate
    app/resume
    app/shutdown
    app/reboot
    app/hide
    app/show
    app/rotateScreen // be careful .. it works :)
    app/resumeScreen
    app/hideCursor
    app/showCursor
    app/changeLoading
    app/screenshot
    app/showScreenshot
    app/resumeInput
    app/suspendInput
    app/raiseLauncher
    app/soundOn
    app/soundOff
    app/stopLoadingTimer
    app/deleteLoadingTimer
    app/canEndLoading
    app/VKBOn
    app/VKBOff

    power/low
    power/lowest
    power/saving
    power/timeout
    power/normal

    player/start //didn't work for me, need runned instance?
    player/stop

    recorder/start //didn't work for me, need runned instance?
    recorder/stop

    there's a lot other messages (i think)
     
  6. osowiecki

    osowiecki Scribbler - Standard Member

    Messages:
    175
    Likes Received:
    0
    Trophy Points:
    31
    qcopsend bookreader bottombar_marklist/disable

    /usr/local/eTablet/qcopsend bookreader bottombar/enable

    in bookreader reader
     
  7. osowiecki

    osowiecki Scribbler - Standard Member

    Messages:
    175
    Likes Received:
    0
    Trophy Points:
    31
    folder/show - add bookmark
    folder/hide - remove bookmark
     
  8. osowiecki

    osowiecki Scribbler - Standard Member

    Messages:
    175
    Likes Received:
    0
    Trophy Points:
    31
    '/usr/local/eTablet/bin/ebookreader/bookreader -d

    =
    parsing argument :

    --- do deactivation
    thread in

    I'll check other letters and see what do they do.

    EDIT :

    -q
    =
    parsing argument :

    --- query activation
    "No device provider implementation"
    thread in

    -qws
    crashes QWSSocket (I will check out what is exactly going on later)
     
  9. osowiecki

    osowiecki Scribbler - Standard Member

    Messages:
    175
    Likes Received:
    0
    Trophy Points:
    31
    export `/usr/local/eTablet/bin/ebookreader/bookreader ` >> info.txt
    =
    bookreader's 'export' log
     
  10. osowiecki

    osowiecki Scribbler - Standard Member

    Messages:
    175
    Likes Received:
    0
    Trophy Points:
    31
    Today I recieved new ea800.
    Welcome back everyone.
     
Loading...

Share This Page