X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=openbox%2Fscreen.c;h=a4a7ba595a6d9807bd2ded9700e8e7e9bb4d73c4;hb=7a6a516b8e3d8ad6b15379eabf6652a6f43eab27;hp=c1c61ed5b7ce476501ffce3136d2c8deadb50c49;hpb=35ab1264ee5efe0c0a5458329f4e7d2ebda43b98;p=chaz%2Fopenbox diff --git a/openbox/screen.c b/openbox/screen.c index c1c61ed5..a4a7ba59 100644 --- a/openbox/screen.c +++ b/openbox/screen.c @@ -2,7 +2,7 @@ screen.c for the Openbox window manager Copyright (c) 2006 Mikael Magnusson - Copyright (c) 2003 Ben Jansens + 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 @@ -28,12 +28,14 @@ #include "config.h" #include "screen.h" #include "client.h" +#include "session.h" #include "frame.h" #include "event.h" #include "focus.h" #include "popup.h" #include "extensions.h" #include "render/render.h" +#include "gettext.h" #include #ifdef HAVE_UNISTD_H @@ -45,21 +47,30 @@ /*! The event mask to grab on the root window */ #define ROOT_EVENTMASK (StructureNotifyMask | PropertyChangeMask | \ EnterWindowMask | LeaveWindowMask | \ - SubstructureNotifyMask | SubstructureRedirectMask | \ + 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; +ObDesktopLayout screen_desktop_layout; gchar **screen_desktop_names; Window screen_support_win; +Time screen_desktop_user_time = CurrentTime; -static Rect **area; /* array of desktop holding array of xinerama areas */ +/*! An array of desktops, holding array of areas per monitor */ static Rect *monitor_area; +static GSList *struts_top; +static GSList *struts_left; +static GSList *struts_right; +static GSList *struts_bottom; static ObPagerPopup *desktop_cycle_popup; @@ -79,7 +90,7 @@ static gboolean replace_wm() current_wm_sn_owner = None; if (current_wm_sn_owner) { if (!ob_replace_wm) { - g_warning("A window manager is already running on screen %d", + g_message(_("A window manager is already running on screen %d"), ob_screen); return FALSE; } @@ -116,7 +127,7 @@ static gboolean replace_wm() timestamp); if (XGetSelectionOwner(ob_display, wm_sn_atom) != screen_support_win) { - g_warning("Could not acquire window manager selection on screen %d", + g_message(_("Could not acquire window manager selection on screen %d"), ob_screen); return FALSE; } @@ -137,16 +148,15 @@ static gboolean replace_wm() } if (wait >= timeout) { - g_warning("Timeout expired while waiting for the current WM to die " - "on screen %d", ob_screen); + 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, 0, 0, SubstructureNotifyMask); - + timestamp, wm_sn_atom, screen_support_win, 0, + SubstructureNotifyMask); return TRUE; } @@ -156,6 +166,7 @@ gboolean screen_annex() XSetWindowAttributes attrib; pid_t pid; gint i, num_support; + Atom *prop_atoms_start, *wm_supported_pos; gulong *supported; /* create the netwm support window */ @@ -166,7 +177,8 @@ gboolean screen_annex() CopyFromParent, InputOutput, CopyFromParent, CWOverrideRedirect, &attrib); - XMapRaised(ob_display, screen_support_win); + XMapWindow(ob_display, screen_support_win); + XLowerWindow(ob_display, screen_support_win); if (!replace_wm()) { XDestroyWindow(ob_display, screen_support_win); @@ -179,14 +191,13 @@ gboolean screen_annex() ROOT_EVENTMASK); xerror_set_ignore(FALSE); if (xerror_occured) { - g_warning("A window manager is already running on screen %d", + g_message(_("A window manager is already running on screen %d"), ob_screen); XDestroyWindow(ob_display, screen_support_win); return FALSE; } - screen_set_root_cursor(); /* set the OPENBOX_PID hint */ @@ -204,9 +215,16 @@ gboolean screen_annex() window, screen_support_win); /* set the _NET_SUPPORTED_ATOMS hint */ - num_support = 53; + + /* 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(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; @@ -225,6 +243,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; @@ -244,6 +265,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; @@ -258,84 +281,184 @@ gboolean screen_annex() 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_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(RootWindow(ob_display, ob_screen), net_supported, atom, supported, num_support); g_free(supported); + screen_tell_ksplash(); + return TRUE; } +static void screen_tell_ksplash() +{ + 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) { - GSList *it; - guint i; + 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) - /* get the initial size */ - screen_resize(); - - /* set the names */ - screen_desktop_names = g_new(gchar*, - g_slist_length(config_desktops_names) + 1); - for (i = 0, it = config_desktops_names; it; ++i, it = g_slist_next(it)) - screen_desktop_names[i] = it->data; /* dont strdup */ - screen_desktop_names[i] = NULL; - 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; + if (reconfig) { + /* update the pager popup's width */ + pager_popup_text_width_to_strings(desktop_cycle_popup, + screen_desktop_names, + screen_num_desktops); + return; + } - if (!reconfig) - screen_num_desktops = 0; - screen_set_num_desktops(config_desktops_num); - if (!reconfig) { - screen_set_desktop(MIN(config_screen_firstdesk, screen_num_desktops) - - 1); + /* get the initial size */ + screen_resize(); - /* don't start in showing-desktop mode */ - screen_showing_desktop = FALSE; - PROP_SET32(RootWindow(ob_display, ob_screen), - net_showing_desktop, cardinal, screen_showing_desktop); + /* 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; + } - screen_update_layout(); + /* 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; + 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(RootWindow(ob_display, ob_screen), + net_showing_desktop, cardinal, screen_showing_desktop); + + if (session_desktop_layout_present && + screen_validate_layout(&session_desktop_layout)) + { + screen_desktop_layout = session_desktop_layout; + } + else + screen_update_layout(); } void screen_shutdown(gboolean reconfig) { - Rect **r; - pager_popup_free(desktop_cycle_popup); - if (!reconfig) { - XSelectInput(ob_display, RootWindow(ob_display, ob_screen), - NoEventMask); + if (reconfig) + return; - /* 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); + XSelectInput(ob_display, RootWindow(ob_display, ob_screen), + NoEventMask); - XDestroyWindow(ob_display, screen_support_win); - } + /* 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() @@ -370,7 +493,7 @@ void screen_resize() void screen_set_num_desktops(guint num) { - guint i, old; + guint old; gulong *viewport; GList *it; @@ -392,9 +515,6 @@ void screen_set_num_desktops(guint num) /* 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(); - /* move windows on desktops that will no longer exist! */ for (it = client_list; it; it = g_list_next(it)) { ObClient *c = it->data; @@ -405,39 +525,40 @@ void screen_set_num_desktops(guint num) /* change our struts/area to match (after moving windows) */ screen_update_areas(); + /* 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); - - /* 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; + 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; + gulong ignore_start; + gboolean allow_omni; g_assert(num < screen_num_desktops); old = screen_desktop; screen_desktop = num; - PROP_SET32(RootWindow(ob_display, ob_screen), - net_current_desktop, cardinal, num); if (old == num) return; + PROP_SET32(RootWindow(ob_display, ob_screen), + net_current_desktop, cardinal, num); + screen_last_desktop = old; ob_debug("Moving to desktop %d\n", num+1); + /* ignore enter events caused by the move */ + ignore_start = event_start_ignore_all_enters(); + if (moveresize_client) client_set_desktop(moveresize_client, num, TRUE); @@ -447,8 +568,36 @@ void screen_set_desktop(guint num) for (it = stacking_list; it; it = g_list_next(it)) { if (WINDOW_IS_CLIENT(it->data)) { ObClient *c = it->data; - if (client_should_show(c)) - frame_show(c->frame); + client_show(c); + } + } + + /* only allow omnipresent windows to get focus on desktop change if + an omnipresent window is already focused (it'll keep focus probably, but + maybe not depending on mouse-focus options) */ + allow_omni = focus_client && (client_normal(focus_client) && + focus_client->desktop == DESKTOP_ALL); + + /* 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, allow_omni))) + { + /* only do the flicker reducing stuff ahead of time if we are going + to call xsetinputfocus on the window ourselves. otherwise there is + 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); } } @@ -456,25 +605,14 @@ void screen_set_desktop(guint num) 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_queued_enters(); + event_end_ignore_all_enters(ignore_start); - focus_hilite = focus_fallback_target(OB_FOCUS_FALLBACK_NOFOCUS); - if (focus_hilite) { - frame_adjust_focus(focus_hilite->frame, TRUE); - - /*! - When this focus_client check is not used, you can end up with races, - as demonstrated with gnome-panel, sometmies the window you click on - another desktop ends up losing focus cuz of the focus change here. - */ - /*if (!focus_client)*/ - client_focus(focus_hilite); - } + if (event_curtime != CurrentTime) + screen_desktop_user_time = event_curtime; } static void get_row_col(guint d, guint *r, guint *c) @@ -592,15 +730,16 @@ void screen_desktop_popup(guint d, gboolean show) if (!show) { pager_popup_hide(desktop_cycle_popup); } else { - a = screen_physical_area_monitor(0); + a = screen_physical_area_monitor_active(); pager_popup_position(desktop_cycle_popup, CenterGravity, a->x + a->width / 2, a->y + a->height / 2); - /* XXX the size and the font extents need to be related on some level - */ - pager_popup_size(desktop_cycle_popup, POPUP_WIDTH, POPUP_HEIGHT); - - pager_popup_set_text_align(desktop_cycle_popup, RR_JUSTIFY_CENTER); - + 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); } } @@ -608,21 +747,17 @@ void screen_desktop_popup(guint d, gboolean show) guint screen_cycle_desktop(ObDirection dir, gboolean wrap, gboolean linear, gboolean dialog, gboolean done, gboolean cancel) { - static gboolean first = TRUE; - static guint origd, d; guint r, c; + static guint d = (guint)-1; + guint ret, oldd; - if (cancel) { - d = origd; - goto done_cycle; - } else if (done && dialog) { - goto done_cycle; - } - if (first) { - first = FALSE; - d = origd = screen_desktop; - } + 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) { @@ -648,19 +783,17 @@ guint screen_cycle_desktop(ObDirection dir, gboolean wrap, gboolean linear, case OB_DIRECTION_EAST: ++c; if (c >= screen_desktop_layout.columns) { - if (wrap) { + if (wrap) c = 0; - } else { - d = screen_desktop; + else goto show_cycle_dialog; - } } d = translate_row_col(r, c); if (d >= screen_num_desktops) { if (wrap) { ++c; } else { - d = screen_desktop; + d = oldd; goto show_cycle_dialog; } } @@ -668,19 +801,17 @@ guint screen_cycle_desktop(ObDirection dir, gboolean wrap, gboolean linear, case OB_DIRECTION_WEST: --c; if (c >= screen_desktop_layout.columns) { - if (wrap) { + if (wrap) c = screen_desktop_layout.columns - 1; - } else { - d = screen_desktop; + else goto show_cycle_dialog; - } } d = translate_row_col(r, c); if (d >= screen_num_desktops) { if (wrap) { --c; } else { - d = screen_desktop; + d = oldd; goto show_cycle_dialog; } } @@ -688,19 +819,17 @@ guint screen_cycle_desktop(ObDirection dir, gboolean wrap, gboolean linear, case OB_DIRECTION_SOUTH: ++r; if (r >= screen_desktop_layout.rows) { - if (wrap) { + if (wrap) r = 0; - } else { - d = screen_desktop; + else goto show_cycle_dialog; - } } d = translate_row_col(r, c); if (d >= screen_num_desktops) { if (wrap) { ++r; } else { - d = screen_desktop; + d = oldd; goto show_cycle_dialog; } } @@ -708,19 +837,17 @@ guint screen_cycle_desktop(ObDirection dir, gboolean wrap, gboolean linear, case OB_DIRECTION_NORTH: --r; if (r >= screen_desktop_layout.rows) { - if (wrap) { + if (wrap) r = screen_desktop_layout.rows - 1; - } else { - d = screen_desktop; + else goto show_cycle_dialog; - } } d = translate_row_col(r, c); if (d >= screen_num_desktops) { if (wrap) { --r; } else { - d = screen_desktop; + d = oldd; goto show_cycle_dialog; } } @@ -734,108 +861,102 @@ guint screen_cycle_desktop(ObDirection dir, gboolean wrap, gboolean linear, } show_cycle_dialog: - if (dialog) { + if (dialog && !cancel && !done) { screen_desktop_popup(d, TRUE); - return d; - } + } else + screen_desktop_popup(0, FALSE); + ret = d; + + if (!dialog || cancel || done) + d = (guint)-1; -done_cycle: - first = TRUE; + return ret; +} + +static gboolean screen_validate_layout(ObDesktopLayout *l) +{ + if (l->columns == 0 && l->rows == 0) /* both 0's is bad data.. */ + return FALSE; - screen_desktop_popup(0, 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--; + } - return d; + /* 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; + + 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_topleft) - corner = OB_CORNER_TOPLEFT; + l.start_corner = OB_CORNER_TOPLEFT; else if (data[3] == prop_atoms.net_wm_topright) - corner = OB_CORNER_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; } - cols = data[1]; - rows = data[2]; - - /* fill in a zero rows/columns */ - if ((cols == 0 && rows == 0)) { /* both 0's is bad data.. */ - goto screen_update_layout_bail; - } else { - if (cols == 0) { - cols = screen_num_desktops / rows; - if (rows * cols < screen_num_desktops) - cols++; - if (rows * cols >= screen_num_desktops + cols) - rows--; - } else if (rows == 0) { - rows = screen_num_desktops / cols; - if (cols * rows < screen_num_desktops) - rows++; - if (cols * rows >= screen_num_desktops + rows) - cols--; - } - } + l.columns = data[1]; + l.rows = data[2]; - /* bounds checking */ - if (orient == OB_ORIENTATION_HORZ) { - cols = MIN(screen_num_desktops, cols); - rows = MIN(rows, (screen_num_desktops + cols - 1) / cols); - cols = screen_num_desktops / rows + - !!(screen_num_desktops % rows); - } else { - rows = MIN(screen_num_desktops, rows); - cols = MIN(cols, (screen_num_desktops + rows - 1) / rows); - rows = screen_num_desktops / cols + - !!(screen_num_desktops % 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() @@ -848,19 +969,42 @@ void screen_update_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); + for (i = 0; screen_desktop_names[i] && i < screen_num_desktops; ++i); else i = 0; - if (i <= screen_num_desktops) { + 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_printf("Desktop %i", i + 1); + + 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; @@ -869,33 +1013,52 @@ void screen_show_desktop(gboolean show) screen_showing_desktop = show; if (show) { - /* bottom to top */ + /* 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 */ + } + 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 = g_list_next(it)) - 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(OB_FOCUS_FALLBACK_NOFOCUS); + } + } + else if (!show_only) { + ObClient *c; + + if ((c = focus_fallback(TRUE, FALSE, TRUE))) { + /* 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 */ @@ -905,23 +1068,18 @@ void screen_show_desktop(gboolean show) void screen_install_colormap(ObClient *client, gboolean install) { - XWindowAttributes wa; - - if (client == NULL) { + 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); } } @@ -971,222 +1129,250 @@ screen_area_add_strut_bottom(const StrutPartial *s, const Rect *monitor_area, void screen_update_areas() { - guint i, x; + guint i, j; gulong *dims; GList *it; - gint o; + GSList *sit; + + ob_debug("updating screen areas\n"); g_free(monitor_area); extensions_xinerama_screens(&monitor_area, &screen_num_monitors); - if (area) { - for (i = 0; area[i]; ++i) - g_free(area[i]); - g_free(area); + dims = g_new(gulong, 4 * screen_num_desktops * screen_num_monitors); + + g_slist_free(struts_left); struts_left = NULL; + g_slist_free(struts_top); struts_top = NULL; + g_slist_free(struts_right); struts_right = NULL; + g_slist_free(struts_bottom); struts_bottom = NULL; + + /* collect the struts */ + for (it = client_list; it; it = g_list_next(it)) { + ObClient *c = it->data; + if (c->strut.left) + struts_left = g_slist_prepend(struts_left, &c->strut); + if (c->strut.top) + struts_top = g_slist_prepend(struts_top, &c->strut); + if (c->strut.right) + struts_right = g_slist_prepend(struts_right, &c->strut); + if (c->strut.bottom) + struts_bottom = g_slist_prepend(struts_bottom, &c->strut); } - area = g_new(Rect*, screen_num_desktops + 2); - for (i = 0; i < screen_num_desktops + 1; ++i) - area[i] = g_new0(Rect, screen_num_monitors + 1); - area[i] = NULL; - - dims = g_new(gulong, 4 * screen_num_desktops); + /* set up the work areas to be full screen */ + for (i = 0; i < screen_num_monitors; ++i) + for (j = 0; j < screen_num_desktops; ++j) { + dims[i * j + 0] = monitor_area[i].x; + dims[i * j + 1] = monitor_area[i].y; + dims[i * j + 2] = monitor_area[i].width; + dims[i * j + 3] = monitor_area[i].height; + } - for (i = 0; i < screen_num_desktops + 1; ++i) { - Strut *struts; - gint l, r, t, b; + /* calculate the work areas from the struts */ + for (i = 0; i < screen_num_monitors; ++i) + for (j = 0; j < screen_num_desktops; ++j) { + gint l = 0, r = 0, t = 0, b = 0; + + /* only add the strut to the area if it touches the monitor */ - struts = g_new0(Strut, screen_num_monitors); - - /* 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); + for (sit = struts_left; sit; sit = g_slist_next(sit)) { + StrutPartial *s = sit->data; + if (RANGE_INTERSECT + (s->left_start, s->left_end - s->left_start + 1, + monitor_area[i].y, monitor_area[i].height)) + l = MAX(l, s->left); } - } - RECT_SET(area[i][x], l, t, r - l + 1, b - t + 1); - - /* apply the struts */ - - /* 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) { - 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]); + for (sit = struts_top; sit; sit = g_slist_next(sit)) { + StrutPartial *s = sit->data; + if (RANGE_INTERSECT + (s->top_start, s->top_end - s->top_start + 1, + monitor_area[i].x, monitor_area[i].width)) + t = MAX(t, s->top); + } + for (sit = struts_right; sit; sit = g_slist_next(sit)) { + StrutPartial *s = sit->data; + if (RANGE_INTERSECT + (s->right_start, s->right_end - s->right_start + 1, + monitor_area[i].y, monitor_area[i].height)) + r = MAX(r, s->right); + } + for (sit = struts_bottom; sit; sit = g_slist_next(sit)) { + StrutPartial *s = sit->data; + if (RANGE_INTERSECT + (s->bottom_start, s->bottom_end - s->bottom_start + 1, + monitor_area[i].x, monitor_area[i].width)) + b = MAX(b, s->bottom); } - screen_area_add_strut_left(&dock_strut, - &monitor_area[x], - o + dock_strut.left - area[i][x].x, - &struts[x]); - area[i][x].x += struts[x].left; - area[i][x].width -= struts[x].left; + /* based on these margins, set the work area for the + monitor/desktop */ + dims[i * j + 0] += l; + dims[i * j + 1] += t; + dims[i * j + 2] -= l + r; + dims[i * j + 3] -= t + b; } - /* 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); - - 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_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]); + PROP_SETA32(RootWindow(ob_display, ob_screen), net_workarea, cardinal, + dims, 4 * screen_num_desktops * screen_num_monitors); - area[i][x].y += struts[x].top; - area[i][x].height -= struts[x].top; - } + /* the area has changed, adjust all the windows if they need it */ + for (it = client_list; it; it = g_list_next(it)) { + gint x, y, w, h, lw, lh; + ObClient *client = it->data; - /* 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); - - 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; - } + RECT_TO_DIMS(client->area, x, y, w, h); + client_try_configure(client, &x, &y, &w, &h, &lw, &lh, FALSE); + if (!RECT_EQUAL_DIMS(client->area, x, y, w, h)) { + gulong ignore_start; - /* 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; + ignore_start = event_start_ignore_all_enters(); + client_configure(client, x, y, w, h, FALSE, TRUE); + event_end_ignore_all_enters(ignore_start); } + } - 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 = g_list_next(it)) { - 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; - } + g_free(dims); +} - g_free(struts); - } +Rect* screen_area(guint desktop, Rect *search) +{ + guint i; + Rect *a; - PROP_SETA32(RootWindow(ob_display, ob_screen), net_workarea, cardinal, - dims, 4 * screen_num_desktops); + a = screen_area_monitor(desktop, 0, search); - g_free(dims); + /* combine all the monitors together */ + for (i = 0; i < screen_num_monitors; ++i) { + Rect *m = screen_area_monitor(desktop, i, search); + gint l, r, t, b; + + l = MIN(RECT_LEFT(*a), RECT_LEFT(*m)); + t = MIN(RECT_TOP(*a), RECT_TOP(*m)); + r = MAX(RECT_RIGHT(*a), RECT_RIGHT(*m)); + b = MAX(RECT_BOTTOM(*a), RECT_BOTTOM(*m)); + + RECT_SET(*a, l, t, r - l + 1, b - t + 1); + + g_free(m); + } + + return a; } -Rect *screen_area(guint desktop) +Rect* screen_area_monitor(guint desktop, guint head, Rect *search) { - return screen_area_monitor(desktop, screen_num_monitors); + Rect *a; + GSList *it; + gint l, r, t, b; + + g_assert(head < screen_num_monitors); + + /* get the base area for the monitor */ + a = g_new(Rect, 1); + *a = monitor_area[head]; + + /* remove any struts which will be affecting the search area */ + l = t = r = b = 0; + for (it = struts_left; it; it = g_slist_next(it)) { + StrutPartial *s = it->data; + if (!search || + RANGE_INTERSECT(search->y, search->height, + s->left_start, s->left_end - s->left_start + 1)) + l = MAX(l, s->left); + } + for (it = struts_right; it; it = g_slist_next(it)) { + StrutPartial *s = it->data; + if (!search == 0 || + RANGE_INTERSECT(search->y, search->height, + s->right_start, s->right_end - s->right_start + 1)) + r = MAX(r, s->right); + } + for (it = struts_top; it; it = g_slist_next(it)) { + StrutPartial *s = it->data; + if (!search == 0 || + RANGE_INTERSECT(search->x, search->width, + s->top_start, s->top_end - s->top_start + 1)) + t = MAX(t, s->top); + } + for (it = struts_bottom; it; it = g_slist_next(it)) { + StrutPartial *s = it->data; + if (search->width == 0 || + RANGE_INTERSECT(search->x, search->width, + s->bottom_start, + s->bottom_end - s->bottom_start + 1)) + b = MAX(b, s->bottom); + } + + a->x += l; + a->y += t; + a->width -= l + r; + a->height -= t + b; + return a; } -Rect *screen_area_monitor(guint desktop, guint head) +guint screen_find_monitor(Rect *search) { - if (head > screen_num_monitors) - return NULL; - if (desktop >= screen_num_desktops) { - if (desktop == DESKTOP_ALL) - return &area[screen_num_desktops][head]; - return NULL; + 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; + } + } + g_free(area); } - return &area[desktop][head]; + return most; } -Rect *screen_physical_area() +Rect* screen_physical_area() { return screen_physical_area_monitor(screen_num_monitors); } -Rect *screen_physical_area_monitor(guint head) +Rect* screen_physical_area_monitor(guint head) { - if (head > screen_num_monitors) - return NULL; - return &monitor_area[head]; + Rect *a; + g_assert(head <= screen_num_monitors); + + a = g_new(Rect, 1); + *a = monitor_area[head]; + return a; +} + +Rect* screen_physical_area_monitor_active() +{ + Rect *a; + gint x, y; + + if (focus_client) + a = screen_physical_area_monitor(client_monitor(focus_client)); + else { + Rect mon; + if (screen_pointer_pos(&x, &y)) + RECT_SET(mon, x, y, 1, 1); + else + RECT_SET(mon, 0, 0, 1, 1); + a = screen_physical_area_monitor(screen_find_monitor(&mon)); + } + return a; } void screen_set_root_cursor() { if (sn_app_starting()) XDefineCursor(ob_display, RootWindow(ob_display, ob_screen), - ob_cursor(OB_CURSOR_BUSY)); + ob_cursor(OB_CURSOR_BUSYPOINTER)); else XDefineCursor(ob_display, RootWindow(ob_display, ob_screen), ob_cursor(OB_CURSOR_POINTER)); @@ -1197,7 +1383,16 @@ gboolean screen_pointer_pos(gint *x, gint *y) Window w; gint i; guint u; - - return !!XQueryPointer(ob_display, RootWindow(ob_display, ob_screen), - &w, &w, x, y, &i, &i, &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; }