+ /* ignore enter events caused by this */
+ ignore_start = event_start_ignore_all_enters();
+
+ screen_set_num_desktops(screen_num_desktops+1);
+
+ /* move all the clients over */
+ if (current) {
+ GList *it;
+
+ for (it = client_list; it; it = g_list_next(it)) {
+ ObClient *c = it->data;
+ if (c->desktop != DESKTOP_ALL && c->desktop >= screen_desktop &&
+ /* don't move direct children, they'll be moved with their
+ parent - which will have to be on the same desktop */
+ !client_direct_parent(c))
+ {
+ ob_debug("moving window %s", c->title);
+ client_set_desktop(c, c->desktop+1, FALSE, TRUE);
+ }
+ }
+ }
+
+ event_end_ignore_all_enters(ignore_start);
+}
+
+void screen_remove_desktop(gboolean current)
+{
+ guint rmdesktop, movedesktop;
+ GList *it, *stacking_copy;
+ gulong ignore_start;
+
+ if (screen_num_desktops <= 1) return;
+
+ /* ignore enter events caused by this */
+ ignore_start = event_start_ignore_all_enters();
+
+ /* what desktop are we removing and moving to? */
+ if (current)
+ rmdesktop = screen_desktop;
+ else
+ rmdesktop = screen_num_desktops - 1;
+ if (rmdesktop < screen_num_desktops - 1)
+ movedesktop = rmdesktop + 1;
+ else
+ movedesktop = rmdesktop;
+
+ /* make a copy of the list cuz we're changing it */
+ stacking_copy = g_list_copy(stacking_list);
+ for (it = g_list_last(stacking_copy); it; it = g_list_previous(it)) {
+ if (WINDOW_IS_CLIENT(it->data)) {
+ ObClient *c = it->data;
+ guint d = c->desktop;
+ if (d != DESKTOP_ALL && d >= movedesktop &&
+ /* don't move direct children, they'll be moved with their
+ parent - which will have to be on the same desktop */
+ !client_direct_parent(c))
+ {
+ ob_debug("moving window %s", c->title);
+ client_set_desktop(c, c->desktop - 1, TRUE, TRUE);
+ }
+ /* raise all the windows that are on the current desktop which
+ is being merged */
+ if ((screen_desktop == rmdesktop - 1 ||
+ screen_desktop == rmdesktop) &&
+ (d == DESKTOP_ALL || d == screen_desktop))
+ {
+ stacking_raise(CLIENT_AS_WINDOW(c));
+ ob_debug("raising window %s", c->title);
+ }
+ }
+ }
+ g_list_free(stacking_copy);
+
+ /* fallback focus like we're changing desktops */
+ if (screen_desktop < screen_num_desktops - 1) {
+ screen_fallback_focus();
+ ob_debug("fake desktop change");
+ }
+
+ screen_set_num_desktops(screen_num_desktops-1);
+
+ event_end_ignore_all_enters(ignore_start);
+}
+
+static void get_row_col(guint d, guint *r, guint *c)
+{
+ switch (screen_desktop_layout.orientation) {
+ case OB_ORIENTATION_HORZ:
+ switch (screen_desktop_layout.start_corner) {
+ case OB_CORNER_TOPLEFT:
+ *r = d / screen_desktop_layout.columns;
+ *c = d % screen_desktop_layout.columns;
+ break;
+ case OB_CORNER_BOTTOMLEFT:
+ *r = screen_desktop_layout.rows - 1 -
+ d / screen_desktop_layout.columns;
+ *c = d % screen_desktop_layout.columns;
+ break;
+ case OB_CORNER_TOPRIGHT:
+ *r = d / screen_desktop_layout.columns;
+ *c = screen_desktop_layout.columns - 1 -
+ d % screen_desktop_layout.columns;
+ break;
+ case OB_CORNER_BOTTOMRIGHT:
+ *r = screen_desktop_layout.rows - 1 -
+ d / screen_desktop_layout.columns;
+ *c = screen_desktop_layout.columns - 1 -
+ d % screen_desktop_layout.columns;
+ break;
+ }
+ break;
+ case OB_ORIENTATION_VERT:
+ switch (screen_desktop_layout.start_corner) {
+ case OB_CORNER_TOPLEFT:
+ *r = d % screen_desktop_layout.rows;
+ *c = d / screen_desktop_layout.rows;
+ break;
+ case OB_CORNER_BOTTOMLEFT:
+ *r = screen_desktop_layout.rows - 1 -
+ d % screen_desktop_layout.rows;
+ *c = d / screen_desktop_layout.rows;
+ break;
+ case OB_CORNER_TOPRIGHT:
+ *r = d % screen_desktop_layout.rows;
+ *c = screen_desktop_layout.columns - 1 -
+ d / screen_desktop_layout.rows;
+ break;
+ case OB_CORNER_BOTTOMRIGHT:
+ *r = screen_desktop_layout.rows - 1 -
+ d % screen_desktop_layout.rows;
+ *c = screen_desktop_layout.columns - 1 -
+ d / screen_desktop_layout.rows;
+ break;
+ }
+ break;
+ }
+}
+
+static guint translate_row_col(guint r, guint c)
+{
+ switch (screen_desktop_layout.orientation) {
+ case OB_ORIENTATION_HORZ:
+ switch (screen_desktop_layout.start_corner) {
+ case OB_CORNER_TOPLEFT:
+ return r % screen_desktop_layout.rows *
+ screen_desktop_layout.columns +
+ c % screen_desktop_layout.columns;
+ case OB_CORNER_BOTTOMLEFT:
+ return (screen_desktop_layout.rows - 1 -
+ r % screen_desktop_layout.rows) *
+ screen_desktop_layout.columns +
+ c % screen_desktop_layout.columns;
+ case OB_CORNER_TOPRIGHT:
+ return r % screen_desktop_layout.rows *
+ screen_desktop_layout.columns +
+ (screen_desktop_layout.columns - 1 -
+ c % screen_desktop_layout.columns);
+ case OB_CORNER_BOTTOMRIGHT:
+ return (screen_desktop_layout.rows - 1 -
+ r % screen_desktop_layout.rows) *
+ screen_desktop_layout.columns +
+ (screen_desktop_layout.columns - 1 -
+ c % screen_desktop_layout.columns);
+ }
+ case OB_ORIENTATION_VERT:
+ switch (screen_desktop_layout.start_corner) {
+ case OB_CORNER_TOPLEFT:
+ return c % screen_desktop_layout.columns *
+ screen_desktop_layout.rows +
+ r % screen_desktop_layout.rows;
+ case OB_CORNER_BOTTOMLEFT:
+ return c % screen_desktop_layout.columns *
+ screen_desktop_layout.rows +
+ (screen_desktop_layout.rows - 1 -
+ r % screen_desktop_layout.rows);
+ case OB_CORNER_TOPRIGHT:
+ return (screen_desktop_layout.columns - 1 -
+ c % screen_desktop_layout.columns) *
+ screen_desktop_layout.rows +
+ r % screen_desktop_layout.rows;
+ case OB_CORNER_BOTTOMRIGHT:
+ return (screen_desktop_layout.columns - 1 -
+ c % screen_desktop_layout.columns) *
+ screen_desktop_layout.rows +
+ (screen_desktop_layout.rows - 1 -
+ r % screen_desktop_layout.rows);
+ }
+ }
+ g_assert_not_reached();
+ return 0;
+}
+
+static gboolean hide_desktop_popup_func(gpointer data)
+{
+ pager_popup_hide(desktop_popup);
+ return FALSE; /* don't repeat */
+}
+
+void screen_show_desktop_popup(guint d, gboolean perm)
+{
+ const Rect *a;
+
+ /* 0 means don't show the popup */
+ if (!config_desktop_popup_time) return;
+
+ a = screen_physical_area_primary(FALSE);
+ pager_popup_position(desktop_popup, CenterGravity,
+ a->x + a->width / 2, a->y + a->height / 2);
+ pager_popup_icon_size_multiplier(desktop_popup,
+ (screen_desktop_layout.columns /
+ screen_desktop_layout.rows) / 2,
+ (screen_desktop_layout.rows/
+ screen_desktop_layout.columns) / 2);
+ pager_popup_max_width(desktop_popup,
+ MAX(a->width/3, POPUP_WIDTH));
+ pager_popup_show(desktop_popup, screen_desktop_names[d], d);
+
+ obt_main_loop_timeout_remove(ob_main_loop, hide_desktop_popup_func);
+ if (!perm && !desktop_popup_perm)
+ /* only hide if its not already being show permanently */
+ obt_main_loop_timeout_add(ob_main_loop,
+ config_desktop_popup_time * 1000,
+ hide_desktop_popup_func, desktop_popup,
+ g_direct_equal, NULL);
+ if (perm)
+ desktop_popup_perm = TRUE;
+}
+
+void screen_hide_desktop_popup(void)
+{
+ obt_main_loop_timeout_remove_data(ob_main_loop, hide_desktop_popup_func,
+ desktop_popup, FALSE);
+ pager_popup_hide(desktop_popup);
+ desktop_popup_perm = FALSE;
+}
+
+guint screen_find_desktop(guint from, ObDirection dir,
+ gboolean wrap, gboolean linear)
+{
+ guint r, c;
+ guint d;
+
+ d = from;
+ get_row_col(d, &r, &c);
+ if (linear) {
+ switch (dir) {
+ case OB_DIRECTION_EAST:
+ if (d < screen_num_desktops - 1)
+ ++d;
+ else if (wrap)
+ d = 0;
+ else
+ return from;
+ break;
+ case OB_DIRECTION_WEST:
+ if (d > 0)
+ --d;
+ else if (wrap)
+ d = screen_num_desktops - 1;
+ else
+ return from;
+ break;
+ default:
+ g_assert_not_reached();
+ return from;
+ }
+ } else {
+ switch (dir) {
+ case OB_DIRECTION_EAST:
+ ++c;
+ if (c >= screen_desktop_layout.columns) {
+ if (wrap)
+ c = 0;
+ else
+ return from;
+ }
+ d = translate_row_col(r, c);
+ if (d >= screen_num_desktops) {
+ if (wrap)
+ ++c;
+ else
+ return from;
+ }
+ break;
+ case OB_DIRECTION_WEST:
+ --c;
+ if (c >= screen_desktop_layout.columns) {
+ if (wrap)
+ c = screen_desktop_layout.columns - 1;
+ else
+ return from;
+ }
+ d = translate_row_col(r, c);
+ if (d >= screen_num_desktops) {
+ if (wrap)
+ --c;
+ else
+ return from;
+ }
+ break;
+ case OB_DIRECTION_SOUTH:
+ ++r;
+ if (r >= screen_desktop_layout.rows) {
+ if (wrap)
+ r = 0;
+ else
+ return from;
+ }
+ d = translate_row_col(r, c);
+ if (d >= screen_num_desktops) {
+ if (wrap)
+ ++r;
+ else
+ return from;
+ }
+ break;
+ case OB_DIRECTION_NORTH:
+ --r;
+ if (r >= screen_desktop_layout.rows) {
+ if (wrap)
+ r = screen_desktop_layout.rows - 1;
+ else
+ return from;
+ }
+ d = translate_row_col(r, c);
+ if (d >= screen_num_desktops) {
+ if (wrap)
+ --r;
+ else
+ return from;
+ }
+ break;
+ default:
+ g_assert_not_reached();
+ return from;
+ }
+
+ d = translate_row_col(r, c);
+ }
+ return d;
+}
+
+static gboolean screen_validate_layout(ObDesktopLayout *l)
+{
+ if (l->columns == 0 && l->rows == 0) /* both 0's is bad data.. */
+ return FALSE;
+
+ /* fill in a zero rows/columns */
+ if (l->columns == 0) {
+ l->columns = screen_num_desktops / l->rows;
+ if (l->rows * l->columns < screen_num_desktops)
+ l->columns++;
+ if (l->rows * l->columns >= screen_num_desktops + l->columns)
+ l->rows--;
+ } else if (l->rows == 0) {
+ l->rows = screen_num_desktops / l->columns;
+ if (l->columns * l->rows < screen_num_desktops)
+ l->rows++;
+ if (l->columns * l->rows >= screen_num_desktops + l->rows)
+ l->columns--;
+ }
+
+ /* bounds checking */
+ if (l->orientation == OB_ORIENTATION_HORZ) {
+ l->columns = MIN(screen_num_desktops, l->columns);
+ l->rows = MIN(l->rows,
+ (screen_num_desktops + l->columns - 1) / l->columns);
+ l->columns = screen_num_desktops / l->rows +
+ !!(screen_num_desktops % l->rows);
+ } else {
+ l->rows = MIN(screen_num_desktops, l->rows);
+ l->columns = MIN(l->columns,
+ (screen_num_desktops + l->rows - 1) / l->rows);
+ l->rows = screen_num_desktops / l->columns +
+ !!(screen_num_desktops % l->columns);
+ }
+ return TRUE;
+}
+
+void screen_update_layout(void)
+
+{
+ ObDesktopLayout l;
+ guint32 *data;
+ guint num;
+
+ screen_desktop_layout.orientation = OB_ORIENTATION_HORZ;
+ screen_desktop_layout.start_corner = OB_CORNER_TOPLEFT;