Commit | Line | Data |
---|---|---|
a09e091a JB |
1 | |
2 | /* | |
3 | ||
4 | Copyright 1993, 1998 The Open Group | |
5 | Copyright (C) Colin Harrison 2005-2008 | |
6 | ||
7 | Permission to use, copy, modify, distribute, and sell this software and its | |
8 | documentation for any purpose is hereby granted without fee, provided that | |
9 | the above copyright notice appear in all copies and that both that | |
10 | copyright notice and this permission notice appear in supporting | |
11 | documentation. | |
12 | ||
13 | The above copyright notice and this permission notice shall be included | |
14 | in all copies or substantial portions of the Software. | |
15 | ||
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | |
17 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | |
19 | IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR | |
20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | |
21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | |
22 | OTHER DEALINGS IN THE SOFTWARE. | |
23 | ||
24 | Except as contained in this notice, the name of The Open Group shall | |
25 | not be used in advertising or otherwise to promote the sale, use or | |
26 | other dealings in this Software without prior written authorization | |
27 | from The Open Group. | |
28 | ||
29 | */ | |
30 | ||
31 | #ifdef HAVE_XWIN_CONFIG_H | |
32 | #include <xwin-config.h> | |
33 | #endif | |
34 | #include "win.h" | |
35 | #include "winmsg.h" | |
36 | #include "winconfig.h" | |
37 | #include "winprefs.h" | |
38 | #ifdef XWIN_CLIPBOARD | |
39 | #include "X11/Xlocale.h" | |
40 | #endif | |
41 | #ifdef DPMSExtension | |
42 | #include "dpmsproc.h" | |
43 | #endif | |
44 | #ifdef __CYGWIN__ | |
45 | #include <mntent.h> | |
46 | #endif | |
47 | #if defined(WIN32) | |
48 | #include "xkbsrv.h" | |
49 | #endif | |
50 | #ifdef RELOCATE_PROJECTROOT | |
51 | #pragma push_macro("Status") | |
52 | #undef Status | |
53 | #define Status wStatus | |
54 | #include <shlobj.h> | |
55 | #pragma pop_macro("Status") | |
56 | typedef WINAPI HRESULT(*SHGETFOLDERPATHPROC) (HWND hwndOwner, | |
57 | int nFolder, | |
58 | HANDLE hToken, | |
59 | DWORD dwFlags, LPTSTR pszPath); | |
60 | #endif | |
61 | ||
62 | #include "glx_extinit.h" | |
63 | /* | |
64 | * References to external symbols | |
65 | */ | |
66 | #ifdef XWIN_CLIPBOARD | |
67 | extern Bool g_fUnicodeClipboard; | |
68 | extern Bool g_fClipboardLaunched; | |
69 | extern Bool g_fClipboardStarted; | |
70 | extern pthread_t g_ptClipboardProc; | |
71 | extern HWND g_hwndClipboard; | |
72 | extern Bool g_fClipboard; | |
73 | #endif | |
74 | ||
75 | /* | |
76 | * Function prototypes | |
77 | */ | |
78 | ||
79 | #ifdef XWIN_CLIPBOARD | |
80 | static void | |
81 | winClipboardShutdown(void); | |
82 | #endif | |
83 | ||
84 | static Bool | |
85 | winCheckDisplayNumber(void); | |
86 | ||
87 | void | |
88 | winLogCommandLine(int argc, char *argv[]); | |
89 | ||
90 | void | |
91 | winLogVersionInfo(void); | |
92 | ||
93 | Bool | |
94 | winValidateArgs(void); | |
95 | ||
96 | #ifdef RELOCATE_PROJECTROOT | |
97 | const char *winGetBaseDir(void); | |
98 | #endif | |
99 | ||
100 | /* | |
101 | * For the depth 24 pixmap we default to 32 bits per pixel, but | |
102 | * we change this pixmap format later if we detect that the display | |
103 | * is going to be running at 24 bits per pixel. | |
104 | * | |
105 | * FIXME: On second thought, don't DIBs only support 32 bits per pixel? | |
106 | * DIBs are the underlying bitmap used for DirectDraw surfaces, so it | |
107 | * seems that all pixmap formats with depth 24 would be 32 bits per pixel. | |
108 | * Confirm whether depth 24 DIBs can have 24 bits per pixel, then remove/keep | |
109 | * the bits per pixel adjustment and update this comment to reflect the | |
110 | * situation. Harold Hunt - 2002/07/02 | |
111 | */ | |
112 | ||
113 | static PixmapFormatRec g_PixmapFormats[] = { | |
114 | {1, 1, BITMAP_SCANLINE_PAD}, | |
115 | {4, 8, BITMAP_SCANLINE_PAD}, | |
116 | {8, 8, BITMAP_SCANLINE_PAD}, | |
117 | {15, 16, BITMAP_SCANLINE_PAD}, | |
118 | {16, 16, BITMAP_SCANLINE_PAD}, | |
119 | {24, 32, BITMAP_SCANLINE_PAD}, | |
120 | {32, 32, BITMAP_SCANLINE_PAD} | |
121 | }; | |
122 | ||
123 | const int NUMFORMATS = sizeof(g_PixmapFormats) / sizeof(g_PixmapFormats[0]); | |
124 | ||
125 | #ifdef XWIN_CLIPBOARD | |
126 | static void | |
127 | winClipboardShutdown(void) | |
128 | { | |
129 | /* Close down clipboard resources */ | |
130 | if (g_fClipboard && g_fClipboardLaunched && g_fClipboardStarted) { | |
131 | /* Synchronously destroy the clipboard window */ | |
132 | if (g_hwndClipboard != NULL) { | |
133 | SendMessage(g_hwndClipboard, WM_DESTROY, 0, 0); | |
134 | /* NOTE: g_hwndClipboard is set to NULL in winclipboardthread.c */ | |
135 | } | |
136 | else | |
137 | return; | |
138 | ||
139 | /* Wait for the clipboard thread to exit */ | |
140 | pthread_join(g_ptClipboardProc, NULL); | |
141 | ||
142 | g_fClipboardLaunched = FALSE; | |
143 | g_fClipboardStarted = FALSE; | |
144 | ||
145 | winDebug("winClipboardShutdown - Clipboard thread has exited.\n"); | |
146 | } | |
147 | } | |
148 | #endif | |
149 | ||
150 | static const ExtensionModule xwinExtensions[] = { | |
151 | #ifdef GLXEXT | |
152 | { GlxExtensionInit, "GLX", &noGlxExtension }, | |
153 | #endif | |
154 | }; | |
155 | ||
156 | /* | |
157 | * XwinExtensionInit | |
158 | * Initialises Xwin-specific extensions. | |
159 | */ | |
160 | static | |
161 | void XwinExtensionInit(void) | |
162 | { | |
163 | int i; | |
164 | ||
165 | #ifdef XWIN_GLX_WINDOWS | |
166 | if (g_fNativeGl) { | |
167 | /* install the native GL provider */ | |
168 | glxWinPushNativeProvider(); | |
169 | } | |
170 | #endif | |
171 | ||
172 | for (i = 0; i < ARRAY_SIZE(xwinExtensions); i++) | |
173 | LoadExtension(&xwinExtensions[i], TRUE); | |
174 | } | |
175 | ||
176 | #if defined(DDXBEFORERESET) | |
177 | /* | |
178 | * Called right before KillAllClients when the server is going to reset, | |
179 | * allows us to shutdown our seperate threads cleanly. | |
180 | */ | |
181 | ||
182 | void | |
183 | ddxBeforeReset(void) | |
184 | { | |
185 | winDebug("ddxBeforeReset - Hello\n"); | |
186 | ||
187 | #ifdef XWIN_CLIPBOARD | |
188 | winClipboardShutdown(); | |
189 | #endif | |
190 | } | |
191 | #endif | |
192 | ||
193 | int | |
194 | main(int argc, char *argv[], char *envp[]) | |
195 | { | |
196 | int iReturn; | |
197 | ||
198 | /* Create & acquire the termination mutex */ | |
199 | iReturn = pthread_mutex_init(&g_pmTerminating, NULL); | |
200 | if (iReturn != 0) { | |
201 | ErrorF("ddxMain - pthread_mutex_init () failed: %d\n", iReturn); | |
202 | } | |
203 | ||
204 | iReturn = pthread_mutex_lock(&g_pmTerminating); | |
205 | if (iReturn != 0) { | |
206 | ErrorF("ddxMain - pthread_mutex_lock () failed: %d\n", iReturn); | |
207 | } | |
208 | ||
209 | return dix_main(argc, argv, envp); | |
210 | } | |
211 | ||
212 | /* See Porting Layer Definition - p. 57 */ | |
213 | void | |
214 | ddxGiveUp(enum ExitCode error) | |
215 | { | |
216 | int i; | |
217 | ||
218 | #if CYGDEBUG | |
219 | winDebug("ddxGiveUp\n"); | |
220 | #endif | |
221 | ||
222 | /* Perform per-screen deinitialization */ | |
223 | for (i = 0; i < g_iNumScreens; ++i) { | |
224 | /* Delete the tray icon */ | |
225 | if (!g_ScreenInfo[i].fNoTrayIcon && g_ScreenInfo[i].pScreen) | |
226 | winDeleteNotifyIcon(winGetScreenPriv(g_ScreenInfo[i].pScreen)); | |
227 | } | |
228 | ||
229 | #ifdef XWIN_MULTIWINDOW | |
230 | /* Unload libraries for taskbar grouping */ | |
231 | winPropertyStoreDestroy(); | |
232 | ||
233 | /* Notify the worker threads we're exiting */ | |
234 | winDeinitMultiWindowWM(); | |
235 | #endif | |
236 | ||
237 | #ifdef HAS_DEVWINDOWS | |
238 | /* Close our handle to our message queue */ | |
239 | if (g_fdMessageQueue != WIN_FD_INVALID) { | |
240 | /* Close /dev/windows */ | |
241 | close(g_fdMessageQueue); | |
242 | ||
243 | /* Set the file handle to invalid */ | |
244 | g_fdMessageQueue = WIN_FD_INVALID; | |
245 | } | |
246 | #endif | |
247 | ||
248 | if (!g_fLogInited) { | |
249 | g_pszLogFile = LogInit(g_pszLogFile, NULL); | |
250 | g_fLogInited = TRUE; | |
251 | } | |
252 | LogClose(error); | |
253 | ||
254 | /* | |
255 | * At this point we aren't creating any new screens, so | |
256 | * we are guaranteed to not need the DirectDraw functions. | |
257 | */ | |
258 | winReleaseDDProcAddresses(); | |
259 | ||
260 | /* Free concatenated command line */ | |
261 | free(g_pszCommandLine); | |
262 | g_pszCommandLine = NULL; | |
263 | ||
264 | /* Remove our keyboard hook if it is installed */ | |
265 | winRemoveKeyboardHookLL(); | |
266 | ||
267 | /* Tell Windows that we want to end the app */ | |
268 | PostQuitMessage(0); | |
269 | ||
270 | { | |
271 | winDebug("ddxGiveUp - Releasing termination mutex\n"); | |
272 | ||
273 | int iReturn = pthread_mutex_unlock(&g_pmTerminating); | |
274 | ||
275 | if (iReturn != 0) { | |
276 | ErrorF("winMsgWindowProc - pthread_mutex_unlock () failed: %d\n", | |
277 | iReturn); | |
278 | } | |
279 | } | |
280 | ||
281 | winDebug("ddxGiveUp - End\n"); | |
282 | } | |
283 | ||
284 | /* See Porting Layer Definition - p. 57 */ | |
285 | void | |
286 | AbortDDX(enum ExitCode error) | |
287 | { | |
288 | #if CYGDEBUG | |
289 | winDebug("AbortDDX\n"); | |
290 | #endif | |
291 | ddxGiveUp(error); | |
292 | } | |
293 | ||
294 | #ifdef __CYGWIN__ | |
295 | /* hasmntopt is currently not implemented for cygwin */ | |
296 | static const char * | |
297 | winCheckMntOpt(const struct mntent *mnt, const char *opt) | |
298 | { | |
299 | const char *s; | |
300 | size_t len; | |
301 | ||
302 | if (mnt == NULL) | |
303 | return NULL; | |
304 | if (opt == NULL) | |
305 | return NULL; | |
306 | if (mnt->mnt_opts == NULL) | |
307 | return NULL; | |
308 | ||
309 | len = strlen(opt); | |
310 | s = strstr(mnt->mnt_opts, opt); | |
311 | if (s == NULL) | |
312 | return NULL; | |
313 | if ((s == mnt->mnt_opts || *(s - 1) == ',') && | |
314 | (s[len] == 0 || s[len] == ',')) | |
315 | return (char *) opt; | |
316 | return NULL; | |
317 | } | |
318 | ||
319 | static void | |
320 | winCheckMount(void) | |
321 | { | |
322 | FILE *mnt; | |
323 | struct mntent *ent; | |
324 | ||
325 | enum { none = 0, sys_root, user_root, sys_tmp, user_tmp } | |
326 | level = none, curlevel; | |
327 | BOOL binary = TRUE; | |
328 | ||
329 | mnt = setmntent("/etc/mtab", "r"); | |
330 | if (mnt == NULL) { | |
331 | ErrorF("setmntent failed"); | |
332 | return; | |
333 | } | |
334 | ||
335 | while ((ent = getmntent(mnt)) != NULL) { | |
336 | BOOL sys = (winCheckMntOpt(ent, "user") != NULL); | |
337 | BOOL root = (strcmp(ent->mnt_dir, "/") == 0); | |
338 | BOOL tmp = (strcmp(ent->mnt_dir, "/tmp") == 0); | |
339 | ||
340 | if (sys) { | |
341 | if (root) | |
342 | curlevel = sys_root; | |
343 | else if (tmp) | |
344 | curlevel = sys_tmp; | |
345 | else | |
346 | continue; | |
347 | } | |
348 | else { | |
349 | if (root) | |
350 | curlevel = user_root; | |
351 | else if (tmp) | |
352 | curlevel = user_tmp; | |
353 | else | |
354 | continue; | |
355 | } | |
356 | ||
357 | if (curlevel <= level) | |
358 | continue; | |
359 | level = curlevel; | |
360 | ||
361 | if ((winCheckMntOpt(ent, "binary") == NULL) && | |
362 | (winCheckMntOpt(ent, "binmode") == NULL)) | |
363 | binary = FALSE; | |
364 | else | |
365 | binary = TRUE; | |
366 | } | |
367 | ||
368 | if (endmntent(mnt) != 1) { | |
369 | ErrorF("endmntent failed"); | |
370 | return; | |
371 | } | |
372 | ||
373 | if (!binary) | |
374 | winMsg(X_WARNING, "/tmp mounted in textmode\n"); | |
375 | } | |
376 | #else | |
377 | static void | |
378 | winCheckMount(void) | |
379 | { | |
380 | } | |
381 | #endif | |
382 | ||
383 | #ifdef RELOCATE_PROJECTROOT | |
384 | const char * | |
385 | winGetBaseDir(void) | |
386 | { | |
387 | static BOOL inited = FALSE; | |
388 | static char buffer[MAX_PATH]; | |
389 | ||
390 | if (!inited) { | |
391 | char *fendptr; | |
392 | HMODULE module = GetModuleHandle(NULL); | |
393 | DWORD size = GetModuleFileName(module, buffer, sizeof(buffer)); | |
394 | ||
395 | if (sizeof(buffer) > 0) | |
396 | buffer[sizeof(buffer) - 1] = 0; | |
397 | ||
398 | fendptr = buffer + size; | |
399 | while (fendptr > buffer) { | |
400 | if (*fendptr == '\\' || *fendptr == '/') { | |
401 | *fendptr = 0; | |
402 | break; | |
403 | } | |
404 | fendptr--; | |
405 | } | |
406 | inited = TRUE; | |
407 | } | |
408 | return buffer; | |
409 | } | |
410 | #endif | |
411 | ||
412 | static void | |
413 | winFixupPaths(void) | |
414 | { | |
415 | BOOL changed_fontpath = FALSE; | |
416 | MessageType font_from = X_DEFAULT; | |
417 | ||
418 | #ifdef RELOCATE_PROJECTROOT | |
419 | const char *basedir = winGetBaseDir(); | |
420 | size_t basedirlen = strlen(basedir); | |
421 | #endif | |
422 | ||
423 | #ifdef READ_FONTDIRS | |
424 | { | |
425 | /* Open fontpath configuration file */ | |
426 | FILE *fontdirs = fopen(ETCX11DIR "/font-dirs", "rt"); | |
427 | ||
428 | if (fontdirs != NULL) { | |
429 | char buffer[256]; | |
430 | int needs_sep = TRUE; | |
431 | int comment_block = FALSE; | |
432 | ||
433 | /* get default fontpath */ | |
434 | char *fontpath = strdup(defaultFontPath); | |
435 | size_t size = strlen(fontpath); | |
436 | ||
437 | /* read all lines */ | |
438 | while (!feof(fontdirs)) { | |
439 | size_t blen; | |
440 | char *hashchar; | |
441 | char *str; | |
442 | int has_eol = FALSE; | |
443 | ||
444 | /* read one line */ | |
445 | str = fgets(buffer, sizeof(buffer), fontdirs); | |
446 | if (str == NULL) /* stop on error or eof */ | |
447 | break; | |
448 | ||
449 | if (strchr(str, '\n') != NULL) | |
450 | has_eol = TRUE; | |
451 | ||
452 | /* check if block is continued comment */ | |
453 | if (comment_block) { | |
454 | /* ignore all input */ | |
455 | *str = 0; | |
456 | blen = 0; | |
457 | if (has_eol) /* check if line ended in this block */ | |
458 | comment_block = FALSE; | |
459 | } | |
460 | else { | |
461 | /* find comment character. ignore all trailing input */ | |
462 | hashchar = strchr(str, '#'); | |
463 | if (hashchar != NULL) { | |
464 | *hashchar = 0; | |
465 | if (!has_eol) /* mark next block as continued comment */ | |
466 | comment_block = TRUE; | |
467 | } | |
468 | } | |
469 | ||
470 | /* strip whitespaces from beginning */ | |
471 | while (*str == ' ' || *str == '\t') | |
472 | str++; | |
473 | ||
474 | /* get size, strip whitespaces from end */ | |
475 | blen = strlen(str); | |
476 | while (blen > 0 && (str[blen - 1] == ' ' || | |
477 | str[blen - 1] == '\t' || | |
478 | str[blen - 1] == '\n')) { | |
479 | str[--blen] = 0; | |
480 | } | |
481 | ||
482 | /* still something left to add? */ | |
483 | if (blen > 0) { | |
484 | size_t newsize = size + blen; | |
485 | ||
486 | /* reserve one character more for ',' */ | |
487 | if (needs_sep) | |
488 | newsize++; | |
489 | ||
490 | /* allocate memory */ | |
491 | if (fontpath == NULL) | |
492 | fontpath = malloc(newsize + 1); | |
493 | else | |
494 | fontpath = realloc(fontpath, newsize + 1); | |
495 | ||
496 | /* add separator */ | |
497 | if (needs_sep) { | |
498 | fontpath[size] = ','; | |
499 | size++; | |
500 | needs_sep = FALSE; | |
501 | } | |
502 | ||
503 | /* mark next line as new entry */ | |
504 | if (has_eol) | |
505 | needs_sep = TRUE; | |
506 | ||
507 | /* add block */ | |
508 | strncpy(fontpath + size, str, blen); | |
509 | fontpath[newsize] = 0; | |
510 | size = newsize; | |
511 | } | |
512 | } | |
513 | ||
514 | /* cleanup */ | |
515 | fclose(fontdirs); | |
516 | defaultFontPath = strdup(fontpath); | |
517 | free(fontpath); | |
518 | changed_fontpath = TRUE; | |
519 | font_from = X_CONFIG; | |
520 | } | |
521 | } | |
522 | #endif /* READ_FONTDIRS */ | |
523 | #ifdef RELOCATE_PROJECTROOT | |
524 | { | |
525 | const char *libx11dir = PROJECTROOT "/lib/X11"; | |
526 | size_t libx11dir_len = strlen(libx11dir); | |
527 | char *newfp = NULL; | |
528 | size_t newfp_len = 0; | |
529 | const char *endptr, *ptr, *oldptr = defaultFontPath; | |
530 | ||
531 | endptr = oldptr + strlen(oldptr); | |
532 | ptr = strchr(oldptr, ','); | |
533 | if (ptr == NULL) | |
534 | ptr = endptr; | |
535 | while (ptr != NULL) { | |
536 | size_t oldfp_len = (ptr - oldptr); | |
537 | size_t newsize = oldfp_len; | |
538 | char *newpath = malloc(newsize + 1); | |
539 | ||
540 | strncpy(newpath, oldptr, newsize); | |
541 | newpath[newsize] = 0; | |
542 | ||
543 | if (strncmp(libx11dir, newpath, libx11dir_len) == 0) { | |
544 | char *compose; | |
545 | ||
546 | newsize = newsize - libx11dir_len + basedirlen; | |
547 | compose = malloc(newsize + 1); | |
548 | strcpy(compose, basedir); | |
549 | strncat(compose, newpath + libx11dir_len, newsize - basedirlen); | |
550 | compose[newsize] = 0; | |
551 | free(newpath); | |
552 | newpath = compose; | |
553 | } | |
554 | ||
555 | oldfp_len = newfp_len; | |
556 | if (oldfp_len > 0) | |
557 | newfp_len++; /* space for separator */ | |
558 | newfp_len += newsize; | |
559 | ||
560 | if (newfp == NULL) | |
561 | newfp = malloc(newfp_len + 1); | |
562 | else | |
563 | newfp = realloc(newfp, newfp_len + 1); | |
564 | ||
565 | if (oldfp_len > 0) { | |
566 | strcpy(newfp + oldfp_len, ","); | |
567 | oldfp_len++; | |
568 | } | |
569 | strcpy(newfp + oldfp_len, newpath); | |
570 | ||
571 | free(newpath); | |
572 | ||
573 | if (*ptr == 0) { | |
574 | oldptr = ptr; | |
575 | ptr = NULL; | |
576 | } | |
577 | else { | |
578 | oldptr = ptr + 1; | |
579 | ptr = strchr(oldptr, ','); | |
580 | if (ptr == NULL) | |
581 | ptr = endptr; | |
582 | } | |
583 | } | |
584 | ||
585 | defaultFontPath = strdup(newfp); | |
586 | free(newfp); | |
587 | changed_fontpath = TRUE; | |
588 | } | |
589 | #endif /* RELOCATE_PROJECTROOT */ | |
590 | if (changed_fontpath) | |
591 | winMsg(font_from, "FontPath set to \"%s\"\n", defaultFontPath); | |
592 | ||
593 | #ifdef RELOCATE_PROJECTROOT | |
594 | if (getenv("XKEYSYMDB") == NULL) { | |
595 | char buffer[MAX_PATH]; | |
596 | ||
597 | snprintf(buffer, sizeof(buffer), "XKEYSYMDB=%s\\XKeysymDB", basedir); | |
598 | buffer[sizeof(buffer) - 1] = 0; | |
599 | putenv(buffer); | |
600 | } | |
601 | if (getenv("XERRORDB") == NULL) { | |
602 | char buffer[MAX_PATH]; | |
603 | ||
604 | snprintf(buffer, sizeof(buffer), "XERRORDB=%s\\XErrorDB", basedir); | |
605 | buffer[sizeof(buffer) - 1] = 0; | |
606 | putenv(buffer); | |
607 | } | |
608 | if (getenv("XLOCALEDIR") == NULL) { | |
609 | char buffer[MAX_PATH]; | |
610 | ||
611 | snprintf(buffer, sizeof(buffer), "XLOCALEDIR=%s\\locale", basedir); | |
612 | buffer[sizeof(buffer) - 1] = 0; | |
613 | putenv(buffer); | |
614 | } | |
615 | if (getenv("HOME") == NULL) { | |
616 | char buffer[MAX_PATH + 5]; | |
617 | ||
618 | strncpy(buffer, "HOME=", 5); | |
619 | ||
620 | /* query appdata directory */ | |
621 | if (SHGetFolderPathA | |
622 | (NULL, CSIDL_APPDATA | CSIDL_FLAG_CREATE, NULL, 0, | |
623 | buffer + 5) == 0) { | |
624 | putenv(buffer); | |
625 | } | |
626 | else { | |
627 | winMsg(X_ERROR, "Can not determine HOME directory\n"); | |
628 | } | |
629 | } | |
630 | if (!g_fLogFileChanged) { | |
631 | static char buffer[MAX_PATH]; | |
632 | DWORD size = GetTempPath(sizeof(buffer), buffer); | |
633 | ||
634 | if (size && size < sizeof(buffer)) { | |
635 | snprintf(buffer + size, sizeof(buffer) - size, | |
636 | "XWin.%s.log", display); | |
637 | buffer[sizeof(buffer) - 1] = 0; | |
638 | g_pszLogFile = buffer; | |
639 | winMsg(X_DEFAULT, "Logfile set to \"%s\"\n", g_pszLogFile); | |
640 | } | |
641 | } | |
642 | { | |
643 | static char xkbbasedir[MAX_PATH]; | |
644 | ||
645 | snprintf(xkbbasedir, sizeof(xkbbasedir), "%s\\xkb", basedir); | |
646 | if (sizeof(xkbbasedir) > 0) | |
647 | xkbbasedir[sizeof(xkbbasedir) - 1] = 0; | |
648 | XkbBaseDirectory = xkbbasedir; | |
649 | XkbBinDirectory = basedir; | |
650 | } | |
651 | #endif /* RELOCATE_PROJECTROOT */ | |
652 | } | |
653 | ||
654 | void | |
655 | OsVendorInit(void) | |
656 | { | |
657 | /* Re-initialize global variables on server reset */ | |
658 | winInitializeGlobals(); | |
659 | ||
660 | winFixupPaths(); | |
661 | ||
662 | #ifdef DDXOSVERRORF | |
663 | if (!OsVendorVErrorFProc) | |
664 | OsVendorVErrorFProc = OsVendorVErrorF; | |
665 | #endif | |
666 | ||
667 | if (!g_fLogInited) { | |
668 | /* keep this order. If LogInit fails it calls Abort which then calls | |
669 | * ddxGiveUp where LogInit is called again and creates an infinite | |
670 | * recursion. If we set g_fLogInited to TRUE before the init we | |
671 | * avoid the second call | |
672 | */ | |
673 | g_fLogInited = TRUE; | |
674 | g_pszLogFile = LogInit(g_pszLogFile, NULL); | |
675 | } | |
676 | LogSetParameter(XLOG_FLUSH, 1); | |
677 | LogSetParameter(XLOG_VERBOSITY, g_iLogVerbose); | |
678 | LogSetParameter(XLOG_FILE_VERBOSITY, g_iLogVerbose); | |
679 | ||
680 | /* Log the version information */ | |
681 | if (serverGeneration == 1) | |
682 | winLogVersionInfo(); | |
683 | ||
684 | winCheckMount(); | |
685 | ||
686 | /* Add a default screen if no screens were specified */ | |
687 | if (g_iNumScreens == 0) { | |
688 | winDebug("OsVendorInit - Creating default screen 0\n"); | |
689 | ||
690 | /* | |
691 | * We need to initialize the default screen 0 if no -screen | |
692 | * arguments were processed. | |
693 | * | |
694 | * Add a screen 0 using the defaults set by winInitializeDefaultScreens() | |
695 | * and any additional default screen parameters given | |
696 | */ | |
697 | winInitializeScreens(1); | |
698 | ||
699 | /* We have to flag this as an explicit screen, even though it isn't */ | |
700 | g_ScreenInfo[0].fExplicitScreen = TRUE; | |
701 | } | |
702 | ||
703 | /* Work out what the default emulate3buttons setting should be, and apply | |
704 | it if nothing was explicitly specified */ | |
705 | { | |
706 | int mouseButtons = GetSystemMetrics(SM_CMOUSEBUTTONS); | |
707 | int j; | |
708 | ||
709 | for (j = 0; j < g_iNumScreens; j++) { | |
710 | if (g_ScreenInfo[j].iE3BTimeout == WIN_E3B_DEFAULT) { | |
711 | if (mouseButtons < 3) { | |
712 | static Bool reportOnce = TRUE; | |
713 | ||
714 | g_ScreenInfo[j].iE3BTimeout = WIN_DEFAULT_E3B_TIME; | |
715 | if (reportOnce) { | |
716 | reportOnce = FALSE; | |
717 | winMsg(X_PROBED, | |
718 | "Windows reports only %d mouse buttons, defaulting to -emulate3buttons\n", | |
719 | mouseButtons); | |
720 | } | |
721 | } | |
722 | else { | |
723 | g_ScreenInfo[j].iE3BTimeout = WIN_E3B_OFF; | |
724 | } | |
725 | } | |
726 | } | |
727 | } | |
728 | } | |
729 | ||
730 | static void | |
731 | winUseMsg(void) | |
732 | { | |
733 | ErrorF("\n"); | |
734 | ErrorF("\n"); | |
735 | ErrorF(EXECUTABLE_NAME " Device Dependent Usage:\n"); | |
736 | ErrorF("\n"); | |
737 | ||
738 | #ifdef XWIN_CLIPBOARD | |
739 | ErrorF("-[no]clipboard\n" | |
740 | "\tEnable [disable] the clipboard integration. Default is enabled.\n"); | |
741 | #endif | |
742 | ||
743 | ErrorF("-clipupdates num_boxes\n" | |
744 | "\tUse a clipping region to constrain shadow update blits to\n" | |
745 | "\tthe updated region when num_boxes, or more, are in the\n" | |
746 | "\tupdated region.\n"); | |
747 | ||
748 | #ifdef XWIN_XF86CONFIG | |
749 | ErrorF("-config\n" "\tSpecify a configuration file.\n"); | |
750 | ||
751 | ErrorF("-configdir\n" "\tSpecify a configuration directory.\n"); | |
752 | #endif | |
753 | ||
754 | ErrorF("-depth bits_per_pixel\n" | |
755 | "\tSpecify an optional bitdepth to use in fullscreen mode\n" | |
756 | "\twith a DirectDraw engine.\n"); | |
757 | ||
758 | ErrorF("-[no]emulate3buttons [timeout]\n" | |
759 | "\tEmulate 3 button mouse with an optional timeout in\n" | |
760 | "\tmilliseconds.\n"); | |
761 | ||
762 | #ifdef XWIN_EMULATEPSEUDO | |
763 | ErrorF("-emulatepseudo\n" | |
764 | "\tCreate a depth 8 PseudoColor visual when running in\n" | |
765 | "\tdepths 15, 16, 24, or 32, collectively known as TrueColor\n" | |
766 | "\tdepths. The PseudoColor visual does not have correct colors,\n" | |
767 | "\tand it may crash, but it at least allows you to run your\n" | |
768 | "\tapplication in TrueColor modes.\n"); | |
769 | #endif | |
770 | ||
771 | ErrorF("-engine engine_type_id\n" | |
772 | "\tOverride the server's automatically selected engine type:\n" | |
773 | "\t\t1 - Shadow GDI\n" | |
774 | "\t\t2 - Shadow DirectDraw\n" | |
775 | "\t\t4 - Shadow DirectDraw4 Non-Locking\n" | |
776 | #ifdef XWIN_PRIMARYFB | |
777 | "\t\t8 - Primary DirectDraw - obsolete\n" | |
778 | #endif | |
779 | #ifdef XWIN_NATIVEGDI | |
780 | "\t\t16 - Native GDI - experimental\n" | |
781 | #endif | |
782 | ); | |
783 | ||
784 | ErrorF("-fullscreen\n" "\tRun the server in fullscreen mode.\n"); | |
785 | ||
786 | ErrorF("-ignoreinput\n" "\tIgnore keyboard and mouse input.\n"); | |
787 | ||
788 | #ifdef XWIN_MULTIWINDOWEXTWM | |
789 | ErrorF("-internalwm\n" "\tRun the internal window manager.\n"); | |
790 | #endif | |
791 | ||
792 | #ifdef XWIN_XF86CONFIG | |
793 | ErrorF("-keyboard\n" | |
794 | "\tSpecify a keyboard device from the configuration file.\n"); | |
795 | #endif | |
796 | ||
797 | ErrorF("-[no]keyhook\n" | |
798 | "\tGrab special Windows keypresses like Alt-Tab or the Menu " | |
799 | "key.\n"); | |
800 | ||
801 | ErrorF("-lesspointer\n" | |
802 | "\tHide the windows mouse pointer when it is over any\n" | |
803 | "\t" EXECUTABLE_NAME | |
804 | " window. This prevents ghost cursors appearing when\n" | |
805 | "\tthe Windows cursor is drawn on top of the X cursor\n"); | |
806 | ||
807 | ErrorF("-logfile filename\n" "\tWrite log messages to <filename>.\n"); | |
808 | ||
809 | ErrorF("-logverbose verbosity\n" | |
810 | "\tSet the verbosity of log messages. [NOTE: Only a few messages\n" | |
811 | "\trespect the settings yet]\n" | |
812 | "\t\t0 - only print fatal error.\n" | |
813 | "\t\t1 - print additional configuration information.\n" | |
814 | "\t\t2 - print additional runtime information [default].\n" | |
815 | "\t\t3 - print debugging and tracing information.\n"); | |
816 | ||
817 | ErrorF("-[no]multimonitors or -[no]multiplemonitors\n" | |
818 | "\tUse the entire virtual screen if multiple\n" | |
819 | "\tmonitors are present.\n"); | |
820 | ||
821 | #ifdef XWIN_MULTIWINDOW | |
822 | ErrorF("-multiwindow\n" "\tRun the server in multi-window mode.\n"); | |
823 | #endif | |
824 | ||
825 | #ifdef XWIN_MULTIWINDOWEXTWM | |
826 | ErrorF("-mwextwm\n" | |
827 | "\tRun the server in multi-window external window manager mode.\n"); | |
828 | #endif | |
829 | ||
830 | ErrorF("-nodecoration\n" | |
831 | "\tDo not draw a window border, title bar, etc. Windowed\n" | |
832 | "\tmode only.\n"); | |
833 | ||
834 | #ifdef XWIN_CLIPBOARD | |
835 | ErrorF("-nounicodeclipboard\n" | |
836 | "\tDo not use Unicode clipboard even if on a NT-based platform.\n"); | |
837 | #endif | |
838 | ||
839 | ErrorF("-refresh rate_in_Hz\n" | |
840 | "\tSpecify an optional refresh rate to use in fullscreen mode\n" | |
841 | "\twith a DirectDraw engine.\n"); | |
842 | ||
843 | ErrorF("-resize=none|scrollbars|randr" | |
844 | "\tIn windowed mode, [don't] allow resizing of the window. 'scrollbars'\n" | |
845 | "\tmode gives the window scrollbars as needed, 'randr' mode uses the RANR\n" | |
846 | "\textension to resize the X screen. 'randr' is the default.\n"); | |
847 | ||
848 | ErrorF("-rootless\n" "\tRun the server in rootless mode.\n"); | |
849 | ||
850 | ErrorF("-screen scr_num [width height [x y] | [[WxH[+X+Y]][@m]] ]\n" | |
851 | "\tEnable screen scr_num and optionally specify a width and\n" | |
852 | "\theight and initial position for that screen. Additionally\n" | |
853 | "\ta monitor number can be specified to start the server on,\n" | |
854 | "\tat which point, all coordinates become relative to that\n" | |
855 | "\tmonitor. Examples:\n" | |
856 | "\t -screen 0 800x600+100+100@2 ; 2nd monitor offset 100,100 size 800x600\n" | |
857 | "\t -screen 0 1024x768@3 ; 3rd monitor size 1024x768\n" | |
858 | "\t -screen 0 @1 ; on 1st monitor using its full resolution (the default)\n"); | |
859 | ||
860 | ErrorF("-silent-dup-error\n" | |
861 | "\tIf another instance of " EXECUTABLE_NAME | |
862 | " with the same display number is running\n" | |
863 | "\texit silently and don't display any error message.\n"); | |
864 | ||
865 | ErrorF("-swcursor\n" | |
866 | "\tDisable the usage of the Windows cursor and use the X11 software\n" | |
867 | "\tcursor instead.\n"); | |
868 | ||
869 | ErrorF("-[no]trayicon\n" | |
870 | "\tDo not create a tray icon. Default is to create one\n" | |
871 | "\ticon per screen. You can globally disable tray icons with\n" | |
872 | "\t-notrayicon, then enable it for specific screens with\n" | |
873 | "\t-trayicon for those screens.\n"); | |
874 | ||
875 | ErrorF("-[no]unixkill\n" "\tCtrl+Alt+Backspace exits the X Server.\n"); | |
876 | ||
877 | #ifdef XWIN_GLX_WINDOWS | |
878 | ErrorF("-[no]wgl\n" | |
879 | "\tEnable the GLX extension to use the native Windows WGL interface for hardware-accelerated OpenGL\n"); | |
880 | #endif | |
881 | ||
882 | ErrorF("-[no]winkill\n" "\tAlt+F4 exits the X Server.\n"); | |
883 | ||
884 | ErrorF("-xkblayout XKBLayout\n" | |
885 | "\tEquivalent to XKBLayout in XF86Config files.\n" | |
886 | "\tFor example: -xkblayout de\n"); | |
887 | ||
888 | ErrorF("-xkbmodel XKBModel\n" | |
889 | "\tEquivalent to XKBModel in XF86Config files.\n"); | |
890 | ||
891 | ErrorF("-xkboptions XKBOptions\n" | |
892 | "\tEquivalent to XKBOptions in XF86Config files.\n"); | |
893 | ||
894 | ErrorF("-xkbrules XKBRules\n" | |
895 | "\tEquivalent to XKBRules in XF86Config files.\n"); | |
896 | ||
897 | ErrorF("-xkbvariant XKBVariant\n" | |
898 | "\tEquivalent to XKBVariant in XF86Config files.\n" | |
899 | "\tFor example: -xkbvariant nodeadkeys\n"); | |
900 | } | |
901 | ||
902 | /* See Porting Layer Definition - p. 57 */ | |
903 | void | |
904 | ddxUseMsg(void) | |
905 | { | |
906 | /* Set a flag so that FatalError won't give duplicate warning message */ | |
907 | g_fSilentFatalError = TRUE; | |
908 | ||
909 | winUseMsg(); | |
910 | ||
911 | /* Log file will not be opened for UseMsg unless we open it now */ | |
912 | if (!g_fLogInited) { | |
913 | g_pszLogFile = LogInit(g_pszLogFile, NULL); | |
914 | g_fLogInited = TRUE; | |
915 | } | |
916 | LogClose(EXIT_NO_ERROR); | |
917 | ||
918 | /* Notify user where UseMsg text can be found. */ | |
919 | if (!g_fNoHelpMessageBox) | |
920 | winMessageBoxF("The " PROJECT_NAME " help text has been printed to " | |
921 | "%s.\n" | |
922 | "Please open %s to read the help text.\n", | |
923 | MB_ICONINFORMATION, g_pszLogFile, g_pszLogFile); | |
924 | } | |
925 | ||
926 | /* See Porting Layer Definition - p. 20 */ | |
927 | /* | |
928 | * Do any global initialization, then initialize each screen. | |
929 | * | |
930 | * NOTE: We use ddxProcessArgument, so we don't need to touch argc and argv | |
931 | */ | |
932 | ||
933 | void | |
934 | InitOutput(ScreenInfo * pScreenInfo, int argc, char *argv[]) | |
935 | { | |
936 | int i; | |
937 | ||
938 | if (serverGeneration == 1) | |
939 | XwinExtensionInit(); | |
940 | ||
941 | /* Log the command line */ | |
942 | winLogCommandLine(argc, argv); | |
943 | ||
944 | #if CYGDEBUG | |
945 | winDebug("InitOutput\n"); | |
946 | #endif | |
947 | ||
948 | /* Validate command-line arguments */ | |
949 | if (serverGeneration == 1 && !winValidateArgs()) { | |
950 | FatalError("InitOutput - Invalid command-line arguments found. " | |
951 | "Exiting.\n"); | |
952 | } | |
953 | ||
954 | /* Check for duplicate invocation on same display number. */ | |
955 | if (serverGeneration == 1 && !winCheckDisplayNumber()) { | |
956 | if (g_fSilentDupError) | |
957 | g_fSilentFatalError = TRUE; | |
958 | FatalError("InitOutput - Duplicate invocation on display " | |
959 | "number: %s. Exiting.\n", display); | |
960 | } | |
961 | ||
962 | #ifdef XWIN_XF86CONFIG | |
963 | /* Try to read the xorg.conf-style configuration file */ | |
964 | if (!winReadConfigfile()) | |
965 | winErrorFVerb(1, "InitOutput - Error reading config file\n"); | |
966 | #else | |
967 | winMsg(X_INFO, "xorg.conf is not supported\n"); | |
968 | winMsg(X_INFO, "See http://x.cygwin.com/docs/faq/cygwin-x-faq.html " | |
969 | "for more information\n"); | |
970 | winConfigFiles(); | |
971 | #endif | |
972 | ||
973 | /* Load preferences from XWinrc file */ | |
974 | LoadPreferences(); | |
975 | ||
976 | /* Setup global screen info parameters */ | |
977 | pScreenInfo->imageByteOrder = IMAGE_BYTE_ORDER; | |
978 | pScreenInfo->bitmapScanlinePad = BITMAP_SCANLINE_PAD; | |
979 | pScreenInfo->bitmapScanlineUnit = BITMAP_SCANLINE_UNIT; | |
980 | pScreenInfo->bitmapBitOrder = BITMAP_BIT_ORDER; | |
981 | pScreenInfo->numPixmapFormats = NUMFORMATS; | |
982 | ||
983 | /* Describe how we want common pixmap formats padded */ | |
984 | for (i = 0; i < NUMFORMATS; i++) { | |
985 | pScreenInfo->formats[i] = g_PixmapFormats[i]; | |
986 | } | |
987 | ||
988 | /* Load pointers to DirectDraw functions */ | |
989 | winGetDDProcAddresses(); | |
990 | ||
991 | /* Detect supported engines */ | |
992 | winDetectSupportedEngines(); | |
993 | #ifdef XWIN_MULTIWINDOW | |
994 | /* Load libraries for taskbar grouping */ | |
995 | winPropertyStoreInit(); | |
996 | #endif | |
997 | ||
998 | /* Store the instance handle */ | |
999 | g_hInstance = GetModuleHandle(NULL); | |
1000 | ||
1001 | /* Create the messaging window */ | |
1002 | if (serverGeneration == 1) | |
1003 | winCreateMsgWindowThread(); | |
1004 | ||
1005 | /* Initialize each screen */ | |
1006 | for (i = 0; i < g_iNumScreens; ++i) { | |
1007 | /* Initialize the screen */ | |
1008 | if (-1 == AddScreen(winScreenInit, argc, argv)) { | |
1009 | FatalError("InitOutput - Couldn't add screen %d", i); | |
1010 | } | |
1011 | } | |
1012 | ||
1013 | #if defined(XWIN_CLIPBOARD) || defined(XWIN_MULTIWINDOW) | |
1014 | ||
1015 | /* Generate a cookie used by internal clients for authorization */ | |
1016 | if (g_fXdmcpEnabled || g_fAuthEnabled) | |
1017 | winGenerateAuthorization(); | |
1018 | ||
1019 | /* Perform some one time initialization */ | |
1020 | if (1 == serverGeneration) { | |
1021 | /* | |
1022 | * setlocale applies to all threads in the current process. | |
1023 | * Apply locale specified in LANG environment variable. | |
1024 | */ | |
1025 | setlocale(LC_ALL, ""); | |
1026 | } | |
1027 | #endif | |
1028 | ||
1029 | #if CYGDEBUG || YES | |
1030 | winDebug("InitOutput - Returning.\n"); | |
1031 | #endif | |
1032 | } | |
1033 | ||
1034 | /* | |
1035 | * winCheckDisplayNumber - Check if another instance of Cygwin/X is | |
1036 | * already running on the same display number. If no one exists, | |
1037 | * make a mutex to prevent new instances from running on the same display. | |
1038 | * | |
1039 | * return FALSE if the display number is already used. | |
1040 | */ | |
1041 | ||
1042 | static Bool | |
1043 | winCheckDisplayNumber(void) | |
1044 | { | |
1045 | int nDisp; | |
1046 | HANDLE mutex; | |
1047 | char name[MAX_PATH]; | |
1048 | char *pszPrefix = '\0'; | |
1049 | OSVERSIONINFO osvi = { 0 }; | |
1050 | ||
1051 | /* Check display range */ | |
1052 | nDisp = atoi(display); | |
1053 | if (nDisp < 0 || nDisp > 65535) { | |
1054 | ErrorF("winCheckDisplayNumber - Bad display number: %d\n", nDisp); | |
1055 | return FALSE; | |
1056 | } | |
1057 | ||
1058 | /* Set first character of mutex name to null */ | |
1059 | name[0] = '\0'; | |
1060 | ||
1061 | /* Get operating system version information */ | |
1062 | osvi.dwOSVersionInfoSize = sizeof(osvi); | |
1063 | GetVersionEx(&osvi); | |
1064 | ||
1065 | /* Want a mutex shared among all terminals on NT > 4.0 */ | |
1066 | if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT && osvi.dwMajorVersion >= 5) { | |
1067 | pszPrefix = "Global\\"; | |
1068 | } | |
1069 | ||
1070 | /* Setup Cygwin/X specific part of name */ | |
1071 | snprintf(name, sizeof(name), "%sCYGWINX_DISPLAY:%d", pszPrefix, nDisp); | |
1072 | ||
1073 | /* Windows automatically releases the mutex when this process exits */ | |
1074 | mutex = CreateMutex(NULL, FALSE, name); | |
1075 | if (!mutex) { | |
1076 | LPVOID lpMsgBuf; | |
1077 | ||
1078 | /* Display a fancy error message */ | |
1079 | FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | | |
1080 | FORMAT_MESSAGE_FROM_SYSTEM | | |
1081 | FORMAT_MESSAGE_IGNORE_INSERTS, | |
1082 | NULL, | |
1083 | GetLastError(), | |
1084 | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), | |
1085 | (LPTSTR) &lpMsgBuf, 0, NULL); | |
1086 | ErrorF("winCheckDisplayNumber - CreateMutex failed: %s\n", | |
1087 | (LPSTR) lpMsgBuf); | |
1088 | LocalFree(lpMsgBuf); | |
1089 | ||
1090 | return FALSE; | |
1091 | } | |
1092 | if (GetLastError() == ERROR_ALREADY_EXISTS) { | |
1093 | ErrorF("winCheckDisplayNumber - " | |
1094 | PROJECT_NAME " is already running on display %d\n", nDisp); | |
1095 | return FALSE; | |
1096 | } | |
1097 | ||
1098 | return TRUE; | |
1099 | } |