17d8a9cc2Snia/*
27d8a9cc2Snia *       Copyright 1988 by Evans & Sutherland Computer Corporation,
37d8a9cc2Snia *                          Salt Lake City, Utah
47d8a9cc2Snia *  Portions Copyright 1989 by the Massachusetts Institute of Technology
57d8a9cc2Snia *                        Cambridge, Massachusetts
6645f5050Syouri *
77d8a9cc2Snia * Copyright 1992 Claude Lecommandeur.
8645f5050Syouri */
9645f5050Syouri
10645f5050Syouri/***********************************************************************
11645f5050Syouri *
12645f5050Syouri * $XConsortium: util.c,v 1.47 91/07/14 13:40:37 rws Exp $
13645f5050Syouri *
14645f5050Syouri * utility routines for twm
15645f5050Syouri *
167d8a9cc2Snia * 28-Oct-87 Thomas E. LaStrange        File created
17645f5050Syouri *
18645f5050Syouri * Do the necessary modification to be integrated in ctwm.
19645f5050Syouri * Can no longer be used for the standard twm.
20645f5050Syouri *
21645f5050Syouri * 22-April-92 Claude Lecommandeur.
22645f5050Syouri *
23645f5050Syouri * Changed behavior of DontMoveOff/MoveOffResistance to allow
24645f5050Syouri * moving a window off screen less than #MoveOffResistance pixels.
25645f5050Syouri * New code will no longer "snap" windows to #MoveOffResistance
26645f5050Syouri * pixels off screen and instead movements will just be stopped and
27645f5050Syouri * then resume once movement of #MoveOffResistance have been attempted.
28645f5050Syouri *
297d8a9cc2Snia * 15-December-02 Bjorn Knutsson
30645f5050Syouri *
31645f5050Syouri ***********************************************************************/
32645f5050Syouri
337d8a9cc2Snia#include "ctwm.h"
34645f5050Syouri
35645f5050Syouri#include <stdio.h>
367d8a9cc2Snia#include <stdlib.h>
377d8a9cc2Snia#include <string.h>
387d8a9cc2Snia#include <strings.h>
39645f5050Syouri
40645f5050Syouri#include <signal.h>
41645f5050Syouri#include <sys/time.h>
42645f5050Syouri
437d8a9cc2Snia#include "animate.h"
447d8a9cc2Snia#include "add_window.h"
457d8a9cc2Snia#include "cursor.h"
467d8a9cc2Snia#include "drawing.h"
477d8a9cc2Snia#include "gram.tab.h"
487d8a9cc2Snia#include "iconmgr.h"
497d8a9cc2Snia#include "icons.h"
507d8a9cc2Snia#include "image.h"
517d8a9cc2Snia#include "screen.h"
527d8a9cc2Snia#include "util.h"
537d8a9cc2Snia#include "vscreen.h"
547d8a9cc2Snia#include "win_decorations.h"
557d8a9cc2Snia#include "win_resize.h"
56645f5050Syouri
57645f5050Syouri
587d8a9cc2Snia/* Handle for debug tracing */
597d8a9cc2SniaFILE *tracefile = NULL;
60645f5050Syouri
61645f5050Syouri
627d8a9cc2Snia/*
637d8a9cc2Snia * Rewrite this, possibly in terms of replace_substr().  Alternately, the
647d8a9cc2Snia * places it's being used might be better served by being preprocessed
657d8a9cc2Snia * into arrays anyway.
66645f5050Syouri */
677d8a9cc2Sniachar *ExpandFilePath(char *path)
68645f5050Syouri{
697d8a9cc2Snia	char *ret, *colon, *p;
707d8a9cc2Snia	int  len;
71645f5050Syouri
727d8a9cc2Snia	len = 0;
737d8a9cc2Snia	p   = path;
747d8a9cc2Snia	while((colon = strchr(p, ':'))) {
757d8a9cc2Snia		len += colon - p + 1;
767d8a9cc2Snia		if(*p == '~') {
777d8a9cc2Snia			len += HomeLen - 1;
787d8a9cc2Snia		}
797d8a9cc2Snia		p = colon + 1;
80645f5050Syouri	}
817d8a9cc2Snia	if(*p == '~') {
827d8a9cc2Snia		len += HomeLen - 1;
83645f5050Syouri	}
847d8a9cc2Snia	len += strlen(p);
857d8a9cc2Snia	ret = malloc(len + 1);
867d8a9cc2Snia	*ret = 0;
87645f5050Syouri
887d8a9cc2Snia	p   = path;
897d8a9cc2Snia	while((colon = strchr(p, ':'))) {
907d8a9cc2Snia		*colon = '\0';
917d8a9cc2Snia		if(*p == '~') {
927d8a9cc2Snia			strcat(ret, Home);
937d8a9cc2Snia			strcat(ret, p + 1);
947d8a9cc2Snia		}
957d8a9cc2Snia		else {
967d8a9cc2Snia			strcat(ret, p);
977d8a9cc2Snia		}
987d8a9cc2Snia		*colon = ':';
997d8a9cc2Snia		strcat(ret, ":");
1007d8a9cc2Snia		p = colon + 1;
101645f5050Syouri	}
1027d8a9cc2Snia	if(*p == '~') {
1037d8a9cc2Snia		strcat(ret, Home);
1047d8a9cc2Snia		strcat(ret, p + 1);
105645f5050Syouri	}
1067d8a9cc2Snia	else {
1077d8a9cc2Snia		strcat(ret, p);
1087d8a9cc2Snia	}
1097d8a9cc2Snia	return ret;
110645f5050Syouri}
111645f5050Syouri
112645f5050Syouri/***********************************************************************
113645f5050Syouri *
114645f5050Syouri *  Procedure:
1157d8a9cc2Snia *      ExpandFilename - expand the tilde character to HOME
1167d8a9cc2Snia *              if it is the first character of the filename
117645f5050Syouri *
118645f5050Syouri *  Returned Value:
1197d8a9cc2Snia *      a pointer to the new name
120645f5050Syouri *
121645f5050Syouri *  Inputs:
1227d8a9cc2Snia *      name    - the filename to expand
123645f5050Syouri *
124645f5050Syouri ***********************************************************************
1257d8a9cc2Snia *
1267d8a9cc2Snia * Currently only used in one place in image_bitmap.c.  I've left this
1277d8a9cc2Snia * here instead of moving it into images at the moment on the assumption
1287d8a9cc2Snia * that there might be other places in the codebase where it's useful.
129645f5050Syouri */
1307d8a9cc2Sniachar *
1317d8a9cc2SniaExpandFilename(const char *name)
132645f5050Syouri{
1337d8a9cc2Snia	char *newname;
134645f5050Syouri
1357d8a9cc2Snia	/* If it doesn't start with ~/ then it's not our concern */
1367d8a9cc2Snia	if(name[0] != '~' || name[1] != '/') {
1377d8a9cc2Snia		return strdup(name);
138645f5050Syouri	}
139645f5050Syouri
1407d8a9cc2Snia	asprintf(&newname, "%s/%s", Home, &name[1]);
141645f5050Syouri
1427d8a9cc2Snia	return newname;
143645f5050Syouri}
144645f5050Syouri
145645f5050Syouri
146df1c27a6Snia
147df1c27a6Snia/*
148df1c27a6Snia * Some color utils
149df1c27a6Snia */
150df1c27a6Snia/**
151df1c27a6Snia * Get info from the server about a given color.
152df1c27a6Snia */
1537d8a9cc2Sniavoid
1547d8a9cc2SniaGetColor(int kind, Pixel *what, const char *name)
155645f5050Syouri{
1567d8a9cc2Snia	XColor color;
1577d8a9cc2Snia	Colormap cmap = Scr->RootColormaps.cwins[0]->colormap->c;
158645f5050Syouri
159df1c27a6Snia	// If we have no valid X connection (generally means a --cfgchk or
160df1c27a6Snia	// similar run; wont' happen in normal operations), just stub out.
161df1c27a6Snia	if(dpy == NULL) {
162df1c27a6Snia		*what = 0;
163df1c27a6Snia		return;
164df1c27a6Snia	}
165df1c27a6Snia
1667d8a9cc2Snia#ifndef TOM
1677d8a9cc2Snia	if(!Scr->FirstTime) {
1687d8a9cc2Snia		return;
169645f5050Syouri	}
1708ae3b938Sjmcneill#endif
171645f5050Syouri
1727d8a9cc2Snia	if(Scr->Monochrome != kind) {
1737d8a9cc2Snia		return;
174645f5050Syouri	}
175645f5050Syouri
1767d8a9cc2Snia	if(! XParseColor(dpy, cmap, name, &color)) {
1777d8a9cc2Snia		fprintf(stderr, "%s:  invalid color name \"%s\"\n", ProgramName, name);
1787d8a9cc2Snia		return;
179645f5050Syouri	}
1807d8a9cc2Snia	if(! XAllocColor(dpy, cmap, &color)) {
1817d8a9cc2Snia		/* if we could not allocate the color, let's see if this is a
1827d8a9cc2Snia		 * standard colormap
1837d8a9cc2Snia		 */
1847d8a9cc2Snia		XStandardColormap *stdcmap = NULL;
185645f5050Syouri
1867d8a9cc2Snia		if(! XParseColor(dpy, cmap, name, &color)) {
1877d8a9cc2Snia			fprintf(stderr, "%s:  invalid color name \"%s\"\n", ProgramName, name);
1887d8a9cc2Snia			return;
1897d8a9cc2Snia		}
190645f5050Syouri
1917d8a9cc2Snia		/*
1927d8a9cc2Snia		 * look through the list of standard colormaps (check cache first)
1937d8a9cc2Snia		 */
1947d8a9cc2Snia		if(Scr->StdCmapInfo.mru && Scr->StdCmapInfo.mru->maps &&
1957d8a9cc2Snia		                (Scr->StdCmapInfo.mru->maps[Scr->StdCmapInfo.mruindex].colormap ==
1967d8a9cc2Snia		                 cmap)) {
1977d8a9cc2Snia			stdcmap = &(Scr->StdCmapInfo.mru->maps[Scr->StdCmapInfo.mruindex]);
1987d8a9cc2Snia		}
1997d8a9cc2Snia		else {
2007d8a9cc2Snia			StdCmap *sc;
2017d8a9cc2Snia
2027d8a9cc2Snia			for(sc = Scr->StdCmapInfo.head; sc; sc = sc->next) {
2037d8a9cc2Snia				int i;
2047d8a9cc2Snia
2057d8a9cc2Snia				for(i = 0; i < sc->nmaps; i++) {
2067d8a9cc2Snia					if(sc->maps[i].colormap == cmap) {
2077d8a9cc2Snia						Scr->StdCmapInfo.mru = sc;
2087d8a9cc2Snia						Scr->StdCmapInfo.mruindex = i;
2097d8a9cc2Snia						stdcmap = &(sc->maps[i]);
2107d8a9cc2Snia						goto gotit;
2117d8a9cc2Snia					}
2127d8a9cc2Snia				}
2137d8a9cc2Snia			}
2147d8a9cc2Snia		}
215645f5050Syouri
2167d8a9cc2Sniagotit:
2177d8a9cc2Snia		if(stdcmap) {
2187d8a9cc2Snia			color.pixel = (stdcmap->base_pixel +
2197d8a9cc2Snia			               ((Pixel)(((float)color.red / 65535.0) *
2207d8a9cc2Snia			                        stdcmap->red_max + 0.5) *
2217d8a9cc2Snia			                stdcmap->red_mult) +
2227d8a9cc2Snia			               ((Pixel)(((float)color.green / 65535.0) *
2237d8a9cc2Snia			                        stdcmap->green_max + 0.5) *
2247d8a9cc2Snia			                stdcmap->green_mult) +
2257d8a9cc2Snia			               ((Pixel)(((float)color.blue  / 65535.0) *
2267d8a9cc2Snia			                        stdcmap->blue_max + 0.5) *
2277d8a9cc2Snia			                stdcmap->blue_mult));
2287d8a9cc2Snia		}
2297d8a9cc2Snia		else {
2307d8a9cc2Snia			fprintf(stderr, "%s:  unable to allocate color \"%s\"\n",
2317d8a9cc2Snia			        ProgramName, name);
2327d8a9cc2Snia			return;
2337d8a9cc2Snia		}
234645f5050Syouri	}
235645f5050Syouri
2367d8a9cc2Snia	*what = color.pixel;
2377d8a9cc2Snia	return;
238645f5050Syouri}
239645f5050Syouri
240df1c27a6Snia
241df1c27a6Snia/**
242df1c27a6Snia * Try and create a 'shaded' version of a color for prettier UI.
243df1c27a6Snia */
244df1c27a6Sniavoid
245df1c27a6SniaGetShadeColors(ColorPair *cp)
246645f5050Syouri{
2477d8a9cc2Snia	XColor      xcol;
2487d8a9cc2Snia	Colormap    cmap = Scr->RootColormaps.cwins[0]->colormap->c;
2497d8a9cc2Snia	bool        save;
2507d8a9cc2Snia	float       clearfactor;
2517d8a9cc2Snia	float       darkfactor;
2527d8a9cc2Snia	char        clearcol [32], darkcol [32];
253645f5050Syouri
254df1c27a6Snia	// If we have no valid X connection (generally means a --cfgchk or
255df1c27a6Snia	// similar run; wont' happen in normal operations), just stub out.
256df1c27a6Snia	if(dpy == NULL) {
257df1c27a6Snia		cp->shadc = 0;
258df1c27a6Snia		cp->shadd = 0;
259df1c27a6Snia		return;
260df1c27a6Snia	}
261df1c27a6Snia
2627d8a9cc2Snia	clearfactor = (float) Scr->ClearShadowContrast / 100.0;
2637d8a9cc2Snia	darkfactor  = (100.0 - (float) Scr->DarkShadowContrast)  / 100.0;
2647d8a9cc2Snia	xcol.pixel = cp->back;
2657d8a9cc2Snia	XQueryColor(dpy, cmap, &xcol);
266645f5050Syouri
2677d8a9cc2Snia	sprintf(clearcol, "#%04x%04x%04x",
2687d8a9cc2Snia	        xcol.red   + (unsigned short)((65535 -   xcol.red) * clearfactor),
2697d8a9cc2Snia	        xcol.green + (unsigned short)((65535 - xcol.green) * clearfactor),
2707d8a9cc2Snia	        xcol.blue  + (unsigned short)((65535 -  xcol.blue) * clearfactor));
2717d8a9cc2Snia	sprintf(darkcol,  "#%04x%04x%04x",
2727d8a9cc2Snia	        (unsigned short)(xcol.red   * darkfactor),
2737d8a9cc2Snia	        (unsigned short)(xcol.green * darkfactor),
2747d8a9cc2Snia	        (unsigned short)(xcol.blue  * darkfactor));
275645f5050Syouri
2767d8a9cc2Snia	save = Scr->FirstTime;
2777d8a9cc2Snia	Scr->FirstTime = true;
2787d8a9cc2Snia	GetColor(Scr->Monochrome, &cp->shadc, clearcol);
2797d8a9cc2Snia	GetColor(Scr->Monochrome, &cp->shadd,  darkcol);
2807d8a9cc2Snia	Scr->FirstTime = save;
281645f5050Syouri}
282645f5050Syouri
283df1c27a6Snia
284df1c27a6Snia
285df1c27a6Snia/*
286df1c27a6Snia * Various font utils
287df1c27a6Snia */
288df1c27a6Snia/**
289df1c27a6Snia * Try adjusting a font's height.  Used in drawing the icon manager.
290df1c27a6Snia */
2917d8a9cc2Sniabool
2927d8a9cc2SniaUpdateFont(MyFont *font, int height)
293645f5050Syouri{
2947d8a9cc2Snia	int prev = font->avg_height;
2957d8a9cc2Snia	font->avg_fheight = (font->avg_fheight * font->avg_count + height)
2967d8a9cc2Snia	                    / (font->avg_count + 1);
2977d8a9cc2Snia	font->avg_count++;
2987d8a9cc2Snia	/* Arbitrary limit.  */
2997d8a9cc2Snia	if(font->avg_count >= 256) {
3007d8a9cc2Snia		font->avg_count = 256;
3017d8a9cc2Snia	}
3027d8a9cc2Snia	font->avg_height = (int)(font->avg_fheight + 0.5);
3037d8a9cc2Snia	/* fprintf (stderr, "Updating avg with %d(%d) + %d -> %d(%f)\n",
3047d8a9cc2Snia	 *       prev, font->avg_count, height,
3057d8a9cc2Snia	 *       font->avg_height, font->avg_fheight); */
3067d8a9cc2Snia	return (prev != font->avg_height);
307645f5050Syouri}
308645f5050Syouri
309df1c27a6Snia
310df1c27a6Snia/**
311df1c27a6Snia * Load up fontsets from the X server.  Only used by CreateFonts() below.
312df1c27a6Snia */
313df1c27a6Sniastatic void
314df1c27a6SniaGetFont(MyFont *font)
315645f5050Syouri{
3167d8a9cc2Snia	char *deffontname = "fixed,*";
3177d8a9cc2Snia	char **missing_charset_list_return;
3187d8a9cc2Snia	int missing_charset_count_return;
3197d8a9cc2Snia	char *def_string_return;
3207d8a9cc2Snia	XFontSetExtents *font_extents;
3217d8a9cc2Snia	XFontStruct **xfonts;
3227d8a9cc2Snia	char **font_names;
3237d8a9cc2Snia	int i;
3247d8a9cc2Snia	int ascent;
3257d8a9cc2Snia	int descent;
3267d8a9cc2Snia	int fnum;
3277d8a9cc2Snia	char *basename2;
3287d8a9cc2Snia
329df1c27a6Snia	// In special cases where we have no dpy, I don't think we're going
330df1c27a6Snia	// to need details here, so just leave things untouched.  We may need
331df1c27a6Snia	// to stub in some magic values; deal with that when we run into the
332df1c27a6Snia	// case.
333df1c27a6Snia	if(dpy == NULL) {
334df1c27a6Snia		return;
335df1c27a6Snia	}
336df1c27a6Snia
3377d8a9cc2Snia	if(font->font_set != NULL) {
3387d8a9cc2Snia		XFreeFontSet(dpy, font->font_set);
3397d8a9cc2Snia	}
3407d8a9cc2Snia
3417d8a9cc2Snia	asprintf(&basename2, "%s,*", font->basename);
3427d8a9cc2Snia	if((font->font_set = XCreateFontSet(dpy, basename2,
3437d8a9cc2Snia	                                    &missing_charset_list_return,
3447d8a9cc2Snia	                                    &missing_charset_count_return,
3457d8a9cc2Snia	                                    &def_string_return)) == NULL) {
3467d8a9cc2Snia		fprintf(stderr, "Failed to get fontset %s\n", basename2);
3477d8a9cc2Snia		if(Scr->DefaultFont.basename) {
3487d8a9cc2Snia			deffontname = Scr->DefaultFont.basename;
3497d8a9cc2Snia		}
3507d8a9cc2Snia		if((font->font_set = XCreateFontSet(dpy, deffontname,
3517d8a9cc2Snia		                                    &missing_charset_list_return,
3527d8a9cc2Snia		                                    &missing_charset_count_return,
3537d8a9cc2Snia		                                    &def_string_return)) == NULL) {
3547d8a9cc2Snia			fprintf(stderr, "%s:  unable to open fonts \"%s\" or \"%s\"\n",
3557d8a9cc2Snia			        ProgramName, font->basename, deffontname);
3567d8a9cc2Snia			exit(1);
3577d8a9cc2Snia		}
3587d8a9cc2Snia	}
3597d8a9cc2Snia	free(basename2);
3607d8a9cc2Snia	font_extents = XExtentsOfFontSet(font->font_set);
361645f5050Syouri
3627d8a9cc2Snia	fnum = XFontsOfFontSet(font->font_set, &xfonts, &font_names);
3637d8a9cc2Snia	for(i = 0, ascent = 0, descent = 0; i < fnum; i++) {
3647d8a9cc2Snia		ascent = MaxSize(ascent, (*xfonts)->ascent);
3657d8a9cc2Snia		descent = MaxSize(descent, (*xfonts)->descent);
3667d8a9cc2Snia		xfonts++;
3677d8a9cc2Snia	}
368645f5050Syouri
3697d8a9cc2Snia	font->height = font_extents->max_logical_extent.height;
3707d8a9cc2Snia	font->y = ascent;
3717d8a9cc2Snia	font->ascent = ascent;
3727d8a9cc2Snia	font->descent = descent;
3737d8a9cc2Snia	font->avg_height = 0;
3747d8a9cc2Snia	font->avg_fheight = 0.0;
3757d8a9cc2Snia	font->avg_count = 0;
376645f5050Syouri}
377645f5050Syouri
378645f5050Syouri
379df1c27a6Snia/**
380df1c27a6Snia * Load up our various defined fonts
381df1c27a6Snia */
382df1c27a6Sniavoid
383df1c27a6SniaCreateFonts(ScreenInfo *scr)
384df1c27a6Snia{
385df1c27a6Snia#define LOADFONT(fld) (GetFont(&scr->fld##Font))
386df1c27a6Snia	LOADFONT(TitleBar);
387df1c27a6Snia	LOADFONT(Menu);
388df1c27a6Snia	LOADFONT(Icon);
389df1c27a6Snia	LOADFONT(Size);
390df1c27a6Snia	LOADFONT(IconManager);
391df1c27a6Snia	LOADFONT(Default);
392df1c27a6Snia	LOADFONT(workSpaceMgr.window);
393df1c27a6Snia#undef LOADFONT
394df1c27a6Snia
395df1c27a6Snia	scr->HaveFonts = true;
396df1c27a6Snia}
397df1c27a6Snia
398df1c27a6Snia
399df1c27a6Snia
4007d8a9cc2Snia#if 0
4017d8a9cc2Sniastatic void move_to_head(TwmWindow *t)
402645f5050Syouri{
4037d8a9cc2Snia	if(t == NULL) {
4047d8a9cc2Snia		return;
4057d8a9cc2Snia	}
4067d8a9cc2Snia	if(Scr->FirstWindow == t) {
4077d8a9cc2Snia		return;
4087d8a9cc2Snia	}
409645f5050Syouri
4107d8a9cc2Snia	/* Unlink t from current position */
4117d8a9cc2Snia	if(t->prev) {
4127d8a9cc2Snia		t->prev->next = t->next;
4137d8a9cc2Snia	}
4147d8a9cc2Snia	if(t->next) {
4157d8a9cc2Snia		t->next->prev = t->prev;
4167d8a9cc2Snia	}
417645f5050Syouri
4187d8a9cc2Snia	/* Re-link t at head */
4197d8a9cc2Snia	t->next = Scr->FirstWindow;
4207d8a9cc2Snia	if(Scr->FirstWindow != NULL) {
4217d8a9cc2Snia		Scr->FirstWindow->prev = t;
4227d8a9cc2Snia	}
4237d8a9cc2Snia	t->prev = NULL;
4247d8a9cc2Snia	Scr->FirstWindow = t;
425645f5050Syouri}
426645f5050Syouri
4277d8a9cc2Snia/*
4287d8a9cc2Snia * Moves window 't' after window 'after'.
4297d8a9cc2Snia *
4307d8a9cc2Snia * If 'after' == NULL, puts it at the head.
4317d8a9cc2Snia * If 't' == NULL, does nothing.
4327d8a9cc2Snia * If the 't' is already after 'after', does nothing.
4337d8a9cc2Snia */
434645f5050Syouri
4357d8a9cc2Sniavoid move_to_after(TwmWindow *t, TwmWindow *after)
4367d8a9cc2Snia{
4377d8a9cc2Snia	if(after == NULL) {
4387d8a9cc2Snia		move_to_head(t);
4397d8a9cc2Snia		return;
4407d8a9cc2Snia	}
4417d8a9cc2Snia	if(t == NULL) {
4427d8a9cc2Snia		return;
4437d8a9cc2Snia	}
4447d8a9cc2Snia	if(after->next == t) {
4457d8a9cc2Snia		return;
4467d8a9cc2Snia	}
4477d8a9cc2Snia
4487d8a9cc2Snia	/* Unlink t from current position */
4497d8a9cc2Snia	if(t->prev) {
4507d8a9cc2Snia		t->prev->next = t->next;
4517d8a9cc2Snia	}
4527d8a9cc2Snia	if(t->next) {
4537d8a9cc2Snia		t->next->prev = t->prev;
4547d8a9cc2Snia	}
4557d8a9cc2Snia
4567d8a9cc2Snia	/* Re-link t after 'after' */
4577d8a9cc2Snia	t->next = after->next;
4587d8a9cc2Snia	if(after->next) {
4597d8a9cc2Snia		after->next->prev = t;
4607d8a9cc2Snia	}
4617d8a9cc2Snia	t->prev = after;
4627d8a9cc2Snia	after->next = t;
4637d8a9cc2Snia}
4647d8a9cc2Snia#endif
4657d8a9cc2Snia
4667d8a9cc2Snia
467df1c27a6Snia
468df1c27a6Snia/**
469df1c27a6Snia * Backend for f.rescuewindows
470df1c27a6Snia */
4717d8a9cc2Sniavoid RescueWindows(void)
4727d8a9cc2Snia{
4737d8a9cc2Snia	TwmWindow *twm_win = Scr->FirstWindow;
4747d8a9cc2Snia
4757d8a9cc2Snia	while(twm_win) {
4767d8a9cc2Snia		VirtualScreen *vs = twm_win->vs;
4777d8a9cc2Snia		if(vs) {
4787d8a9cc2Snia			/*
4797d8a9cc2Snia			 * Check if this window seems completely out of sight.
4807d8a9cc2Snia			 */
4817d8a9cc2Snia			int x = twm_win->frame_x;
4827d8a9cc2Snia			int y = twm_win->frame_y;
4837d8a9cc2Snia			int w = twm_win->frame_width;
4847d8a9cc2Snia			int h = twm_win->frame_height;
4857d8a9cc2Snia			int bw = twm_win->frame_bw;
4867d8a9cc2Snia			int fullw = w + 2 * bw;
4877d8a9cc2Snia			int fullh = h + 2 * bw;
4887d8a9cc2Snia			int old_x = x, old_y = y;
4897d8a9cc2Snia			struct Icon *i;
4907d8a9cc2Snia
4917d8a9cc2Snia#define MARGIN  20
4927d8a9cc2Snia
4937d8a9cc2Snia			if(x >= vs->w - MARGIN) {
4947d8a9cc2Snia				x = vs->w - fullw;
4957d8a9cc2Snia			}
4967d8a9cc2Snia			if(y >= vs->h - MARGIN) {
4977d8a9cc2Snia				y = vs->h - fullh;
4987d8a9cc2Snia			}
4997d8a9cc2Snia			if((x + fullw <= MARGIN)) {
5007d8a9cc2Snia				x = 0;
5017d8a9cc2Snia			}
5027d8a9cc2Snia			if((y + fullh <= MARGIN)) {
5037d8a9cc2Snia				y = 0;
5047d8a9cc2Snia			}
5057d8a9cc2Snia
5067d8a9cc2Snia			if(x != old_x || y != old_y) {
5077d8a9cc2Snia				SetupWindow(twm_win, x, y, w, h, -1);
5087d8a9cc2Snia			}
5097d8a9cc2Snia
5107d8a9cc2Snia			/*
5117d8a9cc2Snia			 * If there is an icon, check it too.
5127d8a9cc2Snia			 */
5137d8a9cc2Snia			i = twm_win->icon;
5147d8a9cc2Snia			if(i != NULL) {
5157d8a9cc2Snia				x = i->w_x;
5167d8a9cc2Snia				y = i->w_y;
5177d8a9cc2Snia				w = i->w_width;
5187d8a9cc2Snia				h = i->w_height;
5197d8a9cc2Snia				old_x = x;
5207d8a9cc2Snia				old_y = y;
5217d8a9cc2Snia
5227d8a9cc2Snia				if(x >= vs->w - MARGIN) {
5237d8a9cc2Snia					x = vs->w - w;
5247d8a9cc2Snia				}
5257d8a9cc2Snia				if(y >= vs->h - MARGIN) {
5267d8a9cc2Snia					y = vs->h - h;
5277d8a9cc2Snia				}
5287d8a9cc2Snia				if((x + w <= MARGIN)) {
5297d8a9cc2Snia					x = 0;
5307d8a9cc2Snia				}
5317d8a9cc2Snia				if((y + h <= MARGIN)) {
5327d8a9cc2Snia					y = 0;
5337d8a9cc2Snia				}
5347d8a9cc2Snia
5357d8a9cc2Snia				if(x != old_x || y != old_y) {
5367d8a9cc2Snia					XMoveWindow(dpy, i->w, x, y);
5377d8a9cc2Snia					i->w_x = x;
5387d8a9cc2Snia					i->w_y = y;
5397d8a9cc2Snia				}
5407d8a9cc2Snia			}
5417d8a9cc2Snia#undef MARGIN
5427d8a9cc2Snia		}
5437d8a9cc2Snia		twm_win = twm_win->next;
5447d8a9cc2Snia	}
545645f5050Syouri}
546645f5050Syouri
547df1c27a6Snia
548df1c27a6Snia
549df1c27a6Snia/**
550df1c27a6Snia * Backend for f.trace
551df1c27a6Snia */
552df1c27a6Sniavoid
553df1c27a6SniaDebugTrace(char *file)
554645f5050Syouri{
5557d8a9cc2Snia	if(!file) {
5567d8a9cc2Snia		return;
5577d8a9cc2Snia	}
5587d8a9cc2Snia	if(tracefile) {
5597d8a9cc2Snia		fprintf(stderr, "stop logging events\n");
5607d8a9cc2Snia		if(tracefile != stderr) {
5617d8a9cc2Snia			fclose(tracefile);
5627d8a9cc2Snia		}
5637d8a9cc2Snia		tracefile = NULL;
5647d8a9cc2Snia	}
5657d8a9cc2Snia	else {
5667d8a9cc2Snia		if(strcmp(file, "stderr")) {
5677d8a9cc2Snia			tracefile = fopen(file, "w");
5687d8a9cc2Snia		}
5697d8a9cc2Snia		else {
5707d8a9cc2Snia			tracefile = stderr;
5717d8a9cc2Snia		}
5727d8a9cc2Snia		fprintf(stderr, "logging events to : %s\n", file);
5737d8a9cc2Snia	}
574645f5050Syouri}
575645f5050Syouri
576645f5050Syouri
577df1c27a6Snia
5787d8a9cc2Snia/*
5797d8a9cc2Snia * A safe strncpy(), which always ensures NUL-termination.
5807d8a9cc2Snia *
5817d8a9cc2Snia * XXX This is really just a slightly pessimized implementation of
5827d8a9cc2Snia * strlcpy().  Maybe we should use that instead, with a local
5837d8a9cc2Snia * implementation for systems like glibc-users that lack it?
5847d8a9cc2Snia */
5857d8a9cc2Sniavoid
5867d8a9cc2Sniasafe_strncpy(char *dest, const char *src, size_t size)
587645f5050Syouri{
5887d8a9cc2Snia	strncpy(dest, src, size - 1);
5897d8a9cc2Snia	dest[size - 1] = '\0';
590645f5050Syouri}
591