diya-shell/src/foreign.c

308 lines
10 KiB
C

#include <assert.h>
#include <inttypes.h>
#include "foreign.h"
/**
* @DiyaForeignWindow Object definition
*
*/
enum
{
NO_PROP,
WIN_APP_ID,
WIN_TITLE,
WIN_HANDLE,
WIN_STATE,
WIN_PARENT,
N_PROPERTIES
};
static GParamSpec *win_properties[N_PROPERTIES] = {0};
struct _DiyaForeignWindow
{
DiyaObject parent;
gchar * appid;
gpointer handle;
gchar* title;
enum diya_win_state state;
DiyaForeignWindow * parent_win;
gchar string[128];
};
G_DEFINE_FINAL_TYPE(DiyaForeignWindow, diya_foreign_window, DIYA_TYPE_SHELL_OBJECT)
static void diya_foreign_window_dispose(GObject* object)
{
DiyaForeignWindow * self = DIYA_FOREIGN_WINDOW(object);
g_debug("diya_foreign_window_dispose: %s", diya_object_to_string(self));
if(self->appid)
{
g_free(self->appid);
}
if(self->title)
{
g_free(self->title);
}
G_OBJECT_CLASS(diya_foreign_window_parent_class)->dispose(object);
}
static void diya_foreign_window_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
{
DiyaForeignWindow * self = DIYA_FOREIGN_WINDOW(object);
switch (property_id)
{
case WIN_APP_ID:
if(self->appid)
{
g_free(self->appid);
}
self->appid = g_strdup(g_value_get_string(value));
break;
case WIN_TITLE:
if(self->title)
{
g_free(self->title);
}
self->title = g_strdup(g_value_get_string(value));
break;
case WIN_HANDLE:
self->handle = g_value_get_pointer(value);
break;
case WIN_PARENT:
self->parent_win = g_value_get_pointer(value);
break;
case WIN_STATE:
self->state = g_value_get_uint(value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void diya_foreign_window_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
{
DiyaForeignWindow * self = DIYA_FOREIGN_WINDOW(object);
switch (property_id)
{
case WIN_APP_ID:
g_value_set_string(value, self->appid);
break;
case WIN_TITLE:
g_value_set_string(value, self->title);
break;
case WIN_HANDLE:
g_value_set_pointer(value, self->handle);
break;
case WIN_PARENT:
g_value_set_pointer(value, self->parent_win);
break;
case WIN_STATE:
g_value_set_uint(value, self->state);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void diya_foreign_window_init(DiyaForeignWindow *self)
{
self->appid = NULL;
//self->handle = NULL;
self->parent_win = NULL;
//self->shell = NULL;
self->state = DIYA_WIN_STATE_NONE;
self->title = NULL;
memset(self->string, 0, sizeof(self->string));
}
static const gchar* diya_foreign_window_to_string(DiyaObject* object)
{
DiyaForeignWindow* self = DIYA_FOREIGN_WINDOW(object);
g_snprintf(self->string, sizeof(self->string), "Window 0x%" PRIXPTR ": %s (%s)", (uintptr_t) self->handle, self->appid?self->appid:"", self->title?self->title:"");
return self->string;
}
static void diya_foreign_window_class_init(DiyaForeignWindowClass *class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS(class);
DiyaObjectClass *base_class = DIYA_OBJECT_CLASS(class);
gobject_class->dispose = diya_foreign_window_dispose;
gobject_class->set_property = diya_foreign_window_set_property;
gobject_class->get_property = diya_foreign_window_get_property;
base_class->to_string = diya_foreign_window_to_string;
win_properties[WIN_APP_ID] = g_param_spec_string("appid", NULL, "Window application id", "", G_PARAM_READWRITE);
win_properties[WIN_TITLE] = g_param_spec_string("title", NULL, "Window title","", G_PARAM_READWRITE );
win_properties[WIN_HANDLE] = g_param_spec_pointer("handle", NULL, "Foreign window handle", G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY );
win_properties[WIN_STATE] = g_param_spec_uint("state", NULL, "Window state",0, UINT_MAX , DIYA_WIN_STATE_NONE,G_PARAM_READWRITE);
win_properties[WIN_PARENT] = g_param_spec_pointer("parent", NULL, "Window parent", G_PARAM_READWRITE);
g_object_class_install_properties (gobject_class, N_PROPERTIES, win_properties);
}
static struct zwlr_foreign_toplevel_manager_v1 *g_toplevel_manager;
static void toplevel_handle_output_leave(void *data,
struct zwlr_foreign_toplevel_handle_v1 *handle,
struct wl_output *output)
{
(void) data;
(void) handle;
(void) output;
}
static void toplevel_handle_title(void *data,
struct zwlr_foreign_toplevel_handle_v1 *handle,
const char *title)
{
DiyaShell *shell = (DiyaShell *)data;
assert(shell);
DiyaForeignWindow *win = diya_shell_get_window(shell, handle);
assert(win);
g_object_set(win, "title", title, NULL);
g_debug("New title for: %s", diya_object_to_string(win));
}
static void toplevel_handle_app_id(void *data,
struct zwlr_foreign_toplevel_handle_v1 *handle,
const char *app_id)
{
DiyaShell *shell = (DiyaShell *)data;
assert(shell);
DiyaForeignWindow *win = diya_shell_get_window(shell, handle);
assert(win);
g_object_set(win, "appid", app_id, NULL);
g_debug("New appid for: %s", diya_object_to_string(win));
}
static void toplevel_handle_output_enter(void *data,
struct zwlr_foreign_toplevel_handle_v1 *handle,
struct wl_output *output)
{
(void) data;
(void) handle;
(void) output;
}
static void toplevel_handle_state(void *data,
struct zwlr_foreign_toplevel_handle_v1 *handle,
struct wl_array *state)
{
uint32_t *entry;
DiyaShell *shell = (DiyaShell *)data;
assert(shell);
DiyaForeignWindow *win = diya_shell_get_window(shell, handle);
assert(win);
enum diya_win_state wstate = DIYA_WIN_STATE_NONE;
wl_array_for_each(entry, state) switch (*entry)
{
case ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_MINIMIZED:
wstate |= DIYA_WIN_STATE_MINIMIZE;
break;
case ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_MAXIMIZED:
wstate |= DIYA_WIN_STATE_MAXIMIZE;
break;
case ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_FULLSCREEN:
wstate |= DIYA_WIN_STATE_FULLSCREEN;
break;
case ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_ACTIVATED:
wstate |= DIYA_WIN_STATE_FOCUS;
break;
}
g_object_set(win, "state", wstate, NULL);
}
static void toplevel_handle_done(void *data,
struct zwlr_foreign_toplevel_handle_v1 *handle)
{
DiyaShell *shell = (DiyaShell *)data;
assert(shell);
DiyaForeignWindow *win = diya_shell_get_window(shell, handle);
assert(win);
g_signal_emit_by_name(shell, "foreign-window-changed", (void *)win);
}
static void toplevel_handle_closed(void *data,
struct zwlr_foreign_toplevel_handle_v1 *handle)
{
DiyaShell *shell = (DiyaShell *)data;
assert(shell);
DiyaForeignWindow *win = diya_shell_get_window(shell, handle);
assert(win);
g_signal_emit_by_name(shell, "foreign-window-removed", (void *)win);
diya_shell_remove_window(shell, win);
zwlr_foreign_toplevel_handle_v1_destroy(handle);
}
static void toplevel_handle_parent(void *data,
struct zwlr_foreign_toplevel_handle_v1 *handle,
struct zwlr_foreign_toplevel_handle_v1 *parent)
{
if (!parent)
{
return;
}
assert(handle != parent);
DiyaShell *shell = (DiyaShell *)data;
assert(shell);
DiyaForeignWindow *child_win = diya_shell_get_window(shell, handle);
DiyaForeignWindow *parent_win = diya_shell_get_window(shell, parent);
assert(child_win);
assert(parent_win);
assert(child_win != parent_win);
g_object_set(child_win, "parent", parent_win, NULL);
g_debug("toplevel_handle_parent: %s is child of %s",
diya_object_to_string(child_win),
diya_object_to_string(parent_win));
}
static const struct zwlr_foreign_toplevel_handle_v1_listener g_toplevel_impl = {
.title = toplevel_handle_title,
.app_id = toplevel_handle_app_id,
.output_enter = toplevel_handle_output_enter,
.output_leave = toplevel_handle_output_leave,
.state = toplevel_handle_state,
.done = toplevel_handle_done,
.closed = toplevel_handle_closed,
.parent = toplevel_handle_parent
};
static DiyaForeignWindow * diya_shell_foreign_window_new(DiyaShell* shell, gpointer handle)
{
DiyaForeignWindow *win = DIYA_FOREIGN_WINDOW(g_object_new(DIYA_TYPE_FOREIGN_WINDOW,"handle", handle, "shell", shell, NULL));
//g_object_set(win, "shell", shell, NULL);
diya_shell_add_window(shell, win);
g_debug("Add new window 0x%" PRIXPTR, (uintptr_t)handle);
return win;
}
static void toplevel_manager_handle_toplevel(void *data, struct zwlr_foreign_toplevel_manager_v1 *toplevel_manager, struct zwlr_foreign_toplevel_handle_v1 *tl)
{
(void) toplevel_manager;
DiyaShell *shell = (DiyaShell *)data;
assert(shell);
DiyaForeignWindow *win = diya_shell_get_window(shell, tl);
if (win)
{
g_debug("[%s] already exists",diya_object_to_string(win));
return;
}
// TODO: different between windows
win = diya_shell_foreign_window_new(shell, tl);
zwlr_foreign_toplevel_handle_v1_add_listener(tl, &g_toplevel_impl, data);
}
static void toplevel_manager_handle_finished(void *data,
struct zwlr_foreign_toplevel_manager_v1 *toplevel_manager)
{
DiyaShell *shell = (DiyaShell *)data;
diya_shell_remove_all_windows(shell);
// remove table entry
zwlr_foreign_toplevel_manager_v1_destroy(toplevel_manager);
}
static const struct zwlr_foreign_toplevel_manager_v1_listener g_toplevel_manager_impl =
{
.toplevel = toplevel_manager_handle_toplevel,
.finished = toplevel_manager_handle_finished,
};
void diya_shell_foreign_toplevel_register(struct wl_registry *registry, uint32_t name, DiyaShell *shell)
{
g_toplevel_manager = wl_registry_bind(registry, name, &zwlr_foreign_toplevel_manager_v1_interface, 3);
zwlr_foreign_toplevel_manager_v1_add_listener(g_toplevel_manager, &g_toplevel_manager_impl, (void *)shell);
}