summaryrefslogtreecommitdiff
path: root/applets/wncklet/window-list.c
diff options
context:
space:
mode:
Diffstat (limited to 'applets/wncklet/window-list.c')
-rw-r--r--applets/wncklet/window-list.c289
1 files changed, 178 insertions, 111 deletions
diff --git a/applets/wncklet/window-list.c b/applets/wncklet/window-list.c
index dc36b89b..93785cc1 100644
--- a/applets/wncklet/window-list.c
+++ b/applets/wncklet/window-list.c
@@ -63,6 +63,7 @@ typedef struct {
TasklistGroupingType grouping;
gboolean move_unminimized_windows;
gboolean scroll_enable;
+ gboolean middle_click_close;
GtkOrientation orientation;
int size;
@@ -70,8 +71,6 @@ typedef struct {
gboolean needs_hints;
#endif
- GtkIconTheme* icon_theme;
-
/* Properties: */
GtkWidget* properties_dialog;
GtkWidget* wayland_info_label;
@@ -88,6 +87,7 @@ typedef struct {
GtkWidget* always_group_radio;
GtkWidget* move_minimized_radio;
GtkWidget* mouse_scroll_check;
+ GtkWidget* middle_click_close_check;
GtkWidget* change_workspace_radio;
GtkWidget* minimized_windows_box;
GtkWidget* window_grouping_box;
@@ -138,6 +138,7 @@ static void tasklist_update(TasklistData* tasklist)
wnck_tasklist_set_include_all_workspaces(WNCK_TASKLIST(tasklist->tasklist), tasklist->include_all_workspaces);
wnck_tasklist_set_switch_workspace_on_unminimize(WNCK_TASKLIST(tasklist->tasklist), tasklist->move_unminimized_windows);
wnck_tasklist_set_scroll_enabled (WNCK_TASKLIST(tasklist->tasklist), tasklist->scroll_enable);
+ wnck_tasklist_set_middle_click_close (WNCK_TASKLIST (tasklist->tasklist), tasklist->middle_click_close);
}
#endif /* HAVE_X11 */
@@ -202,11 +203,6 @@ static void response_cb(GtkWidget* widget, int id, TasklistData* tasklist)
}
}
-static void applet_realized(MatePanelApplet* applet, TasklistData* tasklist)
-{
- tasklist->icon_theme = gtk_icon_theme_get_for_screen(gtk_widget_get_screen(tasklist->applet));
-}
-
static void applet_change_orient(MatePanelApplet* applet, MatePanelAppletOrient orient, TasklistData* tasklist)
{
GtkOrientation new_orient;
@@ -255,7 +251,6 @@ preview_window_thumbnail (WnckWindow *wnck_window,
int *thumbnail_scale)
{
GdkWindow *window;
- GdkWindow *window_wrapper = NULL;
Window win;
cairo_surface_t *thumbnail;
cairo_t *cr;
@@ -264,20 +259,9 @@ preview_window_thumbnail (WnckWindow *wnck_window,
win = wnck_window_get_xid (wnck_window);
- if ((window = gdk_x11_window_lookup_for_display (gdk_display_get_default (), win)) == NULL)
- {
- if ((window = gdk_x11_window_foreign_new_for_display (gdk_display_get_default (), win)) == NULL)
- {
- return NULL;
- }
- else
- {
- window_wrapper = window;
- }
- }
- else
+ if ((window = gdk_x11_window_foreign_new_for_display (gdk_display_get_default (), win)) == NULL)
{
- g_object_ref (window);
+ return NULL;
}
*thumbnail_scale = scale = gdk_window_get_scale_factor (window);
@@ -300,6 +284,8 @@ preview_window_thumbnail (WnckWindow *wnck_window,
*thumbnail_width = (int) ((double) width * ratio);
}
+ gdk_x11_display_error_trap_push (gdk_window_get_display (window));
+
thumbnail = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
*thumbnail_width,
*thumbnail_height);
@@ -310,44 +296,81 @@ preview_window_thumbnail (WnckWindow *wnck_window,
cairo_paint (cr);
cairo_destroy (cr);
- if (window_wrapper)
- g_object_unref (window_wrapper);
+ if (gdk_x11_display_error_trap_pop (gdk_window_get_display (window)))
+ {
+ cairo_surface_destroy (thumbnail);
+ thumbnail = NULL;
+ }
+
g_object_unref (window);
return thumbnail;
}
+static int g_int_compare(gconstpointer a, gconstpointer b)
+{
+ gint a_val = GPOINTER_TO_INT(a);
+ gint b_val = GPOINTER_TO_INT(b);
+ if (a_val > b_val) return -1;
+ if (a_val == b_val) return 0;
+ return 1;
+}
+
+static int find_offset(GList *list, gdouble target)
+{
+ GList *node = list;
+ while (node != NULL) {
+ int value = GPOINTER_TO_INT(node->data);
+ if (value <= target)
+ return value;
+ node = node->next;
+ }
+ return -1;
+}
+
#define PREVIEW_PADDING 5
static void
-preview_window_reposition (TasklistData *tasklist,
- cairo_surface_t *thumbnail,
+preview_window_reposition (WnckTasklist *tl,
+ TasklistData *tasklist,
int width,
int height,
int scale)
{
+ /* Known issues:
+ * - When grouping is toggled the previews won't be centered correctly until a new window is opened or one is closed.
+ * - Previews are not shown at all for grouped windows, this function is not called when hovering over those.
+ */
+
GdkMonitor *monitor;
GdkRectangle monitor_geom;
- int x_pos, y_pos;
+ MatePanelAppletOrient orient;
+ gdouble x_pos, y_pos;
+ int x_offset, y_offset;
- /* Set position at pointer, then re-adjust from there to just outside of the pointer */
- gtk_window_set_position (GTK_WINDOW (tasklist->preview), GTK_WIN_POS_MOUSE);
- gtk_window_get_position (GTK_WINDOW (tasklist->preview), &x_pos, &y_pos);
+ /* Get mouse position */
+ gdk_device_get_position_double (gdk_seat_get_pointer (gdk_display_get_default_seat (gdk_display_get_default ())), NULL, &x_pos, &y_pos);
/* Get geometry of monitor where tasklist is located to calculate correct position of preview */
monitor = gdk_display_get_monitor_at_point (gdk_display_get_default (), x_pos, y_pos);
gdk_monitor_get_geometry (monitor, &monitor_geom);
+ /* Get the position where the window list applet starts */
+ gdk_window_get_origin (gtk_widget_get_window (gtk_widget_get_parent (GTK_WIDGET(tl))), &x_offset, &y_offset);
+
+ /* Get panel orientation */
+ orient = mate_panel_applet_get_orient (MATE_PANEL_APPLET (tasklist->applet));
+
/* Add padding to clear the panel */
- switch (mate_panel_applet_get_orient (MATE_PANEL_APPLET (tasklist->applet)))
+ switch (orient)
{
case MATE_PANEL_APPLET_ORIENT_LEFT:
- x_pos = monitor_geom.width + monitor_geom.x - (width/scale + tasklist->size) - PREVIEW_PADDING;
+ x_pos = monitor_geom.width + monitor_geom.x - width - tasklist->size - PREVIEW_PADDING;
break;
case MATE_PANEL_APPLET_ORIENT_RIGHT:
x_pos = tasklist->size + PREVIEW_PADDING;
break;
case MATE_PANEL_APPLET_ORIENT_UP:
- y_pos = monitor_geom.height + monitor_geom.y - (height/scale + tasklist->size) - PREVIEW_PADDING;
+ y_pos = monitor_geom.height + monitor_geom.y - height - tasklist->size - PREVIEW_PADDING;
break;
case MATE_PANEL_APPLET_ORIENT_DOWN:
default:
@@ -355,6 +378,56 @@ preview_window_reposition (TasklistData *tasklist,
break;
}
+ /* Collect the allocation.x/y values of each button into lists.
+ * We need to iterate over all of them because grouped buttons will be the last children,
+ * even though they are positioned at the beginning. And not all buttons will have the exact same width.
+ * This allows us to avoid off-by-one errors that would cause the preview to be positioned over the adjacent button. */
+ GList *alloc_x_list = NULL;
+ GList *alloc_y_list = NULL;
+ GtkAllocation last_alloc;
+ GList* children = gtk_container_get_children (GTK_CONTAINER(tl));
+ while (children != NULL)
+ {
+ if (g_strcmp0 (gtk_widget_get_name (children->data), "tasklist-button") == 0) {
+ GtkAllocation alloc;
+ gtk_widget_get_allocation (children->data, &alloc);
+
+ /* Skip grouped buttons: these usually have alloc width/heigh=1, except right after grouping is toggled.
+ * Then simply open or close a new window to get the correct offset. */
+ if (alloc.width < 2 || alloc.height < 2)
+ {
+ children = children->next;
+ continue;
+ }
+
+ /* Keep x and y offsets in sorted lists */
+ alloc_x_list = g_list_insert_sorted (alloc_x_list, GINT_TO_POINTER(alloc.x), g_int_compare);
+ alloc_y_list = g_list_insert_sorted (alloc_y_list, GINT_TO_POINTER(alloc.y), g_int_compare);
+
+ /* The width/height from the last allocation will be used for centering the preview.
+ * It might be off by a pixel because not all buttons have the exact same width/height but this isn't critical. */
+ last_alloc = alloc;
+ }
+ children = children->next;
+ }
+
+ /* Center preview at the midpoint of the tasklist button */
+ if (orient == MATE_PANEL_APPLET_ORIENT_LEFT || orient == MATE_PANEL_APPLET_ORIENT_RIGHT)
+ {
+ /* Vertical panel */
+ y_pos = y_offset + find_offset (alloc_y_list, y_pos - y_offset) + (last_alloc.height - height) / 2;
+ y_pos = y_pos < PREVIEW_PADDING ? PREVIEW_PADDING : y_pos;
+ }
+ else if (orient == MATE_PANEL_APPLET_ORIENT_UP || orient == MATE_PANEL_APPLET_ORIENT_DOWN)
+ {
+ /* Horizontal panel */
+ x_pos = x_offset + find_offset (alloc_x_list, x_pos - x_offset) + (last_alloc.width - width) / 2;
+ x_pos = x_pos < PREVIEW_PADDING ? PREVIEW_PADDING : x_pos;
+ }
+
+ g_list_free (alloc_x_list);
+ g_list_free (alloc_y_list);
+
gtk_window_move (GTK_WINDOW (tasklist->preview), x_pos, y_pos);
}
@@ -414,12 +487,14 @@ static gboolean applet_enter_notify_event (WnckTasklist *tl, GList *wnck_windows
gtk_widget_set_app_paintable (tasklist->preview, TRUE);
gtk_window_set_default_size (GTK_WINDOW (tasklist->preview), thumbnail_width/thumbnail_scale, thumbnail_height/thumbnail_scale);
gtk_window_set_resizable (GTK_WINDOW (tasklist->preview), TRUE);
-
- preview_window_reposition (tasklist, thumbnail, thumbnail_width, thumbnail_height, thumbnail_scale);
+ preview_window_reposition (tl, tasklist, thumbnail_width/thumbnail_scale, thumbnail_height/thumbnail_scale, thumbnail_scale);
gtk_widget_show (tasklist->preview);
- g_signal_connect_data (G_OBJECT (tasklist->preview), "draw", G_CALLBACK (preview_window_draw), thumbnail, (GClosureNotify) G_CALLBACK (cairo_surface_destroy), 0);
+ g_signal_connect_data (tasklist->preview, "draw",
+ G_CALLBACK (preview_window_draw), thumbnail,
+ (GClosureNotify) G_CALLBACK (cairo_surface_destroy),
+ 0);
return FALSE;
}
@@ -603,7 +678,6 @@ static void tasklist_update_unminimization_radio(TasklistData* tasklist)
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), TRUE);
}
-
static void move_unminimized_windows_changed(GSettings* settings, gchar* key, TasklistData* tasklist)
{
gboolean value;
@@ -622,6 +696,12 @@ static void scroll_enabled_changed (GSettings* settings, gchar* key, TasklistDat
tasklist_update(tasklist);
}
+static void middle_click_close_changed (GSettings* settings, gchar* key, TasklistData* tasklist)
+{
+ tasklist->middle_click_close = g_settings_get_boolean (settings, key);
+ tasklist_update(tasklist);
+}
+
static void setup_gsettings(TasklistData* tasklist)
{
tasklist->settings = mate_panel_applet_settings_new (MATE_PANEL_APPLET (tasklist->applet), WINDOW_LIST_SCHEMA);
@@ -656,6 +736,10 @@ static void setup_gsettings(TasklistData* tasklist)
"changed::scroll-enabled",
G_CALLBACK (scroll_enabled_changed),
tasklist);
+ g_signal_connect (tasklist->settings,
+ "changed::middle-click-close",
+ G_CALLBACK (middle_click_close_changed),
+ tasklist);
}
static void applet_size_allocate(GtkWidget *widget, GtkAllocation *allocation, TasklistData *tasklist)
@@ -690,55 +774,6 @@ static void applet_size_allocate(GtkWidget *widget, GtkAllocation *allocation, T
mate_panel_applet_set_size_hints(MATE_PANEL_APPLET(tasklist->applet), size_hints, len, 0);
}
-#ifdef HAVE_X11
-/* Currently only used on X11, but should work on Wayland as well when needed */
-static GdkPixbuf* icon_loader_func(const char* icon, int size, unsigned int flags, void* data)
-{
- TasklistData* tasklist;
- GdkPixbuf* retval;
- char* icon_no_extension;
- char* p;
-
- tasklist = data;
-
- if (icon == NULL || strcmp(icon, "") == 0)
- return NULL;
-
- if (g_path_is_absolute(icon))
- {
- if (g_file_test(icon, G_FILE_TEST_EXISTS))
- {
- return gdk_pixbuf_new_from_file_at_size(icon, size, size, NULL);
- }
- else
- {
- char* basename;
-
- basename = g_path_get_basename(icon);
- retval = icon_loader_func(basename, size, flags, data);
- g_free(basename);
-
- return retval;
- }
- }
-
- /* This is needed because some .desktop files have an icon name *and*
- * an extension as icon */
- icon_no_extension = g_strdup(icon);
- p = strrchr(icon_no_extension, '.');
-
- if (p && (strcmp(p, ".png") == 0 || strcmp(p, ".xpm") == 0 || strcmp(p, ".svg") == 0))
- {
- *p = 0;
- }
-
- retval = gtk_icon_theme_load_icon(tasklist->icon_theme, icon_no_extension, size, 0, NULL);
- g_free(icon_no_extension);
-
- return retval;
-}
-#endif /* HAVE_X11 */
-
gboolean window_list_applet_fill(MatePanelApplet* applet)
{
TasklistData* tasklist;
@@ -781,6 +816,8 @@ gboolean window_list_applet_fill(MatePanelApplet* applet)
tasklist->scroll_enable = g_settings_get_boolean (tasklist->settings, "scroll-enabled");
+ tasklist->middle_click_close = g_settings_get_boolean (tasklist->settings, "middle-click-close");
+
tasklist->size = mate_panel_applet_get_size(applet);
#if !defined(WNCKLET_INPROCESS) && !GTK_CHECK_VERSION (3, 23, 0)
@@ -805,12 +842,13 @@ gboolean window_list_applet_fill(MatePanelApplet* applet)
{
tasklist->tasklist = wnck_tasklist_new();
- wnck_tasklist_set_middle_click_close (WNCK_TASKLIST (tasklist->tasklist), TRUE);
- wnck_tasklist_set_icon_loader(WNCK_TASKLIST(tasklist->tasklist), icon_loader_func, tasklist, NULL);
-
#ifdef HAVE_WINDOW_PREVIEWS
- g_signal_connect(G_OBJECT(tasklist->tasklist), "task_enter_notify", G_CALLBACK(applet_enter_notify_event), tasklist);
- g_signal_connect(G_OBJECT(tasklist->tasklist), "task_leave_notify", G_CALLBACK(applet_leave_notify_event), tasklist);
+ g_signal_connect (tasklist->tasklist, "task-enter-notify",
+ G_CALLBACK (applet_enter_notify_event),
+ tasklist);
+ g_signal_connect (tasklist->tasklist, "task-leave-notify",
+ G_CALLBACK (applet_leave_notify_event),
+ tasklist);
#endif /* HAVE_WINDOW_PREVIEWS */
}
else
@@ -830,25 +868,33 @@ gboolean window_list_applet_fill(MatePanelApplet* applet)
tasklist_apply_orientation(tasklist);
- g_signal_connect(G_OBJECT(tasklist->tasklist), "destroy", G_CALLBACK(destroy_tasklist), tasklist);
- g_signal_connect(G_OBJECT(tasklist->applet), "size_allocate", G_CALLBACK(applet_size_allocate), tasklist);
+ g_signal_connect (tasklist->tasklist, "destroy",
+ G_CALLBACK (destroy_tasklist),
+ tasklist);
+ g_signal_connect (tasklist->applet, "size-allocate",
+ G_CALLBACK (applet_size_allocate),
+ tasklist);
gtk_container_add(GTK_CONTAINER(tasklist->applet), tasklist->tasklist);
- g_signal_connect(G_OBJECT(tasklist->applet), "realize", G_CALLBACK(applet_realized), tasklist);
- g_signal_connect(G_OBJECT(tasklist->applet), "change_orient", G_CALLBACK(applet_change_orient), tasklist);
- g_signal_connect(G_OBJECT(tasklist->applet), "change_size", G_CALLBACK(applet_change_pixel_size), tasklist);
- g_signal_connect(G_OBJECT(tasklist->applet), "change_background", G_CALLBACK(applet_change_background), tasklist);
+ g_signal_connect (tasklist->applet, "change-orient",
+ G_CALLBACK (applet_change_orient),
+ tasklist);
+ g_signal_connect (tasklist->applet, "change-size",
+ G_CALLBACK (applet_change_pixel_size),
+ tasklist);
+ g_signal_connect (tasklist->applet, "change-background",
+ G_CALLBACK(applet_change_background),
+ tasklist);
action_group = gtk_action_group_new("Tasklist Applet Actions");
gtk_action_group_set_translation_domain(action_group, GETTEXT_PACKAGE);
gtk_action_group_add_actions(action_group, tasklist_menu_actions, G_N_ELEMENTS(tasklist_menu_actions), tasklist);
-
/* disable the item of system monitor, if not exists.
* example, mate-system-monitor, o gnome-system-monitor */
char* programpath;
- int i;
+ gsize i;
for (i = 0; i < G_N_ELEMENTS(system_monitors); i += 1)
{
@@ -870,7 +916,6 @@ gboolean window_list_applet_fill(MatePanelApplet* applet)
_system_monitor_found:;
/* end of system monitor item */
-
mate_panel_applet_setup_menu_from_resource (MATE_PANEL_APPLET (tasklist->applet),
WNCKLET_RESOURCE_PATH "window-list-menu.xml",
action_group);
@@ -894,7 +939,7 @@ gboolean window_list_applet_fill(MatePanelApplet* applet)
static void call_system_monitor(GtkAction* action, TasklistData* tasklist)
{
- int i;
+ gsize i;
for (i = 0; i < G_N_ELEMENTS(system_monitors); i += 1)
{
@@ -912,7 +957,6 @@ static void call_system_monitor(GtkAction* action, TasklistData* tasklist)
}
}
-
static void display_help_dialog(GtkAction* action, TasklistData* tasklist)
{
wncklet_display_help(tasklist->applet, "mate-user-guide", "windowlist", WINDOW_LIST_ICON);
@@ -1026,7 +1070,6 @@ static void setup_dialog(GtkBuilder* builder, TasklistData* tasklist)
{
GtkWidget* button;
-
tasklist->wayland_info_label = WID("wayland_info_label");
tasklist->show_current_radio = WID("show_current_radio");
tasklist->show_all_radio = WID("show_all_radio");
@@ -1063,6 +1106,7 @@ static void setup_dialog(GtkBuilder* builder, TasklistData* tasklist)
tasklist->move_minimized_radio = WID("move_minimized_radio");
tasklist->change_workspace_radio = WID("change_workspace_radio");
tasklist->mouse_scroll_check = WID("mouse_scroll_check");
+ tasklist->middle_click_close_check = WID("middle_click_close_check");
tasklist->minimized_windows_box = WID("minimized_windows_box");
tasklist->window_grouping_box = WID("window_grouping_box");
tasklist->window_list_content_box = WID("window_list_content_box");
@@ -1076,9 +1120,15 @@ static void setup_dialog(GtkBuilder* builder, TasklistData* tasklist)
g_object_set_data(G_OBJECT(tasklist->auto_group_radio), "group_value", "auto");
g_object_set_data(G_OBJECT(tasklist->always_group_radio), "group_value", "always");
- g_signal_connect(G_OBJECT(tasklist->never_group_radio), "toggled", (GCallback) group_windows_toggled, tasklist);
- g_signal_connect(G_OBJECT(tasklist->auto_group_radio), "toggled", (GCallback) group_windows_toggled, tasklist);
- g_signal_connect(G_OBJECT(tasklist->always_group_radio), "toggled", (GCallback) group_windows_toggled, tasklist);
+ g_signal_connect (tasklist->never_group_radio, "toggled",
+ (GCallback) group_windows_toggled,
+ tasklist);
+ g_signal_connect (tasklist->auto_group_radio, "toggled",
+ (GCallback) group_windows_toggled,
+ tasklist);
+ g_signal_connect (tasklist->always_group_radio, "toggled",
+ (GCallback) group_windows_toggled,
+ tasklist);
/* Mouse Scroll: */
g_settings_bind (tasklist->settings,
@@ -1087,22 +1137,39 @@ static void setup_dialog(GtkBuilder* builder, TasklistData* tasklist)
"active",
G_SETTINGS_BIND_DEFAULT);
+ /* Middle mouse click to close window: */
+ g_settings_bind (tasklist->settings,
+ "middle-click-close",
+ tasklist->middle_click_close_check,
+ "active",
+ G_SETTINGS_BIND_DEFAULT);
+
#ifdef HAVE_WINDOW_PREVIEWS
/* change thumbnail size: */
tasklist_update_thumbnail_size_spin(tasklist);
- g_signal_connect(G_OBJECT(tasklist->thumbnail_size_spin), "value-changed", (GCallback) thumbnail_size_spin_changed, tasklist);
+ g_signal_connect (tasklist->thumbnail_size_spin, "value-changed",
+ (GCallback) thumbnail_size_spin_changed,
+ tasklist);
#endif
/* move window when unminimizing: */
tasklist_update_unminimization_radio(tasklist);
- g_signal_connect(G_OBJECT(tasklist->move_minimized_radio), "toggled", (GCallback) move_minimized_toggled, tasklist);
+ g_signal_connect (tasklist->move_minimized_radio, "toggled",
+ (GCallback) move_minimized_toggled,
+ tasklist);
/* Tasklist content: */
tasklist_properties_update_content_radio (tasklist);
- g_signal_connect(G_OBJECT(tasklist->show_all_radio), "toggled", (GCallback) display_all_workspaces_toggled, tasklist);
-
- g_signal_connect_swapped(WID("done_button"), "clicked", (GCallback) gtk_widget_hide, tasklist->properties_dialog);
- g_signal_connect(tasklist->properties_dialog, "response", G_CALLBACK(response_cb), tasklist);
+ g_signal_connect (tasklist->show_all_radio, "toggled",
+ (GCallback) display_all_workspaces_toggled,
+ tasklist);
+
+ g_signal_connect_swapped (WID ("done_button"), "clicked",
+ (GCallback) gtk_widget_hide,
+ tasklist->properties_dialog);
+ g_signal_connect (tasklist->properties_dialog, "response",
+ G_CALLBACK (response_cb),
+ tasklist);
#ifdef HAVE_WAYLAND
if (GDK_IS_WAYLAND_DISPLAY(gdk_display_get_default())) {