mssh-window.c 24 KB

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