diff --git a/meson.build b/meson.build index 60433b1..cdcdd56 100644 --- a/meson.build +++ b/meson.build @@ -2,7 +2,7 @@ project('diya-shell', ['c'], version: '0.1.0', license: 'MIT', - meson_version: '>=0.51.0', + meson_version: '>=0.58.0', default_options: ['c_std=gnu11', 'warning_level=3']) lib_so_version = '0' @@ -22,7 +22,10 @@ wayland_client = dependency('wayland-client', version: '>=1.10.0') wayland_scanner = find_program('wayland-scanner') # use system xdg-shell protocol when available -#wayland_protocols = dependency('wayland-protocols', version: '>=1.16') +wayland_protocols = dependency('wayland-protocols', version: '>=1.16') + +wl_protocol_dir = wayland_protocols.get_variable('pkgdatadir') + # pkg_config = import('pkgconfig') # gnome = import('gnome') @@ -30,11 +33,12 @@ wayland_scanner = find_program('wayland-scanner') gtk_layer_shell = dependency('gtk4-layer-shell-0', version: '>=1.0.2') wayland_targets=[] -wayland_protos = [ - 'protocols/wlr-foreign-toplevel-management-unstable-v1' +wl_protocols = [ + wl_protocol_dir / 'staging/ext-session-lock/ext-session-lock-v1', + 'protocols/wlr-foreign-toplevel-management-unstable-v1' ] -foreach proto : wayland_protos +foreach proto : wl_protocols xml = ''.join([proto,'.xml']) header = ''.join([proto.split('/').get(-1),'.h']) cfile = ''.join([proto.split('/').get(-1),'.c']) @@ -51,6 +55,9 @@ src = [ 'src/wayland.c', 'src/shell.c', 'src/foreign.c', + 'src/session.c', + 'src/widgets/cairo-widget.c', + 'src/main.c', wayland_targets] executable( diff --git a/src/background.c b/src/background.c index ef87bb9..c8f539c 100644 --- a/src/background.c +++ b/src/background.c @@ -11,9 +11,12 @@ static void on_background_destroy(GtkWindow *window, GApplication *_data) void diya_shell_init_background(DiyaShell * shell) { - GtkWindow *gtk_window; - g_object_get(shell, "background", >k_window, NULL); + GtkApplication * app; + g_object_get(shell, "application", &app, NULL); + assert(app); + GtkWindow *gtk_window = GTK_WINDOW (gtk_application_window_new (app)); assert(gtk_window); + g_object_set(shell, "background", gtk_window, NULL); g_signal_connect (gtk_window, "destroy", G_CALLBACK (on_background_destroy), NULL); // int layer shell for window gtk_layer_init_for_window (gtk_window); diff --git a/src/base.c b/src/base.c index 546e690..ef726f5 100644 --- a/src/base.c +++ b/src/base.c @@ -1,10 +1,20 @@ #include "base.h" +#include "shell.h" G_DEFINE_ABSTRACT_TYPE(DiyaObject, diya_object, G_TYPE_OBJECT) + +static void diya_object_dispose(GObject* object) +{ + g_debug("diya_object_dispose"); + G_OBJECT_CLASS (diya_object_parent_class)->dispose(object); +} + static void diya_object_class_init(DiyaObjectClass *class) { + GObjectClass *gobject_class = G_OBJECT_CLASS(class); class->to_string = NULL; + gobject_class->dispose = diya_object_dispose; } static void diya_object_init(DiyaObject *self) @@ -12,10 +22,82 @@ static void diya_object_init(DiyaObject *self) (void) self; } +enum +{ + SO_NO_PROP, + SO_SHELL, + SO_N_PROPERTIES +}; + +static GParamSpec *g_so_prop[SO_N_PROPERTIES] = {0}; + +typedef struct _DiyaShellObjectPrivate +{ + DiyaObject * parent; + DiyaShell * shell; +} DiyaShellObjectPrivate; +G_DEFINE_TYPE_WITH_PRIVATE(DiyaShellObject, diya_shell_object, DIYA_TYPE_OBJECT); + +static void diya_shell_object_dispose(GObject* object) +{ + g_debug("diya_shell_object_dispose"); + G_OBJECT_CLASS(diya_shell_object_parent_class)->dispose(object); +} + +static void diya_shell_object_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) +{ + DiyaShellObject * self = DIYA_SHELL_OBJECT(object); + DiyaShellObjectPrivate* priv = diya_shell_object_get_instance_private(self); + + switch (property_id) + { + case SO_SHELL: + priv->shell = g_value_get_pointer(value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void diya_shell_object_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec) +{ + DiyaShellObject * self = DIYA_SHELL_OBJECT(object); + DiyaShellObjectPrivate* priv = diya_shell_object_get_instance_private(self); + switch (property_id) + { + case SO_SHELL: + g_value_set_pointer(value, priv->shell); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + + +static void diya_shell_object_init(DiyaShellObject *self) +{ + DiyaShellObjectPrivate* priv = diya_shell_object_get_instance_private(self); + priv->shell = NULL; +} + +static void diya_shell_object_class_init(DiyaShellObjectClass *class) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS(class); + gobject_class->dispose = diya_shell_object_dispose; + gobject_class->set_property = diya_shell_object_set_property; + gobject_class->get_property = diya_shell_object_get_property; + g_so_prop[SO_SHELL] = g_param_spec_pointer("shell", NULL, "Reference to global shell", G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY); // + + g_object_class_install_properties (gobject_class, SO_N_PROPERTIES, g_so_prop); +} + + const gchar * diya_object_to_string(gpointer object) { g_return_val_if_fail(DIYA_IS_OBJECT(object), NULL); DiyaObject * self = DIYA_OBJECT(object); DiyaObjectClass *class = DIYA_OBJECT_GET_CLASS(self); - return class->to_string ? class->to_string(self) : NULL; + return class->to_string ? class->to_string(self) : ""; } \ No newline at end of file diff --git a/src/base.h b/src/base.h index 7efcc69..dd90c11 100644 --- a/src/base.h +++ b/src/base.h @@ -2,23 +2,41 @@ #define DIYA_OBJECT_H #include + +typedef struct +{ + gint x; + gint y; + gint width; + gint height; +} diya_rect_t; + /** * Base class object - * + * */ -#define DIYA_TYPE_OBJECT (diya_object_get_type ()) -G_DECLARE_DERIVABLE_TYPE (DiyaObject, diya_object, DIYA, OBJECT, GObject) +#define DIYA_TYPE_OBJECT (diya_object_get_type()) +G_DECLARE_DERIVABLE_TYPE(DiyaObject, diya_object, DIYA, OBJECT, GObject) -struct _DiyaObjectClass { - GObjectClass parent_class; - const gchar* (*to_string) (DiyaObject *self); - /** - * @brief reserve for futur use to - * define common API for descendants - * - */ +struct _DiyaObjectClass +{ + GObjectClass parent_class; + const gchar *(*to_string)(DiyaObject *self); + /** + * @brief reserve for futur use to + * define common API for descendants + * + */ }; -const gchar* diya_object_to_string(gpointer object); +#define DIYA_TYPE_SHELL_OBJECT (diya_shell_object_get_type()) +G_DECLARE_DERIVABLE_TYPE(DiyaShellObject, diya_shell_object, DIYA, SHELL_OBJECT, DiyaObject) + +struct _DiyaShellObjectClass +{ + DiyaObjectClass parent_class; +}; + +const gchar *diya_object_to_string(gpointer object); #endif \ No newline at end of file diff --git a/src/foreign.c b/src/foreign.c index f7050b4..2bcdd77 100644 --- a/src/foreign.c +++ b/src/foreign.c @@ -3,7 +3,7 @@ #include "foreign.h" /** - * @DiyaWindow Object definition + * @DiyaForeignWindow Object definition * */ enum @@ -14,27 +14,25 @@ enum WIN_HANDLE, WIN_STATE, WIN_PARENT, - SHELL, N_PROPERTIES }; static GParamSpec *win_properties[N_PROPERTIES] = {0}; -struct _DiyaWindow +struct _DiyaForeignWindow { DiyaObject parent; gchar * appid; gpointer handle; gchar* title; enum diya_win_state state; - DiyaWindow * parent_win; - DiyaShell * shell; + DiyaForeignWindow * parent_win; gchar string[128]; }; -G_DEFINE_TYPE(DiyaWindow, diya_window, DIYA_TYPE_OBJECT) +G_DEFINE_FINAL_TYPE(DiyaForeignWindow, diya_foreign_window, DIYA_TYPE_SHELL_OBJECT) -static void diya_window_finalize(GObject* object) +static void diya_foreign_window_dispose(GObject* object) { - DiyaWindow * self = DIYA_WINDOW(object); - g_debug("diya_window_finalize: %s", diya_object_to_string(self)); + 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); @@ -43,11 +41,12 @@ static void diya_window_finalize(GObject* object) { g_free(self->title); } + G_OBJECT_CLASS(diya_foreign_window_parent_class)->dispose(object); } -static void diya_window_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) +static void diya_foreign_window_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { - DiyaWindow * self = DIYA_WINDOW(object); + DiyaForeignWindow * self = DIYA_FOREIGN_WINDOW(object); switch (property_id) { case WIN_APP_ID: @@ -71,9 +70,6 @@ static void diya_window_set_property(GObject *object, guint property_id, const G case WIN_PARENT: self->parent_win = g_value_get_pointer(value); break; - case SHELL: - self->shell = g_value_get_pointer(value); - break; case WIN_STATE: self->state = g_value_get_uint(value); break; @@ -83,9 +79,9 @@ static void diya_window_set_property(GObject *object, guint property_id, const G } } -static void diya_window_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec) +static void diya_foreign_window_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { - DiyaWindow * self = DIYA_WINDOW(object); + DiyaForeignWindow * self = DIYA_FOREIGN_WINDOW(object); switch (property_id) { case WIN_APP_ID: @@ -100,9 +96,6 @@ static void diya_window_get_property(GObject *object, guint property_id, GValue case WIN_PARENT: g_value_set_pointer(value, self->parent_win); break; - case SHELL: - g_value_set_pointer(value, self->shell); - break; case WIN_STATE: g_value_set_uint(value, self->state); break; @@ -112,7 +105,7 @@ static void diya_window_get_property(GObject *object, guint property_id, GValue } } -static void diya_window_init(DiyaWindow *self) +static void diya_foreign_window_init(DiyaForeignWindow *self) { self->appid = NULL; //self->handle = NULL; @@ -120,32 +113,31 @@ static void diya_window_init(DiyaWindow *self) //self->shell = NULL; self->state = DIYA_WIN_STATE_NONE; self->title = NULL; + memset(self->string, 0, sizeof(self->string)); } -static const gchar* diya_window_to_string(DiyaObject* object) +static const gchar* diya_foreign_window_to_string(DiyaObject* object) { - DiyaWindow* self = DIYA_WINDOW(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_window_class_init(DiyaWindowClass *class) +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->finalize = diya_window_finalize; - gobject_class->set_property = diya_window_set_property; - gobject_class->get_property = diya_window_get_property; - base_class->to_string = diya_window_to_string; + 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); - win_properties[SHELL] = g_param_spec_pointer("shell", NULL, "Reference to shell", G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY ); - + 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); } @@ -165,7 +157,7 @@ static void toplevel_handle_title(void *data, { DiyaShell *shell = (DiyaShell *)data; assert(shell); - DiyaWindow *win = diya_shell_get_window(shell, handle); + 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)); @@ -176,7 +168,7 @@ static void toplevel_handle_app_id(void *data, { DiyaShell *shell = (DiyaShell *)data; assert(shell); - DiyaWindow *win = diya_shell_get_window(shell, handle); + 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)); @@ -196,7 +188,7 @@ static void toplevel_handle_state(void *data, uint32_t *entry; DiyaShell *shell = (DiyaShell *)data; assert(shell); - DiyaWindow *win = diya_shell_get_window(shell, handle); + 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) @@ -221,7 +213,7 @@ static void toplevel_handle_done(void *data, { DiyaShell *shell = (DiyaShell *)data; assert(shell); - DiyaWindow *win = diya_shell_get_window(shell, handle); + DiyaForeignWindow *win = diya_shell_get_window(shell, handle); assert(win); g_signal_emit_by_name(shell, "foreign-window-changed", (void *)win); } @@ -230,7 +222,7 @@ static void toplevel_handle_closed(void *data, { DiyaShell *shell = (DiyaShell *)data; assert(shell); - DiyaWindow *win = diya_shell_get_window(shell, handle); + 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); @@ -247,8 +239,8 @@ static void toplevel_handle_parent(void *data, assert(handle != parent); DiyaShell *shell = (DiyaShell *)data; assert(shell); - DiyaWindow *child_win = diya_shell_get_window(shell, handle); - DiyaWindow *parent_win = diya_shell_get_window(shell, parent); + 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); @@ -265,14 +257,24 @@ static const struct zwlr_foreign_toplevel_handle_v1_listener g_toplevel_impl = { .state = toplevel_handle_state, .done = toplevel_handle_done, .closed = toplevel_handle_closed, - .parent = toplevel_handle_parent}; + .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); - DiyaWindow *win = diya_shell_get_window(shell, tl); + DiyaForeignWindow *win = diya_shell_get_window(shell, tl); if (win) { @@ -280,14 +282,15 @@ static void toplevel_manager_handle_toplevel(void *data, struct zwlr_foreign_top return; } // TODO: different between windows - win = diya_window_new(shell, tl); + 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) { - (void) data; + DiyaShell *shell = (DiyaShell *)data; + diya_shell_remove_all_windows(shell); // remove table entry zwlr_foreign_toplevel_manager_v1_destroy(toplevel_manager); } @@ -302,12 +305,4 @@ void diya_shell_foreign_toplevel_register(struct wl_registry *registry, uint32_t { 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); -} - -DiyaWindow * diya_window_new(DiyaShell* shell, gpointer handle) -{ - DiyaWindow *win = DIYA_WINDOW(g_object_new(DIYA_TYPE_WINDOW,"shell", shell, "handle", handle, NULL)); - diya_shell_add_window(shell, win); - g_debug("Add new window 0x%" PRIXPTR, (uintptr_t)handle); - return win; } \ No newline at end of file diff --git a/src/launcher.c b/src/launcher.c index 40a7a60..3c9051b 100644 --- a/src/launcher.c +++ b/src/launcher.c @@ -1,5 +1,6 @@ #include "launcher.h" #include "foreign.h" +#include "session.h" #include #define NAMESPACE "launcher" @@ -11,7 +12,7 @@ static void on_launcher_destroy(GtkWindow *window, GApplication *_data) //g_application_quit (G_APPLICATION (gtk_window_get_application (window))); } -static void on_foreign_window_change(GtkApplication* app, DiyaWindow * win, gpointer data) +static void on_foreign_window_change(GtkApplication* app, DiyaForeignWindow * win, gpointer data) { (void) app; (void) data; @@ -19,7 +20,7 @@ static void on_foreign_window_change(GtkApplication* app, DiyaWindow * win, gpoi g_warning("WINDOW CHANGEEEEEEEEE %s", diya_object_to_string(DIYA_OBJECT(win))); } -static void on_foreign_window_removed(GtkApplication* app, DiyaWindow * win, gpointer data) +static void on_foreign_window_removed(GtkApplication* app, DiyaForeignWindow * win, gpointer data) { (void) app; (void) data; @@ -27,12 +28,21 @@ static void on_foreign_window_removed(GtkApplication* app, DiyaWindow * win, gpo g_warning("WINDOW removed %s", diya_object_to_string(DIYA_OBJECT(win))); } -void diya_launcher_init(DiyaShell * shell) +static void session_lock(GtkWidget *widget,gpointer data) +{ + g_warning("Enter session lock"); + diya_shell_lock(data); +} +void diya_shell_launcher_init(DiyaShell * shell) { assert(shell); - GtkWindow *gtk_window; - g_object_get(shell, "launchpad", >k_window, NULL); + GtkApplication * app; + g_object_get(shell, "application", &app, NULL); + assert(app); + GtkWindow *gtk_window = GTK_WINDOW (gtk_application_window_new (app)); assert(gtk_window); + g_object_set(shell, "launchpad", gtk_window, NULL); + g_signal_connect (gtk_window, "destroy", G_CALLBACK (on_launcher_destroy), NULL); // int layer shell for window gtk_layer_init_for_window (gtk_window); @@ -54,10 +64,14 @@ void diya_launcher_init(DiyaShell * shell) gtk_widget_set_name(GTK_WIDGET(gtk_window),NAMESPACE); gtk_window_set_default_size(gtk_window, 48, 48); - GtkWidget *box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5); + GtkWidget *box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5); gtk_box_set_homogeneous (GTK_BOX (box), TRUE); gtk_window_set_child (GTK_WINDOW (gtk_window), box); - + gtk_widget_set_halign (box, GTK_ALIGN_CENTER); + gtk_widget_set_valign (box, GTK_ALIGN_CENTER); + GtkWidget * button = gtk_button_new_with_label ("lock"); + g_signal_connect (button, "clicked", G_CALLBACK (session_lock), shell); + gtk_box_append (GTK_BOX (box), button); //g_signal_connect (gtk_window, "orientation-changed", G_CALLBACK (on_orientation_changed), /*data*/NULL); gtk_window_present (GTK_WINDOW (gtk_window)); diff --git a/src/launcher.h b/src/launcher.h index c7059f1..7452b15 100644 --- a/src/launcher.h +++ b/src/launcher.h @@ -4,6 +4,6 @@ #include "shell.h" -void diya_launcher_init(DiyaShell * shell); +void diya_shell_launcher_init(DiyaShell * shell); #endif \ No newline at end of file diff --git a/src/log.c b/src/log.c deleted file mode 100644 index e69de29..0000000 diff --git a/src/log.h b/src/log.h deleted file mode 100644 index e69de29..0000000 diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..693f58c --- /dev/null +++ b/src/main.c @@ -0,0 +1,72 @@ +#include +#include "shell.h" +#include "background.h" +#include "launcher.h" +#include "wayland.h" +#include "foreign.h" + +static gchar **g_shell_argv; + +static void activate(GtkApplication *app, void *data) +{ + (void)app; + (void)data; +} + +static gboolean restart(gpointer d) +{ + (void)d; + gint i, fdlimit; + + fdlimit = (int)sysconf(_SC_OPEN_MAX); + g_debug("reload: closing fd's %d to %d", STDERR_FILENO + 1, fdlimit); + for (i = STDERR_FILENO + 1; i < fdlimit; i++) + { + fcntl(i, F_SETFD, FD_CLOEXEC); + } + g_debug("reload: exec: %s", g_shell_argv[0]); + execvp(g_shell_argv[0], g_shell_argv); + exit(1); + return FALSE; +} + +static void startup(GtkApplication *app, void *data) +{ + DiyaShell *shell = data; + + diya_shell_launcher_init(shell); + diya_shell_wayland_init(shell); + diya_shell_init_background(shell); + + GtkCssProvider *provider = gtk_css_provider_new(); + const char *css = "#launcher {background-color: red;} #background {background-image:url(\"file:///etc/xdg/labwc/wpp.jpg\");background-size: cover;}"; + gtk_css_provider_load_from_string(provider, css); + gtk_style_context_add_provider_for_display( + gdk_display_get_default(), GTK_STYLE_PROVIDER(provider), GTK_STYLE_PROVIDER_PRIORITY_USER); + // g_signal_connect (win, "destroy", G_CALLBACK (before_destroy), provider); + g_object_unref(provider); + // CSS support + // set color for it + // g_timeout_add (100,(GSourceFunc )shell_timer,NULL); + g_unix_signal_add(SIGHUP, (GSourceFunc)restart, NULL); + g_unix_signal_add(SIGINT,(GSourceFunc)g_application_quit,(void*)app); +} + +int main(int argc, char *argv[]) +{ + g_shell_argv = g_malloc0(sizeof(gchar *) * (argc + 1)); + for (int i = 0; i < argc; i++) + { + g_shell_argv[i] = argv[i]; + } + GtkApplication *app = gtk_application_new("dev.iohub.diya.shell", G_APPLICATION_DEFAULT_FLAGS); + DiyaShell *shell = diya_shell_new(app); + g_signal_connect(app, "startup", G_CALLBACK(startup), (void *)shell); + g_signal_connect(app, "activate", G_CALLBACK(activate), (void *)shell); + // g_signal_connect(app, "shutdown", G_CALLBACK(shutdown), (void*)shell); + int status = g_application_run(G_APPLICATION(app), argc, argv); + g_warning("Exiting SHELL"); + g_object_unref(app); + g_object_unref(shell); + return status; +} diff --git a/src/session.c b/src/session.c new file mode 100644 index 0000000..2b23e6e --- /dev/null +++ b/src/session.c @@ -0,0 +1,332 @@ +#include +// #include +// #include +#include +#include +#include +#include +#include +#include +#include +#include "session.h" +#include "wayland.h" + +#define DEF_SURF_W 600 +#define DEF_SURF_H 400 + +struct _DiyaLockSession +{ + DiyaObject parent; + + struct ext_session_lock_v1 *session_lock; + struct ext_session_lock_v1_listener session_listener; + + struct ext_session_lock_surface_v1_listener surface_listener; + struct wl_callback_listener frame_listener; + struct wl_surface *wl_surface; + + struct wl_buffer *wl_buffer; + void * raw_shared_buffer; + guint32 raw_shared_buffer_size; + cairo_surface_t *cairo_surface; + + guint surface_width; + guint surface_height; + + guint32 last_frame_time; + + guint hold; +}; + +G_DEFINE_FINAL_TYPE(DiyaLockSession, diya_lock_session, DIYA_TYPE_SHELL_OBJECT) +static struct ext_session_lock_manager_v1 *g_session_lock_manager; +static const cairo_user_data_key_t shm_surface_data_key; + +static void diya_lock_session_dispose(GObject *object) +{ + DiyaLockSession *self = DIYA_LOCK_SESSION(object); + g_debug("diya_lock_session_dispose: %s", diya_object_to_string(self)); + if (self->session_lock && !self->hold) + { + ext_session_lock_v1_unlock_and_destroy(self->session_lock); + } + else + { + g_warning("diya_lock_session_dispose: the lock session is disposed but the lock has not been released"); + } + if (self->cairo_surface) + { + cairo_surface_destroy(self->cairo_surface); + self->cairo_surface = NULL; + } + G_OBJECT_CLASS(diya_lock_session_parent_class)->dispose(object); +} + +static void handle_session_locked(void *data, struct ext_session_lock_v1 *lock) +{ + (void) lock; + DiyaShell *shell; + GtkApplication *app; + DiyaWayland *wayland; + DiyaLockSession *self = data; + g_object_get(self, "shell", &shell, NULL); + assert(shell); + g_object_get(shell, "application", &app, "wayland", &wayland, NULL); + assert(app); + assert(DIYA_IS_WAYLAND(wayland)); + g_debug("Session locked on shell: %s", diya_object_to_string(shell)); + + struct wl_surface *surface = diya_wayland_create_surface(wayland); + struct wl_output *output = diya_wayland_get_output(wayland, 0); + assert(output); + self->wl_surface = surface; + struct ext_session_lock_surface_v1 *lock_surface = ext_session_lock_v1_get_lock_surface(self->session_lock, surface, output); + ext_session_lock_surface_v1_add_listener(lock_surface, &self->surface_listener, data); + struct wl_callback *cb = wl_surface_frame(self->wl_surface); + wl_callback_add_listener(cb, &self->frame_listener, data); +} +static void handle_session_lock_finished(void *data, struct ext_session_lock_v1 *lock) +{ + DiyaShell *shell; + g_object_get(data, "shell", &shell, NULL); + assert(shell); + ext_session_lock_v1_destroy(lock); + g_warning("Session locked finished on shell %s", diya_object_to_string(shell)); +} +static void randname(char *buf) +{ + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + long r = ts.tv_nsec; + for (int i = 0; i < 6; ++i) + { + buf[i] = 'A' + (r & 15) + (r & 16) * 2; + r >>= 5; + } +} +static int create_shm_file(void) +{ + int retries = 100; + do + { + char name[] = "/diya_shell_wl_shm-XXXXXX"; + randname(name + sizeof(name) - 7); + --retries; + int fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600); + if (fd >= 0) + { + shm_unlink(name); + return fd; + } + } while (retries > 0 && errno == EEXIST); + return -1; +} + +static int allocate_shm_file(size_t size) +{ + int fd = create_shm_file(); + if (fd < 0) + { + g_error("allocate_shm_file: unable to create_shm_file: %s", strerror(errno)); + return -1; + } + int ret; + do + { + ret = ftruncate(fd, size); + } while (ret < 0 && errno == EINTR); + if (ret < 0) + { + g_error("allocate_shm_file: unable to ftruncate: %s", strerror(errno)); + close(fd); + return -1; + } + return fd; +} + +static void session_lock_free_surface(void *data) +{ + DiyaLockSession * self = data; + assert(DIYA_IS_LOCK_SESSION(self)); + if (self->wl_buffer) + { + g_debug("Destroy share buffer wl_buffer"); + wl_buffer_destroy(self->wl_buffer); + self->wl_buffer = NULL; + } + if(self->raw_shared_buffer) + { + g_debug("unmapped shared buffer of %d bytes", self->raw_shared_buffer_size); + munmap(self->raw_shared_buffer, self->raw_shared_buffer_size); + self->raw_shared_buffer = NULL; + self->raw_shared_buffer_size = 0; + } +} + +static void session_lock_realloc_surface(DiyaLockSession *self) +{ + DiyaShell *shell; + g_object_get(self, "shell", &shell, NULL); + assert(DIYA_IS_SHELL(shell)); + DiyaWayland *wayland = diya_shell_get_wayland(shell); + assert(DIYA_IS_WAYLAND(wayland)); + if (self->cairo_surface) + { + cairo_surface_destroy(self->cairo_surface); + self->cairo_surface = NULL; + } + int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, self->surface_width); + int size = stride * self->surface_height; + + int fd = allocate_shm_file(size); + if (fd == -1) + { + g_error("session_lock_realloc_surface: unable to allocate_shm_file"); + return; + } + void *data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (data == MAP_FAILED) + { + g_error("session_lock_realloc_surface: unable to mmap: %s", strerror(errno)); + close(fd); + return; + } + self->cairo_surface = cairo_image_surface_create_for_data(data, + CAIRO_FORMAT_ARGB32, + self->surface_width, + self->surface_height, + stride); + cairo_surface_set_user_data(self->cairo_surface, &shm_surface_data_key, self, session_lock_free_surface); + + struct wl_shm_pool *pool = diya_wayland_create_shm_pool(wayland, fd, size); + self->wl_buffer = wl_shm_pool_create_buffer(pool, 0, + self->surface_width, self->surface_height, stride, WL_SHM_FORMAT_XRGB8888); + wl_shm_pool_destroy(pool); + close(fd); + + self->raw_shared_buffer = data; + self->raw_shared_buffer_size = size; +} + +static void lock_session_draw_frame(DiyaLockSession *self) +{ + if(!self->cairo_surface) + { + return; + } + cairo_t *cr = cairo_create(self->cairo_surface); + // Start of example + double xc = 128.0; + double yc = 128.0; + double radius = 100.0; + double angle1 = (double)(self->last_frame_time % 180) * (M_PI / 180.0); /* angles are specified */ + double angle2 = 180.0 * (M_PI / 180.0); /* in radians */ + + cairo_set_line_width(cr, 10.0); + cairo_arc(cr, xc, yc, radius, angle1, angle2); + cairo_stroke(cr); + + /* draw helping lines */ + cairo_set_source_rgba(cr, 1, 0.2, 0.2, 0.6); + cairo_set_line_width(cr, 6.0); + + cairo_arc(cr, xc, yc, 10.0, 0, 2 * M_PI); + cairo_fill(cr); + + cairo_arc(cr, xc, yc, radius, angle1, angle1); + cairo_line_to(cr, xc, yc); + cairo_arc(cr, xc, yc, radius, angle2, angle2); + cairo_line_to(cr, xc, yc); + cairo_stroke(cr); + // End of example + cairo_destroy(cr); + + wl_surface_attach(self->wl_surface, self->wl_buffer, 0, 0); + wl_surface_damage_buffer(self->wl_surface, 0, 0, self->surface_width, self->surface_height); + wl_surface_commit(self->wl_surface); +} + +static void lock_surface_configure(void *data, + struct ext_session_lock_surface_v1 *lock_surface, + uint32_t serial, uint32_t width, uint32_t height) +{ + DiyaLockSession *self = data; + assert(DIYA_IS_LOCK_SESSION(self)); + if (!self->wl_buffer || self->surface_width != width || self->surface_height != height) + { + self->surface_width = width; + self->surface_height = height; + session_lock_realloc_surface(self); + } + ext_session_lock_surface_v1_ack_configure(lock_surface, serial); + + lock_session_draw_frame(self); +} + + +static void lock_surface_frame_done(void *data, struct wl_callback *cb, uint32_t time) +{ + /* Destroy this callback */ + wl_callback_destroy(cb); + DiyaLockSession *lock = data; + assert(DIYA_IS_LOCK_SESSION(lock)); + cb = wl_surface_frame(lock->wl_surface); + wl_callback_add_listener(cb, &lock->frame_listener, data); + + if (!lock->cairo_surface || !lock->wl_buffer) + { + return; + } + lock->last_frame_time = time; + lock_session_draw_frame(lock); +} + +static void diya_lock_session_init(DiyaLockSession *self) +{ + self->session_lock = ext_session_lock_manager_v1_lock(g_session_lock_manager); + self->session_listener.locked = handle_session_locked; + self->session_listener.finished = handle_session_lock_finished; + + self->surface_listener.configure = lock_surface_configure; + ext_session_lock_v1_add_listener(self->session_lock, &self->session_listener, self); + + self->frame_listener.done = lock_surface_frame_done; + + self->surface_width = DEF_SURF_W; + self->surface_height = DEF_SURF_H; + self->hold = true; + self->last_frame_time = 0; + + self->wl_surface = NULL; + self->wl_buffer = NULL; + + self->cairo_surface = NULL; + self->raw_shared_buffer = NULL; + self->raw_shared_buffer_size = 0; +} +static const gchar *diya_lock_session_to_string(DiyaObject *object) +{ + (void)object; + // DiyaLockSession* self = DIYA_LOCK_SESSION(object); + return "DIYA SHELL LOCK SESSION"; +} + +static void diya_lock_session_class_init(DiyaLockSessionClass *class) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS(class); + DiyaObjectClass *base_class = DIYA_OBJECT_CLASS(class); + + gobject_class->dispose = diya_lock_session_dispose; + + base_class->to_string = diya_lock_session_to_string; +} + +void diya_shell_session_lock_register(struct wl_registry *registry, uint32_t name) +{ + g_session_lock_manager = wl_registry_bind(registry, name, &ext_session_lock_manager_v1_interface, 1); +} + +void diya_shell_session_lock_release(DiyaLockSession *self) +{ + self->hold = false; +} \ No newline at end of file diff --git a/src/session.h b/src/session.h new file mode 100644 index 0000000..dd5719b --- /dev/null +++ b/src/session.h @@ -0,0 +1,9 @@ +#ifndef DIYA_SESSION_H +#define DIYA_SESSION_H + +#include "ext-session-lock-v1.h" +#include "shell.h" + +void diya_shell_session_lock_register(struct wl_registry *registry, uint32_t name); +void diya_shell_session_lock_release(DiyaLockSession * self); +#endif \ No newline at end of file diff --git a/src/shell.c b/src/shell.c index a04ec0c..3598a82 100644 --- a/src/shell.c +++ b/src/shell.c @@ -1,9 +1,7 @@ #include -#include "background.h" -#include "launcher.h" -#include "wayland.h" #include "foreign.h" +#include "session.h" #define SHELL_DESCRIPTION "Diya GTK shell for wayland (diyac)" @@ -14,6 +12,7 @@ enum SHELL_BACKGROUND_WIDGET, SHELL_LAUNCHPAD_WIDGET, SHELL_WINDOWS, + SHELL_WAYLAND, N_PROPERTIES }; @@ -26,16 +25,25 @@ struct _DiyaShell GtkWindow* background; GtkWindow* launcher; GHashTable* windows; + DiyaLockSession* lock; + DiyaWayland * wayland; }; -G_DEFINE_TYPE(DiyaShell, diya_shell, DIYA_TYPE_OBJECT) +G_DEFINE_FINAL_TYPE(DiyaShell, diya_shell, DIYA_TYPE_OBJECT) -static void diya_shell_finalize(GObject* object) +static void diya_shell_dispose(GObject* object) { DiyaShell * self = DIYA_SHELL(object); g_hash_table_destroy(self->windows); - // TODO: free element in each entry of the table - // g_object_unref(self->app); - g_warning("diya_shell_finalize"); + g_debug("diya_shell_dispose"); + if(self->wayland) + { + g_object_unref(self->wayland); + } + if(self->lock) + { + g_object_unref(self->lock); + } + G_OBJECT_CLASS(diya_shell_parent_class)->dispose(object); } static void diya_shell_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) @@ -46,11 +54,16 @@ static void diya_shell_set_property(GObject *object, guint property_id, const GV case SHELL_APP: self->app = g_value_get_pointer(value); assert(self->app); - self->background = GTK_WINDOW (gtk_application_window_new (self->app)); - self->launcher = GTK_WINDOW (gtk_application_window_new (self->app)); break; case SHELL_BACKGROUND_WIDGET: + self->background = g_value_get_pointer(value); + break; case SHELL_LAUNCHPAD_WIDGET: + self->launcher = g_value_get_pointer(value); + break; + case SHELL_WAYLAND: + self->wayland = g_value_get_pointer(value); + break; case SHELL_WINDOWS: //self->windows = g_value_get_pointer(value); break; @@ -75,6 +88,9 @@ static void diya_shell_get_property(GObject *object, guint property_id, GValue * assert(self->launcher); g_value_set_pointer(value, self->launcher); break; + case SHELL_WAYLAND: + g_value_set_pointer(value, self->wayland); + break; case SHELL_WINDOWS: g_value_set_pointer(value, self->windows); break; @@ -96,14 +112,16 @@ static void diya_shell_class_init(DiyaShellClass *class) DiyaObjectClass *base_class = DIYA_OBJECT_CLASS(class); base_class->to_string = diya_shell_to_string; - gobject_class->finalize = diya_shell_finalize; + gobject_class->dispose = diya_shell_dispose; gobject_class->set_property = diya_shell_set_property; gobject_class->get_property = diya_shell_get_property; shell_properties[SHELL_APP] = g_param_spec_pointer("application", NULL, "Shell application", G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); - shell_properties[SHELL_BACKGROUND_WIDGET] = g_param_spec_pointer("background", NULL, "Shell background widget", G_PARAM_READABLE ); - shell_properties[SHELL_LAUNCHPAD_WIDGET] = g_param_spec_pointer("launchpad", NULL, "Shell launchpad", G_PARAM_READABLE ); + shell_properties[SHELL_BACKGROUND_WIDGET] = g_param_spec_pointer("background", NULL, "Shell background widget", G_PARAM_READWRITE ); + shell_properties[SHELL_LAUNCHPAD_WIDGET] = g_param_spec_pointer("launchpad", NULL, "Shell launchpad", G_PARAM_READWRITE ); shell_properties[SHELL_WINDOWS] = g_param_spec_pointer("windows", NULL, "Shell foreign windows", G_PARAM_READABLE); + shell_properties[SHELL_WAYLAND] = g_param_spec_pointer("wayland", NULL, "Shell wayland", G_PARAM_READWRITE ); + g_object_class_install_properties (gobject_class, N_PROPERTIES, shell_properties); g_signal_new("foreign-window-changed", @@ -137,14 +155,15 @@ static void diya_shell_init(DiyaShell *self) //self->app = NULL; self->background = NULL; self->launcher = NULL; + self->wayland = NULL; self->windows = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_object_unref); } -gpointer diya_shell_get_window(DiyaShell * shell, gpointer handle) +DiyaForeignWindow* diya_shell_get_window(DiyaShell * shell, gpointer handle) { return g_hash_table_lookup(shell->windows, handle); } -gboolean diya_shell_add_window(DiyaShell * shell, DiyaWindow * win) +gboolean diya_shell_add_window(DiyaShell * shell, DiyaForeignWindow * win) { gpointer handle; g_object_get(win, "handle", &handle, NULL); @@ -152,7 +171,7 @@ gboolean diya_shell_add_window(DiyaShell * shell, DiyaWindow * win) return g_hash_table_insert(shell->windows,handle, win); } -gboolean diya_shell_remove_window(DiyaShell * shell, DiyaWindow * win) +gboolean diya_shell_remove_window(DiyaShell * shell, DiyaForeignWindow * win) { gpointer handle; g_object_get(win, "handle", &handle, NULL); @@ -160,10 +179,39 @@ gboolean diya_shell_remove_window(DiyaShell * shell, DiyaWindow * win) return g_hash_table_remove(shell->windows,handle); } +void diya_shell_remove_all_windows(DiyaShell * shell) +{ + g_hash_table_destroy(shell->windows); + shell->windows = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_object_unref); +} + DiyaShell * diya_shell_new(GtkApplication * app) { return DIYA_SHELL(g_object_new(DIYA_TYPE_SHELL,"application",app, NULL)); } + +void diya_shell_lock(DiyaShell* shell) +{ + if(shell->lock) + { + g_warning("Shell session is already locked, doing nothing"); + return; + } + shell->lock = g_object_new(DIYA_TYPE_LOCK_SESSION, "shell", shell, NULL); +} +void diya_shell_unlock(DiyaShell* shell) +{ + diya_shell_session_lock_release(shell->lock); + g_object_unref(shell->lock); + shell->lock = NULL; +} +DiyaWayland * diya_shell_get_wayland(DiyaShell* shell) +{ + DiyaWayland * wayland; + g_object_get(shell,"wayland", &wayland, NULL); + assert(DIYA_IS_WAYLAND(wayland)); + return wayland; +} /* static void on_orientation_changed (GtkWindow *window, WindowOrientation orientation, ToplevelData *data) { @@ -192,39 +240,10 @@ static void on_orientation_changed (GtkWindow *window, WindowOrientation orienta //gtk_window_resize (window, 1, 1); // force the window to shrink to the smallest size it can } */ -static void shutdown(GtkApplication *app, void *data) -{ - (void) app; - g_warning("Application shutdown"); - DiyaShell * shell = data; - assert(shell); - g_object_unref(shell); -} -static void activate(GtkApplication *app, void *data) -{ - (void)data; - DiyaShell * shell = diya_shell_new(app); - assert(shell); - assert(DIYA_IS_SHELL(shell)); - g_signal_connect(app, "shutdown", G_CALLBACK(shutdown), (void*)shell); - diya_launcher_init(shell); - diya_shell_wayland_init(shell); - diya_shell_init_background(shell); - // CSS support - // set color for it - GtkCssProvider *provider = gtk_css_provider_new(); - const char *css = "#launcher {background-color: red;} #background {background-image:url(\"file:///etc/xdg/labwc/wpp.jpg\");background-size: cover;}"; - gtk_css_provider_load_from_string(provider, css); - gtk_style_context_add_provider_for_display( - gdk_display_get_default(), GTK_STYLE_PROVIDER(provider), GTK_STYLE_PROVIDER_PRIORITY_USER); -} - -int main(int argc, char *argv[]) -{ - GtkApplication* app = gtk_application_new("dev.iohub.diya-shell", G_APPLICATION_DEFAULT_FLAGS); - g_signal_connect(app, "activate", G_CALLBACK(activate), NULL); - int status = g_application_run(G_APPLICATION(app), argc, argv); - g_object_unref(app); - return status; +/* +static void before_destroy (GtkWidget *win, GtkCssProvider *provider) { + GdkDisplay *display = gdk_display_get_default (); + gtk_style_context_remove_provider_for_display (display, GTK_STYLE_PROVIDER (provider)); } +*/ diff --git a/src/shell.h b/src/shell.h index 1ba6234..9570a0b 100644 --- a/src/shell.h +++ b/src/shell.h @@ -15,13 +15,24 @@ enum diya_win_state #define DIYA_TYPE_SHELL (diya_shell_get_type ()) G_DECLARE_FINAL_TYPE (DiyaShell, diya_shell, DIYA, SHELL, DiyaObject) -#define DIYA_TYPE_WINDOW (diya_window_get_type ()) -G_DECLARE_FINAL_TYPE (DiyaWindow, diya_window, DIYA, WINDOW, DiyaObject) +#define DIYA_TYPE_WAYLAND (diya_wayland_get_type ()) +G_DECLARE_FINAL_TYPE (DiyaWayland, diya_wayland, DIYA, WAYLAND, DiyaShellObject) + +#define DIYA_TYPE_FOREIGN_WINDOW (diya_foreign_window_get_type ()) +G_DECLARE_FINAL_TYPE (DiyaForeignWindow, diya_foreign_window, DIYA, FOREIGN_WINDOW, DiyaShellObject) + +#define DIYA_TYPE_LOCK_SESSION (diya_lock_session_get_type ()) +G_DECLARE_FINAL_TYPE (DiyaLockSession, diya_lock_session, DIYA, LOCK_SESSION, DiyaShellObject) + + +DiyaForeignWindow* diya_shell_get_window(DiyaShell * shell, gpointer handle); +gboolean diya_shell_add_window(DiyaShell * shell, DiyaForeignWindow * win); +gboolean diya_shell_remove_window(DiyaShell * shell, DiyaForeignWindow * win); +void diya_shell_remove_all_windows(DiyaShell * shell); + +void diya_shell_lock(DiyaShell* shell); +void diya_shell_unlock(DiyaShell* shell); -gpointer diya_shell_get_window(DiyaShell * shell, gpointer handle); -gboolean diya_shell_add_window(DiyaShell * shell, DiyaWindow * win); -gboolean diya_shell_remove_window(DiyaShell * shell, DiyaWindow * win); DiyaShell * diya_shell_new(GtkApplication * app); - -DiyaWindow * diya_window_new(DiyaShell* shell, gpointer handle); +DiyaWayland * diya_shell_get_wayland(DiyaShell* shell); #endif \ No newline at end of file diff --git a/src/wayland.c b/src/wayland.c index 58dc171..c70f640 100644 --- a/src/wayland.c +++ b/src/wayland.c @@ -1,7 +1,44 @@ #include #include +#include #include "wayland.h" #include "foreign.h" +#include "session.h" + + +struct _DiyaWayland +{ + DiyaObject parent; + struct wl_compositor * compositor; + struct wl_shm * shm; +}; +G_DEFINE_FINAL_TYPE(DiyaWayland, diya_wayland, DIYA_TYPE_SHELL_OBJECT) + +static void diya_wayland_dispose(GObject* object) +{ + (void) object; + //DiyaWayland * self = DIYA_WAYLAND(object); + g_debug("diya_wayland_dispose"); + G_OBJECT_CLASS(diya_wayland_parent_class)->dispose(object); +} + +static void diya_wayland_init(DiyaWayland * self) +{ + self->compositor = NULL; + self->shm = NULL; +} + +static void diya_wayland_class_init(DiyaWaylandClass *class) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS(class); + //DiyaObjectClass *base_class = DIYA_OBJECT_CLASS(class); + + gobject_class->dispose = diya_wayland_dispose; + //gobject_class->set_property = diya_lock_session_set_property; + //gobject_class->get_property = diya_lock_session_get_property; + //base_class->to_string = diya_lock_session_to_string; +} + static void handle_global(void *data, struct wl_registry *registry, uint32_t name, const gchar *interface, uint32_t version) { @@ -14,14 +51,28 @@ static void handle_global(void *data, struct wl_registry *registry, uint32_t nam if (!g_strcmp0(interface,zwlr_foreign_toplevel_manager_v1_interface.name)) foreign_toplevel_register(registry,name); */ - //g_warning("register global: %s VS %s", interface, zwlr_foreign_toplevel_manager_v1_interface.name); (void) version; + DiyaShell * shell = data; + DiyaWayland * wayland; + g_object_get(shell, "wayland", &wayland, NULL); + assert(DIYA_IS_WAYLAND(wayland)); + g_warning("GLOBAL: %s", interface); if (!g_strcmp0(interface, zwlr_foreign_toplevel_manager_v1_interface.name)) { - g_warning("register global: %s", interface); diya_shell_foreign_toplevel_register(registry, name, data); } - + else if(!g_strcmp0(interface, ext_session_lock_manager_v1_interface.name)) + { + diya_shell_session_lock_register(registry, name); + } + else if (strcmp(interface, wl_compositor_interface.name) == 0) + { + wayland->compositor = wl_registry_bind(registry, name, &wl_compositor_interface, 4); + } + else if (strcmp(interface, wl_shm_interface.name) == 0) + { + wayland->shm = wl_registry_bind(registry, name, &wl_shm_interface, 1); + } } static void handle_global_remove(void *data, struct wl_registry *registry, @@ -32,7 +83,8 @@ static void handle_global_remove(void *data, struct wl_registry *registry, (void) name; } -static const struct wl_registry_listener registry_listener = { +static const struct wl_registry_listener registry_listener = +{ .global = handle_global, .global_remove = handle_global_remove }; @@ -43,8 +95,13 @@ void diya_shell_wayland_init(DiyaShell *shell) struct wl_registry *registry; display = gdk_wayland_display_get_wl_display(gdk_display_get_default()); if (!display) - g_error("Can't get wayland display\n"); - + { + g_error("Can't get wayland display"); + return; + } + DiyaWayland * wayland = g_object_new(DIYA_TYPE_WAYLAND, "shell", shell, NULL); + g_object_set(shell, "wayland", wayland, NULL); + //g_object_set(wayland, "shell", shell, NULL); registry = wl_display_get_registry(display); wl_registry_add_listener(registry, ®istry_listener, (void*)shell); wl_display_roundtrip(display); @@ -55,3 +112,33 @@ void diya_shell_wayland_init(DiyaShell *shell) // wl_display_roundtrip(display); // wl_display_roundtrip(display); } + +struct wl_surface* diya_wayland_create_surface(DiyaWayland * self) +{ + assert(self->compositor); + struct wl_surface* surface = wl_compositor_create_surface(self->compositor); + assert(surface); + return surface; +} + +struct wl_output* diya_wayland_get_output(DiyaWayland * self, int index) +{ + (void) self; + /** + * TODO: listen to wl_ouput interface instead of using gdk + */ + GListModel * list = gdk_display_get_monitors(gdk_display_get_default()); + GdkMonitor * monitor = g_list_model_get_item(list,index); + if(! monitor) + { + return NULL; + } + struct wl_output * output = gdk_wayland_monitor_get_wl_output(monitor); + assert(output); + return output; +} +struct wl_shm_pool * diya_wayland_create_shm_pool(DiyaWayland * self, int fd, guint size) +{ + assert(self->shm); + return wl_shm_create_pool(self->shm, fd, size); +} diff --git a/src/wayland.h b/src/wayland.h index 7e46cf6..8cf547f 100644 --- a/src/wayland.h +++ b/src/wayland.h @@ -4,5 +4,7 @@ #include "shell.h" void diya_shell_wayland_init(DiyaShell *shell); - +struct wl_surface* diya_wayland_create_surface(DiyaWayland * self); +struct wl_output* diya_wayland_get_output(DiyaWayland * self, int index); +struct wl_shm_pool * diya_wayland_create_shm_pool(DiyaWayland * self, int fd, guint size); #endif \ No newline at end of file diff --git a/src/widgets/cairo-widget.c b/src/widgets/cairo-widget.c new file mode 100644 index 0000000..282b71e --- /dev/null +++ b/src/widgets/cairo-widget.c @@ -0,0 +1,110 @@ +#include +#include +#include +#include "cairo-widget.h" + +enum +{ + CW_NO_PROP, + CW_EXTENT, + CW_PARENT, + CW_N_PROPERTIES +}; +static GParamSpec *g_cw_prop[CW_N_PROPERTIES] = {0}; + +typedef struct _DiyaCairoWidgetPrivate +{ + DiyaObject * parent_object; + diya_rect_t extent; + DiyaCairoWidget * parent_widget; + // TODO list of children + gchar string[64]; +} DiyaCairoWidgetPrivate; + +G_DEFINE_TYPE_WITH_PRIVATE(DiyaCairoWidget, diya_cairo_widget, DIYA_TYPE_OBJECT); + + +static void diya_cairo_widget_dispose(GObject* object) +{ + g_debug("diya_cairo_widget_dispose"); + G_OBJECT_CLASS(diya_cairo_widget_parent_class)->dispose(object); +} + +static void diya_cairo_widget_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) +{ + DiyaCairoWidget * self = DIYA_CAIRO_WIDGET(object); + DiyaCairoWidgetPrivate* priv = diya_cairo_widget_get_instance_private(self); + diya_rect_t * rect; + switch (property_id) + { + case CW_PARENT: + priv->parent_widget = g_value_get_pointer(value); + break; + case CW_EXTENT: + rect = g_value_get_pointer(value); + assert(rect); + memcpy(&priv->extent,rect, sizeof(priv->extent)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void diya_cairo_widget_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec) +{ + DiyaCairoWidget * self = DIYA_CAIRO_WIDGET(object); + DiyaCairoWidgetPrivate* priv = diya_cairo_widget_get_instance_private(self); + switch (property_id) + { + case CW_PARENT: + g_value_set_pointer(value, priv->parent_widget); + break; + case CW_EXTENT: + g_value_set_pointer(value, &priv->extent); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + + +static void diya_cairo_widget_init(DiyaCairoWidget *self) +{ + DiyaCairoWidgetPrivate* priv = diya_cairo_widget_get_instance_private(self); + memset(&priv->extent,0,sizeof(priv->extent)); + priv->parent_widget = NULL; + priv->string[0] = '\0'; +} + +static const gchar *diya_cairo_widget_to_string(DiyaObject *object) +{ + DiyaCairoWidget * self = DIYA_CAIRO_WIDGET(object); + DiyaCairoWidgetClass *class = DIYA_CAIRO_WIDGET_GET_CLASS(object); + DiyaCairoWidgetPrivate* priv = diya_cairo_widget_get_instance_private(self); + + g_snprintf(priv->string,sizeof(priv->string), + "%s (%dx%d) at %d@%d", + class->name, + priv->extent.x, priv->extent.y, + priv->extent.width, priv->extent.height + ); + return priv->string; +} + +static void diya_cairo_widget_class_init(DiyaCairoWidgetClass *class) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS(class); + DiyaObjectClass *base_class = DIYA_OBJECT_CLASS(class); + DIYA_CAIRO_WIDGET_SET_NAME(class, ""); + gobject_class->dispose = diya_cairo_widget_dispose; + gobject_class->set_property = diya_cairo_widget_set_property; + gobject_class->get_property = diya_cairo_widget_get_property; + g_cw_prop[CW_EXTENT] = g_param_spec_pointer("extent", NULL, "Widget extent relative to its parent", G_PARAM_READWRITE); // + g_cw_prop[CW_PARENT] = g_param_spec_pointer("parent", NULL, "Parent widget", G_PARAM_READWRITE); // + + base_class->to_string = diya_cairo_widget_to_string; + + g_object_class_install_properties (gobject_class, CW_N_PROPERTIES, g_cw_prop); +} diff --git a/src/widgets/cairo-widget.h b/src/widgets/cairo-widget.h new file mode 100644 index 0000000..e6a0138 --- /dev/null +++ b/src/widgets/cairo-widget.h @@ -0,0 +1,20 @@ +#ifndef CAIRO_WIDGET_H +#define CAIRO_WIDGET_H + +#include "../base.h" + +#define DIYA_CAIRO_WIDGET_SET_NAME(c, n) (DIYA_CAIRO_WIDGET_CLASS(c)->name = n) + +#define DIYA_TYPE_CAIRO_WIDGET (diya_cairo_widget_get_type ()) +G_DECLARE_DERIVABLE_TYPE (DiyaCairoWidget, diya_cairo_widget, DIYA, CAIRO_WIDGET, DiyaObject) + +struct _DiyaCairoWidgetClass +{ + DiyaObjectClass parent_class; + const gchar* name; + /** + * @brief TODO define more API function + * + */ +}; +#endif \ No newline at end of file