void
meta_workspace_activate_with_focus (MetaWorkspace *workspace,
                                    MetaWindow    *focus_this,
                                    guint32        timestamp)
{
  MetaWorkspace *old;
  MetaWindow *move_window;
  
  meta_verbose ("Activating workspace %d\n",
                meta_workspace_index (workspace));
  
  if (workspace->screen->active_workspace == workspace)
    return;

  if (workspace->screen->active_workspace)
    workspace_switch_sound(workspace->screen->active_workspace, workspace);

  /* Note that old can be NULL; e.g. when starting up */
  old = workspace->screen->active_workspace;
  
  workspace->screen->active_workspace = workspace;

  set_active_space_hint (workspace->screen);

  /* If the "show desktop" mode is active for either the old workspace
   * or the new one *but not both*, then update the
   * _net_showing_desktop hint
   */
  if (old && (old->showing_desktop ^ workspace->showing_desktop))
    meta_screen_update_showing_desktop_hint (workspace->screen);

  if (old == NULL)
    return;

  move_window = NULL;
  if (workspace->screen->display->grab_op == META_GRAB_OP_MOVING ||
      workspace->screen->display->grab_op == META_GRAB_OP_KEYBOARD_MOVING)
    move_window = workspace->screen->display->grab_window;
      
  if (move_window != NULL)
    {
      if (move_window->on_all_workspaces)
        move_window = NULL; /* don't move it after all */

      /* We put the window on the new workspace, flip spaces,
       * then remove from old workspace, so the window
       * never gets unmapped and we maintain the button grab
       * on it.
       *
       * \bug  This comment appears to be the reverse of what happens
       */
      if (move_window && (move_window->workspace != workspace))
        {
          meta_workspace_remove_window (old, move_window);
          meta_workspace_add_window (workspace, move_window);
        }
    }

  meta_workspace_queue_calc_showing (old);
  meta_workspace_queue_calc_showing (workspace);

  /* FIXME: Why do we need this?!?  Isn't it handled in the lines above? */
  if (move_window)
      /* Removes window from other spaces */
      meta_window_change_workspace (move_window, workspace);

  if (focus_this)
    {
      meta_window_focus (focus_this, timestamp);
      meta_window_raise (focus_this);
    }
  else if (move_window)
    {
      meta_window_raise (move_window);
    }
  else
    {
      meta_topic (META_DEBUG_FOCUS, "Focusing default window on new workspace\n");
      meta_workspace_focus_default_window (workspace, NULL, timestamp);
    }
}
Esempio n. 2
0
MetaWindowMenu*
meta_window_menu_new   (MetaFrames         *frames,
                        MetaMenuOp          ops,
                        MetaMenuOp          insensitive,
                        Window              client_xwindow,
                        unsigned long       active_workspace,
                        int                 n_workspaces,
                        MetaWindowMenuFunc  func,
                        gpointer            data)
{
  int i;
  MetaWindowMenu *menu;

  /* FIXME: Modifications to 'ops' should happen in meta_window_show_menu */
  if (n_workspaces < 2)
    ops &= ~(META_MENU_OP_STICK | META_MENU_OP_UNSTICK | META_MENU_OP_WORKSPACES);
  else if (n_workspaces == 2) 
    /* #151183: If we only have two workspaces, disable the menu listing them. */
    ops &= ~(META_MENU_OP_WORKSPACES);
  
  menu = g_new (MetaWindowMenu, 1);
  menu->frames = frames;
  menu->client_xwindow = client_xwindow;
  menu->func = func;
  menu->data = data;
  menu->ops = ops;
  menu->insensitive = insensitive;  
  
  menu->menu = gtk_menu_new ();

  gtk_menu_set_screen (GTK_MENU (menu->menu),
                       gtk_widget_get_screen (GTK_WIDGET (frames)));

  for (i = 0; i < (int) G_N_ELEMENTS (menuitems); i++)
    {
      MenuItem menuitem = menuitems[i];
      if (ops & menuitem.op || menuitem.op == 0)
        {
          GtkWidget *mi;
          MenuData *md;
          unsigned int key;
          MetaVirtualModifier mods;

          mi = menu_item_new (&menuitem, -1);

          /* Set the activeness of radiobuttons. */
          switch (menuitem.op)
            {
            case META_MENU_OP_STICK:
              gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (mi),
                                              active_workspace == 0xFFFFFFFF);
              break;
            case META_MENU_OP_UNSTICK:
              gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (mi),
                                              active_workspace != 0xFFFFFFFF);
              break;
            default:
              break;
            }

          if (menuitem.type == MENU_ITEM_WORKSPACE_LIST)
            {
              if (ops & META_MENU_OP_WORKSPACES)
                {
                  Display *display;
                  Window xroot;
                  GdkScreen *screen;
                  GdkWindow *window;
                  GtkWidget *submenu;
                  int j;

                  MenuItem to_another_workspace = {
                    0, MENU_ITEM_NORMAL, FALSE,
                    N_("Move to Another _Workspace")
                  };

                  meta_verbose ("Creating %d-workspace menu current space %lu\n",
                      n_workspaces, active_workspace);

                  window = gtk_widget_get_window (GTK_WIDGET (frames));
                  display = GDK_WINDOW_XDISPLAY (window);

                  screen = gdk_window_get_screen (window);
                  xroot = GDK_WINDOW_XID (gdk_screen_get_root_window (screen));

                  submenu = gtk_menu_new ();

                  g_assert (mi==NULL);
                  mi = menu_item_new (&to_another_workspace, -1);
                  gtk_menu_item_set_submenu (GTK_MENU_ITEM (mi), submenu);

                  for (j = 0; j < n_workspaces; j++)
                    {
                      char *label;
                      MenuData *md;
                      unsigned int key;
                      MetaVirtualModifier mods;
                      MenuItem moveitem;
                      GtkWidget *submi;

                      meta_core_get_menu_accelerator (META_MENU_OP_WORKSPACES,
                          j + 1,
                          &key, &mods);

                      label = get_workspace_name_with_accel (display, xroot, j);

                      moveitem.type = MENU_ITEM_NORMAL;
                      moveitem.op = META_MENU_OP_WORKSPACES;
                      moveitem.label = label;
                      submi = menu_item_new (&moveitem, j + 1);

                      g_free (label);

                      if ((active_workspace == (unsigned)j) && (ops & META_MENU_OP_UNSTICK))
                        gtk_widget_set_sensitive (submi, FALSE);

                      md = g_new (MenuData, 1);

                      md->menu = menu;
                      md->op = META_MENU_OP_WORKSPACES;

                      g_object_set_data (G_OBJECT (submi),
                          "workspace",
                          GINT_TO_POINTER (j));

                      g_signal_connect_data (G_OBJECT (submi),
                          "activate",
                          G_CALLBACK (activate_cb),
                          md,
                          (GClosureNotify) g_free, 0);

                      gtk_menu_shell_append (GTK_MENU_SHELL (submenu), submi);

                      gtk_widget_show (submi);
                    }
                  }
                else
                  meta_verbose ("not creating workspace menu\n");
            }
          else if (menuitem.type != MENU_ITEM_SEPARATOR)
            {
              meta_core_get_menu_accelerator (menuitems[i].op, -1,
                                              &key, &mods);

              if (insensitive & menuitem.op)
                gtk_widget_set_sensitive (mi, FALSE);
              
              md = g_new (MenuData, 1);
              
              md->menu = menu;
              md->op = menuitem.op;
              
              g_signal_connect_data (G_OBJECT (mi),
                                     "activate",
                                     G_CALLBACK (activate_cb),
                                     md,
                                     (GClosureNotify) g_free, 0);
            }

          if (mi)
            {
              gtk_menu_shell_append (GTK_MENU_SHELL (menu->menu), mi);
          
              gtk_widget_show (mi);
            }
        }
    }

 
  g_signal_connect (menu->menu, "selection_done",
                    G_CALLBACK (menu_closed), menu);  

  return menu;
}
Esempio n. 3
0
static gboolean
meta_display_handle_event (MetaDisplay        *display,
                           const ClutterEvent *event)
{
  MetaWindow *window;
  gboolean bypass_clutter = FALSE;
  G_GNUC_UNUSED gboolean bypass_wayland = FALSE;
  MetaGestureTracker *tracker;
  ClutterEventSequence *sequence;
  ClutterInputDevice *source;

  sequence = clutter_event_get_event_sequence (event);

  /* Set the pointer emulating sequence on touch begin, if eligible */
  if (event->type == CLUTTER_TOUCH_BEGIN)
    {
      if (sequence_is_pointer_emulated (display, event))
        {
          /* This is the new pointer emulating sequence */
          display->pointer_emulating_sequence = sequence;
        }
      else if (display->pointer_emulating_sequence == sequence)
        {
          /* This sequence was "pointer emulating" in a prior incarnation,
           * but now it isn't. We unset the pointer emulating sequence at
           * this point so the current sequence is not mistaken as pointer
           * emulating, while we've ensured that it's been deemed
           * "pointer emulating" throughout all of the event processing
           * of the previous incarnation.
           */
          display->pointer_emulating_sequence = NULL;
        }
    }

#ifdef HAVE_WAYLAND
  MetaWaylandCompositor *compositor = NULL;
  if (meta_is_wayland_compositor ())
    {
      compositor = meta_wayland_compositor_get_default ();
      meta_wayland_compositor_update (compositor, event);
    }
#endif

  if (!display->current_pad_osd &&
      (event->type == CLUTTER_PAD_BUTTON_PRESS ||
       event->type == CLUTTER_PAD_BUTTON_RELEASE))
    {
      MetaBackend *backend = meta_get_backend ();

      if (meta_input_settings_handle_pad_button (meta_backend_get_input_settings (backend),
                                                 clutter_event_get_source_device (event),
                                                 event->type == CLUTTER_PAD_BUTTON_PRESS,
                                                 event->pad_button.button))
        {
          bypass_wayland = bypass_clutter = TRUE;
          goto out;
        }
    }

  source = clutter_event_get_source_device (event);

  if (source)
    {
      meta_backend_update_last_device (meta_get_backend (),
                                       clutter_input_device_get_device_id (source));
    }

#ifdef HAVE_WAYLAND
  if (meta_is_wayland_compositor () && event->type == CLUTTER_MOTION)
    {
      MetaWaylandCompositor *compositor;

      compositor = meta_wayland_compositor_get_default ();

      if (meta_wayland_tablet_manager_consumes_event (compositor->tablet_manager, event))
        {
          meta_wayland_tablet_manager_update_cursor_position (compositor->tablet_manager, event);
        }
      else
        {
          MetaCursorTracker *tracker = meta_cursor_tracker_get_for_screen (NULL);
          meta_cursor_tracker_update_position (tracker, event->motion.x, event->motion.y);
        }

      display->monitor_cache_invalidated = TRUE;
    }
#endif

  handle_idletime_for_event (event);

  window = get_window_for_event (display, event);

  display->current_time = event->any.time;

  if (window && !window->override_redirect &&
      (event->type == CLUTTER_KEY_PRESS ||
       event->type == CLUTTER_BUTTON_PRESS ||
       event->type == CLUTTER_TOUCH_BEGIN))
    {
      if (CurrentTime == display->current_time)
        {
          /* We can't use missing (i.e. invalid) timestamps to set user time,
           * nor do we want to use them to sanity check other timestamps.
           * See bug 313490 for more details.
           */
          meta_warning ("Event has no timestamp! You may be using a broken "
                        "program such as xse.  Please ask the authors of that "
                        "program to fix it.\n");
        }
      else
        {
          meta_window_set_user_time (window, display->current_time);
          meta_display_sanity_check_timestamps (display, display->current_time);
        }
    }

  tracker = meta_display_get_gesture_tracker (display);

  if (meta_gesture_tracker_handle_event (tracker, event))
    {
      bypass_wayland = bypass_clutter = TRUE;
      goto out;
    }

  if (display->event_route == META_EVENT_ROUTE_WINDOW_OP)
    {
      if (meta_window_handle_mouse_grab_op_event (window, event))
        {
          bypass_clutter = TRUE;
          bypass_wayland = TRUE;
          goto out;
        }
    }

  /* For key events, it's important to enforce single-handling, or
   * we can get into a confused state. So if a keybinding is
   * handled (because it's one of our hot-keys, or because we are
   * in a keyboard-grabbed mode like moving a window, we don't
   * want to pass the key event to the compositor or Wayland at all.
   */
  if (meta_keybindings_process_event (display, window, event))
    {
      bypass_clutter = TRUE;
      bypass_wayland = TRUE;
      goto out;
    }

  /* Do not pass keyboard events to Wayland if key focus is not on the
   * stage in normal mode (e.g. during keynav in the panel)
   */
  if (display->event_route == META_EVENT_ROUTE_NORMAL)
    {
      if (IS_KEY_EVENT (event) && !stage_has_key_focus ())
        {
          bypass_wayland = TRUE;
          goto out;
        }
    }

  if (display->current_pad_osd)
    {
      bypass_wayland = TRUE;
      goto out;
    }

  if (window)
    {
      /* Events that are likely to trigger compositor gestures should
       * be known to clutter so they can propagate along the hierarchy.
       * Gesture-wise, there's two groups of events we should be getting
       * here:
       * - CLUTTER_TOUCH_* with a touch sequence that's not yet accepted
       *   by the gesture tracker, these might trigger gesture actions
       *   into recognition. Already accepted touch sequences are handled
       *   directly by meta_gesture_tracker_handle_event().
       * - CLUTTER_TOUCHPAD_* events over windows. These can likewise
       *   trigger ::captured-event handlers along the way.
       */
      bypass_clutter = !IS_GESTURE_EVENT (event);

      meta_window_handle_ungrabbed_event (window, event);

      /* This might start a grab op. If it does, then filter out the
       * event, and if it doesn't, replay the event to release our
       * own sync grab. */

      if (display->event_route == META_EVENT_ROUTE_WINDOW_OP ||
          display->event_route == META_EVENT_ROUTE_FRAME_BUTTON)
        {
          bypass_clutter = TRUE;
          bypass_wayland = TRUE;
        }
      else
        {
          /* Only replay button press events, since that's where we
           * have the synchronous grab. */
          if (event->type == CLUTTER_BUTTON_PRESS)
            {
              MetaBackend *backend = meta_get_backend ();
              if (META_IS_BACKEND_X11 (backend))
                {
                  Display *xdisplay = meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend));
                  meta_verbose ("Allowing events time %u\n",
                                (unsigned int)event->button.time);
                  XIAllowEvents (xdisplay, clutter_event_get_device_id (event),
                                 XIReplayDevice, event->button.time);
                }
            }
        }

      goto out;
    }

 out:
  /* If the compositor has a grab, don't pass that through to Wayland */
  if (display->event_route == META_EVENT_ROUTE_COMPOSITOR_GRAB)
    bypass_wayland = TRUE;

  /* If a Wayland client has a grab, don't pass that through to Clutter */
  if (display->event_route == META_EVENT_ROUTE_WAYLAND_POPUP)
    bypass_clutter = TRUE;

#ifdef HAVE_WAYLAND
  if (compositor && !bypass_wayland)
    {
      if (meta_wayland_compositor_handle_event (compositor, event))
        bypass_clutter = TRUE;
    }
#endif

  display->current_time = CurrentTime;
  return bypass_clutter;
}
static gboolean on_idle_end_grab(guint timestamp)
{
    meta_verbose ("%s\n", __func__);
    meta_display_end_grab_op(meta_get_display(), timestamp);
    return G_SOURCE_REMOVE;
}
//TODO: response to screen-changed?
void deepin_workspace_overview_populate(DeepinWorkspaceOverview* self,
        MetaWorkspace* ws)
{
    DeepinWorkspaceOverviewPrivate* priv = self->priv;
    priv->workspace = ws;

    GdkScreen* screen = gdk_screen_get_default();
    priv->primary = gdk_screen_get_primary_monitor(screen);
    gint n_monitors = gdk_screen_get_n_monitors(screen);
    priv->monitors = g_ptr_array_new_full(n_monitors, monitor_data_destroy);
    for (int i = 0; i < n_monitors; i++) {
        MonitorData* md = monitor_data_new();
        g_ptr_array_add(priv->monitors, md);
        md->monitor = i;
        md->clones = g_ptr_array_new();
        gdk_screen_get_monitor_geometry(screen, i, (GdkRectangle*)&md->mon_rect);

        /**
         * gdk_screen_get_monitor_workarea fails to honor struts, so I have to use xinerama
         * to get correct workarea
         */

        const MetaXineramaScreenInfo* xinerama = meta_screen_get_xinerama_for_rect(ws->screen, &md->mon_rect);
        meta_workspace_get_work_area_for_xinerama(ws, xinerama->number, (GdkRectangle*)&md->mon_workarea);
    }

    GList* ls = meta_stack_list_windows(ws->screen->stack,
            priv->all_window_mode? NULL: ws);
    GList* l = ls;
    while (l) {
        MetaWindow* win = (MetaWindow*)l->data;
        if (win->type == META_WINDOW_NORMAL) {
            if (priv->present_xids && g_hash_table_size(priv->present_xids)) {
                if (g_hash_table_contains(priv->present_xids, GINT_TO_POINTER(win->xwindow))) {
                    _clone_window(self, win);
                }
            } else {
                _clone_window(self, win);
            }
        }

        l = l->next;
    }
    g_list_free(ls);

    {
        priv->close_button = gtk_event_box_new();
        gtk_event_box_set_above_child(GTK_EVENT_BOX(priv->close_button), FALSE);
        gtk_event_box_set_visible_window(GTK_EVENT_BOX(priv->close_button), FALSE);

        GtkWidget* image = gtk_image_new_from_file(METACITY_PKGDATADIR "/close.png");
        gtk_container_add(GTK_CONTAINER(priv->close_button), image);

        deepin_fixed_put(DEEPIN_FIXED(self), priv->close_button, 0, 0);
        gtk_widget_set_opacity(self->priv->close_button, 0.0);

        g_object_connect(G_OBJECT(priv->close_button), 
                "signal::leave-notify-event", on_close_button_leaved, self,
                "signal::button-release-event", on_close_button_clicked, self,
                NULL);
    }


    priv->dock_height = 0;
    MetaWindow *desktop_win = NULL, *dock_win = NULL;

    GList* windows = priv->workspace->mru_list;
    while (windows != NULL) {
        MetaWindow *w = (MetaWindow*)windows->data;
        if (w->type == META_WINDOW_DESKTOP) {
            desktop_win = w;
        }

        if (w->type == META_WINDOW_DOCK) {
            dock_win = w;
        }

        if (desktop_win && dock_win) break;
        windows = windows->next;
    }

    for (int i = 0; i < n_monitors; i++) {
        MonitorData* md = (MonitorData*)g_ptr_array_index(priv->monitors, i);
        if (i == priv->primary) {
            MetaRectangle r1 = {0, 0, 0, 0}, r2 = {0, 0, 0, 0};
            cairo_surface_t* aux1 = NULL, *aux2 = NULL;

            if (desktop_win) {
                meta_window_get_outer_rect(desktop_win, &r1);
                aux1 = deepin_window_surface_manager_get_surface(desktop_win, 1.0); 
                r1.x -= md->mon_rect.x;
                r1.y -= md->mon_rect.y;
                meta_verbose ("%s: desktop offset(%d, %d)\n", __func__, r1.x, r1.y);
            }

            if (dock_win) {
                meta_window_get_outer_rect(dock_win, &r2);
                aux2 = deepin_window_surface_manager_get_surface(dock_win, 1.0); 
                priv->dock_height = r2.height;
                r2.x -= md->mon_rect.x;
                r2.y -= md->mon_rect.y;
                meta_verbose ("%s: dock offset(%d, %d)\n", __func__, r2.x, r2.y);
            }
            md->desktop_surface = deepin_window_surface_manager_get_combined3(
                    deepin_background_cache_get_surface(md->monitor, 1.0), 
                    aux1, r1.x, r1.y,
                    aux2, r2.x, r2.y,
                    1.0);
        } else {
            md->desktop_surface = deepin_background_cache_get_surface(md->monitor, 1.0);
            cairo_surface_reference(md->desktop_surface);
        }
    }

    gtk_widget_queue_resize(GTK_WIDGET(self));
}
Esempio n. 6
0
void
meta_window_ensure_frame (MetaWindow *window)
{
  MetaFrame *frame;
  XSetWindowAttributes attrs;
  gulong create_serial;

  if (window->frame)
    return;

  frame = g_new (MetaFrame, 1);

  frame->window = window;
  frame->xwindow = None;

  frame->rect = window->rect;
  frame->child_x = 0;
  frame->child_y = 0;
  frame->bottom_height = 0;
  frame->right_width = 0;
  frame->current_cursor = 0;

  frame->is_flashing = FALSE;
  frame->borders_cached = FALSE;

  meta_verbose ("Frame geometry %d,%d  %dx%d\n",
                frame->rect.x, frame->rect.y,
                frame->rect.width, frame->rect.height);

  frame->ui_frame = meta_ui_create_frame (window->screen->ui,
                                          window->display->xdisplay,
                                          frame->window,
                                          window->xvisual,
                                          frame->rect.x,
                                          frame->rect.y,
                                          frame->rect.width,
                                          frame->rect.height,
                                          &create_serial);
  frame->xwindow = frame->ui_frame->xwindow;

  meta_stack_tracker_record_add (window->screen->stack_tracker,
                                 frame->xwindow,
                                 create_serial);

  meta_verbose ("Frame for %s is 0x%lx\n", frame->window->desc, frame->xwindow);
  attrs.event_mask = EVENT_MASK;
  XChangeWindowAttributes (window->display->xdisplay,
			   frame->xwindow, CWEventMask, &attrs);

  meta_display_register_x_window (window->display, &frame->xwindow, window);

  meta_error_trap_push (window->display);
  if (window->mapped)
    {
      window->mapped = FALSE; /* the reparent will unmap the window,
                               * we don't want to take that as a withdraw
                               */
      meta_topic (META_DEBUG_WINDOW_STATE,
                  "Incrementing unmaps_pending on %s for reparent\n", window->desc);
      window->unmaps_pending += 1;
    }

  meta_stack_tracker_record_remove (window->screen->stack_tracker,
                                    window->xwindow,
                                    XNextRequest (window->display->xdisplay));
  XReparentWindow (window->display->xdisplay,
                   window->xwindow,
                   frame->xwindow,
                   frame->child_x,
                   frame->child_y);
  /* FIXME handle this error */
  meta_error_trap_pop (window->display);

  /* stick frame to the window */
  window->frame = frame;

  /* Now that frame->xwindow is registered with window, we can set its
   * style and background.
   */
  meta_frame_update_style (frame);
  meta_frame_update_title (frame);

  meta_ui_map_frame (frame->window->screen->ui, frame->xwindow);

  {
    MetaBackend *backend = meta_get_backend ();
    if (META_IS_BACKEND_X11 (backend))
      {
        Display *xdisplay = meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend));

        /* Since the backend selects for events on another connection,
         * make sure to sync the GTK+ connection to ensure that the
         * frame window has been created on the server at this point. */
        XSync (window->display->xdisplay, False);

        unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 };
        XIEventMask mask = { XIAllMasterDevices, sizeof (mask_bits), mask_bits };

        XISelectEvents (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
                        frame->xwindow, &mask, 1);

        XISetMask (mask.mask, XI_ButtonPress);
        XISetMask (mask.mask, XI_ButtonRelease);
        XISetMask (mask.mask, XI_Motion);
        XISetMask (mask.mask, XI_Enter);
        XISetMask (mask.mask, XI_Leave);

        XISelectEvents (xdisplay, frame->xwindow, &mask, 1);
      }
  }

  /* Move keybindings to frame instead of window */
  meta_window_grab_keys (window);
}
Esempio n. 7
0
void
meta_window_ensure_frame (MetaWindow *window)
{
  MetaFrame *frame;
  XSetWindowAttributes attrs;
  Visual *visual;

  if (window->frame)
    return;

  /* See comment below for why this is required. */
  meta_display_grab (window->display);

  frame = g_new (MetaFrame, 1);

  frame->window = window;
  frame->xwindow = None;

  frame->rect = window->rect;
  frame->child_x = 0;
  frame->child_y = 0;
  frame->bottom_height = 0;
  frame->right_width = 0;
  frame->current_cursor = 0;

  frame->mapped = FALSE;
  frame->need_reapply_frame_shape = TRUE;
  frame->is_flashing = FALSE;

  meta_verbose ("Framing window %s: visual %s default, depth %d default depth %d\n",
                window->desc,
                XVisualIDFromVisual (window->xvisual) ==
                XVisualIDFromVisual (window->screen->default_xvisual) ?
                "is" : "is not",
                window->depth, window->screen->default_depth);
  meta_verbose ("Frame geometry %d,%d  %dx%d\n",
                frame->rect.x, frame->rect.y,
                frame->rect.width, frame->rect.height);

  /* Default depth/visual handles clients with weird visuals; they can
   * always be children of the root depth/visual obviously, but
   * e.g. DRI games can't be children of a parent that has the same
   * visual as the client. NULL means default visual.
   *
   * We look for an ARGB visual if we can find one, otherwise use
   * the default of NULL.
   */

  /* Special case for depth 32 windows (assumed to be ARGB),
   * we use the window's visual. Otherwise we just use the system visual.
   */
  if (window->depth == 32)
    visual = window->xvisual;
  else
    visual = NULL;

  frame->xwindow = meta_ui_create_frame_window (window->screen->ui,
                                                window->display->xdisplay,
                                                visual,
                                                frame->rect.x,
                                                frame->rect.y,
						frame->rect.width,
						frame->rect.height,
						frame->window->screen->number);

  meta_verbose ("Frame for %s is 0x%lx\n", frame->window->desc, frame->xwindow);
  attrs.event_mask = EVENT_MASK;
  XChangeWindowAttributes (window->display->xdisplay,
			   frame->xwindow, CWEventMask, &attrs);

  meta_display_register_x_window (window->display, &frame->xwindow, window);

  /* Now that frame->xwindow is registered with window, we can set its
   * background.
   */
  meta_ui_reset_frame_bg (window->screen->ui, frame->xwindow);

  /* Reparent the client window; it may be destroyed,
   * thus the error trap. We'll get a destroy notify later
   * and free everything. Comment in FVWM source code says
   * we need a server grab or the child can get its MapNotify
   * before we've finished reparenting and getting the decoration
   * window onscreen, so ensure_frame must be called with
   * a grab.
   */
  meta_error_trap_push (window->display);
  if (window->mapped)
    {
      window->mapped = FALSE; /* the reparent will unmap the window,
                               * we don't want to take that as a withdraw
                               */
      meta_topic (META_DEBUG_WINDOW_STATE,
                  "Incrementing unmaps_pending on %s for reparent\n", window->desc);
      window->unmaps_pending += 1;
    }
  /* window was reparented to this position */
  window->rect.x = 0;
  window->rect.y = 0;

  XReparentWindow (window->display->xdisplay,
                   window->xwindow,
                   frame->xwindow,
                   window->rect.x,
                   window->rect.y);
  /* FIXME handle this error */
  meta_error_trap_pop (window->display, FALSE);

  /* stick frame to the window */
  window->frame = frame;

  if (window->title)
    meta_ui_set_frame_title (window->screen->ui,
                             window->frame->xwindow,
                             window->title);

  /* Move keybindings to frame instead of window */
  meta_window_grab_keys (window);

  /* Shape mask */
  meta_ui_apply_frame_shape (frame->window->screen->ui,
                             frame->xwindow,
                             frame->rect.width,
                             frame->rect.height,
                             frame->window->has_shape);
  frame->need_reapply_frame_shape = FALSE;

  meta_display_ungrab (window->display);
}
void
meta_prop_get_values (MetaDisplay   *display,
                      Window         xwindow,
                      MetaPropValue *values,
                      int            n_values)
{
  int i;
  AgGetPropertyTask **tasks;

  meta_verbose ("Requesting %d properties of 0x%lx at once\n",
                n_values, xwindow);
  
  if (n_values == 0)
    return;
  
  tasks = g_new0 (AgGetPropertyTask*, n_values);

  /* Start up tasks. The "values" array can have values
   * with atom == None, which means to ignore that element.
   */
  i = 0;
  while (i < n_values)
    {
      if (values[i].required_type == None)
        {
          switch (values[i].type)
            {
            case META_PROP_VALUE_INVALID:
              /* This means we don't really want a value, e.g. got
               * property notify on an atom we don't care about.
               */
              if (values[i].atom != None)
                meta_bug ("META_PROP_VALUE_INVALID requested in %s\n", G_STRFUNC);
              break;
            case META_PROP_VALUE_UTF8_LIST:
            case META_PROP_VALUE_UTF8:
              values[i].required_type = display->atom_UTF8_STRING;
              break;
            case META_PROP_VALUE_STRING:
            case META_PROP_VALUE_STRING_AS_UTF8:
              values[i].required_type = XA_STRING;
              break;
            case META_PROP_VALUE_MOTIF_HINTS:
              values[i].required_type = AnyPropertyType;
              break;
            case META_PROP_VALUE_CARDINAL_LIST:
            case META_PROP_VALUE_CARDINAL:
              values[i].required_type = XA_CARDINAL;
              break;
            case META_PROP_VALUE_WINDOW:
              values[i].required_type = XA_WINDOW;
              break;
            case META_PROP_VALUE_ATOM_LIST:
              values[i].required_type = XA_ATOM;
              break;
            case META_PROP_VALUE_TEXT_PROPERTY:
              values[i].required_type = AnyPropertyType;
              break;
            case META_PROP_VALUE_WM_HINTS:
              values[i].required_type = XA_WM_HINTS;
              break;
            case META_PROP_VALUE_CLASS_HINT:
              values[i].required_type = XA_STRING;
              break;
            case META_PROP_VALUE_SIZE_HINTS:
              values[i].required_type = XA_WM_SIZE_HINTS;
              break;
            case META_PROP_VALUE_SYNC_COUNTER:
	      values[i].required_type = XA_CARDINAL;
              break;
            }
        }

      if (values[i].atom != None)
        tasks[i] = get_task (display, xwindow,
                             values[i].atom, values[i].required_type);
      
      ++i;
    }  
  
  /* Get replies for all our tasks */
  meta_topic (META_DEBUG_SYNC, "Syncing to get %d GetProperty replies in %s\n",
              n_values, G_STRFUNC);
  XSync (display->xdisplay, False);
  
  /* Collect results, should arrive in order requested */
  i = 0;
  while (i < n_values)
    {
      AgGetPropertyTask *task;
      GetPropertyResults results;
      
      if (tasks[i] == NULL)
        {
          /* Probably values[i].type was None, or ag_task_create()
           * returned NULL.
           */
          values[i].type = META_PROP_VALUE_INVALID;
          goto next;
        }
      
      task = ag_get_next_completed_task (display->xdisplay);
      g_assert (task != NULL);
      g_assert (ag_task_have_reply (task));

      results.display = display;
      results.xwindow = xwindow;
      results.xatom = values[i].atom;
      results.prop = NULL;
      results.n_items = 0;
      results.type = None;
      results.bytes_after = 0;
      results.format = 0;
      
      if (ag_task_get_reply_and_free (task,
                                      &results.type, &results.format,
                                      &results.n_items,
                                      &results.bytes_after,
                                      &results.prop) != Success ||
          results.type == None)
        {
          values[i].type = META_PROP_VALUE_INVALID;
          if (results.prop)
            {
              XFree (results.prop);
              results.prop = NULL;
            }
          goto next;
        }

      switch (values[i].type)
        {
        case META_PROP_VALUE_INVALID:
          g_assert_not_reached ();
          break;
        case META_PROP_VALUE_UTF8_LIST:
          if (!utf8_list_from_results (&results,
                                       &values[i].v.string_list.strings,
                                       &values[i].v.string_list.n_strings))
            values[i].type = META_PROP_VALUE_INVALID;
          break;
        case META_PROP_VALUE_UTF8:
          if (!utf8_string_from_results (&results,
                                         &values[i].v.str))
            values[i].type = META_PROP_VALUE_INVALID;
          break;
        case META_PROP_VALUE_STRING:
          if (!latin1_string_from_results (&results,
                                           &values[i].v.str))
            values[i].type = META_PROP_VALUE_INVALID;
          break;
        case META_PROP_VALUE_STRING_AS_UTF8:
          if (!latin1_string_from_results (&results,
                                           &values[i].v.str))
            values[i].type = META_PROP_VALUE_INVALID;
          else
            {
              char *new_str;
              char *xmalloc_new_str;

              new_str = latin1_to_utf8 (values[i].v.str);
              xmalloc_new_str = ag_Xmalloc (strlen (new_str) + 1);
              if (xmalloc_new_str != NULL)
                {
                  strcpy (xmalloc_new_str, new_str);
                  meta_XFree (values[i].v.str);
                  values[i].v.str = xmalloc_new_str;
                }

              g_free (new_str);
            }
          break;
        case META_PROP_VALUE_MOTIF_HINTS:
          if (!motif_hints_from_results (&results,
                                         &values[i].v.motif_hints))
            values[i].type = META_PROP_VALUE_INVALID;
          break;
        case META_PROP_VALUE_CARDINAL_LIST:
          if (!cardinal_list_from_results (&results,
                                           &values[i].v.cardinal_list.cardinals,
                                           &values[i].v.cardinal_list.n_cardinals))
            values[i].type = META_PROP_VALUE_INVALID;
          break;
        case META_PROP_VALUE_CARDINAL:
          if (!cardinal_with_atom_type_from_results (&results,
                                                     values[i].required_type,
                                                     &values[i].v.cardinal))
            values[i].type = META_PROP_VALUE_INVALID;
          break;
        case META_PROP_VALUE_WINDOW:
          if (!window_from_results (&results,
                                    &values[i].v.xwindow))
            values[i].type = META_PROP_VALUE_INVALID;
          break;
        case META_PROP_VALUE_ATOM_LIST:
          if (!atom_list_from_results (&results,
                                       &values[i].v.atom_list.atoms,
                                       &values[i].v.atom_list.n_atoms))
            values[i].type = META_PROP_VALUE_INVALID;
          break;
        case META_PROP_VALUE_TEXT_PROPERTY:
          if (!text_property_from_results (&results, &values[i].v.str))
            values[i].type = META_PROP_VALUE_INVALID;
          break;
        case META_PROP_VALUE_WM_HINTS:
          if (!wm_hints_from_results (&results, &values[i].v.wm_hints))
            values[i].type = META_PROP_VALUE_INVALID;
          break;
        case META_PROP_VALUE_CLASS_HINT:
          if (!class_hint_from_results (&results, &values[i].v.class_hint))
            values[i].type = META_PROP_VALUE_INVALID;
          break;
        case META_PROP_VALUE_SIZE_HINTS:
          if (!size_hints_from_results (&results,
                                        &values[i].v.size_hints.hints,
                                        &values[i].v.size_hints.flags))
            values[i].type = META_PROP_VALUE_INVALID;
          break;
        case META_PROP_VALUE_SYNC_COUNTER:
#ifdef HAVE_XSYNC
          if (!counter_from_results (&results,
                                     &values[i].v.xcounter))
            values[i].type = META_PROP_VALUE_INVALID;
#else
          values[i].type = META_PROP_VALUE_INVALID;
          if (results.prop)
            {
              XFree (results.prop);
              results.prop = NULL;
            }
#endif
          break;
        }

    next:
      ++i;
    }

  g_free (tasks);
}
Esempio n. 9
0
void
meta_window_destroy_frame (MetaWindow *window)
{
  MetaFrame *frame;
  MetaFrameBorders borders;

  if (window->frame == NULL)
    return;

  meta_verbose ("Unframing window %s\n", window->desc);

  frame = window->frame;

  meta_frame_calc_borders (frame, &borders);

  meta_bell_notify_frame_destroy (frame);

  /* Unparent the client window; it may be destroyed,
   * thus the error trap.
   */
  meta_error_trap_push (window->display);
  if (window->mapped)
    {
      window->mapped = FALSE; /* Keep track of unmapping it, so we
                               * can identify a withdraw initiated
                               * by the client.
                               */
      meta_topic (META_DEBUG_WINDOW_STATE,
                  "Incrementing unmaps_pending on %s for reparent back to root\n", window->desc);
      window->unmaps_pending += 1;
    }
  meta_stack_tracker_record_add (window->screen->stack_tracker,
                                 window->xwindow,
                                 XNextRequest (window->display->xdisplay));
  XReparentWindow (window->display->xdisplay,
                   window->xwindow,
                   window->screen->xroot,
                   /* Using anything other than client root window coordinates
                    * coordinates here means we'll need to ensure a configure
                    * notify event is sent; see bug 399552.
                    */
                   window->frame->rect.x + borders.invisible.left,
                   window->frame->rect.y + borders.invisible.top);
  meta_error_trap_pop (window->display);

  meta_ui_frame_unmanage (frame->ui_frame);

  meta_display_unregister_x_window (window->display,
                                    frame->xwindow);

  window->frame = NULL;
  if (window->frame_bounds)
    {
      cairo_region_destroy (window->frame_bounds);
      window->frame_bounds = NULL;
    }

  /* Move keybindings to window instead of frame */
  meta_window_grab_keys (window);

  g_free (frame);

  /* Put our state back where it should be */
  meta_window_queue (window, META_QUEUE_CALC_SHOWING);
  meta_window_queue (window, META_QUEUE_MOVE_RESIZE);
}
Esempio n. 10
0
static gboolean
meta_display_handle_event (MetaDisplay        *display,
                           const ClutterEvent *event)
{
  MetaWindow *window;
  gboolean bypass_clutter = FALSE;
  G_GNUC_UNUSED gboolean bypass_wayland = FALSE;
  MetaGestureTracker *tracker;
  ClutterEventSequence *sequence;

  sequence = clutter_event_get_event_sequence (event);

  /* Set the pointer emulating sequence on touch begin, if eligible */
  if (event->type == CLUTTER_TOUCH_BEGIN &&
      !display->pointer_emulating_sequence &&
      sequence_is_pointer_emulated (display, event))
    display->pointer_emulating_sequence = sequence;

#ifdef HAVE_WAYLAND
  MetaWaylandCompositor *compositor = NULL;
  if (meta_is_wayland_compositor ())
    {
      compositor = meta_wayland_compositor_get_default ();
      meta_wayland_compositor_update (compositor, event);
    }
#endif

  if (meta_is_wayland_compositor () && event->type == CLUTTER_MOTION)
    {
      MetaCursorTracker *tracker = meta_cursor_tracker_get_for_screen (NULL);
      meta_cursor_tracker_update_position (tracker, event->motion.x, event->motion.y);
    }

  handle_idletime_for_event (event);

  window = get_window_for_event (display, event);

  display->current_time = event->any.time;

  if (window && !window->override_redirect &&
      (event->type == CLUTTER_KEY_PRESS ||
       event->type == CLUTTER_BUTTON_PRESS ||
       event->type == CLUTTER_TOUCH_BEGIN))
    {
      if (CurrentTime == display->current_time)
        {
          /* We can't use missing (i.e. invalid) timestamps to set user time,
           * nor do we want to use them to sanity check other timestamps.
           * See bug 313490 for more details.
           */
          meta_warning ("Event has no timestamp! You may be using a broken "
                        "program such as xse.  Please ask the authors of that "
                        "program to fix it.\n");
        }
      else
        {
          meta_window_set_user_time (window, display->current_time);
          meta_display_sanity_check_timestamps (display, display->current_time);
        }
    }

  tracker = meta_display_get_gesture_tracker (display);

  if (meta_gesture_tracker_handle_event (tracker, event))
    {
      bypass_wayland = bypass_clutter = TRUE;
      goto out;
    }

  if (display->event_route == META_EVENT_ROUTE_WINDOW_OP)
    {
      if (meta_window_handle_mouse_grab_op_event (window, event))
        {
          bypass_clutter = TRUE;
          bypass_wayland = TRUE;
          goto out;
        }
    }

  /* For key events, it's important to enforce single-handling, or
   * we can get into a confused state. So if a keybinding is
   * handled (because it's one of our hot-keys, or because we are
   * in a keyboard-grabbed mode like moving a window, we don't
   * want to pass the key event to the compositor or Wayland at all.
   */
  if (meta_keybindings_process_event (display, window, event))
    {
      bypass_clutter = TRUE;
      bypass_wayland = TRUE;
      goto out;
    }

  if (window)
    {
      if (!clutter_event_get_event_sequence (event))
        {
          /* Swallow all non-touch events on windows that come our way.
           * Touch events that reach here aren't yet in an accepted state,
           * so Clutter must see them to maybe trigger gestures into
           * recognition.
           */
          bypass_clutter = TRUE;
        }

      meta_window_handle_ungrabbed_event (window, event);

      /* This might start a grab op. If it does, then filter out the
       * event, and if it doesn't, replay the event to release our
       * own sync grab. */

      if (display->event_route == META_EVENT_ROUTE_WINDOW_OP)
        {
          bypass_clutter = TRUE;
          bypass_wayland = TRUE;
        }
      else
        {
          /* Only replay button press events, since that's where we
           * have the synchronous grab. */
          if (event->type == CLUTTER_BUTTON_PRESS)
            {
              MetaBackend *backend = meta_get_backend ();
              if (META_IS_BACKEND_X11 (backend))
                {
                  Display *xdisplay = meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend));
                  meta_verbose ("Allowing events time %u\n",
                                (unsigned int)event->button.time);
                  XIAllowEvents (xdisplay, clutter_event_get_device_id (event),
                                 XIReplayDevice, event->button.time);
                }
            }
        }

      goto out;
    }

 out:
  /* If the compositor has a grab, don't pass that through to Wayland */
  if (display->event_route == META_EVENT_ROUTE_COMPOSITOR_GRAB)
    bypass_wayland = TRUE;

  /* If a Wayland client has a grab, don't pass that through to Clutter */
  if (display->event_route == META_EVENT_ROUTE_WAYLAND_POPUP)
    bypass_clutter = TRUE;

#ifdef HAVE_WAYLAND
  if (compositor && !bypass_wayland)
    {
      if (meta_wayland_compositor_handle_event (compositor, event))
        bypass_clutter = TRUE;
    }
#endif

  /* Unset the pointer emulating sequence after its end event is processed */
  if (event->type == CLUTTER_TOUCH_END &&
      display->pointer_emulating_sequence == sequence)
    display->pointer_emulating_sequence = NULL;

  display->current_time = CurrentTime;
  return bypass_clutter;
}
Esempio n. 11
0
MetaWorkspace*
meta_workspace_get_neighbor (MetaWorkspace      *workspace,
                             MetaMotionDirection direction)
{
  MetaWorkspaceLayout layout;
  int i, current_space, num_workspaces;
  gboolean ltr;
  MetaWrapStyle wrap;

  current_space = meta_workspace_index (workspace);
  num_workspaces = meta_screen_get_n_workspaces (workspace->screen);
  meta_screen_calc_workspace_layout (workspace->screen, num_workspaces,
                                     current_space, &layout);
  wrap = meta_prefs_get_wrap_style();

  meta_verbose ("Getting neighbor of %d in direction %s\n",
                current_space, meta_motion_direction_to_string (direction));

  ltr = meta_ui_get_direction() == META_UI_DIRECTION_LTR;

  switch (direction)
    {
    case META_MOTION_LEFT:
      layout.current_col -= ltr ? 1 : -1;
      break;
    case META_MOTION_RIGHT:
      layout.current_col += ltr ? 1 : -1;
      break;
    case META_MOTION_UP:
      layout.current_row -= 1;
      break;
    case META_MOTION_DOWN:
      layout.current_row += 1;
      break;
    case META_MOTION_PREV:
      break;
    }

  /* LEFT */
  if (layout.current_col < 0)
    switch (wrap)
      {
      case META_WRAP_NONE:
        layout.current_col = 0;
        break;
      case META_WRAP_CLASSIC:
        layout.current_row = layout.current_row > 0 ? layout.current_row - 1 : layout.rows - 1;
        /* fall through */
      case META_WRAP_TOROIDAL:
        layout.current_col = layout.cols - 1;
      }
  /* RIGHT */
  if (layout.current_col >= layout.cols)
    switch (wrap)
      {
      case META_WRAP_NONE:
        layout.current_col = layout.cols - 1;
        break;
      case META_WRAP_CLASSIC:
        layout.current_row = layout.current_row < layout.rows - 1 ? layout.current_row + 1 : 0;
        /* fall through */
      case META_WRAP_TOROIDAL:
        layout.current_col = 0;
      }
  /* UP */
  if (layout.current_row < 0)
    switch (wrap)
      {
      case META_WRAP_NONE:
        layout.current_row = 0;
        break;
      case META_WRAP_CLASSIC:
        layout.current_col = layout.current_col > 0 ? layout.current_col - 1 : layout.cols - 1;
        /* fall through */
      case META_WRAP_TOROIDAL:
        layout.current_row = layout.rows - 1;
      }
  /* DOWN */
  if (layout.current_row >= layout.rows)
    switch (wrap)
      {
      case META_WRAP_NONE:
        layout.current_row = layout.rows - 1;
        break;
      case META_WRAP_CLASSIC:
        layout.current_col = layout.current_col < layout.cols - 1 ? layout.current_col + 1 : 0;
        /* fall through */
      case META_WRAP_TOROIDAL:
        layout.current_row = 0;
      }

  /* If we have an uneven arrangement of workspaces, (layout.cols - n, layout.rows - 1) may be an invalid workspace
     e.g. we have 7 workspaces on a 3x3 pane */
  if (wrap != META_WRAP_NONE && (layout.current_row * layout.cols + layout.current_col >= num_workspaces))
    switch (direction)
      {
      case META_MOTION_LEFT:
        layout.current_col = num_workspaces - (layout.current_row * layout.cols + 1);
        break;
      case META_MOTION_RIGHT:
       layout.current_col = 0;
       if (wrap == META_WRAP_CLASSIC)
         layout.current_row = 0;
       break;
      case META_MOTION_UP:
        layout.current_row -= 1;
        break;
      case META_MOTION_DOWN:
        layout.current_row = 0;
        if (wrap == META_WRAP_CLASSIC)
	  layout.current_col = layout.current_col < layout.cols - 1 ? layout.current_col + 1 : 0;
        break;
      case META_MOTION_PREV:
        break;
      }

  i = layout.grid[layout.current_row * layout.cols + layout.current_col];

  if (i < 0)
    i = current_space;

  if (i >= num_workspaces)
    meta_bug ("calc_workspace_layout left an invalid (too-high) workspace number %d in the grid\n",
              i);

  meta_verbose ("Neighbor workspace is %d at row %d col %d\n",
                i, layout.current_row, layout.current_col);

  meta_screen_free_workspace_layout (&layout);

  return meta_screen_get_workspace_by_index (workspace->screen, i);
}
Esempio n. 12
0
void
meta_compositor_sync_stack (MetaCompositor  *compositor,
			    GList	    *stack)
{
  GList *old_stack;

  /* This is painful because hidden windows that we are in the process
   * of animating out of existence. They'll be at the bottom of the
   * stack of X windows, but we want to leave them in their old position
   * until the animation effect finishes.
   */

  /* Sources: first window is the highest */
  stack = g_list_copy (stack); /* The new stack of MetaWindow */
  old_stack = g_list_reverse (compositor->windows); /* The old stack of MetaWindowActor */
  compositor->windows = NULL;

  while (TRUE)
    {
      MetaWindowActor *old_actor = NULL, *stack_actor = NULL, *actor;
      MetaWindow *old_window = NULL, *stack_window = NULL, *window;

      /* Find the remaining top actor in our existing stack (ignoring
       * windows that have been hidden and are no longer animating) */
      while (old_stack)
        {
          old_actor = old_stack->data;
          old_window = meta_window_actor_get_meta_window (old_actor);

          if ((old_window->hidden || old_window->unmanaging) &&
              !meta_window_actor_effect_in_progress (old_actor))
            {
              old_stack = g_list_delete_link (old_stack, old_stack);
              old_actor = NULL;
            }
          else
            break;
        }

      /* And the remaining top actor in the new stack */
      while (stack)
        {
          stack_window = stack->data;
          stack_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (stack_window));
          if (!stack_actor)
            {
              meta_verbose ("Failed to find corresponding MetaWindowActor "
                            "for window %s\n", meta_window_get_description (stack_window));
              stack = g_list_delete_link (stack, stack);
            }
          else
            break;
        }

      if (!old_actor && !stack_actor) /* Nothing more to stack */
        break;

      /* We usually prefer the window in the new stack, but if if we
       * found a hidden window in the process of being animated out
       * of existence in the old stack we use that instead. We've
       * filtered out non-animating hidden windows above.
       */
      if (old_actor &&
          (!stack_actor || old_window->hidden || old_window->unmanaging))
        {
          actor = old_actor;
          window = old_window;
        }
      else
        {
          actor = stack_actor;
          window = stack_window;
        }

      /* OK, we know what actor we want next. Add it to our window
       * list, and remove it from both source lists. (It will
       * be at the front of at least one, hopefully it will be
       * near the front of the other.)
       */
      compositor->windows = g_list_prepend (compositor->windows, actor);

      stack = g_list_remove (stack, window);
      old_stack = g_list_remove (old_stack, actor);
    }

  sync_actor_stacking (compositor);
}
Esempio n. 13
0
/**
 * meta_workspace_activate_with_focus:
 * @workspace: a #MetaWorkspace
 * @focus_this: the #MetaWindow to be focused, or %NULL
 * @timestamp: timestamp for @focus_this
 *
 * Switches to @workspace and possibly activates the window @focus_this.
 *
 * The window @focus_this is activated by calling meta_window_activate()
 * which will unminimize it and transient parents, raise it and give it
 * the focus.
 *
 * If a window is currently being moved by the user, it will be
 * moved to @workspace.
 *
 * The advantage of calling this function instead of meta_workspace_activate()
 * followed by meta_window_activate() is that it happens as a unit, so
 * no other window gets focused first before @focus_this.
 */
void
meta_workspace_activate_with_focus (MetaWorkspace *workspace,
                                    MetaWindow    *focus_this,
                                    guint32        timestamp)
{
  MetaWorkspace  *old;
  MetaWindow     *move_window;
  MetaScreen     *screen;
  MetaDisplay    *display;
  MetaCompositor *comp;
  MetaWorkspaceLayout layout1, layout2;
  gint num_workspaces, current_space, new_space;
  MetaMotionDirection direction;
  
  meta_verbose ("Activating workspace %d\n",
                meta_workspace_index (workspace));
  
  if (workspace->screen->active_workspace == workspace)
    return;

  /* Free any cached pointers to the workspaces's edges from
   * a current resize or move operation */
  meta_display_cleanup_edges (workspace->screen->display);

  if (workspace->screen->active_workspace)
    workspace_switch_sound (workspace->screen->active_workspace, workspace);

  /* Note that old can be NULL; e.g. when starting up */
  old = workspace->screen->active_workspace;

  workspace->screen->active_workspace = workspace;

  meta_screen_set_active_workspace_hint (workspace->screen);

  /* If the "show desktop" mode is active for either the old workspace
   * or the new one *but not both*, then update the
   * _net_showing_desktop hint
   */
  if (old && (old->showing_desktop ^ workspace->showing_desktop))
    meta_screen_update_showing_desktop_hint (workspace->screen);

  if (old == NULL)
    return;

  move_window = NULL;
  if (workspace->screen->display->grab_op == META_GRAB_OP_MOVING ||
      workspace->screen->display->grab_op == META_GRAB_OP_KEYBOARD_MOVING)
    move_window = workspace->screen->display->grab_window;
      
  if (move_window != NULL)
    {
      if (move_window->on_all_workspaces)
        move_window = NULL; /* don't move it after all */

      /* We put the window on the new workspace, flip spaces,
       * then remove from old workspace, so the window
       * never gets unmapped and we maintain the button grab
       * on it.
       *
       * \bug  This comment appears to be the reverse of what happens
       */
      if (move_window && (move_window->workspace != workspace))
        {
          meta_workspace_remove_window (old, move_window);
          meta_workspace_add_window (workspace, move_window);
        }
    }

  meta_workspace_queue_calc_showing (old);
  meta_workspace_queue_calc_showing (workspace);

  /* FIXME: Why do we need this?!?  Isn't it handled in the lines above? */
  if (move_window)
      /* Removes window from other spaces */
      meta_window_change_workspace (move_window, workspace);

   /*
    * Notify the compositor that the active workspace is changing.
    */
   screen = workspace->screen;
   display = meta_screen_get_display (screen);
   comp = meta_display_get_compositor (display);
   direction = 0;

   current_space = meta_workspace_index (old);
   new_space     = meta_workspace_index (workspace);
   num_workspaces = meta_screen_get_n_workspaces (workspace->screen);
   meta_screen_calc_workspace_layout (workspace->screen, num_workspaces,
                                      current_space, &layout1);

   meta_screen_calc_workspace_layout (workspace->screen, num_workspaces,
                                      new_space, &layout2);

   if (meta_ui_get_direction() == META_UI_DIRECTION_RTL)
     {
       if (layout1.current_col > layout2.current_col)
         direction = META_MOTION_RIGHT;
       else if (layout1.current_col < layout2.current_col)
         direction = META_MOTION_LEFT;
     }
   else
    {
       if (layout1.current_col < layout2.current_col)
         direction = META_MOTION_RIGHT;
       else if (layout1.current_col > layout2.current_col)
         direction = META_MOTION_LEFT;
    }

   if (layout1.current_row < layout2.current_row)
     {
       if (!direction)
         direction = META_MOTION_DOWN;
       else if (direction == META_MOTION_RIGHT)
         direction = META_MOTION_DOWN_RIGHT;
       else
         direction = META_MOTION_DOWN_LEFT;
     }

   if (layout1.current_row > layout2.current_row)
     {
       if (!direction)
         direction = META_MOTION_UP;
       else if (direction == META_MOTION_RIGHT)
         direction = META_MOTION_UP_RIGHT;
       else
         direction = META_MOTION_UP_LEFT;
     }

   meta_screen_free_workspace_layout (&layout1);
   meta_screen_free_workspace_layout (&layout2);

   meta_compositor_switch_workspace (comp, screen, old, workspace, direction);

  /* This needs to be done after telling the compositor we are switching
   * workspaces since focusing a window will cause it to be immediately
   * shown and that would confuse the compositor if it didn't know we
   * were in a workspace switch.
   */
  if (focus_this)
    {
      meta_window_activate (focus_this, timestamp);
    }
  else if (move_window)
    {
      meta_window_raise (move_window);
    }
  else
    {
      meta_topic (META_DEBUG_FOCUS, "Focusing default window on new workspace\n");
      meta_workspace_focus_default_window (workspace, NULL, timestamp);
    }

   /* Emit switched signal from screen.c */
   meta_screen_workspace_switched (screen, current_space, new_space, direction);
}
Esempio n. 14
0
MetaWorkspace*
meta_workspace_get_neighbor (MetaWorkspace      *workspace,
                             MetaMotionDirection direction)
{
  MetaWorkspaceLayout layout;
  int i, current_space, num_workspaces;
  gboolean ltr;

  current_space = meta_workspace_index (workspace);
  num_workspaces = meta_screen_get_n_workspaces (workspace->screen);
  meta_screen_calc_workspace_layout (workspace->screen, num_workspaces,
                                     current_space, &layout);

  meta_verbose ("Getting neighbor of %d in direction %s\n",
                current_space, meta_motion_direction_to_string (direction));

  ltr = meta_ui_get_direction() == META_UI_DIRECTION_LTR;

  switch (direction)
    {
    case META_MOTION_LEFT:
      layout.current_col -= ltr ? 1 : -1;
      break;
    case META_MOTION_RIGHT:
      layout.current_col += ltr ? 1 : -1;
      break;
    case META_MOTION_UP:
      layout.current_row -= 1;
      break;
    case META_MOTION_DOWN:
      layout.current_row += 1;
      break;
    default:
      break;
    }

  if (layout.current_col < 0)
    layout.current_col = 0;
  if (layout.current_col >= layout.cols)
    layout.current_col = layout.cols - 1;
  if (layout.current_row < 0)
    layout.current_row = 0;
  if (layout.current_row >= layout.rows)
    layout.current_row = layout.rows - 1;

  i = layout.grid[layout.current_row * layout.cols + layout.current_col];

  if (i < 0)
    i = current_space;

  if (i >= num_workspaces)
    {
      g_error ("calc_workspace_layout left an invalid (too-high) workspace "
               "number %d in the grid", i);
    }

  meta_verbose ("Neighbor workspace is %d at row %d col %d\n",
                i, layout.current_row, layout.current_col);

  meta_screen_free_workspace_layout (&layout);

  return meta_screen_get_workspace_by_index (workspace->screen, i);
}