Skip to content

feat(linux): Add dbus system service#8509

Merged
ermshiperete merged 8 commits into
masterfrom
feat/linux/4273-wayland-systemd
May 23, 2023
Merged

feat(linux): Add dbus system service#8509
ermshiperete merged 8 commits into
masterfrom
feat/linux/4273-wayland-systemd

Conversation

@ermshiperete

@ermshiperete ermshiperete commented Mar 24, 2023

Copy link
Copy Markdown
Contributor

This implements a dbus system service that allows to provide the missing functionality when running under Wayland.

Fixes #4273.

User Testing

Preparations

  • The tests should be run on these Linux platforms:

    • GROUP_JAMMY_X11: Ubuntu 22.04 Jammy with Gnome Shell and X11
    • GROUP_JAMMY_WAYLAND: Ubuntu 22.04 Jammy with Gnome Shell and Wayland
    • GROUP_LUNAR_WAYLAND: Ubuntu 23.04 Lunar with Gnome Shell and Wayland
  • Install build artifacts of this PR

  • Reboot

  • Install Nanum fonts for typing Korean:

    sudo apt install fonts-nanum
  • Change "Complex text layout" setting in LibreOffice Writer:

    Expand to see the steps
    • In LO Tools/Options, go to the Language Settings/Languages tab. Under "Default Languages for Documents" check the box for "Asian" and select "Korean (RoK)" as language, and check "Complex text layout" and select "Khmer" as language.

      Screenshot from 2022-06-23 12-13-56

    • You'll also have to change the default style: go to Styles/Manage Styles, right-click on "Default Paragraph Style" and select Modify. Go to the Font tab. For Asian Text Font, select Family "NanumMyeongjo" and Language "Korean (RoK)". For CTL Font, select Family "Khmer Mondulkiri" (or another "Khmer" font) and Language "Khmer".

      Screenshot from 2022-06-23 12-11-35

  • Install "IPA (SIL)", "Korean KORDA Jamo (SIL)" , and "Khmer Angkor" keyman keyboards

Tests

  • TEST_IPA_WRITER: Open LibreOffice Writer. Switch to "IPA (SIL)" keyboard. Type n>. Verify that the result is "ŋ".
  • TEST_IPA_GEDIT: Open gedit. Switch to "IPA (SIL)" keyboard. Type n>. Verify that the result is "ŋ".
  • TEST_KO_WRITER: Open LibreOffice Writer. Switch to "Korean KORDA Jamo (SIL)" keyboard. Type han<space>geul<space>. Verify that the result is "한글".
  • TEST_KO_GEDIT: Open gedit. Switch to "Korean KORDA Jamo (SIL)" keyboard. Type han<space>geul<space>. Verify that the result is "한글".
  • TEST_KM_WRITER: Open LibreOffice Writer. Switch to "Khmer Angkor" keyboard. Type xEjmr. Verify that the output is "ខ្មែរ".
  • TEST_KM_GEDIT: Open gedit. Switch to "Khmer Angkor" keyboard. Type xEjmr. Verify that the output is "ខ្មែរ".
  • TEST_CONTEXT:
    • Open gedit
    • Switch to "IPA (SIL)" keyboard.
    • Type
      an
      m
      
    • click after n
    • type >
    • verify that the output is
      aŋ
      m
      

@ermshiperete ermshiperete added this to the A17S9 milestone Mar 24, 2023
@keymanapp-test-bot keymanapp-test-bot Bot added the user-test-missing User tests have not yet been defined for the PR label Mar 24, 2023
@keymanapp-test-bot

keymanapp-test-bot Bot commented Mar 24, 2023

Copy link
Copy Markdown

User Test Results

Test specification and instructions

  • ✅ GROUP_JAMMY_X11: Ubuntu 22.04 Jammy with Gnome Shell and X11

    7 tests PASSED
    • TEST_IPA_WRITER (PASSED): Tested with the attached PR build (17.0.107-1~PR-8509+jammy44) in Ubuntu 22.04 Jammy with Gnome Shell and X11 OS and here is my observation: 1. Verified that the typing n> produces the output ŋ in LibreOffice Writer Document.
    • TEST_IPA_GEDIT (PASSED): Verified that the typing n> produces the output ŋ in Text Editor.
    • TEST_KO_WRITER (PASSED): Verified that typing han,space>geul produces the output 한글 in LibreOffice Writer Document.
    • TEST_KO_GEDIT (PASSED): Verified that typing han,space>geul produces the output 한글 in Text Editor.
    • TEST_KM_WRITER (PASSED): Verified that typing xEjmr produces the ouput ខ្មែរ in LibreOffice Writer Document.
    • TEST_KM_GEDIT (PASSED): Verified that typing xEjmr produces the ouput ខ្មែរ in Text Editor.
    • TEST_CONTEXT (PASSED): Verified that after typing > after the letter n, it changed to ŋ. Seems to be working as expected. (notes)
  • ✅ GROUP_JAMMY_WAYLAND: Ubuntu 22.04 Jammy with Gnome Shell and Wayland

    7 tests PASSED
    • TEST_IPA_WRITER (PASSED): Tested with the attached PR build (17.0.107-1~PR-8509+jammy44) in Ubuntu 22.04 Jammy with Gnome Shell and Wayland OS and here is my observation: 1. Verified that the typing n> produces the output ŋ in LibreOffice Writer Document.
    • TEST_IPA_GEDIT (PASSED): Verified that the typing n> produces the output ŋ in Text Editor.
    • TEST_KO_WRITER (PASSED): Verified that typing han,space>geul produces the output 한글 in LibreOffice Writer Document.
    • TEST_KO_GEDIT (PASSED): Verified that typing han,space>geul produces the output 한글 in Text Editor.
    • TEST_KM_WRITER (PASSED): Verified that typing xEjmr produces the ouput ខ្មែរ in LibreOffice Writer Document.
    • TEST_KM_GEDIT (PASSED): Verified that typing xEjmr produces the ouput ខ្មែរ in Text Editor.
    • TEST_CONTEXT (PASSED): Verified that after typing > after the letter n, it changed to ŋ. Seems to be working as expected. (notes)
  • 🟩 GROUP_LUNAR_WAYLAND: Ubuntu 23.04 Lunar with Gnome Shell and Wayland

    • TEST_IPA_WRITER (PASSED): Tested with the attached PR build (17.0.108-1~PR-8509+lunar48) in Ubuntu 23.04 Lunar with Gnome Shell and Wayland OS and here is my observation: 1. Verified that the typing n> produces the output ŋ in LibreOffice Writer Document.
    • TEST_IPA_GEDIT (PASSED): Verified that the typing n> produces the output ŋ in Text Editor.
    • TEST_KO_WRITER (PASSED): Verified that typing han,space>geul produces the output 한글 in LibreOffice Writer Document.
    • TEST_KO_GEDIT (PASSED): Verified that typing han,space>geul produces the output 한글 in Text Editor.
    • TEST_KM_WRITER (PASSED): Verified that typing xEjmr produces the ouput ខ្មែរ in LibreOffice Writer Document.
    • TEST_KM_GEDIT (PASSED): Verified that typing xEjmr produces the ouput ខ្មែរ in Text Editor.
    • 🟩 TEST_CONTEXT (SKIPPED): ): I created bug(linux): context not picked up in Gnome Text Editor #8828 for the failing test.

Test Artifacts

@mcdurdin mcdurdin modified the milestones: A17S9, A17S10 Apr 4, 2023
@mcdurdin mcdurdin modified the milestones: A17S10, A17S11 Apr 15, 2023
@mcdurdin mcdurdin modified the milestones: A17S11, A17S12 Apr 29, 2023
@ermshiperete ermshiperete force-pushed the feat/linux/4273-wayland-systemd branch 8 times, most recently from 5f8baaf to 9f3db08 Compare May 12, 2023 16:00
@ermshiperete ermshiperete changed the base branch from master to chore/linux/install-tc May 12, 2023 16:00
@ermshiperete ermshiperete force-pushed the feat/linux/4273-wayland-systemd branch from 9f3db08 to 166dc83 Compare May 12, 2023 16:04
@ermshiperete ermshiperete force-pushed the feat/linux/4273-wayland-systemd branch from 166dc83 to f27038b Compare May 12, 2023 16:07
@ermshiperete ermshiperete force-pushed the feat/linux/4273-wayland-systemd branch from f27038b to cf96012 Compare May 12, 2023 16:18
@mcdurdin

Copy link
Copy Markdown
Member

I hope to review this in next few days

@bharanidharanj

Copy link
Copy Markdown

Test Results

GROUP_LUNAR_WAYLAND: Ubuntu 23.04 Lunar with Gnome Shell and Wayland

  • TEST_IPA_WRITER (PASSED): Tested with the attached PR build (17.0.108-1~PR-8509+lunar48) in Ubuntu 23.04 Lunar with Gnome Shell and Wayland OS and here is my observation: 1. Verified that the typing n> produces the output ŋ in LibreOffice Writer Document.
  • TEST_IPA_GEDIT (PASSED): Verified that the typing n> produces the output ŋ in Text Editor.
  • TEST_KO_WRITER (PASSED): Verified that typing han,space>geul produces the output 한글 in LibreOffice Writer Document.
  • TEST_KO_GEDIT (PASSED): Verified that typing han,space>geul produces the output 한글 in Text Editor.
  • TEST_KM_WRITER (PASSED): Verified that typing xEjmr produces the ouput ខ្មែរ in LibreOffice Writer Document.
  • TEST_KM_GEDIT (PASSED): Verified that typing xEjmr produces the ouput ខ្មែរ in Text Editor.
  • TEST_CONTEXT (FAILED): Noticed that after typing > after the letter n, it is showing wrong output. Seems to be an issue.

..in LibreOffice Writer

..in Text Editor

@keymanapp-test-bot keymanapp-test-bot Bot added user-test-failed and removed user-test-required User tests have not been completed labels May 16, 2023
sd_bus* bus = NULL;
int result;

if (capsLock > 1) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since capsLock is guint32, does that mean any non-zero value is invalid?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any value besides 0 and 1 is invalid.


if (ret < 0) {
g_error("Failed to connect to system bus: %s", strerror(-ret));
return;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this need exit_loop(slot, bus);?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really, since opening the user bus failed bus is not set, nor slot, but for consistency it would be better to add it.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is because C++ RAII means we don't get nice things (try/finally) -- otherwise we need to wrap these variables in a class for automatic destruction, which is tedious boilerplate. Another pattern I see used is goto loop_cleanup, which at least can keep the cleanup inside the same function, and is thus a little clearer, a little shorter, and avoids accidentally missing the return statement, or calling the cleanup twice (which in the current model would be bad because it would result in double-frees):

  if (ret < 0) {
    g_error("Failed to connect to system bus: %s", strerror(-ret));
    goto cleanup;
  }

  // ... function continues ...

cleanup:
  if (bus)  sd_bus_release_name(bus, KEYMAN_TESTSVC_BUS_NAME);
  if (slot) sd_bus_slot_unref(slot);
  if (bus)  sd_bus_close_unref(bus);
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like gotos, so I put the whole thing in a class to benefit from C++ RAII 😄

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like gotos, so I put the whole thing in a class to benefit from C++ RAII 😄

I thought there was a good chance that you would say that! 🤣

Comment on lines +155 to +156
export WAYLAND_DISPLAY
WAYLAND_DISPLAY=$(grep "Using Wayland display" "$TMPFILE" | cut -d"'" -f2)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I notice this is how the previous code was. But why wouldn't the two lines be combined?

Suggested change
export WAYLAND_DISPLAY
WAYLAND_DISPLAY=$(grep "Using Wayland display" "$TMPFILE" | cut -d"'" -f2)
export WAYLAND_DISPLAY=$(grep "Using Wayland display" "$TMPFILE" | cut -d"'" -f2)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Combining it masks failures. See https://www.shellcheck.net/wiki/SC2155.

Follow-up of code review comments.

# Keyman Conventional Commit suggestions:
# - Consider appending the text ". Fixes #4273" to your commit message.

@darcywong00 darcywong00 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm - I think @mcdurdin wants to get to this too.

@ermshiperete

ermshiperete commented May 17, 2023

Copy link
Copy Markdown
Contributor Author

GROUP_LUNAR_WAYLAND
TEST_CONTEXT (SKIPPED): I created #8828 for the failing test.

@mcdurdin

Copy link
Copy Markdown
Member

@ermshiperete note the format change for your test skip (the format you used skipped all tests)

@mcdurdin mcdurdin left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks really solid. I have one request around resource cleanup patterns, because I think the separate-function pattern is a bit fragile. But I didn't really see any other significant issues. Good job!


if (ret < 0) {
g_error("Failed to connect to system bus: %s", strerror(-ret));
return;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is because C++ RAII means we don't get nice things (try/finally) -- otherwise we need to wrap these variables in a class for automatic destruction, which is tedious boilerplate. Another pattern I see used is goto loop_cleanup, which at least can keep the cleanup inside the same function, and is thus a little clearer, a little shorter, and avoids accidentally missing the return statement, or calling the cleanup twice (which in the current model would be bad because it would result in double-frees):

  if (ret < 0) {
    g_error("Failed to connect to system bus: %s", strerror(-ret));
    goto cleanup;
  }

  // ... function continues ...

cleanup:
  if (bus)  sd_bus_release_name(bus, KEYMAN_TESTSVC_BUS_NAME);
  if (slot) sd_bus_slot_unref(slot);
  if (bus)  sd_bus_close_unref(bus);
}

Comment on lines +115 to +116
if (ret > 0) // we processed a request, try to process another one, right-away
continue;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (ret > 0) // we processed a request, try to process another one, right-away
continue;
if (ret > 0) {
// we processed a request, try to process another one, right-away
continue;
}

Comment on lines +109 to +113
if (exitFlag) {
g_debug("Exiting loop");
exit_loop(slot, bus);
return;
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (exitFlag) {
g_debug("Exiting loop");
exit_loop(slot, bus);
return;
}
if (exitFlag) {
// `exitFlag` can be modified by the callback function
// `on_exit_method` which can be called by `sd_bus_process`
g_debug("Exiting loop");
exit_loop(slot, bus);
return;
}

Comment on lines +10 to +15
static void
finish(sd_bus_error* error, sd_bus_message* msg, sd_bus * bus) {
if (error) { sd_bus_error_free(error); }
if (msg) { sd_bus_message_unref(msg); }
if (bus) { sd_bus_unref(bus); }
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I'd prefer to see the goto cleanup pattern which I've noted in another comment -- it's less vulnerable to copypasta errors.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

else
echo "Can't find neither ${COMMON_ARCH_DIR}/release nor ${COMMON_ARCH_DIR}/debug"
exit 2
echo "Can't find neither ../../../build/$(arch)/debug nor ../../../build/$(arch)/release"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
echo "Can't find neither ../../../build/$(arch)/debug nor ../../../build/$(arch)/release"
echo "Cannot find ../../../build/$(arch)/debug or ../../../build/$(arch)/release"

Yay English grammar (or ... "Can find neither a nor b" is technically okay but weird)

int32_t ret;
uint32_t state;

ret_error = NULL;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a no-op. Did you mean to set the value rather than the pointer?

Suggested change
ret_error = NULL;
*ret_error = NULL;

) {
uint32_t state;

ret_error = NULL;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you mean to do this?

Suggested change
ret_error = NULL;
*ret_error = NULL;

Comment on lines +56 to +62
static int finish(int ret, void *kbd_devices, sd_bus_slot *slot, sd_bus *bus) {
close_kbd_devices(kbd_devices);
sd_bus_slot_unref(slot);
sd_bus_unref(bus);

return ret < 0 ? 1 : 0;
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, would prefer a goto cleanup pattern

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactored to make use of C++ RAII.

Comment on lines +109 to +110
if (ret > 0) // we processed a request, try to process another one, right-away
continue;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (ret > 0) // we processed a request, try to process another one, right-away
continue;
if (ret > 0) {
// we processed a request, try to process another one, right-away
continue;
}

Comment thread linux/scripts/dist.sh

@mcdurdin mcdurdin left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

Comment on lines +36 to +40
KeymanSystemServiceClient::~KeymanSystemServiceClient() {
if (error) { sd_bus_error_free(error); }
if (msg) { sd_bus_message_unref(msg); }
if (bus) { sd_bus_unref(bus); }
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the pattern you have now, if you call SetCapsLockIndicator twice and both times an error is returned, you'll leak error. It would be good to make note of this -- that the class functions are intended to be called just once in the class lifecycle, for future maintainers.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Comment on lines +50 to +58
dbus = g_test_dbus_new(G_TEST_DBUS_NONE);

// Add the private directory with our in-tree service files.
g_test_dbus_add_service_dir(dbus, KEYMAN_TEST_SERVICE_PATH);

std::cout << "Add service dir to " << KEYMAN_TEST_SERVICE_PATH << std::endl;

// Start the private D-Bus daemon
g_test_dbus_up(dbus);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if any of these functions fail?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dunno. Most of these functions are void. g_test_dbus_get_bus_address will return NULL only if g_test_dbus_up hasn't been called. Other than that there are no other possible failures listed in the documentation for these methods.

Comment thread linux/keyman-system-service/build.sh
@ermshiperete ermshiperete merged commit a7c3c54 into master May 23, 2023
@ermshiperete ermshiperete deleted the feat/linux/4273-wayland-systemd branch May 23, 2023 14:26
@keyman-server

Copy link
Copy Markdown
Collaborator

Changes in this pull request will be available for download in Keyman version 17.0.111-alpha

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(linux): Add support for Wayland

5 participants