C语言 如何让 Gtk+ 窗口背景透明?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3908565/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to make Gtk+ window background transparent?
提问by jbeard4
I'd like to make the background of a Gtk+ window transparent so that only the widgets in the window are visible. I found a few tutorials:
我想让 Gtk+ 窗口的背景透明,以便只有窗口中的小部件可见。我找到了一些教程:
http://mikehearn.wordpress.com/2006/03/26/gtk-windows-with-alpha-channels/
http://mikehearn.wordpress.com/2006/03/26/gtk-windows-with-alpha-channels/
http://macslow.thepimp.net/?p=26
http://macslow.thepimp.net/?p=26
But they both appear to listen to the "expose" event, and then delegate to Cairo to do the rendering. This means that other widgets added to the window are not rendered (for example, I've tried adding a button to the window as well).
但它们似乎都在监听“expose”事件,然后委托开罗进行渲染。这意味着不会呈现添加到窗口的其他小部件(例如,我也尝试向窗口添加按钮)。
I see that there's a method modify-bg on GtkWidget: http://library.gnome.org/devel/gtk/stable/GtkWidget.html#gtk-widget-modify-bg
我看到 GtkWidget 上有一个方法 modify-bg:http: //library.gnome.org/devel/gtk/stable/GtkWidget.html#gtk-widget-modify-bg
However, GdkColor does not appear to accept a parameter for transparency: http://library.gnome.org/devel/gdk/stable/gdk-Colormaps-and-Colors.html
但是,GdkColor 似乎不接受透明度参数:http: //library.gnome.org/devel/gdk/stable/gdk-Colormaps-and-Colors.html
I've tried the GtkWindow.set_opacity method as well, but this sets the opacity for the window contents as well, which is not what I want.
我也尝试过 GtkWindow.set_opacity 方法,但这也设置了窗口内容的不透明度,这不是我想要的。
I'd appreciate any guidance anyone can provide in this.
我很感激任何人都可以在这方面提供的任何指导。
回答by karlphillip
I changed the alphademoexample to draw a button instead of the red circle.
我更改了alphademo示例以绘制按钮而不是红色圆圈。
This application draws the button on a 400x400 transparent window.
此应用程序在 400x400 透明窗口上绘制按钮。
When you click on the window the application shows/hides the title bar.
当您单击窗口时,应用程序会显示/隐藏标题栏。
#include <gtk/gtk.h>
#include <gdk/gdkscreen.h>
#include <cairo.h>
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)
{
/* To check if the display supports alpha channels, get the colormap */
GdkScreen *screen = gtk_widget_get_screen(widget);
GdkColormap *colormap = gdk_screen_get_rgba_colormap(screen);
if (!colormap)
{
printf("Your screen does not support alpha channels!\n");
colormap = gdk_screen_get_rgb_colormap(screen);
supports_alpha = FALSE;
}
else
{
printf("Your screen supports alpha channels!\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); /* opaque white */
/* draw the background */
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)
{
/* toggle window manager frames */
gtk_window_set_decorated(win, !gtk_window_get_decorated(win));
}
Compiled on Ubuntu 10.04:
在 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
回答by draekko
Thanks for the code, just what i was looking for though it needs to be modified to work GTK3. Also the expose-event needs to be changed to a 'draw' event to get it working. So here's my code contribution modified for GTK3:
感谢您的代码,这正是我正在寻找的,尽管需要对其进行修改才能工作 GTK3。此外,暴露事件需要更改为“绘制”事件才能使其正常工作。所以这是我为 GTK3 修改的代码贡献:
#include <gtk/gtk.h>
#include <gdk/gdkscreen.h>
#include <cairo.h>
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("Your screen does not support alpha channels!\n");
visual = gdk_screen_get_system_visual(screen);
supports_alpha = FALSE;
} else {
printf("Your screen supports alpha channels!\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("setting transparent window\n");
cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.0);
} else {
printf("setting opaque window\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) {
/* toggle window manager frames */
gtk_window_set_decorated(window, !gtk_window_get_decorated(window));
}
Here's how i compiled it on Ubuntu 15.04:
这是我在 Ubuntu 15.04 上编译它的方法:
gcc alpha.c -o alpha `pkg-config --cflags --libs glib-2.0` `pkg-config --cflags --libs gtk+-3.0`
Hopefully this helps out someone else trying to get it working on GTK3.
希望这有助于其他人试图让它在 GTK3 上工作。
回答by fpemud
Thanks for the answer. I rewrite the code in python + GTK3:
谢谢你的回答。我用python + GTK3重写了代码:
#!/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("Your screen does not support alpha channels!")
visual = screen.get_system_visual()
supports_alpha = False
else:
print("Your screen supports alpha channels!")
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("setting transparent window")
cr.set_source_rgba(1.0, 1.0, 1.0, 0.0)
else:
print("setting opaque window")
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):
# toggle window manager frames
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()
回答by Litarvan
For those using golang, here's one using gotk3 ( https://github.com/gotk3/gotk3) :
对于那些使用 golang 的人,这里有一个使用 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("Unable to create window:", err)
}
win.SetTitle("Simple Example")
win.Connect("destroy", func() {
gtk.MainQuit()
})
// Needed for transparency
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("I'm transparent !")
if err != nil {
log.Fatal("Unable to create label:", 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 not supported")
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()
}

