1 /*
2  * Copyright (C) 2002 Sasha Vasko <sasha at aftercode.net>
3  *
4  * This program 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 program 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 program; if not, write to the Free Software
16  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  *
18  */
19 
20 #define LOCAL_DEBUG
21 #include "../configure.h"
22 #include "asapp.h"
23 
24 #include <signal.h>
25 #include <sys/socket.h>
26 #include <sys/types.h>
27 #include <sys/fcntl.h>
28 #include <sys/un.h>
29 
30 #include "afterstep.h"
31 #include "mystyle.h"
32 #include "screen.h"
33 #include "module.h"
34 #include "wmprops.h"
35 #include "../libAfterImage/afterimage.h"
36 #include <X11/XKBlib.h>
37 #ifdef XSHMIMAGE
38 #include <sys/ipc.h>
39 #include <sys/shm.h>
40 #include <X11/extensions/XShm.h>
41 #endif
42 
43 static Bool as_X_synchronous_mode = False;
44 
45 /*************************************************************************/
46 /* Scr data members access functions to be used in linking DLLs          */
get_screen_width(ScreenInfo * scr)47 int get_screen_width (ScreenInfo * scr)
48 {
49 	if (scr == NULL)
50 		scr = ASDefaultScr;
51 	return scr->MyDisplayWidth;
52 }
53 
get_screen_height(ScreenInfo * scr)54 int get_screen_height (ScreenInfo * scr)
55 {
56 	if (scr == NULL)
57 		scr = ASDefaultScr;
58 	return scr->MyDisplayHeight;
59 }
60 
get_screen_current_desk(ScreenInfo * scr)61 int get_screen_current_desk (ScreenInfo * scr)
62 {
63 	if (scr == NULL)
64 		scr = ASDefaultScr;
65 	return scr->CurrentDesk;
66 }
67 
get_screen_look(ScreenInfo * scr)68 struct MyLook *get_screen_look (ScreenInfo * scr)
69 {
70 	if (scr == NULL)
71 		scr = ASDefaultScr;
72 	return &(scr->Look);
73 }
74 
get_screen_image_manager(ScreenInfo * scr)75 struct ASImageManager *get_screen_image_manager (ScreenInfo * scr)
76 {
77 	if (scr == NULL)
78 		scr = ASDefaultScr;
79 	return scr->image_manager;
80 }
81 
get_screen_font_manager(ScreenInfo * scr)82 struct ASFontManager *get_screen_font_manager (ScreenInfo * scr)
83 {
84 	if (scr == NULL)
85 		scr = ASDefaultScr;
86 	return scr->font_manager;
87 }
88 
get_screen_visual(ScreenInfo * scr)89 struct ASVisual *get_screen_visual (ScreenInfo * scr)
90 {
91 	if (scr == NULL)
92 		scr = ASDefaultScr;
93 	return scr->asv;
94 }
95 
96 
get_current_screen()97 ScreenInfo *get_current_screen ()
98 {
99 	return ASDefaultScr;
100 }
101 
102 void
reload_screen_image_manager(ScreenInfo * scr,ASImageManager ** old_imageman)103 reload_screen_image_manager (ScreenInfo * scr,
104 														 ASImageManager ** old_imageman)
105 {
106 	char *env_path1 = NULL, *env_path2 = NULL;
107 
108 	if (scr == NULL)
109 		scr = ASDefaultScr;
110 	if (old_imageman) {
111 		*old_imageman = scr->image_manager;
112 	} else if (scr->image_manager)
113 		destroy_image_manager (scr->image_manager, False);
114 
115 	env_path1 = getenv ("IMAGE_PATH");
116 	/* otherwise we'll be loading binary files as images - no good!!! */
117 	/*  env_path2 = getenv ("PATH"); */
118 	if (env_path1 == NULL) {
119 		env_path1 = env_path2;
120 		env_path2 = NULL;
121 	}
122 	scr->image_manager =
123 			create_image_manager (NULL, 2.2,
124 														Environment->pixmap_path ? Environment->
125 														pixmap_path : "",
126 														Environment->IconThemePath ? Environment->
127 														IconThemePath : "", env_path1, env_path2,
128 														NULL);
129 	set_xml_image_manager (scr->image_manager);
130 	show_progress ("Pixmap Path changed to \"%s:%s:%s:%s\" ...",
131 								 Environment->pixmap_path ? Environment->pixmap_path : "",
132 								 Environment->IconThemePath ? Environment->
133 								 IconThemePath : "", env_path1 ? env_path1 : "",
134 								 env_path2 ? env_path2 : "");
135 }
136 
137 /*************************************************************************/
138 
get_Xinerama_rectangles(ScreenInfo * scr)139 void get_Xinerama_rectangles (ScreenInfo * scr)
140 {
141 #ifdef HAVE_XINERAMA
142 	if (XineramaQueryExtension
143 			(dpy, &(scr->XineEventBase), &(scr->XineErrorBase))) {
144 		register int i;
145 		XineramaScreenInfo *s;
146 
147 		if ((s =
148 				 XineramaQueryScreens (dpy,
149 															 &(scr->xinerama_screens_num))) != NULL) {
150 			static char buf[256];
151 
152 			scr->xinerama_screens =
153 					safemalloc (sizeof (XRectangle) * scr->xinerama_screens_num);
154 			asxml_var_insert ("xroot.xinerama_screens_num",
155 												scr->xinerama_screens_num);
156 			for (i = 0; i < scr->xinerama_screens_num; ++i) {
157 				char *append_point = &buf[0];
158 
159 				sprintf (append_point, "xroot.xinerama_screens[%d].", i);
160 				append_point += 23;
161 				while (*append_point)
162 					++append_point;
163 
164 				append_point[0] = 'x';
165 				append_point[1] = '\0';
166 				asxml_var_insert (&buf[0], s[i].x_org);
167 				scr->xinerama_screens[i].x = s[i].x_org;
168 
169 				append_point[0] = 'y';
170 				asxml_var_insert (&buf[0], s[i].y_org);
171 				scr->xinerama_screens[i].y = s[i].y_org;
172 
173 				strcpy (append_point, "width");
174 				asxml_var_insert (&buf[0], s[i].width);
175 				scr->xinerama_screens[i].width = s[i].width;
176 
177 				strcpy (append_point, "height");
178 				asxml_var_insert (&buf[0], s[i].height);
179 				scr->xinerama_screens[i].height = s[i].height;
180 			}
181 			XFree (s);
182 		}
183 	} else
184 #endif
185 	{
186 		scr->xinerama_screens = NULL;
187 		scr->xinerama_screens_num = 0;
188 		asxml_var_insert ("xroot.xinerama_screens_num", 0);
189 	}
190 }
191 
set_synchronous_mode(Bool enable)192 Bool set_synchronous_mode (Bool enable)
193 {
194 	Bool old = as_X_synchronous_mode;
195 
196 	XSynchronize (dpy, enable);
197 	as_X_synchronous_mode = enable;
198 	return old;
199 }
200 
is_synchronous_request(int request_code)201 Bool is_synchronous_request (int request_code)
202 {
203 	if (as_X_synchronous_mode)
204 		return True;
205 	switch (request_code) {
206 	case X_CreateWindow:
207 	case X_GetWindowAttributes:
208 	case X_GetGeometry:
209 	case X_QueryTree:
210 	case X_InternAtom:
211 	case X_GetAtomName:
212 	case X_GetProperty:
213 	case X_ListProperties:
214 	case X_GetSelectionOwner:
215 	case X_ConvertSelection:
216 	case X_QueryPointer:
217 	case X_GetMotionEvents:
218 	case X_TranslateCoords:
219 	case X_GetInputFocus:
220 	case X_QueryKeymap:
221 	case X_OpenFont:
222 	case X_QueryFont:
223 	case X_QueryTextExtents:
224 	case X_ListFonts:
225 	case X_ListFontsWithInfo:
226 	case X_GetFontPath:
227 	case X_CreatePixmap:
228 	case X_CreateGC:
229 	case X_GetImage:
230 	case X_CreateColormap:
231 	case X_CopyColormapAndFree:
232 	case X_ListInstalledColormaps:
233 	case X_AllocColor:
234 	case X_AllocNamedColor:
235 	case X_AllocColorCells:
236 	case X_AllocColorPlanes:
237 	case X_QueryColors:
238 	case X_LookupColor:
239 	case X_CreateCursor:
240 	case X_CreateGlyphCursor:
241 	case X_QueryBestSize:
242 	case X_QueryExtension:
243 	case X_ListExtensions:
244 	case X_GetKeyboardMapping:
245 	case X_GetKeyboardControl:
246 	case X_GetPointerControl:
247 	case X_GetScreenSaver:
248 	case X_ListHosts:
249 	case X_GetPointerMapping:
250 	case X_GetModifierMapping:
251 		return True;
252 		break;
253 	default:
254 		break;
255 	}
256 	return False;
257 }
258 
ASErrorHandler(Display * dpy,XErrorEvent * event)259 int ASErrorHandler (Display * dpy, XErrorEvent * event)
260 {
261 	char *err_text;
262 
263 	fprintf (stderr,
264 					 "%s has encountered a problem interacting with X Windows :\n",
265 					 MyName);
266 	if (event && dpy) {
267 		if (event->error_code == BadWindow && ASDefaultScr->Windows != NULL)
268 			if (ASDefaultScr->on_dead_window)
269 				if (ASDefaultScr->on_dead_window (event->resourceid))
270 					return 0;
271 
272 		err_text = safemalloc (128);
273 		strcpy (err_text, "unknown error");
274 		XGetErrorText (dpy, event->error_code, err_text, 120);
275 		fprintf (stderr, "      Request: %d,    Error: %d(%s)\n",
276 						 event->request_code, event->error_code, err_text);
277 		free (err_text);
278 		fprintf (stderr, "      in resource: 0x%lX\n", event->resourceid);
279 #ifndef __CYGWIN__
280 		if (is_synchronous_request (event->request_code))
281 			print_simple_backtrace ();
282 #endif
283 	}
284 	return 0;
285 }
286 
287 
init_ScreenInfo(ScreenInfo * scr)288 void init_ScreenInfo (ScreenInfo * scr)
289 {
290 	if (scr) {
291 		memset (scr, 0x00, sizeof (ScreenInfo));
292 		scr->Look.magic = MAGIC_MYLOOK;
293 	}
294 }
295 
ConnectXDisplay(Display * display,ScreenInfo * scr,Bool as_manager)296 int ConnectXDisplay (Display * display, ScreenInfo * scr, Bool as_manager)
297 {
298 	int width_mm, height_mm;
299 	int display_dpcmx = 0, display_dpcmy = 0;
300 	int button_w, button_h, mini_w, mini_h;
301 
302 	if (display == NULL)
303 		return -1;
304 
305 	dpy = display;
306 	set_current_X_display (display);	/* for libAfterBase X Wrappers */
307 
308 	if (scr == NULL) {
309 		if (ASDefaultScr == NULL)
310 			ASDefaultScr = safecalloc (1, sizeof (ScreenInfo));
311 		scr = ASDefaultScr;
312 	}
313 
314 	init_ScreenInfo (scr);
315 
316 	x_fd = XConnectionNumber (dpy);
317 
318 	if (x_fd < 0) {
319 		show_error ("failed to initialize X Windows session. Aborting!");
320 		exit (1);
321 	}
322 	if (fcntl (x_fd, F_SETFD, 1) == -1)
323 		show_warning ("close-on-exec for X Windows connection failed");
324 
325 	XSetErrorHandler (ASErrorHandler);
326 
327 	if (get_flags (MyArgs.flags, ASS_Debugging))
328 		set_synchronous_mode (True);
329 
330 	intern_hint_atoms ();
331 	intern_wmprop_atoms ();
332 
333 	scr->screen = DefaultScreen (dpy);
334 	scr->Root = RootWindow (dpy, scr->screen);
335 	if (scr->Root == None) {
336 		show_error ("Screen %d is not valid. Exiting.", (int)scr->screen);
337 		exit (1);
338 	}
339 
340 	scr->NumberOfScreens = NumberOfScreens = ScreenCount (dpy);
341 	scr->MyDisplayWidth = DisplayWidth (dpy, scr->screen);
342 	scr->MyDisplayHeight = DisplayHeight (dpy, scr->screen);
343 
344 	asxml_var_insert ("xroot.width", scr->MyDisplayWidth);
345 	asxml_var_insert ("xroot.height", scr->MyDisplayHeight);
346 
347 	width_mm = DisplayWidthMM (dpy, scr->screen);
348 	height_mm = DisplayHeightMM (dpy, scr->screen);
349 	asxml_var_insert ("xroot.widthmm", width_mm);
350 	asxml_var_insert ("xroot.heightmm", height_mm);
351 
352 	display_dpcmx = (scr->MyDisplayWidth * 10) / width_mm;
353 	display_dpcmy = (scr->MyDisplayHeight * 10) / height_mm;
354 
355 	button_w = (display_dpcmx < 50) ? 48 : 64;
356 	button_h = (display_dpcmy < 50) ? 48 : 64;
357 	mini_w =
358 			(display_dpcmx <= 44) ? max (display_dpcmx / 2,
359 																	 12) : display_dpcmx - 20;
360 	mini_h =
361 			(display_dpcmy <= 44) ? max (display_dpcmy / 2,
362 																	 12) : display_dpcmy - 20;
363 	asxml_var_insert (ASXMLVAR_IconButtonWidth, button_w);
364 	asxml_var_insert (ASXMLVAR_IconButtonHeight, button_h);
365 	asxml_var_insert (ASXMLVAR_IconWidth, (button_w * 3) / 4);
366 	asxml_var_insert (ASXMLVAR_IconHeight, (button_h * 3) / 4);
367 	asxml_var_insert (ASXMLVAR_MinipixmapWidth, mini_w);
368 	asxml_var_insert (ASXMLVAR_MinipixmapHeight, mini_h);
369 	asxml_var_insert (ASXMLVAR_TitleFontSize, (mini_h * 7) / 12);
370 	asxml_var_insert (ASXMLVAR_MenuFontSize, (mini_h * 7) / 12 + 1);
371 	asxml_var_insert ("font.size", ((mini_h * 7) / 12));
372 
373 	scr->CurrentDesk = -1;
374 
375 	scr->RootClipArea.width = scr->MyDisplayWidth;
376 	scr->RootClipArea.height = scr->MyDisplayHeight;
377 
378 	if ((scr->wmprops =
379 			 setup_wmprops (scr, as_manager, 0xFFFFFFFF, NULL)) == NULL)
380 		return -1;
381 
382 	scr->asv =
383 			create_asvisual (dpy, scr->screen, DefaultDepth (dpy, scr->screen),
384 											 NULL);
385 	if (scr->asv == NULL) {
386 		show_error ("Failed to find suitable visual for screen %d. Exiting.",
387 								(int)scr->screen);
388 		exit (1);
389 	}
390 
391 	scr->d_depth = scr->asv->visual_info.depth;
392 
393 	scr->last_Timestamp = CurrentTime;
394 	scr->menu_grab_Timestamp = CurrentTime;
395 
396 	setup_modifiers ();
397 
398 	get_Xinerama_rectangles (scr);
399 
400 #ifdef SHAPE
401 	XShapeQueryExtension (dpy, &(scr->ShapeEventBase),
402 												&(scr->ShapeErrorBase));
403 #endif													/* SHAPE */
404 #ifdef XSHMIMAGE
405 	scr->ShmCompletionEventType = XShmGetEventBase (dpy) + ShmCompletion;
406 #endif													/* SHAPE */
407 
408 	init_screen_gcs (scr);
409 
410 	return x_fd;
411 }
412 
ConnectX(ScreenInfo * scr,unsigned long event_mask)413 int ConnectX (ScreenInfo * scr, unsigned long event_mask)
414 {
415 	if (!(dpy = XOpenDisplay (MyArgs.display_name))) {
416 		show_error ("Can't open display \"%s\". Exiting!",
417 								XDisplayName (MyArgs.display_name));
418 		exit (1);
419 	}
420 
421 	ConnectXDisplay (dpy, scr, (event_mask & SubstructureRedirectMask));
422 	XSelectInput (dpy, scr->Root, event_mask);
423 	return x_fd;
424 }
425 
426 
427 /***********************************************************************
428  *  Procedure:
429  *  SetupEnvironment - setup environment variables DISPLAY and HOSTDISPLAY
430  *  for our children to use.
431  ************************************************************************/
make_screen_envvars(ScreenInfo * scr)432 void make_screen_envvars (ScreenInfo * scr)
433 {
434 	int len;
435 	char *display = ":0.0";
436 	char client[MAXHOSTNAME];
437 
438 /* We set environmanet vars and we keep memory used for those allocated
439  * as some OS's don't copy the environment variables properly
440  */
441 	if (scr == NULL)
442 		scr = ASDefaultScr;
443 
444 	if (scr->display_string)
445 		free (scr->display_string);
446 	if (scr->rdisplay_string)
447 		free (scr->rdisplay_string);
448 
449 	/*  Add a DISPLAY entry to the environment, incase we were started
450 	 * with afterstep -display term:0.0
451 	 */
452 	display = XDisplayString (dpy);
453 	len = strlen (display);
454 	scr->display_string = safemalloc (len + 10);
455 	sprintf (scr->display_string, "DISPLAY=%s", display);
456 
457 	/* Add a HOSTDISPLAY environment variable, which is the same as
458 	 * DISPLAY, unless display = :0.0 or unix:0.0, in which case the full
459 	 * host name will be used for ease in networking . */
460 	if (scr->display_string[8] == ':'
461 			|| strncmp (&(scr->display_string[8]), "unix:", 5) == 0) {
462 		register char *ptr = &(scr->display_string[8]);
463 
464 		if (*ptr != ':')
465 			ptr += 5;
466 		mygethostname (client, MAXHOSTNAME);
467 		scr->localhost = True;
468 		scr->rdisplay_string = safemalloc (len + 14 + strlen (client));
469 		sprintf (scr->rdisplay_string, "HOSTDISPLAY=%s:%s", client, ptr);
470 	} else {											/* X Server is likely to be runnig on other computer: */
471 		scr->localhost = False;
472 		scr->rdisplay_string = safemalloc (len + 14);
473 		sprintf (scr->rdisplay_string, "HOSTDISPLAY=%s", display);
474 	}
475 }
476 
init_screen_gcs(ScreenInfo * scr)477 void init_screen_gcs (ScreenInfo * scr)
478 {
479 	XGCValues gcv;
480 	unsigned long gcm = GCGraphicsExposures;
481 
482 	if (scr == NULL)
483 		scr = ASDefaultScr;
484 
485 	gcv.graphics_exposures = False;
486 
487 	scr->RootGC = XCreateGC (dpy, scr->Root, gcm, &gcv);
488 	scr->DrawGC = create_visual_gc (scr->asv, scr->Root, gcm, &gcv);
489 }
490 
destroy_screen_gcs(ScreenInfo * scr)491 void destroy_screen_gcs (ScreenInfo * scr)
492 {
493 	if (scr == NULL)
494 		scr = ASDefaultScr;
495 
496 	if (scr->DrawGC) {
497 		XFreeGC (dpy, scr->DrawGC);
498 		scr->DrawGC = NULL;
499 	}
500 	if (scr->RootGC) {
501 		XFreeGC (dpy, scr->RootGC);
502 		scr->RootGC = NULL;
503 	}
504 }
505 
506 /* Setting up global variables  nonlock_mods, and lock_mods, defined in asapp.c : */
setup_modifiers()507 void setup_modifiers ()
508 {
509 	int m, i, knl;
510 	char *kn;
511 	KeySym ks;
512 	KeyCode kc, *kp;
513 	unsigned lockmask, *mp;
514 	XModifierKeymap *mm = XGetModifierMapping (dpy);
515 
516 	lockmask = LockMask;
517 	if (mm) {
518 		kp = mm->modifiermap;
519 		for (m = 0; m < 8; m++) {
520 			for (i = 0; i < mm->max_keypermod; i++) {
521 				if ((kc = *kp++)
522 						&& ((ks = XkbKeycodeToKeysym (dpy, kc, 0, 0)) != NoSymbol)) {
523 					kn = XKeysymToString (ks);
524 					knl = strlen (kn);
525 					if ((knl > 6) && (mystrcasecmp (kn + knl - 4, "lock") == 0))
526 						lockmask |= (1 << m);
527 				}
528 			}
529 		}
530 		XFreeModifiermap (mm);
531 	}
532 /* forget shift & control locks */
533 	lockmask &= ~(ShiftMask | ControlMask);
534 	nonlock_mods =
535 			((ShiftMask | ControlMask | Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask
536 				| Mod5Mask) & ~lockmask);
537 
538 	LOCAL_DEBUG_OUT ("lockmask = %X, nonlock_mods = %X", lockmask,
539 									 nonlock_mods);
540 
541 	mp = lock_mods;
542 	for (m = 0, i = 1; i < MAX_LOCK_MODS; i++) {
543 		if ((i & lockmask) > m)
544 			m = *mp++ = (i & lockmask);
545 	}
546 	*mp = 0;
547 }
548 
549 /****************************************************************************
550  * Pan Frames : windows for edge-scrolling
551  * the root window is surrounded by four window slices, which are InputOnly.
552  * So you can see 'through' them, but they eat the input. An EnterEvent in
553  * one of these windows causes a Paging. The windows have the according cursor
554  * pointing in the pan direction or are hidden if there is no more panning
555  * in that direction. This is mostly intended to get a panning even atop
556  * of Motif applictions, which does not work yet. It seems Motif windows
557  * eat all mouse events.
558  *
559  * Hermann Dunkel, HEDU, dunkel@cul-ipn.uni-kiel.de 1/94
560  ****************************************************************************/
init_screen_panframes(ScreenInfo * scr)561 void init_screen_panframes (ScreenInfo * scr)
562 {
563 #ifndef NO_VIRTUAL
564 	XRectangle frame_rects[PAN_FRAME_SIDES];
565 
566 	XSetWindowAttributes attributes;	/* attributes for create */
567 	register int i;
568 
569 	if (scr == NULL)
570 		scr = ASDefaultScr;
571 
572 	frame_rects[0].x = frame_rects[0].y = 0;
573 	frame_rects[0].width = scr->MyDisplayWidth;
574 	frame_rects[0].height = SCROLL_REGION;
575 
576 	frame_rects[1].x = scr->MyDisplayWidth - SCROLL_REGION;
577 	frame_rects[1].y = SCROLL_REGION;
578 	frame_rects[1].width = SCROLL_REGION;
579 	frame_rects[1].height = scr->MyDisplayHeight - 2 * SCROLL_REGION;
580 
581 	frame_rects[2].x = 0;
582 	frame_rects[2].y = scr->MyDisplayHeight - SCROLL_REGION;
583 	frame_rects[2].width = scr->MyDisplayWidth;
584 	frame_rects[2].height = SCROLL_REGION;
585 
586 	frame_rects[3].x = 0;
587 	frame_rects[3].y = SCROLL_REGION;
588 	frame_rects[3].width = SCROLL_REGION;
589 	frame_rects[3].height = scr->MyDisplayHeight - 2 * SCROLL_REGION;
590 
591 	frame_rects[2].width = frame_rects[0].width = scr->MyDisplayWidth;
592 	frame_rects[1].x = scr->MyDisplayWidth - SCROLL_REGION;
593 	frame_rects[3].height = frame_rects[1].height =
594 			scr->MyDisplayHeight - (SCROLL_REGION * 2);
595 
596 	attributes.event_mask = AS_PANFRAME_EVENT_MASK;
597 	for (i = 0; i < PAN_FRAME_SIDES; i++) {
598 		scr->PanFrame[i].win = create_screen_window (scr, None, frame_rects[i].x, frame_rects[i].y, frame_rects[i].width, frame_rects[i].height, 0,	/* no border */
599 																								 InputOnly, (CWEventMask),
600 																								 &attributes);
601 		LOCAL_DEBUG_OUT ("creating PanFrame %d(%lX) at %dx%d%+d%+d", i,
602 										 scr->PanFrame[i].win, frame_rects[i].width,
603 										 frame_rects[i].height, frame_rects[i].x,
604 										 frame_rects[i].y);
605 		scr->PanFrame[i].isMapped = False;
606 	}
607 #endif													/* NO_VIRTUAL */
608 }
609 
610 /***************************************************************************
611  * checkPanFrames hides PanFrames if they are on the very border of the
612  * VIRTUELL screen and EdgeWrap for that direction is off.
613  * (A special cursor for the EdgeWrap border could be nice) HEDU
614  ****************************************************************************/
check_screen_panframes(ScreenInfo * scr)615 void check_screen_panframes (ScreenInfo * scr)
616 {
617 #ifndef NO_VIRTUAL
618 	int wrapX;
619 	int wrapY;
620 	Bool map_frame[PAN_FRAME_SIDES] = { False, False, False, False };
621 	register int i;
622 
623 	if (scr == NULL)
624 		scr = ASDefaultScr;
625 
626 	wrapX = get_flags (scr->Feel.flags, EdgeWrapX);
627 	wrapY = get_flags (scr->Feel.flags, EdgeWrapY);
628 
629 	if (get_flags (scr->Feel.flags, DoHandlePageing)) {
630 		if (scr->Feel.EdgeScrollY > 0) {
631 			if (scr->Vy > 0 || wrapY)
632 				map_frame[FR_N] = True;
633 			if (scr->Vy < scr->VyMax || wrapY)
634 				map_frame[FR_S] = True;
635 		}
636 		if (scr->Feel.EdgeScrollX > 0) {
637 			if (scr->Vx < scr->VxMax || wrapX)
638 				map_frame[FR_E] = True;
639 			if (scr->Vx > 0 || wrapX)
640 				map_frame[FR_W] = True;
641 		}
642 	}
643 	/* Remove Pan frames if paging by edge-scroll is permanently or
644 	 * temporarily disabled */
645 	for (i = 0; i < PAN_FRAME_SIDES; i++) {
646 		if (scr->PanFrame[i].win) {
647 			if (map_frame[i] != scr->PanFrame[i].isMapped) {
648 				if (map_frame[i]) {
649 					LOCAL_DEBUG_OUT ("mapping PanFrame %d(%lX)", i,
650 													 scr->PanFrame[i].win);
651 					XMapRaised (dpy, scr->PanFrame[i].win);
652 				} else
653 					XUnmapWindow (dpy, scr->PanFrame[i].win);
654 				scr->PanFrame[i].isMapped = map_frame[i];
655 			}
656 
657 			if (map_frame[i]) {
658 				/* to maintain stacking order where first mapped pan frame is the lowest window : */
659 				LOCAL_DEBUG_OUT ("rasing PanFrame %d(%lX)", i,
660 												 scr->PanFrame[i].win);
661 				XRaiseWindow (dpy, scr->PanFrame[i].win);
662 				XDefineCursor (dpy, scr->PanFrame[i].win,
663 											 scr->Feel.cursors[ASCUR_Top + i]);
664 			}
665 		}
666 	}
667 #endif
668 }
669 
670 /****************************************************************************
671  * Gotta make sure these things are on top of everything else, or they
672  * don't work!
673  ***************************************************************************/
raise_scren_panframes(ScreenInfo * scr)674 void raise_scren_panframes (ScreenInfo * scr)
675 {
676 #ifndef NO_VIRTUAL
677 	register int i;
678 
679 	if (scr == NULL)
680 		scr = ASDefaultScr;
681 	for (i = 0; i < PAN_FRAME_SIDES; i++)
682 		if (scr->PanFrame[i].isMapped) {
683 			LOCAL_DEBUG_OUT ("rasing PanFrame %d(%lX)", i, scr->PanFrame[i].win);
684 			XRaiseWindow (dpy, scr->PanFrame[i].win);
685 		}
686 #endif
687 }
688 
get_lowest_panframe(ScreenInfo * scr)689 Window get_lowest_panframe (ScreenInfo * scr)
690 {
691 	register int i;
692 
693 	if (scr == NULL)
694 		scr = ASDefaultScr;
695 	for (i = 0; i < PAN_FRAME_SIDES; i++)
696 		if (scr->PanFrame[i].isMapped)
697 			return scr->PanFrame[i].win;
698 	return None;
699 }
700 
701 /* utility function for geometry merging : */
merge_geometry(ASGeometry * from,ASGeometry * to)702 void merge_geometry (ASGeometry * from, ASGeometry * to)
703 {
704 	if (get_flags (from->flags, WidthValue))
705 		to->width = from->width;
706 	if (get_flags (from->flags, HeightValue))
707 		to->height = from->height;
708 	if (get_flags (from->flags, XValue)) {
709 		to->x = from->x;
710 		if (!get_flags (from->flags, XNegative))
711 			clear_flags (to->flags, XNegative);
712 	}
713 	if (get_flags (from->flags, YValue)) {
714 		to->y = from->y;
715 		if (!get_flags (from->flags, YNegative))
716 			clear_flags (to->flags, YNegative);
717 	}
718 	to->flags |= from->flags;
719 }
720 
check_desksize_sanity(ScreenInfo * scr)721 void check_desksize_sanity (ScreenInfo * scr)
722 {
723 	if (scr == NULL)
724 		scr = ASDefaultScr;
725 
726 	if (scr->VxMax <= 0)
727 		scr->VxMax = 0;
728 	else if (scr->VxMax < 32000 / scr->MyDisplayWidth)
729 		scr->VxMax = (scr->VxMax * scr->MyDisplayWidth) - scr->MyDisplayWidth;
730 
731 	if (scr->VyMax <= 0)
732 		scr->VyMax = 0;
733 	else if (scr->VyMax < 32000 / scr->MyDisplayHeight)
734 		scr->VyMax =
735 				(scr->VyMax * scr->MyDisplayHeight) - scr->MyDisplayHeight;
736 }
737