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.
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 (http://www.rydia.net/~mental/mini-titlebar.png). -- MenTaLguY
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
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.
2. When you open a dialog, it becomes transient for the currently active document window.
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
- OK, starting to work on that. That would involve a desktop, when activated, to send an event to all dialogs, so they reattach themselves to the new "king of the hill". Is there anything like "broadcast" events in GTK? --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.
III. Dialogs must remember position and status.
It's another major annoyance. Now object-properties.c is easy to kill by Esc, but the joy is spoiled because the next time, it pops up always in the corner and does not remember which tab was active.
Preserving position and status within one session is easy. Preserving them across sessions is more tricky because this involves storing/retrieving preferences which I could not grok. Again, I would very much appreciate if someone could fill me in on how to do this by completing the HandlingPreferences page. This will be needed more and more in the future as people implement various nifty things and want to store data across sessions. Please provide a howto.
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