I wish to render text with transparent/translucent background (or no background) over other gtk widgets like GtkImage or GtkButton etc. Primary goal is to have text display over Gtk Widgets (esp. GtkImage) in the background. I can render text on GtkFrame using pangocairo library but I am not able to get rid of the background of GtkFrame.
I have seen examples of making GtkWindow transparent or translucent but I wish to have opaque GtkWindow with GtkLayout for placing the GtkWidgets, then place GtkImage over the layout and render Text on top of GtkImage so that it gives a nice background to my text.
I also tried using GtkDrawingArea, but then I get lost in creating the cairo context of the pixbuf and rendering text over that. Any help is appreciated.
Note: I am using Compiz for compositing windows.
You can do it with GtkOverlay widget (Gtk+ 3.2 at least)
GtkOverlay — A container which overlays widgets on top of each other
Here is an entire program that does this. Everything that you need to build and run it is at GitHub.
https://github.com/sweckhoff/GTK-Cairo-Sinusoids/blob/master/gtk_cairo_sinusoid_plot.c
#include <gtk/gtk.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
const gdouble pi = 3.14159265359;
#define ERASER_WIDTH 150
#define LABEL_STR_LEN 20
typedef struct {
gint width;
gint height;
gdouble rad_step;
gint scale_factor;
gint y_zero;
gint x_step;
gdouble rads;
gint last_x;
gint last_y;
gint current_x;
gint current_y;
gint current_eraser_x;
cairo_surface_t *plot_surface;
cairo_t *plot;
cairo_t *eraser;
GtkWidget *widget;
GtkWidget *label;
gdouble (*funct)(gdouble);
} graph_data_packet_t;
gboolean
do_graph (graph_data_packet_t *packet)
{
static gchar label_str[LABEL_STR_LEN];
if (packet->rads >= 2.0) {
packet->rads = 0.0;
}
gdouble pi_rads = pi * packet->rads;
snprintf(label_str, LABEL_STR_LEN, "%s%f%s", "Radians ", packet->rads, "pi");
gtk_label_set_text(GTK_LABEL(packet->label), label_str);
packet->rads += packet->rad_step;
if (packet->current_x > packet->width) {
packet->current_x = 0;
}
packet->last_x = packet->current_x;
packet->last_y = packet->current_y;
packet->current_x += packet->x_step;
packet->current_y = packet->y_zero - (packet->scale_factor * packet->funct (pi_rads));
packet->current_eraser_x += packet->x_step;
if (packet->current_eraser_x > packet->width) {
packet->current_eraser_x = 0;
}
gtk_widget_queue_draw(packet->widget);
return TRUE;
}
gboolean
draw_callback (GtkWidget *widget, cairo_t *drawing_area, graph_data_packet_t *packet)
{
// Erase Old
cairo_move_to (packet->eraser, packet->current_eraser_x, 0);
cairo_line_to (packet->eraser, packet->current_eraser_x, packet->height);
cairo_stroke(packet->eraser);
// Plot New
cairo_move_to (packet->plot, packet->last_x, packet->last_y);
cairo_line_to (packet->plot, packet->current_x, packet->current_y);
cairo_stroke (packet->plot);
// Apply source to drawing area
cairo_set_source_surface (drawing_area, packet->plot_surface, 0.0, 0.0);
cairo_paint(drawing_area);
return FALSE;
}
static void
destroy (GtkWidget *window, gpointer data)
{
gtk_main_quit();
}
gboolean
delete_event (GtkWidget *window, GdkEvent *event, gpointer data)
{
return FALSE;
}
int
main(int argc, char **argv)
{
GtkWidget *window = NULL;
GtkWidget *overlay = NULL;
GtkWidget *image_background = NULL;
GtkWidget *image = NULL;
GtkWidget *drawing_area = NULL;
GtkWidget *label = NULL;
graph_data_packet_t packet = {
.width = 400,
.height = 200,
.rad_step = 0.05,
.scale_factor = 75,
.y_zero = 100,
.x_step = 1,
.rads = 0.0,
.last_x = 0,
.last_y = 0,
.current_x = 0,
.current_y = 0,
.current_eraser_x = ERASER_WIDTH,
.plot_surface = NULL,
.plot = NULL,
.eraser = NULL,
.widget = NULL,
.label = NULL,
.funct = NULL
};
if (argc > 1) {
if (!strcmp("sine", argv[1])) {
packet.funct = sin;
} else if (!strcmp("cosine", argv[1])) {
packet.funct = cos;
} else {
packet.funct = sin;
}
} else {
packet.funct = sin;
}
gtk_init(&argc, &argv);
// Setup Cairo stuff
packet.plot_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 400, 200);
if (NULL == packet.plot_surface) {
return EXIT_FAILURE;
}
packet.plot = cairo_create (packet.plot_surface);
if (NULL == packet.plot) {
return EXIT_FAILURE;
}
cairo_set_source_rgb (packet.plot, 1.0, 0.0, 0.0);
packet.eraser = cairo_create (packet.plot_surface);
if (NULL == packet.eraser) {
return EXIT_FAILURE;
}
cairo_set_source_rgba (packet.eraser, 0.0, 0.0, 0.0, 0.0);
cairo_set_operator(packet.eraser, CAIRO_OPERATOR_CLEAR);
// Window
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
if(NULL == window) {
return EXIT_FAILURE;
}
packet.widget = window;
gtk_widget_set_size_request (window, 400, 200);
g_signal_connect (G_OBJECT (window), "destroy",
G_CALLBACK (destroy), NULL);
g_signal_connect (G_OBJECT (window), "delete_event",
G_CALLBACK (delete_event), NULL);
// Overlay
overlay = gtk_overlay_new ();
if (NULL == overlay) {
return EXIT_FAILURE;
}
// Background Image
image = gtk_image_new_from_file ("plot_background.png");
if (NULL == image) {
return EXIT_FAILURE;
}
image_background = gtk_image_new_from_file ("pi_background.png");
if (NULL == image_background) {
return EXIT_FAILURE;
}
// Plot
drawing_area = gtk_drawing_area_new ();
if (NULL == drawing_area) {
return EXIT_FAILURE;
}
gtk_widget_set_size_request (drawing_area, 400, 200);
g_signal_connect (G_OBJECT (drawing_area), "draw",
G_CALLBACK (draw_callback), &packet);
// Label
label = gtk_label_new ("Radians: 0.0 pi");
if (NULL == label) {
return EXIT_FAILURE;
}
packet.label = label;
gtk_widget_set_halign (label, GTK_ALIGN_START);
gtk_widget_set_valign (label, GTK_ALIGN_END);
// Put it all together
gtk_container_add(GTK_CONTAINER(overlay), image_background);
gtk_overlay_add_overlay (GTK_OVERLAY (overlay), image);
gtk_overlay_add_overlay (GTK_OVERLAY (overlay), drawing_area);
gtk_overlay_add_overlay (GTK_OVERLAY (overlay), label);
gtk_container_add (GTK_CONTAINER (window), overlay);
gtk_widget_show_all (window);
g_timeout_add(100, (GSourceFunc) do_graph, &packet);
gtk_main();
return EXIT_SUCCESS;
}
来源:https://stackoverflow.com/questions/5296618/how-can-i-render-text-with-transparent-background-over-other-widgets-in-gtk