#include "startupnotify.h"
#include "moveresize.h"
#include "config.h"
+#include "mainloop.h"
#include "screen.h"
#include "client.h"
#include "session.h"
ButtonPressMask | ButtonReleaseMask)
static gboolean screen_validate_layout(ObDesktopLayout *l);
-static gboolean replace_wm();
-static void screen_tell_ksplash();
+static gboolean replace_wm(void);
+static void screen_tell_ksplash(void);
+static void screen_fallback_focus(void);
guint screen_num_desktops;
guint screen_num_monitors;
guint screen_desktop;
-guint screen_last_desktop;
-Size screen_physical_size;
+guint screen_last_desktop = 1;
gboolean screen_showing_desktop;
ObDesktopLayout screen_desktop_layout;
gchar **screen_desktop_names;
Window screen_support_win;
Time screen_desktop_user_time = CurrentTime;
+static Size screen_physical_size;
+static guint screen_old_desktop;
+static gboolean screen_desktop_timeout = TRUE;
/*! An array of desktops, holding array of areas per monitor */
static Rect *monitor_area = NULL;
/*! An array of desktops, holding an array of struts */
static GSList *struts_right = NULL;
static GSList *struts_bottom = NULL;
-static ObPagerPopup *desktop_cycle_popup;
+static ObPagerPopup *desktop_popup;
-static gboolean replace_wm()
+/*! The number of microseconds that you need to be on a desktop before it will
+ replace the remembered "last desktop" */
+#define REMEMBER_LAST_DESKTOP_TIME 750000
+
+static gboolean replace_wm(void)
{
gchar *wm_sn;
Atom wm_sn_atom;
return TRUE;
}
-gboolean screen_annex()
+gboolean screen_annex(void)
{
XSetWindowAttributes attrib;
pid_t pid;
supported[i++] = prop_atoms.net_wm_sync_request;
supported[i++] = prop_atoms.net_wm_sync_request_counter;
#endif
+ supported[i++] = prop_atoms.net_wm_pid;
+ supported[i++] = prop_atoms.net_wm_ping;
supported[i++] = prop_atoms.kde_wm_change_state;
supported[i++] = prop_atoms.kde_net_wm_frame_strut;
return TRUE;
}
-static void screen_tell_ksplash()
+static void screen_tell_ksplash(void)
{
XEvent e;
char **argv;
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();
+ 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;
screen_desktop_names = NULL;
}
-void screen_resize()
+void screen_resize(void)
{
static gint oldw = 0, oldh = 0;
gint w, h;
screen_set_desktop(num - 1, TRUE);
}
-void screen_set_desktop(guint num, gboolean dofocus)
+static void screen_fallback_focus(void)
{
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
maybe not depending on mouse-focus options) */
/* 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);
}
}
+}
+
+static gboolean last_desktop_func(gpointer data)
+{
+ screen_desktop_timeout = TRUE;
+ return FALSE;
+}
+
+void screen_set_desktop(guint num, gboolean dofocus)
+{
+ GList *it;
+ guint previous;
+ gulong ignore_start;
+
+ g_assert(num < screen_num_desktops);
+
+ previous = screen_desktop;
+ screen_desktop = num;
+
+ if (previous == num) return;
+
+ PROP_SET32(RootWindow(ob_display, ob_screen),
+ net_current_desktop, cardinal, num);
+
+ /* This whole thing decides when/how to save the screen_last_desktop so
+ that it can be restored later if you want */
+ if (screen_desktop_timeout) {
+ /* If screen_desktop_timeout is true, then we've been on this desktop
+ long enough and we can save it as the last desktop. */
+
+ /* save the "last desktop" as the "old desktop" */
+ screen_old_desktop = screen_last_desktop;
+ /* save the desktop we're coming from as the "last desktop" */
+ screen_last_desktop = previous;
+ }
+ else {
+ /* If screen_desktop_timeout is false, then we just got to this desktop
+ and we are moving away again. */
+
+ if (screen_desktop == screen_last_desktop) {
+ /* If we are moving to the "last desktop" .. */
+ if (previous == screen_old_desktop) {
+ /* .. from the "old desktop", change the last desktop to
+ be where we are coming from */
+ screen_last_desktop = screen_old_desktop;
+ }
+ else if (screen_last_desktop == screen_old_desktop) {
+ /* .. and also to the "old desktop", change the "last
+ desktop" to be where we are coming from */
+ screen_last_desktop = previous;
+ }
+ else {
+ /* .. from some other desktop, then set the "last desktop" to
+ be the saved "old desktop", i.e. where we were before the
+ "last desktop" */
+ screen_last_desktop = screen_old_desktop;
+ }
+ }
+ else {
+ /* If we are moving to any desktop besides the "last desktop"..
+ (this is the normal case) */
+ if (screen_desktop == screen_old_desktop) {
+ /* If moving to the "old desktop", which is not the
+ "last desktop", don't save anything */
+ }
+ else if (previous == screen_old_desktop) {
+ /* If moving from the "old desktop", and not to the
+ "last desktop", don't save anything */
+ }
+ else if (screen_last_desktop == screen_old_desktop) {
+ /* If the "last desktop" is the same as "old desktop" and
+ you're not moving to the "last desktop" then save where
+ we're coming from as the "last desktop" */
+ screen_last_desktop = previous;
+ }
+ else {
+ /* If the "last desktop" is different from the "old desktop"
+ and you're not moving to the "last desktop", then don't save
+ anything */
+ }
+ }
+ }
+ screen_desktop_timeout = FALSE;
+ ob_main_loop_timeout_remove(ob_main_loop, last_desktop_func);
+ ob_main_loop_timeout_add(ob_main_loop, REMEMBER_LAST_DESKTOP_TIME,
+ last_desktop_func, NULL, NULL, NULL);
+
+ 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 */
}
}
}
+
+ 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;
}
}
- /* act like we're changing desktops */
+ /* fallback focus like we're changing desktops */
if (screen_desktop < screen_num_desktops - 1) {
- gint d = screen_desktop;
- screen_desktop = screen_last_desktop;
- screen_set_desktop(d, TRUE);
+ 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);
+ g_free(a);
+}
+
+void screen_hide_desktop_popup(void)
+{
+ ob_main_loop_timeout_remove(ob_main_loop, hide_desktop_popup_func);
+ pager_popup_hide(desktop_popup);
}
guint screen_find_desktop(guint from, ObDirection dir,
return d;
}
-guint screen_cycle_desktop(ObDirection dir, gboolean wrap, gboolean linear,
- gboolean dialog, gboolean done, gboolean cancel)
-{
- static guint d = (guint)-1;
- guint ret;
-
- if (d == (guint)-1)
- d = screen_desktop;
-
- if ((!cancel && !done) || !dialog)
- d = screen_find_desktop(d, dir, wrap, linear);
-
- 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;
-}
-
static gboolean screen_validate_layout(ObDesktopLayout *l)
{
if (l->columns == 0 && l->rows == 0) /* both 0's is bad data.. */
return TRUE;
}
-void screen_update_layout()
+void screen_update_layout(void)
{
ObDesktopLayout l;
}
}
-void screen_update_desktop_names()
+void screen_update_desktop_names(void)
{
guint i;
}
/* 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);
}
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.. */
} \
}
-void screen_update_areas()
+void screen_update_areas(void)
{
guint i, j;
gulong *dims;
guint screen_find_monitor(Rect *search)
{
guint i;
- guint most = 0;
+ guint most = screen_num_monitors;
guint mostv = 0;
for (i = 0; i < screen_num_monitors; ++i) {
return most;
}
-Rect* screen_physical_area_all_monitors()
+Rect* screen_physical_area_all_monitors(void)
{
return screen_physical_area_monitor(screen_num_monitors);
}
return RECT_INTERSECTS_RECT(monitor_area[head], *search);
}
-Rect* screen_physical_area_active()
+Rect* screen_physical_area_active(void)
{
Rect *a;
gint x, y;
return a;
}
-void screen_set_root_cursor()
+void screen_set_root_cursor(void)
{
if (sn_app_starting())
XDefineCursor(ob_display, RootWindow(ob_display, ob_screen),