From 1a8458cd5a3252f9d2141de13ef67a30b215476c Mon Sep 17 00:00:00 2001 From: sabetts Date: Sat, 9 Dec 2000 11:34:43 +0000 Subject: * input.c (cook_keycode): properly handle LockMask * input.h: added prototype for keysym_to_string * input.c (keysym_to_string): added * bar.c (show_bar): update_window_names(s) is called whether the bar is raised or not. * conf.h: Added BAR_Y_PADDING BAR_X_PADDING * list.c (goto_window_name): return success or failure * list.h: updated prototype for goto_window_name * events.c (handle_key): Added a message indicating an unbound key. * bar.c (display_msg_in_bar): added (update_window_names): uses BAR_X_PADDING instead of `5' (update_window_names): Updated BAR_PADDING to BAR_Y_PADDING * input.c (cook_keycode): mod is now an usigned int (read_key): Ignores modifier keys. Now returns keysym and modifiers. (get_input): Updated BAR_PADDING to BAR_Y_PADDING and BAR_X_PADDING. * events.c (handle_key): uses read_key instead of XMaskEvent to read a key. * actions.c (goto_window_number): window list is displayed on failure. (bye): added (switch_to): added (execute_command): no longer seg faults when no windows exist. --- src/ChangeLog | 38 ++++++++++++++++++ src/actions.c | 53 +++++++++++++++++++++++- src/actions.h | 2 + src/bar.c | 54 +++++++++++++++++++++---- src/bar.h | 1 + src/conf.h | 7 +++- src/events.c | 82 ++++++++++++++++--------------------- src/input.c | 127 +++++++++++++++++++++++++++++++++++++++++++--------------- src/input.h | 4 +- src/list.c | 5 ++- src/list.h | 2 +- 11 files changed, 281 insertions(+), 94 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index e1477f4..2313b76 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,41 @@ +2000-12-09 shawn + + * input.c (cook_keycode): properly handle LockMask + + * input.h: added prototype for keysym_to_string + + * input.c (keysym_to_string): added + + * bar.c (show_bar): update_window_names(s) is called whether the + bar is raised or not. + + * conf.h: Added BAR_Y_PADDING BAR_X_PADDING + + * list.c (goto_window_name): return success or failure + + * list.h: updated prototype for goto_window_name + + * events.c (handle_key): Added a message indicating an unbound + key. + + * bar.c (display_msg_in_bar): added + (update_window_names): uses BAR_X_PADDING instead of `5' + (update_window_names): Updated BAR_PADDING to BAR_Y_PADDING + + * input.c (cook_keycode): mod is now an usigned int + (read_key): Ignores modifier keys. Now returns keysym and + modifiers. + (get_input): Updated BAR_PADDING to BAR_Y_PADDING and + BAR_X_PADDING. + + * events.c (handle_key): uses read_key instead of XMaskEvent to + read a key. + + * actions.c (goto_window_number): window list is displayed on failure. + (bye): added + (switch_to): added + (execute_command): no longer seg faults when no windows exist. + 2000-12-03 shawn * input.h (cook_keycode): added prototype diff --git a/src/actions.c b/src/actions.c index 323f519..095604b 100644 --- a/src/actions.c +++ b/src/actions.c @@ -67,8 +67,15 @@ next_window (void *data) void last_window (void *data) { + rp_window *oldwin = rp_current_window; + rp_current_window = find_last_accessed_window (); set_active_window (rp_current_window); + + if (rp_current_window == oldwin) + { + display_msg_in_bar (&screens[0], "No other window."); + } } @@ -145,7 +152,17 @@ execute_command (void *data) { char cmd[100]; - get_input (rp_current_window->scr, "Command: ", cmd, 100); + if (rp_current_window) + { + get_input (rp_current_window->scr, "Command: ", cmd, 100); + } + else + { + /* FIXME: We can always assume there is 1 screen, but which one + is the active one? Need to test on multi-screen x-servers. */ + get_input (&screens[0], "Command: ", cmd, 100); + } + PRINT_DEBUG ("user entered: %s\n", cmd); spawn (cmd); @@ -163,8 +180,10 @@ spawn(void *data) if (fork() == 0) { putenv(DisplayString(dpy)); execlp(prog, prog, 0); - fprintf (stderr, "exec %s ", prog); + + PRINT_ERROR ("exec %s ", prog); perror(" failed"); + exit(EXIT_FAILURE); } exit(0); @@ -173,6 +192,32 @@ spawn(void *data) PRINT_DEBUG ("spawned %s\n", prog); } +/* Switch to a different Window Manager. Thanks to +"Chr. v. Stuckrad" for the patch. */ +void +switch_to(void *which) +{ + char *prog=(char *)which; + + PRINT_DEBUG ("Switching to %s\n", prog); + + putenv(DisplayString(dpy)); + execlp(prog, prog, 0); + + PRINT_ERROR ("exec %s ", prog); + perror(" failed"); +} + +/* Quit ratpoison. Thanks to +"Chr. v. Stuckrad" for the patch. */ +void +bye(void *dummy) +{ + PRINT_DEBUG ("Exiting\n"); + clean_up (); + exit (EXIT_SUCCESS); +} + void goto_window_number (int n) { @@ -180,6 +225,10 @@ goto_window_number (int n) if ((win = find_window_by_number (n)) == NULL) { + /* Display window list to indicate failure. */ + /* FIXME: We can always assume there is 1 screen, but which one + is the active one? Need to test on multi-screen x-servers. */ + show_bar (&screens[0]); return; } diff --git a/src/actions.h b/src/actions.h index 793064d..54317c3 100644 --- a/src/actions.h +++ b/src/actions.h @@ -1,6 +1,8 @@ /* actions.h -- prototypes of all actions that can be performed with keystrokes */ +void switch_to(void *which); +void bye(void *dummy); void generate_prefix (void *data); void abort_keypress (void *data); void goto_window_9 (void *data); diff --git a/src/bar.c b/src/bar.c index e61c9cd..c69e0d9 100644 --- a/src/bar.c +++ b/src/bar.c @@ -29,6 +29,11 @@ #include "ratpoison.h" +/* Possible values for bar_is_raised status. */ +#define BAR_IS_WINDOW_LIST 1 +#define BAR_IS_MESSAGE 2 + +/* Hide the bar from sight. */ int hide_bar (screen_info *s) { @@ -42,12 +47,13 @@ hide_bar (screen_info *s) return 0; } +/* Show window listing in bar. */ int show_bar (screen_info *s) { if (!s->bar_is_raised) { - s->bar_is_raised = 1; + s->bar_is_raised = BAR_IS_WINDOW_LIST; XMapWindow (dpy, s->bar_window); update_window_names (s); @@ -56,9 +62,14 @@ show_bar (screen_info *s) return 1; } + /* If the bar is raised we still need to display the window + names. */ + update_window_names (s); return 0; } +/* Calculate the width required for the bar to display the window + list. */ static int calc_bar_width (XFontStruct *font) { @@ -88,7 +99,7 @@ int bar_y (screen_info *s) { if (BAR_LOCATION % 2) return 0; - else return s->root_attr.height - (FONT_HEIGHT (s->font) + BAR_PADDING * 2) - 2; + else return s->root_attr.height - (FONT_HEIGHT (s->font) + BAR_Y_PADDING * 2) - 2; } void @@ -97,14 +108,14 @@ update_window_names (screen_info *s) char str[100]; /* window names are capped at 99 chars */ int width = calc_bar_width (s->font); rp_window *cur; - int cur_x = 5; + int cur_x = BAR_X_PADDING; if (!s->bar_is_raised) return; XMoveResizeWindow (dpy, s->bar_window, bar_x (s, width), bar_y (s), width, - (FONT_HEIGHT (s->font) + BAR_PADDING * 2)); + (FONT_HEIGHT (s->font) + BAR_Y_PADDING * 2)); XClearWindow (dpy, s->bar_window); XRaiseWindow (dpy, s->bar_window); @@ -112,7 +123,7 @@ update_window_names (screen_info *s) /* Draw them in reverse order they were added in, so the oldest windows appear on the left and the newest on the right end of the - program bar. */ + bar. */ for (cur = rp_window_head; cur; cur = cur->next) { if (cur->state == STATE_UNMAPPED) continue; @@ -121,14 +132,43 @@ update_window_names (screen_info *s) if ( rp_current_window == cur) { XDrawString (dpy, s->bar_window, s->bold_gc, cur_x, - BAR_PADDING + s->font->max_bounds.ascent, str, strlen (str)); + BAR_Y_PADDING + s->font->max_bounds.ascent, str, + strlen (str)); } else { XDrawString (dpy, s->bar_window, s->normal_gc, cur_x, - BAR_PADDING + s->font->max_bounds.ascent, str, strlen (str)); + BAR_Y_PADDING + s->font->max_bounds.ascent, str, + strlen (str)); } cur_x += 10 + XTextWidth (s->font, str, strlen (str)); } } + +void +display_msg_in_bar (screen_info *s, char *msg) +{ + int width = BAR_X_PADDING * 2 + XTextWidth (s->font, msg, strlen (msg)); + + /* Map the bar if needed */ + if (!s->bar_is_raised) + { + s->bar_is_raised = BAR_IS_MESSAGE; + XMapWindow (dpy, s->bar_window); + } + + /* Reset the alarm to auto-hide the bar in BAR_TIMEOUT seconds. */ + alarm (BAR_TIMEOUT); + + XMoveResizeWindow (dpy, s->bar_window, + bar_x (s, width), bar_y (s), + width, + (FONT_HEIGHT (s->font) + BAR_Y_PADDING * 2)); + XClearWindow (dpy, s->bar_window); + XRaiseWindow (dpy, s->bar_window); + + XDrawString (dpy, s->bar_window, s->bold_gc, BAR_X_PADDING, + BAR_Y_PADDING + s->font->max_bounds.ascent, msg, + strlen (msg)); +} diff --git a/src/bar.h b/src/bar.h index 383bcdf..49c0ff4 100644 --- a/src/bar.h +++ b/src/bar.h @@ -25,4 +25,5 @@ int show_bar (screen_info *s); int hide_bar (screen_info *s); int bar_y (screen_info *s); int bar_x (screen_info *s, int width); +void display_msg_in_bar (screen_info *s, char *msg); #endif _BAR_H diff --git a/src/conf.h b/src/conf.h index 3092bc6..9b705dd 100644 --- a/src/conf.h +++ b/src/conf.h @@ -27,10 +27,13 @@ #define BAR_FG_COLOR "Gray60" #define BAR_BG_COLOR "Lightgreen" -#define BAR_BOLD_COLOR "Black" /* To indicate the current window */ +#define BAR_BOLD_COLOR "Black" /* To indicate the current window */ #define FONT_NAME "fixed" /* The font you wish to use */ -#define BAR_PADDING 3 /* The amount of padding on the top and bottom of the program bar */ +#define BAR_Y_PADDING 3 /* The amount of padding on the top + and bottom of the message bar */ +#define BAR_X_PADDING 5 /* The amount of padding on the left + and right of the message bar */ #define BAR_LOCATION 3 /* 0=bottom-left 1=top-left 2=bottom-right 3=top-right */ #define BAR_TIMEOUT 5 /* Number of seconds before the progam bar autohides 0=don't autohide */ diff --git a/src/events.c b/src/events.c index bf9c78b..d859965 100644 --- a/src/events.c +++ b/src/events.c @@ -239,59 +239,49 @@ client_msg (XClientMessageEvent *ev) static void handle_key (screen_info *s) { + char *keysym_name; + char msg[100]; const rp_action *i; - int revert; - Window fwin; - XEvent ev; - KeySym keysym; - int mod; + int revert; + Window fwin; /* Window currently in focus */ + KeySym keysym; /* Key pressed */ + unsigned int mod; /* Modifiers */ - PRINT_DEBUG ("handling key.\n"); + PRINT_DEBUG ("handling key...\n"); - /* All functions hide the program bar. */ + /* All functions hide the program bar. Unless the bar doesn't time + out. */ if (BAR_TIMEOUT > 0) hide_bar (s); XGetInputFocus (dpy, &fwin, &revert); XSetInputFocus (dpy, s->key_window, RevertToPointerRoot, CurrentTime); - do - { - XMaskEvent (dpy, KeyPressMask, &ev); - mod = ev.xkey.state; - - cook_keycode (ev.xkey.keycode, &keysym, &mod); + read_key (&keysym, &mod); - for (i = key_actions; i->key != 0; i++) + for (i = key_actions; i->key != 0; i++) + { + if (keysym == i->key) { - if (keysym == i->key) - if (i->state == -1 || mod == i->state) - { - /* Revert focus back to the current window before - executing the command. */ - XSetInputFocus (dpy, fwin, revert, CurrentTime); - (*i->func)(i->data); - goto handled_key; - } + if (i->state == -1 || mod == i->state) + { + /* Revert focus back to the current window before + executing the command. */ + XSetInputFocus (dpy, fwin, revert, CurrentTime); + (*i->func)(i->data); + return; + } } } - while (1); - - handled_key: - -/* } while (keysym == XK_Shift_L */ -/* || keysym == XK_Shift_R */ -/* || keysym == XK_Control_L */ -/* || keysym == XK_Control_R */ -/* || keysym == XK_Caps_Lock */ -/* || keysym == XK_Shift_Lock */ -/* || keysym == XK_Meta_L */ -/* || keysym == XK_Meta_R */ -/* || keysym == XK_Alt_L */ -/* || keysym == XK_Alt_R */ -/* || keysym == XK_Super_L */ -/* || keysym == XK_Super_R */ -/* || keysym == XK_Hyper_L */ -/* || keysym == XK_Hyper_R); /\* ignore modifier keypresses. *\/ */ + + keysym_name = keysym_to_string (keysym, mod); + snprintf (msg, 100, "%s unbound key!", keysym_name); + free (keysym_name); + + PRINT_DEBUG ("%s\n", msg) + + /* No key match, notify user. */ + XSetInputFocus (dpy, fwin, revert, CurrentTime); + display_msg_in_bar (s, msg); } void @@ -404,14 +394,12 @@ delegate_event (XEvent *ev) case KeyPress: PRINT_DEBUG ("KeyPress %d %d\n", ev->xkey.keycode, ev->xkey.state); - { - KeySym thesym; - char buf[512]; - XLookupString (&ev->xkey, buf, 512, &thesym, NULL); - PRINT_DEBUG ("key string: '%s' %ld\n", buf, thesym); - } key_press (ev); break; + + case KeyRelease: + PRINT_DEBUG ("KeyRelease %d %d\n", ev->xkey.keycode, ev->xkey.state); + break; case UnmapNotify: PRINT_DEBUG ("UnmapNotify\n"); diff --git a/src/input.c b/src/input.c index 60e3932..c9a276a 100644 --- a/src/input.c +++ b/src/input.c @@ -9,51 +9,102 @@ #include "ratpoison.h" +/* Return the name of the keysym. caller must free returned pointer */ +char * +keysym_to_string (KeySym keysym, unsigned int modifier) +{ + const unsigned int mod_table[] = {ControlMask, + Mod1Mask, + Mod2Mask, + Mod3Mask, + Mod4Mask, + Mod5Mask}; + const unsigned char str_table[] = "CM2345"; + + unsigned char *name; + int pos, i; + + name = malloc (15); + if (name == NULL) + { + PRINT_ERROR ("Out of memory!\n"); + exit (EXIT_FAILURE); + } + + for (pos = 0, i = 0; i < 6; i++) + { + if (modifier & mod_table[i]) + { + name[pos] = str_table[i]; + name[pos+1] = '-'; + pos += 2; + } + } + + name[pos] = keysym; + name[pos+1] = '\0'; + + return name; +} + /* Cooks a keycode + modifier into a keysym + modifier. This should be used anytime meaningful key information is to be extracted from a KeyPress or KeyRelease event. */ void -cook_keycode (KeyCode keycode, KeySym *keysym, int *mod) +cook_keycode (KeyCode keycode, KeySym *keysym, unsigned int *mod) { KeySym normal, shifted; - if (*mod & ShiftMask) - { - normal = XKeycodeToKeysym(dpy, keycode, 0); - shifted = XKeycodeToKeysym(dpy, keycode, 1); + normal = XKeycodeToKeysym(dpy, keycode, 0); + shifted = XKeycodeToKeysym(dpy, keycode, 1); - /* if the shifted code is not defined, then we use the normal keysym and keep the shift mask */ + /* FIXME: eew, this looks gross. */ + if (*mod & (ShiftMask | LockMask)) + { + /* if the shifted code is not defined, then we use the normal + keysym and keep the shift mask */ if (shifted == NoSymbol) { *keysym = normal; } - /* But if the shifted code is defined, we use it and remove the shift mask */ - else + else if (*mod & ShiftMask) + { + *keysym = shifted; + *mod &= ~(ShiftMask | LockMask); + } + else if (normal >= XK_a + && normal <= XK_z + && *mod & LockMask) { *keysym = shifted; - *mod &= ~ShiftMask; + } + /* But if the shifted code is defined, we use it and remove the + shift mask */ + else + { + *keysym = normal; } } else { - *keysym = XKeycodeToKeysym(dpy, keycode, 0); + *keysym = normal; } - PRINT_DEBUG ("cooked keysym: %ld '%c' mask: %d\n", *keysym, *keysym, *mod); + PRINT_DEBUG ("cooked keysym: %ld '%c' mask: %d\n", + *keysym, (char)*keysym, *mod); } -static KeySym -read_key () +void +read_key (KeySym *keysym, unsigned int *modifiers) { - KeySym keysym; - int mod; XEvent ev; - XMaskEvent (dpy, KeyPressMask, &ev); - mod = ev.xkey.state; - cook_keycode (ev.xkey.keycode, &keysym, &mod); - - return keysym; + do + { + XMaskEvent (dpy, KeyPressMask, &ev); + *modifiers = ev.xkey.state; + cook_keycode (ev.xkey.keycode, keysym, modifiers); + } while (IsModifierKey (*keysym)); } /* pass in a pointer a string and how much room we have, and fill it @@ -63,6 +114,7 @@ get_input (screen_info *s, char *prompt, char *str, int len) { int cur_len; /* Current length of the string. */ KeySym ch; + unsigned int modifier; int revert; Window fwin; int prompt_width = XTextWidth (s->font, prompt, strlen (prompt)); @@ -73,38 +125,49 @@ get_input (screen_info *s, char *prompt, char *str, int len) XMapWindow (dpy, s->input_window); XMoveResizeWindow (dpy, s->input_window, - bar_x (s, width), bar_y (s), width, (FONT_HEIGHT (s->font) + BAR_PADDING * 2)); + bar_x (s, width), bar_y (s), width, + (FONT_HEIGHT (s->font) + BAR_Y_PADDING * 2)); XClearWindow (dpy, s->input_window); XRaiseWindow (dpy, s->input_window); /* draw the window prompt. */ - XDrawString (dpy, s->input_window, s->bold_gc, 5, - BAR_PADDING + s->font->max_bounds.ascent, prompt, strlen (prompt)); + XDrawString (dpy, s->input_window, s->bold_gc, BAR_X_PADDING, + BAR_Y_PADDING + s->font->max_bounds.ascent, prompt, + strlen (prompt)); XGetInputFocus (dpy, &fwin, &revert); XSetInputFocus (dpy, s->input_window, RevertToPointerRoot, CurrentTime); + /* XSync (dpy, False); */ cur_len = 0; - while ((ch = read_key ()) != XK_Return) + + read_key (&ch, &modifier); + while (ch != XK_Return) { - PRINT_DEBUG ("key %d\n", ch); + PRINT_DEBUG ("key %ld\n", ch); if (ch == XK_BackSpace) { if (cur_len > 0) cur_len--; XClearWindow (dpy, s->input_window); - XDrawString (dpy, s->input_window, s->bold_gc, 5, - BAR_PADDING + s->font->max_bounds.ascent, prompt, strlen (prompt)); - XDrawString (dpy, s->input_window, s->bold_gc, 5 + prompt_width, - BAR_PADDING + s->font->max_bounds.ascent, str, cur_len); + XDrawString (dpy, s->input_window, s->bold_gc, BAR_X_PADDING, + BAR_Y_PADDING + s->font->max_bounds.ascent, prompt, + strlen (prompt)); + XDrawString (dpy, s->input_window, s->bold_gc, + BAR_X_PADDING + prompt_width, + BAR_Y_PADDING + s->font->max_bounds.ascent, str, + cur_len); } - else if (!IsModifierKey (ch)) + else { str[cur_len] = ch; if (cur_len < len - 1) cur_len++; - XDrawString (dpy, s->input_window, s->bold_gc, 5 + prompt_width, - BAR_PADDING + s->font->max_bounds.ascent, str, cur_len); + XDrawString (dpy, s->input_window, s->bold_gc, + BAR_X_PADDING + prompt_width, + BAR_Y_PADDING + s->font->max_bounds.ascent, str, cur_len); } + + read_key (&ch, &modifier); } str[cur_len] = 0; diff --git a/src/input.h b/src/input.h index b00414d..ef2b4d3 100644 --- a/src/input.h +++ b/src/input.h @@ -1,2 +1,4 @@ -void cook_keycode (KeyCode keycode, KeySym *keysym, int *mod); +char *keysym_to_string (KeySym keysym, unsigned int modifier); +void cook_keycode (KeyCode keycode, KeySym *keysym, unsigned int *mod); void get_input (screen_info *s, char *prompt, char *str, int len); +void read_key (KeySym *keysym, unsigned int *mode); diff --git a/src/list.c b/src/list.c index fa06f69..8cdb38a 100644 --- a/src/list.c +++ b/src/list.c @@ -154,18 +154,19 @@ find_window_by_name (char *name) return NULL; } -void +int goto_window_name (char *name) { rp_window *win; if ((win = find_window_by_name (name)) == NULL) { - return; + return 0; } rp_current_window = win; set_active_window (rp_current_window); + return 1; } rp_window * diff --git a/src/list.h b/src/list.h index 15b1d98..9004ed7 100644 --- a/src/list.h +++ b/src/list.h @@ -31,7 +31,7 @@ void maximize_current_window (); void set_active_window (rp_window *rp_w); void set_current_window (rp_window *win); void goto_window_number (int n); -void goto_window_name (char *name); +int goto_window_name (char *name); rp_window *find_last_accessed_window (); rp_window *find_window_by_number (int n); #endif /* _LIST_H */ -- cgit v1.2.3