[MIRROR] Fixes issues with closing apps on tablets [MDB IGNORE] (#20969)

* Fixes issues with closing apps on tablets (#75117)

## About The Pull Request

- Fixes background apps not reloading the UI
- Standardizes opening/closing/backgrounding apps
- Simplifies the way apps are closed instead of having 2 procs, one on
the PC and one on the program, being named the same thing (wtf)
- Removes program states. They existed so computers can know to update
their UI every process tick, but since we now do this event based, this
is no longer needed, which is good.
- Replaces the 'forced' arg from kill_program as it was completely
unused, with ``reload_ui``, which is now used to open the UI on close,
and not to when we don't want it to.
- Closing background apps no longer reloads the entire UI
- Responding to an NT Message will no longer open the UI on your face.

## Why It's Good For The Game

Closes https://github.com/tgstation/tgstation/issues/75046
Closes https://github.com/tgstation/tgstation/issues/75108

Makes tablet UIs more responsive and lag less, not checking if a program
is closed every process to close it, and makes responding to messages
not a hassle every time.
Also makes the code easier to understand/read,

## Changelog

🆑
fix: Tablets' minimize apps feature works again.
/🆑

* Fixes issues with closing apps on tablets

* Update tablet.dm

---------

Co-authored-by: John Willard <53777086+JohnFulpWillard@users.noreply.github.com>
Co-authored-by: Gandalf <9026500+Gandalf2k15@users.noreply.github.com>
This commit is contained in:
SkyratBot
2023-05-08 23:02:51 +01:00
committed by GitHub
parent f1b1e8b109
commit c50e7c03b6
21 changed files with 88 additions and 99 deletions
@@ -148,9 +148,7 @@ GLOBAL_LIST_EMPTY(TabletMessengers) // a list of all active messengers, similar
/obj/item/modular_computer/Destroy()
STOP_PROCESSING(SSobj, src)
wipe_program(forced = TRUE)
for(var/datum/computer_file/program/idle as anything in idle_threads)
idle.kill_program(TRUE)
close_all_programs()
//Some components will actually try and interact with this, so let's do it later
QDEL_NULL(soundloop)
QDEL_LIST(stored_files)
@@ -476,20 +474,14 @@ GLOBAL_LIST_EMPTY(TabletMessengers) // a list of all active messengers, similar
active_program.event_networkfailure(FALSE) // Active program requires NTNet to run but we've just lost connection. Crash.
for(var/datum/computer_file/program/idle_programs as anything in idle_threads)
if(idle_programs.program_state == PROGRAM_STATE_KILLED)
idle_threads.Remove(idle_programs)
continue
idle_programs.process_tick(seconds_per_tick)
idle_programs.ntnet_status = get_ntnet_status()
if(idle_programs.requires_ntnet && !idle_programs.ntnet_status)
idle_programs.event_networkfailure(TRUE)
if(active_program)
if(active_program.program_state == PROGRAM_STATE_KILLED)
active_program = null
else
active_program.process_tick(seconds_per_tick)
active_program.ntnet_status = get_ntnet_status()
active_program.process_tick(seconds_per_tick)
active_program.ntnet_status = get_ntnet_status()
handle_power(seconds_per_tick) // Handles all computer power interaction
@@ -571,20 +563,7 @@ GLOBAL_LIST_EMPTY(TabletMessengers) // a list of all active messengers, similar
data["PC_showexitprogram"] = !!active_program // Hides "Exit Program" button on mainscreen
return data
///Wipes the computer's current program. Doesn't handle any of the niceties around doing this
/obj/item/modular_computer/proc/wipe_program(forced)
if(!active_program)
return
active_program.kill_program(forced)
active_program = null
// Relays kill program request to currently active program. Use this to quit current program.
/obj/item/modular_computer/proc/kill_program(forced = FALSE)
wipe_program(forced)
update_appearance()
update_tablet_open_uis(usr)
/obj/item/modular_computer/proc/open_program(mob/user, datum/computer_file/program/program)
/obj/item/modular_computer/proc/open_program(mob/user, datum/computer_file/program/program, open_ui = TRUE)
if(program.computer != src)
CRASH("tried to open program that does not belong to this computer")
@@ -594,11 +573,12 @@ GLOBAL_LIST_EMPTY(TabletMessengers) // a list of all active messengers, similar
// The program is already running. Resume it.
if(program in idle_threads)
program.program_state = PROGRAM_STATE_ACTIVE
active_program = program
program.alert_pending = FALSE
idle_threads.Remove(program)
update_appearance()
if(open_ui)
update_tablet_open_uis(user)
update_appearance(UPDATE_ICON)
return TRUE
if(!program.is_supported_by_hardware(hardware_flag, 1, user))
@@ -617,8 +597,9 @@ GLOBAL_LIST_EMPTY(TabletMessengers) // a list of all active messengers, similar
active_program = program
program.alert_pending = FALSE
update_appearance()
update_tablet_open_uis(user)
if(open_ui)
update_tablet_open_uis(user)
update_appearance(UPDATE_ICON)
return TRUE
// Returns 0 for No Signal, 1 for Low Signal and 2 for Good Signal. 3 is for wired connection (always-on)
@@ -650,10 +631,13 @@ GLOBAL_LIST_EMPTY(TabletMessengers) // a list of all active messengers, similar
return SSmodular_computers.add_log("[src]: [text]")
/obj/item/modular_computer/proc/shutdown_computer(loud = 1)
kill_program(forced = TRUE)
for(var/datum/computer_file/program/idle_program in idle_threads)
idle_program.kill_program(forced = TRUE)
/obj/item/modular_computer/proc/close_all_programs()
active_program = null
for(var/datum/computer_file/program/idle as anything in idle_threads)
idle_threads.Remove(idle)
/obj/item/modular_computer/proc/shutdown_computer(loud = TRUE)
close_all_programs()
if(looping_sound)
soundloop.stop()
if(physical && loud)
@@ -35,10 +35,10 @@
return FALSE
if(istype(file_removing, /datum/computer_file/program))
var/datum/computer_file/program/program_file = file_removing
if(program_file.program_state != PROGRAM_STATE_KILLED)
program_file.kill_program(TRUE)
if(program_file.program_state == PROGRAM_STATE_ACTIVE)
active_program = null
if(program_file == active_program)
active_program.kill_program()
for(var/datum/computer_file/program/programs as anything in idle_threads)
programs.kill_program()
SEND_SIGNAL(file_removing, COMSIG_MODULAR_COMPUTER_FILE_DELETING)
stored_files.Remove(file_removing)
@@ -23,12 +23,13 @@
// Used in following function to reduce copypaste
/obj/item/modular_computer/proc/power_failure()
if(enabled) // Shut down the computer
if(active_program)
active_program.event_powerfailure(background = FALSE)
for(var/datum/computer_file/program/programs as anything in idle_threads)
programs.event_powerfailure(background = TRUE)
shutdown_computer(0)
if(!enabled) // Shut down the computer
return
if(active_program)
active_program.event_powerfailure()
for(var/datum/computer_file/program/programs as anything in idle_threads)
programs.event_powerfailure()
shutdown_computer(loud = FALSE)
// Handles power-related things, such as battery interaction, recharging, shutdown when it's discharged
/obj/item/modular_computer/proc/handle_power(seconds_per_tick)
@@ -126,7 +126,7 @@
switch(action)
if("PC_exit")
kill_program()
active_program.kill_program()
return TRUE
if("PC_shutdown")
shutdown_computer()
@@ -134,26 +134,17 @@
if("PC_minimize")
if(!active_program)
return
//header programs can't be minimized.
if(active_program.header_program)
kill_program()
return TRUE
idle_threads.Add(active_program)
active_program.program_state = PROGRAM_STATE_BACKGROUND // Should close any existing UIs
active_program = null
update_appearance()
active_program.background_program()
return TRUE
if("PC_killprogram")
var/prog = params["name"]
var/datum/computer_file/program/killed_program = find_file_by_name(prog)
if(!istype(killed_program) || killed_program.program_state == PROGRAM_STATE_KILLED)
if(!istype(killed_program))
return
killed_program.kill_program(forced = TRUE)
killed_program.kill_program()
to_chat(usr, span_notice("Program [killed_program.filename].[killed_program.filetype] with PID [rand(100,999)] has been killed."))
return TRUE
@@ -96,7 +96,6 @@
. = ..()
var/datum/computer_file/program/chatclient/chatprogram = cpu.find_file_by_name("ntnrc_client")
chatprogram.username = "[lowertext(console_department)]_department"
chatprogram.program_state = PROGRAM_STATE_ACTIVE
cpu.active_program = chatprogram
/obj/machinery/modular_computer/console/preset/cargochat/service
@@ -23,7 +23,10 @@
/datum/computer_file/Destroy(force)
if(computer)
computer.remove_file(src)
if(src == computer.active_program)
computer.active_program = null
if(src in computer.idle_threads)
computer.idle_threads.Remove(src)
computer = null
if(disk_host)
disk_host.remove_file(src)
@@ -87,8 +90,8 @@
* Arguments:
* * background - Whether the app is running in the background.
*/
/datum/computer_file/program/proc/event_powerfailure(background)
kill_program(forced = TRUE)
/datum/computer_file/program/proc/event_powerfailure()
kill_program()
/**
* Called when a computer program is crashing due to any required connection being shut off.
@@ -96,7 +99,7 @@
* * background - Whether the app is running in the background.
*/
/datum/computer_file/program/proc/event_networkfailure(background)
kill_program(forced = TRUE)
kill_program()
if(background)
computer.visible_message(span_danger("\The [computer]'s screen displays a \"Process [filename].[filetype] (PID [rand(100,999)]) terminated - Network Error\" error"))
else
@@ -7,8 +7,6 @@
var/list/required_access = list()
/// List of required access to download or file host the program. Any match will do.
var/list/transfer_access = list()
/// PROGRAM_STATE_KILLED or PROGRAM_STATE_BACKGROUND or PROGRAM_STATE_ACTIVE - specifies whether this program is running.
var/program_state = PROGRAM_STATE_KILLED
/// User-friendly name of this program.
var/filedesc = "Unknown Program"
/// Short description of this program's function.
@@ -158,23 +156,43 @@
if(requires_ntnet)
var/obj/item/card/id/ID = computer.computer_id_slot?.GetID()
generate_network_log("Connection opened -- Program ID:[filename] User:[ID?"[ID.registered_name]":"None"]")
program_state = PROGRAM_STATE_ACTIVE
return TRUE
return FALSE
/**
* Kills the running program
*
* Use this proc to kill the program. Designed to be implemented by each program if it requires on-quit logic, such as the NTNRC client.
* Arguments:
* * forced - Boolean to determine if this was a forced close. Should be TRUE if the user did not willingly close the program.
* Use this proc to kill the program.
* Designed to be implemented by each program if it requires on-quit logic, such as the NTNRC client.
* Args:
* - reload_ui - Whether we reload the UI on computer's shutdown.
**/
/datum/computer_file/program/proc/kill_program(forced = FALSE)
/datum/computer_file/program/proc/kill_program()
SHOULD_CALL_PARENT(TRUE)
program_state = PROGRAM_STATE_KILLED
if(src == computer.active_program)
computer.active_program = null
if(computer.enabled)
computer.update_tablet_open_uis(usr)
if(src in computer.idle_threads)
computer.idle_threads.Remove(src)
if(requires_ntnet)
var/obj/item/card/id/ID = computer.computer_id_slot?.GetID()
generate_network_log("Connection closed -- Program ID: [filename] User:[ID ? "[ID.registered_name]" : "None"]")
computer.update_appearance(UPDATE_ICON)
return TRUE
///Sends the running program to the background/idle threads. Header programs can't be minimized and will kill instead.
/datum/computer_file/program/proc/background_program()
SHOULD_CALL_PARENT(TRUE)
if(header_program)
return kill_program()
computer.idle_threads.Add(src)
computer.active_program = null
computer.update_tablet_open_uis(usr)
computer.update_appearance(UPDATE_ICON)
return TRUE
@@ -30,7 +30,7 @@
examine_text += span_info("Alt-click to eject the intelliCard.")
return examine_text
/datum/computer_file/program/ai_restorer/kill_program(forced)
/datum/computer_file/program/ai_restorer/kill_program()
try_eject(forced = TRUE)
return ..()
@@ -51,6 +51,6 @@
. = ..(user)
GLOB.alarmdisplay += src
/datum/computer_file/program/alarm_monitor/kill_program(forced = FALSE)
/datum/computer_file/program/alarm_monitor/kill_program()
GLOB.alarmdisplay -= src
return ..()
@@ -32,13 +32,12 @@
target = null
error = "Connection to destination relay lost."
/datum/computer_file/program/ntnet_dos/kill_program(forced = FALSE)
/datum/computer_file/program/ntnet_dos/kill_program()
if(target)
target.dos_sources.Remove(src)
target = null
executed = FALSE
..()
return ..()
/datum/computer_file/program/ntnet_dos/ui_act(action, params, datum/tgui/ui, datum/ui_state/state)
switch(action)
@@ -19,7 +19,7 @@
DL_source = null
return ..()
/datum/computer_file/program/borg_monitor/kill_program(forced = FALSE)
/datum/computer_file/program/borg_monitor/kill_program()
loglist = null //Not everything is saved if you close an app
DL_source = null
DL_progress = 0
@@ -79,7 +79,7 @@
return FALSE
computer.crew_manifest_update = TRUE
/datum/computer_file/program/card_mod/kill_program(forced)
/datum/computer_file/program/card_mod/kill_program()
computer.crew_manifest_update = FALSE
var/obj/item/card/id/inserted_auth_card = computer.computer_id_slot
if(inserted_auth_card)
@@ -162,6 +162,6 @@
return TRUE
return FALSE
/datum/computer_file/program/ntnetdownload/kill_program(forced)
/datum/computer_file/program/ntnetdownload/kill_program()
abort_file_download()
return ..()
@@ -3,7 +3,6 @@
filedesc = "Direct Messenger"
category = PROGRAM_CATEGORY_MISC
program_icon_state = "command"
program_state = PROGRAM_STATE_BACKGROUND
extended_desc = "This program allows old-school communication with other modular devices."
size = 0
undeletable = TRUE // It comes by default in tablets, can't be downloaded, takes no space and should obviously not be able to be deleted.
@@ -417,7 +416,7 @@
if(!computer.turn_on(usr, open_ui = FALSE))
return
if(computer.active_program != src)
if(!computer.open_program(usr, src))
if(!computer.open_program(usr, src, open_ui = FALSE))
return
if(!href_list["close"] && usr.can_perform_action(computer, FORBID_TELEKINESIS_REACH))
switch(href_list["choice"])
@@ -176,7 +176,7 @@
/datum/computer_file/program/chatclient/process_tick(seconds_per_tick)
. = ..()
var/datum/ntnet_conversation/channel = SSmodular_computers.get_chat_channel_by_id(active_channel)
if(program_state != PROGRAM_STATE_KILLED)
if(src in computer.idle_threads)
ui_header = "ntnrc_idle.gif"
if(channel)
// Remember the last message. If there is no message in the channel remember null.
@@ -198,7 +198,7 @@
channel.offline_clients.Remove(src)
channel.active_clients.Add(src)
/datum/computer_file/program/chatclient/kill_program(forced = FALSE)
/datum/computer_file/program/chatclient/kill_program()
for(var/datum/ntnet_conversation/channel as anything in SSmodular_computers.chat_channels)
channel.go_offline(src)
active_channel = null
@@ -236,7 +236,8 @@
authed = TRUE
clients.Add(list(list(
"name" = channel_client.username,
"status" = channel_client.program_state,
"online" = (channel_client == channel_client.computer.active_program),
"away" = (channel_client in channel_client.computer.idle_threads),
"muted" = (channel_client in channel.muted_clients),
"operator" = (channel.channel_operator == channel_client),
"ref" = REF(channel_client),
@@ -29,7 +29,7 @@
return
return FALSE
/datum/computer_file/program/radar/kill_program(forced = FALSE)
/datum/computer_file/program/radar/kill_program()
objects = list()
selected = null
STOP_PROCESSING(SSfastprocess, src)
@@ -313,7 +313,7 @@
RegisterSignal(SSdcs, COMSIG_GLOB_NUKE_DEVICE_ARMED, PROC_REF(on_nuke_armed))
/datum/computer_file/program/radar/fission360/kill_program(forced)
/datum/computer_file/program/radar/fission360/kill_program()
UnregisterSignal(SSdcs, COMSIG_GLOB_NUKE_DEVICE_ARMED)
return ..()
@@ -19,7 +19,7 @@
. = ..()
set_frequency(signal_frequency)
/datum/computer_file/program/signal_commander/kill_program(forced)
/datum/computer_file/program/signal_commander/kill_program()
. = ..()
SSradio.remove_object(computer, signal_frequency)
@@ -22,7 +22,7 @@
refresh()
/// Apparently destroy calls this [/datum/computer_file/Destroy]. Here just to clean our references.
/datum/computer_file/program/supermatter_monitor/kill_program(forced = FALSE)
/datum/computer_file/program/supermatter_monitor/kill_program()
for(var/supermatter in supermatters)
clear_supermatter(supermatter)
return ..()