Skip to content

Commit 6c3e8fd

Browse files
committed
New API - webui_focus
1 parent 6471626 commit 6c3e8fd

File tree

2 files changed

+126
-29
lines changed

2 files changed

+126
-29
lines changed

include/webui.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,15 @@ WEBUI_EXPORT bool webui_show_wv(size_t window, const char* content);
393393
*/
394394
WEBUI_EXPORT void webui_set_kiosk(size_t window, bool status);
395395

396+
/**
397+
* @brief Bring a window to the front and focus it.
398+
*
399+
* @param window The window number
400+
*
401+
* @example webui_focus(myWindow);
402+
*/
403+
WEBUI_EXPORT void webui_focus(size_t window);
404+
396405
/**
397406
* @brief Add a user-defined web browser's CLI parameters.
398407
*

src/webui.c

Lines changed: 117 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -477,7 +477,7 @@ typedef struct _webui_core_t {
477477
bool is_main_run;
478478
bool is_browser_mode;
479479
// WebView
480-
bool is_webview;
480+
bool is_webview_mode;
481481
#ifdef _WIN32
482482
char* webview_cacheFolder;
483483
HMODULE webviewLib;
@@ -985,7 +985,7 @@ bool webui_script_client(webui_event_t* e, const char* script, size_t timeout,
985985
js_status = _webui.run_done[run_id];
986986
_webui_mutex_unlock(&_webui.mutex_js_run);
987987
#if __linux__
988-
if (_webui.is_webview) {
988+
if (_webui.is_webview_mode) {
989989
while (gtk_events_pending()) {
990990
gtk_main_iteration_do(0);
991991
}
@@ -1005,7 +1005,7 @@ bool webui_script_client(webui_event_t* e, const char* script, size_t timeout,
10051005
js_status = _webui.run_done[run_id];
10061006
_webui_mutex_unlock(&_webui.mutex_js_run);
10071007
#if __linux__
1008-
if (_webui.is_webview) {
1008+
if (_webui.is_webview_mode) {
10091009
while (gtk_events_pending()) {
10101010
gtk_main_iteration_do(0);
10111011
}
@@ -1884,6 +1884,68 @@ bool webui_show_client(webui_event_t* e, const char* content) {
18841884
return _webui_show(win, _webui.clients[e->connection_id], content, AnyBrowser);
18851885
}
18861886

1887+
#ifdef _WIN32
1888+
// Callback for EnumWindows used to find the window handle of the web browser process
1889+
// and bring it to the foreground (front).
1890+
BOOL CALLBACK _webui_win32_enum_proc(HWND hwnd, LPARAM lParam) {
1891+
DWORD targetPid = (DWORD)lParam;
1892+
DWORD pid = 0;
1893+
GetWindowThreadProcessId(hwnd, &pid);
1894+
if (pid == targetPid && IsWindowVisible(hwnd)) {
1895+
// Restore if minimized
1896+
if (IsIconic(hwnd)) {
1897+
ShowWindow(hwnd, SW_RESTORE);
1898+
}
1899+
// Bring to foreground
1900+
SetForegroundWindow(hwnd);
1901+
// stop enumeration
1902+
return FALSE;
1903+
}
1904+
// continue enumeration
1905+
return TRUE;
1906+
}
1907+
#endif
1908+
1909+
void webui_focus(size_t window) {
1910+
1911+
#ifdef WEBUI_LOG
1912+
_webui_log_info("[User] webui_focus([%zu])\n", window);
1913+
#endif
1914+
1915+
// Initialization
1916+
_webui_init();
1917+
1918+
// Dereference
1919+
if (_webui_mutex_app_is_exit_now(WEBUI_MUTEX_GET_STATUS) || _webui.wins[window] == NULL)
1920+
return;
1921+
_webui_window_t* win = _webui.wins[window];
1922+
1923+
#ifdef _WIN32
1924+
if (_webui.is_webview_mode) {
1925+
// WebView
1926+
void* hwnd = webui_win32_get_hwnd(window);
1927+
if (hwnd) {
1928+
ShowWindow(hwnd, SW_RESTORE);
1929+
SetForegroundWindow((HWND)hwnd);
1930+
SetFocus((HWND)hwnd);
1931+
}
1932+
} else {
1933+
// Web-Browser Window
1934+
DWORD pid = (DWORD)_webui_get_child_process_id(win);
1935+
if (pid != 0) {
1936+
// Set callback for EnumWindows
1937+
EnumWindows(_webui_win32_enum_proc, (LPARAM)pid);
1938+
}
1939+
}
1940+
1941+
#elif __linux__
1942+
// Linux does not have a standard way to bring a window to the foreground from another process.
1943+
// This is a known limitation and may not work on all desktop environments.
1944+
#else
1945+
// macOS does not have a standard way to bring a window to the foreground from another process.
1946+
#endif
1947+
}
1948+
18871949
bool webui_show(size_t window, const char* content) {
18881950

18891951
#ifdef WEBUI_LOG
@@ -2818,7 +2880,7 @@ void* webui_win32_get_hwnd(size_t window) {
28182880
_webui_window_t* win = _webui.wins[window];
28192881

28202882
#ifdef _WIN32
2821-
if (_webui.is_webview) {
2883+
if (_webui.is_webview_mode) {
28222884
// WebView Window
28232885
if (win->webView && win->webView->cpp_handle) {
28242886
return _webui_win32_wv2_get_hwnd(win->webView->cpp_handle);
@@ -2867,7 +2929,7 @@ void* webui_get_hwnd(size_t window) {
28672929
return NULL;
28682930
_webui_window_t* win = _webui.wins[window];
28692931

2870-
if (_webui.is_webview) {
2932+
if (_webui.is_webview_mode) {
28712933
if (win->webView) {
28722934
return win->webView->gtk_win;
28732935
}
@@ -3613,7 +3675,7 @@ static void _webui_wait_clean(bool async) {
36133675

36143676
// Clean
36153677
#ifdef _WIN32
3616-
if (!_webui.is_webview) {
3678+
if (!_webui.is_webview_mode) {
36173679
// Windows Web browser Clean
36183680

36193681
// ...
@@ -3630,7 +3692,7 @@ static void _webui_wait_clean(bool async) {
36303692
CoUninitialize();
36313693
}
36323694
#elif __linux__
3633-
if (!_webui.is_webview) {
3695+
if (!_webui.is_webview_mode) {
36343696
// Linux Web browser Clean
36353697

36363698
// ...
@@ -3660,7 +3722,7 @@ static void _webui_wait_clean(bool async) {
36603722
_webui_wv_free();
36613723
}
36623724
#else
3663-
if (!_webui.is_webview) {
3725+
if (!_webui.is_webview_mode) {
36643726
// macOS Web browser Clean
36653727

36663728
// ...
@@ -3731,7 +3793,7 @@ static bool _webui_wait(bool async) {
37313793

37323794
// Main loop
37333795
#ifdef _WIN32
3734-
if (!_webui.is_webview) {
3796+
if (!_webui.is_webview_mode) {
37353797
// Windows Web browser main loop
37363798

37373799
#ifdef WEBUI_LOG
@@ -3775,7 +3837,7 @@ static bool _webui_wait(bool async) {
37753837
}
37763838
}
37773839
#elif __linux__
3778-
if (!_webui.is_webview) {
3840+
if (!_webui.is_webview_mode) {
37793841
// Linux Web browser main loop
37803842

37813843
#ifdef WEBUI_LOG
@@ -3825,7 +3887,7 @@ static bool _webui_wait(bool async) {
38253887
}
38263888
}
38273889
#else
3828-
if (!_webui.is_webview) {
3890+
if (!_webui.is_webview_mode) {
38293891
// macOS Web browser main loop
38303892

38313893
#ifdef WEBUI_LOG
@@ -7938,7 +8000,7 @@ static bool _webui_browser_start(_webui_window_t* win, const char* address, size
79388000
static size_t _webui_get_child_process_id(_webui_window_t* win) {
79398001
if (win) {
79408002
// Get PID
7941-
if (_webui.is_webview) {
8003+
if (_webui.is_webview_mode) {
79428004
// WebView Mode
79438005
#if defined(_WIN32)
79448006
return (size_t)GetCurrentProcessId();
@@ -7957,6 +8019,29 @@ static size_t _webui_get_child_process_id(_webui_window_t* win) {
79578019
_webui_system_win32_out(cmd, &out, false);
79588020
size_t process_id = 0;
79598021
if (out) {
8022+
8023+
// Check if we get:
8024+
// "'wmic' is not recognized as an internal or external command"
8025+
// which means WMIC is not available on this system (Windows 11 22H2 and later)
8026+
if (strstr(out, "is not recognized") != NULL) {
8027+
free(out);
8028+
// WMIC is not available, let's try PowerShell as a fallback.
8029+
WEBUI_SN_PRINTF_STATIC(
8030+
cmd,
8031+
sizeof(cmd),
8032+
"cmd.exe /c powershell -NoProfile -Command \"$url='%s';$p=Get-CimInstance Win32_Process | "
8033+
"Where-Object { $_.CommandLine -and $_.CommandLine -match [regex]::Escape($url) };"
8034+
"if($p.Count -gt 0){$p[0].ProcessId}else{0}\" 2>&1",
8035+
win->url
8036+
);
8037+
_webui_system_win32_out(cmd, &out, false);
8038+
if (!out) return 0;
8039+
process_id = (size_t)atoi(out);
8040+
free(out);
8041+
return process_id;
8042+
}
8043+
8044+
// Parse the CSV output
79608045
char* line_start = out;
79618046
char* found_url_ptr = NULL;
79628047
while ((line_start = strstr(line_start, "\n")) != NULL) {
@@ -8233,6 +8318,9 @@ static bool _webui_show(_webui_window_t* win, struct mg_connection* client, cons
82338318
// Reset
82348319
win->is_showing = false;
82358320

8321+
// Bring the window to front after showing content
8322+
webui_focus(win->num);
8323+
82368324
return status;
82378325
}
82388326

@@ -8901,7 +8989,7 @@ static bool _webui_show_window(_webui_window_t* win, struct mg_connection* clien
89018989
_webui.startup_timeout : WEBUI_DEF_TIMEOUT
89028990
);
89038991

8904-
if (_webui.is_webview) {
8992+
if (_webui.is_webview_mode) {
89058993

89068994
// WebView
89078995

@@ -8912,18 +9000,18 @@ static bool _webui_show_window(_webui_window_t* win, struct mg_connection* clien
89129000
_webui_sleep(10);
89139001

89149002
// Process WebView rendering if any
8915-
if (_webui.is_webview) {
9003+
if (_webui.is_webview_mode) {
89169004
#ifdef _WIN32
89179005
// ...
89189006
#elif __linux__
8919-
if (_webui.is_webview) {
9007+
if (_webui.is_webview_mode) {
89209008
while (gtk_events_pending()) {
89219009
gtk_main_iteration_do(0);
89229010
}
89239011
}
89249012
#else
89259013
if (!_webui.is_wkwebview_main_run) {
8926-
if (_webui.is_webview) {
9014+
if (_webui.is_webview_mode) {
89279015
_webui_macos_wv_process();
89289016
}
89299017
}
@@ -10399,7 +10487,7 @@ static WEBUI_THREAD_SERVER_START {
1039910487

1040010488
// Kill Process
1040110489
#ifndef WEBUI_LOG
10402-
if (!_webui.is_webview) {
10490+
if (!_webui.is_webview_mode) {
1040310491
if (_webui.current_browser != WEBUI_NATIVE_BROWSER) {
1040410492
// Terminating the web browser window process
1040510493
_webui_kill_pid(_webui_get_child_process_id(win));
@@ -12122,7 +12210,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved) {
1212212210

1212312211
// Initializing
1212412212
// Expecting `_webui_webview_thread` to change `mutex_is_webview_update`
12125-
// to `false` when initialization is done, and `_webui.is_webview`
12213+
// to `false` when initialization is done, and `_webui.is_webview_mode`
1212612214
// to `true` if loading the WebView is succeeded.
1212712215
_webui_webview_update(win);
1212812216

@@ -12154,10 +12242,10 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved) {
1215412242
}
1215512243

1215612244
#ifdef WEBUI_LOG
12157-
_webui_log_debug("[Core]\t\t_webui_wv_show() -> Return [%d]\n", (_webui.is_webview == true));
12245+
_webui_log_debug("[Core]\t\t_webui_wv_show() -> Return [%d]\n", (_webui.is_webview_mode == true));
1215812246
#endif
1215912247

12160-
return (_webui.is_webview);
12248+
return (_webui.is_webview_mode);
1216112249
};
1216212250

1216312251
static bool _webui_wv_minimize(_webui_wv_win32_t* webView) {
@@ -12352,7 +12440,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved) {
1235212440

1235312441
// Success
1235412442
// Let `wait()` use safe main-thread WebView2 loop
12355-
_webui.is_webview = true;
12443+
_webui.is_webview_mode = true;
1235612444

1235712445
_webui_mutex_is_webview_update(win, WEBUI_MUTEX_SET_FALSE);
1235812446
MSG msg;
@@ -12679,7 +12767,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved) {
1267912767
// when the application ends.
1268012768
}
1268112769

12682-
_webui.is_webview = false;
12770+
_webui.is_webview_mode = false;
1268312771
libwebkit = NULL;
1268412772
libgtk = NULL;
1268512773
};
@@ -12813,7 +12901,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved) {
1281312901
static bool _webui_load_gtk_and_webkit() {
1281412902
if (!libgtk || !libwebkit) {
1281512903

12816-
_webui.is_webview = false;
12904+
_webui.is_webview_mode = false;
1281712905

1281812906
// GTK Dynamic Load
1281912907
const char *gtk_libs[] = GTK_RUNTIME_ARR;
@@ -13070,7 +13158,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved) {
1307013158

1307113159
// Initializing
1307213160
// Expecting `_webui_webview_thread` to change `mutex_is_webview_update`
13073-
// to `false` when initialization is done, and `_webui.is_webview`
13161+
// to `false` when initialization is done, and `_webui.is_webview_mode`
1307413162
// to `true` if loading the WebView is succeeded.
1307513163
_webui_webview_update(win);
1307613164

@@ -13093,10 +13181,10 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved) {
1309313181
}
1309413182

1309513183
#ifdef WEBUI_LOG
13096-
_webui_log_debug("[Core]\t\t_webui_wv_show() -> Return [%d]\n", (_webui.is_webview == true));
13184+
_webui_log_debug("[Core]\t\t_webui_wv_show() -> Return [%d]\n", (_webui.is_webview_mode == true));
1309713185
#endif
1309813186

13099-
return (_webui.is_webview);
13187+
return (_webui.is_webview_mode);
1310013188
};
1310113189

1310213190
static WEBUI_THREAD_WEBVIEW {
@@ -13128,7 +13216,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved) {
1312813216

1312913217
// Success
1313013218
// Let `wait()` use safe main-thread GTK WebView loop
13131-
_webui.is_webview = true;
13219+
_webui.is_webview_mode = true;
1313213220
_webui_mutex_is_webview_update(win, WEBUI_MUTEX_SET_FALSE);
1313313221

1313413222
while (true) {
@@ -13278,9 +13366,9 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved) {
1327813366

1327913367
if (!_webui.is_wkwebview_main_run) {
1328013368
if (_webui_macos_wv_new(win->num, win->frameless, win->resizable)) {
13281-
if (!_webui.is_webview) {
13369+
if (!_webui.is_webview_mode) {
1328213370
// Let `wait()` use safe main-thread WKWebView loop
13283-
_webui.is_webview = true;
13371+
_webui.is_webview_mode = true;
1328413372
// Set close callback once
1328513373
_webui_macos_wv_set_close_cb(_webui_wv_event_closed);
1328613374
}

0 commit comments

Comments
 (0)