This page is a discussion board for the possible approaches to taming the Inkscape multi-window interface - that is, making it as intuitive and convenient as possible within the constraints of our chosen toolkit and the various platforms that we want the program to run on. At the moment, the interface is way too GIMPish and clumsy to satisfy a professional user: windows pop up and bury seemingly at random, taskbar is cluttered, keypresses and mouse events often end up not where they were intended, etc. The only more or less sane way to use Inkscape is by removing it into a desktop of its own, use only non-overlapping windows, and enabling "focus follows mouse." However, Windows users (not sure about Mac) don't have multiple desktops nor "focus follows mouse" and are therefore unlikely to find Inkscape very usable. Hence this page.
Please use offset paragraphs (starting with :) to add your comments. --bb
I. Dialogs and toolbar must be transient.
Transient windows behave like "children" of a parent window; they don't normally have their own taskbar icon, are always on top of their parent window, and are minimized/maximized together with the parent window. Overall this is what most win/mac users expect from dialogs and toolbars.
- By the way, be prepared for a possible flame from Gnome developers. Here's what Havoc Pennington writes in his book:
- A transient dialog is one that appears and is dismissed relatively quickly. (GnomeDialog is really meant for transient dialogs.) Some "dialogs" are just small windows, such as the tool palette in the Gimp. These persistent ("floating") dialogs should be minimizable without minimizing the parent, and they should not be forced to stay above the parent window.
- Which IMHO is very wrong: it does not matter how long a dialog stays open, it only matters what you do with it. A tool palette makes no sense without a document to apply these tools to, and therefore must be "transient" to stay on top. Unfortunately someone chose this wrong term ("transient" meaning "temporary") and this seems to affect many programmers who underutilize transient windows making their interfaces almost unusable (Gimp is not the only example). --bb
Looks like everyone agrees on this one. However, Mental writes:
I tried to submit patches to mark windows transient to Sodipodi a long time ago, but they were rejected on the grounds that some window managers might not put decorations on transient windows. I guess we probably should make a little widget that provides a little bar to drag the window by and a close button, just in case. http://sourceforge.net/tracker/index.php?func=detail&aid=840061&group_id=93438&atid=604309
Perhaps there are two possible approaches to this:
1. Consider the said windowmanagers broken; provide a workaround for them (see below) but otherwise concentrate on the "normal" wms that do not remove decorations. Generally, assume that transient windows do have decorations and not bother with "fake" bars for dragging. Perhaps also help the wms to get it right by explicitly assigning decorations to all transient windows.
Pro: simple to implement. Contra: may be inconsistent across wms.
2. On the contrary, explicitly remove all decorations from transients (assuming all wms will obey) and create instead a set of "fake" decorations for dragging, resizing, etc.
Pro: consistent, unique recognizable look. Possibly more useful functionality than a wm can provide (e.g. roll-up buttons). Contra: lots of work, inconsistent with the rest of the windows on the system.
I need your feedback to choose one of these ways. Something in the mid-way between the two is hardly possible, simply because GTK cannot reliably detect if a window has any decorations or not. So it's like all or nothing.
- Perhaps it is not as all or nothing as one might think, simply make it a configurable option and let the user deceide which approach fits best. I'd prefer the first option as the default, as the bulk of window managers hiding controls don't hide all decorations. Even better, still allow for the gimp-like behaviour, for people that want to fine-tune the window behaviour in their window manager. --HenrikPaulini
- Mmm, we could just do both. Have a very minimal drag bar and close button along the bottom edge of the window. I've prototyped this, and it doesn't look so bad. -- MenTaLguY
- Only if this is an option, off by default. Having both this and the regular decoration is utterly confusing. And if it will only be used without decorations, why not put it at the top, more or less like the regular window bar? --bb
Emulating window decorations
Window decorations serve several functions: moving, resizing, and indicating which window has focus. Let's look at these in turn.
1. For moving, a good workaround that I've just implemented is make an entire dialog draggable, except for controls. That is, you grab the dialog in any point which is not active and drag it wherever you want. It's actually very easy to implement.
However, there is one problem with this: it only works well without window decorations. This is because GTK gets mouse coordinates relative to the window work area (without decorations), and the actual window drag is done by the wm which uses coordinates including the decorations. So if you attempt this on a window with a top bar, it will "jump" when you start dragging it, with the jump distance being equal to the height of the top bar. I haven't found a workaround for this. So, looks like such draggable dialogs are possible only if we go with the second option above (remove all wm decorations and create fakes). Otherwise, it must be provided as an option (off by default) for those whose wms remove decorations for transients, so they can still drag dialogs around. On the other hand, many wms allow alt-dragging windows, so this can be used instead.
- Gtk provides a gtk_window_begin_move_drag() function that passes control to the window manager to handle the move. See experimenta/mental/src/Inkscape/UI/DragBox.* in CVS for an example of its use (via gtkmm). -- MenTaLguY
- Yes, this is what I used, and what gave me the jumps described above if the decorations are on. Is your example any better? --bb
- Mine works fine for me, at least with Metacity. I've not extensively tested with other WMs -- some are certainly going to be less cooperative. What window managers have you tried this with? -- MenTaLguY
- KDE 3.03 - by the way it has some problems with transients too (hides them on the task bar but still shows on the alt-tab panel) --bb
- Sounds like we may be best off always turning off decorations (except borders) on these 'tool' windows. Could you check out experimental/mental from CVS and see how the dragging, alt-tab hiding and other features work for you? I took a sort of belt-and-suspenders approach to setting the window attributes and such. -- MenTaLguY
2. Resizing and even maximizing is actually useful for many dialogs, and it's likely to be difficult to implement via fake controls. It's perhaps easy to enable keyboard resizing of a dialog, though.
- Gtk also provides gtk_window_begin_resize_drag(). -- MenTaLguY
- Did not try this one but I expect similar problems with decorations of unknown width. --bb
3. Indicating if the dialog has focus or not is another useful thing that a fake control may have problems performing (if only because we cannot know e.g. what head bar colors indicate active and inactive windows on user's system). However, if the other ideas on this page are implemented, this will be less of a problem because the annoying situations where you press some key to work on canvas but it gets stealed by a dialog will be less frequent.
Transients and multiple documents
A separate problem is coordinating the transient/parent pairs when there is more than one document window. I propose the following algorithm:
1. When launched, Inkscape at once opens either a document from command line or an empty document. The toolbar then gets attached to that document window as a transient. This means, no more bare toolbar without documents; when you close the last document window, the toolbar and the entire program shut down too.
- Creating new document on startup, and closing the program upon last document window closed, is just checked in. -- bb
2. When you open a dialog, it becomes transient for the currently active document window.
- Done for several dialogs (e.g. ctrl-shift-f). --bb
3. When you switch to a different document window, it steals all transients including the toolbar and makes them its own transients. This is the most tricky part, but it actually should not be too difficult to implement.
- This is what I want. -- MenTaLguY
- I made a prototype, see UnsinkableDialogs for a deskription and issues --bb
II. Dialogs must pass events to the canvas.
The focus problems can be made much less annoying if all dialogs resend all keypresses they cannot handle to the canvas - obviously, to the canvas for which they are currently transient.
I've implemented this in object-properties.c but it does not work completely as I want it to work, and I think I need someone's help. Namely, for some reason the contexts in event-context.c and e.g. select-context.c only get keyboard events when the mouse is over the canvas. So currently, if you have a transient "Object properties" dialog and attempt to move the selection by arrows, this works when the mouse cursor is over the canvas, even if the dialog, not the canvas, has focus. If however the cursor is over the dialog or elsewhere, the events get sent but not received, regardless of focus. On the other hand, global verbs (verbs.c) work everywhere regardless of mouse positions. Why might this be?
Note that this problem is not specific to dialogs. Simple experiment: move a shape by arrows. This works while the mouse cursor is over the document window but stops as soon as you move mouse away from it, even if the document window still has focus. Global verbs like + and - and ctrl-q always work. We cannot however make tool-specific shortcuts global verbs.
Dialogs must also pass focus to the canvas whenever possible. Doing that upon pressing Esc is already implemented. Now we need to force all "one-time" widgets such as buttons to send focus to the canvas as well when activated.
III. Dialogs must remember position and status.
It's another major annoyance. If you kill a dialog (e.g. to make more room for editing), the next time it pops up always in the corner and does not remember which tab was active.
Now done is preserving position and size across sessions. TODO: do we need to also store status (active tab and widget), or on/off status?
This kind of interface is called "SDI", as opposed the current "CSDI" of GIMP and Inkscape. See this page: HIG Compliance for details. Partially it's covered above; in particular, if we make the toolbar transient and make sure it's not left alone, this will be a big step towards SDI.
As for a per-document menu, I don't care much; I prefer to use keyboard anyway. A stationary menu would just add clutter to the window. Also, floating toolbars and dialogs are actually more convenient if they are transient to the document, because they leave more room for the content. However, for newbies this may be a big usability win, compared to the current interface.
- SDI with a shared set of toolboxes/palettes/dialogs is the way we should go, IMO. -- MenTaLguY
Alternatively, see: GlobalMenuBar