/*
* xfdesktop - xfce4 ' s desktop manager
*
* Copyright ( c ) 2004 - 2007 , 2024 Brian Tarricone , < brian @ tarricone . org >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU Library General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software Foundation ,
* Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 , USA
*
* Random portions taken from or inspired by the original xfdesktop for xfce4 :
* Copyright ( C ) 2002 - 2003 Jasper Huijsmans ( huysmans @ users . sourceforge . net )
* Copyright ( C ) 2003 Benedikt Meurer < benedikt . meurer @ unix - ag . uni - siegen . de >
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#ifdef HAVE_TIME_H
#include <time.h>
#endif
#include <gio/gio.h>
#include <glib.h>
#include <gtk/gtk.h>
#include <libxfce4util/libxfce4util.h>
#include <libxfce4ui/libxfce4ui.h>
#include <libxfce4windowing/libxfce4windowing.h>
#include <xfconf/xfconf.h>
#ifdef ENABLE_X11
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <gdk/gdkx.h>
#include <cairo-xlib.h>
#endif /* ENABLE_X11 */
#ifdef ENABLE_WAYLAND
#include <gtk-layer-shell.h>
#endif
#include "xfdesktop-backdrop-manager.h"
#include "xfdesktop-common.h"
#include "xfce-desktop.h"
#ifdef ENABLE_X11
#include "xfdesktop-x11.h"
#endif
/* disable setting the x background for bug 7442 */
//#define DISABLE_FOR_BUG7442
struct _XfceDesktop {
GtkWindow parent_instance;
GdkScreen *gscreen;
XfwScreen *xfw_screen;
XfwMonitor *monitor;
XfdesktopBackdropManager *backdrop_manager;
XfwWorkspaceManager *workspace_manager;
gboolean updates_frozen;
XfconfChannel *channel;
gchar *property_prefix;
XfwWorkspaceGroup *workspace_group;
GList *workspaces; // XfwWorkspace
XfwWorkspace *active_workspace;
gboolean single_workspace_mode;
gint single_workspace_num;
XfwWorkspace *single_workspace;
XfwWorkspace *backdrop_workspace;
GCancellable *backdrop_load_cancellable;
cairo_surface_t *bg_surface;
GdkRectangle bg_surface_region;
gboolean is_active;
gboolean has_pointer;
#ifdef ENABLE_DESKTOP_ICONS
gint style_refresh_timer;
#endif
};
enum
{
PROP_0 = 0 ,
PROP_SCREEN,
PROP_MONITOR,
PROP_CHANNEL,
PROP_PROPERTY_PREFIX,
PROP_BACKDROP_MANAGER,
PROP_SINGLE_WORKSPACE_MODE,
PROP_SINGLE_WORKSPACE_NUMBER,
PROP_ACTIVE,
};
static void xfce_desktop_constructed(GObject *object);
static void xfce_desktop_finalize(GObject *object);
static void xfce_desktop_set_property(GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void xfce_desktop_get_property(GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
static void xfce_desktop_realize(GtkWidget *widget);
static void xfce_desktop_unrealize(GtkWidget *widget);
static gboolean xfce_desktop_draw(GtkWidget *w,
cairo_t *cr);
static gboolean xfce_desktop_enter_leave_event(GtkWidget *w,
GdkEventCrossing *event);
static gboolean xfce_desktop_focus_in_out_event(GtkWidget *w,
GdkEventFocus *event);
static void xfce_desktop_style_updated(GtkWidget *w);
static void xfce_desktop_set_single_workspace_mode(XfceDesktop *desktop,
gboolean single_workspace);
static void xfce_desktop_set_single_workspace_number(XfceDesktop *desktop,
gint workspace_num);
static gboolean update_backdrop_workspace(XfceDesktop *desktop);
static struct
{
const gchar *setting;
GType setting_type;
const gchar *property;
} setting_bindings[] = {
{ SINGLE_WORKSPACE_MODE, G_TYPE_BOOLEAN, "single-workspace-mode" },
{ SINGLE_WORKSPACE_NUMBER, G_TYPE_INT, "single-workspace-number" },
};
/* private functions */
static void
xfce_desktop_place_on_monitor(XfceDesktop *desktop) {
GdkRectangle geom;
xfw_monitor_get_logical_geometry(desktop->monitor, &geom);
DBG("Moving desktop for geometry %dx%d+%d+%d for %s" ,
geom.width, geom.height,
geom.x, geom.y,
xfw_monitor_get_description(desktop->monitor));
gtk_widget_set_size_request(GTK_WIDGET(desktop), geom.width, geom.height);
#ifdef ENABLE_X11
if (xfw_windowing_get() == XFW_WINDOWING_X11) {
gtk_window_move(GTK_WINDOW(desktop), geom.x, geom.y);
}
#endif
// On wayland, layer-shell should already have anchored us to the top-left
// corner of the monitor, so no need to change the position.
}
static void
set_accountsservice_user_bg(const gchar *background)
{
GDBusConnection *bus;
GVariant *variant;
GError *error = NULL;
gchar *object_path = NULL;
bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
if (bus == NULL) {
g_warning ("Failed to get system bus: %s" , error->message);
g_error_free (error);
return ;
}
variant = g_dbus_connection_call_sync (bus,
"org.freedesktop.Accounts" ,
"/org/freedesktop/Accounts" ,
"org.freedesktop.Accounts" ,
"FindUserByName" ,
g_variant_new ("(s)" , g_get_user_name ()),
G_VARIANT_TYPE ("(o)" ),
G_DBUS_CALL_FLAGS_NONE,
-1 ,
NULL,
&error);
if (variant == NULL) {
DBG("Could not contact accounts service to look up '%s': %s" ,
g_get_user_name (), error->message);
g_error_free(error);
g_object_unref (bus);
return ;
}
g_variant_get(variant, "(o)" , &object_path);
g_variant_unref(variant);
variant = g_dbus_connection_call_sync (bus,
"org.freedesktop.Accounts" ,
object_path,
"org.freedesktop.DBus.Properties" ,
"Set" ,
g_variant_new ("(ssv)" ,
"org.freedesktop.DisplayManager.AccountsService" ,
"BackgroundFile" ,
g_variant_new_string (background ? background : "" )),
G_VARIANT_TYPE ("()" ),
G_DBUS_CALL_FLAGS_NONE,
-1 ,
NULL,
&error);
if (variant != NULL) {
g_variant_unref (variant);
} else {
g_warning ("Failed to register the newly set background with AccountsService '%s': %s" , background, error->message);
g_clear_error (&error);
}
g_free (object_path);
g_object_unref (bus);
}
static void
backdrop_loaded(cairo_surface_t *surface, GdkRectangle *region, GFile *image_file, GError *error, gpointer user_data) {
XfceDesktop *desktop = XFCE_DESKTOP(user_data);
DBG("entering, surface=%p, dims=%dx%d+%d+%d" ,
surface,
region != NULL ? region->width : 0 ,
region != NULL ? region->height : 0 ,
region != NULL ? region->x : 0 ,
region != NULL ? region->y : 0 );
if (error != NULL) {
if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
DBG("backdrop loading cancelled" );
} else {
g_clear_object(&desktop->backdrop_load_cancellable);
g_message("Failed to load backdrop for monitor %s: %s" ,
xfw_monitor_get_connector(desktop->monitor),
error->message);
}
} else if (surface != NULL) {
g_clear_object(&desktop->backdrop_load_cancellable);
if (desktop->bg_surface != surface) {
if (desktop->bg_surface != NULL) {
cairo_surface_destroy(desktop->bg_surface);
}
desktop->bg_surface = cairo_surface_reference(surface);
}
desktop->bg_surface_region = *region;
#ifdef ENABLE_X11
if (xfw_monitor_is_primary(desktop->monitor) && xfw_windowing_get() == XFW_WINDOWING_X11) {
gint monitor_idx = -1 ;
for (GList *l = xfw_screen_get_monitors(desktop->xfw_screen); l != NULL; l = l->next) {
if (XFW_MONITOR(l->data) == desktop->monitor) {
xfdesktop_x11_set_root_image_file_property(desktop->gscreen,
monitor_idx,
image_file != NULL
? g_file_peek_path(image_file)
: NULL);
break ;
}
monitor_idx++;
}
/* do this again so apps watching the root win notice the update */
xfdesktop_x11_set_root_image_surface(desktop->gscreen, surface);
xfdesktop_x11_set_compat_properties(GTK_WIDGET(desktop));
}
#endif /* ENABLE_X11 */
if (xfw_monitor_is_primary(desktop->monitor)) {
set_accountsservice_user_bg(image_file != NULL ? g_file_peek_path(image_file) : NULL);
}
gtk_widget_queue_draw(GTK_WIDGET(desktop));
}
}
static void
fetch_backdrop(XfceDesktop *desktop) {
TRACE("entering" );
if (gtk_widget_get_realized(GTK_WIDGET(desktop)) && desktop->backdrop_workspace != NULL) {
if (desktop->backdrop_load_cancellable != NULL) {
g_cancellable_cancel(desktop->backdrop_load_cancellable);
g_object_unref(desktop->backdrop_load_cancellable);
}
desktop->backdrop_load_cancellable = g_cancellable_new();
xfdesktop_backdrop_manager_get_image_surface(desktop->backdrop_manager,
desktop->backdrop_load_cancellable,
desktop->monitor,
desktop->backdrop_workspace,
backdrop_loaded,
desktop);
}
}
static void
screen_composited_changed_cb(GdkScreen *gscreen, XfceDesktop *desktop) {
fetch_backdrop(desktop);
}
static void
monitor_prop_changed(XfwMonitor *monitor, GParamSpec *pspec, XfceDesktop *desktop) {
xfce_desktop_place_on_monitor(desktop);
fetch_backdrop(desktop);
}
static void
workspace_changed_cb(XfwWorkspaceGroup *group, XfwWorkspace *previously_active_space, XfceDesktop *desktop) {
TRACE("entering" );
update_backdrop_workspace(desktop);
}
static void
group_workspace_added(XfwWorkspaceGroup *group, XfwWorkspace *workspace, XfceDesktop *desktop) {
DBG("entering" );
if (g_list_find(desktop->workspaces, workspace) == NULL) {
desktop->workspaces = g_list_prepend(desktop->workspaces, workspace);
}
// Run this again; if ->single_workspace is NULL, it will try to populate it
xfce_desktop_set_single_workspace_number(desktop, desktop->single_workspace_num);
}
static void
group_workspace_removed(XfwWorkspaceGroup *group, XfwWorkspace *workspace, XfceDesktop *desktop) {
desktop->workspaces = g_list_remove(desktop->workspaces, workspace);
if (desktop->active_workspace == workspace) {
desktop->active_workspace = NULL;
}
if (desktop->single_workspace == workspace) {
desktop->single_workspace = NULL;
}
if (desktop->backdrop_workspace == workspace) {
desktop->backdrop_workspace = NULL;
update_backdrop_workspace(desktop);
}
}
static void
group_monitor_added(XfwWorkspaceGroup *group, XfwMonitor *monitor, XfceDesktop *desktop) {
if (monitor == desktop->monitor) {
desktop->workspace_group = group;
g_signal_connect(group, "workspace-added" ,
G_CALLBACK(group_workspace_added), desktop);
g_signal_connect(group, "workspace-removed" ,
G_CALLBACK(group_workspace_removed), desktop);
g_signal_connect(group, "active-workspace-changed" ,
G_CALLBACK(workspace_changed_cb), desktop);
for (GList *l = xfw_workspace_group_list_workspaces(group); l; l = l->next) {
group_workspace_added(desktop->workspace_group, XFW_WORKSPACE(l->data), desktop);
}
update_backdrop_workspace(desktop);
}
}
static void
group_monitor_removed(XfwWorkspaceGroup *group, XfwMonitor *monitor, XfceDesktop *desktop) {
if (monitor == desktop->monitor) {
desktop->workspace_group = NULL;
g_signal_handlers_disconnect_by_func(group, group_workspace_added, desktop);
g_signal_handlers_disconnect_by_func(group, group_workspace_removed, desktop);
g_signal_handlers_disconnect_by_func(group, workspace_changed_cb, desktop);
update_backdrop_workspace(desktop);
}
}
static void
workspace_group_created_cb(XfwWorkspaceManager* manager,
XfwWorkspaceGroup *group,
gpointer user_data)
{
XfceDesktop *desktop = XFCE_DESKTOP(user_data);
TRACE("entering" );
g_signal_connect(group, "monitor-added" ,
G_CALLBACK(group_monitor_added), desktop);
g_signal_connect(group, "monitor-removed" ,
G_CALLBACK(group_monitor_removed), desktop);
GList *monitors = xfw_workspace_group_get_monitors(group);
if (g_list_find(monitors, desktop->monitor) != NULL) {
group_monitor_added(group, desktop->monitor, desktop);
}
}
static void
workspace_group_destroyed_cb(XfwWorkspaceManager *manager,
XfwWorkspaceGroup *group,
gpointer user_data)
{
XfceDesktop *desktop = XFCE_DESKTOP(user_data);
TRACE("entering" );
group_monitor_removed(group, desktop->monitor, desktop);
g_signal_handlers_disconnect_by_data(group, desktop);
}
static void
manager_backdrop_changed(XfdesktopBackdropManager *manager,
XfwMonitor *monitor,
XfwWorkspace *workspace,
XfceDesktop *desktop)
{
DBG("entering: monitor=%p, our monitor=%p, workspace=%d, our workspace=%d" ,
monitor, desktop->monitor, xfw_workspace_get_number(workspace),
xfw_workspace_get_number(desktop->backdrop_workspace));
if (monitor == desktop->monitor && workspace == desktop->backdrop_workspace) {
fetch_backdrop(desktop);
}
}
G_DEFINE_TYPE(XfceDesktop, xfce_desktop, GTK_TYPE_WINDOW)
static void
xfce_desktop_class_init(XfceDesktopClass *klass)
{
GObjectClass *gobject_class = (GObjectClass *)klass;
GtkWidgetClass *widget_class = (GtkWidgetClass *)klass;
gobject_class->constructed = xfce_desktop_constructed;
gobject_class->finalize = xfce_desktop_finalize;
gobject_class->set_property = xfce_desktop_set_property;
gobject_class->get_property = xfce_desktop_get_property;
widget_class->realize = xfce_desktop_realize;
widget_class->unrealize = xfce_desktop_unrealize;
widget_class->draw = xfce_desktop_draw;
widget_class->enter_notify_event = xfce_desktop_enter_leave_event;
widget_class->leave_notify_event = xfce_desktop_enter_leave_event;
widget_class->focus_in_event = xfce_desktop_focus_in_out_event;
widget_class->focus_out_event = xfce_desktop_focus_in_out_event;
widget_class->style_updated = xfce_desktop_style_updated;
g_object_class_install_property(gobject_class, PROP_SCREEN,
g_param_spec_object("screen" ,
"gdk screen" ,
"gdk screen" ,
GDK_TYPE_SCREEN,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
g_object_class_install_property(gobject_class, PROP_MONITOR,
g_param_spec_object("monitor" ,
"xfw monitor" ,
"xfw monitor" ,
XFW_TYPE_MONITOR,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
g_object_class_install_property(gobject_class, PROP_CHANNEL,
g_param_spec_object("channel" ,
"xfconf channel" ,
"xfconf channel" ,
XFCONF_TYPE_CHANNEL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
g_object_class_install_property(gobject_class, PROP_PROPERTY_PREFIX,
g_param_spec_string("property-prefix" ,
"xfconf property prefix" ,
"xfconf property prefix" ,
"" ,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
g_object_class_install_property(gobject_class, PROP_BACKDROP_MANAGER,
g_param_spec_object("backdrop-manager" ,
"backdrop manager" ,
"backdrop manager" ,
XFDESKTOP_TYPE_BACKDROP_MANAGER,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
g_object_class_install_property(gobject_class, PROP_SINGLE_WORKSPACE_MODE,
g_param_spec_boolean("single-workspace-mode" ,
"single-workspace-mode" ,
"single-workspace-mode" ,
TRUE ,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
g_object_class_install_property(gobject_class, PROP_SINGLE_WORKSPACE_NUMBER,
g_param_spec_int("single-workspace-number" ,
"single-workspace-number" ,
"single-workspace-number" ,
-1 , G_MAXINT16, -1 ,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
g_object_class_install_property(gobject_class,
PROP_ACTIVE,
g_param_spec_boolean("active" ,
"active" ,
"active" ,
FALSE ,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
}
static void
xfce_desktop_init(XfceDesktop *desktop)
{
desktop->single_workspace_num = -1 ;
}
static void
xfce_desktop_constructed(GObject *obj)
{
XfceDesktop *desktop = XFCE_DESKTOP(obj);
XfwWorkspaceManager *workspace_manager;
G_OBJECT_CLASS(xfce_desktop_parent_class)->constructed(obj);
gtk_window_set_screen(GTK_WINDOW(desktop), desktop->gscreen);
gtk_window_set_type_hint(GTK_WINDOW(desktop), GDK_WINDOW_TYPE_HINT_DESKTOP);
/* Accept focus is needed for the menu pop up either by the menu key on
* the keyboard or Shift+F10. */
gtk_window_set_accept_focus(GTK_WINDOW(desktop), TRUE );
/* Can focus is needed for the gtk_grab_add/remove commands */
gtk_widget_set_can_focus(GTK_WIDGET(desktop), TRUE );
gtk_window_set_resizable(GTK_WINDOW(desktop), FALSE );
gtk_window_set_title(GTK_WINDOW(desktop), _("Desktop" ));
gtk_window_set_decorated(GTK_WINDOW(desktop), FALSE );
#ifdef ENABLE_WAYLAND
if (xfw_windowing_get() == XFW_WINDOWING_WAYLAND) {
gtk_layer_init_for_window(GTK_WINDOW(desktop));
}
#endif
if (desktop->channel != NULL) {
for (gsize i = 0 ; i < G_N_ELEMENTS(setting_bindings); ++i) {
g_assert(setting_bindings[i].setting_type != 0 );
xfconf_g_property_bind(desktop->channel,
setting_bindings[i].setting, setting_bindings[i].setting_type,
G_OBJECT(desktop), setting_bindings[i].property);
}
}
desktop->xfw_screen = xfw_screen_get_default();
workspace_manager = xfw_screen_get_workspace_manager(desktop->xfw_screen);
desktop->workspace_manager = workspace_manager;
/* watch for workspace changes */
for (GList *gl = xfw_workspace_manager_list_workspace_groups(workspace_manager);
gl != NULL;
gl = gl->next)
{
workspace_group_created_cb(workspace_manager, XFW_WORKSPACE_GROUP(gl->data), desktop);
}
g_signal_connect(workspace_manager, "workspace-group-created" ,
G_CALLBACK(workspace_group_created_cb), desktop);
g_signal_connect(workspace_manager, "workspace-group-destroyed" ,
G_CALLBACK(workspace_group_destroyed_cb), desktop);
g_signal_connect(desktop->backdrop_manager, "backdrop-changed" ,
G_CALLBACK(manager_backdrop_changed), desktop);
}
static void
xfce_desktop_finalize(GObject *object)
{
XfceDesktop *desktop = XFCE_DESKTOP(object);
g_signal_handlers_disconnect_by_data(desktop->backdrop_manager, desktop);
g_signal_handlers_disconnect_by_data(desktop->workspace_manager, desktop);
for (GList *l = xfw_workspace_manager_list_workspace_groups(desktop->workspace_manager);
l != NULL;
l = l->next)
{
g_signal_handlers_disconnect_by_data(l->data, desktop);
}
if (desktop->backdrop_load_cancellable != NULL) {
g_cancellable_cancel(desktop->backdrop_load_cancellable);
g_object_unref(desktop->backdrop_load_cancellable);
}
g_list_free(desktop->workspaces);
g_object_unref(desktop->xfw_screen);
if (desktop->channel != NULL) {
g_object_unref(G_OBJECT(desktop->channel));
}
g_free(desktop->property_prefix);
#ifdef ENABLE_DESKTOP_ICONS
if (desktop->style_refresh_timer != 0 )
g_source_remove(desktop->style_refresh_timer);
#endif
g_signal_handlers_disconnect_by_data(desktop->monitor, desktop);
g_object_unref(desktop->monitor);
G_OBJECT_CLASS(xfce_desktop_parent_class)->finalize(object);
}
static void
xfce_desktop_set_property(GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
XfceDesktop *desktop = XFCE_DESKTOP(object);
switch (property_id) {
case PROP_SCREEN:
desktop->gscreen = g_value_get_object(value);
break ;
case PROP_MONITOR:
xfce_desktop_update_monitor(desktop, g_value_get_object(value));
break ;
case PROP_CHANNEL:
desktop->channel = g_value_dup_object(value);
break ;
case PROP_PROPERTY_PREFIX:
desktop->property_prefix = g_value_dup_string(value);
break ;
case PROP_BACKDROP_MANAGER:
desktop->backdrop_manager = g_value_get_object(value);
break ;
case PROP_SINGLE_WORKSPACE_MODE:
xfce_desktop_set_single_workspace_mode(desktop,
g_value_get_boolean(value));
break ;
case PROP_SINGLE_WORKSPACE_NUMBER:
xfce_desktop_set_single_workspace_number(desktop,
g_value_get_int(value));
break ;
default :
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
break ;
}
}
static void
xfce_desktop_get_property(GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
XfceDesktop *desktop = XFCE_DESKTOP(object);
switch (property_id) {
case PROP_SCREEN:
g_value_set_object(value, desktop->gscreen);
break ;
case PROP_MONITOR:
g_value_set_object(value, desktop->monitor);
break ;
case PROP_CHANNEL:
g_value_set_object(value, desktop->channel);
break ;
case PROP_PROPERTY_PREFIX:
g_value_set_string(value, desktop->property_prefix);
break ;
case PROP_BACKDROP_MANAGER:
g_value_set_object(value, desktop->backdrop_manager);
break ;
case PROP_SINGLE_WORKSPACE_MODE:
g_value_set_boolean(value, desktop->single_workspace_mode);
break ;
case PROP_SINGLE_WORKSPACE_NUMBER:
g_value_set_int(value, desktop->single_workspace_num);
break ;
case PROP_ACTIVE:
g_value_set_boolean(value, xfce_desktop_is_active(desktop));
break ;
default :
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
break ;
}
}
static void
xfce_desktop_realize(GtkWidget *widget)
{
XfceDesktop *desktop = XFCE_DESKTOP(widget);
TRACE("entering" );
#ifdef ENABLE_WAYLAND
if (xfw_windowing_get() == XFW_WINDOWING_WAYLAND) {
GtkWindow *window = GTK_WINDOW(desktop);
gtk_layer_set_layer(window, GTK_LAYER_SHELL_LAYER_BACKGROUND);
gtk_layer_set_monitor(window, xfw_monitor_get_gdk_monitor(desktop->monitor));
gtk_layer_set_anchor(window, GTK_LAYER_SHELL_EDGE_TOP, TRUE );
gtk_layer_set_anchor(window, GTK_LAYER_SHELL_EDGE_LEFT, TRUE );
gtk_layer_set_margin(window, GTK_LAYER_SHELL_EDGE_TOP, 0 );
gtk_layer_set_margin(window, GTK_LAYER_SHELL_EDGE_LEFT, 0 );
gtk_layer_set_margin(window, GTK_LAYER_SHELL_EDGE_BOTTOM, 0 );
gtk_layer_set_margin(window, GTK_LAYER_SHELL_EDGE_RIGHT, 0 );
gtk_layer_set_exclusive_zone(window, -1 );
gtk_layer_set_namespace(window, "desktop" );
}
#endif
/* chain up */
GTK_WIDGET_CLASS(xfce_desktop_parent_class)->realize(widget);
xfce_desktop_place_on_monitor(desktop);
gdk_window_lower(gtk_widget_get_window(widget));
g_signal_connect(G_OBJECT(desktop->gscreen), "composited-changed" ,
G_CALLBACK(screen_composited_changed_cb), desktop);
gtk_widget_add_events(GTK_WIDGET(desktop), GDK_EXPOSURE_MASK);
xfce_desktop_refresh(desktop);
TRACE("exiting" );
}
static void
xfce_desktop_unrealize(GtkWidget *widget)
{
XfceDesktop *desktop = XFCE_DESKTOP(widget);
g_return_if_fail(XFCE_IS_DESKTOP(desktop));
g_signal_handlers_disconnect_by_func(G_OBJECT(desktop->gscreen),
G_CALLBACK(screen_composited_changed_cb), desktop);
#ifdef ENABLE_X11
if (xfw_monitor_is_primary(desktop->monitor) && xfw_windowing_get() == XFW_WINDOWING_X11) {
xfdesktop_x11_set_root_image_surface(desktop->gscreen, NULL);
xfdesktop_x11_set_compat_properties(NULL);
gint monitor_idx = -1 ;
for (GList *l = xfw_screen_get_monitors(desktop->xfw_screen); l != NULL; l = l->next) {
if (XFW_MONITOR(l->data) == desktop->monitor) {
xfdesktop_x11_set_root_image_file_property(desktop->gscreen,
monitor_idx,
NULL);
break ;
}
monitor_idx++;
}
}
#endif
if (desktop->bg_surface != NULL) {
cairo_surface_destroy(desktop->bg_surface);
desktop->bg_surface = NULL;
}
GTK_WIDGET_CLASS(xfce_desktop_parent_class)->unrealize(widget);
}
static gboolean
xfce_desktop_draw(GtkWidget *w,
cairo_t *cr)
{
XfceDesktop *desktop = XFCE_DESKTOP(w);
cairo_save(cr);
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
if (desktop->bg_surface != NULL) {
gdouble scale = xfw_monitor_get_fractional_scale(desktop->monitor);
cairo_scale(cr, 1 .0 / scale, 1 .0 / scale);
cairo_set_source_surface(cr,
desktop->bg_surface,
0 - desktop->bg_surface_region.x,
0 - desktop->bg_surface_region.y);
cairo_rectangle(cr,
0 ,
0 ,
desktop->bg_surface_region.width,
desktop->bg_surface_region.height);
cairo_fill(cr);
} else {
cairo_set_source_rgba(cr, 0 .0 , 0 .0 , 0 .0 , 1 .0 );
cairo_paint(cr);
}
cairo_restore(cr);
GList *children = gtk_container_get_children(GTK_CONTAINER(w));
for (GList *l = children; l; l = l->next) {
gtk_container_propagate_draw(GTK_CONTAINER(w),
GTK_WIDGET(l->data),
cr);
}
g_list_free(children);
return FALSE ;
}
static gboolean
xfce_desktop_enter_leave_event(GtkWidget *w, GdkEventCrossing *event) {
XfceDesktop *desktop = XFCE_DESKTOP(w);
gboolean old_is_active = xfce_desktop_is_active(desktop);
desktop->has_pointer = event->type == GDK_ENTER_NOTIFY;
gboolean (*callback)(GtkWidget *, GdkEventCrossing *) = desktop->has_pointer
? GTK_WIDGET_CLASS(xfce_desktop_parent_class)->enter_notify_event
: GTK_WIDGET_CLASS(xfce_desktop_parent_class)->leave_notify_event;
gboolean ret = callback != NULL ? callback(w, event) : FALSE ;
if (old_is_active != xfce_desktop_is_active(desktop)) {
g_object_notify(G_OBJECT(w), "active" );
}
return ret;
}
static gboolean
xfce_desktop_focus_in_out_event(GtkWidget *w, GdkEventFocus *event) {
gboolean has_focus = event->in;
gboolean (*callback)(GtkWidget *, GdkEventFocus *) = has_focus
? GTK_WIDGET_CLASS(xfce_desktop_parent_class)->focus_in_event
: GTK_WIDGET_CLASS(xfce_desktop_parent_class)->focus_out_event;
gboolean ret = callback != NULL ? callback(w, event) : FALSE ;
XfceDesktop *desktop = XFCE_DESKTOP(w);
if ((has_focus && !desktop->is_active) || (!has_focus && desktop->is_active)) {
g_object_notify(G_OBJECT(w), "active" );
}
return ret;
}
#ifdef ENABLE_DESKTOP_ICONS
static gboolean
style_refresh_cb(gpointer user_data)
{
XfceDesktop *desktop = user_data;
GList *children;
TRACE("entering" );
desktop->style_refresh_timer = 0 ;
g_return_val_if_fail(XFCE_IS_DESKTOP(desktop), FALSE );
if (!gtk_widget_get_realized(GTK_WIDGET(desktop)))
return FALSE ;
if (desktop->workspaces == NULL) {
return FALSE ;
}
gtk_widget_queue_draw(GTK_WIDGET(desktop));
children = gtk_container_get_children(GTK_CONTAINER(desktop));
for (GList *l = children; l != NULL; l = l->next) {
if (GTK_IS_WIDGET(l->data)) {
gtk_widget_reset_style(GTK_WIDGET(l->data));
}
}
g_list_free(children);
return FALSE ;
}
#endif
static void
xfce_desktop_style_updated(GtkWidget *w)
{
#ifdef ENABLE_DESKTOP_ICONS
XfceDesktop *desktop = XFCE_DESKTOP(w);
TRACE("entering" );
if (desktop->style_refresh_timer != 0 ) {
g_source_remove(desktop->style_refresh_timer);
}
desktop->style_refresh_timer = g_idle_add_full(G_PRIORITY_LOW,
style_refresh_cb,
desktop,
NULL);
#endif
GTK_WIDGET_CLASS(xfce_desktop_parent_class)->style_updated(w);
}
static gboolean
update_backdrop_workspace(XfceDesktop *desktop) {
TRACE("entering" );
if (desktop->workspace_group != NULL) {
desktop->active_workspace = xfw_workspace_group_get_active_workspace(desktop->workspace_group);
} else {
desktop->active_workspace = NULL;
}
XfwWorkspace *old_backdrop_workspace = desktop->backdrop_workspace;
if (desktop->single_workspace_mode && desktop->single_workspace != NULL) {
DBG("using single_workspace" );
desktop->backdrop_workspace = desktop->single_workspace;
} else if (desktop->active_workspace != NULL) {
DBG("using active_workspace" );
desktop->backdrop_workspace = desktop->active_workspace;
} else {
XfwWorkspace *lowest_workspace = NULL;
for (GList *l = desktop->workspaces; l != NULL; l = l->next) {
XfwWorkspace *workspace = XFW_WORKSPACE(l->data);
if (lowest_workspace == NULL ||
xfw_workspace_get_number(workspace) < xfw_workspace_get_number(lowest_workspace))
{
lowest_workspace = workspace;
}
}
DBG("using lowest_workspace" );
desktop->backdrop_workspace = lowest_workspace;
}
XF_DEBUG("new_active_workspace %d, new_backdrop_workspace %d" ,
desktop->active_workspace != NULL ? (gint)xfw_workspace_get_number(desktop->active_workspace) : -1 ,
desktop->backdrop_workspace != NULL ? (gint)xfw_workspace_get_number(desktop->backdrop_workspace) : -1 );
if (desktop->backdrop_workspace != old_backdrop_workspace || desktop->bg_surface == NULL) {
fetch_backdrop(desktop);
return TRUE ;
} else {
return FALSE ;
}
}
/* public api */
/**
* xfce_desktop_new :
* @ gscreen : The current # GdkScreen .
* @ monitor : # XfwMonitor to display the widget on .
* @ channel : An # XfconfChannel to use for settings .
* @ property_prefix : String prefix for per - screen properties .
* @ backdrop_manager : An # XfdesktopBackdropManager .
*
* Creates a new # XfceDesktop for the specified # GdkScreen . Settings
* will be fetched using @ channel . Per - screen / monitor settings will
* have @ property_prefix prepended to Xfconf property names .
*
* Return value : A new # XfceDesktop .
**/
GtkWidget *
xfce_desktop_new(GdkScreen *gscreen,
XfwMonitor *monitor,
XfconfChannel *channel,
const gchar *property_prefix,
XfdesktopBackdropManager *backdrop_manager)
{
g_return_val_if_fail(GDK_IS_SCREEN(gscreen), NULL);
g_return_val_if_fail(XFW_IS_MONITOR(monitor), NULL);
g_return_val_if_fail(channel == NULL || XFCONF_IS_CHANNEL(channel), NULL);
g_return_val_if_fail(property_prefix != NULL, NULL);
g_return_val_if_fail(XFDESKTOP_IS_BACKDROP_MANAGER(backdrop_manager), NULL);
return g_object_new(XFCE_TYPE_DESKTOP,
"screen" , gscreen,
"monitor" , monitor,
"channel" , channel,
"property-prefix" , property_prefix,
"backdrop-manager" , backdrop_manager,
NULL);
}
XfwMonitor *
xfce_desktop_get_monitor(XfceDesktop *desktop) {
g_return_val_if_fail(XFCE_IS_DESKTOP(desktop), NULL);
return desktop->monitor;
}
void
xfce_desktop_update_monitor(XfceDesktop *desktop, XfwMonitor *monitor) {
g_return_if_fail(XFCE_IS_DESKTOP(desktop));
g_return_if_fail(XFW_IS_MONITOR(monitor));
if (desktop->monitor != monitor) {
if (desktop->monitor != NULL) {
g_signal_handlers_disconnect_by_data(desktop->monitor, desktop);
g_object_unref(desktop->monitor);
}
desktop->monitor = g_object_ref(monitor);
g_signal_connect(monitor, "notify::logical-geometry" ,
G_CALLBACK(monitor_prop_changed), desktop);
g_signal_connect(monitor, "notify::scale" ,
G_CALLBACK(monitor_prop_changed), desktop);
if (gtk_widget_get_realized(GTK_WIDGET(desktop))) {
xfce_desktop_place_on_monitor(desktop);
fetch_backdrop(desktop);
}
g_object_notify(G_OBJECT(desktop), "monitor" );
}
}
static void
xfce_desktop_set_single_workspace_mode(XfceDesktop *desktop,
gboolean single_workspace)
{
g_return_if_fail(XFCE_IS_DESKTOP(desktop));
if (single_workspace != desktop->single_workspace_mode) {
desktop->single_workspace_mode = single_workspace;
XF_DEBUG("single_workspace_mode now %s" , single_workspace ? "TRUE" : "FALSE" );
update_backdrop_workspace(desktop);
}
}
static void
xfce_desktop_set_single_workspace_number(XfceDesktop *desktop,
gint workspace_num)
{
g_return_if_fail(XFCE_IS_DESKTOP(desktop));
if (workspace_num >= 0
&& (workspace_num != desktop->single_workspace_num
|| desktop->single_workspace == NULL))
{
if (workspace_num != desktop->single_workspace_num) {
XF_DEBUG("single_workspace_num now %d" , workspace_num);
}
desktop->single_workspace_num = workspace_num;
desktop->single_workspace = NULL;
for (GList *l = desktop->workspaces; l != NULL; l = l->next) {
XfwWorkspace *workspace = XFW_WORKSPACE(l->data);
if ((gint)xfw_workspace_get_number(workspace) == workspace_num) {
desktop->single_workspace = workspace;
break ;
}
}
update_backdrop_workspace(desktop);
}
}
void
xfce_desktop_freeze_updates(XfceDesktop *desktop)
{
g_return_if_fail(XFCE_IS_DESKTOP(desktop));
desktop->updates_frozen = TRUE ;
}
void
xfce_desktop_thaw_updates(XfceDesktop *desktop)
{
g_return_if_fail(XFCE_IS_DESKTOP(desktop));
if (desktop->updates_frozen) {
desktop->updates_frozen = FALSE ;
fetch_backdrop(desktop);
}
}
void
xfce_desktop_set_is_active(XfceDesktop *desktop, gboolean active) {
g_return_if_fail(XFCE_IS_DESKTOP(desktop));
if (active != desktop->is_active) {
desktop->is_active = active;
if (!gtk_window_has_toplevel_focus(GTK_WINDOW(desktop))) {
g_object_notify(G_OBJECT(desktop), "active" );
}
}
}
gboolean
xfce_desktop_is_active(XfceDesktop *desktop) {
g_return_val_if_fail(XFCE_IS_DESKTOP(desktop), FALSE );
return desktop->is_active
|| desktop->has_pointer
|| gtk_window_has_toplevel_focus(GTK_WINDOW(desktop));
}
void
xfce_desktop_refresh(XfceDesktop *desktop) {
g_return_if_fail(XFCE_IS_DESKTOP(desktop));
if (desktop->backdrop_workspace != NULL) {
fetch_backdrop(desktop);
}
}
void
xfce_desktop_cycle_backdrop(XfceDesktop *desktop) {
g_return_if_fail(XFCE_IS_DESKTOP(desktop));
if (desktop->backdrop_workspace != NULL) {
xfdesktop_backdrop_manager_cycle_backdrop(desktop->backdrop_manager,
desktop->monitor,
desktop->backdrop_workspace);
}
}
Messung V0.5 in Prozent C=89 H=93 G=90
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.22Bemerkung:
(vorverarbeitet am 2026-07-10)
¤
*© Formatika GbR, Deutschland