Summary
do_touchpad_action() in plugins/media-keys/csd-media-keys-manager.c computes an incorrect state when no external mouse is connected, causing every press of the touchpad-toggle key to write SEND_EVENTS_DISABLED rather than toggling. With an external mouse connected, the same code path works correctly.
Environment
- Linux Mint 22.3 "Zena" (Cinnamon 6.6.7, on Ubuntu 24.04 noble)
- Kernel 6.17.0-113020-tuxedo
- X11 session
- Laptop with touchpad + separate XF86-ish function key (Fn+F11 emitting
KEY_F21) that triggers csd-media-keys' touchpad-toggle action
Reproduction
- Ensure no external USB/Bluetooth mouse is connected.
gsettings get org.cinnamon.desktop.peripherals.touchpad send-events → 'enabled'
- Press the touchpad-toggle hotkey (or
dbus-send the media-key action).
gsettings get ... → 'disabled' ✅ (toggle worked)
- Press the hotkey again.
gsettings get ... → 'disabled' ❌ (should be 'enabled')
- Press again. Still
'disabled'. Indefinitely.
With an external mouse connected during the same sequence, the toggle alternates correctly.
Manually setting send-events back to 'enabled' via the Mouse and Touchpad UI works once, but the next hotkey press immediately flips it back to 'disabled', so the toggle never actually toggles without a mouse present.
Root cause
In do_touchpad_action() (plugins/media-keys/csd-media-keys-manager.c):
state = g_settings_get_enum (settings, TOUCHPAD_SEND_EVENTS_KEY) ==
C_DESKTOP_DEVICE_SEND_EVENTS_ENABLED ||
(C_DESKTOP_DEVICE_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE && !mouse_is_present ());
The second operand of the || is (C_DESKTOP_DEVICE_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE && !mouse_is_present()). C_DESKTOP_DEVICE_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE is an enum constant (non-zero), so that sub-expression reduces to simply !mouse_is_present().
So the line effectively evaluates to:
state = (send_events == ENABLED) || !mouse_is_present();
When no mouse is present, state is always true, so the subsequent g_settings_set_enum(..., state ? DISABLED : ENABLED) always writes DISABLED. Every press.
This was almost certainly intended to be a comparison, mirroring the "is the touchpad effectively on right now?" check. Probably something like:
CsdDeviceSendEvents current = g_settings_get_enum (settings, TOUCHPAD_SEND_EVENTS_KEY);
state = (current == C_DESKTOP_DEVICE_SEND_EVENTS_ENABLED) ||
(current == C_DESKTOP_DEVICE_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE && !mouse_is_present ());
i.e. the touchpad is considered effectively enabled if send-events is either enabled, or disabled-on-external-mouse while no external mouse is present. As written, the comparison was lost and the bare enum constant was left as a boolean operand.
For reference, the GNOME upstream equivalent (gnome-settings-daemon) does it correctly:
state = (g_settings_get_enum (settings, TOUCHPAD_ENABLED_KEY) ==
G_DESKTOP_DEVICE_SEND_EVENTS_ENABLED);
Suggested fix
Replace the broken line with an explicit comparison as shown above. Happy to submit a PR if useful.
Related
Issue #256 ("disable touchpad resets itself") may be a different manifestation of similar state-tracking issues in this handler, though the symptom there was the opposite (auto re-enable after time rather than stuck disabled).
Summary
do_touchpad_action()inplugins/media-keys/csd-media-keys-manager.ccomputes an incorrectstatewhen no external mouse is connected, causing every press of the touchpad-toggle key to writeSEND_EVENTS_DISABLEDrather than toggling. With an external mouse connected, the same code path works correctly.Environment
KEY_F21) that triggers csd-media-keys' touchpad-toggle actionReproduction
gsettings get org.cinnamon.desktop.peripherals.touchpad send-events→'enabled'dbus-sendthe media-key action).gsettings get ...→'disabled'✅ (toggle worked)gsettings get ...→'disabled'❌ (should be'enabled')'disabled'. Indefinitely.With an external mouse connected during the same sequence, the toggle alternates correctly.
Manually setting
send-eventsback to'enabled'via the Mouse and Touchpad UI works once, but the next hotkey press immediately flips it back to'disabled', so the toggle never actually toggles without a mouse present.Root cause
In
do_touchpad_action()(plugins/media-keys/csd-media-keys-manager.c):The second operand of the
||is(C_DESKTOP_DEVICE_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE && !mouse_is_present()).C_DESKTOP_DEVICE_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSEis an enum constant (non-zero), so that sub-expression reduces to simply!mouse_is_present().So the line effectively evaluates to:
When no mouse is present,
stateis alwaystrue, so the subsequentg_settings_set_enum(..., state ? DISABLED : ENABLED)always writesDISABLED. Every press.This was almost certainly intended to be a comparison, mirroring the "is the touchpad effectively on right now?" check. Probably something like:
i.e. the touchpad is considered effectively enabled if
send-eventsis eitherenabled, ordisabled-on-external-mousewhile no external mouse is present. As written, the comparison was lost and the bare enum constant was left as a boolean operand.For reference, the GNOME upstream equivalent (
gnome-settings-daemon) does it correctly:Suggested fix
Replace the broken line with an explicit comparison as shown above. Happy to submit a PR if useful.
Related
Issue #256 ("disable touchpad resets itself") may be a different manifestation of similar state-tracking issues in this handler, though the symptom there was the opposite (auto re-enable after time rather than stuck disabled).