Module: Lich::Common

Includes:
GtkIdleRetention, GtkMainLoopGuards, GtkTimeoutRetention
Defined in:
documented/games.rb,
documented/common/gtk.rb,
documented/common/hmr.rb,
documented/common/log.rb,
documented/common/vars.rb,
documented/global_defs.rb,
documented/common/spell.rb,
documented/common/buffer.rb,
documented/common/script.rb,
documented/common/account.rb,
documented/common/gameobj.rb,
documented/common/pipe_io.rb,
documented/attributes/char.rb,
documented/common/db_store.rb,
documented/common/postload.rb,
documented/common/settings.rb,
documented/common/throttle.rb,
documented/common/uservars.rb,
documented/common/watchfor.rb,
documented/common/front-end.rb,
documented/common/front-end.rb,
documented/common/gui/state.rb,
documented/common/gui_login.rb,
documented/common/watchable.rb,
documented/common/xmlparser.rb,
documented/common/arg_parser.rb,
documented/common/gameloader.rb,
documented/common/map/map_dr.rb,
documented/common/map/map_gs.rb,
documented/common/setup_files.rb,
documented/common/limitedarray.rb,
documented/common/map/map_base.rb,
documented/common/script_death.rb,
documented/common/sharedbuffer.rb,
documented/common/shutdown_log.rb,
documented/common/upstreamhook.rb,
documented/common/xml_entities.rb,
documented/common/feature_flags.rb,
documented/common/gui/utilities.rb,
documented/common/hook_registry.rb,
documented/common/downstreamhook.rb,
documented/common/gui/components.rb,
documented/common/gui/theme_utils.rb,
documented/common/ruby_executable.rb,
documented/common/shutdown_intent.rb,
documented/common/credential_scrub.rb,
documented/common/frontend_locator.rb,
documented/common/orderly_shutdown.rb,
documented/common/process_launcher.rb,
documented/common/session_launcher.rb,
documented/common/socket_read_hook.rb,
documented/common/frontend_launcher.rb,
documented/common/gui/accessibility.rb,
documented/common/gui/conversion_ui.rb,
documented/common/session_lifecycle.rb,
documented/common/shutdown_watchdog.rb,
documented/common/authentication/cli.rb,
documented/common/authentication/gui.rb,
documented/common/bind_host_resolver.rb,
documented/common/cli/cli_conversion.rb,
documented/common/gui/game_selection.rb,
documented/common/saga_launch_policy.rb,
documented/common/saga_managed_login.rb,
documented/common/socketconfigurator.rb,
documented/common/gui/account_manager.rb,
documented/common/gui/login_tab_utils.rb,
documented/common/gui/password_change.rb,
documented/common/gui/password_cipher.rb,
documented/common/gui/saved_login_tab.rb,
documented/common/gui/window_settings.rb,
documented/common/reusable_tcp_server.rb,
documented/common/gui/manual_login_tab.rb,
documented/common/gui/password_manager.rb,
documented/common/gui/tab_communicator.rb,
documented/common/settings_transformer.rb,
documented/common/shutdown_coordinator.rb,
documented/common/class_exts/stringproc.rb,
documented/common/cli/cli_orchestration.rb,
documented/common/gui/favorites_manager.rb,
documented/common/gui/frontend_selector.rb,
documented/common/gui/parameter_objects.rb,
documented/common/saga_managed_launcher.rb,
documented/common/settings/charsettings.rb,
documented/common/settings/gamesettings.rb,
documented/common/shutdown_script_drain.rb,
documented/common/authentication/eaccess.rb,
documented/common/creature/creature_base.rb,
documented/common/gui/account_manager_ui.rb,
documented/common/client_input_dispatcher.rb,
documented/common/settings/path_navigator.rb,
documented/common/settings/settings_proxy.rb,
documented/dragonrealms/drinfomon/startup.rb,
documented/common/cli/cli_options_registry.rb,
documented/common/cli/active_sessions_query.rb,
documented/common/settings/database_adapter.rb,
documented/common/authentication/entry_store.rb,
documented/common/authentication/launch_data.rb,
documented/common/detachable_client_registry.rb,
documented/common/gui/encryption_mode_change.rb,
documented/common/gui/master_password_change.rb,
documented/common/gui/master_password_prompt.rb,
documented/common/settings/instance_settings.rb,
documented/common/settings/sessions_settings.rb,
documented/common/shutdown_result_predicates.rb,
documented/common/authentication/cli_password.rb,
documented/common/gui/master_password_manager.rb,
documented/common/authentication/authenticator.rb,
documented/common/authentication/login_helpers.rb,
documented/common/best_effort_shutdown_cleanup.rb,
documented/common/class_exts/synchronizedsocket.rb,
documented/common/gui/master_password_prompt_ui.rb,
documented/common/cli/cli_encryption_mode_change.rb,
documented/common/gui/windows_credential_manager.rb,
documented/common/settings/session_database_adapter.rb

Overview

Namespace for Lich 5 shared internal utilities and adapters.

Defined Under Namespace

Modules: Account, Authentication, BestEffortShutdownCleanup, BindHostResolver, Buffer, CLI, CharSettings, ClientInputDispatcher, CreatureBase, CredentialScrub, DB_Store, FeatureFlags, Frontend, FrontendLauncher, GUI, GameLoader, GameSettings, GtkIdleRetention, GtkMainLoopGuards, GtkSignalHandlerRetention, GtkTimeoutRetention, HMR, HookRegistry, InstanceSettings, Log, MapBase, OrderlyShutdown, PostLoad, ProcessLauncher, ReusableTCPServer, RubyExecutable, SagaLaunchPolicy, SagaManagedLauncher, SagaManagedLogin, ScriptDeath, SessionLauncher, SessionLifecycle, SessionsSettings, Settings, SettingsTransformer, ShutdownCoordinator, ShutdownIntent, ShutdownLog, ShutdownResultPredicates, ShutdownScriptDrain, ShutdownWatchdog, SocketConfigurator, UserVars, Vars, Watchable, XmlEntities Classes: ArgParser, Char, DatabaseAdapter, DetachableClientRegistry, DownstreamHook, ExecScript, FrontendLocator, GameObj, LimitedArray, LruIndex, Map, MinHeap, PathNavigator, PipeIO, Room, RoomObj, Script, Scripting, SessionDatabaseAdapter, SettingsProxy, SetupFiles, SharedBuffer, SocketReadHook, Spell, StringProc, SynchronizedSocket, TagList, Throttle, UpstreamHook, Watchfor, WizardScript, XMLParser

Constant Summary collapse

CORE_GET_SETTINGS =
true
CORE_SCRIPT_LOADER =
true
CORE_PARSE_ARGS =
true
CORE_AUTOSTART =
true
TRUSTED_SCRIPT_BINDING =

A proc that returns a trusted script binding context.

proc { _script }
CORE_ARGPARSER =
true
CORE_SETUPFILES =
true
CORE_MAP_OVERRIDES =
true
CORE_DR_STARTUP =
true

Class Method Summary collapse

Instance Method Summary collapse

Methods included from GtkTimeoutRetention

#add

Methods included from GtkIdleRetention

#add

Methods included from GtkMainLoopGuards

#lich_main_quit, #main, #main_quit

Class Method Details

.allow_gtk_main_quit { ... } ⇒ Object

Temporarily allows a core-owned Gtk.main_quit call to bypass script guards.

Yields:

  • Runs a core shutdown operation that must reach the underlying GTK API

Returns:

  • (Object)

    the block result



104
105
106
107
108
109
110
# File 'documented/common/gtk.rb', line 104

def self.allow_gtk_main_quit
  previous = Thread.current[:lich_allow_gtk_main_quit]
  Thread.current[:lich_allow_gtk_main_quit] = true
  yield
ensure
  Thread.current[:lich_allow_gtk_main_quit] = previous
end

.cleanup_gtk!Boolean

Destroys retained GTK receivers and releases retained Ruby callbacks.

ruby-gnome will otherwise release surviving widget wrappers during Ruby finalization, which can dispose native GTK objects in an unsafe order. This may run after Gtk.main has returned, so it must not stop the GTK main loop itself.

Returns:

  • (Boolean)

    true when cleanup work was performed



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'documented/common/gtk.rb', line 70

def self.cleanup_gtk!
  retained_receivers = with_gtk_registry_lock { gtk_signal_handlers.keys.dup }
  callbacks_retained = with_gtk_registry_lock do
    gtk_timeout_callbacks.any? || gtk_idle_callbacks.any?
  end
  return false if retained_receivers.empty? && !callbacks_retained

  retained_receivers.each do |receiver|
    next unless receiver.respond_to?(:destroy)
    next if receiver.respond_to?(:destroyed?) && receiver.destroyed?

    begin
      receiver.destroy
    rescue StandardError => e
      Lich.log "warning: Failed to destroy GTK receiver during shutdown: #{e.class}: #{e.message}"
    end
  end

  clear_gtk_retention_registries
  true
end

.clear_gtk_retention_registriesvoid

This method returns an undefined value.

Clears retained GTK callback registries.

This is used by core shutdown paths to avoid leaving Ruby-side callback references alive until interpreter finalization.



54
55
56
57
58
59
60
# File 'documented/common/gtk.rb', line 54

def self.clear_gtk_retention_registries
  with_gtk_registry_lock do
    gtk_signal_handlers.clear
    gtk_timeout_callbacks.clear
    gtk_idle_callbacks.clear
  end
end

.gtk_guard_contextString

Returns log context for GTK guard messages.

Prefers the currently running script name when available so blocked GTK loop operations can be traced back to the offending script.

Returns:

  • (String)

    formatted logging context such as script=map or context=unknown



218
219
220
221
222
223
# File 'documented/common/gtk.rb', line 218

def self.gtk_guard_context
  script_name = Script.current&.name if defined?(Script) && Script.respond_to?(:current)
  script_name && !script_name.to_s.empty? ? "script=#{script_name}" : 'context=unknown'
rescue StandardError
  'context=unknown'
end

.gtk_idle_callbacksHash{Integer => Proc}

Returns the retained GLib idle callback registry.

Returns:

  • (Hash{Integer => Proc})

    map of idle source IDs to retained callbacks



36
37
38
# File 'documented/common/gtk.rb', line 36

def self.gtk_idle_callbacks
  @gtk_idle_callbacks
end

.gtk_main_loop_running?Boolean

Returns true when the shared GTK main loop is currently running.

Used to decide whether core teardown can be handed to the GTK thread via #shutdown_gtk_before_exit. A false return means the queue cannot be serviced; only the terminal lich.rbw backstop may run direct teardown.

Returns:

  • (Boolean)


128
129
130
131
132
# File 'documented/common/gtk.rb', line 128

def self.gtk_main_loop_running?
  return false unless defined?(Gtk) && Gtk.respond_to?(:main_level)

  Gtk.main_level.to_i > 0
end

.gtk_signal_handlersHash

Returns the retained GTK signal handler registry.

The hash compares keys by object identity so each widget wrapper keeps its own retained callback list even if different objects compare equal.

Returns:

  • (Hash)

    identity map of GTK receivers to retained signal metadata



22
23
24
# File 'documented/common/gtk.rb', line 22

def self.gtk_signal_handlers
  @gtk_signal_handlers
end

.gtk_timeout_callbacksHash{Integer => Proc}

Returns the retained GLib timeout callback registry.

Returns:

  • (Hash{Integer => Proc})

    map of timeout source IDs to retained callbacks



29
30
31
# File 'documented/common/gtk.rb', line 29

def self.gtk_timeout_callbacks
  @gtk_timeout_callbacks
end

.quit_gtk_main_loopObject?

Requests a GTK main-loop shutdown through the guarded core escape hatch.

Returns:

  • (Object, nil)

    GTK shutdown result when GTK is available



115
116
117
118
119
# File 'documented/common/gtk.rb', line 115

def self.quit_gtk_main_loop
  return unless defined?(Gtk)
  return Gtk.lich_main_quit if Gtk.respond_to?(:lich_main_quit)
  return Gtk.main_quit if Gtk.respond_to?(:main_quit)
end

.release_gtk_signal_handlers(receiver) ⇒ Object?

Releases retained signal handlers for a GTK receiver.

Parameters:

  • receiver (Object)

    GTK receiver whose retained handlers should be cleared

Returns:

  • (Object, nil)

    removed retention entry, if any



44
45
46
# File 'documented/common/gtk.rb', line 44

def self.release_gtk_signal_handlers(receiver)
  with_gtk_registry_lock { gtk_signal_handlers.delete(receiver) }
end

.shutdown_gtk!Object?

Performs core-owned GTK shutdown before Ruby process exit.

Returns:

  • (Object, nil)

    GTK main quit result when available



95
96
97
98
# File 'documented/common/gtk.rb', line 95

def self.shutdown_gtk!
  cleanup_gtk!
  Gtk.lich_main_quit if defined?(Gtk) && Gtk.respond_to?(:lich_main_quit)
end

.shutdown_gtk_before_exit(timeout: 2.0, direct: false) ⇒ void

This method returns an undefined value.

Runs core GTK teardown before process exit, so Ruby's finalizer is not left to dispose surviving widget wrappers in an unsafe order (which disposes native objects out of order and segfaults).

Dispatch depends on the GTK main loop state and caller context:

  • Loop running (the launcher and the main game loop, which call this from a thread other than the GTK thread): the teardown is queued onto the GTK thread and this method blocks on a bounded barrier until it completes. #shutdown_gtk! also quits the loop, so this both destroys the widgets and unwinds Gtk.main.
  • Loop not running: a queued block would never be serviced. Ordinary callers clear retained Ruby references only. The terminal lich.rbw backstop passes direct: true after Gtk.main returns on the GTK thread; only that path destroys surviving widgets directly in place. Gtk.main has already returned there, so it must not call Gtk.main_quit.

If GTK is unavailable, the queue cannot be serviced, the work cannot be queued, or it does not finish within timeout, the retention registries are cleared directly so Ruby-side callback references are not left alive until interpreter finalization.

Parameters:

  • timeout (Float) (defaults to: 2.0)

    seconds to wait for the queued teardown to complete

  • direct (Boolean) (defaults to: false)

    true only for the terminal GTK-thread backstop after Gtk.main returns



160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
# File 'documented/common/gtk.rb', line 160

def self.shutdown_gtk_before_exit(timeout: 2.0, direct: false)
  return clear_gtk_retention_registries unless defined?(Gtk)

  unless gtk_main_loop_running?
    if direct
      begin
        cleanup_gtk!
      rescue StandardError => e
        Lich.log "warning: Failed to run direct GTK shutdown before exit: #{e.class}: #{e.message}"
        clear_gtk_retention_registries
      end
    else
      clear_gtk_retention_registries
    end
    return
  end

  shutdown_complete = Queue.new
  queued = begin
    Gtk.queue do
      begin
        shutdown_gtk!
      ensure
        shutdown_complete << true
      end
    end
  rescue StandardError => e
    Lich.log "warning: Failed to queue GTK shutdown before exit: #{e.class}: #{e.message}"
    nil
  end

  unless queued
    clear_gtk_retention_registries
    return
  end

  deadline = Process.clock_gettime(Process::CLOCK_MONOTONIC) + timeout
  loop do
    begin
      shutdown_complete.pop(true)
      return
    rescue ThreadError
      break if Process.clock_gettime(Process::CLOCK_MONOTONIC) >= deadline

      sleep 0.01
    end
  end

  Lich.log 'warning: GTK shutdown queue did not complete before exit'
  clear_gtk_retention_registries
end

.with_gtk_registry_lock { ... } ⇒ Object

Synchronizes access to GTK callback retention registries.

Yields:

  • Performs registry reads or writes while holding the shared mutex

Returns:

  • (Object)

    the block result



12
13
14
# File 'documented/common/gtk.rb', line 12

def self.with_gtk_registry_lock
  @gtk_registries_mutex.synchronize { yield }
end

Instance Method Details

#_scriptBinding

Creates a new script binding context.

Returns:

  • (Binding)

    the binding context for the script.



18
19
20
# File 'documented/common/script.rb', line 18

def _script
  Proc.new {}.binding
end

#gui_loginObject

Provides graphical login functionality for the Lich application

This module contains the main entry point for the GUI login system and coordinates the interaction between saved and manual login tabs. It also provides account management functionality. Enhanced with cross-tab communication for data synchronization and targeted refresh capability for post-conversion scenarios.



37
38
39
40
41
42
43
44
45
46
# File 'documented/common/gui_login.rb', line 37

def 
  
  setup_gui_window

  wait_until { @done }

  save_entry_data_if_needed

  return_launch_data_or_exit
end