Marcin Jahn | Dev Notebook
  • Home
  • Programming
  • Technologies
  • Projects
  • About
  • Home
  • Programming
  • Technologies
  • Projects
  • About
  • An icon of the Core section Core
    • Programs Execution
    • Stack and Heap
    • Asynchronous Programming
      • Overview
      • Event Queues
      • Fibers
      • Stackless Coroutines
  • An icon of the .NET section .NET
    • HTTPClient
    • Async
      • How Async Works
      • TAP Tips
    • Equality
    • Comparisons
    • Enumerables
    • Unit Tests
    • Generic Host
    • Logging
    • Configuration
    • Records
    • Nullability
    • Garbage Collector
    • IL and Allocations
    • gRPC
    • Source Generators
    • Platform Invoke
    • ASP.NET Core
      • Overview
      • Middleware
      • Razor Pages
      • Routing in Razor Pages
      • Web APIs
      • Filters
      • Identity
      • Validation
      • Tips
    • Entity Framework Core
      • Overview
      • Testing
      • Tips
  • An icon of the Angular section Angular
    • Overview
    • Components
    • Directives
    • Services and DI
    • Routing
    • Observables (RxJS)
    • Forms
    • Pipes
    • HTTP
    • Modules
    • NgRx
    • Angular Universal
    • Tips
    • Standalone Components
  • An icon of the JavaScript section JavaScript
    • OOP
    • JavaScript - The Weird Parts
    • JS Functions
    • ES Modules
    • Node.js
    • Axios Tips
    • TypeScript
      • TypeScript Environment Setup
      • TypeScript Tips
    • React
      • React Routing
      • MobX
    • Advanced Vue.js Features
  • An icon of the Rust section Rust
    • Overview
    • Cargo
    • Basics
    • Ownership
    • Structures
    • Enums
    • Organization
    • Collections
    • Error Handling
    • Generics
    • Traits
    • Lifetimes
    • Closures
    • Raw Pointers
    • Smart Pointers
    • Concurrency
    • Testing
    • Tips
  • An icon of the C/C++ section C/C++
    • Compilation
    • Structures
    • OOP in C
    • Pointers
    • Strings
    • Dynamic Memory
    • argc and argv Visualization
  • An icon of the GTK section GTK
    • Overview
    • GObject
    • GJS
  • An icon of the CSS section CSS
    • Responsive Design
    • CSS Tips
    • CSS Pixel
  • An icon of the Unity section Unity
    • Unity
  • An icon of the Functional Programming section Functional Programming
    • Fundamentals of Functional Programming
    • .NET Functional Features
    • Signatures
    • Function Composition
    • Error Handling
    • Partial Application
    • Modularity
    • Category Theory
      • Overview
      • Monoid
      • Other Magmas
      • Functors
  • An icon of the Algorithms section Algorithms
    • Big O Notation
    • Array
    • Linked List
    • Queue
    • Hash Table and Set
    • Tree
    • Sorting
    • Searching
  • An icon of the Architecture section Architecture
    • What is architecture?
    • Domain-Driven Design
    • ASP.NET Core Projects
  • An icon of the Core section Core
    • Programs Execution
    • Stack and Heap
    • Asynchronous Programming
      • Overview
      • Event Queues
      • Fibers
      • Stackless Coroutines
  • An icon of the .NET section .NET
    • HTTPClient
    • Async
      • How Async Works
      • TAP Tips
    • Equality
    • Comparisons
    • Enumerables
    • Unit Tests
    • Generic Host
    • Logging
    • Configuration
    • Records
    • Nullability
    • Garbage Collector
    • IL and Allocations
    • gRPC
    • Source Generators
    • Platform Invoke
    • ASP.NET Core
      • Overview
      • Middleware
      • Razor Pages
      • Routing in Razor Pages
      • Web APIs
      • Filters
      • Identity
      • Validation
      • Tips
    • Entity Framework Core
      • Overview
      • Testing
      • Tips
  • An icon of the Angular section Angular
    • Overview
    • Components
    • Directives
    • Services and DI
    • Routing
    • Observables (RxJS)
    • Forms
    • Pipes
    • HTTP
    • Modules
    • NgRx
    • Angular Universal
    • Tips
    • Standalone Components
  • An icon of the JavaScript section JavaScript
    • OOP
    • JavaScript - The Weird Parts
    • JS Functions
    • ES Modules
    • Node.js
    • Axios Tips
    • TypeScript
      • TypeScript Environment Setup
      • TypeScript Tips
    • React
      • React Routing
      • MobX
    • Advanced Vue.js Features
  • An icon of the Rust section Rust
    • Overview
    • Cargo
    • Basics
    • Ownership
    • Structures
    • Enums
    • Organization
    • Collections
    • Error Handling
    • Generics
    • Traits
    • Lifetimes
    • Closures
    • Raw Pointers
    • Smart Pointers
    • Concurrency
    • Testing
    • Tips
  • An icon of the C/C++ section C/C++
    • Compilation
    • Structures
    • OOP in C
    • Pointers
    • Strings
    • Dynamic Memory
    • argc and argv Visualization
  • An icon of the GTK section GTK
    • Overview
    • GObject
    • GJS
  • An icon of the CSS section CSS
    • Responsive Design
    • CSS Tips
    • CSS Pixel
  • An icon of the Unity section Unity
    • Unity
  • An icon of the Functional Programming section Functional Programming
    • Fundamentals of Functional Programming
    • .NET Functional Features
    • Signatures
    • Function Composition
    • Error Handling
    • Partial Application
    • Modularity
    • Category Theory
      • Overview
      • Monoid
      • Other Magmas
      • Functors
  • An icon of the Algorithms section Algorithms
    • Big O Notation
    • Array
    • Linked List
    • Queue
    • Hash Table and Set
    • Tree
    • Sorting
    • Searching
  • An icon of the Architecture section Architecture
    • What is architecture?
    • Domain-Driven Design
    • ASP.NET Core Projects

GObject

GObject is a library that is a base for many other Gnome libraries (like GTK). It is a common base layer providing OOP paradigm to the C language. It may be seen as an alternative to C++ or Objective C, since it enables developers to create classes, but in this case, directly in C (however, in a rather tedious way, since it’s still “just” C)!

GObject is a part of GLib and uses the same version numbers. GLib contains:

  • GObject - type system
  • GThread - threading
  • GIO - I/O operations
  • others…

QT

A kind of similar thing to GLib in the KDE world is QtCore, although QT is a C++ framework so it skips the entire “OOP in C” mess.

Some features of GObject that are often used in GTK apps are:

  • the GObject root base type
  • signals (like events in .NET)

History

GObject has been created in the 90s, and the design hasn’t changed much since then. It’s been created before C++ has been standardized (and probably this is why it was even created instead of just using C++).

GObject was originally a part of GIMP Toolkit, which was created for GIMP. Later, GTK was extracted from GIMP to become a standalone thing.

Implementation

The base type of all types in GTK is GTypeInstance (also GObject inherits from it). However, we usually use GObject as a base when we want to refer to anything in the GTK world, since it implements the core things such as signals or properties (it’s a bit more complicated than that).

Instances and Classes

GTK types have separate structs for instances and classes, e.g. there is GObject (instance) and GObjectClass. The stuff in GObjectClass is shared among all GObjects (a list of signals, properties, CSS classes, etc.), while GObject contains instance-specific data.

Here’s an example of types that we could find in GLib:

struct GObject {
struct GTypeInstance parent_instance;
};
struct GObjectClass {
struct GTypeClass parent_instance;
};
struct GtkWidget {
struct GtkObject parent_instance;
};
struct GtkWidgetClass {
struct GtkObjectClass parent_instance;
};
struct GtkButton {
struct GtkWidget parent_instance;
};
struct GtkButtonClass {
struct GtkWidgetClass parent_instance;
};

The “Thing” and “ThingClass” structs are connected via GTypeInstance and GTypeClass:

struct GTypeClass {
//....
};
struct GTypeInstance {
struct GTypeClass* g_class;
};

So, for example, every instance of GtkButton will have a pointer to a (common) instance of GtkButtonClass. There are even macros that allow us to retrieve a ThingClass from Thing, like GTK_BUTTON_GET_CLASS, (it’s an equivalent of ((GTypeInstance*)instance)->g_type).

There are lots of other macros, some of them just cast one type to another to make the code more readable (plus, they can do some type checks for safety).

Registration

Every type in the GObject inheritance tree (also our custom types) needs to be registered. When registering we need to provide a bunch of information:

  • what is the size of the instance
  • what is the size of the class
  • what’s the init function of the instance type
  • what’s the init function of the class type

Well, actually we don’t need to provide all this information, because there’s a G_DEFINE_TYPE macro that takes care of that, making it as simple as it can be, also verifying that we do not register the same type multiple times, taking care of thread safety, and so on.

Thanks to the registration, the instantation of the new objects of the registered type will be simplified later on, and it will properly set up the new object using the GObject type system. Otherwise, we’d have to do a bunch of things manually, probably making some mistakes in the process and also making the code completely unreadable.

The registration process requires us to follow some conventions, like creating a duet of instance and class types that we talked about before (and the class type needs to have Class postfix!)

The registration returns a GType.

Bindings

The GObject libraries are written in the C language. However, there are a bunch of bindings for many other programming languages that open the toolkit to a vast group of developers. Examples of supported languages include:

  • C (obviously)
  • JavaScript
  • Python
  • Rust
  • Vala
  • C#
  • and more…

Since there are a lot of GObject-based libraries, there is an established way of generating bindings for them - GObject Introspection. The bindings, under the hood, call the C libraries code via mechanisms similar to PInvoke.

GTK is a base for many other GUI frameworks, often those that target multiple operating systems (like Avalonia UI or Tauri). These frameworks often rely on GTK 3, since GTK 4 is still relatively new.

References

  • Dive into GObject (YouTube)
←  Overview
GJS  →
© 2023 Marcin Jahn | Dev Notebook | All Rights Reserved. | Built with Astro.