#include #include #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); }