1 /*
2  * Copyright (C) 2000-2007 Carsten Haitzler, Geoff Harrison and various contributors
3  * Copyright (C) 2004-2015 Kim Woelders
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy
6  * of this software and associated documentation files (the "Software"), to
7  * deal in the Software without restriction, including without limitation the
8  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9  * sell copies of the Software, and to permit persons to whom the Software is
10  * furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies of the Software, its documentation and marketing & publicity
14  * materials, and acknowledgment shall be given in the documentation, materials
15  * and software packages that this Software was used.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20  * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  */
24 #include "config.h"
25 
26 #include <signal.h>
27 #include <X11/Xlib.h>
28 #include <X11/keysym.h>
29 
30 #include "E.h"
31 #include "events.h"
32 #include "ewins.h"
33 #include "screen.h"
34 #include "session.h"
35 #include "xwin.h"
36 
37 static void
HandleXIOError(void)38 HandleXIOError(void)
39 {
40    SessionExit(EEXIT_ERROR, NULL);
41 }
42 
43 /*
44  * This function sets up all of our connections to X
45  */
46 void
SetupX(const char * dstr)47 SetupX(const char *dstr)
48 {
49    int                 err;
50    char                buf[128];
51    unsigned int        mask;
52 
53    if (!dstr)
54       dstr = getenv("DISPLAY");
55    if (!dstr)
56       dstr = ":0.0";
57 
58    /* Open a connection to the diplay nominated by the DISPLAY variable */
59    err = EDisplayOpen(dstr, Dpy.screen);
60    if (err)
61      {
62 	Alert(_("Enlightenment cannot connect to the display nominated by\n"
63 		"your shell's DISPLAY environment variable. You may set this\n"
64 		"variable to indicate which display name Enlightenment is to\n"
65 		"connect to. It may be that you do not have an Xserver already\n"
66 		"running to serve that Display connection, or that you do not\n"
67 		"have permission to connect to that display. Please make sure\n"
68 		"all is correct before trying again. Run an Xserver by running\n"
69 		"xdm or startx first, or contact your local system\n"
70 		"administrator, or Xserver vendor, or read the X, xdm and\n"
71 		"startx manual pages before proceeding.\n"));
72 	EExit(1);
73      }
74 
75    if (getenv("ESYNCHRONIZE"))
76       XSynchronize(disp, True);
77 
78    Dpy.screens = ScreenCount(disp);
79    Dpy.screen = DefaultScreen(disp);
80 
81    if (Mode.wm.master ||
82        Mode.wm.master_screen < 0 || Mode.wm.master_screen >= Dpy.screens)
83       Mode.wm.master_screen = Dpy.screen;
84 
85    /* Start up on multiple heads, if appropriate */
86    if (Dpy.screens > 1 && !Mode.wm.single && !Mode.wm.restart)
87      {
88 	int                 i;
89 
90 	for (i = 0; i < Dpy.screens; i++)
91 	  {
92 	     pid_t               pid;
93 
94 	     if (i == Dpy.screen)
95 		continue;
96 
97 	     pid = fork();
98 	     if (pid)
99 	       {
100 		  /* We are the master */
101 		  Mode.wm.child_count++;
102 		  Mode.wm.children =
103 		     EREALLOC(pid_t, Mode.wm.children, Mode.wm.child_count);
104 		  Mode.wm.children[Mode.wm.child_count - 1] = pid;
105 	       }
106 	     else
107 	       {
108 		  /* We are a slave */
109 		  EDisplayDisconnect();
110 		  Mode.wm.master = 0;
111 		  Mode.wm.pid = getpid();
112 		  Dpy.screen = i;
113 		  ExtInitWinSet(NoXID);
114 #ifdef SIGSTOP
115 		  kill(getpid(), SIGSTOP);
116 #endif
117 		  EDisplayOpen(dstr, i);
118 		  /* Terminate the loop as I am the child process... */
119 		  break;
120 	       }
121 	  }
122      }
123 
124    Dpy.name = Estrdup(DisplayString(disp));
125    Esetenv("DISPLAY", Dpy.name);
126 
127    Dpy.pixel_black = BlackPixel(disp, Dpy.screen);
128    Dpy.pixel_white = WhitePixel(disp, Dpy.screen);
129 
130    EDisplaySetErrorHandlers(EventShowError, HandleXIOError);
131 
132    /* Root defaults */
133    RROOT = ERegisterWindow(DefaultRootWindow(disp), NULL);
134 
135    if (Mode.wm.window)
136      {
137 	VROOT = ECreateWindow(RROOT, 0, 0, Mode.wm.win_w, Mode.wm.win_h, 0);
138 
139 	/* Enable eesh and edox to pick up the virtual root */
140 	Esnprintf(buf, sizeof(buf), "%#x", WinGetXwin(VROOT));
141 	Esetenv("ENL_WM_ROOT", buf);
142      }
143    else
144      {
145 	/* Running E normally on the root window */
146 	VROOT = RROOT;
147      }
148 
149    Dpy.root_gc = EXCreateGC(WinGetXwin(VROOT), 0, NULL);
150 
151    /* Initialise event handling */
152    EventsInit();
153 
154    /* select all the root window events to start managing */
155    Dpy.last_error_code = 0;
156    mask =
157       StructureNotifyMask | SubstructureNotifyMask | SubstructureRedirectMask;
158    ESelectInput(VROOT, mask);
159    ESync(0);
160    if (Dpy.last_error_code)
161      {
162 	AlertX(_("Another Window Manager is already running"),
163 	       _("OK"), NULL, NULL,
164 	       _("Another Window Manager is already running.\n" "\n"
165 		 "You will have to quit your current Window Manager first before\n"
166 		 "you can successfully run Enlightenment.\n"));
167 	EExit(1);
168      }
169 
170    mask |= ButtonPressMask | ButtonReleaseMask;
171    ESelectInput(VROOT, mask);
172    ESync(0);
173    if (Dpy.last_error_code)
174      {
175 	AlertX(_("Cannot select root window button press events"),
176 	       _("OK"), NULL, NULL,
177 	       _("Root window button actions will not work.\n"));
178      }
179 
180    /* warn, if necessary about X version problems */
181    if (ProtocolVersion(disp) != 11)
182      {
183 	AlertX(_("X server version error"), _("Ignore this error"), "",
184 	       _("Quit Enlightenment"),
185 	       _("WARNING:\n"
186 		 "This is not an X11 Xserver. It in fact talks the X%i protocol.\n"
187 		 "This may mean Enlightenment will either not function, or\n"
188 		 "function incorrectly. If it is later than X11, then your\n"
189 		 "server is one the author of Enlightenment neither have\n"
190 		 "access to, nor have heard of.\n"), ProtocolVersion(disp));
191      }
192 
193    /* damn that bloody numlock stuff - ok I'd rather XFree got fixed to not */
194    /* have it as a modifier and everyone have to write specific code to mask */
195    /* it out - but well.... */
196    /* ok under Xfree Numlock and Scollock are lock modifiers and we need */
197    /* to hunt them down to mask them out - EVIL EVIL EVIL hack but needed */
198    {
199       XModifierKeymap    *mod;
200       EX_KeyCode          nl, sl;
201       unsigned int        numlock, scrollock;
202       int                 i;
203 
204       int                 masks[8] = {
205 	 ShiftMask, LockMask, ControlMask, Mod1Mask, Mod2Mask, Mod3Mask,
206 	 Mod4Mask, Mod5Mask
207       };
208 
209       numlock = scrollock = 0;
210       mod = XGetModifierMapping(disp);
211       nl = EKeysymToKeycode(XK_Num_Lock);
212       sl = EKeysymToKeycode(XK_Scroll_Lock);
213       if ((mod) && (mod->max_keypermod > 0))
214 	{
215 	   for (i = 0; i < (8 * mod->max_keypermod); i++)
216 	     {
217 		if ((nl) && (mod->modifiermap[i] == nl))
218 		   numlock = masks[i / mod->max_keypermod];
219 		else if ((sl) && (mod->modifiermap[i] == sl))
220 		   scrollock = masks[i / mod->max_keypermod];
221 	     }
222 	}
223       Mode.masks.mod_combos[0] = 0;
224       Mode.masks.mod_combos[1] = LockMask;
225       if (numlock)
226 	{
227 	   Mode.masks.mod_combos[2] = numlock;
228 	   Mode.masks.mod_combos[5] = LockMask | numlock;
229 	}
230       if (scrollock)
231 	{
232 	   Mode.masks.mod_combos[3] = scrollock;
233 	   Mode.masks.mod_combos[6] = LockMask | scrollock;
234 	}
235       if (numlock && scrollock)
236 	{
237 	   Mode.masks.mod_combos[4] = numlock | scrollock;
238 	   Mode.masks.mod_combos[7] = LockMask | numlock | scrollock;
239 	}
240 
241       Mode.masks.mod_key_mask =
242 	 (ShiftMask | ControlMask | Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask |
243 	  Mod5Mask) & (~(numlock | scrollock | LockMask));
244 
245       if (mod)
246 	 XFreeModifiermap(mod);
247    }
248 
249    ScreenInit();
250 }
251