# Jam setup for HoG:
# This allows to run Pulse & Mandelbrot in qemu with the "hog-demos.run" run
# scenario (invoke it with "jam hog-demos.emu6"), but can also be used for your own
# Haiku-on-Genode apps and scenarios -- call AddInteractiveComponents from your jamfile
# before calling the RunQemu rule, and it will setup libraries, nitpicker and so on for you.

#///later: much of the below, like AddNetworking, is NOT haiku-specific, and could be moved to "jamrules-qemu" instead



rule AddHaikuDepLibs  runfile
{
	local haiku_libbe =
		haiku.lib.so
		libc.lib.so
		libm.lib.so
		stdcxx.lib.so
		vfs.lib.so
		posix.lib.so  # used by e.g. hog_ftpd
		;
	AddRawComponent $(runfile) : $(haiku_libbe) : $(haiku_libbe) ;
}


rule AddInteractiveComponents  runfile : extra_options
{
#/// leaf Jamfiles should test USB... Or better yet, $(HoG_BUILD_HEAVY)
	#echo "building with USB_INPUT = " $(USB_INPUT) ;
	

	local LogOutput_Serial = " <parent/> " ;
	local LogOutput_Terminal_or_Serial = " <child name=\"terminal_log\"/> <parent/> " ;
	
	# Genode minimum: add config, init, timer, acpi, platform, framebuffer
	#
	AddMinimumComponents $(runfile) ;
	
	
	# Haiku libraries and their (libc et al) dependencies
	#
	AddHaikuDepLibs $(runfile) ;
	
	
	# Capture Gui, render to VESA framebuffer
	#
	# resolution: without a configured one, vesa_fb will use the native resolution it seems.
	# (on qemu, oddly, it is 2560x1600@32)
	# That only works on (my) laptops though:
	# F2A55 and ThinkCentre M73 go "black screen" if no resolution is specified (unlike laptops)... So hardcode something:
# On laptops, either of these can come in handy:
#		: "\		<config buffered=\"yes\" />"
#		: "\		<config buffered=\"yes\" width=\"1280\" height=\"800\" />"
if ! $(USE_DRV_MANAGER)
{
if ! "NO_fb_DRIVER" in $(extra_options)
{
	AddComponentAsStart $(runfile) : 59M  #xxxx
		: vesa_fb : "name=\"vesa_fb\" caps=\"150\""
		: "\		<config buffered=\"yes\" width=\"1024\" height=\"768\" />
	\	<route>
	\		<service name=\"Capture\"> <child name=\"nitpicker\"/> </service>
	\		<any-service> <parent/> <any-child/> </any-service>
	\	</route>
		"
		;
}
}
	
	# Genode support: dependancies of nitpicker
	#
#///ToDo: do we need nit_focus ?:
#	AddComponentService $(runfile) : 1M : nit_focus  :  : "
#	\		<config> <default-policy focus=\"yes\"/> </config>
#	\		<route>
#	\			<service name=\"ROM\" label=\"clicked\"> <child name=\"report_rom\"/> </service>
#	\			<service name=\"Report\"> <child name=\"report_rom\"/> </service>
#	\			<any-service> <parent/> </any-service>
#	\		</route>
#		"
#		;
	AddComponentService $(runfile) : 1096K : status_bar :  : "
	\	<route>
	\		<service name=\"ROM\" label=\"focus\"> <child name=\"report_rom\"/> </service>
	\		<service name=\"Gui\"> <child name=\"nitpicker\"/> </service>
	\		<any-service> <parent/> <any-child/> </any-service>
	\	</route>
		"
		;
	AddComponentService $(runfile) : 1096K : pointer :  : "
	\	<route>
	\		<service name=\"Gui\"> <child name=\"nitpicker\"/> </service>
	\		<any-service> <parent/> <any-child/> </any-service>
	\	</route>
		"
		;
	AddComponentService $(runfile) : 1096K : global_keys_handler  :  : "
	\		<config>
	\			<bool name=\"xray\" initial=\"no\"/>
	
	\			<press   name=\"KEY_SCROLLLOCK\" bool=\"xray\" change=\"toggle\"/>
	\			<press   name=\"KEY_F1\"         bool=\"xray\" change=\"on\"/>
	\			<release name=\"KEY_F1\"         bool=\"xray\" change=\"off\"/>
	\			<press   name=\"KEY_F2\"         bool=\"xray\" change=\"toggle\"/>
	
	\			<report name=\"xray\" delay_ms=\"125\">
	\				<hovered domain=\"panel\"/>
	\				<bool name=\"xray\"/>
	\			</report>
	\		</config>
	\		<route>
	\			<service name=\"Report\"> <child name=\"report_rom\"/> </service>
	\			<service name=\"ROM\" label=\"hover\"> <child name=\"report_rom\"/> </service>
	\			<service name=\"Gui\"> <child name=\"nitpicker\"/> </service>
	\			<any-service> <parent/> <any-child/> </any-service>
	\		</route>
		"
		;
	
if ! $(USE_DRV_MANAGER)
{
	# PS/2:
	#
if ! "NO_ps2_DRIVER" in $(extra_options)
{
	AddComponentClient $(runfile) : 2M : ps2 :  # config: set attribute "system=yes" so that ps2 will watch for "reset" ROM change and trigger a reset (useful when ACPI reset refers to a reserved/inaccessible port, see ticket #2726)
	"
	\	<config system=\"yes\"
	\		verbose_keyboard=\"no\"
	\		verbose_mouse=\"no\"
	\		verbose_scancodes=\"no\"
	\		/>
	\	<route>
	\		<service name=\"Event\"> <child name=\"event_filter\" label=\"ps2\"/> </service>
	\		<service name=\"ROM\" label=\"system\"> <child name=\"platform_report_rom\"/> </service>
	\		<any-service> <parent/> <any-child/> </any-service>
	\	</route>
		"
		;
}
}
	
if ! $(USE_DRV_MANAGER)
{
	if $(USB_INPUT) = true
	{
		AddComponentAsStart $(runfile) : 16M : pc_usb_host : "name=\"usb_host\" caps=\"200\"" :
		\	"	<binary name=\"pc_usb_host\"/>
		\		<provides> <service name=\"Usb\"/> </provides>
		\		<config bios_handoff=\"no\">
		\			<report devices=\"yes\"/>
		\			<policy label_prefix=\"usb_hid\"> <device class=\"0x3\"/> </policy>
		\		</config>
		\		<route>
		\			<service name=\"LOG\"> $(LogOutput_Serial) </service>
		\			<service name=\"Report\" label=\"devices\"> <child name=\"report_rom\"/> </service>
		\			<any-service> <parent/> <any-child/> </any-service>
		\		</route>
			"
			;
		AddComponentAsStart $(runfile) : 11M : usb_hid : "name=\"usb_hid\" caps=\"180\"" :
			"
		\		<config/>
		\		<route>
		\			<service name=\"LOG\"> $(LogOutput_Serial) </service>
		\			<service name=\"Event\"> <child name=\"event_filter\"/> </service>
		\			<service name=\"ROM\" label=\"report\"> <child name=\"report_rom\"/> </service>
		\			<any-service> <parent/> <any-child/> </any-service>
		\		</route>
			"
			;
	}
}

#++ set routes for LEDs (not with dynamic_rom though):
#		<config capslock_led="rom" numlock_led="rom" scrlock_led="rom"/>
#			<service name="ROM" label="capslock"> <child name="dynamic_rom"/> </service>
#			<service name="ROM" label="numlock">  <child name="dynamic_rom"/> </service>
#			<service name="ROM" label="scrlock">  <child name="dynamic_rom"/> </service>



	AddBootModule $(runfile) : en_us.chargen ;
	AddBootModule $(runfile) : special.chargen ;
	SEARCH_SOURCE +=  $(GenodeRepos)/os/src/server/event_filter ;
if ! $(USE_DRV_MANAGER)
{
	AddComponentAsStart $(runfile) : 2M
		: event_filter : "name=\"event_filter\" caps=\"90\" priority=\"0\"" : "
	\		<provides> <service name=\"Event\"/> </provides>
	\		<config>
	\			<output>
	\				<chargen>
	\					<remap>
	\						<merge>
	\							<input name=\"ps2\"/>
	\							<input name=\"usb_hid\"/>
	\							<input name=\"vnc\"/>
	\						</merge>
	\					</remap>
			# Remapping/chargen is necessary for Qt apps (and will probably be used in Be apps too eventually)
			# otherwise we hit this: https://github.com/cproc/qt5/qtbase/src/plugins/platforms/genode/qgenodeplatformwindow.cpp:256  "warning: key (KEY_F,33,U+fffe) lacks Qt mapping"...
	\					<mod1>
	\						<key name=\"KEY_LEFTSHIFT\"/> <key name=\"KEY_RIGHTSHIFT\"/>
	\					</mod1>
	\					<mod2>
	\						<key name=\"KEY_LEFTCTRL\"/> <key name=\"KEY_RIGHTCTRL\"/>
	\					</mod2>
	\					<mod3>
	\						<key name=\"KEY_RIGHTALT\"/> <!-- AltGr -->
	\					</mod3>
	\					<repeat delay_ms=\"300\" rate_ms=\"50\"/>
	\		<!--			Hardcode US keyboard layout for now:		-->
	\					<include rom=\"en_us.chargen\"/>
	\				</chargen>
	\			</output>
	\			<policy label=\"ps2\" input=\"ps2\"/>
	\			<policy label_prefix=\"usb_hid\" input=\"usb_hid\"/>
	\			<policy label=\"vnc\" input=\"vnc\"/>
	\		</config>
	\		<route>
	\			<service name=\"Event\"> <child name=\"nitpicker\" /> </service>
	\			<service name=\"Timer\"> <child name=\"timer\"/> </service>
	\			<any-service> <parent/> </any-service>
	\		</route>
		"
		;
}  # ~! USE_DRV_MANAGER~
	
	# Commented out -- this crashes FT-Jam ("stack smashing detected").. Anyway seems we don't need it:
if ! 1
{
	AddComponentAsStart $(runfile) : 1096K : rom_filter : "name=\"nitpicker_config\"" : "
		\	<binary name=\"rom_filter\"/>
		\	<provides><service name=\"ROM\"/></provides>
		\	<config>
		\		<input name=\"xray_enabled\" rom=\"xray\" node=\"xray\">
		\			<attribute name=\"enabled\" /> </input>
		\		<output node=\"config\">
		\			<attribute name=\"focus\" value=\"rom\"/>
		\			<inline>
		\				<report focus=\"yes\" xray=\"yes\" hover=\"yes\" keystate=\"yes\"
		\				        clicked=\"yes\"/>
		\				<domain name=\"pointer\" layer=\"1\" origin=\"pointer\"
		\				        content=\"client\" label=\"no\"/>
		\				<domain name=\"panel\" layer=\"2\"
		\				        content=\"client\" label=\"no\" hover=\"always\"/>
		\			</inline>
		\			<if>
		\				<has_value input=\"xray_enabled\" value=\"no\" />
		\				<then>
		\					<inline>
		\						<domain name=\"launchpad\" layer=\"3\"
		\						        content=\"client\" label=\"no\" hover=\"always\" focus=\"click\"
		\						        ypos=\"18\" height=\"-18\" />
		\						<domain name=\"\" layer=\"3\"
		\						        content=\"client\" label=\"no\" hover=\"always\" focus=\"click\"
		\						        ypos=\"18\" height=\"-18\" />
		\					</inline>
		\				</then>
		\				<else>
		\					<inline>
		\						<domain name=\"launchpad\" layer=\"3\" color=\"#dd0000\"
		\						        content=\"tinted\" label=\"yes\" hover=\"focused\" focus=\"click\"
		\						        ypos=\"18\" height=\"-18\" />
		\						<domain name=\"\" layer=\"3\" color=\"#55dd34\"
		\						        content=\"tinted\" label=\"yes\" hover=\"focused\" focus=\"click\"
		\						        ypos=\"18\" height=\"-18\" />
		\					</inline>
		\				</else>
		\			</if>
		\			<inline>
		\				<policy label_prefix=\"pointer\"            domain=\"pointer\"/>
		\				<policy label_prefix=\"status_bar\"         domain=\"panel\"/>
		\				<policy label_prefix=\"scout -> launchpad\" domain=\"launchpad\"/>
		\				<default-policy                           domain=\"\"/>
	
		\				<global-key name=\"KEY_SCROLLLOCK\" label=\"global_keys_handler -> input\" />
		\				<global-key name=\"KEY_F1\"         label=\"global_keys_handler -> input\" />
		\				<global-key name=\"KEY_F2\"         label=\"global_keys_handler -> input\" />
		\			</inline>
		\		</output>
		\	</config>
		\	<route>
		\		<service name=\"ROM\" label=\"xray\"> <child name=\"report_rom\"/> </service>
		\		<any-service> <parent/> </any-service>
		\	</route>"
		;
}
	
	
	# Playing with "window-manager" and "no-WM" modes:
#			<config focus=\"rom\">
				#<domain name=\"panel\"   layer=\"2\" content=\"client\" label=\"no\" focus=\"none\" />
#				<domain name=\"default\" layer=\"2\" label=\"no\" content=\"client\" hover=\"always\" />
				#<policy label_prefix=\"status_bar\" domain=\"panel\"/>

# UPD: removed usage of the global (!) HAS_WINDOW_MANAGER variable as jamfiles were polluting each other
# Given that, and new usage of "wm.config", it means this if() becomes a dead branch ; what of its contents: migrate to wm.config? Or maybe it's part of it already ?
if $(HAS_WINDOW_MANAGER)
{
	AddComponentAsStart $(runfile) : 4M
		: nitpicker : "name=\"nitpicker\" caps=\"120\"" : "
	\		<provides> <service name=\"Gui\"/> <service name=\"Capture\"/> <service name=\"Event\"/> </provides>
#	\		<config focus=\"rom\">
\	<config>
	\			<capture/> <event/>
	\
				<domain name=\"pointer\" layer=\"1\" label=\"no\" content=\"client\" origin=\"pointer\" />
				<domain name=\"default\" layer=\"2\" label=\"no\" content=\"client\" hover=\"always\" />
	\
				<policy label_prefix=\"pointer\" domain=\"pointer\"/>
				<default-policy domain=\"default\"/>
	\		</config>
		"
		;
}
else
{
	AddComponentAsStart $(runfile) : 4M
		: nitpicker : "name=\"nitpicker\" caps=\"120\"" : "
	\		<provides> <service name=\"Gui\"/> <service name=\"Capture\"/> <service name=\"Event\"/> </provides>
	\		<config>
	\			<capture/> <event/>
	\
				<domain name=\"pointer\"  layer=\"1\" label=\"no\" content=\"client\" origin=\"pointer\" />
				<domain name=\"default\"  layer=\"2\" label=\"no\" content=\"client\" hover=\"always\" focus=\"click\"/>
#				<domain name=\"terminal\" layer=\"3\" label=\"no\" content=\"client\" hover=\"always\" focus=\"click\"/>
#				<domain name=\"tracker\" layer=\"3\" label=\"no\" content=\"client\" hover=\"always\" focus=\"click\"/>
	\
				<policy label_prefix=\"pointer\"  domain=\"pointer\"/>
#				<policy label_prefix=\"terminal\" domain=\"terminal\"/>
#				<policy label_prefix=\"Tracker\"  domain=\"tracker\"/>
				<default-policy domain=\"default\"/>
	\		</config>
	\		<route>
#	\			<service name=\"ROM\" label=\"config\"> <child name=\"nitpicker_config\"/> </service>
	\			<service name=\"ROM\" label=\"focus\"> <child name=\"report_rom\"/> </service>
	\			<service name=\"Report\">  <child name=\"report_rom\"/> </service>
	\			<any-service> <parent/> <any-child/> </any-service>
	\		</route>
		"
		;
}


}  # ~rule AddInteractiveComponents #########################



#///later: rename to "AddMediaStack"
rule AddAudioComponents  runfile
{
	local LogOutput_Terminal_or_Serial = "<child name=\"terminal_log\"/> <parent/>" ;
	
	local media_libs =
		avcodec.lib.so
		avfilter.lib.so
		avformat.lib.so
		avresample.lib.so
		avutil.lib.so
		jpeg.lib.so
		swscale.lib.so
		zlib.lib.so
	#	vfs_oss.lib.so  # enable this if using OSS instead of 'native' audio output
		;
	AddBootModule  $(runfile) : $(media_libs) ;
	
	local FACTOR_RecordPlayMixer = ;
	local FACTOR_LegacyMixer = " " ;  # keep using Legacy mixer for now (the new mixer now works, with -fconcepts, but the config needs tuning)
	
	#///ToDo: instead of USB_INPUT flag, use a flag named "HEAVY_BUILD" or some such:
	if $(USB_INPUT) = true
	{
		AddComponentAsStart $(runfile) : 2M
			: pci_audio : "name=\"audio\" caps=\"105\"" :  # was: pci_audio_drv / audio_drv
		\	"	<binary name=\"pci_audio\"/>
		\		<provides>
		\			<service name=\"Audio_out\"/>
		\		</provides>
			"
	$(FACTOR_RecordPlayMixer)"	<config report_mixer=\"no\" record_play=\"yes\">"
	$(FACTOR_LegacyMixer)"	<config recording=\"true\" verbose=\"no\">"
			"
		\		<mixer field=\"outputs.master\" value=\"148,148\"/>
#		\		<mixer field=\"record.enable\" value=\"on\"/>
#		\			<!-- provide stdout, for when compiled with -DDEBUG: -->
#		\		<libc stdin=\"/dev/null\" stdout=\"/dev/log\" stderr=\"/dev/log\"/>
#		\		<vfs>
#		\			<dir name=\"dev\">
#		\				<log/>
#		\				<null/>
#		\			</dir>
#		\		</vfs>
		\	</config>
		\	<route>
		\		<service name=\"LOG\"> $(LogOutput_Terminal_or_Serial) </service>
		\		<service name=\"Platform\"> <child name=\"platform\"/> <child name=\"drivers_init\" label=\"-> audio\"/> </service>
	# ?	\		<service name=\"Report\"> <child name=\"report_rom\"/> </service> <!-- Otherwise mixer errors out with "cannot create mixer channels Report.." -->
		\		<any-service> <parent/> <any-child/> </any-service>
		\	</route>
		"
			;
		
		if $(FACTOR_RecordPlayMixer)
		{
			AddComponentAsStart $(runfile) : 2M
				: record_play_mixer : "name=\"mixer\" caps=\"256\"" :
			\	"	<binary name=\"record_play_mixer\"/>
			\		<resource name=\"CPU\" quantum=\"20\"/>
			\		<provides>
			\			<service name=\"Record\"/>
			\			<service name=\"Play\"/>
			\		</provides>
			\		<config jitter_ms=\"20\">
			\			<mix name=\"left\">  <play label_suffix=\"left\" />  </mix>
			\			<mix name=\"right\"> <play label_suffix=\"right\"/>  </mix>
			\
			\			<policy label_suffix=\"left\"  record=\"left\"  volume=\"0.7\"/>
			\			<policy label_suffix=\"right\" record=\"right\" volume=\"0.7\"/>
			\		</config>
			\		<route>
			\			<service name=\"LOG\"> $(LogOutput_Terminal_or_Serial) </service>
			
			\			<service name=\"Report\"> <child name=\"report_rom\"/> </service> <!-- Otherwise mixer errors out with "cannot create mixer channels Report.." -->
			\			<any-service> <parent/> <any-child/> </any-service>
			\		</route>
			"
				;
		}
		else
		{
			# eg <service name="ROM" label="config"> <child name="dynamic_rom" label="mixer.config"/> </service>
		AddComponentService $(runfile) : 3M : mixer : Audio_out :
		"	<config  verbose_sessions=\"true\" verbose_changes=\"true\">
		\		<default out_volume=\"80\" volume=\"95\" muted=\"false\"/>
#		\		<channel_list>
#		\			<channel type=\"output\" label=\"master\" name=\"left\" number=\"0\" active=\"1\" volume=\"100\" muted=\"false\"/>
#		\			<channel type=\"output\" label=\"master\" name=\"right\" number=\"1\" active=\"1\" volume=\"100\" muted=\"false\"/>
#		\		</channel_list>
		\	</config>
		\	<route>
		\		<service name=\"LOG\"> $(LogOutput_Terminal_or_Serial) </service>
		\		<service name=\"Audio_out\"> <child name=\"audio\"/> </service>  <!-- was: audio_drv -->
		\		<service name=\"Report\"> <child name=\"report_rom\"/> </service> <!-- Otherwise mixer errors out with "cannot create mixer channels Report.." -->
		\		<any-service> <parent/> <any-child/> </any-service>
		\	</route>
		"
			;
		#xxx temporary, until I fix OSS/mixer interaction on Audio-IN:
		AddComponentService $(runfile) : 1M : black_hole : Audio_in Play :
			<config>
				<audio_in/>
#///FIXME: remove Play+<play/> here, added recently for new Falkon package : once we actually support (migrate to) Play we can revert this
				<play/>
			</config>
			;
		}
	}
	else  # QEMU emulation (probably), so favor light-weight options
	{
		# We don't add a mixer here, so run scripts have to use default routing instead of route-to-mixer.
		AddComponentService $(runfile) : 1M : black_hole : Play Record Audio_out Audio_in :
			<config>
				<play/>
				<record/>
				<audio_out/>
				<audio_in/>
			</config>
			;
	}
}



rule AddWifiStack  runfile : wifi_ssid : wpa2_passphrase
{
	# We don't call "AddBootModule wifi wpa_supplicant.lib.so etc":
	# instead we require the user to use (wired!) networking to download
	# package "genodelabs/pkg/pc_wifi" to the HDD (NTFS?) partition,
	# and then we leverage that below.
	
	local LogOutput_Terminal_or_Serial = "<child name=\"terminal_log\"/> <parent/>" ;
	
	if ! $(wifi_ssid) {
		Exit "AddWifiStack: no wifi SSID specified" ;
	}
	if ! $(wpa2_passphrase) {
		Exit "AddWifiStack: no wifi passphrase specified" ;
	}
	
	# Can't call "AddComponentAsStart wifi" as that requires existence of wifi as a boot-module (rather than as an FS file),
	# so force the CONF appending by calling AddRawComponent with a 'dummy' (here: nic_router) bin:
	#
	#AddComponentAsStart $(runfile)
	AddRawComponent  $(runfile) : nic_router : nic_router :
		"	<start name=\"wifi\" caps=\"300\">
#/// no <provides> node ? The genode .run files have "provide service Nic" nodes here...
	\			<resource name=\"RAM\" quantum=\"32M\"/>
	\			<config ld_verbose=\"no\">
	\				<libc stdout=\"/dev/log\" stderr=\"/dev/log\" rtc=\"/dev/rtc\"/>
	\				<vfs>
	\					<dir name=\"dev\">
	\						<log/> <rtc/> <null/>
	\						<jitterentropy name=\"random\"/>
	\						<jitterentropy name=\"urandom\"/>
	\					</dir>
				#		<dir name="config"> <ram/> </dir>
	\					<dir name=\"firmware\">
	\						<tar name=\"wifi_firmware.tar\"/>
	\					</dir>
	\				</vfs>
	\			</config>
	\			<route>
# Disable 'windowed' logging for now: super verbose, and can't find a way to separate the chaff from the wheat...
# re enable:
	\				<service name=\"LOG\"> $(LogOutput_Terminal_or_Serial) </service>
	\				<service name=\"ROM\" label=\"wifi_config\"> <child name=\"wifi_conf_rom\"/> </service>
	\				<service name=\"Platform\"> <child name=\"platform\"/> <child name=\"drivers_init\" label=\"-> wifi\"/> </service>
			<service name=\"Report\" label=\"accesspoints\"> <child name=\"accesspoints_report_rom\"/> </service>
			<service name=\"Report\" label=\"state\"> <child name=\"accesspoints_report_rom\"/> </service>
#			<service name=\"Report\" label=\"state\"> <child name=\"state_report_rom\"/> </service>

		# Hack, route all ROMs to a particular depot package
		#///later: write a "runtime" file, so that wifi can be started/stopped, and without hardcoding routes ?
	\				<service name=\"ROM\" label_last=\"wifi\">
	\					<child name=\"cached_fs_rom\" label=\"/depot/genodelabs/bin/x86_64/pc_wifi/2024-11-19/wifi\"/> </service>
	\				<service name=\"ROM\" label=\"wifi.lib.so\">
	\					<child name=\"cached_fs_rom\" label=\"/depot/genodelabs/bin/x86_64/pc_wifi/2024-11-19/pc_wifi.lib.so\"/> </service>
	\				<service name=\"ROM\" label=\"wpa_supplicant.lib.so\">
	\					<child name=\"cached_fs_rom\" label=\"/depot/genodelabs/bin/x86_64/pc_wifi/2024-11-19/wpa_supplicant.lib.so\"/> </service>
	\				<service name=\"ROM\" label=\"wpa_driver_nl80211.lib.so\">
	\					<child name=\"cached_fs_rom\" label=\"/depot/genodelabs/bin/x86_64/pc_wifi/2024-11-19/wpa_driver_nl80211.lib.so\"/> </service>
	\				<service name=\"ROM\" label=\"wifi_firmware.tar\">
	\					<child name=\"cached_fs_rom\" label=\"/depot/genodelabs/raw/pc_wifi_firmware/2024-10-29/pc_wifi_firmware.tar\"/> </service>
	\				<service name=\"ROM\" label=\"vfs_jitterentropy.lib.so\">
	\					<child name=\"cached_fs_rom\" label=\"/depot/genodelabs/bin/x86_64/vfs_jitterentropy/2024-11-19/vfs_jitterentropy.lib.so\"/> </service>
					#xxx libcrypto.lib.so, vfs, libc should also be routed to their packaged variants...
	\				<any-service> <parent/> <any-child/> </any-service>
	\			</route>
	\	</start>
		"
		;
	
	AddComponentAsStart  $(runfile) : 2M : report_rom :
			"name=\"accesspoints_report_rom\" caps=\"120\"" :
		"	<binary name=\"report_rom\"/>
		\		<provides> <service name=\"Report\"/> <service name=\"ROM\"/> </provides>
		\		<config verbose=\"no\">
#		\			<policy label_prefix=\"drivers_init\"	report=\"registrar -> system\"/>
		\		</config>
		"
		;
	
	#///ToDo-2: implement this wifi config hack with *rom_filter* (like event config) instead of dynamic_rom, since dynamic_rom is only ever used here -- we can get rid of the boot module and build step if we get rid of it
	AddComponentAsStart $(runfile) : 4M
		: dynamic_rom : "name=\"wifi_conf_rom\" caps=\"290\"" :
	"
	\		<binary name=\"dynamic_rom\"/>
	\		<provides><service name=\"ROM\"/></provides>
	\		<config  verbose=\"no\">
	\		<rom name=\"wifi_config\">
	\			<inline description=\"CONNECT\">
<wifi_config  scan_interval=\"10\" rfkill=\"no\" verbose=\"no\" log_level=\"warning\" update_quality_interval=\"30\">
\   <network ssid=\"$(wifi_ssid)\" protection=\"WPA2\" passphrase=\"$(wpa2_passphrase)\"/>
</wifi_config>
				</inline>
				<sleep milliseconds=\"60000\"/> <!-- 1 minute -->
			</rom>
	\		</config>
		"
		;
}


#///later: rename to "AddNetworkingStack"
rule AddNetworkingComponents  runfile
{
	local LogOutput_Terminal_or_Serial = "<child name=\"terminal_log\"/> <parent/>" ;
	
	# lwip versus lxip:
	# most everybody can accomodate the simpler lightweight-IP (except vnc_server which is more stable with linux-IP, but gets it via packaging, so no need to include it in boot-modules here)
	AddBootModule	$(runfile) : vfs_lwip.lib.so ;  # Needed by Falkon web browser
#	AddBootModule	$(runfile) : vfs_lxip.lib.so ;
#	AddBootModule	$(runfile) : lxip.lib.so ;
	
	AddComponentAsStart $(runfile) : 10M
		: nic_router : "name=\"nic_router\" caps=\"290\"" :
	"		<provides> <service name=\"Nic\"/> <service name=\"Uplink\"/> </provides>
	\		<config  verbose=\"no\"  verbose_packets=\"no\"  verbose_domain_state=\"yes\" verbose_packet_drop=\"no\"  dhcp_discover_timeout_sec=\"15\">
	\			<policy label_prefix=\"sequence -> nic\"  domain=\"uplink\"/>
	\			<policy label_prefix=\"nic\"  domain=\"uplink\"/>
	\			<policy label_prefix=\"wifi\" domain=\"uplink\"/>
					# full label looks like: "run_depot -> dynamic -> depot: -> vnc_server"
					#///ToDo: can't get this to work, it always ends up in domain "default" instead...
	\			<policy label=\"run_depot -> dynamic -> depot:vnc_server -> vnc_server\"	domain=\"vnc_5900\"/>
#///ToDo: moved default-policy down... Test vnc_server again ?
	\			<default-policy domain=\"default\" />
	\
#	\			<domain name=\"uplink\" verbose_packets=\"no\" interface=\"192.168.1.51/24\" gateway=\"192.168.1.1\" >
	\			<domain name=\"uplink\" verbose_packets=\"no\">  <!-- use_arp=\"no\" ? -->
	\					<!-- Respond to inbound packets and forward themm to downlink apps
	\						We somehow match IP addies and ports so they're easier to remember (.3.21 for port 21 and so on)
	\						-->
	\				<nat domain=\"default\"
	\				     tcp-ports=\"16384\"
	\				     udp-ports=\"16384\"
	\				     icmp-ids=\"16384\"/>
	\				<nat domain=\"vnc_5900\"
	\				     tcp-ports=\"16384\"
	\				     udp-ports=\"16384\"
	\				     icmp-ids=\"16384\"/>
	\				<tcp-forward port=\"21\"   domain=\"default\" to=\"10.0.3.21\"/>  <!-- ftpd -->
#	\				<tcp-forward port=\"5900\" domain=\"default\" to=\"10.0.3.11\"/>  <!-- VNC server's 10.0.3.11 is safely outside of the (below) DHCP range -->
#///ToDo: vnc static IP: debug in QEMU ? Try use_arp = no ? For now, assume VNC server is at 1.0.3.101, works fine.
	\				<tcp-forward port=\"5900\" domain=\"default\" to=\"10.0.3.101\"/>  <!-- VNC server's 10.0.3.11 is safely outside of the (below) DHCP range -->
#	\				<tcp-forward port=\"5900\" domain=\"vnc_5900\" to=\"10.0.3.11\"/>  <!-- VNC server's 10.0.3.11 is safely outside of the (below) DHCP range -->
	\				<tcp-forward port=\"22\"   domain=\"default\" to=\"10.0.3.12\"/>  <!-- sftpd (SSH ftpd, port 22 instead of 21) -->
	\			</domain>
	\
			"
		# -- split string to dodge Jam crash --  (or as the case may be, error message "MAXSYM is too low!")
			"
	\			<domain name=\"vnc_5900\" interface=\"10.0.3.2/24\">
	\				<tcp  dst=\"0.0.0.0/0\"> <permit-any domain=\"uplink\"/> </tcp>
	\				<dhcp-server ip_first=\"10.0.3.11\" ip_last=\"10.0.3.11\" dns_config_from=\"uplink\" />
	\			</domain>
	\			<!--
	\				* reserve 10.0.3.1   to 10.0.3.10 for static IPs of 'interfaces-domains' ?
	\				* reserve 10.0.3.11  to 10.0.3.99 for static IPs of VNC server, FTP server, etc that require port-forwarding/NAT mapping of inbound connections
	\		* 10.0.4.11 in fact for VNC.... ?
	\				* reserve 10.0.3.100 to 10.0.3.200 for DHCP (sub-network IPs) for other (client) apps
	\			-->
	\			<domain name=\"default\" interface=\"10.0.3.1/24\">  <!-- also typical: name='downlink' -->
	\					<!-- Allow outbound connections and 'pings' through uplink NIC -->
	\				<tcp  dst=\"0.0.0.0/0\"> <permit-any domain=\"uplink\"/> </tcp>
	\				<udp  dst=\"0.0.0.0/0\"> <permit-any domain=\"uplink\"/> </udp>
	\				<icmp dst=\"0.0.0.0/0\" domain=\"uplink\"/>
	\				<dhcp-server ip_first=\"10.0.3.100\" ip_last=\"10.0.3.200\" dns_config_from=\"uplink\">
	\						<!-- misc params: ip_lease_time_sec=... -->
	#	\					<dns-server ip=\"8.8.8.8\">  <!-- the DNS can be overriden (if e.g. the DHCP-provided one is unreliable) -->
	\				</dhcp-server>
	\			</domain>
	\		</config>
	\		<route>
	\			<service name=\"LOG\"> $(LogOutput_Terminal_or_Serial) </service>
	\			<any-service> <parent/> <any-child/> </any-service>
	\		</route>
		"
		;
	
	if ! 1
	{
		AddComponentAsStart $(runfile) : 10M
			: pc_nic : "name=\"nic\" caps=\"250\"" :  # was: pc_nic_drv / nic_drv
		"		<binary name=\"pc_nic\"/>
		\		<config>
		\		</config>
		\		<route>
		\			<service name=\"LOG\"> $(LogOutput_Terminal_or_Serial) </service>
		\			<any-service> <parent/> <any-child/> </any-service>
		\		</route>
			"
			;
	}
	else
	{
		# Don't launch immediately, as that won't work on e.g. ThinkCentre M73, delay by 8 seconds (5 secs seems a little iffy):
			#///ToDo: "sleep" is not part of the repo currently ; neither 'binutils' nor a custom-made one, this breaks "jam t9"
		AddRawComponent $(runfile) : sleep	: sleep ;
		AddRawComponent $(runfile) : pc_nic	: pc_nic ;
		AddComponentAsStart $(runfile) : 16M
			: sequence : "name=\"sequence\" caps=\"290\"" :
		"		<config>
		\			<start name=\"sleep\" caps=\"100\">
	#				<start name=\"/bin/sleep\" caps=\"100\">
		\				<config>
		\					<libc stdin=\"/dev/null\" stdout=\"/dev/log\" stderr=\"/dev/log\"/>
		\					<arg value=\"/bin/sleep\"/>
		\					<arg value=\"8\"/>
		\					<vfs>
		\		 				<dir name=\"dev\"> <log/> <null/> </dir>
		\					</vfs>
		\				</config>
		\			</start>
		\			
		\			<start name=\"nic\" caps=\"250\"  >
		\				<binary name=\"pc_nic\"/>
		\				<config>
		\				</config>
		\			</start>
		\		</config>
		\		<route>
#		\			<service name=\"LOG\"> $(LogOutput_Terminal_or_Serial) </service>
		\			<service name=\"Platform\"> <child name=\"platform\"/> <child name=\"drivers_init\" label=\"-> nic\"/> </service>
		\			<any-service> <parent/> <any-child/> </any-service>
		\		</route>
			"
			;
	}
}


rule AddDynitLauncher  runfile : vfs_server_name : ram_quota_Init
{
	# Run...
	# * an init named "dynit" (short for dynamically-configured init)
	# * a  report_rom to drive the config (application list) of that init
	# * an fs_rom to provide app ROMs for loading/executing them in the init
	# Requirements:
	# * the vfs that fs_rom relies on is not provided -> provide it and pass its name as second parameter
	
	vfs_server_name	?= "vfs_unspecified" ;
	ram_quota_Init	?= "1G" ;
	
	local LogOutput_Terminal_or_Serial = "<child name=\"terminal_log\"/> <parent/>" ;
	local LogOutput_TermApp_or_Serial = "<child name=\"term_app_log\"/> <parent/>" ;
	
	#///ToDo-2: what to do on fs_rom "resource request" ? (currently occurs after running 10 small'ish apps or so). Maybe fs_rom should be moved to *within* dynit ?
	# fs_rom needs 7 MB for AK et al, 10+ MB for AC, and multiple times that if several apps are launched concurrently!
	AddComponentService $(runfile) : 100M : cached_fs_rom : ROM : "
	#///ToDo-2: fs_rom forwards the path as-is to $vfs_server_name (e.g. vfs_ram), so e.g. it requests "/boot/system/bin/top" to it, without stripping the leading "/boot" prefix... Hacked around that for now, with the "nano3d" and "top" example, but should find an actual solution.
		#	\		<config/>
	\		<route>
	\			<service name=\"LOG\"> $(LogOutput_Terminal_or_Serial) </service>
	\			<service name=\"File_system\"> <child name=\"$(vfs_server_name)\"/> </service>
	\			<any-service> <parent/> <any-child/> </any-service>
	\		</route>
		"
		;
	
	#///ToDo-2: rename to "dynit_deploy_report_rom" ?  or "installrun_report_rom" ?
	AddComponentAsStart  $(runfile) : 4M : report_rom :
			"name=\"dynit_report_rom\" caps=\"120\"" :
		"		<binary name=\"report_rom\"/>
		\		<provides> <service name=\"Report\"/> <service name=\"ROM\"/> </provides>
		\		<config verbose=\"no\">
		\			<policy  label_suffix=\"manager -> installation\"  report=\"dynit -> installation_for_manager\" />
		\				<!-- registrar-to-dynit support: -->
		\				<!-- Only registrar is allowed to drive dynit's config (others do not have access/maintain the 'runners state')  -->
		\			<policy  label_prefix=\"dynit\"			report=\"registrar -> dynit_config\"/>
		\				<!-- Notices go the other way, from dynit to registrar  -->
		\			<policy label=\"registrar -> state\"	report=\"dynit -> state\"/>
		\				<!-- registrar-to-depot_deploy support: -->
		\			<policy  label=\"run_depot -> depotdeploy.config\"  report=\"registrar -> depotdeploy.config\"/>
		\		</config>
		\		<route>
		\			<service name=\"LOG\"> $(LogOutput_Terminal_or_Serial) </service>
		\			<any-service> <parent/> <any-child/> </any-service>
		\		</route>
		"
		;
	AddComponentAsStart  $(runfile) : $(ram_quota_Init) :
		init : "name=\"dynit\" caps=\"2300\"" :
		"		<binary name=\"init\" />
	\		<route>
	\			<service name=\"ROM\" label=\"config\">
	\				<child name=\"dynit_report_rom\" label=\"dynit_config\"/>
	\			</service>
					# Report all exits/crashes (they will be observed by registrar)  --  Requires: activate reports with a <report/> node in the init/dynit
	\			<service name=\"Report\" label=\"state\">
	\				<child name=\"dynit_report_rom\"/>
	\			</service>
	\				<!-- Support specific to GeDepot: -->
	\			<service name=\"Report\" label=\"dyn/GeDepot -> installation_for_manager\">
	\				<child name=\"dynit_report_rom\" label=\"dynit -> installation_for_manager\" />
	\			</service>
	\				<!-- Support specific to part_block: -->
	\			<service name=\"Block\" label=\"dyn/part_block -> \">
	\				<child name=\"drivers_init\" label=\"ahci: default\" />
	\				<child name=\"ahci\" />  <!-- was: ahci_drv -->
	\			</service>
	\			<service name=\"Report\" label=\"dyn/part_block -> partitions\">
	\				<child name=\"storage_report_rom\" label=\"part_block -> partitions\"/>
	\			</service>
##	\			<service name=\"Report\"> <child name=\"dynit_report_rom\"/> </service>
					# wildcard: just set "label_prefix='' (empty string)"...
					# UPD: what we *really* want is to map /foo/something, NOT the boot-modules ROMs ! So distinguish between those slash-less or not:
				# careful with blanket routing, must not mess up basic ROM access
				# otherwise that prevents routing to even "ld.lib.so", the very
				# first needed library, which triggers a NULL-ptr crash in init...
				#
				# Don't route libc.lib.so etc through fs_rom:
				# - they are typically *not* present as vfs files, and
				# - even if they were, we don't want to waste memory within the tight fs_rom quota
				# If fs_rom is asked for a non-existend library, it returns an empty(?) file
				# and we get "Error: binary is not an ELF", so careful with these:
				# (and use "label_suffix" instead of "label" for all but ld.lib.so....):
	\			<service name=\"ROM\" label=\"ld.lib.so\"> <parent/> </service>
	\			<service name=\"ROM\" label_suffix=\"libc.lib.so\"> <parent/> </service>
	\			<service name=\"ROM\" label_suffix=\"libm.lib.so\"> <parent/> </service>
					# for mkntfs etc:
	\			<service name=\"ROM\" label_suffix=\"posix.lib.so\"> <parent/> </service>
	\			<service name=\"ROM\" label_suffix=\"vfs.lib.so\"> <parent/> </service>
	\			<service name=\"ROM\" label_suffix=\"stdcxx.lib.so\"> <parent/> </service>
	\			<service name=\"ROM\" label_suffix=\"haiku.lib.so\"> <parent/> </service>
	\			<service name=\"ROM\" label_suffix=\"zlib.lib.so\"> <parent/> </service>
	\			<service name=\"ROM\" label_suffix=\"jpeg.lib.so\"> <parent/> </service>
	\			<service name=\"ROM\" label_suffix=\"vfs_oss.lib.so\"> <parent/> </service>
	\			<service name=\"ROM\" label_suffix=\"avcodec.lib.so\"> <parent/> </service>
	\			<service name=\"ROM\" label_suffix=\"avfilter.lib.so\"> <parent/> </service>
	\			<service name=\"ROM\" label_suffix=\"avformat.lib.so\"> <parent/> </service>
	\			<service name=\"ROM\" label_suffix=\"avutil.lib.so\"> <parent/> </service>
	\			<service name=\"ROM\" label_suffix=\"avresample.lib.so\"> <parent/> </service>
	\			<service name=\"ROM\" label_suffix=\"swscale.lib.so\"> <parent/> </service>
		# Needed by vfs server(s), not by clients:
		#  vfs_pipe.lib.so, vfs_fuse.lib.so, vfs_indexer.lib.so
#	\			<service name=\"ROM\" label_suffix=\"lxip.lib.so\"> <parent/> </service>
#	\			<service name=\"ROM\" label_suffix=\"vfs_lxip.lib.so\"> <parent/> </service>
	\			<service name=\"ROM\" label_suffix=\"vfs_lwip.lib.so\"> <parent/> </service>
	"
		# --- need to *split* the string in two smaller halves here, as a single big string *crashes* jam.... ---
	"
	\			<service name=\"ROM\" label_suffix=\".lib.so\">
					# prioritize parent (i.e. we consume the fs_rom quota *only* if the target is not found in parent):
	\				<child name=\"cached_fs_rom\"/>
			#///ToDo: we cannot have a "prioritized fall back" as there is NO fallback, how come ?
			# if <parent> comes first, and it fails to find the ROM, it does NOT fall back to fs_rom, and same problem the other way around...
			#	\				<parent/>
	\			</service>
					# Do route "/appname" (e.g. "/boot/Pulse") to cached_fs_rom:
	\			<service name=\"ROM\" label_prefix=\"/\">  <!-- prefix is '/' slash ! -->
	\				<child name=\"cached_fs_rom\"/>
	\			</service>
	\			<service name=\"LOG\"> $(LogOutput_TermApp_or_Serial) </service>
	\			<service name=\"Gui\" label=\"ge_wm_gui\">  <child  name=\"wm\"/> <parent/> <any-child/> </service>  <!-- Genode apps (nano3d, Falkon) : route Gui to WM, if available -->
	\			<service name=\"Gui\">  <child  name=\"nitpicker\"/> </service>  <!-- Be apps: route directly to nitpicker -->
	\			<service name=\"Audio_out\"><child  name=\"mixer\"/> <child name=\"black_hole\"/></service>
	\			<service name=\"Play\">		<child  name=\"mixer\"/> </service>
	\			<service name=\"File_system\"  label_suffix=\"downstream\">
	\				<child name=\"vfs\"/>
	\			</service>
	\			<service name=\"File_system\"  label_suffix=\"part_boot\">
	\				<child name=\"$(vfs_server_name)\"/>
	\			</service>
#	\			<service name=\"File_system\"  label_suffix=\"part_boot2\">
#	\				<child name=\"vfs_nt2\"/>
#	\			</service>
	\			<any-service> <parent/> <any-child/> </any-service>
	\		</route>
		"
		;
}


#### stub out stock Haiku jamfiles stuff to silence "unknown rule" warnings ##############
#

#///ToDo: move to a "dummies.inc" file

rule DoCatalogs
{
}
rule TargetLibsupc++
{
}
rule TargetLibstdc++
{
}
rule AddSubDirSupportedPlatforms
{
}
# For Tracker:
#///ToDo: xxxx Move these to Jamrules ? xxxxxxx
rule MultiArchSubDirSetup
{
	return foo_arch_object ;
}
rule MultiArchDefaultGristFiles full_name
{
	return $(full_name) ;
}
rule SharedLibrary libname : sources : ignored_stuff
{
	# !
	if $(LayerLevel) >= 8
	{
		HaikuKit tracker.a  # ! and not $(libname) !
			:
			$(sources)
			;
	}
}

#///later-2: implement ResAttr (stubbed out) for preferences/mail
rule ResAttr  file : res_def : flag
{
	#Echo "ResAttr  $(file) $(res_def) $(flag)" ;
}


#### forward/alias some Haiku build system rules ##############
# 

rule SetSubDirSupportedPlatformsBeOSCompatible
{
	# Used throughout our imported Jamfiles -- forward to our own header rules:
	
	SetupHeadersHoG ;
}

rule UseLibraryHeaders  libs
{
	# Used by icon-o-matic
	HDRS +=
		$(HoG_TOP)/hai-src/libs/$(libs)
		;
}

rule Preference  exe : sources : libs
{
	# for building e.g. E-Mail preflet -- just alias to the app rule:
	Application  $(exe) : $(sources) : $(libs) ;
}

rule BinCommand  execmd : sources : libs
{
	# Used e.g. to build src/bin/network/ftpd/ftpd, or our custom "sleep" command.
	# forward to the "link against libc.lib.so, but not haiku.lib.so" rule:
	
	if $(libs) { Echo "BinCommand: ignoring 'libs' param: $(libs)" ; }
	
	# T- (!)
	AddMaskedLibrary $(execmd) : posix ;  # Add posix.lib.so, since rule PosixExecutable does not add it itself
	# T+
	PosixExecutable  $(execmd) : $(sources) ;
}

rule StaticLibrary  lib : sources
{
	# Used by hai-src/libs/mapm when building DeskCalc, by libs/agg when building icon-o-matic
	
	Library  $(lib) : $(sources) ;
	
	# create the .a library inside build/x86_64/var/run/_common_/linking_abis, to be found when linking the final exe
	# (xxxx This does "solve" the linking stage, but... could this be done better ?)
	MakeLocate $(lib:S=.a) : $(GenodeAbi) ;  # unlike rule Library, MakeLocate seems to require being told about the .a suffix ; otherwise one cannot invoke simply "StaticLibrary libntfs-3g"
}


