Есть ли API для попиксельного альфа-смешивания на GTK и OSX?

Я хочу рисовать прозрачные окна (с альфа-каналом) в Linux (GTK) и OSX. Есть ли API для этого? Обратите внимание, что я не хочу устанавливать глобальную прозрачность, альфа-уровень должен быть установлен для каждого пикселя.

Я ищу тот же API, что и функция UpdateLayeredWindow в Windows, как в этом примере: Попиксельное альфа-смешение.


person math    schedule 23.07.2009    source источник


Ответы (2)


Для Mac OS X см. пример кода RoundTransparentWindow. Он работает, используя собственное полностью прозрачное окно и рисуя в нем фигуры. Хотя в примере используются только формы с четкими краями + общий альфа-канал, можно использовать произвольный альфа-канал.

Хотя в примере используется пользовательское окно, вы можете использовать ту же технику, чтобы пробить дыры в обычных окнах, вызвав setOpaque:NO. Хакерский пример:

@implementation ClearView

- (void)drawRect:(NSRect)rect
{
    if (mask == nil)  mask = [[NSImage imageNamed:@"mask"] retain];
    [self.window setOpaque:NO];
    [mask drawInRect:self.bounds
            fromRect:(NSRect){{0, 0},mask.size}
           operation:NSCompositeCopy
            fraction:1.0];
}

@end

Основным ограничением этого метода является то, что стандартная тень не очень хорошо взаимодействует с краями с альфа-смешением.

person Jens Ayton    schedule 23.07.2009

Я нашел этот код в папке экспериментов в начале этого года. Я не могу вспомнить, сколько из этого я написал, а сколько основано на примерах из других источников в Интернете.

В этом примере будет отображаться частично прозрачное синее окно с полностью непрозрачной кнопкой GTK+ в центре. Рисование, например, PNG с альфа-смешением где-то внутри окна должно привести к правильной компоновке. Надеюсь, это поставит вас на правильный путь.

Скомпилируйте его со следующим:

$ gcc `pkg-config --cflags --libs gtk+-2.0` -o per-pixel-opacity per-pixel-opacity.c

Теперь для кода:

#include <gtk/gtk.h>

static gboolean on_window_expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer data)
{
    cairo_t *cr;
    cr = gdk_cairo_create(widget->window); // create cairo context

    cairo_set_source_rgba(cr, 0.0, 0.0, 1.0, 0.2);
    cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); // set drawing compositing operator
                                                   // SOURCE -> replace destination
    cairo_paint(cr); // paint source

    cairo_destroy(cr);

    return FALSE;
}

gint main(gint argc, gchar **argv)
{
    GtkWidget *window, *button, *vbox;
    GdkScreen *screen;
    GdkColormap *colormap;

    gtk_init(&argc, &argv);

    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);

    g_signal_connect(G_OBJECT(window), "delete-event", gtk_main_quit, NULL);
    g_signal_connect(G_OBJECT(window), "expose-event", G_CALLBACK(on_window_expose_event), NULL);

    gtk_window_set_decorated(GTK_WINDOW(window), FALSE);
    gtk_container_set_border_width(GTK_CONTAINER(window), 20);

    gtk_widget_set_app_paintable(window, TRUE);

    screen = gtk_widget_get_screen(window);
    colormap = gdk_screen_get_rgba_colormap(screen);
    gtk_widget_set_colormap(window, colormap);

    button = gtk_button_new();
    gtk_button_set_label(GTK_BUTTON(button), "Don't Press!");

    gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(button));

    gtk_widget_show_all(window);

    gtk_main();

    return 0;
}
person Jeremy Visser    schedule 03.08.2009