win32-clipboard 0.6.2 → 0.6.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGES +6 -0
- data/README +1 -1
- data/Rakefile +6 -0
- data/lib/win32/clipboard.rb +34 -14
- data/lib/win32/windows/constants.rb +2 -0
- data/lib/win32/windows/functions.rb +3 -0
- data/test/lock.rb +18 -0
- data/test/notify.rb +27 -0
- data/test/test_clipboard.rb +22 -1
- data/test/test_clipboard_chain.rb +137 -0
- data/win32-clipboard.gemspec +1 -1
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 359fdeba42a4dab1eb7e042e4bcf4a53f816238b
|
4
|
+
data.tar.gz: 03fef4f1ab539e544e6dcb1b8079d38d722cf636
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 55d0dbe9871da1c7af56d9d0a5f2ce9f5daa1154983e47cb9d1f15c0059e68339b281733e9ea33ca3335fbb86a8e985bde343f56d2c4555fe9a45f5eace40bb1
|
7
|
+
data.tar.gz: 3ac574c4d51126ecf250d2e6ce867c1d9447a0e56940be4610d357d361ce03b320e9f3f25e2d311720dc28d11926f97eba4916400befd0ef50410acc558c91ff
|
data/CHANGES
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
== 0.6.3 - 7-Feb-2014
|
2
|
+
* Fixed a potential duplication notification issue in the notify_change method.
|
3
|
+
Thanks go to u338steven for the spot and patch.
|
4
|
+
* Fixed a clipboard chaining issue in the notify_change method when there are
|
5
|
+
multiple clipboard instances. Thanks again go to u338steven.
|
6
|
+
|
1
7
|
== 0.6.2 - 27-Jan-2014
|
2
8
|
* Fix and more tests for the internal get_image_data. Thanks go to u338steven
|
3
9
|
for the spot and patches.
|
data/README
CHANGED
data/Rakefile
CHANGED
@@ -51,6 +51,12 @@ namespace :test do
|
|
51
51
|
t.verbose = true
|
52
52
|
t.test_files = FileList['test/test_image_clipboard.rb']
|
53
53
|
end
|
54
|
+
|
55
|
+
Rake::TestTask.new(:chain) do |t|
|
56
|
+
t.warning = true
|
57
|
+
t.verbose = true
|
58
|
+
t.test_files = FileList['test/test_clipboard_chain.rb']
|
59
|
+
end
|
54
60
|
end
|
55
61
|
|
56
62
|
task :default => 'test:all'
|
data/lib/win32/clipboard.rb
CHANGED
@@ -16,7 +16,7 @@ module Win32
|
|
16
16
|
extend Windows::Structs
|
17
17
|
|
18
18
|
# The version of this library
|
19
|
-
VERSION = '0.6.
|
19
|
+
VERSION = '0.6.3'
|
20
20
|
|
21
21
|
# Clipboard formats
|
22
22
|
|
@@ -44,9 +44,7 @@ module Win32
|
|
44
44
|
def self.empty
|
45
45
|
begin
|
46
46
|
open
|
47
|
-
|
48
|
-
raise SystemCallError.new('EmptyClipboard', FFI.errno)
|
49
|
-
end
|
47
|
+
clear_if_already_opened
|
50
48
|
ensure
|
51
49
|
close
|
52
50
|
end
|
@@ -147,8 +145,8 @@ module Win32
|
|
147
145
|
#
|
148
146
|
def self.set_data(clip_data, format = TEXT)
|
149
147
|
begin
|
150
|
-
clear
|
151
148
|
open
|
149
|
+
clear_if_already_opened
|
152
150
|
|
153
151
|
# NULL terminate text or strip header of bitmap file
|
154
152
|
case format
|
@@ -268,10 +266,25 @@ module Win32
|
|
268
266
|
name = 'ruby-clipboard-' + Time.now.to_s
|
269
267
|
handle = CreateWindowEx(0, 'static', name, 0, 0, 0, 0, 0, 0, 0, 0, nil)
|
270
268
|
|
269
|
+
next_viewer = SetClipboardViewer(handle)
|
270
|
+
|
271
|
+
if next_viewer.nil?
|
272
|
+
raise SystemCallError.new('SetClipboardViewer', FFI.errno)
|
273
|
+
end
|
274
|
+
|
275
|
+
SetWindowLongPtr(handle, GWL_USERDATA, next_viewer)
|
276
|
+
|
277
|
+
ObjectSpace.define_finalizer(self, proc{self.close_window(handle)})
|
278
|
+
|
271
279
|
@first_notify = true
|
272
280
|
|
273
281
|
wnd_proc = FFI::Function.new(:uintptr_t, [:uintptr_t, :uint, :uintptr_t, :uintptr_t]) do |hwnd, umsg, wparam, lparam|
|
274
282
|
case umsg
|
283
|
+
when WM_DESTROY
|
284
|
+
next_viewer = GetWindowLongPtr(hwnd, GWL_USERDATA)
|
285
|
+
ChangeClipboardChain(hwnd, next_viewer)
|
286
|
+
PostQuitMessage(0)
|
287
|
+
rv = 0
|
275
288
|
when WM_DRAWCLIPBOARD
|
276
289
|
yield unless @first_notify
|
277
290
|
next_viewer = GetWindowLongPtr(hwnd, GWL_USERDATA)
|
@@ -280,8 +293,9 @@ module Win32
|
|
280
293
|
end
|
281
294
|
rv = 0
|
282
295
|
when WM_CHANGECBCHAIN
|
283
|
-
|
296
|
+
next_viewer = GetWindowLongPtr(hwnd, GWL_USERDATA)
|
284
297
|
next_viewer = lparam if next_viewer == wparam
|
298
|
+
SetWindowLongPtr(hwnd, GWL_USERDATA, next_viewer)
|
285
299
|
if next_viewer != 0
|
286
300
|
PostMessage(next_viewer, umsg, wparam, lparam)
|
287
301
|
end
|
@@ -299,14 +313,6 @@ module Win32
|
|
299
313
|
raise SystemCallError.new('SetWindowLongPtr', FFI.errno)
|
300
314
|
end
|
301
315
|
|
302
|
-
next_viewer = SetClipboardViewer(handle)
|
303
|
-
|
304
|
-
if next_viewer.nil?
|
305
|
-
raise SystemCallError.new('SetClipboardViewer', FFI.errno)
|
306
|
-
end
|
307
|
-
|
308
|
-
SetWindowLongPtr(handle, GWL_USERDATA, next_viewer)
|
309
|
-
|
310
316
|
msg = FFI::MemoryPointer.new(:char, 100)
|
311
317
|
|
312
318
|
while true
|
@@ -345,6 +351,14 @@ module Win32
|
|
345
351
|
end
|
346
352
|
end
|
347
353
|
|
354
|
+
# Clear the clipboard that is already opened
|
355
|
+
#
|
356
|
+
def self.clear_if_already_opened
|
357
|
+
unless EmptyClipboard()
|
358
|
+
raise SystemCallError.new('EmptyClipboard', FFI.errno)
|
359
|
+
end
|
360
|
+
end
|
361
|
+
|
348
362
|
# Get data for enhanced metadata files
|
349
363
|
#
|
350
364
|
def self.get_metafile_data(handle)
|
@@ -421,6 +435,12 @@ module Win32
|
|
421
435
|
|
422
436
|
array
|
423
437
|
end
|
438
|
+
|
439
|
+
# Close a window.(for self.notify_change)
|
440
|
+
#
|
441
|
+
def self.close_window(handle)
|
442
|
+
SendMessage(handle, WM_CLOSE, 0, 0)
|
443
|
+
end
|
424
444
|
end
|
425
445
|
end
|
426
446
|
|
@@ -24,6 +24,7 @@ module Windows
|
|
24
24
|
|
25
25
|
ffi_lib :user32
|
26
26
|
|
27
|
+
attach_function :ChangeClipboardChain, [:hwnd, :hwnd], :bool
|
27
28
|
attach_function :CloseClipboard, [], :bool
|
28
29
|
attach_function :CountClipboardFormats, [], :int
|
29
30
|
attach_function :CreateWindowEx, :CreateWindowExA, [:dword, :string, :string, :dword, :int, :int, :int, :int, :hwnd, :hmenu, :hinstance, :pointer], :hwnd
|
@@ -37,9 +38,11 @@ module Windows
|
|
37
38
|
attach_function :OpenClipboard, [:hwnd], :bool
|
38
39
|
attach_function :PeekMessage, :PeekMessageA, [:pointer, :hwnd, :uint, :uint, :uint], :bool
|
39
40
|
attach_function :PostMessage, :PostMessageA, [:hwnd, :uint, :uintptr_t, :uintptr_t], :bool
|
41
|
+
attach_function :PostQuitMessage, :PostQuitMessage, [:uint], :void
|
40
42
|
attach_function :RegisterClipboardFormat, :RegisterClipboardFormatA, [:string], :uint
|
41
43
|
attach_function :SetClipboardData, [:uint, :handle], :handle
|
42
44
|
attach_function :SetClipboardViewer, [:hwnd], :hwnd
|
45
|
+
attach_function :SendMessage, :SendMessageA, [:hwnd, :uint, :uintptr_t, :uintptr_t], :bool
|
43
46
|
attach_function :TranslateMessage, [:pointer], :bool
|
44
47
|
|
45
48
|
# Use Long on 32-bit Ruby, LongPtr on 64-bit Ruby
|
data/test/lock.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'timeout'
|
2
|
+
require 'tmpdir'
|
3
|
+
|
4
|
+
def lock(&block)
|
5
|
+
Timeout::timeout(5) do
|
6
|
+
open(File.join(Dir.tmpdir, 'ruby-win32-clipboard.lock'), 'w') do |f|
|
7
|
+
begin
|
8
|
+
f.flock(File::LOCK_EX)
|
9
|
+
yield
|
10
|
+
ensure
|
11
|
+
f.flock(File::LOCK_UN)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
rescue Timeout::Error
|
16
|
+
raise 'Lock(timeout)'
|
17
|
+
end
|
18
|
+
|
data/test/notify.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'win32/clipboard'
|
2
|
+
require File.join(File.dirname(__FILE__), 'lock')
|
3
|
+
|
4
|
+
include Win32
|
5
|
+
|
6
|
+
timeout = ARGV[1].to_i
|
7
|
+
|
8
|
+
def write
|
9
|
+
data = ''
|
10
|
+
lock do
|
11
|
+
data = Clipboard.data
|
12
|
+
end
|
13
|
+
|
14
|
+
begin
|
15
|
+
STDOUT.puts data
|
16
|
+
STDOUT.flush
|
17
|
+
rescue => e
|
18
|
+
puts $!
|
19
|
+
end
|
20
|
+
if data == ARGV[0]
|
21
|
+
exit
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
Timeout::timeout(timeout) do
|
26
|
+
Clipboard.notify_change {write}
|
27
|
+
end
|
data/test/test_clipboard.rb
CHANGED
@@ -10,11 +10,12 @@
|
|
10
10
|
###########################################################################
|
11
11
|
require 'test-unit'
|
12
12
|
require 'win32/clipboard'
|
13
|
+
require 'timeout'
|
13
14
|
include Win32
|
14
15
|
|
15
16
|
class TC_Win32_ClipBoard < Test::Unit::TestCase
|
16
17
|
test "version is set to expected value" do
|
17
|
-
assert_equal('0.6.
|
18
|
+
assert_equal('0.6.3', Clipboard::VERSION)
|
18
19
|
end
|
19
20
|
|
20
21
|
test "data method basic functionality" do
|
@@ -141,6 +142,26 @@ class TC_Win32_ClipBoard < Test::Unit::TestCase
|
|
141
142
|
|
142
143
|
test "notify_change basic functionality" do
|
143
144
|
assert_respond_to(Clipboard, :notify_change)
|
145
|
+
def wait(&block)
|
146
|
+
Timeout::timeout(5) do
|
147
|
+
while @count == 0
|
148
|
+
yield if block
|
149
|
+
sleep(0.1)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
@count = 0
|
155
|
+
t = Thread.start do
|
156
|
+
Clipboard.notify_change {@count += 1}
|
157
|
+
end
|
158
|
+
wait {Clipboard.set_data('ready')}
|
159
|
+
@count = 0
|
160
|
+
|
161
|
+
Clipboard.set_data('foo')
|
162
|
+
wait
|
163
|
+
assert_equal(@count, 1)
|
164
|
+
t.kill
|
144
165
|
end
|
145
166
|
|
146
167
|
test "expected constants are defined" do
|
@@ -0,0 +1,137 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
###########################################################################
|
3
|
+
# test_clipboard_chain.rb
|
4
|
+
#
|
5
|
+
# Test suite for the win32-clipboard library(only clipboard chain).
|
6
|
+
###########################################################################
|
7
|
+
require 'test-unit'
|
8
|
+
require 'win32/clipboard'
|
9
|
+
require 'timeout'
|
10
|
+
require File.join(File.dirname(__FILE__), 'lock')
|
11
|
+
|
12
|
+
include Win32
|
13
|
+
|
14
|
+
class TC_Clipboard_Chain < Test::Unit::TestCase
|
15
|
+
test "clipboard viewer chain" do
|
16
|
+
begin
|
17
|
+
# Add clipboard viewer 1-3
|
18
|
+
# clipboard viewer chain: cv3 -> cv2 -> cv1
|
19
|
+
cv1 = ClipboardViewer.new('1')
|
20
|
+
puts 'Added clipboard viewer 1'
|
21
|
+
|
22
|
+
cv2 = ClipboardViewer.new('2')
|
23
|
+
puts 'Added clipboard viewer 2'
|
24
|
+
|
25
|
+
cv3 = ClipboardViewer.new('3')
|
26
|
+
puts 'Added clipboard viewer 3'
|
27
|
+
|
28
|
+
lock do
|
29
|
+
Clipboard.set_data('foo')
|
30
|
+
end
|
31
|
+
|
32
|
+
result = Clipboard.data
|
33
|
+
assert_equal(result, cv1.result)
|
34
|
+
assert_equal(result, cv2.result)
|
35
|
+
assert_equal(result, cv3.result)
|
36
|
+
|
37
|
+
# Remove clipboard viewer 2
|
38
|
+
# clipboard viewer chain: cv3 -> cv1
|
39
|
+
assert_not_nil(cv2.remove)
|
40
|
+
|
41
|
+
cv1.clear
|
42
|
+
cv3.clear
|
43
|
+
Clipboard.set_data('bar')
|
44
|
+
|
45
|
+
result = Clipboard.data
|
46
|
+
assert_equal(result, cv1.result)
|
47
|
+
assert_equal(result, cv3.result)
|
48
|
+
|
49
|
+
# Remove clipboard viewer 3
|
50
|
+
assert_not_nil(cv3.remove)
|
51
|
+
|
52
|
+
cv1.clear
|
53
|
+
Clipboard.set_data('foobar')
|
54
|
+
|
55
|
+
result = Clipboard.data
|
56
|
+
assert_equal(result, cv1.result)
|
57
|
+
assert_not_nil(cv1.remove)
|
58
|
+
ensure
|
59
|
+
cv1.exit
|
60
|
+
cv2.exit
|
61
|
+
cv3.exit
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
class ClipboardViewer
|
66
|
+
NOTIFY_TIMEOUT = 20
|
67
|
+
def initialize(key)
|
68
|
+
@key = key
|
69
|
+
load_path = File.join(File.join(File.dirname(__FILE__), '..'), 'lib')
|
70
|
+
@pipe = IO.popen("#{RbConfig.ruby} -I #{load_path} #{File.join(File.dirname(__FILE__), "notify.rb")} #{key} #{NOTIFY_TIMEOUT}")
|
71
|
+
@result = nil
|
72
|
+
is_ready = false
|
73
|
+
|
74
|
+
@t = Thread.start do
|
75
|
+
begin
|
76
|
+
while true
|
77
|
+
result = @pipe.gets.chomp
|
78
|
+
|
79
|
+
if result == 'ready'
|
80
|
+
is_ready = true
|
81
|
+
else
|
82
|
+
@result = result
|
83
|
+
end
|
84
|
+
|
85
|
+
if @result == @key.chop
|
86
|
+
break
|
87
|
+
end
|
88
|
+
end
|
89
|
+
rescue => e
|
90
|
+
puts $!
|
91
|
+
puts e.backtrace
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
Timeout::timeout(5) do
|
96
|
+
until is_ready
|
97
|
+
lock do
|
98
|
+
Clipboard.set_data('ready')
|
99
|
+
end
|
100
|
+
sleep(0.1)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def clear
|
106
|
+
@result = nil
|
107
|
+
end
|
108
|
+
|
109
|
+
def result
|
110
|
+
Timeout::timeout(5) do
|
111
|
+
until @result
|
112
|
+
sleep(0.1)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
@result
|
116
|
+
rescue Timeout::Error
|
117
|
+
raise 'Cannot get result.(Timeout)'
|
118
|
+
end
|
119
|
+
|
120
|
+
def remove
|
121
|
+
return unless @t.alive?
|
122
|
+
lock do
|
123
|
+
Clipboard.set_data(@key)
|
124
|
+
end
|
125
|
+
ret = @t.join(3)
|
126
|
+
if ret
|
127
|
+
@pipe.close
|
128
|
+
end
|
129
|
+
ret
|
130
|
+
end
|
131
|
+
|
132
|
+
def exit
|
133
|
+
return unless @t.alive?
|
134
|
+
Process.kill('KILL', @pipe.pid)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
data/win32-clipboard.gemspec
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: win32-clipboard
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.
|
4
|
+
version: 0.6.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel J. Berger
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-
|
12
|
+
date: 2014-02-07 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: ffi
|
@@ -87,7 +87,10 @@ files:
|
|
87
87
|
- test/img/32bit_bitfields2.bmp
|
88
88
|
- test/img/4bit.bmp
|
89
89
|
- test/img/8bit.bmp
|
90
|
+
- test/lock.rb
|
91
|
+
- test/notify.rb
|
90
92
|
- test/test_clipboard.rb
|
93
|
+
- test/test_clipboard_chain.rb
|
91
94
|
- test/test_html_clipboard.rb
|
92
95
|
- test/test_image_clipboard.rb
|
93
96
|
- win32-clipboard.gemspec
|
@@ -111,7 +114,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
111
114
|
version: '0'
|
112
115
|
requirements: []
|
113
116
|
rubyforge_project: win32utils
|
114
|
-
rubygems_version: 2.2.
|
117
|
+
rubygems_version: 2.2.2
|
115
118
|
signing_key:
|
116
119
|
specification_version: 4
|
117
120
|
summary: A library for interacting with the Windows clipboard
|