#include "startupnotify.h"
#include "moveresize.h"
#include "config.h"
+#include "mainloop.h"
#include "screen.h"
#include "client.h"
#include "session.h"
#define ROOT_EVENTMASK (StructureNotifyMask | PropertyChangeMask | \
EnterWindowMask | LeaveWindowMask | \
SubstructureRedirectMask | FocusChangeMask | \
- ButtonPressMask | ButtonReleaseMask | ButtonMotionMask)
+ ButtonPressMask | ButtonReleaseMask)
static gboolean screen_validate_layout(ObDesktopLayout *l);
static gboolean replace_wm();
static void screen_tell_ksplash();
+static void screen_fallback_focus();
guint screen_num_desktops;
guint screen_num_monitors;
static GSList *struts_right = NULL;
static GSList *struts_bottom = NULL;
-static ObPagerPopup *desktop_cycle_popup;
+static ObPagerPopup *desktop_popup;
static gboolean replace_wm()
{
current_wm_sn_owner = None;
}
- {
- /* Generate a timestamp */
- XEvent event;
-
- XSelectInput(ob_display, screen_support_win, PropertyChangeMask);
-
- XChangeProperty(ob_display, screen_support_win,
- prop_atoms.wm_class, prop_atoms.string,
- 8, PropModeAppend, NULL, 0);
- XWindowEvent(ob_display, screen_support_win,
- PropertyChangeMask, &event);
-
- XSelectInput(ob_display, screen_support_win, NoEventMask);
-
- timestamp = event.xproperty.time;
- }
+ timestamp = event_get_server_time();
XSetSelectionOwner(ob_display, wm_sn_atom, screen_support_win,
timestamp);
/* create the netwm support window */
attrib.override_redirect = TRUE;
+ attrib.event_mask = PropertyChangeMask;
screen_support_win = XCreateWindow(ob_display,
RootWindow(ob_display, ob_screen),
-100, -100, 1, 1, 0,
CopyFromParent, InputOutput,
CopyFromParent,
- CWOverrideRedirect, &attrib);
+ CWEventMask | CWOverrideRedirect,
+ &attrib);
XMapWindow(ob_display, screen_support_win);
XLowerWindow(ob_display, screen_support_win);
supported[i++] = prop_atoms.net_moveresize_window;
supported[i++] = prop_atoms.net_wm_moveresize;
supported[i++] = prop_atoms.net_wm_user_time;
+/*
supported[i++] = prop_atoms.net_wm_user_time_window;
+*/
supported[i++] = prop_atoms.net_frame_extents;
supported[i++] = prop_atoms.net_request_frame_extents;
supported[i++] = prop_atoms.net_restack_window;
guint32 d;
gboolean namesexist = FALSE;
- desktop_cycle_popup = pager_popup_new(FALSE);
- pager_popup_height(desktop_cycle_popup, POPUP_HEIGHT);
+ desktop_popup = pager_popup_new(FALSE);
+ pager_popup_height(desktop_popup, POPUP_HEIGHT);
if (reconfig) {
/* update the pager popup's width */
- pager_popup_text_width_to_strings(desktop_cycle_popup,
+ pager_popup_text_width_to_strings(desktop_popup,
screen_desktop_names,
screen_num_desktops);
return;
void screen_shutdown(gboolean reconfig)
{
- pager_popup_free(desktop_cycle_popup);
+ pager_popup_free(desktop_popup);
if (reconfig)
return;
else if (screen_desktop == num - 1 &&
(c->desktop == DESKTOP_ALL ||
c->desktop == screen_desktop))
- stacking_raise(WINDOW_AS_CLIENT(c));
+ stacking_raise(CLIENT_AS_WINDOW(c));
}
}
-
+
/* change our struts/area to match (after moving windows) */
screen_update_areas();
screen_set_desktop(num - 1, TRUE);
}
-void screen_set_desktop(guint num, gboolean dofocus)
+static void screen_fallback_focus()
{
ObClient *c;
- GList *it;
- guint old;
- gulong ignore_start;
gboolean allow_omni;
-
- g_assert(num < screen_num_desktops);
-
- old = screen_desktop;
- screen_desktop = num;
-
- if (old == num) return;
-
- PROP_SET32(RootWindow(ob_display, ob_screen),
- net_current_desktop, cardinal, num);
-
- screen_last_desktop = old;
-
- ob_debug("Moving to desktop %d\n", num+1);
-
- /* ignore enter events caused by the move */
- ignore_start = event_start_ignore_all_enters();
-
- if (moveresize_client)
- client_set_desktop(moveresize_client, num, TRUE, FALSE);
-
- /* show windows before hiding the rest to lessen the enter/leave events */
-
- /* show windows from top to bottom */
- for (it = stacking_list; it; it = g_list_next(it)) {
- if (WINDOW_IS_CLIENT(it->data)) {
- ObClient *c = it->data;
- client_show(c);
- }
- }
/* only allow omnipresent windows to get focus on desktop change if
an omnipresent window is already focused (it'll keep focus probably, but
/* the client moved there already so don't move focus. prevent flicker
on sendtodesktop + follow */
if (focus_client && focus_client->desktop == screen_desktop)
- dofocus = FALSE;
+ return;
/* have to try focus here because when you leave an empty desktop
there is no focus out to watch for. also, we have different rules
do this before hiding the windows so if helper windows are coming
with us, they don't get hidden
*/
- if (dofocus && (c = focus_fallback(TRUE, !config_focus_last, allow_omni)))
+ if ((c = focus_fallback(TRUE, !config_focus_last, allow_omni,
+ !allow_omni)))
{
/* only do the flicker reducing stuff ahead of time if we are going
to call xsetinputfocus on the window ourselves. otherwise there is
client_bring_helper_windows(c);
}
}
+}
+
+void screen_set_desktop(guint num, gboolean dofocus)
+{
+ GList *it;
+ guint old;
+ gulong ignore_start;
+
+ g_assert(num < screen_num_desktops);
+
+ old = screen_desktop;
+ screen_desktop = num;
+
+ if (old == num) return;
+
+ PROP_SET32(RootWindow(ob_display, ob_screen),
+ net_current_desktop, cardinal, num);
+
+ screen_last_desktop = old;
+
+ ob_debug("Moving to desktop %d\n", num+1);
+
+ /* ignore enter events caused by the move */
+ ignore_start = event_start_ignore_all_enters();
+
+ if (moveresize_client)
+ client_set_desktop(moveresize_client, num, TRUE, FALSE);
+
+ /* show windows before hiding the rest to lessen the enter/leave events */
+
+ /* show windows from top to bottom */
+ for (it = stacking_list; it; it = g_list_next(it)) {
+ if (WINDOW_IS_CLIENT(it->data)) {
+ ObClient *c = it->data;
+ client_show(c);
+ }
+ }
+
+ if (dofocus) screen_fallback_focus();
/* hide windows from bottom to top */
for (it = g_list_last(stacking_list); it; it = g_list_previous(it)) {
if (event_curtime != CurrentTime)
screen_desktop_user_time = event_curtime;
+
+ if (ob_state() == OB_STATE_RUNNING)
+ screen_show_desktop_popup(screen_desktop);
+}
+
+void screen_add_desktop(gboolean current)
+{
+ gulong ignore_start;
+
+ /* 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\n", 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\n", 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\n", c->title);
+ }
+ }
+ }
+
+ /* fallback focus like we're changing desktops */
+ if (screen_desktop < screen_num_desktops - 1) {
+ screen_fallback_focus();
+ ob_debug("fake desktop change\n");
+ }
+
+ 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)
return 0;
}
-void screen_desktop_popup(guint d, gboolean show)
+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)
{
Rect *a;
- if (!show) {
- pager_popup_hide(desktop_cycle_popup);
- } else {
- a = screen_physical_area_active();
- pager_popup_position(desktop_cycle_popup, CenterGravity,
- a->x + a->width / 2, a->y + a->height / 2);
- pager_popup_icon_size_multiplier(desktop_cycle_popup,
- (screen_desktop_layout.columns /
- screen_desktop_layout.rows) / 2,
- (screen_desktop_layout.rows/
- screen_desktop_layout.columns) / 2);
- pager_popup_max_width(desktop_cycle_popup,
- MAX(a->width/3, POPUP_WIDTH));
- pager_popup_show(desktop_cycle_popup, screen_desktop_names[d], d);
- }
+ /* 0 means don't show the popup */
+ if (!config_desktop_popup_time) return;
+
+ a = screen_physical_area_active();
+ 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);
+
+ ob_main_loop_timeout_remove(ob_main_loop, hide_desktop_popup_func);
+ ob_main_loop_timeout_add(ob_main_loop, config_desktop_popup_time * 1000,
+ hide_desktop_popup_func, NULL, NULL, NULL);
}
-guint screen_cycle_desktop(ObDirection dir, gboolean wrap, gboolean linear,
- gboolean dialog, gboolean done, gboolean cancel)
+guint screen_find_desktop(guint from, ObDirection dir,
+ gboolean wrap, gboolean linear)
{
guint r, c;
- static guint d = (guint)-1;
- guint ret, oldd;
-
- if (d == (guint)-1)
- d = screen_desktop;
-
- if ((cancel || done) && dialog)
- goto show_cycle_dialog;
+ guint d;
- oldd = d;
+ d = from;
get_row_col(d, &r, &c);
-
if (linear) {
switch (dir) {
case OB_DIRECTION_EAST:
++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:
- assert(0);
- return screen_desktop;
+ g_assert_not_reached();
+ return from;
}
} else {
switch (dir) {
if (wrap)
c = 0;
else
- goto show_cycle_dialog;
+ return from;
}
d = translate_row_col(r, c);
if (d >= screen_num_desktops) {
- if (wrap) {
+ if (wrap)
++c;
- } else {
- d = oldd;
- goto show_cycle_dialog;
- }
+ else
+ return from;
}
break;
case OB_DIRECTION_WEST:
if (wrap)
c = screen_desktop_layout.columns - 1;
else
- goto show_cycle_dialog;
+ return from;
}
d = translate_row_col(r, c);
if (d >= screen_num_desktops) {
- if (wrap) {
+ if (wrap)
--c;
- } else {
- d = oldd;
- goto show_cycle_dialog;
- }
+ else
+ return from;
}
break;
case OB_DIRECTION_SOUTH:
if (wrap)
r = 0;
else
- goto show_cycle_dialog;
+ return from;
}
d = translate_row_col(r, c);
if (d >= screen_num_desktops) {
- if (wrap) {
+ if (wrap)
++r;
- } else {
- d = oldd;
- goto show_cycle_dialog;
- }
+ else
+ return from;
}
break;
case OB_DIRECTION_NORTH:
if (wrap)
r = screen_desktop_layout.rows - 1;
else
- goto show_cycle_dialog;
+ return from;
}
d = translate_row_col(r, c);
if (d >= screen_num_desktops) {
- if (wrap) {
+ if (wrap)
--r;
- } else {
- d = oldd;
- goto show_cycle_dialog;
- }
+ else
+ return from;
}
break;
default:
- assert(0);
- return d = screen_desktop;
+ g_assert_not_reached();
+ return from;
}
d = translate_row_col(r, c);
}
-
-show_cycle_dialog:
- if (dialog && !cancel && !done) {
- screen_desktop_popup(d, TRUE);
- } else
- screen_desktop_popup(0, FALSE);
- ret = d;
-
- if (!dialog || cancel || done)
- d = (guint)-1;
-
- return ret;
+ return d;
}
static gboolean screen_validate_layout(ObDesktopLayout *l)
if (PROP_GETA32(RootWindow(ob_display, ob_screen),
net_desktop_layout, cardinal, &data, &num)) {
if (num == 3 || num == 4) {
-
+
if (data[0] == prop_atoms.net_wm_orientation_vert)
l.orientation = OB_ORIENTATION_VERT;
else if (data[0] == prop_atoms.net_wm_orientation_horz)
}
/* resize the pager for these names */
- pager_popup_text_width_to_strings(desktop_cycle_popup,
+ pager_popup_text_width_to_strings(desktop_popup,
screen_desktop_names,
screen_num_desktops);
}
void screen_show_desktop(gboolean show, ObClient *show_only)
{
GList *it;
-
+
if (show == screen_showing_desktop) return; /* no change */
screen_showing_desktop = show;
else if (!show_only) {
ObClient *c;
- if ((c = focus_fallback(TRUE, FALSE, TRUE))) {
+ if ((c = focus_fallback(TRUE, FALSE, TRUE, FALSE))) {
/* only do the flicker reducing stuff ahead of time if we are going
to call xsetinputfocus on the window ourselves. otherwise there
is no guarantee the window will actually take focus.. */
sl = g_slist_prepend(sl, ss); \
}
+#define VALIDATE_STRUTS(sl, side, max) \
+{ \
+ GSList *it; \
+ for (it = sl; it; it = g_slist_next(it)) { \
+ ObScreenStrut *ss = it->data; \
+ ss->strut->side = MIN(max, ss->strut->side); \
+ } \
+}
+
void screen_update_areas()
{
guint i, j;
GList *it;
GSList *sit;
- ob_debug("updating screen areas\n");
-
g_free(monitor_area);
extensions_xinerama_screens(&monitor_area, &screen_num_monitors);
+ /* set up the user-specified margins */
+ config_margins.top_start = RECT_LEFT(monitor_area[screen_num_monitors]);
+ config_margins.top_end = RECT_RIGHT(monitor_area[screen_num_monitors]);
+ config_margins.bottom_start = RECT_LEFT(monitor_area[screen_num_monitors]);
+ config_margins.bottom_end = RECT_RIGHT(monitor_area[screen_num_monitors]);
+ config_margins.left_start = RECT_TOP(monitor_area[screen_num_monitors]);
+ config_margins.left_end = RECT_BOTTOM(monitor_area[screen_num_monitors]);
+ config_margins.right_start = RECT_TOP(monitor_area[screen_num_monitors]);
+ config_margins.right_end = RECT_BOTTOM(monitor_area[screen_num_monitors]);
+
dims = g_new(gulong, 4 * screen_num_desktops * screen_num_monitors);
RESET_STRUT_LIST(struts_left);
if (dock_strut.bottom)
ADD_STRUT_TO_LIST(struts_bottom, DESKTOP_ALL, &dock_strut);
+ if (config_margins.left)
+ ADD_STRUT_TO_LIST(struts_left, DESKTOP_ALL, &config_margins);
+ if (config_margins.top)
+ ADD_STRUT_TO_LIST(struts_top, DESKTOP_ALL, &config_margins);
+ if (config_margins.right)
+ ADD_STRUT_TO_LIST(struts_right, DESKTOP_ALL, &config_margins);
+ if (config_margins.bottom)
+ ADD_STRUT_TO_LIST(struts_bottom, DESKTOP_ALL, &config_margins);
+
+ VALIDATE_STRUTS(struts_left, left,
+ monitor_area[screen_num_monitors].width / 2);
+ VALIDATE_STRUTS(struts_right, right,
+ monitor_area[screen_num_monitors].width / 2);
+ VALIDATE_STRUTS(struts_top, top,
+ monitor_area[screen_num_monitors].height / 2);
+ VALIDATE_STRUTS(struts_bottom, bottom,
+ monitor_area[screen_num_monitors].height / 2);
+
/* set up the work areas to be full screen */
for (i = 0; i < screen_num_monitors; ++i)
for (j = 0; j < screen_num_desktops; ++j) {
dims[(i * screen_num_desktops + j) * 4 + 3] -= t + b;
}
+ /* all the work areas are not used here, only the ones for the first
+ monitor are */
PROP_SETA32(RootWindow(ob_display, ob_screen), net_workarea, cardinal,
- dims, 4 * screen_num_desktops * screen_num_monitors);
+ dims, 4 * screen_num_desktops);
/* the area has changed, adjust all the windows if they need it */
for (it = client_list; it; it = g_list_next(it))
g_free(m);
}
-
+
return a;
}
#endif
Rect *a;
gint x, y;
- if (focus_client)
+ if (moveresize_client)
+ a = screen_physical_area_monitor(client_monitor(focus_client));
+ else if (focus_client)
a = screen_physical_area_monitor(client_monitor(focus_client));
else {
Rect mon;