Index: sys/dev/vt/vt.h =================================================================== --- sys/dev/vt/vt.h +++ sys/dev/vt/vt.h @@ -124,6 +124,7 @@ struct vt_window *vd_windows[VT_MAXWINDOWS]; /* (c) Windows. */ struct vt_window *vd_curwindow; /* (d) Current window. */ struct vt_window *vd_savedwindow;/* (?) Saved for suspend. */ + struct vt_window *vd_grabwindow; /* (?) Saved before cngrab. */ struct vt_pastebuf vd_pastebuf; /* (?) Copy/paste buf. */ const struct vt_driver *vd_driver; /* (c) Graphics driver. */ void *vd_softc; /* (u) Driver data. */ Index: sys/dev/vt/vt_core.c =================================================================== --- sys/dev/vt/vt_core.c +++ sys/dev/vt/vt_core.c @@ -61,6 +61,9 @@ #include #endif +static int vtterm_cngrab_noswitch(struct vt_device *, struct vt_window *); +static int vtterm_cnungrab_noswitch(struct vt_device *, struct vt_window *); + static tc_bell_t vtterm_bell; static tc_cursor_t vtterm_cursor; static tc_putchar_t vtterm_putchar; @@ -1021,7 +1024,7 @@ if (vd->vd_curwindow == &vt_conswindow) { grabbed = vd->vd_curwindow->vw_grabbed; for (i = 0; i < grabbed; ++i) - vtterm_cnungrab(vd->vd_curwindow->vw_terminal); + vtterm_cnungrab_noswitch(vd, vd->vd_curwindow); } idx0 = kbd_allocate("kbdmux", -1, vd, vt_kbdevent, vd); @@ -1059,7 +1062,7 @@ if (vd->vd_curwindow == &vt_conswindow) { for (i = 0; i < grabbed; ++i) - vtterm_cngrab(vd->vd_curwindow->vw_terminal); + vtterm_cngrab_noswitch(vd, vd->vd_curwindow); } return (idx0); @@ -1605,24 +1608,24 @@ return (-1); } -static void -vtterm_cngrab(struct terminal *tm) +/* + * These two do most of what we want to do in vtterm_cnungrab, but without + * actually switching windows. This is necessary for, e.g., + * vt_allocate_keyboard() to get the current keyboard into the state it needs to + * be in without damaging the device's window state. + * + * Both return the current grab count, though it's only used in vtterm_cnungrab. + */ +static int +vtterm_cngrab_noswitch(struct vt_device *vd, struct vt_window *vw) { - struct vt_device *vd; - struct vt_window *vw; keyboard_t *kbd; - vw = tm->tm_softc; - vd = vw->vw_device; - - if (!cold) - vt_window_switch(vw); + if (vw->vw_grabbed++ > 0) + return (vw->vw_grabbed); if ((kbd = vd->vd_keyboard) == NULL) - return; - - if (vw->vw_grabbed++ > 0) - return; + return (1); /* * Make sure the keyboard is accessible even when the kbd device @@ -1636,29 +1639,64 @@ vt_update_kbd_mode(vw, kbd); kbdd_poll(kbd, TRUE); + return (1); +} + +static int +vtterm_cnungrab_noswitch(struct vt_device *vd, struct vt_window *vw) +{ + keyboard_t *kbd; + + if (--vw->vw_grabbed > 0) + return (vw->vw_grabbed); + + if ((kbd = vd->vd_keyboard) == NULL) + return (0); + + kbdd_poll(kbd, FALSE); + + vw->vw_kbdmode = vw->vw_prev_kbdmode; + vt_update_kbd_mode(vw, kbd); + kbdd_disable(kbd); + return (0); } static void -vtterm_cnungrab(struct terminal *tm) +vtterm_cngrab(struct terminal *tm) { struct vt_device *vd; struct vt_window *vw; - keyboard_t *kbd; vw = tm->tm_softc; vd = vw->vw_device; - if ((kbd = vd->vd_keyboard) == NULL) - return; + /* To be restored after we ungrab. */ + if (vd->vd_grabwindow == NULL) + vd->vd_grabwindow = vd->vd_curwindow; - if (--vw->vw_grabbed > 0) + if (!cold) + vt_window_switch(vw); + + vtterm_cngrab_noswitch(vd, vw); +} + +static void +vtterm_cnungrab(struct terminal *tm) +{ + struct vt_device *vd; + struct vt_window *vw; + + vw = tm->tm_softc; + vd = vw->vw_device; + + MPASS(vd->vd_grabwindow != NULL); + if (vtterm_cnungrab_noswitch(vd, vw) != 0) return; - kbdd_poll(kbd, FALSE); + if (!cold && vd->vd_grabwindow != vw) + vt_window_switch(vd->vd_grabwindow); - vw->vw_kbdmode = vw->vw_prev_kbdmode; - vt_update_kbd_mode(vw, kbd); - kbdd_disable(kbd); + vd->vd_grabwindow = NULL; } static void