Skip to content

Commit

Permalink
Merge branch 'wayland' of https://github.com/ankostis/pyperclip into …
Browse files Browse the repository at this point in the history
…ankostis-wayland
  • Loading branch information
asweigart committed Oct 4, 2020
2 parents 1df4ee5 + 3f6b5da commit cd7ac3b
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 18 deletions.
77 changes: 59 additions & 18 deletions src/pyperclip/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@
On Windows, no additional modules are needed.
On Mac, the pyobjc module is used, falling back to the pbcopy and pbpaste cli
commands. (These commands should come with OS X.).
On Linux, install xclip or xsel via package manager. For example, in Debian:
On Linux, install xclip, xsel, or wl-clipboard (for "wayland" sessions) via package manager.
For example, in Debian:
sudo apt-get install xclip
sudo apt-get install xsel
sudo apt-get install wl-clipboard
Otherwise on Linux, you will need the gtk or PyQt5/PyQt4 modules installed.
Expand All @@ -37,6 +39,7 @@
- pbpaste
- xclip
- xsel
- wl-copy/wl-paste
- klipper
- qdbus
A malicious user could rename or add programs with these names, tricking
Expand Down Expand Up @@ -72,15 +75,18 @@

ENCODING = 'utf-8'

# The "which" unix command finds where a command is.
if platform.system() == 'Windows':
WHICH_CMD = 'where'
else:
WHICH_CMD = 'which'
try:
from shutil import which as _executable_exists
except ImportError:
# The "which" unix command finds where a command is.
if platform.system() == 'Windows':
WHICH_CMD = 'where'
else:
WHICH_CMD = 'which'

def _executable_exists(name):
return subprocess.call([WHICH_CMD, name],
stdout=subprocess.PIPE, stderr=subprocess.PIPE) == 0
def _executable_exists(name):
return subprocess.call([WHICH_CMD, name],
stdout=subprocess.PIPE, stderr=subprocess.PIPE) == 0



Expand Down Expand Up @@ -246,6 +252,33 @@ def paste_xsel(primary=False):
return copy_xsel, paste_xsel


def init_wl_clipboard():
PRIMARY_SELECTION = "-p"

def copy_wl(text, primary=False):
text = _stringifyText(text) # Converts non-str values to str.
args = ["wl-copy"]
if primary:
args.append(PRIMARY_SELECTION)
if not text:
args.append('--clear')
subprocess.check_call(args, close_fds=True)
else:
pass
p = subprocess.Popen(args, stdin=subprocess.PIPE, close_fds=True)
p.communicate(input=text.encode(ENCODING))

def paste_wl(primary=False):
args = ["wl-paste", "-n"]
if primary:
args.append(PRIMARY_SELECTION)
p = subprocess.Popen(args, stdout=subprocess.PIPE, close_fds=True)
stdout, _stderr = p.communicate()
return stdout.decode(ENCODING)

return copy_wl, paste_wl


def init_klipper_clipboard():
def copy_klipper(text):
text = _stringifyText(text) # Converts non-str values to str.
Expand Down Expand Up @@ -531,6 +564,11 @@ def determine_clipboard():
else:
return init_gtk_clipboard()

if (
os.environ["XDG_SESSION_TYPE"] == "wayland" and
_executable_exists("wl-copy")
):
return init_wl_clipboard()
if _executable_exists("xsel"):
return init_xsel_clipboard()
if _executable_exists("xclip"):
Expand Down Expand Up @@ -579,15 +617,18 @@ def set_clipboard(clipboard):
'''
global copy, paste

clipboard_types = {'pbcopy': init_osx_pbcopy_clipboard,
'pyobjc': init_osx_pyobjc_clipboard,
'gtk': init_gtk_clipboard,
'qt': init_qt_clipboard, # TODO - split this into 'qtpy', 'pyqt4', and 'pyqt5'
'xclip': init_xclip_clipboard,
'xsel': init_xsel_clipboard,
'klipper': init_klipper_clipboard,
'windows': init_windows_clipboard,
'no': init_no_clipboard}
clipboard_types = {
"pbcopy": init_osx_pbcopy_clipboard,
"pyobjc": init_osx_pyobjc_clipboard,
"gtk": init_gtk_clipboard,
"qt": init_qt_clipboard, # TODO - split this into 'qtpy', 'pyqt4', and 'pyqt5'
"xclip": init_xclip_clipboard,
"xsel": init_xsel_clipboard,
"wl-clipboard": init_wl_clipboard,
"klipper": init_klipper_clipboard,
"windows": init_windows_clipboard,
"no": init_no_clipboard,
}

if clipboard not in clipboard_types:
raise ValueError('Argument must be one of %s' % (', '.join([repr(_) for _ in clipboard_types.keys()])))
Expand Down
6 changes: 6 additions & 0 deletions tests/test_pyperclip.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
init_dev_clipboard_clipboard,
init_gtk_clipboard, init_qt_clipboard,
init_xclip_clipboard, init_xsel_clipboard,
init_wl_clipboard,
init_klipper_clipboard, init_no_clipboard)
from pyperclip import init_windows_clipboard
from pyperclip import init_wsl_clipboard
Expand Down Expand Up @@ -168,6 +169,11 @@ class TestXSel(_TestClipboard):
clipboard = init_xsel_clipboard()


class TestWlClipboard(_TestClipboard):
if _executable_exists("wl-copy"):
clipboard = init_wl_clipboard()


class TestKlipper(_TestClipboard):
if _executable_exists("klipper") and _executable_exists("qdbus"):
clipboard = init_klipper_clipboard()
Expand Down

0 comments on commit cd7ac3b

Please sign in to comment.