/* -*- mode: C; mode: fold; -*- */ /* Copyright (c) 1992, 1998, 2000, 2002, 2003, 2004, 2005, 2006 John E. Davis * This file is part of JED editor library source. * * You may distribute this file under the terms the GNU General Public * License. See the file COPYING for more information. */ #include "config.h" #include "jed-feat.h" /*{{{ Include Files */ #include #include #include #ifdef HAS_MOUSE #include "jdmacros.h" #include "buffer.h" #include "sysdep.h" #include "keymap.h" #include "misc.h" #include "paste.h" #include "screen.h" #include "ledit.h" #include "ins.h" #include "display.h" #include "hooks.h" /*}}}*/ int (*JMouse_Event_Hook)(void); void (*JMouse_Hide_Mouse_Hook) (int); /*{{{ Static Global Variables */ static SLang_Name_Type *Jed_Default_Mouse_Down_Hook; static SLang_Name_Type *Jed_Mouse_Status_Down_Hook; static SLang_Name_Type *Jed_Default_Mouse_Up_Hook; static SLang_Name_Type *Jed_Mouse_Status_Up_Hook; static SLang_Name_Type *Jed_Default_Mouse_Drag_Hook; static SLang_Name_Type *Jed_Mouse_Status_Drag_Hook; #if JED_HAS_MULTICLICK static SLang_Name_Type *Jed_Mouse_Status_2Click_Hook; static SLang_Name_Type *Jed_Mouse_Status_3Click_Hook; static SLang_Name_Type *Jed_Default_Mouse_2Click_Hook; static SLang_Name_Type *Jed_Default_Mouse_3Click_Hook; #endif static Window_Type *Use_This_Window; static Window_Type *Save_Window; static unsigned int Down_Mask; #ifdef IBMPC_SYSTEM # define JED_MOUSE_MAX_QUEUE_SIZE 8 #else # define JED_MOUSE_MAX_QUEUE_SIZE 64 #endif static JMouse_Type Mouse_Queue [JED_MOUSE_MAX_QUEUE_SIZE]; static JMouse_Type Current_Event; static int Mouse_Queue_Hint; static unsigned char Mouse_Button_Map [6] = { JMOUSE_BUTTON_1, JMOUSE_BUTTON_2, JMOUSE_BUTTON_3, JMOUSE_BUTTON_4, JMOUSE_BUTTON_5, JMOUSE_BUTTON_6 }; /*}}}*/ #ifndef USE_GPM_MOUSE # if defined(__MSDOS__) # if !defined(MSWINDOWS) # include "pcmouse.c" # endif # else # ifdef __os2__ # include "os2mouse.c" # else int (*X_Open_Mouse_Hook)(void); void (*X_Close_Mouse_Hook)(void); # endif /* os2 */ # endif /* ibmpc */ #endif /* NOT USE_GPM_MOUSE */ #if JED_HAS_TTY_MENUS static int Hack_Hack = 1; static Window_Type *Non_Existent_Menu_Window = (Window_Type *)&Hack_Hack; #endif #define BUFFER_STATUS_LINE 1 #define MENU_BAR_STATUS 2 /* returns button number from map */ static unsigned char m2b (int m) { switch (m) { default: case 0x01: return 0; case 0x02: return 1; case 0x04: return 2; case 0x08: return 3; case 0x10: return 4; case 0x20: return 5; } } /* *ap and *bp must have one of values in set (1, 2, 4, 8, 16, 32, 64). */ void jed_map_mouse_buttons (int *ap, int *bp) /*{{{*/ { unsigned char a, b; a = m2b (*ap); b = m2b (*bp); if ((a > 5) || (b > 5)) return; Mouse_Button_Map [a] = b << 1; } /*}}}*/ int jed_mouse_add_event (JMouse_Type *ev) /*{{{*/ { int save = Mouse_Queue_Hint; /* Search the queue looking for an empty slot. */ while (Mouse_Queue_Hint < JED_MOUSE_MAX_QUEUE_SIZE) { if (Mouse_Queue[Mouse_Queue_Hint].type == 0) { Mouse_Queue [Mouse_Queue_Hint] = *ev; return Mouse_Queue_Hint; } Mouse_Queue_Hint++; } Mouse_Queue_Hint = save; while (Mouse_Queue_Hint > 0) { Mouse_Queue_Hint--; if (Mouse_Queue[Mouse_Queue_Hint].type == 0) { Mouse_Queue [Mouse_Queue_Hint] = *ev; return Mouse_Queue_Hint; } } if (Input_Buffer_Len == 0) { jed_flush_mouse_queue (); Mouse_Queue [0] = *ev; return 0; } return -1; } /*}}}*/ static JMouse_Type *get_mouse_event (unsigned int *type) /*{{{*/ { int queue_pos; JMouse_Type *jm; /* Keyboard input should be ready. If it is not, get out. */ if (0 == input_pending (&Number_Zero)) return NULL; queue_pos = jed_getkey (); if ((queue_pos >= JED_MOUSE_MAX_QUEUE_SIZE) || (queue_pos < 0)) return NULL; jm = Mouse_Queue + queue_pos; /* 1, 2, 4, 8,..., 32 --> Mouse_Button_Map of 0, 1, 2, ... 5 */ jm->button = Mouse_Button_Map [m2b(jm->button)]; *type = jm->type; jm->type = 0; Mouse_Queue_Hint = queue_pos; return jm; } /*}}}*/ void jed_mouse_get_event_info (void) /*{{{*/ { SLang_push_integer (Current_Event.x); SLang_push_integer (Current_Event.y); SLang_push_integer (Current_Event.state); } /*}}}*/ void jed_flush_mouse_queue (void) /*{{{*/ { unsigned int i; for (i = 0; i < JED_MOUSE_MAX_QUEUE_SIZE; i++) Mouse_Queue[i].type = 0; Mouse_Queue_Hint = 0; } /*}}}*/ static int window_exists (Window_Type *win) /*{{{*/ { Window_Type *w; w = JWindow; do { if (w == win) return 1; w = w->next; } while (w != JWindow); return 0; } /*}}}*/ static int switch_to_event_window (int x, int y, int *linep, int *colp, int *status) /*{{{*/ { Window_Type *w; int delta_y; static int last_status; *status = 0; if (Use_This_Window != NULL) { #if JED_HAS_TTY_MENUS if (Use_This_Window == Non_Existent_Menu_Window) { *status = last_status = MENU_BAR_STATUS; *colp = x; *linep = y; return 0; } #endif if (0 == window_exists (Use_This_Window)) { last_status = 0; return -1; } *status = last_status; } else { #if JED_HAS_TTY_MENUS if (Jed_Menus_Active || ((y == 1) && (Top_Window_SY != 0))) { Use_This_Window = Non_Existent_Menu_Window; *colp = x; *linep = y; *status = last_status = MENU_BAR_STATUS; return 0; } #endif w = JWindow; do { int sy, bot; sy = w->sy; bot = sy + w->rows + 1; if ((y >= sy) && (y < bot)) { Use_This_Window = w; break; } if (y == bot) { Use_This_Window = w; *status = BUFFER_STATUS_LINE; break; } w = w->next; } while (w != JWindow); } if (Use_This_Window == NULL) { last_status = 0; return -1; } while (JWindow != Use_This_Window) other_window (); last_status = *status; if (last_status) { *colp = x; return 0; } /* What line does y correspond ??? */ delta_y = y - (Use_This_Window->sy + window_line ()); y = LineNum; #if JED_HAS_LINE_ATTRIBUTES if (delta_y == 0) { Line *l = CLine; while ((l != NULL) && (l->flags & JED_LINE_HIDDEN)) { y--; l = l->prev; } } else if (delta_y > 0) { Line *l = CLine; while (delta_y && (l != NULL)) { if (0 == (l->flags & JED_LINE_HIDDEN)) delta_y--; l = l->next; y++; } while ((l != NULL) && (l->flags & JED_LINE_HIDDEN)) { l = l->next; y++; } } else if (delta_y < 0) { Line *l = CLine; while (delta_y && (l != NULL)) { if (0 == (l->flags & JED_LINE_HIDDEN)) delta_y++; l = l->prev; y--; } while ((l != NULL) && (l->flags & JED_LINE_HIDDEN)) { l = l->prev; y--; } } #endif *linep = y + delta_y; *colp = JWindow->hscroll_column + x - 1; return 0; } /*}}}*/ static int do_function (SLang_Name_Type *fun, int line, int col, int button, int shift) /*{{{*/ { int ret; if ((-1 == SLang_start_arg_list ()) || (-1 == SLang_push_integer (line)) || (-1 == SLang_push_integer (col)) || (-1 == SLang_push_integer (button)) || (-1 == SLang_push_integer (shift)) || (-1 == SLang_end_arg_list ())) return 1; if ((-1 == SLexecute_function (fun)) || (-1 == SLang_pop_integer (&ret))) ret = 1; return ret; } /*}}}*/ static void switch_to_window (Window_Type *w) /*{{{*/ { if (window_exists (w)) { while (JWindow != w) other_window (); } } /*}}}*/ static int do_mouse_cmd (JMouse_Type *jmouse, unsigned int type) /*{{{*/ { int button, shift; int linenum, column, is_status; int ret; SLang_Name_Type *fun, *default_fun; Jed_Buffer_Hook_Type *h = CBuf->buffer_hooks; button = jmouse->button; /* Consistency check */ if (type == JMOUSE_DOWN) { if (Down_Mask & button) { Down_Mask = 0; return 0; } Save_Window = JWindow; } else if ((0 == (Down_Mask & button)) && (type != JMOUSE_DOUBLE_CLICK) && (type != JMOUSE_TRIPLE_CLICK)) { Down_Mask = 0; return 0; } if (Down_Mask == 0) Use_This_Window = NULL; if (-1 == switch_to_event_window (jmouse->x, jmouse->y, &linenum, &column, &is_status)) { Down_Mask = 0; Use_This_Window = NULL; return 0; } default_fun = NULL; fun = NULL; switch (type) { case JMOUSE_DRAG: if (is_status) fun = Jed_Mouse_Status_Drag_Hook; else { if (h != NULL) fun = h->mouse_drag_hook; default_fun = Jed_Default_Mouse_Drag_Hook; } break; #if JED_HAS_MULTICLICK case JMOUSE_DOUBLE_CLICK: if (is_status) fun = Jed_Mouse_Status_2Click_Hook; else { if (h != NULL) fun = h->mouse_2click_hook; default_fun = Jed_Default_Mouse_2Click_Hook; } break; case JMOUSE_TRIPLE_CLICK: if (is_status) fun = Jed_Mouse_Status_3Click_Hook; else { if (h != NULL) fun = h->mouse_3click_hook; default_fun = Jed_Default_Mouse_3Click_Hook; } break; #endif case JMOUSE_DOWN: Down_Mask |= button; if (is_status) fun = Jed_Mouse_Status_Down_Hook; else { if (h != NULL) fun = h->mouse_down_hook; default_fun = Jed_Default_Mouse_Down_Hook; } break; case JMOUSE_UP: Down_Mask &= ~button; if (is_status) fun = Jed_Mouse_Status_Up_Hook; else { if (h != NULL) fun = h->mouse_up_hook; default_fun = Jed_Default_Mouse_Up_Hook; } break; default: flush_input (); fun = NULL; } if (jmouse->state & JMOUSE_SHIFT) shift = 1; else if (jmouse->state & JMOUSE_CTRL) shift = 2; else shift = 0; #if JED_HAS_TTY_MENUS if (is_status == MENU_BAR_STATUS) return jed_menu_handle_mouse (type, column, linenum, button, shift); #endif ret = -1; if (fun != NULL) { ret = do_function (fun, linenum, column, button, shift); } if ((ret == -1) && (default_fun != NULL)) { ret = do_function (default_fun, linenum, column, button, shift); } if ((type == JMOUSE_UP) && (Down_Mask == 0) && (ret <= 0)) { switch_to_window (Save_Window); Save_Window = NULL; } return ret; } /*}}}*/ int jed_mouse_cmd (void) /*{{{*/ { unsigned int type; JMouse_Type *jmouse; if ((NULL == (jmouse = get_mouse_event (&type))) || (type == JMOUSE_IGNORE_EVENT)) return 0; Current_Event = *jmouse; #if JED_HAS_MULTICLICK if ((-1 == do_mouse_cmd (jmouse, type)) && ((type == JMOUSE_DOUBLE_CLICK) || (type == JMOUSE_TRIPLE_CLICK))) { /* Event multiclick event not handled so simulated click. */ (void) do_mouse_cmd (&Current_Event, JMOUSE_DOWN); (void) do_mouse_cmd (&Current_Event, JMOUSE_UP); } #else (void) do_mouse_cmd (jmouse, type); #endif return 1; } /*}}}*/ void jed_set_current_mouse_window (void) /*{{{*/ { switch_to_window (Save_Window); } /*}}}*/ void jed_set_default_mouse_hook (char *hook_name, char *function) /*{{{*/ { SLang_Name_Type *f; f = SLang_get_function (function); if (!strcmp ("mouse_drag", hook_name)) Jed_Default_Mouse_Drag_Hook = f; else if (!strcmp ("mouse_up", hook_name)) Jed_Default_Mouse_Up_Hook = f; else if (!strcmp ("mouse_down", hook_name)) Jed_Default_Mouse_Down_Hook = f; else if (!strcmp ("mouse_status_up", hook_name)) Jed_Mouse_Status_Up_Hook = f; else if (!strcmp ("mouse_status_down", hook_name)) Jed_Mouse_Status_Down_Hook = f; else if (!strcmp ("mouse_status_drag", hook_name)) Jed_Mouse_Status_Drag_Hook = f; else if (!strcmp ("mouse_status_drag", hook_name)) Jed_Mouse_Status_Drag_Hook = f; #if JED_HAS_MULTICLICK else if (!strcmp ("mouse_2click", hook_name)) Jed_Default_Mouse_2Click_Hook = f; else if (!strcmp ("mouse_3click", hook_name)) Jed_Default_Mouse_3Click_Hook = f; #endif } /*}}}*/ #endif /* HAS_MOUSE */