mssh-window.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547
  1. #include <string.h>
  2. #include <stdlib.h>
  3. #include <gconf/gconf-client.h>
  4. #include <gdk/gdkkeysyms.h>
  5. #include "mssh-terminal.h"
  6. #include "mssh-pref.h"
  7. #include "mssh-gconf.h"
  8. #include "mssh-window.h"
  9. #include "config.h"
  10. static void mssh_window_sendhost(GtkWidget *widget, gpointer data);
  11. static void mssh_window_destroy(GtkWidget *widget, gpointer data);
  12. static void mssh_window_pref(GtkWidget *widget, gpointer data);
  13. static gboolean mssh_window_key_press(GtkWidget *widget,
  14. GdkEventKey *event, gpointer data);
  15. static gboolean mssh_window_entry_focused(GtkWidget *widget,
  16. GtkDirectionType dir, gpointer data);
  17. static gboolean mssh_window_session_close(gpointer data);
  18. static void mssh_window_session_focused(MSSHTerminal *terminal,
  19. gpointer data);
  20. static gboolean mssh_window_mouse_paste_cb(MSSHTerminal *terminal,
  21. gpointer data);
  22. static void mssh_window_insert(GtkWidget *widget, gchar *new_text,
  23. gint new_text_length, gint *position, gpointer data);
  24. static void mssh_window_add_session(MSSHWindow *window, char *hostname);
  25. static void mssh_window_init(MSSHWindow* window);
  26. static void mssh_window_class_init(MSSHWindowClass *klass);
  27. G_DEFINE_TYPE(MSSHWindow, mssh_window, GTK_TYPE_WINDOW)
  28. struct WinTermPair
  29. {
  30. MSSHWindow *window;
  31. MSSHTerminal *terminal;
  32. };
  33. GtkWidget* mssh_window_new(void)
  34. {
  35. return g_object_new(MSSH_TYPE_WINDOW, NULL);
  36. }
  37. static void mssh_window_sendhost(GtkWidget *widget, gpointer data)
  38. {
  39. int i;
  40. MSSHWindow *window = MSSH_WINDOW(data);
  41. for(i = 0; i < window->terminals->len; i++)
  42. {
  43. mssh_terminal_send_host(g_array_index(window->terminals,
  44. MSSHTerminal*, i));
  45. }
  46. }
  47. static void mssh_window_destroy(GtkWidget *widget, gpointer data)
  48. {
  49. gtk_main_quit();
  50. }
  51. static void mssh_window_pref(GtkWidget *widget, gpointer data)
  52. {
  53. MSSHWindow *window = MSSH_WINDOW(data);
  54. GtkWidget *pref = mssh_pref_new();
  55. gtk_window_set_transient_for(GTK_WINDOW(pref), GTK_WINDOW(window));
  56. gtk_window_set_modal(GTK_WINDOW(pref), TRUE);
  57. gtk_window_set_position(GTK_WINDOW(pref),
  58. GTK_WIN_POS_CENTER_ON_PARENT);
  59. gtk_widget_show_all(pref);
  60. }
  61. static void mssh_window_insert(GtkWidget *widget, gchar *new_text,
  62. gint new_text_length, gint *position, gpointer data)
  63. {
  64. int i;
  65. MSSHWindow *window = MSSH_WINDOW(data);
  66. for(i = 0; i < window->terminals->len; i++)
  67. {
  68. /*fprintf(stderr, "Sending text '%s' to terminal %d\n", new_text, i);*/
  69. mssh_terminal_send_string(g_array_index(window->terminals,
  70. MSSHTerminal*, i), new_text);
  71. }
  72. g_signal_stop_emission_by_name(G_OBJECT(widget), "insert-text");
  73. }
  74. static gboolean mssh_window_key_press(GtkWidget *widget,
  75. GdkEventKey *event, gpointer data)
  76. {
  77. int i;
  78. MSSHTerminal *term;
  79. GtkClipboard *clipboard;
  80. GdkAtom atom;
  81. gchar *text;
  82. MSSHWindow *window = MSSH_WINDOW(data);
  83. for(i = 0; i < window->terminals->len; i++)
  84. {
  85. term = MSSH_TERMINAL(g_array_index(window->terminals,MSSHTerminal*, i));
  86. if ( ( term->CodeAnt == 65505 ) && ( event->keyval == 65379 ) ) {
  87. atom = gdk_atom_intern("PRIMARY", TRUE);
  88. clipboard = gtk_clipboard_get(atom);
  89. text = gtk_clipboard_wait_for_text (clipboard);
  90. fprintf(stderr,"Requesting PRIMARY clipboard content as text on terminal %d\n", i);
  91. fprintf(stderr,"Clipboard has this text: %s\n",text);
  92. g_free(text);
  93. }
  94. /*fprintf(stderr, "Sending keyval %d to terminal %d\n", event->keyval, i);*/
  95. mssh_terminal_send_data(g_array_index(window->terminals,
  96. MSSHTerminal*, i), event);
  97. term->CodeAnt = event->keyval;
  98. }
  99. return TRUE;
  100. }
  101. static gboolean mssh_window_entry_focused(GtkWidget *widget,
  102. GtkDirectionType dir, gpointer data)
  103. {
  104. MSSHWindow *window = MSSH_WINDOW(data);
  105. gtk_window_set_title(GTK_WINDOW(window), PACKAGE_NAME" - All");
  106. return FALSE;
  107. }
  108. gboolean mssh_window_focus(GtkWidget *widget, GObject *acceleratable,
  109. guint keyval, GdkModifierType modifier, gpointer data)
  110. {
  111. MSSHWindow *window = MSSH_WINDOW(data);
  112. GtkWidget *focus;
  113. int i, idx = -1, len = window->terminals->len;
  114. int wcols = window->columns_override ? window->columns_override :
  115. window->columns;
  116. int cols = (len < wcols) ? len : wcols;
  117. focus = gtk_window_get_focus(GTK_WINDOW(window));
  118. for(i = 0; i < len; i++)
  119. {
  120. if(focus == GTK_WIDGET(g_array_index(window->terminals,
  121. MSSHTerminal*, i)))
  122. {
  123. idx = i;
  124. break;
  125. }
  126. }
  127. if(focus == window->global_entry && keyval == GDK_KEY_Down &&
  128. window->dir_focus)
  129. idx = 0;
  130. else if(idx == -1 && window->dir_focus)
  131. return TRUE;
  132. else
  133. {
  134. switch(keyval)
  135. {
  136. case GDK_KEY_Up:
  137. if(window->dir_focus)
  138. idx = idx - cols;
  139. break;
  140. case GDK_KEY_Down:
  141. if(window->dir_focus)
  142. {
  143. if((idx + cols >= len) && (idx < len -
  144. (len % cols) ? (len % cols) : cols))
  145. idx = len - 1;
  146. else
  147. idx = idx + cols;
  148. }
  149. break;
  150. case GDK_KEY_Left:
  151. if(idx % cols != 0 || !window->dir_focus)
  152. idx = idx - 1;
  153. break;
  154. case GDK_KEY_Right:
  155. if(idx % cols != cols - 1 || !window->dir_focus)
  156. idx = idx + 1;
  157. break;
  158. }
  159. }
  160. if(idx >= len && !window->dir_focus)
  161. focus = window->global_entry;
  162. if(idx < -1 && !window->dir_focus)
  163. idx = len - 1;
  164. if(idx < 0)
  165. focus = window->global_entry;
  166. else if(idx < len)
  167. {
  168. focus = GTK_WIDGET(g_array_index(window->terminals,
  169. MSSHTerminal*, idx));
  170. }
  171. gtk_window_set_focus(GTK_WINDOW(window), focus);
  172. return TRUE;
  173. }
  174. static gboolean mssh_window_session_close(gpointer data)
  175. {
  176. int i, idx = -1;
  177. struct WinTermPair *data_pair = (struct WinTermPair*)data;
  178. for(i = 0; i < data_pair->window->terminals->len; i++)
  179. {
  180. if(data_pair->terminal == g_array_index(
  181. data_pair->window->terminals, MSSHTerminal*, i))
  182. {
  183. idx = i;
  184. break;
  185. }
  186. }
  187. data_pair->window->last_closed = idx;
  188. if(idx == -1)
  189. {
  190. fprintf(stderr,
  191. "mssh: Fatal Error: Can't find terminal to remove!\n");
  192. }
  193. else
  194. {
  195. gtk_widget_destroy(data_pair->terminal->menu_item);
  196. gtk_container_remove(GTK_CONTAINER(data_pair->window->table),
  197. GTK_WIDGET(data_pair->terminal));
  198. g_array_remove_index(data_pair->window->terminals, idx);
  199. mssh_window_relayout(data_pair->window);
  200. }
  201. if(data_pair->window->terminals->len == 0 &&
  202. data_pair->window->exit_on_all_closed)
  203. {
  204. mssh_window_destroy(NULL, (void*)data_pair->window);
  205. }
  206. free(data_pair);
  207. return FALSE;
  208. }
  209. void mssh_window_session_closed(MSSHTerminal *terminal, gpointer data)
  210. {
  211. struct WinTermPair *data_pair = malloc(sizeof(struct WinTermPair));
  212. data_pair->terminal = terminal;
  213. data_pair->window = MSSH_WINDOW(data);
  214. if(data_pair->window->close_ended_sessions)
  215. {
  216. g_timeout_add_seconds(data_pair->window->timeout,
  217. mssh_window_session_close, data_pair);
  218. }
  219. }
  220. static gboolean mssh_window_mouse_paste_cb(MSSHTerminal *terminal,
  221. gpointer data)
  222. {
  223. gtk_widget_grab_focus(GTK_WIDGET(terminal));
  224. return FALSE;
  225. }
  226. static void mssh_window_session_focused(MSSHTerminal *terminal,
  227. gpointer data)
  228. {
  229. char *title;
  230. size_t len;
  231. MSSHWindow *window = MSSH_WINDOW(data);
  232. len = strlen(PACKAGE_NAME" - ") + strlen(terminal->hostname) + 1;
  233. title = malloc(len);
  234. snprintf(title, len, PACKAGE_NAME" - %s", terminal->hostname);
  235. gtk_window_set_title(GTK_WINDOW(window), title);
  236. free(title);
  237. }
  238. void mssh_window_relayout(MSSHWindow *window)
  239. {
  240. GConfClient *client;
  241. GConfEntry *entry;
  242. GtkWidget *focus;
  243. int i, len = window->terminals->len;
  244. int wcols = window->columns_override ? window->columns_override :
  245. window->columns;
  246. int cols = (len < wcols) ? len : wcols;
  247. int rows = (len + 0.5) / cols;
  248. focus = gtk_window_get_focus(GTK_WINDOW(window));
  249. if(!focus)
  250. {
  251. if(window->last_closed < 0)
  252. window->last_closed = 0;
  253. if(len == 0)
  254. focus = window->global_entry;
  255. else if(window->last_closed < len)
  256. {
  257. focus = GTK_WIDGET(g_array_index(window->terminals,
  258. MSSHTerminal*, window->last_closed));
  259. }
  260. else
  261. {
  262. focus = GTK_WIDGET(g_array_index(window->terminals,
  263. MSSHTerminal*, 0));
  264. }
  265. }
  266. for(i = 0; i < len; i++)
  267. {
  268. MSSHTerminal *terminal = g_array_index(window->terminals,
  269. MSSHTerminal*, i);
  270. g_object_ref(terminal);
  271. if(gtk_widget_get_parent(GTK_WIDGET(terminal)) == GTK_WIDGET(window->table))
  272. {
  273. gtk_container_remove(GTK_CONTAINER(window->table),
  274. GTK_WIDGET(terminal));
  275. }
  276. gtk_table_attach(GTK_TABLE(window->table), GTK_WIDGET(terminal),
  277. (i % cols), (i == len - 1) ? cols : (i % cols) + 1, i / cols,
  278. (i / cols) + 1,
  279. GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 1, 1);
  280. g_object_unref(terminal);
  281. if(!terminal->started)
  282. {
  283. mssh_terminal_start_session(terminal, window->env);
  284. terminal->started = 1;
  285. }
  286. }
  287. if(len > 0)
  288. {
  289. gtk_table_resize(GTK_TABLE(window->table), rows, cols);
  290. }
  291. client = gconf_client_get_default();
  292. gtk_widget_show_all(GTK_WIDGET(window));
  293. entry = gconf_client_get_entry(client, MSSH_GCONF_KEY_FONT, NULL,
  294. TRUE, NULL);
  295. mssh_gconf_notify_font(client, 0, entry, window);
  296. entry = gconf_client_get_entry(client, MSSH_GCONF_KEY_FG_COLOUR, NULL,
  297. TRUE, NULL);
  298. mssh_gconf_notify_fg_colour(client, 0, entry, window);
  299. entry = gconf_client_get_entry(client, MSSH_GCONF_KEY_BG_COLOUR, NULL,
  300. TRUE, NULL);
  301. mssh_gconf_notify_bg_colour(client, 0, entry, window);
  302. gtk_window_set_focus(GTK_WINDOW(window), GTK_WIDGET(focus));
  303. }
  304. static void mssh_window_add_session(MSSHWindow *window, char *hostname)
  305. {
  306. MSSHTerminal *terminal = MSSH_TERMINAL(mssh_terminal_new());
  307. terminal->CodeAnt = 0;
  308. g_array_append_val(window->terminals, terminal);
  309. g_signal_connect(G_OBJECT(terminal), "session-closed",
  310. G_CALLBACK(mssh_window_session_closed), window);
  311. g_signal_connect(G_OBJECT(terminal), "session-focused",
  312. G_CALLBACK(mssh_window_session_focused), window);
  313. g_signal_connect(GTK_WIDGET(terminal), "button-release-event",
  314. G_CALLBACK(mssh_window_mouse_paste_cb), window);
  315. mssh_terminal_init_session(terminal, hostname);
  316. gtk_menu_shell_append(GTK_MENU_SHELL(window->server_menu),
  317. terminal->menu_item);
  318. }
  319. static void mssh_window_init(MSSHWindow* window)
  320. {
  321. GConfClient *client;
  322. GtkWidget *vbox = gtk_vbox_new(FALSE, 0);
  323. GtkWidget *entry = gtk_entry_new();
  324. GtkWidget *menu_bar = gtk_menu_bar_new();
  325. GtkWidget *file_menu = gtk_menu_new();
  326. GtkWidget *edit_menu = gtk_menu_new();
  327. GtkWidget *file_item = gtk_menu_item_new_with_label("File");
  328. GtkWidget *edit_item = gtk_menu_item_new_with_label("Edit");
  329. GtkWidget *server_item = gtk_menu_item_new_with_label("Servers");
  330. GtkWidget *file_quit = gtk_image_menu_item_new_from_stock(
  331. GTK_STOCK_QUIT, NULL);
  332. GtkWidget *file_sendhost = gtk_image_menu_item_new_with_label(
  333. "Send hostname");
  334. /* GtkWidget *file_add = gtk_image_menu_item_new_with_label(
  335. "Add session");*/
  336. GtkWidget *edit_pref = gtk_image_menu_item_new_from_stock(
  337. GTK_STOCK_PREFERENCES, NULL);
  338. GtkAccelGroup *accel = gtk_accel_group_new();
  339. window->accel = NULL;
  340. window->server_menu = gtk_menu_new();
  341. window->global_entry = entry;
  342. window->last_closed = -1;
  343. window->terminals = g_array_new(FALSE, TRUE, sizeof(MSSHTerminal*));
  344. gtk_menu_item_set_submenu(GTK_MENU_ITEM(file_item), file_menu);
  345. gtk_menu_item_set_submenu(GTK_MENU_ITEM(edit_item), edit_menu);
  346. gtk_menu_item_set_submenu(GTK_MENU_ITEM(server_item),
  347. window->server_menu);
  348. /* gtk_menu_shell_append(GTK_MENU_SHELL(file_menu), file_add);*/
  349. gtk_menu_shell_append(GTK_MENU_SHELL(file_menu), file_sendhost);
  350. gtk_menu_shell_append(GTK_MENU_SHELL(file_menu), file_quit);
  351. gtk_menu_shell_append(GTK_MENU_SHELL(edit_menu), edit_pref);
  352. g_signal_connect(G_OBJECT(file_sendhost), "activate",
  353. G_CALLBACK(mssh_window_sendhost), window);
  354. g_signal_connect(G_OBJECT(file_quit), "activate",
  355. G_CALLBACK(mssh_window_destroy), window);
  356. g_signal_connect(G_OBJECT(edit_pref), "activate",
  357. G_CALLBACK(mssh_window_pref), window);
  358. gtk_menu_shell_append(GTK_MENU_SHELL(menu_bar), file_item);
  359. gtk_menu_shell_append(GTK_MENU_SHELL(menu_bar), edit_item);
  360. gtk_menu_shell_append(GTK_MENU_SHELL(menu_bar), server_item);
  361. g_signal_connect(G_OBJECT(entry), "key-press-event",
  362. G_CALLBACK(mssh_window_key_press), window);
  363. g_signal_connect(G_OBJECT(entry), "insert-text",
  364. G_CALLBACK(mssh_window_insert), window);
  365. g_signal_connect(G_OBJECT(entry), "focus-in-event",
  366. G_CALLBACK(mssh_window_entry_focused), window);
  367. gtk_box_pack_start(GTK_BOX(vbox), menu_bar, FALSE, TRUE, 0);
  368. gtk_box_pack_start(GTK_BOX(vbox), entry, FALSE, TRUE, 2);
  369. window->table = gtk_table_new(1, 1, TRUE);
  370. gtk_box_pack_start(GTK_BOX(vbox), window->table, TRUE, TRUE, 0);
  371. gtk_container_add(GTK_CONTAINER(window), vbox);
  372. gtk_widget_set_size_request(GTK_WIDGET(window), 0, 0);
  373. gtk_window_set_default_size(GTK_WINDOW(window), 1024, 768);
  374. gtk_window_set_title(GTK_WINDOW(window), PACKAGE_NAME);
  375. client = gconf_client_get_default();
  376. gconf_client_add_dir(client, MSSH_GCONF_PATH,
  377. GCONF_CLIENT_PRELOAD_RECURSIVE, NULL);
  378. gconf_client_notify_add(client, MSSH_GCONF_KEY_FONT,
  379. mssh_gconf_notify_font, window, NULL, NULL);
  380. gconf_client_notify_add(client, MSSH_GCONF_KEY_FG_COLOUR,
  381. mssh_gconf_notify_fg_colour, window, NULL, NULL);
  382. gconf_client_notify_add(client, MSSH_GCONF_KEY_BG_COLOUR,
  383. mssh_gconf_notify_bg_colour, window, NULL, NULL);
  384. gconf_client_notify_add(client, MSSH_GCONF_KEY_COLUMNS,
  385. mssh_gconf_notify_columns, window, NULL, NULL);
  386. gconf_client_notify_add(client, MSSH_GCONF_KEY_TIMEOUT,
  387. mssh_gconf_notify_timeout, window, NULL, NULL);
  388. gconf_client_notify_add(client, MSSH_GCONF_KEY_CLOSE_ENDED,
  389. mssh_gconf_notify_close_ended, window, NULL, NULL);
  390. gconf_client_notify_add(client, MSSH_GCONF_KEY_QUIT_ALL_ENDED,
  391. mssh_gconf_notify_quit_all_ended, window, NULL, NULL);
  392. gconf_client_notify_add(client, MSSH_GCONF_KEY_DIR_FOCUS,
  393. mssh_gconf_notify_dir_focus, window, NULL, NULL);
  394. gconf_client_notify_add(client, MSSH_GCONF_KEY_MODIFIER,
  395. mssh_gconf_notify_modifier, window, NULL, NULL);
  396. gconf_client_notify(client, MSSH_GCONF_KEY_COLUMNS);
  397. gconf_client_notify(client, MSSH_GCONF_KEY_TIMEOUT);
  398. gconf_client_notify(client, MSSH_GCONF_KEY_CLOSE_ENDED);
  399. gconf_client_notify(client, MSSH_GCONF_KEY_QUIT_ALL_ENDED);
  400. gconf_client_notify(client, MSSH_GCONF_KEY_DIR_FOCUS);
  401. gconf_client_notify(client, MSSH_GCONF_KEY_MODIFIER);
  402. gtk_accel_group_connect(accel, GDK_KEY_Up, window->modifier,
  403. GTK_ACCEL_VISIBLE, g_cclosure_new(
  404. G_CALLBACK(mssh_window_focus), window, NULL));
  405. gtk_accel_group_connect(accel, GDK_KEY_Down, window->modifier,
  406. GTK_ACCEL_VISIBLE, g_cclosure_new(
  407. G_CALLBACK(mssh_window_focus), window, NULL));
  408. gtk_accel_group_connect(accel, GDK_KEY_Left, window->modifier,
  409. GTK_ACCEL_VISIBLE, g_cclosure_new(
  410. G_CALLBACK(mssh_window_focus), window, NULL));
  411. gtk_accel_group_connect(accel, GDK_KEY_Right, window->modifier,
  412. GTK_ACCEL_VISIBLE, g_cclosure_new(
  413. G_CALLBACK(mssh_window_focus), window, NULL));
  414. window->accel = accel;
  415. gtk_window_add_accel_group(GTK_WINDOW(window), accel);
  416. }
  417. void mssh_window_start_session(MSSHWindow* window, char **env,
  418. GArray *hosts, long cols)
  419. {
  420. int i, j, k;
  421. int nhosts = hosts->len;
  422. int rows = (nhosts / 2) + (nhosts % 2);
  423. window->env = env;
  424. window->columns_override = cols;
  425. for(i = 0; i < rows; i++)
  426. {
  427. for(j = 0; j < 2; j++)
  428. {
  429. k = j + i*2;
  430. if(k < nhosts)
  431. {
  432. mssh_window_add_session(window, g_array_index(hosts,
  433. char*, k));
  434. }
  435. }
  436. }
  437. mssh_window_relayout(window);
  438. }
  439. static void mssh_window_class_init(MSSHWindowClass *klass)
  440. {
  441. }