You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2570 lines
81 KiB
2570 lines
81 KiB
/*
|
|
* Copyright (C) 2009-2010 Nick Schermer <nick@xfce.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 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.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
#ifdef HAVE_STDIO_H
|
|
#include <stdio.h>
|
|
#endif
|
|
#ifdef HAVE_MATH_H
|
|
#include <math.h>
|
|
#endif
|
|
|
|
#ifdef GDK_WINDOWING_X11
|
|
#include <gdk/gdkx.h>
|
|
#include <X11/Xlib.h>
|
|
#endif
|
|
|
|
#include <exo/exo.h>
|
|
#include <common/panel-private.h>
|
|
#include <common/panel-debug.h>
|
|
#include <common/panel-utils.h>
|
|
#include <libxfce4panel/libxfce4panel.h>
|
|
#include <libxfce4panel/xfce-panel-plugin-provider.h>
|
|
#include <panel/panel-base-window.h>
|
|
#include <panel/panel-window.h>
|
|
#include <panel/panel-item-dialog.h>
|
|
#include <panel/panel-preferences-dialog.h>
|
|
#include <panel/panel-dialogs.h>
|
|
#include <panel/panel-dbus-service.h>
|
|
#include <panel/panel-plugin-external.h>
|
|
#include <panel/panel-plugin-external-46.h>
|
|
|
|
|
|
|
|
#define SNAP_DISTANCE (10)
|
|
#define SET_OLD_WM_STRUTS (FALSE)
|
|
#define DEFAULT_POPUP_DELAY (225)
|
|
#define DEFAULT_POPDOWN_DELAY (350)
|
|
#define HANDLE_SPACING (4)
|
|
#define HANDLE_DOTS (2)
|
|
#define HANDLE_PIXELS (2)
|
|
#define HANDLE_PIXEL_SPACE (1)
|
|
#define HANDLE_SIZE (HANDLE_DOTS * (HANDLE_PIXELS + \
|
|
HANDLE_PIXEL_SPACE) - HANDLE_PIXEL_SPACE)
|
|
#define HANDLE_SIZE_TOTAL (2 * HANDLE_SPACING + HANDLE_SIZE)
|
|
|
|
|
|
|
|
typedef enum _StrutsEgde StrutsEgde;
|
|
typedef enum _AutohideState AutohideState;
|
|
typedef enum _SnapPosition SnapPosition;
|
|
typedef enum _PluginProp PluginProp;
|
|
|
|
|
|
|
|
static void panel_window_get_property (GObject *object,
|
|
guint prop_id,
|
|
GValue *value,
|
|
GParamSpec *pspec);
|
|
static void panel_window_set_property (GObject *object,
|
|
guint prop_id,
|
|
const GValue *value,
|
|
GParamSpec *pspec);
|
|
static void panel_window_finalize (GObject *object);
|
|
static gboolean panel_window_expose_event (GtkWidget *widget,
|
|
GdkEventExpose *event);
|
|
static gboolean panel_window_enter_notify_event (GtkWidget *widget,
|
|
GdkEventCrossing *event);
|
|
static gboolean panel_window_leave_notify_event (GtkWidget *widget,
|
|
GdkEventCrossing *event);
|
|
static gboolean panel_window_drag_motion (GtkWidget *widget,
|
|
GdkDragContext *context,
|
|
gint x,
|
|
gint y,
|
|
guint drag_time);
|
|
static void panel_window_drag_leave (GtkWidget *widget,
|
|
GdkDragContext *context,
|
|
guint drag_time);
|
|
static gboolean panel_window_motion_notify_event (GtkWidget *widget,
|
|
GdkEventMotion *event);
|
|
static gboolean panel_window_button_press_event (GtkWidget *widget,
|
|
GdkEventButton *event);
|
|
static gboolean panel_window_button_release_event (GtkWidget *widget,
|
|
GdkEventButton *event);
|
|
static void panel_window_grab_notify (GtkWidget *widget,
|
|
gboolean was_grabbed);
|
|
static void panel_window_size_request (GtkWidget *widget,
|
|
GtkRequisition *requisition);
|
|
static void panel_window_size_allocate (GtkWidget *widget,
|
|
GtkAllocation *alloc);
|
|
static void panel_window_size_allocate_set_xy (PanelWindow *window,
|
|
gint window_width,
|
|
gint window_height,
|
|
gint *return_x,
|
|
gint *return_y);
|
|
static void panel_window_screen_changed (GtkWidget *widget,
|
|
GdkScreen *previous_screen);
|
|
static void panel_window_style_set (GtkWidget *widget,
|
|
GtkStyle *previous_style);
|
|
static void panel_window_realize (GtkWidget *widget);
|
|
static StrutsEgde panel_window_screen_struts_edge (PanelWindow *window);
|
|
static void panel_window_screen_struts_set (PanelWindow *window);
|
|
static void panel_window_screen_force_update (PanelWindow *window);
|
|
static void panel_window_screen_update_borders (PanelWindow *window);
|
|
static SnapPosition panel_window_snap_position (PanelWindow *window);
|
|
static void panel_window_display_layout_debug (GtkWidget *widget);
|
|
static void panel_window_screen_layout_changed (GdkScreen *screen,
|
|
PanelWindow *window);
|
|
static void panel_window_autohide_queue (PanelWindow *window,
|
|
AutohideState new_state);
|
|
static void panel_window_set_autohide (PanelWindow *window,
|
|
gboolean autohide);
|
|
static void panel_window_menu_popup (PanelWindow *window,
|
|
guint32 event_time);
|
|
static void panel_window_update_plugins (PanelWindow *window,
|
|
PluginProp prop);
|
|
static void panel_window_set_plugin_orientation (GtkWidget *widget,
|
|
gpointer user_data);
|
|
static void panel_window_set_plugin_size (GtkWidget *widget,
|
|
gpointer user_data);
|
|
static void panel_window_set_plugin_screen_position (GtkWidget *widget,
|
|
gpointer user_data);
|
|
|
|
|
|
|
|
enum
|
|
{
|
|
PROP_0,
|
|
PROP_HORIZONTAL,
|
|
PROP_SIZE,
|
|
PROP_LENGTH,
|
|
PROP_LENGTH_ADJUST,
|
|
PROP_POSITION_LOCKED,
|
|
PROP_AUTOHIDE,
|
|
PROP_SPAN_MONITORS,
|
|
PROP_OUTPUT_NAME,
|
|
PROP_POSITION,
|
|
PROP_DISABLE_STRUTS
|
|
};
|
|
|
|
enum _PluginProp
|
|
{
|
|
PLUGIN_PROP_ORIENTATION,
|
|
PLUGIN_PROP_SCREEN_POSITION,
|
|
PLUGIN_PROP_SIZE
|
|
};
|
|
|
|
enum _AutohideState
|
|
{
|
|
AUTOHIDE_DISABLED = 0, /* autohide is disabled */
|
|
AUTOHIDE_VISIBLE, /* visible */
|
|
AUTOHIDE_POPDOWN, /* visible, but hide timeout is running */
|
|
AUTOHIDE_POPDOWN_SLOW, /* same as popdown, but timeout is 4x longer */
|
|
AUTOHIDE_HIDDEN, /* invisible */
|
|
AUTOHIDE_POPUP, /* invisible, but show timeout is running */
|
|
AUTOHIDE_BLOCKED /* autohide is enabled, but blocked */
|
|
};
|
|
|
|
enum _SnapPosition
|
|
{
|
|
/* no snapping */
|
|
SNAP_POSITION_NONE, /* snapping */
|
|
|
|
/* right edge */
|
|
SNAP_POSITION_E, /* right */
|
|
SNAP_POSITION_NE, /* top right */
|
|
SNAP_POSITION_EC, /* right center */
|
|
SNAP_POSITION_SE, /* bottom right */
|
|
|
|
/* left edge */
|
|
SNAP_POSITION_W, /* left */
|
|
SNAP_POSITION_NW, /* top left */
|
|
SNAP_POSITION_WC, /* left center */
|
|
SNAP_POSITION_SW, /* bottom left */
|
|
|
|
/* top and bottom */
|
|
SNAP_POSITION_NC, /* top center */
|
|
SNAP_POSITION_SC, /* bottom center */
|
|
SNAP_POSITION_N, /* top */
|
|
SNAP_POSITION_S, /* bottom */
|
|
};
|
|
|
|
enum
|
|
{
|
|
EDGE_GRAVITY_NONE = 0,
|
|
EDGE_GRAVITY_START = (SNAP_POSITION_NE - SNAP_POSITION_E),
|
|
EDGE_GRAVITY_CENTER = (SNAP_POSITION_EC - SNAP_POSITION_E),
|
|
EDGE_GRAVITY_END = (SNAP_POSITION_SE - SNAP_POSITION_E)
|
|
};
|
|
|
|
enum _StrutsEgde
|
|
{
|
|
STRUTS_EDGE_NONE = 0,
|
|
STRUTS_EDGE_LEFT,
|
|
STRUTS_EDGE_RIGHT,
|
|
STRUTS_EDGE_TOP,
|
|
STRUTS_EDGE_BOTTOM
|
|
};
|
|
|
|
enum
|
|
{
|
|
STRUT_LEFT = 0,
|
|
STRUT_RIGHT,
|
|
STRUT_TOP,
|
|
STRUT_BOTTOM,
|
|
STRUT_LEFT_START_Y,
|
|
STRUT_LEFT_END_Y,
|
|
STRUT_RIGHT_START_Y,
|
|
STRUT_RIGHT_END_Y,
|
|
STRUT_TOP_START_X,
|
|
STRUT_TOP_END_X,
|
|
STRUT_BOTTOM_START_X,
|
|
STRUT_BOTTOM_END_X,
|
|
N_STRUTS
|
|
};
|
|
|
|
struct _PanelWindowClass
|
|
{
|
|
PanelBaseWindowClass __parent__;
|
|
};
|
|
|
|
struct _PanelWindow
|
|
{
|
|
PanelBaseWindow __parent__;
|
|
|
|
/* whether the user is allowed to make
|
|
* changes to this window */
|
|
guint locked : 1;
|
|
|
|
/* screen and working area of this panel */
|
|
GdkScreen *screen;
|
|
GdkRectangle area;
|
|
|
|
/* struts information */
|
|
StrutsEgde struts_edge;
|
|
gulong struts[N_STRUTS];
|
|
guint struts_disabled : 1;
|
|
|
|
/* window positioning */
|
|
guint size;
|
|
gdouble length;
|
|
guint length_adjust : 1;
|
|
guint horizontal : 1;
|
|
SnapPosition snap_position;
|
|
guint span_monitors : 1;
|
|
gchar *output_name;
|
|
|
|
/* allocated position of the panel */
|
|
GdkRectangle alloc;
|
|
|
|
/* autohiding */
|
|
GtkWidget *autohide_window;
|
|
AutohideState autohide_state;
|
|
guint autohide_timeout_id;
|
|
gint autohide_block;
|
|
gint autohide_grab_block;
|
|
|
|
/* popup/down delay from gtk style */
|
|
gint popup_delay;
|
|
gint popdown_delay;
|
|
|
|
/* whether the window position is locked */
|
|
guint position_locked : 1;
|
|
|
|
/* window base point */
|
|
gint base_x;
|
|
gint base_y;
|
|
|
|
/* window drag information */
|
|
guint32 grab_time;
|
|
gint grab_x;
|
|
gint grab_y;
|
|
};
|
|
|
|
/* used for a full XfcePanelWindow name in the class, but not in the code */
|
|
typedef PanelWindow XfcePanelWindow;
|
|
typedef PanelWindowClass XfcePanelWindowClass;
|
|
|
|
|
|
|
|
static GdkAtom cardinal_atom = 0;
|
|
#if SET_OLD_WM_STRUTS
|
|
static GdkAtom net_wm_strut_atom = 0;
|
|
#endif
|
|
static GdkAtom net_wm_strut_partial_atom = 0;
|
|
|
|
|
|
|
|
G_DEFINE_TYPE (XfcePanelWindow, panel_window, PANEL_TYPE_BASE_WINDOW)
|
|
|
|
|
|
|
|
static void
|
|
panel_window_class_init (PanelWindowClass *klass)
|
|
{
|
|
GObjectClass *gobject_class;
|
|
GtkWidgetClass *gtkwidget_class;
|
|
|
|
gobject_class = G_OBJECT_CLASS (klass);
|
|
gobject_class->get_property = panel_window_get_property;
|
|
gobject_class->set_property = panel_window_set_property;
|
|
gobject_class->finalize = panel_window_finalize;
|
|
|
|
gtkwidget_class = GTK_WIDGET_CLASS (klass);
|
|
gtkwidget_class->expose_event = panel_window_expose_event;
|
|
gtkwidget_class->enter_notify_event = panel_window_enter_notify_event;
|
|
gtkwidget_class->leave_notify_event = panel_window_leave_notify_event;
|
|
gtkwidget_class->drag_motion = panel_window_drag_motion;
|
|
gtkwidget_class->drag_leave = panel_window_drag_leave;
|
|
gtkwidget_class->motion_notify_event = panel_window_motion_notify_event;
|
|
gtkwidget_class->button_press_event = panel_window_button_press_event;
|
|
gtkwidget_class->button_release_event = panel_window_button_release_event;
|
|
gtkwidget_class->grab_notify = panel_window_grab_notify;
|
|
gtkwidget_class->size_request = panel_window_size_request;
|
|
gtkwidget_class->size_allocate = panel_window_size_allocate;
|
|
gtkwidget_class->screen_changed = panel_window_screen_changed;
|
|
gtkwidget_class->style_set = panel_window_style_set;
|
|
gtkwidget_class->realize = panel_window_realize;
|
|
|
|
g_object_class_install_property (gobject_class,
|
|
PROP_HORIZONTAL,
|
|
g_param_spec_boolean ("horizontal", NULL, NULL,
|
|
TRUE,
|
|
EXO_PARAM_READWRITE));
|
|
|
|
g_object_class_install_property (gobject_class,
|
|
PROP_SIZE,
|
|
g_param_spec_uint ("size", NULL, NULL,
|
|
16, 128, 48,
|
|
EXO_PARAM_READWRITE));
|
|
|
|
g_object_class_install_property (gobject_class,
|
|
PROP_LENGTH,
|
|
g_param_spec_uint ("length", NULL, NULL,
|
|
1, 100, 25,
|
|
EXO_PARAM_READWRITE));
|
|
|
|
g_object_class_install_property (gobject_class,
|
|
PROP_LENGTH_ADJUST,
|
|
g_param_spec_boolean ("length-adjust", NULL, NULL,
|
|
TRUE,
|
|
EXO_PARAM_READWRITE));
|
|
|
|
g_object_class_install_property (gobject_class,
|
|
PROP_POSITION_LOCKED,
|
|
g_param_spec_boolean ("position-locked", NULL, NULL,
|
|
FALSE,
|
|
EXO_PARAM_READWRITE));
|
|
|
|
g_object_class_install_property (gobject_class,
|
|
PROP_AUTOHIDE,
|
|
g_param_spec_boolean ("autohide", NULL, NULL,
|
|
FALSE,
|
|
EXO_PARAM_READWRITE));
|
|
|
|
g_object_class_install_property (gobject_class,
|
|
PROP_SPAN_MONITORS,
|
|
g_param_spec_boolean ("span-monitors", NULL, NULL,
|
|
FALSE,
|
|
EXO_PARAM_READWRITE));
|
|
|
|
g_object_class_install_property (gobject_class,
|
|
PROP_OUTPUT_NAME,
|
|
g_param_spec_string ("output-name", NULL, NULL,
|
|
NULL,
|
|
EXO_PARAM_READWRITE));
|
|
|
|
g_object_class_install_property (gobject_class,
|
|
PROP_POSITION,
|
|
g_param_spec_string ("position", NULL, NULL,
|
|
NULL,
|
|
EXO_PARAM_READWRITE));
|
|
|
|
g_object_class_install_property (gobject_class,
|
|
PROP_DISABLE_STRUTS,
|
|
g_param_spec_boolean ("disable-struts", NULL, NULL,
|
|
FALSE,
|
|
EXO_PARAM_READWRITE));
|
|
|
|
gtk_widget_class_install_style_property (gtkwidget_class,
|
|
g_param_spec_int ("popup-delay",
|
|
NULL,
|
|
"Time before the panel will unhide on an enter event",
|
|
1, G_MAXINT,
|
|
DEFAULT_POPUP_DELAY,
|
|
EXO_PARAM_READABLE));
|
|
|
|
gtk_widget_class_install_style_property (gtkwidget_class,
|
|
g_param_spec_int ("popdown-delay",
|
|
NULL,
|
|
"Time before the panel will hide on a leave event",
|
|
1, G_MAXINT,
|
|
DEFAULT_POPDOWN_DELAY,
|
|
EXO_PARAM_READABLE));
|
|
|
|
/* initialize the atoms */
|
|
cardinal_atom = gdk_atom_intern_static_string ("CARDINAL");
|
|
net_wm_strut_partial_atom = gdk_atom_intern_static_string ("_NET_WM_STRUT_PARTIAL");
|
|
#if SET_OLD_WM_STRUTS
|
|
net_wm_strut_atom = gdk_atom_intern_static_string ("_NET_WM_STRUT");
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
panel_window_init (PanelWindow *window)
|
|
{
|
|
window->locked = TRUE;
|
|
window->screen = NULL;
|
|
window->struts_edge = STRUTS_EDGE_NONE;
|
|
window->struts_disabled = FALSE;
|
|
window->horizontal = TRUE;
|
|
window->size = 30;
|
|
window->length = 0.10;
|
|
window->length_adjust = TRUE;
|
|
window->snap_position = SNAP_POSITION_NONE;
|
|
window->span_monitors = FALSE;
|
|
window->position_locked = FALSE;
|
|
window->autohide_state = AUTOHIDE_DISABLED;
|
|
window->autohide_timeout_id = 0;
|
|
window->autohide_block = 0;
|
|
window->autohide_grab_block = 0;
|
|
window->popup_delay = DEFAULT_POPUP_DELAY;
|
|
window->popdown_delay = DEFAULT_POPDOWN_DELAY;
|
|
window->base_x = -1;
|
|
window->base_y = -1;
|
|
window->grab_time = 0;
|
|
window->grab_x = 0;
|
|
window->grab_y = 0;
|
|
|
|
/* not resizable, so allocation will follow size request */
|
|
gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
|
|
|
|
/* set additional events */
|
|
gtk_widget_add_events (GTK_WIDGET (window), GDK_BUTTON_PRESS_MASK);
|
|
|
|
/* create a 'fake' drop zone for autohide drag motion */
|
|
gtk_drag_dest_set (GTK_WIDGET (window), 0, NULL, 0, 0);
|
|
|
|
/* set the screen */
|
|
panel_window_screen_changed (GTK_WIDGET (window), NULL);
|
|
|
|
/* watch changes in the compositing */
|
|
g_signal_connect (G_OBJECT (window), "notify::composited",
|
|
G_CALLBACK (panel_window_screen_force_update), NULL);
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
panel_window_get_property (GObject *object,
|
|
guint prop_id,
|
|
GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
PanelWindow *window = PANEL_WINDOW (object);
|
|
gchar *position;
|
|
|
|
switch (prop_id)
|
|
{
|
|
case PROP_HORIZONTAL:
|
|
g_value_set_boolean (value, window->horizontal);
|
|
break;
|
|
|
|
case PROP_SIZE:
|
|
g_value_set_uint (value, window->size);
|
|
break;
|
|
|
|
case PROP_LENGTH:
|
|
g_value_set_uint (value, rint (window->length * 100.00));
|
|
break;
|
|
|
|
case PROP_LENGTH_ADJUST:
|
|
g_value_set_boolean (value, window->length_adjust);
|
|
break;
|
|
|
|
case PROP_POSITION_LOCKED:
|
|
g_value_set_boolean (value, window->position_locked);
|
|
break;
|
|
|
|
case PROP_AUTOHIDE:
|
|
g_value_set_boolean (value, !!(window->autohide_state != AUTOHIDE_DISABLED));
|
|
break;
|
|
|
|
case PROP_SPAN_MONITORS:
|
|
g_value_set_boolean (value, window->span_monitors);
|
|
break;
|
|
|
|
case PROP_OUTPUT_NAME:
|
|
g_value_set_static_string (value, window->output_name);
|
|
break;
|
|
|
|
case PROP_POSITION:
|
|
position = g_strdup_printf ("p=%d;x=%d;y=%d",
|
|
window->snap_position,
|
|
window->base_x,
|
|
window->base_y);
|
|
g_value_take_string (value, position);
|
|
break;
|
|
|
|
case PROP_DISABLE_STRUTS:
|
|
g_value_set_boolean (value, window->struts_disabled);
|
|
break;
|
|
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
panel_window_set_property (GObject *object,
|
|
guint prop_id,
|
|
const GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
PanelWindow *window = PANEL_WINDOW (object);
|
|
gboolean val_bool;
|
|
guint val_uint;
|
|
gdouble val_double;
|
|
const gchar *val_string;
|
|
gboolean update = FALSE;
|
|
gint x, y, snap_position;
|
|
|
|
switch (prop_id)
|
|
{
|
|
case PROP_HORIZONTAL:
|
|
val_bool = g_value_get_boolean (value);
|
|
if (window->horizontal != val_bool)
|
|
{
|
|
window->horizontal = !!val_bool;
|
|
panel_window_screen_layout_changed (window->screen, window);
|
|
}
|
|
|
|
/* send the new orientation and screen position to the panel plugins */
|
|
panel_window_update_plugins (window, PLUGIN_PROP_ORIENTATION);
|
|
panel_window_update_plugins (window, PLUGIN_PROP_SCREEN_POSITION);
|
|
break;
|
|
|
|
case PROP_SIZE:
|
|
val_uint = g_value_get_uint (value);
|
|
if (window->size != val_uint)
|
|
{
|
|
window->size = val_uint;
|
|
gtk_widget_queue_resize (GTK_WIDGET (window));
|
|
}
|
|
|
|
/* send the new size to the panel plugins */
|
|
panel_window_update_plugins (window, PLUGIN_PROP_SIZE);
|
|
break;
|
|
|
|
case PROP_LENGTH:
|
|
val_double = g_value_get_uint (value) / 100.00;
|
|
if (window->length != val_double)
|
|
{
|
|
if (window->length == 1.00 || val_double == 1.00)
|
|
update = TRUE;
|
|
|
|
window->length = val_double;
|
|
|
|
if (update)
|
|
panel_window_screen_update_borders (window);
|
|
|
|
gtk_widget_queue_resize (GTK_WIDGET (window));
|
|
}
|
|
break;
|
|
|
|
case PROP_LENGTH_ADJUST:
|
|
val_bool = g_value_get_boolean (value);
|
|
if (window->length_adjust != val_bool)
|
|
{
|
|
window->length_adjust = !!val_bool;
|
|
gtk_widget_queue_resize (GTK_WIDGET (window));
|
|
}
|
|
break;
|
|
|
|
case PROP_POSITION_LOCKED:
|
|
val_bool = g_value_get_boolean (value);
|
|
if (window->position_locked != val_bool)
|
|
{
|
|
window->position_locked = !!val_bool;
|
|
gtk_widget_queue_resize (GTK_WIDGET (window));
|
|
}
|
|
break;
|
|
|
|
case PROP_AUTOHIDE:
|
|
panel_window_set_autohide (window, g_value_get_boolean (value));
|
|
break;
|
|
|
|
case PROP_SPAN_MONITORS:
|
|
val_bool = g_value_get_boolean (value);
|
|
if (window->span_monitors != val_bool)
|
|
{
|
|
window->span_monitors = !!val_bool;
|
|
panel_window_screen_layout_changed (window->screen, window);
|
|
}
|
|
break;
|
|
|
|
case PROP_OUTPUT_NAME:
|
|
g_free (window->output_name);
|
|
|
|
val_string = g_value_get_string (value);
|
|
if (exo_str_is_empty (val_string))
|
|
window->output_name = NULL;
|
|
else
|
|
window->output_name = g_strdup (val_string);
|
|
|
|
panel_window_screen_layout_changed (window->screen, window);
|
|
break;
|
|
|
|
case PROP_POSITION:
|
|
val_string = g_value_get_string (value);
|
|
if (!exo_str_is_empty (val_string)
|
|
&& sscanf (val_string, "p=%d;x=%d;y=%d", &snap_position, &x, &y) == 3)
|
|
{
|
|
window->snap_position = CLAMP (snap_position, SNAP_POSITION_NONE, SNAP_POSITION_S);
|
|
window->base_x = x;
|
|
window->base_y = y;
|
|
|
|
panel_window_screen_layout_changed (window->screen, window);
|
|
|
|
/* send the new screen position to the panel plugins */
|
|
panel_window_update_plugins (window, PLUGIN_PROP_SCREEN_POSITION);
|
|
}
|
|
else
|
|
{
|
|
g_message ("no valid position defined");
|
|
}
|
|
break;
|
|
|
|
case PROP_DISABLE_STRUTS:
|
|
val_bool = g_value_get_boolean (value);
|
|
if (val_bool != window->struts_disabled)
|
|
{
|
|
window->struts_disabled = val_bool;
|
|
panel_window_screen_layout_changed (window->screen, window);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
panel_window_finalize (GObject *object)
|
|
{
|
|
PanelWindow *window = PANEL_WINDOW (object);
|
|
|
|
/* stop running autohide timeout */
|
|
if (G_UNLIKELY (window->autohide_timeout_id != 0))
|
|
g_source_remove (window->autohide_timeout_id);
|
|
|
|
/* destroy the autohide window */
|
|
if (window->autohide_window != NULL)
|
|
gtk_widget_destroy (window->autohide_window);
|
|
|
|
g_free (window->output_name);
|
|
|
|
(*G_OBJECT_CLASS (panel_window_parent_class)->finalize) (object);
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
panel_window_expose_event (GtkWidget *widget,
|
|
GdkEventExpose *event)
|
|
{
|
|
PanelWindow *window = PANEL_WINDOW (widget);
|
|
cairo_t *cr;
|
|
GdkColor *color;
|
|
guint xx, yy, i;
|
|
gint xs, xe, ys, ye;
|
|
gint handle_w, handle_h;
|
|
gdouble alpha = 1.00;
|
|
GtkWidget *child;
|
|
|
|
/* expose the background and borders handled in PanelBaseWindow */
|
|
(*GTK_WIDGET_CLASS (panel_window_parent_class)->expose_event) (widget, event);
|
|
|
|
if (window->position_locked || !GTK_WIDGET_DRAWABLE (widget))
|
|
goto end;
|
|
|
|
if (window->horizontal)
|
|
{
|
|
handle_h = window->alloc.height / 2;
|
|
handle_w = HANDLE_SIZE;
|
|
|
|
xs = HANDLE_SPACING + 1;
|
|
xe = window->alloc.width - HANDLE_SIZE - HANDLE_SIZE;
|
|
ys = ye = (window->alloc.height - handle_h) / 2;
|
|
|
|
/* dirty check if we have to redraw the handles */
|
|
if (event->area.x > xs + HANDLE_SIZE
|
|
&& event->area.x + event->area.width < xe)
|
|
goto end;
|
|
}
|
|
else
|
|
{
|
|
handle_h = HANDLE_SIZE;
|
|
handle_w = window->alloc.width / 2;
|
|
|
|
xs = xe = (window->alloc.width - handle_w) / 2;
|
|
ys = HANDLE_SPACING + 1;
|
|
ye = window->alloc.height - HANDLE_SIZE - HANDLE_SIZE;
|
|
|
|
/* dirty check if we have to redraw the handles */
|
|
if (event->area.y > ys + HANDLE_SIZE
|
|
&& event->area.y + event->area.height < ye)
|
|
goto end;
|
|
}
|
|
|
|
/* create cairo context and set some default properties */
|
|
cr = gdk_cairo_create (widget->window);
|
|
panel_return_val_if_fail (cr != NULL, FALSE);
|
|
cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
|
|
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
|
|
|
|
/* clip the drawing area */
|
|
gdk_cairo_rectangle (cr, &event->area);
|
|
cairo_clip (cr);
|
|
|
|
/* alpha color */
|
|
if (PANEL_BASE_WINDOW (window)->is_composited)
|
|
alpha = MAX (0.50, PANEL_BASE_WINDOW (window)->background_alpha);
|
|
|
|
for (i = HANDLE_PIXELS; i >= HANDLE_PIXELS - 1; i--)
|
|
{
|
|
/* set the source color */
|
|
if (i == HANDLE_PIXELS)
|
|
color = &(widget->style->light[GTK_STATE_NORMAL]);
|
|
else
|
|
color = &(widget->style->dark[GTK_STATE_NORMAL]);
|
|
panel_util_set_source_rgba (cr, color, alpha);
|
|
|
|
/* draw the dots */
|
|
for (xx = 0; xx < (guint) handle_w; xx += HANDLE_PIXELS + HANDLE_PIXEL_SPACE)
|
|
for (yy = 0; yy < (guint) handle_h; yy += HANDLE_PIXELS + HANDLE_PIXEL_SPACE)
|
|
{
|
|
cairo_rectangle (cr, xs + xx, ys + yy, i, i);
|
|
cairo_rectangle (cr, xe + xx, ye + yy, i, i);
|
|
}
|
|
|
|
/* fill the rectangles */
|
|
cairo_fill (cr);
|
|
}
|
|
|
|
cairo_destroy (cr);
|
|
|
|
end:
|
|
/* send the expose event to the child */
|
|
child = gtk_bin_get_child (GTK_BIN (widget));
|
|
if (G_LIKELY (child != NULL))
|
|
gtk_container_propagate_expose (GTK_CONTAINER (widget), child, event);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
panel_window_enter_notify_event (GtkWidget *widget,
|
|
GdkEventCrossing *event)
|
|
{
|
|
PanelWindow *window = PANEL_WINDOW (widget);
|
|
|
|
/* update autohide status */
|
|
if (event->detail != GDK_NOTIFY_INFERIOR
|
|
&& window->autohide_state != AUTOHIDE_DISABLED)
|
|
{
|
|
/* stop a running autohide timeout */
|
|
if (window->autohide_timeout_id != 0)
|
|
g_source_remove (window->autohide_timeout_id);
|
|
|
|
/* update autohide status */
|
|
if (window->autohide_state == AUTOHIDE_POPDOWN)
|
|
window->autohide_state = AUTOHIDE_VISIBLE;
|
|
}
|
|
|
|
return (*GTK_WIDGET_CLASS (panel_window_parent_class)->enter_notify_event) (widget, event);
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
panel_window_leave_notify_event (GtkWidget *widget,
|
|
GdkEventCrossing *event)
|
|
{
|
|
PanelWindow *window = PANEL_WINDOW (widget);
|
|
|
|
/* queue an autohide timeout if needed */
|
|
if (event->detail != GDK_NOTIFY_INFERIOR
|
|
&& window->autohide_state != AUTOHIDE_DISABLED
|
|
&& window->autohide_state != AUTOHIDE_BLOCKED)
|
|
panel_window_autohide_queue (window, AUTOHIDE_POPDOWN);
|
|
|
|
return (*GTK_WIDGET_CLASS (panel_window_parent_class)->leave_notify_event) (widget, event);
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
panel_window_drag_motion (GtkWidget *widget,
|
|
GdkDragContext *context,
|
|
gint x,
|
|
gint y,
|
|
guint drag_time)
|
|
{
|
|
if ((*GTK_WIDGET_CLASS (panel_window_parent_class)->drag_motion) != NULL)
|
|
(*GTK_WIDGET_CLASS (panel_window_parent_class)->drag_motion) (widget, context, x, y, drag_time);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
panel_window_drag_leave (GtkWidget *widget,
|
|
GdkDragContext *context,
|
|
guint drag_time)
|
|
{
|
|
PanelWindow *window = PANEL_WINDOW (widget);
|
|
|
|
/* queue an autohide timeout if needed */
|
|
if (window->autohide_state == AUTOHIDE_VISIBLE)
|
|
panel_window_autohide_queue (window, AUTOHIDE_POPDOWN);
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
panel_window_motion_notify_event (GtkWidget *widget,
|
|
GdkEventMotion *event)
|
|
{
|
|
PanelWindow *window = PANEL_WINDOW (widget);
|
|
gint pointer_x, pointer_y;
|
|
gint window_x, window_y;
|
|
gint high;
|
|
|
|
/* leave when the pointer is not grabbed */
|
|
if (G_UNLIKELY (window->grab_time == 0))
|
|
return FALSE;
|
|
|
|
/* get the pointer position from the event */
|
|
pointer_x = event->x_root;
|
|
pointer_y = event->y_root;
|
|
|
|
/* check if the pointer moved to another monitor */
|
|
if (!window->span_monitors
|
|
&& (pointer_x < window->area.x
|
|
|| pointer_y < window->area.y
|
|
|| pointer_x > window->area.x + window->area.width
|
|
|| pointer_y > window->area.y + window->area.height))
|
|
{
|
|
/* set base point to cursor position and update working area */
|
|
window->base_x = pointer_x;
|
|
window->base_y = pointer_y;
|
|
panel_window_screen_layout_changed (window->screen, window);
|
|
}
|
|
|
|
/* calculate the new window position, but keep it inside the working geometry */
|
|
window_x = pointer_x - window->grab_x;
|
|
high = window->area.x + window->area.width - window->alloc.width;
|
|
window_x = CLAMP (window_x, window->area.x, high);
|
|
|
|
window_y = pointer_y - window->grab_y;
|
|
high = window->area.y + window->area.height - window->alloc.height;
|
|
window_y = CLAMP (window_y, window->area.y, high);
|
|
|
|
/* update the grab coordinates */
|
|
window->grab_x = pointer_x - window_x;
|
|
window->grab_y = pointer_y - window_y;
|
|
|
|
/* update the base coordinates */
|
|
window->base_x = window_x + window->alloc.width / 2;
|
|
window->base_y = window_y + window->alloc.height / 2;
|
|
|
|
/* update the allocation */
|
|
window->alloc.x = window_x;
|
|
window->alloc.y = window_y;
|
|
|
|
/* update the snapping position */
|
|
window->snap_position = panel_window_snap_position (window);
|
|
|
|
/* update the working area */
|
|
panel_window_screen_layout_changed (window->screen, window);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
panel_window_button_press_event (GtkWidget *widget,
|
|
GdkEventButton *event)
|
|
{
|
|
PanelWindow *window = PANEL_WINDOW (widget);
|
|
GdkCursor *cursor;
|
|
GdkGrabStatus status;
|
|
GdkDisplay *display;
|
|
guint modifiers;
|
|
|
|
/* leave if the event is not for this window */
|
|
if (event->window != widget->window)
|
|
goto end;
|
|
|
|
modifiers = event->state & gtk_accelerator_get_default_mod_mask ();
|
|
|
|
if (event->button == 1
|
|
&& event->type == GDK_BUTTON_PRESS
|
|
&& !window->position_locked
|
|
&& modifiers == 0)
|
|
{
|
|
panel_return_val_if_fail (window->grab_time == 0, FALSE);
|
|
|
|
/* create a cursor */
|
|
display = gdk_screen_get_display (window->screen);
|
|
cursor = gdk_cursor_new_for_display (display, GDK_FLEUR);
|
|
|
|
/* grab the pointer for dragging the window */
|
|
status = gdk_pointer_grab (event->window, FALSE,
|
|
GDK_BUTTON_MOTION_MASK
|
|
| GDK_BUTTON_RELEASE_MASK,
|
|
NULL, cursor, event->time);
|
|
|
|
gdk_cursor_unref (cursor);
|
|
|
|
/* set the grab info if the grab was successfully made */
|
|
if (G_LIKELY (status == GDK_GRAB_SUCCESS))
|
|
{
|
|
window->grab_time = event->time;
|
|
window->grab_x = event->x;
|
|
window->grab_y = event->y;
|
|
}
|
|
|
|
return !!(status == GDK_GRAB_SUCCESS);
|
|
}
|
|
else if (event->button == 3
|
|
|| (event->button == 1 && modifiers == GDK_CONTROL_MASK))
|
|
{
|
|
panel_window_menu_popup (window, event->time);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
end:
|
|
if (GTK_WIDGET_CLASS (panel_window_parent_class)->button_release_event != NULL)
|
|
return (*GTK_WIDGET_CLASS (panel_window_parent_class)->button_release_event) (widget, event);
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
panel_window_button_release_event (GtkWidget *widget,
|
|
GdkEventButton *event)
|
|
{
|
|
PanelWindow *window = PANEL_WINDOW (widget);
|
|
GdkDisplay *display;
|
|
|
|
panel_return_val_if_fail (PANEL_IS_WINDOW (window), FALSE);
|
|
|
|
if (window->grab_time != 0)
|
|
{
|
|
/* ungrab the pointer */
|
|
display = gdk_screen_get_display (window->screen);
|
|
gdk_display_pointer_ungrab (display, window->grab_time);
|
|
window->grab_time = 0;
|
|
|
|
/* store the new position */
|
|
g_object_notify (G_OBJECT (widget), "position");
|
|
|
|
/* send the new screen position to the panel plugins */
|
|
panel_window_update_plugins (window, PLUGIN_PROP_SCREEN_POSITION);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
if (GTK_WIDGET_CLASS (panel_window_parent_class)->button_release_event != NULL)
|
|
return (*GTK_WIDGET_CLASS (panel_window_parent_class)->button_release_event) (widget, event);
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
panel_window_grab_notify (GtkWidget *widget,
|
|
gboolean was_grabbed)
|
|
{
|
|
PanelWindow *window = PANEL_WINDOW (widget);
|
|
GtkWidget *current;
|
|
GdkScreen *screen;
|
|
gint x, y;
|
|
|
|
current = gtk_grab_get_current ();
|
|
if (GTK_IS_MENU_SHELL (current))
|
|
{
|
|
/* don't act on menu grabs, they should be registered through the
|
|
* plugin if they should block autohide */
|
|
window->autohide_grab_block++;
|
|
}
|
|
else if (window->autohide_grab_block > 0)
|
|
{
|
|
/* drop previous menu block or grab from outside window */
|
|
window->autohide_grab_block--;
|
|
}
|
|
else if (window->autohide_grab_block == 0)
|
|
{
|
|
if (current != NULL)
|
|
{
|
|
gdk_display_get_pointer (gtk_widget_get_display (current),
|
|
&screen, &x, &y, NULL);
|
|
|
|
/* filter out grab event that did not occur in the panel window,
|
|
* but in a windows that is part of this process */
|
|
if (gtk_window_get_screen (GTK_WINDOW (window)) != screen
|
|
|| x < window->alloc.x
|
|
|| x > window->alloc.x + window->alloc.width
|
|
|| y < window->alloc.y
|
|
|| y > window->alloc.y + window->alloc.height)
|
|
{
|
|
/* block the next notification */
|
|
window->autohide_grab_block++;
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* avoid hiding the panel when the window is grabbed. this
|
|
* (for example) happens when the user drags in the pager plugin
|
|
* see bug #4597 */
|
|
if (was_grabbed)
|
|
panel_window_thaw_autohide (window);
|
|
else
|
|
panel_window_freeze_autohide (window);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
panel_window_size_request (GtkWidget *widget,
|
|
GtkRequisition *requisition)
|
|
{
|
|
PanelWindow *window = PANEL_WINDOW (widget);
|
|
GtkRequisition child_requisition = { 0, 0 };
|
|
gint length;
|
|
gint extra_width = 0, extra_height = 0;
|
|
PanelBorders borders;
|
|
|
|
/* get the child requisition */
|
|
if (GTK_BIN (widget)->child != NULL)
|
|
gtk_widget_size_request (GTK_BIN (widget)->child, &child_requisition);
|
|
|
|
/* handle size */
|
|
if (!window->position_locked)
|
|
{
|
|
if (window->horizontal)
|
|
extra_width += 2 * HANDLE_SIZE_TOTAL;
|
|
else
|
|
extra_height += 2 * HANDLE_SIZE_TOTAL;
|
|
}
|
|
|
|
/* get the active borders */
|
|
borders = panel_base_window_get_borders (PANEL_BASE_WINDOW (window));
|
|
if (PANEL_HAS_FLAG (borders, PANEL_BORDER_LEFT))
|
|
extra_width++;
|
|
if (PANEL_HAS_FLAG (borders, PANEL_BORDER_RIGHT))
|
|
extra_width++;
|
|
if (PANEL_HAS_FLAG (borders, PANEL_BORDER_TOP))
|
|
extra_height++;
|
|
if (PANEL_HAS_FLAG (borders, PANEL_BORDER_BOTTOM))
|
|
extra_height++;
|
|
|
|
requisition->height = child_requisition.height + extra_height;
|
|
requisition->width = child_requisition.width + extra_width;
|
|
|
|
/* respect the length and monitor/screen size */
|
|
if (window->horizontal)
|
|
{
|
|
if (!window->length_adjust)
|
|
requisition->width = extra_width;
|
|
|
|
length = window->area.width * window->length;
|
|
requisition->width = CLAMP (requisition->width, length, window->area.width);
|
|
}
|
|
else
|
|
{
|
|
if (!window->length_adjust)
|
|
requisition->height = extra_height;
|
|
|
|
length = window->area.height * window->length;
|
|
requisition->height = CLAMP (requisition->height, length, window->area.height);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
panel_window_size_allocate (GtkWidget *widget,
|
|
GtkAllocation *alloc)
|
|
{
|
|
PanelWindow *window = PANEL_WINDOW (widget);
|
|
GtkAllocation child_alloc;
|
|
gint w, h, x, y;
|
|
PanelBorders borders;
|
|
GtkWidget *child;
|
|
|
|
widget->allocation = *alloc;
|
|
window->alloc = *alloc;
|
|
|
|
if (G_UNLIKELY (window->autohide_state == AUTOHIDE_HIDDEN
|
|
|| window->autohide_state == AUTOHIDE_POPUP))
|
|
{
|
|
/* window is invisible */
|
|
window->alloc.x = window->alloc.y = -9999;
|
|
|
|
/* set hidden window size */
|
|
w = h = 3;
|
|
if (window->horizontal)
|
|
w = alloc->width;
|
|
else
|
|
h = alloc->height;
|
|
|
|
/* position the autohide window */
|
|
panel_window_size_allocate_set_xy (window, w, h, &x, &y);
|
|
panel_base_window_move_resize (PANEL_BASE_WINDOW (window->autohide_window),
|
|
x, y, w, h);
|
|
}
|
|
else
|
|
{
|
|
/* update the allocation */
|
|
panel_window_size_allocate_set_xy (window, alloc->width,
|
|
alloc->height, &window->alloc.x, &window->alloc.y);
|
|
|
|
/* update the struts if needed, leave when nothing changed */
|
|
if (window->struts_edge != STRUTS_EDGE_NONE
|
|
&& window->autohide_state == AUTOHIDE_DISABLED)
|
|
panel_window_screen_struts_set (window);
|
|
|
|
/* move the autohide window offscreen */
|
|
if (window->autohide_window != NULL)
|
|
panel_base_window_move_resize (PANEL_BASE_WINDOW (window->autohide_window),
|
|
-9999, -9999, -1, -1);
|
|
}
|
|
|
|
gtk_window_move (GTK_WINDOW (window), window->alloc.x, window->alloc.y);
|
|
|
|
child = gtk_bin_get_child (GTK_BIN (widget));
|
|
if (G_LIKELY (child != NULL))
|
|
{
|
|
child_alloc.x = 0;
|
|
child_alloc.y = 0;
|
|
child_alloc.width = alloc->width;
|
|
child_alloc.height = alloc->height;
|
|
|
|
/* set position against the borders */
|
|
borders = panel_base_window_get_borders (PANEL_BASE_WINDOW (window));
|
|
if (PANEL_HAS_FLAG (borders, PANEL_BORDER_LEFT))
|
|
{
|
|
child_alloc.x++;
|
|
child_alloc.width--;
|
|
}
|
|
if (PANEL_HAS_FLAG (borders, PANEL_BORDER_TOP))
|
|
{
|
|
child_alloc.y++;
|
|
child_alloc.height--;
|
|
}
|
|
if (PANEL_HAS_FLAG (borders, PANEL_BORDER_RIGHT))
|
|
child_alloc.width--;
|
|
if (PANEL_HAS_FLAG (borders, PANEL_BORDER_BOTTOM))
|
|
child_alloc.height--;
|
|
|
|
/* keep space for the panel handles if not locked */
|
|
if (!window->position_locked)
|
|
{
|
|
if (window->horizontal)
|
|
{
|
|
child_alloc.width -= 2 * HANDLE_SIZE_TOTAL;
|
|
child_alloc.x += HANDLE_SIZE_TOTAL;
|
|
}
|
|
else
|
|
{
|
|
child_alloc.height -= 2 * HANDLE_SIZE_TOTAL;
|
|
child_alloc.y += HANDLE_SIZE_TOTAL;
|
|
}
|
|
}
|
|
|
|
/* allocate the itembar */
|
|
gtk_widget_size_allocate (child, &child_alloc);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
panel_window_size_allocate_set_xy (PanelWindow *window,
|
|
gint window_width,
|
|
gint window_height,
|
|
gint *return_x,
|
|
gint *return_y)
|
|
{
|
|
gint value, hight;
|
|
|
|
/* x-position */
|
|
switch (window->snap_position)
|
|
{
|
|
case SNAP_POSITION_NONE:
|
|
case SNAP_POSITION_N:
|
|
case SNAP_POSITION_S:
|
|
/* clamp base point on screen */
|
|
value = window->base_x - (window_width / 2);
|
|
hight = window->area.x + window->area.width - window_width;
|
|
*return_x = CLAMP (value, window->area.x, hight);
|
|
break;
|
|
|
|
case SNAP_POSITION_W:
|
|
case SNAP_POSITION_NW:
|
|
case SNAP_POSITION_WC:
|
|
case SNAP_POSITION_SW:
|
|
/* left */
|
|
*return_x = window->area.x;
|
|
break;
|
|
|
|
case SNAP_POSITION_E:
|
|
case SNAP_POSITION_NE:
|
|
case SNAP_POSITION_EC:
|
|
case SNAP_POSITION_SE:
|
|
/* right */
|
|
*return_x = window->area.x + window->area.width - window_width;
|
|
break;
|
|
|
|
case SNAP_POSITION_NC:
|
|
case SNAP_POSITION_SC:
|
|
/* center */
|
|
*return_x = window->area.x + (window->area.width - window_width) / 2;
|
|
break;
|
|
}
|
|
|
|
/* y-position */
|
|
switch (window->snap_position)
|
|
{
|
|
case SNAP_POSITION_NONE:
|
|
case SNAP_POSITION_E:
|
|
case SNAP_POSITION_W:
|
|
/* clamp base point on screen */
|
|
value = window->base_y - (window_height / 2);
|
|
hight = window->area.y + window->area.height - window_height;
|
|
*return_y = CLAMP (value, window->area.y, hight);
|
|
break;
|
|
|
|
case SNAP_POSITION_NE:
|
|
case SNAP_POSITION_NW:
|
|
case SNAP_POSITION_NC:
|
|
case SNAP_POSITION_N:
|
|
/* top */
|
|
*return_y = window->area.y;
|
|
break;
|
|
|
|
case SNAP_POSITION_SE:
|
|
case SNAP_POSITION_SW:
|
|
case SNAP_POSITION_SC:
|
|
case SNAP_POSITION_S:
|
|
/* bottom */
|
|
*return_y = window->area.y + window->area.height - window_height;
|
|
break;
|
|
|
|
case SNAP_POSITION_EC:
|
|
case SNAP_POSITION_WC:
|
|
/* center */
|
|
*return_y = window->area.y + (window->area.height - window_height) / 2;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
panel_window_screen_changed (GtkWidget *widget,
|
|
GdkScreen *previous_screen)
|
|
{
|
|
PanelWindow *window = PANEL_WINDOW (widget);
|
|
GdkScreen *screen;
|
|
|
|
/* get the new screen */
|
|
screen = gtk_window_get_screen (GTK_WINDOW (widget));
|
|
panel_return_if_fail (GDK_IS_SCREEN (screen));
|
|
if (G_UNLIKELY (window->screen == screen))
|
|
return;
|
|
|
|
/* disconnect from previous screen */
|
|
if (G_UNLIKELY (window->screen != NULL))
|
|
g_signal_handlers_disconnect_by_func (G_OBJECT (window->screen),
|
|
panel_window_screen_layout_changed, window);
|
|
|
|
/* set the new screen */
|
|
window->screen = screen;
|
|
g_signal_connect (G_OBJECT (window->screen), "monitors-changed",
|
|
G_CALLBACK (panel_window_screen_layout_changed), window);
|
|
g_signal_connect (G_OBJECT (window->screen), "size-changed",
|
|
G_CALLBACK (panel_window_screen_layout_changed), window);
|
|
|
|
/* set new output name */
|
|
if (gdk_display_get_n_screens (gdk_screen_get_display (screen)) > 1)
|
|
{
|
|
g_free (window->output_name);
|
|
window->output_name = g_strdup_printf ("screen-%d", gdk_screen_get_number (screen));
|
|
}
|
|
|
|
/* update the screen layout */
|
|
panel_window_screen_layout_changed (screen, window);
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
panel_window_style_set (GtkWidget *widget,
|
|
GtkStyle *previous_style)
|
|
{
|
|
PanelWindow *window = PANEL_WINDOW (widget);
|
|
|
|
/* let gtk update the widget style */
|
|
(*GTK_WIDGET_CLASS (panel_window_parent_class)->style_set) (widget, previous_style);
|
|
|
|
gtk_widget_style_get (GTK_WIDGET (widget),
|
|
"popup-delay", &window->popup_delay,
|
|
"popdown-delay", &window->popdown_delay,
|
|
NULL);
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
panel_window_realize (GtkWidget *widget)
|
|
{
|
|
PanelWindow *window = PANEL_WINDOW (widget);
|
|
|
|
(*GTK_WIDGET_CLASS (panel_window_parent_class)->realize) (widget);
|
|
|
|
/* set struts if we snap to an edge */
|
|
if (window->struts_edge != STRUTS_EDGE_NONE)
|
|
panel_window_screen_struts_set (window);
|
|
}
|
|
|
|
|
|
|
|
static StrutsEgde
|
|
panel_window_screen_struts_edge (PanelWindow *window)
|
|
{
|
|
panel_return_val_if_fail (PANEL_IS_WINDOW (window), STRUTS_EDGE_NONE);
|
|
|
|
/* no struts when autohide is active or they are disabled by the user */
|
|
if (window->autohide_state != AUTOHIDE_DISABLED
|
|
|| window->struts_disabled)
|
|
return STRUTS_EDGE_NONE;
|
|
|
|
/* return the screen edge on which the window is
|
|
* visually snapped and where the struts are set */
|
|
switch (window->snap_position)
|
|
{
|
|
case SNAP_POSITION_NONE:
|
|
return STRUTS_EDGE_NONE;
|
|
|
|
case SNAP_POSITION_E:
|
|
case SNAP_POSITION_EC:
|
|
return window->horizontal ? STRUTS_EDGE_NONE : STRUTS_EDGE_RIGHT;
|
|
|
|
case SNAP_POSITION_NE:
|
|
return window->horizontal ? STRUTS_EDGE_TOP : STRUTS_EDGE_RIGHT;
|
|
|
|
case SNAP_POSITION_SE:
|
|
return window->horizontal ? STRUTS_EDGE_BOTTOM : STRUTS_EDGE_RIGHT;
|
|
|
|
case SNAP_POSITION_W:
|
|
case SNAP_POSITION_WC:
|
|
return window->horizontal ? STRUTS_EDGE_NONE : STRUTS_EDGE_LEFT;
|
|
|
|
case SNAP_POSITION_NW:
|
|
return window->horizontal ? STRUTS_EDGE_TOP : STRUTS_EDGE_LEFT;
|
|
|
|
case SNAP_POSITION_SW:
|
|
return window->horizontal ? STRUTS_EDGE_BOTTOM : STRUTS_EDGE_LEFT;
|
|
|
|
case SNAP_POSITION_NC:
|
|
case SNAP_POSITION_N:
|
|
return window->horizontal ? STRUTS_EDGE_TOP : STRUTS_EDGE_NONE;
|
|
|
|
case SNAP_POSITION_SC:
|
|
case SNAP_POSITION_S:
|
|
return window->horizontal ? STRUTS_EDGE_BOTTOM : STRUTS_EDGE_NONE;
|
|
}
|
|
|
|
return STRUTS_EDGE_NONE;
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
panel_window_screen_struts_set (PanelWindow *window)
|
|
{
|
|
gulong struts[N_STRUTS] = { 0, };
|
|
GdkRectangle *alloc = &window->alloc;
|
|
guint i;
|
|
gboolean update_struts = FALSE;
|
|
gint n;
|
|
const gchar *strut_border[] = { "left", "right", "top", "bottom" };
|
|
const gchar *strut_xy[] = { "y", "y", "x", "x" };
|
|
|
|
panel_return_if_fail (PANEL_IS_WINDOW (window));
|
|
panel_return_if_fail (cardinal_atom != 0 && net_wm_strut_partial_atom != 0);
|
|
panel_return_if_fail (GDK_IS_SCREEN (window->screen));
|
|
|
|
if (!GTK_WIDGET_REALIZED (window))
|
|
return;
|
|
|
|
/* set the struts */
|
|
/* note that struts are relative to the screen edge! */
|
|
if (window->struts_edge == STRUTS_EDGE_TOP)
|
|
{
|
|
/* the window is snapped on the top screen edge */
|
|
struts[STRUT_TOP] = alloc->y + alloc->height;
|
|
struts[STRUT_TOP_START_X] = alloc->x;
|
|
struts[STRUT_TOP_END_X] = alloc->x + alloc->width;
|
|
}
|
|
else if (window->struts_edge == STRUTS_EDGE_BOTTOM)
|
|
{
|
|
/* the window is snapped on the bottom screen edge */
|
|
struts[STRUT_BOTTOM] = gdk_screen_get_height (window->screen) - alloc->y;
|
|
struts[STRUT_BOTTOM_START_X] = alloc->x;
|
|
struts[STRUT_BOTTOM_END_X] = alloc->x + alloc->width;
|
|
}
|
|
else if (window->struts_edge == STRUTS_EDGE_LEFT)
|
|
{
|
|
/* the window is snapped on the left screen edge */
|
|
struts[STRUT_LEFT] = alloc->x + alloc->width;
|
|
struts[STRUT_LEFT_START_Y] = alloc->y;
|
|
struts[STRUT_LEFT_END_Y] = alloc->y + alloc->height;
|
|
}
|
|
else if (window->struts_edge == STRUTS_EDGE_RIGHT)
|
|
{
|
|
/* the window is snapped on the right screen edge */
|
|
struts[STRUT_RIGHT] = gdk_screen_get_width (window->screen) - alloc->x;
|
|
struts[STRUT_RIGHT_START_Y] = alloc->y;
|
|
struts[STRUT_RIGHT_END_Y] = alloc->y + alloc->height;
|
|
}
|
|
|
|
/* store the new struts */
|
|
for (i = 0; i < N_STRUTS; i++)
|
|
{
|
|
/* check if we need to update */
|
|
if (G_LIKELY (struts[i] == window->struts[i]))
|
|
continue;
|
|
|
|
/* set new value */
|
|
update_struts = TRUE;
|
|
window->struts[i] = struts[i];
|
|
}
|
|
|
|
/* leave when there is nothing to update */
|
|
if (!update_struts)
|
|
return;
|
|
|
|
/* don't crash on x errors */
|
|
gdk_error_trap_push ();
|
|
|
|
/* set the wm strut partial */
|
|
panel_return_if_fail (GDK_IS_WINDOW (GTK_WIDGET (window)->window));
|
|
gdk_property_change (GTK_WIDGET (window)->window,
|
|
net_wm_strut_partial_atom,
|
|
cardinal_atom, 32, GDK_PROP_MODE_REPLACE,
|
|
(guchar *) &struts, N_STRUTS);
|
|
|
|
#if SET_OLD_WM_STRUTS
|
|
/* set the wm strut (old window managers) */
|
|
gdk_property_change (GTK_WIDGET (window)->window,
|
|
net_wm_strut_atom,
|
|
cardinal_atom, 32, GDK_PROP_MODE_REPLACE,
|
|
(guchar *) &struts, 4);
|
|
#endif
|
|
|
|
/* release the trap */
|
|
if (gdk_error_trap_pop () != 0)
|
|
g_critical ("Failed to set the struts");
|
|
|
|
if (panel_debug_has_domain (PANEL_DEBUG_YES))
|
|
{
|
|
n = -1;
|
|
|
|
if (struts[STRUT_LEFT] != 0)
|
|
n = STRUT_LEFT;
|
|
else if (struts[STRUT_RIGHT] != 0)
|
|
n = STRUT_RIGHT;
|
|
else if (struts[STRUT_TOP] != 0)
|
|
n = STRUT_TOP;
|
|
else if (struts[STRUT_BOTTOM] != 0)
|
|
n = STRUT_BOTTOM;
|
|
else
|
|
panel_debug (PANEL_DEBUG_STRUTS, "unset");
|
|
|
|
if (n != -1)
|
|
{
|
|
panel_debug (PANEL_DEBUG_STRUTS,
|
|
"%s=%ld, start_%s=%ld, end_%s=%ld",
|
|
strut_border[n], struts[n],
|
|
strut_xy[n], struts[4 + n * 2],
|
|
strut_xy[n], struts[5 + n * 2]);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
panel_window_screen_force_update (PanelWindow *window)
|
|
{
|
|
panel_return_if_fail (PANEL_IS_WINDOW (window));
|
|
|
|
if (GTK_WIDGET_VISIBLE (window))
|
|
{
|
|
/* make sure the struts are set again, when enabled */
|
|
if (window->struts_edge != STRUTS_EDGE_NONE
|
|
&& window->autohide_state == AUTOHIDE_DISABLED)
|
|
window->struts[0] = -1;
|
|
|
|
/* update the panel position */
|
|
panel_window_screen_layout_changed (window->screen, window);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
panel_window_screen_update_borders (PanelWindow *window)
|
|
{
|
|
PanelBorders borders = PANEL_BORDER_NONE;
|
|
|
|
panel_return_if_fail (PANEL_IS_WINDOW (window));
|
|
|
|
switch (window->snap_position)
|
|
{
|
|
case SNAP_POSITION_NONE:
|
|
borders = PANEL_BORDER_TOP | PANEL_BORDER_BOTTOM
|
|
| PANEL_BORDER_LEFT | PANEL_BORDER_RIGHT;
|
|
break;
|
|
|
|
case SNAP_POSITION_E:
|
|
case SNAP_POSITION_EC:
|
|
borders = PANEL_BORDER_TOP | PANEL_BORDER_BOTTOM
|
|
| PANEL_BORDER_LEFT;
|
|
break;
|
|
|
|
case SNAP_POSITION_W:
|
|
case SNAP_POSITION_WC:
|
|
borders = PANEL_BORDER_TOP | PANEL_BORDER_BOTTOM
|
|
| PANEL_BORDER_RIGHT;
|
|
break;
|
|
|
|
case SNAP_POSITION_N:
|
|
case SNAP_POSITION_NC:
|
|
borders = PANEL_BORDER_BOTTOM | PANEL_BORDER_LEFT
|
|
| PANEL_BORDER_RIGHT;
|
|
break;
|
|
|
|
case SNAP_POSITION_S:
|
|
case SNAP_POSITION_SC:
|
|
borders = PANEL_BORDER_TOP | PANEL_BORDER_LEFT
|
|
| PANEL_BORDER_RIGHT;
|
|
break;
|
|
|
|
case SNAP_POSITION_NE:
|
|
|
|
borders = PANEL_BORDER_BOTTOM | PANEL_BORDER_LEFT;
|
|
break;
|
|
|
|
case SNAP_POSITION_SE:
|
|
borders = PANEL_BORDER_LEFT | PANEL_BORDER_TOP;
|
|
break;
|
|
|
|
case SNAP_POSITION_NW:
|
|
borders = PANEL_BORDER_RIGHT | PANEL_BORDER_BOTTOM;
|
|
break;
|
|
|
|
case SNAP_POSITION_SW:
|
|
borders = PANEL_BORDER_RIGHT | PANEL_BORDER_TOP;
|
|
break;
|
|
}
|
|
|
|
/* don't show the side borders if the length is 100% */
|
|
if (window->length == 1.00)
|
|
{
|
|
if (window->horizontal)
|
|
PANEL_UNSET_FLAG (borders, PANEL_BORDER_LEFT | PANEL_BORDER_RIGHT);
|
|
else
|
|
PANEL_UNSET_FLAG (borders, PANEL_BORDER_TOP | PANEL_BORDER_BOTTOM);
|
|
}
|
|
|
|
/* set the borders */
|
|
panel_base_window_set_borders (PANEL_BASE_WINDOW (window), borders);
|
|
}
|
|
|
|
|
|
|
|
static inline guint
|
|
panel_window_snap_edge_gravity (gint value,
|
|
gint start,
|
|
gint end)
|
|
{
|
|
gint center;
|
|
|
|
/* snap at the start */
|
|
if (value >= start && value <= start + SNAP_DISTANCE)
|
|
return EDGE_GRAVITY_START;
|
|
|
|
/* snap at the end */
|
|
if (value <= end && value >= end - SNAP_DISTANCE)
|
|
return EDGE_GRAVITY_END;
|
|
|
|
/* snap at the center */
|
|
center = start + (end - start) / 2;
|
|
if (value >= center - 10 && value <= center + SNAP_DISTANCE)
|
|
return EDGE_GRAVITY_CENTER;
|
|
|
|
return EDGE_GRAVITY_NONE;
|
|
}
|
|
|
|
|
|
|
|
static SnapPosition
|
|
panel_window_snap_position (PanelWindow *window)
|
|
{
|
|
guint snap_horz, snap_vert;
|
|
GdkRectangle *alloc = &window->alloc;
|
|
|
|
/* get the snap offsets */
|
|
snap_horz = panel_window_snap_edge_gravity (alloc->x, window->area.x,
|
|
window->area.x + window->area.width - alloc->width);
|
|
snap_vert = panel_window_snap_edge_gravity (alloc->y, window->area.y,
|
|
window->area.y + window->area.height - alloc->height);
|
|
|
|
/* detect the snap mode */
|
|
if (snap_horz == EDGE_GRAVITY_START)
|
|
return SNAP_POSITION_W + snap_vert;
|
|
else if (snap_horz == EDGE_GRAVITY_END)
|
|
return SNAP_POSITION_E + snap_vert;
|
|
else if (snap_horz == EDGE_GRAVITY_CENTER && snap_vert == EDGE_GRAVITY_START)
|
|
return SNAP_POSITION_NC;
|
|
else if (snap_horz == EDGE_GRAVITY_CENTER && snap_vert == EDGE_GRAVITY_END)
|
|
return SNAP_POSITION_SC;
|
|
else if (snap_horz == EDGE_GRAVITY_NONE && snap_vert == EDGE_GRAVITY_START)
|
|
return SNAP_POSITION_N;
|
|
else if (snap_horz == EDGE_GRAVITY_NONE && snap_vert == EDGE_GRAVITY_END)
|
|
return SNAP_POSITION_S;
|
|
|
|
return SNAP_POSITION_NONE;
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
panel_window_display_layout_debug (GtkWidget *widget)
|
|
{
|
|
GdkDisplay *display;
|
|
GdkScreen *screen;
|
|
gint n, n_screens;
|
|
gint m, n_monitors;
|
|
GdkRectangle rect;
|
|
GString *str;
|
|
gchar *name;
|
|
|
|
panel_return_if_fail (GTK_IS_WIDGET (widget));
|
|
panel_return_if_fail (panel_debug_has_domain (PANEL_DEBUG_YES));
|
|
|
|
str = g_string_new (NULL);
|
|
|
|
display = gtk_widget_get_display (widget);
|
|
|
|
n_screens = gdk_display_get_n_screens (display);
|
|
for (n = 0; n < n_screens; n++)
|
|
{
|
|
screen = gdk_display_get_screen (display, n);
|
|
g_string_append_printf (str, "screen-%d=[%d,%d] (", n,
|
|
gdk_screen_get_width (screen), gdk_screen_get_height (screen));
|
|
|
|
n_monitors = gdk_screen_get_n_monitors (screen);
|
|
for (m = 0; m < n_monitors; m++)
|
|
{
|
|
name = gdk_screen_get_monitor_plug_name (screen, m);
|
|
if (name == NULL)
|
|
name = g_strdup_printf ("monitor-%d", m);
|
|
|
|
gdk_screen_get_monitor_geometry (screen, m, &rect);
|
|
g_string_append_printf (str, "%s=[%d,%d;%d,%d]", name,
|
|
rect.x, rect.y, rect.width, rect.height);
|
|
|
|
g_free (name);
|
|
|
|
if (m < n_monitors - 1)
|
|
g_string_append (str, ", ");
|
|
}
|
|
|
|
g_string_append (str, ")");
|
|
if (n < n_screens - 1)
|
|
g_string_append (str, ", ");
|
|
}
|
|
|
|
panel_debug (PANEL_DEBUG_DISPLAY_LAYOUT,
|
|
"display %s: %s",
|
|
gdk_display_get_name (display), str->str);
|
|
|
|
g_string_free (str, TRUE);
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
panel_window_screen_layout_changed (GdkScreen *screen,
|
|
PanelWindow *window)
|
|
{
|
|
GdkRectangle a, b;
|
|
gint monitor_num, n_monitors, n;
|
|
gint dest_x, dest_y;
|
|
gint dest_w, dest_h;
|
|
gchar *name;
|
|
StrutsEgde struts_edge;
|
|
gboolean force_struts_update = FALSE;
|
|
gint screen_num;
|
|
GdkDisplay *display;
|
|
|
|
panel_return_if_fail (PANEL_IS_WINDOW (window));
|
|
panel_return_if_fail (GDK_IS_SCREEN (screen));
|
|
panel_return_if_fail (window->screen == screen);
|
|
|
|
/* leave when the screen position if not set */
|
|
if (window->base_x == -1 && window->base_y == -1)
|
|
return;
|
|
|
|
/* print the display layout when debugging is enabled */
|
|
if (G_UNLIKELY (panel_debug_has_domain (PANEL_DEBUG_YES)))
|
|
panel_window_display_layout_debug (GTK_WIDGET (window));
|
|
|
|
/* update the struts edge of this window and check if we need to force
|
|
* a struts update (ie. remove struts that are currently set) */
|
|
struts_edge = panel_window_screen_struts_edge (window);
|
|
if (window->struts_edge != struts_edge && struts_edge == STRUTS_EDGE_NONE)
|
|
force_struts_update = TRUE;
|
|
window->struts_edge = struts_edge;
|
|
|
|
/* get the number of monitors */
|
|
n_monitors = gdk_screen_get_n_monitors (screen);
|
|
panel_return_if_fail (n_monitors > 0);
|
|
|
|
panel_debug (PANEL_DEBUG_POSITIONING,
|
|
"monitors=%d, output-name=%s, span-monitors=%s, base=%d,%d",
|
|
n_monitors, window->output_name,
|
|
PANEL_DEBUG_BOOL (window->span_monitors),
|
|
window->base_x, window->base_y);
|
|
|
|
if (window->output_name == NULL
|
|
&& (window->span_monitors || n_monitors == 1))
|
|
{
|
|
get_screen_geometry:
|
|
|
|
/* get the screen geometry we also use this if there is only
|
|
* one monitor and no output is choosen, as a fast-path */
|
|
a.x = a.y = 0;
|
|
a.width = gdk_screen_get_width (screen);
|
|
a.height = gdk_screen_get_height (screen);
|
|
panel_return_if_fail (a.width > 0 && a.height > 0);
|
|
}
|
|
else if (window->output_name != NULL
|
|
&& strncmp (window->output_name, "screen-", 7) == 0
|
|
&& sscanf (window->output_name, "screen-%d", &screen_num) == 1)
|
|
{
|
|
/* check if the panel is on the correct screen */
|
|
if (gdk_screen_get_number (screen) != screen_num)
|
|
{
|
|
display = gdk_screen_get_display (screen);
|
|
if (gdk_display_get_n_screens (display) - 1 < screen_num)
|
|
{
|
|
panel_debug (PANEL_DEBUG_POSITIONING,
|
|
"screen-%d not found, hiding panel", screen_num);
|
|
|
|
/* out of range, hide the window */
|
|
if (GTK_WIDGET_VISIBLE (window))
|
|
gtk_widget_hide (GTK_WIDGET (window));
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
panel_debug (PANEL_DEBUG_POSITIONING,
|
|
"moving panel from screen %d to %d",
|
|
gdk_screen_get_number (screen),
|
|
screen_num);
|
|
|
|
/* move window to the correct screen */
|
|
screen = gdk_display_get_screen (display, screen_num);
|
|
gtk_window_set_screen (GTK_WINDOW (window), screen);
|
|
|
|
/* we will invoke this function again when the screen
|
|
* changes, so bail out */
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* screen is correct, get geometry and continue */
|
|
goto get_screen_geometry;
|
|
}
|
|
else
|
|
{
|
|
if (exo_str_is_empty (window->output_name))
|
|
{
|
|
normal_monitor_positioning:
|
|
|
|
/* get the monitor geometry based on the panel position */
|
|
monitor_num = gdk_screen_get_monitor_at_point (screen, window->base_x,
|
|
window->base_y);
|
|
gdk_screen_get_monitor_geometry (screen, monitor_num, &a);
|
|
panel_return_if_fail (a.width > 0 && a.height > 0);
|
|
}
|
|
else
|
|
{
|
|
/* check if we've stored the monitor number in the config or
|
|
* should lookup the number from the randr output name */
|
|
if (strncmp (window->output_name, "monitor-", 8) == 0
|
|
&& sscanf (window->output_name, "monitor-%d", &monitor_num) == 1)
|
|
{
|
|
/* check if extracted monitor number is out of range */
|
|
if (n_monitors - 1 < monitor_num)
|
|
monitor_num = -1;
|
|
}
|
|
else
|
|
{
|
|
/* detect the monitor number by output name */
|
|
for (n = 0, monitor_num = -1; n < n_monitors && monitor_num == -1; n++)
|
|
{
|
|
name = gdk_screen_get_monitor_plug_name (screen, n);
|
|
|
|
/* check if this driver supports output names */
|
|
if (G_UNLIKELY (name == NULL))
|
|
{
|
|
/* print a warnings why this went wrong */
|
|
g_message ("An output is set on the panel window (%s), "
|
|
"but it looks like the driver does not "
|
|
"support output names. Falling back to normal "
|
|
"monitor positioning, you have to set the output "
|
|
"again in the preferences to activate this feature.",
|
|
window->output_name);
|
|
|
|
/* unset the output name */
|
|
g_free (window->output_name);
|
|
window->output_name = NULL;
|
|
|
|
/* fall back to normal positioning */
|
|
goto normal_monitor_positioning;
|
|
}
|
|
|
|
/* check if this is the monitor we're looking for */
|
|
if (strcmp (window->output_name, name) == 0)
|
|
monitor_num = n;
|
|
|
|
g_free (name);
|
|
}
|
|
}
|
|
|
|
if (G_UNLIKELY (monitor_num == -1))
|
|
{
|
|
panel_debug (PANEL_DEBUG_POSITIONING,
|
|
"output/monitor %s not found, hiding window",
|
|
window->output_name);
|
|
|
|
/* hide the panel if the monitor was not found */
|
|
if (GTK_WIDGET_VISIBLE (window))
|
|
gtk_widget_hide (GTK_WIDGET (window));
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
/* get the monitor geometry */
|
|
gdk_screen_get_monitor_geometry (screen, monitor_num, &a);
|
|
panel_return_if_fail (a.width > 0 && a.height > 0);
|
|
}
|
|
}
|
|
|
|
/* check if another monitor is preventing the active monitor
|
|
* from setting struts (ie. we can't set struts though another
|
|
* monitor's area) */
|
|
for (n = 0; n < n_monitors; n++)
|
|
{
|
|
/* stop if another window prevented us from settings struts */
|
|
if (window->struts_edge == STRUTS_EDGE_NONE)
|
|
break;
|
|
|
|
/* skip the active monitor */
|
|
if (monitor_num == n)
|
|
continue;
|
|
|
|
/* get other monitor geometry */
|
|
gdk_screen_get_monitor_geometry (screen, n, &b);
|
|
|
|
/* check if this monitor prevents us from setting struts */
|
|
if ((window->struts_edge == STRUTS_EDGE_LEFT && b.x < a.x)
|
|
|| (window->struts_edge == STRUTS_EDGE_RIGHT
|
|
&& b.x + b.width > a.x + a.width))
|
|
{
|
|
dest_y = MAX (a.y, b.y);
|
|
dest_h = MIN (a.y + a.height, b.y + b.height) - dest_y;
|
|
if (dest_h > 0)
|
|
window->struts_edge = STRUTS_EDGE_NONE;
|
|
}
|
|
else if ((window->struts_edge == STRUTS_EDGE_TOP && b.y < a.y)
|
|
|| (window->struts_edge == STRUTS_EDGE_BOTTOM
|
|
&& b.y + b.height > a.y + a.height))
|
|
{
|
|
dest_x = MAX (a.x, b.x);
|
|
dest_w = MIN (a.x + a.width, b.x + b.width) - dest_x;
|
|
if (dest_w > 0)
|
|
window->struts_edge = STRUTS_EDGE_NONE;
|
|
}
|
|
}
|
|
|
|
panel_debug (PANEL_DEBUG_POSITIONING,
|
|
"struts edge: %d", window->struts_edge);
|
|
}
|
|
|
|
/* set the new working area of the panel */
|
|
window->area = a;
|
|
panel_debug (PANEL_DEBUG_POSITIONING,
|
|
"working-area: x=%d, y=%d, w=%d, h=%d",
|
|
a.x, a.y, a.width, a.height);
|
|
|
|
panel_window_screen_update_borders (window);
|
|
|
|
gtk_widget_queue_resize (GTK_WIDGET (window));
|
|
|
|
/* update the struts if needed (ie. we need to reset the struts) */
|
|
if (force_struts_update)
|
|
panel_window_screen_struts_set (window);
|
|
|
|
if (!GTK_WIDGET_VISIBLE (window))
|
|
gtk_widget_show (GTK_WIDGET (window));
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
panel_window_autohide_timeout (gpointer user_data)
|
|
{
|
|
PanelWindow *window = PANEL_WINDOW (user_data);
|
|
|
|
panel_return_val_if_fail (window->autohide_state != AUTOHIDE_DISABLED, FALSE);
|
|
panel_return_val_if_fail (window->autohide_state != AUTOHIDE_BLOCKED, FALSE);
|
|
|
|
/* update the status */
|
|
if (window->autohide_state == AUTOHIDE_POPDOWN
|
|
|| window->autohide_state == AUTOHIDE_POPDOWN_SLOW)
|
|
window->autohide_state = AUTOHIDE_HIDDEN;
|
|
else if (window->autohide_state == AUTOHIDE_POPUP)
|
|
window->autohide_state = AUTOHIDE_VISIBLE;
|
|
|
|
/* move the windows around */
|
|
gtk_widget_queue_resize (GTK_WIDGET (window));
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
panel_window_autohide_timeout_destroy (gpointer user_data)
|
|
{
|
|
PANEL_WINDOW (user_data)->autohide_timeout_id = 0;
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
panel_window_autohide_queue (PanelWindow *window,
|
|
AutohideState new_state)
|
|
{
|
|
guint delay;
|
|
|
|
panel_return_if_fail (PANEL_IS_WINDOW (window));
|
|
|
|
/* stop pending timeout */
|
|
if (window->autohide_timeout_id != 0)
|
|
g_source_remove (window->autohide_timeout_id);
|
|
|
|
/* set new autohide state */
|
|
window->autohide_state = new_state;
|
|
|
|
/* force a layout update to disable struts */
|
|
if (window->struts_edge != STRUTS_EDGE_NONE
|
|
|| window->snap_position != SNAP_POSITION_NONE)
|
|
panel_window_screen_layout_changed (window->screen, window);
|
|
|
|
if (new_state == AUTOHIDE_DISABLED || new_state == AUTOHIDE_BLOCKED)
|
|
{
|
|
/* queue a resize to make sure the panel is visible */
|
|
gtk_widget_queue_resize (GTK_WIDGET (window));
|
|
}
|
|
else
|
|
{
|
|
/* timeout delay */
|
|
if (new_state == AUTOHIDE_POPDOWN)
|
|
delay = window->popdown_delay;
|
|
else if (new_state == AUTOHIDE_POPDOWN_SLOW)
|
|
delay = window->popdown_delay * 4;
|
|
else
|
|
delay = window->popup_delay;
|
|
|
|
/* start a new timeout to hide the panel */
|
|
window->autohide_timeout_id =
|
|
g_timeout_add_full (G_PRIORITY_LOW, delay,
|
|
panel_window_autohide_timeout, window,
|
|
panel_window_autohide_timeout_destroy);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
panel_window_autohide_drag_motion (GtkWidget *widget,
|
|
GdkDragContext *context,
|
|
gint x,
|
|
gint y,
|
|
guint drag_time,
|
|
PanelWindow *window)
|
|
{
|
|
panel_return_val_if_fail (PANEL_IS_WINDOW (window), TRUE);
|
|
panel_return_val_if_fail (window->autohide_window == widget, TRUE);
|
|
|
|
/* queue a popup is state is hidden */
|
|
if (window->autohide_state == AUTOHIDE_HIDDEN)
|
|
panel_window_autohide_queue (window, AUTOHIDE_POPUP);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
panel_window_autohide_drag_leave (GtkWidget *widget,
|
|
GdkDragContext *drag_context,
|
|
guint drag_time,
|
|
PanelWindow *window)
|
|
{
|
|
panel_return_if_fail (PANEL_IS_WINDOW (window));
|
|
panel_return_if_fail (window->autohide_window == widget);
|
|
|
|
/* we left the window before it was hidden, stop the queue */
|
|
if (window->autohide_timeout_id != 0)
|
|
g_source_remove (window->autohide_timeout_id);
|
|
|
|
/* update the status */
|
|
if (window->autohide_state == AUTOHIDE_POPUP)
|
|
window->autohide_state = AUTOHIDE_HIDDEN;
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
panel_window_autohide_event (GtkWidget *widget,
|
|
GdkEventCrossing *event,
|
|
PanelWindow *window)
|
|
{
|
|
panel_return_val_if_fail (PANEL_IS_WINDOW (window), FALSE);
|
|
panel_return_val_if_fail (window->autohide_window == widget, FALSE);
|
|
|
|
if (event->type == GDK_ENTER_NOTIFY)
|
|
panel_window_autohide_queue (window, AUTOHIDE_POPUP);
|
|
else
|
|
panel_window_autohide_drag_leave (widget, NULL, 0, window);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
panel_window_set_autohide (PanelWindow *window,
|
|
gboolean autohide)
|
|
{
|
|
GtkWidget *popup;
|
|
guint i;
|
|
const gchar *properties[] = { "enter-opacity", "leave-opacity",
|
|
"background-alpha", "borders",
|
|
"background-style", "background-color" };
|
|
|
|
panel_return_if_fail (PANEL_IS_WINDOW (window));
|
|
|
|
if ((window->autohide_state != AUTOHIDE_DISABLED) == autohide)
|
|
return;
|
|
|
|
/* respond to drag motion */
|
|
gtk_drag_dest_set_track_motion (GTK_WIDGET (window), autohide);
|
|
|
|
if (autohide)
|
|
{
|
|
/* create the window */
|
|
panel_return_if_fail (window->autohide_window == NULL);
|
|
popup = g_object_new (PANEL_TYPE_BASE_WINDOW,
|
|
"type", GTK_WINDOW_POPUP,
|
|
"decorated", FALSE,
|
|
"resizable", TRUE,
|
|
"type-hint", GDK_WINDOW_TYPE_HINT_DOCK,
|
|
"gravity", GDK_GRAVITY_STATIC,
|
|
"name", "XfcePanelWindowHidden",
|
|
NULL);
|
|
|
|
/* move the window offscreen */
|
|
panel_base_window_move_resize (PANEL_BASE_WINDOW (popup),
|
|
-9999, -9999, 3, 3);
|
|
|
|
/* bind some properties to sync the two windows */
|
|
for (i = 0; i < G_N_ELEMENTS (properties); i++)
|
|
exo_binding_new (G_OBJECT (window), properties[i],
|
|
G_OBJECT (popup), properties[i]);
|
|
|
|
/* signals for pointer enter/leave events */
|
|
g_signal_connect (G_OBJECT (popup), "enter-notify-event",
|
|
G_CALLBACK (panel_window_autohide_event), window);
|
|
g_signal_connect (G_OBJECT (popup), "leave-notify-event",
|
|
G_CALLBACK (panel_window_autohide_event), window);
|
|
|
|
/* show/hide the panel on drag events */
|
|
gtk_drag_dest_set (popup, 0, NULL, 0, 0);
|
|
gtk_drag_dest_set_track_motion (popup, TRUE);
|
|
g_signal_connect (G_OBJECT (popup), "drag-motion",
|
|
G_CALLBACK (panel_window_autohide_drag_motion), window);
|
|
g_signal_connect (G_OBJECT (popup), "drag-leave",
|
|
G_CALLBACK (panel_window_autohide_drag_leave), window);
|
|
|
|
/* show the window */
|
|
window->autohide_window = popup;
|
|
gtk_widget_show (popup);
|
|
|
|
/* start autohide */
|
|
panel_window_autohide_queue (window,
|
|
window->autohide_block == 0 ? AUTOHIDE_POPDOWN_SLOW : AUTOHIDE_BLOCKED);
|
|
}
|
|
else if (window->autohide_window != NULL)
|
|
{
|
|
/* stop autohide */
|
|
panel_window_autohide_queue (window, AUTOHIDE_DISABLED);
|
|
|
|
/* destroy the autohide window */
|
|
panel_return_if_fail (GTK_IS_WINDOW (window->autohide_window));
|
|
gtk_widget_destroy (window->autohide_window);
|
|
window->autohide_window = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
panel_window_menu_help (void)
|
|
{
|
|
panel_utils_show_help (NULL, NULL, NULL);
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
panel_window_menu_deactivate (GtkMenu *menu,
|
|
PanelWindow *window)
|
|
{
|
|
panel_return_if_fail (GTK_IS_MENU (menu));
|
|
panel_return_if_fail (PANEL_IS_WINDOW (window));
|
|
|
|
/* thaw autohide block */
|
|
panel_window_thaw_autohide (window);
|
|
|
|
g_object_unref (G_OBJECT (menu));
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
panel_window_menu_popup (PanelWindow *window,
|
|
guint32 event_time)
|
|
{
|
|
GtkWidget *menu;
|
|
GtkWidget *item;
|
|
GtkWidget *image;
|
|
|
|
panel_return_if_fail (PANEL_IS_WINDOW (window));
|
|
|
|
/* freeze autohide */
|
|
panel_window_freeze_autohide (window);
|
|
|
|
/* create menu */
|
|
menu = gtk_menu_new ();
|
|
g_object_ref_sink (G_OBJECT (menu));
|
|
g_signal_connect (G_OBJECT (menu), "deactivate",
|
|
G_CALLBACK (panel_window_menu_deactivate), window);
|
|
|
|
item = gtk_image_menu_item_new_with_label (_("Panel"));
|
|
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
|
|
gtk_widget_set_sensitive (item, FALSE);
|
|
gtk_widget_show (item);
|
|
|
|
item = gtk_separator_menu_item_new ();
|
|
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
|
|
gtk_widget_show (item);
|
|
|
|
if (!panel_window_get_locked (window))
|
|
{
|
|
/* add new items */
|
|
item = gtk_image_menu_item_new_with_mnemonic (_("Add _New Items..."));
|
|
g_signal_connect_swapped (G_OBJECT (item), "activate",
|
|
G_CALLBACK (panel_item_dialog_show), window);
|
|
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
|
|
gtk_widget_show (item);
|
|
|
|
image = gtk_image_new_from_stock (GTK_STOCK_ADD, GTK_ICON_SIZE_MENU);
|
|
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
|
|
gtk_widget_show (image);
|
|
|
|
/* customize panel */
|
|
item = gtk_image_menu_item_new_with_mnemonic (_("Panel Pr_eferences..."));
|
|
g_signal_connect_swapped (G_OBJECT (item), "activate",
|
|
G_CALLBACK (panel_preferences_dialog_show), window);
|
|
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
|
|
gtk_widget_show (item);
|
|
|
|
image = gtk_image_new_from_stock (GTK_STOCK_PREFERENCES, GTK_ICON_SIZE_MENU);
|
|
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
|
|
gtk_widget_show (image);
|
|
|
|
item = gtk_separator_menu_item_new ();
|
|
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
|
|
gtk_widget_show (item);
|
|
}
|
|
|
|
/* logout item */
|
|
item = gtk_image_menu_item_new_with_mnemonic (_("Log _Out"));
|
|
g_signal_connect_swapped (G_OBJECT (item), "activate",
|
|
G_CALLBACK (panel_application_logout), NULL);
|
|
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
|
|
gtk_widget_show (item);
|
|
|
|
image = gtk_image_new_from_icon_name ("system-log-out", GTK_ICON_SIZE_MENU);
|
|
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
|
|
gtk_widget_show (image);
|
|
|
|
item = gtk_separator_menu_item_new ();
|
|
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
|
|
gtk_widget_show (item);
|
|
|
|
/* help item */
|
|
item = gtk_image_menu_item_new_from_stock (GTK_STOCK_HELP, NULL);
|
|
g_signal_connect (G_OBJECT (item), "activate",
|
|
G_CALLBACK (panel_window_menu_help), NULL);
|
|
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
|
|
gtk_widget_show (item);
|
|
|
|
/* about item */
|
|
item = gtk_image_menu_item_new_from_stock (GTK_STOCK_ABOUT, NULL);
|
|
g_signal_connect (G_OBJECT (item), "activate",
|
|
G_CALLBACK (panel_dialogs_show_about), NULL);
|
|
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
|
|
gtk_widget_show (item);
|
|
|
|
gtk_menu_popup (GTK_MENU (menu), NULL, NULL,
|
|
NULL, NULL, 0, event_time);
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
panel_window_update_plugins (PanelWindow *window,
|
|
PluginProp prop)
|
|
{
|
|
GtkWidget *itembar;
|
|
GtkCallback func;
|
|
|
|
panel_return_if_fail (PANEL_IS_WINDOW (window));
|
|
|
|
switch (prop)
|
|
{
|
|
case PLUGIN_PROP_ORIENTATION:
|
|
func = panel_window_set_plugin_orientation;
|
|
break;
|
|
|
|
case PLUGIN_PROP_SCREEN_POSITION:
|
|
func = panel_window_set_plugin_screen_position;
|
|
break;
|
|
|
|
case PLUGIN_PROP_SIZE:
|
|
func = panel_window_set_plugin_size;
|
|
break;
|
|
|
|
default:
|
|
panel_assert_not_reached ();
|
|
return;
|
|
}
|
|
|
|
itembar = gtk_bin_get_child (GTK_BIN (window));
|
|
if (G_LIKELY (itembar != NULL))
|
|
{
|
|
panel_return_if_fail (GTK_IS_CONTAINER (itembar));
|
|
gtk_container_foreach (GTK_CONTAINER (itembar), func, window);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
panel_window_set_plugin_orientation (GtkWidget *widget,
|
|
gpointer user_data)
|
|
{
|
|
panel_return_if_fail (XFCE_IS_PANEL_PLUGIN_PROVIDER (widget));
|
|
panel_return_if_fail (PANEL_IS_WINDOW (user_data));
|
|
|
|
xfce_panel_plugin_provider_set_orientation (XFCE_PANEL_PLUGIN_PROVIDER (widget),
|
|
PANEL_WINDOW (user_data)->horizontal ? GTK_ORIENTATION_HORIZONTAL:
|
|
GTK_ORIENTATION_VERTICAL);
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
panel_window_set_plugin_size (GtkWidget *widget,
|
|
gpointer user_data)
|
|
{
|
|
panel_return_if_fail (XFCE_IS_PANEL_PLUGIN_PROVIDER (widget));
|
|
panel_return_if_fail (PANEL_IS_WINDOW (user_data));
|
|
|
|
xfce_panel_plugin_provider_set_size (XFCE_PANEL_PLUGIN_PROVIDER (widget),
|
|
PANEL_WINDOW (user_data)->size);
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
panel_window_set_plugin_screen_position (GtkWidget *widget,
|
|
gpointer user_data)
|
|
{
|
|
PanelWindow *window = PANEL_WINDOW (user_data);
|
|
XfceScreenPosition position;
|
|
|
|
panel_return_if_fail (XFCE_IS_PANEL_PLUGIN_PROVIDER (widget));
|
|
panel_return_if_fail (PANEL_IS_WINDOW (user_data));
|
|
|
|
switch (window->snap_position)
|
|
{
|
|
case SNAP_POSITION_NONE:
|
|
position = window->horizontal ? XFCE_SCREEN_POSITION_FLOATING_H :
|
|
XFCE_SCREEN_POSITION_FLOATING_V;
|
|
break;
|
|
|
|
case SNAP_POSITION_NW:
|
|
position = window->horizontal ? XFCE_SCREEN_POSITION_NW_H :
|
|
XFCE_SCREEN_POSITION_NW_V;
|
|
break;
|
|
|
|
case SNAP_POSITION_NE:
|
|
position = window->horizontal ? XFCE_SCREEN_POSITION_NE_H :
|
|
XFCE_SCREEN_POSITION_NE_V;
|
|
break;
|
|
|
|
case SNAP_POSITION_SW:
|
|
position = window->horizontal ? XFCE_SCREEN_POSITION_SW_H :
|
|
XFCE_SCREEN_POSITION_SW_V;
|
|
break;
|
|
|
|
case SNAP_POSITION_SE:
|
|
position = window->horizontal ? XFCE_SCREEN_POSITION_SE_H :
|
|
XFCE_SCREEN_POSITION_SE_V;
|
|
break;
|
|
|
|
case SNAP_POSITION_W:
|
|
case SNAP_POSITION_WC:
|
|
position = window->horizontal ? XFCE_SCREEN_POSITION_FLOATING_H :
|
|
XFCE_SCREEN_POSITION_W;
|
|
break;
|
|
|
|
case SNAP_POSITION_E:
|
|
case SNAP_POSITION_EC:
|
|
position = window->horizontal ? XFCE_SCREEN_POSITION_FLOATING_H :
|
|
XFCE_SCREEN_POSITION_E;
|
|
break;
|
|
|
|
case SNAP_POSITION_S:
|
|
case SNAP_POSITION_SC:
|
|
position = window->horizontal ? XFCE_SCREEN_POSITION_S :
|
|
XFCE_SCREEN_POSITION_FLOATING_V;
|
|
break;
|
|
|
|
case SNAP_POSITION_N:
|
|
case SNAP_POSITION_NC:
|
|
position = window->horizontal ? XFCE_SCREEN_POSITION_N :
|
|
XFCE_SCREEN_POSITION_FLOATING_V;
|
|
break;
|
|
|
|
default:
|
|
panel_assert_not_reached ();
|
|
break;
|
|
}
|
|
|
|
xfce_panel_plugin_provider_set_screen_position (XFCE_PANEL_PLUGIN_PROVIDER (widget),
|
|
position);
|
|
}
|
|
|
|
|
|
|
|
GtkWidget *
|
|
panel_window_new (void)
|
|
{
|
|
return g_object_new (PANEL_TYPE_WINDOW,
|
|
"type", GTK_WINDOW_TOPLEVEL,
|
|
"decorated", FALSE,
|
|
"resizable", FALSE,
|
|
"type-hint", GDK_WINDOW_TYPE_HINT_DOCK,
|
|
"gravity", GDK_GRAVITY_STATIC,
|
|
"name", "XfcePanelWindow",
|
|
NULL);
|
|
}
|
|
|
|
|
|
|
|
void
|
|
panel_window_set_povider_info (PanelWindow *window,
|
|
GtkWidget *provider)
|
|
{
|
|
PanelBaseWindow *base_window = PANEL_BASE_WINDOW (window);
|
|
|
|
panel_return_if_fail (PANEL_IS_WINDOW (window));
|
|
panel_return_if_fail (XFCE_IS_PANEL_PLUGIN_PROVIDER (provider));
|
|
|
|
xfce_panel_plugin_provider_set_locked (XFCE_PANEL_PLUGIN_PROVIDER (provider),
|
|
panel_window_get_locked (window));
|
|
|
|
if (base_window->background_alpha < 1.0)
|
|
{
|
|
if (PANEL_IS_PLUGIN_EXTERNAL (provider))
|
|
panel_plugin_external_set_background_alpha (PANEL_PLUGIN_EXTERNAL (provider),
|
|
base_window->background_alpha);
|
|
}
|
|
|
|
if (base_window->background_style == PANEL_BG_STYLE_COLOR)
|
|
{
|
|
if (PANEL_IS_PLUGIN_EXTERNAL (provider))
|
|
panel_plugin_external_set_background_color (PANEL_PLUGIN_EXTERNAL (provider),
|
|
base_window->background_color);
|
|
}
|
|
else if (base_window->background_style == PANEL_BG_STYLE_IMAGE)
|
|
{
|
|
if (PANEL_IS_PLUGIN_EXTERNAL (provider))
|
|
panel_plugin_external_set_background_image (PANEL_PLUGIN_EXTERNAL (provider),
|
|
base_window->background_image);
|
|
}
|
|
|
|
panel_window_set_plugin_orientation (provider, window);
|
|
panel_window_set_plugin_screen_position (provider, window);
|
|
panel_window_set_plugin_size (provider, window);
|
|
}
|
|
|
|
|
|
|
|
void
|
|
panel_window_freeze_autohide (PanelWindow *window)
|
|
{
|
|
panel_return_if_fail (PANEL_IS_WINDOW (window));
|
|
panel_return_if_fail (window->autohide_block >= 0);
|
|
|
|
/* increase autohide block counter */
|
|
window->autohide_block++;
|
|
|
|
if (window->autohide_block == 1
|
|
&& window->autohide_state != AUTOHIDE_DISABLED)
|
|
panel_window_autohide_queue (window, AUTOHIDE_BLOCKED);
|
|
}
|
|
|
|
|
|
|
|
void
|
|
panel_window_thaw_autohide (PanelWindow *window)
|
|
{
|
|
panel_return_if_fail (PANEL_IS_WINDOW (window));
|
|
panel_return_if_fail (window->autohide_block > 0);
|
|
|
|
/* decrease autohide block counter */
|
|
window->autohide_block--;
|
|
|
|
if (window->autohide_block == 0
|
|
&& window->autohide_state != AUTOHIDE_DISABLED)
|
|
panel_window_autohide_queue (window, AUTOHIDE_POPDOWN);
|
|
}
|
|
|
|
|
|
|
|
void
|
|
panel_window_set_locked (PanelWindow *window,
|
|
gboolean locked)
|
|
{
|
|
panel_return_if_fail (PANEL_IS_WINDOW (window));
|
|
|
|
window->locked = locked;
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
panel_window_get_locked (PanelWindow *window)
|
|
{
|
|
panel_return_val_if_fail (PANEL_IS_WINDOW (window), TRUE);
|
|
|
|
return window->locked;
|
|
}
|
|
|
|
|
|
|
|
void
|
|
panel_window_focus (PanelWindow *window)
|
|
{
|
|
#ifdef GDK_WINDOWING_X11
|
|
XClientMessageEvent event;
|
|
|
|
panel_return_if_fail (PANEL_IS_WINDOW (window));
|
|
panel_return_if_fail (GTK_WIDGET_REALIZED (window));
|
|
|
|
/* we need a slightly custom version of the call through Gtk+ to
|
|
* properly focus the panel when a plugin calls
|
|
* xfce_panel_plugin_focus_widget() */
|
|
event.type = ClientMessage;
|
|
event.window = GDK_WINDOW_XID (GTK_WIDGET (window)->window);
|
|
event.message_type = gdk_x11_get_xatom_by_name ("_NET_ACTIVE_WINDOW");
|
|
event.format = 32;
|
|
event.data.l[0] = 0;
|
|
|
|
gdk_error_trap_push ();
|
|
|
|
XSendEvent (GDK_DISPLAY (), GDK_ROOT_WINDOW (), False,
|
|
StructureNotifyMask, (XEvent *) &event);
|
|
|
|
gdk_flush ();
|
|
|
|
if (gdk_error_trap_pop () != 0)
|
|
g_critical ("Failed to focus panel window");
|
|
#else
|
|
/* our best guess on non-x11 clients */
|
|
gtk_window_present (GTK_WINDOW (window));
|
|
#endif
|
|
}
|
|
|