X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=openbox%2Fscreen.c;h=7b4ca7406066034c010b8c353c63642466d8dfe8;hb=22a17d3a28603637cf9259d050c19e8090d7ab2f;hp=c9b05a514013aba8eab10346a118224c012e1a5a;hpb=4736c257a54409bf3b0ef0d803da650c71684dee;p=chaz%2Fopenbox diff --git a/openbox/screen.c b/openbox/screen.c index c9b05a51..7b4ca740 100644 --- a/openbox/screen.c +++ b/openbox/screen.c @@ -1,105 +1,226 @@ +/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*- + + screen.c for the Openbox window manager + Copyright (c) 2006 Mikael Magnusson + Copyright (c) 2003-2007 Dana Jansens + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + See the COPYING file for a copy of the GNU General Public License. +*/ + +#include "debug.h" #include "openbox.h" #include "dock.h" #include "xerror.h" #include "prop.h" -#include "startup.h" -#include "timer.h" +#include "grab.h" +#include "startupnotify.h" +#include "moveresize.h" #include "config.h" #include "screen.h" #include "client.h" +#include "session.h" #include "frame.h" +#include "event.h" #include "focus.h" -#include "dispatch.h" +#include "popup.h" #include "extensions.h" #include "render/render.h" - -#ifdef USE_LIBSN -# define SN_API_NOT_YET_FROZEN -# include -#endif +#include "gettext.h" #include #ifdef HAVE_UNISTD_H # include # include #endif +#include /*! The event mask to grab on the root window */ #define ROOT_EVENTMASK (StructureNotifyMask | PropertyChangeMask | \ - EnterWindowMask | LeaveWindowMask | \ - SubstructureNotifyMask | SubstructureRedirectMask | \ - ButtonPressMask | ButtonReleaseMask | ButtonMotionMask) - -guint screen_num_desktops = 0; -guint screen_num_monitors = 0; -guint screen_desktop = 0; + EnterWindowMask | LeaveWindowMask | \ + SubstructureRedirectMask | FocusChangeMask | \ + ButtonPressMask | ButtonReleaseMask | ButtonMotionMask) + +static gboolean screen_validate_layout(ObDesktopLayout *l); +static gboolean replace_wm(); +static void screen_tell_ksplash(); + +guint screen_num_desktops; +guint screen_num_monitors; +guint screen_desktop; +guint screen_last_desktop; Size screen_physical_size; gboolean screen_showing_desktop; -DesktopLayout screen_desktop_layout; -char **screen_desktop_names = NULL; +ObDesktopLayout screen_desktop_layout; +gchar **screen_desktop_names; +Window screen_support_win; +Time screen_desktop_user_time = CurrentTime; -static Rect **area = NULL; /* array of desktop holding array of - xinerama areas */ -static Rect *monitor_area = NULL; -static Window support_window = None; +static Rect **area; /* array of desktop holding array of xinerama areas */ +static Rect *monitor_area; -#ifdef USE_LIBSN -static SnMonitorContext *sn_context; -static int sn_busy_cnt; -static Timer *sn_timer = NULL; +static ObPagerPopup *desktop_cycle_popup; -static void sn_event_func(SnMonitorEvent *event, void *data); -#endif +static gboolean replace_wm() +{ + gchar *wm_sn; + Atom wm_sn_atom; + Window current_wm_sn_owner; + Time timestamp; + + wm_sn = g_strdup_printf("WM_S%d", ob_screen); + wm_sn_atom = XInternAtom(ob_display, wm_sn, FALSE); + g_free(wm_sn); + + current_wm_sn_owner = XGetSelectionOwner(ob_display, wm_sn_atom); + if (current_wm_sn_owner == screen_support_win) + current_wm_sn_owner = None; + if (current_wm_sn_owner) { + if (!ob_replace_wm) { + g_message(_("A window manager is already running on screen %d"), + ob_screen); + return FALSE; + } + xerror_set_ignore(TRUE); + xerror_occured = FALSE; -static void set_root_cursor(); + /* We want to find out when the current selection owner dies */ + XSelectInput(ob_display, current_wm_sn_owner, StructureNotifyMask); + XSync(ob_display, FALSE); -static gboolean running; -static int another_running(Display *d, XErrorEvent *e) -{ - (void)d;(void)e; - g_message("A window manager is already running on screen %d", - ob_screen); - running = TRUE; - return -1; + xerror_set_ignore(FALSE); + if (xerror_occured) + 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; + } + + XSetSelectionOwner(ob_display, wm_sn_atom, screen_support_win, + timestamp); + + if (XGetSelectionOwner(ob_display, wm_sn_atom) != screen_support_win) { + g_message(_("Could not acquire window manager selection on screen %d"), + ob_screen); + return FALSE; + } + + /* Wait for old window manager to go away */ + if (current_wm_sn_owner) { + XEvent event; + gulong wait = 0; + const gulong timeout = G_USEC_PER_SEC * 15; /* wait for 15s max */ + + while (wait < timeout) { + if (XCheckWindowEvent(ob_display, current_wm_sn_owner, + StructureNotifyMask, &event) && + event.type == DestroyNotify) + break; + g_usleep(G_USEC_PER_SEC / 10); + wait += G_USEC_PER_SEC / 10; + } + + if (wait >= timeout) { + g_message(_("The WM on screen %d is not exiting"), ob_screen); + return FALSE; + } + } + + /* Send client message indicating that we are now the WM */ + prop_message(RootWindow(ob_display, ob_screen), prop_atoms.manager, + timestamp, wm_sn_atom, screen_support_win, 0, + SubstructureNotifyMask); + + return TRUE; } gboolean screen_annex() { - XErrorHandler old; + XSetWindowAttributes attrib; pid_t pid; - int i, num_support; - guint32 *supported; + gint i, num_support; + Atom *prop_atoms_start, *wm_supported_pos; + gulong *supported; - running = FALSE; - old = XSetErrorHandler(another_running); - XSelectInput(ob_display, ob_root, ROOT_EVENTMASK); - XSync(ob_display, FALSE); - XSetErrorHandler(old); - if (running) - return FALSE; + /* create the netwm support window */ + attrib.override_redirect = TRUE; + screen_support_win = XCreateWindow(ob_display, + RootWindow(ob_display, ob_screen), + -100, -100, 1, 1, 0, + CopyFromParent, InputOutput, + CopyFromParent, + CWOverrideRedirect, &attrib); + XMapWindow(ob_display, screen_support_win); + XLowerWindow(ob_display, screen_support_win); + + if (!replace_wm()) { + XDestroyWindow(ob_display, screen_support_win); + return FALSE; + } - g_message("Managing screen %d", ob_screen); + xerror_set_ignore(TRUE); + xerror_occured = FALSE; + XSelectInput(ob_display, RootWindow(ob_display, ob_screen), + ROOT_EVENTMASK); + xerror_set_ignore(FALSE); + if (xerror_occured) { + g_message(_("A window manager is already running on screen %d"), + ob_screen); + + XDestroyWindow(ob_display, screen_support_win); + return FALSE; + } - set_root_cursor(); + screen_set_root_cursor(); /* set the OPENBOX_PID hint */ pid = getpid(); - PROP_SET32(ob_root, openbox_pid, cardinal, pid); - - /* create the netwm support window */ - support_window = XCreateSimpleWindow(ob_display, ob_root, 0,0,1,1,0,0,0); + PROP_SET32(RootWindow(ob_display, ob_screen), + openbox_pid, cardinal, pid); /* set supporting window */ - PROP_SET32(ob_root, net_supporting_wm_check, window, support_window); + PROP_SET32(RootWindow(ob_display, ob_screen), + net_supporting_wm_check, window, screen_support_win); /* set properties on the supporting window */ - PROP_SETS(support_window, net_wm_name, "Openbox"); - PROP_SET32(support_window, net_supporting_wm_check, window,support_window); + PROP_SETS(screen_support_win, net_wm_name, "Openbox"); + PROP_SET32(screen_support_win, net_supporting_wm_check, + window, screen_support_win); /* set the _NET_SUPPORTED_ATOMS hint */ - num_support = 61; + + /* this is all the atoms after net_supported in the prop_atoms struct */ + prop_atoms_start = (Atom*)&prop_atoms; + wm_supported_pos = (Atom*)&(prop_atoms.net_supported); + num_support = sizeof(prop_atoms) / sizeof(Atom) - + (wm_supported_pos - prop_atoms_start) - 1; i = 0; - supported = g_new(guint32, num_support); + supported = g_new(gulong, num_support); + supported[i++] = prop_atoms.net_supporting_wm_check; + supported[i++] = prop_atoms.net_wm_full_placement; supported[i++] = prop_atoms.net_current_desktop; supported[i++] = prop_atoms.net_number_of_desktops; supported[i++] = prop_atoms.net_desktop_geometry; @@ -118,6 +239,9 @@ gboolean screen_annex() supported[i++] = prop_atoms.net_wm_visible_icon_name; supported[i++] = prop_atoms.net_wm_desktop; supported[i++] = prop_atoms.net_wm_strut; + supported[i++] = prop_atoms.net_wm_strut_partial; + supported[i++] = prop_atoms.net_wm_icon; + supported[i++] = prop_atoms.net_wm_icon_geometry; supported[i++] = prop_atoms.net_wm_window_type; supported[i++] = prop_atoms.net_wm_window_type_desktop; supported[i++] = prop_atoms.net_wm_window_type_dock; @@ -137,6 +261,8 @@ gboolean screen_annex() supported[i++] = prop_atoms.net_wm_action_fullscreen; supported[i++] = prop_atoms.net_wm_action_change_desktop; supported[i++] = prop_atoms.net_wm_action_close; + supported[i++] = prop_atoms.net_wm_action_above; + supported[i++] = prop_atoms.net_wm_action_below; supported[i++] = prop_atoms.net_wm_state; supported[i++] = prop_atoms.net_wm_state_modal; supported[i++] = prop_atoms.net_wm_state_maximized_vert; @@ -148,92 +274,202 @@ gboolean screen_annex() supported[i++] = prop_atoms.net_wm_state_fullscreen; supported[i++] = prop_atoms.net_wm_state_above; supported[i++] = prop_atoms.net_wm_state_below; + supported[i++] = prop_atoms.net_wm_state_demands_attention; supported[i++] = prop_atoms.net_moveresize_window; supported[i++] = prop_atoms.net_wm_moveresize; - supported[i++] = prop_atoms.net_wm_moveresize_size_topleft; - supported[i++] = prop_atoms.net_wm_moveresize_size_top; - supported[i++] = prop_atoms.net_wm_moveresize_size_topright; - supported[i++] = prop_atoms.net_wm_moveresize_size_right; - supported[i++] = prop_atoms.net_wm_moveresize_size_bottomright; - supported[i++] = prop_atoms.net_wm_moveresize_size_bottom; - supported[i++] = prop_atoms.net_wm_moveresize_size_bottomleft; - supported[i++] = prop_atoms.net_wm_moveresize_size_left; - supported[i++] = prop_atoms.net_wm_moveresize_move; - supported[i++] = prop_atoms.net_wm_moveresize_size_keyboard; - supported[i++] = prop_atoms.net_wm_moveresize_move_keyboard; + 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; + supported[i++] = prop_atoms.net_startup_id; +#ifdef SYNC + supported[i++] = prop_atoms.net_wm_sync_request; + supported[i++] = prop_atoms.net_wm_sync_request_counter; +#endif + + supported[i++] = prop_atoms.kde_wm_change_state; + supported[i++] = prop_atoms.kde_net_wm_frame_strut; + supported[i++] = prop_atoms.kde_net_wm_window_type_override; + + supported[i++] = prop_atoms.ob_wm_action_undecorate; + supported[i++] = prop_atoms.ob_wm_state_undecorated; + supported[i++] = prop_atoms.openbox_pid; + supported[i++] = prop_atoms.ob_theme; + supported[i++] = prop_atoms.ob_control; g_assert(i == num_support); -/* - supported[] = prop_atoms.net_wm_action_stick; -*/ - PROP_SETA32(ob_root, net_supported, atom, supported, num_support); + PROP_SETA32(RootWindow(ob_display, ob_screen), + net_supported, atom, supported, num_support); g_free(supported); + screen_tell_ksplash(); + return TRUE; } -void screen_startup() +static void screen_tell_ksplash() { - GSList *it; - guint i; + XEvent e; + char **argv; + + argv = g_new(gchar*, 6); + argv[0] = g_strdup("dcop"); + argv[1] = g_strdup("ksplash"); + argv[2] = g_strdup("ksplash"); + argv[3] = g_strdup("upAndRunning(QString)"); + argv[4] = g_strdup("wm started"); + argv[5] = NULL; + + /* tell ksplash through the dcop server command line interface */ + g_spawn_async(NULL, argv, NULL, + G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD | + G_SPAWN_STDERR_TO_DEV_NULL | G_SPAWN_STDOUT_TO_DEV_NULL, + NULL, NULL, NULL, NULL); + g_strfreev(argv); + + /* i'm not sure why we do this, kwin does it, but ksplash doesn't seem to + hear it anyways. perhaps it is for old ksplash. or new ksplash. or + something. oh well. */ + e.xclient.type = ClientMessage; + e.xclient.display = ob_display; + e.xclient.window = RootWindow(ob_display, ob_screen); + e.xclient.message_type = + XInternAtom(ob_display, "_KDE_SPLASH_PROGRESS", False ); + e.xclient.format = 8; + strcpy(e.xclient.data.b, "wm started"); + XSendEvent(ob_display, RootWindow(ob_display, ob_screen), + False, SubstructureNotifyMask, &e ); +} + +void screen_startup(gboolean reconfig) +{ + gchar **names = NULL; + guint32 d; + gboolean namesexist = FALSE; + + desktop_cycle_popup = pager_popup_new(FALSE); + pager_popup_height(desktop_cycle_popup, POPUP_HEIGHT); + + if (reconfig) { + /* update the pager popup's width */ + pager_popup_text_width_to_strings(desktop_cycle_popup, + screen_desktop_names, + screen_num_desktops); + return; + } /* get the initial size */ screen_resize(); - /* set the names */ - screen_desktop_names = g_new(char*, - g_slist_length(config_desktops_names) + 1); - for (i = 0, it = config_desktops_names; it; ++i, it = it->next) - screen_desktop_names[i] = it->data; /* dont strdup */ - screen_desktop_names[i] = NULL; - PROP_SETSS(ob_root, net_desktop_names, screen_desktop_names); - g_free(screen_desktop_names); /* dont free the individual strings */ - screen_desktop_names = NULL; + /* have names already been set for the desktops? */ + if (PROP_GETSS(RootWindow(ob_display, ob_screen), + net_desktop_names, utf8, &names)) + { + g_strfreev(names); + namesexist = TRUE; + } + + /* if names don't exist and we have session names, set those. + do this stuff BEFORE setting the number of desktops, because that + will create default names for them + */ + if (!namesexist && session_desktop_names != NULL) { + guint i, numnames; + GSList *it; + + /* get the desktop names */ + numnames = g_slist_length(session_desktop_names); + names = g_new(gchar*, numnames + 1); + names[numnames] = NULL; + for (i = 0, it = session_desktop_names; it; ++i, it = g_slist_next(it)) + names[i] = g_strdup(it->data); + + /* set the root window property */ + PROP_SETSS(RootWindow(ob_display, ob_screen), net_desktop_names,names); + + g_strfreev(names); + } + + /* set the number of desktops, if it's not already set. + this will also set the default names from the config file up for + desktops that don't have names yet */ screen_num_desktops = 0; - screen_set_num_desktops(config_desktops_num); - if (startup_desktop >= screen_num_desktops) - startup_desktop = 0; - screen_desktop = startup_desktop; - screen_set_desktop(startup_desktop); + if (PROP_GET32(RootWindow(ob_display, ob_screen), + net_number_of_desktops, cardinal, &d)) + screen_set_num_desktops(d); + /* restore from session if possible */ + else if (session_num_desktops) + screen_set_num_desktops(session_num_desktops); + else + screen_set_num_desktops(config_desktops_num); + + screen_desktop = screen_num_desktops; /* something invalid */ + /* start on the current desktop when a wm was already running */ + if (PROP_GET32(RootWindow(ob_display, ob_screen), + net_current_desktop, cardinal, &d) && + d < screen_num_desktops) + { + screen_set_desktop(d, FALSE); + } else if (session_desktop >= 0) + screen_set_desktop(MIN((guint)session_desktop, + screen_num_desktops), FALSE); + else + screen_set_desktop(MIN(config_screen_firstdesk, + screen_num_desktops) - 1, FALSE); + screen_last_desktop = screen_desktop; /* don't start in showing-desktop mode */ screen_showing_desktop = FALSE; - PROP_SET32(ob_root, net_showing_desktop, cardinal, screen_showing_desktop); - - screen_update_layout(); + PROP_SET32(RootWindow(ob_display, ob_screen), + net_showing_desktop, cardinal, screen_showing_desktop); -#ifdef USE_LIBSN - sn_context = sn_monitor_context_new(ob_sn_display, ob_screen, - sn_event_func, NULL, NULL); - sn_busy_cnt = 0; -#endif + if (session_desktop_layout_present && + screen_validate_layout(&session_desktop_layout)) + { + screen_desktop_layout = session_desktop_layout; + } + else + screen_update_layout(); } -void screen_shutdown() +void screen_shutdown(gboolean reconfig) { Rect **r; - XSelectInput(ob_display, ob_root, NoEventMask); + pager_popup_free(desktop_cycle_popup); - PROP_ERASE(ob_root, openbox_pid); /* we're not running here no more! */ - PROP_ERASE(ob_root, net_supported); /* not without us */ - PROP_ERASE(ob_root, net_showing_desktop); /* don't keep this mode */ + if (reconfig) + return; + + XSelectInput(ob_display, RootWindow(ob_display, ob_screen), + NoEventMask); - XDestroyWindow(ob_display, support_window); + /* we're not running here no more! */ + PROP_ERASE(RootWindow(ob_display, ob_screen), openbox_pid); + /* not without us */ + PROP_ERASE(RootWindow(ob_display, ob_screen), net_supported); + /* don't keep this mode */ + PROP_ERASE(RootWindow(ob_display, ob_screen), net_showing_desktop); + + XDestroyWindow(ob_display, screen_support_win); g_strfreev(screen_desktop_names); + screen_desktop_names = NULL; + for (r = area; *r; ++r) g_free(*r); g_free(area); + area = NULL; } void screen_resize() { - static int oldw = 0, oldh = 0; - int w, h; + static gint oldw = 0, oldh = 0; + gint w, h; GList *it; - guint32 geometry[2]; + gulong geometry[2]; w = WidthOfScreen(ScreenOfDisplay(ob_display, ob_screen)); h = HeightOfScreen(ScreenOfDisplay(ob_display, ob_screen)); @@ -245,192 +481,479 @@ void screen_resize() /* Set the _NET_DESKTOP_GEOMETRY hint */ screen_physical_size.width = geometry[0] = w; screen_physical_size.height = geometry[1] = h; - PROP_SETA32(ob_root, net_desktop_geometry, cardinal, geometry, 2); + PROP_SETA32(RootWindow(ob_display, ob_screen), + net_desktop_geometry, cardinal, geometry, 2); - if (ob_state == OB_STATE_STARTING) - return; + if (ob_state() == OB_STATE_STARTING) + return; - dock_configure(); screen_update_areas(); + dock_configure(); - for (it = client_list; it; it = it->next) - client_move_onscreen(it->data); + for (it = client_list; it; it = g_list_next(it)) + client_move_onscreen(it->data, FALSE); } void screen_set_num_desktops(guint num) { - guint i, old; - guint32 *viewport; + guint old; + gulong *viewport; GList *it; g_assert(num > 0); + if (screen_num_desktops == num) return; + old = screen_num_desktops; screen_num_desktops = num; - PROP_SET32(ob_root, net_number_of_desktops, cardinal, num); + PROP_SET32(RootWindow(ob_display, ob_screen), + net_number_of_desktops, cardinal, num); /* set the viewport hint */ - viewport = g_new0(guint32, num * 2); - PROP_SETA32(ob_root, net_desktop_viewport, cardinal, viewport, num * 2); + viewport = g_new0(gulong, num * 2); + PROP_SETA32(RootWindow(ob_display, ob_screen), + net_desktop_viewport, cardinal, viewport, num * 2); g_free(viewport); /* the number of rows/columns will differ */ screen_update_layout(); - /* may be some unnamed desktops that we need to fill in with names */ - screen_update_desktop_names(); - - /* update the focus lists */ - /* free our lists for the desktops which have disappeared */ - for (i = num; i < old; ++i) - g_list_free(focus_order[i]); - /* realloc the array */ - focus_order = g_renew(GList*, focus_order, num); - /* set the new lists to be empty */ - for (i = old; i < num; ++i) - focus_order[i] = NULL; - /* move windows on desktops that will no longer exist! */ - for (it = client_list; it != NULL; it = it->next) { + for (it = client_list; it; it = g_list_next(it)) { ObClient *c = it->data; if (c->desktop >= num && c->desktop != DESKTOP_ALL) client_set_desktop(c, num - 1, FALSE); } - + /* change our struts/area to match (after moving windows) */ screen_update_areas(); - dispatch_ob(Event_Ob_NumDesktops, num, old); + /* may be some unnamed desktops that we need to fill in with names + (after updating the areas so the popup can resize) */ + screen_update_desktop_names(); /* change our desktop if we're on one that no longer exists! */ if (screen_desktop >= screen_num_desktops) - screen_set_desktop(num - 1); + screen_set_desktop(num - 1, TRUE); } -void screen_set_desktop(guint num) +void screen_set_desktop(guint num, gboolean dofocus) { + ObClient *c; GList *it; guint old; - XEvent e; g_assert(num < screen_num_desktops); old = screen_desktop; screen_desktop = num; - PROP_SET32(ob_root, net_current_desktop, cardinal, num); if (old == num) return; - g_message("Moving to desktop %d", num+1); + 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); + + if (moveresize_client) + client_set_desktop(moveresize_client, num, TRUE); /* show windows before hiding the rest to lessen the enter/leave events */ /* show windows from top to bottom */ - for (it = stacking_list; it != NULL; it = it->next) { + for (it = stacking_list; it; it = g_list_next(it)) { if (WINDOW_IS_CLIENT(it->data)) { ObClient *c = it->data; - if (!c->frame->visible && client_should_show(c)) - frame_show(c->frame); + client_show(c); + } + } + + if (focus_client && ((client_normal(focus_client) && + focus_client->desktop == DESKTOP_ALL) || + focus_client->desktop == screen_desktop)) + dofocus = FALSE; + + /* 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 + here. we always allow it to look under the mouse pointer if + config_focus_last is FALSE + + 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))) + { + /* 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.. */ + if (c->can_focus) { + /* reduce flicker by hiliting now rather than waiting for the + server FocusIn event */ + frame_adjust_focus(c->frame, TRUE); + /* do this here so that if you switch desktops to a window with + helper windows then the helper windows won't flash */ + client_bring_helper_windows(c); } } /* hide windows from bottom to top */ - for (it = g_list_last(stacking_list); it != NULL; it = it->prev) { + for (it = g_list_last(stacking_list); it; it = g_list_previous(it)) { if (WINDOW_IS_CLIENT(it->data)) { ObClient *c = it->data; - if (c->frame->visible && !client_should_show(c)) - frame_hide(c->frame); + client_hide(c); + } + } + + event_ignore_all_queued_enters(); + + if (event_curtime != CurrentTime) + screen_desktop_user_time = event_curtime; +} + +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; +} + +void screen_desktop_popup(guint d, gboolean show) +{ + Rect *a; + + if (!show) { + pager_popup_hide(desktop_cycle_popup); + } else { + a = screen_physical_area_monitor(0); + 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); + } +} + +guint screen_cycle_desktop(ObDirection dir, gboolean wrap, gboolean linear, + gboolean dialog, gboolean done, gboolean cancel) +{ + 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; + + oldd = d; + 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; + break; + case OB_DIRECTION_WEST: + if (d > 0) + --d; + else if (wrap) + d = screen_num_desktops - 1; + break; + default: + assert(0); + return screen_desktop; + } + } else { + switch (dir) { + case OB_DIRECTION_EAST: + ++c; + if (c >= screen_desktop_layout.columns) { + if (wrap) + c = 0; + else + goto show_cycle_dialog; + } + d = translate_row_col(r, c); + if (d >= screen_num_desktops) { + if (wrap) { + ++c; + } else { + d = oldd; + goto show_cycle_dialog; + } + } + break; + case OB_DIRECTION_WEST: + --c; + if (c >= screen_desktop_layout.columns) { + if (wrap) + c = screen_desktop_layout.columns - 1; + else + goto show_cycle_dialog; + } + d = translate_row_col(r, c); + if (d >= screen_num_desktops) { + if (wrap) { + --c; + } else { + d = oldd; + goto show_cycle_dialog; + } + } + break; + case OB_DIRECTION_SOUTH: + ++r; + if (r >= screen_desktop_layout.rows) { + if (wrap) + r = 0; + else + goto show_cycle_dialog; + } + d = translate_row_col(r, c); + if (d >= screen_num_desktops) { + if (wrap) { + ++r; + } else { + d = oldd; + goto show_cycle_dialog; + } + } + break; + case OB_DIRECTION_NORTH: + --r; + if (r >= screen_desktop_layout.rows) { + if (wrap) + r = screen_desktop_layout.rows - 1; + else + goto show_cycle_dialog; + } + d = translate_row_col(r, c); + if (d >= screen_num_desktops) { + if (wrap) { + --r; + } else { + d = oldd; + goto show_cycle_dialog; + } + } + break; + default: + assert(0); + return d = screen_desktop; } + + d = translate_row_col(r, c); } - /* focus the last focused window on the desktop, and ignore enter events - from the switch so it doesnt mess with the focus */ - while (XCheckTypedEvent(ob_display, EnterNotify, &e)); - g_message("switch fallback"); - focus_fallback(Fallback_Desktop); - g_message("/switch fallback"); +show_cycle_dialog: + if (dialog && !cancel && !done) { + screen_desktop_popup(d, TRUE); + } else + screen_desktop_popup(0, FALSE); + ret = d; - dispatch_ob(Event_Ob_Desktop, num, old); + 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 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() + { - ObOrientation orient; - ObCorner corner; - guint rows; - guint cols; + ObDesktopLayout l; guint32 *data; guint num; - gboolean valid = FALSE; - if (PROP_GETA32(ob_root, net_desktop_layout, cardinal, &data, &num)) { - if (num == 3 || num == 4) { + screen_desktop_layout.orientation = OB_ORIENTATION_HORZ; + screen_desktop_layout.start_corner = OB_CORNER_TOPLEFT; + screen_desktop_layout.rows = 1; + screen_desktop_layout.columns = screen_num_desktops; + 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) - orient = OB_ORIENTATION_VERT; + l.orientation = OB_ORIENTATION_VERT; else if (data[0] == prop_atoms.net_wm_orientation_horz) - orient = OB_ORIENTATION_HORZ; + l.orientation = OB_ORIENTATION_HORZ; else - goto screen_update_layout_bail; + return; if (num < 4) - corner = OB_CORNER_TOPLEFT; + l.start_corner = OB_CORNER_TOPLEFT; else { - if (data[3] == prop_atoms.net_wm_topright) - corner = OB_CORNER_TOPRIGHT; + if (data[3] == prop_atoms.net_wm_topleft) + l.start_corner = OB_CORNER_TOPLEFT; + else if (data[3] == prop_atoms.net_wm_topright) + l.start_corner = OB_CORNER_TOPRIGHT; else if (data[3] == prop_atoms.net_wm_bottomright) - corner = OB_CORNER_BOTTOMRIGHT; + l.start_corner = OB_CORNER_BOTTOMRIGHT; else if (data[3] == prop_atoms.net_wm_bottomleft) - corner = OB_CORNER_BOTTOMLEFT; + l.start_corner = OB_CORNER_BOTTOMLEFT; else - goto screen_update_layout_bail; + return; } - /* fill in a zero rows/columns */ - if ((data[1] == 0 && data[2] == 0) || /* both 0's is bad data.. */ - (data[1] != 0 && data[2] != 0)) { /* no 0's is bad data.. */ - goto screen_update_layout_bail; - } else { - if (data[1] == 0) { - data[1] = (screen_num_desktops + - screen_num_desktops % data[2]) / data[2]; - } else if (data[2] == 0) { - data[2] = (screen_num_desktops + - screen_num_desktops % data[1]) / data[1]; - } - cols = data[1]; - rows = data[2]; - } + l.columns = data[1]; + l.rows = data[2]; - /* bounds checking */ - if (orient == OB_ORIENTATION_HORZ) { - rows = MIN(rows, screen_num_desktops); - cols = MIN(cols, ((screen_num_desktops + - (screen_num_desktops % rows)) / rows)); - } else { - cols = MIN(cols, screen_num_desktops); - rows = MIN(rows, ((screen_num_desktops + - (screen_num_desktops % cols)) / cols)); - } + if (screen_validate_layout(&l)) + screen_desktop_layout = l; - valid = TRUE; + g_free(data); } - screen_update_layout_bail: - g_free(data); - } - - if (!valid) { - /* defaults */ - orient = OB_ORIENTATION_HORZ; - corner = OB_CORNER_TOPLEFT; - rows = 1; - cols = screen_num_desktops; } - - screen_desktop_layout.orientation = orient; - screen_desktop_layout.start_corner = corner; - screen_desktop_layout.rows = rows; - screen_desktop_layout.columns = cols; } void screen_update_desktop_names() @@ -441,20 +964,44 @@ void screen_update_desktop_names() g_strfreev(screen_desktop_names); screen_desktop_names = NULL; - if (PROP_GETSS(ob_root, net_desktop_names, utf8, &screen_desktop_names)) - for (i = 0; screen_desktop_names[i] && i <= screen_num_desktops; ++i); + if (PROP_GETSS(RootWindow(ob_display, ob_screen), + net_desktop_names, utf8, &screen_desktop_names)) + for (i = 0; screen_desktop_names[i] && i < screen_num_desktops; ++i); else i = 0; - if (i <= screen_num_desktops) { - screen_desktop_names = g_renew(char*, screen_desktop_names, + if (i < screen_num_desktops) { + GSList *it; + + screen_desktop_names = g_renew(gchar*, screen_desktop_names, screen_num_desktops + 1); screen_desktop_names[screen_num_desktops] = NULL; - for (; i < screen_num_desktops; ++i) - screen_desktop_names[i] = g_strdup("Unnamed Desktop"); + + it = g_slist_nth(config_desktops_names, i); + + for (; i < screen_num_desktops; ++i) { + if (it && ((char*)it->data)[0]) /* not empty */ + /* use the names from the config file when possible */ + screen_desktop_names[i] = g_strdup(it->data); + else + /* make up a nice name if it's not though */ + screen_desktop_names[i] = g_strdup_printf(_("desktop %i"), + i + 1); + if (it) it = g_slist_next(it); + } + + /* if we changed any names, then set the root property so we can + all agree on the names */ + PROP_SETSS(RootWindow(ob_display, ob_screen), net_desktop_names, + screen_desktop_names); } + + /* resize the pager for these names */ + pager_popup_text_width_to_strings(desktop_cycle_popup, + screen_desktop_names, + screen_num_desktops); } -void screen_show_desktop(gboolean show) +void screen_show_desktop(gboolean show, ObClient *show_only) { GList *it; @@ -463,70 +1010,126 @@ void screen_show_desktop(gboolean show) screen_showing_desktop = show; if (show) { - /* bottom to top */ - for (it = g_list_last(stacking_list); it != NULL; it = it->prev) { + /* hide windows bottom to top */ + for (it = g_list_last(stacking_list); it; it = g_list_previous(it)) { if (WINDOW_IS_CLIENT(it->data)) { ObClient *client = it->data; - if (client->frame->visible && !client_should_show(client)) - frame_hide(client->frame); + client_showhide(client); } - } - } else { - /* top to bottom */ - for (it = stacking_list; it != NULL; it = it->next) { + } + } + else { + /* restore windows top to bottom */ + for (it = stacking_list; it; it = g_list_next(it)) { if (WINDOW_IS_CLIENT(it->data)) { ObClient *client = it->data; - if (!client->frame->visible && client_should_show(client)) - frame_show(client->frame); + if (client_should_show(client)) { + if (!show_only || client == show_only) + client_show(client); + else + client_iconify(client, TRUE, FALSE, TRUE); + } } - } + } } if (show) { - /* focus desktop */ - for (it = focus_order[screen_desktop]; it; it = it->next) - if (((ObClient*)it->data)->type == OB_CLIENT_TYPE_DESKTOP && + /* focus the desktop */ + for (it = focus_order; it; it = g_list_next(it)) { + ObClient *c = it->data; + if (c->type == OB_CLIENT_TYPE_DESKTOP && + (c->desktop == screen_desktop || c->desktop == DESKTOP_ALL) && client_focus(it->data)) break; - } else { - focus_fallback(Fallback_NoFocus); + } + } + else if (!show_only) { + ObClient *c; + + if ((c = focus_fallback(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.. */ + if (c->can_focus) { + /* reduce flicker by hiliting now rather than waiting for the + server FocusIn event */ + frame_adjust_focus(c->frame, TRUE); + } + } } show = !!show; /* make it boolean */ - PROP_SET32(ob_root, net_showing_desktop, cardinal, show); - - dispatch_ob(Event_Ob_ShowDesktop, show, 0); + PROP_SET32(RootWindow(ob_display, ob_screen), + net_showing_desktop, cardinal, show); } void screen_install_colormap(ObClient *client, gboolean install) { - XWindowAttributes wa; - - if (client == NULL) { - if (install) - XInstallColormap(RrDisplay(ob_rr_inst), RrColormap(ob_rr_inst)); - else - XUninstallColormap(RrDisplay(ob_rr_inst), RrColormap(ob_rr_inst)); + if (client == NULL || client->colormap == None) { + if (install) + XInstallColormap(RrDisplay(ob_rr_inst), RrColormap(ob_rr_inst)); + else + XUninstallColormap(RrDisplay(ob_rr_inst), RrColormap(ob_rr_inst)); } else { - if (XGetWindowAttributes(ob_display, client->window, &wa) && - wa.colormap != None) { - xerror_set_ignore(TRUE); - if (install) - XInstallColormap(RrDisplay(ob_rr_inst), wa.colormap); - else - XUninstallColormap(RrDisplay(ob_rr_inst), wa.colormap); - xerror_set_ignore(FALSE); - } + xerror_set_ignore(TRUE); + if (install) + XInstallColormap(RrDisplay(ob_rr_inst), client->colormap); + else + XUninstallColormap(RrDisplay(ob_rr_inst), client->colormap); + xerror_set_ignore(FALSE); } } +static inline void +screen_area_add_strut_left(const StrutPartial *s, const Rect *monitor_area, + gint edge, Strut *ret) +{ + if (s->left && + ((s->left_end <= s->left_start) || + (RECT_TOP(*monitor_area) < s->left_end && + RECT_BOTTOM(*monitor_area) > s->left_start))) + ret->left = MAX(ret->left, edge); +} + +static inline void +screen_area_add_strut_top(const StrutPartial *s, const Rect *monitor_area, + gint edge, Strut *ret) +{ + if (s->top && + ((s->top_end <= s->top_start) || + (RECT_LEFT(*monitor_area) < s->top_end && + RECT_RIGHT(*monitor_area) > s->top_start))) + ret->top = MAX(ret->top, edge); +} + +static inline void +screen_area_add_strut_right(const StrutPartial *s, const Rect *monitor_area, + gint edge, Strut *ret) +{ + if (s->right && + ((s->right_end <= s->right_start) || + (RECT_TOP(*monitor_area) < s->right_end && + RECT_BOTTOM(*monitor_area) > s->right_start))) + ret->right = MAX(ret->right, edge); +} + +static inline void +screen_area_add_strut_bottom(const StrutPartial *s, const Rect *monitor_area, + gint edge, Strut *ret) +{ + if (s->bottom && + ((s->bottom_end <= s->bottom_start) || + (RECT_LEFT(*monitor_area) < s->bottom_end && + RECT_RIGHT(*monitor_area) > s->bottom_start))) + ret->bottom = MAX(ret->bottom, edge); +} + void screen_update_areas() { guint i, x; - guint32 *dims; - Rect **old_area = area; - Rect **rit; + gulong *dims; GList *it; + gint o; g_free(monitor_area); extensions_xinerama_screens(&monitor_area, &screen_num_monitors); @@ -539,15 +1142,16 @@ void screen_update_areas() area = g_new(Rect*, screen_num_desktops + 2); for (i = 0; i < screen_num_desktops + 1; ++i) - area[i] = g_new(Rect, screen_num_monitors + 1); + area[i] = g_new0(Rect, screen_num_monitors + 1); area[i] = NULL; - dims = g_new(guint32, 4 * screen_num_desktops); + dims = g_new(gulong, 4 * screen_num_desktops); - rit = old_area; for (i = 0; i < screen_num_desktops + 1; ++i) { - Strut s; - int l, r, t, b; + Strut *struts; + gint l, r, t, b; + + struts = g_new0(Strut, screen_num_monitors); /* calc the xinerama areas */ for (x = 0; x < screen_num_monitors; ++x) { @@ -566,111 +1170,120 @@ void screen_update_areas() } RECT_SET(area[i][x], l, t, r - l + 1, b - t + 1); - /* apply struts */ - STRUT_SET(s, 0, 0, 0, 0); - for (it = client_list; it; it = it->next) - STRUT_ADD(s, ((ObClient*)it->data)->strut); - STRUT_ADD(s, dock_strut); - - if (s.left) { - int o; - - /* find the left-most xin heads, i do this in 2 loops :| */ - o = area[i][0].x; - for (x = 1; x < screen_num_monitors; ++x) - o = MIN(o, area[i][x].x); - - for (x = 0; x < screen_num_monitors; ++x) { - int edge = o + s.left - area[i][x].x; - if (edge > 0) { - area[i][x].x += edge; - area[i][x].width -= edge; - } - } + /* apply the struts */ - area[i][screen_num_monitors].x += s.left; - area[i][screen_num_monitors].width -= s.left; - } - if (s.top) { - int o; - - /* find the left-most xin heads, i do this in 2 loops :| */ - o = area[i][0].y; - for (x = 1; x < screen_num_monitors; ++x) - o = MIN(o, area[i][x].y); - - for (x = 0; x < screen_num_monitors; ++x) { - int edge = o + s.top - area[i][x].y; - if (edge > 0) { - area[i][x].y += edge; - area[i][x].height -= edge; - } - } + /* find the left-most xin heads, i do this in 2 loops :| */ + o = area[i][0].x; + for (x = 1; x < screen_num_monitors; ++x) + o = MIN(o, area[i][x].x); - area[i][screen_num_monitors].y += s.top; - area[i][screen_num_monitors].height -= s.top; - } - if (s.right) { - int o; - - /* find the bottom-most xin heads, i do this in 2 loops :| */ - o = area[i][0].x + area[i][0].width - 1; - for (x = 1; x < screen_num_monitors; ++x) - o = MAX(o, area[i][x].x + area[i][x].width - 1); - - for (x = 0; x < screen_num_monitors; ++x) { - int edge = (area[i][x].x + area[i][x].width - 1) - - (o - s.right); - if (edge > 0) - area[i][x].width -= edge; + for (x = 0; x < screen_num_monitors; ++x) { + for (it = client_list; it; it = g_list_next(it)) { + ObClient *c = it->data; + screen_area_add_strut_left(&c->strut, + &monitor_area[x], + o + c->strut.left - area[i][x].x, + &struts[x]); } + screen_area_add_strut_left(&dock_strut, + &monitor_area[x], + o + dock_strut.left - area[i][x].x, + &struts[x]); - area[i][screen_num_monitors].width -= s.right; + area[i][x].x += struts[x].left; + area[i][x].width -= struts[x].left; } - if (s.bottom) { - int o; - - /* find the bottom-most xin heads, i do this in 2 loops :| */ - o = area[i][0].y + area[i][0].height - 1; - for (x = 1; x < screen_num_monitors; ++x) - o = MAX(o, area[i][x].y + area[i][x].height - 1); - - for (x = 0; x < screen_num_monitors; ++x) { - int edge = (area[i][x].y + area[i][x].height - 1) - - (o - s.bottom); - if (edge > 0) - area[i][x].height -= edge; - } - area[i][screen_num_monitors].height -= s.bottom; - } + /* find the top-most xin heads, i do this in 2 loops :| */ + o = area[i][0].y; + for (x = 1; x < screen_num_monitors; ++x) + o = MIN(o, area[i][x].y); - /* XXX when dealing with partial struts, if its in a single - xinerama area, then only subtract it from that area's space for (x = 0; x < screen_num_monitors; ++x) { - GList *it; - + for (it = client_list; it; it = g_list_next(it)) { + ObClient *c = it->data; + screen_area_add_strut_top(&c->strut, + &monitor_area[x], + o + c->strut.top - area[i][x].y, + &struts[x]); + } + screen_area_add_strut_top(&dock_strut, + &monitor_area[x], + o + dock_strut.top - area[i][x].y, + &struts[x]); - do something smart with it for the 'all xinerama areas' one... + area[i][x].y += struts[x].top; + area[i][x].height -= struts[x].top; + } - for (it = client_list; it; it = it->next) { + /* find the right-most xin heads, i do this in 2 loops :| */ + o = area[i][0].x + area[i][0].width - 1; + for (x = 1; x < screen_num_monitors; ++x) + o = MAX(o, area[i][x].x + area[i][x].width - 1); - XXX if gunna test this shit, then gotta worry about when - the client moves between xinerama heads.. + for (x = 0; x < screen_num_monitors; ++x) { + for (it = client_list; it; it = g_list_next(it)) { + ObClient *c = it->data; + screen_area_add_strut_right(&c->strut, + &monitor_area[x], + (area[i][x].x + + area[i][x].width - 1) - + (o - c->strut.right), + &struts[x]); + } + screen_area_add_strut_right(&dock_strut, + &monitor_area[x], + (area[i][x].x + + area[i][x].width - 1) - + (o - dock_strut.right), + &struts[x]); + + area[i][x].width -= struts[x].right; + } - if (RECT_CONTAINS_RECT(((ObClient*)it->data)->frame->area, - area[i][x])) { + /* find the bottom-most xin heads, i do this in 2 loops :| */ + o = area[i][0].y + area[i][0].height - 1; + for (x = 1; x < screen_num_monitors; ++x) + o = MAX(o, area[i][x].y + area[i][x].height - 1); - } + for (x = 0; x < screen_num_monitors; ++x) { + for (it = client_list; it; it = g_list_next(it)) { + ObClient *c = it->data; + screen_area_add_strut_bottom(&c->strut, + &monitor_area[x], + (area[i][x].y + + area[i][x].height - 1) - \ + (o - c->strut.bottom), + &struts[x]); } + screen_area_add_strut_bottom(&dock_strut, + &monitor_area[x], + (area[i][x].y + + area[i][x].height - 1) - \ + (o - dock_strut.bottom), + &struts[x]); + + area[i][x].height -= struts[x].bottom; + } + + l = RECT_LEFT(area[i][0]); + t = RECT_TOP(area[i][0]); + r = RECT_RIGHT(area[i][0]); + b = RECT_BOTTOM(area[i][0]); + for (x = 1; x < screen_num_monitors; ++x) { + l = MIN(l, RECT_LEFT(area[i][x])); + t = MIN(l, RECT_TOP(area[i][x])); + r = MAX(r, RECT_RIGHT(area[i][x])); + b = MAX(b, RECT_BOTTOM(area[i][x])); } - */ + RECT_SET(area[i][screen_num_monitors], l, t, + r - l + 1, b - t + 1); /* XXX optimize when this is run? */ /* the area has changed, adjust all the maximized windows */ - for (it = client_list; it; it = it->next) { + for (it = client_list; it; it = g_list_next(it)) { ObClient *c = it->data; if (i < screen_num_desktops) { if (c->desktop == i) @@ -685,9 +1298,12 @@ void screen_update_areas() dims[(i * 4) + 2] = area[i][screen_num_monitors].width; dims[(i * 4) + 3] = area[i][screen_num_monitors].height; } + + g_free(struts); } - PROP_SETA32(ob_root, net_workarea, cardinal, - dims, 4 * screen_num_desktops); + + PROP_SETA32(RootWindow(ob_display, ob_screen), net_workarea, cardinal, + dims, 4 * screen_num_desktops); g_free(dims); } @@ -702,13 +1318,37 @@ Rect *screen_area_monitor(guint desktop, guint head) if (head > screen_num_monitors) return NULL; if (desktop >= screen_num_desktops) { - if (desktop == DESKTOP_ALL) - return &area[screen_num_desktops][head]; - return NULL; + if (desktop == DESKTOP_ALL) + return &area[screen_num_desktops][head]; + return NULL; } return &area[desktop][head]; } +guint screen_find_monitor(Rect *search) +{ + guint i; + guint most = 0; + guint mostv = 0; + + for (i = 0; i < screen_num_monitors; ++i) { + Rect *area = screen_physical_area_monitor(i); + if (RECT_INTERSECTS_RECT(*area, *search)) { + Rect r; + guint v; + + RECT_SET_INTERSECTION(r, *area, *search); + v = r.width * r.height; + + if (v > mostv) { + mostv = v; + most = i; + } + } + } + return most; +} + Rect *screen_physical_area() { return screen_physical_area_monitor(screen_num_monitors); @@ -721,67 +1361,31 @@ Rect *screen_physical_area_monitor(guint head) return &monitor_area[head]; } -static void set_root_cursor() +void screen_set_root_cursor() { -#ifdef USE_LIBSN - if (sn_busy_cnt) - XDefineCursor(ob_display, ob_root, ob_cursor(OB_CURSOR_BUSY)); - else -#endif - XDefineCursor(ob_display, ob_root, ob_cursor(OB_CURSOR_POINTER)); -} - -#ifdef USE_LIBSN -static void sn_timeout(void *data) -{ - timer_stop(sn_timer); - sn_timer = NULL; - sn_busy_cnt = 0; - - set_root_cursor(); + if (sn_app_starting()) + XDefineCursor(ob_display, RootWindow(ob_display, ob_screen), + ob_cursor(OB_CURSOR_BUSYPOINTER)); + else + XDefineCursor(ob_display, RootWindow(ob_display, ob_screen), + ob_cursor(OB_CURSOR_POINTER)); } -static void sn_event_func(SnMonitorEvent *ev, void *data) +gboolean screen_pointer_pos(gint *x, gint *y) { - SnStartupSequence *seq; - const char *seq_id, *bin_name; - int cnt = sn_busy_cnt; - - if (!(seq = sn_monitor_event_get_startup_sequence(ev))) - return; - - seq_id = sn_startup_sequence_get_id(seq); - bin_name = sn_startup_sequence_get_binary_name(seq); - - if (!(seq_id && bin_name)) - return; - - switch (sn_monitor_event_get_type(ev)) { - case SN_MONITOR_EVENT_INITIATED: - ++sn_busy_cnt; - if (sn_timer) - timer_stop(sn_timer); - /* 30 second timeout for apps to start */ - sn_timer = timer_start(30 * 1000000, sn_timeout, NULL); - break; - case SN_MONITOR_EVENT_CHANGED: - break; - case SN_MONITOR_EVENT_COMPLETED: - if (sn_busy_cnt) --sn_busy_cnt; - if (sn_timer) { - timer_stop(sn_timer); - sn_timer = NULL; - } - break; - case SN_MONITOR_EVENT_CANCELED: - if (sn_busy_cnt) --sn_busy_cnt; - if (sn_timer) { - timer_stop(sn_timer); - sn_timer = NULL; - } - }; - - if (sn_busy_cnt != cnt) - set_root_cursor(); + Window w; + gint i; + guint u; + gboolean ret; + + ret = !!XQueryPointer(ob_display, RootWindow(ob_display, ob_screen), + &w, &w, x, y, &i, &i, &u); + if (!ret) { + for (i = 0; i < ScreenCount(ob_display); ++i) + if (i != ob_screen) + if (XQueryPointer(ob_display, RootWindow(ob_display, i), + &w, &w, x, y, &i, &i, &u)) + break; + } + return ret; } -#endif