1 /*
2 * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
3 *
4 * This is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This software is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this software; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
17 * USA.
18 */
19
20 /*
21 * misc.c - miscellaneous functions.
22 */
23
24 #include <vncviewer.h>
25 #include <signal.h>
26 #include <fcntl.h>
27
28 static void CleanupSignalHandler(int sig);
29 static int CleanupXErrorHandler(Display *dpy, XErrorEvent *error);
30 static int CleanupXIOErrorHandler(Display *dpy);
31 static void CleanupXtErrorHandler(String message);
32 static Bool IconifyNamedWindow(Window w, char *name, Bool undo);
33
34 Dimension dpyWidth, dpyHeight;
35 Atom wmDeleteWindow, wmState;
36
37 static Bool xloginIconified = False;
38 static XErrorHandler defaultXErrorHandler;
39 static XIOErrorHandler defaultXIOErrorHandler;
40 static XtErrorHandler defaultXtErrorHandler;
41
42
43 /*
44 * ToplevelInitBeforeRealization sets the title, geometry and other resources
45 * on the toplevel window.
46 */
47
48 void
ToplevelInitBeforeRealization()49 ToplevelInitBeforeRealization()
50 {
51 char *titleFormat;
52 char *title;
53 char *geometry;
54
55 XtVaGetValues(toplevel, XtNtitle, &titleFormat, NULL);
56 title = XtMalloc(strlen(titleFormat) + strlen(desktopName) + 1);
57 sprintf(title, titleFormat, desktopName);
58 XtVaSetValues(toplevel, XtNtitle, title, XtNiconName, title, NULL);
59
60 XtVaSetValues(toplevel, XtNmaxWidth, si.framebufferWidth,
61 XtNmaxHeight, si.framebufferHeight, NULL);
62
63 dpyWidth = WidthOfScreen(DefaultScreenOfDisplay(dpy));
64 dpyHeight = HeightOfScreen(DefaultScreenOfDisplay(dpy));
65
66 if (appData.fullScreen) {
67
68 /* full screen - set position to 0,0, but defer size calculation until
69 widgets are realized */
70
71 XtVaSetValues(toplevel, XtNoverrideRedirect, True,
72 XtNgeometry, "+0+0", NULL);
73
74 } else {
75
76 /* not full screen - work out geometry for middle of screen unless
77 specified by user */
78
79 XtVaGetValues(toplevel, XtNgeometry, &geometry, NULL);
80
81 if (geometry == NULL) {
82 Dimension toplevelX, toplevelY;
83 Dimension toplevelWidth = si.framebufferWidth;
84 Dimension toplevelHeight = si.framebufferHeight;
85
86 if ((toplevelWidth + appData.wmDecorationWidth) >= dpyWidth)
87 toplevelWidth = dpyWidth - appData.wmDecorationWidth;
88
89 if ((toplevelHeight + appData.wmDecorationHeight) >= dpyHeight)
90 toplevelHeight = dpyHeight - appData.wmDecorationHeight;
91
92 toplevelX = (dpyWidth - toplevelWidth - appData.wmDecorationWidth) / 2;
93
94 toplevelY = (dpyHeight - toplevelHeight - appData.wmDecorationHeight) /2;
95
96 /* set position via "geometry" so that window manager thinks it's a
97 user-specified position and therefore honours it */
98
99 geometry = XtMalloc(256);
100
101 sprintf(geometry, "%dx%d+%d+%d",
102 toplevelWidth, toplevelHeight, toplevelX, toplevelY);
103 XtVaSetValues(toplevel, XtNgeometry, geometry, NULL);
104 }
105 }
106
107 /* Test if the keyboard is grabbed. If so, it's probably because the
108 XDM login window is up, so try iconifying it to release the grab */
109
110 if (XGrabKeyboard(dpy, DefaultRootWindow(dpy), False, GrabModeSync,
111 GrabModeSync, CurrentTime) == GrabSuccess) {
112 XUngrabKeyboard(dpy, CurrentTime);
113 } else {
114 wmState = XInternAtom(dpy, "WM_STATE", False);
115
116 if (IconifyNamedWindow(DefaultRootWindow(dpy), "xlogin", False)) {
117 xloginIconified = True;
118 XSync(dpy, False);
119 sleep(1);
120 }
121 }
122
123 /* Set handlers for signals and X errors to perform cleanup */
124
125 signal(SIGHUP, CleanupSignalHandler);
126 signal(SIGINT, CleanupSignalHandler);
127 signal(SIGTERM, CleanupSignalHandler);
128 defaultXErrorHandler = XSetErrorHandler(CleanupXErrorHandler);
129 defaultXIOErrorHandler = XSetIOErrorHandler(CleanupXIOErrorHandler);
130 defaultXtErrorHandler = XtAppSetErrorHandler(appContext,
131 CleanupXtErrorHandler);
132 }
133
134
135 /*
136 * ToplevelInitAfterRealization initialises things which require the X windows
137 * to exist. It goes into full-screen mode if appropriate, and tells the
138 * window manager we accept the "delete window" message.
139 */
140
141 void
ToplevelInitAfterRealization()142 ToplevelInitAfterRealization()
143 {
144 if (appData.fullScreen) {
145 FullScreenOn();
146 }
147
148 wmDeleteWindow = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
149 XSetWMProtocols(dpy, XtWindow(toplevel), &wmDeleteWindow, 1);
150 XtOverrideTranslations
151 (toplevel, XtParseTranslationTable ("<Message>WM_PROTOCOLS: Quit()"));
152 }
153
154
155 /*
156 * TimeFromEvent() gets the time field out of the given event. It returns
157 * CurrentTime if the event has no time field.
158 */
159
160 Time
TimeFromEvent(XEvent * ev)161 TimeFromEvent(XEvent *ev)
162 {
163 switch (ev->type) {
164 case KeyPress:
165 case KeyRelease:
166 return ev->xkey.time;
167 case ButtonPress:
168 case ButtonRelease:
169 return ev->xbutton.time;
170 case MotionNotify:
171 return ev->xmotion.time;
172 case EnterNotify:
173 case LeaveNotify:
174 return ev->xcrossing.time;
175 case PropertyNotify:
176 return ev->xproperty.time;
177 case SelectionClear:
178 return ev->xselectionclear.time;
179 case SelectionRequest:
180 return ev->xselectionrequest.time;
181 case SelectionNotify:
182 return ev->xselection.time;
183 default:
184 return CurrentTime;
185 }
186 }
187
188
189 /*
190 * Pause is an action which pauses for a number of milliseconds (100 by
191 * default). It is sometimes useful to space out "fake" pointer events
192 * generated by SendRFBEvent.
193 */
194
195 void
Pause(Widget w,XEvent * event,String * params,Cardinal * num_params)196 Pause(Widget w, XEvent *event, String *params, Cardinal *num_params)
197 {
198 int msec;
199
200 if (*num_params == 0) {
201 msec = 100;
202 } else {
203 msec = atoi(params[0]);
204 }
205
206 usleep(msec * 1000);
207 }
208
209
210 /*
211 * Run an arbitrary command via execvp()
212 */
213 void
RunCommand(Widget w,XEvent * event,String * params,Cardinal * num_params)214 RunCommand(Widget w, XEvent *event, String *params, Cardinal *num_params)
215 {
216 int childstatus;
217
218 if (*num_params == 0)
219 return;
220
221 if (fcntl (ConnectionNumber (dpy), F_SETFD, 1L) == -1)
222 fprintf(stderr, "warning: file descriptor %d unusable for spawned program", ConnectionNumber(dpy));
223
224 if (fcntl (rfbsock, F_SETFD, 1L) == -1)
225 fprintf(stderr, "warning: file descriptor %d unusable for spawned program", rfbsock);
226
227 switch (fork()) {
228 case -1:
229 perror("fork");
230 break;
231 case 0:
232 /* Child 1. Fork again. */
233 switch (fork()) {
234 case -1:
235 perror("fork");
236 break;
237
238 case 0:
239 /* Child 2. Do some work. */
240 execvp(params[0], params);
241 perror("exec");
242 exit(1);
243 break;
244
245 default:
246 break;
247 }
248
249 /* Child 1. Exit, and let init adopt our child */
250 exit(0);
251
252 default:
253 break;
254 }
255
256 /* Wait for Child 1 to die */
257 wait(&childstatus);
258
259 return;
260 }
261
262
263 /*
264 * Quit action - called when we get a "delete window" message.
265 */
266
267 void
Quit(Widget w,XEvent * event,String * params,Cardinal * num_params)268 Quit(Widget w, XEvent *event, String *params, Cardinal *num_params)
269 {
270 Cleanup();
271 exit(0);
272 }
273
274
275 /*
276 * Cleanup - perform any cleanup operations prior to exiting.
277 */
278
279 void
Cleanup()280 Cleanup()
281 {
282 if (xloginIconified) {
283 IconifyNamedWindow(DefaultRootWindow(dpy), "xlogin", True);
284 XFlush(dpy);
285 }
286 #ifdef MITSHM
287 if (appData.useShm)
288 ShmCleanup();
289 #endif
290 }
291
292 static int
CleanupXErrorHandler(Display * dpy,XErrorEvent * error)293 CleanupXErrorHandler(Display *dpy, XErrorEvent *error)
294 {
295 fprintf(stderr,"CleanupXErrorHandler called\n");
296 Cleanup();
297 return (*defaultXErrorHandler)(dpy, error);
298 }
299
300 static int
CleanupXIOErrorHandler(Display * dpy)301 CleanupXIOErrorHandler(Display *dpy)
302 {
303 fprintf(stderr,"CleanupXIOErrorHandler called\n");
304 Cleanup();
305 return (*defaultXIOErrorHandler)(dpy);
306 }
307
308 static void
CleanupXtErrorHandler(String message)309 CleanupXtErrorHandler(String message)
310 {
311 fprintf(stderr,"CleanupXtErrorHandler called\n");
312 Cleanup();
313 (*defaultXtErrorHandler)(message);
314 }
315
316 static void
CleanupSignalHandler(int sig)317 CleanupSignalHandler(int sig)
318 {
319 fprintf(stderr,"CleanupSignalHandler called\n");
320 Cleanup();
321 exit(1);
322 }
323
324
325 /*
326 * IconifyNamedWindow iconifies another client's window with the given name.
327 */
328
329 static Bool
IconifyNamedWindow(Window w,char * name,Bool undo)330 IconifyNamedWindow(Window w, char *name, Bool undo)
331 {
332 Window *children, dummy;
333 unsigned int nchildren;
334 int i;
335 char *window_name;
336 Atom type = None;
337 int format;
338 unsigned long nitems, after;
339 unsigned char *data;
340
341 if (XFetchName(dpy, w, &window_name)) {
342 if (strcmp(window_name, name) == 0) {
343 if (undo) {
344 XMapWindow(dpy, w);
345 } else {
346 XIconifyWindow(dpy, w, DefaultScreen(dpy));
347 }
348 XFree(window_name);
349 return True;
350 }
351 XFree(window_name);
352 }
353
354 XGetWindowProperty(dpy, w, wmState, 0, 0, False,
355 AnyPropertyType, &type, &format, &nitems,
356 &after, &data);
357 if (type != None) {
358 XFree(data);
359 return False;
360 }
361
362 if (!XQueryTree(dpy, w, &dummy, &dummy, &children, &nchildren))
363 return False;
364
365 for (i = 0; i < nchildren; i++) {
366 if (IconifyNamedWindow(children[i], name, undo)) {
367 XFree ((char *)children);
368 return True;
369 }
370 }
371 if (children) XFree ((char *)children);
372 return False;
373 }
374