tkmain.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488
  1. /* Midnight Commander Tk initialization and main loop
  2. Copyright (C) 1995, 1997 Miguel de Icaza
  3. Copyright (C) 1995 Jakub Jelinek
  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. /*
  16. * The Tk version of the code tries to use as much code as possible
  17. * from the curses version of the code, so we Tk as barely as possible
  18. * and manage most of the events ourselves. This may cause some
  19. * confusion at the beginning.
  20. */
  21. #include <config.h>
  22. #include <stdarg.h>
  23. #include <string.h>
  24. #include <ctype.h>
  25. #include "main.h"
  26. #include "tkmain.h"
  27. #include "key.h"
  28. #include "global.h"
  29. #include "tty.h" /* for KEY_BACKSPACE */
  30. /* Tcl interpreter */
  31. Tcl_Interp *interp;
  32. /* if true, it's like mc, otherwise is like mxc */
  33. int use_one_window = 1;
  34. static char *display = NULL;
  35. /* Used to quote the next character, emulates mi_getch () */
  36. static int mi_getch_waiting = 0;
  37. static int mi_getch_value;
  38. static Tk_ArgvInfo arg_table[] = {
  39. {"-display", TK_ARGV_STRING, (char *) NULL, (char *) &display,
  40. "Display to use"},
  41. {(char *) NULL, TK_ARGV_END, (char *) NULL, (char *) NULL,
  42. (char *) NULL}
  43. };
  44. static int tkmc_callback (ClientData cd, Tcl_Interp *i, int ac, char *av[]);
  45. char *ALPHA =
  46. "\n\n"
  47. "\n\t\t\t*** IMPORTANT ***\n\n"
  48. "The Tk edition of the Midnight Commander is an ALPHA release of the code.\n\n"
  49. "Many features are missing and in general, not all of the features that\n"
  50. "are available in the text mode version of the program are available on\n"
  51. "this edition.\n\n"
  52. "The internal viewer is incomplete, the built-in editor does not work\n"
  53. "the Tree widget does not work, the Info Widget is incomplete, the setup\n"
  54. "code is incomplete, the keybindings are incomplete, and little testing\n"
  55. "has been done in this code. ** This is not a finished product **\n\n"
  56. "Feel free to send fixes to mc-devel@nuclecu.unam.mx\n\n\n";
  57. int
  58. xtoolkit_init (int *argc, char *argv[])
  59. {
  60. interp = Tcl_CreateInterp ();
  61. if (Tk_ParseArgv (interp, (Tk_Window) NULL, argc, argv, arg_table, 0)
  62. != TCL_OK) {
  63. fprintf(stderr, "%s\n", interp->result);
  64. exit(1);
  65. }
  66. printf (ALPHA);
  67. COLS = 80;
  68. LINES = 25;
  69. /* Pass DISPLAY variable to child procedures */
  70. if (display != NULL) {
  71. Tcl_SetVar2 (interp, "env", "DISPLAY", display, TCL_GLOBAL_ONLY);
  72. }
  73. Tcl_SetVar(interp, "tcl_interactive", "0", TCL_GLOBAL_ONLY);
  74. Tcl_SetVar (interp, "LIBDIR", mc_home, TCL_GLOBAL_ONLY);
  75. Tcl_SetVar (interp, "mc_running", "1", TCL_GLOBAL_ONLY);
  76. Tcl_SetVar(interp, "one_window",
  77. use_one_window ? "1" : "0", TCL_GLOBAL_ONLY);
  78. /*
  79. * Initialize the Tk application.
  80. */
  81. #ifdef OLD_VERSION
  82. tkwin = Tk_CreateMainWindow (interp, display, "Midnight Commander","tkmc");
  83. #endif
  84. /* #define HAVE_BLT */
  85. if (Tcl_Init (interp) != TCL_OK){
  86. fprintf (stderr, "Tcl_Init: %s\n", interp->result);
  87. exit (1);
  88. }
  89. if (Tk_Init (interp) != TCL_OK){
  90. fprintf (stderr, "Tk_Init: %s\n", interp->result);
  91. exit (1);
  92. }
  93. #ifdef HAVE_BLT
  94. give an error here
  95. if (Blt_DragDropInit (interp) != TCL_OK){
  96. fprintf (stderr, "Blt_DragDropInit: %s\n", interp->result);
  97. exit (1);
  98. }
  99. Tcl_SetVar (interp, "have_blt", "1", TCL_GLOBAL_ONLY);
  100. #else
  101. Tcl_SetVar (interp, "have_blt", "0", TCL_GLOBAL_ONLY);
  102. #endif
  103. Tcl_CreateCommand (interp, "tkmc", tkmc_callback, 0, 0);
  104. {
  105. char *mc_tcl = concat_dir_and_file (mc_home, "mc.tcl");
  106. if (Tcl_EvalFile (interp, mc_tcl) == TCL_OK){
  107. free (mc_tcl);
  108. return 0;
  109. } else {
  110. printf ("%s\n", interp->result);
  111. exit (1);
  112. }
  113. }
  114. }
  115. int
  116. xtoolkit_end (void)
  117. {
  118. /* Cleanup */
  119. Tcl_Eval (interp, "exit");
  120. return 1;
  121. }
  122. void
  123. tk_evalf (char *format, ...)
  124. {
  125. va_list ap;
  126. char buffer [1024];
  127. va_start (ap, format);
  128. vsprintf (buffer, format, ap);
  129. if (Tcl_Eval (interp, buffer) != TCL_OK){
  130. fprintf (stderr, "[%s]: %s\n", buffer, interp->result);
  131. }
  132. va_end (ap);
  133. }
  134. int
  135. tk_evalf_val (char *format, ...)
  136. {
  137. va_list ap;
  138. char buffer [1024];
  139. int r;
  140. va_start (ap, format);
  141. vsprintf (buffer, format, ap);
  142. r = Tcl_Eval (interp, buffer);
  143. va_end (ap);
  144. return r;
  145. }
  146. widget_data
  147. xtoolkit_create_dialog (Dlg_head *h, int flags)
  148. {
  149. char *dialog_name = copy_strings (".", h->name, 0);
  150. tk_evalf ("toplevel %s", dialog_name);
  151. h->grided = flags & DLG_GRID;
  152. if (h->grided)
  153. tk_evalf ("create_gui_canvas %s", dialog_name);
  154. return (widget_data) dialog_name;
  155. }
  156. void
  157. x_set_dialog_title (Dlg_head *h, char *title)
  158. {
  159. tk_evalf ("wm title %s {%s}", (char *)(h->wdata), title);
  160. }
  161. widget_data
  162. xtoolkit_get_main_dialog (Dlg_head *h)
  163. {
  164. return (widget_data) strdup (".");
  165. }
  166. /* Creates the containers */
  167. widget_data
  168. x_create_panel_container (int which)
  169. {
  170. char *s, *cmd;
  171. cmd = use_one_window ? "frame" : "toplevel";
  172. s = which ? ".right" : ".left";
  173. tk_evalf ("%s %s", cmd, s);
  174. s = which ? ".right.canvas" : ".left.canvas";
  175. tk_evalf ("create_container %s", s);
  176. return (widget_data) s;
  177. }
  178. void
  179. x_panel_container_show (widget_data wdata)
  180. {
  181. }
  182. static int
  183. do_esc_key (int d)
  184. {
  185. if (isdigit(d))
  186. return KEY_F(d-'0');
  187. if ((d >= 'a' && d <= 'z') || (d >= 'A' && d <= 'Z' )
  188. || d == '\n' || d == '\t' || d == XCTRL ('h') || d == '!'
  189. || d == KEY_BACKSPACE || d == 127 || d == '\r')
  190. return ALT(d);
  191. else {
  192. return ESC_CHAR;
  193. }
  194. }
  195. /* This commands has this sintax:
  196. * [r|a|c] ascii
  197. *
  198. * r, a, c, k: regular, alt, control, keysym
  199. */
  200. static int
  201. tkmc_callback (ClientData cd, Tcl_Interp *i, int ac, char *av[])
  202. {
  203. Dlg_head *h = current_dlg;
  204. int key;
  205. static int got_esc;
  206. key = av [2][0];
  207. /* Control or alt keys? */
  208. if (av [1][0] == 'c' || av [1][0] == 'a'){
  209. if (!key)
  210. return TCL_OK;
  211. /* Regular? */
  212. if (!isascii (key)){
  213. return TCL_OK;
  214. } else {
  215. key = tolower (key);
  216. }
  217. }
  218. switch (av [1][0]){
  219. case 'a':
  220. key = ALT(key);
  221. break;
  222. case 'c':
  223. key = XCTRL(key);
  224. break;
  225. case 'r':
  226. if (!key)
  227. return TCL_OK;
  228. break;
  229. case 'k':
  230. if (!(key = lookup_keysym (av [2])))
  231. return TCL_OK;
  232. break;
  233. case 'e':
  234. key = ESC_CHAR;
  235. dlg_key_event (h, key);
  236. update_cursor (h);
  237. return TCL_OK;
  238. }
  239. if (key == '\r')
  240. key = '\n';
  241. if (key == ESC_CHAR){
  242. if (!got_esc){
  243. got_esc = 1;
  244. return TCL_OK;
  245. }
  246. got_esc = 0;
  247. }
  248. if (got_esc){
  249. key = do_esc_key (key);
  250. got_esc = 0;
  251. }
  252. if (mi_getch_waiting && key){
  253. mi_getch_waiting = 0;
  254. mi_getch_value = key;
  255. return TCL_OK;
  256. }
  257. dlg_key_event (h, key);
  258. update_cursor (h);
  259. return TCL_OK;
  260. }
  261. void
  262. x_focus_widget (Widget_Item *p)
  263. {
  264. char *wname;
  265. if (!p->widget)
  266. return;
  267. wname = (char *) p->widget->wdata;
  268. if (!wname)
  269. return;
  270. tk_evalf ("focus %s", wname+1);
  271. }
  272. void
  273. x_unfocus_widget (Widget_Item *p)
  274. {
  275. }
  276. /* Setup done before using tkrundlg_event */
  277. void
  278. x_init_dlg (Dlg_head *h)
  279. {
  280. Widget_Item *h_track;
  281. char *top_level_name;
  282. int grided;
  283. int i;
  284. /* Set wlist to hold all the widget names that will be ran */
  285. h_track = h->current;
  286. grided = h->grided;
  287. top_level_name = (char *) h->wdata;
  288. /* Set up the layout of the dialog box.
  289. * We support two ways for laying out twidgets on Tk/mc:
  290. *
  291. * 1. At widget creation time a unique name is assigned to
  292. * each widget. We create a global list called wlist that
  293. * holds the names and invoke a routine that does the layout
  294. * using Tk laying out primitives (usually pack).
  295. *
  296. * 2. If the widgets were created with supplied names, then
  297. * the widgets are intended to be laid out with the grid
  298. * manager with a property table contained in the Tcl source
  299. * file.
  300. *
  301. * If there are no properties defined for a dialog box, then
  302. * a small Tcl-based GUI designed is started up so that the
  303. * programmer can define the grided layout for it
  304. */
  305. if (grided){
  306. tk_evalf ("set components {}");
  307. for (i = 0; i < h->count; i++){
  308. tk_evalf ("set components \"%s $components\"", h_track->widget->tkname);
  309. h_track = h_track->prev;
  310. }
  311. tk_evalf ("layout_with_grid %s %d", h->name, h->count);
  312. if (atoi (interp->result) == 0){
  313. tk_evalf ("run_gui_design .%s", h->name);
  314. /* Run Tk code */
  315. while (1)
  316. Tcl_DoOneEvent (TCL_ALL_EVENTS);
  317. }
  318. } else {
  319. tk_evalf ("set wlist {}");
  320. for (i = 0; i < h->count; i++){
  321. char *wname = (char *)h_track->widget->wdata;
  322. if (wname)
  323. tk_evalf ("set wlist \"%s $wlist\"", wname+1);
  324. h_track = h_track->prev;
  325. }
  326. tk_evalf ("layout_%s", h->name);
  327. }
  328. /* setup window bindings */
  329. tk_evalf ("bind_setup %s", top_level_name);
  330. /* If this is not the main window, center it */
  331. if (top_level_name [0] && top_level_name [1]){
  332. tk_evalf ("center_win %s", top_level_name);
  333. }
  334. }
  335. int
  336. tkrundlg_event (Dlg_head *h)
  337. {
  338. /* Run the dialog */
  339. while (h->running){
  340. if (h->send_idle_msg){
  341. if (Tcl_DoOneEvent (TCL_DONT_WAIT))
  342. if (idle_hook)
  343. execute_hooks (idle_hook);
  344. while (Tcl_DoOneEvent (TCL_DONT_WAIT) &&
  345. h->running && h->send_idle_msg){
  346. (*h->callback) (h, 0, DLG_IDLE);
  347. }
  348. } else
  349. Tcl_DoOneEvent (TCL_ALL_EVENTS);
  350. }
  351. return 1;
  352. }
  353. int
  354. Tcl_AppInit (Tcl_Interp *interp)
  355. {
  356. return TCL_OK;
  357. }
  358. void
  359. x_interactive_display ()
  360. {
  361. }
  362. int
  363. tk_getch ()
  364. {
  365. mi_getch_waiting = 1;
  366. while (mi_getch_waiting)
  367. Tk_DoOneEvent (TK_ALL_EVENTS);
  368. return mi_getch_value;
  369. }
  370. void
  371. tk_dispatch_all (void)
  372. {
  373. while (Tk_DoOneEvent (TK_DONT_WAIT))
  374. ;
  375. }
  376. void
  377. x_destroy_dlg_start (Dlg_head *h)
  378. {
  379. /* nothing */
  380. }
  381. void
  382. x_destroy_dlg (Dlg_head *h)
  383. {
  384. tk_evalf ("destroy %s", (char *) h->wdata);
  385. tk_dispatch_all ();
  386. free ((char *) h->wdata);
  387. tk_end_frame (); /* Cleanup, in case I forget */
  388. }
  389. void
  390. edition_post_exec (void)
  391. {
  392. if (iconify_on_exec)
  393. tk_evalf ("wm deiconify .");
  394. }
  395. void
  396. edition_pre_exec (void)
  397. {
  398. if (iconify_on_exec)
  399. tk_evalf ("wm iconify .");
  400. }
  401. int
  402. try_alloc_color_pair (char *fg, char *bg)
  403. {
  404. }