mirror of
https://github.com/cesanta/mongoose.git
synced 2024-11-27 20:59:00 +08:00
UI for Win32
This commit is contained in:
parent
facb2846fd
commit
83c106a857
@ -2,8 +2,8 @@ PROG ?= example
|
||||
ROOT ?= $(realpath $(CURDIR)/../..)
|
||||
DEFS ?= -DMG_ENABLE_LINES=1 -DMG_ENABLE_DIRECTORY_LISTING=1 -DMG_ENABLE_SSI=1
|
||||
CFLAGS ?= -I../.. -W -Wall -DMG_ENABLE_IPV6=1 $(DEFS) $(EXTRA)
|
||||
VCFLAGS = /nologo /W3 /O2 /I../.. $(DEFS) $(EXTRA)
|
||||
VC98 = docker run --rm -e WINEDEBUG=-all -v $(ROOT):$(ROOT) -w $(CURDIR) docker.io/mdashnet/vc98
|
||||
VCFLAGS = /nologo /W3 /O2 /I../.. $(DEFS) $(EXTRA) /link /incremental:no /machine:IX86
|
||||
VC98 = docker run --rm -e Tmp=. -v $(ROOT):$(ROOT) -w $(CURDIR) docker.io/mdashnet/vc98
|
||||
GCC = docker run --rm -v $(ROOT):$(ROOT) -w $(CURDIR) mdashnet/cc2
|
||||
|
||||
all: $(PROG)
|
||||
@ -16,10 +16,11 @@ mongoose_mac: $(PROG)
|
||||
cp $(PROG) $@
|
||||
|
||||
mongoose_linux: main.c
|
||||
$(GCC) $(CC) ../../mongoose.c main.c $(CFLAGS) -o $@
|
||||
$(GCC) $(CC) ../../mongoose.c main.c $(CFLAGS) -s -static -o $@
|
||||
|
||||
mongoose.exe: main.c
|
||||
$(VC98) wine cl ../../mongoose.c main.c $(VCFLAGS) ws2_32.lib /Fe$@
|
||||
$(VC98) wine rc /fomongoose.res win32/res.rc
|
||||
$(VC98) wine cl ../../mongoose.c main.c $(VCFLAGS) mongoose.res shell32.lib ws2_32.lib user32.lib /out:$@
|
||||
|
||||
zip: mongoose.exe mongoose_linux mongoose_mac
|
||||
rm -rf mongoose; mkdir mongoose
|
||||
|
@ -9,6 +9,9 @@ static const char *s_listening_address = "http://localhost:8000";
|
||||
static const char *s_enable_hexdump = "no";
|
||||
static const char *s_ssi_pattern = "#.shtml";
|
||||
|
||||
static struct mg_mgr s_mgr;
|
||||
static struct mg_timer s_timer;
|
||||
|
||||
static void cb(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||
if (ev == MG_EV_HTTP_MSG) {
|
||||
struct mg_http_serve_opts opts = {s_root_dir, s_ssi_pattern};
|
||||
@ -50,17 +53,21 @@ static void cfg(const char *progname, const char *optname, const char *value) {
|
||||
LOG(LL_INFO, ("Setting option [%s] to [%s]", optname, value));
|
||||
}
|
||||
|
||||
static void parse_config_file(const char *exe) {
|
||||
static FILE *opencfg(const char *exe, const char *mode) {
|
||||
char path[1024];
|
||||
const char *p = strrchr(exe, MG_DIRSEP);
|
||||
FILE *fp;
|
||||
if (p == NULL) p = strrchr(exe, '/');
|
||||
snprintf(path, sizeof(path), "%.*s%c%s", p == NULL ? 1 : (int) (p - exe),
|
||||
p == NULL ? "." : exe, MG_DIRSEP, "mongoose.conf");
|
||||
if ((fp = fopen(path, "rb")) != NULL) {
|
||||
return fopen(path, mode);
|
||||
}
|
||||
|
||||
static void parse_config_file(const char *exe) {
|
||||
FILE *fp = opencfg(exe, "rb");
|
||||
if (fp != NULL) {
|
||||
char line[8192], *name;
|
||||
int i, line_no = 0;
|
||||
LOG(LL_INFO, ("Processing config file %s", path));
|
||||
LOG(LL_INFO, ("Processing config file..."));
|
||||
while (fgets(line, sizeof(line), fp) != NULL) {
|
||||
line_no++;
|
||||
// Trim whitespaces at the end
|
||||
@ -71,20 +78,41 @@ static void parse_config_file(const char *exe) {
|
||||
name = &line[i];
|
||||
while (line[i] != '\0' && !isspace(line[i])) i++;
|
||||
if (line[i] != ' ') {
|
||||
LOG(LL_ERROR,
|
||||
("%s: ignoring invalid line %d: %s", path, line_no, line));
|
||||
LOG(LL_ERROR, ("Ignoring invalid line %d: %s", line_no, line));
|
||||
} else {
|
||||
line[i++] = '\0'; // nul-terminate name
|
||||
while (isspace(line[i])) i++;
|
||||
cfg(exe, name, &line[i]);
|
||||
cfg(exe, name, strdup(&line[i]));
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
struct mg_mgr mgr;
|
||||
static void ccb(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||
if (ev == MG_EV_HTTP_MSG) {
|
||||
struct mg_http_message *hm = ev_data;
|
||||
LOG(LL_DEBUG, ("New version: %.*s", (int) hm->body.len, hm->body.ptr));
|
||||
c->is_closing = 1;
|
||||
}
|
||||
(void) fn_data;
|
||||
}
|
||||
|
||||
// Check latest version, alert user if upgrade is available
|
||||
static void timer_fn(void *arg) {
|
||||
struct mg_connection *c =
|
||||
mg_http_connect(&s_mgr, "http://cesanta.com", ccb, NULL);
|
||||
if (c) {
|
||||
c->is_hexdumping = 1;
|
||||
mg_printf(c, "%s",
|
||||
"GET /downloads/mws/version.json HTTP/1.0\r\n"
|
||||
"Host: cesanta.com\r\n"
|
||||
"\r\n");
|
||||
}
|
||||
(void) arg;
|
||||
}
|
||||
|
||||
static void init_mongoose(int argc, char *argv[]) {
|
||||
struct mg_connection *c;
|
||||
int i;
|
||||
|
||||
@ -94,18 +122,28 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
// Initialise stuff
|
||||
mg_log_set(s_debug_level);
|
||||
mg_mgr_init(&mgr);
|
||||
if ((c = mg_http_listen(&mgr, s_listening_address, cb, &mgr)) == NULL) {
|
||||
mg_mgr_init(&s_mgr);
|
||||
if ((c = mg_http_listen(&s_mgr, s_listening_address, cb, &s_mgr)) == NULL) {
|
||||
LOG(LL_ERROR, ("Cannot listen on %s. Use http://ADDR:PORT or :PORT",
|
||||
s_listening_address));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
mg_timer_init(&s_timer, 3600000, MG_TIMER_REPEAT | MG_TIMER_RUN_NOW, timer_fn,
|
||||
&s_mgr);
|
||||
if (mg_casecmp(s_enable_hexdump, "yes") == 0) c->is_hexdumping = 1;
|
||||
s_root_dir = realpath(s_root_dir, NULL);
|
||||
if (s_root_dir == NULL) s_root_dir = ".";
|
||||
LOG(LL_INFO, ("Starting Mongoose v%s, serving %s", MG_VERSION, s_root_dir));
|
||||
}
|
||||
|
||||
// Start infinite event loop
|
||||
LOG(LL_INFO, ("Starting Mongoose v%s, serving %s", MG_VERSION,
|
||||
realpath(s_root_dir, NULL)));
|
||||
for (;;) mg_mgr_poll(&mgr, 1000);
|
||||
mg_mgr_free(&mgr);
|
||||
#ifdef _WIN32
|
||||
#include "win32/winmain.c"
|
||||
#else
|
||||
int main(int argc, char *argv[]) {
|
||||
init_mongoose(argc, argv);
|
||||
for (;;) mg_mgr_poll(&s_mgr, 1000);
|
||||
mg_timer_free(&s_timer);
|
||||
mg_mgr_free(&s_mgr);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
1
examples/desktop-server/win32/res.rc
Normal file
1
examples/desktop-server/win32/res.rc
Normal file
@ -0,0 +1 @@
|
||||
150 ICON DISCARDABLE "systray.ico"
|
BIN
examples/desktop-server/win32/systray.ico
Normal file
BIN
examples/desktop-server/win32/systray.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
131
examples/desktop-server/win32/winmain.c
Normal file
131
examples/desktop-server/win32/winmain.c
Normal file
@ -0,0 +1,131 @@
|
||||
#include <shellapi.h>
|
||||
#include <shlobj.h>
|
||||
|
||||
static const char *s_server_name = "Mongoose v" MG_VERSION;
|
||||
static HANDLE hThread; // Serving thread
|
||||
static NOTIFYICONDATA TrayIcon;
|
||||
|
||||
enum {
|
||||
ID_QUIT = 100, // Menu item IDs
|
||||
ID_SEPARATOR,
|
||||
ID_SET_DIR,
|
||||
ID_ICON_MONGOOSE = 150, // Icons for mongoose menu
|
||||
};
|
||||
|
||||
static const char *get_my_url(void) {
|
||||
static char buf[100];
|
||||
char local_ip[50] = "", hostname[200];
|
||||
struct hostent *he;
|
||||
if (gethostname(hostname, sizeof(hostname)) == 0 &&
|
||||
(he = gethostbyname(hostname)) != NULL) {
|
||||
snprintf(local_ip, sizeof(local_ip), "%s",
|
||||
inet_ntoa(*(struct in_addr *) he->h_addr_list[0]));
|
||||
}
|
||||
if (local_ip[0] == '\0') snprintf(local_ip, sizeof(local_ip), "127.0.0.1");
|
||||
snprintf(buf, sizeof(buf), "http://%s:%d", local_ip,
|
||||
mg_url_port(s_listening_address));
|
||||
return buf;
|
||||
}
|
||||
|
||||
static LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam,
|
||||
LPARAM lParam) {
|
||||
POINT pt;
|
||||
HMENU hMenu;
|
||||
switch (msg) {
|
||||
case WM_COMMAND:
|
||||
switch (LOWORD(wParam)) {
|
||||
case ID_QUIT:
|
||||
Shell_NotifyIcon(NIM_DELETE, &TrayIcon);
|
||||
PostQuitMessage(0);
|
||||
return 0;
|
||||
case ID_SET_DIR: {
|
||||
char path[PATH_MAX] = "";
|
||||
BROWSEINFO bi;
|
||||
memset(&bi, 0, sizeof(bi));
|
||||
bi.hwndOwner = hWnd;
|
||||
bi.lpszTitle = "Choose root directory:";
|
||||
bi.ulFlags = BIF_RETURNONLYFSDIRS;
|
||||
SHGetPathFromIDList(SHBrowseForFolder(&bi), path);
|
||||
if (path[0] != '\0') {
|
||||
FILE *fp = opencfg(__argv[0], "w");
|
||||
s_root_dir = strdup(path);
|
||||
if (fp != NULL) {
|
||||
fprintf(fp, "-d %s\n", path);
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case WM_USER:
|
||||
switch (lParam) {
|
||||
case WM_RBUTTONUP:
|
||||
case WM_LBUTTONUP:
|
||||
case WM_LBUTTONDBLCLK: {
|
||||
char buf[1024];
|
||||
hMenu = CreatePopupMenu();
|
||||
AppendMenu(hMenu, MF_STRING | MF_GRAYED, ID_SEPARATOR, s_server_name);
|
||||
AppendMenu(hMenu, MF_SEPARATOR, ID_SEPARATOR, "");
|
||||
snprintf(buf, sizeof(buf), "Shared directory: %s", s_root_dir);
|
||||
AppendMenu(hMenu, MF_STRING | MF_GRAYED, ID_SEPARATOR, buf);
|
||||
snprintf(buf, sizeof(buf), "URL: %s", get_my_url());
|
||||
AppendMenu(hMenu, MF_STRING | MF_GRAYED, ID_SEPARATOR, buf);
|
||||
AppendMenu(hMenu, MF_SEPARATOR, ID_SEPARATOR, "");
|
||||
AppendMenu(hMenu, MF_STRING, ID_SET_DIR,
|
||||
"Change shared directory ...");
|
||||
AppendMenu(hMenu, MF_STRING, ID_QUIT, "Exit");
|
||||
GetCursorPos(&pt);
|
||||
SetForegroundWindow(hWnd);
|
||||
TrackPopupMenu(hMenu, 0, pt.x, pt.y, 0, hWnd, NULL);
|
||||
PostMessage(hWnd, WM_NULL, 0, 0);
|
||||
DestroyMenu(hMenu);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case WM_CLOSE:
|
||||
Shell_NotifyIcon(NIM_DELETE, &TrayIcon);
|
||||
PostQuitMessage(0);
|
||||
return 0; // We've just sent our own quit message, with proper hwnd.
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return DefWindowProc(hWnd, msg, wParam, lParam);
|
||||
}
|
||||
|
||||
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR cmdline, int show) {
|
||||
WNDCLASS cls;
|
||||
HWND hWnd;
|
||||
MSG msg = {0};
|
||||
|
||||
init_mongoose(__argc, __argv);
|
||||
memset(&cls, 0, sizeof(cls));
|
||||
cls.lpfnWndProc = (WNDPROC) WindowProc;
|
||||
cls.hIcon = LoadIcon(NULL, IDI_APPLICATION);
|
||||
cls.lpszClassName = s_server_name;
|
||||
RegisterClass(&cls);
|
||||
hWnd = CreateWindow(cls.lpszClassName, s_server_name, WS_OVERLAPPEDWINDOW, 0,
|
||||
0, 0, 0, NULL, NULL, NULL, NULL);
|
||||
ShowWindow(hWnd, SW_HIDE);
|
||||
|
||||
TrayIcon.cbSize = sizeof(TrayIcon);
|
||||
TrayIcon.uID = ID_ICON_MONGOOSE;
|
||||
TrayIcon.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
|
||||
TrayIcon.hIcon =
|
||||
LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(ID_ICON_MONGOOSE));
|
||||
TrayIcon.hWnd = hWnd;
|
||||
snprintf(TrayIcon.szTip, sizeof(TrayIcon.szTip), "%s", s_server_name);
|
||||
TrayIcon.uCallbackMessage = WM_USER;
|
||||
Shell_NotifyIcon(NIM_ADD, &TrayIcon);
|
||||
|
||||
while (msg.message != WM_QUIT) {
|
||||
mg_mgr_poll(&s_mgr, 1);
|
||||
if (PeekMessage(&msg, hWnd, 0, 0, PM_REMOVE) > 0) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
}
|
||||
mg_mgr_free(&s_mgr);
|
||||
return msg.wParam;
|
||||
}
|
Loading…
Reference in New Issue
Block a user