mssh-window.c 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875
  1. #include <string.h>
  2. #include <stdlib.h>
  3. #include <stdio.h>
  4. #include <gconf/gconf-client.h>
  5. #include <gdk/gdkkeysyms.h>
  6. #include <gtk/gtk.h>
  7. #define GETTEXT_PACKAGE "mssh"
  8. #include <glib/gi18n-lib.h>
  9. #include "mssh-terminal.h"
  10. #include "mssh-pref.h"
  11. #include "mssh-gconf.h"
  12. #include "mssh-window.h"
  13. #include "config.h"
  14. #include <regex.h>
  15. static void mssh_window_sendhost(GtkWidget *widget, gpointer data);
  16. static void mssh_window_destroy(GtkWidget *widget, gpointer data);
  17. static void mssh_window_pref(GtkWidget *widget, gpointer data);
  18. static gboolean mssh_window_key_press(GtkWidget *widget,
  19. GdkEventKey *event, gpointer data);
  20. static gboolean mssh_window_entry_focused(GtkWidget *widget,
  21. GtkDirectionType dir, gpointer data);
  22. static gboolean mssh_window_session_close(gpointer data);
  23. static void mssh_window_session_focused(MSSHTerminal *terminal,
  24. gpointer data);
  25. static gboolean mssh_window_mouse_paste_cb(MSSHTerminal *terminal,
  26. gpointer data);
  27. static void mssh_window_insert(GtkWidget *widget, gchar *new_text,
  28. gint new_text_length, gint *position, gpointer data);
  29. static void mssh_window_add_session(MSSHWindow *window, char *hostname);
  30. static void mssh_window_init(MSSHWindow* window);
  31. static void mssh_window_class_init(MSSHWindowClass *klass);
  32. static void mssh_window_add(GtkWidget *widget, gpointer data);
  33. gboolean mssh_window_dialog_emit_response(GtkWidget *widget, GObject *acceleratable,
  34. guint keyval, GdkModifierType modifier, gpointer data);
  35. static void mssh_window_maximize(GtkWidget *widget, gpointer data);
  36. static void mssh_window_restore_layout(GtkWidget *widget, gpointer data);
  37. void mssh_window_relayout_for_one(MSSHWindow *window, GtkWidget *t);
  38. G_DEFINE_TYPE(MSSHWindow, mssh_window, GTK_TYPE_WINDOW)
  39. struct WinTermPair
  40. {
  41. MSSHWindow *window;
  42. MSSHTerminal *terminal;
  43. };
  44. GtkWidget* mssh_window_new(void)
  45. {
  46. return g_object_new(MSSH_TYPE_WINDOW, NULL);
  47. }
  48. static void mssh_window_sendhost(GtkWidget *widget, gpointer data)
  49. {
  50. int i;
  51. MSSHWindow *window = MSSH_WINDOW(data);
  52. for(i = 0; i < window->terminals->len; i++)
  53. {
  54. mssh_terminal_send_host(g_array_index(window->terminals,
  55. MSSHTerminal*, i));
  56. }
  57. }
  58. static void mssh_window_sendcommand(GtkWidget *widget, gpointer data)
  59. {
  60. int i;
  61. char *command;
  62. MSSHWindow *window = MSSH_WINDOW(data);
  63. GtkMenuItem *item = (GtkMenuItem *)widget;
  64. command = g_datalist_get_data(MSSH_WINDOW(data)->commands, gtk_menu_item_get_label (item));
  65. for(i = 0; i < window->terminals->len; i++)
  66. {
  67. mssh_terminal_send_string(g_array_index(window->terminals,
  68. MSSHTerminal*, i), command);
  69. }
  70. }
  71. static void mssh_window_destroy(GtkWidget *widget, gpointer data)
  72. {
  73. gtk_main_quit();
  74. }
  75. static void mssh_window_pref(GtkWidget *widget, gpointer data)
  76. {
  77. MSSHWindow *window = MSSH_WINDOW(data);
  78. GtkWidget *pref = mssh_pref_new();
  79. gtk_window_set_transient_for(GTK_WINDOW(pref), GTK_WINDOW(window));
  80. gtk_window_set_modal(GTK_WINDOW(pref), TRUE);
  81. gtk_window_set_position(GTK_WINDOW(pref),
  82. GTK_WIN_POS_CENTER_ON_PARENT);
  83. gtk_widget_show_all(pref);
  84. }
  85. static void mssh_window_insert(GtkWidget *widget, gchar *new_text,
  86. gint new_text_length, gint *position, gpointer data)
  87. {
  88. int i;
  89. MSSHWindow *window = MSSH_WINDOW(data);
  90. for(i = 0; i < window->terminals->len; i++)
  91. {
  92. mssh_terminal_send_string(g_array_index(window->terminals,
  93. MSSHTerminal*, i), new_text);
  94. }
  95. g_signal_stop_emission_by_name(G_OBJECT(widget), "insert-text");
  96. }
  97. static gboolean mssh_window_key_press(GtkWidget *widget,
  98. GdkEventKey *event, gpointer data)
  99. {
  100. int i;
  101. MSSHWindow *window = MSSH_WINDOW(data);
  102. for(i = 0; i < window->terminals->len; i++)
  103. {
  104. mssh_terminal_send_data(g_array_index(window->terminals,
  105. MSSHTerminal*, i), event);
  106. }
  107. return TRUE;
  108. }
  109. static gboolean mssh_window_entry_focused(GtkWidget *widget,
  110. GtkDirectionType dir, gpointer data)
  111. {
  112. GConfClient *client;
  113. GConfEntry *entry;
  114. MSSHWindow *window = MSSH_WINDOW(data);
  115. gtk_window_set_title(GTK_WINDOW(window), PACKAGE_NAME" - All");
  116. window->last_focus = NULL;
  117. /* clear the coloring for the focused window */
  118. client = gconf_client_get_default();
  119. entry = gconf_client_get_entry(client, MSSH_GCONF_KEY_FG_COLOUR, NULL,
  120. TRUE, NULL);
  121. mssh_gconf_notify_fg_colour(client, 0, entry, window);
  122. entry = gconf_client_get_entry(client, MSSH_GCONF_KEY_BG_COLOUR, NULL,
  123. TRUE, NULL);
  124. mssh_gconf_notify_bg_colour(client, 0, entry, window);
  125. return FALSE;
  126. }
  127. gboolean mssh_window_focus(GtkWidget *widget, GObject *acceleratable,
  128. guint keyval, GdkModifierType modifier, gpointer data)
  129. {
  130. MSSHWindow *window = MSSH_WINDOW(data);
  131. GtkWidget *focus;
  132. GConfClient *client;
  133. GConfEntry *entry;
  134. int i, idx = -1, len = window->terminals->len;
  135. int wcols = window->columns_override ? window->columns_override :
  136. window->columns;
  137. int cols = (len < wcols) ? len : wcols;
  138. focus = gtk_window_get_focus(GTK_WINDOW(window));
  139. for(i = 0; i < len; i++)
  140. {
  141. if(focus == GTK_WIDGET(g_array_index(window->terminals,
  142. MSSHTerminal*, i)))
  143. {
  144. idx = i;
  145. break;
  146. }
  147. }
  148. client = gconf_client_get_default();
  149. /* recolor the windows */
  150. if (window->recolor_focused) {
  151. entry = gconf_client_get_entry(client, MSSH_GCONF_KEY_FG_COLOUR, NULL,
  152. TRUE, NULL);
  153. mssh_gconf_notify_fg_colour(client, 0, entry, window);
  154. entry = gconf_client_get_entry(client, MSSH_GCONF_KEY_BG_COLOUR, NULL,
  155. TRUE, NULL);
  156. mssh_gconf_notify_bg_colour(client, 0, entry, window);
  157. }
  158. if(focus == window->global_entry && keyval == GDK_KEY_Down &&
  159. window->dir_focus)
  160. idx = 0;
  161. else if(idx == -1 && window->dir_focus)
  162. return TRUE;
  163. else
  164. {
  165. switch(keyval)
  166. {
  167. case GDK_KEY_Up:
  168. if(window->dir_focus)
  169. idx = idx - cols;
  170. break;
  171. case GDK_KEY_Down:
  172. if(window->dir_focus)
  173. {
  174. if((idx + cols >= len) && (idx < len -
  175. (len % cols) ? (len % cols) : cols))
  176. idx = len - 1;
  177. else
  178. idx = idx + cols;
  179. }
  180. break;
  181. case GDK_KEY_Left:
  182. if(idx % cols != 0 || !window->dir_focus)
  183. idx = idx - 1;
  184. break;
  185. case GDK_KEY_Right:
  186. if(idx % cols != cols - 1 || !window->dir_focus)
  187. idx = idx + 1;
  188. break;
  189. }
  190. }
  191. if(idx >= len && !window->dir_focus)
  192. focus = window->global_entry;
  193. if(idx < -1 && !window->dir_focus)
  194. idx = len - 1;
  195. if(idx < 0)
  196. focus = window->global_entry;
  197. else if(idx < len)
  198. {
  199. focus = GTK_WIDGET(g_array_index(window->terminals,
  200. MSSHTerminal*, idx));
  201. }
  202. gtk_window_set_focus(GTK_WINDOW(window), focus);
  203. return TRUE;
  204. }
  205. static gboolean mssh_window_session_close(gpointer data)
  206. {
  207. int i, idx = -1;
  208. struct WinTermPair *data_pair = (struct WinTermPair*)data;
  209. for(i = 0; i < data_pair->window->terminals->len; i++)
  210. {
  211. if(data_pair->terminal == g_array_index(
  212. data_pair->window->terminals, MSSHTerminal*, i))
  213. {
  214. idx = i;
  215. break;
  216. }
  217. }
  218. data_pair->window->last_closed = idx;
  219. if(idx == -1)
  220. {
  221. fprintf(stderr,
  222. _("mssh: Fatal Error: Can't find terminal to remove!\n"));
  223. }
  224. else
  225. {
  226. /* set the focus on the entry only if the terminal closed has it */
  227. if ( gtk_window_get_focus(GTK_WINDOW(data_pair->window)) == GTK_WIDGET(data_pair->terminal) ) {
  228. gtk_window_set_focus(GTK_WINDOW(data_pair->window), GTK_WIDGET(data_pair->window->global_entry));
  229. }
  230. gtk_widget_destroy(data_pair->terminal->menu_item);
  231. gtk_container_remove(GTK_CONTAINER(data_pair->window->grid),
  232. GTK_WIDGET(data_pair->terminal));
  233. g_array_remove_index(data_pair->window->terminals, idx);
  234. mssh_window_relayout(data_pair->window);
  235. }
  236. if(data_pair->window->terminals->len == 0 &&
  237. data_pair->window->exit_on_all_closed)
  238. {
  239. mssh_window_destroy(NULL, (void*)data_pair->window);
  240. }
  241. free(data_pair);
  242. return FALSE;
  243. }
  244. void mssh_window_session_closed(MSSHTerminal *terminal, gpointer data)
  245. {
  246. struct WinTermPair *data_pair = malloc(sizeof(struct WinTermPair));
  247. data_pair->terminal = terminal;
  248. data_pair->window = MSSH_WINDOW(data);
  249. if(data_pair->window->close_ended_sessions)
  250. {
  251. g_timeout_add_seconds(data_pair->window->timeout,
  252. mssh_window_session_close, data_pair);
  253. }
  254. }
  255. static gboolean mssh_window_mouse_paste_cb(MSSHTerminal *terminal,
  256. gpointer data)
  257. {
  258. gtk_widget_grab_focus(GTK_WIDGET(terminal));
  259. return FALSE;
  260. }
  261. static void mssh_window_session_focused(MSSHTerminal *terminal,
  262. gpointer data)
  263. {
  264. char *title;
  265. size_t len;
  266. GConfClient *client;
  267. GConfEntry *entry;
  268. MSSHWindow *window = MSSH_WINDOW(data);
  269. len = strlen(PACKAGE_NAME" - ") + strlen(terminal->hostname) + 1;
  270. title = malloc(len);
  271. snprintf(title, len, PACKAGE_NAME" - %s", terminal->hostname);
  272. gtk_window_set_title(GTK_WINDOW(window), title);
  273. free(title);
  274. client = gconf_client_get_default();
  275. /* recolor all windows */
  276. entry = gconf_client_get_entry(client, MSSH_GCONF_KEY_FG_COLOUR, NULL,
  277. TRUE, NULL);
  278. mssh_gconf_notify_fg_colour(client, 0, entry, window);
  279. entry = gconf_client_get_entry(client, MSSH_GCONF_KEY_BG_COLOUR, NULL,
  280. TRUE, NULL);
  281. mssh_gconf_notify_bg_colour(client, 0, entry, window);
  282. /* recolor the focused window - if needed */
  283. if (window->recolor_focused && window->is_maximized == 0) {
  284. entry = gconf_client_get_entry(client, MSSH_GCONF_KEY_FG_COLOUR_FOCUS, NULL,
  285. TRUE, NULL);
  286. mssh_gconf_notify_fg_colour_focus(client, 0, entry, window);
  287. entry = gconf_client_get_entry(client, MSSH_GCONF_KEY_BG_COLOUR_FOCUS, NULL,
  288. TRUE, NULL);
  289. mssh_gconf_notify_bg_colour_focus(client, 0, entry, window);
  290. }
  291. }
  292. void mssh_window_relayout(MSSHWindow *window)
  293. {
  294. GConfClient *client;
  295. GConfEntry *entry;
  296. GtkWidget *focus;
  297. int i, len = window->terminals->len;
  298. int wcols = window->columns_override ? window->columns_override :
  299. window->columns;
  300. int cols = (len < wcols) ? len : wcols;
  301. int width = 1;
  302. focus = gtk_window_get_focus(GTK_WINDOW(window));
  303. if(!focus)
  304. {
  305. if(window->last_closed < 0)
  306. window->last_closed = 0;
  307. if(len == 0)
  308. focus = window->global_entry;
  309. else if(window->last_closed < len)
  310. {
  311. focus = GTK_WIDGET(g_array_index(window->terminals,
  312. MSSHTerminal*, window->last_closed));
  313. }
  314. else
  315. {
  316. focus = GTK_WIDGET(g_array_index(window->terminals,
  317. MSSHTerminal*, 0));
  318. }
  319. }
  320. for(i = 0; i < len; i++)
  321. {
  322. MSSHTerminal *terminal = g_array_index(window->terminals,
  323. MSSHTerminal*, i);
  324. g_object_ref(terminal);
  325. if(gtk_widget_get_parent(GTK_WIDGET(terminal)) == GTK_WIDGET(window->grid))
  326. {
  327. gtk_container_remove(GTK_CONTAINER(window->grid),
  328. GTK_WIDGET(terminal));
  329. }
  330. /* Set margins to terminal widget */
  331. gtk_widget_set_margin_start(GTK_WIDGET(terminal), 1);
  332. gtk_widget_set_margin_end(GTK_WIDGET(terminal), 1);
  333. gtk_widget_set_margin_top(GTK_WIDGET(terminal), 1);
  334. gtk_widget_set_margin_bottom(GTK_WIDGET(terminal), 1);
  335. if (i == len - 1) {
  336. width = cols - (i % cols);
  337. }
  338. gtk_grid_attach(GTK_GRID(window->grid), /* grid */
  339. GTK_WIDGET(terminal), /* child */
  340. (i % cols), /* left */
  341. i / cols, /* top */
  342. width, /* width */
  343. 1); /* height */
  344. g_object_unref(terminal);
  345. if(!terminal->started)
  346. {
  347. mssh_terminal_start_session(terminal, window->env);
  348. terminal->started = 1;
  349. }
  350. }
  351. client = gconf_client_get_default();
  352. gtk_widget_show_all(GTK_WIDGET(window));
  353. entry = gconf_client_get_entry(client, MSSH_GCONF_KEY_FONT, NULL,
  354. TRUE, NULL);
  355. mssh_gconf_notify_font(client, 0, entry, window);
  356. entry = gconf_client_get_entry(client, MSSH_GCONF_KEY_FG_COLOUR, NULL,
  357. TRUE, NULL);
  358. mssh_gconf_notify_fg_colour(client, 0, entry, window);
  359. entry = gconf_client_get_entry(client, MSSH_GCONF_KEY_BG_COLOUR, NULL,
  360. TRUE, NULL);
  361. mssh_gconf_notify_bg_colour(client, 0, entry, window);
  362. gtk_window_set_focus(GTK_WINDOW(window), GTK_WIDGET(focus));
  363. }
  364. static void mssh_window_add_session(MSSHWindow *window, char *hostname)
  365. {
  366. MSSHTerminal *terminal = MSSH_TERMINAL(mssh_terminal_new());
  367. terminal->backscroll_buffer_size = window->backscroll_buffer_size;
  368. g_array_append_val(window->terminals, terminal);
  369. g_signal_connect(G_OBJECT(terminal), "session-closed",
  370. G_CALLBACK(mssh_window_session_closed), window);
  371. g_signal_connect(G_OBJECT(terminal), "session-focused",
  372. G_CALLBACK(mssh_window_session_focused), window);
  373. g_signal_connect(GTK_WIDGET(terminal), "button-release-event",
  374. G_CALLBACK(mssh_window_mouse_paste_cb), window);
  375. mssh_terminal_init_session(terminal, hostname);
  376. gtk_menu_shell_append(GTK_MENU_SHELL(window->server_menu),
  377. terminal->menu_item);
  378. }
  379. static void mssh_window_init(MSSHWindow* window)
  380. {
  381. GConfClient *client;
  382. GtkWidget *vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
  383. GtkWidget *entry = gtk_entry_new();
  384. GtkWidget *menu_bar = gtk_menu_bar_new();
  385. GtkWidget *file_menu = gtk_menu_new();
  386. GtkWidget *edit_menu = gtk_menu_new();
  387. GtkWidget *file_item = gtk_menu_item_new_with_label(_("File"));
  388. GtkWidget *edit_item = gtk_menu_item_new_with_label(_("Edit"));
  389. GtkWidget *server_item = gtk_menu_item_new_with_label(_("Servers"));
  390. GtkWidget *command_item = gtk_menu_item_new_with_label(_("Commands"));
  391. GtkWidget *file_quit = gtk_menu_item_new_with_mnemonic(_("_Quit"));
  392. GtkWidget *file_sendhost = gtk_menu_item_new_with_label(_("Send hostname"));
  393. GtkWidget *file_add = gtk_menu_item_new_with_label(_("Add session"));
  394. GtkWidget *edit_pref = gtk_menu_item_new_with_mnemonic(_("_Edit"));
  395. GtkAccelGroup *accel = gtk_accel_group_new();
  396. window->accel = NULL;
  397. window->server_menu = gtk_menu_new();
  398. window->command_menu = gtk_menu_new();
  399. window->global_entry = entry;
  400. window->last_closed = -1;
  401. window->terminals = g_array_new(FALSE, TRUE, sizeof(MSSHTerminal*));
  402. window->backscroll_buffer_size = 5000;
  403. window->is_maximized = 0;
  404. window->recolor_focused = FALSE;
  405. gtk_menu_item_set_submenu(GTK_MENU_ITEM(file_item), file_menu);
  406. gtk_menu_item_set_submenu(GTK_MENU_ITEM(edit_item), edit_menu);
  407. gtk_menu_item_set_submenu(GTK_MENU_ITEM(server_item),
  408. window->server_menu);
  409. gtk_menu_item_set_submenu(GTK_MENU_ITEM(command_item),
  410. window->command_menu);
  411. gtk_menu_shell_append(GTK_MENU_SHELL(file_menu), file_add);
  412. gtk_menu_shell_append(GTK_MENU_SHELL(file_menu), file_sendhost);
  413. gtk_menu_shell_append(GTK_MENU_SHELL(file_menu), file_quit);
  414. gtk_menu_shell_append(GTK_MENU_SHELL(edit_menu), edit_pref);
  415. g_signal_connect(G_OBJECT(file_sendhost), "activate",
  416. G_CALLBACK(mssh_window_sendhost), window);
  417. g_signal_connect(G_OBJECT(file_add), "activate",
  418. G_CALLBACK(mssh_window_add), window);
  419. g_signal_connect(G_OBJECT(file_quit), "activate",
  420. G_CALLBACK(mssh_window_destroy), window);
  421. g_signal_connect(G_OBJECT(edit_pref), "activate",
  422. G_CALLBACK(mssh_window_pref), window);
  423. gtk_menu_shell_append(GTK_MENU_SHELL(menu_bar), file_item);
  424. gtk_menu_shell_append(GTK_MENU_SHELL(menu_bar), edit_item);
  425. gtk_menu_shell_append(GTK_MENU_SHELL(menu_bar), server_item);
  426. gtk_menu_shell_append(GTK_MENU_SHELL(menu_bar), command_item);
  427. g_signal_connect(G_OBJECT(entry), "key-press-event",
  428. G_CALLBACK(mssh_window_key_press), window);
  429. g_signal_connect(G_OBJECT(entry), "insert-text",
  430. G_CALLBACK(mssh_window_insert), window);
  431. g_signal_connect(G_OBJECT(entry), "focus-in-event",
  432. G_CALLBACK(mssh_window_entry_focused), window);
  433. gtk_box_pack_start(GTK_BOX(vbox), menu_bar, FALSE, TRUE, 0);
  434. gtk_box_pack_start(GTK_BOX(vbox), entry, FALSE, TRUE, 2);
  435. window->grid = gtk_grid_new();
  436. gtk_grid_set_row_homogeneous(GTK_GRID(window->grid), TRUE);
  437. gtk_grid_set_column_homogeneous(GTK_GRID(window->grid), TRUE);
  438. gtk_box_pack_start(GTK_BOX(vbox), window->grid, TRUE, TRUE, 0);
  439. gtk_container_add(GTK_CONTAINER(window), vbox);
  440. gtk_widget_set_size_request(GTK_WIDGET(window), 0, 0);
  441. gtk_window_set_default_size(GTK_WINDOW(window), 1024, 768);
  442. gtk_window_set_title(GTK_WINDOW(window), PACKAGE_NAME);
  443. client = gconf_client_get_default();
  444. gconf_client_add_dir(client, MSSH_GCONF_PATH,
  445. GCONF_CLIENT_PRELOAD_RECURSIVE, NULL);
  446. gconf_client_notify_add(client, MSSH_GCONF_KEY_FONT,
  447. mssh_gconf_notify_font, window, NULL, NULL);
  448. gconf_client_notify_add(client, MSSH_GCONF_KEY_FG_COLOUR,
  449. mssh_gconf_notify_fg_colour, window, NULL, NULL);
  450. gconf_client_notify_add(client, MSSH_GCONF_KEY_BG_COLOUR,
  451. mssh_gconf_notify_bg_colour, window, NULL, NULL);
  452. gconf_client_notify_add(client, MSSH_GCONF_KEY_FG_COLOUR_FOCUS,
  453. mssh_gconf_notify_fg_colour_focus, window, NULL, NULL);
  454. gconf_client_notify_add(client, MSSH_GCONF_KEY_BG_COLOUR_FOCUS,
  455. mssh_gconf_notify_bg_colour_focus, window, NULL, NULL);
  456. gconf_client_notify_add(client, MSSH_GCONF_KEY_COLUMNS,
  457. mssh_gconf_notify_columns, window, NULL, NULL);
  458. gconf_client_notify_add(client, MSSH_GCONF_KEY_TIMEOUT,
  459. mssh_gconf_notify_timeout, window, NULL, NULL);
  460. gconf_client_notify_add(client, MSSH_GCONF_KEY_CLOSE_ENDED,
  461. mssh_gconf_notify_close_ended, window, NULL, NULL);
  462. gconf_client_notify_add(client, MSSH_GCONF_KEY_RECOLOR_FOCUSED,
  463. mssh_gconf_notify_recolor_focused, window, NULL, NULL);
  464. gconf_client_notify_add(client, MSSH_GCONF_KEY_QUIT_ALL_ENDED,
  465. mssh_gconf_notify_quit_all_ended, window, NULL, NULL);
  466. gconf_client_notify_add(client, MSSH_GCONF_KEY_DIR_FOCUS,
  467. mssh_gconf_notify_dir_focus, window, NULL, NULL);
  468. gconf_client_notify_add(client, MSSH_GCONF_KEY_MODIFIER,
  469. mssh_gconf_notify_modifier, window, NULL, NULL);
  470. gconf_client_notify_add(client, MSSH_GCONF_KEY_BACKSCROLL_BUFFER_SIZE,
  471. mssh_gconf_backscroll_buffer_size, window, NULL, NULL);
  472. gconf_client_notify(client, MSSH_GCONF_KEY_COLUMNS);
  473. gconf_client_notify(client, MSSH_GCONF_KEY_TIMEOUT);
  474. gconf_client_notify(client, MSSH_GCONF_KEY_CLOSE_ENDED);
  475. gconf_client_notify(client, MSSH_GCONF_KEY_RECOLOR_FOCUSED);
  476. gconf_client_notify(client, MSSH_GCONF_KEY_QUIT_ALL_ENDED);
  477. gconf_client_notify(client, MSSH_GCONF_KEY_DIR_FOCUS);
  478. gconf_client_notify(client, MSSH_GCONF_KEY_MODIFIER);
  479. gconf_client_notify(client, MSSH_GCONF_KEY_BACKSCROLL_BUFFER_SIZE);
  480. gtk_accel_group_connect(accel, GDK_KEY_Up, window->modifier,
  481. GTK_ACCEL_VISIBLE, g_cclosure_new(
  482. G_CALLBACK(mssh_window_focus), window, NULL));
  483. gtk_accel_group_connect(accel, GDK_KEY_Down, window->modifier,
  484. GTK_ACCEL_VISIBLE, g_cclosure_new(
  485. G_CALLBACK(mssh_window_focus), window, NULL));
  486. gtk_accel_group_connect(accel, GDK_KEY_Left, window->modifier,
  487. GTK_ACCEL_VISIBLE, g_cclosure_new(
  488. G_CALLBACK(mssh_window_focus), window, NULL));
  489. gtk_accel_group_connect(accel, GDK_KEY_Right, window->modifier,
  490. GTK_ACCEL_VISIBLE, g_cclosure_new(
  491. G_CALLBACK(mssh_window_focus), window, NULL));
  492. /* bind Ctrl + Shift + x to toggling maximize terminal */
  493. gtk_accel_group_connect(accel, GDK_KEY_x, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
  494. GTK_ACCEL_VISIBLE, g_cclosure_new(
  495. G_CALLBACK(mssh_window_toggle_maximize), window, NULL));
  496. /* bind Ctrl + Shift + N to show the dialog for adding new sessions */
  497. gtk_accel_group_connect(accel, GDK_KEY_n, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
  498. GTK_ACCEL_VISIBLE, g_cclosure_new(
  499. G_CALLBACK(mssh_window_add), window, NULL));
  500. window->accel = accel;
  501. gtk_window_add_accel_group(GTK_WINDOW(window), accel);
  502. }
  503. void mssh_window_start_session(MSSHWindow* window, char **env,
  504. GArray *hosts, long cols)
  505. {
  506. int i, j, k;
  507. int nhosts = hosts->len;
  508. int rows = (nhosts / 2) + (nhosts % 2);
  509. window->env = env;
  510. window->columns_override = cols;
  511. for(i = 0; i < rows; i++)
  512. {
  513. for(j = 0; j < 2; j++)
  514. {
  515. k = j + i*2;
  516. if(k < nhosts)
  517. {
  518. mssh_window_add_session(window, g_array_index(hosts,
  519. char*, k));
  520. }
  521. }
  522. }
  523. mssh_window_relayout(window);
  524. }
  525. void mssh_window_add_command(GQuark key_id, gpointer data, gpointer user_data)
  526. {
  527. GtkWidget *menu_item;
  528. GtkWidget* window = (GtkWidget *)user_data;
  529. menu_item = gtk_menu_item_new_with_label(g_quark_to_string (key_id));
  530. gtk_menu_shell_append(GTK_MENU_SHELL(MSSH_WINDOW(window)->command_menu), menu_item);
  531. g_signal_connect(G_OBJECT(menu_item), "activate",
  532. G_CALLBACK(mssh_window_sendcommand), window);
  533. }
  534. static void mssh_window_class_init(MSSHWindowClass *klass)
  535. {
  536. }
  537. void mssh_window_relayout_for_one(MSSHWindow *window, GtkWidget *t)
  538. {
  539. GConfClient *client;
  540. GConfEntry *entry;
  541. int len = window->terminals->len;
  542. int wcols = window->columns_override ? window->columns_override :
  543. window->columns;
  544. int cols = (len < wcols) ? len : wcols;
  545. int rows = (len + 1) / cols;
  546. /* get the terminal widget */
  547. GtkWidget *terminal = GTK_WIDGET(t);
  548. g_object_ref(terminal);
  549. /* remove the widget from the container temporarily */
  550. gtk_container_remove(GTK_CONTAINER(window->grid), GTK_WIDGET(terminal));
  551. /* add it back again, now resized */
  552. gtk_grid_attach(GTK_GRID(window->grid), GTK_WIDGET(terminal), 0, 0, cols, rows);
  553. /* make the terminal focused */
  554. gtk_window_set_focus(GTK_WINDOW(window), GTK_WIDGET(terminal));
  555. /* remove the coloring */
  556. if (window->recolor_focused) {
  557. client = gconf_client_get_default();
  558. entry = gconf_client_get_entry(client, MSSH_GCONF_KEY_FG_COLOUR, NULL,
  559. TRUE, NULL);
  560. mssh_gconf_notify_fg_colour(client, 0, entry, window);
  561. entry = gconf_client_get_entry(client, MSSH_GCONF_KEY_BG_COLOUR, NULL,
  562. TRUE, NULL);
  563. mssh_gconf_notify_bg_colour(client, 0, entry, window);
  564. }
  565. g_object_unref(terminal);
  566. }
  567. gboolean mssh_window_toggle_maximize(GtkWidget *widget, GObject *acceleratable,
  568. guint keyval, GdkModifierType modifier, gpointer data)
  569. {
  570. MSSHWindow *window = MSSH_WINDOW(data);
  571. if (window->is_maximized) {
  572. /* toggle restore */
  573. mssh_window_restore_layout(widget, data);
  574. } else {
  575. /* toggle maximize */
  576. mssh_window_maximize(widget, data);
  577. }
  578. return TRUE;
  579. }
  580. static void mssh_window_maximize(GtkWidget *widget, gpointer data)
  581. {
  582. /* find the id of the currently focused window (if any) */
  583. MSSHWindow *window = MSSH_WINDOW(data);
  584. int i;
  585. int idx = -1;
  586. int len = window->terminals->len;
  587. GConfClient *client;
  588. GConfEntry *entry;
  589. /* get the currently focused window */
  590. GtkWidget *focus = gtk_window_get_focus(GTK_WINDOW(window));
  591. /* save the currently focused window so we can restore it later */
  592. window->last_focus = focus;
  593. /* find the focused window in the terminal list */
  594. for(i = 0; i < len; i++)
  595. {
  596. if(focus == GTK_WIDGET(g_array_index(window->terminals,
  597. MSSHTerminal*, i)))
  598. {
  599. idx = i;
  600. break;
  601. }
  602. }
  603. /* recolor the window with the normal color */
  604. if (window->recolor_focused) {
  605. client = gconf_client_get_default();
  606. entry = gconf_client_get_entry(client, MSSH_GCONF_KEY_FG_COLOUR, NULL,
  607. TRUE, NULL);
  608. mssh_gconf_notify_fg_colour(client, 0, entry, window);
  609. entry = gconf_client_get_entry(client, MSSH_GCONF_KEY_BG_COLOUR, NULL,
  610. TRUE, NULL);
  611. mssh_gconf_notify_bg_colour(client, 0, entry, window);
  612. }
  613. if (idx == -1) {
  614. /* there's no window focused, do nothing */
  615. } else {
  616. /* call relayout, it will reposition the widget to occupy the whole table */
  617. mssh_window_relayout_for_one(window, GTK_WIDGET(g_array_index(window->terminals,
  618. MSSHTerminal*, idx)));
  619. window->is_maximized = 1;
  620. }
  621. }
  622. static void mssh_window_restore_layout(GtkWidget *widget, gpointer data)
  623. {
  624. GConfClient *client;
  625. GConfEntry *entry;
  626. /* get the window */
  627. MSSHWindow *window = MSSH_WINDOW(data);
  628. /* just call relayout */
  629. mssh_window_relayout(window);
  630. window->is_maximized = 0;
  631. /* restore the focus */
  632. if (window->last_focus != NULL) {
  633. gtk_window_set_focus(GTK_WINDOW(window), window->last_focus);
  634. }
  635. /* recolor the focused window - if needed */
  636. client = gconf_client_get_default();
  637. if (window->recolor_focused && window->is_maximized == 0) {
  638. entry = gconf_client_get_entry(client, MSSH_GCONF_KEY_FG_COLOUR_FOCUS, NULL,
  639. TRUE, NULL);
  640. mssh_gconf_notify_fg_colour_focus(client, 0, entry, window);
  641. entry = gconf_client_get_entry(client, MSSH_GCONF_KEY_BG_COLOUR_FOCUS, NULL,
  642. TRUE, NULL);
  643. mssh_gconf_notify_bg_colour_focus(client, 0, entry, window);
  644. }
  645. }
  646. /* show a popup window for adding new sessions */
  647. static void mssh_window_add(GtkWidget *widget, gpointer data)
  648. {
  649. MSSHWindow *window = MSSH_WINDOW(data);
  650. GtkWidget *dialog, *label, *content_area, *button_add;
  651. GtkWidget *new_session_entry;
  652. gint result;
  653. /* create new dialog */
  654. dialog = gtk_dialog_new();
  655. /* get the content area that will be packed */
  656. content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
  657. /* label for text */
  658. label = gtk_label_new (_("Add new session with hostname: "));
  659. /* Add the label and entry, and show everything we've added to the dialog */
  660. new_session_entry = gtk_entry_new();
  661. gtk_entry_set_max_length (GTK_ENTRY(new_session_entry), 255);
  662. /* pack the widgets */
  663. gtk_container_add (GTK_CONTAINER (content_area), label);
  664. gtk_container_add (GTK_CONTAINER (content_area), new_session_entry);
  665. /* add two buttons */
  666. button_add = gtk_dialog_add_button(GTK_DIALOG(dialog), _("Add"), GTK_RESPONSE_ACCEPT);
  667. gtk_dialog_add_button(GTK_DIALOG(dialog), _("Cancel"), GTK_RESPONSE_CANCEL);
  668. /* make the add button the default */
  669. gtk_widget_grab_default(button_add);
  670. /* set dialog properties (modal, etc) */
  671. gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
  672. gtk_window_set_destroy_with_parent(GTK_WINDOW(dialog), TRUE);
  673. gtk_window_set_transient_for (GTK_WINDOW(dialog), GTK_WINDOW(window));
  674. /* set it's title */
  675. gtk_window_set_title(GTK_WINDOW(dialog), _("Add new session"));
  676. /* catch the activate signal (hitting enter) */
  677. g_signal_connect(G_OBJECT(new_session_entry), "activate",
  678. G_CALLBACK(mssh_window_dialog_emit_response), window);
  679. /* show the dialog and it's widgets */
  680. gtk_widget_show_all (dialog);
  681. /* wait for input */
  682. result = gtk_dialog_run (GTK_DIALOG (dialog));
  683. switch (result)
  684. {
  685. case GTK_RESPONSE_ACCEPT:
  686. mssh_window_add_session(window, (gchar*) gtk_entry_get_text(GTK_ENTRY(new_session_entry)));
  687. /* relayout */
  688. mssh_window_relayout(window);
  689. break;
  690. default:
  691. /* do nothing */
  692. break;
  693. }
  694. gtk_widget_destroy (dialog);
  695. }
  696. /* catch the 'activate' signal of the entry (return has been pushed) */
  697. /* emit the response for accept, simulating a mouse click on the add button */
  698. gboolean mssh_window_dialog_emit_response(GtkWidget *widget, GObject *acceleratable,
  699. guint keyval, GdkModifierType modifier, gpointer data)
  700. {
  701. /* get the dialog by getting the parent of the parent for the emitting (entry) widget */
  702. GtkWidget *vbox = gtk_widget_get_parent(widget);
  703. GtkWidget *dialog = gtk_widget_get_parent(vbox);
  704. /* emit the response signal simulating the clicking of 'ok' */
  705. gtk_dialog_response (GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
  706. return TRUE;
  707. }