Commit 1a9b36e8 authored by valenok's avatar valenok

win32 systray functionality

parent 2b732a80
...@@ -17,9 +17,9 @@ ...@@ -17,9 +17,9 @@
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. // THE SOFTWARE.
#if defined(_WIN32) #if defined(_WIN32)
#define _CRT_SECURE_NO_WARNINGS // Disable deprecation warning in VS2005 #define _CRT_SECURE_NO_WARNINGS // Disable deprecation warning in VS2005
#else #else
#define _XOPEN_SOURCE 600 // For PATH_MAX on linux #define _XOPEN_SOURCE 600 // For PATH_MAX on linux
#endif #endif
...@@ -42,9 +42,9 @@ ...@@ -42,9 +42,9 @@
#define PATH_MAX MAX_PATH #define PATH_MAX MAX_PATH
#define S_ISDIR(x) ((x) & _S_IFDIR) #define S_ISDIR(x) ((x) & _S_IFDIR)
#define DIRSEP '\\' #define DIRSEP '\\'
#define snprintf _snprintf #define snprintf _snprintf
#define vsnprintf _vsnprintf #define vsnprintf _vsnprintf
#define sleep(x) Sleep((x) * 1000) #define sleep(x) Sleep((x) * 1000)
#define WINCDECL __cdecl #define WINCDECL __cdecl
#else #else
#include <sys/wait.h> #include <sys/wait.h>
...@@ -58,10 +58,11 @@ ...@@ -58,10 +58,11 @@
static int exit_flag; static int exit_flag;
static char *options[MAX_OPTIONS]; static char *options[MAX_OPTIONS];
static char server_name[40]; static char server_name[40];
static char *config_file;
static struct mg_context *ctx; static struct mg_context *ctx;
#if !defined(CONFIG_FILE) #if !defined(CONFIG_FILE)
#define CONFIG_FILE "mongoose.conf" #define CONFIG_FILE "mongoose.conf"
#endif /* !CONFIG_FILE */ #endif /* !CONFIG_FILE */
static void WINCDECL signal_handler(int sig_num) { static void WINCDECL signal_handler(int sig_num) {
...@@ -98,7 +99,7 @@ static void die(const char *fmt, ...) { ...@@ -98,7 +99,7 @@ static void die(const char *fmt, ...) {
*/ */
static int mg_edit_passwords(const char *fname, const char *domain, static int mg_edit_passwords(const char *fname, const char *domain,
const char *user, const char *pass) { const char *user, const char *pass) {
struct mg_context *ctx; struct mg_context *ctx;
const char *options[] = {"authentication_domain", NULL, NULL}; const char *options[] = {"authentication_domain", NULL, NULL};
int success; int success;
...@@ -178,27 +179,26 @@ static void set_option(char **options, const char *name, const char *value) { ...@@ -178,27 +179,26 @@ static void set_option(char **options, const char *name, const char *value) {
} }
static void process_command_line_arguments(char *argv[], char **options) { static void process_command_line_arguments(char *argv[], char **options) {
const char *config_file = NULL;
char line[512], opt[512], val[512], path[PATH_MAX], *p; char line[512], opt[512], val[512], path[PATH_MAX], *p;
FILE *fp = NULL; FILE *fp = NULL;
struct stat st;
size_t i, line_no = 0; size_t i, line_no = 0;
/* Should we use a config file ? */ /* Should we use a config file ? */
if (argv[1] != NULL && argv[2] == NULL) { if (argv[1] != NULL && argv[2] == NULL) {
config_file = argv[1]; config_file = argv[1];
} else if (argv[1] == NULL && (p = strrchr(argv[0], DIRSEP)) == NULL) { } else if ((p = strrchr(argv[0], DIRSEP)) == NULL) {
// No command line flags specified. Look where binary lives // No command line flags specified. Look where binary lives
config_file = CONFIG_FILE; config_file = CONFIG_FILE;
} else if (argv[1] == NULL) { } else {
snprintf(path, sizeof(path), "%.*s%c%s", snprintf(path, sizeof(path), "%.*s%c%s",
(int) (p - argv[0]), argv[0], DIRSEP, CONFIG_FILE); (int) (p - argv[0]), argv[0], DIRSEP, CONFIG_FILE);
if (stat(path, &st) == 0) { config_file = path;
config_file = path;
}
} }
fp = fopen(config_file, "r");
/* If config file was set in command line and open failed, exit */ /* If config file was set in command line and open failed, exit */
if (config_file != NULL && (fp = fopen(config_file, "r")) == NULL) { if (argv[1] != NULL && argv[2] == NULL && fp == NULL) {
die("Cannot open config file %s: %s", config_file, strerror(errno)); die("Cannot open config file %s: %s", config_file, strerror(errno));
} }
...@@ -231,12 +231,14 @@ static void process_command_line_arguments(char *argv[], char **options) { ...@@ -231,12 +231,14 @@ static void process_command_line_arguments(char *argv[], char **options) {
} }
} }
static void init_server_name(void) {
snprintf(server_name, sizeof(server_name), "Mongoose web server v.%s",
mg_version());
}
static void start_mongoose(int argc, char *argv[]) { static void start_mongoose(int argc, char *argv[]) {
int i; int i;
snprintf(server_name, sizeof(server_name),
"Mongoose %s web server", mg_version());
/* Edit passwords file if -A option is specified */ /* Edit passwords file if -A option is specified */
if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'A') { if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'A') {
if (argc != 6) { if (argc != 6) {
...@@ -294,7 +296,6 @@ static void WINAPI ServiceMain(void) { ...@@ -294,7 +296,6 @@ static void WINAPI ServiceMain(void) {
hStatus = RegisterServiceCtrlHandler(server_name, ControlHandler); hStatus = RegisterServiceCtrlHandler(server_name, ControlHandler);
SetServiceStatus(hStatus, &ss); SetServiceStatus(hStatus, &ss);
//Sleep(3000);
while (ss.dwCurrentState == SERVICE_RUNNING) { while (ss.dwCurrentState == SERVICE_RUNNING) {
Sleep(1000); Sleep(1000);
} }
...@@ -305,43 +306,89 @@ static void WINAPI ServiceMain(void) { ...@@ -305,43 +306,89 @@ static void WINAPI ServiceMain(void) {
SetServiceStatus(hStatus, &ss); SetServiceStatus(hStatus, &ss);
} }
static void try_to_run_as_nt_service(void) { #define ID_TRAYICON 100
static SERVICE_TABLE_ENTRY service_table[] = { #define ID_QUIT 101
{server_name, (LPSERVICE_MAIN_FUNCTION) ServiceMain}, #define ID_EDIT_CONFIG 102
{NULL, NULL} #define ID_SEPARATOR 103
}; #define ID_INSTALL_SERVICE 104
#define ID_REMOVE_SERVICE 105
if (StartServiceCtrlDispatcher(service_table)) { #define ID_ICON 200
exit(EXIT_SUCCESS); static NOTIFYICONDATA TrayIcon;
static void edit_config_file(void) {
const char **names, *value;
FILE *fp;
int i;
char cmd[200];
// Create config file if it is not present yet
if ((fp = fopen(config_file, "r")) != NULL) {
fclose(fp);
} else if ((fp = fopen(config_file, "a+")) != NULL) {
fprintf(fp,
"# Mongoose web server configuration file.\n"
"# Lines starting with '#' and empty lines are ignored.\n"
"# For detailed description of every option, visit\n"
"# http://code.google.com/p/mongoose/wiki/MongooseManual\n\n");
names = mg_get_valid_option_names();
for (i = 0; names[i] != NULL; i += 3) {
value = mg_get_option(ctx, names[i]);
fprintf(fp, "# %s %s\n", names[i + 1], *value ? value : "<value>");
}
fclose(fp);
} }
}
#define ID_TRAYICON 100 snprintf(cmd, sizeof(cmd), "notepad.exe %s", config_file);
#define ID_QUIT 101 WinExec(cmd, SW_SHOW);
static NOTIFYICONDATA ni; }
static LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam, static LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam,
LPARAM lParam) { LPARAM lParam) {
POINT pt; static SERVICE_TABLE_ENTRY service_table[] = {
HMENU hMenu; {server_name, (LPSERVICE_MAIN_FUNCTION) ServiceMain},
{NULL, NULL}
};
POINT pt;
HMENU hMenu;
switch (msg) { switch (msg) {
case WM_CREATE:
// Win32 runtime must prepare __argc and __argv for us
start_mongoose(__argc, __argv);
// TODO(lsm): figure out why this executes long time
if (StartServiceCtrlDispatcher(service_table)) {
exit(EXIT_SUCCESS);
}
break;
case WM_COMMAND: case WM_COMMAND:
switch (LOWORD(wParam)) { switch (LOWORD(wParam)) {
case ID_QUIT: case ID_QUIT:
exit(EXIT_SUCCESS); mg_stop(ctx);
Shell_NotifyIcon(NIM_DELETE, &TrayIcon);
PostQuitMessage(0);
break;
case ID_EDIT_CONFIG:
edit_config_file();
break; break;
} }
break; break;
case WM_USER: case WM_USER:
switch (lParam) { switch (lParam) {
case WM_RBUTTONUP: case WM_RBUTTONUP:
case WM_LBUTTONUP: case WM_LBUTTONUP:
case WM_LBUTTONDBLCLK: case WM_LBUTTONDBLCLK:
hMenu = CreatePopupMenu(); hMenu = CreatePopupMenu();
AppendMenu(hMenu, 0, ID_QUIT, "Exit"); AppendMenu(hMenu, MF_STRING | MF_GRAYED, ID_SEPARATOR, server_name);
AppendMenu(hMenu, MF_SEPARATOR, ID_SEPARATOR, "");
#if 0
AppendMenu(hMenu, MF_STRING | MF_GRAYED, ID_SEPARATOR,
"NT service: not installed");
AppendMenu(hMenu, MF_STRING, ID_INSTALL_SERVICE, "Install");
AppendMenu(hMenu, MF_STRING, ID_REMOVE_SERVICE, "Deinstall");
AppendMenu(hMenu, MF_SEPARATOR, ID_SEPARATOR, "");
#endif
AppendMenu(hMenu, MF_STRING, ID_EDIT_CONFIG, "Edit config file");
AppendMenu(hMenu, MF_STRING, ID_QUIT, "Exit");
GetCursorPos(&pt); GetCursorPos(&pt);
TrackPopupMenu(hMenu, 0, pt.x, pt.y, 0, hWnd, NULL); TrackPopupMenu(hMenu, 0, pt.x, pt.y, 0, hWnd, NULL);
DestroyMenu(hMenu); DestroyMenu(hMenu);
...@@ -358,12 +405,9 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR cmdline, int show) { ...@@ -358,12 +405,9 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR cmdline, int show) {
HWND hWnd; HWND hWnd;
MSG msg; MSG msg;
// Win32 runtime must prepare __argc and __argv for us init_server_name();
start_mongoose(__argc, __argv);
try_to_run_as_nt_service();
memset(&cls, 0, sizeof(cls)); memset(&cls, 0, sizeof(cls));
cls.lpfnWndProc = (WNDPROC) WindowProc; cls.lpfnWndProc = (WNDPROC) WindowProc;
cls.hIcon = LoadIcon(NULL, IDI_APPLICATION); cls.hIcon = LoadIcon(NULL, IDI_APPLICATION);
cls.lpszClassName = server_name; cls.lpszClassName = server_name;
...@@ -372,23 +416,24 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR cmdline, int show) { ...@@ -372,23 +416,24 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR cmdline, int show) {
0, 0, 0, 0, NULL, NULL, NULL, NULL); 0, 0, 0, 0, NULL, NULL, NULL, NULL);
ShowWindow(hWnd, SW_HIDE); ShowWindow(hWnd, SW_HIDE);
ni.cbSize = sizeof(ni); TrayIcon.cbSize = sizeof(TrayIcon);
ni.uID = ID_TRAYICON; TrayIcon.uID = ID_TRAYICON;
ni.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP; TrayIcon.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
ni.hIcon = LoadIcon(NULL, IDI_APPLICATION); TrayIcon.hIcon = LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(ID_ICON),
ni.hWnd = hWnd; IMAGE_ICON, 16, 16, 0);
snprintf(ni.szTip, sizeof(ni.szTip), "%s", server_name); TrayIcon.hWnd = hWnd;
ni.uCallbackMessage = WM_USER; snprintf(TrayIcon.szTip, sizeof(TrayIcon.szTip), "%s", server_name);
Shell_NotifyIcon(NIM_ADD, &ni); TrayIcon.uCallbackMessage = WM_USER;
Shell_NotifyIcon(NIM_ADD, &TrayIcon);
while (GetMessage(&msg, hWnd, 0, 0)) {
TranslateMessage(&msg); while (GetMessage(&msg, hWnd, 0, 0)) {
DispatchMessage(&msg); TranslateMessage(&msg);
DispatchMessage(&msg);
} }
} }
#endif /* _WIN32 */ #else
int main(int argc, char *argv[]) {
int WINCDECL main(int argc, char *argv[]) { init_server_name();
start_mongoose(argc, argv); start_mongoose(argc, argv);
printf("%s started on port(s) %s with web root [%s]\n", printf("%s started on port(s) %s with web root [%s]\n",
server_name, mg_get_option(ctx, "listening_ports"), server_name, mg_get_option(ctx, "listening_ports"),
...@@ -404,3 +449,4 @@ int WINCDECL main(int argc, char *argv[]) { ...@@ -404,3 +449,4 @@ int WINCDECL main(int argc, char *argv[]) {
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
#endif /* _WIN32 */
200 ICON DISCARDABLE "systray.ico"
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment