Clipboard for ubuntu

update on 11.23

noilinux没有预装剪贴板是怎么回事呢?noilinux相信大家都很熟悉,但是noilinux没有预装剪贴板是怎么回事呢,下面就让小编带大家一起了解吧。
noilinux没有预装剪贴板,其实就是无法查看剪贴板历史,大家可能会很惊讶noilinux怎么会没有预装剪贴板呢?但事实就是这样,小编也感到非常惊讶。
这就是关于noilinux没有预装剪贴板的事情了,大家有什么想法呢,欢迎在评论区告诉小编一起讨论哦!

因为 noi linux 没装历史剪贴板所以写一个

大致思路:

明文存储剪贴板内容和sha256sum哈希较验码,更新时比较较验码

文件结构:

──clipboard/
  ├── sha/		//sha256sum
  │	└── nw.txt
  ├── store/	//历史剪贴板内容
  │	└── nw.txt
  ├── upd.py	//记录内容
  └── UI.py		//GUI界面

使用说明:

upd.py

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gdk
import time
import os

cur_dir=''
cur_sto=''
cur_sha=''
nw_sto=''
nw_sha=''

maxn=10
cnt=0


def sto_file(id):
	if(type(id)==type(0)):
		fn=str(id)
		return f'{cur_sto}{fn}.txt'
	else:
		return f'{cur_sto}{id}.txt'


def sha_file(id):
	if(type(id)==type(0)):
		fn=str(id)
		return f'{cur_sha}{fn}.txt'
	else:
		return f'{cur_sha}{id}.txt'

def pre():
	global cur_dir,cur_sto,cur_sha,nw_sto,nw_sha
	cur_file_path = os.path.abspath(__file__)
	cur_dir = os.path.dirname(cur_file_path)
	cur_sto = cur_dir+'/store/'
	cur_sha = cur_dir+'/sha/'
	nw_sto = sto_file('nw')
	nw_sha = sha_file('nw')

	if os.path.exists('store')==False:
		os.system('mkdir store')
	if os.path.exists('sha')==False:
		os.system('mkdir sha')
	if os.path.exists('store/nw.txt')==False:
		os.system('touch store/nw.txt')
	if os.path.exists('sha/nw.txt')==False:
		os.system('touch sha/nw.txt')


def count_files_in_directory(directory):
	files = os.listdir(directory)
	return len(files)

def chk(now):
	global cnt
	cnt=count_files_in_directory(cur_sto)-1
	if cnt==0:
		return 1
	else:
		flag=1
		with open(nw_sto, 'w') as f:
			f.write(now)
		os.system(f'sha256sum {nw_sto} > {nw_sha}')
		with open(nw_sha, 'r', encoding='utf-8') as f:
			sha_nw,nwname= f.read().strip().split()

		for i in range(1,cnt+1):
			with open(sha_file(i), 'r', encoding='utf-8') as f:
				sha_ps,psname= f.read().strip().split()
			if sha_ps==sha_nw:
				flag=0
				break
		
		return flag

def write_to_file(now):
	for i in range(min(maxn-1,cnt),0,-1):
		os.system(f'mv {sto_file(i)} {sto_file(i+1)}')
		os.system(f'mv {sha_file(i)} {sha_file(i+1)}')
	with open(sto_file(1), 'w') as f:
		f.write(now)
	os.system(f'sha256sum {sto_file(1)} > {sha_file(1)}')

def get_clipboard_text():
	clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
	text = clipboard.wait_for_text()
	return text

def output():
	now = get_clipboard_text()
	if now==None:
		now="There must be something wrong"
	if chk(now):
		write_to_file(now)

if __name__ == '__main__':
	print('Recording clipboard content, please do not end the process or close the terminal')
	pre()
	# print(sto_file('nw'))
	while 1:
		output()
		time.sleep(2)

UI.py

import gi
gi.require_version('Gtk', '3.0')
gi.require_version('Gdk', '3.0')
from gi.repository import Gtk, Gdk, GLib
import cairo
import os

cur_dir = ''

def count_files_in_directory(directory):
	files = os.listdir(directory)
	return len(files)

def update_content(file_path):
	if os.path.exists(file_path):
		with open(file_path, 'r', encoding='utf-8') as f:
			content = f.read().strip()

		if len(content) > 50:
			content = content[:50] + "..."
		
		return content
	return ""

class TextDisplayApp:
	def __init__(self):
		self.window = Gtk.Window(type=Gtk.WindowType.TOPLEVEL)
		self.window.set_title("pastebin")
		self.window.set_default_size(350, 400)
		self.window.set_resizable(True)
		self.window.set_border_width(10)    
		self.window.set_keep_above(True)
		self.window.set_skip_taskbar_hint(True)
		self.window.set_skip_pager_hint(True)

		self._position_window_bottom_right()
		
		main_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=5)
		self.window.add(main_box)
		
		scrolled_window = Gtk.ScrolledWindow()
		scrolled_window.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
		scrolled_window.set_shadow_type(Gtk.ShadowType.NONE)
		main_box.pack_start(scrolled_window, True, True, 0)
		
		self.text_container = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=8)
		scrolled_window.add(self.text_container)
		
		self.text_labels = []
		self.event_boxes = []
		
		self.text_data = ["BY GON_TATA","https://www.cnblogs.com/gon-tata/p/19084568","gugugaga"]
		
		GLib.timeout_add_seconds(2, self.flash_all_content)
		self.window.connect("destroy", Gtk.main_quit)
		
		self.create_text_areas()
		
		self.window.show_all()
	
	def _position_window_bottom_right(self):
		display = Gdk.Display.get_default()
		n_monitors = display.get_n_monitors()
		
		mon_geoms = [
			display.get_monitor(i).get_geometry()
			for i in range(n_monitors)
		]
		
		x0 = min(r.x for r in mon_geoms)
		y0 = min(r.y for r in mon_geoms)
		x1 = max(r.x + r.width for r in mon_geoms)
		y1 = max(r.y + r.height for r in mon_geoms)
		
		screen_width = x1 - x0
		screen_height = y1 - y0
		
		self.window.realize()
		width, height = self.window.get_size()
		
		x = screen_width - width - 20
		y = screen_height - height - 50
		
		self.window.move(x, y)

	def create_text_areas(self):
		for child in self.text_container.get_children():
			self.text_container.remove(child)
		
		self.text_labels.clear()
		self.event_boxes.clear()
		
		self.flash_all_content(False)
		
		for i, text in enumerate(self.text_data):
			event_box = Gtk.EventBox()
			event_box.connect("button-press-event", self.on_text_clicked, text)
					
			frame = Gtk.Frame()
			frame.get_style_context().add_class("text-frame")
			event_box.add(frame)
			
			text_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=5)
			frame.add(text_box)
			
			label = Gtk.Label()
			label.set_text(text)
			label.set_line_wrap(True)
			label.set_max_width_chars(35)
			label.set_xalign(0)
			label.set_yalign(0)
			label.get_style_context().add_class("text-label")
			
			text_box.pack_start(label, True, True, 0)
			
			self.text_labels.append(label)
			self.event_boxes.append(event_box)
			
			self.text_container.pack_start(event_box, False, False, 0)
			
			if i < len(self.text_data) - 1:
				separator = Gtk.Separator(orientation=Gtk.Orientation.HORIZONTAL)
				self.text_container.pack_start(separator, False, False, 0)
		
		self.text_container.show_all()

	def flash_all_content(self, update_ui=True):
		old_count = len(self.text_data)
		self.text_data.clear()
		
		cnt = count_files_in_directory(cur_dir + "/store")-1
		
		for i in range(1, cnt + 1):
			fileid = str(i)
			content = update_content(cur_dir + "/store/" + fileid + '.txt')
			self.text_data.append(content)
		
		if old_count != cnt and update_ui:
			self.create_text_areas()
		elif update_ui:
			for i, label in enumerate(self.text_labels):
				if i < len(self.text_data):
					label.set_text(self.text_data[i])
		
		return True

	def on_text_clicked(self, widget, event, text):
		if event.button == 1:
			index = self.event_boxes.index(widget)
			file_id = index + 1
			file_path = f"{cur_dir}/store/{file_id}.txt"
			
			if os.path.exists(file_path):
				with open(file_path, 'r', encoding='utf-8') as f:
					full_content = f.read().strip()
				self.copy_to_clipboard(full_content)
				self.show_notification("copied!")
			return True
		return False

	def copy_to_clipboard(self, text):
		clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
		clipboard.set_text(text, -1)
		clipboard.store()

	def show_notification(self, message):
		overlay = Gtk.Window(type=Gtk.WindowType.POPUP)
		overlay.set_decorated(False)
		overlay.set_resizable(False)
		overlay.set_skip_taskbar_hint(True)
		overlay.set_skip_pager_hint(True)
		overlay.set_keep_above(True)
				
		label = Gtk.Label(label=message)
		label.set_name("notification-label")
		label.get_style_context().add_class("notification")
		
		css_provider = Gtk.CssProvider()
		css = """
		#notification-label {
			background-color: rgba(0, 0, 0, 0.0);
			color: white;
			padding: 8px 12px;
			border-radius: 4px;
			font-weight: bold;
			text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.8);
		}
		"""
		css_provider.load_from_data(css.encode())
		Gtk.StyleContext.add_provider_for_screen(
			Gdk.Screen.get_default(),
			css_provider,
			Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
		)
		
		overlay.add(label)
		overlay.show_all()
		
		self._position_notification(overlay)
		
		GLib.timeout_add(2000, overlay.destroy)

	def _position_notification(self, notification_window):
		screen = Gdk.Screen.get_default()
		screen_width = screen.get_width()
		
		notification_window.realize()
		width, height = notification_window.get_size()
		
		x = screen_width - width - 20
		y = 20
		
		notification_window.move(x, y)

	def run(self):
		Gtk.main()

if __name__ == "__main__":
	cur_file_path = os.path.abspath(__file__)
	cur_dir = os.path.dirname(cur_file_path)
	app = TextDisplayApp()
	app.run()

新建 upd.pyUI.py (不用管sha/store/upd.py会把它们建好)

终端 cd 到当前文件夹

python3 upd.py

另开一个终端

python3 UI.py

使用建议:

开一个终端跑 upd.py 挂后台,为 UI.py 设置快捷键

设置 > 键盘快捷键 拉到页面最底下点击 +

名称 随便填

命令python3 $UI.py的绝对路径$

例:UI.py 的绝对路径为 /home/hzoi/下载/hwsp/clipboard/UI.py

命令 应填 python3 /home/hzoi/下载/hwsp/clipboard/UI.py

另:

默认保留最近10次记录,次数和更新频率可自行修改源代码,GUI界面单击预览部分可以快速复制对应文本

posted @ 2025-09-10 19:43  Gon-Tata  阅读(59)  评论(5)    收藏  举报