From 46d224f5ae65b06076a56b85f994e5c609545278 Mon Sep 17 00:00:00 2001 From: rhp Date: Sat, 28 Jul 2001 06:11:15 +0000 Subject: [PATCH] ... --- README | 89 ++++++++++++------- src/session.c | 237 ++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 278 insertions(+), 48 deletions(-) diff --git a/README b/README index fd2249a97..423ff0d6a 100644 --- a/README +++ b/README @@ -6,6 +6,23 @@ on UNIX keyboards. The first release of Metacity is version 2.3. Metacity has no need for your petty hangups about version numbers. +COMPILING METACITY +=== + +You need GTK+ 1.3.x (to become 2.0). At the moment CVS HEAD is +required. Once 1.3.7 is available that will probably work. Metacity is +a fairly trivial 6000-line C program, so once you get GTK+ built it +should be no problem to build Metacity. + +REPORTING BUGS AND SUBMITTING PATCHES +=== + +Report new bugs to hp@redhat.com for now. Will switch to Bugzilla +sometime probably. + +Feel free to send patches too; Metacity is really small and simple, so +if you find a bug or want to add a feature it should be pretty easy. + METACITY FEATURES === @@ -69,8 +86,9 @@ METACITY FEATURES - Session management: - Metacity connects to the session manager and will set itself up - to be respawned. + Metacity connects to the session manager and will set itself up to + be respawned. It theoretically restores sizes/positions/workspace + for session-aware applications. - Here is an example of how you can configure the Metacity window border appearance in ~/.gtkrc-2.0: @@ -115,16 +133,18 @@ METACITY BUGS, NON-FEATURES, AND CAVEATS - Metacity does not have any way to unminimize a window. So clicking the minimize button is sort of a bad idea. + (If you had a WM-spec-compliant tasklist, it would work + for unminimization.) - - Metacity uses the new window manager spec, but only random bits - of the old GNOME spec. It correctly advertises exactly which - parts of the GNOME spec it supports, but it does not support - enough of it to make the GNOME task list and desk guide happy, - and they do not support the new spec. I don't want anyone to - spend time sending me patches to support the old GNOME spec; - instead, send patches to the task list and desk guide to support - the new spec. As far as I know, Metacity does support enough - of the new spec to allow a working tasklist and pager. + - Metacity uses the new window manager spec, but only random bits of + the old GNOME spec. It correctly advertises exactly which parts of + the GNOME spec it supports, but it does not support enough of it to + make the GNOME task list and desk guide happy, and they do not + support the new spec. I don't want anyone to spend time sending me + patches to support the old GNOME spec in Metacity; instead, send + patches to the task list and desk guide to support the new spec. As + far as I know, Metacity does support enough of the new spec to + allow a working tasklist and pager. Upshot: task list and desk guide DO NOT WORK with Metacity. @@ -134,12 +154,14 @@ METACITY BUGS, NON-FEATURES, AND CAVEATS instead of Alt as the main keybinding shortcut, if super/hyper exist, and then keyboards with a windows key can use that for WM functions and Alt for application shortcuts. + We'd fall back to Alt if no other suitable modifier existed. - Cycling windows with Alt-Tab is flickery, AFAIK because Metacity passes the entire window stack to XRestackWindows() every time you restack. Instead it should probably only restack windows that have changed their stacking with respect to one - another. + another. (But sometimes I don't see the flicker, so + I'm not sure.) - Various operations, such as minimize, maximize, etc., should have simple animations to make them clearer to users. @@ -151,8 +173,13 @@ METACITY BUGS, NON-FEATURES, AND CAVEATS as described in the ICCCM. But then, most other window managers don't handle this correctly either. - - I know there's at least one race condition involving rapidly - created and destroyed windows that will crash Metacity. + - There are probably other ICCCM-compliance issues. + + - I know there's at least one race condition involving rapidly + created and destroyed windows that will crash Metacity. I think a + small test app that did a lot of rapid show/hide on a GtkWindow, + in combination with the METACITY_SYNC environment variable and + Metacity in a debugger, would turn this up quickly. - Window placement is always cascade for now; I want to implement "first fit, falling back to cascade if no fit." @@ -186,21 +213,18 @@ METACITY BUGS, NON-FEATURES, AND CAVEATS locale. I assume the window titles should be right-justified; should the window controls also be flipped? -COMPILING METACITY -=== + - Need keyboard shortcuts for hide/show desktop (minimize/unminimize + all windows temporarily, basically, and focus desktop); also + for focusing dock windows (though since current GNOME panel has + no useful keynav, this doesn't get you far at the moment). -You need GTK+ 1.3.x (to become 2.0). See configure.in for the exact -version you need. Metacity is a fairly trivial 6000-line C program, so -once you get GTK+ built it should be no problem to build Metacity. + - Resize menu item doesn't do anything. It's intended to enter + resize-with-the-keyboard mode, similar to Move menu item. -REPORTING BUGS AND SUBMITTING PATCHES -=== - -Report new bugs to hp@redhat.com for now. Will switch to Bugzilla -sometime probably. - -Feel free to send patches too; Metacity is really small and simple, so -if you find a bug or want to add a feature it should be pretty easy. + - I haven't set up the po subdir and translations, mostly because + autotools seem to get all confused if you set these up but + don't actually have any translations. So if someone translates + something we can set it up. FAQ === @@ -267,8 +291,8 @@ A: Metacity only stores sizes/positions for apps that are session bunch of new windows appear. But it can't distinguish between windows that were stored in your session, or windows you just launched after logging in. If Metacity tried to guess that a window - was from the session, it could e.g. maximize a dialog, or put a - window you just launched on another desktop or in a weird + was from the session, it could e.g. end up maximizing a dialog, or + put a window you just launched on another desktop or in a weird place. And in fact I see a lot of bugs like this in window managers that try to handle non-session-aware apps. @@ -287,10 +311,9 @@ A: Metacity only stores sizes/positions for apps that are session ftp://ftp.x.org/pub/R6.4/xc/doc/hardcopy/SM/xsmp.PS.gz ftp://ftp.x.org:21/pub/R6.4/xc/doc/hardcopy/SM/SMlib.PS.gz - See also the ICCCM section on SM. For GNOME apps, use - the GnomeClient object. For a simple coding example using - libSM directly, twm/session.c in the twm source code is - pretty easy to understand. + See also the ICCCM section on SM. For GNOME apps, use the + GnomeClient object. For a simple example of using libSM directly, + twm/session.c in the twm source code is pretty easy to understand. Q: How about adding viewports in addition to workspaces? diff --git a/src/session.c b/src/session.c index 980a8b635..968fa952a 100644 --- a/src/session.c +++ b/src/session.c @@ -585,6 +585,116 @@ window_type_from_string (const char *str) return META_WINDOW_NORMAL; } +static const char* +window_gravity_to_string (int gravity) +{ + switch (gravity) + { + case NorthWestGravity: + return "NorthWestGravity"; + break; + case NorthGravity: + return "NorthGravity"; + break; + case NorthEastGravity: + return "NorthEastGravity"; + break; + case WestGravity: + return "WestGravity"; + break; + case CenterGravity: + return "CenterGravity"; + break; + case EastGravity: + return "EastGravity"; + break; + case SouthWestGravity: + return "SouthWestGravity"; + break; + case SouthGravity: + return "SouthGravity"; + break; + case SouthEastGravity: + return "SouthEastGravity"; + break; + case StaticGravity: + return "StaticGravity"; + break; + default: + return "NorthWestGravity"; + break; + } +} + +static int +window_gravity_from_string (const char *str) +{ + if (strcmp (str, "NorthWestGravity") == 0) + return NorthWestGravity; + else if (strcmp (str, "NorthGravity") == 0) + return NorthGravity; + else if (strcmp (str, "NorthEastGravity") == 0) + return NorthEastGravity; + else if (strcmp (str, "WestGravity") == 0) + return WestGravity; + else if (strcmp (str, "CenterGravity") == 0) + return CenterGravity; + else if (strcmp (str, "EastGravity") == 0) + return EastGravity; + else if (strcmp (str, "SouthWestGravity") == 0) + return SouthWestGravity; + else if (strcmp (str, "SouthGravity") == 0) + return SouthGravity; + else if (strcmp (str, "SouthEastGravity") == 0) + return SouthEastGravity; + else if (strcmp (str, "StaticGravity") == 0) + return StaticGravity; + else + return NorthWestGravity; +} + +static char* +encode_text_as_utf8 (const char *text) +{ + /* text can be any encoding, and is nul-terminated. + * we pretend it's Latin-1 and encode as UTF-8 + */ + GString *str; + const char *p; + + str = g_string_new (""); + + p = text; + while (*p) + { + g_string_append_unichar (str, *p); + ++p; + } + + return g_string_free (str, FALSE); +} + +static char* +decode_text_from_utf8 (const char *text) +{ + /* Convert back from the encoded UTF-8 */ + GString *str; + const char *p; + + str = g_string_new (""); + + p = text; + while (*p) + { + /* obviously this barfs if the UTF-8 contains chars > 255 */ + g_string_append_c (str, g_utf8_get_char (p)); + + p = g_utf8_next_char (p); + } + + return g_string_free (str, FALSE); +} + static void save_state (void) { @@ -651,10 +761,6 @@ save_state (void) * child elements are the saved state to be applied. * */ - - /* FIXME we are putting non-UTF-8 in here. */ - - meta_warning ("FIXME Saving session ID, class, name, etc. pretending that they are valid UTF-8, but no such thing is necessarily true"); fprintf (outfile, "\n", client_id); @@ -676,18 +782,41 @@ save_state (void) if (window->sm_client_id) { + char *sm_client_id; + char *res_class; + char *res_name; + char *role; + + /* client id, class, name, role are not expected to be + * in UTF-8 (I think they are in XPCS which is Latin-1? + * in practice they are always ascii though.) + */ + + sm_client_id = encode_text_as_utf8 (window->sm_client_id); + res_class = window->res_class ? + encode_text_as_utf8 (window->res_class) : NULL; + res_name = window->res_name ? + encode_text_as_utf8 (window->res_name) : NULL; + role = window->role ? + encode_text_as_utf8 (window->role) : NULL; + meta_verbose ("Saving session managed window %s, client ID '%s'\n", window->desc, window->sm_client_id); fprintf (outfile, " \n", - window->sm_client_id, - window->res_class ? window->res_class : "", - window->res_name ? window->res_name : "", + sm_client_id, + res_class ? res_class : "", + res_name ? res_name : "", window->title ? window->title : "", - window->role ? window->role : "", + role ? role : "", window_type_to_string (window->type)); + g_free (sm_client_id); + g_free (res_class); + g_free (res_name); + g_free (role); + /* Sticky */ if (window->on_all_workspaces) fputs (" \n", outfile); @@ -706,6 +835,17 @@ save_state (void) w = w->next; } } + + /* Gravity */ + { + int x, y, w, h; + meta_window_get_geometry (window, &x, &y, &w, &h); + + fprintf (outfile, + " \n", + x, y, w, h, + window_gravity_to_string (window->size_hints.win_gravity)); + } fputs (" \n", outfile); } @@ -813,6 +953,10 @@ load_state (const char *previous_id) return; } + meta_verbose ("Parsing saved session file %s\n", session_file); + g_free (session_file); + session_file = NULL; + parse_data.info = NULL; context = g_markup_parse_context_new (&metacity_session_parser, @@ -835,13 +979,16 @@ load_state (const char *previous_id) goto out; error: - + meta_warning (_("Failed to parse saved session file: %s\n"), error->message); g_error_free (error); + if (parse_data.info) + session_info_free (parse_data.info); + out: - + g_free (text); } @@ -889,17 +1036,17 @@ start_element_handler (GMarkupParseContext *context, if (strcmp (name, "id") == 0) { if (*val) - pd->info->id = g_strdup (val); + pd->info->id = decode_text_from_utf8 (val); } else if (strcmp (name, "class") == 0) { if (*val) - pd->info->res_class = g_strdup (val); + pd->info->res_class = decode_text_from_utf8 (val); } else if (strcmp (name, "name") == 0) { if (*val) - pd->info->res_name = g_strdup (val); + pd->info->res_name = decode_text_from_utf8 (val); } else if (strcmp (name, "title") == 0) { @@ -909,7 +1056,7 @@ start_element_handler (GMarkupParseContext *context, else if (strcmp (name, "role") == 0) { if (*val) - pd->info->role = g_strdup (val); + pd->info->role = decode_text_from_utf8 (val); } else if (strcmp (name, "type") == 0) { @@ -970,8 +1117,63 @@ start_element_handler (GMarkupParseContext *context, } else if (strcmp (element_name, "geometry") == 0) { + int i; + pd->info->geometry_set = TRUE; + + i = 0; + while (attribute_names[i]) + { + const char *name; + const char *val; + + name = attribute_names[i]; + val = attribute_values[i]; + + if (strcmp (name, "x") == 0) + { + if (*val) + pd->info->rect.x = atoi (val); + } + else if (strcmp (name, "y") == 0) + { + if (*val) + pd->info->rect.y = atoi (val); + } + else if (strcmp (name, "width") == 0) + { + if (*val) + pd->info->rect.width = atoi (val); + } + else if (strcmp (name, "height") == 0) + { + if (*val) + pd->info->rect.height = atoi (val); + } + else if (strcmp (name, "gravity") == 0) + { + if (*val) + pd->info->gravity = window_gravity_from_string (val); + } + else + { + g_set_error (error, + G_MARKUP_ERROR, + G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE, + _("Unknown attribute %s on element"), + name); + return; + } + + ++i; + } + meta_verbose ("Loaded geometry %d,%d %dx%d gravity %s\n", + pd->info->rect.x, + pd->info->rect.y, + pd->info->rect.width, + pd->info->rect.height, + window_gravity_to_string (pd->info->gravity)); } else { @@ -1045,9 +1247,12 @@ get_possible_matches (MetaWindow *window) /* Get all windows with this client ID */ GSList *retval; GSList *tmp; + gboolean ignore_client_id; retval = NULL; + ignore_client_id = g_getenv ("METACITY_DEBUG_SM") != NULL; + tmp = window_info_list; while (tmp != NULL) { @@ -1055,7 +1260,8 @@ get_possible_matches (MetaWindow *window) info = tmp->data; - if (both_null_or_matching (info->id, window->sm_client_id) && + if ((ignore_client_id || + both_null_or_matching (info->id, window->sm_client_id)) && both_null_or_matching (info->res_class, window->res_class) && both_null_or_matching (info->res_name, window->res_name) && both_null_or_matching (info->role, window->role)) @@ -1216,6 +1422,7 @@ session_info_new (void) info = g_new0 (MetaWindowSessionInfo, 1); info->type = META_WINDOW_NORMAL; + info->gravity = NorthWestGravity; return info; }