From 790b7c50cbfa5b6892bd0aeef58f6acbe9c63118 Mon Sep 17 00:00:00 2001 From: John R Dietrick Date: Sun, 27 Sep 2015 16:09:15 +0800 Subject: [PATCH 1/3] Window: Simple keybinding for cycling monitor Notes / loose ends: * I went from an original approach of setting the relative x and y coordinates to (0, 0) after cycling to the next monitor, to instead preserving the relative x and y against the newly-selected display. In both cases not messing with the size. This might not be the *best* approach -- some other possibilities I can think of would be (1) a "proportional transposition", or (2) just setting the position and/or size to arbitrary, consistent values (like filling the entire workspace on the new monitor). I spend almost all my time in fullscreen mode, however, so I am neither affected by nor the best judge of this use case. * No effort is made to update the wizard UI if we cycle monitors while the wizard is open. (It looks like we aren't supposed to be able to trigger hotkeys while the wizard is open, but I was able to get it to work by changing focus.) This decicison is based on the precedent set by other hotkeys such as "enable fullscreen". * What would an integration with the wip/monitornames branch look like? Or, that branch, done right and completely, probably supersedes us. --- src/configsys.c | 1 + src/tilda_window.c | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/src/configsys.c b/src/configsys.c index 8214ac0c..674be24d 100644 --- a/src/configsys.c +++ b/src/configsys.c @@ -74,6 +74,7 @@ static cfg_opt_t config_opts[] = { CFG_STR("normalize_font_size_key", "0", CFGF_NONE), CFG_STR("show_on_monitor", "", CFGF_NONE), CFG_STR("word_chars", DEFAULT_WORD_CHARS, CFGF_NONE), + CFG_STR("cycle_monitor_key", "Right", CFGF_NONE), /* ints */ CFG_INT("lines", 5000, CFGF_NONE), diff --git a/src/tilda_window.c b/src/tilda_window.c index b6811674..5d773d36 100644 --- a/src/tilda_window.c +++ b/src/tilda_window.c @@ -312,6 +312,46 @@ static gboolean decrease_font_size (tilda_window *tw) return GDK_EVENT_STOP; } +gint cycle_monitor_cb (tilda_window *tw) +{ + DEBUG_FUNCTION("cycle_monitor_cb"); + DEBUG_ASSERT(tw != NULL); + + // Figure out what monitor we're on, and + // which monitor we're going to + GdkScreen* screen = gtk_window_get_screen(GTK_WINDOW(tw->window)); + int original_monitor = config_getint("show_on_monitor_number"); + int num_monitors = gdk_screen_get_n_monitors(screen); + int new_monitor = (original_monitor + 1) % num_monitors; + + // Calculate the workareas of the two + // monitors + GdkRectangle* rect = malloc(sizeof(GdkRectangle) * num_monitors); + for (int i = 0; i < num_monitors; i++) { + gdk_screen_get_monitor_workarea(screen, i, rect + i); + } + GdkRectangle *original_workarea = rect + original_monitor; + GdkRectangle *new_workarea = rect + new_monitor; + + // Keep the same relative position on + // the new monitor + int original_absolute_x = config_getint("x_pos"); + int original_absolute_y = config_getint("y_pos"); + int new_absolute_x = new_workarea->x + (original_absolute_x - original_workarea->x); + int new_absolute_y = new_workarea->y + (original_absolute_y - original_workarea->y); + + config_setint("show_on_monitor_number", new_monitor); + config_setint("x_pos", new_absolute_x); + config_setint("y_pos", new_absolute_y); + + // Make the change + gtk_window_move(GTK_WINDOW(tw->window), new_absolute_x, new_absolute_y); + generate_animation_positions(tw); + free(rect); + + return GDK_EVENT_STOP; +} + gint tilda_window_next_tab (tilda_window *tw) { DEBUG_FUNCTION ("next_tab"); @@ -674,6 +714,7 @@ static gint tilda_window_setup_keyboard_accelerators (tilda_window *tw) tilda_add_config_accelerator_by_path("quit_key", "/context/Quit", G_CALLBACK(gtk_main_quit), tw); tilda_add_config_accelerator_by_path("toggle_transparency_key", "/context/Toggle Transparency", G_CALLBACK(toggle_transparency_cb), tw); tilda_add_config_accelerator_by_path("toggle_searchbar_key", "/context/Toggle Searchbar", G_CALLBACK(tilda_window_toggle_searchbar), tw); + tilda_add_config_accelerator_by_path("cycle_monitor_key", "/context/Cycle Monitor", G_CALLBACK(cycle_monitor_cb), tw); tilda_add_config_accelerator_by_path("nexttab_key", "/context/Next Tab", G_CALLBACK(tilda_window_next_tab), tw); tilda_add_config_accelerator_by_path("prevtab_key", "/context/Previous Tab", G_CALLBACK(tilda_window_prev_tab), tw); From 088187b69e5ef5e04b54461093655428d13d0a62 Mon Sep 17 00:00:00 2001 From: John R Dietrick Date: Mon, 28 Sep 2015 15:35:28 +0800 Subject: [PATCH 2/3] Window: Logic for position disagreement Sometimes -- usually if a monitor is hotplugged or the multiple-monitor geometry is changed -- the prevailing (x_pos, y_pos) in the absolute coordinate space do not agree with show_on_monitor_number. We now add some additional logic to trust show_on_monitor_number above all; if the newly- calculated absolute (x, y) that we get from trying to retain relative position on our new monitor places the window outside the workarea of the destination monitor, we drop the hammer and set x and/or y to 0 as needed. This means, for example, if you have a Dell monitor on your left (as monitor 0) and an LG monitor on your right (as monitor 1), and have tilda on monitor 0 (the Dell), but then change your virtual monitor configuration such that the LG is to the left of the Dell, tilda will go from being on monitor 0 to monitor 1, but without updating its configuration values. And your absolute coordinates might be messed up, too. With this patch, next time you cycle the monitors, you'll land tilda on the Dell (where it already is!), but after that, things will operate normally. --- src/tilda_window.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/tilda_window.c b/src/tilda_window.c index 5d773d36..eb936dae 100644 --- a/src/tilda_window.c +++ b/src/tilda_window.c @@ -333,12 +333,23 @@ gint cycle_monitor_cb (tilda_window *tw) GdkRectangle *original_workarea = rect + original_monitor; GdkRectangle *new_workarea = rect + new_monitor; - // Keep the same relative position on - // the new monitor + // Try to keep the same relative position + // on the new monitor if possible, but + // sometimes the saved (x, y) absolutes + // are in disagreement with the selected + // monitor; in that case set x or y to 0 int original_absolute_x = config_getint("x_pos"); int original_absolute_y = config_getint("y_pos"); - int new_absolute_x = new_workarea->x + (original_absolute_x - original_workarea->x); - int new_absolute_y = new_workarea->y + (original_absolute_y - original_workarea->y); + int relative_x = original_absolute_x - original_workarea->x; + int relative_y = original_absolute_y - original_workarea->y; + if (relative_x < 0 || relative_x > new_workarea->width) { + relative_x = 0; + } + if (relative_y < 0 || relative_y > new_workarea->height) { + relative_y = 0; + } + int new_absolute_x = new_workarea->x + relative_x; + int new_absolute_y = new_workarea->y + relative_y; config_setint("show_on_monitor_number", new_monitor); config_setint("x_pos", new_absolute_x); From 72c8aedfca24324ea779e350c978d0fde2bc103d Mon Sep 17 00:00:00 2001 From: John R Dietrick Date: Thu, 8 Oct 2015 18:38:29 +0800 Subject: [PATCH 3/3] Wizard: Add cycle monitor accelerator --- src/tilda.ui | 37 +++++++++++++++++++++++++++++++++++++ src/wizard.c | 10 ++++++++++ 2 files changed, 47 insertions(+) diff --git a/src/tilda.ui b/src/tilda.ui index f70b6d24..6a0b2d45 100644 --- a/src/tilda.ui +++ b/src/tilda.ui @@ -3670,6 +3670,43 @@ 0 11 + 1 + 1 + + + + + True + False + 0 + + + True + False + 12 + + + + True + True + True + 2 + + + + + + + True + False + <b>Move To Next Monitor</b> + True + + + + + 1 + 11 diff --git a/src/wizard.c b/src/wizard.c index 81f7831e..50548dfd 100644 --- a/src/wizard.c +++ b/src/wizard.c @@ -387,6 +387,7 @@ static void wizard_close_dialog (tilda_window *tw) const gchar *fullscreen_key = GET_BUTTON_LABEL("button_keybinding_fullscreen"); const gchar *toggle_transparency_key = GET_BUTTON_LABEL("button_keybinding_toggle_transparency"); const gchar *toggle_searchbar_key = GET_BUTTON_LABEL("button_keybinding_toggle_searchbar"); + const gchar *cycle_monitor_key = GET_BUTTON_LABEL("button_keybinding_cycle_monitor"); const GtkWidget *entry_custom_command = GTK_WIDGET (gtk_builder_get_object(xml, "entry_custom_command")); @@ -444,6 +445,8 @@ static void wizard_close_dialog (tilda_window *tw) return; if (!validate_keybinding(toggle_searchbar_key, tw, _("The keybinding you chose for \"Toggle Search Bar\" is invalid. Please choose another."))) return; + if (!validate_keybinding(cycle_monitor_key, wizard_window, _("The keybinding you chose for \"Move To Next Monitor\" is invalid. Please choose another."))) + return; /* Now that our shortcuts are validated, store them back into the config. */ config_setstr ("key", key); @@ -469,6 +472,7 @@ static void wizard_close_dialog (tilda_window *tw) config_setstr ("fullscreen_key", fullscreen_key); config_setstr ("toggle_transparency_key", toggle_transparency_key); config_setstr ("toggle_searchbar_key", toggle_searchbar_key); + config_setstr ("cycle_monitor_key", cycle_monitor_key); /* Now that they're in the config, reset the keybindings right now. */ tilda_window_update_keyboard_accelerators("/context/New Tab", addtab_key); @@ -493,6 +497,7 @@ static void wizard_close_dialog (tilda_window *tw) tilda_window_update_keyboard_accelerators("/context/Toggle Fullscreen", fullscreen_key); tilda_window_update_keyboard_accelerators("/context/Toggle Transparency", toggle_transparency_key); tilda_window_update_keyboard_accelerators("/context/Toggle Searchbar", toggle_searchbar_key); + tilda_window_update_keyboard_accelerators("/context/Cycle Monitor", cycle_monitor_key); /* TODO: validate this?? */ @@ -2062,6 +2067,7 @@ static void button_keybinding_clicked_cb (GtkWidget *w, tilda_window *tw) const GtkWidget *button_keybinding_fullscreen = GTK_WIDGET (gtk_builder_get_object (xml, "button_keybinding_fullscreen")); const GtkWidget *button_keybinding_toggle_transparency = GTK_WIDGET (gtk_builder_get_object (xml, "button_keybinding_toggle_transparency")); const GtkWidget *button_keybinding_toggle_searchbar = GTK_WIDGET (gtk_builder_get_object (xml, "button_keybinding_toggle_searchbar")); + const GtkWidget *button_keybinding_cycle_monitor = GTK_WIDGET (gtk_builder_get_object (xml, "button_keybinding_cycle_monitor")); /* Make the preferences window and buttons non-sensitive while we are grabbing keys. */ gtk_widget_set_sensitive (GTK_WIDGET(wizard_notebook), FALSE); @@ -2089,6 +2095,7 @@ static void button_keybinding_clicked_cb (GtkWidget *w, tilda_window *tw) gtk_widget_set_sensitive (GTK_WIDGET(button_keybinding_fullscreen), FALSE); gtk_widget_set_sensitive (GTK_WIDGET(button_keybinding_toggle_transparency), FALSE); gtk_widget_set_sensitive (GTK_WIDGET(button_keybinding_toggle_searchbar), FALSE); + gtk_widget_set_sensitive (GTK_WIDGET(button_keybinding_cycle_monitor), FALSE); /* Bring up the dialog that will accept the new keybinding */ GtkWidget *dialog = gtk_message_dialog_new (GTK_WINDOW(wizard_window), @@ -2131,6 +2138,7 @@ static void button_keybinding_clicked_cb (GtkWidget *w, tilda_window *tw) gtk_widget_set_sensitive (GTK_WIDGET(button_keybinding_fullscreen), TRUE); gtk_widget_set_sensitive (GTK_WIDGET(button_keybinding_toggle_transparency), TRUE); gtk_widget_set_sensitive (GTK_WIDGET(button_keybinding_toggle_searchbar), TRUE); + gtk_widget_set_sensitive (GTK_WIDGET(button_keybinding_cycle_monitor), TRUE); /* If the dialog was "programmatically destroyed" (we got a key), we don't want to destroy it again. Otherwise, we do want to destroy it, otherwise it would stick around even after hitting Cancel. */ @@ -2383,6 +2391,7 @@ static void set_wizard_state_from_config (tilda_window *tw) { BUTTON_LABEL_FROM_CFG ("button_keybinding_fullscreen", "fullscreen_key"); BUTTON_LABEL_FROM_CFG ("button_keybinding_toggle_transparency", "toggle_transparency_key"); BUTTON_LABEL_FROM_CFG ("button_keybinding_toggle_searchbar", "toggle_searchbar_key"); + BUTTON_LABEL_FROM_CFG ("button_keybinding_cycle_monitor", "cycle_monitor_key"); } static void initialize_scrollback_settings(void) { @@ -2538,6 +2547,7 @@ static void connect_wizard_signals (tilda_window *tw) CONNECT_SIGNAL ("button_keybinding_fullscreen", "clicked", button_keybinding_clicked_cb, tw); CONNECT_SIGNAL ("button_keybinding_toggle_transparency", "clicked", button_keybinding_clicked_cb, tw); CONNECT_SIGNAL ("button_keybinding_toggle_searchbar", "clicked", button_keybinding_clicked_cb, tw); + CONNECT_SIGNAL ("button_keybinding_cycle_monitor", "clicked", button_keybinding_clicked_cb, tw); /* Close Button */ CONNECT_SIGNAL ("button_wizard_close","clicked", wizard_button_close_clicked_cb, tw);