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