diff options
author | Marc-André Lureau <marcandre.lureau@redhat.com> | 2011-03-17 15:11:42 +0100 |
---|---|---|
committer | Marc-André Lureau <marcandre.lureau@redhat.com> | 2011-03-17 15:11:42 +0100 |
commit | ce03127a4cda764ee397692ec0137131a6531af3 (patch) | |
tree | 010e566c2dc95992353937544077329a56366aee | |
parent | 7a98604aa0f09009b9a26f7b7681ebe63fe9d2fe (diff) |
spicy: change current output resolution in fullscreen
-rw-r--r-- | gtk/spicy.c | 281 |
1 files changed, 238 insertions, 43 deletions
diff --git a/gtk/spicy.c b/gtk/spicy.c index d1423cc..175cf40 100644 --- a/gtk/spicy.c +++ b/gtk/spicy.c @@ -59,7 +59,7 @@ struct spice_window { GtkUIManager *ui; bool fullscreen; bool mouse_grabbed; - SpiceChannel *channel; + SpiceChannel *display_channel; }; struct spice_connection { @@ -68,15 +68,17 @@ struct spice_connection { SpiceAudio *audio; char *mouse_state; char *agent_state; + gboolean agent_connected; int channels; int disconnecting; }; -static GMainLoop *mainloop; -static int connections; -static GKeyFile *keyfile; -static GnomeRRScreen *rrscreen; -static GnomeRRConfig *rrsaved; +static GMainLoop *mainloop = NULL; +static int connections = 0; +static GKeyFile *keyfile = NULL; +static GnomeRRScreen *rrscreen = NULL; +static GnomeRRConfig *rrsaved = NULL; +static GnomeRRConfig *rrcurrent = NULL; static spice_connection *connection_new(void); static void connection_connect(spice_connection *conn); @@ -627,12 +629,182 @@ static void recent_item_activated_cb(GtkRecentChooser *chooser, gpointer data) connection_connect(conn); } -static void resolution_change(struct spice_window *win) +static GnomeRROutputInfo * +get_nearest_output (GnomeRRConfig *configuration, int x, int y) { + int i; + int nearest_index; + int nearest_dist; + GnomeRROutputInfo **outputs; + + nearest_index = -1; + nearest_dist = G_MAXINT; + + outputs = gnome_rr_config_get_outputs (configuration); + for (i = 0; outputs[i] != NULL; i++) + { + int dist_x, dist_y; + int output_x, output_y, output_width, output_height; + + if (!(gnome_rr_output_info_is_connected (outputs[i]) && gnome_rr_output_info_is_active (outputs[i]))) + continue; + + gnome_rr_output_info_get_geometry (outputs[i], &output_x, &output_y, &output_width, &output_height); + + if (x < output_x) + dist_x = output_x - x; + else if (x >= output_x + output_width) + dist_x = x - (output_x + output_width) + 1; + else + dist_x = 0; + + if (y < output_y) + dist_y = output_y - y; + else if (y >= output_y + output_height) + dist_y = y - (output_y + output_height) + 1; + else + dist_y = 0; + + if (MIN (dist_x, dist_y) < nearest_dist) + { + nearest_dist = MIN (dist_x, dist_y); + nearest_index = i; + } + } + + if (nearest_index != -1) + return outputs[nearest_index]; + else + return NULL; +} + +#if !GTK_CHECK_VERSION (2, 91, 0) +#define gdk_window_get_geometry(win,x,y,w,h) gdk_window_get_geometry(win,x,y,w,h,NULL) +#endif + +static GnomeRROutputInfo * +get_output_for_window(GnomeRRConfig *configuration, GdkWindow *window) +{ + GdkRectangle win_rect; + int i; + int largest_area; + int largest_index; + GnomeRROutputInfo **outputs; + + gdk_window_get_geometry (window, &win_rect.x, &win_rect.y, &win_rect.width, &win_rect.height); + gdk_window_get_origin (window, &win_rect.x, &win_rect.y); + + largest_area = 0; + largest_index = -1; + + outputs = gnome_rr_config_get_outputs (configuration); + for (i = 0; outputs[i] != NULL; i++) + { + GdkRectangle output_rect, intersection; + + gnome_rr_output_info_get_geometry (outputs[i], &output_rect.x, &output_rect.y, &output_rect.width, &output_rect.height); + + if (gnome_rr_output_info_is_connected (outputs[i]) && gdk_rectangle_intersect (&win_rect, &output_rect, &intersection)) + { + int area; + + area = intersection.width * intersection.height; + if (area > largest_area) + { + largest_area = area; + largest_index = i; + } + } + } + + if (largest_index != -1) + return outputs[largest_index]; + else + return get_nearest_output (configuration, + win_rect.x + win_rect.width / 2, + win_rect.y + win_rect.height / 2); +} + +#if 0 +static GnomeRROutputInfo *get_primary_output() { + GnomeRROutputInfo **outputs; + GnomeRROutputInfo *output; + guint i; + + outputs = gnome_rr_config_get_outputs (rrcurrent); + for (i = 0; outputs[i] != NULL; ++i) { + output = outputs[i]; + if (!gnome_rr_output_info_is_connected (output)) + continue; + if (gnome_rr_output_info_get_primary (output)) + break; + } + output = outputs[i]; + g_return_if_fail(output != NULL); + return output; +} +#endif + +static void +on_screen_changed(GnomeRRScreen *scr, gpointer data) +{ + GError *error = NULL; + GnomeRRConfig *current; + + current = gnome_rr_config_new_current(rrscreen, &error); + if (!current) { + g_warning("Can't get current display config: %s", error->message); + goto end; + } + + if (rrcurrent) + g_object_unref(rrcurrent); + rrcurrent = current; + +end: + g_clear_error(&error); +} + +static void resolution_fullscreen(struct spice_window *win) +{ + GnomeRROutputInfo *output; + int x, y, width, height; + GError *error = NULL;; + + if (!rrsaved) { + rrsaved = gnome_rr_config_new_current(rrscreen, &error); + g_clear_error(&error); + } + + output = get_output_for_window(rrcurrent, gtk_widget_get_window(win->spice)); + g_return_if_fail(output != NULL); + + gnome_rr_output_info_get_geometry (output, &x, &y, &width, &height); + g_object_get(win->display_channel, "width", &width, "height", &height, NULL); + gnome_rr_output_info_set_geometry (output, x, y, width, height); + + if (!gnome_rr_config_apply_with_time(rrcurrent, rrscreen, + gtk_get_current_event_time (), &error)) { + g_warning("Can't set display config: %s", error->message); + } + g_clear_error(&error); } -static void resolution_restore(struct spice_window *win) +static void resolution_restore(void) { + GError *error = NULL;; + + if (!rrsaved) + return; + + if (!gnome_rr_config_apply_with_time(rrsaved, rrscreen, + gtk_get_current_event_time (), &error)) { + g_warning("Can't restore display config: %s", error->message); + } + g_clear_error(&error); + + g_object_unref(rrsaved); + rrsaved = NULL; } static gboolean configure_event_cb(GtkWidget *widget, @@ -641,19 +813,18 @@ static gboolean configure_event_cb(GtkWidget *widget, { gboolean resize_guest; struct spice_window *win = data; - guint w, h; + + g_return_val_if_fail(win != NULL, FALSE); + g_return_val_if_fail(win->conn != NULL, FALSE); g_object_get(win->spice, "resize-guest", &resize_guest, NULL); - if (resize_guest) + if (resize_guest && win->conn->agent_connected) return FALSE; - g_object_get(win->channel, "width", &w, "height", &h, NULL); - g_message("test: %d %d win %d %d %d", w, h, event->width, event->height, win->fullscreen); - if (win->fullscreen) { - resolution_change(win); - } else { - resolution_restore(win); - } + if (win->fullscreen) + resolution_fullscreen(win); + else + resolution_restore(); return FALSE; } @@ -676,7 +847,7 @@ static spice_window *create_spice_window(spice_connection *conn, int id, SpiceCh memset(win,0,sizeof(*win)); win->id = id; win->conn = conn; - win->channel = channel; + win->display_channel = channel; g_message("create window (#%d)", win->id); /* toplevel */ @@ -900,10 +1071,9 @@ static void main_mouse_update(SpiceChannel *channel, gpointer data) static void main_agent_update(SpiceChannel *channel, gpointer data) { spice_connection *conn = data; - gboolean agent_connected; - g_object_get(channel, "agent-connected", &agent_connected, NULL); - conn->agent_state = agent_connected ? _("yes") : _("no"); + g_object_get(channel, "agent-connected", &conn->agent_connected, NULL); + conn->agent_state = conn->agent_connected ? _("yes") : _("no"); update_status(conn->wins[0]); } @@ -1055,28 +1225,6 @@ static void connection_destroy(spice_connection *conn) g_main_loop_quit(mainloop); } -static void -on_screen_changed(GnomeRRScreen *scr, gpointer data) -{ - GError *error = NULL; - - rrsaved = gnome_rr_config_new_current(rrscreen, &error); - if (!rrsaved) { - g_warning("Can't get current display config: %s", error->message); - goto end; - } - g_clear_error(&error); - - if (!gnome_rr_config_apply_with_time(rrsaved, rrscreen, - gtk_get_current_event_time (), &error)) { - g_warning("Can't restore display config: %s", error->message); - } - g_clear_error(&error); - -end: - g_clear_error(&error); -} - /* ------------------------------------------------------------------ */ static GOptionEntry cmd_entries[] = { @@ -1098,6 +1246,40 @@ static GOptionEntry cmd_entries[] = { } }; +static void (* segv_handler) (int) = SIG_DFL; +static void (* abrt_handler) (int) = SIG_DFL; +static void (* fpe_handler) (int) = SIG_DFL; +static void (* ill_handler) (int) = SIG_DFL; +#ifndef WIN32 +static void (* bus_handler) (int) = SIG_DFL; +#endif + +static void +signal_handler(int signum) +{ + static gint recursion = FALSE; + + /* + * reset all signal handlers: any further crashes should just be allowed + * to crash normally. + * */ + signal(SIGSEGV, segv_handler); + signal(SIGABRT, abrt_handler); + signal(SIGFPE, fpe_handler); + signal(SIGILL, ill_handler); +#ifndef WIN32 + signal(SIGBUS, bus_handler); +#endif + + /* Stop bizarre loops */ + if (recursion) + abort (); + + recursion = TRUE; + + g_main_loop_quit(mainloop); +} + int main(int argc, char *argv[]) { GError *error = NULL; @@ -1110,6 +1292,17 @@ int main(int argc, char *argv[]) bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8"); textdomain(GETTEXT_PACKAGE); + signal(SIGINT, signal_handler); + signal(SIGTERM, signal_handler); + signal(SIGHUP, signal_handler); + segv_handler = signal(SIGSEGV, signal_handler); + abrt_handler = signal(SIGABRT, signal_handler); + fpe_handler = signal(SIGFPE, signal_handler); + ill_handler = signal(SIGILL, signal_handler); +#ifndef WIN32 + bus_handler = signal(SIGBUS, signal_handler); +#endif + keyfile = g_key_file_new(); int mode = S_IRWXU; @@ -1166,5 +1359,7 @@ int main(int argc, char *argv[]) g_free(conf_file); + resolution_restore(); + return 0; } |