1#
2#   tk/virtevent.rb : treats virtual events
3#                     1998/07/16 by Hidetoshi Nagai <nagai@ai.kyutech.ac.jp>
4#
5require 'tk'
6
7class TkVirtualEvent<TkObject
8  extend Tk
9
10  TkCommandNames = ['event'.freeze].freeze
11
12  (TkVirtualEventID = ["VirtEvent".freeze, TkUtil.untrust("00000")]).instance_eval{
13    @mutex = Mutex.new
14    def mutex; @mutex; end
15    freeze
16  }
17
18  TkVirtualEventTBL = TkCore::INTERP.create_table
19
20  TkCore::INTERP.init_ip_env{
21    TkVirtualEventTBL.mutex.synchronize{ TkVirtualEventTBL.clear }
22  }
23
24  class PreDefVirtEvent<self
25    def self.new(event, *sequences)
26      if event =~ /^<(<.*>)>$/
27        event = $1
28      elsif event !~ /^<.*>$/
29        event = '<' + event + '>'
30      end
31      TkVirtualEvent::TkVirtualEventTBL.mutex.synchronize{
32        if TkVirtualEvent::TkVirtualEventTBL.has_key?(event)
33          TkVirtualEvent::TkVirtualEventTBL[event]
34        else
35          # super(event, *sequences)
36          (obj = self.allocate).instance_eval{
37            initialize(event, *sequences)
38            TkVirtualEvent::TkVirtualEventTBL[@id] = self
39          }
40        end
41      }
42    end
43
44    def initialize(event, *sequences)
45      @path = @id = event
46      _add_sequences(sequences)
47    end
48  end
49
50  def TkVirtualEvent.getobj(event)
51    obj = nil
52    TkVirtualEventTBL.mutex.synchronize{
53      obj = TkVirtualEventTBL[event]
54    }
55    if obj
56      obj
57    else
58      if tk_call_without_enc('event', 'info').index("<#{event}>")
59        PreDefVirtEvent.new(event)
60      else
61        fail ArgumentError, "undefined virtual event '<#{event}>'"
62      end
63    end
64  end
65
66  def TkVirtualEvent.info
67    tk_call_without_enc('event', 'info').split(/\s+/).collect!{|seq|
68      TkVirtualEvent.getobj(seq[1..-2])
69    }
70  end
71
72  def initialize(*sequences)
73    TkVirtualEventID.mutex.synchronize{
74      # @path = @id = '<' + TkVirtualEventID.join('') + '>'
75      @path = @id = '<' + TkVirtualEventID.join(TkCore::INTERP._ip_id_) + '>'
76      TkVirtualEventID[1].succ!
77    }
78    _add_sequences(sequences)
79  end
80
81  def _add_sequences(seq_ary)
82    unless seq_ary.empty?
83      tk_call_without_enc('event', 'add', "<#{@id}>",
84                          *(seq_ary.collect{|seq|
85                              "<#{tk_event_sequence(seq)}>"
86                            }) )
87    end
88    self
89  end
90  private :_add_sequences
91
92  def add(*sequences)
93    if sequences != []
94      _add_sequences(sequences)
95      TkVirtualEventTBL.mutex.synchronize{
96        TkVirtualEventTBL[@id] = self
97      }
98    end
99    self
100  end
101
102  def delete(*sequences)
103    if sequences.empty?
104      tk_call_without_enc('event', 'delete', "<#{@id}>")
105      TkVirtualEventTBL.mutex.synchronize{
106        TkVirtualEventTBL.delete(@id)
107      }
108    else
109      tk_call_without_enc('event', 'delete', "<#{@id}>",
110                          *(sequences.collect{|seq|
111                              "<#{tk_event_sequence(seq)}>"
112                            }) )
113      if tk_call_without_enc('event','info',"<#{@id}>").empty?
114        TkVirtualEventTBL.mutex.synchronize{
115          TkVirtualEventTBL.delete(@id)
116        }
117      end
118    end
119    self
120  end
121
122  def info
123    tk_call_without_enc('event','info',"<#{@id}>").split(/\s+/).collect!{|seq|
124      lst = seq.scan(/<*[^<>]+>*/).collect!{|subseq|
125        case (subseq)
126        when /^<<[^<>]+>>$/
127          TkVirtualEvent.getobj(subseq[1..-2])
128        when /^<[^<>]+>$/
129          subseq[1..-2]
130        else
131          subseq.split('')
132        end
133      }.flatten
134      (lst.size == 1) ? lst[0] : lst
135    }
136  end
137end
138
139TkNamedVirtualEvent = TkVirtualEvent::PreDefVirtEvent
140