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)