/* workspace object */

/*
 * Copyright (C) 2001 Havoc Pennington
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#ifdef HAVE_MEMORY_H
#include <memory.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif

#include "netk-workspace.h"
#include "netk-xutils.h"
#include "netk-private.h"

#define NETK_WORKSPACE_GET_PRIVATE(o)    (G_TYPE_INSTANCE_GET_PRIVATE ((o), NETK_TYPE_WORKSPACE, NetkWorkspacePrivate))

struct _NetkWorkspacePrivate
{
    NetkScreen *screen;
    int number;
    char *name;
    int width, height;          /* Workspace size */
    int viewport_x, viewport_y; /* Viewport origin */
    gboolean is_virtual;
};

enum
{
    NAME_CHANGED,
    LAST_SIGNAL
};

static void netk_workspace_init (NetkWorkspace * workspace);
static void netk_workspace_class_init (NetkWorkspaceClass * klass);
static void netk_workspace_finalize (GObject * object);


static void emit_name_changed (NetkWorkspace * space);

static GObjectClass *parent_class;
static guint signals[LAST_SIGNAL] = { 0 };

GType
netk_workspace_get_type (void)
{
    static GType type = G_TYPE_INVALID;

    if (G_UNLIKELY (type == G_TYPE_INVALID))
    {
        type = _netk_g_type_register_simple (G_TYPE_OBJECT,
                                             "NetkWorkspace",
                                             sizeof (NetkWorkspaceClass),
                                             netk_workspace_class_init,
                                             sizeof (NetkWorkspace),
                                             netk_workspace_init,
                                             0);
    }

    return type;
}

static void
netk_workspace_init (NetkWorkspace * workspace)
{
    workspace->priv = NETK_WORKSPACE_GET_PRIVATE (workspace);
    
    workspace->priv->number = -1;
}

static void
netk_workspace_class_init (NetkWorkspaceClass * klass)
{
    GObjectClass *object_class = G_OBJECT_CLASS (klass);
    
    g_type_class_add_private (klass, sizeof (NetkWorkspacePrivate));

    parent_class = g_type_class_peek_parent (klass);

    object_class->finalize = netk_workspace_finalize;

    signals[NAME_CHANGED] =
        g_signal_new (I_("name_changed"), G_OBJECT_CLASS_TYPE (object_class),
                      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NetkWorkspaceClass,
                                                          name_changed), NULL,
                      NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
}

static void
netk_workspace_finalize (GObject * object)
{
    NetkWorkspace *workspace;

    workspace = NETK_WORKSPACE (object);

    g_free (workspace->priv->name);

    G_OBJECT_CLASS (parent_class)->finalize (object);
}

/**
 * netk_workspace_get_number:
 * @space: a #NetkWorkspace
 * 
 * 
 * 
 * Return value: get the index of the workspace
 **/
int
netk_workspace_get_number (NetkWorkspace * space)
{
    g_return_val_if_fail (NETK_IS_WORKSPACE (space), 0);

    return space->priv->number;
}

/**
 * netk_workspace_get_name:
 * @space: a #NetkWorkspace
 * 
 * Gets the name that should be used to refer to the workspace
 * in the user interface. If the user hasn't set a special name,
 * will be something like "Workspace 3" - otherwise whatever name
 * the user set.
 *
 * Return value: workspace name, never %NULL 
 **/
const char *
netk_workspace_get_name (NetkWorkspace * space)
{
    g_return_val_if_fail (NETK_IS_WORKSPACE (space), NULL);

    return space->priv->name;
}

/**
 * netk_workspace_change_name:
 * @space: a #NetkWorkspace
 * @name: new workspace name
 *
 * Try changing the name of the workspace.
 * 
 **/
void
netk_workspace_change_name (NetkWorkspace * space, const char *name)
{
    g_return_if_fail (NETK_IS_WORKSPACE (space));
    g_return_if_fail (name != NULL);

    p_netk_screen_change_workspace_name (space->priv->screen,
                                         space->priv->number, name);
}

/**
 * netk_workspace_activate:
 * @space: a #NetkWorkspace
 * 
 * Ask window manager to make @space the active workspace.
 * 
 **/
void
netk_workspace_activate (NetkWorkspace * space)
{
    g_return_if_fail (NETK_IS_WORKSPACE (space));

    p_netk_activate_workspace (NETK_SCREEN_XSCREEN (space->priv->screen),
                               space->priv->number);
}

NetkWorkspace *
p_netk_workspace_create (int number, NetkScreen * screen)
{
    NetkWorkspace *space;

    space = g_object_new (NETK_TYPE_WORKSPACE, NULL);
    space->priv->number = number;
    space->priv->name = NULL;
    space->priv->screen = screen;
    space->priv->is_virtual = FALSE;

    p_netk_workspace_update_name (space, NULL);

    /* Just set reasonable defaults */
    space->priv->width = netk_screen_get_width (screen);
    space->priv->height = netk_screen_get_height (screen);

    space->priv->viewport_x = 0;
    space->priv->viewport_y = 0;

    return space;
}

void
p_netk_workspace_update_name (NetkWorkspace * space, const char *name)
{
    char *old;

    g_return_if_fail (NETK_IS_WORKSPACE (space));

    old = space->priv->name;
    space->priv->name = g_strdup (name);

    if (space->priv->name == NULL)
        space->priv->name = g_strdup_printf ("%d", space->priv->number + 1);

    if ((old && !name) || (!old && name)
        || (old && name && strcmp (old, name) != 0))
        emit_name_changed (space);

    g_free (old);
}

static void
emit_name_changed (NetkWorkspace * space)
{
    g_signal_emit (G_OBJECT (space), signals[NAME_CHANGED], 0);
}

gboolean
p_netk_workspace_set_geometry (NetkWorkspace * space, int w, int h)
{
    if (space->priv->width != w || space->priv->height != h)
    {
        space->priv->width = w;
        space->priv->height = h;
        space->priv->is_virtual = 
            ((w > netk_screen_get_width (space->priv->screen)) ||
             (h > netk_screen_get_height (space->priv->screen)));
             
        return TRUE;            /* change was made */
    }
    else
        return FALSE;
}

gboolean
p_netk_workspace_set_viewport (NetkWorkspace * space, int x, int y)
{
    if (space->priv->viewport_x != x || space->priv->viewport_y != y)
    {
        space->priv->viewport_x = x;
        space->priv->viewport_y = y;

        return TRUE;            /* change was made */
    }
    else
        return FALSE;
}

int
netk_workspace_get_width (NetkWorkspace * space)
{
    g_return_val_if_fail (NETK_IS_WORKSPACE (space), 0);

    return space->priv->width;
}

int
netk_workspace_get_height (NetkWorkspace * space)
{
    return space->priv->height;
}

int
netk_workspace_get_viewport_x (NetkWorkspace * space)
{
    return space->priv->viewport_x;
}

int
netk_workspace_get_viewport_y (NetkWorkspace * space)
{
    return space->priv->viewport_y;
}

gboolean
netk_workspace_is_virtual (NetkWorkspace *space)
{
    return space->priv->is_virtual;
}
