rubywxruby

Display multiple instances of a shaped window/image on desktop?


I'm trying to display an image multiple times on the desktop in different positions but I'm not sure how to go about it. Right now I'm trying out Wxruby but I'm wondering if there is another way to do it that I'm missing.

So far I'm able to display one image at one position with wxruby pretty much from one of the samples:

require 'wx'
include Wx

class Warning < Wx::App
  include Wx
  def on_init(x = 300, y = 300)
    @frame = Frame.new( nil, -1, "Application", Point.new(x,y), Size.new(50,50), FRAME_SHAPED|SIMPLE_BORDER|FRAME_NO_TASKBAR|STAY_ON_TOP)
    @frame.show
    @has_shape = false
    @delta = [0,0]

    evt_paint {on_paint}

    shape = File.join( 'pathToImage' )
    @bmp = Bitmap.new( Image.new(shape) )
    @frame.set_client_size(@bmp.width, @bmp.height)

    if PLATFORM == 'WXGTK'
      # wxGTK requires that the window be created before you can
      # set its shape, so delay the call to SetWindowShape until
      # this event.
      evt_window_create { set_window_shape }
    else
      # On wxMSW and wxMac the window has already been created, so go for it.
      set_window_shape
    end

    #@frame.paint { | dc | dc.draw_bitmap(@bmp, 0, 0, true) }
  end

  def set_window_shape
    r = Region.new(@bmp)
    @has_shape = @frame.set_shape(r)
  end

  def on_paint
    @frame.paint { | dc | dc.draw_bitmap(@bmp, 0, 0, true) }
  end
end

app = Warning.new
app.main_loop

Solution

  • I finally figured it out! This ruby script uses the wx gem to display the shaped windows and uses some windows stuff to get the current screen resolution(I assume of the primary monitor).

    It gets the resolution then the width/height of the image you want to display across the desktop. One note on the image, it appears that when wx displays an image(I don't know if its just for shaped windows or not) any part of the image that is solid black is not display but instead you see what is behind the window.

    Hope this save someone some trouble later on, or if not oh well.

    require 'wx'
    require 'dl/import'
    require 'dl/struct'
    include Wx
    
    class Warning < Wx::Frame
      include Wx
        @@x = 0
        @@y = 0
      def setXY(x = 0, y = 0)
        @@x = x
        @@y = y
      end
      def initialize(parent, bmp)
        super(nil, -1, '', pos = [@@x,@@y], size = DEFAULT_SIZE, style = FRAME_SHAPED|SIMPLE_BORDER|FRAME_NO_TASKBAR|STAY_ON_TOP)
        @has_shape = false
        @delta = [0,0]
        @bmp = bmp
    
        evt_paint {on_paint}
        self.set_client_size(@bmp.width, @bmp.height)
    
        if PLATFORM == 'WXGTK'
          # wxGTK requires that the window be created before you can
          # set its shape, so delay the call to SetWindowShape until
          # this event.
          evt_window_create { set_window_shape }
        else
          # On wxMSW and wxMac the window has already been created, so go for it.
          set_window_shape
        end
        self.paint { | dc | dc.draw_bitmap(@bmp, 0, 0, true) }
      end
    
      def set_window_shape
        r = Region.new(@bmp)
        @has_shape = self.set_shape(r)
      end
    
      def on_paint
        self.paint { | dc | dc.draw_bitmap(@bmp, 0, 0, true) }
      end
    end # of Warning
    
    class WarnTest < Wx::App
      def on_init
        @frame = Frame.new()
        warnings = []
        resolution = getScreenResolution()
        shape = File.join( 'image you want' )
        @bmp = Bitmap.new( Image.new(shape) )
        imageWidth = @bmp.get_width
        imageHeight = @bmp.get_height
    
        imagesAcross = resolution[0] / imageWidth
        imagesDown = resolution[1] / imageHeight
    
        j = 0
        (1..imagesDown).each do |y|
          i = 0
          (1..imagesAcross).each do |x|
            warnings << [(imageWidth * i), (imageHeight * j)]
            i = i + 1
          end
          j = j + 1
        end
    
        warnings << [resolution[0], resolution[1]]
    
        # Create a new window for each xy in warnings array
        warnings.each do |x|
          win = Warning.new(self, @bmp)
          win.setXY(x[0], x[1])
          win.show(true)
          win.update
          sleep 0.01
        end
      end # of on_init
    
      def getScreenResolution
        sM_CXSCREEN =   0
        sM_CYSCREEN =   1
        user32 = DL.dlopen("user32")
    
        get_system_metrics = user32['GetSystemMetrics', 'ILI']
        x, tmp = get_system_metrics.call(sM_CXSCREEN,0)
        y, tmp = get_system_metrics.call(sM_CYSCREEN,0)
        res = [x, y]
        return res
      end # of getScreenResolution
    end # of WarnTest
    
    app = WarnTest.new
    app.main_loop