editwidget.c 33 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219
  1. /* editor initialisation and callback handler.
  2. Copyright (C) 1996, 1997 the Free Software Foundation
  3. Authors: 1996, 1997 Paul Sheer
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
  15. #include <config.h>
  16. #include "edit.h"
  17. #ifndef MIDNIGHT
  18. #include <X11/Xmd.h> /* CARD32 */
  19. #include <X11/Xatom.h>
  20. #ifndef GTK
  21. #include "app_glob.c"
  22. #include "coollocal.h"
  23. #endif
  24. #include "editcmddef.h"
  25. #include "mousemark.h"
  26. #endif
  27. #ifndef MIDNIGHT
  28. extern int EditExposeRedraw;
  29. CWidget *wedit = 0;
  30. void edit_destroy_callback (CWidget * w)
  31. {
  32. if (w) {
  33. edit_clean (w->editor);
  34. if (w->editor)
  35. free (w->editor);
  36. w->editor = NULL;
  37. } else
  38. /* NLS ? */
  39. CError ("Trying to destroy non-existing editor widget.\n");
  40. }
  41. #ifdef GTK
  42. #else
  43. void link_hscrollbar_to_editor (CWidget * scrollbar, CWidget * editor, XEvent * xevent, CEvent * cwevent, int whichscrbutton);
  44. #endif
  45. /* returns the position in the edit buffer of a window click */
  46. long edit_get_click_pos (WEdit * edit, int x, int y)
  47. {
  48. long click;
  49. /* (1) goto to left margin */
  50. click = edit_bol (edit, edit->curs1);
  51. /* (1) move up or down */
  52. if (y > (edit->curs_row + 1))
  53. click = edit_move_forward (edit, click, y - (edit->curs_row + 1), 0);
  54. if (y < (edit->curs_row + 1))
  55. click = edit_move_backward (edit, click, (edit->curs_row + 1) - y);
  56. /* (3) move right to x pos */
  57. click = edit_move_forward3 (edit, click, x - edit->start_col - 1, 0);
  58. return click;
  59. }
  60. void edit_translate_xy (int xs, int ys, int *x, int *y)
  61. {
  62. *x = xs - EDIT_TEXT_HORIZONTAL_OFFSET;
  63. *y = (ys - EDIT_TEXT_VERTICAL_OFFSET - option_text_line_spacing / 2 - 1) / FONT_PIX_PER_LINE + 1;
  64. }
  65. extern int just_dropped_something;
  66. static void mouse_redraw (WEdit * edit, long click)
  67. {
  68. edit->force |= REDRAW_PAGE | REDRAW_LINE;
  69. edit_update_curs_row (edit);
  70. edit_update_curs_col (edit);
  71. edit->prev_col = edit_get_col (edit);
  72. edit_update_screen (edit);
  73. edit->search_start = click;
  74. }
  75. static void xy (int x, int y, int *x_return, int *y_return)
  76. {
  77. edit_translate_xy (x, y, x_return, y_return);
  78. }
  79. static long cp (WEdit *edit, int x, int y)
  80. {
  81. return edit_get_click_pos (edit, x, y);
  82. }
  83. /* return 1 if not marked */
  84. static int marks (WEdit * edit, long *start, long *end)
  85. {
  86. return eval_marks (edit, start, end);
  87. }
  88. int column_highlighting = 0;
  89. static int erange (WEdit * edit, long start, long end, int click)
  90. {
  91. if (column_highlighting) {
  92. int x;
  93. x = edit_move_forward3 (edit, edit_bol (edit, click), 0, click);
  94. if ((x >= edit->column1 && x < edit->column2)
  95. || (x > edit->column2 && x <= edit->column1))
  96. return (start <= click && click < end);
  97. else
  98. return 0;
  99. }
  100. return (start <= click && click < end);
  101. }
  102. static void fin_mark (WEdit *edit)
  103. {
  104. if (edit->mark2 < 0)
  105. edit_mark_cmd (edit, 0);
  106. }
  107. static void move_mark (WEdit *edit)
  108. {
  109. edit_mark_cmd (edit, 1);
  110. edit_mark_cmd (edit, 0);
  111. }
  112. static void release_mark (WEdit *edit, XEvent *event)
  113. {
  114. if (edit->mark2 < 0)
  115. edit_mark_cmd (edit, 0);
  116. else
  117. edit_mark_cmd (edit, 1);
  118. if (edit->mark1 != edit->mark2 && event) {
  119. edit_get_selection (edit);
  120. #ifdef GTK
  121. #if 0
  122. /* *** */
  123. gtk_set_selection_owner (CWindowOf (edit->widget));
  124. #endif
  125. #else
  126. XSetSelectionOwner (CDisplay, XA_PRIMARY, CWindowOf (edit->widget), event->xbutton.time);
  127. #endif
  128. }
  129. }
  130. static char *get_block (WEdit * edit, long start_mark, long end_mark, int *type, int *l)
  131. {
  132. char *t;
  133. t = (char *) edit_get_block (edit, start_mark, end_mark, l);
  134. if (strlen (t) < *l)
  135. *type = DndRawData; /* if there are nulls in the data, send as raw */
  136. else
  137. *type = DndText; /* else send as text */
  138. return t;
  139. }
  140. static void move (WEdit *edit, long click, int y)
  141. {
  142. edit_cursor_move (edit, click - edit->curs1);
  143. }
  144. static void dclick (WEdit *edit, XEvent *event)
  145. {
  146. edit_mark_cmd (edit, 1);
  147. edit_right_word_move (edit);
  148. edit_mark_cmd (edit, 0);
  149. edit_left_word_move (edit);
  150. release_mark (edit, event);
  151. }
  152. static void redraw (WEdit *edit, long click)
  153. {
  154. mouse_redraw (edit, click);
  155. }
  156. void edit_insert_column_of_text (WEdit * edit, unsigned char *data, int size, int width);
  157. /* strips out the first i chars and returns a null terminated string, result must be free'd */
  158. char *filename_from_url (char *data, int size, int i)
  159. {
  160. char *p, *f;
  161. int l;
  162. for (p = data + i; (unsigned long) p - (unsigned long) data < size && *p && *p != '\n'; p++);
  163. l = (unsigned long) p - (unsigned long) data - i;
  164. f = malloc (l + 1);
  165. memcpy (f, data + i, l);
  166. f[l] = '\0';
  167. return f;
  168. }
  169. static int insert_drop (WEdit * e, Window from, unsigned char *data, int size, int xs, int ys, Atom type, Atom action)
  170. {
  171. #ifndef GTK
  172. long start_mark = 0, end_mark = 0;
  173. int x, y;
  174. edit_translate_xy (xs, ys, &x, &y);
  175. /* musn't be able to drop into a block, otherwise a single click will copy a block: */
  176. if (eval_marks (e, &start_mark, &end_mark))
  177. goto fine;
  178. if (start_mark > e->curs1 || e->curs1 >= end_mark)
  179. goto fine;
  180. if (column_highlighting) {
  181. if (!((x >= e->column1 && x < e->column2)
  182. || (x > e->column2 && x <= e->column1)))
  183. goto fine;
  184. }
  185. return 1;
  186. fine:
  187. if (from == e->widget->winid && action == CDndClass->XdndActionMove) {
  188. edit_block_move_cmd (e);
  189. edit_mark_cmd (e, 1);
  190. return 0;
  191. } else if (from == e->widget->winid) {
  192. edit_block_copy_cmd (e);
  193. return 0;
  194. } else { /* data from another widget, or from another application */
  195. edit_push_action (e, KEY_PRESS + e->start_display);
  196. if (type == XInternAtom (CDisplay, "url/url", False)) {
  197. if (!strncmp ((char *) data, "file:/", 6)) {
  198. char *f;
  199. edit_insert_file (e, f = filename_from_url ((char *) data, size, strlen ("file:")));
  200. free (f);
  201. } else {
  202. while (size--)
  203. edit_insert_ahead (e, data[size]);
  204. }
  205. } else {
  206. if (column_highlighting) {
  207. edit_insert_column_of_text (e, data, size, abs (e->column2 - e->column1));
  208. } else {
  209. while (size--)
  210. edit_insert_ahead (e, data[size]);
  211. }
  212. }
  213. }
  214. CExpose (e->widget->ident);
  215. #endif
  216. return 0;
  217. }
  218. static char *mime_majors[2] =
  219. {"text", 0};
  220. struct mouse_funcs edit_mouse_funcs =
  221. {
  222. 0,
  223. (void (*)(int, int, int *, int *)) xy,
  224. (long (*)(void *, int, int)) cp,
  225. (int (*)(void *, long *, long *)) marks,
  226. (int (*)(void *, long, long, long)) erange,
  227. (void (*)(void *)) fin_mark,
  228. (void (*)(void *)) move_mark,
  229. (void (*)(void *, XEvent *)) release_mark,
  230. (char *(*)(void *, long, long, int *, int *)) get_block,
  231. (void (*)(void *, long, int)) move,
  232. 0,
  233. (void (*)(void *, XEvent *)) dclick,
  234. (void (*)(void *, long)) redraw,
  235. (int (*)(void *, Window, unsigned char *, int, int, int, Atom, Atom)) insert_drop,
  236. (void (*)(void *)) edit_block_delete,
  237. DndText,
  238. mime_majors
  239. };
  240. #ifndef GTK
  241. extern int option_editor_bg_normal;
  242. void edit_tri_cursor (Window win);
  243. /* starting_directory is for the filebrowser */
  244. CWidget *CDrawEditor (const char *identifier, Window parent, int x, int y,
  245. int width, int height, const char *text, const char *filename,
  246. const char *starting_directory, unsigned int options, unsigned long text_size)
  247. {
  248. static made_directory = 0;
  249. int extra_space_for_hscroll = 0;
  250. CWidget *w;
  251. WEdit *e;
  252. if (options & EDITOR_HORIZ_SCROLL)
  253. extra_space_for_hscroll = 8;
  254. wedit = w = CSetupWidget (identifier, parent, x, y,
  255. width + 7, height + 6, C_EDITOR_WIDGET,
  256. ExposureMask | ButtonPressMask | ButtonReleaseMask | \
  257. KeyPressMask | KeyReleaseMask | ButtonMotionMask | \
  258. PropertyChangeMask | StructureNotifyMask | \
  259. EnterWindowMask | LeaveWindowMask, color_palette (option_editor_bg_normal), 1);
  260. xdnd_set_dnd_aware (CDndClass, w->winid, 0);
  261. xdnd_set_type_list (CDndClass, w->winid, xdnd_typelist_send[DndText]);
  262. edit_tri_cursor (w->winid);
  263. w->options = options | WIDGET_TAKES_SELECTION;
  264. w->destroy = edit_destroy_callback;
  265. if (filename)
  266. w->label = strdup (filename);
  267. else
  268. w->label = strdup ("");
  269. if (!made_directory) {
  270. mkdir (catstrs (home_dir, EDIT_DIR, 0), 0700);
  271. made_directory = 1;
  272. }
  273. e = w->editor = CMalloc (sizeof (WEdit));
  274. w->funcs = mouse_funcs_new (w->editor, &edit_mouse_funcs);
  275. if (!w->editor) {
  276. /* Not essential to translate */
  277. CError (_ ("Error initialising editor.\n"));
  278. return 0;
  279. }
  280. w->editor->widget = w;
  281. w->editor = edit_init (e, height / FONT_PIX_PER_LINE, width / FONT_MEAN_WIDTH, filename, text, starting_directory, text_size);
  282. w->funcs->data = (void *) w->editor;
  283. if (!w->editor) {
  284. free (e);
  285. CDestroyWidget (w->ident);
  286. return 0;
  287. }
  288. e->macro_i = -1;
  289. e->widget = w;
  290. set_hint_pos (x + width + 7 + WIDGET_SPACING, y + height + 6 + WIDGET_SPACING + extra_space_for_hscroll);
  291. if (extra_space_for_hscroll) {
  292. w->hori_scrollbar = CDrawHorizontalScrollbar (catstrs (identifier, ".hsc", 0), parent,
  293. x, y + height + 6, width + 6, 12, 0, 0);
  294. CSetScrollbarCallback (w->hori_scrollbar->ident, w->ident, link_hscrollbar_to_editor);
  295. }
  296. if (!(options & EDITOR_NO_TEXT))
  297. CDrawText (catstrs (identifier, ".text", 0), parent, x, y + height + 6 + WIDGET_SPACING + extra_space_for_hscroll, "%s", e->filename);
  298. if (!(options & EDITOR_NO_SCROLL)) {
  299. w->vert_scrollbar = CDrawVerticalScrollbar (catstrs (identifier, ".vsc", 0), parent,
  300. x + width + 7 + WIDGET_SPACING, y, height + 6, 20, 0, 0);
  301. CSetScrollbarCallback (w->vert_scrollbar->ident, w->ident, link_scrollbar_to_editor);
  302. }
  303. return w;
  304. }
  305. #endif
  306. #ifdef GTK
  307. void update_scroll_bars (WEdit * e)
  308. {
  309. }
  310. #else
  311. void update_scroll_bars (WEdit * e)
  312. {
  313. int i, x1, x2;
  314. CWidget *scroll;
  315. scroll = e->widget->vert_scrollbar;
  316. if (scroll) {
  317. i = e->total_lines - e->start_line + 1;
  318. if (i > e->num_widget_lines)
  319. i = e->num_widget_lines;
  320. if (e->total_lines) {
  321. x1 = (double) 65535.0 *e->start_line / (e->total_lines + 1);
  322. x2 = (double) 65535.0 *i / (e->total_lines + 1);
  323. } else {
  324. x1 = 0;
  325. x2 = 65535;
  326. }
  327. if (x1 != scroll->firstline || x2 != scroll->numlines) {
  328. scroll->firstline = x1;
  329. scroll->numlines = x2;
  330. EditExposeRedraw = 1;
  331. render_scrollbar (scroll);
  332. EditExposeRedraw = 0;
  333. }
  334. }
  335. scroll = e->widget->hori_scrollbar;
  336. if (scroll) {
  337. i = e->max_column - (-e->start_col) + 1;
  338. if (i > e->num_widget_columns * FONT_MEAN_WIDTH)
  339. i = e->num_widget_columns * FONT_MEAN_WIDTH;
  340. x1 = (double) 65535.0 *(-e->start_col) / (e->max_column + 1);
  341. x2 = (double) 65535.0 *i / (e->max_column + 1);
  342. if (x1 != scroll->firstline || x2 != scroll->numlines) {
  343. scroll->firstline = x1;
  344. scroll->numlines = x2;
  345. EditExposeRedraw = 1;
  346. render_scrollbar (scroll);
  347. EditExposeRedraw = 0;
  348. }
  349. }
  350. }
  351. #endif
  352. void edit_mouse_mark (WEdit * edit, XEvent * event, int double_click)
  353. {
  354. edit_update_curs_row (edit);
  355. edit_update_curs_col (edit);
  356. if (event->type != MotionNotify) {
  357. edit_push_action (edit, KEY_PRESS + edit->start_display);
  358. if (edit->mark2 == -1)
  359. edit_push_action (edit, MARK_1 + edit->mark1); /* mark1 must be following the cursor */
  360. }
  361. if (event->type == ButtonPress) {
  362. edit->highlight = 0;
  363. edit->found_len = 0;
  364. }
  365. mouse_mark (
  366. event,
  367. double_click,
  368. edit->widget->funcs
  369. );
  370. }
  371. #ifdef GTK
  372. #else
  373. void link_scrollbar_to_editor (CWidget * scrollbar, CWidget * editor, XEvent * xevent, CEvent * cwevent, int whichscrbutton)
  374. {
  375. int i, start_line;
  376. WEdit *e;
  377. e = editor->editor;
  378. if (!e)
  379. return;
  380. if (!e->widget->vert_scrollbar)
  381. return;
  382. start_line = e->start_line;
  383. if ((xevent->type == ButtonRelease || xevent->type == MotionNotify) && whichscrbutton == 3) {
  384. edit_move_display (e, (double) scrollbar->firstline * e->total_lines / 65535.0 + 1);
  385. } else if (xevent->type == ButtonPress && (cwevent->button == Button1 || cwevent->button == Button2)) {
  386. switch (whichscrbutton) {
  387. case 1:
  388. edit_move_display (e, e->start_line - e->num_widget_lines + 1);
  389. break;
  390. case 2:
  391. edit_move_display (e, e->start_line - 1);
  392. break;
  393. case 5:
  394. edit_move_display (e, e->start_line + 1);
  395. break;
  396. case 4:
  397. edit_move_display (e, e->start_line + e->num_widget_lines - 1);
  398. break;
  399. }
  400. }
  401. if (e->total_lines)
  402. scrollbar->firstline = (double) 65535.0 *e->start_line / (e->total_lines + 1);
  403. else
  404. scrollbar->firstline = 0;
  405. i = e->total_lines - e->start_line + 1;
  406. if (i > e->num_widget_lines)
  407. i = e->num_widget_lines;
  408. if (e->total_lines)
  409. scrollbar->numlines = (double) 65535.0 *i / (e->total_lines + 1);
  410. else
  411. scrollbar->numlines = 65535;
  412. if (start_line != e->start_line) {
  413. e->force |= REDRAW_PAGE | REDRAW_LINE;
  414. set_cursor_position (0, 0, 0, 0, 0, 0, 0, 0, 0);
  415. if (CCheckWindowEvent (xevent->xany.window, ButtonReleaseMask | ButtonMotionMask, 0))
  416. return;
  417. }
  418. if (e->force) {
  419. edit_render_keypress (e);
  420. edit_status (e);
  421. }
  422. }
  423. #endif
  424. #ifdef GTK
  425. #else
  426. void link_hscrollbar_to_editor (CWidget * scrollbar, CWidget * editor, XEvent * xevent, CEvent * cwevent, int whichscrbutton)
  427. {
  428. int i, start_col;
  429. WEdit *e;
  430. e = editor->editor;
  431. if (!e)
  432. return;
  433. if (!e->widget->hori_scrollbar)
  434. return;
  435. start_col = (-e->start_col);
  436. if ((xevent->type == ButtonRelease || xevent->type == MotionNotify) && whichscrbutton == 3) {
  437. e->start_col = (double) scrollbar->firstline * e->max_column / 65535.0 + 1;
  438. e->start_col -= e->start_col % FONT_MEAN_WIDTH;
  439. if (e->start_col < 0)
  440. e->start_col = 0;
  441. e->start_col = (-e->start_col);
  442. } else if (xevent->type == ButtonPress && (cwevent->button == Button1 || cwevent->button == Button2)) {
  443. switch (whichscrbutton) {
  444. case 1:
  445. edit_scroll_left (e, (e->num_widget_columns - 1) * FONT_MEAN_WIDTH);
  446. break;
  447. case 2:
  448. edit_scroll_left (e, FONT_MEAN_WIDTH);
  449. break;
  450. case 5:
  451. edit_scroll_right (e, FONT_MEAN_WIDTH);
  452. break;
  453. case 4:
  454. edit_scroll_right (e, (e->num_widget_columns - 1) * FONT_MEAN_WIDTH);
  455. break;
  456. }
  457. }
  458. scrollbar->firstline = (double) 65535.0 *(-e->start_col) / (e->max_column + 1);
  459. i = e->max_column - (-e->start_col) + 1;
  460. if (i > e->num_widget_columns * FONT_MEAN_WIDTH)
  461. i = e->num_widget_columns * FONT_MEAN_WIDTH;
  462. scrollbar->numlines = (double) 65535.0 *i / (e->max_column + 1);
  463. if (start_col != (-e->start_col)) {
  464. e->force |= REDRAW_PAGE | REDRAW_LINE;
  465. set_cursor_position (0, 0, 0, 0, 0, 0, 0, 0, 0);
  466. if (CCheckWindowEvent (xevent->xany.window, ButtonReleaseMask | ButtonMotionMask, 0))
  467. return;
  468. }
  469. if (e->force) {
  470. edit_render_keypress (e);
  471. edit_status (e);
  472. }
  473. }
  474. #endif
  475. /*
  476. This section comes from rxvt-2.21b1/src/screen.c by
  477. Robert Nation <nation@rocket.sanders.lockheed.com> &
  478. mods by mj olesen <olesen@me.QueensU.CA>
  479. Changes made for cooledit
  480. */
  481. void selection_send (XSelectionRequestEvent * rq)
  482. {
  483. XEvent ev;
  484. static Atom xa_targets = None;
  485. if (xa_targets == None)
  486. xa_targets = XInternAtom (CDisplay, "TARGETS", False);
  487. ev.xselection.type = SelectionNotify;
  488. ev.xselection.property = None;
  489. ev.xselection.display = rq->display;
  490. ev.xselection.requestor = rq->requestor;
  491. ev.xselection.selection = rq->selection;
  492. ev.xselection.target = rq->target;
  493. ev.xselection.time = rq->time;
  494. if (rq->target == xa_targets) {
  495. /*
  496. * On some systems, the Atom typedef is 64 bits wide.
  497. * We need to have a typedef that is exactly 32 bits wide,
  498. * because a format of 64 is not allowed by the X11 protocol.
  499. */
  500. typedef CARD32 Atom32;
  501. Atom32 target_list[2];
  502. target_list[0] = (Atom32) xa_targets;
  503. target_list[1] = (Atom32) XA_STRING;
  504. XChangeProperty (CDisplay, rq->requestor, rq->property,
  505. xa_targets, 8 * sizeof (target_list[0]), PropModeReplace,
  506. (unsigned char *) target_list,
  507. sizeof (target_list) / sizeof (target_list[0]));
  508. ev.xselection.property = rq->property;
  509. } else if (rq->target == XA_STRING) {
  510. XChangeProperty (CDisplay, rq->requestor, rq->property,
  511. XA_STRING, 8, PropModeReplace,
  512. selection.text, selection.len);
  513. ev.xselection.property = rq->property;
  514. }
  515. XSendEvent (CDisplay, rq->requestor, False, 0, &ev);
  516. }
  517. /*{{{ paste selection */
  518. /*
  519. * Respond to a notification that a primary selection has been sent
  520. */
  521. void paste_prop (void *data, void (*insert) (void *, int), Window win, unsigned prop, int delete)
  522. {
  523. long nread;
  524. unsigned long bytes_after;
  525. if (prop == None)
  526. return;
  527. nread = 0;
  528. do {
  529. unsigned char *s;
  530. Atom actual_type;
  531. int actual_fmt, i;
  532. unsigned long nitems;
  533. #ifdef GTK
  534. #if 0
  535. /* *** */
  536. if (gtk_get_window_property (win, prop,
  537. nread / 4, 65536, delete,
  538. AnyPropertyType, &actual_type, &actual_fmt,
  539. &nitems, &bytes_after,
  540. &s) != Success) {
  541. XFree (s);
  542. return;
  543. }
  544. #endif
  545. #else
  546. if (XGetWindowProperty (CDisplay, win, prop,
  547. nread / 4, 65536, delete,
  548. AnyPropertyType, &actual_type, &actual_fmt,
  549. &nitems, &bytes_after,
  550. &s) != Success) {
  551. XFree (s);
  552. return;
  553. }
  554. #endif
  555. nread += nitems;
  556. for (i = 0; i < nitems; i++)
  557. (*insert) (data, s[i]);
  558. XFree (s);
  559. } while (bytes_after);
  560. }
  561. void selection_paste (WEdit * edit, Window win, unsigned prop, int delete)
  562. {
  563. long c;
  564. c = edit->curs1;
  565. paste_prop ((void *) edit,
  566. (void (*)(void *, int)) edit_insert,
  567. win, prop, delete);
  568. edit_cursor_move (edit, c - edit->curs1);
  569. edit->force |= REDRAW_COMPLETELY | REDRAW_LINE;
  570. }
  571. /*}}} */
  572. void selection_clear (void)
  573. {
  574. selection.text = 0;
  575. selection.len = 0;
  576. }
  577. void edit_update_screen (WEdit * e)
  578. {
  579. if (!e)
  580. return;
  581. if (!e->force)
  582. return;
  583. edit_scroll_screen_over_cursor (e);
  584. edit_update_curs_row (e);
  585. edit_update_curs_col (e);
  586. update_scroll_bars (e);
  587. edit_status (e);
  588. if (e->force & REDRAW_COMPLETELY)
  589. e->force |= REDRAW_PAGE;
  590. /* pop all events for this window for internal handling */
  591. if (e->force & (REDRAW_CHAR_ONLY | REDRAW_COMPLETELY)) {
  592. edit_render_keypress (e);
  593. #ifdef GTK
  594. } else if (
  595. #if 0
  596. /* *** */
  597. gtk_edit_key_pending () || gtk_edit_mouse_pending ()
  598. #else
  599. 0
  600. #endif
  601. ) {
  602. #else
  603. } else if (CCheckWindowEvent (e->widget->winid, ButtonPressMask | ButtonReleaseMask | ButtonMotionMask, 0)
  604. || CKeyPending ()) {
  605. #endif
  606. e->force |= REDRAW_PAGE;
  607. return;
  608. } else {
  609. edit_render_keypress (e);
  610. }
  611. }
  612. extern int space_width;
  613. #ifdef HAVE_DND
  614. #define free_data if (data) {free(data);data=0;}
  615. /* handles drag and drop */
  616. void handle_client_message (CWidget * w, XEvent * xevent)
  617. {
  618. int data_type;
  619. unsigned char *data = 0;
  620. unsigned long size;
  621. int xs, ys;
  622. long start_line;
  623. int x, y, r, deleted = 0;
  624. long click;
  625. unsigned int state;
  626. long start_mark = 0, end_mark = 0;
  627. WEdit *e = w->editor;
  628. /* see just below for a comment on what this is for: */
  629. if (CIsDropAcknowledge (xevent, &state) != DndNotDnd) {
  630. if (!(state & Button1Mask) && just_dropped_something) {
  631. edit_push_action (e, KEY_PRESS + e->start_display);
  632. edit_block_delete_cmd (e);
  633. }
  634. return;
  635. }
  636. data_type = CGetDrop (xevent, &data, &size, &xs, &ys);
  637. if (data_type == DndNotDnd || xs < 0 || ys < 0 || xs >= CWidthOf (w) || ys >= CHeightOf (w)) {
  638. free_data;
  639. return;
  640. }
  641. edit_translate_xy (xs, ys, &x, &y);
  642. click = edit_get_click_pos (e, x, y);
  643. r = eval_marks (e, &start_mark, &end_mark);
  644. /* musn't be able to drop into a block, otherwise a single click will copy a block: */
  645. if (r)
  646. goto fine;
  647. if (start_mark > click || click >= end_mark)
  648. goto fine;
  649. if (column_highlighting) {
  650. if (!((x >= e->column1 && x < e->column2)
  651. || (x > e->column2 && x <= e->column1)))
  652. goto fine;
  653. }
  654. free_data;
  655. return;
  656. fine:
  657. edit_push_action (e, KEY_PRESS + e->start_display);
  658. /* drops to the same window moving to the left: */
  659. start_line = e->start_line;
  660. if (xevent->xclient.data.l[2] == xevent->xclient.window && !(xevent->xclient.data.l[1] & Button1Mask))
  661. if ((column_highlighting && x < max (e->column1, e->column2)) || !column_highlighting) {
  662. edit_block_delete_cmd (e);
  663. deleted = 1;
  664. }
  665. edit_update_curs_row (e);
  666. edit_move_display (e, start_line);
  667. click = edit_get_click_pos (e, x, y); /* click pos changes with edit_block_delete_cmd() */
  668. edit_cursor_move (e, click - e->curs1);
  669. if (data_type == DndFile) {
  670. edit_insert_file (e, (char *) data);
  671. } else if (data_type != DndFiles) {
  672. if (dnd_null_term_type (data_type)) {
  673. int len;
  674. len = strlen ((char *) data);
  675. size = min (len, size);
  676. }
  677. if (column_highlighting) {
  678. edit_insert_column_of_text (e, data, size, abs (e->column2 - e->column1));
  679. } else {
  680. while (size--)
  681. edit_insert_ahead (e, data[size]);
  682. }
  683. } else {
  684. while (size--)
  685. edit_insert_ahead (e, data[size] ? data[size] : '\n');
  686. }
  687. /* drops to the same window moving to the right: */
  688. if (xevent->xclient.data.l[2] == xevent->xclient.window && !(xevent->xclient.data.l[1] & Button1Mask))
  689. if (column_highlighting && !deleted)
  690. edit_block_delete_cmd (e);
  691. /* The drop has now been successfully recieved. We can now send an acknowledge
  692. event back to the window that send the data. When this window recieves
  693. the acknowledge event, the app can decide whether or not to delete the data.
  694. This allows text to be safely moved betweem text windows without the
  695. risk of data being lost. In our case, drag with button1 is a copy
  696. drag, while drag with any other button is a move drag (i.e. the sending
  697. application must delete its selection after recieving an acknowledge
  698. event). We must not, however, send an acknowledge signal if a filelist
  699. (for example) was passed to us, since the sender might take this to
  700. mean that all those files can be deleted! The two types we can acknowledge
  701. are: */
  702. if (xevent->xclient.data.l[2] != xevent->xclient.window) /* drops to the same window */
  703. if (data_type == DndText || data_type == DndRawData)
  704. CDropAcknowledge (xevent);
  705. e->force |= REDRAW_COMPLETELY | REDRAW_LINE;
  706. free_data;
  707. }
  708. #endif
  709. #ifndef GTK
  710. int eh_editor (CWidget * w, XEvent * xevent, CEvent * cwevent)
  711. {
  712. WEdit *e = w->editor;
  713. int r = 0;
  714. static int old_tab_spacing = -1;
  715. if (!e)
  716. return 0;
  717. if (old_tab_spacing != option_tab_spacing)
  718. e->force |= REDRAW_COMPLETELY + REDRAW_LINE;
  719. old_tab_spacing = option_tab_spacing;
  720. if (xevent->type == KeyPress) {
  721. if (xevent->xkey.keycode == 0x31 && xevent->xkey.state == 0xD) {
  722. CSetColor (color_palette (18));
  723. CRectangle (w->winid, 0, 0, w->width, w->height);
  724. }
  725. }
  726. switch (xevent->type) {
  727. case SelectionNotify:
  728. selection_paste (e, xevent->xselection.requestor, xevent->xselection.property, True);
  729. r = 1;
  730. break;
  731. case SelectionRequest:
  732. selection_send (&(xevent->xselectionrequest));
  733. return 1;
  734. /* case SelectionClear: ---> This is handled by coolnext.c: CNextEvent() */
  735. #ifdef HAVE_DND
  736. case ClientMessage:
  737. handle_client_message (w, xevent);
  738. r = 1;
  739. #endif
  740. break;
  741. case ButtonPress:
  742. CFocus (w);
  743. edit_render_tidbits (w);
  744. case ButtonRelease:
  745. if (xevent->xbutton.state & ControlMask) {
  746. if (!column_highlighting)
  747. edit_push_action (e, COLUMN_OFF);
  748. column_highlighting = 1;
  749. } else {
  750. if (column_highlighting)
  751. edit_push_action (e, COLUMN_ON);
  752. column_highlighting = 0;
  753. }
  754. case MotionNotify:
  755. if (!xevent->xmotion.state && xevent->type == MotionNotify)
  756. return 0;
  757. resolve_button (xevent, cwevent);
  758. if ((cwevent->button == Button4 || cwevent->button == Button5)
  759. && (xevent->type == ButtonRelease)) {
  760. /* ahaack: wheel mouse mapped as button 4 and 5 */
  761. r = edit_execute_key_command (e, (cwevent->button == Button5) ? CK_Page_Down : CK_Page_Up, -1);
  762. break;
  763. }
  764. edit_mouse_mark (e, xevent, cwevent->double_click);
  765. break;
  766. case Expose:
  767. edit_render_expose (e, &(xevent->xexpose));
  768. return 1;
  769. case FocusIn:
  770. CSetCursorColor (e->overwrite ? color_palette (24) : color_palette (19));
  771. case FocusOut:
  772. edit_render_tidbits (w);
  773. e->force |= REDRAW_CHAR_ONLY | REDRAW_LINE;
  774. edit_render_keypress (e);
  775. return 1;
  776. break;
  777. case KeyRelease:
  778. #if 0
  779. if (column_highlighting) {
  780. column_highlighting = 0;
  781. e->force = REDRAW_COMPLETELY | REDRAW_LINE;
  782. edit_mark_cmd (e, 1);
  783. }
  784. #endif
  785. break;
  786. case KeyPress:
  787. cwevent->ident = w->ident;
  788. if (!cwevent->command && cwevent->insert < 0) { /* no translation */
  789. if ((cwevent->key == XK_r || cwevent->key == XK_R) && (cwevent->state & ControlMask)) {
  790. cwevent->command = e->macro_i < 0 ? CK_Begin_Record_Macro : CK_End_Record_Macro;
  791. } else {
  792. cwevent->command = CKeySymMod (xevent);
  793. if (cwevent->command > 0)
  794. cwevent->command = CK_Macro (cwevent->command);
  795. else
  796. break;
  797. }
  798. }
  799. r = edit_execute_key_command (e, cwevent->command, cwevent->insert);
  800. if (r)
  801. edit_update_screen (e);
  802. return r;
  803. break;
  804. case EditorCommand:
  805. cwevent->ident = w->ident;
  806. cwevent->command = xevent->xkey.keycode;
  807. r = cwevent->handled = edit_execute_key_command (e, xevent->xkey.keycode, -1);
  808. if (r)
  809. edit_update_screen (e);
  810. return r;
  811. default:
  812. return 0;
  813. }
  814. edit_update_screen (e);
  815. return r;
  816. }
  817. #endif /* ! GTK */
  818. #else
  819. WEdit *wedit;
  820. WButtonBar *edit_bar;
  821. Dlg_head *edit_dlg;
  822. WMenu *edit_menubar;
  823. int column_highlighting = 0;
  824. static int edit_callback (Dlg_head * h, WEdit * edit, int msg, int par);
  825. static int edit_mode_callback (struct Dlg_head *h, int id, int msg)
  826. {
  827. return 0;
  828. }
  829. int edit_event (WEdit * edit, Gpm_Event * event, int *result)
  830. {
  831. *result = MOU_NORMAL;
  832. edit_update_curs_row (edit);
  833. edit_update_curs_col (edit);
  834. if (event->type & (GPM_DOWN | GPM_DRAG | GPM_UP)) {
  835. if (event->y > 1 && event->x > 0
  836. && event->x <= edit->num_widget_columns
  837. && event->y <= edit->num_widget_lines + 1) {
  838. if (edit->mark2 != -1 && event->type & (GPM_UP | GPM_DRAG))
  839. return 1; /* a lone up mustn't do anything */
  840. if (event->type & (GPM_DOWN | GPM_UP))
  841. edit_push_key_press (edit);
  842. edit_cursor_move (edit, edit_bol (edit, edit->curs1) - edit->curs1);
  843. if (--event->y > (edit->curs_row + 1))
  844. edit_cursor_move (edit,
  845. edit_move_forward (edit, edit->curs1, event->y - (edit->curs_row + 1), 0)
  846. - edit->curs1);
  847. if (event->y < (edit->curs_row + 1))
  848. edit_cursor_move (edit,
  849. +edit_move_backward (edit, edit->curs1, (edit->curs_row + 1) - event->y)
  850. - edit->curs1);
  851. edit_cursor_move (edit, (int) edit_move_forward3 (edit, edit->curs1,
  852. event->x - edit->start_col - 1, 0) - edit->curs1);
  853. edit->prev_col = edit_get_col (edit);
  854. if (event->type & GPM_DOWN) {
  855. edit_mark_cmd (edit, 1); /* reset */
  856. edit->highlight = 0;
  857. }
  858. if (!(event->type & GPM_DRAG))
  859. edit_mark_cmd (edit, 0);
  860. edit->force |= REDRAW_COMPLETELY;
  861. edit_update_curs_row (edit);
  862. edit_update_curs_col (edit);
  863. edit_update_screen (edit);
  864. return 1;
  865. }
  866. }
  867. return 0;
  868. }
  869. int menubar_event (Gpm_Event * event, WMenu * menubar); /* menu.c */
  870. int edit_mouse_event (Gpm_Event * event, void *x)
  871. {
  872. int result;
  873. if (edit_event ((WEdit *) x, event, &result))
  874. return result;
  875. else
  876. return menubar_event (event, edit_menubar);
  877. }
  878. extern Menu EditMenuBar[5];
  879. int edit (const char *_file, int line)
  880. {
  881. static int made_directory = 0;
  882. int framed = 0;
  883. int midnight_colors[4];
  884. char *text = 0;
  885. if (option_backup_ext_int != -1) {
  886. option_backup_ext = malloc (sizeof(int) + 1);
  887. option_backup_ext[sizeof(int)] = '\0';
  888. memcpy (option_backup_ext, (char *) &option_backup_ext_int, sizeof (int));
  889. }
  890. if (!made_directory) {
  891. mkdir (catstrs (home_dir, EDIT_DIR, 0), 0700);
  892. made_directory = 1;
  893. }
  894. if (_file) {
  895. if (!(*_file)) {
  896. _file = 0;
  897. text = "";
  898. }
  899. } else
  900. text = "";
  901. if (!(wedit = edit_init (NULL, LINES - 2, COLS, _file, text, "", 0))) {
  902. message (1, _(" Error "), get_error_msg (""));
  903. return 0;
  904. }
  905. wedit->macro_i = -1;
  906. /* Create a new dialog and add it widgets to it */
  907. edit_dlg = create_dlg (0, 0, LINES, COLS, midnight_colors,
  908. edit_mode_callback, "[Internal File Editor]",
  909. "edit",
  910. DLG_NONE);
  911. edit_dlg->raw = 1; /*so that tab = '\t' key works */
  912. init_widget (&(wedit->widget), 0, 0, LINES - 1, COLS,
  913. (callback_fn) edit_callback,
  914. (destroy_fn) edit_clean,
  915. (mouse_h) edit_mouse_event, 0);
  916. widget_want_cursor (wedit->widget, 1);
  917. edit_bar = buttonbar_new (1);
  918. if (!framed) {
  919. switch (edit_key_emulation) {
  920. case EDIT_KEY_EMULATION_NORMAL:
  921. edit_init_menu_normal (); /* editmenu.c */
  922. break;
  923. case EDIT_KEY_EMULATION_EMACS:
  924. edit_init_menu_emacs (); /* editmenu.c */
  925. break;
  926. }
  927. edit_menubar = menubar_new (0, 0, COLS, EditMenuBar, N_menus);
  928. }
  929. add_widget (edit_dlg, wedit);
  930. if (!framed)
  931. add_widget (edit_dlg, edit_menubar);
  932. add_widget (edit_dlg, edit_bar);
  933. edit_move_display (wedit, line - 1);
  934. edit_move_to_line (wedit, line - 1);
  935. run_dlg (edit_dlg);
  936. if (!framed)
  937. edit_done_menu (); /* editmenu.c */
  938. destroy_dlg (edit_dlg);
  939. return 1;
  940. }
  941. static void edit_my_define (Dlg_head * h, int idx, char *text,
  942. void (*fn) (WEdit *), WEdit * edit)
  943. {
  944. define_label_data (h, (Widget *) edit, idx, text, (buttonbarfn) fn, edit);
  945. }
  946. void cmd_F1 (WEdit * edit)
  947. {
  948. send_message (edit->widget.parent, (Widget *) edit, WIDGET_KEY, KEY_F (1));
  949. }
  950. void cmd_F2 (WEdit * edit)
  951. {
  952. send_message (edit->widget.parent, (Widget *) edit, WIDGET_KEY, KEY_F (2));
  953. }
  954. void cmd_F3 (WEdit * edit)
  955. {
  956. send_message (edit->widget.parent, (Widget *) edit, WIDGET_KEY, KEY_F (3));
  957. }
  958. void cmd_F4 (WEdit * edit)
  959. {
  960. send_message (edit->widget.parent, (Widget *) edit, WIDGET_KEY, KEY_F (4));
  961. }
  962. void cmd_F5 (WEdit * edit)
  963. {
  964. send_message (edit->widget.parent, (Widget *) edit, WIDGET_KEY, KEY_F (5));
  965. }
  966. void cmd_F6 (WEdit * edit)
  967. {
  968. send_message (edit->widget.parent, (Widget *) edit, WIDGET_KEY, KEY_F (6));
  969. }
  970. void cmd_F7 (WEdit * edit)
  971. {
  972. send_message (edit->widget.parent, (Widget *) edit, WIDGET_KEY, KEY_F (7));
  973. }
  974. void cmd_F8 (WEdit * edit)
  975. {
  976. send_message (edit->widget.parent, (Widget *) edit, WIDGET_KEY, KEY_F (8));
  977. }
  978. void cmd_F9 (WEdit * edit)
  979. {
  980. send_message (edit->widget.parent, (Widget *) edit, WIDGET_KEY, KEY_F (9));
  981. }
  982. void cmd_F10 (WEdit * edit)
  983. {
  984. send_message (edit->widget.parent, (Widget *) edit, WIDGET_KEY, KEY_F (10));
  985. }
  986. void edit_labels (WEdit * edit)
  987. {
  988. Dlg_head *h = edit->widget.parent;
  989. edit_my_define (h, 1, _("Help"), cmd_F1, edit);
  990. edit_my_define (h, 2, _("Save"), cmd_F2, edit);
  991. edit_my_define (h, 3, _("Mark"), cmd_F3, edit);
  992. edit_my_define (h, 4, _("Replac"), cmd_F4, edit);
  993. edit_my_define (h, 5, _("Copy"), cmd_F5, edit);
  994. edit_my_define (h, 6, _("Move"), cmd_F6, edit);
  995. edit_my_define (h, 7, _("Search"), cmd_F7, edit);
  996. edit_my_define (h, 8, _("Delete"), cmd_F8, edit);
  997. if (!edit->have_frame)
  998. edit_my_define (h, 9, _("PullDn"), edit_menu_cmd, edit);
  999. edit_my_define (h, 10, _("Quit"), cmd_F10, edit);
  1000. redraw_labels (h, (Widget *) edit);
  1001. }
  1002. long get_key_state ()
  1003. {
  1004. return (long) get_modifier ();
  1005. }
  1006. void edit_adjust_size (Dlg_head * h)
  1007. {
  1008. WEdit *edit;
  1009. WButtonBar *edit_bar;
  1010. edit = (WEdit *) find_widget_type (h, (callback_fn) edit_callback);
  1011. edit_bar = (WButtonBar *) edit->widget.parent->current->next->widget;
  1012. widget_set_size (&edit->widget, 0, 0, LINES - 1, COLS);
  1013. widget_set_size (&edit_bar->widget, LINES - 1, 0, 1, COLS);
  1014. widget_set_size (&edit_menubar->widget, 0, 0, 1, COLS);
  1015. #ifdef RESIZABLE_MENUBAR
  1016. menubar_arrange(edit_menubar);
  1017. #endif
  1018. }
  1019. void edit_update_screen (WEdit * e)
  1020. {
  1021. edit_scroll_screen_over_cursor (e);
  1022. edit_update_curs_col (e);
  1023. edit_status (e);
  1024. /* pop all events for this window for internal handling */
  1025. if (!is_idle ()) {
  1026. e->force |= REDRAW_PAGE;
  1027. return;
  1028. }
  1029. if (e->force & REDRAW_COMPLETELY)
  1030. e->force |= REDRAW_PAGE;
  1031. edit_render_keypress (e);
  1032. }
  1033. static int edit_callback (Dlg_head * h, WEdit * e, int msg, int par)
  1034. {
  1035. switch (msg) {
  1036. case WIDGET_INIT:
  1037. e->force |= REDRAW_COMPLETELY;
  1038. edit_labels (e);
  1039. break;
  1040. case WIDGET_DRAW:
  1041. e->force |= REDRAW_COMPLETELY;
  1042. e->num_widget_lines = LINES - 2;
  1043. e->num_widget_columns = COLS;
  1044. case WIDGET_FOCUS:
  1045. edit_update_screen (e);
  1046. return 1;
  1047. case WIDGET_KEY:{
  1048. int cmd, ch;
  1049. if (edit_drop_hotkey_menu (e, par)) /* first check alt-f, alt-e, alt-s, etc for drop menus */
  1050. return 1;
  1051. if (!edit_translate_key (e, 0, par, get_key_state (), &cmd, &ch))
  1052. return 0;
  1053. edit_execute_key_command (e, cmd, ch);
  1054. edit_update_screen (e);
  1055. }
  1056. return 1;
  1057. case WIDGET_COMMAND:
  1058. edit_execute_key_command (e, par, -1);
  1059. edit_update_screen (e);
  1060. return 1;
  1061. case WIDGET_CURSOR:
  1062. widget_move (&e->widget, e->curs_row + EDIT_TEXT_VERTICAL_OFFSET, e->curs_col + e->start_col);
  1063. return 1;
  1064. }
  1065. return default_proc (h, msg, par);
  1066. }
  1067. #endif