Single Instance Application - WIN

While multiple instances of the application is sometimes desired, often it's not. If an application is managing devices, multiple instances competing can cause conflict between them. The following demonstrates using a unique value for the frame window's id to ensure only one running instance. The code looks for an existing instance on entry. If one is found it's brought to the top and quits the new instance. If not found it simply continues on.

-- collect any program arguments
local app_args = { ... }

-- create the application's main frame
local appFrame = win.create_app_frame ()


local APP_TITLE = "Single"

-- ids should be between 1 - 65535

-- control ids
local ID_MENUBTN = 101

-- command ids
local IDM_ONE = 1001
local IDM_TWO = 1002
local IDM_THREE = 1003
local IDM_QUITAPP = 1004

-- unique id for app frame
local ID_MYAPP_FRAME = 12673


-- handle control, wanted and custom events
function appFrame:on_event (event, p1, p2, p3, p4, p5, ...)
-- handle events and return true
if event == "btn_click" then
if p1:get_id () == ID_MENUBTN then
self:on_menu ()
return true
end

elseif event == "menu_cmd" then
return self:on_command (p1)
end

return false
end


-- if needed, low priority, called about every 1/3 second
-- when nothing happening - but keep it brief
function appFrame:on_idle (idle_count)
return false
end


-- if needed
function appFrame:on_alarm (alarm_id)
return false
end


-- if needed
function appFrame:on_timer (timer_id)
return false
end


-- to reposition control windows, app frames should only
-- move if monitor device changes size/resolution or
-- fullscreen mode changes
function appFrame:on_move ()
return false
end


-- for clean up, if needed
function appFrame:on_destroy_wnd ()
end


-- to implement accelerator keys. best to use with combo keys
-- to try and avoid char event following to child
function appFrame:on_child_key (wnd, key, ctrl, alt, shift)
-- base implements tab key navigation
if win.applicationFrame.on_child_key (self, wnd, key, ctrl, alt, shift) then
return true
end

-- return true if handled so child does not receive key event

-- accelerators to menu commands
if ctrl and not alt and not shift then
if key == keys.KEY_1 then
return self:on_command (IDM_ONE)
end

if key == keys.KEY_2 then
return self:on_command (IDM_TWO)
end

if key == keys.KEY_3 then
return self:on_command (IDM_THREE)
end
end

return false
end


-- called when app becomes and stops being the active app
function appFrame:on_frame_activate (active)
end


-- called when app is quitting
function appFrame:on_quit ()
-- return true to stop app from quitting

return false
end


-- method to create and display menu
function appFrame:on_menu ()
local menu = win.menuWindow:new (self)

menu:add_string ("One Ctrl+1", IDM_ONE)
menu:add_string ("Two Ctrl+2", IDM_TWO)
menu:add_string ("Three Ctrl+3", IDM_THREE)
menu:add_string ("------------")
menu:add_string ("Quit App", IDM_QUITAPP)

menu:track (0, 1)
end


-- command handler
function appFrame:on_command (cmd_id)
if cmd_id == IDM_ONE then
self:msgbox ("Menu Command", "Application message box.")
return true
end

if cmd_id == IDM_TWO then
self:msgbox ("Menu Command",
"Application message box with custom color.",
term.colors.sky)
return true
end

if cmd_id == IDM_THREE then
self:get_desktop ():msgbox ("Menu Command",
"System message box with custom color.",
term.colors.red)
return true
end

if cmd_id == IDM_QUITAPP then
self:quit_app ()
return true
end

return false
end


function appFrame:on_create ()
-- single instance, look for existing frame
local instance = self:get_desktop ():get_wnd_by_id (ID_MYAPP_FRAME, false)

-- if found
if instance then
-- bring running instance to top
instance:set_active_top_frame ()

-- and drop out
return false
end

-- not found, change frame id to ID_MYAPP_FRAME
self:set_id (ID_MYAPP_FRAME)

-- add title bar and close btn, close btn will have focus
-- frame wnd text displays in running app list
self:dress (APP_TITLE)

-- create menu button on title bar
local menu_btn = win.buttonWindow:new (self, ID_MENUBTN, 0, 0, "Menu")
-- customise to blend into title bar
menu_btn:set_colors (menu_btn:get_colors ().frame_text,
menu_btn:get_colors ().title_back,
menu_btn:get_colors ().frame_back)
-- move on top of title bar text so wont get obscured
menu_btn:move (nil, nil, nil, nil, win.WND_TOP)


-- create controls, usually setting focus to first


-- app is constructed, bring it to top
self:set_active_top_frame ()

return true
end


-- run the application's loop
appFrame:run_app ()


See Application Writing, WIN.