After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 499301 - Refactor: MetaDisplay is a singleton, despite what the code thinks
Refactor: MetaDisplay is a singleton, despite what the code thinks
Status: RESOLVED FIXED
Product: metacity
Classification: Other
Component: general
trunk
Other Linux
: Normal normal
: ---
Assigned To: Thomas Thurman
Metacity maintainers list
Depends on:
Blocks:
 
 
Reported: 2007-11-24 04:50 UTC by Thomas Thurman
Modified: 2008-03-25 03:40 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
Replace meta_displays_list with meta_display_get (first draft) (52.68 KB, patch)
2008-03-18 02:41 UTC, Thomas Thurman
none Details | Review
Second draft (52.85 KB, patch)
2008-03-25 02:42 UTC, Thomas Thurman
committed Details | Review

Description Thomas Thurman 2007-11-24 04:50:03 UTC
doc/code-overview says:

  Don't confuse displays and screens.  While Metacity can run with multiple
  displays, it is kind of useless since you might as well just run two
  copies of Metacity.

The belief that Metacity can run with multiple displays appears to be widespread throughout the code. All functions which can deal with a display get passed a MetaDisplay as parameter. We also have a GSList in display.c called "all_displays" which supposedly contains the MetaDisplays for all displays we're handling, and a function meta_displays_list() to return this list for the benefit of other parts of the program.

This belief is not true, however: MetaDisplay in the current code is functionally a singleton. The only time a MetaDisplay is created is in meta_display_open(), which is only *ever* called once, from main() during startup, and only *ever* creates a display for the display referred to by the DISPLAY environment variable; the only time a MetaDisplay is destroyed is in meta_display_close(), which is only ever called from main() during shutdown and from meta_display_open() during error.

This means that meta_displays_list() will only ever return a list of exactly one item, and so all the code which calls it and iterates over it will always run exactly once.

I propose that we do one of two things:

1) Make it so you can run multiple displays from one copy of Metacity, as the documentation says, even though the documentation goes on to say that this is "kind of useless".

2) Recognise that we can only deal with one display at once; remove the MetaDisplay* parameter from all relevant functions in display.h so that they deals with the one created display (with a precondition that meta_display_open() has been called and meta_display_close() has not); replace meta_displays_list() with a function that simply returns a MetaDisplay. This would simplify the code a good deal.

For the avoidance of doubt, this issue does not concern xinerama.
Comment 1 Havoc Pennington 2007-11-24 05:08:56 UTC
fwiw, I think it's pretty ugly and non-object-oriented to make the methods on display not take a display object.

Replacing meta_displays_list() with meta_display_get() probably does make sense, assuming we'll never want to do #1, though afaik #1 would work fine if some means of telling metacity to connect to multiple displays were added. Not that I can come up with what those means would be, or why you would want to do this.
It is in fact kind of useless.

I do think though that meta_displays_list(), or a hypothetical meta_display_get(), should only be used in contexts where the display is unknown (e.g. when handling a notification from gconf), and should never be used e.g. inside a method on a display. Think about in Java:

  class Display {
    private static Display theDisplay;

    private List<Window> windows;

    static List<Window> listWindows() {
       return theDisplay.windows;
    }
  }

that is just bizarre, it should be:

  class Display {
     private List<Window> windows;

     List<Window> listWindows() {
       return windows;
     }
  }


Comment 2 Thomas Thurman 2007-12-11 17:33:21 UTC
(In reply to comment #1)
> fwiw, I think it's pretty ugly and non-object-oriented to make the methods on
> display not take a display object.

It does mean that in a number of places we call meta_display_list (or meta_display_get in happy fun singleton world) only in order to be able to pass the result in as the first parameter of various meta_display_* functions later in the function; this is useless extra complexity and extra code if the value is predictable. (I agree it's not terribly OO, but singleton objects rather break the OO pattern anyway.)
Comment 3 Havoc Pennington 2007-12-11 18:18:27 UTC
There are only 10 calls to meta_displays_list(), all in places where there really is no known display (i.e. in truly global contexts).

I don't know. All my programming experience would say "don't make this change"

It is perhaps a bit of an indentation-style issue though, challenging to build an irrefutable argument either way.

I guess I would say the only reason to do it your way is that it saves a (small) amount of typing and work up front, but since the work is already done to be completely OO and even multiple-display-safe, why undo that? Seems like a downgrade.


Comment 4 Thomas Thurman 2007-12-11 18:35:05 UTC
It is a downgrade, insofar as it removes abilities we don't use and have no plans to. I'm not trying to save us work we've already done-- and new patches, like the one Alex posted recently, sometimes need to add new calls to meta_display_list() after all, so not *all* the work is already done.

Rather, I'm trying to reduce the complexity of the existing code, giving us less to maintain in future: if we replace meta_displays_list() with meta_display_get(), we save one outermost for loop in every one of those ten places; if we also then stop passing MetaDisplay*s around (which is really a second possible refactoring made possible by the first) we save ourselves one parameter every time we call meta_display_*. We could do both of those, or just the first, or neither.

On the other hand, perhaps neither would be good: it's mature code, so probably it's best not to mess with it even though I think it's pretty clear that the paths through it would be identical with and without this change.

I'm fine with marking this WONTFIX if your spidey-sense is tingling against it, though: I've been looking for places to tidy up the code recently, and this was something that jumped out at me, but if you'd rather keep it as it is that's fine.
Comment 5 Havoc Pennington 2007-12-11 18:39:32 UTC
I don't have a strong view on get vs. list, that seems toss-up-ish. I think calling get() (or just using a global var directly) in the display methods, instead of passing in the display object, is pretty fugly though.
Comment 6 Thomas Thurman 2007-12-11 18:42:50 UTC
Oh, okay, yay. I know I said I didn't mind either way, but I didn't mind either way more about that part. :) I'll see about a patch and we'll see how it goes.
Comment 7 Elijah Newren 2007-12-13 04:38:03 UTC
I think the current handling of displays is probably more similar to how gtk+ and X are coded than changing it to a singleton.  I don't think gtk+ deals with multiple X servers in most cases either, but I think keeping the style to be familiar to other coders (there's a lot more people familiar with gtk+ than metacity, and gtk+-hackers have often been known to help out with metacity issues here and there) is more of a win.

Also even when I do singletons in C++, there's some global function to get 'the instance' and then I call the functions on that instance...thus meaning the object is passed to the function.  So, I think I agree with Havoc here as far as passing the display objects goes.  Now, if you wanted to change meta_display_list() to meta_display_get() and added some other cleanups to make it clear that there would ever only be one display, I probably wouldn't have an opinion.  But I agree with Havoc that it seems to make more sense to pass the display object to various display functions.

Anyway, that's my $0.02.
Comment 8 Thomas Thurman 2008-03-18 02:41:13 UTC
Created attachment 107506 [details] [review]
Replace meta_displays_list with meta_display_get (first draft)

Here's a patch doing that, then.

There is actually one place where it's not clear that the code paths before and after are identical: it turns out that the old display list didn't always have exactly one element in it.  When Metacity's starting up, there was nothing in the list.  This is the same now as meta_display_get() returning NULL.  Of course before we'd iterate over the list, and if there was nothing in it we'd do nothing, whereas now if we just charge ahead we'll end up dereffing a null pointer.  So in the cases where we call meta_display_get() where we might be called before the display is initialised, we need to check whether meta_display_get() returns null and not use the result if so.  After some checking I believe there is only one such case.
Comment 9 Thomas Thurman 2008-03-18 02:46:24 UTC
Oops, I left in a FIXME towards the end which I meant to clear up.  The current Metacity trunk is ambiguous on casual reading whether it terminates in meta_display_close() at

  if (all_displays == NULL)
    {
      meta_verbose ("Last display closed, exiting\n");
      meta_quit (META_EXIT_SUCCESS);
    }

or by reaching the end of main(), and why.  (I think it reaches the end of main(), otherwise session management would be broken, but I need to check and remove the one which isn't in use.)
Comment 10 Thomas Thurman 2008-03-24 23:56:14 UTC
Oh, my bad.  meta_quit() tells the main loop to quit and returns: it's not some kind of exit() type affair.  So this should be all good.
Comment 11 Thomas Thurman 2008-03-25 02:42:08 UTC
Created attachment 107968 [details] [review]
Second draft

I think this is ready to be checked in, and I will later, but I want to go to bed.
Comment 12 Thomas Thurman 2008-03-25 03:40:34 UTC
Yay.  FIXED.

http://svn.gnome.org/viewvc/metacity?rev=3663&view=rev