Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions extensions/color-picker/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules
vicinae-env.d.ts
57 changes: 57 additions & 0 deletions extensions/color-picker/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Color Picker for Vicinae

A powerful color picker, manager, and converter extension for **Vicinae** on **Linux**, ported and adapted from Raycast's Color Picker.

Supported on **Linux** (GNOME, KDE, Hyprland, Sway, Wayland, and X11).

---

## Commands

### `pick-color` - Pick Color
Activates a screen loupe/eyedropper across your monitors, allowing you to sample any pixel.
- Copies the sampled color directly to the clipboard in your preferred format.
- Adds the color to your persistent color history.
- Shows a HUD confirmation with the copied color.

### `organize-colors` - Organize Colors
Manage, search, and export your picked color history.
- View in grid mode (with live SVG color swatches) or list mode.
- Pin your favorite colors to the top.
- Rename colors with custom titles.
- Copy colors in 12 different formats (HEX, RGB, RGBA, HSL, HSV, OKLCH, LCH, Display P3, etc.).
- Export colors as CSS variables, CSS classes, or JSON.
- Trigger color sampling directly with a single click.

### `favorite-colors` - Favorite Colors
Quick access to all colors pinned as favorites in Organize Colors.

### `convert-color` - Convert Color
Universal color conversion tool. Pass any color format (or enter one in the search bar) to immediately get conversions in all major formats with one-click copy.

### `color-names` - Color Names
Search and identify colors by their descriptive names using the `color-namer` palette.

### `color-wheel` - Color Wheel Reference
Displays an RGB spectrum color wheel reference with quick access to the desktop screen picker.

---

## Screen Picker Architecture

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🟠 Warning — Documented native picker fallbacks are not implemented

Rule: MANIFEST-001

The README claims fallbacks through hyprpicker, grim/slurp, xcolor, gpick, and import, but the supplied picker only attempts GNOME Shell and XDG Desktop Portal D-Bus APIs and never invokes those tools.

Suggested resolution: Remove the fallback-tool claim or implement the documented fallback paths.

Suggested change
- **Linux**: Uses D-Bus color picking through `org.freedesktop.portal.Screenshot.PickColor` and `org.gnome.Shell.Screenshot.PickColor`.

- **Linux**: Uses D-Bus color picking through `org.freedesktop.portal.Screenshot.PickColor` and `org.gnome.Shell.Screenshot.PickColor`.

---

## Preferences

- **Color Format**: Default format when copying picked colors (`HEX`, `HEX Lower Case`, `HEX No Prefix`, `RGB`, `RGB %`, `RGBA`, `RGBA %`, `HSLA`, `HSVA`, `OKLCH`, `LCH`, `P3`).
- **Show color name after picking**: Optionally show the matched color name in the notification after sampling.
- **Primary Action**: Configure whether selecting a color copies it to the clipboard or pastes it directly to the frontmost application.

---

## Credits

- Ported and maintained for Vicinae by [manuelcontrera](https://github.com/manuelcontrera).
- Original Raycast extension created by [thomas](https://github.com/thomas).
119 changes: 119 additions & 0 deletions extensions/color-picker/assets/bin/picker-linux.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
#!/usr/bin/env python3
import sys
import json
import uuid

def try_gnome(bus):
try:
from gi.repository import Gio
proxy = Gio.DBusProxy.new_sync(
bus,
Gio.DBusProxyFlags.NONE,
None,
'org.gnome.Shell.Screenshot',
'/org/gnome/Shell/Screenshot',
'org.gnome.Shell.Screenshot',
None
)
res = proxy.call_sync('PickColor', None, Gio.DBusCallFlags.NONE, 60000, None)
val = res.unpack()[0]
if 'color' in val:
r, g, b = val['color']
return {
"red": float(r),
"green": float(g),
"blue": float(b),
"alpha": 1.0,
"colorSpace": "sRGB"
}
return None
except Exception as e:
err_msg = str(e).lower()
if "cancel" in err_msg or "abort" in err_msg or "dismiss" in err_msg:
return "CANCELLED"
return None

def try_portal(bus):
try:
from gi.repository import Gio, GLib
loop = GLib.MainLoop()
token = "picker_" + uuid.uuid4().hex[:8]
sender = bus.get_unique_name()[1:].replace('.', '_')
handle_path = f"/org/freedesktop/portal/desktop/request/{sender}/{token}"

result_color = None

def on_signal(connection, sender_name, object_path, interface_name, signal_name, parameters, user_data):
nonlocal result_color
try:
response_code, results = parameters.unpack()
if response_code == 0 and 'color' in results:
r, g, b = results['color']
result_color = {
"red": float(r),
"green": float(g),
"blue": float(b),
"alpha": 1.0,
"colorSpace": "sRGB"
}
finally:
loop.quit()

bus.signal_subscribe(
None,
"org.freedesktop.portal.Request",
"Response",
handle_path,
None,
Gio.DBusSignalFlags.NONE,
on_signal,
None
)

params = GLib.Variant.new_tuple(
GLib.Variant.new_string(""),
GLib.Variant('a{sv}', {'handle_token': GLib.Variant('s', token)})
)

bus.call_sync(
"org.freedesktop.portal.Desktop",
"/org/freedesktop/portal/desktop",
"org.freedesktop.portal.Screenshot",
"PickColor",
params,
None,
Gio.DBusCallFlags.NONE,
-1,
None
)
loop.run()
return result_color
except Exception:
return None

def main():
try:
from gi.repository import Gio
bus = Gio.bus_get_sync(Gio.BusType.SESSION, None)
except Exception as e:
sys.stderr.write(f"Failed to connect to D-Bus: {e}\n")
sys.exit(2)

# 1. First try GNOME Shell native loupe (direct, no portal prompt)
color = try_gnome(bus)
if color == "CANCELLED":
sys.exit(1)
if color:
print(json.dumps(color))
sys.exit(0)

# 2. Fallback to XDG Desktop Portal (KDE, Wayland compositors)
color = try_portal(bus)
if color:
print(json.dumps(color))
sys.exit(0)

sys.exit(1)

if __name__ == "__main__":
main()
Binary file added extensions/color-picker/assets/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading