tk-win 0.2.1-x86-mingw32 → 0.2.2-x86-mingw32

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.
data/Rakefile CHANGED
@@ -5,18 +5,19 @@ require 'rake'
5
5
  begin
6
6
  require 'jeweler'
7
7
  Jeweler::Tasks.new do |gem|
8
- gem.name = "tk-win"
9
- gem.summary = %Q{RubyTk bindings for windows bundled with tcltklib and tkutil}
10
- gem.description = %Q{RubyTk bindings for windows bundled with tcltklib.so and tkutil.soin}
11
- gem.email = "elia.schito@gmail.com"
12
- gem.homepage = "http://github.com/elia/tk-win"
13
- gem.authors = ["Hidetoshi NAGAI", "Elia Schito"]
14
- gem.add_development_dependency "rspec", "~> 1.2.9"
8
+ gem.name = "tk-win"
9
+ gem.summary = %Q{RubyTk bindings for MS Windows RubyInstaller 1.9.1 bundled with binaries.}
10
+ gem.description = %Q{RubyTk bindings for windows bundled with tcltklib.so and tkutil.so for windows RubyInstaller 1.9.1}
11
+ gem.email = "elia.schito@gmail.com"
12
+ gem.homepage = "http://www.dumbo.ai.kyutech.ac.jp/nagai/RubyTk/?Ruby%2FTk-Kit"
13
+ gem.authors = ["Hidetoshi Nagai", "Elia Schito"]
14
+
15
15
  gem.required_ruby_version = "~> 1.9.1"
16
- gem.platform = 'x86-mingw32'
17
- gem.require_paths << "lib/#{gem.platform}"
18
- gem.files += Dir["lib/#{gem.platform}/*.so"]
16
+ gem.platform = "x86-mingw32"
17
+ gem.require_paths += Dir["lib/#{gem.platform}"]
18
+ gem.files += Dir["lib/#{gem.platform}/*.so"]
19
19
 
20
+ gem.add_development_dependency "rspec", "~> 1.2.9"
20
21
  # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
21
22
  end
22
23
  Jeweler::GemcutterTasks.new
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.1
1
+ 0.2.2
@@ -0,0 +1,3740 @@
1
+ #
2
+ # multi-tk.rb - supports multi Tk interpreters
3
+ # by Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
4
+
5
+ require 'tcltklib'
6
+ require 'tkutil'
7
+ require 'thread'
8
+
9
+ if defined? Tk
10
+ fail RuntimeError,"'multi-tk' library must be required before requiring 'tk'"
11
+ end
12
+
13
+ ################################################
14
+ # ignore exception on the mainloop?
15
+
16
+ TclTkLib.mainloop_abort_on_exception = true
17
+ # TclTkLib.mainloop_abort_on_exception = false
18
+ # TclTkLib.mainloop_abort_on_exception = nil
19
+
20
+
21
+ ################################################
22
+ # add ThreadGroup check to TclTkIp.new
23
+ class << TclTkIp
24
+ alias __new__ new
25
+ private :__new__
26
+
27
+ def new(*args)
28
+ if Thread.current.group != ThreadGroup::Default
29
+ raise SecurityError, 'only ThreadGroup::Default can call TclTkIp.new'
30
+ end
31
+ obj = __new__(*args)
32
+ obj.instance_eval{
33
+ @force_default_encoding ||= TkUtil.untrust([false])
34
+ @encoding ||= TkUtil.untrust([nil])
35
+ def @encoding.to_s; self.join(nil); end
36
+ }
37
+ obj
38
+ end
39
+ end
40
+
41
+
42
+ ################################################
43
+ # use pseudo-toplevel feature of MultiTkIp ?
44
+ if (!defined?(Use_PseudoToplevel_Feature_of_MultiTkIp) ||
45
+ Use_PseudoToplevel_Feature_of_MultiTkIp)
46
+ module MultiTkIp_PseudoToplevel_Evaluable
47
+ #def pseudo_toplevel_eval(body = Proc.new)
48
+ # Thread.current[:TOPLEVEL] = self
49
+ # begin
50
+ # body.call
51
+ # ensure
52
+ # Thread.current[:TOPLEVEL] = nil
53
+ # end
54
+ #end
55
+
56
+ def pseudo_toplevel_evaluable?
57
+ @pseudo_toplevel_evaluable
58
+ end
59
+
60
+ def pseudo_toplevel_evaluable=(mode)
61
+ @pseudo_toplevel_evaluable = (mode)? true: false
62
+ end
63
+
64
+ def self.extended(mod)
65
+ mod.__send__(:extend_object, mod)
66
+ mod.instance_variable_set('@pseudo_toplevel_evaluable', true)
67
+ end
68
+ end
69
+
70
+ class Object
71
+ alias __method_missing_alias_for_MultiTkIp__ method_missing
72
+ private :__method_missing_alias_for_MultiTkIp__
73
+
74
+ def method_missing(id, *args)
75
+ begin
76
+ has_top = (top = MultiTkIp.__getip.__pseudo_toplevel) &&
77
+ top.respond_to?(:pseudo_toplevel_evaluable?) &&
78
+ top.pseudo_toplevel_evaluable? &&
79
+ top.respond_to?(id)
80
+ rescue Exception => e
81
+ has_top = false
82
+ end
83
+
84
+ if has_top
85
+ top.__send__(id, *args)
86
+ else
87
+ __method_missing_alias_for_MultiTkIp__(id, *args)
88
+ end
89
+ end
90
+ end
91
+ else
92
+ # dummy
93
+ module MultiTkIp_PseudoToplevel_Evaluable
94
+ def pseudo_toplevel_evaluable?
95
+ false
96
+ end
97
+ end
98
+ end
99
+
100
+ ################################################
101
+ # exceptiopn to treat the return value from IP
102
+ class MultiTkIp_OK < Exception
103
+ def self.send(thread, ret=nil)
104
+ thread.raise self.new(ret)
105
+ end
106
+
107
+ def initialize(ret=nil)
108
+ super('succeed')
109
+ @return_value = ret
110
+ end
111
+
112
+ attr_reader :return_value
113
+ alias value return_value
114
+ end
115
+ MultiTkIp_OK.freeze
116
+
117
+
118
+ ################################################
119
+ # methods for construction
120
+ class MultiTkIp
121
+ class Command_Queue < Queue
122
+ def initialize(interp)
123
+ @interp = interp
124
+ super()
125
+ end
126
+
127
+ def push(value)
128
+ if !@interp || @interp.deleted?
129
+ fail RuntimeError, "Tk interpreter is already deleted"
130
+ end
131
+ super(value)
132
+ end
133
+ alias << push
134
+ alias enq push
135
+
136
+ def close
137
+ @interp = nil
138
+ end
139
+ end
140
+ Command_Queue.freeze
141
+
142
+ BASE_DIR = File.dirname(__FILE__)
143
+
144
+ WITH_RUBY_VM = Object.const_defined?(:RubyVM) && ::RubyVM.class == Class
145
+ WITH_ENCODING = defined?(::Encoding.default_external)
146
+ #WITH_ENCODING = Object.const_defined?(:Encoding) && ::Encoding.class == Class
147
+
148
+ (@@SLAVE_IP_ID = ['slave'.freeze, TkUtil.untrust('0')]).instance_eval{
149
+ @mutex = Mutex.new
150
+ def mutex; @mutex; end
151
+ freeze
152
+ }
153
+
154
+ @@IP_TABLE = TkUtil.untrust({}) unless defined?(@@IP_TABLE)
155
+
156
+ @@INIT_IP_ENV = TkUtil.untrust([]) unless defined?(@@INIT_IP_ENV) # table of Procs
157
+ @@ADD_TK_PROCS = TkUtil.untrust([]) unless defined?(@@ADD_TK_PROCS) # table of [name, args, body]
158
+
159
+ @@TK_TABLE_LIST = TkUtil.untrust([]) unless defined?(@@TK_TABLE_LIST)
160
+
161
+ unless defined?(@@TK_CMD_TBL)
162
+ @@TK_CMD_TBL = TkUtil.untrust(Object.new)
163
+
164
+ # @@TK_CMD_TBL.instance_variable_set('@tbl', {}.taint)
165
+ tbl_obj = TkUtil.untrust(Hash.new{|hash,key|
166
+ fail IndexError, "unknown command ID '#{key}'"
167
+ })
168
+ @@TK_CMD_TBL.instance_variable_set('@tbl', tbl_obj)
169
+
170
+ class << @@TK_CMD_TBL
171
+ allow = [
172
+ '__send__', '__id__', 'freeze', 'inspect', 'kind_of?', 'object_id',
173
+ '[]', '[]=', 'delete', 'each', 'has_key?'
174
+ ]
175
+ instance_methods.each{|m| undef_method(m) unless allow.index(m.to_s)}
176
+
177
+ def kind_of?(klass)
178
+ @tbl.kind_of?(klass)
179
+ end
180
+
181
+ def inspect
182
+ if Thread.current.group == ThreadGroup::Default
183
+ @tbl.inspect
184
+ else
185
+ ip = MultiTkIp.__getip
186
+ @tbl.reject{|idx, ent| ent.respond_to?(:ip) && ent.ip != ip}.inspect
187
+ end
188
+ end
189
+
190
+ def [](idx)
191
+ return unless (ent = @tbl[idx])
192
+ if Thread.current.group == ThreadGroup::Default
193
+ ent
194
+ elsif ent.respond_to?(:ip)
195
+ (ent.ip == MultiTkIp.__getip)? ent: nil
196
+ else
197
+ ent
198
+ end
199
+ end
200
+
201
+ def []=(idx,val)
202
+ if self.has_key?(idx) && Thread.current.group != ThreadGroup::Default
203
+ fail SecurityError,"cannot change the entried command"
204
+ end
205
+ @tbl[idx] = val
206
+ end
207
+
208
+ def delete(idx, &blk)
209
+ # if gets an entry, is permited to delete
210
+ if self[idx]
211
+ @tbl.delete(idx)
212
+ elsif blk
213
+ blk.call(idx)
214
+ else
215
+ nil
216
+ end
217
+ end
218
+
219
+ def each(&blk)
220
+ if Thread.current.group == ThreadGroup::Default
221
+ @tbl.each(&blk)
222
+ else
223
+ ip = MultiTkIp.__getip
224
+ @tbl.each{|idx, ent|
225
+ blk.call(idx, ent) unless ent.respond_to?(:ip) && ent.ip != ip
226
+ }
227
+ end
228
+ self
229
+ end
230
+
231
+ def has_key?(k)
232
+ @tbl.has_key?(k)
233
+ end
234
+ alias include? has_key?
235
+ alias key? has_key?
236
+ alias member? has_key?
237
+ end
238
+
239
+ @@TK_CMD_TBL.freeze
240
+ end
241
+
242
+ ######################################
243
+
244
+ @@CB_ENTRY_CLASS = Class.new(TkCallbackEntry){
245
+ def initialize(ip, cmd)
246
+ @ip = ip
247
+ @safe = safe = $SAFE
248
+ # @cmd = cmd
249
+ cmd = MultiTkIp._proc_on_safelevel(&cmd)
250
+ @cmd = proc{|*args| cmd.call(safe, *args)}
251
+ self.freeze
252
+ end
253
+ attr_reader :ip, :cmd
254
+ def inspect
255
+ cmd.inspect
256
+ end
257
+ def call(*args)
258
+ unless @ip.deleted?
259
+ current = Thread.current
260
+ backup_ip = current[:callback_ip]
261
+ current[:callback_ip] = @ip
262
+ begin
263
+ ret = @ip.cb_eval(@cmd, *args)
264
+ fail ret if ret.kind_of?(Exception)
265
+ ret
266
+ rescue TkCallbackBreak, TkCallbackContinue => e
267
+ fail e
268
+ rescue SecurityError => e
269
+ # in 'exit', 'exit!', and 'abort' : security error --> delete IP
270
+ if e.backtrace[0] =~ /^(.+?):(\d+):in `(exit|exit!|abort)'/
271
+ @ip.delete
272
+ elsif @ip.safe?
273
+ if @ip.respond_to?(:cb_error)
274
+ @ip.cb_error(e)
275
+ else
276
+ nil # ignore
277
+ end
278
+ else
279
+ fail e
280
+ end
281
+ rescue Exception => e
282
+ fail e if e.message =~ /^TkCallback/
283
+
284
+ if @ip.safe?
285
+ if @ip.respond_to?(:cb_error)
286
+ @ip.cb_error(e)
287
+ else
288
+ nil # ignore
289
+ end
290
+ else
291
+ fail e
292
+ end
293
+ ensure
294
+ current[:callback_ip] = backup_ip
295
+ end
296
+ end
297
+ end
298
+ }.freeze
299
+
300
+ ######################################
301
+
302
+ def _keys2opts(src_keys)
303
+ return nil if src_keys == nil
304
+ keys = {}; src_keys.each{|k, v| keys[k.to_s] = v}
305
+ #keys.collect{|k,v| "-#{k} #{v}"}.join(' ')
306
+ keys.collect{|k,v| "-#{k} #{TclTkLib._conv_listelement(TkComm::_get_eval_string(v))}"}.join(' ')
307
+ end
308
+ private :_keys2opts
309
+
310
+ def _check_and_return(thread, exception, wait=0)
311
+ unless thread
312
+ unless exception.kind_of?(MultiTkIp_OK)
313
+ msg = "#{exception.class}: #{exception.message}"
314
+
315
+ if @interp.deleted?
316
+ warn("Warning (#{self}): " + msg)
317
+ return nil
318
+ end
319
+
320
+ if safe?
321
+ warn("Warning (#{self}): " + msg) if $DEBUG
322
+ return nil
323
+ end
324
+
325
+ begin
326
+ @interp._eval_without_enc(@interp._merge_tklist('bgerror', msg))
327
+ rescue Exception => e
328
+ warn("Warning (#{self}): " + msg)
329
+ end
330
+ end
331
+ return nil
332
+ end
333
+
334
+ if wait == 0
335
+ # no wait
336
+ Thread.pass
337
+ if thread.stop?
338
+ thread.raise exception
339
+ end
340
+ return thread
341
+ end
342
+
343
+ # wait to stop the caller thread
344
+ wait.times{
345
+ if thread.stop?
346
+ # ready to send exception
347
+ thread.raise exception
348
+ return thread
349
+ end
350
+
351
+ # wait
352
+ Thread.pass
353
+ }
354
+
355
+ # unexpected error
356
+ thread.raise RuntimeError, "the thread may not wait for the return value"
357
+ return thread
358
+ end
359
+
360
+ ######################################
361
+
362
+ def set_cb_error(cmd = Proc.new)
363
+ @cb_error_proc[0] = cmd
364
+ end
365
+
366
+ def cb_error(e)
367
+ if @cb_error_proc[0].respond_to?(:call)
368
+ @cb_error_proc[0].call(e)
369
+ end
370
+ end
371
+
372
+ ######################################
373
+
374
+ def set_safe_level(safe)
375
+ if safe > @safe_level[0]
376
+ @safe_level[0] = safe
377
+ @cmd_queue.enq([@system, 'set_safe_level', safe])
378
+ end
379
+ @safe_level[0]
380
+ end
381
+ def safe_level=(safe)
382
+ set_safe_level(safe)
383
+ end
384
+ def self.set_safe_level(safe)
385
+ __getip.set_safe_level(safe)
386
+ end
387
+ def self.safe_level=(safe)
388
+ self.set_safe_level(safe)
389
+ end
390
+ def safe_level
391
+ @safe_level[0]
392
+ end
393
+ def self.safe_level
394
+ __getip.safe_level
395
+ end
396
+
397
+ def wait_on_mainloop?
398
+ @wait_on_mainloop[0]
399
+ end
400
+ def wait_on_mainloop=(bool)
401
+ @wait_on_mainloop[0] = bool
402
+ end
403
+
404
+ def running_mainloop?
405
+ @wait_on_mainloop[1] > 0
406
+ end
407
+
408
+ def _destroy_slaves_of_slaveIP(ip)
409
+ unless ip.deleted?
410
+ # ip._split_tklist(ip._invoke('interp', 'slaves')).each{|name|
411
+ ip._split_tklist(ip._invoke_without_enc('interp', 'slaves')).each{|name|
412
+ name = _fromUTF8(name)
413
+ begin
414
+ # ip._eval_without_enc("#{name} eval {foreach i [after info] {after cancel $i}}")
415
+ after_ids = ip._eval_without_enc("#{name} eval {after info}")
416
+ ip._eval_without_enc("#{name} eval {foreach i {#{after_ids}} {after cancel $i}}")
417
+ rescue Exception
418
+ end
419
+ begin
420
+ # ip._invoke('interp', 'eval', name, 'destroy', '.')
421
+ ip._invoke(name, 'eval', 'destroy', '.')
422
+ rescue Exception
423
+ end
424
+
425
+ # safe_base?
426
+ if ip._eval_without_enc("catch {::safe::interpConfigure #{name}}") == '0'
427
+ begin
428
+ ip._eval_without_enc("::safe::interpDelete #{name}")
429
+ rescue Exception
430
+ end
431
+ end
432
+ =begin
433
+ if ip._invoke('interp', 'exists', name) == '1'
434
+ begin
435
+ ip._invoke(name, 'eval', 'exit')
436
+ rescue Exception
437
+ end
438
+ end
439
+ =end
440
+ unless ip.deleted?
441
+ if ip._invoke('interp', 'exists', name) == '1'
442
+ begin
443
+ ip._invoke('interp', 'delete', name)
444
+ rescue Exception
445
+ end
446
+ end
447
+ end
448
+ }
449
+ end
450
+ end
451
+
452
+ def _receiver_eval_proc_core(safe_level, thread, cmd, *args)
453
+ begin
454
+ #ret = proc{$SAFE = safe_level; cmd.call(*args)}.call
455
+ #ret = cmd.call(safe_level, *args)
456
+ normal_ret = false
457
+ ret = catch(:IRB_EXIT) do # IRB hack
458
+ retval = cmd.call(safe_level, *args)
459
+ normal_ret = true
460
+ retval
461
+ end
462
+ unless normal_ret
463
+ # catch IRB_EXIT
464
+ exit(ret)
465
+ end
466
+ ret
467
+ rescue SystemExit => e
468
+ # delete IP
469
+ unless @interp.deleted?
470
+ @slave_ip_tbl.each{|name, subip|
471
+ _destroy_slaves_of_slaveIP(subip)
472
+ begin
473
+ # subip._eval_without_enc("foreach i [after info] {after cancel $i}")
474
+ after_ids = subip._eval_without_enc("after info")
475
+ subip._eval_without_enc("foreach i {#{after_ids}} {after cancel $i}")
476
+ rescue Exception
477
+ end
478
+ =begin
479
+ begin
480
+ subip._invoke('destroy', '.') unless subip.deleted?
481
+ rescue Exception
482
+ end
483
+ =end
484
+ # safe_base?
485
+ if @interp._eval_without_enc("catch {::safe::interpConfigure #{name}}") == '0'
486
+ begin
487
+ @interp._eval_without_enc("::safe::interpDelete #{name}")
488
+ rescue Exception
489
+ else
490
+ next if subip.deleted?
491
+ end
492
+ end
493
+ if subip.respond_to?(:safe_base?) && subip.safe_base? &&
494
+ !subip.deleted?
495
+ # do 'exit' to call the delete_hook procedure
496
+ begin
497
+ subip._eval_without_enc('exit')
498
+ rescue Exception
499
+ end
500
+ else
501
+ begin
502
+ subip.delete unless subip.deleted?
503
+ rescue Exception
504
+ end
505
+ end
506
+ }
507
+
508
+ begin
509
+ # @interp._eval_without_enc("foreach i [after info] {after cancel $i}")
510
+ after_ids = @interp._eval_without_enc("after info")
511
+ @interp._eval_without_enc("foreach i {#{after_ids}} {after cancel $i}")
512
+ rescue Exception
513
+ end
514
+ begin
515
+ @interp._invoke('destroy', '.') unless @interp.deleted?
516
+ rescue Exception
517
+ end
518
+ if @safe_base && !@interp.deleted?
519
+ # do 'exit' to call the delete_hook procedure
520
+ @interp._eval_without_enc('exit')
521
+ else
522
+ @interp.delete unless @interp.deleted?
523
+ end
524
+ end
525
+
526
+ if e.backtrace[0] =~ /^(.+?):(\d+):in `(exit|exit!|abort)'/
527
+ _check_and_return(thread, MultiTkIp_OK.new($3 == 'exit'))
528
+ else
529
+ _check_and_return(thread, MultiTkIp_OK.new(nil))
530
+ end
531
+
532
+ # if master? && !safe? && allow_ruby_exit?
533
+ if !@interp.deleted? && master? && !safe? && allow_ruby_exit?
534
+ =begin
535
+ ObjectSpace.each_object(TclTkIp){|obj|
536
+ obj.delete unless obj.deleted?
537
+ }
538
+ =end
539
+ #exit(e.status)
540
+ fail e
541
+ end
542
+ # break
543
+
544
+ rescue SecurityError => e
545
+ # in 'exit', 'exit!', and 'abort' : security error --> delete IP
546
+ if e.backtrace[0] =~ /^(.+?):(\d+):in `(exit|exit!|abort)'/
547
+ ret = ($3 == 'exit')
548
+ unless @interp.deleted?
549
+ @slave_ip_tbl.each{|name, subip|
550
+ _destroy_slaves_of_slaveIP(subip)
551
+ begin
552
+ # subip._eval_without_enc("foreach i [after info] {after cancel $i}")
553
+ after_ids = subip._eval_without_enc("after info")
554
+ subip._eval_without_enc("foreach i {#{after_ids}} {after cancel $i}")
555
+ rescue Exception
556
+ end
557
+ =begin
558
+ begin
559
+ subip._invoke('destroy', '.') unless subip.deleted?
560
+ rescue Exception
561
+ end
562
+ =end
563
+ # safe_base?
564
+ if @interp._eval_without_enc("catch {::safe::interpConfigure #{name}}") == '0'
565
+ begin
566
+ @interp._eval_without_enc("::safe::interpDelete #{name}")
567
+ rescue Exception
568
+ else
569
+ next if subip.deleted?
570
+ end
571
+ end
572
+ if subip.respond_to?(:safe_base?) && subip.safe_base? &&
573
+ !subip.deleted?
574
+ # do 'exit' to call the delete_hook procedure
575
+ begin
576
+ subip._eval_without_enc('exit')
577
+ rescue Exception
578
+ end
579
+ else
580
+ begin
581
+ subip.delete unless subip.deleted?
582
+ rescue Exception
583
+ end
584
+ end
585
+ }
586
+
587
+ begin
588
+ # @interp._eval_without_enc("foreach i [after info] {after cancel $i}")
589
+ after_ids = @interp._eval_without_enc("after info")
590
+ @interp._eval_without_enc("foreach i {#{after_ids}} {after cancel $i}")
591
+ rescue Exception
592
+ end
593
+ =begin
594
+ begin
595
+ @interp._invoke('destroy', '.') unless @interp.deleted?
596
+ rescue Exception
597
+ end
598
+ =end
599
+ if @safe_base && !@interp.deleted?
600
+ # do 'exit' to call the delete_hook procedure
601
+ @interp._eval_without_enc('exit')
602
+ else
603
+ @interp.delete unless @interp.deleted?
604
+ end
605
+ end
606
+ _check_and_return(thread, MultiTkIp_OK.new(ret))
607
+ # break
608
+
609
+ else
610
+ # raise security error
611
+ _check_and_return(thread, e)
612
+ end
613
+
614
+ rescue Exception => e
615
+ # raise exception
616
+ begin
617
+ bt = _toUTF8(e.backtrace.join("\n"))
618
+ if MultiTkIp::WITH_ENCODING
619
+ bt.force_encoding('utf-8')
620
+ else
621
+ bt.instance_variable_set(:@encoding, 'utf-8')
622
+ end
623
+ rescue Exception
624
+ bt = e.backtrace.join("\n")
625
+ end
626
+ begin
627
+ @interp._set_global_var('errorInfo', bt)
628
+ rescue Exception
629
+ end
630
+ _check_and_return(thread, e)
631
+
632
+ else
633
+ # no exception
634
+ _check_and_return(thread, MultiTkIp_OK.new(ret))
635
+ end
636
+ end
637
+
638
+ def _receiver_eval_proc(last_thread, safe_level, thread, cmd, *args)
639
+ if thread
640
+ Thread.new{
641
+ last_thread.join if last_thread
642
+ unless @interp.deleted?
643
+ _receiver_eval_proc_core(safe_level, thread, cmd, *args)
644
+ end
645
+ }
646
+ else
647
+ Thread.new{
648
+ unless @interp.deleted?
649
+ _receiver_eval_proc_core(safe_level, thread, cmd, *args)
650
+ end
651
+ }
652
+ last_thread
653
+ end
654
+ end
655
+
656
+ private :_receiver_eval_proc, :_receiver_eval_proc_core
657
+
658
+ def _receiver_mainloop(check_root)
659
+ if @evloop_thread[0] && @evloop_thread[0].alive?
660
+ @evloop_thread[0]
661
+ else
662
+ @evloop_thread[0] = Thread.new{
663
+ while !@interp.deleted?
664
+ #if check_root
665
+ # inf = @interp._invoke_without_enc('info', 'command', '.')
666
+ # break if !inf.kind_of?(String) || inf != '.'
667
+ #end
668
+ break if check_root && !@interp.has_mainwindow?
669
+ sleep 0.5
670
+ end
671
+ }
672
+ @evloop_thread[0]
673
+ end
674
+ end
675
+
676
+ def _create_receiver_and_watchdog(lvl = $SAFE)
677
+ lvl = $SAFE if lvl < $SAFE
678
+
679
+ # command-procedures receiver
680
+ receiver = Thread.new(lvl){|safe_level|
681
+ last_thread = {}
682
+
683
+ loop do
684
+ break if @interp.deleted?
685
+ thread, cmd, *args = @cmd_queue.deq
686
+ if thread == @system
687
+ # control command
688
+ case cmd
689
+ when 'set_safe_level'
690
+ begin
691
+ safe_level = args[0] if safe_level < args[0]
692
+ rescue Exception
693
+ end
694
+ when 'call_mainloop'
695
+ thread = args.shift
696
+ _check_and_return(thread,
697
+ MultiTkIp_OK.new(_receiver_mainloop(*args)))
698
+ else
699
+ # ignore
700
+ end
701
+
702
+ else
703
+ # procedure
704
+ last_thread[thread] = _receiver_eval_proc(last_thread[thread],
705
+ safe_level, thread,
706
+ cmd, *args)
707
+ end
708
+ end
709
+ }
710
+
711
+ # watchdog of receiver
712
+ watchdog = Thread.new{
713
+ begin
714
+ loop do
715
+ sleep 1
716
+ if @interp.deleted?
717
+ receiver.kill
718
+ @cmd_queue.close
719
+ end
720
+ break unless receiver.alive?
721
+ end
722
+ rescue Exception
723
+ # ignore all kind of Exception
724
+ end
725
+
726
+ # receiver is dead
727
+ retry_count = 3
728
+ loop do
729
+ Thread.pass
730
+ begin
731
+ thread, cmd, *args = @cmd_queue.deq(true) # non-block
732
+ rescue ThreadError
733
+ # queue is empty
734
+ retry_count -= 1
735
+ break if retry_count <= 0
736
+ sleep 0.5
737
+ retry
738
+ end
739
+ next unless thread
740
+ if thread.alive?
741
+ if @interp.deleted?
742
+ thread.raise RuntimeError, 'the interpreter is already deleted'
743
+ else
744
+ thread.raise RuntimeError,
745
+ 'the interpreter no longer receives command procedures'
746
+ end
747
+ end
748
+ end
749
+ }
750
+
751
+ # return threads
752
+ [receiver, watchdog]
753
+ end
754
+ private :_check_and_return, :_create_receiver_and_watchdog
755
+
756
+ ######################################
757
+
758
+ unless self.const_defined? :RUN_EVENTLOOP_ON_MAIN_THREAD
759
+ ### Ruby 1.9 !!!!!!!!!!!!!!!!!!!!!!!!!!
760
+ RUN_EVENTLOOP_ON_MAIN_THREAD = false
761
+ end
762
+
763
+ if self.const_defined? :DEFAULT_MASTER_NAME
764
+ name = DEFAULT_MASTER_NAME.to_s
765
+ else
766
+ name = nil
767
+ end
768
+ if self.const_defined?(:DEFAULT_MASTER_OPTS) &&
769
+ DEFAULT_MASTER_OPTS.kind_of?(Hash)
770
+ keys = DEFAULT_MASTER_OPTS
771
+ else
772
+ keys = {}
773
+ end
774
+
775
+ @@DEFAULT_MASTER = self.allocate
776
+ @@DEFAULT_MASTER.instance_eval{
777
+ @tk_windows = TkUtil.untrust({})
778
+
779
+ @tk_table_list = TkUtil.untrust([])
780
+
781
+ @slave_ip_tbl = TkUtil.untrust({})
782
+
783
+ @slave_ip_top = TkUtil.untrust({})
784
+
785
+ @evloop_thread = TkUtil.untrust([])
786
+
787
+ unless keys.kind_of? Hash
788
+ fail ArgumentError, "expecting a Hash object for the 2nd argument"
789
+ end
790
+
791
+ if !WITH_RUBY_VM || RUN_EVENTLOOP_ON_MAIN_THREAD ### check Ruby 1.9 !!!!!!!
792
+ @interp = TclTkIp.new(name, _keys2opts(keys))
793
+ else ### Ruby 1.9 !!!!!!!!!!!
794
+ @interp_thread = Thread.new{
795
+ current = Thread.current
796
+ begin
797
+ current[:interp] = interp = TclTkIp.new(name, _keys2opts(keys))
798
+ rescue e
799
+ current[:interp] = e
800
+ raise e
801
+ end
802
+ #sleep
803
+ current[:mutex] = mutex = Mutex.new
804
+ current[:root_check] = cond_var = ConditionVariable.new
805
+
806
+ status = [nil]
807
+ def status.value
808
+ self[0]
809
+ end
810
+ def status.value=(val)
811
+ self[0] = val
812
+ end
813
+ current[:status] = status
814
+
815
+ begin
816
+ begin
817
+ #TclTkLib.mainloop_abort_on_exception = false
818
+ #Thread.current[:status].value = TclTkLib.mainloop(true)
819
+ interp.mainloop_abort_on_exception = true
820
+ current[:status].value = interp.mainloop(true)
821
+ rescue SystemExit=>e
822
+ current[:status].value = e
823
+ rescue Exception=>e
824
+ current[:status].value = e
825
+ retry if interp.has_mainwindow?
826
+ ensure
827
+ mutex.synchronize{ cond_var.broadcast }
828
+ end
829
+
830
+ #Thread.current[:status].value = TclTkLib.mainloop(false)
831
+ current[:status].value = interp.mainloop(false)
832
+
833
+ ensure
834
+ # interp must be deleted before the thread for interp is dead.
835
+ # If not, raise Tcl_Panic on Tcl_AsyncDelete because async handler
836
+ # deleted by the wrong thread.
837
+ interp.delete
838
+ end
839
+ }
840
+ until @interp_thread[:interp]
841
+ Thread.pass
842
+ end
843
+ # INTERP_THREAD.run
844
+ @interp = @interp_thread[:interp]
845
+
846
+ def self.mainloop(check_root = true)
847
+ begin
848
+ TclTkLib.set_eventloop_window_mode(true)
849
+ @interp_thread.value
850
+ ensure
851
+ TclTkLib.set_eventloop_window_mode(false)
852
+ end
853
+ end
854
+ end
855
+
856
+ @interp.instance_eval{
857
+ @force_default_encoding ||= TkUtil.untrust([false])
858
+ @encoding ||= TkUtil.untrust([nil])
859
+ def @encoding.to_s; self.join(nil); end
860
+ }
861
+
862
+ @ip_name = nil
863
+
864
+ @callback_status = TkUtil.untrust([])
865
+
866
+ @system = Object.new
867
+
868
+ @wait_on_mainloop = TkUtil.untrust([true, 0])
869
+
870
+ @threadgroup = Thread.current.group
871
+
872
+ @safe_base = false
873
+
874
+ @safe_level = [$SAFE]
875
+
876
+ @cmd_queue = MultiTkIp::Command_Queue.new(@interp)
877
+
878
+ @cmd_receiver, @receiver_watchdog = _create_receiver_and_watchdog(@safe_level[0])
879
+
880
+ @threadgroup.add @cmd_receiver
881
+ @threadgroup.add @receiver_watchdog
882
+
883
+ # NOT enclose @threadgroup for @@DEFAULT_MASTER
884
+
885
+ @@IP_TABLE[ThreadGroup::Default] = self
886
+ @@IP_TABLE[@threadgroup] = self
887
+
888
+ #################################
889
+
890
+ @pseudo_toplevel = [false, nil]
891
+
892
+ def self.__pseudo_toplevel
893
+ Thread.current.group == ThreadGroup::Default &&
894
+ MultiTkIp.__getip == @@DEFAULT_MASTER &&
895
+ self.__pseudo_toplevel_evaluable? && @pseudo_toplevel[1]
896
+ end
897
+
898
+ def self.__pseudo_toplevel=(m)
899
+ unless (Thread.current.group == ThreadGroup::Default &&
900
+ MultiTkIp.__getip == @@DEFAULT_MASTER)
901
+ fail SecurityError, "no permission to manipulate"
902
+ end
903
+
904
+ # if m.kind_of?(Module) && m.respond_to?(:pseudo_toplevel_evaluable?)
905
+ if m.respond_to?(:pseudo_toplevel_evaluable?)
906
+ @pseudo_toplevel[0] = true
907
+ @pseudo_toplevel[1] = m
908
+ else
909
+ fail ArgumentError, 'fail to set pseudo-toplevel'
910
+ end
911
+ self
912
+ end
913
+
914
+ def self.__pseudo_toplevel_evaluable?
915
+ begin
916
+ @pseudo_toplevel[0] && @pseudo_toplevel[1].pseudo_toplevel_evaluable?
917
+ rescue Exception
918
+ false
919
+ end
920
+ end
921
+
922
+ def self.__pseudo_toplevel_evaluable=(mode)
923
+ unless (Thread.current.group == ThreadGroup::Default &&
924
+ MultiTkIp.__getip == @@DEFAULT_MASTER)
925
+ fail SecurityError, "no permission to manipulate"
926
+ end
927
+
928
+ @pseudo_toplevel[0] = (mode)? true: false
929
+ end
930
+
931
+ #################################
932
+
933
+ @assign_request = Class.new(Exception){
934
+ def self.new(target, ret)
935
+ obj = super()
936
+ obj.target = target
937
+ obj.ret = ret
938
+ obj
939
+ end
940
+ attr_accessor :target, :ret
941
+ }
942
+
943
+ @assign_thread = Thread.new{
944
+ loop do
945
+ begin
946
+ Thread.stop
947
+ rescue @assign_request=>req
948
+ begin
949
+ req.ret[0] = req.target.instance_eval{
950
+ @cmd_receiver, @receiver_watchdog =
951
+ _create_receiver_and_watchdog(@safe_level[0])
952
+ @threadgroup.add @cmd_receiver
953
+ @threadgroup.add @receiver_watchdog
954
+ @threadgroup.enclose
955
+ true
956
+ }
957
+ rescue Exception=>e
958
+ begin
959
+ req.ret[0] = e
960
+ rescue Exception
961
+ # ignore
962
+ end
963
+ end
964
+ rescue Exception
965
+ # ignore
966
+ end
967
+ end
968
+ }
969
+
970
+ def self.assign_receiver_and_watchdog(target)
971
+ ret = [nil]
972
+ @assign_thread.raise(@assign_request.new(target, ret))
973
+ while ret[0] == nil
974
+ unless @assign_thread.alive?
975
+ raise RuntimeError, 'lost the thread to assign a receiver and a watchdog thread'
976
+ end
977
+ end
978
+ if ret[0].kind_of?(Exception)
979
+ raise ret[0]
980
+ else
981
+ ret[0]
982
+ end
983
+ end
984
+
985
+ #################################
986
+
987
+ @init_ip_env_queue = Queue.new
988
+ Thread.new{
989
+ current = Thread.current
990
+ loop {
991
+ mtx, cond, ret, table, script = @init_ip_env_queue.deq
992
+ begin
993
+ ret[0] = table.each{|tg, ip| ip._init_ip_env(script) }
994
+ rescue Exception => e
995
+ ret[0] = e
996
+ ensure
997
+ mtx.synchronize{ cond.signal }
998
+ end
999
+ mtx = cond = ret = table = script = nil # clear variables for GC
1000
+ }
1001
+ }
1002
+
1003
+ def self.__init_ip_env__(table, script)
1004
+ ret = []
1005
+ mtx = (Thread.current[:MultiTk_ip_Mutex] ||= Mutex.new)
1006
+ cond = (Thread.current[:MultiTk_ip_CondVar] ||= ConditionVariable.new)
1007
+ mtx.synchronize{
1008
+ @init_ip_env_queue.enq([mtx, cond, ret, table, script])
1009
+ cond.wait(mtx)
1010
+ }
1011
+ if ret[0].kind_of?(Exception)
1012
+ raise ret[0]
1013
+ else
1014
+ ret[0]
1015
+ end
1016
+ end
1017
+
1018
+ #################################
1019
+
1020
+ class << self
1021
+ undef :instance_eval
1022
+ end
1023
+ }
1024
+
1025
+ @@DEFAULT_MASTER.freeze # defend against modification
1026
+
1027
+ ######################################
1028
+
1029
+ def self.inherited(subclass)
1030
+ # trust if on ThreadGroup::Default or @@DEFAULT_MASTER's ThreadGroup
1031
+ if @@IP_TABLE[Thread.current.group] == @@DEFAULT_MASTER
1032
+ begin
1033
+ class << subclass
1034
+ self.methods.each{|m|
1035
+ name = m.to_s
1036
+ begin
1037
+ unless name == '__id__' || name == '__send__' || name == 'freeze'
1038
+ undef_method(m)
1039
+ end
1040
+ rescue Exception
1041
+ # ignore all exceptions
1042
+ end
1043
+ }
1044
+ end
1045
+ ensure
1046
+ subclass.freeze
1047
+ fail SecurityError,
1048
+ "cannot create subclass of MultiTkIp on a untrusted ThreadGroup"
1049
+ end
1050
+ end
1051
+ end
1052
+
1053
+ ######################################
1054
+
1055
+ @@SAFE_OPT_LIST = [
1056
+ 'accessPath'.freeze,
1057
+ 'statics'.freeze,
1058
+ 'nested'.freeze,
1059
+ 'deleteHook'.freeze
1060
+ ].freeze
1061
+
1062
+ def _parse_slaveopts(keys)
1063
+ name = nil
1064
+ safe = false
1065
+ safe_opts = {}
1066
+ tk_opts = {}
1067
+
1068
+ keys.each{|k,v|
1069
+ k_str = k.to_s
1070
+ if k_str == 'name'
1071
+ name = v
1072
+ elsif k_str == 'safe'
1073
+ safe = v
1074
+ elsif @@SAFE_OPT_LIST.member?(k_str)
1075
+ safe_opts[k_str] = v
1076
+ else
1077
+ tk_opts[k_str] = v
1078
+ end
1079
+ }
1080
+
1081
+ if keys['without_tk'] || keys[:without_tk]
1082
+ [name, safe, safe_opts, nil]
1083
+ else
1084
+ [name, safe, safe_opts, tk_opts]
1085
+ end
1086
+ end
1087
+ private :_parse_slaveopts
1088
+
1089
+ def _create_slave_ip_name
1090
+ @@SLAVE_IP_ID.mutex.synchronize{
1091
+ name = @@SLAVE_IP_ID.join('')
1092
+ @@SLAVE_IP_ID[1].succ!
1093
+ name.freeze
1094
+ }
1095
+ end
1096
+ private :_create_slave_ip_name
1097
+
1098
+ ######################################
1099
+
1100
+ def __check_safetk_optkeys(optkeys)
1101
+ # based on 'safetk.tcl'
1102
+ new_keys = {}
1103
+ optkeys.each{|k,v| new_keys[k.to_s] = v}
1104
+
1105
+ # check 'display'
1106
+ if !new_keys.key?('display')
1107
+ begin
1108
+ #new_keys['display'] = @interp._invoke('winfo screen .')
1109
+ new_keys['display'] = @interp._invoke('winfo', 'screen', '.')
1110
+ rescue
1111
+ if ENV[DISPLAY]
1112
+ new_keys['display'] = ENV[DISPLAY]
1113
+ elsif !new_keys.key?('use')
1114
+ warn "Warning: no screen info or ENV[DISPLAY], so use ':0.0'"
1115
+ new_keys['display'] = ':0.0'
1116
+ end
1117
+ end
1118
+ end
1119
+
1120
+ # check 'use'
1121
+ if new_keys.key?('use')
1122
+ # given 'use'
1123
+ case new_keys['use']
1124
+ when TkWindow
1125
+ new_keys['use'] = TkWinfo.id(new_keys['use'])
1126
+ #assoc_display = @interp._eval('winfo screen .')
1127
+ assoc_display = @interp._invoke('winfo', 'screen', '.')
1128
+ when /^\..*/
1129
+ new_keys['use'] = @interp._invoke('winfo', 'id', new_keys['use'])
1130
+ assoc_display = @interp._invoke('winfo', 'screen', new_keys['use'])
1131
+ else
1132
+ begin
1133
+ pathname = @interp._invoke('winfo', 'pathname', new_keys['use'])
1134
+ assoc_display = @interp._invoke('winfo', 'screen', pathname)
1135
+ rescue
1136
+ assoc_display = new_keys['display']
1137
+ end
1138
+ end
1139
+
1140
+ # match display?
1141
+ if assoc_display != new_keys['display']
1142
+ if optkeys.key?(:display) || optkeys.key?('display')
1143
+ fail RuntimeError,
1144
+ "conflicting 'display'=>#{new_keys['display']} " +
1145
+ "and display '#{assoc_display}' on 'use'=>#{new_keys['use']}"
1146
+ else
1147
+ new_keys['display'] = assoc_display
1148
+ end
1149
+ end
1150
+ end
1151
+
1152
+ # return
1153
+ new_keys
1154
+ end
1155
+ private :__check_safetk_optkeys
1156
+
1157
+ def __create_safetk_frame(slave_ip, slave_name, app_name, keys)
1158
+ # display option is used by ::safe::loadTk
1159
+ loadTk_keys = {}
1160
+ loadTk_keys['display'] = keys['display']
1161
+ dup_keys = keys.dup
1162
+
1163
+ # keys for toplevel : allow followings
1164
+ toplevel_keys = {}
1165
+ ['height', 'width', 'background', 'menu'].each{|k|
1166
+ toplevel_keys[k] = dup_keys.delete(k) if dup_keys.key?(k)
1167
+ }
1168
+ toplevel_keys['classname'] = 'SafeTk'
1169
+ toplevel_keys['screen'] = dup_keys.delete('display')
1170
+
1171
+ # other keys used by pack option of container frame
1172
+
1173
+ # create toplevel widget
1174
+ begin
1175
+ top = TkToplevel.new(toplevel_keys)
1176
+ rescue NameError => e
1177
+ fail e unless @interp.safe?
1178
+ fail SecurityError, "unable create toplevel on the safe interpreter"
1179
+ end
1180
+ msg = "Untrusted Ruby/Tk applet (#{slave_name})"
1181
+ if app_name.kind_of?(String)
1182
+ top.title "#{app_name} (#{slave_name})"
1183
+ else
1184
+ top.title msg
1185
+ end
1186
+
1187
+ # procedure to delete slave interpreter
1188
+ slave_delete_proc = proc{
1189
+ unless slave_ip.deleted?
1190
+ #if slave_ip._invoke('info', 'command', '.') != ""
1191
+ # slave_ip._invoke('destroy', '.')
1192
+ #end
1193
+ #slave_ip.delete
1194
+ slave_ip._eval_without_enc('exit')
1195
+ end
1196
+ begin
1197
+ top.destroy if top.winfo_exist?
1198
+ rescue
1199
+ # ignore
1200
+ end
1201
+ }
1202
+ tag = TkBindTag.new.bind('Destroy', slave_delete_proc)
1203
+
1204
+ top.bindtags = top.bindtags.unshift(tag)
1205
+
1206
+ # create control frame
1207
+ TkFrame.new(top, :bg=>'red', :borderwidth=>3, :relief=>'ridge') {|fc|
1208
+ fc.bindtags = fc.bindtags.unshift(tag)
1209
+
1210
+ TkFrame.new(fc, :bd=>0){|f|
1211
+ TkButton.new(f,
1212
+ :text=>'Delete', :bd=>1, :padx=>2, :pady=>0,
1213
+ :highlightthickness=>0, :command=>slave_delete_proc
1214
+ ).pack(:side=>:right, :fill=>:both)
1215
+ f.pack(:side=>:right, :fill=>:both, :expand=>true)
1216
+ }
1217
+
1218
+ TkLabel.new(fc, :text=>msg, :padx=>2, :pady=>0,
1219
+ :anchor=>:w).pack(:side=>:left, :fill=>:both, :expand=>true)
1220
+
1221
+ fc.pack(:side=>:bottom, :fill=>:x)
1222
+ }
1223
+
1224
+ # container frame for slave interpreter
1225
+ dup_keys['fill'] = :both unless dup_keys.key?('fill')
1226
+ dup_keys['expand'] = true unless dup_keys.key?('expand')
1227
+ c = TkFrame.new(top, :container=>true).pack(dup_keys)
1228
+ c.bind('Destroy', proc{top.destroy})
1229
+
1230
+ # return keys
1231
+ loadTk_keys['use'] = TkWinfo.id(c)
1232
+ [loadTk_keys, top.path]
1233
+ end
1234
+ private :__create_safetk_frame
1235
+
1236
+ def __create_safe_slave_obj(safe_opts, app_name, tk_opts)
1237
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
1238
+
1239
+ # safe interpreter
1240
+ ip_name = _create_slave_ip_name
1241
+ slave_ip = @interp.create_slave(ip_name, true)
1242
+ slave_ip.instance_eval{
1243
+ @force_default_encoding ||= TkUtil.untrust([false])
1244
+ @encoding ||= TkUtil.untrust([nil])
1245
+ def @encoding.to_s; self.join(nil); end
1246
+ }
1247
+ @slave_ip_tbl[ip_name] = slave_ip
1248
+ def slave_ip.safe_base?
1249
+ true
1250
+ end
1251
+
1252
+ @interp._eval("::safe::interpInit #{ip_name}")
1253
+
1254
+ slave_ip._invoke('set', 'argv0', app_name) if app_name.kind_of?(String)
1255
+
1256
+ if tk_opts
1257
+ tk_opts = __check_safetk_optkeys(tk_opts)
1258
+ if tk_opts.key?('use')
1259
+ @slave_ip_top[ip_name] = ''
1260
+ else
1261
+ tk_opts, top_path = __create_safetk_frame(slave_ip, ip_name, app_name,
1262
+ tk_opts)
1263
+ @slave_ip_top[ip_name] = top_path
1264
+ end
1265
+ @interp._eval("::safe::loadTk #{ip_name} #{_keys2opts(tk_opts)}")
1266
+ @interp._invoke('__replace_slave_tk_commands__', ip_name)
1267
+ else
1268
+ @slave_ip_top[ip_name] = nil
1269
+ end
1270
+
1271
+ if safe_opts.key?('deleteHook') || safe_opts.key?(:deleteHook)
1272
+ @interp._eval("::safe::interpConfigure #{ip_name} " +
1273
+ _keys2opts(safe_opts))
1274
+ else
1275
+ @interp._eval("::safe::interpConfigure #{ip_name} " +
1276
+ _keys2opts(safe_opts) + '-deleteHook {' +
1277
+ TkComm._get_eval_string(proc{|slave|
1278
+ self._default_delete_hook(slave)
1279
+ }) + '}')
1280
+ end
1281
+
1282
+ [slave_ip, ip_name]
1283
+ end
1284
+
1285
+ def __create_trusted_slave_obj(name, keys)
1286
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
1287
+
1288
+ ip_name = _create_slave_ip_name
1289
+ slave_ip = @interp.create_slave(ip_name, false)
1290
+ slave_ip.instance_eval{
1291
+ @force_default_encoding ||= TkUtil.untrust([false])
1292
+ @encoding ||= TkUtil.untrust([nil])
1293
+ def @encoding.to_s; self.join(nil); end
1294
+ }
1295
+ slave_ip._invoke('set', 'argv0', name) if name.kind_of?(String)
1296
+ slave_ip._invoke('set', 'argv', _keys2opts(keys))
1297
+ @interp._invoke('load', '', 'Tk', ip_name)
1298
+ @interp._invoke('__replace_slave_tk_commands__', ip_name)
1299
+ @slave_ip_tbl[ip_name] = slave_ip
1300
+ [slave_ip, ip_name]
1301
+ end
1302
+
1303
+ ######################################
1304
+
1305
+ def _create_slave_object(keys={})
1306
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
1307
+
1308
+ ip = MultiTkIp.new_slave(self, keys={})
1309
+ @slave_ip_tbl[ip.name] = ip
1310
+ end
1311
+
1312
+ ######################################
1313
+
1314
+ def initialize(master, safeip=true, keys={})
1315
+ if $SAFE >= 4
1316
+ fail SecurityError, "cannot create a new interpreter at level #{$SAFE}"
1317
+ end
1318
+
1319
+ if safeip == nil && $SAFE >= 2
1320
+ fail SecurityError, "cannot create a master-ip at level #{$SAFE}"
1321
+ end
1322
+
1323
+ if master.deleted? && safeip == nil
1324
+ fail RuntimeError, "cannot create a slave of a deleted interpreter"
1325
+ end
1326
+
1327
+ if !master.deleted? && !master.master? && master.safe?
1328
+ fail SecurityError, "safe-slave-ip cannot create a new interpreter"
1329
+ end
1330
+
1331
+ if safeip == nil && !master.master?
1332
+ fail SecurityError, "slave-ip cannot create a master-ip"
1333
+ end
1334
+
1335
+ unless keys.kind_of? Hash
1336
+ fail ArgumentError, "expecting a Hash object for the 2nd argument"
1337
+ end
1338
+
1339
+ @tk_windows = {}
1340
+ @tk_table_list = []
1341
+ @slave_ip_tbl = {}
1342
+ @slave_ip_top = {}
1343
+ @cb_error_proc = []
1344
+ @evloop_thread = []
1345
+
1346
+ TkUtil.untrust(@tk_windows) unless @tk_windows.tainted?
1347
+ TkUtil.untrust(@tk_table_list) unless @tk_table_list.tainted?
1348
+ TkUtil.untrust(@slave_ip_tbl) unless @slave_ip_tbl.tainted?
1349
+ TkUtil.untrust(@slave_ip_top) unless @slave_ip_top.tainted?
1350
+ TkUtil.untrust(@cb_error_proc) unless @cb_error_proc.tainted?
1351
+ TkUtil.untrust(@evloop_thread) unless @evloop_thread.tainted?
1352
+
1353
+ @callback_status = []
1354
+
1355
+ name, safe, safe_opts, tk_opts = _parse_slaveopts(keys)
1356
+
1357
+ safe = 4 if safe && !safe.kind_of?(Fixnum)
1358
+
1359
+ @safe_base = false
1360
+
1361
+ if safeip == nil
1362
+ # create master-ip
1363
+ unless WITH_RUBY_VM
1364
+ @interp = TclTkIp.new(name, _keys2opts(tk_opts))
1365
+ @interp.instance_eval{
1366
+ @force_default_encoding ||= TkUtil.untrust([false])
1367
+ @encoding ||= TkUtil.untrust([nil])
1368
+ def @encoding.to_s; self.join(nil); end
1369
+ }
1370
+
1371
+ else ### Ruby 1.9 !!!!!!!!!!!
1372
+ =begin
1373
+ @interp_thread = Thread.new{
1374
+ Thread.current[:interp] = interp = TclTkIp.new(name, _keys2opts(tk_opts))
1375
+ interp.instance_eval{
1376
+ @force_default_encoding ||= TkUtil.untrust([false])
1377
+ @encoding ||= TkUtil.untrust([nil])
1378
+ def @encoding.to_s; self.join(nil); end
1379
+ }
1380
+
1381
+ #sleep
1382
+ TclTkLib.mainloop(true)
1383
+ }
1384
+ until @interp_thread[:interp]
1385
+ Thread.pass
1386
+ end
1387
+ # INTERP_THREAD.run
1388
+ @interp = @interp_thread[:interp]
1389
+ =end
1390
+ @interp_thread = Thread.new{
1391
+ current = Thread.current
1392
+ begin
1393
+ current[:interp] = interp = TclTkIp.new(name, _keys2opts(tk_opts))
1394
+ rescue e
1395
+ current[:interp] = e
1396
+ raise e
1397
+ end
1398
+ #sleep
1399
+ #TclTkLib.mainloop(true)
1400
+ current[:mutex] = mutex = Mutex.new
1401
+ current[:root_check] = cond_ver = ConditionVariable.new
1402
+
1403
+ status = [nil]
1404
+ def status.value
1405
+ self[0]
1406
+ end
1407
+ def status.value=(val)
1408
+ self[0] = val
1409
+ end
1410
+ current[:status] = status
1411
+
1412
+ begin
1413
+ begin
1414
+ current[:status].value = interp.mainloop(true)
1415
+ rescue SystemExit=>e
1416
+ current[:status].value = e
1417
+ rescue Exception=>e
1418
+ current[:status].value = e
1419
+ retry if interp.has_mainwindow?
1420
+ ensure
1421
+ mutex.synchronize{ cond_var.broadcast }
1422
+ end
1423
+ current[:status].value = interp.mainloop(false)
1424
+ ensure
1425
+ interp.delete
1426
+ end
1427
+ }
1428
+ until @interp_thread[:interp]
1429
+ Thread.pass
1430
+ end
1431
+ # INTERP_THREAD.run
1432
+ @interp = @interp_thread[:interp]
1433
+
1434
+ @evloop_thread[0] = @interp_thread
1435
+
1436
+ def self.mainloop(check_root = true)
1437
+ begin
1438
+ TclTkLib.set_eventloop_window_mode(true)
1439
+ @interp_thread.value
1440
+ ensure
1441
+ TclTkLib.set_eventloop_window_mode(false)
1442
+ end
1443
+ end
1444
+ end
1445
+
1446
+ @interp.instance_eval{
1447
+ @force_default_encoding ||= TkUtil.untrust([false])
1448
+ @encoding ||= TkUtil.untrust([nil])
1449
+ def @encoding.to_s; self.join(nil); end
1450
+ }
1451
+
1452
+ @ip_name = nil
1453
+
1454
+ if safe
1455
+ safe = $SAFE if safe < $SAFE
1456
+ @safe_level = [safe]
1457
+ else
1458
+ @safe_level = [$SAFE]
1459
+ end
1460
+
1461
+ else
1462
+ # create slave-ip
1463
+ if safeip || master.safe?
1464
+ @safe_base = true
1465
+ @interp, @ip_name = master.__create_safe_slave_obj(safe_opts,
1466
+ name, tk_opts)
1467
+ # @interp_thread = nil if RUBY_VERSION < '1.9.0' ### !!!!!!!!!!!
1468
+ @interp_thread = nil unless WITH_RUBY_VM ### Ruby 1.9 !!!!!!!!!!!
1469
+ if safe
1470
+ safe = master.safe_level if safe < master.safe_level
1471
+ @safe_level = [safe]
1472
+ else
1473
+ @safe_level = [4]
1474
+ end
1475
+ else
1476
+ @interp, @ip_name = master.__create_trusted_slave_obj(name, tk_opts)
1477
+ # @interp_thread = nil if RUBY_VERSION < '1.9.0' ### !!!!!!!!!!!
1478
+ @interp_thread = nil unless WITH_RUBY_VM ### Ruby 1.9 !!!!!!!!!!!
1479
+ if safe
1480
+ safe = master.safe_level if safe < master.safe_level
1481
+ @safe_level = [safe]
1482
+ else
1483
+ @safe_level = [master.safe_level]
1484
+ end
1485
+ end
1486
+ @set_alias_proc = proc{|name|
1487
+ master._invoke('interp', 'alias', @ip_name, name, '', name)
1488
+ }.freeze
1489
+ end
1490
+
1491
+ @system = Object.new
1492
+
1493
+ @wait_on_mainloop = TkUtil.untrust([true, 0])
1494
+ # @wait_on_mainloop = TkUtil.untrust([false, 0])
1495
+
1496
+ @threadgroup = ThreadGroup.new
1497
+
1498
+ @pseudo_toplevel = [false, nil]
1499
+
1500
+ @cmd_queue = MultiTkIp::Command_Queue.new(@interp)
1501
+
1502
+ =begin
1503
+ @cmd_receiver, @receiver_watchdog = _create_receiver_and_watchdog(@safe_level[0])
1504
+
1505
+ @threadgroup.add @cmd_receiver
1506
+ @threadgroup.add @receiver_watchdog
1507
+
1508
+ @threadgroup.enclose
1509
+ =end
1510
+ @@DEFAULT_MASTER.assign_receiver_and_watchdog(self)
1511
+
1512
+ @@IP_TABLE[@threadgroup] = self
1513
+ @@TK_TABLE_LIST.size.times{
1514
+ @tk_table_list << TkUtil.untrust({})
1515
+ }
1516
+ _init_ip_internal(@@INIT_IP_ENV, @@ADD_TK_PROCS)
1517
+
1518
+ class << self
1519
+ undef :instance_eval
1520
+ end
1521
+
1522
+ # dummy call for initialization
1523
+ self.eval_proc{ Tk.tk_call('set', 'tcl_patchLevel') }
1524
+
1525
+ self.freeze # defend against modification
1526
+ end
1527
+
1528
+ ######################################
1529
+
1530
+ def _default_delete_hook(slave)
1531
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
1532
+ @slave_ip_tbl.delete(slave)
1533
+ top = @slave_ip_top.delete(slave)
1534
+ if top.kind_of?(String)
1535
+ # call default hook of safetk.tcl (ignore exceptions)
1536
+ if top == ''
1537
+ begin
1538
+ @interp._eval("::safe::disallowTk #{slave}")
1539
+ rescue
1540
+ warn("Waring: fail to call '::safe::disallowTk'") if $DEBUG
1541
+ end
1542
+ else # toplevel path
1543
+ begin
1544
+ @interp._eval("::safe::tkDelete {} #{top} #{slave}")
1545
+ rescue
1546
+ warn("Waring: fail to call '::safe::tkDelete'") if $DEBUG
1547
+ begin
1548
+ @interp._eval("destroy #{top}")
1549
+ rescue
1550
+ warn("Waring: fail to destroy toplevel") if $DEBUG
1551
+ end
1552
+ end
1553
+ end
1554
+ end
1555
+ end
1556
+
1557
+ end
1558
+
1559
+
1560
+ # get target IP
1561
+ class MultiTkIp
1562
+ @@CALLBACK_SUBTHREAD = Class.new(Thread){
1563
+ def self.new(interp, &blk)
1564
+ super(interp){|ip| Thread.current[:callback_ip] = ip; blk.call}
1565
+ end
1566
+
1567
+ @table = TkUtil.untrust(Hash.new{|h,k| h[k] = TkUtil.untrust([])})
1568
+ def self.table
1569
+ @table
1570
+ end
1571
+ }
1572
+
1573
+ def self._ip_id_
1574
+ __getip._ip_id_
1575
+ end
1576
+ def _ip_id_
1577
+ # for RemoteTkIp
1578
+ ''
1579
+ end
1580
+
1581
+ def self.__getip
1582
+ current = Thread.current
1583
+ if current.kind_of?(@@CALLBACK_SUBTHREAD)
1584
+ return current[:callback_ip]
1585
+ end
1586
+ if TclTkLib.mainloop_thread? != false && current[:callback_ip]
1587
+ return current[:callback_ip]
1588
+ end
1589
+ if current.group == ThreadGroup::Default
1590
+ @@DEFAULT_MASTER
1591
+ else
1592
+ ip = @@IP_TABLE[current.group]
1593
+ unless ip
1594
+ fail SecurityError,
1595
+ "cannot call Tk methods on #{Thread.current.inspect}"
1596
+ end
1597
+ ip
1598
+ end
1599
+ end
1600
+ end
1601
+
1602
+
1603
+ # aliases of constructor
1604
+ class << MultiTkIp
1605
+ alias __new new
1606
+ private :__new
1607
+
1608
+ def new_master(safe=nil, keys={}, &blk)
1609
+ if MultiTkIp::WITH_RUBY_VM
1610
+ #### TODO !!!!!!
1611
+ fail RuntimeError,
1612
+ 'sorry, still not support multiple master-interpreters on RubyVM'
1613
+ end
1614
+
1615
+ if safe.kind_of?(Hash)
1616
+ keys = safe
1617
+ elsif safe.kind_of?(Integer)
1618
+ raise ArgumentError, "unexpected argument(s)" unless keys.kind_of?(Hash)
1619
+ if !keys.key?(:safe) && !keys.key?('safe')
1620
+ keys[:safe] = safe
1621
+ end
1622
+ elsif safe == nil
1623
+ # do nothing
1624
+ else
1625
+ raise ArgumentError, "unexpected argument(s)"
1626
+ end
1627
+
1628
+ ip = __new(__getip, nil, keys)
1629
+ #ip.eval_proc(proc{$SAFE=ip.safe_level; Proc.new}.call) if block_given?
1630
+ if block_given?
1631
+ #Thread.new{ip.eval_proc(proc{$SAFE=ip.safe_level; Proc.new}.call)}
1632
+ #Thread.new{ip.eval_proc(proc{$SAFE=ip.safe_level; yield}.call)}
1633
+ ip._proc_on_safelevel(&blk).call(ip.safe_level)
1634
+ end
1635
+ ip
1636
+ end
1637
+
1638
+ alias new new_master
1639
+
1640
+ def new_slave(safe=nil, keys={}, &blk)
1641
+ if safe.kind_of?(Hash)
1642
+ keys = safe
1643
+ elsif safe.kind_of?(Integer)
1644
+ raise ArgumentError, "unexpected argument(s)" unless keys.kind_of?(Hash)
1645
+ if !keys.key?(:safe) && !keys.key?('safe')
1646
+ keys[:safe] = safe
1647
+ end
1648
+ elsif safe == nil
1649
+ # do nothing
1650
+ else
1651
+ raise ArgumentError, "unexpected argument(s)"
1652
+ end
1653
+
1654
+ ip = __new(__getip, false, keys)
1655
+ # ip.eval_proc(proc{$SAFE=ip.safe_level; Proc.new}.call) if block_given?
1656
+ if block_given?
1657
+ #Thread.new{ip.eval_proc(proc{$SAFE=ip.safe_level; Proc.new}.call)}
1658
+ #Thread.new{ip.eval_proc(proc{$SAFE=ip.safe_level; yield}.call)}
1659
+ ip._proc_on_safelevel(&blk).call(ip.safe_level)
1660
+ end
1661
+ ip
1662
+ end
1663
+ alias new_trusted_slave new_slave
1664
+
1665
+ def new_safe_slave(safe=4, keys={}, &blk)
1666
+ if safe.kind_of?(Hash)
1667
+ keys = safe
1668
+ elsif safe.kind_of?(Integer)
1669
+ raise ArgumentError, "unexpected argument(s)" unless keys.kind_of?(Hash)
1670
+ if !keys.key?(:safe) && !keys.key?('safe')
1671
+ keys[:safe] = safe
1672
+ end
1673
+ else
1674
+ raise ArgumentError, "unexpected argument(s)"
1675
+ end
1676
+
1677
+ ip = __new(__getip, true, keys)
1678
+ # ip.eval_proc(proc{$SAFE=ip.safe_level; Proc.new}.call) if block_given?
1679
+ if block_given?
1680
+ #Thread.new{ip.eval_proc(proc{$SAFE=ip.safe_level; Proc.new}.call)}
1681
+ #Thread.new{ip.eval_proc(proc{$SAFE=ip.safe_level; yield}.call)}
1682
+ ip._proc_on_safelevel(&blk).call(ip.safe_level)
1683
+ end
1684
+ ip
1685
+ end
1686
+ alias new_safeTk new_safe_slave
1687
+ end
1688
+
1689
+
1690
+ # get info
1691
+ class MultiTkIp
1692
+ def inspect
1693
+ s = self.to_s.chop!
1694
+ if self.manipulable?
1695
+ if master?
1696
+ if @interp.deleted?
1697
+ s << ':deleted-master'
1698
+ else
1699
+ s << ':master'
1700
+ end
1701
+ else
1702
+ if @interp.deleted?
1703
+ s << ':deleted-slave'
1704
+ elsif @interp.safe?
1705
+ s << ':safe-slave'
1706
+ else
1707
+ s << ':trusted-slave'
1708
+ end
1709
+ end
1710
+ end
1711
+ s << '>'
1712
+ end
1713
+
1714
+ def master?
1715
+ if @ip_name
1716
+ false
1717
+ else
1718
+ true
1719
+ end
1720
+ end
1721
+ def self.master?
1722
+ __getip.master?
1723
+ end
1724
+
1725
+ def slave?
1726
+ not master?
1727
+ end
1728
+ def self.slave?
1729
+ not self.master?
1730
+ end
1731
+
1732
+ def alive?
1733
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
1734
+ begin
1735
+ return false unless @cmd_receiver.alive?
1736
+ return false if @interp.deleted?
1737
+ return false if @interp._invoke('interp', 'exists', '') == '0'
1738
+ rescue Exception
1739
+ return false
1740
+ end
1741
+ true
1742
+ end
1743
+ def self.alive?
1744
+ __getip.alive?
1745
+ end
1746
+
1747
+ def path
1748
+ @ip_name || ''
1749
+ end
1750
+ def self.path
1751
+ __getip.path
1752
+ end
1753
+ def ip_name
1754
+ @ip_name || ''
1755
+ end
1756
+ def self.ip_name
1757
+ __getip.ip_name
1758
+ end
1759
+ def to_eval
1760
+ @ip_name || ''
1761
+ end
1762
+ def self.to_eval
1763
+ __getip.to_eval
1764
+ end
1765
+
1766
+ def slaves(all = false)
1767
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
1768
+ @interp._invoke('interp','slaves').split.map!{|name|
1769
+ if @slave_ip_tbl.key?(name)
1770
+ @slave_ip_tbl[name]
1771
+ elsif all
1772
+ name
1773
+ else
1774
+ nil
1775
+ end
1776
+ }.compact!
1777
+ end
1778
+ def self.slaves(all = false)
1779
+ __getip.slaves(all)
1780
+ end
1781
+
1782
+ def manipulable?
1783
+ return true if (Thread.current.group == ThreadGroup::Default)
1784
+ ip = MultiTkIp.__getip
1785
+ (ip == self) || ip._is_master_of?(@interp)
1786
+ end
1787
+ def self.manipulable?
1788
+ true
1789
+ end
1790
+
1791
+ def _is_master_of?(tcltkip_obj)
1792
+ tcltkip_obj.slave_of?(@interp)
1793
+ end
1794
+ protected :_is_master_of?
1795
+ end
1796
+
1797
+
1798
+ # instance methods to treat tables
1799
+ class MultiTkIp
1800
+ def _tk_cmd_tbl
1801
+ tbl = {}
1802
+ MultiTkIp.tk_cmd_tbl.each{|id, ent| tbl[id] = ent if ent.ip == self }
1803
+ tbl
1804
+ end
1805
+
1806
+ def _tk_windows
1807
+ @tk_windows
1808
+ end
1809
+
1810
+ def _tk_table_list
1811
+ @tk_table_list
1812
+ end
1813
+
1814
+ def _add_new_tables
1815
+ (@@TK_TABLE_LIST.size - @tk_table_list.size).times{
1816
+ @tk_table_list << TkUtil.untrust({})
1817
+ }
1818
+ end
1819
+
1820
+ def _init_ip_env(script)
1821
+ self.eval_proc{script.call(self)}
1822
+ end
1823
+
1824
+ def _add_tk_procs(name, args, body)
1825
+ return if slave?
1826
+ @interp._invoke('proc', name, args, body) if args && body
1827
+ @interp._invoke('interp', 'slaves').split.each{|slave|
1828
+ @interp._invoke('interp', 'alias', slave, name, '', name)
1829
+ }
1830
+ end
1831
+
1832
+ def _remove_tk_procs(*names)
1833
+ return if slave?
1834
+ names.each{|name|
1835
+ name = name.to_s
1836
+
1837
+ return if @interp.deleted?
1838
+ @interp._invoke('rename', name, '')
1839
+
1840
+ return if @interp.deleted?
1841
+ @interp._invoke('interp', 'slaves').split.each{|slave|
1842
+ return if @interp.deleted?
1843
+ @interp._invoke('interp', 'alias', slave, name, '') rescue nil
1844
+ }
1845
+ }
1846
+ end
1847
+
1848
+ def _init_ip_internal(init_ip_env, add_tk_procs)
1849
+ #init_ip_env.each{|script| self.eval_proc{script.call(self)}}
1850
+ init_ip_env.each{|script| self._init_ip_env(script)}
1851
+ add_tk_procs.each{|name, args, body|
1852
+ if master?
1853
+ @interp._invoke('proc', name, args, body) if args && body
1854
+ else
1855
+ @set_alias_proc.call(name)
1856
+ end
1857
+ }
1858
+ end
1859
+ end
1860
+
1861
+
1862
+ # class methods to treat tables
1863
+ class MultiTkIp
1864
+ def self.tk_cmd_tbl
1865
+ @@TK_CMD_TBL
1866
+ end
1867
+ def self.tk_windows
1868
+ __getip._tk_windows
1869
+ end
1870
+ def self.tk_object_table(id)
1871
+ __getip._tk_table_list[id]
1872
+ end
1873
+ def self.create_table
1874
+ if __getip.slave?
1875
+ begin
1876
+ raise SecurityError, "slave-IP has no permission creating a new table"
1877
+ rescue SecurityError => e
1878
+ #p e.backtrace
1879
+ # Is called on a Ruby/Tk library?
1880
+ caller_info = e.backtrace[1]
1881
+ if caller_info =~ %r{^#{MultiTkIp::BASE_DIR}/(tk|tkextlib)/[^:]+\.rb:}
1882
+ # Probably, caller is a Ruby/Tk library --> allow creating
1883
+ else
1884
+ raise e
1885
+ end
1886
+ end
1887
+ end
1888
+
1889
+ id = @@TK_TABLE_LIST.size
1890
+ obj = Object.new
1891
+ @@TK_TABLE_LIST << obj
1892
+ obj.instance_variable_set(:@id, id)
1893
+ obj.instance_variable_set(:@mutex, Mutex.new)
1894
+ obj.instance_eval{
1895
+ def self.mutex
1896
+ @mutex
1897
+ end
1898
+ def self.method_missing(m, *args)
1899
+ MultiTkIp.tk_object_table(@id).__send__(m, *args)
1900
+ end
1901
+ }
1902
+ obj.freeze
1903
+ @@IP_TABLE.each{|tg, ip| ip._add_new_tables }
1904
+ return obj
1905
+ end
1906
+
1907
+ def self.init_ip_env(script = Proc.new)
1908
+ @@INIT_IP_ENV << script
1909
+ if __getip.slave?
1910
+ begin
1911
+ raise SecurityError, "slave-IP has no permission initializing IP env"
1912
+ rescue SecurityError => e
1913
+ #p e.backtrace
1914
+ # Is called on a Ruby/Tk library?
1915
+ caller_info = e.backtrace[1]
1916
+ if caller_info =~ %r{^#{MultiTkIp::BASE_DIR}/(tk|tkextlib)/[^:]+\.rb:}
1917
+ # Probably, caller is a Ruby/Tk library --> allow creating
1918
+ else
1919
+ raise e
1920
+ end
1921
+ end
1922
+ end
1923
+
1924
+ # @@IP_TABLE.each{|tg, ip|
1925
+ # ip._init_ip_env(script)
1926
+ # }
1927
+ @@DEFAULT_MASTER.__init_ip_env__(@@IP_TABLE, script)
1928
+ end
1929
+
1930
+ def self.add_tk_procs(name, args=nil, body=nil)
1931
+ if name.kind_of?(Array) # => an array of [name, args, body]
1932
+ name.each{|param| self.add_tk_procs(*param)}
1933
+ else
1934
+ name = name.to_s
1935
+ @@ADD_TK_PROCS << [name, args, body]
1936
+ @@IP_TABLE.each{|tg, ip|
1937
+ ip._add_tk_procs(name, args, body)
1938
+ }
1939
+ end
1940
+ end
1941
+
1942
+ def self.remove_tk_procs(*names)
1943
+ names.each{|name|
1944
+ name = name.to_s
1945
+ @@ADD_TK_PROCS.delete_if{|elem|
1946
+ elem.kind_of?(Array) && elem[0].to_s == name
1947
+ }
1948
+ }
1949
+ @@IP_TABLE.each{|tg, ip|
1950
+ ip._remove_tk_procs(*names)
1951
+ }
1952
+ end
1953
+
1954
+ def self.init_ip_internal
1955
+ __getip._init_ip_internal(@@INIT_IP_ENV, @@ADD_TK_PROCS)
1956
+ end
1957
+ end
1958
+
1959
+ # for callback operation
1960
+ class MultiTkIp
1961
+ def self.cb_entry_class
1962
+ @@CB_ENTRY_CLASS
1963
+ end
1964
+ def self.get_cb_entry(cmd)
1965
+ @@CB_ENTRY_CLASS.new(__getip, cmd).freeze
1966
+ end
1967
+
1968
+ =begin
1969
+ def cb_eval(cmd, *args)
1970
+ #self.eval_callback{ TkComm._get_eval_string(TkUtil.eval_cmd(cmd, *args)) }
1971
+ #ret = self.eval_callback{ TkComm._get_eval_string(TkUtil.eval_cmd(cmd, *args)) }
1972
+ ret = self.eval_callback(*args){|safe, *params|
1973
+ $SAFE=safe if $SAFE < safe
1974
+ TkComm._get_eval_string(TkUtil.eval_cmd(cmd, *params))
1975
+ }
1976
+ if ret.kind_of?(Exception)
1977
+ raise ret
1978
+ end
1979
+ ret
1980
+ end
1981
+ =end
1982
+ def cb_eval(cmd, *args)
1983
+ self.eval_callback(*args,
1984
+ &_proc_on_safelevel{|*params|
1985
+ TkComm._get_eval_string(TkUtil.eval_cmd(cmd, *params))
1986
+ })
1987
+ end
1988
+ =begin
1989
+ def cb_eval(cmd, *args)
1990
+ self.eval_callback(*args){|safe, *params|
1991
+ $SAFE=safe if $SAFE < safe
1992
+ # TkUtil.eval_cmd(cmd, *params)
1993
+ TkComm._get_eval_string(TkUtil.eval_cmd(cmd, *params))
1994
+ }
1995
+ end
1996
+ =end
1997
+ =begin
1998
+ def cb_eval(cmd, *args)
1999
+ @callback_status[0] ||= TkVariable.new
2000
+ @callback_status[1] ||= TkVariable.new
2001
+ st, val = @callback_status
2002
+ th = Thread.new{
2003
+ self.eval_callback(*args){|safe, *params|
2004
+ #p [status, val, safe, *params]
2005
+ $SAFE=safe if $SAFE < safe
2006
+ begin
2007
+ TkComm._get_eval_string(TkUtil.eval_cmd(cmd, *params))
2008
+ rescue TkCallbackContinue
2009
+ st.value = 4
2010
+ rescue TkCallbackBreak
2011
+ st.value = 3
2012
+ rescue TkCallbackReturn
2013
+ st.value = 2
2014
+ rescue Exception => e
2015
+ val.value = e.message
2016
+ st.value = 1
2017
+ else
2018
+ st.value = 0
2019
+ end
2020
+ }
2021
+ }
2022
+ begin
2023
+ st.wait
2024
+ status = st.numeric
2025
+ retval = val.value
2026
+ rescue => e
2027
+ fail e
2028
+ end
2029
+
2030
+ if status == 1
2031
+ fail RuntimeError, retval
2032
+ elsif status == 2
2033
+ fail TkCallbackReturn, "Tk callback returns 'return' status"
2034
+ elsif status == 3
2035
+ fail TkCallbackBreak, "Tk callback returns 'break' status"
2036
+ elsif status == 4
2037
+ fail TkCallbackContinue, "Tk callback returns 'continue' status"
2038
+ else
2039
+ ''
2040
+ end
2041
+ end
2042
+ =end
2043
+
2044
+ end
2045
+
2046
+ # pseudo-toplevel operation support
2047
+ class MultiTkIp
2048
+ # instance method
2049
+ def __pseudo_toplevel
2050
+ ip = MultiTkIp.__getip
2051
+ (ip == @@DEFAULT_MASTER || ip == self) &&
2052
+ self.__pseudo_toplevel_evaluable? && @pseudo_toplevel[1]
2053
+ end
2054
+
2055
+ def __pseudo_toplevel=(m)
2056
+ unless (Thread.current.group == ThreadGroup::Default &&
2057
+ MultiTkIp.__getip == @@DEFAULT_MASTER)
2058
+ fail SecurityError, "no permission to manipulate"
2059
+ end
2060
+
2061
+ # if m.kind_of?(Module) && m.respond_to?(:pseudo_toplevel_evaluable?)
2062
+ if m.respond_to?(:pseudo_toplevel_evaluable?)
2063
+ @pseudo_toplevel[0] = true
2064
+ @pseudo_toplevel[1] = m
2065
+ else
2066
+ fail ArgumentError, 'fail to set pseudo-toplevel'
2067
+ end
2068
+ self
2069
+ end
2070
+
2071
+ def __pseudo_toplevel_evaluable?
2072
+ begin
2073
+ @pseudo_toplevel[0] && @pseudo_toplevel[1].pseudo_toplevel_evaluable?
2074
+ rescue Exception
2075
+ false
2076
+ end
2077
+ end
2078
+
2079
+ def __pseudo_toplevel_evaluable=(mode)
2080
+ unless (Thread.current.group == ThreadGroup::Default &&
2081
+ MultiTkIp.__getip == @@DEFAULT_MASTER)
2082
+ fail SecurityError, "no permission to manipulate"
2083
+ end
2084
+
2085
+ @pseudo_toplevel[0] = (mode)? true: false
2086
+ end
2087
+ end
2088
+
2089
+ # evaluate a procedure on the proper interpreter
2090
+ class MultiTkIp
2091
+ # instance & class method
2092
+ def _proc_on_safelevel(cmd=nil, &blk) # require a block for eval
2093
+ if cmd
2094
+ if cmd.kind_of?(Method)
2095
+ _proc_on_safelevel{|*args| cmd.call(*args)}
2096
+ else
2097
+ _proc_on_safelevel(&cmd)
2098
+ end
2099
+ else
2100
+ #Proc.new{|safe, *args| $SAFE=safe if $SAFE < safe; yield(*args)}
2101
+ Proc.new{|safe, *args|
2102
+ # avoid security error on Exception objects
2103
+ untrust_proc = proc{|err|
2104
+ begin
2105
+ err.untrust if err.respond_to?(:untrust)
2106
+ rescue SecurityError
2107
+ end
2108
+ err
2109
+ }
2110
+ $SAFE=safe if $SAFE < safe;
2111
+ begin
2112
+ yield(*args)
2113
+ rescue Exception => e
2114
+ fail untrust_proc.call(e)
2115
+ end
2116
+ }
2117
+ end
2118
+ end
2119
+ def MultiTkIp._proc_on_safelevel(cmd=nil, &blk)
2120
+ MultiTkIp.__getip._proc_on_safelevel(cmd, &blk)
2121
+ end
2122
+
2123
+ def _proc_on_current_safelevel(cmd=nil, &blk) # require a block for eval
2124
+ safe = $SAFE
2125
+ cmd = _proc_on_safelevel(cmd, &blk)
2126
+ Proc.new{|*args| cmd.call(safe, *args)}
2127
+ end
2128
+ def MultiTkIp._proc_on_current_safelevel(cmd=nil, &blk)
2129
+ MultiTkIp.__getip._proc_on_current_safelevel(cmd, &blk)
2130
+ end
2131
+
2132
+ ######################################
2133
+ # instance method
2134
+ def eval_proc_core(req_val, cmd, *args)
2135
+ # check
2136
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
2137
+ unless cmd.kind_of?(Proc) || cmd.kind_of?(Method)
2138
+ raise RuntimeError, "A Proc/Method object is expected for the 'cmd' argument"
2139
+ end
2140
+
2141
+ # on IP thread
2142
+ if @cmd_receiver == Thread.current ||
2143
+ (!req_val && TclTkLib.mainloop_thread? != false) # callback
2144
+ begin
2145
+ ret = cmd.call(safe_level, *args)
2146
+ rescue SystemExit => e
2147
+ # exit IP
2148
+ warn("Warning: "+ e.inspect + " on " + self.inspect) if $DEBUG
2149
+ begin
2150
+ self._eval_without_enc('exit')
2151
+ rescue Exception => e
2152
+ end
2153
+ self.delete
2154
+ ret = nil
2155
+ rescue Exception => e
2156
+ if $DEBUG
2157
+ warn("Warning: " + e.class.inspect +
2158
+ ((e.message.length > 0)? ' "' + e.message + '"': '') +
2159
+ " on " + self.inspect)
2160
+ end
2161
+ =begin
2162
+ begin
2163
+ bt = _toUTF8(e.backtrace.join("\n"))
2164
+ bt.instance_variable_set(:@encoding, 'utf-8')
2165
+ rescue Exception
2166
+ bt = e.backtrace.join("\n")
2167
+ end
2168
+ begin
2169
+ @interp._set_global_var('errorInfo', bt)
2170
+ rescue Exception
2171
+ end
2172
+ =end
2173
+ ret = e
2174
+ end
2175
+ return ret
2176
+ end
2177
+
2178
+ # send cmd to the proc-queue
2179
+ unless req_val
2180
+ begin
2181
+ @cmd_queue.enq([nil, cmd, *args])
2182
+ rescue Exception => e
2183
+ # ignore
2184
+ if $DEBUG
2185
+ warn("Warning: " + e.class.inspect +
2186
+ ((e.message.length > 0)? ' "' + e.message + '"': '') +
2187
+ " on " + self.inspect)
2188
+ end
2189
+ return e
2190
+ end
2191
+ return nil
2192
+ end
2193
+
2194
+ # send and get return value by exception
2195
+ begin
2196
+ @cmd_queue.enq([Thread.current, cmd, *args])
2197
+ Thread.stop
2198
+ rescue MultiTkIp_OK => ret
2199
+ # return value
2200
+ return ret.value
2201
+ rescue SystemExit => e
2202
+ # exit IP
2203
+ warn("Warning: " + e.inspect + " on " + self.inspect) if $DEBUG
2204
+ begin
2205
+ self._eval_without_enc('exit')
2206
+ rescue Exception
2207
+ end
2208
+ if !self.deleted? && !safe? && allow_ruby_exit?
2209
+ self.delete
2210
+ fail e
2211
+ else
2212
+ self.delete
2213
+ end
2214
+ rescue Exception => e
2215
+ if $DEBUG
2216
+ warn("Warning: " + e.class.inspect +
2217
+ ((e.message.length > 0)? ' "' + e.message + '"': '') +
2218
+ " on " + self.inspect)
2219
+ end
2220
+ return e
2221
+ end
2222
+ return nil
2223
+ end
2224
+ private :eval_proc_core
2225
+
2226
+ if false && WITH_RUBY_VM ### Ruby 1.9
2227
+ # Not stable, so disable this feature
2228
+ def eval_callback(*args)
2229
+ if block_given?
2230
+ cmd = Proc.new
2231
+ else
2232
+ cmd = args.shift
2233
+ end
2234
+ begin
2235
+ if @@CALLBACK_SUBTHREAD.table[self].index(Thread.current)
2236
+ last_th = nil
2237
+ else
2238
+ last_th = @@CALLBACK_SUBTHREAD.table[self][-1]
2239
+ end
2240
+ @@CALLBACK_SUBTHREAD.new(self){
2241
+ @@CALLBACK_SUBTHREAD.table[self] << Thread.current
2242
+ begin
2243
+ last_th.join if last_th
2244
+ eval_proc_core(false, cmd, *args)
2245
+ rescue Exception=>e
2246
+ e
2247
+ ensure
2248
+ @@CALLBACK_SUBTHREAD.table[self].delete(Thread.current)
2249
+ end
2250
+ }
2251
+ end
2252
+ end
2253
+ else ### Ruby 1.8
2254
+ def eval_callback(*args)
2255
+ if block_given?
2256
+ cmd = Proc.new
2257
+ else
2258
+ cmd = args.shift
2259
+ end
2260
+ begin
2261
+ eval_proc_core(false, cmd, *args)
2262
+ rescue Exception=>e
2263
+ e
2264
+ ensure
2265
+ end
2266
+ end
2267
+ end
2268
+
2269
+ def eval_proc(*args, &blk)
2270
+ if block_given?
2271
+ cmd = _proc_on_safelevel(&blk)
2272
+ else
2273
+ unless (cmd = args.shift)
2274
+ fail ArgumentError, "A Proc or Method object is expected for 1st argument"
2275
+ end
2276
+ cmd = _proc_on_safelevel(&cmd)
2277
+ end
2278
+ if TclTkLib.mainloop_thread? == true
2279
+ # call from eventloop
2280
+ current = Thread.current
2281
+ backup_ip = current[:callback_ip]
2282
+ current[:callback_ip] = self
2283
+ begin
2284
+ eval_proc_core(false, cmd, *args)
2285
+ ensure
2286
+ current[:callback_ip] = backup_ip
2287
+ end
2288
+ else
2289
+ eval_proc_core(true,
2290
+ proc{|safe, *params|
2291
+ Thread.new{cmd.call(safe, *params)}.value
2292
+ },
2293
+ *args)
2294
+ end
2295
+ end
2296
+ =begin
2297
+ def eval_proc(*args)
2298
+ # The scope of the eval-block of 'eval_proc' method is different from
2299
+ # the external. If you want to pass local values to the eval-block,
2300
+ # use arguments of eval_proc method. They are passed to block-arguments.
2301
+ if block_given?
2302
+ cmd = Proc.new
2303
+ else
2304
+ unless (cmd = args.shift)
2305
+ fail ArgumentError, "A Proc or Method object is expected for 1st argument"
2306
+ end
2307
+ end
2308
+ if TclTkLib.mainloop_thread? == true
2309
+ # call from eventloop
2310
+ current = Thread.current
2311
+ backup_ip = current[:callback_ip]
2312
+ current[:callback_ip] = self
2313
+ begin
2314
+ eval_proc_core(false,
2315
+ proc{|safe, *params|
2316
+ $SAFE=safe if $SAFE < safe
2317
+ cmd.call(*params)
2318
+ }, *args)
2319
+ ensure
2320
+ current[:callback_ip] = backup_ip
2321
+ end
2322
+ else
2323
+ eval_proc_core(true,
2324
+ proc{|safe, *params|
2325
+ $SAFE=safe if $SAFE < safe
2326
+ Thread.new(*params, &cmd).value
2327
+ },
2328
+ *args)
2329
+ end
2330
+ end
2331
+ =end
2332
+ alias call eval_proc
2333
+
2334
+ def bg_eval_proc(*args)
2335
+ if block_given?
2336
+ cmd = Proc.new
2337
+ else
2338
+ unless (cmd = args.shift)
2339
+ fail ArgumentError, "A Proc or Method object is expected for 1st argument"
2340
+ end
2341
+ end
2342
+ Thread.new{
2343
+ eval_proc(cmd, *args)
2344
+ =begin
2345
+ eval_proc_core(false,
2346
+ proc{|safe, *params|
2347
+ $SAFE=safe if $SAFE < safe
2348
+ Thread.new(*params, &cmd).value
2349
+ },
2350
+ safe_level, *args)
2351
+ =end
2352
+ }
2353
+ end
2354
+ alias background_eval_proc bg_eval_proc
2355
+ alias thread_eval_proc bg_eval_proc
2356
+ alias bg_call bg_eval_proc
2357
+ alias background_call bg_eval_proc
2358
+
2359
+ def eval_string(cmd, *eval_args)
2360
+ # cmd string ==> proc
2361
+ unless cmd.kind_of?(String)
2362
+ raise RuntimeError, "A String object is expected for the 'cmd' argument"
2363
+ end
2364
+
2365
+ eval_proc_core(true,
2366
+ proc{|safe|
2367
+ Kernel.eval("$SAFE=#{safe} if $SAFE < #{safe};" << cmd,
2368
+ *eval_args)
2369
+ })
2370
+ end
2371
+ alias eval_str eval_string
2372
+
2373
+ def bg_eval_string(cmd, *eval_args)
2374
+ # cmd string ==> proc
2375
+ unless cmd.kind_of?(String)
2376
+ raise RuntimeError, "A String object is expected for the 'cmd' argument"
2377
+ end
2378
+ Thread.new{
2379
+ eval_proc_core(true,
2380
+ proc{|safe|
2381
+ Kernel.eval("$SAFE=#{safe} if $SAFE < #{safe};" << cmd,
2382
+ *eval_args)
2383
+ })
2384
+ }
2385
+ end
2386
+ alias background_eval_string bg_eval_string
2387
+ alias bg_eval_str bg_eval_string
2388
+ alias background_eval_str bg_eval_string
2389
+
2390
+ def eval(*args, &blk)
2391
+ if block_given?
2392
+ eval_proc(*args, &blk)
2393
+ elsif args[0]
2394
+ if args[0].respond_to?(:call)
2395
+ eval_proc(*args)
2396
+ else
2397
+ eval_string(*args)
2398
+ end
2399
+ else
2400
+ fail ArgumentError, "no argument to eval"
2401
+ end
2402
+ end
2403
+
2404
+ def bg_eval(*args, &blk)
2405
+ if block_given?
2406
+ bg_eval_proc(*args, &blk)
2407
+ elsif args[0]
2408
+ if args[0].respond_to?(:call)
2409
+ bg_eval_proc(*args)
2410
+ else
2411
+ bg_eval_string(*args)
2412
+ end
2413
+ else
2414
+ fail ArgumentError, "no argument to eval"
2415
+ end
2416
+ end
2417
+ alias background_eval bg_eval
2418
+ end
2419
+
2420
+ class << MultiTkIp
2421
+ # class method
2422
+ def eval_proc(*args, &blk)
2423
+ # class ==> interp object
2424
+ __getip.eval_proc(*args, &blk)
2425
+ end
2426
+ alias call eval_proc
2427
+
2428
+ def bg_eval_proc(*args, &blk)
2429
+ # class ==> interp object
2430
+ __getip.bg_eval_proc(*args, &blk)
2431
+ end
2432
+ alias background_eval_proc bg_eval_proc
2433
+ alias thread_eval_proc bg_eval_proc
2434
+ alias bg_call bg_eval_proc
2435
+ alias background_call bg_eval_proc
2436
+
2437
+ def eval_string(cmd, *eval_args)
2438
+ # class ==> interp object
2439
+ __getip.eval_string(cmd, *eval_args)
2440
+ end
2441
+ alias eval_str eval_string
2442
+
2443
+ def bg_eval_string(cmd, *eval_args)
2444
+ # class ==> interp object
2445
+ __getip.bg_eval_string(cmd, *eval_args)
2446
+ end
2447
+ alias background_eval_string bg_eval_string
2448
+ alias bg_eval_str bg_eval_string
2449
+ alias background_eval_str bg_eval_string
2450
+
2451
+ def eval(*args, &blk)
2452
+ # class ==> interp object
2453
+ __getip.eval(*args, &blk)
2454
+ end
2455
+ def bg_eval(*args, &blk)
2456
+ # class ==> interp object
2457
+ __getip.bg_eval(*args, &blk)
2458
+ end
2459
+ alias background_eval bg_eval
2460
+ end
2461
+
2462
+
2463
+ # event loop
2464
+ # all master/slave IPs are controled by only one event-loop
2465
+ class MultiTkIp
2466
+ def self.default_master?
2467
+ __getip == @@DEFAULT_MASTER
2468
+ end
2469
+ end
2470
+ class << MultiTkIp
2471
+ def mainloop(check_root = true)
2472
+ __getip.mainloop(check_root)
2473
+ end
2474
+ def mainloop_watchdog(check_root = true)
2475
+ __getip.mainloop_watchdog(check_root)
2476
+ end
2477
+ def do_one_event(flag = TclTkLib::EventFlag::ALL)
2478
+ __getip.do_one_event(flag)
2479
+ end
2480
+ def mainloop_abort_on_exception
2481
+ # __getip.mainloop_abort_on_exception
2482
+ TclTkLib.mainloop_abort_on_exception
2483
+ end
2484
+ def mainloop_abort_on_exception=(mode)
2485
+ # __getip.mainloop_abort_on_exception=(mode)
2486
+ TclTkLib.mainloop_abort_on_exception=(mode)
2487
+ end
2488
+ def set_eventloop_tick(tick)
2489
+ __getip.set_eventloop_tick(tick)
2490
+ end
2491
+ def get_eventloop_tick
2492
+ __getip.get_eventloop_tick
2493
+ end
2494
+ def set_no_event_wait(tick)
2495
+ __getip.set_no_event_wait(tick)
2496
+ end
2497
+ def get_no_event_wait
2498
+ __getip.get_no_event_wait
2499
+ end
2500
+ def set_eventloop_weight(loop_max, no_event_tick)
2501
+ __getip.set_eventloop_weight(loop_max, no_event_tick)
2502
+ end
2503
+ def get_eventloop_weight
2504
+ __getip.get_eventloop_weight
2505
+ end
2506
+ end
2507
+
2508
+ # class methods to delegate to TclTkIp
2509
+ class << MultiTkIp
2510
+ def method_missing(id, *args)
2511
+ __getip.__send__(id, *args)
2512
+ end
2513
+
2514
+ def make_safe
2515
+ __getip.make_safe
2516
+ end
2517
+
2518
+ def safe?
2519
+ __getip.safe?
2520
+ end
2521
+
2522
+ def safe_base?
2523
+ begin
2524
+ __getip.safe_base?
2525
+ rescue
2526
+ false
2527
+ end
2528
+ end
2529
+
2530
+ def allow_ruby_exit?
2531
+ __getip.allow_ruby_exit?
2532
+ end
2533
+
2534
+ def allow_ruby_exit= (mode)
2535
+ __getip.allow_ruby_exit = mode
2536
+ end
2537
+
2538
+ def delete
2539
+ __getip.delete
2540
+ end
2541
+
2542
+ def deleted?
2543
+ __getip.deleted?
2544
+ end
2545
+
2546
+ def has_mainwindow?
2547
+ __getip.has_mainwindow?
2548
+ end
2549
+
2550
+ def invalid_namespace?
2551
+ __getip.invalid_namespace?
2552
+ end
2553
+
2554
+ def abort(msg = nil)
2555
+ __getip.abort(msg)
2556
+ end
2557
+
2558
+ def exit(st = true)
2559
+ __getip.exit(st)
2560
+ end
2561
+
2562
+ def exit!(st = false)
2563
+ __getip.exit!(st)
2564
+ end
2565
+
2566
+ def restart(app_name = nil, keys = {})
2567
+ init_ip_internal
2568
+
2569
+ __getip._invoke('set', 'argv0', app_name) if app_name
2570
+ if keys.kind_of?(Hash)
2571
+ __getip._invoke('set', 'argv', _keys2opts(keys))
2572
+ end
2573
+
2574
+ __getip.restart
2575
+ end
2576
+
2577
+ def _eval(str)
2578
+ __getip._eval(str)
2579
+ end
2580
+
2581
+ def _invoke(*args)
2582
+ __getip._invoke(*args)
2583
+ end
2584
+
2585
+ def _eval_without_enc(str)
2586
+ __getip._eval_without_enc(str)
2587
+ end
2588
+
2589
+ def _invoke_without_enc(*args)
2590
+ __getip._invoke_without_enc(*args)
2591
+ end
2592
+
2593
+ def _eval_with_enc(str)
2594
+ __getip._eval_with_enc(str)
2595
+ end
2596
+
2597
+ def _invoke_with_enc(*args)
2598
+ __getip._invoke_with_enc(*args)
2599
+ end
2600
+
2601
+ def _toUTF8(str, encoding=nil)
2602
+ __getip._toUTF8(str, encoding)
2603
+ end
2604
+
2605
+ def _fromUTF8(str, encoding=nil)
2606
+ __getip._fromUTF8(str, encoding)
2607
+ end
2608
+
2609
+ def _thread_vwait(var)
2610
+ __getip._thread_vwait(var)
2611
+ end
2612
+
2613
+ def _thread_tkwait(mode, target)
2614
+ __getip._thread_tkwait(mode, target)
2615
+ end
2616
+
2617
+ def _return_value
2618
+ __getip._return_value
2619
+ end
2620
+
2621
+ def _get_variable(var, flag)
2622
+ __getip._get_variable(var, flag)
2623
+ end
2624
+ def _get_variable2(var, idx, flag)
2625
+ __getip._get_variable2(var, idx, flag)
2626
+ end
2627
+ def _set_variable(var, value, flag)
2628
+ __getip._set_variable(var, value, flag)
2629
+ end
2630
+ def _set_variable2(var, idx, value, flag)
2631
+ __getip._set_variable2(var, idx, value, flag)
2632
+ end
2633
+ def _unset_variable(var, flag)
2634
+ __getip._unset_variable(var, flag)
2635
+ end
2636
+ def _unset_variable2(var, idx, flag)
2637
+ __getip._unset_variable2(var, idx, flag)
2638
+ end
2639
+
2640
+ def _get_global_var(var)
2641
+ __getip._get_global_var(var)
2642
+ end
2643
+ def _get_global_var2(var, idx)
2644
+ __getip._get_global_var2(var, idx)
2645
+ end
2646
+ def _set_global_var(var, value)
2647
+ __getip._set_global_var(var, value)
2648
+ end
2649
+ def _set_global_var2(var, idx, value)
2650
+ __getip._set_global_var2(var, idx, value)
2651
+ end
2652
+ def _unset_global_var(var)
2653
+ __getip._unset_global_var(var)
2654
+ end
2655
+ def _unset_global_var2(var, idx)
2656
+ __getip._unset_global_var2(var, idx)
2657
+ end
2658
+
2659
+ def _make_menu_embeddable(menu_path)
2660
+ __getip._make_menu_embeddable(menu_path)
2661
+ end
2662
+
2663
+ def _split_tklist(str)
2664
+ __getip._split_tklist(str)
2665
+ end
2666
+ def _merge_tklist(*args)
2667
+ __getip._merge_tklist(*args)
2668
+ end
2669
+ def _conv_listelement(arg)
2670
+ __getip._conv_listelement(arg)
2671
+ end
2672
+
2673
+ def _create_console
2674
+ __getip._create_console
2675
+ end
2676
+ end
2677
+
2678
+
2679
+ # wrap methods on TclTkLib : not permit calling TclTkLib module methods
2680
+ class << TclTkLib
2681
+ def mainloop(check_root = true)
2682
+ MultiTkIp.mainloop(check_root)
2683
+ end
2684
+ def mainloop_watchdog(check_root = true)
2685
+ MultiTkIp.mainloop_watchdog(check_root)
2686
+ end
2687
+ def do_one_event(flag = TclTkLib::EventFlag::ALL)
2688
+ MultiTkIp.do_one_event(flag)
2689
+ end
2690
+ #def mainloop_abort_on_exception
2691
+ # MultiTkIp.mainloop_abort_on_exception
2692
+ #end
2693
+ #def mainloop_abort_on_exception=(mode)
2694
+ # MultiTkIp.mainloop_abort_on_exception=(mode)
2695
+ #end
2696
+ def set_eventloop_tick(tick)
2697
+ MultiTkIp.set_eventloop_tick(tick)
2698
+ end
2699
+ def get_eventloop_tick
2700
+ MultiTkIp.get_eventloop_tick
2701
+ end
2702
+ def set_no_event_wait(tick)
2703
+ MultiTkIp.set_no_event_wait(tick)
2704
+ end
2705
+ def get_no_event_wait
2706
+ MultiTkIp.get_no_event_wait
2707
+ end
2708
+ def set_eventloop_weight(loop_max, no_event_tick)
2709
+ MultiTkIp.set_eventloop_weight(loop_max, no_event_tick)
2710
+ end
2711
+ def get_eventloop_weight
2712
+ MultiTkIp.get_eventloop_weight
2713
+ end
2714
+ def restart(*args)
2715
+ MultiTkIp.restart(*args)
2716
+ end
2717
+
2718
+ def _merge_tklist(*args)
2719
+ MultiTkIp._merge_tklist(*args)
2720
+ end
2721
+ def _conv_listelement(arg)
2722
+ MultiTkIp._conv_listelement(arg)
2723
+ end
2724
+ end
2725
+
2726
+
2727
+ # depend on TclTkIp
2728
+ class MultiTkIp
2729
+ # def mainloop(check_root = true, restart_on_dead = true)
2730
+ def mainloop(check_root = true, restart_on_dead = false)
2731
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
2732
+
2733
+ if WITH_RUBY_VM ### Ruby 1.9 !!!!!!!!!!!
2734
+ return @interp_thread.value if @interp_thread
2735
+ end
2736
+
2737
+ #return self if self.slave?
2738
+ #return self if self != @@DEFAULT_MASTER
2739
+ if self != @@DEFAULT_MASTER
2740
+ if @wait_on_mainloop[0]
2741
+ begin
2742
+ @wait_on_mainloop[1] += 1
2743
+ if $SAFE >= 4
2744
+ _receiver_mainloop(check_root).join
2745
+ else
2746
+ @cmd_queue.enq([@system, 'call_mainloop',
2747
+ Thread.current, check_root])
2748
+ Thread.stop
2749
+ end
2750
+ rescue MultiTkIp_OK => ret
2751
+ # return value
2752
+ if ret.value.kind_of?(Thread)
2753
+ return ret.value.value
2754
+ else
2755
+ return ret.value
2756
+ end
2757
+ rescue SystemExit => e
2758
+ # exit IP
2759
+ warn("Warning: " + e.inspect + " on " + self.inspect) if $DEBUG
2760
+ begin
2761
+ self._eval_without_enc('exit')
2762
+ rescue Exception
2763
+ end
2764
+ self.delete
2765
+ rescue StandardError => e
2766
+ if $DEBUG
2767
+ warn("Warning: " + e.class.inspect +
2768
+ ((e.message.length > 0)? ' "' + e.message + '"': '') +
2769
+ " on " + self.inspect)
2770
+ end
2771
+ return e
2772
+ rescue Exception => e
2773
+ return e
2774
+ ensure
2775
+ @wait_on_mainloop[1] -= 1
2776
+ end
2777
+ end
2778
+ return
2779
+ end
2780
+
2781
+ unless restart_on_dead
2782
+ @wait_on_mainloop[1] += 1
2783
+ =begin
2784
+ begin
2785
+ @interp.mainloop(check_root)
2786
+ rescue StandardError => e
2787
+ if $DEBUG
2788
+ warn("Warning: " + e.class.inspect +
2789
+ ((e.message.length > 0)? ' "' + e.message + '"': '') +
2790
+ " on " + self.inspect)
2791
+ end
2792
+ end
2793
+ =end
2794
+ begin
2795
+ @interp.mainloop(check_root)
2796
+ ensure
2797
+ @wait_on_mainloop[1] -= 1
2798
+ end
2799
+ else
2800
+ loop do
2801
+ break unless self.alive?
2802
+ if check_root
2803
+ begin
2804
+ break if TclTkLib.num_of_mainwindows == 0
2805
+ rescue StandardError
2806
+ break
2807
+ end
2808
+ end
2809
+ break if @interp.deleted?
2810
+ begin
2811
+ @wait_on_mainloop[1] += 1
2812
+ @interp.mainloop(check_root)
2813
+ rescue StandardError => e
2814
+ if TclTkLib.mainloop_abort_on_exception != nil
2815
+ #STDERR.print("Warning: Tk mainloop receives ", $!.class.inspect,
2816
+ # " exception (ignore) : ", $!.message, "\n");
2817
+ if $DEBUG
2818
+ warn("Warning: Tk mainloop receives " << e.class.inspect <<
2819
+ " exception (ignore) : " << e.message);
2820
+ end
2821
+ end
2822
+ #raise e
2823
+ rescue Exception => e
2824
+ =begin
2825
+ if TclTkLib.mainloop_abort_on_exception != nil
2826
+ #STDERR.print("Warning: Tk mainloop receives ", $!.class.inspect,
2827
+ # " exception (ignore) : ", $!.message, "\n");
2828
+ if $DEBUG
2829
+ warn("Warning: Tk mainloop receives " << e.class.inspect <<
2830
+ " exception (ignore) : " << e.message);
2831
+ end
2832
+ end
2833
+ =end
2834
+ raise e
2835
+ ensure
2836
+ @wait_on_mainloop[1] -= 1
2837
+ Thread.pass # avoid eventloop conflict
2838
+ end
2839
+ end
2840
+ end
2841
+ self
2842
+ end
2843
+
2844
+ def make_safe
2845
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
2846
+ @interp.make_safe
2847
+ end
2848
+
2849
+ def safe?
2850
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
2851
+ @interp.safe?
2852
+ end
2853
+
2854
+ def safe_base?
2855
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
2856
+ @safe_base
2857
+ end
2858
+
2859
+ def allow_ruby_exit?
2860
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
2861
+ @interp.allow_ruby_exit?
2862
+ end
2863
+
2864
+ def allow_ruby_exit= (mode)
2865
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
2866
+ @interp.allow_ruby_exit = mode
2867
+ end
2868
+
2869
+ def delete
2870
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
2871
+ @slave_ip_tbl.each{|name, subip|
2872
+ _destroy_slaves_of_slaveIP(subip)
2873
+ =begin
2874
+ begin
2875
+ subip._invoke('destroy', '.') unless subip.deleted?
2876
+ rescue Exception
2877
+ end
2878
+ =end
2879
+ begin
2880
+ # subip._eval_without_enc("foreach i [after info] {after cancel $i}")
2881
+ unless subip.deleted?
2882
+ after_ids = subip._eval_without_enc("after info")
2883
+ subip._eval_without_enc("foreach i {#{after_ids}} {after cancel $i}")
2884
+ end
2885
+ rescue Exception
2886
+ end
2887
+
2888
+ # safe_base?
2889
+ if @interp._eval_without_enc("catch {::safe::interpConfigure #{name}}") == '0'
2890
+ begin
2891
+ @interp._eval_without_enc("::safe::interpDelete #{name}")
2892
+ rescue Exception
2893
+ else
2894
+ next if subip.deleted?
2895
+ end
2896
+ end
2897
+ if subip.respond_to?(:safe_base?) && subip.safe_base? &&
2898
+ !subip.deleted?
2899
+ # do 'exit' to call the delete_hook procedure
2900
+ begin
2901
+ subip._eval_without_enc('exit')
2902
+ rescue Exception
2903
+ end
2904
+ else
2905
+ begin
2906
+ subip.delete unless subip.deleted?
2907
+ rescue Exception
2908
+ end
2909
+ end
2910
+ }
2911
+
2912
+ begin
2913
+ # @interp._eval_without_enc("foreach i [after info] {after cancel $i}")
2914
+ after_ids = @interp._eval_without_enc("after info")
2915
+ @interp._eval_without_enc("foreach i {#{after_ids}} {after cancel $i}")
2916
+ rescue Exception
2917
+ end
2918
+
2919
+ begin
2920
+ @interp._invoke('destroy', '.') unless @interp.deleted?
2921
+ rescue Exception
2922
+ end
2923
+
2924
+ if @safe_base && !@interp.deleted?
2925
+ # do 'exit' to call the delete_hook procedure
2926
+ @interp._eval_without_enc('exit')
2927
+ end
2928
+ @interp.delete
2929
+ self
2930
+ end
2931
+
2932
+ def deleted?
2933
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
2934
+ @interp.deleted?
2935
+ end
2936
+
2937
+ def has_mainwindow?
2938
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
2939
+ @interp.has_mainwindow?
2940
+ end
2941
+
2942
+ def invalid_namespace?
2943
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
2944
+ @interp.invalid_namespace?
2945
+ end
2946
+
2947
+ def abort(msg = nil)
2948
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
2949
+ if master? && !safe? && allow_ruby_exit?
2950
+ if msg
2951
+ Kernel.abort(msg)
2952
+ else
2953
+ Kernel.abort
2954
+ end
2955
+ else
2956
+ # ignore msg
2957
+ delete
2958
+ 1
2959
+ end
2960
+ end
2961
+
2962
+ def exit(st = true)
2963
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
2964
+ if master? && !safe? && allow_ruby_exit?
2965
+ Kernel.exit(st)
2966
+ else
2967
+ delete
2968
+ st
2969
+ end
2970
+ end
2971
+
2972
+ def exit!(st = false)
2973
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
2974
+ if master? && !safe? && allow_ruby_exit?
2975
+ Kernel.exit!(st)
2976
+ else
2977
+ delete
2978
+ st
2979
+ end
2980
+ end
2981
+
2982
+ def restart(app_name = nil, keys = {})
2983
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
2984
+
2985
+ _init_ip_internal(@@INIT_IP_ENV, @@ADD_TK_PROCS)
2986
+
2987
+ @interp._invoke('set', 'argv0', app_name) if app_name
2988
+ if keys.kind_of?(Hash)
2989
+ @interp._invoke('set', 'argv', _keys2opts(keys))
2990
+ end
2991
+
2992
+ @interp.restart
2993
+ end
2994
+
2995
+ def __eval(str)
2996
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
2997
+ @interp.__eval(str)
2998
+ end
2999
+
3000
+ def __invoke(*args)
3001
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3002
+ @interp.__invoke(*args)
3003
+ end
3004
+
3005
+ def _eval(str)
3006
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3007
+ @interp._eval(str)
3008
+ end
3009
+
3010
+ def _invoke(*args)
3011
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3012
+ @interp._invoke(*args)
3013
+ end
3014
+
3015
+ def _eval_without_enc(str)
3016
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3017
+ @interp._eval_without_enc(str)
3018
+ end
3019
+
3020
+ def _invoke_without_enc(*args)
3021
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3022
+ @interp._invoke_without_enc(*args)
3023
+ end
3024
+
3025
+ def _eval_with_enc(str)
3026
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3027
+ @interp._eval_with_enc(str)
3028
+ end
3029
+
3030
+ def _invoke_with_enc(*args)
3031
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3032
+ @interp._invoke_with_enc(*args)
3033
+ end
3034
+
3035
+ def _toUTF8(str, encoding=nil)
3036
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3037
+ @interp._toUTF8(str, encoding)
3038
+ end
3039
+
3040
+ def _fromUTF8(str, encoding=nil)
3041
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3042
+ @interp._fromUTF8(str, encoding)
3043
+ end
3044
+
3045
+ def _thread_vwait(var)
3046
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3047
+ @interp._thread_vwait(var)
3048
+ end
3049
+
3050
+ def _thread_tkwait(mode, target)
3051
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3052
+ @interp._thread_tkwait(mode, target)
3053
+ end
3054
+
3055
+ def _return_value
3056
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3057
+ @interp._return_value
3058
+ end
3059
+
3060
+ def _get_variable(var, flag)
3061
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3062
+ @interp._get_variable(var, flag)
3063
+ end
3064
+ def _get_variable2(var, idx, flag)
3065
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3066
+ @interp._get_variable2(var, idx, flag)
3067
+ end
3068
+ def _set_variable(var, value, flag)
3069
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3070
+ @interp._set_variable(var, value, flag)
3071
+ end
3072
+ def _set_variable2(var, idx, value, flag)
3073
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3074
+ @interp._set_variable2(var, idx, value, flag)
3075
+ end
3076
+ def _unset_variable(var, flag)
3077
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3078
+ @interp._unset_variable(var, flag)
3079
+ end
3080
+ def _unset_variable2(var, idx, flag)
3081
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3082
+ @interp._unset_variable2(var, idx, flag)
3083
+ end
3084
+
3085
+ def _get_global_var(var)
3086
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3087
+ @interp._get_global_var(var)
3088
+ end
3089
+ def _get_global_var2(var, idx)
3090
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3091
+ @interp._get_global_var2(var, idx)
3092
+ end
3093
+ def _set_global_var(var, value)
3094
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3095
+ @interp._set_global_var(var, value)
3096
+ end
3097
+ def _set_global_var2(var, idx, value)
3098
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3099
+ @interp._set_global_var2(var, idx, value)
3100
+ end
3101
+ def _unset_global_var(var)
3102
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3103
+ @interp._unset_global_var(var)
3104
+ end
3105
+ def _unset_global_var2(var, idx)
3106
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3107
+ @interp._unset_global_var2(var, idx)
3108
+ end
3109
+
3110
+ def _make_menu_embeddable(menu_path)
3111
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3112
+ @interp._make_menu_embeddable(menu_path)
3113
+ end
3114
+
3115
+ def _split_tklist(str)
3116
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3117
+ @interp._split_tklist(str)
3118
+ end
3119
+ def _merge_tklist(*args)
3120
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3121
+ @interp._merge_tklist(*args)
3122
+ end
3123
+ def _conv_listelement(arg)
3124
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3125
+ @interp._conv_listelement(arg)
3126
+ end
3127
+ end
3128
+
3129
+
3130
+ # interp command support
3131
+ class MultiTkIp
3132
+ def _lst2ary(str)
3133
+ return [] if str == ""
3134
+ idx = str.index('{')
3135
+ while idx and idx > 0 and str[idx-1] == ?\\
3136
+ idx = str.index('{', idx+1)
3137
+ end
3138
+ return str.split unless idx
3139
+
3140
+ list = str[0,idx].split
3141
+ str = str[idx+1..-1]
3142
+ i = -1
3143
+ brace = 1
3144
+ str.each_byte {|c|
3145
+ c = c.chr
3146
+ i += 1
3147
+ brace += 1 if c == '{'
3148
+ brace -= 1 if c == '}'
3149
+ break if brace == 0
3150
+ }
3151
+ if i == 0
3152
+ list.push ''
3153
+ elsif str[0, i] == ' '
3154
+ list.push ' '
3155
+ else
3156
+ list.push str[0..i-1]
3157
+ end
3158
+ #list += _lst2ary(str[i+1..-1])
3159
+ list.concat(_lst2ary(str[i+1..-1]))
3160
+ list
3161
+ end
3162
+ private :_lst2ary
3163
+
3164
+ def _slavearg(slave)
3165
+ if slave.kind_of?(MultiTkIp)
3166
+ slave.path
3167
+ elsif slave.kind_of?(String)
3168
+ slave
3169
+ else
3170
+ slave.to_s
3171
+ end
3172
+ end
3173
+ private :_slavearg
3174
+
3175
+ def alias_info(slave, cmd_name)
3176
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3177
+ _lst2ary(@interp._invoke('interp', 'alias', _slavearg(slave), cmd_name))
3178
+ end
3179
+ def self.alias_info(slave, cmd_name)
3180
+ __getip.alias_info(slave, cmd_name)
3181
+ end
3182
+
3183
+ def alias_delete(slave, cmd_name)
3184
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3185
+ @interp._invoke('interp', 'alias', _slavearg(slave), cmd_name, '')
3186
+ self
3187
+ end
3188
+ def self.alias_delete(slave, cmd_name)
3189
+ __getip.alias_delete(slave, cmd_name)
3190
+ self
3191
+ end
3192
+
3193
+ def def_alias(slave, new_cmd, org_cmd, *args)
3194
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3195
+ ret = @interp._invoke('interp', 'alias', _slavearg(slave), new_cmd,
3196
+ '', org_cmd, *args)
3197
+ (ret == new_cmd)? self: nil
3198
+ end
3199
+ def self.def_alias(slave, new_cmd, org_cmd, *args)
3200
+ ret = __getip.def_alias(slave, new_cmd, org_cmd, *args)
3201
+ (ret == new_cmd)? self: nil
3202
+ end
3203
+
3204
+ def aliases(slave = '')
3205
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3206
+ _lst2ary(@interp._invoke('interp', 'aliases', _slavearg(slave)))
3207
+ end
3208
+ def self.aliases(slave = '')
3209
+ __getip.aliases(slave)
3210
+ end
3211
+
3212
+ def delete_slaves(*args)
3213
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3214
+ slaves = args.collect{|s| _slavearg(s)}
3215
+ @interp._invoke('interp', 'delete', *slaves) if slaves.size > 0
3216
+ self
3217
+ end
3218
+ def self.delete_slaves(*args)
3219
+ __getip.delete_slaves(*args)
3220
+ self
3221
+ end
3222
+
3223
+ def exist?(slave = '')
3224
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3225
+ ret = @interp._invoke('interp', 'exists', _slavearg(slave))
3226
+ (ret == '1')? true: false
3227
+ end
3228
+ def self.exist?(slave = '')
3229
+ __getip.exist?(slave)
3230
+ end
3231
+
3232
+ def delete_cmd(slave, cmd)
3233
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3234
+ slave_invoke = @interp._invoke('list', 'rename', cmd, '')
3235
+ @interp._invoke('interp', 'eval', _slavearg(slave), slave_invoke)
3236
+ self
3237
+ end
3238
+ def self.delete_cmd(slave, cmd)
3239
+ __getip.delete_cmd(slave, cmd)
3240
+ self
3241
+ end
3242
+
3243
+ def expose_cmd(slave, cmd, aliasname = nil)
3244
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3245
+ if aliasname
3246
+ @interp._invoke('interp', 'expose', _slavearg(slave), cmd, aliasname)
3247
+ else
3248
+ @interp._invoke('interp', 'expose', _slavearg(slave), cmd)
3249
+ end
3250
+ self
3251
+ end
3252
+ def self.expose_cmd(slave, cmd, aliasname = nil)
3253
+ __getip.expose_cmd(slave, cmd, aliasname)
3254
+ self
3255
+ end
3256
+
3257
+ def hide_cmd(slave, cmd, aliasname = nil)
3258
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3259
+ if aliasname
3260
+ @interp._invoke('interp', 'hide', _slavearg(slave), cmd, aliasname)
3261
+ else
3262
+ @interp._invoke('interp', 'hide', _slavearg(slave), cmd)
3263
+ end
3264
+ self
3265
+ end
3266
+ def self.hide_cmd(slave, cmd, aliasname = nil)
3267
+ __getip.hide_cmd(slave, cmd, aliasname)
3268
+ self
3269
+ end
3270
+
3271
+ def hidden_cmds(slave = '')
3272
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3273
+ _lst2ary(@interp._invoke('interp', 'hidden', _slavearg(slave)))
3274
+ end
3275
+ def self.hidden_cmds(slave = '')
3276
+ __getip.hidden_cmds(slave)
3277
+ end
3278
+
3279
+ def invoke_hidden(slave, cmd, *args)
3280
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3281
+ if args[-1].kind_of?(Hash)
3282
+ keys = _symbolkey2str(args.pop)
3283
+ else
3284
+ keys = []
3285
+ end
3286
+ keys << _slavearg(slave)
3287
+ if Tk::TCL_MAJOR_VERSION > 8 ||
3288
+ (Tk::TCL_MAJOR_VERSION == 8 && Tk::TCL_MINOR_VERSION >= 5)
3289
+ keys << '--'
3290
+ end
3291
+ keys << cmd
3292
+ keys.concat(args)
3293
+ @interp._invoke('interp', 'invokehidden', *keys)
3294
+ end
3295
+ def self.invoke_hidden(slave, cmd, *args)
3296
+ __getip.invoke_hidden(slave, cmd, *args)
3297
+ end
3298
+
3299
+ def invoke_hidden_on_global(slave, cmd, *args)
3300
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3301
+ if args[-1].kind_of?(Hash)
3302
+ keys = _symbolkey2str(args.pop)
3303
+ else
3304
+ keys = []
3305
+ end
3306
+ keys << _slavearg(slave)
3307
+ keys << '-global'
3308
+ if Tk::TCL_MAJOR_VERSION > 8 ||
3309
+ (Tk::TCL_MAJOR_VERSION == 8 && Tk::TCL_MINOR_VERSION >= 5)
3310
+ keys << '--'
3311
+ end
3312
+ keys << cmd
3313
+ keys.concat(args)
3314
+ @interp._invoke('interp', 'invokehidden', *keys)
3315
+ end
3316
+ def self.invoke_hidden_on_global(slave, cmd, *args)
3317
+ __getip.invoke_hidden_on_global(slave, cmd, *args)
3318
+ end
3319
+
3320
+ def invoke_hidden_on_namespace(slave, ns, cmd, *args)
3321
+ # for Tcl8.5 or later
3322
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3323
+ if args[-1].kind_of?(Hash)
3324
+ keys = _symbolkey2str(args.pop)
3325
+ else
3326
+ keys = []
3327
+ end
3328
+ keys << _slavearg(slave)
3329
+ keys << '-namespace' << TkComm._get_eval_string(ns)
3330
+ keys << '--' << cmd
3331
+ keys.concat(args)
3332
+ @interp._invoke('interp', 'invokehidden', *keys)
3333
+ end
3334
+ def self.invoke_hidden_on_namespace(slave, ns, cmd, *args)
3335
+ __getip.invoke_hidden_on_namespace(slave, ns, cmd, *args)
3336
+ end
3337
+
3338
+ def mark_trusted(slave = '')
3339
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3340
+ @interp._invoke('interp', 'marktrusted', _slavearg(slave))
3341
+ self
3342
+ end
3343
+ def self.mark_trusted(slave = '')
3344
+ __getip.mark_trusted(slave)
3345
+ self
3346
+ end
3347
+
3348
+ def set_bgerror_handler(cmd = Proc.new, slave = nil, &b)
3349
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3350
+
3351
+ unless TkComm._callback_entry?(cmd)
3352
+ if !slave && b
3353
+ slave = cmd
3354
+ cmd = Proc.new(&b)
3355
+ end
3356
+ end
3357
+ slave = '' unless slave
3358
+
3359
+ @interp._invoke('interp', 'bgerror', _slavearg(slave), cmd)
3360
+ end
3361
+ def self.bgerror(cmd = Proc.new, slave = nil, &b)
3362
+ __getip.bgerror(cmd, slave, &b)
3363
+ end
3364
+
3365
+ def get_bgerror_handler(slave = '')
3366
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3367
+ procedure(@interp._invoke('interp', 'bgerror', _slavearg(slave)))
3368
+ end
3369
+ def self.bgerror(slave = '')
3370
+ __getip.bgerror(slave)
3371
+ end
3372
+
3373
+ def set_limit(limit_type, slave = '', opts = {})
3374
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3375
+ @interp._invoke('interp', 'limit', _slavearg(slave), limit_type, opts)
3376
+ end
3377
+ def self.set_limit(limit_type, slave = '', opts = {})
3378
+ __getip.set_limit(limit_type, slave, opts)
3379
+ end
3380
+
3381
+ def get_limit(limit_type, slave = '', slot = nil)
3382
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3383
+
3384
+ if slot
3385
+ num_or_str(@interp._invoke('interp', 'limit', _slavearg(slave),
3386
+ limit_type, slot))
3387
+ else
3388
+ l = @interp._split_tklist(@interp._invoke_without_enc('interp', 'limit',
3389
+ _slavearg(slave),
3390
+ limit_type))
3391
+ l.map!{|s| _fromUTF8(s)}
3392
+ r = {}
3393
+ until l.empty?
3394
+ key = l.shift[1..-1]
3395
+ val = l.shift
3396
+ val = num_or_str(val) if val
3397
+ r[key] = val
3398
+ end
3399
+ r
3400
+ end
3401
+ end
3402
+ def self.get_limit(limit_type, slave = '', slot = nil)
3403
+ __getip.get_limit(limit_type, slave, slot)
3404
+ end
3405
+
3406
+ def recursion_limit(slave = '', limit = None)
3407
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3408
+ number(@interp._invoke('interp', 'recursionlimit',
3409
+ _slavearg(slave), limit))
3410
+ end
3411
+ def self.recursion_limit(slave = '', limit = None)
3412
+ __getip.recursion_limit(slave)
3413
+ end
3414
+
3415
+ def alias_target(aliascmd, slave = '')
3416
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3417
+ @interp._invoke('interp', 'target', _slavearg(slave), aliascmd)
3418
+ end
3419
+ def self.alias_target(aliascmd, slave = '')
3420
+ __getip.alias_target(aliascmd, slave)
3421
+ end
3422
+
3423
+ def share_stdin(dist, src = '')
3424
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3425
+ @interp._invoke('interp', 'share', src, 'stdin', dist)
3426
+ self
3427
+ end
3428
+ def self.share_stdin(dist, src = '')
3429
+ __getip.share_stdin(dist, src)
3430
+ self
3431
+ end
3432
+
3433
+ def share_stdout(dist, src = '')
3434
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3435
+ @interp._invoke('interp', 'share', src, 'stdout', dist)
3436
+ self
3437
+ end
3438
+ def self.share_stdout(dist, src = '')
3439
+ __getip.share_stdout(dist, src)
3440
+ self
3441
+ end
3442
+
3443
+ def share_stderr(dist, src = '')
3444
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3445
+ @interp._invoke('interp', 'share', src, 'stderr', dist)
3446
+ self
3447
+ end
3448
+ def self.share_stderr(dist, src = '')
3449
+ __getip.share_stderr(dist, src)
3450
+ self
3451
+ end
3452
+
3453
+ def transfer_stdin(dist, src = '')
3454
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3455
+ @interp._invoke('interp', 'transfer', src, 'stdin', dist)
3456
+ self
3457
+ end
3458
+ def self.transfer_stdin(dist, src = '')
3459
+ __getip.transfer_stdin(dist, src)
3460
+ self
3461
+ end
3462
+
3463
+ def transfer_stdout(dist, src = '')
3464
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3465
+ @interp._invoke('interp', 'transfer', src, 'stdout', dist)
3466
+ self
3467
+ end
3468
+ def self.transfer_stdout(dist, src = '')
3469
+ __getip.transfer_stdout(dist, src)
3470
+ self
3471
+ end
3472
+
3473
+ def transfer_stderr(dist, src = '')
3474
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3475
+ @interp._invoke('interp', 'transfer', src, 'stderr', dist)
3476
+ self
3477
+ end
3478
+ def self.transfer_stderr(dist, src = '')
3479
+ __getip.transfer_stderr(dist, src)
3480
+ self
3481
+ end
3482
+
3483
+ def share_stdio(dist, src = '')
3484
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3485
+ @interp._invoke('interp', 'share', src, 'stdin', dist)
3486
+ @interp._invoke('interp', 'share', src, 'stdout', dist)
3487
+ @interp._invoke('interp', 'share', src, 'stderr', dist)
3488
+ self
3489
+ end
3490
+ def self.share_stdio(dist, src = '')
3491
+ __getip.share_stdio(dist, src)
3492
+ self
3493
+ end
3494
+
3495
+ def transfer_stdio(dist, src = '')
3496
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3497
+ @interp._invoke('interp', 'transfer', src, 'stdin', dist)
3498
+ @interp._invoke('interp', 'transfer', src, 'stdout', dist)
3499
+ @interp._invoke('interp', 'transfer', src, 'stderr', dist)
3500
+ self
3501
+ end
3502
+ def self.transfer_stdio(dist, src = '')
3503
+ __getip.transfer_stdio(dist, src)
3504
+ self
3505
+ end
3506
+ end
3507
+
3508
+
3509
+ # Safe Base :: manipulating safe interpreter
3510
+ class MultiTkIp
3511
+ def safeip_configure(slot, value=None)
3512
+ # use for '-noStatics' option ==> {statics=>false}
3513
+ # for '-nestedLoadOk' option ==> {nested=>true}
3514
+ if slot.kind_of?(Hash)
3515
+ ip = MultiTkIp.__getip
3516
+ ip._eval('::safe::interpConfigure ' + @ip_name + ' ' + _keys2opts(slot))
3517
+ else
3518
+ ip._eval('::safe::interpConfigure ' + @ip_name + ' ' +
3519
+ "-#{slot} #{_get_eval_string(value)}")
3520
+ end
3521
+ self
3522
+ end
3523
+
3524
+ def safeip_configinfo(slot = nil)
3525
+ ip = MultiTkIp.__getip
3526
+ ret = {}
3527
+ if slot
3528
+ conf = _lst2ary(ip._eval("::safe::interpConfigure " +
3529
+ @ip_name + " -#{slot}"))
3530
+ if conf[0] == '-deleteHook'
3531
+ =begin
3532
+ if conf[1] =~ /^rb_out\S* (c(_\d+_)?\d+)/
3533
+ ret[conf[0][1..-1]] = MultiTkIp._tk_cmd_tbl[$1]
3534
+ =end
3535
+ if conf[1] =~ /rb_out\S*(?:\s+(::\S*|[{](::.*)[}]|["](::.*)["]))? (c(_\d+_)?(\d+))/
3536
+ ret[conf[0][1..-1]] = MultiTkIp._tk_cmd_tbl[$4]
3537
+ else
3538
+ ret[conf[0][1..-1]] = conf[1]
3539
+ end
3540
+ else
3541
+ ret[conf[0][1..-1]] = conf[1]
3542
+ end
3543
+ else
3544
+ Hash[*_lst2ary(ip._eval("::safe::interpConfigure " +
3545
+ @ip_name))].each{|k, v|
3546
+ if k == '-deleteHook'
3547
+ =begin
3548
+ if v =~ /^rb_out\S* (c(_\d+_)?\d+)/
3549
+ ret[k[1..-1]] = MultiTkIp._tk_cmd_tbl[$1]
3550
+ =end
3551
+ if v =~ /rb_out\S*(?:\s+(::\S*|[{](::.*)[}]|["](::.*)["]))? (c(_\d+_)?(\d+))/
3552
+ ret[k[1..-1]] = MultiTkIp._tk_cmd_tbl[$4]
3553
+ else
3554
+ ret[k[1..-1]] = v
3555
+ end
3556
+ else
3557
+ ret[k[1..-1]] = v
3558
+ end
3559
+ }
3560
+ end
3561
+ ret
3562
+ end
3563
+
3564
+ def safeip_delete
3565
+ ip = MultiTkIp.__getip
3566
+ ip._eval("::safe::interpDelete " + @ip_name)
3567
+ end
3568
+
3569
+ def safeip_add_to_access_path(dir)
3570
+ ip = MultiTkIp.__getip
3571
+ ip._eval("::safe::interpAddToAccessPath #{@ip_name} #{dir}")
3572
+ end
3573
+
3574
+ def safeip_find_in_access_path(dir)
3575
+ ip = MultiTkIp.__getip
3576
+ ip._eval("::safe::interpFindInAccessPath #{@ip_name} #{dir}")
3577
+ end
3578
+
3579
+ def safeip_set_log_cmd(cmd = Proc.new)
3580
+ ip = MultiTkIp.__getip
3581
+ ip._eval("::safe::setLogCmd #{@ip_name} #{_get_eval_string(cmd)}")
3582
+ end
3583
+ end
3584
+
3585
+
3586
+ # encoding convert
3587
+ class << MultiTkIp
3588
+ def encoding_table
3589
+ __getip.encoding_table
3590
+ end
3591
+
3592
+ def force_default_encoding=(mode)
3593
+ __getip.force_default_encoding=(mode)
3594
+ end
3595
+
3596
+ def force_default_encoding?
3597
+ __getip.force_default_encoding?
3598
+ end
3599
+
3600
+ def default_encoding=(enc)
3601
+ __getip.default_encoding=(enc)
3602
+ end
3603
+
3604
+ def encoding=(enc)
3605
+ __getip.encoding=(enc)
3606
+ end
3607
+
3608
+ def encoding_name
3609
+ __getip.encoding_name
3610
+ end
3611
+
3612
+ def encoding_obj
3613
+ __getip.encoding_obj
3614
+ end
3615
+ alias encoding encoding_name
3616
+ alias default_encoding encoding_name
3617
+
3618
+ def encoding_convertfrom(str, enc=None)
3619
+ __getip.encoding_convertfrom(str, enc)
3620
+ end
3621
+ alias encoding_convert_from encoding_convertfrom
3622
+
3623
+ def encoding_convertto(str, enc=None)
3624
+ __getip.encoding_convertto(str, enc)
3625
+ end
3626
+ alias encoding_convert_to encoding_convertto
3627
+ end
3628
+ class MultiTkIp
3629
+ def encoding_table
3630
+ @interp.encoding_table
3631
+ end
3632
+
3633
+ def force_default_encoding=(mode)
3634
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3635
+ @interp.force_default_encoding = mode
3636
+ end
3637
+ def force_default_encoding?
3638
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3639
+ @interp.force_default_encoding?
3640
+ end
3641
+
3642
+ def default_encoding=(enc)
3643
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3644
+ @interp.default_encoding = enc
3645
+ end
3646
+
3647
+ def encoding=(enc)
3648
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3649
+ @interp.encoding = enc
3650
+ end
3651
+ def encoding_name
3652
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3653
+ @interp.encoding_name
3654
+ end
3655
+ def encoding_obj
3656
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3657
+ @interp.encoding_obj
3658
+ end
3659
+ alias encoding encoding_name
3660
+ alias default_encoding encoding_name
3661
+
3662
+ def encoding_convertfrom(str, enc=None)
3663
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3664
+ @interp.encoding_convertfrom(str, enc)
3665
+ end
3666
+ alias encoding_convert_from encoding_convertfrom
3667
+
3668
+ def encoding_convertto(str, enc=None)
3669
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
3670
+ @interp.encoding_convertto(str, enc)
3671
+ end
3672
+ alias encoding_convert_to encoding_convertto
3673
+ end
3674
+
3675
+
3676
+ # remove methods for security
3677
+ =begin
3678
+ class MultiTkIp
3679
+ INTERP_THREAD = @@DEFAULT_MASTER.instance_variable_get('@interp_thread')
3680
+ INTERP_MUTEX = INTERP_THREAD[:mutex]
3681
+ INTERP_ROOT_CHECK = INTERP_THREAD[:root_check]
3682
+
3683
+ # undef_method :instance_eval
3684
+ undef_method :instance_variable_get
3685
+ undef_method :instance_variable_set
3686
+ end
3687
+
3688
+ module TkCore
3689
+ if MultiTkIp::WITH_RUBY_VM &&
3690
+ ! MultiTkIp::RUN_EVENTLOOP_ON_MAIN_THREAD ### check Ruby 1.9 !!!!!!!
3691
+ INTERP_THREAD = MultiTkIp::INTERP_THREAD
3692
+ INTERP_MUTEX = MultiTkIp::INTERP_MUTEX
3693
+ INTERP_ROOT_CHECK = MultiTkIp::INTERP_ROOT_CHECK
3694
+ end
3695
+ end
3696
+ class MultiTkIp
3697
+ remove_const(:INTERP_THREAD)
3698
+ remove_const(:INTERP_MUTEX)
3699
+ remove_const(:INTERP_ROOT_CHECK)
3700
+ end
3701
+ =end
3702
+ if MultiTkIp::WITH_RUBY_VM &&
3703
+ ! MultiTkIp::RUN_EVENTLOOP_ON_MAIN_THREAD ### check Ruby 1.9 !!!!!!!
3704
+ class MultiTkIp
3705
+ INTERP_THREAD = @@DEFAULT_MASTER.instance_variable_get('@interp_thread')
3706
+ INTERP_THREAD_STATUS = INTERP_THREAD[:status]
3707
+ INTERP_MUTEX = INTERP_THREAD[:mutex]
3708
+ INTERP_ROOT_CHECK = INTERP_THREAD[:root_check]
3709
+ end
3710
+ module TkCore
3711
+ INTERP_THREAD = MultiTkIp::INTERP_THREAD
3712
+ INTERP_THREAD_STATUS = MultiTkIp::INTERP_THREAD_STATUS
3713
+ INTERP_MUTEX = MultiTkIp::INTERP_MUTEX
3714
+ INTERP_ROOT_CHECK = MultiTkIp::INTERP_ROOT_CHECK
3715
+ end
3716
+ class MultiTkIp
3717
+ remove_const(:INTERP_THREAD)
3718
+ remove_const(:INTERP_THREAD_STATUS)
3719
+ remove_const(:INTERP_MUTEX)
3720
+ remove_const(:INTERP_ROOT_CHECK)
3721
+ end
3722
+ end
3723
+
3724
+ class MultiTkIp
3725
+ # undef_method :instance_eval
3726
+ undef_method :instance_variable_get
3727
+ undef_method :instance_variable_set
3728
+ end
3729
+ # end of MultiTkIp definition
3730
+
3731
+ # defend against modification
3732
+ #MultiTkIp.freeze
3733
+ #TclTkLib.freeze
3734
+
3735
+ ########################################
3736
+ # start Tk which depends on MultiTkIp
3737
+ module TkCore
3738
+ INTERP = MultiTkIp
3739
+ end
3740
+ require 'tk'