Exemple #1
0
/*
 * Flashes the frame of the focussed window. If there is no focussed window,
 * flashes the screen.
 *
 * \param display  The display the bell event came in on
 * \param xkb_ev   The bell event we just received
 */
static void
bell_flash_frame (MetaDisplay *display, 
		  XkbAnyEvent *xkb_ev)
{
  XkbBellNotifyEvent *xkb_bell_event = (XkbBellNotifyEvent *) xkb_ev;
  MetaWindow *window;
  
  g_assert (xkb_ev->xkb_type == XkbBellNotify);
  window = meta_display_lookup_x_window (display, xkb_bell_event->window);
  if (!window && (display->focus_window))
    {
      window = display->focus_window;
    }
  if (window && window->frame)
    {
      bell_flash_window_frame (window);
    }
  else /* revert to fullscreen flash if there's no focussed window */
    {
      bell_flash_fullscreen (display, xkb_ev);
    }
}
Exemple #2
0
void
meta_core_get (Display *xdisplay,
    Window xwindow,
    ...)
{
  va_list args;
  MetaCoreGetType request;

  MetaDisplay *display = meta_display_for_x_display (xdisplay);
  MetaWindow *window = meta_display_lookup_x_window (display, xwindow);

  va_start (args, xwindow);

  request = va_arg (args, MetaCoreGetType);

  /* Now, we special-case the first request slightly. Mostly, requests
   * for information on windows which have no frame are errors.
   * But sometimes we may want to know *whether* a window has a frame.
   * In this case, pass the key META_CORE_WINDOW_HAS_FRAME
   * as the *first* request, with a pointer to a boolean; if the window
   * has no frame, this will be set to False and meta_core_get will
   * exit immediately (so the values of any other requests will be
   * undefined). Otherwise it will be set to True and meta_core_get will
   * continue happily on its way.
   */

  if (request != META_CORE_WINDOW_HAS_FRAME &&
      (window == NULL || window->frame == NULL)) {
    meta_bug ("No such frame window 0x%lx!\n", xwindow);
    return;
  }

  while (request != META_CORE_GET_END) {
    
    gpointer answer = va_arg (args, gpointer);

    switch (request) {
      case META_CORE_WINDOW_HAS_FRAME:
        *((gboolean*)answer) = window != NULL && window->frame != NULL;
        if (!*((gboolean*)answer)) return; /* see above */
        break; 
      case META_CORE_GET_CLIENT_WIDTH:
        *((gint*)answer) = window->rect.width;
        break;
      case META_CORE_GET_CLIENT_HEIGHT:
        *((gint*)answer) = window->rect.height;
        break;
      case META_CORE_IS_TITLEBAR_ONSCREEN:
        *((gboolean*)answer) = meta_window_titlebar_is_onscreen (window);
        break;
      case META_CORE_GET_CLIENT_XWINDOW:
        *((Window*)answer) = window->xwindow;
        break;
      case META_CORE_GET_FRAME_FLAGS:
        *((MetaFrameFlags*)answer) = meta_frame_get_flags (window->frame);
        break; 
      case META_CORE_GET_FRAME_TYPE:
          {
          MetaFrameType base_type = META_FRAME_TYPE_LAST;

          switch (window->type)
            {
            case META_WINDOW_NORMAL:
              base_type = META_FRAME_TYPE_NORMAL;
              break;

            case META_WINDOW_DIALOG:
              base_type = META_FRAME_TYPE_DIALOG;
              break;

            case META_WINDOW_MODAL_DIALOG:
              base_type = META_FRAME_TYPE_MODAL_DIALOG;
              break;

            case META_WINDOW_MENU:
              base_type = META_FRAME_TYPE_MENU;
              break;

            case META_WINDOW_UTILITY:
              base_type = META_FRAME_TYPE_UTILITY;
              break;

            case META_WINDOW_DESKTOP:
            case META_WINDOW_DOCK:
            case META_WINDOW_TOOLBAR:
            case META_WINDOW_SPLASHSCREEN:
              /* No frame */
              base_type = META_FRAME_TYPE_LAST;
              break;

            }

          if (base_type == META_FRAME_TYPE_LAST)
            {
              /* can't add border if undecorated */
              *((MetaFrameType*)answer) = META_FRAME_TYPE_LAST; 
            }
          else if (window->border_only)
            {
              /* override base frame type */
              *((MetaFrameType*)answer) = META_FRAME_TYPE_BORDER; 
            }
          else
            {
              *((MetaFrameType*)answer) = base_type;
            }

          break; 
          }
      case META_CORE_GET_MINI_ICON:
        *((GdkPixbuf**)answer) = window->mini_icon;
        break;
      case META_CORE_GET_ICON:
        *((GdkPixbuf**)answer) = window->icon;
        break;
      case META_CORE_GET_X:
        meta_window_get_position (window, (int*)answer, NULL);
        break;
      case META_CORE_GET_Y:
        meta_window_get_position (window, NULL, (int*)answer);
        break;
      case META_CORE_GET_FRAME_WORKSPACE:
        *((gint*)answer) = meta_window_get_net_wm_desktop (window);
        break;
      case META_CORE_GET_FRAME_X:
        *((gint*)answer) = window->frame->rect.x;
        break;
      case META_CORE_GET_FRAME_Y:
        *((gint*)answer) = window->frame->rect.y;
        break;
      case META_CORE_GET_FRAME_WIDTH:
        *((gint*)answer) = window->frame->rect.width;
        break;
      case META_CORE_GET_FRAME_HEIGHT:
        *((gint*)answer) = window->frame->rect.height;
        break;
      case META_CORE_GET_SCREEN_WIDTH:
        *((gint*)answer) = window->screen->rect.width;
        break;
      case META_CORE_GET_SCREEN_HEIGHT:
        *((gint*)answer) = window->screen->rect.height;
        break;

      default:
        meta_warning(_("Unknown window information request: %d"), request);
    }

    request = va_arg (args, MetaCoreGetType);
  } 

  va_end (args);
}
Exemple #3
0
static void
create_constraints (Constraint **constraints,
                    GList       *windows)
{
  GList *tmp;
  
  tmp = windows;
  while (tmp != NULL)
    {
      MetaWindow *w = tmp->data;

      if (!WINDOW_IN_STACK (w))
        {
          meta_topic (META_DEBUG_STACK, "Window %s not in the stack, not constraining it\n",
                      w->desc);
          tmp = tmp->next;
          continue;
        }
      
      if (WINDOW_TRANSIENT_FOR_WHOLE_GROUP (w))
        {
          GSList *group_windows;
          GSList *tmp2;
          MetaGroup *group;

          group = meta_window_get_group (w);

          if (group != NULL)
            group_windows = meta_group_list_windows (group);
          else
            group_windows = NULL;
          
          tmp2 = group_windows;
          
          while (tmp2 != NULL)
            {
              MetaWindow *group_window = tmp2->data;

              if (!WINDOW_IN_STACK (group_window) ||
                  w->screen != group_window->screen ||
                  group_window->override_redirect)
                {
                  tmp2 = tmp2->next;
                  continue;
                }
              
#if 0
              /* old way of doing it */
              if (!(meta_window_is_ancestor_of_transient (w, group_window)) &&
                  !WINDOW_TRANSIENT_FOR_WHOLE_GROUP (group_window))  /* note */;/*note*/
#else
              /* better way I think, so transient-for-group are constrained
               * only above non-transient-type windows in their group
               */
              if (!WINDOW_HAS_TRANSIENT_TYPE (group_window))
#endif
                {
                  meta_topic (META_DEBUG_STACK, "Constraining %s above %s as it's transient for its group\n",
                              w->desc, group_window->desc);
                  add_constraint (constraints, w, group_window);
                }
              
              tmp2 = tmp2->next;
            }

          g_slist_free (group_windows);
        }
      else if (w->xtransient_for != None &&
               !w->transient_parent_is_root_window)
        {
          MetaWindow *parent;
          
          parent =
            meta_display_lookup_x_window (w->display, w->xtransient_for);

          if (parent && WINDOW_IN_STACK (parent) &&
              parent->screen == w->screen)
            {
              meta_topic (META_DEBUG_STACK, "Constraining %s above %s due to transiency\n",
                          w->desc, parent->desc);
              add_constraint (constraints, w, parent);
            }
        }
      
      tmp = tmp->next;
    }
}
Exemple #4
0
/*
 * Order the windows on the X server to be the same as in our structure.
 * We do this using XRestackWindows if we don't know the previous order,
 * or XConfigureWindow on a few particular windows if we do and can figure
 * out the minimum set of changes.  After that, we set __NET_CLIENT_LIST
 * and __NET_CLIENT_LIST_STACKING.
 *
 * FIXME: Now that we have a good view of the stacking order on the server
 * with MetaStackTracker it should be possible to do a simpler and better
 * job of computing the minimal set of stacking requests needed.
 */
static void
stack_sync_to_server (MetaStack *stack)
{
  GArray *stacked;
  GArray *root_children_stacked;
  GList *tmp;
  GArray *all_hidden;
  int n_override_redirect = 0;
  int n_unmanaging = 0;
  
  /* Bail out if frozen */
  if (stack->freeze_count > 0)
    return;
  
  meta_topic (META_DEBUG_STACK, "Syncing window stack to server\n");  

  stack_ensure_sorted (stack);

  /* Create stacked xwindow arrays.
   * Painfully, "stacked" is in bottom-to-top order for the
   * _NET hints, and "root_children_stacked" is in top-to-bottom
   * order for XRestackWindows()
   */
  stacked = g_array_new (FALSE, FALSE, sizeof (Window));
  root_children_stacked = g_array_new (FALSE, FALSE, sizeof (Window));
  all_hidden = g_array_new (FALSE, FALSE, sizeof (Window));

  /* The screen guard window sits above all hidden windows and acts as
   * a barrier to input reaching these windows. */
  g_array_append_val (all_hidden, stack->screen->guard_window);

  meta_topic (META_DEBUG_STACK, "Top to bottom: ");
  meta_push_no_msg_prefix ();

  for (tmp = stack->sorted; tmp != NULL; tmp = tmp->next)
    {
      MetaWindow *w = tmp->data;
      Window top_level_window;

      if (w->unmanaging)
        {
          n_unmanaging ++;
          continue;
        }
      
      meta_topic (META_DEBUG_STACK, "%u:%d - %s ",
		  w->layer, w->stack_position, w->desc);

      /* remember, stacked is in reverse order (bottom to top) */
      if (w->override_redirect)
	n_override_redirect++;
      else
	g_array_prepend_val (stacked, w->xwindow);
      
      if (w->frame)
	top_level_window = w->frame->xwindow;
      else
	top_level_window = w->xwindow;

      /* We don't restack hidden windows along with the rest, though they are
       * reflected in the _NET hints. Hidden windows all get pushed below
       * the screens fullscreen guard_window. */
      if (w->hidden)
	{
	  g_array_append_val (all_hidden, top_level_window);
	  continue;
	}

      /* build XRestackWindows() array from top to bottom */
      g_array_append_val (root_children_stacked, top_level_window);
    }

  meta_topic (META_DEBUG_STACK, "\n");
  meta_pop_no_msg_prefix ();

  /* All windows should be in some stacking order */
  if (stacked->len != stack->windows->len - n_override_redirect - n_unmanaging)
    meta_bug ("%u windows stacked, %u windows exist in stack\n",
              stacked->len, stack->windows->len);
  
  /* Sync to server */

  meta_topic (META_DEBUG_STACK, "Restacking %u windows\n",
              root_children_stacked->len);
  
  meta_error_trap_push (stack->screen->display);

  if (stack->last_root_children_stacked == NULL)
    {
      /* Just impose our stack, we don't know the previous state.
       * This involves a ton of circulate requests and may flicker.
       */
      meta_topic (META_DEBUG_STACK, "Don't know last stack state, restacking everything\n");

      if (root_children_stacked->len > 0)
        {
          meta_stack_tracker_record_restack_windows (stack->screen->stack_tracker,
                                                     (Window *) root_children_stacked->data,
                                                     root_children_stacked->len,
                                                     XNextRequest (stack->screen->display->xdisplay));
          XRestackWindows (stack->screen->display->xdisplay,
                           (Window *) root_children_stacked->data,
                           root_children_stacked->len);
        }
    }
  else if (root_children_stacked->len > 0)
    {
      /* Try to do minimal window moves to get the stack in order */
      /* A point of note: these arrays include frames not client windows,
       * so if a client window has changed frame since last_root_children_stacked
       * was saved, then we may have inefficiency, but I don't think things
       * break...
       */
      const Window *old_stack = (Window *) stack->last_root_children_stacked->data;
      const Window *new_stack = (Window *) root_children_stacked->data;
      const int old_len = stack->last_root_children_stacked->len;
      const int new_len = root_children_stacked->len;
      const Window *oldp = old_stack;
      const Window *newp = new_stack;
      const Window *old_end = old_stack + old_len;
      const Window *new_end = new_stack + new_len;
      Window last_window = None;
      
      while (oldp != old_end &&
             newp != new_end)
        {
          if (*oldp == *newp)
            {
              /* Stacks are the same here, move on */
              ++oldp;
              last_window = *newp;
              ++newp;
            }
          else if (meta_display_lookup_x_window (stack->screen->display,
                                                 *oldp) == NULL)
            {
              /* *oldp is no longer known to us (probably destroyed),
               * so we can just skip it
               */
              ++oldp;
            }
          else
            {
              /* Move *newp below last_window */
              if (last_window == None)
                {
                  meta_topic (META_DEBUG_STACK, "Using window 0x%lx as topmost (but leaving it in-place)\n", *newp);

                  raise_window_relative_to_managed_windows (stack->screen,
                                                            *newp);
                }
              else
                {
                  /* This means that if last_window is dead, but not
                   * *newp, then we fail to restack *newp; but on
                   * unmanaging last_window, we'll fix it up.
                   */
                  
                  XWindowChanges changes;

                  changes.sibling = last_window;
                  changes.stack_mode = Below;

                  meta_topic (META_DEBUG_STACK, "Placing window 0x%lx below 0x%lx\n",
                              *newp, last_window);

                  meta_stack_tracker_record_lower_below (stack->screen->stack_tracker,
                                                         *newp, last_window,
                                                         XNextRequest (stack->screen->display->xdisplay));
                  XConfigureWindow (stack->screen->display->xdisplay,
                                    *newp,
                                    CWSibling | CWStackMode,
                                    &changes);
                }

              last_window = *newp;
              ++newp;
            }
        }

      if (newp != new_end)
        {
          /* Restack remaining windows */
          meta_topic (META_DEBUG_STACK, "Restacking remaining %d windows\n",
                        (int) (new_end - newp));
          /* We need to include an already-stacked window
           * in the restack call, so we get in the proper position
           * with respect to it.
           */
          if (newp != new_stack)
            --newp;
          meta_stack_tracker_record_restack_windows (stack->screen->stack_tracker,
                                                     (Window *) newp, new_end - newp,
                                                     XNextRequest (stack->screen->display->xdisplay));
          XRestackWindows (stack->screen->display->xdisplay,
                           (Window *) newp, new_end - newp);
        }
    }

  /* Push hidden windows to the bottom of the stack under the guard window */
  meta_stack_tracker_record_lower (stack->screen->stack_tracker,
                                   stack->screen->guard_window,
                                   XNextRequest (stack->screen->display->xdisplay));
  XLowerWindow (stack->screen->display->xdisplay, stack->screen->guard_window);
  meta_stack_tracker_record_restack_windows (stack->screen->stack_tracker,
                                             (Window *)all_hidden->data,
                                             all_hidden->len,
                                             XNextRequest (stack->screen->display->xdisplay));
  XRestackWindows (stack->screen->display->xdisplay,
		   (Window *)all_hidden->data,
		   all_hidden->len);
  g_array_free (all_hidden, TRUE);

  meta_error_trap_pop (stack->screen->display);
  /* on error, a window was destroyed; it should eventually
   * get removed from the stacking list when we unmanage it
   * and we'll fix stacking at that time.
   */
  
  /* Sync _NET_CLIENT_LIST and _NET_CLIENT_LIST_STACKING */

  XChangeProperty (stack->screen->display->xdisplay,
                   stack->screen->xroot,
                   stack->screen->display->atom__NET_CLIENT_LIST,
                   XA_WINDOW,
                   32, PropModeReplace,
                   (unsigned char *)stack->windows->data,
                   stack->windows->len);
  XChangeProperty (stack->screen->display->xdisplay,
                   stack->screen->xroot,
                   stack->screen->display->atom__NET_CLIENT_LIST_STACKING,
                   XA_WINDOW,
                   32, PropModeReplace,
                   (unsigned char *)stacked->data,
                   stacked->len);

  g_array_free (stacked, TRUE);

  if (stack->last_root_children_stacked)
    g_array_free (stack->last_root_children_stacked, TRUE);
  stack->last_root_children_stacked = root_children_stacked;

  /* That was scary... */
}
Exemple #5
0
/*
 * This function is used to avoid raising a window above popup
 * menus and other such things.
 *
 * The key to the operation of this function is that we are expecting
 * at most one window to be added at a time. If xwindow is newly added,
 * then its own stack position will be too high (the frame window
 * is created at the top of the stack), but if we ignore xwindow,
 * then the *next* managed window in the stack will be a window that
 * we've already stacked.
 *
 * We could generalize this and remove the assumption that windows
 * are added one at a time by keeping an explicit ->stacked flag in
 * MetaWindow.
 *
 * An alternate approach would be to reverse the stacking algorithm to
 * work by placing each window above the others, and start by lowering
 * a window to the bottom (instead of the current way, which works by
 * placing each window below another and starting with a raise)
 */
static void
raise_window_relative_to_managed_windows (MetaScreen *screen,
                                          Window      xwindow)
{

  Window *children;
  int n_children;
  int i;

  meta_stack_tracker_get_stack (screen->stack_tracker,
                                &children, &n_children);

  /* Children are in order from bottom to top. We want to
   * find the topmost managed child, then configure
   * our window to be above it.
   */
  i = n_children - 1;
  while (i >= 0)
    {
      if (children[i] == xwindow)
        {
          /* Do nothing. This means we're already the topmost managed
           * window, but it DOES NOT mean we are already just above
           * the topmost managed window. This is important because if
           * an override redirect window is up, and we map a new
           * managed window, the new window is probably above the old
           * popup by default, and we want to push it below that
           * popup. So keep looking for a sibling managed window
           * to be moved below.
           */
        }
      else
        {
          MetaWindow *other = meta_display_lookup_x_window (screen->display,
                                                            children[i]);
          if (other != NULL && !other->override_redirect && !other->unmanaging)
            {
              XWindowChanges changes;

              /* children[i] is the topmost managed child */
              meta_topic (META_DEBUG_STACK,
                          "Moving 0x%lx above topmost managed child window 0x%lx\n",
                          xwindow, children[i]);

              changes.sibling = children[i];
              changes.stack_mode = Above;

              meta_error_trap_push (screen->display);
              meta_stack_tracker_record_raise_above (screen->stack_tracker,
                                                     xwindow,
                                                     children[i],
                                                     XNextRequest (screen->display->xdisplay));
              XConfigureWindow (screen->display->xdisplay,
                                xwindow,
                                CWSibling | CWStackMode,
                                &changes);
              meta_error_trap_pop (screen->display);

              break;
            }
        }

      --i;
    }

  if (i < 0)
    {
      /* No sibling to use, just lower ourselves to the bottom
       * to be sure we're below any override redirect windows.
       */
      meta_error_trap_push (screen->display);
      meta_stack_tracker_record_lower (screen->stack_tracker,
                                       xwindow,
                                       XNextRequest (screen->display->xdisplay));
      XLowerWindow (screen->display->xdisplay,
                    xwindow);
      meta_error_trap_pop (screen->display);
    }
}
static gboolean
validate_or_free_results (GetPropertyResults *results,
                          int                 expected_format,
                          Atom                expected_type,
                          gboolean            must_have_items)
{
  char *type_name;
  char *expected_name;
  char *prop_name;
  const char *title;
  const char *res_class;
  const char *res_name;
  MetaWindow *w;
  
  if (expected_format == results->format &&
      expected_type == results->type &&
      (!must_have_items || results->n_items > 0))
    return TRUE;  
  
  meta_error_trap_push (results->display);
  type_name = XGetAtomName (results->display->xdisplay, results->type);
  expected_name = XGetAtomName (results->display->xdisplay, expected_type);
  prop_name = XGetAtomName (results->display->xdisplay, results->xatom);
  meta_error_trap_pop (results->display, TRUE);

  w = meta_display_lookup_x_window (results->display, results->xwindow);

  if (w != NULL)
    {
      title = w->title;
      res_class = w->res_class;
      res_name = w->res_name;
    }
  else
    {
      title = NULL;
      res_class = NULL;
      res_name = NULL;
    }
  
  if (title == NULL)
    title = "unknown";

  if (res_class == NULL)
    res_class = "unknown";

  if (res_name == NULL)
    res_name = "unknown";
  
  meta_warning (_("Window 0x%lx has property %s\nthat was expected to have type %s format %d\nand actually has type %s format %d n_items %d.\nThis is most likely an application bug, not a window manager bug.\nThe window has title=\"%s\" class=\"%s\" name=\"%s\"\n"),
                results->xwindow,
                prop_name ? prop_name : "(bad atom)",
                expected_name ? expected_name : "(bad atom)",
                expected_format,
                type_name ? type_name : "(bad atom)",
                results->format, (int) results->n_items,
                title, res_class, res_name);

  if (type_name)
    XFree (type_name);
  if (expected_name)
    XFree (expected_name);
  if (prop_name)
    XFree (prop_name);

  if (results->prop)
    {
      XFree (results->prop);
      results->prop = NULL;
    }
  
  return FALSE;
}
Exemple #7
0
void
meta_core_get (Display *xdisplay,
    Window xwindow,
    ...)
{
  va_list args;
  MetaCoreGetType request;

  MetaDisplay *display = meta_display_for_x_display (xdisplay);
  MetaWindow *window = meta_display_lookup_x_window (display, xwindow);

  va_start (args, xwindow);

  request = va_arg (args, MetaCoreGetType);

  /* Now, we special-case the first request slightly. Mostly, requests
   * for information on windows which have no frame are errors.
   * But sometimes we may want to know *whether* a window has a frame.
   * In this case, pass the key META_CORE_WINDOW_HAS_FRAME
   * as the *first* request, with a pointer to a boolean; if the window
   * has no frame, this will be set to False and meta_core_get will
   * exit immediately (so the values of any other requests will be
   * undefined). Otherwise it will be set to True and meta_core_get will
   * continue happily on its way.
   */

  if (request != META_CORE_WINDOW_HAS_FRAME &&
      (window == NULL || window->frame == NULL)) {
    meta_bug ("No such frame window 0x%lx!\n", xwindow);
    return;
  }

  while (request != META_CORE_GET_END) {
    
    gpointer answer = va_arg (args, gpointer);

    switch (request) {
      case META_CORE_WINDOW_HAS_FRAME:
        *((gboolean*)answer) = window != NULL && window->frame != NULL;
        if (!*((gboolean*)answer)) return; /* see above */
        break; 
      case META_CORE_GET_CLIENT_WIDTH:
        *((gint*)answer) = window->rect.width;
        break;
      case META_CORE_GET_CLIENT_HEIGHT:
        *((gint*)answer) = window->rect.height;
        break;
      case META_CORE_GET_CLIENT_XWINDOW:
        *((Window*)answer) = window->xwindow;
        break;
      case META_CORE_GET_FRAME_FLAGS:
        *((MetaFrameFlags*)answer) = meta_frame_get_flags (window->frame);
        break; 
      case META_CORE_GET_FRAME_TYPE:
        *((MetaFrameType*)answer) = meta_window_get_frame_type (window);
        break;
      case META_CORE_GET_MINI_ICON:
        *((GdkPixbuf**)answer) = window->mini_icon;
        break;
      case META_CORE_GET_ICON:
        *((GdkPixbuf**)answer) = window->icon;
        break;
      case META_CORE_GET_X:
        meta_window_get_position (window, (int*)answer, NULL);
        break;
      case META_CORE_GET_Y:
        meta_window_get_position (window, NULL, (int*)answer);
        break;
      case META_CORE_GET_FRAME_WORKSPACE:
        *((gint*)answer) = meta_window_get_net_wm_desktop (window);
        break;
      case META_CORE_GET_FRAME_X:
        *((gint*)answer) = window->frame->rect.x;
        break;
      case META_CORE_GET_FRAME_Y:
        *((gint*)answer) = window->frame->rect.y;
        break;
      case META_CORE_GET_FRAME_WIDTH:
        *((gint*)answer) = window->frame->rect.width;
        break;
      case META_CORE_GET_FRAME_HEIGHT:
        *((gint*)answer) = window->frame->rect.height;
        break;
      case META_CORE_GET_THEME_VARIANT:
        *((char**)answer) = window->gtk_theme_variant;
        break;
      case META_CORE_GET_SCREEN_WIDTH:
        *((gint*)answer) = window->screen->rect.width;
        break;
      case META_CORE_GET_SCREEN_HEIGHT:
        *((gint*)answer) = window->screen->rect.height;
        break;

      default:
        meta_warning(_("Unknown window information request: %d"), request);
    }

    request = va_arg (args, MetaCoreGetType);
  } 

  va_end (args);
}
/**
 * This function is used to avoid raising a window above popup
 * menus and other such things.
 *
 * FIXME This is sort of an expensive function, should probably
 * do something to avoid it. One approach would be to reverse
 * the stacking algorithm to work by placing each window above
 * the others, and start by lowering a window to the bottom
 * (instead of the current way, which works by placing each
 * window below another and starting with a raise)
 */
static void
raise_window_relative_to_managed_windows (MetaScreen *screen,
                                          Window      xwindow)
{

  Window ignored1, ignored2;
  Window *children;
  unsigned int n_children;
  int i;

  /* Normally XQueryTree() means "must grab server" but here
   * we don't, since we know we won't manage any new windows
   * or restack any windows before using the XQueryTree results.
   */
  
  meta_error_trap_push_with_return (screen->display);
  
  XQueryTree (screen->display->xdisplay,
              screen->xroot,
              &ignored1, &ignored2, &children, &n_children);

  if (meta_error_trap_pop_with_return (screen->display, TRUE) != Success)
    {
      meta_topic (META_DEBUG_STACK,
                  "Error querying root children to raise window 0x%lx\n",
                  xwindow);
      return;
    }

  /* Children are in order from bottom to top. We want to
   * find the topmost managed child, then configure
   * our window to be above it.
   */
  i = n_children - 1;
  while (i >= 0)
    {
      if (children[i] == xwindow)
        {
          /* Do nothing. This means we're already the topmost managed
           * window, but it DOES NOT mean we are already just above
           * the topmost managed window. This is important because if
           * an override redirect window is up, and we map a new
           * managed window, the new window is probably above the old
           * popup by default, and we want to push it below that
           * popup. So keep looking for a sibling managed window
           * to be moved below.
           */
        }
      else if (meta_display_lookup_x_window (screen->display,
                                             children[i]) != NULL)
        {
          XWindowChanges changes;
          
          /* children[i] is the topmost managed child */
          meta_topic (META_DEBUG_STACK,
                      "Moving 0x%lx above topmost managed child window 0x%lx\n",
                      xwindow, children[i]);

          changes.sibling = children[i];
          changes.stack_mode = Above;

          meta_error_trap_push (screen->display);
          XConfigureWindow (screen->display->xdisplay,
                            xwindow,
                            CWSibling | CWStackMode,
                            &changes);
          meta_error_trap_pop (screen->display, FALSE);

          break;
        }

      --i;
    }

  if (i < 0)
    {
      /* No sibling to use, just lower ourselves to the bottom
       * to be sure we're below any override redirect windows.
       */
      meta_error_trap_push (screen->display);
      XLowerWindow (screen->display->xdisplay,
                    xwindow);
      meta_error_trap_pop (screen->display, FALSE);
    }
  
  if (children)
    XFree (children);
}
void
meta_window_place (MetaWindow        *window,
                   MetaFrameGeometry *fgeom,
                   int                x,
                   int                y,
                   int               *new_x,
                   int               *new_y)
{
  GList *windows;
  const MetaXineramaScreenInfo *xi;

  /* frame member variables should NEVER be used in here, only
   * MetaFrameGeometry. But remember fgeom == NULL
   * for undecorated windows. Also, this function should
   * NEVER have side effects other than computing the
   * placement coordinates.
   */
  
  meta_topic (META_DEBUG_PLACEMENT, "Placing window %s\n", window->desc);

  windows = NULL;
  
  switch (window->type)
    {
      /* Run placement algorithm on these. */
    case META_WINDOW_NORMAL:
    case META_WINDOW_DIALOG:
    case META_WINDOW_MODAL_DIALOG:
    case META_WINDOW_SPLASHSCREEN:
      break;
          
      /* Assume the app knows best how to place these, no placement
       * algorithm ever (other than "leave them as-is")
       */
    case META_WINDOW_DESKTOP:
    case META_WINDOW_DOCK:
    case META_WINDOW_TOOLBAR:
    case META_WINDOW_MENU:
    case META_WINDOW_UTILITY:
      goto done_no_constraints;
    }
  
  if (meta_prefs_get_disable_workarounds ())
    {
      switch (window->type)
        {
          /* Only accept USPosition on normal windows because the app is full
           * of shit claiming the user set -geometry for a dialog or dock
           */
        case META_WINDOW_NORMAL:
          if (window->size_hints.flags & USPosition)
            {
              /* don't constrain with placement algorithm */
              meta_topic (META_DEBUG_PLACEMENT,
                          "Honoring USPosition for %s instead of using placement algorithm\n", window->desc);

              goto done;
            }
          break;

          /* Ignore even USPosition on dialogs, splashscreen */
        case META_WINDOW_DIALOG:
        case META_WINDOW_MODAL_DIALOG:
        case META_WINDOW_SPLASHSCREEN:
          break;
          
          /* Assume the app knows best how to place these. */
        case META_WINDOW_DESKTOP:
        case META_WINDOW_DOCK:
        case META_WINDOW_TOOLBAR:
        case META_WINDOW_MENU:
        case META_WINDOW_UTILITY:
          if (window->size_hints.flags & PPosition)
            {
              meta_topic (META_DEBUG_PLACEMENT,
                          "Not placing non-normal non-dialog window with PPosition set\n");
              goto done_no_constraints;
            }
          break;
        }
    }
  else
    {
      /* workarounds enabled */
      
      if ((window->size_hints.flags & PPosition) ||
          (window->size_hints.flags & USPosition))
        {
          meta_topic (META_DEBUG_PLACEMENT,
                      "Not placing window with PPosition or USPosition set\n");
          avoid_being_obscured_as_second_modal_dialog (window, fgeom, &x, &y);
          goto done_no_constraints;
        }
    }
  
  if ((window->type == META_WINDOW_DIALOG ||
       window->type == META_WINDOW_MODAL_DIALOG) &&
      window->xtransient_for != None)
    {
      /* Center horizontally, at top of parent vertically */

      MetaWindow *parent;
          
      parent =
        meta_display_lookup_x_window (window->display,
                                      window->xtransient_for);

      if (parent)
        {
          int w;

          meta_window_get_position (parent, &x, &y);
          w = parent->rect.width;

          /* center of parent */
          x = x + w / 2;
          /* center of child over center of parent */
          x -= window->rect.width / 2;

          /* "visually" center window over parent, leaving twice as
           * much space below as on top.
           */
          y += (parent->rect.height - window->rect.height)/3;

          /* put top of child's frame, not top of child's client */
          if (fgeom)
            y += fgeom->top_height;

          meta_topic (META_DEBUG_PLACEMENT, "Centered window %s over transient parent\n",
                      window->desc);
          
          avoid_being_obscured_as_second_modal_dialog (window, fgeom, &x, &y);

          goto done;
        }
    }
  
  /* FIXME UTILITY with transient set should be stacked up
   * on the sides of the parent window or something.
   */
  
  if (window->type == META_WINDOW_DIALOG ||
      window->type == META_WINDOW_MODAL_DIALOG ||
      window->type == META_WINDOW_SPLASHSCREEN)
    {
      /* Center on current xinerama (i.e. on current monitor) */
      int w, h;

      /* Warning, this function is a round trip! */
      xi = meta_screen_get_current_xinerama (window->screen);

      w = xi->rect.width;
      h = xi->rect.height;

      x = (w - window->rect.width) / 2;
      y = (h - window->rect.height) / 2;

      x += xi->rect.x;
      y += xi->rect.y;
      
      meta_topic (META_DEBUG_PLACEMENT, "Centered window %s on screen %d xinerama %d\n",
                  window->desc, window->screen->number, xi->number);

      goto done_check_denied_focus;
    }
  
  /* Find windows that matter (not minimized, on same workspace
   * as placed window, may be shaded - if shaded we pretend it isn't
   * for placement purposes)
   */
  {
    GSList *all_windows;
    GSList *tmp;
    
    all_windows = meta_display_list_windows (window->display);

    tmp = all_windows;
    while (tmp != NULL)
      {
        MetaWindow *w = tmp->data;

        if (meta_window_showing_on_its_workspace (w) &&
            w != window && 
            (window->workspace == w->workspace ||
             window->on_all_workspaces || w->on_all_workspaces))
          windows = g_list_prepend (windows, w);

        tmp = tmp->next;
      }

    g_slist_free (all_windows);
  }

  /* Warning, this is a round trip! */
  xi = meta_screen_get_current_xinerama (window->screen);
  
  /* "Origin" placement algorithm */
  x = xi->rect.x;
  y = xi->rect.y;

  if (find_first_fit (window, fgeom, windows,
                      xi->number,
                      x, y, &x, &y))
    goto done_check_denied_focus;

  /* Maximize windows if they are too big for their work area (bit of
   * a hack here). Assume undecorated windows probably don't intend to
   * be maximized.  
   */
  if (window->has_maximize_func && window->decorated &&
      !window->fullscreen)
    {
      MetaRectangle workarea;
      MetaRectangle outer;

      meta_window_get_work_area_for_xinerama (window,
                                              xi->number,
                                              &workarea);      
      meta_window_get_outer_rect (window, &outer);
      
      /* If the window is bigger than the screen, then automaximize.  Do NOT
       * auto-maximize the directions independently.  See #419810.
       */
      if (outer.width >= workarea.width && outer.height >= workarea.height)
        {
          window->maximize_horizontally_after_placement = TRUE;
          window->maximize_vertically_after_placement = TRUE;
        }
    }

  /* If no placement has been done, revert to cascade to avoid 
   * fully overlapping window (e.g. starting multiple terminals)
   * */
  if (!meta_prefs_get_center_new_windows() && (x == xi->rect.x && y == xi->rect.y))
    find_next_cascade (window, fgeom, windows, x, y, &x, &y);

 done_check_denied_focus:
  /* If the window is being denied focus and isn't a transient of the
   * focus window, we do NOT want it to overlap with the focus window
   * if at all possible.  This is guaranteed to only be called if the
   * focus_window is non-NULL, and we try to avoid that window.
   */
  if (window->denied_focus_and_not_transient)
    {
      gboolean       found_fit;
      MetaWindow    *focus_window;
      MetaRectangle  overlap;

      focus_window = window->display->focus_window;
      g_assert (focus_window != NULL);

      /* No need to do anything if the window doesn't overlap at all */
      found_fit = !meta_rectangle_intersect (&window->rect,
                                             &focus_window->rect,
                                             &overlap);

      /* Try to do a first fit again, this time only taking into account the
       * focus window.
       */
      if (!meta_prefs_get_center_new_windows() && !found_fit)
        {
          GList *focus_window_list;
          focus_window_list = g_list_prepend (NULL, focus_window);

          /* Reset x and y ("origin" placement algorithm) */
          x = xi->rect.x;
          y = xi->rect.y;

          found_fit = find_first_fit (window, fgeom, focus_window_list,
                                      xi->number,
                                      x, y, &x, &y);
          g_list_free (focus_window_list);
	}

      /* If that still didn't work, just place it where we can see as much
       * as possible.
       */
      if (!found_fit)
        find_most_freespace (window, fgeom, focus_window, x, y, &x, &y);
    }
  
 done:
  g_list_free (windows);
  
 done_no_constraints:

  *new_x = x;
  *new_y = y;
}
Exemple #10
0
/**
 * meta_compositor_process_event: (skip)
 *
 */
gboolean
meta_compositor_process_event (MetaCompositor *compositor,
                               XEvent         *event,
                               MetaWindow     *window)
{
    if (compositor->modal_plugin && is_grabbed_event (event))
    {
        MetaPluginClass *klass = META_PLUGIN_GET_CLASS (compositor->modal_plugin);

        if (klass->xevent_filter)
            klass->xevent_filter (compositor->modal_plugin, event);

        /* We always consume events even if the plugin says it didn't handle them;
         * exclusive is exclusive */
        return TRUE;
    }

    if (window)
    {
        MetaCompScreen *info;
        MetaScreen     *screen;

        screen = meta_window_get_screen (window);
        info = meta_screen_get_compositor_data (screen);

        if (meta_plugin_manager_xevent_filter (info->plugin_mgr, event))
        {
            DEBUG_TRACE ("meta_compositor_process_event (filtered,window==NULL)\n");
            return TRUE;
        }
    }
    else
    {
        GSList *l;

        l = meta_display_get_screens (compositor->display);

        while (l)
        {
            MetaScreen     *screen = l->data;
            MetaCompScreen *info;

            info = meta_screen_get_compositor_data (screen);

            if (meta_plugin_manager_xevent_filter (info->plugin_mgr, event))
            {
                DEBUG_TRACE ("meta_compositor_process_event (filtered,window==NULL)\n");
                return TRUE;
            }

            l = l->next;
        }
    }

    switch (event->type)
    {
    case PropertyNotify:
        process_property_notify (compositor, (XPropertyEvent *) event, window);
        break;

    default:
        if (event->type == meta_display_get_damage_event_base (compositor->display) + XDamageNotify)
        {
            /* Core code doesn't handle damage events, so we need to extract the MetaWindow
             * ourselves
             */
            if (window == NULL)
            {
                Window xwin = ((XDamageNotifyEvent *) event)->drawable;
                window = meta_display_lookup_x_window (compositor->display, xwin);
            }

            DEBUG_TRACE ("meta_compositor_process_event (process_damage)\n");
            process_damage (compositor, (XDamageNotifyEvent *) event, window);
        }
        break;
    }

    /* Clutter needs to know about MapNotify events otherwise it will
       think the stage is invisible */
    if (event->type == MapNotify)
        clutter_x11_handle_event (event);

    /* The above handling is basically just "observing" the events, so we return
     * FALSE to indicate that the event should not be filtered out; if we have
     * GTK+ windows in the same process, GTK+ needs the ConfigureNotify event, for example.
     */
    return FALSE;
}