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.
 
 
 
 
 

2251 lines
69 KiB

  1. /* $Id$ */
  2. /*
  3. * Copyright (C) 2008-2009 Nick Schermer <nick@xfce.org>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License along
  16. * with this program; if not, write to the Free Software Foundation, Inc.,
  17. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  18. */
  19. #ifdef HAVE_CONFIG_H
  20. #include <config.h>
  21. #endif
  22. #ifdef HAVE_MATH_H
  23. #include <math.h>
  24. #endif
  25. #include <exo/exo.h>
  26. #include <libxfce4panel/libxfce4panel.h>
  27. #include <common/panel-private.h>
  28. #include <panel/panel-window.h>
  29. #include <panel/panel-glue.h>
  30. #include <panel/panel-application.h>
  31. #include <panel/panel-plugin-external.h>
  32. #include <panel/panel-item-dialog.h>
  33. #include <panel/panel-preferences-dialog.h>
  34. #include <panel/panel-dialogs.h>
  35. #include <panel/panel-dbus-service.h>
  36. #define HANDLE_SIZE (8)
  37. #define HANDLE_SPACING (2)
  38. #define HANDLE_SIZE_TOTAL ((HANDLE_SIZE + HANDLE_SPACING) * 2)
  39. #define SNAP_DISTANCE (10)
  40. #define POPUP_DELAY (225)
  41. #define POPDOWN_DELAY (350)
  42. #define HIDDEN_PANEL_SIZE (2)
  43. #define OFFSCREEN (-9999)
  44. static void panel_window_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
  45. static void panel_window_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
  46. static void panel_window_finalize (GObject *object);
  47. static void panel_window_realize (GtkWidget *widget);
  48. static gboolean panel_window_expose_event (GtkWidget *widget, GdkEventExpose *event);
  49. static gboolean panel_window_motion_notify (GtkWidget *widget, GdkEventMotion *event);
  50. static gboolean panel_window_button_press_event (GtkWidget *widget, GdkEventButton *event);
  51. static gboolean panel_window_button_release_event (GtkWidget *widget, GdkEventButton *event);
  52. static gboolean panel_window_enter_notify_event (GtkWidget *widget, GdkEventCrossing *event);
  53. static gboolean panel_window_leave_notify_event (GtkWidget *widget, GdkEventCrossing *event);
  54. static void panel_window_grab_notify (GtkWidget *widget, gboolean was_grabbed);
  55. static void panel_window_size_request (GtkWidget *widget, GtkRequisition *requisition);
  56. static void panel_window_size_allocate (GtkWidget *widget, GtkAllocation *allocation);
  57. static void panel_window_screen_changed (GtkWidget *widget, GdkScreen *previous_screen);
  58. static void panel_window_paint_handle (PanelWindow *window, gboolean start, GtkStateType state, cairo_t *rc);
  59. static void panel_window_paint_borders (PanelWindow *window, GtkStateType state, cairo_t *rc);
  60. static void panel_window_calculate_position (PanelWindow *window, gint width, gint height, gint *x, gint *y);
  61. static void panel_window_working_area (PanelWindow *window, gint root_x, gint root_y, GdkRectangle *dest);
  62. static gboolean panel_window_struts_are_possible (PanelWindow *window, gint x, gint y, gint width, gint height);
  63. static void panel_window_struts_update (PanelWindow *window, gint x, gint y, gint width, gint height);
  64. static void panel_window_set_colormap (PanelWindow *window);
  65. static void panel_window_get_position (PanelWindow *window, gint *root_x, gint *root_y);
  66. static void panel_window_set_borders (PanelWindow *window);
  67. static void panel_window_set_autohide (PanelWindow *window, gboolean autohide);
  68. static void panel_window_menu_quit (gpointer boolean);
  69. static void panel_window_menu_deactivate (GtkMenu *menu, PanelWindow *window);
  70. static void panel_window_menu_popup (PanelWindow *window);
  71. static void panel_window_set_plugin_background_alpha (GtkWidget *widget, gpointer user_data);
  72. static void panel_window_set_plugin_size (GtkWidget *widget, gpointer user_data);
  73. static void panel_window_set_plugin_orientation (GtkWidget *widget, gpointer user_data);
  74. enum
  75. {
  76. PROP_0,
  77. PROP_HORIZONTAL,
  78. PROP_SIZE,
  79. PROP_LENGTH,
  80. PROP_LOCKED,
  81. PROP_X_OFFSET,
  82. PROP_Y_OFFSET,
  83. PROP_ENTER_OPACITY,
  84. PROP_LEAVE_OPACITY,
  85. PROP_SNAP_EDGE,
  86. PROP_BACKGROUND_ALPHA,
  87. PROP_SPAN_MONITORS,
  88. PROP_AUTOHIDE
  89. };
  90. enum
  91. {
  92. SNAP_NONE,
  93. SNAP_START,
  94. SNAP_CENTER,
  95. SNAP_END
  96. };
  97. typedef enum
  98. {
  99. DISABLED,
  100. BLOCKED,
  101. VISIBLE,
  102. POPUP_QUEUED,
  103. HIDDEN,
  104. POPDOWN_QUEUED,
  105. POPDOWN_QUEUED_SLOW
  106. }
  107. AutohideStatus;
  108. enum
  109. {
  110. STRUT_LEFT = 0,
  111. STRUT_RIGHT,
  112. STRUT_TOP,
  113. STRUT_BOTTOM,
  114. STRUT_LEFT_START_Y,
  115. STRUT_LEFT_END_Y,
  116. STRUT_RIGHT_START_Y,
  117. STRUT_RIGHT_END_Y,
  118. STRUT_TOP_START_X,
  119. STRUT_TOP_END_X,
  120. STRUT_BOTTOM_START_X,
  121. STRUT_BOTTOM_END_X,
  122. N_STRUTS
  123. };
  124. struct _PanelWindowClass
  125. {
  126. GtkWindowClass __parent__;
  127. };
  128. struct _PanelWindow
  129. {
  130. GtkWindow __parent__;
  131. /* last allocated size, for recentering */
  132. GtkAllocation prev_allocation;
  133. /* snapping edge of the window */
  134. PanelWindowSnapEdge snap_edge;
  135. /* the borders we're going to draw */
  136. PanelWindowBorders borders;
  137. /* whether we should apply struts for this screen position */
  138. gint struts_possible;
  139. /* the last used struts for this window */
  140. gulong struts[N_STRUTS];
  141. /* the last calculated panel working area */
  142. GdkRectangle working_area;
  143. /* whether we span monitors */
  144. guint span_monitors : 1;
  145. /* whether the panel has a rgba colormap */
  146. guint is_composited : 1;
  147. /* whether the panel is locked */
  148. guint locked : 1;
  149. /* active panel redraw timeout id */
  150. guint active_timeout_id;
  151. /* panel orientation */
  152. guint horizontal : 1;
  153. /* panel size (px) and length (%) */
  154. guint size;
  155. gdouble length;
  156. /* autohide */
  157. AutohideStatus autohide_status;
  158. guint autohide_timer;
  159. gint autohide_block;
  160. /* the window we use to show during autohide */
  161. GtkWidget *autohide_window;
  162. /* background alpha */
  163. gdouble background_alpha;
  164. /* panel enter/leave opacity */
  165. gdouble enter_opacity;
  166. gdouble leave_opacity;
  167. /* variables for dragging the panel */
  168. guint drag_motion : 1;
  169. gint drag_start_x;
  170. gint drag_start_y;
  171. };
  172. static GdkAtom cardinal_atom = GDK_NONE;
  173. static GdkAtom net_wm_strut_atom = GDK_NONE;
  174. static GdkAtom net_wm_strut_partial_atom = GDK_NONE;
  175. G_DEFINE_TYPE (PanelWindow, panel_window, GTK_TYPE_WINDOW);
  176. static void
  177. panel_window_class_init (PanelWindowClass *klass)
  178. {
  179. GObjectClass *gobject_class;
  180. GtkWidgetClass *gtkwidget_class;
  181. gobject_class = G_OBJECT_CLASS (klass);
  182. gobject_class->get_property = panel_window_get_property;
  183. gobject_class->set_property = panel_window_set_property;
  184. gobject_class->finalize = panel_window_finalize;
  185. gtkwidget_class = GTK_WIDGET_CLASS (klass);
  186. gtkwidget_class->realize = panel_window_realize;
  187. gtkwidget_class->expose_event = panel_window_expose_event;
  188. gtkwidget_class->motion_notify_event = panel_window_motion_notify;
  189. gtkwidget_class->button_press_event = panel_window_button_press_event;
  190. gtkwidget_class->button_release_event = panel_window_button_release_event;
  191. gtkwidget_class->enter_notify_event = panel_window_enter_notify_event;
  192. gtkwidget_class->leave_notify_event = panel_window_leave_notify_event;
  193. gtkwidget_class->grab_notify = panel_window_grab_notify;
  194. gtkwidget_class->size_request = panel_window_size_request;
  195. gtkwidget_class->size_allocate = panel_window_size_allocate;
  196. gtkwidget_class->screen_changed = panel_window_screen_changed;
  197. g_object_class_install_property (gobject_class,
  198. PROP_HORIZONTAL,
  199. g_param_spec_boolean ("horizontal", NULL, NULL,
  200. TRUE,
  201. EXO_PARAM_READWRITE));
  202. g_object_class_install_property (gobject_class,
  203. PROP_SIZE,
  204. g_param_spec_uint ("size", NULL, NULL,
  205. 16, 128, 48,
  206. EXO_PARAM_READWRITE));
  207. g_object_class_install_property (gobject_class,
  208. PROP_LENGTH,
  209. g_param_spec_uint ("length", NULL, NULL,
  210. 1, 100, 25,
  211. EXO_PARAM_READWRITE));
  212. g_object_class_install_property (gobject_class,
  213. PROP_LOCKED,
  214. g_param_spec_boolean ("locked", NULL, NULL,
  215. FALSE,
  216. EXO_PARAM_READWRITE));
  217. g_object_class_install_property (gobject_class,
  218. PROP_X_OFFSET,
  219. g_param_spec_uint ("x-offset", NULL, NULL,
  220. 0, G_MAXUINT, 0,
  221. EXO_PARAM_READWRITE));
  222. g_object_class_install_property (gobject_class,
  223. PROP_Y_OFFSET,
  224. g_param_spec_uint ("y-offset", NULL, NULL,
  225. 0, G_MAXUINT, 0,
  226. EXO_PARAM_READWRITE));
  227. g_object_class_install_property (gobject_class,
  228. PROP_ENTER_OPACITY,
  229. g_param_spec_uint ("enter-opacity", NULL, NULL,
  230. 0, 100, 100,
  231. EXO_PARAM_READWRITE));
  232. g_object_class_install_property (gobject_class,
  233. PROP_LEAVE_OPACITY,
  234. g_param_spec_uint ("leave-opacity", NULL, NULL,
  235. 0, 100, 100,
  236. EXO_PARAM_READWRITE));
  237. g_object_class_install_property (gobject_class,
  238. PROP_BACKGROUND_ALPHA,
  239. g_param_spec_uint ("background-alpha", NULL, NULL,
  240. 0, 100, 100,
  241. EXO_PARAM_READWRITE));
  242. g_object_class_install_property (gobject_class,
  243. PROP_AUTOHIDE,
  244. g_param_spec_boolean ("autohide", NULL, NULL,
  245. FALSE,
  246. EXO_PARAM_READWRITE));
  247. g_object_class_install_property (gobject_class,
  248. PROP_SPAN_MONITORS,
  249. g_param_spec_boolean ("span-monitors", NULL, NULL,
  250. FALSE,
  251. EXO_PARAM_READWRITE));
  252. g_object_class_install_property (gobject_class,
  253. PROP_SNAP_EDGE,
  254. g_param_spec_uint ("snap-edge", NULL, NULL,
  255. PANEL_SNAP_EGDE_NONE,
  256. PANEL_SNAP_EGDE_S,
  257. PANEL_SNAP_EGDE_NONE,
  258. EXO_PARAM_READWRITE));
  259. /* initialize the atoms */
  260. cardinal_atom = gdk_atom_intern_static_string ("CARDINAL");
  261. net_wm_strut_atom = gdk_atom_intern_static_string ("_NET_WM_STRUT");
  262. net_wm_strut_partial_atom = gdk_atom_intern_static_string ("_NET_WM_STRUT_PARTIAL");
  263. }
  264. static void
  265. panel_window_init (PanelWindow *window)
  266. {
  267. GdkScreen *screen;
  268. /* set window properties */
  269. gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
  270. gtk_window_set_decorated (GTK_WINDOW (window), FALSE);
  271. gtk_window_set_type_hint (GTK_WINDOW (window), GDK_WINDOW_TYPE_HINT_DOCK);
  272. gtk_window_set_gravity (GTK_WINDOW (window), GDK_GRAVITY_STATIC);
  273. /* init vars */
  274. window->is_composited = FALSE;
  275. window->drag_motion = FALSE;
  276. window->struts_possible = -1;
  277. window->size = 48;
  278. window->snap_edge = PANEL_SNAP_EGDE_NONE;
  279. window->borders = 0;
  280. window->span_monitors = FALSE;
  281. window->length = 0.25;
  282. window->horizontal = TRUE;
  283. window->background_alpha = 1.00;
  284. window->enter_opacity = 1.00;
  285. window->leave_opacity = 1.00;
  286. window->autohide_timer = 0;
  287. window->autohide_status = DISABLED;
  288. window->autohide_block = 0;
  289. window->autohide_window = NULL;
  290. window->active_timeout_id = 0;
  291. /* set additional events we want to have */
  292. gtk_widget_add_events (GTK_WIDGET (window), GDK_BUTTON_PRESS_MASK);
  293. /* connect signal to monitor the compositor changes */
  294. g_signal_connect (G_OBJECT (window), "composited-changed", G_CALLBACK (panel_window_set_colormap), NULL);
  295. /* set the colormap */
  296. panel_window_set_colormap (window);
  297. /* get the window screen */
  298. screen = gtk_window_get_screen (GTK_WINDOW (window));
  299. /* connect screen update signals */
  300. g_signal_connect_swapped (G_OBJECT (screen), "size-changed", G_CALLBACK (panel_window_screen_changed), window);
  301. #if GTK_CHECK_VERSION (2,14,0)
  302. g_signal_connect_swapped (G_OBJECT (screen), "monitors-changed", G_CALLBACK (panel_window_screen_changed), window);
  303. #endif
  304. }
  305. static void
  306. panel_window_get_property (GObject *object,
  307. guint prop_id,
  308. GValue *value,
  309. GParamSpec *pspec)
  310. {
  311. PanelWindow *window = PANEL_WINDOW (object);
  312. //gint pos;
  313. switch (prop_id)
  314. {
  315. case PROP_HORIZONTAL:
  316. g_value_set_boolean (value, window->horizontal);
  317. break;
  318. case PROP_SIZE:
  319. g_value_set_uint (value, window->size);
  320. break;
  321. case PROP_LENGTH:
  322. g_value_set_uint (value, rint (window->length * 100.00));
  323. break;
  324. case PROP_LOCKED:
  325. g_value_set_boolean (value, window->locked);
  326. break;
  327. case PROP_X_OFFSET:
  328. //panel_window_get_position (window, &pos, NULL);
  329. //g_value_set_uint (value, pos);
  330. g_value_set_uint (value, 0);
  331. break;
  332. case PROP_Y_OFFSET:
  333. //panel_window_get_position (window, NULL, &pos);
  334. //g_value_set_uint (value, pos);
  335. g_value_set_uint (value, 0);
  336. break;
  337. case PROP_ENTER_OPACITY:
  338. g_value_set_uint (value, rint (window->enter_opacity * 100.00));
  339. break;
  340. case PROP_LEAVE_OPACITY:
  341. g_value_set_uint (value, rint (window->leave_opacity * 100.00));
  342. break;
  343. case PROP_BACKGROUND_ALPHA:
  344. g_value_set_uint (value, rint (window->background_alpha * 100.00));
  345. break;
  346. case PROP_SNAP_EDGE:
  347. g_value_set_uint (value, window->snap_edge);
  348. break;
  349. case PROP_SPAN_MONITORS:
  350. g_value_set_boolean (value, window->span_monitors);
  351. break;
  352. case PROP_AUTOHIDE:
  353. g_value_set_boolean (value, !!(window->autohide_status != DISABLED));
  354. break;
  355. default:
  356. G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
  357. break;
  358. }
  359. }
  360. static void
  361. panel_window_set_property (GObject *object,
  362. guint prop_id,
  363. const GValue *value,
  364. GParamSpec *pspec)
  365. {
  366. PanelWindow *window = PANEL_WINDOW (object);
  367. //gint pos;
  368. switch (prop_id)
  369. {
  370. case PROP_HORIZONTAL:
  371. /* set whether the panel */
  372. window->horizontal = g_value_get_boolean (value);
  373. /* update all the panel plugins */
  374. gtk_container_foreach (GTK_CONTAINER (gtk_bin_get_child (GTK_BIN (window))),
  375. panel_window_set_plugin_orientation,
  376. GUINT_TO_POINTER (window->horizontal ? GTK_ORIENTATION_HORIZONTAL:
  377. GTK_ORIENTATION_VERTICAL));
  378. /* queue a resize */
  379. gtk_widget_queue_resize (GTK_WIDGET (window));
  380. break;
  381. case PROP_SIZE:
  382. /* update the panel size */
  383. window->size = g_value_get_uint (value);
  384. /* update all the panel plugins */
  385. gtk_container_foreach (GTK_CONTAINER (gtk_bin_get_child (GTK_BIN (window))),
  386. panel_window_set_plugin_size,
  387. GUINT_TO_POINTER (window->size));
  388. /* queue a resize */
  389. gtk_widget_queue_resize (GTK_WIDGET (window));
  390. break;
  391. case PROP_LENGTH:
  392. /* set the new length */
  393. window->length = g_value_get_uint (value) / 100.00;
  394. /* update the border and resize */
  395. panel_window_set_borders (window);
  396. gtk_widget_queue_resize (GTK_WIDGET (window));
  397. break;
  398. case PROP_LOCKED:
  399. /* set new lock value and resize */
  400. window->locked = g_value_get_boolean (value);
  401. gtk_widget_queue_resize (GTK_WIDGET (window));
  402. break;
  403. case PROP_X_OFFSET:
  404. /* get window position */
  405. //gtk_window_get_position (GTK_WINDOW (window), NULL, &pos);
  406. //gtk_window_move (GTK_WINDOW (window), g_value_get_uint (value), pos);
  407. break;
  408. case PROP_Y_OFFSET:
  409. /* get window position */
  410. //gtk_window_get_position (GTK_WINDOW (window), &pos, NULL);
  411. //gtk_window_move (GTK_WINDOW (window), pos, g_value_get_uint (value));
  412. break;
  413. case PROP_ENTER_OPACITY:
  414. /* set the new enter opacity */
  415. window->enter_opacity = g_value_get_uint (value) / 100.00;
  416. break;
  417. case PROP_LEAVE_OPACITY:
  418. /* set the new leave opacity */
  419. window->leave_opacity = g_value_get_uint (value) / 100.00;
  420. /* set the autohide window opacity if created */
  421. if (window->autohide_window)
  422. gtk_window_set_opacity (GTK_WINDOW (window->autohide_window), window->leave_opacity);
  423. /* update the panel window opacity */
  424. gtk_window_set_opacity (GTK_WINDOW (window), window->leave_opacity);
  425. break;
  426. case PROP_BACKGROUND_ALPHA:
  427. /* set the new value and redraw the panel */
  428. window->background_alpha = g_value_get_uint (value) / 100.00;
  429. gtk_widget_queue_draw (GTK_WIDGET (window));
  430. /* update the external plugins */
  431. gtk_container_foreach (GTK_CONTAINER (gtk_bin_get_child (GTK_BIN (window))),
  432. panel_window_set_plugin_background_alpha,
  433. GUINT_TO_POINTER (g_value_get_uint (value)));
  434. break;
  435. case PROP_SNAP_EDGE:
  436. /* set snap edge value */
  437. window->snap_edge = g_value_get_uint (value);
  438. /* update the window borders */
  439. panel_window_set_borders (window);
  440. /* queue a resize */
  441. gtk_widget_queue_resize (GTK_WIDGET (window));
  442. break;
  443. case PROP_SPAN_MONITORS:
  444. /* store new value */
  445. window->span_monitors = g_value_get_boolean (value);
  446. /* update the working area */
  447. panel_window_working_area (window, -1, -1, &window->working_area);
  448. /* resize the panel */
  449. gtk_widget_queue_resize (GTK_WIDGET (window));
  450. break;
  451. case PROP_AUTOHIDE:
  452. panel_window_set_autohide (window, g_value_get_boolean (value));
  453. break;
  454. default:
  455. G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
  456. break;
  457. }
  458. }
  459. static void
  460. panel_window_finalize (GObject *object)
  461. {
  462. PanelWindow *window = PANEL_WINDOW (object);
  463. /* stop a running active timeout id */
  464. if (window->active_timeout_id != 0)
  465. g_source_remove (window->active_timeout_id);
  466. /* stop the autohide timeout */
  467. if (window->autohide_timer != 0)
  468. g_source_remove (window->autohide_timer);
  469. /* destroy autohide window */
  470. if (window->autohide_window != NULL)
  471. gtk_widget_destroy (window->autohide_window);
  472. (*G_OBJECT_CLASS (panel_window_parent_class)->finalize) (object);
  473. }
  474. static void
  475. panel_window_realize (GtkWidget *widget)
  476. {
  477. /* realize the window */
  478. (*GTK_WIDGET_CLASS (panel_window_parent_class)->realize) (widget);
  479. /* initialize the working area */
  480. panel_window_working_area (PANEL_WINDOW (widget), -1, -1, &PANEL_WINDOW (widget)->working_area);
  481. }
  482. static gboolean
  483. panel_window_expose_event (GtkWidget *widget,
  484. GdkEventExpose *event)
  485. {
  486. PanelWindow *window = PANEL_WINDOW (widget);
  487. cairo_t *cr;
  488. GdkColor *color;
  489. GtkStateType state = GTK_STATE_NORMAL;
  490. gdouble alpha = window->is_composited ? window->background_alpha : 1.00;
  491. if (GTK_WIDGET_DRAWABLE (widget))
  492. {
  493. /* create cairo context */
  494. cr = gdk_cairo_create (widget->window);
  495. /* clip the drawing area */
  496. gdk_cairo_rectangle (cr, &event->area);
  497. cairo_clip (cr);
  498. if (alpha < 1.00 || window->active_timeout_id != 0)
  499. {
  500. /* get the background gdk color */
  501. color = &(widget->style->bg[state]);
  502. /* set the cairo source color */
  503. xfce_panel_cairo_set_source_rgba (cr, color, alpha);
  504. /* create retangle */
  505. cairo_rectangle (cr, event->area.x, event->area.y,
  506. event->area.width, event->area.height);
  507. /* draw on source */
  508. cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
  509. /* paint rectangle */
  510. cairo_fill (cr);
  511. }
  512. /* paint handles */
  513. if (window->locked == FALSE)
  514. {
  515. panel_window_paint_handle (window, TRUE, state, cr);
  516. panel_window_paint_handle (window, FALSE, state, cr);
  517. }
  518. /* paint the panel borders */
  519. panel_window_paint_borders (window, state, cr);
  520. /* destroy cairo context */
  521. cairo_destroy (cr);
  522. }
  523. /* send expose event to child too */
  524. if (GTK_BIN (widget)->child)
  525. gtk_container_propagate_expose (GTK_CONTAINER (widget), GTK_BIN (widget)->child, event);
  526. return FALSE;
  527. }
  528. static guint
  529. panel_window_motion_notify_snap (gint value,
  530. gint length,
  531. gint start,
  532. gint end,
  533. gint *return_value)
  534. {
  535. gint tmp;
  536. /* snap in the center */
  537. tmp = start + ((end - start) - length) / 2;
  538. if (value >= tmp - SNAP_DISTANCE && value <= tmp + SNAP_DISTANCE)
  539. {
  540. *return_value = tmp;
  541. return SNAP_CENTER;
  542. }
  543. /* snap on the start */
  544. if (value >= start && value <= start + SNAP_DISTANCE)
  545. {
  546. *return_value = start;
  547. return SNAP_START;
  548. }
  549. /* snap on the end */
  550. tmp = end - length;
  551. if (value >= tmp - SNAP_DISTANCE && value <= tmp)
  552. {
  553. *return_value = tmp;
  554. return SNAP_END;
  555. }
  556. /* set value as return value */
  557. *return_value = value;
  558. return SNAP_NONE;
  559. }
  560. static gboolean
  561. panel_window_motion_notify (GtkWidget *widget,
  562. GdkEventMotion *event)
  563. {
  564. PanelWindow *window = PANEL_WINDOW (widget);
  565. gint clamp_x, clamp_y;
  566. GdkScreen *screen;
  567. gint window_width, window_height;
  568. gint window_x, window_y;
  569. GdkRectangle area;
  570. gint snap_x, snap_y;
  571. guint snap_horizontal;
  572. guint snap_vertical;
  573. PanelWindowSnapEdge snap_edge = PANEL_SNAP_EGDE_NONE;
  574. if (window->drag_motion)
  575. {
  576. /* get the pointer position and current screen */
  577. gdk_display_get_pointer (gtk_widget_get_display (widget), &screen, &window_x, &window_y, NULL);
  578. /* make sure the window is on the correct screen */
  579. gtk_window_set_screen (GTK_WINDOW (widget), screen);
  580. /* get the maximum panel area on this coordinate */
  581. panel_window_working_area (window, window_x, window_y, &area);
  582. /* convert to corner offset */
  583. window_x -= window->drag_start_x;
  584. window_y -= window->drag_start_y;
  585. /* get allocated window size, but make sure it fits in the maximum area */
  586. window_width = MIN (widget->allocation.width, area.width);
  587. window_height = MIN (widget->allocation.height, area.height);
  588. /* keep the panel inside the maximum area */
  589. clamp_x = CLAMP (window_x, area.x, area.x + area.width - window_width);
  590. clamp_y = CLAMP (window_y, area.y, area.y + area.height - window_height);
  591. /* update the drag coordinates, so dragging feels responsive when the user hits a screen edge */
  592. window->drag_start_x += window_x - clamp_x;
  593. window->drag_start_y += window_y - clamp_y;
  594. /* try to find snapping edges */
  595. snap_horizontal = panel_window_motion_notify_snap (clamp_x, window_width, area.x, area.x + area.width, &snap_x);
  596. snap_vertical = panel_window_motion_notify_snap (clamp_y, window_height, area.y, area.y + area.height, &snap_y);
  597. /* detect the snap mode */
  598. if (snap_horizontal == SNAP_START)
  599. snap_edge = PANEL_SNAP_EGDE_W + snap_vertical;
  600. else if (snap_horizontal == SNAP_END)
  601. snap_edge = PANEL_SNAP_EGDE_E + snap_vertical;
  602. else if (snap_horizontal == SNAP_CENTER && snap_vertical == SNAP_START)
  603. snap_edge = PANEL_SNAP_EGDE_NC;
  604. else if (snap_horizontal == SNAP_CENTER && snap_vertical == SNAP_END)
  605. snap_edge = PANEL_SNAP_EGDE_SC;
  606. else if (snap_horizontal == SNAP_NONE && snap_vertical == SNAP_START)
  607. snap_edge = PANEL_SNAP_EGDE_N;
  608. else if (snap_horizontal == SNAP_NONE && snap_vertical == SNAP_END)
  609. snap_edge = PANEL_SNAP_EGDE_S;
  610. /* when snapping succeeded, set the snap coordinates for visual feedback */
  611. if (snap_edge != PANEL_SNAP_EGDE_NONE)
  612. {
  613. clamp_x = snap_x;
  614. clamp_y = snap_y;
  615. }
  616. /* move and resize the window */
  617. gdk_window_move_resize (widget->window, clamp_x, clamp_y, window_width, window_height);
  618. /* if the snap edge changed, update the border */
  619. if (window->snap_edge != snap_edge)
  620. {
  621. /* set the new value */
  622. window->snap_edge = snap_edge;
  623. /* notify the property */
  624. g_object_notify (G_OBJECT (window), "snap-edge");
  625. /* update the borders */
  626. panel_window_set_borders (window);
  627. }
  628. return TRUE;
  629. }
  630. return FALSE;
  631. }
  632. static gboolean
  633. panel_window_button_press_event (GtkWidget *widget,
  634. GdkEventButton *event)
  635. {
  636. PanelWindow *window = PANEL_WINDOW (widget);
  637. GdkCursor *cursor;
  638. guint modifiers;
  639. /* get the modifiers */
  640. modifiers = event->state & gtk_accelerator_get_default_mod_mask ();
  641. if (event->button == 1
  642. && event->window == widget->window
  643. && window->locked == FALSE
  644. && modifiers == 0)
  645. {
  646. /* set initial start coordinates */
  647. window->drag_start_x = event->x;
  648. window->drag_start_y = event->y;
  649. /* create a moving cursor */
  650. cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget), GDK_FLEUR);
  651. /* try to drab the pointer */
  652. window->drag_motion = (gdk_pointer_grab (widget->window, FALSE,
  653. GDK_BUTTON_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
  654. NULL, cursor, event->time) == GDK_GRAB_SUCCESS);
  655. /* release the cursor */
  656. gdk_cursor_unref (cursor);
  657. return TRUE;
  658. }
  659. else if (event->button == 3 || (event->button == 1 && modifiers == GDK_CONTROL_MASK))
  660. {
  661. /* popup the panel menu */
  662. panel_window_menu_popup (window);
  663. return TRUE;
  664. }
  665. return FALSE;
  666. }
  667. static gboolean
  668. panel_window_button_release_event (GtkWidget *widget,
  669. GdkEventButton *event)
  670. {
  671. PanelWindow *window = PANEL_WINDOW (widget);
  672. if (window->drag_motion)
  673. {
  674. /* unset the drag */
  675. window->drag_motion = FALSE;
  676. /* release the pointer */
  677. gdk_pointer_ungrab (event->time);
  678. /* update the borders */
  679. panel_window_set_borders (window);
  680. /* update working area, struts and reallocate */
  681. panel_window_screen_changed (widget, gtk_window_get_screen (GTK_WINDOW (widget)));
  682. /* update the plugins */
  683. /* TODO panel function for this */
  684. return TRUE;
  685. }
  686. return FALSE;
  687. }
  688. static gboolean
  689. panel_window_autohide_timeout (gpointer user_data)
  690. {
  691. PanelWindow *window = PANEL_WINDOW (user_data);
  692. panel_return_val_if_fail (window->autohide_status != DISABLED
  693. && window->autohide_status != BLOCKED, FALSE);
  694. /* change status */
  695. if (window->autohide_status == POPDOWN_QUEUED || window->autohide_status == POPDOWN_QUEUED_SLOW)
  696. window->autohide_status = HIDDEN;
  697. else if (window->autohide_status == POPUP_QUEUED)
  698. window->autohide_status = VISIBLE;
  699. gtk_widget_queue_resize (GTK_WIDGET (window));
  700. return FALSE;
  701. }
  702. static void
  703. panel_window_autohide_timeout_destroy (gpointer user_data)
  704. {
  705. PANEL_WINDOW (user_data)->autohide_timer = 0;
  706. }
  707. static void
  708. panel_window_autohide_queue (PanelWindow *window,
  709. AutohideStatus status)
  710. {
  711. guint delay;
  712. panel_return_if_fail (PANEL_IS_WINDOW (window));
  713. /* stop a running autohide timeout */
  714. if (window->autohide_timer != 0)
  715. g_source_remove (window->autohide_timer);
  716. /* set new autohide status */
  717. window->autohide_status = status;
  718. /* leave when the autohide is disabled */
  719. if (status == DISABLED || status == BLOCKED)
  720. {
  721. /* queue a resize to make sure everything is visible */
  722. gtk_widget_queue_resize (GTK_WIDGET (window));
  723. }
  724. else
  725. {
  726. /* get the delay */
  727. if (status == POPDOWN_QUEUED)
  728. delay = POPDOWN_DELAY;
  729. else if (status == POPDOWN_QUEUED_SLOW)
  730. delay = POPDOWN_DELAY * 3;
  731. else
  732. delay = POPUP_DELAY;
  733. /* schedule a new timeout */
  734. window->autohide_timer = g_timeout_add_full (G_PRIORITY_LOW, delay,
  735. panel_window_autohide_timeout, window,
  736. panel_window_autohide_timeout_destroy);
  737. }
  738. }
  739. static gboolean
  740. panel_window_autohide_enter_notify_event (GtkWidget *widget,
  741. GdkEventCrossing *event,
  742. PanelWindow *window)
  743. {
  744. panel_return_val_if_fail (PANEL_IS_WINDOW (window), FALSE);
  745. /* queue a hide timeout */
  746. panel_window_autohide_queue (window, POPUP_QUEUED);
  747. return TRUE;
  748. }
  749. static gboolean
  750. panel_window_autohide_leave_notify_event (GtkWidget *widget,
  751. GdkEventCrossing *event,
  752. PanelWindow *window)
  753. {
  754. panel_return_val_if_fail (PANEL_IS_WINDOW (window), FALSE);
  755. /* stop a running autohide timeout */
  756. if (window->autohide_timer != 0)
  757. g_source_remove (window->autohide_timer);
  758. /* update the status */
  759. if (window->autohide_status == POPUP_QUEUED)
  760. window->autohide_status = HIDDEN;
  761. return TRUE;
  762. }
  763. static GtkWidget *
  764. panel_window_autohide_window (PanelWindow *window)
  765. {
  766. GtkWidget *popup;
  767. /* create window */
  768. popup = gtk_window_new (GTK_WINDOW_POPUP);
  769. gtk_window_set_gravity (GTK_WINDOW (popup), GDK_GRAVITY_STATIC);
  770. /* connect signals to monitor enter/leave events */
  771. g_signal_connect (G_OBJECT (popup), "enter-notify-event", G_CALLBACK (panel_window_autohide_enter_notify_event), window);
  772. g_signal_connect (G_OBJECT (popup), "leave-notify-event", G_CALLBACK (panel_window_autohide_leave_notify_event), window);
  773. /* put the window offscreen */
  774. gtk_window_move (GTK_WINDOW (popup), OFFSCREEN, OFFSCREEN);
  775. /* set window opacity */
  776. gtk_window_set_opacity (GTK_WINDOW (popup), window->leave_opacity);
  777. /* show the window */
  778. gtk_widget_show (popup);
  779. return popup;
  780. }
  781. static gboolean
  782. panel_window_enter_notify_event (GtkWidget *widget,
  783. GdkEventCrossing *event)
  784. {
  785. PanelWindow *window = PANEL_WINDOW (widget);
  786. /* ignore event when entered from an inferior */
  787. if (event->detail == GDK_NOTIFY_INFERIOR)
  788. return FALSE;
  789. /* set the opacity (when they differ) */
  790. if (window->leave_opacity != window->enter_opacity)
  791. gtk_window_set_opacity (GTK_WINDOW (window), window->enter_opacity);
  792. /* stop a running autohide timeout */
  793. if (window->autohide_timer != 0)
  794. g_source_remove (window->autohide_timer);
  795. /* update autohide status */
  796. if (window->autohide_status == POPDOWN_QUEUED)
  797. window->autohide_status = VISIBLE;
  798. return FALSE;
  799. }
  800. static gboolean
  801. panel_window_leave_notify_event (GtkWidget *widget,
  802. GdkEventCrossing *event)
  803. {
  804. PanelWindow *window = PANEL_WINDOW (widget);
  805. /* ignore event when left towards an inferior */
  806. if (event->detail == GDK_NOTIFY_INFERIOR)
  807. return FALSE;
  808. /* set the opacity (when they differ) */
  809. if (window->leave_opacity != window->enter_opacity)
  810. gtk_window_set_opacity (GTK_WINDOW (window), window->leave_opacity);
  811. /* stop a running autohide timeout */
  812. if (window->autohide_timer != 0)
  813. g_source_remove (window->autohide_timer);
  814. /* queue a new autohide time if needed */
  815. if (window->autohide_status > BLOCKED && window->snap_edge != PANEL_SNAP_EGDE_NONE)
  816. panel_window_autohide_queue (window, POPDOWN_QUEUED);
  817. return FALSE;
  818. }
  819. static void
  820. panel_window_grab_notify (GtkWidget *widget,
  821. gboolean was_grabbed)
  822. {
  823. PanelWindow *window = PANEL_WINDOW (widget);
  824. /* avoid hiding the panel when the window is grabbed. this
  825. * (for example) happens when the user drags in the pager plugin
  826. * see bug #4597 */
  827. if (was_grabbed)
  828. panel_window_thaw_autohide (window);
  829. else
  830. panel_window_freeze_autohide (window);
  831. }
  832. /**
  833. * panel_window_size_request:
  834. * @widget : the panel window.
  835. * @requisition : the size we're requesting and receiving on
  836. * allocation.
  837. *
  838. * In this function we request the panel size, this size must fit
  839. * on the screen and match all the settings. It's not nessecarily
  840. * that all the plugins fit (based on their requisition that is),
  841. * they have to respect the size we allocate, requesting is only
  842. * being kind to plugins (actually the itembar), and we're not ;).
  843. **/
  844. static void
  845. panel_window_size_request (GtkWidget *widget,
  846. GtkRequisition *requisition)
  847. {
  848. PanelWindow *window = PANEL_WINDOW (widget);
  849. GtkRequisition child_requisition;
  850. gint extra_width = 0, extra_height = 0;
  851. if (GTK_WIDGET_REALIZED (widget))
  852. {
  853. /* poke the itembar to request it's size */
  854. if (G_LIKELY (GTK_BIN (widget)->child))
  855. gtk_widget_size_request (GTK_BIN (widget)->child, &child_requisition);
  856. else
  857. child_requisition.width = child_requisition.height = 0;
  858. /* add the handle size */
  859. if (window->locked == FALSE)
  860. {
  861. if (window->horizontal)
  862. extra_width += HANDLE_SIZE_TOTAL;
  863. else
  864. extra_height += HANDLE_SIZE_TOTAL;
  865. }
  866. /* handle the borders */
  867. if (PANEL_HAS_FLAG (window->borders, PANEL_BORDER_LEFT))
  868. extra_width++;
  869. /* handle the borders */
  870. if (PANEL_HAS_FLAG (window->borders, PANEL_BORDER_RIGHT))
  871. extra_width++;
  872. /* handle the borders */
  873. if (PANEL_HAS_FLAG (window->borders, PANEL_BORDER_TOP))
  874. extra_height++;
  875. /* handle the borders */
  876. if (PANEL_HAS_FLAG (window->borders, PANEL_BORDER_BOTTOM))
  877. extra_height++;
  878. /* get the real allocated size */
  879. if (window->horizontal)
  880. {
  881. /* calculate the panel width (fits content, fits on the screen, and extands to user size) */
  882. requisition->width = CLAMP (child_requisition.width + extra_width,
  883. window->working_area.width * window->length,
  884. window->working_area.width);
  885. /* set height based on user setting */
  886. requisition->height = window->size + extra_height;
  887. }
  888. else
  889. {
  890. /* calculate the panel width (fits content, fits on the screen, and extands to user size) */
  891. requisition->height = CLAMP (child_requisition.height + extra_height,
  892. window->working_area.height * window->length,
  893. window->working_area.height);
  894. /* set width based on user setting */
  895. requisition->width = window->size + extra_width;
  896. }
  897. }
  898. }
  899. /**
  900. * panel_window_size_allocate:
  901. * @widget : the panel window.
  902. * @allocation : the allocation.
  903. *
  904. * Here we position the window on the monitor/screen. The width and
  905. * height of the allocation cannot be changed, it's determend in
  906. * panel_window_size_request, so if it's wrong: fix things there.
  907. *
  908. * Because the panel window is a GtkWindow, the allocation x and y
  909. * are 0, which is fine for the child, but not for screen, so we
  910. * calculate the new screen position move and resize we window (at
  911. * once to avoid strange visual effects).
  912. *
  913. * The child allocation is basiclly the same, only a small change
  914. * to keep the handles free, when the panel is locked.
  915. **/
  916. static void
  917. panel_window_size_allocate (GtkWidget *widget,
  918. GtkAllocation *allocation)
  919. {
  920. PanelWindow *window = PANEL_WINDOW (widget);
  921. GtkAllocation child_allocation;
  922. gint root_x, root_y;
  923. gint width = HIDDEN_PANEL_SIZE, height = HIDDEN_PANEL_SIZE;
  924. gint hidden_root_x, hidden_root_y;
  925. if (GTK_WIDGET_REALIZED (widget))
  926. {
  927. /* set the widget allocation */
  928. widget->allocation = *allocation;
  929. /* get coordinates for the panel window */
  930. panel_window_calculate_position (window, allocation->width, allocation->height, &root_x, &root_y);
  931. /* handle hidden windows */
  932. if (window->autohide_status != DISABLED
  933. && window->autohide_window != NULL
  934. && window->snap_edge != PANEL_SNAP_EGDE_NONE)
  935. {
  936. if (window->autohide_status == VISIBLE
  937. || window->autohide_status == POPDOWN_QUEUED
  938. || window->autohide_status == POPDOWN_QUEUED_SLOW
  939. || window->autohide_status == BLOCKED)
  940. {
  941. /* put the hidden window offscreen */
  942. gtk_window_move (GTK_WINDOW (window->autohide_window), OFFSCREEN, OFFSCREEN);
  943. }
  944. else
  945. {
  946. /* init width and height */
  947. width = height = HIDDEN_PANEL_SIZE;
  948. /* get hidden panel size */
  949. switch (window->snap_edge)
  950. {
  951. case PANEL_SNAP_EGDE_E:
  952. case PANEL_SNAP_EGDE_EC:
  953. case PANEL_SNAP_EGDE_W:
  954. case PANEL_SNAP_EGDE_WC:
  955. height = allocation->height;
  956. break;
  957. case PANEL_SNAP_EGDE_NC:
  958. case PANEL_SNAP_EGDE_SC:
  959. case PANEL_SNAP_EGDE_N:
  960. case PANEL_SNAP_EGDE_S:
  961. width = allocation->width;
  962. break;
  963. default:
  964. if (window->horizontal)
  965. width = allocation->width;
  966. else
  967. height = allocation->height;
  968. break;
  969. }
  970. /* get coordinates for the hidden window */
  971. panel_window_calculate_position (window, width, height, &hidden_root_x, &hidden_root_y);
  972. /* position the hidden window */
  973. gtk_window_move (GTK_WINDOW (window->autohide_window), hidden_root_x, hidden_root_y);
  974. gtk_window_resize (GTK_WINDOW (window->autohide_window), width, height);
  975. /* put the panel window offscreen */
  976. root_x = root_y = OFFSCREEN;
  977. }
  978. }
  979. /* move and resize the panel window */
  980. gdk_window_move_resize (widget->window, root_x, root_y, allocation->width, allocation->height);
  981. if (GTK_BIN (widget)->child)
  982. {
  983. /* set the child allocation */
  984. child_allocation = *allocation;
  985. /* extract the border sizes from the allocation */
  986. if (PANEL_HAS_FLAG (window->borders, PANEL_BORDER_LEFT))
  987. {
  988. child_allocation.x++;
  989. child_allocation.width--;
  990. }
  991. if (PANEL_HAS_FLAG (window->borders, PANEL_BORDER_TOP))
  992. {
  993. child_allocation.y++;
  994. child_allocation.height--;
  995. }
  996. if (PANEL_HAS_FLAG (window->borders, PANEL_BORDER_RIGHT))
  997. child_allocation.width--;
  998. if (PANEL_HAS_FLAG (window->borders, PANEL_BORDER_BOTTOM))
  999. child_allocation.height--;
  1000. /* keep free space for the handles if needed */
  1001. if (window->locked == FALSE)
  1002. {
  1003. if (window->horizontal)
  1004. {
  1005. child_allocation.width -= HANDLE_SIZE_TOTAL;
  1006. child_allocation.x += HANDLE_SIZE + HANDLE_SPACING;
  1007. }
  1008. else
  1009. {
  1010. child_allocation.height -= HANDLE_SIZE_TOTAL;
  1011. child_allocation.y += HANDLE_SIZE + HANDLE_SPACING;
  1012. }
  1013. }
  1014. /* keep things positive */
  1015. child_allocation.width = MAX (0, child_allocation.width);
  1016. child_allocation.height = MAX (0, child_allocation.height);
  1017. /* allocate the child */
  1018. gtk_widget_size_allocate (GTK_BIN (widget)->child, &child_allocation);
  1019. }
  1020. /* update struts if possible */
  1021. if (window->struts_possible != 0)
  1022. panel_window_struts_update (window, root_x, root_y, allocation->width, allocation->height);
  1023. }
  1024. /* update previous allocation */
  1025. window->prev_allocation = *allocation;
  1026. }
  1027. static void
  1028. panel_window_screen_changed (GtkWidget *widget,
  1029. GdkScreen *previous_screen)
  1030. {
  1031. GdkScreen *screen;
  1032. PanelWindow *window = PANEL_WINDOW (widget);
  1033. panel_return_if_fail (PANEL_IS_WINDOW (widget));
  1034. panel_return_if_fail (GDK_IS_SCREEN (previous_screen));
  1035. /* get the new screen */
  1036. screen = gtk_window_get_screen (GTK_WINDOW (widget));
  1037. if (screen != previous_screen)
  1038. {
  1039. /* disconnect old screen changed handles */
  1040. g_signal_handlers_disconnect_by_func (G_OBJECT (previous_screen), G_CALLBACK (panel_window_screen_changed), widget);
  1041. /* connect new screen update signals */
  1042. g_signal_connect_swapped (G_OBJECT (screen), "size-changed", G_CALLBACK (panel_window_screen_changed), widget);
  1043. #if GTK_CHECK_VERSION (2,14,0)
  1044. g_signal_connect_swapped (G_OBJECT (screen), "monitors-changed", G_CALLBACK (panel_window_screen_changed), widget);
  1045. #endif
  1046. }
  1047. /* update the panel working area */
  1048. panel_window_working_area (window, -1, -1, &window->working_area);
  1049. /* check if struts are needed on the next resize */
  1050. window->struts_possible = -1;
  1051. /* queue a resize */
  1052. gtk_widget_queue_resize (widget);
  1053. }
  1054. static void
  1055. panel_window_paint_handle (PanelWindow *window,
  1056. gboolean start,
  1057. GtkStateType state,
  1058. cairo_t *cr)
  1059. {
  1060. GtkWidget *widget = GTK_WIDGET (window);
  1061. GtkAllocation *alloc = &(widget->allocation);
  1062. gint x, y, width, height;
  1063. guint i, xx, yy;
  1064. GdkColor *color;
  1065. gdouble alpha = 1.00;
  1066. /* set the alpha (always show to handle for atleast 50%) */
  1067. if (window->active_timeout_id == 0 && window->is_composited)
  1068. alpha = 0.50 + window->background_alpha / 2.00;
  1069. /* set initial numbers */
  1070. x = alloc->x + 2;
  1071. y = alloc->y + 2;
  1072. if (window->horizontal)
  1073. {
  1074. width = HANDLE_SIZE / 3 * 3;
  1075. height = alloc->height / 2;
  1076. y += height / 2 - 1;
  1077. x += (HANDLE_SIZE - width);
  1078. /* draw handle on the right */
  1079. if (!start)
  1080. x += alloc->width - HANDLE_SIZE - 4;
  1081. }
  1082. else
  1083. {
  1084. height = HANDLE_SIZE / 3 * 3;
  1085. width = alloc->width / 2;
  1086. x += width / 2 - 1;
  1087. y += (HANDLE_SIZE - height);
  1088. /* draw handle on the bottom */
  1089. if (!start)
  1090. y += alloc->height - HANDLE_SIZE - 4;
  1091. }
  1092. /* draw handler */
  1093. for (i = 2; i > 0; i--)
  1094. {
  1095. /* get the color for the job */
  1096. if (i == 2)
  1097. color = &(widget->style->light[state]);
  1098. else
  1099. color = &(widget->style->dark[state]);
  1100. /* set source color */
  1101. xfce_panel_cairo_set_source_rgba (cr, color, alpha);
  1102. /* draw the dots */
  1103. for (xx = 0; xx < (guint) width; xx += 3)
  1104. for (yy = 0; yy < (guint) height; yy += 3)
  1105. cairo_rectangle (cr, x + xx, y + yy, i, i);
  1106. /* fill the rectangles */
  1107. cairo_fill (cr);
  1108. }
  1109. }
  1110. static void
  1111. panel_window_paint_borders (PanelWindow *window,
  1112. GtkStateType state,
  1113. cairo_t *cr)
  1114. {
  1115. GtkWidget *widget = GTK_WIDGET (window);
  1116. GtkAllocation *alloc = &(widget->allocation);
  1117. GdkColor *color;
  1118. gdouble alpha = 1.00;
  1119. const gdouble dashes[] = {4.00, 4.00};
  1120. GTimeVal timeval;
  1121. /* 1px line (1.5 results in a sharp 1px line) */
  1122. cairo_set_line_width (cr, 1.5);
  1123. if (G_UNLIKELY (window->active_timeout_id != 0))
  1124. g_get_current_time (&timeval);
  1125. else if (window->is_composited)
  1126. alpha = window->background_alpha;
  1127. /* possibly save some time */
  1128. if (PANEL_HAS_FLAG (window->borders, (PANEL_BORDER_BOTTOM | PANEL_BORDER_RIGHT)))
  1129. {
  1130. /* dark color */
  1131. if (G_UNLIKELY (window->active_timeout_id != 0))
  1132. color = &(widget->style->black);
  1133. else
  1134. color = &(widget->style->dark[state]);
  1135. xfce_panel_cairo_set_source_rgba (cr, color, alpha);
  1136. /* move the cursor the the bottom left */
  1137. cairo_move_to (cr, alloc->x, alloc->y + alloc->height);
  1138. /* bottom line */
  1139. if (PANEL_HAS_FLAG (window->borders, PANEL_BORDER_BOTTOM))
  1140. cairo_rel_line_to (cr, alloc->width, 0);
  1141. else
  1142. cairo_rel_move_to (cr, alloc->width, 0);
  1143. /* right line */
  1144. if (PANEL_HAS_FLAG (window->borders, PANEL_BORDER_RIGHT))
  1145. cairo_rel_line_to (cr, 0, -alloc->height);
  1146. else
  1147. cairo_rel_move_to (cr, 0, -alloc->height);
  1148. if (G_UNLIKELY (window->active_timeout_id != 0))
  1149. cairo_set_dash (cr, dashes, G_N_ELEMENTS (dashes),
  1150. timeval.tv_sec % 2 ? 0.00 : 4.00);
  1151. /* stroke this part */
  1152. cairo_stroke (cr);
  1153. }
  1154. /* possibly save some time */
  1155. if (PANEL_HAS_FLAG (window->borders, (PANEL_BORDER_TOP | PANEL_BORDER_LEFT)))
  1156. {
  1157. /* light color */
  1158. if (G_UNLIKELY (window->active_timeout_id != 0))
  1159. color = &(widget->style->black);
  1160. else
  1161. color = &(widget->style->light[state]);
  1162. xfce_panel_cairo_set_source_rgba (cr, color, alpha);
  1163. /* move the cursor the the bottom left */
  1164. cairo_move_to (cr, alloc->x, alloc->y + alloc->height);
  1165. /* left line */
  1166. if (PANEL_HAS_FLAG (window->borders, PANEL_BORDER_LEFT))
  1167. cairo_rel_line_to (cr, 0, -alloc->height);
  1168. else
  1169. cairo_rel_move_to (cr, 0, -alloc->height);
  1170. /* top line */
  1171. if (PANEL_HAS_FLAG (window->borders, PANEL_BORDER_TOP))
  1172. cairo_rel_line_to (cr, alloc->width, 0);
  1173. else
  1174. cairo_rel_move_to (cr, alloc->width, 0);
  1175. if (G_UNLIKELY (window->active_timeout_id != 0))
  1176. cairo_set_dash (cr, dashes, G_N_ELEMENTS (dashes),
  1177. timeval.tv_sec % 2 ? 0.00 : -4.00);
  1178. /* stroke the lines */
  1179. cairo_stroke (cr);
  1180. }
  1181. }
  1182. static void
  1183. panel_window_calculate_position (PanelWindow *window,
  1184. gint width,
  1185. gint height,
  1186. gint *x,
  1187. gint *y)
  1188. {
  1189. gint root_x, root_y;
  1190. GdkRectangle *area = &window->working_area;
  1191. /* get the panel window position */
  1192. panel_window_get_position (window, &root_x, &root_y);
  1193. /* x position of the window */
  1194. switch (window->snap_edge)
  1195. {
  1196. /* left */
  1197. case PANEL_SNAP_EGDE_W:
  1198. case PANEL_SNAP_EGDE_NW:
  1199. case PANEL_SNAP_EGDE_WC:
  1200. case PANEL_SNAP_EGDE_SW:
  1201. *x = area->x;
  1202. break;
  1203. /* right */
  1204. case PANEL_SNAP_EGDE_E:
  1205. case PANEL_SNAP_EGDE_NE:
  1206. case PANEL_SNAP_EGDE_EC:
  1207. case PANEL_SNAP_EGDE_SE:
  1208. *x = area->x + area->width - width;
  1209. break;
  1210. /* center */
  1211. case PANEL_SNAP_EGDE_NC:
  1212. case PANEL_SNAP_EGDE_SC:
  1213. *x = area->x + (area->width - width) / 2;
  1214. break;
  1215. /* other, recenter based on previous allocation */
  1216. default:
  1217. *x = root_x + (window->prev_allocation.width - width) / 2;
  1218. *x = CLAMP (*x, area->x, area->x + area->width - width);
  1219. break;
  1220. }
  1221. /* y position of the window */
  1222. switch (window->snap_edge)
  1223. {
  1224. /* north */
  1225. case PANEL_SNAP_EGDE_NE:
  1226. case PANEL_SNAP_EGDE_NW:
  1227. case PANEL_SNAP_EGDE_NC:
  1228. case PANEL_SNAP_EGDE_N:
  1229. *y = area->y;
  1230. break;
  1231. /* south */
  1232. case PANEL_SNAP_EGDE_SE:
  1233. case PANEL_SNAP_EGDE_SW:
  1234. case PANEL_SNAP_EGDE_SC:
  1235. case PANEL_SNAP_EGDE_S:
  1236. *y = area->y + area->height - height;
  1237. break;
  1238. /* center */
  1239. case PANEL_SNAP_EGDE_EC:
  1240. case PANEL_SNAP_EGDE_WC:
  1241. *y = area->y + (area->height - height) / 2;
  1242. break;
  1243. /* other, recenter based on previous allocation */
  1244. default:
  1245. *y = root_y + (window->prev_allocation.height - height) / 2;
  1246. *y = CLAMP (*y, area->y, area->y + area->height - height);
  1247. break;
  1248. }
  1249. }
  1250. static void
  1251. panel_window_working_area (PanelWindow *window,
  1252. gint root_x,
  1253. gint root_y,
  1254. GdkRectangle *dest)
  1255. {
  1256. GdkScreen *screen;
  1257. gint monitor_num;
  1258. gint n_monitors;
  1259. GdkRectangle geometry;
  1260. gint i;
  1261. panel_return_if_fail (PANEL_IS_WINDOW (window));
  1262. panel_return_if_fail (GDK_IS_WINDOW (GTK_WIDGET (window)->window));
  1263. /* get valid coordinates if not set */
  1264. if (root_x == -1 && root_y == -1)
  1265. gtk_window_get_position (GTK_WINDOW (window), &root_x, &root_y);
  1266. /* get panel screen */
  1267. screen = gtk_window_get_screen (GTK_WINDOW (window));
  1268. /* get the monitor number */
  1269. monitor_num = gdk_screen_get_monitor_at_point (screen, root_x, root_y);
  1270. /* get the root monitor geometry */
  1271. gdk_screen_get_monitor_geometry (screen, monitor_num, dest);
  1272. if (window->span_monitors)
  1273. {
  1274. /* get the number of monitors */
  1275. n_monitors = gdk_screen_get_n_monitors (screen);
  1276. /* only try to extend when there are more then 2 monitors */
  1277. if (G_LIKELY (n_monitors > 1))
  1278. {
  1279. for (i = 0; i < n_monitors; i++)
  1280. {
  1281. /* skip the origional monitor */
  1282. if (i == monitor_num)
  1283. continue;
  1284. /* get the monitor geometry */
  1285. gdk_screen_get_monitor_geometry (screen, i, &geometry);
  1286. g_message ("monitor %d, x=%d, y=%d, w=%d, h=%d", i, geometry.x, geometry.y, geometry.width, geometry.height);
  1287. /* try to extend the dest geometry from the root coordinate's point of view */
  1288. if (window->horizontal
  1289. && root_y >= geometry.y
  1290. && root_y <= geometry.y + geometry.height
  1291. && (dest->x + dest->width == geometry.x
  1292. || dest->x == geometry.x + geometry.width))
  1293. {
  1294. /* extend the maximum area horizontally */
  1295. dest->x = MIN (dest->x, geometry.x);
  1296. dest->width += geometry.width;
  1297. }
  1298. else if (window->horizontal == FALSE
  1299. && root_x >= geometry.x
  1300. && root_x <= geometry.x + geometry.width
  1301. && (dest->y + dest->height == geometry.y
  1302. || dest->y == geometry.y + geometry.height))
  1303. {
  1304. /* extend the maximum area vertically */
  1305. dest->y = MIN (dest->y, geometry.y);
  1306. dest->height += geometry.height;
  1307. }
  1308. }
  1309. }
  1310. }
  1311. }
  1312. static gboolean
  1313. panel_window_struts_are_possible (PanelWindow *window,
  1314. gint x,
  1315. gint y,
  1316. gint width,
  1317. gint height)
  1318. {
  1319. GdkScreen *screen;
  1320. gint n_monitors;
  1321. gint i;
  1322. GdkRectangle geometry;
  1323. panel_return_val_if_fail (PANEL_IS_WINDOW (window), FALSE);
  1324. /* never set struts when we don't snap or when autohide is enabled */
  1325. if (window->snap_edge == PANEL_SNAP_EGDE_NONE || window->autohide_status != DISABLED)
  1326. return FALSE;
  1327. /* always set struts on the following condition */
  1328. if ((window->horizontal && y == 0) || (!window->horizontal && x == 0))
  1329. return TRUE;
  1330. /* get panel screen */
  1331. screen = gtk_window_get_screen (GTK_WINDOW (window));
  1332. /* get the number of monitors */
  1333. n_monitors = gdk_screen_get_n_monitors (screen);
  1334. if (G_LIKELY (n_monitors == 1))
  1335. {
  1336. /* don't set the struts when we're not at a screen edge */
  1337. if ((window->horizontal && y + height != gdk_screen_get_height (screen))
  1338. || (!window->horizontal && x + width != gdk_screen_get_width (screen)))
  1339. return FALSE;
  1340. }
  1341. else
  1342. {
  1343. for (i = 0; i < n_monitors; i++)
  1344. {
  1345. /* get the monitor geometry */
  1346. gdk_screen_get_monitor_geometry (screen, i, &geometry);
  1347. if (window->horizontal
  1348. && x >= geometry.x
  1349. && x + width <= geometry.x + geometry.width
  1350. && y + height < geometry.y + geometry.height)
  1351. return FALSE;
  1352. if (window->horizontal == FALSE
  1353. && y >= geometry.y
  1354. && y + height <= geometry.y + geometry.height
  1355. && x + width < geometry.x + geometry.width)
  1356. return FALSE;
  1357. }
  1358. }
  1359. return TRUE;
  1360. }
  1361. static void
  1362. panel_window_struts_update (PanelWindow *window,
  1363. gint x,
  1364. gint y,
  1365. gint width,
  1366. gint height)
  1367. {
  1368. gulong struts[N_STRUTS] = { 0, };
  1369. GdkScreen *screen;
  1370. guint i;
  1371. gboolean update_struts = FALSE;
  1372. panel_return_if_fail (PANEL_IS_WINDOW (window));
  1373. panel_return_if_fail (GDK_IS_WINDOW (GTK_WIDGET (window)->window));
  1374. panel_return_if_fail (N_STRUTS == 12);
  1375. panel_return_if_fail (cardinal_atom != GDK_NONE);
  1376. panel_return_if_fail (net_wm_strut_atom != GDK_NONE);
  1377. panel_return_if_fail (net_wm_strut_partial_atom != GDK_NONE);
  1378. if (G_UNLIKELY (window->struts_possible == -1))
  1379. {
  1380. /* check whether struts are possible, skip to apply if not */
  1381. window->struts_possible = panel_window_struts_are_possible (window, x, y, width, height);
  1382. /* struts are not possible, reset them only this time */
  1383. if (window->struts_possible == 0)
  1384. goto reset_only;
  1385. }
  1386. /* get the panel window screen */
  1387. screen = gtk_window_get_screen (GTK_WINDOW (window));
  1388. if (window->horizontal)
  1389. {
  1390. if (snap_edge_is_top (window->snap_edge))
  1391. {
  1392. /* the window is snapped on the top screen edge */
  1393. struts[STRUT_TOP] = y + height;
  1394. struts[STRUT_TOP_START_X] = x;
  1395. struts[STRUT_TOP_END_X] = x + width;
  1396. }
  1397. else if (snap_edge_is_bottom (window->snap_edge))
  1398. {
  1399. /* the window is snapped on the bottom screen edge */
  1400. struts[STRUT_BOTTOM] = gdk_screen_get_height (screen) - y;
  1401. struts[STRUT_BOTTOM_START_X] = x;
  1402. struts[STRUT_BOTTOM_END_X] = x + width;
  1403. }
  1404. }
  1405. else /* vertical */
  1406. {
  1407. if (snap_edge_is_left (window->snap_edge))
  1408. {
  1409. /* the window is snapped on the left screen edge */
  1410. struts[STRUT_LEFT] = x + width;
  1411. struts[STRUT_LEFT_START_Y] = y;
  1412. struts[STRUT_LEFT_END_Y] = y + height;
  1413. }
  1414. else if (snap_edge_is_right (window->snap_edge))
  1415. {
  1416. /* the window is snapped on the right screen edge */
  1417. struts[STRUT_RIGHT] = gdk_screen_get_width (screen) - x;
  1418. struts[STRUT_RIGHT_START_Y] = y;
  1419. struts[STRUT_RIGHT_END_Y] = y + height;
  1420. }
  1421. }
  1422. reset_only:
  1423. for (i = 0; i < N_STRUTS; i++)
  1424. {
  1425. /* check if we need to update */
  1426. if (struts[i] != window->struts[i])
  1427. update_struts = TRUE;
  1428. /* store new strut */
  1429. window->struts[i] = struts[i];
  1430. }
  1431. if (update_struts)
  1432. {
  1433. /* don't crash on x errors */
  1434. gdk_error_trap_push ();
  1435. /* set the wm strut partial */
  1436. gdk_property_change (GTK_WIDGET (window)->window, net_wm_strut_partial_atom,
  1437. cardinal_atom, 32, GDK_PROP_MODE_REPLACE, (guchar *) &struts, 12);
  1438. /* set the wm strut (old window managers) */
  1439. /* gdk_property_change (GTK_WIDGET (window)->window, net_wm_strut_atom,
  1440. * cardinal_atom, 32, GDK_PROP_MODE_REPLACE, (guchar *) &struts, 4);
  1441. */
  1442. /* release the trap push */
  1443. gdk_error_trap_pop ();
  1444. #if 0
  1445. gint n = -1;
  1446. const gchar *names1[] = { "left", "right", "top", "bottom" };
  1447. const gchar *names2[] = { "y", "y", "x", "x" };
  1448. if (struts[STRUT_LEFT] != 0)
  1449. n = STRUT_LEFT;
  1450. else if (struts[STRUT_RIGHT] != 0)
  1451. n = STRUT_RIGHT;
  1452. else if (struts[STRUT_TOP] != 0)
  1453. n = STRUT_TOP;
  1454. else if (struts[STRUT_BOTTOM] != 0)
  1455. n = STRUT_BOTTOM;
  1456. if (n == -1)
  1457. g_print ("Struts: All set to zero\n");
  1458. else
  1459. g_print ("Struts: %s = %ld, start_%s = %ld, end_%s = %ld\n", names1[n],
  1460. struts[n], names2[n], struts[4 + n * 2], names2[n], struts[5 + n * 2]);
  1461. #endif
  1462. }
  1463. }
  1464. static void
  1465. panel_window_set_colormap (PanelWindow *window)
  1466. {
  1467. GdkColormap *colormap = NULL;
  1468. GdkScreen *screen;
  1469. gboolean restore;
  1470. GtkWidget *widget = GTK_WIDGET (window);
  1471. gint root_x, root_y;
  1472. panel_return_if_fail (PANEL_IS_WINDOW (window));
  1473. /* whether the widget was previously visible */
  1474. restore = GTK_WIDGET_REALIZED (widget);
  1475. /* unrealize the window if needed */
  1476. if (restore)
  1477. {
  1478. /* store the window position */
  1479. gtk_window_get_position (GTK_WINDOW (window), &root_x, &root_y);
  1480. /* reset the struts */
  1481. if (window->struts_possible == 1)
  1482. panel_window_struts_update (window, 0, 0, 0, 0);
  1483. /* hide the widget */
  1484. gtk_widget_hide (widget);
  1485. gtk_widget_unrealize (widget);
  1486. }
  1487. /* set bool */
  1488. window->is_composited = gtk_widget_is_composited (widget);
  1489. /* get the screen */
  1490. screen = gtk_window_get_screen (GTK_WINDOW (window));
  1491. /* try to get the rgba colormap */
  1492. if (window->is_composited)
  1493. colormap = gdk_screen_get_rgba_colormap (screen);
  1494. /* get the default colormap */
  1495. if (colormap == NULL)
  1496. {
  1497. colormap = gdk_screen_get_rgb_colormap (screen);
  1498. window->is_composited = FALSE;
  1499. }
  1500. /* set the colormap */
  1501. if (colormap)
  1502. gtk_widget_set_colormap (widget, colormap);
  1503. /* restore the window */
  1504. if (restore)
  1505. {
  1506. /* restore the position */
  1507. gtk_window_move (GTK_WINDOW (window), root_x, root_y);
  1508. /* show the widget again */
  1509. gtk_widget_realize (widget);
  1510. gtk_widget_show (widget);
  1511. /* set the struts again */
  1512. if (window->struts_possible == 1)
  1513. panel_window_struts_update (window, root_x, root_y, widget->allocation.width, widget->allocation.height);
  1514. }
  1515. }
  1516. static void
  1517. panel_window_get_position (PanelWindow *window,
  1518. gint *root_x,
  1519. gint *root_y)
  1520. {
  1521. panel_return_if_fail (PANEL_IS_WINDOW (window));
  1522. /* get the window position of the visible window */
  1523. if (G_UNLIKELY (window->autohide_window
  1524. && (window->autohide_status == HIDDEN || window->autohide_status == POPUP_QUEUED)))
  1525. gtk_window_get_position (GTK_WINDOW (window->autohide_window), root_x, root_y);
  1526. else
  1527. gtk_window_get_position (GTK_WINDOW (window), root_x, root_y);
  1528. }
  1529. static void
  1530. panel_window_set_borders (PanelWindow *window)
  1531. {
  1532. PanelWindowBorders borders = 0;
  1533. panel_return_if_fail (PANEL_IS_WINDOW (window));
  1534. if (window->horizontal)
  1535. {
  1536. /* only attempt to show the side borders if we're not filling the area */
  1537. if (window->length < 1.00)
  1538. {
  1539. /* show the left border if we don't snap to the left */
  1540. if (snap_edge_is_left (window->snap_edge) == FALSE)
  1541. PANEL_SET_FLAG (borders, PANEL_BORDER_LEFT);
  1542. /* show the right border if we don't snap to the right */
  1543. if (snap_edge_is_right (window->snap_edge) == FALSE)
  1544. PANEL_SET_FLAG (borders, PANEL_BORDER_RIGHT);
  1545. }
  1546. /* show the top border if not snapped to the top */
  1547. if (snap_edge_is_top (window->snap_edge) == FALSE)
  1548. PANEL_SET_FLAG (borders, PANEL_BORDER_TOP);
  1549. /* show the bottom border if not snapped to the bottom */
  1550. if (snap_edge_is_bottom (window->snap_edge) == FALSE)
  1551. PANEL_SET_FLAG (borders, PANEL_BORDER_BOTTOM);
  1552. }
  1553. else
  1554. {
  1555. /* only attempt to show the top borders if we're not filling the area */
  1556. if (window->length < 1.00)
  1557. {
  1558. /* show the top border if we don't snap to the top */
  1559. if (snap_edge_is_top (window->snap_edge) == FALSE)
  1560. PANEL_SET_FLAG (borders, PANEL_BORDER_TOP);
  1561. /* show the bottom border if we don't snap to the bottom */
  1562. if (snap_edge_is_bottom (window->snap_edge) == FALSE)
  1563. PANEL_SET_FLAG (borders, PANEL_BORDER_BOTTOM);
  1564. }
  1565. /* show the left border if not snapped to the left */
  1566. if (snap_edge_is_left (window->snap_edge) == FALSE)
  1567. PANEL_SET_FLAG (borders, PANEL_BORDER_LEFT);
  1568. /* show the right border if not snapped to the right */
  1569. if (snap_edge_is_right (window->snap_edge) == FALSE)
  1570. PANEL_SET_FLAG (borders, PANEL_BORDER_RIGHT);
  1571. }
  1572. /* set the new value and queue a resize if needed */
  1573. if (window->borders != borders)
  1574. {
  1575. /* set the new value */
  1576. window->borders = borders;
  1577. /* queue a resize */
  1578. gtk_widget_queue_resize (GTK_WIDGET (window));
  1579. }
  1580. }
  1581. static void
  1582. panel_window_set_autohide (PanelWindow *window,
  1583. gboolean autohide)
  1584. {
  1585. AutohideStatus status;
  1586. panel_return_if_fail (PANEL_IS_WINDOW (window));
  1587. if (G_LIKELY ((window->autohide_status != DISABLED) != autohide))
  1588. {
  1589. /* determ whether struts are possible on the next resize */
  1590. window->struts_possible = -1;
  1591. if (autohide)
  1592. {
  1593. /* create popup window if needed */
  1594. if (window->autohide_window == NULL)
  1595. window->autohide_window = panel_window_autohide_window (window);
  1596. /* get the correct status */
  1597. status = window->autohide_block == 0 ? POPDOWN_QUEUED_SLOW : BLOCKED;
  1598. /* queue a popdown */
  1599. panel_window_autohide_queue (window, status);
  1600. }
  1601. else
  1602. {
  1603. /* disable autohiding */
  1604. panel_window_autohide_queue (window, DISABLED);
  1605. /* destroy the autohide window */
  1606. if (window->autohide_window)
  1607. {
  1608. gtk_widget_destroy (window->autohide_window);
  1609. window->autohide_window = NULL;
  1610. }
  1611. }
  1612. }
  1613. }
  1614. static void
  1615. panel_window_menu_quit (gpointer boolean)
  1616. {
  1617. /* restart or quit */
  1618. dbus_quit_with_restart = !!(GPOINTER_TO_UINT (boolean));
  1619. /* quit main loop */
  1620. gtk_main_quit ();
  1621. }
  1622. static void
  1623. panel_window_menu_deactivate (GtkMenu *menu,
  1624. PanelWindow *window)
  1625. {
  1626. panel_return_if_fail (GTK_IS_MENU (menu));
  1627. panel_return_if_fail (PANEL_IS_WINDOW (window));
  1628. /* thaw autohide block */
  1629. panel_window_thaw_autohide (window);
  1630. /* destroy the menu */
  1631. g_object_unref (G_OBJECT (menu));
  1632. }
  1633. static void
  1634. panel_window_menu_popup (PanelWindow *window)
  1635. {
  1636. GtkWidget *menu;
  1637. GtkWidget *item;
  1638. GtkWidget *image;
  1639. panel_return_if_fail (PANEL_IS_WINDOW (window));
  1640. /* freeze autohide */
  1641. panel_window_freeze_autohide (window);
  1642. /* create menu */
  1643. menu = gtk_menu_new ();
  1644. /* sink the menu and add unref on deactivate */
  1645. g_object_ref_sink (G_OBJECT (menu));
  1646. g_signal_connect (G_OBJECT (menu), "deactivate", G_CALLBACK (panel_window_menu_deactivate), window);
  1647. /* label */
  1648. item = gtk_image_menu_item_new_with_label (_("Xfce Panel"));
  1649. gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
  1650. gtk_widget_set_sensitive (item, FALSE);
  1651. gtk_widget_show (item);
  1652. /* separator */
  1653. item = gtk_separator_menu_item_new ();
  1654. gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
  1655. gtk_widget_show (item);
  1656. /* add new items */
  1657. item = gtk_image_menu_item_new_with_mnemonic (_("Add _New Items..."));
  1658. g_signal_connect_swapped (G_OBJECT (item), "activate", G_CALLBACK (panel_item_dialog_show), window);
  1659. gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
  1660. gtk_widget_show (item);
  1661. image = gtk_image_new_from_stock (GTK_STOCK_ADD, GTK_ICON_SIZE_MENU);
  1662. gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
  1663. gtk_widget_show (image);
  1664. /* customize panel */
  1665. item = gtk_image_menu_item_new_with_mnemonic (_("Panel Pr_eferences..."));
  1666. g_signal_connect_swapped (G_OBJECT (item), "activate", G_CALLBACK (panel_preferences_dialog_show), window);
  1667. gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
  1668. gtk_widget_show (item);
  1669. image = gtk_image_new_from_stock (GTK_STOCK_PREFERENCES, GTK_ICON_SIZE_MENU);
  1670. gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
  1671. gtk_widget_show (image);
  1672. /* separator */
  1673. item = gtk_separator_menu_item_new ();
  1674. gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
  1675. gtk_widget_show (item);
  1676. /* quit item */
  1677. item = gtk_image_menu_item_new_from_stock (GTK_STOCK_QUIT, NULL);
  1678. g_signal_connect_swapped (G_OBJECT (item), "activate", G_CALLBACK (panel_window_menu_quit), GUINT_TO_POINTER (0));
  1679. gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
  1680. gtk_widget_show (item);
  1681. /* restart item */
  1682. item = gtk_image_menu_item_new_with_mnemonic (_("_Restart"));
  1683. g_signal_connect_swapped (G_OBJECT (item), "activate", G_CALLBACK (panel_window_menu_quit), GUINT_TO_POINTER (1));
  1684. gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
  1685. gtk_widget_show (item);
  1686. image = gtk_image_new_from_stock (GTK_STOCK_REFRESH, GTK_ICON_SIZE_MENU);
  1687. gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
  1688. gtk_widget_show (image);
  1689. /* separator */
  1690. item = gtk_separator_menu_item_new ();
  1691. gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
  1692. gtk_widget_show (item);
  1693. /* about item */
  1694. item = gtk_image_menu_item_new_from_stock (GTK_STOCK_ABOUT, NULL);
  1695. g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (panel_dialogs_show_about), NULL);
  1696. gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
  1697. gtk_widget_show (item);
  1698. /* popup the menu */
  1699. gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL,
  1700. 0, gtk_get_current_event_time ());
  1701. }
  1702. static void
  1703. panel_window_set_plugin_background_alpha (GtkWidget *widget,
  1704. gpointer user_data)
  1705. {
  1706. panel_return_if_fail (XFCE_IS_PANEL_PLUGIN_PROVIDER (widget));
  1707. /* we only have to send the alpha to external plugins */
  1708. if (PANEL_IS_PLUGIN_EXTERNAL (widget))
  1709. panel_plugin_external_set_background_alpha (PANEL_PLUGIN_EXTERNAL (widget),
  1710. GPOINTER_TO_UINT (user_data));
  1711. }
  1712. static void
  1713. panel_window_set_plugin_size (GtkWidget *widget,
  1714. gpointer user_data)
  1715. {
  1716. panel_return_if_fail (XFCE_IS_PANEL_PLUGIN_PROVIDER (widget));
  1717. /* set the new plugin size */
  1718. xfce_panel_plugin_provider_set_size (XFCE_PANEL_PLUGIN_PROVIDER (widget),
  1719. GPOINTER_TO_INT (user_data));
  1720. }
  1721. static void
  1722. panel_window_set_plugin_orientation (GtkWidget *widget,
  1723. gpointer user_data)
  1724. {
  1725. panel_return_if_fail (XFCE_IS_PANEL_PLUGIN_PROVIDER (widget));
  1726. /* set the new plugin orientation */
  1727. xfce_panel_plugin_provider_set_orientation (XFCE_PANEL_PLUGIN_PROVIDER (widget),
  1728. GPOINTER_TO_INT (user_data));
  1729. }
  1730. gboolean
  1731. panel_window_is_composited (PanelWindow *window)
  1732. {
  1733. panel_return_val_if_fail (PANEL_IS_WINDOW (window), FALSE);
  1734. return window->is_composited;
  1735. }
  1736. void
  1737. panel_window_set_active_panel (PanelWindow *window,
  1738. gboolean active)
  1739. {
  1740. panel_return_if_fail (PANEL_IS_WINDOW (window));
  1741. if (G_UNLIKELY ((window->active_timeout_id != 0) != active))
  1742. {
  1743. /* set new value */
  1744. if (active)
  1745. {
  1746. window->active_timeout_id = g_timeout_add_seconds (1,
  1747. (GSourceFunc) gtk_widget_queue_draw, window);
  1748. }
  1749. else
  1750. {
  1751. g_source_remove (window->active_timeout_id);
  1752. window->active_timeout_id = 0;
  1753. }
  1754. /* queue a redraw */
  1755. gtk_widget_queue_draw (GTK_WIDGET (window));
  1756. }
  1757. }
  1758. void
  1759. panel_window_freeze_autohide (PanelWindow *window)
  1760. {
  1761. panel_return_if_fail (PANEL_IS_WINDOW (window));
  1762. panel_return_if_fail (window->autohide_block >= 0);
  1763. /* increase autohide block counter */
  1764. window->autohide_block++;
  1765. /* block autohide */
  1766. if (window->autohide_block == 1 && window->autohide_status != DISABLED)
  1767. panel_window_autohide_queue (window, BLOCKED);
  1768. }
  1769. void
  1770. panel_window_thaw_autohide (PanelWindow *window)
  1771. {
  1772. panel_return_if_fail (PANEL_IS_WINDOW (window));
  1773. panel_return_if_fail (window->autohide_block > 0);
  1774. /* decrease autohide block counter */
  1775. window->autohide_block--;
  1776. /* queue an autohide when needed */
  1777. if (window->autohide_block == 0 && window->autohide_status != DISABLED)
  1778. panel_window_autohide_queue (window, POPDOWN_QUEUED);
  1779. }