Git Product home page Git Product logo

xqemu-manager's Introduction

XQEMU

XQEMU is an open-source emulator to play original Xbox games on Windows, macOS, and Linux. Please visit xqemu.com to learn more.

Build Status

Platform Build Status
Windows Build status
macOS Build status
Ubuntu Build status

xqemu-manager's People

Contributors

bigbrainafk avatar cakelancelot avatar discostarslayer avatar dracc avatar gxtx avatar jayfoxrox avatar libbers avatar mborgerson avatar thrimbor avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

xqemu-manager's Issues

AV Cable configuration

xqemu/xqemu#253 added the option to configure the reported video cable type. XQEMU-Manager should support this in the GUI.

I'd personally suggest using a naming like this for the GUI:

  • None
  • Standard AV Cable (Composite)
  • Advanced AV Pack (S-Video)
  • RF Adapter (RFU)
  • High Definition AV Pack (Component)
  • Advanced SCART Cable (SCART)

(So basically list the official MS adapter name, and then add some information about the video-standard / cable)

Settings can be changed while XQEMU is running, but aren't effective until next start of XQEMU

The settings dialog can be opened while XQEMU is running.
However, many of its options configure the hardware state and should not be modifiable while the Xbox is already running (Flash / EEPROM / HDD image / LPC / SMC flags / ..).

We should disable most of the settings dialog while XQEMU is running.

Settings which should still be configurable at runtime:

  • Input
  • DVD Image (needs to properly eject the tray via SMC first)
  • Network (at least connecting / disconnecting cable)
  • AV cable (warning should be displayed so user is aware that Xbox might reboot)

Ideally, all of these would have a separate UI in the main-window, as these are features that a physical Xbox exposes to a user.

Other options could be runtime configurable if supported by QEMU (can it switch to hw-virt at runtime?), however, those should probably remain in the settings window.

Retrieve state of virtual Xbox via memory inspection

Keep in mind that XQEMU is LLE and we can't always assume that it's running the official MS bios / kernel / licensed games. Anything which makes such assumptions is part of HLE.
HLE in XQEMU and its UI should always be entirely optional and it must be possible to disable such features (or they must handle non-MS code gracefully).


Following is some code which could be used to get information about the running XBE.
For more information, check http://xboxdevwiki.net/Xbe which also has a link to the file format at the bottom.

  • Doesn't handle bad XBEs gracefully and does no bounds checking.
  • Retrieves the information in multiple steps which might be problematic if the XBE is changed during readback.
  • Timestamp conversion could be broken.
  • Unicode conversion could be broken.
  • Not known wether it runs synchronously or asynchronously.
  • Written for Python 3, whereas XQEMU-Manager also supports Python 2.

Function to do HMP commands via QMP:

def read(self, addr, size):
  cmd = {
      "execute": "human-monitor-command", 
      "arguments": { "command-line": "x /%dxb %d" % (size,addr) }
  }
  response = self.run_cmd(cmd)
  lines = response['return'].replace('\r', '').split('\n')
  data_string = ' '.join(l.partition(': ')[2] for l in lines).strip()
  data = bytes(int(b, 16) for b in data_string.split(' '))
  return data

Code to read, parse and print XBE fields:

base = 0x00010000
if t.read(base, 4) == b'XBEH':
  xbe_timestamp = int.from_bytes(t.read(base + 0x114, 4), 'little')
  ts = datetime.datetime.utcfromtimestamp(xbe_timestamp)
  print("XBE Timestamp: %s (0x%08X)" % (str(ts), xbe_timestamp))

  cert_address = int.from_bytes(t.read(base + 0x118, 4), 'little')

  cert_timestamp = int.from_bytes(t.read(cert_address + 0x4, 4), 'little')
  ts = datetime.datetime.utcfromtimestamp(cert_timestamp)
  print("XBE Certificate Timestamp: %s (0x%08X)" % (str(ts), cert_timestamp))

  title_id = int.from_bytes(t.read(cert_address + 0x8, 4), 'little')
  a = title_id >> 24
  b = (title_id >> 16) & 0xFF
  i = title_id & 0xFFFF
  print('XBE Title-ID: 0x%X (%c%c-%03d)' % (title_id, a, b, i))

  title_name = t.read(cert_address + 0xC, 40 * 2).decode('utf-8')
  print("XBE Title-Name: '%s'" % title_name)
else:
  print("No XBE found")

Output:

XBE Timestamp: 2001-12-12 19:15:05 (0x3C17ACB9)
XBE Certificate Timestamp: 2002-03-04 15:58:09 (0x3C839991)
XBE Title-ID: 0x4D530007 (MS-007)
XBE Title-Name: 'Azurik - Rise of Perathia'

The primary use of this information would probably be that it could be displayed as part of the UI (possibly move it into the QEMU window title). This would be immediately visible for use in bug reports.

If we allow some kind of telemetry or motivate users to report often, we can also use this information to create a complete set of XBE header dumps / complete gameset, possibly discovering undumped DVDs.
A sneaky way to get telemetry could be rich presence (which I don't want for XQEMU) or pairing players for network games in the future (which I want, regardless of telemetry).


The memory-read gadget can also retrieve kernel information for bug reports.
Otherwise, it's quite limited in use, because the UI can get information directly through our hardware-emulation.

Reminder: Xbox RAM contains copyrighted or otherwise protected material during runtime. So I'd advise against doing full crashdumps.
We should selectively dump the metadata we need, much like the code above does.

xqemu-manager should download xqemu for ease of use

As discussed on IM, this would greatly improve usability for first-time users, especially windows users, that are used to easy first-time setups.

That's why I would like to make it a wizard for the first xqemu run:

  1. Warn the user that their MCPX and Kernel are needed for now, with two browsing fields just under it
  2. Offer to download the HDD image (a browse button, with a download button next to it)
  3. Offer to download xqemu. I can see a dropdown with the 10 latest artifacts or so, and a download button next to it, plus a browse button.

The wizard could accommodate other settings in the future, such as input, and console configuration (region, etc). But those three steps are the most important for first time users. Of course, the wizard would be cancellable, launchable again, pages could be skipped, and the downloaders could be called again directly from the settings.

An update check could also be performed on launch, and offer the user to upgrade if a new one is available.


As a reference, these were my alternative proposals to make the setup easier:

  • creating a repo with xqemu-manager and xqemu as submodules, that would compile both
  • changing the xqemu appveyor script to include xqemu-manager
  • xqemu manager could be a frontend that lists and downloads (or compiles!) specific revisions. That might be a better solution for the user.

Hook up HDD lock checkbox

The UI checkbox is there but it doesn't do anything. It just needs to add the ,locked flag to the HDD -drive param.

"Restart" button crashes XQEMU

When hitting the "Restart" button (which sends QMP system_reset), I always seem to get:

hw/xbox/nv2a/nv2a_pfifo.c:278: pfifo_run_pusher: Assertion `false' failed.

I think we should remove the button for now, or hide/disable it (until XQEMU doesn't crash anymore).
@mborgerson has mentioned on IRC that he already fixed XQEMU system resets while working on snapshots. So if he fixes the issue in XQEMU soon, hiding the button might not be necessary.


Additionally, the "Restart" button is always enabled, even if XQEMU is not running. It just does nothing. So if we don't remove it, we'll need a new issue about this.

UI hangs while establishing QMP monitor connection

The UI hangs after hitting the start button, until QMP is connected.

This means that UI elements like the log that is being added in #48 are not refereshed, which means a large number of log messages are suddenly shown, once the connection is established.
The "Start" button won't change into "Stop" for about a second on my machine - this makes the UI feel unresponsive.

To avoid this, the connection loop should be improved / replaced:

xqemu-manager/main.py

Lines 288 to 302 in 00f3bf0

self._p = subprocess.Popen(cmd)
i = 0
while True:
print('Trying to connect %d' % i)
if i > 0: time.sleep(1)
try:
self._qmp = QEMUMonitorProtocol(('localhost', 4444))
self._qmp.connect()
except Exception as e:
if i > 4:
raise
else:
i += 1
continue
break

PyQt5 can not be installed through MSYS2 pip

I don't have the exact error message available, but I have a workaround:

  • pacman -S mingw-w64-x86_64-python2-pyqt5
  • pacman -S mingw-w64-x86_64-python3-pyqt5

One of those, depending on wether we want to promote python 2 or 3 (both for 64 bit only).
MSYS2 python seems to pick the highest available version as default.

So please decide a good default version for the shebang in main.py (Probably python 2 so we can use the same Python that's necessary for QEMU install)

Issue instead of PR as I don't have time to integrate this into README right now

Add networking configuration

The UI tab/components are there but nothing is hooked up. This needs to add the proper net flags to xqemu. Should support port forwarding. Here's a sample partial command line to get started:

-net nic,model=nvnet -net user,hostfwd=tcp:127.0.0.1:8081-:21,hostfwd=tcp:127.0.0.1:731-:731 \

Settings dialog can be opened multiple times

The settings dialog can be opened multiple times.
That is confusing. Especially because the dialogs aren't synchronized and because of #15 (so the user doesn't know which settings are actually used).

We should only allow to open one settings-dialog.

Settings dialog does not have a "Save changes" button

In my opinion the current settings dialog is unintuitive design.
I always have the instinct to go back to confirm that my settings have been changed, because just closing a dialog doesn't confirm to me that anything has been saved.

It's also odd that you have to press the โŒ at the top of the window after working yourself from top-to-bottom for configuring each setting in the window.

The solution to this does not necessarily have to be a button labeled "Save changes" - other solutions are also possible, as long as it's intuitive.

Black screen and freezes at some titles

Tested and confirmed in Grand Theft Auto San Andreas - with xqemu-manager it stucks (black screen - BS) after copyright screen just before Press Start. With bat-file it boots and after pressing Start button assertion error (its not xqemu-manager bug, already reported to xqemu's issue-tracker).
Tested on 5d4058d6.
Bat-file:
xqemu.exe -cpu pentium3 -machine xbox,short_animation,bootrom=mcpx.bin -bios bios.bin -m 64 -drive index=0,media=disk,file=hdd.qcow2,locked -drive index=1,media=cdrom,file=gtasa.iso -usb -device usb-xbox-gamepad

Titles (tested on xqemu-manager):
Grand Theft Auto San Andreas - BS after "Press Start" screen
Lord of the Rings: Third age - freezes (maybe its working, but I am not sure) at main menu, input is not response. Also it has some graphic glitches - yellow garbage.
Mortal Kombat Deception - BS after credits screen, just before FMVs.

Add XQEMU startup/runtime error handling

If XQEMU fails to start, which might be caused by an invalid command line being passed to it (e.g. use controllers which are not connected), XQEMU-Manager will fail to connect to XQEMU over QMP. A cryptic "WinError 10061" error message will be displayed to users. In this case, we should be able to determine why XQEMU failed to start and report this to the user.

Additionally, XQEMU-Manager isn't aware of when the XQEMU subprocess crashes (e.g. hitting an assert), but it should be. We should be able to collect error messages and display them to the users. In the future, automated error reporting would be nice too but that's a separate issue.

dsound issue

not sure whats going on, I can start xqemu via a bat file and it works fine, but if I start it via the manager i get
QEMU 4.2.0 monitor - type 'help' for more information
(qemu) dsp_init
dsp_init
Found game controller 0 (XInput Controller)
ac97: invalid bm_index(3) in voice_set_active
ac97: invalid bm_index(3) in voice_set_active
ac97: invalid bm_index(3) in voice_set_active
ac97: invalid bm_index(3) in voice_set_active
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer
ac97: invalid bm_index(3) in voice_set_active
ac97: invalid bm_index(3) in voice_set_active
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer

the command lines are virtually Identical (only small difference in structure, no additions and using same iso, mcpx and bios)
Via bat game runs, via manager it goes to xbox needs servicing

Add option to set EEPROM path

XQEMU had supported an EEPROM file for some time (xqemu/xqemu#107).

XQEMU-Manager doesn't support this yet.

It should be implemented.


Additionally, a warning should be added which tells users that writeback isn't supported (as we rejected xqemu/xqemu#122 ; new attempts at fixing it properly will be welcome!)

Reported command line and what is ran could diverge

There is a discrepancy of what xqemu-manager claims to run (launchCmdToString(cmd)), and what is actually being ran (cmd).

There could be cases where launchCmdToString and the expansion in subprocess.Popen diverge. So copy pasting the "Running: ..." line from stdout might not produce the same result as running it through xqemu-manager.

Different names for log area

Our UI labels the log as "XQEMU Messages", but the "XQEMU quit prematurely" message will refer to it as "log area".

We should make this more consistent.

"Latest build" broken link

Hello ๐Ÿ‘‹

Due to appveyor keeping artifacts only for 1 month, the link to download the latest build is broken.

Could you please trigger a fresh build and make some GitHub release with a build copy as a release asset so it wouldn't be cleaned up after 1 month.

Thank you ๐Ÿ™

Loss of QMP connection results in abort / crash of XQEMU-Manager

When pressing "Restart" it will crash XQEMU (See #50). When pressing the button again, XQEMU-Manager will try to send another QMP command before realizing that XQEMU crashed.

This leads to XQEMU-Manager aborting (closing):

Traceback (most recent call last):
  File "./main.py", line 426, in onRestartButtonClicked
    self.inst.restart()
  File "./main.py", line 330, in restart
    return self.run_cmd('system_reset')
  File "./main.py", line 318, in run_cmd
    resp = self._qmp.cmd_obj(cmd)
  File "xqemu-manager/qmp.py", line 174, in cmd_obj
    resp = self.__json_read()
  File "xqemu-manager/qmp.py", line 82, in __json_read
    data = self.__sockfile.readline()
  File "/usr/lib/python3.7/socket.py", line 589, in readinto
    return self._sock.recv_into(b)
ConnectionResetError: [Errno 104] Connection reset by peer
Aborted (core dumped)

or

Traceback (most recent call last):
  File "./main.py", line 426, in onRestartButtonClicked
    self.inst.restart()
  File "./main.py", line 330, in restart
    return self.run_cmd('system_reset')
  File "./main.py", line 320, in run_cmd
    raise Exception('Disconnected!')
Exception: Disconnected!
Aborted (core dumped)

We should handle the disconnection / loss of connection more gracefully.

This might also affect other QMP commands.

Special characters not supported in pathname

While #12 was a hacky way to support spaces, we still don't support other symbols in paths (MCPX, Flash, HDD, DVD path).
This probably includes backslash (\), comma (,) and possibly more.

We should properly use a double quoted string in the command lines whenever necessary.
Also see previously mentioned #12 where to implement this.

Cannot open the application

Hi, I am on Win 10 device and unable to run your application, as it exits with "Failed to execute script main". I am using your latest AppVayor pre-build. What I got on the command line is:

ModuleNotFoundError: No module named 'PyQt5.sip'

I have PyQt5 and sip installed and latest. I didn't look at your code or recompiled but for the time being it doesn't work.

No specific GUI / `-display` forced

As XQEMU Manager does not force a specific GUI / -display, a default one is picked, which is typically Gtk on platforms which support it.

To avoid such variety, we should add ['-display', 'sdl'] into the cmd array which forces the simple SDL UI.

Issue instead of PR due to lack of time - this is also a beginner task

Log doesn't auto-scroll to the bottom / blank lines at end of log

There's 2 related bugs that we noticed during review of the original log PR #48 (comment):

  1. The log doesn't auto-scroll all the way to the bottom by default (when new messages are added). It always seems to scroll 1 line short (which is a blank line, due to the second bug).
    Scroll bug
  2. There are 2 blank lines at the bottom of the log when fully scrolled down.
    Blank line bug

Hook up debug options

The UI is there but nothing is hooked up yet. Should support enabling SuperIO, GDB (and port), and whether it should halt on startup to wait for connection.

Add input device configuration

Eventually XQEMU will support emulating Xbox controllers using SDL2 input devices (which might actually be Xbox controllers...). Once available, Update: XQEMU now supports SDL2 input devices! This should be configurable through this page. That is:

  • Which SDL controllers were detected
  • Which controllers should map to which port
  • How the axis/buttons should map to an Xbox controller

"Screenshot" button is poorly integrated

I think we should remove the "Screenshot" button - most operating systems have a feature for this built-in anyway (example: Alt+PrtSc on Windows puts screenshot of active Window in clipboard).

Having support for taking screenshots can potentially be useful for telemetry or bug reports, but this would need better integration.

Issues with the current implementation:

  • A standalone screenshot feature feels unnecessary to me.
  • Button is always shown, even when XQEMU is not even running.
  • There's no confirmation that a screenshot was taken.
  • The user does not know where the file is saved.
  • Only a single screenshot file (screenshot.ppm) is allowed.
  • PPM is not widely supported, especially in browsers, so screenshots can not be shared too easily.

I think we should remove the button for now to avoid all of these issues.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.