class Metasm::Gui::Window

Constants

Keyboard_trad

keypress event keyval traduction table

Attributes

clientheight[R]
clientwidth[R]
clientx[R]
clienty[R]
height[R]
hwnd[RW]
menu[RW]
popups[RW]
width[R]
x[R]
y[R]

Public Class Methods

new(*a, &b) click to toggle source
Calls superclass method
# File metasm/gui/gtk.rb, line 775
def initialize(*a, &b)
        super()

        signal_connect('destroy') { destroy_window }

        @vbox = Gtk::VBox.new
        add @vbox

        @menu = []
        @menubar = Gtk::MenuBar.new
        @accel_group = Gtk::AccelGroup.new

        set_gravity Gdk::Window::GRAVITY_STATIC
        @vbox.add @menubar, 'expand' => false
        @child = nil
        s = Gdk::Screen.default
        set_default_size s.width*3/4, s.height*3/4

        Gtk::Settings.default.gtk_menu_bar_accel = nil        # disable F10 -> focus menubar

        (@@mainwindow_list ||= []) << self

        initialize_window(*a, &b)
        build_menu
        update_menu

        Gtk::Drag.dest_set(self,
                           Gtk::Drag::DEST_DEFAULT_MOTION |
                           Gtk::Drag::DEST_DEFAULT_DROP,
                           [['text/plain', 0, 0], ['text/uri-list', 0, 0]],
                           Gdk::DragContext::ACTION_COPY | Gdk::DragContext::ACTION_MOVE)

        signal_connect('drag_data_received') { |w, dc, x, y, data, info, time|
                dc.targets.each { |target|
                        next if target.name != 'text/plain' and target.name != 'text/uri-list'
                        data.data.each_line { |l|
                                next if not @child or not @child.respond_to? :dragdropfile
                                l = l.chomp.sub(%r{^file://}, '')
                                protect { @child.dragdropfile(l) }
                        }
                }
                Gtk::Drag.finish(dc, true, false, time)
        }

        show_all
end

Public Instance Methods

addsubmenu(menu, *args, &action) click to toggle source

append stuff to a menu arglist: empty = menu separator string = menu entry display name (use a single '_' keyboard for shortcut, eg 'Sho_rtcut' => 'r') :check = menu entry is a checkbox type, add a true/false argument to specify initial value second string = keyboard shortcut (accelerator) - use '^' for Ctrl, and '<up>' for special keys a menu object = this entry will open a submenu (you must specify a name, and action is ignored) the method takes a block or a Proc argument that will be run whenever the menu item is selected

use @menu to reference the top-level menu bar call #update_menu when the menu is done

# File metasm/gui/gtk.rb, line 873
def addsubmenu(menu, *args, &action)
        args << action if action
        menu << args
        menu.last
end
build_menu() click to toggle source
# File metasm/gui/gtk.rb, line 838
def build_menu
end
create_menu_item(menu, entry) click to toggle source
# File metasm/gui/gtk.rb, line 888
def create_menu_item(menu, entry)
        args = entry.dup

        # recognise 'OPEN', 'SAVE' etc, with special icon/localisation
        stock = (Gtk::Stock.constants.map { |c| c.to_s } & args).first
        args.delete stock if stock
        accel = args.grep(/^\^?(\w|<\w+>)$/).first
        args.delete accel if accel
        check = args.delete :check
        action = args.grep(::Proc).first
        args.delete action if action
        if submenu = args.grep(::Array).first
                args.delete submenu
                sm = Gtk::Menu.new
                submenu.each { |e| create_menu_item(sm, e) }
                submenu = sm
        end
        label = args.shift

        if stock
                item = Gtk::ImageMenuItem.new(Gtk::Stock.const_get(stock))
                begin
                        item.label = label if label
                rescue
                        # in some version of gtk, no #label=
                        item = Gtk::MenuItem.new(label) if label
                end
        elsif check
                item = Gtk::CheckMenuItem.new(label)
                item.active = args.shift
        elsif label
                item = Gtk::MenuItem.new(label)
        else
                item = Gtk::MenuItem.new
        end
        item.set_submenu(submenu) if submenu

        if accel
                key = accel[-1]
                if key == ?>
                        key = accel[/<(.*)>/, 1]
                        key = DrawableWidget::Keyboard_trad.index(case key
                          when 'enter', 'esc', 'tab', /^f(\d\d?)$/i; key.downcase.to_sym
                          else ??
                          end)
                end
                key = key.unpack('C')[0] if key.kind_of? String      # yay rb19
                item.add_accelerator('activate', @accel_group, key, (accel[0] == ?^ ? Gdk::Window::CONTROL_MASK : 0), Gtk::ACCEL_VISIBLE)
        end
        if action
                a = action
                if check
                        a = lambda { |it| it.active = action.call(it.active?) }
                end
                item.signal_connect('activate') { protect { a.call(item) } }
        end
        menu.append item
        item
end
destroy() click to toggle source
# File metasm/gui/win32.rb, line 2262
def destroy
        Win32Gui.sendmessagea(@hwnd, Win32Gui::WM_CLOSE, 0, 0)
end
destroy_window() click to toggle source
# File metasm/gui/gtk.rb, line 822
def destroy_window
        @@mainwindow_list.delete self
        Gui.main_quit if @@mainwindow_list.empty?     # XXX we don't call main_start ourself..
end
destroyed?() click to toggle source
# File metasm/gui/win32.rb, line 2272
def destroyed? ; @destroyed ||= false ; end
find_menu(name, from=@menu) click to toggle source

finds a menu by name (recursive) returns a valid arg for addsubmenu(ret)

# File metasm/gui/gtk.rb, line 847
def find_menu(name, from=@menu)
        name = name.gsub('_', '')
        if not l = from.find { |e| e.grep(::String).find { |es| es.gsub('_', '') == name } }
               l = from.map { |e| e.grep(::Array).map { |ae| find_menu(name, ae) }.compact.first }.compact.first
        end
        l.grep(::Array).first if l
end
height=(newheight) click to toggle source
# File metasm/gui/win32.rb, line 2240
def height=(newheight)
        Win32Gui.movewindow(@hwnd, @x, @y, @width, newheight, Win32Gui::TRUE)
end
initialize_visible_() click to toggle source
# File metasm/gui/win32.rb, line 2223
def initialize_visible_
        return if @visible
        @visible = true
        @widget.initialize_visible_ if @widget
end
initialize_window() click to toggle source
# File metasm/gui/gtk.rb, line 948
def initialize_window
end
keyboard_state(query=nil) click to toggle source
# File metasm/gui/win32.rb, line 2069
def keyboard_state(query=nil)
        case query
        when :control, :ctrl
                Win32Gui.getkeystate(Win32Gui::VK_CONTROL) & 0x8000 > 0
        when :shift
                Win32Gui.getkeystate(Win32Gui::VK_SHIFT) & 0x8000 > 0
        when :alt
                Win32Gui.getkeystate(Win32Gui::VK_MENU) & 0x8000 > 0
        end
end
mouse_msg(msg, wparam, lparam) click to toggle source
# File metasm/gui/win32.rb, line 2186
def mouse_msg(msg, wparam, lparam)
        return if not @widget
        x = Expression.make_signed(lparam & 0xffff, 16)
        y = Expression.make_signed((lparam >> 16) & 0xffff, 16)
        ctrl = true if wparam & Win32Gui::MK_CONTROL > 0
        cmsg =
        case msg
        when Win32Gui::WM_MOUSEMOVE
                :mousemove
        when Win32Gui::WM_LBUTTONDOWN
                ctrl ? :click_ctrl : :click
        when Win32Gui::WM_LBUTTONUP
                :mouserelease
        when Win32Gui::WM_RBUTTONDOWN
                :rightclick
        when Win32Gui::WM_LBUTTONDBLCLK
                :doubleclick
        when Win32Gui::WM_MOUSEWHEEL
                off = Expression.make_signed((wparam >> 16) & 0xffff, 16)
                dir = off > 0 ? :up : :down
                if ctrl
                        return(@widget.mouse_wheel_ctrl(dir, x-@clientx, y-@clienty) if @widget.respond_to? :mouse_wheel_ctrl)
                else
                        return(@widget.mouse_wheel(dir, x-@clientx, y-@clienty) if @widget.respond_to? :mouse_wheel)
                end
        end

        case cmsg
        when :click
                Win32Gui.setcapture(@hwnd)
        when :mouserelease
                Win32Gui.releasecapture
        end

        @widget.send(cmsg, x, y) if cmsg and @widget.respond_to? cmsg
end
new_menu() click to toggle source
# File metasm/gui/gtk.rb, line 841
def new_menu
        []
end
popupmenu(m, x, y) click to toggle source
# File metasm/gui/gtk.rb, line 855
def popupmenu(m, x, y)
        mh = Gtk::Menu.new
        m.each { |e| create_menu_item(mh, e) }
        mh.show_all
        mh.popup(nil, nil, 2, 0) { |_m, _x, _y, _p| [position[0]+x, position[1]+y, true] }
end
redraw() click to toggle source
# File metasm/gui/win32.rb, line 2258
def redraw
        Win32Gui.invalidaterect(@hwnd, 0, Win32Gui::FALSE)
end
show() click to toggle source
# File metasm/gui/win32.rb, line 2064
def show
        Win32Gui.showwindow(@hwnd, Win32Gui::SW_SHOWDEFAULT)
        Win32Gui.updatewindow(@hwnd)
end
title() click to toggle source
# File metasm/gui/qt.rb, line 431
def title; window_title end
title=(t) click to toggle source
# File metasm/gui/qt.rb, line 430
def title=(t); set_window_title(t) end
unuse_menu(m) click to toggle source
# File metasm/gui/win32.rb, line 2329
def unuse_menu(m)
        m.flatten.grep(Proc).reverse_each { |c|
                if @control_action[@controlid-1] == c
                        @controlid -= 1             # recycle IDs
                        @control_action.delete @controlid
                elsif i = @control_action.index(c)
                        @control_action.delete i
                end
        }
end
update_menu() click to toggle source

make the window's MenuBar reflect the content of @menu

# File metasm/gui/gtk.rb, line 880
def update_menu
        # clear
        @menubar.children.dup.each { |mc| @menubar.remove mc }
        # populate the menubar using @menu
        @menu.each { |e| create_menu_item(@menubar, e) }
        @menubar.show_all
end
widget() click to toggle source
# File metasm/gui/gtk.rb, line 834
def widget
        @child
end
widget=(w) click to toggle source
# File metasm/gui/gtk.rb, line 827
def widget=(w)
        @vbox.remove @child if @child
        @child = w
        @vbox.add w if w
        show_all
end
width=(newwidth) click to toggle source
# File metasm/gui/win32.rb, line 2237
def width=(newwidth)
        Win32Gui.movewindow(@hwnd, @x, @y, newwidth, @height, Win32Gui::TRUE)
end
win32style() click to toggle source
# File metasm/gui/win32.rb, line 2062
def win32style; Win32Gui::WS_OVERLAPPEDWINDOW ; end
win32styleex() click to toggle source
# File metasm/gui/win32.rb, line 2061
def win32styleex; 0 ; end
windowproc(hwnd, msg, wparam, lparam) click to toggle source

MSGNAME = Metasm::DynLdr.cp.lexer.definition.keys.grep(/WM_/).sort.inject({}) { |h, c| h.update Win32Gui.const_get© => c }

# File metasm/gui/win32.rb, line 2093
        def windowproc(hwnd, msg, wparam, lparam)
#puts "wproc #{'%x' % hwnd} #{MSGNAME[msg] || msg} #{'%x' % wparam} #{'%x' % lparam}" if not %w[WM_NCHITTEST WM_SETCURSOR WM_MOUSEMOVE WM_NCMOUSEMOVE].include? MSGNAME[msg]
                @hwnd ||= hwnd                # some messages are sent before createwin returns
                case msg
                when Win32Gui::WM_NCHITTEST, Win32Gui::WM_SETCURSOR
                        # most frequent messages (with MOUSEMOVE)
                        return Win32Gui.defwindowproca(hwnd, msg, wparam, lparam)
                when Win32Gui::WM_MOUSEMOVE, Win32Gui::WM_LBUTTONDOWN, Win32Gui::WM_RBUTTONDOWN,
                        Win32Gui::WM_LBUTTONDBLCLK, Win32Gui::WM_MOUSEWHEEL, Win32Gui::WM_LBUTTONUP
                        mouse_msg(msg, wparam, lparam)
                when Win32Gui::WM_PAINT
                        ps = Win32Gui.alloc_c_struct('PAINTSTRUCT')
                        hdc = Win32Gui.beginpaint(hwnd, ps)
                        if @widget
                                @widget.paint_(hdc)
                        else
                                Win32Gui.selectobject(hdc, Win32Gui.getstockobject(Win32Gui::DC_BRUSH))
                                Win32Gui.selectobject(hdc, Win32Gui.getstockobject(Win32Gui::DC_PEN))
                                col = Win32Gui.getsyscolor(Win32Gui::COLOR_BTNFACE)
                                Win32Gui.setdcbrushcolor(hdc, col)
                                Win32Gui.setdcpencolor(hdc, col)
                                Win32Gui.rectangle(hdc, 0, 0, @width, @height)
                        end
                        Win32Gui.endpaint(hwnd, ps)
                when Win32Gui::WM_MOVE
                        rect = Win32Gui.alloc_c_struct('RECT')
                        Win32Gui.getwindowrect(@hwnd, rect)
                        @x, @y, @width, @height = rect[:left], rect[:top], rect[:right]-rect[:left], rect[:bottom]-rect[:top]
                        @clientx = lparam & 0xffff
                        @clienty = (lparam >> 16) & 0xffff
                when Win32Gui::WM_SIZE
                        rect = Win32Gui.alloc_c_struct('RECT')
                        Win32Gui.getwindowrect(@hwnd, rect)
                        @x, @y, @width, @height = rect[:left], rect[:top], rect[:right]-rect[:left], rect[:bottom]-rect[:top]
                        @clientwidth = lparam & 0xffff
                        @clientheight = (lparam >> 16) & 0xffff
                        @widget.resized_(lparam & 0xffff, (lparam >> 16) & 0xffff) if @widget
                        redraw
                when Win32Gui::WM_WINDOWPOSCHANGING
                        if @popups.first
                                # must move popups to top before updating hwndInsertafter
                                f = Win32Gui::SWP_NOACTIVATE | Win32Gui::SWP_NOMOVE | Win32Gui::SWP_NOSIZE |
                                        Win32Gui::SWP_NOOWNERZORDER | Win32Gui::SWP_NOSENDCHANGING
                                @popups.each { |pw| Win32Gui.setwindowpos(pw.hwnd, Win32Gui::HWND_TOP, 0, 0, 0, 0, f) }
                                Win32Gui.memory_write_int(lparam+Win32Gui.cp.typesize[:ptr], @popups.first.hwnd)
                        end
                when Win32Gui::WM_SHOWWINDOW
                        initialize_visible_
                when Win32Gui::WM_KEYDOWN, Win32Gui::WM_SYSKEYDOWN
                        # SYSKEYDOWN for f10 (default = activate the menu bar)
                        if key = Keyboard_trad[wparam]
                                if [?+, ?-, ?/, ?*].include?(key)
                                        # keypad keys generate wm_keydown + wm_char, ignore this one
                                elsif keyboard_state(:control)
                                        @widget.keypress_ctrl_(key) if @widget
                                else
                                        @widget.keypress_(key) if @widget
                                end
                        end
                        Win32Gui.defwindowproca(hwnd, msg, wparam, lparam) if key != :f10    # alt+f4 etc
                when Win32Gui::WM_CHAR
                        if keyboard_state(:control) and not keyboard_state(:alt)     # altgr+[ returns CTRL on..
                                if ?a.kind_of?(String)
                                        wparam += (keyboard_state(:shift) ? ?A.ord : ?a.ord) - 1 if wparam < 0x1a
                                        key = wparam.chr
                                else
                                        wparam += (keyboard_state(:shift) ? ?A : ?a) - 1 if wparam < 0x1a
                                        key = wparam
                                end
                                @widget.keypress_ctrl_(key) if @widget
                        else
                                key = (?a.kind_of?(String) ? wparam.chr : wparam)
                                @widget.keypress_(key) if @widget
                        end
                when Win32Gui::WM_DESTROY
                        destroy_window
                when Win32Gui::WM_COMMAND
                        if a = @control_action[wparam]
                                protect { a.call }
                        end
                when Win32Gui::WM_DROPFILES
                        cnt = Win32Gui.dragqueryfilea(wparam, -1, 0, 0)
                        cnt.times { |i|
                                buf = [0].pack('C')*1024
                                len = Win32Gui.dragqueryfilea(wparam, i, buf, buf.length)
                                protect { @widget.dragdropfile(buf[0, len]) } if @widget and @widget.respond_to? :dragdropfile
                        }
                        Win32Gui.dragfinish(wparam)
                else return Win32Gui.defwindowproca(hwnd, msg, wparam, lparam)
                end
                0
        end
x=(newx) click to toggle source
# File metasm/gui/win32.rb, line 2231
def x=(newx)
        Win32Gui.movewindow(@hwnd, newx, @y, @width, @height, Win32Gui::TRUE)
end
y=(newy) click to toggle source
# File metasm/gui/win32.rb, line 2234
def y=(newy)
        Win32Gui.movewindow(@hwnd, @x, newy, @width, @height, Win32Gui::TRUE)
end