lib/iconify.rb in iconify-0.2.0 vs lib/iconify.rb in iconify-0.2.1
- old
+ new
@@ -1,130 +1,241 @@
require 'gtk3'
require 'vte3'
-require "iconify/version"
-require "iconify/program"
+require 'iconify/version'
+require 'iconify/program'
module Iconify
+ # メインウィンドウ
+ class TerminalWindow < Gtk::Window
+ include Gtk
-class TerminalWindow < Gtk::Window
- include Gtk
+ type_register
+ signal_new('changed', GLib::Signal::ACTION, nil, nil)
- type_register
- signal_new('changed', GLib::Signal::ACTION, nil, nil)
+ attr_reader :state
- attr_reader :state
+ # [String]
+ def initialize(argv)
+ super()
- def initialize(argv)
- super()
+ @argv = argv
+ @state = :stopped
- @argv = argv
+ update_title
- @terminal = Vte::Terminal.new
- @terminal.font = Pango::FontDescription.new("monospace 14")
- @terminal.set_size_request(@terminal.char_width * 80, @terminal.char_height * 24)
- @terminal.cursor_blink_mode = Vte::CursorBlinkMode::OFF
+ @rerun_button = create_rerun_button
+ @kill_button = create_kill_button
+ @quit_button = create_quit_button
+ @terminal = create_vte_terminal
+ @copy_button = create_copy_button
+ @paste_button = create_paste_button
- self.title = "iconify - #{argv[0]}"
+ layout
- @state = :stopped
+ set_geometry_hints
+ end
- vbox = Box.new(:vertical)
- hbox = ButtonBox.new(:horizontal)
- rerun_button = Button.new(label: "Rerun")
- rerun_button.signal_connect('clicked') do
- self.exec
+ def set_geometry_hints
+ @terminal.realize
+ @terminal.set_geometry_hints_for_window(self)
end
- signal_connect('changed') do
- rerun_button.sensitive = (@state == :stopped)
+
+ def layout
+ vbox = Box.new(:vertical)
+ toolbar = Toolbar.new
+
+ toolbar.add(@rerun_button)
+ toolbar.add(@kill_button)
+ toolbar.add(SeparatorToolItem.new)
+ toolbar.add(@copy_button)
+ toolbar.add(@paste_button)
+ toolbar.add(SeparatorToolItem.new)
+ toolbar.add(@quit_button)
+ vbox.pack_start(toolbar, expand: false)
+
+ padding_box = Box.new(:vertical)
+ padding_box.pack_start(@terminal, expand: true, fill: true)
+ padding_box.border_width = 18
+ override_background_color(StateFlags::NORMAL, COLORS[15])
+ vbox.pack_start(padding_box, expand: true, fill: true)
+
+ add vbox
end
- kill_button = Button.new(label: "Kill")
- kill_button.signal_connect('clicked') do
- Process.kill("KILL", @pid) if @pid
+ def create_copy_button
+ ToolButton.new(stock_id: Stock::COPY).tap do |b|
+ b.tooltip_text = 'Copy'
+ b.signal_connect('clicked') do
+ @terminal.copy_clipboard
+ end
+ end
end
- signal_connect('changed') do
- kill_button.sensitive = (@state == :running)
+
+ def create_paste_button
+ ToolButton.new(stock_id: Stock::PASTE).tap do |b|
+ b.tooltip_text = 'Paste'
+ b.signal_connect('clicked') do
+ @terminal.paste_clipboard
+ end
+ end
end
- quit_button = Button.new(label: "Quit")
- quit_button.signal_connect('clicked') do
- Gtk.main_quit
+ def create_kill_button
+ ToolButton.new(label: 'Kill').tap do |b|
+ b.icon_name = Stock::STOP
+ b.tooltip_text = 'Stop the child process by sending the QUIT signal.'
+ b.signal_connect('clicked') do
+ Process.kill('KILL', @pid) if @pid
+ end
+ end
end
- hbox.pack_start(rerun_button)
- hbox.pack_start(kill_button)
- hbox.pack_start(quit_button)
- vbox.pack_start(hbox, expand: false)
- vbox.pack_start(@terminal, expand: true, fill: true)
- add vbox
+ def create_rerun_button
+ ToolButton.new(label: 'Rerun').tap do |b|
+ b.icon_name = Stock::REFRESH
+ b.tooltip_text = 'Rerun the program.'
+ b.signal_connect('clicked') do
+ exec
+ end
+ end
+ end
- @terminal.signal_connect('child-exited') do
- @state = :stopped
- @pid = nil
- rerun_button.sensitive = true
- signal_emit('changed')
+ def create_quit_button
+ ToolButton.new(label: 'Quit').tap do |b|
+ b.icon_name = Stock::QUIT
+ b.tooltip_text = 'Stop the program and quit.'
+ b.signal_connect('clicked') do
+ Gtk.main_quit
+ end
+ end
end
- end
- def exec
- @pid = @terminal.spawn(argv: @argv)
- @state = :running
- signal_emit('changed')
- end
+ def update_title
+ self.title = "iconify - #{@argv[0]}"
+ end
-end
+ def changed
+ @rerun_button.sensitive = (@state == :stopped)
+ @kill_button.sensitive = (@state == :running)
-class CommandStatusIcon < Gtk::StatusIcon
- include Gtk
+ @copy_button.sensitive = @terminal.has_selection?
- def initialize(name)
- super()
+ signal_emit('changed')
+ end
- @name = name
- end
+ # the shimbun color scheme
+ COLORS = [[0x30, 0x30, 0x30],
+ [0xbe, 0x11, 0x37],
+ [0x29, 0x73, 0x2c],
+ [0xc9, 0x5c, 0x26],
+ [0x2a, 0x5a, 0xa2],
+ [0xcd, 0x3a, 0x93],
+ [0x07, 0x86, 0x92],
+ [0xd0, 0xd0, 0xd0],
+ [0x50, 0x50, 0x50],
+ [0xe6, 0x2b, 0x5d],
+ [0x40, 0x9e, 0x01],
+ [0xec, 0x75, 0x42],
+ [0x17, 0x7f, 0xe0],
+ [0xe9, 0x53, 0xba],
+ [0x00, 0xa9, 0xb2],
+ [0xf2, 0xf2, 0xf2]]
+ .map { |rgb| Gdk::RGBA.new(*rgb.map { |n| n.fdiv(255) }, 1.0) }
- def set_state(state)
- case state
- when :running
- @background_color = [0.67, 1.0, 0.0]
- @foreground_color = [0.1, 0.1, 0.1]
- when :stopped
- @background_color = [192/255.0, 0.0, 0.0]
- @foreground_color = [0.9, 0.9, 0.9]
- else
- raise "unknown sate #{state}"
+ def create_vte_terminal
+ Vte::Terminal.new.tap do |t|
+ t.font = Pango::FontDescription.new('monospace 14')
+ t.set_size_request(t.char_width * 40, t.char_height * 12)
+ t.set_size(80, 24)
+ t.cursor_blink_mode = Vte::CursorBlinkMode::OFF
+ t.set_colors(COLORS[0], COLORS[15], COLORS)
+
+ t.signal_connect('child-exited') do
+ on_child_exited
+ end
+ t.signal_connect('selection-changed') do
+ changed
+ end
+ end
end
- redraw
+
+ def on_child_exited
+ @state = :stopped
+ @pid = nil
+ @rerun_button.sensitive = true
+ changed
+ end
+
+ def exec
+ @pid = @terminal.spawn(argv: @argv)
+ @state = :running
+ changed
+ end
end
- def redraw
- # pixmap = Gdk::Pixmap.new(nil, 64, 64, 24)
+ # プログラム名を表示するステータスアイコン
+ class CommandStatusIcon < Gtk::StatusIcon
+ include Gtk
+ include Cairo
- image_surface = Cairo::ImageSurface.new(Cairo::FORMAT_ARGB32, 64, 64)
+ def initialize(name)
+ super()
- cr = Cairo::Context.new(image_surface)
+ @name = name
+ end
- cr.set_source_rgb(0.8, 0.8, 0.8)
- cr.set_operator(Cairo::OPERATOR_SOURCE)
- cr.paint
+ COLOR_SCHEME = {
+ running: [[0.67, 1.0, 0.0], [0.1, 0.1, 0.1]],
+ stopped: [[0.75, 0.0, 0.0], [0.9, 0.9, 0.9]]
+ }.freeze
- cr.set_source_rgb(*@background_color)
- cr.rounded_rectangle(1, 1, 62, 62, 15)
- cr.fill
+ def update(state)
+ raise "unknown sate #{state}" unless COLOR_SCHEME.key?(state)
- cr.set_font_size(24)
- cr.move_to(3, 64 / 2 + cr.font_extents.ascent / 2)
- cr.set_source_rgba(*@foreground_color, 1)
- cr.show_text(@name)
+ @background_color, @foreground_color = COLOR_SCHEME[state]
+ redraw
+ end
- cr.destroy
+ def using(destroyable)
+ yield destroyable
+ destroyable.destroy
+ end
- buf = image_surface.to_pixbuf(0, 0, 64, 64)
- self.pixbuf = buf
+ def paint_background(cr)
+ cr.save do
+ cr.set_source_rgb(0.8, 0.8, 0.8)
+ cr.set_operator(OPERATOR_SOURCE)
+ cr.paint
+ end
+ end
- image_surface.destroy
- end
+ def fill_rounded_rectangle(cr)
+ cr.save do
+ cr.set_source_rgb(*@background_color)
+ cr.rounded_rectangle(1, 1, 62, 62, 15)
+ cr.fill
+ end
+ end
-end
+ def draw_name(cr)
+ cr.save do
+ cr.set_font_size(24)
+ cr.move_to(3, 64 / 2 + cr.font_extents.ascent / 2)
+ cr.set_source_rgba(*@foreground_color, 1)
+ cr.show_text(@name)
+ end
+ end
+ def redraw
+ using ImageSurface.new(FORMAT_ARGB32, 64, 64) do |surface|
+ using Context.new(surface) do |cr|
+ paint_background(cr)
+ fill_rounded_rectangle(cr)
+ draw_name(cr)
+ end
+
+ self.pixbuf = surface.to_pixbuf(0, 0, 64, 64)
+ end
+ end
+ end
end