X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=openbox%2Fscreen.c;h=3e3b9632d50ede9169864fb03a6a251b0c5aa0ef;hb=845833226b7d65019d41eb3afce6fad7ae3d30a2;hp=72363cdc74ee61f0bc9e41aebc51e80b005c0f36;hpb=322b2d0a05daf0c0c9de07baf5e27e4945f7bfd5;p=chaz%2Fopenbox diff --git a/openbox/screen.c b/openbox/screen.c index 72363cdc..3e3b9632 100644 --- a/openbox/screen.c +++ b/openbox/screen.c @@ -1,12 +1,22 @@ #include "openbox.h" +#include "dock.h" +#include "xerror.h" #include "prop.h" +#include "startup.h" +#include "timer.h" #include "config.h" #include "screen.h" #include "client.h" #include "frame.h" #include "focus.h" #include "dispatch.h" -#include "../render/render.h" +#include "extensions.h" +#include "render/render.h" + +#ifdef USE_LIBSN +# define SN_API_NOT_YET_FROZEN +# include +#endif #include #ifdef HAVE_UNISTD_H @@ -15,67 +25,171 @@ #endif /*! The event mask to grab on the root window */ -#define ROOT_EVENTMASK (/*ColormapChangeMask |*/ PropertyChangeMask | \ +#define ROOT_EVENTMASK (StructureNotifyMask | PropertyChangeMask | \ EnterWindowMask | LeaveWindowMask | \ SubstructureNotifyMask | SubstructureRedirectMask | \ ButtonPressMask | ButtonReleaseMask | ButtonMotionMask) -guint screen_num_desktops = 0; -guint screen_desktop = 0; +guint screen_num_desktops; +guint screen_num_monitors; +guint screen_desktop; Size screen_physical_size; gboolean screen_showing_desktop; DesktopLayout screen_desktop_layout; -char **screen_desktop_names = NULL; +char **screen_desktop_names; +Window screen_support_win; + +static Rect **area; /* array of desktop holding array of xinerama areas */ +static Rect *monitor_area; -static Rect *area = NULL; -static Strut *strut = NULL; -static Window support_window = None; +#ifdef USE_LIBSN +static SnMonitorContext *sn_context; +static int sn_busy_cnt; +static ObTimer *sn_timer; + +static void sn_event_func(SnMonitorEvent *event, void *data); +#endif -static void screen_update_area(); +static void set_root_cursor(); -static gboolean running; -static int another_running(Display *d, XErrorEvent *e) +static gboolean replace_wm() { - (void)d;(void)e; - g_message("A window manager is already running on screen %d", - ob_screen); - running = TRUE; - return -1; + char *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); + + current_wm_sn_owner = XGetSelectionOwner(ob_display, wm_sn_atom); + 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; + + /* We want to find out when the current selection owner dies */ + XSelectInput(ob_display, current_wm_sn_owner, StructureNotifyMask); + XSync(ob_display, FALSE); + + 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("Timeout expired while waiting for the current WM to die " + "on screen %d", 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, 0, 0, SubstructureNotifyMask); + + + return TRUE; } gboolean screen_annex() { - XErrorHandler old; + XSetWindowAttributes attrib; pid_t pid; - int i, num_support; + gint i, num_support; guint32 *supported; - running = FALSE; - old = XSetErrorHandler(another_running); - XSelectInput(ob_display, ob_root, ROOT_EVENTMASK); - XSync(ob_display, FALSE); - XSetErrorHandler(old); - if (running) + /* 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); + XMapRaised(ob_display, screen_support_win); + + if (!replace_wm()) { + XDestroyWindow(ob_display, screen_support_win); + return FALSE; + } + + 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; + } + g_message("Managing screen %d", ob_screen); - /* set the mouse cursor for the root window (the default cursor) */ - XDefineCursor(ob_display, ob_root, ob_cursors.ptr); + 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; @@ -147,7 +261,8 @@ gboolean screen_annex() 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); return TRUE; @@ -167,55 +282,81 @@ void screen_startup() 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); + PROP_SETSS(RootWindow(ob_display, ob_screen), + net_desktop_names, screen_desktop_names); g_free(screen_desktop_names); /* dont free the individual strings */ screen_desktop_names = NULL; screen_num_desktops = 0; screen_set_num_desktops(config_desktops_num); - screen_desktop = 0; - screen_set_desktop(0); + if (startup_desktop >= screen_num_desktops) + startup_desktop = 0; + screen_desktop = startup_desktop; + screen_set_desktop(startup_desktop); /* don't start in showing-desktop mode */ screen_showing_desktop = FALSE; - PROP_SET32(ob_root, net_showing_desktop, cardinal, screen_showing_desktop); + PROP_SET32(RootWindow(ob_display, ob_screen), + net_showing_desktop, cardinal, screen_showing_desktop); screen_update_layout(); + +#ifdef USE_LIBSN + sn_context = sn_monitor_context_new(ob_sn_display, ob_screen, + sn_event_func, NULL, NULL); + sn_busy_cnt = 0; +#endif } void screen_shutdown() { - XSelectInput(ob_display, ob_root, NoEventMask); + Rect **r; - 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 */ + 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); - g_free(strut); + for (r = area; *r; ++r) + g_free(*r); g_free(area); } void screen_resize() { - /* XXX RandR support here? */ + static int oldw = 0, oldh = 0; + int w, h; + GList *it; guint32 geometry[2]; + w = WidthOfScreen(ScreenOfDisplay(ob_display, ob_screen)); + h = HeightOfScreen(ScreenOfDisplay(ob_display, ob_screen)); + + if (w == oldw && h == oldh) return; + + oldw = w; oldh = h; + /* Set the _NET_DESKTOP_GEOMETRY hint */ - geometry[0] = WidthOfScreen(ScreenOfDisplay(ob_display, ob_screen)); - geometry[1] = HeightOfScreen(ScreenOfDisplay(ob_display, ob_screen)); - PROP_SETA32(ob_root, net_desktop_geometry, cardinal, geometry, 2); - screen_physical_size.width = geometry[0]; - screen_physical_size.height = geometry[1]; + screen_physical_size.width = geometry[0] = w; + screen_physical_size.height = geometry[1] = h; + PROP_SETA32(RootWindow(ob_display, ob_screen), + net_desktop_geometry, cardinal, geometry, 2); - if (ob_state == State_Starting) + if (ob_state() == OB_STATE_STARTING) return; - screen_update_struts(); + dock_configure(); + screen_update_areas(); - /* XXX adjust more stuff ? */ + for (it = client_list; it; it = it->next) + client_move_onscreen(it->data); } void screen_set_num_desktops(guint num) @@ -228,16 +369,15 @@ void screen_set_num_desktops(guint num) 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); + PROP_SETA32(RootWindow(ob_display, ob_screen), + net_desktop_viewport, cardinal, viewport, num * 2); g_free(viewport); - /* change our struts/area to match */ - screen_update_struts(); - /* the number of rows/columns will differ */ screen_update_layout(); @@ -256,11 +396,14 @@ void screen_set_num_desktops(guint num) /* move windows on desktops that will no longer exist! */ for (it = client_list; it != NULL; it = it->next) { - Client *c = it->data; - if (c->desktop >= num) + 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); /* change our desktop if we're on one that no longer exists! */ @@ -278,7 +421,8 @@ void screen_set_desktop(guint num) old = screen_desktop; screen_desktop = num; - PROP_SET32(ob_root, net_current_desktop, cardinal, num); + PROP_SET32(RootWindow(ob_display, ob_screen), + net_current_desktop, cardinal, num); if (old == num) return; @@ -288,56 +432,75 @@ void screen_set_desktop(guint num) /* show windows from top to bottom */ for (it = stacking_list; it != NULL; it = it->next) { - Client *c = it->data; - if (!c->frame->visible && client_should_show(c)) - frame_show(c->frame); + if (WINDOW_IS_CLIENT(it->data)) { + ObClient *c = it->data; + if (!c->frame->visible && client_should_show(c)) + frame_show(c->frame); + } } /* hide windows from bottom to top */ for (it = g_list_last(stacking_list); it != NULL; it = it->prev) { - Client *c = it->data; - if (c->frame->visible && !client_should_show(c)) - frame_hide(c->frame); + if (WINDOW_IS_CLIENT(it->data)) { + ObClient *c = it->data; + if (c->frame->visible && !client_should_show(c)) + frame_hide(c->frame); + } } /* focus the last focused window on the desktop, and ignore enter events from the switch so it doesnt mess with the focus */ - XSync(ob_display, FALSE); while (XCheckTypedEvent(ob_display, EnterNotify, &e)); - focus_fallback(Fallback_Desktop); +#ifdef DEBUG_FOCUS + g_message("switch fallback"); +#endif + focus_fallback(OB_FOCUS_FALLBACK_DESKTOP); +#ifdef DEBUG_FOCUS + g_message("/switch fallback"); +#endif dispatch_ob(Event_Ob_Desktop, num, old); } void screen_update_layout() { - guint32 *data = NULL; + ObOrientation orient; + ObCorner corner; + guint rows; + guint cols; + guint32 *data; guint num; + gboolean valid = FALSE; - /* defaults */ - screen_desktop_layout.orientation = prop_atoms.net_wm_orientation_horz; - screen_desktop_layout.start_corner = prop_atoms.net_wm_topleft; - screen_desktop_layout.rows = 1; - screen_desktop_layout.columns = screen_num_desktops; - - if (PROP_GETA32(ob_root, net_desktop_layout, cardinal, &data, &num)) { + 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) - screen_desktop_layout.orientation = data[0]; - if (num == 3) - screen_desktop_layout.start_corner = - prop_atoms.net_wm_topright; + orient = OB_ORIENTATION_VERT; + else if (data[0] == prop_atoms.net_wm_orientation_horz) + orient = OB_ORIENTATION_HORZ; + else + goto screen_update_layout_bail; + + if (num < 4) + corner = OB_CORNER_TOPLEFT; else { if (data[3] == prop_atoms.net_wm_topright) - screen_desktop_layout.start_corner = data[3]; + corner = OB_CORNER_TOPRIGHT; else if (data[3] == prop_atoms.net_wm_bottomright) - screen_desktop_layout.start_corner = data[3]; + corner = OB_CORNER_BOTTOMRIGHT; else if (data[3] == prop_atoms.net_wm_bottomleft) - screen_desktop_layout.start_corner = data[3]; + corner = OB_CORNER_BOTTOMLEFT; + else + goto screen_update_layout_bail; } /* fill in a zero rows/columns */ - if (!(data[1] == 0 && data[2] == 0)) { /* both 0's is bad data.. */ + 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]; @@ -345,38 +508,39 @@ void screen_update_layout() data[2] = (screen_num_desktops + screen_num_desktops % data[1]) / data[1]; } - screen_desktop_layout.columns = data[1]; - screen_desktop_layout.rows = data[2]; + cols = data[1]; + rows = data[2]; } /* bounds checking */ - if (screen_desktop_layout.orientation == - prop_atoms.net_wm_orientation_horz) { - if (screen_desktop_layout.rows > screen_num_desktops) - screen_desktop_layout.rows = screen_num_desktops; - if (screen_desktop_layout.columns > - ((screen_num_desktops + screen_num_desktops % - screen_desktop_layout.rows) / - screen_desktop_layout.rows)) - screen_desktop_layout.columns = - (screen_num_desktops + screen_num_desktops % - screen_desktop_layout.rows) / - screen_desktop_layout.rows; + if (orient == OB_ORIENTATION_HORZ) { + rows = MIN(rows, screen_num_desktops); + cols = MIN(cols, ((screen_num_desktops + + (screen_num_desktops % rows)) / rows)); } else { - if (screen_desktop_layout.columns > screen_num_desktops) - screen_desktop_layout.columns = screen_num_desktops; - if (screen_desktop_layout.rows > - ((screen_num_desktops + screen_num_desktops % - screen_desktop_layout.columns) / - screen_desktop_layout.columns)) - screen_desktop_layout.rows = - (screen_num_desktops + screen_num_desktops % - screen_desktop_layout.columns) / - screen_desktop_layout.columns; + cols = MIN(cols, screen_num_desktops); + rows = MIN(rows, ((screen_num_desktops + + (screen_num_desktops % cols)) / cols)); } + + 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() @@ -387,7 +551,8 @@ 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)) + 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; @@ -411,172 +576,336 @@ void screen_show_desktop(gboolean show) if (show) { /* bottom to top */ for (it = g_list_last(stacking_list); it != NULL; it = it->prev) { - Client *client = it->data; - if (client->frame->visible && !client_should_show(client)) - frame_hide(client->frame); + if (WINDOW_IS_CLIENT(it->data)) { + ObClient *client = it->data; + if (client->frame->visible && !client_should_show(client)) + frame_hide(client->frame); + } } } else { /* top to bottom */ for (it = stacking_list; it != NULL; it = it->next) { - Client *client = it->data; - if (!client->frame->visible && client_should_show(client)) - frame_show(client->frame); + if (WINDOW_IS_CLIENT(it->data)) { + ObClient *client = it->data; + if (!client->frame->visible && client_should_show(client)) + frame_show(client->frame); + } } } if (show) { /* focus desktop */ for (it = focus_order[screen_desktop]; it; it = it->next) - if (((Client*)it->data)->type == Type_Desktop && + if (((ObClient*)it->data)->type == OB_CLIENT_TYPE_DESKTOP && client_focus(it->data)) break; } else { - focus_fallback(Fallback_NoFocus); + focus_fallback(OB_FOCUS_FALLBACK_NOFOCUS); } show = !!show; /* make it boolean */ - PROP_SET32(ob_root, net_showing_desktop, cardinal, show); + PROP_SET32(RootWindow(ob_display, ob_screen), + net_showing_desktop, cardinal, show); dispatch_ob(Event_Ob_ShowDesktop, show, 0); } -void screen_install_colormap(Client *client, gboolean install) +void screen_install_colormap(ObClient *client, gboolean install) { XWindowAttributes wa; if (client == NULL) { if (install) - XInstallColormap(ob_display, render_colormap); + XInstallColormap(RrDisplay(ob_rr_inst), RrColormap(ob_rr_inst)); else - XUninstallColormap(ob_display, render_colormap); + 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(ob_display, wa.colormap); + XInstallColormap(RrDisplay(ob_rr_inst), wa.colormap); else - XUninstallColormap(ob_display, wa.colormap); + XUninstallColormap(RrDisplay(ob_rr_inst), wa.colormap); + xerror_set_ignore(FALSE); } } } -void screen_update_struts() +void screen_update_areas() { + guint i, x; + guint32 *dims; + Rect **old_area = area; + Rect **rit; GList *it; - guint i; - - g_free(strut); - strut = g_new0(Strut, screen_num_desktops + 1); - for (it = client_list; it != NULL; it = it->next) { - Client *c = it->data; - if (c->iconic) continue; /* these dont count in the strut */ - - if (c->desktop == 0xffffffff) { - for (i = 0; i < screen_num_desktops; ++i) - STRUT_ADD(strut[i], c->strut); - } else { - g_assert(c->desktop < screen_num_desktops); - STRUT_ADD(strut[c->desktop], c->strut); - } - /* apply to the 'all desktops' strut */ - STRUT_ADD(strut[screen_num_desktops], c->strut); - } - screen_update_area(); -} + g_free(monitor_area); + extensions_xinerama_screens(&monitor_area, &screen_num_monitors); -static void screen_update_area() -{ - guint i; - guint32 *dims; + if (area) { + for (i = 0; area[i]; ++i) + g_free(area[i]); + g_free(area); + } - g_free(area); - area = g_new0(Rect, screen_num_desktops + 1); + 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] = NULL; dims = g_new(guint32, 4 * screen_num_desktops); + + rit = old_area; for (i = 0; i < screen_num_desktops + 1; ++i) { - Rect old_area = area[i]; -/* - #ifdef XINERAMA - // reset to the full areas - if (isXineramaActive()) - xineramaUsableArea = getXineramaAreas(); - #endif // XINERAMA -*/ + Strut s; + int l, r, t, b; + + /* calc the xinerama areas */ + for (x = 0; x < screen_num_monitors; ++x) { + area[i][x] = monitor_area[x]; + if (x == 0) { + l = monitor_area[x].x; + t = monitor_area[x].y; + r = monitor_area[x].x + monitor_area[x].width - 1; + b = monitor_area[x].y + monitor_area[x].height - 1; + } else { + l = MIN(l, monitor_area[x].x); + t = MIN(t, monitor_area[x].y); + r = MAX(r, monitor_area[x].x + monitor_area[x].width - 1); + b = MAX(b, monitor_area[x].y + monitor_area[x].height - 1); + } + } + 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; + } + } - RECT_SET(area[i], strut[i].left, strut[i].top, - screen_physical_size.width - (strut[i].left + - strut[i].right), - screen_physical_size.height - (strut[i].top + - strut[i].bottom)); - -/* - #ifdef XINERAMA - if (isXineramaActive()) { - // keep each of the ximerama-defined areas inside the strut - RectList::iterator xit, xend = xineramaUsableArea.end(); - for (xit = xineramaUsableArea.begin(); xit != xend; ++xit) { - if (xit->x() < usableArea.x()) { - xit->setX(usableArea.x()); - xit->setWidth(xit->width() - usableArea.x()); - } - if (xit->y() < usableArea.y()) { - xit->setY(usableArea.y()); - xit->setHeight(xit->height() - usableArea.y()); - } - if (xit->x() + xit->width() > usableArea.width()) - xit->setWidth(usableArea.width() - xit->x()); - if (xit->y() + xit->height() > usableArea.height()) - xit->setHeight(usableArea.height() - xit->y()); - } - } - #endif // XINERAMA -*/ - if (!RECT_EQUAL(old_area, area[i])) { - /* the area has changed, adjust all the maximized windows */ + 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; + } + } + + 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; + } + + area[i][screen_num_monitors].width -= s.right; + } + 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; + } + + /* 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; + + + do something smart with it for the 'all xinerama areas' one... + for (it = client_list; it; it = it->next) { - Client *c = it->data; - if (i < screen_num_desktops) { - if (c->desktop == i) - client_remaximize(c); - } else { - /* the 'all desktops' size */ - if (c->desktop == DESKTOP_ALL) - client_remaximize(c); - } - } - } - /* don't set these for the 'all desktops' area */ - if (i < screen_num_desktops) { - dims[(i * 4) + 0] = area[i].x; - dims[(i * 4) + 1] = area[i].y; - dims[(i * 4) + 2] = area[i].width; - dims[(i * 4) + 3] = area[i].height; - } + XXX if gunna test this shit, then gotta worry about when + the client moves between xinerama heads.. + + if (RECT_CONTAINS_RECT(((ObClient*)it->data)->frame->area, + area[i][x])) { + + } + } + } + */ + + /* XXX optimize when this is run? */ + + /* the area has changed, adjust all the maximized + windows */ + for (it = client_list; it; it = it->next) { + ObClient *c = it->data; + if (i < screen_num_desktops) { + if (c->desktop == i) + client_reconfigure(c); + } else if (c->desktop == DESKTOP_ALL) + client_reconfigure(c); + } + if (i < screen_num_desktops) { + /* don't set these for the 'all desktops' area */ + dims[(i * 4) + 0] = area[i][screen_num_monitors].x; + dims[(i * 4) + 1] = area[i][screen_num_monitors].y; + dims[(i * 4) + 2] = area[i][screen_num_monitors].width; + dims[(i * 4) + 3] = area[i][screen_num_monitors].height; + } } - PROP_SETA32(ob_root, net_workarea, cardinal, + PROP_SETA32(RootWindow(ob_display, ob_screen), net_workarea, cardinal, dims, 4 * screen_num_desktops); + g_free(dims); } Rect *screen_area(guint desktop) { - if (desktop >= screen_num_desktops) { - if (desktop == DESKTOP_ALL) - return &area[screen_num_desktops]; - return NULL; - } - return &area[desktop]; + return screen_area_monitor(desktop, screen_num_monitors); } -Strut *screen_strut(guint desktop) +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 &strut[screen_num_desktops]; + return &area[screen_num_desktops][head]; return NULL; } - return &strut[desktop]; + return &area[desktop][head]; +} + +Rect *screen_physical_area() +{ + return screen_physical_area_monitor(screen_num_monitors); +} + +Rect *screen_physical_area_monitor(guint head) +{ + if (head > screen_num_monitors) + return NULL; + return &monitor_area[head]; +} + +static void set_root_cursor() +{ +#ifdef USE_LIBSN + if (sn_busy_cnt) + XDefineCursor(ob_display, RootWindow(ob_display, ob_screen), + ob_cursor(OB_CURSOR_BUSY)); + else +#endif + XDefineCursor(ob_display, RootWindow(ob_display, ob_screen), + 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(); +} + +static void sn_event_func(SnMonitorEvent *ev, void *data) +{ + 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(); +} +#endif + +gboolean screen_pointer_pos(int *x, int *y) +{ + Window w; + int i; + guint u; + + return !!XQueryPointer(ob_display, RootWindow(ob_display, ob_screen), + &w, &w, x, y, &i, &i, &u); }