16 Stimmen

Wie macht man das Hintergrundfenster von Gtk+ transparent?

Ich möchte den Hintergrund eines Gtk+ Fensters transparent machen, so dass nur die Widgets im Fenster sichtbar sind. Ich habe ein paar Tutorials gefunden:

http://mikehearn.wordpress.com/2006/03/26/gtk-windows-with-alpha-channels/

http://macslow.thepimp.net/?p=26

Aber sie scheinen beide auf das "expose" Ereignis zu hören und dann an Cairo delegieren, um die Darstellung zu erledigen. Das bedeutet, dass andere Widgets, die dem Fenster hinzugefügt werden, nicht gerendert werden (zum Beispiel habe ich versucht, auch einen Button zum Fenster hinzuzufügen).

Ich sehe, dass es eine Methode modify-bg auf GtkWidget gibt: http://library.gnome.org/devel/gtk/stable/GtkWidget.html#gtk-widget-modify-bg

Allerdings scheint GdkColor keinen Parameter für Transparenz zu akzeptieren: http://library.gnome.org/devel/gdk/stable/gdk-Colormaps-and-Colors.html

Ich habe auch die Methode GtkWindow.set_opacity ausprobiert, aber dies setzt die Deckkraft auch für den Fensterinhalt, was ich nicht möchte.

Ich würde mich über jede Hilfe freuen, die jemand dazu bieten kann.

17voto

karlphillip Punkte 89618

Ich habe das alphademo Beispiel geändert, um anstelle des roten Kreises eine Schaltfläche zu zeichnen.

Diese Anwendung zeichnet die Schaltfläche auf einem 400x400 transparenten Fenster.

Wenn Sie auf das Fenster klicken, zeigt/versteckt die Anwendung die Titelleiste.

#include 
#include 
#include 

static void screen_changed(GtkWidget *widget, GdkScreen *old_screen, gpointer user_data);
static gboolean expose(GtkWidget *widget, GdkEventExpose *event, gpointer user_data);
static void clicked(GtkWindow *win, GdkEventButton *event, gpointer user_data);

int main(int argc, char **argv)
{
    gtk_init(&argc, &argv);

    GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
    gtk_window_set_default_size(GTK_WINDOW(window), 400, 400);
    gtk_window_set_title(GTK_WINDOW(window), "Alpha Demo");
    g_signal_connect(G_OBJECT(window), "delete-event", gtk_main_quit, NULL);

    gtk_widget_set_app_paintable(window, TRUE);

    g_signal_connect(G_OBJECT(window), "expose-event", G_CALLBACK(expose), NULL);
    g_signal_connect(G_OBJECT(window), "screen-changed", G_CALLBACK(screen_changed), NULL);

    gtk_window_set_decorated(GTK_WINDOW(window), FALSE);
    gtk_widget_add_events(window, GDK_BUTTON_PRESS_MASK);
    g_signal_connect(G_OBJECT(window), "button-press-event", G_CALLBACK(clicked), NULL);

    GtkWidget* fixed_container = gtk_fixed_new();
    gtk_container_add(GTK_CONTAINER(window), fixed_container);
    GtkWidget* button = gtk_button_new_with_label("button1");
    gtk_widget_set_size_request(button, 100, 100);
    gtk_container_add(GTK_CONTAINER(fixed_container), button);

    screen_changed(window, NULL, NULL);

    gtk_widget_show_all(window);
    gtk_main();

    return 0;
}

gboolean supports_alpha = FALSE;
static void screen_changed(GtkWidget *widget, GdkScreen *old_screen, gpointer userdata)
{
    /* Um zu überprüfen, ob der Bildschirm Alphakanäle unterstützt, die Farbkarte abrufen */
    GdkScreen *screen = gtk_widget_get_screen(widget);
    GdkColormap *colormap = gdk_screen_get_rgba_colormap(screen);

    if (!colormap)
    {
        printf("Ihr Bildschirm unterstützt keine Alphakanäle!\n");
        colormap = gdk_screen_get_rgb_colormap(screen);
        supports_alpha = FALSE;
    }
    else
    {
        printf("Ihr Bildschirm unterstützt Alphakanäle!\n");
        supports_alpha = TRUE;
    }

    gtk_widget_set_colormap(widget, colormap);
}

static gboolean expose(GtkWidget *widget, GdkEventExpose *event, gpointer userdata)
{
   cairo_t *cr = gdk_cairo_create(widget->window);

    if (supports_alpha)
        cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.0); /* transparent */
    else
        cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* opakes Weiß */

    /* Hintergrund zeichnen */
    cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
    cairo_paint (cr);

    cairo_destroy(cr);

    return FALSE;
}

static void clicked(GtkWindow *win, GdkEventButton *event, gpointer user_data)
{
    /* Fensterrahmen umschalten */
    gtk_window_set_decorated(win, !gtk_window_get_decorated(win));
}

Kompiliert unter Ubuntu 10.04:

gcc alpha.c -o alpha -I/usr/include/gtk-2.0 -I/usr/lib/gtk-2.0/include -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/cairo -I/usr/include/pango-1.0 -I/usr/include/atk-1.0 -lgtk-x11-2.0

15voto

fpemud Punkte 353

Danke für die Antwort. Ich schreibe den Code in Python + GTK3 um:

#!/usr/bin/env python3

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gdk
import cairo

supports_alpha = False

def screen_changed(widget, old_screen, userdata=None):
    global supports_alpha

    screen = widget.get_screen()
    visual = screen.get_rgba_visual()

    if visual is None:
        print("Ihr Bildschirm unterstützt keine Alpha-Kanäle!")
        visual = screen.get_system_visual()
        supports_alpha = False
    else:
        print("Ihr Bildschirm unterstützt Alpha-Kanäle!")
        supports_alpha = True

    widget.set_visual(visual)

def expose_draw(widget, event, userdata=None):
    global supports_alpha

    cr = Gdk.cairo_create(widget.get_window())

    if supports_alpha:
        print("transparentes Fenster einstellen")
        cr.set_source_rgba(1.0, 1.0, 1.0, 0.0) 
    else:
        print("undurchsichtiges Fenster einstellen")
        cr.set_source_rgb(1.0, 1.0, 1.0)

    cr.set_operator(cairo.OPERATOR_SOURCE)
    cr.paint()

    return False

def clicked(window, event, userdata=None):
    # Fensterrahmen umschalten
    window.set_decorated(not window.get_decorated())

if __name__ == "__main__":
    window = Gtk.Window()
    window.set_position(Gtk.WindowPosition.CENTER)
    window.set_default_size(400, 400)
    window.set_title("Alpha-Demo")
    window.connect("delete-event", Gtk.main_quit)

    window.set_app_paintable(True)

    window.connect("draw", expose_draw)
    window.connect("screen-changed", screen_changed)

    window.set_decorated(False)
    window.add_events(Gdk.EventMask.BUTTON_PRESS_MASK)
    window.connect("button-press-event", clicked)

    fixed_container = Gtk.Fixed()
    window.add(fixed_container)
    button = Gtk.Button.new_with_label("button1")
    button.set_size_request(100, 100)
    fixed_container.add(button)

    screen_changed(window, None, None)

    window.show_all()
    Gtk.main()

12voto

draekko Punkte 141

Danke für den Code, genau das, wonach ich gesucht habe, obwohl er modifiziert werden muss, um mit GTK3 zu funktionieren. Außerdem muss das expose-event in ein 'draw'-Event geändert werden, damit es funktioniert. Hier ist also mein Beitrag zum Code, modifiziert für GTK3:

#include 
#include 
#include 

static void screen_changed(GtkWidget *widget, GdkScreen *old_screen, gpointer user_data);
static gboolean expose_draw(GtkWidget *widget, GdkEventExpose *event, gpointer userdata);
static void clicked(GtkWindow *window, GdkEventButton *event, gpointer user_data);

int main(int argc, char **argv) {
    gtk_init(&argc, &argv);

    GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
    gtk_window_set_default_size(GTK_WINDOW(window), 400, 400);
    gtk_window_set_title(GTK_WINDOW(window), "Alpha Demo");
    g_signal_connect(G_OBJECT(window), "delete-event", gtk_main_quit, NULL);

    gtk_widget_set_app_paintable(window, TRUE);

    g_signal_connect(G_OBJECT(window), "draw", G_CALLBACK(expose_draw), NULL);
    g_signal_connect(G_OBJECT(window), "screen-changed", G_CALLBACK(screen_changed), NULL);

    gtk_window_set_decorated(GTK_WINDOW(window), FALSE);
    gtk_widget_add_events(window, GDK_BUTTON_PRESS_MASK);
    g_signal_connect(G_OBJECT(window), "button-press-event", G_CALLBACK(clicked), NULL);

    GtkWidget* fixed_container = gtk_fixed_new();
    gtk_container_add(GTK_CONTAINER(window), fixed_container);
    GtkWidget* button = gtk_button_new_with_label("button1");
    gtk_widget_set_size_request(button, 100, 100);
    gtk_container_add(GTK_CONTAINER(fixed_container), button);

    screen_changed(window, NULL, NULL);

    gtk_widget_show_all(window);
    gtk_main();

    return 0;
}

gboolean supports_alpha = FALSE;
static void screen_changed(GtkWidget *widget, GdkScreen *old_screen, gpointer userdata) {
    GdkScreen *screen = gtk_widget_get_screen(widget);
    GdkVisual *visual = gdk_screen_get_rgba_visual(screen);

    if (!visual) {
        printf("Ihr Bildschirm unterstützt keine Alpha-Kanäle!\n");
        visual = gdk_screen_get_system_visual(screen);
        supports_alpha = FALSE;
    } else {
        printf("Ihr Bildschirm unterstützt Alpha-Kanäle!\n");
        supports_alpha = TRUE;
    }

        gtk_widget_set_visual(widget, visual);
}

static gboolean expose_draw(GtkWidget *widget, GdkEventExpose *event, gpointer userdata) {
    cairo_t *cr = gdk_cairo_create(gtk_widget_get_window(widget));

    if (supports_alpha) {
        printf("Einstellen des transparenten Fensters\n");
        cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.0); 
    } else {
        printf("Einstellen des undurchsichtigen Fensters\n");
        cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); 
    }

    cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
    cairo_paint (cr);

    cairo_destroy(cr);

    return FALSE;
}

static void clicked(GtkWindow *window, GdkEventButton *event, gpointer user_data) {
    /* Fensterrahmen umschalten */
    gtk_window_set_decorated(window, !gtk_window_get_decorated(window));
}

So habe ich es auf Ubuntu 15.04 kompiliert:

gcc alpha.c -o alpha  `pkg-config --cflags --libs glib-2.0` `pkg-config --cflags --libs gtk+-3.0`

Hoffentlich hilft dies jemand anderem, der versucht, es unter GTK3 zum Laufen zu bringen.

5voto

Litarvan Punkte 125

Für diejenigen, die Golang verwenden, hier ist eine mit gotk3 (https://github.com/gotk3/gotk3):

package main

import (
    "github.com/gotk3/gotk3/cairo"
    "github.com/gotk3/gotk3/gdk"
    "github.com/gotk3/gotk3/gtk"
    "log"
)

var alphaSupported = false

func main() {
    gtk.Init(nil)

    win, err := gtk.WindowNew(gtk.WINDOW_TOPLEVEL)
    if err != nil {
        log.Fatal("Fenster konnte nicht erstellt werden:", err)
    }
    win.SetTitle("Einfaches Beispiel")
    win.Connect("destroy", func() {
        gtk.MainQuit()
    })

    // Benötigt für Transparenz
    win.SetAppPaintable(true)

    win.Connect("screen-changed", func (widget *gtk.Widget, oldScreen *gdk.Screen, userData ...interface{}) {
        screenChanged(widget)
    })
    win.Connect("draw", func (window *gtk.Window, context *cairo.Context) {
        exposeDraw(window, context)
    })

    l, err := gtk.LabelNew("Ich bin transparent!")
    if err != nil {
        log.Fatal("Label konnte nicht erstellt werden:", err)
    }

    win.Add(l)
    win.SetDefaultSize(800, 600)

    screenChanged(&win.Widget)

    win.ShowAll()
    gtk.Main()
}

func screenChanged(widget *gtk.Widget) {
    screen, _ := widget.GetScreen()
    visual, _ := screen.GetRGBAVisual()

    if visual != nil {
        alphaSupported = true
    } else {
        println("Alpha nicht unterstützt")
        alphaSupported = false
    }

    widget.SetVisual(visual)
}

func exposeDraw(w *gtk.Window, ctx *cairo.Context) {
    if alphaSupported {
        ctx.SetSourceRGBA(0.0, 0.0, 0.0, 0.25)
    } else {
        ctx.SetSourceRGB(0.0, 0.0, 0.0)
    }

    ctx.SetOperator(cairo.OPERATOR_SOURCE)
    ctx.Paint()
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X