Fix bug #9955 with mouse-highlight that starts at beginning of window.
[bpt/emacs.git] / nt / runemacs.c
CommitLineData
95df8112
GM
1/* runemacs --- Simple program to start Emacs with its console window hidden.
2
3Copyright (C) 2001-2011 Free Software Foundation, Inc.
b65d8176
TTN
4
5This file is part of GNU Emacs.
6
eef0be9e 7GNU Emacs is free software: you can redistribute it and/or modify
b65d8176 8it under the terms of the GNU General Public License as published by
eef0be9e
GM
9the Free Software Foundation, either version 3 of the License, or
10(at your option) any later version.
b65d8176
TTN
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
eef0be9e 18along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
b65d8176
TTN
19
20
c911543b
GV
21/*
22 Simple program to start Emacs with its console window hidden.
23
24 This program is provided purely for convenience, since most users will
25 use Emacs in windowing (GUI) mode, and will not want to have an extra
26 console window lying around. */
27
662463d9
RS
28/*
29 You may want to define this if you want to be able to install updated
30 emacs binaries even when other users are using the current version.
31 The problem with some file servers (notably Novell) is that an open
32 file cannot be overwritten, deleted, or even renamed. So if someone
33 is running emacs.exe already, you cannot install a newer version.
34 By defining CHOOSE_NEWEST_EXE, you can name your new emacs.exe
35 something else which matches "emacs*.exe", and runemacs will
4da0d3f7 36 automatically select the newest emacs executable in the bin directory.
662463d9
RS
37 (So you'll probably be able to delete the old version some hours/days
38 later).
39*/
40
41/* #define CHOOSE_NEWEST_EXE */
42
c911543b
GV
43#include <windows.h>
44#include <string.h>
45#include <malloc.h>
46
361358ea 47static void set_user_model_id (void);
ff90fbde 48
c911543b
GV
49int WINAPI
50WinMain (HINSTANCE hSelf, HINSTANCE hPrev, LPSTR cmdline, int nShow)
51{
52 STARTUPINFO start;
53 SECURITY_ATTRIBUTES sec_attrs;
c911543b
GV
54 PROCESS_INFORMATION child;
55 int wait_for_child = FALSE;
05c4be3c 56 DWORD priority_class = NORMAL_PRIORITY_CLASS;
c911543b 57 DWORD ret_code = 0;
662463d9
RS
58 char *new_cmdline;
59 char *p;
c911543b
GV
60 char modname[MAX_PATH];
61
ff90fbde
JR
62 set_user_model_id ();
63
c911543b
GV
64 if (!GetModuleFileName (NULL, modname, MAX_PATH))
65 goto error;
66 if ((p = strrchr (modname, '\\')) == NULL)
67 goto error;
68 *p = 0;
69
0ac7bf6c
JR
70 new_cmdline = alloca (MAX_PATH + strlen (cmdline) + 3);
71 /* Quote executable name in case of spaces in the path. */
72 *new_cmdline = '"';
73 strcpy (new_cmdline + 1, modname);
c911543b 74
662463d9 75#ifdef CHOOSE_NEWEST_EXE
c911543b 76 {
662463d9
RS
77 /* Silly hack to allow new versions to be installed on
78 server even when current version is in use. */
79
80 char * best_name = alloca (MAX_PATH + 1);
81 FILETIME best_time = {0,0};
82 WIN32_FIND_DATA wfd;
83 HANDLE fh;
84 p = new_cmdline + strlen (new_cmdline);
0ac7bf6c 85 strcpy (p, "\\emacs*.exe\" ");
662463d9
RS
86 fh = FindFirstFile (new_cmdline, &wfd);
87 if (fh == INVALID_HANDLE_VALUE)
88 goto error;
89 do
90 {
4da0d3f7
JB
91 if (wfd.ftLastWriteTime.dwHighDateTime > best_time.dwHighDateTime
92 || (wfd.ftLastWriteTime.dwHighDateTime == best_time.dwHighDateTime
93 && wfd.ftLastWriteTime.dwLowDateTime > best_time.dwLowDateTime))
94 {
95 best_time = wfd.ftLastWriteTime;
96 strcpy (best_name, wfd.cFileName);
97 }
662463d9
RS
98 }
99 while (FindNextFile (fh, &wfd));
100 FindClose (fh);
101 *p++ = '\\';
102 strcpy (p, best_name);
103 strcat (p, " ");
c911543b 104 }
662463d9 105#else
0ac7bf6c 106 strcat (new_cmdline, "\\emacs.exe\" ");
662463d9
RS
107#endif
108
05c4be3c
GV
109 /* Append original arguments if any; first look for arguments we
110 recognise (-wait, -high, and -low), and apply them ourselves. */
111 while (cmdline[0] == '-' || cmdline[0] == '/')
662463d9 112 {
05c4be3c
GV
113 if (strncmp (cmdline+1, "wait", 4) == 0)
114 {
4da0d3f7
JB
115 wait_for_child = TRUE;
116 cmdline += 5;
117 }
05c4be3c
GV
118 else if (strncmp (cmdline+1, "high", 4) == 0)
119 {
120 priority_class = HIGH_PRIORITY_CLASS;
121 cmdline += 5;
122 }
123 else if (strncmp (cmdline+1, "low", 3) == 0)
124 {
125 priority_class = IDLE_PRIORITY_CLASS;
126 cmdline += 4;
127 }
128 else
129 break;
4da0d3f7
JB
130 /* Look for next argument. */
131 while (*++cmdline == ' ');
05c4be3c 132 }
4da0d3f7 133
c911543b
GV
134 strcat (new_cmdline, cmdline);
135
662463d9 136 /* Set emacs_dir variable if runemacs was in "%emacs_dir%\bin". */
c911543b 137 if ((p = strrchr (modname, '\\')) && stricmp (p, "\\bin") == 0)
662463d9
RS
138 {
139 *p = 0;
140 for (p = modname; *p; p++)
141 if (*p == '\\') *p = '/';
142 SetEnvironmentVariable ("emacs_dir", modname);
143 }
c911543b
GV
144
145 memset (&start, 0, sizeof (start));
146 start.cb = sizeof (start);
3bb69bbd 147 start.dwFlags = STARTF_USESHOWWINDOW | STARTF_USECOUNTCHARS;
c911543b 148 start.wShowWindow = SW_HIDE;
3bb69bbd
JR
149 /* Ensure that we don't waste memory if the user has specified a huge
150 default screen buffer for command windows. */
151 start.dwXCountChars = 80;
152 start.dwYCountChars = 25;
c911543b
GV
153
154 sec_attrs.nLength = sizeof (sec_attrs);
155 sec_attrs.lpSecurityDescriptor = NULL;
156 sec_attrs.bInheritHandle = FALSE;
157
05c4be3c 158 if (CreateProcess (NULL, new_cmdline, &sec_attrs, NULL, TRUE, priority_class,
1e3c9713 159 NULL, NULL, &start, &child))
c911543b
GV
160 {
161 if (wait_for_child)
162 {
163 WaitForSingleObject (child.hProcess, INFINITE);
164 GetExitCodeProcess (child.hProcess, &ret_code);
165 }
166 CloseHandle (child.hThread);
167 CloseHandle (child.hProcess);
168 }
169 else
170 goto error;
171 return (int) ret_code;
172
173error:
174 MessageBox (NULL, "Could not start Emacs.", "Error", MB_ICONSTOP);
175 return 1;
176}
ab5796a9 177
7c3320d8
JB
178void
179set_user_model_id (void)
ff90fbde
JR
180{
181 HMODULE shell;
0a3472c7 182 HRESULT (WINAPI * set_user_model) (wchar_t * id);
ff90fbde
JR
183
184 /* On Windows 7 and later, we need to set the user model ID
185 to associate emacsclient launched files with Emacs frames
186 in the UI. */
187 shell = LoadLibrary ("shell32.dll");
188 if (shell)
189 {
190 set_user_model
191 = (void *) GetProcAddress (shell,
192 "SetCurrentProcessExplicitAppUserModelID");
193
194 /* If the function is defined, then we are running on Windows 7
195 or newer, and the UI uses this to group related windows
196 together. Since emacs, runemacs, emacsclient are related, we
197 want them grouped even though the executables are different,
198 so we need to set a consistent ID between them. */
199 if (set_user_model)
200 set_user_model (L"GNU.Emacs");
201
202 FreeLibrary (shell);
203 }
204}
205