mssh-window.c 23 KB

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