diff options
author | Philippe Brochard <pbrochard@common-lisp.net> | 2009-05-18 15:28:11 +0200 |
---|---|---|
committer | Philippe Brochard <pbrochard@common-lisp.net> | 2009-05-18 15:28:11 +0200 |
commit | 0d5a90f36acc602d993075bbccaebb44e671dca6 (patch) | |
tree | 71f73266ef446b8f030f7182544ef21593318fb1 /xbindkeys.c | |
parent | be5b5354a2af10580bde41d3cbf6d2c9db72bb9b (diff) | |
download | xbindkeys-0d5a90f36acc602d993075bbccaebb44e671dca6.tar.gz |
Initial import
Diffstat (limited to 'xbindkeys.c')
-rw-r--r-- | xbindkeys.c | 548 |
1 files changed, 548 insertions, 0 deletions
diff --git a/xbindkeys.c b/xbindkeys.c new file mode 100644 index 0000000..d88b34e --- /dev/null +++ b/xbindkeys.c @@ -0,0 +1,548 @@ +/*************************************************************************** + xbindkeys : a program to bind keys to commands under X11. + ------------------- + begin : Sat Oct 13 14:11:34 CEST 2001 + copyright : (C) 2001 by Philippe Brochard + email : hocwp@free.fr + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <X11/Xlib.h> +#include <signal.h> +#include <unistd.h> +#include <string.h> +#include <sys/wait.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include "xbindkeys.h" +#include "keys.h" +#include "options.h" +#include "get_key.h" +#include "grab_key.h" + +#ifdef GUILE_FLAG +#include <libguile.h> +#endif + + + +void end_it_all (Display * d); + +static Display *start (char *); +static void event_loop (Display *); +static int *null_X_error (Display *, XErrorEvent *); +static void reload_rc_file (void); +static void catch_HUP_signal (int sig); +static void catch_CHLD_signal (int sig); +static void start_as_daemon (void); + + +Display *current_display; // The current display + +#ifndef GUILE_FLAG +extern char rc_file[512]; +#else +extern char rc_guile_file[512]; +#endif + + +#define SLEEP_TIME 100 + +#ifndef GUILE_FLAG +int +main (int argc, char **argv) +#else +int argc_t; char** argv_t; +void +inner_main (int argc, char **argv) +#endif +{ + Display *d; + +#ifdef GUILE_FLAG + argc = argc_t; + argv = argv_t; +#endif + + get_options (argc, argv); + + if (!rc_file_exist ()) + exit (-1); + + if (have_to_start_as_daemon && !have_to_show_binding && !have_to_get_binding) + start_as_daemon (); + + if (!display_name) + display_name = XDisplayName (NULL); + + show_options (); + + d = start (display_name); + current_display = d; + + get_offending_modifiers (d); + + if (have_to_get_binding) + { + get_key_binding (d, argv, argc); + end_it_all (d); + exit (0); + } + +#ifdef GUILE_FLAG + if (get_rc_guile_file () != 0) + { +#endif + if (get_rc_file () != 0) + { + end_it_all (d); + exit (-1); + } +#ifdef GUILE_FLAG + } +#endif + + + if (have_to_show_binding) + { + show_key_binding (d); + end_it_all (d); + exit (0); + } + + grab_keys (d); + + /* This: for restarting reading the RC file if get a HUP signal */ + signal (SIGHUP, catch_HUP_signal); + /* and for reaping dead children */ + signal (SIGCHLD, catch_CHLD_signal); + + if (verbose) + printf ("starting loop...\n"); + event_loop (d); + + if (verbose) + printf ("ending...\n"); + end_it_all (d); + +#ifndef GUILE_FLAG + return (0); /* not reached... */ +#endif +} + +#ifdef GUILE_FLAG +int +main (int argc, char** argv) +{ + //guile shouldn't steal our arguments! we already parse them! + //so we put them in temporary variables. + argv_t = argv; + argc_t = argc; + //printf("Starting in guile mode...\n"); //debugery! + scm_boot_guile(0,(char**)NULL,(void *)inner_main,NULL); + return 0; /* not reached ...*/ +} +#endif + + + +static Display * +start (char *display) +{ + Display *d; + int screen; + + d = XOpenDisplay (display); + if (!d) + { + fprintf (stderr, + "Could not open display, check shell DISPLAY variable, \ +and export or setenv it!\n"); + exit (1); + } + + + XAllowEvents (d, AsyncBoth, CurrentTime); + + for (screen = 0; screen < ScreenCount (d); screen++) + { + XSelectInput (d, RootWindow (d, screen), + KeyPressMask | KeyReleaseMask | PointerMotionMask); + } + + return (d); +} + + + +void +end_it_all (Display * d) +{ + ungrab_all_keys (d); + + close_keys (); + XCloseDisplay (d); +} + + + +static void +adjust_display (XAnyEvent * xany) +{ + size_t envstr_size = strlen(DisplayString(xany->display)) + 8 + 1; + char* envstr = malloc (envstr_size); + XWindowAttributes attr; + char* ptr; + char buf[16]; + + snprintf (envstr, envstr_size, "DISPLAY=%s", DisplayString(xany->display)); + + XGetWindowAttributes (xany->display, xany->window, &attr); + + if (verbose) + printf ("got screen %d for window %x\n", XScreenNumberOfScreen(attr.screen), (unsigned int)xany->window ); + + ptr = strchr (strchr (envstr, ':'), '.'); + if (ptr) + *ptr = '\0'; + + snprintf (buf, sizeof(buf), ".%i", XScreenNumberOfScreen(attr.screen)); + strncat (envstr, buf, 16); + + putenv (envstr); +} + + + +static void +event_loop (Display * d) +{ + XEvent e; + int i; + struct stat rc_file_info; +#ifndef GUILE_FLAG + time_t rc_file_changed; +#else + time_t rc_guile_file_changed; +#endif + + + + XSetErrorHandler ((XErrorHandler) null_X_error); + +#ifndef GUILE_FLAG + stat(rc_file, &rc_file_info); + rc_file_changed = rc_file_info.st_mtime; +#else + stat (rc_guile_file, &rc_file_info); + rc_guile_file_changed = rc_file_info.st_mtime; +#endif + + + while (True) + { + while(!XPending(d)) + { +#ifndef GUILE_FLAG + // if the rc file has been modified, reload it + stat (rc_file, &rc_file_info); + if (rc_file_info.st_mtime != rc_file_changed) + { + reload_rc_file (); + if (verbose) + { + printf ("The rc file has been modified, reload it\n"); + } + rc_file_changed = rc_file_info.st_mtime; + } +#else + // if the rc guile file has been modified, reload it + stat (rc_guile_file, &rc_file_info); + if (rc_file_info.st_mtime != rc_guile_file_changed) + { + reload_rc_file (); + if (verbose) + { + printf ("The rc guile file has been modified, reload it\n"); + } + rc_guile_file_changed = rc_file_info.st_mtime; + } +#endif + + usleep(SLEEP_TIME*1000); + } + + XNextEvent (d, &e); + + switch (e.type) + { + case KeyPress: + if (verbose) + { + printf ("Key press !\n"); + printf ("e.xkey.keycode=%d\n", e.xkey.keycode); + printf ("e.xkey.state=%d\n", e.xkey.state); + } + + e.xkey.state &= ~(numlock_mask | capslock_mask | scrolllock_mask); + + for (i = 0; i < nb_keys; i++) + { + if (keys[i].type == SYM && keys[i].event_type == PRESS) + { + if (e.xkey.keycode == XKeysymToKeycode (d, keys[i].key.sym) + && e.xkey.state == keys[i].modifier) + { + print_key (d, &keys[i]); + adjust_display(&e.xany); + start_command_key (&keys[i]); + } + } + else + if (keys[i].type == CODE && keys[i].event_type == PRESS) + { + if (e.xkey.keycode == keys[i].key.code + && e.xkey.state == keys[i].modifier) + { + print_key (d, &keys[i]); + adjust_display(&e.xany); + start_command_key (&keys[i]); + } + } + } + break; + + case KeyRelease: + if (verbose) + { + printf ("Key release !\n"); + printf ("e.xkey.keycode=%d\n", e.xkey.keycode); + printf ("e.xkey.state=%d\n", e.xkey.state); + } + + e.xkey.state &= ~(numlock_mask | capslock_mask | scrolllock_mask); + + for (i = 0; i < nb_keys; i++) + { + if (keys[i].type == SYM && keys[i].event_type == RELEASE) + { + if (e.xkey.keycode == XKeysymToKeycode (d, keys[i].key.sym) + && e.xkey.state == keys[i].modifier) + { + print_key (d, &keys[i]); + adjust_display(&e.xany); + start_command_key (&keys[i]); + } + } + else + if (keys[i].type == CODE && keys[i].event_type == RELEASE) + { + if (e.xkey.keycode == keys[i].key.code + && e.xkey.state == keys[i].modifier) + { + print_key (d, &keys[i]); + adjust_display(&e.xany); + start_command_key (&keys[i]); + } + } + } + break; + + case ButtonPress: + if (verbose) + { + printf ("Button press !\n"); + printf ("e.xbutton.button=%d\n", e.xbutton.button); + printf ("e.xbutton.state=%d\n", e.xbutton.state); + } + + e.xbutton.state &= ~(numlock_mask | capslock_mask | scrolllock_mask + | Button1Mask | Button2Mask | Button3Mask + | Button4Mask | Button5Mask); + + for (i = 0; i < nb_keys; i++) + { + if (keys[i].type == BUTTON && keys[i].event_type == PRESS) + { + if (e.xbutton.button == keys[i].key.button + && e.xbutton.state == keys[i].modifier) + { + print_key (d, &keys[i]); + adjust_display(&e.xany); + start_command_key (&keys[i]); + } + } + } + break; + + case ButtonRelease: + if (verbose) + { + printf ("Button release !\n"); + printf ("e.xbutton.button=%d\n", e.xbutton.button); + printf ("e.xbutton.state=%d\n", e.xbutton.state); + } + + e.xbutton.state &= ~(numlock_mask | capslock_mask | scrolllock_mask + | Button1Mask | Button2Mask | Button3Mask + | Button4Mask | Button5Mask); + + for (i = 0; i < nb_keys; i++) + { + if (keys[i].type == BUTTON && keys[i].event_type == RELEASE) + { + if (e.xbutton.button == keys[i].key.button + && e.xbutton.state == keys[i].modifier) + { + print_key (d, &keys[i]); + adjust_display(&e.xany); + start_command_key (&keys[i]); + } + } + } + break; + + default: + break; + } + } /* infinite loop */ +} + + + +static int * +null_X_error (Display * d, XErrorEvent * e) +{ + static int already = 0; + + /* The warning is displayed only once */ + if (already != 0) + return (NULL); + already = 1; + + printf ("\n*** Warning ***\n"); + printf ("Please verify that there is not another program running\n"); + printf ("which captures one of the keys captured by xbindkeys.\n"); + printf ("It seems that there is a conflict, and xbindkeys can't\n"); + printf ("grab all the keys defined in its configuration file.\n"); + +/* end_it_all (d); */ + +/* exit (-1); */ + + return (NULL); +} + + + +static void +reload_rc_file (void) +{ + int min, max; + int screen; + + XDisplayKeycodes (current_display, &min, &max); + + if (verbose) + printf ("Reload RC file\n"); + + for (screen = 0; screen < ScreenCount (current_display); screen++) + { + XUngrabKey (current_display, AnyKey, AnyModifier, RootWindow (current_display, screen)); + } + close_keys (); + +#ifdef GUILE_FLAG + if (get_rc_guile_file () != 0) + { +#endif + if (get_rc_file () != 0) + { + end_it_all (current_display); + exit (-1); + } +#ifdef GUILE_FLAG + } +#endif + + grab_keys (current_display); +} + + +static void +catch_HUP_signal (int sig) +{ + reload_rc_file (); +} + + +static void +catch_CHLD_signal (int sig) +{ + pid_t child; + + /* If more than one child exits at approximately the same time, the signals */ + /* may get merged. Handle this case correctly. */ + while ((child = waitpid(-1, NULL, WNOHANG)) > 0) + { + if (verbose) + printf ("Catch CHLD signal -> pid %i terminated\n", child); + } +} + + + + + +static void +start_as_daemon (void) +{ + pid_t pid; + int i; + + pid = fork (); + if (pid < 0) + { + perror ("Could not fork"); + } + if (pid > 0) + { + exit (EXIT_SUCCESS); + } + + setsid (); + + pid = fork (); + if (pid < 0) + { + perror ("Could not fork"); + } + if (pid > 0) + { + exit (EXIT_SUCCESS); + } + + for (i = getdtablesize (); i >= 0; i--) + { + close (i); + } + + i = open ("/dev/null", O_RDWR); + dup (i); + dup (i); + +/* umask (022); */ +/* chdir ("/tmp"); */ +} |