1 /*
2 * Copyright © 2001 Havoc Pennington
3 * Copyright © 2002 Red Hat, Inc.
4 * Copyright © 2007, 2008, 2009 Christian Persch
5 * Copyright (C) 2012-2021 MATE Developers
6 *
7 * Mate-terminal is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * Mate-terminal is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include <config.h>
22
23 #include <string.h>
24 #include <stdlib.h>
25 #include <gtk/gtk.h>
26 #include <gdk/gdk.h>
27 #ifdef GDK_WINDOWING_X11
28 #include <gdk/gdkx.h>
29 #endif
30 #include <gdk/gdkkeysyms.h>
31
32 #include "terminal-accels.h"
33 #include "terminal-app.h"
34 #include "terminal-debug.h"
35 #include "terminal-encoding.h"
36 #include "terminal-intl.h"
37 #include "terminal-screen-container.h"
38 #include "terminal-search-dialog.h"
39 #include "terminal-tab-label.h"
40 #include "terminal-tabs-menu.h"
41 #include "terminal-util.h"
42 #include "terminal-window.h"
43
44 #ifdef ENABLE_SKEY
45 #include "skey-popup.h"
46 #endif
47
48 static gboolean detach_tab = FALSE;
49
50 struct _TerminalWindowPrivate
51 {
52 GtkActionGroup *action_group;
53 GtkUIManager *ui_manager;
54 guint ui_id;
55
56 GtkActionGroup *profiles_action_group;
57 guint profiles_ui_id;
58
59 GtkActionGroup *encodings_action_group;
60 guint encodings_ui_id;
61
62 TerminalTabsMenu *tabs_menu;
63
64 TerminalScreenPopupInfo *popup_info;
65 guint remove_popup_info_idle;
66
67 GtkActionGroup *new_terminal_action_group;
68 guint new_terminal_ui_id;
69
70 GtkWidget *menubar;
71 GtkWidget *notebook;
72 GtkWidget *main_vbox;
73 TerminalScreen *active_screen;
74
75 /* Size of a character cell in pixels */
76 int old_char_width;
77 int old_char_height;
78
79 /* Width and height added to the actual terminal grid by "chrome" inside
80 * what was traditionally the X11 window: menu bar, title bar,
81 * style-provided padding. This must be included when resizing the window
82 * and also included in geometry hints. */
83 int old_chrome_width;
84 int old_chrome_height;
85
86 /* Width and height of the padding around the geometry widget. */
87 int old_padding_width;
88 int old_padding_height;
89
90 void *old_geometry_widget; /* only used for pointer value as it may be freed */
91
92 GtkWidget *confirm_close_dialog;
93 GtkWidget *search_find_dialog;
94
95 guint menubar_visible : 1;
96 guint use_default_menubar_visibility : 1;
97
98 /* Compositing manager integration */
99 guint have_argb_visual : 1;
100
101 /* Used to clear stray "demands attention" flashing on our window when we
102 * unmap and map it to switch to an ARGB visual.
103 */
104 guint clear_demands_attention : 1;
105
106 guint disposed : 1;
107 guint present_on_insert : 1;
108
109 /* Workaround until gtk+ bug #535557 is fixed */
110 guint icon_title_set : 1;
111 time_t focus_time;
112
113 /* should we copy selection to clibpoard */
114 int copy_selection;
115 };
116
117 #define PROFILE_DATA_KEY "GT::Profile"
118
119 #define FILE_NEW_TERMINAL_TAB_UI_PATH "/menubar/File/FileNewTabProfiles"
120 #define FILE_NEW_TERMINAL_WINDOW_UI_PATH "/menubar/File/FileNewWindowProfiles"
121 #define SET_ENCODING_UI_PATH "/menubar/Terminal/TerminalSetEncoding/EncodingsPH"
122 #define SET_ENCODING_ACTION_NAME_PREFIX "TerminalSetEncoding"
123
124 #define PROFILES_UI_PATH "/menubar/Terminal/TerminalProfiles/ProfilesPH"
125 #define PROFILES_POPUP_UI_PATH "/Popup/PopupTerminalProfiles/ProfilesPH"
126
127 #define SIZE_TO_UI_PATH "/menubar/Terminal/TerminalSizeToPH"
128 #define SIZE_TO_ACTION_NAME_PREFIX "TerminalSizeTo"
129
130 #define STOCK_NEW_TAB "tab-new"
131
132 #define ENCODING_DATA_KEY "encoding"
133
134 #if 1
135 /*
136 * We don't want to enable content saving until vte supports it async.
137 * So we disable this code for stable versions.
138 */
139 #include "terminal-version.h"
140
141 #if (TERMINAL_MINOR_VERSION & 1) != 0
142 #define ENABLE_SAVE
143 #else
144 #undef ENABLE_SAVE
145 #endif
146 #endif
147
148 static void terminal_window_dispose (GObject *object);
149 static void terminal_window_finalize (GObject *object);
150 static gboolean terminal_window_state_event (GtkWidget *widget,
151 GdkEventWindowState *event);
152
153 static gboolean terminal_window_delete_event (GtkWidget *widget,
154 GdkEvent *event,
155 gpointer data);
156 static gboolean terminal_window_focus_in_event (GtkWidget *widget,
157 GdkEventFocus *event,
158 gpointer data);
159
160 static gboolean notebook_button_press_cb (GtkWidget *notebook,
161 GdkEventButton *event,
162 GSettings *settings);
163 static gboolean window_key_press_cb (GtkWidget *notebook,
164 GdkEventKey *event,
165 GSettings *settings);
166 static gboolean notebook_popup_menu_cb (GtkWidget *notebook,
167 TerminalWindow *window);
168 static void notebook_page_selected_callback (GtkWidget *notebook,
169 GtkWidget *page,
170 guint page_num,
171 TerminalWindow *window);
172 static void notebook_page_added_callback (GtkWidget *notebook,
173 GtkWidget *container,
174 guint page_num,
175 TerminalWindow *window);
176 static void notebook_page_removed_callback (GtkWidget *notebook,
177 GtkWidget *container,
178 guint page_num,
179 TerminalWindow *window);
180 static gboolean notebook_scroll_event_cb (GtkWidget *notebook,
181 GdkEventScroll *event,
182 TerminalWindow *window);
183
184 /* Menu action callbacks */
185 static void file_new_window_callback (GtkAction *action,
186 TerminalWindow *window);
187 static void file_new_tab_callback (GtkAction *action,
188 TerminalWindow *window);
189 static void file_new_profile_callback (GtkAction *action,
190 TerminalWindow *window);
191 static void file_close_window_callback (GtkAction *action,
192 TerminalWindow *window);
193 static void file_save_contents_callback (GtkAction *action,
194 TerminalWindow *window);
195 static void file_close_tab_callback (GtkAction *action,
196 TerminalWindow *window);
197 static void edit_copy_callback (GtkAction *action,
198 TerminalWindow *window);
199 static void edit_paste_callback (GtkAction *action,
200 TerminalWindow *window);
201 static void edit_select_all_callback (GtkAction *action,
202 TerminalWindow *window);
203 static void edit_keybindings_callback (GtkAction *action,
204 TerminalWindow *window);
205 static void edit_profiles_callback (GtkAction *action,
206 TerminalWindow *window);
207 static void edit_current_profile_callback (GtkAction *action,
208 TerminalWindow *window);
209 static void view_menubar_toggled_callback (GtkToggleAction *action,
210 TerminalWindow *window);
211 static void view_fullscreen_toggled_callback (GtkToggleAction *action,
212 TerminalWindow *window);
213 static void view_zoom_in_callback (GtkAction *action,
214 TerminalWindow *window);
215 static void view_zoom_out_callback (GtkAction *action,
216 TerminalWindow *window);
217 static void view_zoom_normal_callback (GtkAction *action,
218 TerminalWindow *window);
219 static void search_find_callback (GtkAction *action,
220 TerminalWindow *window);
221 static void search_find_next_callback (GtkAction *action,
222 TerminalWindow *window);
223 static void search_find_prev_callback (GtkAction *action,
224 TerminalWindow *window);
225 static void search_clear_highlight_callback (GtkAction *action,
226 TerminalWindow *window);
227 static void terminal_next_or_previous_profile_cb (GtkAction *action,
228 TerminalWindow *window);
229 static void terminal_set_title_callback (GtkAction *action,
230 TerminalWindow *window);
231 static void terminal_add_encoding_callback (GtkAction *action,
232 TerminalWindow *window);
233 static void terminal_reset_callback (GtkAction *action,
234 TerminalWindow *window);
235 static void terminal_reset_clear_callback (GtkAction *action,
236 TerminalWindow *window);
237 static void tabs_next_or_previous_tab_cb (GtkAction *action,
238 TerminalWindow *window);
239 static void tabs_move_left_callback (GtkAction *action,
240 TerminalWindow *window);
241 static void tabs_move_right_callback (GtkAction *action,
242 TerminalWindow *window);
243 static void tabs_detach_tab_callback (GtkAction *action,
244 TerminalWindow *window);
245 static void help_contents_callback (GtkAction *action,
246 TerminalWindow *window);
247 static void help_about_callback (GtkAction *action,
248 TerminalWindow *window);
249
250 static gboolean find_larger_zoom_factor (double current,
251 double *found);
252 static gboolean find_smaller_zoom_factor (double current,
253 double *found);
254
255 static void terminal_window_show (GtkWidget *widget);
256
257 static gboolean confirm_close_window_or_tab (TerminalWindow *window,
258 TerminalScreen *screen);
259
260 static void
261 profile_set_callback (TerminalScreen *screen,
262 TerminalProfile *old_profile,
263 TerminalWindow *window);
264 static void
265 sync_screen_icon_title (TerminalScreen *screen,
266 GParamSpec *psepc,
267 TerminalWindow *window);
268
G_DEFINE_TYPE_WITH_PRIVATE(TerminalWindow,terminal_window,GTK_TYPE_WINDOW)269 G_DEFINE_TYPE_WITH_PRIVATE (TerminalWindow, terminal_window, GTK_TYPE_WINDOW)
270
271 /* Menubar mnemonics & accel settings handling */
272
273 static void
274 app_setting_notify_cb (TerminalApp *app,
275 GParamSpec *pspec,
276 GdkScreen *screen)
277 {
278 GtkSettings *settings;
279 const char *prop_name;
280
281 if (pspec)
282 prop_name = pspec->name;
283 else
284 prop_name = NULL;
285
286 settings = gtk_settings_get_for_screen (screen);
287
288 if (!prop_name || prop_name == I_(TERMINAL_APP_ENABLE_MNEMONICS))
289 {
290 gboolean enable_mnemonics;
291
292 g_object_get (app, TERMINAL_APP_ENABLE_MNEMONICS, &enable_mnemonics, NULL);
293 g_object_set (settings, "gtk-enable-mnemonics", enable_mnemonics, NULL);
294 }
295
296 if (!prop_name || prop_name == I_(TERMINAL_APP_ENABLE_MENU_BAR_ACCEL))
297 {
298 /* const */ char *saved_menubar_accel;
299 gboolean enable_menubar_accel;
300
301 /* FIXME: Once gtk+ bug 507398 is fixed, use that to reset the property instead */
302 /* Now this is a bad hack on so many levels. */
303 saved_menubar_accel = g_object_get_data (G_OBJECT (settings), "GT::gtk-menu-bar-accel");
304 if (!saved_menubar_accel)
305 {
306 g_object_get (settings, "gtk-menu-bar-accel", &saved_menubar_accel, NULL);
307 g_object_set_data_full (G_OBJECT (settings), "GT::gtk-menu-bar-accel",
308 saved_menubar_accel, (GDestroyNotify) g_free);
309 }
310
311 g_object_get (app, TERMINAL_APP_ENABLE_MENU_BAR_ACCEL, &enable_menubar_accel, NULL);
312 if (enable_menubar_accel)
313 g_object_set (settings, "gtk-menu-bar-accel", saved_menubar_accel, NULL);
314 else
315 g_object_set (settings, "gtk-menu-bar-accel", NULL, NULL);
316 }
317 }
318
319 static void
app_setting_notify_destroy_cb(GdkScreen * screen)320 app_setting_notify_destroy_cb (GdkScreen *screen)
321 {
322 g_signal_handlers_disconnect_by_func (terminal_app_get (),
323 G_CALLBACK (app_setting_notify_cb),
324 screen);
325 }
326
327 /* utility functions */
328
329 /*
330 Derived from XParseGeometry() in X.org
331
332 Copyright 1985, 1986, 1987, 1998 The Open Group
333
334 All Rights Reserved.
335
336 The above copyright notice and this permission notice shall be included
337 in all copies or substantial portions of the Software.
338
339 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
340 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
341 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
342 IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
343 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
344 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
345 OTHER DEALINGS IN THE SOFTWARE.
346
347 Except as contained in this notice, the name of The Open Group shall
348 not be used in advertising or otherwise to promote the sale, use or
349 other dealings in this Software without prior written authorization
350 from The Open Group.
351 */
352
353 /*
354 * XParseGeometry parses strings of the form
355 * "=<width>x<height>{+-}<xoffset>{+-}<yoffset>", where
356 * width, height, xoffset, and yoffset are unsigned integers.
357 * Example: "=80x24+300-49"
358 * The equal sign is optional.
359 * It returns a bitmask that indicates which of the four values
360 * were actually found in the string. For each value found,
361 * the corresponding argument is updated; for each value
362 * not found, the corresponding argument is left unchanged.
363 */
364
365 /* The following code is from Xlib, and is minimally modified, so we
366 * can track any upstream changes if required. Don’t change this
367 * code. Or if you do, put in a huge comment marking which thing
368 * changed.
369 */
370
371 static int
terminal_window_ReadInteger(char * string,char ** NextString)372 terminal_window_ReadInteger (char *string,
373 char **NextString)
374 {
375 register int Result = 0;
376 int Sign = 1;
377
378 if (*string == '+')
379 string++;
380 else if (*string == '-')
381 {
382 string++;
383 Sign = -1;
384 }
385 for (; (*string >= '0') && (*string <= '9'); string++)
386 {
387 Result = (Result * 10) + (*string - '0');
388 }
389 *NextString = string;
390 if (Sign >= 0)
391 return (Result);
392 else
393 return (-Result);
394 }
395
396 /*
397 * Bitmask returned by XParseGeometry(). Each bit tells if the corresponding
398 * value (x, y, width, height) was found in the parsed string.
399 */
400 #define NoValue 0x0000
401 #define XValue 0x0001
402 #define YValue 0x0002
403 #define WidthValue 0x0004
404 #define HeightValue 0x0008
405 #define XNegative 0x0010
406 #define YNegative 0x0020
407
408 static int
terminal_window_XParseGeometry(const char * string,int * x,int * y,unsigned int * width,unsigned int * height)409 terminal_window_XParseGeometry (const char *string,
410 int *x, int *y,
411 unsigned int *width,
412 unsigned int *height)
413 {
414 int mask = NoValue;
415 register char *strind;
416 unsigned int tempWidth = 0, tempHeight = 0;
417 int tempX = 0, tempY = 0;
418 char *nextCharacter;
419
420 if ( (string == NULL) || (*string == '\0')) return(mask);
421 if (*string == '=')
422 string++; /* ignore possible '=' at beg of geometry spec */
423
424 strind = (char *)string;
425 if (*strind != '+' && *strind != '-' && *strind != 'x') {
426 tempWidth = terminal_window_ReadInteger(strind, &nextCharacter);
427 if (strind == nextCharacter)
428 return (0);
429 strind = nextCharacter;
430 mask |= WidthValue;
431 }
432
433 if (*strind == 'x' || *strind == 'X') {
434 strind++;
435 tempHeight = terminal_window_ReadInteger(strind, &nextCharacter);
436 if (strind == nextCharacter)
437 return (0);
438 strind = nextCharacter;
439 mask |= HeightValue;
440 }
441
442 if ((*strind == '+') || (*strind == '-')) {
443 if (*strind == '-') {
444 strind++;
445 tempX = -terminal_window_ReadInteger(strind, &nextCharacter);
446 if (strind == nextCharacter)
447 return (0);
448 strind = nextCharacter;
449 mask |= XNegative;
450
451 }
452 else
453 { strind++;
454 tempX = terminal_window_ReadInteger(strind, &nextCharacter);
455 if (strind == nextCharacter)
456 return(0);
457 strind = nextCharacter;
458 }
459 mask |= XValue;
460 if ((*strind == '+') || (*strind == '-')) {
461 if (*strind == '-') {
462 strind++;
463 tempY = -terminal_window_ReadInteger(strind, &nextCharacter);
464 if (strind == nextCharacter)
465 return(0);
466 strind = nextCharacter;
467 mask |= YNegative;
468
469 }
470 else
471 {
472 strind++;
473 tempY = terminal_window_ReadInteger(strind, &nextCharacter);
474 if (strind == nextCharacter)
475 return(0);
476 strind = nextCharacter;
477 }
478 mask |= YValue;
479 }
480 }
481
482 /* If strind isn't at the end of the string the it's an invalid
483 geometry specification. */
484
485 if (*strind != '\0') return (0);
486
487 if (mask & XValue)
488 *x = tempX;
489 if (mask & YValue)
490 *y = tempY;
491 if (mask & WidthValue)
492 *width = tempWidth;
493 if (mask & HeightValue)
494 *height = tempHeight;
495 return (mask);
496 }
497
498 static char *
escape_underscores(const char * name)499 escape_underscores (const char *name)
500 {
501 GString *escaped_name;
502
503 g_assert (name != NULL);
504
505 /* Who'd use more that 4 underscores in a profile name... */
506 escaped_name = g_string_sized_new (strlen (name) + 4 + 1);
507
508 while (*name)
509 {
510 if (*name == '_')
511 g_string_append (escaped_name, "__");
512 else
513 g_string_append_c (escaped_name, *name);
514 name++;
515 }
516
517 return g_string_free (escaped_name, FALSE);
518 }
519
520 static int
find_tab_num_at_pos(GtkNotebook * notebook,int screen_x,int screen_y)521 find_tab_num_at_pos (GtkNotebook *notebook,
522 int screen_x,
523 int screen_y)
524 {
525 GtkPositionType tab_pos;
526 int page_num = 0;
527 GtkNotebook *nb = GTK_NOTEBOOK (notebook);
528 GtkWidget *page;
529 GtkAllocation tab_allocation;
530
531 tab_pos = gtk_notebook_get_tab_pos (GTK_NOTEBOOK (notebook));
532
533 while ((page = gtk_notebook_get_nth_page (nb, page_num)))
534 {
535 GtkWidget *tab;
536 int max_x, max_y, x_root, y_root;
537
538 tab = gtk_notebook_get_tab_label (nb, page);
539 g_return_val_if_fail (tab != NULL, -1);
540
541 if (!gtk_widget_get_mapped (GTK_WIDGET (tab)))
542 {
543 page_num++;
544 continue;
545 }
546
547 gdk_window_get_origin (gtk_widget_get_window (tab), &x_root, &y_root);
548
549 gtk_widget_get_allocation (tab, &tab_allocation);
550 max_x = x_root + tab_allocation.x + tab_allocation.width;
551 max_y = y_root + tab_allocation.y + tab_allocation.height;
552
553 if ((tab_pos == GTK_POS_TOP || tab_pos == GTK_POS_BOTTOM) && screen_x <= max_x)
554 return page_num;
555
556 if ((tab_pos == GTK_POS_LEFT || tab_pos == GTK_POS_RIGHT) && screen_y <= max_y)
557 return page_num;
558
559 page_num++;
560 }
561
562 return -1;
563 }
564
565 static void
terminal_set_profile_toggled_callback(GtkToggleAction * action,TerminalWindow * window)566 terminal_set_profile_toggled_callback (GtkToggleAction *action,
567 TerminalWindow *window)
568 {
569 TerminalWindowPrivate *priv = window->priv;
570 TerminalProfile *profile;
571
572 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
573 if (!gtk_toggle_action_get_active (action))
574 return;
575 G_GNUC_END_IGNORE_DEPRECATIONS;
576
577 if (priv->active_screen == NULL)
578 return;
579
580 profile = g_object_get_data (G_OBJECT (action), PROFILE_DATA_KEY);
581 g_assert (profile);
582
583 if (_terminal_profile_get_forgotten (profile))
584 return;
585
586 g_signal_handlers_block_by_func (priv->active_screen, G_CALLBACK (profile_set_callback), window);
587 terminal_screen_set_profile (priv->active_screen, profile);
588 g_signal_handlers_unblock_by_func (priv->active_screen, G_CALLBACK (profile_set_callback), window);
589 }
590
591 static void
profile_visible_name_notify_cb(TerminalProfile * profile,GParamSpec * pspec,GtkAction * action)592 profile_visible_name_notify_cb (TerminalProfile *profile,
593 GParamSpec *pspec,
594 GtkAction *action)
595 {
596 const char *visible_name;
597 char *dot, *display_name;
598 guint num;
599
600 visible_name = terminal_profile_get_property_string (profile, TERMINAL_PROFILE_VISIBLE_NAME);
601 display_name = escape_underscores (visible_name);
602
603 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
604 dot = strchr (gtk_action_get_name (action), '.');
605 G_GNUC_END_IGNORE_DEPRECATIONS;
606 if (dot != NULL)
607 {
608 char *free_me;
609
610 num = g_ascii_strtoll (dot + 1, NULL, 10);
611
612 free_me = display_name;
613 if (num < 10)
614 /* Translators: This is the label of a menu item to choose a profile.
615 * _%d is used as the accelerator (with d between 1 and 9), and
616 * the %s is the name of the terminal profile.
617 */
618 display_name = g_strdup_printf (_("_%d. %s"), num, display_name);
619 else if (num < 36)
620 /* Translators: This is the label of a menu item to choose a profile.
621 * _%c is used as the accelerator (it will be a character between A and Z),
622 * and the %s is the name of the terminal profile.
623 */
624 display_name = g_strdup_printf (_("_%c. %s"), ('A' + num - 10), display_name);
625 else
626 free_me = NULL;
627
628 g_free (free_me);
629 }
630
631 g_object_set (action, "label", display_name, NULL);
632 g_free (display_name);
633 }
634
635 static void
disconnect_profiles_from_actions_in_group(GtkActionGroup * action_group)636 disconnect_profiles_from_actions_in_group (GtkActionGroup *action_group)
637 {
638 GList *actions, *l;
639
640 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
641 actions = gtk_action_group_list_actions (action_group);
642 G_GNUC_END_IGNORE_DEPRECATIONS;
643 for (l = actions; l != NULL; l = l->next)
644 {
645 GObject *action = G_OBJECT (l->data);
646 TerminalProfile *profile;
647
648 profile = g_object_get_data (action, PROFILE_DATA_KEY);
649 if (!profile)
650 continue;
651
652 g_signal_handlers_disconnect_by_func (profile, G_CALLBACK (profile_visible_name_notify_cb), action);
653 }
654 g_list_free (actions);
655 }
656
657 static void
terminal_window_update_set_profile_menu_active_profile(TerminalWindow * window)658 terminal_window_update_set_profile_menu_active_profile (TerminalWindow *window)
659 {
660 TerminalWindowPrivate *priv = window->priv;
661 TerminalProfile *new_active_profile;
662 GList *actions, *l;
663
664 if (!priv->profiles_action_group)
665 return;
666
667 if (!priv->active_screen)
668 return;
669
670 new_active_profile = terminal_screen_get_profile (priv->active_screen);
671
672 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
673 actions = gtk_action_group_list_actions (priv->profiles_action_group);
674 G_GNUC_END_IGNORE_DEPRECATIONS;
675 for (l = actions; l != NULL; l = l->next)
676 {
677 GObject *action = G_OBJECT (l->data);
678 TerminalProfile *profile;
679
680 profile = g_object_get_data (action, PROFILE_DATA_KEY);
681 if (profile != new_active_profile)
682 continue;
683
684 g_signal_handlers_block_by_func (action, G_CALLBACK (terminal_set_profile_toggled_callback), window);
685 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
686 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
687 G_GNUC_END_IGNORE_DEPRECATIONS;
688 g_signal_handlers_unblock_by_func (action, G_CALLBACK (terminal_set_profile_toggled_callback), window);
689
690 break;
691 }
692 g_list_free (actions);
693 }
694
695 static void
terminal_window_update_set_profile_menu(TerminalWindow * window)696 terminal_window_update_set_profile_menu (TerminalWindow *window)
697 {
698 TerminalWindowPrivate *priv = window->priv;
699 TerminalProfile *active_profile;
700 GtkActionGroup *action_group;
701 GtkAction *action;
702 GList *profiles, *p;
703 GSList *group;
704 guint n;
705 gboolean single_profile;
706
707 /* Remove the old UI */
708 if (priv->profiles_ui_id != 0)
709 {
710 gtk_ui_manager_remove_ui (priv->ui_manager, priv->profiles_ui_id);
711 priv->profiles_ui_id = 0;
712 }
713
714 if (priv->profiles_action_group != NULL)
715 {
716 disconnect_profiles_from_actions_in_group (priv->profiles_action_group);
717 gtk_ui_manager_remove_action_group (priv->ui_manager,
718 priv->profiles_action_group);
719 priv->profiles_action_group = NULL;
720 }
721
722 profiles = terminal_app_get_profile_list (terminal_app_get ());
723
724 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
725 action = gtk_action_group_get_action (priv->action_group, "TerminalProfiles");
726 single_profile = !profiles || profiles->next == NULL; /* list length <= 1 */
727 gtk_action_set_sensitive (action, !single_profile);
728 G_GNUC_END_IGNORE_DEPRECATIONS;
729 if (profiles == NULL)
730 return;
731
732 if (priv->active_screen)
733 active_profile = terminal_screen_get_profile (priv->active_screen);
734 else
735 active_profile = NULL;
736
737 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
738 action_group = priv->profiles_action_group = gtk_action_group_new ("Profiles");
739 G_GNUC_END_IGNORE_DEPRECATIONS;
740 gtk_ui_manager_insert_action_group (priv->ui_manager, action_group, -1);
741 g_object_unref (action_group);
742
743 priv->profiles_ui_id = gtk_ui_manager_new_merge_id (priv->ui_manager);
744
745 group = NULL;
746 n = 0;
747 for (p = profiles; p != NULL; p = p->next)
748 {
749 TerminalProfile *profile = (TerminalProfile *) p->data;
750 GtkRadioAction *profile_action;
751 char name[32];
752
753 g_snprintf (name, sizeof (name), "TerminalSetProfile%u", n++);
754
755 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
756 profile_action = gtk_radio_action_new (name,
757 NULL,
758 NULL,
759 NULL,
760 n);
761
762 gtk_radio_action_set_group (profile_action, group);
763 group = gtk_radio_action_get_group (profile_action);
764
765 if (profile == active_profile)
766 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (profile_action), TRUE);
767 G_GNUC_END_IGNORE_DEPRECATIONS;
768
769 g_object_set_data_full (G_OBJECT (profile_action),
770 PROFILE_DATA_KEY,
771 g_object_ref (profile),
772 (GDestroyNotify) g_object_unref);
773 profile_visible_name_notify_cb (profile, NULL, GTK_ACTION (profile_action));
774 g_signal_connect (profile, "notify::" TERMINAL_PROFILE_VISIBLE_NAME,
775 G_CALLBACK (profile_visible_name_notify_cb), profile_action);
776 g_signal_connect (profile_action, "toggled",
777 G_CALLBACK (terminal_set_profile_toggled_callback), window);
778
779 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
780 gtk_action_group_add_action (action_group, GTK_ACTION (profile_action));
781 G_GNUC_END_IGNORE_DEPRECATIONS;
782 g_object_unref (profile_action);
783
784 gtk_ui_manager_add_ui (priv->ui_manager, priv->profiles_ui_id,
785 PROFILES_UI_PATH,
786 name, name,
787 GTK_UI_MANAGER_MENUITEM, FALSE);
788 gtk_ui_manager_add_ui (priv->ui_manager, priv->profiles_ui_id,
789 PROFILES_POPUP_UI_PATH,
790 name, name,
791 GTK_UI_MANAGER_MENUITEM, FALSE);
792 }
793
794 g_list_free (profiles);
795 }
796
797 static void
terminal_window_create_new_terminal_action(TerminalWindow * window,TerminalProfile * profile,const char * name,guint num,GCallback callback)798 terminal_window_create_new_terminal_action (TerminalWindow *window,
799 TerminalProfile *profile,
800 const char *name,
801 guint num,
802 GCallback callback)
803 {
804 TerminalWindowPrivate *priv = window->priv;
805 GtkAction *action;
806
807 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
808 action = gtk_action_new (name, NULL, NULL, NULL);
809 G_GNUC_END_IGNORE_DEPRECATIONS;
810
811 g_object_set_data_full (G_OBJECT (action),
812 PROFILE_DATA_KEY,
813 g_object_ref (profile),
814 (GDestroyNotify) g_object_unref);
815 profile_visible_name_notify_cb (profile, NULL, action);
816 g_signal_connect (profile, "notify::" TERMINAL_PROFILE_VISIBLE_NAME,
817 G_CALLBACK (profile_visible_name_notify_cb), action);
818 g_signal_connect (action, "activate", callback, window);
819
820 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
821 gtk_action_group_add_action (priv->new_terminal_action_group, action);
822 G_GNUC_END_IGNORE_DEPRECATIONS;
823 g_object_unref (action);
824 }
825
826 static void
terminal_window_update_new_terminal_menus(TerminalWindow * window)827 terminal_window_update_new_terminal_menus (TerminalWindow *window)
828 {
829 TerminalWindowPrivate *priv = window->priv;
830 GtkActionGroup *action_group;
831 GtkAction *action;
832 GList *profiles, *p;
833 guint n;
834 gboolean have_single_profile;
835
836 /* Remove the old UI */
837 if (priv->new_terminal_ui_id != 0)
838 {
839 gtk_ui_manager_remove_ui (priv->ui_manager, priv->new_terminal_ui_id);
840 priv->new_terminal_ui_id = 0;
841 }
842
843 if (priv->new_terminal_action_group != NULL)
844 {
845 disconnect_profiles_from_actions_in_group (priv->new_terminal_action_group);
846 gtk_ui_manager_remove_action_group (priv->ui_manager,
847 priv->new_terminal_action_group);
848 priv->new_terminal_action_group = NULL;
849 }
850
851 profiles = terminal_app_get_profile_list (terminal_app_get ());
852 have_single_profile = !profiles || !profiles->next;
853
854 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
855 action = gtk_action_group_get_action (priv->action_group, "FileNewTab");
856 gtk_action_set_visible (action, have_single_profile);
857 action = gtk_action_group_get_action (priv->action_group, "FileNewWindow");
858 gtk_action_set_visible (action, have_single_profile);
859 G_GNUC_END_IGNORE_DEPRECATIONS;
860
861 if (have_single_profile)
862 {
863 g_list_free (profiles);
864 return;
865 }
866
867 /* Now build the submenus */
868
869 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
870 action_group = priv->new_terminal_action_group = gtk_action_group_new ("NewTerminal");
871 G_GNUC_END_IGNORE_DEPRECATIONS;
872 gtk_ui_manager_insert_action_group (priv->ui_manager, action_group, -1);
873 g_object_unref (action_group);
874
875 priv->new_terminal_ui_id = gtk_ui_manager_new_merge_id (priv->ui_manager);
876
877 n = 0;
878 for (p = profiles; p != NULL; p = p->next)
879 {
880 TerminalProfile *profile = (TerminalProfile *) p->data;
881 char name[32];
882
883 g_snprintf (name, sizeof (name), "FileNewTab.%u", n);
884 terminal_window_create_new_terminal_action (window,
885 profile,
886 name,
887 n,
888 G_CALLBACK (file_new_tab_callback));
889
890 gtk_ui_manager_add_ui (priv->ui_manager, priv->new_terminal_ui_id,
891 FILE_NEW_TERMINAL_TAB_UI_PATH,
892 name, name,
893 GTK_UI_MANAGER_MENUITEM, FALSE);
894
895 g_snprintf (name, sizeof (name), "FileNewWindow.%u", n);
896 terminal_window_create_new_terminal_action (window,
897 profile,
898 name,
899 n,
900 G_CALLBACK (file_new_window_callback));
901
902 gtk_ui_manager_add_ui (priv->ui_manager, priv->new_terminal_ui_id,
903 FILE_NEW_TERMINAL_WINDOW_UI_PATH,
904 name, name,
905 GTK_UI_MANAGER_MENUITEM, FALSE);
906
907 ++n;
908 }
909
910 g_list_free (profiles);
911 }
912
913 static void
terminal_set_encoding_callback(GtkToggleAction * action,TerminalWindow * window)914 terminal_set_encoding_callback (GtkToggleAction *action,
915 TerminalWindow *window)
916 {
917 TerminalWindowPrivate *priv = window->priv;
918 TerminalEncoding *encoding;
919
920 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
921 if (!gtk_toggle_action_get_active (action))
922 return;
923 G_GNUC_END_IGNORE_DEPRECATIONS;
924
925 if (priv->active_screen == NULL)
926 return;
927
928 encoding = g_object_get_data (G_OBJECT (action), ENCODING_DATA_KEY);
929 g_assert (encoding);
930
931 vte_terminal_set_encoding (VTE_TERMINAL (priv->active_screen),
932 terminal_encoding_get_charset (encoding), NULL);
933 }
934
935 static void
terminal_window_update_encoding_menu(TerminalWindow * window)936 terminal_window_update_encoding_menu (TerminalWindow *window)
937 {
938 TerminalWindowPrivate *priv = window->priv;
939 TerminalApp *app;
940 GtkActionGroup *action_group;
941 GSList *group;
942 guint n;
943 GSList *encodings, *l;
944 const char *charset;
945 TerminalEncoding *active_encoding;
946
947 /* Remove the old UI */
948 if (priv->encodings_ui_id != 0)
949 {
950 gtk_ui_manager_remove_ui (priv->ui_manager, priv->encodings_ui_id);
951 priv->encodings_ui_id = 0;
952 }
953
954 if (priv->encodings_action_group != NULL)
955 {
956 gtk_ui_manager_remove_action_group (priv->ui_manager,
957 priv->encodings_action_group);
958 priv->encodings_action_group = NULL;
959 }
960
961 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
962 action_group = priv->encodings_action_group = gtk_action_group_new ("Encodings");
963 G_GNUC_END_IGNORE_DEPRECATIONS;
964 gtk_ui_manager_insert_action_group (priv->ui_manager, action_group, -1);
965 g_object_unref (action_group);
966
967 priv->encodings_ui_id = gtk_ui_manager_new_merge_id (priv->ui_manager);
968
969 if (priv->active_screen)
970 charset = vte_terminal_get_encoding (VTE_TERMINAL (priv->active_screen));
971 else
972 charset = "current";
973
974 app = terminal_app_get ();
975 active_encoding = terminal_app_ensure_encoding (app, charset);
976
977 encodings = terminal_app_get_active_encodings (app);
978
979 if (g_slist_find (encodings, active_encoding) == NULL)
980 encodings = g_slist_append (encodings, terminal_encoding_ref (active_encoding));
981
982 group = NULL;
983 n = 0;
984 for (l = encodings; l != NULL; l = l->next)
985 {
986 TerminalEncoding *e = (TerminalEncoding *) l->data;
987 GtkRadioAction *encoding_action;
988 char name[128];
989 char *display_name;
990
991 g_snprintf (name, sizeof (name), SET_ENCODING_ACTION_NAME_PREFIX "%s", terminal_encoding_get_id (e));
992 display_name = g_strdup_printf ("%s (%s)", e->name, terminal_encoding_get_charset (e));
993
994 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
995 encoding_action = gtk_radio_action_new (name,
996 display_name,
997 NULL,
998 NULL,
999 n);
1000 g_free (display_name);
1001
1002 gtk_radio_action_set_group (encoding_action, group);
1003 group = gtk_radio_action_get_group (encoding_action);
1004
1005 if (charset && strcmp (terminal_encoding_get_id (e), charset) == 0)
1006 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (encoding_action), TRUE);
1007 G_GNUC_END_IGNORE_DEPRECATIONS;
1008
1009 g_signal_connect (encoding_action, "toggled",
1010 G_CALLBACK (terminal_set_encoding_callback), window);
1011
1012 g_object_set_data_full (G_OBJECT (encoding_action), ENCODING_DATA_KEY,
1013 terminal_encoding_ref (e),
1014 (GDestroyNotify) terminal_encoding_unref);
1015
1016 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
1017 gtk_action_group_add_action (action_group, GTK_ACTION (encoding_action));
1018 G_GNUC_END_IGNORE_DEPRECATIONS;
1019 g_object_unref (encoding_action);
1020
1021 gtk_ui_manager_add_ui (priv->ui_manager, priv->encodings_ui_id,
1022 SET_ENCODING_UI_PATH,
1023 name, name,
1024 GTK_UI_MANAGER_MENUITEM, FALSE);
1025 }
1026
1027 g_slist_foreach (encodings, (GFunc) terminal_encoding_unref, NULL);
1028 g_slist_free (encodings);
1029 }
1030
1031 static void
terminal_window_update_encoding_menu_active_encoding(TerminalWindow * window)1032 terminal_window_update_encoding_menu_active_encoding (TerminalWindow *window)
1033 {
1034 TerminalWindowPrivate *priv = window->priv;
1035 GtkAction *action;
1036 char name[128];
1037
1038 if (!priv->active_screen)
1039 return;
1040 if (!priv->encodings_action_group)
1041 return;
1042
1043 g_snprintf (name, sizeof (name), SET_ENCODING_ACTION_NAME_PREFIX "%s",
1044 vte_terminal_get_encoding (VTE_TERMINAL (priv->active_screen)));
1045 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
1046 action = gtk_action_group_get_action (priv->encodings_action_group, name);
1047 G_GNUC_END_IGNORE_DEPRECATIONS;
1048 if (!action)
1049 return;
1050
1051 g_signal_handlers_block_by_func (action, G_CALLBACK (terminal_set_encoding_callback), window);
1052 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
1053 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
1054 G_GNUC_END_IGNORE_DEPRECATIONS;
1055 g_signal_handlers_unblock_by_func (action, G_CALLBACK (terminal_set_encoding_callback), window);
1056 }
1057
1058 static void
terminal_size_to_cb(GtkAction * action,TerminalWindow * window)1059 terminal_size_to_cb (GtkAction *action,
1060 TerminalWindow *window)
1061 {
1062 TerminalWindowPrivate *priv = window->priv;
1063 const char *name;
1064 char *end = NULL;
1065 guint width, height;
1066
1067 if (priv->active_screen == NULL)
1068 return;
1069
1070 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
1071 name = gtk_action_get_name (action) + strlen (SIZE_TO_ACTION_NAME_PREFIX);
1072 G_GNUC_END_IGNORE_DEPRECATIONS;
1073 width = g_ascii_strtoull (name, &end, 10);
1074 g_assert (end && *end == 'x');
1075 height = g_ascii_strtoull (end + 1, &end, 10);
1076 g_assert (end && *end == '\0');
1077
1078 vte_terminal_set_size (VTE_TERMINAL (priv->active_screen), width, height);
1079
1080 terminal_window_update_size (window, priv->active_screen, TRUE);
1081 }
1082
1083 static void
terminal_window_update_size_to_menu(TerminalWindow * window)1084 terminal_window_update_size_to_menu (TerminalWindow *window)
1085 {
1086 static const struct
1087 {
1088 guint grid_width;
1089 guint grid_height;
1090 } predefined_sizes[] =
1091 {
1092 { 80, 24 },
1093 { 80, 43 },
1094 { 132, 24 },
1095 { 132, 43 }
1096 };
1097 TerminalWindowPrivate *priv = window->priv;
1098 guint i;
1099
1100 /* We only install this once, so there's no need for a separate action group
1101 * and any cleanup + build-new-one action here.
1102 */
1103
1104 for (i = 0; i < G_N_ELEMENTS (predefined_sizes); ++i)
1105 {
1106 guint grid_width = predefined_sizes[i].grid_width;
1107 guint grid_height = predefined_sizes[i].grid_height;
1108 GtkAction *action;
1109 char name[40];
1110 char *display_name;
1111
1112 g_snprintf (name, sizeof (name), SIZE_TO_ACTION_NAME_PREFIX "%ux%u",
1113 grid_width, grid_height);
1114
1115 /* If there are ever more than 9 of these, extend this to use A..Z as mnemonics,
1116 * like we do for the profiles menu.
1117 */
1118 display_name = g_strdup_printf ("_%u. %ux%u", i + 1, grid_width, grid_height);
1119
1120 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
1121 action = gtk_action_new (name, display_name, NULL, NULL);
1122 G_GNUC_END_IGNORE_DEPRECATIONS;
1123 g_free (display_name);
1124
1125 g_signal_connect (action, "activate",
1126 G_CALLBACK (terminal_size_to_cb), window);
1127
1128 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
1129 gtk_action_group_add_action (priv->action_group, action);
1130 G_GNUC_END_IGNORE_DEPRECATIONS;
1131 g_object_unref (action);
1132
1133 gtk_ui_manager_add_ui (priv->ui_manager, priv->ui_id,
1134 SIZE_TO_UI_PATH,
1135 name, name,
1136 GTK_UI_MANAGER_MENUITEM, FALSE);
1137 }
1138 }
1139
1140 /* Actions stuff */
1141
1142 static void
terminal_window_update_copy_sensitivity(TerminalScreen * screen,TerminalWindow * window)1143 terminal_window_update_copy_sensitivity (TerminalScreen *screen,
1144 TerminalWindow *window)
1145 {
1146 TerminalWindowPrivate *priv = window->priv;
1147 GtkAction *action;
1148 gboolean can_copy;
1149
1150 if (screen != priv->active_screen)
1151 return;
1152
1153 can_copy = vte_terminal_get_has_selection (VTE_TERMINAL (screen));
1154
1155 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
1156 action = gtk_action_group_get_action (priv->action_group, "EditCopy");
1157 gtk_action_set_sensitive (action, can_copy);
1158 G_GNUC_END_IGNORE_DEPRECATIONS;
1159
1160 if (can_copy && priv->copy_selection)
1161 #if VTE_CHECK_VERSION (0, 50, 0)
1162 vte_terminal_copy_clipboard_format (VTE_TERMINAL(screen), VTE_FORMAT_TEXT);
1163 #else
1164 vte_terminal_copy_clipboard(VTE_TERMINAL(screen));
1165 #endif
1166 }
1167
1168 static void
terminal_window_update_zoom_sensitivity(TerminalWindow * window)1169 terminal_window_update_zoom_sensitivity (TerminalWindow *window)
1170 {
1171 TerminalWindowPrivate *priv = window->priv;
1172 TerminalScreen *screen;
1173 GtkAction *action;
1174 double current, zoom;
1175
1176 screen = priv->active_screen;
1177 if (screen == NULL)
1178 return;
1179
1180 current = terminal_screen_get_font_scale (screen);
1181
1182 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
1183 action = gtk_action_group_get_action (priv->action_group, "ViewZoomOut");
1184 gtk_action_set_sensitive (action, find_smaller_zoom_factor (current, &zoom));
1185 action = gtk_action_group_get_action (priv->action_group, "ViewZoomIn");
1186 gtk_action_set_sensitive (action, find_larger_zoom_factor (current, &zoom));
1187 G_GNUC_END_IGNORE_DEPRECATIONS;
1188 }
1189
1190 static void
terminal_window_update_search_sensitivity(TerminalScreen * screen,TerminalWindow * window)1191 terminal_window_update_search_sensitivity (TerminalScreen *screen,
1192 TerminalWindow *window)
1193 {
1194 TerminalWindowPrivate *priv = window->priv;
1195 GtkAction *action;
1196 gboolean can_search;
1197
1198 if (screen != priv->active_screen)
1199 return;
1200
1201 can_search = vte_terminal_search_get_regex (VTE_TERMINAL (screen)) != NULL;
1202
1203 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
1204 action = gtk_action_group_get_action (priv->action_group, "SearchFindNext");
1205 gtk_action_set_sensitive (action, can_search);
1206 action = gtk_action_group_get_action (priv->action_group, "SearchFindPrevious");
1207 gtk_action_set_sensitive (action, can_search);
1208 action = gtk_action_group_get_action (priv->action_group, "SearchClearHighlight");
1209 gtk_action_set_sensitive (action, can_search);
1210 G_GNUC_END_IGNORE_DEPRECATIONS;
1211 }
1212
1213 static void
update_edit_menu_cb(GtkClipboard * clipboard,GdkAtom * targets,int n_targets,TerminalWindow * window)1214 update_edit_menu_cb (GtkClipboard *clipboard,
1215 GdkAtom *targets,
1216 int n_targets,
1217 TerminalWindow *window)
1218 {
1219 TerminalWindowPrivate *priv = window->priv;
1220 GtkAction *action;
1221 gboolean can_paste, can_paste_uris;
1222
1223 can_paste = targets != NULL && gtk_targets_include_text (targets, n_targets);
1224 can_paste_uris = targets != NULL && gtk_targets_include_uri (targets, n_targets);
1225
1226 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
1227 action = gtk_action_group_get_action (priv->action_group, "EditPaste");
1228 gtk_action_set_sensitive (action, can_paste);
1229 action = gtk_action_group_get_action (priv->action_group, "EditPasteURIPaths");
1230 gtk_action_set_visible (action, can_paste_uris);
1231 gtk_action_set_sensitive (action, can_paste_uris);
1232 G_GNUC_END_IGNORE_DEPRECATIONS;
1233
1234 /* Ref was added in gtk_clipboard_request_targets below */
1235 g_object_unref (window);
1236 }
1237
1238 static void
update_edit_menu(TerminalWindow * window)1239 update_edit_menu(TerminalWindow *window)
1240 {
1241 GtkClipboard *clipboard;
1242
1243 clipboard = gtk_widget_get_clipboard (GTK_WIDGET (window), GDK_SELECTION_CLIPBOARD);
1244 gtk_clipboard_request_targets (clipboard,
1245 (GtkClipboardTargetsReceivedFunc) update_edit_menu_cb,
1246 g_object_ref (window));
1247 }
1248
1249 static void
screen_resize_window_cb(TerminalScreen * screen,guint width,guint height,TerminalWindow * window)1250 screen_resize_window_cb (TerminalScreen *screen,
1251 guint width,
1252 guint height,
1253 TerminalWindow* window)
1254 {
1255 TerminalWindowPrivate *priv = window->priv;
1256 VteTerminal *terminal = VTE_TERMINAL (screen);
1257 GtkWidget *widget = GTK_WIDGET (screen);
1258
1259 /* Don't do anything if we're maximised or fullscreened */
1260 // FIXME: realized && ... instead?
1261 if (!gtk_widget_get_realized (widget) ||
1262 (gdk_window_get_state (gtk_widget_get_window (widget)) & (GDK_WINDOW_STATE_MAXIMIZED | GDK_WINDOW_STATE_FULLSCREEN)) != 0)
1263 return;
1264
1265 vte_terminal_set_size (terminal, width, height);
1266
1267 if (screen != priv->active_screen)
1268 return;
1269
1270 terminal_window_update_size (window, screen, TRUE);
1271 }
1272
1273 static void
terminal_window_update_tabs_menu_sensitivity(TerminalWindow * window)1274 terminal_window_update_tabs_menu_sensitivity (TerminalWindow *window)
1275 {
1276 TerminalWindowPrivate *priv = window->priv;
1277 GtkNotebook *notebook = GTK_NOTEBOOK (priv->notebook);
1278 GtkActionGroup *action_group = priv->action_group;
1279 GtkAction *action;
1280 int num_pages, page_num;
1281 gboolean not_first, not_last;
1282
1283 if (priv->disposed)
1284 return;
1285
1286 num_pages = gtk_notebook_get_n_pages (notebook);
1287 page_num = gtk_notebook_get_current_page (notebook);
1288 not_first = page_num > 0;
1289 not_last = page_num + 1 < num_pages;
1290
1291 /* Hide the tabs menu in single-tab windows */
1292 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
1293 action = gtk_action_group_get_action (action_group, "Tabs");
1294 gtk_action_set_visible (action, num_pages > 1);
1295
1296 #if 1
1297 /* NOTE: We always make next/prev actions sensitive except in
1298 * single-tab windows, so the corresponding shortcut key escape code
1299 * isn't sent to the terminal. See bug #453193 and bug #138609.
1300 * This also makes tab cycling work, bug #92139.
1301 * FIXME: Find a better way to do this.
1302 */
1303 action = gtk_action_group_get_action (action_group, "TabsPrevious");
1304 gtk_action_set_sensitive (action, num_pages > 1);
1305 action = gtk_action_group_get_action (action_group, "TabsNext");
1306 gtk_action_set_sensitive (action, num_pages > 1);
1307 #else
1308 /* This would be correct, but see the comment above. */
1309 action = gtk_action_group_get_action (action_group, "TabsPrevious");
1310 gtk_action_set_sensitive (action, not_first);
1311 action = gtk_action_group_get_action (action_group, "TabsNext");
1312 gtk_action_set_sensitive (action, not_last);
1313 #endif
1314
1315 action = gtk_action_group_get_action (action_group, "TabsMoveLeft");
1316 gtk_action_set_sensitive (action, not_first);
1317 action = gtk_action_group_get_action (action_group, "TabsMoveRight");
1318 gtk_action_set_sensitive (action, not_last);
1319 action = gtk_action_group_get_action (action_group, "TabsDetach");
1320 gtk_action_set_sensitive (action, num_pages > 1);
1321 action = gtk_action_group_get_action (action_group, "FileCloseTab");
1322 gtk_action_set_sensitive (action, num_pages > 1);
1323 G_GNUC_END_IGNORE_DEPRECATIONS;
1324 }
1325
1326 static void
update_tab_visibility(TerminalWindow * window,int change)1327 update_tab_visibility (TerminalWindow *window,
1328 int change)
1329 {
1330 TerminalWindowPrivate *priv = window->priv;
1331 gboolean show_tabs;
1332 guint num;
1333
1334 num = gtk_notebook_get_n_pages (GTK_NOTEBOOK (priv->notebook));
1335
1336 show_tabs = (num + change) > 1;
1337 gtk_notebook_set_show_tabs (GTK_NOTEBOOK (priv->notebook), show_tabs);
1338 }
1339
1340 static GtkNotebook *
handle_tab_droped_on_desktop(GtkNotebook * source_notebook,GtkWidget * container,gint x,gint y,gpointer data)1341 handle_tab_droped_on_desktop (GtkNotebook *source_notebook,
1342 GtkWidget *container,
1343 gint x,
1344 gint y,
1345 gpointer data)
1346 {
1347 TerminalWindow *source_window;
1348 TerminalWindow *new_window;
1349 TerminalWindowPrivate *new_priv;
1350
1351 source_window = TERMINAL_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (source_notebook)));
1352 g_return_val_if_fail (TERMINAL_IS_WINDOW (source_window), NULL);
1353
1354 new_window = terminal_app_new_window (terminal_app_get (),
1355 gtk_widget_get_screen (GTK_WIDGET (source_window)));
1356 new_priv = new_window->priv;
1357 new_priv->present_on_insert = TRUE;
1358
1359 update_tab_visibility (source_window, -1);
1360 update_tab_visibility (new_window, +1);
1361
1362 return GTK_NOTEBOOK (new_priv->notebook);
1363 }
1364
1365 /* Terminal screen popup menu handling */
1366
1367 static void
popup_open_url_callback(GtkAction * action,TerminalWindow * window)1368 popup_open_url_callback (GtkAction *action,
1369 TerminalWindow *window)
1370 {
1371 TerminalWindowPrivate *priv = window->priv;
1372 TerminalScreenPopupInfo *info = priv->popup_info;
1373
1374 if (info == NULL)
1375 return;
1376
1377 terminal_util_open_url (GTK_WIDGET (window), info->string, info->flavour,
1378 gtk_get_current_event_time ());
1379 }
1380
1381 static void
popup_copy_url_callback(GtkAction * action,TerminalWindow * window)1382 popup_copy_url_callback (GtkAction *action,
1383 TerminalWindow *window)
1384 {
1385 TerminalWindowPrivate *priv = window->priv;
1386 TerminalScreenPopupInfo *info = priv->popup_info;
1387 GtkClipboard *clipboard;
1388
1389 if (info == NULL)
1390 return;
1391
1392 if (info->string == NULL)
1393 return;
1394
1395 clipboard = gtk_widget_get_clipboard (GTK_WIDGET (window), GDK_SELECTION_CLIPBOARD);
1396 gtk_clipboard_set_text (clipboard, info->string, -1);
1397 }
1398
1399 static void
popup_leave_fullscreen_callback(GtkAction * action,TerminalWindow * window)1400 popup_leave_fullscreen_callback (GtkAction *action,
1401 TerminalWindow *window)
1402 {
1403 gtk_window_unfullscreen (GTK_WINDOW (window));
1404 }
1405
1406 static void
remove_popup_info(TerminalWindow * window)1407 remove_popup_info (TerminalWindow *window)
1408 {
1409 TerminalWindowPrivate *priv = window->priv;
1410
1411 if (priv->remove_popup_info_idle != 0)
1412 {
1413 g_source_remove (priv->remove_popup_info_idle);
1414 priv->remove_popup_info_idle = 0;
1415 }
1416
1417 if (priv->popup_info != NULL)
1418 {
1419 terminal_screen_popup_info_unref (priv->popup_info);
1420 priv->popup_info = NULL;
1421 }
1422 }
1423
1424 static gboolean
idle_remove_popup_info(TerminalWindow * window)1425 idle_remove_popup_info (TerminalWindow *window)
1426 {
1427 TerminalWindowPrivate *priv = window->priv;
1428
1429 priv->remove_popup_info_idle = 0;
1430 remove_popup_info (window);
1431 return FALSE;
1432 }
1433
1434 static void
unset_popup_info(TerminalWindow * window)1435 unset_popup_info (TerminalWindow *window)
1436 {
1437 TerminalWindowPrivate *priv = window->priv;
1438
1439 /* Unref the event from idle since we still need it
1440 * from the action callbacks which will run before idle.
1441 */
1442 if (priv->remove_popup_info_idle == 0 &&
1443 priv->popup_info != NULL)
1444 {
1445 priv->remove_popup_info_idle =
1446 g_idle_add ((GSourceFunc) idle_remove_popup_info, window);
1447 }
1448 }
1449
1450 static void
popup_menu_deactivate_callback(GtkWidget * popup,TerminalWindow * window)1451 popup_menu_deactivate_callback (GtkWidget *popup,
1452 TerminalWindow *window)
1453 {
1454 TerminalWindowPrivate *priv = window->priv;
1455 GtkWidget *im_menu_item;
1456
1457 g_signal_handlers_disconnect_by_func
1458 (popup, G_CALLBACK (popup_menu_deactivate_callback), window);
1459
1460 im_menu_item = gtk_ui_manager_get_widget (priv->ui_manager,
1461 "/Popup/PopupInputMethods");
1462 gtk_menu_item_set_submenu (GTK_MENU_ITEM (im_menu_item), NULL);
1463
1464 unset_popup_info (window);
1465 }
1466
1467 static void
popup_clipboard_targets_received_cb(GtkClipboard * clipboard,GdkAtom * targets,int n_targets,TerminalScreenPopupInfo * info)1468 popup_clipboard_targets_received_cb (GtkClipboard *clipboard,
1469 GdkAtom *targets,
1470 int n_targets,
1471 TerminalScreenPopupInfo *info)
1472 {
1473 TerminalWindow *window = info->window;
1474 TerminalWindowPrivate *priv = window->priv;
1475 TerminalScreen *screen = info->screen;
1476 GtkWidget *popup_menu;
1477 GtkAction *action;
1478 gboolean can_paste, can_paste_uris, show_link, show_email_link, show_call_link, show_input_method_menu;
1479 int n_pages;
1480
1481 if (!gtk_widget_get_realized (GTK_WIDGET (screen)))
1482 {
1483 terminal_screen_popup_info_unref (info);
1484 return;
1485 }
1486
1487 /* Now we know that the screen is realized, we know that the window is still alive */
1488 remove_popup_info (window);
1489
1490 priv->popup_info = info; /* adopt the ref added when requesting the clipboard */
1491
1492 n_pages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (priv->notebook));
1493
1494 can_paste = targets != NULL && gtk_targets_include_text (targets, n_targets);
1495 can_paste_uris = targets != NULL && gtk_targets_include_uri (targets, n_targets);
1496 show_link = info->string != NULL && (info->flavour == FLAVOR_AS_IS || info->flavour == FLAVOR_DEFAULT_TO_HTTP);
1497 show_email_link = info->string != NULL && info->flavour == FLAVOR_EMAIL;
1498 show_call_link = info->string != NULL && info->flavour == FLAVOR_VOIP_CALL;
1499
1500 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
1501 action = gtk_action_group_get_action (priv->action_group, "PopupSendEmail");
1502 gtk_action_set_visible (action, show_email_link);
1503 action = gtk_action_group_get_action (priv->action_group, "PopupCopyEmailAddress");
1504 gtk_action_set_visible (action, show_email_link);
1505 action = gtk_action_group_get_action (priv->action_group, "PopupCall");
1506 gtk_action_set_visible (action, show_call_link);
1507 action = gtk_action_group_get_action (priv->action_group, "PopupCopyCallAddress");
1508 gtk_action_set_visible (action, show_call_link);
1509 action = gtk_action_group_get_action (priv->action_group, "PopupOpenLink");
1510 gtk_action_set_visible (action, show_link);
1511 action = gtk_action_group_get_action (priv->action_group, "PopupCopyLinkAddress");
1512 gtk_action_set_visible (action, show_link);
1513
1514 action = gtk_action_group_get_action (priv->action_group, "PopupCloseWindow");
1515 gtk_action_set_visible (action, n_pages <= 1);
1516 action = gtk_action_group_get_action (priv->action_group, "PopupCloseTab");
1517 gtk_action_set_visible (action, n_pages > 1);
1518
1519 action = gtk_action_group_get_action (priv->action_group, "PopupCopy");
1520 gtk_action_set_sensitive (action, vte_terminal_get_has_selection (VTE_TERMINAL (screen)));
1521 action = gtk_action_group_get_action (priv->action_group, "PopupPaste");
1522 gtk_action_set_sensitive (action, can_paste);
1523 action = gtk_action_group_get_action (priv->action_group, "PopupPasteURIPaths");
1524 gtk_action_set_visible (action, can_paste_uris);
1525 G_GNUC_END_IGNORE_DEPRECATIONS;
1526
1527 g_object_get (gtk_widget_get_settings (GTK_WIDGET (window)),
1528 "gtk-show-input-method-menu", &show_input_method_menu,
1529 NULL);
1530
1531 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
1532 action = gtk_action_group_get_action (priv->action_group, "PopupInputMethods");
1533 gtk_action_set_visible (action, show_input_method_menu);
1534 G_GNUC_END_IGNORE_DEPRECATIONS;
1535
1536 popup_menu = gtk_ui_manager_get_widget (priv->ui_manager, "/Popup");
1537 g_signal_connect (popup_menu, "deactivate",
1538 G_CALLBACK (popup_menu_deactivate_callback), window);
1539
1540 /* Pseudo activation of the popup menu's action */
1541 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
1542 action = gtk_action_group_get_action (priv->action_group, "Popup");
1543 gtk_action_activate (action);
1544 G_GNUC_END_IGNORE_DEPRECATIONS;
1545
1546 if (info->button == 0)
1547 gtk_menu_shell_select_first (GTK_MENU_SHELL (popup_menu), FALSE);
1548
1549 if (!gtk_menu_get_attach_widget (GTK_MENU (popup_menu)))
1550 gtk_menu_attach_to_widget (GTK_MENU (popup_menu),GTK_WIDGET (screen),NULL);
1551
1552 gtk_menu_popup (GTK_MENU (popup_menu),
1553 NULL, NULL,
1554 NULL, NULL,
1555 info->button,
1556 info->timestamp);
1557 }
1558
1559 static void
screen_show_popup_menu_callback(TerminalScreen * screen,TerminalScreenPopupInfo * info,TerminalWindow * window)1560 screen_show_popup_menu_callback (TerminalScreen *screen,
1561 TerminalScreenPopupInfo *info,
1562 TerminalWindow *window)
1563 {
1564 GtkClipboard *clipboard;
1565
1566 g_return_if_fail (info->window == window);
1567
1568 clipboard = gtk_widget_get_clipboard (GTK_WIDGET (window), GDK_SELECTION_CLIPBOARD);
1569 gtk_clipboard_request_targets (clipboard,
1570 (GtkClipboardTargetsReceivedFunc) popup_clipboard_targets_received_cb,
1571 terminal_screen_popup_info_ref (info));
1572 }
1573
1574 static gboolean
screen_match_clicked_cb(TerminalScreen * screen,const char * match,int flavour,guint state,TerminalWindow * window)1575 screen_match_clicked_cb (TerminalScreen *screen,
1576 const char *match,
1577 int flavour,
1578 guint state,
1579 TerminalWindow *window)
1580 {
1581 TerminalWindowPrivate *priv = window->priv;
1582
1583 if (screen != priv->active_screen)
1584 return FALSE;
1585
1586 switch (flavour)
1587 {
1588 #ifdef ENABLE_SKEY
1589 case FLAVOR_SKEY:
1590 terminal_skey_do_popup (GTK_WINDOW (window), screen, match);
1591 break;
1592 #endif
1593 default:
1594 gtk_widget_grab_focus (GTK_WIDGET (screen));
1595 terminal_util_open_url (GTK_WIDGET (window), match, flavour,
1596 gtk_get_current_event_time ());
1597 break;
1598 }
1599
1600 return TRUE;
1601 }
1602
1603 static void
screen_close_cb(TerminalScreen * screen,TerminalWindow * window)1604 screen_close_cb (TerminalScreen *screen,
1605 TerminalWindow *window)
1606 {
1607 terminal_window_remove_screen (window, screen);
1608 }
1609
1610 static gboolean
terminal_window_accel_activate_cb(GtkAccelGroup * accel_group,GObject * acceleratable,guint keyval,GdkModifierType modifier,TerminalWindow * window)1611 terminal_window_accel_activate_cb (GtkAccelGroup *accel_group,
1612 GObject *acceleratable,
1613 guint keyval,
1614 GdkModifierType modifier,
1615 TerminalWindow *window)
1616 {
1617 GtkAccelGroupEntry *entries;
1618 guint n_entries;
1619 gboolean retval = FALSE;
1620
1621 entries = gtk_accel_group_query (accel_group, keyval, modifier, &n_entries);
1622 if (n_entries > 0)
1623 {
1624 const char *accel_path;
1625
1626 accel_path = g_quark_to_string (entries[0].accel_path_quark);
1627
1628 if (g_str_has_prefix (accel_path, "<Actions>/Main/"))
1629 {
1630 const char *action_name;
1631
1632 /* We want to always consume these accelerators, even if the corresponding
1633 * action is insensitive, so the corresponding shortcut key escape code
1634 * isn't sent to the terminal. See bug #453193, bug #138609 and bug #559728.
1635 * This also makes tab cycling work, bug #92139. (NOT!)
1636 */
1637
1638 action_name = I_(accel_path + strlen ("<Actions>/Main/"));
1639
1640 #if 0
1641 if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (priv->notebook)) > 1 &&
1642 (action_name == I_("TabsPrevious") || action_name == I_("TabsNext")))
1643 retval = TRUE;
1644 else
1645 #endif
1646 if (action_name == I_("EditCopy") ||
1647 action_name == I_("PopupCopy") ||
1648 action_name == I_("EditPaste") ||
1649 action_name == I_("PopupPaste"))
1650 retval = TRUE;
1651 }
1652 }
1653
1654 return retval;
1655 }
1656
1657 /*****************************************/
1658
1659 #ifdef MATE_ENABLE_DEBUG
1660 static void
terminal_window_size_allocate_cb(GtkWidget * widget,GtkAllocation * allocation)1661 terminal_window_size_allocate_cb (GtkWidget *widget,
1662 GtkAllocation *allocation)
1663 {
1664 _terminal_debug_print (TERMINAL_DEBUG_GEOMETRY,
1665 "[window %p] size-alloc result %d : %d at (%d, %d)\n",
1666 widget,
1667 allocation->width, allocation->height,
1668 allocation->x, allocation->y);
1669 }
1670 #endif /* MATE_ENABLE_DEBUG */
1671
1672 static void
terminal_window_realize(GtkWidget * widget)1673 terminal_window_realize (GtkWidget *widget)
1674 {
1675 TerminalWindow *window = TERMINAL_WINDOW (widget);
1676 TerminalWindowPrivate *priv = window->priv;
1677 #if defined(GDK_WINDOWING_X11) || defined(GDK_WINDOWING_WAYLAND)
1678 GdkScreen *screen;
1679 GtkAllocation widget_allocation;
1680 GdkVisual *visual;
1681
1682 gtk_widget_get_allocation (widget, &widget_allocation);
1683 screen = gtk_widget_get_screen (GTK_WIDGET (window));
1684
1685 if (gdk_screen_is_composited (screen) &&
1686 (visual = gdk_screen_get_rgba_visual (screen)) != NULL)
1687 {
1688 /* Set RGBA visual if possible so VTE can use real transparency */
1689 gtk_widget_set_visual (GTK_WIDGET (widget), visual);
1690 priv->have_argb_visual = TRUE;
1691 }
1692 else
1693 {
1694 gtk_widget_set_visual (GTK_WIDGET (window), gdk_screen_get_system_visual (screen));
1695 priv->have_argb_visual = FALSE;
1696 }
1697 #endif
1698
1699 _terminal_debug_print (TERMINAL_DEBUG_GEOMETRY,
1700 "[window %p] realize, size %d : %d at (%d, %d)\n",
1701 widget,
1702 widget_allocation.width, widget_allocation.height,
1703 widget_allocation.x, widget_allocation.y);
1704
1705 GTK_WIDGET_CLASS (terminal_window_parent_class)->realize (widget);
1706
1707 /* Need to do this now since this requires the window to be realized */
1708 if (priv->active_screen != NULL)
1709 sync_screen_icon_title (priv->active_screen, NULL, window);
1710 }
1711
1712 static gboolean
terminal_window_map_event(GtkWidget * widget,GdkEventAny * event)1713 terminal_window_map_event (GtkWidget *widget,
1714 GdkEventAny *event)
1715 {
1716 TerminalWindow *window = TERMINAL_WINDOW (widget);
1717 TerminalWindowPrivate *priv = window->priv;
1718 gboolean (* map_event) (GtkWidget *, GdkEventAny *) =
1719 GTK_WIDGET_CLASS (terminal_window_parent_class)->map_event;
1720 GtkAllocation widget_allocation;
1721
1722 gtk_widget_get_allocation (widget, &widget_allocation);
1723 _terminal_debug_print (TERMINAL_DEBUG_GEOMETRY,
1724 "[window %p] map-event, size %d : %d at (%d, %d)\n",
1725 widget,
1726 widget_allocation.width, widget_allocation.height,
1727 widget_allocation.x, widget_allocation.y);
1728
1729 if (priv->clear_demands_attention)
1730 {
1731 #ifdef GDK_WINDOWING_X11
1732 terminal_util_x11_clear_demands_attention (gtk_widget_get_window (widget));
1733 #endif
1734
1735 priv->clear_demands_attention = FALSE;
1736 }
1737
1738 if (map_event)
1739 return map_event (widget, event);
1740
1741 return FALSE;
1742 }
1743
1744
1745 static gboolean
terminal_window_state_event(GtkWidget * widget,GdkEventWindowState * event)1746 terminal_window_state_event (GtkWidget *widget,
1747 GdkEventWindowState *event)
1748 {
1749 gboolean (* window_state_event) (GtkWidget *, GdkEventWindowState *event) =
1750 GTK_WIDGET_CLASS (terminal_window_parent_class)->window_state_event;
1751
1752 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN)
1753 {
1754 TerminalWindow *window = TERMINAL_WINDOW (widget);
1755 TerminalWindowPrivate *priv = window->priv;
1756 GtkAction *action;
1757 gboolean is_fullscreen;
1758
1759 is_fullscreen = (event->new_window_state & GDK_WINDOW_STATE_FULLSCREEN) != 0;
1760
1761 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
1762 action = gtk_action_group_get_action (priv->action_group, "ViewFullscreen");
1763 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), is_fullscreen);
1764
1765 action = gtk_action_group_get_action (priv->action_group, "PopupLeaveFullscreen");
1766 gtk_action_set_visible (action, is_fullscreen);
1767 G_GNUC_END_IGNORE_DEPRECATIONS;
1768 }
1769
1770 if (window_state_event)
1771 return window_state_event (widget, event);
1772
1773 return FALSE;
1774 }
1775
1776 #ifdef GDK_WINDOWING_X11
1777 static void
terminal_window_window_manager_changed_cb(GdkScreen * screen,TerminalWindow * window)1778 terminal_window_window_manager_changed_cb (GdkScreen *screen,
1779 TerminalWindow *window)
1780 {
1781 TerminalWindowPrivate *priv = window->priv;
1782 GtkAction *action;
1783 gboolean supports_fs;
1784
1785 supports_fs = gdk_x11_screen_supports_net_wm_hint (screen, gdk_atom_intern ("_NET_WM_STATE_FULLSCREEN", FALSE));
1786
1787 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
1788 action = gtk_action_group_get_action (priv->action_group, "ViewFullscreen");
1789 gtk_action_set_sensitive (action, supports_fs);
1790 G_GNUC_END_IGNORE_DEPRECATIONS;
1791 }
1792 #endif
1793
1794 static void
terminal_window_screen_update(TerminalWindow * window,GdkScreen * screen)1795 terminal_window_screen_update (TerminalWindow *window,
1796 GdkScreen *screen)
1797 {
1798 TerminalApp *app;
1799
1800 #ifdef GDK_WINDOWING_X11
1801 if (screen && GDK_IS_X11_SCREEN (screen))
1802 {
1803 terminal_window_window_manager_changed_cb (screen, window);
1804 g_signal_connect (screen, "window-manager-changed",
1805 G_CALLBACK (terminal_window_window_manager_changed_cb), window);
1806 }
1807 #endif
1808
1809 if (GPOINTER_TO_INT (g_object_get_data (G_OBJECT (screen), "GT::HasSettingsConnection")))
1810 return;
1811
1812 g_object_set_data_full (G_OBJECT (screen), "GT::HasSettingsConnection",
1813 GINT_TO_POINTER (TRUE),
1814 (GDestroyNotify) app_setting_notify_destroy_cb);
1815
1816 app = terminal_app_get ();
1817 app_setting_notify_cb (app, NULL, screen);
1818 g_signal_connect (app, "notify::" TERMINAL_APP_ENABLE_MNEMONICS,
1819 G_CALLBACK (app_setting_notify_cb), screen);
1820 g_signal_connect (app, "notify::" TERMINAL_APP_ENABLE_MENU_BAR_ACCEL,
1821 G_CALLBACK (app_setting_notify_cb), screen);
1822 }
1823
1824 static void
terminal_window_screen_changed(GtkWidget * widget,GdkScreen * previous_screen)1825 terminal_window_screen_changed (GtkWidget *widget,
1826 GdkScreen *previous_screen)
1827 {
1828 TerminalWindow *window = TERMINAL_WINDOW (widget);
1829 void (* screen_changed) (GtkWidget *, GdkScreen *) =
1830 GTK_WIDGET_CLASS (terminal_window_parent_class)->screen_changed;
1831 GdkScreen *screen;
1832
1833 if (screen_changed)
1834 screen_changed (widget, previous_screen);
1835
1836 screen = gtk_widget_get_screen (widget);
1837 if (previous_screen == screen)
1838 return;
1839
1840 #ifdef GDK_WINDOWING_X11
1841 if (previous_screen && GDK_IS_X11_SCREEN (previous_screen))
1842 {
1843 g_signal_handlers_disconnect_by_func (previous_screen,
1844 G_CALLBACK (terminal_window_window_manager_changed_cb),
1845 window);
1846 }
1847 #endif
1848
1849 if (!screen)
1850 return;
1851
1852 terminal_window_screen_update (window, screen);
1853 }
1854
1855 static void
terminal_window_profile_list_changed_cb(TerminalApp * app,TerminalWindow * window)1856 terminal_window_profile_list_changed_cb (TerminalApp *app,
1857 TerminalWindow *window)
1858 {
1859 terminal_window_update_set_profile_menu (window);
1860 terminal_window_update_new_terminal_menus (window);
1861 }
1862
1863 static void
terminal_window_encoding_list_changed_cb(TerminalApp * app,TerminalWindow * window)1864 terminal_window_encoding_list_changed_cb (TerminalApp *app,
1865 TerminalWindow *window)
1866 {
1867 terminal_window_update_encoding_menu (window);
1868 }
1869
1870 static void
terminal_window_init(TerminalWindow * window)1871 terminal_window_init (TerminalWindow *window)
1872 {
1873 const GtkActionEntry menu_entries[] =
1874 {
1875 /* Toplevel */
1876 { "File", NULL, N_("_File"), NULL, NULL, NULL },
1877 { "FileNewWindowProfiles", "utilities-terminal", N_("Open _Terminal"), NULL, NULL, NULL },
1878 { "FileNewTabProfiles", STOCK_NEW_TAB, N_("Open Ta_b"), NULL, NULL, NULL },
1879 { "Edit", NULL, N_("_Edit"), NULL, NULL, NULL },
1880 { "View", NULL, N_("_View"), NULL, NULL, NULL },
1881 { "Search", NULL, N_("_Search"), NULL, NULL, NULL },
1882 { "Terminal", NULL, N_("_Terminal"), NULL, NULL, NULL },
1883 { "Tabs", NULL, N_("Ta_bs"), NULL, NULL, NULL },
1884 { "Help", NULL, N_("_Help"), NULL, NULL, NULL },
1885 { "Popup", NULL, NULL, NULL, NULL, NULL },
1886 { "NotebookPopup", NULL, "", NULL, NULL, NULL },
1887
1888 /* File menu */
1889 {
1890 "FileNewWindow", "utilities-terminal", N_("Open _Terminal"), "<shift><control>N",
1891 NULL,
1892 G_CALLBACK (file_new_window_callback)
1893 },
1894 {
1895 "FileNewTab", STOCK_NEW_TAB, N_("Open Ta_b"), "<shift><control>T",
1896 NULL,
1897 G_CALLBACK (file_new_tab_callback)
1898 },
1899 {
1900 "FileNewProfile", "document-open", N_("New _Profile…"), "",
1901 NULL,
1902 G_CALLBACK (file_new_profile_callback)
1903 },
1904 {
1905 "FileSaveContents", "document-save", N_("_Save Contents"), "",
1906 NULL,
1907 G_CALLBACK (file_save_contents_callback)
1908 },
1909 {
1910 "FileCloseTab", "window-close", N_("C_lose Tab"), "<shift><control>W",
1911 NULL,
1912 G_CALLBACK (file_close_tab_callback)
1913 },
1914 {
1915 "FileCloseWindow", "window-close", N_("_Close Window"), "<shift><control>Q",
1916 NULL,
1917 G_CALLBACK (file_close_window_callback)
1918 },
1919
1920 /* Edit menu */
1921 {
1922 "EditCopy", "edit-copy", N_("_Copy"), "<shift><control>C",
1923 NULL,
1924 G_CALLBACK (edit_copy_callback)
1925 },
1926 {
1927 "EditPaste", "edit-paste", N_("_Paste"), "<shift><control>V",
1928 NULL,
1929 G_CALLBACK (edit_paste_callback)
1930 },
1931 {
1932 "EditPasteURIPaths", "edit-paste", N_("Paste _Filenames"), "",
1933 NULL,
1934 G_CALLBACK (edit_paste_callback)
1935 },
1936 {
1937 "EditSelectAll", "edit-select-all", N_("Select _All"), "<shift><control>A",
1938 NULL,
1939 G_CALLBACK (edit_select_all_callback)
1940 },
1941 {
1942 "EditProfiles", NULL, N_("P_rofiles…"), NULL,
1943 NULL,
1944 G_CALLBACK (edit_profiles_callback)
1945 },
1946 {
1947 "EditKeybindings", NULL, N_("_Keyboard Shortcuts…"), NULL,
1948 NULL,
1949 G_CALLBACK (edit_keybindings_callback)
1950 },
1951 {
1952 "EditCurrentProfile", NULL, N_("Pr_ofile Preferences"), NULL,
1953 NULL,
1954 G_CALLBACK (edit_current_profile_callback)
1955 },
1956
1957 /* View menu */
1958 {
1959 "ViewZoomIn", "zoom-in", N_("Zoom _In"), "<control>plus",
1960 NULL,
1961 G_CALLBACK (view_zoom_in_callback)
1962 },
1963 {
1964 "ViewZoomOut", "zoom-out", N_("Zoom _Out"), "<control>minus",
1965 NULL,
1966 G_CALLBACK (view_zoom_out_callback)
1967 },
1968 {
1969 "ViewZoom100", "zoom-original", N_("_Normal Size"), "<control>0",
1970 NULL,
1971 G_CALLBACK (view_zoom_normal_callback)
1972 },
1973
1974 /* Search menu */
1975 {
1976 "SearchFind", "edit-find", N_("_Find..."), "<shift><control>F",
1977 NULL,
1978 G_CALLBACK (search_find_callback)
1979 },
1980 {
1981 "SearchFindNext", NULL, N_("Find Ne_xt"), "<shift><control>H",
1982 NULL,
1983 G_CALLBACK (search_find_next_callback)
1984 },
1985 {
1986 "SearchFindPrevious", NULL, N_("Find Pre_vious"), "<shift><control>G",
1987 NULL,
1988 G_CALLBACK (search_find_prev_callback)
1989 },
1990 {
1991 "SearchClearHighlight", NULL, N_("_Clear Highlight"), "<shift><control>J",
1992 NULL,
1993 G_CALLBACK (search_clear_highlight_callback)
1994 },
1995 #if 0
1996 {
1997 "SearchGoToLine", "go-jump", N_("Go to _Line..."), "<shift><control>I",
1998 NULL,
1999 G_CALLBACK (search_goto_line_callback)
2000 },
2001 {
2002 "SearchIncrementalSearch", "edit-find", N_("_Incremental Search..."), "<shift><control>K",
2003 NULL,
2004 G_CALLBACK (search_incremental_search_callback)
2005 },
2006 #endif
2007
2008 /* Terminal menu */
2009 { "TerminalProfiles", NULL, N_("Change _Profile"), NULL, NULL, NULL },
2010 {
2011 "ProfilePrevious", NULL, N_("_Previous Profile"), "<alt>Page_Up",
2012 NULL,
2013 G_CALLBACK (terminal_next_or_previous_profile_cb)
2014 },
2015 {
2016 "ProfileNext", NULL, N_("_Next Profile"), "<alt>Page_Down",
2017 NULL,
2018 G_CALLBACK (terminal_next_or_previous_profile_cb)
2019 },
2020 {
2021 "TerminalSetTitle", NULL, N_("_Set Title…"), NULL,
2022 NULL,
2023 G_CALLBACK (terminal_set_title_callback)
2024 },
2025 { "TerminalSetEncoding", NULL, N_("Set _Character Encoding"), NULL, NULL, NULL },
2026 {
2027 "TerminalReset", NULL, N_("_Reset"), NULL,
2028 NULL,
2029 G_CALLBACK (terminal_reset_callback)
2030 },
2031 {
2032 "TerminalResetClear", NULL, N_("Reset and C_lear"), NULL,
2033 NULL,
2034 G_CALLBACK (terminal_reset_clear_callback)
2035 },
2036
2037 /* Terminal/Encodings menu */
2038 {
2039 "TerminalAddEncoding", NULL, N_("_Add or Remove…"), NULL,
2040 NULL,
2041 G_CALLBACK (terminal_add_encoding_callback)
2042 },
2043
2044 /* Tabs menu */
2045 {
2046 "TabsPrevious", NULL, N_("_Previous Tab"), "<control>Page_Up",
2047 NULL,
2048 G_CALLBACK (tabs_next_or_previous_tab_cb)
2049 },
2050 {
2051 "TabsNext", NULL, N_("_Next Tab"), "<control>Page_Down",
2052 NULL,
2053 G_CALLBACK (tabs_next_or_previous_tab_cb)
2054 },
2055 {
2056 "TabsMoveLeft", NULL, N_("Move Tab _Left"), "<shift><control>Page_Up",
2057 NULL,
2058 G_CALLBACK (tabs_move_left_callback)
2059 },
2060 {
2061 "TabsMoveRight", NULL, N_("Move Tab _Right"), "<shift><control>Page_Down",
2062 NULL,
2063 G_CALLBACK (tabs_move_right_callback)
2064 },
2065 {
2066 "TabsDetach", NULL, N_("_Detach tab"), NULL,
2067 NULL,
2068 G_CALLBACK (tabs_detach_tab_callback)
2069 },
2070
2071 /* Help menu */
2072 {
2073 "HelpContents", "help-browser", N_("_Contents"), "F1",
2074 NULL,
2075 G_CALLBACK (help_contents_callback)
2076 },
2077 {
2078 "HelpAbout", "help-about", N_("_About"), NULL,
2079 NULL,
2080 G_CALLBACK (help_about_callback)
2081 },
2082
2083 /* Popup menu */
2084 {
2085 "PopupSendEmail", NULL, N_("_Send Mail To…"), NULL,
2086 NULL,
2087 G_CALLBACK (popup_open_url_callback)
2088 },
2089 {
2090 "PopupCopyEmailAddress", NULL, N_("_Copy E-mail Address"), NULL,
2091 NULL,
2092 G_CALLBACK (popup_copy_url_callback)
2093 },
2094 {
2095 "PopupCall", NULL, N_("C_all To…"), NULL,
2096 NULL,
2097 G_CALLBACK (popup_open_url_callback)
2098 },
2099 {
2100 "PopupCopyCallAddress", NULL, N_("_Copy Call Address"), NULL,
2101 NULL,
2102 G_CALLBACK (popup_copy_url_callback)
2103 },
2104 {
2105 "PopupOpenLink", NULL, N_("_Open Link"), NULL,
2106 NULL,
2107 G_CALLBACK (popup_open_url_callback)
2108 },
2109 {
2110 "PopupCopyLinkAddress", NULL, N_("_Copy Link Address"), NULL,
2111 NULL,
2112 G_CALLBACK (popup_copy_url_callback)
2113 },
2114 { "PopupTerminalProfiles", NULL, N_("P_rofiles"), NULL, NULL, NULL },
2115 {
2116 "PopupCopy", "edit-copy", N_("_Copy"), "",
2117 NULL,
2118 G_CALLBACK (edit_copy_callback)
2119 },
2120 {
2121 "PopupPaste", "edit-paste", N_("_Paste"), "",
2122 NULL,
2123 G_CALLBACK (edit_paste_callback)
2124 },
2125 {
2126 "PopupPasteURIPaths", "edit-paste", N_("Paste _Filenames"), "",
2127 NULL,
2128 G_CALLBACK (edit_paste_callback)
2129 },
2130 {
2131 "PopupNewTerminal", "utilities-terminal", N_("Open _Terminal"), NULL,
2132 NULL,
2133 G_CALLBACK (file_new_window_callback)
2134 },
2135 {
2136 "PopupNewTab", "tab-new", N_("Open Ta_b"), NULL,
2137 NULL,
2138 G_CALLBACK (file_new_tab_callback)
2139 },
2140 {
2141 "PopupCloseWindow", "window-close", N_("C_lose Window"), NULL,
2142 NULL,
2143 G_CALLBACK (file_close_window_callback)
2144 },
2145 {
2146 "PopupCloseTab", "window-close", N_("C_lose Tab"), NULL,
2147 NULL,
2148 G_CALLBACK (file_close_tab_callback)
2149 },
2150 {
2151 "PopupLeaveFullscreen", NULL, N_("L_eave Full Screen"), NULL,
2152 NULL,
2153 G_CALLBACK (popup_leave_fullscreen_callback)
2154 },
2155 { "PopupInputMethods", NULL, N_("_Input Methods"), NULL, NULL, NULL }
2156 };
2157
2158 const GtkToggleActionEntry toggle_menu_entries[] =
2159 {
2160 /* View Menu */
2161 {
2162 "ViewMenubar", NULL, N_("Show _Menubar"), NULL,
2163 NULL,
2164 G_CALLBACK (view_menubar_toggled_callback),
2165 FALSE
2166 },
2167 {
2168 "ViewFullscreen", NULL, N_("_Full Screen"), NULL,
2169 NULL,
2170 G_CALLBACK (view_fullscreen_toggled_callback),
2171 FALSE
2172 }
2173 };
2174 TerminalWindowPrivate *priv;
2175 TerminalApp *app;
2176 GtkActionGroup *action_group;
2177 GtkAction *action;
2178 GtkUIManager *manager;
2179 GError *error;
2180 GtkWindowGroup *window_group;
2181 GtkAccelGroup *accel_group;
2182 GtkClipboard *clipboard;
2183
2184 priv = window->priv = terminal_window_get_instance_private (window);
2185
2186 g_signal_connect (G_OBJECT (window), "delete_event",
2187 G_CALLBACK(terminal_window_delete_event),
2188 NULL);
2189 g_signal_connect (G_OBJECT (window), "focus_in_event",
2190 G_CALLBACK(terminal_window_focus_in_event),
2191 NULL);
2192
2193 #ifdef MATE_ENABLE_DEBUG
2194 _TERMINAL_DEBUG_IF (TERMINAL_DEBUG_GEOMETRY)
2195 {
2196 g_signal_connect_after (window, "size-allocate", G_CALLBACK (terminal_window_size_allocate_cb), NULL);
2197 }
2198 #endif
2199
2200 GtkStyleContext *context;
2201
2202 context = gtk_widget_get_style_context (GTK_WIDGET (window));
2203 gtk_style_context_add_class (context, "mate-terminal");
2204
2205 gtk_window_set_title (GTK_WINDOW (window), _("Terminal"));
2206
2207 priv->active_screen = NULL;
2208 priv->menubar_visible = FALSE;
2209
2210 priv->main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
2211 gtk_container_add (GTK_CONTAINER (window), priv->main_vbox);
2212 gtk_widget_show (priv->main_vbox);
2213
2214 priv->notebook = gtk_notebook_new ();
2215 gtk_notebook_set_scrollable (GTK_NOTEBOOK (priv->notebook), TRUE);
2216 gtk_notebook_set_show_border (GTK_NOTEBOOK (priv->notebook), FALSE);
2217 gtk_notebook_set_show_tabs (GTK_NOTEBOOK (priv->notebook), FALSE);
2218 gtk_notebook_set_group_name (GTK_NOTEBOOK (priv->notebook), I_("mate-terminal-window"));
2219 g_signal_connect (priv->notebook, "button-press-event",
2220 G_CALLBACK (notebook_button_press_cb), settings_global);
2221 g_signal_connect (window, "key-press-event",
2222 G_CALLBACK (window_key_press_cb), settings_global);
2223 g_signal_connect (priv->notebook, "popup-menu",
2224 G_CALLBACK (notebook_popup_menu_cb), window);
2225 g_signal_connect_after (priv->notebook, "switch-page",
2226 G_CALLBACK (notebook_page_selected_callback), window);
2227 g_signal_connect_after (priv->notebook, "page-added",
2228 G_CALLBACK (notebook_page_added_callback), window);
2229 g_signal_connect_after (priv->notebook, "page-removed",
2230 G_CALLBACK (notebook_page_removed_callback), window);
2231 g_signal_connect_data (priv->notebook, "page-reordered",
2232 G_CALLBACK (terminal_window_update_tabs_menu_sensitivity),
2233 window, NULL, G_CONNECT_SWAPPED | G_CONNECT_AFTER);
2234
2235 gtk_widget_add_events (priv->notebook, GDK_SCROLL_MASK);
2236 g_signal_connect (priv->notebook, "scroll-event",
2237 G_CALLBACK (notebook_scroll_event_cb), window);
2238
2239 g_signal_connect (priv->notebook, "create-window",
2240 G_CALLBACK (handle_tab_droped_on_desktop), window);
2241
2242 gtk_box_pack_end (GTK_BOX (priv->main_vbox), priv->notebook, TRUE, TRUE, 0);
2243 gtk_widget_show (priv->notebook);
2244
2245 priv->old_char_width = -1;
2246 priv->old_char_height = -1;
2247
2248 priv->old_chrome_width = -1;
2249 priv->old_chrome_height = -1;
2250 priv->old_padding_width = -1;
2251 priv->old_padding_height = -1;
2252
2253 priv->old_geometry_widget = NULL;
2254
2255 /* Create the UI manager */
2256 manager = priv->ui_manager = gtk_ui_manager_new ();
2257
2258 accel_group = gtk_ui_manager_get_accel_group (manager);
2259 gtk_window_add_accel_group (GTK_WINDOW (window), accel_group);
2260 /* Workaround for bug #453193, bug #138609 and bug #559728 */
2261 g_signal_connect_after (accel_group, "accel-activate",
2262 G_CALLBACK (terminal_window_accel_activate_cb), window);
2263
2264 /* Create the actions */
2265 /* Note that this action group name is used in terminal-accels.c; do not change it */
2266 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
2267 priv->action_group = action_group = gtk_action_group_new ("Main");
2268 gtk_action_group_set_translation_domain (action_group, NULL);
2269 gtk_action_group_add_actions (action_group, menu_entries,
2270 G_N_ELEMENTS (menu_entries), window);
2271 gtk_action_group_add_toggle_actions (action_group,
2272 toggle_menu_entries,
2273 G_N_ELEMENTS (toggle_menu_entries),
2274 window);
2275 G_GNUC_END_IGNORE_DEPRECATIONS;
2276 gtk_ui_manager_insert_action_group (manager, action_group, 0);
2277 g_object_unref (action_group);
2278
2279 clipboard = gtk_widget_get_clipboard (GTK_WIDGET (window), GDK_SELECTION_CLIPBOARD);
2280 g_signal_connect_swapped (clipboard, "owner-change",
2281 G_CALLBACK (update_edit_menu), window);
2282 update_edit_menu (window);
2283 /* Idem for this action, since the window is not fullscreen. */
2284 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
2285 action = gtk_action_group_get_action (priv->action_group, "PopupLeaveFullscreen");
2286 gtk_action_set_visible (action, FALSE);
2287
2288 #ifndef ENABLE_SAVE
2289 action = gtk_action_group_get_action (priv->action_group, "FileSaveContents");
2290 gtk_action_set_visible (action, FALSE);
2291 #endif
2292 G_GNUC_END_IGNORE_DEPRECATIONS;
2293
2294 /* Load the UI */
2295 error = NULL;
2296 priv->ui_id = gtk_ui_manager_add_ui_from_resource (manager,
2297 TERMINAL_RESOURCES_PATH_PREFIX G_DIR_SEPARATOR_S "ui/terminal.xml",
2298 &error);
2299 g_assert_no_error (error);
2300
2301 priv->menubar = gtk_ui_manager_get_widget (manager, "/menubar");
2302 gtk_box_pack_start (GTK_BOX (priv->main_vbox),
2303 priv->menubar,
2304 FALSE, FALSE, 0);
2305
2306 /* Add tabs menu */
2307 priv->tabs_menu = terminal_tabs_menu_new (window);
2308
2309 app = terminal_app_get ();
2310 terminal_window_profile_list_changed_cb (app, window);
2311 g_signal_connect (app, "profile-list-changed",
2312 G_CALLBACK (terminal_window_profile_list_changed_cb), window);
2313
2314 terminal_window_encoding_list_changed_cb (app, window);
2315 g_signal_connect (app, "encoding-list-changed",
2316 G_CALLBACK (terminal_window_encoding_list_changed_cb), window);
2317
2318 terminal_window_set_menubar_visible (window, TRUE);
2319 priv->use_default_menubar_visibility = TRUE;
2320
2321 terminal_window_update_size_to_menu (window);
2322
2323 /* We have to explicitly call this, since screen-changed is NOT
2324 * emitted for the toplevel the first time!
2325 */
2326 terminal_window_screen_update (window, gtk_widget_get_screen (GTK_WIDGET (window)));
2327
2328 window_group = gtk_window_group_new ();
2329 gtk_window_group_add_window (window_group, GTK_WINDOW (window));
2330 g_object_unref (window_group);
2331
2332 terminal_util_set_unique_role (GTK_WINDOW (window), "mate-terminal-window");
2333 }
2334
2335 static void
terminal_window_class_init(TerminalWindowClass * klass)2336 terminal_window_class_init (TerminalWindowClass *klass)
2337 {
2338 GObjectClass *object_class = G_OBJECT_CLASS (klass);
2339 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
2340
2341 object_class->dispose = terminal_window_dispose;
2342 object_class->finalize = terminal_window_finalize;
2343
2344 widget_class->show = terminal_window_show;
2345 widget_class->realize = terminal_window_realize;
2346 widget_class->map_event = terminal_window_map_event;
2347 widget_class->window_state_event = terminal_window_state_event;
2348 widget_class->screen_changed = terminal_window_screen_changed;
2349 }
2350
2351 static void
terminal_window_dispose(GObject * object)2352 terminal_window_dispose (GObject *object)
2353 {
2354 TerminalWindow *window = TERMINAL_WINDOW (object);
2355 TerminalWindowPrivate *priv = window->priv;
2356 TerminalApp *app;
2357 GdkScreen *screen;
2358 GtkClipboard *clipboard;
2359
2360 remove_popup_info (window);
2361
2362 priv->disposed = TRUE;
2363
2364 if (priv->tabs_menu)
2365 {
2366 g_object_unref (priv->tabs_menu);
2367 priv->tabs_menu = NULL;
2368 }
2369
2370 if (priv->profiles_action_group != NULL)
2371 disconnect_profiles_from_actions_in_group (priv->profiles_action_group);
2372 if (priv->new_terminal_action_group != NULL)
2373 disconnect_profiles_from_actions_in_group (priv->new_terminal_action_group);
2374
2375 app = terminal_app_get ();
2376 g_signal_handlers_disconnect_by_func (app,
2377 G_CALLBACK (terminal_window_profile_list_changed_cb),
2378 window);
2379 g_signal_handlers_disconnect_by_func (app,
2380 G_CALLBACK (terminal_window_encoding_list_changed_cb),
2381 window);
2382 clipboard = gtk_widget_get_clipboard (GTK_WIDGET (window), GDK_SELECTION_CLIPBOARD);
2383 g_signal_handlers_disconnect_by_func (clipboard,
2384 G_CALLBACK (update_edit_menu),
2385 window);
2386
2387 #ifdef GDK_WINDOWING_X11
2388 screen = gtk_widget_get_screen (GTK_WIDGET (object));
2389 if (screen && GDK_IS_X11_SCREEN (screen))
2390 {
2391 g_signal_handlers_disconnect_by_func (screen,
2392 G_CALLBACK (terminal_window_window_manager_changed_cb),
2393 window);
2394 }
2395 #endif
2396
2397 G_OBJECT_CLASS (terminal_window_parent_class)->dispose (object);
2398 }
2399
2400 static void
terminal_window_finalize(GObject * object)2401 terminal_window_finalize (GObject *object)
2402 {
2403 TerminalWindow *window = TERMINAL_WINDOW (object);
2404 TerminalWindowPrivate *priv = window->priv;
2405
2406 g_object_unref (priv->ui_manager);
2407
2408 if (priv->confirm_close_dialog)
2409 gtk_dialog_response (GTK_DIALOG (priv->confirm_close_dialog),
2410 GTK_RESPONSE_DELETE_EVENT);
2411
2412 if (priv->search_find_dialog)
2413 gtk_dialog_response (GTK_DIALOG (priv->search_find_dialog),
2414 GTK_RESPONSE_DELETE_EVENT);
2415
2416 G_OBJECT_CLASS (terminal_window_parent_class)->finalize (object);
2417 }
2418
2419 static gboolean
terminal_window_delete_event(GtkWidget * widget,GdkEvent * event,gpointer data)2420 terminal_window_delete_event (GtkWidget *widget,
2421 GdkEvent *event,
2422 gpointer data)
2423 {
2424 return confirm_close_window_or_tab (TERMINAL_WINDOW (widget), NULL);
2425 }
2426
2427 static gboolean
terminal_window_focus_in_event(GtkWidget * widget,GdkEventFocus * event,gpointer data)2428 terminal_window_focus_in_event (GtkWidget *widget,
2429 GdkEventFocus *event,
2430 gpointer data)
2431 {
2432 TerminalWindow *window = TERMINAL_WINDOW (widget);
2433 TerminalWindowPrivate *priv = window->priv;
2434
2435 if (event->in)
2436 priv->focus_time = time(NULL);
2437
2438 return FALSE;
2439 }
2440
2441 static void
terminal_window_show(GtkWidget * widget)2442 terminal_window_show (GtkWidget *widget)
2443 {
2444 TerminalWindow *window = TERMINAL_WINDOW (widget);
2445 GtkAllocation widget_allocation;
2446
2447 gtk_widget_get_allocation (widget, &widget_allocation);
2448
2449 TerminalWindowPrivate *priv = window->priv;
2450
2451 if (priv->active_screen != NULL)
2452 {
2453 terminal_window_update_copy_selection (priv->active_screen, window);
2454 #if 0
2455 /* At this point, we have our GdkScreen, and hence the right
2456 * font size, so we can go ahead and size the window. */
2457 terminal_window_update_size (window, priv->active_screen, FALSE);
2458 #endif
2459 }
2460
2461 terminal_window_update_geometry (window);
2462
2463 _terminal_debug_print (TERMINAL_DEBUG_GEOMETRY,
2464 "[window %p] show, size %d : %d at (%d, %d)\n",
2465 widget,
2466 widget_allocation.width, widget_allocation.height,
2467 widget_allocation.x, widget_allocation.y);
2468
2469 GTK_WIDGET_CLASS (terminal_window_parent_class)->show (widget);
2470 }
2471
2472 TerminalWindow*
terminal_window_new(void)2473 terminal_window_new (void)
2474 {
2475 return g_object_new (TERMINAL_TYPE_WINDOW, NULL);
2476 }
2477
2478 /**
2479 * terminal_window_set_is_restored:
2480 * @window:
2481 *
2482 * Marks the window as restored from session.
2483 */
2484 void
terminal_window_set_is_restored(TerminalWindow * window)2485 terminal_window_set_is_restored (TerminalWindow *window)
2486 {
2487 g_return_if_fail (TERMINAL_IS_WINDOW (window));
2488 g_return_if_fail (!gtk_widget_get_mapped (GTK_WIDGET (window)));
2489
2490 window->priv->clear_demands_attention = TRUE;
2491 }
2492
2493 static void
profile_set_callback(TerminalScreen * screen,TerminalProfile * old_profile,TerminalWindow * window)2494 profile_set_callback (TerminalScreen *screen,
2495 TerminalProfile *old_profile,
2496 TerminalWindow *window)
2497 {
2498 TerminalWindowPrivate *priv = window->priv;
2499
2500 if (!gtk_widget_get_realized (GTK_WIDGET (window)))
2501 return;
2502
2503 if (screen != priv->active_screen)
2504 return;
2505
2506 terminal_window_update_set_profile_menu_active_profile (window);
2507 }
2508
2509 static void
sync_screen_title(TerminalScreen * screen,GParamSpec * psepc,TerminalWindow * window)2510 sync_screen_title (TerminalScreen *screen,
2511 GParamSpec *psepc,
2512 TerminalWindow *window)
2513 {
2514 TerminalWindowPrivate *priv = window->priv;
2515
2516 if (screen != priv->active_screen)
2517 return;
2518
2519 gtk_window_set_title (GTK_WINDOW (window), terminal_screen_get_title (screen));
2520 }
2521
2522 static void
sync_screen_icon_title(TerminalScreen * screen,GParamSpec * psepc,TerminalWindow * window)2523 sync_screen_icon_title (TerminalScreen *screen,
2524 GParamSpec *psepc,
2525 TerminalWindow *window)
2526 {
2527 TerminalWindowPrivate *priv = window->priv;
2528
2529 if (!gtk_widget_get_realized (GTK_WIDGET (window)))
2530 return;
2531
2532 if (screen != priv->active_screen)
2533 return;
2534
2535 if (!terminal_screen_get_icon_title_set (screen))
2536 return;
2537
2538 gdk_window_set_icon_name (gtk_widget_get_window (GTK_WIDGET (window)), terminal_screen_get_icon_title (screen));
2539
2540 priv->icon_title_set = TRUE;
2541 }
2542
2543 static void
sync_screen_icon_title_set(TerminalScreen * screen,GParamSpec * psepc,TerminalWindow * window)2544 sync_screen_icon_title_set (TerminalScreen *screen,
2545 GParamSpec *psepc,
2546 TerminalWindow *window)
2547 {
2548 TerminalWindowPrivate *priv = window->priv;
2549
2550 if (!gtk_widget_get_realized (GTK_WIDGET (window)))
2551 return;
2552
2553 /* No need to restore the title if we never set an icon title */
2554 if (!priv->icon_title_set)
2555 return;
2556
2557 if (screen != priv->active_screen)
2558 return;
2559
2560 if (terminal_screen_get_icon_title_set (screen))
2561 return;
2562
2563 /* Need to reset the icon name */
2564 /* FIXME: Once gtk+ bug 535557 is fixed, use that to unset the icon title. */
2565
2566 g_object_set_qdata (G_OBJECT (gtk_widget_get_window (GTK_WIDGET (window))),
2567 g_quark_from_static_string ("gdk-icon-name-set"),
2568 GUINT_TO_POINTER (FALSE));
2569 priv->icon_title_set = FALSE;
2570
2571 /* Re-setting the right title will be done by the notify::title handler which comes after this one */
2572 }
2573
2574 /* Notebook callbacks */
2575
2576 static void
close_button_clicked_cb(GtkWidget * tab_label,GtkWidget * screen_container)2577 close_button_clicked_cb (GtkWidget *tab_label,
2578 GtkWidget *screen_container)
2579 {
2580 GtkWidget *toplevel;
2581 TerminalWindow *window;
2582 TerminalScreen *screen;
2583
2584 toplevel = gtk_widget_get_toplevel (screen_container);
2585 if (!gtk_widget_is_toplevel (toplevel))
2586 return;
2587
2588 if (!TERMINAL_IS_WINDOW (toplevel))
2589 return;
2590
2591 window = TERMINAL_WINDOW (toplevel);
2592
2593 screen = terminal_screen_container_get_screen (TERMINAL_SCREEN_CONTAINER (screen_container));
2594 if (confirm_close_window_or_tab (window, screen))
2595 return;
2596
2597 terminal_window_remove_screen (window, screen);
2598 }
2599
2600 void
terminal_window_add_screen(TerminalWindow * window,TerminalScreen * screen,int position)2601 terminal_window_add_screen (TerminalWindow *window,
2602 TerminalScreen *screen,
2603 int position)
2604 {
2605 TerminalWindowPrivate *priv = window->priv;
2606 GtkWidget *old_window;
2607 GtkWidget *screen_container, *tab_label;
2608
2609 old_window = gtk_widget_get_toplevel (GTK_WIDGET (screen));
2610 if (gtk_widget_is_toplevel (old_window) &&
2611 TERMINAL_IS_WINDOW (old_window) &&
2612 TERMINAL_WINDOW (old_window)== window)
2613 return;
2614
2615 if (TERMINAL_IS_WINDOW (old_window))
2616 terminal_window_remove_screen (TERMINAL_WINDOW (old_window), screen);
2617
2618 screen_container = terminal_screen_container_new (screen);
2619 gtk_widget_show (screen_container);
2620
2621 update_tab_visibility (window, +1);
2622
2623 tab_label = terminal_tab_label_new (screen);
2624 g_signal_connect (tab_label, "close-button-clicked",
2625 G_CALLBACK (close_button_clicked_cb), screen_container);
2626
2627 gtk_notebook_insert_page (GTK_NOTEBOOK (priv->notebook),
2628 screen_container,
2629 tab_label,
2630 position);
2631 gtk_container_child_set (GTK_CONTAINER (priv->notebook),
2632 screen_container,
2633 "tab-expand", TRUE,
2634 "tab-fill", TRUE,
2635 NULL);
2636 gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (priv->notebook),
2637 screen_container,
2638 TRUE);
2639 gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (priv->notebook),
2640 screen_container,
2641 TRUE);
2642 }
2643
2644 void
terminal_window_remove_screen(TerminalWindow * window,TerminalScreen * screen)2645 terminal_window_remove_screen (TerminalWindow *window,
2646 TerminalScreen *screen)
2647 {
2648 TerminalWindowPrivate *priv = window->priv;
2649 TerminalScreenContainer *screen_container;
2650
2651 g_return_if_fail (gtk_widget_get_toplevel (GTK_WIDGET (screen)) == GTK_WIDGET (window));
2652
2653 update_tab_visibility (window, -1);
2654
2655 screen_container = terminal_screen_container_get_from_screen (screen);
2656 if (detach_tab)
2657 {
2658 gtk_notebook_detach_tab (GTK_NOTEBOOK (priv->notebook),
2659 GTK_WIDGET (screen_container));
2660 detach_tab = FALSE;
2661 }
2662 else
2663 gtk_container_remove (GTK_CONTAINER (priv->notebook),
2664 GTK_WIDGET (screen_container));
2665 }
2666
2667 void
terminal_window_move_screen(TerminalWindow * source_window,TerminalWindow * dest_window,TerminalScreen * screen,int dest_position)2668 terminal_window_move_screen (TerminalWindow *source_window,
2669 TerminalWindow *dest_window,
2670 TerminalScreen *screen,
2671 int dest_position)
2672 {
2673 TerminalScreenContainer *screen_container;
2674
2675 g_return_if_fail (TERMINAL_IS_WINDOW (source_window));
2676 g_return_if_fail (TERMINAL_IS_WINDOW (dest_window));
2677 g_return_if_fail (TERMINAL_IS_SCREEN (screen));
2678 g_return_if_fail (gtk_widget_get_toplevel (GTK_WIDGET (screen)) == GTK_WIDGET (source_window));
2679 g_return_if_fail (dest_position >= -1);
2680
2681 screen_container = terminal_screen_container_get_from_screen (screen);
2682 g_assert (TERMINAL_IS_SCREEN_CONTAINER (screen_container));
2683
2684 /* We have to ref the screen container as well as the screen,
2685 * because otherwise removing the screen container from the source
2686 * window's notebook will cause the container and its containing
2687 * screen to be gtk_widget_destroy()ed!
2688 */
2689 g_object_ref_sink (screen_container);
2690 g_object_ref_sink (screen);
2691
2692 detach_tab = TRUE;
2693
2694 terminal_window_remove_screen (source_window, screen);
2695
2696 /* Now we can safely remove the screen from the container and let the container die */
2697 gtk_container_remove (GTK_CONTAINER (gtk_widget_get_parent (GTK_WIDGET (screen))), GTK_WIDGET (screen));
2698 g_object_unref (screen_container);
2699
2700 terminal_window_add_screen (dest_window, screen, dest_position);
2701 gtk_notebook_set_current_page (GTK_NOTEBOOK (dest_window->priv->notebook), dest_position);
2702 g_object_unref (screen);
2703 }
2704
2705 GList*
terminal_window_list_screen_containers(TerminalWindow * window)2706 terminal_window_list_screen_containers (TerminalWindow *window)
2707 {
2708 TerminalWindowPrivate *priv = window->priv;
2709
2710 /* We are trusting that GtkNotebook will return pages in order */
2711 return gtk_container_get_children (GTK_CONTAINER (priv->notebook));
2712 }
2713
2714 void
terminal_window_set_menubar_visible(TerminalWindow * window,gboolean setting)2715 terminal_window_set_menubar_visible (TerminalWindow *window,
2716 gboolean setting)
2717 {
2718 TerminalWindowPrivate *priv = window->priv;
2719 GtkAction *action;
2720
2721 /* it's been set now, so don't override when adding a screen.
2722 * this side effect must happen before we short-circuit below.
2723 */
2724 priv->use_default_menubar_visibility = FALSE;
2725
2726 if (setting == priv->menubar_visible)
2727 return;
2728
2729 priv->menubar_visible = setting;
2730
2731 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
2732 action = gtk_action_group_get_action (priv->action_group, "ViewMenubar");
2733 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), setting);
2734 G_GNUC_END_IGNORE_DEPRECATIONS;
2735
2736 g_object_set (priv->menubar, "visible", setting, NULL);
2737
2738 /* FIXMEchpe: use gtk_widget_get_realized instead? */
2739 if (priv->active_screen)
2740 {
2741 _terminal_debug_print (TERMINAL_DEBUG_GEOMETRY,
2742 "[window %p] setting size after toggling menubar visibility\n",
2743 window);
2744
2745 terminal_window_update_size (window, priv->active_screen, TRUE);
2746 }
2747 }
2748
2749 gboolean
terminal_window_get_menubar_visible(TerminalWindow * window)2750 terminal_window_get_menubar_visible (TerminalWindow *window)
2751 {
2752 TerminalWindowPrivate *priv = window->priv;
2753
2754 return priv->menubar_visible;
2755 }
2756
2757 GtkWidget *
terminal_window_get_notebook(TerminalWindow * window)2758 terminal_window_get_notebook (TerminalWindow *window)
2759 {
2760 TerminalWindowPrivate *priv = window->priv;
2761
2762 g_return_val_if_fail (TERMINAL_IS_WINDOW (window), NULL);
2763
2764 return GTK_WIDGET (priv->notebook);
2765 }
2766
2767 void
terminal_window_update_size(TerminalWindow * window,TerminalScreen * screen,gboolean even_if_mapped)2768 terminal_window_update_size (TerminalWindow *window,
2769 TerminalScreen *screen,
2770 gboolean even_if_mapped)
2771 {
2772 terminal_window_update_size_set_geometry (window, screen,
2773 even_if_mapped, NULL);
2774 }
2775
2776 gboolean
terminal_window_update_size_set_geometry(TerminalWindow * window,TerminalScreen * screen,gboolean even_if_mapped,gchar * geometry_string)2777 terminal_window_update_size_set_geometry (TerminalWindow *window,
2778 TerminalScreen *screen,
2779 gboolean even_if_mapped,
2780 gchar *geometry_string)
2781 {
2782 TerminalWindowPrivate *priv = window->priv;
2783 GtkWidget *widget;
2784 GtkWidget *app;
2785 gboolean result;
2786 int geom_result;
2787 gint force_pos_x = 0, force_pos_y = 0;
2788 unsigned int force_grid_width = 0, force_grid_height = 0;
2789 int grid_width, grid_height;
2790 gint pixel_width, pixel_height;
2791 GdkWindow *gdk_window;
2792 GdkGravity pos_gravity;
2793
2794 gdk_window = gtk_widget_get_window (GTK_WIDGET (window));
2795 result = TRUE;
2796
2797 if (gdk_window != NULL &&
2798 (gdk_window_get_state (gdk_window) &
2799 (GDK_WINDOW_STATE_MAXIMIZED | GDK_WINDOW_STATE_TILED)))
2800 {
2801 /* Don't adjust the size of maximized or tiled (snapped, half-maximized)
2802 * windows: if we do, there will be ugly gaps of up to 1 character cell
2803 * around otherwise tiled windows. */
2804 return result;
2805 }
2806
2807 /* be sure our geometry is up-to-date */
2808 terminal_window_update_geometry (window);
2809
2810 if (GTK_IS_WIDGET (screen))
2811 widget = GTK_WIDGET (screen);
2812 else
2813 widget = GTK_WIDGET (window);
2814
2815 app = gtk_widget_get_toplevel (widget);
2816 g_assert (app != NULL);
2817
2818 terminal_screen_get_size (screen, &grid_width, &grid_height);
2819 if (geometry_string != NULL)
2820 {
2821 geom_result = terminal_window_XParseGeometry (geometry_string,
2822 &force_pos_x,
2823 &force_pos_y,
2824 &force_grid_width,
2825 &force_grid_height);
2826 if (geom_result == NoValue)
2827 result = FALSE;
2828 }
2829 else
2830 geom_result = NoValue;
2831
2832 if ((geom_result & WidthValue) != 0)
2833 grid_width = force_grid_width;
2834 if ((geom_result & HeightValue) != 0)
2835 grid_height = force_grid_height;
2836
2837 /* the "old" struct members were updated by update_geometry */
2838 pixel_width = priv->old_chrome_width + grid_width * priv->old_char_width;
2839 pixel_height = priv->old_chrome_height + grid_height * priv->old_char_height;
2840
2841 _terminal_debug_print (TERMINAL_DEBUG_GEOMETRY,
2842 "[window %p] size is %dx%d cells of %dx%d px\n",
2843 window, grid_width, grid_height,
2844 priv->old_char_width, priv->old_char_height);
2845
2846 _terminal_debug_print (TERMINAL_DEBUG_GEOMETRY,
2847 "[window %p] %dx%d + %dx%d = %dx%d\n",
2848 window, grid_width * priv->old_char_width,
2849 grid_height * priv->old_char_height,
2850 priv->old_chrome_width, priv->old_chrome_height,
2851 pixel_width, pixel_height);
2852
2853 pos_gravity = GDK_GRAVITY_NORTH_WEST;
2854 if ((geom_result & XNegative) != 0 && (geom_result & YNegative) != 0)
2855 pos_gravity = GDK_GRAVITY_SOUTH_EAST;
2856 else if ((geom_result & XNegative) != 0)
2857 pos_gravity = GDK_GRAVITY_NORTH_EAST;
2858 else if ((geom_result & YNegative) != 0)
2859 pos_gravity = GDK_GRAVITY_SOUTH_WEST;
2860
2861 if ((geom_result & XValue) == 0)
2862 force_pos_x = 0;
2863 if ((geom_result & YValue) == 0)
2864 force_pos_y = 0;
2865
2866 if (pos_gravity == GDK_GRAVITY_SOUTH_EAST ||
2867 pos_gravity == GDK_GRAVITY_NORTH_EAST)
2868 force_pos_x = WidthOfScreen (gdk_x11_screen_get_xscreen (gtk_widget_get_screen (app))) -
2869 pixel_width + force_pos_x;
2870 if (pos_gravity == GDK_GRAVITY_SOUTH_WEST ||
2871 pos_gravity == GDK_GRAVITY_SOUTH_EAST)
2872 force_pos_y = HeightOfScreen (gdk_x11_screen_get_xscreen (gtk_widget_get_screen (app))) -
2873 pixel_height + force_pos_y;
2874
2875 /* we don't let you put a window offscreen; maybe some people would
2876 * prefer to be able to, but it's kind of a bogus thing to do.
2877 */
2878 if (force_pos_x < 0)
2879 force_pos_x = 0;
2880 if (force_pos_y < 0)
2881 force_pos_y = 0;
2882
2883 if (even_if_mapped && gtk_widget_get_mapped (app))
2884 gtk_window_resize (GTK_WINDOW (app), pixel_width, pixel_height);
2885 else
2886 gtk_window_set_default_size (GTK_WINDOW (app), pixel_width, pixel_height);
2887
2888 if ((geom_result & XValue) != 0 || (geom_result & YValue) != 0)
2889 {
2890 gtk_window_set_gravity (GTK_WINDOW (app), pos_gravity);
2891 gtk_window_move (GTK_WINDOW (app), force_pos_x, force_pos_y);
2892 }
2893
2894 return result;
2895 }
2896
2897 void
terminal_window_switch_screen(TerminalWindow * window,TerminalScreen * screen)2898 terminal_window_switch_screen (TerminalWindow *window,
2899 TerminalScreen *screen)
2900 {
2901 TerminalWindowPrivate *priv = window->priv;
2902 TerminalScreenContainer *screen_container;
2903 int page_num;
2904
2905 screen_container = terminal_screen_container_get_from_screen (screen);
2906 g_assert (TERMINAL_IS_SCREEN_CONTAINER (screen_container));
2907 page_num = gtk_notebook_page_num (GTK_NOTEBOOK (priv->notebook),
2908 GTK_WIDGET (screen_container));
2909 gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->notebook), page_num);
2910 }
2911
2912 TerminalScreen*
terminal_window_get_active(TerminalWindow * window)2913 terminal_window_get_active (TerminalWindow *window)
2914 {
2915 TerminalWindowPrivate *priv = window->priv;
2916
2917 return priv->active_screen;
2918 }
2919
2920 static gboolean
notebook_button_press_cb(GtkWidget * widget,GdkEventButton * event,GSettings * settings)2921 notebook_button_press_cb (GtkWidget *widget,
2922 GdkEventButton *event,
2923 GSettings *settings)
2924 {
2925 TerminalWindow *window = TERMINAL_WINDOW (gtk_widget_get_toplevel (widget));
2926 TerminalWindowPrivate *priv = window->priv;
2927 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2928 GtkWidget *tab;
2929 GtkWidget *menu;
2930 GtkAction *action;
2931 int tab_clicked;
2932 int page_num;
2933 int before_pages;
2934 int later_pages;
2935
2936 if ((event->type == GDK_BUTTON_PRESS && event->button == 2) &&
2937 (g_settings_get_boolean (settings, "middle-click-closes-tabs")))
2938 {
2939 tab_clicked = find_tab_num_at_pos (notebook,
2940 (int)event->x_root,
2941 (int)event->y_root);
2942 if (tab_clicked >= 0)
2943 {
2944 before_pages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (notebook));
2945 page_num = gtk_notebook_get_current_page (notebook);
2946 gtk_notebook_set_current_page (notebook, tab_clicked);
2947 TerminalScreen *active_screen = priv->active_screen;
2948
2949 if (!(confirm_close_window_or_tab (window, active_screen)))
2950 {
2951 update_tab_visibility (window, -1);
2952 gtk_notebook_remove_page(notebook, tab_clicked);
2953 }
2954
2955 later_pages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (notebook));
2956
2957 if (before_pages > later_pages) {
2958 if (tab_clicked > page_num)
2959 gtk_notebook_set_current_page (notebook, page_num);
2960 else if (tab_clicked < page_num)
2961 gtk_notebook_set_current_page (notebook, page_num - 1);
2962 }
2963 else
2964 gtk_notebook_set_current_page (notebook, page_num);
2965
2966 }
2967 }
2968
2969 if (event->type != GDK_BUTTON_PRESS ||
2970 event->button != 3 ||
2971 (event->state & gtk_accelerator_get_default_mod_mask ()) != 0)
2972 return FALSE;
2973
2974 tab_clicked = find_tab_num_at_pos (notebook,
2975 (int)event->x_root,
2976 (int)event->y_root);
2977 if (tab_clicked < 0)
2978 return FALSE;
2979
2980 /* switch to the page the mouse is over */
2981 gtk_notebook_set_current_page (notebook, tab_clicked);
2982
2983 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
2984 action = gtk_action_group_get_action (priv->action_group, "NotebookPopup");
2985 gtk_action_activate (action);
2986 G_GNUC_END_IGNORE_DEPRECATIONS;
2987
2988 menu = gtk_ui_manager_get_widget (priv->ui_manager, "/NotebookPopup");
2989 if (gtk_menu_get_attach_widget (GTK_MENU (menu)))
2990 gtk_menu_detach (GTK_MENU (menu));
2991 tab = gtk_notebook_get_nth_page (notebook, tab_clicked);
2992 gtk_menu_attach_to_widget (GTK_MENU (menu), tab, NULL);
2993 gtk_menu_popup_at_pointer (GTK_MENU (menu), NULL);
2994
2995 return TRUE;
2996 }
2997
2998 static gboolean
window_key_press_cb(GtkWidget * widget,GdkEventKey * event,GSettings * settings)2999 window_key_press_cb (GtkWidget *widget,
3000 GdkEventKey *event,
3001 GSettings *settings)
3002 {
3003 if (g_settings_get_boolean (settings, "ctrl-tab-switch-tabs") &&
3004 event->state & GDK_CONTROL_MASK)
3005 {
3006 TerminalWindow *window = TERMINAL_WINDOW (widget);
3007 TerminalWindowPrivate *priv = window->priv;
3008 GtkNotebook *notebook = GTK_NOTEBOOK (priv->notebook);
3009
3010 int pages = gtk_notebook_get_n_pages (notebook);
3011 int page_num = gtk_notebook_get_current_page (notebook);
3012
3013 if (event->keyval == GDK_KEY_ISO_Left_Tab)
3014 {
3015 if (page_num != 0)
3016 gtk_notebook_prev_page (notebook);
3017 else
3018 gtk_notebook_set_current_page (notebook, (pages - 1));
3019 return TRUE;
3020 }
3021
3022 if (event->keyval == GDK_KEY_Tab)
3023 {
3024 if (page_num != (pages -1))
3025 gtk_notebook_next_page (notebook);
3026 else
3027 gtk_notebook_set_current_page (notebook, 0);
3028 return TRUE;
3029 }
3030 }
3031 return FALSE;
3032 }
3033
3034 static gboolean
notebook_popup_menu_cb(GtkWidget * widget,TerminalWindow * window)3035 notebook_popup_menu_cb (GtkWidget *widget,
3036 TerminalWindow *window)
3037 {
3038 TerminalWindowPrivate *priv = window->priv;
3039 GtkNotebook *notebook = GTK_NOTEBOOK (priv->notebook);
3040 GtkWidget *focus_widget, *tab, *tab_label, *menu;
3041 GtkAction *action;
3042 int page_num;
3043
3044 focus_widget = gtk_window_get_focus (GTK_WINDOW (window));
3045 /* Only respond if the notebook is the actual focus */
3046 if (focus_widget != priv->notebook)
3047 return FALSE;
3048
3049 page_num = gtk_notebook_get_current_page (notebook);
3050 tab = gtk_notebook_get_nth_page (notebook, page_num);
3051 tab_label = gtk_notebook_get_tab_label (notebook, tab);
3052
3053 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
3054 action = gtk_action_group_get_action (priv->action_group, "NotebookPopup");
3055 gtk_action_activate (action);
3056 G_GNUC_END_IGNORE_DEPRECATIONS;
3057
3058 menu = gtk_ui_manager_get_widget (priv->ui_manager, "/NotebookPopup");
3059 if (gtk_menu_get_attach_widget (GTK_MENU (menu)))
3060 gtk_menu_detach (GTK_MENU (menu));
3061 gtk_menu_attach_to_widget (GTK_MENU (menu), tab_label, NULL);
3062 gtk_menu_popup_at_widget (GTK_MENU (menu),
3063 tab_label,
3064 GDK_GRAVITY_SOUTH_WEST,
3065 GDK_GRAVITY_NORTH_WEST,
3066 NULL);
3067 gtk_menu_shell_select_first (GTK_MENU_SHELL (menu), FALSE);
3068
3069 return TRUE;
3070 }
3071
3072 static void
notebook_page_selected_callback(GtkWidget * notebook,GtkWidget * page_widget,guint page_num,TerminalWindow * window)3073 notebook_page_selected_callback (GtkWidget *notebook,
3074 GtkWidget *page_widget,
3075 guint page_num,
3076 TerminalWindow *window)
3077 {
3078 TerminalWindowPrivate *priv = window->priv;
3079 GtkWidget *widget;
3080 TerminalScreen *screen;
3081 int old_grid_width, old_grid_height;
3082
3083 _terminal_debug_print (TERMINAL_DEBUG_MDI,
3084 "[window %p] MDI: page-selected %d\n",
3085 window, page_num);
3086
3087 if (priv->disposed)
3088 return;
3089
3090 screen = terminal_screen_container_get_screen (TERMINAL_SCREEN_CONTAINER (page_widget));
3091 widget = GTK_WIDGET (screen);
3092 g_assert (screen != NULL);
3093
3094 _terminal_debug_print (TERMINAL_DEBUG_MDI,
3095 "[window %p] MDI: setting active tab to screen %p (old active screen %p)\n",
3096 window, screen, priv->active_screen);
3097
3098 if (priv->active_screen == screen)
3099 return;
3100
3101 if (priv->active_screen != NULL)
3102 {
3103 terminal_screen_get_size (priv->active_screen, &old_grid_width, &old_grid_height);
3104
3105 /* This is so that we maintain the same grid */
3106 vte_terminal_set_size (VTE_TERMINAL (screen), old_grid_width, old_grid_height);
3107 }
3108
3109 /* Workaround to remove gtknotebook's feature of computing its size based on
3110 * all pages. When the widget is hidden, its size will not be taken into
3111 * account.
3112 */
3113 if (priv->active_screen)
3114 gtk_widget_hide (GTK_WIDGET (priv->active_screen)); /* FIXME */
3115
3116 /* Make sure that the widget is no longer hidden due to the workaround */
3117 gtk_widget_show (widget);
3118
3119 priv->active_screen = screen;
3120
3121 /* Override menubar setting if it wasn't restored from session */
3122 if (priv->use_default_menubar_visibility)
3123 {
3124 gboolean setting =
3125 terminal_profile_get_property_boolean (terminal_screen_get_profile (screen), TERMINAL_PROFILE_DEFAULT_SHOW_MENUBAR);
3126
3127 terminal_window_set_menubar_visible (window, setting);
3128 }
3129
3130 sync_screen_icon_title_set (screen, NULL, window);
3131 sync_screen_icon_title (screen, NULL, window);
3132 sync_screen_title (screen, NULL, window);
3133
3134 /* set size of window to current grid size */
3135 _terminal_debug_print (TERMINAL_DEBUG_GEOMETRY,
3136 "[window %p] setting size after flipping notebook pages\n",
3137 window);
3138 terminal_window_update_size (window, screen, TRUE);
3139
3140 terminal_window_update_tabs_menu_sensitivity (window);
3141 terminal_window_update_encoding_menu_active_encoding (window);
3142 terminal_window_update_set_profile_menu_active_profile (window);
3143 terminal_window_update_copy_sensitivity (screen, window);
3144 terminal_window_update_zoom_sensitivity (window);
3145 terminal_window_update_search_sensitivity (screen, window);
3146 }
3147
3148 static void
notebook_page_added_callback(GtkWidget * notebook,GtkWidget * container,guint page_num,TerminalWindow * window)3149 notebook_page_added_callback (GtkWidget *notebook,
3150 GtkWidget *container,
3151 guint page_num,
3152 TerminalWindow *window)
3153 {
3154 TerminalWindowPrivate *priv = window->priv;
3155 TerminalScreen *screen;
3156 int pages;
3157
3158 screen = terminal_screen_container_get_screen (TERMINAL_SCREEN_CONTAINER (container));
3159
3160 _terminal_debug_print (TERMINAL_DEBUG_MDI,
3161 "[window %p] MDI: screen %p inserted\n",
3162 window, screen);
3163
3164 g_signal_connect (G_OBJECT (screen),
3165 "profile-set",
3166 G_CALLBACK (profile_set_callback),
3167 window);
3168
3169 /* FIXME: only connect on the active screen, not all screens! */
3170 g_signal_connect (screen, "notify::title",
3171 G_CALLBACK (sync_screen_title), window);
3172 g_signal_connect (screen, "notify::icon-title",
3173 G_CALLBACK (sync_screen_icon_title), window);
3174 g_signal_connect (screen, "notify::icon-title-set",
3175 G_CALLBACK (sync_screen_icon_title_set), window);
3176 g_signal_connect (screen, "selection-changed",
3177 G_CALLBACK (terminal_window_update_copy_sensitivity), window);
3178
3179 g_signal_connect (screen, "show-popup-menu",
3180 G_CALLBACK (screen_show_popup_menu_callback), window);
3181 g_signal_connect (screen, "match-clicked",
3182 G_CALLBACK (screen_match_clicked_cb), window);
3183 g_signal_connect (screen, "resize-window",
3184 G_CALLBACK (screen_resize_window_cb), window);
3185
3186 g_signal_connect (screen, "close-screen",
3187 G_CALLBACK (screen_close_cb), window);
3188
3189 update_tab_visibility (window, 0);
3190 terminal_window_update_tabs_menu_sensitivity (window);
3191 terminal_window_update_search_sensitivity (screen, window);
3192
3193 #if 0
3194 /* FIXMEchpe: wtf is this doing? */
3195
3196 /* If we have an active screen, match its size and zoom */
3197 if (priv->active_screen)
3198 {
3199 int current_width, current_height;
3200 double scale;
3201
3202 terminal_screen_get_size (priv->active_screen, ¤t_width, ¤t_height);
3203 vte_terminal_set_size (VTE_TERMINAL (screen), current_width, current_height);
3204
3205 scale = terminal_screen_get_font_scale (priv->active_screen);
3206 terminal_screen_set_font_scale (screen, scale);
3207 }
3208 #endif
3209
3210 if (priv->present_on_insert)
3211 {
3212 gtk_window_present_with_time (GTK_WINDOW (window), gtk_get_current_event_time ());
3213 priv->present_on_insert = FALSE;
3214 }
3215 pages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (notebook));
3216 if (pages == 2) terminal_window_update_size (window, priv->active_screen, TRUE);
3217 }
3218
3219 static void
notebook_page_removed_callback(GtkWidget * notebook,GtkWidget * container,guint page_num,TerminalWindow * window)3220 notebook_page_removed_callback (GtkWidget *notebook,
3221 GtkWidget *container,
3222 guint page_num,
3223 TerminalWindow *window)
3224 {
3225 TerminalWindowPrivate *priv = window->priv;
3226 TerminalScreen *screen;
3227 int pages;
3228
3229 if (priv->disposed)
3230 return;
3231
3232 screen = terminal_screen_container_get_screen (TERMINAL_SCREEN_CONTAINER (container));
3233
3234 _terminal_debug_print (TERMINAL_DEBUG_MDI,
3235 "[window %p] MDI: screen %p removed\n",
3236 window, screen);
3237
3238 g_signal_handlers_disconnect_by_func (G_OBJECT (screen),
3239 G_CALLBACK (profile_set_callback),
3240 window);
3241
3242 g_signal_handlers_disconnect_by_func (G_OBJECT (screen),
3243 G_CALLBACK (sync_screen_title),
3244 window);
3245
3246 g_signal_handlers_disconnect_by_func (G_OBJECT (screen),
3247 G_CALLBACK (sync_screen_icon_title),
3248 window);
3249
3250 g_signal_handlers_disconnect_by_func (G_OBJECT (screen),
3251 G_CALLBACK (sync_screen_icon_title_set),
3252 window);
3253
3254 g_signal_handlers_disconnect_by_func (G_OBJECT (screen),
3255 G_CALLBACK (terminal_window_update_copy_sensitivity),
3256 window);
3257
3258 g_signal_handlers_disconnect_by_func (screen,
3259 G_CALLBACK (screen_show_popup_menu_callback),
3260 window);
3261
3262 g_signal_handlers_disconnect_by_func (screen,
3263 G_CALLBACK (screen_match_clicked_cb),
3264 window);
3265 g_signal_handlers_disconnect_by_func (screen,
3266 G_CALLBACK (screen_resize_window_cb),
3267 window);
3268
3269 g_signal_handlers_disconnect_by_func (screen,
3270 G_CALLBACK (screen_close_cb),
3271 window);
3272
3273 terminal_window_update_tabs_menu_sensitivity (window);
3274 update_tab_visibility (window, 0);
3275 terminal_window_update_search_sensitivity (screen, window);
3276
3277 pages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (notebook));
3278 if (pages == 1)
3279 {
3280 terminal_window_update_size (window, priv->active_screen, TRUE);
3281 }
3282 else if (pages == 0)
3283 {
3284 gtk_widget_destroy (GTK_WIDGET (window));
3285 }
3286 }
3287
3288 void
terminal_window_update_copy_selection(TerminalScreen * screen,TerminalWindow * window)3289 terminal_window_update_copy_selection (TerminalScreen *screen,
3290 TerminalWindow *window)
3291 {
3292 TerminalWindowPrivate *priv = window->priv;
3293 priv->copy_selection =
3294 terminal_profile_get_property_boolean (terminal_screen_get_profile (screen),
3295 TERMINAL_PROFILE_COPY_SELECTION);
3296 }
3297
3298 static gboolean
notebook_scroll_event_cb(GtkWidget * widget,GdkEventScroll * event,TerminalWindow * window)3299 notebook_scroll_event_cb (GtkWidget *widget,
3300 GdkEventScroll *event,
3301 TerminalWindow *window)
3302 {
3303 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
3304 GtkWidget *child, *event_widget, *action_widget;
3305
3306 child = gtk_notebook_get_nth_page (notebook, gtk_notebook_get_current_page (notebook));
3307 if (child == NULL)
3308 return FALSE;
3309
3310 event_widget = gtk_get_event_widget ((GdkEvent *) event);
3311
3312 /* Ignore scroll events from the content of the page */
3313 if (event_widget == NULL ||
3314 event_widget == child ||
3315 gtk_widget_is_ancestor (event_widget, child))
3316 return FALSE;
3317
3318 /* And also from the action widgets */
3319 action_widget = gtk_notebook_get_action_widget (notebook, GTK_PACK_START);
3320 if (event_widget == action_widget ||
3321 (action_widget != NULL && gtk_widget_is_ancestor (event_widget, action_widget)))
3322 return FALSE;
3323 action_widget = gtk_notebook_get_action_widget (notebook, GTK_PACK_END);
3324 if (event_widget == action_widget ||
3325 (action_widget != NULL && gtk_widget_is_ancestor (event_widget, action_widget)))
3326 return FALSE;
3327
3328 switch (event->direction) {
3329 case GDK_SCROLL_RIGHT:
3330 case GDK_SCROLL_DOWN:
3331 gtk_notebook_next_page (notebook);
3332 break;
3333 case GDK_SCROLL_LEFT:
3334 case GDK_SCROLL_UP:
3335 gtk_notebook_prev_page (notebook);
3336 break;
3337 case GDK_SCROLL_SMOOTH:
3338 switch (gtk_notebook_get_tab_pos (notebook)) {
3339 case GTK_POS_LEFT:
3340 case GTK_POS_RIGHT:
3341 if (event->delta_y > 0)
3342 gtk_notebook_next_page (notebook);
3343 else if (event->delta_y < 0)
3344 gtk_notebook_prev_page (notebook);
3345 break;
3346 case GTK_POS_TOP:
3347 case GTK_POS_BOTTOM:
3348 if (event->delta_x > 0)
3349 gtk_notebook_next_page (notebook);
3350 else if (event->delta_x < 0)
3351 gtk_notebook_prev_page (notebook);
3352 break;
3353 }
3354 break;
3355 }
3356
3357 return TRUE;
3358 }
3359
3360 void
terminal_window_update_geometry(TerminalWindow * window)3361 terminal_window_update_geometry (TerminalWindow *window)
3362 {
3363 TerminalWindowPrivate *priv = window->priv;
3364 GtkWidget *widget;
3365 GdkGeometry hints;
3366 GtkBorder padding;
3367 GtkRequisition toplevel_request, vbox_request, widget_request;
3368 int grid_width, grid_height;
3369 int char_width, char_height;
3370 int chrome_width, chrome_height;
3371
3372 if (priv->active_screen == NULL)
3373 return;
3374
3375 widget = GTK_WIDGET (priv->active_screen);
3376
3377 /* We set geometry hints from the active term; best thing
3378 * I can think of to do. Other option would be to try to
3379 * get some kind of union of all hints from all terms in the
3380 * window, but that doesn't make too much sense.
3381 */
3382 terminal_screen_get_cell_size (priv->active_screen, &char_width, &char_height);
3383
3384 terminal_screen_get_size (priv->active_screen, &grid_width, &grid_height);
3385 _terminal_debug_print (TERMINAL_DEBUG_GEOMETRY, "%dx%d cells of %dx%d px = %dx%d px\n",
3386 grid_width, grid_height, char_width, char_height,
3387 char_width * grid_width, char_height * grid_height);
3388
3389 gtk_style_context_get_padding(gtk_widget_get_style_context (widget),
3390 gtk_widget_get_state_flags (widget),
3391 &padding);
3392
3393 _terminal_debug_print (TERMINAL_DEBUG_GEOMETRY, "padding = %dx%d px\n",
3394 padding.left + padding.right,
3395 padding.top + padding.bottom);
3396
3397 gtk_widget_get_preferred_size (priv->main_vbox, NULL, &vbox_request);
3398 _terminal_debug_print (TERMINAL_DEBUG_GEOMETRY, "content area requests %dx%d px\n",
3399 vbox_request.width, vbox_request.height);
3400
3401 gtk_widget_get_preferred_size (GTK_WIDGET (window), NULL, &toplevel_request);
3402 _terminal_debug_print (TERMINAL_DEBUG_GEOMETRY, "window requests %dx%d px\n",
3403 toplevel_request.width, toplevel_request.height);
3404
3405 chrome_width = vbox_request.width - (char_width * grid_width);
3406 chrome_height = vbox_request.height - (char_height * grid_height);
3407 _terminal_debug_print (TERMINAL_DEBUG_GEOMETRY, "chrome: %dx%d px\n",
3408 chrome_width, chrome_height);
3409
3410 gtk_widget_get_preferred_size (widget, NULL, &widget_request);
3411 _terminal_debug_print (TERMINAL_DEBUG_GEOMETRY, "terminal widget requests %dx%d px\n",
3412 widget_request.width, widget_request.height);
3413
3414 if (char_width != priv->old_char_width ||
3415 char_height != priv->old_char_height ||
3416 padding.left + padding.right != priv->old_padding_width ||
3417 padding.top + padding.bottom != priv->old_padding_height ||
3418 chrome_width != priv->old_chrome_width ||
3419 chrome_height != priv->old_chrome_height ||
3420 widget != GTK_WIDGET (priv->old_geometry_widget))
3421 {
3422 hints.base_width = chrome_width;
3423 hints.base_height = chrome_height;
3424
3425 #define MIN_WIDTH_CHARS 4
3426 #define MIN_HEIGHT_CHARS 1
3427
3428 hints.width_inc = char_width;
3429 hints.height_inc = char_height;
3430
3431 /* min size is min size of the whole window, remember. */
3432 hints.min_width = hints.base_width + hints.width_inc * MIN_WIDTH_CHARS;
3433 hints.min_height = hints.base_height + hints.height_inc * MIN_HEIGHT_CHARS;
3434
3435 gtk_window_set_geometry_hints (GTK_WINDOW (window),
3436 NULL,
3437 &hints,
3438 GDK_HINT_RESIZE_INC |
3439 GDK_HINT_MIN_SIZE |
3440 GDK_HINT_BASE_SIZE);
3441
3442 _terminal_debug_print (TERMINAL_DEBUG_GEOMETRY,
3443 "[window %p] hints: base %dx%d min %dx%d inc %d %d\n",
3444 window,
3445 hints.base_width,
3446 hints.base_height,
3447 hints.min_width,
3448 hints.min_height,
3449 hints.width_inc,
3450 hints.height_inc);
3451
3452 priv->old_geometry_widget = widget;
3453 }
3454 else
3455 {
3456 _terminal_debug_print (TERMINAL_DEBUG_GEOMETRY,
3457 "[window %p] hints: increment unchanged, not setting\n",
3458 window);
3459 }
3460
3461 /* We need these for the size calculation in terminal_window_update_size(),
3462 * so we set them unconditionally. */
3463 priv->old_char_width = char_width;
3464 priv->old_char_height = char_height;
3465 priv->old_chrome_width = chrome_width;
3466 priv->old_chrome_height = chrome_height;
3467 priv->old_padding_width = padding.left + padding.right;
3468 priv->old_padding_height = padding.top + padding.bottom;
3469 }
3470
3471 static void
file_new_window_callback(GtkAction * action,TerminalWindow * window)3472 file_new_window_callback (GtkAction *action,
3473 TerminalWindow *window)
3474 {
3475 TerminalWindowPrivate *priv = window->priv;
3476 TerminalApp *app;
3477 TerminalWindow *new_window;
3478 TerminalProfile *profile;
3479 char *new_working_directory;
3480
3481 app = terminal_app_get ();
3482
3483 profile = g_object_get_data (G_OBJECT (action), PROFILE_DATA_KEY);
3484 if (!profile)
3485 profile = terminal_screen_get_profile (priv->active_screen);
3486 if (!profile)
3487 profile = terminal_app_get_profile_for_new_term (app);
3488 if (!profile)
3489 return;
3490
3491 if (_terminal_profile_get_forgotten (profile))
3492 return;
3493
3494 new_window = terminal_app_new_window (app, gtk_widget_get_screen (GTK_WIDGET (window)));
3495
3496 new_working_directory = terminal_screen_get_current_dir_with_fallback (priv->active_screen);
3497 terminal_app_new_terminal (app, new_window, profile,
3498 NULL, NULL,
3499 new_working_directory,
3500 terminal_screen_get_initial_environment (priv->active_screen),
3501 1.0);
3502 g_free (new_working_directory);
3503
3504 gtk_window_present (GTK_WINDOW (new_window));
3505 }
3506
3507 static void
file_new_tab_callback(GtkAction * action,TerminalWindow * window)3508 file_new_tab_callback (GtkAction *action,
3509 TerminalWindow *window)
3510 {
3511 TerminalWindowPrivate *priv = window->priv;
3512 TerminalApp *app;
3513 TerminalProfile *profile;
3514 char *new_working_directory;
3515
3516 app = terminal_app_get ();
3517 profile = g_object_get_data (G_OBJECT (action), PROFILE_DATA_KEY);
3518 if (!profile)
3519 profile = terminal_screen_get_profile (priv->active_screen);
3520 if (!profile)
3521 profile = terminal_app_get_profile_for_new_term (app);
3522 if (!profile)
3523 return;
3524
3525 if (_terminal_profile_get_forgotten (profile))
3526 return;
3527
3528 new_working_directory = terminal_screen_get_current_dir_with_fallback (priv->active_screen);
3529 terminal_app_new_terminal (app, window, profile,
3530 NULL, NULL,
3531 new_working_directory,
3532 terminal_screen_get_initial_environment (priv->active_screen),
3533 1.0);
3534 g_free (new_working_directory);
3535 }
3536
3537 static void
confirm_close_response_cb(GtkWidget * dialog,int response,TerminalWindow * window)3538 confirm_close_response_cb (GtkWidget *dialog,
3539 int response,
3540 TerminalWindow *window)
3541 {
3542 TerminalScreen *screen;
3543
3544 screen = g_object_get_data (G_OBJECT (dialog), "close-screen");
3545
3546 gtk_widget_destroy (dialog);
3547
3548 if (response != GTK_RESPONSE_ACCEPT)
3549 return;
3550
3551 if (screen)
3552 terminal_window_remove_screen (window, screen);
3553 else
3554 gtk_widget_destroy (GTK_WIDGET (window));
3555 }
3556
3557 /* Returns: TRUE if closing needs to wait until user confirmation;
3558 * FALSE if the terminal or window can close immediately.
3559 */
3560 static gboolean
confirm_close_window_or_tab(TerminalWindow * window,TerminalScreen * screen)3561 confirm_close_window_or_tab (TerminalWindow *window,
3562 TerminalScreen *screen)
3563 {
3564 GtkBuilder *builder;
3565 TerminalWindowPrivate *priv = window->priv;
3566 GtkWidget *dialog;
3567 gboolean do_confirm;
3568 gboolean has_processes;
3569 int n_tabs;
3570 char *confirm_msg;
3571
3572 do_confirm = g_settings_get_boolean (settings_global, "confirm-window-close");
3573
3574 if (!do_confirm)
3575 return FALSE;
3576
3577 if (screen)
3578 {
3579 has_processes = terminal_screen_has_foreground_process (screen);
3580 n_tabs = 1;
3581 }
3582 else
3583 {
3584 GList *tabs, *t;
3585
3586 do_confirm = FALSE;
3587
3588 tabs = terminal_window_list_screen_containers (window);
3589 n_tabs = g_list_length (tabs);
3590
3591 for (t = tabs; t != NULL; t = t->next)
3592 {
3593 TerminalScreen *terminal_screen;
3594
3595 terminal_screen = terminal_screen_container_get_screen (TERMINAL_SCREEN_CONTAINER (t->data));
3596 has_processes = terminal_screen_has_foreground_process (terminal_screen);
3597 if (has_processes)
3598 break;
3599 }
3600 g_list_free (tabs);
3601 }
3602
3603
3604 if (has_processes)
3605 {
3606 if (n_tabs > 1)
3607 confirm_msg = _("There are still processes running in some terminals in this window.\n"
3608 "Closing the window will kill all of them.");
3609 else
3610 confirm_msg = _("There is still a process running in this terminal.\n"
3611 "Closing the terminal will kill it.");
3612 } else if (n_tabs > 1)
3613 confirm_msg = _("There are multiple tabs open in this window.");
3614 else
3615 return FALSE;
3616
3617
3618 builder = gtk_builder_new_from_resource (TERMINAL_RESOURCES_PATH_PREFIX G_DIR_SEPARATOR_S "ui/confirm-close-dialog.ui");
3619 priv->confirm_close_dialog = dialog = GTK_WIDGET (gtk_builder_get_object (builder, "confirm_close_dialog"));
3620 if (n_tabs > 1) {
3621 gtk_label_set_text (GTK_LABEL (gtk_builder_get_object (builder, "question_text")), _("Close this window?"));
3622 gtk_button_set_label (GTK_BUTTON (gtk_builder_get_object (builder, "button_close")), _("C_lose Window"));
3623 } else {
3624 gtk_label_set_text (GTK_LABEL (gtk_builder_get_object (builder, "question_text")), _("Close this terminal?"));
3625 gtk_button_set_label (GTK_BUTTON (gtk_builder_get_object (builder, "button_close")), _("C_lose Terminal"));
3626 }
3627 gtk_label_set_text (GTK_LABEL (gtk_builder_get_object (builder, "description_text")), confirm_msg);
3628 g_object_unref (builder);
3629
3630 g_object_set_data (G_OBJECT (dialog), "close-screen", screen);
3631
3632 g_signal_connect (dialog, "destroy",
3633 G_CALLBACK (gtk_widget_destroyed), &priv->confirm_close_dialog);
3634 g_signal_connect (dialog, "response",
3635 G_CALLBACK (confirm_close_response_cb), window);
3636
3637 gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (window));
3638 gtk_window_set_title (GTK_WINDOW (dialog), "");
3639 gtk_window_present (GTK_WINDOW (dialog));
3640
3641 return TRUE;
3642 }
3643
3644 static void
file_close_window_callback(GtkAction * action,TerminalWindow * window)3645 file_close_window_callback (GtkAction *action,
3646 TerminalWindow *window)
3647 {
3648 if (confirm_close_window_or_tab (window, NULL))
3649 return;
3650
3651 gtk_widget_destroy (GTK_WIDGET (window));
3652 }
3653
3654 #ifdef ENABLE_SAVE
3655 static void
save_contents_dialog_on_response(GtkDialog * dialog,gint response_id,gpointer terminal)3656 save_contents_dialog_on_response (GtkDialog *dialog, gint response_id, gpointer terminal)
3657 {
3658 GtkWindow *parent;
3659 gchar *filename_uri = NULL;
3660 GFile *file;
3661 GOutputStream *stream;
3662 GError *error = NULL;
3663
3664 if (response_id != GTK_RESPONSE_ACCEPT)
3665 {
3666 gtk_widget_destroy (GTK_WIDGET (dialog));
3667 return;
3668 }
3669
3670 parent = (GtkWindow*) gtk_widget_get_ancestor (GTK_WIDGET (terminal), GTK_TYPE_WINDOW);
3671 filename_uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (dialog));
3672
3673 gtk_widget_destroy (GTK_WIDGET (dialog));
3674
3675 if (filename_uri == NULL)
3676 return;
3677
3678 file = g_file_new_for_uri (filename_uri);
3679 stream = G_OUTPUT_STREAM (g_file_replace (file, NULL, FALSE, G_FILE_CREATE_NONE, NULL, &error));
3680
3681 if (stream)
3682 {
3683 /* FIXME
3684 * Should be replaced with the async version when vte implements that.
3685 */
3686 vte_terminal_write_contents_sync (terminal, stream,
3687 VTE_WRITE_DEFAULT,
3688 NULL, &error);
3689 g_object_unref (stream);
3690 }
3691
3692 if (error)
3693 {
3694 terminal_util_show_error_dialog (parent, NULL, error,
3695 "%s", _("Could not save contents"));
3696 g_error_free (error);
3697 }
3698
3699 g_object_unref(file);
3700 g_free(filename_uri);
3701 }
3702 #endif /* ENABLE_SAVE */
3703
3704 static void
file_save_contents_callback(GtkAction * action,TerminalWindow * window)3705 file_save_contents_callback (GtkAction *action,
3706 TerminalWindow *window)
3707 {
3708 #ifdef ENABLE_SAVE
3709 GtkWidget *dialog = NULL;
3710 TerminalWindowPrivate *priv = window->priv;
3711 VteTerminal *terminal;
3712
3713 if (!priv->active_screen)
3714 return;
3715
3716 terminal = VTE_TERMINAL (priv->active_screen);
3717 g_return_if_fail (VTE_IS_TERMINAL (terminal));
3718
3719 dialog = gtk_file_chooser_dialog_new (_("Save as..."),
3720 GTK_WINDOW(window),
3721 GTK_FILE_CHOOSER_ACTION_SAVE,
3722 "gtk-cancel", GTK_RESPONSE_CANCEL,
3723 "gtk-save", GTK_RESPONSE_ACCEPT,
3724 NULL);
3725
3726 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog), TRUE);
3727 /* XXX where should we save to? */
3728 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), g_get_user_special_dir (G_USER_DIRECTORY_DESKTOP));
3729
3730 gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW(window));
3731 gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
3732 gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE);
3733
3734 g_signal_connect (dialog, "response", G_CALLBACK (save_contents_dialog_on_response), terminal);
3735 g_signal_connect (dialog, "delete_event", G_CALLBACK (terminal_util_dialog_response_on_delete), NULL);
3736
3737 gtk_window_present (GTK_WINDOW (dialog));
3738 #endif /* ENABLE_SAVE */
3739 }
3740
3741 static void
file_close_tab_callback(GtkAction * action,TerminalWindow * window)3742 file_close_tab_callback (GtkAction *action,
3743 TerminalWindow *window)
3744 {
3745 TerminalWindowPrivate *priv = window->priv;
3746 TerminalScreen *active_screen = priv->active_screen;
3747
3748 if (!active_screen)
3749 return;
3750
3751 if (confirm_close_window_or_tab (window, active_screen))
3752 return;
3753
3754 terminal_window_remove_screen (window, active_screen);
3755 }
3756
3757 static void
edit_copy_callback(GtkAction * action,TerminalWindow * window)3758 edit_copy_callback (GtkAction *action,
3759 TerminalWindow *window)
3760 {
3761 TerminalWindowPrivate *priv = window->priv;
3762
3763 if (!priv->active_screen)
3764 return;
3765
3766 #if VTE_CHECK_VERSION (0, 50, 0)
3767 vte_terminal_copy_clipboard_format (VTE_TERMINAL (priv->active_screen), VTE_FORMAT_TEXT);
3768 #else
3769 vte_terminal_copy_clipboard (VTE_TERMINAL (priv->active_screen));
3770 #endif
3771 }
3772
3773 typedef struct
3774 {
3775 TerminalScreen *screen;
3776 gboolean uris_as_paths;
3777 } PasteData;
3778
3779 static void
clipboard_uris_received_cb(GtkClipboard * clipboard,char ** uris,PasteData * data)3780 clipboard_uris_received_cb (GtkClipboard *clipboard,
3781 /* const */ char **uris,
3782 PasteData *data)
3783 {
3784 char *text;
3785 gsize len;
3786
3787 if (!uris)
3788 {
3789 g_object_unref (data->screen);
3790 g_slice_free (PasteData, data);
3791 return;
3792 }
3793
3794 /* This potentially modifies the strings in |uris| but that's ok */
3795 if (data->uris_as_paths)
3796 terminal_util_transform_uris_to_quoted_fuse_paths (uris);
3797
3798 text = terminal_util_concat_uris (uris, &len);
3799 vte_terminal_feed_child (VTE_TERMINAL (data->screen), text, len);
3800 g_free (text);
3801
3802 g_object_unref (data->screen);
3803 g_slice_free (PasteData, data);
3804 }
3805
3806 static void
clipboard_targets_received_cb(GtkClipboard * clipboard,GdkAtom * targets,int n_targets,PasteData * data)3807 clipboard_targets_received_cb (GtkClipboard *clipboard,
3808 GdkAtom *targets,
3809 int n_targets,
3810 PasteData *data)
3811 {
3812 if (!targets)
3813 {
3814 g_object_unref (data->screen);
3815 g_slice_free (PasteData, data);
3816 return;
3817 }
3818
3819 if (gtk_targets_include_uri (targets, n_targets))
3820 {
3821 gtk_clipboard_request_uris (clipboard,
3822 (GtkClipboardURIReceivedFunc) clipboard_uris_received_cb,
3823 data);
3824 return;
3825 }
3826 else /* if (gtk_targets_include_text (targets, n_targets)) */
3827 {
3828 vte_terminal_paste_clipboard (VTE_TERMINAL (data->screen));
3829 }
3830
3831 g_object_unref (data->screen);
3832 g_slice_free (PasteData, data);
3833 }
3834
3835 static void
edit_paste_callback(GtkAction * action,TerminalWindow * window)3836 edit_paste_callback (GtkAction *action,
3837 TerminalWindow *window)
3838 {
3839 TerminalWindowPrivate *priv = window->priv;
3840 GtkClipboard *clipboard;
3841 PasteData *data;
3842 const char *name;
3843
3844 if (!priv->active_screen)
3845 return;
3846
3847 clipboard = gtk_widget_get_clipboard (GTK_WIDGET (window), GDK_SELECTION_CLIPBOARD);
3848 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
3849 name = gtk_action_get_name (action);
3850 G_GNUC_END_IGNORE_DEPRECATIONS;
3851
3852 data = g_slice_new (PasteData);
3853 data->screen = g_object_ref (priv->active_screen);
3854 data->uris_as_paths = (name == I_("EditPasteURIPaths") || name == I_("PopupPasteURIPaths"));
3855
3856 gtk_clipboard_request_targets (clipboard,
3857 (GtkClipboardTargetsReceivedFunc) clipboard_targets_received_cb,
3858 data);
3859 }
3860
3861 static void
edit_select_all_callback(GtkAction * action,TerminalWindow * window)3862 edit_select_all_callback (GtkAction *action,
3863 TerminalWindow *window)
3864 {
3865 TerminalWindowPrivate *priv = window->priv;
3866
3867 if (!priv->active_screen)
3868 return;
3869
3870 vte_terminal_select_all (VTE_TERMINAL (priv->active_screen));
3871 }
3872
3873 static void
edit_keybindings_callback(GtkAction * action,TerminalWindow * window)3874 edit_keybindings_callback (GtkAction *action,
3875 TerminalWindow *window)
3876 {
3877 terminal_app_edit_keybindings (terminal_app_get (),
3878 GTK_WINDOW (window));
3879 }
3880
3881 static void
edit_current_profile_callback(GtkAction * action,TerminalWindow * window)3882 edit_current_profile_callback (GtkAction *action,
3883 TerminalWindow *window)
3884 {
3885 TerminalWindowPrivate *priv = window->priv;
3886
3887 terminal_app_edit_profile (terminal_app_get (),
3888 terminal_screen_get_profile (priv->active_screen),
3889 GTK_WINDOW (window),
3890 NULL);
3891 }
3892
3893 static void
file_new_profile_callback(GtkAction * action,TerminalWindow * window)3894 file_new_profile_callback (GtkAction *action,
3895 TerminalWindow *window)
3896 {
3897 TerminalWindowPrivate *priv = window->priv;
3898
3899 terminal_app_new_profile (terminal_app_get (),
3900 terminal_screen_get_profile (priv->active_screen),
3901 GTK_WINDOW (window));
3902 }
3903
3904 static void
edit_profiles_callback(GtkAction * action,TerminalWindow * window)3905 edit_profiles_callback (GtkAction *action,
3906 TerminalWindow *window)
3907 {
3908 terminal_app_manage_profiles (terminal_app_get (),
3909 GTK_WINDOW (window));
3910 }
3911
3912 static void
view_menubar_toggled_callback(GtkToggleAction * action,TerminalWindow * window)3913 view_menubar_toggled_callback (GtkToggleAction *action,
3914 TerminalWindow *window)
3915 {
3916 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
3917 terminal_window_set_menubar_visible (window, gtk_toggle_action_get_active (action));
3918 G_GNUC_END_IGNORE_DEPRECATIONS;
3919 }
3920
3921 static void
view_fullscreen_toggled_callback(GtkToggleAction * action,TerminalWindow * window)3922 view_fullscreen_toggled_callback (GtkToggleAction *action,
3923 TerminalWindow *window)
3924 {
3925 gboolean toggle_action_check;
3926
3927 g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (window)));
3928
3929 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
3930 toggle_action_check = gtk_toggle_action_get_active (action);
3931 G_GNUC_END_IGNORE_DEPRECATIONS;
3932 if (toggle_action_check)
3933 gtk_window_fullscreen (GTK_WINDOW (window));
3934 else
3935 gtk_window_unfullscreen (GTK_WINDOW (window));
3936 }
3937
3938 static const double zoom_factors[] =
3939 {
3940 TERMINAL_SCALE_MINIMUM,
3941 TERMINAL_SCALE_XXXXX_SMALL,
3942 TERMINAL_SCALE_XXXX_SMALL,
3943 TERMINAL_SCALE_XXX_SMALL,
3944 PANGO_SCALE_XX_SMALL,
3945 PANGO_SCALE_X_SMALL,
3946 PANGO_SCALE_SMALL,
3947 PANGO_SCALE_MEDIUM,
3948 PANGO_SCALE_LARGE,
3949 PANGO_SCALE_X_LARGE,
3950 PANGO_SCALE_XX_LARGE,
3951 TERMINAL_SCALE_XXX_LARGE,
3952 TERMINAL_SCALE_XXXX_LARGE,
3953 TERMINAL_SCALE_XXXXX_LARGE,
3954 TERMINAL_SCALE_MAXIMUM
3955 };
3956
3957 static gboolean
find_larger_zoom_factor(double current,double * found)3958 find_larger_zoom_factor (double current,
3959 double *found)
3960 {
3961 guint i;
3962
3963 for (i = 0; i < G_N_ELEMENTS (zoom_factors); ++i)
3964 {
3965 /* Find a font that's larger than this one */
3966 if ((zoom_factors[i] - current) > 1e-6)
3967 {
3968 *found = zoom_factors[i];
3969 return TRUE;
3970 }
3971 }
3972
3973 return FALSE;
3974 }
3975
3976 static gboolean
find_smaller_zoom_factor(double current,double * found)3977 find_smaller_zoom_factor (double current,
3978 double *found)
3979 {
3980 int i;
3981
3982 i = (int) G_N_ELEMENTS (zoom_factors) - 1;
3983 while (i >= 0)
3984 {
3985 /* Find a font that's smaller than this one */
3986 if ((current - zoom_factors[i]) > 1e-6)
3987 {
3988 *found = zoom_factors[i];
3989 return TRUE;
3990 }
3991
3992 --i;
3993 }
3994
3995 return FALSE;
3996 }
3997
3998 static void
view_zoom_in_callback(GtkAction * action,TerminalWindow * window)3999 view_zoom_in_callback (GtkAction *action,
4000 TerminalWindow *window)
4001 {
4002 TerminalWindowPrivate *priv = window->priv;
4003 double current;
4004
4005 if (priv->active_screen == NULL)
4006 return;
4007
4008 current = terminal_screen_get_font_scale (priv->active_screen);
4009 if (!find_larger_zoom_factor (current, ¤t))
4010 return;
4011
4012 terminal_screen_set_font_scale (priv->active_screen, current);
4013 terminal_window_update_zoom_sensitivity (window);
4014 }
4015
4016 static void
view_zoom_out_callback(GtkAction * action,TerminalWindow * window)4017 view_zoom_out_callback (GtkAction *action,
4018 TerminalWindow *window)
4019 {
4020 TerminalWindowPrivate *priv = window->priv;
4021 double current;
4022
4023 if (priv->active_screen == NULL)
4024 return;
4025
4026 current = terminal_screen_get_font_scale (priv->active_screen);
4027 if (!find_smaller_zoom_factor (current, ¤t))
4028 return;
4029
4030 terminal_screen_set_font_scale (priv->active_screen, current);
4031 terminal_window_update_zoom_sensitivity (window);
4032 }
4033
4034 static void
view_zoom_normal_callback(GtkAction * action,TerminalWindow * window)4035 view_zoom_normal_callback (GtkAction *action,
4036 TerminalWindow *window)
4037 {
4038 TerminalWindowPrivate *priv = window->priv;
4039
4040 if (priv->active_screen == NULL)
4041 return;
4042
4043 terminal_screen_set_font_scale (priv->active_screen, PANGO_SCALE_MEDIUM);
4044 terminal_window_update_zoom_sensitivity (window);
4045 }
4046
4047
4048 static void
search_find_response_callback(GtkWidget * dialog,int response,gpointer user_data)4049 search_find_response_callback (GtkWidget *dialog,
4050 int response,
4051 gpointer user_data)
4052 {
4053 TerminalWindow *window = TERMINAL_WINDOW (user_data);
4054 TerminalWindowPrivate *priv = window->priv;
4055 TerminalSearchFlags flags;
4056 VteRegex *regex;
4057
4058 if (response != GTK_RESPONSE_ACCEPT)
4059 return;
4060
4061 if (G_UNLIKELY (!priv->active_screen))
4062 return;
4063
4064 regex = terminal_search_dialog_get_regex (dialog);
4065 g_return_if_fail (regex != NULL);
4066
4067 flags = terminal_search_dialog_get_search_flags (dialog);
4068
4069 vte_terminal_search_set_regex (VTE_TERMINAL (priv->active_screen), regex, 0);
4070 vte_terminal_search_set_wrap_around (VTE_TERMINAL (priv->active_screen),
4071 (flags & TERMINAL_SEARCH_FLAG_WRAP_AROUND));
4072
4073 if (flags & TERMINAL_SEARCH_FLAG_BACKWARDS)
4074 vte_terminal_search_find_previous (VTE_TERMINAL (priv->active_screen));
4075 else
4076 vte_terminal_search_find_next (VTE_TERMINAL (priv->active_screen));
4077
4078 terminal_window_update_search_sensitivity (priv->active_screen, window);
4079 }
4080
4081 static gboolean
search_dialog_delete_event_cb(GtkWidget * widget,GdkEventAny * event,gpointer user_data)4082 search_dialog_delete_event_cb (GtkWidget *widget,
4083 GdkEventAny *event,
4084 gpointer user_data)
4085 {
4086 /* prevent destruction */
4087 return TRUE;
4088 }
4089
4090 static void
search_find_callback(GtkAction * action,TerminalWindow * window)4091 search_find_callback (GtkAction *action,
4092 TerminalWindow *window)
4093 {
4094 TerminalWindowPrivate *priv = window->priv;
4095
4096 if (!priv->search_find_dialog)
4097 {
4098 GtkWidget *dialog;
4099
4100 dialog = priv->search_find_dialog = terminal_search_dialog_new (GTK_WINDOW (window));
4101
4102 g_signal_connect (dialog, "destroy",
4103 G_CALLBACK (gtk_widget_destroyed), &priv->search_find_dialog);
4104 g_signal_connect (dialog, "response",
4105 G_CALLBACK (search_find_response_callback), window);
4106 g_signal_connect (dialog, "delete-event",
4107 G_CALLBACK (search_dialog_delete_event_cb), NULL);
4108 }
4109
4110 terminal_search_dialog_present (priv->search_find_dialog);
4111 }
4112
4113 static void
search_find_next_callback(GtkAction * action,TerminalWindow * window)4114 search_find_next_callback (GtkAction *action,
4115 TerminalWindow *window)
4116 {
4117 if (G_UNLIKELY (!window->priv->active_screen))
4118 return;
4119
4120 vte_terminal_search_find_next (VTE_TERMINAL (window->priv->active_screen));
4121 }
4122
4123 static void
search_find_prev_callback(GtkAction * action,TerminalWindow * window)4124 search_find_prev_callback (GtkAction *action,
4125 TerminalWindow *window)
4126 {
4127 if (G_UNLIKELY (!window->priv->active_screen))
4128 return;
4129
4130 vte_terminal_search_find_previous (VTE_TERMINAL (window->priv->active_screen));
4131 }
4132
4133 static void
search_clear_highlight_callback(GtkAction * action,TerminalWindow * window)4134 search_clear_highlight_callback (GtkAction *action,
4135 TerminalWindow *window)
4136 {
4137 if (G_UNLIKELY (!window->priv->active_screen))
4138 return;
4139
4140 vte_terminal_search_set_regex (VTE_TERMINAL (window->priv->active_screen), NULL, 0);
4141 }
4142
4143 static void
terminal_next_or_previous_profile_cb(GtkAction * action,TerminalWindow * window)4144 terminal_next_or_previous_profile_cb (GtkAction *action,
4145 TerminalWindow *window)
4146 {
4147 TerminalWindowPrivate *priv = window->priv;
4148 TerminalProfile *active_profile, *new_profile = NULL;
4149 GList *profiles, *p;
4150
4151 const char *name;
4152 guint backwards = 0;
4153
4154 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
4155 name = gtk_action_get_name (action);
4156 G_GNUC_END_IGNORE_DEPRECATIONS;
4157 if (strcmp (name, "ProfilePrevious") == 0)
4158 {
4159 backwards = 1;
4160 }
4161
4162 profiles = terminal_app_get_profile_list (terminal_app_get ());
4163 if (profiles == NULL)
4164 return;
4165
4166 if (priv->active_screen)
4167 active_profile = terminal_screen_get_profile (priv->active_screen);
4168 else
4169 return;
4170
4171 for (p = profiles; p != NULL; p = p->next)
4172 {
4173 TerminalProfile *profile = (TerminalProfile *) p->data;
4174 if (profile == active_profile)
4175 {
4176 if (backwards) {
4177 p = p->prev;
4178 if (p == NULL)
4179 p = g_list_last (profiles);
4180 new_profile = p->data;
4181 break;
4182 }
4183 else
4184 {
4185 p = p->next;
4186 if (p == NULL)
4187 p = g_list_first (profiles);
4188 new_profile = p->data;
4189 break;
4190 }
4191 }
4192 }
4193
4194 if (new_profile)
4195 terminal_screen_set_profile (priv->active_screen, new_profile);
4196
4197 g_list_free (profiles);
4198 }
4199
4200 static void
terminal_set_title_dialog_response_cb(GtkWidget * dialog,int response,TerminalScreen * screen)4201 terminal_set_title_dialog_response_cb (GtkWidget *dialog,
4202 int response,
4203 TerminalScreen *screen)
4204 {
4205 if (response == GTK_RESPONSE_OK)
4206 {
4207 GtkEntry *entry;
4208 const char *text;
4209
4210 entry = GTK_ENTRY (g_object_get_data (G_OBJECT (dialog), "title-entry"));
4211 text = gtk_entry_get_text (entry);
4212 terminal_screen_set_user_title (screen, text);
4213 }
4214
4215 gtk_widget_destroy (dialog);
4216 }
4217
4218 static void
terminal_set_title_callback(GtkAction * action,TerminalWindow * window)4219 terminal_set_title_callback (GtkAction *action,
4220 TerminalWindow *window)
4221 {
4222 GtkBuilder *builder;
4223 TerminalWindowPrivate *priv = window->priv;
4224 GtkWidget *dialog, *entry;
4225
4226 if (priv->active_screen == NULL)
4227 return;
4228
4229 builder = gtk_builder_new_from_resource (TERMINAL_RESOURCES_PATH_PREFIX G_DIR_SEPARATOR_S "ui/set-title-dialog.ui");
4230 dialog = GTK_WIDGET (gtk_builder_get_object (builder, "dialog"));
4231 entry = GTK_WIDGET (gtk_builder_get_object (builder, "title_entry"));
4232 g_object_unref (builder);
4233
4234 gtk_widget_grab_focus (entry);
4235 gtk_entry_set_text (GTK_ENTRY (entry), terminal_screen_get_raw_title (priv->active_screen));
4236 gtk_editable_select_region (GTK_EDITABLE (entry), 0, -1);
4237 g_object_set_data (G_OBJECT (dialog), "title-entry", entry);
4238
4239 g_signal_connect (dialog, "response",
4240 G_CALLBACK (terminal_set_title_dialog_response_cb), priv->active_screen);
4241 g_signal_connect (dialog, "delete-event",
4242 G_CALLBACK (terminal_util_dialog_response_on_delete), NULL);
4243
4244 gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (window));
4245
4246 gtk_window_present (GTK_WINDOW (dialog));
4247 }
4248
4249 static void
terminal_add_encoding_callback(GtkAction * action,TerminalWindow * window)4250 terminal_add_encoding_callback (GtkAction *action,
4251 TerminalWindow *window)
4252 {
4253 terminal_app_edit_encodings (terminal_app_get (),
4254 GTK_WINDOW (window));
4255 }
4256
4257 static void
terminal_reset_callback(GtkAction * action,TerminalWindow * window)4258 terminal_reset_callback (GtkAction *action,
4259 TerminalWindow *window)
4260 {
4261 TerminalWindowPrivate *priv = window->priv;
4262
4263 if (priv->active_screen == NULL)
4264 return;
4265
4266 vte_terminal_reset (VTE_TERMINAL (priv->active_screen), TRUE, FALSE);
4267 }
4268
4269 static void
terminal_reset_clear_callback(GtkAction * action,TerminalWindow * window)4270 terminal_reset_clear_callback (GtkAction *action,
4271 TerminalWindow *window)
4272 {
4273 TerminalWindowPrivate *priv = window->priv;
4274
4275 if (priv->active_screen == NULL)
4276 return;
4277
4278 vte_terminal_reset (VTE_TERMINAL (priv->active_screen), TRUE, TRUE);
4279 }
4280
4281 static void
tabs_next_or_previous_tab_cb(GtkAction * action,TerminalWindow * window)4282 tabs_next_or_previous_tab_cb (GtkAction *action,
4283 TerminalWindow *window)
4284 {
4285 TerminalWindowPrivate *priv = window->priv;
4286 GtkNotebookClass *klass;
4287 const char *name;
4288 guint keyval = 0;
4289
4290 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
4291 name = gtk_action_get_name (action);
4292 G_GNUC_END_IGNORE_DEPRECATIONS;
4293 if (strcmp (name, "TabsNext") == 0)
4294 {
4295 keyval = GDK_KEY_Page_Down;
4296 }
4297 else if (strcmp (name, "TabsPrevious") == 0)
4298 {
4299 keyval = GDK_KEY_Page_Up;
4300 }
4301
4302 klass = GTK_NOTEBOOK_GET_CLASS (GTK_NOTEBOOK (priv->notebook));
4303 gtk_binding_set_activate (gtk_binding_set_by_class (klass),
4304 keyval,
4305 GDK_CONTROL_MASK,
4306 G_OBJECT (priv->notebook));
4307 }
4308
4309 static void
tabs_move_left_callback(GtkAction * action,TerminalWindow * window)4310 tabs_move_left_callback (GtkAction *action,
4311 TerminalWindow *window)
4312 {
4313 TerminalWindowPrivate *priv = window->priv;
4314 GtkNotebook *notebook = GTK_NOTEBOOK (priv->notebook);
4315 gint page_num,last_page;
4316 GtkWidget *page;
4317
4318 page_num = gtk_notebook_get_current_page (notebook);
4319 last_page = gtk_notebook_get_n_pages (notebook) - 1;
4320 page = gtk_notebook_get_nth_page (notebook, page_num);
4321
4322 gtk_notebook_reorder_child (notebook, page, page_num == 0 ? last_page : page_num - 1);
4323 }
4324
4325 static void
tabs_move_right_callback(GtkAction * action,TerminalWindow * window)4326 tabs_move_right_callback (GtkAction *action,
4327 TerminalWindow *window)
4328 {
4329 TerminalWindowPrivate *priv = window->priv;
4330 GtkNotebook *notebook = GTK_NOTEBOOK (priv->notebook);
4331 gint page_num,last_page;
4332 GtkWidget *page;
4333
4334 page_num = gtk_notebook_get_current_page (notebook);
4335 last_page = gtk_notebook_get_n_pages (notebook) - 1;
4336 page = gtk_notebook_get_nth_page (notebook, page_num);
4337
4338 gtk_notebook_reorder_child (notebook, page, page_num == last_page ? 0 : page_num + 1);
4339 }
4340
4341 static void
tabs_detach_tab_callback(GtkAction * action,TerminalWindow * window)4342 tabs_detach_tab_callback (GtkAction *action,
4343 TerminalWindow *window)
4344 {
4345 TerminalWindowPrivate *priv = window->priv;
4346 TerminalApp *app;
4347 TerminalWindow *new_window;
4348 TerminalScreen *screen;
4349
4350 app = terminal_app_get ();
4351
4352 screen = priv->active_screen;
4353
4354 new_window = terminal_app_new_window (app, gtk_widget_get_screen (GTK_WIDGET (window)));
4355
4356 terminal_window_move_screen (window, new_window, screen, -1);
4357
4358 /* FIXME: this seems wrong if tabs are shown in the window */
4359 terminal_window_update_size (new_window, screen, FALSE);
4360
4361 gtk_window_present_with_time (GTK_WINDOW (new_window), gtk_get_current_event_time ());
4362 }
4363
4364 static void
help_contents_callback(GtkAction * action,TerminalWindow * window)4365 help_contents_callback (GtkAction *action,
4366 TerminalWindow *window)
4367 {
4368 terminal_util_show_help (NULL, GTK_WINDOW (window));
4369 }
4370
4371 #define ABOUT_GROUP "About"
4372 #define EMAILIFY(string) (g_strdelimit ((string), "%", '@'))
4373
4374 static void
help_about_callback(GtkAction * action,TerminalWindow * window)4375 help_about_callback (GtkAction *action,
4376 TerminalWindow *window)
4377 {
4378 char *licence_text;
4379 GBytes *bytes;
4380 const guint8 *data;
4381 GKeyFile *key_file;
4382 GError *error = NULL;
4383 char **authors, **contributors, **artists, **documenters, **array_strv;
4384 gchar *comments = NULL;
4385 gsize data_len, n_authors = 0, n_contributors = 0, n_artists = 0, n_documenters = 0 , i;
4386 GPtrArray *array;
4387
4388
4389 bytes = g_resources_lookup_data (TERMINAL_RESOURCES_PATH_PREFIX G_DIR_SEPARATOR_S "ui/terminal.about",
4390 G_RESOURCE_LOOKUP_FLAGS_NONE,
4391 &error);
4392 g_assert_no_error (error);
4393
4394 data = g_bytes_get_data (bytes, &data_len);
4395 key_file = g_key_file_new ();
4396 g_key_file_load_from_data (key_file, (const char *) data, data_len, 0, &error);
4397 g_assert_no_error (error);
4398
4399 authors = g_key_file_get_string_list (key_file, ABOUT_GROUP, "Authors", &n_authors, NULL);
4400 contributors = g_key_file_get_string_list (key_file, ABOUT_GROUP, "Contributors", &n_contributors, NULL);
4401 artists = g_key_file_get_string_list (key_file, ABOUT_GROUP, "Artists", &n_artists, NULL);
4402 documenters = g_key_file_get_string_list (key_file, ABOUT_GROUP, "Documenters", &n_documenters, NULL);
4403 g_key_file_free (key_file);
4404 g_bytes_unref (bytes);
4405
4406 array = g_ptr_array_new ();
4407
4408 for (i = 0; i < n_authors; ++i)
4409 g_ptr_array_add (array, EMAILIFY (authors[i]));
4410 g_free (authors); /* strings are now owned by the array */
4411
4412 if (n_contributors > 0)
4413 {
4414 g_ptr_array_add (array, g_strdup (""));
4415 g_ptr_array_add (array, g_strdup (_("Contributors:")));
4416 for (i = 0; i < n_contributors; ++i)
4417 g_ptr_array_add (array, EMAILIFY (contributors[i]));
4418 }
4419 g_free (contributors); /* strings are now owned by the array */
4420
4421 g_ptr_array_add (array, NULL);
4422 array_strv = (char **) g_ptr_array_free (array, FALSE);
4423
4424 for (i = 0; i < n_artists; ++i)
4425 artists[i] = EMAILIFY (artists[i]);
4426 for (i = 0; i < n_documenters; ++i)
4427 documenters[i] = EMAILIFY (documenters[i]);
4428
4429 licence_text = terminal_util_get_licence_text ();
4430
4431 comments = g_strdup_printf (_("MATE Terminal is a terminal emulator for the MATE Desktop Environment.\nPowered by Virtual TErminal %d.%d.%d"),
4432 vte_get_major_version (), vte_get_minor_version (), vte_get_micro_version ());
4433
4434 gtk_show_about_dialog (GTK_WINDOW (window),
4435 "program-name", _("MATE Terminal"),
4436 "version", VERSION,
4437 "title", _("About MATE Terminal"),
4438 "copyright", _("Copyright \xc2\xa9 2002–2004 Havoc Pennington\n"
4439 "Copyright \xc2\xa9 2003–2004, 2007 Mariano Suárez-Alvarez\n"
4440 "Copyright \xc2\xa9 2006 Guilherme de S. Pastore\n"
4441 "Copyright \xc2\xa9 2007–2010 Christian Persch\n"
4442 "Copyright \xc2\xa9 2011 Perberos\n"
4443 "Copyright \xc2\xa9 2012-2021 MATE developers"),
4444 "comments", comments,
4445 "authors", array_strv,
4446 "artists", artists,
4447 "documenters", documenters,
4448 "license", licence_text,
4449 "wrap-license", TRUE,
4450 "translator-credits", _("translator-credits"),
4451 "logo-icon-name", MATE_TERMINAL_ICON_NAME,
4452 "website", PACKAGE_URL,
4453 NULL);
4454
4455 g_free (comments);
4456 g_strfreev (array_strv);
4457 g_strfreev (artists);
4458 g_strfreev (documenters);
4459 g_free (licence_text);
4460 }
4461
4462 GtkUIManager *
terminal_window_get_ui_manager(TerminalWindow * window)4463 terminal_window_get_ui_manager (TerminalWindow *window)
4464 {
4465 TerminalWindowPrivate *priv = window->priv;
4466
4467 return priv->ui_manager;
4468 }
4469
4470 void
terminal_window_save_state(TerminalWindow * window,GKeyFile * key_file,const char * group)4471 terminal_window_save_state (TerminalWindow *window,
4472 GKeyFile *key_file,
4473 const char *group)
4474 {
4475 TerminalWindowPrivate *priv = window->priv;
4476 GList *tabs, *lt;
4477 TerminalScreen *active_screen;
4478 GdkWindowState state;
4479 GPtrArray *tab_names_array;
4480 char **tab_names;
4481 gsize len;
4482
4483 //XXXif (priv->menub)//XXX
4484 g_key_file_set_boolean (key_file, group, TERMINAL_CONFIG_WINDOW_PROP_MENUBAR_VISIBLE,
4485 priv->menubar_visible);
4486
4487 g_key_file_set_string (key_file, group, TERMINAL_CONFIG_WINDOW_PROP_ROLE,
4488 gtk_window_get_role (GTK_WINDOW (window)));
4489
4490 state = gdk_window_get_state (gtk_widget_get_window (GTK_WIDGET (window)));
4491 if (state & GDK_WINDOW_STATE_MAXIMIZED)
4492 g_key_file_set_boolean (key_file, group, TERMINAL_CONFIG_WINDOW_PROP_MAXIMIZED, TRUE);
4493 if (state & GDK_WINDOW_STATE_FULLSCREEN)
4494 g_key_file_set_boolean (key_file, group, TERMINAL_CONFIG_WINDOW_PROP_FULLSCREEN, TRUE);
4495
4496 active_screen = terminal_window_get_active (window);
4497 tabs = terminal_window_list_screen_containers (window);
4498
4499 tab_names_array = g_ptr_array_sized_new (g_list_length (tabs) + 1);
4500
4501 for (lt = tabs; lt != NULL; lt = lt->next)
4502 {
4503 TerminalScreen *screen;
4504 char *tab_group;
4505
4506 screen = terminal_screen_container_get_screen (TERMINAL_SCREEN_CONTAINER (lt->data));
4507
4508 tab_group = g_strdup_printf ("Terminal%p", screen);
4509 g_ptr_array_add (tab_names_array, tab_group);
4510
4511 terminal_screen_save_config (screen, key_file, tab_group);
4512
4513 if (screen == active_screen)
4514 {
4515 int w, h, x, y;
4516 char *geometry;
4517
4518 g_key_file_set_string (key_file, group, TERMINAL_CONFIG_WINDOW_PROP_ACTIVE_TAB, tab_group);
4519
4520 /* FIXME saving the geometry is not great :-/ */
4521 terminal_screen_get_size (screen, &w, &h);
4522 gtk_window_get_position (GTK_WINDOW (window), &x, &y);
4523 geometry = g_strdup_printf ("%dx%d+%d+%d", w, h, x, y);
4524 g_key_file_set_string (key_file, group, TERMINAL_CONFIG_WINDOW_PROP_GEOMETRY, geometry);
4525 g_free (geometry);
4526 }
4527 }
4528
4529 g_list_free (tabs);
4530
4531 len = tab_names_array->len;
4532 g_ptr_array_add (tab_names_array, NULL);
4533 tab_names = (char **) g_ptr_array_free (tab_names_array, FALSE);
4534 g_key_file_set_string_list (key_file, group, TERMINAL_CONFIG_WINDOW_PROP_TABS, (const char * const *) tab_names, len);
4535 g_strfreev (tab_names);
4536 }
4537
4538
4539 TerminalWindow *
terminal_window_get_latest_focused(TerminalWindow * window1,TerminalWindow * window2)4540 terminal_window_get_latest_focused (TerminalWindow *window1,
4541 TerminalWindow *window2)
4542 {
4543 TerminalWindowPrivate *priv1 = NULL;
4544 TerminalWindowPrivate *priv2 = NULL;
4545
4546 if (!window1)
4547 return window2;
4548
4549 if (!window2)
4550 return window1;
4551
4552 priv1 = window1->priv;
4553 priv2 = window2->priv;
4554
4555 if (priv2->focus_time > priv1->focus_time)
4556 return window2;
4557
4558 return window1;
4559 }
4560