window-props.c

Go to the documentation of this file.
00001 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
00002 
00016 /* 
00017  * Copyright (C) 2001, 2002, 2003 Red Hat, Inc.
00018  * Copyright (C) 2004, 2005 Elijah Newren
00019  * 
00020  * This program is free software; you can redistribute it and/or
00021  * modify it under the terms of the GNU General Public License as
00022  * published by the Free Software Foundation; either version 2 of the
00023  * License, or (at your option) any later version.
00024  *
00025  * This program is distributed in the hope that it will be useful, but
00026  * WITHOUT ANY WARRANTY; without even the implied warranty of
00027  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00028  * General Public License for more details.
00029  * 
00030  * You should have received a copy of the GNU General Public License
00031  * along with this program; if not, write to the Free Software
00032  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
00033  * 02111-1307, USA.
00034  */
00035 
00036 #define _GNU_SOURCE
00037 #define _SVID_SOURCE /* for gethostname() */
00038 
00039 #include <config.h>
00040 #include "window-props.h"
00041 #include "errors.h"
00042 #include "xprops.h"
00043 #include "frame-private.h"
00044 #include "group.h"
00045 #include <X11/Xatom.h>
00046 #include <unistd.h>
00047 #include <string.h>
00048 #ifndef HOST_NAME_MAX
00049 /* Solaris headers apparently don't define this so do so manually; #326745 */
00050 #define HOST_NAME_MAX 255
00051 #endif
00052 
00053 typedef void (* InitValueFunc)   (MetaDisplay   *display,
00054                                   Atom           property,
00055                                   MetaPropValue *value);
00056 typedef void (* ReloadValueFunc) (MetaWindow    *window,
00057                                   MetaPropValue *value);
00058 
00059 struct _MetaWindowPropHooks
00060 {
00061   Atom property;
00062   InitValueFunc   init_func;
00063   ReloadValueFunc reload_func;
00064 };
00065 
00066 static void init_prop_value            (MetaDisplay   *display,
00067                                         Atom           property,
00068                                         MetaPropValue *value);
00069 static void reload_prop_value          (MetaWindow    *window,
00070                                         MetaPropValue *value);
00071 static MetaWindowPropHooks* find_hooks (MetaDisplay *display,
00072                                         Atom         property);
00073 
00074 
00075 void
00076 meta_window_reload_property (MetaWindow *window,
00077                              Atom        property)
00078 {
00079   meta_window_reload_properties (window, &property, 1);
00080 }
00081 
00082 void
00083 meta_window_reload_properties (MetaWindow *window,
00084                                const Atom *properties,
00085                                int         n_properties)
00086 {
00087   meta_window_reload_properties_from_xwindow (window,
00088                                               window->xwindow,
00089                                               properties,
00090                                               n_properties);
00091 }
00092 
00093 void
00094 meta_window_reload_property_from_xwindow (MetaWindow *window,
00095                                           Window      xwindow,
00096                                           Atom        property)
00097 {
00098   meta_window_reload_properties_from_xwindow (window, xwindow, &property, 1);
00099 }
00100 
00101 void
00102 meta_window_reload_properties_from_xwindow (MetaWindow *window,
00103                                             Window      xwindow,
00104                                             const Atom *properties,
00105                                             int         n_properties)
00106 {
00107   int i;
00108   MetaPropValue *values;
00109 
00110   g_return_if_fail (properties != NULL);
00111   g_return_if_fail (n_properties > 0);
00112   
00113   values = g_new0 (MetaPropValue, n_properties);
00114   
00115   i = 0;
00116   while (i < n_properties)
00117     {
00118       init_prop_value (window->display, properties[i], &values[i]);
00119       ++i;
00120     }
00121   
00122   meta_prop_get_values (window->display, xwindow,
00123                         values, n_properties);
00124 
00125   i = 0;
00126   while (i < n_properties)
00127     {
00128       reload_prop_value (window, &values[i]);
00129       
00130       ++i;
00131     }
00132 
00133   meta_prop_free_values (values, n_properties);
00134   
00135   g_free (values);
00136 }
00137 
00138 /* Fill in the MetaPropValue used to get the value of "property" */
00139 static void
00140 init_prop_value (MetaDisplay   *display,
00141                  Atom           property,
00142                  MetaPropValue *value)
00143 {
00144   MetaWindowPropHooks *hooks;  
00145 
00146   value->type = META_PROP_VALUE_INVALID;
00147   value->atom = None;
00148   
00149   hooks = find_hooks (display, property);
00150   if (hooks && hooks->init_func != NULL)
00151     (* hooks->init_func) (display, property, value);
00152 }
00153 
00154 static void
00155 reload_prop_value (MetaWindow    *window,
00156                    MetaPropValue *value)
00157 {
00158   MetaWindowPropHooks *hooks;  
00159   
00160   hooks = find_hooks (window->display, value->atom);
00161   if (hooks && hooks->reload_func != NULL)
00162     (* hooks->reload_func) (window, value);
00163 }
00164 
00165 static void
00166 init_wm_client_machine (MetaDisplay   *display,
00167                         Atom           property,
00168                         MetaPropValue *value)
00169 {
00170   value->type = META_PROP_VALUE_STRING;
00171   value->atom = display->atom_WM_CLIENT_MACHINE;
00172 }
00173 
00174 static void
00175 reload_wm_client_machine (MetaWindow    *window,
00176                           MetaPropValue *value)
00177 {
00178   g_free (window->wm_client_machine);
00179   window->wm_client_machine = NULL;
00180   
00181   if (value->type != META_PROP_VALUE_INVALID)
00182     window->wm_client_machine = g_strdup (value->v.str);
00183 
00184   meta_verbose ("Window has client machine \"%s\"\n",
00185                 window->wm_client_machine ? window->wm_client_machine : "unset");
00186 }
00187 
00188 static void
00189 init_net_wm_pid (MetaDisplay   *display,
00190                  Atom           property,
00191                  MetaPropValue *value)
00192 {
00193   value->type = META_PROP_VALUE_CARDINAL;
00194   value->atom = display->atom__NET_WM_PID;
00195 }
00196 
00197 static void
00198 reload_net_wm_pid (MetaWindow    *window,
00199                    MetaPropValue *value)
00200 {
00201   if (value->type != META_PROP_VALUE_INVALID)
00202     {
00203       gulong cardinal = (int) value->v.cardinal;
00204       
00205       if (cardinal <= 0)
00206         meta_warning (_("Application set a bogus _NET_WM_PID %lu\n"),
00207                       cardinal);
00208       else
00209         {
00210           window->net_wm_pid = cardinal;
00211           meta_verbose ("Window has _NET_WM_PID %d\n",
00212                         window->net_wm_pid);
00213         }
00214     }
00215 }
00216 
00217 static void
00218 init_net_wm_user_time (MetaDisplay   *display,
00219                        Atom           property,
00220                        MetaPropValue *value)
00221 {
00222   value->type = META_PROP_VALUE_CARDINAL;
00223   value->atom = display->atom__NET_WM_USER_TIME;
00224 }
00225 
00226 static void
00227 reload_net_wm_user_time (MetaWindow    *window,
00228                          MetaPropValue *value)
00229 {
00230   if (value->type != META_PROP_VALUE_INVALID)
00231     {
00232       gulong cardinal = value->v.cardinal;
00233       meta_window_set_user_time (window, cardinal);
00234     }
00235 }
00236 
00237 static void
00238 init_net_wm_user_time_window (MetaDisplay   *display,
00239                               Atom           property,
00240                               MetaPropValue *value)
00241 {
00242   value->type = META_PROP_VALUE_WINDOW;
00243   value->atom = display->atom__NET_WM_USER_TIME_WINDOW;
00244 }
00245 
00246 static void
00247 reload_net_wm_user_time_window (MetaWindow    *window,
00248                                 MetaPropValue *value)
00249 {
00250   if (value->type != META_PROP_VALUE_INVALID)
00251     {
00252       /* Unregister old NET_WM_USER_TIME_WINDOW */
00253       if (window->user_time_window != None)
00254         {
00255           /* See the comment to the meta_display_register_x_window call below. */
00256           meta_display_unregister_x_window (window->display,
00257                                             window->user_time_window);
00258           /* Don't get events on not-managed windows */
00259           XSelectInput (window->display->xdisplay,
00260                         window->user_time_window,
00261                         NoEventMask);
00262         }
00263 
00264 
00265       /* Obtain the new NET_WM_USER_TIME_WINDOW and register it */
00266       window->user_time_window = value->v.xwindow;
00267       if (window->user_time_window != None)
00268         {
00269           /* Kind of a hack; display.c:event_callback() ignores events
00270            * for unknown windows.  We make window->user_time_window
00271            * known by registering it with window (despite the fact
00272            * that window->xwindow is already registered with window).
00273            * This basically means that property notifies to either the
00274            * window->user_time_window or window->xwindow will be
00275            * treated identically and will result in functions for
00276            * window being called to update it.  Maybe we should ignore
00277            * any property notifies to window->user_time_window other
00278            * than atom__NET_WM_USER_TIME ones, but I just don't care
00279            * and it's not specified in the spec anyway.
00280            */
00281           meta_display_register_x_window (window->display,
00282                                           &window->user_time_window,
00283                                           window);
00284           /* Just listen for property notify events */
00285           XSelectInput (window->display->xdisplay,
00286                         window->user_time_window,
00287                         PropertyChangeMask);
00288 
00289           /* Manually load the _NET_WM_USER_TIME field from the given window
00290            * at this time as well.  If the user_time_window ever broadens in
00291            * scope, we'll probably want to load all relevant properties here.
00292            */
00293           meta_window_reload_property_from_xwindow (
00294             window,
00295             window->user_time_window,
00296             window->display->atom__NET_WM_USER_TIME);
00297         }
00298     }
00299 }
00300 
00301 #define MAX_TITLE_LENGTH 512
00302 
00310 static gboolean
00311 set_title_text (MetaWindow  *window,
00312                 gboolean     previous_was_modified,
00313                 const char  *title,
00314                 Atom         atom,
00315                 char       **target)
00316 {
00317   char hostname[HOST_NAME_MAX + 1];
00318   gboolean modified = FALSE;
00319   
00320   if (!target)
00321     return FALSE;
00322   
00323   g_free (*target);
00324   
00325   if (!title)
00326     *target = g_strdup ("");
00327   else if (g_utf8_strlen (title, MAX_TITLE_LENGTH + 1) > MAX_TITLE_LENGTH)
00328     {
00329       *target = meta_g_utf8_strndup (title, MAX_TITLE_LENGTH);
00330       modified = TRUE;
00331     }
00332   /* if WM_CLIENT_MACHINE indicates this machine is on a remote host
00333    * lets place that hostname in the title */
00334   else if (window->wm_client_machine &&
00335            !gethostname (hostname, HOST_NAME_MAX + 1) &&
00336            strcmp (hostname, window->wm_client_machine))
00337     {
00338       *target = g_strdup_printf (_("%s (on %s)"),
00339                       title, window->wm_client_machine);
00340       modified = TRUE;
00341     }
00342   else
00343     *target = g_strdup (title);
00344 
00345   if (modified && atom != None)
00346     meta_prop_set_utf8_string_hint (window->display,
00347                                     window->xwindow,
00348                                     atom, *target);
00349 
00350   /* Bug 330671 -- Don't forget to clear _NET_WM_VISIBLE_(ICON_)NAME */
00351   if (!modified && previous_was_modified)
00352     {
00353       meta_error_trap_push (window->display);
00354       XDeleteProperty (window->display->xdisplay,
00355                        window->xwindow,
00356                        atom);
00357       meta_error_trap_pop (window->display, FALSE);
00358     }
00359 
00360   return modified;
00361 }
00362 
00363 static void
00364 set_window_title (MetaWindow *window,
00365                   const char *title)
00366 {
00367   char *str;
00368  
00369   gboolean modified =
00370     set_title_text (window,
00371                     window->using_net_wm_visible_name,
00372                     title,
00373                     window->display->atom__NET_WM_VISIBLE_NAME,
00374                     &window->title);
00375   window->using_net_wm_visible_name = modified;
00376   
00377   /* strndup is a hack since GNU libc has broken %.10s */
00378   str = g_strndup (window->title, 10);
00379   g_free (window->desc);
00380   window->desc = g_strdup_printf ("0x%lx (%s)", window->xwindow, str);
00381   g_free (str);
00382 
00383   if (window->frame)
00384     meta_ui_set_frame_title (window->screen->ui,
00385                              window->frame->xwindow,
00386                              window->title);
00387 }
00388 
00389 static void
00390 init_net_wm_name (MetaDisplay   *display,
00391                   Atom           property,
00392                   MetaPropValue *value)
00393 {
00394   value->type = META_PROP_VALUE_UTF8;
00395   value->atom = display->atom__NET_WM_NAME;
00396 }
00397 
00398 static void
00399 reload_net_wm_name (MetaWindow    *window,
00400                     MetaPropValue *value)
00401 {
00402   if (value->type != META_PROP_VALUE_INVALID)
00403     {
00404       set_window_title (window, value->v.str);
00405       window->using_net_wm_name = TRUE;
00406 
00407       meta_verbose ("Using _NET_WM_NAME for new title of %s: \"%s\"\n",
00408                     window->desc, window->title);
00409     }
00410   else
00411     {
00412       set_window_title (window, NULL);
00413       window->using_net_wm_name = FALSE;
00414     }
00415 }
00416 
00417 
00418 static void
00419 init_wm_name (MetaDisplay   *display,
00420               Atom           property,
00421               MetaPropValue *value)
00422 {
00423   value->type = META_PROP_VALUE_TEXT_PROPERTY;
00424   value->atom = XA_WM_NAME;
00425 }
00426 
00427 static void
00428 reload_wm_name (MetaWindow    *window,
00429                 MetaPropValue *value)
00430 {
00431   if (window->using_net_wm_name)
00432     {
00433       meta_verbose ("Ignoring WM_NAME \"%s\" as _NET_WM_NAME is set\n",
00434                     value->v.str);
00435       return;
00436     }
00437   
00438   if (value->type != META_PROP_VALUE_INVALID)
00439     {
00440       set_window_title (window, value->v.str);
00441 
00442       meta_verbose ("Using WM_NAME for new title of %s: \"%s\"\n",
00443                     window->desc, window->title);
00444     }
00445   else
00446     {
00447       set_window_title (window, NULL);
00448     }
00449 }
00450 
00451 static void
00452 set_icon_title (MetaWindow *window,
00453                 const char *title)
00454 {
00455   gboolean modified =
00456     set_title_text (window,
00457                     window->using_net_wm_visible_icon_name,
00458                     title,
00459                     window->display->atom__NET_WM_VISIBLE_ICON_NAME,
00460                     &window->icon_name);
00461   window->using_net_wm_visible_icon_name = modified;
00462 }
00463 
00464 static void
00465 init_net_wm_icon_name (MetaDisplay   *display,
00466                   Atom           property,
00467                   MetaPropValue *value)
00468 {
00469   value->type = META_PROP_VALUE_UTF8;
00470   value->atom = display->atom__NET_WM_ICON_NAME;
00471 }
00472 
00473 static void
00474 reload_net_wm_icon_name (MetaWindow    *window,
00475                     MetaPropValue *value)
00476 {
00477   if (value->type != META_PROP_VALUE_INVALID)
00478     {
00479       set_icon_title (window, value->v.str);
00480       window->using_net_wm_icon_name = TRUE;
00481 
00482       meta_verbose ("Using _NET_WM_ICON_NAME for new title of %s: \"%s\"\n",
00483                     window->desc, window->title);
00484     }
00485   else
00486     {
00487       set_icon_title (window, NULL);
00488       window->using_net_wm_icon_name = FALSE;
00489     }
00490 }
00491 
00492 
00493 static void
00494 init_wm_icon_name (MetaDisplay   *display,
00495                   Atom           property,
00496                   MetaPropValue *value)
00497 {
00498   value->type = META_PROP_VALUE_TEXT_PROPERTY;
00499   value->atom = XA_WM_ICON_NAME;
00500 }
00501 
00502 static void
00503 reload_wm_icon_name (MetaWindow    *window,
00504                      MetaPropValue *value)
00505 {
00506   if (window->using_net_wm_icon_name)
00507     {
00508       meta_verbose ("Ignoring WM_ICON_NAME \"%s\" as _NET_WM_ICON_NAME is set\n",
00509                     value->v.str);
00510       return;
00511     }
00512   
00513   if (value->type != META_PROP_VALUE_INVALID)
00514     {
00515       set_icon_title (window, value->v.str);
00516       
00517       meta_verbose ("Using WM_ICON_NAME for new title of %s: \"%s\"\n",
00518                     window->desc, window->title);
00519     }
00520   else
00521     {
00522       set_icon_title (window, NULL);
00523     }
00524 }
00525 
00526 static void
00527 init_net_wm_state (MetaDisplay    *display,
00528                    Atom            property,
00529                    MetaPropValue  *value)
00530 {
00531   value->type = META_PROP_VALUE_ATOM_LIST;
00532   value->atom = display->atom__NET_WM_STATE;
00533 }
00534 
00535 static void
00536 reload_net_wm_state (MetaWindow    *window,
00537                      MetaPropValue *value)
00538 {
00539   int i;
00540 
00541   /* We know this is only an initial window creation,
00542    * clients don't change the property.
00543    */
00544 
00545   window->shaded = FALSE;
00546   window->maximized_horizontally = FALSE;
00547   window->maximized_vertically = FALSE;
00548   window->wm_state_modal = FALSE;
00549   window->wm_state_skip_taskbar = FALSE;
00550   window->wm_state_skip_pager = FALSE;
00551   window->wm_state_above = FALSE;
00552   window->wm_state_below = FALSE;
00553   window->wm_state_demands_attention = FALSE;
00554 
00555   if (value->type == META_PROP_VALUE_INVALID)
00556     return;
00557 
00558   i = 0;
00559   while (i < value->v.atom_list.n_atoms)
00560     {
00561       if (value->v.atom_list.atoms[i] == window->display->atom__NET_WM_STATE_SHADED)
00562         window->shaded = TRUE;
00563       else if (value->v.atom_list.atoms[i] == window->display->atom__NET_WM_STATE_MAXIMIZED_HORZ)
00564         window->maximize_horizontally_after_placement = TRUE;
00565       else if (value->v.atom_list.atoms[i] == window->display->atom__NET_WM_STATE_MAXIMIZED_VERT)
00566         window->maximize_vertically_after_placement = TRUE;
00567       else if (value->v.atom_list.atoms[i] == window->display->atom__NET_WM_STATE_HIDDEN)
00568         window->minimize_after_placement = TRUE;
00569       else if (value->v.atom_list.atoms[i] == window->display->atom__NET_WM_STATE_MODAL)
00570         window->wm_state_modal = TRUE;
00571       else if (value->v.atom_list.atoms[i] == window->display->atom__NET_WM_STATE_SKIP_TASKBAR)
00572         window->wm_state_skip_taskbar = TRUE;
00573       else if (value->v.atom_list.atoms[i] == window->display->atom__NET_WM_STATE_SKIP_PAGER)
00574         window->wm_state_skip_pager = TRUE;
00575       else if (value->v.atom_list.atoms[i] == window->display->atom__NET_WM_STATE_FULLSCREEN)
00576         window->fullscreen = TRUE;
00577       else if (value->v.atom_list.atoms[i] == window->display->atom__NET_WM_STATE_ABOVE)
00578         window->wm_state_above = TRUE;
00579       else if (value->v.atom_list.atoms[i] == window->display->atom__NET_WM_STATE_BELOW)
00580         window->wm_state_below = TRUE;
00581       else if (value->v.atom_list.atoms[i] == window->display->atom__NET_WM_STATE_DEMANDS_ATTENTION)
00582         window->wm_state_demands_attention = TRUE;
00583 
00584       ++i;
00585     }
00586 
00587   meta_verbose ("Reloaded _NET_WM_STATE for %s\n",
00588                 window->desc);
00589 
00590   meta_window_recalc_window_type (window);
00591 }
00592 
00593 static void
00594 init_mwm_hints (MetaDisplay    *display,
00595                 Atom            property,
00596                 MetaPropValue  *value)
00597 {
00598   value->type = META_PROP_VALUE_MOTIF_HINTS;
00599   value->atom = display->atom__MOTIF_WM_HINTS;
00600 }
00601 
00602 static void
00603 reload_mwm_hints (MetaWindow    *window,
00604                   MetaPropValue *value)
00605 {
00606   MotifWmHints *hints;
00607 
00608   window->mwm_decorated = TRUE;
00609   window->mwm_border_only = FALSE;
00610   window->mwm_has_close_func = TRUE;
00611   window->mwm_has_minimize_func = TRUE;
00612   window->mwm_has_maximize_func = TRUE;
00613   window->mwm_has_move_func = TRUE;
00614   window->mwm_has_resize_func = TRUE;
00615 
00616   if (value->type == META_PROP_VALUE_INVALID)
00617     {
00618       meta_verbose ("Window %s has no MWM hints\n", window->desc);
00619       meta_window_recalc_features (window);
00620       return;
00621     }
00622 
00623   hints = value->v.motif_hints;
00624 
00625   /* We support those MWM hints deemed non-stupid */
00626 
00627   meta_verbose ("Window %s has MWM hints\n",
00628                 window->desc);
00629 
00630   if (hints->flags & MWM_HINTS_DECORATIONS)
00631     {
00632       meta_verbose ("Window %s sets MWM_HINTS_DECORATIONS 0x%lx\n",
00633           window->desc, hints->decorations);
00634 
00635       if (hints->decorations == 0)
00636         window->mwm_decorated = FALSE;
00637       /* some input methods use this */
00638       else if (hints->decorations == MWM_DECOR_BORDER)
00639         window->mwm_border_only = TRUE;
00640     }
00641   else
00642     meta_verbose ("Decorations flag unset\n");
00643 
00644   if (hints->flags & MWM_HINTS_FUNCTIONS)
00645     {
00646       gboolean toggle_value;
00647 
00648       meta_verbose ("Window %s sets MWM_HINTS_FUNCTIONS 0x%lx\n",
00649                     window->desc, hints->functions);
00650 
00651       /* If _ALL is specified, then other flags indicate what to turn off;
00652        * if ALL is not specified, flags are what to turn on.
00653        * at least, I think so
00654        */
00655 
00656       if ((hints->functions & MWM_FUNC_ALL) == 0)
00657         {
00658           toggle_value = TRUE;
00659 
00660           meta_verbose ("Window %s disables all funcs then reenables some\n",
00661                         window->desc);
00662           window->mwm_has_close_func = FALSE;
00663           window->mwm_has_minimize_func = FALSE;
00664           window->mwm_has_maximize_func = FALSE;
00665           window->mwm_has_move_func = FALSE;
00666           window->mwm_has_resize_func = FALSE;
00667         }
00668       else
00669         {
00670           meta_verbose ("Window %s enables all funcs then disables some\n",
00671                         window->desc);
00672           toggle_value = FALSE;
00673         }
00674 
00675       if ((hints->functions & MWM_FUNC_CLOSE) != 0)
00676         {
00677           meta_verbose ("Window %s toggles close via MWM hints\n",
00678                         window->desc);
00679           window->mwm_has_close_func = toggle_value;
00680         }
00681       if ((hints->functions & MWM_FUNC_MINIMIZE) != 0)
00682         {
00683           meta_verbose ("Window %s toggles minimize via MWM hints\n",
00684                         window->desc);
00685           window->mwm_has_minimize_func = toggle_value;
00686         }
00687       if ((hints->functions & MWM_FUNC_MAXIMIZE) != 0)
00688         {
00689           meta_verbose ("Window %s toggles maximize via MWM hints\n",
00690                         window->desc);
00691           window->mwm_has_maximize_func = toggle_value;
00692         }
00693       if ((hints->functions & MWM_FUNC_MOVE) != 0)
00694         {
00695           meta_verbose ("Window %s toggles move via MWM hints\n",
00696                         window->desc);
00697           window->mwm_has_move_func = toggle_value;
00698         }
00699       if ((hints->functions & MWM_FUNC_RESIZE) != 0)
00700         {
00701           meta_verbose ("Window %s toggles resize via MWM hints\n",
00702                         window->desc);
00703           window->mwm_has_resize_func = toggle_value;
00704         }
00705     }
00706   else
00707     meta_verbose ("Functions flag unset\n");
00708 
00709   meta_window_recalc_features (window);
00710   
00711   /* We do all this anyhow at the end of meta_window_new() */
00712   if (!window->constructing)
00713     {
00714       if (window->decorated)
00715         meta_window_ensure_frame (window);
00716       else
00717         meta_window_destroy_frame (window);
00718       
00719       meta_window_queue (window,
00720                          META_QUEUE_MOVE_RESIZE |
00721                          /* because ensure/destroy frame may unmap: */
00722                          META_QUEUE_CALC_SHOWING);
00723     }
00724 }
00725 
00726 static void
00727 init_wm_class (MetaDisplay    *display,
00728                Atom            property,
00729                MetaPropValue  *value)
00730 {
00731   value->type = META_PROP_VALUE_CLASS_HINT;
00732   value->atom = XA_WM_CLASS;
00733 }
00734 
00735 static void
00736 reload_wm_class (MetaWindow    *window,
00737                  MetaPropValue *value)
00738 {
00739   if (window->res_class)
00740     g_free (window->res_class);
00741   if (window->res_name)
00742     g_free (window->res_name);
00743 
00744   window->res_class = NULL;
00745   window->res_name = NULL;
00746 
00747   if (value->type != META_PROP_VALUE_INVALID)
00748     { 
00749       if (value->v.class_hint.res_name)
00750         window->res_name = g_strdup (value->v.class_hint.res_name);
00751 
00752       if (value->v.class_hint.res_class)
00753         window->res_class = g_strdup (value->v.class_hint.res_class);
00754     }
00755 
00756   meta_verbose ("Window %s class: '%s' name: '%s'\n",
00757       window->desc,
00758       window->res_class ? window->res_class : "none",
00759       window->res_name ? window->res_name : "none");
00760 }
00761 
00762 static void
00763 init_net_wm_desktop (MetaDisplay   *display,
00764                      Atom           property,
00765                      MetaPropValue *value)
00766 {
00767   value->type = META_PROP_VALUE_CARDINAL;
00768   value->atom = display->atom__NET_WM_DESKTOP;
00769 }
00770 
00771 static void
00772 reload_net_wm_desktop (MetaWindow    *window,
00773                        MetaPropValue *value)
00774 {
00775   if (value->type != META_PROP_VALUE_INVALID)
00776     {
00777       window->initial_workspace_set = TRUE;
00778       window->initial_workspace = value->v.cardinal;
00779       meta_topic (META_DEBUG_PLACEMENT,
00780                   "Read initial workspace prop %d for %s\n",
00781                   window->initial_workspace, window->desc);
00782     }
00783 }
00784 
00785 static void
00786 init_net_startup_id (MetaDisplay   *display,
00787                      Atom           property,
00788                      MetaPropValue *value)
00789 {
00790   value->type = META_PROP_VALUE_UTF8;
00791   value->atom = display->atom__NET_STARTUP_ID;
00792 }
00793 
00794 static void
00795 reload_net_startup_id (MetaWindow    *window,
00796                        MetaPropValue *value)
00797 {
00798   guint32 timestamp = window->net_wm_user_time;
00799   MetaWorkspace *workspace = NULL;
00800   
00801   g_free (window->startup_id);
00802   
00803   if (value->type != META_PROP_VALUE_INVALID)
00804     window->startup_id = g_strdup (value->v.str);
00805   else
00806     window->startup_id = NULL;
00807     
00808   /* Update timestamp and workspace on a running window */
00809   if (!window->constructing)
00810   {
00811     window->initial_timestamp_set = 0;  
00812     window->initial_workspace_set = 0;
00813     
00814     if (meta_screen_apply_startup_properties (window->screen, window))
00815       {
00816   
00817         if (window->initial_timestamp_set)
00818           timestamp = window->initial_timestamp;
00819         if (window->initial_workspace_set)
00820           workspace = meta_screen_get_workspace_by_index (window->screen, window->initial_workspace);
00821     
00822         meta_window_activate_with_workspace (window, timestamp, workspace);
00823       }
00824   }
00825   
00826   meta_verbose ("New _NET_STARTUP_ID \"%s\" for %s\n",
00827                 window->startup_id ? window->startup_id : "unset",
00828                 window->desc);
00829 }
00830 
00831 static void
00832 init_update_counter (MetaDisplay   *display,
00833                      Atom           property,
00834                      MetaPropValue *value)
00835 {
00836   value->type = META_PROP_VALUE_SYNC_COUNTER;
00837   value->atom = display->atom__NET_WM_SYNC_REQUEST_COUNTER;
00838 }
00839 
00840 static void
00841 reload_update_counter (MetaWindow    *window,
00842                        MetaPropValue *value)
00843 {
00844   if (value->type != META_PROP_VALUE_INVALID)
00845     {
00846 #ifdef HAVE_XSYNC
00847       XSyncCounter counter = value->v.xcounter;
00848 
00849       window->sync_request_counter = counter;
00850       meta_verbose ("Window has _NET_WM_SYNC_REQUEST_COUNTER 0x%lx\n",
00851                     window->sync_request_counter);
00852 #endif
00853     }
00854 }
00855 
00856 
00857 static void
00858 init_normal_hints (MetaDisplay   *display,
00859                    Atom           property,
00860                    MetaPropValue *value)
00861 {
00862   value->type = META_PROP_VALUE_SIZE_HINTS;
00863   value->atom = XA_WM_NORMAL_HINTS;
00864 }
00865 
00866 
00867 #define FLAG_TOGGLED_ON(old,new,flag) \
00868  (((old)->flags & (flag)) == 0 &&     \
00869   ((new)->flags & (flag)) != 0)
00870 
00871 #define FLAG_TOGGLED_OFF(old,new,flag) \
00872  (((old)->flags & (flag)) != 0 &&      \
00873   ((new)->flags & (flag)) == 0)
00874 
00875 #define FLAG_CHANGED(old,new,flag) \
00876   (FLAG_TOGGLED_ON(old,new,flag) || FLAG_TOGGLED_OFF(old,new,flag))
00877 
00878 static void
00879 spew_size_hints_differences (const XSizeHints *old,
00880                              const XSizeHints *new)
00881 {
00882   if (FLAG_CHANGED (old, new, USPosition))
00883     meta_topic (META_DEBUG_GEOMETRY, "XSizeHints: USPosition now %s\n",
00884                 FLAG_TOGGLED_ON (old, new, USPosition) ? "set" : "unset");
00885   if (FLAG_CHANGED (old, new, USSize))
00886     meta_topic (META_DEBUG_GEOMETRY, "XSizeHints: USSize now %s\n",
00887                 FLAG_TOGGLED_ON (old, new, USSize) ? "set" : "unset");
00888   if (FLAG_CHANGED (old, new, PPosition))
00889     meta_topic (META_DEBUG_GEOMETRY, "XSizeHints: PPosition now %s\n",
00890                 FLAG_TOGGLED_ON (old, new, PPosition) ? "set" : "unset");
00891   if (FLAG_CHANGED (old, new, PSize))
00892     meta_topic (META_DEBUG_GEOMETRY, "XSizeHints: PSize now %s\n",
00893                 FLAG_TOGGLED_ON (old, new, PSize) ? "set" : "unset");
00894   if (FLAG_CHANGED (old, new, PMinSize))
00895     meta_topic (META_DEBUG_GEOMETRY, "XSizeHints: PMinSize now %s (%d x %d -> %d x %d)\n",
00896                 FLAG_TOGGLED_ON (old, new, PMinSize) ? "set" : "unset",
00897                 old->min_width, old->min_height,
00898                 new->min_width, new->min_height);
00899   if (FLAG_CHANGED (old, new, PMaxSize))
00900     meta_topic (META_DEBUG_GEOMETRY, "XSizeHints: PMaxSize now %s (%d x %d -> %d x %d)\n",
00901                 FLAG_TOGGLED_ON (old, new, PMaxSize) ? "set" : "unset",
00902                 old->max_width, old->max_height,
00903                 new->max_width, new->max_height);
00904   if (FLAG_CHANGED (old, new, PResizeInc))
00905     meta_topic (META_DEBUG_GEOMETRY, "XSizeHints: PResizeInc now %s (width_inc %d -> %d height_inc %d -> %d)\n",
00906                 FLAG_TOGGLED_ON (old, new, PResizeInc) ? "set" : "unset",
00907                 old->width_inc, new->width_inc,
00908                 old->height_inc, new->height_inc);
00909   if (FLAG_CHANGED (old, new, PAspect))
00910     meta_topic (META_DEBUG_GEOMETRY, "XSizeHints: PAspect now %s (min %d/%d -> %d/%d max %d/%d -> %d/%d)\n",
00911                 FLAG_TOGGLED_ON (old, new, PAspect) ? "set" : "unset",
00912                 old->min_aspect.x, old->min_aspect.y,
00913                 new->min_aspect.x, new->min_aspect.y,
00914                 old->max_aspect.x, old->max_aspect.y,
00915                 new->max_aspect.x, new->max_aspect.y);
00916   if (FLAG_CHANGED (old, new, PBaseSize))
00917     meta_topic (META_DEBUG_GEOMETRY, "XSizeHints: PBaseSize now %s (%d x %d -> %d x %d)\n",
00918                 FLAG_TOGGLED_ON (old, new, PBaseSize) ? "set" : "unset",
00919                 old->base_width, old->base_height,
00920                 new->base_width, new->base_height);
00921   if (FLAG_CHANGED (old, new, PWinGravity))
00922     meta_topic (META_DEBUG_GEOMETRY, "XSizeHints: PWinGravity now %s  (%d -> %d)\n",
00923                 FLAG_TOGGLED_ON (old, new, PWinGravity) ? "set" : "unset",
00924                 old->win_gravity, new->win_gravity);  
00925 }
00926 
00927 void
00928 meta_set_normal_hints (MetaWindow *window,
00929                        XSizeHints *hints)
00930 {
00931   int x, y, w, h;
00932   double minr, maxr;
00933   /* Some convenience vars */
00934   int minw, minh, maxw, maxh;   /* min/max width/height                      */
00935   int basew, baseh, winc, hinc; /* base width/height, width/height increment */
00936 
00937   /* Save the last ConfigureRequest, which we put here.
00938    * Values here set in the hints are supposed to
00939    * be ignored.
00940    */
00941   x = window->size_hints.x;
00942   y = window->size_hints.y;
00943   w = window->size_hints.width;
00944   h = window->size_hints.height;
00945 
00946   /* as far as I can tell, value->v.size_hints.flags is just to
00947    * check whether we had old-style normal hints without gravity,
00948    * base size as returned by XGetNormalHints(), so we don't
00949    * really use it as we fixup window->size_hints to have those
00950    * fields if they're missing.
00951    */
00952 
00953   /*
00954    * When the window is first created, NULL hints will
00955    * be passed in which will initialize all of the fields
00956    * as if flags were zero
00957    */
00958   if (hints)
00959     window->size_hints = *hints;
00960   else
00961     window->size_hints.flags = 0;
00962 
00963   /* Put back saved ConfigureRequest. */
00964   window->size_hints.x = x;
00965   window->size_hints.y = y;
00966   window->size_hints.width = w;
00967   window->size_hints.height = h;
00968 
00969   /* Get base size hints */
00970   if (window->size_hints.flags & PBaseSize)
00971     {
00972       meta_topic (META_DEBUG_GEOMETRY, "Window %s sets base size %d x %d\n",
00973                   window->desc,
00974                   window->size_hints.base_width,
00975                   window->size_hints.base_height);
00976     }
00977   else if (window->size_hints.flags & PMinSize)
00978     {
00979       window->size_hints.base_width = window->size_hints.min_width;
00980       window->size_hints.base_height = window->size_hints.min_height;
00981     }
00982   else
00983     {
00984       window->size_hints.base_width = 0;
00985       window->size_hints.base_height = 0;
00986     }
00987   window->size_hints.flags |= PBaseSize;
00988 
00989   /* Get min size hints */
00990   if (window->size_hints.flags & PMinSize)
00991     {
00992       meta_topic (META_DEBUG_GEOMETRY, "Window %s sets min size %d x %d\n",
00993                   window->desc,
00994                   window->size_hints.min_width,
00995                   window->size_hints.min_height);
00996     }
00997   else if (window->size_hints.flags & PBaseSize)
00998     {
00999       window->size_hints.min_width = window->size_hints.base_width;
01000       window->size_hints.min_height = window->size_hints.base_height;
01001     }
01002   else
01003     {
01004       window->size_hints.min_width = 0;
01005       window->size_hints.min_height = 0;
01006     }
01007   window->size_hints.flags |= PMinSize;
01008 
01009   /* Get max size hints */
01010   if (window->size_hints.flags & PMaxSize)
01011     {
01012       meta_topic (META_DEBUG_GEOMETRY, "Window %s sets max size %d x %d\n",
01013                   window->desc,
01014                   window->size_hints.max_width,
01015                   window->size_hints.max_height);
01016     }
01017   else
01018     {
01019       window->size_hints.max_width = G_MAXINT;
01020       window->size_hints.max_height = G_MAXINT;
01021       window->size_hints.flags |= PMaxSize;
01022     }
01023 
01024   /* Get resize increment hints */
01025   if (window->size_hints.flags & PResizeInc)
01026     {
01027       meta_topic (META_DEBUG_GEOMETRY,
01028                   "Window %s sets resize width inc: %d height inc: %d\n",
01029                   window->desc,
01030                   window->size_hints.width_inc,
01031                   window->size_hints.height_inc);
01032     }
01033   else
01034     {
01035       window->size_hints.width_inc = 1;
01036       window->size_hints.height_inc = 1;
01037       window->size_hints.flags |= PResizeInc;
01038     }
01039 
01040   /* Get aspect ratio hints */
01041   if (window->size_hints.flags & PAspect)
01042     {
01043       meta_topic (META_DEBUG_GEOMETRY,
01044                   "Window %s sets min_aspect: %d/%d max_aspect: %d/%d\n",
01045                   window->desc,
01046                   window->size_hints.min_aspect.x,
01047                   window->size_hints.min_aspect.y,
01048                   window->size_hints.max_aspect.x,
01049                   window->size_hints.max_aspect.y);
01050     }
01051   else
01052     {
01053       window->size_hints.min_aspect.x = 1;
01054       window->size_hints.min_aspect.y = G_MAXINT;
01055       window->size_hints.max_aspect.x = G_MAXINT;
01056       window->size_hints.max_aspect.y = 1;
01057       window->size_hints.flags |= PAspect;
01058     }
01059 
01060   /* Get gravity hint */
01061   if (window->size_hints.flags & PWinGravity)
01062     {
01063       meta_topic (META_DEBUG_GEOMETRY, "Window %s sets gravity %d\n",
01064                   window->desc,
01065                   window->size_hints.win_gravity);
01066     }
01067   else
01068     {
01069       meta_topic (META_DEBUG_GEOMETRY,
01070                   "Window %s doesn't set gravity, using NW\n",
01071                   window->desc);
01072       window->size_hints.win_gravity = NorthWestGravity;
01073       window->size_hints.flags |= PWinGravity;
01074     }
01075 
01076   /*** Lots of sanity checking ***/
01077 
01078   /* Verify all min & max hints are at least 1 pixel */
01079   if (window->size_hints.min_width < 1)
01080     {
01081       /* someone is on crack */
01082       meta_topic (META_DEBUG_GEOMETRY,
01083                   "Window %s sets min width to 0, which makes no sense\n",
01084                   window->desc);
01085       window->size_hints.min_width = 1;
01086     }
01087   if (window->size_hints.max_width < 1)
01088     {
01089       /* another cracksmoker */
01090       meta_topic (META_DEBUG_GEOMETRY,
01091                   "Window %s sets max width to 0, which makes no sense\n",
01092                   window->desc);
01093       window->size_hints.max_width = 1;
01094     }
01095   if (window->size_hints.min_height < 1)
01096     {
01097       /* another cracksmoker */
01098       meta_topic (META_DEBUG_GEOMETRY,
01099                   "Window %s sets min height to 0, which makes no sense\n",
01100                   window->desc);
01101       window->size_hints.min_height = 1;
01102     }
01103   if (window->size_hints.max_height < 1)
01104     {
01105       /* another cracksmoker */
01106       meta_topic (META_DEBUG_GEOMETRY,
01107                   "Window %s sets max height to 0, which makes no sense\n",
01108                   window->desc);
01109       window->size_hints.max_height = 1;
01110     }
01111 
01112   /* Verify size increment hints are at least 1 pixel */
01113   if (window->size_hints.width_inc < 1)
01114     {
01115       /* app authors find so many ways to smoke crack */
01116       window->size_hints.width_inc = 1;
01117       meta_topic (META_DEBUG_GEOMETRY, "Corrected 0 width_inc to 1\n");
01118     }
01119   if (window->size_hints.height_inc < 1)
01120     {
01121       /* another cracksmoker */
01122       window->size_hints.height_inc = 1;
01123       meta_topic (META_DEBUG_GEOMETRY, "Corrected 0 height_inc to 1\n");
01124     }
01125   /* divide by 0 cracksmokers; note that x & y in (min|max)_aspect are
01126    * numerator & denominator
01127    */
01128   if (window->size_hints.min_aspect.y < 1)
01129     window->size_hints.min_aspect.y = 1;
01130   if (window->size_hints.max_aspect.y < 1)
01131     window->size_hints.max_aspect.y = 1;
01132 
01133   minw  = window->size_hints.min_width;  minh  = window->size_hints.min_height;
01134   maxw  = window->size_hints.max_width;  maxh  = window->size_hints.max_height;
01135   basew = window->size_hints.base_width; baseh = window->size_hints.base_height;
01136   winc  = window->size_hints.width_inc;  hinc  = window->size_hints.height_inc;
01137 
01138   /* Make sure min and max size hints are consistent with the base + increment
01139    * size hints.  If they're not, it's not a real big deal, but it means the
01140    * effective min and max size are more restrictive than the application
01141    * specified values.
01142    */
01143   if ((minw - basew) % winc != 0)
01144     {
01145       /* Take advantage of integer division throwing away the remainder... */
01146       window->size_hints.min_width = basew + ((minw - basew)/winc + 1)*winc;
01147 
01148       meta_topic (META_DEBUG_GEOMETRY,
01149                   "Window %s has width_inc (%d) that does not evenly divide "
01150                   "min_width - base_width (%d - %d); thus effective "
01151                   "min_width is really %d\n",
01152                   window->desc,
01153                   winc, minw, basew, window->size_hints.min_width);
01154       minw = window->size_hints.min_width;
01155     }
01156   if (maxw != G_MAXINT && (maxw - basew) % winc != 0)
01157     {
01158       /* Take advantage of integer division throwing away the remainder... */
01159       window->size_hints.max_width = basew + ((maxw - basew)/winc)*winc;
01160 
01161       meta_topic (META_DEBUG_GEOMETRY,
01162                   "Window %s has width_inc (%d) that does not evenly divide "
01163                   "max_width - base_width (%d - %d); thus effective "
01164                   "max_width is really %d\n",
01165                   window->desc,
01166                   winc, maxw, basew, window->size_hints.max_width);
01167       maxw = window->size_hints.max_width;
01168     }
01169   if ((minh - baseh) % hinc != 0)
01170     {
01171       /* Take advantage of integer division throwing away the remainder... */
01172       window->size_hints.min_height = baseh + ((minh - baseh)/hinc + 1)*hinc;
01173 
01174       meta_topic (META_DEBUG_GEOMETRY,
01175                   "Window %s has height_inc (%d) that does not evenly divide "
01176                   "min_height - base_height (%d - %d); thus effective "
01177                   "min_height is really %d\n",
01178                   window->desc,
01179                   hinc, minh, baseh, window->size_hints.min_height);
01180       minh = window->size_hints.min_height;
01181     }
01182   if (maxh != G_MAXINT && (maxh - baseh) % hinc != 0)
01183     {
01184       /* Take advantage of integer division throwing away the remainder... */
01185       window->size_hints.max_height = baseh + ((maxh - baseh)/hinc)*hinc;
01186 
01187       meta_topic (META_DEBUG_GEOMETRY,
01188                   "Window %s has height_inc (%d) that does not evenly divide "
01189                   "max_height - base_height (%d - %d); thus effective "
01190                   "max_height is really %d\n",
01191                   window->desc,
01192                   hinc, maxh, baseh, window->size_hints.max_height);
01193       maxh = window->size_hints.max_height;
01194     }
01195 
01196   /* make sure maximum size hints are compatible with minimum size hints; min
01197    * size hints take precedence.
01198    */
01199   if (window->size_hints.max_width < window->size_hints.min_width)
01200     {
01201       /* another cracksmoker */
01202       meta_topic (META_DEBUG_GEOMETRY,
01203                   "Window %s sets max width %d less than min width %d, "
01204                   "disabling resize\n",
01205                   window->desc,
01206                   window->size_hints.max_width,
01207                   window->size_hints.min_width);
01208       maxw = window->size_hints.max_width = window->size_hints.min_width;
01209     }
01210   if (window->size_hints.max_height < window->size_hints.min_height)
01211     {
01212       /* another cracksmoker */
01213       meta_topic (META_DEBUG_GEOMETRY,
01214                   "Window %s sets max height %d less than min height %d, "
01215                   "disabling resize\n",
01216                   window->desc,
01217                   window->size_hints.max_height,
01218                   window->size_hints.min_height);
01219       maxh = window->size_hints.max_height = window->size_hints.min_height;
01220     }
01221 
01222   /* Make sure the aspect ratio hints are sane. */
01223   minr =         window->size_hints.min_aspect.x /
01224          (double)window->size_hints.min_aspect.y;
01225   maxr =         window->size_hints.max_aspect.x /
01226          (double)window->size_hints.max_aspect.y;
01227   if (minr > maxr)
01228     {
01229       /* another cracksmoker; not even minimally (self) consistent */
01230       meta_topic (META_DEBUG_GEOMETRY,
01231                   "Window %s sets min aspect ratio larger than max aspect "
01232                   "ratio; disabling aspect ratio constraints.\n",
01233                   window->desc);
01234       window->size_hints.min_aspect.x = 1;
01235       window->size_hints.min_aspect.y = G_MAXINT;
01236       window->size_hints.max_aspect.x = G_MAXINT;
01237       window->size_hints.max_aspect.y = 1;
01238     }
01239   else /* check consistency of aspect ratio hints with other hints */
01240     {
01241       if (minh > 0 && minr > (maxw / (double)minh))
01242         {
01243           /* another cracksmoker */
01244           meta_topic (META_DEBUG_GEOMETRY,
01245                       "Window %s sets min aspect ratio larger than largest "
01246                       "aspect ratio possible given min/max size constraints; "
01247                       "disabling min aspect ratio constraint.\n",
01248                       window->desc);
01249           window->size_hints.min_aspect.x = 1;
01250           window->size_hints.min_aspect.y = G_MAXINT;
01251         }
01252       if (maxr < (minw / (double)maxh))
01253         {
01254           /* another cracksmoker */
01255           meta_topic (META_DEBUG_GEOMETRY,
01256                       "Window %s sets max aspect ratio smaller than smallest "
01257                       "aspect ratio possible given min/max size constraints; "
01258                       "disabling max aspect ratio constraint.\n",
01259                       window->desc);
01260           window->size_hints.max_aspect.x = G_MAXINT;
01261           window->size_hints.max_aspect.y = 1;
01262         }
01263       /* FIXME: Would be nice to check that aspect ratios are
01264        * consistent with base and size increment constraints.
01265        */
01266     }
01267 }
01268 
01269 static void
01270 reload_normal_hints (MetaWindow    *window,
01271                      MetaPropValue *value)
01272 {
01273   if (value->type != META_PROP_VALUE_INVALID)
01274     {
01275       XSizeHints old_hints;
01276   
01277       meta_topic (META_DEBUG_GEOMETRY, "Updating WM_NORMAL_HINTS for %s\n", window->desc);
01278 
01279       old_hints = window->size_hints;
01280   
01281       meta_set_normal_hints (window, value->v.size_hints.hints);
01282       
01283       spew_size_hints_differences (&old_hints, &window->size_hints);
01284       
01285       meta_window_recalc_features (window);
01286     }
01287 }
01288 
01289 
01290 static void
01291 init_wm_protocols (MetaDisplay   *display,
01292                    Atom           property,
01293                    MetaPropValue *value)
01294 {
01295   value->type = META_PROP_VALUE_ATOM_LIST;
01296   value->atom = display->atom_WM_PROTOCOLS;
01297 }
01298 
01299 static void
01300 reload_wm_protocols (MetaWindow    *window,
01301                      MetaPropValue *value)
01302 {
01303   int i;
01304   
01305   window->take_focus = FALSE;
01306   window->delete_window = FALSE;
01307   window->net_wm_ping = FALSE;
01308   
01309   if (value->type == META_PROP_VALUE_INVALID)    
01310     return;
01311 
01312   i = 0;
01313   while (i < value->v.atom_list.n_atoms)
01314     {
01315       if (value->v.atom_list.atoms[i] ==
01316           window->display->atom_WM_TAKE_FOCUS)
01317         window->take_focus = TRUE;
01318       else if (value->v.atom_list.atoms[i] ==
01319                window->display->atom_WM_DELETE_WINDOW)
01320         window->delete_window = TRUE;
01321       else if (value->v.atom_list.atoms[i] ==
01322                window->display->atom__NET_WM_PING)
01323         window->net_wm_ping = TRUE;
01324       ++i;
01325     }
01326   
01327   meta_verbose ("New _NET_STARTUP_ID \"%s\" for %s\n",
01328                 window->startup_id ? window->startup_id : "unset",
01329                 window->desc);
01330 }
01331 
01332 static void
01333 init_wm_hints (MetaDisplay   *display,
01334                Atom           property,
01335                MetaPropValue *value)
01336 {
01337   value->type = META_PROP_VALUE_WM_HINTS;
01338   value->atom = XA_WM_HINTS;
01339 }
01340 
01341 static void
01342 reload_wm_hints (MetaWindow    *window,
01343                  MetaPropValue *value)
01344 {
01345   Window old_group_leader;
01346   
01347   old_group_leader = window->xgroup_leader;
01348   
01349   /* Fill in defaults */
01350   window->input = TRUE;
01351   window->initially_iconic = FALSE;
01352   window->xgroup_leader = None;
01353   window->wm_hints_pixmap = None;
01354   window->wm_hints_mask = None;
01355   
01356   if (value->type != META_PROP_VALUE_INVALID)
01357     {
01358       const XWMHints *hints = value->v.wm_hints;
01359       
01360       if (hints->flags & InputHint)
01361         window->input = hints->input;
01362 
01363       if (hints->flags & StateHint)
01364         window->initially_iconic = (hints->initial_state == IconicState);
01365 
01366       if (hints->flags & WindowGroupHint)
01367         window->xgroup_leader = hints->window_group;
01368 
01369       if (hints->flags & IconPixmapHint)
01370         window->wm_hints_pixmap = hints->icon_pixmap;
01371 
01372       if (hints->flags & IconMaskHint)
01373         window->wm_hints_mask = hints->icon_mask;
01374       
01375       meta_verbose ("Read WM_HINTS input: %d iconic: %d group leader: 0x%lx pixmap: 0x%lx mask: 0x%lx\n",
01376                     window->input, window->initially_iconic,
01377                     window->xgroup_leader,
01378                     window->wm_hints_pixmap,
01379                     window->wm_hints_mask);
01380     }
01381 
01382   if (window->xgroup_leader != old_group_leader)
01383     {
01384       meta_verbose ("Window %s changed its group leader to 0x%lx\n",
01385                     window->desc, window->xgroup_leader);
01386       
01387       meta_window_group_leader_changed (window);
01388     }
01389 
01390   meta_icon_cache_property_changed (&window->icon_cache,
01391                                     window->display,
01392                                     XA_WM_HINTS);
01393 
01394   meta_window_queue (window, META_QUEUE_UPDATE_ICON | META_QUEUE_MOVE_RESIZE);
01395 }
01396 
01397 static void
01398 init_transient_for (MetaDisplay   *display,
01399                     Atom           property,
01400                     MetaPropValue *value)
01401 {
01402   value->type = META_PROP_VALUE_WINDOW;
01403   value->atom = XA_WM_TRANSIENT_FOR;
01404 }
01405 
01406 static void
01407 reload_transient_for (MetaWindow    *window,
01408                       MetaPropValue *value)
01409 {
01410   window->xtransient_for = None;
01411   
01412   if (value->type != META_PROP_VALUE_INVALID)
01413     window->xtransient_for = value->v.xwindow;
01414 
01415   /* Make sure transient_for is valid */
01416   if (window->xtransient_for != None &&
01417       meta_display_lookup_x_window (window->display, 
01418                                     window->xtransient_for) == NULL)
01419     {
01420       meta_warning (_("Invalid WM_TRANSIENT_FOR window 0x%lx specified "
01421                       "for %s.\n"),
01422                     window->xtransient_for, window->desc);
01423       window->xtransient_for = None;
01424     }
01425 
01426   window->transient_parent_is_root_window =
01427     window->xtransient_for == window->screen->xroot;
01428 
01429   if (window->xtransient_for != None)
01430     meta_verbose ("Window %s transient for 0x%lx (root = %d)\n", window->desc,
01431         window->xtransient_for, window->transient_parent_is_root_window);
01432   else
01433     meta_verbose ("Window %s is not transient\n", window->desc);
01434 
01435   /* may now be a dialog */
01436   meta_window_recalc_window_type (window);
01437 
01438   /* update stacking constraints */
01439   meta_stack_update_transient (window->screen->stack, window);
01440 
01441   /* possibly change its group. We treat being a window's transient as
01442    * equivalent to making it your group leader, to work around shortcomings
01443    * in programs such as xmms-- see #328211.
01444    */
01445   if (window->xtransient_for != None &&
01446       window->xgroup_leader != None &&
01447       window->xtransient_for != window->xgroup_leader)
01448     meta_window_group_leader_changed (window);
01449 
01450   if (!window->constructing)
01451     meta_window_queue (window, META_QUEUE_MOVE_RESIZE);
01452 }
01453 
01454 #define N_HOOKS 26
01455 
01456 void
01457 meta_display_init_window_prop_hooks (MetaDisplay *display)
01458 {
01459   int i;
01460   MetaWindowPropHooks *hooks;
01461   
01462   g_assert (display->prop_hooks == NULL);
01463 
01464   display->prop_hooks = g_new0 (MetaWindowPropHooks, N_HOOKS); 
01465   hooks = display->prop_hooks;
01466   
01467   i = 0;
01468 
01469   hooks[i].property = display->atom_WM_STATE;
01470   hooks[i].init_func = NULL;
01471   hooks[i].reload_func = NULL;
01472   ++i;
01473 
01474   hooks[i].property = display->atom_WM_CLIENT_MACHINE;
01475   hooks[i].init_func = init_wm_client_machine;
01476   hooks[i].reload_func = reload_wm_client_machine;
01477   ++i;
01478 
01479   hooks[i].property = display->atom__NET_WM_PID;
01480   hooks[i].init_func = init_net_wm_pid;
01481   hooks[i].reload_func = reload_net_wm_pid;
01482   ++i;
01483 
01484   hooks[i].property = display->atom__NET_WM_USER_TIME;
01485   hooks[i].init_func = init_net_wm_user_time;
01486   hooks[i].reload_func = reload_net_wm_user_time;
01487   ++i;
01488 
01489   hooks[i].property = display->atom__NET_WM_NAME;
01490   hooks[i].init_func = init_net_wm_name;
01491   hooks[i].reload_func = reload_net_wm_name;
01492   ++i;
01493 
01494   hooks[i].property = XA_WM_NAME;
01495   hooks[i].init_func = init_wm_name;
01496   hooks[i].reload_func = reload_wm_name;
01497   ++i;
01498 
01499   hooks[i].property = display->atom__NET_WM_ICON_NAME;
01500   hooks[i].init_func = init_net_wm_icon_name;
01501   hooks[i].reload_func = reload_net_wm_icon_name;
01502   ++i;
01503 
01504   hooks[i].property = XA_WM_ICON_NAME;
01505   hooks[i].init_func = init_wm_icon_name;
01506   hooks[i].reload_func = reload_wm_icon_name;
01507   ++i;
01508 
01509   hooks[i].property = display->atom__NET_WM_STATE;
01510   hooks[i].init_func = init_net_wm_state;
01511   hooks[i].reload_func = reload_net_wm_state;
01512   ++i;
01513   
01514   hooks[i].property = display->atom__MOTIF_WM_HINTS;
01515   hooks[i].init_func = init_mwm_hints;
01516   hooks[i].reload_func = reload_mwm_hints;
01517   ++i;
01518 
01519   hooks[i].property = display->atom__NET_WM_ICON_GEOMETRY;
01520   hooks[i].init_func = NULL;
01521   hooks[i].reload_func = NULL;
01522   ++i;
01523 
01524   hooks[i].property = XA_WM_CLASS;
01525   hooks[i].init_func = init_wm_class;
01526   hooks[i].reload_func = reload_wm_class;
01527   ++i;
01528 
01529   hooks[i].property = display->atom_WM_CLIENT_LEADER;
01530   hooks[i].init_func = NULL;
01531   hooks[i].reload_func = NULL;
01532   ++i;
01533 
01534   hooks[i].property = display->atom_SM_CLIENT_ID;
01535   hooks[i].init_func = NULL;
01536   hooks[i].reload_func = NULL;
01537   ++i;
01538 
01539   hooks[i].property = display->atom_WM_WINDOW_ROLE;
01540   hooks[i].init_func = NULL;
01541   hooks[i].reload_func = NULL;
01542   ++i;
01543 
01544   hooks[i].property = display->atom__NET_WM_WINDOW_TYPE;
01545   hooks[i].init_func = NULL;
01546   hooks[i].reload_func = NULL;
01547   ++i;
01548 
01549   hooks[i].property = display->atom__NET_WM_DESKTOP;
01550   hooks[i].init_func = init_net_wm_desktop;
01551   hooks[i].reload_func = reload_net_wm_desktop;
01552   ++i;
01553 
01554   hooks[i].property = display->atom__NET_WM_STRUT;
01555   hooks[i].init_func = NULL;
01556   hooks[i].reload_func = NULL;
01557   ++i;
01558 
01559   hooks[i].property = display->atom__NET_WM_STRUT_PARTIAL;
01560   hooks[i].init_func = NULL;
01561   hooks[i].reload_func = NULL;
01562   ++i;
01563 
01564   hooks[i].property = display->atom__NET_STARTUP_ID;
01565   hooks[i].init_func = init_net_startup_id;
01566   hooks[i].reload_func = reload_net_startup_id;
01567   ++i;
01568 
01569   hooks[i].property = display->atom__NET_WM_SYNC_REQUEST_COUNTER;
01570   hooks[i].init_func = init_update_counter;
01571   hooks[i].reload_func = reload_update_counter;
01572   ++i;
01573 
01574   hooks[i].property = XA_WM_NORMAL_HINTS;
01575   hooks[i].init_func = init_normal_hints;
01576   hooks[i].reload_func = reload_normal_hints;
01577   ++i;
01578 
01579   hooks[i].property = display->atom_WM_PROTOCOLS;
01580   hooks[i].init_func = init_wm_protocols;
01581   hooks[i].reload_func = reload_wm_protocols;
01582   ++i;
01583 
01584   hooks[i].property = XA_WM_HINTS;
01585   hooks[i].init_func = init_wm_hints;
01586   hooks[i].reload_func = reload_wm_hints;
01587   ++i;
01588   
01589   hooks[i].property = XA_WM_TRANSIENT_FOR;
01590   hooks[i].init_func = init_transient_for;
01591   hooks[i].reload_func = reload_transient_for;
01592   ++i;
01593 
01594   hooks[i].property = display->atom__NET_WM_USER_TIME_WINDOW;
01595   hooks[i].init_func = init_net_wm_user_time_window;
01596   hooks[i].reload_func = reload_net_wm_user_time_window;
01597   ++i;
01598 
01599   if (i != N_HOOKS)
01600     {
01601       g_error ("Initialized %d hooks should have been %d\n", i, N_HOOKS);
01602     }
01603 }
01604 
01605 void
01606 meta_display_free_window_prop_hooks (MetaDisplay *display)
01607 {
01608   g_assert (display->prop_hooks != NULL);
01609   
01610   g_free (display->prop_hooks);
01611   display->prop_hooks = NULL;
01612 }
01613 
01614 static MetaWindowPropHooks*
01615 find_hooks (MetaDisplay *display,
01616             Atom         property)
01617 {
01618   int i;
01619 
01620   /* FIXME we could sort the array and do binary search or
01621    * something
01622    */
01623   
01624   i = 0;
01625   while (i < N_HOOKS)
01626     {
01627       if (display->prop_hooks[i].property == property)
01628         return &display->prop_hooks[i];
01629       
01630       ++i;
01631     }
01632 
01633   return NULL;
01634 }

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