win32-clipboard 0.6.2 → 0.6.3

Sign up to get free protection for your applications and to get access to all the features.
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