X-Git-Url: https://git.dogcows.com/gitweb?p=chaz%2Fopenbox;a=blobdiff_plain;f=openbox%2Fscreen.c;h=9295194e82048ee3b4548cd6c65661f5830a9939;hp=d69b2447cec1499a99c329a50112076675c53b55;hb=HEAD;hpb=64adc0eeba598cb1469b2140777fba30e3053f0e diff --git a/openbox/screen.c b/openbox/screen.c index d69b2447..9295194e 100644 --- a/openbox/screen.c +++ b/openbox/screen.c @@ -36,8 +36,8 @@ #include "obrender/render.h" #include "gettext.h" #include "obt/display.h" +#include "obt/xqueue.h" #include "obt/prop.h" -#include "obt/mainloop.h" #include #ifdef HAVE_UNISTD_H @@ -70,6 +70,7 @@ Time screen_desktop_user_time = CurrentTime; static Size screen_physical_size; static guint screen_old_desktop; static gboolean screen_desktop_timeout = TRUE; +static guint screen_desktop_timer = 0; /*! An array of desktops, holding an array of areas per monitor */ static Rect *monitor_area = NULL; /*! An array of desktops, holding an array of struts */ @@ -79,11 +80,12 @@ static GSList *struts_right = NULL; static GSList *struts_bottom = NULL; static ObPagerPopup *desktop_popup; +static guint desktop_popup_timer = 0; static gboolean desktop_popup_perm; /*! 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 +#define REMEMBER_LAST_DESKTOP_TIME 750 static gboolean replace_wm(void) { @@ -116,7 +118,7 @@ static gboolean replace_wm(void) current_wm_sn_owner = None; } - timestamp = event_get_server_time(); + timestamp = event_time(); XSetSelectionOwner(obt_display, wm_sn_atom, screen_support_win, timestamp); @@ -129,14 +131,16 @@ static gboolean replace_wm(void) /* 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 */ + ObtXQueueWindowType wt; + + wt.window = current_wm_sn_owner; + wt.type = DestroyNotify; while (wait < timeout) { - if (XCheckWindowEvent(obt_display, current_wm_sn_owner, - StructureNotifyMask, &event) && - event.type == DestroyNotify) + /* Checks the local queue and incoming events for this event */ + if (xqueue_exists_local(xqueue_match_window_type, &wt)) break; g_usleep(G_USEC_PER_SEC / 10); wait += G_USEC_PER_SEC / 10; @@ -202,7 +206,7 @@ gboolean screen_annex(void) NET_SUPPORTING_WM_CHECK, WINDOW, screen_support_win); /* set properties on the supporting window */ - OBT_PROP_SETS(screen_support_win, NET_WM_NAME, utf8, "Openbox"); + OBT_PROP_SETS(screen_support_win, NET_WM_NAME, "Openbox"); OBT_PROP_SET32(screen_support_win, NET_SUPPORTING_WM_CHECK, WINDOW, screen_support_win); @@ -245,6 +249,7 @@ gboolean screen_annex(void) supported[i++] = OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_DIALOG); supported[i++] = OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_NORMAL); supported[i++] = OBT_PROP_ATOM(NET_WM_ALLOWED_ACTIONS); + supported[i++] = OBT_PROP_ATOM(NET_WM_WINDOW_OPACITY); supported[i++] = OBT_PROP_ATOM(NET_WM_ACTION_MOVE); supported[i++] = OBT_PROP_ATOM(NET_WM_ACTION_RESIZE); supported[i++] = OBT_PROP_ATOM(NET_WM_ACTION_MINIMIZE); @@ -300,6 +305,8 @@ gboolean screen_annex(void) supported[i++] = OBT_PROP_ATOM(OB_APP_TITLE); supported[i++] = OBT_PROP_ATOM(OB_APP_NAME); supported[i++] = OBT_PROP_ATOM(OB_APP_CLASS); + supported[i++] = OBT_PROP_ATOM(OB_APP_GROUP_NAME); + supported[i++] = OBT_PROP_ATOM(OB_APP_GROUP_CLASS); supported[i++] = OBT_PROP_ATOM(OB_APP_TYPE); g_assert(i == num_support); @@ -307,7 +314,7 @@ gboolean screen_annex(void) NET_SUPPORTED, ATOM, supported, num_support); g_free(supported); - OBT_PROP_SETS(RootWindow(obt_display, ob_screen), OB_VERSION, utf8, + OBT_PROP_SETS(RootWindow(obt_display, ob_screen), OB_VERSION, OPENBOX_VERSION); screen_tell_ksplash(); @@ -371,7 +378,7 @@ void screen_startup(gboolean reconfig) screen_resize(); /* have names already been set for the desktops? */ - if (OBT_PROP_GETSS(obt_root(ob_screen), NET_DESKTOP_NAMES, utf8, &names)) { + if (OBT_PROP_GETSS_UTF8(obt_root(ob_screen), NET_DESKTOP_NAMES, &names)) { g_strfreev(names); namesexist = TRUE; } @@ -393,7 +400,7 @@ void screen_startup(gboolean reconfig) /* set the root window property */ OBT_PROP_SETSS(obt_root(ob_screen), - NET_DESKTOP_NAMES, utf8, (const gchar**)names); + NET_DESKTOP_NAMES, (const gchar*const*)names); g_strfreev(names); } @@ -475,7 +482,6 @@ void screen_shutdown(gboolean reconfig) void screen_resize(void) { - static gint oldw = 0, oldh = 0; gint w, h; GList *it; gulong geometry[2]; @@ -483,10 +489,6 @@ void screen_resize(void) w = WidthOfScreen(ScreenOfDisplay(obt_display, ob_screen)); h = HeightOfScreen(ScreenOfDisplay(obt_display, ob_screen)); - if (w == oldw && h == oldh) return; - - oldw = w; oldh = h; - /* Set the _NET_DESKTOP_GEOMETRY hint */ screen_physical_size.width = geometry[0] = w; screen_physical_size.height = geometry[1] = h; @@ -496,11 +498,13 @@ void screen_resize(void) if (ob_state() != OB_STATE_RUNNING) return; - screen_update_areas(); + /* this calls screen_update_areas(), which we need ! */ dock_configure(); - for (it = client_list; it; it = g_list_next(it)) + for (it = client_list; it; it = g_list_next(it)) { client_move_onscreen(it->data, FALSE); + client_reconfigure(it->data, FALSE); + } } void screen_set_num_desktops(guint num) @@ -598,7 +602,8 @@ static void screen_fallback_focus(void) static gboolean last_desktop_func(gpointer data) { screen_desktop_timeout = TRUE; - return FALSE; + screen_desktop_timer = 0; + return FALSE; /* don't repeat */ } void screen_set_desktop(guint num, gboolean dofocus) @@ -680,9 +685,9 @@ void screen_set_desktop(guint num, gboolean dofocus) } } screen_desktop_timeout = FALSE; - obt_main_loop_timeout_remove(ob_main_loop, last_desktop_func); - obt_main_loop_timeout_add(ob_main_loop, REMEMBER_LAST_DESKTOP_TIME, - last_desktop_func, NULL, NULL, NULL); + if (screen_desktop_timer) g_source_remove(screen_desktop_timer); + screen_desktop_timer = g_timeout_add(REMEMBER_LAST_DESKTOP_TIME, + last_desktop_func, NULL); ob_debug("Moving to desktop %d", num+1); @@ -731,8 +736,8 @@ void screen_set_desktop(guint num, gboolean dofocus) event_end_ignore_all_enters(ignore_start); - if (event_curtime != CurrentTime) - screen_desktop_user_time = event_curtime; + if (event_source_time() != CurrentTime) + screen_desktop_user_time = event_source_time(); } void screen_add_desktop(gboolean current) @@ -934,12 +939,13 @@ static guint translate_row_col(guint r, guint c) static gboolean hide_desktop_popup_func(gpointer data) { pager_popup_hide(desktop_popup); + desktop_popup_timer = 0; return FALSE; /* don't repeat */ } void screen_show_desktop_popup(guint d, gboolean perm) { - Rect const *a; + const Rect *a; /* 0 means don't show the popup */ if (!config_desktop_popup_time) return; @@ -956,21 +962,21 @@ void screen_show_desktop_popup(guint d, gboolean perm) MAX(a->width/3, POPUP_WIDTH)); pager_popup_show(desktop_popup, screen_desktop_names[d], d); - obt_main_loop_timeout_remove(ob_main_loop, hide_desktop_popup_func); + if (desktop_popup_timer) g_source_remove(desktop_popup_timer); + desktop_popup_timer = 0; if (!perm && !desktop_popup_perm) /* only hide if its not already being show permanently */ - obt_main_loop_timeout_add(ob_main_loop, - config_desktop_popup_time * 1000, - hide_desktop_popup_func, desktop_popup, - g_direct_equal, NULL); + desktop_popup_timer = g_timeout_add(config_desktop_popup_time, + hide_desktop_popup_func, + desktop_popup); if (perm) desktop_popup_perm = TRUE; } void screen_hide_desktop_popup(void) { - obt_main_loop_timeout_remove_data(ob_main_loop, hide_desktop_popup_func, - desktop_popup, FALSE); + if (desktop_popup_timer) g_source_remove(desktop_popup_timer); + desktop_popup_timer = 0; pager_popup_hide(desktop_popup); desktop_popup_perm = FALSE; } @@ -1176,7 +1182,7 @@ void screen_update_desktop_names(void) screen_desktop_names = NULL; if (OBT_PROP_GETSS(obt_root(ob_screen), - NET_DESKTOP_NAMES, utf8, &screen_desktop_names)) + NET_DESKTOP_NAMES, &screen_desktop_names)) for (i = 0; screen_desktop_names[i] && i < screen_num_desktops; ++i); else i = 0; @@ -1203,7 +1209,7 @@ void screen_update_desktop_names(void) /* if we changed any names, then set the root property so we can all agree on the names */ OBT_PROP_SETSS(obt_root(ob_screen), NET_DESKTOP_NAMES, - utf8, (const gchar**)screen_desktop_names); + (const gchar*const*)screen_desktop_names); } /* resize the pager for these names */ @@ -1321,8 +1327,9 @@ typedef struct { static void get_xinerama_screens(Rect **xin_areas, guint *nxin) { guint i; - gint n, l, r, t, b; + gint l, r, t, b; #ifdef XINERAMA + gint n; XineramaScreenInfo *info; #endif @@ -1365,13 +1372,28 @@ static void get_xinerama_screens(Rect **xin_areas, guint *nxin) b = MAX(b, (*xin_areas)[i].y + (*xin_areas)[i].height - 1); } RECT_SET((*xin_areas)[*nxin], l, t, r - l + 1, b - t + 1); + + for (i = 0; i < *nxin; ++i) + ob_debug("Monitor %d @ %d,%d %dx%d\n", i, + (*xin_areas)[i].x, (*xin_areas)[i].y, + (*xin_areas)[i].width, (*xin_areas)[i].height); + ob_debug("Full desktop @ %d,%d %dx%d\n", + (*xin_areas)[i].x, (*xin_areas)[i].y, + (*xin_areas)[i].width, (*xin_areas)[i].height); } void screen_update_areas(void) { guint i; gulong *dims; - GList *it; + GList *it, *onscreen; + + /* collect the clients that are on screen */ + onscreen = NULL; + for (it = client_list; it; it = g_list_next(it)) { + if (client_monitor(it->data) != screen_num_monitors) + onscreen = g_list_prepend(onscreen, it->data); + } g_free(monitor_area); get_xinerama_screens(&monitor_area, &screen_num_monitors); @@ -1445,7 +1467,7 @@ void screen_update_areas(void) 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)) + for (it = onscreen; it; it = g_list_next(it)) client_reconfigure(it->data, FALSE); g_free(dims); @@ -1617,36 +1639,161 @@ Rect* screen_area(guint desktop, guint head, Rect *search) return a; } -guint screen_find_monitor(const Rect const *search) +typedef struct { + Rect r; + gboolean subtract; +} RectArithmetic; + +guint screen_find_monitor(const Rect *search) { guint i; - guint most = screen_num_monitors; - guint mostv = 0; + guint mostpx_index = screen_num_monitors; + guint mostpx = 0; + guint closest_distance_index = screen_num_monitors; + guint closest_distance = G_MAXUINT; + GSList *counted = NULL; + + /* we want to count the number of pixels search has on each monitor, but not + double count. so if a pixel is counted on monitor A then we should not + count it again on monitor B. in the end we want to return the monitor + that had the most pixels counted under this scheme. + + this assumes that monitors earlier in the list are more desirable to be + considered the search area's monitor. we try the configured primary + monitor first, so it gets the highest preference. + + if we have counted an area A, then we want to subtract the intersection + of A with the area on future monitors. + but now consider if we count an area B that intersects A. we want to + subtract the area B from that counted on future monitors, but not + subtract the intersection of A and B twice! so we would add the + intersection of A and B back, to account for it being subtracted both + for A and B. + + this is the idea behind the algorithm. we always subtract the full area + for monitor M intersected with the search area. we'll call that AREA. + but then we go through the list |counted| and for each rectangle in + the list that is being subtracted from future monitors, we insert a + request to add back the intersection of the subtracted rect with AREA. + vice versa for a rect in |counted| that is getting added back. + */ + + if (config_primary_monitor_index < screen_num_monitors) { + const Rect *monitor; + Rect on_current_monitor; + glong area; + + monitor = screen_physical_area_monitor(config_primary_monitor_index); + + if (RECT_INTERSECTS_RECT(*monitor, *search)) { + RECT_SET_INTERSECTION(on_current_monitor, *monitor, *search); + area = RECT_AREA(on_current_monitor); + + if (area > mostpx) { + mostpx = area; + mostpx_index = config_primary_monitor_index; + } + + /* add the intersection rect on the current monitor to the + counted list. that's easy for the first one, we just mark it for + subtraction */ + { + RectArithmetic *ra = g_slice_new(RectArithmetic); + ra->r = on_current_monitor; + ra->subtract = TRUE; + counted = g_slist_prepend(counted, ra); + } + } + } for (i = 0; i < screen_num_monitors; ++i) { - Rect const *area = screen_physical_area_monitor(i); - if (RECT_INTERSECTS_RECT(*area, *search)) { - Rect r; - guint v; + const Rect *monitor; + Rect on_current_monitor; + glong area; + GSList *it; + + monitor = screen_physical_area_monitor(i); - RECT_SET_INTERSECTION(r, *area, *search); - v = r.width * r.height; + if (!RECT_INTERSECTS_RECT(*monitor, *search)) { + /* If we don't intersect then find the distance between the search + rect and the monitor. We'll use the closest monitor from this + metric if none of the monitors intersect. */ + guint distance = rect_manhatten_distance(*monitor, *search); - if (v > mostv) { - mostv = v; - most = i; + if (distance < closest_distance) { + closest_distance = distance; + closest_distance_index = i; } + continue; } + + if (i == config_primary_monitor_index) + continue; /* already did this one */ + + RECT_SET_INTERSECTION(on_current_monitor, *monitor, *search); + area = RECT_AREA(on_current_monitor); + + /* remove pixels we already counted on any previous monitors. */ + for (it = counted; it; it = g_slist_next(it)) { + RectArithmetic *ra = it->data; + Rect intersection; + + RECT_SET_INTERSECTION(intersection, ra->r, *search); + if (ra->subtract) area -= RECT_AREA(intersection); + else area += RECT_AREA(intersection); + } + + if (area > mostpx) { + mostpx = area; + mostpx_index = i; + } + + /* add the intersection rect on the current monitor I to the counted + list. + but now we need to compensate for every rectangle R already in the + counted list, and add a new rect R' that is the intersection of + R and I, but with the reverse subtraction/addition operation. + */ + for (it = counted; it; it = g_slist_next(it)) { + RectArithmetic *saved = it->data; + + if (!RECT_INTERSECTS_RECT(saved->r, on_current_monitor)) + continue; + /* we are going to subtract our rect from future monitors, but + part of it may already be being subtracted/added, so compensate + to not double add/subtract. */ + RectArithmetic *reverse = g_slice_new(RectArithmetic); + RECT_SET_INTERSECTION(reverse->r, saved->r, on_current_monitor); + reverse->subtract = !saved->subtract; + /* prepend so we can continue thru the list uninterupted */ + counted = g_slist_prepend(counted, reverse); + } + { + RectArithmetic *ra = g_slice_new(RectArithmetic); + ra->r = on_current_monitor; + ra->subtract = TRUE; + counted = g_slist_prepend(counted, ra); + } + } + + while (counted) { + g_slice_free(RectArithmetic, counted->data); + counted = g_slist_delete_link(counted, counted); } - return most; + + if (mostpx_index < screen_num_monitors) + return mostpx_index; + + g_assert(closest_distance_index < screen_num_monitors); + return closest_distance_index; } -Rect const* screen_physical_area_all_monitors(void) +const Rect* screen_physical_area_all_monitors(void) { return screen_physical_area_monitor(screen_num_monitors); } -Rect const* screen_physical_area_monitor(guint head) +const Rect* screen_physical_area_monitor(guint head) { g_assert(head <= screen_num_monitors); @@ -1670,7 +1817,7 @@ guint screen_monitor_active(void) return screen_monitor_pointer(); } -Rect const* screen_physical_area_active(void) +const Rect* screen_physical_area_active(void) { return screen_physical_area_monitor(screen_monitor_active()); } @@ -1691,7 +1838,7 @@ guint screen_monitor_primary(gboolean fixed) return screen_monitor_pointer(); } -Rect const *screen_physical_area_primary(gboolean fixed) +const Rect* screen_physical_area_primary(gboolean fixed) { return screen_physical_area_monitor(screen_monitor_primary(fixed)); } @@ -1739,3 +1886,12 @@ gboolean screen_pointer_pos(gint *x, gint *y) } return ret; } + +gboolean screen_compare_desktops(guint a, guint b) +{ + if (a == DESKTOP_ALL) + a = screen_desktop; + if (b == DESKTOP_ALL) + b = screen_desktop; + return a == b; +}