ob_clipboard_manager.py 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. #!/usr/bin/env python
  2. # OpenBox pipe menu clipboard manager. Show parcellite clipboard, and inserts selected clip.
  3. #
  4. # Copyright 2013 Joe Bloggs (vapniks@yahoo.com)
  5. #
  6. # These scripts: ob_clipboard_manager.py, ob_clipboard_pipe_menu.py & ob_paste_clip.py
  7. # create a pipe menu for openbox which will display the history of clippings stored by parcellite
  8. # or clipit, and allow you to paste one of them by selecting it.
  9. # Obviously either parcellite or clipit needs to be installed for this to work, and they should not
  10. # be run in daemon mode.
  11. # parcellite should be available from the usual repositories, and clipit can be
  12. # obtained from here: http://clipit.rspwn.com/
  13. # If clipit is used then any static clippings will also be displayed in the pipe menu.
  14. # You may need to alter some of the following variables in ob_clipboard_manager.py:
  15. # clipit_history_file, parcellite_history_file, max_displayed_items
  16. # Installation: copy ob_clipboard_manager.py, ob_clipboard_pipe_menu.py & ob_paste_clip.py to your openbox
  17. # config directory (on Ubuntu its ~/.config/openbox), then add an item to your openbox menu.xml file
  18. # (also in the config dir) in the form:
  19. #
  20. # <menu execute="~/.config/openbox/ob_clipboard_pipe_menu.py" id="clipboard" label="Clipboard"/>
  21. #
  22. # This program is free software: you can redistribute it and/or modify
  23. # it under the terms of the GNU General Public License as published by
  24. # the Free Software Foundation, either version 3 of the License, or
  25. # (at your option) any later version.
  26. #
  27. # This program is distributed in the hope that it will be useful,
  28. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  29. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  30. # GNU General Public License for more details.
  31. #
  32. # You should have received a copy of the GNU General Public License
  33. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  34. #
  35. import os
  36. import struct
  37. from xml.sax.saxutils import escape
  38. from os.path import expanduser
  39. import string
  40. import subprocess
  41. # change the following paths if necessary
  42. clipit_history_file = expanduser('~') + "/.local/share/clipit/history"
  43. parcellite_history_file = expanduser('~') + "/.local/share/parcellite/history"
  44. max_displayed_items = 20
  45. class ob_cb_manager:
  46. def __init__(self): # constructor
  47. # alter the following line if your history file is found elsewhere
  48. self.clippings = []
  49. self.running = False
  50. # find out which clipboard manager is running and read appropriate history file
  51. ps = subprocess.Popen("ps -ef | grep \"parcellite\|clipit\" | grep -v grep", shell=True, stdout=subprocess.PIPE)
  52. output = ps.stdout.read()
  53. ps.wait()
  54. if string.find(output,"clipit") != -1:
  55. # read the appropriate history file
  56. self.read_clipit_history(length=max_displayed_items, filepath=clipit_history_file)
  57. self.running = True
  58. elif string.find(output,"parcellite") != -1:
  59. self.read_parcellite_history(length=max_displayed_items, filepath=parcellite_history_file)
  60. self.running = True
  61. def read_parcellite_history(self, length=20, filepath=None):
  62. if filepath is None:
  63. filepath = parcellite_history_file
  64. self.clippings = []
  65. # open the file as binary
  66. f = open(filepath,"rb")
  67. # read the first 4 bytes (which should indicate the size of the first clipping)
  68. size = struct.unpack('i',f.read(4))[0]
  69. # stop when we have enough clippings or if we reach a clipping of length 0
  70. count = 0
  71. while size != 0 and count < length:
  72. # read the clipping and append it to clippings
  73. self.clippings.append(f.read(size))
  74. count = count + 1
  75. # read the next 4 bytes
  76. data = f.read(4)
  77. # convert to a size, or quit if we've reached the end of the file
  78. if data:
  79. size = struct.unpack('i',data)[0]
  80. else:
  81. size = 0
  82. def read_clipit_history(self, length=20, filepath=None):
  83. if filepath is None:
  84. filepath = clipit_history_file
  85. volatile_clippings = []
  86. static_clippings = []
  87. # open the file as binary
  88. f = open(filepath,"rb")
  89. # save some typing with this subfunction
  90. def read4bytes():
  91. data = f.read(4)
  92. if data:
  93. return struct.unpack('i',data)[0]
  94. else:
  95. return 0
  96. # read the first 4 bytes (which should indicate the size of the first clipping)
  97. size = read4bytes()
  98. # if size = -1 we are using the new filetype introduced in 1.4.1
  99. if size == -1:
  100. # ignore the extra 64 bytes of initial data
  101. f.read(64)
  102. # read clippings until we reach the end
  103. size = read4bytes()
  104. data_type = read4bytes()
  105. while size and data_type:
  106. item = f.read(size)
  107. if data_type == 1:
  108. clip = item
  109. elif data_type == 2: # FIXME!!!!!!!!!!
  110. if not struct.unpack('i',item)[0]:
  111. volatile_clippings.append(clip)
  112. else:
  113. static_clippings.append(clip)
  114. size = read4bytes()
  115. data_type = read4bytes()
  116. # take required number of volatile clippings and add static clippings to the end
  117. self.clippings = volatile_clippings[0:length] + static_clippings[0:length]
  118. # for versions of clipit prior to 1.4.1 the history file format is the same as parcellite
  119. else:
  120. self.read_parcellite_history(length, filepath)
  121. # print the pipe menu items
  122. def print_menu_items(self):
  123. dic = {'&':'&amp;','"':'&quot;','<':'&lt;','>':'&gt;',"'":'&apos;','_':'__','':' ','':' '}
  124. if self.running:
  125. for i in range(0,len(self.clippings)):
  126. clip = self.clippings[i]
  127. sanetext = clip[:50]
  128. for j, k in dic.iteritems():
  129. sanetext = sanetext.replace(j, k)
  130. if i < 10:
  131. shortcut = '_' + str(i) + ': '
  132. elif i < 10+26:
  133. shortcut = '_' + string.ascii_lowercase[i-10] + ': '
  134. elif i < 36+26:
  135. shortcut = '_' + string.ascii_uppercase[i-36] + ': '
  136. else:
  137. shortcut = ' '
  138. thisdir = os.path.dirname(os.path.realpath(__file__))
  139. command = thisdir + "/ob_paste_clip.py " + str(i)
  140. print '<item label="' + shortcut + sanetext + '">\n<action name="execute"><execute>' + \
  141. command + '</execute></action>\n</item>'
  142. else:
  143. print '<item label="You need to start parcellite or clipit for this to work!">\n</item>'
  144. print '<item label="(without daemon option)">\n</item>'
  145. #manager = ob_cb_manager()
  146. #manager.read_clipit_history()