LoginSignup
12
13

More than 5 years have passed since last update.

【Ruby】GTKでなんか外部から攻撃を受けているときのアレを再現

Posted at

GTKを使って、アニメなどでよくあるオペレータやハッカーっぽい人がなんか外部から攻撃を受けているとき画面いっぱいに警告ウィンドウが出てくるアレをつくりました。

warning_window.gif

動作環境

  • Ubuntu 14.04
  • Ruby 2.2.0
  • gtk2 3.0.7 (gem)

必要なもののインストール

$ gem install gtk2

ソースコード

使用した画像はソースコードと併せてここ(→ https://gist.github.com/seinosuke/9e615852063807427dab )においてあります。自分ではしょぼい画像しかつくれなかったので、もっとそれっぽい画像を用意すればそれっぽさが増すと思います。

ソースコードは以下の通りです。Rubyです。

main.rb
require 'gtk2'
include Math

WIDTH = 1280 # 画面の幅
HEIGHT = 800 # 画面の高さ
MAX = 30 # 表示するウィンドウの数

# 使用する色
COLOR_DICT = {
  :yellow => Gdk::Color.new(65535, 65535, 0),
  :black => Gdk::Color.new(0, 0, 0),
}
colormap = Gdk::Colormap.system
COLOR_DICT.each do |_, color|
  colormap.alloc_color(color, false, true)
end

# 生成される警告ウィンドウ
class WarningWindow < Gtk::Window
  def initialize
    super(Gtk::Window::POPUP)
    @width = 300  # ウィンドウの幅
    @height = 150 # ウィンドウの高さ

    m = [WIDTH/2 - @width/2, HEIGHT/2 - @height/2]
    s = [WIDTH/8, HEIGHT/8]
    @x, @y = box_muller(m, s)
    @x_adder = [-2, -1, 1, 2].sample
    @y_adder = [-2, -1, 1, 2].sample

    self.move(@x, @y)
    self.set_size_request(@width, @height)
    self.set_app_paintable(true)
    self.set_title("WARNING!!")

    self.realize
    @drawable = self.window
    @gc = Gdk::GC.new(@drawable)
    @gc.set_line_attributes(20, Gdk::GC::LINE_SOLID, Gdk::GC::CAP_ROUND, Gdk::GC::JOIN_BEVEL)

    # 画像を表示
    source = ["./msg_warning.png", "./msg_danger.png"].sample
    @image = Gtk::Image.new(source)
    self.add(@image)

    # 縞模様用のカウンタ
    @counters = (-1..5).map do |i|
      ->(init, max) do
        n = init
        -> { n == max - 1 ? n = -50 : n += 1 }
      end[i*50, @width]
    end
  end

  # 縞模様を流すアニメーション
  def add_task
    Gtk.timeout_add(20) do
      @x += @x_adder
      @y += @y_adder
      @x_adder *= -1 if @x < 0 || @x > WIDTH - @width
      @y_adder *= -1 if @y < 0 || @y > HEIGHT - @height
      # self.move(@x, @y)
      clear
      draw
    end
  end

  # 黒い斜め線を描画
  def draw
    @gc.set_foreground(COLOR_DICT[:black])
    @counters.each do |counter|
      from = [counter[], 0]
      to = [from[0] + 50 ,@height]
      @drawable.draw_line(@gc, *from, *to)
    end
  end

  # 背景を黄色で描画
  def clear
    @gc.set_foreground(COLOR_DICT[:yellow])
    @drawable.draw_rectangle(@gc, true, 0, 0, @width, @height)
  end

  private

  # ウィンドウの出現位置を散らすため
  def box_muller(m = [0, 0], s = [1, 1])
    r1 = rand
    r2 = rand
    x = sqrt(-2 * log(r1)) * cos(2*PI * r2)
    y = sqrt(-2 * log(r1)) * sin(2*PI * r2)
    [s[0] * x + m[0], s[1] * y + m[1]]
  end
end


wins = []
Gtk.timeout_add(100) do
  wins << WarningWindow.new
  wins.last.show_all

  # たまにどれか消える
  if rand < 0.3
    win = wins.sample
    win.destroy
    wins.delete(win)
  end

  # MAXを越えたらこれ以上ウィンドウは増えない
  if wins.size > MAX
    sleep 1
    wins.each(&:add_task)
    true
  end.!
end

begin
  Gtk.main
rescue Interrupt
  Gtk.main_quit
end

add_task メソッド内は指定した数のウィンドウが全て出力し終わったら定期的に実行される処理です(最後に縞模様を流してるのはそれっぽい演出のつもりです)。その中の self.move(@x, @y) のコメントアウトを外すと以下のように画面内をウィンドウがごちゃごちゃ動き回るようになります。

warning_window_move.gif

おわりに

これを使えば誰でも、なんか攻撃を受けてるハッカーごっこができます。また、突然画面を隠さないといけない時などにも便利です。

GTKについてはまだあまり詳しくないので、ご意見ご指摘等ありましたらよろしくお願いします。

参考サイト
ウインドウへの直接描画(Gdk::Drawable編)
自作ペイントソフトで筆のような効果を出す

12
13
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
13