1 /*
2  * Copyright (c) 1997 Guylhem Aznar <guylhem@oeil.qc.ca>
3  * Copyright (c) 1994 Nobutaka Suzuki <nobuta-s@is.aist-nara.ac.jp>
4  * Copyright (c) 1994 Robert Nation
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  */
20 
21 #define YES "Yes"
22 #define NO  "No"
23 
24 #include "../../configure.h"
25 
26 #include <stdlib.h>
27 
28 #include <X11/Xlib.h>
29 #include <X11/Xutil.h>
30 #include <X11/cursorfont.h>
31 #include <X11/Xmu/WinUtil.h>
32 
33 #define IN_MODULE
34 #define MODULE_X_INTERFACE
35 #include "../../include/aftersteplib.h"
36 #include "../../include/module.h"
37 #include "Scroll.h"
38 
39 int fd[2];
40 
41 ScreenInfo Scr;
42 
43 char *BackColor = "black";
44 char *ForeColor = "grey";
45 
46 Window app_win;
47 
48 #define MW_EVENTS   (ExposureMask | ButtonReleaseMask | KeyReleaseMask)
49 
50 void ParseOptions (const char *);
51 
52 void
version(void)53 version (void)
54 {
55   printf ("%s version %s\n", MyName, VERSION);
56   exit (0);
57 }
58 
59 void
usage(void)60 usage (void)
61 {
62   printf ("Usage:\n"
63 	  "%s [-v|--version] [-h|--help] [--window window-id] [x y]\n", MyName);
64   exit (0);
65 }
66 
67 /***********************************************************************
68  *
69  *  Procedure:
70  *	main - start of module
71  *
72  ***********************************************************************/
73 int
main(int argc,char ** argv)74 main (int argc, char **argv)
75 {
76   char configfile[255];
77   char *realconfigfile;
78   char *temp;
79   int i;
80   char *global_config_file = NULL;
81 
82   /* Save our program name - for error messages */
83   temp = strrchr (argv[0], '/');
84   MyName = temp ? temp + 1 : argv[0];
85   set_application_name( argv[0] );
86 
87   for (i = 1; i < argc && *argv[i] == '-'; i++)
88     {
89       if (!strcmp (argv[i], "-h") || !strcmp (argv[i], "--help"))
90 	usage ();
91       else if (!strcmp (argv[i], "-v") || !strcmp (argv[i], "--version"))
92 	version ();
93       else if (!strcmp (argv[i], "-w") || !strcmp (argv[i], "--window"))
94 	app_win = strtol (argv[++i], NULL, 16);
95       else if (!strcmp (argv[i], "-c") || !strcmp (argv[i], "--context"))
96 	i++;
97       else if (!strcmp (argv[i], "-f") && i + 1 < argc)
98 	global_config_file = argv[++i];
99     }
100 
101   /* Dead pipe == dead AfterStep */
102   signal (SIGPIPE, DeadPipe);
103   set_signal_handler (SIGSEGV);
104 
105   x_fd = ConnectX( ASDefaultScr, display_name, 0 );
106   /* connect to AfterStep */
107   fd[0] = fd[1] = ConnectAfterStep (0);
108 
109   if (i < argc)
110     {
111       char *cptr = argv[i++];
112       extern int Reduction_H, Reduction_V;
113       Reduction_H = strtol (cptr, &cptr, 10);
114       Reduction_V = strtol (cptr, &cptr, 10);
115       if (Reduction_H < 2)
116 	Reduction_H = 2;
117       if (Reduction_V < 2)
118 	Reduction_V = 2;
119     }
120 
121   /* scan config file for set-up parameters */
122   /* Colors and fonts */
123   if (global_config_file != NULL)
124     ParseOptions (global_config_file);
125   else
126     {
127       sprintf (configfile, "%s/scroll", AFTER_DIR);
128 
129       realconfigfile = PutHome (configfile);
130 
131       if ((CheckFile (realconfigfile)) == -1)
132 	{
133 	  free (realconfigfile);
134 	  sprintf (configfile, "%s/scroll", AFTER_SHAREDIR);
135 	  realconfigfile = PutHome (configfile);
136 	}
137       ParseOptions (realconfigfile);
138       free (realconfigfile);
139     }
140 
141   if (app_win == 0)
142     GetTargetWindow (&app_win);
143 
144   if (app_win == 0)
145     return 1;
146 
147   fd_width = GetFdWidth ();
148 
149   GrabWindow (app_win);
150   Loop (app_win);
151 
152   return 0;
153 }
154 
155 
156 void
ParseOptions(const char * filename)157 ParseOptions (const char *filename)
158 {
159   FILE *file;
160   char *line, *tline;
161   int len;
162 
163   if ((file = fopen (filename, "r")) != (FILE *) NULL)
164     {
165       line = (char *) safemalloc (MAXLINELENGTH);
166       len = strlen (MyName);
167       while ((tline = fgets (line, MAXLINELENGTH, file)) == NULL)
168 	{
169 	  while (isspace (*tline))
170 	    tline++;
171 	  if ((*tline == '*') && (!mystrncasecmp (tline + 1, MyName, len)))
172 	    {
173 	      tline += len + 1;
174 	      if (!mystrncasecmp (tline, "Fore", 4))
175         ForeColor = stripcpy( tline + 4);
176 	      else if (!mystrncasecmp (tline, "Back", 4))
177         BackColor = stripcpy( tline + 4);
178 	    }
179 	}
180       free (line);
181       fclose (file);
182     }
183 }
184 
185 /***********************************************************************
186  *
187  * Detected a broken pipe - time to exit
188  *
189  **********************************************************************/
190 void
DeadPipe(int nonsense)191 DeadPipe (int nonsense)
192 {
193   extern Atom wm_del_win;
194 
195   XReparentWindow (dpy, app_win, Scr.Root, 0, 0);
196   send_wm_protocol_request(app_win, wm_del_win, CurrentTime);
197   XSync (dpy, 0);
198   exit (0);
199 }
200 
201 
202 /**********************************************************************
203  *
204  * If no application window was indicated on the command line, prompt
205  * the user to select one
206  *
207  *********************************************************************/
208 void
GetTargetWindow(Window * app_win)209 GetTargetWindow (Window * app_win)
210 {
211   XEvent eventp;
212   int val = -10, trials;
213   Window target_win;
214 
215   trials = 0;
216   while ((trials < 100) && (val != GrabSuccess))
217     {
218       val = XGrabPointer (dpy, Scr.Root, True,
219 			  ButtonReleaseMask,
220 			  GrabModeAsync, GrabModeAsync, Root,
221 			  XCreateFontCursor (dpy, XC_crosshair),
222 			  CurrentTime);
223       if (val != GrabSuccess)
224 	{
225 	  sleep_a_little (1000);
226 	}
227       trials++;
228     }
229   if (val != GrabSuccess)
230     {
231       fprintf (stderr, "%s: Couldn't grab the cursor!\n", MyName);
232       exit (1);
233     }
234   XMaskEvent (dpy, ButtonReleaseMask, &eventp);
235   XUngrabPointer (dpy, CurrentTime);
236   XSync (dpy, 0);
237   *app_win = eventp.xany.window;
238   if (eventp.xbutton.subwindow != None)
239     *app_win = eventp.xbutton.subwindow;
240 
241   target_win = ClientWindow (*app_win);
242   if (target_win != None)
243     *app_win = target_win;
244 }
245 
246 
247 /****************************************************************************
248  *
249  * Find the actual application
250  *
251  ***************************************************************************/
252 Window
ClientWindow(Window input)253 ClientWindow (Window input)
254 {
255   Atom _XA_WM_STATE;
256   unsigned int nchildren;
257   Window root, parent, *children, target;
258   unsigned long nitems, bytesafter;
259   unsigned char *prop;
260   Atom atype;
261   int aformat;
262   int i;
263 
264   _XA_WM_STATE = XInternAtom (dpy, "WM_STATE", False);
265 
266   if (XGetWindowProperty (dpy, input, _XA_WM_STATE, 0L,
267 			  3L, False, _XA_WM_STATE, &atype,
268 			  &aformat, &nitems, &bytesafter,
269 			  &prop) == Success)
270     {
271       if (prop != NULL)
272 	{
273 	  XFree (prop);
274 	  return input;
275 	}
276     }
277 
278   if (!XQueryTree (dpy, input, &root, &parent, &children, &nchildren))
279     return None;
280 
281   for (i = 0; i < nchildren; i++)
282     {
283       target = ClientWindow (children[i]);
284       if (target != None)
285 	{
286 	  XFree ((char *) children);
287 	  return target;
288 	}
289     }
290   XFree ((char *) children);
291   return None;
292 }
293