Gtk+: How to set the cursor of a window from a Cairo context?
I have written the following code to set the cursor of a Gtk::Window
from a Cairo::Context
. When I run the program and move the cursor into the window, the cursor changes to a horizontal开发者_开发百科 black line at the top, followed by some undefinable white shape at the bottom. I was expecting the cursor to change into a black 16×16 square. Why doesn't the cursor assume the shape I intended?
#include <gtkmm.h>
const int size = 16, hotspot = 0;
class Window : public Gtk::Window
{
public:
void change_cursor()
{
Glib::RefPtr<Gdk::Drawable> pixmap = Gdk::Pixmap::create(
Glib::RefPtr<Gdk::Drawable>(), size, size, get_window()->get_depth());
pixmap->set_colormap(get_window()->get_colormap());
Cairo::RefPtr<Cairo::Context> context = pixmap->create_cairo_context();
context->set_source_rgba(0, 0, 0, 0);
context->rectangle(0, 0, size, size);
context->fill();
Glib::RefPtr<Gdk::Pixbuf> pixbuf
= Gdk::Pixbuf::create(pixmap, 0, 0, size, size);
Gdk::Cursor cursor(get_window()->get_display(), pixbuf, hotspot, hotspot);
window->set_cursor(cursor);
}
};
int main(int argc, char* argv[])
{
Gtk::Main app(argc, argv);
Window window;
window.show_all();
window.change_cursor();
Gtk::Main::run(window);
return 0;
}
When I draw the Gdk::Pixmap
to the screen, it looks fine. When I draw the Gdk::Pixbuf
to the screen, I get garbage.
I did not figure out the cause of the problem, but a way to work around it:
- Create an empty
Gdk::Pixbuf
. - Create a
Cairo::ImageSurface
using theGdk::Pixbuf
's pixels as data buffer. - Create a
Cairo::Context
from theCairo::ImageSurface
. - Clear the
Cairo::Context
(this is important, becauseGdk::Pixbuf
's pixel data seem not to be initialized yet).
The code looks like this:
Glib::RefPtr<Gdk::Pixbuf> pixbuf
= Gdk::Pixbuf::create(Gdk::COLORSPACE_RGB, true, 8, size, size);
Cairo::RefPtr<Cairo::ImageSurface> surface
= Cairo::ImageSurface::create(
pixbuf->get_pixels(), Cairo::FORMAT_ARGB32,
size, size, pixbuf->get_rowstride() );
Cairo::RefPtr<Cairo::Context> context = Cairo::Context::create(surface);
context->save();
context->set_operator(Cairo::OPERATOR_CLEAR);
context->paint();
context->restore();
When I now paint to that context and set the cursor from the Gdk::Pixbuf
, I get almost what I want: the shape is fine, but Red and Blue are swapped. This can be fixed as outlined in Question 4291994 (How to write contents of a Cairo Image surface into a Gdk Pixbuf?):
void fix_buffer_after_cairo(Glib::RefPtr<Gdk::Pixbuf> pixbuf)
{
guint8* pixels = pixbuf->get_pixels();
int height = pixbuf->get_height();
int width = pixbuf->get_width();
int rowstride = pixbuf->get_rowstride();
guint8 tmp;
guint8* p;
guint8* end;
for (int j = height; j > 0; --j)
{
p = pixels;
end = p + 4 * width;
while (p < end)
{
tmp = p[0];
if (G_BYTE_ORDER == G_LITTLE_ENDIAN)
{
p[0] = p[2]; p[2] = tmp;
}
else
{
p[0] = p[1]; p[1] = p[2]; p[2] = p[3]; p[3] = tmp;
}
p += 4;
}
pixels += rowstride;
}
}
}
精彩评论