vbox: dynamic adaptation to screen-size changes

Fixes #1554
This commit is contained in:
Christian Prochaska 2015-06-04 13:47:42 +02:00 committed by Christian Helmuth
parent b22f3c67f0
commit a801976727
4 changed files with 160 additions and 75 deletions

View File

@ -133,21 +133,21 @@ void GenodeConsole::update_video_mode()
d->SetVideoModeHint(0 /*=display*/,
true /*=enabled*/, false /*=changeOrigin*/,
0 /*=originX*/, 0 /*=originY*/,
fb->w(), fb->h(), fb->depth());
fb->w(), fb->h(),
/* Windows 8 only accepts 32-bpp modes */
32);
}
void GenodeConsole::eventWait(IKeyboard * gKeyboard, IMouse * gMouse)
void GenodeConsole::handle_input(unsigned)
{
static LONG64 mt_events [64];
unsigned mt_number = 0;
_receiver.wait_for_signal();
/* read out input capabilities of guest */
bool guest_abs = false, guest_rel = false, guest_multi = false;
gMouse->COMGETTER(AbsoluteSupported)(&guest_abs);
gMouse->COMGETTER(RelativeSupported)(&guest_rel);
gMouse->COMGETTER(MultiTouchSupported)(&guest_multi);
_vbox_mouse->COMGETTER(AbsoluteSupported)(&guest_abs);
_vbox_mouse->COMGETTER(RelativeSupported)(&guest_rel);
_vbox_mouse->COMGETTER(MultiTouchSupported)(&guest_multi);
for (int i = 0, num_ev = _input.flush(); i < num_ev; ++i) {
Input::Event &ev = _ev_buf[i];
@ -166,11 +166,11 @@ void GenodeConsole::eventWait(IKeyboard * gKeyboard, IMouse * gMouse)
(ev.type() == Input::Event::RELEASE) ? 0x80 : 0;
if (scan_code.is_normal())
gKeyboard->PutScancode(scan_code.code() | release_bit);
_vbox_keyboard->PutScancode(scan_code.code() | release_bit);
if (scan_code.is_ext()) {
gKeyboard->PutScancode(0xe0);
gKeyboard->PutScancode(scan_code.ext() | release_bit);
_vbox_keyboard->PutScancode(0xe0);
_vbox_keyboard->PutScancode(scan_code.ext() | release_bit);
}
}
@ -204,10 +204,10 @@ void GenodeConsole::eventWait(IKeyboard * gKeyboard, IMouse * gMouse)
int ry = ev.ay() - _ay;
rx = Genode::min(boundary, Genode::max(-boundary, rx));
ry = Genode::min(boundary, Genode::max(-boundary, ry));
gMouse->PutMouseEvent(rx, ry, 0, 0, buttons);
_vbox_mouse->PutMouseEvent(rx, ry, 0, 0, buttons);
} else
gMouse->PutMouseEventAbsolute(ev.ax(), ev.ay(), 0,
0, buttons);
_vbox_mouse->PutMouseEventAbsolute(ev.ax(), ev.ay(), 0,
0, buttons);
_ax = ev.ax();
_ay = ev.ay();
@ -218,11 +218,11 @@ void GenodeConsole::eventWait(IKeyboard * gKeyboard, IMouse * gMouse)
/* prefer relative motion event */
if (guest_rel)
gMouse->PutMouseEvent(ev.rx(), ev.ry(), 0, 0, buttons);
_vbox_mouse->PutMouseEvent(ev.rx(), ev.ry(), 0, 0, buttons);
else if (guest_abs) {
_ax += ev.rx();
_ay += ev.ry();
gMouse->PutMouseEventAbsolute(_ax, _ay, 0, 0, buttons);
_vbox_mouse->PutMouseEventAbsolute(_ax, _ay, 0, 0, buttons);
}
}
/* only the buttons changed */
@ -231,28 +231,28 @@ void GenodeConsole::eventWait(IKeyboard * gKeyboard, IMouse * gMouse)
if (_last_received_motion_event_was_absolute) {
/* prefer absolute button event */
if (guest_abs)
gMouse->PutMouseEventAbsolute(_ax, _ay, 0, 0, buttons);
_vbox_mouse->PutMouseEventAbsolute(_ax, _ay, 0, 0, buttons);
else if (guest_rel)
gMouse->PutMouseEvent(0, 0, 0, 0, buttons);
_vbox_mouse->PutMouseEvent(0, 0, 0, 0, buttons);
} else {
/* prefer relative button event */
if (guest_rel)
gMouse->PutMouseEvent(0, 0, 0, 0, buttons);
_vbox_mouse->PutMouseEvent(0, 0, 0, 0, buttons);
else if (guest_abs)
gMouse->PutMouseEventAbsolute(_ax, _ay, 0, 0, buttons);
_vbox_mouse->PutMouseEventAbsolute(_ax, _ay, 0, 0, buttons);
}
}
}
if (is_wheel)
gMouse->PutMouseEvent(0, 0, ev.rx(), ev.ry(), 0);
_vbox_mouse->PutMouseEvent(0, 0, ev.rx(), ev.ry(), 0);
if (is_touch) {
/* if multitouch queue is full - send it */
if (mt_number >= sizeof(mt_events) / sizeof(mt_events[0])) {
gMouse->PutEventMultiTouch(mt_number, mt_number,
mt_events, RTTimeMilliTS());
_vbox_mouse->PutEventMultiTouch(mt_number, mt_number,
mt_events, RTTimeMilliTS());
mt_number = 0;
}
@ -282,8 +282,39 @@ void GenodeConsole::eventWait(IKeyboard * gKeyboard, IMouse * gMouse)
/* if there are elements - send it */
if (mt_number)
gMouse->PutEventMultiTouch(mt_number, mt_number, mt_events,
RTTimeMilliTS());
_vbox_mouse->PutEventMultiTouch(mt_number, mt_number, mt_events,
RTTimeMilliTS());
}
void GenodeConsole::handle_mode_change(unsigned)
{
Display *d = getDisplay();
Genodefb *fb = dynamic_cast<Genodefb *>(d->getFramebuffer());
fb->update_mode();
update_video_mode();
}
void GenodeConsole::event_loop(IKeyboard * gKeyboard, IMouse * gMouse)
{
_vbox_keyboard = gKeyboard;
_vbox_mouse = gMouse;
/* register the mode change signal dispatcher at the framebuffer */
Display *d = getDisplay();
Genodefb *fb = dynamic_cast<Genodefb *>(d->getFramebuffer());
fb->mode_sigh(_mode_change_signal_dispatcher);
for (;;) {
Genode::Signal sig = _receiver.wait_for_signal();
Genode::Signal_dispatcher_base *dispatcher =
dynamic_cast<Genode::Signal_dispatcher_base *>(sig.context());
if (dispatcher)
dispatcher->dispatch(sig.num());
}
}
void GenodeConsole::onMouseCapabilityChange(BOOL supportsAbsolute, BOOL supportsRelative,

View File

@ -107,15 +107,18 @@ class GenodeConsole : public Console {
private:
Input::Connection _input;
Genode::Signal_receiver _receiver;
Genode::Signal_context _context;
Input::Event *_ev_buf;
unsigned _ax, _ay;
bool _last_received_motion_event_was_absolute;
Report::Connection _shape_report_connection;
Genode::Attached_dataspace _shape_report_ds;
Vbox_pointer::Shape_report *_shape_report;
Input::Connection _input;
Genode::Signal_receiver _receiver;
Input::Event *_ev_buf;
unsigned _ax, _ay;
bool _last_received_motion_event_was_absolute;
Report::Connection _shape_report_connection;
Genode::Attached_dataspace _shape_report_ds;
Vbox_pointer::Shape_report *_shape_report;
IKeyboard *_vbox_keyboard;
IMouse *_vbox_mouse;
Genode::Signal_dispatcher<GenodeConsole> _input_signal_dispatcher;
Genode::Signal_dispatcher<GenodeConsole> _mode_change_signal_dispatcher;
bool _key_status[Input::KEY_MAX + 1];
@ -136,15 +139,19 @@ class GenodeConsole : public Console {
_last_received_motion_event_was_absolute(false),
_shape_report_connection("shape", sizeof(Vbox_pointer::Shape_report)),
_shape_report_ds(_shape_report_connection.dataspace()),
_shape_report(_shape_report_ds.local_addr<Vbox_pointer::Shape_report>())
_shape_report(_shape_report_ds.local_addr<Vbox_pointer::Shape_report>()),
_vbox_keyboard(0),
_vbox_mouse(0),
_input_signal_dispatcher(_receiver, *this, &GenodeConsole::handle_input),
_mode_change_signal_dispatcher(_receiver, *this, &GenodeConsole::handle_mode_change)
{
for (unsigned i = 0; i <= Input::KEY_MAX; i++)
_key_status[i] = 0;
_input.sigh(_receiver.manage(&_context));
_input.sigh(_input_signal_dispatcher);
}
void eventWait(IKeyboard * gKeyboard, IMouse * gMouse);
void event_loop(IKeyboard * gKeyboard, IMouse * gMouse);
void onMouseCapabilityChange(BOOL supportsAbsolute, BOOL supportsRelative,
BOOL supportsMT, BOOL needsHostCursor);
@ -209,4 +216,7 @@ class GenodeConsole : public Console {
}
void update_video_mode();
void handle_input(unsigned);
void handle_mode_change(unsigned);
};

View File

@ -26,46 +26,76 @@ class Genodefb :
{
private:
Fb_Genode::Connection _fb;
Fb_Genode::Mode const _fb_mode;
void * _fb_base;
RTCRITSECT _fb_lock;
Fb_Genode::Connection _fb;
unsigned long _width;
unsigned long _height;
/* The mode matching the currently attached dataspace */
Fb_Genode::Mode _fb_mode;
/* The mode at the time when the mode change signal was received */
Fb_Genode::Mode _next_fb_mode;
/*
* The mode currently used by the VM. Can be smaller than the
* framebuffer mode.
*/
Fb_Genode::Mode _virtual_fb_mode;
void *_fb_base;
RTCRITSECT _fb_lock;
void _clear_screen()
{
size_t const num_pixels = _fb_mode.width() * _virtual_fb_mode.height();
memset(_fb_base, 0, num_pixels * _fb_mode.bytes_per_pixel());
_fb.refresh(0, 0, _virtual_fb_mode.width(), _virtual_fb_mode.height());
}
public:
Genodefb ()
:
_fb_mode(_fb.mode()),
_fb_base(Genode::env()->rm_session()->attach(_fb.dataspace())),
_width(_fb_mode.width()),
_height(_fb_mode.height())
_next_fb_mode(_fb_mode),
_virtual_fb_mode(_fb_mode),
_fb_base(Genode::env()->rm_session()->attach(_fb.dataspace()))
{
int rc = RTCritSectInit(&_fb_lock);
Assert(rc == VINF_SUCCESS);
}
int w() const { return _fb_mode.width(); }
int h() const { return _fb_mode.height(); }
int depth() const { return 16; /* XXX */ }
/* Return the next mode of the framebuffer */
int w() const { return _next_fb_mode.width(); }
int h() const { return _next_fb_mode.height(); }
void mode_sigh(Genode::Signal_context_capability sigh)
{
_fb.mode_sigh(sigh);
}
void update_mode()
{
Lock();
_next_fb_mode = _fb.mode();
Unlock();
}
STDMETHODIMP COMGETTER(Width)(ULONG *width)
{
if (!width)
return E_INVALIDARG;
*width = (int)_width > _fb_mode.width() ? _fb_mode.width() : _width;
*width = _virtual_fb_mode.width();
return S_OK;
}
STDMETHODIMP COMGETTER(Height)(ULONG *height)
{
if (!height)
return E_INVALIDARG;
*height = (int)_height > _fb_mode.height() ? _fb_mode.height() : _height;
*height = _virtual_fb_mode.height();
return S_OK;
}
@ -90,7 +120,8 @@ class Genodefb :
if (!bits)
return E_INVALIDARG;
*bits = _fb_mode.bytes_per_pixel() * 8;
*bits = _virtual_fb_mode.bytes_per_pixel() * 8;
return S_OK;
}
@ -111,29 +142,44 @@ class Genodefb :
ULONG bytesPerLine, ULONG w, ULONG h,
BOOL *finished)
{
/* clear screen to avoid artefacts during resize */
size_t const num_pixels = _fb_mode.width() * _fb_mode.height();
memset(_fb_base, 0, num_pixels * _fb_mode.bytes_per_pixel());
HRESULT result = E_FAIL;
_fb.refresh(0, 0, _fb_mode.width(), _fb_mode.height());
Lock();
/* bitsPerPixel == 0 is set by DevVGA when in text mode */
bool ok = ((bitsPerPixel == 16) || (bitsPerPixel == 0)) &&
(w <= (ULONG)_fb_mode.width()) &&
(h <= (ULONG)_fb_mode.height());
if (ok)
PINF("fb resize : %lux%lu@%zu -> %ux%u@%u", _width, _height,
_fb_mode.bytes_per_pixel() * 8, w, h, bitsPerPixel);
else
PWRN("fb resize : %lux%lu@%zu -> %ux%u@%u ignored", _width, _height,
_fb_mode.bytes_per_pixel() * 8, w, h, bitsPerPixel);
bool ok = (w <= (ULONG)_next_fb_mode.width()) &&
(h <= (ULONG)_next_fb_mode.height());
_width = w;
_height = h;
if (ok) {
PINF("fb resize : %dx%d@%zu -> %ux%u@%u",
_virtual_fb_mode.width(), _virtual_fb_mode.height(),
_virtual_fb_mode.bytes_per_pixel() * 8, w, h, bitsPerPixel);
if ((w < (ULONG)_next_fb_mode.width()) ||
(h < (ULONG)_next_fb_mode.height())) {
/* clear the old content around the new, smaller area. */
_clear_screen();
}
_fb_mode = _next_fb_mode;
_virtual_fb_mode = Fb_Genode::Mode(w, h, Fb_Genode::Mode::RGB565);
Genode::env()->rm_session()->detach(_fb_base);
_fb_base = Genode::env()->rm_session()->attach(_fb.dataspace());
result = S_OK;
} else
PWRN("fb resize : %dx%d@%zu -> %ux%u@%u ignored",
_virtual_fb_mode.width(), _virtual_fb_mode.height(),
_virtual_fb_mode.bytes_per_pixel() * 8, w, h, bitsPerPixel);
*finished = true;
return S_OK;
Unlock();
return result;
}
STDMETHODIMP COMGETTER(PixelFormat) (ULONG *format)
@ -177,9 +223,8 @@ class Genodefb :
if (!supported)
return E_POINTER;
*supported = ((width <= (ULONG)_fb_mode.width()) &&
(height <= (ULONG)_fb_mode.height()) &&
(bpp == _fb_mode.bytes_per_pixel() * 8));
*supported = ((width <= (ULONG)_next_fb_mode.width()) &&
(height <= (ULONG)_next_fb_mode.height()));
return S_OK;
}

View File

@ -198,9 +198,8 @@ HRESULT setupmachine()
/* handle input of Genode and forward it to VMM layer */
ComPtr<GenodeConsole> genodeConsole = gConsole;
RTLogPrintf("genodeConsole = %p\n", genodeConsole);
while (true) {
genodeConsole->eventWait(gKeyboard, gMouse);
}
genodeConsole->event_loop(gKeyboard, gMouse);
Assert(!"return not expected");
return E_FAIL;