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.
 
 
 
 

1996 lines
55 KiB

/* $Id$ */
/*
* 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., 59 Temple
* Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef HAVE_MATH_H
#include <math.h>
#endif
#include <exo/exo.h>
#include <libxfce4panel/libxfce4panel.h>
#include <panel/panel-private.h>
#include <panel/panel-window.h>
#include <panel/panel-glue.h>
#include <panel/panel-application.h>
#define HANDLE_SIZE (8)
#define HANDLE_SPACING (2)
#define HANDLE_SIZE_TOTAL ((HANDLE_SIZE + HANDLE_SPACING) * 2)
#define SNAP_DISTANCE (10)
#define POPUP_DELAY (225)
#define POPDOWN_DELAY (350)
#define HIDDEN_PANEL_SIZE (2)
#define OFFSCREEN (-9999)
static void panel_window_class_init (PanelWindowClass *klass);
static void panel_window_init (PanelWindow *window);
static void panel_window_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
static void panel_window_finalize (GObject *object);
static void panel_window_realize (GtkWidget *widget);
static gboolean panel_window_expose_event (GtkWidget *widget, GdkEventExpose *event);
static gboolean panel_window_motion_notify (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 gboolean panel_window_enter_notify_event (GtkWidget *widget, GdkEventCrossing *event);
static gboolean panel_window_leave_notify_event (GtkWidget *widget, GdkEventCrossing *event);
static void panel_window_size_request (GtkWidget *widget, GtkRequisition *requisition);
static void panel_window_size_allocate (GtkWidget *widget, GtkAllocation *allocation);
static void panel_window_screen_changed (GtkWidget *widget, GdkScreen *previous_screen);
static void panel_window_paint_handle (PanelWindow *window, gboolean start, GtkStateType state, cairo_t *rc);
static void panel_window_paint_border (PanelWindow *window, GtkStateType state, cairo_t *rc);
static void panel_window_calculate_position (PanelWindow *window, gint width, gint height, gint *x, gint *y);
static void panel_window_working_area (PanelWindow *window, gint root_x, gint root_y, GdkRectangle *dest);
static gboolean panel_window_struts_are_possible (PanelWindow *window, gint x, gint y, gint width, gint height);
static void panel_window_struts_update (PanelWindow *window, gint x, gint y, gint width, gint height);
static void panel_window_set_colormap (PanelWindow *window);
static void panel_window_get_position (PanelWindow *window, gint *root_x, gint *root_y);
enum
{
PROP_0,
PROP_ORIENTATION
};
enum
{
SNAP_NONE,
SNAP_START,
SNAP_CENTER,
SNAP_END
};
typedef enum
{
DISABLED,
BLOCKED,
VISIBLE,
POPUP_QUEUED,
HIDDEN,
POPDOWN_QUEUED,
POPDOWN_QUEUED_SLOW
}
AutohideStatus;
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
{
GtkWindowClass __parent__;
};
struct _PanelWindow
{
GtkWindow __parent__;
/* last allocated size, for recentering */
GtkAllocation prev_allocation;
/* snapping edge of the window */
PanelWindowSnapEdge snap_edge;
/* whether we should apply struts for this screen position */
gint struts_possible;
/* the last used struts for this window */
gulong struts[N_STRUTS];
/* the last calculated panel working area */
GdkRectangle working_area;
/* whether we span monitors */
guint span_monitors : 1;
/* whether the panel has an rgba colormap */
guint is_composited : 1;
/* whether the panel is locked */
guint locked : 1;
/* when the panel is 'selected' */
guint selected : 1;
/* panel orientation */
guint horizontal;
/* panel size (px) and length (%) */
gint size;
gdouble length;
/* autohide */
AutohideStatus autohide_status;
guint autohide_timer;
gint autohide_block;
/* the window we use to show during autohide */
GtkWidget *autohide_window;
/* background alpha */
gdouble background_alpha;
/* panel enter/leave opacity */
gdouble enter_opacity;
gdouble leave_opacity;
/* variables for dragging the panel */
guint drag_motion : 1;
gint drag_start_x;
gint drag_start_y;
};
static GdkAtom cardinal_atom = GDK_NONE;
static GdkAtom net_wm_strut_atom = GDK_NONE;
static GdkAtom net_wm_strut_partial_atom = GDK_NONE;
G_DEFINE_TYPE (PanelWindow, panel_window, GTK_TYPE_WINDOW);
static void
panel_window_class_init (PanelWindowClass *klass)
{
GObjectClass *gobject_class;
GtkWidgetClass *gtkwidget_class;
panel_window_parent_class = g_type_class_peek_parent (klass);
gobject_class = G_OBJECT_CLASS (klass);
gobject_class->get_property = panel_window_get_property;
gobject_class->finalize = panel_window_finalize;
gtkwidget_class = GTK_WIDGET_CLASS (klass);
gtkwidget_class->realize = panel_window_realize;
gtkwidget_class->expose_event = panel_window_expose_event;
gtkwidget_class->motion_notify_event = panel_window_motion_notify;
gtkwidget_class->button_press_event = panel_window_button_press_event;
gtkwidget_class->button_release_event = panel_window_button_release_event;
gtkwidget_class->enter_notify_event = panel_window_enter_notify_event;
gtkwidget_class->leave_notify_event = panel_window_leave_notify_event;
gtkwidget_class->size_request = panel_window_size_request;
gtkwidget_class->size_allocate = panel_window_size_allocate;
gtkwidget_class->screen_changed = panel_window_screen_changed;
/**
* PanelWindow::orientation:
*
* The orientation of the panel window. This is used to sync the
* panel orientation with that of the itembar, using exo bindings.
**/
g_object_class_install_property (gobject_class,
PROP_ORIENTATION,
g_param_spec_enum ("orientation", "orientation", "orientation",
GTK_TYPE_ORIENTATION,
GTK_ORIENTATION_HORIZONTAL,
EXO_PARAM_READABLE));
/* initialize the atoms */
cardinal_atom = panel_atom_intern ("CARDINAL");
net_wm_strut_atom = panel_atom_intern ("_NET_WM_STRUT");
net_wm_strut_partial_atom = panel_atom_intern ("_NET_WM_STRUT_PARTIAL");
}
static void
panel_window_init (PanelWindow *window)
{
GdkScreen *screen;
/* set window properties */
gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
gtk_window_set_decorated (GTK_WINDOW (window), FALSE);
gtk_window_set_type_hint (GTK_WINDOW (window), GDK_WINDOW_TYPE_HINT_DOCK);
gtk_window_set_gravity (GTK_WINDOW (window), GDK_GRAVITY_STATIC);
/* init vars */
window->is_composited = FALSE;
window->drag_motion = FALSE;
window->struts_possible = -1;
window->size = 48;
window->snap_edge = PANEL_SNAP_EGDE_NONE;
window->span_monitors = FALSE;
window->length = 0.25;
window->horizontal = TRUE;
window->background_alpha = 1.00;
window->enter_opacity = 1.00;
window->leave_opacity = 1.00;
window->autohide_timer = 0;
window->autohide_status = DISABLED;
window->autohide_block = 0;
window->autohide_window = NULL;
window->selected = FALSE;
/* set additional events we want to have */
gtk_widget_add_events (GTK_WIDGET (window), GDK_BUTTON_PRESS_MASK);
/* connect signal to monitor the compositor changes */
g_signal_connect (G_OBJECT (window), "composited-changed", G_CALLBACK (panel_window_set_colormap), NULL);
/* set the colormap */
panel_window_set_colormap (window);
/* get the window screen */
screen = gtk_window_get_screen (GTK_WINDOW (window));
/* connect screen update signals */
g_signal_connect_swapped (G_OBJECT (screen), "size-changed", G_CALLBACK (panel_window_screen_changed), window);
#if GTK_CHECK_VERSION (2,14,0)
g_signal_connect_swapped (G_OBJECT (screen), "monitors-changed", G_CALLBACK (panel_window_screen_changed), window);
#endif
}
static void
panel_window_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
PanelWindow *window = PANEL_WINDOW (object);
switch (prop_id)
{
case PROP_ORIENTATION:
g_value_set_enum (value, panel_window_get_orientation (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 the autohide timeout */
if (window->autohide_timer != 0)
g_source_remove (window->autohide_timer);
/* destroy autohide window */
if (window->autohide_window != NULL)
gtk_widget_destroy (window->autohide_window);
(*G_OBJECT_CLASS (panel_window_parent_class)->finalize) (object);
}
static void
panel_window_realize (GtkWidget *widget)
{
/* realize the window */
(*GTK_WIDGET_CLASS (panel_window_parent_class)->realize) (widget);
/* initialize the working area */
panel_window_working_area (PANEL_WINDOW (widget), -1, -1, &PANEL_WINDOW (widget)->working_area);
}
static gboolean
panel_window_expose_event (GtkWidget *widget,
GdkEventExpose *event)
{
PanelWindow *window = PANEL_WINDOW (widget);
cairo_t *cr;
GdkColor *color;
GtkStateType state = GTK_STATE_NORMAL;
if (GTK_WIDGET_DRAWABLE (widget))
{
/* create cairo context */
cr = gdk_cairo_create (widget->window);
/* use another state when the panel is selected */
if (G_UNLIKELY (window->selected))
state = GTK_STATE_SELECTED;
if (window->selected ||
(window->is_composited && window->background_alpha < 1.00))
{
/* get the background gdk color */
color = &(widget->style->bg[state]);
/* set the cairo source color */
_set_source_rgba (cr, color, window->selected ? 1.00 : window->background_alpha);
/* create retangle */
cairo_rectangle (cr, event->area.x, event->area.y,
event->area.width, event->area.height);
/* draw on source */
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
/* paint rectangle */
cairo_fill (cr);
}
/* paint handles */
if (window->locked == FALSE)
{
panel_window_paint_handle (window, TRUE, state, cr);
panel_window_paint_handle (window, FALSE, state, cr);
}
/* paint the panel border */
panel_window_paint_border (window, state, cr);
/* destroy cairo context */
cairo_destroy (cr);
}
/* send expose event to child too */
if (GTK_BIN (widget)->child)
gtk_container_propagate_expose (GTK_CONTAINER (widget), GTK_BIN (widget)->child, event);
return FALSE;
}
static guint
panel_window_motion_notify_snap (gint value,
gint length,
gint start,
gint end,
gint *return_value)
{
gint tmp;
/* snap in the center */
tmp = start + ((end - start) - length) / 2;
if (value >= tmp - SNAP_DISTANCE && value <= tmp + SNAP_DISTANCE)
{
*return_value = tmp;
return SNAP_CENTER;
}
/* snap on the start */
if (value >= start && value <= start + SNAP_DISTANCE)
{
*return_value = start;
return SNAP_START;
}
/* snap on the end */
tmp = end - length;
if (value >= tmp - SNAP_DISTANCE && value <= tmp)
{
*return_value = tmp;
return SNAP_END;
}
/* set value as return value */
*return_value = value;
return SNAP_NONE;
}
static gboolean
panel_window_motion_notify (GtkWidget *widget,
GdkEventMotion *event)
{
PanelWindow *window = PANEL_WINDOW (widget);
gint clamp_x, clamp_y;
GdkScreen *screen;
gint window_width, window_height;
gint window_x, window_y;
GdkRectangle area;
gint snap_x, snap_y;
guint snap_horizontal;
guint snap_vertical;
if (window->drag_motion)
{
/* get the pointer position and current screen */
gdk_display_get_pointer (gtk_widget_get_display (widget), &screen, &window_x, &window_y, NULL);
/* make sure the window is on the correct screen */
gtk_window_set_screen (GTK_WINDOW (widget), screen);
/* get the maximum panel area on this coordinate */
panel_window_working_area (window, window_x, window_y, &area);
/* convert to corner offset */
window_x -= window->drag_start_x;
window_y -= window->drag_start_y;
/* get allocated window size, but make sure it fits in the maximum area */
window_width = MIN (widget->allocation.width, area.width);
window_height = MIN (widget->allocation.height, area.height);
/* keep the panel inside the maximum area */
clamp_x = CLAMP (window_x, area.x, area.x + area.width - window_width);
clamp_y = CLAMP (window_y, area.y, area.y + area.height - window_height);
/* update the drag coordinates, so dragging feels responsive when the user hits a screen edge */
window->drag_start_x += window_x - clamp_x;
window->drag_start_y += window_y - clamp_y;
/* try to find snapping edges */
snap_horizontal = panel_window_motion_notify_snap (clamp_x, window_width, area.x, area.x + area.width, &snap_x);
snap_vertical = panel_window_motion_notify_snap (clamp_y, window_height, area.y, area.y + area.height, &snap_y);
/* detect the snap mode */
if (snap_horizontal == SNAP_START)
window->snap_edge = PANEL_SNAP_EGDE_W + snap_vertical;
else if (snap_horizontal == SNAP_END)
window->snap_edge = PANEL_SNAP_EGDE_E + snap_vertical;
else if (snap_horizontal == SNAP_CENTER && snap_vertical == SNAP_START)
window->snap_edge = PANEL_SNAP_EGDE_NC;
else if (snap_horizontal == SNAP_CENTER && snap_vertical == SNAP_END)
window->snap_edge = PANEL_SNAP_EGDE_SC;
else if (snap_horizontal == SNAP_NONE && snap_vertical == SNAP_START)
window->snap_edge = PANEL_SNAP_EGDE_N;
else if (snap_horizontal == SNAP_NONE && snap_vertical == SNAP_END)
window->snap_edge = PANEL_SNAP_EGDE_S;
else
window->snap_edge = PANEL_SNAP_EGDE_NONE;
/* when snapping succeeded, set the snap coordinates for visual feedback */
if (window->snap_edge != PANEL_SNAP_EGDE_NONE)
{
clamp_x = snap_x;
clamp_y = snap_y;
}
/* move and resize the window */
gdk_window_move_resize (widget->window, clamp_x, clamp_y, window_width, window_height);
return TRUE;
}
return FALSE;
}
static gboolean
panel_window_button_press_event (GtkWidget *widget,
GdkEventButton *event)
{
PanelWindow *window = PANEL_WINDOW (widget);
GdkCursor *cursor;
guint modifiers;
/* get the modifiers */
modifiers = event->state & gtk_accelerator_get_default_mod_mask ();
if (event->button == 1
&& event->window == widget->window
&& window->locked == FALSE
&& modifiers == 0)
{
/* set initial start coordinates */
window->drag_start_x = event->x;
window->drag_start_y = event->y;
/* create a moving cursor */
cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget), GDK_FLEUR);
/* try to drab the pointer */
window->drag_motion = (gdk_pointer_grab (widget->window, FALSE,
GDK_BUTTON_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
NULL, cursor, event->time) == GDK_GRAB_SUCCESS);
/* release the cursor */
gdk_cursor_unref (cursor);
return TRUE;
}
else if (event->button == 3 || (event->button == 1 && modifiers == GDK_CONTROL_MASK))
{
/* popup the panel menu */
panel_glue_popup_menu (window);
return TRUE;
}
return FALSE;
}
static gboolean
panel_window_button_release_event (GtkWidget *widget,
GdkEventButton *event)
{
PanelWindow *window = PANEL_WINDOW (widget);
if (window->drag_motion)
{
/* unset the drag */
window->drag_motion = FALSE;
/* release the pointer */
gdk_pointer_ungrab (event->time);
/* update working area, struts and reallocate */
panel_window_screen_changed (widget, gtk_window_get_screen (GTK_WINDOW (widget)));
/* update the plugins */
panel_glue_set_screen_position (window);
return TRUE;
}
return FALSE;
}
static gboolean
panel_window_autohide_timeout (gpointer user_data)
{
PanelWindow *window = PANEL_WINDOW (user_data);
panel_return_val_if_fail (window->autohide_status != DISABLED
&& window->autohide_status != BLOCKED, FALSE);
/* change status */
if (window->autohide_status == POPDOWN_QUEUED || window->autohide_status == POPDOWN_QUEUED_SLOW)
window->autohide_status = HIDDEN;
else if (window->autohide_status == POPUP_QUEUED)
window->autohide_status = VISIBLE;
gtk_widget_queue_resize (GTK_WIDGET (window));
return FALSE;
}
static void
panel_window_autohide_timeout_destroy (gpointer user_data)
{
PANEL_WINDOW (user_data)->autohide_timer = 0;
}
static void
panel_window_autohide_queue (PanelWindow *window,
AutohideStatus status)
{
guint delay;
panel_return_if_fail (PANEL_IS_WINDOW (window));
/* stop a running autohide timeout */
if (window->autohide_timer != 0)
g_source_remove (window->autohide_timer);
/* set new autohide status */
window->autohide_status = status;
/* leave when the autohide is disabled */
if (status == DISABLED || status == BLOCKED)
{
/* queue a resize to make sure everything is visible */
gtk_widget_queue_resize (GTK_WIDGET (window));
}
else
{
/* get the delay */
if (status == POPDOWN_QUEUED)
delay = POPDOWN_DELAY;
else if (status == POPDOWN_QUEUED_SLOW)
delay = POPDOWN_DELAY * 3;
else
delay = POPUP_DELAY;
/* schedule a new timeout */
window->autohide_timer = g_timeout_add_full (G_PRIORITY_LOW, delay,
panel_window_autohide_timeout, window,
panel_window_autohide_timeout_destroy);
}
}
static gboolean
panel_window_autohide_enter_notify_event (GtkWidget *widget,
GdkEventCrossing *event,
PanelWindow *window)
{
panel_return_val_if_fail (PANEL_IS_WINDOW (window), FALSE);
/* queue a hide timeout */
panel_window_autohide_queue (window, POPUP_QUEUED);
return TRUE;
}
static gboolean
panel_window_autohide_leave_notify_event (GtkWidget *widget,
GdkEventCrossing *event,
PanelWindow *window)
{
panel_return_val_if_fail (PANEL_IS_WINDOW (window), FALSE);
/* stop a running autohide timeout */
if (window->autohide_timer != 0)
g_source_remove (window->autohide_timer);
/* update the status */
if (window->autohide_status == POPUP_QUEUED)
window->autohide_status = HIDDEN;
return TRUE;
}
static GtkWidget *
panel_window_autohide_window (PanelWindow *window)
{
GtkWidget *popup;
/* create window */
popup = gtk_window_new (GTK_WINDOW_POPUP);
gtk_window_set_gravity (GTK_WINDOW (popup), GDK_GRAVITY_STATIC);
/* connect signals to monitor enter/leave events */
g_signal_connect (G_OBJECT (popup), "enter-notify-event", G_CALLBACK (panel_window_autohide_enter_notify_event), window);
g_signal_connect (G_OBJECT (popup), "leave-notify-event", G_CALLBACK (panel_window_autohide_leave_notify_event), window);
/* put the window offscreen */
gtk_window_move (GTK_WINDOW (popup), OFFSCREEN, OFFSCREEN);
/* set window opacity */
_window_set_opacity (GTK_WINDOW (popup), window->leave_opacity);
/* show the window */
gtk_widget_show (popup);
return popup;
}
static gboolean
panel_window_enter_notify_event (GtkWidget *widget,
GdkEventCrossing *event)
{
PanelWindow *window = PANEL_WINDOW (widget);
/* ignore event when entered from an inferior */
if (event->detail == GDK_NOTIFY_INFERIOR)
return FALSE;
/* set the opacity (when they differ) */
if (window->leave_opacity != window->enter_opacity)
_window_set_opacity (GTK_WINDOW (window), window->enter_opacity);
/* stop a running autohide timeout */
if (window->autohide_timer != 0)
g_source_remove (window->autohide_timer);
/* update autohide status */
if (window->autohide_status == POPDOWN_QUEUED)
window->autohide_status = VISIBLE;
return FALSE;
}
static gboolean
panel_window_leave_notify_event (GtkWidget *widget,
GdkEventCrossing *event)
{
PanelWindow *window = PANEL_WINDOW (widget);
/* ignore event when left towards an inferior */
if (event->detail == GDK_NOTIFY_INFERIOR)
return FALSE;
/* set the opacity (when they differ) */
if (window->leave_opacity != window->enter_opacity)
_window_set_opacity (GTK_WINDOW (window), window->leave_opacity);
/* stop a running autohide timeout */
if (window->autohide_timer != 0)
g_source_remove (window->autohide_timer);
/* queue a new autohide time if needed */
if (window->autohide_status > BLOCKED && window->snap_edge != PANEL_SNAP_EGDE_NONE)
panel_window_autohide_queue (window, POPDOWN_QUEUED);
return FALSE;
}
/**
* panel_window_size_request:
* @widget : the panel window.
* @requisition : the size we're requesting and receiving on
* allocation.
*
* In this function we request the panel size, this size must fit
* on the screen and match all the settings. It's not nessecarily
* that all the plugins fit (based on their requisition that is),
* they have to respect the size we allocate, requesting is only
* being kind to plugins (actually the itembar), and we're not ;).
**/
static void
panel_window_size_request (GtkWidget *widget,
GtkRequisition *requisition)
{
PanelWindow *window = PANEL_WINDOW (widget);
GtkRequisition child_requisition;
if (GTK_WIDGET_REALIZED (widget))
{
/* poke the itembar to request it's size */
if (G_LIKELY (GTK_BIN (widget)->child))
gtk_widget_size_request (GTK_BIN (widget)->child, &child_requisition);
else
child_requisition.width = child_requisition.height = 0;
/* add the handle size */
if (window->locked == FALSE)
{
if (window->horizontal)
child_requisition.width += HANDLE_SIZE_TOTAL;
else
child_requisition.height += HANDLE_SIZE_TOTAL;
}
/* get the real allocated size */
if (window->horizontal)
{
/* calculate the panel width (fits content, fits on the screen, and extands to user size) */
requisition->width = CLAMP (child_requisition.width,
window->working_area.width * window->length,
window->working_area.width);
/* set height based on user setting */
requisition->height = window->size;
}
else
{
/* calculate the panel width (fits content, fits on the screen, and extands to user size) */
requisition->height = CLAMP (child_requisition.height,
window->working_area.height * window->length,
window->working_area.height);
/* set width based on user setting */
requisition->width = window->size;
}
}
}
/**
* panel_window_size_allocate:
* @widget : the panel window.
* @allocation : the allocation.
*
* Here we position the window on the monitor/screen. The width and
* height of the allocation cannot be changed, it's determend in
* panel_window_size_request, so if it's wrong: fix things there.
*
* Because the panel window is a GtkWindow, the allocation x and y
* are 0, which is fine for the child, but not for screen, so we
* calculate the new screen position move and resize we window (at
* once to avoid strange visual effects).
*
* The child allocation is basiclly the same, only a small change
* to keep the handles free, when the panel is locked.
**/
static void
panel_window_size_allocate (GtkWidget *widget,
GtkAllocation *allocation)
{
PanelWindow *window = PANEL_WINDOW (widget);
GtkAllocation child_allocation;
gint root_x, root_y;
gint width = HIDDEN_PANEL_SIZE, height = HIDDEN_PANEL_SIZE;
gint hidden_root_x, hidden_root_y;
if (GTK_WIDGET_REALIZED (widget))
{
/* set the widget allocation */
widget->allocation = *allocation;
/* get coordinates for the panel window */
panel_window_calculate_position (window, allocation->width, allocation->height, &root_x, &root_y);
/* handle hidden windows */
if (window->autohide_status != DISABLED
&& window->autohide_window != NULL
&& window->snap_edge != PANEL_SNAP_EGDE_NONE)
{
if (window->autohide_status == VISIBLE
|| window->autohide_status == POPDOWN_QUEUED
|| window->autohide_status == POPDOWN_QUEUED_SLOW
|| window->autohide_status == BLOCKED)
{
/* put the hidden window offscreen */
gtk_window_move (GTK_WINDOW (window->autohide_window), OFFSCREEN, OFFSCREEN);
}
else
{
/* init width and height */
width = height = HIDDEN_PANEL_SIZE;
/* get hidden panel size */
switch (window->snap_edge)
{
case PANEL_SNAP_EGDE_E:
case PANEL_SNAP_EGDE_EC:
case PANEL_SNAP_EGDE_W:
case PANEL_SNAP_EGDE_WC:
height = allocation->height;
break;
case PANEL_SNAP_EGDE_NC:
case PANEL_SNAP_EGDE_SC:
case PANEL_SNAP_EGDE_N:
case PANEL_SNAP_EGDE_S:
width = allocation->width;
break;
default:
if (window->horizontal)
width = allocation->width;
else
height = allocation->height;
break;
}
/* get coordinates for the hidden window */
panel_window_calculate_position (window, width, height, &hidden_root_x, &hidden_root_y);
/* position the hidden window */
gtk_window_move (GTK_WINDOW (window->autohide_window), hidden_root_x, hidden_root_y);
gtk_window_resize (GTK_WINDOW (window->autohide_window), width, height);
/* put the panel window offscreen */
root_x = root_y = OFFSCREEN;
}
}
/* move and resize the panel window */
gdk_window_move_resize (widget->window, root_x, root_y, allocation->width, allocation->height);
if (GTK_BIN (widget)->child)
{
/* set the child allocation */
child_allocation = *allocation;
/* change to allocation to keep the handles free */
if (window->locked == FALSE)
{
if (window->horizontal)
{
child_allocation.width -= HANDLE_SIZE_TOTAL;
child_allocation.x += HANDLE_SIZE + HANDLE_SPACING;
}
else
{
child_allocation.height -= HANDLE_SIZE_TOTAL;
child_allocation.y += HANDLE_SIZE + HANDLE_SPACING;
}
}
/* keep things positive */
child_allocation.width = MAX (0, child_allocation.width);
child_allocation.height = MAX (0, child_allocation.height);
/* allocate the child */
gtk_widget_size_allocate (GTK_BIN (widget)->child, &child_allocation);
}
/* update struts if possible */
if (window->struts_possible != 0)
panel_window_struts_update (window, root_x, root_y, allocation->width, allocation->height);
}
/* update previous allocation */
window->prev_allocation = *allocation;
}
static void
panel_window_screen_changed (GtkWidget *widget,
GdkScreen *previous_screen)
{
GdkScreen *screen;
PanelWindow *window = PANEL_WINDOW (widget);
panel_return_if_fail (PANEL_IS_WINDOW (widget));
panel_return_if_fail (GDK_IS_SCREEN (previous_screen));
/* get the new screen */
screen = gtk_window_get_screen (GTK_WINDOW (widget));
if (screen != previous_screen)
{
/* disconnect old screen changed handles */
g_signal_handlers_disconnect_by_func (G_OBJECT (previous_screen), G_CALLBACK (gtk_widget_queue_resize), widget);
/* connect new screen update signals */
g_signal_connect_swapped (G_OBJECT (screen), "size-changed", G_CALLBACK (panel_window_screen_changed), widget);
#if GTK_CHECK_VERSION (2,14,0)
g_signal_connect_swapped (G_OBJECT (screen), "monitors-changed", G_CALLBACK (panel_window_screen_changed), widget);
#endif
}
/* update the panel working area */
panel_window_working_area (window, -1, -1, &window->working_area);
/* check if struts are needed on the next resize */
window->struts_possible = -1;
/* queue a resize */
gtk_widget_queue_resize (widget);
}
static void
panel_window_paint_handle (PanelWindow *window,
gboolean start,
GtkStateType state,
cairo_t *cr)
{
GtkWidget *widget = GTK_WIDGET (window);
GtkAllocation *alloc = &(widget->allocation);
gint x, y, width, height;
gint i, xx, yy;
GdkColor *color;
gdouble alpha = window->is_composited ? window->background_alpha : 1.00;
/* set initial numbers */
x = alloc->x + 2;
y = alloc->y + 2;
if (window->horizontal)
{
width = HANDLE_SIZE / 3 * 3;
height = alloc->height / 2;
y += height / 2 - 1;
x += (HANDLE_SIZE - width);
/* draw handle on the right */
if (!start)
x += alloc->width - HANDLE_SIZE - 4;
}
else
{
height = HANDLE_SIZE / 3 * 3;
width = alloc->width / 2;
x += width / 2 - 1;
y += (HANDLE_SIZE - height);
/* draw handle on the bottom */
if (!start)
y += alloc->height - HANDLE_SIZE - 4;
}
/* draw handler */
for (i = 2; i > 0; i--)
{
/* get the color for the job */
if (i == 2)
color = &(widget->style->light[state]);
else
color = &(widget->style->dark[state]);
/* set source color */
_set_source_rgba (cr, color, alpha);
/* draw the dots */
for (xx = 0; xx < width; xx += 3)
for (yy = 0; yy < height; yy += 3)
cairo_rectangle (cr, x + xx, y + yy, i, i);
/* fill the rectangles */
cairo_fill (cr);
}
}
static void
panel_window_paint_border (PanelWindow *window,
GtkStateType state,
cairo_t *cr)
{
GtkWidget *widget = GTK_WIDGET (window);
GtkAllocation *alloc = &(widget->allocation);
GdkColor *color;
gdouble alpha = window->is_composited ? window->background_alpha : 1.00;
/* 1px line */
cairo_set_line_width (cr, 1.0);
/* dark color */
color = &(widget->style->dark[state]);
_set_source_rgba (cr, color, alpha);
/* set start position to bottom left */
cairo_move_to (cr, alloc->x, alloc->y + alloc->height);
/* bottom line */
cairo_rel_line_to (cr, alloc->width, 0);
/* right line */
cairo_rel_line_to (cr, 0, -alloc->height);
/* stroke this part */
cairo_stroke (cr);
/* light color */
color = &(widget->style->light[state]);
_set_source_rgba (cr, color, alpha);
/* set start position to bottom left */
cairo_move_to (cr, alloc->x, alloc->y + alloc->height);
/* left line */
cairo_rel_line_to (cr, 0, -alloc->height);
/* top line */
cairo_rel_line_to (cr, alloc->width, 0);
/* stroke this part */
cairo_stroke (cr);
}
static void
panel_window_calculate_position (PanelWindow *window,
gint width,
gint height,
gint *x,
gint *y)
{
gint root_x, root_y;
GdkRectangle *area = &window->working_area;
/* get the panel window position */
panel_window_get_position (window, &root_x, &root_y);
/* x position of the window */
switch (window->snap_edge)
{
/* left */
case PANEL_SNAP_EGDE_W:
case PANEL_SNAP_EGDE_NW:
case PANEL_SNAP_EGDE_WC:
case PANEL_SNAP_EGDE_SW:
*x = area->x;
break;
/* right */
case PANEL_SNAP_EGDE_E:
case PANEL_SNAP_EGDE_NE:
case PANEL_SNAP_EGDE_EC:
case PANEL_SNAP_EGDE_SE:
*x = area->x + area->width - width;
break;
/* center */
case PANEL_SNAP_EGDE_NC:
case PANEL_SNAP_EGDE_SC:
*x = area->x + (area->width - width) / 2;
break;
/* other, recenter based on previous allocation */
default:
*x = root_x + (window->prev_allocation.width - width) / 2;
*x = CLAMP (*x, area->x, area->x + area->width - width);
break;
}
/* y position of the window */
switch (window->snap_edge)
{
/* north */
case PANEL_SNAP_EGDE_NE:
case PANEL_SNAP_EGDE_NW:
case PANEL_SNAP_EGDE_NC:
case PANEL_SNAP_EGDE_N:
*y = area->y;
break;
/* south */
case PANEL_SNAP_EGDE_SE:
case PANEL_SNAP_EGDE_SW:
case PANEL_SNAP_EGDE_SC:
case PANEL_SNAP_EGDE_S:
*y = area->y + area->height - height;
break;
/* center */
case PANEL_SNAP_EGDE_EC:
case PANEL_SNAP_EGDE_WC:
*y = area->y + (area->height - height) / 2;
break;
/* other, recenter based on previous allocation */
default:
*y = root_y + (window->prev_allocation.height - height) / 2;
*y = CLAMP (*y, area->y, area->y + area->height - height);
break;
}
}
static void
panel_window_working_area (PanelWindow *window,
gint root_x,
gint root_y,
GdkRectangle *dest)
{
GdkScreen *screen;
gint monitor_num;
gint n_monitors;
GdkRectangle geometry;
gint i;
panel_return_if_fail (PANEL_IS_WINDOW (window));
panel_return_if_fail (GDK_IS_WINDOW (GTK_WIDGET (window)->window));
/* get valid coordinates if not set */
if (root_x == -1 && root_y == -1)
gtk_window_get_position (GTK_WINDOW (window), &root_x, &root_y);
/* get panel screen */
screen = gtk_window_get_screen (GTK_WINDOW (window));
/* get the monitor number */
monitor_num = gdk_screen_get_monitor_at_point (screen, root_x, root_y);
/* get the root monitor geometry */
gdk_screen_get_monitor_geometry (screen, monitor_num, dest);
if (window->span_monitors)
{
/* get the number of monitors */
n_monitors = gdk_screen_get_n_monitors (screen);
/* only try to extend when there are more then 2 monitors */
if (G_LIKELY (n_monitors > 1))
{
/* TODO: loop for > 2 monitors */
for (i = 0; i < n_monitors; i++)
{
/* skip the origional monitor */
if (i == monitor_num)
continue;
/* get the monitor geometry */
gdk_screen_get_monitor_geometry (screen, i, &geometry);
/* try to extend the dest geometry from the root coordinate's point of view */
if (window->horizontal
&& root_y >= geometry.y
&& root_y <= geometry.y + geometry.height
&& (dest->x + dest->width == geometry.x
|| dest->x == geometry.x + geometry.width))
{
/* extend the maximum area horizontally */
dest->x = MIN (dest->x, geometry.x);
dest->width += geometry.width;
}
else if (window->horizontal == FALSE
&& root_x >= geometry.x
&& root_x <= geometry.x + geometry.width
&& (dest->y + dest->height == geometry.y
|| dest->y == geometry.y + geometry.height))
{
/* extend the maximum area vertically */
dest->y = MIN (dest->y, geometry.y);
dest->height += geometry.height;
}
}
}
}
}
static gboolean
panel_window_struts_are_possible (PanelWindow *window,
gint x,
gint y,
gint width,
gint height)
{
GdkScreen *screen;
gint n_monitors;
gint i;
GdkRectangle geometry;
panel_return_val_if_fail (PANEL_IS_WINDOW (window), FALSE);
/* never set struts when we don't snap or when autohide is enabled */
if (window->snap_edge == PANEL_SNAP_EGDE_NONE || window->autohide_status != DISABLED)
return FALSE;
/* always set struts on the following condition */
if ((window->horizontal && y == 0) || (!window->horizontal && x == 0))
return TRUE;
/* get panel screen */
screen = gtk_window_get_screen (GTK_WINDOW (window));
/* get the number of monitors */
n_monitors = gdk_screen_get_n_monitors (screen);
if (G_LIKELY (n_monitors == 1))
{
/* don't set the struts when we're not at a screen edge */
if ((window->horizontal && y + height != gdk_screen_get_height (screen))
|| (!window->horizontal && x + width != gdk_screen_get_width (screen)))
return FALSE;
}
else
{
for (i = 0; i < n_monitors; i++)
{
/* get the monitor geometry */
gdk_screen_get_monitor_geometry (screen, i, &geometry);
if (window->horizontal
&& x >= geometry.x
&& x + width <= geometry.x + geometry.width
&& y + height < geometry.y + geometry.height)
return FALSE;
if (window->horizontal == FALSE
&& y >= geometry.y
&& y + height <= geometry.y + geometry.height
&& x + width < geometry.x + geometry.width)
return FALSE;
}
}
return TRUE;
}
static void
panel_window_struts_update (PanelWindow *window,
gint x,
gint y,
gint width,
gint height)
{
gulong struts[N_STRUTS] = { 0, };
GdkScreen *screen;
guint i;
gboolean update_struts = FALSE;
panel_return_if_fail (PANEL_IS_WINDOW (window));
panel_return_if_fail (GDK_IS_WINDOW (GTK_WIDGET (window)->window));
panel_return_if_fail (N_STRUTS == 12);
panel_return_if_fail (cardinal_atom != GDK_NONE);
if (G_UNLIKELY (window->struts_possible == -1))
{
/* check whether struts are possible, skip to apply if not */
window->struts_possible = panel_window_struts_are_possible (window, x, y, width, height);
/* struts are not possible, reset them only this time */
if (window->struts_possible == 0)
goto reset_only;
}
/* get the panel window screen */
screen = gtk_window_get_screen (GTK_WINDOW (window));
if (window->horizontal)
{
if (snap_edge_is_top (window->snap_edge))
{
/* the window is snapped on the top screen edge */
struts[STRUT_TOP] = y + height;
struts[STRUT_TOP_START_X] = x;
struts[STRUT_TOP_END_X] = x + width;
}
else if (snap_edge_is_bottom (window->snap_edge))
{
/* the window is snapped on the bottom screen edge */
struts[STRUT_BOTTOM] = gdk_screen_get_height (screen) - y;
struts[STRUT_BOTTOM_START_X] = x;
struts[STRUT_BOTTOM_END_X] = x + width;
}
}
else /* vertical */
{
if (snap_edge_is_left (window->snap_edge))
{
/* the window is snapped on the left screen edge */
struts[STRUT_LEFT] = x + width;
struts[STRUT_LEFT_START_Y] = y;
struts[STRUT_LEFT_END_Y] = y + height;
}
else if (snap_edge_is_right (window->snap_edge))
{
/* the window is snapped on the right screen edge */
struts[STRUT_RIGHT] = gdk_screen_get_width (screen) - x;
struts[STRUT_RIGHT_START_Y] = y;
struts[STRUT_RIGHT_END_Y] = y + height;
}
}
reset_only:
for (i = 0; i < N_STRUTS; i++)
{
/* check if we need to update */
if (struts[i] != window->struts[i])
update_struts = TRUE;
/* store new strut */
window->struts[i] = struts[i];
}
if (update_struts)
{
/* don't crash on x errors */
gdk_error_trap_push ();
/* set the wm strut partial */
gdk_property_change (GTK_WIDGET (window)->window, net_wm_strut_partial_atom,
cardinal_atom, 32, GDK_PROP_MODE_REPLACE, (guchar *) &struts, 12);
/* set the wm strut */
gdk_property_change (GTK_WIDGET (window)->window, net_wm_strut_atom,
cardinal_atom, 32, GDK_PROP_MODE_REPLACE, (guchar *) &struts, 4);
/* release the trap push */
gdk_error_trap_pop ();
#if 0
gint n = -1;
const gchar *names1[] = { "left", "right", "top", "bottom" };
const gchar *names2[] = { "y", "y", "x", "x" };
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;
if (n == -1)
g_print ("Struts: All set to zero\n");
else
g_print ("Struts: %s = %ld, start_%s = %ld, end_%s = %ld\n", names1[n],
struts[n], names2[n], struts[4 + n * 2], names2[n], struts[5 + n * 2]);
#endif
}
}
static void
panel_window_set_colormap (PanelWindow *window)
{
GdkColormap *colormap = NULL;
GdkScreen *screen;
gboolean restore;
GtkWidget *widget = GTK_WIDGET (window);
gint root_x, root_y;
panel_return_if_fail (PANEL_IS_WINDOW (window));
/* whether the widget was previously visible */
restore = GTK_WIDGET_REALIZED (widget);
/* unrealize the window if needed */
if (restore)
{
/* store the window position */
gtk_window_get_position (GTK_WINDOW (window), &root_x, &root_y);
/* reset the struts */
if (window->struts_possible == 1)
panel_window_struts_update (window, 0, 0, 0, 0);
/* hide the widget */
gtk_widget_hide (widget);
gtk_widget_unrealize (widget);
}
/* set bool */
window->is_composited = gtk_widget_is_composited (widget);
/* get the screen */
screen = gtk_window_get_screen (GTK_WINDOW (window));
/* try to get the rgba colormap */
if (window->is_composited)
colormap = gdk_screen_get_rgba_colormap (screen);
/* get the default colormap */
if (colormap == NULL)
{
colormap = gdk_screen_get_rgb_colormap (screen);
window->is_composited = FALSE;
}
/* set the colormap */
if (G_LIKELY (colormap))
gtk_widget_set_colormap (widget, colormap);
/* restore the window */
if (restore)
{
/* restore the position */
gtk_window_move (GTK_WINDOW (window), root_x, root_y);
/* show the widget again */
gtk_widget_realize (widget);
gtk_widget_show (widget);
/* set the struts again */
if (window->struts_possible == 1)
panel_window_struts_update (window, root_x, root_y, widget->allocation.width, widget->allocation.height);
}
}
static void
panel_window_get_position (PanelWindow *window,
gint *root_x,
gint *root_y)
{
/* get the window position of the visible window */
if (G_UNLIKELY (window->autohide_window
&& (window->autohide_status == HIDDEN || window->autohide_status == POPUP_QUEUED)))
gtk_window_get_position (GTK_WINDOW (window->autohide_window), root_x, root_y);
else
gtk_window_get_position (GTK_WINDOW (window), root_x, root_y);
}
GtkWidget *
panel_window_new (void)
{
return g_object_new (PANEL_TYPE_WINDOW, NULL);
}
gboolean
panel_window_is_composited (PanelWindow *window)
{
panel_return_val_if_fail (PANEL_IS_WINDOW (window), FALSE);
return window->is_composited;
}
void
panel_window_set_selected (PanelWindow *window,
gboolean selected)
{
panel_return_if_fail (PANEL_IS_WINDOW (window));
if (G_UNLIKELY (window->selected != selected))
{
/* set new value */
window->selected = selected;
/* queue a redraw */
gtk_widget_queue_draw (GTK_WIDGET (window));
}
}
PanelWindowSnapEdge
panel_window_get_snap_edge (PanelWindow *window)
{
panel_return_val_if_fail (PANEL_IS_WINDOW (window), PANEL_SNAP_EGDE_NONE);
return window->snap_edge;
}
void
panel_window_set_snap_edge (PanelWindow *window,
PanelWindowSnapEdge snap_edge)
{
panel_return_if_fail (PANEL_IS_WINDOW (window));
if (G_LIKELY (window->snap_edge != snap_edge))
{
/* set snap edge value */
window->snap_edge = snap_edge;
/* queue a resize */
gtk_widget_queue_resize (GTK_WIDGET (window));
}
}
gboolean
panel_window_get_locked (PanelWindow *window)
{
panel_return_val_if_fail (PANEL_IS_WINDOW (window), FALSE);
return window->locked;
}
void
panel_window_set_locked (PanelWindow *window,
gboolean locked)
{
panel_return_if_fail (PANEL_IS_WINDOW (window));
if (G_LIKELY (window->locked != locked))
{
/* set new lock value */
window->locked = !!locked;
/* queue a resize */
gtk_widget_queue_resize (GTK_WIDGET (window));
}
}
GtkOrientation
panel_window_get_orientation (PanelWindow *window)
{
panel_return_val_if_fail (PANEL_IS_WINDOW (window), GTK_ORIENTATION_HORIZONTAL);
return window->horizontal ? GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL;
}
void
panel_window_set_orientation (PanelWindow *window,
GtkOrientation orientation)
{
gboolean horizontal;
panel_return_if_fail (PANEL_IS_WINDOW (window));
/* whether the orientation is horizontal */
horizontal = !!(orientation == GTK_ORIENTATION_HORIZONTAL);
if (G_LIKELY ((gboolean) window->horizontal != horizontal))
{
/* set new orientation */
window->horizontal = horizontal;
/* resize */
gtk_widget_queue_resize (GTK_WIDGET (window));
/* notify listeners */
g_object_notify (G_OBJECT (window), "orientation");
}
}
gint
panel_window_get_size (PanelWindow *window)
{
panel_return_val_if_fail (PANEL_IS_WINDOW (window), 0);
return window->size;
}
void
panel_window_set_size (PanelWindow *window,
gint size)
{
panel_return_if_fail (PANEL_IS_WINDOW (window));
if (G_LIKELY (window->size != size))
{
/* set new size */
window->size = size;
/* resize */
gtk_widget_queue_resize (GTK_WIDGET (window));
}
}
gint
panel_window_get_length (PanelWindow *window)
{
panel_return_val_if_fail (PANEL_IS_WINDOW (window), 0);
return rint (window->length * 100.00);
}
void
panel_window_set_length (PanelWindow *window,
gint percentage)
{
gdouble length;
panel_return_if_fail (PANEL_IS_WINDOW (window));
/* normalize value */
length = CLAMP (percentage, 1, 100) / 100.00;
if (G_LIKELY (window->length != length))
{
/* set new length */
window->length = length;
/* resize */
gtk_widget_queue_resize (GTK_WIDGET (window));
}
}
gint
panel_window_get_xoffset (PanelWindow *window)
{
gint root_x;
panel_return_val_if_fail (PANEL_IS_WINDOW (window), 0);
/* get the panel window position */
panel_window_get_position (window, &root_x, NULL);
return root_x;
}
void
panel_window_set_xoffset (PanelWindow *window,
gint xoffset)
{
gint x, y;
panel_return_if_fail (PANEL_IS_WINDOW (window));
/* get window position */
gtk_window_get_position (GTK_WINDOW (window), &x, &y);
/* move window is needed */
if (G_LIKELY (x != xoffset))
gtk_window_move (GTK_WINDOW (window), xoffset, y);
}
gint
panel_window_get_yoffset (PanelWindow *window)
{
gint root_y;
panel_return_val_if_fail (PANEL_IS_WINDOW (window), 0);
/* get the panel window position */
panel_window_get_position (window, NULL, &root_y);
return root_y;
}
void
panel_window_set_yoffset (PanelWindow *window,
gint yoffset)
{
gint x, y;
panel_return_if_fail (PANEL_IS_WINDOW (window));
/* get window position */
gtk_window_get_position (GTK_WINDOW (window), &x, &y);
/* move window if needed */
if (G_LIKELY (y != yoffset))
gtk_window_move (GTK_WINDOW (window), x, yoffset);
}
gboolean
panel_window_get_autohide (PanelWindow *window)
{
panel_return_val_if_fail (PANEL_IS_WINDOW (window), FALSE);
return !!(window->autohide_status != DISABLED);
}
void
panel_window_set_autohide (PanelWindow *window,
gboolean autohide)
{
AutohideStatus status;
panel_return_if_fail (PANEL_IS_WINDOW (window));
if (G_LIKELY (panel_window_get_autohide (window) != autohide))
{
/* determ whether struts are possible on the next resize */
window->struts_possible = -1;
if (autohide)
{
/* create popup window if needed */
if (window->autohide_window == NULL)
window->autohide_window = panel_window_autohide_window (window);
/* get the correct status */
status = window->autohide_block == 0 ? POPDOWN_QUEUED_SLOW : BLOCKED;
/* queue a popdown */
panel_window_autohide_queue (window, status);
}
else
{
/* disable autohiding */
panel_window_autohide_queue (window, DISABLED);
/* destroy the autohide window */
if (window->autohide_window)
{
gtk_widget_destroy (window->autohide_window);
window->autohide_window = NULL;
}
}
}
}
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++;
/* block autohide */
if (window->autohide_status != DISABLED && window->autohide_block == 1)
panel_window_autohide_queue (window, 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--;
/* queue an autohide when needed */
if (window->autohide_status != DISABLED && window->autohide_block == 0)
panel_window_autohide_queue (window, POPDOWN_QUEUED);
}
gint
panel_window_get_background_alpha (PanelWindow *window)
{
panel_return_val_if_fail (PANEL_IS_WINDOW (window), 100);
return rint (window->background_alpha * 100.00);
}
void
panel_window_set_background_alpha (PanelWindow *window,
gint alpha)
{
gdouble value;
panel_return_if_fail (PANEL_IS_WINDOW (window));
panel_return_if_fail (alpha >= 0 && alpha <= 100);
value = CLAMP (alpha, 0, 100) / 100.00;
if (G_LIKELY (window->background_alpha != value))
{
/* set new alpha value */
window->background_alpha = value;
/* redraw */
gtk_widget_queue_draw (GTK_WIDGET (window));
}
}
gint
panel_window_get_enter_opacity (PanelWindow *window)
{
panel_return_val_if_fail (PANEL_IS_WINDOW (window), 100);
return rint (window->enter_opacity * 100.00);
}
void
panel_window_set_enter_opacity (PanelWindow *window,
gint opacity)
{
gdouble value;
panel_return_if_fail (PANEL_IS_WINDOW (window));
panel_return_if_fail (opacity >= 0 && opacity <= 100);
value = CLAMP (opacity, 0, 100) / 100.00;
if (G_LIKELY (window->enter_opacity != value))
{
/* set new opacity */
window->enter_opacity = value;
}
}
gint
panel_window_get_leave_opacity (PanelWindow *window)
{
panel_return_val_if_fail (PANEL_IS_WINDOW (window), 100);
return rint (window->leave_opacity * 100.00);
}
void
panel_window_set_leave_opacity (PanelWindow *window,
gint opacity)
{
gdouble value;
panel_return_if_fail (PANEL_IS_WINDOW (window));
panel_return_if_fail (opacity >= 0 && opacity <= 100);
value = CLAMP (opacity, 0, 100) / 100.00;
if (window->leave_opacity != value)
{
/* set new value */
window->leave_opacity = value;
/* update the panel window opacity */
_window_set_opacity (GTK_WINDOW (window), value);
/* set the autohide window opacity if created */
if (window->autohide_window)
_window_set_opacity (GTK_WINDOW (window->autohide_window), value);
}
}
gboolean
panel_window_get_span_monitors (PanelWindow *window)
{
panel_return_val_if_fail (PANEL_IS_WINDOW (window), FALSE);
return window->span_monitors;
}
void
panel_window_set_span_monitors (PanelWindow *window,
gboolean span_monitors)
{
panel_return_if_fail (PANEL_IS_WINDOW (window));
if (window->span_monitors != span_monitors)
{
window->span_monitors = span_monitors;
gtk_widget_queue_resize (GTK_WIDGET (window));
}
}