Gtk +: Как установить курсор окна из контекста Каира? - PullRequest
2 голосов
/ 07 февраля 2011

Я написал следующий код для установки курсора Gtk::Window из Cairo::Context.Когда я запускаю программу и перемещаю курсор в окно, курсор меняется на горизонтальную черную линию вверху, за которой следует неопределяемая белая фигура внизу.Я ожидал, что курсор изменится на черный квадрат 16 × 16.Почему курсор не принимает нужную мне форму?

#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;
}

Когда я рисую Gdk::Pixmap на экране, он выглядит хорошо.Когда я рисую Gdk::Pixbuf на экране, я получаю мусор.

1 Ответ

2 голосов
/ 09 февраля 2011

Я не выяснил причину проблемы, но как обойти ее:

  1. Создать пустое Gdk::Pixbuf.
  2. Создать Cairo::ImageSurface, используяпиксели Gdk::Pixbuf как буфер данных.
  3. Создайте Cairo::Context из Cairo::ImageSurface.
  4. Очистите Cairo::Context (это важно, потому что Gdk::Pixbufданные пикселей, похоже, еще не инициализированы).

Код выглядит следующим образом:

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();

Когда я сейчас рисую в этом контексте и устанавливаю курсор из Gdk::PixbufЯ получаю почти , что я хочу: форма в порядке, но красный и синий поменялись местами.Это можно исправить, как указано в Вопрос 4291994 (Как записать содержимое поверхности Каирского изображения в Pixbuf Gdk?) :

  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;
    }
  }
}
...