Bearsampp 2026.5.5
Loading...
Searching...
No Matches
class.action.loading.php
Go to the documentation of this file.
1<?php
2/*
3 *
4 * * Copyright (c) 2022-2025 Bearsampp
5 * * License: GNU General Public License version 3 or later; see LICENSE.txt
6 * * Website: https://bearsampp.com
7 * * Github: https://github.com/Bearsampp
8 *
9 */
10
17{
19 const WINDOW_WIDTH = 360;
20
22 const WINDOW_HEIGHT = 90;
23
25 const GAUGE = 20;
26
28 private $wbWindow;
29
31 private $wbLabel;
32
35
43 public function __construct($args)
44 {
45 global $bearsamppCore, $bearsamppLang, $bearsamppWinbinder;
46
47 $currentPid = Win32Ps::getCurrentPid();
48 Log::trace('ActionLoading constructor started - PID: ' . $currentPid);
49
50 $bearsamppWinbinder->reset();
51 Log::trace('WinBinder reset complete');
52
53 $bearsamppCore->addLoadingPid($currentPid);
54 Log::trace('Loading PID added to tracking file: ' . $currentPid);
55
56 // Screen information
57 Log::trace('Getting screen information');
58 $screenArea = explode(' ', $bearsamppWinbinder->getSystemInfo(WinBinder::SYSINFO_WORKAREA));
59 $screenWidth = intval($screenArea[2]);
60 $screenHeight = intval($screenArea[3]);
61 $xPos = $screenWidth - self::WINDOW_WIDTH;
62 $yPos = $screenHeight - self::WINDOW_HEIGHT - 5;
63 Log::trace('Screen dimensions: ' . $screenWidth . 'x' . $screenHeight . ', Window position: (' . $xPos . ',' . $yPos . ')');
64
65 // Create the window and progress bar
66 Log::trace('Creating loading window...');
67 $this->wbWindow = $bearsamppWinbinder->createWindow(null, ToolDialog, null, $xPos, $yPos, self::WINDOW_WIDTH, self::WINDOW_HEIGHT, WBC_TOP, null);
68
69 // Check if window was created successfully
70 if ($this->wbWindow === false || $this->wbWindow === null) {
71 Log::error('CRITICAL: Failed to create loading window - window handle is: ' . var_export($this->wbWindow, true));
72 Log::error('WinBinder extension loaded: ' . (extension_loaded('winbinder') ? 'YES' : 'NO'));
73 Log::error('wb_create_window function exists: ' . (function_exists('wb_create_window') ? 'YES' : 'NO'));
74 return;
75 }
76
77 Log::trace('Loading window created successfully - handle: ' . $this->wbWindow);
78
79 // CRITICAL: wb_set_visible() must be called AFTER window creation in PHP 8.4
80 // The WS_VISIBLE flag during creation doesn't work
81 Log::trace('Making window visible with wb_set_visible()');
82 wb_set_visible($this->wbWindow, true);
83 Log::trace('Window set to visible');
84
85 Log::trace('Drawing image...');
86 $bearsamppWinbinder->drawImage($this->wbWindow, $bearsamppCore->getImagesPath() . '/bearsampp.bmp');
87 Log::trace('Image drawn');
88
89 Log::trace('Creating progress bar...');
90 $this->wbProgressBar = $bearsamppWinbinder->createProgressBar($this->wbWindow, self::GAUGE + 1, 42, 24, self::WINDOW_WIDTH - 62, 15);
91 Log::trace('Progress bar created: ' . var_export($this->wbProgressBar, true));
92
93 Log::trace('Drawing initial text...');
94 $this->wbLabel = $bearsamppWinbinder->drawText($this->wbWindow, '', 42, 0, self::WINDOW_WIDTH - 64, 25);
95 Log::trace('Label created: ' . var_export($this->wbLabel, true));
96
97 // Set the handler and start the main loop
98 Log::trace('Setting window handler...');
99 $bearsamppWinbinder->setHandler($this->wbWindow, $this, 'processLoading', 10);
100 Log::trace('Handler set, starting main loop...');
101 $bearsamppWinbinder->mainLoop();
102 Log::trace('Main loop exited');
103 }
104
110 public function incrProgressBar($nb = 1)
111 {
112 global $bearsamppCore, $bearsamppWinbinder;
113
114 for ($i = 0; $i < $nb; $i++) {
115 $bearsamppWinbinder->incrProgressBar($this->wbProgressBar);
116 $bearsamppWinbinder->drawImage($this->wbWindow, $bearsamppCore->getImagesPath() . '/bearsampp.bmp', 4, 2, 32, 32);
117 }
118
119 $bearsamppWinbinder->wait();
120 $bearsamppWinbinder->wait($this->wbWindow);
121 }
122
132 public function processLoading($window, $id, $ctrl, $param1, $param2)
133 {
134 global $bearsamppRoot, $bearsamppWinbinder;
135
136 switch ($id) {
137 case IDCLOSE:
139 break;
140 }
141
142 // Set a maximum number of iterations to prevent infinite loops
143 $maxIterations = 10;
144 $iterations = 0;
145
146 // Set a timeout for the entire loading process
147 $startTime = microtime(true); // Use microtime for more precise timing
148 $maxLoadingTime = 15; // 15 seconds maximum
149
150 while ($iterations < $maxIterations && (microtime(true) - $startTime) < $maxLoadingTime) {
151 $bearsamppRoot->removeErrorHandling();
152 $bearsamppWinbinder->resetProgressBar($this->wbProgressBar);
153
154 usleep(100000);
155
156 for ($i = 0; $i < self::GAUGE && (microtime(true) - $startTime) < $maxLoadingTime; $i++) {
157 $this->incrProgressBar();
158
159 // Check for status file updates to show current service being processed
161
162 usleep(100000);
163 }
164
165 // Check if all services have started successfully
166 $allServicesStarted = $this->checkAllServicesStarted();
167 if ($allServicesStarted) {
168 Log::trace('All services started successfully');
169 break;
170 }
171
172 $iterations++;
173 Log::trace('Loading iteration ' . $iterations . ' completed, checking services again');
174 }
175
176 if ($iterations >= $maxIterations) {
177 Log::trace('Maximum iterations reached (' . $maxIterations . '), some services may not have started properly');
178 }
179
180 if ((microtime(true) - $startTime) >= $maxLoadingTime) {
181 Log::trace('Loading timeout reached (' . $maxLoadingTime . ' seconds), some services may not have started properly');
182 }
183
184 // Close the loading window
185 Log::trace('Closing loading window');
187 }
188
194 private function updateLoadingText($text)
195 {
196 global $bearsamppWinbinder;
197
198 if ($this->wbLabel) {
199 wb_set_text($this->wbLabel, $text);
200 wb_refresh($this->wbWindow);
201 }
202 }
203
208 private function updateLabelFromStatusFile()
209 {
210 global $bearsamppCore, $bearsamppWinbinder;
211
212 $statusFile = $bearsamppCore->getTmpPath() . '/loading_status.txt';
213
214 if (file_exists($statusFile)) {
215 $content = @file_get_contents($statusFile);
216 if ($content !== false && !empty($content)) {
217 $status = @json_decode($content, true);
218 if ($status && isset($status['text']) && !empty($status['text'])) {
219 // Clear the text area and redraw with new text
220 $bearsamppWinbinder->drawRect($this->wbWindow, 42, 0, self::WINDOW_WIDTH - 52, 25);
221 $this->wbLabel = $bearsamppWinbinder->drawText($this->wbWindow, $status['text'], 42, 0, self::WINDOW_WIDTH - 64, 25);
222 }
223 }
224 } else {
225 // If no status file exists, show a default message
226 $currentText = $this->wbLabel;
227 if (empty($currentText)) {
228 $bearsamppWinbinder->drawRect($this->wbWindow, 42, 0, self::WINDOW_WIDTH - 52, 25);
229 $this->wbLabel = $bearsamppWinbinder->drawText($this->wbWindow, 'Processing...', 42, 0, self::WINDOW_WIDTH - 64, 25);
230 }
231 }
232 }
233
241 private function checkAllServicesStarted()
242 {
243 global $bearsamppBins;
244
245 Log::trace('Checking if all services have started successfully');
246
247 // getServices() already filters to enabled-only services
248 $allStarted = true;
249 foreach ($bearsamppBins->getServices() as $sName => $service) {
250 $serviceName = $service->getName();
251 $this->updateLoadingText('Checking ' . $serviceName . '...');
252
253 try {
254 $state = Win32Native::getServiceState($serviceName);
255 $serviceRunning = ($state === 'Running');
256 Log::trace('Service ' . $sName . ' status check: ' . ($serviceRunning ? 'running' : 'not running') . ' (state: ' . var_export($state, true) . ')');
257 } catch (\Throwable $e) {
258 Log::trace('Exception during service status check for ' . $sName . ': ' . $e->getMessage());
259 $serviceRunning = false;
260 }
261
262 if (!$serviceRunning) {
263 Log::trace('Service ' . $sName . ' is not running');
264 $allStarted = false;
265 break;
266 }
267 }
268
269 Log::trace('All services started check result: ' . ($allStarted ? 'true' : 'false'));
270 return $allStarted;
271 }
272}
global $bearsamppBins
global $bearsamppLang
global $bearsamppRoot
global $bearsamppCore
processLoading($window, $id, $ctrl, $param1, $param2)
static trace($data, $file=null)
static error($data, $file=null)
static getServiceState($serviceName)
static getCurrentPid()
static kill($pid)
const SYSINFO_WORKAREA