Hi all,We talked in the past with other GTK developers about the possibility of integrating a preview library, allowing GTK applications to easily get a widget that represents the preview of a file. This would currently be used by GtkFileChooser, or a future evolution of the current class, but also by file managers, possibly mail clients, etc.I wrote a draft proposal for the architecture of the library. The "master copy" lives for now in a Google Doc free for comments here [1], but I will also paste it here below. I will move this to the GNOME Wiki once I have received the initial feedback.Comments welcome![1] https://docs.google.com/document/d/1kaHZtOSUMgm6qB3FLzGNuYJIgJVAEnWMvBPDvlzNeNY/edit?usp=sharingOverview
The primary goal of the feature is to be able to create an interactive preview of a given file, in the form of a GtkWidget, from a generic interface that is extensible to different mime types.
“Interactive” means that a set of actions can be performed on the preview itself. For instance, when previewing a PDF document it is desirable to switch to previous/next page; when previewing a video or a song it’s desirable to play/pause, etc.
The feature lives ideally inside GTK.
Architecture
The requirement of supporting the widest variety of formats possible in the library calls for an extensible system, where a set of modules are registered as preview “providers”, each handling a list of mime types. This also avoids the need for GTK to directly link to all the dependencies directly, but some providers could be distributed as part of GTK (e.g. a GdkPixbuf-based one for images).
The most straightforward way to implement this is through an extension point with a well-defined interface that can be implemented by shared objects modules installed by the different libraries or applications that want to extend the functionality.
It should also be possible for implementations to use a DBus interface to transfer the data. This makes it possible for an actual application to be spawned in response to a preview request, and send the data over the wire, which will be not as expensive as it is now when kdbus enters the picture. Doing this in a generic “dbus implementation” module might be hard though, because it’s not possible to export a GtkWidget over DBus, and is outside the scope of this proposal. I imagine e.g. a Totem-provided viewer to be able to stream the video to the library, but the Totem module would still know how to draw back the data it receives from the Totem process.
Registration
Modules can register themselves by installing a .so file into a known location. A design where a textual descriptor is also installed, providing metadata about the module capabilities is possible; otherwise there could be methods on the module interface to define that without the need of an extra file. An advantage of the descriptor file is that it makes it easy to e.g. load modules in priority order (by just sorting the descriptors alphabetically), giving the library a mechanism to predictably resolve conflicts in case two modules claim to handle the same mime type.
Interface
We need two separate interfaces; one used by the client of the library and one between the library and the modules.
Client
GtkWidget * gtk_preview_widget_new (void)
GtkWidget * gtk_preview_widget_new_from_file (GFile *)
void gtk_preview_widget_set_file (GtkPreviewWidget *, GFile *)
GFile * gtk_preview_widget_get_file (GtkPreviewWidget *)
These are all pretty obvious; to create a preview widget you need a file.
GtkPreviewContext * gtk_preview_widget_get_context (GtkPreviewWidget *)
Everything that relates to the widget but is not part of the widget itself is split into a GtkPreviewContext object. This is effectively the entry point for all the actions-related operations.
GtkPreviewContext implements GActionGroup
GIcon * gtk_preview_context_get_icon (GtkPreviewContext *, gchar * action)
gchar * gtk_preview_context_get_label (GtkPreviewContext *, gchar * action)
gchar * gtk_preview_context_get_description (GtkPreviewContext *, gchar * action)
By implementing GActionGroup, GtkPreviewContext can be used by the client to enumerate actions and create UI elements with them. There are no assumptions on where the actions come from; for instance, GtkPreviewContext could add by default an “open” action that is handled in a generic way entirely outside of the module. Similarly, applications could add their own actions on top of the stock.
Higher level objects can be built on top of these two simple classes. For instance, a GtkPreviewDialog could be created that displays the preview widget in a GtkScrolledWindow with actions in a GtkActionBar below it.
Module
GLib and GIO offer low-level and higher-level APIs to setup a library extension point. Assuming that part of the problem is solved, let’s define GtkPreviewModule as the interface that all modules need to implement.
GtkPreviewModule * gtk_preview_get_module_for_file (GFile *)
This is where the type detection mechanism is plugged in; GTK will internally keep knowledge of the available modules and return the right one compatible with the passed-in file.
GtkPreviewWidget * gtk_preview_module_create_widget (GtkPreviewModule *, GFile *)
This is the main entry point for the module to return the widget.
GIcon * gtk_preview_module_get_icon (GtkPreviewModule *, gchar * action)
gchar * gtk_preview_module_get_label (GtkPreviewModule *, gchar * action)
gchar * gtk_preview_module_get_description (GtkPreviewModule *, gchar * action)
These methods are useful to return the information needed by the context object exposed to the client.
GtkPreviewContext * gtk_preview_context_new (GtkPreviewModule *)
void gtk_preview_widget_set_context (GtkPreviewWidget *, GtkPreviewContext *)
These methods tie the module and the context together, and are only used for module implementations.
Depending on how mimetype detection is implemented, modules might need to expose a method like gboolean gtk_preview_module_supports_type (GtkPreviewModule *). However, I’m leaning towards the text file descriptor for this kind of information, as it allows more easily a distributor or system administrator to give priority to certain modules over others or blacklist them.