From f4c882e3b5ea946f8d74b9cfcb36994e133c4718 Mon Sep 17 00:00:00 2001 From: Alexander Drozdov Date: Wed, 10 Jul 2019 19:24:52 +1000 Subject: [PATCH] Automatically open new Xed window on current workspace... (#319) ...if it wasn't already opened. Otherwise, open new tab in Xed window on current Workspace. Fix regression #318 --- docs/reference/xed-sections.txt | 2 + xed/xed-app.c | 85 ++++++++++++++- xed/xed-utils.c | 180 ++++++++++++++++++++++++++++++++ xed/xed-utils.h | 8 ++ 4 files changed, 274 insertions(+), 1 deletion(-) diff --git a/docs/reference/xed-sections.txt b/docs/reference/xed-sections.txt index 2d6d271..4339965 100644 --- a/docs/reference/xed-sections.txt +++ b/docs/reference/xed-sections.txt @@ -472,6 +472,8 @@ xed_warning xed_utils_make_valid_utf8 xed_utils_uri_get_dirname xed_utils_replace_home_dir_with_tilde +xed_utils_get_current_workspace +xed_utils_get_window_workspace xed_utils_activate_url xed_utils_is_valid_uri xed_utils_get_glade_widgets diff --git a/xed/xed-app.c b/xed/xed-app.c index b4c3691..62ffd3d 100644 --- a/xed/xed-app.c +++ b/xed/xed-app.c @@ -356,6 +356,89 @@ xed_app_startup (GApplication *application) app); } +static gboolean +is_in_viewport (GtkWindow *window, + GdkScreen *screen, + gint workspace, + gint viewport_x, + gint viewport_y) +{ + GdkScreen *s; + GdkDisplay *display; + GdkMonitor *monitor; + GdkWindow *gdkwindow; + GdkRectangle geometry; + const gchar *cur_name; + const gchar *name; + gint ws; + gint x, y, width, height; + + /* Check for screen and display match */ + display = gdk_screen_get_display (screen); + cur_name = gdk_display_get_name (display); + + s = gtk_window_get_screen (window); + display = gdk_screen_get_display (s); + name = gdk_display_get_name (display); + + if (strcmp (cur_name, name) != 0) + { + return FALSE; + } + + /* Check for workspace match */ + ws = xed_utils_get_window_workspace (window); + + if (ws != workspace && ws != XED_ALL_WORKSPACES) + { + return FALSE; + } + + /* Check for viewport match */ + gdkwindow = gtk_widget_get_window (GTK_WIDGET (window)); + gdk_window_get_position (gdkwindow, &x, &y); + width = gdk_window_get_width (gdkwindow); + height = gdk_window_get_height (gdkwindow); + x += viewport_x; + y += viewport_y; + + monitor = gdk_display_get_monitor_at_window(display, gdkwindow); + gdk_monitor_get_geometry(monitor, &geometry); + + return x + width * .75 >= geometry.x && + x + width * .25 <= geometry.x + geometry.width && + y + height * .75 >= geometry.y && + y + height * .25 <= geometry.y + geometry.height; +} + +static XedWindow * +get_active_window (GtkApplication *app) +{ + GdkScreen *screen; + guint workspace; + gint viewport_x, viewport_y; + GList *windows, *l; + + screen = gdk_screen_get_default (); + + workspace = xed_utils_get_current_workspace (screen); + xed_utils_get_current_viewport (screen, &viewport_x, &viewport_y); + + /* Gtk documentation says the window list is always in MRU order */ + windows = gtk_application_get_windows (app); + for (l = windows; l != NULL; l = l->next) + { + GtkWindow *window = l->data; + + if (XED_IS_WINDOW (window) && is_in_viewport (window, screen, workspace, viewport_x, viewport_y)) + { + return XED_WINDOW (window); + } + } + + return NULL; +} + static void set_command_line_wait (XedApp *app, XedTab *tab) @@ -392,7 +475,7 @@ open_files (GApplication *application, if (!new_window) { - window = XED_WINDOW (gtk_application_get_active_window (GTK_APPLICATION (application))); + window = get_active_window (GTK_APPLICATION (application)); } if (window == NULL) diff --git a/xed/xed-utils.c b/xed/xed-utils.c index 1cad43b..a0dba50 100644 --- a/xed/xed-utils.c +++ b/xed/xed-utils.c @@ -414,6 +414,186 @@ xed_utils_uri_get_dirname (const gchar *uri) return res; } +/* the following two functions are courtesy of galeon */ + +/** + * xed_utils_get_current_workspace: + * @screen: a #GdkScreen + * + * Get the currently visible workspace for the #GdkScreen. + * + * If the X11 window property isn't found, 0 (the first workspace) + * is returned. + */ +guint +xed_utils_get_current_workspace (GdkScreen *screen) +{ +#ifdef GDK_WINDOWING_X11 + GdkWindow *root_win; + GdkDisplay *display; + guint ret = 0; + + g_return_val_if_fail (GDK_IS_SCREEN (screen), 0); + + root_win = gdk_screen_get_root_window (screen); + display = gdk_screen_get_display (screen); + + if (GDK_IS_X11_DISPLAY (display)) + { + Atom type; + gint format; + gulong nitems; + gulong bytes_after; + guint *current_desktop; + gint err, result; + + gdk_x11_display_error_trap_push (display); + result = XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (root_win), + gdk_x11_get_xatom_by_name_for_display (display, "_NET_CURRENT_DESKTOP"), + 0, G_MAXLONG, False, XA_CARDINAL, &type, &format, &nitems, + &bytes_after, (gpointer) ¤t_desktop); + err = gdk_x11_display_error_trap_pop (display); + + if (err != Success || result != Success) + return ret; + + if (type == XA_CARDINAL && format == 32 && nitems > 0) + ret = current_desktop[0]; + + XFree (current_desktop); + } + + return ret; +#else + /* FIXME: on mac etc proably there are native APIs + * to get the current workspace etc */ + return 0; +#endif +} + +/** + * xed_utils_get_window_workspace: + * @gtkwindow: a #GtkWindow. + * + * Get the workspace the window is on. + * + * This function gets the workspace that the #GtkWindow is visible on, + * it returns XED_ALL_WORKSPACES if the window is sticky, or if + * the window manager doesn't support this function. + * + * Returns: the workspace the window is on. + */ +guint +xed_utils_get_window_workspace (GtkWindow *gtkwindow) +{ +#ifdef GDK_WINDOWING_X11 + GdkWindow *window; + GdkDisplay *display; + Atom type; + gint format; + gulong nitems; + gulong bytes_after; + guint *workspace; + gint err, result; + guint ret = XED_ALL_WORKSPACES; + + g_return_val_if_fail (GTK_IS_WINDOW (gtkwindow), 0); + g_return_val_if_fail (gtk_widget_get_realized (GTK_WIDGET (gtkwindow)), 0); + + window = gtk_widget_get_window (GTK_WIDGET (gtkwindow)); + display = gdk_window_get_display (window); + + if (GDK_IS_X11_DISPLAY (display)) + { + gdk_x11_display_error_trap_push (display); + result = XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (window), + gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_DESKTOP"), + 0, G_MAXLONG, False, XA_CARDINAL, &type, &format, &nitems, + &bytes_after, (gpointer) &workspace); + err = gdk_x11_display_error_trap_pop (display); + + if (err != Success || result != Success) + return ret; + + if (type == XA_CARDINAL && format == 32 && nitems > 0) + ret = workspace[0]; + + XFree (workspace); + } + + return ret; +#else + /* FIXME: on mac etc proably there are native APIs + * to get the current workspace etc */ + return 0; +#endif +} + +/** + * xed_utils_get_current_viewport: + * @screen: a #GdkScreen + * @x: (out): x-axis point. + * @y: (out): y-axis point. + * + * Get the currently visible viewport origin for the #GdkScreen. + * + * If the X11 window property isn't found, (0, 0) is returned. + */ +void +xed_utils_get_current_viewport (GdkScreen *screen, + gint *x, + gint *y) +{ +#ifdef GDK_WINDOWING_X11 + GdkWindow *root_win; + GdkDisplay *display; + Atom type; + gint format; + gulong nitems; + gulong bytes_after; + gulong *coordinates; + gint err, result; + + g_return_if_fail (GDK_IS_SCREEN (screen)); + g_return_if_fail (x != NULL && y != NULL); + + /* Default values for the viewport origin */ + *x = 0; + *y = 0; + + root_win = gdk_screen_get_root_window (screen); + display = gdk_screen_get_display (screen); + + if (GDK_IS_X11_DISPLAY (display)) + { + gdk_x11_display_error_trap_push (display); + result = XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (root_win), + gdk_x11_get_xatom_by_name_for_display (display, "_NET_DESKTOP_VIEWPORT"), + 0, G_MAXLONG, False, XA_CARDINAL, &type, &format, &nitems, + &bytes_after, (void*) &coordinates); + err = gdk_x11_display_error_trap_pop (display); + + if (err != Success || result != Success) + return; + + if (type != XA_CARDINAL || format != 32 || nitems < 2) + { + XFree (coordinates); + return; + } + + *x = coordinates[0]; + *y = coordinates[1]; + XFree (coordinates); + } +#else + /* FIXME: on mac etc proably there are native APIs + * to get the current workspace etc */ + *x = 0; + *y = 0; +#endif +} + /** * xed_utils_location_get_dirname_for_display * @file: the location diff --git a/xed/xed-utils.h b/xed/xed-utils.h index 2d0d0c8..5e467fa 100644 --- a/xed/xed-utils.h +++ b/xed/xed-utils.h @@ -85,6 +85,14 @@ gchar *xed_utils_location_get_dirname_for_display (GFile *location); gchar *xed_utils_replace_home_dir_with_tilde (const gchar *uri); +guint xed_utils_get_current_workspace (GdkScreen *screen); + +guint xed_utils_get_window_workspace (GtkWindow *gtkwindow); + +void xed_utils_get_current_viewport (GdkScreen *screen, + gint *x, + gint *y); + gboolean xed_utils_is_valid_location (GFile *location); gboolean xed_utils_get_ui_objects (const gchar *filename,