2 /* This module, and the entire FvwmAuto program, and the concept for
3 * interfacing this module to the Window Manager, are all original work
6 * Copyright 1994, Robert Nation. No guarantees or warantees or anything
7 * are provided or implied in any way whatsoever. Use this program at your
8 * own risk. Permission to use this program for any purpose is given,
9 * as long as the copyright is kept intact.
11 * reworked by A.Kadlec (albrecht@auto.tuwien.ac.at) 09/96
12 * to support an arbitrary enter_fn & leave_fn (command line arguments)
13 * completely reworked, while I was there.
15 * Modified by John Aughey (jha@cs.purdue.edu) 11/96
16 * to not perform any action when entering the root window
18 * Minor patch by C. Hines 12/96.
21 /* This program is free software; you can redistribute it and/or modify
22 * it under the terms of the GNU General Public License as published by
23 * the Free Software Foundation; either version 2 of the License, or
24 * (at your option) any later version.
26 * This program is distributed in the hope that it will be useful,
27 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29 * GNU General Public License for more details.
31 * You should have received a copy of the GNU General Public License
32 * along with this program; if not, write to the Free Software
33 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
38 #if HAVE_SYS_BSDTYPES_H
39 #include <sys/bsdtypes.h> /* Saul */
46 #include "libs/ftime.h"
50 #include "libs/Module.h"
51 #include "libs/fvwmlib.h"
52 #include "libs/fvwmsignal.h"
53 #include "libs/Parse.h"
54 #include "libs/Strings.h"
55 #include "libs/wild.h"
57 /* here is the old double parens trick. */
63 #define myfprintf(X) \
71 static RETSIGTYPE
TerminateHandler(int signo
);
76 * Termination procedure : *not* a signal handler
79 RETSIGTYPE
DeadPipe(int nonsense
)
82 myfprintf((stderr
,"Leaving via DeadPipe\n"));
90 * Signal handler that tells the module to quit
94 TerminateHandler(int signo
)
96 fvwmSetTerminate(signo
);
103 * main - start of module
107 main(int argc
, char **argv
)
109 /* The struct holding the module info */
110 static ModuleArgs
* module
;
111 char *enter_fn
="Silent Raise"; /* default */
115 unsigned long m_mask
;
116 unsigned long mx_mask
;
117 unsigned long last_win
= 0; /* last window handled */
118 unsigned long focus_win
= 0; /* current focus */
119 unsigned long raised_win
= 0;
120 fd_set_size_t fd_width
;
126 struct timeval value
;
127 struct timeval
*delay
;
129 Bool do_pass_id
= False
;
130 Bool use_enter_mode
= False
;
131 Bool use_leave_mode
= False
;
137 freopen(".FvwmAutoDebug","w",stderr
);
140 module
= ParseModuleArgs(argc
,argv
,0); /* no alias in this module */
143 fprintf(stderr
,"FvwmAuto Version "VERSION
" should only be executed by fvwm!\n");
148 if (module
->user_argc
< 1 || module
->user_argc
> 5)
150 fprintf(stderr
,"FvwmAuto can use one to five arguments.\n");
154 /* Dead pipes mean fvwm died */
155 #ifdef HAVE_SIGACTION
157 struct sigaction sigact
;
159 sigemptyset(&sigact
.sa_mask
);
160 sigaddset(&sigact
.sa_mask
, SIGPIPE
);
161 sigaddset(&sigact
.sa_mask
, SIGINT
);
162 sigaddset(&sigact
.sa_mask
, SIGHUP
);
163 sigaddset(&sigact
.sa_mask
, SIGQUIT
);
164 sigaddset(&sigact
.sa_mask
, SIGTERM
);
166 sigact
.sa_flags
= SA_RESTART
;
170 sigact
.sa_handler
= TerminateHandler
;
172 sigaction(SIGPIPE
, &sigact
, NULL
);
173 sigaction(SIGINT
, &sigact
, NULL
);
174 sigaction(SIGHUP
, &sigact
, NULL
);
175 sigaction(SIGQUIT
, &sigact
, NULL
);
176 sigaction(SIGTERM
, &sigact
, NULL
);
179 /* We don't have sigaction(), so fall back to less robust methods. */
180 #ifdef USE_BSD_SIGNALS
181 fvwmSetSignalMask( sigmask(SIGPIPE
) |
188 signal(SIGPIPE
, TerminateHandler
);
189 signal(SIGINT
, TerminateHandler
);
190 signal(SIGHUP
, TerminateHandler
);
191 signal(SIGQUIT
, TerminateHandler
);
192 signal(SIGTERM
, TerminateHandler
);
193 #ifdef HAVE_SIGINTERRUPT
194 siginterrupt(SIGPIPE
, 0);
195 siginterrupt(SIGINT
, 0);
196 siginterrupt(SIGHUP
, 0);
197 siginterrupt(SIGQUIT
, 0);
198 siginterrupt(SIGTERM
, 0);
202 fd
[0] = module
->to_fvwm
;
203 fd
[1] = module
->from_fvwm
;
205 if ((timeout
= atoi(module
->user_argv
[0]) ))
207 sec
= timeout
/ 1000;
208 usec
= (timeout
% 1000) * 1000;
218 if (n
< module
->user_argc
&& module
->user_argv
[n
])
223 if (n
< module
->user_argc
&& *module
->user_argv
[n
] && StrEquals(module
->user_argv
[n
], "-passid"))
228 if (n
< module
->user_argc
&& *module
->user_argv
[n
] && StrEquals(module
->user_argv
[n
], "-menterleave"))
230 /* enterleave mode */
231 use_leave_mode
= True
;
232 use_enter_mode
= True
;
235 else if (n
< module
->user_argc
&& *module
->user_argv
[n
] && StrEquals(module
->user_argv
[n
], "-menter"))
238 use_leave_mode
= False
;
239 use_enter_mode
= True
;
242 else if (n
< module
->user_argc
&& *module
->user_argv
[n
] && StrEquals(module
->user_argv
[n
], "-mfocus"))
245 use_leave_mode
= False
;
246 use_enter_mode
= False
;
249 /*** enter command ***/
250 if (n
< module
->user_argc
&& *module
->user_argv
[n
] && StrEquals(module
->user_argv
[n
], "Nop"))
256 else if (n
< module
->user_argc
)
258 /* override default */
259 enter_fn
= module
->user_argv
[n
];
262 /* This is a hack to prevent user interaction with old configs.
266 token
= PeekToken(enter_fn
, NULL
);
267 if (!StrEquals(token
, "Silent"))
269 enter_fn
= safestrdup(
270 CatString2("Silent ", enter_fn
));
273 /*** leave command ***/
274 if (n
< module
->user_argc
&& module
->user_argv
[n
] && *module
->user_argv
[n
] &&
275 StrEquals(module
->user_argv
[n
], "Nop"))
281 else if (n
< module
->user_argc
)
283 /* leave function specified */
284 leave_fn
=module
->user_argv
[n
];
289 token
= PeekToken(leave_fn
, NULL
);
290 if (!StrEquals(token
, "Silent"))
292 leave_fn
= safestrdup(
293 CatString2("Silent ", leave_fn
));
298 /* Exit if nothing to do. */
299 if (!enter_fn
&& !leave_fn
)
307 mx_mask
= MX_ENTER_WINDOW
| MX_LEAVE_WINDOW
| M_EXTENDED_MSG
;
311 mx_mask
= M_EXTENDED_MSG
;
312 m_mask
= M_FOCUS_CHANGE
;
314 /* Disable special raise/lower support on general actions. *
315 * This works as expected in most of cases. */
316 if (matchWildcards("*Raise*", CatString2(enter_fn
, leave_fn
)) ||
317 matchWildcards("*Lower*", CatString2(enter_fn
, leave_fn
)))
319 m_mask
|= M_RAISE_WINDOW
| M_LOWER_WINDOW
;
322 /* migo (04/May/2000): It is simply incorrect to listen to raise/lower
323 * packets and change the state if the action itself has no raise/lower.
324 * Detecting whether to listen or not by the action name is good enough.
325 m_mask = M_FOCUS_CHANGE | M_RAISE_WINDOW | M_LOWER_WINDOW;
328 SetMessageMask(fd
, m_mask
);
329 SetMessageMask(fd
, mx_mask
);
330 /* tell fvwm we're running */
331 SendFinishedStartupNotification(fd
);
332 /* tell fvwm that we want to be lock on send */
333 SetSyncMask(fd
, m_mask
);
334 SetSyncMask(fd
, mx_mask
);
336 fd_width
= fd
[1] + 1;
339 /* create the command buffer */
343 len
= strlen(enter_fn
);
345 if (leave_fn
!= NULL
)
347 len
= max(len
, strlen(leave_fn
));
353 buf
= safemalloc(len
);
355 while (!isTerminated
)
357 char raise_window_now
;
358 static char have_new_window
= 0;
360 FD_SET(fd
[1], &in_fdset
);
363 (stderr
, "\nstart %d (hnw = %d, usec = %d)\n", count
++,
364 have_new_window
, usec
));
365 /* fill in struct - modified by select() */
367 delay
->tv_usec
= usec
;
372 sprintf(tmp
, "%d usecs", (delay
) ?
373 (int)delay
->tv_usec
: -1);
374 myfprintf((stderr
, "select: delay = %s\n",
375 (have_new_window
) ? tmp
: "infinite" ));
378 if (fvwmSelect(fd_width
, &in_fdset
, NULL
, NULL
,
379 (have_new_window
) ? delay
: NULL
) == -1)
382 (stderr
, "select: error! (%s)\n",
387 raise_window_now
= 0;
388 if (FD_ISSET(fd
[1], &in_fdset
))
390 FvwmPacket
*packet
= ReadFvwmPacket(fd
[1]);
396 "Leaving because of null packet\n"));
402 "pw = 0x%x, fw=0x%x, rw = 0x%x, lw=0x%x\n",
403 (int)packet
->body
[0], (int)focus_win
,
404 (int)raised_win
, (int)last_win
));
406 switch (packet
->type
)
408 case MX_ENTER_WINDOW
:
409 focus_win
= packet
->body
[0];
410 if (focus_win
!= raised_win
)
413 "entered new window\n"));
415 raise_window_now
= 0;
417 else if (focus_win
== last_win
)
424 "entered other window\n"));
428 case MX_LEAVE_WINDOW
:
431 if (focus_win
== raised_win
)
436 "left raised window\n"));
438 raise_window_now
= 0;
443 /* it's a focus package */
444 focus_win
= packet
->body
[0];
445 if (focus_win
!= raised_win
)
448 "focus on new window\n"));
450 raise_window_now
= 0;
455 "focus on old window\n"));
461 (stderr
, "raise packet 0x%x\n",
462 (int)packet
->body
[0]));
463 raised_win
= packet
->body
[0];
464 if (have_new_window
&& focus_win
== raised_win
)
467 (stderr
, "its the old window:"
475 (stderr
, "lower packet 0x%x\n",
476 (int)packet
->body
[0]));
477 if (have_new_window
&&
478 focus_win
== packet
->body
[0])
482 "window was explicitly"
483 " lowered, don't raise it"
489 SendUnlockNotification(fd
);
495 myfprintf((stderr
, "must raise now\n"));
496 raise_window_now
= 1;
500 if (raise_window_now
)
502 myfprintf((stderr
, "raising 0x%x\n", (int)focus_win
));
505 ((last_win
&& !use_leave_mode
) ||
506 (raised_win
&& use_enter_mode
)))
508 /* if focus_win isn't the root */
511 sprintf(buf
, "%s 0x%x\n", leave_fn
,
516 sprintf(buf
, "%s\n", leave_fn
);
518 SendInfo(fd
, buf
, last_win
);
525 if (focus_win
&& enter_fn
)
527 /* if focus_win isn't the root */
530 sprintf(buf
, "%s 0x%x\n", enter_fn
,
535 sprintf(buf
, "%s\n", enter_fn
);
537 SendInfo(fd
, buf
, focus_win
);
538 raised_win
= focus_win
;
540 else if (focus_win
&& enter_fn
== NULL
)
542 raised_win
= focus_win
;
544 /* force fvwm to synchronise on slow X connections to
545 * avoid a race condition. Still possible, but much
547 SendInfo(fd
, "XSync", focus_win
);
549 /* switch to wait mode again */
550 last_win
= focus_win
;