Repository: pwr-Solaar/Solaar

Issue:
Keyboard name display abnormally on left side
**Information**
<!-- Make sure that your issue is not one of the known issues in the Solaar documentation at https://pwr-solaar.github.io/Solaar/ -->
<!-- Do not bother opening an issue for a version older than 1.1.0.  Upgrade to the latest version and see if your issue persists. -->
<!-- If you not running the current version of Solaar, strongly consider upgrading to the newest version. -->
- Solaar version (`solaar --version` or `git describe --tags` if cloned from this repository): solaar 1.1.9
- Distribution: Arch Linux
- Kernel version (ex. `uname -srmo`): `Linux 6.2.11-zen1-1-zen x86_64 GNU/Linux`
- Output of `solaar show`: 

<details>

```
solaar version 1.1.9

USB and Bluetooth Devices

  1: K780 Multi-Device Wireless Keyboard
     Device path  : /dev/hidraw3
     USB id       : 046d:B33B
     Codename     : Keyboard K780
     Kind         : ?
     Protocol     : HID++ 4.5
     Serial number:
     Model ID:      B33B405B0000
     Unit ID:       BE529ECE
        Bootloader: BOT 25.01.B0006
          Firmware: MPK 01.05.B0029
             Other:
     Supports 18 HID++ 2.0 features:
         0: ROOT                   {0000} V0
         1: FEATURE SET            {0001} V0
         2: DEVICE FW VERSION      {0003} V2
            Firmware: Bootloader BOT 25.01.B0006 00003C32CFDB01
            Firmware: Firmware MPK 01.05.B0029 B33B3C32CFDB01
            Firmware: Other
            Unit ID: BE529ECE  Model ID: B33B405B0000  Transport IDs: {'btleid': 'B33B', 'wpid': '405B'}
         3: DEVICE NAME            {0005} V0
            Name: K780 Multi-Device Wireless Keyboard
            Kind: keyboard
         4: WIRELESS DEVICE STATUS {1D4B} V0
         5: CONFIG CHANGE          {0020} V0
         6: DEVICE FRIENDLY NAME   {0007} V0
            Friendly Name: Keyboard K780
         7: BATTERY STATUS         {1000} V0
            Battery: 90%, discharging, next level 50%.
         8: CHANGE HOST            {1814} V1
            Change Host        : 1:Bryan-YOGA14s
         9: HOSTS INFO             {1815} V1
            Host 0 (paired): Bryan-YOGA14s
            Host 1 (paired): Bryan的Redmi K40 Pro
            Host 2 (paired): ASUS-DESKTOP
        10: REPROG CONTROLS V4     {1B04} V3
            Key/Button Diversion (saved): {Volume Up:Regular, Volume Down:Regular, Mute:Regular, Play/Pause:Regular, Next:Regular, Previous:Regular, Multiplatform Back:Regular, Multiplatform Insert:Regular, Screen Capture/Print Screen:Regular, Fn Down:Regular, Fn Up:Regular, Multiplatform Lock:Regular, Host Switch Channel 1:Regular, Host Switch Channel 2:Regular, Host Switch Channel 3:Regular, MultiPlatform Search:Regular, MultiPlatform Home/Mission Control:Regular, MultiPlatform Menu/Show/Hide Virtual Keyboard/Launchpad:Regular}
            Key/Button Diversion        : {Volume Up:Regular, Volume Down:Regular, Mute:Regular, Play/Pause:Regular, Next:Regular, Previous:Regular, Multiplatform Back:Regular, Multiplatform Insert:Regular, Screen Capture/Print Screen:Regular, Fn Down:Regular, Fn Up:Regular, Multiplatform Lock:Regular, Host Switch Channel 1:Regular, Host Switch Channel 2:Regular, Host Switch Channel 3:Regular, MultiPlatform Search:Regular, MultiPlatform Home/Mission Control:Regular, MultiPlatform Menu/Show/Hide Virtual Keyboard/Launchpad:Regular}
        11: PERSISTENT REMAPPABLE ACTION {1C00} V0
            Persistent Key/Button Mapping        : {Volume Up:Volume Up, Volume Down:Volume Down, Mute:Mute, Play/Pause:Play/Pause, Next:Scan Next Track, Previous:Scan Previous Track, Multiplatform Back:AC Back, MultiPlatform Search:AC Search, MultiPlatform Home/Mission Control:AC Home, MultiPlatform Menu/Show/Hide Virtual Keyboard/Launchpad:COMPOSE}
        12: NEW FN INVERSION       {40A2} V0
            Fn-swap: disabled
            Fn-swap default: enabled
            Swap Fx function (saved): False
            Swap Fx function        : False
        13: ENCRYPTION             {4100} V0
        14: KEYBOARD DISABLE KEYS  {4521} V0
            Disable keys (saved): {Caps Lock:False, Num Lock:False, Scroll Lock:False, Insert:False, Win:False}
            Disable keys        : {Caps Lock:False, Num Lock:False, Scroll Lock:False, Insert:False, Win:False}
        15: MULTIPLATFORM          {4531} V0
            Set OS (saved): Windows
            Set OS        : Windows
        16: LOCK KEY STATE         {4220} V0
        17: DFUCONTROL SIGNED      {00C2} V0
     Has 19 reprogrammable keys:
         0: Host Switch Channel 1     , default: HostSwitch Channel 1        => HostSwitch Channel 1
             is FN, FN sensitive, divertable, persistently divertable, pos:1, group:0, group mask:empty
             reporting: default
         1: Host Switch Channel 2     , default: HostSwitch Channel 2        => HostSwitch Channel 2
             is FN, FN sensitive, divertable, persistently divertable, pos:2, group:0, group mask:empty
             reporting: default
         2: Host Switch Channel 3     , default: HostSwitch Channel 3        => HostSwitch Channel 3
             is FN, FN sensitive, divertable, persistently divertable, pos:3, group:0, group mask:empty
             reporting: default
         3: MultiPlatform Home/Mission Control, default: Multiplatform Home/Mission Control => Multiplatform Home/Mission Control
             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:4, group:0, group mask:empty
             reporting: default
         4: MultiPlatform Menu/Show/Hide Virtual Keyboard/Launchpad, default: Multiplatform Menu/Launchpad => Multiplatform Menu/Launchpad
             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:5, group:0, group mask:empty
             reporting: default
         5: Multiplatform Back        , default: MultiPlatform Back          => MultiPlatform Back
             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:6, group:0, group mask:empty
             reporting: default
         6: Previous                  , default: Previous                    => Previous
             is FN, FN sensitive, divertable, persistently divertable, pos:7, group:0, group mask:empty
             reporting: default
         7: Play/Pause                , default: Play/Pause                  => Play/Pause
             is FN, FN sensitive, divertable, persistently divertable, pos:8, group:0, group mask:empty
             reporting: default
         8: Next                      , default: Next                        => Next
             is FN, FN sensitive, divertable, persistently divertable, pos:9, group:0, group mask:empty
             reporting: default
         9: Mute                      , default: Mute                        => Mute
             is FN, FN sensitive, divertable, persistently divertable, pos:10, group:0, group mask:empty
             reporting: default
        10: Volume Down               , default: Volume Down                 => Volume Down
             is FN, FN sensitive, divertable, persistently divertable, pos:11, group:0, group mask:empty
             reporting: default
        11: Volume Up                 , default: Volume Up                   => Volume Up
             is FN, FN sensitive, divertable, persistently divertable, pos:12, group:0, group mask:empty
             reporting: default
        12: MultiPlatform Search      , default: Multiplatform Search        => Multiplatform Search
             nonstandard, reprogrammable, divertable, persistently divertable, pos:0, group:0, group mask:empty
             reporting: default
        13: Multiplatform Insert      , default: Switch Language             => Switch Language
             is FN, reprogrammable, divertable, persistently divertable, pos:0, group:0, group mask:empty
             reporting: default
        14: Screen Capture/Print Screen, default: Screen Capture              => Screen Capture
             is FN, reprogrammable, divertable, persistently divertable, pos:0, group:0, group mask:empty
             reporting: default
        15: Multiplatform Lock        , default: WindowsLock                 => WindowsLock
             is FN, reprogrammable, divertable, persistently divertable, pos:0, group:0, group mask:empty
             reporting: default
        16: Fn Up                     , default: unknown:0070                => unknown:0070
             is FN, divertable, persistently divertable, pos:0, group:0, group mask:empty
             reporting: default
        17: Fn Down                   , default: unknown:006F                => unknown:006F
             is FN, divertable, persistently divertable, pos:0, group:0, group mask:empty
             reporting: default
        18: FN Key                    , default: Do Nothing One              => Do Nothing One
             nonstandard, pos:0, group:0, group mask:empty
             reporting: default
     Has 10 persistent remappable keys:
         0: MultiPlatform Home/Mission Control => Consumer: AC Home
         1: MultiPlatform Menu/Show/Hide Virtual Keyboard/Launchpad => Key: COMPOSE
         2: Multiplatform Back         => Consumer: AC Back
         3: Previous                   => Consumer: Scan Previous Track
         4: Play/Pause                 => Consumer: Play/Pause
         5: Next                       => Consumer: Scan Next Track
         6: Mute                       => Consumer: Mute
         7: Volume Down                => Consumer: Volume Down
         8: Volume Up                  => Consumer: Volume Up
         9: MultiPlatform Search       => Consumer: AC Search
     Battery: 90%, discharging, next level 50%.
```
</details>

- Contents of `~/.config/solaar/config.yaml` (or `~/.config/solaar/config.json` if `~/.config/solaar/config.yaml` not present):

<details>

```
- 1.1.9
- _NAME: K780 Multi-Device Wireless Keyboard
  _absent: [hi-res-scroll, lowres-scroll-mode, hires-smooth-invert, hires-smooth-resolution, hires-scroll-mode, scroll-ratchet, smart-shift, thumb-scroll-invert,
    thumb-scroll-mode, onboard_profiles, report_rate, pointer_speed, dpi, speed-change, backlight, backlight-timed, reprogrammable-keys, crown-smooth, divert-crown,
    divert-gkeys, m-key-leds, mr-key-led, gesture2-gestures, gesture2-divert, gesture2-params, sidetone, equalizer, adc_power_management]
  _battery: 4096
  _modelId: B33B405B0000
  _sensitive: {fn-swap: false}
  _unitId: BE529ECE
  change-host: null
  disable-keyboard-keys: {1: false, 2: false, 4: false, 8: false, 16: false}
  divert-keys: {1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, 189: 0, 190: 0, 191: 0, 192: 0, 193: 0, 194: 0, 209: 0, 210: 0, 211: 0, 212: 0, 213: 0, 214: 0}
  fn-swap: false
  multiplatform: 0
  persistent-remappable-keys: null
```
</details>


- Errors or warrnings from Solaar:
<!-- Under normal operation Solaar keeps a log of warning and error messages in ~/.tmp
while it is running as a file starting with 'Solaar'.
If this file is not available or does not have useful information you can
run Solaar as `solaar -dd`, after killing any running Solaar processes to
have Solaar log informational, warning, and error messages to stdout. -->


**Describe the bug**
The device name cannot be displayed normally on the left side device list in current version. But in the previous version, there is no such problem. And the keyboard is connected to my laptop via Bluetooth.

**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error

**Screenshots**
If applicable, add screenshots to help explain your problem.
![solaar](https://user-images.githubusercontent.com/31512600/232228758-46987cf0-b85c-45bc-a291-7278e6a5eb21.png)

**Additional context**
Add any other context about the problem here.



Discussion:
There is a race condition in Solaar between setting up device information and setting up the window.   If the window is set up before the device information then Solaar does not correctly show the short name for the device (but only if Solaar has to query the device to get the short name).
I have a fix that I will be testing out locally for a little while.

Resolving patch:
diff --git a/lib/logitech_receiver/device.py b/lib/logitech_receiver/device.py
--- a/lib/logitech_receiver/device.py
+++ b/lib/logitech_receiver/device.py
@@ -170,35 +170,32 @@ def find(self, serial):
 
     @property
     def protocol(self):
-        if not self._protocol and self.online:
-            self._protocol = _base.ping(
-                self.handle or self.receiver.handle, self.number, long_message=self.bluetooth or self.hidpp_short is False
-            )
-            # if the ping failed, the peripheral is (almost) certainly offline
-            self.online = self._protocol is not None
-
-            # if _log.isEnabledFor(_DEBUG):
-            #     _log.debug("device %d protocol %s", self.number, self._protocol)
+        if not self._protocol:
+            self.ping()
         return self._protocol or 0
 
     @property
     def codename(self):
         if not self._codename:
+            if not self.online:  # be very defensive
+                self.ping()
             if self.online and self.protocol >= 2.0:
                 self._codename = _hidpp20.get_friendly_name(self)
                 if not self._codename:
                     self._codename = self.name.split(' ', 1)[0] if self.name else None
-            elif self.receiver:
+            if not self._codename and self.receiver:
                 codename = self.receiver.device_codename(self.number)
                 if codename:
                     self._codename = codename
                 elif self.protocol < 2.0:
                     self._codename = '? (%s)' % (self.wpid or self.product_id)
-        return self._codename if self._codename else '?? (%s)' % (self.wpid or self.product_id)
+        return self._codename or '?? (%s)' % (self.wpid or self.product_id)
 
     @property
     def name(self):
         if not self._name:
+            if not self.online:  # be very defensive
+                self.ping()
             if self.online and self.protocol >= 2.0:
                 self._name = _hidpp20.get_name(self)
         return self._name or self._codename or ('Unknown device %s' % (self.wpid or self.product_id))


Test patch: