308 lines
10 KiB
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);
|
|
} |