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

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