This is the old design for the ApplicationClass; it's kept here mostly because of the points raised
2010-02-22
- the Application class should provide a "best practise" approach, not be a "one-size-fits-all" approach
- the current best practise is the document-based model, where "document" is any object an application considers an atomic block of data
- 1:1 mapping between documents and windows is the least common denominator
- one (document) to many (windows) mapping is a hard requirement
- many (documents) to one (window) mapping is a soft requirement
- should hold a reference to every document object and to every window
- should also be an abstract class: applications should subclass it in order to use it
- should not be an interface, as a default base implementation is desiderable for simple applications
- should provide hooks for the session management
- should provide a subclass for single instance applications
should bind a desktop entry file, possibly using the EggLauncher object in libegg, to an application
- should provide a way to automatically save the open documents if needed
- should provide a way to automatically save the metadata bound to a document view
Bottom-Up
Document
- the Document is an interface
- async vfuncs to open and save a file
- flags (readable, writable, printable, lockable, etc.)
- metadata (application-specific, just hooks to set/get)
typedef void (* EggDocumentSaveCallback) (EggDocumentHandle *handle, const gchar *uri, gboolean overwrite, gboolean save_backup, GError *error, gpointer data); typedef void (* EggDocumentOpenCallback) (EggDocumentHandle *handle, const gchar *uri, gboolean read_only, GError *error, gpointer data); typedef void (* EggDocumentSetInfoCallback) (EggDocumentHandle *handle, const gchar *uri, EggDocumentInfo *info, GError *error, gpointer data); typedef void (* EggDocumentGetInfoCallback) (EggDocumentHandle *handle, const gchar *uri, EggDocumentInfo *info, GError *error, gpointer data); struct _EggDocumentClassIface { GTypeInterface g_iface; /* vtable */ EggDocumentFlags (* get_flags) (EggDocument *document); void (* set_flags) (EggDocument *document, EggDocumentFlags flags); EggDocumentHandle (* save_document) (EggDocument *document, const gchar *save_uri, gboolean overwrite, gboolean save_backup, EggDocumentSaveCallback callback, gpointer data); EggDocumentHandle (* open_document) (EggDocument *document, const gchar *uri, gboolean read_only, EggDocumentOpenCallback callback, gpointer data); EggDocumentHandle (* set_info) (EggDocument *document, EggDocumentInfo *info, EggDocumentSetInfoCallback callback, gpointer data); EggDocumentHandle (* get_info) (EggDocument *document, EggDocumentGetInfoCallback callback, gpointer data); void (* cancel_operation) (EggDocumentHandle *handle); /* signals */ void (* changed) (EggDocument *document); void (* error) (EggDocument *document, const GError *error); };
GTK+ might provide some simple document implementation, like GtkTextDocument
- the set_info and get_info functions should be used to save the metadata bound to a document
should EggDocumentInfo be an opaque structure with predefined data or a subclassable object?
Document Model
- keeps a reference to every document type
- every document has a path, in form of "element:element:element"
- this allows doing "document:revision", or "document:section"
uses the GType to create documents
- overridable or chainable
- can set the properties to its children
- overridable or chainable
struct _EggDocumentModel { GObject parent_instance; /*< private >*/ EggDocumentModelPrivate *priv; }; struct _EggDocumentModel { GObjectClass parent_class; /* vtable, not signals */ EggDocument *(* create_document) (EggDocumentModel *model, GType document_type); void (* set_document_property) (EggDocumentModel *model, EggDocument *document, const gchar *property_name, const GValue *value); void (* get_document_property) (EggDocumentModel *model, EggDocument *document, const gchar *property_name, GValue *value); /* signals */ void (* document_changed) (EggDocumentModel *model, EggDocumentPath *path, EggDocument *document); void (* document_add) (EggDocumentModel *model, EggDocumentPath *path, EggDocument *document); void (* document_remove) (EggDocumentModel *model, EggDocumentPath *path, EggDocument *document); /* padding for future expansion */ void (*_egg_reserved1) (void) void (*_egg_reserved2) (void) void (*_egg_reserved3) (void) void (*_egg_reserved4) (void) };
- create a new document model:
enum { DOCUMENT_TEXT_PLAIN, DOCUMENT_TEXT_HTML }; EggDocumentModel *model; model = egg_document_model_new (2, DOCUMENT_TEXT_PLAIN, DOCUMENT_TYPE_TEXT, DOCUMENT_TEXT_HTML, DOCUMENT_TYPE_HTML);
- create a new document:
EggDocument *document; EggDocumentPath *path; document = egg_document_model_create_document (DOCUMENT_TEXT_PLAIN, "file", "foo.txt", NULL); path = egg_document_path_new_from_string ("myapp:foo-txt"); egg_document_model_add_document (model, path, document);
Application
- provides the default document model
- can set/get the document model
- hooks documents and windows together
- replaces the gtk_init()/gtk_main()/gtk_main_quit() cycle
- provides signals for handling the lifetime of the application
- hooks into the session management
struct _EggApplicationClass { GObjectClass parent_class; /* vfuncs, not signals */ /* override if you wish to parse the command line arguments */ gboolean (* application_init) (EggApplication *application, GOptionContext *context, gint *argc, gchar ***argv); /* override to manager the widget for the document GtkWidget *(* create_document_view) (GtkApplication *application, GtkDocument *document); /* used to control the widget type of the document view */ GType document_view_type; /* signals */ /* return FALSE to stop the emission of the event */ gboolean (* application_quit) (EggApplication *application); /* emitted when the document model changes */ void (* document_model_set) (EggApplication *application, EggDocumentModel *old_model); void (* document_view_add) (EggApplication *application, EggDocument *document, GtkWidget *widget); void (* document_view_remove) (EggApplication *application, EggDocument *document, GtkWidget *widget); };
should we add a EggDocumentView interface?
struct _EggDocumentViewIface { GTypeInterface g_iface; void (* add_document) (EggDocumentView *view, EggDocument *document); void (* remove_document) (EggDocumentView *view, EggDocument *document); GSList *(* list_documents) (EggDocumentView *view); };
- this would allow many-documents-to-single-view mapping
Comments
Support for LibUnique and/or DesktopAppsAsDBusServices
(RaphaelBosshard) Is there a chance to extend GtkApplication with a GtkMainMenuBar? (See http://bugzilla.gnome.org/show_bug.cgi?id=353076)
How can the DocumentSave and DocumentOpen callbacks indicate that an error happened during loading.
- Will there by default implementation to show common error messages for common problems such as wrong access rights?
- A future version should probably have API or default implementation to indicate inability to load newer versions of file formats, and to warn when re-saving a document in a later version of a file format.
- (murrayc)
errors are relayed from inside the actual document implementation, by setting the GError structure and invoking the callback; the async design is similar to the GtkFileSystem async design kris did.
- So who implements the error dialogs? GTK+ or the application author. If it's in GTK+ then it will be consistent.
- (murrayc)
- versioning of the file is at application level: how could GTK+ know that the version changed?
- If the Document is a GInterface, then that can be a method of the interface, for the application author to implement.
- (murrayc)
- GTK+ could provide at most an error code for that, but not every application have a file format that can change (text editors?)
- Almost every application will have this issue. The feature would not be a problem for applications that don't need it.
- (ebassi)
- About these document paths:
- If its going to be used to indicate both revision numbers and document sub-sections, how do these two concepts look different in the syntax?
- For document structure, why not just use XML, and let the application coder use libxml to navigate through the structure, maybe with some helper functions.
- (murrayc)
- the document path is a unique identifier for a document object inside the model: the semantics of the path elements are entirely up to the application to define; I though of using paths to offer a uniform access method instead of using the documents URI - that is why the path is an opaque structure.
- what kind of structure? a document might also be unstructured data (text/plain, to continue the editor instance).
- (ebassi)
- This sounds rather ambitious and vague. There's plenty of work to do on making the basic open/save funtionality easy and consistent, without this.
- (murrayc)