mssh-window.c 27 KB

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