The revised code:
from pprint import pprint import gi gi.require_version('Gtk', '3.0') gi.require_version('Gst', '1.0') gi.require_version('GstVideo', '1.0') from gi.repository import Gtk, Gst Gst.init(None) Gst.init_check(None) class GstWidget(Gtk.Box): def __init__(self, pipeline): super().__init__() self.connect('realize', self._on_realize) self._bin = Gst.parse_bin_from_description('videotestsrc', True) def _on_realize(self, widget): pipeline = Gst.Pipeline() factory = pipeline.get_factory() gtksink = factory.make('gtksink') pipeline.add(gtksink) pipeline.add(self._bin) self._bin.link(gtksink) self.pack_start(gtksink.props.widget, True, True, 0) gtksink.props.widget.show() pipeline.set_state(Gst.State.PLAYING) window = Gtk.ApplicationWindow() header_bar = Gtk.HeaderBar() header_bar.set_show_close_button(True) window.set_titlebar(header_bar) # Place 2 widget = GstWidget('videotestsrc') widget.set_size_request(200, 200) window.add(widget) window.show_all() def on_destroy(win): try: Gtk.main_quit() except KeyboardInterrupt: pass window.connect('destroy', on_destroy) Gtk.main()
last modified January 6, 2022
#include <gtk/gtk.h>
int main(int argc, char *argv[]) {
GtkWidget *window;
GtkWidget *vbox;
GtkWidget *menubar;
GtkWidget *fileMenu;
GtkWidget *fileMi;
GtkWidget *quitMi;
gtk_init(&argc, &argv);
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), 300, 200);
gtk_window_set_title(GTK_WINDOW(window), "Simple menu");
vbox = gtk_vbox_new(FALSE, 0);
gtk_container_add(GTK_CONTAINER(window), vbox);
menubar = gtk_menu_bar_new();
fileMenu = gtk_menu_new();
fileMi = gtk_menu_item_new_with_label("File");
quitMi = gtk_menu_item_new_with_label("Quit");
gtk_menu_item_set_submenu(GTK_MENU_ITEM(fileMi), fileMenu);
gtk_menu_shell_append(GTK_MENU_SHELL(fileMenu), quitMi);
gtk_menu_shell_append(GTK_MENU_SHELL(menubar), fileMi);
gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 0);
g_signal_connect(G_OBJECT(window), "destroy",
G_CALLBACK(gtk_main_quit), NULL);
g_signal_connect(G_OBJECT(quitMi), "activate",
G_CALLBACK(gtk_main_quit), NULL);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
The menu in the examle has one menu item. By selecting the item, the application quits.
menubar = gtk_menu_bar_new();
The gtk_menu_bar_new
creates a new GtkMenuBar
.
filemenu = gtk_menu_new();
The fileMenu
is set to the File menu item with the
gtk_menu_item_set_submenu
function. Menus are containers
which hold menu items. They are themselves plugged to a particular menu item.
gtk_menu_shell_append(GTK_MENU_SHELL(fileMenu), quitMi);
The quitMi
is added to the File menu with the gtk_menu_shell_append
function.
gtk_menu_shell_append(GTK_MENU_SHELL(menubar), fileMi);
GtkSettings:gtk-menu-bar-popup-delay has been deprecated since version 3.10 and should not be used in newly-written code.,GtkSettings:gtk-menu-popup-delay has been deprecated since version 3.10 and should not be used in newly-written code.,GtkSettings:gtk-menu-popdown-delay has been deprecated since version 3.10 and should not be used in newly-written code.,GtkSettings:gtk-menu-bar-accel has been deprecated since version 3.10 and should not be used in newly-written code.
Object Hierarchy
GObject╰── GtkSettings
Includes
#include <gtk /gtk.h>
1 2 3 4 5 6
gtk_init( & argc, & argv);
// make sure the type is realized
g_type_class_unref(g_type_class_ref(GTK_TYPE_IMAGE_MENU_ITEM));
g_object_set(gtk_settings_get_default(), "gtk-enable-animations", FALSE, NULL);
gtk_settings_get_default ()
GtkSettings *
gtk_settings_get_default(void);
gtk_settings_get_for_screen ()
GtkSettings * gtk_settings_get_for_screen(GdkScreen * screen);
Create a GtkApplicationWindow with a menubar (with submenus) set to be shown.,Run the app, and open one of the menubar's items at least once.,Create a callback function that calls gtk_application_window_set_show_menubar() ,Connect this callback to the notify::fullscreened signal of the window
(hello: 203502): Gdk - ERROR **: 13: 32: 39.551: The program 'hello'
received an X Window System error.
This probably reflects a bug in the program.
The error was 'BadWindow (invalid Window parameter)'.
(Details: serial 2032 error_code 3 request_code 12(core protocol) minor_code 0)
(Note to programmers: normally, X errors are reported asynchronously; that is, you will receive the error a
while after causing it.To debug your program, run it with the GDK_SYNCHRONIZE environment variable to change this behavior.You can then get a meaningful backtrace from your debugger
if you
break on the gdk_x_error()
function.)
Trace / breakpoint trap(core dumped)
We are going to build a media player using the GTK+ toolkit, but the concepts apply to other toolkits like Qt, for example. A minimum knowledge of GTK+ will help understand this tutorial.,The error_cb, eos_cb and state_changed_cb are not really worth explaining, since they do the same as in all previous tutorials, but from their own function now.,And this is it! The amount of code in this tutorial might seem daunting but the required concepts are few and easy. If you have followed the previous tutorials and have a little knowledge of GTK, you probably understood this one can now enjoy your very own media player!,The main point is telling GStreamer to output the video to a window of our choice. The specific mechanism depends on the operating system (or rather, on the windowing system), but GStreamer provides a layer of abstraction for the sake of platform independence. This independence comes through the GstVideoOverlay interface, that allows the application to tell a video sink the handler of the window that should receive the rendering.
Regarding this tutorial's structure, we are not going to use forward function definitions anymore: Functions will be defined before they are used. Also, for clarity of explanation, the order in which the snippets of code are presented will not always match the program order. Use the line numbers to locate the snippets in the complete code.
#include <gdk /gdk.h>
#if defined (GDK_WINDOWING_X11)
#include <gdk /gdkx.h>
#elif defined (GDK_WINDOWING_WIN32)
#include <gdk /gdkwin32.h>
#elif defined (GDK_WINDOWING_QUARTZ)
#include <gdk /gdkquartzwindow.h>
#endif
This tutorial is composed mostly of callback functions, which will be
called from GStreamer or GTK+, so let's review the main
function,
which registers all these callbacks.
int main(int argc, char * argv[]) {
CustomData data;
GstStateChangeReturn ret;
GstBus * bus;
/* Initialize GTK */
gtk_init( & argc, & argv);
/* Initialize GStreamer */
gst_init( & argc, & argv);
/* Initialize our data structure */
memset( & data, 0, sizeof(data));
data.duration = GST_CLOCK_TIME_NONE;
/* Create the elements */
data.playbin = gst_element_factory_make("playbin", "playbin");
if (!data.playbin) {
g_printerr("Not all elements could be created.\n");
return -1;
}
/* Set the URI to play */
g_object_set(data.playbin, "uri", "https://www.freedesktop.org/software/gstreamer-sdk/data/media/sintel_trailer-480p.webm", NULL);
Standard GStreamer initialization and playbin pipeline creation, along with GTK+ initialization. Not much new.
/* Connect to interesting signals in playbin */
g_signal_connect(G_OBJECT(data.playbin), "video-tags-changed", (GCallback) tags_cb, & data);
g_signal_connect(G_OBJECT(data.playbin), "audio-tags-changed", (GCallback) tags_cb, & data);
g_signal_connect(G_OBJECT(data.playbin), "text-tags-changed", (GCallback) tags_cb, & data);
All GTK+ widget creation and signal registration happens in this function. It contains only GTK-related function calls, so we will skip over its definition. The signals to which it registers convey user commands, as shown below when reviewing the callbacks.
/* Instruct the bus to emit signals for each received message, and connect to the interesting signals */
bus = gst_element_get_bus(data.playbin);
gst_bus_add_signal_watch(bus);
g_signal_connect(G_OBJECT(bus), "message::error", (GCallback) error_cb, & data);
g_signal_connect(G_OBJECT(bus), "message::eos", (GCallback) eos_cb, & data);
g_signal_connect(G_OBJECT(bus), "message::state-changed", (GCallback) state_changed_cb, & data);
g_signal_connect(G_OBJECT(bus), "message::application", (GCallback) application_cb, & data);
gst_object_unref(bus);
Keep in mind that, in order for the bus watches to work (be it a
gst_bus_add_watch()
or a gst_bus_add_signal_watch()
), there must be
GLib Main Loop
running. In this case, it is hidden inside the
GTK+ main loop.
/* Register a function that GLib will call every second */
g_timeout_add_seconds(1, (GSourceFunc) refresh_ui, & data);
Mono will eventually implement a complete compatibility layer for the Windows.Forms user interface toolkit from Microsoft’s .NET platform. Windows.Forms should be seen as a migration strategy: Gtk# is the preferred toolkit for Linux., The -pkg:gtk-sharp option tells the compiler to reference all the Gtk# assemblies. Without it, the compiler wouldn’t know where to find the Gtk namespace. In MonoDevelop, you can control this from the References section of the Projects tab., User activity in one part of the interface often affects another part. Event handlers provide the plumbing.,The widget interaction is simple to understand. The creation of the interface using boxes should also be familiar from the previous lab. However, there are some new features introduced that give the user interface a little more polish and are worth noting:
// 04-gtk/01-basics
using System;
using Gtk;
class MainClass {
public static void Main(string[] args) {
Application.Init();
Window w = new Window("Gtk# Basics");
Button b = new Button("Hit me");
// set up event handling: verbose to illustrate
// the use of delegates.
w.DeleteEvent += new DeleteEventHandler(Window_Delete);
b.Clicked += new EventHandler(Button_Clicked);
// initialize the GUI
w.Add(b);
w.SetDefaultSize(200, 100);
w.ShowAll();
Application.Run();
}
static void Window_Delete(object o, DeleteEventArgs args) {
Application.Quit();
args.RetVal = true;
}
static void Button_Clicked(object o, EventArgs args) {
System.Console.WriteLine("Hello, World!");
}
}
// 04-gtk/01-basics
using System;
using Gtk;
class MainClass {
public static void Main(string[] args) {
Application.Init();
Window w = new Window("Gtk# Basics");
Button b = new Button("Hit me");
// set up event handling: verbose to illustrate
// the use of delegates.
w.DeleteEvent += new DeleteEventHandler(Window_Delete);
b.Clicked += new EventHandler(Button_Clicked);
// initialize the GUI
w.Add(b);
w.SetDefaultSize(200, 100);
w.ShowAll();
Application.Run();
}
static void Window_Delete(object o, DeleteEventArgs args) {
Application.Quit();
args.RetVal = true;
}
static void Button_Clicked(object o, EventArgs args) {
System.Console.WriteLine("Hello, World!");
}
}
Hello, World! Hello, World! Hello, World!
Hello, World! Hello, World! Hello, World!
// 04-gtk/02-layout
using System;
using Gtk;
class MainClass {
public static void Main(string[] args) {
Application.Init();
SetUpGui();
Application.Run();
}
static void SetUpGui() {
Window w = new Window("Layout Test");
HBox h = new HBox();
h.BorderWidth = 6;
h.Spacing = 6;
w.Add(h);
VBox v = new VBox();
v.Spacing = 6;
h.PackStart(v, false, false, 0);
Label l = new Label("Full name:");
l.Xalign = 0;
v.PackStart(l, true, false, 0);
l = new Label("Email address:");
l.Xalign = 0;
v.PackStart(l, true, false, 0);
v = new VBox();
v.Spacing = 6;
h.PackStart(v, true, true, 0);
v.PackStart(new Entry(), true, true, 0);
v.PackStart(new Entry(), true, true, 0);
w.DeleteEvent += Window_Delete;
w.ShowAll();
}
static void Window_Delete(object o, DeleteEventArgs args) {
Application.Quit();
args.RetVal = true;
}
}