PDA

View Full Version : QDBus and org.freedesktop.Notifications.Notify



TheOneRing
20th November 2009, 20:31
Hi I'm currently developing a small tcp based notification server using the "org.freedesktop.Notifications.Notify" dbus binding and everything works fine on my Kubuntu, I even got the callbacks working with qdbus(I don't want to use libnotify because there are too many gtk depenecys).
The current problem is that I don't know how to sent the a notification image over qdbus.

on http://www.galago-project.org/specs/notification/0.9/x207.html
the image is defined as

The icon_data field should be a raw image data structure of signature (iiibiiay) which describes the width, height, rowstride, has alpha, bits per sample, channels and image data respectively.


and here is an except from dbus-monitor of a working notification


array [
dict entry(
string "icon_data"
variant struct {
int32 50
int32 50
int32 200
boolean true
int32 8
int32 4
array [
byte 255
byte 32
byte 57
byte 93
byte 255
byte 32
byte 57
byte 93
byte 255
byte 32
.......
]
}
)
]

The image defined above should be part of a QVariantMap.

Problematic is how to get bits per sample and channels and finally how to sent these data over dbus.


Regards

TheOneRing

wysota
21st November 2009, 12:01
Bits per sample is most probably 8 or 24 - this is just the depth of your image (the only thing to check out is that if the number should describe one pixel (24b for RGB) or one channel(8b for RGB)). Channels will be one for gray images, 3 for colour images and 4 for colour images with alpha channel. You can deduce all the values based on QImage::format().

TheOneRing
21st November 2009, 13:49
Great but how to send the data over dbus?
Currently I'm getting this



string "icon_data"
int32 133
int32 135
int32 532
boolean true
int32 8
int32 4
array [
byte 137
byte 80
byte 78
byte 71
.....
]

how to get the right form?

wysota
21st November 2009, 14:57
I don't understand your question. What exactly do you have trouble with? From your post it seems an image 32bit deep (4 channels (RGBA) 8 bits each) with size of 133x135 is carried.

TheOneRing
21st November 2009, 16:27
The problem is not the data (thanks for help) the current problem is which datatype I have to use that QDBus sends it in the correct form.
Currently I use a QVariantList and insert all the vaues, in the working notification it looks like I have to send a struct over QDBus but I don't know how.

Here is what I get

string "icon_data"
int32 133
int32 135
int32 532
boolean true
int32 8
int32 4
array [
byte 137
byte 80
byte 78
byte 71
.....
]


and this is what I need:

array [
dict entry(
string "icon_data"
variant struct {
int32 50
int32 50
int32 200
boolean true
int32 8
int32 4
array [
byte 255
byte 32
byte 57
byte 93
byte 255
byte 32
byte 57
byte 93
byte 255
byte 32
.......
]
}
)
]

TheOneRing
21st November 2009, 19:24
Ok now I get that far


array [
dict entry(
string "icon_data"
variant array [
variant int32 133
variant int32 135
variant int32 532
variant boolean true
variant int32 8
variant int32 4
variant array [
byte 137
byte 80
byte 78
byte 71
byte 13
byte 10
.......


at least the beginning seams to be right
but I have no idea how to get the entry struct.

My current code is

QVariantMap Notify::getImage(QString* path){
QImage img(*path);
QVariantMap out;

if(img.isNull())return out;
int width=img.width();
int height=img.height();
int rowstride=img.bytesPerLine();
bool hasAlpha=img.hasAlphaChannel();
int channels;
if(img.isGrayscale())
channels=1;
else{
channels =3;
if(hasAlpha)
channels=4;
}
int bitsPerSample=img.depth()/channels;
QByteArray image;
QBuffer buffer(&image,NULL );
buffer.open( QBuffer::WriteOnly);
img.save( &buffer, "PNG" );
QVariantList o2;
o2<<width<<height<<rowstride<<hasAlpha<<bitsPerSample<<channels<<image;
out.insert("icon_data",o2);
return out;

}

but instead of QVariantList for the body i have to use something different, but what?

TheOneRing
22nd November 2009, 19:54
Hi I finally got it to send a image but the image is not displayed correct, so I think there is a bug in my mtheode so here is the code


void Notify::getImage(QVariantMap *hints,QString* path){
QImage img(*path);
if(img.isNull())return;
int id=qDBusRegisterMetaType<iiibiiay>();
iiibiiay i;
i.width=img.width();
i.height=img.height();
i.rowstride=img.bytesPerLine();
i.hasAlpha=img.hasAlphaChannel();
if(img.isGrayscale())
i.channels=1;
else{
i.channels =3;
if(i.hasAlpha)
i.channels=4;
}
i.bitsPerSample=img.depth()/i.channels;
QBuffer buffer(&i.image,NULL );
buffer.open( QBuffer::WriteOnly);
img.save( &buffer, "PNG" );
hints->insert("icon_data",QVariant(id,&i));
}

QDBusArgument &operator<<(QDBusArgument &a, const iiibiiay &i) {
a.beginStructure();
a << i.width<<i.height<<i.rowstride<<i.hasAlpha<<i.bitsPerSample<<i.channels<<i.image;
a.endStructure();
return a;
}

const QDBusArgument & operator >>(const QDBusArgument &a, iiibiiay &i) {
a.beginStructure();
a >> i.width>> i.height>> i.rowstride>> i.hasAlpha>> i.bitsPerSample>> i.channels>> i.image;
a.endStructure();
return a;
}


http://lh4.ggpht.com/_HGaCai9Q1Cw/SwmWi0aH1lI/AAAAAAAABCs/vAS8FTNfzRQ/snapshot3.png
The image in the upper left corner and the big rectangel should be the same

wysota
22nd November 2009, 22:43
Try only sending img.bits() as the image data. If you were to send PNG image will all headers and stuff, all the information about the image wouldn't be necessary because they could be taken from PNG headers.

TheOneRing
22nd November 2009, 23:51
I'v got even one step closer to my ultimate goal

http://lh4.ggpht.com/_HGaCai9Q1Cw/SwnOCXCxEjI/AAAAAAAABC0/I2933eQSYgE/snapshot4.png


for(int ii=0;ii<img.numBytes();++ii)
i.image.append(img.pixel(ii%i.width,ii/i.width));

does anybody know how to get a pixbuff out of a QImage without using gdk?

wysota
23rd November 2009, 00:20
pixbuff is a GDK concept. It's equivalent in Qt is either QImage::bits() or QImage itself. Based on your code I think you should really try QImage::bits()

TheOneRing
23rd November 2009, 09:06
Big thanks but I get the wrong color.
http://lh5.ggpht.com/_HGaCai9Q1Cw/SwpQcQ9dioI/AAAAAAAABC8/l1r5aeYsssE/snapshot5.png



iiibiiay::iiibiiay(QImage* img){
width=img->width();
height=img->height();
rowstride=img->bytesPerLine();
hasAlpha=img->hasAlphaChannel();
channels =img->isGrayscale()?1:hasAlpha?4:3;
bitsPerSample=img->depth()/channels;
image.append((char*)img->bits(),img->numBytes());
}

wysota
23rd November 2009, 09:48
You probably have to swap the order of channels. I would assume - from RGB to BGR, or something like that.

TheOneRing
23rd November 2009, 10:34
And again big thanks QImage::rgbSwapped() solved the problem
so finally every problem is solved, wysota you are my hero!