Re: [hatari-devel] Hatari UI with Qt?

[ Thread Index | Date Index | More Archives ]


On maanantai 26 marraskuu 2012, Nicolas Pomarède wrote:
> On 25/11/2012 23:03, Eero Tamminen wrote:
>> - Either all code is compiled with:
>>    - C++ compiler and needs to be cleaned of C stuff that's
>>      not valid in C++ (most already done I guess)
>>    - UI part is compiled with C++ compiler and rest is
>>      compiled with C-compiler in which case headers need
>>      to declared that prototypes in them aren't C++ ones
>>      (i.e. those symbols don't have C++ mangling when linked)
>> Which one of the latter options it should be?
> considering that QT UI should remain an option, I think we should keep a
> model where most code is C (as it is now).


> Then adding a generic UI layer between current hatari and SDL UI or QT
> UI. So, QT would only know this layer, and only it should be C++ aware
> (with some slight exceptions in other part maybe).
> Each UI type could be considered as a "control plugin" (to extend it to
> the socket code as well).

Are you proposing that UI plugins would be dynamically loaded instead
of one of them being selected at built time and being statically
compiling into Hatari (like now)?

Unless somebody is volunteering to do the work of implementing that also
for Windows and OSX, that change alone would make Hatari much less

> It would be more work, but I think the best would be to have a structure
> of things to change from the UI for each part (cpu, sound, system, ...)..
> Then SDL or QT UI would manipulate only these structures (either
> directly, or using some set/get functions with some flags to indicate if
> the option was changed in the UI or not).

Hatari already has such structures.  They're accessible through
the ConfigureParams global variable.  See configuration.h.

Currently with SDL GUI, a copy of the settings in ConfiguraParams
is taken before calling the SDL GUI.  After the GUI is done,
the new options are either applied (with required HW re-initializations),
or settings from the copy of the ConfigureParams are restored.

In the Qt UI case, the code doesn't need to use things through
global variable, ConfigureParams (copy) can be passed as an argument.

> And these structure would be passed to the generic UI/control layer
> (that would be independant of the toolkit) and propagated to each "low
> level" part (video.c, mfp.c, sound.c, ...).

Besides ConfigureParams, rest of the Hatari code uses quite a lot
of global variables and it might be a good idea to get rid of
some of them, but that's not a discussion related to the UI.

> The socket layer could also be considered has an "UI plugin", so in the
> end we would have a way to add as many UI/control plugins that we want
> (so, someone could even write a GTK UI or whatever).

How the control socket works interaction-wise is opposite of the UI,
and it offers control to more things than the Hatari options UI.
It cannot work as "UI plugin" interchangable with other UIs
without fairly complete rewrite.

Normal UI interaction is modal, and it's Hatari that invokes the UI.

Emulation is stopped while user changes the options, and all the changes
are applied at the same time before emulation continues.  The UI part will
next time get the changed settings.

Control socket interaction model towards Hatari is non-modal and
asynchronous, and one-directionally from the remote UI to Hatari
(not other way round).

Only thing controller knows about the current Hatari settings is what
it has read from the Hatari config file.  The controller and emulator
run in parallel, nothing is stopped.    The changes coming through
the socket are applied immediately by Hatari on next VBL when it reads
the socket, but controller doesn't wait for any return value.

(more info on what can be done through the control socket is
at the bottom)

To work similarly to other UIs, control socket would need a return
channel for invoking things in the controller and a way to pass
the configuration structures which are tens of OKs in size (each
path string is 4kB in the struct).  On Linux I would use shared
memory for latter and messages would need to be synchronous, i.e.
wait for return value.  Shared memory is also rather unportable.

> For the generic layer, we need to define what generic access method we
> need when Hatari requires some informations from the user :
>   - dialog box with 1..n choices

There are already HookedAlertNotice() and HookedAlertQuery()
APIs, but how they're used is a bit messy, SDL UI calls those
instead if ALERT_HOOKS is defined and rest of code just calls
the SDL GUI functions.

I think code should call the hook functions directly and those
"hook" functions should determine what real function to call.

>   - fileselector

Currently SDLGui_FileSelect() is called only for from "change floppy"
shortcut in shortcuts.c.

If you want to make a generic file selector wrapper, we need to
drop the support for selecting disk images in zip archives, that's
not supported by any GUI toolkit file selector that I know of.

(I would actually be happy about dropping zip support from the SDL
UI too.  Zip archive support just complicates more the already complicated
SDL file selector code while Gzip, which doesn't have this problem,
compresses the disk images better than zip.)

>   - input window with 1..n text/type/value parameters and optional
> layout parameter ?

Currently the API between GUI and rest of Hatari is rather simple:

Hatari API used by GUI:
- ConfigureParams structure
- Configuration_Load/Save()
- MemorySnapShot_Capture/Restore()
- Floppy_SetDiskFileName/None()
- CreateBlankImage_CreateFile()
- Resolution_GetDesktopSize()
- Avi_StartRecording/AreWeRecording(),
- Sound_BeginRecording/AreWeRecording/EndRecording()
- util functions from file.c and str.c

SDL GUI API used by Hatari:
- SDLGui_Init()			// from main.c Main_Init()
- SDLGui_UnInit()		// from main.c Main_UnInit()
- Dialog_MainDlg()		// from dialog.c Dialog_DoProperty()
- DlgAlert_Notice()		// from log.c on alert log levels
- DlgAlert_Query()		// from main.c, dialog.c, change.c, file.c
- SDLGui_FileSelect()	// from shortcut.c to change disk

GUI init and uninit functions are still needed, but could
have a wrapper.

The Alert & File selector functions I already commented.

Dialog_MainDlg() is the SDL GUI option dialog you get with F12,
Dialog_DoProperty() is the wrapper for that entry point.

Replacing Dialog_MainDlg() with large number of extra functions would
just make implementing the GUIs much harder & constraining without any
added benefits I could see.

Btw. SDL GUI directory has also these functions that are called
from elsewhere:
- SDLGui_SetScreen()	// from screen.c, statusbar.c
- SDLGui_GetFontSize()	// from statusbar.c
- SDLGui_Text()			// from statusbar.c

SDLGui_SetScreen() initializes SDL GUI's window size specific
settings, SDLGui_GetFontSize() gives them, they're needed for
SDLGui_Text() usage in statusbar.

Currently you can consider statusbar more of a part of the SDL window
than GUI.  It would be possible to split statusbar.c to SDL specific
part under gui-sdl/ and generic part, but that can wait at least until
there's an actual working Qt UI.

> Regarding QT's future, we can't know how it evolve, but it seems it's
> quite alive, with QT 5 coming soon.

While in Nokia, I was peripherally involved with that (debugged
some stuff using latest Qt versions that weren't yet publicly
available).  Nokia was turning Qt more into something using QML
to do mobile UIs and not so interested about desktop widgets
which were split into separate library not included on N9.

(I'm not planning on doing things with QML as Qt5 isn't yet in
distros.  QML use would again be complete rewrite of the UI.)

Qt5 isn't even source compatible with Qt4 programs:

After Digia purchacing Qt, I hope that there's again some desktop
focus, but there's sure to be some developers lost on both ownership

> And even so it certainly remains the
> most integrated linux/windows/os x and IMO the best choice for a new UI


	- Eero

More info on the control socket:

In the case of emulation options, the user changes them in the remote UI
(while Hatari runs unimpeded) and when user clicks OK, option changes are
passed to the Hatari emulation as command line options which are parsed
immediately.  This works like the the XBios(255) call that emulated programs
can do when --bios-intercept is enabled.

In addition to Hatari command line options, following things can be
done with the control socket:
- call debugger commands (but breakpoints aren't really useful through
  this because they invoke the debugger, not the remote UI)
- inject keyboard and mouse events to emulation, this can be used
  e.g. to copy paste text to Hatari emulation [1]
- invoke Hatari shortcuts so that remote UI can have buttons for
  these keyboard actions. This and above item can also be used to
  automate emulation activity for testing
- stop and continue Hatari emulation [2]
- change Hatari paths, mainly for devices etc
- toggle devices on/off

Last two items are related to Hatari command line options limitations,
one can't separately toggle the device status and change their paths,
therefore separate commands were needed for that.

[1] on mobile devices without keyboard, it's also useful because
    the remote UI can interact with the mobile device on-screen keyboard
    while SDL probably doesn't have such interaction.

[2] this is to workaround SDL bug with joysticks, SDL programs like Hatari
    which enable SDL joystick subsystem will constantly wakeup even when
    program sits in SDL event loop waiting for events.   "stop" remote
    command will instead make Hatari to sit in select() loop waiting for
    remote commands (and X events so that it can redraw Hatari screen).

	With this, Hatari user using Python UI on a mobile device can stop
    Hatari from draining the mobile device battery while user isn't
    interacting with Hatari.

Mail converted by MHonArc 2.6.19+