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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f1e9d66dee40bab2644c326883aa740d9cda4c7a
4
- data.tar.gz: a35a610cd2d18dd40fdc04486b9492c41df6a065
3
+ metadata.gz: 359fdeba42a4dab1eb7e042e4bcf4a53f816238b
4
+ data.tar.gz: 03fef4f1ab539e544e6dcb1b8079d38d722cf636
5
5
  SHA512:
6
- metadata.gz: 019a82dd2e1110b082fa59c815f551b53a1620db009112d5d506889c88527f78d8cd84692112627ebb1f725406cd258a60d22c07552377922e68a8502c845c19
7
- data.tar.gz: 22c2fad73246cd26eedca03248e5a3f0afc2d28bea15350341807ee4c57102f5c9089ae175a1cf47e016886df1f3c473afa197200796d0164b6d6e3afdfd5fa3
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
@@ -104,7 +104,7 @@ Clipboard::UNICODETEXT
104
104
  Ruby's
105
105
 
106
106
  == Copyright
107
- (C) 2003-2008 Daniel J. Berger
107
+ (C) 2003-2014 Daniel J. Berger
108
108
  All Rights Reserved
109
109
 
110
110
  == Authors
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'
@@ -16,7 +16,7 @@ module Win32
16
16
  extend Windows::Structs
17
17
 
18
18
  # The version of this library
19
- VERSION = '0.6.2'
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
- unless EmptyClipboard()
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
- yield unless @first_notify
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
 
@@ -1,6 +1,8 @@
1
1
  module Windows
2
2
  module Constants
3
3
  GHND = 0x0042
4
+ WM_DESTROY = 0x0002
5
+ WM_CLOSE = 0x0010
4
6
  WM_DRAWCLIPBOARD = 0x0308
5
7
  WM_CHANGECBCHAIN = 0x030D
6
8
  GWL_USERDATA = -21
@@ -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
@@ -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
+
@@ -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
@@ -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.2', Clipboard::VERSION)
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
@@ -2,7 +2,7 @@ require "rubygems"
2
2
 
3
3
  Gem::Specification.new do |spec|
4
4
  spec.name = 'win32-clipboard'
5
- spec.version = '0.6.2'
5
+ spec.version = '0.6.3'
6
6
  spec.authors = ['Daniel J. Berger', 'Park Heesob']
7
7
  spec.license = 'Artistic 2.0'
8
8
  spec.email = 'djberg96@gmail.com'
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.2
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-01-27 00:00:00.000000000 Z
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.1
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