mssh-window.c 28 KB

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