Gir.Core

repository·main·Indexed 19 days ago

https://github.com/gircore/gir.core

High-fidelity C# bindings for GObject-based libraries, such as GTK and GStreamer, using GObject Introspection. It enables cross-platform .NET development for rich UIs and multimedia by bridging the GObject type system with .NET. The project provides NuGet packages for various libraries including GTK-4.0, Libadwaita-1, GStreamer-1.0, Cairo-1.0, and WebKit-6.0.

Tokens
9.6K
Snippets
30
Records
49
Agent score
65%

What's inside Gir.Core

  1. Overview of Gir.Core

    main

    Gir.Core provides C# bindings for GObject-based libraries, such as GTK for user interfaces. It is built upon the GObject Introspection (GI) framework to provide a complete set of APIs for writing rich, cross-platform user interfaces and multimedia programs.

    Key features include:

    • Deep integration: Bridges the GObject type system with .NET without relying on reflection.
    • Automatic memory management: Simplifies the C-API by handling memory automatically.
    • Complete API support: Covers the entire GTK and GStreamer stacks.
    • Extensibility: Allows 3rd party developers to write bindings for other GObject-based libraries, ensuring interoperability.
  2. Explore GirCore integration libraries

    main

    GirCore is integrated with several libraries across different platforms. You can use these libraries to extend GirCore's capabilities for specific desktop environments, graphics engines, or cross-platform frameworks.

    GTK Ecosystem

    • Nickvision.Desktop: Provides cross-platform C# service classes to encapsulate differences between Windows and Linux.
    • Nickvision.Desktop.GNOME: Provides GirCore extensions and helpers specifically for using Blueprint files in C# projects.
    • SkiaSharp.Views.GirCore: Enables using SkiaSharp on Linux by providing GTK4 and Cairo-backed views.

    .NET MAUI

    • Linux GTK4 backend: An experimental backend for .NET MAUI that uses GirCore bindings to render MAUI controls as native GTK4 widgets.

    Tooling

    • Nickvision.FlatpakGenerator: A tool used to generate a nuget-sources.json file, which is required for including NuGet packages in a Flatpak build.
  3. Explore applications built with Gir.Core

    main

    Gir.Core is used by a variety of desktop applications across different domains such as media players, finance managers, and web browsers. You can use these applications as reference implementations for how to integrate Gir.Core into your own projects.

    Key application examples include:

    • Media & Audio:
      • Aria: Music player controller (e.g., for MPD).
      • Cavalier: Audio visualizer based on CAVA.
      • JellyTune: GNOME audio client for Jellyfin.
      • Tagger: Music tag editor.
    • Productivity & Utilities:
      • Denaro: Personal finance manager.
      • Parabolic: Web video and audio media downloader.
      • Pinta: Image editing and drawing application.
      • WebCamControl: Linux GUI for controlling webcam properties (pan, tilt, zoom, etc.).
    • Browsers & Hardware:
      • Ouch Browser: Web browser featuring vertical tabs.
      • Maus: Configuration tool for Microsoft IntelliMouse Pro (serves as a technology demo for latest Gir.Core features).
  4. Implement a Complex DropDown using Gio.ListStore and SignalListItemFactory

    main

    For advanced DropDown requirements where each item needs to hold custom data, follow this pattern:

    1. Data Model: Use Gio.ListStore to hold instances of your custom model/object.
    2. Item Rendering: Use Gtk.SignalListItemFactory to define how the custom data is mapped to the UI. In complex scenarios, you may need multiple instances of Gtk.SignalListItemFactory to handle different aspects of the item display.
  5. Use factory methods instead of C# constructors for GObject classes

    main

    In Gir.Core, classes inheriting from GObject.Object should not use standard C# constructors for instantiation. This is because GObject uses factory methods for instance creation, and using C# constructors can break the integration between the .NET and GObject type systems.

    Instead of using the new keyword, use the NewWithProperties factory method provided by the GObject.Object class. This ensures the instance is correctly recognized by the GObject runtime.

    // Instead of:
    // var obj = new MyObject();
    
    // Use:
    var obj = MyObject.NewWithProperties([]);
  6. Handle property changed notifications in GObject

    main

    GObject uses a notification system similar to INotifyPropertyChanged. Every class inheriting from GObject.Object has an Object.OnNotify event.

    Key Concepts

    • Native vs. Managed Names: C# properties are often camel-cased, while native GObject properties use different naming. Use the static Property descriptor on a class to find the mapping between managed and unmanaged names.
    • Specific Property Subscriptions: Instead of listening to all changes via OnNotify, you can subscribe to a specific property using NotifySignal.Connect() by providing the native name in the detail parameter.
    • Alternative API: You can avoid manual string names by using the Notify() method provided on property definition objects.

    Usage Examples

    Using NotifySignal.Connect (requires native name):

    NotifySignal.Connect(
        sender: myObj,
        signalHandler: OnMyPropertyChanged,
        detail: "my-property" // Must be the native name
    );

    Using the Property Definition API (recommended):

    Gtk.Button.LabelPropertyDefinition.Notify(
        sender: myButton,
        signalHandler: OnButtonLabelChanged
    );
    NotifySignal.Connect(
        sender: myObj,
        signalHandler: OnMyPropertyChanged,
        detail: "my-property"
    );
  7. Use Gtk.Box for layout management

    main

    A Gtk.Box is used to arrange multiple widgets either vertically or horizontally.

    Key Concepts:

    • Orientation: Set via Gtk.Orientation.Horizontal (side-by-side) or Gtk.Orientation.Vertical (stacked).
    • Spacing: The gap between widgets in pixels is defined during initialization.
    • Adding Widgets:
      • Append(widget): Adds the widget to the end of the box.
      • Prepend(widget): Adds the widget to the start of the box.

    Creating Spacers for Alignment:

    To push widgets to specific sides of a window during resizing, use an empty Gtk.Box as a spacer and set its expansion property:

    • Vertical Spacer: Create a vertical box and call SetVexpand(true). This pushes subsequent widgets to the bottom.
    • Horizontal Spacer: Create a horizontal box and call SetHexpand(true). This pushes subsequent widgets to the right.
    // Vertical spacer to push widgets to the bottom
    var vSpacer = Gtk.Box.New(Gtk.Orientation.Vertical, 0);
    vSpacer.SetVexpand(true);
    
    // Horizontal spacer to push widgets to the right
    var hSpacer = Gtk.Box.New(Gtk.Orientation.Horizontal, 0);
    hSpacer.SetHexpand(true);
  8. Create custom widgets with GTK composite templates

    main

    GTK composite templates allow you to associate a Gtk.Widget subclass with a *.ui file.

    Implementation Steps

    1. Use [GObject.Subclass<BaseWidgetType>] to define the base type.
    2. Use [Gtk.Template(typeof(YourTemplateLoader))] to define the UI file source.
    3. Use [Gtk.Connect] to bind class members to specific UI elements in the template. If no name is specified in the attribute, it defaults to the member's name.

    Supported Template Loaders

    • Gtk.AssemblyResource: Loads the UI file from an assembly resource.
    • Gtk.GResource: Loads the UI file from a registered GResource.

    You can implement the Gtk.TemplateLoader interface to create custom loaders that retrieve UI files from arbitrary locations.

  9. Introduction to GTK GUI Development with Gir.Core

    main

    When developing GTK applications with Gir.Core, you have two primary approaches for UI construction:

    1. Code-based UI: Useful for learning the basics of the framework and understanding how widgets are instantiated and configured programmatically.
    2. Declarative UI: For real-world applications, it is recommended to use external UI definition files rather than hardcoding layouts.

    Recommended UI Tools:

    • GTK Builder XML: The standard way to define UIs in GTK.
    • Blueprint: A modern, human-readable language for describing GTK interfaces. You can use Workbench to preview Blueprint code in real-time.
    • Cambalache: A visual UI designer (similar to the old Glade) that works with GTK 4, unlike the original Glade which is limited to GTK 2/3.
  10. Implement a GObject subclass with a parameterized constructor

    main

    Since standard C# parameterized constructors are not supported for GObject subclasses, you should implement a static factory method (e.g., NewWith[ParameterName]) that handles the creation and subsequent property assignment.

    1. Use [GObject.Subclass<TBase>] on a partial class.
    2. Create a public static method that calls NewWithProperties([]).
    3. Assign the passed parameters to the instance fields.
    4. Return the instance.
    [GObject.Subclass<GObject.Object>]
    public partial class MyObject
    {
        private string? data;
     
        public static MyObject NewWithString(string data)
        {
            var obj = NewWithProperties([]);
            obj.data = data;
            return obj;
        }
    }
  11. Generate bindings and build libraries locally

    main

    To generate the bindings and build the libraries from source, you must first clone the repository with submodules initialized recursively to ensure the gir-files directory is correctly loaded. Then, use the provided F# scripts to generate the libraries and the .slnf solution filter to build them.

    Prerequisites:

    • Git
    • .NET SDK (for dotnet commands and fsi execution)
    • Submodules must be initialized with --recursive.
    $ git clone --recursive https://github.com/gircore/gir.core.git
    $ cd gir.core/scripts
    $ dotnet fsi GenerateLibs.fsx
    $ cd ../src
    $ dotnet build GirCore.Libs.slnf