screen.c

Go to the documentation of this file.
00001 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
00002 
00003 /* Metacity X screen handler */
00004 
00005 /* 
00006  * Copyright (C) 2001, 2002 Havoc Pennington
00007  * Copyright (C) 2002, 2003 Red Hat Inc.
00008  * Some ICCCM manager selection code derived from fvwm2,
00009  * Copyright (C) 2001 Dominik Vogt, Matthias Clasen, and fvwm2 team
00010  * Copyright (C) 2003 Rob Adams
00011  * Copyright (C) 2004-2006 Elijah Newren
00012  * 
00013  * This program is free software; you can redistribute it and/or
00014  * modify it under the terms of the GNU General Public License as
00015  * published by the Free Software Foundation; either version 2 of the
00016  * License, or (at your option) any later version.
00017  *
00018  * This program is distributed in the hope that it will be useful, but
00019  * WITHOUT ANY WARRANTY; without even the implied warranty of
00020  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00021  * General Public License for more details.
00022  * 
00023  * You should have received a copy of the GNU General Public License
00024  * along with this program; if not, write to the Free Software
00025  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
00026  * 02111-1307, USA.
00027  */
00028 
00029 #include <config.h>
00030 #include "screen-private.h"
00031 #include "util.h"
00032 #include "errors.h"
00033 #include "window-private.h"
00034 #include "frame-private.h"
00035 #include "prefs.h"
00036 #include "workspace.h"
00037 #include "keybindings.h"
00038 #include "stack.h"
00039 #include "xprops.h"
00040 #include "compositor.h"
00041 
00042 #ifdef HAVE_SOLARIS_XINERAMA
00043 #include <X11/extensions/xinerama.h>
00044 #endif
00045 #ifdef HAVE_XFREE_XINERAMA
00046 #include <X11/extensions/Xinerama.h>
00047 #endif
00048 
00049 #include <X11/Xatom.h>
00050 #include <locale.h>
00051 #include <string.h>
00052 #include <stdio.h>
00053 
00054 static char* get_screen_name (MetaDisplay *display,
00055                               int          number);
00056 
00057 static void update_num_workspaces  (MetaScreen *screen,
00058                                     guint32     timestamp);
00059 static void update_focus_mode      (MetaScreen *screen);
00060 static void set_workspace_names    (MetaScreen *screen);
00061 static void prefs_changed_callback (MetaPreference pref,
00062                                     gpointer       data);
00063 
00064 static void set_desktop_geometry_hint (MetaScreen *screen);
00065 static void set_desktop_viewport_hint (MetaScreen *screen);
00066 
00067 #ifdef HAVE_STARTUP_NOTIFICATION
00068 static void meta_screen_sn_event   (SnMonitorEvent *event,
00069                                     void           *user_data);
00070 #endif
00071 
00072 static int
00073 set_wm_check_hint (MetaScreen *screen)
00074 {
00075   unsigned long data[1];
00076 
00077   g_return_val_if_fail (screen->display->leader_window != None, 0);
00078   
00079   data[0] = screen->display->leader_window;
00080 
00081   XChangeProperty (screen->display->xdisplay, screen->xroot,
00082                    screen->display->atom__NET_SUPPORTING_WM_CHECK,
00083                    XA_WINDOW,
00084                    32, PropModeReplace, (guchar*) data, 1);
00085 
00086   return Success;
00087 }
00088 
00089 static int
00090 set_supported_hint (MetaScreen *screen)
00091 {
00092   Atom atoms[] = {
00093 #define EWMH_ATOMS_ONLY
00094 #define item(x)  screen->display->atom_##x,
00095 #include "atomnames.h"
00096 #undef item
00097 #undef EWMH_ATOMS_ONLY
00098   };
00099 
00100   XChangeProperty (screen->display->xdisplay, screen->xroot,
00101                    screen->display->atom__NET_SUPPORTED,
00102                    XA_ATOM,
00103                    32, PropModeReplace,
00104                    (guchar*) atoms, G_N_ELEMENTS(atoms));
00105   
00106   return Success;
00107 }
00108 
00109 static int
00110 set_wm_icon_size_hint (MetaScreen *screen)
00111 {
00112 #define N_VALS 6
00113   gulong vals[N_VALS];
00114 
00115   /* min width, min height, max w, max h, width inc, height inc */
00116   vals[0] = META_ICON_WIDTH;
00117   vals[1] = META_ICON_HEIGHT;
00118   vals[2] = META_ICON_WIDTH;
00119   vals[3] = META_ICON_HEIGHT;
00120   vals[4] = 0;
00121   vals[5] = 0;
00122   
00123   XChangeProperty (screen->display->xdisplay, screen->xroot,
00124                    screen->display->atom_WM_ICON_SIZE,
00125                    XA_CARDINAL,
00126                    32, PropModeReplace, (guchar*) vals, N_VALS);
00127   
00128   return Success;
00129 #undef N_VALS
00130 }
00131 
00132 static void
00133 reload_xinerama_infos (MetaScreen *screen)
00134 {
00135   MetaDisplay *display;
00136 
00137   {
00138     GList *tmp;
00139 
00140     tmp = screen->workspaces;
00141     while (tmp != NULL)
00142       {
00143         MetaWorkspace *space = tmp->data;
00144 
00145         meta_workspace_invalidate_work_area (space);
00146         
00147         tmp = tmp->next;
00148       }
00149   }
00150 
00151   display = screen->display;
00152   
00153   if (screen->xinerama_infos)
00154     g_free (screen->xinerama_infos);
00155   
00156   screen->xinerama_infos = NULL;
00157   screen->n_xinerama_infos = 0;
00158   screen->last_xinerama_index = 0;
00159 
00160   screen->display->xinerama_cache_invalidated = TRUE;
00161   
00162 #ifdef HAVE_XFREE_XINERAMA
00163   if (XineramaIsActive (display->xdisplay))
00164     {
00165       XineramaScreenInfo *infos;
00166       int n_infos;
00167       int i;
00168       
00169       n_infos = 0;
00170       infos = XineramaQueryScreens (display->xdisplay, &n_infos);
00171 
00172       meta_topic (META_DEBUG_XINERAMA,
00173                   "Found %d Xinerama screens on display %s\n",
00174                   n_infos, display->name);
00175 
00176       if (n_infos > 0)
00177         {
00178           screen->xinerama_infos = g_new (MetaXineramaScreenInfo, n_infos);
00179           screen->n_xinerama_infos = n_infos;
00180           
00181           i = 0;
00182           while (i < n_infos)
00183             {
00184               screen->xinerama_infos[i].number = infos[i].screen_number;
00185               screen->xinerama_infos[i].rect.x = infos[i].x_org;
00186               screen->xinerama_infos[i].rect.y = infos[i].y_org;
00187               screen->xinerama_infos[i].rect.width = infos[i].width;
00188               screen->xinerama_infos[i].rect.height = infos[i].height;
00189 
00190               meta_topic (META_DEBUG_XINERAMA,
00191                           "Xinerama %d is %d,%d %d x %d\n",
00192                           screen->xinerama_infos[i].number,
00193                           screen->xinerama_infos[i].rect.x,
00194                           screen->xinerama_infos[i].rect.y,
00195                           screen->xinerama_infos[i].rect.width,
00196                           screen->xinerama_infos[i].rect.height);
00197               
00198               ++i;
00199             }
00200         }
00201       
00202       meta_XFree (infos);
00203     }
00204   else
00205     {
00206       meta_topic (META_DEBUG_XINERAMA,
00207                   "No XFree86 Xinerama extension or XFree86 Xinerama inactive on display %s\n",
00208                   display->name);
00209     }
00210 #else
00211   meta_topic (META_DEBUG_XINERAMA,
00212               "Metacity compiled without XFree86 Xinerama support\n");
00213 #endif /* HAVE_XFREE_XINERAMA */
00214 
00215 #ifdef HAVE_SOLARIS_XINERAMA
00216   /* This code from GDK, Copyright (C) 2002 Sun Microsystems */
00217   if (screen->n_xinerama_infos == 0 &&
00218       XineramaGetState (screen->display->xdisplay,
00219                         screen->number))
00220     {
00221       XRectangle monitors[MAXFRAMEBUFFERS];
00222       unsigned char hints[16];
00223       int result;
00224       int n_monitors;
00225       int i;
00226 
00227       n_monitors = 0;
00228       result = XineramaGetInfo (screen->display->xdisplay,
00229                                 screen->number,
00230                                 monitors, hints,
00231                                 &n_monitors);
00232       /* Yes I know it should be Success but the current implementation 
00233        * returns the num of monitor
00234        */
00235       if (result > 0)
00236         {
00237           g_assert (n_monitors > 0);
00238           
00239           screen->xinerama_infos = g_new (MetaXineramaScreenInfo, n_monitors);
00240           screen->n_xinerama_infos = n_monitors;
00241           
00242           i = 0;
00243           while (i < n_monitors)
00244             {
00245               screen->xinerama_infos[i].number = i;
00246               screen->xinerama_infos[i].rect.x = monitors[i].x;
00247               screen->xinerama_infos[i].rect.y = monitors[i].y;
00248               screen->xinerama_infos[i].rect.width = monitors[i].width;
00249               screen->xinerama_infos[i].rect.height = monitors[i].height;
00250 
00251               meta_topic (META_DEBUG_XINERAMA,
00252                           "Xinerama %d is %d,%d %d x %d\n",
00253                           screen->xinerama_infos[i].number,
00254                           screen->xinerama_infos[i].rect.x,
00255                           screen->xinerama_infos[i].rect.y,
00256                           screen->xinerama_infos[i].rect.width,
00257                           screen->xinerama_infos[i].rect.height);              
00258               
00259               ++i;
00260             }
00261         }
00262     }
00263   else if (screen->n_xinerama_infos == 0)
00264     {
00265       meta_topic (META_DEBUG_XINERAMA,
00266                   "No Solaris Xinerama extension or Solaris Xinerama inactive on display %s\n",
00267                   display->name);
00268     }
00269 #else
00270   meta_topic (META_DEBUG_XINERAMA,
00271               "Metacity compiled without Solaris Xinerama support\n");
00272 #endif /* HAVE_SOLARIS_XINERAMA */
00273 
00274   
00275   /* If no Xinerama, fill in the single screen info so
00276    * we can use the field unconditionally
00277    */
00278   if (screen->n_xinerama_infos == 0)
00279     {
00280       if (g_getenv ("METACITY_DEBUG_XINERAMA"))
00281         {
00282           meta_topic (META_DEBUG_XINERAMA,
00283                       "Pretending a single monitor has two Xinerama screens\n");
00284           
00285           screen->xinerama_infos = g_new (MetaXineramaScreenInfo, 2);
00286           screen->n_xinerama_infos = 2;
00287           
00288           screen->xinerama_infos[0].number = 0;
00289           screen->xinerama_infos[0].rect = screen->rect;
00290           screen->xinerama_infos[0].rect.width = screen->rect.width / 2;
00291 
00292           screen->xinerama_infos[1].number = 1;
00293           screen->xinerama_infos[1].rect = screen->rect;
00294           screen->xinerama_infos[1].rect.x = screen->rect.width / 2;
00295           screen->xinerama_infos[1].rect.width = screen->rect.width / 2;
00296         }
00297       else
00298         {
00299           meta_topic (META_DEBUG_XINERAMA,
00300                       "No Xinerama screens, using default screen info\n");
00301           
00302           screen->xinerama_infos = g_new (MetaXineramaScreenInfo, 1);
00303           screen->n_xinerama_infos = 1;
00304           
00305           screen->xinerama_infos[0].number = 0;
00306           screen->xinerama_infos[0].rect = screen->rect;
00307         }
00308     }
00309 
00310   g_assert (screen->n_xinerama_infos > 0);
00311   g_assert (screen->xinerama_infos != NULL);
00312 }
00313 
00314 MetaScreen*
00315 meta_screen_new (MetaDisplay *display,
00316                  int          number,
00317                  guint32      timestamp)
00318 {
00319   MetaScreen *screen;
00320   Window xroot;
00321   Display *xdisplay;
00322   XWindowAttributes attr;
00323   Window new_wm_sn_owner;
00324   Window current_wm_sn_owner;
00325   gboolean replace_current_wm;
00326   Atom wm_sn_atom;
00327   char buf[128];
00328   guint32 manager_timestamp;
00329   gulong current_workspace;
00330   
00331   replace_current_wm = meta_get_replace_current_wm ();
00332   
00333   /* Only display->name, display->xdisplay, and display->error_traps
00334    * can really be used in this function, since normally screens are
00335    * created from the MetaDisplay constructor
00336    */
00337   
00338   xdisplay = display->xdisplay;
00339   
00340   meta_verbose ("Trying screen %d on display '%s'\n",
00341                 number, display->name);
00342 
00343   xroot = RootWindow (xdisplay, number);
00344 
00345   /* FVWM checks for None here, I don't know if this
00346    * ever actually happens
00347    */
00348   if (xroot == None)
00349     {
00350       meta_warning (_("Screen %d on display '%s' is invalid\n"),
00351                     number, display->name);
00352       return NULL;
00353     }
00354 
00355   sprintf (buf, "WM_S%d", number);
00356   wm_sn_atom = XInternAtom (xdisplay, buf, False);  
00357   
00358   current_wm_sn_owner = XGetSelectionOwner (xdisplay, wm_sn_atom);
00359 
00360   if (current_wm_sn_owner != None)
00361     {
00362       XSetWindowAttributes attrs;
00363       
00364       if (!replace_current_wm)
00365         {
00366           meta_warning (_("Screen %d on display \"%s\" already has a window manager; try using the --replace option to replace the current window manager.\n"),
00367                         number, display->name);
00368 
00369           return NULL;
00370         }
00371 
00372       /* We want to find out when the current selection owner dies */
00373       meta_error_trap_push_with_return (display);
00374       attrs.event_mask = StructureNotifyMask;
00375       XChangeWindowAttributes (xdisplay,
00376                                current_wm_sn_owner, CWEventMask, &attrs);
00377       if (meta_error_trap_pop_with_return (display, FALSE) != Success)
00378         current_wm_sn_owner = None; /* don't wait for it to die later on */
00379     }
00380 
00381   /* We need SelectionClear and SelectionRequest events on the new_wm_sn_owner,
00382    * but those cannot be masked, so we only need NoEventMask.
00383    */
00384   new_wm_sn_owner = meta_create_offscreen_window (xdisplay, xroot, NoEventMask);
00385 
00386   manager_timestamp = timestamp;
00387   
00388   XSetSelectionOwner (xdisplay, wm_sn_atom, new_wm_sn_owner,
00389                       manager_timestamp);
00390 
00391   if (XGetSelectionOwner (xdisplay, wm_sn_atom) != new_wm_sn_owner)
00392     {
00393       meta_warning (_("Could not acquire window manager selection on screen %d display \"%s\"\n"),
00394                     number, display->name);
00395 
00396       XDestroyWindow (xdisplay, new_wm_sn_owner);
00397       
00398       return NULL;
00399     }
00400   
00401   {
00402     /* Send client message indicating that we are now the WM */
00403     XClientMessageEvent ev;
00404     
00405     ev.type = ClientMessage;
00406     ev.window = xroot;
00407     ev.message_type = display->atom_MANAGER;
00408     ev.format = 32;
00409     ev.data.l[0] = manager_timestamp;
00410     ev.data.l[1] = wm_sn_atom;
00411 
00412     XSendEvent (xdisplay, xroot, False, StructureNotifyMask, (XEvent*)&ev);
00413   }
00414 
00415   /* Wait for old window manager to go away */
00416   if (current_wm_sn_owner != None)
00417     {
00418       XEvent event;
00419 
00420       /* We sort of block infinitely here which is probably lame. */
00421       
00422       meta_verbose ("Waiting for old window manager to exit\n");
00423       do
00424         {
00425           XWindowEvent (xdisplay, current_wm_sn_owner,
00426                         StructureNotifyMask, &event);
00427         }
00428       while (event.type != DestroyNotify);
00429     }
00430   
00431   /* select our root window events */
00432   meta_error_trap_push_with_return (display);
00433 
00434   /* We need to or with the existing event mask since
00435    * gtk+ may be interested in other events.
00436    */
00437   XGetWindowAttributes (xdisplay, xroot, &attr);
00438   XSelectInput (xdisplay,
00439                 xroot,
00440                 SubstructureRedirectMask | SubstructureNotifyMask |
00441                 ColormapChangeMask | PropertyChangeMask |
00442                 LeaveWindowMask | EnterWindowMask |
00443                 KeyPressMask | KeyReleaseMask |
00444                 FocusChangeMask | StructureNotifyMask |
00445 #ifdef HAVE_COMPOSITE_EXTENSIONS
00446                 ExposureMask |
00447 #endif
00448                 attr.your_event_mask);
00449   if (meta_error_trap_pop_with_return (display, FALSE) != Success)
00450     {
00451       meta_warning (_("Screen %d on display \"%s\" already has a window manager\n"),
00452                     number, display->name);
00453 
00454       XDestroyWindow (xdisplay, new_wm_sn_owner);
00455       
00456       return NULL;
00457     }
00458   
00459   screen = g_new (MetaScreen, 1);
00460   screen->closing = 0;
00461   
00462   screen->display = display;
00463   screen->number = number;
00464   screen->screen_name = get_screen_name (display, number);
00465   screen->xscreen = ScreenOfDisplay (xdisplay, number);
00466   screen->xroot = xroot;
00467   screen->rect.x = screen->rect.y = 0;
00468   screen->rect.width = WidthOfScreen (screen->xscreen);
00469   screen->rect.height = HeightOfScreen (screen->xscreen);
00470   screen->current_cursor = -1; /* invalid/unset */
00471   screen->default_xvisual = DefaultVisualOfScreen (screen->xscreen);
00472   screen->default_depth = DefaultDepthOfScreen (screen->xscreen);
00473   screen->flash_window = None;
00474 
00475   screen->wm_sn_selection_window = new_wm_sn_owner;
00476   screen->wm_sn_atom = wm_sn_atom;
00477   screen->wm_sn_timestamp = manager_timestamp;
00478 
00479 #ifdef HAVE_COMPOSITE_EXTENSIONS
00480   screen->wm_cm_selection_window = meta_create_offscreen_window (xdisplay, 
00481                                                                  xroot, 
00482                                                                  NoEventMask);
00483 #endif
00484   screen->work_area_idle = 0;
00485 
00486   screen->active_workspace = NULL;
00487   screen->workspaces = NULL;
00488   screen->rows_of_workspaces = 1;
00489   screen->columns_of_workspaces = -1;
00490   screen->vertical_workspaces = FALSE;
00491   screen->starting_corner = META_SCREEN_TOPLEFT;
00492   screen->compositor_data = NULL;
00493 
00494   {
00495     XFontStruct *font_info;
00496     XGCValues gc_values;
00497     gulong value_mask = 0;
00498     
00499     gc_values.subwindow_mode = IncludeInferiors;
00500     value_mask |= GCSubwindowMode;
00501     gc_values.function = GXinvert;
00502     value_mask |= GCFunction;
00503     gc_values.line_width = META_WIREFRAME_XOR_LINE_WIDTH;
00504     value_mask |= GCLineWidth;
00505 
00506     font_info = XLoadQueryFont (screen->display->xdisplay, "fixed");
00507 
00508     if (font_info != NULL)
00509       {
00510         gc_values.font = font_info->fid;
00511         value_mask |= GCFont;
00512         XFreeFontInfo (NULL, font_info, 1);
00513       }
00514     else
00515       meta_warning ("xserver doesn't have 'fixed' font.\n");
00516 
00517     screen->root_xor_gc = XCreateGC (screen->display->xdisplay,
00518                                      screen->xroot,
00519                                      value_mask,
00520                                      &gc_values);
00521   }
00522   
00523   screen->xinerama_infos = NULL;
00524   screen->n_xinerama_infos = 0;
00525   screen->last_xinerama_index = 0;  
00526   
00527   reload_xinerama_infos (screen);
00528   
00529   meta_screen_set_cursor (screen, META_CURSOR_DEFAULT);
00530 
00531   /* Handle creating a no_focus_window for this screen */  
00532   screen->no_focus_window =
00533     meta_create_offscreen_window (display->xdisplay,
00534                                   screen->xroot,
00535                                   FocusChangeMask|KeyPressMask|KeyReleaseMask);
00536   XMapWindow (display->xdisplay, screen->no_focus_window);
00537   /* Done with no_focus_window stuff */
00538   
00539   set_wm_icon_size_hint (screen);
00540   
00541   set_supported_hint (screen);
00542   
00543   set_wm_check_hint (screen);
00544 
00545   set_desktop_viewport_hint (screen);
00546 
00547   set_desktop_geometry_hint (screen);
00548 
00549   meta_screen_update_workspace_layout (screen);
00550 
00551   /* Get current workspace */
00552   current_workspace = 0;
00553   if (meta_prop_get_cardinal (screen->display,
00554                               screen->xroot,
00555                               screen->display->atom__NET_CURRENT_DESKTOP,
00556                               &current_workspace))
00557     meta_verbose ("Read existing _NET_CURRENT_DESKTOP = %d\n",
00558                   (int) current_workspace);
00559   else
00560     meta_verbose ("No _NET_CURRENT_DESKTOP present\n");
00561   
00562   /* Screens must have at least one workspace at all times,
00563    * so create that required workspace.
00564    */
00565   meta_workspace_activate (meta_workspace_new (screen), timestamp);
00566   update_num_workspaces (screen, timestamp);
00567   
00568   set_workspace_names (screen);
00569 
00570   screen->all_keys_grabbed = FALSE;
00571   screen->keys_grabbed = FALSE;
00572   meta_screen_grab_keys (screen);
00573 
00574   screen->ui = meta_ui_new (screen->display->xdisplay,
00575                             screen->xscreen);
00576 
00577   screen->tab_popup = NULL;
00578   
00579   screen->stack = meta_stack_new (screen);
00580 
00581   meta_prefs_add_listener (prefs_changed_callback, screen);
00582 
00583 #ifdef HAVE_STARTUP_NOTIFICATION
00584   screen->sn_context =
00585     sn_monitor_context_new (screen->display->sn_display,
00586                             screen->number,
00587                             meta_screen_sn_event,
00588                             screen,
00589                             NULL);
00590   screen->startup_sequences = NULL;
00591   screen->startup_sequence_timeout = 0;
00592 #endif
00593 
00594   /* Switch to the _NET_CURRENT_DESKTOP workspace */
00595   {
00596     MetaWorkspace *space;
00597     
00598     space = meta_screen_get_workspace_by_index (screen,
00599                                                 current_workspace);
00600     
00601     if (space != NULL)
00602       meta_workspace_activate (space, timestamp);
00603   }
00604 
00605   meta_verbose ("Added screen %d ('%s') root 0x%lx\n",
00606                 screen->number, screen->screen_name, screen->xroot);
00607   
00608   return screen;
00609 }
00610 
00611 void
00612 meta_screen_free (MetaScreen *screen,
00613                   guint32     timestamp)
00614 {
00615   MetaDisplay *display;
00616   XGCValues gc_values = { 0 };
00617 
00618   display = screen->display;
00619 
00620   screen->closing += 1;
00621   
00622   meta_display_grab (display);
00623 
00624   if (screen->display->compositor)
00625     {
00626       meta_compositor_unmanage_screen (screen->display->compositor,
00627                                        screen);
00628     }
00629   
00630   meta_display_unmanage_windows_for_screen (display, screen, timestamp);
00631   
00632   meta_prefs_remove_listener (prefs_changed_callback, screen);
00633   
00634   meta_screen_ungrab_keys (screen);
00635 
00636 #ifdef HAVE_STARTUP_NOTIFICATION
00637   g_slist_foreach (screen->startup_sequences,
00638                    (GFunc) sn_startup_sequence_unref, NULL);
00639   g_slist_free (screen->startup_sequences);
00640   screen->startup_sequences = NULL;
00641 
00642   if (screen->startup_sequence_timeout != 0)
00643     {
00644       g_source_remove (screen->startup_sequence_timeout);
00645       screen->startup_sequence_timeout = 0;
00646     }
00647   if (screen->sn_context)
00648     {
00649       sn_monitor_context_unref (screen->sn_context);
00650       screen->sn_context = NULL;
00651     }
00652 #endif
00653   
00654   meta_ui_free (screen->ui);
00655 
00656   meta_stack_free (screen->stack);
00657 
00658   meta_error_trap_push_with_return (screen->display);
00659   XSelectInput (screen->display->xdisplay, screen->xroot, 0);
00660   if (meta_error_trap_pop_with_return (screen->display, FALSE) != Success)
00661     meta_warning (_("Could not release screen %d on display \"%s\"\n"),
00662                   screen->number, screen->display->name);
00663 
00664   XDestroyWindow (screen->display->xdisplay,
00665                   screen->wm_sn_selection_window);
00666   
00667   if (screen->work_area_idle != 0)
00668     g_source_remove (screen->work_area_idle);
00669 
00670 
00671   if (XGetGCValues (screen->display->xdisplay,
00672                     screen->root_xor_gc,
00673                     GCFont,
00674                     &gc_values))
00675     {
00676       XUnloadFont (screen->display->xdisplay,
00677                    gc_values.font);
00678     }
00679 
00680   XFreeGC (screen->display->xdisplay,
00681            screen->root_xor_gc);
00682   
00683   if (screen->xinerama_infos)
00684     g_free (screen->xinerama_infos);
00685   
00686   g_free (screen->screen_name);
00687   g_free (screen);
00688 
00689   XFlush (display->xdisplay);
00690   meta_display_ungrab (display);
00691 }
00692 
00693 typedef struct
00694 {
00695   Window                xwindow;
00696   XWindowAttributes     attrs;
00697 } WindowInfo;
00698 
00699 static GList *
00700 list_windows (MetaScreen *screen)
00701 {
00702   Window ignored1, ignored2;
00703   Window *children;
00704   guint n_children, i;
00705   GList *result;
00706 
00707   XQueryTree (screen->display->xdisplay,
00708               screen->xroot,
00709               &ignored1, &ignored2, &children, &n_children);
00710 
00711   result = NULL;
00712   for (i = 0; i < n_children; ++i)
00713     {
00714       WindowInfo *info = g_new0 (WindowInfo, 1);
00715 
00716       meta_error_trap_push_with_return (screen->display);
00717       
00718       XGetWindowAttributes (screen->display->xdisplay,
00719                             children[i], &info->attrs);
00720 
00721       if (meta_error_trap_pop_with_return (screen->display, TRUE))
00722         {
00723           meta_verbose ("Failed to get attributes for window 0x%lx\n",
00724                         children[i]);
00725           g_free (info);
00726         }
00727       else
00728         {
00729           info->xwindow = children[i];
00730         }
00731 
00732       result = g_list_prepend (result, info);
00733     }
00734 
00735   if (children)
00736     XFree (children);
00737 
00738   return g_list_reverse (result);
00739 }
00740 
00741 void
00742 meta_screen_manage_all_windows (MetaScreen *screen)
00743 {
00744   GList *windows;
00745   GList *list;
00746 
00747   meta_display_grab (screen->display);
00748   
00749   windows = list_windows (screen);
00750 
00751   meta_stack_freeze (screen->stack);
00752   for (list = windows; list != NULL; list = list->next)
00753     {
00754       WindowInfo *info = list->data;
00755       MetaWindow *window;
00756 
00757       window = meta_window_new_with_attrs (screen->display, info->xwindow, TRUE,
00758                                            &info->attrs);
00759       if (info->xwindow == screen->no_focus_window ||
00760           info->xwindow == screen->flash_window ||
00761 #ifdef HAVE_COMPOSITE_EXTENSIONS
00762           info->xwindow == screen->wm_cm_selection_window ||
00763 #endif
00764           info->xwindow == screen->wm_sn_selection_window) {
00765         meta_verbose ("Not managing our own windows\n");
00766         continue;
00767       }
00768 
00769       if (screen->display->compositor)
00770         meta_compositor_add_window (screen->display->compositor, window,
00771                                     info->xwindow, &info->attrs);
00772     }
00773   meta_stack_thaw (screen->stack);
00774 
00775   g_list_foreach (windows, (GFunc)g_free, NULL);
00776   g_list_free (windows);
00777 
00778   meta_display_ungrab (screen->display);
00779 }
00780 
00781 void
00782 meta_screen_composite_all_windows (MetaScreen *screen)
00783 {
00784 #ifdef HAVE_COMPOSITE_EXTENSIONS
00785   MetaDisplay *display;
00786   GList *windows, *list;
00787 
00788   display = screen->display;
00789   if (!display->compositor)
00790     return;
00791 
00792   windows = list_windows (screen);
00793 
00794   meta_stack_freeze (screen->stack);
00795 
00796   for (list = windows; list != NULL; list = list->next)
00797     {
00798       WindowInfo *info = list->data;
00799 
00800       if (info->xwindow == screen->no_focus_window ||
00801           info->xwindow == screen->flash_window ||
00802           info->xwindow == screen->wm_sn_selection_window ||
00803           info->xwindow == screen->wm_cm_selection_window) {
00804         meta_verbose ("Not managing our own windows\n");
00805         continue;
00806       }
00807 
00808       meta_compositor_add_window (display->compositor,
00809                                   meta_display_lookup_x_window (display,
00810                                                                 info->xwindow),
00811                                   info->xwindow, &info->attrs);
00812     }
00813 
00814   meta_stack_thaw (screen->stack);
00815 
00816   g_list_foreach (windows, (GFunc)g_free, NULL);
00817   g_list_free (windows);
00818 #endif
00819 }
00820 
00821 MetaScreen*
00822 meta_screen_for_x_screen (Screen *xscreen)
00823 {
00824   MetaDisplay *display;
00825   
00826   display = meta_display_for_x_display (DisplayOfScreen (xscreen));
00827 
00828   if (display == NULL)
00829     return NULL;
00830   
00831   return meta_display_screen_for_x_screen (display, xscreen);
00832 }
00833 
00834 static void
00835 prefs_changed_callback (MetaPreference pref,
00836                         gpointer       data)
00837 {
00838   MetaScreen *screen = data;
00839   
00840   if (pref == META_PREF_NUM_WORKSPACES)
00841     {
00842       /* GConf doesn't provide timestamps, but luckily update_num_workspaces
00843        * often doesn't need it...
00844        */
00845       guint32 timestamp = 
00846         meta_display_get_current_time_roundtrip (screen->display);
00847       update_num_workspaces (screen, timestamp);
00848     }
00849   else if (pref == META_PREF_FOCUS_MODE)
00850     {
00851       update_focus_mode (screen);
00852     }
00853   else if (pref == META_PREF_WORKSPACE_NAMES)
00854     {
00855       set_workspace_names (screen);
00856     }
00857 }
00858 
00859 
00860 static char*
00861 get_screen_name (MetaDisplay *display,
00862                  int          number)
00863 {
00864   char *p;
00865   char *dname;
00866   char *scr;
00867   
00868   /* DisplayString gives us a sort of canonical display,
00869    * vs. the user-entered name from XDisplayName()
00870    */
00871   dname = g_strdup (DisplayString (display->xdisplay));
00872 
00873   /* Change display name to specify this screen.
00874    */
00875   p = strrchr (dname, ':');
00876   if (p)
00877     {
00878       p = strchr (p, '.');
00879       if (p)
00880         *p = '\0';
00881     }
00882   
00883   scr = g_strdup_printf ("%s.%d", dname, number);
00884 
00885   g_free (dname);
00886 
00887   return scr;
00888 }
00889 
00890 static gint
00891 ptrcmp (gconstpointer a, gconstpointer b)
00892 {
00893   if (a < b)
00894     return -1;
00895   else if (a > b)
00896     return 1;
00897   else
00898     return 0;
00899 }
00900 
00901 static void
00902 listify_func (gpointer key, gpointer value, gpointer data)
00903 {
00904   GSList **listp;
00905   
00906   listp = data;
00907 
00908   *listp = g_slist_prepend (*listp, value);
00909 }
00910 
00911 void
00912 meta_screen_foreach_window (MetaScreen *screen,
00913                             MetaScreenWindowFunc func,
00914                             gpointer data)
00915 {
00916   GSList *winlist;
00917   GSList *tmp;
00918 
00919   /* If we end up doing this often, just keeping a list
00920    * of windows might be sensible.
00921    */
00922   
00923   winlist = NULL;
00924   g_hash_table_foreach (screen->display->window_ids,
00925                         listify_func,
00926                         &winlist);
00927   
00928   winlist = g_slist_sort (winlist, ptrcmp);
00929   
00930   tmp = winlist;
00931   while (tmp != NULL)
00932     {
00933       /* If the next node doesn't contain this window
00934        * a second time, delete the window.
00935        */
00936       if (tmp->next == NULL ||
00937           (tmp->next && tmp->next->data != tmp->data))
00938         {
00939           MetaWindow *window = tmp->data;
00940 
00941           if (window->screen == screen)
00942             (* func) (screen, window, data);
00943         }
00944       
00945       tmp = tmp->next;
00946     }
00947   g_slist_free (winlist);
00948 }
00949 
00950 static void
00951 queue_draw (MetaScreen *screen, MetaWindow *window, gpointer data)
00952 {
00953   if (window->frame)
00954     meta_frame_queue_draw (window->frame);
00955 }
00956 
00957 void
00958 meta_screen_queue_frame_redraws (MetaScreen *screen)
00959 {
00960   meta_screen_foreach_window (screen, queue_draw, NULL);
00961 }
00962 
00963 static void
00964 queue_resize (MetaScreen *screen, MetaWindow *window, gpointer data)
00965 {
00966   meta_window_queue (window, META_QUEUE_MOVE_RESIZE);
00967 }
00968 
00969 void
00970 meta_screen_queue_window_resizes (MetaScreen *screen)
00971 {
00972   meta_screen_foreach_window (screen, queue_resize, NULL);
00973 }
00974 
00975 int
00976 meta_screen_get_n_workspaces (MetaScreen *screen)
00977 {
00978   return g_list_length (screen->workspaces);
00979 }
00980 
00981 MetaWorkspace*
00982 meta_screen_get_workspace_by_index (MetaScreen  *screen,
00983                                     int          idx)
00984 {
00985   GList *tmp;
00986   int i;
00987 
00988   /* should be robust, idx is maybe from an app */
00989   if (idx < 0)
00990     return NULL;
00991   
00992   i = 0;
00993   tmp = screen->workspaces;
00994   while (tmp != NULL)
00995     {
00996       MetaWorkspace *w = tmp->data;
00997 
00998       if (i == idx)
00999         return w;
01000 
01001       ++i;
01002       tmp = tmp->next;
01003     }
01004 
01005   return NULL;
01006 }
01007 
01008 static void
01009 set_number_of_spaces_hint (MetaScreen *screen,
01010                            int         n_spaces)
01011 {
01012   unsigned long data[1];
01013 
01014   if (screen->closing > 0)
01015     return;
01016 
01017   data[0] = n_spaces;
01018 
01019   meta_verbose ("Setting _NET_NUMBER_OF_DESKTOPS to %lu\n", data[0]);
01020 
01021   meta_error_trap_push (screen->display);
01022   XChangeProperty (screen->display->xdisplay, screen->xroot,
01023                    screen->display->atom__NET_NUMBER_OF_DESKTOPS,
01024                    XA_CARDINAL,
01025                    32, PropModeReplace, (guchar*) data, 1);
01026   meta_error_trap_pop (screen->display, FALSE);
01027 }
01028 
01029 static void
01030 set_desktop_geometry_hint (MetaScreen *screen)
01031 {
01032   unsigned long data[2];
01033 
01034   if (screen->closing > 0)
01035     return;
01036 
01037   data[0] = screen->rect.width;
01038   data[1] = screen->rect.height;
01039 
01040   meta_verbose ("Setting _NET_DESKTOP_GEOMETRY to %lu, %lu\n", data[0], data[1]);
01041 
01042   meta_error_trap_push (screen->display);
01043   XChangeProperty (screen->display->xdisplay, screen->xroot,
01044                    screen->display->atom__NET_DESKTOP_GEOMETRY,
01045                    XA_CARDINAL,
01046                    32, PropModeReplace, (guchar*) data, 2);
01047   meta_error_trap_pop (screen->display, FALSE);
01048 }
01049 
01050 static void
01051 set_desktop_viewport_hint (MetaScreen *screen)
01052 {
01053   unsigned long data[2];
01054 
01055   if (screen->closing > 0)
01056     return;
01057 
01058   /*
01059    * Metacity does not implement viewports, so this is a fixed 0,0
01060    */
01061   data[0] = 0;
01062   data[1] = 0;
01063 
01064   meta_verbose ("Setting _NET_DESKTOP_VIEWPORT to 0, 0\n");
01065 
01066   meta_error_trap_push (screen->display);
01067   XChangeProperty (screen->display->xdisplay, screen->xroot,
01068                    screen->display->atom__NET_DESKTOP_VIEWPORT,
01069                    XA_CARDINAL,
01070                    32, PropModeReplace, (guchar*) data, 2);
01071   meta_error_trap_pop (screen->display, FALSE);
01072 }
01073 
01074 static void
01075 update_num_workspaces (MetaScreen *screen,
01076                        guint32     timestamp)
01077 {
01078   int new_num;
01079   GList *tmp;
01080   int i;
01081   GList *extras;
01082   MetaWorkspace *last_remaining;
01083   gboolean need_change_space;
01084   
01085   new_num = meta_prefs_get_num_workspaces ();
01086 
01087   g_assert (new_num > 0);
01088 
01089   last_remaining = NULL;
01090   extras = NULL;
01091   i = 0;
01092   tmp = screen->workspaces;
01093   while (tmp != NULL)
01094     {
01095       MetaWorkspace *w = tmp->data;
01096 
01097       if (i >= new_num)
01098         extras = g_list_prepend (extras, w);
01099       else
01100         last_remaining = w;
01101           
01102       ++i;
01103       tmp = tmp->next;
01104     }
01105 
01106   g_assert (last_remaining);
01107   
01108   /* Get rid of the extra workspaces by moving all their windows
01109    * to last_remaining, then activating last_remaining if
01110    * one of the removed workspaces was active. This will be a bit
01111    * wacky if the config tool for changing number of workspaces
01112    * is on a removed workspace ;-)
01113    */
01114   need_change_space = FALSE;
01115   tmp = extras;
01116   while (tmp != NULL)
01117     {
01118       MetaWorkspace *w = tmp->data;
01119 
01120       meta_workspace_relocate_windows (w, last_remaining);      
01121 
01122       if (w == screen->active_workspace)
01123         need_change_space = TRUE;
01124       
01125       tmp = tmp->next;
01126     }
01127 
01128   if (need_change_space)
01129     meta_workspace_activate (last_remaining, timestamp);
01130 
01131   /* Should now be safe to free the workspaces */
01132   tmp = extras;
01133   while (tmp != NULL)
01134     {
01135       MetaWorkspace *w = tmp->data;
01136 
01137       g_assert (w->windows == NULL);
01138       meta_workspace_free (w);
01139       
01140       tmp = tmp->next;
01141     }
01142   
01143   g_list_free (extras);
01144   
01145   while (i < new_num)
01146     {
01147       meta_workspace_new (screen);
01148       ++i;
01149     }
01150 
01151   set_number_of_spaces_hint (screen, new_num);
01152 
01153   meta_screen_queue_workarea_recalc (screen);
01154 }
01155 
01156 static void
01157 update_focus_mode (MetaScreen *screen)
01158 {
01159   /* nothing to do anymore */ ;
01160 }
01161 
01162 void
01163 meta_screen_set_cursor (MetaScreen *screen,
01164                         MetaCursor  cursor)
01165 {
01166   Cursor xcursor;
01167 
01168   if (cursor == screen->current_cursor)
01169     return;
01170 
01171   screen->current_cursor = cursor;
01172   
01173   xcursor = meta_display_create_x_cursor (screen->display, cursor);
01174   XDefineCursor (screen->display->xdisplay, screen->xroot, xcursor);
01175   XFlush (screen->display->xdisplay);
01176   XFreeCursor (screen->display->xdisplay, xcursor);
01177 }
01178 
01179 void
01180 meta_screen_update_cursor (MetaScreen *screen)
01181 {
01182   Cursor xcursor;
01183 
01184   xcursor = meta_display_create_x_cursor (screen->display, 
01185                                           screen->current_cursor);
01186   XDefineCursor (screen->display->xdisplay, screen->xroot, xcursor);
01187   XFlush (screen->display->xdisplay);
01188   XFreeCursor (screen->display->xdisplay, xcursor);
01189 }
01190 
01191 #define MAX_PREVIEW_SIZE 150.0
01192 
01193 static GdkPixbuf *
01194 get_window_pixbuf (MetaWindow *window,
01195                    int        *width,
01196                    int        *height)
01197 {
01198   Pixmap pmap;
01199   GdkPixbuf *pixbuf, *scaled;
01200   double ratio;
01201 
01202   pmap = meta_compositor_get_window_pixmap (window->display->compositor,
01203                                             window);
01204   if (pmap == None)
01205     return NULL;
01206 
01207   pixbuf = meta_ui_get_pixbuf_from_pixmap (pmap);
01208   if (pixbuf == NULL) 
01209     return NULL;
01210 
01211   *width = gdk_pixbuf_get_width (pixbuf);
01212   *height = gdk_pixbuf_get_height (pixbuf);
01213 
01214   /* Scale pixbuf to max dimension MAX_PREVIEW_SIZE */
01215   if (*width > *height)
01216     {
01217       ratio = ((double) *width) / MAX_PREVIEW_SIZE;
01218       *width = (int) MAX_PREVIEW_SIZE;
01219       *height = (int) (((double) *height) / ratio);
01220     }
01221   else
01222     {
01223       ratio = ((double) *height) / MAX_PREVIEW_SIZE;
01224       *height = (int) MAX_PREVIEW_SIZE;
01225       *width = (int) (((double) *width) / ratio);
01226     }
01227 
01228   scaled = gdk_pixbuf_scale_simple (pixbuf, *width, *height,
01229                                     GDK_INTERP_BILINEAR);
01230   g_object_unref (pixbuf);
01231   return scaled;
01232 }
01233                                          
01234 void
01235 meta_screen_ensure_tab_popup (MetaScreen      *screen,
01236                               MetaTabList      list_type,
01237                               MetaTabShowType  show_type)
01238 {
01239   MetaTabEntry *entries;
01240   GList *tab_list;
01241   GList *tmp;
01242   int len;
01243   int i;
01244 
01245   if (screen->tab_popup)
01246     return;
01247 
01248   tab_list = meta_display_get_tab_list (screen->display,
01249                                         list_type,
01250                                         screen,
01251                                         screen->active_workspace);
01252   
01253   len = g_list_length (tab_list);
01254 
01255   entries = g_new (MetaTabEntry, len + 1);
01256   entries[len].key = NULL;
01257   entries[len].title = NULL;
01258   entries[len].icon = NULL;
01259   
01260   i = 0;
01261   tmp = tab_list;
01262   while (i < len)
01263     {
01264       MetaWindow *window;
01265       MetaRectangle r;
01266       GdkPixbuf *win_pixbuf;
01267       int width, height;
01268 
01269       window = tmp->data;
01270       
01271       entries[i].key = (MetaTabEntryKey) window->xwindow;
01272       entries[i].title = window->title;
01273 
01274       win_pixbuf = get_window_pixbuf (window, &width, &height);
01275       if (win_pixbuf == NULL)
01276         entries[i].icon = g_object_ref (window->icon);
01277       else
01278         {
01279           int icon_width, icon_height, t_width, t_height;
01280 #define ICON_OFFSET 6
01281 
01282           icon_width = gdk_pixbuf_get_width (window->icon);
01283           icon_height = gdk_pixbuf_get_height (window->icon);
01284 
01285           t_width = width + ICON_OFFSET;
01286           t_height = height + ICON_OFFSET;
01287 
01288           entries[i].icon = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8,
01289                                             t_width, t_height);
01290           gdk_pixbuf_fill (entries[i].icon, 0x00000000);
01291           gdk_pixbuf_copy_area (win_pixbuf, 0, 0, width, height,
01292                                 entries[i].icon, 0, 0);
01293           g_object_unref (win_pixbuf);
01294           gdk_pixbuf_composite (window->icon, entries[i].icon, 
01295                                 t_width - icon_width, t_height - icon_height,
01296                                 icon_width, icon_height,
01297                                 t_width - icon_width, t_height - icon_height, 
01298                                 1.0, 1.0, GDK_INTERP_BILINEAR, 255);
01299         }
01300                                 
01301       entries[i].blank = FALSE;
01302       entries[i].hidden = !meta_window_showing_on_its_workspace (window);
01303       entries[i].demands_attention = window->wm_state_demands_attention;
01304       
01305       if (show_type == META_TAB_SHOW_INSTANTLY ||
01306           !entries[i].hidden                   ||
01307           !meta_window_get_icon_geometry (window, &r))
01308         meta_window_get_outer_rect (window, &r);
01309       
01310       entries[i].rect = r;
01311 
01312       /* Find inside of highlight rectangle to be used when window is
01313        * outlined for tabbing.  This should be the size of the
01314        * east/west frame, and the size of the south frame, on those
01315        * sides.  On the top it should be the size of the south frame
01316        * edge.
01317        */
01318 #define OUTLINE_WIDTH 5
01319       /* Top side */
01320       if (!entries[i].hidden &&
01321           window->frame && window->frame->bottom_height > 0 &&
01322           window->frame->child_y >= window->frame->bottom_height)
01323         entries[i].inner_rect.y = window->frame->bottom_height;
01324       else
01325         entries[i].inner_rect.y = OUTLINE_WIDTH;
01326 
01327       /* Bottom side */
01328       if (!entries[i].hidden &&
01329           window->frame && window->frame->bottom_height != 0)
01330         entries[i].inner_rect.height = r.height
01331           - entries[i].inner_rect.y - window->frame->bottom_height;
01332       else
01333         entries[i].inner_rect.height = r.height
01334           - entries[i].inner_rect.y - OUTLINE_WIDTH;
01335 
01336       /* Left side */
01337       if (!entries[i].hidden && window->frame && window->frame->child_x != 0)
01338         entries[i].inner_rect.x = window->frame->child_x;
01339       else
01340         entries[i].inner_rect.x = OUTLINE_WIDTH;
01341 
01342       /* Right side */
01343       if (!entries[i].hidden &&
01344           window->frame && window->frame->right_width != 0)
01345         entries[i].inner_rect.width = r.width
01346           - entries[i].inner_rect.x - window->frame->right_width;
01347       else
01348         entries[i].inner_rect.width = r.width
01349           - entries[i].inner_rect.x - OUTLINE_WIDTH;
01350       
01351       ++i;
01352       tmp = tmp->next;
01353     }
01354 
01355   screen->tab_popup = meta_ui_tab_popup_new (entries, 
01356                                              screen->number,
01357                                              len,
01358                                              5, /* FIXME */
01359                                              TRUE);
01360 
01361   for (i = 0; i < len; i++) 
01362     g_object_unref (entries[i].icon);
01363 
01364   g_free (entries);
01365 
01366   g_list_free (tab_list);
01367   
01368   /* don't show tab popup, since proper window isn't selected yet */
01369 }
01370 
01371 void
01372 meta_screen_ensure_workspace_popup (MetaScreen *screen)
01373 {
01374   MetaTabEntry *entries;
01375   int len;
01376   int i;
01377   MetaWorkspaceLayout layout;
01378   int n_workspaces;
01379   int current_workspace;
01380   
01381   if (screen->tab_popup)
01382     return;
01383 
01384   current_workspace = meta_workspace_index (screen->active_workspace);
01385   n_workspaces = meta_screen_get_n_workspaces (screen);
01386 
01387   meta_screen_calc_workspace_layout (screen, n_workspaces,
01388                                      current_workspace, &layout);
01389 
01390   len = layout.grid_area;
01391   
01392   entries = g_new (MetaTabEntry, len + 1);
01393   entries[len].key = NULL;
01394   entries[len].title = NULL;
01395   entries[len].icon = NULL;
01396 
01397   i = 0;
01398   while (i < len)
01399     {
01400       if (layout.grid[i] >= 0)
01401         {
01402           MetaWorkspace *workspace;
01403           
01404           workspace = meta_screen_get_workspace_by_index (screen,
01405                                                           layout.grid[i]);
01406           
01407           entries[i].key = (MetaTabEntryKey) workspace;
01408           entries[i].title = meta_workspace_get_name (workspace);
01409           entries[i].icon = NULL;
01410           entries[i].blank = FALSE;
01411           
01412           g_assert (entries[i].title != NULL);
01413         }
01414       else
01415         {
01416           entries[i].key = NULL;
01417           entries[i].title = NULL;
01418           entries[i].icon = NULL;
01419           entries[i].blank = TRUE;
01420         }
01421       entries[i].hidden = FALSE;
01422       entries[i].demands_attention = FALSE;
01423 
01424       ++i;
01425     }
01426 
01427   screen->tab_popup = meta_ui_tab_popup_new (entries, 
01428                                              screen->number,
01429                                              len,
01430                                              layout.cols,
01431                                              FALSE);      
01432 
01433   g_free (entries);
01434   meta_screen_free_workspace_layout (&layout);
01435 
01436   /* don't show tab popup, since proper space isn't selected yet */
01437 }
01438 
01439 MetaWindow*
01440 meta_screen_get_mouse_window (MetaScreen  *screen,
01441                               MetaWindow  *not_this_one)
01442 {
01443   MetaWindow *window;
01444   Window root_return, child_return;
01445   int root_x_return, root_y_return;
01446   int win_x_return, win_y_return;
01447   unsigned int mask_return;
01448   
01449   if (not_this_one)
01450     meta_topic (META_DEBUG_FOCUS,
01451                 "Focusing mouse window excluding %s\n", not_this_one->desc);
01452 
01453   meta_error_trap_push (screen->display);
01454   XQueryPointer (screen->display->xdisplay,
01455                  screen->xroot,
01456                  &root_return,
01457                  &child_return,
01458                  &root_x_return,
01459                  &root_y_return,
01460                  &win_x_return,
01461                  &win_y_return,
01462                  &mask_return);
01463   meta_error_trap_pop (screen->display, TRUE);
01464 
01465   window = meta_stack_get_default_focus_window_at_point (screen->stack,
01466                                                          screen->active_workspace,
01467                                                          not_this_one,
01468                                                          root_x_return,
01469                                                          root_y_return);
01470 
01471   return window;
01472 }
01473 
01474 const MetaXineramaScreenInfo*
01475 meta_screen_get_xinerama_for_rect (MetaScreen    *screen,
01476                                    MetaRectangle *rect)
01477 {
01478   int i;
01479   int best_xinerama, xinerama_score;
01480 
01481   if (screen->n_xinerama_infos == 1)
01482     return &screen->xinerama_infos[0];
01483 
01484   best_xinerama = 0;
01485   xinerama_score = 0;
01486 
01487   for (i = 0; i < screen->n_xinerama_infos; i++)
01488     {
01489       MetaRectangle dest;
01490       if (meta_rectangle_intersect (&screen->xinerama_infos[i].rect,
01491                                     rect,
01492                                     &dest))
01493         {
01494           int cur = meta_rectangle_area (&dest);
01495           if (cur > xinerama_score)
01496             {
01497               xinerama_score = cur;
01498               best_xinerama = i;
01499             }
01500         }
01501     }
01502 
01503   return &screen->xinerama_infos[best_xinerama];
01504 }
01505 
01506 const MetaXineramaScreenInfo*
01507 meta_screen_get_xinerama_for_window (MetaScreen *screen,
01508                                      MetaWindow *window)
01509 {
01510   MetaRectangle window_rect;
01511   
01512   meta_window_get_outer_rect (window, &window_rect);
01513 
01514   return meta_screen_get_xinerama_for_rect (screen, &window_rect);
01515 }
01516 
01517 const MetaXineramaScreenInfo* 
01518 meta_screen_get_xinerama_neighbor (MetaScreen         *screen,
01519                                    int                 which_xinerama,
01520                                    MetaScreenDirection direction)
01521 {
01522   MetaXineramaScreenInfo* input = screen->xinerama_infos + which_xinerama;
01523   MetaXineramaScreenInfo* current;
01524   int i;
01525 
01526   for (i = 0; i < screen->n_xinerama_infos; i++)
01527     {
01528       current = screen->xinerama_infos + i;
01529 
01530       if ((direction == META_SCREEN_RIGHT && 
01531            current->rect.x == input->rect.x + input->rect.width &&
01532            meta_rectangle_vert_overlap(&current->rect, &input->rect)) ||
01533           (direction == META_SCREEN_LEFT && 
01534            input->rect.x == current->rect.x + current->rect.width &&
01535            meta_rectangle_vert_overlap(&current->rect, &input->rect)) ||
01536           (direction == META_SCREEN_UP && 
01537            input->rect.y == current->rect.y + current->rect.height &&
01538            meta_rectangle_horiz_overlap(&current->rect, &input->rect)) ||
01539           (direction == META_SCREEN_DOWN && 
01540            current->rect.y == input->rect.y + input->rect.height &&
01541            meta_rectangle_horiz_overlap(&current->rect, &input->rect)))
01542         {
01543           return current;
01544         }
01545     }
01546   
01547   return NULL;
01548 }
01549 
01550 void
01551 meta_screen_get_natural_xinerama_list (MetaScreen *screen,
01552                                        int**       xineramas_list,
01553                                        int*        n_xineramas)
01554 {
01555   const MetaXineramaScreenInfo* current;
01556   const MetaXineramaScreenInfo* tmp;
01557   GQueue* xinerama_queue;
01558   int* visited;
01559   int cur = 0;
01560   int i;
01561 
01562   *n_xineramas = screen->n_xinerama_infos;
01563   *xineramas_list = g_new (int, screen->n_xinerama_infos);
01564 
01565   /* we calculate a natural ordering by which to choose xineramas for
01566    * window placement.  We start at the current xinerama, and perform
01567    * a breadth-first search of the xineramas starting from that
01568    * xinerama.  We choose preferentially left, then right, then down,
01569    * then up.  The visitation order produced by this traversal is the
01570    * natural xinerama ordering.
01571    */
01572 
01573   visited = g_new (int, screen->n_xinerama_infos);
01574   for (i = 0; i < screen->n_xinerama_infos; i++)
01575     {
01576       visited[i] = FALSE;
01577     }
01578 
01579   current = meta_screen_get_current_xinerama (screen);
01580   xinerama_queue = g_queue_new ();
01581   g_queue_push_tail (xinerama_queue, (gpointer) current);
01582   visited[current->number] = TRUE;
01583 
01584   while (!g_queue_is_empty (xinerama_queue))
01585     {
01586       current = (const MetaXineramaScreenInfo*) 
01587         g_queue_pop_head (xinerama_queue);
01588 
01589       (*xineramas_list)[cur++] = current->number;
01590 
01591       /* enqueue each of the directions */
01592       tmp = meta_screen_get_xinerama_neighbor (screen,
01593                                                current->number,
01594                                                META_SCREEN_LEFT);
01595       if (tmp && !visited[tmp->number])
01596         {
01597           g_queue_push_tail (xinerama_queue,
01598                              (MetaXineramaScreenInfo*) tmp);
01599           visited[tmp->number] = TRUE;
01600         }
01601       tmp = meta_screen_get_xinerama_neighbor (screen,
01602                                                current->number,
01603                                                META_SCREEN_RIGHT);
01604       if (tmp && !visited[tmp->number])
01605         {
01606           g_queue_push_tail (xinerama_queue,
01607                              (MetaXineramaScreenInfo*) tmp);
01608           visited[tmp->number] = TRUE;
01609         }
01610       tmp = meta_screen_get_xinerama_neighbor (screen,
01611                                                current->number,
01612                                                META_SCREEN_UP);
01613       if (tmp && !visited[tmp->number])
01614         {
01615           g_queue_push_tail (xinerama_queue,
01616                              (MetaXineramaScreenInfo*) tmp);
01617           visited[tmp->number] = TRUE;
01618         }
01619       tmp = meta_screen_get_xinerama_neighbor (screen,
01620                                                current->number,
01621                                                META_SCREEN_DOWN);
01622       if (tmp && !visited[tmp->number])
01623         {
01624           g_queue_push_tail (xinerama_queue,
01625                              (MetaXineramaScreenInfo*) tmp);
01626           visited[tmp->number] = TRUE;
01627         }
01628     }
01629 
01630   /* in case we somehow missed some set of xineramas, go through the
01631    * visited list and add in any xineramas that were missed
01632    */
01633   for (i = 0; i < screen->n_xinerama_infos; i++)
01634     {
01635       if (visited[i] == FALSE)
01636         {
01637           (*xineramas_list)[cur++] = i;
01638         }
01639     }
01640 
01641   g_free (visited);
01642   g_queue_free (xinerama_queue);
01643 }
01644 
01645 const MetaXineramaScreenInfo*
01646 meta_screen_get_current_xinerama (MetaScreen *screen)
01647 {
01648   if (screen->n_xinerama_infos == 1)
01649     return &screen->xinerama_infos[0];
01650   
01651   /* Sadly, we have to do it this way. Yuck.
01652    */
01653   
01654   if (screen->display->xinerama_cache_invalidated)
01655     {
01656       Window root_return, child_return;
01657       int win_x_return, win_y_return;
01658       unsigned int mask_return;
01659       int i;
01660       MetaRectangle pointer_position;
01661       
01662       screen->display->xinerama_cache_invalidated = FALSE;
01663       
01664       pointer_position.width = pointer_position.height = 1;
01665       XQueryPointer (screen->display->xdisplay,
01666                      screen->xroot,
01667                      &root_return,
01668                      &child_return,
01669                      &pointer_position.x,
01670                      &pointer_position.y,
01671                      &win_x_return,
01672                      &win_y_return,
01673                      &mask_return);
01674 
01675       screen->last_xinerama_index = 0;
01676       for (i = 0; i < screen->n_xinerama_infos; i++)
01677         {
01678           if (meta_rectangle_contains_rect (&screen->xinerama_infos[i].rect,
01679                                             &pointer_position))
01680             {
01681               screen->last_xinerama_index = i;
01682               break;
01683             }
01684         }
01685       
01686       meta_topic (META_DEBUG_XINERAMA,
01687                   "Rechecked current Xinerama, now %d\n",
01688                   screen->last_xinerama_index);
01689     }
01690 
01691   return &screen->xinerama_infos[screen->last_xinerama_index];
01692 }
01693 
01694 #define _NET_WM_ORIENTATION_HORZ 0
01695 #define _NET_WM_ORIENTATION_VERT 1
01696 
01697 #define _NET_WM_TOPLEFT     0
01698 #define _NET_WM_TOPRIGHT    1
01699 #define _NET_WM_BOTTOMRIGHT 2
01700 #define _NET_WM_BOTTOMLEFT  3
01701 
01702 void
01703 meta_screen_update_workspace_layout (MetaScreen *screen)
01704 {
01705   gulong *list;
01706   int n_items;
01707   
01708   list = NULL;
01709   n_items = 0;
01710 
01711   if (meta_prop_get_cardinal_list (screen->display,
01712                                    screen->xroot,
01713                                    screen->display->atom__NET_DESKTOP_LAYOUT,
01714                                    &list, &n_items))
01715     {
01716       if (n_items == 3 || n_items == 4)
01717         {
01718           int cols, rows;
01719           
01720           switch (list[0])
01721             {
01722             case _NET_WM_ORIENTATION_HORZ:
01723               screen->vertical_workspaces = FALSE;
01724               break;
01725             case _NET_WM_ORIENTATION_VERT:
01726               screen->vertical_workspaces = TRUE;
01727               break;
01728             default:
01729               meta_warning ("Someone set a weird orientation in _NET_DESKTOP_LAYOUT\n");
01730               break;
01731             }
01732 
01733           cols = list[1];
01734           rows = list[2];
01735 
01736           if (rows <= 0 && cols <= 0)
01737             {
01738               meta_warning ("Columns = %d rows = %d in _NET_DESKTOP_LAYOUT makes no sense\n", rows, cols);
01739             }
01740           else
01741             {
01742               if (rows > 0)
01743                 screen->rows_of_workspaces = rows;
01744               else
01745                 screen->rows_of_workspaces = -1;
01746               
01747               if (cols > 0)
01748                 screen->columns_of_workspaces = cols;
01749               else
01750                 screen->columns_of_workspaces = -1;
01751             }
01752 
01753           if (n_items == 4)
01754             {
01755               switch (list[3])
01756                 {
01757                   case _NET_WM_TOPLEFT:
01758                     screen->starting_corner = META_SCREEN_TOPLEFT;
01759                     break;
01760                   case _NET_WM_TOPRIGHT:
01761                     screen->starting_corner = META_SCREEN_TOPRIGHT;
01762                     break;
01763                   case _NET_WM_BOTTOMRIGHT:
01764                     screen->starting_corner = META_SCREEN_BOTTOMRIGHT;
01765                     break;
01766                   case _NET_WM_BOTTOMLEFT:
01767                     screen->starting_corner = META_SCREEN_BOTTOMLEFT;
01768                     break;
01769                   default:
01770                     meta_warning ("Someone set a weird starting corner in _NET_DESKTOP_LAYOUT\n");
01771                     break;
01772                 }
01773             }
01774           else
01775             screen->starting_corner = META_SCREEN_TOPLEFT;
01776         }
01777       else
01778         {
01779           meta_warning ("Someone set _NET_DESKTOP_LAYOUT to %d integers instead of 4 "
01780                         "(3 is accepted for backwards compat)\n", n_items);
01781         }
01782 
01783       meta_XFree (list);
01784     }
01785 
01786   meta_verbose ("Workspace layout rows = %d cols = %d orientation = %d starting corner = %u\n",
01787                 screen->rows_of_workspaces,
01788                 screen->columns_of_workspaces,
01789                 screen->vertical_workspaces,
01790                 screen->starting_corner);
01791 }
01792 
01793 static void
01794 set_workspace_names (MetaScreen *screen)
01795 {
01796   /* This updates names on root window when the pref changes,
01797    * note we only get prefs change notify if things have
01798    * really changed.
01799    */
01800   GString *flattened;
01801   int i;
01802   int n_spaces;
01803 
01804   /* flatten to nul-separated list */
01805   n_spaces = meta_screen_get_n_workspaces (screen);
01806   flattened = g_string_new ("");
01807   i = 0;
01808   while (i < n_spaces)
01809     {
01810       const char *name;
01811 
01812       name = meta_prefs_get_workspace_name (i);
01813 
01814       if (name)
01815         g_string_append_len (flattened, name,
01816                              strlen (name) + 1);
01817       else
01818         g_string_append_len (flattened, "", 1);
01819       
01820       ++i;
01821     }
01822   
01823   meta_error_trap_push (screen->display);
01824   XChangeProperty (screen->display->xdisplay,
01825                    screen->xroot,
01826                    screen->display->atom__NET_DESKTOP_NAMES,
01827                    screen->display->atom_UTF8_STRING,
01828                    8, PropModeReplace,
01829                    (unsigned char *)flattened->str, flattened->len);
01830   meta_error_trap_pop (screen->display, FALSE);
01831   
01832   g_string_free (flattened, TRUE);
01833 }
01834 
01835 void
01836 meta_screen_update_workspace_names (MetaScreen *screen)
01837 {
01838   char **names;
01839   int n_names;
01840   int i;
01841 
01842   /* this updates names in prefs when the root window property changes,
01843    * iff the new property contents don't match what's already in prefs
01844    */
01845   
01846   names = NULL;
01847   n_names = 0;
01848   if (!meta_prop_get_utf8_list (screen->display,
01849                                 screen->xroot,
01850                                 screen->display->atom__NET_DESKTOP_NAMES,
01851                                 &names, &n_names))
01852     {
01853       meta_verbose ("Failed to get workspace names from root window %d\n",
01854                     screen->number);
01855       return;
01856     }
01857 
01858   i = 0;
01859   while (i < n_names)
01860     {
01861       meta_topic (META_DEBUG_PREFS,
01862                   "Setting workspace %d name to \"%s\" due to _NET_DESKTOP_NAMES change\n",
01863                   i, names[i] ? names[i] : "null");
01864       meta_prefs_change_workspace_name (i, names[i]);
01865       
01866       ++i;
01867     }
01868   
01869   g_strfreev (names);
01870 }
01871 
01872 Window
01873 meta_create_offscreen_window (Display *xdisplay,
01874                               Window   parent,
01875                               long     valuemask)
01876 {
01877   XSetWindowAttributes attrs;
01878 
01879   /* we want to be override redirect because sometimes we
01880    * create a window on a screen we aren't managing.
01881    * (but on a display we are managing at least one screen for)
01882    */
01883   attrs.override_redirect = True;
01884   attrs.event_mask = valuemask;
01885   
01886   return XCreateWindow (xdisplay,
01887                         parent,
01888                         -100, -100, 1, 1,
01889                         0,
01890                         CopyFromParent,
01891                         CopyFromParent,
01892                         (Visual *)CopyFromParent,
01893                         CWOverrideRedirect | CWEventMask,
01894                         &attrs);
01895 }
01896 
01897 static void
01898 set_work_area_hint (MetaScreen *screen)
01899 {
01900   int num_workspaces;
01901   GList *tmp_list;
01902   unsigned long *data, *tmp;
01903   MetaRectangle area;
01904   
01905   num_workspaces = meta_screen_get_n_workspaces (screen);
01906   data = g_new (unsigned long, num_workspaces * 4);
01907   tmp_list = screen->workspaces;
01908   tmp = data;
01909   
01910   while (tmp_list != NULL)
01911     {
01912       MetaWorkspace *workspace = tmp_list->data;
01913 
01914       if (workspace->screen == screen)
01915         {
01916           meta_workspace_get_work_area_all_xineramas (workspace, &area);
01917           tmp[0] = area.x;
01918           tmp[1] = area.y;
01919           tmp[2] = area.width;
01920           tmp[3] = area.height;
01921 
01922           tmp += 4;
01923         }
01924       
01925       tmp_list = tmp_list->next;
01926     }
01927   
01928   meta_error_trap_push (screen->display);
01929   XChangeProperty (screen->display->xdisplay, screen->xroot,
01930                    screen->display->atom__NET_WORKAREA,
01931                    XA_CARDINAL, 32, PropModeReplace,
01932                    (guchar*) data, num_workspaces*4);
01933   g_free (data);
01934   meta_error_trap_pop (screen->display, FALSE);
01935 }
01936 
01937 static gboolean
01938 set_work_area_idle_func (MetaScreen *screen)
01939 {
01940   meta_topic (META_DEBUG_WORKAREA,
01941               "Running work area idle function\n");
01942   
01943   screen->work_area_idle = 0;
01944   
01945   set_work_area_hint (screen);
01946   
01947   return FALSE;
01948 }
01949 
01950 void
01951 meta_screen_queue_workarea_recalc (MetaScreen *screen)
01952 {
01953   /* Recompute work area in an idle */
01954   if (screen->work_area_idle == 0)
01955     {
01956       meta_topic (META_DEBUG_WORKAREA,
01957                   "Adding work area hint idle function\n");
01958       screen->work_area_idle =
01959         g_idle_add_full (META_PRIORITY_WORK_AREA_HINT,
01960                          (GSourceFunc) set_work_area_idle_func,
01961                          screen,
01962                          NULL);
01963     }
01964 }
01965 
01966 
01967 #ifdef WITH_VERBOSE_MODE
01968 static char *
01969 meta_screen_corner_to_string (MetaScreenCorner corner)
01970 {
01971   switch (corner)
01972     {
01973     case META_SCREEN_TOPLEFT:
01974       return "TopLeft";
01975     case META_SCREEN_TOPRIGHT:
01976       return "TopRight";
01977     case META_SCREEN_BOTTOMLEFT:
01978       return "BottomLeft";
01979     case META_SCREEN_BOTTOMRIGHT:
01980       return "BottomRight";
01981     }
01982 
01983   return "Unknown";
01984 }
01985 #endif /* WITH_VERBOSE_MODE */
01986 
01987 void
01988 meta_screen_calc_workspace_layout (MetaScreen          *screen,
01989                                    int                  num_workspaces,
01990                                    int                  current_space,
01991                                    MetaWorkspaceLayout *layout)
01992 {
01993   int rows, cols;
01994   int grid_area;
01995   int *grid;
01996   int i, r, c;
01997   int current_row, current_col;
01998   
01999   rows = screen->rows_of_workspaces;
02000   cols = screen->columns_of_workspaces;
02001   if (rows <= 0 && cols <= 0)
02002     cols = num_workspaces;
02003 
02004   if (rows <= 0)
02005     rows = num_workspaces / cols + ((num_workspaces % cols) > 0 ? 1 : 0);
02006   if (cols <= 0)
02007     cols = num_workspaces / rows + ((num_workspaces % rows) > 0 ? 1 : 0);
02008 
02009   /* paranoia */
02010   if (rows < 1)
02011     rows = 1;
02012   if (cols < 1)
02013     cols = 1;
02014 
02015   g_assert (rows != 0 && cols != 0);
02016   
02017   grid_area = rows * cols;
02018   
02019   meta_verbose ("Getting layout rows = %d cols = %d current = %d "
02020                 "num_spaces = %d vertical = %s corner = %s\n",
02021                 rows, cols, current_space, num_workspaces,
02022                 screen->vertical_workspaces ? "(true)" : "(false)",
02023                 meta_screen_corner_to_string (screen->starting_corner));
02024   
02025   /* ok, we want to setup the distances in the workspace array to go     
02026    * in each direction. Remember, there are many ways that a workspace   
02027    * array can be setup.                                                 
02028    * see http://www.freedesktop.org/standards/wm-spec/1.2/html/x109.html 
02029    * and look at the _NET_DESKTOP_LAYOUT section for details.            
02030    * For instance:
02031    */
02032   /* starting_corner = META_SCREEN_TOPLEFT                         
02033    *  vertical_workspaces = 0                 vertical_workspaces=1
02034    *       1234                                    1357            
02035    *       5678                                    2468            
02036    *                                                               
02037    * starting_corner = META_SCREEN_TOPRIGHT                        
02038    *  vertical_workspaces = 0                 vertical_workspaces=1
02039    *       4321                                    7531            
02040    *       8765                                    8642            
02041    *                                                               
02042    * starting_corner = META_SCREEN_BOTTOMLEFT                      
02043    *  vertical_workspaces = 0                 vertical_workspaces=1
02044    *       5678                                    2468            
02045    *       1234                                    1357            
02046    *                                                               
02047    * starting_corner = META_SCREEN_BOTTOMRIGHT                     
02048    *  vertical_workspaces = 0                 vertical_workspaces=1
02049    *       8765                                    8642            
02050    *       4321                                    7531            
02051    *
02052    */
02053   /* keep in mind that we could have a ragged layout, e.g. the "8"
02054    * in the above grids could be missing
02055    */
02056 
02057   
02058   grid = g_new (int, grid_area);
02059 
02060   current_row = -1;
02061   current_col = -1;
02062   i = 0;
02063   
02064   switch (screen->starting_corner) 
02065     {
02066     case META_SCREEN_TOPLEFT:
02067       if (screen->vertical_workspaces) 
02068         {
02069           c = 0;
02070           while (c < cols)
02071             {
02072               r = 0;
02073               while (r < rows)
02074                 {
02075                   grid[r*cols+c] = i;
02076                   ++i;
02077                   ++r;
02078                 }
02079               ++c;
02080             }
02081         }
02082       else
02083         {
02084           r = 0;
02085           while (r < rows)
02086             {
02087               c = 0;
02088               while (c < cols)
02089                 {
02090                   grid[r*cols+c] = i;
02091                   ++i;
02092                   ++c;
02093                 }
02094               ++r;
02095             }
02096         }
02097       break;
02098     case META_SCREEN_TOPRIGHT:
02099       if (screen->vertical_workspaces) 
02100         {
02101           c = cols - 1;
02102           while (c >= 0)
02103             {
02104               r = 0;
02105               while (r < rows)
02106                 {
02107                   grid[r*cols+c] = i;
02108                   ++i;
02109                   ++r;
02110                 }
02111               --c;
02112             }
02113         }
02114       else
02115         {
02116           r = 0;
02117           while (r < rows)
02118             {
02119               c = cols - 1;
02120               while (c >= 0)
02121                 {
02122                   grid[r*cols+c] = i;
02123                   ++i;
02124                   --c;
02125                 }
02126               ++r;
02127             }
02128         }
02129       break;
02130     case META_SCREEN_BOTTOMLEFT:
02131       if (screen->vertical_workspaces) 
02132         {
02133           c = 0;
02134           while (c < cols)
02135             {
02136               r = rows - 1;
02137               while (r >= 0)
02138                 {
02139                   grid[r*cols+c] = i;
02140                   ++i;
02141                   --r;
02142                 }
02143               ++c;
02144             }
02145         }
02146       else
02147         {
02148           r = rows - 1;
02149           while (r >= 0)
02150             {
02151               c = 0;
02152               while (c < cols)
02153                 {
02154                   grid[r*cols+c] = i;
02155                   ++i;
02156                   ++c;
02157                 }
02158               --r;
02159             }
02160         }
02161       break;
02162     case META_SCREEN_BOTTOMRIGHT:
02163       if (screen->vertical_workspaces) 
02164         {
02165           c = cols - 1;
02166           while (c >= 0)
02167             {
02168               r = rows - 1;
02169               while (r >= 0)
02170                 {
02171                   grid[r*cols+c] = i;
02172                   ++i;
02173                   --r;
02174                 }
02175               --c;
02176             }
02177         }
02178       else
02179         {
02180           r = rows - 1;
02181           while (r >= 0)
02182             {
02183               c = cols - 1;
02184               while (c >= 0)
02185                 {
02186                   grid[r*cols+c] = i;
02187                   ++i;
02188                   --c;
02189                 }
02190               --r;
02191             }
02192         }
02193       break;
02194     }  
02195 
02196   if (i != grid_area)
02197     meta_bug ("did not fill in the whole workspace grid in %s (%d filled)\n",
02198               G_STRFUNC, i);
02199   
02200   current_row = 0;
02201   current_col = 0;
02202   r = 0;
02203   while (r < rows)
02204     {
02205       c = 0;
02206       while (c < cols)
02207         {
02208           if (grid[r*cols+c] == current_space)
02209             {
02210               current_row = r;
02211               current_col = c;
02212             }
02213           else if (grid[r*cols+c] >= num_workspaces)
02214             {
02215               /* flag nonexistent spaces with -1 */
02216               grid[r*cols+c] = -1;
02217             }
02218           ++c;
02219         }
02220       ++r;
02221     }
02222 
02223   layout->rows = rows;
02224   layout->cols = cols;
02225   layout->grid = grid;
02226   layout->grid_area = grid_area;
02227   layout->current_row = current_row;
02228   layout->current_col = current_col;
02229 
02230 #ifdef WITH_VERBOSE_MODE
02231   if (meta_is_verbose ())
02232     {
02233       r = 0;
02234       while (r < layout->rows)
02235         {
02236           meta_verbose (" ");
02237           meta_push_no_msg_prefix ();
02238           c = 0;
02239           while (c < layout->cols)
02240             {
02241               if (r == layout->current_row &&
02242                   c == layout->current_col)
02243                 meta_verbose ("*%2d ", layout->grid[r*layout->cols+c]);
02244               else
02245                 meta_verbose ("%3d ", layout->grid[r*layout->cols+c]);
02246               ++c;
02247             }
02248           meta_verbose ("\n");
02249           meta_pop_no_msg_prefix ();
02250           ++r;
02251         }
02252     }
02253 #endif /* WITH_VERBOSE_MODE */
02254 }
02255 
02256 void
02257 meta_screen_free_workspace_layout (MetaWorkspaceLayout *layout)
02258 {
02259   g_free (layout->grid);
02260 }
02261 
02262 static void
02263 meta_screen_resize_func (MetaScreen *screen,
02264                          MetaWindow *window,
02265                          void       *user_data)
02266 {
02267   if (window->struts)
02268     {
02269       meta_window_update_struts (window);
02270     }
02271   meta_window_queue (window, META_QUEUE_MOVE_RESIZE);
02272 
02273   meta_window_recalc_features (window);
02274 }
02275 
02276 void
02277 meta_screen_resize (MetaScreen *screen,
02278                     int         width,
02279                     int         height)
02280 {  
02281   screen->rect.width = width;
02282   screen->rect.height = height;
02283 
02284   reload_xinerama_infos (screen);
02285   set_desktop_geometry_hint (screen);
02286   
02287   /* Queue a resize on all the windows */
02288   meta_screen_foreach_window (screen, meta_screen_resize_func, 0);
02289 }
02290 
02291 void
02292 meta_screen_update_showing_desktop_hint (MetaScreen *screen)
02293 {
02294   unsigned long data[1];
02295 
02296   data[0] = screen->active_workspace->showing_desktop ? 1 : 0;
02297       
02298   meta_error_trap_push (screen->display);
02299   XChangeProperty (screen->display->xdisplay, screen->xroot,
02300                    screen->display->atom__NET_SHOWING_DESKTOP,
02301                    XA_CARDINAL,
02302                    32, PropModeReplace, (guchar*) data, 1);
02303   meta_error_trap_pop (screen->display, FALSE);
02304 }
02305 
02306 static void
02307 queue_windows_showing (MetaScreen *screen)
02308 {
02309   GSList *windows;
02310   GSList *tmp;
02311 
02312   /* Must operate on all windows on display instead of just on the
02313    * active_workspace's window list, because the active_workspace's
02314    * window list may not contain the on_all_workspace windows.
02315    */
02316   windows = meta_display_list_windows (screen->display);
02317 
02318   tmp = windows;
02319   while (tmp != NULL)
02320     {
02321       MetaWindow *w = tmp->data;
02322 
02323       if (w->screen == screen)
02324         meta_window_queue (w, META_QUEUE_CALC_SHOWING);
02325       
02326       tmp = tmp->next;
02327     }
02328 
02329   g_slist_free (windows);
02330 }
02331 
02332 void
02333 meta_screen_minimize_all_on_active_workspace_except (MetaScreen *screen,
02334                                                      MetaWindow *keep)
02335 {
02336   GList *windows;
02337   GList *tmp;
02338 
02339   windows = screen->active_workspace->windows;
02340   
02341   tmp = windows;
02342   while (tmp != NULL)
02343     {
02344       MetaWindow *w = tmp->data;
02345       
02346       if (w->screen == screen  &&
02347           w->has_minimize_func &&
02348           w != keep)
02349         meta_window_minimize (w);
02350       
02351       tmp = tmp->next;
02352     }
02353 }
02354 
02355 void
02356 meta_screen_show_desktop (MetaScreen *screen, 
02357                           guint32     timestamp)
02358 {
02359   GList *windows;
02360 
02361   if (screen->active_workspace->showing_desktop)
02362     return;
02363   
02364   screen->active_workspace->showing_desktop = TRUE;
02365   
02366   queue_windows_showing (screen);
02367 
02368   /* Focus the most recently used META_WINDOW_DESKTOP window, if there is one;
02369    * see bug 159257.
02370    */
02371   windows = screen->active_workspace->mru_list;
02372   while (windows != NULL)
02373     {
02374       MetaWindow *w = windows->data;
02375       
02376       if (w->screen == screen  && 
02377           w->type == META_WINDOW_DESKTOP)
02378         {
02379           meta_window_focus (w, timestamp);
02380           break;
02381         }
02382       
02383       windows = windows->next;
02384     }
02385 
02386   
02387   meta_screen_update_showing_desktop_hint (screen);
02388 }
02389 
02390 void
02391 meta_screen_unshow_desktop (MetaScreen *screen)
02392 {
02393   if (!screen->active_workspace->showing_desktop)
02394     return;
02395 
02396   screen->active_workspace->showing_desktop = FALSE;
02397 
02398   queue_windows_showing (screen);
02399 
02400   meta_screen_update_showing_desktop_hint (screen);
02401 }
02402 
02403 
02404 #ifdef HAVE_STARTUP_NOTIFICATION
02405 static gboolean startup_sequence_timeout (void *data);
02406 
02407 static void
02408 update_startup_feedback (MetaScreen *screen)
02409 {
02410   if (screen->startup_sequences != NULL)
02411     {
02412       meta_topic (META_DEBUG_STARTUP,
02413                   "Setting busy cursor\n");
02414       meta_screen_set_cursor (screen, META_CURSOR_BUSY);
02415     }
02416   else
02417     {
02418       meta_topic (META_DEBUG_STARTUP,
02419                   "Setting default cursor\n");
02420       meta_screen_set_cursor (screen, META_CURSOR_DEFAULT);
02421     }
02422 }
02423 
02424 static void
02425 add_sequence (MetaScreen        *screen,
02426               SnStartupSequence *sequence)
02427 {
02428   meta_topic (META_DEBUG_STARTUP,
02429               "Adding sequence %s\n",
02430               sn_startup_sequence_get_id (sequence));
02431   sn_startup_sequence_ref (sequence);
02432   screen->startup_sequences = g_slist_prepend (screen->startup_sequences,
02433                                                sequence);
02434 
02435   /* our timeout just polls every second, instead of bothering
02436    * to compute exactly when we may next time out
02437    */
02438   if (screen->startup_sequence_timeout == 0)
02439     screen->startup_sequence_timeout = g_timeout_add (1000,
02440                                                       startup_sequence_timeout,
02441                                                       screen);
02442 
02443   update_startup_feedback (screen);
02444 }
02445 
02446 static void
02447 remove_sequence (MetaScreen        *screen,
02448                  SnStartupSequence *sequence)
02449 {
02450   meta_topic (META_DEBUG_STARTUP,
02451               "Removing sequence %s\n",
02452               sn_startup_sequence_get_id (sequence));
02453   
02454   screen->startup_sequences = g_slist_remove (screen->startup_sequences,
02455                                               sequence);
02456   sn_startup_sequence_unref (sequence);
02457   
02458   if (screen->startup_sequences == NULL &&
02459       screen->startup_sequence_timeout != 0)
02460     {
02461       g_source_remove (screen->startup_sequence_timeout);
02462       screen->startup_sequence_timeout = 0;
02463     }
02464 
02465   update_startup_feedback (screen);
02466 }
02467 
02468 typedef struct
02469 {
02470   GSList *list;
02471   GTimeVal now;
02472 } CollectTimedOutData;
02473 
02474 /* This should be fairly long, as it should never be required unless
02475  * apps or .desktop files are buggy, and it's confusing if
02476  * OpenOffice or whatever seems to stop launching - people
02477  * might decide they need to launch it again.
02478  */
02479 #define STARTUP_TIMEOUT 15000
02480 
02481 static void
02482 collect_timed_out_foreach (void *element,
02483                            void *data)
02484 {
02485   CollectTimedOutData *ctod = data;
02486   SnStartupSequence *sequence = element;
02487   long tv_sec, tv_usec;
02488   double elapsed;
02489   
02490   sn_startup_sequence_get_last_active_time (sequence, &tv_sec, &tv_usec);
02491 
02492   elapsed =
02493     ((((double)ctod->now.tv_sec - tv_sec) * G_USEC_PER_SEC +
02494       (ctod->now.tv_usec - tv_usec))) / 1000.0;
02495 
02496   meta_topic (META_DEBUG_STARTUP,
02497               "Sequence used %g seconds vs. %g max: %s\n",
02498               elapsed, (double) STARTUP_TIMEOUT,
02499               sn_startup_sequence_get_id (sequence));
02500   
02501   if (elapsed > STARTUP_TIMEOUT)
02502     ctod->list = g_slist_prepend (ctod->list, sequence);
02503 }
02504 
02505 static gboolean
02506 startup_sequence_timeout (void *data)
02507 {
02508   MetaScreen *screen = data;
02509   CollectTimedOutData ctod;
02510   GSList *tmp;
02511   
02512   ctod.list = NULL;
02513   g_get_current_time (&ctod.now);
02514   g_slist_foreach (screen->startup_sequences,
02515                    collect_timed_out_foreach,
02516                    &ctod);
02517 
02518   tmp = ctod.list;
02519   while (tmp != NULL)
02520     {
02521       SnStartupSequence *sequence = tmp->data;
02522 
02523       meta_topic (META_DEBUG_STARTUP,
02524                   "Timed out sequence %s\n",
02525                   sn_startup_sequence_get_id (sequence));
02526       
02527       sn_startup_sequence_complete (sequence);
02528       
02529       tmp = tmp->next;
02530     }
02531 
02532   g_slist_free (ctod.list);
02533   
02534   if (screen->startup_sequences != NULL)
02535     {
02536       return TRUE;
02537     }
02538   else
02539     {
02540       /* remove */
02541       screen->startup_sequence_timeout = 0;
02542       return FALSE;
02543     }
02544 }
02545 
02546 static void
02547 meta_screen_sn_event (SnMonitorEvent *event,
02548                       void           *user_data)
02549 {
02550   MetaScreen *screen;
02551   SnStartupSequence *sequence;
02552   
02553   screen = user_data;
02554 
02555   sequence = sn_monitor_event_get_startup_sequence (event);
02556   
02557   switch (sn_monitor_event_get_type (event))
02558     {
02559     case SN_MONITOR_EVENT_INITIATED:
02560       {
02561         const char *wmclass;
02562 
02563         wmclass = sn_startup_sequence_get_wmclass (sequence);
02564         
02565         meta_topic (META_DEBUG_STARTUP,
02566                     "Received startup initiated for %s wmclass %s\n",
02567                     sn_startup_sequence_get_id (sequence),
02568                     wmclass ? wmclass : "(unset)");
02569         add_sequence (screen, sequence);
02570       }
02571       break;
02572 
02573     case SN_MONITOR_EVENT_COMPLETED:
02574       {
02575         meta_topic (META_DEBUG_STARTUP,
02576                     "Received startup completed for %s\n",
02577                     sn_startup_sequence_get_id (sequence));
02578         remove_sequence (screen,
02579                          sn_monitor_event_get_startup_sequence (event));
02580       }
02581       break;
02582 
02583     case SN_MONITOR_EVENT_CHANGED:
02584       meta_topic (META_DEBUG_STARTUP,
02585                   "Received startup changed for %s\n",
02586                   sn_startup_sequence_get_id (sequence));
02587       break;
02588 
02589     case SN_MONITOR_EVENT_CANCELED:
02590       meta_topic (META_DEBUG_STARTUP,
02591                   "Received startup canceled for %s\n",
02592                   sn_startup_sequence_get_id (sequence));
02593       break;
02594     }
02595 }
02596 #endif
02597 
02598 /* Sets the initial_timestamp and initial_workspace properties
02599  * of a window according to information given us by the
02600  * startup-notification library.
02601  *
02602  * Returns TRUE if startup properties have been applied, and
02603  * FALSE if they have not (for example, if they had already
02604  * been applied.)
02605  */
02606 gboolean
02607 meta_screen_apply_startup_properties (MetaScreen *screen,
02608                                       MetaWindow *window)
02609 {
02610 #ifdef HAVE_STARTUP_NOTIFICATION
02611   const char *startup_id;
02612   GSList *tmp;
02613   SnStartupSequence *sequence;
02614   
02615   /* Does the window have a startup ID stored? */
02616   startup_id = meta_window_get_startup_id (window);
02617 
02618   meta_topic (META_DEBUG_STARTUP,
02619               "Applying startup props to %s id \"%s\"\n",
02620               window->desc,
02621               startup_id ? startup_id : "(none)");
02622   
02623   sequence = NULL;
02624   if (startup_id == NULL)
02625     {
02626       /* No startup ID stored for the window. Let's ask the
02627        * startup-notification library whether there's anything
02628        * stored for the resource name or resource class hints.
02629        */
02630       tmp = screen->startup_sequences;
02631       while (tmp != NULL)
02632         {
02633           const char *wmclass;
02634 
02635           wmclass = sn_startup_sequence_get_wmclass (tmp->data);
02636 
02637           if (wmclass != NULL &&
02638               ((window->res_class &&
02639                 strcmp (wmclass, window->res_class) == 0) ||
02640                (window->res_name &&
02641                 strcmp (wmclass, window->res_name) == 0)))
02642             {
02643               sequence = tmp->data;
02644 
02645               g_assert (window->startup_id == NULL);
02646               window->startup_id = g_strdup (sn_startup_sequence_get_id (sequence));
02647               startup_id = window->startup_id;
02648 
02649               meta_topic (META_DEBUG_STARTUP,
02650                           "Ending legacy sequence %s due to window %s\n",
02651                           sn_startup_sequence_get_id (sequence),
02652                           window->desc);
02653               
02654               sn_startup_sequence_complete (sequence);
02655               break;
02656             }
02657           
02658           tmp = tmp->next;
02659         }
02660     }
02661 
02662   /* Still no startup ID? Bail. */
02663   if (startup_id == NULL)
02664     return FALSE;
02665   
02666   /* We might get this far and not know the sequence ID (if the window
02667    * already had a startup ID stored), so let's look for one if we don't
02668    * already know it.
02669    */
02670   if (sequence == NULL)
02671     {
02672       tmp = screen->startup_sequences;
02673       while (tmp != NULL)
02674         {
02675           const char *id;
02676           
02677           id = sn_startup_sequence_get_id (tmp->data);
02678           
02679           if (strcmp (id, startup_id) == 0)
02680             {
02681               sequence = tmp->data;
02682               break;
02683             }
02684           
02685           tmp = tmp->next;
02686         }
02687     }
02688 
02689   if (sequence != NULL)
02690     {
02691       gboolean changed_something = FALSE;
02692           
02693       meta_topic (META_DEBUG_STARTUP,
02694                   "Found startup sequence for window %s ID \"%s\"\n",
02695                   window->desc, startup_id);
02696 
02697       if (!window->initial_workspace_set)
02698         {
02699           int space = sn_startup_sequence_get_workspace (sequence);
02700           if (space >= 0)
02701             {
02702               meta_topic (META_DEBUG_STARTUP,
02703                           "Setting initial window workspace to %d based on startup info\n",
02704                           space);
02705               
02706               window->initial_workspace_set = TRUE;
02707               window->initial_workspace = space;
02708               changed_something = TRUE;
02709             }
02710         }
02711 
02712       if (!window->initial_timestamp_set)
02713         {
02714           guint32 timestamp = sn_startup_sequence_get_timestamp (sequence);
02715           meta_topic (META_DEBUG_STARTUP,
02716                       "Setting initial window timestamp to %u based on startup info\n",
02717                       timestamp);
02718               
02719           window->initial_timestamp_set = TRUE;
02720           window->initial_timestamp = timestamp;
02721           changed_something = TRUE;
02722         }
02723 
02724       return changed_something;
02725     }
02726   else
02727     {
02728       meta_topic (META_DEBUG_STARTUP,
02729                   "Did not find startup sequence for window %s ID \"%s\"\n",
02730                   window->desc, startup_id);
02731     }
02732   
02733 #endif /* HAVE_STARTUP_NOTIFICATION */
02734 
02735   return FALSE;
02736 }
02737 
02738 int
02739 meta_screen_get_screen_number (MetaScreen *screen)
02740 {
02741   return screen->number;
02742 }
02743 
02744 MetaDisplay *
02745 meta_screen_get_display (MetaScreen *screen)
02746 {
02747   return screen->display;
02748 }
02749 
02750 Window
02751 meta_screen_get_xroot (MetaScreen *screen)
02752 {
02753   return screen->xroot;
02754 }
02755 
02756 void 
02757 meta_screen_get_size (MetaScreen *screen,
02758                       int        *width,
02759                       int        *height)
02760 {
02761   *width = screen->rect.width;
02762   *height = screen->rect.height;
02763 }
02764 
02765 gpointer
02766 meta_screen_get_compositor_data (MetaScreen *screen)
02767 {
02768   return screen->compositor_data;
02769 }
02770 
02771 void
02772 meta_screen_set_compositor_data (MetaScreen *screen,
02773                                  gpointer    compositor)
02774 {
02775   screen->compositor_data = compositor;
02776 }
02777 
02778 #ifdef HAVE_COMPOSITE_EXTENSIONS
02779 void
02780 meta_screen_set_cm_selection (MetaScreen *screen)
02781 {
02782   char selection[32];
02783   Atom a;
02784 
02785   g_snprintf (selection, sizeof(selection), "_NET_WM_CM_S%d", screen->number);
02786   meta_verbose ("Setting selection: %s\n", selection);
02787   a = XInternAtom (screen->display->xdisplay, selection, FALSE);
02788   XSetSelectionOwner (screen->display->xdisplay, a, 
02789                       screen->wm_cm_selection_window, CurrentTime);
02790 }
02791 
02792 void
02793 meta_screen_unset_cm_selection (MetaScreen *screen)
02794 {
02795   char selection[32];
02796   Atom a;
02797 
02798   g_snprintf (selection, sizeof(selection), "_NET_WM_CM_S%d", screen->number);
02799   a = XInternAtom (screen->display->xdisplay, selection, FALSE);
02800   XSetSelectionOwner (screen->display->xdisplay, a, None, CurrentTime);
02801 }
02802 #endif /* HAVE_COMPOSITE_EXTENSIONS */

Generated on Sat Aug 23 22:04:17 2008 for metacity by  doxygen 1.5.5