Initial commit: add code
- using meson build - implement shell using gobject API - support wlr-foreign-toplevel protocol - shell base UI (WIP)
This commit is contained in:
parent
e9ef315aa4
commit
ac300c32cf
3
.gitignore
vendored
3
.gitignore
vendored
@ -85,4 +85,5 @@ dkms.conf
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
|
||||
build
|
||||
.vscode
|
59
meson.build
Normal file
59
meson.build
Normal file
@ -0,0 +1,59 @@
|
||||
project('diya-shell',
|
||||
['c'],
|
||||
version: '0.1.0',
|
||||
license: 'MIT',
|
||||
meson_version: '>=0.51.0',
|
||||
default_options: ['c_std=gnu11', 'warning_level=3'])
|
||||
|
||||
lib_so_version = '0'
|
||||
|
||||
add_project_arguments(
|
||||
[
|
||||
'-Wno-pedantic',
|
||||
'-Werror=implicit-function-declaration',
|
||||
'-Werror=return-type',
|
||||
],
|
||||
language: 'c')
|
||||
|
||||
gtk = dependency('gtk4')
|
||||
wayland_client = dependency('wayland-client', version: '>=1.10.0')
|
||||
|
||||
# wayland_scanner is required, but we can find it without pkg-config
|
||||
wayland_scanner = find_program('wayland-scanner')
|
||||
|
||||
# use system xdg-shell protocol when available
|
||||
#wayland_protocols = dependency('wayland-protocols', version: '>=1.16')
|
||||
|
||||
# pkg_config = import('pkgconfig')
|
||||
# gnome = import('gnome')
|
||||
|
||||
gtk_layer_shell = dependency('gtk4-layer-shell-0', version: '>=1.0.2')
|
||||
wayland_targets=[]
|
||||
|
||||
wayland_protos = [
|
||||
'protocols/wlr-foreign-toplevel-management-unstable-v1'
|
||||
]
|
||||
|
||||
foreach proto : wayland_protos
|
||||
xml = ''.join([proto,'.xml'])
|
||||
header = ''.join([proto.split('/').get(-1),'.h'])
|
||||
cfile = ''.join([proto.split('/').get(-1),'.c'])
|
||||
wayland_targets += custom_target(header,output:header,input:xml,
|
||||
command: [ wayland_scanner, 'client-header', '@INPUT@', '@OUTPUT@' ] )
|
||||
wayland_targets += custom_target(cfile,output:cfile,input:xml,
|
||||
command: [ wayland_scanner, 'public-code', '@INPUT@', '@OUTPUT@' ] )
|
||||
endforeach
|
||||
|
||||
src = [
|
||||
'src/base.c',
|
||||
'src/launcher.c',
|
||||
'src/background.c',
|
||||
'src/wayland.c',
|
||||
'src/shell.c',
|
||||
'src/foreign.c',
|
||||
wayland_targets]
|
||||
|
||||
executable(
|
||||
'diya-shell',
|
||||
src,
|
||||
dependencies: [gtk, gtk_layer_shell, wayland_client])
|
270
protocols/wlr-foreign-toplevel-management-unstable-v1.xml
Normal file
270
protocols/wlr-foreign-toplevel-management-unstable-v1.xml
Normal file
@ -0,0 +1,270 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<protocol name="wlr_foreign_toplevel_management_unstable_v1">
|
||||
<copyright>
|
||||
Copyright © 2018 Ilia Bozhinov
|
||||
|
||||
Permission to use, copy, modify, distribute, and sell this
|
||||
software and its documentation for any purpose is hereby granted
|
||||
without fee, provided that the above copyright notice appear in
|
||||
all copies and that both that copyright notice and this permission
|
||||
notice appear in supporting documentation, and that the name of
|
||||
the copyright holders not be used in advertising or publicity
|
||||
pertaining to distribution of the software without specific,
|
||||
written prior permission. The copyright holders make no
|
||||
representations about the suitability of this software for any
|
||||
purpose. It is provided "as is" without express or implied
|
||||
warranty.
|
||||
|
||||
THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
|
||||
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
|
||||
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
||||
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
||||
THIS SOFTWARE.
|
||||
</copyright>
|
||||
|
||||
<interface name="zwlr_foreign_toplevel_manager_v1" version="3">
|
||||
<description summary="list and control opened apps">
|
||||
The purpose of this protocol is to enable the creation of taskbars
|
||||
and docks by providing them with a list of opened applications and
|
||||
letting them request certain actions on them, like maximizing, etc.
|
||||
|
||||
After a client binds the zwlr_foreign_toplevel_manager_v1, each opened
|
||||
toplevel window will be sent via the toplevel event
|
||||
</description>
|
||||
|
||||
<event name="toplevel">
|
||||
<description summary="a toplevel has been created">
|
||||
This event is emitted whenever a new toplevel window is created. It
|
||||
is emitted for all toplevels, regardless of the app that has created
|
||||
them.
|
||||
|
||||
All initial details of the toplevel(title, app_id, states, etc.) will
|
||||
be sent immediately after this event via the corresponding events in
|
||||
zwlr_foreign_toplevel_handle_v1.
|
||||
</description>
|
||||
<arg name="toplevel" type="new_id" interface="zwlr_foreign_toplevel_handle_v1"/>
|
||||
</event>
|
||||
|
||||
<request name="stop">
|
||||
<description summary="stop sending events">
|
||||
Indicates the client no longer wishes to receive events for new toplevels.
|
||||
However the compositor may emit further toplevel_created events, until
|
||||
the finished event is emitted.
|
||||
|
||||
The client must not send any more requests after this one.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<event name="finished">
|
||||
<description summary="the compositor has finished with the toplevel manager">
|
||||
This event indicates that the compositor is done sending events to the
|
||||
zwlr_foreign_toplevel_manager_v1. The server will destroy the object
|
||||
immediately after sending this request, so it will become invalid and
|
||||
the client should free any resources associated with it.
|
||||
</description>
|
||||
</event>
|
||||
</interface>
|
||||
|
||||
<interface name="zwlr_foreign_toplevel_handle_v1" version="3">
|
||||
<description summary="an opened toplevel">
|
||||
A zwlr_foreign_toplevel_handle_v1 object represents an opened toplevel
|
||||
window. Each app may have multiple opened toplevels.
|
||||
|
||||
Each toplevel has a list of outputs it is visible on, conveyed to the
|
||||
client with the output_enter and output_leave events.
|
||||
</description>
|
||||
|
||||
<event name="title">
|
||||
<description summary="title change">
|
||||
This event is emitted whenever the title of the toplevel changes.
|
||||
</description>
|
||||
<arg name="title" type="string"/>
|
||||
</event>
|
||||
|
||||
<event name="app_id">
|
||||
<description summary="app-id change">
|
||||
This event is emitted whenever the app-id of the toplevel changes.
|
||||
</description>
|
||||
<arg name="app_id" type="string"/>
|
||||
</event>
|
||||
|
||||
<event name="output_enter">
|
||||
<description summary="toplevel entered an output">
|
||||
This event is emitted whenever the toplevel becomes visible on
|
||||
the given output. A toplevel may be visible on multiple outputs.
|
||||
</description>
|
||||
<arg name="output" type="object" interface="wl_output"/>
|
||||
</event>
|
||||
|
||||
<event name="output_leave">
|
||||
<description summary="toplevel left an output">
|
||||
This event is emitted whenever the toplevel stops being visible on
|
||||
the given output. It is guaranteed that an entered-output event
|
||||
with the same output has been emitted before this event.
|
||||
</description>
|
||||
<arg name="output" type="object" interface="wl_output"/>
|
||||
</event>
|
||||
|
||||
<request name="set_maximized">
|
||||
<description summary="requests that the toplevel be maximized">
|
||||
Requests that the toplevel be maximized. If the maximized state actually
|
||||
changes, this will be indicated by the state event.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<request name="unset_maximized">
|
||||
<description summary="requests that the toplevel be unmaximized">
|
||||
Requests that the toplevel be unmaximized. If the maximized state actually
|
||||
changes, this will be indicated by the state event.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<request name="set_minimized">
|
||||
<description summary="requests that the toplevel be minimized">
|
||||
Requests that the toplevel be minimized. If the minimized state actually
|
||||
changes, this will be indicated by the state event.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<request name="unset_minimized">
|
||||
<description summary="requests that the toplevel be unminimized">
|
||||
Requests that the toplevel be unminimized. If the minimized state actually
|
||||
changes, this will be indicated by the state event.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<request name="activate">
|
||||
<description summary="activate the toplevel">
|
||||
Request that this toplevel be activated on the given seat.
|
||||
There is no guarantee the toplevel will be actually activated.
|
||||
</description>
|
||||
<arg name="seat" type="object" interface="wl_seat"/>
|
||||
</request>
|
||||
|
||||
<enum name="state">
|
||||
<description summary="types of states on the toplevel">
|
||||
The different states that a toplevel can have. These have the same meaning
|
||||
as the states with the same names defined in xdg-toplevel
|
||||
</description>
|
||||
|
||||
<entry name="maximized" value="0" summary="the toplevel is maximized"/>
|
||||
<entry name="minimized" value="1" summary="the toplevel is minimized"/>
|
||||
<entry name="activated" value="2" summary="the toplevel is active"/>
|
||||
<entry name="fullscreen" value="3" summary="the toplevel is fullscreen" since="2"/>
|
||||
</enum>
|
||||
|
||||
<event name="state">
|
||||
<description summary="the toplevel state changed">
|
||||
This event is emitted immediately after the zlw_foreign_toplevel_handle_v1
|
||||
is created and each time the toplevel state changes, either because of a
|
||||
compositor action or because of a request in this protocol.
|
||||
</description>
|
||||
|
||||
<arg name="state" type="array"/>
|
||||
</event>
|
||||
|
||||
<event name="done">
|
||||
<description summary="all information about the toplevel has been sent">
|
||||
This event is sent after all changes in the toplevel state have been
|
||||
sent.
|
||||
|
||||
This allows changes to the zwlr_foreign_toplevel_handle_v1 properties
|
||||
to be seen as atomic, even if they happen via multiple events.
|
||||
</description>
|
||||
</event>
|
||||
|
||||
<request name="close">
|
||||
<description summary="request that the toplevel be closed">
|
||||
Send a request to the toplevel to close itself. The compositor would
|
||||
typically use a shell-specific method to carry out this request, for
|
||||
example by sending the xdg_toplevel.close event. However, this gives
|
||||
no guarantees the toplevel will actually be destroyed. If and when
|
||||
this happens, the zwlr_foreign_toplevel_handle_v1.closed event will
|
||||
be emitted.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<request name="set_rectangle">
|
||||
<description summary="the rectangle which represents the toplevel">
|
||||
The rectangle of the surface specified in this request corresponds to
|
||||
the place where the app using this protocol represents the given toplevel.
|
||||
It can be used by the compositor as a hint for some operations, e.g
|
||||
minimizing. The client is however not required to set this, in which
|
||||
case the compositor is free to decide some default value.
|
||||
|
||||
If the client specifies more than one rectangle, only the last one is
|
||||
considered.
|
||||
|
||||
The dimensions are given in surface-local coordinates.
|
||||
Setting width=height=0 removes the already-set rectangle.
|
||||
</description>
|
||||
|
||||
<arg name="surface" type="object" interface="wl_surface"/>
|
||||
<arg name="x" type="int"/>
|
||||
<arg name="y" type="int"/>
|
||||
<arg name="width" type="int"/>
|
||||
<arg name="height" type="int"/>
|
||||
</request>
|
||||
|
||||
<enum name="error">
|
||||
<entry name="invalid_rectangle" value="0"
|
||||
summary="the provided rectangle is invalid"/>
|
||||
</enum>
|
||||
|
||||
<event name="closed">
|
||||
<description summary="this toplevel has been destroyed">
|
||||
This event means the toplevel has been destroyed. It is guaranteed there
|
||||
won't be any more events for this zwlr_foreign_toplevel_handle_v1. The
|
||||
toplevel itself becomes inert so any requests will be ignored except the
|
||||
destroy request.
|
||||
</description>
|
||||
</event>
|
||||
|
||||
<request name="destroy" type="destructor">
|
||||
<description summary="destroy the zwlr_foreign_toplevel_handle_v1 object">
|
||||
Destroys the zwlr_foreign_toplevel_handle_v1 object.
|
||||
|
||||
This request should be called either when the client does not want to
|
||||
use the toplevel anymore or after the closed event to finalize the
|
||||
destruction of the object.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<!-- Version 2 additions -->
|
||||
|
||||
<request name="set_fullscreen" since="2">
|
||||
<description summary="request that the toplevel be fullscreened">
|
||||
Requests that the toplevel be fullscreened on the given output. If the
|
||||
fullscreen state and/or the outputs the toplevel is visible on actually
|
||||
change, this will be indicated by the state and output_enter/leave
|
||||
events.
|
||||
|
||||
The output parameter is only a hint to the compositor. Also, if output
|
||||
is NULL, the compositor should decide which output the toplevel will be
|
||||
fullscreened on, if at all.
|
||||
</description>
|
||||
<arg name="output" type="object" interface="wl_output" allow-null="true"/>
|
||||
</request>
|
||||
|
||||
<request name="unset_fullscreen" since="2">
|
||||
<description summary="request that the toplevel be unfullscreened">
|
||||
Requests that the toplevel be unfullscreened. If the fullscreen state
|
||||
actually changes, this will be indicated by the state event.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<!-- Version 3 additions -->
|
||||
|
||||
<event name="parent" since="3">
|
||||
<description summary="parent change">
|
||||
This event is emitted whenever the parent of the toplevel changes.
|
||||
|
||||
No event is emitted when the parent handle is destroyed by the client.
|
||||
</description>
|
||||
<arg name="parent" type="object" interface="zwlr_foreign_toplevel_handle_v1" allow-null="true"/>
|
||||
</event>
|
||||
</interface>
|
||||
</protocol>
|
33
src/background.c
Normal file
33
src/background.c
Normal file
@ -0,0 +1,33 @@
|
||||
#include "background.h"
|
||||
#include <assert.h>
|
||||
#define NAMESPACE "background"
|
||||
|
||||
static void on_background_destroy(GtkWindow *window, GApplication *_data)
|
||||
{
|
||||
(void) window;
|
||||
(void)_data;
|
||||
//g_application_quit (G_APPLICATION (gtk_window_get_application (window)));
|
||||
}
|
||||
|
||||
void diya_shell_init_background(DiyaShell * shell)
|
||||
{
|
||||
GtkWindow *gtk_window;
|
||||
g_object_get(shell, "background", >k_window, NULL);
|
||||
assert(gtk_window);
|
||||
g_signal_connect (gtk_window, "destroy", G_CALLBACK (on_background_destroy), NULL);
|
||||
// int layer shell for window
|
||||
gtk_layer_init_for_window (gtk_window);
|
||||
// anchor window to all edges
|
||||
for (int i = 0; i < GTK_LAYER_SHELL_EDGE_ENTRY_NUMBER; i++)
|
||||
gtk_layer_set_anchor (gtk_window, i, true);
|
||||
// set margin on window
|
||||
for (int i = 0; i < GTK_LAYER_SHELL_EDGE_ENTRY_NUMBER; i++)
|
||||
gtk_layer_set_margin (gtk_window, i, 0);
|
||||
gtk_layer_set_layer (gtk_window, GTK_LAYER_SHELL_LAYER_BACKGROUND);
|
||||
gtk_layer_set_keyboard_mode (gtk_window, GTK_LAYER_SHELL_KEYBOARD_MODE_NONE);
|
||||
gtk_layer_set_namespace (gtk_window, NAMESPACE);
|
||||
gtk_widget_set_name(GTK_WIDGET(gtk_window),NAMESPACE);
|
||||
//gtk_layer_auto_exclusive_zone_enable (gtk_window);
|
||||
//g_signal_connect (gtk_window, "orientation-changed", G_CALLBACK (on_orientation_changed), /*data*/NULL);
|
||||
gtk_window_present (GTK_WINDOW (gtk_window));
|
||||
}
|
8
src/background.h
Normal file
8
src/background.h
Normal file
@ -0,0 +1,8 @@
|
||||
#ifndef DIYA_SHELL_BACKGROUND_H
|
||||
#define DIYA_SHELL_BACKGROUND_H
|
||||
|
||||
#include "shell.h"
|
||||
|
||||
void diya_shell_init_background(DiyaShell * shell);
|
||||
|
||||
#endif
|
21
src/base.c
Normal file
21
src/base.c
Normal file
@ -0,0 +1,21 @@
|
||||
#include "base.h"
|
||||
|
||||
G_DEFINE_ABSTRACT_TYPE(DiyaObject, diya_object, G_TYPE_OBJECT)
|
||||
|
||||
static void diya_object_class_init(DiyaObjectClass *class)
|
||||
{
|
||||
class->to_string = NULL;
|
||||
}
|
||||
|
||||
static void diya_object_init(DiyaObject *self)
|
||||
{
|
||||
(void) self;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
24
src/base.h
Normal file
24
src/base.h
Normal file
@ -0,0 +1,24 @@
|
||||
#ifndef DIYA_OBJECT_H
|
||||
#define DIYA_OBJECT_H
|
||||
|
||||
#include <glib-object.h>
|
||||
/**
|
||||
* Base class object
|
||||
*
|
||||
*/
|
||||
#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
|
||||
*
|
||||
*/
|
||||
};
|
||||
|
||||
const gchar* diya_object_to_string(gpointer object);
|
||||
|
||||
#endif
|
313
src/foreign.c
Normal file
313
src/foreign.c
Normal file
@ -0,0 +1,313 @@
|
||||
#include <assert.h>
|
||||
#include <inttypes.h>
|
||||
#include "foreign.h"
|
||||
|
||||
/**
|
||||
* @DiyaWindow Object definition
|
||||
*
|
||||
*/
|
||||
enum
|
||||
{
|
||||
NO_PROP,
|
||||
WIN_APP_ID,
|
||||
WIN_TITLE,
|
||||
WIN_HANDLE,
|
||||
WIN_STATE,
|
||||
WIN_PARENT,
|
||||
SHELL,
|
||||
N_PROPERTIES
|
||||
};
|
||||
static GParamSpec *win_properties[N_PROPERTIES] = {0};
|
||||
struct _DiyaWindow
|
||||
{
|
||||
DiyaObject parent;
|
||||
gchar * appid;
|
||||
gpointer handle;
|
||||
gchar* title;
|
||||
enum diya_win_state state;
|
||||
DiyaWindow * parent_win;
|
||||
DiyaShell * shell;
|
||||
gchar string[128];
|
||||
};
|
||||
G_DEFINE_TYPE(DiyaWindow, diya_window, DIYA_TYPE_OBJECT)
|
||||
|
||||
static void diya_window_finalize(GObject* object)
|
||||
{
|
||||
DiyaWindow * self = DIYA_WINDOW(object);
|
||||
g_debug("diya_window_finalize: %s", diya_object_to_string(self));
|
||||
if(self->appid)
|
||||
{
|
||||
g_free(self->appid);
|
||||
}
|
||||
if(self->title)
|
||||
{
|
||||
g_free(self->title);
|
||||
}
|
||||
}
|
||||
|
||||
static void diya_window_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
|
||||
{
|
||||
DiyaWindow * self = DIYA_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 SHELL:
|
||||
self->shell = 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_window_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
|
||||
{
|
||||
DiyaWindow * self = DIYA_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 SHELL:
|
||||
g_value_set_pointer(value, self->shell);
|
||||
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_window_init(DiyaWindow *self)
|
||||
{
|
||||
self->appid = NULL;
|
||||
//self->handle = NULL;
|
||||
self->parent_win = NULL;
|
||||
//self->shell = NULL;
|
||||
self->state = DIYA_WIN_STATE_NONE;
|
||||
self->title = NULL;
|
||||
}
|
||||
|
||||
static const gchar* diya_window_to_string(DiyaObject* object)
|
||||
{
|
||||
DiyaWindow* self = DIYA_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)
|
||||
{
|
||||
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;
|
||||
|
||||
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 );
|
||||
|
||||
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);
|
||||
DiyaWindow *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);
|
||||
DiyaWindow *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);
|
||||
DiyaWindow *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);
|
||||
DiyaWindow *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);
|
||||
DiyaWindow *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);
|
||||
DiyaWindow *child_win = diya_shell_get_window(shell, handle);
|
||||
DiyaWindow *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 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);
|
||||
|
||||
if (win)
|
||||
{
|
||||
g_debug("[%s] already exists",diya_object_to_string(win));
|
||||
return;
|
||||
}
|
||||
// TODO: different between windows
|
||||
win = diya_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;
|
||||
// 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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
7
src/foreign.h
Normal file
7
src/foreign.h
Normal file
@ -0,0 +1,7 @@
|
||||
#ifndef DIYA_SHELL_FOREIGN_H
|
||||
#define DIYA_SHELL_FOREIGN_H
|
||||
#include "wlr-foreign-toplevel-management-unstable-v1.h"
|
||||
#include "shell.h"
|
||||
|
||||
void diya_shell_foreign_toplevel_register(struct wl_registry *registry, uint32_t name, DiyaShell * shell);
|
||||
#endif
|
78
src/launcher.c
Normal file
78
src/launcher.c
Normal file
@ -0,0 +1,78 @@
|
||||
#include "launcher.h"
|
||||
#include "foreign.h"
|
||||
#include <assert.h>
|
||||
|
||||
#define NAMESPACE "launcher"
|
||||
|
||||
static void on_launcher_destroy(GtkWindow *window, GApplication *_data)
|
||||
{
|
||||
(void) window;
|
||||
(void)_data;
|
||||
//g_application_quit (G_APPLICATION (gtk_window_get_application (window)));
|
||||
}
|
||||
|
||||
static void on_foreign_window_change(GtkApplication* app, DiyaWindow * win, gpointer data)
|
||||
{
|
||||
(void) app;
|
||||
(void) data;
|
||||
assert(win);
|
||||
g_warning("WINDOW CHANGEEEEEEEEE %s", diya_object_to_string(DIYA_OBJECT(win)));
|
||||
}
|
||||
|
||||
static void on_foreign_window_removed(GtkApplication* app, DiyaWindow * win, gpointer data)
|
||||
{
|
||||
(void) app;
|
||||
(void) data;
|
||||
assert(win);
|
||||
g_warning("WINDOW removed %s", diya_object_to_string(DIYA_OBJECT(win)));
|
||||
}
|
||||
|
||||
void diya_launcher_init(DiyaShell * shell)
|
||||
{
|
||||
assert(shell);
|
||||
GtkWindow *gtk_window;
|
||||
g_object_get(shell, "launchpad", >k_window, NULL);
|
||||
assert(gtk_window);
|
||||
g_signal_connect (gtk_window, "destroy", G_CALLBACK (on_launcher_destroy), NULL);
|
||||
// int layer shell for window
|
||||
gtk_layer_init_for_window (gtk_window);
|
||||
// anchor window to all edges
|
||||
gtk_layer_set_anchor (gtk_window, GTK_LAYER_SHELL_EDGE_LEFT, true);
|
||||
gtk_layer_set_anchor (gtk_window, GTK_LAYER_SHELL_EDGE_RIGHT, true);
|
||||
gtk_layer_set_anchor (gtk_window, GTK_LAYER_SHELL_EDGE_TOP, true);
|
||||
gtk_layer_set_anchor (gtk_window, GTK_LAYER_SHELL_EDGE_BOTTOM, false);
|
||||
|
||||
// set margin on window
|
||||
for (int i = 0; i < GTK_LAYER_SHELL_EDGE_ENTRY_NUMBER; i++)
|
||||
gtk_layer_set_margin (gtk_window, i, 0);
|
||||
gtk_layer_set_layer (gtk_window, GTK_LAYER_SHELL_LAYER_TOP);
|
||||
gtk_layer_set_keyboard_mode (gtk_window, GTK_LAYER_SHELL_KEYBOARD_MODE_ON_DEMAND);
|
||||
gtk_layer_set_namespace (gtk_window, NAMESPACE);
|
||||
// the top launcher shall be exclusive
|
||||
gtk_layer_auto_exclusive_zone_enable (gtk_window);
|
||||
|
||||
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);
|
||||
gtk_box_set_homogeneous (GTK_BOX (box), TRUE);
|
||||
gtk_window_set_child (GTK_WINDOW (gtk_window), box);
|
||||
|
||||
//g_signal_connect (gtk_window, "orientation-changed", G_CALLBACK (on_orientation_changed), /*data*/NULL);
|
||||
gtk_window_present (GTK_WINDOW (gtk_window));
|
||||
|
||||
g_signal_connect (shell, "foreign-window-changed", G_CALLBACK (on_foreign_window_change), NULL);
|
||||
g_signal_connect (shell, "foreign-window-removed", G_CALLBACK (on_foreign_window_removed), NULL);
|
||||
|
||||
GList *apps = g_app_info_get_all ();
|
||||
GList * l;
|
||||
for (l = apps; l != NULL; l = l->next)
|
||||
{
|
||||
gpointer element_data = l->data;
|
||||
g_warning("%s", g_app_info_get_display_name(element_data)); /*print out all of the display names of the .desktop files */
|
||||
g_warning("%s", g_app_info_get_id(element_data));
|
||||
g_warning("%s", g_app_info_get_name(element_data));
|
||||
//g_warning("%s", g_app_info_get_icon(element_data));
|
||||
}
|
||||
g_list_free_full(apps, g_object_unref);
|
||||
}
|
9
src/launcher.h
Normal file
9
src/launcher.h
Normal file
@ -0,0 +1,9 @@
|
||||
#ifndef DIYA_SHELL_LAUNCHER_H
|
||||
#define DIYA_SHELL_LAUNCHER_H
|
||||
|
||||
#include "shell.h"
|
||||
|
||||
|
||||
void diya_launcher_init(DiyaShell * shell);
|
||||
|
||||
#endif
|
230
src/shell.c
Normal file
230
src/shell.c
Normal file
@ -0,0 +1,230 @@
|
||||
#include <assert.h>
|
||||
|
||||
#include "background.h"
|
||||
#include "launcher.h"
|
||||
#include "wayland.h"
|
||||
#include "foreign.h"
|
||||
|
||||
#define SHELL_DESCRIPTION "Diya GTK shell for wayland (diyac)"
|
||||
|
||||
enum
|
||||
{
|
||||
NO_PROP,
|
||||
SHELL_APP,
|
||||
SHELL_BACKGROUND_WIDGET,
|
||||
SHELL_LAUNCHPAD_WIDGET,
|
||||
SHELL_WINDOWS,
|
||||
N_PROPERTIES
|
||||
};
|
||||
|
||||
static GParamSpec *shell_properties[N_PROPERTIES] = {0};
|
||||
|
||||
struct _DiyaShell
|
||||
{
|
||||
DiyaObject parent;
|
||||
GtkApplication* app;
|
||||
GtkWindow* background;
|
||||
GtkWindow* launcher;
|
||||
GHashTable* windows;
|
||||
};
|
||||
G_DEFINE_TYPE(DiyaShell, diya_shell, DIYA_TYPE_OBJECT)
|
||||
|
||||
static void diya_shell_finalize(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");
|
||||
}
|
||||
|
||||
static void diya_shell_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
|
||||
{
|
||||
DiyaShell * self = DIYA_SHELL(object);
|
||||
switch (property_id)
|
||||
{
|
||||
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:
|
||||
case SHELL_LAUNCHPAD_WIDGET:
|
||||
case SHELL_WINDOWS:
|
||||
//self->windows = g_value_get_pointer(value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void diya_shell_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
|
||||
{
|
||||
DiyaShell * self = DIYA_SHELL(object);
|
||||
switch (property_id)
|
||||
{
|
||||
case SHELL_APP:
|
||||
g_value_set_pointer(value, self->app);
|
||||
break;
|
||||
case SHELL_BACKGROUND_WIDGET:
|
||||
g_value_set_pointer(value, self->background);
|
||||
break;
|
||||
case SHELL_LAUNCHPAD_WIDGET:
|
||||
assert(self->launcher);
|
||||
g_value_set_pointer(value, self->launcher);
|
||||
break;
|
||||
case SHELL_WINDOWS:
|
||||
g_value_set_pointer(value, self->windows);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static const gchar* diya_shell_to_string(DiyaObject* object)
|
||||
{
|
||||
(void) object;
|
||||
return SHELL_DESCRIPTION;
|
||||
}
|
||||
|
||||
static void diya_shell_class_init(DiyaShellClass *class)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS(class);
|
||||
DiyaObjectClass *base_class = DIYA_OBJECT_CLASS(class);
|
||||
|
||||
base_class->to_string = diya_shell_to_string;
|
||||
gobject_class->finalize = diya_shell_finalize;
|
||||
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_WINDOWS] = g_param_spec_pointer("windows", NULL, "Shell foreign windows", G_PARAM_READABLE);
|
||||
g_object_class_install_properties (gobject_class, N_PROPERTIES, shell_properties);
|
||||
|
||||
g_signal_new("foreign-window-changed",
|
||||
DIYA_TYPE_SHELL,
|
||||
G_SIGNAL_DETAILED |
|
||||
G_SIGNAL_ACTION |
|
||||
G_SIGNAL_RUN_FIRST,
|
||||
0,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
G_TYPE_NONE,
|
||||
1,
|
||||
G_TYPE_POINTER);
|
||||
g_signal_new("foreign-window-removed",
|
||||
DIYA_TYPE_SHELL,
|
||||
G_SIGNAL_DETAILED |
|
||||
G_SIGNAL_ACTION |
|
||||
G_SIGNAL_RUN_FIRST,
|
||||
0,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
G_TYPE_NONE,
|
||||
1,
|
||||
G_TYPE_POINTER);
|
||||
}
|
||||
|
||||
static void diya_shell_init(DiyaShell *self)
|
||||
{
|
||||
//self->app = NULL;
|
||||
self->background = NULL;
|
||||
self->launcher = 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)
|
||||
{
|
||||
return g_hash_table_lookup(shell->windows, handle);
|
||||
}
|
||||
gboolean diya_shell_add_window(DiyaShell * shell, DiyaWindow * win)
|
||||
{
|
||||
gpointer handle;
|
||||
g_object_get(win, "handle", &handle, NULL);
|
||||
assert(handle);
|
||||
return g_hash_table_insert(shell->windows,handle, win);
|
||||
}
|
||||
|
||||
gboolean diya_shell_remove_window(DiyaShell * shell, DiyaWindow * win)
|
||||
{
|
||||
gpointer handle;
|
||||
g_object_get(win, "handle", &handle, NULL);
|
||||
assert(handle);
|
||||
return g_hash_table_remove(shell->windows,handle);
|
||||
}
|
||||
|
||||
DiyaShell * diya_shell_new(GtkApplication * app)
|
||||
{
|
||||
return DIYA_SHELL(g_object_new(DIYA_TYPE_SHELL,"application",app, NULL));
|
||||
}
|
||||
/*
|
||||
static void on_orientation_changed (GtkWindow *window, WindowOrientation orientation, ToplevelData *data)
|
||||
{
|
||||
(void)window;
|
||||
GtkOrientation orient_toplevel, orient_sub;
|
||||
orient_toplevel = GTK_ORIENTATION_HORIZONTAL;
|
||||
orient_sub = GTK_ORIENTATION_VERTICAL;
|
||||
|
||||
switch (orientation) {
|
||||
case WINDOW_ORIENTATION_HORIZONTAL:
|
||||
orient_toplevel = GTK_ORIENTATION_HORIZONTAL;
|
||||
orient_sub = GTK_ORIENTATION_HORIZONTAL;
|
||||
break;
|
||||
case WINDOW_ORIENTATION_VERTICAL:
|
||||
orient_toplevel = GTK_ORIENTATION_VERTICAL;
|
||||
orient_sub = GTK_ORIENTATION_VERTICAL;
|
||||
break;
|
||||
case WINDOW_ORIENTATION_NONE:
|
||||
orient_toplevel = GTK_ORIENTATION_HORIZONTAL;
|
||||
orient_sub = GTK_ORIENTATION_VERTICAL;
|
||||
break;
|
||||
}
|
||||
gtk_orientable_set_orientation (GTK_ORIENTABLE (data->toplevel_box), orient_toplevel);
|
||||
gtk_orientable_set_orientation (GTK_ORIENTABLE (data->first_box), orient_sub);
|
||||
gtk_orientable_set_orientation (GTK_ORIENTABLE (data->second_box), orient_sub);
|
||||
//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;
|
||||
}
|
27
src/shell.h
Normal file
27
src/shell.h
Normal file
@ -0,0 +1,27 @@
|
||||
#ifndef DIYA_SHELL_H
|
||||
#define DIYA_SHELL_H
|
||||
#include <gtk4-layer-shell.h>
|
||||
#include "base.h"
|
||||
|
||||
enum diya_win_state
|
||||
{
|
||||
DIYA_WIN_STATE_NONE = 0,
|
||||
DIYA_WIN_STATE_MINIMIZE = 1 << 0,
|
||||
DIYA_WIN_STATE_MAXIMIZE = 1 << 1,
|
||||
DIYA_WIN_STATE_FULLSCREEN = 1 << 2,
|
||||
DIYA_WIN_STATE_FOCUS = 1 << 3,
|
||||
};
|
||||
|
||||
#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)
|
||||
|
||||
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);
|
||||
#endif
|
57
src/wayland.c
Normal file
57
src/wayland.c
Normal file
@ -0,0 +1,57 @@
|
||||
#include <wayland-client-protocol.h>
|
||||
#include <gdk/wayland/gdkwayland.h>
|
||||
#include "wayland.h"
|
||||
#include "foreign.h"
|
||||
|
||||
static void handle_global(void *data, struct wl_registry *registry, uint32_t name, const gchar *interface, uint32_t version)
|
||||
{
|
||||
/*if (!g_strcmp0(interface, zxdg_output_manager_v1_interface.name))
|
||||
xdg_output_register(registry, name);
|
||||
else if (!g_strcmp0(interface, wl_shm_interface.name))
|
||||
shm_register(registry, name);
|
||||
else if (!g_strcmp0(interface, zwlr_layer_shell_v1_interface.name))
|
||||
layer_shell_register(registry, name, version);
|
||||
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;
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void handle_global_remove(void *data, struct wl_registry *registry,
|
||||
uint32_t name)
|
||||
{
|
||||
(void) data;
|
||||
(void) registry;
|
||||
(void) name;
|
||||
}
|
||||
|
||||
static const struct wl_registry_listener registry_listener = {
|
||||
.global = handle_global,
|
||||
.global_remove = handle_global_remove
|
||||
};
|
||||
|
||||
void diya_shell_wayland_init(DiyaShell *shell)
|
||||
{
|
||||
struct wl_display *display;
|
||||
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");
|
||||
|
||||
registry = wl_display_get_registry(display);
|
||||
wl_registry_add_listener(registry, ®istry_listener, (void*)shell);
|
||||
wl_display_roundtrip(display);
|
||||
// wayland_monitor_probe();
|
||||
// GdkMonitor *mon = wayland_monitor_get_default();
|
||||
// g_info("default output: %s", (gchar *)g_object_get_data(G_OBJECT(mon), "xdg_name"));
|
||||
|
||||
// wl_display_roundtrip(display);
|
||||
// wl_display_roundtrip(display);
|
||||
}
|
8
src/wayland.h
Normal file
8
src/wayland.h
Normal file
@ -0,0 +1,8 @@
|
||||
#ifndef DIYA_SHELL_WAYLAND_H
|
||||
#define DIYA_SHELL_WAYLAND_H
|
||||
|
||||
#include "shell.h"
|
||||
|
||||
void diya_shell_wayland_init(DiyaShell *shell);
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user