Skip to content

Add basic gui tray app#22

Open
Agent-Hellboy wants to merge 4 commits intomainfrom
add_gui_app
Open

Add basic gui tray app#22
Agent-Hellboy wants to merge 4 commits intomainfrom
add_gui_app

Conversation

@Agent-Hellboy
Copy link
Copy Markdown
Owner

@Agent-Hellboy Agent-Hellboy commented Jul 8, 2025

Summary by CodeRabbit

  • New Features

    • Added a GUI tray application for clipboard management, included in the Debian package and manageable via systemd service for user sessions.
    • Introduced a manual page for the command-line tool with detailed usage and options.
    • Added functionality to set clipboard content directly from the application.
  • Documentation

    • Updated README with instructions for accessing the manual page and starting the tray app using systemd.
  • Chores

    • Updated package dependencies to support the new GUI tray app.
    • Enhanced installation scripts to guide users on enabling and starting the tray service.
    • Improved CI workflow to include dependencies for building and testing the GUI tray app.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jul 8, 2025

Warning

Rate limit exceeded

@Agent-Hellboy has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 14 minutes and 3 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 1e8fc37 and 05dadc4.

📒 Files selected for processing (1)
  • build_deb.sh (4 hunks)

"""

Walkthrough

The changes introduce a new function for setting clipboard content using X11, expand the Debian packaging script to include a GUI tray app, add a systemd service template for the tray app, and update documentation with instructions for using the man page and starting the tray app. New dependencies and a man page are also included.

Changes

File(s) Change Summary
README.md Added sections on using the man page and starting the GUI tray app via systemd.
build_deb.sh, .../hcp-tray@.service, .../hcp.1 Enhanced packaging to build/install GUI tray app, add systemd service, dependencies, man page, and instructions.
include/clipboard_mgmt.hpp Declared new function: void set_clipboard(Display*, const std::string&).
src/clipboard_mgmt.cpp Implemented set_clipboard to set clipboard content via X11 selection ownership and event handling.
gui/Makefile, gui/trey_app.cpp Added build system and implementation for GUI tray app using GTK and AppIndicator with clipboard history UI.
.github/workflows/test.yml Updated CI workflow to install GUI dependencies and streamline steps.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Systemd
    participant TrayApp
    participant X11Server

    User->>Systemd: Enable/start hcp-tray@user.service
    Systemd->>TrayApp: Launch hcp-tray process
    TrayApp->>X11Server: Connect and listen for clipboard changes
    TrayApp->>X11Server: Set clipboard content (set_clipboard)
    X11Server->>TrayApp: Send SelectionRequest event
    TrayApp->>X11Server: Respond with clipboard data
Loading

Possibly related issues

Possibly related PRs

Poem

In the land of code where clipboards play,
A tray app hops to brighten your day.
With systemd magic and X11 delight,
Now copy and paste feels just right.
Man pages and docs, all clear and new—
Hooray for the clipboard, and rabbits too! 🐇✨
"""

✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (2)
README.md (2)

138-138: Add language specification to code block.

The fenced code block should specify a language for better syntax highlighting.

-```
+```bash
 man hcp

---

`148-151`: **Add language specification to code block.**

The fenced code block should specify a language for better syntax highlighting.


```diff
-```
+```bash
 sudo systemctl enable hcp-tray@$(whoami).service
 sudo systemctl start hcp-tray@$(whoami).service

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**


<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between f4a0c2accd5cbbb5857d92f6aed56fd79a97a4b1 and 8e6cbea1388c65f9f4bd448531ca8c9374b3f00a.

</details>

<details>
<summary>📒 Files selected for processing (4)</summary>

* `README.md` (1 hunks)
* `build_deb.sh` (3 hunks)
* `include/clipboard_mgmt.hpp` (1 hunks)
* `src/clipboard_mgmt.cpp` (1 hunks)

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🪛 LanguageTool</summary>

<details>
<summary>README.md</summary>

[grammar] ~134-~134: Use proper spacing conventions.
Context: ... See [LICENSE](LICENSE).  ## Manual Page  After installing the package, you can vi...

(QB_NEW_EN_OTHER_ERROR_IDS_000007)

---

[grammar] ~136-~136: Use proper spacing conventions.
Context: ...w the manual page for usage and options:  ``` man hcp ```  This provides detailed information about...

(QB_NEW_EN_OTHER_ERROR_IDS_000007)

---

[grammar] ~142-~142: Use proper spacing conventions.
Context: ...t available commands and usage examples.  ## Starting the GUI Tray App  After install...

(QB_NEW_EN_OTHER_ERROR_IDS_000007)

---

[grammar] ~144-~144: Use proper spacing conventions.
Context: ... examples.  ## Starting the GUI Tray App  After installing, you can enable and sta...

(QB_NEW_EN_OTHER_ERROR_IDS_000007)

---

[grammar] ~146-~146: Use proper spacing conventions.
Context: ...em tray and provides clipboard history):  ``` sudo systemctl enable hcp-tray@$(whoami).service sudo systemctl start hcp-tray@$(whoami).service ```  This will launch the tray app in the bac...

(QB_NEW_EN_OTHER_ERROR_IDS_000007)

---

[grammar] ~153-~153: Use proper spacing conventions.
Context: ...in the background for your user session. 

(QB_NEW_EN_OTHER_ERROR_IDS_000007)

</details>

</details>
<details>
<summary>🪛 markdownlint-cli2 (0.17.2)</summary>

<details>
<summary>README.md</summary>

138-138: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

---

148-148: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

</details>

</details>

</details>

<details>
<summary>🔇 Additional comments (4)</summary><blockquote>

<details>
<summary>include/clipboard_mgmt.hpp (1)</summary>

`7-7`: **Function declaration looks good.**

The new `set_clipboard` function declaration is consistent with the existing code style and uses appropriate parameter types for X11 clipboard operations.

</details>
<details>
<summary>README.md (1)</summary>

`134-153`: **Documentation additions look good.**

The new sections provide clear instructions for users to access the man page and start the GUI tray app. The content is well-structured and helpful.

</details>
<details>
<summary>build_deb.sh (2)</summary>

`27-27`: **Dependencies added correctly.**

The new GTK and AppIndicator dependencies are appropriate for the GUI tray app functionality.

---

`63-65`: **Post-install instructions updated appropriately.**

The addition of tray app instructions in the post-install script provides helpful guidance for users.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->

Comment thread src/clipboard_mgmt.cpp
Comment on lines +201 to 239
void set_clipboard(Display *display, const std::string &text) {
Atom clipboard = XInternAtom(display, "CLIPBOARD", False);
Atom utf8 = XInternAtom(display, "UTF8_STRING", False);
Atom targets[] = {utf8, XA_STRING};

Window window = XCreateSimpleWindow(display, DefaultRootWindow(display), 0, 0,
1, 1, 0, 0, 0);
XSetSelectionOwner(display, clipboard, window, CurrentTime);

XEvent event;
bool running = true;
while (running) {
XNextEvent(display, &event);

if (event.type == SelectionRequest) {
XSelectionRequestEvent *req = &event.xselectionrequest;
XEvent respond;
memset(&respond, 0, sizeof(respond));
respond.xselection.type = SelectionNotify;
respond.xselection.display = req->display;
respond.xselection.requestor = req->requestor;
respond.xselection.selection = req->selection;
respond.xselection.target = req->target;
respond.xselection.time = req->time;
respond.xselection.property = None;

if (req->target == utf8 || req->target == XA_STRING) {
XChangeProperty(display, req->requestor, req->property, req->target, 8,
PropModeReplace, (const unsigned char *)text.c_str(),
text.length());
respond.xselection.property = req->property;
}
XSendEvent(display, req->requestor, 0, 0, &respond);
XFlush(display);
running = false; // Only serve one request
}
}
XDestroyWindow(display, window);
} No newline at end of file
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Critical issue: Clipboard ownership model is flawed.

The current implementation has several serious problems:

  1. Single-use limitation: The function exits after serving one SelectionRequest (line 235), meaning clipboard data will only be available for one paste operation. Subsequent paste attempts will fail.

  2. Infinite blocking: The event loop has no timeout mechanism - if no SelectionRequest arrives, the function will block indefinitely.

  3. Missing error handling: No verification that XSetSelectionOwner succeeded or that window creation didn't fail.

For proper clipboard management, consider one of these approaches:

Option 1: Persistent ownership (recommended for GUI tray app)

-void set_clipboard(Display *display, const std::string &text) {
+void set_clipboard(Display *display, const std::string &text, bool persistent = true) {
   // ... existing setup code ...
   
   XEvent event;
-  bool running = true;
+  bool running = persistent;
   while (running) {
     XNextEvent(display, &event);
     
     if (event.type == SelectionRequest) {
       // ... existing handling code ...
-      running = false; // Only serve one request
+      if (!persistent) running = false; // Only serve one request for CLI usage
     }
   }
   XDestroyWindow(display, window);
 }

Option 2: Add timeout for non-persistent usage

+  fd_set readfds;
+  struct timeval timeout;
+  int x11_fd = ConnectionNumber(display);
+  
   while (running) {
+    FD_ZERO(&readfds);
+    FD_SET(x11_fd, &readfds);
+    timeout.tv_sec = 30; // 30 second timeout
+    timeout.tv_usec = 0;
+    
+    if (select(x11_fd + 1, &readfds, NULL, NULL, &timeout) <= 0) {
+      break; // Timeout or error
+    }
+    
+    if (XPending(display)) {
       XNextEvent(display, &event);
       // ... rest of event handling
+    }
   }

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/clipboard_mgmt.cpp around lines 201 to 239, the clipboard ownership is
handled incorrectly by serving only one SelectionRequest and then exiting,
causing clipboard data to be unavailable for subsequent paste operations. To fix
this, modify the event loop to persistently handle multiple SelectionRequest
events instead of stopping after one, ensuring continuous clipboard ownership.
Additionally, add error handling to verify that XCreateSimpleWindow and
XSetSelectionOwner succeed, and implement a timeout mechanism in the event loop
to prevent indefinite blocking if no requests arrive. This will make clipboard
management robust and reliable.

Comment thread build_deb.sh
Comment on lines +78 to +93
cat > $PKGDIR/etc/systemd/system/hcp-tray@.service <<EOF
[Unit]
Description=HCP Clipboard Tray App
After=graphical-session.target

[Service]
Type=simple
User=%i
Environment=DISPLAY=:0
Environment=XAUTHORITY=/home/%i/.Xauthority
ExecStart=/usr/bin/hcp-tray
Restart=on-failure

[Install]
WantedBy=default.target
EOF
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Fix systemd service configuration inconsistency.

The service uses After=graphical-session.target but WantedBy=default.target. For a GUI tray app, consider using graphical-session.target for both or verify the intended behavior.

 [Unit]
 Description=HCP Clipboard Tray App
-After=graphical-session.target
+After=graphical-session.target

 [Service]
 Type=simple
 User=%i
 Environment=DISPLAY=:0
 Environment=XAUTHORITY=/home/%i/.Xauthority
 ExecStart=/usr/bin/hcp-tray
 Restart=on-failure

 [Install]
-WantedBy=default.target
+WantedBy=graphical-session.target
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
cat > $PKGDIR/etc/systemd/system/hcp-tray@.service <<EOF
[Unit]
Description=HCP Clipboard Tray App
After=graphical-session.target
[Service]
Type=simple
User=%i
Environment=DISPLAY=:0
Environment=XAUTHORITY=/home/%i/.Xauthority
ExecStart=/usr/bin/hcp-tray
Restart=on-failure
[Install]
WantedBy=default.target
EOF
cat > $PKGDIR/etc/systemd/system/hcp-tray@.service <<EOF
[Unit]
Description=HCP Clipboard Tray App
After=graphical-session.target
[Service]
Type=simple
User=%i
Environment=DISPLAY=:0
Environment=XAUTHORITY=/home/%i/.Xauthority
ExecStart=/usr/bin/hcp-tray
Restart=on-failure
[Install]
WantedBy=graphical-session.target
EOF
🤖 Prompt for AI Agents
In build_deb.sh around lines 78 to 93, the systemd service file inconsistently
uses After=graphical-session.target but WantedBy=default.target. To fix this,
update the WantedBy directive to graphical-session.target to match the After
directive, ensuring consistent and correct service startup ordering for the GUI
tray app.

Comment thread build_deb.sh
Comment on lines +73 to +75
# Build the GUI tray app
cd gui && make && cd ..
cp gui/hcp-tray $PKGDIR/usr/bin/hcp-tray
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add error handling for GUI build process.

The build process assumes the gui directory exists and has a working Makefile without verification.

-# Build the GUI tray app
-cd gui && make && cd ..
-cp gui/hcp-tray $PKGDIR/usr/bin/hcp-tray
+# Build the GUI tray app
+if [ ! -d "gui" ]; then
+    echo "Error: gui directory not found"
+    exit 1
+fi
+cd gui && make && cd ..
+if [ ! -f "gui/hcp-tray" ]; then
+    echo "Error: hcp-tray binary not built"
+    exit 1
+fi
+cp gui/hcp-tray $PKGDIR/usr/bin/hcp-tray
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# Build the GUI tray app
cd gui && make && cd ..
cp gui/hcp-tray $PKGDIR/usr/bin/hcp-tray
# Build the GUI tray app
if [ ! -d "gui" ]; then
echo "Error: gui directory not found"
exit 1
fi
cd gui && make && cd ..
if [ ! -f "gui/hcp-tray" ]; then
echo "Error: hcp-tray binary not built"
exit 1
fi
cp gui/hcp-tray $PKGDIR/usr/bin/hcp-tray
🤖 Prompt for AI Agents
In build_deb.sh around lines 73 to 75, the script assumes the gui directory
exists and the make command succeeds without checking. Add error handling by
first verifying the gui directory exists before running make, and check the exit
status of the make command. If the directory is missing or make fails, output an
error message and exit the script to prevent further steps from running on a
failed build.

Comment thread build_deb.sh
Comment on lines +97 to +128
cat > $PKGDIR/usr/share/man/man1/hcp.1 <<'EOF'
.TH hcp 1 "$(date +%Y-%m-%d)" "$VERSION" "hcp manual"
.SH NAME
hcp \- Historical Clipboard Manager for X11
.SH SYNOPSIS
.B hcp
[service start | list | <index> | pop | --help | -h]
.SH DESCRIPTION
.B hcp
is a lightweight clipboard manager for X11 systems. It captures clipboard entries, maintains a history, and allows you to list, print, or remove entries. Designed for reliability and minimalism, it works directly with the X11 clipboard and is suitable for use as a background service or on-demand.
.SH COMMANDS
.TP
.B service start
Start clipboard monitoring service in the background.
.TP
.B list
List clipboard history.
.TP
.B <index>
Print clipboard entry at <index>.
.TP
.B pop
Remove most recent clipboard entry.
.TP
.B --help, -h
Show this help message.
.SH AUTHOR
Written by the hcp project contributors.
.SH SEE ALSO
clipboard(1)
EOF
gzip -f $PKGDIR/usr/share/man/man1/hcp.1
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix variable expansion in man page creation.

The man page uses $(date +%Y-%m-%d) and $VERSION in a single-quoted heredoc, which prevents variable expansion.

-cat > $PKGDIR/usr/share/man/man1/hcp.1 <<'EOF'
-.TH hcp 1 "$(date +%Y-%m-%d)" "$VERSION" "hcp manual"
+cat > $PKGDIR/usr/share/man/man1/hcp.1 <<EOF
+.TH hcp 1 "$(date +%Y-%m-%d)" "$VERSION" "hcp manual"

Or use a different approach:

+# Create the man page with proper variable expansion
+MANPAGE_DATE=$(date +%Y-%m-%d)
+cat > $PKGDIR/usr/share/man/man1/hcp.1 <<EOF
+.TH hcp 1 "$MANPAGE_DATE" "$VERSION" "hcp manual"
🤖 Prompt for AI Agents
In build_deb.sh around lines 97 to 128, the man page is created using a
single-quoted heredoc which prevents the variables $(date +%Y-%m-%d) and
$VERSION from expanding. To fix this, change the heredoc delimiter from single
quotes to unquoted or double quotes so that shell variables are expanded
properly during the cat command execution.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
.github/workflows/test.yml (2)

25-28: “List workspace files” step produces noisy logs—consider dropping or gating behind debug flag

ls -lR will dump the whole repository tree into the CI log on every PR.
This is useful once when troubleshooting, but quickly becomes spam and can expose directory layout to forks.

-      - name: List workspace files
-        run: ls -lR
+#      - name: List workspace files  # uncomment for ad-hoc debugging
+#        if: ${{ github.event_name == 'workflow_dispatch' && inputs.debug }}
+#        run: ls -lR

Keeping the command commented or conditioned on an explicit debug flag keeps routine runs lean while preserving the option to inspect files when needed.


30-33: Package list can be trimmed & made non-interactive

  1. libx11-dev already depends on libx11-6; installing both is redundant.
  2. Adding DEBIAN_FRONTEND=noninteractive avoids any edge-case prompts.
  3. --no-install-recommends speeds up CI by skipping extras you don’t ship.
-          sudo apt-get install -y libx11-dev libx11-6 dpkg xvfb xclip libgtk-3-dev libappindicator3-dev
+          sudo DEBIAN_FRONTEND=noninteractive \
+            apt-get install -y --no-install-recommends \
+            dpkg xvfb xclip libx11-dev libgtk-3-dev libappindicator3-dev

This shaves a few seconds off every CI run and reduces network traffic.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8e6cbea and 027a59e.

📒 Files selected for processing (1)
  • .github/workflows/test.yml (1 hunks)
🔇 Additional comments (1)
.github/workflows/test.yml (1)

30-33: Confirm libappindicator3-dev availability on ubuntu-latest

The sandbox environment didn’t include apt-cache, so we couldn’t verify package availability automatically. Please manually confirm that libappindicator3-dev is present in the universe repo on your target runner (e.g. by running apt-cache policy libappindicator3-dev on both ubuntu-22.04 and any future ubuntu-24.04 images). To guard against breakage:

  • Pin the workflow to a known image:
    runs-on: ubuntu-22.04
  • Or add a fail-fast check before installing:
    - run: |
        if ! apt-cache policy libappindicator3-dev | grep -q 'Candidate:'; then
          echo 'libappindicator3-dev not found on runner' >&2
          exit 1
        fi
        sudo apt-get update
        sudo apt-get install -y libx11-dev libx11-6 dpkg xvfb xclip libgtk-3-dev libappindicator3-dev

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🧹 Nitpick comments (3)
gui/trey_app.cpp (2)

32-32: Make text truncation configurable and add ellipsis.

The hardcoded 60-character limit may not be suitable for all use cases and should provide visual indication of truncation.

-    GtkWidget *label = gtk_label_new(entry.substr(0, 60).c_str());
+    constexpr size_t MAX_LABEL_LENGTH = 60;
+    std::string label_text = entry.length() > MAX_LABEL_LENGTH ? 
+        entry.substr(0, MAX_LABEL_LENGTH - 3) + "..." : entry;
+    GtkWidget *label = gtk_label_new(label_text.c_str());

19-21: Add proper window management and user experience improvements.

The window lacks proper parent-child relationship and should be centered on screen.

     GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
     gtk_window_set_title(GTK_WINDOW(window), "Clipboard History");
     gtk_window_set_default_size(GTK_WINDOW(window), 400, 400);
+    gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
+    gtk_window_set_resizable(GTK_WINDOW(window), TRUE);
+    g_signal_connect(window, "destroy", G_CALLBACK(gtk_widget_destroy), NULL);
gui/Makefile (1)

10-11: Add object file tracking and parallel build support.

The current build system recompiles all sources on every change, which is inefficient.

+OBJS = $(SRC:.cpp=.o)
+
-$(TARGET): $(SRC)
-	$(CXX) $(CXXFLAGS) -o $@ $^ $(LDFLAGS)
+$(TARGET): $(OBJS)
+	$(CXX) -o $@ $^ $(LDFLAGS)
+
+%.o: %.cpp
+	$(CXX) $(CXXFLAGS) -c $< -o $@

And update the clean target:

 clean:
-	rm -f $(TARGET)
+	rm -f $(TARGET) $(OBJS)
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 027a59e and 1e8fc37.

📒 Files selected for processing (2)
  • gui/Makefile (1 hunks)
  • gui/trey_app.cpp (1 hunks)
🧰 Additional context used
🪛 checkmake (0.2.2)
gui/Makefile

[warning] 1-1: Missing required phony target "all"

(minphony)


[warning] 1-1: Missing required phony target "clean"

(minphony)


[warning] 1-1: Missing required phony target "test"

(minphony)


[warning] 8-8: Target "all" should be declared PHONY.

(phonydeclared)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: lint
  • GitHub Check: test
🔇 Additional comments (2)
gui/trey_app.cpp (2)

46-50: Verify AppIndicator icon availability and implement a fallback

Hardcoding "system-run-symbolic" risks an invisible tray icon if that name isn’t provided by the user’s icon theme. At runtime, check for the primary icon and fall back to a known default (e.g. "application-default-icon").

• File: gui/trey_app.cpp Lines 46–50
• Use gtk_icon_theme_get_default() + gtk_icon_theme_has_icon() (or equivalent) to detect presence

Suggested diff:

-    const char *icon_name = "system-run-symbolic";
+    const char *icon_name = "system-run-symbolic";
+    GtkIconTheme *theme = gtk_icon_theme_get_default();
+    if (!gtk_icon_theme_has_icon(theme, icon_name)) {
+        icon_name = "application-default-icon";
+    }
     AppIndicator *indicator = app_indicator_new(
         "clipboard-manager",
-        "system-run-symbolic",
+        icon_name,
         APP_INDICATOR_CATEGORY_APPLICATION_STATUS
     );

43-44: Add command-line argument validation.

The GTK initialization should validate command-line arguments properly.

 int main(int argc, char **argv) {
+    if (argc < 1 || argv == nullptr) {
+        g_error("Invalid command line arguments");
+        return 1;
+    }
     gtk_init(&argc, &argv);

Likely an incorrect or invalid review comment.

Comment thread gui/trey_app.cpp
Comment on lines +11 to +15
Display *display = XOpenDisplay(nullptr);
if (display) {
set_clipboard(display, std::string(text));
XCloseDisplay(display);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add error handling for clipboard operations.

The function should handle potential failures in clipboard operations and provide user feedback.

 static void on_copy_clicked(GtkButton *button, gpointer user_data) {
     const char *text = (const char *)user_data;
     Display *display = XOpenDisplay(nullptr);
     if (display) {
-        set_clipboard(display, std::string(text));
+        try {
+            set_clipboard(display, std::string(text));
+        } catch (const std::exception &e) {
+            g_warning("Failed to set clipboard: %s", e.what());
+        }
         XCloseDisplay(display);
+    } else {
+        g_warning("Failed to open X11 display");
     }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Display *display = XOpenDisplay(nullptr);
if (display) {
set_clipboard(display, std::string(text));
XCloseDisplay(display);
}
static void on_copy_clicked(GtkButton *button, gpointer user_data) {
const char *text = (const char *)user_data;
Display *display = XOpenDisplay(nullptr);
if (display) {
try {
set_clipboard(display, std::string(text));
} catch (const std::exception &e) {
g_warning("Failed to set clipboard: %s", e.what());
}
XCloseDisplay(display);
} else {
g_warning("Failed to open X11 display");
}
}
🤖 Prompt for AI Agents
In gui/trey_app.cpp around lines 11 to 15, the clipboard operations lack error
handling. Modify the code to check the success of set_clipboard and handle any
failures by providing appropriate user feedback, such as logging an error
message or notifying the user. Ensure that XOpenDisplay failure is also handled
gracefully by informing the user if the display cannot be opened.

Comment thread gui/trey_app.cpp
GtkWidget *vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5);
gtk_container_add(GTK_CONTAINER(scrolled), vbox);

std::vector<std::string> history = load_clipboard_blocks();
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add error handling for database operations.

The load_clipboard_blocks() function call should handle potential database errors gracefully.

-    std::vector<std::string> history = load_clipboard_blocks();
+    std::vector<std::string> history;
+    try {
+        history = load_clipboard_blocks();
+    } catch (const std::exception &e) {
+        g_warning("Failed to load clipboard history: %s", e.what());
+        // Show error message to user
+        GtkWidget *error_label = gtk_label_new("Error loading clipboard history");
+        gtk_container_add(GTK_CONTAINER(vbox), error_label);
+        gtk_widget_show_all(window);
+        return;
+    }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
std::vector<std::string> history = load_clipboard_blocks();
// Before: std::vector<std::string> history = load_clipboard_blocks();
std::vector<std::string> history;
try {
history = load_clipboard_blocks();
} catch (const std::exception &e) {
g_warning("Failed to load clipboard history: %s", e.what());
// Show error message to user
GtkWidget *error_label = gtk_label_new("Error loading clipboard history");
gtk_container_add(GTK_CONTAINER(vbox), error_label);
gtk_widget_show_all(window);
return;
}
🤖 Prompt for AI Agents
In gui/trey_app.cpp at line 29, the call to load_clipboard_blocks() lacks error
handling for potential database failures. Modify the code to catch exceptions or
check error return values from load_clipboard_blocks(), and handle these errors
gracefully by logging the issue or providing fallback behavior to prevent
crashes or undefined states.

Comment thread gui/trey_app.cpp
Comment on lines +9 to +16
static void on_copy_clicked(GtkButton *button, gpointer user_data) {
const char *text = (const char *)user_data;
Display *display = XOpenDisplay(nullptr);
if (display) {
set_clipboard(display, std::string(text));
XCloseDisplay(display);
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Critical memory safety issue with dangling pointer.

The entry.c_str() pointer passed as user_data will become invalid after the entry object goes out of scope in the show_history_window function. This creates a dangling pointer that can cause crashes or undefined behavior when the copy button is clicked.

Apply this diff to fix the memory safety issue by copying the string data:

-    g_signal_connect(button, "clicked", G_CALLBACK(on_copy_clicked), (gpointer)entry.c_str());
+    char *entry_copy = g_strdup(entry.c_str());
+    g_signal_connect(button, "clicked", G_CALLBACK(on_copy_clicked), entry_copy);
+    g_object_set_data_full(G_OBJECT(button), "entry_data", entry_copy, g_free);

And update the on_copy_clicked function to handle the copied data:

 static void on_copy_clicked(GtkButton *button, gpointer user_data) {
-    const char *text = (const char *)user_data;
+    const char *text = (const char *)g_object_get_data(G_OBJECT(button), "entry_data");
     Display *display = XOpenDisplay(nullptr);
     if (display) {
         set_clipboard(display, std::string(text));
         XCloseDisplay(display);
     }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
static void on_copy_clicked(GtkButton *button, gpointer user_data) {
const char *text = (const char *)user_data;
Display *display = XOpenDisplay(nullptr);
if (display) {
set_clipboard(display, std::string(text));
XCloseDisplay(display);
}
}
static void on_copy_clicked(GtkButton *button, gpointer user_data) {
- const char *text = (const char *)user_data;
+ const char *text = (const char *)g_object_get_data(G_OBJECT(button), "entry_data");
Display *display = XOpenDisplay(nullptr);
if (display) {
set_clipboard(display, std::string(text));
XCloseDisplay(display);
}
}
🤖 Prompt for AI Agents
In gui/trey_app.cpp around lines 9 to 16, the user_data pointer passed to
on_copy_clicked is a dangling pointer from entry.c_str() that becomes invalid
after the entry object is destroyed. To fix this, allocate a copy of the string
data on the heap before passing it as user_data, ensuring it remains valid when
the callback is invoked. Then update on_copy_clicked to properly handle and free
this copied string after use to avoid memory leaks.

Comment thread gui/Makefile
Comment on lines +2 to +3
CXXFLAGS = -std=c++11 `pkg-config --cflags gtk+-3.0 appindicator3-0.1` -I../include
LDFLAGS = `pkg-config --libs gtk+-3.0 appindicator3-0.1` -lX11
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add dependency checking and error handling.

The Makefile should verify that required packages are available before building.

-CXXFLAGS = -std=c++11 `pkg-config --cflags gtk+-3.0 appindicator3-0.1` -I../include
-LDFLAGS = `pkg-config --libs gtk+-3.0 appindicator3-0.1` -lX11
+# Check for required packages
+PKG_CHECK := $(shell pkg-config --exists gtk+-3.0 appindicator3-0.1 && echo "ok")
+ifneq ($(PKG_CHECK),ok)
+$(error Required packages not found. Install libgtk-3-dev and libappindicator3-dev)
+endif
+
+CXXFLAGS = -std=c++11 -Wall -Wextra `pkg-config --cflags gtk+-3.0 appindicator3-0.1` -I../include
+LDFLAGS = `pkg-config --libs gtk+-3.0 appindicator3-0.1` -lX11
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
CXXFLAGS = -std=c++11 `pkg-config --cflags gtk+-3.0 appindicator3-0.1` -I../include
LDFLAGS = `pkg-config --libs gtk+-3.0 appindicator3-0.1` -lX11
# Check for required packages
PKG_CHECK := $(shell pkg-config --exists gtk+-3.0 appindicator3-0.1 && echo "ok")
ifneq ($(PKG_CHECK),ok)
$(error Required packages not found. Install libgtk-3-dev and libappindicator3-dev)
endif
CXXFLAGS = -std=c++11 -Wall -Wextra `pkg-config --cflags gtk+-3.0 appindicator3-0.1` -I../include
LDFLAGS = `pkg-config --libs gtk+-3.0 appindicator3-0.1` -lX11
🤖 Prompt for AI Agents
In gui/Makefile around lines 2 to 3, the Makefile currently sets compiler and
linker flags without checking if the required packages are installed. Add
dependency checking by using pkg-config with the --exists flag for gtk+-3.0 and
appindicator3-0.1 before setting CXXFLAGS and LDFLAGS. If the packages are not
found, print an error message and stop the build process to prevent build
failures later.

Comment thread gui/Makefile
Comment on lines +1 to +14
CXX = g++
CXXFLAGS = -std=c++11 `pkg-config --cflags gtk+-3.0 appindicator3-0.1` -I../include
LDFLAGS = `pkg-config --libs gtk+-3.0 appindicator3-0.1` -lX11

SRC = trey_app.cpp ../src/clipboard_mgmt.cpp ../src/db.cpp ../src/logging.cpp
TARGET = hcp-tray

all: $(TARGET)

$(TARGET): $(SRC)
$(CXX) $(CXXFLAGS) -o $@ $^ $(LDFLAGS)

clean:
rm -f $(TARGET) No newline at end of file
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add missing phony targets and improve Makefile robustness.

The static analysis correctly identifies missing phony targets and other Makefile best practices.

 CXX = g++
 CXXFLAGS = -std=c++11 `pkg-config --cflags gtk+-3.0 appindicator3-0.1` -I../include
 LDFLAGS = `pkg-config --libs gtk+-3.0 appindicator3-0.1` -lX11
 
 SRC = trey_app.cpp ../src/clipboard_mgmt.cpp ../src/db.cpp ../src/logging.cpp 
 TARGET = hcp-tray
 
+.PHONY: all clean test
+
 all: $(TARGET)
 
 $(TARGET): $(SRC)
 	$(CXX) $(CXXFLAGS) -o $@ $^ $(LDFLAGS)
 
+test:
+	@echo "No tests defined for GUI component"
+
 clean:
 	rm -f $(TARGET)
🧰 Tools
🪛 checkmake (0.2.2)

[warning] 1-1: Missing required phony target "all"

(minphony)


[warning] 1-1: Missing required phony target "clean"

(minphony)


[warning] 1-1: Missing required phony target "test"

(minphony)


[warning] 8-8: Target "all" should be declared PHONY.

(phonydeclared)

🤖 Prompt for AI Agents
In gui/Makefile lines 1 to 14, the Makefile lacks .PHONY declarations for
targets like 'all' and 'clean', which can cause issues if files with those names
exist. Add a .PHONY target listing 'all' and 'clean' to ensure these are always
treated as commands, not files. This improves robustness and follows Makefile
best practices.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant