Display transparent background image in Gtk2 and Gtk3 window

Linux specific forum
User avatar
Shardik
Addict
Addict
Posts: 1991
Joined: Thu Apr 21, 2005 2:38 pm
Location: Germany

Display transparent background image in Gtk2 and Gtk3 window

Post by Shardik »

The following code example demonstrates how to display a PNG background image in a Gtk2 or Gtk3 window. I have tested the code example successfully in PB 5.41 with both Gtk3 and subsystem gtk2 in these Linux distributions and desktop managers:
- Linux Mint 17.3 x86 "Rosa"
- Lubuntu 14.04 x86 with LXDE
- Ubuntu 14.04 x64 with Enlightenment E17
- Ubuntu 14.04 x64 with KDE
- Ubuntu 14.04 x64 with Unity
- Xubuntu 14.04 x86 with Xfce

Code: Select all

EnableExplicit

#CAIRO_EXTEND_REPEAT = 1

ImportC ""
  gdk_cairo_create(*Drawable.GdkDrawable)
EndImport

ImportC "-lcairo"
  cairo_destroy(*CairoContext)
  cairo_fill(*CairoContext)
  cairo_get_source(*CairoContext)
  cairo_image_surface_create_from_png(Filename.P-UTF8)
  cairo_pattern_create_for_surface(*CairoSurface)
  cairo_pattern_destroy(*CairoPattern)
  cairo_pattern_set_extend(*CairoPattern, Extend.I)
  cairo_rectangle(*CairoContext, x.D, y.D, Width.D, Height.D)
  cairo_set_source(*CairoContext, *CairoPattern)
  cairo_surface_destroy(*CairoSurface)
EndImport

Define Pattern.I
Define Surface.I

CompilerIf Subsystem("gtk2")
  ProcedureC WidgetExposeHandler(*Widget.GtkWidget, *Event.GdkEventExpose)
    Protected CairoContext.I

    CairoContext = gdk_cairo_create(*Widget\window)
CompilerElse
  ProcedureC WidgetDrawHandler(*Widget.GtkWidget, CairoContext.I, *UserData)
CompilerEndIf
    Shared Pattern.I
    Shared Surface.I

    cairo_set_source(CairoContext, Pattern)
    cairo_pattern_set_extend(cairo_get_source(CairoContext),
      #CAIRO_EXTEND_REPEAT)
    cairo_rectangle(CairoContext, 10, 10, WindowWidth(0) - 20,
      WindowHeight(0) - 20)
    cairo_fill(CairoContext)

  CompilerIf Subsystem("gtk2") = #True
    cairo_destroy(CairoContext)
  CompilerEndIf
EndProcedure ;}

Procedure.I GetContainer(WindowID.I, ContainerName.S)
  Protected Child.I
  Protected ChildrenList.I
  Protected *Name
  Protected Widget.I = WindowID(WindowID)

  Child = gtk_bin_get_child_(Widget)

  Repeat
    ChildrenList = gtk_container_get_children_(Widget)
    Child = g_list_nth_data_(ChildrenList, 0)

    If Child = 0
      Break
    Else
      *Name = gtk_widget_get_name_(Child)
      Widget = Child
    EndIf
  Until PeekS(*Name, -1, #PB_UTF8) = ContainerName

  ProcedureReturn Child
EndProcedure

OpenWindow(0, 140, 100, 550, 530,
  "Window with transparent PNG background image", #PB_Window_SizeGadget)
SetWindowColor(0, $CDFAFF)
ButtonGadget(0, 220, 400, 100, 25, "Click me!")

Surface = cairo_image_surface_create_from_png(#PB_Compiler_Home +
  "examples/3d/Data/Textures/grass1.png")
Pattern = cairo_pattern_create_for_surface(Surface)

CompilerIf Subsystem("gtk2")
  g_signal_connect_(GetContainer(0, "GtkFixed"), "expose-event",
    @WidgetExposeHandler(), 0)
CompilerElse
  g_signal_connect_(GetContainer(0, "GtkFixed"), "draw",
    @WidgetDrawHandler(), 0)
CompilerEndIf

; ----- Force initial drawing of window
gtk_widget_queue_draw_(WindowID(0))

Repeat
  Select WaitWindowEvent()
    Case #PB_Event_CloseWindow
      cairo_pattern_destroy(Pattern)
      cairo_surface_destroy(Surface)
      Break
    Case #PB_Event_Gadget
     If EventGadget() = 0
       Debug "Button was clicked!"
     EndIf
  EndSelect
ForEver
Changes:
- I have changed

Code: Select all

cairo_image_surface_create_from_png(Filename.S)
to

Code: Select all

cairo_image_surface_create_from_png(Filename.P-UTF8)
in order to also work in Unicode mode (thank you for your hint, Charly!).

- I added

Code: Select all

SetWindowColor(0, $CDFAFF)
to demonstrate the overlay of the PNG image over the colored window background.

- I removed the creation of the surface and the pattern from the callback and moved it to the main program because it's bad practice to put resource-hungry operations in a callback which has to be optimized for speed because it is called very often.

- I added the line

Code: Select all

gtk_widget_queue_draw_(WindowID(0))
to eliminate a problem with the initial display of the background image on some distributions like Xubuntu 14.04 and Linux Mint 17.3 "Rosa".
Last edited by Shardik on Sat Jun 03, 2017 8:37 pm, edited 7 times in total.
User avatar
ts-soft
Always Here
Always Here
Posts: 5756
Joined: Thu Jun 24, 2004 2:44 pm
Location: Berlin - Germany

Re: Display background image in Gtk2 and Gtk3 window

Post by ts-soft »

It works with gtk3 and ASCII compilation on Xubuntu 14.04 and Linux Mint Rosa.

It doesn,t work with gtk2 or in Unicode compilation.

Code: Select all

[12:46:40] Warte auf den Start des Executable...
[12:46:40] Executable-Typ: Linux - x64  (64bit, Unicode)
[12:46:40] Executable gestartet.
[12:46:41] [WARNING] Zeile: 48
[12:46:41] [WARNING] Gtk (WARNING): drawing failure for widget `GtkFixed': error while reading from input stream
[12:46:41] [WARNING] Zeile: 48
[12:46:41] [WARNING] Gtk (WARNING): drawing failure for widget `GtkViewport': error while reading from input stream
[12:46:41] [WARNING] Zeile: 48
[12:46:41] [WARNING] Gtk (WARNING): drawing failure for widget `GtkScrolledWindow': error while reading from input stream
[12:46:41] [WARNING] Zeile: 48
[12:46:41] [WARNING] Gtk (WARNING): drawing failure for widget `GtkVBox': error while reading from input stream
[12:46:41] [WARNING] Zeile: 48
[12:46:41] [WARNING] Gtk (WARNING): drawing failure for widget `GtkWindow': error while reading from input stream
[12:46:53] Die Programmausführung ist abgeschlossen.
Greetings - Thomas
PureBasic 5.73 | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Old bugs good, new bugs bad! Updates are evil: might fix old bugs and introduce no new ones.
Image
Oma
Enthusiast
Enthusiast
Posts: 312
Joined: Thu Jun 26, 2014 9:17 am
Location: Germany

Re: Display background image in Gtk2 and Gtk3 window

Post by Oma »

The wallpaper strikes back ... :lol: :wink:

Thank you shardik, so i can stop my trials definitively :D
This version has the advantage to be 'theme'-independent unlike the CSS-solution.
If you change the following Import:

Code: Select all

cairo_image_surface_create_from_png(Filename.S)
to

Code: Select all

cairo_image_surface_create_from_png(Filename.p-utf8)
it works on all my installations.

Best Regards, Charly
PureBasic 5.4-5.7, Linux: (X/L/K)Ubuntus+Mint - Windows XP (32Bit)
PureBasic Linux-API-Library & Viewer: http://www.chabba.de
User avatar
Shardik
Addict
Addict
Posts: 1991
Joined: Thu Apr 21, 2005 2:38 pm
Location: Germany

Re: Display background image in Gtk2 and Gtk3 window

Post by Shardik »

Thank you Thomas for your testing and error reports and thank you Charly for pinpointing the error in my import statement which caused the non-working in Unicode mode. I have corrected the import statement in my example above.

A further advantage of my solution is that it allows us to overlay images with a transparent background over a colored window background. I therefore also added a SetWindowColor() statement in my example above setting the window's color to a light yellow before overlaying the image while keeping its background transparent so that the yellow background is shining through... :wink:
ts-soft wrote:It doesn,t work with gtk2 or in Unicode compilation.
Does subsystem "gtk2" not work at all or only when using Unicode compilation (which should be fixed now)?
User avatar
ts-soft
Always Here
Always Here
Posts: 5756
Joined: Thu Jun 24, 2004 2:44 pm
Location: Berlin - Germany

Re: Display transparent background image in Gtk2 and Gtk3 wi

Post by ts-soft »

gtk2 doesn't work at all! No error, yellow background but no picture!
PureBasic 5.73 | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Old bugs good, new bugs bad! Updates are evil: might fix old bugs and introduce no new ones.
Image
Oma
Enthusiast
Enthusiast
Posts: 312
Joined: Thu Jun 26, 2014 9:17 am
Location: Germany

Re: Display transparent background image in Gtk2 and Gtk3 wi

Post by Oma »

Hello Thomas,
with gtk2 it works, but some systems need a kick to show a quick pic :wink: .
Since I don't want to post Shardik's Code completely, a few snippets to add ...
Add to Import ...

Code: Select all

ImportC ""
  gdk_cairo_create(*Drawable.GdkDrawable)
  g_signal_emit_by_name(*instance, detailed_signal.p-utf8, *callback); force a signal
Add to the Callback ...

Code: Select all

    cairo_rectangle(CairoContext, 10, 10, WindowWidth(0) - 20,
      WindowHeight(0) - 20)
    cairo_fill(CairoContext)
    gtk_widget_queue_draw_(*widget); added for instant display
And add to Signal-connection ...

Code: Select all

CompilerIf Subsystem("gtk2")
	g_signal_connect_(GetContainer(#Win_Main, "GtkFixed"), "expose-event", @WidgetExposeHandler(), 0)
	g_signal_emit_by_name(GetContainer(#Win_Main, "GtkFixed"), "expose-event", @WidgetExposeHandler()); force initial display
[added:] And so i think the following line is no longer necessary ...

Code: Select all

; While WindowEvent() : Wend;  no longer necessary, it think

It should force an initial redraw - i hope it works.

Bye, Charly

ps:
i've combined shardiks code with my trials and found out, that a single and stretched image or a cairo-painted background is possible too :D
PureBasic 5.4-5.7, Linux: (X/L/K)Ubuntus+Mint - Windows XP (32Bit)
PureBasic Linux-API-Library & Viewer: http://www.chabba.de
User avatar
Shardik
Addict
Addict
Posts: 1991
Joined: Thu Apr 21, 2005 2:38 pm
Location: Germany

Re: Display transparent background image in Gtk2 and Gtk3 wi

Post by Shardik »

ts-soft wrote:It works with gtk3 and ASCII compilation on Xubuntu 14.04 and Linux Mint Rosa.

It doesn,t work with gtk2 or in Unicode compilation.
In have modified my above example by inserting the line

Code: Select all

gtk_widget_queue_draw_(WindowID(0))
which forces an initial drawing of the window. Now also Xubuntu 14.04 x86 and Linux Mint 17.3 x86 "Rosa" are correctly displaying the background image directly at start overlaying the yellow background.

Thank you Charly for your workaround, but the addition of the single line for queuing the drawing of the window seems to be sufficient for both GTK2 and GTK3... :wink:
Post Reply